【直播切片工作台】第36章:剪映草稿流水线总览

简介: 本章详解剪映草稿生成流水线设计:以`Request/Result`解耦入参、`Pipeline`准备素材、`Recipe/Steps`有序组装、`Session`共享状态,实现高内聚、可测试、易扩展的AI视频成片工程化架构。(239字)

第36章:剪映草稿流水线总览

从本章起进入成片阶段。internal/draft 包把"从 clips 到剪映草稿"的完整过程组织为四个协作角色:Request/Result(与任务模型解耦的入参出参)、Pipeline(素材准备)、Recipe/Steps(有序组装步骤)、Session(贯穿全程的可变状态)。本章先建立全局图景,后三章分别深入。

流程

Builder.Build 是流水线的总指挥:解析 clips(入参直给或从 project 的 clips1/clips0 反推)→ 500ms 合并相邻片段 → 校验 → 构造 Session → Prepare 下载裁剪 → 按顺序执行 Recipe 的三个 Step → 校验 draft_url → 打包上传切片 tar。

flowchart TD
    A[Request<br/>JobID/Material/Project/Clips] --> B[Build]
    B --> C{Clips 为空?}
    C -- 是 --> D[ResolveClipRanges<br/>从 clips1/clips0 解析]
    C -- 否 --> E[直接使用]
    D & E --> F[MergeAdjacentClipRanges<br/>间隙≤500ms 合并]
    F --> G[ValidateClipRanges]
    G --> H[构造 Session<br/>含 NewTimeline 空时间线]
    H --> I[Prepare.Run<br/>下载源视频+ffmpeg 裁剪]
    I --> J[Step1 CreateStep<br/>创建剪映草稿]
    J --> K[Step2 VideosStep<br/>上传切片+铺视频轨]
    K --> L[Step3 CaptionsStep<br/>按 ASR 铺字幕]
    L --> M{draft_url 非空?}
    M -- 是 --> N[PackAndUploadClipsTar<br/>失败不阻断]
    N --> O[Result: DraftURL + ClipsTarURL]
    M -- 空 --> P[报错]

实现

分层解耦是这个包最大的特点。Request 的注释明确"与任务模型无关"——JobID 只用于日志与目录命名,不强制是 task id;Progress 是一个 func(local int16) 回调,任务层负责把 0~100 的本地进度映射到全局 task.progress(独立任务直接透传,一键成片按阶段区间缩放)。Generator 接口因此可以被任何调用方使用:独立 draft Worker、一键成片 Worker、甚至未来的手动重放工具。

Recipe 的编译期安全:DefaultRecipe 返回三步——CreateStep → VideosStep → CaptionsStep,每步自持依赖(API client、Uploader、Logger),Recipe.Steps 为空时回落默认。Builder 尾部的 var _ steps.Step = steps.CreateStep{} 是接口实现断言,把"某步忘了实现 Step 接口"从运行期错误提前到编译期。

收尾的降级语义:PackAndUploadClipsTar 失败只记 Error 日志、ClipsTarURL 留空——草稿本体已成功,附带产物(供用户单独下载切片的 tar 包)不应拖垮主结果。而 s.DraftURL == "" 则是硬失败:三步全跑完却没产出 URL,说明步骤实现有 bug,宁可报错也不返回空壳成功。

NewGenerator 的依赖兜底链:Cutter 缺省回落 media.NewFFmpegConverter(""),Downloader 缺省走工厂函数——组合根可以全量注入,单测可以只注入关心的部分,其余落默认。

📌 设计决策

  • 准备与组装两段式:Prepare 产出本地文件(ClipPaths),Steps 消费本地文件并调用远端 API。文件系统是两段之间的"接口",让 ffmpeg 重活与 HTTP 调活可独立测试与重试。
  • Session 作为共享黑板:所有 Step 读写同一个 Session(草稿 ID、时间线、clip 路径),避免步骤间参数传递链条爆炸;代价是步骤执行顺序隐含数据依赖,必须由 Recipe 保证。
  • tar 包失败不阻断:附带产物与主产物的失败域隔离;用户仍能打开草稿,tar 可后续手动补。
  • Progress 回调而非进度对象:函数类型比接口更轻,任务层闭包捕获 task ID 即可,draft 包对"进度写到哪"零知识。

