jarvis-ai-assistant 0.1.93__py3-none-any.whl → 0.1.97__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of jarvis-ai-assistant might be problematic. Click here for more details.

Files changed (41) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/agent.py +138 -144
  3. jarvis/jarvis_codebase/main.py +87 -54
  4. jarvis/jarvis_coder/git_utils.py +4 -7
  5. jarvis/jarvis_coder/main.py +17 -22
  6. jarvis/jarvis_coder/patch_handler.py +141 -442
  7. jarvis/jarvis_coder/plan_generator.py +64 -36
  8. jarvis/jarvis_platform/main.py +1 -1
  9. jarvis/jarvis_rag/main.py +1 -1
  10. jarvis/jarvis_smart_shell/main.py +15 -15
  11. jarvis/main.py +24 -24
  12. jarvis/models/ai8.py +22 -22
  13. jarvis/models/base.py +17 -13
  14. jarvis/models/kimi.py +31 -31
  15. jarvis/models/ollama.py +28 -28
  16. jarvis/models/openai.py +22 -24
  17. jarvis/models/oyi.py +25 -25
  18. jarvis/models/registry.py +33 -34
  19. jarvis/tools/ask_user.py +5 -5
  20. jarvis/tools/base.py +2 -2
  21. jarvis/tools/chdir.py +9 -9
  22. jarvis/tools/codebase_qa.py +4 -4
  23. jarvis/tools/coder.py +4 -4
  24. jarvis/tools/file_ops.py +1 -1
  25. jarvis/tools/generator.py +23 -23
  26. jarvis/tools/methodology.py +4 -4
  27. jarvis/tools/rag.py +4 -4
  28. jarvis/tools/registry.py +38 -38
  29. jarvis/tools/search.py +42 -42
  30. jarvis/tools/shell.py +13 -13
  31. jarvis/tools/sub_agent.py +16 -16
  32. jarvis/tools/thinker.py +41 -41
  33. jarvis/tools/webpage.py +17 -17
  34. jarvis/utils.py +59 -60
  35. {jarvis_ai_assistant-0.1.93.dist-info → jarvis_ai_assistant-0.1.97.dist-info}/METADATA +1 -1
  36. jarvis_ai_assistant-0.1.97.dist-info/RECORD +47 -0
  37. jarvis_ai_assistant-0.1.93.dist-info/RECORD +0 -47
  38. {jarvis_ai_assistant-0.1.93.dist-info → jarvis_ai_assistant-0.1.97.dist-info}/LICENSE +0 -0
  39. {jarvis_ai_assistant-0.1.93.dist-info → jarvis_ai_assistant-0.1.97.dist-info}/WHEEL +0 -0
  40. {jarvis_ai_assistant-0.1.93.dist-info → jarvis_ai_assistant-0.1.97.dist-info}/entry_points.txt +0 -0
  41. {jarvis_ai_assistant-0.1.93.dist-info → jarvis_ai_assistant-0.1.97.dist-info}/top_level.txt +0 -0
@@ -1,49 +1,54 @@
1
- from typing import Dict, List, Optional
1
+ import re
2
+ from typing import Dict, List, Tuple
2
3
  from jarvis.models.registry import PlatformRegistry
3
- from jarvis.utils import PrettyOutput, OutputType, get_multiline_input, while_success
4
- from jarvis.models.base import BasePlatform
4
+ from jarvis.utils import PrettyOutput, OutputType, get_multiline_input
5
5
 
6
6
  class PlanGenerator:
7
7
  """修改方案生成器"""
8
8
 
9
- def __init__(self):
10
- """初始化
11
-
12
- Args:
13
- thinking_model: 用于思考的大模型
14
- """
15
- self.thinking_model = PlatformRegistry.get_global_platform_registry().get_thinking_platform()
16
-
17
- def _build_prompt(self, feature: str, related_files: List[Dict]) -> str:
9
+ def _build_prompt(self, feature: str, related_files: List[Dict], additional_info: str) -> str:
18
10
  """构建提示词
19
11
 
20
12
  Args:
21
13
  feature: 功能描述
22
14
  related_files: 相关文件列表
23
- user_feedback: 用户反馈信息
15
+ additional_info: 用户补充信息
24
16
 
25
17
  Returns:
26
18
  str: 完整的提示词
27
19
  """
