This commit is contained in:
martin legrand
2025-05-29 15:37:32 +02:00
7 changed files with 304 additions and 2787 deletions
+19
View File
@@ -0,0 +1,19 @@
# Python cache files
__pycache__/
*.py[cod]
# Virtual environments
venv/
.venv/
# Environment variables (secrets)
.env
# Git metadata
.git/
# macOS Finder files
.DS_Store
# Log files
*.log
+1
View File
@@ -9,6 +9,7 @@ test_agent.py
config.ini
.voices/
experimental/
chrome_bundle/
.logs/
.screenshots/*.png
.screenshots/*.jpg
+3 -1
View File
@@ -32,7 +32,9 @@ https://github.com/user-attachments/assets/b8ca60e9-7b3b-4533-840e-08f9ac426316
Disclaimer: This demo, including all the files that appear (e.g: CV_candidates.zip), are entirely fictional. We are not a corporation, we seek open-source contributors not candidates.
> 🛠️ **Work in Progress** Looking for contributors!
> 🛠⚠️ **Active Work in Progress** Please note that Code/Bash is not dockerized yet but will be soon (see docker_deployement branch) - Do not deploy over network or production.
> 🙏 Please also understand that this project began as a side experiment, with no roadmap and no expectations, we didn't expect to end in Github trending. Financial backing is exactly $1/month (shoutout to my single sponsor). Contributions, feedback, and patience are deeply appreciated.
## Installation
+47 -47
View File
@@ -8,23 +8,23 @@
[English](./README.md) | 繁體中文 | [日本語](./README_JP.md)
*一个 **100% 本地替代 Manus AI** 的方案,款支持音的 AI 助理能够自主浏览网页、编代码和规划任务,同时所有数据保留在您的设备上。专为本地推理模型量身打造,完全在您自己的硬件上运行,确保完全的隐私保护和零端依。*
*一个 **100% 本地替代 Manus AI** 的方案,款支持音的 AI 助理能够自主瀏覽網頁、编代码和規劃任務,同时所有用戶資料保留在您的裝置上。專門為本地推理模型量身打造,完全在您自己的硬體上執行,确保完全的隐私保护和零端依。*
[![Visit AgenticSeek](https://img.shields.io/static/v1?label=Website&message=AgenticSeek&color=blue&style=flat-square)](https://fosowl.github.io/agenticSeek.html) ![License](https://img.shields.io/badge/license-GPL--3.0-green) [![Discord](https://img.shields.io/badge/Discord-Join%20Us-7289DA?logo=discord&logoColor=white)](https://discord.gg/8hGDaME3TC) [![Twitter](https://img.shields.io/twitter/url/https/twitter.com/fosowl.svg?style=social&label=Update%20%40Fosowl)](https://x.com/Martin993886460)
### 为什么选择 AgenticSeek
### 为什么選擇 AgenticSeek
* 🔒 完全本地化隐私保护 - 所有功能都在您的设备上行 — 无云端服务,无数据共享。您的文件、对话和搜索始终保持私密。
* 🔒 完全本地化隐私保护 - 所有功能都在您的设备上行 — 无云端服务,无数据共享。您的文件、对话和搜索始终保持私密。
* 🌐 智能网页浏览 - AgenticSeek 能够自主浏览互联网 — 搜索、读、提取信息、填写网页表 — 全程无需人工操作。
* 🌐 智能網頁瀏覽 - AgenticSeek 能够自主瀏覽網頁 — 搜索、读、提取信息、填寫網页表 — 全程无需人工操作。
* 💻 自主编码助手 - 需要代码?它可以编、调试并行 Python、C、Go、Java 等多种语言的程序 — 全程无需监督。
* 💻 自主编码助手 - 需要代码?它可以编、调试并行 Python、C、Go、Java 等多种语言的程序 — 全程无需监督。
* 🧠 智能代理选择 - 您提问,它自动选择最适合该任务的代理。就像拥有一个随时待命的家团队。
* 🧠 智能代理选择 - 您提问,它自动选择最适合该任务的代理。就像拥有一个随时待命的家团队。
* 📋 规划执行复杂任务 - 从旅行规划到复杂项目 — 它能大型任务分解为步骤,并利用多个 AI 代理完成工作。
* 📋 规划执行复杂任务 - 从旅行规划到复杂项目 — 它能大型任务分解为步骤,并利用多个 AI 代理完成工作。
* 🎙️ 音功能 - 清晰、快速、未来感十足的语音与语音转文本功能,您能像科幻电影中一样您的个人 AI 助手对话。
* 🎙️ 音功能 - 清晰、快速、未来感十足的語音與語音轉文本功能,您能像科幻电影中一样您的个人 AI 助手对话。
https://github.com/user-attachments/assets/4bd5faf6-459f-4f94-bd1d-238c4b331469
@@ -36,7 +36,7 @@ https://github.com/user-attachments/assets/4bd5faf6-459f-4f94-bd1d-238c4b331469
確保已安裝了 Chrome driverDocker 和 Python 3.10(或更新)。
我们强烈建议您使用 Python 3.10 进行设置,否则可能发生依赖错误。
我们强烈建议您使用 Python 3.10 進行設定,否则可能发生依赖错误。
有關於 Chrome driver 的問題,請參見 **Chromedriver** 部分。
@@ -64,7 +64,7 @@ source agentic_seek_env/bin/activate
./install.sh
```
** 若要让文本转语音(TTS)功能支持中文,你需要安装 jieba(中文分词库)和 cn2an(中文数字转换库):**
** 若要將文字轉成語音(TTS)功能支持中文,你需要安装 jieba(中文分詞庫)和 cn2an(中文數字轉換庫):**
```
pip3 install jieba cn2an
@@ -73,7 +73,7 @@ pip3 install jieba cn2an
**手動安裝:**
**注意:对于任何操作系统,请确保您安装的 ChromeDriver 您已安装的 Chrome 版本匹配。运行 `google-chrome --version`。如果您的 Chrome 版本 > 135请参阅已知问题**
**注意:對於不同作業系統,請確保已經安装的 ChromeDriver 您已安装的 Chrome 版本一致。可以執行 `google-chrome --version`。如果您的 Chrome 版本 > 135請參考已知问题**
- *Linux*:
@@ -81,7 +81,7 @@ pip3 install jieba cn2an
安装依赖项:`sudo apt install -y alsa-utils portaudio19-dev python3-pyaudio libgtk-3-dev libnotify-dev libgconf-2-4 libnss3 libxss1`
安装您的 Chrome 浏览器版本匹配的 ChromeDriver
安装您的 Chrome 瀏覽器版本匹配的 ChromeDriver
`sudo apt install -y chromium-chromedriver`
安装 requirements`pip3 install -r requirements.txt`
@@ -104,11 +104,11 @@ pip3 install jieba cn2an
安装 pyreadline3`pip install pyreadline3`
手动安装 portaudio(例如,通过 vcpkg 或预编译的二制文件),然后运行:`pip install pyaudio`
手动安装 portaudio(例如,通过 vcpkg 或預編譯的二制文件),然後運行:`pip install pyaudio`
从以下址手动下载并安装 chromedriverhttps://sites.google.com/chromium.org/driver/getting-started
从以下址手动下载并安装 chromedriverhttps://sites.google.com/chromium.org/driver/getting-started
chromedriver 放置在包含在您的 PATH 中的目录中。
chromedriver 放置在包含在您的 PATH 中的目录中。
安装 requirements`pip3 install -r requirements.txt`
@@ -116,45 +116,45 @@ pip3 install jieba cn2an
**建議至少使用 Deepseek 14B 以上參數的模型,較小的模型難以使用助理功能並且很快就會忘記上下文之間的關係。**
**本地行助手**
**本地行助手**
启动你的本地提供者,例如使用 ollama:
啟動你的本地提供者,例如使用 ollama:
```sh
ollama serve
```
请参下方支持的本地提供者列表。
请参下方支持的本地提供者列表。
修改 config.ini 文件以设置 provider_name 为支持的提供者,并 provider_model 设置为该提供者支持的 LLM。我们推荐使用具有推理能力的模型,如 *Qwen**Deepseek*
修改 config.ini 文件以設定 provider_name 为支持的提供者,并 provider_model 設定为该提供者支持的 LLM。我们推荐使用具有推理能力的模型,如 *Qwen**Deepseek*
请参见 README 末尾的 **FAQ** 部分了解所需硬件。
```sh
[MAIN]
is_local = True # 无论是在本地行还是使用远程提供者。
is_local = True # 无论是在本地行还是使用远程提供者。
provider_name = ollama # 或 lm-studio, openai 等..
provider_model = deepseek-r1:14b # 选择适合您硬件的模型
provider_server_address = 127.0.0.1:11434
agent_name = Jarvis # 您的 AI 助手的名称
recover_last_session = True # 是否恢复之前的
save_session = True # 是否记住当前
speak = True # 文本转语
listen = False # 语音转文本,适用于命令行界面
recover_last_session = True # 是否恢复之前的
save_session = True # 是否记住当前
speak = True # 文本轉語
listen = False # 語音轉文本,适用于命令行界面
work_dir = /Users/mlg/Documents/workspace # AgenticSeek 的工作空间。
jarvis_personality = False # 是否使用更"贾维斯"风格的性格,不推荐在小型模型上使用
languages = en zh # 语言列表,文本转语音将默认使用列表中的第一种语言
languages = en zh # 语言列表,文本轉語音將默认使用列表中的第一种语言
[BROWSER]
headless_browser = True # 是否使用无头浏览器,只有在使用页界面时才推荐使用。
stealth_mode = True # 使用无法检测的 selenium 来减少浏览器检测
headless_browser = True # 是否使用无头瀏覽器,只有在使用页界面时才推荐使用。
stealth_mode = True # 使用无法檢測的 selenium 来减少瀏覽器檢測
```
**本地提供者列表**
| 提供者 | 本地? | 描述 |
|-------------|--------|-------------------------------------------------------|
| ollama | 是 | 使用 ollama 作为 LLM 提供者,轻松本地行 LLM |
| lm-studio | 是 | 使用 LM Studio 本地行 LLM `provider_name` 设置`lm-studio`|
| ollama | 是 | 使用 ollama 作为 LLM 提供者,轻松本地行 LLM |
| lm-studio | 是 | 使用 LM Studio 本地行 LLM `provider_name` 設定`lm-studio`|
| openai | 否 | 使用兼容的 API |
下一步: [Start services and run AgenticSeek](#Start-services-and-Run)
@@ -184,14 +184,14 @@ provider_server_address = 127.0.0.1:5000
---
## Start services and Run
(启动服务并行)
(啟動服务并行)
如果需要,请激活你的 Python 环境。
```sh
source agentic_seek_env/bin/activate
```
启动所需的服务。这将启动 `docker-compose.yml` 中的所有服务,包括:
啟動所需的服务。这將啟動 `docker-compose.yml` 中的所有服务,包括:
- searxng
- redis(由 redis 提供支持)
- 前端
@@ -201,25 +201,25 @@ sudo ./start_services.sh # MacOS
start ./start_services.cmd # Windows
```
**选项 1:** 使用 CLI 界面行。
**選項 1:** 使用 CLI 界面行。
```sh
python3 cli.py
```
**选项 2:** 使用 Web 界面行。
**選項 2:** 使用 Web 界面行。
注意:目前我們建議您使用 CLI 界面。Web 界面仍在積極開發中。
启动后端服务。
啟動後端服务。
```sh
python3 api.py
```
访问 `http://localhost:3000/`,你应该看到 Web 界面。
访问 `http://localhost:3000/`,你应该看到 Web 界面。
请注意,目前 Web 界面不支持消息流式传输
请注意,目前 Web 界面不支持消息流式傳輸
*如果你不知道如何開始,請參閱 **Usage** 部分*
@@ -228,9 +228,9 @@ python3 api.py
## Usage (使用方法)
为确保 agenticSeek 在中文环境下正常工作,请确保在 config.ini 中设置语言选项
为确保 agenticSeek 在中文环境下正常工作,请确保在 config.ini 中設定语言選項
languages = en zh
更多信息请参 Config 部分
更多信息请参 Config 部分
確定所有的核心檔案都啟用了,也就是執行過這條命令 `./start_services.sh` 然後你就可以使用 `python3 cli.py` 來啟動 AgenticSeek 了!
@@ -287,11 +287,11 @@ python3 cli.py
所以我們希望你在使用時,能明確地表明你希望他要怎麼做,下面給你一個範例!
你該說:
- 进行网络搜索,找出哪些国家最适合自旅行
- 進行網路搜索,找出哪些国家最适合自旅行
而不是說:
- 你知道哪些国家适合自旅行?
- 你知道哪些国家适合自旅行?
---
@@ -357,7 +357,7 @@ provider_server_address = x.x.x.x:3333
## 語音轉文字
请注意,目前语音转文字功能仅支持英语。
请注意,目前語音轉文字功能僅支援英语。
預設狀況下,語音轉文字功能是停用的。若要啟用它,請在 `config.ini` 檔案中,將 `listen` 選項設為 `True`
@@ -538,13 +538,13 @@ https://googlechromelabs.github.io/chrome-for-testing/
**Q: 是否支持中文以外的语言?**
DeepSeek R1 天生说中文
DeepSeek R1 天生说中文
但注意:代理路由系统只懂英文,所以必须通过 config.ini 的 languages 参数(如 languages = en zh)告诉系统:
如果不设置中文?果可能是:你让它写代码,结果跳出来个"生代理"(虽然我们根本没有这个代理... 但系统一脸懵圈!)
如果不設定中文?果可能是:你讓它寫代码,结果跳出来个"生代理"(虽然我们根本没有这个代理... 但系统一脸懵圈!)
实际上下载一个小型翻译模型来协助任务分配
实际上下载一个小型翻译模型来协助任务分配
## 貢獻
@@ -556,8 +556,8 @@ DeepSeek R1 天生会说中文
## 维护者:
> [Fosowl](https://github.com/Fosowl) | 巴黎时间
> [Fosowl](https://github.com/Fosowl) | 巴黎時間 | (有时很忙)
> [antoineVIVIES](https://github.com/antoineVIVIES) | Taipei Time
> [https://github.com/antoineVIVIES](https://github.com/antoineVIVIES) | 台北時間 | (經常很忙)
> [steveh8758](https://github.com/steveh8758) | 台北时间
> [steveh8758](https://github.com/steveh8758) | 台北時間 | (總是很忙)
File diff suppressed because it is too large Load Diff
+4 -2
View File
@@ -140,8 +140,10 @@ class Agent():
Remove the reasoning block of reasoning model like deepseek.
"""
end_tag = "</think>"
end_idx = text.rfind(end_tag)+8
return text[end_idx:]
end_idx = text.rfind(end_tag)
if end_idx == -1:
return text
return text[end_idx+8:]
def extract_reasoning_text(self, text: str) -> None:
"""
+230
View File
@@ -0,0 +1,230 @@
import unittest
import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from sources.tools.tools import Tools
class TestToolsParsing(unittest.TestCase):
"""
Test suite for the Tools class parsing functionality, specifically the load_exec_block method.
This method is responsible for extracting code blocks from LLM-generated text.
"""
def setUp(self):
"""Set up test fixtures before each test method."""
class TestTool(Tools):
def execute(self, blocks, safety=False):
return "test execution"
def execution_failure_check(self, output):
return False
def interpreter_feedback(self, output):
return "test feedback"
self.tool = TestTool()
self.tool.tag = "python" # Set tag for testing
def test_load_exec_block_single_block(self):
"""Test parsing a single code block from LLM text."""
llm_text = """Here's some Python code:
```python
print("Hello, World!")
x = 42
```
That's the code."""
blocks, save_path = self.tool.load_exec_block(llm_text)
self.assertIsNotNone(blocks)
self.assertEqual(len(blocks), 1)
self.assertEqual(blocks[0], '\nprint("Hello, World!")\nx = 42\n')
self.assertIsNone(save_path)
def test_load_exec_block_multiple_blocks(self):
"""Test parsing multiple code blocks from LLM text."""
llm_text = """First block:
```python
import os
print("First block")
```
Second block:
```python
import sys
print("Second block")
```
Done."""
blocks, save_path = self.tool.load_exec_block(llm_text)
self.assertIsNotNone(blocks)
self.assertEqual(len(blocks), 2)
self.assertEqual(blocks[0], '\nimport os\nprint("First block")\n')
self.assertEqual(blocks[1], '\nimport sys\nprint("Second block")\n')
self.assertIsNone(save_path)
def test_load_exec_block_with_save_path(self):
"""Test parsing code block with save path specification."""
llm_text = """```python
save_path: test_file.py
import os
print("Hello with save path")
```"""
blocks, save_path = self.tool.load_exec_block(llm_text)
self.assertIsNotNone(blocks)
self.assertEqual(len(blocks), 1)
self.assertEqual(blocks[0], '\nsave_path: test_file.py\nimport os\nprint("Hello with save path")\n')
self.assertIsNone(save_path)
def test_load_exec_block_with_indentation(self):
"""Test parsing code blocks with leading whitespace/indentation."""
llm_text = """ Here's indented code:
```python
def hello():
print("Hello")
return True
```
End of code."""
blocks, save_path = self.tool.load_exec_block(llm_text)
self.assertIsNotNone(blocks)
self.assertEqual(len(blocks), 1)
expected_code = '\ndef hello():\n print("Hello")\n return True\n'
self.assertEqual(blocks[0], expected_code)
def test_load_exec_block_no_blocks(self):
"""Test parsing text with no code blocks."""
llm_text = """This is just regular text with no code blocks.
There are no python blocks here.
Just plain text."""
blocks, save_path = self.tool.load_exec_block(llm_text)
self.assertIsNone(blocks)
self.assertIsNone(save_path)
def test_load_exec_block_wrong_tag(self):
"""Test parsing text with code blocks but wrong language tag."""
llm_text = """```javascript
console.log("This is JavaScript, not Python");
```"""
blocks, save_path = self.tool.load_exec_block(llm_text)
self.assertIsNone(blocks)
self.assertIsNone(save_path)
def test_load_exec_block_incomplete_block(self):
"""Test parsing text with incomplete code block (missing closing tag)."""
llm_text = """```python
print("This block has no closing tag")
x = 42"""
blocks, save_path = self.tool.load_exec_block(llm_text)
self.assertEqual(blocks, [])
self.assertIsNone(save_path)
def test_load_exec_block_empty_block(self):
"""Test parsing empty code block."""
llm_text = """```python
```"""
blocks, save_path = self.tool.load_exec_block(llm_text)
self.assertIsNotNone(blocks)
self.assertEqual(len(blocks), 1)
self.assertEqual(blocks[0], '\n')
def test_load_exec_block_mixed_content(self):
"""Test parsing text with mixed content including code blocks."""
llm_text = """Let me help you with that task.
First, I'll import the necessary modules:
```python
import os
import sys
```
Then I'll define a function:
```python
def process_data(data):
return data.upper()
```
Finally, let's use it:
```python
result = process_data("hello world")
print(result)
```
That should work!"""
blocks, save_path = self.tool.load_exec_block(llm_text)
self.assertIsNotNone(blocks)
self.assertEqual(len(blocks), 3)
self.assertEqual(blocks[0], '\nimport os\nimport sys\n')
self.assertEqual(blocks[1], '\ndef process_data(data):\n return data.upper()\n')
self.assertEqual(blocks[2], '\nresult = process_data("hello world")\nprint(result)\n')
def test_load_exec_block_with_special_characters(self):
"""Test parsing code blocks containing special characters."""
llm_text = """```python
text = "Hello \"world\" with 'quotes'"
regex = r"^\\d+$"
path = "C:\\Users\\test\\file.txt"
```"""
blocks, save_path = self.tool.load_exec_block(llm_text)
self.assertIsNotNone(blocks)
self.assertEqual(len(blocks), 1)
expected = '\ntext = "Hello "world" with \'quotes\'"\nregex = r"^\\d+$"\npath = "C:\\Users\\test\\file.txt"\n'
self.assertEqual(blocks[0], expected)
def test_load_exec_block_tag_undefined(self):
"""Test that assertion error is raised when tag is undefined."""
self.tool.tag = "undefined"
llm_text = """```python
print("test")
```"""
with self.assertRaises(AssertionError):
self.tool.load_exec_block(llm_text)
def test_found_executable_blocks_flag(self):
"""Test that the executable blocks found flag is set correctly."""
self.assertFalse(self.tool.found_executable_blocks())
llm_text = """```python
print("test")
```"""
blocks, save_path = self.tool.load_exec_block(llm_text)
self.assertTrue(self.tool.found_executable_blocks())
self.assertFalse(self.tool.found_executable_blocks())
def test_get_parameter_value(self):
"""Test the get_parameter_value helper method."""
block = """param1 = value1
param2 = value2
some other text
param3 = value3"""
self.assertEqual(self.tool.get_parameter_value(block, "param1"), "value1")
self.assertEqual(self.tool.get_parameter_value(block, "param2"), "value2")
self.assertEqual(self.tool.get_parameter_value(block, "param3"), "value3")
self.assertIsNone(self.tool.get_parameter_value(block, "nonexistent"))
if __name__ == '__main__':
unittest.main()