jarvis-ai-assistant 0.1.44__py3-none-any.whl → 0.1.46__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/agent.py +47 -32
  3. jarvis/main.py +52 -30
  4. jarvis/models/__init__.py +1 -1
  5. jarvis/models/ai8.py +88 -58
  6. jarvis/models/base.py +6 -6
  7. jarvis/models/kimi.py +171 -80
  8. jarvis/models/openai.py +43 -23
  9. jarvis/models/oyi.py +93 -65
  10. jarvis/models/registry.py +63 -44
  11. jarvis/tools/__init__.py +1 -1
  12. jarvis/tools/base.py +2 -2
  13. jarvis/tools/file_ops.py +19 -15
  14. jarvis/tools/generator.py +15 -12
  15. jarvis/tools/methodology.py +20 -20
  16. jarvis/tools/registry.py +44 -30
  17. jarvis/tools/shell.py +12 -11
  18. jarvis/tools/sub_agent.py +1 -2
  19. jarvis/utils.py +47 -27
  20. {jarvis_ai_assistant-0.1.44.dist-info → jarvis_ai_assistant-0.1.46.dist-info}/METADATA +1 -1
  21. jarvis_ai_assistant-0.1.46.dist-info/RECORD +25 -0
  22. jarvis/__pycache__/__init__.cpython-313.pyc +0 -0
  23. jarvis/__pycache__/agent.cpython-313.pyc +0 -0
  24. jarvis/__pycache__/main.cpython-313.pyc +0 -0
  25. jarvis/__pycache__/models.cpython-313.pyc +0 -0
  26. jarvis/__pycache__/tools.cpython-313.pyc +0 -0
  27. jarvis/__pycache__/utils.cpython-313.pyc +0 -0
  28. jarvis/__pycache__/zte_llm.cpython-313.pyc +0 -0
  29. jarvis/models/__pycache__/__init__.cpython-313.pyc +0 -0
  30. jarvis/models/__pycache__/ai8.cpython-313.pyc +0 -0
  31. jarvis/models/__pycache__/base.cpython-313.pyc +0 -0
  32. jarvis/models/__pycache__/kimi.cpython-313.pyc +0 -0
  33. jarvis/models/__pycache__/openai.cpython-313.pyc +0 -0
  34. jarvis/models/__pycache__/oyi.cpython-313.pyc +0 -0
  35. jarvis/models/__pycache__/registry.cpython-313.pyc +0 -0
  36. jarvis/tools/__pycache__/__init__.cpython-313.pyc +0 -0
  37. jarvis/tools/__pycache__/base.cpython-313.pyc +0 -0
  38. jarvis/tools/__pycache__/bing_search.cpython-313.pyc +0 -0
  39. jarvis/tools/__pycache__/calculator.cpython-313.pyc +0 -0
  40. jarvis/tools/__pycache__/calculator_tool.cpython-313.pyc +0 -0
  41. jarvis/tools/__pycache__/file_ops.cpython-313.pyc +0 -0
  42. jarvis/tools/__pycache__/generator.cpython-313.pyc +0 -0
  43. jarvis/tools/__pycache__/methodology.cpython-313.pyc +0 -0
  44. jarvis/tools/__pycache__/python_script.cpython-313.pyc +0 -0
  45. jarvis/tools/__pycache__/rag.cpython-313.pyc +0 -0
  46. jarvis/tools/__pycache__/registry.cpython-313.pyc +0 -0
  47. jarvis/tools/__pycache__/search.cpython-313.pyc +0 -0
  48. jarvis/tools/__pycache__/shell.cpython-313.pyc +0 -0
  49. jarvis/tools/__pycache__/sub_agent.cpython-313.pyc +0 -0
  50. jarvis/tools/__pycache__/user_confirmation.cpython-313.pyc +0 -0
  51. jarvis/tools/__pycache__/user_input.cpython-313.pyc +0 -0
  52. jarvis/tools/__pycache__/user_interaction.cpython-313.pyc +0 -0
  53. jarvis/tools/__pycache__/webpage.cpython-313.pyc +0 -0
  54. jarvis_ai_assistant-0.1.44.dist-info/RECORD +0 -57
  55. {jarvis_ai_assistant-0.1.44.dist-info → jarvis_ai_assistant-0.1.46.dist-info}/LICENSE +0 -0
  56. {jarvis_ai_assistant-0.1.44.dist-info → jarvis_ai_assistant-0.1.46.dist-info}/WHEEL +0 -0
  57. {jarvis_ai_assistant-0.1.44.dist-info → jarvis_ai_assistant-0.1.46.dist-info}/entry_points.txt +0 -0
  58. {jarvis_ai_assistant-0.1.44.dist-info → jarvis_ai_assistant-0.1.46.dist-info}/top_level.txt +0 -0
