All checks were successful
Deploy FluentGerman.ai / deploy (push) Successful in 49s
68 lines
2.5 KiB
Python
68 lines
2.5 KiB
Python
"""FluentGerman.ai — Admin voice-to-instruction & voice API router."""
|
|
|
|
import logging
|
|
from fastapi import APIRouter, Depends, UploadFile, File, HTTPException
|
|
from fastapi.responses import Response
|
|
|
|
from app.auth import require_admin, get_current_user
|
|
from app.config import get_settings
|
|
from app.models import User
|
|
from app.schemas import VoiceConfigOut, VoiceInstructionRequest
|
|
from app.services.llm_service import summarize_instruction
|
|
from app.services.voice_service import synthesize, transcribe
|
|
|
|
# Setup logger
|
|
logger = logging.getLogger("fluentgerman.voice")
|
|
|
|
router = APIRouter(prefix="/api/voice", tags=["voice"])
|
|
|
|
|
|
@router.get("/config", response_model=VoiceConfigOut)
|
|
async def voice_config(user: User = Depends(get_current_user)):
|
|
"""Return current voice mode so frontend knows whether to use browser or API."""
|
|
settings = get_settings()
|
|
# Check if we have a dedicated voice key OR a generic LLM key for OpenAI
|
|
has_key = bool(settings.openai_api_key or (settings.llm_api_key and settings.llm_provider == "openai"))
|
|
|
|
api_available = bool(settings.voice_mode == "api" and has_key)
|
|
return VoiceConfigOut(
|
|
voice_mode=settings.voice_mode,
|
|
voice_api_available=api_available,
|
|
)
|
|
|
|
|
|
@router.post("/transcribe")
|
|
async def transcribe_audio(
|
|
audio: UploadFile = File(...),
|
|
user: User = Depends(get_current_user),
|
|
):
|
|
"""Transcribe uploaded audio to text (API mode only)."""
|
|
try:
|
|
audio_bytes = await audio.read()
|
|
text = await transcribe(audio_bytes, filename=audio.filename or "audio.webm")
|
|
return {"text": text}
|
|
except Exception as e:
|
|
logger.error(f"Transcription failed: {str(e)}", exc_info=True)
|
|
raise HTTPException(status_code=500, detail=f"Transcription failed: {str(e)}")
|
|
|
|
|
|
@router.post("/synthesize")
|
|
async def synthesize_text(
|
|
text: str,
|
|
user: User = Depends(get_current_user),
|
|
):
|
|
"""Convert text to speech audio (API mode only)."""
|
|
try:
|
|
audio_bytes = await synthesize(text)
|
|
return Response(content=audio_bytes, media_type="audio/mpeg")
|
|
except Exception as e:
|
|
logger.error(f"Synthesis failed: {str(e)}", exc_info=True)
|
|
raise HTTPException(status_code=500, detail=f"Synthesis failed: {str(e)}")
|
|
|
|
|
|
@router.post("/generate-instruction", dependencies=[Depends(require_admin)])
|
|
async def generate_instruction(body: VoiceInstructionRequest):
|
|
"""Admin: takes raw transcript and returns a structured instruction via LLM."""
|
|
structured = await summarize_instruction(body.raw_text)
|
|
return {"instruction": structured}
|