jarvis-ai-assistant 0.1.132__py3-none-any.whl → 0.1.138__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.
Potentially problematic release.
This version of jarvis-ai-assistant might be problematic. Click here for more details.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +330 -347
- jarvis/jarvis_agent/builtin_input_handler.py +16 -6
- jarvis/jarvis_agent/file_input_handler.py +9 -9
- jarvis/jarvis_agent/jarvis.py +143 -0
- jarvis/jarvis_agent/main.py +12 -13
- jarvis/jarvis_agent/output_handler.py +3 -3
- jarvis/jarvis_agent/patch.py +92 -64
- jarvis/jarvis_agent/shell_input_handler.py +5 -3
- jarvis/jarvis_code_agent/code_agent.py +263 -177
- jarvis/jarvis_code_agent/file_select.py +24 -24
- jarvis/jarvis_dev/main.py +45 -59
- jarvis/jarvis_git_details/__init__.py +0 -0
- jarvis/jarvis_git_details/main.py +179 -0
- jarvis/jarvis_git_squash/main.py +7 -7
- jarvis/jarvis_lsp/base.py +11 -53
- jarvis/jarvis_lsp/cpp.py +13 -28
- jarvis/jarvis_lsp/go.py +13 -28
- jarvis/jarvis_lsp/python.py +8 -27
- jarvis/jarvis_lsp/registry.py +21 -83
- jarvis/jarvis_lsp/rust.py +15 -30
- jarvis/jarvis_methodology/main.py +101 -0
- jarvis/jarvis_multi_agent/__init__.py +10 -51
- jarvis/jarvis_multi_agent/main.py +43 -0
- jarvis/jarvis_platform/__init__.py +1 -1
- jarvis/jarvis_platform/ai8.py +67 -89
- jarvis/jarvis_platform/base.py +14 -13
- jarvis/jarvis_platform/kimi.py +25 -28
- jarvis/jarvis_platform/ollama.py +24 -26
- jarvis/jarvis_platform/openai.py +15 -19
- jarvis/jarvis_platform/oyi.py +48 -50
- jarvis/jarvis_platform/registry.py +29 -44
- jarvis/jarvis_platform/yuanbao.py +39 -43
- jarvis/jarvis_platform_manager/main.py +81 -81
- jarvis/jarvis_platform_manager/openai_test.py +21 -21
- jarvis/jarvis_rag/file_processors.py +18 -18
- jarvis/jarvis_rag/main.py +262 -278
- jarvis/jarvis_smart_shell/main.py +12 -12
- jarvis/jarvis_tools/ask_codebase.py +85 -78
- jarvis/jarvis_tools/ask_user.py +8 -8
- jarvis/jarvis_tools/base.py +4 -4
- jarvis/jarvis_tools/chdir.py +9 -9
- jarvis/jarvis_tools/code_review.py +40 -21
- jarvis/jarvis_tools/create_code_agent.py +15 -15
- jarvis/jarvis_tools/create_sub_agent.py +0 -1
- jarvis/jarvis_tools/execute_python_script.py +3 -3
- jarvis/jarvis_tools/execute_shell.py +11 -11
- jarvis/jarvis_tools/execute_shell_script.py +3 -3
- jarvis/jarvis_tools/file_analyzer.py +116 -105
- jarvis/jarvis_tools/file_operation.py +22 -20
- jarvis/jarvis_tools/find_caller.py +105 -40
- jarvis/jarvis_tools/find_methodolopy.py +65 -0
- jarvis/jarvis_tools/find_symbol.py +123 -39
- jarvis/jarvis_tools/function_analyzer.py +140 -57
- jarvis/jarvis_tools/git_commiter.py +10 -10
- jarvis/jarvis_tools/lsp_get_diagnostics.py +19 -19
- jarvis/jarvis_tools/methodology.py +22 -67
- jarvis/jarvis_tools/project_analyzer.py +137 -53
- jarvis/jarvis_tools/rag.py +15 -20
- jarvis/jarvis_tools/read_code.py +25 -23
- jarvis/jarvis_tools/read_webpage.py +31 -31
- jarvis/jarvis_tools/registry.py +72 -52
- jarvis/jarvis_tools/search_web.py +23 -353
- jarvis/jarvis_tools/tool_generator.py +19 -19
- jarvis/jarvis_utils/config.py +36 -96
- jarvis/jarvis_utils/embedding.py +83 -83
- jarvis/jarvis_utils/git_utils.py +20 -20
- jarvis/jarvis_utils/globals.py +18 -6
- jarvis/jarvis_utils/input.py +10 -9
- jarvis/jarvis_utils/methodology.py +141 -140
- jarvis/jarvis_utils/output.py +13 -13
- jarvis/jarvis_utils/utils.py +23 -71
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/METADATA +6 -15
- jarvis_ai_assistant-0.1.138.dist-info/RECORD +85 -0
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/entry_points.txt +4 -3
- jarvis/jarvis_tools/lsp_find_definition.py +0 -150
- jarvis/jarvis_tools/lsp_find_references.py +0 -127
- jarvis/jarvis_tools/select_code_files.py +0 -62
- jarvis_ai_assistant-0.1.132.dist-info/RECORD +0 -82
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""
|
|
2
|
+
方法论导入导出命令行工具
|
|
3
|
+
|
|
4
|
+
功能:
|
|
5
|
+
- 导入方法论文件(合并策略)
|
|
6
|
+
- 导出当前方法论
|
|
7
|
+
- 列出所有方法论
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import hashlib
|
|
11
|
+
import os
|
|
12
|
+
import json
|
|
13
|
+
import argparse
|
|
14
|
+
from jarvis.jarvis_utils.methodology import (
|
|
15
|
+
_get_methodology_directory,
|
|
16
|
+
_load_all_methodologies
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
def import_methodology(input_file):
|
|
20
|
+
"""导入方法论文件(合并策略)"""
|
|
21
|
+
try:
|
|
22
|
+
# 加载现有方法论
|
|
23
|
+
existing_methodologies = _load_all_methodologies()
|
|
24
|
+
|
|
25
|
+
# 加载要导入的方法论
|
|
26
|
+
with open(input_file, "r", encoding="utf-8") as f:
|
|
27
|
+
import_data = json.load(f)
|
|
28
|
+
|
|
29
|
+
# 合并方法论(新数据会覆盖旧数据)
|
|
30
|
+
merged_data = {**existing_methodologies, **import_data}
|
|
31
|
+
|
|
32
|
+
# 保存合并后的方法论
|
|
33
|
+
methodology_dir = _get_methodology_directory()
|
|
34
|
+
for problem_type, content in merged_data.items():
|
|
35
|
+
safe_filename = hashlib.md5(problem_type.encode('utf-8')).hexdigest()
|
|
36
|
+
file_path = os.path.join(methodology_dir, f"{safe_filename}.json")
|
|
37
|
+
|
|
38
|
+
with open(file_path, "w", encoding="utf-8") as f:
|
|
39
|
+
json.dump({
|
|
40
|
+
"problem_type": problem_type,
|
|
41
|
+
"content": content
|
|
42
|
+
}, f, ensure_ascii=False, indent=2)
|
|
43
|
+
|
|
44
|
+
print(f"成功导入 {len(import_data)} 个方法论(总计 {len(merged_data)} 个)")
|
|
45
|
+
except (json.JSONDecodeError, OSError) as e:
|
|
46
|
+
print(f"导入失败: {str(e)}")
|
|
47
|
+
|
|
48
|
+
def export_methodology(output_file):
|
|
49
|
+
"""导出当前方法论到单个文件"""
|
|
50
|
+
try:
|
|
51
|
+
methodologies = _load_all_methodologies()
|
|
52
|
+
|
|
53
|
+
with open(output_file, "w", encoding="utf-8") as f:
|
|
54
|
+
json.dump(methodologies, f, ensure_ascii=False, indent=2)
|
|
55
|
+
|
|
56
|
+
print(f"成功导出 {len(methodologies)} 个方法论到 {output_file}")
|
|
57
|
+
except (OSError, TypeError) as e:
|
|
58
|
+
print(f"导出失败: {str(e)}")
|
|
59
|
+
|
|
60
|
+
def list_methodologies():
|
|
61
|
+
"""列出所有方法论"""
|
|
62
|
+
try:
|
|
63
|
+
methodologies = _load_all_methodologies()
|
|
64
|
+
|
|
65
|
+
if not methodologies:
|
|
66
|
+
print("没有找到方法论")
|
|
67
|
+
return
|
|
68
|
+
|
|
69
|
+
print("可用方法论:")
|
|
70
|
+
for i, (problem_type, _) in enumerate(methodologies.items(), 1):
|
|
71
|
+
print(f"{i}. {problem_type}")
|
|
72
|
+
except (OSError, json.JSONDecodeError) as e:
|
|
73
|
+
print(f"列出方法论失败: {str(e)}")
|
|
74
|
+
|
|
75
|
+
def main():
|
|
76
|
+
"""方法论管理工具主函数"""
|
|
77
|
+
parser = argparse.ArgumentParser(description="方法论管理工具")
|
|
78
|
+
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
79
|
+
|
|
80
|
+
# import命令
|
|
81
|
+
import_parser = subparsers.add_parser("import", help="导入方法论文件(合并策略)")
|
|
82
|
+
import_parser.add_argument("input_file", type=str, help="要导入的方法论文件路径")
|
|
83
|
+
|
|
84
|
+
# export命令
|
|
85
|
+
export_parser = subparsers.add_parser("export", help="导出当前方法论到单个文件")
|
|
86
|
+
export_parser.add_argument("output_file", type=str, help="导出文件路径")
|
|
87
|
+
|
|
88
|
+
# list命令
|
|
89
|
+
subparsers.add_parser("list", help="列出所有方法论")
|
|
90
|
+
|
|
91
|
+
args = parser.parse_args()
|
|
92
|
+
|
|
93
|
+
if args.command == "import":
|
|
94
|
+
import_methodology(args.input_file)
|
|
95
|
+
elif args.command == "export":
|
|
96
|
+
export_methodology(args.output_file)
|
|
97
|
+
elif args.command == "list":
|
|
98
|
+
list_methodologies()
|
|
99
|
+
|
|
100
|
+
if __name__ == "__main__":
|
|
101
|
+
main()
|
|
@@ -35,16 +35,16 @@ class MultiAgent(OutputHandler):
|
|
|
35
35
|
to: 智能体名称 # 目标智能体名称
|
|
36
36
|
content: |
|
|
37
37
|
# 消息主题
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
## 背景信息
|
|
40
40
|
[提供必要的上下文和背景]
|
|
41
|
-
|
|
41
|
+
|
|
42
42
|
## 具体需求
|
|
43
43
|
[明确表达期望完成的任务]
|
|
44
|
-
|
|
44
|
+
|
|
45
45
|
## 相关资源
|
|
46
46
|
[列出相关文档、数据或工具]
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
## 期望结果
|
|
49
49
|
[描述期望的输出格式和内容]
|
|
50
50
|
|
|
@@ -60,7 +60,7 @@ content: |
|
|
|
60
60
|
to: 智能体名称 # 目标智能体名称
|
|
61
61
|
content: |
|
|
62
62
|
# 消息主题
|
|
63
|
-
|
|
63
|
+
|
|
64
64
|
## 任务结果
|
|
65
65
|
[任务完成结果,用于反馈]
|
|
66
66
|
{ct("SEND_MESSAGE")}
|
|
@@ -74,22 +74,22 @@ content: |
|
|
|
74
74
|
return len(self._extract_send_msg(response)) > 0
|
|
75
75
|
|
|
76
76
|
|
|
77
|
-
def handle(self, response: str) -> Tuple[bool, Any]:
|
|
77
|
+
def handle(self, response: str, agent: Any) -> Tuple[bool, Any]:
|
|
78
78
|
send_messages = self._extract_send_msg(response)
|
|
79
79
|
if len(send_messages) > 1:
|
|
80
80
|
return False, f"Send multiple messages, please only send one message at a time."
|
|
81
81
|
if len(send_messages) == 0:
|
|
82
82
|
return False, ""
|
|
83
83
|
return True, send_messages[0]
|
|
84
|
-
|
|
84
|
+
|
|
85
85
|
def name(self) -> str:
|
|
86
86
|
return "SEND_MESSAGE"
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
|
|
88
|
+
|
|
89
89
|
@staticmethod
|
|
90
90
|
def _extract_send_msg(content: str) -> List[Dict]:
|
|
91
91
|
"""Extract send message from content.
|
|
92
|
-
|
|
92
|
+
|
|
93
93
|
Args:
|
|
94
94
|
content: The content containing send message
|
|
95
95
|
"""
|
|
@@ -139,44 +139,3 @@ content: {msg['content']}
|
|
|
139
139
|
msg = self.agents[msg['to']].run(prompt)
|
|
140
140
|
return ""
|
|
141
141
|
|
|
142
|
-
|
|
143
|
-
def main():
|
|
144
|
-
"""从YAML配置文件初始化并运行多智能体系统
|
|
145
|
-
|
|
146
|
-
Returns:
|
|
147
|
-
最终处理结果
|
|
148
|
-
"""
|
|
149
|
-
init_env()
|
|
150
|
-
import argparse
|
|
151
|
-
parser = argparse.ArgumentParser(description="多智能体系统启动器")
|
|
152
|
-
parser.add_argument("--config", "-c", required=True, help="YAML配置文件路径")
|
|
153
|
-
parser.add_argument("--input", "-i", help="用户输入(可选)")
|
|
154
|
-
args = parser.parse_args()
|
|
155
|
-
|
|
156
|
-
try:
|
|
157
|
-
with open(args.config, 'r', errors="ignore") as f:
|
|
158
|
-
config_data = yaml.safe_load(f)
|
|
159
|
-
|
|
160
|
-
# 获取agents配置
|
|
161
|
-
agents_config = config_data.get('agents', [])
|
|
162
|
-
|
|
163
|
-
main_agent_name = config_data.get('main_agent', '')
|
|
164
|
-
if not main_agent_name:
|
|
165
|
-
raise ValueError("必须指定main_agent作为主智能体")
|
|
166
|
-
|
|
167
|
-
# 创建并运行多智能体系统
|
|
168
|
-
multi_agent = MultiAgent(agents_config, main_agent_name)
|
|
169
|
-
user_input = args.input if args.input is not None else get_multiline_input("请输入内容(输入空行结束):")
|
|
170
|
-
if user_input == "":
|
|
171
|
-
return
|
|
172
|
-
return multi_agent.run(user_input)
|
|
173
|
-
|
|
174
|
-
except yaml.YAMLError as e:
|
|
175
|
-
raise ValueError(f"YAML配置文件解析错误: {str(e)}")
|
|
176
|
-
except Exception as e:
|
|
177
|
-
raise RuntimeError(f"多智能体系统初始化失败: {str(e)}")
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
if __name__ == "__main__":
|
|
181
|
-
result = main()
|
|
182
|
-
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import yaml
|
|
2
|
+
from jarvis.jarvis_multi_agent import MultiAgent
|
|
3
|
+
from jarvis.jarvis_utils.utils import init_env
|
|
4
|
+
from jarvis.jarvis_utils.input import get_multiline_input
|
|
5
|
+
|
|
6
|
+
def main():
|
|
7
|
+
"""从YAML配置文件初始化并运行多智能体系统
|
|
8
|
+
|
|
9
|
+
Returns:
|
|
10
|
+
最终处理结果
|
|
11
|
+
"""
|
|
12
|
+
init_env()
|
|
13
|
+
import argparse
|
|
14
|
+
parser = argparse.ArgumentParser(description="多智能体系统启动器")
|
|
15
|
+
parser.add_argument("--config", "-c", required=True, help="YAML配置文件路径")
|
|
16
|
+
parser.add_argument("--input", "-i", help="用户输入(可选)")
|
|
17
|
+
args = parser.parse_args()
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
with open(args.config, 'r', errors="ignore") as f:
|
|
21
|
+
config_data = yaml.safe_load(f)
|
|
22
|
+
|
|
23
|
+
# 获取agents配置
|
|
24
|
+
agents_config = config_data.get('agents', [])
|
|
25
|
+
|
|
26
|
+
main_agent_name = config_data.get('main_agent', '')
|
|
27
|
+
if not main_agent_name:
|
|
28
|
+
raise ValueError("必须指定main_agent作为主智能体")
|
|
29
|
+
|
|
30
|
+
# 创建并运行多智能体系统
|
|
31
|
+
multi_agent = MultiAgent(agents_config, main_agent_name)
|
|
32
|
+
user_input = args.input if args.input is not None else get_multiline_input("请输入内容(输入空行结束):")
|
|
33
|
+
if user_input == "":
|
|
34
|
+
return
|
|
35
|
+
return multi_agent.run(user_input)
|
|
36
|
+
|
|
37
|
+
except yaml.YAMLError as e:
|
|
38
|
+
raise ValueError(f"YAML配置文件解析错误: {str(e)}")
|
|
39
|
+
except Exception as e:
|
|
40
|
+
raise RuntimeError(f"多智能体系统初始化失败: {str(e)}")
|
|
41
|
+
|
|
42
|
+
if __name__ == "__main__":
|
|
43
|
+
result = main()
|
jarvis/jarvis_platform/ai8.py
CHANGED
|
@@ -9,7 +9,7 @@ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
|
9
9
|
|
|
10
10
|
class AI8Model(BasePlatform):
|
|
11
11
|
"""AI8 model implementation"""
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
platform_name = "ai8"
|
|
14
14
|
BASE_URL = "https://ai8.rcouyi.com"
|
|
15
15
|
|
|
@@ -17,7 +17,7 @@ class AI8Model(BasePlatform):
|
|
|
17
17
|
"""获取模型列表"""
|
|
18
18
|
self.get_available_models()
|
|
19
19
|
return [(name,info['desc']) for name,info in self.models.items()]
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
def __init__(self):
|
|
22
22
|
"""Initialize model"""
|
|
23
23
|
super().__init__()
|
|
@@ -28,48 +28,55 @@ class AI8Model(BasePlatform):
|
|
|
28
28
|
self.token = os.getenv("AI8_API_KEY")
|
|
29
29
|
if not self.token:
|
|
30
30
|
PrettyOutput.print("未设置 AI8_API_KEY", OutputType.WARNING)
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
|
|
32
|
+
self.headers = {
|
|
33
|
+
'Authorization': self.token,
|
|
34
|
+
'Content-Type': 'application/json',
|
|
35
|
+
'Accept': 'application/json, text/plain, */*',
|
|
36
|
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
|
|
37
|
+
'X-APP-VERSION': '2.3.0',
|
|
38
|
+
'Origin': self.BASE_URL,
|
|
39
|
+
'Referer': f'{self.BASE_URL}/chat?_userMenuKey=chat',
|
|
40
|
+
'Sec-Fetch-Site': 'same-origin',
|
|
41
|
+
'Sec-Fetch-Mode': 'cors',
|
|
42
|
+
'Sec-Fetch-Dest': 'empty',
|
|
43
|
+
}
|
|
44
|
+
|
|
33
45
|
self.model_name = os.getenv("JARVIS_MODEL") or "deepseek-chat"
|
|
34
46
|
if self.model_name not in self.get_available_models():
|
|
35
47
|
PrettyOutput.print(f"警告: 选择的模型 {self.model_name} 不在可用列表中", OutputType.WARNING)
|
|
36
|
-
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
37
51
|
|
|
38
52
|
def set_model_name(self, model_name: str):
|
|
39
53
|
"""Set model name"""
|
|
40
54
|
|
|
41
55
|
self.model_name = model_name
|
|
42
|
-
|
|
56
|
+
|
|
43
57
|
def create_conversation(self) -> bool:
|
|
44
58
|
"""Create a new conversation"""
|
|
45
59
|
try:
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
'Content-Type': 'application/json',
|
|
49
|
-
'Accept': 'application/json, text/plain, */*',
|
|
50
|
-
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
|
|
51
|
-
'X-APP-VERSION': '2.2.2',
|
|
52
|
-
'Origin': self.BASE_URL,
|
|
53
|
-
'Referer': f'{self.BASE_URL}/chat?_userMenuKey=chat'
|
|
54
|
-
}
|
|
55
|
-
|
|
60
|
+
|
|
61
|
+
|
|
56
62
|
# 1. 创建会话
|
|
57
63
|
response = requests.post(
|
|
58
64
|
f"{self.BASE_URL}/api/chat/session",
|
|
59
|
-
headers=headers
|
|
65
|
+
headers=self.headers,
|
|
66
|
+
json={}
|
|
60
67
|
)
|
|
61
|
-
|
|
68
|
+
|
|
62
69
|
if response.status_code != 200:
|
|
63
70
|
PrettyOutput.print(f"创建会话失败: {response.status_code}", OutputType.WARNING)
|
|
64
71
|
return False
|
|
65
|
-
|
|
72
|
+
|
|
66
73
|
data = response.json()
|
|
67
74
|
if data['code'] != 0:
|
|
68
75
|
PrettyOutput.print(f"创建会话失败: {data.get('msg', '未知错误')}", OutputType.WARNING)
|
|
69
76
|
return False
|
|
70
|
-
|
|
77
|
+
|
|
71
78
|
self.conversation = data['data']
|
|
72
|
-
|
|
79
|
+
|
|
73
80
|
# 2. 更新会话设置
|
|
74
81
|
session_data = {
|
|
75
82
|
**self.conversation,
|
|
@@ -80,13 +87,13 @@ class AI8Model(BasePlatform):
|
|
|
80
87
|
"localPlugins": None,
|
|
81
88
|
"useAppId": 0
|
|
82
89
|
}
|
|
83
|
-
|
|
90
|
+
|
|
84
91
|
response = requests.put(
|
|
85
92
|
f"{self.BASE_URL}/api/chat/session/{self.conversation['id']}",
|
|
86
|
-
headers=headers,
|
|
93
|
+
headers=self.headers,
|
|
87
94
|
json=session_data
|
|
88
95
|
)
|
|
89
|
-
|
|
96
|
+
|
|
90
97
|
if response.status_code == 200:
|
|
91
98
|
data = response.json()
|
|
92
99
|
if data['code'] == 0:
|
|
@@ -98,53 +105,45 @@ class AI8Model(BasePlatform):
|
|
|
98
105
|
else:
|
|
99
106
|
PrettyOutput.print(f"更新会话设置失败: {response.status_code}", OutputType.WARNING)
|
|
100
107
|
return False
|
|
101
|
-
|
|
108
|
+
|
|
102
109
|
except Exception as e:
|
|
103
110
|
PrettyOutput.print(f"创建会话失败: {str(e)}", OutputType.ERROR)
|
|
104
111
|
return False
|
|
105
|
-
|
|
112
|
+
|
|
106
113
|
def set_system_message(self, message: str):
|
|
107
114
|
"""Set system message"""
|
|
108
115
|
self.system_message = message
|
|
109
|
-
|
|
116
|
+
|
|
110
117
|
def chat(self, message: str) -> str:
|
|
111
118
|
"""Execute conversation"""
|
|
112
119
|
try:
|
|
113
|
-
|
|
120
|
+
|
|
114
121
|
# 确保有会话ID
|
|
115
122
|
if not self.conversation:
|
|
116
123
|
if not self.create_conversation():
|
|
117
124
|
raise Exception("Failed to create conversation")
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
'Content-Type': 'application/json',
|
|
122
|
-
'Accept': 'text/event-stream',
|
|
123
|
-
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
|
|
124
|
-
'X-APP-VERSION': '2.2.2',
|
|
125
|
-
'Origin': self.BASE_URL,
|
|
126
|
-
'Referer': f'{self.BASE_URL}/chat?_userMenuKey=chat'
|
|
127
|
-
}
|
|
128
|
-
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
|
|
129
128
|
payload = {
|
|
130
129
|
"text": message,
|
|
131
130
|
"sessionId": self.conversation['id'] if self.conversation else None,
|
|
132
131
|
"files": []
|
|
133
132
|
}
|
|
134
|
-
|
|
135
|
-
|
|
133
|
+
|
|
134
|
+
|
|
136
135
|
response = requests.post(
|
|
137
136
|
f"{self.BASE_URL}/api/chat/completions",
|
|
138
|
-
headers=headers,
|
|
137
|
+
headers=self.headers,
|
|
139
138
|
json=payload,
|
|
140
139
|
stream=True
|
|
141
140
|
)
|
|
142
|
-
|
|
141
|
+
|
|
143
142
|
if response.status_code != 200:
|
|
144
143
|
error_msg = f"Failed to chat: {response.status_code} {response.text}"
|
|
145
144
|
PrettyOutput.print(error_msg, OutputType.WARNING)
|
|
146
145
|
raise Exception(error_msg)
|
|
147
|
-
|
|
146
|
+
|
|
148
147
|
# 处理流式响应
|
|
149
148
|
full_response = ""
|
|
150
149
|
for line in response.iter_lines():
|
|
@@ -162,49 +161,37 @@ class AI8Model(BasePlatform):
|
|
|
162
161
|
|
|
163
162
|
except json.JSONDecodeError:
|
|
164
163
|
continue
|
|
165
|
-
|
|
164
|
+
|
|
166
165
|
if not self.suppress_output:
|
|
167
166
|
PrettyOutput.print_stream_end()
|
|
168
167
|
|
|
169
168
|
return full_response
|
|
170
|
-
|
|
169
|
+
|
|
171
170
|
except Exception as e:
|
|
172
171
|
PrettyOutput.print(f"对话异常: {str(e)}", OutputType.ERROR)
|
|
173
172
|
raise e
|
|
174
|
-
|
|
173
|
+
|
|
175
174
|
def name(self) -> str:
|
|
176
175
|
"""Return model name"""
|
|
177
176
|
return self.model_name
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
"""Reset model state"""
|
|
181
|
-
self.conversation = None
|
|
182
|
-
|
|
177
|
+
|
|
178
|
+
|
|
183
179
|
def delete_chat(self) -> bool:
|
|
184
180
|
"""Delete current chat session"""
|
|
185
181
|
try:
|
|
186
182
|
if not self.conversation:
|
|
187
183
|
return True
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
'Authorization': self.token,
|
|
191
|
-
'Content-Type': 'application/json',
|
|
192
|
-
'Accept': 'application/json, text/plain, */*',
|
|
193
|
-
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
|
|
194
|
-
'X-APP-VERSION': '2.2.2',
|
|
195
|
-
'Origin': self.BASE_URL,
|
|
196
|
-
'Referer': f'{self.BASE_URL}/chat?_userMenuKey=chat'
|
|
197
|
-
}
|
|
198
|
-
|
|
184
|
+
|
|
185
|
+
|
|
199
186
|
response = requests.delete(
|
|
200
187
|
f"{self.BASE_URL}/api/chat/session/{self.conversation['id']}",
|
|
201
|
-
headers=headers
|
|
188
|
+
headers=self.headers
|
|
202
189
|
)
|
|
203
|
-
|
|
190
|
+
|
|
204
191
|
if response.status_code == 200:
|
|
205
192
|
data = response.json()
|
|
206
193
|
if data['code'] == 0:
|
|
207
|
-
self.
|
|
194
|
+
self.conversation = None
|
|
208
195
|
return True
|
|
209
196
|
else:
|
|
210
197
|
error_msg = f"删除会话失败: {data.get('msg', '未知错误')}"
|
|
@@ -214,54 +201,45 @@ class AI8Model(BasePlatform):
|
|
|
214
201
|
error_msg = f"删除会话请求失败: {response.status_code}"
|
|
215
202
|
PrettyOutput.print(error_msg, OutputType.WARNING)
|
|
216
203
|
return False
|
|
217
|
-
|
|
204
|
+
|
|
218
205
|
except Exception as e:
|
|
219
206
|
PrettyOutput.print(f"删除会话失败: {str(e)}", OutputType.ERROR)
|
|
220
207
|
return False
|
|
221
|
-
|
|
208
|
+
|
|
222
209
|
def get_available_models(self) -> List[str]:
|
|
223
210
|
"""Get available model list
|
|
224
|
-
|
|
211
|
+
|
|
225
212
|
Returns:
|
|
226
213
|
List[str]: Available model name list
|
|
227
214
|
"""
|
|
228
215
|
try:
|
|
229
216
|
if self.models:
|
|
230
217
|
return list(self.models.keys())
|
|
231
|
-
|
|
232
|
-
headers = {
|
|
233
|
-
'Content-Type': 'application/json',
|
|
234
|
-
'Accept': 'application/json, text/plain, */*',
|
|
235
|
-
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
|
|
236
|
-
'X-APP-VERSION': '2.2.2',
|
|
237
|
-
'Origin': self.BASE_URL,
|
|
238
|
-
'Referer': f'{self.BASE_URL}/chat?_userMenuKey=chat'
|
|
239
|
-
}
|
|
240
|
-
|
|
218
|
+
|
|
241
219
|
response = requests.get(
|
|
242
220
|
f"{self.BASE_URL}/api/chat/tmpl",
|
|
243
|
-
headers=headers
|
|
221
|
+
headers=self.headers
|
|
244
222
|
)
|
|
245
|
-
|
|
223
|
+
|
|
246
224
|
if response.status_code != 200:
|
|
247
225
|
PrettyOutput.print(f"获取模型列表失败: {response.status_code}", OutputType.WARNING)
|
|
248
226
|
return []
|
|
249
|
-
|
|
227
|
+
|
|
250
228
|
data = response.json()
|
|
251
229
|
if data['code'] != 0:
|
|
252
230
|
PrettyOutput.print(f"获取模型列表失败: {data.get('msg', '未知错误')}", OutputType.WARNING)
|
|
253
231
|
return []
|
|
254
|
-
|
|
232
|
+
|
|
255
233
|
# 保存模型信息
|
|
256
234
|
self.models = {
|
|
257
|
-
model['value']: model
|
|
235
|
+
model['value']: model
|
|
258
236
|
for model in data['data']['models']
|
|
259
237
|
}
|
|
260
238
|
|
|
261
239
|
for model in self.models.values():
|
|
262
240
|
# 添加标签
|
|
263
241
|
model_str = f"{model['label']}"
|
|
264
|
-
|
|
242
|
+
|
|
265
243
|
# 添加特性标记
|
|
266
244
|
features = []
|
|
267
245
|
if model['attr'].get('multimodal'):
|
|
@@ -279,12 +257,12 @@ class AI8Model(BasePlatform):
|
|
|
279
257
|
model_str += f" - {model['attr']['note']}"
|
|
280
258
|
if features:
|
|
281
259
|
model_str += f" [{'|'.join(features)}]"
|
|
282
|
-
|
|
260
|
+
|
|
283
261
|
model['desc'] = model_str
|
|
284
|
-
|
|
262
|
+
|
|
285
263
|
return list(self.models.keys())
|
|
286
|
-
|
|
264
|
+
|
|
287
265
|
except Exception as e:
|
|
288
266
|
PrettyOutput.print(f"获取模型列表失败: {str(e)}", OutputType.ERROR)
|
|
289
267
|
return []
|
|
290
|
-
|
|
268
|
+
|
jarvis/jarvis_platform/base.py
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
2
|
import re
|
|
3
3
|
from typing import Dict, List, Tuple
|
|
4
|
+
from jarvis.jarvis_utils.globals import clear_read_file_record
|
|
4
5
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
5
6
|
from jarvis.jarvis_utils.utils import ct, ot, get_context_token_count, while_success, while_true
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
class BasePlatform(ABC):
|
|
9
10
|
"""Base class for large language models"""
|
|
10
|
-
|
|
11
|
+
|
|
11
12
|
def __init__(self):
|
|
12
13
|
"""Initialize model"""
|
|
13
14
|
self.suppress_output = True # 添加输出控制标志
|
|
@@ -20,7 +21,12 @@ class BasePlatform(ABC):
|
|
|
20
21
|
def set_model_name(self, model_name: str):
|
|
21
22
|
"""Set model name"""
|
|
22
23
|
raise NotImplementedError("set_model_name is not implemented")
|
|
23
|
-
|
|
24
|
+
|
|
25
|
+
def reset(self):
|
|
26
|
+
"""Reset model"""
|
|
27
|
+
clear_read_file_record()
|
|
28
|
+
self.delete_chat()
|
|
29
|
+
|
|
24
30
|
@abstractmethod
|
|
25
31
|
def chat(self, message: str) -> str:
|
|
26
32
|
"""Execute conversation"""
|
|
@@ -31,11 +37,11 @@ class BasePlatform(ABC):
|
|
|
31
37
|
import time
|
|
32
38
|
start_time = time.time()
|
|
33
39
|
response = self.chat(message)
|
|
34
|
-
|
|
40
|
+
|
|
35
41
|
end_time = time.time()
|
|
36
42
|
duration = end_time - start_time
|
|
37
43
|
char_count = len(response)
|
|
38
|
-
|
|
44
|
+
|
|
39
45
|
# Calculate token count and tokens per second
|
|
40
46
|
try:
|
|
41
47
|
token_count = get_context_token_count(response)
|
|
@@ -55,29 +61,24 @@ class BasePlatform(ABC):
|
|
|
55
61
|
# Keep original think tag handling
|
|
56
62
|
response = re.sub(ot("think")+r'.*?'+ct("think"), '', response, flags=re.DOTALL)
|
|
57
63
|
return response
|
|
58
|
-
|
|
64
|
+
|
|
59
65
|
return while_true(lambda: while_success(lambda: _chat(), 5), 5)
|
|
60
66
|
|
|
61
|
-
@abstractmethod
|
|
62
|
-
def reset(self):
|
|
63
|
-
"""Reset model"""
|
|
64
|
-
raise NotImplementedError("reset is not implemented")
|
|
65
|
-
|
|
66
67
|
@abstractmethod
|
|
67
68
|
def name(self) -> str:
|
|
68
69
|
"""Model name"""
|
|
69
70
|
raise NotImplementedError("name is not implemented")
|
|
70
|
-
|
|
71
|
+
|
|
71
72
|
@abstractmethod
|
|
72
73
|
def delete_chat(self)->bool:
|
|
73
74
|
"""Delete chat"""
|
|
74
75
|
raise NotImplementedError("delete_chat is not implemented")
|
|
75
|
-
|
|
76
|
+
|
|
76
77
|
@abstractmethod
|
|
77
78
|
def set_system_message(self, message: str):
|
|
78
79
|
"""Set system message"""
|
|
79
80
|
raise NotImplementedError("set_system_message is not implemented")
|
|
80
|
-
|
|
81
|
+
|
|
81
82
|
@abstractmethod
|
|
82
83
|
def get_model_list(self) -> List[Tuple[str, str]]:
|
|
83
84
|
"""Get model list"""
|