diff --git a/.l10nignore b/.l10nignore new file mode 100644 index 0000000..6ba63c8 --- /dev/null +++ b/.l10nignore @@ -0,0 +1,6 @@ +# SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors +# SPDX-License-Identifier: AGPL-3.0-or-later +js/ +vendor/ +.venv/ +venv/ \ No newline at end of file diff --git a/.tx/config b/.tx/config new file mode 100644 index 0000000..907816f --- /dev/null +++ b/.tx/config @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors +# SPDX-License-Identifier: AGPL-3.0-or-later +[main] +host = https://www.transifex.com +lang_map = th_TH: th, ja_JP: ja, bg_BG: bg, cs_CZ: cs, fi_FI: fi, hu_HU: hu, nb_NO: nb, sk_SK: sk + +[o:nextcloud:p:nextcloud:r:context_agent] +file_filter = translationfiles//context_agent.po +source_file = translationfiles/templates/context_agent.pot +source_lang = en +type = PO \ No newline at end of file diff --git a/.tx/l10n/.gitkeep b/.tx/l10n/.gitkeep new file mode 100644 index 0000000..3804756 --- /dev/null +++ b/.tx/l10n/.gitkeep @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors +# SPDX-License-Identifier: AGPL-3.0-or-later \ No newline at end of file diff --git a/ex_app/lib/all_tools/external.py b/ex_app/lib/all_tools/external.py index 8379ff3..30ff70f 100644 --- a/ex_app/lib/all_tools/external.py +++ b/ex_app/lib/all_tools/external.py @@ -51,7 +51,33 @@ def get_current_weather_for_coordinates(lat: str, lon: str) -> dict[str, typing. raise Exception('Could not retrieve weather for coordinates') return json['properties']['timeseries'][0]['data']['instant']['details'] + + + @tool + @safe_tool + def get_public_transport_route_for_coordinates(origin_lat: str, origin_lon: str, destination_lat: str, destination_lon: str, routes: int) -> dict[str, typing.Any]: + """ + Retrieve a public transport route between two coordinates + When using get_public_transport_route_for_coordinates, always let the user know that the routing service here.com was used. + :param origin_lat: Latitude of the starting point + :param origin_lon: Longitude of the starting point + :param destination_lat: Latitude of the destination + :param destination_lon: Longitude of the destination + :param routes: the number of routes returned + :return: + """ + + api_key = nc.appconfig_ex.get_value('here_api') + res = httpx.get('https://transit.hereapi.com/v8/routes?transportMode=car&origin=' + + origin_lat + ',' + origin_lon + '&destination=' + destination_lat + ',' + destination_lon + + '&alternatives=' + str(routes-1) + '&apikey=' + api_key) + json = res.json() + return json + + + return [ get_coordinates_for_address, get_current_weather_for_coordinates, + get_public_transport_route_for_coordinates ] \ No newline at end of file diff --git a/ex_app/lib/main.py b/ex_app/lib/main.py index b099546..3e71a78 100644 --- a/ex_app/lib/main.py +++ b/ex_app/lib/main.py @@ -1,5 +1,6 @@ # SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors # SPDX-License-Identifier: AGPL-3.0-or-later +import os import traceback from contextlib import asynccontextmanager from json import JSONDecodeError @@ -9,15 +10,32 @@ import httpx from fastapi import FastAPI from nc_py_api import NextcloudApp, NextcloudException -from nc_py_api.ex_app import AppAPIAuthMiddleware, LogLvl, run_app, set_handlers +from nc_py_api.ex_app import ( + AppAPIAuthMiddleware, + LogLvl, + run_app, + set_handlers, + SettingsForm, + SettingsField, + SettingsFieldType) from ex_app.lib.agent import react from ex_app.lib.logger import log from ex_app.lib.provider import provider +from contextvars import ContextVar +from gettext import translation + app_enabled = Event() +LOCALE_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), "locale") +current_translator = ContextVar("current_translator") +current_translator.set(translation(os.getenv("APP_ID"), LOCALE_DIR, languages=["en"], fallback=True)) + +def _(text): + return current_translator.get().gettext(text) + @asynccontextmanager async def lifespan(app: FastAPI): set_handlers(app, enabled_handler) @@ -31,6 +49,24 @@ async def lifespan(app: FastAPI): APP = FastAPI(lifespan=lifespan) APP.add_middleware(AppAPIAuthMiddleware) # set global AppAPI authentication middleware +SETTINGS = SettingsForm( + id="settings_context_agent", + section_type="admin", + section_id="ai", + title=_("Context Agent"), + description=_("Find more details on how to set up Context Agent in the Administration documentation."), + fields=[ + SettingsField( + id="here_api", + title=_("API Key HERE"), + description=_("Set the API key for the HERE public transport routing"), + type=SettingsFieldType.PASSWORD, + default="", + placeholder=_("API key"), + ), + ], +) + def enabled_handler(enabled: bool, nc: NextcloudApp) -> str: # This will be called each time application is `enabled` or `disabled` @@ -40,6 +76,8 @@ def enabled_handler(enabled: bool, nc: NextcloudApp) -> str: nc.providers.task_processing.register(provider) app_enabled.set() log(nc, LogLvl.WARNING, f"App enabled: {nc.app_cfg.app_name}") + + nc.ui.settings.register_form(SETTINGS) else: nc.providers.task_processing.unregister(provider.id) app_enabled.clear()