Spaces:
Runtime error
Runtime error
File size: 5,246 Bytes
39d46e1 5b0bfda be31ce6 39d46e1 5b0bfda 39d46e1 5b0bfda 39d46e1 3b10a63 39d46e1 f5e4024 39d46e1 f5e4024 39d46e1 c2e3966 5b0bfda 39d46e1 5b0bfda 39d46e1 5b0bfda 39d46e1 5b0bfda 39d46e1 5b0bfda 4902504 81ee5ca 39d46e1 be31ce6 39d46e1 3a1afda 39d46e1 be31ce6 39d46e1 be31ce6 5b0bfda 39d46e1 be31ce6 39d46e1 be31ce6 5b0bfda 39d46e1 5b0bfda 39d46e1 f4b5c65 5b0bfda 077e0e7 be31ce6 68958ab |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
from fastapi import FastAPI, HTTPException, BackgroundTasks
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse, JSONResponse
from pydantic import BaseModel
from typing import Optional, Dict, Any, List, Tuple
import time
import uvicorn
from datetime import datetime
import psutil
import asyncio
import edge_tts
from pydub import AudioSegment
import os
import uuid
import tempfile
from concurrent.futures import ThreadPoolExecutor
# Initialize FastAPI app
app = FastAPI(
title="TTS API Service",
description="Text-to-Speech API with real-time status monitoring",
version="1.0.0"
)
# Configure CORS
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Core functionality (moved from app.py)
class TTSError(Exception):
pass
class FileManager:
def __init__(self):
self.temp_dir = tempfile.mkdtemp(prefix="tts_api_")
self.output_files = []
def get_temp_path(self, prefix: str) -> str:
return os.path.join(self.temp_dir, f"{prefix}_{uuid.uuid4()}")
def cleanup_old_files(self):
for path in self.output_files[:-5]: # Keep only last 5 files
try:
if os.path.exists(path):
os.remove(path)
except Exception:
pass
self.output_files = self.output_files[-5:]
# Global state management
class ProcessingState:
def __init__(self):
self.active_jobs: Dict[str, Dict[str, Any]] = {}
self.file_manager = FileManager()
state = ProcessingState()
# Pydantic models
class TTSRequest(BaseModel):
text: str
voice: str = "en-US-JennyNeural"
pitch: int = 0
rate: int = 0
class HealthResponse(BaseModel):
status: str
timestamp: str
cpu_usage: float
memory_usage: float
active_jobs: int
# Voice options dictionary (simplified)
voice_options = {
"Jenny": "en-US-JennyNeural",
"Guy": "en-US-GuyNeural",
"Ana": "en-US-AnaNeural",
"Aria": "en-US-AriaNeural"
}
async def generate_tts(text: str, voice: str, rate: str, pitch: str) -> Tuple[str, str]:
"""Core TTS generation function"""
try:
audio_path = state.file_manager.get_temp_path("audio") + ".mp3"
tts = edge_tts.Communicate(text, voice, rate=rate, pitch=pitch)
await tts.save(audio_path)
if not os.path.exists(audio_path):
raise TTSError("Failed to generate audio file")
state.file_manager.output_files.append(audio_path)
state.file_manager.cleanup_old_files()
return audio_path
except Exception as e:
raise TTSError(f"TTS generation failed: {str(e)}")
# API endpoints
@app.post("/api/v1/tts")
async def create_tts(request: TTSRequest, background_tasks: BackgroundTasks):
job_id = f"job_{int(time.time())}_{hash(request.text)}"
state.active_jobs[job_id] = {
"id": job_id,
"status": "queued",
"progress": 0,
"created_at": datetime.now().isoformat(),
"last_update": datetime.now().isoformat(),
"request": request.dict()
}
async def process_tts():
try:
pitch_str = f"{request.pitch:+d}Hz"
rate_str = f"{request.rate:+d}%"
audio_path = await generate_tts(
request.text,
request.voice,
rate_str,
pitch_str
)
state.active_jobs[job_id].update({
"status": "completed",
"progress": 1.0,
"result": {
"audio_path": audio_path
}
})
except Exception as e:
state.active_jobs[job_id].update({
"status": "failed",
"error": str(e)
})
background_tasks.add_task(process_tts)
return {"job_id": job_id, "status": "queued"}
@app.get("/api/v1/status/{job_id}")
async def get_job_status(job_id: str):
if job_id not in state.active_jobs:
raise HTTPException(status_code=404, detail="Job not found")
return state.active_jobs[job_id]
@app.get("/api/v1/download/{job_id}")
async def download_file(job_id: str):
if job_id not in state.active_jobs:
raise HTTPException(status_code=404, detail="Job not found")
job = state.active_jobs[job_id]
if job["status"] != "completed":
raise HTTPException(status_code=400, detail="Job not completed")
file_path = job["result"]["audio_path"]
return FileResponse(
file_path,
filename=f"tts_output.mp3"
)
@app.get("/api/v1/health", response_model=HealthResponse)
async def health_check():
return {
"status": "healthy",
"timestamp": datetime.now().isoformat(),
"cpu_usage": psutil.cpu_percent(),
"memory_usage": psutil.virtual_memory().percent,
"active_jobs": len(state.active_jobs)
}
@app.get("/api/v1/voices")
async def list_voices():
return {"voices": voice_options}
if __name__ == "__main__":
# Change to use import string format
uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=True)
|