jarvis-ai-assistant 0.1.222__py3-none-any.whl → 0.7.0__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.
Files changed (162) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +1143 -245
  3. jarvis/jarvis_agent/agent_manager.py +97 -0
  4. jarvis/jarvis_agent/builtin_input_handler.py +12 -10
  5. jarvis/jarvis_agent/config_editor.py +57 -0
  6. jarvis/jarvis_agent/edit_file_handler.py +392 -99
  7. jarvis/jarvis_agent/event_bus.py +48 -0
  8. jarvis/jarvis_agent/events.py +157 -0
  9. jarvis/jarvis_agent/file_context_handler.py +79 -0
  10. jarvis/jarvis_agent/file_methodology_manager.py +117 -0
  11. jarvis/jarvis_agent/jarvis.py +1117 -147
  12. jarvis/jarvis_agent/main.py +78 -34
  13. jarvis/jarvis_agent/memory_manager.py +195 -0
  14. jarvis/jarvis_agent/methodology_share_manager.py +174 -0
  15. jarvis/jarvis_agent/prompt_manager.py +82 -0
  16. jarvis/jarvis_agent/prompts.py +46 -9
  17. jarvis/jarvis_agent/protocols.py +4 -1
  18. jarvis/jarvis_agent/rewrite_file_handler.py +141 -0
  19. jarvis/jarvis_agent/run_loop.py +146 -0
  20. jarvis/jarvis_agent/session_manager.py +9 -9
  21. jarvis/jarvis_agent/share_manager.py +228 -0
  22. jarvis/jarvis_agent/shell_input_handler.py +23 -3
  23. jarvis/jarvis_agent/stdio_redirect.py +295 -0
  24. jarvis/jarvis_agent/task_analyzer.py +212 -0
  25. jarvis/jarvis_agent/task_manager.py +154 -0
  26. jarvis/jarvis_agent/task_planner.py +496 -0
  27. jarvis/jarvis_agent/tool_executor.py +8 -4
  28. jarvis/jarvis_agent/tool_share_manager.py +139 -0
  29. jarvis/jarvis_agent/user_interaction.py +42 -0
  30. jarvis/jarvis_agent/utils.py +54 -0
  31. jarvis/jarvis_agent/web_bridge.py +189 -0
  32. jarvis/jarvis_agent/web_output_sink.py +53 -0
  33. jarvis/jarvis_agent/web_server.py +751 -0
  34. jarvis/jarvis_c2rust/__init__.py +26 -0
  35. jarvis/jarvis_c2rust/cli.py +613 -0
  36. jarvis/jarvis_c2rust/collector.py +258 -0
  37. jarvis/jarvis_c2rust/library_replacer.py +1122 -0
  38. jarvis/jarvis_c2rust/llm_module_agent.py +1300 -0
  39. jarvis/jarvis_c2rust/optimizer.py +960 -0
  40. jarvis/jarvis_c2rust/scanner.py +1681 -0
  41. jarvis/jarvis_c2rust/transpiler.py +2325 -0
  42. jarvis/jarvis_code_agent/build_validation_config.py +133 -0
  43. jarvis/jarvis_code_agent/code_agent.py +1605 -178
  44. jarvis/jarvis_code_agent/code_analyzer/__init__.py +62 -0
  45. jarvis/jarvis_code_agent/code_analyzer/base_language.py +74 -0
  46. jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +44 -0
  47. jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +102 -0
  48. jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +59 -0
  49. jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +125 -0
  50. jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +69 -0
  51. jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +38 -0
  52. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +44 -0
  53. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +38 -0
  54. jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +50 -0
  55. jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +93 -0
  56. jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +129 -0
  57. jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +54 -0
  58. jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +154 -0
  59. jarvis/jarvis_code_agent/code_analyzer/build_validator.py +43 -0
  60. jarvis/jarvis_code_agent/code_analyzer/context_manager.py +363 -0
  61. jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +18 -0
  62. jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +132 -0
  63. jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +330 -0
  64. jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +781 -0
  65. jarvis/jarvis_code_agent/code_analyzer/language_registry.py +185 -0
  66. jarvis/jarvis_code_agent/code_analyzer/language_support.py +89 -0
  67. jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +31 -0
  68. jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +231 -0
  69. jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +183 -0
  70. jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +219 -0
  71. jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +209 -0
  72. jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +451 -0
  73. jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +77 -0
  74. jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +48 -0
  75. jarvis/jarvis_code_agent/lint.py +275 -13
  76. jarvis/jarvis_code_agent/utils.py +142 -0
  77. jarvis/jarvis_code_analysis/checklists/loader.py +20 -6
  78. jarvis/jarvis_code_analysis/code_review.py +583 -548
  79. jarvis/jarvis_data/config_schema.json +339 -28
  80. jarvis/jarvis_git_squash/main.py +22 -13
  81. jarvis/jarvis_git_utils/git_commiter.py +171 -55
  82. jarvis/jarvis_mcp/sse_mcp_client.py +22 -15
  83. jarvis/jarvis_mcp/stdio_mcp_client.py +4 -4
  84. jarvis/jarvis_mcp/streamable_mcp_client.py +36 -16
  85. jarvis/jarvis_memory_organizer/memory_organizer.py +753 -0
  86. jarvis/jarvis_methodology/main.py +48 -63
  87. jarvis/jarvis_multi_agent/__init__.py +302 -43
  88. jarvis/jarvis_multi_agent/main.py +70 -24
  89. jarvis/jarvis_platform/ai8.py +40 -23
  90. jarvis/jarvis_platform/base.py +210 -49
  91. jarvis/jarvis_platform/human.py +11 -1
  92. jarvis/jarvis_platform/kimi.py +82 -76
  93. jarvis/jarvis_platform/openai.py +73 -1
  94. jarvis/jarvis_platform/registry.py +8 -15
  95. jarvis/jarvis_platform/tongyi.py +115 -101
  96. jarvis/jarvis_platform/yuanbao.py +89 -63
  97. jarvis/jarvis_platform_manager/main.py +194 -132
  98. jarvis/jarvis_platform_manager/service.py +122 -86
  99. jarvis/jarvis_rag/cli.py +156 -53
  100. jarvis/jarvis_rag/embedding_manager.py +155 -12
  101. jarvis/jarvis_rag/llm_interface.py +10 -13
  102. jarvis/jarvis_rag/query_rewriter.py +63 -12
  103. jarvis/jarvis_rag/rag_pipeline.py +222 -40
  104. jarvis/jarvis_rag/reranker.py +26 -3
  105. jarvis/jarvis_rag/retriever.py +270 -14
  106. jarvis/jarvis_sec/__init__.py +3605 -0
  107. jarvis/jarvis_sec/checkers/__init__.py +32 -0
  108. jarvis/jarvis_sec/checkers/c_checker.py +2680 -0
  109. jarvis/jarvis_sec/checkers/rust_checker.py +1108 -0
  110. jarvis/jarvis_sec/cli.py +116 -0
  111. jarvis/jarvis_sec/report.py +257 -0
  112. jarvis/jarvis_sec/status.py +264 -0
  113. jarvis/jarvis_sec/types.py +20 -0
  114. jarvis/jarvis_sec/workflow.py +219 -0
  115. jarvis/jarvis_smart_shell/main.py +405 -137
  116. jarvis/jarvis_stats/__init__.py +13 -0
  117. jarvis/jarvis_stats/cli.py +387 -0
  118. jarvis/jarvis_stats/stats.py +711 -0
  119. jarvis/jarvis_stats/storage.py +612 -0
  120. jarvis/jarvis_stats/visualizer.py +282 -0
  121. jarvis/jarvis_tools/ask_user.py +1 -0
  122. jarvis/jarvis_tools/base.py +18 -2
  123. jarvis/jarvis_tools/clear_memory.py +239 -0
  124. jarvis/jarvis_tools/cli/main.py +220 -144
  125. jarvis/jarvis_tools/execute_script.py +52 -12
  126. jarvis/jarvis_tools/file_analyzer.py +17 -12
  127. jarvis/jarvis_tools/generate_new_tool.py +46 -24
  128. jarvis/jarvis_tools/read_code.py +277 -18
  129. jarvis/jarvis_tools/read_symbols.py +141 -0
  130. jarvis/jarvis_tools/read_webpage.py +86 -13
  131. jarvis/jarvis_tools/registry.py +294 -90
  132. jarvis/jarvis_tools/retrieve_memory.py +227 -0
  133. jarvis/jarvis_tools/save_memory.py +194 -0
  134. jarvis/jarvis_tools/search_web.py +62 -28
  135. jarvis/jarvis_tools/sub_agent.py +205 -0
  136. jarvis/jarvis_tools/sub_code_agent.py +217 -0
  137. jarvis/jarvis_tools/virtual_tty.py +330 -62
  138. jarvis/jarvis_utils/builtin_replace_map.py +4 -5
  139. jarvis/jarvis_utils/clipboard.py +90 -0
  140. jarvis/jarvis_utils/config.py +607 -50
  141. jarvis/jarvis_utils/embedding.py +3 -0
  142. jarvis/jarvis_utils/fzf.py +57 -0
  143. jarvis/jarvis_utils/git_utils.py +251 -29
  144. jarvis/jarvis_utils/globals.py +174 -17
  145. jarvis/jarvis_utils/http.py +58 -79
  146. jarvis/jarvis_utils/input.py +899 -153
  147. jarvis/jarvis_utils/methodology.py +210 -83
  148. jarvis/jarvis_utils/output.py +220 -137
  149. jarvis/jarvis_utils/utils.py +1906 -135
  150. jarvis_ai_assistant-0.7.0.dist-info/METADATA +465 -0
  151. jarvis_ai_assistant-0.7.0.dist-info/RECORD +192 -0
  152. {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/entry_points.txt +8 -2
  153. jarvis/jarvis_git_details/main.py +0 -265
  154. jarvis/jarvis_platform/oyi.py +0 -357
  155. jarvis/jarvis_tools/edit_file.py +0 -255
  156. jarvis/jarvis_tools/rewrite_file.py +0 -195
  157. jarvis_ai_assistant-0.1.222.dist-info/METADATA +0 -767
  158. jarvis_ai_assistant-0.1.222.dist-info/RECORD +0 -110
  159. /jarvis/{jarvis_git_details → jarvis_memory_organizer}/__init__.py +0 -0
  160. {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/WHEEL +0 -0
  161. {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/licenses/LICENSE +0 -0
  162. {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/top_level.txt +0 -0
@@ -8,6 +8,7 @@ from typing import Any, Dict, Generator, List, Tuple
8
8
  from jarvis.jarvis_platform.base import BasePlatform
9
9
  from jarvis.jarvis_utils import http
10
10
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
11
+ from jarvis.jarvis_utils.tag import ot, ct
11
12
  from jarvis.jarvis_utils.utils import while_success
12
13
 
13
14
 
@@ -81,10 +82,10 @@ class TongyiPlatform(BasePlatform):
81
82
  "contentType": "text",
82
83
  "role": "user",
83
84
  "ext": {
84
- "searchType": "",
85
+ "searchType": "depth" if self.web else "",
85
86
  "pptGenerate": False,
86
- "deepThink": False,
87
- "deepResearch": False,
87
+ "deepThink": self.model_name == "Thinking",
88
+ "deepResearch": self.model_name == "Deep-Research",
88
89
  },
89
90
  }
90
91
  ]
@@ -98,10 +99,10 @@ class TongyiPlatform(BasePlatform):
98
99
  "contentType": "text",
99
100
  "role": "system",
100
101
  "ext": {
101
- "searchType": "",
102
+ "searchType": "depth" if self.web else "",
102
103
  "pptGenerate": False,
103
- "deepThink": False,
104
- "deepResearch": False,
104
+ "deepThink": self.model_name == "Thinking",
105
+ "deepResearch": self.model_name == "Deep-Research",
105
106
  },
106
107
  },
107
108
  )
