""" 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)