language-learning-app/api/app/routers/api/generation.py

93 lines
3.2 KiB
Python

import uuid
from functools import partial
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from sqlalchemy.ext.asyncio import AsyncSession
from ...languages import SUPPORTED_LANGUAGES, SUPPORTED_LEVELS
from ...auth import require_admin
from ...outbound.postgres.database import get_db, AsyncSessionLocal
from ...outbound.postgres.repositories import summarise_job_repository
from ...outbound.postgres.repositories.translated_article_repository import TranslatedArticleRepository
from ...outbound.anthropic.anthropic_client import AnthropicClient
from ...outbound.deepgram.deepgram_client import LocalDeepgramClient
from ...outbound.deepl.deepl_client import DeepLClient
from ...outbound.gemini.gemini_client import GeminiClient
from ...outbound.spacy.spacy_client import SpacyClient
from ...domain.services.summarise_service import SummariseService
from ...config import settings
from ... import worker
router = APIRouter(prefix="/generate", tags=["api"])
class GenerationRequest(BaseModel):
target_language: str
complexity_level: str
input_texts: list[str]
source_language: str = "en"
class GenerationResponse(BaseModel):
job_id: str
async def _run_generation(
job_id: uuid.UUID,
article_id: uuid.UUID,
request: GenerationRequest,
) -> None:
service = SummariseService(
anthropic_client=AnthropicClient.new(settings.anthropic_api_key),
deepgram_client=LocalDeepgramClient(settings.deepgram_api_key),
deepl_client=DeepLClient(settings.deepl_api_key),
gemini_client=GeminiClient(settings.gemini_api_key),
spacy_client=SpacyClient(),
)
async with AsyncSessionLocal() as db:
await service.run(
db=db,
job_id=job_id,
article_id=article_id,
source_language=request.source_language,
target_language=request.target_language,
complexity_level=request.complexity_level,
input_texts=request.input_texts,
)
@router.post("", response_model=GenerationResponse, status_code=202)
async def create_generation_job(
request: GenerationRequest,
db: AsyncSession = Depends(get_db),
token_data: dict = Depends(require_admin),
) -> GenerationResponse:
if request.target_language not in SUPPORTED_LANGUAGES:
raise HTTPException(
status_code=400,
detail=f"Unsupported language '{request.target_language}'. "
f"Supported: {list(SUPPORTED_LANGUAGES)}",
)
if request.complexity_level not in SUPPORTED_LEVELS:
raise HTTPException(
status_code=400,
detail=f"Unsupported level '{request.complexity_level}'. "
f"Supported: {sorted(SUPPORTED_LEVELS)}",
)
article = await TranslatedArticleRepository(db).create(
source_language=request.source_language,
target_language=request.target_language,
target_complexities=[request.complexity_level],
)
job = await summarise_job_repository.create(
db,
user_id=uuid.UUID(token_data["sub"]),
translated_article_id=uuid.UUID(article.id),
)
await worker.enqueue(partial(_run_generation, job.id, uuid.UUID(article.id), request))
return GenerationResponse(job_id=str(job.id))