@@ -140,13 +141,13 @@ class TongyiPlatform(BasePlatform):
140
141
  "parentMsgId": self.msg_id,
141
142
  "params": {
142
143
  "agentId": "",
143
- "searchType": "",
144
+ "searchType": "depth" if self.web else "",
144
145
  "pptGenerate": False,
145
146
  "bizScene": "code_chat" if self.model_name == "Code-Chat" else "",
146
147
  "bizSceneInfo": {},
147
148
  "specifiedModel": "",
148
- "deepThink": True if self.model_name == "Thinking" else False,
149
- "deepResearch": False,
149
+ "deepThink": self.model_name == "Thinking",
150
+ "deepResearch": self.model_name == "Deep-Research",
150
151
  "fileUploadBatchId": (
151
152
  self.uploaded_file_info[0]["batchId"]
152
153
  if self.uploaded_file_info
@@ -168,88 +169,68 @@ class TongyiPlatform(BasePlatform):
168
169
  thinking_content = ""
169
170
  text_content = ""
170
171
  in_thinking = False
171
- response_data = b""
172
172
 
173
173
  # 处理流式响应
174
- for chunk in response_stream:
175
- response_data += chunk
176
-
177
- # 尝试解析SSE格式的数据
178
- try:
179
- # 查找完整的数据行
180
- lines = response_data.decode("utf-8").split("\n")
181
- response_data = b"" # 重置缓冲区
182
-
183
- for line in lines:
184
- if not line.strip():
185
- continue
186
-
187
- # SSE格式的行通常以"data: "开头
188
- if line.startswith("data: "):
189
- try:
190
- data = json.loads(line[6:])
191
- # 记录消息ID和会话ID
192
- if "msgId" in data:
193
- msg_id = data["msgId"]
194
- if "sessionId" in data:
195
- session_id = data["sessionId"]
196
-
197
- if "contents" in data and len(data["contents"]) > 0:
198
- for content in data["contents"]:
199
- if content.get("contentType") == "think":
200
- if not in_thinking:
201
- yield "<think>\n\n"
202
- in_thinking = True
203
- if content.get("incremental"):
204
- tmp_content = json.loads(
205
- content.get("content")
206
- )["content"]
207
- thinking_content += tmp_content
208
- yield tmp_content
209
- else:
210
- tmp_content = json.loads(
211
- content.get("content")
212
- )["content"]
213
- if len(thinking_content) < len(
214
- tmp_content
215
- ):
216
- yield tmp_content[
217
- len(thinking_content) :
218
- ]
219
- thinking_content = tmp_content
220
- else:
221
- yield "\r\n</think>\n"[
222
- len(thinking_content)
223
- - len(tmp_content) :
224
- ]
225
- thinking_content = tmp_content
226
- in_thinking = False
227
- elif content.get("contentType") == "text":
228
- if in_thinking:
229
- continue
230
- if content.get("incremental"):
231
- tmp_content = content.get("content")
232
- text_content += tmp_content
233
- yield tmp_content
234
- else:
235
- tmp_content = content.get("content")
236
- if len(text_content) < len(tmp_content):
237
- yield tmp_content[
238
- len(text_content) :
239
- ]
240
- text_content = tmp_content
241
-
242
- except json.JSONDecodeError:
243
- continue
244
-
245
- except UnicodeDecodeError:
246
- # 如果解码失败,继续累积数据
174
+ for line in response_stream:
175
+ if not line.strip():
247
176
  continue
248
177
 
178
+ # SSE格式的行通常以"data: "开头
179
+ if line.startswith("data: "):
180
+ try:
181
+ data = json.loads(line[6:])
182
+ # 记录消息ID和会话ID
183
+ if "msgId" in data:
184
+ msg_id = data["msgId"]
185
+ if "sessionId" in data:
186
+ session_id = data["sessionId"]
187
+
188
+ if "contents" in data and len(data["contents"]) > 0:
189
+ for content in data["contents"]:
190
+ if content.get("contentType") == "think":
191
+ if not in_thinking:
192
+ yield f"{ot('think')}\n\n"
193
+ in_thinking = True
194
+ if content.get("incremental"):
195
+ tmp_content = json.loads(
196
+ content.get("content")
197
+ )["content"]
198
+ thinking_content += tmp_content
199
+ yield tmp_content
200
+ else:
201
+ tmp_content = json.loads(
202
+ content.get("content")
203
+ )["content"]
204
+ if len(thinking_content) < len(tmp_content):
205
+ yield tmp_content[len(thinking_content) :]
206
+ thinking_content = tmp_content
207
+ else:
208
+ yield f"\r\n{ct('think')}\n"[
209
+ len(thinking_content)
210
+ - len(tmp_content) :
211
+ ]
212
+ thinking_content = tmp_content
213
+ in_thinking = False
214
+ elif content.get("contentType") == "text":
215
+ if in_thinking:
216
+ continue
217
+ if content.get("incremental"):
218
+ tmp_content = content.get("content")
219
+ text_content += tmp_content
220
+ yield tmp_content
221
+ else:
222
+ tmp_content = content.get("content")
223
+ if len(text_content) < len(tmp_content):
224
+ yield tmp_content[len(text_content) :]
225
+ text_content = tmp_content
226
+
227
+ except json.JSONDecodeError:
228
+ continue
229
+
249
230
  self.msg_id = msg_id
250
231
  self.session_id = session_id
251
232
 
252
- return None
233
+ return
253
234
 
254
235
  except Exception as e:
255
236
  raise Exception(f"Chat failed: {str(e)}")
@@ -295,16 +276,19 @@ class TongyiPlatform(BasePlatform):
295
276
 
296
277
  for file_path in file_list:
297
278
  file_name = os.path.basename(file_path)
298
- print(f"🔍 上传文件 {file_name}")
279
+ log_lines: List[str] = []
280
+ log_lines.append(f"上传文件 {file_name}")
299
281
  try:
300
282
  if not os.path.exists(file_path):
301
- print(f"❌ 文件不存在: {file_path}")
283
+ # 先输出已收集的日志与错误后返回
284
+ log_lines.append(f"文件不存在: {file_path}")
285
+ PrettyOutput.print("\n".join(log_lines), OutputType.ERROR)
302
286
  return False
303
287
 
304
288
  # Get file name and content type
305
289
  content_type = self._get_content_type(file_path)
306
290
 
307
- print(f"🔍 准备上传文件: {file_name}")
291
+ log_lines.append(f"准备上传文件: {file_name}")
308
292
 
309
293
  # Prepare form data
310
294
  form_data = {
@@ -319,7 +303,7 @@ class TongyiPlatform(BasePlatform):
319
303
  # Prepare files
320
304
  files = {"file": (file_name, open(file_path, "rb"), content_type)}
321
305
 
322
- print(f"📤 正在上传文件: {file_name}")
306
+ log_lines.append(f"正在上传文件: {file_name}")
323
307
 
324
308
  # Upload file
325
309
  response = http.post(
@@ -327,7 +311,8 @@ class TongyiPlatform(BasePlatform):
327
311
  )
328
312
 
329
313
  if response.status_code != 200:
330
- print(f"上传失败 {file_name}: HTTP {response.status_code}")
314
+ log_lines.append(f"上传失败 {file_name}: HTTP {response.status_code}")
315
+ PrettyOutput.print("\n".join(log_lines), OutputType.ERROR)
331
316
  return False
332
317
 
333
318
  # Determine file type based on extension
@@ -342,7 +327,7 @@ class TongyiPlatform(BasePlatform):
342
327
  }
343
328
  )
344
329
 
345
- print(f"🔍 获取下载链接: {file_name}")
330
+ log_lines.append(f"获取下载链接: {file_name}")
346
331
 
347
332
  # Get download links for uploaded files
348
333
  url = "https://api.tongyi.com/dialog/downloadLink/batch"
@@ -359,18 +344,20 @@ class TongyiPlatform(BasePlatform):
359
344
 
360
345
  response = http.post(url, headers=headers, json=payload)
361
346
  if response.status_code != 200:
362
- print(f"获取下载链接失败: HTTP {response.status_code}")
347
+ log_lines.append(f"获取下载链接失败: HTTP {response.status_code}")
348
+ PrettyOutput.print("\n".join(log_lines), OutputType.ERROR)
363
349
  return False
364
350
 
365
351
  result = response.json()
366
352
  if not result.get("success"):
367
- print(f"获取下载链接失败: {result.get('errorMsg')}")
353
+ log_lines.append(f"获取下载链接失败: {result.get('errorMsg')}")
354
+ PrettyOutput.print("\n".join(log_lines), OutputType.ERROR)
368
355
  return False
369
356
 
370
357
  # Add files to chat
371
358
  self.uploaded_file_info = result.get("data", {}).get("results", [])
372
359
  for file_info in self.uploaded_file_info:
373
- print(f"🔍 添加文件到对话: {file_name}")
360
+ log_lines.append(f"添加文件到对话: {file_name}")
374
361
  add_url = "https://api.tongyi.com/assistant/api/chat/file/add"
375
362
  add_payload = {
376
363
  "workSource": "chat",
@@ -393,25 +380,23 @@ class TongyiPlatform(BasePlatform):
393
380
  add_url, headers=headers, json=add_payload
394
381
  )
395
382
  if add_response.status_code != 200:
396
- print(
397
- f"❌ 添加文件到对话失败: HTTP {add_response.status_code}"
398
- )
383
+ log_lines.append(f"添加文件到对话失败: HTTP {add_response.status_code}")
399
384
  continue
400
385
 
401
386
  add_result = add_response.json()
402
387
  if not add_result.get("success"):
403
- print(
404
- f"❌ 添加文件到对话失败: {add_result.get('errorMsg')}"
405
- )
388
+ log_lines.append(f"添加文件到对话失败: {add_result.get('errorMsg')}")
406
389
  continue
407
390
 
408
391
  file_info.update(add_result.get("data", {}))
409
392
 
410
- print(f"文件 {file_name} 上传成功")
393
+ log_lines.append(f"文件 {file_name} 上传成功")
394
+ PrettyOutput.print("\n".join(log_lines), OutputType.INFO)
411
395
  time.sleep(1) # 短暂暂停以便用户看到成功状态
412
396
 
413
397
  except Exception as e:
414
- print(f"上传文件 {file_name} 时出错: {str(e)}")
398
+ log_lines.append(f"上传文件 {file_name} 时出错: {str(e)}")
399
+ PrettyOutput.print("\n".join(log_lines), OutputType.ERROR)
415
400
  return False
416
401
  return True
417
402
 
@@ -576,3 +561,32 @@ class TongyiPlatform(BasePlatform):
576
561
  bool: True if web is supported, False otherwise
577
562
  """
578
563
  return True
564
+
565
+ @classmethod
566
+ def get_required_env_keys(cls) -> List[str]:
567
+ """
568
+ 获取通义平台所需的环境变量键列表
569
+
570
+ 返回:
571
+ List[str]: 环境变量键的列表
572
+ """
573
+ return ["TONGYI_COOKIES"]
574
+
575
+ @classmethod
576
+ def get_env_config_guide(cls) -> Dict[str, str]:
577
+ """
578
+ 获取环境变量配置指导
579
+
580
+ 返回:
581
+ Dict[str, str]: 环境变量名到配置指导的映射
582
+ """
583
+ return {
584
+ "TONGYI_COOKIES": (
585
+ "1. 登录通义千问网页版: https://tongyi.aliyun.com/\n"
586
+ "2. 打开浏览器开发者工具 (F12)\n"
587
+ '3. 切换到"网络"(Network)标签页\n'
588
+ "4. 刷新页面或发送一条消息\n"
589
+ "5. 找到 conversation 请求或任意发往 api.tongyi.com 的请求\n"
590
+ '6. 在"请求标头"中复制完整的 Cookie 值'
591
+ )
592
+ }
@@ -12,6 +12,7 @@ from PIL import Image # type: ignore
12
12
  from jarvis.jarvis_platform.base import BasePlatform
13
13
  from jarvis.jarvis_utils import http
14
14
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
15
+ from jarvis.jarvis_utils.tag import ot, ct
15
16
  from jarvis.jarvis_utils.utils import while_success
16
17
 
17
18
 
@@ -68,7 +69,6 @@ class YuanbaoPlatform(BasePlatform):
68
69
  "X-Requested-With": "XMLHttpRequest",
69
70
  "chat_version": "v1",
70
71
  "X-Instance-ID": "5",
71
- "X-Requested-With": "XMLHttpRequest",
72
72
  "Accept": "application/json, text/plain, */*",
73
73
  "Content-Type": "application/json",
74
74
  "sec-ch-ua-mobile": "?0",
@@ -77,7 +77,7 @@ class YuanbaoPlatform(BasePlatform):
77
77
  "Referer": f"https://yuanbao.tencent.com/chat/{self.agent_id}",
78
78
  "X-Source": "web",
79
79
  "Accept-Encoding": "gzip, deflate, br, zstd",
80
- "Accept": "*/*",
80
+
81
81
  "Sec-Fetch-Site": "same-origin",
82
82
  "Sec-Fetch-Mode": "cors",
83
83
  "Sec-Fetch-Dest": "empty",
@@ -133,10 +133,11 @@ class YuanbaoPlatform(BasePlatform):
133
133
 
134
134
  for file_path in file_list:
135
135
  file_name = os.path.basename(file_path)
136
- print(f"🔍 上传文件 {file_name}")
136
+ log_lines: List[str] = []
137
+ log_lines.append(f"上传文件 {file_name}")
137
138
  try:
138
139
  # 1. Prepare the file information
139
- print(f"🔍 准备文件信息: {file_name}")
140
+ log_lines.append(f"准备文件信息: {file_name}")
140
141
  file_size = os.path.getsize(file_path)
141
142
  file_extension = os.path.splitext(file_path)[1].lower().lstrip(".")
142
143
 
@@ -191,21 +192,23 @@ class YuanbaoPlatform(BasePlatform):
191
192
  file_type = "code"
192
193
 
193
194
  # 2. Generate upload information
194
- print(f"🔍 获取上传信息: {file_name}")
195
+ log_lines.append(f"获取上传信息: {file_name}")
195
196
  upload_info = self._generate_upload_info(file_name)
196
197
  if not upload_info:
197
- print(f"无法获取文件 {file_name} 的上传信息")
198
+ log_lines.append(f"无法获取文件 {file_name} 的上传信息")
199
+ PrettyOutput.print("\n".join(log_lines), OutputType.ERROR)
198
200
  return False
199
201
 
200
202
  # 3. Upload the file to COS
201
- print(f"🔍 上传文件到云存储: {file_name}")
203
+ log_lines.append(f"上传文件到云存储: {file_name}")
202
204
  upload_success = self._upload_file_to_cos(file_path, upload_info)
203
205
  if not upload_success:
204
- print(f"上传文件 {file_name} 失败")
206
+ log_lines.append(f"上传文件 {file_name} 失败")
207
+ PrettyOutput.print("\n".join(log_lines), OutputType.ERROR)
205
208
  return False
206
209
 
207
210
  # 4. Create file metadata for chat
208
- print(f"🔍 生成文件元数据: {file_name}")
211
+ log_lines.append(f"生成文件元数据: {file_name}")
209
212
  file_metadata = {
210
213
  "type": file_type,
211
214
  "docType": file_extension if file_extension else file_type,
@@ -223,14 +226,16 @@ class YuanbaoPlatform(BasePlatform):
223
226
  file_metadata["width"] = img.width
224
227
  file_metadata["height"] = img.height
225
228
  except Exception as e:
226
- print(f"⚠️ 无法获取图片 {file_name} 的尺寸: {str(e)}")
229
+ log_lines.append(f"无法获取图片 {file_name} 的尺寸: {str(e)}")
227
230
 
228
231
  uploaded_files.append(file_metadata)
229
- print(f"文件 {file_name} 上传成功")
232
+ log_lines.append(f"文件 {file_name} 上传成功")
233
+ PrettyOutput.print("\n".join(log_lines), OutputType.INFO)
230
234
  time.sleep(3) # 上传成功后等待3秒
231
235
 
232
236
  except Exception as e:
233
- print(f"上传文件 {file_path} 时出错: {str(e)}")
237
+ log_lines.append(f"上传文件 {file_path} 时出错: {str(e)}")
238
+ PrettyOutput.print("\n".join(log_lines), OutputType.ERROR)
234
239
  return False
235
240
 
236
241
  self.multimedia = uploaded_files
@@ -301,7 +306,7 @@ class YuanbaoPlatform(BasePlatform):
301
306
  with open(file_path, "rb") as file:
302
307
  file_content = file.read()
303
308
 
304
- print(f"ℹ️ 上传文件大小: {len(file_content)}")
309
+ PrettyOutput.print(f"上传文件大小: {len(file_content)}", OutputType.INFO)
305
310
 
306
311
  # Prepare headers for PUT request
307
312
  host = f"{upload_info['bucketName']}.{upload_info.get('accelerateDomain', 'cos.accelerate.myqcloud.com')}"
@@ -474,61 +479,54 @@ class YuanbaoPlatform(BasePlatform):
474
479
  )
475
480
 
476
481
  in_thinking = False
477
- response_data = b""
478
482
 
479
483
  # 处理流式响应
480
- for chunk in response_stream:
481
- response_data += chunk
482
-
483
- # 尝试解析SSE格式的数据
484
- try:
485
- # 查找完整的数据行
486
- lines = response_data.decode("utf-8").split("\n")
487
- response_data = b"" # 重置缓冲区
488
-
489
- for line in lines:
490
- if not line.strip():
491
- continue
492
-
493
- # SSE格式的行通常以"data: "开头
494
- if line.startswith("data: "):
495
- try:
496
- data_str = line[6:] # 移除"data: "前缀
497
-
498
- # 检查结束标志
499
- if data_str == "[DONE]":
500
- self.first_chat = False
501
- return None
502
-
503
- data = json.loads(data_str)
504
-
505
- # 处理文本类型的消息
506
- if data.get("type") == "text":
507
- if in_thinking:
508
- yield "</think>\n"
509
- in_thinking = False
510
- msg = data.get("msg", "")
511
- if msg:
512
- yield msg
513
-
514
- # 处理思考中的消息
515
- elif data.get("type") == "think":
516
- if not in_thinking:
517
- yield "<think>\n"
518
- in_thinking = True
519
- think_content = data.get("content", "")
520
- if think_content:
521
- yield think_content
522
-
523
- except json.JSONDecodeError:
524
- pass
525
-
526
- except UnicodeDecodeError:
527
- # 如果解码失败,继续累积数据
484
+ for line in response_stream:
485
+ if not line.strip():
528
486
  continue
529
487
 
488
+ # SSE格式的行通常以"data: "开头
489
+ if line.startswith("data: "):
490
+ try:
491
+ data_str = line[6:] # 移除"data: "前缀
492
+
493
+ # 检查结束标志
494
+ if data_str == "[DONE]":
495
+ self.first_chat = False
496
+ return
497
+
498
+ data = json.loads(data_str)
499
+
500
+ # 处理文本类型的消息
501
+ if data.get("type") == "text":
502
+ if in_thinking:
503
+ yield f"{ct('think')}\n"
504
+ in_thinking = False
505
+ msg = data.get("msg", "")
506
+ if msg:
507
+ yield msg
508
+
509
+ # 处理思考中的消息
510
+ elif data.get("type") == "think":
511
+ if not in_thinking:
512
+ yield f"{ot('think')}\n"
513
+ in_thinking = True
514
+ think_content = data.get("content", "")
515
+ if think_content:
516
+ yield think_content
517
+
518
+ except json.JSONDecodeError:
519
+ pass
520
+ else:
521
+ try:
522
+ data = json.loads(line)
523
+ if "msg" in data:
524
+ yield data["msg"]
525
+ except json.JSONDecodeError:
526
+ pass
527
+
530
528
  self.first_chat = False
531
- return None
529
+ return
532
530
 
533
531
  except Exception as e:
534
532
  raise Exception(f"对话失败: {str(e)}")
@@ -629,3 +627,31 @@ class YuanbaoPlatform(BasePlatform):
629
627
  def support_web(self) -> bool:
630
628
  """Yuanbao平台支持web功能"""
631
629
  return True
630
+
631
+ @classmethod
632
+ def get_required_env_keys(cls) -> List[str]:
633
+ """
634
+ 获取元宝平台所需的环境变量键列表
635
+
636
+ 返回:
637
+ List[str]: 环境变量键的列表
638
+ """
639
+ return ["YUANBAO_COOKIES"]
640
+
641
+ @classmethod
642
+ def get_env_config_guide(cls) -> Dict[str, str]:
643
+ """
644
+ 获取环境变量配置指导
645
+
646
+ 返回:
647
+ Dict[str, str]: 环境变量名到配置指导的映射
648
+ """
649
+ return {
650
+ "YUANBAO_COOKIES": (
651
+ "1. 登录腾讯元宝网页版: https://yuanbao.tencent.com/\n"
652
+ "2. 打开浏览器开发者工具 (F12)\n"
653
+ '3. 切换到"网络"(Network)标签页\n'
654
+ "4. 刷新页面,找到任意一个发往 yuanbao.tencent.com 的请求\n"
655
+ '5. 在"请求标头"中复制完整的 Cookie 值'
656
+ )
657
+ }