代码示例

片段 1 展示流水线总指挥(摘自 draft/builder.go,节选):

// Build 解析 clips → Prepare → 按 Recipe 执行 Steps,返回 draft_url。
func (b *Builder) Build(ctx context.Context, req Request) (*Result, error) {
   
    clips := req.Clips
    if len(clips) == 0 {
   
        if req.Project == nil {
   
            return nil, fmt.Errorf("clips 为空且未提供 project")
        }
        var err error
        clips, err = prepare.ResolveClipRanges(req.Project)
        if err != nil {
   
            return nil, err
        }
    }
    beforeMerge := len(clips)
    clips = prepare.MergeAdjacentClipRanges(clips, prepare.ClipMergeGapMS)
    b.Logger.Info("草稿裁剪前合并相邻片段",
        zap.String("job_id", req.JobID),
        zap.Int("clips_before", beforeMerge),
        zap.Int("clips_after", len(clips)),
    )
    if err := prepare.ValidateClipRanges(clips); err != nil {
   
        return nil, err
    }

    recipe := req.Recipe
    if len(recipe.Steps) == 0 {
   
        recipe = DefaultRecipe(b.API, b.Uploader, b.Logger)
    }

    s := &session.Session{
   
        JobID: req.JobID, Project: req.Project, Material: req.Material,
        StagingDir: req.StagingDir, RecordDir: req.RecordDir,
        Clips: clips, CanvasW: req.CanvasW, CanvasH: req.CanvasH,
        Timeline: session.NewTimeline(), Progress: req.Progress,
    }

    if err := b.Prepare.Run(ctx, s); err != nil {
   
        return nil, err
    }
    for _, step := range recipe.Steps {
   
        if err := step.Run(ctx, s); err != nil {
   
            return nil, fmt.Errorf("步骤 %s 失败: %w", step.Name(), err)
        }
    }
    if s.DraftURL == "" {
   
        return nil, fmt.Errorf("草稿组装完成但 draft_url 为空")
    }

    result := &Result{
   DraftURL: s.DraftURL}
    // 将本地 clip_XXX.mp4 打成 {jobID}.tar 并上传;失败仅记日志,不阻断草稿成功。
    clipsTarURL, err := PackAndUploadClipsTar(ctx, b.Uploader, s.StagingDir, s.JobID, s.ClipPaths)
    if err != nil {
   
        b.Logger.Error("切片 tar 打包上传失败", zap.String("job_id", s.JobID), zap.Error(err))
    } else {
   
        result.ClipsTarURL = clipsTarURL
    }
    return result, nil
}

片段 2 展示契约类型与默认 Recipe(摘自 draft/request.go 与 draft/recipe.go):

// Request 剪映草稿组装入参(与任务模型无关)。
type Request struct {
   
    JobID    string // 仅用于日志/目录命名,不强制是 task id
    Material *model.LiveMaterial
    Project  *model.VideoProject
    // Clips 为空时,若 Project 非空则从 clips1/clips0 解析并合并相邻片段。
    Clips            []model.ClipRange
    CanvasW, CanvasH int
    StagingDir       string
    RecordDir        string
    // Progress 可选:本地进度 0–100;由任务层映射到 task.progress。
    Progress func(local int16)
    // Recipe 为空时使用 DefaultRecipe。
    Recipe Recipe
}

// Recipe 有序组装步骤列表。
type Recipe struct {
   
    Steps []steps.Step
}

// DefaultRecipe 默认流水线:创建草稿 → 上传切片并添加主视频轨 → 按 ASR 添加同步字幕。
func DefaultRecipe(api CapCutMateAPI, uploader steps.ObjectUploader, logger *zap.Logger) Recipe {
   
    return Recipe{
   
        Steps: []steps.Step{
   
            steps.CreateStep{
   API: api, Logger: logger},
            steps.VideosStep{
   API: api, Uploader: uploader, Logger: logger},
            steps.CaptionsStep{
   API: api, Logger: logger},
        },
    }
}

