2 Your First Show
xenarathon edited this page 2026-09-04 14:48:46 -04:00
This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Your first show

A lesson. Follow it start to finish on one season of one show and you will end with a video file that plays a dubtitle track. Everything is deliberately narrow — one show, one season, defaults everywhere — so that when something goes wrong you know where it was.

Budget about 20 minutes of your attention and a few hours of the machine's. A 24-minute episode takes roughly 515 minutes to transcribe depending on your card.

This is a beta. One Pace is the only configuration that has been validated end to end. Other shows work, and are also where the bugs are. See Why it works this way.


Before you start

You need:

  1. An NVIDIA card with CUDA. 6 GB is enough if the language model lives elsewhere; see How-to guides.
  2. Docker, with the NVIDIA container runtime working. Check it:
    docker run --rm --gpus all nvidia/cuda:12.4.0-base-ubuntu22.04 nvidia-smi
    
    If that prints your card, you are ready.
  3. A show with an English dub, in a folder named like Show Name (Year) containing Season 01/ and files tagged S01E01.
  4. A place to run a small language model. The repair stage needs one. Step 1 sets it up.

Step 1 — Serve the repair model

The pipeline calls an OpenAI-compatible chat-completions endpoint. Anything that speaks that protocol works; the validated setup is llama.cpp serving a GGUF.

The default model is qwen3-4b-instruct. Pick a quantisation that fits the VRAM you have left after Whisper — see How-to guides.

llama-server \
  -m /path/to/qwen3-4b-instruct-Q6_K.gguf \
  -c 16384 --jinja \
  --host 0.0.0.0 --port 8090 \
  --alias qwen3-4b-instruct

Q6_K is what this project runs. There is no --chat-template-kwargs '{"enable_thinking":false}' here: that flag exists to stop a thinking model emitting <think> blocks, and qwen3-4b-instruct has no thinking mode to disable. Verified 2026-09-02 — the instruct model returns clean completions without it. If you swap in qwen3-4b or qwen3.5-*, which do think, add the flag back.

--jinja is required. Without it, chat_template_kwargs is silently ignored — the server starts, reports healthy, and a thinking-capable model spends its whole token budget on reasoning and returns an empty reply, which the pipeline treats as "no repair" and tells you nothing. Measured (repair.py's llm_llamacpp): empty after 114s at max_tokens=512 with thinking on; correct output in 4.3s with it off.

--chat-template-kwargs '{"enable_thinking":false}' is what turns thinking off, and it only takes effect with --jinja — the flag applies the model's own chat template, which is where enable_thinking is read.

Check it is really ready. A freshly started server answers /health with 200 while it is still loading weights, then fails the first real request. Ask it something instead:

curl -s http://127.0.0.1:8090/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{"model":"qwen3-4b-instruct","messages":[{"role":"user","content":"hi"}],"max_tokens":4}'

When that returns JSON with a message in it, the model is loaded.


Step 2 — Make a config directory

mkdir -p ~/dubtitlerr/{glossaries,decisions,wiki_cache}

Tell it which show to do. One line, exactly matching the folder name:

echo 'Show Name (Year)' > ~/dubtitlerr/anime_order.txt

Nothing else goes in this file yet. One show is the whole point of this lesson.


Step 3 — Start the container

Save this as docker-compose.yml:

services:
  dubtitlerr:
    image: ghcr.io/xenarathon/dubtitlerr:latest
    restart: unless-stopped
    ports:
      - "8842:8842"
    environment:
      # --- where things are ---
      ANIME_ROOT: /media/Anime Library
      MERGE_ROOTS: /media/Anime Library
      MUX_ROOTS: /media/Anime Library
      ANIME_ORDER: /config/anime_order.txt
      GLOSSARY_DIR: /config/glossaries
      DECISIONS_DIR: /config/decisions
      WIKI_CACHE_DIR: /config/wiki_cache

      # --- transcription ---
      WHISPER_MODEL: large-v3-turbo
      COMPUTE_TYPE: int8
      REQUIRE_ENG: "1"

      # --- repair model, from step 1 ---
      REPAIR_BACKEND: llamacpp
      REPAIR_MODEL: qwen3-4b-instruct
      REPAIR_LLAMACPP_URL: http://host.docker.internal:8090/v1/chat/completions

      # --- ownership of what it writes ---
      MEDIA_UID: "1000"
      MEDIA_GID: "100"
    volumes:
      - /path/to/your/media:/media
      - ~/dubtitlerr:/config
    extra_hosts:
      - "host.docker.internal:host-gateway"
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]

Change the two volumes lines and ANIME_ROOT to match your library. Then:

docker compose up -d
docker compose logs -f

ANIME_ROOT and MERGE_ROOTS have different built-in defaults, which is why the compose file sets all three roots explicitly. Do not remove them.


Step 4 — Watch the first episode go through

In the log you will see, in order:

  1. Mining — proper nouns pulled out of the episode's existing subtitle track, building ~/dubtitlerr/glossaries/Show Name (Year).json.
  2. Verification — those names checked against the show's Fandom wiki.
  3. Transcription — Whisper on the English dub audio. This is the slow part.
  4. Repair — the low-confidence and name-suspect lines sent to your model.
  5. Merge and mux — signs and songs folded in, then written into the MKV as a default track named Dubtitles.

Then open the episode in your player. There is a subtitle track called Dubtitles. Play a scene with dialogue.

That is the lesson's goal, reached. Everything below makes it better.


Step 5 — Look at what the repair stage was unsure about

Open http://localhost:8842.

The first thing the log printed on startup was an access token:

review server: generated an access token, stored /config/review_token (0600)
review server: token = ...

You can also read it back at any time:

docker exec <container> cat /config/review_token

The page shows a tree of shows, seasons and episodes. Open your episode. You are looking at only the lines the pipeline was unsure about — not the whole episode. Each row shows what was transcribed, what the repair model proposed, and the lines either side for context.

For each one, choose:

  • accept — the proposal is right
  • reject — keep the original
  • correct — neither is right; type what the dub actually says
  • force — admit a repair the mechanical gate refused

Then press Save verdicts.


Step 6 — Put your verdicts into the video

Saving is not enough. Saving records your judgement and changes what the next repair run ships. The video on disk has not changed.

Press Apply decisions to this episode.

That rewrites the subtitle, drops the completion stamp, and lets the merge loop re-mux the file. Wait for the next merge pass (default: every 10 minutes), then reopen the episode.

Your corrections are in the track.


What you have learned

  • The pipeline transcribes the dub audio, never the existing subtitle track.
  • Glossaries are built for you and live in /config, editable by hand.
  • The review page shows uncertain lines only, and a verdict there applies to that line everywhere in the show.
  • Saving a verdict and changing the video are two separate actions.

Where to go next