mirror of
https://github.com/tcsenpai/agenticSeek.git
synced 2025-06-07 03:25:32 +00:00
Merge pull request #126 from Fosowl/dev
Update readme and slight frontend fix attempt
This commit is contained in:
commit
50142b48f8
@ -15,6 +15,7 @@ English | [中文](./README_CHS.md) | [繁體中文](./README_CHT.md) | [Franç
|
|||||||
> 🛠️ **Work in Progress** – Looking for contributors!
|
> 🛠️ **Work in Progress** – Looking for contributors!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
https://github.com/user-attachments/assets/4bd5faf6-459f-4f94-bd1d-238c4b331469
|
https://github.com/user-attachments/assets/4bd5faf6-459f-4f94-bd1d-238c4b331469
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
**Manus AI 的本地替代品**,它是一个具有语音功能的大语言模型秘书,可以 Coding、访问你的电脑文件、浏览网页,并自动修正错误与反省,最重要的是不会向云端传送任何资料。采用 DeepSeek R1 等推理模型构建,完全在本地硬体上运行,进而保证资料的隐私。
|
**Manus AI 的本地替代品**,它是一个具有语音功能的大语言模型秘书,可以 Coding、访问你的电脑文件、浏览网页,并自动修正错误与反省,最重要的是不会向云端传送任何资料。采用 DeepSeek R1 等推理模型构建,完全在本地硬体上运行,进而保证资料的隐私。
|
||||||
|
|
||||||
[](https://fosowl.github.io/agenticSeek.html)  [](https://discord.gg/4Ub2D6Fj) [](https://x.com/Martin993886460)
|
[](https://fosowl.github.io/agenticSeek.html)  [](https://discord.gg/XSTKZ8nP) [](https://x.com/Martin993886460)
|
||||||
|
|
||||||
> 🛠️ **目前还在开发阶段** – 欢迎任何贡献者加入我们!
|
> 🛠️ **目前还在开发阶段** – 欢迎任何贡献者加入我们!
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
**Manus AI 的本地替代品**,它是一個具有語音功能的大語言模型秘書,可以 Coding、訪問你的電腦文件、瀏覽網頁,並自動修正錯誤與反省,最重要的是不會向雲端傳送任何資料。採用 DeepSeek R1 等推理模型構建,完全在本地硬體上運行,進而保證資料的隱私。
|
**Manus AI 的本地替代品**,它是一個具有語音功能的大語言模型秘書,可以 Coding、訪問你的電腦文件、瀏覽網頁,並自動修正錯誤與反省,最重要的是不會向雲端傳送任何資料。採用 DeepSeek R1 等推理模型構建,完全在本地硬體上運行,進而保證資料的隱私。
|
||||||
|
|
||||||
[](https://fosowl.github.io/agenticSeek.html)  [](https://discord.gg/4Ub2D6Fj) [](https://x.com/Martin993886460)
|
[](https://fosowl.github.io/agenticSeek.html)  [](https://discord.gg/XSTKZ8nP) [](https://x.com/Martin993886460)
|
||||||
|
|
||||||
> 🛠️ **目前還在開發階段** – 歡迎任何貢獻者加入我們!
|
> 🛠️ **目前還在開發階段** – 歡迎任何貢獻者加入我們!
|
||||||
|
|
||||||
|
12
api.py
12
api.py
@ -12,6 +12,7 @@ from fastapi.responses import JSONResponse
|
|||||||
from fastapi.responses import FileResponse
|
from fastapi.responses import FileResponse
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
|
import uuid
|
||||||
|
|
||||||
from sources.llm_provider import Provider
|
from sources.llm_provider import Provider
|
||||||
from sources.interaction import Interaction
|
from sources.interaction import Interaction
|
||||||
@ -21,6 +22,7 @@ from sources.utility import pretty_print
|
|||||||
from sources.logger import Logger
|
from sources.logger import Logger
|
||||||
from sources.schemas import QueryRequest, QueryResponse
|
from sources.schemas import QueryRequest, QueryResponse
|
||||||
|
|
||||||
|
|
||||||
from celery import Celery
|
from celery import Celery
|
||||||
|
|
||||||
api = FastAPI(title="AgenticSeek API", version="0.1.0")
|
api = FastAPI(title="AgenticSeek API", version="0.1.0")
|
||||||
@ -131,7 +133,8 @@ async def get_latest_answer():
|
|||||||
global query_resp_history
|
global query_resp_history
|
||||||
if interaction.current_agent is None:
|
if interaction.current_agent is None:
|
||||||
return JSONResponse(status_code=404, content={"error": "No agent available"})
|
return JSONResponse(status_code=404, content={"error": "No agent available"})
|
||||||
if interaction.current_agent.last_answer not in [q["answer"] for q in query_resp_history]:
|
uid = str(uuid.uuid4())
|
||||||
|
if not any(q["answer"] == interaction.current_agent.last_answer for q in query_resp_history):
|
||||||
query_resp = {
|
query_resp = {
|
||||||
"done": "false",
|
"done": "false",
|
||||||
"answer": interaction.current_agent.last_answer,
|
"answer": interaction.current_agent.last_answer,
|
||||||
@ -139,8 +142,9 @@ async def get_latest_answer():
|
|||||||
"success": interaction.current_agent.success,
|
"success": interaction.current_agent.success,
|
||||||
"blocks": {f'{i}': block.jsonify() for i, block in enumerate(interaction.current_agent.get_blocks_result())} if interaction.current_agent else {},
|
"blocks": {f'{i}': block.jsonify() for i, block in enumerate(interaction.current_agent.get_blocks_result())} if interaction.current_agent else {},
|
||||||
"status": interaction.current_agent.get_status_message if interaction.current_agent else "No status available",
|
"status": interaction.current_agent.get_status_message if interaction.current_agent else "No status available",
|
||||||
"timestamp": str(time.time())
|
"uid": uid
|
||||||
}
|
}
|
||||||
|
interaction.current_agent.last_answer = ""
|
||||||
query_resp_history.append(query_resp)
|
query_resp_history.append(query_resp)
|
||||||
return JSONResponse(status_code=200, content=query_resp)
|
return JSONResponse(status_code=200, content=query_resp)
|
||||||
if query_resp_history:
|
if query_resp_history:
|
||||||
@ -176,7 +180,7 @@ async def process_query(request: QueryRequest):
|
|||||||
success="false",
|
success="false",
|
||||||
blocks={},
|
blocks={},
|
||||||
status="Ready",
|
status="Ready",
|
||||||
timestamp=str(time.time())
|
uid=str(uuid.uuid4())
|
||||||
)
|
)
|
||||||
if is_generating:
|
if is_generating:
|
||||||
logger.warning("Another query is being processed, please wait.")
|
logger.warning("Another query is being processed, please wait.")
|
||||||
@ -215,7 +219,7 @@ async def process_query(request: QueryRequest):
|
|||||||
"success": query_resp.success,
|
"success": query_resp.success,
|
||||||
"blocks": query_resp.blocks,
|
"blocks": query_resp.blocks,
|
||||||
"status": query_resp.status,
|
"status": query_resp.status,
|
||||||
"timestamp": query_resp.timestamp
|
"uid": query_resp.uid
|
||||||
}
|
}
|
||||||
query_resp_history.append(query_resp_dict)
|
query_resp_history.append(query_resp_dict)
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ function App() {
|
|||||||
checkHealth();
|
checkHealth();
|
||||||
fetchLatestAnswer();
|
fetchLatestAnswer();
|
||||||
fetchScreenshot();
|
fetchScreenshot();
|
||||||
}, 1500);
|
}, 3000);
|
||||||
return () => clearInterval(intervalId);
|
return () => clearInterval(intervalId);
|
||||||
}, [messages]);
|
}, [messages]);
|
||||||
|
|
||||||
@ -61,7 +61,13 @@ function App() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const normalizeAnswer = (answer) => answer.trim().toLowerCase();
|
const normalizeAnswer = (answer) => {
|
||||||
|
return answer
|
||||||
|
.trim()
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/\s+/g, ' ')
|
||||||
|
.replace(/[.,!?]/g, '')
|
||||||
|
};
|
||||||
|
|
||||||
const scrollToBottom = () => {
|
const scrollToBottom = () => {
|
||||||
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
||||||
@ -75,12 +81,10 @@ function App() {
|
|||||||
if (!data.answer || data.answer.trim() === '') {
|
if (!data.answer || data.answer.trim() === '') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const normalizedNewAnswer = normalizeAnswer(data.answer);
|
||||||
const answerExists = messages.some(
|
const answerExists = messages.some(
|
||||||
(msg) =>
|
(msg) => normalizeAnswer(msg.content) === normalizedNewAnswer
|
||||||
msg.timestamp === data.timestamp &&
|
|
||||||
normalizeAnswer(msg.content) === normalizeAnswer(data.answer)
|
|
||||||
);
|
);
|
||||||
console.log('Fetched latest answer:', data.answer);
|
|
||||||
if (!answerExists) {
|
if (!answerExists) {
|
||||||
setMessages((prev) => [
|
setMessages((prev) => [
|
||||||
...prev,
|
...prev,
|
||||||
@ -89,11 +93,13 @@ function App() {
|
|||||||
content: data.answer,
|
content: data.answer,
|
||||||
agentName: data.agent_name,
|
agentName: data.agent_name,
|
||||||
status: data.status,
|
status: data.status,
|
||||||
timestamp: data.timestamp,
|
uid: data.uid,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
setStatus(data.status);
|
setStatus(data.status);
|
||||||
scrollToBottom();
|
scrollToBottom();
|
||||||
|
} else {
|
||||||
|
console.log('Duplicate answer detected, skipping:', data.answer);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching latest answer:', error);
|
console.error('Error fetching latest answer:', error);
|
||||||
|
@ -115,7 +115,7 @@ class Agent():
|
|||||||
|
|
||||||
def extract_reasoning_text(self, text: str) -> None:
|
def extract_reasoning_text(self, text: str) -> None:
|
||||||
"""
|
"""
|
||||||
Extract the reasoning block of a easoning model like deepseek.
|
Extract the reasoning block of a reasoning model like deepseek.
|
||||||
"""
|
"""
|
||||||
start_tag = "<think>"
|
start_tag = "<think>"
|
||||||
end_tag = "</think>"
|
end_tag = "</think>"
|
||||||
|
@ -244,7 +244,7 @@ class Browser:
|
|||||||
|
|
||||||
def is_link_valid(self, url:str) -> bool:
|
def is_link_valid(self, url:str) -> bool:
|
||||||
"""Check if a URL is a valid link (page, not related to icon or metadata)."""
|
"""Check if a URL is a valid link (page, not related to icon or metadata)."""
|
||||||
if len(url) > 64:
|
if len(url) > 72:
|
||||||
self.logger.warning(f"URL too long: {url}")
|
self.logger.warning(f"URL too long: {url}")
|
||||||
return False
|
return False
|
||||||
parsed_url = urlparse(url)
|
parsed_url = urlparse(url)
|
||||||
|
@ -22,7 +22,7 @@ class Provider:
|
|||||||
self.provider_name = provider_name.lower()
|
self.provider_name = provider_name.lower()
|
||||||
self.model = model
|
self.model = model
|
||||||
self.is_local = is_local
|
self.is_local = is_local
|
||||||
self.server_ip = self.check_address_format(server_address)
|
self.server_ip = server_address
|
||||||
self.available_providers = {
|
self.available_providers = {
|
||||||
"ollama": self.ollama_fn,
|
"ollama": self.ollama_fn,
|
||||||
"server": self.server_fn,
|
"server": self.server_fn,
|
||||||
@ -44,7 +44,6 @@ class Provider:
|
|||||||
self.api_key = self.get_api_key(self.provider_name)
|
self.api_key = self.get_api_key(self.provider_name)
|
||||||
elif self.provider_name != "ollama":
|
elif self.provider_name != "ollama":
|
||||||
pretty_print(f"Provider: {provider_name} initialized at {self.server_ip}", color="success")
|
pretty_print(f"Provider: {provider_name} initialized at {self.server_ip}", color="success")
|
||||||
self.check_address_format(self.server_ip)
|
|
||||||
if not self.is_ip_online(self.server_ip.split(':')[0]):
|
if not self.is_ip_online(self.server_ip.split(':')[0]):
|
||||||
raise Exception(f"Server at {self.server_ip} is offline.")
|
raise Exception(f"Server at {self.server_ip} is offline.")
|
||||||
|
|
||||||
@ -57,21 +56,6 @@ class Provider:
|
|||||||
exit(1)
|
exit(1)
|
||||||
return api_key
|
return api_key
|
||||||
|
|
||||||
def check_address_format(self, address):
|
|
||||||
"""
|
|
||||||
Validate if the address is valid IP.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
address = address.replace('http://', '')
|
|
||||||
ip, port = address.rsplit(":", 1)
|
|
||||||
if all(c.lower() in ".:abcdef0123456789" for c in ip):
|
|
||||||
ipaddress.ip_address(ip)
|
|
||||||
if not port.isdigit() or not (0 <= int(port) <= 65535):
|
|
||||||
raise ValueError("Port must be a number between 0 and 65535.")
|
|
||||||
except ValueError as e:
|
|
||||||
raise Exception(f"Invalid address format: {e}. Is port specified?")
|
|
||||||
return address
|
|
||||||
|
|
||||||
def respond(self, history, verbose = True):
|
def respond(self, history, verbose = True):
|
||||||
"""
|
"""
|
||||||
Use the choosen provider to generate text.
|
Use the choosen provider to generate text.
|
||||||
|
@ -178,6 +178,7 @@ class AgentRouter:
|
|||||||
("Find a public API for movie data and build a web app to display movie ratings", "HIGH"),
|
("Find a public API for movie data and build a web app to display movie ratings", "HIGH"),
|
||||||
("Create a Node.js server that queries a public API for traffic data and displays it", "HIGH"),
|
("Create a Node.js server that queries a public API for traffic data and displays it", "HIGH"),
|
||||||
("can you find api and build a python web app with it ?", "HIGH"),
|
("can you find api and build a python web app with it ?", "HIGH"),
|
||||||
|
("do a deep search of current AI player for 2025 and make me a report in a file", "HIGH"),
|
||||||
("Find a public API for recipe data and build a web app to display recipes", "HIGH"),
|
("Find a public API for recipe data and build a web app to display recipes", "HIGH"),
|
||||||
("Search the web for recent space mission updates and build a Flask app", "HIGH"),
|
("Search the web for recent space mission updates and build a Flask app", "HIGH"),
|
||||||
("Create a Python script to scrape a website and save data to a database", "HIGH"),
|
("Create a Python script to scrape a website and save data to a database", "HIGH"),
|
||||||
|
@ -23,10 +23,10 @@ class QueryResponse(BaseModel):
|
|||||||
success: str
|
success: str
|
||||||
blocks: dict
|
blocks: dict
|
||||||
status: str
|
status: str
|
||||||
timestamp: str
|
uid: str
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"Done: {self.done}, Answer: {self.answer}, Agent Name: {self.agent_name}, Success: {self.success}, Blocks: {self.blocks}"
|
return f"Done: {self.done}, Answer: {self.answer}, Agent Name: {self.agent_name}, Success: {self.success}, Blocks: {self.blocks}, Status: {self.status}, UID: {self.uid}"
|
||||||
|
|
||||||
def jsonify(self):
|
def jsonify(self):
|
||||||
return {
|
return {
|
||||||
@ -34,7 +34,9 @@ class QueryResponse(BaseModel):
|
|||||||
"answer": self.answer,
|
"answer": self.answer,
|
||||||
"agent_name": self.agent_name,
|
"agent_name": self.agent_name,
|
||||||
"success": self.success,
|
"success": self.success,
|
||||||
"blocks": self.blocks
|
"blocks": self.blocks,
|
||||||
|
"status": self.status,
|
||||||
|
"uid": self.uid
|
||||||
}
|
}
|
||||||
|
|
||||||
class executorResult:
|
class executorResult:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user