@contractspec/lib.video-gen 2.7.17 → 2.7.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/compositions/api-overview.js +1 -645
- package/dist/browser/compositions/index.js +1 -1133
- package/dist/browser/compositions/primitives/animated-text.js +1 -144
- package/dist/browser/compositions/primitives/brand-frame.js +1 -181
- package/dist/browser/compositions/primitives/code-block.js +1 -226
- package/dist/browser/compositions/primitives/index.js +1 -656
- package/dist/browser/compositions/primitives/progress-bar.js +1 -59
- package/dist/browser/compositions/primitives/terminal.js +1 -265
- package/dist/browser/compositions/primitives/transition.js +1 -98
- package/dist/browser/compositions/social-clip.js +1 -500
- package/dist/browser/compositions/terminal-demo.js +1 -558
- package/dist/browser/design/index.js +1 -155
- package/dist/browser/design/layouts.js +1 -50
- package/dist/browser/design/motion.js +1 -43
- package/dist/browser/design/tokens.js +1 -28
- package/dist/browser/design/typography.js +1 -61
- package/dist/browser/docs/compositions.docblock.js +1 -182
- package/dist/browser/docs/design.docblock.js +2 -17
- package/dist/browser/docs/generators.docblock.js +2 -24
- package/dist/browser/docs/rendering.docblock.js +2 -24
- package/dist/browser/docs/video-gen.docblock.js +2 -17
- package/dist/browser/generators/index.js +7 -769
- package/dist/browser/generators/scene-planner.js +7 -651
- package/dist/browser/generators/script-generator.js +7 -599
- package/dist/browser/generators/video-generator.js +7 -768
- package/dist/browser/i18n/catalogs/en.js +3 -135
- package/dist/browser/i18n/catalogs/es.js +3 -135
- package/dist/browser/i18n/catalogs/fr.js +3 -135
- package/dist/browser/i18n/catalogs/index.js +7 -387
- package/dist/browser/i18n/index.js +7 -459
- package/dist/browser/i18n/keys.js +1 -54
- package/dist/browser/i18n/locale.js +1 -21
- package/dist/browser/i18n/messages.js +7 -399
- package/dist/browser/index.js +7 -1903
- package/dist/browser/player/demo-player.js +1 -1136
- package/dist/browser/player/index.js +1 -1136
- package/dist/browser/remotion/Root.js +2 -1172
- package/dist/browser/remotion/index.js +2 -1173
- package/dist/browser/renderers/config.js +1 -40
- package/dist/browser/renderers/index.js +1 -160
- package/dist/browser/renderers/local.js +1 -156
- package/dist/browser/types.js +1 -13
- package/dist/compositions/api-overview.js +1 -639
- package/dist/compositions/index.js +1 -1127
- package/dist/compositions/primitives/animated-text.js +1 -138
- package/dist/compositions/primitives/brand-frame.js +1 -175
- package/dist/compositions/primitives/code-block.js +1 -220
- package/dist/compositions/primitives/index.js +1 -650
- package/dist/compositions/primitives/progress-bar.js +1 -53
- package/dist/compositions/primitives/terminal.js +1 -259
- package/dist/compositions/primitives/transition.js +1 -92
- package/dist/compositions/social-clip.js +1 -494
- package/dist/compositions/terminal-demo.js +1 -552
- package/dist/design/index.js +1 -149
- package/dist/design/layouts.js +1 -44
- package/dist/design/motion.js +1 -37
- package/dist/design/tokens.js +1 -22
- package/dist/design/typography.js +1 -55
- package/dist/docs/compositions.docblock.js +1 -182
- package/dist/docs/design.docblock.js +2 -17
- package/dist/docs/generators.docblock.js +2 -24
- package/dist/docs/rendering.docblock.js +2 -24
- package/dist/docs/video-gen.docblock.js +2 -17
- package/dist/generators/index.js +7 -763
- package/dist/generators/scene-planner.js +7 -645
- package/dist/generators/script-generator.js +7 -593
- package/dist/generators/video-generator.js +7 -762
- package/dist/i18n/catalogs/en.js +3 -129
- package/dist/i18n/catalogs/es.js +3 -129
- package/dist/i18n/catalogs/fr.js +3 -129
- package/dist/i18n/catalogs/index.js +7 -381
- package/dist/i18n/index.js +7 -453
- package/dist/i18n/keys.js +1 -48
- package/dist/i18n/locale.js +1 -15
- package/dist/i18n/messages.js +7 -393
- package/dist/index.js +7 -1897
- package/dist/node/compositions/api-overview.js +1 -640
- package/dist/node/compositions/index.js +1 -1128
- package/dist/node/compositions/primitives/animated-text.js +1 -139
- package/dist/node/compositions/primitives/brand-frame.js +1 -176
- package/dist/node/compositions/primitives/code-block.js +1 -221
- package/dist/node/compositions/primitives/index.js +1 -651
- package/dist/node/compositions/primitives/progress-bar.js +1 -54
- package/dist/node/compositions/primitives/terminal.js +1 -260
- package/dist/node/compositions/primitives/transition.js +1 -93
- package/dist/node/compositions/social-clip.js +1 -495
- package/dist/node/compositions/terminal-demo.js +1 -553
- package/dist/node/design/index.js +1 -150
- package/dist/node/design/layouts.js +1 -45
- package/dist/node/design/motion.js +1 -38
- package/dist/node/design/tokens.js +1 -23
- package/dist/node/design/typography.js +1 -56
- package/dist/node/docs/compositions.docblock.js +1 -182
- package/dist/node/docs/design.docblock.js +2 -17
- package/dist/node/docs/generators.docblock.js +2 -24
- package/dist/node/docs/rendering.docblock.js +2 -24
- package/dist/node/docs/video-gen.docblock.js +2 -17
- package/dist/node/generators/index.js +7 -764
- package/dist/node/generators/scene-planner.js +7 -646
- package/dist/node/generators/script-generator.js +7 -594
- package/dist/node/generators/video-generator.js +7 -763
- package/dist/node/i18n/catalogs/en.js +3 -130
- package/dist/node/i18n/catalogs/es.js +3 -130
- package/dist/node/i18n/catalogs/fr.js +3 -130
- package/dist/node/i18n/catalogs/index.js +7 -382
- package/dist/node/i18n/index.js +7 -454
- package/dist/node/i18n/keys.js +1 -49
- package/dist/node/i18n/locale.js +1 -16
- package/dist/node/i18n/messages.js +7 -394
- package/dist/node/index.js +7 -1898
- package/dist/node/player/demo-player.js +1 -1131
- package/dist/node/player/index.js +1 -1131
- package/dist/node/remotion/Root.js +2 -1167
- package/dist/node/remotion/index.js +2 -1168
- package/dist/node/renderers/config.js +1 -35
- package/dist/node/renderers/index.js +1 -155
- package/dist/node/renderers/local.js +1 -151
- package/dist/node/types.js +1 -8
- package/dist/player/demo-player.js +1 -1130
- package/dist/player/index.js +1 -1130
- package/dist/remotion/Root.js +2 -1166
- package/dist/remotion/index.js +2 -1167
- package/dist/renderers/config.js +1 -34
- package/dist/renderers/index.js +1 -154
- package/dist/renderers/local.js +1 -150
- package/dist/types.js +1 -7
- package/package.json +16 -16
|
@@ -1,57 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
3
|
-
|
|
4
|
-
// src/design/layouts.ts
|
|
5
|
-
import { VIDEO_FORMATS } from "@contractspec/lib.contracts-integrations/integrations/providers/video";
|
|
6
|
-
var DEFAULT_FPS = 30;
|
|
7
|
-
var videoSafeZone = {
|
|
8
|
-
horizontal: 120,
|
|
9
|
-
vertical: 80,
|
|
10
|
-
contentWidth: 1680,
|
|
11
|
-
contentHeight: 920
|
|
12
|
-
};
|
|
13
|
-
function scaleSafeZone(format) {
|
|
14
|
-
const scaleX = format.width / 1920;
|
|
15
|
-
const scaleY = format.height / 1080;
|
|
16
|
-
return {
|
|
17
|
-
horizontal: Math.round(videoSafeZone.horizontal * scaleX),
|
|
18
|
-
vertical: Math.round(videoSafeZone.vertical * scaleY),
|
|
19
|
-
contentWidth: Math.round(videoSafeZone.contentWidth * scaleX),
|
|
20
|
-
contentHeight: Math.round(videoSafeZone.contentHeight * scaleY)
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
var videoPositions = {
|
|
24
|
-
center: { x: 960, y: 540 },
|
|
25
|
-
topLeft: { x: 120, y: 80 },
|
|
26
|
-
topRight: { x: 1800, y: 80 },
|
|
27
|
-
bottomLeft: { x: 120, y: 1000 },
|
|
28
|
-
bottomRight: { x: 1800, y: 1000 },
|
|
29
|
-
bottomCenter: { x: 960, y: 960 }
|
|
30
|
-
};
|
|
31
|
-
function getAllFormatVariants() {
|
|
32
|
-
return [
|
|
33
|
-
VIDEO_FORMATS.landscape,
|
|
34
|
-
VIDEO_FORMATS.square,
|
|
35
|
-
VIDEO_FORMATS.portrait
|
|
36
|
-
];
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// src/i18n/catalogs/en.ts
|
|
40
|
-
import { defineTranslation } from "@contractspec/lib.contracts-spec/translations";
|
|
41
|
-
var enMessages = defineTranslation({
|
|
42
|
-
meta: {
|
|
43
|
-
key: "video-gen.messages",
|
|
44
|
-
version: "1.0.0",
|
|
45
|
-
domain: "video-gen",
|
|
46
|
-
description: "All user-facing, LLM-facing, and developer-facing strings for the video-gen package",
|
|
47
|
-
owners: ["platform"],
|
|
48
|
-
stability: "experimental"
|
|
49
|
-
},
|
|
50
|
-
locale: "en",
|
|
51
|
-
fallback: "en",
|
|
52
|
-
messages: {
|
|
53
|
-
"prompt.script.system": {
|
|
54
|
-
value: `You are a video narration script writer.
|
|
1
|
+
import{createRequire as _}from"node:module";var b=_(import.meta.url);import{VIDEO_FORMATS as W}from"@contractspec/lib.contracts-integrations/integrations/providers/video";var Q=30,J={horizontal:120,vertical:80,contentWidth:1680,contentHeight:920};function r(x){let L=x.width/1920,K=x.height/1080;return{horizontal:Math.round(J.horizontal*L),vertical:Math.round(J.vertical*K),contentWidth:Math.round(J.contentWidth*L),contentHeight:Math.round(J.contentHeight*K)}}var a={center:{x:960,y:540},topLeft:{x:120,y:80},topRight:{x:1800,y:80},bottomLeft:{x:120,y:1000},bottomRight:{x:1800,y:1000},bottomCenter:{x:960,y:960}};function c(){return[W.landscape,W.square,W.portrait]}import{defineTranslation as M}from"@contractspec/lib.contracts-spec/translations";var $=M({meta:{key:"video-gen.messages",version:"1.0.0",domain:"video-gen",description:"All user-facing, LLM-facing, and developer-facing strings for the video-gen package",owners:["platform"],stability:"experimental"},locale:"en",fallback:"en",messages:{"prompt.script.system":{value:`You are a video narration script writer.
|
|
55
2
|
Write a narration script for a short video (30-60 seconds).
|
|
56
3
|
{styleGuide}
|
|
57
4
|
|
|
@@ -62,12 +9,7 @@ Return JSON with shape:
|
|
|
62
9
|
}
|
|
63
10
|
|
|
64
11
|
Scene IDs should be: "intro", "problems", "solutions", "metrics", "cta".
|
|
65
|
-
Only include segments that are relevant to the brief content.`,
|
|
66
|
-
description: "Script generator LLM system prompt",
|
|
67
|
-
placeholders: [{ name: "styleGuide", type: "string" }]
|
|
68
|
-
},
|
|
69
|
-
"prompt.scenePlanner.system": {
|
|
70
|
-
value: `You are a video scene planner for ContractSpec marketing/documentation videos.
|
|
12
|
+
Only include segments that are relevant to the brief content.`,description:"Script generator LLM system prompt",placeholders:[{name:"styleGuide",type:"string"}]},"prompt.scenePlanner.system":{value:`You are a video scene planner for ContractSpec marketing/documentation videos.
|
|
71
13
|
Given a content brief, break it into video scenes.
|
|
72
14
|
|
|
73
15
|
Each scene must have:
|
|
@@ -83,125 +25,7 @@ Return a JSON object with shape:
|
|
|
83
25
|
}
|
|
84
26
|
|
|
85
27
|
Keep the total duration around {targetSeconds} seconds.
|
|
86
|
-
Prioritize clarity and pacing. Each scene should communicate one idea.`,
|
|
87
|
-
description: "Scene planner LLM system prompt",
|
|
88
|
-
placeholders: [
|
|
89
|
-
{ name: "fps", type: "number" },
|
|
90
|
-
{ name: "targetSeconds", type: "number" }
|
|
91
|
-
]
|
|
92
|
-
},
|
|
93
|
-
"prompt.style.professional": {
|
|
94
|
-
value: "Use a clear, authoritative, professional tone. Be concise and direct.",
|
|
95
|
-
description: "Style guide for professional narration"
|
|
96
|
-
},
|
|
97
|
-
"prompt.style.casual": {
|
|
98
|
-
value: "Use a friendly, conversational tone. Be approachable and relatable.",
|
|
99
|
-
description: "Style guide for casual narration"
|
|
100
|
-
},
|
|
101
|
-
"prompt.style.technical": {
|
|
102
|
-
value: "Use precise technical language. Be detailed and accurate.",
|
|
103
|
-
description: "Style guide for technical narration"
|
|
104
|
-
},
|
|
105
|
-
"script.segment.challenge": {
|
|
106
|
-
value: "The challenge: {content}",
|
|
107
|
-
description: "Narration segment prefix for problems",
|
|
108
|
-
placeholders: [{ name: "content", type: "string" }]
|
|
109
|
-
},
|
|
110
|
-
"script.segment.solution": {
|
|
111
|
-
value: "The solution: {content}",
|
|
112
|
-
description: "Narration segment prefix for solutions",
|
|
113
|
-
placeholders: [{ name: "content", type: "string" }]
|
|
114
|
-
},
|
|
115
|
-
"script.segment.results": {
|
|
116
|
-
value: "The results: {content}",
|
|
117
|
-
description: "Narration segment prefix for metrics",
|
|
118
|
-
placeholders: [{ name: "content", type: "string" }]
|
|
119
|
-
},
|
|
120
|
-
"scene.cta.default": {
|
|
121
|
-
value: "Learn more",
|
|
122
|
-
description: "Default call-to-action text for scenes"
|
|
123
|
-
},
|
|
124
|
-
"scene.hook.problem": {
|
|
125
|
-
value: "The Problem",
|
|
126
|
-
description: "Scene hook label for problem statement"
|
|
127
|
-
},
|
|
128
|
-
"scene.narration.problem": {
|
|
129
|
-
value: "The problem: {content}",
|
|
130
|
-
description: "Scene narration for problem statement",
|
|
131
|
-
placeholders: [{ name: "content", type: "string" }]
|
|
132
|
-
},
|
|
133
|
-
"scene.hook.solution": {
|
|
134
|
-
value: "The Solution",
|
|
135
|
-
description: "Scene hook label for solution"
|
|
136
|
-
},
|
|
137
|
-
"scene.narration.solution": {
|
|
138
|
-
value: "The solution: {content}",
|
|
139
|
-
description: "Scene narration for solution",
|
|
140
|
-
placeholders: [{ name: "content", type: "string" }]
|
|
141
|
-
},
|
|
142
|
-
"scene.hook.results": {
|
|
143
|
-
value: "Results",
|
|
144
|
-
description: "Scene hook label for results/metrics"
|
|
145
|
-
},
|
|
146
|
-
"composition.apiOverview.generates": {
|
|
147
|
-
value: "Generates:",
|
|
148
|
-
description: "ApiOverview heading for generated outputs"
|
|
149
|
-
},
|
|
150
|
-
"composition.apiOverview.tagline": {
|
|
151
|
-
value: "One spec. Every surface.",
|
|
152
|
-
description: "ApiOverview default tagline"
|
|
153
|
-
},
|
|
154
|
-
"composition.apiOverview.output.rest": {
|
|
155
|
-
value: "REST Endpoint",
|
|
156
|
-
description: "Generated output label: REST"
|
|
157
|
-
},
|
|
158
|
-
"composition.apiOverview.output.graphql": {
|
|
159
|
-
value: "GraphQL Mutation",
|
|
160
|
-
description: "Generated output label: GraphQL"
|
|
161
|
-
},
|
|
162
|
-
"composition.apiOverview.output.prisma": {
|
|
163
|
-
value: "Prisma Model",
|
|
164
|
-
description: "Generated output label: Prisma"
|
|
165
|
-
},
|
|
166
|
-
"composition.apiOverview.output.typescript": {
|
|
167
|
-
value: "TypeScript SDK",
|
|
168
|
-
description: "Generated output label: TypeScript SDK"
|
|
169
|
-
},
|
|
170
|
-
"composition.apiOverview.output.mcp": {
|
|
171
|
-
value: "MCP Tool",
|
|
172
|
-
description: "Generated output label: MCP Tool"
|
|
173
|
-
},
|
|
174
|
-
"composition.apiOverview.output.openapi": {
|
|
175
|
-
value: "OpenAPI Spec",
|
|
176
|
-
description: "Generated output label: OpenAPI"
|
|
177
|
-
},
|
|
178
|
-
"composition.socialClip.cta": {
|
|
179
|
-
value: "Learn more",
|
|
180
|
-
description: "SocialClip default CTA"
|
|
181
|
-
},
|
|
182
|
-
"composition.terminal.title": {
|
|
183
|
-
value: "Terminal",
|
|
184
|
-
description: "TerminalDemo default window title"
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
// src/i18n/catalogs/es.ts
|
|
190
|
-
import { defineTranslation as defineTranslation2 } from "@contractspec/lib.contracts-spec/translations";
|
|
191
|
-
var esMessages = defineTranslation2({
|
|
192
|
-
meta: {
|
|
193
|
-
key: "video-gen.messages",
|
|
194
|
-
version: "1.0.0",
|
|
195
|
-
domain: "video-gen",
|
|
196
|
-
description: "Spanish translations for the video-gen package",
|
|
197
|
-
owners: ["platform"],
|
|
198
|
-
stability: "experimental"
|
|
199
|
-
},
|
|
200
|
-
locale: "es",
|
|
201
|
-
fallback: "en",
|
|
202
|
-
messages: {
|
|
203
|
-
"prompt.script.system": {
|
|
204
|
-
value: `Eres un redactor de guiones de narración para vídeo.
|
|
28
|
+
Prioritize clarity and pacing. Each scene should communicate one idea.`,description:"Scene planner LLM system prompt",placeholders:[{name:"fps",type:"number"},{name:"targetSeconds",type:"number"}]},"prompt.style.professional":{value:"Use a clear, authoritative, professional tone. Be concise and direct.",description:"Style guide for professional narration"},"prompt.style.casual":{value:"Use a friendly, conversational tone. Be approachable and relatable.",description:"Style guide for casual narration"},"prompt.style.technical":{value:"Use precise technical language. Be detailed and accurate.",description:"Style guide for technical narration"},"script.segment.challenge":{value:"The challenge: {content}",description:"Narration segment prefix for problems",placeholders:[{name:"content",type:"string"}]},"script.segment.solution":{value:"The solution: {content}",description:"Narration segment prefix for solutions",placeholders:[{name:"content",type:"string"}]},"script.segment.results":{value:"The results: {content}",description:"Narration segment prefix for metrics",placeholders:[{name:"content",type:"string"}]},"scene.cta.default":{value:"Learn more",description:"Default call-to-action text for scenes"},"scene.hook.problem":{value:"The Problem",description:"Scene hook label for problem statement"},"scene.narration.problem":{value:"The problem: {content}",description:"Scene narration for problem statement",placeholders:[{name:"content",type:"string"}]},"scene.hook.solution":{value:"The Solution",description:"Scene hook label for solution"},"scene.narration.solution":{value:"The solution: {content}",description:"Scene narration for solution",placeholders:[{name:"content",type:"string"}]},"scene.hook.results":{value:"Results",description:"Scene hook label for results/metrics"},"composition.apiOverview.generates":{value:"Generates:",description:"ApiOverview heading for generated outputs"},"composition.apiOverview.tagline":{value:"One spec. Every surface.",description:"ApiOverview default tagline"},"composition.apiOverview.output.rest":{value:"REST Endpoint",description:"Generated output label: REST"},"composition.apiOverview.output.graphql":{value:"GraphQL Mutation",description:"Generated output label: GraphQL"},"composition.apiOverview.output.prisma":{value:"Prisma Model",description:"Generated output label: Prisma"},"composition.apiOverview.output.typescript":{value:"TypeScript SDK",description:"Generated output label: TypeScript SDK"},"composition.apiOverview.output.mcp":{value:"MCP Tool",description:"Generated output label: MCP Tool"},"composition.apiOverview.output.openapi":{value:"OpenAPI Spec",description:"Generated output label: OpenAPI"},"composition.socialClip.cta":{value:"Learn more",description:"SocialClip default CTA"},"composition.terminal.title":{value:"Terminal",description:"TerminalDemo default window title"}}});import{defineTranslation as v}from"@contractspec/lib.contracts-spec/translations";var I=v({meta:{key:"video-gen.messages",version:"1.0.0",domain:"video-gen",description:"Spanish translations for the video-gen package",owners:["platform"],stability:"experimental"},locale:"es",fallback:"en",messages:{"prompt.script.system":{value:`Eres un redactor de guiones de narración para vídeo.
|
|
205
29
|
Escribe un guión de narración para un vídeo corto (30-60 segundos).
|
|
206
30
|
{styleGuide}
|
|
207
31
|
|
|
@@ -212,12 +36,7 @@ Devuelve JSON con la forma:
|
|
|
212
36
|
}
|
|
213
37
|
|
|
214
38
|
Los identificadores de escena deben ser: "intro", "problems", "solutions", "metrics", "cta".
|
|
215
|
-
Incluye solo los segmentos relevantes para el brief.`,
|
|
216
|
-
description: "Script generator LLM system prompt",
|
|
217
|
-
placeholders: [{ name: "styleGuide", type: "string" }]
|
|
218
|
-
},
|
|
219
|
-
"prompt.scenePlanner.system": {
|
|
220
|
-
value: `Eres un planificador de escenas de vídeo para vídeos de marketing/documentación de ContractSpec.
|
|
39
|
+
Incluye solo los segmentos relevantes para el brief.`,description:"Script generator LLM system prompt",placeholders:[{name:"styleGuide",type:"string"}]},"prompt.scenePlanner.system":{value:`Eres un planificador de escenas de vídeo para vídeos de marketing/documentación de ContractSpec.
|
|
221
40
|
Dado un brief de contenido, divídelo en escenas de vídeo.
|
|
222
41
|
|
|
223
42
|
Cada escena debe tener:
|
|
@@ -233,125 +52,7 @@ Devuelve un objeto JSON con la forma:
|
|
|
233
52
|
}
|
|
234
53
|
|
|
235
54
|
Mantén la duración total alrededor de {targetSeconds} segundos.
|
|
236
|
-
Prioriza la claridad y el ritmo. Cada escena debe comunicar una idea.`,
|
|
237
|
-
description: "Scene planner LLM system prompt",
|
|
238
|
-
placeholders: [
|
|
239
|
-
{ name: "fps", type: "number" },
|
|
240
|
-
{ name: "targetSeconds", type: "number" }
|
|
241
|
-
]
|
|
242
|
-
},
|
|
243
|
-
"prompt.style.professional": {
|
|
244
|
-
value: "Usa un tono claro, autoritario y profesional. Sé conciso y directo.",
|
|
245
|
-
description: "Style guide for professional narration"
|
|
246
|
-
},
|
|
247
|
-
"prompt.style.casual": {
|
|
248
|
-
value: "Usa un tono amigable y conversacional. Sé accesible y cercano.",
|
|
249
|
-
description: "Style guide for casual narration"
|
|
250
|
-
},
|
|
251
|
-
"prompt.style.technical": {
|
|
252
|
-
value: "Usa un lenguaje técnico preciso. Sé detallado y exacto.",
|
|
253
|
-
description: "Style guide for technical narration"
|
|
254
|
-
},
|
|
255
|
-
"script.segment.challenge": {
|
|
256
|
-
value: "El desafío: {content}",
|
|
257
|
-
description: "Narration segment prefix for problems",
|
|
258
|
-
placeholders: [{ name: "content", type: "string" }]
|
|
259
|
-
},
|
|
260
|
-
"script.segment.solution": {
|
|
261
|
-
value: "La solución: {content}",
|
|
262
|
-
description: "Narration segment prefix for solutions",
|
|
263
|
-
placeholders: [{ name: "content", type: "string" }]
|
|
264
|
-
},
|
|
265
|
-
"script.segment.results": {
|
|
266
|
-
value: "Los resultados: {content}",
|
|
267
|
-
description: "Narration segment prefix for metrics",
|
|
268
|
-
placeholders: [{ name: "content", type: "string" }]
|
|
269
|
-
},
|
|
270
|
-
"scene.cta.default": {
|
|
271
|
-
value: "Más información",
|
|
272
|
-
description: "Default call-to-action text for scenes"
|
|
273
|
-
},
|
|
274
|
-
"scene.hook.problem": {
|
|
275
|
-
value: "El problema",
|
|
276
|
-
description: "Scene hook label for problem statement"
|
|
277
|
-
},
|
|
278
|
-
"scene.narration.problem": {
|
|
279
|
-
value: "El problema: {content}",
|
|
280
|
-
description: "Scene narration for problem statement",
|
|
281
|
-
placeholders: [{ name: "content", type: "string" }]
|
|
282
|
-
},
|
|
283
|
-
"scene.hook.solution": {
|
|
284
|
-
value: "La solución",
|
|
285
|
-
description: "Scene hook label for solution"
|
|
286
|
-
},
|
|
287
|
-
"scene.narration.solution": {
|
|
288
|
-
value: "La solución: {content}",
|
|
289
|
-
description: "Scene narration for solution",
|
|
290
|
-
placeholders: [{ name: "content", type: "string" }]
|
|
291
|
-
},
|
|
292
|
-
"scene.hook.results": {
|
|
293
|
-
value: "Resultados",
|
|
294
|
-
description: "Scene hook label for results/metrics"
|
|
295
|
-
},
|
|
296
|
-
"composition.apiOverview.generates": {
|
|
297
|
-
value: "Genera:",
|
|
298
|
-
description: "ApiOverview heading for generated outputs"
|
|
299
|
-
},
|
|
300
|
-
"composition.apiOverview.tagline": {
|
|
301
|
-
value: "Una spec. Todas las superficies.",
|
|
302
|
-
description: "ApiOverview default tagline"
|
|
303
|
-
},
|
|
304
|
-
"composition.apiOverview.output.rest": {
|
|
305
|
-
value: "Endpoint REST",
|
|
306
|
-
description: "Generated output label: REST"
|
|
307
|
-
},
|
|
308
|
-
"composition.apiOverview.output.graphql": {
|
|
309
|
-
value: "Mutación GraphQL",
|
|
310
|
-
description: "Generated output label: GraphQL"
|
|
311
|
-
},
|
|
312
|
-
"composition.apiOverview.output.prisma": {
|
|
313
|
-
value: "Modelo Prisma",
|
|
314
|
-
description: "Generated output label: Prisma"
|
|
315
|
-
},
|
|
316
|
-
"composition.apiOverview.output.typescript": {
|
|
317
|
-
value: "SDK TypeScript",
|
|
318
|
-
description: "Generated output label: TypeScript SDK"
|
|
319
|
-
},
|
|
320
|
-
"composition.apiOverview.output.mcp": {
|
|
321
|
-
value: "Herramienta MCP",
|
|
322
|
-
description: "Generated output label: MCP Tool"
|
|
323
|
-
},
|
|
324
|
-
"composition.apiOverview.output.openapi": {
|
|
325
|
-
value: "Spec OpenAPI",
|
|
326
|
-
description: "Generated output label: OpenAPI"
|
|
327
|
-
},
|
|
328
|
-
"composition.socialClip.cta": {
|
|
329
|
-
value: "Más información",
|
|
330
|
-
description: "SocialClip default CTA"
|
|
331
|
-
},
|
|
332
|
-
"composition.terminal.title": {
|
|
333
|
-
value: "Terminal",
|
|
334
|
-
description: "TerminalDemo default window title"
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
// src/i18n/catalogs/fr.ts
|
|
340
|
-
import { defineTranslation as defineTranslation3 } from "@contractspec/lib.contracts-spec/translations";
|
|
341
|
-
var frMessages = defineTranslation3({
|
|
342
|
-
meta: {
|
|
343
|
-
key: "video-gen.messages",
|
|
344
|
-
version: "1.0.0",
|
|
345
|
-
domain: "video-gen",
|
|
346
|
-
description: "French translations for the video-gen package",
|
|
347
|
-
owners: ["platform"],
|
|
348
|
-
stability: "experimental"
|
|
349
|
-
},
|
|
350
|
-
locale: "fr",
|
|
351
|
-
fallback: "en",
|
|
352
|
-
messages: {
|
|
353
|
-
"prompt.script.system": {
|
|
354
|
-
value: `Vous êtes un rédacteur de scripts de narration vidéo.
|
|
55
|
+
Prioriza la claridad y el ritmo. Cada escena debe comunicar una idea.`,description:"Scene planner LLM system prompt",placeholders:[{name:"fps",type:"number"},{name:"targetSeconds",type:"number"}]},"prompt.style.professional":{value:"Usa un tono claro, autoritario y profesional. Sé conciso y directo.",description:"Style guide for professional narration"},"prompt.style.casual":{value:"Usa un tono amigable y conversacional. Sé accesible y cercano.",description:"Style guide for casual narration"},"prompt.style.technical":{value:"Usa un lenguaje técnico preciso. Sé detallado y exacto.",description:"Style guide for technical narration"},"script.segment.challenge":{value:"El desafío: {content}",description:"Narration segment prefix for problems",placeholders:[{name:"content",type:"string"}]},"script.segment.solution":{value:"La solución: {content}",description:"Narration segment prefix for solutions",placeholders:[{name:"content",type:"string"}]},"script.segment.results":{value:"Los resultados: {content}",description:"Narration segment prefix for metrics",placeholders:[{name:"content",type:"string"}]},"scene.cta.default":{value:"Más información",description:"Default call-to-action text for scenes"},"scene.hook.problem":{value:"El problema",description:"Scene hook label for problem statement"},"scene.narration.problem":{value:"El problema: {content}",description:"Scene narration for problem statement",placeholders:[{name:"content",type:"string"}]},"scene.hook.solution":{value:"La solución",description:"Scene hook label for solution"},"scene.narration.solution":{value:"La solución: {content}",description:"Scene narration for solution",placeholders:[{name:"content",type:"string"}]},"scene.hook.results":{value:"Resultados",description:"Scene hook label for results/metrics"},"composition.apiOverview.generates":{value:"Genera:",description:"ApiOverview heading for generated outputs"},"composition.apiOverview.tagline":{value:"Una spec. Todas las superficies.",description:"ApiOverview default tagline"},"composition.apiOverview.output.rest":{value:"Endpoint REST",description:"Generated output label: REST"},"composition.apiOverview.output.graphql":{value:"Mutación GraphQL",description:"Generated output label: GraphQL"},"composition.apiOverview.output.prisma":{value:"Modelo Prisma",description:"Generated output label: Prisma"},"composition.apiOverview.output.typescript":{value:"SDK TypeScript",description:"Generated output label: TypeScript SDK"},"composition.apiOverview.output.mcp":{value:"Herramienta MCP",description:"Generated output label: MCP Tool"},"composition.apiOverview.output.openapi":{value:"Spec OpenAPI",description:"Generated output label: OpenAPI"},"composition.socialClip.cta":{value:"Más información",description:"SocialClip default CTA"},"composition.terminal.title":{value:"Terminal",description:"TerminalDemo default window title"}}});import{defineTranslation as A}from"@contractspec/lib.contracts-spec/translations";var V=A({meta:{key:"video-gen.messages",version:"1.0.0",domain:"video-gen",description:"French translations for the video-gen package",owners:["platform"],stability:"experimental"},locale:"fr",fallback:"en",messages:{"prompt.script.system":{value:`Vous êtes un rédacteur de scripts de narration vidéo.
|
|
355
56
|
Écrivez un script de narration pour une courte vidéo (30-60 secondes).
|
|
356
57
|
{styleGuide}
|
|
357
58
|
|
|
@@ -362,12 +63,7 @@ Retournez du JSON avec la forme :
|
|
|
362
63
|
}
|
|
363
64
|
|
|
364
65
|
Les identifiants de scène doivent être : "intro", "problems", "solutions", "metrics", "cta".
|
|
365
|
-
N'incluez que les segments pertinents au brief.`,
|
|
366
|
-
description: "Script generator LLM system prompt",
|
|
367
|
-
placeholders: [{ name: "styleGuide", type: "string" }]
|
|
368
|
-
},
|
|
369
|
-
"prompt.scenePlanner.system": {
|
|
370
|
-
value: `Vous êtes un planificateur de scènes vidéo pour les vidéos marketing/documentation de ContractSpec.
|
|
66
|
+
N'incluez que les segments pertinents au brief.`,description:"Script generator LLM system prompt",placeholders:[{name:"styleGuide",type:"string"}]},"prompt.scenePlanner.system":{value:`Vous êtes un planificateur de scènes vidéo pour les vidéos marketing/documentation de ContractSpec.
|
|
371
67
|
À partir d'un brief, décomposez-le en scènes vidéo.
|
|
372
68
|
|
|
373
69
|
Chaque scène doit avoir :
|
|
@@ -383,456 +79,4 @@ Retournez un objet JSON avec la forme :
|
|
|
383
79
|
}
|
|
384
80
|
|
|
385
81
|
Gardez la durée totale autour de {targetSeconds} secondes.
|
|
386
|
-
Privilégiez la clarté et le rythme. Chaque scène doit communiquer une idée.`,
|
|
387
|
-
description: "Scene planner LLM system prompt",
|
|
388
|
-
placeholders: [
|
|
389
|
-
{ name: "fps", type: "number" },
|
|
390
|
-
{ name: "targetSeconds", type: "number" }
|
|
391
|
-
]
|
|
392
|
-
},
|
|
393
|
-
"prompt.style.professional": {
|
|
394
|
-
value: "Utilisez un ton clair, autoritaire et professionnel. Soyez concis et direct.",
|
|
395
|
-
description: "Style guide for professional narration"
|
|
396
|
-
},
|
|
397
|
-
"prompt.style.casual": {
|
|
398
|
-
value: "Utilisez un ton amical et conversationnel. Soyez accessible et proche.",
|
|
399
|
-
description: "Style guide for casual narration"
|
|
400
|
-
},
|
|
401
|
-
"prompt.style.technical": {
|
|
402
|
-
value: "Utilisez un langage technique précis. Soyez détaillé et exact.",
|
|
403
|
-
description: "Style guide for technical narration"
|
|
404
|
-
},
|
|
405
|
-
"script.segment.challenge": {
|
|
406
|
-
value: "Le défi : {content}",
|
|
407
|
-
description: "Narration segment prefix for problems",
|
|
408
|
-
placeholders: [{ name: "content", type: "string" }]
|
|
409
|
-
},
|
|
410
|
-
"script.segment.solution": {
|
|
411
|
-
value: "La solution : {content}",
|
|
412
|
-
description: "Narration segment prefix for solutions",
|
|
413
|
-
placeholders: [{ name: "content", type: "string" }]
|
|
414
|
-
},
|
|
415
|
-
"script.segment.results": {
|
|
416
|
-
value: "Les résultats : {content}",
|
|
417
|
-
description: "Narration segment prefix for metrics",
|
|
418
|
-
placeholders: [{ name: "content", type: "string" }]
|
|
419
|
-
},
|
|
420
|
-
"scene.cta.default": {
|
|
421
|
-
value: "En savoir plus",
|
|
422
|
-
description: "Default call-to-action text for scenes"
|
|
423
|
-
},
|
|
424
|
-
"scene.hook.problem": {
|
|
425
|
-
value: "Le problème",
|
|
426
|
-
description: "Scene hook label for problem statement"
|
|
427
|
-
},
|
|
428
|
-
"scene.narration.problem": {
|
|
429
|
-
value: "Le problème : {content}",
|
|
430
|
-
description: "Scene narration for problem statement",
|
|
431
|
-
placeholders: [{ name: "content", type: "string" }]
|
|
432
|
-
},
|
|
433
|
-
"scene.hook.solution": {
|
|
434
|
-
value: "La solution",
|
|
435
|
-
description: "Scene hook label for solution"
|
|
436
|
-
},
|
|
437
|
-
"scene.narration.solution": {
|
|
438
|
-
value: "La solution : {content}",
|
|
439
|
-
description: "Scene narration for solution",
|
|
440
|
-
placeholders: [{ name: "content", type: "string" }]
|
|
441
|
-
},
|
|
442
|
-
"scene.hook.results": {
|
|
443
|
-
value: "Résultats",
|
|
444
|
-
description: "Scene hook label for results/metrics"
|
|
445
|
-
},
|
|
446
|
-
"composition.apiOverview.generates": {
|
|
447
|
-
value: "Génère :",
|
|
448
|
-
description: "ApiOverview heading for generated outputs"
|
|
449
|
-
},
|
|
450
|
-
"composition.apiOverview.tagline": {
|
|
451
|
-
value: "Un spec. Toutes les surfaces.",
|
|
452
|
-
description: "ApiOverview default tagline"
|
|
453
|
-
},
|
|
454
|
-
"composition.apiOverview.output.rest": {
|
|
455
|
-
value: "Endpoint REST",
|
|
456
|
-
description: "Generated output label: REST"
|
|
457
|
-
},
|
|
458
|
-
"composition.apiOverview.output.graphql": {
|
|
459
|
-
value: "Mutation GraphQL",
|
|
460
|
-
description: "Generated output label: GraphQL"
|
|
461
|
-
},
|
|
462
|
-
"composition.apiOverview.output.prisma": {
|
|
463
|
-
value: "Modèle Prisma",
|
|
464
|
-
description: "Generated output label: Prisma"
|
|
465
|
-
},
|
|
466
|
-
"composition.apiOverview.output.typescript": {
|
|
467
|
-
value: "SDK TypeScript",
|
|
468
|
-
description: "Generated output label: TypeScript SDK"
|
|
469
|
-
},
|
|
470
|
-
"composition.apiOverview.output.mcp": {
|
|
471
|
-
value: "Outil MCP",
|
|
472
|
-
description: "Generated output label: MCP Tool"
|
|
473
|
-
},
|
|
474
|
-
"composition.apiOverview.output.openapi": {
|
|
475
|
-
value: "Spec OpenAPI",
|
|
476
|
-
description: "Generated output label: OpenAPI"
|
|
477
|
-
},
|
|
478
|
-
"composition.socialClip.cta": {
|
|
479
|
-
value: "En savoir plus",
|
|
480
|
-
description: "SocialClip default CTA"
|
|
481
|
-
},
|
|
482
|
-
"composition.terminal.title": {
|
|
483
|
-
value: "Terminal",
|
|
484
|
-
description: "TerminalDemo default window title"
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
});
|
|
488
|
-
|
|
489
|
-
// src/i18n/keys.ts
|
|
490
|
-
var PROMPT_KEYS = {
|
|
491
|
-
"prompt.script.system": "prompt.script.system",
|
|
492
|
-
"prompt.scenePlanner.system": "prompt.scenePlanner.system",
|
|
493
|
-
"prompt.style.professional": "prompt.style.professional",
|
|
494
|
-
"prompt.style.casual": "prompt.style.casual",
|
|
495
|
-
"prompt.style.technical": "prompt.style.technical"
|
|
496
|
-
};
|
|
497
|
-
var SCRIPT_KEYS = {
|
|
498
|
-
"script.segment.challenge": "script.segment.challenge",
|
|
499
|
-
"script.segment.solution": "script.segment.solution",
|
|
500
|
-
"script.segment.results": "script.segment.results"
|
|
501
|
-
};
|
|
502
|
-
var SCENE_KEYS = {
|
|
503
|
-
"scene.cta.default": "scene.cta.default",
|
|
504
|
-
"scene.hook.problem": "scene.hook.problem",
|
|
505
|
-
"scene.narration.problem": "scene.narration.problem",
|
|
506
|
-
"scene.hook.solution": "scene.hook.solution",
|
|
507
|
-
"scene.narration.solution": "scene.narration.solution",
|
|
508
|
-
"scene.hook.results": "scene.hook.results"
|
|
509
|
-
};
|
|
510
|
-
var COMPOSITION_KEYS = {
|
|
511
|
-
"composition.apiOverview.generates": "composition.apiOverview.generates",
|
|
512
|
-
"composition.apiOverview.tagline": "composition.apiOverview.tagline",
|
|
513
|
-
"composition.apiOverview.output.rest": "composition.apiOverview.output.rest",
|
|
514
|
-
"composition.apiOverview.output.graphql": "composition.apiOverview.output.graphql",
|
|
515
|
-
"composition.apiOverview.output.prisma": "composition.apiOverview.output.prisma",
|
|
516
|
-
"composition.apiOverview.output.typescript": "composition.apiOverview.output.typescript",
|
|
517
|
-
"composition.apiOverview.output.mcp": "composition.apiOverview.output.mcp",
|
|
518
|
-
"composition.apiOverview.output.openapi": "composition.apiOverview.output.openapi",
|
|
519
|
-
"composition.socialClip.cta": "composition.socialClip.cta",
|
|
520
|
-
"composition.terminal.title": "composition.terminal.title"
|
|
521
|
-
};
|
|
522
|
-
var I18N_KEYS = {
|
|
523
|
-
...PROMPT_KEYS,
|
|
524
|
-
...SCRIPT_KEYS,
|
|
525
|
-
...SCENE_KEYS,
|
|
526
|
-
...COMPOSITION_KEYS
|
|
527
|
-
};
|
|
528
|
-
|
|
529
|
-
// src/i18n/locale.ts
|
|
530
|
-
import {
|
|
531
|
-
DEFAULT_LOCALE,
|
|
532
|
-
isSupportedLocale,
|
|
533
|
-
resolveLocale,
|
|
534
|
-
SUPPORTED_LOCALES
|
|
535
|
-
} from "@contractspec/lib.contracts-spec/translations";
|
|
536
|
-
|
|
537
|
-
// src/i18n/messages.ts
|
|
538
|
-
import {
|
|
539
|
-
createI18nFactory
|
|
540
|
-
} from "@contractspec/lib.contracts-spec/translations";
|
|
541
|
-
var factory = createI18nFactory({
|
|
542
|
-
specKey: "video-gen.messages",
|
|
543
|
-
catalogs: [enMessages, frMessages, esMessages]
|
|
544
|
-
});
|
|
545
|
-
var createVideoGenI18n = factory.create;
|
|
546
|
-
var getDefaultI18n = factory.getDefault;
|
|
547
|
-
var resetI18nRegistry = factory.resetRegistry;
|
|
548
|
-
// src/generators/scene-planner.ts
|
|
549
|
-
class ScenePlanner {
|
|
550
|
-
llm;
|
|
551
|
-
model;
|
|
552
|
-
temperature;
|
|
553
|
-
fps;
|
|
554
|
-
i18n;
|
|
555
|
-
modelSelector;
|
|
556
|
-
selectionContext;
|
|
557
|
-
constructor(options) {
|
|
558
|
-
this.llm = options?.llm;
|
|
559
|
-
this.model = options?.model;
|
|
560
|
-
this.temperature = options?.temperature ?? 0.3;
|
|
561
|
-
this.fps = options?.fps ?? DEFAULT_FPS;
|
|
562
|
-
this.i18n = createVideoGenI18n(options?.locale);
|
|
563
|
-
this.modelSelector = options?.modelSelector;
|
|
564
|
-
this.selectionContext = options?.selectionContext;
|
|
565
|
-
}
|
|
566
|
-
async plan(brief) {
|
|
567
|
-
if (this.llm) {
|
|
568
|
-
return this.planWithLlm(brief);
|
|
569
|
-
}
|
|
570
|
-
return this.planDeterministic(brief);
|
|
571
|
-
}
|
|
572
|
-
planDeterministic(brief) {
|
|
573
|
-
const { content } = brief;
|
|
574
|
-
const { t } = this.i18n;
|
|
575
|
-
const scenes = [];
|
|
576
|
-
const fps = this.fps;
|
|
577
|
-
scenes.push({
|
|
578
|
-
compositionId: "SocialClip",
|
|
579
|
-
props: {
|
|
580
|
-
hook: content.title,
|
|
581
|
-
message: content.summary,
|
|
582
|
-
points: content.solutions.slice(0, 3),
|
|
583
|
-
cta: content.callToAction ?? t("scene.cta.default")
|
|
584
|
-
},
|
|
585
|
-
durationInFrames: 3 * fps,
|
|
586
|
-
narrationText: `${content.title}. ${content.summary}`
|
|
587
|
-
});
|
|
588
|
-
if (content.problems.length > 0) {
|
|
589
|
-
scenes.push({
|
|
590
|
-
compositionId: "SocialClip",
|
|
591
|
-
props: {
|
|
592
|
-
hook: t("scene.hook.problem"),
|
|
593
|
-
message: content.problems[0] ?? "",
|
|
594
|
-
points: content.problems.slice(1, 4)
|
|
595
|
-
},
|
|
596
|
-
durationInFrames: 4 * fps,
|
|
597
|
-
narrationText: t("scene.narration.problem", {
|
|
598
|
-
content: content.problems.join(". ")
|
|
599
|
-
})
|
|
600
|
-
});
|
|
601
|
-
}
|
|
602
|
-
if (content.solutions.length > 0) {
|
|
603
|
-
scenes.push({
|
|
604
|
-
compositionId: "SocialClip",
|
|
605
|
-
props: {
|
|
606
|
-
hook: t("scene.hook.solution"),
|
|
607
|
-
message: content.solutions[0] ?? "",
|
|
608
|
-
points: content.solutions.slice(1, 4)
|
|
609
|
-
},
|
|
610
|
-
durationInFrames: 5 * fps,
|
|
611
|
-
narrationText: t("scene.narration.solution", {
|
|
612
|
-
content: content.solutions.join(". ")
|
|
613
|
-
})
|
|
614
|
-
});
|
|
615
|
-
}
|
|
616
|
-
if (content.metrics && content.metrics.length > 0) {
|
|
617
|
-
scenes.push({
|
|
618
|
-
compositionId: "SocialClip",
|
|
619
|
-
props: {
|
|
620
|
-
hook: t("scene.hook.results"),
|
|
621
|
-
message: content.metrics[0] ?? "",
|
|
622
|
-
points: content.metrics.slice(1, 3)
|
|
623
|
-
},
|
|
624
|
-
durationInFrames: 3 * fps,
|
|
625
|
-
narrationText: content.metrics.join(". ")
|
|
626
|
-
});
|
|
627
|
-
}
|
|
628
|
-
if (content.callToAction) {
|
|
629
|
-
scenes.push({
|
|
630
|
-
compositionId: "SocialClip",
|
|
631
|
-
props: {
|
|
632
|
-
hook: content.callToAction,
|
|
633
|
-
message: "",
|
|
634
|
-
cta: content.callToAction
|
|
635
|
-
},
|
|
636
|
-
durationInFrames: 2 * fps,
|
|
637
|
-
narrationText: content.callToAction
|
|
638
|
-
});
|
|
639
|
-
}
|
|
640
|
-
if (brief.targetDurationSeconds) {
|
|
641
|
-
const targetFrames = brief.targetDurationSeconds * fps;
|
|
642
|
-
const currentFrames = scenes.reduce((sum, s) => sum + s.durationInFrames, 0);
|
|
643
|
-
const ratio = targetFrames / currentFrames;
|
|
644
|
-
for (const scene of scenes) {
|
|
645
|
-
scene.durationInFrames = Math.round(scene.durationInFrames * ratio);
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
const totalDuration = scenes.reduce((sum, s) => sum + s.durationInFrames, 0);
|
|
649
|
-
const narrationScript = scenes.filter((s) => s.narrationText).map((s) => s.narrationText).join(" ");
|
|
650
|
-
return {
|
|
651
|
-
scenes,
|
|
652
|
-
estimatedDurationSeconds: totalDuration / fps,
|
|
653
|
-
narrationScript
|
|
654
|
-
};
|
|
655
|
-
}
|
|
656
|
-
async resolveModel() {
|
|
657
|
-
if (this.model)
|
|
658
|
-
return this.model;
|
|
659
|
-
if (this.modelSelector) {
|
|
660
|
-
const ctx = this.selectionContext ?? {
|
|
661
|
-
taskDimension: "reasoning"
|
|
662
|
-
};
|
|
663
|
-
const result = await this.modelSelector.select(ctx);
|
|
664
|
-
return result.modelId;
|
|
665
|
-
}
|
|
666
|
-
return;
|
|
667
|
-
}
|
|
668
|
-
async planWithLlm(brief) {
|
|
669
|
-
const { t } = this.i18n;
|
|
670
|
-
const messages = [
|
|
671
|
-
{
|
|
672
|
-
role: "system",
|
|
673
|
-
content: [
|
|
674
|
-
{
|
|
675
|
-
type: "text",
|
|
676
|
-
text: t("prompt.scenePlanner.system", {
|
|
677
|
-
fps: this.fps,
|
|
678
|
-
targetSeconds: brief.targetDurationSeconds ?? 30
|
|
679
|
-
})
|
|
680
|
-
}
|
|
681
|
-
]
|
|
682
|
-
},
|
|
683
|
-
{
|
|
684
|
-
role: "user",
|
|
685
|
-
content: [
|
|
686
|
-
{
|
|
687
|
-
type: "text",
|
|
688
|
-
text: JSON.stringify(brief.content)
|
|
689
|
-
}
|
|
690
|
-
]
|
|
691
|
-
}
|
|
692
|
-
];
|
|
693
|
-
if (!this.llm) {
|
|
694
|
-
return this.planDeterministic(brief);
|
|
695
|
-
}
|
|
696
|
-
try {
|
|
697
|
-
const model = await this.resolveModel();
|
|
698
|
-
const response = await this.llm.chat(messages, {
|
|
699
|
-
model,
|
|
700
|
-
temperature: this.temperature,
|
|
701
|
-
responseFormat: "json"
|
|
702
|
-
});
|
|
703
|
-
const text = response.message.content.find((p) => p.type === "text");
|
|
704
|
-
if (!text || text.type !== "text") {
|
|
705
|
-
return this.planDeterministic(brief);
|
|
706
|
-
}
|
|
707
|
-
const parsed = JSON.parse(text.text);
|
|
708
|
-
const totalDuration = parsed.scenes.reduce((sum, s) => sum + s.durationInFrames, 0);
|
|
709
|
-
return {
|
|
710
|
-
scenes: parsed.scenes,
|
|
711
|
-
estimatedDurationSeconds: totalDuration / this.fps,
|
|
712
|
-
narrationScript: parsed.narrationScript
|
|
713
|
-
};
|
|
714
|
-
} catch {
|
|
715
|
-
return this.planDeterministic(brief);
|
|
716
|
-
}
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
// src/generators/video-generator.ts
|
|
721
|
-
import { VIDEO_FORMATS as VIDEO_FORMATS2 } from "@contractspec/lib.contracts-integrations/integrations/providers/video";
|
|
722
|
-
class VideoGenerator {
|
|
723
|
-
scenePlanner;
|
|
724
|
-
voice;
|
|
725
|
-
transcriber;
|
|
726
|
-
image;
|
|
727
|
-
fps;
|
|
728
|
-
constructor(options) {
|
|
729
|
-
this.fps = options?.fps ?? DEFAULT_FPS;
|
|
730
|
-
this.voice = options?.voice;
|
|
731
|
-
this.transcriber = options?.transcriber;
|
|
732
|
-
this.image = options?.image;
|
|
733
|
-
this.scenePlanner = new ScenePlanner({
|
|
734
|
-
llm: options?.llm,
|
|
735
|
-
model: options?.model,
|
|
736
|
-
temperature: options?.temperature,
|
|
737
|
-
fps: this.fps,
|
|
738
|
-
locale: options?.locale,
|
|
739
|
-
modelSelector: options?.modelSelector,
|
|
740
|
-
selectionContext: options?.selectionContext
|
|
741
|
-
});
|
|
742
|
-
}
|
|
743
|
-
async generate(brief) {
|
|
744
|
-
const scenePlan = await this.scenePlanner.plan(brief);
|
|
745
|
-
const scenes = scenePlan.scenes.map((planned, i) => ({
|
|
746
|
-
id: `scene-${i}`,
|
|
747
|
-
compositionId: planned.compositionId,
|
|
748
|
-
props: planned.props,
|
|
749
|
-
durationInFrames: planned.durationInFrames,
|
|
750
|
-
narrationText: planned.narrationText
|
|
751
|
-
}));
|
|
752
|
-
let ttsProject;
|
|
753
|
-
let narrationAudio;
|
|
754
|
-
if (brief.narration?.enabled && this.voice) {
|
|
755
|
-
try {
|
|
756
|
-
ttsProject = await this.voice.synthesizeForVideo({
|
|
757
|
-
content: brief.content,
|
|
758
|
-
scenePlan: {
|
|
759
|
-
scenes: scenes.map((s) => ({
|
|
760
|
-
id: s.id,
|
|
761
|
-
compositionId: s.compositionId,
|
|
762
|
-
durationInFrames: s.durationInFrames,
|
|
763
|
-
narrationText: s.narrationText
|
|
764
|
-
})),
|
|
765
|
-
estimatedDurationSeconds: scenePlan.estimatedDurationSeconds
|
|
766
|
-
},
|
|
767
|
-
voice: { voiceId: brief.narration.voiceId ?? "" },
|
|
768
|
-
pacing: { strategy: "scene-matched" },
|
|
769
|
-
fps: this.fps
|
|
770
|
-
});
|
|
771
|
-
if (ttsProject.timingMap) {
|
|
772
|
-
for (const seg of ttsProject.timingMap.segments) {
|
|
773
|
-
const scene = scenes.find((s) => s.id === seg.sceneId);
|
|
774
|
-
if (scene) {
|
|
775
|
-
scene.durationInFrames = seg.recommendedSceneDurationInFrames;
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
if (ttsProject.assembledAudio) {
|
|
780
|
-
narrationAudio = {
|
|
781
|
-
data: ttsProject.assembledAudio.data,
|
|
782
|
-
format: ttsProject.assembledAudio.format === "wav" ? "wav" : "mp3",
|
|
783
|
-
durationSeconds: (ttsProject.assembledAudio.durationMs ?? 0) / 1000,
|
|
784
|
-
volume: 1
|
|
785
|
-
};
|
|
786
|
-
}
|
|
787
|
-
} catch {}
|
|
788
|
-
}
|
|
789
|
-
let subtitles;
|
|
790
|
-
if (this.transcriber && ttsProject?.assembledAudio) {
|
|
791
|
-
try {
|
|
792
|
-
const transcription = await this.transcriber.transcribe({
|
|
793
|
-
audio: ttsProject.assembledAudio,
|
|
794
|
-
subtitleFormat: "vtt"
|
|
795
|
-
});
|
|
796
|
-
subtitles = transcription.subtitles;
|
|
797
|
-
} catch {}
|
|
798
|
-
}
|
|
799
|
-
let thumbnail;
|
|
800
|
-
if (this.image) {
|
|
801
|
-
try {
|
|
802
|
-
const thumbProject = await this.image.generate({
|
|
803
|
-
content: brief.content,
|
|
804
|
-
purpose: "video-thumbnail",
|
|
805
|
-
format: "png",
|
|
806
|
-
style: "photorealistic"
|
|
807
|
-
});
|
|
808
|
-
const imageUrl = thumbProject.results?.images[0]?.url;
|
|
809
|
-
thumbnail = {
|
|
810
|
-
prompt: thumbProject.prompt.text,
|
|
811
|
-
...imageUrl ? { imageUrl } : {}
|
|
812
|
-
};
|
|
813
|
-
} catch {}
|
|
814
|
-
}
|
|
815
|
-
const format = brief.format ?? VIDEO_FORMATS2.landscape;
|
|
816
|
-
const totalDurationInFrames = scenes.reduce((sum, s) => sum + s.durationInFrames, 0);
|
|
817
|
-
const project = {
|
|
818
|
-
id: generateProjectId(),
|
|
819
|
-
scenes,
|
|
820
|
-
totalDurationInFrames,
|
|
821
|
-
fps: this.fps,
|
|
822
|
-
format,
|
|
823
|
-
audio: narrationAudio ? { narration: narrationAudio } : undefined,
|
|
824
|
-
subtitles,
|
|
825
|
-
voiceTimingMap: ttsProject?.timingMap,
|
|
826
|
-
thumbnail
|
|
827
|
-
};
|
|
828
|
-
return project;
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
function generateProjectId() {
|
|
832
|
-
const timestamp = Date.now().toString(36);
|
|
833
|
-
const random = Math.random().toString(36).slice(2, 8);
|
|
834
|
-
return `vp_${timestamp}_${random}`;
|
|
835
|
-
}
|
|
836
|
-
export {
|
|
837
|
-
VideoGenerator
|
|
838
|
-
};
|
|
82
|
+
Privilégiez la clarté et le rythme. Chaque scène doit communiquer une idée.`,description:"Scene planner LLM system prompt",placeholders:[{name:"fps",type:"number"},{name:"targetSeconds",type:"number"}]},"prompt.style.professional":{value:"Utilisez un ton clair, autoritaire et professionnel. Soyez concis et direct.",description:"Style guide for professional narration"},"prompt.style.casual":{value:"Utilisez un ton amical et conversationnel. Soyez accessible et proche.",description:"Style guide for casual narration"},"prompt.style.technical":{value:"Utilisez un langage technique précis. Soyez détaillé et exact.",description:"Style guide for technical narration"},"script.segment.challenge":{value:"Le défi : {content}",description:"Narration segment prefix for problems",placeholders:[{name:"content",type:"string"}]},"script.segment.solution":{value:"La solution : {content}",description:"Narration segment prefix for solutions",placeholders:[{name:"content",type:"string"}]},"script.segment.results":{value:"Les résultats : {content}",description:"Narration segment prefix for metrics",placeholders:[{name:"content",type:"string"}]},"scene.cta.default":{value:"En savoir plus",description:"Default call-to-action text for scenes"},"scene.hook.problem":{value:"Le problème",description:"Scene hook label for problem statement"},"scene.narration.problem":{value:"Le problème : {content}",description:"Scene narration for problem statement",placeholders:[{name:"content",type:"string"}]},"scene.hook.solution":{value:"La solution",description:"Scene hook label for solution"},"scene.narration.solution":{value:"La solution : {content}",description:"Scene narration for solution",placeholders:[{name:"content",type:"string"}]},"scene.hook.results":{value:"Résultats",description:"Scene hook label for results/metrics"},"composition.apiOverview.generates":{value:"Génère :",description:"ApiOverview heading for generated outputs"},"composition.apiOverview.tagline":{value:"Un spec. Toutes les surfaces.",description:"ApiOverview default tagline"},"composition.apiOverview.output.rest":{value:"Endpoint REST",description:"Generated output label: REST"},"composition.apiOverview.output.graphql":{value:"Mutation GraphQL",description:"Generated output label: GraphQL"},"composition.apiOverview.output.prisma":{value:"Modèle Prisma",description:"Generated output label: Prisma"},"composition.apiOverview.output.typescript":{value:"SDK TypeScript",description:"Generated output label: TypeScript SDK"},"composition.apiOverview.output.mcp":{value:"Outil MCP",description:"Generated output label: MCP Tool"},"composition.apiOverview.output.openapi":{value:"Spec OpenAPI",description:"Generated output label: OpenAPI"},"composition.socialClip.cta":{value:"En savoir plus",description:"SocialClip default CTA"},"composition.terminal.title":{value:"Terminal",description:"TerminalDemo default window title"}}});var h={"prompt.script.system":"prompt.script.system","prompt.scenePlanner.system":"prompt.scenePlanner.system","prompt.style.professional":"prompt.style.professional","prompt.style.casual":"prompt.style.casual","prompt.style.technical":"prompt.style.technical"},y={"script.segment.challenge":"script.segment.challenge","script.segment.solution":"script.segment.solution","script.segment.results":"script.segment.results"},R={"scene.cta.default":"scene.cta.default","scene.hook.problem":"scene.hook.problem","scene.narration.problem":"scene.narration.problem","scene.hook.solution":"scene.hook.solution","scene.narration.solution":"scene.narration.solution","scene.hook.results":"scene.hook.results"},U={"composition.apiOverview.generates":"composition.apiOverview.generates","composition.apiOverview.tagline":"composition.apiOverview.tagline","composition.apiOverview.output.rest":"composition.apiOverview.output.rest","composition.apiOverview.output.graphql":"composition.apiOverview.output.graphql","composition.apiOverview.output.prisma":"composition.apiOverview.output.prisma","composition.apiOverview.output.typescript":"composition.apiOverview.output.typescript","composition.apiOverview.output.mcp":"composition.apiOverview.output.mcp","composition.apiOverview.output.openapi":"composition.apiOverview.output.openapi","composition.socialClip.cta":"composition.socialClip.cta","composition.terminal.title":"composition.terminal.title"},D={...h,...y,...R,...U};import{DEFAULT_LOCALE as O,isSupportedLocale as S,resolveLocale as T,SUPPORTED_LOCALES as g}from"@contractspec/lib.contracts-spec/translations";import{createI18nFactory as m}from"@contractspec/lib.contracts-spec/translations";var Y=m({specKey:"video-gen.messages",catalogs:[$,V,I]}),E=Y.create,j=Y.getDefault,F=Y.resetRegistry;class X{llm;model;temperature;fps;i18n;modelSelector;selectionContext;constructor(x){this.llm=x?.llm,this.model=x?.model,this.temperature=x?.temperature??0.3,this.fps=x?.fps??Q,this.i18n=E(x?.locale),this.modelSelector=x?.modelSelector,this.selectionContext=x?.selectionContext}async plan(x){if(this.llm)return this.planWithLlm(x);return this.planDeterministic(x)}planDeterministic(x){let{content:L}=x,{t:K}=this.i18n,G=[],z=this.fps;if(G.push({compositionId:"SocialClip",props:{hook:L.title,message:L.summary,points:L.solutions.slice(0,3),cta:L.callToAction??K("scene.cta.default")},durationInFrames:3*z,narrationText:`${L.title}. ${L.summary}`}),L.problems.length>0)G.push({compositionId:"SocialClip",props:{hook:K("scene.hook.problem"),message:L.problems[0]??"",points:L.problems.slice(1,4)},durationInFrames:4*z,narrationText:K("scene.narration.problem",{content:L.problems.join(". ")})});if(L.solutions.length>0)G.push({compositionId:"SocialClip",props:{hook:K("scene.hook.solution"),message:L.solutions[0]??"",points:L.solutions.slice(1,4)},durationInFrames:5*z,narrationText:K("scene.narration.solution",{content:L.solutions.join(". ")})});if(L.metrics&&L.metrics.length>0)G.push({compositionId:"SocialClip",props:{hook:K("scene.hook.results"),message:L.metrics[0]??"",points:L.metrics.slice(1,3)},durationInFrames:3*z,narrationText:L.metrics.join(". ")});if(L.callToAction)G.push({compositionId:"SocialClip",props:{hook:L.callToAction,message:"",cta:L.callToAction},durationInFrames:2*z,narrationText:L.callToAction});if(x.targetDurationSeconds){let N=x.targetDurationSeconds*z,q=G.reduce((C,k)=>C+k.durationInFrames,0),H=N/q;for(let C of G)C.durationInFrames=Math.round(C.durationInFrames*H)}let w=G.reduce((N,q)=>N+q.durationInFrames,0),B=G.filter((N)=>N.narrationText).map((N)=>N.narrationText).join(" ");return{scenes:G,estimatedDurationSeconds:w/z,narrationScript:B}}async resolveModel(){if(this.model)return this.model;if(this.modelSelector){let x=this.selectionContext??{taskDimension:"reasoning"};return(await this.modelSelector.select(x)).modelId}return}async planWithLlm(x){let{t:L}=this.i18n,K=[{role:"system",content:[{type:"text",text:L("prompt.scenePlanner.system",{fps:this.fps,targetSeconds:x.targetDurationSeconds??30})}]},{role:"user",content:[{type:"text",text:JSON.stringify(x.content)}]}];if(!this.llm)return this.planDeterministic(x);try{let G=await this.resolveModel(),w=(await this.llm.chat(K,{model:G,temperature:this.temperature,responseFormat:"json"})).message.content.find((q)=>q.type==="text");if(!w||w.type!=="text")return this.planDeterministic(x);let B=JSON.parse(w.text),N=B.scenes.reduce((q,H)=>q+H.durationInFrames,0);return{scenes:B.scenes,estimatedDurationSeconds:N/this.fps,narrationScript:B.narrationScript}}catch{return this.planDeterministic(x)}}}import{VIDEO_FORMATS as P}from"@contractspec/lib.contracts-integrations/integrations/providers/video";class u{scenePlanner;voice;transcriber;image;fps;constructor(x){this.fps=x?.fps??Q,this.voice=x?.voice,this.transcriber=x?.transcriber,this.image=x?.image,this.scenePlanner=new X({llm:x?.llm,model:x?.model,temperature:x?.temperature,fps:this.fps,locale:x?.locale,modelSelector:x?.modelSelector,selectionContext:x?.selectionContext})}async generate(x){let L=await this.scenePlanner.plan(x),K=L.scenes.map((C,k)=>({id:`scene-${k}`,compositionId:C.compositionId,props:C.props,durationInFrames:C.durationInFrames,narrationText:C.narrationText})),G,z;if(x.narration?.enabled&&this.voice)try{if(G=await this.voice.synthesizeForVideo({content:x.content,scenePlan:{scenes:K.map((C)=>({id:C.id,compositionId:C.compositionId,durationInFrames:C.durationInFrames,narrationText:C.narrationText})),estimatedDurationSeconds:L.estimatedDurationSeconds},voice:{voiceId:x.narration.voiceId??""},pacing:{strategy:"scene-matched"},fps:this.fps}),G.timingMap)for(let C of G.timingMap.segments){let k=K.find((Z)=>Z.id===C.sceneId);if(k)k.durationInFrames=C.recommendedSceneDurationInFrames}if(G.assembledAudio)z={data:G.assembledAudio.data,format:G.assembledAudio.format==="wav"?"wav":"mp3",durationSeconds:(G.assembledAudio.durationMs??0)/1000,volume:1}}catch{}let w;if(this.transcriber&&G?.assembledAudio)try{w=(await this.transcriber.transcribe({audio:G.assembledAudio,subtitleFormat:"vtt"})).subtitles}catch{}let B;if(this.image)try{let C=await this.image.generate({content:x.content,purpose:"video-thumbnail",format:"png",style:"photorealistic"}),k=C.results?.images[0]?.url;B={prompt:C.prompt.text,...k?{imageUrl:k}:{}}}catch{}let N=x.format??P.landscape,q=K.reduce((C,k)=>C+k.durationInFrames,0);return{id:d(),scenes:K,totalDurationInFrames:q,fps:this.fps,format:N,audio:z?{narration:z}:void 0,subtitles:w,voiceTimingMap:G?.timingMap,thumbnail:B}}}function d(){let x=Date.now().toString(36),L=Math.random().toString(36).slice(2,8);return`vp_${x}_${L}`}export{u as VideoGenerator};
|