get-docs-talk / app.py
IsraaMShamkh's picture
Add Bark TTS service for Ebonex storytelling
62d8f5f
Raw History Blame Contribute Delete
2.56 kB
"""
Bark TTS microservice for Ebonex AI — Hugging Face Spaces deployment.
Bark (by Suno) generates highly expressive, emotional audio from text.
It supports laughter, breathing, whispering, and dramatic storytelling —
perfect for the Ebonex Kids Mode.
Arabic voice presets: v2/ar_speaker_0 through v2/ar_speaker_9
English voice presets: v2/en_speaker_0 through v2/en_speaker_9
Recommended for storytelling:
Arabic: v2/ar_speaker_9 (warm, expressive narrator)
English: v2/en_speaker_6 (clear, warm storyteller)
"""
import base64
import io
import os
import numpy as np
import soundfile as sf
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from bark import SAMPLE_RATE, generate_audio, preload_models
# Pre-load models on startup (takes ~30s, only once)
# Set SUNO_USE_SMALL_MODELS=True for faster but lower-quality output on CPU
use_small = os.environ.get("SUNO_USE_SMALL_MODELS", "True").lower() == "true"
preload_models(
text_use_small=use_small,
coarse_use_small=use_small,
fine_use_small=use_small,
)
app = FastAPI(
title="Bark TTS for Ebonex",
description="Storytelling TTS powered by Suno Bark",
version="1.0.0",
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["POST", "GET"],
allow_headers=["*"],
)
class TtsRequest(BaseModel):
text: str
voice_preset: str = "v2/ar_speaker_9"
@app.get("/")
def root():
return {"status": "ok", "service": "Bark TTS for Ebonex"}
@app.get("/health")
def health():
return {"status": "ok"}
@app.post("/tts")
def text_to_speech(req: TtsRequest):
if not req.text or not req.text.strip():
raise HTTPException(status_code=400, detail="text is required")
# Bark works best with texts under 400 characters.
# For longer texts, split and concatenate (handled by TtsService on Node side).
text = req.text.strip()[:400]
try:
audio_array = generate_audio(text, history_prompt=req.voice_preset)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Bark generation failed: {str(e)}")
# Convert numpy float32 array → WAV bytes → base64 string
buffer = io.BytesIO()
sf.write(buffer, audio_array, SAMPLE_RATE, format="WAV", subtype="PCM_16")
buffer.seek(0)
audio_b64 = base64.b64encode(buffer.read()).decode("utf-8")
return {
"audio": audio_b64,
"sample_rate": SAMPLE_RATE,
"format": "wav",
"voice_preset": req.voice_preset,
}