jarvis-ai-assistant 0.1.10__py3-none-any.whl → 0.1.12__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/agent.py +33 -79
- 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.12.dist-info}/METADATA +26 -19
- {jarvis_ai_assistant-0.1.10.dist-info → jarvis_ai_assistant-0.1.12.dist-info}/RECORD +15 -15
- {jarvis_ai_assistant-0.1.10.dist-info → jarvis_ai_assistant-0.1.12.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.10.dist-info → jarvis_ai_assistant-0.1.12.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.10.dist-info → jarvis_ai_assistant-0.1.12.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,10 +101,7 @@ 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
|
|
|
@@ -123,7 +128,7 @@ ReAct 框架:
|
|
|
123
128
|
- 只使用下面列出的工具
|
|
124
129
|
- 每次只执行一个工具
|
|
125
130
|
- 工具由用户手动执行
|
|
126
|
-
-
|
|
131
|
+
- 必须使用有效合法的YAML格式:
|
|
127
132
|
<START_TOOL_CALL>
|
|
128
133
|
name: tool_name
|
|
129
134
|
arguments:
|
|
@@ -164,7 +169,6 @@ arguments:
|
|
|
164
169
|
‼️ 工具调用必须是有效的YAML格式
|
|
165
170
|
‼️ 参数必须正确缩进
|
|
166
171
|
‼️ 使用YAML块样式(|)表示多行值
|
|
167
|
-
‼️ <END_TOOL_CALL>后的内容将被丢弃
|
|
168
172
|
‼️ 工具由用户手动执行
|
|
169
173
|
‼️ 等待用户提供工具执行结果
|
|
170
174
|
‼️ 不要假设或想象用户回应
|
|
@@ -190,32 +194,21 @@ arguments:
|
|
|
190
194
|
任务:
|
|
191
195
|
{user_input}
|
|
192
196
|
"""
|
|
193
|
-
|
|
194
|
-
]
|
|
197
|
+
|
|
195
198
|
|
|
196
199
|
while True:
|
|
197
200
|
try:
|
|
198
201
|
# 显示思考状态
|
|
199
202
|
PrettyOutput.print("分析任务...", OutputType.PROGRESS)
|
|
200
203
|
|
|
201
|
-
current_response = self._call_model(self.
|
|
204
|
+
current_response = self._call_model(self.prompt)
|
|
202
205
|
|
|
203
206
|
try:
|
|
204
207
|
result = Agent.extract_tool_calls(current_response)
|
|
205
208
|
except Exception as e:
|
|
206
209
|
PrettyOutput.print(f"工具调用错误: {str(e)}", OutputType.ERROR)
|
|
207
|
-
self.
|
|
208
|
-
"role": "user",
|
|
209
|
-
"content": f"工具调用错误: {str(e)}"
|
|
210
|
-
})
|
|
210
|
+
self.prompt = f"工具调用错误: {str(e)}"
|
|
211
211
|
continue
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
self.messages.append({
|
|
215
|
-
"role": "assistant",
|
|
216
|
-
"content": current_response
|
|
217
|
-
})
|
|
218
|
-
|
|
219
212
|
|
|
220
213
|
if len(result) > 0:
|
|
221
214
|
try:
|
|
@@ -227,68 +220,29 @@ arguments:
|
|
|
227
220
|
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
228
221
|
tool_result = f"Tool call failed: {str(e)}"
|
|
229
222
|
|
|
230
|
-
self.
|
|
231
|
-
"role": "user",
|
|
232
|
-
"content": tool_result
|
|
233
|
-
})
|
|
223
|
+
self.prompt = tool_result
|
|
234
224
|
continue
|
|
235
225
|
|
|
236
226
|
# 获取用户输入
|
|
237
227
|
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
228
|
if user_input == "__interrupt__":
|
|
280
229
|
PrettyOutput.print("任务已取消", OutputType.WARNING)
|
|
281
230
|
return "Task cancelled by user"
|
|
231
|
+
if user_input:
|
|
232
|
+
self.prompt = user_input
|
|
233
|
+
continue
|
|
234
|
+
|
|
235
|
+
if not user_input:
|
|
236
|
+
PrettyOutput.section("任务完成", OutputType.SUCCESS)
|
|
237
|
+
return
|
|
238
|
+
|
|
239
|
+
|
|
282
240
|
|
|
283
|
-
self.messages.append({
|
|
284
|
-
"role": "user",
|
|
285
|
-
"content": user_input
|
|
286
|
-
})
|
|
287
241
|
|
|
288
242
|
except Exception as e:
|
|
289
243
|
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
290
244
|
|
|
291
245
|
def clear_history(self):
|
|
292
246
|
"""清除对话历史,只保留系统提示"""
|
|
293
|
-
self.
|
|
247
|
+
self.prompt = ""
|
|
294
248
|
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,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: jarvis-ai-assistant
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.12
|
|
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
|
|
@@ -36,7 +36,7 @@ Dynamic: requires-python
|
|
|
36
36
|
<img src="docs/images/jarvis-logo.png" alt="Jarvis Logo" width="200"/>
|
|
37
37
|
</p>
|
|
38
38
|
|
|
39
|
-
[](https://badge.fury.io/py/jarvis-ai)
|
|
39
|
+
[](https://badge.fury.io/py/jarvis-ai-assistant)
|
|
40
40
|
[](https://opensource.org/licenses/MIT)
|
|
41
41
|
[](https://www.python.org/downloads/)
|
|
42
42
|
|
|
@@ -54,20 +54,23 @@ Dynamic: requires-python
|
|
|
54
54
|
|
|
55
55
|
## 🌟 Features
|
|
56
56
|
|
|
57
|
-
🤖 **
|
|
58
|
-
-
|
|
59
|
-
-
|
|
57
|
+
🤖 **AI Integration**
|
|
58
|
+
- Kimi AI integration with streaming responses
|
|
59
|
+
- Context-aware conversations
|
|
60
|
+
- File understanding capabilities
|
|
60
61
|
|
|
61
62
|
🛠️ **Rich Tool Integration**
|
|
62
|
-
-
|
|
63
|
-
- File operations
|
|
64
|
-
-
|
|
65
|
-
-
|
|
63
|
+
- Shell command execution
|
|
64
|
+
- File operations (read/write/append)
|
|
65
|
+
- Task automation
|
|
66
|
+
- Predefined task support
|
|
66
67
|
|
|
67
68
|
🔄 **Interactive Experience**
|
|
68
69
|
- Natural language understanding
|
|
69
70
|
- Context-aware responses
|
|
70
71
|
- User-friendly interface
|
|
72
|
+
- Multi-line input support
|
|
73
|
+
- Colored output with progress indicators
|
|
71
74
|
|
|
72
75
|
## 🚀 Installation
|
|
73
76
|
|
|
@@ -81,25 +84,21 @@ pip install jarvis-ai-assistant
|
|
|
81
84
|
# Quick Start
|
|
82
85
|
jarvis
|
|
83
86
|
|
|
84
|
-
#
|
|
85
|
-
jarvis
|
|
87
|
+
# Process files
|
|
88
|
+
jarvis -f file1.txt file2.py
|
|
86
89
|
|
|
87
|
-
#
|
|
88
|
-
jarvis
|
|
90
|
+
# Using predefined tasks
|
|
91
|
+
# Create .jarvis file in your working directory:
|
|
92
|
+
analyze_code: Analyze the code in the current directory
|
|
93
|
+
fix_bugs: Help me find and fix bugs in the code
|
|
89
94
|
```
|
|
90
95
|
|
|
91
96
|
## 🧰 Tools
|
|
92
97
|
|
|
93
98
|
| Tool | Description | Example |
|
|
94
99
|
|------|-------------|---------|
|
|
95
|
-
| 🔍 Search | Web search using DuckDuckGo | Search latest tech news |
|
|
96
|
-
| 📚 RAG | Document querying with embeddings | Query your documentation |
|
|
97
|
-
| 🐍 Python | Execute Python code | Run data analysis |
|
|
98
100
|
| 🖥️ Shell | Execute system commands | Manage files and processes |
|
|
99
101
|
| 📂 Files | Read/write operations | Handle configuration files |
|
|
100
|
-
| 🌐 Web | Extract webpage content | Gather information |
|
|
101
|
-
| 👤 User | Interactive input/confirmation | Get user preferences |
|
|
102
|
-
|
|
103
102
|
|
|
104
103
|
## 🤝 Contributing
|
|
105
104
|
|
|
@@ -115,6 +114,14 @@ Contributions are welcome! Please feel free to submit a Pull Request.
|
|
|
115
114
|
|
|
116
115
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
117
116
|
|
|
117
|
+
## ⚙️ Environment Setup
|
|
118
|
+
|
|
119
|
+
Create a `.jarvis_env` file in your home directory with:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
KIMI_API_KEY=your_kimi_api_key_here
|
|
123
|
+
```
|
|
124
|
+
|
|
118
125
|
---
|
|
119
126
|
|
|
120
127
|
<div align="center">
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
jarvis/__init__.py,sha256=
|
|
2
|
-
jarvis/agent.py,sha256=
|
|
3
|
-
jarvis/main.py,sha256=
|
|
1
|
+
jarvis/__init__.py,sha256=famvLolv2Q7BJtAyM81Gi64oXQv1nh1rjb1kJ_f5hKc,50
|
|
2
|
+
jarvis/agent.py,sha256=xo5YdY8UbgE3AJaitT1dXoNoVm769LrWyFzEXxVCG7A,8672
|
|
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=GspJR-EdT1vU33bJjBm_IcUrNBtFKVEhKoHJnyIYY5s,209
|
|
6
|
+
jarvis/__pycache__/agent.cpython-313.pyc,sha256=DP0zgyKjGuwc62rH_vpoy_hXmGMI3zoHPlXZYu0qqp4,9956
|
|
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=ks1WiR1d8NTu-0B4s9zIyifWUvijBN4qI6AFD0Jtgk0,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.12.dist-info/METADATA,sha256=BDwc5sbj9q6qHxq5KDMKdZCod0_PrMX-6H9YHWd0Pkg,3507
|
|
36
|
+
jarvis_ai_assistant-0.1.12.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
37
|
+
jarvis_ai_assistant-0.1.12.dist-info/entry_points.txt,sha256=iKu7OMfew9dtfGhW71gIMTg4wvafuPqKb4wyQOnMAGU,44
|
|
38
|
+
jarvis_ai_assistant-0.1.12.dist-info/top_level.txt,sha256=1BOxyWfzOP_ZXj8rVTDnNCJ92bBGB0rwq8N1PCpoMIs,7
|
|
39
|
+
jarvis_ai_assistant-0.1.12.dist-info/RECORD,,
|
|
File without changes
|
{jarvis_ai_assistant-0.1.10.dist-info → jarvis_ai_assistant-0.1.12.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|