jarvis-ai-assistant 0.7.8__py3-none-any.whl → 1.0.2__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 +567 -222
- jarvis/jarvis_agent/agent_manager.py +19 -12
- jarvis/jarvis_agent/builtin_input_handler.py +79 -11
- jarvis/jarvis_agent/config_editor.py +7 -2
- jarvis/jarvis_agent/event_bus.py +24 -13
- jarvis/jarvis_agent/events.py +19 -1
- jarvis/jarvis_agent/file_context_handler.py +67 -64
- jarvis/jarvis_agent/file_methodology_manager.py +38 -24
- jarvis/jarvis_agent/jarvis.py +186 -114
- jarvis/jarvis_agent/language_extractors/__init__.py +8 -1
- jarvis/jarvis_agent/language_extractors/c_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/cpp_extractor.py +9 -4
- jarvis/jarvis_agent/language_extractors/go_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/java_extractor.py +27 -20
- jarvis/jarvis_agent/language_extractors/javascript_extractor.py +22 -17
- jarvis/jarvis_agent/language_extractors/python_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/rust_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/typescript_extractor.py +22 -17
- jarvis/jarvis_agent/language_support_info.py +250 -219
- jarvis/jarvis_agent/main.py +19 -23
- jarvis/jarvis_agent/memory_manager.py +9 -6
- jarvis/jarvis_agent/methodology_share_manager.py +21 -15
- jarvis/jarvis_agent/output_handler.py +4 -2
- jarvis/jarvis_agent/prompt_builder.py +7 -6
- jarvis/jarvis_agent/prompt_manager.py +113 -8
- jarvis/jarvis_agent/prompts.py +317 -85
- jarvis/jarvis_agent/protocols.py +5 -2
- jarvis/jarvis_agent/run_loop.py +192 -32
- jarvis/jarvis_agent/session_manager.py +7 -3
- jarvis/jarvis_agent/share_manager.py +23 -13
- jarvis/jarvis_agent/shell_input_handler.py +12 -8
- jarvis/jarvis_agent/stdio_redirect.py +25 -26
- jarvis/jarvis_agent/task_analyzer.py +29 -23
- jarvis/jarvis_agent/task_list.py +869 -0
- jarvis/jarvis_agent/task_manager.py +26 -23
- jarvis/jarvis_agent/tool_executor.py +6 -5
- jarvis/jarvis_agent/tool_share_manager.py +24 -14
- jarvis/jarvis_agent/user_interaction.py +3 -3
- jarvis/jarvis_agent/utils.py +9 -1
- jarvis/jarvis_agent/web_bridge.py +37 -17
- jarvis/jarvis_agent/web_output_sink.py +5 -2
- jarvis/jarvis_agent/web_server.py +165 -36
- jarvis/jarvis_c2rust/__init__.py +1 -1
- jarvis/jarvis_c2rust/cli.py +260 -141
- jarvis/jarvis_c2rust/collector.py +37 -18
- jarvis/jarvis_c2rust/constants.py +60 -0
- jarvis/jarvis_c2rust/library_replacer.py +242 -1010
- jarvis/jarvis_c2rust/library_replacer_checkpoint.py +133 -0
- jarvis/jarvis_c2rust/library_replacer_llm.py +287 -0
- jarvis/jarvis_c2rust/library_replacer_loader.py +191 -0
- jarvis/jarvis_c2rust/library_replacer_output.py +134 -0
- jarvis/jarvis_c2rust/library_replacer_prompts.py +124 -0
- jarvis/jarvis_c2rust/library_replacer_utils.py +188 -0
- jarvis/jarvis_c2rust/llm_module_agent.py +98 -1044
- jarvis/jarvis_c2rust/llm_module_agent_apply.py +170 -0
- jarvis/jarvis_c2rust/llm_module_agent_executor.py +288 -0
- jarvis/jarvis_c2rust/llm_module_agent_loader.py +170 -0
- jarvis/jarvis_c2rust/llm_module_agent_prompts.py +268 -0
- jarvis/jarvis_c2rust/llm_module_agent_types.py +57 -0
- jarvis/jarvis_c2rust/llm_module_agent_utils.py +150 -0
- jarvis/jarvis_c2rust/llm_module_agent_validator.py +119 -0
- jarvis/jarvis_c2rust/loaders.py +28 -10
- jarvis/jarvis_c2rust/models.py +5 -2
- jarvis/jarvis_c2rust/optimizer.py +192 -1974
- jarvis/jarvis_c2rust/optimizer_build_fix.py +286 -0
- jarvis/jarvis_c2rust/optimizer_clippy.py +766 -0
- jarvis/jarvis_c2rust/optimizer_config.py +49 -0
- jarvis/jarvis_c2rust/optimizer_docs.py +183 -0
- jarvis/jarvis_c2rust/optimizer_options.py +48 -0
- jarvis/jarvis_c2rust/optimizer_progress.py +469 -0
- jarvis/jarvis_c2rust/optimizer_report.py +52 -0
- jarvis/jarvis_c2rust/optimizer_unsafe.py +309 -0
- jarvis/jarvis_c2rust/optimizer_utils.py +469 -0
- jarvis/jarvis_c2rust/optimizer_visibility.py +185 -0
- jarvis/jarvis_c2rust/scanner.py +229 -166
- jarvis/jarvis_c2rust/transpiler.py +531 -2732
- jarvis/jarvis_c2rust/transpiler_agents.py +503 -0
- jarvis/jarvis_c2rust/transpiler_build.py +1294 -0
- jarvis/jarvis_c2rust/transpiler_codegen.py +204 -0
- jarvis/jarvis_c2rust/transpiler_compile.py +146 -0
- jarvis/jarvis_c2rust/transpiler_config.py +178 -0
- jarvis/jarvis_c2rust/transpiler_context.py +122 -0
- jarvis/jarvis_c2rust/transpiler_executor.py +516 -0
- jarvis/jarvis_c2rust/transpiler_generation.py +278 -0
- jarvis/jarvis_c2rust/transpiler_git.py +163 -0
- jarvis/jarvis_c2rust/transpiler_mod_utils.py +225 -0
- jarvis/jarvis_c2rust/transpiler_modules.py +336 -0
- jarvis/jarvis_c2rust/transpiler_planning.py +394 -0
- jarvis/jarvis_c2rust/transpiler_review.py +1196 -0
- jarvis/jarvis_c2rust/transpiler_symbols.py +176 -0
- jarvis/jarvis_c2rust/utils.py +269 -79
- jarvis/jarvis_code_agent/after_change.py +233 -0
- jarvis/jarvis_code_agent/build_validation_config.py +37 -30
- jarvis/jarvis_code_agent/builtin_rules.py +68 -0
- jarvis/jarvis_code_agent/code_agent.py +976 -1517
- jarvis/jarvis_code_agent/code_agent_build.py +227 -0
- jarvis/jarvis_code_agent/code_agent_diff.py +246 -0
- jarvis/jarvis_code_agent/code_agent_git.py +525 -0
- jarvis/jarvis_code_agent/code_agent_impact.py +177 -0
- jarvis/jarvis_code_agent/code_agent_lint.py +283 -0
- jarvis/jarvis_code_agent/code_agent_llm.py +159 -0
- jarvis/jarvis_code_agent/code_agent_postprocess.py +105 -0
- jarvis/jarvis_code_agent/code_agent_prompts.py +46 -0
- jarvis/jarvis_code_agent/code_agent_rules.py +305 -0
- jarvis/jarvis_code_agent/code_analyzer/__init__.py +52 -48
- jarvis/jarvis_code_agent/code_analyzer/base_language.py +12 -10
- jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +12 -11
- jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +16 -12
- jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +26 -17
- jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +558 -104
- jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +27 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +22 -18
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +21 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +20 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +27 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +47 -23
- jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +71 -37
- jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +162 -35
- jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +111 -57
- jarvis/jarvis_code_agent/code_analyzer/build_validator.py +18 -12
- jarvis/jarvis_code_agent/code_analyzer/context_manager.py +185 -183
- jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +2 -1
- jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +24 -15
- jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +227 -141
- jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +321 -247
- jarvis/jarvis_code_agent/code_analyzer/language_registry.py +37 -29
- jarvis/jarvis_code_agent/code_analyzer/language_support.py +21 -13
- jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +15 -9
- jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +75 -45
- jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +87 -52
- jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +84 -51
- jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +94 -64
- jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +109 -71
- jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +97 -63
- jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +103 -69
- jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +271 -268
- jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +76 -64
- jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +92 -19
- jarvis/jarvis_code_agent/diff_visualizer.py +998 -0
- jarvis/jarvis_code_agent/lint.py +223 -524
- jarvis/jarvis_code_agent/rule_share_manager.py +158 -0
- jarvis/jarvis_code_agent/rules/clean_code.md +144 -0
- jarvis/jarvis_code_agent/rules/code_review.md +115 -0
- jarvis/jarvis_code_agent/rules/documentation.md +165 -0
- jarvis/jarvis_code_agent/rules/generate_rules.md +52 -0
- jarvis/jarvis_code_agent/rules/performance.md +158 -0
- jarvis/jarvis_code_agent/rules/refactoring.md +139 -0
- jarvis/jarvis_code_agent/rules/security.md +160 -0
- jarvis/jarvis_code_agent/rules/tdd.md +78 -0
- jarvis/jarvis_code_agent/test_rules/cpp_test.md +118 -0
- jarvis/jarvis_code_agent/test_rules/go_test.md +98 -0
- jarvis/jarvis_code_agent/test_rules/java_test.md +99 -0
- jarvis/jarvis_code_agent/test_rules/javascript_test.md +113 -0
- jarvis/jarvis_code_agent/test_rules/php_test.md +117 -0
- jarvis/jarvis_code_agent/test_rules/python_test.md +91 -0
- jarvis/jarvis_code_agent/test_rules/ruby_test.md +102 -0
- jarvis/jarvis_code_agent/test_rules/rust_test.md +86 -0
- jarvis/jarvis_code_agent/utils.py +36 -26
- jarvis/jarvis_code_analysis/checklists/loader.py +21 -21
- jarvis/jarvis_code_analysis/code_review.py +64 -33
- jarvis/jarvis_data/config_schema.json +285 -192
- jarvis/jarvis_git_squash/main.py +8 -6
- jarvis/jarvis_git_utils/git_commiter.py +53 -76
- jarvis/jarvis_mcp/__init__.py +5 -2
- jarvis/jarvis_mcp/sse_mcp_client.py +40 -30
- jarvis/jarvis_mcp/stdio_mcp_client.py +27 -19
- jarvis/jarvis_mcp/streamable_mcp_client.py +35 -26
- jarvis/jarvis_memory_organizer/memory_organizer.py +78 -55
- jarvis/jarvis_methodology/main.py +48 -39
- jarvis/jarvis_multi_agent/__init__.py +56 -23
- jarvis/jarvis_multi_agent/main.py +15 -18
- jarvis/jarvis_platform/base.py +179 -111
- jarvis/jarvis_platform/human.py +27 -16
- jarvis/jarvis_platform/kimi.py +52 -45
- jarvis/jarvis_platform/openai.py +101 -40
- jarvis/jarvis_platform/registry.py +51 -33
- jarvis/jarvis_platform/tongyi.py +68 -38
- jarvis/jarvis_platform/yuanbao.py +59 -43
- jarvis/jarvis_platform_manager/main.py +68 -76
- jarvis/jarvis_platform_manager/service.py +24 -14
- jarvis/jarvis_rag/README_CONFIG.md +314 -0
- jarvis/jarvis_rag/README_DYNAMIC_LOADING.md +311 -0
- jarvis/jarvis_rag/README_ONLINE_MODELS.md +230 -0
- jarvis/jarvis_rag/__init__.py +57 -4
- jarvis/jarvis_rag/cache.py +3 -1
- jarvis/jarvis_rag/cli.py +48 -68
- jarvis/jarvis_rag/embedding_interface.py +39 -0
- jarvis/jarvis_rag/embedding_manager.py +7 -230
- jarvis/jarvis_rag/embeddings/__init__.py +41 -0
- jarvis/jarvis_rag/embeddings/base.py +114 -0
- jarvis/jarvis_rag/embeddings/cohere.py +66 -0
- jarvis/jarvis_rag/embeddings/edgefn.py +117 -0
- jarvis/jarvis_rag/embeddings/local.py +260 -0
- jarvis/jarvis_rag/embeddings/openai.py +62 -0
- jarvis/jarvis_rag/embeddings/registry.py +293 -0
- jarvis/jarvis_rag/llm_interface.py +8 -6
- jarvis/jarvis_rag/query_rewriter.py +8 -9
- jarvis/jarvis_rag/rag_pipeline.py +61 -52
- jarvis/jarvis_rag/reranker.py +7 -75
- jarvis/jarvis_rag/reranker_interface.py +32 -0
- jarvis/jarvis_rag/rerankers/__init__.py +41 -0
- jarvis/jarvis_rag/rerankers/base.py +109 -0
- jarvis/jarvis_rag/rerankers/cohere.py +67 -0
- jarvis/jarvis_rag/rerankers/edgefn.py +140 -0
- jarvis/jarvis_rag/rerankers/jina.py +79 -0
- jarvis/jarvis_rag/rerankers/local.py +89 -0
- jarvis/jarvis_rag/rerankers/registry.py +293 -0
- jarvis/jarvis_rag/retriever.py +58 -43
- jarvis/jarvis_sec/__init__.py +66 -141
- jarvis/jarvis_sec/agents.py +21 -17
- jarvis/jarvis_sec/analysis.py +80 -33
- jarvis/jarvis_sec/checkers/__init__.py +7 -13
- jarvis/jarvis_sec/checkers/c_checker.py +356 -164
- jarvis/jarvis_sec/checkers/rust_checker.py +47 -29
- jarvis/jarvis_sec/cli.py +43 -21
- jarvis/jarvis_sec/clustering.py +430 -272
- jarvis/jarvis_sec/file_manager.py +99 -55
- jarvis/jarvis_sec/parsers.py +9 -6
- jarvis/jarvis_sec/prompts.py +4 -3
- jarvis/jarvis_sec/report.py +44 -22
- jarvis/jarvis_sec/review.py +180 -107
- jarvis/jarvis_sec/status.py +50 -41
- jarvis/jarvis_sec/types.py +3 -0
- jarvis/jarvis_sec/utils.py +160 -83
- jarvis/jarvis_sec/verification.py +411 -181
- jarvis/jarvis_sec/workflow.py +132 -21
- jarvis/jarvis_smart_shell/main.py +28 -41
- jarvis/jarvis_stats/cli.py +14 -12
- jarvis/jarvis_stats/stats.py +28 -19
- jarvis/jarvis_stats/storage.py +14 -8
- jarvis/jarvis_stats/visualizer.py +12 -7
- jarvis/jarvis_tools/base.py +5 -2
- jarvis/jarvis_tools/clear_memory.py +13 -9
- jarvis/jarvis_tools/cli/main.py +23 -18
- jarvis/jarvis_tools/edit_file.py +572 -873
- jarvis/jarvis_tools/execute_script.py +10 -7
- jarvis/jarvis_tools/file_analyzer.py +7 -8
- jarvis/jarvis_tools/meta_agent.py +287 -0
- jarvis/jarvis_tools/methodology.py +5 -3
- jarvis/jarvis_tools/read_code.py +305 -1438
- jarvis/jarvis_tools/read_symbols.py +50 -17
- jarvis/jarvis_tools/read_webpage.py +19 -18
- jarvis/jarvis_tools/registry.py +435 -156
- jarvis/jarvis_tools/retrieve_memory.py +16 -11
- jarvis/jarvis_tools/save_memory.py +8 -6
- jarvis/jarvis_tools/search_web.py +31 -31
- jarvis/jarvis_tools/sub_agent.py +32 -28
- jarvis/jarvis_tools/sub_code_agent.py +44 -60
- jarvis/jarvis_tools/task_list_manager.py +1811 -0
- jarvis/jarvis_tools/virtual_tty.py +29 -19
- jarvis/jarvis_utils/__init__.py +4 -0
- jarvis/jarvis_utils/builtin_replace_map.py +2 -1
- jarvis/jarvis_utils/clipboard.py +9 -8
- jarvis/jarvis_utils/collections.py +331 -0
- jarvis/jarvis_utils/config.py +699 -194
- jarvis/jarvis_utils/dialogue_recorder.py +294 -0
- jarvis/jarvis_utils/embedding.py +6 -3
- jarvis/jarvis_utils/file_processors.py +7 -1
- jarvis/jarvis_utils/fzf.py +9 -3
- jarvis/jarvis_utils/git_utils.py +71 -42
- jarvis/jarvis_utils/globals.py +116 -32
- jarvis/jarvis_utils/http.py +6 -2
- jarvis/jarvis_utils/input.py +318 -83
- jarvis/jarvis_utils/jsonnet_compat.py +119 -104
- jarvis/jarvis_utils/methodology.py +37 -28
- jarvis/jarvis_utils/output.py +201 -44
- jarvis/jarvis_utils/utils.py +986 -628
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/METADATA +49 -33
- jarvis_ai_assistant-1.0.2.dist-info/RECORD +304 -0
- jarvis/jarvis_code_agent/code_analyzer/structured_code.py +0 -556
- jarvis/jarvis_tools/generate_new_tool.py +0 -205
- jarvis/jarvis_tools/lsp_client.py +0 -1552
- jarvis/jarvis_tools/rewrite_file.py +0 -105
- jarvis_ai_assistant-0.7.8.dist-info/RECORD +0 -218
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/top_level.txt +0 -0
jarvis/jarvis_platform/kimi.py
CHANGED
|
@@ -5,10 +5,17 @@ import json
|
|
|
5
5
|
import mimetypes
|
|
6
6
|
import os
|
|
7
7
|
import time
|
|
8
|
-
from typing import
|
|
8
|
+
from typing import Any
|
|
9
|
+
from typing import Dict
|
|
10
|
+
from typing import Generator
|
|
11
|
+
from typing import List
|
|
12
|
+
from typing import Optional
|
|
13
|
+
from typing import Tuple
|
|
14
|
+
from typing import cast
|
|
9
15
|
|
|
10
16
|
from jarvis.jarvis_platform.base import BasePlatform
|
|
11
17
|
from jarvis.jarvis_utils import http
|
|
18
|
+
from jarvis.jarvis_utils.output import PrettyOutput
|
|
12
19
|
from jarvis.jarvis_utils.utils import while_success
|
|
13
20
|
|
|
14
21
|
|
|
@@ -28,17 +35,23 @@ class KimiModel(BasePlatform):
|
|
|
28
35
|
("k2", "基于网页的 Kimi,深度思考模型 K2"),
|
|
29
36
|
]
|
|
30
37
|
|
|
31
|
-
def __init__(self):
|
|
38
|
+
def __init__(self, llm_config: Optional[Dict[str, Any]] = None):
|
|
32
39
|
"""
|
|
33
40
|
Initialize Kimi model
|
|
41
|
+
|
|
42
|
+
参数:
|
|
43
|
+
llm_config: LLM配置字典,包含 kimi_api_key 等
|
|
34
44
|
"""
|
|
35
45
|
super().__init__()
|
|
36
46
|
self.chat_id = "" # 当前会话ID
|
|
37
|
-
|
|
47
|
+
llm_config = llm_config or {}
|
|
48
|
+
|
|
49
|
+
# 从 llm_config 获取配置,如果没有则从环境变量获取(向后兼容)
|
|
50
|
+
self.api_key = llm_config.get("kimi_api_key") or os.getenv("KIMI_API_KEY")
|
|
38
51
|
if not self.api_key:
|
|
39
|
-
|
|
52
|
+
PrettyOutput.auto_print("⚠️ KIMI_API_KEY 未设置")
|
|
40
53
|
self.auth_header = f"Bearer {self.api_key}" # 认证头信息
|
|
41
|
-
self.uploaded_files = [] # 存储已上传文件的信息
|
|
54
|
+
self.uploaded_files: List[Dict[str, Any]] = [] # 存储已上传文件的信息
|
|
42
55
|
self.chat_id = "" # 当前会话ID
|
|
43
56
|
self.first_chat = True # 标记是否是第一次对话
|
|
44
57
|
self.system_message = "" # 系统提示消息
|
|
@@ -67,12 +80,12 @@ class KimiModel(BasePlatform):
|
|
|
67
80
|
lambda: http.post(url, headers=headers, data=payload)
|
|
68
81
|
)
|
|
69
82
|
if response.status_code != 200:
|
|
70
|
-
|
|
83
|
+
PrettyOutput.auto_print(f"❌ 错误:创建会话失败:{response.json()}")
|
|
71
84
|
return False
|
|
72
|
-
self.chat_id = response.json()["id"]
|
|
85
|
+
self.chat_id = cast(str, cast(Dict[str, Any], response.json())["id"])
|
|
73
86
|
return True
|
|
74
87
|
except Exception as e:
|
|
75
|
-
|
|
88
|
+
PrettyOutput.auto_print(f"❌ 错误:创建会话失败:{e}")
|
|
76
89
|
return False
|
|
77
90
|
|
|
78
91
|
def _get_presigned_url(self, filename: str, action: str) -> Dict:
|
|
@@ -88,9 +101,8 @@ class KimiModel(BasePlatform):
|
|
|
88
101
|
"Content-Type": "application/json",
|
|
89
102
|
}
|
|
90
103
|
|
|
91
|
-
response = while_success(
|
|
92
|
-
|
|
93
|
-
return response.json()
|
|
104
|
+
response = while_success(lambda: http.post(url, headers=headers, data=payload))
|
|
105
|
+
return cast(Dict[str, Any], response.json())
|
|
94
106
|
|
|
95
107
|
def support_upload_files(self) -> bool:
|
|
96
108
|
"""Check if platform supports upload files"""
|
|
@@ -101,12 +113,10 @@ class KimiModel(BasePlatform):
|
|
|
101
113
|
try:
|
|
102
114
|
with open(file_path, "rb") as f:
|
|
103
115
|
content = f.read()
|
|
104
|
-
response = while_success(
|
|
105
|
-
|
|
106
|
-
)
|
|
107
|
-
return response.status_code == 200
|
|
116
|
+
response = while_success(lambda: http.put(presigned_url, data=content))
|
|
117
|
+
return bool(response.status_code == 200)
|
|
108
118
|
except Exception as e:
|
|
109
|
-
|
|
119
|
+
PrettyOutput.auto_print(f"❌ 错误:上传文件失败:{e}")
|
|
110
120
|
return False
|
|
111
121
|
|
|
112
122
|
def _get_file_info(self, file_data: Dict, name: str, file_type: str) -> Dict:
|
|
@@ -128,9 +138,8 @@ class KimiModel(BasePlatform):
|
|
|
128
138
|
"Content-Type": "application/json",
|
|
129
139
|
}
|
|
130
140
|
|
|
131
|
-
response = while_success(
|
|
132
|
-
|
|
133
|
-
return response.json()
|
|
141
|
+
response = while_success(lambda: http.post(url, headers=headers, data=payload))
|
|
142
|
+
return cast(Dict[str, Any], response.json())
|
|
134
143
|
|
|
135
144
|
def _wait_for_parse(self, file_id: str) -> bool:
|
|
136
145
|
"""Wait for file parsing to complete"""
|
|
@@ -178,11 +187,11 @@ class KimiModel(BasePlatform):
|
|
|
178
187
|
return True
|
|
179
188
|
|
|
180
189
|
if not self.chat_id:
|
|
181
|
-
|
|
190
|
+
PrettyOutput.auto_print("ℹ️ 正在创建聊天会话...")
|
|
182
191
|
if not self._create_chat():
|
|
183
|
-
|
|
192
|
+
PrettyOutput.auto_print("❌ 创建聊天会话失败")
|
|
184
193
|
return False
|
|
185
|
-
|
|
194
|
+
PrettyOutput.auto_print("✅ 创建聊天会话成功")
|
|
186
195
|
|
|
187
196
|
uploaded_files = []
|
|
188
197
|
for index, file_path in enumerate(file_list, 1):
|
|
@@ -213,26 +222,26 @@ class KimiModel(BasePlatform):
|
|
|
213
222
|
log_lines.append(f"文件处理完成: {file_name}")
|
|
214
223
|
else:
|
|
215
224
|
log_lines.append(f"文件解析失败: {file_name}")
|
|
216
|
-
joined_logs =
|
|
217
|
-
|
|
225
|
+
joined_logs = "\n".join(log_lines)
|
|
226
|
+
PrettyOutput.auto_print(f"❌ {joined_logs}")
|
|
218
227
|
return False
|
|
219
228
|
else:
|
|
220
229
|
uploaded_files.append(file_info)
|
|
221
230
|
log_lines.append(f"图片处理完成: {file_name}")
|
|
222
231
|
else:
|
|
223
232
|
log_lines.append(f"文件上传失败: {file_name}")
|
|
224
|
-
joined_logs =
|
|
225
|
-
|
|
233
|
+
joined_logs = "\n".join(log_lines)
|
|
234
|
+
PrettyOutput.auto_print(f"❌ {joined_logs}")
|
|
226
235
|
return False
|
|
227
236
|
|
|
228
237
|
# 成功路径统一输出本文件的处理日志
|
|
229
|
-
joined_logs =
|
|
230
|
-
|
|
238
|
+
joined_logs = "\n".join(log_lines)
|
|
239
|
+
PrettyOutput.auto_print(f"ℹ️ {joined_logs}")
|
|
231
240
|
|
|
232
241
|
except Exception as e:
|
|
233
242
|
log_lines.append(f"处理文件出错 {file_path}: {str(e)}")
|
|
234
|
-
joined_logs =
|
|
235
|
-
|
|
243
|
+
joined_logs = "\n".join(log_lines)
|
|
244
|
+
PrettyOutput.auto_print(f"❌ {joined_logs}")
|
|
236
245
|
return False
|
|
237
246
|
|
|
238
247
|
self.uploaded_files = uploaded_files
|
|
@@ -322,25 +331,23 @@ class KimiModel(BasePlatform):
|
|
|
322
331
|
}
|
|
323
332
|
|
|
324
333
|
try:
|
|
325
|
-
response = while_success(
|
|
326
|
-
lambda: http.delete(url, headers=headers)
|
|
327
|
-
)
|
|
334
|
+
response = while_success(lambda: http.delete(url, headers=headers))
|
|
328
335
|
if response.status_code == 200:
|
|
329
336
|
self.chat_id = ""
|
|
330
337
|
self.uploaded_files = []
|
|
331
338
|
self.first_chat = True # 重置first_chat标记
|
|
332
339
|
return True
|
|
333
340
|
else:
|
|
334
|
-
|
|
341
|
+
PrettyOutput.auto_print(f"⚠️ 删除会话失败: HTTP {response.status_code}")
|
|
335
342
|
return False
|
|
336
343
|
except Exception as e:
|
|
337
|
-
|
|
344
|
+
PrettyOutput.auto_print(f"❌ 删除会话时发生错误: {str(e)}")
|
|
338
345
|
return False
|
|
339
346
|
|
|
340
347
|
def save(self, file_path: str) -> bool:
|
|
341
348
|
"""Save chat session to a file."""
|
|
342
349
|
if not self.chat_id:
|
|
343
|
-
|
|
350
|
+
PrettyOutput.auto_print("⚠️ 没有活动的会话可供保存")
|
|
344
351
|
return False
|
|
345
352
|
|
|
346
353
|
state = {
|
|
@@ -355,10 +362,10 @@ class KimiModel(BasePlatform):
|
|
|
355
362
|
with open(file_path, "w", encoding="utf-8") as f:
|
|
356
363
|
json.dump(state, f, ensure_ascii=False, indent=4)
|
|
357
364
|
self._saved = True
|
|
358
|
-
|
|
365
|
+
PrettyOutput.auto_print(f"✅ 会话已成功保存到 {file_path}")
|
|
359
366
|
return True
|
|
360
367
|
except Exception as e:
|
|
361
|
-
|
|
368
|
+
PrettyOutput.auto_print(f"❌ 保存会话失败: {str(e)}")
|
|
362
369
|
return False
|
|
363
370
|
|
|
364
371
|
def restore(self, file_path: str) -> bool:
|
|
@@ -374,13 +381,13 @@ class KimiModel(BasePlatform):
|
|
|
374
381
|
self.uploaded_files = state.get("uploaded_files", [])
|
|
375
382
|
self._saved = True
|
|
376
383
|
|
|
377
|
-
|
|
384
|
+
PrettyOutput.auto_print(f"✅ 从 {file_path} 成功恢复会话")
|
|
378
385
|
return True
|
|
379
386
|
except FileNotFoundError:
|
|
380
|
-
|
|
387
|
+
PrettyOutput.auto_print(f"❌ 会话文件未找到: {file_path}")
|
|
381
388
|
return False
|
|
382
389
|
except Exception as e:
|
|
383
|
-
|
|
390
|
+
PrettyOutput.auto_print(f"❌ 恢复会话失败: {str(e)}")
|
|
384
391
|
return False
|
|
385
392
|
|
|
386
393
|
def name(self) -> str:
|
|
@@ -399,20 +406,20 @@ class KimiModel(BasePlatform):
|
|
|
399
406
|
@classmethod
|
|
400
407
|
def get_required_env_keys(cls) -> List[str]:
|
|
401
408
|
"""
|
|
402
|
-
获取Kimi
|
|
409
|
+
获取Kimi平台所需的配置键列表(已弃用:建议使用 llm_config 配置)
|
|
403
410
|
|
|
404
411
|
返回:
|
|
405
|
-
List[str]:
|
|
412
|
+
List[str]: 配置键的列表(对应 llm_config 中的 kimi_api_key)
|
|
406
413
|
"""
|
|
407
414
|
return ["KIMI_API_KEY"]
|
|
408
415
|
|
|
409
416
|
@classmethod
|
|
410
417
|
def get_env_config_guide(cls) -> Dict[str, str]:
|
|
411
418
|
"""
|
|
412
|
-
|
|
419
|
+
获取配置指导(已弃用:建议使用 llm_config 配置)
|
|
413
420
|
|
|
414
421
|
返回:
|
|
415
|
-
Dict[str, str]:
|
|
422
|
+
Dict[str, str]: 配置键名到配置指导的映射
|
|
416
423
|
"""
|
|
417
424
|
return {
|
|
418
425
|
"KIMI_API_KEY": (
|
jarvis/jarvis_platform/openai.py
CHANGED
|
@@ -1,55 +1,90 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
import json
|
|
3
3
|
import os
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import Any
|
|
5
|
+
from typing import Dict
|
|
6
|
+
from typing import Generator
|
|
7
|
+
from typing import List
|
|
8
|
+
from typing import Optional
|
|
9
|
+
from typing import Tuple
|
|
5
10
|
|
|
6
11
|
from openai import OpenAI
|
|
12
|
+
from openai.types.chat import ChatCompletionMessageParam
|
|
7
13
|
|
|
8
14
|
from jarvis.jarvis_platform.base import BasePlatform
|
|
15
|
+
from jarvis.jarvis_utils.output import PrettyOutput
|
|
9
16
|
|
|
10
17
|
|
|
11
18
|
class OpenAIModel(BasePlatform):
|
|
12
|
-
|
|
13
|
-
def __init__(self):
|
|
19
|
+
def __init__(self, llm_config: Optional[Dict[str, Any]] = None):
|
|
14
20
|
"""
|
|
15
21
|
Initialize OpenAI model
|
|
22
|
+
|
|
23
|
+
参数:
|
|
24
|
+
llm_config: LLM配置字典,包含 openai_api_key, openai_api_base, openai_extra_headers 等
|
|
16
25
|
"""
|
|
17
26
|
super().__init__()
|
|
18
27
|
self.system_message = ""
|
|
19
|
-
|
|
20
|
-
if not self.api_key:
|
|
21
|
-
print("⚠️ OPENAI_API_KEY 未设置")
|
|
28
|
+
llm_config = llm_config or {}
|
|
22
29
|
|
|
23
|
-
|
|
24
|
-
self.
|
|
30
|
+
# 从 llm_config 获取配置,如果没有则从环境变量获取(向后兼容)
|
|
31
|
+
self.api_key = llm_config.get("openai_api_key") or os.getenv("OPENAI_API_KEY")
|
|
32
|
+
if not self.api_key:
|
|
33
|
+
PrettyOutput.auto_print("⚠️ OPENAI_API_KEY 未设置")
|
|
34
|
+
|
|
35
|
+
self.base_url = llm_config.get("openai_api_base") or os.getenv(
|
|
36
|
+
"OPENAI_API_BASE", "https://api.openai.com/v1"
|
|
37
|
+
)
|
|
38
|
+
self.model_name = os.getenv("model") or "gpt-4o"
|
|
39
|
+
|
|
40
|
+
# Optional: Inject extra HTTP headers via llm_config or environment variable
|
|
41
|
+
# Expected format: openai_extra_headers='{"Header-Name": "value", "X-Trace": "abc"}'
|
|
42
|
+
headers_value = llm_config.get("openai_extra_headers")
|
|
43
|
+
if headers_value is None:
|
|
44
|
+
headers_str = os.getenv("OPENAI_EXTRA_HEADERS")
|
|
45
|
+
else:
|
|
46
|
+
headers_str = (
|
|
47
|
+
headers_value
|
|
48
|
+
if isinstance(headers_value, str)
|
|
49
|
+
else json.dumps(headers_value)
|
|
50
|
+
)
|
|
25
51
|
|
|
26
|
-
# Optional: Inject extra HTTP headers via environment variable
|
|
27
|
-
# Expected format: OPENAI_EXTRA_HEADERS='{"Header-Name": "value", "X-Trace": "abc"}'
|
|
28
|
-
headers_str = os.getenv("OPENAI_EXTRA_HEADERS")
|
|
29
52
|
self.extra_headers: Dict[str, str] = {}
|
|
30
53
|
if headers_str:
|
|
31
54
|
try:
|
|
32
|
-
parsed =
|
|
55
|
+
parsed = (
|
|
56
|
+
json.loads(headers_str)
|
|
57
|
+
if isinstance(headers_str, str)
|
|
58
|
+
else headers_str
|
|
59
|
+
)
|
|
33
60
|
if isinstance(parsed, dict):
|
|
34
61
|
# Ensure all header keys/values are strings
|
|
35
62
|
self.extra_headers = {str(k): str(v) for k, v in parsed.items()}
|
|
36
63
|
else:
|
|
37
|
-
|
|
64
|
+
PrettyOutput.auto_print(
|
|
65
|
+
"⚠️ openai_extra_headers 应为 JSON 对象,如 {'X-Source':'jarvis'}"
|
|
66
|
+
)
|
|
38
67
|
except Exception as e:
|
|
39
|
-
|
|
68
|
+
PrettyOutput.auto_print(f"⚠️ 解析 openai_extra_headers 失败: {e}")
|
|
40
69
|
|
|
41
70
|
# Initialize OpenAI client, try to pass default headers if SDK supports it
|
|
42
71
|
try:
|
|
43
72
|
if self.extra_headers:
|
|
44
|
-
self.client = OpenAI(
|
|
73
|
+
self.client = OpenAI(
|
|
74
|
+
api_key=self.api_key,
|
|
75
|
+
base_url=self.base_url,
|
|
76
|
+
default_headers=self.extra_headers,
|
|
77
|
+
)
|
|
45
78
|
else:
|
|
46
79
|
self.client = OpenAI(api_key=self.api_key, base_url=self.base_url)
|
|
47
80
|
except TypeError:
|
|
48
81
|
# Fallback: SDK version may not support default_headers
|
|
49
82
|
self.client = OpenAI(api_key=self.api_key, base_url=self.base_url)
|
|
50
83
|
if self.extra_headers:
|
|
51
|
-
|
|
52
|
-
|
|
84
|
+
PrettyOutput.auto_print(
|
|
85
|
+
"⚠️ 当前 OpenAI SDK 不支持 default_headers,未能注入额外 HTTP 头"
|
|
86
|
+
)
|
|
87
|
+
self.messages: List[ChatCompletionMessageParam] = []
|
|
53
88
|
self.system_message = ""
|
|
54
89
|
|
|
55
90
|
def upload_files(self, file_list: List[str]) -> bool:
|
|
@@ -81,7 +116,7 @@ class OpenAIModel(BasePlatform):
|
|
|
81
116
|
model_list.append((model.id, model.id))
|
|
82
117
|
return model_list
|
|
83
118
|
except Exception as e:
|
|
84
|
-
|
|
119
|
+
PrettyOutput.auto_print(f"❌ 获取模型列表失败:{str(e)}")
|
|
85
120
|
return []
|
|
86
121
|
|
|
87
122
|
def set_model_name(self, model_name: str):
|
|
@@ -126,26 +161,26 @@ class OpenAIModel(BasePlatform):
|
|
|
126
161
|
|
|
127
162
|
# 累计完整响应
|
|
128
163
|
accumulated_response = ""
|
|
129
|
-
|
|
164
|
+
|
|
130
165
|
# 循环处理,直到不是因为长度限制而结束
|
|
131
166
|
while True:
|
|
132
167
|
response = self.client.chat.completions.create(
|
|
133
168
|
model=self.model_name, # Use the configured model name
|
|
134
|
-
messages=self.messages,
|
|
169
|
+
messages=self.messages,
|
|
135
170
|
stream=True,
|
|
136
|
-
)
|
|
171
|
+
)
|
|
137
172
|
|
|
138
173
|
full_response = ""
|
|
139
174
|
finish_reason = None
|
|
140
|
-
|
|
175
|
+
|
|
141
176
|
for chunk in response:
|
|
142
177
|
if chunk.choices and len(chunk.choices) > 0:
|
|
143
178
|
choice = chunk.choices[0]
|
|
144
|
-
|
|
179
|
+
|
|
145
180
|
# 检查 finish_reason(通常在最后一个 chunk 中)
|
|
146
181
|
if choice.finish_reason:
|
|
147
182
|
finish_reason = choice.finish_reason
|
|
148
|
-
|
|
183
|
+
|
|
149
184
|
# 获取内容增量
|
|
150
185
|
if choice.delta and choice.delta.content:
|
|
151
186
|
text = choice.delta.content
|
|
@@ -158,11 +193,20 @@ class OpenAIModel(BasePlatform):
|
|
|
158
193
|
# 将已获取的内容追加到消息历史中,以便下次请求时模型知道已生成的内容
|
|
159
194
|
if self.messages and self.messages[-1].get("role") == "assistant":
|
|
160
195
|
# 追加到现有的 assistant 消息
|
|
161
|
-
self.messages[-1]["content"]
|
|
196
|
+
last_content = self.messages[-1]["content"]
|
|
197
|
+
if isinstance(last_content, str):
|
|
198
|
+
self.messages[-1]["content"] = last_content + full_response
|
|
199
|
+
else:
|
|
200
|
+
# 如果content不是字符串,创建新的消息
|
|
201
|
+
self.messages.append(
|
|
202
|
+
{"role": "assistant", "content": full_response}
|
|
203
|
+
)
|
|
162
204
|
else:
|
|
163
205
|
# 创建新的 assistant 消息
|
|
164
|
-
self.messages.append(
|
|
165
|
-
|
|
206
|
+
self.messages.append(
|
|
207
|
+
{"role": "assistant", "content": full_response}
|
|
208
|
+
)
|
|
209
|
+
|
|
166
210
|
# 添加一个继续请求的用户消息,让模型继续生成
|
|
167
211
|
self.messages.append({"role": "user", "content": "请继续。"})
|
|
168
212
|
# 继续循环,获取剩余内容
|
|
@@ -171,18 +215,35 @@ class OpenAIModel(BasePlatform):
|
|
|
171
215
|
# 正常结束(stop、null 或其他原因)
|
|
172
216
|
# 将完整响应添加到消息历史
|
|
173
217
|
if accumulated_response:
|
|
174
|
-
if
|
|
218
|
+
if (
|
|
219
|
+
self.messages
|
|
220
|
+
and self.messages[-1].get("role") == "assistant"
|
|
221
|
+
):
|
|
175
222
|
# 如果最后一条是 assistant 消息,追加本次的内容
|
|
176
|
-
self.messages[-1]["content"]
|
|
223
|
+
last_content = self.messages[-1]["content"]
|
|
224
|
+
if isinstance(last_content, str):
|
|
225
|
+
self.messages[-1]["content"] = (
|
|
226
|
+
last_content + full_response
|
|
227
|
+
)
|
|
228
|
+
else:
|
|
229
|
+
# 如果content不是字符串,创建新的消息
|
|
230
|
+
self.messages.append(
|
|
231
|
+
{
|
|
232
|
+
"role": "assistant",
|
|
233
|
+
"content": accumulated_response,
|
|
234
|
+
}
|
|
235
|
+
)
|
|
177
236
|
else:
|
|
178
237
|
# 创建新的 assistant 消息,使用累计的完整响应
|
|
179
|
-
self.messages.append(
|
|
238
|
+
self.messages.append(
|
|
239
|
+
{"role": "assistant", "content": accumulated_response}
|
|
240
|
+
)
|
|
180
241
|
break
|
|
181
242
|
|
|
182
243
|
return None
|
|
183
244
|
|
|
184
245
|
except Exception as e:
|
|
185
|
-
|
|
246
|
+
PrettyOutput.auto_print(f"❌ 对话失败:{str(e)}")
|
|
186
247
|
raise Exception(f"Chat failed: {str(e)}")
|
|
187
248
|
|
|
188
249
|
def name(self) -> str:
|
|
@@ -231,10 +292,10 @@ class OpenAIModel(BasePlatform):
|
|
|
231
292
|
with open(file_path, "w", encoding="utf-8") as f:
|
|
232
293
|
json.dump(state, f, ensure_ascii=False, indent=4)
|
|
233
294
|
self._saved = True
|
|
234
|
-
|
|
295
|
+
PrettyOutput.auto_print(f"✅ 会话已成功保存到 {file_path}")
|
|
235
296
|
return True
|
|
236
297
|
except Exception as e:
|
|
237
|
-
|
|
298
|
+
PrettyOutput.auto_print(f"❌ 保存会话失败: {str(e)}")
|
|
238
299
|
return False
|
|
239
300
|
|
|
240
301
|
def restore(self, file_path: str) -> bool:
|
|
@@ -248,13 +309,13 @@ class OpenAIModel(BasePlatform):
|
|
|
248
309
|
# atexit.register(self.delete_chat)
|
|
249
310
|
self._saved = True
|
|
250
311
|
|
|
251
|
-
|
|
312
|
+
PrettyOutput.auto_print(f"✅ 从 {file_path} 成功恢复会话")
|
|
252
313
|
return True
|
|
253
314
|
except FileNotFoundError:
|
|
254
|
-
|
|
315
|
+
PrettyOutput.auto_print(f"❌ 会话文件未找到: {file_path}")
|
|
255
316
|
return False
|
|
256
317
|
except Exception as e:
|
|
257
|
-
|
|
318
|
+
PrettyOutput.auto_print(f"❌ 恢复会话失败: {str(e)}")
|
|
258
319
|
return False
|
|
259
320
|
|
|
260
321
|
def support_web(self) -> bool:
|
|
@@ -278,20 +339,20 @@ class OpenAIModel(BasePlatform):
|
|
|
278
339
|
@classmethod
|
|
279
340
|
def get_required_env_keys(cls) -> List[str]:
|
|
280
341
|
"""
|
|
281
|
-
获取OpenAI
|
|
342
|
+
获取OpenAI平台所需的配置键列表(已弃用:建议使用 llm_config 配置)
|
|
282
343
|
|
|
283
344
|
返回:
|
|
284
|
-
List[str]:
|
|
345
|
+
List[str]: 配置键的列表(对应 llm_config 中的 openai_api_key, openai_api_base)
|
|
285
346
|
"""
|
|
286
347
|
return ["OPENAI_API_KEY", "OPENAI_API_BASE"]
|
|
287
348
|
|
|
288
349
|
@classmethod
|
|
289
350
|
def get_env_config_guide(cls) -> Dict[str, str]:
|
|
290
351
|
"""
|
|
291
|
-
|
|
352
|
+
获取配置指导(已弃用:建议使用 llm_config 配置)
|
|
292
353
|
|
|
293
354
|
返回:
|
|
294
|
-
Dict[str, str]:
|
|
355
|
+
Dict[str, str]: 配置键名到配置指导的映射
|
|
295
356
|
"""
|
|
296
357
|
return {
|
|
297
358
|
"OPENAI_API_KEY": (
|
|
@@ -3,18 +3,22 @@ import importlib
|
|
|
3
3
|
import inspect
|
|
4
4
|
import os
|
|
5
5
|
import sys
|
|
6
|
-
from typing import
|
|
6
|
+
from typing import Any
|
|
7
|
+
from typing import Dict
|
|
8
|
+
from typing import List
|
|
9
|
+
from typing import Optional
|
|
10
|
+
from typing import Type
|
|
7
11
|
|
|
8
12
|
from jarvis.jarvis_platform.base import BasePlatform
|
|
9
|
-
from jarvis.jarvis_utils.config import
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
from jarvis.jarvis_utils.config import get_cheap_model_name
|
|
14
|
+
from jarvis.jarvis_utils.config import get_cheap_platform_name
|
|
15
|
+
from jarvis.jarvis_utils.config import get_data_dir
|
|
16
|
+
from jarvis.jarvis_utils.config import get_llm_config
|
|
17
|
+
from jarvis.jarvis_utils.config import get_normal_model_name
|
|
18
|
+
from jarvis.jarvis_utils.config import get_normal_platform_name
|
|
19
|
+
from jarvis.jarvis_utils.config import get_smart_model_name
|
|
20
|
+
from jarvis.jarvis_utils.config import get_smart_platform_name
|
|
21
|
+
from jarvis.jarvis_utils.output import PrettyOutput
|
|
18
22
|
|
|
19
23
|
REQUIRED_METHODS = [
|
|
20
24
|
("chat", ["message"]), # 方法名和参数列表
|
|
@@ -45,7 +49,7 @@ class PlatformRegistry:
|
|
|
45
49
|
):
|
|
46
50
|
pass
|
|
47
51
|
except Exception as e:
|
|
48
|
-
|
|
52
|
+
PrettyOutput.auto_print(f"❌ 创建平台目录失败: {str(e)}")
|
|
49
53
|
return ""
|
|
50
54
|
return user_platform_dir
|
|
51
55
|
|
|
@@ -80,7 +84,9 @@ class PlatformRegistry:
|
|
|
80
84
|
missing_methods.append(f"{method_name}(parameter mismatch)")
|
|
81
85
|
|
|
82
86
|
if missing_methods:
|
|
83
|
-
|
|
87
|
+
PrettyOutput.auto_print(
|
|
88
|
+
f"⚠️ 平台 {platform_class.__name__} 缺少必要的方法: {', '.join(missing_methods)}"
|
|
89
|
+
)
|
|
84
90
|
return False
|
|
85
91
|
|
|
86
92
|
return True
|
|
@@ -99,7 +105,7 @@ class PlatformRegistry:
|
|
|
99
105
|
|
|
100
106
|
# 确保目录存在
|
|
101
107
|
if not os.path.exists(directory):
|
|
102
|
-
|
|
108
|
+
PrettyOutput.auto_print(f"⚠️ 平台目录不存在: {directory}")
|
|
103
109
|
return platforms
|
|
104
110
|
|
|
105
111
|
# 获取目录的包名
|
|
@@ -149,8 +155,8 @@ class PlatformRegistry:
|
|
|
149
155
|
error_lines.append(f"加载平台 {module_name} 失败: {str(e)}")
|
|
150
156
|
|
|
151
157
|
if error_lines:
|
|
152
|
-
joined_errors =
|
|
153
|
-
|
|
158
|
+
joined_errors = "\n".join(error_lines)
|
|
159
|
+
PrettyOutput.auto_print(f"❌ {joined_errors}")
|
|
154
160
|
return platforms
|
|
155
161
|
|
|
156
162
|
@staticmethod
|
|
@@ -179,28 +185,39 @@ class PlatformRegistry:
|
|
|
179
185
|
) in PlatformRegistry.load_platform_from_dir(platform_dir).items():
|
|
180
186
|
self.register_platform(platform_name, platform_class)
|
|
181
187
|
|
|
182
|
-
def get_normal_platform(
|
|
188
|
+
def get_normal_platform(
|
|
189
|
+
self, model_group_override: Optional[str] = None
|
|
190
|
+
) -> BasePlatform:
|
|
183
191
|
"""获取正常操作的平台实例"""
|
|
184
|
-
platform_name = get_normal_platform_name()
|
|
185
|
-
model_name = get_normal_model_name()
|
|
186
|
-
|
|
192
|
+
platform_name = get_normal_platform_name(model_group_override)
|
|
193
|
+
model_name = get_normal_model_name(model_group_override)
|
|
194
|
+
llm_config = get_llm_config("normal", model_group_override)
|
|
195
|
+
platform = self.create_platform(platform_name, llm_config)
|
|
187
196
|
platform.set_model_name(model_name) # type: ignore
|
|
188
197
|
return platform # type: ignore
|
|
189
198
|
|
|
190
|
-
def get_cheap_platform(
|
|
199
|
+
def get_cheap_platform(
|
|
200
|
+
self, model_group_override: Optional[str] = None
|
|
201
|
+
) -> BasePlatform:
|
|
191
202
|
"""获取廉价操作的平台实例"""
|
|
192
|
-
platform_name = get_cheap_platform_name()
|
|
193
|
-
model_name = get_cheap_model_name()
|
|
194
|
-
|
|
203
|
+
platform_name = get_cheap_platform_name(model_group_override)
|
|
204
|
+
model_name = get_cheap_model_name(model_group_override)
|
|
205
|
+
llm_config = get_llm_config("cheap", model_group_override)
|
|
206
|
+
platform = self.create_platform(platform_name, llm_config)
|
|
195
207
|
platform.set_model_name(model_name) # type: ignore
|
|
208
|
+
platform.set_platform_type("cheap") # type: ignore
|
|
196
209
|
return platform # type: ignore
|
|
197
210
|
|
|
198
|
-
def get_smart_platform(
|
|
211
|
+
def get_smart_platform(
|
|
212
|
+
self, model_group_override: Optional[str] = None
|
|
213
|
+
) -> BasePlatform:
|
|
199
214
|
"""获取智能操作的平台实例"""
|
|
200
|
-
platform_name = get_smart_platform_name()
|
|
201
|
-
model_name = get_smart_model_name()
|
|
202
|
-
|
|
215
|
+
platform_name = get_smart_platform_name(model_group_override)
|
|
216
|
+
model_name = get_smart_model_name(model_group_override)
|
|
217
|
+
llm_config = get_llm_config("smart", model_group_override)
|
|
218
|
+
platform = self.create_platform(platform_name, llm_config)
|
|
203
219
|
platform.set_model_name(model_name) # type: ignore
|
|
220
|
+
platform.set_platform_type("smart") # type: ignore
|
|
204
221
|
return platform # type: ignore
|
|
205
222
|
|
|
206
223
|
def register_platform(self, name: str, platform_class: Type[BasePlatform]) -> None:
|
|
@@ -212,26 +229,27 @@ class PlatformRegistry:
|
|
|
212
229
|
"""
|
|
213
230
|
self.platforms[name] = platform_class
|
|
214
231
|
|
|
215
|
-
def create_platform(
|
|
216
|
-
|
|
232
|
+
def create_platform(
|
|
233
|
+
self, name: str, llm_config: Optional[Dict[str, Any]] = None
|
|
234
|
+
) -> Optional[BasePlatform]:
|
|
217
235
|
"""Create platform instance
|
|
218
236
|
|
|
219
237
|
Args:
|
|
220
238
|
name: Platform name
|
|
239
|
+
llm_config: LLM配置字典,包含平台特定的配置参数(如 api_key, base_url 等)
|
|
221
240
|
|
|
222
241
|
Returns:
|
|
223
242
|
BasePlatform: Platform instance
|
|
224
243
|
"""
|
|
225
244
|
if name not in self.platforms:
|
|
226
|
-
|
|
245
|
+
PrettyOutput.auto_print(f"⚠️ 未找到平台: {name}")
|
|
227
246
|
return None
|
|
228
247
|
|
|
229
248
|
try:
|
|
230
|
-
|
|
231
|
-
platform = self.platforms[name]()
|
|
249
|
+
platform = self.platforms[name](llm_config=llm_config or {})
|
|
232
250
|
return platform
|
|
233
251
|
except Exception as e:
|
|
234
|
-
|
|
252
|
+
PrettyOutput.auto_print(f"❌ 创建平台失败: {str(e)}")
|
|
235
253
|
return None
|
|
236
254
|
|
|
237
255
|
def get_available_platforms(self) -> List[str]:
|