Merge pull request #18 from Fosowl/dev

Fix various issues, requirement not up to date, search not working, file search bug
This commit is contained in:
Martin 2025-03-11 12:50:14 +01:00 committed by GitHub
commit 4ed24669d9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 89 additions and 51 deletions

View File

@ -3,9 +3,9 @@ is_local = True
provider_name = ollama
provider_model = deepseek-r1:14b
provider_server_address = 127.0.0.1:5000
agent_name = jarvis
agent_name = Friday
recover_last_session = True
save_session = False
speak = True
listen = False
work_dir = None
work_dir = none

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 254 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

View File

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 107 KiB

View File

@ -13,7 +13,10 @@ flask==3.1.0
soundfile==0.13.1
protobuf==3.20.3
termcolor==2.5.0
ipython==9.0.2
gliclass==0.1.8
pyaudio==0.2.14
librosa==0.10.2.post1
# if use chinese
ordered_set
pypinyin

View File

@ -30,6 +30,9 @@ setup(
"protobuf==3.20.3",
"termcolor==2.5.0",
"gliclass==0.1.8",
"ipython==7.16.1",
"pyaudio-0.2.14",
"librosa==0.10.2.post1"
],
extras_require={
"chinese": [

View File

@ -3,10 +3,13 @@ from typing import Tuple, Callable
from abc import abstractmethod
import os
import random
import time
from sources.memory import Memory
from sources.utility import pretty_print
random.seed(time.time())
class executorResult:
"""
A class to store the result of a tool execution.
@ -106,7 +109,6 @@ class Agent():
if speech_module is None:
return
messages = ["Please be patient sir, I am working on it.",
"At it, sir. In the meantime, how about a joke?",
"Computing... I recommand you have a coffee while I work.",
"Hold on, Im crunching numbers.",
"Working on it sir, please let me think."]

View File

@ -18,22 +18,23 @@ class CasualAgent(Agent):
"file_finder": FileFinder(),
"bash": BashInterpreter()
}
self.role = "talking, advices and philosophical"
self.role = "talking, advices, events and philosophical"
def process(self, prompt, speech_module) -> str:
complete = False
exec_success = False
self.memory.push('user', prompt)
self.wait_message(speech_module)
while not complete:
if exec_success:
complete = True
animate_thinking("Thinking...", color="status")
answer, reasoning = self.llm_request()
exec_success, _ = self.execute_modules(answer)
answer = self.remove_blocks(answer)
self.last_answer = answer
complete = True
for tool in self.tools.values():
if tool.found_executable_blocks():
complete = False # AI read results and continue the conversation
return answer, reasoning
if __name__ == "__main__":

View File

@ -32,6 +32,7 @@ class CoderAgent(Agent):
animate_thinking("Thinking...", color="status")
self.wait_message(speech_module)
answer, reasoning = self.llm_request()
animate_thinking("Executing code...", color="status")
exec_success, _ = self.execute_modules(answer)
answer = self.remove_blocks(answer)
self.last_answer = answer

View File

@ -30,6 +30,10 @@ class FileAgent(Agent):
exec_success, _ = self.execute_modules(answer)
answer = self.remove_blocks(answer)
self.last_answer = answer
complete = True
for name, tool in self.tools.items():
if tool.found_executable_blocks():
complete = False # AI read results and continue the conversation
return answer, reasoning
if __name__ == "__main__":

View File

@ -81,6 +81,9 @@ class PlannerAgent(Agent):
speech_module.speak(f"I will {task_name}. I assigned the {task['agent']} agent to the task.")
try:
self.agents[task['agent'].lower()].process(agent_prompt, None)
pretty_print(f"-- Agent answer ---\n\n", color="output")
self.agents[task['agent'].lower()].show_answer()
pretty_print(f"\n\n", color="output")
except Exception as e:
pretty_print(f"Error: {e}", color="failure")
speech_module.speak(f"I encountered an error: {e}")

View File

@ -80,7 +80,7 @@ if __name__ == "__main__":
Hey could you search the web for the latest news on the stock market ?
""",
"""
hey can you give dating advice ?
hey can you give give a list of the files in the current directory ?
""",
"""
Make a cool game to illustrate the current relation between USA and europe

View File

@ -40,8 +40,7 @@ class Speech():
)
for i, (gs, ps, audio) in enumerate(generator):
audio_file = 'sample.wav'
print(audio_file)
display(Audio(data=audio, rate=24000, autoplay=i==0))
display(Audio(data=audio, rate=24000, autoplay=i==0), display_id=False)
sf.write(audio_file, audio, 24000) # save each audio file
if platform.system().lower() != "windows":
subprocess.call(["afplay", audio_file])

View File

@ -1,5 +1,6 @@
import sys
import os
import re
from io import StringIO
@ -25,10 +26,15 @@ class PyInterpreter(Tools):
return "Code rejected by user."
stdout_buffer = StringIO()
sys.stdout = stdout_buffer
global_vars = {
'__builtins__': __builtins__,
'os': os,
'sys': sys,
}
code = '\n\n'.join(codes)
try:
try:
buffer = exec(code)
buffer = exec(code, global_vars)
if buffer is not None:
output = buffer + '\n'
except Exception as e:

View File

@ -62,7 +62,6 @@ class FileFinder(Tools):
file_path = None
excluded_files = [".pyc", ".o", ".so", ".a", ".lib", ".dll", ".dylib", ".so", ".git"]
for root, dirs, files in os.walk(directory_path):
print(f"Root: {root}, Files: {files}")
for file in files:
if any(excluded_file in file for excluded_file in excluded_files):
continue

View File

@ -39,6 +39,7 @@ class Tools():
self.messages = []
self.config = configparser.ConfigParser()
self.current_dir = self.create_work_dir()
self.excutable_blocks_found = False
def check_config_dir_validity(self):
"""
@ -129,6 +130,14 @@ class Tools():
print(f"Saving code block to: {save_path}")
with open(os.path.join(directory, save_path_file), 'w') as f:
f.write(block)
def found_executable_blocks(self):
"""
Check if executable blocks were found.
"""
tmp = self.excutable_blocks_found
self.excutable_blocks_found = False
return tmp
def load_exec_block(self, llm_text: str) -> tuple[list[str], str | None]:
"""
@ -178,6 +187,7 @@ class Tools():
if ':' in content.split('\n')[0]:
save_path = content.split('\n')[0].split(':')[1]
content = content[content.find('\n')+1:]
self.excutable_blocks_found = True
code_blocks.append(content)
start_index = end_pos + len(end_tag)
return code_blocks, save_path

View File

@ -6,9 +6,13 @@ import dotenv
dotenv.load_dotenv()
if __name__ == "__main__":
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from utility import animate_thinking, pretty_print
from tools import Tools
else:
from sources.tools.tools import Tools
from sources.utility import animate_thinking, pretty_print
class webSearch(Tools):
def __init__(self, api_key: str = None):
@ -24,6 +28,7 @@ class webSearch(Tools):
return "Error: No SerpApi key provided."
for block in blocks:
query = block.strip()
pretty_print(f"Searching for: {query}", color="status")
if not query:
return "Error: No search query provided."
@ -32,19 +37,21 @@ class webSearch(Tools):
params = {
"q": query,
"api_key": self.api_key,
"num": 1,
"num": 100,
"output": "json"
}
response = requests.get(url, params=params)
response.raise_for_status()
data = response.json()
results = []
if "organic_results" in data and len(data["organic_results"]) > 0:
first_result = data["organic_results"][0]
title = first_result.get("title", "No title")
snippet = first_result.get("snippet", "No snippet available")
link = first_result.get("link", "No link available")
return f"Title: {title}\nSnippet: {snippet}\nLink: {link}"
for result in data["organic_results"][:50]:
title = result.get("title", "No title")
snippet = result.get("snippet", "No snippet available")
link = result.get("link", "No link available")
results.append(f"Title: {title}\nSnippet: {snippet}\nLink: {link}")
return "\n\n".join(results)
else:
return "No results found for the query."
except requests.RequestException as e:
@ -65,6 +72,6 @@ class webSearch(Tools):
if __name__ == "__main__":
search_tool = webSearch(api_key=os.getenv("SERPAPI_KEY"))
query = "when did covid start"
result = search_tool.execute(query, safety=True)
result = search_tool.execute([query], safety=True)
feedback = search_tool.interpreter_feedback(result)
print(feedback)

View File

@ -2,6 +2,9 @@
from colorama import Fore
from termcolor import colored
import platform
import threading
import itertools
import time
def pretty_print(text, color = "info"):
@ -49,44 +52,41 @@ def pretty_print(text, color = "info"):
color = "default"
print(colored(text, color_map[color]))
def animate_thinking(text="thinking...", color="status", duration=2):
def animate_thinking(text, color="status", duration=2):
"""
Display an animated "thinking..." indicator.
Display an animated "thinking..." indicator in a separate thread.
Args:
text (str): Text to display (default: "thinking...")
color (str): Color for the text (matches pretty_print colors)
text (str): Text to display
color (str): Color for the text
duration (float): How long to animate in seconds
"""
import time
import itertools
def _animate():
color_map = {
"success": (Fore.GREEN, "green"),
"failure": (Fore.RED, "red"),
"status": (Fore.LIGHTGREEN_EX, "light_green"),
"code": (Fore.LIGHTBLUE_EX, "light_blue"),
"warning": (Fore.YELLOW, "yellow"),
"output": (Fore.LIGHTCYAN_EX, "cyan"),
"default": (Fore.RESET, "black"),
"info": (Fore.CYAN, "cyan")
}
color_map = {
"success": (Fore.GREEN, "green"),
"failure": (Fore.RED, "red"),
"status": (Fore.LIGHTGREEN_EX, "light_green"),
"code": (Fore.LIGHTBLUE_EX, "light_blue"),
"warning": (Fore.YELLOW, "yellow"),
"output": (Fore.LIGHTCYAN_EX, "cyan"),
"default": (Fore.RESET, "black"),
"info": (Fore.CYAN, "cyan")
}
fore_color, term_color = color_map[color]
spinner = itertools.cycle(['', '', '', '', '', '', '', '', '', ''])
end_time = time.time() + duration
if color not in color_map:
color = "info"
fore_color, term_color = color_map[color]
spinner = itertools.cycle(['', '', '', '', '', '', '', '', '', ''])
end_time = time.time() + duration
while time.time() < end_time:
symbol = next(spinner)
if platform.system().lower() != "windows":
print(f"\r{fore_color}{symbol} {text}{Fore.RESET}", end="", flush=True)
else:
print(colored(f"\r{symbol} {text}", term_color), end="", flush=True)
time.sleep(0.1)
print()
while time.time() < end_time:
symbol = next(spinner)
if platform.system().lower() != "windows":
print(f"\r{fore_color}{symbol} {text}{Fore.RESET}", end="", flush=True)
else:
print(colored(f"\r{symbol} {text}", term_color), end="", flush=True)
time.sleep(0.1)
print()
animation_thread = threading.Thread(target=_animate)
animation_thread.daemon = True
animation_thread.start()
def timer_decorator(func):
"""