Skip to content
  1. Sep 01, 2026
    • Stefy Lanza (nextime / spora )'s avatar
      audio: CrisperWhisper long-form overlap windowing (no seam drops) · b6f6ca9e
      Stefy Lanza (nextime / spora ) authored
      
      
      Contiguous windows dropped words at each ~28s seam (Whisper's weak edge context +
      words straddling the boundary). Now use overlapping windows (29s wide, 24s hop =
      5s overlap), advancing by the hop and transcribing each full window, then
      de-duplicate the overlap by keeping only words that start at/after the last kept
      word's end, and rebuild the transcript from the de-duped words. Verified on an
      ~11min clip: 0 gaps >2s across all seams, continuous word timestamps to 673s,
      recovered the previously-dropped seam words.
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_01R6iugoNeEgt9PkajKrFyq4
      b6f6ca9e
    • Stefy Lanza (nextime / spora )'s avatar
      audio: CrisperWhisper long-form windowing + worker self-heal · b0483e8c
      Stefy Lanza (nextime / spora ) authored
      
      
      - Long-form fix: the HF pipeline's internal word-timestamp stitching crashes at
        the ~30s chunk boundary for CrisperWhisper (IndexError, dim-2 index==size). The
        service now windows manually — pipeline built without chunk_length_s; audio read
        via soundfile, split into <=28s windows (each a single Whisper pass), per-window
        word/segment timestamps offset by window start and concatenated. Verified on an
        ~11min clip: 1877 words, continuous timestamps to 673s, HTTP 200.
      - Self-heal: _RemoteCrisperWhisperBackend + _RemoteNemoBackend re-ensure the
        worker and retry once on a ConnectionError, so a restarted/killed worker no
        longer leaves a stale cached service_url in acquire_stt_backend.
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_01R6iugoNeEgt9PkajKrFyq4
      b0483e8c
    • Stefy Lanza (nextime / spora )'s avatar
      audio: CrisperWhisper support (isolated venv, verbatim + word timestamps) · b069137b
      Stefy Lanza (nextime / spora ) authored
      CrisperWhisper does verbatim ASR with precise word timestamps, but its custom
      generation config crashes on the server's transformers 5.x. Run it in its own
      venv worker (pinned torch 2.5.1+cu124 + transformers 4.46.3 — last pre-5.x with
      working Whisper word timestamps and a py3.13 tokenizers wheel):
      - codai/api/crisperwhisper_worker.py + tools/crisperwhisper_service.py
        (return_timestamps="word" + CrisperWhisper pause redistribution).
      - requirements-crisperwhisper.txt.
      - stt_backends.py: `crisperwhisper` is its own family -> _RemoteCrisperWhisperBackend
        (HTTP to the worker); generic `whisper-hf` still runs in the shared venv
        (text-only default + graceful timestamp fallback); HF-ASR path now converts any
        container (mp4/m4a/webm) to 16k mono wav first and uses model-correct
        return_timestamps (Whisper True/"word", CTC "chunk"/"word").
      - transcriptions.py: crisperwhisper dispatched as a GPU worker.
      - manager skip-download + ad...
      b069137b
    • Stefy Lanza (nextime / spora )'s avatar
      audio: sliding-window speaker embeddings (window/step) · ed8c014d
      Stefy Lanza (nextime / spora ) authored
      
      
      /v1/audio/speaker-embeddings gains window (seconds) + step (default = window):
      returns one embedding per sliding window, each tagged start/end, instead of a
      single whole-file embedding. Implemented in the pyannote worker's /embed via
      _crop_wav over the cached embedder; client + endpoint pass the params through;
      whole-file mode and enroll/identify/verify are unchanged.
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_01R6iugoNeEgt9PkajKrFyq4
      ed8c014d
    • Stefy Lanza (nextime / spora )'s avatar
      audio: STT backends, diarization, speaker embeddings/ID, word timestamps · 7e5a925c
      Stefy Lanza (nextime / spora ) authored
      Transcription (/v1/audio/transcriptions):
      - Route multipart uploads by peeked model (front _peek_model) so they land on
        the model's assigned engine instead of scattering by capability.
      - New pluggable STT backends (codai/api/stt_backends.py): wav2vec2 (HF), vosk
        (CPU dirs), NVIDIA NeMo-Canary (isolated venv worker) + faster-whisper/whisper.
      - Per-model language selection + validation; Canary source->target translation.
      - OpenAI timestamp_granularities[]=word: top-level words[] in verbose_json
        (vosk/wav2vec2/faster-whisper/canary).
      - VRAM-eviction tracking (acquire_stt_backend) + keep_resident co-residency for
        the small set; /v1/models surfaces languages + backends.
      
      Diarization (/v1/audio/diarization + diarize=true):
      - pyannote.audio isolated venv worker (codai/api/pyannote_worker.py,
        tools/pyannote_service.py) on the 3090; speaker-labeled segments; graceful
        degradation. Pinned torch/pyannote/hf_hub/matplotlib in requirem...
      7e5a925c
  2. Jul 03, 2026
    • Stefy Lanza (nextime / spora )'s avatar
      township: Run page invents characters/environments from scratch, phased · 15a0e81b
      Stefy Lanza (nextime / spora ) authored
      Two changes to the Run-page character/environment generation:
      
      1. Generate FROM SCRATCH via the text model instead of the built-in static pool.
         stage_characters/stage_environments always iterated FIGHTER_POOL/
         ENVIRONMENT_POOL and used their hardcoded (pre-fallback) prompts — the LLM was
         never invoked for a full run. New _invent_profiles() calls the text model
         (_autogen_profile_payload) to invent fresh profiles; the static pool is only a
         fallback when no text model is configured (with a clear warning).
      
      2. Phase the pipeline: invent ALL prompts first, then render ALL reference images,
         then train image LoRAs, then video LoRAs (prompts → images → image-LoRA →
         video-LoRA). New _render_profile_images() does the image phase from the saved
         prompts; the reuse/skip paths are unchanged. num_fighters/num_environments set
         how many to invent (default: the pool size).
      
      (CLI main() still uses the pool-based stage_...
      15a0e81b
  3. Jun 30, 2026
  4. Jun 29, 2026
    • Stefy Lanza (nextime / spora )'s avatar
      township: gate enhance + odds + ZIP + upload behind full-match checkboxes · f4ce8539
      Stefy Lanza (nextime / spora ) authored
      
      
      A whole-match regen (scope=full) now exposes two checkboxes on the match
      detail page that drive the finalization tail of the pipeline:
      
        - "Finalize & package" (default on): after assembly, run the 2x AI
          upscale + 2x frame interpolation pass, generate arbitrage-safe odds,
          and pack the renamed upload ZIP (each of the nine slots picked from
          its highest-quality variant via _best_variant).
        - "Upload after" (default = upload_after_render): also push the prepared
          match to the configured Township endpoint. Implies package; refuses
          cleanly (no server call) when the endpoint isn't configured.
      
      The full job is now seven phases (was four): prompts, keyframes, render,
      assemble (always) + enhance, odds/ZIP, upload (gated). The enhance pass
      was previously always-on; it now sits under the package checkbox (default
      checked, so existing behaviour is preserved) — unchecking gives a fast
      base-res iteration with no upscale/odds/zip.
      
      Wiring: added package/upload to the /matches/render params allowlist;
      reMatch() reads the checkboxes for scope=full, folds them into the
      confirm dialog, and posts them; odds/ZIP via prepare_match_odds_zip and
      upload via upload_prepared_match (progress piped into the job bar).
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_01RdMufYvtTbtGDWsiZVoXce
      f4ce8539
  5. Jun 25, 2026
  6. Jun 24, 2026
    • Stefy Lanza (nextime / spora )'s avatar
      runner: pass per-tool args from coderai-docker; video editor --session on by default · b56ca99e
      Stefy Lanza (nextime / spora ) authored
      
      
      * coderai-docker (run_oci.sh): new --tool-arg TOOL VAL (one token) and
        --tool-args TOOL STR (whitespace string), repeatable, for video-editor |
        videogen | township | parler. They accumulate into CODERAI_<TOOL>_ARGS env vars
        that supervisord appends to each tool's command line. Documented in --help
        (plus the --map dir-or-file note and bring-your-config examples), and shown on
        the startup banner (tool-args:).
      * entrypoint: default+export the four CODERAI_*_ARGS (empty) so supervisord's
        %(ENV_...)s never fails on an undefined var; pre-create /cache/video_editor/sessions.
      * supervisord: append %(ENV_CODERAI_*_ARGS)s to all four tool launchers; the video
        editor now runs with --session --session-dir /cache/video_editor/sessions so
        editor-state recovery is ON by default and persists on the cache volume.
      * video_editor.py: new --session-dir to place session state/assets at a
        persistent/mapped path (defaults to ~/.cache/... when omitted).
      
      Bump version to 0.1.6.
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_01RdMufYvtTbtGDWsiZVoXce
      b56ca99e
    • Stefy Lanza (nextime / spora )'s avatar
      video_editor: auto-load mapped config + --map accepts files · ac81c655
      Stefy Lanza (nextime / spora ) authored
      
      
      Mirror the township config fix for the bundled video editor:
      * supervisord: pass --config /cache/video_editor/video_editor.config.json so a
        bind-mounted (or cache-persisted) config auto-loads — previously it only
        auto-loaded video_editor.config.json from the baked cwd, which isn't mappable.
      * video_editor.py: a MISSING --config file is no longer fatal (was raise
        SystemExit) — start with defaults; the web UI Save creates it.
      * entrypoint: pre-create /cache/video_editor so the config dir exists for
        auto-load + web-UI Save (persists on the standard /cache volume by default).
      * run_oci.sh (coderai-docker): --map now accepts a single FILE, not just a dir,
        so a tool config that lives loose on the host can be linked directly, e.g.
        --map /host/video_editor.config.json:/cache/video_editor/video_editor.config.json
      
      Bump version to 0.1.5.
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_01RdMufYvtTbtGDWsiZVoXce
      ac81c655
    • Stefy Lanza (nextime / spora )'s avatar
      township: auto-load mapped township_config.json in the bundled launcher · fadc340d
      Stefy Lanza (nextime / spora ) authored
      
      
      The bundled township tool (supervisord [program:township]) launched without
      -c/--config, so a township_config.json bind-mounted via --map into
      /cache/township_output was never read — the web UI came up with blank API key /
      league upload credentials / options every restart.
      
      * supervisord: pass --config /cache/township_output/township_config.json so a
        mapped config auto-loads. Map the bare-metal dir with
          coderai-docker --map /path/to/township_output:/cache/township_output
        and the saved settings + credentials come up automatically.
      * gen_township_fighters.py: a MISSING --config file is no longer fatal (fresh
        install with no mapped dir) — fall back to defaults and start normally; a
        malformed config still errors. The web UI's Save already writes back to
        <out-dir>/township_config.json, so first-run saves persist into the mapped dir.
      
      Bump version to 0.1.4.
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_01RdMufYvtTbtGDWsiZVoXce
      fadc340d
  7. Jun 18, 2026
  8. Jun 17, 2026
    • Stefy Lanza (nextime / spora )'s avatar
      township: inline the upload helpers into the generator · 2fb085f4
      Stefy Lanza (nextime / spora ) authored
      
      
      Fold tools/township_upload.py back into gen_township_fighters.py to match the
      project's single-file convention. Odds generation, anti-arbitrage checks, ZIP
      packing and the chunked upload now live alongside the other township helpers;
      _best_variant reuses the existing _video_variants. Behaviour is unchanged.
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      2fb085f4
    • Stefy Lanza (nextime / spora )'s avatar
      township: pack + price + upload matches to townshipcombatleague.com · c84c6208
      Stefy Lanza (nextime / spora ) authored
      
      
      Add ZIP packing, anti-arbitrage odds generation, and chunked upload of a
      rendered match to the Township Combat League server (mbetterd 3-step API).
      
      - New tools/township_upload.py: generate_odds (constraint-aware, retries up
        to 10x, verified with the server's exact sure-bet checks), check_arbitrage,
        build_match_zip (OVER/UNDER/WIN1-2/KO1-2/RET1-2/DRAW, best enhanced variant),
        upload_match (create -> chunked zip -> finalize, proxy-safe, progress_cb),
        and a content signature for upload-state invalidation.
      - Run page: server endpoint/token/fixture-id, "upload after render" checkbox,
        and configurable odds ranges; persisted via /save-config + load_config.
      - Match page: generate/regenerate odds & ZIP, upload with a progress bar
        (polls /job/<id>), and an "Uploaded" badge that clears when the match is
        re-rendered, enhanced, edited or deleted.
      - Auto-upload after a full render when configured; skips (keeps local) any
        match whose odds fail the arbitrage check after 10 tries.
      
      KO/RET odds are coupled to wins by the product cap, so high maxima are not
      reachable in a no-arbitrage book; the generator samples wins first then bounds
      KO/RET accordingly.
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      c84c6208
  9. Jun 16, 2026
  10. Jun 15, 2026
    • Stefy Lanza (nextime / spora )'s avatar
      township: normalize draw to one canonical both-fighters entry · a9b6d35e
      Stefy Lanza (nextime / spora ) authored
      
      
      Auto-collapse a match's draw outcome(s) to a single canonical draw owned by
      f1 with f2 as opponent (representing both fighters), preferring an existing
      f1-owned draw so its rendered files survive. Fixes legacy per-fighter draws
      and the lone-f2 self-opponent case; lets the draw be regenerated on its own.
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      a9b6d35e
    • Stefy Lanza (nextime / spora )'s avatar
      township: auto-fix legacy per-fighter draws to one draw per match · 85317252
      Stefy Lanza (nextime / spora ) authored
      
      
      Old matches stored a DRAW per fighter, but a draw concerns both fighters so
      there must be exactly one per match. _run_match_job now dedupes the match's
      draws (keeping the first) and persists prompts.json on ANY operation, so a
      legacy match self-heals the moment it's touched — regen no longer rewrites a
      draw per fighter, and the per-outcome prompt regen targets the single draw.
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      85317252
    • Stefy Lanza (nextime / spora )'s avatar
      township: camera-motion clips, cancel-whole-queue, queue UI, per-outcome... · 6c22ea86
      Stefy Lanza (nextime / spora ) authored
      
      township: camera-motion clips, cancel-whole-queue, queue UI, per-outcome prompt regen, 3-person draw
      
      - Camera motion: add CAMERA_MOVES and flag every other fight clip as a
        camera-motion shot whose prompt LEADS with a bold moving-camera directive
        (front position = strongest weight) so the I2V model moves the camera through
        the environment instead of locking off. Legacy clips get a camera decision
        assigned + persisted on prompt regen. The directive is stripped from the
        keyframe prompt so the still anchor stays sharp.
      - Cancel whole queue: new /job/cancel-all endpoint flags the running job AND
        every queued job (worker skips them); the progress cancel button now reads
        "Cancel all (N)" and empties the queue instead of just the active job.
      - Queue visibility: detail monitor renders a "Queued (N)" list of the waiting
        jobs (by friendly scope label), not just a count; matches-list page uses ONE
        monitor per card (no more blinking between running job and its queued ones).
      - Per-outcome prompt regen: "prompt↻" on every outcome tile + new
        outcome-prompt scope rewrites a single outcome's finish+victory shots only.
      - Draw outcome: strengthen prompts so the victory shot shows all THREE in frame
        (both fighters + referee) with the referee thrusting BOTH fighters' fists high.
      - Entrance clips: more explosive/threatening, galvanized, shadow-boxing the air.
      - "win" outcome is now a POINTS decision by the referee, not a KO.
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      6c22ea86
    • Stefy Lanza (nextime / spora )'s avatar
      township: infer intro role on prompt regen + make prompt drive keyframe · 300d5669
      Stefy Lanza (nextime / spora ) authored
      
      
      Legacy matches (created before the intro-clips feature) have no role on their
      clips, so per-clip prompt regen wrote fight prompts for clips 0-2 instead of
      the entrance/entrance/face-off intro. Add _clip_role_fighters() which honours an
      explicit role/fighters or infers from position (clip 0 = f1 entrance, clip 1 =
      f2 entrance, clip 2 = referee face-off, rest = fight). _fill_clip_prompt() now
      uses it and PERSISTS the resolved role/fighters onto the clip so the subsequent
      keyframe regen and render apply the correct profiles + LoRAs.
      
      Also make a regenerated prompt authoritative for keyframe generation: clear any
      stale kf_prompt override when (re)writing a clip prompt (keyframes compose from
      the clip prompt unless an override exists, which would silently win). Same for
      outcomes — _plan_outcome_shots now drops o['kf_prompt'] so regenerated outcome
      prompts feed the outcome keyframes.
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      300d5669
    • Stefy Lanza (nextime / spora )'s avatar
      township: apply correct per-segment LoRAs/profiles at outcome render time · ba4dedac
      Stefy Lanza (nextime / spora ) authored
      
      
      The outcome video render applied one fighter list (both match fighters) to the
      whole clip, so the referee LoRA and winner-only identity only existed in the
      keyframe, not at video-generation time. Thread per-segment fighters through
      _render: segments are now (prompt, frames, seg_stem, seg_fighters) and each
      segment (and each chained part) applies exactly its own character_profiles +
      LoRAs, overriding the clip-level list.
      
      Outcome segments now load: FINISH = both fighters; VICTORY = winner + referee
      (decisive) or both fighters + referee (draw). Referee resolution matches the
      keyframe path. Backward compatible — shorter segment tuples and legacy clips
      without role/fighters fall back to the clip-level fighters.
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      ba4dedac
    • Stefy Lanza (nextime / spora )'s avatar
      township: pre-fight intro clips, per-clip prompt regen, whole-match 2x enhance · e28f11e9
      Stefy Lanza (nextime / spora ) authored
      
      
      - Every match now opens with 3 intro clips before the fight: a bold solo
        entrance for each fighter, then a referee-officiated face-off stare-down
        with the start signal. The real fight begins at clip 4. New intro prompt
        templates + LLM system prompt + PromptGenerator.intro_shot().
      - Factor out _build_match_clip_specs() and _fill_clip_prompt() so all four
        clip-building paths (stage_videos Phase A, new-match, replan, full regen)
        build intros consistently; intro clips attach only their own participants
        (solo entrance = one fighter; face-off = both + match referee).
      - New "clip-prompt" job scope + per-clip "prompt↻" link: rewrite ONLY one
        clip's prompt in place (role-aware), steering fight clips away from the
        match's other shots; renders nothing.
      - "Create whole match" and "Regenerate whole match" (scope "full") now finish
        with a 2x AI upscale + 2x frame interpolation pass over the final short/long
        assemblies and outcome videos, reusing the existing enhance machinery.
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      e28f11e9
    • Stefy Lanza (nextime / spora )'s avatar
      township: 2-keyframe outcomes, referees, autogen, generation queue; favicons · 3bfefed0
      Stefy Lanza (nextime / spora ) authored
      
      
      Township tool (tools/gen_township_fighters.py):
      - Outcome videos now generate TWO keyframes per outcome (finish + victory),
        each anchoring its own clip; victory clip uses a dedicated referee shot.
      - Referee characters: new role on create form, kept out of fighter pools,
        dressed as officials, attachable per-match and used in victory keyframes.
      - Per-match referee selection (new-match form + match editor, persisted).
      - Autogenerate buttons on character/referee, environment and new-match forms
        (LLM-filled, editable before create) via /profile/autogen + /matches/autogen.
      - Single-worker generation queue: all coderai-bound jobs (create/regen/train/
        match/process) are serialised and surfaced as "queued", with one persistent
        match-detail monitor replacing the competing per-job pollers (fixes the
        blinking progress when two jobs were launched at once).
      
      coderai: favicon.ico served at /favicon.ico + linked in admin/login templates;
      bundled township favicon served at /favicon.ico.
      
      Also gitignore large packaging/runtime artifact dirs (.packaging-cache/, tmp/).
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      3bfefed0
  11. Jun 14, 2026
    • Stefy Lanza (nextime / spora )'s avatar
      video: AI upscale/interpolate, township outcomes, configurable tmp dir · cc2436ed
      Stefy Lanza (nextime / spora ) authored
      
      
      Make video enhancement fully AI-on-CoderAI and rework township outcomes.
      
      Upscaling (Real-ESRGAN / SD upscalers):
      - Support diffusers-style .safetensors weights + config.json (e.g.
        hlky/RealESRGAN_*), not just classic .pth; infer RRDBNet arch/scale from
        config. fp16 + tiling for performance.
      - AI-or-fail: no ffmpeg fallback. Auto-select a configured upscaler when the
        request omits a model (find_capable_model).
      - Fix a registry-pollution bug: cache upscalers in a private dict, never under
        a synthetic 'upscale:<id>' key in multi_model_manager.models (which made a
        later request_model() resolve/reload the bogus key -> 400).
      - Per-frame progress + a first-class "upscale" task (pause/cancel/thermal),
        with a periodic thermal re-check through the frame loop.
      
      Interpolation (RIFE):
      - AI-or-fail: removed the ffmpeg minterpolate fallback. Resolve the
        rife-ncnn-vulkan binary + bundled model robustly, pass exact -n frame count,
        and pin -g to the SAME GPU CoderAI uses (matched by CUDA device name, not a
        hardcoded index). Progress + "interpolate" task + thermal guard.
      
      Township generator:
      - One draw per match (not per fighter); longer, configurable outcome videos
        built as a finish -> victory two-shot sequence; richer, more brutal,
        camera-aware prompts (finish/victory templates editable on the Prompts page).
      - Stream large results via response_format=url instead of base64-in-JSON;
        per-frame progress for both upscale and interpolate.
      
      Configurable temp dir:
      - New --tmp CLI flag and config.tmp_dir (+ admin Settings field, applied live).
        Sets tempfile.tempdir and TMPDIR/TMP/TEMP so all scratch (frame extraction,
        upscaling, interpolation) and child processes use it — fixes
        "[Errno 28] No space left on device" when /tmp is small.
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      cc2436ed
  12. Jun 13, 2026
    • Stefy Lanza (nextime / spora )'s avatar
      township: whole-match regen — assemble last, clean slate first · 06e61257
      Stefy Lanza (nextime / spora ) authored
      
      
      The 'full' match-regen scope now (1) removes this match's existing
      keyframes, clip videos, outcome videos and finals up front, so a re-plan
      that changes the clip count can't leave orphaned files that would get
      globbed into the reassembled finals; and (2) runs strictly in order —
      prompts -> keyframes -> clips + outcomes (assemble_finals=False) ->
      assemble finals as the explicit last phase (4/4) via _reassemble_finals.
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      06e61257
    • Stefy Lanza (nextime / spora )'s avatar
      township: "Regenerate whole match" button (end-to-end match redo) · 94a5f1ac
      Stefy Lanza (nextime / spora ) authored
      
      
      Adds a `full` scope to the per-match action handler that rebuilds one
      match in order: re-plan all fight-clip + outcome prompts (text model) →
      regenerate every keyframe (image model) → re-render all clips + outcomes
      and reassemble finals (video model), with live per-phase progress. Other
      matches are untouched. Wires the confirm dialog, the match-detail button,
      and the /matches/render scope allowlist.
      
      Fix: the `full` confirm label used an apostrophe (match's) inside the
      single-quoted JS string of the plain triple-quoted _match_js block, which
      collapsed to a real quote and broke the whole script (reMatch undefined).
      Reworded to avoid it; verified the rendered JS parses with node --check.
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      94a5f1ac
    • Stefy Lanza (nextime / spora )'s avatar
      video: VACE frame-tail extend, cancellable downloads, MMA fight variety · 0b355364
      Stefy Lanza (nextime / spora ) authored
      
      
      Downloads: run each model download in a clean `python -m
      codai.admin.download_worker` subprocess streaming JSON progress, so the
      Stop button reliably cancels by terminating the process (HF parallel/Xet
      chunk transfers ignore in-thread flags). Adds download-cancel-all. Avoids
      multiprocessing spawn, which re-imports the server launcher as __main__.
      
      VACE extension: detect WanVACEPipeline; new 'extend' mode + cond_frames
      request field condition on the previous chained part's frame tail (real
      motion -> forward continuation, fixing the single-frame boomerang).
      _build_vace_conditioning builds the (video, mask) pair; _snap_wan_frames
      enforces 4k+1; only the freshly generated frames are returned. VACE also
      serves keyframe i2v / t2v via masking; i2v/t2v fallbacks skipped for it.
      Township auto-uses extend for chained parts when the model is VACE.
      
      Fight prompts: full-MMA system prompt + rotating per-clip action focus
      (kicks/knees/elbows/takedowns/ground/submissions) and occasional blood,
      rebalanced fallback templates, keyframe wardrobe enforcement.
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      0b355364
    • Stefy Lanza (nextime / spora )'s avatar
      Township configurable playback fps; quiet progress-poll access logs · 07b3be5c
      Stefy Lanza (nextime / spora ) authored
      
      
      - township: new playback_fps (0 = same as generation fps). coderai uses fps only
        for the mp4 encode (Wan generates a fixed frame count), so a higher playback
        fps plays the same frames faster (less slow-motion). The planner counts clip
        duration as nf/playback_fps so the finals reach their target length at the real
        play speed. Wired through config/CLI (--playback-fps)/web form/all call sites.
      - main.py: suppress /v1/{video,images,audio}/progress access-log lines unless
        --debug-web is set (matching the existing /v1/loras/progress filter).
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      07b3be5c
    • Stefy Lanza (nextime / spora )'s avatar
      Exempt progress polls from rate limit; retry 429s on clip render · 0bdd9466
      Stefy Lanza (nextime / spora ) authored
      
      
      - ratelimit.py: exempt /v1/video, /v1/audio and /v1/loras progress polls from
        BOTH auth and rate limiting (shared _PROGRESS_PATHS), matching /v1/images.
        The township script polls /v1/video/progress ~1/s during a clip; being
        rate-limited, those polls ate the budget so the generation POST got 429'd
        (clip failed) and the polls themselves 429'd (stuck step bar).
      - township _render_once: a 429 now backs off and retries the same render (up to
        40 attempts, capped 60s) instead of abandoning the clip; covers clips,
        chained parts and outcomes. Genuine errors still fail fast.
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      0bdd9466
    • Stefy Lanza (nextime / spora )'s avatar
      Thermal soft-throttle, accel hot-swap + UI, township progress & concat fixes · 2ec9c384
      Stefy Lanza (nextime / spora ) authored
      
      
      coderai:
      - Thermal: configurable proactive CPU soft-throttle (engage temp + max
        per-step sleep) that gently slows generation in a warm band so it rarely hits
        the hard pause; CPU-only, hard pause always takes precedence. Tasks page shows
        a soft-throttle banner + per-task badge (live, gated on a running task).
      - Acceleration hot-swap: toggling/changing a model's acceleration now evicts the
        loaded model (manager.unload_model) so the next request reloads with the new
        setting — no restart. (acceleration is fused at load time.)
      - Models UI: cascading distill-LoRA pickers — new /admin/api/accel-loras scans
        the cache for distill repos; pick the distill model, then its high/low (or
        single) LoRA from dropdowns. Presets now also fill the high/low fields.
      - Tasks queue summary now reflects ALL model activity (derived from the unified
        task list), not just queue-manager requests — fixes the stuck "0 active".
      - images.py: proactive eviction no longer skipped by a NameError (model_key).
      
      township (tools/gen_township_fighters.py):
      - Per-clip/outcome/keyframe progress now shows real diffusion-step progress
        (polls /v1/{images,video}/progress) on the CLI spinner and the web step bars,
        including "shot part N/total" for chained single shots.
      - Chained-shot concat re-encodes (CFR) instead of stream-copy, fixing the
        "first half is a static image" freeze at the part boundary.
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      2ec9c384
    • Stefy Lanza (nextime / spora )'s avatar
      Township gen overhaul + coderai thermal/offload/eviction fixes · c8ace9d8
      Stefy Lanza (nextime / spora ) authored
      
      
      Township fight-video generator (tools/gen_township_fighters.py):
      - 16:9 native resolution: default 832x480 video + matching keyframes
        (configurable video_size); square 512 was off-distribution for Wan2.2.
      - Split-and-chain rendering: single-render cap (default 50f); clips/outcomes
        longer than the cap render as chained sub-renders (last frame seeds the next)
        concatenated into one continuous shot, parts discarded — Matches page unchanged.
        Planned-clip ceiling raised to 480f.
      - Separate outcome min/max frames (default 40/70), same split-chain path.
      - Configurable short/long final-assembly intervals; clip count derives from the
        long target + fps so the long cut always fills.
      - Prompt continuity: deterministic wardrobe+environment clause on every clip,
        replan clip and outcome; stronger LLM system prompts; updated default suffix.
      - Run page: configurable fighter/environment counts + reference-image counts;
        moved "Include female fighters" into the Characters card; suggested
        steps/rank/weight guide table; per-profile LoRA train defaults now mirror the
        run-page config (lora_* for characters, env_lora_* for environments).
      - Matches: "Remove match completely" (files + keyframes + prompts.json entry).
      - Renamed the prompts step to "Generate matches prompts"; removed the gallery page.
      
      coderai:
      - images.py: fix NameError ('model_key' undefined) that silently skipped
        proactive VRAM eviction before every image load.
      - thermal.py: cross-worker cooldown — when one generation pauses for heat, all
        parallel generations now back off until the resume threshold; add process-tree
        CPU% reader (100%/core).
      - video.py/manager.py/main.py: offload ref-leak fix, offloaded-load VRAM guard,
        wire --pipeline-cache flags.
      - Tasks page CPU tile shows process-tree CPU% scaled to cores.
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      c8ace9d8
  13. Jun 12, 2026
    • Stefy Lanza (nextime / spora )'s avatar
      Wan2.2 video fixes, pipeline cache, smarter offload, model-load tasks · dbc09b75
      Stefy Lanza (nextime / spora ) authored
      
      
      Wan2.2 A14B (dual-expert) generation fixes:
      - Fuse the Lightning distill LoRA into BOTH experts (transformer +
        transformer_2); diffusers' fuse_lora defaults to ["transformer"] only, which
        left the low-noise expert undistilled → 4-step clips collapsed to a solid
        colour. Also load per-request fighter/env LoRAs into both experts.
      - Pre-configure the wan22_lightning_4step preset with the local high/low-noise
        LoRAs (lora_high/lora_low), used when acceleration is enabled, ignored when
        not; surfaced in the Acceleration UI.
      - Safety net: only apply the preset's low step count when the distill LoRA
        actually fused, else fall back to safe steps.
      - Skip bitsandbytes/quanto quant for the VAE (conv-only → "no linear modules").
      
      VRAM / offload:
      - Strategy auto-selection actually fires now ('auto' is normalised, not passed
        through as a no-op) and no longer double-counts the runtime/accel reserve.
      - Graceful OOM degrade ladder: full-GPU → balanced @ configured% → 80 → 60 →
        40 → sequential → disk, respecting the model's balanced_gpu_percent as the
        starting cap. Expose 'balanced' as a selectable offload strategy.
      
      Pipeline disk cache (--pipeline-cache / --rebuild-pipeline-cache):
      - Cache the quantized base pipeline to disk and reload it on later starts,
        skipping re-download/re-quantization; accel LoRA re-fused per load. Fail-safe
        with self-healing invalidate-and-rebuild.
      
      Tasks / misc:
      - Show model loading as a (non-cancellable, non-pausable) Tasks entry.
      - Filter the Tasks-page pollers from the access log unless --debug-web.
      - Township gen script: per-image keyframe progress (no longer all-or-nothing).
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      dbc09b75
  14. Jun 11, 2026
    • Stefy Lanza (nextime / spora )'s avatar
      LoRA transport: upload / id / url / inline file (no shared filesystem) · 42e45456
      Stefy Lanza (nextime / spora ) authored
      
      
      Previously a per-request LoRA could only be a local path or HF id, which
      assumed the client shared the server's filesystem. Add a content-addressed
      store so remote clients can supply LoRAs by value or handle.
      
      Request `loras` spec now accepts (resolved server-side, in priority):
        id "name:<registered>"  -> a LoRA trained on this server (path-independent)
        id "sha256:<hex>"       -> a previously uploaded blob
        file/data (base64)      -> inline weights, cached in the blob store
        url                     -> server downloads (cached by content hash)
        model/path              -> legacy local path / HF id (unchanged)
      
      - loras.py: blob store (save_lora_blob / lora_blob_exists / _lora_blob_path),
        resolve_lora_ref(), resolve_request_loras() (in-place -> clean 400 on a
        missing blob / unknown name). New POST /v1/loras/upload (multipart / JSON
        base64 / raw, dedup) and GET /v1/loras/blob/{hash} existence check.
      - LoraConfig / VideoLoraConfig: model now optional; add id/url/file/data/path.
      - image + video handlers resolve_request_loras() before model work, so
        signature dedup / VRAM reserve / load_lora_weights read lora.model as before.
      - gen_township_fighters.py: reference trained LoRAs by id "name:<registered>"
        (derived from the server path) with the raw path kept as a co-located
        fallback, so the script works client/server-split.
      
      Also harden video load: float(cfg.get('balanced_gpu_percent', 80)) crashed on
      an explicit null (admin UI writes null for blank fields); use `or 80`.
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      42e45456
  15. Jun 10, 2026
    • Stefy Lanza (nextime / spora )'s avatar
      Township: attach env + both fighters' LoRAs to outcome clips & keyframes · bf50d8a1
      Stefy Lanza (nextime / spora ) authored
      
      
      Outcome scenes belong to a match, so their keyframe (image model) and video
      clip (video model) now attach the environment + BOTH match fighters' LoRAs,
      matching the fight clips — previously they sent only the single named
      fighter. Resolves the match pair from the in-memory fight_plan, falling back
      to the saved prompts.json so a single-outcome regen (fight_plan == []) still
      gets both. Legacy outcomes with no resolvable match keep the single fighter.
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      bf50d8a1
    • Stefy Lanza (nextime / spora )'s avatar
      Township: "Generate missing" keyframes button · d3878ff3
      Stefy Lanza (nextime / spora ) authored
      
      
      New keyframes-missing render scope fills in only the keyframes that don't
      exist yet for a whole match (clips + outcomes) — existing ones are kept and
      nothing is re-rendered. Buttons added on the keyframes page and the match
      detail action row; finishes immediately when none are missing.
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      d3878ff3
    • Stefy Lanza (nextime / spora )'s avatar
      Township: dedicated keyframes page for a match + outcome fixes · 71fe0c19
      Stefy Lanza (nextime / spora ) authored
      - New /match/keyframes page (🖼
      
       Keyframes ▸ from the match page): thumbnail
        grid of every clip + planned-outcome keyframe, each with per-tile
        regenerate (image model) and delete, plus match-level Regenerate all /
        Clear all. Live progress bars; reloads on completion with mtime
        cache-bust.
      - Regenerate all (whole match) now also covers this match's OUTCOME
        keyframes, not just clips.
      - Clear all now removes planned outcome keyframes too (not only ones with a
        rendered video), keeping it symmetric with Regenerate all.
      - Fix outcome keyframe stem on the page: use the plan entry's actual
        match_name (None → legacy "<fighter>_<outcome>") so it matches the file
        the generator writes, instead of a "<match>_<fighter>_<outcome>" that is
        never created (outcome keyframes were showing "no keyframe" after a
        successful regen).
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      71fe0c19
    • Stefy Lanza (nextime / spora )'s avatar
      Township: allow keyframes/keyframe scopes in /matches/render · 9a6550d8
      Stefy Lanza (nextime / spora ) authored
      
      
      The render endpoint's scope allowlist rejected the new keyframe-regen
      scopes with a 400 before reaching the handler. Add them so the
      "Regenerate keyframes" / per-clip kf↻ buttons work.
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      9a6550d8
    • Stefy Lanza (nextime / spora )'s avatar
      LoRA training: async kickoff, restart recovery, keyframe regen UI · 80f48d72
      Stefy Lanza (nextime / spora ) authored
      
      
      Server (codai/api/loras.py):
      - /v1/loras/train gains wait (default True) + session; wait=false detaches
        the job and returns a job_id, avoiding HTTP read-timeouts on multi-hour
        video trainings.
      - Disk-persisted job registry keyed by job_id (carries session). Progress
        endpoint serves ?job=<id> / ?session=<tok> so a client only ever sees its
        own job — no cross-user spillover. Jobs left mid-flight at startup are
        marked interrupted.
      - Mid-training PEFT checkpoints (SD1.5/SDXL/Wan) + train_state.json; a
        resubmit resumes from the last step when base/target/rank (and session)
        match, so a reboot no longer throws away hours of Wan training.
      
      Township (tools/gen_township_fighters.py):
      - Async training: per-run session token + persisted per-LoRA job_id; polls
        by job_id, re-attaches to a running server job after a restart, resubmits
        an interrupted one (server resumes from checkpoint).
      - Dedicated train timeouts (24h video / 4h image).
      - Match page: regenerate/clear keyframes (match-level + per-clip/outcome)
        via new keyframes/keyframe render + delete scopes.
      
      tools/videogen.py: mirror the session-token + job-id recovery helpers.
      
      Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
      80f48d72
Loading