jarvis/models/kimi.py CHANGED
@@ -8,31 +8,46 @@ from jarvis.models.base import BasePlatform
8
8
  from jarvis.utils import PrettyOutput, OutputType
9
9
  from jarvis.utils import while_success
10
10
 
11
+
11
12
  class KimiModel(BasePlatform):
12
13
  """Kimi模型实现"""
13
14
 
14
15
  platform_name = "kimi"
15
-
16
+
16
17
  def __init__(self):
17
18
  """
18
19
  初始化Kimi模型
19
20
  """
20
21
  self.api_key = os.getenv("KIMI_API_KEY")
21
22
  if not self.api_key:
22
- PrettyOutput.print("\n需要设置 KIMI_API_KEY 才能使用 Jarvis。请按以下步骤操作:", OutputType.INFO)
23
+ PrettyOutput.print(
24
+ "\n需要设置 KIMI_API_KEY 才能使用 Jarvis。请按以下步骤操作:",
25
+ OutputType.INFO)
23
26
  PrettyOutput.print("\n1. 获取 Kimi API Key:", OutputType.INFO)
24
- PrettyOutput.print(" • 访问 Kimi AI 平台: https://kimi.moonshot.cn", OutputType.INFO)
27
+ PrettyOutput.print(
28
+ " • 访问 Kimi AI 平台: https://kimi.moonshot.cn",
29
+ OutputType.INFO)
25
30
  PrettyOutput.print(" • 登录您的账号", OutputType.INFO)
26
- PrettyOutput.print(" • 打开浏览器开发者工具 (F12 或右键 -> 检查)", OutputType.INFO)
31
+ PrettyOutput.print(
32
+ " • 打开浏览器开发者工具 (F12 或右键 -> 检查)",
33
+ OutputType.INFO)
27
34
  PrettyOutput.print(" • 切换到 Network 标签页", OutputType.INFO)
28
35
  PrettyOutput.print(" • 发送任意消息", OutputType.INFO)
29
36
  PrettyOutput.print(" • 在请求中找到 Authorization 头部", OutputType.INFO)
30
- PrettyOutput.print(" • 复制 token 值(去掉 'Bearer ' 前缀)", OutputType.INFO)
37
+ PrettyOutput.print(
38
+ " • 复制 token 值(去掉 'Bearer ' 前缀)",
39
+ OutputType.INFO)
31
40
  PrettyOutput.print("\n2. 设置环境变量:", OutputType.INFO)
32
- PrettyOutput.print(" 方法 1: 创建或编辑 ~/.jarvis_env 文件:", OutputType.INFO)
33
- PrettyOutput.print(" echo 'KIMI_API_KEY=your_key_here' > ~/.jarvis_env", OutputType.INFO)
41
+ PrettyOutput.print(
42
+ " 方法 1: 创建或编辑 ~/.jarvis_env 文件:",
43
+ OutputType.INFO)
44
+ PrettyOutput.print(
45
+ " echo 'KIMI_API_KEY=your_key_here' > ~/.jarvis_env",
46
+ OutputType.INFO)
34
47
  PrettyOutput.print("\n 方法 2: 直接设置环境变量:", OutputType.INFO)
35
- PrettyOutput.print(" export KIMI_API_KEY=your_key_here", OutputType.INFO)
48
+ PrettyOutput.print(
49
+ " export KIMI_API_KEY=your_key_here",
50
+ OutputType.INFO)
36
51
  PrettyOutput.print("\n设置完成后重新运行 Jarvis。", OutputType.INFO)
