# One settings file for the whole pipeline. Relative paths are relative to the repo root. books_dir: books # where book folders live: books/// work_dir: /tmp/audiobook-work # scratch only (OCR output, wav pieces). Point at local NVMe in production. # Where finished audio goes. Empty = the book folder in the repo (the agreed default). # Set to a folder to write ///audio there instead. archive_dir: "" narrator: "" # spoken in the credits only if filled in (leave empty for a TTS voice) # Inserted parts. All OFF by default. Per-book and per-chapter switches in book.json override these. summaries: chapter_preview: false chapter_summary: false concept_summary: false # one mid-chapter concept summary # OpenAI-compatible chat endpoint, used only when a summary switch is on. llm: endpoint: "" # e.g. http://host:8081/v1/chat/completions model: "" api_key_env: "" # name of an environment variable that holds the key (never put a key here) timeout_s: 300 # OpenAI-compatible speech endpoint. voice: # LOCKED by Ty 2026-10-17 for MVP ("clip B"): Chatterbox, stock voice Michael, native settings only. # Never set speed_factor: the server applies it as a time-stretch after generation and ruins the sound. api: chatterbox_tts # chatterbox_tts = native /tts route; anything else = OpenAI-style /v1/audio/speech endpoint: http://voice:8004/tts # override with env AUDIOBOOK_VOICE_ENDPOINT (CI uses the LAN address) model: chatterbox voice: Michael.wav extra: # extra JSON fields sent with every request exaggeration: 0.25 cfg_weight: 0.2 temperature: 0.6 seed: 7 split_text: true chunk_size: 240 # the server splits long text at sentence ends into chunks of about this size timeout_s: 600 retries: 3 # a failed request is retried this many times (5 s, then 15 s, then 45 s apart) before the run fails load_if_needed: true # if the server is up but its model is unloaded, ask it to load (POST /restart_server) before rendering unload_when_done: false # true = free the GPU after a render (POST /api/unload); the next run loads it again max_chunk_chars: 100000 # one request per paragraph; the server does the sentence splitting (chunk_size above) gap_sentence_s: 0.25 # pause between pieces inside a paragraph gap_paragraph_s: 0.7 # pause between paragraphs and after cues and labels ocr: enabled: true # run ocrmypdf only when a page has no text layer required: true # pages without a text layer and no working OCR = the run fails (env AUDIOBOOK_REQUIRE_OCR=0 to allow) language: eng min_chars_per_page: 10 # fewer characters than this = no text layer meta: first_pages: 10 # title/author are looked for on the first pages (OCR only for pages with no text layer) fetch: # a .url/.txt file in _incoming/ holding a link to a PDF max_mb: 300 # larger downloads are refused connect_timeout_s: 30 max_time_s: 900 # a whole download may take this long script: retail_sample_words: 400 # about 2.5 minutes at 155 words per minute (ACX asks for 1 to 5 minutes) chime_label: Chime license: public_domain_max_year: 1930 # US, as of 2026 audio: sample_rate: 44100 channels: 1 mp3_bitrate: 192k head_room_tone_s: 0.75 # ACX 0.5 to 1 tail_room_tone_s: 2.0 # ACX 1 to 5 room_tone_db: -66 # RMS level of the room tone (ACX noise floor limit is -60) target_rms_db: -20.5 # ACX -23 to -18 peak_ceiling_db: -4.0 # limiter ceiling; ACX limit is -3 and MP3 encoding can add a little chime_hz: 660 chime_s: 1.0 chime_db: -18 # peak level of the chime in the final file, kept soft acx: # limits used by the checker (R13) min_bitrate_kbps: 192 sample_rate: 44100 rms_min_db: -23 rms_max_db: -18 peak_max_db: -3 noise_floor_max_db: -60 head_min_s: 0.5 head_max_s: 1.0 tail_min_s: 1.0 tail_max_s: 5.0 max_minutes: 120 retail_min_s: 60 retail_max_s: 300 speech_window_db: -50 # a 50 ms window louder than this counts as speech when measuring head and tail