【直播切片工作台】

简介: live-mixer 是面向直播回放的端到端AI切片工作台,基于Go+React构建。通过DB任务队列(乐观锁)、同进程Worker、JSONB存储与接口化依赖,实现ASR转写、AI智能选段、剪映草稿自动生成及成片导出,全流程轻量高效。(239字)

第1章:项目全景与架构总览

本章鸟瞰 live-mixer(直播切片工作台)的整体面貌:它解决什么问题、由哪些部分组成、数据如何流动。后续所有章节都在这张地图上展开,建议先通读本章再进入细节。

流程

live-mixer 是一条面向直播回放的端到端切片流水线。用户从浏览器(React 前端)录入直播素材 URL,后端(Go + Gin)将素材落库并异步触发 ASR 语音转写;转写完成后,用户创建剪辑项目,选择系统提示词;随后走上两条路径之一——「一键成片」自动串联 AI 切片与剪映草稿生成,或「AI 粗选 + 人工精修」先让大模型挑出高价值句段(clips1),人工调整后再单独生成草稿。最终产物是可供下载的剪映草稿(draft_url)、切片 tar 包(clips_tar_url)以及可选的成片视频(video_url)。

整个系统由四类进程/容器协作:

  • live-mixer 主服务:单进程同时承载 HTTP API 与后台 Worker(ASR、AI 切片、草稿、一键成片四组)。
  • capcut-mate 服务:独立的剪映草稿生成服务,主服务通过 REST 调用它。
  • nginx:静态资源与反向代理,统一对外入口。
  • PostgreSQL:唯一的持久化存储,Worker 通过数据库乐观锁实现多实例安全调度。
flowchart TD
    A[浏览器 React 前端] -->|HTTP/JSON| B[Go API: Gin 路由]
    B --> C[(PostgreSQL)]
    B --> D[ASR Worker]
    B --> E[AI 切片 Worker]
    B --> F[草稿/一键成片 Worker]
    D --> G[豆包 BigModel ASR]
    E --> H[OpenAI 兼容 LLM]
    F --> I[capcut-mate]
    F --> J[ffmpeg / 对象存储]
    I --> K[剪映草稿 / 成片]

一次典型「一键成片」任务的时序是:POST /tasks/ai-slice-draft 创建 Task(pending)→ Worker 乐观锁抢占(processing)→ 读取素材 ASR 段落与项目提示词 → LLM 返回索引数组与标题/描述/话题 → 回写 video_project.clips1 → 下载源视频、ffmpeg 裁剪切片、上传对象存储 → 调用 capcut-mate 建草稿、加视频轨、加字幕 →(可选)触发成片生成并轮询 → 任务标记 completed,客户端轮询 GET /tasks/:id 拿到三个 URL。

实现

代码采用经典的 Go 分层架构,目录即架构:

backend/internal/
├── handler/    # HTTP 层:参数绑定、校验、调 service、写响应
├── service/    # 业务层:编排 repository 与 Worker、跨模块流程
├── repository/ # 数据访问层:GORM 封装、乐观锁、筛选
├── model/      # 实体与 JSONB 嵌套结构
├── draft/      # 剪映草稿流水线(prepare → session → steps)
├── pkg/        # 可复用内聚包:asr / llm / capcutmate / storage / media ...
├── scheduler/  # 独立于业务 Worker 的定时任务
├── migrator/   # 建表(仅 envinit 调用)
└── seeder/     # 种子数据

几个贯穿全书的架构决策值得先记住:

  1. API 与 Worker 同进程cmd/webserver/main.go 在启动 HTTP 服务的同时 Start() 四个 Worker,部署上只需一个容器。并发度与孤儿回收阈值由 WorkerConfig 控制。
  2. 数据库即任务队列:没有引入消息队列,Task 表 + 乐观锁(version CAS)+ 定时轮询(3 秒)完成多实例安全的任务分发。这是整个系统最值得学习的简化取舍。
  3. 快照式冗余:Task 创建时把画布尺寸、live_url、live_name 从关联表复制到本行,列表查询零 JOIN;代价是关联数据变更后任务显示的是创建时快照。
  4. 外部依赖全部接口化:LLM(LLMChatClient)、裁剪(VideoSegmentCutter)、上传(ObjectUploader)等在依赖处定义为小接口,配合大量 *_test.go 实现高覆盖单测。