37
52
  raise Exception("KIMI_API_KEY is not set")
38
53
  self.auth_header = f"Bearer {self.api_key}"
@@ -62,30 +77,41 @@ class KimiModel(BasePlatform):
62
77
  'Content-Type': 'application/json'
63
78
  }
64
79
  try:
65
- response = while_success(lambda: requests.request("POST", url, headers=headers, data=payload), sleep_time=5)
80
+ response = while_success(
81
+ lambda: requests.request(
82
+ "POST",
83
+ url,
84
+ headers=headers,
85
+ data=payload),
86
+ sleep_time=5)
66
87
  self.chat_id = response.json()["id"]
67
88
  return True
68
89
  except Exception as e:
69
- PrettyOutput.print(f"Error: Failed to create chat: {e}", OutputType.ERROR)
90
+ PrettyOutput.print(
91
+ f"Error: Failed to create chat: {e}",
92
+ OutputType.ERROR)
70
93
  return False
71
94
 
72
95
  def _get_presigned_url(self, filename: str, action: str) -> Dict:
73
96
  """获取预签名上传URL"""
74
97
  url = "https://kimi.moonshot.cn/api/pre-sign-url"
75
-
76
-
77
-
98
+
78
99
  payload = json.dumps({
79
100
  "action": action,
80
101
  "name": os.path.basename(filename)
81
102
  }, ensure_ascii=False)
82
-
103
+
83
104
  headers = {
84
105
  'Authorization': self.auth_header,
85
106
  'Content-Type': 'application/json'
86
107
  }
87
-
88
- response = while_success(lambda: requests.post(url, headers=headers, data=payload), sleep_time=5)
108
+
109
+ response = while_success(
110
+ lambda: requests.post(
111
+ url,
112
+ headers=headers,
113
+ data=payload),
114
+ sleep_time=5)
89
115
  return response.json()
90
116
 
91
117
  def _upload_file(self, file_path: str, presigned_url: str) -> bool:
@@ -93,13 +119,20 @@ class KimiModel(BasePlatform):
93
119
  try:
94
120
  with open(file_path, 'rb') as f:
95
121
  content = f.read()
96
- response = while_success(lambda: requests.put(presigned_url, data=content), sleep_time=5)
122
+ response = while_success(
123
+ lambda: requests.put(
124
+ presigned_url,
125
+ data=content),
126
+ sleep_time=5)
97
127
  return response.status_code == 200
98
128
  except Exception as e:
99
- PrettyOutput.print(f"Error: Failed to upload file: {e}", OutputType.ERROR)
129
+ PrettyOutput.print(
130
+ f"Error: Failed to upload file: {e}",
131
+ OutputType.ERROR)
100
132
  return False
101
133
 
102
- def _get_file_info(self, file_data: Dict, name: str, file_type: str) -> Dict:
134
+ def _get_file_info(self, file_data: Dict, name: str,
135
+ file_type: str) -> Dict:
103
136
  """获取文件信息"""
104
137
  url = "https://kimi.moonshot.cn/api/file"
105
138
  payload = json.dumps({
@@ -109,13 +142,18 @@ class KimiModel(BasePlatform):
109
142
  "chat_id": self.chat_id,
110
143
  "file_id": file_data.get("file_id", "")
111
144
  }, ensure_ascii=False)
112
-
145
+
113
146
  headers = {
114
147
  'Authorization': self.auth_header,
115
148
  'Content-Type': 'application/json'
116
149
  }
117
-
118
- response = while_success(lambda: requests.post(url, headers=headers, data=payload), sleep_time=5)
150
+
151
+ response = while_success(
152
+ lambda: requests.post(
153
+ url,
154
+ headers=headers,
155
+ data=payload),
156
+ sleep_time=5)
119
157
  return response.json()
120
158
 
121
159
  def _wait_for_parse(self, file_id: str) -> bool:
