mirror of
https://github.com/tcsenpai/agenticSeek.git
synced 2025-06-06 11:05:26 +00:00
Merge pull request #95 from Fosowl/dev
Multilingual routing system (english, french, chinese) + Better web agent handling of web form (#94 corrected)
This commit is contained in:
commit
32b3908aa3
31
README.md
31
README.md
@ -14,6 +14,10 @@ English | [繁體中文](./README_CHT.md) | [Français](./README_FR.md)
|
||||
|
||||
> 🛠️ **Work in Progress** – Looking for contributors!
|
||||
|
||||
## Task planning with multiple agents
|
||||
|
||||

|
||||
|
||||
> *Do a deep search of AI startup in Osaka and Tokyo, find at least 5, then save in the research_japan.txt file*
|
||||
|
||||
> *Can you make a tetris game in C ?*
|
||||
@ -21,12 +25,6 @@ English | [繁體中文](./README_CHT.md) | [Français](./README_FR.md)
|
||||
> *I would like to setup a new project file index as mark2.*
|
||||
|
||||
|
||||
### agenticSeek can now plan tasks!
|
||||
|
||||

|
||||
|
||||
*See media/examples for other use case screenshots.*
|
||||
|
||||
## Features:
|
||||
|
||||
- **100% Local**: No cloud, runs on your hardware. Your data stays yours.
|
||||
@ -142,8 +140,7 @@ python3 main.py
|
||||
|
||||
## Usage
|
||||
|
||||
Warning: currently the system that choose the best AI agent routing system will work poorly with non-english text. This is because the agent routing currently use a model that was trained on english text. We are working hard to fix this. Please use english for now.
|
||||
|
||||
Warning: We only support French, English and Chinese, prompt in other language would work but might not be routed to the proper agent.
|
||||
|
||||
Make sure the services are up and running with `./start_services.sh` and run the agenticSeek with `python3 main.py`
|
||||
|
||||
@ -162,9 +159,9 @@ Here are some example usage:
|
||||
|
||||
### Coding/Bash
|
||||
|
||||
> *Help me with matrix multiplication in Golang*
|
||||
> *Show me how to multiply matrice in C*
|
||||
|
||||
> *Scan my network with nmap, find if any suspicious devices is connected*
|
||||
> *Can you install follow the readme and install project at /home/path/project*
|
||||
|
||||
> *Make a snake game in python*
|
||||
|
||||
@ -174,7 +171,7 @@ Here are some example usage:
|
||||
|
||||
> *Can you find on the internet who created agenticSeek?*
|
||||
|
||||
> *Can you find on which website I can buy a rtx 4090 for cheap*
|
||||
> *Can you use a fuel calculator online to estimate the cost of a Nice - Milan trip*
|
||||
|
||||
### File system
|
||||
|
||||
@ -186,11 +183,11 @@ Here are some example usage:
|
||||
|
||||
### Casual
|
||||
|
||||
> *Tell me about France*
|
||||
> *Tell me about Rennes, France*
|
||||
|
||||
> *What is the meaning of life ?*
|
||||
> *Should I pursue a phd ?*
|
||||
|
||||
> *Should I take creatine before or after workout?*
|
||||
> *What's the best workout routine ?*
|
||||
|
||||
|
||||
After you type your query, agenticSeek will allocate the best agent for the task.
|
||||
@ -430,9 +427,11 @@ Ensure Ollama is running (`ollama serve`), your `config.ini` matches your provid
|
||||
|
||||
Yes with Ollama or Server providers, all speech to text, LLM and text to speech model run locally. Non-local options (OpenAI or others API) are optional.
|
||||
|
||||
**Q: How come it is older than manus ?**
|
||||
**Q: Why should I use AgenticSeek when I have Manus?**
|
||||
|
||||
we started this a fun side project to make a fully local, Jarvis-like AI. However, with the rise of Manus, we saw the opportunity to redirected some tasks to make yet another alternative.
|
||||
This started as Side-Project we did out of interest about AI agents. What’s special about it is that we want to use local model and avoid APIs.
|
||||
We draw inspiration from Jarvis and Friday (Iron man movies) to make it "cool" but for functionnality we take more inspiration from Manus, because that's what people want in the first place: a local manus alternative.
|
||||
Unlike Manus, AgenticSeek prioritizes independence from external systems, giving you more control, privacy and avoid cost.
|
||||
|
||||
**Q: How is it better than manus ?**
|
||||
|
||||
|
@ -24,9 +24,7 @@
|
||||
|
||||
### AgenticSeek 可以進行任務規劃!
|
||||
|
||||

|
||||
|
||||
*可以查看我們的圖片集和範例了解他到底可以做些甚麼。*
|
||||

|
||||
|
||||
## Features:
|
||||
|
||||
@ -145,9 +143,6 @@ python3 main.py
|
||||
|
||||
## Usage (使用方法)
|
||||
|
||||
警告:目前 AgenticSeek 選擇助理的方式,暫且只支援英文,因為選擇助理的方式是使用英文文本訓練,所以使用非英文方式會出現挺多問題的。但放心,我們正在努力解決這個問題,還請體諒 QAQ
|
||||
|
||||
|
||||
確定所有的核心檔案都啟用了,也就是執行過這條命令 `./start_services.sh` 然後你就可以使用 `python3 main.py` 來啟動 AgenticSeek 了!
|
||||
|
||||
```sh
|
||||
|
56
README_FR.md
56
README_FR.md
@ -15,16 +15,17 @@ Une alternative **entièrement locale** à Manus AI, un assistant vocal IA qui c
|
||||
|
||||

|
||||
|
||||
> *Do a deep search of AI startup in Osaka and Tokyo, find at least 5, then save in the research_japan.txt file*
|
||||
> *Recherche sur le web des activités à faire à Paris*
|
||||
|
||||
> *Can you make a tetris game in C ?*
|
||||
> *Code le jeu snake en python*
|
||||
|
||||
> *I would like to setup a new project file index as mark2.*
|
||||
> *J'aimerais que tu trouve une api météo et que tu me code un application qui affiche la météo à Toulouse*
|
||||
|
||||
|
||||
### agenticSeek peut planifier des taches!
|
||||
### agenticSeek peut désormais planifier des taches!
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## Fonctionnalités:
|
||||
|
||||
@ -135,8 +136,6 @@ Voir la section **Configuration** pour une explication détaillée du fichier de
|
||||
|
||||
## Utilisation
|
||||
|
||||
Avertissement : actuellement, le système qui choisit le meilleur agent IA fonctionnera mal avec du texte non anglophone. Cela est dû au fait que le routage des agents utilise un modèle entraîné sur du texte en anglais. Nous travaillons dur pour corriger cela. Veuillez utiliser l’anglais pour le moment.
|
||||
|
||||
Assurez-vous que les services sont en cours d’exécution avec ./start_services.sh et lancez AgenticSeek avec python3 main.py
|
||||
|
||||
```sh
|
||||
@ -154,42 +153,41 @@ Voici quelques exemples d’utilisation :
|
||||
|
||||
### Programmation
|
||||
|
||||
> *Help me with matrix multiplication in Golang*
|
||||
> *Aide-moi avec la multiplication de matrices en Golang*
|
||||
|
||||
> *Scan my network with nmap, find if any suspicious devices is connected*
|
||||
> *Initalize un nouveau project python, setup le readme, gitignore et tout le bordel et fait un premier commit*
|
||||
|
||||
> *Make a snake game in python*
|
||||
> *Fais un jeu snake en Python*
|
||||
|
||||
### Recherche web
|
||||
|
||||
> *Do a web search to find cool tech startup in Japan working on cutting edge AI research*
|
||||
> *Fais une recherche sur le web pour trouver des startups technologiques au Japon qui travaillent sur des recherches avancées en IA*
|
||||
|
||||
> *Can you find on the internet who created agenticSeek?*
|
||||
> *Peux-tu trouver sur internet qui a créé agenticSeek ?*
|
||||
|
||||
> *Can you find on which website I can buy a rtx 4090 for cheap*
|
||||
> *Peux-tu trouver sur quel site je peux acheter une RTX 4090 à bas prix ?*
|
||||
|
||||
### Fichier
|
||||
|
||||
> *Hey can you find where is million_dollars_contract.pdf i lost it*
|
||||
> *Hé, peux-tu trouver où est million_dollars_contract.pdf ? Je l’ai perdu*
|
||||
|
||||
> *Show me how much space I have left on my disk*
|
||||
> *Montre-moi combien d’espace il me reste sur mon disque*
|
||||
|
||||
> *Find and read the README.md and follow the install instruction*
|
||||
> *Trouve et lis le fichier README.md et suis les instructions d’installation*
|
||||
|
||||
### Conversation
|
||||
|
||||
> *Tell me about France*
|
||||
> *Parle-moi de la France*
|
||||
|
||||
> *What is the meaning of life ?*
|
||||
|
||||
> *Should I take creatine before or after workout?*
|
||||
> *Quel est le sens de la vie ?*
|
||||
|
||||
> *Donne moi une recette avec les ingrédients suivant de mon frigo...*
|
||||
|
||||
Après avoir saisi votre requête, AgenticSeek attribuera le meilleur agent pour la tâche.
|
||||
|
||||
Comme il s’agit d’un prototype, le système de routage des agents pourrait ne pas toujours attribuer le bon agent en fonction de votre requête.
|
||||
Le système de routage des agents peut parfois ne pas toujours attribuer le bon agent en fonction de votre requête.
|
||||
|
||||
Par conséquent, vous devez être explicite sur ce que vous voulez et sur la manière dont l’IA doit procéder. Par exemple, si vous voulez qu’elle effectue une recherche sur le web, ne dites pas :
|
||||
Par conséquent, vous devez être assez explicite sur ce que vous voulez et sur la manière dont l’IA doit procéder. Par exemple, si vous voulez qu’elle effectue une recherche sur le web, ne dites pas :
|
||||
|
||||
Connait-tu de bons pays pour voyager seul ?
|
||||
|
||||
@ -336,7 +334,7 @@ stealth_mode = False
|
||||
|
||||
## Providers
|
||||
|
||||
Le tableau ci-dessous montre les fournisseurs disponibles :
|
||||
Le tableau ci-dessous montre les LLM providers disponibles :
|
||||
|
||||
| Provider | Local? | Description |
|
||||
|-----------|--------|-----------------------------------------------------------|
|
||||
@ -347,7 +345,7 @@ Le tableau ci-dessous montre les fournisseurs disponibles :
|
||||
| deepseek-api | No | Deepseek API (pas privé) |
|
||||
| huggingface| No | Hugging-Face API (pas privé) |
|
||||
|
||||
Pour sélectionner un fournisseur, modifiez le config.ini :
|
||||
Pour sélectionner un provider LLM, modifiez le config.ini :
|
||||
|
||||
```
|
||||
is_local = False
|
||||
@ -387,7 +385,7 @@ Et téléchargez la version de chromedriver correspondant à votre système d’
|
||||
|
||||

|
||||
|
||||
Si cette section est incomplète, veuillez signaler un problème.
|
||||
Si cette section est incomplète, merci de faire une nouvelle issue github.
|
||||
|
||||
## FAQ
|
||||
|
||||
@ -408,15 +406,11 @@ Assurez-vous qu’Ollama est en cours d’exécution (ollama serve), que votre c
|
||||
|
||||
**Q: C'est vraiment 100% local?**
|
||||
|
||||
Oui, avec les fournisseurs Ollama ou Server, toute la reconnaissance vocale, le LLM et la synthèse vocale fonctionnent localement. Les options non locales (OpenAI ou autres API) sont facultatives.
|
||||
|
||||
**Q: Pourquoi le projet est plus vieux que la date de sortie de Manus?**
|
||||
|
||||
Nous avons commencé cela comme un projet amusant pour créer une IA locale de type Jarvis. Cependant, avec l’émergence de Manus, nous avons vu l’opportunité de réorienter certaines tâches pour en faire une autre alternative.
|
||||
Oui, avec les fournisseurs Ollama, lm-studio ou Server, toute la reconnaissance vocale, le LLM et la synthèse vocale fonctionnent localement. Les options non locales (OpenAI ou autres API) sont facultatives.
|
||||
|
||||
**Q: En quoi c'est supérieur à Manus**
|
||||
|
||||
Il ne l'est pas mais nous privilégions l’exécution locale et la confidentialité par rapport à une approche basée sur le cloud. C’est une alternative plus accessible et surtout moins cher !
|
||||
Il ne l'est pas, mais nous privilégions l’exécution locale et la confidentialité par rapport à une approche basée sur le cloud. C’est une alternative plus accessible et surtout moins cher !
|
||||
|
||||
## Contribute
|
||||
|
||||
|
BIN
media/examples/planner.png
Normal file
BIN
media/examples/planner.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 879 KiB |
Binary file not shown.
Before Width: | Height: | Size: 129 KiB |
Binary file not shown.
Before Width: | Height: | Size: 825 KiB |
Binary file not shown.
Before Width: | Height: | Size: 103 KiB |
Binary file not shown.
Before Width: | Height: | Size: 182 KiB |
Binary file not shown.
Before Width: | Height: | Size: 344 KiB |
@ -47,5 +47,5 @@ Some rules:
|
||||
- Do not ever use user input, input are not supported by the system.
|
||||
- Do not ever tell user how to run it. user know it.
|
||||
- For simple explanation you don't need to code.
|
||||
- Dont be lazy, write full implementation for user.
|
||||
- If using gui, make sure echap close the program
|
||||
- If query is unclear say REQUEST_CLARIFICATION
|
@ -46,8 +46,8 @@ Some rules:
|
||||
- You do not ever need to use bash to execute code.
|
||||
- Do not ever use user input, input are not supported by the system.
|
||||
- Do not ever tell user how to run it. user know it.
|
||||
- Dont be lazy, write full implementation for user.
|
||||
- For simple explanation you don't need to code.
|
||||
- If using gui, make sure echap close the program
|
||||
- If query is unclear say REQUEST_CLARIFICATION
|
||||
|
||||
Personality:
|
||||
|
@ -32,6 +32,7 @@ tqdm>4
|
||||
fake_useragent>=2.1.0
|
||||
selenium_stealth>=1.0.6
|
||||
undetected-chromedriver>=3.5.5
|
||||
sentencepiece>=0.2.0
|
||||
# for api provider
|
||||
openai
|
||||
# if use chinese
|
||||
|
1
setup.py
1
setup.py
@ -44,6 +44,7 @@ setup(
|
||||
"fake_useragent>=2.1.0",
|
||||
"selenium_stealth>=1.0.6",
|
||||
"undetected-chromedriver>=3.5.5",
|
||||
"sentencepiece>=0.2.0",
|
||||
"sniffio",
|
||||
"tqdm>4"
|
||||
],
|
||||
|
@ -187,7 +187,7 @@ class BrowserAgent(Agent):
|
||||
def conclude_prompt(self, user_query: str) -> str:
|
||||
annotated_notes = [f"{i+1}: {note.lower().replace('note:', '')}" for i, note in enumerate(self.notes)]
|
||||
search_note = '\n'.join(annotated_notes)
|
||||
print("AI research notes:\n", search_note)
|
||||
pretty_print(f"AI notes:\n{search_note}", color="success")
|
||||
return f"""
|
||||
Following a human request:
|
||||
{user_query}
|
||||
@ -251,7 +251,7 @@ class BrowserAgent(Agent):
|
||||
complete = False
|
||||
|
||||
animate_thinking(f"Thinking...", color="status")
|
||||
self.memory.push('user', self.search_prompt(user_prompt))
|
||||
mem_begin_idx = self.memory.push('user', self.search_prompt(user_prompt))
|
||||
ai_prompt, _ = self.llm_request()
|
||||
if "REQUEST_EXIT" in ai_prompt:
|
||||
pretty_print(f"{reasoning}\n{ai_prompt}", color="output")
|
||||
@ -305,9 +305,10 @@ class BrowserAgent(Agent):
|
||||
prompt = self.make_navigation_prompt(user_prompt, page_text)
|
||||
|
||||
prompt = self.conclude_prompt(user_prompt)
|
||||
self.memory.push('user', prompt)
|
||||
mem_last_idx = self.memory.push('assistant', prompt)
|
||||
answer, reasoning = self.llm_request()
|
||||
pretty_print(answer, color="output")
|
||||
self.memory.clear_section(mem_begin_idx, mem_last_idx)
|
||||
return answer, reasoning
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -1,3 +1,4 @@
|
||||
import platform, os
|
||||
|
||||
from sources.utility import pretty_print, animate_thinking
|
||||
from sources.agents.agent import Agent, executorResult
|
||||
@ -20,6 +21,7 @@ class CoderAgent(Agent):
|
||||
"go": GoInterpreter(),
|
||||
"file_finder": FileFinder()
|
||||
}
|
||||
self.work_dir = self.tools["file_finder"].get_work_dir()
|
||||
self.role = {
|
||||
"en": "code",
|
||||
"fr": "codage",
|
||||
@ -27,10 +29,20 @@ class CoderAgent(Agent):
|
||||
}
|
||||
self.type = "code_agent"
|
||||
|
||||
|
||||
def add_sys_info_prompt(self, prompt):
|
||||
"""Add system information to the prompt."""
|
||||
info = f"System Info:\n" \
|
||||
f"OS: {platform.system()} {platform.release()}\n" \
|
||||
f"Python Version: {platform.python_version()}\n" \
|
||||
f"\nYou must work in directory: {self.work_dir}"
|
||||
return f"{prompt}\n\n{info}"
|
||||
|
||||
def process(self, prompt, speech_module) -> str:
|
||||
answer = ""
|
||||
attempt = 0
|
||||
max_attempts = 3
|
||||
max_attempts = 4
|
||||
prompt = self.add_sys_info_prompt(prompt)
|
||||
self.memory.push('user', prompt)
|
||||
clarify_trigger = "REQUEST_CLARIFICATION"
|
||||
|
||||
|
@ -24,6 +24,9 @@ import re
|
||||
|
||||
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')
|
||||
|
||||
def get_chrome_path() -> str:
|
||||
if sys.platform.startswith("win"):
|
||||
paths = [
|
||||
@ -111,13 +114,15 @@ class Browser:
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.logger.info("Browser initialized successfully")
|
||||
except Exception as e:
|
||||
logging.basicConfig(filename='browser.log', level=logging.ERROR,
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
raise Exception(f"Failed to initialize browser: {str(e)}")
|
||||
self.driver.get("https://www.google.com")
|
||||
if anticaptcha_manual_install:
|
||||
self.load_anticatpcha_manually()
|
||||
|
||||
def load_anticatpcha_manually(self):
|
||||
print("You might want to install the AntiCaptcha extension for captchas.")
|
||||
pretty_print("You might want to install the AntiCaptcha extension for captchas.", color="warning")
|
||||
self.driver.get(self.anticaptcha)
|
||||
|
||||
def go_to(self, url:str) -> bool:
|
||||
@ -263,7 +268,7 @@ class Browser:
|
||||
except Exception as e:
|
||||
raise e
|
||||
|
||||
def find_all_inputs(self, timeout=4):
|
||||
def find_all_inputs(self, timeout=3):
|
||||
WebDriverWait(self.driver, timeout).until(
|
||||
EC.presence_of_element_located((By.TAG_NAME, "body"))
|
||||
)
|
||||
@ -275,26 +280,28 @@ class Browser:
|
||||
def get_form_inputs(self) -> List[str]:
|
||||
"""Extract all input from the page and return them."""
|
||||
try:
|
||||
#input_elements = self.driver.find_elements(By.TAG_NAME, "input")
|
||||
input_elements = self.find_all_inputs()
|
||||
if not input_elements:
|
||||
return ["No input forms found on the page."]
|
||||
|
||||
form_strings = []
|
||||
for element in input_elements:
|
||||
input_type = element["type"] or "text"
|
||||
input_type = element.get("type") or "text"
|
||||
if input_type in ["hidden", "submit", "button", "image"] or not element["displayed"]:
|
||||
continue
|
||||
input_name = element["text"] or element["id"] or input_type
|
||||
input_name = element.get("text") or element.get("id") or input_type
|
||||
if input_type == "checkbox" or input_type == "radio":
|
||||
checked_status = "checked" if element.is_selected() else "unchecked"
|
||||
try:
|
||||
checked_status = "checked" if element.is_selected() else "unchecked"
|
||||
except Exception as e:
|
||||
continue
|
||||
form_strings.append(f"[{input_name}]({checked_status})")
|
||||
else:
|
||||
form_strings.append(f"[{input_name}]("")")
|
||||
return form_strings
|
||||
|
||||
except Exception as e:
|
||||
return [f"Error extracting form inputs."]
|
||||
raise e
|
||||
|
||||
def get_buttons_xpath(self) -> List[str]:
|
||||
"""
|
||||
@ -308,13 +315,14 @@ class Browser:
|
||||
continue
|
||||
text = (button.text or button.get_attribute("value") or "").lower().replace(' ', '')
|
||||
xpath = f"(//button | //input[@type='submit'])[{i + 1}]"
|
||||
if "login" in text or "sign" in text or "register":
|
||||
result.append((text, xpath))
|
||||
result.append((text, xpath))
|
||||
result.sort(key=lambda x: len(x[0]))
|
||||
return result
|
||||
|
||||
def find_and_click_submission(self, timeout: int = 10) -> bool:
|
||||
possible_submissions = ["login", "submit", "register"]
|
||||
possible_submissions = ["login", "submit", "register", "calculate", "login", "submit", "register", "calculate", "save", "send",
|
||||
"continue", "apply", "ok", "confirm", "next", "proceed", "accept", "agree", "yes", "no", "cancel",
|
||||
"close", "done", "finish", "start", "calculate"]
|
||||
for submission in possible_submissions:
|
||||
if self.find_and_click_btn(submission, timeout):
|
||||
return True
|
||||
@ -388,6 +396,7 @@ class Browser:
|
||||
element.click()
|
||||
self.logger.info(f"Set {name} to {value}")
|
||||
else:
|
||||
element.clear()
|
||||
element.send_keys(value)
|
||||
self.logger.info(f"Filled {name} with {value}")
|
||||
return True
|
||||
@ -409,7 +418,7 @@ class Browser:
|
||||
self.driver.execute_script(
|
||||
"window.scrollTo(0, document.body.scrollHeight);"
|
||||
)
|
||||
time.sleep(1) # Wait for scroll to complete
|
||||
time.sleep(1)
|
||||
return True
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error scrolling: {str(e)}")
|
||||
@ -439,13 +448,12 @@ if __name__ == "__main__":
|
||||
browser = Browser(driver, anticaptcha_manual_install=True)
|
||||
time.sleep(10)
|
||||
|
||||
print("AntiCaptcha Test")
|
||||
print("AntiCaptcha / Form Test")
|
||||
browser.go_to("https://www.google.com/recaptcha/api2/demo")
|
||||
#browser.go_to("https://practicetestautomation.com/practice-test-login/")
|
||||
time.sleep(10)
|
||||
print("Form Test:")
|
||||
browser.go_to("https://practicetestautomation.com/practice-test-login/")
|
||||
inputs = browser.get_form_inputs()
|
||||
inputs = ['[username](student)', f'[password](Password123)', '[appOtp]()', '[backupOtp]()']
|
||||
inputs = ['[input1](Martin)', f'[input2](Test)', '[input3](test@gmail.com)']
|
||||
browser.fill_form_inputs(inputs)
|
||||
browser.find_and_click_submission()
|
||||
time.sleep(30)
|
||||
|
@ -1,17 +1,35 @@
|
||||
from typing import List, Tuple, Type, Dict, Tuple
|
||||
import langid
|
||||
import re
|
||||
import langid
|
||||
import nltk
|
||||
from nltk.sentiment.vader import SentimentIntensityAnalyzer
|
||||
from transformers import MarianMTModel, MarianTokenizer
|
||||
|
||||
from sources.utility import pretty_print, animate_thinking
|
||||
|
||||
class LanguageUtility:
|
||||
"""LanguageUtility for language, or emotion identification"""
|
||||
def __init__(self):
|
||||
self.sid = None
|
||||
self.translators_tokenizer = None
|
||||
self.translators_model = None
|
||||
self.load_model()
|
||||
|
||||
def load_model(self) -> None:
|
||||
animate_thinking("Loading language utility...", color="status")
|
||||
try:
|
||||
nltk.data.find('vader_lexicon')
|
||||
except LookupError:
|
||||
nltk.download('vader_lexicon')
|
||||
self.sid = SentimentIntensityAnalyzer()
|
||||
self.translators_tokenizer = {
|
||||
"fr": MarianTokenizer.from_pretrained("Helsinki-NLP/opus-mt-fr-en"),
|
||||
"zh": MarianTokenizer.from_pretrained("Helsinki-NLP/opus-mt-zh-en")
|
||||
}
|
||||
self.translators_model = {
|
||||
"fr": MarianMTModel.from_pretrained("Helsinki-NLP/opus-mt-fr-en"),
|
||||
"zh": MarianMTModel.from_pretrained("Helsinki-NLP/opus-mt-zh-en")
|
||||
}
|
||||
|
||||
def detect_language(self, text: str) -> str:
|
||||
"""
|
||||
@ -24,6 +42,25 @@ class LanguageUtility:
|
||||
lang, score = langid.classify(text)
|
||||
return lang
|
||||
|
||||
def translate(self, text: str, origin_lang: str) -> str:
|
||||
"""
|
||||
Translate the given text to English
|
||||
Args:
|
||||
text: string to translate
|
||||
origin_lang: ISO language code
|
||||
Returns: translated str
|
||||
"""
|
||||
if origin_lang == "en":
|
||||
return text
|
||||
if origin_lang not in self.translators_tokenizer:
|
||||
pretty_print(f"Language {origin_lang} not supported for translation", color="error")
|
||||
return text
|
||||
tokenizer = self.translators_tokenizer[origin_lang]
|
||||
inputs = tokenizer(text, return_tensors="pt", padding=True)
|
||||
model = self.translators_model[origin_lang]
|
||||
translation = model.generate(**inputs)
|
||||
return tokenizer.decode(translation[0], skip_special_tokens=True)
|
||||
|
||||
def detect_emotion(self, text: str) -> str:
|
||||
"""
|
||||
Detect the dominant emotion in the given text
|
||||
@ -75,11 +112,12 @@ if __name__ == "__main__":
|
||||
|
||||
test_texts = [
|
||||
"I am so happy today!",
|
||||
"Qué tristeza siento ahora",
|
||||
"我不要去巴黎",
|
||||
"La vie c'est cool"
|
||||
]
|
||||
for text in test_texts:
|
||||
print(f"\nAnalyzing: {text}")
|
||||
pretty_print("Analyzing...", color="status")
|
||||
pretty_print(f"Language: {detector.detect_language(text)}", color="status")
|
||||
result = detector.analyze(text)
|
||||
print(result)
|
||||
trans = detector.translate(text, result['language'])
|
||||
pretty_print(f"Translation: {trans} - from: {result['language']} - Emotion: {result['emotions']}")
|
@ -67,9 +67,9 @@ class Memory():
|
||||
|
||||
def load_memory(self, agent_type: str = "casual_agent") -> None:
|
||||
"""Load the memory from the last session."""
|
||||
pretty_print(f"Loading {agent_type} past memories... ", color="status")
|
||||
if self.session_recovered == True:
|
||||
return
|
||||
pretty_print(f"Loading {agent_type} past memories... ", color="status")
|
||||
save_path = os.path.join(self.conversation_folder, agent_type)
|
||||
if not os.path.exists(save_path):
|
||||
pretty_print("No memory to load.", color="success")
|
||||
@ -89,7 +89,7 @@ class Memory():
|
||||
def reset(self, memory: list) -> None:
|
||||
self.memory = memory
|
||||
|
||||
def push(self, role: str, content: str) -> None:
|
||||
def push(self, role: str, content: str) -> int:
|
||||
"""Push a message to the memory."""
|
||||
if self.memory_compression and role == 'assistant':
|
||||
self.compress()
|
||||
@ -97,10 +97,14 @@ class Memory():
|
||||
if self.memory[curr_idx-1]['content'] == content:
|
||||
pretty_print("Warning: same message have been pushed twice to memory", color="error")
|
||||
self.memory.append({'role': role, 'content': content})
|
||||
return curr_idx-1
|
||||
|
||||
def clear(self) -> None:
|
||||
self.memory = []
|
||||
|
||||
def clear_section(self, start: int, end: int) -> None:
|
||||
self.memory = self.memory[:start] + self.memory[end:]
|
||||
|
||||
def get(self) -> list:
|
||||
return self.memory
|
||||
|
||||
|
@ -8,14 +8,13 @@ from adaptive_classifier import AdaptiveClassifier
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
|
||||
from sources.agents.agent import Agent
|
||||
from sources.agents.code_agent import CoderAgent
|
||||
from sources.agents.casual_agent import CasualAgent
|
||||
from sources.agents.planner_agent import FileAgent
|
||||
from sources.agents.browser_agent import BrowserAgent
|
||||
from sources.language import LanguageUtility
|
||||
from sources.utility import pretty_print
|
||||
from sources.utility import pretty_print, animate_thinking, timer_decorator
|
||||
|
||||
class AgentRouter:
|
||||
"""
|
||||
@ -24,13 +23,22 @@ class AgentRouter:
|
||||
def __init__(self, agents: list):
|
||||
self.agents = agents
|
||||
self.lang_analysis = LanguageUtility()
|
||||
self.pipelines = {
|
||||
"bart": pipeline("zero-shot-classification", model="facebook/bart-large-mnli")
|
||||
}
|
||||
self.pipelines = self.load_pipelines()
|
||||
self.talk_classifier = self.load_llm_router()
|
||||
self.complexity_classifier = self.load_llm_router()
|
||||
self.learn_few_shots_tasks()
|
||||
self.learn_few_shots_complexity()
|
||||
|
||||
def load_pipelines(self) -> Dict[str, Type[pipeline]]:
|
||||
"""
|
||||
Load the pipelines for the text classification used for routing.
|
||||
returns:
|
||||
Dict[str, Type[pipeline]]: The loaded pipelines
|
||||
"""
|
||||
animate_thinking("Loading zero-shot pipeline...", color="status")
|
||||
return {
|
||||
"bart": pipeline("zero-shot-classification", model="facebook/bart-large-mnli")
|
||||
}
|
||||
|
||||
def load_llm_router(self) -> AdaptiveClassifier:
|
||||
"""
|
||||
@ -42,6 +50,7 @@ class AgentRouter:
|
||||
"""
|
||||
path = "../llm_router" if __name__ == "__main__" else "./llm_router"
|
||||
try:
|
||||
animate_thinking("Loading LLM router model...", color="status")
|
||||
talk_classifier = AdaptiveClassifier.from_pretrained(path)
|
||||
except Exception as e:
|
||||
raise Exception("Failed to load the routing model. Please run the dl_safetensors.sh script inside llm_router/ directory to download the model.")
|
||||
@ -302,25 +311,14 @@ class AgentRouter:
|
||||
pretty_print(f"Agent choice -> BART: {bart} ({final_score_bart}) LLM-router: {llm_router} ({final_score_llm})")
|
||||
return bart if final_score_bart > final_score_llm else llm_router
|
||||
|
||||
def classify_text(self, text: str, threshold: float = 0.4) -> list:
|
||||
"""
|
||||
Classify the text using the LLM router and BART model.
|
||||
"""
|
||||
def find_first_sentence(self, text: str) -> str:
|
||||
first_sentence = None
|
||||
lang = "en"
|
||||
for line in text.split("\n"):
|
||||
first_sentence = line.strip()
|
||||
break
|
||||
if first_sentence is None:
|
||||
first_sentence = text
|
||||
try:
|
||||
lang = self.lang_analysis.detect_language(first_sentence)
|
||||
# no multilanguage support yet
|
||||
labels = [agent.role["en"] for agent in self.agents]
|
||||
result = self.router_vote(first_sentence, labels, log_confidence=False)
|
||||
except Exception as e:
|
||||
raise e
|
||||
return result, lang
|
||||
return first_sentence
|
||||
|
||||
def estimate_complexity(self, text: str) -> str:
|
||||
"""
|
||||
@ -328,7 +326,7 @@ class AgentRouter:
|
||||
Args:
|
||||
text: The input text
|
||||
Returns:
|
||||
str: The estimated complexity
|
||||
str: The estimated complexity
|
||||
"""
|
||||
predictions = self.complexity_classifier.predict(text)
|
||||
predictions = sorted(predictions, key=lambda x: x[1], reverse=True)
|
||||
@ -358,12 +356,6 @@ class AgentRouter:
|
||||
pretty_print(f"Error finding planner agent. Please add a planner agent to the list of agents.", color="failure")
|
||||
return None
|
||||
|
||||
def multi_language_message(self, text: str):
|
||||
pretty_print(f"选择代理时出错。路由系统尚不支持多语言", color="failure")
|
||||
pretty_print(f"エージェントの選択エラー。ルーティングシステムはまだ多言語に対応していません", color="failure")
|
||||
pretty_print(f"Erreur lors du choix de l'agent. Le système de routage n'est pas encore multilingue.", color="failure")
|
||||
pretty_print(f"Error al elegir agente. El sistema de enrutamiento aún no es multilingüe.", color="failure")
|
||||
|
||||
def select_agent(self, text: str) -> Agent:
|
||||
"""
|
||||
Select the appropriate agent based on the text.
|
||||
@ -374,16 +366,21 @@ class AgentRouter:
|
||||
"""
|
||||
if len(self.agents) == 0:
|
||||
return self.agents[0]
|
||||
lang = self.lang_analysis.detect_language(text)
|
||||
text = self.find_first_sentence(text)
|
||||
text = self.lang_analysis.translate(text, lang)
|
||||
labels = [agent.role["en"] for agent in self.agents]
|
||||
complexity = self.estimate_complexity(text)
|
||||
best_agent, lang = self.classify_text(text)
|
||||
if lang != "en":
|
||||
self.multi_language_message(text)
|
||||
if complexity == None:
|
||||
pretty_print(f"Humm, the task seem complex but you gave very little information. can you clarify?", color="info")
|
||||
return None
|
||||
if complexity == "HIGH" and lang == "en":
|
||||
if complexity == "HIGH":
|
||||
pretty_print(f"Complex task detected, routing to planner agent.", color="info")
|
||||
return self.find_planner_agent()
|
||||
try:
|
||||
best_agent = self.router_vote(text, labels, log_confidence=False)
|
||||
except Exception as e:
|
||||
raise e
|
||||
for agent in self.agents:
|
||||
if best_agent == agent.role["en"]:
|
||||
pretty_print(f"Selected agent: {agent.agent_name} (roles: {agent.role[lang]})", color="warning")
|
||||
@ -393,52 +390,52 @@ class AgentRouter:
|
||||
|
||||
if __name__ == "__main__":
|
||||
agents = [
|
||||
CasualAgent("jarvis", "../prompts/casual_agent.txt", None),
|
||||
BrowserAgent("browser", "../prompts/planner_agent.txt", None),
|
||||
CoderAgent("coder", "../prompts/coder_agent.txt", None),
|
||||
FileAgent("file", "../prompts/coder_agent.txt", None)
|
||||
CasualAgent("jarvis", "../prompts/base/casual_agent.txt", None),
|
||||
BrowserAgent("browser", "../prompts/base/planner_agent.txt", None),
|
||||
CoderAgent("coder", "../prompts/base/coder_agent.txt", None),
|
||||
FileAgent("file", "../prompts/base/coder_agent.txt", None)
|
||||
]
|
||||
router = AgentRouter(agents)
|
||||
texts = [
|
||||
"hi",
|
||||
#"你好",
|
||||
#"Bonjour",
|
||||
"你好",
|
||||
"Bonjour",
|
||||
"Write a python script to check if the device on my network is connected to the internet",
|
||||
# "Peut tu écrire un script python qui vérifie si l'appareil sur mon réseau est connecté à internet?",
|
||||
# "写一个Python脚本,检查我网络上的设备是否连接到互联网",
|
||||
"Peut tu écrire un script python qui vérifie si l'appareil sur mon réseau est connecté à internet?",
|
||||
"写一个Python脚本,检查我网络上的设备是否连接到互联网",
|
||||
"Hey could you search the web for the latest news on the tesla stock market ?",
|
||||
# "嘿,你能搜索网页上关于股票市场的最新新闻吗?",
|
||||
# "Yo, cherche sur internet comment va tesla en bourse.",
|
||||
"嘿,你能搜索网页上关于股票市场的最新新闻吗?",
|
||||
"Yo, cherche sur internet comment va tesla en bourse.",
|
||||
"I would like you to search for weather api and then make an app using this API",
|
||||
# "我想让你搜索天气API,然后用这个API做一个应用程序",
|
||||
# "J'aimerais que tu cherche une api météo et que l'utilise pour faire une application",
|
||||
"我想让你搜索天气API,然后用这个API做一个应用程序",
|
||||
"J'aimerais que tu cherche une api météo et que l'utilise pour faire une application",
|
||||
"Plan a 3-day trip to New York, including flights and hotels.",
|
||||
# "计划一次为期3天的纽约之旅,包括机票和酒店。",
|
||||
# "Planifie un trip de 3 jours à Paris, y compris les vols et hotels.",
|
||||
"计划一次为期3天的纽约之旅,包括机票和酒店。",
|
||||
"Planifie un trip de 3 jours à Paris, y compris les vols et hotels.",
|
||||
"Find on the web the latest research papers on AI.",
|
||||
# "在网上找到最新的人工智能研究论文。",
|
||||
# "Trouve moi les derniers articles de recherche sur l'IA sur internet",
|
||||
"在网上找到最新的人工智能研究论文。",
|
||||
"Trouve moi les derniers articles de recherche sur l'IA sur internet",
|
||||
"Help me write a C++ program to sort an array",
|
||||
"Tell me what France been up to lately",
|
||||
# "告诉我法国最近在做什么",
|
||||
# "Dis moi ce que la France a fait récemment",
|
||||
"告诉我法国最近在做什么",
|
||||
"Dis moi ce que la France a fait récemment",
|
||||
"Who is Sergio Pesto ?",
|
||||
# "谁是Sergio Pesto?",
|
||||
# "Qui est Sergio Pesto ?",
|
||||
# "帮我写一个C++程序来排序数组",
|
||||
# "Aide moi à faire un programme c++ pour trier une array.",
|
||||
"谁是Sergio Pesto?",
|
||||
"Qui est Sergio Pesto ?",
|
||||
"帮我写一个C++程序来排序数组",
|
||||
"Aide moi à faire un programme c++ pour trier une array.",
|
||||
"What’s the weather like today? Oh, and can you find a good weather app?",
|
||||
# "今天天气怎么样?哦,你还能找到一个好的天气应用程序吗?",
|
||||
# "La météo est comment aujourd'hui ? oh et trouve moi une bonne appli météo tant que tu y est.",
|
||||
"今天天气怎么样?哦,你还能找到一个好的天气应用程序吗?",
|
||||
"La météo est comment aujourd'hui ? oh et trouve moi une bonne appli météo tant que tu y est.",
|
||||
"Can you debug this Java code? It’s not working.",
|
||||
# "你能调试这段Java代码吗?它不起作用。",
|
||||
# "Peut tu m'aider à debugger ce code java, ça marche pas",
|
||||
#"Can you browse the web and find me a 4090 for cheap?",
|
||||
#"你能浏览网页,为我找一个便宜的4090吗?",
|
||||
#"Peut tu chercher sur internet et me trouver une 4090 pas cher ?",
|
||||
#"Hey, can you find the old_project.zip file somewhere on my drive?",
|
||||
#"嘿,你能在我驱动器上找到old_project.zip文件吗?",
|
||||
#"Hé trouve moi le old_project.zip, il est quelque part sur mon disque.",
|
||||
"你能调试这段Java代码吗?它不起作用。",
|
||||
"Peut tu m'aider à debugger ce code java, ça marche pas",
|
||||
"Can you browse the web and find me a 4090 for cheap?",
|
||||
"你能浏览网页,为我找一个便宜的4090吗?",
|
||||
"Peut tu chercher sur internet et me trouver une 4090 pas cher ?",
|
||||
"Hey, can you find the old_project.zip file somewhere on my drive?",
|
||||
"嘿,你能在我驱动器上找到old_project.zip文件吗?",
|
||||
"Hé trouve moi le old_project.zip, il est quelque part sur mon disque.",
|
||||
"Tell me a funny story",
|
||||
"给我讲一个有趣的故事",
|
||||
"Raconte moi une histoire drole"
|
||||
|
@ -28,6 +28,9 @@ unsafe_commands_unix = [
|
||||
"parted", # Disk partitioning
|
||||
"chroot", # Change root directory
|
||||
"route" # Routing table management
|
||||
"--force", # Force flag for many commands
|
||||
"rebase", # Rebase git repository
|
||||
"git ." # Git commands, feel free to remove it but i dont want to risk agenticSeek pushing to its own repo lol (see 56b5db7)
|
||||
]
|
||||
|
||||
unsafe_commands_windows = [
|
||||
|
Loading…
x
Reference in New Issue
Block a user