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.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +69 -37
- jarvis/jarvis_agent/builtin_input_handler.py +26 -4
- jarvis/jarvis_agent/jarvis.py +38 -22
- 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 +93 -90
- 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 +51 -35
- 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 +293 -192
- 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 +12 -3
- 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 +81 -47
- 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 +49 -21
- jarvis/jarvis_platform/human.py +5 -3
- jarvis/jarvis_platform/kimi.py +96 -72
- jarvis/jarvis_platform/openai.py +23 -28
- jarvis/jarvis_platform/registry.py +50 -33
- jarvis/jarvis_platform/tongyi.py +16 -10
- jarvis/jarvis_platform/yuanbao.py +205 -147
- jarvis/jarvis_platform_manager/main.py +4 -2
- jarvis/jarvis_smart_shell/main.py +35 -29
- 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 +10 -13
- 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 +42 -33
- jarvis/jarvis_tools/read_webpage.py +7 -16
- jarvis/jarvis_tools/registry.py +65 -32
- 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 +96 -8
- jarvis/jarvis_utils/config.py +59 -32
- jarvis/jarvis_utils/embedding.py +17 -14
- jarvis/jarvis_utils/file_processors.py +16 -9
- jarvis/jarvis_utils/git_utils.py +140 -99
- jarvis/jarvis_utils/globals.py +1 -1
- jarvis/jarvis_utils/input.py +84 -52
- jarvis/jarvis_utils/methodology.py +28 -21
- jarvis/jarvis_utils/output.py +159 -78
- jarvis/jarvis_utils/tag.py +2 -1
- jarvis/jarvis_utils/utils.py +85 -51
- {jarvis_ai_assistant-0.1.192.dist-info → jarvis_ai_assistant-0.1.194.dist-info}/METADATA +337 -204
- jarvis_ai_assistant-0.1.194.dist-info/RECORD +97 -0
- jarvis/jarvis_agent/file_input_handler.py +0 -112
- jarvis/jarvis_event/__init__.py +0 -0
- jarvis_ai_assistant-0.1.192.dist-info/RECORD +0 -99
- {jarvis_ai_assistant-0.1.192.dist-info → jarvis_ai_assistant-0.1.194.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.192.dist-info → jarvis_ai_assistant-0.1.194.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.192.dist-info → jarvis_ai_assistant-0.1.194.dist-info}/licenses/LICENSE +0 -0
- {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 (
|
21
|
-
|
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(
|
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
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
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(
|
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(
|
131
|
-
|
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(
|
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[
|
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(
|
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
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
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(
|
227
|
-
|
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(
|
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[
|
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(
|
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
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
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(
|
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
|
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
@@ -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 (
|
13
|
-
|
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
|
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(
|
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(
|
81
|
-
|
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(
|
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 =
|
131
|
+
tokens_per_second = (
|
132
|
+
token_count / duration if duration > 0 else 0
|
133
|
+
)
|
112
134
|
except Exception as e:
|
113
|
-
PrettyOutput.print(
|
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(
|
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(
|
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
|
|
jarvis/jarvis_platform/human.py
CHANGED
@@ -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 =
|
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
|