@@ -125,22 +163,28 @@ class KimiModel(BasePlatform):
125
163
  'Authorization': self.auth_header,
126
164
  'Content-Type': 'application/json'
127
165
  }
128
-
166
+
129
167
  max_retries = 30
130
168
  retry_count = 0
131
-
169
+
132
170
  while retry_count < max_retries:
133
171
  payload = json.dumps({"ids": [file_id]}, ensure_ascii=False)
134
- response = while_success(lambda: requests.post(url, headers=headers, data=payload, stream=True), sleep_time=5)
135
-
172
+ response = while_success(
173
+ lambda: requests.post(
174
+ url,
175
+ headers=headers,
176
+ data=payload,
177
+ stream=True),
178
+ sleep_time=5)
179
+
136
180
  for line in response.iter_lines():
137
181
  if not line:
138
182
  continue
139
-
183
+
140
184
  line = line.decode('utf-8')
141
185
  if not line.startswith("data: "):
142
186
  continue
143
-
187
+
144
188
  try:
145
189
  data = json.loads(line[6:])
146
190
  if data.get("event") == "resp":
@@ -151,18 +195,19 @@ class KimiModel(BasePlatform):
151
195
  return False
152
196
  except json.JSONDecodeError:
153
197
  continue
154
-
198
+
155
199
  retry_count += 1
156
200
  time.sleep(1)
157
-
201
+
158
202
  return False
203
+
159
204
  def upload_files(self, file_list: List[str]) -> List[Dict]:
160
205
  """上传文件列表并返回文件信息"""
161
206
  if not file_list:
162
207
  return []
163
208
 
164
209
  PrettyOutput.print("Progress: 开始处理文件上传...", OutputType.PROGRESS)
165
-
210
+
166
211
  if not self.chat_id:
167
212
  PrettyOutput.print("创建新的对话会话...", OutputType.PROGRESS)
168
213
  if not self._create_chat():
@@ -171,21 +216,24 @@ class KimiModel(BasePlatform):
171
216
  uploaded_files = []
172
217
  for index, file_path in enumerate(file_list, 1):
173
218
  try:
174
- PrettyOutput.print(f"处理文件 [{index}/{len(file_list)}]: {file_path}", OutputType.PROGRESS)
219
+ PrettyOutput.print(
220
+ f"处理文件 [{index}/{len(file_list)}]: {file_path}", OutputType.PROGRESS)
175
221
 
176
222
  mime_type, _ = mimetypes.guess_type(file_path)
177
- action = "image" if mime_type and mime_type.startswith('image/') else "file"
178
-
223
+ action = "image" if mime_type and mime_type.startswith(
224
+ 'image/') else "file"
225
+
179
226
  # 获取预签名URL
180
227
  PrettyOutput.print("获取上传URL...", OutputType.PROGRESS)
181
228
  presigned_data = self._get_presigned_url(file_path, action)
182
-
229
+
183
230
  # 上传文件
184
231
  PrettyOutput.print("上传文件内容...", OutputType.PROGRESS)
185
232
  if self._upload_file(file_path, presigned_data["url"]):
186
233
  # 获取文件信息
187
234
  PrettyOutput.print("获取文件信息...", OutputType.PROGRESS)
188
- file_info = self._get_file_info(presigned_data, os.path.basename(file_path), action)
235
+ file_info = self._get_file_info(
236
+ presigned_data, os.path.basename(file_path), action)
189
237
  # 等待文件解析
190
238
  PrettyOutput.print("等待文件解析完成...", OutputType.PROGRESS)
191
239
 
@@ -193,24 +241,31 @@ class KimiModel(BasePlatform):
193
241
  if action == "file":
194
242
  if self._wait_for_parse(file_info["id"]):
195
243
  uploaded_files.append(file_info)
196
- PrettyOutput.print(f"Success: 文件处理成功: {file_path}", OutputType.SUCCESS)
244
+ PrettyOutput.print(
245
+ f"Success: 文件处理成功: {file_path}", OutputType.SUCCESS)
197
246
  else:
198
- PrettyOutput.print(f"✗ 文件解析失败: {file_path}", OutputType.ERROR)
247
+ PrettyOutput.print(
248
+ f"✗ 文件解析失败: {file_path}", OutputType.ERROR)
199
249
  else:
200
250
  uploaded_files.append(file_info)
201
- PrettyOutput.print(f"Success: 文件处理成功: {file_path}", OutputType.SUCCESS)
251
+ PrettyOutput.print(
252
+ f"Success: 文件处理成功: {file_path}", OutputType.SUCCESS)
202
253
  else:
203
- PrettyOutput.print(f"Error: 文件上传失败: {file_path}", OutputType.ERROR)
204
-
254
+ PrettyOutput.print(
255
+ f"Error: 文件上传失败: {file_path}", OutputType.ERROR)
256
+
205
257
  except Exception as e:
206
- PrettyOutput.print(f"✗ 处理文件出错 {file_path}: {str(e)}", OutputType.ERROR)
258
+ PrettyOutput.print(
259
+ f"✗ 处理文件出错 {file_path}: {
260
+ str(e)}", OutputType.ERROR)
207
261
  continue
208
-
262
+
209
263
  if uploaded_files:
210
- PrettyOutput.print(f"成功处理 {len(uploaded_files)}/{len(file_list)} 个文件", OutputType.SUCCESS)
264
+ PrettyOutput.print(
265
+ f"成功处理 {len(uploaded_files)}/{len(file_list)} 个文件", OutputType.SUCCESS)
211
266
  else:
212
267
  PrettyOutput.print("没有文件成功处理", OutputType.ERROR)
213
-
268
+
214
269
  self.uploaded_files = uploaded_files
215
270
  return uploaded_files
216
271
 
@@ -221,19 +276,21 @@ class KimiModel(BasePlatform):
221
276
  if not self._create_chat():
222
277
  raise Exception("Failed to create chat session")
223
278
 
224
- url = f"https://kimi.moonshot.cn/api/chat/{self.chat_id}/completion/stream"
225
-
279
+ url = f"https://kimi.moonshot.cn/api/chat/{
280
+ self.chat_id}/completion/stream"
281
+
226
282
  # 只在第一次对话时带上文件引用
227
283
  refs = []
228
284
  refs_file = []
229
285
  if self.first_chat:
230
286
  if self.uploaded_files:
231
- PrettyOutput.print(f"首次对话,引用 {len(self.uploaded_files)} 个文件...", OutputType.PROGRESS)
287
+ PrettyOutput.print(
288
+ f"首次对话,引用 {len(self.uploaded_files)} 个文件...", OutputType.PROGRESS)
232
289
  refs = [f["id"] for f in self.uploaded_files]
233
290
  refs_file = self.uploaded_files
234
291
  message = self.system_message + "\n" + message
235
292
  self.first_chat = False
236
-
293
+
237
294
  PrettyOutput.print("发送请求...", OutputType.PROGRESS)
238
295
  payload = {
239
296
  "messages": [{"role": "user", "content": message}],
@@ -252,33 +309,39 @@ class KimiModel(BasePlatform):
252
309
  }
253
310
 
254
311
  try:
255
- response = while_success(lambda: requests.post(url, headers=headers, json=payload, stream=True), sleep_time=5)
312
+ response = while_success(
313
+ lambda: requests.post(
314
+ url,
315
+ headers=headers,
316
+ json=payload,
317
+ stream=True),
318
+ sleep_time=5)
256
319
  full_response = ""
257
-
320
+
258
321
  # 收集搜索和引用结果
259
322
  search_results = []
260
323
  ref_sources = []
261
-
324
+
262
325
  PrettyOutput.print("接收响应...", OutputType.PROGRESS)
263
326
  for line in response.iter_lines():
264
327
  if not line:
265
328
  continue
266
-
329
+
267
330
  line = line.decode('utf-8')
268
331
  if not line.startswith("data: "):
269
332
  continue
270
-
333
+
271
334
  try:
272
335
  data = json.loads(line[6:])
273
336
  event = data.get("event")
274
-
337
+
275
338
  if event == "cmpl":
276
339
  # 处理补全文本
