Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"__comment::changes_to_the_config": "the program needs to be restarted if you change this file since it is stored in memory on startup",
"log_level": 20,
"idle_polling_interval": 5,
"idle_polling_interval_with_trigger": 300,
"tokenizer_file": "spiece.model",
"loader": {
"model_name": "Nextcloud-AI/madlad400-3b-mt-ct2-int8_float32",
Expand Down
40 changes: 28 additions & 12 deletions lib/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@
import threading
import traceback
from contextlib import asynccontextmanager, suppress
from time import sleep
from threading import Event

import httpx
import uvicorn.logging
from dotenv import load_dotenv
from fastapi import FastAPI, Request, responses
from nc_py_api import AsyncNextcloudApp, NextcloudApp, NextcloudException
from nc_py_api.ex_app import LogLvl, run_app, set_handlers, setup_nextcloud_logging
from nc_py_api.ex_app.integration_fastapi import fetch_models_task
from nc_py_api.ex_app.providers.task_processing import ShapeEnumValue, TaskProcessingProvider
from niquests import RequestException
from Service import Service, ServiceException, TranslateRequest
from util import load_config_file, save_config_file

Expand Down Expand Up @@ -61,6 +61,7 @@ async def lifespan(_: FastAPI):
fast_api_app=APP,
enabled_handler=enabled_handler, # type: ignore
models_to_fetch=models_to_fetch, # type: ignore
trigger_handler=trigger_handler,
)

print(f"Config loaded: {json.dumps(config, indent=4)}", flush=True)
Expand All @@ -81,6 +82,7 @@ async def lifespan(_: FastAPI):
APP_ID = "translate2"
TASK_TYPE_ID = "core:text2text:translate"
IDLE_POLLING_INTERVAL = config["idle_polling_interval"]
IDLE_POLLING_INTERVAL_WITH_TRIGGER = config["idle_polling_interval_with_trigger"]
DETECT_LANGUAGE = ShapeEnumValue(name="Detect Language", value="detect_language")
APP = FastAPI(lifespan=lifespan)

Expand All @@ -95,7 +97,7 @@ def report_error(task: dict | None, exc: Exception):
task["task"]["id"],
error_message=f"Error translating the input text: {exc}"
)
except (NextcloudException, httpx.NetworkError) as e:
except (NextcloudException, RequestException) as e:
logger.error(f"Error reporting error to the server: {e}")


Expand Down Expand Up @@ -130,21 +132,16 @@ def task_fetch_thread(service: Service):
task = nc.providers.task_processing.next_task([APP_ID], [TASK_TYPE_ID])
except (NextcloudException, json.JSONDecodeError) as e:
logger.error("Error fetching the next task", exc_info=e)
sleep(IDLE_POLLING_INTERVAL)
wait_for_task()
continue
except (
httpx.RemoteProtocolError,
httpx.ReadError,
httpx.LocalProtocolError,
httpx.PoolTimeout,
) as e:
except RequestException as e:
logger.debug("Ignored error during task polling", exc_info=e)
sleep(IDLE_POLLING_INTERVAL / 2)
wait_for_task(IDLE_POLLING_INTERVAL / 2)
continue

if not task:
logger.debug("No tasks found")
sleep(IDLE_POLLING_INTERVAL)
wait_for_task()
continue

logger.debug(f"Processing task: {task}")
Expand Down Expand Up @@ -218,6 +215,25 @@ async def enabled_handler(enabled: bool, nc: AsyncNextcloudApp) -> str:
return ""


TRIGGER = Event()
# Trigger is only available in nc >= 33
def trigger_handler(providerId: str):
global TRIGGER
TRIGGER.set()

# Waits for interval seconds or IDLE_POLLING_INTERVAL seconds
# if TRIGGER is received, IDLE_POLLING_INTERVAL is set to IDLE_POLLING_INTERVAL_WITH_TRIGGER
def wait_for_task(interval = None):
global TRIGGER
global IDLE_POLLING_INTERVAL
global IDLE_POLLING_INTERVAL_WITH_TRIGGER
if interval is None:
interval = IDLE_POLLING_INTERVAL
if TRIGGER.wait(timeout=interval):
IDLE_POLLING_INTERVAL = IDLE_POLLING_INTERVAL_WITH_TRIGGER
TRIGGER.clear()


if __name__ == "__main__":
uvicorn_log_level = (
uvicorn.logging.TRACE_LOG_LEVEL
Expand Down
2 changes: 1 addition & 1 deletion requirements.in.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
fastapi
ctranslate2
huggingface_hub
nc_py_api[app]>=0.20.0
nc_py_api[app]>=0.22.0
sentencepiece
63 changes: 34 additions & 29 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,38 +1,43 @@
annotated-doc==0.0.3
annotated-types==0.7.0
anyio==4.9.0
certifi==2025.6.15
charset-normalizer==3.4.2
click==8.2.1
cmake==4.0.3
anyio==4.11.0
certifi==2025.10.5
charset-normalizer==3.4.4
click==8.3.0
ctranslate2==4.6.0
fastapi==0.116.0
filelock==3.18.0
fsspec==2025.5.1
fastapi==0.120.1
filelock==3.20.0
fsspec==2025.9.0
h11==0.16.0
hf-xet==1.1.5
hf-xet==1.2.0
httpcore==1.0.9
httptools==0.6.4
httptools==0.7.1
httpx==0.28.1
huggingface-hub==0.33.2
idna==3.10
nc-py-api==0.20.2
numpy==2.3.1
huggingface-hub==1.0.0
idna==3.11
jh2==5.0.10
nc-py-api==0.22.0
niquests==3.15.2
numpy==2.3.4
packaging==25.0
pydantic==2.11.7
pydantic_core==2.33.2
python-dotenv==1.1.1
PyYAML==6.0.2
requests==2.32.4
sentencepiece==0.2.0
pydantic==2.12.3
pydantic_core==2.41.4
python-dotenv==1.2.1
PyYAML==6.0.3
qh3==1.5.5
sentencepiece==0.2.1
setuptools==80.9.0
shellingham==1.5.4
sniffio==1.3.1
starlette==0.46.2
starlette==0.48.0
tqdm==4.67.1
truststore==0.10.0
typing-inspection==0.4.1
typing_extensions==4.14.1
urllib3==2.5.0
uvicorn==0.35.0
uvloop==0.21.0
watchfiles==1.1.0
typer-slim==0.20.0
typing-inspection==0.4.2
typing_extensions==4.15.0
urllib3-future==2.14.905
uvicorn==0.38.0
uvloop==0.22.1
wassima==2.0.2
watchfiles==1.1.1
websockets==15.0.1
xmltodict==0.14.2
xmltodict==1.0.2