@starreel/mcp 0.1.105 → 0.1.107
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/SKILL.md +41 -5
- package/assets/handoff/compile_timeline.py +1 -1
- package/assets/handoff/fetch_pack.py +20 -2
- package/dist/tools/local-postproduction.js +1 -1
- package/dist/tools/produce.js +39 -17
- package/openapi.json +577 -8
- package/package.json +1 -1
- package/server.json +2 -2
package/SKILL.md
CHANGED
|
@@ -488,7 +488,14 @@ content that will be rejected.
|
|
|
488
488
|
storyboards; `get_characters` after portraits to confirm every on-screen
|
|
489
489
|
character has an image and a sheet; `get_storyboards` after frames and after
|
|
490
490
|
videos to read `frame_status` / `video_status` / `fail_reason` / `fail_hint`
|
|
491
|
-
and fix failed shots before moving on
|
|
491
|
+
and fix failed shots before moving on. `video_status=ready` means generation
|
|
492
|
+
finished, not visual acceptance. Read `video_quality_issues`: `terminal_cut`
|
|
493
|
+
with `suspected` blocks automatic tail promotion and chaining for that result;
|
|
494
|
+
`unavailable` means the check failed, not that a defect was confirmed. A missing
|
|
495
|
+
issue does not prove a scan happened. `scan_intra_shot_cuts` also reports
|
|
496
|
+
`shots_with_terminal_cuts` and `detail.terminal_cut`, including individual
|
|
497
|
+
clips split from a group. Review the footage before any paid regeneration.
|
|
498
|
+
Use `get_pipeline_status` before the
|
|
492
499
|
final cut to confirm no shot is missing. `review_all` gives a whole-episode
|
|
493
500
|
checkup at any time (it issues no token — the gates want a review of the
|
|
494
501
|
*current* artifact).
|
|
@@ -1066,10 +1073,17 @@ to close") tells the vendor to fit that entire sequence into each 3-second shot.
|
|
|
1066
1073
|
the customer — **every time**, including revisions. Otherwise the platform's
|
|
1067
1074
|
records describe a cut the customer never received, and nobody can later tell
|
|
1068
1075
|
which version shipped or which generation each shot came from. The platform
|
|
1069
|
-
re-hashes the file itself
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
`
|
|
1076
|
+
re-hashes the file itself. When delivery provenance is enabled, pass the original
|
|
1077
|
+
`handoff_pack_id` and `handoff_manifest_sha256`: registration uses that frozen
|
|
1078
|
+
export, never today's shot pointers. Without an export, provenance stays unknown.
|
|
1079
|
+
Keep `source-manifest.json` and `download-receipt.json`; downloaded hashes are
|
|
1080
|
+
client-side evidence, not proof of customer acceptance. Put finishing edits in
|
|
1081
|
+
`manifest`. Registration does not select or accept a version in the new flow.
|
|
1082
|
+
Use `set_current_delivery` for selection and `confirm_delivery_acceptance` only
|
|
1083
|
+
after the customer's explicit statement. For verbal completion without a file,
|
|
1084
|
+
use `delivery_id=null`: the platform reports completion with file unverified.
|
|
1085
|
+
Read `delivery_completion` independently of historical production warnings.
|
|
1086
|
+
`get_final_cut.download_url` remains the platform render URL.
|
|
1073
1087
|
- **Local color grading / third-party AI finishing**: call `export_handoff_pack`
|
|
1074
1088
|
with `purpose="local_color"`; for existing still frames use `media_type="images"`
|
|
1075
1089
|
(no video generation required). Save the result as `manifest.json`, obtain the
|
|
@@ -1123,3 +1137,25 @@ to close") tells the vendor to fit that entire sequence into each 3-second shot.
|
|
|
1123
1137
|
outside the kept window)
|
|
1124
1138
|
|
|
1125
1139
|
Full reference: https://api.shortreelai.com/docs/mcp
|
|
1140
|
+
|
|
1141
|
+
### 资产引用与版本有效性
|
|
1142
|
+
|
|
1143
|
+
- `get_storyboards.asset_versions` 对首帧、尾帧和视频分别返回四项事实:`generated`(已生成)、`input_consistent`(与当前输入一致)、`review_valid`(审核有效)、`adopted`(已采用)。`null` 表示证据不足,不能当作 true。
|
|
1144
|
+
- `ready` 和生成数量只表示产物存在;当前有效数量使用 `get_pipeline_status.asset_versions_summary.*.current_effective`。换帧后旧视频仍可查看,但失效版本不能混入当前有效汇总。
|
|
1145
|
+
- `get_asset_versions(storyboard_id)` 查看历史版本链接、依赖 ID/版本哈希及各自状态。历史没有快照时不从当前绑定伪造依赖。
|
|
1146
|
+
- `get_asset_binding_repair_plan(episode_id)` 只返回缺失场景绑定的候选和依据,`applied=false`。必须逐项审核,不按名字自动回填,也不自动重新生成客户已完成的片子。
|
|
1147
|
+
|
|
1148
|
+
### Original product lettering
|
|
1149
|
+
|
|
1150
|
+
Use `update_shot(product_text_contract=...)` only for explicitly chosen assets,
|
|
1151
|
+
source images, normalized source regions, and exact original text. Never infer
|
|
1152
|
+
these bindings from names or backfill old shots. `quote_shot_frame` and
|
|
1153
|
+
`quote_frames` expose the rendering limitation and original-media/postproduction
|
|
1154
|
+
alternatives before generation. Generated text matching the requested text still
|
|
1155
|
+
needs a visual check. `record_product_text_review` may record a result only after
|
|
1156
|
+
the user explicitly confirms they inspected that exact file. Bind the current
|
|
1157
|
+
contract hash, generation ID and URL from `get_storyboards.product_text`;
|
|
1158
|
+
model output is not human acceptance. This does not accept the entire film.
|
|
1159
|
+
|
|
1160
|
+
### 费用归因
|
|
1161
|
+
核对任务、素材版本、采用情况和返工原因使用 `get_cost_attribution`。实际花费是账本净额,未知证据不猜测;未采用不等于浪费,图片修改也可能产生费用。明确原因后用 `classify_cost_reason` 登记说明,不会改变账单。旧 `rework.video` 是重复成功出片计数,不是平台失败归责。
|
|
@@ -204,7 +204,7 @@ def compile_timeline(pack_dir, plan_path=None, outdir=None):
|
|
|
204
204
|
total = cursor
|
|
205
205
|
by_n = {s["shot_number"]: s for s in shots}
|
|
206
206
|
bgm = []
|
|
207
|
-
for b in manifest.get("bgm", []):
|
|
207
|
+
for b in ([] if (manifest.get("audio_contract") or {}).get("music_output") == "forbidden" else manifest.get("bgm", [])):
|
|
208
208
|
anchor = by_n.get(int(b.get("anchor_shot", 1)))
|
|
209
209
|
if not anchor:
|
|
210
210
|
warnings.append(f"BGM {b.get('file')}: anchor_shot 不存在,按 0 处理")
|
|
@@ -156,11 +156,14 @@ def main():
|
|
|
156
156
|
if local_color and os.path.exists(out) and os.listdir(out):
|
|
157
157
|
sys.exit("本地后期请使用新的空目录,避免覆盖源素材或误用旧版本缓存")
|
|
158
158
|
os.makedirs(out, exist_ok=True)
|
|
159
|
-
if local_color:
|
|
159
|
+
if local_color or m.get("pack_id"):
|
|
160
160
|
with open(os.path.join(out, "source-manifest.json"), "w", encoding="utf-8") as f:
|
|
161
161
|
json.dump(m, f, ensure_ascii=False, indent=2)
|
|
162
|
+
if local_color:
|
|
162
163
|
# 再次兜底:本地后期不自动烘焙项目 LUT。
|
|
163
164
|
m.setdefault("render_target", {})["color_lut"] = None
|
|
165
|
+
expected_hashes = {}
|
|
166
|
+
receipts = []
|
|
164
167
|
jobs = [] # (url, 包内相对路径)
|
|
165
168
|
|
|
166
169
|
for i, sh in enumerate(m.get("shots", [])):
|
|
@@ -178,6 +181,7 @@ def main():
|
|
|
178
181
|
clip = sh.get("clip") or {}
|
|
179
182
|
if clip.get("url"):
|
|
180
183
|
rel = f"clips/shot_{tag}.mp4"
|
|
184
|
+
expected_hashes[rel] = (sh.get("provenance") or {}).get("generation_sha256")
|
|
181
185
|
jobs.append((clip.pop("url"), rel))
|
|
182
186
|
clip["file"] = rel
|
|
183
187
|
|
|
@@ -225,13 +229,27 @@ def main():
|
|
|
225
229
|
def one(job):
|
|
226
230
|
url, rel = job
|
|
227
231
|
try:
|
|
228
|
-
|
|
232
|
+
dest = os.path.join(out, rel)
|
|
233
|
+
fetch(url, dest)
|
|
234
|
+
digest = hashlib.sha256()
|
|
235
|
+
with open(dest, "rb") as downloaded:
|
|
236
|
+
for chunk in iter(lambda: downloaded.read(1024 * 1024), b""):
|
|
237
|
+
digest.update(chunk)
|
|
238
|
+
sha = digest.hexdigest()
|
|
239
|
+
expected = expected_hashes.get(rel)
|
|
240
|
+
if expected and expected != sha:
|
|
241
|
+
os.unlink(dest)
|
|
242
|
+
raise RuntimeError("downloaded file SHA-256 differs from exported version")
|
|
243
|
+
receipts.append({"file": rel, "source_url": url, "sha256": sha, "size_bytes": os.path.getsize(dest), "expected_sha256": expected})
|
|
229
244
|
except Exception as e: # 单个失败不中断整批,最后一起报
|
|
230
245
|
errors.append(f"{rel}: {e}")
|
|
231
246
|
|
|
232
247
|
with ThreadPoolExecutor(max_workers=max(1, a.jobs)) as ex:
|
|
233
248
|
list(ex.map(one, jobs))
|
|
234
249
|
|
|
250
|
+
with open(os.path.join(out, "download-receipt.json"), "w", encoding="utf-8") as receipt:
|
|
251
|
+
json.dump({"pack_id": m.get("pack_id"), "manifest_sha256": m.get("manifest_sha256"), "status": "failed" if errors else "downloaded", "files": sorted(receipts, key=lambda r: r["file"]), "errors": errors}, receipt, ensure_ascii=False, indent=2)
|
|
252
|
+
|
|
235
253
|
if local_color and not errors:
|
|
236
254
|
write_postproduction(out, m, jobs)
|
|
237
255
|
|
|
@@ -8,7 +8,7 @@ export function localColorHandoff(manifest, goal = '', missingShots = []) {
|
|
|
8
8
|
workflow: 'local_color',
|
|
9
9
|
status: 'not_processed',
|
|
10
10
|
goal,
|
|
11
|
-
platform_lut: manifest.render_target?.color_lut ?? null,
|
|
11
|
+
platform_lut: manifest.render_target?.source_color_lut ?? manifest.render_target?.color_lut ?? null,
|
|
12
12
|
missing_shots: missingShots,
|
|
13
13
|
steps: [
|
|
14
14
|
'将本清单保存为 manifest.json,用 save_handoff_toolchain 保存工具链,再运行 python3 fetch_pack.py manifest.json -o ./pack;使用新的输出目录。',
|
package/dist/tools/produce.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* 用 get_storyboards / get_episode_status 轮询到完成。下载链接只发我方 COS 链接。
|
|
12
12
|
*/
|
|
13
13
|
import { z } from 'zod';
|
|
14
|
-
import {
|
|
14
|
+
import { localColorHandoff } from './local-postproduction.js';
|
|
15
15
|
import { readFileSync, writeFileSync, chmodSync, mkdirSync } from 'node:fs';
|
|
16
16
|
import { tmpdir } from 'node:os';
|
|
17
17
|
import { dirname, join } from 'node:path';
|
|
@@ -485,6 +485,7 @@ export function registerProduceTools(server, client) {
|
|
|
485
485
|
// ---------- 完整工作流进度 ----------
|
|
486
486
|
server.tool('get_pipeline_status', '查某一集完整工作流的进度(script_rewrite/提取/分镜/语音/出图/出视频/合成/配乐/终拼…各步 ' +
|
|
487
487
|
'done/partial/pending/not_required)。照它按序推进、不跳步。免费。' +
|
|
488
|
+
'asset_versions_summary 将 generated、input_consistent、review_valid、adopted 和 current_effective 分开计数;不能把 generate_videos.completed 当当前有效数量。' +
|
|
488
489
|
'★not_required=当前模式不需要该步(如原声剧的 TTS 三步、关配乐的 generate_bgm),不是没做完,别去补做。' +
|
|
489
490
|
'图片/视频分母已剔除卡镜(shots_not_applicable);merge_episode.bgm_stale=true 表示配乐晚于成片,重新 compose_episode 即可。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.produceGet(`/episodes/${episode_id}/pipeline-status`)));
|
|
490
491
|
// ---------- 角色定妆图(一致性锚) ----------
|
|
@@ -524,13 +525,19 @@ export function registerProduceTools(server, client) {
|
|
|
524
525
|
}, async ({ episode_id, quote_id, confirm_replace, review_token, acknowledge_review }) => jsonResult(await client.producePost(`/episodes/${episode_id}/storyboards/generate`, {
|
|
525
526
|
quote_id, review_token, acknowledge_review, ...(confirm_replace ? { confirm_replace } : {}),
|
|
526
527
|
})));
|
|
528
|
+
server.tool('get_asset_versions', '只读查询一个镜头的全部图片/视频版本、历史查看链接、依赖 ID 与版本哈希,以及已生成→与当前输入一致→审核有效→已采用四项独立事实。历史缺少依赖记录时显示未知,不补造快照。免费。', { storyboard_id: z.number().int().positive() }, async ({ storyboard_id }) => jsonResult(await client.produceGet(`/storyboards/${storyboard_id}/asset-versions`)));
|
|
529
|
+
server.tool('get_asset_binding_repair_plan', '只读生成一集历史缺失场景绑定的可审核修复提案。返回原始地点/时段、候选 ID、匹配依据、歧义和 proposed_scene_id;applied=false,绝不按名字自动回填。逐项核对后才由客户决定是否改绑。免费。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.produceGet(`/episodes/${episode_id}/asset-binding-repair-plan`)));
|
|
527
530
|
server.tool('get_storyboards', '读某一集的分镜列表(供审阅/查进度)。含每镜首帧(first_frame_image)与视频(video_url)是否就绪。' +
|
|
531
|
+
'asset_versions 按首帧/尾帧/视频分别给出 generated(已生成)、input_consistent(与当前输入一致)、review_valid(审核有效)、adopted(已采用)、current_effective(当前有效)。null=缺少证据;ready 只表示存在产物,不代表当前有效。旧素材仍可查看。' +
|
|
528
532
|
'★每镜带**台词与说话人**:dialogue(原文,无台词为 null)、dialogue_lines([{speaker,text}] 逐行,' +
|
|
529
533
|
'与字幕/配音同一个解析器拆的——这里的 speaker 就是成片里被配音的那个;舞台提示已剥),' +
|
|
530
534
|
'以及 is_key_moment(1=关键镜,走高端图模)与 emotion_intensity(1-10)。' +
|
|
531
535
|
'核对「台词有没有丢/谁说的/关键镜是哪几镜/情绪曲线」用这一次调用即可,不用逐镜拉;update_shot 改完台词也在这里核对。' +
|
|
532
536
|
'画面/视频/首尾帧提示词仍只在 get_shot_prompts 逐镜读。' +
|
|
533
537
|
'★每镜还带**结构化状态**:frame_status/video_status(ready/pending/authorizing/rejected/failed/none/not_required)、' +
|
|
538
|
+
'★video_status=ready 只表示视频已生成,不等于画面验收通过。video_quality_issues 若含 terminal_cut:' +
|
|
539
|
+
'status=suspected 表示片尾疑似短促切镜,cut_at_s/tail_duration_s 给出位置;status=unavailable 表示探测未完成,不能当检测通过。' +
|
|
540
|
+
'两者均暂停本次自动尾帧回写与续接,先复核视频;字段缺席不代表做过检测,也不要直接重试收费生成。' +
|
|
534
541
|
'★not_required=旁白/片尾卡镜:帧与视频由成片层渲染,本镜不需要生成——数补齐进度时把它当已完成,别重试。' +
|
|
535
542
|
'fail_reason(sensitive/text_sensitive/copyright/face_mismatch/account_overdue/quota_full/authorizing/' +
|
|
536
543
|
'insufficient_credits/transient/repeat_rejected/pair_collateral)、retryable(true=可重试;false=改内容换图,重试无效)、fail_hint(人读文案)。' +
|
|
@@ -553,6 +560,7 @@ export function registerProduceTools(server, client) {
|
|
|
553
560
|
'出图注入谁的定妆图/哪张场景图/哪些道具图由这几项决定;角色名对照 get_characters、道具名对照 get_props。' +
|
|
554
561
|
'改绑用 update_shot 的 character_ids(★全量覆盖,先从这里读现值再改,漏传即解绑)与 character_presence;' +
|
|
555
562
|
'改完再读一次本工具核对。character_bindings 缺席 = 这次没读到(不是没绑),空数组才是没绑。' +
|
|
563
|
+
'★启用双边版本审核时,seam_review.status 为 passed/failed/not_checked/stale;stale 是证据过期,不是画面失败,不据此付费重生。continuity_intent 可用 update_shot 明确。' +
|
|
556
564
|
'★每镜带 **seam_state**(本镜与上一镜的镜间接缝,与官网帧时间线同一判据):' +
|
|
557
565
|
'ok=已续接(首帧就是上镜尾帧,或平台做过首尾帧衔接、已落地且之后两侧都没再重生) / ' +
|
|
558
566
|
'unchained=该连续却没接上(标了连续从没接过,或平台发起的衔接重生没落地:被拒/失败/还在生成——本镜 frame_status 会是 failed/processing;' +
|
|
@@ -1079,22 +1087,19 @@ export function registerProduceTools(server, client) {
|
|
|
1079
1087
|
const image_url = await client.uploadLocalFile(file_path, 'image');
|
|
1080
1088
|
return jsonResult(await client.producePost(`/storyboards/${storyboard_id}/frame`, { image_url, frame_type: frame_type ?? 'first_frame' }));
|
|
1081
1089
|
});
|
|
1082
|
-
server.tool('register_external_delivery', '
|
|
1083
|
-
'不登记的话,平台里的成片记录并不代表客户实际收到的版本,事后无法追溯「交付的是哪一版、每镜用的哪次生成」。' +
|
|
1084
|
-
'平台会自己下载复核 sha256/大小/时长(不采信你报的值),并自动快照每镜此刻的来源素材(当前视频、采用的生成 id 及其哈希、裁剪窗口)' +
|
|
1085
|
-
'和最近一次平台成片;你可在 manifest 里附上外部后期做了什么(例如 {audio:{narration:"本地替换",music:"..."}, trims:[...], ending:"..."})。' +
|
|
1086
|
-
'新登记即为当前交付版,版本号每集递增;不改平台成片(get_final_cut 的 download_url 不变,另返回 delivery)。' +
|
|
1087
|
-
'传 file_path(本地视频,≤300MB,自动上传)或已用 upload-url(kind=footage)上传得到的 file_url,二选一。', {
|
|
1090
|
+
server.tool('register_external_delivery', '登记外部后期成片,服务端核验 sha256、大小和时长。免费。有原始导出时传导出时的 handoff_pack_id 与 handoff_manifest_sha256;平台使用原始冻结清单,不按登记时最新素材猜来源。没有原始导出时来源标未知。登记不代表客户接受;启用追溯后还需 set_current_delivery 选择当前版本,confirm_delivery_acceptance 记录客户明确确认。file_path 或 file_url 二选一。', {
|
|
1088
1091
|
episode_id: z.number().int().positive(),
|
|
1089
1092
|
file_path: z.string().optional().describe('本地成片路径(mp4/mov/webm/m4v,≤300MB)'),
|
|
1090
1093
|
file_url: z.string().optional().describe('已上传到本平台的 public_url(与 file_path 二选一)'),
|
|
1094
|
+
handoff_pack_id: z.string().optional(),
|
|
1095
|
+
handoff_manifest_sha256: z.string().regex(/^[a-f0-9]{64}$/).optional(),
|
|
1091
1096
|
note: z.string().max(500).optional(),
|
|
1092
1097
|
manifest: z.record(z.unknown()).optional().describe('外部后期做了什么(≤64KB),原样存进交付清单的 client 段'),
|
|
1093
|
-
}, async ({ episode_id, file_path, file_url, note, manifest }) => {
|
|
1098
|
+
}, async ({ episode_id, file_path, file_url, note, manifest, handoff_pack_id, handoff_manifest_sha256 }) => {
|
|
1094
1099
|
const url = file_path ? await client.uploadLocalFile(file_path, 'footage') : file_url;
|
|
1095
1100
|
if (!url)
|
|
1096
1101
|
throw new Error('file_path 与 file_url 必须给一个');
|
|
1097
|
-
return jsonResult(await client.producePost(`/episodes/${episode_id}/deliveries`, { file_url: url, note, manifest }));
|
|
1102
|
+
return jsonResult(await client.producePost(`/episodes/${episode_id}/deliveries`, { file_url: url, note, manifest, handoff_pack_id, handoff_manifest_sha256 }));
|
|
1098
1103
|
});
|
|
1099
1104
|
server.tool('list_deliveries', '列本集**所有成片版本**(新→旧,平台成片与外部交付共用一条版本号),每条含 sha256、时长、is_current 与完整清单。免费。' +
|
|
1100
1105
|
'\n★source=platform:平台每出一版成片(compose_episode / rerender_episode / 多画幅)都会**自动登记**,清单记的是**渲染用的那份时间线**——' +
|
|
@@ -1102,6 +1107,7 @@ export function registerProduceTools(server, client) {
|
|
|
1102
1107
|
'以及登记时刻的台词审计分族计数。写交付说明、核对「交出去的是哪一版」以它为准,别凭记忆。' +
|
|
1103
1108
|
'平台版本**不会自动成为当前交付版**;客户选定哪一版,用 set_current_delivery 指过去。' +
|
|
1104
1109
|
'\n★source=external:register_external_delivery 登记的外部后期成片。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.produceGet(`/episodes/${episode_id}/deliveries`)));
|
|
1110
|
+
server.tool('confirm_delivery_acceptance', '只有客户明确确认后才记录接受或撤销接受;不得把下载成功、模型判断或生成完成当客户验收。delivery_id=null 表示只有客户口头确认、文件未核验;否则绑定指定交付版本。选择当前与客户接受是独立事实,使用 set_current_delivery 选定后平台才显示该文件已交付完成。免费,不生成、不改素材。', { episode_id: z.number().int().positive(), delivery_id: z.number().int().positive().nullable(), client_accepted: z.boolean(), confirm_client_statement: z.literal(true), note: z.string().min(1).max(1000) }, async ({ episode_id, ...body }) => jsonResult(await client.producePost(`/episodes/${episode_id}/delivery-confirmation`, body)));
|
|
1105
1111
|
server.tool('set_current_delivery', '把本集的某个成片版本设为当前交付版(例如客户最终选了较早的一版)。免费。平台版本(source=platform)与外部版本都可以设。' +
|
|
1106
1112
|
'只影响 get_final_cut 的 delivery,不改平台成片。', { episode_id: z.number().int().positive(), delivery_id: z.number().int().positive() }, async ({ episode_id, delivery_id }) => jsonResult(await client.producePost(`/episodes/${episode_id}/deliveries/${delivery_id}/current`)));
|
|
1107
1113
|
server.tool('upload_shot_footage', '用**客户自有的整段视频**(录屏 / 产品实拍 / 第三方成片)直接当某镜的视频——实拍素材镜。' +
|
|
@@ -1201,12 +1207,12 @@ export function registerProduceTools(server, client) {
|
|
|
1201
1207
|
server.tool('scan_intra_shot_cuts', '★客户报「镜头切太快 / 一个镜头里画面跳来跳去」时先跑这个。免费零扣费。'
|
|
1202
1208
|
+ '一个分镜本应是**一个连续镜头**,但厂商可能在片内自行换机位硬切(望远镜特写→高空全景→人物中景),'
|
|
1203
1209
|
+ '这类切点在分镜表和 timeline 里都看不到——只能扫画面。'
|
|
1204
|
-
+ '返回 shots_with_cuts(有镜内跳切的镜号)/total_cuts/engine_suspect/message
|
|
1210
|
+
+ '返回 shots_with_cuts(有镜内跳切的镜号)/total_cuts/engine_suspect/message;shots_with_terminal_cuts 单列疑似短促片尾切镜,detail.terminal_cut 给出位置和状态。'
|
|
1205
1211
|
+ '★判读:成片观感切点 = 镜与镜的接缝 + 这里报的镜内跳切;若本项占了大头,那不是剪辑节奏问题,'
|
|
1206
1212
|
+ '重新拆镜或改转场都没用。engine_suspect=true 表示本剧引擎是已知高发源(WAN),'
|
|
1207
1213
|
+ '实测 WAN 11/12 镜有镜内跳切、Seedance 1/6、H3 0/5,且提示词层拦不住(负向约束已在其中)——'
|
|
1208
|
-
+ '
|
|
1209
|
-
+ '
|
|
1214
|
+
+ '先复核实际切点与叙事意图,再决定调整切分还是重新生成;不要因扫描告警直接重试收费生成。'
|
|
1215
|
+
+ '普通镜内多切统计仍排除组模式与显式蒙太奇;但组切分后的单段不能豁免片尾检查,需另看 shots_with_terminal_cuts/detail.terminal_cut。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.produceGet(`/episodes/${episode_id}/intra-shot-cuts`)));
|
|
1210
1216
|
server.tool('scan_burned_subtitles', '★原声剧(视频自带人声)终拼前建议跑一次;客户报「成片里有两层字幕 / 画面里多出一行字」时先跑这个。'
|
|
1211
1217
|
+ '视频厂商有时会无视「不要字幕」的约束,把台词烧进画面——字小、通常只在说出那句台词的一两秒内出现,'
|
|
1212
1218
|
+ '而平台成片还会再叠一层字幕,于是变成双字幕。重新拼接去不掉它,只能 regenerate_shot_video 重出该镜。'
|
|
@@ -1271,6 +1277,8 @@ export function registerProduceTools(server, client) {
|
|
|
1271
1277
|
'有终态描述的是 40.2%;不补描述就重生,送厂商的提示词里根本没有终态段,画出来仍和首帧一样、' +
|
|
1272
1278
|
'还是会被拒,而每次重生都照常扣费。get_shot_prompts 的 terminal_desc_missing=true 就是这个信号。', {
|
|
1273
1279
|
storyboard_id: z.number().int().positive(),
|
|
1280
|
+
product_text_contract: z.object({ version: z.literal(1), strategy: z.enum(['generate_with_review', 'original_media', 'postproduction']), targets: z.array(z.object({ asset_kind: z.enum(['prop', 'product']), asset_id: z.number().int().positive(), reference_url: z.string().url(), region: z.object({ x: z.number(), y: z.number(), width: z.number(), height: z.number() }), exact_text: z.string().min(1).max(256) })).min(1).max(4) }).nullable().optional().describe('明确保留的实物原字:资产 ID、原图、归一化区域、原文及处理方式;生成不保证逐字正确,必须人工核对。null 清除声明,不回填历史。'),
|
|
1281
|
+
continuity_intent: z.enum(['continuous_action', 'shot_change', 'insert_detail', 'jump_cut']).optional().describe('本镜相对上镜的剪辑意图:连续动作、换景别、插入细节、有意跳切。改变后旧双边审核失效;不自动生成或补审。'),
|
|
1274
1282
|
character_ids: z.array(z.number().int().positive()).optional()
|
|
1275
1283
|
.describe('本镜出场角色 ID 列表(★全量覆盖式,非增量,漏传的角色会被解绑)。决定出图时注入哪些角色的定妆图/设定图——非人角色(动物/生物)也必须绑定,否则形象会漂移。id 必须来自当前集已关联角色'),
|
|
1276
1284
|
character_presence: z.array(z.object({
|
|
@@ -1436,9 +1444,11 @@ export function registerProduceTools(server, client) {
|
|
|
1436
1444
|
'\n· totals / by_kind:每类 charged(扣费)、refunded(已退回)、net(净额)、charges/refunds(笔数)。' +
|
|
1437
1445
|
'**net 才是花费**,与网页「本剧已花费」、get_budget_status 同源;charged 含失败后自动退回的空转,只用于核账。' +
|
|
1438
1446
|
'\n· in_flight:已扣费、结果还没出的任务(平台是提交即扣、失败再退,没有单独的预扣)。' +
|
|
1439
|
-
'\n· rework.video:同一镜第 2
|
|
1447
|
+
'\n· rework.video:同一镜第 2 次起的成功出片计数(不证明浪费或失败);原因与图片费用用 get_cost_attribution 核验。旧统计出图不计(首帧/尾帧/best-of-N 候选本来就是同镜多张)。' +
|
|
1440
1448
|
'\n· account_level:音色库克隆/设计/试听等**不属于任何一部剧**的语音扣费,单列、counted_in_drama=false,不计入本剧。' +
|
|
1441
1449
|
'\n· available=false:账本暂时不可达,不给数字(不拿估算冒充),稍后重试。', { drama_id: z.number().int().positive() }, async ({ drama_id }) => jsonResult(await client.produceGet(`/dramas/${drama_id}/bill`)));
|
|
1450
|
+
server.tool('get_cost_attribution', '读取实际扣费与退款逐行归因。免费;净额仍以账本为准。图片和视频均显示任务、冻结输入版本、是否采用和明确登记的返工原因。未知和歧义不猜测;未采用不等于浪费。available=false 时没有可靠金额;complete=false 时明细有截断但 totals 是全额。历史 rework.video 只是重复成功出片的计数,不证明失败或浪费。', { drama_id: z.number().int().positive() }, async ({ drama_id }) => jsonResult(await client.produceGet(`/dramas/${drama_id}/cost-attribution`)));
|
|
1451
|
+
server.tool('classify_cost_reason', '按明确证据登记某一账本行原因,保留操作者和说明。免费,不改变任何扣费或退款;不能仅凭未采用、重试或报错就判为供应商失败。', { drama_id: z.number().int().positive(), ledger_id: z.number().int().positive(), category: z.enum(['normal_alternative', 'customer_change', 'platform_repair', 'provider_failure', 'unknown']), note: z.string().min(1).max(2000) }, async ({ drama_id, ledger_id, category, note }) => jsonResult(await client.producePost(`/dramas/${drama_id}/cost-attribution/${ledger_id}/reason`, { category, note })));
|
|
1442
1452
|
server.tool('get_cost_estimate', '查一部剧的整体成本(点数):已花费 + 还没做的部分的待花费区间 + 分类明细。免费。' +
|
|
1443
1453
|
'already_spent_points 与 get_budget_status 的 spent、网页「本剧已花费」同源(平台扣费账本净额,已减退款),是同一个数。' +
|
|
1444
1454
|
'spent_source=usage_mirror 表示账本暂不可达、回退到本地镜像(偏少,不含文本/配乐),向客户报数时须注明,稍后重试即恢复;spent_note 是口径说明。' +
|
|
@@ -1585,6 +1595,17 @@ export function registerProduceTools(server, client) {
|
|
|
1585
1595
|
server.tool('mark_signature_prop', '标记/取消「招牌道具」(会在多镜复现的关键道具,加强一致性追踪)。signature=false 取消。免费。', { prop_id: z.number().int().positive(), signature: z.boolean().optional().describe('默认 true 标记;false 取消') }, async ({ prop_id, signature }) => jsonResult(await client.producePost(`/props/${prop_id}/signature`, { signature: signature !== false })));
|
|
1586
1596
|
server.tool('get_color_scripts', '读该剧已生成的色彩脚本(全片配色情绪)。generate_color_script 生成、此工具读取。免费。', { drama_id: z.number().int().positive() }, async ({ drama_id }) => jsonResult(await client.produceGet(`/dramas/${drama_id}/color-scripts`)));
|
|
1587
1597
|
server.tool('get_motion_templates', '读该剧已有的动作模板(运镜/动作预设)。generate_motion_templates 生成、此工具读取。免费。', { drama_id: z.number().int().positive() }, async ({ drama_id }) => jsonResult(await client.produceGet(`/dramas/${drama_id}/motion-templates`)));
|
|
1598
|
+
server.tool('record_product_text_review', '免费记录用户对当前产品原字的人工核对结果。只有用户明确打开文件逐字核对并确认结果后才能调用;不得用模型判断冒充人工核对。' +
|
|
1599
|
+
'从 get_storyboards 的 product_text 取当前 contract_hash 和 reviews 中的帧位、文件、generation_id;上传素材 generation_id 为 null,必须传同一响应的 media_version。任一变化后旧审核不能沿用。不重生、不换采用版本、不代表整片客户验收。', { storyboard_id: z.number().int().positive(), frame_type: z.enum(['first_frame', 'last_frame', 'video_identity']), generation_id: z.number().int().positive().nullable(), media_version: z.string().optional(), image_url: z.string(), contract_hash: z.string(), passed: z.boolean(), confirm_visual_review: z.literal(true), note: z.string().min(1).max(1000) }, async ({ storyboard_id, ...body }) => jsonResult(await client.producePost(`/storyboards/${storyboard_id}/product-text-review`, body)));
|
|
1600
|
+
server.tool('audit_seams', '审核当前双边帧的剪辑连续性,只检查、不重生、不替换资产。默认 dry_run=true 返回待审范围,不收费。' +
|
|
1601
|
+
'插入细节仅检查物体身份和状态,不要求复制构图。已有当前有效结论不重复审核。' +
|
|
1602
|
+
'执行会按实际文本 token 用量计费,estimated_points=null 表示金额未报价,并非免费。' +
|
|
1603
|
+
'先展示计划和计费方式,经客户明确接受后才传 dry_run=false 与 confirm_usage_billing=true。' +
|
|
1604
|
+
'执行后用 get_storyboards 的 seam_review 检查实际结果;attempted 不代表通过。', {
|
|
1605
|
+
episode_id: z.number().int().positive(),
|
|
1606
|
+
dry_run: z.boolean().optional().describe('默认 true,只读计划'),
|
|
1607
|
+
confirm_usage_billing: z.boolean().optional().describe('仅客户明确接受按实际文本 token 用量计费后传 true'),
|
|
1608
|
+
}, async ({ episode_id, dry_run, confirm_usage_billing }) => jsonResult(await client.producePost(`/episodes/${episode_id}/audit-seams`, { dry_run: dry_run !== false, confirm_usage_billing: confirm_usage_billing === true })));
|
|
1588
1609
|
// ========== P2 · 连续性 / 场景组 / 多画幅 ==========
|
|
1589
1610
|
server.tool('chain_frames', '整集首尾帧接力链:让每镜首帧承接上镜尾帧,镜间画面连续(比各镜独立出帧更顺)。' +
|
|
1590
1611
|
'★何时调:首帧出完、tail_frame_plan 要的尾帧也补完之后,review_frames / generate_videos 之前。' +
|
|
@@ -1770,7 +1791,8 @@ export function registerProduceTools(server, client) {
|
|
|
1770
1791
|
// ── 素材交接包:客户自己拼片的通道 ──────────────────────────────────────
|
|
1771
1792
|
// 与 compose_episode 的分工:compose_episode = 「平台替你拼」;本组工具 = 「素材给你,
|
|
1772
1793
|
// 你自己决定转场、自己拼」。两条路都不丢客户的对白/音效/配乐/字幕成果。
|
|
1773
|
-
server.tool('export_handoff_pack', '
|
|
1794
|
+
server.tool('export_handoff_pack', '启用交付追溯后会保存不可变导出清单(不改素材)。保留 pack_id 和 manifest_sha256,回传外部成片时引用。' +
|
|
1795
|
+
'导出本集「素材交接包」清单:逐镜裸片 + 对白音轨 + 音效 + 配乐 + 字幕的可下载 URL,' +
|
|
1774
1796
|
'交给你在**自己那边**完成转场决策、拼接、混音、烧字幕——平台不参与终拼。免费,零扣费。\n' +
|
|
1775
1797
|
'★本地调色/第三方 AI 后期:purpose=local_color;只有图片时传 media_type=images,无需生成视频。' +
|
|
1776
1798
|
'本模式保留源文件、关闭导出包的自动 LUT、附带后期说明和本地对比页流程;不上传第三方、不收费生成、不回填平台。' +
|
|
@@ -1799,10 +1821,10 @@ export function registerProduceTools(server, client) {
|
|
|
1799
1821
|
color_goal: z.string().max(4000).optional().describe('客户的后期目标与保护项;作为说明保存,不发送给模型'),
|
|
1800
1822
|
}, async ({ episode_id, media_type, purpose, color_goal }) => {
|
|
1801
1823
|
if (media_type === 'images') {
|
|
1802
|
-
const
|
|
1803
|
-
return jsonResult(
|
|
1824
|
+
const manifest = await client.produceGet(`/episodes/${episode_id}/handoff-pack?media_type=images`);
|
|
1825
|
+
return jsonResult(localColorHandoff(manifest, color_goal, manifest.missing_shots ?? []));
|
|
1804
1826
|
}
|
|
1805
|
-
const manifest = await client.produceGet(`/episodes/${episode_id}/handoff-pack`);
|
|
1827
|
+
const manifest = await client.produceGet(`/episodes/${episode_id}/handoff-pack${purpose === 'local_color' ? '?purpose=local_color' : ''}`);
|
|
1806
1828
|
if (purpose === 'local_color')
|
|
1807
1829
|
return jsonResult(localColorHandoff(manifest, color_goal));
|
|
1808
1830
|
return jsonResult({
|
package/openapi.json
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"openapi": "3.1.0",
|
|
3
3
|
"info": {
|
|
4
4
|
"title": "StarReel Production API",
|
|
5
|
-
"version": "0.1.
|
|
6
|
-
"description": "Turn a script into a finished, downloadable short-drama episode over REST.\n\nPipeline: script → AI rewrite → cast/scenes/props extraction → storyboards → portraits & sheets + scene plates → keyframes → video shots → TTS → final cut (.mp4).\n\n**Billing is prepaid and agent-safe**: big-ticket stages are quote-then-generate (`quote_*` returns a `quote_id`). For video, quote == actual charge. For images the quote is a *range* — models billed per reference image are priced before those are assembled, so `estimated_points` is the upper bound (size the balance by it and a run never dies half-way) and `typical_points` is the usual cost; fixed-price models return the two equal. Insufficient balance returns 402 — nothing half-runs and the account never goes negative.\n\nAuth: exchange your API key at `POST /v1/agent/token` for a 15-minute bearer token.\n\nGenerated from the @starreel/mcp v0.1.
|
|
5
|
+
"version": "0.1.107",
|
|
6
|
+
"description": "Turn a script into a finished, downloadable short-drama episode over REST.\n\nPipeline: script → AI rewrite → cast/scenes/props extraction → storyboards → portraits & sheets + scene plates → keyframes → video shots → TTS → final cut (.mp4).\n\n**Billing is prepaid and agent-safe**: big-ticket stages are quote-then-generate (`quote_*` returns a `quote_id`). For video, quote == actual charge. For images the quote is a *range* — models billed per reference image are priced before those are assembled, so `estimated_points` is the upper bound (size the balance by it and a run never dies half-way) and `typical_points` is the usual cost; fixed-price models return the two equal. Insufficient balance returns 402 — nothing half-runs and the account never goes negative.\n\nAuth: exchange your API key at `POST /v1/agent/token` for a 15-minute bearer token.\n\nGenerated from the @starreel/mcp v0.1.107 tool surface (operationIds match MCP tool names 1:1)."
|
|
7
7
|
},
|
|
8
8
|
"servers": [
|
|
9
9
|
{
|
|
@@ -1375,7 +1375,7 @@
|
|
|
1375
1375
|
"get": {
|
|
1376
1376
|
"operationId": "get_drama_bill",
|
|
1377
1377
|
"summary": "本剧净费用账单(免费)",
|
|
1378
|
-
"description": "本剧净费用账单(免费)。核账、回答「到底花了多少、钱花在哪、退了多少」时用它,别自己拼流水。\n· totals / by_kind:每类 charged(扣费)、refunded(已退回)、net(净额)、charges/refunds(笔数)。**net 才是花费**,与网页「本剧已花费」、get_budget_status 同源;charged 含失败后自动退回的空转,只用于核账。\n· in_flight:已扣费、结果还没出的任务(平台是提交即扣、失败再退,没有单独的预扣)。\n· rework.video:同一镜第 2
|
|
1378
|
+
"description": "本剧净费用账单(免费)。核账、回答「到底花了多少、钱花在哪、退了多少」时用它,别自己拼流水。\n· totals / by_kind:每类 charged(扣费)、refunded(已退回)、net(净额)、charges/refunds(笔数)。**net 才是花费**,与网页「本剧已花费」、get_budget_status 同源;charged 含失败后自动退回的空转,只用于核账。\n· in_flight:已扣费、结果还没出的任务(平台是提交即扣、失败再退,没有单独的预扣)。\n· rework.video:同一镜第 2 次起的成功出片计数(不证明浪费或失败);原因与图片费用用 get_cost_attribution 核验。旧统计出图不计(首帧/尾帧/best-of-N 候选本来就是同镜多张)。\n· account_level:音色库克隆/设计/试听等**不属于任何一部剧**的语音扣费,单列、counted_in_drama=false,不计入本剧。\n· available=false:账本暂时不可达,不给数字(不拿估算冒充),稍后重试。",
|
|
1379
1379
|
"tags": [
|
|
1380
1380
|
"dramas"
|
|
1381
1381
|
],
|
|
@@ -1575,6 +1575,140 @@
|
|
|
1575
1575
|
}
|
|
1576
1576
|
}
|
|
1577
1577
|
},
|
|
1578
|
+
"/dramas/{drama_id}/cost-attribution": {
|
|
1579
|
+
"get": {
|
|
1580
|
+
"operationId": "get_cost_attribution",
|
|
1581
|
+
"summary": "读取实际扣费与退款逐行归因",
|
|
1582
|
+
"description": "读取实际扣费与退款逐行归因。免费;净额仍以账本为准。图片和视频均显示任务、冻结输入版本、是否采用和明确登记的返工原因。未知和歧义不猜测;未采用不等于浪费。available=false 时没有可靠金额;complete=false 时明细有截断但 totals 是全额。历史 rework.video 只是重复成功出片的计数,不证明失败或浪费。",
|
|
1583
|
+
"tags": [
|
|
1584
|
+
"dramas"
|
|
1585
|
+
],
|
|
1586
|
+
"parameters": [
|
|
1587
|
+
{
|
|
1588
|
+
"name": "drama_id",
|
|
1589
|
+
"in": "path",
|
|
1590
|
+
"required": true,
|
|
1591
|
+
"schema": {
|
|
1592
|
+
"type": "integer",
|
|
1593
|
+
"exclusiveMinimum": 0
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
],
|
|
1597
|
+
"responses": {
|
|
1598
|
+
"200": {
|
|
1599
|
+
"description": "StarReel envelope",
|
|
1600
|
+
"content": {
|
|
1601
|
+
"application/json": {
|
|
1602
|
+
"schema": {
|
|
1603
|
+
"type": "object",
|
|
1604
|
+
"properties": {
|
|
1605
|
+
"code": {
|
|
1606
|
+
"type": "integer"
|
|
1607
|
+
},
|
|
1608
|
+
"message": {
|
|
1609
|
+
"type": "string"
|
|
1610
|
+
},
|
|
1611
|
+
"data": {
|
|
1612
|
+
"description": "Operation result payload"
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
},
|
|
1619
|
+
"402": {
|
|
1620
|
+
"description": "Insufficient prepaid balance (never overdrafts); response carries `needed` points"
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
},
|
|
1625
|
+
"/dramas/{drama_id}/cost-attribution/{ledger_id}/reason": {
|
|
1626
|
+
"post": {
|
|
1627
|
+
"operationId": "classify_cost_reason",
|
|
1628
|
+
"summary": "按明确证据登记某一账本行原因,保留操作者和说明",
|
|
1629
|
+
"description": "按明确证据登记某一账本行原因,保留操作者和说明。免费,不改变任何扣费或退款;不能仅凭未采用、重试或报错就判为供应商失败。",
|
|
1630
|
+
"tags": [
|
|
1631
|
+
"dramas"
|
|
1632
|
+
],
|
|
1633
|
+
"parameters": [
|
|
1634
|
+
{
|
|
1635
|
+
"name": "drama_id",
|
|
1636
|
+
"in": "path",
|
|
1637
|
+
"required": true,
|
|
1638
|
+
"schema": {
|
|
1639
|
+
"type": "integer",
|
|
1640
|
+
"exclusiveMinimum": 0
|
|
1641
|
+
}
|
|
1642
|
+
},
|
|
1643
|
+
{
|
|
1644
|
+
"name": "ledger_id",
|
|
1645
|
+
"in": "path",
|
|
1646
|
+
"required": true,
|
|
1647
|
+
"schema": {
|
|
1648
|
+
"type": "integer",
|
|
1649
|
+
"exclusiveMinimum": 0
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
],
|
|
1653
|
+
"requestBody": {
|
|
1654
|
+
"required": true,
|
|
1655
|
+
"content": {
|
|
1656
|
+
"application/json": {
|
|
1657
|
+
"schema": {
|
|
1658
|
+
"type": "object",
|
|
1659
|
+
"properties": {
|
|
1660
|
+
"category": {
|
|
1661
|
+
"type": "string",
|
|
1662
|
+
"enum": [
|
|
1663
|
+
"normal_alternative",
|
|
1664
|
+
"customer_change",
|
|
1665
|
+
"platform_repair",
|
|
1666
|
+
"provider_failure",
|
|
1667
|
+
"unknown"
|
|
1668
|
+
]
|
|
1669
|
+
},
|
|
1670
|
+
"note": {
|
|
1671
|
+
"type": "string",
|
|
1672
|
+
"minLength": 1,
|
|
1673
|
+
"maxLength": 2000
|
|
1674
|
+
}
|
|
1675
|
+
},
|
|
1676
|
+
"required": [
|
|
1677
|
+
"category",
|
|
1678
|
+
"note"
|
|
1679
|
+
]
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
},
|
|
1684
|
+
"responses": {
|
|
1685
|
+
"200": {
|
|
1686
|
+
"description": "StarReel envelope",
|
|
1687
|
+
"content": {
|
|
1688
|
+
"application/json": {
|
|
1689
|
+
"schema": {
|
|
1690
|
+
"type": "object",
|
|
1691
|
+
"properties": {
|
|
1692
|
+
"code": {
|
|
1693
|
+
"type": "integer"
|
|
1694
|
+
},
|
|
1695
|
+
"message": {
|
|
1696
|
+
"type": "string"
|
|
1697
|
+
},
|
|
1698
|
+
"data": {
|
|
1699
|
+
"description": "Operation result payload"
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
},
|
|
1706
|
+
"402": {
|
|
1707
|
+
"description": "Insufficient prepaid balance (never overdrafts); response carries `needed` points"
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
},
|
|
1578
1712
|
"/dramas/{drama_id}/cost-estimate": {
|
|
1579
1713
|
"get": {
|
|
1580
1714
|
"operationId": "get_cost_estimate",
|
|
@@ -2767,6 +2901,53 @@
|
|
|
2767
2901
|
}
|
|
2768
2902
|
}
|
|
2769
2903
|
},
|
|
2904
|
+
"/episodes/{episode_id}/asset-binding-repair-plan": {
|
|
2905
|
+
"get": {
|
|
2906
|
+
"operationId": "get_asset_binding_repair_plan",
|
|
2907
|
+
"summary": "只读生成一集历史缺失场景绑定的可审核修复提案",
|
|
2908
|
+
"description": "只读生成一集历史缺失场景绑定的可审核修复提案。返回原始地点/时段、候选 ID、匹配依据、歧义和 proposed_scene_id;applied=false,绝不按名字自动回填。逐项核对后才由客户决定是否改绑。免费。",
|
|
2909
|
+
"tags": [
|
|
2910
|
+
"episodes"
|
|
2911
|
+
],
|
|
2912
|
+
"parameters": [
|
|
2913
|
+
{
|
|
2914
|
+
"name": "episode_id",
|
|
2915
|
+
"in": "path",
|
|
2916
|
+
"required": true,
|
|
2917
|
+
"schema": {
|
|
2918
|
+
"type": "integer",
|
|
2919
|
+
"exclusiveMinimum": 0
|
|
2920
|
+
}
|
|
2921
|
+
}
|
|
2922
|
+
],
|
|
2923
|
+
"responses": {
|
|
2924
|
+
"200": {
|
|
2925
|
+
"description": "StarReel envelope",
|
|
2926
|
+
"content": {
|
|
2927
|
+
"application/json": {
|
|
2928
|
+
"schema": {
|
|
2929
|
+
"type": "object",
|
|
2930
|
+
"properties": {
|
|
2931
|
+
"code": {
|
|
2932
|
+
"type": "integer"
|
|
2933
|
+
},
|
|
2934
|
+
"message": {
|
|
2935
|
+
"type": "string"
|
|
2936
|
+
},
|
|
2937
|
+
"data": {
|
|
2938
|
+
"description": "Operation result payload"
|
|
2939
|
+
}
|
|
2940
|
+
}
|
|
2941
|
+
}
|
|
2942
|
+
}
|
|
2943
|
+
}
|
|
2944
|
+
},
|
|
2945
|
+
"402": {
|
|
2946
|
+
"description": "Insufficient prepaid balance (never overdrafts); response carries `needed` points"
|
|
2947
|
+
}
|
|
2948
|
+
}
|
|
2949
|
+
}
|
|
2950
|
+
},
|
|
2770
2951
|
"/episodes/{episode_id}/asset-recovery": {
|
|
2771
2952
|
"get": {
|
|
2772
2953
|
"operationId": "get_asset_recovery",
|
|
@@ -3074,6 +3255,71 @@
|
|
|
3074
3255
|
}
|
|
3075
3256
|
}
|
|
3076
3257
|
},
|
|
3258
|
+
"/episodes/{episode_id}/audit-seams": {
|
|
3259
|
+
"post": {
|
|
3260
|
+
"operationId": "audit_seams",
|
|
3261
|
+
"summary": "审核当前双边帧的剪辑连续性,只检查、不重生、不替换资产",
|
|
3262
|
+
"description": "审核当前双边帧的剪辑连续性,只检查、不重生、不替换资产。默认 dry_run=true 返回待审范围,不收费。插入细节仅检查物体身份和状态,不要求复制构图。已有当前有效结论不重复审核。执行会按实际文本 token 用量计费,estimated_points=null 表示金额未报价,并非免费。先展示计划和计费方式,经客户明确接受后才传 dry_run=false 与 confirm_usage_billing=true。执行后用 get_storyboards 的 seam_review 检查实际结果;attempted 不代表通过。",
|
|
3263
|
+
"tags": [
|
|
3264
|
+
"episodes"
|
|
3265
|
+
],
|
|
3266
|
+
"parameters": [
|
|
3267
|
+
{
|
|
3268
|
+
"name": "episode_id",
|
|
3269
|
+
"in": "path",
|
|
3270
|
+
"required": true,
|
|
3271
|
+
"schema": {
|
|
3272
|
+
"type": "integer",
|
|
3273
|
+
"exclusiveMinimum": 0
|
|
3274
|
+
}
|
|
3275
|
+
}
|
|
3276
|
+
],
|
|
3277
|
+
"requestBody": {
|
|
3278
|
+
"required": false,
|
|
3279
|
+
"content": {
|
|
3280
|
+
"application/json": {
|
|
3281
|
+
"schema": {
|
|
3282
|
+
"type": "object",
|
|
3283
|
+
"properties": {
|
|
3284
|
+
"dry_run": {
|
|
3285
|
+
"type": "boolean"
|
|
3286
|
+
},
|
|
3287
|
+
"confirm_usage_billing": {
|
|
3288
|
+
"type": "boolean"
|
|
3289
|
+
}
|
|
3290
|
+
}
|
|
3291
|
+
}
|
|
3292
|
+
}
|
|
3293
|
+
}
|
|
3294
|
+
},
|
|
3295
|
+
"responses": {
|
|
3296
|
+
"200": {
|
|
3297
|
+
"description": "StarReel envelope",
|
|
3298
|
+
"content": {
|
|
3299
|
+
"application/json": {
|
|
3300
|
+
"schema": {
|
|
3301
|
+
"type": "object",
|
|
3302
|
+
"properties": {
|
|
3303
|
+
"code": {
|
|
3304
|
+
"type": "integer"
|
|
3305
|
+
},
|
|
3306
|
+
"message": {
|
|
3307
|
+
"type": "string"
|
|
3308
|
+
},
|
|
3309
|
+
"data": {
|
|
3310
|
+
"description": "Operation result payload"
|
|
3311
|
+
}
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3314
|
+
}
|
|
3315
|
+
}
|
|
3316
|
+
},
|
|
3317
|
+
"402": {
|
|
3318
|
+
"description": "Insufficient prepaid balance (never overdrafts); response carries `needed` points"
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3321
|
+
}
|
|
3322
|
+
},
|
|
3077
3323
|
"/episodes/{episode_id}/autofill-status": {
|
|
3078
3324
|
"get": {
|
|
3079
3325
|
"operationId": "get_autofill_status",
|
|
@@ -3558,6 +3804,87 @@
|
|
|
3558
3804
|
}
|
|
3559
3805
|
}
|
|
3560
3806
|
},
|
|
3807
|
+
"/episodes/{episode_id}/delivery-confirmation": {
|
|
3808
|
+
"post": {
|
|
3809
|
+
"operationId": "confirm_delivery_acceptance",
|
|
3810
|
+
"summary": "只有客户明确确认后才记录接受或撤销接受;不得把下载成功、模型判断或生成完成当客户验收",
|
|
3811
|
+
"description": "只有客户明确确认后才记录接受或撤销接受;不得把下载成功、模型判断或生成完成当客户验收。delivery_id=null 表示只有客户口头确认、文件未核验;否则绑定指定交付版本。选择当前与客户接受是独立事实,使用 set_current_delivery 选定后平台才显示该文件已交付完成。免费,不生成、不改素材。",
|
|
3812
|
+
"tags": [
|
|
3813
|
+
"episodes"
|
|
3814
|
+
],
|
|
3815
|
+
"parameters": [
|
|
3816
|
+
{
|
|
3817
|
+
"name": "episode_id",
|
|
3818
|
+
"in": "path",
|
|
3819
|
+
"required": true,
|
|
3820
|
+
"schema": {
|
|
3821
|
+
"type": "integer",
|
|
3822
|
+
"exclusiveMinimum": 0
|
|
3823
|
+
}
|
|
3824
|
+
}
|
|
3825
|
+
],
|
|
3826
|
+
"requestBody": {
|
|
3827
|
+
"required": true,
|
|
3828
|
+
"content": {
|
|
3829
|
+
"application/json": {
|
|
3830
|
+
"schema": {
|
|
3831
|
+
"type": "object",
|
|
3832
|
+
"properties": {
|
|
3833
|
+
"delivery_id": {
|
|
3834
|
+
"type": "integer",
|
|
3835
|
+
"exclusiveMinimum": 0
|
|
3836
|
+
},
|
|
3837
|
+
"client_accepted": {
|
|
3838
|
+
"type": "boolean"
|
|
3839
|
+
},
|
|
3840
|
+
"confirm_client_statement": {
|
|
3841
|
+
"type": "boolean",
|
|
3842
|
+
"const": true
|
|
3843
|
+
},
|
|
3844
|
+
"note": {
|
|
3845
|
+
"type": "string",
|
|
3846
|
+
"minLength": 1,
|
|
3847
|
+
"maxLength": 1000
|
|
3848
|
+
}
|
|
3849
|
+
},
|
|
3850
|
+
"required": [
|
|
3851
|
+
"delivery_id",
|
|
3852
|
+
"client_accepted",
|
|
3853
|
+
"confirm_client_statement",
|
|
3854
|
+
"note"
|
|
3855
|
+
]
|
|
3856
|
+
}
|
|
3857
|
+
}
|
|
3858
|
+
}
|
|
3859
|
+
},
|
|
3860
|
+
"responses": {
|
|
3861
|
+
"200": {
|
|
3862
|
+
"description": "StarReel envelope",
|
|
3863
|
+
"content": {
|
|
3864
|
+
"application/json": {
|
|
3865
|
+
"schema": {
|
|
3866
|
+
"type": "object",
|
|
3867
|
+
"properties": {
|
|
3868
|
+
"code": {
|
|
3869
|
+
"type": "integer"
|
|
3870
|
+
},
|
|
3871
|
+
"message": {
|
|
3872
|
+
"type": "string"
|
|
3873
|
+
},
|
|
3874
|
+
"data": {
|
|
3875
|
+
"description": "Operation result payload"
|
|
3876
|
+
}
|
|
3877
|
+
}
|
|
3878
|
+
}
|
|
3879
|
+
}
|
|
3880
|
+
}
|
|
3881
|
+
},
|
|
3882
|
+
"402": {
|
|
3883
|
+
"description": "Insufficient prepaid balance (never overdrafts); response carries `needed` points"
|
|
3884
|
+
}
|
|
3885
|
+
}
|
|
3886
|
+
}
|
|
3887
|
+
},
|
|
3561
3888
|
"/episodes/{episode_id}/derive-pose-chain": {
|
|
3562
3889
|
"post": {
|
|
3563
3890
|
"operationId": "derive_pose_chain",
|
|
@@ -4694,8 +5021,8 @@
|
|
|
4694
5021
|
"/episodes/{episode_id}/handoff-pack": {
|
|
4695
5022
|
"get": {
|
|
4696
5023
|
"operationId": "export_handoff_pack",
|
|
4697
|
-
"summary": "
|
|
4698
|
-
"description": "
|
|
5024
|
+
"summary": "启用交付追溯后会保存不可变导出清单(不改素材)",
|
|
5025
|
+
"description": "启用交付追溯后会保存不可变导出清单(不改素材)。保留 pack_id 和 manifest_sha256,回传外部成片时引用。导出本集「素材交接包」清单:逐镜裸片 + 对白音轨 + 音效 + 配乐 + 字幕的可下载 URL,交给你在**自己那边**完成转场决策、拼接、混音、烧字幕——平台不参与终拼。免费,零扣费。\n★本地调色/第三方 AI 后期:purpose=local_color;只有图片时传 media_type=images,无需生成视频。本模式保留源文件、关闭导出包的自动 LUT、附带后期说明和本地对比页流程;不上传第三方、不收费生成、不回填平台。图片来源可能已有处理,不能把所有导出图承诺为未调色原片。\n\n【推荐流程】① 调本工具拿 manifest;② 按 clips[].url 把裸片下载到本地;③ 你自己看片判断每个接缝该用什么转场(manifest 给了 scene_boundary 场景边界作判据),写一份 plan.json;④ 用 get_handoff_toolchain 拿到 compile_timeline.py 展开时间轴、assemble.sh 装配出成片。工具链已经把「加了重叠转场之后字幕/对白/音效怎么跟着位移」算好了。\n\n【三个不看就会翻车的事实】\n① **人声在哪要逐镜读 `shots[].voice_track.location`,不能读整集的 audio_contract.mode**——后者是整剧级声明,而全画外旁白镜的旁白是平台在完成侧混进裸片的,同一集里逐镜可以不同。四种取值各有各的处置:`separate_file`=对白在 dialogue_audio,不铺这镜就没台词;`baked_in_clip`=已在裸片音轨里,再叠一遍会双声;`missing`=**平台侧确认缺失**(旁白补偿失败),字幕还在但声音哪都没有——回平台重生成该镜,拉长转场掩盖不了;`unknown`=有台词却查不到来源,**必须试听裸片**再决定。★有字幕从来不等于有声音:字幕是逐句的,音频是逐镜的。`conflicts_with_contract=true` 的镜以实测为准,notes 里已按镜号点名。\n② 每镜必须按 trim_head_ms / duration_ms 裁剪再用;直接拼整条裸片会把平台已经 QC 掉的首尾形变帧一起拼进去。\n③ 字幕 cue、dialogue_audio.offset_ms、sfx[].offset_ms 的基准都是「该镜 trim 之后的第 0 毫秒」,不是成片绝对时间。你加多少重叠转场都不用改它们——交给 compile_timeline.py 展开,别手算累加。\n\n想让平台代拼、要平台级质量闸(终拼预检/音画等长/响度母带),改用 compose_episode。",
|
|
4699
5026
|
"tags": [
|
|
4700
5027
|
"episodes"
|
|
4701
5028
|
],
|
|
@@ -4789,7 +5116,7 @@
|
|
|
4789
5116
|
"get": {
|
|
4790
5117
|
"operationId": "scan_intra_shot_cuts",
|
|
4791
5118
|
"summary": "★客户报「镜头切太快 / 一个镜头里画面跳来跳去」时先跑这个",
|
|
4792
|
-
"description": "★客户报「镜头切太快 / 一个镜头里画面跳来跳去」时先跑这个。免费零扣费。一个分镜本应是**一个连续镜头**,但厂商可能在片内自行换机位硬切(望远镜特写→高空全景→人物中景),这类切点在分镜表和 timeline 里都看不到——只能扫画面。返回 shots_with_cuts(有镜内跳切的镜号)/total_cuts/engine_suspect/message
|
|
5119
|
+
"description": "★客户报「镜头切太快 / 一个镜头里画面跳来跳去」时先跑这个。免费零扣费。一个分镜本应是**一个连续镜头**,但厂商可能在片内自行换机位硬切(望远镜特写→高空全景→人物中景),这类切点在分镜表和 timeline 里都看不到——只能扫画面。返回 shots_with_cuts(有镜内跳切的镜号)/total_cuts/engine_suspect/message;shots_with_terminal_cuts 单列疑似短促片尾切镜,detail.terminal_cut 给出位置和状态。★判读:成片观感切点 = 镜与镜的接缝 + 这里报的镜内跳切;若本项占了大头,那不是剪辑节奏问题,重新拆镜或改转场都没用。engine_suspect=true 表示本剧引擎是已知高发源(WAN),实测 WAN 11/12 镜有镜内跳切、Seedance 1/6、H3 0/5,且提示词层拦不住(负向约束已在其中)——先复核实际切点与叙事意图,再决定调整切分还是重新生成;不要因扫描告警直接重试收费生成。普通镜内多切统计仍排除组模式与显式蒙太奇;但组切分后的单段不能豁免片尾检查,需另看 shots_with_terminal_cuts/detail.terminal_cut。",
|
|
4793
5120
|
"tags": [
|
|
4794
5121
|
"episodes"
|
|
4795
5122
|
],
|
|
@@ -4930,7 +5257,7 @@
|
|
|
4930
5257
|
"get": {
|
|
4931
5258
|
"operationId": "get_pipeline_status",
|
|
4932
5259
|
"summary": "查某一集完整工作流的进度(script_rewrite/提取/分镜/语音/出图/出视频/合成/配乐/终拼…各步 done/partial/pending/not_required)",
|
|
4933
|
-
"description": "查某一集完整工作流的进度(script_rewrite/提取/分镜/语音/出图/出视频/合成/配乐/终拼…各步 done/partial/pending/not_required)
|
|
5260
|
+
"description": "查某一集完整工作流的进度(script_rewrite/提取/分镜/语音/出图/出视频/合成/配乐/终拼…各步 done/partial/pending/not_required)。照它按序推进、不跳步。免费。asset_versions_summary 将 generated、input_consistent、review_valid、adopted 和 current_effective 分开计数;不能把 generate_videos.completed 当当前有效数量。★not_required=当前模式不需要该步(如原声剧的 TTS 三步、关配乐的 generate_bgm),不是没做完,别去补做。图片/视频分母已剔除卡镜(shots_not_applicable);merge_episode.bgm_stale=true 表示配乐晚于成片,重新 compose_episode 即可。",
|
|
4934
5261
|
"tags": [
|
|
4935
5262
|
"episodes"
|
|
4936
5263
|
],
|
|
@@ -6333,7 +6660,7 @@
|
|
|
6333
6660
|
"get": {
|
|
6334
6661
|
"operationId": "get_storyboards",
|
|
6335
6662
|
"summary": "读某一集的分镜列表(供审阅/查进度)",
|
|
6336
|
-
"description": "读某一集的分镜列表(供审阅/查进度)。含每镜首帧(first_frame_image)与视频(video_url)
|
|
6663
|
+
"description": "读某一集的分镜列表(供审阅/查进度)。含每镜首帧(first_frame_image)与视频(video_url)是否就绪。asset_versions 按首帧/尾帧/视频分别给出 generated(已生成)、input_consistent(与当前输入一致)、review_valid(审核有效)、adopted(已采用)、current_effective(当前有效)。null=缺少证据;ready 只表示存在产物,不代表当前有效。旧素材仍可查看。★每镜带**台词与说话人**:dialogue(原文,无台词为 null)、dialogue_lines([{speaker,text}] 逐行,与字幕/配音同一个解析器拆的——这里的 speaker 就是成片里被配音的那个;舞台提示已剥),以及 is_key_moment(1=关键镜,走高端图模)与 emotion_intensity(1-10)。核对「台词有没有丢/谁说的/关键镜是哪几镜/情绪曲线」用这一次调用即可,不用逐镜拉;update_shot 改完台词也在这里核对。画面/视频/首尾帧提示词仍只在 get_shot_prompts 逐镜读。★每镜还带**结构化状态**:frame_status/video_status(ready/pending/authorizing/rejected/failed/none/not_required)、★video_status=ready 只表示视频已生成,不等于画面验收通过。video_quality_issues 若含 terminal_cut:status=suspected 表示片尾疑似短促切镜,cut_at_s/tail_duration_s 给出位置;status=unavailable 表示探测未完成,不能当检测通过。两者均暂停本次自动尾帧回写与续接,先复核视频;字段缺席不代表做过检测,也不要直接重试收费生成。★not_required=旁白/片尾卡镜:帧与视频由成片层渲染,本镜不需要生成——数补齐进度时把它当已完成,别重试。fail_reason(sensitive/text_sensitive/copyright/face_mismatch/account_overdue/quota_full/authorizing/insufficient_credits/transient/repeat_rejected/pair_collateral)、retryable(true=可重试;false=改内容换图,重试无效)、fail_hint(人读文案)。照 retryable 判该重试还是该改内容,别解析中文。★pair_collateral=同镜另一帧未通过、本帧随批结束——**本帧自身没被判不合格,别去改它**:有 reopen_pair_id 就用它只重掷有过错的一侧,否则直接重生本镜。★若某镜带 degraded_frames:[{frame_type,reason,reason_label,since,hint}],表示该帧是系统在同因连拒熔断后**放行**的(判据照记未拒),URL 上与干净帧无区别但需人工复核;不满意按 hint 修正输入后 generate_shot_frame 重生该帧。★terminal_desc_missing=true:该镜标为「状态改变」却三处都没说结束时什么样——**出尾帧前**就能看出来,现在整集一次拿到(此前只有 get_shot_prompts 能逐镜问,一集几十次没人会去问)。先 update_shot 把结束状态写进 last_frame_prompt 再出尾帧:照现状硬出的历史成功率 9.4%,写了终态的 40.2%,而每次被拒都照常扣费。确实该「几乎不变」的镜才用 generate_shot_frame 的 allow_missing_terminal 放行。★first_frame_source/last_frame_source='upload' 表示该帧是**外部上传图**(绕开了身份锚/画风锚/best-of-N/帧审计整条质量链路)——人物·服装·画风漂移排查先看这些镜;外部图导致的漂移不是平台生成质量问题,修复正路是删掉外部图改走 generate_shot_frame 平台重生。★若某镜带 reopen_pair_id:该镜首尾帧同时生成时只有一侧真的有问题、另一侧是无辜陪拒,原样传给 generate_shot_frame 的 reopen_pair_id 参数可以只重掷有问题的那一侧(省一半算力/费用,不会拿去生成一张这次根本没打算重做的图)。没有这个字段就按 fail_reason/retryable 走常规重试。免费。★每镜还带**绑定**(只有 ID):character_ids(本镜绑定的角色)、character_bindings[{character_id,presence}](presence=on_screen 在画面 / voice_only 只有声音、不进画面)、scene_id、prop_ids、active_wardrobe_id。出图注入谁的定妆图/哪张场景图/哪些道具图由这几项决定;角色名对照 get_characters、道具名对照 get_props。改绑用 update_shot 的 character_ids(★全量覆盖,先从这里读现值再改,漏传即解绑)与 character_presence;改完再读一次本工具核对。character_bindings 缺席 = 这次没读到(不是没绑),空数组才是没绑。★启用双边版本审核时,seam_review.status 为 passed/failed/not_checked/stale;stale 是证据过期,不是画面失败,不据此付费重生。continuity_intent 可用 update_shot 明确。★每镜带 **seam_state**(本镜与上一镜的镜间接缝,与官网帧时间线同一判据):ok=已续接(首帧就是上镜尾帧,或平台做过首尾帧衔接、已落地且之后两侧都没再重生) / unchained=该连续却没接上(标了连续从没接过,或平台发起的衔接重生没落地:被拒/失败/还在生成——本镜 frame_status 会是 failed/processing;或衔接审过之后本镜首帧又被重生过) / broken=接过但没接上(seam_failed_dims 给出哪几维不连续:characters/wardrobe/props/lighting/scene;seam_audit_status=stale 且没有维度 = 上一镜尾帧在衔接之后又重生过,本镜首帧接的还是旧尾帧) / intended=有意切换(硬切/换场/时间跳跃/景别大跳/插入镜/外部上传帧),不用管 / missing=两侧帧没齐 / unknown=没标意图也没接过(系统没判,不是有问题) / na=首镜或旁白卡。seam_audit_status=pending 表示衔接已落地、平台的衔接审计还没出结论。出视频前只需处理 unchained 与 broken:整集用 chain_frames(先 dry_run),单道用 chain_shot_from_prev / chain_shot_from。",
|
|
6337
6664
|
"tags": [
|
|
6338
6665
|
"episodes"
|
|
6339
6666
|
],
|
|
@@ -8793,6 +9120,100 @@
|
|
|
8793
9120
|
"schema": {
|
|
8794
9121
|
"type": "object",
|
|
8795
9122
|
"properties": {
|
|
9123
|
+
"product_text_contract": {
|
|
9124
|
+
"type": "object",
|
|
9125
|
+
"properties": {
|
|
9126
|
+
"version": {
|
|
9127
|
+
"type": "number",
|
|
9128
|
+
"const": 1
|
|
9129
|
+
},
|
|
9130
|
+
"strategy": {
|
|
9131
|
+
"type": "string",
|
|
9132
|
+
"enum": [
|
|
9133
|
+
"generate_with_review",
|
|
9134
|
+
"original_media",
|
|
9135
|
+
"postproduction"
|
|
9136
|
+
]
|
|
9137
|
+
},
|
|
9138
|
+
"targets": {
|
|
9139
|
+
"type": "array",
|
|
9140
|
+
"items": {
|
|
9141
|
+
"type": "object",
|
|
9142
|
+
"properties": {
|
|
9143
|
+
"asset_kind": {
|
|
9144
|
+
"type": "string",
|
|
9145
|
+
"enum": [
|
|
9146
|
+
"prop",
|
|
9147
|
+
"product"
|
|
9148
|
+
]
|
|
9149
|
+
},
|
|
9150
|
+
"asset_id": {
|
|
9151
|
+
"type": "integer",
|
|
9152
|
+
"exclusiveMinimum": 0
|
|
9153
|
+
},
|
|
9154
|
+
"reference_url": {
|
|
9155
|
+
"type": "string",
|
|
9156
|
+
"format": "uri"
|
|
9157
|
+
},
|
|
9158
|
+
"region": {
|
|
9159
|
+
"type": "object",
|
|
9160
|
+
"properties": {
|
|
9161
|
+
"x": {
|
|
9162
|
+
"type": "number"
|
|
9163
|
+
},
|
|
9164
|
+
"y": {
|
|
9165
|
+
"type": "number"
|
|
9166
|
+
},
|
|
9167
|
+
"width": {
|
|
9168
|
+
"type": "number"
|
|
9169
|
+
},
|
|
9170
|
+
"height": {
|
|
9171
|
+
"type": "number"
|
|
9172
|
+
}
|
|
9173
|
+
},
|
|
9174
|
+
"required": [
|
|
9175
|
+
"x",
|
|
9176
|
+
"y",
|
|
9177
|
+
"width",
|
|
9178
|
+
"height"
|
|
9179
|
+
],
|
|
9180
|
+
"additionalProperties": false
|
|
9181
|
+
},
|
|
9182
|
+
"exact_text": {
|
|
9183
|
+
"type": "string",
|
|
9184
|
+
"minLength": 1,
|
|
9185
|
+
"maxLength": 256
|
|
9186
|
+
}
|
|
9187
|
+
},
|
|
9188
|
+
"required": [
|
|
9189
|
+
"asset_kind",
|
|
9190
|
+
"asset_id",
|
|
9191
|
+
"reference_url",
|
|
9192
|
+
"region",
|
|
9193
|
+
"exact_text"
|
|
9194
|
+
],
|
|
9195
|
+
"additionalProperties": false
|
|
9196
|
+
},
|
|
9197
|
+
"minItems": 1,
|
|
9198
|
+
"maxItems": 4
|
|
9199
|
+
}
|
|
9200
|
+
},
|
|
9201
|
+
"required": [
|
|
9202
|
+
"version",
|
|
9203
|
+
"strategy",
|
|
9204
|
+
"targets"
|
|
9205
|
+
],
|
|
9206
|
+
"additionalProperties": false
|
|
9207
|
+
},
|
|
9208
|
+
"continuity_intent": {
|
|
9209
|
+
"type": "string",
|
|
9210
|
+
"enum": [
|
|
9211
|
+
"continuous_action",
|
|
9212
|
+
"shot_change",
|
|
9213
|
+
"insert_detail",
|
|
9214
|
+
"jump_cut"
|
|
9215
|
+
]
|
|
9216
|
+
},
|
|
8796
9217
|
"character_ids": {
|
|
8797
9218
|
"type": "array",
|
|
8798
9219
|
"items": {
|
|
@@ -9028,6 +9449,53 @@
|
|
|
9028
9449
|
}
|
|
9029
9450
|
}
|
|
9030
9451
|
},
|
|
9452
|
+
"/storyboards/{storyboard_id}/asset-versions": {
|
|
9453
|
+
"get": {
|
|
9454
|
+
"operationId": "get_asset_versions",
|
|
9455
|
+
"summary": "只读查询一个镜头的全部图片/视频版本、历史查看链接、依赖 ID 与版本哈希,以及已生成→与当前输入一致→审核有效→已采用四项独立事实",
|
|
9456
|
+
"description": "只读查询一个镜头的全部图片/视频版本、历史查看链接、依赖 ID 与版本哈希,以及已生成→与当前输入一致→审核有效→已采用四项独立事实。历史缺少依赖记录时显示未知,不补造快照。免费。",
|
|
9457
|
+
"tags": [
|
|
9458
|
+
"storyboards"
|
|
9459
|
+
],
|
|
9460
|
+
"parameters": [
|
|
9461
|
+
{
|
|
9462
|
+
"name": "storyboard_id",
|
|
9463
|
+
"in": "path",
|
|
9464
|
+
"required": true,
|
|
9465
|
+
"schema": {
|
|
9466
|
+
"type": "integer",
|
|
9467
|
+
"exclusiveMinimum": 0
|
|
9468
|
+
}
|
|
9469
|
+
}
|
|
9470
|
+
],
|
|
9471
|
+
"responses": {
|
|
9472
|
+
"200": {
|
|
9473
|
+
"description": "StarReel envelope",
|
|
9474
|
+
"content": {
|
|
9475
|
+
"application/json": {
|
|
9476
|
+
"schema": {
|
|
9477
|
+
"type": "object",
|
|
9478
|
+
"properties": {
|
|
9479
|
+
"code": {
|
|
9480
|
+
"type": "integer"
|
|
9481
|
+
},
|
|
9482
|
+
"message": {
|
|
9483
|
+
"type": "string"
|
|
9484
|
+
},
|
|
9485
|
+
"data": {
|
|
9486
|
+
"description": "Operation result payload"
|
|
9487
|
+
}
|
|
9488
|
+
}
|
|
9489
|
+
}
|
|
9490
|
+
}
|
|
9491
|
+
}
|
|
9492
|
+
},
|
|
9493
|
+
"402": {
|
|
9494
|
+
"description": "Insufficient prepaid balance (never overdrafts); response carries `needed` points"
|
|
9495
|
+
}
|
|
9496
|
+
}
|
|
9497
|
+
}
|
|
9498
|
+
},
|
|
9031
9499
|
"/storyboards/{storyboard_id}/chain-from": {
|
|
9032
9500
|
"post": {
|
|
9033
9501
|
"operationId": "chain_shot_from",
|
|
@@ -9825,6 +10293,107 @@
|
|
|
9825
10293
|
}
|
|
9826
10294
|
}
|
|
9827
10295
|
},
|
|
10296
|
+
"/storyboards/{storyboard_id}/product-text-review": {
|
|
10297
|
+
"post": {
|
|
10298
|
+
"operationId": "record_product_text_review",
|
|
10299
|
+
"summary": "免费记录用户对当前产品原字的人工核对结果",
|
|
10300
|
+
"description": "免费记录用户对当前产品原字的人工核对结果。只有用户明确打开文件逐字核对并确认结果后才能调用;不得用模型判断冒充人工核对。从 get_storyboards 的 product_text 取当前 contract_hash 和 reviews 中的帧位、文件、generation_id;上传素材 generation_id 为 null,必须传同一响应的 media_version。任一变化后旧审核不能沿用。不重生、不换采用版本、不代表整片客户验收。",
|
|
10301
|
+
"tags": [
|
|
10302
|
+
"storyboards"
|
|
10303
|
+
],
|
|
10304
|
+
"parameters": [
|
|
10305
|
+
{
|
|
10306
|
+
"name": "storyboard_id",
|
|
10307
|
+
"in": "path",
|
|
10308
|
+
"required": true,
|
|
10309
|
+
"schema": {
|
|
10310
|
+
"type": "integer",
|
|
10311
|
+
"exclusiveMinimum": 0
|
|
10312
|
+
}
|
|
10313
|
+
}
|
|
10314
|
+
],
|
|
10315
|
+
"requestBody": {
|
|
10316
|
+
"required": true,
|
|
10317
|
+
"content": {
|
|
10318
|
+
"application/json": {
|
|
10319
|
+
"schema": {
|
|
10320
|
+
"type": "object",
|
|
10321
|
+
"properties": {
|
|
10322
|
+
"frame_type": {
|
|
10323
|
+
"type": "string",
|
|
10324
|
+
"enum": [
|
|
10325
|
+
"first_frame",
|
|
10326
|
+
"last_frame",
|
|
10327
|
+
"video_identity"
|
|
10328
|
+
]
|
|
10329
|
+
},
|
|
10330
|
+
"generation_id": {
|
|
10331
|
+
"type": "integer",
|
|
10332
|
+
"exclusiveMinimum": 0
|
|
10333
|
+
},
|
|
10334
|
+
"media_version": {
|
|
10335
|
+
"type": "string"
|
|
10336
|
+
},
|
|
10337
|
+
"image_url": {
|
|
10338
|
+
"type": "string"
|
|
10339
|
+
},
|
|
10340
|
+
"contract_hash": {
|
|
10341
|
+
"type": "string"
|
|
10342
|
+
},
|
|
10343
|
+
"passed": {
|
|
10344
|
+
"type": "boolean"
|
|
10345
|
+
},
|
|
10346
|
+
"confirm_visual_review": {
|
|
10347
|
+
"type": "boolean",
|
|
10348
|
+
"const": true
|
|
10349
|
+
},
|
|
10350
|
+
"note": {
|
|
10351
|
+
"type": "string",
|
|
10352
|
+
"minLength": 1,
|
|
10353
|
+
"maxLength": 1000
|
|
10354
|
+
}
|
|
10355
|
+
},
|
|
10356
|
+
"required": [
|
|
10357
|
+
"frame_type",
|
|
10358
|
+
"generation_id",
|
|
10359
|
+
"image_url",
|
|
10360
|
+
"contract_hash",
|
|
10361
|
+
"passed",
|
|
10362
|
+
"confirm_visual_review",
|
|
10363
|
+
"note"
|
|
10364
|
+
]
|
|
10365
|
+
}
|
|
10366
|
+
}
|
|
10367
|
+
}
|
|
10368
|
+
},
|
|
10369
|
+
"responses": {
|
|
10370
|
+
"200": {
|
|
10371
|
+
"description": "StarReel envelope",
|
|
10372
|
+
"content": {
|
|
10373
|
+
"application/json": {
|
|
10374
|
+
"schema": {
|
|
10375
|
+
"type": "object",
|
|
10376
|
+
"properties": {
|
|
10377
|
+
"code": {
|
|
10378
|
+
"type": "integer"
|
|
10379
|
+
},
|
|
10380
|
+
"message": {
|
|
10381
|
+
"type": "string"
|
|
10382
|
+
},
|
|
10383
|
+
"data": {
|
|
10384
|
+
"description": "Operation result payload"
|
|
10385
|
+
}
|
|
10386
|
+
}
|
|
10387
|
+
}
|
|
10388
|
+
}
|
|
10389
|
+
}
|
|
10390
|
+
},
|
|
10391
|
+
"402": {
|
|
10392
|
+
"description": "Insufficient prepaid balance (never overdrafts); response carries `needed` points"
|
|
10393
|
+
}
|
|
10394
|
+
}
|
|
10395
|
+
}
|
|
10396
|
+
},
|
|
9828
10397
|
"/storyboards/{storyboard_id}/prompts": {
|
|
9829
10398
|
"get": {
|
|
9830
10399
|
"operationId": "get_shot_prompts",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@starreel/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.107",
|
|
4
4
|
"mcpName": "ai.starreel/starreel",
|
|
5
5
|
"description": "StarReel MCP server — drive the AI short-drama production pipeline (script → storyboards → frames → video → final cut) from Claude, Cursor, or any MCP client",
|
|
6
6
|
"license": "MIT",
|
package/server.json
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json",
|
|
3
3
|
"name": "ai.starreel/starreel",
|
|
4
4
|
"description": "Turn a script into a finished, downloadable short-drama episode — via MCP or REST.",
|
|
5
|
-
"version": "0.1.
|
|
5
|
+
"version": "0.1.107",
|
|
6
6
|
"websiteUrl": "https://starreel.ai",
|
|
7
7
|
"packages": [
|
|
8
8
|
{
|
|
9
9
|
"registryType": "npm",
|
|
10
10
|
"identifier": "@starreel/mcp",
|
|
11
|
-
"version": "0.1.
|
|
11
|
+
"version": "0.1.107",
|
|
12
12
|
"transport": {
|
|
13
13
|
"type": "stdio"
|
|
14
14
|
},
|