28
- prompt = "我需要你帮我分析如何实现以下功能:\n\n"
20
+ prompt = "You are a code modification expert who can generate modification plans based on requirements and relevant code snippets. I need your help to analyze how to implement the following feature:\n\n"
29
21
  prompt += f"{feature}\n\n"
30
22
 
31
- prompt += "以下是相关的代码文件片段:\n\n"
23
+ prompt += "Here are the relevant code file snippets:\n\n"
32
24
 
33
25
  for file in related_files:
34
- prompt += f"文件: {file['file_path']}\n"
26
+ prompt += f"File: {file['file_path']}\n"
35
27
  for part in file["parts"]:
36
28
  prompt += f"<PART>\n{part}\n</PART>\n"
37
29
 
38
- prompt += "\n请详细说明需要做哪些修改来实现这个功能。包括:\n"
39
- prompt += "1. 需要修改哪些文件\n"
40
- prompt += "2. 每个文件需要做什么修改\n"
41
- prompt += "3. 修改的主要逻辑和原因\n"
42
- prompt += "4. 不要生成具体的代码,只需要生成修改方案\n"
30
+ prompt += "\nPlease provide detailed modifications needed to implement this feature. Include:\n"
31
+ prompt += "1. Which files need to be modified\n"
32
+ prompt += "2. How to modify each file, no explanation needed\n"
33
+ prompt += "3. Don't assume other files or code exist, only generate modification plans based on provided file contents and description\n"
34
+ prompt += "4. Don't implement features outside the requirement\n"
35
+ prompt += "5. Output only one modification plan per file (can be multiple lines)\n"
36
+ prompt += "6. Output format as follows:\n"
37
+ prompt += "<PLAN>\n"
38
+ prompt += "> path/to/file1\n"
39
+ prompt += "modification plan\n"
40
+ prompt += "</PLAN>\n"
41
+ prompt += "<PLAN>\n"
42
+ prompt += "> path/to/file2\n"
43
+ prompt += "modification plan\n"
44
+ prompt += "</PLAN>\n"
45
+ if additional_info:
46
+ prompt += f"# Additional information:\n{additional_info}\n"
43
47
 
44
48
  return prompt
45
49
 
46
- def generate_plan(self, feature: str, related_files: List[Dict]) -> str:
50
+
51
+ def generate_plan(self, feature: str, related_files: List[Dict]) -> Tuple[str, Dict[str,str]]:
47
52
  """生成修改方案
48
53
 
49
54
  Args:
@@ -51,25 +56,48 @@ class PlanGenerator:
51
56
  related_files: 相关文件列表
52
57
 
53
58
  Returns:
54
- str: 修改方案,如果用户取消则返回 None
59
+ Tuple[str, Dict[str,str]]: 修改方案,如果用户取消则返回 None
55
60
  """
56
- prompt = self._build_prompt(feature, related_files)
61
+ additional_info = ""
57
62
  while True:
63
+ prompt = self._build_prompt(feature, related_files, additional_info)
58
64
  # 构建提示词
59
65
  PrettyOutput.print("开始生成修改方案...", OutputType.PROGRESS)
60
66
 
61
67
  # 获取修改方案
62
- plan = while_success(lambda: self.thinking_model.chat(prompt), 5)
63
-
64
- user_input = input("\n是否同意这个修改方案?(y/n/f) [y]: ").strip().lower() or 'y'
65
- if user_input == 'y':
66
- return plan
68
+ raw_plan = PlatformRegistry.get_global_platform_registry().get_thinking_platform().chat_until_success(prompt)
69
+ structed_plan = self._extract_code(raw_plan)
70
+ if not structed_plan:
71
+ PrettyOutput.print("修改方案生成失败,请重试", OutputType.ERROR)
72
+ tmp = get_multiline_input("请输入您的补充意见或建议(直接回车取消):")
73
+ if tmp == "__interrupt__" or prompt == "":
74
+ return "", {}
75
+ additional_info += tmp + "\n"
76
+ continue
77
+ user_input = input("\n是否同意这个修改方案?(y/n) [y]: ").strip().lower() or 'y'
78
+ if user_input == 'y' or user_input == '':
79
+ return raw_plan, structed_plan
67
80
  elif user_input == 'n':
68
- return ""
69
- else: # 'f' - feedback
70
81
  # 获取用户反馈
