tts-api / app.py
matrixcoder's picture
Update app.py
c1f680b verified
Raw History Blame Contribute Delete
2.71 kB
"""
ESP32 TTS Server — Hugging Face Space
WAV output: 22050Hz, Mono, 8-bit unsigned
ESP32 DAC ke liye perfect — direct mapping, no conversion
"""
from flask import Flask, request, Response
import os
import io
import hashlib
from gtts import gTTS
from pydub import AudioSegment
from pydub.effects import normalize
app = Flask(__name__)
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
CACHE_DIR = os.path.join(BASE_DIR, "tts_cache")
os.makedirs(CACHE_DIR, exist_ok=True)
def text_to_wav_bytes(text, lang):
# Step 1: gTTS → MP3 in memory
mp3_buf = io.BytesIO()
tts = gTTS(text, lang=lang)
tts.write_to_fp(mp3_buf)
mp3_buf.seek(0)
# Step 2: Load audio
audio = AudioSegment.from_file(mp3_buf, format="mp3")
# Step 3: Normalize — consistent volume
audio = normalize(audio)
# Step 4: Convert — 22050Hz, Mono, 8-bit unsigned
# ESP32 DAC = 8-bit (0-255), 22050Hz enough for clear voice
audio = audio.set_frame_rate(22050)
audio = audio.set_channels(1)
audio = audio.set_sample_width(1) # 8-bit unsigned (0-255)
# Step 5: WAV bytes
wav_buf = io.BytesIO()
audio.export(wav_buf, format="wav")
wav_buf.seek(0)
return wav_buf.read()
def get_wav(text, lang):
key = hashlib.md5((text + lang).encode()).hexdigest()
cache_path = os.path.join(CACHE_DIR, key + ".wav")
if os.path.exists(cache_path):
print(f'[Cache HIT] "{text}"')
with open(cache_path, "rb") as f:
return f.read()
print(f'[Generating] "{text}" | {lang}')
wav_data = text_to_wav_bytes(text, lang)
with open(cache_path, "wb") as f:
f.write(wav_data)
return wav_data
@app.route("/tts", methods=["GET"])
def tts_get():
text = request.args.get("text", "Hello").replace("+", " ")
lang = request.args.get("lang", "en")
try:
wav_data = get_wav(text, lang)
except Exception as e:
print(f"[ERROR] {e}")
return f"Error: {e}", 500
return Response(wav_data, mimetype="audio/wav",
headers={"Content-Length": str(len(wav_data))})
@app.route("/tts", methods=["POST"])
def tts_post():
data = request.get_json(silent=True) or {}
text = data.get("text", "Hello")
lang = data.get("lang", "en")
try:
wav_data = get_wav(text, lang)
except Exception as e:
print(f"[ERROR] {e}")
return f"Error: {e}", 500
return Response(wav_data, mimetype="audio/wav",
headers={"Content-Length": str(len(wav_data))})
@app.route("/ping")
def ping():
return {"status": "ok", "server": "ESP32 TTS Server"}
if __name__ == "__main__":
app.run(host="0.0.0.0", port=7860, debug=False)