Merge pull request #98 from Fosowl/dev
Fix various bug + handle webpage numerical value + improve prompts.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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**
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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**
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ class BrowserAgent(Agent):
|
||||
{remaining_links_text}
|
||||
|
||||
Your task:
|
||||
1. Decide if the current page answers the user’s query: {user_prompt}
|
||||
1. Decide if the current page answers the user’s 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 doesn’t, say: Error: This page does not answer the user’s 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}
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
+18
-7
@@ -22,6 +22,9 @@ import logging
|
||||
import sys
|
||||
import re
|
||||
|
||||
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,
|
||||
@@ -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):
|
||||
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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
Reference in New Issue
Block a user