Spaces:
Running
Running
| """Main app file for the translation service""" | |
| from contextlib import asynccontextmanager | |
| from typing import List, Tuple | |
| import asyncio | |
| import httpx | |
| from fastapi import FastAPI, HTTPException | |
| from fastapi.responses import JSONResponse, FileResponse | |
| from fastapi.staticfiles import StaticFiles | |
| from pydantic import BaseModel | |
| from translate import translate_batch_async | |
| class TranslateRequest(BaseModel): | |
| sourceLangCode: str | |
| targetLangCode: str | |
| textArray: List[str] | |
| active_translation_requests: List[Tuple[str, str, List[str], asyncio.Future]] = [ | |
| ] # a list to store translation requests | |
| async def process_translation( | |
| src_lang: str, tgt_lang: str, textArr: List[str] | |
| ) -> List[str]: | |
| future = asyncio.get_running_loop().create_future() | |
| active_translation_requests.append( | |
| (src_lang, tgt_lang, textArr, future)) | |
| result = await future | |
| return result | |
| async def batch_translate(): | |
| """Background task that processes queued translation requests.""" | |
| global active_translation_requests | |
| while True: | |
| if active_translation_requests: | |
| requestsProcessingNow = len(active_translation_requests) | |
| results = await translate_batch_async( | |
| [src for src, _, _, _ in active_translation_requests], | |
| [tgt for _, tgt, _, _ in active_translation_requests], | |
| [text for _, _, text, _ in active_translation_requests] | |
| ) | |
| for i, (_, _, _, future) in enumerate(active_translation_requests[:requestsProcessingNow]): | |
| future.set_result(results[i]) | |
| # remove the processed tasks: | |
| active_translation_requests = active_translation_requests[requestsProcessingNow:] | |
| else: | |
| await asyncio.sleep(0.1) | |
| async def lifespan(app_instance: FastAPI): | |
| """Lifespan context manager for startup and shutdown events.""" | |
| # Startup: Launch the batch translation background task | |
| asyncio.create_task(batch_translate()) | |
| yield | |
| # Shutdown: Clean up (if needed in the future) | |
| # Define a FastAPI app with lifespan | |
| app = FastAPI(lifespan=lifespan) | |
| async def exception_handler(request, exc): | |
| """Handle exceptions""" | |
| error_data = { | |
| 'status': 'failure', | |
| 'error': 'An unexpected error occurred' | |
| } | |
| return JSONResponse(content=error_data, status_code=500) | |
| # Serve static files | |
| app.mount("/static", StaticFiles(directory="static"), name="static") | |
| def index(): | |
| """Serve UI page""" | |
| return FileResponse("templates/index.html") | |
| def favicon(): | |
| "Serve favicon" | |
| return FileResponse("static/favicon.svg", media_type="image/svg+xml") | |
| async def api_translate(data: TranslateRequest): | |
| """ | |
| Endpoint to handle batch translation requests. | |
| """ | |
| if data.targetLangCode == 'bn_NG': | |
| # Bini endpoint uses en_XX for English source instead of eng_Latn | |
| if data.sourceLangCode == 'eng_Latn': | |
| data.sourceLangCode = 'en_XX' | |
| # Route Bini requests to the external endpoint | |
| try: | |
| async with httpx.AsyncClient() as client: | |
| response = await client.post( | |
| "https://dalaone-bini.hf.space/api/translate", | |
| json=data.dict(), | |
| timeout=30.0 | |
| ) | |
| response.raise_for_status() | |
| return response.json() | |
| except httpx.HTTPError as e: | |
| raise HTTPException(status_code=502, detail=f"Error proxying request to Bini endpoint: {str(e)}") | |
| try: | |
| task = asyncio.create_task(process_translation( | |
| data.sourceLangCode, | |
| data.targetLangCode, | |
| data.textArray | |
| )) | |
| result = await task | |
| return { | |
| "status": "success", | |
| "data": { | |
| "translationArray": result | |
| } | |
| } | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=str(e)) |