jarvis-ai-assistant 0.1.10__py3-none-any.whl → 0.1.11__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.
- 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/agent.py +33 -86
- jarvis/main.py +6 -2
- jarvis/models/__pycache__/base.cpython-313.pyc +0 -0
- jarvis/models/__pycache__/kimi.cpython-313.pyc +0 -0
- jarvis/models/base.py +5 -1
- jarvis/models/kimi.py +179 -56
- {jarvis_ai_assistant-0.1.10.dist-info → jarvis_ai_assistant-0.1.11.dist-info}/METADATA +1 -1
- {jarvis_ai_assistant-0.1.10.dist-info → jarvis_ai_assistant-0.1.11.dist-info}/RECORD +15 -15
- {jarvis_ai_assistant-0.1.10.dist-info → jarvis_ai_assistant-0.1.11.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.10.dist-info → jarvis_ai_assistant-0.1.11.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.10.dist-info → jarvis_ai_assistant-0.1.11.dist-info}/top_level.txt +0 -0
jarvis/__init__.py
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
jarvis/agent.py
CHANGED
|
@@ -11,7 +11,7 @@ import os
|
|
|
11
11
|
from datetime import datetime
|
|
12
12
|
|
|
13
13
|
class Agent:
|
|
14
|
-
def __init__(self, model: BaseModel, tool_registry: ToolRegistry, name: str = "Jarvis"
|
|
14
|
+
def __init__(self, model: BaseModel, tool_registry: ToolRegistry, name: str = "Jarvis"):
|
|
15
15
|
"""Initialize Agent with a model, optional tool registry and name
|
|
16
16
|
|
|
17
17
|
Args:
|
|
@@ -23,8 +23,7 @@ class Agent:
|
|
|
23
23
|
self.model = model
|
|
24
24
|
self.tool_registry = tool_registry or ToolRegistry(model)
|
|
25
25
|
self.name = name
|
|
26
|
-
self.
|
|
27
|
-
self.messages = []
|
|
26
|
+
self.prompt = ""
|
|
28
27
|
|
|
29
28
|
|
|
30
29
|
@staticmethod
|
|
@@ -71,19 +70,28 @@ class Agent:
|
|
|
71
70
|
|
|
72
71
|
return []
|
|
73
72
|
|
|
74
|
-
def _call_model(self,
|
|
73
|
+
def _call_model(self, message: str) -> str:
|
|
75
74
|
"""调用模型获取响应"""
|
|
76
75
|
try:
|
|
77
|
-
return self.model.chat(
|
|
78
|
-
messages=messages,
|
|
79
|
-
)
|
|
76
|
+
return self.model.chat(message)
|
|
80
77
|
except Exception as e:
|
|
81
78
|
raise Exception(f"{self.name}: 模型调用失败: {str(e)}")
|
|
82
79
|
|
|
83
|
-
def run(self, user_input: str
|
|
84
|
-
"""处理用户输入并返回响应,返回任务总结报告
|
|
80
|
+
def run(self, user_input: str, file_list: Optional[List[str]] = None):
|
|
81
|
+
"""处理用户输入并返回响应,返回任务总结报告
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
user_input: 用户输入的任务描述
|
|
85
|
+
file_list: 可选的文件列表,默认为None
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
str: 任务总结报告
|
|
89
|
+
"""
|
|
85
90
|
self.clear_history()
|
|
86
91
|
|
|
92
|
+
if file_list:
|
|
93
|
+
self.model.upload_files(file_list)
|
|
94
|
+
|
|
87
95
|
# 显示任务开始
|
|
88
96
|
PrettyOutput.section(f"开始新任务: {self.name}", OutputType.PLANNING)
|
|
89
97
|
|
|
@@ -93,20 +101,10 @@ class Agent:
|
|
|
93
101
|
tools_prompt += f" 描述: {tool['description']}\n"
|
|
94
102
|
tools_prompt += f" 参数: {tool['parameters']}\n"
|
|
95
103
|
|
|
96
|
-
self.
|
|
97
|
-
{
|
|
98
|
-
"role": "user",
|
|
99
|
-
"content": f"""你是 {self.name},一个严格遵循 ReAct 框架进行逐步推理和行动的 AI 助手。
|
|
104
|
+
self.prompt =f"""你是 {self.name},一个严格遵循 ReAct 框架进行逐步推理和行动的 AI 助手。
|
|
100
105
|
|
|
101
106
|
{tools_prompt}
|
|
102
107
|
|
|
103
|
-
关键规则:
|
|
104
|
-
‼️ 禁止创建虚假对话
|
|
105
|
-
‼️ 禁止假设用户回应
|
|
106
|
-
‼️ 禁止在没有实际用户输入时继续
|
|
107
|
-
‼️ 只回应用户实际说的内容
|
|
108
|
-
‼️ 每个动作后停止并等待
|
|
109
|
-
|
|
110
108
|
ReAct 框架:
|
|
111
109
|
1. 思考
|
|
112
110
|
- 分析当前情况
|
|
@@ -123,7 +121,7 @@ ReAct 框架:
|
|
|
123
121
|
- 只使用下面列出的工具
|
|
124
122
|
- 每次只执行一个工具
|
|
125
123
|
- 工具由用户手动执行
|
|
126
|
-
-
|
|
124
|
+
- 必须使用有效合法的YAML格式:
|
|
127
125
|
<START_TOOL_CALL>
|
|
128
126
|
name: tool_name
|
|
129
127
|
arguments:
|
|
@@ -164,7 +162,6 @@ arguments:
|
|
|
164
162
|
‼️ 工具调用必须是有效的YAML格式
|
|
165
163
|
‼️ 参数必须正确缩进
|
|
166
164
|
‼️ 使用YAML块样式(|)表示多行值
|
|
167
|
-
‼️ <END_TOOL_CALL>后的内容将被丢弃
|
|
168
165
|
‼️ 工具由用户手动执行
|
|
169
166
|
‼️ 等待用户提供工具执行结果
|
|
170
167
|
‼️ 不要假设或想象用户回应
|
|
@@ -190,32 +187,21 @@ arguments:
|
|
|
190
187
|
任务:
|
|
191
188
|
{user_input}
|
|
192
189
|
"""
|
|
193
|
-
|
|
194
|
-
]
|
|
190
|
+
|
|
195
191
|
|
|
196
192
|
while True:
|
|
197
193
|
try:
|
|
198
194
|
# 显示思考状态
|
|
199
195
|
PrettyOutput.print("分析任务...", OutputType.PROGRESS)
|
|
200
196
|
|
|
201
|
-
current_response = self._call_model(self.
|
|
197
|
+
current_response = self._call_model(self.prompt)
|
|
202
198
|
|
|
203
199
|
try:
|
|
204
200
|
result = Agent.extract_tool_calls(current_response)
|
|
205
201
|
except Exception as e:
|
|
206
202
|
PrettyOutput.print(f"工具调用错误: {str(e)}", OutputType.ERROR)
|
|
207
|
-
self.
|
|
208
|
-
"role": "user",
|
|
209
|
-
"content": f"工具调用错误: {str(e)}"
|
|
210
|
-
})
|
|
203
|
+
self.prompt = f"工具调用错误: {str(e)}"
|
|
211
204
|
continue
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
self.messages.append({
|
|
215
|
-
"role": "assistant",
|
|
216
|
-
"content": current_response
|
|
217
|
-
})
|
|
218
|
-
|
|
219
205
|
|
|
220
206
|
if len(result) > 0:
|
|
221
207
|
try:
|
|
@@ -227,68 +213,29 @@ arguments:
|
|
|
227
213
|
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
228
214
|
tool_result = f"Tool call failed: {str(e)}"
|
|
229
215
|
|
|
230
|
-
self.
|
|
231
|
-
"role": "user",
|
|
232
|
-
"content": tool_result
|
|
233
|
-
})
|
|
216
|
+
self.prompt = tool_result
|
|
234
217
|
continue
|
|
235
218
|
|
|
236
219
|
# 获取用户输入
|
|
237
220
|
user_input = get_multiline_input(f"{self.name}: 您可以继续输入,或输入空行结束当前任务")
|
|
238
|
-
if not user_input:
|
|
239
|
-
# 只有子Agent才需要生成任务总结
|
|
240
|
-
if self.is_sub_agent:
|
|
241
|
-
PrettyOutput.print("生成任务总结...", OutputType.PROGRESS)
|
|
242
|
-
|
|
243
|
-
# 生成任务总结
|
|
244
|
-
summary_prompt = {
|
|
245
|
-
"role": "user",
|
|
246
|
-
"content": """任务已完成。请根据之前的分析和执行结果,提供一个简明的任务总结,包括:
|
|
247
|
-
|
|
248
|
-
1. 关键发现:
|
|
249
|
-
- 分析过程中的重要发现
|
|
250
|
-
- 工具执行的关键结果
|
|
251
|
-
- 发现的重要数据
|
|
252
|
-
|
|
253
|
-
2. 执行成果:
|
|
254
|
-
- 任务完成情况
|
|
255
|
-
- 具体实现结果
|
|
256
|
-
- 达成的目标
|
|
257
|
-
|
|
258
|
-
请直接描述事实和实际结果,保持简洁明了。"""
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
while True:
|
|
262
|
-
try:
|
|
263
|
-
summary = self._call_model(self.messages + [summary_prompt])
|
|
264
|
-
|
|
265
|
-
# 显示任务总结
|
|
266
|
-
PrettyOutput.section("任务总结", OutputType.SUCCESS)
|
|
267
|
-
PrettyOutput.print(summary, OutputType.SYSTEM)
|
|
268
|
-
PrettyOutput.section("任务完成", OutputType.SUCCESS)
|
|
269
|
-
|
|
270
|
-
return summary
|
|
271
|
-
|
|
272
|
-
except Exception as e:
|
|
273
|
-
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
274
|
-
else:
|
|
275
|
-
# 顶层Agent直接返回空字符串
|
|
276
|
-
PrettyOutput.section("任务完成", OutputType.SUCCESS)
|
|
277
|
-
return ""
|
|
278
|
-
|
|
279
221
|
if user_input == "__interrupt__":
|
|
280
222
|
PrettyOutput.print("任务已取消", OutputType.WARNING)
|
|
281
223
|
return "Task cancelled by user"
|
|
224
|
+
if user_input:
|
|
225
|
+
self.prompt = user_input
|
|
226
|
+
continue
|
|
227
|
+
|
|
228
|
+
if not user_input:
|
|
229
|
+
PrettyOutput.section("任务完成", OutputType.SUCCESS)
|
|
230
|
+
return
|
|
231
|
+
|
|
232
|
+
|
|
282
233
|
|
|
283
|
-
self.messages.append({
|
|
284
|
-
"role": "user",
|
|
285
|
-
"content": user_input
|
|
286
|
-
})
|
|
287
234
|
|
|
288
235
|
except Exception as e:
|
|
289
236
|
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
290
237
|
|
|
291
238
|
def clear_history(self):
|
|
292
239
|
"""清除对话历史,只保留系统提示"""
|
|
293
|
-
self.
|
|
240
|
+
self.prompt = ""
|
|
294
241
|
self.model.reset()
|
jarvis/main.py
CHANGED
|
@@ -72,6 +72,10 @@ def select_task(tasks: dict) -> str:
|
|
|
72
72
|
|
|
73
73
|
def main():
|
|
74
74
|
"""Main entry point for Jarvis."""
|
|
75
|
+
# Add argument parser
|
|
76
|
+
parser = argparse.ArgumentParser(description='Jarvis AI Assistant')
|
|
77
|
+
parser.add_argument('-f', '--files', nargs='*', help='List of files to process')
|
|
78
|
+
args = parser.parse_args()
|
|
75
79
|
|
|
76
80
|
load_env_from_file()
|
|
77
81
|
|
|
@@ -95,7 +99,7 @@ def main():
|
|
|
95
99
|
selected_task = select_task(tasks)
|
|
96
100
|
if selected_task:
|
|
97
101
|
PrettyOutput.print(f"\n执行任务: {selected_task}", OutputType.INFO)
|
|
98
|
-
agent.run(selected_task)
|
|
102
|
+
agent.run(selected_task, args.files)
|
|
99
103
|
return 0
|
|
100
104
|
|
|
101
105
|
# 如果没有选择预定义任务,进入交互模式
|
|
@@ -104,7 +108,7 @@ def main():
|
|
|
104
108
|
user_input = get_multiline_input("请输入您的任务(输入空行退出):")
|
|
105
109
|
if not user_input or user_input == "__interrupt__":
|
|
106
110
|
break
|
|
107
|
-
agent.run(user_input)
|
|
111
|
+
agent.run(user_input, args.files)
|
|
108
112
|
except Exception as e:
|
|
109
113
|
PrettyOutput.print(f"错误: {str(e)}", OutputType.ERROR)
|
|
110
114
|
|
|
Binary file
|
|
Binary file
|
jarvis/models/base.py
CHANGED
|
@@ -5,10 +5,14 @@ class BaseModel(ABC):
|
|
|
5
5
|
"""大语言模型基类"""
|
|
6
6
|
|
|
7
7
|
@abstractmethod
|
|
8
|
-
def chat(self,
|
|
8
|
+
def chat(self, message: str) -> str:
|
|
9
9
|
"""执行对话"""
|
|
10
10
|
pass
|
|
11
11
|
|
|
12
|
+
def upload_files(self, file_list: List[str]) -> List[Dict]:
|
|
13
|
+
"""上传文件"""
|
|
14
|
+
pass
|
|
15
|
+
|
|
12
16
|
def reset(self):
|
|
13
17
|
"""重置模型"""
|
|
14
18
|
pass
|
jarvis/models/kimi.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
from typing import Dict, List
|
|
1
|
+
from typing import Dict, List, Optional
|
|
2
2
|
import requests
|
|
3
3
|
import json
|
|
4
4
|
import os
|
|
5
|
+
import mimetypes
|
|
5
6
|
from .base import BaseModel
|
|
6
7
|
from ..utils import PrettyOutput, OutputType
|
|
7
8
|
import time
|
|
@@ -20,6 +21,8 @@ class KimiModel(BaseModel):
|
|
|
20
21
|
raise Exception("KIMI_API_KEY is not set")
|
|
21
22
|
self.auth_header = f"Bearer {self.api_key}"
|
|
22
23
|
self.chat_id = ""
|
|
24
|
+
self.uploaded_files = [] # 存储已上传文件的信息
|
|
25
|
+
self.first_chat = True # 添加标记,用于判断是否是第一次对话
|
|
23
26
|
|
|
24
27
|
def _create_chat(self) -> bool:
|
|
25
28
|
"""创建新的对话会话"""
|
|
@@ -41,93 +44,213 @@ class KimiModel(BaseModel):
|
|
|
41
44
|
PrettyOutput.print(f"Failed to create chat: {e}", OutputType.ERROR)
|
|
42
45
|
return False
|
|
43
46
|
|
|
44
|
-
def
|
|
45
|
-
"""
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
def _get_presigned_url(self, filename: str) -> Dict:
|
|
48
|
+
"""获取预签名上传URL"""
|
|
49
|
+
url = "https://kimi.moonshot.cn/api/pre-sign-url"
|
|
50
|
+
mime_type, _ = mimetypes.guess_type(filename)
|
|
51
|
+
action = "image" if mime_type and mime_type.startswith('image/') else "file"
|
|
52
|
+
|
|
53
|
+
payload = json.dumps({
|
|
54
|
+
"action": action,
|
|
55
|
+
"name": os.path.basename(filename)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
headers = {
|
|
59
|
+
'Authorization': self.auth_header,
|
|
60
|
+
'Content-Type': 'application/json'
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
response = requests.post(url, headers=headers, data=payload)
|
|
64
|
+
return response.json()
|
|
65
|
+
|
|
66
|
+
def _upload_file(self, file_path: str, presigned_url: str) -> bool:
|
|
67
|
+
"""上传文件到预签名URL"""
|
|
68
|
+
try:
|
|
69
|
+
with open(file_path, 'rb') as f:
|
|
70
|
+
content = f.read()
|
|
71
|
+
response = requests.put(presigned_url, data=content)
|
|
72
|
+
return response.status_code == 200
|
|
73
|
+
except Exception as e:
|
|
74
|
+
PrettyOutput.print(f"Failed to upload file: {e}", OutputType.ERROR)
|
|
75
|
+
return False
|
|
76
|
+
|
|
77
|
+
def _get_file_info(self, file_data: Dict, name: str) -> Dict:
|
|
78
|
+
"""获取文件信息"""
|
|
79
|
+
url = "https://kimi.moonshot.cn/api/file"
|
|
80
|
+
payload = json.dumps({
|
|
81
|
+
"type": "file",
|
|
82
|
+
"name": name,
|
|
83
|
+
"object_name": file_data["object_name"],
|
|
84
|
+
"chat_id": self.chat_id,
|
|
85
|
+
"file_id": file_data.get("file_id", "")
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
headers = {
|
|
89
|
+
'Authorization': self.auth_header,
|
|
90
|
+
'Content-Type': 'application/json'
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
response = requests.post(url, headers=headers, data=payload)
|
|
94
|
+
return response.json()
|
|
95
|
+
|
|
96
|
+
def _wait_for_parse(self, file_id: str) -> bool:
|
|
97
|
+
"""等待文件解析完成"""
|
|
98
|
+
url = "https://kimi.moonshot.cn/api/file/parse_process"
|
|
99
|
+
headers = {
|
|
100
|
+
'Authorization': self.auth_header,
|
|
101
|
+
'Content-Type': 'application/json'
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
max_retries = 30
|
|
105
|
+
retry_count = 0
|
|
106
|
+
|
|
107
|
+
while retry_count < max_retries:
|
|
108
|
+
payload = json.dumps({"ids": [file_id]})
|
|
109
|
+
response = requests.post(url, headers=headers, data=payload, stream=True)
|
|
110
|
+
|
|
111
|
+
for line in response.iter_lines():
|
|
112
|
+
if not line:
|
|
113
|
+
continue
|
|
114
|
+
|
|
115
|
+
line = line.decode('utf-8')
|
|
116
|
+
if not line.startswith("data: "):
|
|
117
|
+
continue
|
|
118
|
+
|
|
119
|
+
try:
|
|
120
|
+
data = json.loads(line[6:])
|
|
121
|
+
if data.get("event") == "resp":
|
|
122
|
+
status = data.get("file_info", {}).get("status")
|
|
123
|
+
if status == "parsed":
|
|
124
|
+
return True
|
|
125
|
+
elif status == "failed":
|
|
126
|
+
return False
|
|
127
|
+
except json.JSONDecodeError:
|
|
128
|
+
continue
|
|
129
|
+
|
|
130
|
+
retry_count += 1
|
|
131
|
+
time.sleep(1)
|
|
132
|
+
|
|
133
|
+
return False
|
|
134
|
+
|
|
135
|
+
def upload_files(self, file_list: List[str]) -> List[Dict]:
|
|
136
|
+
"""上传文件列表并返回文件信息"""
|
|
137
|
+
if not file_list:
|
|
138
|
+
return []
|
|
139
|
+
|
|
140
|
+
PrettyOutput.print("开始处理文件上传...", OutputType.PROGRESS)
|
|
141
|
+
|
|
52
142
|
if not self.chat_id:
|
|
143
|
+
PrettyOutput.print("创建新的对话会话...", OutputType.PROGRESS)
|
|
53
144
|
if not self._create_chat():
|
|
54
|
-
raise Exception("Failed to create chat")
|
|
145
|
+
raise Exception("Failed to create chat session")
|
|
146
|
+
|
|
147
|
+
uploaded_files = []
|
|
148
|
+
for index, file_path in enumerate(file_list, 1):
|
|
149
|
+
try:
|
|
150
|
+
PrettyOutput.print(f"处理文件 [{index}/{len(file_list)}]: {file_path}", OutputType.PROGRESS)
|
|
151
|
+
|
|
152
|
+
# 获取预签名URL
|
|
153
|
+
PrettyOutput.print("获取上传URL...", OutputType.PROGRESS)
|
|
154
|
+
presigned_data = self._get_presigned_url(file_path)
|
|
155
|
+
|
|
156
|
+
# 上传文件
|
|
157
|
+
PrettyOutput.print("上传文件内容...", OutputType.PROGRESS)
|
|
158
|
+
if self._upload_file(file_path, presigned_data["url"]):
|
|
159
|
+
# 获取文件信息
|
|
160
|
+
PrettyOutput.print("获取文件信息...", OutputType.PROGRESS)
|
|
161
|
+
file_info = self._get_file_info(presigned_data, os.path.basename(file_path))
|
|
162
|
+
|
|
163
|
+
# 等待文件解析
|
|
164
|
+
PrettyOutput.print("等待文件解析完成...", OutputType.PROGRESS)
|
|
165
|
+
if self._wait_for_parse(file_info["id"]):
|
|
166
|
+
uploaded_files.append(file_info)
|
|
167
|
+
PrettyOutput.print(f"✓ 文件处理成功: {file_path}", OutputType.SUCCESS)
|
|
168
|
+
else:
|
|
169
|
+
PrettyOutput.print(f"✗ 文件解析失败: {file_path}", OutputType.ERROR)
|
|
170
|
+
else:
|
|
171
|
+
PrettyOutput.print(f"✗ 文件上传失败: {file_path}", OutputType.ERROR)
|
|
172
|
+
|
|
173
|
+
except Exception as e:
|
|
174
|
+
PrettyOutput.print(f"✗ 处理文件出错 {file_path}: {str(e)}", OutputType.ERROR)
|
|
175
|
+
continue
|
|
176
|
+
|
|
177
|
+
if uploaded_files:
|
|
178
|
+
PrettyOutput.print(f"成功处理 {len(uploaded_files)}/{len(file_list)} 个文件", OutputType.SUCCESS)
|
|
179
|
+
else:
|
|
180
|
+
PrettyOutput.print("没有文件成功处理", OutputType.WARNING)
|
|
55
181
|
|
|
182
|
+
self.uploaded_files = uploaded_files
|
|
183
|
+
return uploaded_files
|
|
184
|
+
|
|
185
|
+
def chat(self, message: str) -> str:
|
|
186
|
+
"""发送消息并获取响应"""
|
|
187
|
+
if not self.chat_id:
|
|
188
|
+
PrettyOutput.print("创建新的对话会话...", OutputType.PROGRESS)
|
|
189
|
+
if not self._create_chat():
|
|
190
|
+
raise Exception("Failed to create chat session")
|
|
191
|
+
|
|
56
192
|
url = f"https://kimi.moonshot.cn/api/chat/{self.chat_id}/completion/stream"
|
|
57
|
-
|
|
58
|
-
|
|
193
|
+
|
|
194
|
+
# 只在第一次对话时带上文件引用
|
|
195
|
+
refs = []
|
|
196
|
+
refs_file = []
|
|
197
|
+
if self.first_chat and self.uploaded_files:
|
|
198
|
+
PrettyOutput.print(f"首次对话,引用 {len(self.uploaded_files)} 个文件...", OutputType.PROGRESS)
|
|
199
|
+
refs = [f["id"] for f in self.uploaded_files]
|
|
200
|
+
refs_file = self.uploaded_files
|
|
201
|
+
self.first_chat = False
|
|
202
|
+
|
|
203
|
+
PrettyOutput.print("发送请求...", OutputType.PROGRESS)
|
|
204
|
+
payload = {
|
|
205
|
+
"messages": [{"role": "user", "content": message}],
|
|
59
206
|
"use_search": True,
|
|
60
|
-
"extend": {
|
|
61
|
-
"sidebar": True
|
|
62
|
-
},
|
|
207
|
+
"extend": {"sidebar": True},
|
|
63
208
|
"kimiplus_id": "kimi",
|
|
64
209
|
"use_research": False,
|
|
65
210
|
"use_math": False,
|
|
66
|
-
"refs":
|
|
67
|
-
"refs_file":
|
|
68
|
-
}
|
|
211
|
+
"refs": refs,
|
|
212
|
+
"refs_file": refs_file
|
|
213
|
+
}
|
|
214
|
+
|
|
69
215
|
headers = {
|
|
70
216
|
'Authorization': self.auth_header,
|
|
71
217
|
'Content-Type': 'application/json'
|
|
72
218
|
}
|
|
73
219
|
|
|
74
220
|
try:
|
|
75
|
-
response = requests.
|
|
221
|
+
response = requests.post(url, headers=headers, json=payload, stream=True)
|
|
76
222
|
full_response = ""
|
|
77
|
-
references = []
|
|
78
223
|
|
|
224
|
+
PrettyOutput.print("接收响应...", OutputType.PROGRESS)
|
|
79
225
|
for line in response.iter_lines():
|
|
80
226
|
if not line:
|
|
81
227
|
continue
|
|
82
|
-
|
|
228
|
+
|
|
83
229
|
line = line.decode('utf-8')
|
|
84
230
|
if not line.startswith("data: "):
|
|
85
231
|
continue
|
|
86
|
-
|
|
87
|
-
try:
|
|
88
|
-
data = json.loads(line[6:]) # 去掉 "data: " 前缀
|
|
89
232
|
|
|
90
|
-
|
|
233
|
+
try:
|
|
234
|
+
data = json.loads(line[6:])
|
|
91
235
|
if data.get("event") == "cmpl":
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
PrettyOutput.print_stream(text, OutputType.SYSTEM)
|
|
236
|
+
text = data.get("text", "")
|
|
237
|
+
if text:
|
|
238
|
+
PrettyOutput.print_stream(text, OutputType.SYSTEM)
|
|
95
239
|
full_response += text
|
|
96
|
-
elif data.get("event") == "ref_docs":
|
|
97
|
-
if "ref_cards" in data:
|
|
98
|
-
for ref in data["ref_cards"]:
|
|
99
|
-
reference = {
|
|
100
|
-
"title": ref.get("title", ""),
|
|
101
|
-
"url": ref.get("url", ""),
|
|
102
|
-
"abstract": ref.get("abstract", "")
|
|
103
|
-
}
|
|
104
|
-
references.append(reference)
|
|
105
|
-
PrettyOutput.print(f"\n参考来源: {reference['title']} - {reference['url']}",
|
|
106
|
-
OutputType.INFO)
|
|
107
|
-
elif data.get("event") == "error":
|
|
108
|
-
error_msg = data.get("error", "Unknown error")
|
|
109
|
-
raise Exception(f"Chat error: {error_msg}")
|
|
110
|
-
elif data.get("event") == "all_done":
|
|
111
|
-
break
|
|
112
|
-
|
|
113
240
|
except json.JSONDecodeError:
|
|
114
241
|
continue
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
if references:
|
|
118
|
-
full_response += "\n\n参考来源:\n"
|
|
119
|
-
for i, ref in enumerate(references, 1):
|
|
120
|
-
full_response += f"{i}. {ref['title']} - {ref['url']}\n"
|
|
121
|
-
|
|
122
|
-
PrettyOutput.print_stream_end() # 结束流式输出
|
|
242
|
+
|
|
243
|
+
PrettyOutput.print_stream_end()
|
|
123
244
|
return full_response
|
|
124
245
|
|
|
125
246
|
except Exception as e:
|
|
126
|
-
raise Exception(f"
|
|
127
|
-
|
|
247
|
+
raise Exception(f"Chat failed: {str(e)}")
|
|
248
|
+
|
|
128
249
|
def reset(self):
|
|
129
|
-
"""
|
|
250
|
+
"""重置对话"""
|
|
130
251
|
self.chat_id = ""
|
|
252
|
+
self.uploaded_files = []
|
|
253
|
+
self.first_chat = True # 重置first_chat标记
|
|
131
254
|
|
|
132
255
|
|
|
133
256
|
if __name__ == "__main__":
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
jarvis/__init__.py,sha256=
|
|
2
|
-
jarvis/agent.py,sha256=
|
|
3
|
-
jarvis/main.py,sha256=
|
|
1
|
+
jarvis/__init__.py,sha256=_aIzFZNgMY8TxeqpWoDZOcvaSQ7uK4SxZvtdW_HPIHw,50
|
|
2
|
+
jarvis/agent.py,sha256=AJCRmjrvlK19K-yj5zNwrFvVDbZ3mWEnzwHwxKCXTL8,8462
|
|
3
|
+
jarvis/main.py,sha256=_1hE0MZ1OsIJpmlipUwtqFszh9rm7VmQcnnWr80o3p4,4176
|
|
4
4
|
jarvis/utils.py,sha256=3hLtv-HcBL8Ngw69cowhARuIFrjcQ6yRP3Y1o9CvtsI,5992
|
|
5
|
-
jarvis/__pycache__/__init__.cpython-313.pyc,sha256=
|
|
6
|
-
jarvis/__pycache__/agent.cpython-313.pyc,sha256=
|
|
7
|
-
jarvis/__pycache__/main.cpython-313.pyc,sha256=
|
|
5
|
+
jarvis/__pycache__/__init__.cpython-313.pyc,sha256=QtWKLHgbSECIa7pnYFe-pSmrHEzJUhP4Aorar8bxZqA,209
|
|
6
|
+
jarvis/__pycache__/agent.cpython-313.pyc,sha256=sLDZttVT9sOC6WKgs_SWhrEzfsN9vzlMhknMJkEqkVY,9746
|
|
7
|
+
jarvis/__pycache__/main.cpython-313.pyc,sha256=o80rvS95KbpeL4MSEoMC0rt0Y91-asDHbHPJU8M8kxo,5933
|
|
8
8
|
jarvis/__pycache__/models.cpython-313.pyc,sha256=uWuRIjGrY4YDB3dGW5PGDLWaS03et8g11O725TjY_eU,5960
|
|
9
9
|
jarvis/__pycache__/tools.cpython-313.pyc,sha256=lAD4LrnnWzNZQmHXGfZ_2l7oskOpr2_2OC-gdFhxQY8,33933
|
|
10
10
|
jarvis/__pycache__/utils.cpython-313.pyc,sha256=k4jyAlx4tlW0MKLMLzV7OOH9zsKrK0H955kY6M2SuFU,8772
|
|
11
11
|
jarvis/__pycache__/zte_llm.cpython-313.pyc,sha256=kMm9IGundGmOPqjsgrm9oIaWLDagYGCPRAaE3ipkc-0,5662
|
|
12
12
|
jarvis/models/__init__.py,sha256=B_IJFvKTaxdg19FAD1ea288tYp3-bRYRpkeGI0_OcBI,262
|
|
13
|
-
jarvis/models/base.py,sha256=
|
|
14
|
-
jarvis/models/kimi.py,sha256=
|
|
13
|
+
jarvis/models/base.py,sha256=GgVl5N0qDqn-yqRcX_PX3wHjogouE6GPFAWktG40cXg,403
|
|
14
|
+
jarvis/models/kimi.py,sha256=J_0QB6XY61tY-Oeu2cexWto58QbMU_liYj1f6PKbNRw,9763
|
|
15
15
|
jarvis/models/__pycache__/__init__.cpython-313.pyc,sha256=jAwySX4diR7EWM_alK75tiIb_J8bVfs4Bh_U3bdjDLo,534
|
|
16
|
-
jarvis/models/__pycache__/base.cpython-313.pyc,sha256=
|
|
17
|
-
jarvis/models/__pycache__/kimi.cpython-313.pyc,sha256=
|
|
16
|
+
jarvis/models/__pycache__/base.cpython-313.pyc,sha256=4I9KZlXHvTB7vENA9YWK4Fx0sns_KvIOtWqzE9y_-Co,1094
|
|
17
|
+
jarvis/models/__pycache__/kimi.cpython-313.pyc,sha256=doDXu1nPClQOVqnDFGGBl2p_3AMDuDaiFAgdsP-G1NM,12524
|
|
18
18
|
jarvis/tools/__init__.py,sha256=000SvX1Z0yzKtuVR9NS45r41DHUVpE6EiSEzzE99uR0,196
|
|
19
19
|
jarvis/tools/base.py,sha256=qm73kMOkqAWHjUisUWFye-x69LJuZdwm0U3Tct-mmMc,3890
|
|
20
20
|
jarvis/tools/file_ops.py,sha256=zTksx45NZm3iz9itN5iQGZ8DoxnSeTHdrnF08_ix7PU,3770
|
|
@@ -32,8 +32,8 @@ jarvis/tools/__pycache__/user_confirmation.cpython-313.pyc,sha256=wK3Ev10lHSUSRv
|
|
|
32
32
|
jarvis/tools/__pycache__/user_input.cpython-313.pyc,sha256=JjTFOhObKsKF4Pn8KBRuKfV1_Ssj083fjU7Mfc_5z7c,2531
|
|
33
33
|
jarvis/tools/__pycache__/user_interaction.cpython-313.pyc,sha256=RuVZ-pmiPBDywY3efgXSfohMAciC1avMGPmBK5qlnew,3305
|
|
34
34
|
jarvis/tools/__pycache__/webpage.cpython-313.pyc,sha256=BjzSfnNzsKCrLETCcWjt32lNDLzwnjqcVGg4JfWd9OM,3008
|
|
35
|
-
jarvis_ai_assistant-0.1.
|
|
36
|
-
jarvis_ai_assistant-0.1.
|
|
37
|
-
jarvis_ai_assistant-0.1.
|
|
38
|
-
jarvis_ai_assistant-0.1.
|
|
39
|
-
jarvis_ai_assistant-0.1.
|
|
35
|
+
jarvis_ai_assistant-0.1.11.dist-info/METADATA,sha256=PLBiD-OM5rCBVi3MWF93SXePf6piXNW0OI8I_D2tUP8,3585
|
|
36
|
+
jarvis_ai_assistant-0.1.11.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
37
|
+
jarvis_ai_assistant-0.1.11.dist-info/entry_points.txt,sha256=iKu7OMfew9dtfGhW71gIMTg4wvafuPqKb4wyQOnMAGU,44
|
|
38
|
+
jarvis_ai_assistant-0.1.11.dist-info/top_level.txt,sha256=1BOxyWfzOP_ZXj8rVTDnNCJ92bBGB0rwq8N1PCpoMIs,7
|
|
39
|
+
jarvis_ai_assistant-0.1.11.dist-info/RECORD,,
|
|
File without changes
|
{jarvis_ai_assistant-0.1.10.dist-info → jarvis_ai_assistant-0.1.11.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|