jarvis-ai-assistant 0.1.192__py3-none-any.whl → 0.1.194__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 (91) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +69 -37
  3. jarvis/jarvis_agent/builtin_input_handler.py +26 -4
  4. jarvis/jarvis_agent/jarvis.py +38 -22
  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 +93 -90
  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 +51 -35
  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 +293 -192
  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 +12 -3
  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 +81 -47
  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 +49 -21
  44. jarvis/jarvis_platform/human.py +5 -3
  45. jarvis/jarvis_platform/kimi.py +96 -72
  46. jarvis/jarvis_platform/openai.py +23 -28
  47. jarvis/jarvis_platform/registry.py +50 -33
  48. jarvis/jarvis_platform/tongyi.py +16 -10
  49. jarvis/jarvis_platform/yuanbao.py +205 -147
  50. jarvis/jarvis_platform_manager/main.py +4 -2
  51. jarvis/jarvis_smart_shell/main.py +35 -29
  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 +10 -13
  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 +42 -33
  66. jarvis/jarvis_tools/read_webpage.py +7 -16
  67. jarvis/jarvis_tools/registry.py +65 -32
  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 +96 -8
  73. jarvis/jarvis_utils/config.py +59 -32
  74. jarvis/jarvis_utils/embedding.py +17 -14
  75. jarvis/jarvis_utils/file_processors.py +16 -9
  76. jarvis/jarvis_utils/git_utils.py +140 -99
  77. jarvis/jarvis_utils/globals.py +1 -1
  78. jarvis/jarvis_utils/input.py +84 -52
  79. jarvis/jarvis_utils/methodology.py +28 -21
  80. jarvis/jarvis_utils/output.py +159 -78
  81. jarvis/jarvis_utils/tag.py +2 -1
  82. jarvis/jarvis_utils/utils.py +85 -51
  83. {jarvis_ai_assistant-0.1.192.dist-info → jarvis_ai_assistant-0.1.194.dist-info}/METADATA +337 -204
  84. jarvis_ai_assistant-0.1.194.dist-info/RECORD +97 -0
  85. jarvis/jarvis_agent/file_input_handler.py +0 -112
  86. jarvis/jarvis_event/__init__.py +0 -0
  87. jarvis_ai_assistant-0.1.192.dist-info/RECORD +0 -99
  88. {jarvis_ai_assistant-0.1.192.dist-info → jarvis_ai_assistant-0.1.194.dist-info}/WHEEL +0 -0
  89. {jarvis_ai_assistant-0.1.192.dist-info → jarvis_ai_assistant-0.1.194.dist-info}/entry_points.txt +0 -0
  90. {jarvis_ai_assistant-0.1.192.dist-info → jarvis_ai_assistant-0.1.194.dist-info}/licenses/LICENSE +0 -0
  91. {jarvis_ai_assistant-0.1.192.dist-info → jarvis_ai_assistant-0.1.194.dist-info}/top_level.txt +0 -0
@@ -17,8 +17,10 @@ import yaml # type: ignore
17
17
  from yaspin import yaspin # type: ignore
18
18
 
19
19
  from jarvis.jarvis_platform.registry import PlatformRegistry
20
- from jarvis.jarvis_utils.methodology import (_get_methodology_directory,
21
- _load_all_methodologies)
20
+ from jarvis.jarvis_utils.methodology import (
21
+ _get_methodology_directory,
22
+ _load_all_methodologies,
23
+ )
22
24
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
23
25
 
24
26
 
@@ -38,18 +40,24 @@ def import_methodology(input_file):
38
40
  # 保存合并后的方法论
39
41
  methodology_dir = _get_methodology_directory()
40
42
  for problem_type, content in merged_data.items():
41
- safe_filename = hashlib.md5(problem_type.encode('utf-8')).hexdigest()
43
+ safe_filename = hashlib.md5(problem_type.encode("utf-8")).hexdigest()
42
44
  file_path = os.path.join(methodology_dir, f"{safe_filename}.json")
43
45
 
44
46
  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