71
- prompt = get_multiline_input("请输入您的补充意见或建议:")
72
- if prompt == "__interrupt__":
73
- return ""
74
- prompt = f"用户补充反馈:\n{prompt}\n\n请重新生成完整方案"
75
- continue
82
+ tmp = get_multiline_input("请输入您的补充意见或建议(直接回车取消):")
83
+ if prompt == "__interrupt__" or prompt == "":
84
+ return "", {}
85
+ additional_info += tmp + "\n"
86
+ continue
87
+
88
+
89
+ def _extract_code(self, response: str) -> Dict[str, str]:
90
+ """从响应中提取代码
91
+
92
+ Args:
93
+ response: 模型响应内容
94
+
95
+ Returns:
96
+ Dict[str, List[str]]: 代码字典,key为文件路径,value为代码片段列表
97
+ """
98
+ code_dict = {}
99
+ for match in re.finditer(r'<PLAN>\n> (.+?)\n(.*?)\n</PLAN>', response, re.DOTALL):
100
+ file_path = match.group(1)
101
+ code_part = match.group(2)
102
+ code_dict[file_path] = code_part
103
+ return code_dict
@@ -75,7 +75,7 @@ def chat_with_model(platform_name: str, model_name: str):
75
75
 
76
76
  try:
77
77
  # 发送到模型并获取回复
78
- response = platform.chat(user_input)
78
+ response = platform.chat_until_success(user_input)
79
79
  if not response:
80
80
  PrettyOutput.print("未获得有效回复", OutputType.WARNING)
81
81
 
jarvis/jarvis_rag/main.py CHANGED
@@ -744,7 +744,7 @@ class RAGTool:
744
744
 
745
745
  # 获取模型实例并生成回答
746
746
  model = PlatformRegistry.get_global_platform_registry().get_normal_platform()
747
- response = model.chat(prompt)
747
+ response = model.chat_until_success(prompt)
748
748
 
749
749
  return response
750
750
 
@@ -46,34 +46,34 @@ def process_request(request: str) -> Optional[str]:
46
46
  current_path = os.getcwd()
47
47
 
48
48
  # 设置系统提示
49
- system_message = f"""你是一个 shell 命令生成助手。
49
+ system_message = f"""You are a shell command generation assistant.
50
50
 
51
- 你的唯一任务是将用户的自然语言需求转换为对应的shell命令。
51
+ Your only task is to convert user's natural language requirements into corresponding shell commands.
52
52
 
