jarvis-ai-assistant 0.1.6__py3-none-any.whl → 0.1.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of jarvis-ai-assistant might be problematic. Click here for more details.
- jarvis/__init__.py +1 -1
- jarvis/__pycache__/__init__.cpython-313.pyc +0 -0
- jarvis/__pycache__/agent.cpython-313.pyc +0 -0
- jarvis/__pycache__/main.cpython-313.pyc +0 -0
- jarvis/__pycache__/models.cpython-313.pyc +0 -0
- jarvis/__pycache__/zte_llm.cpython-313.pyc +0 -0
- jarvis/agent.py +203 -100
- jarvis/main.py +22 -6
- jarvis/models.py +58 -66
- jarvis/tools/__init__.py +0 -2
- jarvis/tools/__pycache__/__init__.cpython-313.pyc +0 -0
- jarvis/tools/__pycache__/base.cpython-313.pyc +0 -0
- jarvis/tools/__pycache__/bing_search.cpython-313.pyc +0 -0
- jarvis/tools/__pycache__/file_ops.cpython-313.pyc +0 -0
- jarvis/tools/__pycache__/search.cpython-313.pyc +0 -0
- jarvis/tools/__pycache__/shell.cpython-313.pyc +0 -0
- jarvis/tools/__pycache__/sub_agent.cpython-313.pyc +0 -0
- jarvis/tools/__pycache__/webpage.cpython-313.pyc +0 -0
- jarvis/tools/base.py +8 -19
- jarvis/tools/file_ops.py +1 -1
- jarvis/tools/search.py +112 -16
- jarvis/tools/shell.py +1 -20
- jarvis/tools/sub_agent.py +17 -75
- jarvis/tools/webpage.py +12 -26
- jarvis/zte_llm.py +26 -27
- {jarvis_ai_assistant-0.1.6.dist-info → jarvis_ai_assistant-0.1.8.dist-info}/METADATA +2 -1
- jarvis_ai_assistant-0.1.8.dist-info/RECORD +38 -0
- jarvis/tools/user_input.py +0 -74
- jarvis_ai_assistant-0.1.6.dist-info/RECORD +0 -38
- {jarvis_ai_assistant-0.1.6.dist-info → jarvis_ai_assistant-0.1.8.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.6.dist-info → jarvis_ai_assistant-0.1.8.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.6.dist-info → jarvis_ai_assistant-0.1.8.dist-info}/top_level.txt +0 -0
jarvis/tools/base.py
CHANGED
|
@@ -13,12 +13,9 @@ class Tool:
|
|
|
13
13
|
def to_dict(self) -> Dict:
|
|
14
14
|
"""转换为Ollama工具格式"""
|
|
15
15
|
return {
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
"description": self.description,
|
|
20
|
-
"parameters": self.parameters
|
|
21
|
-
}
|
|
16
|
+
"name": self.name,
|
|
17
|
+
"description": self.description,
|
|
18
|
+
"parameters": json.dumps(self.parameters)
|
|
22
19
|
}
|
|
23
20
|
|
|
24
21
|
def execute(self, arguments: Dict) -> Dict[str, Any]:
|
|
@@ -38,14 +35,13 @@ class ToolRegistry:
|
|
|
38
35
|
from .file_ops import FileOperationTool
|
|
39
36
|
from .webpage import WebpageTool
|
|
40
37
|
from .sub_agent import SubAgentTool
|
|
41
|
-
from .user_input import UserInputTool
|
|
42
38
|
|
|
43
39
|
tools = [
|
|
44
|
-
SearchTool(),
|
|
40
|
+
SearchTool(self.model),
|
|
45
41
|
ShellTool(),
|
|
46
42
|
FileOperationTool(),
|
|
47
43
|
WebpageTool(),
|
|
48
|
-
|
|
44
|
+
SubAgentTool(self.model)
|
|
49
45
|
]
|
|
50
46
|
|
|
51
47
|
for tool in tools:
|
|
@@ -56,14 +52,6 @@ class ToolRegistry:
|
|
|
56
52
|
func=tool.execute
|
|
57
53
|
)
|
|
58
54
|
|
|
59
|
-
sub_agent_tool = SubAgentTool(self.model)
|
|
60
|
-
self.register_tool(
|
|
61
|
-
name=sub_agent_tool.name,
|
|
62
|
-
description=sub_agent_tool.description,
|
|
63
|
-
parameters=sub_agent_tool.parameters,
|
|
64
|
-
func=sub_agent_tool.execute
|
|
65
|
-
)
|
|
66
|
-
|
|
67
55
|
def register_tool(self, name: str, description: str, parameters: Dict, func: Callable):
|
|
68
56
|
"""注册新工具"""
|
|
69
57
|
self.tools[name] = Tool(name, description, parameters, func)
|
|
@@ -90,8 +78,8 @@ class ToolRegistry:
|
|
|
90
78
|
|
|
91
79
|
# 只处理第一个工具调用
|
|
92
80
|
tool_call = tool_calls[0]
|
|
93
|
-
name = tool_call["
|
|
94
|
-
args = tool_call["
|
|
81
|
+
name = tool_call["name"]
|
|
82
|
+
args = tool_call["arguments"]
|
|
95
83
|
|
|
96
84
|
if isinstance(args, str):
|
|
97
85
|
try:
|
|
@@ -121,6 +109,7 @@ class ToolRegistry:
|
|
|
121
109
|
if stderr:
|
|
122
110
|
output_parts.append(f"错误:\n{stderr}")
|
|
123
111
|
output = "\n\n".join(output_parts)
|
|
112
|
+
output = "没有输出和错误" if not output else output
|
|
124
113
|
PrettyOutput.section("执行成功", OutputType.SUCCESS)
|
|
125
114
|
else:
|
|
126
115
|
error_msg = result["error"]
|
jarvis/tools/file_ops.py
CHANGED
|
@@ -5,7 +5,7 @@ from ..utils import PrettyOutput, OutputType
|
|
|
5
5
|
|
|
6
6
|
class FileOperationTool:
|
|
7
7
|
name = "file_operation"
|
|
8
|
-
description = "
|
|
8
|
+
description = "文件操作 (read/write/append/exists)"
|
|
9
9
|
parameters = {
|
|
10
10
|
"type": "object",
|
|
11
11
|
"properties": {
|
jarvis/tools/search.py
CHANGED
|
@@ -1,43 +1,139 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import os
|
|
2
|
+
import requests
|
|
3
|
+
from typing import Dict, Any, List
|
|
3
4
|
from ..utils import PrettyOutput, OutputType
|
|
5
|
+
from .webpage import WebpageTool
|
|
4
6
|
|
|
5
7
|
class SearchTool:
|
|
6
8
|
name = "search"
|
|
7
|
-
description = "
|
|
9
|
+
description = "使用搜索引擎搜索信息,并根据问题提取关键信息"
|
|
8
10
|
parameters = {
|
|
9
11
|
"type": "object",
|
|
10
12
|
"properties": {
|
|
11
13
|
"query": {
|
|
12
14
|
"type": "string",
|
|
13
|
-
"description": "
|
|
15
|
+
"description": "搜索关键词"
|
|
16
|
+
},
|
|
17
|
+
"question": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"description": "需要回答的具体问题,用于从搜索结果中提取相关信息"
|
|
14
20
|
},
|
|
15
21
|
"max_results": {
|
|
16
22
|
"type": "integer",
|
|
17
|
-
"description": "
|
|
18
|
-
"default":
|
|
23
|
+
"description": "最大搜索结果数量",
|
|
24
|
+
"default": 3
|
|
19
25
|
}
|
|
20
26
|
},
|
|
21
|
-
"required": ["query"]
|
|
27
|
+
"required": ["query", "question"]
|
|
22
28
|
}
|
|
23
29
|
|
|
30
|
+
def __init__(self, model):
|
|
31
|
+
"""初始化搜索工具,需要传入语言模型用于信息提取"""
|
|
32
|
+
self.model = model
|
|
33
|
+
self.webpage_tool = WebpageTool()
|
|
34
|
+
self.api_key = os.getenv("SEARCH_API_KEY")
|
|
35
|
+
self.engine = os.getenv("SEARCH_ENGINE", "bing")
|
|
36
|
+
if not self.api_key:
|
|
37
|
+
raise ValueError("未设置SEARCH_API_KEY环境变量")
|
|
38
|
+
|
|
39
|
+
def _search(self, query: str, max_results: int) -> List[Dict]:
|
|
40
|
+
"""执行搜索请求"""
|
|
41
|
+
url = "https://serpapi.webscrapingapi.com/v2"
|
|
42
|
+
params = {
|
|
43
|
+
"engine": self.engine,
|
|
44
|
+
"api_key": self.api_key,
|
|
45
|
+
"q": query
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
try:
|
|
49
|
+
response = requests.get(url, params=params)
|
|
50
|
+
response.raise_for_status()
|
|
51
|
+
data = response.json()
|
|
52
|
+
|
|
53
|
+
# 从搜索结果中提取有机结果
|
|
54
|
+
results = []
|
|
55
|
+
if "organic" in data:
|
|
56
|
+
for result in data["organic"][:max_results]:
|
|
57
|
+
results.append({
|
|
58
|
+
"title": result.get("title", ""),
|
|
59
|
+
"href": result.get("link", ""),
|
|
60
|
+
"body": result.get("description", "")
|
|
61
|
+
})
|
|
62
|
+
return results
|
|
63
|
+
except Exception as e:
|
|
64
|
+
PrettyOutput.print(f"搜索请求失败: {str(e)}", OutputType.ERROR)
|
|
65
|
+
return []
|
|
66
|
+
|
|
67
|
+
def _extract_info(self, contents: List[str], question: str) -> str:
|
|
68
|
+
"""使用语言模型从网页内容中提取关键信息"""
|
|
69
|
+
prompt = {
|
|
70
|
+
"role": "user",
|
|
71
|
+
"content": f"""请根据以下搜索结果内容,回答问题:{question}
|
|
72
|
+
|
|
73
|
+
搜索结果内容:
|
|
74
|
+
{'-' * 40}
|
|
75
|
+
{''.join(contents)}
|
|
76
|
+
{'-' * 40}
|
|
77
|
+
|
|
78
|
+
请提供一个简洁、准确的答案,重点关注与问题直接相关的信息。如果搜索结果中没有相关信息,请明确说明。
|
|
79
|
+
回答时注意:
|
|
80
|
+
1. 保持客观性,只基于搜索结果提供信息
|
|
81
|
+
2. 如果不同来源有冲突,请指出差异
|
|
82
|
+
3. 适当引用信息来源
|
|
83
|
+
4. 如果信息不完整或不确定,请说明"""
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
response = self.model.chat([prompt])
|
|
88
|
+
return response
|
|
89
|
+
except Exception as e:
|
|
90
|
+
return f"信息提取失败: {str(e)}"
|
|
91
|
+
|
|
24
92
|
def execute(self, args: Dict) -> Dict[str, Any]:
|
|
25
|
-
"""
|
|
93
|
+
"""执行搜索并提取信息"""
|
|
26
94
|
try:
|
|
27
|
-
|
|
28
|
-
|
|
95
|
+
query = args["query"]
|
|
96
|
+
question = args["question"]
|
|
97
|
+
max_results = args.get("max_results", 3)
|
|
98
|
+
|
|
99
|
+
# 打印搜索信息
|
|
100
|
+
PrettyOutput.print(f"搜索查询: {query}", OutputType.INFO)
|
|
101
|
+
PrettyOutput.print(f"相关问题: {question}", OutputType.INFO)
|
|
29
102
|
|
|
30
103
|
# 获取搜索结果
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
104
|
+
results = self._search(query, max_results)
|
|
105
|
+
if not results:
|
|
106
|
+
return {
|
|
107
|
+
"success": False,
|
|
108
|
+
"error": "未能获取任何搜索结果"
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# 收集网页内容
|
|
112
|
+
contents = []
|
|
113
|
+
for i, result in enumerate(results, 1):
|
|
114
|
+
try:
|
|
115
|
+
PrettyOutput.print(f"正在读取第 {i}/{len(results)} 个结果... {result['title']} - {result['href']}", OutputType.PROGRESS)
|
|
116
|
+
webpage_result = self.webpage_tool.execute({"url": result["href"]})
|
|
117
|
+
if webpage_result["success"]:
|
|
118
|
+
contents.append(f"\n来源 {i}:{result['href']}\n")
|
|
119
|
+
contents.append(webpage_result["stdout"])
|
|
120
|
+
except Exception as e:
|
|
121
|
+
PrettyOutput.print(f"读取结果 {i} 失败: {str(e)}", OutputType.WARNING)
|
|
122
|
+
continue
|
|
123
|
+
|
|
124
|
+
if not contents:
|
|
125
|
+
return {
|
|
126
|
+
"success": False,
|
|
127
|
+
"error": "未能获取任何有效的搜索结果"
|
|
128
|
+
}
|
|
36
129
|
|
|
130
|
+
# 提取信息
|
|
131
|
+
PrettyOutput.print("正在分析搜索结果...", OutputType.PROGRESS)
|
|
132
|
+
analysis = self._extract_info(contents, question)
|
|
37
133
|
|
|
38
134
|
return {
|
|
39
135
|
"success": True,
|
|
40
|
-
"stdout":
|
|
136
|
+
"stdout": f"搜索分析结果:\n\n{analysis}",
|
|
41
137
|
"stderr": ""
|
|
42
138
|
}
|
|
43
139
|
|
jarvis/tools/shell.py
CHANGED
|
@@ -7,26 +7,7 @@ from ..utils import PrettyOutput, OutputType
|
|
|
7
7
|
|
|
8
8
|
class ShellTool:
|
|
9
9
|
name = "execute_shell"
|
|
10
|
-
description = """
|
|
11
|
-
|
|
12
|
-
Guidelines:
|
|
13
|
-
1. Filter outputs
|
|
14
|
-
- Use grep/sed for specific data
|
|
15
|
-
- Use head/tail to limit lines
|
|
16
|
-
- Use -q for status checks
|
|
17
|
-
|
|
18
|
-
Examples:
|
|
19
|
-
✓ <START_TOOL_CALL>
|
|
20
|
-
name: execute_shell
|
|
21
|
-
arguments:
|
|
22
|
-
command: ls -l file.txt # specific file
|
|
23
|
-
<END_TOOL_CALL>
|
|
24
|
-
|
|
25
|
-
✗ <START_TOOL_CALL>
|
|
26
|
-
name: execute_shell
|
|
27
|
-
arguments:
|
|
28
|
-
command: ps aux # too much output
|
|
29
|
-
<END_TOOL_CALL>"""
|
|
10
|
+
description = """执行shell命令并返回结果"""
|
|
30
11
|
|
|
31
12
|
parameters = {
|
|
32
13
|
"type": "object",
|
jarvis/tools/sub_agent.py
CHANGED
|
@@ -6,78 +6,22 @@ from .base import ToolRegistry
|
|
|
6
6
|
|
|
7
7
|
class SubAgentTool:
|
|
8
8
|
name = "create_sub_agent"
|
|
9
|
-
description = """
|
|
10
|
-
|
|
11
|
-
IMPORTANT: Sub-agents start with NO context!
|
|
12
|
-
Must provide complete steps and context.
|
|
13
|
-
|
|
14
|
-
Required:
|
|
15
|
-
1. Context
|
|
16
|
-
- Project background
|
|
17
|
-
- File locations
|
|
18
|
-
- Current standards
|
|
19
|
-
- Requirements
|
|
20
|
-
|
|
21
|
-
2. Steps
|
|
22
|
-
- Clear actions
|
|
23
|
-
- Success criteria
|
|
24
|
-
- Expected output
|
|
25
|
-
|
|
26
|
-
Example (Good):
|
|
27
|
-
<START_TOOL_CALL>
|
|
28
|
-
name: create_sub_agent
|
|
29
|
-
arguments:
|
|
30
|
-
name: CodeAnalyzer
|
|
31
|
-
task: Analyze error handling
|
|
32
|
-
context: |
|
|
33
|
-
Project: Python 3.8+
|
|
34
|
-
File: src/utils.py
|
|
35
|
-
|
|
36
|
-
Steps:
|
|
37
|
-
1. Read file content
|
|
38
|
-
2. Find error patterns
|
|
39
|
-
3. Check consistency
|
|
40
|
-
4. Verify logging
|
|
41
|
-
|
|
42
|
-
Expected:
|
|
43
|
-
- Pattern list
|
|
44
|
-
- Issues found
|
|
45
|
-
- Suggestions
|
|
46
|
-
|
|
47
|
-
Standards:
|
|
48
|
-
- Dict[str, Any] returns
|
|
49
|
-
- PrettyOutput logging
|
|
50
|
-
<END_TOOL_CALL>
|
|
51
|
-
|
|
52
|
-
Example (Bad):
|
|
53
|
-
<START_TOOL_CALL>
|
|
54
|
-
name: create_sub_agent
|
|
55
|
-
arguments:
|
|
56
|
-
name: Analyzer
|
|
57
|
-
task: Check code
|
|
58
|
-
context: Look at utils.py
|
|
59
|
-
<END_TOOL_CALL>
|
|
60
|
-
|
|
61
|
-
Use for:
|
|
62
|
-
✓ Clear, independent tasks
|
|
63
|
-
✓ Well-defined goals
|
|
64
|
-
✗ Vague tasks
|
|
65
|
-
✗ Simple operations"""
|
|
9
|
+
description = """创建一个子代理来处理独立任务。(重要:子代理启动时没有任何上下文!必须提供完整的步骤和上下文。)"""
|
|
66
10
|
|
|
67
11
|
parameters = {
|
|
68
12
|
"type": "object",
|
|
69
13
|
"properties": {
|
|
70
14
|
"name": {
|
|
71
15
|
"type": "string",
|
|
72
|
-
"description": "
|
|
16
|
+
"description": "子代理名称(例如:'文件分析器')"
|
|
73
17
|
},
|
|
74
18
|
"task": {
|
|
75
19
|
"type": "string",
|
|
76
|
-
"description": "
|
|
20
|
+
"description": "需要明确步骤和目标的任务"
|
|
77
21
|
},
|
|
78
22
|
"context": {
|
|
79
23
|
"type": "string",
|
|
80
|
-
"description": "
|
|
24
|
+
"description": "必填:背景信息、执行步骤和预期结果",
|
|
81
25
|
"default": ""
|
|
82
26
|
}
|
|
83
27
|
},
|
|
@@ -98,44 +42,42 @@ Use for:
|
|
|
98
42
|
if not context:
|
|
99
43
|
return {
|
|
100
44
|
"success": False,
|
|
101
|
-
"error": "
|
|
45
|
+
"error": "必须提供上下文信息,包括完整的背景和执行步骤。"
|
|
102
46
|
}
|
|
103
47
|
|
|
104
|
-
PrettyOutput.print(f"
|
|
48
|
+
PrettyOutput.print(f"正在创建子代理 '{name}'...", OutputType.INFO)
|
|
105
49
|
|
|
106
50
|
# Create a new tool registry for the sub-agent
|
|
107
51
|
tool_registry = ToolRegistry(self.model)
|
|
108
52
|
|
|
109
53
|
# Create the sub-agent with the specified name
|
|
110
|
-
sub_agent = Agent(self.model, tool_registry, name=name)
|
|
54
|
+
sub_agent = Agent(self.model, tool_registry, name=name, is_sub_agent=True)
|
|
111
55
|
|
|
112
56
|
# Prepare the task with context
|
|
113
|
-
full_task = f"""
|
|
57
|
+
full_task = f"""背景和步骤:
|
|
114
58
|
{context}
|
|
115
59
|
|
|
116
|
-
|
|
60
|
+
主要任务:
|
|
117
61
|
{task}
|
|
118
62
|
|
|
119
|
-
|
|
120
|
-
1.
|
|
121
|
-
2.
|
|
122
|
-
3.
|
|
123
|
-
4.
|
|
63
|
+
要求:
|
|
64
|
+
1. 严格按照提供的步骤执行
|
|
65
|
+
2. 每完成一个步骤都要报告进度
|
|
66
|
+
3. 突出显示任何问题或不明确的点
|
|
67
|
+
4. 提供符合预期输出的详细结果"""
|
|
124
68
|
|
|
125
|
-
PrettyOutput.print(f"
|
|
69
|
+
PrettyOutput.print(f"子代理 '{name}' 正在执行任务...", OutputType.INFO)
|
|
126
70
|
|
|
127
|
-
|
|
128
71
|
# Execute the task and get the summary
|
|
129
72
|
summary = sub_agent.run(full_task)
|
|
130
73
|
return {
|
|
131
74
|
"success": True,
|
|
132
|
-
"stdout": f"
|
|
75
|
+
"stdout": f"子代理 '{name}' 已完成。\n\n结果:\n{summary}",
|
|
133
76
|
"stderr": ""
|
|
134
77
|
}
|
|
135
78
|
|
|
136
|
-
|
|
137
79
|
except Exception as e:
|
|
138
80
|
return {
|
|
139
81
|
"success": False,
|
|
140
|
-
"error": f"
|
|
82
|
+
"error": f"子代理执行失败:{str(e)}"
|
|
141
83
|
}
|
jarvis/tools/webpage.py
CHANGED
|
@@ -5,19 +5,13 @@ from ..utils import PrettyOutput, OutputType
|
|
|
5
5
|
|
|
6
6
|
class WebpageTool:
|
|
7
7
|
name = "read_webpage"
|
|
8
|
-
description = "
|
|
8
|
+
description = "读取网页内容,提取标题和正文文本"
|
|
9
9
|
parameters = {
|
|
10
10
|
"type": "object",
|
|
11
11
|
"properties": {
|
|
12
12
|
"url": {
|
|
13
13
|
"type": "string",
|
|
14
|
-
"description": "URL
|
|
15
|
-
},
|
|
16
|
-
"extract_type": {
|
|
17
|
-
"type": "string",
|
|
18
|
-
"description": "Type of content to extract: 'text', 'title', or 'all'",
|
|
19
|
-
"enum": ["text", "title", "all"],
|
|
20
|
-
"default": "all"
|
|
14
|
+
"description": "需要读取的网页URL"
|
|
21
15
|
}
|
|
22
16
|
},
|
|
23
17
|
"required": ["url"]
|
|
@@ -27,7 +21,6 @@ class WebpageTool:
|
|
|
27
21
|
"""读取网页内容"""
|
|
28
22
|
try:
|
|
29
23
|
url = args["url"]
|
|
30
|
-
extract_type = args.get("extract_type", "all")
|
|
31
24
|
|
|
32
25
|
# 设置请求头
|
|
33
26
|
headers = {
|
|
@@ -49,28 +42,21 @@ class WebpageTool:
|
|
|
49
42
|
for script in soup(["script", "style"]):
|
|
50
43
|
script.decompose()
|
|
51
44
|
|
|
52
|
-
result = {}
|
|
53
|
-
|
|
54
45
|
# 提取标题
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
result["title"] = title.strip() if title else "无标题"
|
|
46
|
+
title = soup.title.string if soup.title else ""
|
|
47
|
+
title = title.strip() if title else "无标题"
|
|
58
48
|
|
|
59
49
|
# 提取正文
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
lines = [line.strip() for line in text.splitlines() if line.strip()]
|
|
63
|
-
result["text"] = "\n".join(lines)
|
|
50
|
+
text = soup.get_text(separator='\n', strip=True)
|
|
51
|
+
lines = [line.strip() for line in text.splitlines() if line.strip()]
|
|
64
52
|
|
|
65
53
|
# 构建输出
|
|
66
|
-
output = [
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
output.append("正文内容:")
|
|
73
|
-
output.append(result["text"])
|
|
54
|
+
output = [
|
|
55
|
+
f"标题: {title}",
|
|
56
|
+
"",
|
|
57
|
+
"正文内容:",
|
|
58
|
+
"\n".join(lines)
|
|
59
|
+
]
|
|
74
60
|
|
|
75
61
|
return {
|
|
76
62
|
"success": True,
|
jarvis/zte_llm.py
CHANGED
|
@@ -37,20 +37,34 @@ class ZteLLM(BaseModel):
|
|
|
37
37
|
response = requests.post(
|
|
38
38
|
f"{self.base_url}/{endpoint}",
|
|
39
39
|
headers=headers,
|
|
40
|
-
json=data
|
|
40
|
+
json=data,
|
|
41
|
+
stream=True # 启用流式传输
|
|
41
42
|
)
|
|
42
43
|
|
|
43
44
|
response.raise_for_status()
|
|
44
|
-
result = response.json()
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
46
|
+
full_content = []
|
|
47
|
+
for line in response.iter_lines():
|
|
48
|
+
if line:
|
|
49
|
+
# 解析 SSE 数据
|
|
50
|
+
line = line.decode('utf-8')
|
|
51
|
+
if line.startswith('data: '):
|
|
52
|
+
try:
|
|
53
|
+
data = json.loads(line[6:]) # 跳过 "data: " 前缀
|
|
54
|
+
if "result" in data:
|
|
55
|
+
result = data["result"]
|
|
56
|
+
if result: # 只处理非空结果
|
|
57
|
+
full_content.append(result)
|
|
58
|
+
PrettyOutput.print_stream(result, OutputType.SYSTEM)
|
|
59
|
+
if data.get("finishReason") == "stop":
|
|
60
|
+
break
|
|
61
|
+
except json.JSONDecodeError:
|
|
62
|
+
continue
|
|
63
|
+
PrettyOutput.print_stream_end()
|
|
64
|
+
|
|
65
|
+
return "".join(full_content)
|
|
52
66
|
|
|
53
|
-
def chat(self, messages: List[Dict[str, Any]]
|
|
67
|
+
def chat(self, messages: List[Dict[str, Any]]) -> str:
|
|
54
68
|
"""Chat with ZTE LLM"""
|
|
55
69
|
# Convert messages to prompt
|
|
56
70
|
prompt = self._convert_messages_to_prompt(messages)
|
|
@@ -59,30 +73,15 @@ class ZteLLM(BaseModel):
|
|
|
59
73
|
data = {
|
|
60
74
|
"chatUuid": "",
|
|
61
75
|
"chatName": "",
|
|
62
|
-
"stream":
|
|
76
|
+
"stream": True, # 启用流式响应
|
|
63
77
|
"keep": False,
|
|
64
78
|
"text": prompt,
|
|
65
79
|
"model": self.model
|
|
66
80
|
}
|
|
67
81
|
|
|
68
|
-
# If tools are provided, add them to the prompt
|
|
69
|
-
if tools:
|
|
70
|
-
tools_desc = "Available tools:\n\n" + json.dumps(tools, indent=2, ensure_ascii=False)
|
|
71
|
-
data["text"] = tools_desc + "\n\n" + data["text"]
|
|
72
|
-
|
|
73
82
|
try:
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
# Parse the response to extract potential tool calls
|
|
77
|
-
response_text = result["result"]
|
|
78
|
-
tool_calls = BaseModel.extract_tool_calls(response_text)
|
|
79
|
-
|
|
80
|
-
return {
|
|
81
|
-
"message": {
|
|
82
|
-
"content": response_text,
|
|
83
|
-
"tool_calls": tool_calls
|
|
84
|
-
}
|
|
85
|
-
}
|
|
83
|
+
return self._make_request("chat", data)
|
|
84
|
+
|
|
86
85
|
|
|
87
86
|
except Exception as e:
|
|
88
87
|
raise Exception(f"ZTE LLM chat failed: {str(e)}")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: jarvis-ai-assistant
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.8
|
|
4
4
|
Summary: Jarvis: An AI assistant that uses tools to interact with the system
|
|
5
5
|
Home-page: https://github.com/skyfireitdiy/Jarvis
|
|
6
6
|
Author: skyfire
|
|
@@ -22,6 +22,7 @@ Requires-Dist: duckduckgo-search>=3.0.0
|
|
|
22
22
|
Requires-Dist: pyyaml>=5.1
|
|
23
23
|
Requires-Dist: ollama>=0.1.6
|
|
24
24
|
Requires-Dist: colorama>=0.4.6
|
|
25
|
+
Requires-Dist: openai>=1.2.0
|
|
25
26
|
Provides-Extra: dev
|
|
26
27
|
Requires-Dist: pytest; extra == "dev"
|
|
27
28
|
Requires-Dist: black; extra == "dev"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
jarvis/__init__.py,sha256=QIcBZBFMcOFbIudbA0VykyqY4RphA3fWQlRP_kUMcPM,49
|
|
2
|
+
jarvis/agent.py,sha256=ePgdOCWdkw35KITvZOqcrJOGl-F4wzvrltHTw7N4p88,11014
|
|
3
|
+
jarvis/main.py,sha256=4IqebMKGoBGJMSNFE6E6GQ_Ay-uuOT-BLsQPnQVW47k,6705
|
|
4
|
+
jarvis/models.py,sha256=G9QkUqoyOyUx6eSqwbn3hCSwHguN0bUm7Nbd6Ql0IQs,3771
|
|
5
|
+
jarvis/utils.py,sha256=3hLtv-HcBL8Ngw69cowhARuIFrjcQ6yRP3Y1o9CvtsI,5992
|
|
6
|
+
jarvis/zte_llm.py,sha256=Us5D6zMdZT6SoSnUgKWQbxthGadXkulLs_oSmW5MPDo,4666
|
|
7
|
+
jarvis/__pycache__/__init__.cpython-313.pyc,sha256=lGXFfeYKcGsFZjgHY8y4zLca1xBIkr2zKSQv06rhoBY,208
|
|
8
|
+
jarvis/__pycache__/agent.cpython-313.pyc,sha256=itbFLk6qJ9FTjbiyj6DsQhu5NbdxVaP4g-SygRguvSc,11625
|
|
9
|
+
jarvis/__pycache__/main.cpython-313.pyc,sha256=6hWRW-RG_bZrqwhSQXyhKaJBXexgLqKa-_SZzAk6_eo,8479
|
|
10
|
+
jarvis/__pycache__/models.cpython-313.pyc,sha256=uWuRIjGrY4YDB3dGW5PGDLWaS03et8g11O725TjY_eU,5960
|
|
11
|
+
jarvis/__pycache__/tools.cpython-313.pyc,sha256=lAD4LrnnWzNZQmHXGfZ_2l7oskOpr2_2OC-gdFhxQY8,33933
|
|
12
|
+
jarvis/__pycache__/utils.cpython-313.pyc,sha256=k4jyAlx4tlW0MKLMLzV7OOH9zsKrK0H955kY6M2SuFU,8772
|
|
13
|
+
jarvis/__pycache__/zte_llm.cpython-313.pyc,sha256=R_HT_Gc6OQelxRLRQ-yB8Tf0sYHcb18dh9E4RF6ivbE,5662
|
|
14
|
+
jarvis/tools/__init__.py,sha256=tH6YaApKpqs1YSjEllRzOZZUd-OTFKSZ5oA0zs7HdSE,297
|
|
15
|
+
jarvis/tools/base.py,sha256=zK-JteBwj9d2BD_7BSAp-zD7wgJbVBppAWyfFxaPObI,4114
|
|
16
|
+
jarvis/tools/file_ops.py,sha256=zTksx45NZm3iz9itN5iQGZ8DoxnSeTHdrnF08_ix7PU,3770
|
|
17
|
+
jarvis/tools/search.py,sha256=HJQ1_-CXB9M4wiq4wbLYdI-Vz92JiA6LGnog3b1dDd4,5293
|
|
18
|
+
jarvis/tools/shell.py,sha256=7q52lA3slf0TdjBjP1bkwugoO5pB0eqh6cYjAzAXNtI,2547
|
|
19
|
+
jarvis/tools/sub_agent.py,sha256=QJYWdil1goZfo95CQkuhkjZBl-Rx6UvyeFMiGnDyjOA,2832
|
|
20
|
+
jarvis/tools/webpage.py,sha256=DBnh9gye6oL2nVjzU2SU4Jupsck8x9g9On-rbjV6d8Y,2386
|
|
21
|
+
jarvis/tools/__pycache__/__init__.cpython-313.pyc,sha256=1d1eUI0FlaydGB8TFBln6s7cBKd6gcPdER2_DIfX2Aw,443
|
|
22
|
+
jarvis/tools/__pycache__/base.cpython-313.pyc,sha256=2OJWYNsGJjKJs6Vdj9NcN_Snjd2bA_OLlB-zr2j4wfs,6462
|
|
23
|
+
jarvis/tools/__pycache__/bing_search.cpython-313.pyc,sha256=t4OZJrEgP35xdidDjVypxsDN07JAlh5PcpTkauFyllA,7029
|
|
24
|
+
jarvis/tools/__pycache__/file_ops.cpython-313.pyc,sha256=LbOp31JUzoRp5XVazy1VBqCQhpFg0qQYmVftFVY90V4,3628
|
|
25
|
+
jarvis/tools/__pycache__/python_script.cpython-313.pyc,sha256=8JpryqTovEiTvBlWAK1KjZmPvHUuPc9GT9rTXBEQoJc,6693
|
|
26
|
+
jarvis/tools/__pycache__/rag.cpython-313.pyc,sha256=JH6-PSZRMKAvTZqCwlRXJGClxYXNMs-vetU0q7hBLz0,6064
|
|
27
|
+
jarvis/tools/__pycache__/search.cpython-313.pyc,sha256=7lS5jDmClpHJXKnbBaUCys8CmW1YBJtZAa4c64JGO6I,6624
|
|
28
|
+
jarvis/tools/__pycache__/shell.cpython-313.pyc,sha256=QMaLUc1MtZXWod3msv_x7iMq2IybwMwz1OoaKsbm6U4,3271
|
|
29
|
+
jarvis/tools/__pycache__/sub_agent.cpython-313.pyc,sha256=qzNLnQxqFZoAiYOPH4GrCGxaQVs-QWfTLspW5a1Xa6c,3144
|
|
30
|
+
jarvis/tools/__pycache__/user_confirmation.cpython-313.pyc,sha256=wK3Ev10lHSUSRvoYmi7A0GzxYkzU-C4Wfhs5qW_HBqs,2271
|
|
31
|
+
jarvis/tools/__pycache__/user_input.cpython-313.pyc,sha256=JjTFOhObKsKF4Pn8KBRuKfV1_Ssj083fjU7Mfc_5z7c,2531
|
|
32
|
+
jarvis/tools/__pycache__/user_interaction.cpython-313.pyc,sha256=RuVZ-pmiPBDywY3efgXSfohMAciC1avMGPmBK5qlnew,3305
|
|
33
|
+
jarvis/tools/__pycache__/webpage.cpython-313.pyc,sha256=BjzSfnNzsKCrLETCcWjt32lNDLzwnjqcVGg4JfWd9OM,3008
|
|
34
|
+
jarvis_ai_assistant-0.1.8.dist-info/METADATA,sha256=3zrOu0XJCW5EO4UbCeRIK0xNw6JcW60tFr6b6VdWET4,3719
|
|
35
|
+
jarvis_ai_assistant-0.1.8.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
36
|
+
jarvis_ai_assistant-0.1.8.dist-info/entry_points.txt,sha256=iKu7OMfew9dtfGhW71gIMTg4wvafuPqKb4wyQOnMAGU,44
|
|
37
|
+
jarvis_ai_assistant-0.1.8.dist-info/top_level.txt,sha256=1BOxyWfzOP_ZXj8rVTDnNCJ92bBGB0rwq8N1PCpoMIs,7
|
|
38
|
+
jarvis_ai_assistant-0.1.8.dist-info/RECORD,,
|