- print(f"成功导入 {len(import_data)} 个方法论(总计 {len(merged_data)} 个)")
47
+ json.dump(
48
+ {"problem_type": problem_type, "content": content},
49
+ f,
50
+ ensure_ascii=False,
51
+ indent=2,
52
+ )
53
+
54
+ PrettyOutput.print(
55
+ f"成功导入 {len(import_data)} 个方法论(总计 {len(merged_data)} 个)",
56
+ OutputType.SUCCESS,
57
+ )
51
58
  except (json.JSONDecodeError, OSError) as e:
52
- print(f"导入失败: {str(e)}")
59
+ PrettyOutput.print(f"导入失败: {str(e)}", OutputType.ERROR)
60
+
53
61
 
54
62
  def export_methodology(output_file):
55
63
  """导出当前方法论到单个文件"""
@@ -59,9 +67,13 @@ def export_methodology(output_file):
59
67
  with open(output_file, "w", encoding="utf-8") as f:
60
68
  json.dump(methodologies, f, ensure_ascii=False, indent=2)
61
69
 
62
- print(f"成功导出 {len(methodologies)} 个方法论到 {output_file}")
70
+ PrettyOutput.print(
71
+ f"成功导出 {len(methodologies)} 个方法论到 {output_file}",
72
+ OutputType.SUCCESS,
73
+ )
63
74
  except (OSError, TypeError) as e:
64
- print(f"导出失败: {str(e)}")
75
+ PrettyOutput.print(f"导出失败: {str(e)}", OutputType.ERROR)
76
+
65
77
 
66
78
  def list_methodologies():
67
79
  """列出所有方法论"""
@@ -69,14 +81,15 @@ def list_methodologies():
69
81
  methodologies = _load_all_methodologies()
70
82
 
71
83
  if not methodologies:
72
- print("没有找到方法论")
84
+ PrettyOutput.print("没有找到方法论", OutputType.INFO)
73
85
  return
74
86
 
75
- print("可用方法论:")
87
+ PrettyOutput.print("可用方法论:", OutputType.INFO)
76
88
  for i, (problem_type, _) in enumerate(methodologies.items(), 1):
77
- print(f"{i}. {problem_type}")
89
+ PrettyOutput.print(f"{i}. {problem_type}", OutputType.INFO)
78
90
  except (OSError, json.JSONDecodeError) as e:
79
- print(f"列出方法论失败: {str(e)}")
91
+ PrettyOutput.print(f"列出方法论失败: {str(e)}", OutputType.ERROR)
92
+
80
93
 
81
94
  def extract_methodology(input_file):
82
95
  """从文本文件中提取方法论"""
@@ -87,7 +100,7 @@ def extract_methodology(input_file):
87
100
 
88
101
  # 获取平台实例
89
102
  platform = PlatformRegistry().get_normal_platform()
90
-
103
+
91
104
  # 构建提取提示
