jarvis-ai-assistant 0.1.96__py3-none-any.whl → 0.1.98__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 +22 -25
  5. jarvis/jarvis_coder/main.py +166 -171
  6. jarvis/jarvis_coder/patch_handler.py +153 -453
  7. jarvis/jarvis_coder/plan_generator.py +76 -48
  8. jarvis/jarvis_platform/main.py +39 -39
  9. jarvis/jarvis_rag/main.py +182 -182
  10. jarvis/jarvis_smart_shell/main.py +34 -34
  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.96.dist-info → jarvis_ai_assistant-0.1.98.dist-info}/METADATA +1 -1
  36. jarvis_ai_assistant-0.1.98.dist-info/RECORD +47 -0
  37. jarvis_ai_assistant-0.1.96.dist-info/RECORD +0 -47
  38. {jarvis_ai_assistant-0.1.96.dist-info → jarvis_ai_assistant-0.1.98.dist-info}/LICENSE +0 -0
  39. {jarvis_ai_assistant-0.1.96.dist-info → jarvis_ai_assistant-0.1.98.dist-info}/WHEEL +0 -0
  40. {jarvis_ai_assistant-0.1.96.dist-info → jarvis_ai_assistant-0.1.98.dist-info}/entry_points.txt +0 -0
  41. {jarvis_ai_assistant-0.1.96.dist-info → jarvis_ai_assistant-0.1.98.dist-info}/top_level.txt +0 -0
@@ -11,33 +11,33 @@ from jarvis.models.registry import PlatformRegistry
11
11
  from jarvis.utils import PrettyOutput, OutputType, load_env_from_file
12
12
 
13
13
  def execute_command(command: str) -> None:
14
- """显示命令并允许用户编辑,回车执行,Ctrl+C取消"""
14
+ """Show command and allow user to edit, then execute, Ctrl+C to cancel"""
15
15
  try:
16
- print("\n生成的命令 (可以编辑,回车执行,Ctrl+C取消):")
17
- # 预填充输入行
16
+ print("\nGenerated command (can be edited, press Enter to execute, Ctrl+C to cancel):")
17
+ # Pre-fill input line
18
18
  readline.set_startup_hook(lambda: readline.insert_text(command))
19
19
  try:
20
20
  edited_command = input("> ")
21
- if edited_command.strip(): # 确保命令不为空
21
+ if edited_command.strip(): # Ensure command is not empty
22
22
  os.system(edited_command)
23
23
  except KeyboardInterrupt:
24
- print("\n已取消执行")
24
+ print("\nExecution cancelled")
25
25
  finally:
26
- readline.set_startup_hook() # 清除预填充
26
+ readline.set_startup_hook() # Clear pre-filled
27
27
  except Exception as e:
28
- PrettyOutput.print(f"执行命令时发生错误: {str(e)}", OutputType.ERROR)
28
+ PrettyOutput.print(f"Failed to execute command: {str(e)}", OutputType.ERROR)
29
29
 
30
30
  def process_request(request: str) -> Optional[str]:
31
- """处理用户请求并返回对应的shell命令
31
+ """Process user request and return corresponding shell command
32
32
 
33
33
  Args:
34
- request: 用户的自然语言请求
34
+ request: User's natural language request
35
35
 
36
36
  Returns:
37
- Optional[str]: 对应的shell命令,如果处理失败则返回None
37
+ Optional[str]: Corresponding shell command, return None if processing fails
38
38
  """
39
39
  try:
40
- # 获取语言模型实例
40
+ # Get language model instance
41
41
  PlatformRegistry.suppress_output = True
42
42
  model = PlatformRegistry.get_global_platform_registry().get_normal_platform()
43
43
  model.set_suppress_output(True)
@@ -45,35 +45,35 @@ def process_request(request: str) -> Optional[str]:
45
45
  shell = os.environ.get("SHELL") or "bash"
46
46
  current_path = os.getcwd()
47
47
 
48
- # 设置系统提示
49
- system_message = f"""你是一个 shell 命令生成助手。
48
+ # Set system prompt
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):
@@ -85,26 +85,26 @@ find . -name "*.py"
85
85
  return None
86
86
 
87
87
  except Exception as e:
88
- PrettyOutput.print(f"处理请求时发生错误: {str(e)}", OutputType.ERROR)
88
+ PrettyOutput.print(f"Failed to process request: {str(e)}", OutputType.ERROR)
89
89
  return None
90
90
 
91
91
  def main():
92
92
  # 创建参数解析器
93
93
  load_env_from_file()
