Estr/00-sapi_tts/
├── exec_script_py.php ← Crida el Python
├── generar_tts.py ← Script Python que genera l'àudio
| des de Synology
├── index.php ← Interfície web
└── tts.mp3 ← Fitxer generatuctura
index.php
<?php
// Llista de veus
$voices = [
"Microsoft Helena Desktop",
"Microsoft Hazel Desktop",
"Microsoft Zira Desktop",
"Microsoft Hortense Desktop",
"Vocalizer Expressive Jordi Harpo 22kHz"
];
// Carrega valors antics per mantenir-los al formulari
$lastText = isset($_GET['text']) ? htmlspecialchars($_GET['text']) : '';
$lastVoice = isset($_GET['voice']) ? $_GET['voice'] : '';
?>
<!DOCTYPE html>
<html lang="ca">
<head>
<meta charset="UTF-8">
<title>Generador TTS</title>
</head>
<body>
<h1>Text-to-Speech (amb Python)</h1>
<form action="exec_script_py.php" method="POST">
<label for="text">Introdueix el text:</label><br>
<textarea name="text" id="text" rows="4" cols="50"><?= $lastText ?></textarea><br><br>
<label for="voice">Selecciona una veu:</label><br>
<select name="voice" id="voice">
<?php foreach ($voices as $voice): ?>
<option value="<?= htmlspecialchars($voice) ?>" <?= ($voice == $lastVoice ? 'selected' : '') ?>>
<?= htmlspecialchars($voice) ?>
</option>
<?php endforeach; ?>
</select><br><br>
<input type="submit" value="Generar àudio">
</form>
<?php if (isset($_GET['error'])): ?>
<p style="color:red;">❌ Error: <?= htmlspecialchars($_GET['error']) ?></p>
<?php endif; ?>
<?php if (file_exists("tts.mp3")): ?>
<h2>Resultat:</h2>
<audio controls>
<source src="tts.mp3?<?= time() ?>" type="audio/mpeg">
El teu navegador no suporta àudio.
</audio>
<?php endif; ?>
</body>
</html>
generar_tts.py
import sys
import os
# 🔧 Elimina rutes locals que poden interferir
sys.path = [p for p in sys.path if ".local" not in p and "urqtejmi" not in p]
print("🔍 sys.path netejat:")
for p in sys.path:
print(" -", p)
# 📦 Comprovació de la importació
try:
import gtts
print("📦 gtts importat des de:", getattr(gtts, '__file__', '❌ No definit'))
from gtts import gTTS
print("✅ gTTS importat correctament")
except Exception as e:
print("❌ Error important gTTS:", e)
raise
# 📄 Preparació del fitxer de sortida
base_dir = os.path.dirname(os.path.abspath(__file__))
output_path = os.path.join(base_dir, "tts.mp3")
# 📝 Recollir text i veu
text = sys.argv[1] if len(sys.argv) > 1 else "Text per defecte"
voice = sys.argv[2] if len(sys.argv) > 2 else "default"
print(f"▶ Text: {text}")
print(f"▶ Veu seleccionada: {voice} (no utilitzada per gTTS)")
print(f"▶ Fitxer a guardar: {output_path}")
# 🔊 Generar MP3
tts = gTTS(text=text, lang='ca')
tts.save(output_path)
exec_script_py.php
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$textRaw = $_POST['text'] ?? '';
$voiceRaw = $_POST['voice'] ?? '';
$text = escapeshellarg($textRaw);
$voice = escapeshellarg($voiceRaw);
// ✅ Ruta al Python de l'entorn virtual
$python = '/volume2/web/00-sapi_tts/venv/bin/python';
// ✅ Comanda per executar el script Python
$command = "$python generar_tts.py $text $voice 2>&1";
// 🔁 Executa el script i captura la sortida
$output = shell_exec($command);
echo "<pre>📤 Comanda executada:\n$command\n\n📄 Sortida:\n$output</pre>";
// ❌ Si no s'ha generat l'àudio, redirigeix amb error
if (!file_exists("tts.mp3")) {
$error = "No s'ha pogut generar l'àudio. Sortida: $output";
header("Location: index.php?error=" . urlencode($error) . "&text=" . urlencode($textRaw) . "&voice=" . urlencode($voiceRaw));
exit();
}
// ✅ Si tot ha anat bé, redirigeix amb els valors conservats
header("Location: index.php?text=" . urlencode($textRaw) . "&voice=" . urlencode($voiceRaw));
exit();
}
?>
🛠️ Historial de passos per solucionar l’error amb gtts
1. Diagnòstic inicial
- El teu script Python donava aquest error:
ImportError: cannot import name 'gTTS' from 'gtts' (unknown location)
- El mòdul
gtts
semblava instal·lat, perògtts.__file__
retornavaNone
.
2. Depuració del sistema
- Vam comprovar que hi havia múltiples versions de
gtts
instal·lades: - Una a
/usr/lib/python3.8/site-packages
✅ - Una altra a
~/.local/lib/python3.8/site-packages
❌ (interferia) - Vam eliminar la versió local conflictiva:
rm -rf ~/.local/lib/python3.8/site-packages/gtts
rm -rf ~/.local/lib/python3.8/site-packages/gTTS-*.dist-info
3. Reinstal·lació neta
- Vam reinstal·lar
gtts
globalment:
sudo /bin/python3 -m pip install --no-cache-dir gtts
- Tot i això, l’error persistia perquè el servidor web seguia usant el Python del sistema, amb rutes contaminades.
4. Creació d’un entorn virtual
- Vam crear un entorn virtual aïllat:
python3 -m virtualenv venv
source venv/bin/activate
pip install gtts
- Això va instal·lar
gtts
netament a:
/volume2/web/00-sapi_tts/venv/lib/python3.8/site-packages
5. Modificació del script PHP
- Vam modificar
exec_script_py.php
per cridar el Python del virtualenv:
$python = '/volume2/web/00-sapi_tts/venv/bin/python';
$command = "$python generar_tts.py $text $voice 2>&1";
- Això va assegurar que el servidor web executés el Python correcte, amb el mòdul
gtts
funcional.
6. Èxit final
- El fitxer
tts.mp3
es va generar correctament. - El reproductor d’àudio es va mostrar a la pàgina.
- El text “bona nit” es va convertir en veu 🎉
🔜 Què queda pendent?
- La veu no sona com la del “Jordi” de Vocalizer: això és perquè
gtts
fa servir la veu de Google Translate, no veus locals com Vocalizer. - Si vols fer servir veus com la del Jordi, caldrà integrar motors com:
- eSpeak NG
- Festival
- Vocalizer TTS (si tens llicència)
- Microsoft Azure, Google Cloud TTS, etc.
Vols que demà explorem com fer servir una veu real com la del Jordi amb un motor TTS local o en el núvol? O vols que et prepari una comparativa de motors TTS amb veus catalanes?