• Stefy Lanza (nextime / spora )'s avatar
    compose: POST /v1/video/compose and POST /v1/files/upload (v0.2.22) · 5abbb81d
    Stefy Lanza (nextime / spora ) authored
    CoderAI could make every piece of a short video and nothing turned the pieces
    into a reel — assembly needs ffmpeg and two facts only the server has (how long
    the narration it just synthesised is, and when each word falls), so a detached
    client cannot do it. Requested by the Motus project over the HTTP API.
    
    - codai/api/compose.py: scenes -> one uploadable video. Scene length = narration
      + padding (min_duration floor), visuals split it evenly; async job with
      stage/progress/message/warnings, cancel (the ffmpeg child is killed), a queue
      that reports its position, and a blocking form for tests. Narration, music and
      word timings come from this server's own endpoints, called on a loop this
      module owns — never the request's loop, which may be closed before the render
      needs it. 400 names the offending scene/field; 501 when a sub-feature has no
      model (music.generate, timing=stt, TTS for narration) or ffmpeg is missing.
    - codai/compose/render.py: one normalised clip per visual (so a failed visual
      becomes a gradient and a warning instead of a lost render), concat or xfade
      that preserves the total duration, narration padded per scene and
      loudness-normalised, music looped/faded/ducked with sidechaincompress, burned
      captions + overlays with the final H.264 High/AAC/+faststart encode, thumbnail.
    - codai/compose/captions.py: word timings from STT aligned onto the CALLER's
      words (a mis-heard word never reaches the screen) or estimated; line breaking;
      ASS with six presets inside a 10%/6% safe area; SRT/VTT with the same text.
    - codai/compose/media.py: resolve a URL / /v1/files path / data URI / base64
      (never a server path), probe with ffprobe, resolve fonts through fontconfig.
    - codai/api/uploads.py: POST /v1/files/upload, content-addressed by sha256 with
      GET /v1/files/blob/{hash} so a client can skip a re-upload; type decided by
      content, not by the client's claim.
    - compose and uploads are pinned local in the capability gateway (a pod has
      ffmpeg but not this install's models or files); both advertised in the
      capability document; caption fonts (Montserrat/Inter/Noto CJK) added to the
      three image builds.
    - docs/video-compose.md; tests/test_compose.py (30, real ffmpeg, no model/GPU).
    Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01B7EnDW6RSd2nhEPZMzMkqi
    5abbb81d
render.py 22 KB