92
105
  prompt = f"""请从以下文本中提取方法论:
93
106
 
@@ -127,21 +140,24 @@ def extract_methodology(input_file):
127
140
  return
128
141
 
129
142
  # 提取YAML部分
130
- methodologies_start = response.find('<methodologies>') + len('<methodologies>')
131
- methodologies_end = response.find('</methodologies>')
143
+ methodologies_start = response.find("<methodologies>") + len(
144
+ "<methodologies>"
145
+ )
146
+ methodologies_end = response.find("</methodologies>")
132
147
  if methodologies_start == -1 or methodologies_end == -1:
133
148
  spinner.text = "响应格式无效"
134
149
  spinner.fail("❌")
135
- PrettyOutput.print("大模型未返回有效的<methodologies>格式", OutputType.ERROR)
150
+ PrettyOutput.print(
151
+ "大模型未返回有效的<methodologies>格式", OutputType.ERROR
152
+ )
136
153
  return
137
-
154
+
138
155
  yaml_content = response[methodologies_start:methodologies_end].strip()
139
-
156
+
140
157
  try:
141
158
  data = yaml.safe_load(yaml_content)
142
159
  extracted_methodologies = {
143
- item['problem_type']: item['content']
144
- for item in data
160
+ item["problem_type"]: item["content"] for item in data
145
161
  }
146
162
  except (yaml.YAMLError, KeyError, TypeError) as e:
147
163
  spinner.text = "YAML解析失败"
@@ -164,19 +180,25 @@ def extract_methodology(input_file):
164
180
  # 保存合并后的方法论
165
181
  methodology_dir = _get_methodology_directory()
166
182
  for problem_type, content in merged_data.items():
167
- safe_filename = hashlib.md5(problem_type.encode('utf-8')).hexdigest()
183
+ safe_filename = hashlib.md5(problem_type.encode("utf-8")).hexdigest()
168
184
  file_path = os.path.join(methodology_dir, f"{safe_filename}.json")
169
185
 
170
186
  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)
187
+ json.dump(
188
+ {"problem_type": problem_type, "content": content},
189
+ f,
190
+ ensure_ascii=False,
191
+ indent=2,
192
+ )
193
+
194
+ PrettyOutput.print(
195
+ f"成功从文件提取 {len(extracted_methodologies)} 个方法论(总计 {len(merged_data)} 个)",
196
+ OutputType.SUCCESS,
197
+ )
177
198
  except Exception as e:
178
199
  PrettyOutput.print(f"提取失败: {str(e)}", OutputType.ERROR)
179
200
 
201
+
180
202
  def extract_methodology_from_url(url):
181
203
  """从URL提取方法论"""
182
204
  try:
@@ -184,7 +206,7 @@ def extract_methodology_from_url(url):
184
206
  platform = PlatformRegistry().get_normal_platform()
185
207
 
186
208
  platform.web = True
187
-
209
+
188
210
  # 构建提取提示
189
211
  prompt = f"""请从以下URL内容中提取方法论:
190
212
 
@@ -223,21 +245,24 @@ def extract_methodology_from_url(url):
223
245
  return
224
246
 
225
247
  # 提取YAML部分
226
- methodologies_start = response.find('<methodologies>') + len('<methodologies>')
227
- methodologies_end = response.find('</methodologies>')
248
+ methodologies_start = response.find("<methodologies>") + len(
249
+ "<methodologies>"
250
+ )
251
+ methodologies_end = response.find("</methodologies>")
228
252
  if methodologies_start == -1 or methodologies_end == -1:
229
253
  spinner.text = "响应格式无效"
230
254
  spinner.fail("❌")
231
- PrettyOutput.print("大模型未返回有效的<methodologies>格式", OutputType.ERROR)
255
+ PrettyOutput.print(
256
+ "大模型未返回有效的<methodologies>格式", OutputType.ERROR
257
+ )
232
258
  return
233
-
259
+
234
260
  yaml_content = response[methodologies_start:methodologies_end].strip()
235
-
261
+
236
262
  try:
237
263
  data = yaml.safe_load(yaml_content)
238
264
  extracted_methodologies = {
239
- item['problem_type']: item['content']
240
- for item in data
265
+ item["problem_type"]: item["content"] for item in data
241
266
  }
242
267
  except (yaml.YAMLError, KeyError, TypeError) as e:
243
268
  spinner.text = "YAML解析失败"
@@ -260,19 +285,25 @@ def extract_methodology_from_url(url):
260
285
  # 保存合并后的方法论
261
286
  methodology_dir = _get_methodology_directory()
262
287
  for problem_type, content in merged_data.items():
263
- safe_filename = hashlib.md5(problem_type.encode('utf-8')).hexdigest()
288
+ safe_filename = hashlib.md5(problem_type.encode("utf-8")).hexdigest()
264
289
  file_path = os.path.join(methodology_dir, f"{safe_filename}.json")
265
290
 
266
291
  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)
292
+ json.dump(
293
+ {"problem_type": problem_type, "content": content},
294
+ f,
295
+ ensure_ascii=False,
296
+ indent=2,
297
+ )
298
+
299
+ PrettyOutput.print(
300
+ f"成功从URL提取 {len(extracted_methodologies)} 个方法论(总计 {len(merged_data)} 个)",
301
+ OutputType.SUCCESS,
302
+ )
273
303
  except Exception as e:
