TTS / app.py
Techbitforge's picture
Update app.py
0b9014b verified
from flask import Flask, request, jsonify, send_file
import edge_tts
import asyncio
import tempfile
import os
app = Flask(__name__)
# ---------------------------
# Async helpers
# ---------------------------
async def get_voices_async():
voices = await edge_tts.list_voices()
return [
{
"short_name": v["ShortName"],
"locale": v["Locale"],
"gender": v["Gender"],
"display": f"{v['ShortName']} - {v['Locale']} ({v['Gender']})"
}
for v in voices
]
async def tts_async(text, voice, rate, pitch):
rate_str = f"{rate:+d}%"
pitch_str = f"{pitch:+d}Hz"
communicate = edge_tts.Communicate(
text=text,
voice=voice,
rate=rate_str,
pitch=pitch_str
)
tmp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".mp3")
tmp_path = tmp_file.name
tmp_file.close()
await communicate.save(tmp_path)
return tmp_path
# ---------------------------
# Routes
# ---------------------------
@app.route("/", methods=["GET"])
def hello():
return """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Edge TTS Voices</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #111;
color: #fff;
padding: 40px;
}
h1 {
text-align: center;
}
.stats {
display: flex;
justify-content: center;
gap: 40px;
margin-bottom: 30px;
}
.card {
background: #1e1e1e;
padding: 20px;
border-radius: 10px;
text-align: center;
min-width: 150px;
}
.male { border: 2px solid #3498db; }
.female { border: 2px solid #e91e63; }
.total { border: 2px solid #2ecc71; }
.voices-container {
display: flex;
gap: 40px;
}
.voices-list {
flex: 1;
background: #1a1a1a;
padding: 20px;
border-radius: 10px;
max-height: 500px;
overflow-y: auto;
}
.voice-item {
padding: 6px 0;
border-bottom: 1px solid #333;
font-size: 14px;
}
</style>
</head>
<body>
<h1>πŸŽ™ Edge TTS Voices</h1>
<div class="stats">
<div class="card total">
<h2 id="totalCount">0</h2>
<p>Total Voices</p>
</div>
<div class="card male">
<h2 id="maleCount">0</h2>
<p>Male Voices</p>
</div>
<div class="card female">
<h2 id="femaleCount">0</h2>
<p>Female Voices</p>
</div>
</div>
<div class="voices-container">
<div class="voices-list">
<h3>πŸ‘¨ Male Voices</h3>
<div id="maleVoices"></div>
</div>
<div class="voices-list">
<h3>πŸ‘© Female Voices</h3>
<div id="femaleVoices"></div>
</div>
</div>
<script>
async function loadVoices() {
try {
const response = await fetch("/voices");
const data = await response.json();
const maleVoices = data.Male.voices;
const femaleVoices = data.Female.voices;
const maleCount = data.Male.count;
const femaleCount = data.Female.count;
const total = maleCount + femaleCount;
document.getElementById("maleCount").innerText = maleCount;
document.getElementById("femaleCount").innerText = femaleCount;
document.getElementById("totalCount").innerText = total;
const maleContainer = document.getElementById("maleVoices");
const femaleContainer = document.getElementById("femaleVoices");
maleVoices.forEach(v => {
const div = document.createElement("div");
div.className = "voice-item";
div.innerText = v.short_name;
maleContainer.appendChild(div);
});
femaleVoices.forEach(v => {
const div = document.createElement("div");
div.className = "voice-item";
div.innerText = v.short_name;
femaleContainer.appendChild(div);
});
} catch (error) {
alert("Error loading voices: " + error);
}
}
loadVoices();
</script>
</body>
</html>
"""
@app.route("/voices", methods=["GET"])
def voices():
voices = asyncio.run(get_voices_async())
grouped = {
"Male": {
"count": 0,
"voices": []
},
"Female": {
"count": 0,
"voices": []
}
}
for v in voices:
gender = v["gender"].lower()
if gender == "male":
grouped["Male"]["voices"].append(v)
grouped["Male"]["count"] += 1
elif gender == "female":
grouped["Female"]["voices"].append(v)
grouped["Female"]["count"] += 1
return jsonify(grouped)
@app.route("/tts", methods=["POST"])
def tts():
data = request.json
text = data.get("text", "").strip()
voice = data.get("voice")
rate = int(data.get("rate", 0))
pitch = int(data.get("pitch", 0))
if not text:
return jsonify({"error": "Text is required"}), 400
if not voice:
return jsonify({"error": "Voice is required"}), 400
try:
audio_path = asyncio.run(tts_async(text, voice, rate, pitch))
return send_file(
audio_path,
mimetype="audio/mpeg",
as_attachment=True,
download_name="tts.mp3"
)
except Exception as e:
return jsonify({"error": str(e)}), 500
# ---------------------------
# Run server
# ---------------------------
if __name__ == "__main__":
app.run(
host="0.0.0.0",
port=7860,
debug=False
)