All apps Β· 0 apps
Vellichor
Docker app from woodsjail.'s Repository
Overview
Readme
View on GitHubVellichor π§
A self-hosted web app that turns your written stories (and ebooks) into narrated audiobooks. Fast by default with the Kokoro-82M TTS model, plus an optional expressive engine (Chatterbox) that adds emotional intensity and voice cloning β clone a voice from a short clip, or record your own right in the browser. GPU-accelerated and light enough to run on a modest card (originally built on a GTX 1080); falls back to CPU. Open source (MIT).
Requirements
- Docker and Docker Compose.
- (Optional) NVIDIA GPU for acceleration β requires the NVIDIA Container Toolkit on the host (on Unraid, the Nvidia Driver plugin). With no GPU it runs on CPU instead β see the no-GPU note in Getting started.
- Disk: ~7 GB for the Docker image, plus models downloaded on first use β Kokoro (small), the optional Ollama Smart-cast LLM (~2 GB), and the optional Chatterbox expressive model (~1β2 GB). Budget ~12 GB total to use everything.
Getting started
# 1. Clone
git clone https://github.com/woodscode/vellichor-web.git
cd vellichor-web
# 2. Create your .env: set the admin password and a cookie-signing key
cp .env.example .env
sed -i "s|^SECRET_KEY=.*|SECRET_KEY=$(openssl rand -hex 32)|" .env
$EDITOR .env # set VELLICHOR_PASSWORD
# 3. Edit docker-compose.yml for your box:
# - Audiobookshelf export mount (β¦:/library) β repoint to your library, or
# remove the volume if you don't use Audiobookshelf
# - host port (default 7777:7777)
# - NO GPU? remove the `runtime: nvidia` and `NVIDIA_*` lines from BOTH
# services (it then runs on CPU β slower, but works)
# 4. Build & start
docker compose up -d --build
# 5. (Optional) enable AI Smart cast β pull the local LLM once
docker exec vellichor-ollama ollama pull llama3.2:3b
Then open http://:7777 and sign in as admin with your
VELLICHOR_PASSWORD. Store that password in your password manager.
To give someone else an account, click π€ admin in the header β People β add a username and an initial password. See Accounts below.
Features
- Built-in story editor (type/paste,
#lines become chapters) + upload.txt,.md,.epub,.kepub,.pdf,.docx,.html,.rtf,.fb2. EPUBs are split into chapters in reading order using the book's table of contents; PDFs split on their bookmarks/outline when present. - π Book library & batch conversion β a managed shelf of source files at
data/users/<username>/books/. Add files or a whole folder from the Upload tab, or just drop ebooks straight into that share and they appear automatically. Then Convert all, or tick a few and Convert selected β each book shows its detected chapter count, and batch jobs queue one at a time using the voice/settings you've chosen. - Narration directives β inline cues the studio interprets itself:
[pause 3s]/[pause]/[beat]insert real silence, and[slow],[fast],[normal]change the pace of the following text. (These are reserved words β they're never read aloud or mistaken for a[Name]speaker tag.) - Voice picker with 35 voices, grouped/filterable, each with a βΆ sample you
can play/stop (every play button toggles). Story-friendly voices are starred
(β
).
af_heartis the default. - Saved presets & My Stories β save a bundle of settings (voice, engine, loudness, ambienceβ¦) as a named preset and reapply it per series; keep works-in-progress in a My Stories list. Re-saving a preset updates it in place rather than duplicating.
- Live preview β hear your chosen voice read the current text before committing to a full conversion.
- Choose your TTS engine (dropdown, per conversion):
- Kokoro (default) β fast, lightweight, many preset voices.
- Chatterbox (expressive) β richer, more lifelike delivery with an Expressiveness dial and voice cloning. Heavier (more VRAM, slower).
- ποΈ Record / clone a voice (Chatterbox) β record your own voice in the browser (read the on-screen script for ~15β20s) or upload a short clip, and save it to a reusable My Voices library. Narrate in your voice. (The mic needs a secure page β see Expressive voices below.)
- Reading-speed slider, optional cover art, author label.
- Output loudness control (Off / Standard / Loud / Extra loud) β applies EBU R128 loudness normalization so the finished book plays at a consistent, full volume, even on quiet speakers (e.g. a Toniebox). Defaults to Loud.
- Live progress (stage, segment count, ETA) + per-job log.
- π Multi-voice cast β give each character their own voice. Three ways:
- πͺ Smart cast (AI) β a local Ollama model (Llama 3.2 3B) reads the story,
attributes each line to a speaker, and auto-inserts
[Name]tags for you to review. Best for messy/untagged dialogue. Falls back to Quick detect if the model isn't ready. - π Quick detect β fast rule-based: quotes + dialogue tags, with gender inference (honorifics + pronouns) to pick matching-gender voices.
[Name]markup β tag speakers yourself for exact control, e.g.[Pip] "I can do it!". The cast panel lets you assign/preview a voice per character before converting. Works for uploaded files too: multi-voice auto-assigns distinct gender-matched voices to detected characters with zero setup, and π/πͺ read the file's text so you can review/override the cast first.
- πͺ Smart cast (AI) β a local Ollama model (Llama 3.2 3B) reads the story,
attributes each line to a speaker, and auto-inserts
- π΅ Background ambience β mix a bed under the narration: built-in
license-free beds (Soft Rain, Gentle Night, Warm Hum, Dreamy Pad), or upload
your own / drop files in
data/ambience/. Volume slider + auto-ducking (music dips under speech). - Output: chaptered M4B + per-chapter MP3 (zip). Both downloadable.
- Auto-export to an Audiobookshelf library (path + owner UID/GID
configurable; see
docker-compose.yml). - π¨ Themes β Bookshop Light (aged paper), Bookshop Dark (a lamplit study), and Violet (the original look), switchable from the header and remembered per browser.
- Accounts β everyone signs in with their own username and gets their own stories, saved voices, book library, presets, pronunciations and conversion history. Job history survives restarts.
Tests
The account layer has standalone smoke tests (no pytest needed) β see
tests/README.md:
pip install fastapi httpx python-multipart itsdangerous # once, outside the container
for t in tests/test_*.py; do python3 "$t" || break; done
Managing it
cd vellichor-web # your project directory
docker compose up -d # start / apply changes
docker compose logs -f # watch logs
docker compose down # stop
docker compose up -d --build # rebuild after editing app/ code
AI Smart cast (Ollama)
Smart cast is optional β without it, multi-voice casting uses the
rule-based Quick detect instead. To enable it, the ollama service (in
docker-compose) runs a local LLM. After the first docker compose up -d, pull
the model once:
docker exec vellichor-ollama ollama pull llama3.2:3b
Both models share the GPU; OLLAMA_KEEP_ALIVE=2m unloads the LLM from VRAM
after use so Kokoro has room (on an 8 GB card they can't both stay resident).
To try a more accurate (heavier) model, pull it and set SMARTCAST_MODEL in
.env (e.g. qwen2.5:7b), then up -d.
Expressive voices (Chatterbox)
Pick Chatterbox (expressive) from the TTS engine dropdown for more lifelike, emotional narration. Two extra controls appear:
- Expressiveness β how animated the delivery is (0.5 is a good default).
- Voice source β clone a voice instead of using a preset:
- Preset β clones the Kokoro voice picked on the left (zero setup).
- Record a voice β record yourself in the browser (read the on-screen script for ~15β20s), review, then Use for this book or Save it to My Voices.
- Upload a clip β a clean 5β30s single-speaker clip works best.
Saved voices form a My Voices library reusable across books, stored under
data/users/<username>/voices/ β your recordings are private to your account. Cloning runs locally on your GPU β clips never leave the box.
Notes:
- The microphone only works on a secure page (
https://orlocalhost). Overhttp://<ip>:7777the browser blocks the mic β put Vellichor behind an HTTPS reverse proxy (or use localhost). Uploading a clip works either way. - Chatterbox is heavier than Kokoro (more VRAM, slower). It loads/unloads
around Kokoro and the Ollama model to share an 8 GB card; its model (~1β2 GB)
downloads on first use into
data/hf-cache. - Multi-voice cast is Kokoro-only for now.
- Chatterbox is MIT-licensed; outputs carry an inaudible Resemble "Perth" watermark by design (harmless for personal use).
Configuration (.env)
VELLICHOR_PASSWORDβ the initial password for the admin account, applied on first start. Once set, change it in the app (π€ β Your password); the env var is then ignored, so a stale.envcan't undo it. Leaving it blank disables sign-in entirely (see Security).VELLICHOR_ADMIN_USERβ optional; the admin's username (defaultadmin). Only used when the account store is first created.SECRET_KEYβ session-cookie signing key (don't change or logins reset).TRUSTED_PROXIESβ whoseX-Forwarded-Forto believe when identifying a caller for rate limiting:private(default β loopback + RFC1918, right for a reverse proxy on your LAN/Docker network),none(no proxy; Vellichor is reached directly), or a comma-separated list of IPs/CIDRs.LOGIN_MAX_FAILS/LOGIN_LOCK_SECONDSβ failed sign-ins before lockout (default 5) and the first lockout's length (default 10s, doubling per failure up to 15 minutes).NOTIFY_URLβ optional. Set to an ntfy/gotify URL to get a push when a conversion finishes, e.g.http://<server-ip>:8087/vellichor.
Data
Shared, at the top of ./data/:
users.jsonβ the account list (usernames, roles, scrypt password hashes).jobs/+jobs.jsonβ conversion workdirs and history (each job records its owner; you only ever see your own).samples/,refs/,ambience/,hf-cache/β cached voice samples, cloning references, ambience beds and the Hugging Face model cache. Models download on first use.uploads/β transient scratch space.
Private, one folder per account under ./data/users/<username>/:
books/β that person's book library. Drop ebooks in over SMB and they appear in their UI.voices/β their saved My Voices cloning clips.stories.json,presets.json,pronunciations.jsonβ their saved stories, setting presets and pronunciation rules.
Deleting an account from the People panel deletes its folder and its conversions; audiobooks already exported to Audiobookshelf stay put.
Notes
- GPU is used automatically (
β‘ GPUchip in the header). Falls back to CPU if the NVIDIA runtime is unavailable. - Conversions run one at a time (single worker) so the GPU isn't oversubscribed.
Accounts
- Everyone gets a username and their own private library. Private: stories, saved voices, book library, presets, pronunciations, conversions and their downloads. Shared: the voice models and preset voices, ambience beds, and the Audiobookshelf library you export into.
- Admins manage people: π€ in the header β People β add someone, reset a password, promote/demote, or delete. There is no self-registration β nobody can create their own account.
- Resetting or changing a password signs that person out of every device immediately. So does deleting their account.
- Two people exporting the same title by author into the shared Audiobookshelf library would collide; the second export is refused (with a note on the job) rather than overwriting the first.
- Upgrading from the single-password version: the first start creates the
adminaccount from your existingVELLICHOR_PASSWORDand moves all existing data β stories, books, voices, presets, pronunciations, job history β into it. Nothing is lost and the move happens once (marked bydata/.multiuser-migrated).
Security & deployment
- Set a password.
VELLICHOR_PASSWORDseeds the admin account. If no account has a password, authentication is disabled entirely and every request runs as the admin β only do that on a trusted private network. - Passwords are stored as scrypt hashes in
data/users.json(mode 600), never in plaintext. - The login form is rate limited. After
LOGIN_MAX_FAILSfailures a caller is locked out for a doubling delay (10s, 20s, 40s β¦ capped at 15 min), so a password list gets a handful of guesses and then a few per hour. Signing in successfully clears the record, and a quiet 15 minutes resets the count. Failures are logged (docker compose logs) with the username and IP, so you can see when you're being probed. A username can only be locked for 60s β long enough to slow distributed guessing, too short for anyone to lock a housemate out on purpose. - Set
TRUSTED_PROXIEScorrectly β it's what makes the above work. Behind a reverse proxy, the connection always comes from the proxy, so without it every visitor shares one bucket and one attacker locks out the house. It's also whyX-Forwarded-Foris only believed from a trusted peer: taking it from anyone would let an attacker send a fresh header per request and never be limited. - Don't expose it directly to the internet. Accounts keep housemates out of each other's libraries; they are not a hardened security boundary against the open web. If you need remote access, put it behind a reverse proxy (Nginx Proxy Manager, Traefik, Caddy) with HTTPS and ideally an extra auth layer (e.g. Authelia).
- Keep
.envprivate (chmod 600). It holds your password andSECRET_KEYand is gitignored β never commit it. SECRET_KEYsigns the session cookie. Generate one withopenssl rand -hex 32. Changing it invalidates existing logins.- Uploaded documents (epub/pdf/docx/html/rtf/fb2/β¦) are parsed server-side, and every account can use the GPU β only hand out accounts to people you trust.
License
MIT β free to use, modify, and redistribute. TTS by Kokoro-82M (Apache-2.0).
Install Vellichor on Unraid in a few clicks.
Find Vellichor in Community Apps on your Unraid server, review the template, and click Install. Unraid handles the Docker app or plugin setup from the published template.
Categories
Related apps
Explore more like this
Explore allDetails
ghcr.io/woodscode/vellichor-web:latestRuntime arguments
- Web UI
http://[IP]:[PORT:7777]/- Network
bridge- Shell
bash- Privileged
- false
- Extra Params
--runtime=nvidia --memory=12g
Template configuration
Port for the web UI.
- Target
- 7777
- Default
- 7777
- Value
- 7777
Accounts, each user's private library (users/name/), job history, and the model cache (Kokoro). Persisted.
- Target
- /data
- Default
- /mnt/user/appdata/vellichor/data
- Value
- /mnt/user/appdata/vellichor/data
Optional. Where finished audiobooks are exported, e.g. your Audiobookshelf library share. Leave blank if unused.
- Target
- /library
Initial password for the admin account, applied on first start only (change it afterwards in the app: π€ β Your password). LEAVE BLANK ONLY ON A TRUSTED LAN β blank disables sign-in entirely.
- Target
- VELLICHOR_PASSWORD
Username for the admin account. Only used when the account list is first created. Other people are added from inside the app (π€ β People).
- Target
- VELLICHOR_ADMIN_USER
- Default
- admin
- Value
- admin
Session-cookie signing key. Generate with: openssl rand -hex 32. Blank = a random key each restart (everyone gets logged out on restart).
- Target
- SECRET_KEY
Whose X-Forwarded-For header to believe when identifying a caller for login rate limiting. "private" (default) trusts loopback + LAN/Docker ranges, which is right when Vellichor is behind a reverse proxy. Use "none" if nothing proxies it, or list IPs/CIDRs. Wrong value = every visitor shares one lockout bucket, or the limit can be bypassed with a spoofed header.
- Target
- TRUSTED_PROXIES
- Default
- private
- Value
- private
Failed sign-ins before a caller is locked out.
- Target
- LOGIN_MAX_FAILS
- Default
- 5
- Value
- 5
Length of the first lockout in seconds; it doubles with each further failure, up to 15 minutes.
- Target
- LOGIN_LOCK_SECONDS
- Default
- 10
- Value
- 10
Optional. URL of a separate Ollama container for AI Smart cast, e.g. http://192.168.1.50:11434. Blank disables Smart cast (rule-based Quick detect still works).
- Target
- OLLAMA_URL
Ollama model used for Smart cast (must be pulled in your Ollama container).
- Target
- SMARTCAST_MODEL
- Default
- llama3.2:3b
- Value
- llama3.2:3b
Optional ntfy/gotify URL to get a push when a conversion finishes.
- Target
- NOTIFY_URL
UID to own exported audiobook files so your library app can read them (Unraid 'nobody' = 99).
- Target
- ABS_UID
- Default
- 99
- Value
- 99
GID to own exported files (Unraid 'users' = 100).
- Target
- ABS_GID
- Default
- 100
- Value
- 100
GPU(s) to expose. Requires the Nvidia Driver plugin. NO GPU? Clear 'Extra Parameters' (remove --runtime=nvidia) and ignore this.
- Default
- all
- Value
- all
Leave as-is for GPU acceleration.
- Default
- compute,utility
- Value
- compute,utility