ad-studio

ad-studio

Docker app from Argus006's Repository

Overview

AD Studio adds audio description (narration of what is on screen) to videos. It watches the video with a vision model (Ollama or Gemini), writes short descriptions, voices them with Kokoro and mixes them into a descriptive audio track (or a longer video that pauses for them). Nothing is kept on the server: results are downloaded and deleted when the browser tab closes. Needs Whisper, Ollama and Kokoro services reachable over HTTP.

AD Studio

Add audio description to videos: a narrator that says what is on screen, mixed into the original soundtrack.

AD Studio watches your video with a vision model, writes short descriptions, voices them with a text-to-speech engine and mixes them into a descriptive audio track (or a longer video that pauses for them). It is made for lectures, slide decks, screen recordings and everyday videos, so people who are blind or have low vision can follow along.

It runs as one small Docker container (no GPU, no PyTorch) and talks to three services over HTTP. It is built with Unraid in mind (there is a Community Apps template) but runs anywhere Docker does.

Features

  • Four ways to place descriptions
    • Fit in pauses: only speaks in gaps in the original speech.
    • Talk over speaker: speaks over the video and lowers the original audio underneath.
    • Extended (pause the video): freezes the picture to fit longer descriptions, producing a longer video.
    • Describe screen changes: detects page and slide switches and handwriting, and describes them without pausing.
  • Vision backends: local Ollama (default qwen3-vl:8b-instruct) or Google Gemini (cloud, gemini-2.5-flash).
  • Edit before you build: a description table you can edit, with a preview player that follows along. Rows that are too long for their gap are flagged.
  • Batch mode: drop many videos, review each one's descriptions for a few seconds, and download everything as a .zip.
  • Private by design: the server keeps no uploads or results. Everything lives in a per-browser-tab scratch folder that is deleted when the tab closes, on a timer, and at startup. You download your results.
  • Download / load descriptions (.json) to and from your own computer.
  • Settings can be saved from the UI or preset with environment variables, with Test buttons for each service.

What you need

AD Studio itself only orchestrates. You run these alongside it:

Service Used for Image / project
Whisper speech timing (finds the pauses) onerahmet/openai-whisper-asr-webservice
Kokoro-FastAPI text to speech ghcr.io/remsky/kokoro-fastapi-cpu
Ollama or a Gemini API key looking at the video ollama.com / Google AI Studio

A GPU helps Whisper and Ollama a lot but is not required by AD Studio itself. If you only use Gemini you do not need Ollama.

Install

Unraid (Community Apps)

Search for AD Studio in Community Apps and fill in the three service addresses. Put Scratch on a cache-pool path (not inside docker.img).

To install by hand before it appears in the store, add this template URL under Docker, Add Container, template:

https://raw.githubusercontent.com/Chrisv006/ad-studio/main/unraid/ad-studio.xml

Docker Compose

git clone https://github.com/Chrisv006/ad-studio.git
cd ad-studio
cp .env.example .env      # edit the three service URLs
mkdir -p config scratch && sudo chown 99:100 config scratch
docker compose up -d

Open http://localhost:8585.

Docker run

docker run -d --name ad-studio --user 99:100 -p 8585:8585 \
  -v /path/to/config:/config -v /path/to/scratch:/scratch \
  -e WHISPER_URL=http://SERVER:9000 \
  -e OLLAMA_URL=http://SERVER:11434 \
  -e TTS_URL=http://SERVER:8880/v1 \
  ghcr.io/chrisv006/ad-studio:latest

