Muntatge d’un servidor TTS local amb veu catalana (Ona, UPC) a Deepin proposat per Qween

Perfecte! Aquí tens el text complet i millorat del teu blog, llest per copiar i enganxar:


# ⭐⭐⭐ Muntatge d'un servidor TTS local amb veu catalana (Ona, UPC) a Deepin

## 🎯 Objectius

L'objectiu del projecte és doble:

1. **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).
2. **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 àudio.

El resultat final combina dues eines complementàries:

- **`speech-to-speech`** (servidor conversacional complet, port 8765)
- **Piper TTS** amb la veu **Ona de la UPC** (port 10200)

---

## 🔄 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
- Endpoint WebSocket: `ws://127.0.0.1:8765/v1/realtime`

---

### 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 http://127.0.0.1:10200/` retorna "Empty reply from server")
- Dissenyat per a **Home Assistant**

---

### 📋 Resum clar:

| Servei | Port | Protocol | Comanda de prova |
|--------|------|----------|------------------|
| **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) |

---

## 📦 Fase 1 — Preparació de l'entorn

**Sistema:** Deepin (basat en Debian)

```bash
sudo apt update
sudo apt install python3 python3-pip python3-venv git docker.io -y

Creació de l’entorn virtual i instal·lació del paquet conversacional:

mkdir -p ~/tts-server && cd ~/tts-server
python3 -m venv venv
source venv/bin/activate
pip install --upgrade pip
pip install speech-to-speech

🚀 Fase 2 — Primera arrencada del servidor speech-to-speech

speech-to-speech

Resultats de la primera execució:

  • ✅ Descàrrega automàtica de dependències (NLTK, Silero VAD)
  • ✅ Descàrrega del model de reconeixement de veu Parakeet TDT (nvidia/parakeet-tdt-0.6b-v3, ~230 MB)
  • ✅ Model desat en memòria cau (~/.cache/huggingface)

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.


🗣️ Fase 4 — Piper TTS amb veu catalana (Ona, UPC)

Creació del contenidor amb la veu catalana:

docker run -d \
  --name piper \
  -p 10200:10200 \
  -e PIPER_VOICE=ca_ES-upc_ona-medium \
  --restart unless-stopped \
  linuxserver/piper

💡 Pro Tip: La imatge linuxserver/piper admet la variable d’entorn PIPER_VOICE. Si s’especifica (ex: ca_ES-upc_ona-medium), el contenidor descarrega i configura el model automàticament en arrencar, estalviant-nos haver de baixar el fitxer .onnx manualment.

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

Opció A: Guardar com a fitxer WAV

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"

Extracció i reproducció:

docker cp piper:/config/prova.wav ~/prova.wav
aplay ~/prova.wav

Opció B: Streaming directe als altaveus (recomanada)

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-raw" | aplay -f S16_LE -r 22050 -c 1

⚠️ Important: Utilitza --output-raw (no --output_file -) quan facis pipe directe a aplay.

  • --output-raw: Genera àudio RAW sense capçalera → compatible amb aplay -f S16_LE -r 22050 -c 1
  • --output_file -: Genera WAV complet → només per guardar a fitxer

Explicació dels paràmetres d’aplay:

  • -f S16_LE: Format Signed 16-bit Little Endian
  • -r 22050: Sample rate 22050 Hz
  • -c 1: Mono (1 canal)

🐍 Fase 6 — Integració amb Python (Flask)

Per enviar text al Piper directament des d’un script de Python (com un servidor Flask), podem cridar la comanda de Docker mitjançant la llibreria subprocess:

import subprocess

def reproduir_text_en_catala(text):
    """
    Reprodueix un text en català utilitzant la veu Ona de la UPC
    mitjançant el contenidor Docker Piper.
    """
    # Escapar cometes simples per evitar errors de bash
    text_net = text.replace("'", "\\'")
    
    comanda = f"""
    docker exec piper bash -c "echo '{text_net}' | piper --model /config/ca_ES-upc_ona-medium.onnx --output-raw" | aplay -f S16_LE -r 22050 -c 1
    """
    
    print(f"🔊 Reproduint: {text}")
    subprocess.run(comanda, shell=True)

# Prova
reproduir_text_en_catala("Hola, això és una prova des de Python.")

Exemple complet amb Flask:

from flask import Flask, request, render_template_string
import subprocess

app = Flask(__name__)

def reproduir_text(text, desti='ona'):
    """Reprodueix el text segons el destinatari"""
    if desti == 'ona':
        text_net = text.replace("'", "\\'")
        comanda = f"""
        docker exec piper bash -c "echo '{text_net}' | piper --model /config/ca_ES-upc_ona-medium.onnx --output-raw" | aplay -f S16_LE -r 22050 -c 1
        """
        subprocess.run(comanda, shell=True)

@app.route('/')
def index():
    return '''
    <!DOCTYPE html>
    <html>
    <head><title>Enviar text a l Ona</title></head>
    <body>
        <h1>Enviar text al servidor TTS</h1>
        <form action="/processa" method="POST">
            <label>Text:</label><br>
            <textarea name="text" rows="4" cols="50"></textarea><br><br>
            <input type="submit" value="Enviar i reproduir">
        </form>
    </body>
    </html>
    '''

@app.route('/processa', methods=['POST'])
def processa():
    missatge = request.form.get('text', '')
    reproduir_text(missatge, 'ona')
    
    return f'''
    <!DOCTYPE html>
    <html>
    <head><title>Missatge rebut</title></head>
    <body>
        <h1>Missatge rebut:</h1>
        <p><strong>Text:</strong> {missatge}</p>
        <p>🔊 S ha reproduït amb la veu Ona</p>
        <a href="/">Tornar a enviar</a>
    </body>
    </html>
    '''

if __name__ == '__main__':
    app.run(debug=True, host='127.0.0.1', port=5000)

📊 Resultats finals

ServeiPortProtocolEstat
speech-to-speech (STT+LLM+TTS)8765WebSocket (/v1/realtime)✅ Instal·lat (models en cau)
Piper TTS (veu Ona, català)10200Wyoming✅ Funcionant
Docker✅ Operatiu

Verificació final

# Docker i el teu grup
groups | grep docker

# El contenidor Piper en marxa
docker ps | grep piper

# Provar connexió al port Wyoming
nc -zv 127.0.0.1 10200

Si surt docker a la primera comanda i el contenidor piper apareix com a Up, tot està correcte! ✅


🛠️ Solució de problemes comuns

Error: aplay: read_header:2973: read error

Causa: Estàs utilitzant --output_file - amb aplay -f S16_LE...
Solució: Canvia a --output-raw

Error: Empty reply from server amb curl

Causa: El port 10200 utilitza protocol Wyoming, no HTTP
Solució: Utilitza docker exec per accedir a Piper

Error: --voice is required for the piper backend

Causa: No s’ha especificat la variable PIPER_VOICE
Solució: Afegeix -e PIPER_VOICE=ca_ES-upc_ona-medium al docker run


🎓 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.
  • La integració amb Python/Flask permet automatitzar la reproducció de textos des d’aplicacions web personalitzades.

📚 Recursos addicionals


Autor: Miquel
Data: Setembre 2026
Sistema: Deepin (Debian-based)
Tags: TTS, Català, Docker, Piper, Voice Synthesis, Local AI

---

Aquest és el text **complet, corregit i millorat** amb:

✅ Correcció de `--output_file -` a `--output-raw`  
✅ Pro Tip sobre `PIPER_VOICE`  
✅ Explicació detallada dels errors comuns  
✅ Fase 6 amb integració Python/Flask completa  
✅ Taula de solució de problemes  
✅ Recursos addicionals  
✅ Format Markdown net i professional  

Llest per publicar! 🚀