Spaces:
Running
Running
Vedika commited on
Update app.py
Browse files
app.py
CHANGED
|
@@ -2,15 +2,13 @@ import os
|
|
| 2 |
import requests
|
| 3 |
import json
|
| 4 |
import re
|
| 5 |
-
import tempfile
|
| 6 |
import io
|
| 7 |
import numpy as np
|
| 8 |
from datetime import datetime, timedelta, timezone
|
| 9 |
from bs4 import BeautifulSoup
|
| 10 |
-
from flask import Flask, request, Response, stream_with_context, render_template_string
|
| 11 |
from supertonic import TTS
|
| 12 |
from pydub import AudioSegment
|
| 13 |
-
from scipy.io import wavfile
|
| 14 |
|
| 15 |
app = Flask(__name__)
|
| 16 |
|
|
@@ -19,7 +17,6 @@ app = Flask(__name__)
|
|
| 19 |
# ----------------------------------------------------
|
| 20 |
print("Loading Supertonic TTS Model...")
|
| 21 |
try:
|
| 22 |
-
# This runs on CPU by default via ONNX
|
| 23 |
tts = TTS(auto_download=True)
|
| 24 |
print("β
TTS Model loaded successfully!")
|
| 25 |
except Exception as e:
|
|
@@ -314,7 +311,7 @@ STRICT DIRECTIVES:
|
|
| 314 |
|
| 315 |
|
| 316 |
# ----------------------------------------------------
|
| 317 |
-
# ποΈ TTS DIRECT API ENDPOINT (
|
| 318 |
# ----------------------------------------------------
|
| 319 |
@app.route('/api/tts', methods=['POST'])
|
| 320 |
def generate_tts():
|
|
@@ -329,7 +326,7 @@ def generate_tts():
|
|
| 329 |
if not text.strip():
|
| 330 |
return Response(json.dumps({"error": "Text is empty."}), status=400, mimetype='application/json')
|
| 331 |
|
| 332 |
-
# Text cleaning:
|
| 333 |
clean_text = re.sub(r'[^\w\s.,!?\'\"\-\<\>\:\u0900-\u097F]', '', text, flags=re.UNICODE)
|
| 334 |
|
| 335 |
if not clean_text.strip():
|
|
@@ -338,37 +335,38 @@ def generate_tts():
|
|
| 338 |
try:
|
| 339 |
lang_code = LANGUAGES.get(language_name, "en")
|
| 340 |
|
| 341 |
-
# π
|
| 342 |
if voice not in VOICE_STYLES_CACHE:
|
| 343 |
VOICE_STYLES_CACHE[voice] = tts.get_voice_style(voice_name=voice)
|
| 344 |
style = VOICE_STYLES_CACHE[voice]
|
| 345 |
|
| 346 |
-
# Synthesize audio
|
| 347 |
wav, duration = tts.synthesize(clean_text, voice_style=style, lang=lang_code)
|
| 348 |
|
| 349 |
-
#
|
| 350 |
-
buffer = io.BytesIO()
|
| 351 |
-
sample_rate = 22050
|
| 352 |
-
|
| 353 |
if wav.dtype != np.int16:
|
| 354 |
max_val = np.max(np.abs(wav))
|
| 355 |
if max_val > 0:
|
| 356 |
wav_int16 = np.int16(wav / max_val * 32767)
|
| 357 |
else:
|
| 358 |
wav_int16 = wav.astype(np.int16)
|
| 359 |
-
wavfile.write(buffer, sample_rate, wav_int16)
|
| 360 |
else:
|
| 361 |
-
|
| 362 |
-
|
| 363 |
-
|
| 364 |
-
|
| 365 |
-
|
| 366 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 367 |
mp3_buffer = io.BytesIO()
|
| 368 |
-
audio_segment.export(mp3_buffer, format="mp3", bitrate="128k", parameters=["-ar",
|
| 369 |
mp3_buffer.seek(0)
|
| 370 |
-
|
| 371 |
-
# Return the actual audio file
|
| 372 |
return Response(mp3_buffer.read(), mimetype="audio/mpeg")
|
| 373 |
|
| 374 |
except Exception as e:
|
|
@@ -376,5 +374,4 @@ def generate_tts():
|
|
| 376 |
|
| 377 |
|
| 378 |
if __name__ == '__main__':
|
| 379 |
-
# Flask App Run
|
| 380 |
app.run(host='0.0.0.0', port=7860)
|
|
|
|
| 2 |
import requests
|
| 3 |
import json
|
| 4 |
import re
|
|
|
|
| 5 |
import io
|
| 6 |
import numpy as np
|
| 7 |
from datetime import datetime, timedelta, timezone
|
| 8 |
from bs4 import BeautifulSoup
|
| 9 |
+
from flask import Flask, request, Response, stream_with_context, render_template_string
|
| 10 |
from supertonic import TTS
|
| 11 |
from pydub import AudioSegment
|
|
|
|
| 12 |
|
| 13 |
app = Flask(__name__)
|
| 14 |
|
|
|
|
| 17 |
# ----------------------------------------------------
|
| 18 |
print("Loading Supertonic TTS Model...")
|
| 19 |
try:
|
|
|
|
| 20 |
tts = TTS(auto_download=True)
|
| 21 |
print("β
TTS Model loaded successfully!")
|
| 22 |
except Exception as e:
|
|
|
|
| 311 |
|
| 312 |
|
| 313 |
# ----------------------------------------------------
|
| 314 |
+
# ποΈ TTS DIRECT API ENDPOINT (OPTIMIZED)
|
| 315 |
# ----------------------------------------------------
|
| 316 |
@app.route('/api/tts', methods=['POST'])
|
| 317 |
def generate_tts():
|
|
|
|
| 326 |
if not text.strip():
|
| 327 |
return Response(json.dumps({"error": "Text is empty."}), status=400, mimetype='application/json')
|
| 328 |
|
| 329 |
+
# Text cleaning: allow Hindi Devanagari script safely
|
| 330 |
clean_text = re.sub(r'[^\w\s.,!?\'\"\-\<\>\:\u0900-\u097F]', '', text, flags=re.UNICODE)
|
| 331 |
|
| 332 |
if not clean_text.strip():
|
|
|
|
| 335 |
try:
|
| 336 |
lang_code = LANGUAGES.get(language_name, "en")
|
| 337 |
|
| 338 |
+
# π Use cached voice style
|
| 339 |
if voice not in VOICE_STYLES_CACHE:
|
| 340 |
VOICE_STYLES_CACHE[voice] = tts.get_voice_style(voice_name=voice)
|
| 341 |
style = VOICE_STYLES_CACHE[voice]
|
| 342 |
|
| 343 |
+
# Synthesize audio (returns numpy array)
|
| 344 |
wav, duration = tts.synthesize(clean_text, voice_style=style, lang=lang_code)
|
| 345 |
|
| 346 |
+
# Convert to 16-bit PCM if needed
|
|
|
|
|
|
|
|
|
|
| 347 |
if wav.dtype != np.int16:
|
| 348 |
max_val = np.max(np.abs(wav))
|
| 349 |
if max_val > 0:
|
| 350 |
wav_int16 = np.int16(wav / max_val * 32767)
|
| 351 |
else:
|
| 352 |
wav_int16 = wav.astype(np.int16)
|
|
|
|
| 353 |
else:
|
| 354 |
+
wav_int16 = wav
|
| 355 |
+
|
| 356 |
+
sample_rate = 22050
|
| 357 |
+
# Create AudioSegment directly from raw bytes (mono, 16βbit PCM)
|
| 358 |
+
audio_segment = AudioSegment(
|
| 359 |
+
wav_int16.tobytes(),
|
| 360 |
+
frame_rate=sample_rate,
|
| 361 |
+
sample_width=2, # 2 bytes = 16 bit
|
| 362 |
+
channels=1
|
| 363 |
+
)
|
| 364 |
+
|
| 365 |
+
# Export to MP3 in memory
|
| 366 |
mp3_buffer = io.BytesIO()
|
| 367 |
+
audio_segment.export(mp3_buffer, format="mp3", bitrate="128k", parameters=["-ar", str(sample_rate)])
|
| 368 |
mp3_buffer.seek(0)
|
| 369 |
+
|
|
|
|
| 370 |
return Response(mp3_buffer.read(), mimetype="audio/mpeg")
|
| 371 |
|
| 372 |
except Exception as e:
|
|
|
|
| 374 |
|
| 375 |
|
| 376 |
if __name__ == '__main__':
|
|
|
|
| 377 |
app.run(host='0.0.0.0', port=7860)
|