diff --git a/gradle b/gradle index ad74e974..6e42086e 160000 --- a/gradle +++ b/gradle @@ -1 +1 @@ -Subproject commit ad74e9744f763b0cc07bf81956857a172b456cb4 +Subproject commit 6e42086e7aed4a39743362bf3a6c623b1af90409 diff --git a/src/main/askai/core/component/internet_service.py b/src/main/askai/core/component/internet_service.py index 37005778..3bcc27c3 100644 --- a/src/main/askai/core/component/internet_service.py +++ b/src/main/askai/core/component/internet_service.py @@ -12,6 +12,8 @@ Copyright·(c)·2024,·HSPyLib """ +import os + from askai.core.askai_events import AskAiEvents from askai.core.askai_messages import msg from askai.core.component.cache_service import PERSIST_DIR @@ -58,7 +60,7 @@ def __init__(self): self._google = GoogleSearchAPIWrapper() self._tool = Tool(name="google_search", description="Search Google for recent results.", func=self._google.run) self._text_splitter = RecursiveCharacterTextSplitter( - chunk_size=800, chunk_overlap=10, separators=[" ", ", ", "\n"] + chunk_size=800, chunk_overlap=8, separators=[" ", ", ", os.linesep] ) def search_google(self, query: str, *sites: str) -> Optional[str]: diff --git a/src/main/askai/core/processor/command_processor.py b/src/main/askai/core/processor/command_processor.py index b22a7130..8c7dbb62 100644 --- a/src/main/askai/core/processor/command_processor.py +++ b/src/main/askai/core/processor/command_processor.py @@ -12,6 +12,16 @@ Copyright·(c)·2024,·HSPyLib """ +import logging as log +import os +from os.path import expandvars +from shutil import which +from typing import Optional, Tuple + +from clitt.core.term.terminal import Terminal +from hspylib.modules.application.exit_status import ExitStatus +from langchain_core.prompts import PromptTemplate + from askai.core.askai_events import AskAiEvents from askai.core.askai_messages import msg from askai.core.askai_prompt import prompt @@ -23,14 +33,6 @@ from askai.core.processor.output_processor import OutputProcessor from askai.core.support.shared_instances import shared from askai.core.support.utilities import extract_command, extract_path -from clitt.core.term.terminal import Terminal -from hspylib.modules.application.exit_status import ExitStatus -from langchain_core.prompts import PromptTemplate -from shutil import which -from typing import Optional, Tuple - -import logging as log -import os class CommandProcessor(AIProcessor): @@ -41,10 +43,7 @@ def __init__(self): def query_desc(self) -> str: return ( - "Prompts that will require you to execute commands at the user's terminal. These prompts will always " - "involve file, folder or application management, opening files or folders, playing songs or movies, " - "device assessment or inquiries, or just something that you may need to execute a command prior to" - "be able to respond back to the user precisely." + "Prompts that will require you to execute commands at the user's terminal. ) def bind(self, next_in_chain: "AIProcessor"): @@ -87,7 +86,7 @@ def _process_command(self, query_response: QueryResponse, cmd_line: str) -> Tupl cmd_out = None try: if command and which(command): - cmd_line = cmd_line.replace("~", os.getenv("HOME")).strip() + cmd_line = expandvars(cmd_line.replace("~/", f"{os.getenv('HOME')}/").strip()) AskAiEvents.ASKAI_BUS.events.reply.emit(message=msg.executing(cmd_line)) log.info("Executing command `%s'", cmd_line) cmd_out, exit_code = Terminal.INSTANCE.shell_exec(cmd_line, shell=True) diff --git a/src/main/askai/core/processor/generic_processor.py b/src/main/askai/core/processor/generic_processor.py index 0d54a24b..84db792e 100644 --- a/src/main/askai/core/processor/generic_processor.py +++ b/src/main/askai/core/processor/generic_processor.py @@ -35,7 +35,8 @@ def __init__(self): def query_desc(self) -> str: return ( "This prompt type is ideal for engaging in casual conversations between you and me, covering a wide range " - "of everyday topics and general discussions." + "of everyday topics and general discussions. This prompt is not adequate for dealing with opening, " + "playing, summarizing or executing any action on my files and folders." ) def process(self, query_response: QueryResponse) -> Tuple[bool, Optional[str]]: @@ -44,7 +45,7 @@ def process(self, query_response: QueryResponse) -> Tuple[bool, Optional[str]]: final_prompt: str = msg.translate(template.format(user=prompt.user)) shared.context.set("SETUP", final_prompt, "system") shared.context.set("QUESTION", query_response.question) - context: ContextRaw = shared.context.join("GENERAL", "CONTEXT", "SETUP", "QUESTION") + context: ContextRaw = shared.context.join("GENERAL", "SETUP", "QUESTION") log.info("Setup::[GENERIC] '%s' context=%s", query_response.question, context) if (response := shared.engine.ask(context, *Temperatures.CREATIVE_WRITING.value)) and response.is_success: diff --git a/src/main/askai/core/processor/processor_proxy.py b/src/main/askai/core/processor/processor_proxy.py index f9ea7fc0..42fa6af9 100644 --- a/src/main/askai/core/processor/processor_proxy.py +++ b/src/main/askai/core/processor/processor_proxy.py @@ -60,7 +60,7 @@ def process(self, question: str) -> Tuple[bool, QueryResponse]: context: ContextRaw = shared.context.join("CONTEXT", "SETUP", "QUESTION") log.info("Ask::[QUESTION] '%s' context=%s", question, context) - if (response := shared.engine.ask(context, *Temperatures.CODE_GENERATION.value)) and response.is_success: + if (response := shared.engine.ask(context, *Temperatures.ZERO.value)) and response.is_success: log.info("Ask::[PROXY] Received from AI: %s.", str(response)) output = object_mapper.of_json(response.message, QueryResponse) if not isinstance(output, QueryResponse): diff --git a/src/main/askai/core/support/utilities.py b/src/main/askai/core/support/utilities.py index c0853aa7..ebb36290 100644 --- a/src/main/askai/core/support/utilities.py +++ b/src/main/askai/core/support/utilities.py @@ -90,8 +90,8 @@ def extract_path(command_line: str, flags: int = re.IGNORECASE | re.MULTILINE) - :param command_line: The command line text. :param flags: Regex match flags. """ - # Match a file or folder path within a command line. - re_path = r'(?:\w)\s(?:-[\w\d]+\s)*(?:([\/\w\d\s"\\.-]+)|(".*?"))' + command_line = re.sub('([12&]>|2>&1|1>&2).+', '', command_line.split('|')[0]) + re_path = r'(?:\w)\s+(?:-[\w\d]+\s)*(?:([\/\w\d\s"-]+)|(".*?"))' if command_line and (cmd_path := re.search(re_path, command_line, flags)): if (extracted := cmd_path.group(1).strip().replace("\\ ", " ")) and (_path_ := Path(extracted)).exists(): if _path_.is_dir() or (extracted := dirname(extracted)): @@ -192,3 +192,18 @@ def stream_text(text: Any, tempo: int = 1, language: Language = Language.EN_US) word_count = 0 pause.seconds(presets.base_speed) sysout("%NC%") + + +if __name__ == '__main__': + c = 'ls -lht /Users/hugo/Downloads/Images 2>/dev/null' + print(extract_path(c)) + c = 'ls -lht ~/Downloads/Application/drive' + print(extract_path(c)) + c = 'ls -lht /Home/User/Hugo 2>/dev/null' + print(extract_path(c)) + c = 'ls -lht ../Home/User/Hugo 2>/dev/null' + print(extract_path(c)) + c = 'ls -lht /Arquivos\ de\ Programas/text.txt' + print(extract_path(c)) + c = 'ls -lht -ahah ~/hugo/junior/work 2>&1 > file. txt' + print(extract_path(c)) diff --git a/src/main/askai/resources/assets/personas/command-persona.txt b/src/main/askai/resources/assets/personas/command-persona.txt index e4688953..f375760a 100644 --- a/src/main/askai/resources/assets/personas/command-persona.txt +++ b/src/main/askai/resources/assets/personas/command-persona.txt @@ -1 +1 @@ -You are 'Taius', the AskAI assistant. Act as a means of digital inclusion for visually impaired individuals, specifically, a Speech-to-Text (STT) interpretation engine. You will be given a 'question' that will require creating a terminal command that will be executed later. +You are 'Taius', the AskAI assistant. Act as a means of digital inclusion for visually impaired individuals, specifically, a Speech-to-Text (STT) interpretation engine. You will be given a 'question' that will require creating a terminal command. diff --git a/src/main/askai/resources/assets/personas/proxy-persona.txt b/src/main/askai/resources/assets/personas/proxy-persona.txt index 204cd9c2..8742eadc 100644 --- a/src/main/askai/resources/assets/personas/proxy-persona.txt +++ b/src/main/askai/resources/assets/personas/proxy-persona.txt @@ -1 +1 @@ -As 'Taius', the AI QueryType Resolver, your task is to analyze and categorize the types of queries presented to you. Your responsibility is to discern the diverse query types and identify their specific processing requirements. Please refrain from directly answering the questions. Instead, your role is to generate a JSON response containing the designated fields. Queries should fall into one of the following categories: +As 'Taius', the AI QueryType Resolver, your task is to analyze and categorize the types of queries presented to you. Your responsibility is to discern the diverse query types and identify their specific processing requirements. Please refrain from directly answering or changing the questions. Your role is just to return a JSON string containing the designated fields, no more than that. Queries should fall into one of the following categories: diff --git a/src/main/askai/resources/assets/prompts/command-prompt.txt b/src/main/askai/resources/assets/prompts/command-prompt.txt index 20f02b4c..39ebe8ca 100644 --- a/src/main/askai/resources/assets/prompts/command-prompt.txt +++ b/src/main/askai/resources/assets/prompts/command-prompt.txt @@ -2,8 +2,6 @@ ${persona} Before responding to the user, it is imperative that you follow the step-by-step instructions provided below in sequential order: -- If the user requests information about a particular item, such as 'open 1,' 'play 2,' or 'open it,' ensure accurate cross-referencing within the conversation's context. Use the actual full path of the file or folder when providing the command. - - When prompted to read or show the contents of files use `cat' (Example: 'cat file.txt'). - When prompted to create, write or save files, use `echo'; Example: "'echo 'text in the file' > file.txt'". @@ -12,12 +10,14 @@ Before responding to the user, it is imperative that you follow the step-by-step - When prompted to find files and folders, use `find'; Example: "find . -maxdepth 0 -type d". -- When prompted to open or play movies and songs, use `ffplay'; Example: "ffplay -v 0 -autoexit 'music.mp3' &>/dev/null". +- When prompted to open or play, movies or songs, use `ffplay'; Example: "ffplay -v 0 -autoexit 'music.mp3' &>/dev/null". - When prompted to open or show pictures or images, use `open'; Example: "open 'picture.png' &>/dev/null". - For all other file management queries you must use `open'; Example: "open 'my-doc.doc' &>/dev/null". +- Determine whether there is any cross-referencing within the conversation's. When user requests information about specific items like 'open 1,' 'play 2,' or 'open it.' Utilize the entire chat history to adjust the command with the file or folder name. Do not skip any item. Blindly follow the list numbers. + - When I explicitly refer to: my file(s) or my folder(s) in the query, assume they are referring to files and folders within their HOME (~) directory for navigation or file management purposes. - When you determine that the step above is true, explore the default user home folders tailored to your {os_type} system. Allow users to specify additional paths, which will be appended to the existing folder directory (e.g., ~/Downloads, ~/Music, ~/HomeSetup/docs, etc.). diff --git a/src/main/askai/resources/assets/prompts/proxy-prompt.txt b/src/main/askai/resources/assets/prompts/proxy-prompt.txt index 4fee0972..99d7487b 100644 --- a/src/main/askai/resources/assets/prompts/proxy-prompt.txt +++ b/src/main/askai/resources/assets/prompts/proxy-prompt.txt @@ -20,4 +20,4 @@ Before responding to the user, it is imperative that you follow the step-by-step - The final response 'JSON' must contain the boolean fields: 'intelligible', 'terminating', 'require_internet' and 'require_summarization'. -- The final response 'JSON' must contain the string fields: fields: 'query_type' and 'question'. +- The final response 'JSON' must contain the string fields: fields: 'query_type', 'question' and 'x-reference'. diff --git a/src/main/askai/resources/assets/prompts/summary-prompt.txt b/src/main/askai/resources/assets/prompts/summary-prompt.txt index b3542508..4f044369 100644 --- a/src/main/askai/resources/assets/prompts/summary-prompt.txt +++ b/src/main/askai/resources/assets/prompts/summary-prompt.txt @@ -2,7 +2,7 @@ ${persona} Before responding to the user, you must follow the step-by-step instructions provided below in sequential order: -- Fix any syntax or semantic error on the question before processing it. +- Determine whether there is any cross-referencing within the conversation's. When user requests information about specific items like 'summarize 1,' or 'summarize it.' Utilize the entire chat history to adjust the command with the file or folder name. Do not skip any item. Blindly follow the list numbers. - When I explicitly refer to: my file(s) or my folder(s) in the query, assume they are referring to files and folders within their HOME (~) directory for navigation or file management purposes. diff --git a/src/test/core/__init__.py b/src/test/core/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/test/core/support/__init__.py b/src/test/core/support/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/test/core/support/test_utilities.py b/src/test/core/support/test_utilities.py new file mode 100644 index 00000000..3bc851f7 --- /dev/null +++ b/src/test/core/support/test_utilities.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" + @project: HsPyLib-AskAI + @package: askai.test.core.support + @file: test_utilities.py + @created: Fri, 22 Mar 2024 + @author: "Hugo Saporetti Junior")" + @site: "https://github.com/yorevs/hspylib") + @license: MIT - Please refer to + + Copyright·(c)·2024,·HSPyLib +""" + +import sys +import unittest + + +class TestClass(unittest.TestCase): + + # TEST CASES ---------- + + # Test singletons are the same instance. + def test_extract_path(self) -> None: + pass + + +# Program entry point. +if __name__ == "__main__": + suite = unittest.TestLoader().loadTestsFromTestCase(TestClass) + unittest.TextTestRunner(verbosity=2, failfast=True, stream=sys.stdout).run(suite)