94
94
  parser = argparse.ArgumentParser(
95
- description="将自然语言需求转换为shell命令",
95
+ description="Convert natural language requirements to shell commands",
96
96
  formatter_class=argparse.RawDescriptionHelpFormatter,
97
97
  epilog="""
98
- 示例:
99
- %(prog)s "查找当前目录下所有的Python文件"
100
- %(prog)s "压缩所有jpg图片"
101
- %(prog)s "查找最近一周修改过的文档"
98
+ Example:
99
+ %(prog)s "Find all Python files in the current directory"
100
+ %(prog)s "Compress all jpg images"
101
+ %(prog)s "Find documents modified in the last week"
102
102
  """)
103
103
 
104
104
  # 添加参数
105
105
  parser.add_argument(
106
106
  "request",
107
- help="用自然语言描述你需要执行的操作"
107
+ help="Describe the operation you want to perform in natural language"
108
108
  )
109
109
 
110
110
  # 解析参数
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
jarvis/models/kimi.py CHANGED
@@ -9,38 +9,38 @@ from jarvis.utils import PrettyOutput, OutputType
9
9
  from jarvis.utils import while_success
10
10
 
11
11
  class KimiModel(BasePlatform):
12
- """Kimi模型实现"""
12
+ """Kimi model implementation"""
13
13
 
14
14
  platform_name = "kimi"
15
15
 
16
16
  def get_model_list(self) -> List[Tuple[str, str]]:
17
- """获取模型列表"""
18
- return [("kimi", "基于网页Kimi的封装,免费接口")]
17
+ """Get model list"""
18
+ return [("kimi", "Based on the web Kimi, free interface")]
19
19
 
20
20
  def __init__(self):
21
21
  """
22
- 初始化Kimi模型
22
+ Initialize Kimi model
23
23
  """
24
24
  super().__init__()
25
25
  self.chat_id = ""
26
26
  self.api_key = os.getenv("KIMI_API_KEY")
27
27
  if not self.api_key:
28
- PrettyOutput.print("\n需要设置 KIMI_API_KEY 才能使用 Jarvis。请按以下步骤操作:", OutputType.INFO)
29
- PrettyOutput.print("\n1. 获取 Kimi API Key:", OutputType.INFO)
30
- PrettyOutput.print(" • 访问 Kimi AI 平台: https://kimi.moonshot.cn", OutputType.INFO)
31
- PrettyOutput.print(" • 登录您的账号", OutputType.INFO)
32
- PrettyOutput.print(" • 打开浏览器开发者工具 (F12 或右键 -> 检查)", OutputType.INFO)
33
- PrettyOutput.print(" • 切换到 Network 标签页", OutputType.INFO)
34
- PrettyOutput.print(" • 发送任意消息", OutputType.INFO)
35
- PrettyOutput.print(" • 在请求中找到 Authorization 头部", OutputType.INFO)
36
- PrettyOutput.print(" • 复制 token 值(去掉 'Bearer ' 前缀)", OutputType.INFO)
37
- PrettyOutput.print("\n2. 设置环境变量:", OutputType.INFO)
38
- PrettyOutput.print(" 方法 1: 创建或编辑 ~/.jarvis_env 文件:", OutputType.INFO)
28
+ PrettyOutput.print("\nNeed to set KIMI_API_KEY to use Jarvis. Please follow the steps below:", OutputType.INFO)
29
+ PrettyOutput.print("\n1. Get Kimi API Key:", OutputType.INFO)
30
+ PrettyOutput.print(" • Visit Kimi AI platform: https://kimi.moonshot.cn", OutputType.INFO)
31
+ PrettyOutput.print(" • Login to your account", OutputType.INFO)
32
+ PrettyOutput.print(" • Open browser developer tools (F12 or right-click -> Inspect)", OutputType.INFO)
33
+ PrettyOutput.print(" • Switch to the Network tab", OutputType.INFO)
34
+ PrettyOutput.print(" • Send any message", OutputType.INFO)
35
+ PrettyOutput.print(" • Find the Authorization header in the request", OutputType.INFO)
36
+ PrettyOutput.print(" • Copy the token value (remove the 'Bearer ' prefix)", OutputType.INFO)
37
+ PrettyOutput.print("\n2. Set environment variable:", OutputType.INFO)
38
+ PrettyOutput.print(" Method 1: Create or edit ~/.jarvis_env file:", OutputType.INFO)
39
39
  PrettyOutput.print(" echo 'KIMI_API_KEY=your_key_here' > ~/.jarvis_env", OutputType.INFO)
40
- PrettyOutput.print("\n 方法 2: 直接设置环境变量:", OutputType.INFO)
40
+ PrettyOutput.print("\n Method 2: Set environment variable directly:", OutputType.INFO)
41
41
  PrettyOutput.print(" export KIMI_API_KEY=your_key_here", OutputType.INFO)
