@lingjingai/scriptctl 0.63.8 → 0.63.10

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.
@@ -0,0 +1,4 @@
1
+ # 0.63.10
2
+
3
+ - 原片没有音轨时记录证据不足,保留台词与时间并继续画面审核,不再尝试无效音频提取。
4
+ - 审核视频及结构化请求使用服务端默认输出额度。
@@ -0,0 +1,5 @@
1
+ # 0.63.9
2
+
3
+ - `scriptctl review` 逐集审核动作叙述的人物指代,依据资产、上下文与原片证据,将可确认的称呼、别名和代词规范为资产正式名;有歧义时保留原文并记录待核对项。
4
+ - 动作换名要求保留已有视觉描述、动作事实和人物 aliases;普通词义、对白及动作内引用的原声与画面文字保留原文。
5
+ - 全剧收敛在人物合并或更名后核对受影响动作叙述的名称一致性。
package/dist/bin.js CHANGED
File without changes
@@ -2474,12 +2474,7 @@ async function generateReviewJson(request) {
2474
2474
  { text: request.prompt }
2475
2475
  ] }],
2476
2476
  ...request.system ? { systemInstruction: { parts: [{ text: request.system }] } } : {},
2477
- generationConfig: {
2478
- temperature: 0,
2479
- responseMimeType: "application/json",
2480
- responseJsonSchema: schema,
2481
- ...request.maxOutputTokens ? { maxOutputTokens: request.maxOutputTokens } : {}
2482
- }
2477
+ generationConfig: { temperature: 0, responseMimeType: "application/json", responseJsonSchema: schema }
2483
2478
  } : {
2484
2479
  model: route.model,
2485
2480
  input: [{ role: "user", content: [
@@ -2487,7 +2482,6 @@ async function generateReviewJson(request) {
2487
2482
  { type: "input_text", text: request.prompt }
2488
2483
  ] }],
2489
2484
  ...request.system ? { instructions: request.system } : {},
2490
- ...request.maxOutputTokens ? { max_output_tokens: request.maxOutputTokens } : {},
2491
2485
  text: { format: { type: "json_schema", name: "review", schema } }
2492
2486
  };
2493
2487
  for (let attempt = 1; attempt <= route.maxAttempts; attempt++) {
@@ -2579,7 +2573,6 @@ async function watchWindow(video, from, to, question, opts) {
2579
2573
  video: { data: fs3.readFileSync(clip2.path, "base64"), fps: CLIP_FPS },
2580
2574
  schema: z3.object({ answer: z3.string().min(1) }),
2581
2575
  timeoutMs: 18e4,
2582
- maxOutputTokens: 2048,
2583
2576
  callKey: opts.callKey
2584
2577
  });
2585
2578
  return { answer: result.value.answer, usage: result.usage.map((row) => ({
@@ -2613,6 +2606,20 @@ var wordsSchema = z4.array(z4.object({
2613
2606
  })).transform((words) => words.filter((word) => word.text.trim().length > 0)).pipe(z4.array(timedTextSchema));
2614
2607
  var utteranceSchema = timedTextSchema.safeExtend({ words: wordsSchema.optional() });
2615
2608
  var responseSchema = z4.object({ result: z4.object({ utterances: z4.array(utteranceSchema) }) });
2609
+ async function hasAudioTrack(video) {
2610
+ const { stdout } = await exec("ffprobe", [
2611
+ "-v",
2612
+ "error",
2613
+ "-select_streams",
2614
+ "a:0",
2615
+ "-show_entries",
2616
+ "stream=index",
2617
+ "-of",
2618
+ "csv=p=0",
2619
+ video
2620
+ ], { timeout: 3e4 });
2621
+ return stdout.trim().length > 0;
2622
+ }
2616
2623
  function parseAsr(raw) {
2617
2624
  return responseSchema.parse(raw).result.utterances;
2618
2625
  }
@@ -2738,6 +2745,7 @@ var DOCTRINE = `
2738
2745
  - Scene \u4EBA\u7269\u3001\u72B6\u6001\u3001\u8BF4\u8BDD\u4EBA\u4E0E Action \u4E3B\u4F53\u662F\u5426\u4E00\u81F4\u3002
2739
2746
  - \u4EBA\u7269\u8EAB\u4EFD\u3001\u58F0\u97F3\u6765\u6E90\u3001\u9020\u578B\u3001\u5730\u70B9\u3001\u9053\u5177\u662F\u5426\u8BEF\u5EFA\u3001\u91CD\u590D\u6216\u9519\u6302\u3002
2740
2747
  - \u5BF9\u767D\u662F\u5426\u9010\u5B57\u5FE0\u5B9E\u4E8E\u539F\u58F0\uFF0C\u52A8\u4F5C\u662F\u5426\u5FE0\u5B9E\u4E8E\u53EF\u89C1\u4E8B\u5B9E\uFF1B\u6709\u65E0\u9057\u6F0F\u3001\u91CD\u590D\u6216\u5E7B\u89C9\u3002
2748
+ - Action \u53D9\u8FF0\u4E2D\u7684\u4EBA\u7269\u522B\u540D\u3001\u79F0\u547C\u548C\u4EE3\u8BCD\u662F\u5426\u80FD\u4F9D\u636E\u8BC1\u636E\u660E\u786E\u4E3A\u8D44\u4EA7\u6B63\u5F0F\u540D\u3002
2741
2749
  - \u573A\u754C\u662F\u5426\u5BF9\u5E94\u771F\u5B9E\u7684\u65F6\u7A7A\u5207\u6362\u3002
2742
2750
  - \u65F6\u95F4\u6233\u662F\u5426\u7F3A\u5931\u3001\u5012\u5E8F\u3001\u8D8A\u754C\u6216\u4EA7\u751F\u8D85\u8FC7 15 \u79D2\u7684\u7A7A\u6863\uFF08\u76F8\u90BB\u540C\u503C\u5408\u6CD5\uFF09\u3002
2743
2751
  - \u591A\u72B6\u6001\u4EBA\u7269\u7684\u76F8\u4F3C\u9020\u578B\u5FC5\u987B\u53D6\u5F97\u4EE3\u8868\u6027\u89C6\u9891\u7A97\u53E3\u540E\u518D\u5224\u65AD\uFF0C\u4E0D\u51ED\u540D\u79F0\u76F4\u63A5\u5408\u5E76\u3002
@@ -2756,6 +2764,19 @@ var DOCTRINE = `
2756
2764
  - \u9020\u578B\u72B6\u6001\u91CD\u590D \u2192 \u628A\u5F15\u7528\u8FC1\u79FB\u5230\u6709\u8BC1\u636E\u652F\u6301\u7684\u90A3\u4E2A\u72B6\u6001\uFF0C\u518D\u5220\u91CD\u590D\u7684\u3002
2757
2765
  - Scene \u7F3A\u4EBA\u7269\u5F15\u7528 \u2192 \u53EA\u6709\u8BE5\u4EBA\u7269\u786E\u5B9E\u51FA\u573A\u6216\u5F00\u53E3\u624D\u8865\uFF1B\u6B63\u6587\u91CC\u88AB\u63D0\u5230\u4E0D\u6784\u6210\u4F9D\u636E\u3002
2758
2766
  - \u7F3A\u5931\u7684 Action / \u5BF9\u767D \u2192 \u53EA\u5728\u539F\u7247\u660E\u786E\u7684\u65F6\u95F4\u70B9\u63D2\u5165\uFF1B\u4E0D\u5F97\u6539\u5199\u539F\u58F0\uFF0C\u4E0D\u5F97\u51ED\u7A7A\u8865\u4E0D\u53EF\u89C1\u7684\u4E8B\u5B9E\u3002
2767
+
2768
+ ## \u52A8\u4F5C\u53D9\u8FF0\u7684\u4EBA\u7269\u6307\u4EE3
2769
+
2770
+ \u9010\u6761\u68C0\u67E5 type=action \u7684\u53D9\u8FF0\u6B63\u6587\u3002\u4F9D\u636E\u4EBA\u7269\u8D44\u4EA7\u3001\u524D\u540E\u6587\u3001\u5173\u7CFB\u4E0E\u539F\u7247\u8BC1\u636E\uFF0C\u8BC6\u522B\u52A8\u4F5C\u4E3B\u4F53\u3001\u52A8\u4F5C\u5BF9\u8C61\u548C\u89C6\u7EBF\u5BF9\u8C61\uFF1B\u80FD\u660E\u786E\u5BF9\u5E94\u4EBA\u7269\u65F6\uFF0C\u7528\u8BE5\u8D44\u4EA7\u7684\u6B63\u5F0F actor_name \u8868\u8FBE\uFF0C\u4FDD\u7559\u539F\u6709\u52A8\u4F5C\u3001\u60C5\u7EEA\u3001\u4F4D\u7F6E\u3001\u56E0\u679C\u3001\u65F6\u95F4\u6233\u548C\u5F15\u7528\u3002
2771
+
2772
+ - \u5148 read \u4EBA\u7269\u5361\u6838\u5BF9\u6B63\u5F0F name \u4E0E aliases\uFF1B\u5DE5\u5177\u6B63\u6587\u91CC\u7684\u6700\u77ED\u663E\u793A\u540D\u4E0D\u4E00\u5B9A\u662F\u6B63\u5F0F\u540D\u3002aliases \u662F\u5019\u9009\u7EBF\u7D22\uFF0C\u540C\u4E00\u4E2A\u79F0\u547C\u53EF\u4EE5\u6307\u5411\u4E0D\u540C\u4EBA\u7269\uFF0C\u4E0D\u80FD\u5F53\u4F5C\u5168\u5267\u552F\u4E00\u6620\u5C04\u3002
2773
+ - \u4F8B\u5982\u786E\u8BA4\u201C\u5927\u54E5\u201D\u6307\u767D\u6267\u6E0A\u540E\uFF0C\u201C\u767D\u53D9\u770B\u7740\u5979\u88AB\u5927\u54E5\u5E26\u8D70\u201D\u4E2D\u7684\u201C\u5927\u54E5\u201D\u5199\u6210\u201C\u767D\u6267\u6E0A\u201D\uFF1B\u201C\u5979\u201D\u53EA\u6709\u5728\u72EC\u7ACB\u8BC1\u636E\u4E5F\u660E\u786E\u65F6\u624D\u5199\u51FA\u5BF9\u5E94\u6B63\u5F0F\u540D\u3002
2774
+ - \u201C\u955C\u5934\u3001\u4F4E\u5934\u3001\u70B9\u5934\u201D\u201C\u6D45\u6D45\u7684\u7B11\u610F\u201D\u201C\u4F9D\u7136\u7AD9\u7740\u201D\u662F\u666E\u901A\u8BCD\u4E49\uFF0C\u4FDD\u7559\u539F\u6587\uFF1B\u5224\u65AD\u4EBA\u7269\u6307\u4EE3\u8981\u8BFB\u6574\u53E5\uFF0C\u4E0D\u80FD\u6309\u522B\u540D\u5B50\u4E32\u6279\u91CF\u66FF\u6362\u3002
2775
+ - \u5BF9\u767D\u3001\u5FC3\u58F0\u3001\u65C1\u767D\u53CA action \u5185\u5F15\u7528\u7684\u539F\u58F0\u3001\u624B\u673A\u6D88\u606F\u3001\u5B57\u5E55\u3001\u62DB\u724C\u7B49\u53EF\u89C1\u6587\u5B57\u4FDD\u7559\u539F\u6587\u3002\u4F8B\u5982\u5C4F\u5E55\u6D88\u606F\u201C\u6211\u6015\u8001\u5A46\u201D\u4FDD\u7559\u201C\u8001\u5A46\u201D\uFF1B\u52A8\u4F5C\u53D9\u8FF0\u201C\u4ED6\u6276\u7740\u8001\u5A46\u5750\u4E0B\u201D\u4E2D\u7684\u4EBA\u7269\u6307\u4EE3\u6309\u8BC1\u636E\u660E\u786E\u3002
2776
+ - \u8BC1\u636E\u5DF2\u660E\u786E\u540C\u4E00\u4EBA\u7269\u3001\u53EA\u628A\u53D9\u8FF0\u79F0\u547C\u5199\u6210\u6B63\u5F0F\u540D\uFF0C\u5C5E\u4E8E\u8EAB\u4EFD\u8868\u8FBE\u6821\u51C6\uFF0C\u4E0D\u662F\u5267\u60C5\u6DA6\u8272\u3002\u4ECD\u987B\u6EE1\u8DB3\u8BC1\u636E\u51C6\u5165\uFF1B\u8EAB\u4EFD\u6709\u6B67\u4E49\u65F6\u4FDD\u7559\u539F\u6587\u5E76\u8BB0\u5F55 unresolved\uFF0C\u8BF4\u660E\u7F3A\u5C11\u7684\u951A\u70B9\uFF0C\u4E0D\u5F3A\u884C\u9009\u62E9 alias \u6240\u5C5E\u4EBA\u7269\u3002
2777
+ - \u660E\u786E\u4EBA\u7269\u540D\u65F6\u4FDD\u7559\u539F\u53E5\u5DF2\u6709\u7684\u989C\u8272\u3001\u4F53\u578B\u3001\u670D\u88C5\u3001\u7269\u79CD\u4E0E\u5F53\u524D\u5F62\u6001\u7B49\u89C6\u89C9\u4FE1\u606F\u3002\u6B63\u5F0F\u540D\u53EA\u89E3\u51B3\u201C\u662F\u8C01\u201D\uFF0C\u4E0D\u80FD\u66FF\u4EE3\u201C\u6B64\u523B\u957F\u4EC0\u4E48\u6837\u201D\uFF1B\u4FEE\u9970\u8BED\u4E0E\u6CDB\u79F0\u8FDE\u5728\u4E00\u8D77\u65F6\uFF0C\u53EF\u5199\u6210\u201C\u6B63\u5F0F\u540D\uFF08\u539F\u6709\u5F62\u6001\u63CF\u8FF0\uFF09\u201D\uFF0C\u4E0D\u80FD\u628A\u6574\u6BB5\u63CF\u8FF0\u4E00\u5E76\u5220\u6389\u3002
2778
+ - \u4FEE\u6539\u9650\u5B9A\u5230\u5DF2\u6838\u5B9E\u7684\u672C\u6761 action\uFF0C\u8BFB\u56DE\u786E\u8BA4\u5176\u4ED6\u8BCD\u53E5\u672A\u53D8\u3002\u4EBA\u7269\u4EC5\u88AB\u63D0\u5230\u65F6\u4E0D\u636E\u6B64\u8865\u573A\u666F\u51FA\u573A\u7ED1\u5B9A\uFF1B\u4EBA\u7269\u8D44\u4EA7\u4E0E aliases \u4FDD\u7559\u4F9B\u540E\u7EED\u7406\u89E3\u3002
2779
+
2759
2780
  `.trim();
2760
2781
  var MEDIA = `
2761
2782
  ## \u5A92\u4F53\u8BC1\u636E
@@ -2821,6 +2842,7 @@ function episodeTask(input) {
2821
2842
  "## \u672C\u6B21\u4EFB\u52A1\uFF1A\u5168\u5267\u6536\u655B",
2822
2843
  "\u53EA\u5904\u7406\u8DE8\u96C6\u4E00\u81F4\u6027\uFF1A\u4EBA\u7269\u8EAB\u4EFD\u91CD\u590D\u3001\u9020\u578B\u72B6\u6001\u91CD\u590D\u3001\u5730\u70B9/\u9053\u5177\u91CD\u590D\u3001\u6B8B\u4F59\u5F15\u7528\u3002",
2823
2844
  "\u4E0D\u8981\u91CD\u590D\u9010\u96C6\u5185\u5BB9\u5BA1\u6838\u3002\u672C\u9636\u6BB5\u53EF\u4EE5\u4F7F\u7528 merge \u4E0E\u8D44\u4EA7/\u72B6\u6001\u7EA7\u7684 edit / del\u3002",
2845
+ "\u4EBA\u7269\u5408\u5E76\u6216\u6B63\u5F0F\u540D\u53D8\u66F4\u540E\uFF0C\u6838\u5BF9\u53D7\u5F71\u54CD action \u7684\u53D9\u8FF0\u540D\u79F0\u4E0E\u6700\u7EC8\u8D44\u4EA7\u4E00\u81F4\uFF1B\u53EA\u5904\u7406\u5DF2\u786E\u8BA4\u7684\u540C\u4E00\u8EAB\u4EFD\uFF0C\u4FDD\u7559\u5BF9\u767D\u4E0E\u53EF\u89C1\u6587\u5B57\u539F\u6587\u3002",
2824
2846
  "\u6BCF\u6536\u53E3\u4E00\u4E2A\u95EE\u9898\u8C03\u7528\u4E00\u6B21 finding\uFF0C\u6700\u540E\u8DD1\u4E00\u6B21 validate\u3002"
2825
2847
  ].join("\n");
2826
2848
  }
@@ -2831,6 +2853,7 @@ function episodeTask(input) {
2831
2853
  "",
2832
2854
  "\u5148 scan \u672C\u96C6\u5EFA\u7ACB\u4E0A\u4E0B\u6587\uFF0C\u518D\u9010\u6761\u68C0\u67E5 Dialogue\u3001inner thought \u4E0E Action\u3002",
2833
2855
  "\u5148\u5EFA\u7ACB\u4EBA\u7269\u76EE\u6807\u3001\u5DF2\u77E5\u4FE1\u606F\u3001\u5173\u7CFB\u548C\u76F8\u90BB\u884C\u4E3A\u7684\u56E0\u679C\uFF0C\u518D\u5224\u65AD\u5355\u6761\u662F\u5426\u5FE0\u5B9E\u3002",
2856
+ "\u9010\u6761\u5B8C\u6210\u52A8\u4F5C\u53D9\u8FF0\u7684\u4EBA\u7269\u6307\u4EE3\u68C0\u67E5\uFF1A\u6709\u8BC1\u636E\u7684\u79F0\u547C\u3001\u522B\u540D\u548C\u4EE3\u8BCD\u5199\u6210\u8D44\u4EA7\u6B63\u5F0F\u540D\uFF1B\u666E\u901A\u8BCD\u4E49\u53CA\u5F15\u7528\u539F\u6587\u4FDD\u7559\u3002",
2834
2857
  input.neighbours ? `
2835
2858
  \u76F8\u90BB\u96C6\u6897\u6982\uFF08\u53EA\u7528\u4E8E\u7406\u89E3\u56E0\u679C\uFF09\uFF1A
2836
2859
  ${input.neighbours}` : "",
@@ -3373,6 +3396,18 @@ function resolveComparison(doc, episode, cues, comparison) {
3373
3396
  }
3374
3397
  async function alignEpisode(doc, episode, video, scriptPath, config, onAsrComplete) {
3375
3398
  const root = path4.join(path4.dirname(scriptPath), ".review", "asr", `episode-${episode}`);
3399
+ await fs6.mkdir(root, { recursive: true });
3400
+ if (!await hasAudioTrack(video)) {
3401
+ const report2 = {
3402
+ summary: "\u539F\u7247\u6CA1\u6709\u97F3\u8F68\uFF0C\u65E0\u6CD5\u6267\u884C ASR \u6821\u65F6\uFF1B\u7EE7\u7EED\u5BA1\u6838\u753B\u9762\u4E0E\u5267\u672C\u3002",
3403
+ timestamp_corrections: [],
3404
+ missing_dialogue: [],
3405
+ notes: ["ffprobe \u786E\u8BA4\u539F\u7247\u6CA1\u6709\u97F3\u9891\u6D41\u3002\u4FDD\u7559\u73B0\u6709\u53F0\u8BCD\u53CA\u65F6\u95F4\uFF0C\u4E0D\u6839\u636E\u65E0\u97F3\u8F68\u63A8\u65AD\u53F0\u8BCD\u4E0D\u5B58\u5728\uFF1B\u770B\u7247\u6838\u5BF9\u753B\u9762\u4E0E\u5B57\u5E55\uFF0C\u65E0\u6CD5\u4ECE\u753B\u9762\u786E\u8BA4\u7684\u53D1\u58F0\u5185\u5BB9\u660E\u786E\u6807\u4E3A\u8BC1\u636E\u4E0D\u8DB3\u3002"]
3406
+ };
3407
+ const reportDir2 = await fs6.mkdtemp(path4.join(root, "no-audio-"));
3408
+ await fs6.writeFile(path4.join(reportDir2, "report.json"), JSON.stringify(report2, null, 2));
3409
+ return { report: report2, reportDir: reportDir2, usage: [] };
3410
+ }
3376
3411
  const utterances = await episodeAsr(video, root);
3377
3412
  onAsrComplete?.();
3378
3413
  const script = read(doc, String(episode), { timestamps: true });