Spaces:
Sleeping
Sleeping
Update main.py
Browse files
main.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
"""
|
| 2 |
Production FastAPI Server for Public Speaking Coach
|
| 3 |
-
|
| 4 |
"""
|
| 5 |
|
| 6 |
import os
|
|
@@ -12,28 +12,36 @@ from typing import Optional
|
|
| 12 |
import uvicorn
|
| 13 |
from fastapi import FastAPI, UploadFile, File, HTTPException, status
|
| 14 |
from fastapi.middleware.cors import CORSMiddleware
|
| 15 |
-
from fastapi.responses import JSONResponse
|
|
|
|
| 16 |
from pydantic import BaseModel
|
| 17 |
|
| 18 |
-
from
|
| 19 |
|
| 20 |
# ================= APP CONFIGURATION =================
|
| 21 |
|
| 22 |
app = FastAPI(
|
| 23 |
title="Public Speaking Coach API",
|
| 24 |
-
description="AI-powered speech analysis
|
| 25 |
-
version="
|
| 26 |
)
|
| 27 |
|
| 28 |
-
# CORS Configuration
|
| 29 |
app.add_middleware(
|
| 30 |
CORSMiddleware,
|
| 31 |
-
allow_origins=["*"],
|
| 32 |
allow_credentials=True,
|
| 33 |
allow_methods=["*"],
|
| 34 |
allow_headers=["*"],
|
| 35 |
)
|
| 36 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
# Global engine instance
|
| 38 |
coach_engine: Optional[EnhancedPublicSpeakingCoach] = None
|
| 39 |
|
|
@@ -53,6 +61,7 @@ class HealthResponse(BaseModel):
|
|
| 53 |
"""Health check response"""
|
| 54 |
status: str
|
| 55 |
engine_loaded: bool
|
|
|
|
| 56 |
supported_formats: list
|
| 57 |
|
| 58 |
|
|
@@ -75,7 +84,10 @@ async def startup_event():
|
|
| 75 |
|
| 76 |
try:
|
| 77 |
print("\n📦 Loading AI models...")
|
| 78 |
-
coach_engine = EnhancedPublicSpeakingCoach(
|
|
|
|
|
|
|
|
|
|
| 79 |
print("✅ Coach engine ready!")
|
| 80 |
print("\n" + "="*60)
|
| 81 |
print("🎤 API is ready to analyze speeches!")
|
|
@@ -101,6 +113,7 @@ async def root():
|
|
| 101 |
return {
|
| 102 |
"status": "online",
|
| 103 |
"engine_loaded": coach_engine is not None,
|
|
|
|
| 104 |
"supported_formats": list(SUPPORTED_FORMATS)
|
| 105 |
}
|
| 106 |
|
|
@@ -111,6 +124,7 @@ async def health_check():
|
|
| 111 |
return {
|
| 112 |
"status": "healthy" if coach_engine else "degraded",
|
| 113 |
"engine_loaded": coach_engine is not None,
|
|
|
|
| 114 |
"supported_formats": list(SUPPORTED_FORMATS)
|
| 115 |
}
|
| 116 |
|
|
@@ -118,19 +132,13 @@ async def health_check():
|
|
| 118 |
@app.post("/coach")
|
| 119 |
async def analyze_speech(file: UploadFile = File(...)):
|
| 120 |
"""
|
| 121 |
-
Main endpoint: Upload audio file and receive
|
| 122 |
|
| 123 |
-
Args:
|
| 124 |
-
file: Audio file (wav, mp3, m4a, flac, ogg, etc.)
|
| 125 |
-
|
| 126 |
Returns:
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
413: File too large
|
| 132 |
-
500: Analysis failed
|
| 133 |
-
503: Engine not loaded
|
| 134 |
"""
|
| 135 |
|
| 136 |
# Check if engine is loaded
|
|
@@ -189,7 +197,7 @@ async def analyze_speech(file: UploadFile = File(...)):
|
|
| 189 |
print(f"\n📁 Processing: {file.filename} ({len(content) / 1024:.1f} KB)")
|
| 190 |
|
| 191 |
# Run analysis
|
| 192 |
-
result = coach_engine.analyze_speech(temp_file)
|
| 193 |
|
| 194 |
# Check for analysis errors
|
| 195 |
if "error" in result:
|
|
@@ -232,6 +240,24 @@ async def analyze_speech_alias(file: UploadFile = File(...)):
|
|
| 232 |
return await analyze_speech(file)
|
| 233 |
|
| 234 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 235 |
# ================= ERROR HANDLERS =================
|
| 236 |
|
| 237 |
@app.exception_handler(HTTPException)
|
|
@@ -268,6 +294,6 @@ if __name__ == "__main__":
|
|
| 268 |
uvicorn.run(
|
| 269 |
app,
|
| 270 |
host="0.0.0.0",
|
| 271 |
-
port=
|
| 272 |
log_level="info"
|
| 273 |
)
|
|
|
|
| 1 |
"""
|
| 2 |
Production FastAPI Server for Public Speaking Coach
|
| 3 |
+
With LLM Tips and Avatar Voice Support
|
| 4 |
"""
|
| 5 |
|
| 6 |
import os
|
|
|
|
| 12 |
import uvicorn
|
| 13 |
from fastapi import FastAPI, UploadFile, File, HTTPException, status
|
| 14 |
from fastapi.middleware.cors import CORSMiddleware
|
| 15 |
+
from fastapi.responses import JSONResponse, FileResponse
|
| 16 |
+
from fastapi.staticfiles import StaticFiles
|
| 17 |
from pydantic import BaseModel
|
| 18 |
|
| 19 |
+
from enhanced_speech_coach_with_llm import EnhancedPublicSpeakingCoach
|
| 20 |
|
| 21 |
# ================= APP CONFIGURATION =================
|
| 22 |
|
| 23 |
app = FastAPI(
|
| 24 |
title="Public Speaking Coach API",
|
| 25 |
+
description="AI-powered speech analysis with LLM tips and avatar voice",
|
| 26 |
+
version="3.0.0"
|
| 27 |
)
|
| 28 |
|
| 29 |
+
# CORS Configuration
|
| 30 |
app.add_middleware(
|
| 31 |
CORSMiddleware,
|
| 32 |
+
allow_origins=["*"],
|
| 33 |
allow_credentials=True,
|
| 34 |
allow_methods=["*"],
|
| 35 |
allow_headers=["*"],
|
| 36 |
)
|
| 37 |
|
| 38 |
+
# Audio output directory
|
| 39 |
+
AUDIO_OUTPUT_DIR = "/tmp/audio_outputs"
|
| 40 |
+
os.makedirs(AUDIO_OUTPUT_DIR, exist_ok=True)
|
| 41 |
+
|
| 42 |
+
# Mount static files for audio serving
|
| 43 |
+
app.mount("/audio", StaticFiles(directory=AUDIO_OUTPUT_DIR), name="audio")
|
| 44 |
+
|
| 45 |
# Global engine instance
|
| 46 |
coach_engine: Optional[EnhancedPublicSpeakingCoach] = None
|
| 47 |
|
|
|
|
| 61 |
"""Health check response"""
|
| 62 |
status: str
|
| 63 |
engine_loaded: bool
|
| 64 |
+
tts_enabled: bool
|
| 65 |
supported_formats: list
|
| 66 |
|
| 67 |
|
|
|
|
| 84 |
|
| 85 |
try:
|
| 86 |
print("\n📦 Loading AI models...")
|
| 87 |
+
coach_engine = EnhancedPublicSpeakingCoach(
|
| 88 |
+
whisper_model_size="base",
|
| 89 |
+
enable_tts=True
|
| 90 |
+
)
|
| 91 |
print("✅ Coach engine ready!")
|
| 92 |
print("\n" + "="*60)
|
| 93 |
print("🎤 API is ready to analyze speeches!")
|
|
|
|
| 113 |
return {
|
| 114 |
"status": "online",
|
| 115 |
"engine_loaded": coach_engine is not None,
|
| 116 |
+
"tts_enabled": coach_engine.tts_enabled if coach_engine else False,
|
| 117 |
"supported_formats": list(SUPPORTED_FORMATS)
|
| 118 |
}
|
| 119 |
|
|
|
|
| 124 |
return {
|
| 125 |
"status": "healthy" if coach_engine else "degraded",
|
| 126 |
"engine_loaded": coach_engine is not None,
|
| 127 |
+
"tts_enabled": coach_engine.tts_enabled if coach_engine else False,
|
| 128 |
"supported_formats": list(SUPPORTED_FORMATS)
|
| 129 |
}
|
| 130 |
|
|
|
|
| 132 |
@app.post("/coach")
|
| 133 |
async def analyze_speech(file: UploadFile = File(...)):
|
| 134 |
"""
|
| 135 |
+
Main endpoint: Upload audio file and receive comprehensive analysis
|
| 136 |
|
|
|
|
|
|
|
|
|
|
| 137 |
Returns:
|
| 138 |
+
- Full speech analysis
|
| 139 |
+
- Personalized tips from LLM
|
| 140 |
+
- Improved transcript
|
| 141 |
+
- Avatar voice audio (if TTS enabled)
|
|
|
|
|
|
|
|
|
|
| 142 |
"""
|
| 143 |
|
| 144 |
# Check if engine is loaded
|
|
|
|
| 197 |
print(f"\n📁 Processing: {file.filename} ({len(content) / 1024:.1f} KB)")
|
| 198 |
|
| 199 |
# Run analysis
|
| 200 |
+
result = coach_engine.analyze_speech(temp_file, output_dir=AUDIO_OUTPUT_DIR)
|
| 201 |
|
| 202 |
# Check for analysis errors
|
| 203 |
if "error" in result:
|
|
|
|
| 240 |
return await analyze_speech(file)
|
| 241 |
|
| 242 |
|
| 243 |
+
@app.get("/audio/{filename}")
|
| 244 |
+
async def get_audio(filename: str):
|
| 245 |
+
"""Serve generated avatar audio files"""
|
| 246 |
+
file_path = os.path.join(AUDIO_OUTPUT_DIR, filename)
|
| 247 |
+
|
| 248 |
+
if not os.path.exists(file_path):
|
| 249 |
+
raise HTTPException(
|
| 250 |
+
status_code=status.HTTP_404_NOT_FOUND,
|
| 251 |
+
detail="Audio file not found"
|
| 252 |
+
)
|
| 253 |
+
|
| 254 |
+
return FileResponse(
|
| 255 |
+
file_path,
|
| 256 |
+
media_type="audio/wav",
|
| 257 |
+
filename=filename
|
| 258 |
+
)
|
| 259 |
+
|
| 260 |
+
|
| 261 |
# ================= ERROR HANDLERS =================
|
| 262 |
|
| 263 |
@app.exception_handler(HTTPException)
|
|
|
|
| 294 |
uvicorn.run(
|
| 295 |
app,
|
| 296 |
host="0.0.0.0",
|
| 297 |
+
port=8000,
|
| 298 |
log_level="info"
|
| 299 |
)
|