42
- PrettyOutput.print("\n设置完成后重新运行 Jarvis", OutputType.INFO)
43
- PrettyOutput.print("KIMI_API_KEY未设置", OutputType.WARNING)
42
+ PrettyOutput.print("\nAfter setting, run Jarvis again.", OutputType.INFO)
43
+ PrettyOutput.print("KIMI_API_KEY is not set", OutputType.WARNING)
44
44
  self.auth_header = f"Bearer {self.api_key}"
45
45
  self.chat_id = ""
46
46
  self.uploaded_files = [] # 存储已上传文件的信息
@@ -48,18 +48,18 @@ class KimiModel(BasePlatform):
48
48
  self.system_message = ""
49
49
 
50
50
  def set_system_message(self, message: str):
51
- """设置系统消息"""
51
+ """Set system message"""
52
52
  self.system_message = message
53
53
 
54
54
  def set_model_name(self, model_name: str):
55
- """设置模型名称"""
55
+ """Set model name"""
56
56
  pass
57
57
 
58
58
  def _create_chat(self) -> bool:
59
- """创建新的对话会话"""
59
+ """Create a new chat session"""
60
60
  url = "https://kimi.moonshot.cn/api/chat"
61
61
  payload = json.dumps({
62
- "name": "未命名会话",
62
+ "name": "Unnamed session",
63
63
  "is_example": False,
64
64
  "kimiplus_id": "kimi"
65
65
  })
@@ -76,7 +76,7 @@ class KimiModel(BasePlatform):
76
76
  return False
77
77
 
78
78
  def _get_presigned_url(self, filename: str, action: str) -> Dict:
79
- """获取预签名上传URL"""
79
+ """Get presigned upload URL"""
80
80
  url = "https://kimi.moonshot.cn/api/pre-sign-url"
81
81
 
82
82
 
@@ -95,7 +95,7 @@ class KimiModel(BasePlatform):
95
95
  return response.json()
96
96
 
97
97
  def _upload_file(self, file_path: str, presigned_url: str) -> bool:
98
- """上传文件到预签名URL"""
98
+ """Upload file to presigned URL"""
99
99
  try:
100
100
  with open(file_path, 'rb') as f:
101
101
  content = f.read()
@@ -106,7 +106,7 @@ class KimiModel(BasePlatform):
106
106
  return False
107
107
 
108
108
  def _get_file_info(self, file_data: Dict, name: str, file_type: str) -> Dict:
109
- """获取文件信息"""
109
+ """Get file information"""
110
110
  url = "https://kimi.moonshot.cn/api/file"
111
111
  payload = json.dumps({
112
112
  "type": file_type,
@@ -125,7 +125,7 @@ class KimiModel(BasePlatform):
125
125
  return response.json()
126
126
 
127
127
  def _wait_for_parse(self, file_id: str) -> bool:
128
- """等待文件解析完成"""
128
+ """Wait for file parsing to complete"""
129
129
  url = "https://kimi.moonshot.cn/api/file/parse_process"
130
130
  headers = {
131
131
  'Authorization': self.auth_header,
@@ -163,7 +163,7 @@ class KimiModel(BasePlatform):
163
163
 
164
164
  return False
165
165
  def upload_files(self, file_list: List[str]) -> List[Dict]:
166
- """上传文件列表并返回文件信息"""
166
+ """Upload file list and return file information"""
167
167
  if not file_list:
168
168
  return []
169
169
 
@@ -209,7 +209,7 @@ class KimiModel(BasePlatform):
209
209
  return uploaded_files
210
210
 
211
211
  def chat(self, message: str) -> str:
212
- """发送消息并获取响应"""
212
+ """Send message and get response"""
213
213
  if not self.chat_id:
214
214
  if not self._create_chat():
215
215
  raise Exception("Failed to create chat session")
@@ -353,7 +353,7 @@ class KimiModel(BasePlatform):
353
353
  raise Exception(f"Chat failed: {str(e)}")
354
354
 
355
355
  def delete_chat(self) -> bool:
356
- """删除当前会话"""
356
+ """Delete current session"""
357
357
  if not self.chat_id:
358
358
  return True # 如果没有会话ID,视为删除成功
359
359
 
@@ -376,11 +376,11 @@ class KimiModel(BasePlatform):
376
376
  return False
377
377
 
378
378
  def reset(self):
379
- """重置对话"""
379
+ """Reset chat"""
380
380
  self.chat_id = ""
381
381
  self.uploaded_files = []
382
382
  self.first_chat = True # 重置first_chat标记
383
383
 
384
384
  def name(self) -> str:
385
- """模型名称"""
385
+ """Model name"""
386
386
  return "kimi"