"""Main app file for the translation service""" from contextlib import asynccontextmanager from typing import List, Tuple import asyncio 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) @asynccontextmanager 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) @app.exception_handler(Exception) 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") # @app.get("/") # def index(): # """Serve UI page""" # return FileResponse("templates/index.html") # @app.get("/favicon.svg") # def favicon(): # "Serve favicon" # return FileResponse("static/favicon.svg", media_type="image/svg+xml") @app.post("/api/translate") async def api_translate(data: TranslateRequest): """ Endpoint to handle batch translation requests. Args: data (TranslateRequest): The request payload containing: - sourceLangCode: FLORES code for the source language. - targetLangCode: FLORES code for the target language. - textArray: List of strings to translate. Returns: dict: A dictionary containing the translation status and the translated array. """ try: task = asyncio.create_task(process_translation( data.sourceLangCode, data.targetLangCode, data.textArray)) await task translation_array = task.result() return { 'status': 'success', 'data': {'translationArray': translation_array}} except Exception as e: raise HTTPException(status_code=500, detail="An error occurred during translation") from e