53
- 严格要求:
54
- 1. 只返回shell命令本身
55
- 2. 不要添加任何标记(如```、/**/、//等)
56
- 3. 不要添加任何解释或说明
57
- 4. 不要添加任何换行或额外空格
58
- 5. 如果需要多个命令,使用 && 连接
53
+ Strict requirements:
54
+ 1. Only return the shell command itself
55
+ 2. Do not add any markers (like ```, /**/, // etc.)
56
+ 3. Do not add any explanations or descriptions
57
+ 4. Do not add any line breaks or extra spaces
58
+ 5. If multiple commands are needed, connect them with &&
59
59
 
60
- 示例输入:
61
- "查找当前目录下的所有Python文件"
60
+ Example input:
61
+ "Find all Python files in the current directory"
62
62
 
63
- 示例输出:
63
+ Example output:
64
64
  find . -name "*.py"
65
65
 
66
- 记住:只返回命令本身,不要有任何额外的内容。
66
+ Remember: Only return the command itself, without any additional content.
67
67
  """
68
68
  model.set_system_message(system_message)
69
69
 
70
- prefix = f"当前路径: {current_path}\n"
71
- prefix += f"当前shell: {shell}\n"
70
+ prefix = f"Current path: {current_path}\n"
71
+ prefix += f"Current shell: {shell}\n"
72
72
 
73
73
  # 使用yaspin显示Thinking状态
74
74
  with yaspin(Spinners.dots, text="Thinking", color="yellow") as spinner:
75
75
  # 处理请求
76
- result = model.chat(prefix + request)
76
+ result = model.chat_until_success(prefix + request)
77
77
 
78
78
  # 提取命令
79
79
  if result and isinstance(result, str):
jarvis/main.py CHANGED
@@ -10,7 +10,7 @@ from prompt_toolkit import prompt
10
10
 
11
11
  from jarvis.models.registry import PlatformRegistry
12
12
 
13
- # 添加父目录到Python路径以支持导入
13
+ # Add parent directory to Python path to support imports
14
14
  sys.path.insert(0, str(Path(__file__).parent.parent))
15
15
 
16
16
  from jarvis.agent import Agent
@@ -22,7 +22,7 @@ def load_tasks() -> dict:
22
22
  """Load tasks from .jarvis files in user home and current directory."""
23
23
  tasks = {}
24
24
 
25
- # 检查用户目录下的 .jarvis
25
+ # Check .jarvis in user directory
26
26
  user_jarvis = os.path.expanduser("~/.jarvis")
27
27
  if os.path.exists(user_jarvis):
28
28
  try:
@@ -30,39 +30,39 @@ def load_tasks() -> dict:
30
30
  user_tasks = yaml.safe_load(f)
31
31
 
32
32
  if isinstance(user_tasks, dict):
33
- # 验证并添加用户目录的任务
33
+ # Validate and add user directory tasks
34
34
  for name, desc in user_tasks.items():
35
- if desc: # 确保描述不为空
35
+ if desc: # Ensure description is not empty
36
36
  tasks[str(name)] = str(desc)
37
37
  else:
38
38
  PrettyOutput.print("Warning: ~/.jarvis file should contain a dictionary of task_name: task_description", OutputType.ERROR)
39
39
  except Exception as e:
40
40
  PrettyOutput.print(f"Error loading ~/.jarvis file: {str(e)}", OutputType.ERROR)
41
41
 
42
- # 检查当前目录下的 .jarvis
42
+ # Check .jarvis in current directory
43
43
  if os.path.exists(".jarvis"):
44
44
  try:
45
45
  with open(".jarvis", "r", encoding="utf-8") as f:
46
46
  local_tasks = yaml.safe_load(f)
47
47
 
48
48
  if isinstance(local_tasks, dict):
49
- # 验证并添加当前目录的任务,如果有重名则覆盖用户目录的任务
49
+ # Validate and add current directory tasks, overwrite user directory tasks if there is a name conflict
50
50
  for name, desc in local_tasks.items():
51
- if desc: # 确保描述不为空
51
+ if desc: # Ensure description is not empty
52
52
  tasks[str(name)] = str(desc)
53
53
  else:
54
54
  PrettyOutput.print("Warning: .jarvis file should contain a dictionary of task_name: task_description", OutputType.ERROR)
55
55
  except Exception as e:
56
56
  PrettyOutput.print(f"Error loading .jarvis file: {str(e)}", OutputType.ERROR)
57
57
 
58
- # 读取方法论
58
+ # Read methodology
59
59
  method_path = os.path.expanduser("~/.jarvis_methodology")
60
60
  if os.path.exists(method_path):
61
61
  with open(method_path, "r", encoding="utf-8") as f:
62
62
  methodology = yaml.safe_load(f)
63
63
  if isinstance(methodology, dict):
64
64
  for name, desc in methodology.items():
65
- tasks[f"执行方法论:{str(name)}\n {str(desc)}" ] = str(desc)
65
+ tasks[f"Run Methodology: {str(name)}\n {str(desc)}" ] = str(desc)
66
66
 
67
67
  return tasks
68
68
 
@@ -77,13 +77,13 @@ def select_task(tasks: dict) -> str:
77
77
  PrettyOutput.print("\nAvailable tasks:", OutputType.INFO)
78
78
  for i, name in enumerate(task_names, 1):
79
79
  PrettyOutput.print(f"[{i}] {name}", OutputType.INFO)
80
- PrettyOutput.print("[0] 跳过预定义任务", OutputType.INFO)
80
+ PrettyOutput.print("[0] Skip predefined tasks", OutputType.INFO)
81
81
 
82
82
 
83
83
  while True:
84
84
  try:
85
85
  choice = prompt(
86
- "\n请选择一个任务编号(0跳过): ",
86
+ "\nPlease select a task number (0 to skip): ",
87
87
  ).strip()
88
88
 
89
89
  if not choice:
@@ -103,16 +103,16 @@ def select_task(tasks: dict) -> str:
103
103
  except EOFError:
104
104
  return "" # Return empty on Ctrl+D
105
105
  except Exception as e:
106
- PrettyOutput.print(f"选择失败: {str(e)}", OutputType.ERROR)
106
+ PrettyOutput.print(f"Failed to select task: {str(e)}", OutputType.ERROR)
107
107
  continue
108
108
 
109
109
  def main():
110
- """Jarvis 的主入口点"""
111
- # 添加参数解析器
110
+ """Jarvis main entry point"""
111
+ # Add argument parser
112
112
  load_env_from_file()
113
- parser = argparse.ArgumentParser(description='Jarvis AI 助手')
114
- parser.add_argument('-f', '--files', nargs='*', help='要处理的文件列表')
115
- parser.add_argument('--keep-history', action='store_true', help='保持聊天历史(不删除会话)')
113
+ parser = argparse.ArgumentParser(description='Jarvis AI assistant')
114
+ parser.add_argument('-f', '--files', nargs='*', help='List of files to process')
115
+ parser.add_argument('--keep-history', action='store_true', help='Keep chat history (do not delete session)')
116
116
  args = parser.parse_args()
117
117
 
118
118
  try:
@@ -121,32 +121,32 @@ def main():
121
121
 
122
122
  # 如果用户传入了模型参数,则更换当前模型为用户指定的模型
123
123
 
124
- # 欢迎信息
125
- PrettyOutput.print(f"Jarvis 已初始化 - With {agent.model.name()}", OutputType.SYSTEM)
124
+ # Welcome information
125
+ PrettyOutput.print(f"Jarvis initialized - With {agent.model.name()}", OutputType.SYSTEM)
126
126
  if args.keep_history:
127
- PrettyOutput.print("已启用历史保留模式", OutputType.INFO)
127
+ PrettyOutput.print("History preservation mode enabled", OutputType.INFO)
128
128
 
129
129
  # 加载预定义任务
130
130
  tasks = load_tasks()
131
131
  if tasks:
132
132
  selected_task = select_task(tasks)
133
133
  if selected_task:
134
- PrettyOutput.print(f"\n执行任务: {selected_task}", OutputType.INFO)
134
+ PrettyOutput.print(f"\nExecute task: {selected_task}", OutputType.INFO)
135
135
  agent.run(selected_task, args.files)
136
136
  return 0
137
137
 
138
138
  # 如果没有选择预定义任务,进入交互模式
139
139
  while True:
140
140
  try:
141
- user_input = get_multiline_input("请输入您的任务(输入空行退出):")
141
+ user_input = get_multiline_input("Please enter your task (input empty line to exit):")
142
142
  if not user_input or user_input == "__interrupt__":
143
143
  break
144
144
  agent.run(user_input, args.files)
145
145
  except Exception as e:
146
- PrettyOutput.print(f"错误: {str(e)}", OutputType.ERROR)
146
+ PrettyOutput.print(f"Error: {str(e)}", OutputType.ERROR)
147
147
 
148
148
  except Exception as e:
149
- PrettyOutput.print(f"初始化错误: {str(e)}", OutputType.ERROR)
149
+ PrettyOutput.print(f"Initialization error: {str(e)}", OutputType.ERROR)
150
150
  return 1
151
151
 
152
152
  return 0
jarvis/models/ai8.py CHANGED
@@ -26,16 +26,16 @@ class AI8Model(BasePlatform):
26
26
 
27
27
  self.token = os.getenv("AI8_API_KEY")
28
28
  if not self.token:
29
- PrettyOutput.print("AI8_API_KEY未设置", OutputType.WARNING)
29
+ PrettyOutput.print("AI8_API_KEY is not set", OutputType.WARNING)
30
30
 
31
31
 
32
32
  self.model_name = os.getenv("JARVIS_MODEL") or "deepseek-chat"
33
33
  if self.model_name not in self.get_available_models():
34
- PrettyOutput.print(f"警告: 当前选择的模型 {self.model_name} 不在可用列表中", OutputType.WARNING)
34
+ PrettyOutput.print(f"Warning: The selected model {self.model_name} is not in the available list", OutputType.WARNING)
35
35
 
36
36
 
37
37
  def set_model_name(self, model_name: str):
38
- """设置模型名称"""
38
+ """Set model name"""
39
39
 
40
40
  self.model_name = model_name
41
41
 
@@ -59,12 +59,12 @@ class AI8Model(BasePlatform):
59
59
  )
60
60
 
61
61
  if response.status_code != 200:
62
- PrettyOutput.print(f"创建会话失败: {response.status_code}", OutputType.ERROR)
62
+ PrettyOutput.print(f"Failed to create session: {response.status_code}", OutputType.ERROR)
63
63
  return False
64
64
 
65
65
  data = response.json()
66
66
  if data['code'] != 0:
67
- PrettyOutput.print(f"创建会话失败: {data.get('msg', '未知错误')}", OutputType.ERROR)
67
+ PrettyOutput.print(f"Failed to create session: {data.get('msg', 'Unknown error')}", OutputType.ERROR)
68
68
  return False
69
69
 
70
70
  self.conversation = data['data']
@@ -92,14 +92,14 @@ class AI8Model(BasePlatform):
92
92
  self.conversation = data['data']
93
93
  return True
94
94
  else:
95
- PrettyOutput.print(f"更新会话设置失败: {data.get('msg', '未知错误')}", OutputType.ERROR)
95
+ PrettyOutput.print(f"Failed to update session settings: {data.get('msg', 'Unknown error')}", OutputType.ERROR)
96
96
  return False
97
97
  else:
98
- PrettyOutput.print(f"更新会话设置失败: {response.status_code}", OutputType.ERROR)
98
+ PrettyOutput.print(f"Failed to update session settings: {response.status_code}", OutputType.ERROR)
99
99
  return False
100
100
 
101
101
  except Exception as e:
102
- PrettyOutput.print(f"创建会话异常: {str(e)}", OutputType.ERROR)
102
+ PrettyOutput.print(f"Failed to create session: {str(e)}", OutputType.ERROR)
103
103
  return False
104
104
 
105
105
  def upload_files(self, file_list: List[str]) -> List[Dict]:
@@ -119,7 +119,7 @@ class AI8Model(BasePlatform):
119
119
  self.system_message = message
120
120
 
121
121
  def chat(self, message: str) -> str:
122
- """执行对话"""
122
+ """Execute conversation"""
123
123
  try:
124
124
 
125
125
  # 确保有会话ID
@@ -160,7 +160,7 @@ class AI8Model(BasePlatform):
160
160
  )
161
161
 
162
162
  if response.status_code != 200:
163
- error_msg = f"聊天请求失败: {response.status_code}"
163
+ error_msg = f"Failed to chat: {response.status_code}"
164
164
  PrettyOutput.print(error_msg, OutputType.ERROR)
165
165
  raise Exception(error_msg)
166
166
 
@@ -188,7 +188,7 @@ class AI8Model(BasePlatform):
188
188
  return full_response
189
189
 
190
190
  except Exception as e:
191
- PrettyOutput.print(f"聊天异常: {str(e)}", OutputType.ERROR)
191
+ PrettyOutput.print(f"Chat exception: {str(e)}", OutputType.ERROR)
192
192
  raise e
193
193
 
194
194
  def name(self) -> str:
@@ -227,23 +227,23 @@ class AI8Model(BasePlatform):
227
227
  self.reset()
228
228
  return True
229
229
  else:
230
- error_msg = f"删除会话失败: {data.get('msg', '未知错误')}"
230
+ error_msg = f"Failed to delete session: {data.get('msg', 'Unknown error')}"
231
231
  PrettyOutput.print(error_msg, OutputType.ERROR)
232
232
  return False
233
233
  else:
234
- error_msg = f"删除会话请求失败: {response.status_code}"
234
+ error_msg = f"Failed to delete session request: {response.status_code}"
235
235
  PrettyOutput.print(error_msg, OutputType.ERROR)
236
236
  return False
237
237
 
238
238
  except Exception as e:
239
- PrettyOutput.print(f"删除会话异常: {str(e)}", OutputType.ERROR)
239
+ PrettyOutput.print(f"Failed to delete session: {str(e)}", OutputType.ERROR)
240
240
  return False
241
241
 
242
242
  def get_available_models(self) -> List[str]:
243
- """获取可用的模型列表
243
+ """Get available model list
244
244
 
245
245
  Returns:
246
- List[str]: 可用模型名称列表
246
+ List[str]: Available model name list
247
247
  """
248
248
  try:
249
249
  if self.models:
@@ -264,12 +264,12 @@ class AI8Model(BasePlatform):
264
264
  )