Both folders must be writable by UID 99 / GID 100 (Unraid's nobody:users).

Configuration

Every setting is an environment variable; blank or unset uses the built-in default. Values saved from the UI (Save settings) override the environment, and Reset settings goes back to it.

Variable Default Meaning
WHISPER_URL required whisper-asr-webservice address
OLLAMA_URL Ollama address
TTS_URL required Kokoro-FastAPI address including /v1
VISION_BACKEND local local (Ollama) or gemini
VISION_MODEL qwen3-vl:8b-instruct Ollama model
GEMINI_MODEL gemini-2.5-flash Gemini model
KEY_MODE user user: every visitor enters their own Gemini key, kept only in their browser tab. server: one shared key stored in /config
GEMINI_API_KEY shared key (only with KEY_MODE=server)
PLACEMENT_MODE pauses pauses, talkover, extended or changes
MIN_PAUSE_SEC 1.0 shortest silence to use
TALK_OVER_INTERVAL_SEC 20 how often to describe in talk-over / extended
MAX_WORDS 20 max words per description
WORDS_PER_SEC 2.5 speaking rate used to size descriptions
DUCK_DB 8 how far the original audio is lowered under narration
AD_GAIN 2 narration volume (dB)
FRAMES_PER_DESC 6 frames sent to the local model per description
TTS_VOICE / TTS_SPEED af_heart / 1.0 Kokoro voice id, speed 0.8 to 3.0
CHANGE_SENSITIVITY 5 changes mode, 1 (page switches only) to 10
MIN_DESC_SPACING_SEC 4 changes mode, fewest seconds between descriptions
MAX_DESC_DELAY_SEC 8 changes mode, longest wait for a sentence break
BATCH_REVIEW_SECS 10 batch review window per video
SESSION_TTL_HOURS 6 delete idle sessions after this long
SCRATCH_DIR / CONFIG_DIR /scratch / /config container paths

Using it

  1. Analyze: pick a video and press Analyze. The video is transcribed, a vision model describes it, and the descriptions appear in a table.
  2. Edit: click a row to jump the video there, fix wording or timing, delete or add rows.
  3. Build: produces descriptive.mp3, a preview.mp4 and (in Extended mode) the longer video. Download them.

In Batch, drop several files, set a review time and press Analyze & build all. You can pause on any video to edit its descriptions. Closing the tab cancels the batch.

Security and privacy

  • No accounts and no login. If you expose AD Studio beyond your home network, put it behind a reverse proxy with authentication.
  • Public deployments should keep KEY_MODE=user so your own Gemini key is never stored or shared.
  • When Gemini is the backend, video frames and transcript text are sent to Google. With Ollama everything stays on your network.
  • Uploads and results exist only in /scratch while your tab is open.

Development

pip install -r requirements.txt
WHISPER_URL=... TTS_URL=... OLLAMA_URL=... python -m ad_studio     # needs ffmpeg on PATH

The UI is Gradio (pinned at 6.30.0); the preview window depends on Gradio's table markup, so re-check the preview popup and row highlighting when upgrading. Styles are in ad_studio/assets/app.css, the preview script in ad_studio/assets/preview.js.

License

MIT, see LICENSE.

Related apps

Details

Repository
ghcr.io/chrisv006/ad-studio:latest
Last Updated2026-10-12
First Seen2026-10-12

Runtime arguments

Web UI
http://[IP]:[PORT:8585]/
Network
bridge
Shell
sh
Privileged
false
Extra Params
--user 99:100

Template configuration

WebUI PortPorttcp

Port for the web page.

Target
8585
Default
8585
Value
8585
ConfigPathrw

Holds only settings.json (and the saved Gemini key when KEY_MODE=server). Must be writable by nobody:users.

Target
/config
Default
/mnt/user/appdata/ad-studio
Value
/mnt/user/appdata/ad-studio
ScratchPathrw

Temporary working files and uploads, one folder per browser tab, deleted when the tab closes and wiped at startup. Put it on the cache pool, not in docker.img.

Target
/scratch
Default
/mnt/cache/appdata/ad-studio-scratch
Value
/mnt/cache/appdata/ad-studio-scratch
Whisper URLVariable

Whisper (whisper-asr-webservice) address, e.g. http://SERVER-IP:9000

Target
WHISPER_URL
Ollama URLVariable

Ollama address, e.g. http://SERVER-IP:11434 (not needed if you only use Gemini)

Target
OLLAMA_URL
Kokoro URLVariable

Kokoro-FastAPI address including /v1, e.g. http://SERVER-IP:8880/v1

Target
TTS_URL
Vision backendVariable

local = Ollama, gemini = Google Gemini (cloud).

Target
VISION_BACKEND
Default
local
Value
local
Vision modelVariable

Ollama vision model.

Target
VISION_MODEL
Default
qwen3-vl:8b-instruct
Value
qwen3-vl:8b-instruct
Gemini modelVariable

Used when the backend is Gemini.

Target
GEMINI_MODEL
Default
gemini-2.5-flash
Value
gemini-2.5-flash
Gemini API keyVariable

Shared Gemini key (only used when Key mode is server).

Target
GEMINI_API_KEY
Key modeVariable

user = each visitor types their own Gemini key, kept only in their browser tab (safest, required if the app is exposed to the internet). server = one shared key stored on this server.

Target
KEY_MODE
Default
user
Value
user
Change sensitivityVariable

Changes mode: 1 (only page switches) to 10 (almost any change). 5 catches writing and page switches.

Target
CHANGE_SENSITIVITY
Default
5
Value
5
Min seconds between descriptionsVariable

Changes mode: fewest seconds between two descriptions (1-60).

Target
MIN_DESC_SPACING_SEC
Default
4
Value
4
Max wait for sentence break (s)Variable

Changes mode: longest a description may wait to start at the end of a sentence (0-30; 0 = at the change).

Target
MAX_DESC_DELAY_SEC
Default
8
Value
8
Placement modeVariable

pauses (fit in pauses), talkover (talk over speaker), extended (pause the video) or changes (describe screen changes, no pausing).

Target
PLACEMENT_MODE
Default
pauses
Value
pauses
Shortest pause (s)Variable

Pauses mode: shortest silence to use.

Target
MIN_PAUSE_SEC
Default
1.0
Value
1.0
Describe every (s)Variable

Talk over / extended: about how often to describe.

Target
TALK_OVER_INTERVAL_SEC
Default
20
Value
20
Max wordsVariable

Talk over / extended: maximum words per description.

Target
MAX_WORDS
Default
20
Value
20
Words per secondVariable

Pauses mode: speaking rate used to size descriptions.

Target
WORDS_PER_SEC
Default
2.5
Value
2.5
Duck (dB)Variable

How far to turn the original audio down under narration.

Target
DUCK_DB
Default
8
Value
8
Narration gain (dB)Variable

Narration volume.

Target
AD_GAIN
Default
2
Value
2
Frames per descriptionVariable

Frames sent to the local vision model per description.

Target
FRAMES_PER_DESC
Default
6
Value
6
VoiceVariable

Kokoro voice id.

Target
TTS_VOICE
Default
af_heart
Value
af_heart
Voice speedVariable

0.8 to 3.0.

Target
TTS_SPEED
Default
1.0
Value
1.0
Batch review time (s)Variable

Seconds to review each video's descriptions before it is built.

Target
BATCH_REVIEW_SECS
Default
10
Value
10
Session TTL (hours)Variable

Safety net: delete sessions idle longer than this.

Target
SESSION_TTL_HOURS
Default
6
Value
6