274
304
  PrettyOutput.print(f"从URL提取失败: {str(e)}", OutputType.ERROR)
275
305
 
306
+
276
307
  def main():
277
308
  """方法论管理工具主函数"""
278
309
  parser = argparse.ArgumentParser(description="方法论管理工具")
@@ -291,7 +322,9 @@ def main():
291
322
 
292
323
  # extract命令
293
324
  extract_parser = subparsers.add_parser("extract", help="从文本文件中提取方法论")
294
- extract_parser.add_argument("input_file", type=str, help="要提取方法论的文本文件路径")
325
+ extract_parser.add_argument(
326
+ "input_file", type=str, help="要提取方法论的文本文件路径"
327
+ )
295
328
 
296
329
  # extract-url命令
297
330
  extract_url_parser = subparsers.add_parser("extract-url", help="从URL提取方法论")
@@ -310,5 +343,6 @@ def main():
310
343
  elif args.command == "extract-url":
311
344
  extract_methodology_from_url(args.url)
312
345
 
346
+
313
347
  if __name__ == "__main__":
314
348
  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"]
@@ -9,15 +9,16 @@ from rich.panel import Panel
9
9
  from rich.text import Text
10
10
  from yaspin import yaspin
11
11
 
12
- from jarvis.jarvis_utils.config import (get_max_input_token_count,
13
- get_pretty_output, is_print_prompt)
12
+ from jarvis.jarvis_utils.config import (
13
+ get_max_input_token_count,
14
+ get_pretty_output,
15
+ is_print_prompt,
16
+ )
14
17
  from jarvis.jarvis_utils.embedding import split_text_into_chunks
15
18
  from jarvis.jarvis_utils.globals import set_in_chat
16
19
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
17
20
  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,
20
- while_true)
21
+ from jarvis.jarvis_utils.utils import get_context_token_count, while_success, while_true
21
22
 
22
23
 
23
24
  class BasePlatform(ABC):
@@ -45,7 +46,7 @@ class BasePlatform(ABC):
45
46
  def chat(self, message: str) -> Generator[str, None, None]:
46
47
  """Execute conversation"""
47
48
  raise NotImplementedError("chat is not implemented")
48
-
49
+
49
50
  @abstractmethod
50
51
  def upload_files(self, file_list: List[str]) -> bool:
51
52
  raise NotImplementedError("upload_files is not implemented")
@@ -55,9 +56,9 @@ class BasePlatform(ABC):
55
56
  """Check if platform supports upload files"""
56
57
  return False
57
58
 
58
-
59
59
  def _chat(self, message: str):
60
60
  import time
61
+
61
62
  start_time = time.time()
62
63
 
63
64
  input_token_count = get_context_token_count(message)
@@ -70,28 +71,47 @@ class BasePlatform(ABC):
70
71
  prefix_prompt = f"""
71
72
  我将分多次提供大量内容,在我明确告诉你内容已经全部提供完毕之前,每次仅需要输出"已收到",明白请输出"开始接收输入"。
72
73
  """
73
- while_true(lambda: while_success(lambda: self.chat(prefix_prompt), 5), 5)
74
+ while_true(
75
+ lambda: while_success(lambda: self.chat(prefix_prompt), 5), 5
76
+ )
74
77
  submit_count = 0
75
78
  length = 0
76
79
  for input in inputs:
77
80
  submit_count += 1
78
81
  length += len(input)
79
82
  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)}")
83
+ list(
84
+ while_true(
85
+ lambda: while_success(
86
+ lambda: self.chat(
87
+ f"<part_content>{input}</part_content>请返回已收到"
88
+ ),
89
+ 5,
90
+ ),
91
+ 5,
92
+ )
93
+ )
94
+ spinner.write(
95
+ f"提交第{submit_count}部分完成,当前进度:{length}/{len(message)}"
96
+ )
82
97
  spinner.text = "提交完成"
83
98
  spinner.ok("✅")
84
- response = while_true(lambda: while_success(lambda: self._chat("内容已经全部提供完毕,请继续"), 5), 5)
99
+ response = while_true(
100
+ lambda: while_success(
101
+ lambda: self._chat("内容已经全部提供完毕,请继续"), 5
102
+ ),
103
+ 5,
104
+ )
85
105
  else:
86
106
  response = ""
87
107
 
88
108
  text_content = Text()
89
109
  panel = Panel(
90
- text_content,
91
- title=f"[bold cyan]{self.name()}[/bold cyan]",
92
- subtitle="[dim]思考中...[/dim]",
110
+ text_content,
111
+ title=f"[bold cyan]{self.name()}[/bold cyan]",
112
+ subtitle="[dim]思考中...[/dim]",
93
113
  border_style="bright_blue",
94
- box=box.ROUNDED
114
+ box=box.ROUNDED,
95
115
  )
96
116
 
97
117
  if not self.suppress_output:
@@ -108,9 +128,13 @@ class BasePlatform(ABC):
108
128
  # Calculate token count and tokens per second
109
129
  try:
110
130
  token_count = get_context_token_count(response)
111
- tokens_per_second = token_count / duration if duration > 0 else 0
131
+ tokens_per_second = (
132
+ token_count / duration if duration > 0 else 0
133
+ )
112
134
  except Exception as e:
113
- PrettyOutput.print(f"Tokenization failed: {str(e)}", OutputType.WARNING)
135
+ PrettyOutput.print(
136
+ f"Tokenization failed: {str(e)}", OutputType.WARNING
137
+ )
114
138
  token_count = 0
115
139
  tokens_per_second = 0
116
140
  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 +148,20 @@ class BasePlatform(ABC):
124
148
  for s in self.chat(message):
125
149
  response += s
126
150
  # Keep original think tag handling
127
- response = re.sub(ot("think")+r'.*?'+ct("think"), '', response, flags=re.DOTALL)
151
+ response = re.sub(
152
+ ot("think") + r".*?" + ct("think"), "", response, flags=re.DOTALL
153
+ )
128
154
  return response
129
-
155
+
130
156
  def chat_until_success(self, message: str) -> str:
131
157
  """Chat with model until successful response"""
132
158
  try:
133
159
  set_in_chat(True)
134
160
  if not self.suppress_output and is_print_prompt():
135
161
  PrettyOutput.print(f"{message}", OutputType.USER)
136
- result: str = while_true(lambda: while_success(lambda: self._chat(message), 5), 5)
162
+ result: str = while_true(
163
+ lambda: while_success(lambda: self._chat(message), 5), 5
164
+ )
137
165
  return result
138
166
  finally:
139
167
  set_in_chat(False)
@@ -144,7 +172,7 @@ class BasePlatform(ABC):
144
172
  raise NotImplementedError("name is not implemented")
145
173
 
146
174
  @abstractmethod
147
- def delete_chat(self)->bool:
175
+ def delete_chat(self) -> bool:
148
176
  """Delete chat"""
149
177
  raise NotImplementedError("delete_chat is not implemented")
150
178
 
@@ -39,7 +39,9 @@ class HumanPlatform(BasePlatform):
39
39
  def chat(self, message: str) -> Generator[str, None, None]:
40
40
  """发送消息并获取人类响应"""
41
41
  if not self.conversation_id:
42
- self.conversation_id = ''.join(random.choices(string.ascii_letters + string.digits, k=8))
42
+ self.conversation_id = "".join(
43
+ random.choices(string.ascii_letters + string.digits, k=8)
44
+ )
43
45
  session_info = f"(会话ID: {self.conversation_id})"
44
46
  else:
45
47
  session_info = f"(会话ID: {self.conversation_id})"
@@ -49,7 +51,7 @@ class HumanPlatform(BasePlatform):
49
51
  self.first_message = False
50
52
  else:
51
53
  prompt = f"{message} {session_info}\n\n请回复:"
52
-
54
+
53
55
  response = get_multiline_input(prompt)
54
56
  yield response
55
57
  return None
@@ -70,4 +72,4 @@ class HumanPlatform(BasePlatform):
70
72
  return self.model_name
71
73
 
72
74
  def support_web(self) -> bool:
73
- return False
75
+ return False