refactor(stage-4): partition monolithic main.py into modular APIRouters
This commit is contained in:
1 parent
4e1f809018
commit
dde87e5d6c
15 files changed
+2202
-2138
No files matched your search
@@ -0,0 +1,117 @@
|
||||
import asyncio
|
||||
from typing import Optional
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from app.auth import require_user
|
||||
from app.database import get_db
|
||||
from app.tasks import (
|
||||
create_task,
|
||||
get_task_status,
|
||||
get_active_task,
|
||||
cancel_task,
|
||||
)
|
||||
from app.miner import run_mining_task_background
|
||||
|
||||
router = APIRouter(tags=["Background Tasks"])
|
||||
|
||||
|
||||
class MineBooksRequest(BaseModel):
|
||||
book_id: Optional[int] = None
|
||||
level: str = "A1"
|
||||
count: int = Field(15, ge=1, le=50)
|
||||
|
||||
|
||||
@router.post("/api/tasks/mine-books")
|
||||
async def api_tasks_mine_books(
|
||||
req: MineBooksRequest,
|
||||
user: dict = Depends(require_user),
|
||||
):
|
||||
"""
|
||||
Starts an asynchronous background task to mine CEFR Cloze Tap questions
|
||||
from user's uploaded books (EPUB, TXT, PDF).
|
||||
"""
|
||||
level = req.level.upper().strip()
|
||||
if level not in ["A1", "A2", "B1", "B2", "ALL"]:
|
||||
raise HTTPException(status_code=400, detail="Invalid CEFR level")
|
||||
|
||||
count = max(1, min(req.count, 50))
|
||||
|
||||
with get_db() as conn:
|
||||
active = get_active_task(conn, user["id"], task_type="mine_books")
|
||||
if active:
|
||||
return {
|
||||
"status": "already_running",
|
||||
"message": "Сборка уже выполняется в фоне",
|
||||
"task": active,
|
||||
}
|
||||
|
||||
task_id = create_task(
|
||||
conn,
|
||||
user_id=user["id"],
|
||||
task_type="mine_books",
|
||||
params={
|
||||
"book_id": req.book_id,
|
||||
"level": level,
|
||||
"count": count,
|
||||
},
|
||||
total=count,
|
||||
)
|
||||
|
||||
# Launch background asyncio task
|
||||
asyncio.create_task(
|
||||
run_mining_task_background(
|
||||
task_id=task_id,
|
||||
user_id=user["id"],
|
||||
book_id=req.book_id,
|
||||
target_level=level,
|
||||
target_count=count,
|
||||
)
|
||||
)
|
||||
|
||||
return {
|
||||
"status": "ok",
|
||||
"task_id": task_id,
|
||||
"message": f"Запущена фоновая сборка тестов ({level})",
|
||||
}
|
||||
|
||||
|
||||
@router.get("/api/tasks/active")
|
||||
async def api_tasks_active(
|
||||
task_type: Optional[str] = Query(None),
|
||||
user: dict = Depends(require_user),
|
||||
):
|
||||
"""
|
||||
Returns current user's active background task (if any).
|
||||
"""
|
||||
with get_db() as conn:
|
||||
task = get_active_task(conn, user["id"], task_type=task_type)
|
||||
return {"task": task}
|
||||
|
||||
|
||||
@router.get("/api/tasks/{task_id}")
|
||||
async def api_tasks_status(
|
||||
task_id: int,
|
||||
user: dict = Depends(require_user),
|
||||
):
|
||||
"""
|
||||
Returns status and progress of a background task.
|
||||
"""
|
||||
with get_db() as conn:
|
||||
task = get_task_status(conn, task_id, user_id=user["id"])
|
||||
if not task:
|
||||
raise HTTPException(status_code=404, detail="Task not found")
|
||||
return {"task": task}
|
||||
|
||||
|
||||
@router.post("/api/tasks/{task_id}/cancel")
|
||||
async def api_tasks_cancel(
|
||||
task_id: int,
|
||||
user: dict = Depends(require_user),
|
||||
):
|
||||
"""
|
||||
Cancels a running background task.
|
||||
"""
|
||||
with get_db() as conn:
|
||||
cancelled = cancel_task(conn, task_id, user_id=user["id"])
|
||||
return {"status": "ok" if cancelled else "not_found", "cancelled": cancelled}
|
||||
Reference in new issue
Block a user