tuna-agent 0.1.145 → 0.1.147
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.
|
@@ -280,8 +280,9 @@ Return ONLY a JSON object, no markdown fences:
|
|
|
280
280
|
|
|
281
281
|
Rules:
|
|
282
282
|
- characters.name: a stable short uppercase label reused for this subject (e.g. "THE BISHOP", "U-94 SUBMARINE"). Max 4 words.
|
|
283
|
-
-
|
|
284
|
-
- characters.description: ENGLISH only, factual, no camera/action words
|
|
283
|
+
- RECALL (CRITICAL): list EVERY distinct recurring subject SEPARATELY. If a family or group recurs, include EACH member as its own entry (e.g. adult man, adult woman, older boy, younger girl) — never merge them into one. Skip only true one-off background extras. Be COMPLETE: missing a recurring character is worse than one extra. Up to 8.
|
|
284
|
+
- characters.description: ENGLISH only, factual, no camera/action words.
|
|
285
|
+
- DISTINCT FACES (CRITICAL): every character MUST have a HIGHLY UNIQUE facial structure, a distinct hairstyle, a specific body type and a clearly different age. NEVER reuse the same or a similar facial description for two characters — they must look completely different from one another.`,
|
|
285
286
|
},
|
|
286
287
|
];
|
|
287
288
|
for (const b64 of frames) {
|
|
@@ -307,7 +308,7 @@ Rules:
|
|
|
307
308
|
}
|
|
308
309
|
const characters = (parsed.characters || [])
|
|
309
310
|
.filter(c => c && c.name && c.description)
|
|
310
|
-
.slice(0,
|
|
311
|
+
.slice(0, 8)
|
|
311
312
|
.map(c => ({ name: String(c.name).trim(), description: String(c.description).trim() }));
|
|
312
313
|
const video_summary = (parsed.video_summary || '').trim();
|
|
313
314
|
const video_style = (parsed.video_style || '').trim();
|
|
@@ -319,7 +320,7 @@ Rules:
|
|
|
319
320
|
`[AESTHETIC & STYLE]\n${styleLine}\n` +
|
|
320
321
|
`[COMPOSITION & LAYOUT]\nCharacter Reference Sheet. Full-body side-by-side.\n` +
|
|
321
322
|
`[CHARACTER CAST LIST]\n${castList}\n` +
|
|
322
|
-
`[TECHNICAL SPECIFICATIONS]\nHigh detail, 8k resolution, consistent facial structures across all frames.`;
|
|
323
|
+
`[TECHNICAL SPECIFICATIONS]\nHigh detail, 8k resolution, consistent facial structures across all frames. Each character has a completely distinct face, hairstyle, body type and age — no two characters look alike.`;
|
|
323
324
|
}
|
|
324
325
|
return { video_summary, video_style, master_cast_prompt, characters };
|
|
325
326
|
}
|
|
@@ -517,8 +518,10 @@ export async function analyzeVideo(url, onProgress) {
|
|
|
517
518
|
// master cast + characters. Runs before per-scene describe so the cast
|
|
518
519
|
// context keeps naming consistent across the whole timeline.
|
|
519
520
|
progress('Đang phân tích tổng thể (summary + style + master cast)...');
|
|
520
|
-
// Sample up to
|
|
521
|
-
|
|
521
|
+
// Sample up to 30 frames evenly across the whole video — denser sampling
|
|
522
|
+
// is critical for cast RECALL on sparse-narration (ASMR) videos where
|
|
523
|
+
// Phase-1 relies almost entirely on frames (matches AI_Video_Clone).
|
|
524
|
+
const p1SampleCount = Math.min(30, frameBuffers.length);
|
|
522
525
|
const p1Step = Math.max(1, Math.floor(frameBuffers.length / p1SampleCount));
|
|
523
526
|
const p1Samples = frameBuffers
|
|
524
527
|
.filter((_, i) => i % p1Step === 0)
|