From 0b33dc19e7bf9dd0dc34e05eff31a74977ca535d Mon Sep 17 00:00:00 2001 From: zucham Date: Sun, 4 May 2025 14:51:39 +0200 Subject: [PATCH] Add LibreTranslate module, add separate envs for it in Makefile --- Makefile | 39 +++++++++++++++++++++-- libretranslate_requirements.txt | 3 ++ main.py | 55 ++++++++++++++++++++++++++++++--- 3 files changed, 90 insertions(+), 7 deletions(-) create mode 100644 libretranslate_requirements.txt diff --git a/Makefile b/Makefile index a3e899d..55d7e8d 100644 --- a/Makefile +++ b/Makefile @@ -3,9 +3,29 @@ default: run include client/make.mk +LIBRETRANSLATE_PYTHON_VERSION = 3.10.12 + +ifeq ($(shell command -v pyenv 2> /dev/null),) + HAS_PYENV = false +else + HAS_PYENV = true +endif + +.PHONY: setup +setup: setup_pyenv setup_venvs + +.PHONY: setup_pyenv +setup_pyenv: +ifeq ($(HAS_PYENV),true) + pyenv install -s $(LIBRETRANSLATE_PYTHON_VERSION) +endif + +.PHONY: setup_venvs +setup_venvs: venv libretranslate_venv + .PHONY: run run: $(CLIENT_TARGETS) venv - source venv/bin/activate && python main.py + . venv/bin/activate && python main.py .PHONY: build build: $(CLIENT_TARGETS) @@ -18,13 +38,26 @@ test: client_test .PHONY: clean clean: client_clean - rm -rf __pycache__ + rm -rf **pycache** rm -rf venv + rm -rf libretranslate_venv rm -f pythagoras.tar.xz venv: python -m venv venv - source venv/bin/activate && pip install --upgrade pip && pip install -r requirements.txt + . venv/bin/activate && pip install --upgrade pip && pip install -r requirements.txt + +libretranslate_venv: +ifeq ($(HAS_PYENV),true) + PYENV_VERSION=$(LIBRETRANSLATE_PYTHON_VERSION) pyenv exec python -m venv libretranslate_venv +else + @exit 1 +endif + . libretranslate_venv/bin/activate && pip install --upgrade pip && pip install -r libretranslate_requirements.txt + +.PHONY: start_libretranslate +start_libretranslate: libretranslate_venv + . libretranslate_venv/bin/activate && libretranslate --port 5000 --load-only en,cs pythagoras.tar.xz: main.py $(CLIENT_TARGETS) tar --transform='s|^|pythagoras/|' -Jcvf $@ $^ diff --git a/libretranslate_requirements.txt b/libretranslate_requirements.txt new file mode 100644 index 0000000..02e11b2 --- /dev/null +++ b/libretranslate_requirements.txt @@ -0,0 +1,3 @@ +libretranslate +torch==2.2.0 + diff --git a/main.py b/main.py index f5e2290..9ac106a 100644 --- a/main.py +++ b/main.py @@ -26,6 +26,7 @@ logger = logging.getLogger("pythagoras") app = FastAPI(title="Pythagoras", description="A proxy service handling HTTP and WebSocket connections") app.state.auto_polling = False app.state.polling_rate = 5 +app.state.enable_libretranslate = True # Define the media directory MEDIA_DIR = Path("./media") @@ -115,6 +116,11 @@ async def control_endpoint(request: Request): app.state.auto_polling = new_state logger.info(f"Polling command issued, changing auto-polling to {new_state}") + elif data['command'] == "setlibretranslate" and 'state' in data: + new_state = data['state'] + app.state.auto_polling = new_state + logger.info(f"LibreTranslate command issued, changing state to {new_state}") + elif data['command'] == "autopollingrate" and 'rate' in data: new_rate = data['rate'] app.state.polling_rate = new_rate @@ -184,12 +190,16 @@ async def get_media(file_path: str): async def process_subtitles(request: Request, sub_type: str): try: text_content = await request.body() - subtitle_text = text_content.decode("utf-8") - logger.info(f"Received subtitle text: {subtitle_text}, request type: {sub_type}") + en_subtitle_text = text_content.decode("utf-8") + logger.info(f"Received subtitle text: {en_subtitle_text}, request type: {sub_type}") if manager.active_connections: - await manager.broadcast_binary({"type": f"subtitle_{sub_type}", "text": subtitle_text}) - + await manager.broadcast_binary({"type": f"subtitle_en_{sub_type}", "text": en_subtitle_text}) + + if app.state.enable_libretranslate and sub_type == "submit_sentence": + cs_subtitle_text = await translate_to_cs_libre(en_subtitle_text) + await manager.broadcast_binary({"type": f"subtitle_cs_{sub_type}", "text": cs_subtitle_text}) + return JSONResponse( status_code=200, content={"status": "success", "message": "Subtitle text received"} @@ -201,6 +211,43 @@ async def process_subtitles(request: Request, sub_type: str): content={"status": "error", "message": f"Failed to process request."} ) +async def translate_to_cs_libre(text: str): + """ + Translates the provided text from English to Czech using LibreTranslate. + """ + if not text: + return text + + try: + url = "http://localhost:5000/translate" + + payload = { + "q": text, + "source": "en", + "target": "cs", + "format": "text" + } + + timeout = httpx.Timeout(10.0) + + async with httpx.AsyncClient(timeout=timeout) as client: + response = await client.post(url, json=payload) + + if response.status_code == 200: + result = response.json() + translated_text = result.get("translatedText", text) + logger.info(f"Successfully translated text to Czech") + return translated_text + else: + logger.error(f"Translation API error: {response.status_code}, {response.text}") + return text + + except Exception as e: + logger.error(f"Translation error: {str(e)}") + return text + + + async def fetch_selected_message(): """ Fetches a selected message from the specified endpoint.