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.
Files changed (92) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +45 -41
  3. jarvis/jarvis_agent/builtin_input_handler.py +26 -4
  4. jarvis/jarvis_agent/jarvis.py +30 -19
  5. jarvis/jarvis_agent/main.py +20 -12
  6. jarvis/jarvis_agent/output_handler.py +7 -7
  7. jarvis/jarvis_agent/shell_input_handler.py +14 -11
  8. jarvis/jarvis_code_agent/code_agent.py +81 -79
  9. jarvis/jarvis_code_agent/lint.py +92 -105
  10. jarvis/jarvis_code_analysis/checklists/__init__.py +1 -1
  11. jarvis/jarvis_code_analysis/checklists/c_cpp.py +1 -1
  12. jarvis/jarvis_code_analysis/checklists/csharp.py +1 -1
  13. jarvis/jarvis_code_analysis/checklists/data_format.py +1 -1
  14. jarvis/jarvis_code_analysis/checklists/devops.py +1 -1
  15. jarvis/jarvis_code_analysis/checklists/docs.py +1 -1
  16. jarvis/jarvis_code_analysis/checklists/go.py +1 -1
  17. jarvis/jarvis_code_analysis/checklists/infrastructure.py +1 -1
  18. jarvis/jarvis_code_analysis/checklists/java.py +1 -1
  19. jarvis/jarvis_code_analysis/checklists/javascript.py +1 -1
  20. jarvis/jarvis_code_analysis/checklists/kotlin.py +1 -1
  21. jarvis/jarvis_code_analysis/checklists/loader.py +31 -29
  22. jarvis/jarvis_code_analysis/checklists/php.py +1 -1
  23. jarvis/jarvis_code_analysis/checklists/python.py +1 -1
  24. jarvis/jarvis_code_analysis/checklists/ruby.py +1 -1
  25. jarvis/jarvis_code_analysis/checklists/rust.py +1 -1
  26. jarvis/jarvis_code_analysis/checklists/shell.py +1 -1
  27. jarvis/jarvis_code_analysis/checklists/sql.py +1 -1
  28. jarvis/jarvis_code_analysis/checklists/swift.py +1 -1
  29. jarvis/jarvis_code_analysis/checklists/web.py +1 -1
  30. jarvis/jarvis_code_analysis/code_review.py +292 -190
  31. jarvis/jarvis_dev/main.py +73 -56
  32. jarvis/jarvis_git_details/main.py +29 -33
  33. jarvis/jarvis_git_squash/main.py +13 -11
  34. jarvis/jarvis_git_utils/git_commiter.py +15 -5
  35. jarvis/jarvis_mcp/__init__.py +8 -10
  36. jarvis/jarvis_mcp/sse_mcp_client.py +182 -205
  37. jarvis/jarvis_mcp/stdio_mcp_client.py +93 -120
  38. jarvis/jarvis_mcp/streamable_mcp_client.py +117 -142
  39. jarvis/jarvis_methodology/main.py +71 -39
  40. jarvis/jarvis_multi_agent/__init__.py +24 -16
  41. jarvis/jarvis_multi_agent/main.py +10 -4
  42. jarvis/jarvis_platform/__init__.py +1 -1
  43. jarvis/jarvis_platform/base.py +44 -18
  44. jarvis/jarvis_platform/human.py +15 -3
  45. jarvis/jarvis_platform/kimi.py +117 -81
  46. jarvis/jarvis_platform/openai.py +23 -28
  47. jarvis/jarvis_platform/registry.py +43 -29
  48. jarvis/jarvis_platform/tongyi.py +16 -10
  49. jarvis/jarvis_platform/yuanbao.py +197 -144
  50. jarvis/jarvis_platform_manager/main.py +4 -2
  51. jarvis/jarvis_smart_shell/main.py +35 -30
  52. jarvis/jarvis_tools/ask_user.py +8 -16
  53. jarvis/jarvis_tools/base.py +3 -2
  54. jarvis/jarvis_tools/chdir.py +7 -19
  55. jarvis/jarvis_tools/cli/main.py +14 -10
  56. jarvis/jarvis_tools/code_plan.py +10 -31
  57. jarvis/jarvis_tools/create_code_agent.py +6 -11
  58. jarvis/jarvis_tools/create_sub_agent.py +10 -22
  59. jarvis/jarvis_tools/edit_file.py +98 -76
  60. jarvis/jarvis_tools/execute_script.py +46 -46
  61. jarvis/jarvis_tools/file_analyzer.py +22 -34
  62. jarvis/jarvis_tools/file_operation.py +69 -62
  63. jarvis/jarvis_tools/generate_new_tool.py +0 -2
  64. jarvis/jarvis_tools/methodology.py +19 -23
  65. jarvis/jarvis_tools/read_code.py +35 -35
  66. jarvis/jarvis_tools/read_webpage.py +7 -16
  67. jarvis/jarvis_tools/registry.py +63 -30
  68. jarvis/jarvis_tools/rewrite_file.py +26 -29
  69. jarvis/jarvis_tools/search_web.py +5 -8
  70. jarvis/jarvis_tools/virtual_tty.py +133 -122
  71. jarvis/jarvis_utils/__init__.py +0 -1
  72. jarvis/jarvis_utils/builtin_replace_map.py +9 -9
  73. jarvis/jarvis_utils/config.py +60 -37
  74. jarvis/jarvis_utils/embedding.py +24 -19
  75. jarvis/jarvis_utils/file_processors.py +16 -9
  76. jarvis/jarvis_utils/git_utils.py +157 -107
  77. jarvis/jarvis_utils/globals.py +1 -1
  78. jarvis/jarvis_utils/input.py +85 -52
  79. jarvis/jarvis_utils/jarvis_history.py +43 -0
  80. jarvis/jarvis_utils/methodology.py +31 -24
  81. jarvis/jarvis_utils/output.py +164 -80
  82. jarvis/jarvis_utils/tag.py +2 -1
  83. jarvis/jarvis_utils/utils.py +84 -52
  84. {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/METADATA +362 -230
  85. jarvis_ai_assistant-0.1.195.dist-info/RECORD +98 -0
  86. jarvis/jarvis_agent/file_input_handler.py +0 -112
  87. jarvis/jarvis_event/__init__.py +0 -0
  88. jarvis_ai_assistant-0.1.193.dist-info/RECORD +0 -99
  89. {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/WHEEL +0 -0
  90. {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/entry_points.txt +0 -0
  91. {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/licenses/LICENSE +0 -0
  92. {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('utf-8')).hexdigest()
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
- "content": content
48
- }, f, ensure_ascii=False, indent=2)
49
-
50
- PrettyOutput.print(f"成功导入 {len(import_data)} 个方法论(总计 {len(merged_data)} 个)", OutputType.SUCCESS)
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(f"成功导出 {len(methodologies)} 个方法论到 {output_file}", OutputType.SUCCESS)
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('<methodologies>') + len('<methodologies>')
131
- methodologies_end = response.find('</methodologies>')
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("大模型未返回有效的<methodologies>格式", OutputType.ERROR)
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['problem_type']: item['content']
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('utf-8')).hexdigest()
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
- "content": content
174
- }, f, ensure_ascii=False, indent=2)
175
-
176
- PrettyOutput.print(f"成功从文件提取 {len(extracted_methodologies)} 个方法论(总计 {len(merged_data)} 个)", OutputType.SUCCESS)
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('<methodologies>') + len('<methodologies>')
227
- methodologies_end = response.find('</methodologies>')
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("大模型未返回有效的<methodologies>格式", OutputType.ERROR)
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['problem_type']: item['content']
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('utf-8')).hexdigest()
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
- "content": content
270
- }, f, ensure_ascii=False, indent=2)
271
-
272
- PrettyOutput.print(f"成功从URL提取 {len(extracted_methodologies)} 个方法论(总计 {len(merged_data)} 个)", OutputType.SUCCESS)
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("input_file", type=str, help="要提取方法论的文本文件路径")
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 False, f"Send multiple messages, please only send one message at a time."
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(ot("SEND_MESSAGE")+r'\n(.*?)\n'+ct("SEND_MESSAGE"), content, re.DOTALL)
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 'to' in msg and 'content' in msg:
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('output_handler', [])
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['output_handler'] = output_handler
114
+ config["output_handler"] = output_handler
112
115
  agent = Agent(**config)
