# Chatterbox TTS in locale (CPU/GPU) con Docker + Nginx – Guida completa > Fonte: https://francescogruner.it/chatterbox-tts-locale-docker-nginx-guida/ Negli ultimi mesi sto facendo un giro d’orizzonte sui **Text-to-Speech locali**, per capire cosa abbia senso usare “on-prem” quando privacy, latenza e costi ricorrenti contano più di tutto. In questo post metto sotto la lente **Chatterbox TTS**, un progetto open che espone un’API stile OpenAI e supporta la **clonazione voce** e lo **streaming**. > Sul mio hardware (Windows 11 + Docker Desktop/WSL2, **RTX 3050 Ti 4 GB** e **64 GB RAM**) Chatterbox TTS gira bene in locale. Con **GPU** l’inferenza è nettamente più vivace rispetto alla **CPU** (che per una frase breve arrivava anche a ~60s), ma **per l’italiano** oggi sento ancora un accento inglese e un timbro un po’ metallico anche clonando la mia voce. Non è “pronto per doppiaggio”, però è **promettente** e lo terrò **in test continuo**. 👉[Valutazione e pro/contro qui](https://francescogruner.it/tools-directory/chatterbox-tts-tts-locale-multilingua-con-clonazione-vocale/) Indice dei contenuti [Toggle](#) - [Perché TTS locale](#Perche_TTS_locale) - [Cosa è Chatterbox TTS (in 20 secondi)](#Cosa_e_Chatterbox_TTS_in_20_secondi) - [Ti sta piacendo?](#Ti_sta_piacendo) - [La mia postazione di test](#La_mia_postazione_di_test) - [Cosa ho testato](#Cosa_ho_testato) - [Tuning che mi ha convinto di più (italiano)](#Tuning_che_mi_ha_convinto_di_piu_italiano) - [Qualità della voce in italiano](#Qualita_della_voce_in_italiano) - [Come migliorare la resa (consigli pratici)](#Come_migliorare_la_resa_consigli_pratici) - [Performance: CPU vs GPU](#Performance_CPU_vs_GPU) - [Frontend & Nginx: due note che ti risparmiano ore](#Frontend_Nginx_due_note_che_ti_risparmiano_ore) - [Problemi incontrati (e soluzioni lampo)](#Problemi_incontrati_e_soluzioni_lampo) - [In sintesi](#In_sintesi) - [Guida pratica](#Guida_pratica) - [1) Prerequisiti](#1_Prerequisiti) - [2) Clona il progetto](#2_Clona_il_progetto) - [3) Avviare il backend API](#3_Avviare_il_backend_API) - [3.1 CPU (semplice e universale)](#31_CPU_semplice_e_universale) - [3.2 GPU (più veloce)](#32_GPU_piu_veloce) - [3.3 Verifiche veloci](#33_Verifiche_veloci) - [3.4 Script in Python per caricare la tua voce](#34_Script_in_Python_per_caricare_la_tua_voce) - [3.5 Script in Python per generare l’audio e salvarlo](#35_Script_in_Python_per_generare_laudio_e_salvarlo) - [4) Avviare il frontend con Docker](#4_Avviare_il_frontend_con_Docker) - [4.1 Modalità “standalone” (frontend separato dall’API)](#41_Modalita_%E2%80%9Cstandalone%E2%80%9D_frontend_separato_dallAPI) - [4.2 Modalità “tutto in Compose” (frontend + API nella stessa rete)](#42_Modalita_%E2%80%9Ctutto_in_Compose%E2%80%9D_frontend_API_nella_stessa_rete) - [5) Nginx: configurazione pronta](#5_Nginx_configurazione_pronta) - [5.1 Se il frontend è standalone (API fuori dal compose)](#51_Se_il_frontend_e_standalone_API_fuori_dal_compose) - [5.2 Se usi compose per entrambi](#52_Se_usi_compose_per_entrambi) - [6) Primi test API (PowerShell-friendly)](#6_Primi_test_API_PowerShell-friendly) - [6.1 Lingue e voci](#61_Lingue_e_voci) - [6.2 Carica una voce (clonazione semplice)](#62_Carica_una_voce_clonazione_semplice) - [6.3 Genera audio (WAV) – endpoint compatto](#63_Genera_audio_WAV_%E2%80%93_endpoint_compatto) - [6.4 Streaming “a spezzoni” (Python, salva mentre arriva)](#64_Streaming_%E2%80%9Ca_spezzoni%E2%80%9D_Python_salva_mentre_arriva) - [7) Impostazioni consigliate (italiano)](#7_Impostazioni_consigliate_italiano) - [8) Operazioni utili](#8_Operazioni_utili) - [9) Troubleshooting (problemi visti davvero)](#9_Troubleshooting_problemi_visti_davvero) - [10) Pulizia/Disinstallazione](#10_PuliziaDisinstallazione) - [11) Esempio “ready-to-run” (CPU) con tutto in Compose](#11_Esempio_%E2%80%9Cready-to-run%E2%80%9D_CPU_con_tutto_in_Compose) - [12) FAQ lampo](#12_FAQ_lampo) - [Conclusione](#Conclusione) ## Perché TTS locale - **Privacy**: gli audio non escono dalla tua macchina. - **Predictable cost**: niente token/overage. - **Bassa latenza** (specie su GPU) + **controllo totale** del deployment. ## Cosa è Chatterbox TTS (in 20 secondi) ![](https://francescogruner.it/wp-content/uploads/2025/09/image-2-1024x772.png) - Server **FastAPI** con documentazione **/docs** e schema **/openapi.json**. - Endpoint compatibili con OpenAI per **/v1/audio/speech** e vari alias (**/audio/speech**, **/audio/speech/stream**). - Modello **multilingua** con 20+ lingue (italiano incluso). - **Voice library** integrata: puoi caricare campioni WAV/MP3, rinominare, impostare una **default voice**, gestire alias, scaricare/eliminare. - Modalità **streaming** per sentire l’audio mentre viene generato. ## Ti sta piacendo? Ricevi una guida pratica ogni settimana. AI, tool e automazioni. Iscriviti gratis Perfetto, sei dentro. ## La mia postazione di test - **OS**: Windows 11 + **Docker Desktop** (con **WSL2**) - **GPU**: NVIDIA **RTX 3050 Ti 4 GB** - **RAM**: **64 GB** - **Container**: - **chatterbox-tts-api-cpu** (porta **4123**) - **chatterbox-tts-api-gpu** (sempre **4123**, device `cuda`) - **Frontend** statico su **Nginx** (porta **8080**) con `VITE_API_BASE` puntato all’API > Nota: per chi usa Docker su Windows, l’API gira dentro **docker-desktop** (WSL2). Il processo **VmmemWSL** può salire di RAM: è normale durante il primo warm-up modello. ## Cosa ho testato - **Lingue** disponibili via `GET /languages` → 22 (italiano incluso). - **Voci** personali caricate via `POST /voices` (es. `italian_sample.wav`) e verificate con `GET /voices`. - Generazione **non-streaming** su `/audio/speech` e **streaming** su `/audio/speech/stream` con chunking per frase. - Frontend Docker con **Nginx** davanti: pulsante “Generate”, pannello “Advanced Settings”. ### Tuning che mi ha convinto di più (italiano) Nella UI, questi range hanno dato i risultati più naturali: - **Exaggeration** (emotività): **0.35–0.50** - **Pace / CFG Weight** (ritmo/pausa): **0.25–0.40** - **Temperature** (variazione/creatività): **0.60–0.80** - **Streaming**: strategy **sentence**, chunk ~frase > Se senti “sibilanti” o cantilena inglese, abbassa un filo **Exaggeration** e **Temperature**, e tieni **CFG** sotto 0.4. ## Qualità della voce in **italiano** La parte più importante. Con **campioni voce personali** puliti (WAV 16-48 kHz, 16-bit, senza musica/riverbero, 30–60 s), la **somiglianza timbrica** c’è, ma: - rimane **una patina anglofona** (intonazione e /r/ /t/ /s/ spesso “anglicizzate”); - in certe frasi si sente una **leggerissima metallicità**; - la **prosodia** non sempre “aggancia” le virgole. Non è un problema di pipeline: è proprio lo **stato attuale del modello** multilingua. Se il tuo target è **assistenti vocali**, **demo interne** o **prototipi** va già bene; per **voice-over** pubblicitari o **doppiaggio** serve ancora un salto. ### Come migliorare la resa (consigli pratici) 1. **Campione voce**: 30–60 s, ambiente trattato, microfono decente, ritmo naturale. 2. **Testo campione**: includi accenti, apostrofi, numeri, nomi propri italiani. 3. **Pronuncia**: evita inflessioni teatrali; meglio neutra e scorrevole. 4. **Parametri**: parti dai range sopra, poi micro-tuning su frasi difficili. 5. **Warm-up**: la prima generazione scalda cache e può essere lenta; le successive migliorano. Se ti serve, ho preparato un **copione sample** per caricare una voce “ricca” di fonemi italiani (lo trovi nella guida). ## Performance: CPU vs GPU - **CPU**: una frase breve può arrivare anche a **~60 secondi** la prima volta (poi migliora, ma resta poco reattivo). - **GPU (RTX 3050 Ti 4 GB)**: inferenza **molto più fluida**; non è “istantanea” come i TTS nativi-inglese più ottimizzati, ma è **usabile** e con **streaming** l’effetto percepito è decisamente migliore. - **RAM**: tener d’occhio **VmmemWSL** durante i primi minuti; poi si stabilizza. ## Frontend & Nginx: due note che ti risparmiano ore - Se avvii il frontend in Docker, **non** usare nomi di servizio hard-codati (`chatterbox-tts`) nell’upstream Nginx. Punta l’API a **`http://host.docker.internal:4123`** (Windows/Mac) o all’**IP della macchina**. - Nel container del frontend, passa **`-e VITE_API_BASE=http://host.docker.internal:4123`** e usa l’Nginx già configurato per servire gli asset statici. ## Problemi incontrati (e soluzioni lampo) - **PowerShell vs bash**: i comandi `curl` con `-H` e `-d` danno errore in PS se copiati “alla Linux”. Usa `curl.exe` e **json** con `--data`/`-d` tra **apici doppi**, oppure fai le chiamate con **Python/requests**. - **Frontend che “loopa” sulle voci**: era l’upstream sbagliato in Nginx. Sistemato puntando a `host.docker.internal:4123`. - **/docs ok ma frontend vuoto**: quasi sempre è **CORS/endpoint** o variabile `VITE_API_BASE` mancante. ## In sintesi **Chatterbox TTS** è già oggi un **buon candidato** per chi vuole un **TTS locale** multilingua con una vera **voice library** ed endpoint comodi. Nel mio uso reale: - **Pro**: facile da containerizzare, API chiare, streaming, voice management, gira su GPU “consumer”. - **Contro**: **italiano** ancora con accento straniero e prosodia da limare; **CPU** troppo lenta per scenari “live”. Io lo terrò **in produzione “di prova”** su GPU e aggiornerò questo post man mano che escono nuovi pesi/preset. Adesso passiamo al pezzo forte, ovvero la **guida completa** per rifare esattamente i miei test (CPU **e** GPU), con **frontend Docker** e **Nginx** già pronti, script per **upload voce** e chiamate **streaming**. Buon divertimento! ## Guida pratica Intanto se vuoi avere maggiori informazioni ti invito ad accedere alla [Repo GitHub](https://github.com/resemble-ai/chatterbox) del progetto. Iniziamo con il vero setup: ### 1) Prerequisiti - **Windows 10/11** con **WSL2** abilitato. - **Docker Desktop** (usa sempre la distro `docker-desktop` come VM dei container). - **GPU (opzionale):** driver NVIDIA recenti + “Use the WSL 2 based engine” abilitato in Docker Desktop → *Settings → Resources → WSL Integration* e *Settings → Resources → GPU*. - **curl.exe** (già presente su Windows 11), **Python 3** (per gli esempi), **ffmpeg** opzionale se vuoi ascoltare stream al volo. > 🔎 Nota WSL: le distro “Ubuntu”/“Ubuntu-22.04” sono facoltative per te. **I container girano in `docker-desktop`**. ### 2) Clona il progetto ``` cd $HOME git clone https://github.com/travisvn/chatterbox-tts-api.git cd chatterbox-tts-api ``` Struttura che ci interessa: ``` chatterbox-tts-api/ docker/ docker-compose.cpu.yml docker-compose.gpu.yml frontend/ Dockerfile nginx.conf ``` ### 3) Avviare il **backend** API #### 3.1 CPU (semplice e universale) ``` cd docker docker compose -f docker-compose.cpu.yml up -d --build ``` - Espone l’API su **[http://localhost:4123](http://localhost:4123)** - Contenitore tipico: `chatterbox-tts-api-cpu` #### 3.2 GPU (più veloce) ``` cd docker # se il container CPU è acceso, spegnilo PRIMA (stesso port 4123) docker compose -f docker-compose.cpu.yml down # poi avvia la versione GPU docker compose -f docker-compose.gpu.yml up -d --build ``` - Espone **sempre** su **[http://localhost:4123](http://localhost:4123)** - Contenitore tipico: `chatterbox-tts-api-gpu` - Nei log vedrai `Device: cuda`. Puoi verificare: ``` docker exec -it chatterbox-tts-api-gpu bash -lc "nvidia-smi" ``` #### 3.3 Verifiche veloci ``` curl.exe -s http://127.0.0.1:4123/health curl.exe -s http://127.0.0.1:4123/openapi.json > NUL start http://127.0.0.1:4123/docs ``` Se `/docs` si apre, l’API è pronta. #### 3.4 Script in Python per caricare la tua voce ``` import requests files = { "voice_file": ("italian_sample.wav", open("C:/Users/Francesco/Desktop/tts/italian_sample.wav", "rb"), "audio/wav") } data = { "voice_name": "italian_sample", "language": "it" } response = requests.post("http://localhost:4123/voices", data=data, files=files) print(f"Upload status: {response.status_code}, response: {response.text}") ``` #### 3.5 Script in Python per generare l’audio e salvarlo ``` import requests url = "http://localhost:4123/audio/speech" headers = {"accept": "audio/wav", "Content-Type": "application/json"} data = { "input": "Ciao, come stai? Tutto bene? Questo è un test di generazione vocale.", "voice": "italian_sample", "response_format": "wav", "speed": 1.0, "exaggeration": 0.5, "cfg_weight": 0.5, "temperature": 0.75 } r = requests.post(url, headers=headers, json=data) if r.ok: with open("output_italian.wav", "wb") as f: f.write(r.content) print("Audio salvato come output_italian.wav") else: print(r.status_code, r.text) ``` ### 4) Avviare il **frontend** con Docker Costruiamo l’immagine e lanciamo un container Nginx statico. ``` cd ..\frontend docker build -t chatterbox-tts-frontend . ``` #### 4.1 Modalità “standalone” (frontend separato dall’API) In Windows, il frontend deve parlare con l’API host usando `host.docker.internal`: ``` docker run --name tts-frontend --rm -p 8080:80 ` -e VITE_API_BASE=http://host.docker.internal:4123 ` chatterbox-tts-frontend ``` Apri **[http://localhost:8080](http://localhost:8080)** → ora il frontend chiama correttamente l’API. > 💡 Se preferisci **127.0.0.1** al posto di `host.docker.internal`, modifica direttamente `nginx.conf` (vedi §5). #### 4.2 Modalità “tutto in Compose” (frontend + API nella stessa rete) Se vuoi far parlare Nginx con l’API usando il **nome del servizio** (`chatterbox-tts`), serve un compose unico. Esempio minimale: ``` # docker-compose.app.yml services: chatterbox-tts: build: context: .. dockerfile: docker/Dockerfile.cpu # o .gpu per GPU image: docker-chatterbox-tts ports: - "4123:4123" tts-frontend: build: context: ../frontend image: chatterbox-tts-frontend ports: - "8080:80" environment: - VITE_API_BASE=http://chatterbox-tts:4123 depends_on: - chatterbox-tts ``` Poi: ``` docker compose -f docker-compose.app.yml up -d --build ``` ### 5) **Nginx**: configurazione pronta #### 5.1 Se il frontend è **standalone** (API fuori dal compose) Usa questa `nginx.conf` (è quella che ci ha sbloccato tutto): ``` server { listen 80; server_name localhost; root /usr/share/nginx/html; index index.html index.htm; gzip on; gzip_vary on; gzip_min_length 1024; gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json; # API Proxy → backend locale su Windows/Mac: set $api http://host.docker.internal:4123; location /v1/ { proxy_pass $api; } location /health { proxy_pass $api; } location /config { proxy_pass $api; } location /models { proxy_pass $api; } location /memory { proxy_pass $api; } location /docs { proxy_pass $api; } location /redoc { proxy_pass $api; } location /openapi.json { proxy_pass $api; } # Static cache location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ { expires 1y; add_header Cache-Control "public, immutable"; try_files $uri =404; } # SPA routing location / { try_files $uri $uri/ /index.html; add_header X-Content-Type-Options nosniff; add_header X-Frame-Options DENY; add_header X-XSS-Protection "1; mode=block"; } # Health del frontend location /frontend-health { access_log off; return 200 "frontend healthy\n"; } # Sicurezza di base add_header Referrer-Policy "strict-origin-when-cross-origin"; add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' http://host.docker.internal:4123 ws://localhost:*"; server_tokens off; client_max_body_size 10M; } ``` > Se preferisci **127.0.0.1**, cambia `set $api http://127.0.0.1:4123;`. #### 5.2 Se usi **compose** per entrambi Nel `nginx.conf` metti: ``` set $api http://chatterbox-tts:4123; ``` perché i servizi condividono la rete Compose. ### 6) Primi test API (PowerShell-friendly) > ⚠️ In PowerShell usa **`curl.exe`** (non l’alias `curl`) per evitare i classici errori di parametri. #### 6.1 Lingue e voci ``` curl.exe -s http://127.0.0.1:4123/languages curl.exe -s http://127.0.0.1:4123/voices ``` #### 6.2 Carica una voce (clonazione semplice) File di esempio: `C:\Users\Francesco\Desktop\tts\italian_sample.wav` (16 kHz/24 kHz, mono, 5–20 s, pulito). ``` curl.exe -s -X POST http://127.0.0.1:4123/voices ` --form "voice_name=italian_sample" ` --form "language=it" ` --form "voice_file=@C:\Users\Francesco\Desktop\tts\italian_sample.wav" ``` Verifica: ``` curl.exe -s http://127.0.0.1:4123/voices ``` #### 6.3 Genera audio (WAV) – **endpoint compatto** ``` curl.exe -s -X POST http://127.0.0.1:4123/audio/speech ` --json "{`"input`": `"Ciao, come stai? Tutto bene?`", `"voice`": `"italian_sample`", `"language_id`": `"it`", `"exaggeration`": 0.4, `"cfg_weight`": 0.3, `"temperature`": 0.6}" ` --output out.wav ``` Apri `out.wav` e ascolta. #### 6.4 Streaming “a spezzoni” (Python, salva mentre arriva) ``` import requests URL = "http://127.0.0.1:4123/audio/speech/stream" payload = { "input": "Ciao! Prova di streaming in tempo reale.", "voice": "italian_sample", "language_id": "it", "streaming_strategy": "sentence", "exaggeration": 0.4, "cfg_weight": 0.3, "temperature": 0.6 } with requests.post(URL, json=payload, stream=True, timeout=120) as r: r.raise_for_status() with open("stream.wav", "wb") as f: for chunk in r.iter_content(8192): if chunk: f.write(chunk) print("OK -> stream.wav") ``` ### 7) Impostazioni consigliate (italiano) - **Campione voce**: 5–20 s, **mono**, **16 kHz o 24 kHz**, senza rumore/sottofondo, tono colloquiale. - **Parametri “Advanced”** - `language_id`: **“it”** - `cfg_weight` (Pace): **0.3–0.45** - `exaggeration` (Emozione): **0.35–0.6** - `temperature` (creatività): **0.55–0.8** - Per voci “piatte” o con accento inglese: carica un campione più pulito e rallenta un filo il pace (`cfg_weight ~0.35`). ### 8) Operazioni utili - **Imposta la voce di default** `curl.exe -s -X POST http://127.0.0.1:4123/voices/default -d "voice_name=italian_sample" curl.exe -s http://127.0.0.1:4123/voices/default` - **Pulizia/diagnostica memoria** `curl.exe -s "http://127.0.0.1:4123/memory?cleanup=true&force_cuda_clear=true"` - **Stato/Statistiche** `curl.exe -s http://127.0.0.1:4123/status curl.exe -s http://127.0.0.1:4123/status/statistics` ### 9) Troubleshooting (problemi visti davvero) ![](https://francescogruner.it/wp-content/uploads/2025/09/image-1.png) - **Frontend “non trova le voci” / loop richieste** → Manca/è sbagliato l’endpoint API. Se è **standalone**: lancia con `-e VITE_API_BASE=http://host.docker.internal:4123` **oppure** modifica `nginx.conf` come in §5.1. In alternativa puoi cambiarlo facilmente dal frontend. - **Errore Nginx “host not found in upstream ‘chatterbox-tts’”** → Capitava quando il frontend era *standalone* ma il proxy puntava al **nome compose**. Usa `host.docker.internal` (Windows/Mac) o `127.0.0.1`. - **PowerShell e `curl` che “non capisce” `-H` o `-d`** → In PS l’alias `curl` è `Invoke-WebRequest`. Usa **`curl.exe`**. - **CPU e GPU insieme sullo stesso 4123** → Non puoi pubblicare **lo stesso port** due volte. Spegni l’altro: `docker compose -f docker-compose.cpu.yml down` - **GPU non usata** → Controlla i log dell’API (`Device: cuda`) e `docker exec ... nvidia-smi`. Abilita GPU in Docker Desktop. - **IPv6/localhost “muto”** → Usa `http://127.0.0.1:4123` per i test curl. ### 10) Pulizia/Disinstallazione Spegni i container: ``` # backend (CPU o GPU) cd chatterbox-tts-api\docker docker compose -f docker-compose.cpu.yml down docker compose -f docker-compose.gpu.yml down # frontend docker rm -f tts-frontend ``` Rimuovi immagini (facoltativo): ``` docker rmi docker-chatterbox-tts chatterbox-tts-frontend ``` Volumi (attenzione: **perdi voci caricate e cache modelli**): ``` docker volume rm docker_chatterbox-voices docker_chatterbox-models ``` ### 11) Esempio “ready-to-run” (CPU) con tutto in Compose Salva come `docker-compose.all.yml` nella cartella `docker/`: ``` services: chatterbox-tts: build: context: .. dockerfile: docker/Dockerfile.cpu image: docker-chatterbox-tts ports: - "4123:4123" volumes: - chatterbox-models:/cache - chatterbox-voices:/voices tts-frontend: build: context: ../frontend image: chatterbox-tts-frontend ports: - "8080:80" environment: - VITE_API_BASE=http://chatterbox-tts:4123 depends_on: - chatterbox-tts volumes: chatterbox-models: chatterbox-voices: ``` Lancio: ``` cd chatterbox-tts-api\docker docker compose -f docker-compose.all.yml up -d --build start http://localhost:8080 ``` ### 12) FAQ lampo - **Posso usare solo l’API senza frontend?** Certo, lavori da `/docs` o con script. - **Perché vedo tanta RAM su “VmmemWSL”?** È la VM WSL che contiene `docker-desktop`; è normale (cache). Puoi limitare risorse con un `.wslconfig` se vuoi. - In locale Chatterbox TTS è tra i motori più semplici da mettere in piedi e integrare via API. Per assistenti vocali, demo e POC è già usabile (soprattutto su GPU). In italiano resta un po’ di accento/prosodia da rifinire per voice-over pro. Continuerò i test e aggiornerò il post quando usciranno preset/modelli migliori. ## Conclusione In locale Chatterbox TTS è tra i motori più semplici da mettere in piedi e integrare via API. Per assistenti vocali, demo e POC è già usabile (soprattutto su GPU). In italiano resta un po’ di accento/prosodia da rifinire per voice-over pro. Continuerò i test e aggiornerò il post quando usciranno preset/modelli migliori. Spero che questa guida ti sia stata utile, se hai dubbi e domande o semplicemente vuoi condividere il tuo feedback ti invito a scrivere un commento qui sotto.