diff --git a/ex_app/lib/all_tools/audio2text.py b/ex_app/lib/all_tools/audio2text.py index cbfffa9..395d747 100644 --- a/ex_app/lib/all_tools/audio2text.py +++ b/ex_app/lib/all_tools/audio2text.py @@ -14,7 +14,7 @@ async def get_tools(nc: Nextcloud): @safe_tool def transcribe_file(file_url: str) -> str: """ - Transcribe a media file stored inside the nextcloud + Transcribe a media file stored inside Nextcloud :param file_url: The file URL to the media file in nextcloud (The user can input this using the smart picker for example) :return: the transcription result """ diff --git a/ex_app/lib/all_tools/contacts.py b/ex_app/lib/all_tools/contacts.py index f7c08ff..0ea4d6a 100644 --- a/ex_app/lib/all_tools/contacts.py +++ b/ex_app/lib/all_tools/contacts.py @@ -80,7 +80,7 @@ def find_person_in_contacts(name: str) -> list[dict[str, typing.Any]]: @safe_tool def find_details_of_current_user() -> dict[str, typing.Any]: """ - Find the user's personal information + Find the current user's personal information :return: a dictionary with the person's personal information """ diff --git a/ex_app/lib/all_tools/context_chat.py b/ex_app/lib/all_tools/context_chat.py index 837eccf..3c31b5f 100644 --- a/ex_app/lib/all_tools/context_chat.py +++ b/ex_app/lib/all_tools/context_chat.py @@ -13,7 +13,7 @@ async def get_tools(nc: Nextcloud): @safe_tool def ask_context_chat(question: str) -> str: """ - Ask the context chat oracle, which knows all of the user's documents, a question about them + Ask the context chat oracle a question about the user's documents. It knows the contents of all of the users documents. :param question: The question to ask :return: the answer from context chat """ diff --git a/ex_app/lib/all_tools/deck.py b/ex_app/lib/all_tools/deck.py index cba72bf..0671943 100644 --- a/ex_app/lib/all_tools/deck.py +++ b/ex_app/lib/all_tools/deck.py @@ -1,27 +1,19 @@ # SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors # SPDX-License-Identifier: AGPL-3.0-or-later -from datetime import datetime, timezone, timedelta -from time import sleep -from typing import Optional - -import pytz from langchain_core.tools import tool from nc_py_api import Nextcloud from nc_py_api.ex_app import LogLvl -import xml.etree.ElementTree as ET -import vobject from ex_app.lib.all_tools.lib.decorator import safe_tool, dangerous_tool -from ex_app.lib.logger import log async def get_tools(nc: Nextcloud): @tool @safe_tool - def list_decks(): + def list_boards(): """ - List all existing kanban decks with their available info + List all existing kanban boards available in the Nextcloud Deck app for the current user with their available info :return: a dictionary with all decks of the user """ @@ -35,17 +27,17 @@ def list_decks(): @tool @dangerous_tool - def add_card(deck_id: int, stack_id: int, title: str): + def add_card(board_id: int, stack_id: int, title: str): """ - Create a new card in a list of a kanban deck. - When using this tool, you need to specify in which deck and map the card should be created. - :param deck_id: the id of the deck the card should be created in, obtainable with list_decks - :param stack_id: the id of the stack the card should be created in, obtainable with list_decks + Create a new card in a list of a kanban board in the Nextcloud Deck app. + When using this tool, you need to specify in which board and map the card should be created. + :param board_id: the id of the board the card should be created in, obtainable with list_boards + :param stack_id: the id of the stack the card should be created in, obtainable with list_boards :param title: The title of the card :return: bool """ - response = nc._session._create_adapter(True).request('POST', f"{nc.app_cfg.endpoint}/index.php/apps/deck/api/v1.0//boards/{deck_id}/stacks/{stack_id}/cards", headers={ + response = nc._session._create_adapter(True).request('POST', f"{nc.app_cfg.endpoint}/index.php/apps/deck/api/v1.0/boards/{board_id}/stacks/{stack_id}/cards", headers={ "Content-Type": "application/json", }, json={ 'title': title, @@ -58,7 +50,7 @@ def add_card(deck_id: int, stack_id: int, title: str): return True return [ - list_decks, + list_boards, add_card ] diff --git a/ex_app/lib/all_tools/doc-gen.py b/ex_app/lib/all_tools/doc-gen.py index c9d41e7..72d3210 100644 --- a/ex_app/lib/all_tools/doc-gen.py +++ b/ex_app/lib/all_tools/doc-gen.py @@ -13,8 +13,8 @@ async def get_tools(nc: Nextcloud): @safe_tool def generate_document(input: str, format: str) -> str: """ - Generate a document with the input string as description. - :param text: the instructions for the document + Generate an office document based on a description of what it should contain + :param input: the instructions for what the document should contain :param format: the format of the generated file, allowed values are "text document", "pdf", "spreadsheet", "excel spreadsheet" and "slides" :return: a download link to the generated document """ diff --git a/ex_app/lib/all_tools/files.py b/ex_app/lib/all_tools/files.py index 15a7a2b..ef397cb 100644 --- a/ex_app/lib/all_tools/files.py +++ b/ex_app/lib/all_tools/files.py @@ -2,8 +2,9 @@ # SPDX-License-Identifier: AGPL-3.0-or-later from langchain_core.tools import tool from nc_py_api import Nextcloud +import niquests -from typing import Optional +from ex_app.lib.all_tools.lib.files import get_file_id_from_file_url from ex_app.lib.all_tools.lib.decorator import safe_tool, dangerous_tool @@ -27,6 +28,28 @@ def get_file_content(file_path: str): return response.text + @tool + @safe_tool + def get_file_content_by_file_link(file_url: str): + """ + Get the content of a file given an internal Nextcloud link (e.g., https://host/index.php/f/12345) + :param file_url: the internal file URL + :return: text content of the file + """ + + file_id = get_file_id_from_file_url(file_url) + # Generate a direct download link using the fileId + info = nc.ocs('POST', '/ocs/v2.php/apps/dav/api/v1/direct', json={'fileId': file_id}, response_type='json') + download_url = info.get('ocs', {}).get('data', {}).get('url', None) + + if not download_url: + raise Exception('Could not generate download URL from file id') + + # Download the file from the direct download URL + response = niquests.get(download_url) + + return response.text + @tool @safe_tool def get_folder_tree(depth: int): @@ -56,6 +79,7 @@ def create_public_sharing_link(path: str): return [ get_file_content, + get_file_content_by_file_link, get_folder_tree, create_public_sharing_link, ] diff --git a/ex_app/lib/all_tools/image_gen.py b/ex_app/lib/all_tools/image_gen.py index 979ae49..6da44a0 100644 --- a/ex_app/lib/all_tools/image_gen.py +++ b/ex_app/lib/all_tools/image_gen.py @@ -3,7 +3,6 @@ from langchain_core.tools import tool from nc_py_api import Nextcloud -from ex_app.lib.all_tools.lib.files import get_file_id_from_file_url from ex_app.lib.all_tools.lib.task_processing import run_task from ex_app.lib.all_tools.lib.decorator import safe_tool @@ -14,7 +13,7 @@ async def get_tools(nc: Nextcloud): @safe_tool def generate_image(input: str) -> str: """ - Generate an image with the input string as description + Generate an image using AI from a text description input :param text: the instructions for the image generation :return: a download link to the generated image """ diff --git a/ex_app/lib/all_tools/mail.py b/ex_app/lib/all_tools/mail.py index c37109e..f4b964a 100644 --- a/ex_app/lib/all_tools/mail.py +++ b/ex_app/lib/all_tools/mail.py @@ -16,11 +16,11 @@ async def get_tools(nc: Nextcloud): @dangerous_tool def send_email(subject: str, body: str, account_id: int, from_email: str, to_emails: list[str]): """ - Send an email to a list of emails + Send an email to a list of email addresses :param subject: The subject of the email :param body: The body of the email :param account_id: The id of the account to send from, obtainable via get_mail_account_list - :param to_emails: The emails to send + :param to_emails: The email addresses to send the message to """ i = 0 body_with_ai_note = f"{body}\n\n---\n\nThis email was sent by Nextcloud AI Assistant." @@ -47,7 +47,7 @@ def send_email(subject: str, body: str, account_id: int, from_email: str, to_ema @safe_tool def get_mail_account_list(): """ - Lists all available email accounts including their account id + Lists all available email accounts of the current user including their account id :param subject: The subject of the email :param body: The body of the email :param account_id: The id of the account to send from diff --git a/ex_app/lib/all_tools/talk.py b/ex_app/lib/all_tools/talk.py index 814f941..bd968da 100644 --- a/ex_app/lib/all_tools/talk.py +++ b/ex_app/lib/all_tools/talk.py @@ -12,7 +12,7 @@ async def get_tools(nc: Nextcloud): @safe_tool def list_talk_conversations(): """ - List all conversations in talk + List all conversations of the current user in the Nextcloud Talk app :return: returns a list of conversation names, e.g. ["Conversation 1", "Conversation 2"] """ conversations = nc.talk.get_user_conversations() @@ -23,7 +23,7 @@ def list_talk_conversations(): @dangerous_tool def create_public_conversation(conversation_name: str) -> str: """ - Create a new talk conversation + Create a new conversation in the Nextcloud Talk app :param conversation_name: The name of the conversation to create :return: The URL of the new conversation """ @@ -36,7 +36,7 @@ def create_public_conversation(conversation_name: str) -> str: @dangerous_tool def send_message_to_conversation(conversation_name: str, message: str): """ - List all conversations in talk + Send a message to a conversation in the Nextcloud talk app :param message: The message to send :param conversation_name: The name of the conversation to send a message to :return: @@ -52,7 +52,7 @@ def send_message_to_conversation(conversation_name: str, message: str): @safe_tool def list_messages_in_conversation(conversation_name: str, n_messages: int = 30): """ - List messages of a conversation in talk + List messages of a conversation in the Nextcloud Talk app :param conversation_name: The name of the conversation to list messages of (can only be one conversation per Tool call, obtainable via list_talk_conversations) :param n_messages: The number of messages to receive :return: A list of messages