Usa el motor intern de Chromium (Google TTS) o el del sistema si està disponible
Configuració
/etc/speech-dispatcher/speechd.conf
No té fitxer de configuració propi; gestiona les veus via l’API speechSynthesis
Idiomes disponibles
Depenen dels mòduls carregats (espeak-ng, pico, festival, etc.)
Depenen de les veus instal·lades al sistema o integrades al navegador
Comanda per veure veus
spd-say -L o espeak-ng --voices
speechSynthesis.getVoices() des de la consola del navegador
Integració amb TTS
Firefox → speech‑dispatcher
Edge → motor Chromium (pot usar speech‑dispatcher si el sistema ho exposa)
Per defecte, el Festival s’instal·la en aquestes ubicacions estàndard (sistema Debian):
Contingut Ruta Executable principal /usr/bin/festival Veus (dades) /usr/share/festival/voices/ Llibreries i suport /usr/lib/festival/ Configuració global /etc/festival.scm Config del mòdul speech-dispatcher /etc/speech-dispatcher/modules/festival.conf
Molt bona observació, Miquel 👏
El que has mostrat és la configuració del serveispeech‑dispatcher del teu sistema Linux, que és el motor que Firefox (i altres aplicacions) fan servir per convertir text en veu. Però Microsoft Edge no utilitzaspeech‑dispatcher directament — té un comportament diferent:
🧩 Diferència clau entre Firefox i Edge (en Linux)
Aspecte
Firefox
Microsoft Edge
Motor de veu
Usa speech‑dispatcher del sistema (Linux)
Usa el motor intern de Chromium (Google TTS) o el del sistema si està disponible
Configuració
/etc/speech-dispatcher/speechd.conf
No té fitxer de configuració propi; gestiona les veus via l’API speechSynthesis
Idiomes disponibles
Depenen dels mòduls carregats (espeak-ng, pico, festival, etc.)
Depenen de les veus instal·lades al sistema o integrades al navegador
Comanda per veure veus
spd-say -L o espeak-ng --voices
speechSynthesis.getVoices() des de la consola del navegador
Integració amb TTS
Firefox → speech‑dispatcher
Edge → motor Chromium (pot usar speech‑dispatcher si el sistema ho exposa)
Això vol dir que el teu speech‑dispatcher usa Piper, un motor de veu neuronal molt més natural que espeak-ng. Firefox pot aprofitar-lo si està ben configurat, però Edge normalment no el fa servir — ell usa les seves pròpies veus integrades.
🗣️ Si vols que Edge parli amb les mateixes veus que speech‑dispatcher
Pots provar d’executar Edge amb la variable d’entorn següent (només en Linux):
Això força Edge a intentar comunicar-se amb speech‑dispatcher. No tots els sistemes ho suporten, però en Deepin o Debian pot funcionar.
Vols que t’expliqui com verificar si Edge està realment usant speech‑dispatcher o el seu motor intern? Et puc mostrar una prova ràpida amb JavaScript per comprovar-ho.
Objectiu
Acció
Que speech‑dispatcher trobi Ona
Posar el model al host (ja ho tens)
Que speech‑dispatcher cridi Piper dins Docker
Crear wrapper /usr/local/bin/piper-docker
Que Piper usi Ona
Editar piper-generic.conf amb PIPER_VOICE=/home/Miquel/tts-server/...
Que Firefox parli amb Ona
Reiniciar speech‑dispatcher
Aquí tens, Miquel, un post complet, estructurat i llest per publicar al teu bloc, explicant la integració de Piper (veu Ona) amb speech‑dispatcher en Linux, incloent l’ús de models fora del contenidor Docker.
He escrit el post com si fos per Beseit i una mica de xirigol: clar, pràctic, amb passos verificables i sense misteris.
🟦 Integrar Piper (veu Ona) amb Speech‑Dispatcher en Linux
Funcionant amb models fora del Docker i accessible per Firefox, Orca i aplicacions TTS del sistema
Durant molt de temps, fer servir veus neuronals en Linux ha estat complicat: motors antics com espeak-ng o festival no ofereixen la qualitat que molts usuaris necessiten. Amb l’arribada de Piper, un motor TTS neuronal lleuger i de gran qualitat, la situació ha canviat radicalment.
En aquest article explico com integrar Piper (i concretament la veu catalana Ona) amb speech‑dispatcher, de manera que Firefox, Orca, LibreOffice i qualsevol aplicació que utilitzi TTS del sistema pugui parlar amb una veu natural.
A més, ho fem en un escenari real: el model Ona està dins un contenidor Docker, però speech‑dispatcher necessita accés directe al model. Aquí tens la solució completa.
🟥 El problema: speech‑dispatcher no pot veure dins Docker
Speech‑dispatcher només pot accedir a fitxers del sistema host. Si el model de Piper (per exemple ca_ES-upc_ona-medium.onnx) està dins Docker, speech‑dispatcher no el pot carregar.
Per tant:
❌ No podem apuntar directament a /models/... dins Docker
❌ No podem fer servir PIPER_VOICE amb un camí intern del contenidor
✔️ Necessitem que el model estigui accessible des del host
Afortunadament, Piper permet executar el motor des de Docker, però el model ha d’estar fora.
🟦 Solució correcta (i la que funciona)
1) Col·locar el model Ona al sistema host
En el nostre cas, el model ja és accessible:
Codi
/home/Miquel/tts-server/ca_ES-upc_ona-medium.onnx
Perfecte: speech‑dispatcher ja pot veure aquest fitxer.
2) Crear un “wrapper” perquè speech‑dispatcher pugui cridar Piper dins Docker
Creem un script que executi Piper dins el contenidor:
Codi
sudo nano /usr/local/bin/piper-docker
Contingut:
bash
#!/bin/bash
docker exec -i piper piper "$@"
Fem executable:
Codi
sudo chmod +x /usr/local/bin/piper-docker
Ara tenim un “binari virtual” que speech‑dispatcher pot cridar com si fos Piper.
Sí, és possible! I de fet, recordo que ja ho vam treballar abans. Deixa’m recuperar els detalls d’aquella configuració per donar-te la resposta exacta.
Sí, és possible! I de fet, ja ho vam integrar abans — tens un script pont piper-spd que connecta Speech Dispatcher amb el contenidor Docker del Piper. 🎙️
El mòdul sd_generic espera l’àudio per stdout, però el primer script el desava en un fitxer (-o). Cal que l’script emeti el WAV per stdout perquè funcioni. La solució és usar --output_file - (i opcionalment --output_raw per PCM pur).
Com ho comprovem ara?
Primer mira si la configuració anterior encara hi és:
ls -l /usr/lib/speech-dispatcher-modules/piper-spd
cat /etc/speech-dispatcher/modules/piper.conf 2>/dev/null
grep -n "piper" /etc/speech-dispatcher/speechd.conf
✅ TTS local i offline amb veu catalana de qualitat (Ona, UPC)
✅ Instal·lació senzilla amb Docker i reinici automàtic
✅ Protocol Wyoming estàndard → integrable amb Home Assistant i altres apps
✅ També es pot usar amb Speech Dispatcher perquè les aplicacions d’escriptori parlin en català
Aquesta és la base per a l’entrada! Si vols, també puc afegir una secció amb captures de pantalla o una part sobre com integrar-ho amb Speech Dispatcher (perquè el sistema llegeixi text en català). Ho deixem així o hi afegim alguna cosa més? 😊
Aclariments
Bona pregunta! 👌 El port 10200 no l’hem triat nosaltres — és el port per defecte d’aquesta imatge i de l’ecosistema Wyoming:
Motius
Port per defecte de linuxserver/piper — el servidor que hi ha dins del contenidor escolta al port 10200 de manera nativa. Per això al Docker fem -p 10200:10200 (port del host → port del contenidor).
Convenció de l’ecosistema Wyoming / Home Assistant — el protocol Wyoming (el que parla aquest servidor) fa servir habitualment ports del rang 10200-10300. De fet, el add-on de Piper per a Home Assistant també usa el 10200 per defecte. Així, si algun dia el connectes a Home Assistant o a una altra eina de veu, ja parlarà el mateix idioma al mateix port.
Port sense privilegis — està per sobre del 1024, així que no cal ser root ni configuracions especials per obrir-lo.
Es pot canviar?
Sí! La part de l’esquerra del mapeig és el port del host, així que podries posar-hi el que vulguis:
docker run -d --name piper -p 10500:10200 ...
(aleshores el servidor seria accessible a 127.0.0.1:10500). Però com que 10200 és l’estàndard, és millor deixar-lo com està perquè tot l’ecosistema el reconegui sense tocar res. 😊
Molt bona pregunta! No és que canviéssim de port — són dos servidors TTS diferents que conviuen, cadascun amb el seu port i la seva funció:
Els dos servidors
Port 8765
Port 10200
Servei
speech-to-speech
Piper (Docker)
Què és
Servidor compatible amb OpenAI Realtime (TTS + STT + LLM)
Motor TTS lleuger amb veu catalana
Veu catalana?
No específica (Qwen3-TTS, general)
Sí: Ona (ca_ES-upc_ona-medium, UPC)
Instal·lació
Python venv a ~/tts-server
Docker
Estat actual
Aturat
En marxa ✅
Per què vam afegir el Piper (10200)?
Perquè volies una veu catalana de qualitat (l’Ona de la UPC). El Piper és:
Lleuger i offline — perfecte per a un punt de treball local
Té el model ca_ES-upc_ona-medium específic per a català
S’integra amb Speech Dispatcher perquè el sistema llegeixi text en català
Docker el fa fàcil d’instal·lar, actualitzar i reinstal·lar
I el 8765?
No l’hem tret! El speech-to-speech continua instal·lat a ~/tts-server, només està aturat (ho vam veure quan ss no mostrava res al port 8765). És un servidor més «complet» (xat de veu amb micròfon + LLM), però no té la veu catalana específica.
Resum: el 8765 és per al xat de veu general, i el 10200 és el que et dona l’Ona en català. Cadascú al seu port, sense conflictes! 😊
SERVIDOR TTS SERVER /home/Miquel/tts-server
Què hi ha a ~/tts-server (sí, tot el servei speech-to-speech)
/home/Miquel/tts-server/
├── venv/ ← entorn Python amb el paquet speech-to-speech
├── prova_piper.py ← els nostres scripts de prova
├── prova_piper_dbg.py
└── ...
Aquí hi ha tot el servei speech-to-speech (el del port 8765): l’entorn virtual, el paquet instal·lat i els scripts.
On és la veu de l’Ona? (⚠️ NO és aquí)
La veu Ona NO està a ~/tts-server — està dins del contenidor Docker piper, a la carpeta /config/:
# Per veure-ho:
docker exec piper ls -lh /config/
Hi trobaràs:
ca_ES-upc_ona-medium.onnx ← el model de veu
ca_ES-upc_ona-medium.onnx.json ← config de la veu
⚠️ Punt important
Com que al docker runno vam muntar cap volum (-v), la veu viu dins de la capa del contenidor. Si algun dia fas docker rm -f piper, la veu es perd i es tornarà a descarregar en recrear el contenidor (caldrà internet la primera vegada).
Resum:
speech-to-speech → tot a ~/tts-server ✅
Ona → dins del contenidor Docker piper a /config/ ✅
Si vols preservar la veu encara que esborris el contenidor, et puc explicar com muntar un volum per a /config. T’interessa? 😊
Docker no penja de cap carpeta del teu usuari — el seu directori d’emmagatzematge és a nivell de sistema: /var/lib/docker
📁 Directori arrel de Docker /var/lib/docker
/var/lib/docker/
├── containers/ ← dades dels contenidors
├── image/ ← imatges (linuxserver/piper, etc.)
├── overlay2/ ← capes del sistema de fitxers dels contenidors
├── volumes/ ← volums (si n'hi ha)
└── ...
# Backup
tar czf tts-server-backup.tar.gz -C /home/Miquel tts-server
# Restauració (al mateix camí /home/Miquel/tts-server)
tar xzf tts-server-backup.tar.gz -C /home/Miquel
⚠️ Detall important: l’entorn virtual (venv) guarda camins absoluts. Si restaures al mateix camí (/home/Miquel/tts-server), funciona tal qual. Si el camí canvia, caldria recrear el venv i reinstal·lar el paquet.
2️⃣ Piper + veu Ona (port 10200) → Docker
Aquí tens dues opcions:
Opció A — Recomanada (lleugera): fer backup de la imatge + la carpeta de config
# Backup de la imatge Docker (el programa)
docker save linuxserver/piper -o piper-image.tar
# La veu: si muntem el volum /config (com et vaig suggerir), es desa a ~/piper-config
tar czf piper-config-backup.tar.gz ~/piper-config
Opció B — Completa (tot Docker): backup de /var/lib/docker
# Requereix sudo i és més pesat
sudo tar czf docker-full-backup.tar.gz /var/lib/docker
✅ El teu plantejament, confirmat PODEM FER BACKUP DEL SERVIDORS TTS
Servei
On es desa
Com es recupera
speech-to-speech (8765)
~/tts-server
Copiar la carpeta enrere
Piper + Ona (10200)
/var/lib/docker (imatge + capa contenidor)
Restaurar Docker odocker save + volum /config
Resum: sí, amb un backup de ~/tts-server + Docker ho recuperes tot. Però la manera més neta és:
tar de ~/tts-server (per al 8765)
docker save de la imatge + volum /config (per al 10200 i l’Ona) — així no cal tocar tot /var/lib/docker
Vols que et prepari un script de backup/restauració senzill amb tot això? 😊
Endavant! Et preparo dos scripts: un de backup i un de restauració. Els pots desar on vulguis (per exemple a ~/).
📦 Script 1 — Backup (tts_backup.sh)
Desa’l amb aquesta comanda:
# Amb l'USB "backup_tot" connectat, només cal:
~/tts_backup.sh
# → USB 'backup_tot' trobat a: /media/Miquel/backup_tot
# → Desant a: /media/Miquel/backup_tot/20260913_...
# Si l'USB no està connectat, et dirà que el connectis
Sí! Podem fer que el script busqui automàticament l’USB amb l’etiqueta backup_tot. Desa aquesta versió:
cat > ~/tts_backup.sh << 'EOF'
#!/bin/bash
# ============================================
# Backup del sistema TTS local (Deepin)
# Us: ./tts_backup.sh [carpeta_destinacio]
# Sense arguments: busca automaticament l'USB "backup_tot"
# Exemple: ./tts_backup.sh /media/Miquel/backup_tot
# ============================================
set -e
USB_LABEL="backup_tot"
DEST=""
# 1) Si es passa una carpeta, s'usa aquesta
if [ -n "$1" ]; then
DEST="$1"
else
# 2) Si no, buscar l'USB amb l'etiqueta backup_tot
DEST=$(findmnt -rn -o TARGET -S LABEL="$USB_LABEL" 2>/dev/null | head -1)
if [ -z "$DEST" ]; then
DEST=$(ls -d /media/*/"$USB_LABEL" /run/media/*/"$USB_LABEL" 2>/dev/null | head -1)
fi
if [ -n "$DEST" ]; then
echo "USB '$USB_LABEL' trobat a: $DEST"
fi
fi
# Si no s'ha trobat cap destinacio, error
if [ -z "$DEST" ]; then
echo "ERROR: no s'ha trobat la destinacio."
echo " - Connecta l'USB '$USB_LABEL' i munta'l"
echo " - O indica una carpeta: $0 /ruta/destinacio"
exit 1
fi
# Comprovar permisos
if [ ! -d "$DEST" ] || [ ! -w "$DEST" ]; then
echo "ERROR: la destinacio '$DEST' no existeix o no es pot escriure."
exit 1
fi
DATA=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="$DEST/$DATA"
mkdir -p "$BACKUP_DIR"
echo "Desant a: $BACKUP_DIR"
echo "=== 1/3 Backup de ~/tts-server (speech-to-speech) ==="
if [ -d "$HOME/tts-server" ]; then
tar czf "$BACKUP_DIR/tts-server.tar.gz" -C "$HOME" tts-server
echo "OK -> tts-server.tar.gz"
else
echo "AVIS: ~/tts-server no existeix, s'omet."
fi
echo "=== 2/3 Backup de la imatge Docker linuxserver/piper ==="
if docker image inspect linuxserver/piper >/dev/null 2>&1; then
docker save linuxserver/piper -o "$BACKUP_DIR/piper-image.tar"
echo "OK -> piper-image.tar"
else
echo "AVIS: imatge linuxserver/piper no trobada, s'omet."
fi
echo "=== 3/3 Backup de la veu Ona (/config del contenidor piper) ==="
if docker ps -a --format '{{.Names}}' | grep -qx piper; then
mkdir -p "$BACKUP_DIR/piper-config"
docker cp piper:/config/. "$BACKUP_DIR/piper-config/"
echo "OK -> piper-config/"
else
echo "AVIS: contenidor piper no existeix, s'omet."
fi
echo ""
echo "=== RESUM ==="
du -sh "$BACKUP_DIR"/*
echo "Backup completat a: $BACKUP_DIR"
EOF
chmod +x ~/tts_backup.sh
🚀 Com funciona ara
# Amb l'USB "backup_tot" connectat, només cal:
~/tts_backup.sh
# → USB 'backup_tot' trobat a: /media/Miquel/backup_tot
# → Desant a: /media/Miquel/backup_tot/20260913_...
# Si l'USB no està connectat, et dirà que el connectis
Com ho detecta:
Primer prova findmnt -S LABEL=backup_tot (busca per etiqueta a tots els punts de muntatge)
Si no, busca a les rutes típiques /media/*/backup_tot i /run/media/*/backup_tot
Encara pots forçar una ruta manual si vols: ~/tts_backup.sh /altre/lloc
⚠️ Recorda: l’USB ha d’estar connectat i muntat abans d’executar el script. Vols provar-ho? 😊
♻️ Script 2 — Restauració (tts_restore.sh)
cat > ~/tts_restore.sh << 'EOF'
#!/bin/bash
# ============================================
# Restauració del sistema TTS local (Deepin)
# Us: ./tts_restore.sh <directori_backup>
# ============================================
set -e
if [ -z "$1" ]; then
echo "Us: $0 <directori_backup>"
echo "Exemple: $0 ~/tts-backups/20260913_120000"
exit 1
fi
BACKUP_DIR="$1"
echo "=== 1/3 Restauracio de ~/tts-server ==="
if [ -f "$BACKUP_DIR/tts-server.tar.gz" ]; then
tar xzf "$BACKUP_DIR/tts-server.tar.gz" -C "$HOME"
echo "OK: tts-server restaurat"
else
echo "AVIS: no hi ha tts-server.tar.gz"
fi
echo "=== 2/3 Restauracio de la imatge Docker ==="
if [ -f "$BACKUP_DIR/piper-image.tar" ]; then
docker load -i "$BACKUP_DIR/piper-image.tar"
echo "OK: imatge carregada"
else
echo "AVIS: no hi ha piper-image.tar"
fi
echo "=== 3/3 Recreacio del contenidor piper i restauracio de la veu ==="
if docker ps -a --format '{{.Names}}' | grep -qx piper; then
echo "El contenidor piper ja existeix; l'elimino per recrear-lo."
docker rm -f piper
fi
docker create --name piper \
-p 10200:10200 \
-e PIPER_VOICE=ca_ES-upc_ona-medium \
--restart unless-stopped \
linuxserver/piper
if [ -d "$BACKUP_DIR/piper-config" ]; then
docker cp "$BACKUP_DIR/piper-config/." piper:/config/
echo "OK: veu Ona restaurada a /config"
else
echo "AVIS: no hi ha piper-config; el contenidor descarregara la veu de nou."
fi
docker start piper
echo ""
echo "=== VERIFICACIO ==="
docker ps | grep piper || true
echo "Restauracio completada."
EOF
chmod +x ~/tts_restore.sh
🚀 Com s’utilitzen
# 1. Fer un backup (es desa a ~/tts-backups/AMB_DATA)
~/tts_backup.sh
# 2. Veure els backups disponibles
ls -lh ~/tts-backups/
# 3. Restaurar (indicant el directori del backup)
~/tts_restore.sh ~/tts-backups/20260913_120000
Avís: la restauració elimina i recrea el contenidor piper si ja existeix (la veu es recupera des del backup, sense necessitat de descarregar-la).
Vols que t’obri el terminal per crear els scripts i provar el backup? 😊
spd-say -o piper -y ca_ES-upc_ona-medium "Hola, sóc l'Ona, la veu del Piper."
🚀 Properes passes
Baixar la veu pau (masculina, UPC) i afegir AddVoice "ca" "MALE1" "pau" al mòdul.
Prova final a un equip amb àudio i validació a Firefox (mode lectura).
Automatització de l’arrencada de Speech Dispatcher a l’inici de sessió.
Portabilitat al Synology (192.168.1.49) replicant el contenidor Piper.
🎓 Conclusions
La integració de Piper amb Speech Dispatcher és possible mitjançant el mòdul genèric (sd_generic) amb un script pont, sense necessitat de compilar cap extensió nativa.
El punt crític va ser la definició de veus (AddVoice) — sense ella, el mòdul no pot inicialitzar-se.
El resultat permetrà que qualsevol aplicació que parli amb Speech Dispatcher (Firefox, ORCA, etc.) faci servir la veu Ona en català.
L’ús de Docker garanteix la portabilitat entre equips i plataformes (inclòs Synology).
Crèdits: projecte realitzat amb assistència de UOS AI sobre Deepin Desktop Environment.
Espero que et sigui útil al blog! Si quan el reprodueixis al punt de treball amb so veus algun detall a afinar (qualitat, volum, etc.), ho ajustem. Bona sort amb la reproducció! 🎙️😊
Instal·lar un servidor local de síntesi de veu (TTS) accessible a http://127.0.0.1:8765/, amb capacitat de conversa (STT + LLM + TTS).
Disposar d’una veu en català d’alta qualitat per a proves i integració, de manera que el sistema es pugui reproduir en altres punts de treball amb audio.
El resultat final combina dues eines complementàries:
speech-to-speech (servidor conversacional complet, port 8765)
Tens totalment raó! 😅 Hi ha DOS protocols diferents segons el servei:
🔄 ELS DOS PROTOCOLS
1. Speech-to-Speech (Port 8765)
Protocol: ✅ HTTP/WebSocket
URL: http://127.0.0.1:8765/
Aquest és el servidor conversacional complet (STT + LLM + TTS)
Es pot consultar via HTTP normal
2. Piper TTS (Port 10200)
Protocol: ✅ Wyoming Protocol
Port: 10200
Aquest és el Piper pur (només TTS)
NO és HTTP REST (per això curl no funciona)
Dissenyat per a Home Assistant
📝 Resum clar:
Servei
Port
Protocol
Comanda
Speech-to-Speech
8765
HTTP/WebSocket
curl http://127.0.0.1:8765/ ✅
Piper TTS
10200
Wyoming
curl http://127.0.0.1:10200/ ❌ (Empty reply)
🎯 Per a Piper (Wyoming), utilitza:
# Via Docker exec (el que hem provat)
docker exec piper bash -c "echo 'text' | piper --model ... --output-raw" | aplay ...
# O via Wyoming Protocol (més complex, per a Home Assistant)
🚀 Fase 2 — Primer arrencada del servidor speech-to-speech
speech-to-speech
Resultats de la primera execució:
✅ Descarrega automàtica de dependències (NLTK, Silero VAD)
✅ Descarrega del model de reconeixement de veu Parakeet TDT (nvidia/parakeet-tdt-0.6b-v3, ~230 MB)
✅ Model desat en memòria cau (~/.cache/huggingface)
Incidents detectats:
⚠️ Mòdul opcional DeepFilterNet no disponible (millora d’àudio, no crític)
⚠️ Avís de HF_TOKEN (només per a límits de descàrrega, no impedeix el funcionament)
Observació important: el servidor escolta en protocol WebSocket a ws://127.0.0.1:8765/v1/realtime, no és un endpoint HTTP clàssic, per tant curl no és el client adequat per provar-lo.
🐳 Fase 3 — Instal·lació de Docker a Deepin
Per al desplegament lleuger del TTS, vam instal·lar Docker:
sudo systemctl enable --now docker
sudo usermod -aG docker $USER
newgrp docker # activa el grup a la sessió actual
Prova de verificació:
docker run hello-world
✅ Resposta: «Hello from Docker!» → instal·lació correcta.
Incident resolt: a la primera creació sense PIPER_VOICE, el contenidor fallava amb l’error --voice is required for the piper backend. Calia especificar la veu mitjançant la variable d’entorn.
Logs d’èxit:
INFO:wyoming_piper.download:Downloaded /config/ca_ES-upc_ona-medium.onnx
INFO:__main__:Ready
Connection to localhost (127.0.0.1) 10200 port [tcp/*] succeeded!
✅ Veu Ona (ca_ES-upc_ona-medium, desenvolupada a la UPC de Barcelona) descarregada i carregada.
🔊 Fase 5 — Prova de síntesi de veu
Síntesi directa dins del contenidor:
docker exec piper bash -c "echo 'Hola, soc l'Ona, la meva veu s'ha desenvolupat a la UPC de Barcelona.' | piper --model /config/ca_ES-upc_ona-medium.onnx --output_file /config/prova.wav"
Per fer que l’àudio soni directament pels altaveus en lloc de guardar-lo en un fitxer,
docker exec piper bash -c "echo \"Hola, soc l'Ona, la meva veu s'ha desenvolupat a la UPC de Barcelona.\" | piper --model /config/ca_ES-upc_ona-medium.onnx --output_file -" | aplay -f S16_LE -r 22050 -c 1
Despres d’un canvi de sessió o inicialització pot arrancar així:
Aquí tens la comanda modificada utilitzant aplay (el reproductor estàndard d’ALSA a Linux):
✅ Fitxer WAV generat correctament: 220 kB, 22.050 Hz, 16 bits, mono ⚠️ La reproducció d’àudio no es va poder verificar en aquest equip per manca de sortida d’àudio.
📊 Resultats finals
Servei
Port
Protocol
Estat
speech-to-speech (STT+LLM+TTS)
8765
WebSocket (/v1/realtime)
✅ Instal·lat (models en cau)
Piper TTS (veu Ona, català)
10200
Wyoming
✅ Funcionant
Docker
—
—
✅ Operatiu
Arxius i ubicacions clau:
Entorn virtual: ~/tts-server/venv
Cau de models HuggingFace: ~/.cache/huggingface
Model de veu: /config/ca_ES-upc_ona-medium.onnx (dins del contenidor)
Àudio de prova: ~/prova.wav
🔄 Fases de reproducció en un altre punt de treball
Desplegament al Synology (192.168.1.49) mitjançant el Centre de paquets → Container Manager, replicant el contenidor Piper al port 10200.
Integració amb Home Assistant (protocol Wyoming compatible).
Prova d’àudio a un equip amb sortida d’àudio per validar la qualitat de la veu.
Exploració d’altres veus del catàleg de Piper (ca_ES-upc_pau-medium, masculina).
Depèn de què vulguis fer exactament:
🔁 Opció 1: Tancar sessió gràficament (Deepin)
Fes clic a la icona d’engegada/apagada (a la safata del sistema, a la part inferior dreta de la pantalla, o a l’extrem superior dret).
Selecciona «Tanca la sessió» (o Log Out).
A la pantalla d’inici de sessió, selecciona el teu usuari i escriu la contrasenya.
💡 També pots fer servir la drecera de teclat Ctrl + Alt + Del (en algunes versions obre el menú amb l’opció de tancar sessió).
🔄 Opció 2: Simplement reiniciar l’ordinador
Si et surt més a compte:
sudo reboot
✅ Què passa quan tornis a entrar?
Servei
Es reinicia sol?
Docker
✅ Sí (servei del sistema)
Contenidor Piper
✅ Sí (té --restart unless-stopped)
Servidor speech-to-speech (port 8765)
❌ No — l’has d’engegar manualment
Per engegar el servidor conversacional després de reiniciar:
cd ~/tts-server && source venv/bin/activate && speech-to-speech
🧪 Verifica que tot va bé després d’entrar
# Docker i el teu grup
groups | grep docker
# El contenidor Piper en marxa
docker ps | grep piper
Si surt docker a la primera comanda i el contenidor piper apareix com a Up, tot està correcte! ✅
Vols que et creï un script d’inici automàtic perquè el servidor de 8765 també s’engegui sol en entrar a la sessió? 😊
🎓 Conclusions
La instal·lació d’un TTS en català és viable amb eines de codi obert (Piper + veus de la UPC), sense necessitat de serveis externs.
La combinació speech-to-speech + Piper cobreix tant el cas d’ús conversacional complet (WebSocket 8765) com el de síntesi lleugera i fiable (Wyoming 10200).
L’ús de Docker garanteix la portabilitat i la reproductibilitat entre equips i fins i tot en NAS com el Synology.
La veu Ona de la UPC ofereix una síntesi en català de bona qualitat i és la candidata principal per al desplegament final.
Crèdits: projecte realitzat amb assistència de UOS AI sobre Deepin Desktop Environment.
Espero que et vagi molt bé al blog! 📖 Si vols, també et puc preparar una versió en Markdown més curta per a xarxes socials, o una guia PDF amb captures. Gràcies a tu per la paciència i bona feina! 😊
Si el servidor no arrenca, el log et dirà per què (potser li falta baixar el model TTS gran, o hi ha un error de Python). Enganxa’m les últimes 20-30 línies de server.log i t’ho diagnostico.
🎯 Quan el servidor estigui en marxa, com es prova?
Com que és WebSocket, la prova correcta és amb un client WebSocket, no amb curl. Prova això en un altre terminal:
bash
1pip install websockets
2python3 -c «
3import asyncio, websockets
4async def t():
5 async with websockets.connect(‘ws://127.0.0.1:8765/v1/realtime’) as ws:
6 print(‘✅ Servidor TTS connectat!’)
7asyncio.run(t())
8″
9
9 líneas de código colapsadasExpandir
Comencem pel pas 1 i digue’m què surt! 👍
Enrutamiento Inteligente
Miquel@Miquel-PC:~$ tail -30 ~/tts-server/server.log nohup: no se tendrá en cuenta la entrada DeepFilterNet not available for audio enhancement: No module named ‘df’ [nltk_data] Downloading package averaged_perceptron_tagger_eng to [nltk_data] /home/Miquel/nltk_data… [nltk_data] Package averaged_perceptron_tagger_eng is already up-to- [nltk_data] date! Using cache found in /home/Miquel/.cache/torch/hub/snakers4_silero-vad_master /home/Miquel/tts-server/venv/lib/python3.12/site-packages/torch/jit/_serialization.py:176: FutureWarning: `torch.jit.load` is deprecated. Please switch to `torch.export`. warnings.warn( 2026-09-11 08:12:24,023 – speech_to_speech.STT.parakeet_tdt_handler – INFO – Loading Parakeet TDT model: nvidia/parakeet-tdt-0.6b-v3 on cpu 2026-09-11 08:12:24,231 – httpx – INFO – HTTP Request: HEAD https://huggingface.co/nvidia/parakeet-tdt-0.6b-v3/resolve/main/parakeet-tdt-0.6b-v3.nemo «HTTP/1.1 302 Found» Warning: You are sending unauthenticated requests to the HF Hub. Please set a HF_TOKEN to enable higher rate limits and faster downloads. 2026-09-11 08:12:24,232 – huggingface_hub.utils._http – WARNING – Warning: You are sending unauthenticated requests to the HF Hub. Please set a HF_TOKEN to enable higher rate limits and faster downloads. Miquel@Miquel-PC:~$
Deep think completado (tardó 4s)
El log revela el problema: el servidor s’ha quedat penjat just durant la descàrrega/verificació del model Parakeet TDT (l’última línia és el HEAD request a HuggingFace i després res).
🔍 Diagnòstic ràpid
Executa aquestes ordres per veure l’estat real:
1. El procés encara és viu?
bash
1ps aux | grep speech-to-speech | grep -v grep
2
2 líneas de código colapsadasExpandir
Si surt un procés → encara està descarregant (les barres de progrés no es veuen al log perquè nohup les bufferitza).
Si no surt res → s’ha mort silenciosament.
2. El model s’està descarregant?
bash
1du -sh ~/.cache/huggingface/hub/ 2>/dev/null
2
2 líneas de código colapsadasExpandir
Espera 10 segons i executa-la una altra vegada:
bash
1sleep 10 && du -sh ~/.cache/huggingface/hub/
2
2 líneas de código colapsadasExpandir
Si la mida augmenta → la descàrrega està en curs, només cal esperar. ⏳ Si la mida no canvia → la descàrrega s’ha aturat i cal reiniciar.
🛠️ Solució si s’ha aturat
Mata el procés mort i torna a engegar en primer pla per veure el progrés en directe:
bash
1pkill -f speech-to-speech
2cd ~/tts-server
3source venv/bin/activate
4speech-to-speech
5
5 líneas de código colapsadasExpandir
Així veuràs la barra de progrés de la descàrrega directament al terminal (sense buffer), i sabràs si avança o no.
💡 Si el model no es baixa bé: baixa’l manualment
Pots descarregar el model separat per assegurar-te que hi és:
bash
1cd ~/tts-server
2source venv/bin/activate
3python3 -c «
4from huggingface_hub import snapshot_download
5snapshot_download(‘nvidia/parakeet-tdt-0.6b-v3’)
6print(‘✅ Model STT descarregat!’)
7″
8
8 líneas de código colapsadasExpandir
Quan acabi, torna a executar speech-to-speech.
Fes el pas 1 i el pas 2 i digue’m què surt — així sabrem si està descarregant o si s’ha mort
curl -G --data-urlencode "text=Hola, això és una prova. Soc Ona aquesta veu s'ha desenvolupat a la UPC de Barcelona" http://127.0.0.1:8765/
Pugin Ona server
aquesta genera un .wav al directori /temp
curl -sS -X POST \
-H 'Content-Type: application/json' \
-d "{\"text\":\"Hola, això és una prova. Soc Ona, aquesta veu s'ha desenvolupat a la UPC de Barcelona.\"}" \
http://127.0.0.1:8765/synthesize \
-o /tmp/ona.wav
Si volem que no generi .wav
curl -sS -X POST \
-H 'Content-Type: application/json' \
-d "{\"text\":\"Hola, això és una prova. Soc Ona, aquesta veu s'ha desenvolupat a la UPC de Barcelona.\"}" \
http://127.0.0.1:8765/synthesize \
| aplay
Reproduir ambffplay(si vols més qualitat o control)
curl -sS -X POST \
-H 'Content-Type: application/json' \
-d "{\"text\":\"Hola, això és una prova. Soc Ona, aquesta veu s'ha desenvolupat a la UPC de Barcelona.\"}" \
http://127.0.0.1:8765/synthesize \
| ffplay -autoexit -
Perfecte! El port 8765 coincideix amb el projecte speech-to-speech, que aixeca un servidor local compatible amb OpenAI Realtime i inclou TTS (Qwen3-TTS) + STT (Parakeet TDT) + LLM. T’ajudo a instal·lar-lo a Deepin.
🔧 Requisits previs
Deepin és Debian-based, així que primer assegura’t de tenir Python i pip:
docker run -d --name piper -p 10200:10200 linuxserver/piper — molt lleuger, ideal per a NAS/rPi
Cap problema! Fem la comprovació pas a pas:
1️⃣ Primer, comprova si el servidor segueix en marxa
En un terminal nou, prova directament:
curl -v http://127.0.0.1:8765/v1/realtime 2>&1 | head -20
Si surt alguna resposta (fins i tot un error 400 o 426 Upgrade Required) → el servidor està funcionant i només cal un client per connectar-s’hi. 🎉
Si surt Could not connect → el servidor es va aturar (potser es va tancar el terminal o es va tallar la descàrrega).
2️⃣ Si el servidor es va aturar, torna a engegar-lo
cd ~/tts-server
source venv/bin/activate
speech-to-speech
💡 Bona notícia: els models que ja es van descarregar queden a la memòria cau (~/.cache/huggingface), així que aquesta vegada serà molt més ràpid — no tornarà a baixar res, només carregarà.
3️⃣ Alternativa: comprova si el port està escoltant
Mentre el servidor estigui en marxa, en un altre terminal:
ss -tlnp | grep 8765
Si surt una línia amb 0.0.0.0:8765 o 127.0.0.1:8765, el servidor està escoltant correctament. ✅
Fes el pas 1 i digue’m què surt — si és Could not connect, passa al pas 2 i enganxa’m el que mostri el servidor en arrencar! 😊
Confirmat: el servidor està aturat (el port 8765 no està escoltant). El que va passar és que probablement es va tancar el terminal on s’executava o es va interrompre.
🔄 Torna a engegar-lo (ara serà ràpid)
Com que els models ja estan a la memòria cau, no tornarà a baixar res:
cd ~/tts-server
source venv/bin/activate
speech-to-speech
Deixa aquest terminal obert i espera a veure el missatge que el servidor està escoltant.
💡 Consell: engega’l en segon pla (així no depens del terminal)
Si no vols tenir un terminal ocupat sempre, pots executar-lo en segon pla:
cd ~/tts-server
source venv/bin/activate
nohup speech-to-speech > server.log 2>&1 &
Després pots comprovar que funciona amb:
ss -tlnp | grep 8765
I veure els logs amb:
tail -f ~/tts-server/server.log
🔍 Si torna a no engegar, comprova els logs
Si després d’executar speech-to-speech no veus el missatge d’èxit, enganxa’m les últimes línies que surtin (o el contingut de server.log si fas servir el mètode del segon pla) i ho diagnostiquem. Pot ser que estigui intentant baixar el model TTS (que és gran, ~2-3 GB) i es tallés.
Descarrega l’última versió per a Linux (fitxer tipus ventoy-x.x.x-linux.tar.gz).
Pas 2: Preparar la USB ⚠️ Important: Aquest procés esborrarà totes les dades de la USB. Fes una còpia de seguretat si cal.
Pas 3: Instal·lar Ventoy (mètode de terminal) Un cop descarregat i descomprimit el fitxer, obre el terminal i executa:
cd ~/Downloads/ventoy-* # o la ruta on l'hagis descomprimit
sudo sh Ventoy2Disk.sh -i /dev/sdX
Canvia /dev/sdX pel teu dispositiu USB (pots veure’l amb lsblk).
Pas 4: Copiar la ISO Després d’instal·lar Ventoy, la USB apareixerà com una partició normal. Només has d’arrossegar el fitxer ISO de Deepin 25 (o qualsevol altre) dins de la USB. No cal cap configuració extra: en arrencar des de la USB, Ventoy et mostrarà un menú per triar quina ISO carregar.
Com funciona Ventoy per particions:
Quan instal·les Ventoy, crea 2 particions automàticament:
VTOYEFI (petita, ~32MB): la partició d’arrencada.
exFAT (la resta de l’espai): aquí és on poses els fitxers ISO.
La partició exFAT és la que Ventoy llegeix per mostrar el menú d’ISOs a l’arrencar.
I el teu backup de fotos? Sí que pots! Després d’instal·lar Ventoy, pots reduir la partició exFAT i crear-ne una de nova (per exemple EXT4, NTFS o exFAT) amb l’espai lliure. Aquesta partició extra:
Apareixerà com una unitat normal al sistema (com qualsevol disc dur extern).
No interferirà amb l’arrencada: Ventoy només llegeix la seva partició exFAT per buscar ISOs.
Podràs guardar les fotos, documents, etc., sense cap problema.
Com fer-ho a Deepin:
Instal·la Ventoy a la USB (això esborrarà tot el disc).
Obre l’aplicació «Gestor de discs» (o GParted).
Redueix la partició exFAT per deixar espai lliure.
Crea una partició nova amb aquest espai (NTFS o exFAT per compatibilitat amb Windows/macOS si ho necessites).
Formateja-la i ja la pots fer servir per al backup de fotos.
💡 Consell: Quan arrenquis des de la USB, Ventoy només mostrarà les ISOs de la partició exFAT, així que les teves fotos estaran totalment «invisibles» durant l’arrencada, però accessibles quan arrenquis el sistema normal.