feat: improve voice studio alpha recovery flow
This commit is contained in:
@@ -12,6 +12,7 @@ from fastapi import (
|
||||
)
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.config import settings
|
||||
from app.core.deps import require_user
|
||||
from app.core.rate_limiter import check_rate_limit
|
||||
from app.db.database import get_db
|
||||
@@ -34,11 +35,14 @@ from app.services.voice_session_service import (
|
||||
create_voice_turn_from_text_service,
|
||||
create_voice_turn_from_upload_service,
|
||||
finalize_voice_session_service,
|
||||
get_latest_active_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,
|
||||
retry_voice_turn_audio_service,
|
||||
retry_voice_turn_service,
|
||||
)
|
||||
|
||||
router = APIRouter()
|
||||
@@ -68,8 +72,13 @@ async def create_voice_session(
|
||||
|
||||
@router.get("/voice-sessions", response_model=list[VoiceSessionSummaryResponse])
|
||||
async def list_voice_sessions(
|
||||
limit: int = Query(default=8, ge=1, le=20),
|
||||
limit: int = Query(
|
||||
default=settings.voice_session_default_list_limit,
|
||||
ge=1,
|
||||
le=settings.voice_session_max_list_limit,
|
||||
),
|
||||
active_only: bool = Query(default=False),
|
||||
active_first: bool = Query(default=True),
|
||||
user: User = Depends(require_user),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
@@ -79,9 +88,19 @@ async def list_voice_sessions(
|
||||
db,
|
||||
limit=limit,
|
||||
active_only=active_only,
|
||||
active_first=active_first,
|
||||
)
|
||||
|
||||
|
||||
@router.get("/voice-sessions/active", response_model=VoiceSessionSummaryResponse | None)
|
||||
async def get_latest_active_voice_session(
|
||||
user: User = Depends(require_user),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
"""Get the latest active voice session for quick resume behavior."""
|
||||
return await get_latest_active_voice_session_service(user.id, db)
|
||||
|
||||
|
||||
@router.get("/voice-sessions/{session_id}", response_model=VoiceSessionDetailResponse)
|
||||
async def get_voice_session(
|
||||
session_id: str,
|
||||
@@ -158,6 +177,21 @@ async def get_voice_turn(
|
||||
return await get_voice_turn_service(session_id, turn_id, user.id, db)
|
||||
|
||||
|
||||
@router.post(
|
||||
"/voice-sessions/{session_id}/turns/{turn_id}/retry",
|
||||
response_model=VoiceTurnAcceptedResponse,
|
||||
status_code=status.HTTP_202_ACCEPTED,
|
||||
)
|
||||
async def retry_voice_turn(
|
||||
session_id: str,
|
||||
turn_id: str,
|
||||
user: User = Depends(require_user),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
"""Retry one failed voice turn using its saved transcript."""
|
||||
return await retry_voice_turn_service(session_id, turn_id, user.id, db)
|
||||
|
||||
|
||||
@router.get("/voice-sessions/{session_id}/turns/{turn_id}/audio")
|
||||
async def get_voice_turn_audio(
|
||||
session_id: str,
|
||||
@@ -170,6 +204,20 @@ async def get_voice_turn_audio(
|
||||
return Response(content=audio_bytes, media_type="audio/mpeg")
|
||||
|
||||
|
||||
@router.post(
|
||||
"/voice-sessions/{session_id}/turns/{turn_id}/retry-audio",
|
||||
response_model=VoiceTurnSummaryResponse,
|
||||
)
|
||||
async def retry_voice_turn_audio(
|
||||
session_id: str,
|
||||
turn_id: str,
|
||||
user: User = Depends(require_user),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
"""Retry assistant audio synthesis when one turn only has text output."""
|
||||
return await retry_voice_turn_audio_service(session_id, turn_id, user.id, db)
|
||||
|
||||
|
||||
@router.get("/voice-sessions/{session_id}/turns/{turn_id}/user-audio")
|
||||
async def get_voice_turn_user_audio(
|
||||
session_id: str,
|
||||
|
||||
Reference in New Issue
Block a user