113
- self.agents[config['name']] = agent
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 = f"""
125
+ prompt = f"""
123
126
  Please handle this message:
124
127
  from: {last_agent}
125
128
  content: {msg['content']}
126
129
  """
127
- if msg['to'] not in self.agents:
128
- PrettyOutput.print(f"未找到智能体 {msg['to']},正在重试...", OutputType.WARNING)
129
- msg = self.agents[last_agent].run(f"未找到智能体 {msg['to']},可用智能体列表: {self.agents.keys()}")
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(f"{last_agent} 正在向 {msg['to']} 发送消息...", OutputType.INFO)
132
- last_agent = self.agents[msg['to']].name
133
- msg = self.agents[msg['to']].run(prompt)
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, 'r', errors="ignore") as f:
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('agents', [])
28
+ agents_config = config_data.get("agents", [])
28
29
 
29
- main_agent_name = config_data.get('main_agent', '')
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 = args.input if args.input is not None else get_multiline_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()
@@ -1,4 +1,4 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  from jarvis.jarvis_platform.base import BasePlatform
3
3
 
4
- __all__ = ['BasePlatform']
4
+ __all__ = ["BasePlatform"]
@@ -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(lambda: while_success(lambda: self.chat(prefix_prompt), 5), 5)
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(while_true(lambda: while_success(lambda: self.chat(f"<part_content>{input}</part_content>请返回已收到"), 5), 5))
81
- spinner.write(f"提交第{submit_count}部分完成,当前进度:{length}/{len(message)}")
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(lambda: while_success(lambda: self._chat("内容已经全部提供完毕,请继续"), 5), 5)
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 = token_count / duration if duration > 0 else 0
129
+ tokens_per_second = (
130
+ token_count / duration if duration > 0 else 0
131
+ )
112
132
  except Exception as e:
113
- PrettyOutput.print(f"Tokenization failed: {str(e)}", OutputType.WARNING)
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(ot("think")+r'.*?'+ct("think"), '', response, flags=re.DOTALL)
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(lambda: while_success(lambda: self._chat(message), 5), 5)
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
 
@@ -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 = ''.join(random.choices(string.ascii_letters + string.digits, k=8))
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
- return False
80
+ """是否支持网页浏览功能"""
81
+ return False
82
+
83
+ def support_upload_files(self) -> bool:
84
+ """是否支持文件上传功能"""
85
+ return False