feat: add voice studio prototype flow
This commit is contained in:
@@ -1,6 +1,15 @@
|
||||
"""Voice co-creation session APIs."""
|
||||
|
||||
from fastapi import APIRouter, Depends, Response, status
|
||||
from fastapi import (
|
||||
APIRouter,
|
||||
Depends,
|
||||
File,
|
||||
Form,
|
||||
Query,
|
||||
Response,
|
||||
UploadFile,
|
||||
status,
|
||||
)
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.deps import require_user
|
||||
@@ -17,15 +26,19 @@ from app.schemas.voice_session_schemas import (
|
||||
VoiceTurnAcceptedResponse,
|
||||
VoiceTurnCreateFallbackRequest,
|
||||
VoiceTurnSummaryResponse,
|
||||
VoiceTurnUploadAcceptedResponse,
|
||||
)
|
||||
from app.services.voice_session_service import (
|
||||
abandon_voice_session_service,
|
||||
create_voice_session_service,
|
||||
create_voice_turn_from_text_service,
|
||||
create_voice_turn_from_upload_service,
|
||||
finalize_voice_session_service,
|
||||
get_voice_session_detail_service,
|
||||
get_voice_turn_audio_service,
|
||||
get_voice_turn_service,
|
||||
get_voice_turn_user_audio_service,
|
||||
list_voice_sessions_service,
|
||||
)
|
||||
|
||||
router = APIRouter()
|
||||
@@ -53,6 +66,22 @@ async def create_voice_session(
|
||||
return await create_voice_session_service(request, user.id, db)
|
||||
|
||||
|
||||
@router.get("/voice-sessions", response_model=list[VoiceSessionSummaryResponse])
|
||||
async def list_voice_sessions(
|
||||
limit: int = Query(default=8, ge=1, le=20),
|
||||
active_only: bool = Query(default=False),
|
||||
user: User = Depends(require_user),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
"""List recent voice co-creation sessions for restore/resume behavior."""
|
||||
return await list_voice_sessions_service(
|
||||
user.id,
|
||||
db,
|
||||
limit=limit,
|
||||
active_only=active_only,
|
||||
)
|
||||
|
||||
|
||||
@router.get("/voice-sessions/{session_id}", response_model=VoiceSessionDetailResponse)
|
||||
async def get_voice_session(
|
||||
session_id: str,
|
||||
@@ -83,6 +112,38 @@ async def create_voice_turn_from_text(
|
||||
return await create_voice_turn_from_text_service(session_id, request, user.id, db)
|
||||
|
||||
|
||||
@router.post(
|
||||
"/voice-sessions/{session_id}/turns",
|
||||
response_model=VoiceTurnUploadAcceptedResponse,
|
||||
status_code=status.HTTP_202_ACCEPTED,
|
||||
)
|
||||
async def create_voice_turn_from_upload(
|
||||
session_id: str,
|
||||
audio_file: UploadFile = File(...),
|
||||
duration_ms: int | None = Form(default=None),
|
||||
transcript_hint: str | None = Form(default=None),
|
||||
user: User = Depends(require_user),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
"""Create one turn from uploaded audio and configured ASR behavior."""
|
||||
await check_rate_limit(
|
||||
f"voice-turn:{user.id}",
|
||||
VOICE_SESSION_RATE_LIMIT_REQUESTS,
|
||||
VOICE_SESSION_RATE_LIMIT_WINDOW,
|
||||
)
|
||||
audio_bytes = await audio_file.read()
|
||||
return await create_voice_turn_from_upload_service(
|
||||
session_id=session_id,
|
||||
user_id=user.id,
|
||||
audio_bytes=audio_bytes,
|
||||
file_name=audio_file.filename or "voice-turn.webm",
|
||||
mime_type=audio_file.content_type,
|
||||
duration_ms=duration_ms,
|
||||
transcript_hint=transcript_hint,
|
||||
db=db,
|
||||
)
|
||||
|
||||
|
||||
@router.get(
|
||||
"/voice-sessions/{session_id}/turns/{turn_id}",
|
||||
response_model=VoiceTurnSummaryResponse,
|
||||
@@ -109,6 +170,23 @@ async def get_voice_turn_audio(
|
||||
return Response(content=audio_bytes, media_type="audio/mpeg")
|
||||
|
||||
|
||||
@router.get("/voice-sessions/{session_id}/turns/{turn_id}/user-audio")
|
||||
async def get_voice_turn_user_audio(
|
||||
session_id: str,
|
||||
turn_id: str,
|
||||
user: User = Depends(require_user),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
"""Get uploaded user audio for one voice turn."""
|
||||
audio_bytes, mime_type = await get_voice_turn_user_audio_service(
|
||||
session_id,
|
||||
turn_id,
|
||||
user.id,
|
||||
db,
|
||||
)
|
||||
return Response(content=audio_bytes, media_type=mime_type)
|
||||
|
||||
|
||||
@router.post(
|
||||
"/voice-sessions/{session_id}/finalize",
|
||||
response_model=VoiceSessionFinalizeResponse,
|
||||
|
||||
Reference in New Issue
Block a user