from __future__ import annotations import asyncio import logging import os import uuid from typing import Optional, List, Dict, Any from fastapi import APIRouter, UploadFile, File, Form, HTTPException, Query from fastapi.responses import JSONResponse, FileResponse from app.core.converter.conversion_manager import ConversionManager from app.core.models.converter.conversion_models import ( ContentMetadata, ConversionPriority, ConversionStatus, ) router = APIRouter(prefix="/api/converter", tags=["converter"]) logger = logging.getLogger(__name__) # Глобальный singleton менеджера (можно заменить DI контейнером) _conversion_manager: Optional[ConversionManager] = None def get_manager() -> ConversionManager: global _conversion_manager if _conversion_manager is None: _conversion_manager = ConversionManager() return _conversion_manager @router.post("/submit") async def submit_conversion( file: UploadFile = File(...), title: str = Form(...), description: Optional[str] = Form(None), author: Optional[str] = Form(None), collection: Optional[str] = Form(None), tags: Optional[str] = Form(None), # CSV language: Optional[str] = Form(None), explicit: Optional[bool] = Form(None), quality: str = Form("high"), # "high" | "low" input_ext: Optional[str] = Form(None), # если неизвестно — попытаемся из файла priority: int = Form(50), trim: Optional[str] = Form(None), custom: Optional[str] = Form(None), # произвольные ffmpeg-параметры через пробел ): """ Принимает файл и ставит задачу конвертации в очередь. Возвращает task_id. """ try: # Сохраняем входной файл во временное хранилище uploader-bot uploads_dir = "uploader-bot/uploader-bot/data/uploads" os.makedirs(uploads_dir, exist_ok=True) input_name = file.filename or f"upload-{uuid.uuid4().hex}" local_path = os.path.join(uploads_dir, input_name) with open(local_path, "wb") as f: f.write(await file.read()) # Определяем расширение, если не передано in_ext = input_ext or os.path.splitext(input_name)[1].lstrip(".").lower() or "bin" # Метаданные md = ContentMetadata( title=title, description=description, author=author, collection=collection, tags=[t.strip() for t in (tags.split(","))] if tags else [], language=language, explicit=explicit, attributes={}, ) prio = ConversionPriority.NORMAL try: # нормализуем диапазон int -> enum p_int = int(priority) if p_int >= ConversionPriority.CRITICAL: prio = ConversionPriority.CRITICAL elif p_int >= ConversionPriority.HIGH: prio = ConversionPriority.HIGH elif p_int >= ConversionPriority.NORMAL: prio = ConversionPriority.NORMAL else: prio = ConversionPriority.LOW except Exception: pass custom_list: List[str] = [] if custom: # Разбиваем по пробелам, без сложного парсинга custom_list = [c for c in custom.split(" ") if c] manager = get_manager() task_id = await manager.process_upload( local_input_path=local_path, input_ext=in_ext, quality="high" if quality == "high" else "low", metadata=md, priority=prio, custom=custom_list, trim=trim, ) return JSONResponse({"task_id": task_id}) except Exception as e: logger.exception("submit_conversion failed: %s", e) raise HTTPException(status_code=500, detail=str(e)) @router.get("/status/{task_id}") async def get_status(task_id: str): """ Возвращает статус задачи. """ try: manager = get_manager() status = await manager.get_conversion_status(task_id) return JSONResponse({"task_id": task_id, "status": status.value}) except Exception as e: logger.exception("get_status failed: %s", e) raise HTTPException(status_code=500, detail=str(e)) @router.get("/result/{task_id}") async def get_result(task_id: str): """ Возвращает результат задачи с content_id, чанками и nft метаданными. """ try: manager = get_manager() res = await manager.handle_conversion_result(task_id) if not res: # если задача всё ещё идёт/в очереди status = await manager.get_conversion_status(task_id) if status in (ConversionStatus.QUEUED, ConversionStatus.RUNNING): return JSONResponse({"task_id": task_id, "status": status.value}) raise HTTPException(status_code=404, detail="result not ready") return JSONResponse(res.to_dict()) except Exception as e: logger.exception("get_result failed: %s", e) raise HTTPException(status_code=500, detail=str(e))