前端是独立的 React 18 + Vite + Ant Design 5 工程,通过 /openapi/live-mixer/v1/* 与后端通信,详见第 47~49 章。

📌 设计决策

  • 选择「DB 任务队列」而非 Redis/MQ:依赖最小化,多实例扩展仍安全;代价是轮询延迟(≤3 秒)与数据库写放大,对本系统任务量级完全可接受。
  • 选择「同进程 Worker」而非独立 worker 容器:运维简单;若未来需要独立扩缩容,只需把 main.go 中 Worker 启动段拆为另一个 cmd。
  • 大量业务字段(clips、asr_paragraphs、topics)用 PostgreSQL JSONB + GORM serializer 存储,避免为嵌套结构建关联表。

代码示例

启动入口清晰展示了「一个进程,两类职责」的装配方式:

// cmd/webserver/main.go(节选)
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()

asrWorker.Start(ctx)         // ASR 转写 Worker
aiSliceWorker.Start(ctx)     // AI 切片 Worker
draftWorker.Start(ctx)       // 剪映草稿 Worker
aiSliceDraftWorker.Start(ctx) // 一键成片 Worker

sched := scheduler.New(logger)
sched.Register(scheduler.Job{
    /* staging 清理 */ })
sched.Start(ctx)

srv := &http.Server{
   Addr: cfg.Server.Addr(), Handler: r}
go func() {
    _ = srv.ListenAndServe() }()

<-ctx.Done() // 优雅退出:先停 HTTP,再随 ctx 取消停 Worker

任务实体是理解全局的钥匙,其字段注释即业务契约:

// internal/model/task.go(节选)
type Task struct {
   
    ID             string `gorm:"primaryKey;size:36"` // UUID,仓储层生成
    Type           string `gorm:"size:32;index"`      // ai_slice / draft / ai_slice_draft
    Status         string `gorm:"default:pending;index"`
    Progress       int16                              // 0-100,客户端轮询展示
    Version        int64                              // 乐观锁:CAS 抢占时递增
    VideoProjectID *uint                              // 关联剪辑项目(可空)
    DraftURL       string                             // 草稿下载地址,成功后回写
    VideoURL       string                             // 成片地址,gen_video 完成后回写
    ClipsTarURL    string                             // 切片 tar 包地址
    LiveURL        string                             // 创建时快照,列表免 JOIN
}

小结

  • live-mixer = 素材管理 + ASR + AI 选段 + 剪映草稿 + 成片导出的单进程 Go 服务。
  • 核心架构关键词:分层、DB 任务队列(乐观锁)、JSONB、外部依赖接口化。
  • 三个产物 URL(draft / video / clips_tar)都挂在 Task 上,客户端只需轮询一个接口。

思考题

  1. 若任务量从每天数百涨到数十万,DB 任务队列会在哪些点先到达瓶颈?
  2. Task 冗余快照字段与实时 JOIN 各自的适用边界在哪里?

项目信息

  • GitHub仓库:Chyona/live-mixer
相关文章
人工智能 缓存 前端开发
12026 63
人工智能 JavaScript 开发工具
4812 17
Web App开发 人工智能 API
1385 1
人工智能 Java BI
1472 1
开发工具 Swift git
1974 6
人工智能 JavaScript 测试技术
2406 2
人工智能 自然语言处理 安全
992 0
人工智能 JavaScript 测试技术
1200 4
缓存 JavaScript Shell
2102 3

热门文章

最新文章