jarvis-ai-assistant 0.1.193__py3-none-any.whl → 0.1.195__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 +45 -41
- jarvis/jarvis_agent/builtin_input_handler.py +26 -4
- jarvis/jarvis_agent/jarvis.py +30 -19
- jarvis/jarvis_agent/main.py +20 -12
- jarvis/jarvis_agent/output_handler.py +7 -7
- jarvis/jarvis_agent/shell_input_handler.py +14 -11
- jarvis/jarvis_code_agent/code_agent.py +81 -79
- jarvis/jarvis_code_agent/lint.py +92 -105
- jarvis/jarvis_code_analysis/checklists/__init__.py +1 -1
- jarvis/jarvis_code_analysis/checklists/c_cpp.py +1 -1
- jarvis/jarvis_code_analysis/checklists/csharp.py +1 -1
- jarvis/jarvis_code_analysis/checklists/data_format.py +1 -1
- jarvis/jarvis_code_analysis/checklists/devops.py +1 -1
- jarvis/jarvis_code_analysis/checklists/docs.py +1 -1
- jarvis/jarvis_code_analysis/checklists/go.py +1 -1
- jarvis/jarvis_code_analysis/checklists/infrastructure.py +1 -1
- jarvis/jarvis_code_analysis/checklists/java.py +1 -1
- jarvis/jarvis_code_analysis/checklists/javascript.py +1 -1
- jarvis/jarvis_code_analysis/checklists/kotlin.py +1 -1
- jarvis/jarvis_code_analysis/checklists/loader.py +31 -29
- jarvis/jarvis_code_analysis/checklists/php.py +1 -1
- jarvis/jarvis_code_analysis/checklists/python.py +1 -1
- jarvis/jarvis_code_analysis/checklists/ruby.py +1 -1
- jarvis/jarvis_code_analysis/checklists/rust.py +1 -1
- jarvis/jarvis_code_analysis/checklists/shell.py +1 -1
- jarvis/jarvis_code_analysis/checklists/sql.py +1 -1
- jarvis/jarvis_code_analysis/checklists/swift.py +1 -1
- jarvis/jarvis_code_analysis/checklists/web.py +1 -1
- jarvis/jarvis_code_analysis/code_review.py +292 -190
- jarvis/jarvis_dev/main.py +73 -56
- jarvis/jarvis_git_details/main.py +29 -33
- jarvis/jarvis_git_squash/main.py +13 -11
- jarvis/jarvis_git_utils/git_commiter.py +15 -5
- jarvis/jarvis_mcp/__init__.py +8 -10
- jarvis/jarvis_mcp/sse_mcp_client.py +182 -205
- jarvis/jarvis_mcp/stdio_mcp_client.py +93 -120
- jarvis/jarvis_mcp/streamable_mcp_client.py +117 -142
- jarvis/jarvis_methodology/main.py +71 -39
- jarvis/jarvis_multi_agent/__init__.py +24 -16
- jarvis/jarvis_multi_agent/main.py +10 -4
- jarvis/jarvis_platform/__init__.py +1 -1
- jarvis/jarvis_platform/base.py +44 -18
- jarvis/jarvis_platform/human.py +15 -3
- jarvis/jarvis_platform/kimi.py +117 -81
- jarvis/jarvis_platform/openai.py +23 -28
- jarvis/jarvis_platform/registry.py +43 -29
- jarvis/jarvis_platform/tongyi.py +16 -10
- jarvis/jarvis_platform/yuanbao.py +197 -144
- jarvis/jarvis_platform_manager/main.py +4 -2
- jarvis/jarvis_smart_shell/main.py +35 -30
- jarvis/jarvis_tools/ask_user.py +8 -16
- jarvis/jarvis_tools/base.py +3 -2
- jarvis/jarvis_tools/chdir.py +7 -19
- jarvis/jarvis_tools/cli/main.py +14 -10
- jarvis/jarvis_tools/code_plan.py +10 -31
- jarvis/jarvis_tools/create_code_agent.py +6 -11
- jarvis/jarvis_tools/create_sub_agent.py +10 -22
- jarvis/jarvis_tools/edit_file.py +98 -76
- jarvis/jarvis_tools/execute_script.py +46 -46
- jarvis/jarvis_tools/file_analyzer.py +22 -34
- jarvis/jarvis_tools/file_operation.py +69 -62
- jarvis/jarvis_tools/generate_new_tool.py +0 -2
- jarvis/jarvis_tools/methodology.py +19 -23
- jarvis/jarvis_tools/read_code.py +35 -35
- jarvis/jarvis_tools/read_webpage.py +7 -16
- jarvis/jarvis_tools/registry.py +63 -30
- jarvis/jarvis_tools/rewrite_file.py +26 -29
- jarvis/jarvis_tools/search_web.py +5 -8
- jarvis/jarvis_tools/virtual_tty.py +133 -122
- jarvis/jarvis_utils/__init__.py +0 -1
- jarvis/jarvis_utils/builtin_replace_map.py +9 -9
- jarvis/jarvis_utils/config.py +60 -37
- jarvis/jarvis_utils/embedding.py +24 -19
- jarvis/jarvis_utils/file_processors.py +16 -9
- jarvis/jarvis_utils/git_utils.py +157 -107
- jarvis/jarvis_utils/globals.py +1 -1
- jarvis/jarvis_utils/input.py +85 -52
- jarvis/jarvis_utils/jarvis_history.py +43 -0
- jarvis/jarvis_utils/methodology.py +31 -24
- jarvis/jarvis_utils/output.py +164 -80
- jarvis/jarvis_utils/tag.py +2 -1
- jarvis/jarvis_utils/utils.py +84 -52
- {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/METADATA +362 -230
- jarvis_ai_assistant-0.1.195.dist-info/RECORD +98 -0
- jarvis/jarvis_agent/file_input_handler.py +0 -112
- jarvis/jarvis_event/__init__.py +0 -0
- jarvis_ai_assistant-0.1.193.dist-info/RECORD +0 -99
- {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/top_level.txt +0 -0
@@ -38,19 +38,25 @@ def import_methodology(input_file):
|
|
38
38
|
# 保存合并后的方法论
|
39
39
|
methodology_dir = _get_methodology_directory()
|
40
40
|
for problem_type, content in merged_data.items():
|
41
|
-
safe_filename = hashlib.md5(problem_type.encode(
|
41
|
+
safe_filename = hashlib.md5(problem_type.encode("utf-8")).hexdigest()
|
42
42
|
file_path = os.path.join(methodology_dir, f"{safe_filename}.json")
|
43
43
|
|
44
44
|
with open(file_path, "w", encoding="utf-8") as f:
|
45
|
-
json.dump(
|
46
|
-
"problem_type": problem_type,
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
45
|
+
json.dump(
|
46
|
+
{"problem_type": problem_type, "content": content},
|
47
|
+
f,
|
48
|
+
ensure_ascii=False,
|
49
|
+
indent=2,
|
50
|
+
)
|
51
|
+
|
52
|
+
PrettyOutput.print(
|
53
|
+
f"成功导入 {len(import_data)} 个方法论(总计 {len(merged_data)} 个)",
|
54
|
+
OutputType.SUCCESS,
|
55
|
+
)
|
51
56
|
except (json.JSONDecodeError, OSError) as e:
|
52
57
|
PrettyOutput.print(f"导入失败: {str(e)}", OutputType.ERROR)
|
53
58
|
|
59
|
+
|
54
60
|
def export_methodology(output_file):
|
55
61
|
"""导出当前方法论到单个文件"""
|
56
62
|
try:
|
@@ -59,10 +65,14 @@ def export_methodology(output_file):
|
|
59
65
|
with open(output_file, "w", encoding="utf-8") as f:
|
60
66
|
json.dump(methodologies, f, ensure_ascii=False, indent=2)
|
61
67
|
|
62
|
-
PrettyOutput.print(
|
68
|
+
PrettyOutput.print(
|
69
|
+
f"成功导出 {len(methodologies)} 个方法论到 {output_file}",
|
70
|
+
OutputType.SUCCESS,
|
71
|
+
)
|
63
72
|
except (OSError, TypeError) as e:
|
64
73
|
PrettyOutput.print(f"导出失败: {str(e)}", OutputType.ERROR)
|
65
74
|
|
75
|
+
|
66
76
|
def list_methodologies():
|
67
77
|
"""列出所有方法论"""
|
68
78
|
try:
|
@@ -78,6 +88,7 @@ def list_methodologies():
|
|
78
88
|
except (OSError, json.JSONDecodeError) as e:
|
79
89
|
PrettyOutput.print(f"列出方法论失败: {str(e)}", OutputType.ERROR)
|
80
90
|
|
91
|
+
|
81
92
|
def extract_methodology(input_file):
|
82
93
|
"""从文本文件中提取方法论"""
|
83
94
|
try:
|
@@ -87,7 +98,7 @@ def extract_methodology(input_file):
|
|
87
98
|
|
88
99
|
# 获取平台实例
|
89
100
|
platform = PlatformRegistry().get_normal_platform()
|
90
|
-
|
101
|
+
|
91
102
|
# 构建提取提示
|
92
103
|
prompt = f"""请从以下文本中提取方法论:
|
93
104
|
|
@@ -127,21 +138,24 @@ def extract_methodology(input_file):
|
|
127
138
|
return
|
128
139
|
|
129
140
|
# 提取YAML部分
|
130
|
-
methodologies_start = response.find(
|
131
|
-
|
141
|
+
methodologies_start = response.find("<methodologies>") + len(
|
142
|
+
"<methodologies>"
|
143
|
+
)
|
144
|
+
methodologies_end = response.find("</methodologies>")
|
132
145
|
if methodologies_start == -1 or methodologies_end == -1:
|
133
146
|
spinner.text = "响应格式无效"
|
134
147
|
spinner.fail("❌")
|
135
|
-
PrettyOutput.print(
|
148
|
+
PrettyOutput.print(
|
149
|
+
"大模型未返回有效的<methodologies>格式", OutputType.ERROR
|
150
|
+
)
|
136
151
|
return
|
137
|
-
|
152
|
+
|
138
153
|
yaml_content = response[methodologies_start:methodologies_end].strip()
|
139
|
-
|
154
|
+
|
140
155
|
try:
|
141
156
|
data = yaml.safe_load(yaml_content)
|
142
157
|
extracted_methodologies = {
|
143
|
-
item[
|
144
|
-
for item in data
|
158
|
+
item["problem_type"]: item["content"] for item in data
|
145
159
|
}
|
146
160
|
except (yaml.YAMLError, KeyError, TypeError) as e:
|
147
161
|
spinner.text = "YAML解析失败"
|
@@ -164,19 +178,25 @@ def extract_methodology(input_file):
|
|
164
178
|
# 保存合并后的方法论
|
165
179
|
methodology_dir = _get_methodology_directory()
|
166
180
|
for problem_type, content in merged_data.items():
|
167
|
-
safe_filename = hashlib.md5(problem_type.encode(
|
181
|
+
safe_filename = hashlib.md5(problem_type.encode("utf-8")).hexdigest()
|
168
182
|
file_path = os.path.join(methodology_dir, f"{safe_filename}.json")
|
169
183
|
|
170
184
|
with open(file_path, "w", encoding="utf-8") as f:
|
171
|
-
json.dump(
|
172
|
-
"problem_type": problem_type,
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
185
|
+
json.dump(
|
186
|
+
{"problem_type": problem_type, "content": content},
|
187
|
+
f,
|
188
|
+
ensure_ascii=False,
|
189
|
+
indent=2,
|
190
|
+
)
|
191
|
+
|
192
|
+
PrettyOutput.print(
|
193
|
+
f"成功从文件提取 {len(extracted_methodologies)} 个方法论(总计 {len(merged_data)} 个)",
|
194
|
+
OutputType.SUCCESS,
|
195
|
+
)
|
177
196
|
except Exception as e:
|
178
197
|
PrettyOutput.print(f"提取失败: {str(e)}", OutputType.ERROR)
|
179
198
|
|
199
|
+
|
180
200
|
def extract_methodology_from_url(url):
|
181
201
|
"""从URL提取方法论"""
|
182
202
|
try:
|
@@ -184,7 +204,7 @@ def extract_methodology_from_url(url):
|
|
184
204
|
platform = PlatformRegistry().get_normal_platform()
|
185
205
|
|
186
206
|
platform.web = True
|
187
|
-
|
207
|
+
|
188
208
|
# 构建提取提示
|
189
209
|
prompt = f"""请从以下URL内容中提取方法论:
|
190
210
|
|
@@ -223,21 +243,24 @@ def extract_methodology_from_url(url):
|
|
223
243
|
return
|
224
244
|
|
225
245
|
# 提取YAML部分
|
226
|
-
methodologies_start = response.find(
|
227
|
-
|
246
|
+
methodologies_start = response.find("<methodologies>") + len(
|
247
|
+
"<methodologies>"
|
248
|
+
)
|
249
|
+
methodologies_end = response.find("</methodologies>")
|
228
250
|
if methodologies_start == -1 or methodologies_end == -1:
|
229
251
|
spinner.text = "响应格式无效"
|
230
252
|
spinner.fail("❌")
|
231
|
-
PrettyOutput.print(
|
253
|
+
PrettyOutput.print(
|
254
|
+
"大模型未返回有效的<methodologies>格式", OutputType.ERROR
|
255
|
+
)
|
232
256
|
return
|
233
|
-
|
257
|
+
|
234
258
|
yaml_content = response[methodologies_start:methodologies_end].strip()
|
235
|
-
|
259
|
+
|
236
260
|
try:
|
237
261
|
data = yaml.safe_load(yaml_content)
|
238
262
|
extracted_methodologies = {
|
239
|
-
item[
|
240
|
-
for item in data
|
263
|
+
item["problem_type"]: item["content"] for item in data
|
241
264
|
}
|
242
265
|
except (yaml.YAMLError, KeyError, TypeError) as e:
|
243
266
|
spinner.text = "YAML解析失败"
|
@@ -260,19 +283,25 @@ def extract_methodology_from_url(url):
|
|
260
283
|
# 保存合并后的方法论
|
261
284
|
methodology_dir = _get_methodology_directory()
|
262
285
|
for problem_type, content in merged_data.items():
|
263
|
-
safe_filename = hashlib.md5(problem_type.encode(
|
286
|
+
safe_filename = hashlib.md5(problem_type.encode("utf-8")).hexdigest()
|
264
287
|
file_path = os.path.join(methodology_dir, f"{safe_filename}.json")
|
265
288
|
|
266
289
|
with open(file_path, "w", encoding="utf-8") as f:
|
267
|
-
json.dump(
|
268
|
-
"problem_type": problem_type,
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
290
|
+
json.dump(
|
291
|
+
{"problem_type": problem_type, "content": content},
|
292
|
+
f,
|
293
|
+
ensure_ascii=False,
|
294
|
+
indent=2,
|
295
|
+
)
|
296
|
+
|
297
|
+
PrettyOutput.print(
|
298
|
+
f"成功从URL提取 {len(extracted_methodologies)} 个方法论(总计 {len(merged_data)} 个)",
|
299
|
+
OutputType.SUCCESS,
|
300
|
+
)
|
273
301
|
except Exception as e:
|
274
302
|
PrettyOutput.print(f"从URL提取失败: {str(e)}", OutputType.ERROR)
|
275
303
|
|
304
|
+
|
276
305
|
def main():
|
277
306
|
"""方法论管理工具主函数"""
|
278
307
|
parser = argparse.ArgumentParser(description="方法论管理工具")
|
@@ -291,7 +320,9 @@ def main():
|
|
291
320
|
|
292
321
|
# extract命令
|
293
322
|
extract_parser = subparsers.add_parser("extract", help="从文本文件中提取方法论")
|
294
|
-
extract_parser.add_argument(
|
323
|
+
extract_parser.add_argument(
|
324
|
+
"input_file", type=str, help="要提取方法论的文本文件路径"
|
325
|
+
)
|
295
326
|
|
296
327
|
# extract-url命令
|
297
328
|
extract_url_parser = subparsers.add_parser("extract-url", help="从URL提取方法论")
|
@@ -310,5 +341,6 @@ def main():
|
|
310
341
|
elif args.command == "extract-url":
|
311
342
|
extract_methodology_from_url(args.url)
|
312
343
|
|
344
|
+
|
313
345
|
if __name__ == "__main__":
|
314
346
|
main()
|
@@ -67,11 +67,13 @@ content: |2
|
|
67
67
|
def can_handle(self, response: str) -> bool:
|
68
68
|
return len(self._extract_send_msg(response)) > 0
|
69
69
|
|
70
|
-
|
71
70
|
def handle(self, response: str, agent: Any) -> Tuple[bool, Any]:
|
72
71
|
send_messages = self._extract_send_msg(response)
|
73
72
|
if len(send_messages) > 1:
|
74
|
-
return
|
73
|
+
return (
|
74
|
+
False,
|
75
|
+
f"Send multiple messages, please only send one message at a time.",
|
76
|
+
)
|
75
77
|
if len(send_messages) == 0:
|
76
78
|
return False, ""
|
77
79
|
return True, send_messages[0]
|
@@ -79,7 +81,6 @@ content: |2
|
|
79
81
|
def name(self) -> str:
|
80
82
|
return "SEND_MESSAGE"
|
81
83
|
|
82
|
-
|
83
84
|
@staticmethod
|
84
85
|
def _extract_send_msg(content: str) -> List[Dict]:
|
85
86
|
"""Extract send message from content.
|
@@ -87,12 +88,14 @@ content: |2
|
|
87
88
|
Args:
|
88
89
|
content: The content containing send message
|
89
90
|
"""
|
90
|
-
data = re.findall(
|
91
|
+
data = re.findall(
|
92
|
+
ot("SEND_MESSAGE") + r"\n(.*?)\n" + ct("SEND_MESSAGE"), content, re.DOTALL
|
93
|
+
)
|
91
94
|
ret = []
|
92
95
|
for item in data:
|
93
96
|
try:
|
94
97
|
msg = yaml.safe_load(item)
|
95
|
-
if
|
98
|
+
if "to" in msg and "content" in msg:
|
96
99
|
ret.append(msg)
|
97
100
|
except Exception as e:
|
98
101
|
continue
|
@@ -100,7 +103,7 @@ content: |2
|
|
100
103
|
|
101
104
|
def init_agents(self):
|
102
105
|
for config in self.agents_config:
|
103
|
-
output_handler = config.get(
|
106
|
+
output_handler = config.get("output_handler", [])
|
104
107
|
if len(output_handler) == 0:
|
105
108
|
output_handler = [
|
106
109
|
ToolRegistry(),
|
@@ -108,9 +111,9 @@ content: |2
|
|
108
111
|
]
|
109
112
|
else:
|
110
113
|
output_handler.append(self)
|
111
|
-
config[
|
114
|
+
config["output_handler"] = output_handler
|
112
115
|
agent = Agent(**config)
|
113
|
-
self.agents[config[
|
116
|
+
self.agents[config["name"]] = agent
|
114
117
|
|
115
118
|
def run(self, user_input: str) -> str:
|
116
119
|
last_agent = self.main_agent_name
|
@@ -119,17 +122,22 @@ content: |2
|
|
119
122
|
if isinstance(msg, str):
|
120
123
|
return msg
|
121
124
|
elif isinstance(msg, Dict):
|
122
|
-
prompt
|
125
|
+
prompt = f"""
|
123
126
|
Please handle this message:
|
124
127
|
from: {last_agent}
|
125
128
|
content: {msg['content']}
|
126
129
|
"""
|
127
|
-
if msg[
|
128
|
-
PrettyOutput.print(
|
129
|
-
|
130
|
+
if msg["to"] not in self.agents:
|
131
|
+
PrettyOutput.print(
|
132
|
+
f"未找到智能体 {msg['to']},正在重试...", OutputType.WARNING
|
133
|
+
)
|
134
|
+
msg = self.agents[last_agent].run(
|
135
|
+
f"未找到智能体 {msg['to']},可用智能体列表: {self.agents.keys()}"
|
136
|
+
)
|
130
137
|
continue
|
131
|
-
PrettyOutput.print(
|
132
|
-
|
133
|
-
|
138
|
+
PrettyOutput.print(
|
139
|
+
f"{last_agent} 正在向 {msg['to']} 发送消息...", OutputType.INFO
|
140
|
+
)
|
141
|
+
last_agent = self.agents[msg["to"]].name
|
142
|
+
msg = self.agents[msg["to"]].run(prompt)
|
134
143
|
return ""
|
135
|
-
|
@@ -14,25 +14,30 @@ def main():
|
|
14
14
|
"""
|
15
15
|
init_env("欢迎使用 Jarvis-MultiAgent,您的多智能体系统已准备就绪!")
|
16
16
|
import argparse
|
17
|
+
|
17
18
|
parser = argparse.ArgumentParser(description="多智能体系统启动器")
|
18
19
|
parser.add_argument("--config", "-c", required=True, help="YAML配置文件路径")
|
19
20
|
parser.add_argument("--input", "-i", help="用户输入(可选)")
|
20
21
|
args = parser.parse_args()
|
21
22
|
|
22
23
|
try:
|
23
|
-
with open(args.config,
|
24
|
+
with open(args.config, "r", errors="ignore") as f:
|
24
25
|
config_data = yaml.safe_load(f)
|
25
26
|
|
26
27
|
# 获取agents配置
|
27
|
-
agents_config = config_data.get(
|
28
|
+
agents_config = config_data.get("agents", [])
|
28
29
|
|
29
|
-
main_agent_name = config_data.get(
|
30
|
+
main_agent_name = config_data.get("main_agent", "")
|
30
31
|
if not main_agent_name:
|
31
32
|
raise ValueError("必须指定main_agent作为主智能体")
|
32
33
|
|
33
34
|
# 创建并运行多智能体系统
|
34
35
|
multi_agent = MultiAgent(agents_config, main_agent_name)
|
35
|
-
user_input =
|
36
|
+
user_input = (
|
37
|
+
args.input
|
38
|
+
if args.input is not None
|
39
|
+
else get_multiline_input("请输入内容(输入空行结束):")
|
40
|
+
)
|
36
41
|
if user_input == "":
|
37
42
|
return
|
38
43
|
return multi_agent.run(user_input)
|
@@ -42,5 +47,6 @@ def main():
|
|
42
47
|
except Exception as e:
|
43
48
|
raise RuntimeError(f"多智能体系统初始化失败: {str(e)}")
|
44
49
|
|
50
|
+
|
45
51
|
if __name__ == "__main__":
|
46
52
|
result = main()
|
jarvis/jarvis_platform/base.py
CHANGED
@@ -15,8 +15,7 @@ from jarvis.jarvis_utils.embedding import split_text_into_chunks
|
|
15
15
|
from jarvis.jarvis_utils.globals import set_in_chat
|
16
16
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
17
17
|
from jarvis.jarvis_utils.tag import ct, ot
|
18
|
-
from jarvis.jarvis_utils.utils import (get_context_token_count,
|
19
|
-
is_context_overflow, while_success,
|
18
|
+
from jarvis.jarvis_utils.utils import (get_context_token_count, while_success,
|
20
19
|
while_true)
|
21
20
|
|
22
21
|
|
@@ -45,7 +44,7 @@ class BasePlatform(ABC):
|
|
45
44
|
def chat(self, message: str) -> Generator[str, None, None]:
|
46
45
|
"""Execute conversation"""
|
47
46
|
raise NotImplementedError("chat is not implemented")
|
48
|
-
|
47
|
+
|
49
48
|
@abstractmethod
|
50
49
|
def upload_files(self, file_list: List[str]) -> bool:
|
51
50
|
raise NotImplementedError("upload_files is not implemented")
|
@@ -55,9 +54,9 @@ class BasePlatform(ABC):
|
|
55
54
|
"""Check if platform supports upload files"""
|
56
55
|
return False
|
57
56
|
|
58
|
-
|
59
57
|
def _chat(self, message: str):
|
60
58
|
import time
|
59
|
+
|
61
60
|
start_time = time.time()
|
62
61
|
|
63
62
|
input_token_count = get_context_token_count(message)
|
@@ -70,28 +69,47 @@ class BasePlatform(ABC):
|
|
70
69
|
prefix_prompt = f"""
|
71
70
|
我将分多次提供大量内容,在我明确告诉你内容已经全部提供完毕之前,每次仅需要输出"已收到",明白请输出"开始接收输入"。
|
72
71
|
"""
|
73
|
-
while_true(
|
72
|
+
while_true(
|
73
|
+
lambda: while_success(lambda: self.chat(prefix_prompt), 5), 5
|
74
|
+
)
|
74
75
|
submit_count = 0
|
75
76
|
length = 0
|
76
77
|
for input in inputs:
|
77
78
|
submit_count += 1
|
78
79
|
length += len(input)
|
79
80
|
spinner.text = f"正在提交第{submit_count}部分(共{len(inputs)}部分({length}/{len(message)}))"
|
80
|
-
list(
|
81
|
-
|
81
|
+
list(
|
82
|
+
while_true(
|
83
|
+
lambda: while_success(
|
84
|
+
lambda: self.chat(
|
85
|
+
f"<part_content>{input}</part_content>请返回已收到"
|
86
|
+
),
|
87
|
+
5,
|
88
|
+
),
|
89
|
+
5,
|
90
|
+
)
|
91
|
+
)
|
92
|
+
spinner.write(
|
93
|
+
f"提交第{submit_count}部分完成,当前进度:{length}/{len(message)}"
|
94
|
+
)
|
82
95
|
spinner.text = "提交完成"
|
83
96
|
spinner.ok("✅")
|
84
|
-
response = while_true(
|
97
|
+
response = while_true(
|
98
|
+
lambda: while_success(
|
99
|
+
lambda: self._chat("内容已经全部提供完毕,请继续"), 5
|
100
|
+
),
|
101
|
+
5,
|
102
|
+
)
|
85
103
|
else:
|
86
104
|
response = ""
|
87
105
|
|
88
106
|
text_content = Text()
|
89
107
|
panel = Panel(
|
90
|
-
text_content,
|
91
|
-
title=f"[bold cyan]{self.name()}[/bold cyan]",
|
92
|
-
subtitle="[dim]思考中...[/dim]",
|
108
|
+
text_content,
|
109
|
+
title=f"[bold cyan]{self.name()}[/bold cyan]",
|
110
|
+
subtitle="[dim]思考中...[/dim]",
|
93
111
|
border_style="bright_blue",
|
94
|
-
box=box.ROUNDED
|
112
|
+
box=box.ROUNDED,
|
95
113
|
)
|
96
114
|
|
97
115
|
if not self.suppress_output:
|
@@ -108,9 +126,13 @@ class BasePlatform(ABC):
|
|
108
126
|
# Calculate token count and tokens per second
|
109
127
|
try:
|
110
128
|
token_count = get_context_token_count(response)
|
111
|
-
tokens_per_second =
|
129
|
+
tokens_per_second = (
|
130
|
+
token_count / duration if duration > 0 else 0
|
131
|
+
)
|
112
132
|
except Exception as e:
|
113
|
-
PrettyOutput.print(
|
133
|
+
PrettyOutput.print(
|
134
|
+
f"Tokenization failed: {str(e)}", OutputType.WARNING
|
135
|
+
)
|
114
136
|
token_count = 0
|
115
137
|
tokens_per_second = 0
|
116
138
|
panel.subtitle = f"[bold green]✓ 对话完成耗时: {duration:.2f}秒, 输入字符数: {len(message)}, 输入Token数量: {input_token_count}, 输出字符数: {char_count}, 输出Token数量: {token_count}, 每秒Token数量: {tokens_per_second:.2f}[/bold green]"
|
@@ -124,16 +146,20 @@ class BasePlatform(ABC):
|
|
124
146
|
for s in self.chat(message):
|
125
147
|
response += s
|
126
148
|
# Keep original think tag handling
|
127
|
-
response = re.sub(
|
149
|
+
response = re.sub(
|
150
|
+
ot("think") + r".*?" + ct("think"), "", response, flags=re.DOTALL
|
151
|
+
)
|
128
152
|
return response
|
129
|
-
|
153
|
+
|
130
154
|
def chat_until_success(self, message: str) -> str:
|
131
155
|
"""Chat with model until successful response"""
|
132
156
|
try:
|
133
157
|
set_in_chat(True)
|
134
158
|
if not self.suppress_output and is_print_prompt():
|
135
159
|
PrettyOutput.print(f"{message}", OutputType.USER)
|
136
|
-
result: str = while_true(
|
160
|
+
result: str = while_true(
|
161
|
+
lambda: while_success(lambda: self._chat(message), 5), 5
|
162
|
+
)
|
137
163
|
return result
|
138
164
|
finally:
|
139
165
|
set_in_chat(False)
|
@@ -144,7 +170,7 @@ class BasePlatform(ABC):
|
|
144
170
|
raise NotImplementedError("name is not implemented")
|
145
171
|
|
146
172
|
@abstractmethod
|
147
|
-
def delete_chat(self)->bool:
|
173
|
+
def delete_chat(self) -> bool:
|
148
174
|
"""Delete chat"""
|
149
175
|
raise NotImplementedError("delete_chat is not implemented")
|
150
176
|
|
jarvis/jarvis_platform/human.py
CHANGED
@@ -1,4 +1,9 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
# 人类交互平台实现模块
|
4
|
+
|
5
|
+
# 提供与真实人类交互的模拟接口
|
6
|
+
|
2
7
|
import random
|
3
8
|
import string
|
4
9
|
from typing import Generator, List, Tuple
|
@@ -39,7 +44,9 @@ class HumanPlatform(BasePlatform):
|
|
39
44
|
def chat(self, message: str) -> Generator[str, None, None]:
|
40
45
|
"""发送消息并获取人类响应"""
|
41
46
|
if not self.conversation_id:
|
42
|
-
self.conversation_id =
|
47
|
+
self.conversation_id = "".join(
|
48
|
+
random.choices(string.ascii_letters + string.digits, k=8)
|
49
|
+
)
|
43
50
|
session_info = f"(会话ID: {self.conversation_id})"
|
44
51
|
else:
|
45
52
|
session_info = f"(会话ID: {self.conversation_id})"
|
@@ -49,7 +56,7 @@ class HumanPlatform(BasePlatform):
|
|
49
56
|
self.first_message = False
|
50
57
|
else:
|
51
58
|
prompt = f"{message} {session_info}\n\n请回复:"
|
52
|
-
|
59
|
+
|
53
60
|
response = get_multiline_input(prompt)
|
54
61
|
yield response
|
55
62
|
return None
|
@@ -70,4 +77,9 @@ class HumanPlatform(BasePlatform):
|
|
70
77
|
return self.model_name
|
71
78
|
|
72
79
|
def support_web(self) -> bool:
|
73
|
-
|
80
|
+
"""是否支持网页浏览功能"""
|
81
|
+
return False
|
82
|
+
|
83
|
+
def support_upload_files(self) -> bool:
|
84
|
+
"""是否支持文件上传功能"""
|
85
|
+
return False
|