265
265
 
266
266
  if response.status_code != 200:
267
- PrettyOutput.print(f"获取模型列表失败: {response.status_code}", OutputType.ERROR)
267
+ PrettyOutput.print(f"Failed to get model list: {response.status_code}", OutputType.ERROR)
268
268
  return []
269
269
 
270
270
  data = response.json()
271
271
  if data['code'] != 0:
272
- PrettyOutput.print(f"获取模型列表失败: {data.get('msg', '未知错误')}", OutputType.ERROR)
272
+ PrettyOutput.print(f"Failed to get model list: {data.get('msg', 'Unknown error')}", OutputType.ERROR)
273
273
  return []
274
274
 
275
275
  # 保存模型信息
@@ -292,11 +292,11 @@ class AI8Model(BasePlatform):
292
292
  # 添加特性标记
293
293
  features = []
294
294
  if model['attr'].get('multimodal'):
295
- features.append("多模态")
295
+ features.append("Multimodal")
296
296
  if model['attr'].get('plugin'):
297
- features.append("插件支持")
297
+ features.append("Plugin support")
298
298
  if model['attr'].get('onlyImg'):
299
- features.append("图像支持")
299
+ features.append("Image support")
300
300
  if features:
301
301
  model_str += f" [{'|'.join(features)}]"
