feat(media): service contracts between media slices
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0138YqDj3ttfayRwuMKKrqVj
This commit is contained in:
parent
475710e27e
commit
2556ed197e
@ -11,10 +11,30 @@ import type {
|
||||
MediaSourceProvider,
|
||||
MotionGraphicsRenderer,
|
||||
} from "@rakazo/adapter-kit";
|
||||
import type { ModelTier } from "@rakazo/contracts";
|
||||
import type {
|
||||
AiAlteration,
|
||||
ClientMediaItem,
|
||||
CreateMarkInput,
|
||||
Edl,
|
||||
EdlError,
|
||||
FfprobeReport,
|
||||
GateReport,
|
||||
IntroVariant,
|
||||
MarketingCopy,
|
||||
MarkTreatment,
|
||||
MediaEditPlan,
|
||||
MediaMark,
|
||||
MediaPublication,
|
||||
MediaRender,
|
||||
MediaRenderOutput,
|
||||
MediaRenderQuality,
|
||||
ModelTier,
|
||||
PlatformProfile,
|
||||
Utm,
|
||||
} from "@rakazo/contracts";
|
||||
import type { MediaRepos, PrismaClient } from "@rakazo/db";
|
||||
import { getLogger } from "@rakazo/logging";
|
||||
import type { ProfileSet } from "@rakazo/media";
|
||||
import type { CompileSource, ProfileSet } from "@rakazo/media";
|
||||
import type { z } from "zod";
|
||||
import { aiRecipient } from "./ai-consent.js";
|
||||
|
||||
@ -184,3 +204,152 @@ export function createMediaModelClient(deps: {
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Service contracts between media slices. Each slice implements its part; the
|
||||
// API, worker, and agent tools only depend on these interfaces.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export type CreateMarkInputType = z.infer<typeof CreateMarkInput>;
|
||||
|
||||
export interface MediaActor {
|
||||
spaceId: string;
|
||||
userId: string;
|
||||
}
|
||||
|
||||
export interface MediaIngestService {
|
||||
/** Client-pushed metadata (Apple Photos, iOS): upsert, apply deletions, enqueue work. */
|
||||
pushItems(
|
||||
actor: MediaActor,
|
||||
input: {
|
||||
sourceId: string;
|
||||
items: ClientMediaItem[];
|
||||
deletedExternalIds: string[];
|
||||
syncToken: string | null;
|
||||
complete: boolean;
|
||||
},
|
||||
): Promise<{ created: number; updated: number; unchanged: number; deleted: number }>;
|
||||
/** Enqueue an incremental sync of a server-side source. */
|
||||
requestSync(actor: MediaActor, sourceId: string): Promise<void>;
|
||||
/** An upload finished: move the file into place and enqueue proxy and analysis. */
|
||||
uploadCompleted(
|
||||
actor: MediaActor,
|
||||
input: { assetId: string; tempPath: string; sha256: string; fileName: string },
|
||||
): Promise<void>;
|
||||
recluster(actor: MediaActor): Promise<void>;
|
||||
/** Remove a source with its assets and every derived file. */
|
||||
removeSource(actor: MediaActor, sourceId: string): Promise<void>;
|
||||
}
|
||||
|
||||
export interface MediaPreparedSources {
|
||||
sources: Map<string, CompileSource>;
|
||||
/** Alterations applied while preparing (inpaint, synthetic identity, voice). */
|
||||
aiAlterations: AiAlteration[];
|
||||
/** Redactions that could not be honored and fell back, for the plan rationale. */
|
||||
fallbacks: string[];
|
||||
}
|
||||
|
||||
export interface MediaPrivacyService {
|
||||
/**
|
||||
* Resolve every clip's source file and apply all face, mark, and region
|
||||
* redactions from the EDL plus person and mark defaults. Fails closed: a
|
||||
* redaction that cannot be applied throws instead of returning an unredacted source.
|
||||
*/
|
||||
prepareSources(input: {
|
||||
actor: MediaActor;
|
||||
projectId: string;
|
||||
edl: Edl;
|
||||
quality: MediaRenderQuality;
|
||||
workDir: string;
|
||||
signal?: AbortSignal;
|
||||
}): Promise<MediaPreparedSources>;
|
||||
/** Re-detect on the rendered output and evaluate the full gate. */
|
||||
gate(input: {
|
||||
actor: MediaActor;
|
||||
projectId: string;
|
||||
edl: Edl;
|
||||
profile: PlatformProfile;
|
||||
outputPath: string;
|
||||
ffprobe: FfprobeReport;
|
||||
copy: { title: string | null; caption: string | null; tags: string[] };
|
||||
bundleHasDisclosure: boolean;
|
||||
autoFixRound: number;
|
||||
signal?: AbortSignal;
|
||||
}): Promise<GateReport>;
|
||||
/** Create a mark: segment from the prompt, propagate, score, and suggest a fallback. */
|
||||
createMark(actor: MediaActor, input: CreateMarkInputType): Promise<MediaMark>;
|
||||
updateMark(
|
||||
actor: MediaActor,
|
||||
input: {
|
||||
markId: string;
|
||||
treatment?: MarkTreatment;
|
||||
label?: string | null;
|
||||
personId?: string | null;
|
||||
},
|
||||
): Promise<MediaMark>;
|
||||
/** Delete a person, their biometric data, and their files. */
|
||||
removePerson(actor: MediaActor, personId: string): Promise<void>;
|
||||
}
|
||||
|
||||
export interface MediaRenderService {
|
||||
start(
|
||||
actor: MediaActor,
|
||||
input: { planId: string; quality: MediaRenderQuality },
|
||||
): Promise<MediaRender>;
|
||||
cancel(actor: MediaActor, renderId: string): Promise<MediaRender>;
|
||||
/** Absolute path of a finished output for streaming, or null. */
|
||||
outputPath(actor: MediaActor, renderId: string, fileName: string): Promise<string | null>;
|
||||
}
|
||||
|
||||
export interface MediaMarketingService {
|
||||
autoPlan(
|
||||
actor: MediaActor,
|
||||
input: { projectId: string; profileIds?: string[] },
|
||||
): Promise<MediaEditPlan[]>;
|
||||
submitPlan(
|
||||
actor: MediaActor,
|
||||
input: {
|
||||
projectId: string;
|
||||
edl: unknown;
|
||||
rationale: string | null;
|
||||
createdBy: "agent" | "user";
|
||||
},
|
||||
): Promise<{ ok: true; plan: MediaEditPlan } | { ok: false; errors: EdlError[] }>;
|
||||
introVariants(
|
||||
actor: MediaActor,
|
||||
input: { brandKitId: string; count: number },
|
||||
): Promise<IntroVariant[]>;
|
||||
thumbnails(
|
||||
actor: MediaActor,
|
||||
input: { renderId: string; count: number },
|
||||
): Promise<MediaRenderOutput[]>;
|
||||
copy(actor: MediaActor, input: { renderId: string; language: string }): Promise<MarketingCopy>;
|
||||
createPublication(
|
||||
actor: MediaActor,
|
||||
input: {
|
||||
renderId: string;
|
||||
destination: string;
|
||||
targetUrl: string | null;
|
||||
utm: Utm | null;
|
||||
title: string | null;
|
||||
caption: string | null;
|
||||
tags: string[];
|
||||
thumbnailVariant: string | null;
|
||||
scheduledAt: string | null;
|
||||
},
|
||||
): Promise<MediaPublication>;
|
||||
bundle(actor: MediaActor, publicationId: string): Promise<MediaPublication>;
|
||||
cancelPublication(actor: MediaActor, publicationId: string): Promise<MediaPublication>;
|
||||
importMetricsCsv(
|
||||
actor: MediaActor,
|
||||
input: { mappingId: string; csv: string },
|
||||
): Promise<{ imported: number; skipped: Array<{ row: number; reason: string }> }>;
|
||||
}
|
||||
|
||||
export interface MediaServices {
|
||||
deps: MediaServiceDeps;
|
||||
ingest: MediaIngestService;
|
||||
privacy: MediaPrivacyService;
|
||||
render: MediaRenderService;
|
||||
marketing: MediaMarketingService;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user