refactor(workflow): 统一 OSS 接口并重构恢复锁

- 将文件地址前缀与上传逻辑迁移至 common/oss
- 恢复执行改用 utils.WithLock 自动续期锁
- 转写提示词增加单镜头最小时长约束
This commit is contained in:
2026-08-29 11:51:30 +08:00
parent 740003a192
commit 67d049e586
13 changed files with 173 additions and 226 deletions
@@ -101,12 +101,13 @@ func ScriptTranscribeLambda(ctx context.Context, input any) (any, error) {
if totalDuration > 0 {
systemPrompt += fmt.Sprintf("\n\n视频总时长 %d 秒(MM:SS 为 %s):所有镜头的时间码需前后衔接并完整覆盖该总时长,最后一镜的 endTime 对齐到总时长。", totalDuration, formatSecondsToMMSS(totalDuration))
}
// 单镜头时长上限约束:按视频模型推导单段最大时长注入转写提示词,从源头避免超长镜头
//SplitOversized 仍是机械兜底);推导失败仅降级跳过约束注入,不影响转写主流程。
if maxSeg, _, err := split_shots_pipeline.SegmentBounds(ctx, modelId); err != nil {
// 单镜头时长约束:按视频模型推导单段最大/最小时长注入转写提示词,从源头避免超长/超短镜头
//SplitOversized / GroupSegments 咬取补齐仍是机械兜底);推导失败仅降级跳过约束注入,不影响转写主流程。
if maxSeg, minSeg, err := split_shots_pipeline.SegmentBounds(ctx, modelId); err != nil {
g.Log().Warningf(ctx, "获取视频模型单段时长约束失败,跳过单镜时长约束注入: %v", err)
} else {
systemPrompt += shotDurationConstraintPrompt(maxSeg)
systemPrompt += shotMinDurationConstraintPrompt(minSeg, totalDuration)
}
// 静音模式硬约束:从转写源头杜绝对白/旁白/开口说话,后续清洗只做兜底
if noSpeech {
@@ -373,6 +374,19 @@ func shotDurationConstraintPrompt(maxSeg int) string {
return fmt.Sprintf("\n\n单个镜头时长不超过 %d 秒:每镜的 startTime 与 endTime 之差必须 ≤ %d 秒。", maxSeg, maxSeg)
}
// shotMinDurationConstraintPrompt 生成"单个镜头时长不少于 minSeg 秒"的转写约束提示词片段。
// minSeg<=0 返回空串;minSeg 超过视频总时长时也返回空串——此时与"末镜 endTime 对齐总时长"的约束
// 自相矛盾、模型无法满足,强行注入反而会让模型困惑(GroupSegments 对末段残余本就放行短于 min)。
func shotMinDurationConstraintPrompt(minSeg, totalDuration int) string {
if minSeg <= 0 {
return ""
}
if totalDuration > 0 && minSeg > totalDuration {
return ""
}
return fmt.Sprintf("\n\n单个镜头时长不少于 %d 秒:每镜的 startTime 与 endTime 之差必须 ≥ %d 秒。", minSeg, minSeg)
}
// noSpeechSystemPromptConstraint 静音模式的转写硬约束:要求模型从源头就不产出对白/旁白/说话动词,
// 后续 noSpeech 清洗(清空台词旁白 + cleanSpeechVerbs)只做机械兜底。
func noSpeechSystemPromptConstraint() string {