302
302
 
@@ -308,6 +308,6 @@ class AI8Model(BasePlatform):
308
308
  return list(self.models.keys())
309
309
 
310
310
  except Exception as e:
311
- PrettyOutput.print(f"获取模型列表异常: {str(e)}", OutputType.WARNING)
311
+ PrettyOutput.print(f"Failed to get model list: {str(e)}", OutputType.WARNING)
312
312
  return []
313
313
 
jarvis/models/base.py CHANGED
@@ -1,59 +1,63 @@
1
1
  from abc import ABC, abstractmethod
2
2
  from typing import Dict, List, Tuple
3
3
 
4
+ from jarvis.utils import OutputType, PrettyOutput, while_success, while_true
5
+
4
6
 
5
7
  class BasePlatform(ABC):
6
- """大语言模型基类"""
8
+ """Base class for large language models"""
7
9
 
8
10
  def __init__(self):
9
- """初始化模型"""
11
+ """Initialize model"""
10
12
  self.suppress_output = False # 添加输出控制标志
11
- pass
12
13
 
13
14
  def __del__(self):
14
- """销毁模型"""
15
+ """Destroy model"""
15
16
  self.delete_chat()
16
17
 
17
18
  @abstractmethod
18
19
  def set_model_name(self, model_name: str):