277
340
  text = data.get("text", "")
278
341
  if text:
279
342
  PrettyOutput.print_stream(text)
280
343
  full_response += text
281
-
344
+
282
345
  elif event == "search_plus":
283
346
  # 收集搜索结果
284
347
  msg = data.get("msg", {})
@@ -291,7 +354,7 @@ class KimiModel(BasePlatform):
291
354
  "type": msg.get("type", ""),
292
355
  "url": msg.get("url", "")
293
356
  })
294
-
357
+
295
358
  elif event == "ref_docs":
296
359
  # 收集引用来源
297
360
  ref_cards = data.get("ref_cards", [])
@@ -307,52 +370,75 @@ class KimiModel(BasePlatform):
307
370
  "rag_segments": card.get("rag_segments", []),
308
371
  "origin": card.get("origin", {})
309
372
  })
310
-
373
+
311
374
  except json.JSONDecodeError:
312
375
  continue
313
-
376
+
314
377
  PrettyOutput.print_stream_end()
315
-
316
378
 
317
379
  # 显示搜索结果摘要
318
380
  if search_results:
319
381
  PrettyOutput.print("\n搜索结果:", OutputType.PROGRESS)
320
382
  for result in search_results:
321
- PrettyOutput.print(f"- {result['title']}", OutputType.PROGRESS)
383
+ PrettyOutput.print(
384
+ f"- {result['title']}", OutputType.PROGRESS)
322
385
  if result['date']:
323
- PrettyOutput.print(f" 日期: {result['date']}", OutputType.PROGRESS)
324
- PrettyOutput.print(f" 来源: {result['site_name']}", OutputType.PROGRESS)
386
+ PrettyOutput.print(
387
+ f" 日期: {
388
+ result['date']}",
389
+ OutputType.PROGRESS)
390
+ PrettyOutput.print(
391
+ f" 来源: {
392
+ result['site_name']}",
393
+ OutputType.PROGRESS)
325
394
  if result['snippet']:
326
- PrettyOutput.print(f" 摘要: {result['snippet']}", OutputType.PROGRESS)
327
- PrettyOutput.print(f" 链接: {result['url']}", OutputType.PROGRESS)
395
+ PrettyOutput.print(
396
+ f" 摘要: {
397
+ result['snippet']}",
398
+ OutputType.PROGRESS)
399
+ PrettyOutput.print(
400
+ f" 链接: {
401
+ result['url']}",
402
+ OutputType.PROGRESS)
328
403
  PrettyOutput.print("", OutputType.PROGRESS)
329
-
404
+
330
405
  # 显示引用来源
331
406
  if ref_sources:
332
407
  PrettyOutput.print("\n引用来源:", OutputType.PROGRESS)
333
408
  for source in ref_sources:
334
- PrettyOutput.print(f"- [{source['ref_id']}] {source['title']} ({source['source']})", OutputType.PROGRESS)
335
- PrettyOutput.print(f" 链接: {source['url']}", OutputType.PROGRESS)
409
+ PrettyOutput.print(
410
+ f"- [{source['ref_id']}] {source['title']} ({source['source']})", OutputType.PROGRESS)
411
+ PrettyOutput.print(
412
+ f" 链接: {
413
+ source['url']}",
414
+ OutputType.PROGRESS)
336
415
  if source['abstract']:
337
- PrettyOutput.print(f" 摘要: {source['abstract']}", OutputType.PROGRESS)
338
-
416
+ PrettyOutput.print(
417
+ f" 摘要: {
418
+ source['abstract']}",
419
+ OutputType.PROGRESS)
420
+
339
421
  # 显示相关段落
340
422
  if source['rag_segments']:
341
423
  PrettyOutput.print(" 相关段落:", OutputType.PROGRESS)
342
424
  for segment in source['rag_segments']:
343
- text = segment.get('text', '').replace('\n', ' ').strip()
425
+ text = segment.get(
426
+ 'text', '').replace(
427
+ '\n', ' ').strip()
344
428
  if text:
345
- PrettyOutput.print(f" - {text}", OutputType.PROGRESS)
346
-
429
+ PrettyOutput.print(
430
+ f" - {text}", OutputType.PROGRESS)
431
+
347
432
  # 显示原文引用
348
433
  origin = source['origin']
349
434
  if origin:
350
435
  text = origin.get('text', '')
351
436
  if text:
352
- PrettyOutput.print(f" 原文: {text}", OutputType.PROGRESS)
353
-
437
+ PrettyOutput.print(
438
+ f" 原文: {text}", OutputType.PROGRESS)
439
+
354
440
  PrettyOutput.print("", OutputType.PROGRESS)
355
-
441
+
356
442
  return full_response
357
443
 
358
444
  except Exception as e:
@@ -362,21 +448,26 @@ class KimiModel(BasePlatform):
362
448
  """删除当前会话"""
363
449
  if not self.chat_id:
364
450
  return True # 如果没有会话ID,视为删除成功
365
-
451
+
366
452
  url = f"https://kimi.moonshot.cn/api/chat/{self.chat_id}"
367
453
  headers = {
368
454
  'Authorization': self.auth_header,
369
455
  'Content-Type': 'application/json'
370
456
  }
371
-
457
+
372
458
  try:
373
- response = while_success(lambda: requests.delete(url, headers=headers), sleep_time=5)
459
+ response = while_success(
460
+ lambda: requests.delete(
461
+ url, headers=headers), sleep_time=5)
374
462
  if response.status_code == 200:
375
463
  PrettyOutput.print("会话已删除", OutputType.SUCCESS)
376
464
  self.reset()
377
465
  return True
378
466
  else:
379
- PrettyOutput.print(f"删除会话失败: HTTP {response.status_code}", OutputType.ERROR)
467
+ PrettyOutput.print(
468
+ f"删除会话失败: HTTP {
469
+ response.status_code}",
470
+ OutputType.ERROR)
380
471
  return False
381
472
  except Exception as e:
382
473
  PrettyOutput.print(f"删除会话时发生错误: {str(e)}", OutputType.ERROR)
jarvis/models/openai.py CHANGED
@@ -4,11 +4,12 @@ from openai import OpenAI
4
4
  from jarvis.models.base import BasePlatform
5
5
  from jarvis.utils import PrettyOutput, OutputType
6
6
 
7
+
7
8
  class OpenAIModel(BasePlatform):
8
9
  """DeepSeek模型实现"""
9
10
 
10
11
  platform_name = "openai"
11
-
12
+
12
13
  def __init__(self):
