mirror of
https://github.com/tcsenpai/agenticSeek.git
synced 2025-06-06 11:05:26 +00:00
Merge pull request #152 from Fosowl/dev
Improve chromedriver install error handling + improved fileFinder
This commit is contained in:
commit
a15dd998f3
10
README.md
10
README.md
@ -159,9 +159,9 @@ Set the desired provider in the `config.ini`. See below for a list of API provid
|
||||
```sh
|
||||
[MAIN]
|
||||
is_local = False
|
||||
provider_name = openai
|
||||
provider_model = gpt-4o
|
||||
provider_server_address = 127.0.0.1:5000
|
||||
provider_name = google
|
||||
provider_model = gemini-2.0-flash
|
||||
provider_server_address = 127.0.0.1:5000 # doesn't matter
|
||||
```
|
||||
Warning: Make sure there is not trailing space in the config.
|
||||
|
||||
@ -179,6 +179,10 @@ Example: export `TOGETHER_API_KEY="xxxxx"`
|
||||
| togetherAI | No | Use together AI API (non-private) |
|
||||
| google | No | Use google gemini API (non-private) |
|
||||
|
||||
*We advice against using gpt-4o or other closedAI models*, performance are poor for web browsing and task planning.
|
||||
|
||||
Please also note that coding/bash might fail with gemini, it seem to ignore our prompt for format to respect, which are optimized for deepseek r1.
|
||||
|
||||
Next step: [Start services and run AgenticSeek](#Start-services-and-Run)
|
||||
|
||||
*See the **Known issues** section if you are having issues*
|
||||
|
@ -123,6 +123,8 @@ class Agent():
|
||||
"""
|
||||
start_tag = "<think>"
|
||||
end_tag = "</think>"
|
||||
if text is None:
|
||||
return None
|
||||
start_idx = text.find(start_tag)
|
||||
end_idx = text.rfind(end_tag)+8
|
||||
return text[start_idx:end_idx]
|
||||
|
@ -151,7 +151,7 @@ class PlannerAgent(Agent):
|
||||
return []
|
||||
agents_tasks = self.parse_agent_tasks(answer)
|
||||
if agents_tasks == []:
|
||||
prompt = f"Failed to parse the tasks. Please make a plan within ```json. Do not ask for clarification.\n"
|
||||
prompt = f"Failed to parse the tasks. Please write down your task followed by a json plan within ```json. Do not ask for clarification.\n"
|
||||
pretty_print("Failed to make plan. Retrying...", color="warning")
|
||||
continue
|
||||
self.show_plan(agents_tasks, answer)
|
||||
|
@ -65,6 +65,25 @@ def get_random_user_agent() -> str:
|
||||
]
|
||||
return random.choice(user_agents)
|
||||
|
||||
def install_chromedriver() -> str:
|
||||
"""
|
||||
Install the ChromeDriver if not already installed. Return the path.
|
||||
"""
|
||||
chromedriver_path = shutil.which("chromedriver")
|
||||
if not chromedriver_path:
|
||||
try:
|
||||
chromedriver_path = chromedriver_autoinstaller.install()
|
||||
except Exception as e:
|
||||
raise FileNotFoundError(
|
||||
"ChromeDriver not found and could not be installed automatically. "
|
||||
"Please install it manually from https://chromedriver.chromium.org/downloads."
|
||||
"and ensure it's in your PATH or specify the path directly."
|
||||
"See know issues in readme if your chrome version is above 115."
|
||||
) from e
|
||||
if not chromedriver_path:
|
||||
raise FileNotFoundError("ChromeDriver not found. Please install it or add it to your PATH.")
|
||||
return chromedriver_path
|
||||
|
||||
def create_driver(headless=False, stealth_mode=True, crx_path="./crx/nopecha.crx") -> webdriver.Chrome:
|
||||
"""Create a Chrome WebDriver with specified options."""
|
||||
chrome_options = Options()
|
||||
@ -98,12 +117,7 @@ def create_driver(headless=False, stealth_mode=True, crx_path="./crx/nopecha.crx
|
||||
else:
|
||||
chrome_options.add_extension(crx_path)
|
||||
|
||||
chromedriver_path = shutil.which("chromedriver")
|
||||
if not chromedriver_path:
|
||||
chromedriver_path = chromedriver_autoinstaller.install()
|
||||
|
||||
if not chromedriver_path:
|
||||
raise FileNotFoundError("ChromeDriver not found. Please install it or add it to your PATH.")
|
||||
chromedriver_path = install_chromedriver()
|
||||
|
||||
service = Service(chromedriver_path)
|
||||
if stealth_mode:
|
||||
|
@ -72,6 +72,8 @@ class Provider:
|
||||
except ModuleNotFoundError as e:
|
||||
raise ModuleNotFoundError(f"{str(e)}\nA import related to provider {self.provider_name} was not found. Is it installed ?")
|
||||
except Exception as e:
|
||||
if "try again later" in str(e).lower():
|
||||
return f"{self.provider_name} server is overloaded. Please try again later."
|
||||
if "refused" in str(e):
|
||||
return f"Server {self.server_ip} seem offline. Unable to answer."
|
||||
raise Exception(f"Provider {self.provider_name} failed: {str(e)}") from e
|
||||
@ -214,7 +216,7 @@ class Provider:
|
||||
"""
|
||||
base_url = self.server_ip
|
||||
if self.is_local:
|
||||
raise Exception("Google Gemini is not available for local use.")
|
||||
raise Exception("Google Gemini is not available for local use. Change config.ini")
|
||||
|
||||
client = OpenAI(api_key=self.api_key, base_url="https://generativelanguage.googleapis.com/v1beta/openai/")
|
||||
try:
|
||||
@ -237,6 +239,8 @@ class Provider:
|
||||
"""
|
||||
from together import Together
|
||||
client = Together(api_key=self.api_key)
|
||||
if self.is_local:
|
||||
raise Exception("Together AI is not available for local use. Change config.ini")
|
||||
|
||||
try:
|
||||
response = client.chat.completions.create(
|
||||
@ -257,6 +261,8 @@ class Provider:
|
||||
Use deepseek api to generate text.
|
||||
"""
|
||||
client = OpenAI(api_key=self.api_key, base_url="https://api.deepseek.com")
|
||||
if self.is_local:
|
||||
raise Exception("Deepseek (API) is not available for local use. Change config.ini")
|
||||
try:
|
||||
response = client.chat.completions.create(
|
||||
model="deepseek-chat",
|
||||
|
@ -140,6 +140,7 @@ class Speech():
|
||||
return sentence
|
||||
|
||||
if __name__ == "__main__":
|
||||
# TODO add info message for cn2an, jieba chinese related import
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
speech = Speech()
|
||||
tosay_en = """
|
||||
|
@ -1,13 +1,12 @@
|
||||
|
||||
import sys
|
||||
import os, sys
|
||||
import re
|
||||
from io import StringIO
|
||||
import subprocess
|
||||
|
||||
if __name__ == "__main__":
|
||||
from tools import Tools
|
||||
from safety import is_unsafe
|
||||
else:
|
||||
if __name__ == "__main__": # if running as a script for individual testing
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
|
||||
|
||||
from sources.tools.tools import Tools
|
||||
from sources.tools.safety import is_unsafe
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
import subprocess
|
||||
import os
|
||||
import os, sys
|
||||
import tempfile
|
||||
import re
|
||||
|
||||
if __name__ == "__main__":
|
||||
from tools import Tools
|
||||
else:
|
||||
if __name__ == "__main__": # if running as a script for individual testing
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
|
||||
|
||||
from sources.tools.tools import Tools
|
||||
|
||||
class CInterpreter(Tools):
|
||||
|
@ -1,11 +1,11 @@
|
||||
import subprocess
|
||||
import os
|
||||
import os, sys
|
||||
import tempfile
|
||||
import re
|
||||
|
||||
if __name__ == "__main__":
|
||||
from tools import Tools
|
||||
else:
|
||||
if __name__ == "__main__": # if running as a script for individual testing
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
|
||||
|
||||
from sources.tools.tools import Tools
|
||||
|
||||
class GoInterpreter(Tools):
|
||||
|
@ -1,11 +1,11 @@
|
||||
import subprocess
|
||||
import os
|
||||
import os, sys
|
||||
import tempfile
|
||||
import re
|
||||
|
||||
if __name__ == "__main__":
|
||||
from tools import Tools
|
||||
else:
|
||||
if __name__ == "__main__": # if running as a script for individual testing
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
|
||||
|
||||
from sources.tools.tools import Tools
|
||||
|
||||
class JavaInterpreter(Tools):
|
||||
|
@ -4,9 +4,9 @@ import os
|
||||
import re
|
||||
from io import StringIO
|
||||
|
||||
if __name__ == "__main__":
|
||||
from tools import Tools
|
||||
else:
|
||||
if __name__ == "__main__": # if running as a script for individual testing
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
|
||||
|
||||
from sources.tools.tools import Tools
|
||||
|
||||
class PyInterpreter(Tools):
|
||||
|
@ -1,13 +1,12 @@
|
||||
import os
|
||||
import os, sys
|
||||
import stat
|
||||
import mimetypes
|
||||
import configparser
|
||||
|
||||
if __name__ == "__main__":
|
||||
from tools import Tools
|
||||
else:
|
||||
from sources.tools.tools import Tools
|
||||
if __name__ == "__main__": # if running as a script for individual testing
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
|
||||
|
||||
from sources.tools.tools import Tools
|
||||
|
||||
class FileFinder(Tools):
|
||||
"""
|
||||
@ -31,13 +30,45 @@ class FileFinder(Tools):
|
||||
except Exception as e:
|
||||
return f"Error reading file: {e}"
|
||||
|
||||
def read_arbitrary_file(self, file_path: str, file_type: str) -> str:
|
||||
"""
|
||||
Reads the content of a file with arbitrary encoding.
|
||||
Args:
|
||||
file_path (str): The path to the file to read
|
||||
Returns:
|
||||
str: The content of the file in markdown format
|
||||
"""
|
||||
mime_type, _ = mimetypes.guess_type(file_path)
|
||||
if mime_type:
|
||||
if mime_type.startswith(('image/', 'video/', 'audio/')):
|
||||
return "can't read file type: image, video, or audio files are not supported."
|
||||
content_raw = self.read_file(file_path)
|
||||
if "text" in file_type:
|
||||
content = content_raw
|
||||
elif "pdf" in file_type:
|
||||
from pypdf import PdfReader
|
||||
reader = PdfReader(file_path)
|
||||
content = '\n'.join([pt.extract_text() for pt in reader.pages])
|
||||
elif "binary" in file_type:
|
||||
content = content_raw.decode('utf-8', errors='replace')
|
||||
else:
|
||||
content = content_raw
|
||||
return content
|
||||
|
||||
def get_file_info(self, file_path: str) -> str:
|
||||
"""
|
||||
Gets information about a file, including its name, path, type, content, and permissions.
|
||||
Args:
|
||||
file_path (str): The path to the file
|
||||
Returns:
|
||||
str: A dictionary containing the file information
|
||||
"""
|
||||
if os.path.exists(file_path):
|
||||
stats = os.stat(file_path)
|
||||
permissions = oct(stat.S_IMODE(stats.st_mode))
|
||||
file_type, _ = mimetypes.guess_type(file_path)
|
||||
file_type = file_type if file_type else "Unknown"
|
||||
content = self.read_file(file_path)
|
||||
content = self.read_arbitrary_file(file_path, file_type)
|
||||
|
||||
result = {
|
||||
"filename": os.path.basename(file_path),
|
||||
|
@ -1,12 +1,12 @@
|
||||
import os
|
||||
import os, sys
|
||||
import requests
|
||||
import dotenv
|
||||
|
||||
dotenv.load_dotenv()
|
||||
|
||||
if __name__ == "__main__":
|
||||
from tools import Tools
|
||||
else:
|
||||
if __name__ == "__main__": # if running as a script for individual testing
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
|
||||
|
||||
from sources.tools.tools import Tools
|
||||
|
||||
class FlightSearch(Tools):
|
||||
|
@ -1,13 +1,14 @@
|
||||
import os
|
||||
import os, sys
|
||||
import requests
|
||||
from urllib.parse import urljoin
|
||||
from typing import Dict, Any, Optional
|
||||
|
||||
if __name__ == "__main__":
|
||||
from tools import Tools
|
||||
else:
|
||||
from sources.tools.tools import Tools
|
||||
|
||||
if __name__ == "__main__": # if running as a script for individual testing
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
|
||||
|
||||
|
||||
class MCP_finder(Tools):
|
||||
"""
|
||||
Tool to find MCPs server
|
||||
|
@ -2,9 +2,9 @@ import requests
|
||||
from bs4 import BeautifulSoup
|
||||
import os
|
||||
|
||||
if __name__ == "__main__":
|
||||
from tools import Tools
|
||||
else:
|
||||
if __name__ == "__main__": # if running as a script for individual testing
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
|
||||
|
||||
from sources.tools.tools import Tools
|
||||
|
||||
class searxSearch(Tools):
|
||||
|
@ -14,13 +14,17 @@ For example:
|
||||
print("Hello world")
|
||||
```
|
||||
This is then executed by the tool with its own class implementation of execute().
|
||||
A tool is not just for code tool but also API, internet, etc..
|
||||
A tool is not just for code tool but also API, internet search, MCP, etc..
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import configparser
|
||||
from abc import abstractmethod
|
||||
|
||||
if __name__ == "__main__": # if running as a script for individual testing
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from sources.logger import Logger
|
||||
|
||||
class Tools():
|
||||
|
@ -5,12 +5,6 @@ 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
|
||||
|
||||
|
@ -17,13 +17,13 @@ class TestBrowserAgentParsing(unittest.TestCase):
|
||||
# Test various link formats
|
||||
test_text = """
|
||||
Check this out: https://thriveonai.com/15-ai-startups-in-japan-to-take-note-of, and www.google.com!
|
||||
Also try https://test.org/about?page=1, hey this one as well bro https://weatherstack.com/documentation.
|
||||
Also try https://test.org/about?page=1, hey this one as well bro https://weatherstack.com/documentation/.
|
||||
"""
|
||||
expected = [
|
||||
"https://thriveonai.com/15-ai-startups-in-japan-to-take-note-of",
|
||||
"www.google.com",
|
||||
"https://test.org/about?page=1",
|
||||
"https://weatherstack.com/documentation"
|
||||
"https://weatherstack.com/documentation",
|
||||
]
|
||||
result = self.agent.extract_links(test_text)
|
||||
self.assertEqual(result, expected)
|
||||
|
Loading…
x
Reference in New Issue
Block a user