19
- """设置模型名称"""
20
+ """Set model name"""
20
21
  raise NotImplementedError("set_model_name is not implemented")
21
22
 
22
23
  @abstractmethod
23
24
  def chat(self, message: str) -> str:
24
- """执行对话"""
25
+ """Execute conversation"""
25
26
  raise NotImplementedError("chat is not implemented")
26
27
 
28
+ def chat_until_success(self, message: str) -> str:
29
+ return while_true(lambda: while_success(lambda: self.chat(message), 5), 5)
30
+
27
31
  @abstractmethod
28
32
  def upload_files(self, file_list: List[str]) -> List[Dict]:
29
- """上传文件"""
33
+ """Upload files"""
30
34
  raise NotImplementedError("upload_files is not implemented")
31
35
 
32
36
  @abstractmethod
33
37
  def reset(self):
34
- """重置模型"""
38
+ """Reset model"""
35
39
  raise NotImplementedError("reset is not implemented")
36
40
 
37
41
  @abstractmethod
38
42
  def name(self) -> str:
39
- """模型名称"""
43
+ """Model name"""
40
44
  raise NotImplementedError("name is not implemented")
41
45
 
42
46
  @abstractmethod
43
47
  def delete_chat(self)->bool:
44
- """删除对话"""
48
+ """Delete chat"""
45
49
  raise NotImplementedError("delete_chat is not implemented")
46
50
 
47
51
  @abstractmethod
48
52
  def set_system_message(self, message: str):
49
- """设置系统消息"""
53
+ """Set system message"""
50
54
  raise NotImplementedError("set_system_message is not implemented")
51
55
 
52
56
  @abstractmethod
53
57
  def get_model_list(self) -> List[Tuple[str, str]]:
54
- """获取模型列表"""
58
+ """Get model list"""
55
59
  raise NotImplementedError("get_model_list is not implemented")
56
60
 
57
61
  def set_suppress_output(self, suppress: bool):
58
- """设置是否屏蔽输出"""
62
+ """Set whether to suppress output"""
59
63
  self.suppress_output = suppress