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.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +1143 -245
- jarvis/jarvis_agent/agent_manager.py +97 -0
- jarvis/jarvis_agent/builtin_input_handler.py +12 -10
- jarvis/jarvis_agent/config_editor.py +57 -0
- jarvis/jarvis_agent/edit_file_handler.py +392 -99
- jarvis/jarvis_agent/event_bus.py +48 -0
- jarvis/jarvis_agent/events.py +157 -0
- jarvis/jarvis_agent/file_context_handler.py +79 -0
- jarvis/jarvis_agent/file_methodology_manager.py +117 -0
- jarvis/jarvis_agent/jarvis.py +1117 -147
- jarvis/jarvis_agent/main.py +78 -34
- jarvis/jarvis_agent/memory_manager.py +195 -0
- jarvis/jarvis_agent/methodology_share_manager.py +174 -0
- jarvis/jarvis_agent/prompt_manager.py +82 -0
- jarvis/jarvis_agent/prompts.py +46 -9
- jarvis/jarvis_agent/protocols.py +4 -1
- jarvis/jarvis_agent/rewrite_file_handler.py +141 -0
- jarvis/jarvis_agent/run_loop.py +146 -0
- jarvis/jarvis_agent/session_manager.py +9 -9
- jarvis/jarvis_agent/share_manager.py +228 -0
- jarvis/jarvis_agent/shell_input_handler.py +23 -3
- jarvis/jarvis_agent/stdio_redirect.py +295 -0
- jarvis/jarvis_agent/task_analyzer.py +212 -0
- jarvis/jarvis_agent/task_manager.py +154 -0
- jarvis/jarvis_agent/task_planner.py +496 -0
- jarvis/jarvis_agent/tool_executor.py +8 -4
- jarvis/jarvis_agent/tool_share_manager.py +139 -0
- jarvis/jarvis_agent/user_interaction.py +42 -0
- jarvis/jarvis_agent/utils.py +54 -0
- jarvis/jarvis_agent/web_bridge.py +189 -0
- jarvis/jarvis_agent/web_output_sink.py +53 -0
- jarvis/jarvis_agent/web_server.py +751 -0
- jarvis/jarvis_c2rust/__init__.py +26 -0
- jarvis/jarvis_c2rust/cli.py +613 -0
- jarvis/jarvis_c2rust/collector.py +258 -0
- jarvis/jarvis_c2rust/library_replacer.py +1122 -0
- jarvis/jarvis_c2rust/llm_module_agent.py +1300 -0
- jarvis/jarvis_c2rust/optimizer.py +960 -0
- jarvis/jarvis_c2rust/scanner.py +1681 -0
- jarvis/jarvis_c2rust/transpiler.py +2325 -0
- jarvis/jarvis_code_agent/build_validation_config.py +133 -0
- jarvis/jarvis_code_agent/code_agent.py +1605 -178
- jarvis/jarvis_code_agent/code_analyzer/__init__.py +62 -0
- jarvis/jarvis_code_agent/code_analyzer/base_language.py +74 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +44 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +102 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +59 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +125 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +69 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +38 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +44 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +38 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +50 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +93 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +129 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +54 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +154 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator.py +43 -0
- jarvis/jarvis_code_agent/code_analyzer/context_manager.py +363 -0
- jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +18 -0
- jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +132 -0
- jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +330 -0
- jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +781 -0
- jarvis/jarvis_code_agent/code_analyzer/language_registry.py +185 -0
- jarvis/jarvis_code_agent/code_analyzer/language_support.py +89 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +31 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +231 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +183 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +219 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +209 -0
- jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +451 -0
- jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +77 -0
- jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +48 -0
- jarvis/jarvis_code_agent/lint.py +275 -13
- jarvis/jarvis_code_agent/utils.py +142 -0
- jarvis/jarvis_code_analysis/checklists/loader.py +20 -6
- jarvis/jarvis_code_analysis/code_review.py +583 -548
- jarvis/jarvis_data/config_schema.json +339 -28
- jarvis/jarvis_git_squash/main.py +22 -13
- jarvis/jarvis_git_utils/git_commiter.py +171 -55
- jarvis/jarvis_mcp/sse_mcp_client.py +22 -15
- jarvis/jarvis_mcp/stdio_mcp_client.py +4 -4
- jarvis/jarvis_mcp/streamable_mcp_client.py +36 -16
- jarvis/jarvis_memory_organizer/memory_organizer.py +753 -0
- jarvis/jarvis_methodology/main.py +48 -63
- jarvis/jarvis_multi_agent/__init__.py +302 -43
- jarvis/jarvis_multi_agent/main.py +70 -24
- jarvis/jarvis_platform/ai8.py +40 -23
- jarvis/jarvis_platform/base.py +210 -49
- jarvis/jarvis_platform/human.py +11 -1
- jarvis/jarvis_platform/kimi.py +82 -76
- jarvis/jarvis_platform/openai.py +73 -1
- jarvis/jarvis_platform/registry.py +8 -15
- jarvis/jarvis_platform/tongyi.py +115 -101
- jarvis/jarvis_platform/yuanbao.py +89 -63
- jarvis/jarvis_platform_manager/main.py +194 -132
- jarvis/jarvis_platform_manager/service.py +122 -86
- jarvis/jarvis_rag/cli.py +156 -53
- jarvis/jarvis_rag/embedding_manager.py +155 -12
- jarvis/jarvis_rag/llm_interface.py +10 -13
- jarvis/jarvis_rag/query_rewriter.py +63 -12
- jarvis/jarvis_rag/rag_pipeline.py +222 -40
- jarvis/jarvis_rag/reranker.py +26 -3
- jarvis/jarvis_rag/retriever.py +270 -14
- jarvis/jarvis_sec/__init__.py +3605 -0
- jarvis/jarvis_sec/checkers/__init__.py +32 -0
- jarvis/jarvis_sec/checkers/c_checker.py +2680 -0
- jarvis/jarvis_sec/checkers/rust_checker.py +1108 -0
- jarvis/jarvis_sec/cli.py +116 -0
- jarvis/jarvis_sec/report.py +257 -0
- jarvis/jarvis_sec/status.py +264 -0
- jarvis/jarvis_sec/types.py +20 -0
- jarvis/jarvis_sec/workflow.py +219 -0
- jarvis/jarvis_smart_shell/main.py +405 -137
- jarvis/jarvis_stats/__init__.py +13 -0
- jarvis/jarvis_stats/cli.py +387 -0
- jarvis/jarvis_stats/stats.py +711 -0
- jarvis/jarvis_stats/storage.py +612 -0
- jarvis/jarvis_stats/visualizer.py +282 -0
- jarvis/jarvis_tools/ask_user.py +1 -0
- jarvis/jarvis_tools/base.py +18 -2
- jarvis/jarvis_tools/clear_memory.py +239 -0
- jarvis/jarvis_tools/cli/main.py +220 -144
- jarvis/jarvis_tools/execute_script.py +52 -12
- jarvis/jarvis_tools/file_analyzer.py +17 -12
- jarvis/jarvis_tools/generate_new_tool.py +46 -24
- jarvis/jarvis_tools/read_code.py +277 -18
- jarvis/jarvis_tools/read_symbols.py +141 -0
- jarvis/jarvis_tools/read_webpage.py +86 -13
- jarvis/jarvis_tools/registry.py +294 -90
- jarvis/jarvis_tools/retrieve_memory.py +227 -0
- jarvis/jarvis_tools/save_memory.py +194 -0
- jarvis/jarvis_tools/search_web.py +62 -28
- jarvis/jarvis_tools/sub_agent.py +205 -0
- jarvis/jarvis_tools/sub_code_agent.py +217 -0
- jarvis/jarvis_tools/virtual_tty.py +330 -62
- jarvis/jarvis_utils/builtin_replace_map.py +4 -5
- jarvis/jarvis_utils/clipboard.py +90 -0
- jarvis/jarvis_utils/config.py +607 -50
- jarvis/jarvis_utils/embedding.py +3 -0
- jarvis/jarvis_utils/fzf.py +57 -0
- jarvis/jarvis_utils/git_utils.py +251 -29
- jarvis/jarvis_utils/globals.py +174 -17
- jarvis/jarvis_utils/http.py +58 -79
- jarvis/jarvis_utils/input.py +899 -153
- jarvis/jarvis_utils/methodology.py +210 -83
- jarvis/jarvis_utils/output.py +220 -137
- jarvis/jarvis_utils/utils.py +1906 -135
- jarvis_ai_assistant-0.7.0.dist-info/METADATA +465 -0
- jarvis_ai_assistant-0.7.0.dist-info/RECORD +192 -0
- {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/entry_points.txt +8 -2
- jarvis/jarvis_git_details/main.py +0 -265
- jarvis/jarvis_platform/oyi.py +0 -357
- jarvis/jarvis_tools/edit_file.py +0 -255
- jarvis/jarvis_tools/rewrite_file.py +0 -195
- jarvis_ai_assistant-0.1.222.dist-info/METADATA +0 -767
- jarvis_ai_assistant-0.1.222.dist-info/RECORD +0 -110
- /jarvis/{jarvis_git_details → jarvis_memory_organizer}/__init__.py +0 -0
- {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/top_level.txt +0 -0
jarvis/jarvis_platform/tongyi.py
CHANGED
|
@@ -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":
|
|
87
|
-
"deepResearch":
|
|
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":
|
|
104
|
-
"deepResearch":
|
|
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":
|
|
149
|
-
"deepResearch":
|
|
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
|
|
175
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
136
|
+
log_lines: List[str] = []
|
|
137
|
+
log_lines.append(f"上传文件 {file_name}")
|
|
137
138
|
try:
|
|
138
139
|
# 1. Prepare the file information
|
|
139
|
-
|
|
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
|
-
|
|
195
|
+
log_lines.append(f"获取上传信息: {file_name}")
|
|
195
196
|
upload_info = self._generate_upload_info(file_name)
|
|
196
197
|
if not upload_info:
|
|
197
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
229
|
+
log_lines.append(f"无法获取图片 {file_name} 的尺寸: {str(e)}")
|
|
227
230
|
|
|
228
231
|
uploaded_files.append(file_metadata)
|
|
229
|
-
|
|
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
|
-
|
|
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"
|
|
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
|
|
481
|
-
|
|
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
|
|
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
|
+
}
|