jarvis-ai-assistant 0.3.23__py3-none-any.whl → 0.3.24__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 +96 -13
- jarvis/jarvis_agent/agent_manager.py +0 -3
- jarvis/jarvis_agent/jarvis.py +2 -17
- jarvis/jarvis_agent/main.py +2 -8
- jarvis/jarvis_code_agent/code_agent.py +5 -11
- jarvis/jarvis_code_analysis/code_review.py +12 -40
- jarvis/jarvis_data/config_schema.json +4 -18
- jarvis/jarvis_git_utils/git_commiter.py +7 -22
- jarvis/jarvis_mcp/sse_mcp_client.py +4 -3
- jarvis/jarvis_mcp/streamable_mcp_client.py +9 -8
- jarvis/jarvis_memory_organizer/memory_organizer.py +46 -53
- jarvis/jarvis_methodology/main.py +4 -2
- jarvis/jarvis_platform/base.py +49 -12
- jarvis/jarvis_platform/kimi.py +16 -22
- jarvis/jarvis_platform/registry.py +7 -14
- jarvis/jarvis_platform/tongyi.py +21 -32
- jarvis/jarvis_platform/yuanbao.py +15 -17
- jarvis/jarvis_platform_manager/main.py +14 -51
- jarvis/jarvis_rag/cli.py +14 -13
- jarvis/jarvis_rag/embedding_manager.py +18 -6
- jarvis/jarvis_rag/llm_interface.py +0 -2
- jarvis/jarvis_rag/rag_pipeline.py +20 -13
- jarvis/jarvis_rag/retriever.py +21 -23
- jarvis/jarvis_tools/cli/main.py +22 -15
- jarvis/jarvis_tools/file_analyzer.py +12 -6
- jarvis/jarvis_tools/registry.py +13 -10
- jarvis/jarvis_tools/sub_agent.py +1 -1
- jarvis/jarvis_tools/sub_code_agent.py +1 -4
- jarvis/jarvis_utils/config.py +14 -10
- jarvis/jarvis_utils/input.py +6 -3
- jarvis/jarvis_utils/methodology.py +11 -6
- jarvis/jarvis_utils/utils.py +30 -13
- {jarvis_ai_assistant-0.3.23.dist-info → jarvis_ai_assistant-0.3.24.dist-info}/METADATA +10 -3
- {jarvis_ai_assistant-0.3.23.dist-info → jarvis_ai_assistant-0.3.24.dist-info}/RECORD +39 -39
- {jarvis_ai_assistant-0.3.23.dist-info → jarvis_ai_assistant-0.3.24.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.3.23.dist-info → jarvis_ai_assistant-0.3.24.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.3.23.dist-info → jarvis_ai_assistant-0.3.24.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.3.23.dist-info → jarvis_ai_assistant-0.3.24.dist-info}/top_level.txt +0 -0
@@ -20,8 +20,6 @@ from jarvis.jarvis_utils.config import (
|
|
20
20
|
get_data_dir,
|
21
21
|
get_normal_platform_name,
|
22
22
|
get_normal_model_name,
|
23
|
-
get_thinking_platform_name,
|
24
|
-
get_thinking_model_name,
|
25
23
|
)
|
26
24
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
27
25
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
@@ -31,18 +29,14 @@ from jarvis.jarvis_utils.utils import init_env
|
|
31
29
|
class MemoryOrganizer:
|
32
30
|
"""记忆整理器,用于合并具有相似标签的记忆"""
|
33
31
|
|
34
|
-
def __init__(self, llm_group: Optional[str] = None
|
32
|
+
def __init__(self, llm_group: Optional[str] = None):
|
35
33
|
"""初始化记忆整理器"""
|
36
34
|
self.project_memory_dir = Path(".jarvis/memory")
|
37
35
|
self.global_memory_dir = Path(get_data_dir()) / "memory"
|
38
36
|
|
39
|
-
#
|
40
|
-
|
41
|
-
|
42
|
-
model_name_func = get_thinking_model_name
|
43
|
-
else:
|
44
|
-
platform_name_func = get_normal_platform_name
|
45
|
-
model_name_func = get_normal_model_name
|
37
|
+
# 统一使用 normal 平台与模型
|
38
|
+
platform_name_func = get_normal_platform_name
|
39
|
+
model_name_func = get_normal_model_name
|
46
40
|
|
47
41
|
# 确定平台和模型
|
48
42
|
platform_name = platform_name_func(model_group_override=llm_group)
|
@@ -72,6 +66,7 @@ class MemoryOrganizer:
|
|
72
66
|
"""加载指定类型的所有记忆"""
|
73
67
|
memories = []
|
74
68
|
memory_files = self._get_memory_files(memory_type)
|
69
|
+
error_lines: list[str] = []
|
75
70
|
|
76
71
|
for memory_file in memory_files:
|
77
72
|
try:
|
@@ -80,9 +75,10 @@ class MemoryOrganizer:
|
|
80
75
|
memory_data["file_path"] = str(memory_file)
|
81
76
|
memories.append(memory_data)
|
82
77
|
except Exception as e:
|
83
|
-
|
84
|
-
|
85
|
-
|
78
|
+
error_lines.append(f"读取记忆文件 {memory_file} 失败: {str(e)}")
|
79
|
+
|
80
|
+
if error_lines:
|
81
|
+
PrettyOutput.print("\n".join(error_lines), OutputType.WARNING)
|
86
82
|
|
87
83
|
return memories
|
88
84
|
|
@@ -314,16 +310,14 @@ tags:
|
|
314
310
|
|
315
311
|
group_memories = [memories[i] for i in original_indices]
|
316
312
|
|
317
|
-
#
|
318
|
-
|
319
|
-
f"\n准备合并 {len(group_memories)} 个记忆:", OutputType.INFO
|
320
|
-
)
|
313
|
+
# 显示将要合并的记忆(先拼接后统一打印,避免循环逐条输出)
|
314
|
+
lines = [f"", f"准备合并 {len(group_memories)} 个记忆:"]
|
321
315
|
for mem in group_memories:
|
322
|
-
|
316
|
+
lines.append(
|
323
317
|
f" - ID: {mem.get('id', '未知')}, "
|
324
|
-
f"标签: {', '.join(mem.get('tags', []))[:50]}..."
|
325
|
-
OutputType.INFO,
|
318
|
+
f"标签: {', '.join(mem.get('tags', []))[:50]}..."
|
326
319
|
)
|
320
|
+
PrettyOutput.print("\n".join(lines), OutputType.INFO)
|
327
321
|
|
328
322
|
if not dry_run:
|
329
323
|
# 合并记忆
|
@@ -396,27 +390,28 @@ tags:
|
|
396
390
|
OutputType.SUCCESS,
|
397
391
|
)
|
398
392
|
|
399
|
-
#
|
393
|
+
# 删除原始记忆文件(先汇总日志,最后统一打印)
|
394
|
+
info_lines: list[str] = []
|
395
|
+
warn_lines: list[str] = []
|
400
396
|
for orig_memory in original_memories:
|
401
397
|
if "file_path" in orig_memory:
|
402
398
|
try:
|
403
399
|
file_path = Path(orig_memory["file_path"])
|
404
400
|
if file_path.exists():
|
405
401
|
file_path.unlink()
|
406
|
-
|
407
|
-
f"删除原始记忆: {orig_memory.get('id', '未知')}",
|
408
|
-
OutputType.INFO,
|
409
|
-
)
|
402
|
+
info_lines.append(f"删除原始记忆: {orig_memory.get('id', '未知')}")
|
410
403
|
else:
|
411
|
-
|
412
|
-
f"原始记忆文件已不存在,跳过删除: {orig_memory.get('id', '未知')}"
|
413
|
-
OutputType.INFO,
|
404
|
+
info_lines.append(
|
405
|
+
f"原始记忆文件已不存在,跳过删除: {orig_memory.get('id', '未知')}"
|
414
406
|
)
|
415
407
|
except Exception as e:
|
416
|
-
|
417
|
-
f"删除记忆文件失败 {orig_memory
|
418
|
-
OutputType.WARNING,
|
408
|
+
warn_lines.append(
|
409
|
+
f"删除记忆文件失败 {orig_memory.get('file_path', '')}: {str(e)}"
|
419
410
|
)
|
411
|
+
if info_lines:
|
412
|
+
PrettyOutput.print("\n".join(info_lines), OutputType.INFO)
|
413
|
+
if warn_lines:
|
414
|
+
PrettyOutput.print("\n".join(warn_lines), OutputType.WARNING)
|
420
415
|
|
421
416
|
def export_memories(
|
422
417
|
self,
|
@@ -436,9 +431,10 @@ tags:
|
|
436
431
|
导出的记忆数量
|
437
432
|
"""
|
438
433
|
all_memories = []
|
434
|
+
progress_lines: list[str] = []
|
439
435
|
|
440
436
|
for memory_type in memory_types:
|
441
|
-
|
437
|
+
progress_lines.append(f"正在导出 {memory_type} 类型的记忆...")
|
442
438
|
memories = self._load_memories(memory_type)
|
443
439
|
|
444
440
|
# 如果指定了标签,进行过滤
|
@@ -456,9 +452,11 @@ tags:
|
|
456
452
|
memory.pop("file_path", None)
|
457
453
|
|
458
454
|
all_memories.extend(memories)
|
459
|
-
|
460
|
-
|
461
|
-
|
455
|
+
progress_lines.append(f"从 {memory_type} 导出了 {len(memories)} 个记忆")
|
456
|
+
|
457
|
+
# 统一展示导出进度日志
|
458
|
+
if progress_lines:
|
459
|
+
PrettyOutput.print("\n".join(progress_lines), OutputType.INFO)
|
462
460
|
|
463
461
|
# 保存到文件
|
464
462
|
output_file.parent.mkdir(parents=True, exist_ok=True)
|
@@ -505,10 +503,6 @@ tags:
|
|
505
503
|
for memory in memories:
|
506
504
|
memory_type = memory.get("memory_type", memory.get("type"))
|
507
505
|
if not memory_type:
|
508
|
-
PrettyOutput.print(
|
509
|
-
f"跳过没有类型的记忆: {memory.get('id', '未知')}",
|
510
|
-
OutputType.WARNING,
|
511
|
-
)
|
512
506
|
skipped_count += 1
|
513
507
|
continue
|
514
508
|
|
@@ -560,8 +554,9 @@ tags:
|
|
560
554
|
|
561
555
|
# 显示导入结果
|
562
556
|
PrettyOutput.print("\n导入完成!", OutputType.SUCCESS)
|
563
|
-
|
564
|
-
|
557
|
+
if import_stats:
|
558
|
+
lines = [f"{memory_type}: 导入了 {count} 个记忆" for memory_type, count in import_stats.items()]
|
559
|
+
PrettyOutput.print("\n".join(lines), OutputType.INFO)
|
565
560
|
|
566
561
|
if skipped_count > 0:
|
567
562
|
PrettyOutput.print(f"跳过了 {skipped_count} 个记忆", OutputType.WARNING)
|
@@ -592,12 +587,7 @@ def organize(
|
|
592
587
|
llm_group: Optional[str] = typer.Option(
|
593
588
|
None, "-g", "--llm-group", help="使用的模型组,覆盖配置文件中的设置"
|
594
589
|
),
|
595
|
-
|
596
|
-
"normal",
|
597
|
-
"-t",
|
598
|
-
"--llm-type",
|
599
|
-
help="使用的LLM类型,可选值:'normal'(普通)或 'thinking'(思考模式)",
|
600
|
-
),
|
590
|
+
|
601
591
|
):
|
602
592
|
"""
|
603
593
|
整理和合并具有相似标签的记忆。
|
@@ -627,7 +617,7 @@ def organize(
|
|
627
617
|
|
628
618
|
# 创建整理器并执行
|
629
619
|
try:
|
630
|
-
organizer = MemoryOrganizer(llm_group=llm_group
|
620
|
+
organizer = MemoryOrganizer(llm_group=llm_group)
|
631
621
|
stats = organizer.organize_memories(
|
632
622
|
memory_type=memory_type, min_overlap=min_overlap, dry_run=dry_run
|
633
623
|
)
|
@@ -681,12 +671,15 @@ def export(
|
|
681
671
|
try:
|
682
672
|
organizer = MemoryOrganizer()
|
683
673
|
|
684
|
-
#
|
674
|
+
# 验证记忆类型(先收集无效类型,统一打印一次)
|
685
675
|
valid_types = ["project_long_term", "global_long_term"]
|
686
|
-
for mt in memory_types
|
687
|
-
|
688
|
-
|
689
|
-
|
676
|
+
invalid_types = [mt for mt in memory_types if mt not in valid_types]
|
677
|
+
if invalid_types:
|
678
|
+
PrettyOutput.print(
|
679
|
+
"错误:不支持的记忆类型: " + ", ".join(f"'{mt}'" for mt in invalid_types),
|
680
|
+
OutputType.ERROR,
|
681
|
+
)
|
682
|
+
raise typer.Exit(1)
|
690
683
|
|
691
684
|
count = organizer.export_memories(
|
692
685
|
memory_types=memory_types,
|
@@ -94,9 +94,11 @@ def list_methodologies():
|
|
94
94
|
PrettyOutput.print("没有找到方法论", OutputType.INFO)
|
95
95
|
return
|
96
96
|
|
97
|
-
|
97
|
+
# 先拼接再统一打印,避免在循环中逐条输出造成信息稀疏
|
98
|
+
lines = ["可用方法论:"]
|
98
99
|
for i, (problem_type, _) in enumerate(methodologies.items(), 1):
|
99
|
-
|
100
|
+
lines.append(f"{i}. {problem_type}")
|
101
|
+
PrettyOutput.print("\n".join(lines), OutputType.INFO)
|
100
102
|
except (OSError, json.JSONDecodeError) as e:
|
101
103
|
PrettyOutput.print(f"列出方法论失败: {str(e)}", OutputType.ERROR)
|
102
104
|
raise typer.Exit(code=1)
|
jarvis/jarvis_platform/base.py
CHANGED
@@ -120,32 +120,69 @@ class BasePlatform(ABC):
|
|
120
120
|
else:
|
121
121
|
response = ""
|
122
122
|
|
123
|
-
text_content = Text()
|
123
|
+
text_content = Text(overflow="fold") # 添加文本溢出处理
|
124
124
|
panel = Panel(
|
125
125
|
text_content,
|
126
126
|
title=f"[bold cyan]{self.name()}[/bold cyan]",
|
127
127
|
subtitle="[dim]思考中... (按 Ctrl+C 中断)[/dim]",
|
128
128
|
border_style="bright_blue",
|
129
129
|
box=box.ROUNDED,
|
130
|
+
expand=True # 允许面板自动调整大小
|
130
131
|
)
|
131
132
|
|
132
133
|
if not self.suppress_output:
|
133
134
|
if get_pretty_output():
|
134
|
-
|
135
|
+
# 优化Live输出,减少闪烁
|
136
|
+
buffer = []
|
137
|
+
buffer_count = 0
|
138
|
+
with Live(panel, refresh_per_second=4, transient=False) as live:
|
135
139
|
for s in self.chat(message):
|
136
|
-
response += s
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
140
|
+
response += s # Accumulate the full response string
|
141
|
+
buffer.append(s)
|
142
|
+
buffer_count += 1
|
143
|
+
|
144
|
+
# 积累一定量或达到最后再更新,减少闪烁
|
145
|
+
if buffer_count >= 5 or s == "":
|
146
|
+
# Append buffered content to the Text object
|
147
|
+
text_content.append("".join(buffer), style="bright_white")
|
148
|
+
buffer.clear()
|
149
|
+
buffer_count = 0
|
150
|
+
|
151
|
+
# --- Scrolling Logic ---
|
152
|
+
# Calculate available height in the panel
|
153
|
+
max_text_height = console.height - 5 # Leave space for borders/titles
|
154
|
+
if max_text_height <= 0:
|
155
|
+
max_text_height = 1
|
156
|
+
|
157
|
+
# Get the actual number of lines the text will wrap to
|
158
|
+
lines = text_content.wrap(
|
159
|
+
console,
|
160
|
+
console.width - 4 if console.width > 4 else 1,
|
161
|
+
)
|
162
|
+
|
163
|
+
# If content overflows, truncate to show only the last few lines
|
164
|
+
if len(lines) > max_text_height:
|
165
|
+
new_text = "\n".join(
|
166
|
+
text_content.plain.splitlines()[-max_text_height:]
|
167
|
+
)
|
168
|
+
text_content.plain = new_text
|
169
|
+
|
170
|
+
panel.subtitle = "[yellow]正在回答... (按 Ctrl+C 中断)[/yellow]"
|
171
|
+
live.update(panel)
|
172
|
+
|
142
173
|
if is_immediate_abort() and get_interrupt():
|
143
|
-
return response
|
174
|
+
return response # Return the partial response immediately
|
175
|
+
|
176
|
+
# Ensure any remaining content in the buffer is displayed
|
177
|
+
if buffer:
|
178
|
+
text_content.append("".join(buffer), style="bright_white")
|
179
|
+
|
180
|
+
# At the end, display the entire response
|
181
|
+
text_content.plain = response
|
182
|
+
|
144
183
|
end_time = time.time()
|
145
184
|
duration = end_time - start_time
|
146
|
-
panel.subtitle =
|
147
|
-
f"[bold green]✓ 对话完成耗时: {duration:.2f}秒[/bold green]"
|
148
|
-
)
|
185
|
+
panel.subtitle = f"[bold green]✓ 对话完成耗时: {duration:.2f}秒[/bold green]"
|
149
186
|
live.update(panel)
|
150
187
|
else:
|
151
188
|
# Print a clear prefix line before streaming model output (non-pretty mode)
|
jarvis/jarvis_platform/kimi.py
CHANGED
@@ -194,9 +194,7 @@ class KimiModel(BasePlatform):
|
|
194
194
|
uploaded_files = []
|
195
195
|
for index, file_path in enumerate(file_list, 1):
|
196
196
|
file_name = os.path.basename(file_path)
|
197
|
-
|
198
|
-
f"处理文件 [{index}/{len(file_list)}]: {file_name}", OutputType.INFO
|
199
|
-
)
|
197
|
+
log_lines: list[str] = [f"处理文件 [{index}/{len(file_list)}]: {file_name}"]
|
200
198
|
try:
|
201
199
|
mime_type, _ = mimetypes.guess_type(file_path)
|
202
200
|
action = (
|
@@ -204,44 +202,40 @@ class KimiModel(BasePlatform):
|
|
204
202
|
)
|
205
203
|
|
206
204
|
# 获取预签名URL
|
207
|
-
|
205
|
+
log_lines.append(f"获取上传URL: {file_name}")
|
208
206
|
presigned_data = self._get_presigned_url(file_path, action)
|
209
207
|
|
210
208
|
# 上传文件
|
211
|
-
|
209
|
+
log_lines.append(f"上传文件: {file_name}")
|
212
210
|
if self._upload_file(file_path, presigned_data["url"]):
|
213
211
|
# 获取文件信息
|
214
|
-
|
212
|
+
log_lines.append(f"获取文件信息: {file_name}")
|
215
213
|
file_info = self._get_file_info(presigned_data, file_name, action)
|
216
214
|
|
217
215
|
# 只有文件需要解析
|
218
216
|
if action == "file":
|
219
|
-
|
220
|
-
f"等待文件解析: {file_name}", OutputType.INFO
|
221
|
-
)
|
217
|
+
log_lines.append(f"等待文件解析: {file_name}")
|
222
218
|
if self._wait_for_parse(file_info["id"]):
|
223
219
|
uploaded_files.append(file_info)
|
224
|
-
|
225
|
-
f"文件处理完成: {file_name}", OutputType.SUCCESS
|
226
|
-
)
|
220
|
+
log_lines.append(f"文件处理完成: {file_name}")
|
227
221
|
else:
|
228
|
-
|
229
|
-
|
230
|
-
)
|
222
|
+
log_lines.append(f"文件解析失败: {file_name}")
|
223
|
+
PrettyOutput.print("\n".join(log_lines), OutputType.ERROR)
|
231
224
|
return False
|
232
225
|
else:
|
233
226
|
uploaded_files.append(file_info)
|
234
|
-
|
235
|
-
f"图片处理完成: {file_name}", OutputType.SUCCESS
|
236
|
-
)
|
227
|
+
log_lines.append(f"图片处理完成: {file_name}")
|
237
228
|
else:
|
238
|
-
|
229
|
+
log_lines.append(f"文件上传失败: {file_name}")
|
230
|
+
PrettyOutput.print("\n".join(log_lines), OutputType.ERROR)
|
239
231
|
return False
|
240
232
|
|
233
|
+
# 成功路径统一输出本文件的处理日志
|
234
|
+
PrettyOutput.print("\n".join(log_lines), OutputType.INFO)
|
235
|
+
|
241
236
|
except Exception as e:
|
242
|
-
|
243
|
-
|
244
|
-
)
|
237
|
+
log_lines.append(f"处理文件出错 {file_path}: {str(e)}")
|
238
|
+
PrettyOutput.print("\n".join(log_lines), OutputType.ERROR)
|
245
239
|
return False
|
246
240
|
|
247
241
|
self.uploaded_files = uploaded_files
|
@@ -10,8 +10,6 @@ from jarvis.jarvis_utils.config import (
|
|
10
10
|
get_data_dir,
|
11
11
|
get_normal_model_name,
|
12
12
|
get_normal_platform_name,
|
13
|
-
get_thinking_model_name,
|
14
|
-
get_thinking_platform_name,
|
15
13
|
)
|
16
14
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
17
15
|
|
@@ -113,6 +111,7 @@ class PlatformRegistry:
|
|
113
111
|
if directory not in sys.path:
|
114
112
|
sys.path.append(directory)
|
115
113
|
|
114
|
+
error_lines = []
|
116
115
|
# 遍历目录下的所有.py文件
|
117
116
|
for filename in os.listdir(directory):
|
118
117
|
if filename.endswith(".py") and not filename.startswith("__"):
|
@@ -142,16 +141,15 @@ class PlatformRegistry:
|
|
142
141
|
platform_name = obj.platform_name()
|
143
142
|
platforms[platform_name] = obj
|
144
143
|
except Exception as e:
|
145
|
-
|
146
|
-
f"实例化或注册平台失败 {obj.__name__}: {str(e)}"
|
147
|
-
OutputType.ERROR,
|
144
|
+
error_lines.append(
|
145
|
+
f"实例化或注册平台失败 {obj.__name__}: {str(e)}"
|
148
146
|
)
|
149
147
|
break
|
150
148
|
except Exception as e:
|
151
|
-
|
152
|
-
f"加载平台 {module_name} 失败: {str(e)}", OutputType.ERROR
|
153
|
-
)
|
149
|
+
error_lines.append(f"加载平台 {module_name} 失败: {str(e)}")
|
154
150
|
|
151
|
+
if error_lines:
|
152
|
+
PrettyOutput.print("\n".join(error_lines), OutputType.ERROR)
|
155
153
|
return platforms
|
156
154
|
|
157
155
|
@staticmethod
|
@@ -187,12 +185,7 @@ class PlatformRegistry:
|
|
187
185
|
platform.set_model_name(model_name) # type: ignore
|
188
186
|
return platform # type: ignore
|
189
187
|
|
190
|
-
|
191
|
-
platform_name = get_thinking_platform_name()
|
192
|
-
model_name = get_thinking_model_name()
|
193
|
-
platform = self.create_platform(platform_name)
|
194
|
-
platform.set_model_name(model_name) # type: ignore
|
195
|
-
return platform # type: ignore
|
188
|
+
|
196
189
|
|
197
190
|
def register_platform(self, name: str, platform_class: Type[BasePlatform]) -> None:
|
198
191
|
"""Register platform class
|
jarvis/jarvis_platform/tongyi.py
CHANGED
@@ -276,16 +276,19 @@ class TongyiPlatform(BasePlatform):
|
|
276
276
|
|
277
277
|
for file_path in file_list:
|
278
278
|
file_name = os.path.basename(file_path)
|
279
|
-
|
279
|
+
log_lines: list[str] = []
|
280
|
+
log_lines.append(f"上传文件 {file_name}")
|
280
281
|
try:
|
281
282
|
if not os.path.exists(file_path):
|
282
|
-
|
283
|
+
# 先输出已收集的日志与错误后返回
|
284
|
+
log_lines.append(f"文件不存在: {file_path}")
|
285
|
+
PrettyOutput.print("\n".join(log_lines), OutputType.ERROR)
|
283
286
|
return False
|
284
287
|
|
285
288
|
# Get file name and content type
|
286
289
|
content_type = self._get_content_type(file_path)
|
287
290
|
|
288
|
-
|
291
|
+
log_lines.append(f"准备上传文件: {file_name}")
|
289
292
|
|
290
293
|
# Prepare form data
|
291
294
|
form_data = {
|
@@ -300,7 +303,7 @@ class TongyiPlatform(BasePlatform):
|
|
300
303
|
# Prepare files
|
301
304
|
files = {"file": (file_name, open(file_path, "rb"), content_type)}
|
302
305
|
|
303
|
-
|
306
|
+
log_lines.append(f"正在上传文件: {file_name}")
|
304
307
|
|
305
308
|
# Upload file
|
306
309
|
response = http.post(
|
@@ -308,10 +311,8 @@ class TongyiPlatform(BasePlatform):
|
|
308
311
|
)
|
309
312
|
|
310
313
|
if response.status_code != 200:
|
311
|
-
|
312
|
-
|
313
|
-
OutputType.ERROR,
|
314
|
-
)
|
314
|
+
log_lines.append(f"上传失败 {file_name}: HTTP {response.status_code}")
|
315
|
+
PrettyOutput.print("\n".join(log_lines), OutputType.ERROR)
|
315
316
|
return False
|
316
317
|
|
317
318
|
# Determine file type based on extension
|
@@ -326,7 +327,7 @@ class TongyiPlatform(BasePlatform):
|
|
326
327
|
}
|
327
328
|
)
|
328
329
|
|
329
|
-
|
330
|
+
log_lines.append(f"获取下载链接: {file_name}")
|
330
331
|
|
331
332
|
# Get download links for uploaded files
|
332
333
|
url = "https://api.tongyi.com/dialog/downloadLink/batch"
|
@@ -343,26 +344,20 @@ class TongyiPlatform(BasePlatform):
|
|
343
344
|
|
344
345
|
response = http.post(url, headers=headers, json=payload)
|
345
346
|
if response.status_code != 200:
|
346
|
-
|
347
|
-
|
348
|
-
OutputType.ERROR,
|
349
|
-
)
|
347
|
+
log_lines.append(f"获取下载链接失败: HTTP {response.status_code}")
|
348
|
+
PrettyOutput.print("\n".join(log_lines), OutputType.ERROR)
|
350
349
|
return False
|
351
350
|
|
352
351
|
result = response.json()
|
353
352
|
if not result.get("success"):
|
354
|
-
|
355
|
-
|
356
|
-
OutputType.ERROR,
|
357
|
-
)
|
353
|
+
log_lines.append(f"获取下载链接失败: {result.get('errorMsg')}")
|
354
|
+
PrettyOutput.print("\n".join(log_lines), OutputType.ERROR)
|
358
355
|
return False
|
359
356
|
|
360
357
|
# Add files to chat
|
361
358
|
self.uploaded_file_info = result.get("data", {}).get("results", [])
|
362
359
|
for file_info in self.uploaded_file_info:
|
363
|
-
|
364
|
-
f"添加文件到对话: {file_name}", OutputType.INFO
|
365
|
-
)
|
360
|
+
log_lines.append(f"添加文件到对话: {file_name}")
|
366
361
|
add_url = "https://api.tongyi.com/assistant/api/chat/file/add"
|
367
362
|
add_payload = {
|
368
363
|
"workSource": "chat",
|
@@ -385,29 +380,23 @@ class TongyiPlatform(BasePlatform):
|
|
385
380
|
add_url, headers=headers, json=add_payload
|
386
381
|
)
|
387
382
|
if add_response.status_code != 200:
|
388
|
-
|
389
|
-
f"添加文件到对话失败: HTTP {add_response.status_code}",
|
390
|
-
OutputType.ERROR,
|
391
|
-
)
|
383
|
+
log_lines.append(f"添加文件到对话失败: HTTP {add_response.status_code}")
|
392
384
|
continue
|
393
385
|
|
394
386
|
add_result = add_response.json()
|
395
387
|
if not add_result.get("success"):
|
396
|
-
|
397
|
-
f"添加文件到对话失败: {add_result.get('errorMsg')}",
|
398
|
-
OutputType.ERROR,
|
399
|
-
)
|
388
|
+
log_lines.append(f"添加文件到对话失败: {add_result.get('errorMsg')}")
|
400
389
|
continue
|
401
390
|
|
402
391
|
file_info.update(add_result.get("data", {}))
|
403
392
|
|
404
|
-
|
393
|
+
log_lines.append(f"文件 {file_name} 上传成功")
|
394
|
+
PrettyOutput.print("\n".join(log_lines), OutputType.INFO)
|
405
395
|
time.sleep(1) # 短暂暂停以便用户看到成功状态
|
406
396
|
|
407
397
|
except Exception as e:
|
408
|
-
|
409
|
-
|
410
|
-
)
|
398
|
+
log_lines.append(f"上传文件 {file_name} 时出错: {str(e)}")
|
399
|
+
PrettyOutput.print("\n".join(log_lines), OutputType.ERROR)
|
411
400
|
return False
|
412
401
|
return True
|
413
402
|
|
@@ -134,10 +134,11 @@ class YuanbaoPlatform(BasePlatform):
|
|
134
134
|
|
135
135
|
for file_path in file_list:
|
136
136
|
file_name = os.path.basename(file_path)
|
137
|
-
|
137
|
+
log_lines: list[str] = []
|
138
|
+
log_lines.append(f"上传文件 {file_name}")
|
138
139
|
try:
|
139
140
|
# 1. Prepare the file information
|
140
|
-
|
141
|
+
log_lines.append(f"准备文件信息: {file_name}")
|
141
142
|
file_size = os.path.getsize(file_path)
|
142
143
|
file_extension = os.path.splitext(file_path)[1].lower().lstrip(".")
|
143
144
|
|
@@ -192,23 +193,23 @@ class YuanbaoPlatform(BasePlatform):
|
|
192
193
|
file_type = "code"
|
193
194
|
|
194
195
|
# 2. Generate upload information
|
195
|
-
|
196
|
+
log_lines.append(f"获取上传信息: {file_name}")
|
196
197
|
upload_info = self._generate_upload_info(file_name)
|
197
198
|
if not upload_info:
|
198
|
-
|
199
|
-
|
200
|
-
)
|
199
|
+
log_lines.append(f"无法获取文件 {file_name} 的上传信息")
|
200
|
+
PrettyOutput.print("\n".join(log_lines), OutputType.ERROR)
|
201
201
|
return False
|
202
202
|
|
203
203
|
# 3. Upload the file to COS
|
204
|
-
|
204
|
+
log_lines.append(f"上传文件到云存储: {file_name}")
|
205
205
|
upload_success = self._upload_file_to_cos(file_path, upload_info)
|
206
206
|
if not upload_success:
|
207
|
-
|
207
|
+
log_lines.append(f"上传文件 {file_name} 失败")
|
208
|
+
PrettyOutput.print("\n".join(log_lines), OutputType.ERROR)
|
208
209
|
return False
|
209
210
|
|
210
211
|
# 4. Create file metadata for chat
|
211
|
-
|
212
|
+
log_lines.append(f"生成文件元数据: {file_name}")
|
212
213
|
file_metadata = {
|
213
214
|
"type": file_type,
|
214
215
|
"docType": file_extension if file_extension else file_type,
|
@@ -226,19 +227,16 @@ class YuanbaoPlatform(BasePlatform):
|
|
226
227
|
file_metadata["width"] = img.width
|
227
228
|
file_metadata["height"] = img.height
|
228
229
|
except Exception as e:
|
229
|
-
|
230
|
-
f"无法获取图片 {file_name} 的尺寸: {str(e)}",
|
231
|
-
OutputType.WARNING,
|
232
|
-
)
|
230
|
+
log_lines.append(f"无法获取图片 {file_name} 的尺寸: {str(e)}")
|
233
231
|
|
234
232
|
uploaded_files.append(file_metadata)
|
235
|
-
|
233
|
+
log_lines.append(f"文件 {file_name} 上传成功")
|
234
|
+
PrettyOutput.print("\n".join(log_lines), OutputType.INFO)
|
236
235
|
time.sleep(3) # 上传成功后等待3秒
|
237
236
|
|
238
237
|
except Exception as e:
|
239
|
-
|
240
|
-
|
241
|
-
)
|
238
|
+
log_lines.append(f"上传文件 {file_path} 时出错: {str(e)}")
|
239
|
+
PrettyOutput.print("\n".join(log_lines), OutputType.ERROR)
|
242
240
|
return False
|
243
241
|
|
244
242
|
self.multimedia = uploaded_files
|