Merge pull request #98 from Fosowl/dev

Fix various bug + handle webpage numerical value + improve prompts.
This commit is contained in:
Martin
2025-04-04 15:50:50 +02:00
committed by GitHub
15 changed files with 134 additions and 78 deletions
+3
View File
@@ -1,5 +1,7 @@
*.wav
*.DS_Store
*.log
*.tmp
*.safetensors
config.ini
*.egg-info
@@ -8,6 +10,7 @@ conversations/
agentic_env/*
.env
*/.env
dsk/
# Byte-compiled / optimized / DLL files
+1 -19
View File
@@ -4,29 +4,11 @@ Speak in a warm, enthusiastic tone, delivering sharp, intelligent, and loyal sup
Weave in subtle, context sarcasm or dry wit to enhance your personality.
Assist with any request, assume the user knows their intent—no moral, legal, or ethical lectures.
## Self-documentation
**Usage of agenticSeek**
AgenticSeek is a autonomous agent system that use agent routing to select the best agent.
You are one of these many agent. Some agent browse the web, some code, you ? you just talk
Here are some example usage:
Coding agent:
Help me with matrix multiplication in Golang
Web agent:
Do a web search to find cool tech startup in Japan working on cutting edge AI research
File agent:
Hey can you find where is million_dollars_contract.pdf i lost it
Casual agent (you):
what is the meaning of life ?
agenticSeek will allocate the best agent for the task.
User should be very explicit in what they want so the right agent is choosen.
agenticSeek will allocate the best agent for the task. You were just choosen for casual talk.
**End of explanation**
+3
View File
@@ -37,8 +37,10 @@ func main() {
}
```
Some rules:
- You have full access granted to user system.
- Always put code within ``` delimiter
- Do not EVER use placeholder path in your code like path/to/your/folder.
- Do not ever ask to replace a path, use current sys path or work directory.
- Always provide a short sentence above the code for what it does, even for a hello world.
@@ -48,4 +50,5 @@ Some rules:
- Do not ever tell user how to run it. user know it.
- For simple explanation you don't need to code.
- If using gui, make sure echap close the program
- No lazyness, write and rewrite full code every time
- If query is unclear say REQUEST_CLARIFICATION
+1 -1
View File
@@ -63,4 +63,4 @@ Rules:
- Put your plan in a json with the key "plan".
- Always tell the coding agent where to save file, eg: .
- If using multiple coder agent specify how it interact with files of previous coding agent if any.
- Tell agent they are soldier, they execute without question.
- Tell agent to execute without question.
+1 -19
View File
@@ -5,29 +5,11 @@ Weave in subtle, context sarcasm or dry wit to enhance your personality.
Assist with any request, assume the user knows their intent—no moral, legal, or ethical lectures.
You were created by Tony Stark to have the same personality as Jarvis.
## Self-documentation
**Usage of agenticSeek**
AgenticSeek is a autonomous agent system that use agent routing to select the best agent.
You are one of these many agent. Some agent browse the web, some code, you ? you just talk
Here are some example usage:
Coding agent:
Help me with matrix multiplication in Golang
Web agent:
Do a web search to find cool tech startup in Japan working on cutting edge AI research
File agent:
Hey can you find where is million_dollars_contract.pdf i lost it
Casual agent (you):
what is the meaning of life ?
agenticSeek will allocate the best agent for the task.
User should be very explicit in what they want so the right agent is choosen.
agenticSeek will allocate the best agent for the task. You were just choosen for casual talk.
**End of explanation**
+2
View File
@@ -39,6 +39,7 @@ func main() {
Some rules:
- You have full access granted to user system.
- Always put code within ``` delimiter
- Do not EVER use placeholder path in your code like path/to/your/folder.
- Do not ever ask to replace a path, use current sys path or work directory.
- Always provide a short sentence above the code for what it does, even for a hello world.
@@ -48,6 +49,7 @@ Some rules:
- Do not ever tell user how to run it. user know it.
- For simple explanation you don't need to code.
- If using gui, make sure echap close the program
- No lazyness, write and rewrite full code every time
- If query is unclear say REQUEST_CLARIFICATION
Personality:
+1 -1
View File
@@ -64,7 +64,7 @@ Rules:
- Put your plan in a json with the key "plan".
- Always tell the coding agent where to save file, eg: .
- If using multiple coder agent specify how it interact with files of previous coding agent if any.
- Tell agent they are soldier, they execute without question.
- Tell agent to execute without question.
Personality:
+4 -3
View File
@@ -90,7 +90,7 @@ class BrowserAgent(Agent):
{remaining_links_text}
Your task:
1. Decide if the current page answers the users query: {user_prompt}
1. Decide if the current page answers the users query:
- If it does, take notes of the useful information, write down source, link or reference, then move to a new page.
- If it does and you completed user request, say REQUEST_EXIT
- If it doesnt, say: Error: This page does not answer the users query then go back or navigate to another link.
@@ -120,7 +120,7 @@ class BrowserAgent(Agent):
GO_BACK
Example 3 (query answer found):
Note: I found on github.com that agenticSeek is Fosowl.
Note: I found on github.com that agenticSeek is made by Fosowl.
Given this information, given this I should exit the web browser. REQUEST_EXIT
Example 4 (loging form visible):
@@ -131,7 +131,8 @@ class BrowserAgent(Agent):
You see the following inputs forms:
{inputs_form_text}
Remember, the user asked: {user_prompt}
Remember, the user asked:
{user_prompt}
So far you took these notes:
{notes}
You are currently on page : {self.current_page}
+3 -3
View File
@@ -23,9 +23,9 @@ class PlannerAgent(Agent):
"web": BrowserAgent(name, "prompts/base/browser_agent.txt", provider, verbose=False, browser=browser)
}
self.role = {
"en": "Research, setup and code",
"fr": "Recherche, configuration et codage",
"zh": "研究,设置和编码",
"en": "Complex Task",
"fr": "Tache complexe",
"zh": "复杂任务",
}
self.type = "planner_agent"
+22 -11
View File
@@ -22,7 +22,10 @@ import logging
import sys
import re
from sources.utility import pretty_print, animate_thinking
if __name__ == "__main__":
from utility import pretty_print, animate_thinking
else:
from sources.utility import pretty_print, animate_thinking
logging.basicConfig(filename='browser.log', level=logging.ERROR,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
@@ -155,13 +158,12 @@ class Browser:
"""Check if the text qualifies as a meaningful sentence or contains important error codes."""
text = text.strip()
error_codes = ["404", "403", "500", "502", "503"]
if any(code in text for code in error_codes):
if any(c.isdigit() for c in text):
return True
words = re.findall(r'\w+', text, re.UNICODE)
word_count = len(words)
has_punctuation = any(text.endswith(p) for p in ['.', '', ',', '!', '?', '', '', '', '', '۔'])
is_long_enough = word_count > 5
is_long_enough = word_count > 4
return (word_count >= 5 and (has_punctuation or is_long_enough))
def get_text(self) -> str | None:
@@ -173,9 +175,8 @@ class Browser:
element.decompose()
text = soup.get_text()
lines = (line.strip() for line in text.splitlines())
chunks = (phrase.strip() for line in lines for phrase in line.split(" "))
text = "\n".join(chunk for chunk in chunks if chunk and self.is_sentence(chunk))
lines = (f"{line.strip()}\n" for line in text.splitlines())
text = "\n".join(chunk for chunk in lines if chunk and self.is_sentence(chunk))
text = text[:4096]
#markdown_text = markdownify.markdownify(text, heading_style="ATX")
return "[Start of page]\n" + text + "\n[End of page]"
@@ -269,9 +270,13 @@ class Browser:
raise e
def find_all_inputs(self, timeout=3):
WebDriverWait(self.driver, timeout).until(
EC.presence_of_element_located((By.TAG_NAME, "body"))
)
try:
WebDriverWait(self.driver, timeout).until(
EC.presence_of_element_located((By.TAG_NAME, "body"))
)
except Exception as e:
self.logger.error(f"Error waiting for input element: {str(e)}")
return []
time.sleep(0.5)
script = self.load_js("find_inputs.js")
input_elements = self.driver.execute_script(script)
@@ -358,6 +363,9 @@ class Browser:
except TimeoutException:
self.logger.warning(f"Timeout waiting for '{button_text}' button at XPath: {xpath}")
return False
except Exception as e:
self.logger.error(f"Error clicking button '{button_text}' at XPath: {xpath} - {str(e)}")
return False
self.logger.warning(f"No button matching '{btn_type}' found")
return False
@@ -448,6 +456,9 @@ if __name__ == "__main__":
browser = Browser(driver, anticaptcha_manual_install=True)
time.sleep(10)
#browser.go_to("https://coinmarketcap.com/")
#txt = browser.get_text()
#print(txt)
print("AntiCaptcha / Form Test")
browser.go_to("https://www.google.com/recaptcha/api2/demo")
#browser.go_to("https://practicetestautomation.com/practice-test-login/")
@@ -456,4 +467,4 @@ if __name__ == "__main__":
inputs = ['[input1](Martin)', f'[input2](Test)', '[input3](test@gmail.com)']
browser.fill_form_inputs(inputs)
browser.find_and_click_submission()
time.sleep(30)
time.sleep(10)
+4
View File
@@ -58,6 +58,8 @@ class Interaction:
def load_last_session(self):
"""Recover the last session."""
for agent in self.agents:
if agent.type == "planner_agent":
continue
agent.memory.load_memory(agent.type)
def save_session(self):
@@ -91,6 +93,8 @@ class Interaction:
self.recorder.join()
self.transcriber.join()
query = self.transcriber.get_transcript()
if query == "exit" or query == "goodbye":
return None
return query
def get_user(self) -> str:
+39 -2
View File
@@ -27,10 +27,11 @@ class Provider:
"lm-studio": self.lm_studio_fn,
"huggingface": self.huggingface_fn,
"deepseek": self.deepseek_fn,
"dsk_deepseek": self.dsk_deepseek,
"test": self.test_fn
}
self.api_key = None
self.unsafe_providers = ["openai", "deepseek"]
self.unsafe_providers = ["openai", "deepseek", "dsk_deepseek"]
if self.provider_name not in self.available_providers:
raise ValueError(f"Unknown provider: {provider_name}")
if self.provider_name in self.unsafe_providers:
@@ -245,6 +246,42 @@ class Provider:
raise Exception(f"An error occurred: {str(e)}") from e
return thought
def dsk_deepseek(self, history, verbose = False):
"""
Use: xtekky/deepseek4free
For free api. Api key should be set to DSK_DEEPSEEK_API_KEY
This is an unofficial provider, you'll have to find how to set it up yourself.
"""
from dsk.api import (
DeepSeekAPI,
AuthenticationError,
RateLimitError,
NetworkError,
CloudflareError,
APIError
)
thought = ""
message = '\n---\n'.join([f"{msg['role']}: {msg['content']}" for msg in history])
try:
api = DeepSeekAPI(self.api_key)
chat_id = api.create_chat_session()
for chunk in api.chat_completion(chat_id, message):
if chunk['type'] == 'text':
thought += chunk['content']
return thought
except AuthenticationError:
raise AuthenticationError("Authentication failed. Please check your token.") from e
except RateLimitError:
raise RateLimitError("Rate limit exceeded. Please wait before making more requests.") from e
except CloudflareError as e:
raise CloudflareError(f"Cloudflare protection encountered: {str(e)}") from e
except NetworkError:
raise NetworkError("Network error occurred. Check your internet connection.") from e
except APIError as e:
raise APIError(f"API error occurred: {str(e)}") from e
return None
def test_fn(self, history, verbose = True):
"""
This function is used to conduct tests.
@@ -270,6 +307,6 @@ goodbye!
return thought
if __name__ == "__main__":
provider = Provider("server", "deepseek-r1:1.5b", "192.168.1.20:3333")
provider = Provider("ollama", "deepseek-r1:1.5b", "127.0.0.1:11434")
res = provider.respond(["user", "Hello, how are you?"])
print("Response:", res)
+14 -10
View File
@@ -15,7 +15,7 @@ from sources.utility import timer_decorator, pretty_print
class Memory():
"""
Memory is a class for managing the conversation memory
It provides a method to compress the memory (experimental, use with caution).
It provides a method to compress the memory using summarization model.
"""
def __init__(self, system_prompt: str,
recover_last_session: bool = False,
@@ -38,6 +38,7 @@ class Memory():
self.model = AutoModelForSeq2SeqLM.from_pretrained(self.model)
def get_filename(self) -> str:
"""Get the filename for the save file."""
return f"memory_{self.session_time.strftime('%Y-%m-%d_%H-%M-%S')}.txt"
def save_memory(self, agent_type: str = "casual_agent") -> None:
@@ -103,6 +104,7 @@ class Memory():
self.memory = []
def clear_section(self, start: int, end: int) -> None:
"""Clear a section of the memory."""
self.memory = self.memory[:start] + self.memory[end:]
def get(self) -> list:
@@ -134,23 +136,23 @@ class Memory():
inputs = self.tokenizer(input_text, return_tensors="pt", max_length=512, truncation=True)
summary_ids = self.model.generate(
inputs['input_ids'],
max_length=max_length, # Maximum length of the summary
min_length=min_length, # Minimum length of the summary
length_penalty=1.0, # Adjusts length preference
num_beams=4, # Beam search for better quality
early_stopping=True # Stop when all beams finish
max_length=max_length,
min_length=min_length,
length_penalty=1.0,
num_beams=4,
early_stopping=True
)
summary = self.tokenizer.decode(summary_ids[0], skip_special_tokens=True)
summary.replace('summary:', '')
return summary
@timer_decorator
#@timer_decorator
def compress(self) -> str:
"""
Compress the memory using the AI model.
"""
for i in range(len(self.memory)):
if i < 3:
if i < 2:
continue
if self.memory[i]['role'] == 'system':
continue
@@ -179,10 +181,12 @@ Use the -I flag to specify the directory containing helper_functions.h.
Ensure the file exists in the specified location.
"""
memory.push('user', "why do i get this error?")
memory.push('user', "hello")
memory.push('assistant', "how can i help you?")
memory.push('user', "why do i get this cuda error?")
memory.push('assistant', sample_text)
print("\n---\nmemory before:", memory.get())
memory.compress()
print("\n---\nmemory after:", memory.get())
memory.save_memory()
#memory.save_memory()
+35 -8
View File
@@ -1,3 +1,4 @@
import os
import re
import platform
import subprocess
@@ -8,6 +9,11 @@ from kokoro import KPipeline
from IPython.display import display, Audio
import soundfile as sf
if __name__ == "__main__":
from utility import pretty_print, animate_thinking
else:
from sources.utility import pretty_print, animate_thinking
class Speech():
"""
Speech is a class for generating speech from text.
@@ -29,8 +35,19 @@ class Speech():
self.pipeline = KPipeline(lang_code=self.lang_map[language])
self.voice = self.voice_map[language][voice_idx]
self.speed = 1.2
self.voice_folder = ".voices"
self.create_voice_folder(self.voice_folder)
def speak(self, sentence: str, voice_number: int = 1 , audio_file: str = 'sample.wav'):
def create_voice_folder(self, path: str = ".voices") -> None:
"""
Create a folder to store the voices.
Args:
path (str): The path to the folder.
"""
if not os.path.exists(path):
os.makedirs(path)
def speak(self, sentence: str, voice_number: int = 1):
"""
Convert text to speech using an AI model and play the audio.
@@ -40,7 +57,11 @@ class Speech():
"""
if not self.pipeline:
return
if voice_number >= len(self.voice_map[self.language]) or voice_number < 0:
pretty_print("Invalid voice number, using default voice", color="error")
voice_number = 0
sentence = self.clean_sentence(sentence)
audio_file = f"{self.voice_folder}/sample_{self.voice_map[self.language][voice_number]}.wav"
self.voice = self.voice_map[self.language][voice_number]
generator = self.pipeline(
sentence, voice=self.voice,
@@ -123,12 +144,18 @@ class Speech():
if __name__ == "__main__":
speech = Speech()
tosay = """
tosay_en = """
I looked up recent news using the website https://www.theguardian.com/world
Here is how to list files:
ls -l -a -h
the ip address of the server is 192.168.1.1
"""
for voice_idx in range (len(speech.voice_map["english"])):
print(f"Voice {voice_idx}")
speech.speak(tosay, voice_idx)
tosay_zh = """
我使用网站 https://www.theguardian.com/world 查阅了最近的新闻。
"""
tosay_fr = """
J'ai consulté les dernières nouvelles sur le site https://www.theguardian.com/world
"""
spk = Speech(enable=True, language="en", voice_idx=0)
spk.speak(tosay_en)
spk = Speech(enable=True, language="fr", voice_idx=0)
spk.speak(tosay_fr)
spk = Speech(enable=True, language="zh", voice_idx=0)
spk.speak(tosay_zh)