combo-voiceover-fit · writeback-pipeline

成片怎么写回 Mai
这次双边各改了什么

combo 跑完,结果不是直接进 Mai 画布的。它先发回调给网关,网关导入产物拿到 Mai file_id,再交给 canvas 服务生成画布卡片。这次我们想多回一张"原视频"卡片、还带条字幕链接——发现得动两个仓库。

写回经过三道手

runner 不直接写 Mai 的画布表。它发的回调要过两层加工才变成你在 canvas 上看到的卡片:

Tobatsu runner mai-combo-runner-test 发 delivery 回调 tobatsu-gateway import 拿 mai_file_id 挑哪些进 canvas 解 @ref canvas worker canvas-format.ts 生成 canvas_v2 卡片 delivery item url/mai_file_id/canvas_extra canvasItem 已配 mai_file_id + 解好的 url → canvases_v2.data 你看到的卡片 我改这里 mai-cc 改网关 + worker 这两道

关键:runner 给的 url 网关其实不直接用——canvas 的 dataURL 是网关 import 后用 mai_file_id 重新拼的(cdn-asia/ultra/<file_id>)。所以"想让某字段出现在画布上",光 runner 发没用,得网关/worker 那两道认它。这就是为什么这次得双边改。

回调有两类,产物在第一类

runner 一共发两种回调到同一个 callback_url:

① delivery_update status=running

真正的产物在这里,分两批发:

  • digital_human_uploaded:主播图 + 数字人原片
  • final_artifacts_uploaded:成片 + 音频 + 字幕 +原视频

② delivery_result status=succeeded

终态,outputs:[] 是空的(产物上面发过了)。只带全局元信息

  • summary 人读总结
  • adjustments[] 改了哪些段
  • provider / fallback_used / warnings

原视频卡片要进画布,就必须作为一条产物 item 跟着 final_artifacts_uploaded 那批发——和字幕同批,否则下面那个 @ref 解析不到字幕。

每条产物长这样

runner 用 output_record() 造每条产物,字段是固定的。网关把它映射成 canvas 卡片:

# runner 发的一条产物 item(以原视频为例,这次新增的) { "delivery_item_id": "out_source_video", "role": "out_source_video", "kind": "video", "name": "原视频", "title": "原视频", "mime_type": "video/mp4", "mai_file_id": "qrIwwY.mp4", # 给 file_id → 网关 skip import 不重传 "canvas_extra": { "srtURL": "@out_subtitle" } # ← 透传袋 + @ref(新机制) }
canvas 卡片字段来自哪
id= mai_file_id(import 后的,缺了才随机)
dataURL网关用 file_id 重拼 ultra/<file_id>,runner 的 url 被忽略
name / title / mimeType原样来自 item
createdcanvas 服务插入时的时间戳,runner 不给
srtURL canvas_extra 透传 + @ref 解析(见下)

这次改了什么 · 双边

目标就两件小事:成片回传多一张"原视频"卡片,且这张卡片上挂一个 srtURL 指向本次字幕,给下游做视频/音频合成用。但因为写回要过三道手,落点散在两个仓库:

Tobatsu runner(我)

  • 新增 source_video_output_record():发 out_source_video,回显源视频 mai_file_id不重传,挂 canvas_extra:{srtURL:"@out_subtitle"}
  • 放进 final_artifacts_uploaded 同批
  • summary 在有改词时追加"其中 N 段因时长策略已自动改写文案"

skill v1 → v2(test only)

Mai 网关 + canvas worker(mai-cc,4 处)

  • normalizer:把顶层 canvas_extra 提为一等字段透传
  • canvas-delivery:out_source_video 加进显示白名单 + 建 @ref 解析器
  • canvas-format:末尾把 canvas_extra spread 进卡片 + 保留键护栏
  • expected_outputs:补一项保持契约一致

push c5de8d4 → CI 自动部署(test)

为什么不能光 runner 改?因为白名单不认就被丢、canvas_extra 不提就被 normalizer 扔、额外键不 spread 就进不了卡片——这三关都在 Mai 侧。runner 只能"发",能不能"显示"是网关说了算。

srtURL 这个值,runner 给不了

你要的 srtURL 是字幕 import 后的 Mai 链接ultra/<字幕的 mai_file_id>)。但那个 file_id 是网关 import 字幕时才分配的,runner 跑的时候根本不存在。所以没法静态塞。解法是一个通用的引用机制

srtURL: "@out_subtitle" runner 只写一个引用 网关 @ref 解析器 查本批 import 表 role→file_id ultra/Rk9bdp.srt 解析成真实 Mai 链接 @开头=引用 解不到就丢键,不输出悬空 url

跑出来的样子

真 canvas 联调(gw_1bf2ac61)+ 你自己那单(gw_e085fa11)都验过,原视频卡片最终长这样:

{ "id": "qrIwwY.mp4", "name": "原视频", "title": "原视频", "dataURL": "https://cdn-asia.funplus-marketing.ai/ultra/qrIwwY.mp4", # 原视频,没重传 "mimeType": "video/mp4", "srtURL": "https://cdn-asia.funplus-marketing.ai/ultra/Rk9bdp.srt" # @ref 解析出的字幕 }

6 张卡片全到、canvas_delivered=true、srtURL 只挂在原视频卡片其余没有、保留键护栏没被穿透。顺带这两单都触发了 2 段配音改词自愈——写回链路和自愈是同一条 runner 上的两件事。当前全部在 test,prod 未动。