小结

draft 包用"入参出参解耦 + 两段式流水 + 有序步骤 + 共享 Session"四件套,把一段混杂 ffmpeg、对象存储、远端 HTTP 的复杂流程驯服为可测试、可复用、可编排的纯组件。下一章进入 Prepare 的裁剪细节。

思考题

  1. 若在 Recipe 中插入一个 MusicStep(添加背景音乐),它对 Session 需要哪些新字段?时间线结构是否需要扩展?
  2. Build 在 Step 失败后直接返回,不做草稿清理——capcut-mate 侧会留下半成品草稿。你会如何设计补偿机制(回滚 API / 标记孤儿草稿定期清理)?

项目信息

  • GitHub仓库:Chyona/live-mixer
相关文章
|
15天前
|
Linux 开发工具 iOS开发
Codex保姆级教程(下载+安装+登录+使用,含所有版本,2026最新)
Codex是OpenAI推出的开源AI编程智能体,本地运行,可理解整个代码库,支持自然语言指令改代码、执行命令、跑测试、修Bug,兼容Win/macOS/Linux。(239字)
6433 47
|
3天前
|
云安全 人工智能 安全
|
16天前
|
JavaScript API iOS开发
DeepSeek Harness下载、安装、配置一篇搞定(2026整理,送常用插件)
DeepSeek Harness(DSH)是DeepSeek于2026年开源的MIT协议AI Agent框架,支持插件化组装模型、工具、沙箱与UI,兼容主流大模型。本文提供免Node.js的桌面端安装包(Win/macOS),含详细图文教程及热门插件推荐。
5246 63
|
10天前
|
Linux 开发工具 iOS开发
2026最新codex下载安装保姆级使用教程(下载+安装+登录+使用,含所有历史版本)
本文详解OpenAI Codex国内快速上手指南:提供Win/macOS/Linux全平台免安装包、npm/Homebrew等多方式安装、账号/API Key双登录、简体中文切换,覆盖下载、安装、汉化、使用及高频避坑(如微软商店失败、npm超时等),10分钟即可跑通。
2591 6
|
2天前
|
JSON 前端开发 API
阿里云最新Qwen4-Max大模型介绍:模型定位、特征、能力、适用场景解析
2026 年 11 月 11 日,阿里发布第四代旗舰模型Qwen4-Max预览版,首发千问 AI 平台 Token Plan,并同步接入千问办公、Qoder 等入口。该版本聚焦知识理解、世界感知、编程与 Agentic 四项升级,主打复杂编程、专业办公、前端设计与专业软件操作。预览期至 11 月 25 日 24:00,到期后模型标识下线;限时 2 折、新用户再享 5 折,最低 1 折可体验。
|
8天前
|
人工智能 安全 API
DeepSeek Harness下载、安装、配置一篇搞定(2026整理,送常用插件)
DeepSeek Harness(dsh)是DeepSeek AI于2026年开源的轻量级Agent运行框架,基于Cordis内核,践行“一切皆插件”理念。支持Web/桌面双端,开箱即用;内置多模型接入、丰富插件生态(超3.5万),适配编程、办公、创作等场景。(239字)
1654 1
|
2天前
|
人工智能 前端开发 API
阿里云Qwen4-Max 大模型详解:定位、特征、能力、适用场景与相对Qwen3-Max差异解析
2026年11月11日,阿里发布第四代旗舰模型Qwen4-Max预览版,首发千问AI平台Token Plan并接入千问办公、Qoder等入口。该版本聚焦知识理解、世界感知、编程与Agentic四项升级,主打复杂编程、专业办公、前端设计与专业软件操作等真实任务。预览期为11月11日10:00至11月25日24:00,仅支持Token Plan调用,到期后模型标识下线;限时2折、新用户再享5折,最低1折可体验。

热门文章

最新文章