13
14
  """
14
15
  初始化DeepSeek模型
@@ -17,23 +18,39 @@ class OpenAIModel(BasePlatform):
17
18
  if not self.api_key:
18
19
  PrettyOutput.print("\n需要设置以下环境变量才能使用 OpenAI 模型:", OutputType.INFO)
19
20
  PrettyOutput.print(" • OPENAI_API_KEY: API 密钥", OutputType.INFO)
20
- PrettyOutput.print(" • OPENAI_API_BASE: (可选) API 基础地址,默认使用 https://api.deepseek.com", OutputType.INFO)
21
+ PrettyOutput.print(
22
+ " • OPENAI_API_BASE: (可选) API 基础地址,默认使用 https://api.deepseek.com",
23
+ OutputType.INFO)
21
24
  PrettyOutput.print("\n可以通过以下方式设置:", OutputType.INFO)
22
25
  PrettyOutput.print("1. 创建或编辑 ~/.jarvis_env 文件:", OutputType.INFO)
23
- PrettyOutput.print(" OPENAI_API_KEY=your_api_key", OutputType.INFO)
24
- PrettyOutput.print(" OPENAI_API_BASE=your_api_base", OutputType.INFO)
25
- PrettyOutput.print(" OPENAI_MODEL_NAME=your_model_name", OutputType.INFO)
26
+ PrettyOutput.print(
27
+ " OPENAI_API_KEY=your_api_key",
28
+ OutputType.INFO)
29
+ PrettyOutput.print(
30
+ " OPENAI_API_BASE=your_api_base",
31
+ OutputType.INFO)
32
+ PrettyOutput.print(
33
+ " OPENAI_MODEL_NAME=your_model_name",
34
+ OutputType.INFO)
26
35
  PrettyOutput.print("\n2. 或者直接设置环境变量:", OutputType.INFO)
27
- PrettyOutput.print(" export OPENAI_API_KEY=your_api_key", OutputType.INFO)
28
- PrettyOutput.print(" export OPENAI_API_BASE=your_api_base", OutputType.INFO)
29
- PrettyOutput.print(" export OPENAI_MODEL_NAME=your_model_name", OutputType.INFO)
36
+ PrettyOutput.print(
37
+ " export OPENAI_API_KEY=your_api_key",
38
+ OutputType.INFO)
39
+ PrettyOutput.print(
40
+ " export OPENAI_API_BASE=your_api_base",
41
+ OutputType.INFO)
42
+ PrettyOutput.print(
43
+ " export OPENAI_MODEL_NAME=your_model_name",
44
+ OutputType.INFO)
30
45
  raise Exception("OPENAI_API_KEY is not set")
31
-
32
- self.base_url = os.getenv("OPENAI_API_BASE", "https://api.deepseek.com")
46
+
47
+ self.base_url = os.getenv(
48
+ "OPENAI_API_BASE",
49
+ "https://api.deepseek.com")
33
50
  self.model_name = os.getenv("OPENAI_MODEL_NAME", "deepseek-chat")
34
51
 
35
52
  PrettyOutput.print(f"当前使用模型: {self.model_name}", OutputType.SYSTEM)
36
-
53
+
37
54
  self.client = OpenAI(
38
55
  api_key=self.api_key,
39
56
  base_url=self.base_url
@@ -48,38 +65,40 @@ class OpenAIModel(BasePlatform):
48
65
  def set_system_message(self, message: str):
49
66
  """设置系统消息"""
50
67
  self.system_message = message
51
- self.messages.append({"role": "system", "content": self.system_message})
68
+ self.messages.append(
69
+ {"role": "system", "content": self.system_message})
52
70
 
53
71
  def chat(self, message: str) -> str:
54
72
  """执行对话"""
55
73
  try:
56
74
  PrettyOutput.print("发送请求...", OutputType.PROGRESS)
57
-
75
+
58
76
  # 添加用户消息到历史记录
59
77
  self.messages.append({"role": "user", "content": message})
60
-
78
+
61
79
  response = self.client.chat.completions.create(
62
80
  model=self.model_name, # 使用配置的模型名称
63
81
  messages=self.messages,
64
82
  stream=True
65
83
  )
66
-
84
+
67
85
  PrettyOutput.print("接收响应...", OutputType.PROGRESS)
68
86
  full_response = ""
69
-
87
+
70
88
  for chunk in response:
71
89
  if chunk.choices[0].delta.content:
72
90
  text = chunk.choices[0].delta.content
73
91
  PrettyOutput.print_stream(text)
74
92
  full_response += text
75
-
93
+
76
94
  PrettyOutput.print_stream_end()
77
-
95
+
78
96
  # 添加助手回复到历史记录
79
- self.messages.append({"role": "assistant", "content": full_response})
80
-
97
+ self.messages.append(
98
+ {"role": "assistant", "content": full_response})
99
+
81
100
  return full_response
82
-
101
+
83
102
  except Exception as e:
84
103
  PrettyOutput.print(f"对话失败: {str(e)}", OutputType.ERROR)
85
104
  raise Exception(f"Chat failed: {str(e)}")
@@ -92,11 +111,12 @@ class OpenAIModel(BasePlatform):
92
111
  """重置模型状态"""
93
112
  # 清空对话历史,只保留system message
94
113
  if self.system_message:
95
- self.messages = [{"role": "system", "content": self.system_message}]
114
+ self.messages = [
115
+ {"role": "system", "content": self.system_message}]
96
116
  else:
97
117
  self.messages = []
98
118
 
99
- def delete_chat(self)->bool:
119
+ def delete_chat(self) -> bool:
100
120
  """删除对话"""
101
121
  self.reset()
102
122
  return True