jarvis-ai-assistant 0.1.212__py3-none-any.whl → 0.1.213__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 CHANGED
@@ -1,4 +1,4 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """Jarvis AI Assistant"""
3
3
 
4
- __version__ = "0.1.212"
4
+ __version__ = "0.1.213"
@@ -1,11 +1,12 @@
1
1
  import os
2
- from typing import Dict, Generator, List, Tuple
2
+ from typing import Generator, List, Tuple
3
3
  from jarvis.jarvis_platform.base import BasePlatform
4
- import requests
5
4
  import json
6
- import base64
7
5
 
6
+ from jarvis.jarvis_utils import http
8
7
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
8
+ from jarvis.jarvis_utils.utils import while_success
9
+
9
10
 
10
11
  class AI8Model(BasePlatform):
11
12
  """AI8 model implementation"""
@@ -16,7 +17,7 @@ class AI8Model(BasePlatform):
16
17
  def get_model_list(self) -> List[Tuple[str, str]]:
17
18
  """获取模型列表"""
18
19
  self.get_available_models()
19
- return [(name,info['desc']) for name,info in self.models.items()]
20
+ return [(name, info["desc"]) for name, info in self.models.items()]
20
21
 
21
22
  def __init__(self):
22
23
  """Initialize model"""
@@ -30,24 +31,23 @@ class AI8Model(BasePlatform):
30
31
  PrettyOutput.print("未设置 AI8_API_KEY", OutputType.WARNING)
31
32
 
32
33
  self.headers = {
33
- 'Authorization': self.token,
34
- 'Content-Type': 'application/json',
35
- 'Accept': 'application/json, text/plain, */*',
36
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
37
- 'X-APP-VERSION': '2.3.0',
38
- 'Origin': self.BASE_URL,
39
- 'Referer': f'{self.BASE_URL}/chat?_userMenuKey=chat',
40
- 'Sec-Fetch-Site': 'same-origin',
41
- 'Sec-Fetch-Mode': 'cors',
42
- 'Sec-Fetch-Dest': 'empty',
34
+ "Authorization": self.token,
35
+ "Content-Type": "application/json",
36
+ "Accept": "application/json, text/plain, */*",
37
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
38
+ "X-APP-VERSION": "2.3.0",
39
+ "Origin": self.BASE_URL,
40
+ "Referer": f"{self.BASE_URL}/chat?_userMenuKey=chat",
41
+ "Sec-Fetch-Site": "same-origin",
42
+ "Sec-Fetch-Mode": "cors",
43
+ "Sec-Fetch-Dest": "empty",
43
44
  }
44
45
 
45
46
  self.model_name = os.getenv("JARVIS_MODEL") or "deepseek-chat"
46
47
  if self.model_name not in self.get_available_models():
47
- PrettyOutput.print(f"警告: 选择的模型 {self.model_name} 不在可用列表中", OutputType.WARNING)
48
-
49
-
50
-
48
+ PrettyOutput.print(
49
+ f"警告: 选择的模型 {self.model_name} 不在可用列表中", OutputType.WARNING
50
+ )
51
51
 
52
52
  def set_model_name(self, model_name: str):
53
53
  """Set model name"""
@@ -58,24 +58,22 @@ class AI8Model(BasePlatform):
58
58
  """Create a new conversation"""
59
59
  try:
60
60
 
61
-
62
61
  # 1. 创建会话
63
- response = requests.post(
64
- f"{self.BASE_URL}/api/chat/session",
65
- headers=self.headers,
66
- json={}
62
+ response = while_success(
63
+ lambda: http.post(
64
+ f"{self.BASE_URL}/api/chat/session", headers=self.headers, json={}
65
+ ),
66
+ sleep_time=5,
67
67
  )
68
68
 
69
- if response.status_code != 200:
70
- PrettyOutput.print(f"创建会话失败: {response.status_code}", OutputType.WARNING)
71
- return False
72
-
73
69
  data = response.json()
74
- if data['code'] != 0:
75
- PrettyOutput.print(f"创建会话失败: {data.get('msg', '未知错误')}", OutputType.WARNING)
70
+ if data["code"] != 0:
71
+ PrettyOutput.print(
72
+ f"创建会话失败: {data.get('msg', '未知错误')}", OutputType.WARNING
73
+ )
76
74
  return False
77
75
 
78
- self.conversation = data['data']
76
+ self.conversation = data["data"]
79
77
 
80
78
  # 2. 更新会话设置
81
79
  session_data = {
@@ -85,25 +83,27 @@ class AI8Model(BasePlatform):
85
83
  "prompt": self.system_prompt,
86
84
  "plugins": [],
87
85
  "localPlugins": None,
88
- "useAppId": 0
86
+ "useAppId": 0,
89
87
  }
90
88
 
91
- response = requests.put(
92
- f"{self.BASE_URL}/api/chat/session/{self.conversation['id']}",
93
- headers=self.headers,
94
- json=session_data
89
+ response = while_success(
90
+ lambda: http.put(
91
+ f"{self.BASE_URL}/api/chat/session/{self.conversation['id']}", # type: ignore
92
+ headers=self.headers,
93
+ json=session_data,
94
+ ),
95
+ sleep_time=5,
95
96
  )
96
97
 
97
- if response.status_code == 200:
98
- data = response.json()
99
- if data['code'] == 0:
100
- self.conversation = data['data']
101
- return True
102
- else:
103
- PrettyOutput.print(f"更新会话设置失败: {data.get('msg', '未知错误')}", OutputType.WARNING)
104
- return False
98
+ data = response.json()
99
+ if data["code"] == 0:
100
+ self.conversation = data["data"]
101
+ return True
105
102
  else:
106
- PrettyOutput.print(f"更新会话设置失败: {response.status_code}", OutputType.WARNING)
103
+ PrettyOutput.print(
104
+ f"更新会话设置失败: {data.get('msg', '未知错误')}",
105
+ OutputType.WARNING,
106
+ )
107
107
  return False
108
108
 
109
109
  except Exception as e:
@@ -123,41 +123,40 @@ class AI8Model(BasePlatform):
123
123
  if not self.create_conversation():
124
124
  raise Exception("Failed to create conversation")
125
125
 
126
-
127
-
128
126
  payload = {
129
127
  "text": message,
130
- "sessionId": self.conversation['id'] if self.conversation else None,
131
- "files": []
128
+ "sessionId": self.conversation["id"] if self.conversation else None,
129
+ "files": [],
132
130
  }
133
131
 
134
-
135
- response = requests.post(
136
- f"{self.BASE_URL}/api/chat/completions",
137
- headers=self.headers,
138
- json=payload,
139
- stream=True
132
+ # 使用stream_post进行流式请求
133
+ response_stream = while_success(
134
+ lambda: http.stream_post(
135
+ f"{self.BASE_URL}/api/chat/completions",
136
+ headers=self.headers,
137
+ json=payload,
138
+ ),
139
+ sleep_time=5,
140
140
  )
141
141
 
142
- if response.status_code != 200:
143
- error_msg = f"Failed to chat: {response.status_code} {response.text}"
144
- PrettyOutput.print(error_msg, OutputType.WARNING)
145
- raise Exception(error_msg)
146
-
147
142
  # 处理流式响应
148
- for line in response.iter_lines():
149
- if line:
150
- line = line.decode('utf-8')
151
- if line.startswith('data: '):
152
- try:
153
- data = json.loads(line[6:])
154
- if data.get('type') == 'string':
155
- chunk = data.get('data', '')
156
- if chunk:
157
- yield chunk
158
-
159
- except json.JSONDecodeError:
160
- continue
143
+ for chunk in response_stream:
144
+ if chunk:
145
+ try:
146
+ line = chunk.decode("utf-8")
147
+ if line.startswith("data: "):
148
+ try:
149
+ data = json.loads(line[6:])
150
+ if data.get("type") == "string":
151
+ chunk_data = data.get("data", "")
152
+ if chunk_data:
153
+ yield chunk_data
154
+
155
+ except json.JSONDecodeError:
156
+ continue
157
+
158
+ except UnicodeDecodeError:
159
+ continue
161
160
 
162
161
  return None
163
162
 
@@ -169,30 +168,26 @@ class AI8Model(BasePlatform):
169
168
  """Return model name"""
170
169
  return self.model_name
171
170
 
172
-
173
171
  def delete_chat(self) -> bool:
174
172
  """Delete current chat session"""
175
173
  try:
176
174
  if not self.conversation:
177
175
  return True
178
176
 
179
-
180
- response = requests.delete(
181
- f"{self.BASE_URL}/api/chat/session/{self.conversation['id']}",
182
- headers=self.headers
177
+ response = while_success(
178
+ lambda: http.delete(
179
+ f"{self.BASE_URL}/api/chat/session/{self.conversation['id']}", # type: ignore
180
+ headers=self.headers,
181
+ ),
182
+ sleep_time=5,
183
183
  )
184
184
 
185
- if response.status_code == 200:
186
- data = response.json()
187
- if data['code'] == 0:
188
- self.conversation = None
189
- return True
190
- else:
191
- error_msg = f"删除会话失败: {data.get('msg', '未知错误')}"
192
- PrettyOutput.print(error_msg, OutputType.WARNING)
193
- return False
185
+ data = response.json()
186
+ if data["code"] == 0:
187
+ self.conversation = None
188
+ return True
194
189
  else:
195
- error_msg = f"删除会话请求失败: {response.status_code}"
190
+ error_msg = f"删除会话失败: {data.get('msg', '未知错误')}"
196
191
  PrettyOutput.print(error_msg, OutputType.WARNING)
197
192
  return False
198
193
 
@@ -210,25 +205,23 @@ class AI8Model(BasePlatform):
210
205
  if self.models:
211
206
  return list(self.models.keys())
212
207
 
213
- response = requests.get(
214
- f"{self.BASE_URL}/api/chat/tmpl",
215
- headers=self.headers
208
+ response = while_success(
209
+ lambda: http.get(
210
+ f"{self.BASE_URL}/api/chat/tmpl", headers=self.headers
211
+ ),
212
+ sleep_time=5,
216
213
  )
217
214
 
218
- if response.status_code != 200:
219
- PrettyOutput.print(f"获取模型列表失败: {response.status_code}", OutputType.WARNING)
220
- return []
221
-
222
215
  data = response.json()
223
- if data['code'] != 0:
224
- PrettyOutput.print(f"获取模型列表失败: {data.get('msg', '未知错误')}", OutputType.WARNING)
216
+ if data["code"] != 0:
217
+ PrettyOutput.print(
218
+ f"获取模型列表失败: {data.get('msg', '未知错误')}",
219
+ OutputType.WARNING,
220
+ )
225
221
  return []
226
222
 
227
223
  # 保存模型信息
228
- self.models = {
229
- model['value']: model
230
- for model in data['data']['models']
231
- }
224
+ self.models = {model["value"]: model for model in data["data"]["models"]}
232
225
 
233
226
  for model in self.models.values():
234
227
  # 添加标签
@@ -236,23 +229,23 @@ class AI8Model(BasePlatform):
236
229
 
237
230
  # 添加特性标记
238
231
  features = []
239
- if model['attr'].get('multimodal'):
232
+ if model["attr"].get("multimodal"):
240
233
  features.append("Multimodal")
241
- if model['attr'].get('plugin'):
234
+ if model["attr"].get("plugin"):
242
235
  features.append("Plugin support")
243
- if model['attr'].get('onlyImg'):
236
+ if model["attr"].get("onlyImg"):
244
237
  features.append("Image support")
245
- if model['attr'].get('tag'):
246
- features.append(model['attr']['tag'])
247
- if model['attr'].get('integral'):
248
- features.append(model['attr']['integral'])
238
+ if model["attr"].get("tag"):
239
+ features.append(model["attr"]["tag"])
240
+ if model["attr"].get("integral"):
241
+ features.append(model["attr"]["integral"])
249
242
  # 添加备注
250
- if model['attr'].get('note'):
243
+ if model["attr"].get("note"):
251
244
  model_str += f" - {model['attr']['note']}"
252
245
  if features:
253
246
  model_str += f" [{'|'.join(features)}]"
254
247
 
255
- model['desc'] = model_str
248
+ model["desc"] = model_str
256
249
 
257
250
  return list(self.models.keys())
258
251
 
@@ -262,9 +255,9 @@ class AI8Model(BasePlatform):
262
255
 
263
256
  def support_upload_files(self) -> bool:
264
257
  return False
265
-
258
+
266
259
  def support_web(self) -> bool:
267
260
  return False
268
-
261
+
269
262
  def upload_files(self, file_list: List[str]) -> bool:
270
263
  return False
@@ -2,10 +2,12 @@ import mimetypes
2
2
  import os
3
3
  from typing import Dict, Generator, List, Tuple
4
4
  from jarvis.jarvis_platform.base import BasePlatform
5
- import requests
6
5
  import json
7
6
 
7
+ from jarvis.jarvis_utils import http
8
8
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
9
+ from jarvis.jarvis_utils.utils import while_success
10
+
9
11
 
10
12
  class OyiModel(BasePlatform):
11
13
  """Oyi model implementation"""
@@ -16,7 +18,7 @@ class OyiModel(BasePlatform):
16
18
  def get_model_list(self) -> List[Tuple[str, str]]:
17
19
  """Get model list"""
18
20
  self.get_available_models()
19
- return [(name,info['desc']) for name,info in self.models.items()]
21
+ return [(name, info["desc"]) for name, info in self.models.items()]
20
22
 
21
23
  def __init__(self):
22
24
  """Initialize model"""
@@ -33,23 +35,23 @@ class OyiModel(BasePlatform):
33
35
 
34
36
  self.model_name = os.getenv("JARVIS_MODEL") or "deepseek-chat"
35
37
  if self.model_name not in [m.split()[0] for m in self.get_available_models()]:
36
- PrettyOutput.print(f"警告: 选择的模型 {self.model_name} 不在可用列表中", OutputType.WARNING)
37
-
38
+ PrettyOutput.print(
39
+ f"警告: 选择的模型 {self.model_name} 不在可用列表中", OutputType.WARNING
40
+ )
38
41
 
39
42
  def set_model_name(self, model_name: str):
40
43
  """Set model name"""
41
44
 
42
45
  self.model_name = model_name
43
46
 
44
-
45
47
  def create_conversation(self) -> bool:
46
48
  """Create a new conversation"""
47
49
  try:
48
50
  headers = {
49
- 'Authorization': f'Bearer {self.token}',
50
- 'Content-Type': 'application/json',
51
- 'Accept': 'application/json',
52
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36'
51
+ "Authorization": f"Bearer {self.token}",
52
+ "Content-Type": "application/json",
53
+ "Accept": "application/json",
54
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
53
55
  }
54
56
 
55
57
  payload = {
@@ -58,35 +60,36 @@ class OyiModel(BasePlatform):
58
60
  "title": "New conversation",
59
61
  "isLock": False,
60
62
  "systemMessage": "",
61
- "params": json.dumps({
62
- "model": self.model_name,
63
- "is_webSearch": True,
64
- "message": [],
65
- "systemMessage": None,
66
- "requestMsgCount": 65536,
67
- "temperature": 0.8,
68
- "speechVoice": "Alloy",
69
- "max_tokens": 8192,
70
- "chatPluginIds": []
71
- })
63
+ "params": json.dumps(
64
+ {
65
+ "model": self.model_name,
66
+ "is_webSearch": True,
67
+ "message": [],
68
+ "systemMessage": None,
69
+ "requestMsgCount": 65536,
70
+ "temperature": 0.8,
71
+ "speechVoice": "Alloy",
72
+ "max_tokens": 8192,
73
+ "chatPluginIds": [],
74
+ }
75
+ ),
72
76
  }
73
77
 
74
- response = requests.post(
75
- f"{self.BASE_URL}/chatapi/chat/save",
76
- headers=headers,
77
- json=payload
78
+ response = while_success(
79
+ lambda: http.post(
80
+ f"{self.BASE_URL}/chatapi/chat/save", headers=headers, json=payload
81
+ ),
82
+ sleep_time=5,
78
83
  )
79
84
 
80
- if response.status_code == 200:
81
- data = response.json()
82
- if data['code'] == 200 and data['type'] == 'success':
83
- self.conversation = data
84
- return True
85
- else:
86
- PrettyOutput.print(f"创建会话失败: {data['message']}", OutputType.WARNING)
87
- return False
85
+ data = response.json()
86
+ if data["code"] == 200 and data["type"] == "success":
87
+ self.conversation = data
88
+ return True
88
89
  else:
89
- PrettyOutput.print(f"创建会话失败: {response.status_code}", OutputType.WARNING)
90
+ PrettyOutput.print(
91
+ f"创建会话失败: {data['message']}", OutputType.WARNING
92
+ )
90
93
  return False
91
94
 
92
95
  except Exception as e:
@@ -114,19 +117,21 @@ class OyiModel(BasePlatform):
114
117
 
115
118
  # 1. 发送消息
116
119
  headers = {
117
- 'Authorization': f'Bearer {self.token}',
118
- 'Content-Type': 'application/json',
119
- 'Accept': 'application/json, text/plain, */*',
120
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
121
- 'Origin': 'https://ai.rcouyi.com',
122
- 'Referer': 'https://ai.rcouyi.com/'
120
+ "Authorization": f"Bearer {self.token}",
121
+ "Content-Type": "application/json",
122
+ "Accept": "application/json, text/plain, */*",
123
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
124
+ "Origin": "https://ai.rcouyi.com",
125
+ "Referer": "https://ai.rcouyi.com/",
123
126
  }
124
127
 
125
128
  payload = {
126
- "topicId": self.conversation['result']['id'] if self.conversation else None,
129
+ "topicId": (
130
+ self.conversation["result"]["id"] if self.conversation else None
131
+ ),
127
132
  "messages": self.messages,
128
133
  "content": message,
129
- "contentFiles": []
134
+ "contentFiles": [],
130
135
  }
131
136
 
132
137
  # 如果有上传的文件,添加到请求中
@@ -138,52 +143,47 @@ class OyiModel(BasePlatform):
138
143
  self.messages.append({"role": "user", "content": message})
139
144
 
140
145
  # 发送消息
141
- response = requests.post(
142
- f"{self.BASE_URL}/chatapi/chat/message",
143
- headers=headers,
144
- json=payload
146
+ response = while_success(
147
+ lambda: http.post(
148
+ f"{self.BASE_URL}/chatapi/chat/message",
149
+ headers=headers,
150
+ json=payload,
151
+ ),
152
+ sleep_time=5,
145
153
  )
146
154
 
147
- if response.status_code != 200:
148
- error_msg = f"聊天请求失败: {response.status_code}"
149
- PrettyOutput.print(error_msg, OutputType.WARNING)
150
- raise Exception(error_msg)
151
-
152
155
  data = response.json()
153
- if data['code'] != 200 or data['type'] != 'success':
156
+ if data["code"] != 200 or data["type"] != "success":
154
157
  error_msg = f"聊天失败: {data.get('message', '未知错误')}"
155
158
  PrettyOutput.print(error_msg, OutputType.WARNING)
156
159
  raise Exception(error_msg)
157
160
 
158
- message_id = data['result'][-1]
161
+ message_id = data["result"][-1]
159
162
 
160
163
  # 获取响应内容
161
- response = requests.post(
162
- f"{self.BASE_URL}/chatapi/chat/message/{message_id}",
163
- headers=headers,
164
- stream=True
164
+ response = while_success(
165
+ lambda: http.stream_post(
166
+ f"{self.BASE_URL}/chatapi/chat/message/{message_id}",
167
+ headers=headers,
168
+ ),
169
+ sleep_time=5,
165
170
  )
166
171
 
167
- if response.status_code == 200:
168
- full_response = ""
169
- bin = b""
170
- for chunk in response.iter_content(decode_unicode=True):
171
- if chunk:
172
- bin += chunk
173
- try:
174
- text = bin.decode('utf-8')
175
- except UnicodeDecodeError:
176
- continue
177
- full_response += text
178
- bin = b""
179
- yield text
180
-
181
- self.messages.append({"role": "assistant", "content": full_response})
182
- return None
183
- else:
184
- error_msg = f"获取响应失败: {response.status_code}"
185
- PrettyOutput.print(error_msg, OutputType.WARNING)
186
- raise Exception(error_msg)
172
+ full_response = ""
173
+ bin = b""
174
+ for chunk in response:
175
+ if chunk:
176
+ bin += chunk
177
+ try:
178
+ text = bin.decode("utf-8")
179
+ except UnicodeDecodeError:
180
+ continue
181
+ full_response += text
182
+ bin = b""
183
+ yield text
184
+
185
+ self.messages.append({"role": "assistant", "content": full_response})
186
+ return None
187
187
  except Exception as e:
188
188
  PrettyOutput.print(f"聊天失败: {str(e)}", OutputType.ERROR)
189
189
  raise e
@@ -192,7 +192,6 @@ class OyiModel(BasePlatform):
192
192
  """Return model name"""
193
193
  return self.model_name
194
194
 
195
-
196
195
  def delete_chat(self) -> bool:
197
196
  """Delete current chat session"""
198
197
  try:
@@ -200,37 +199,34 @@ class OyiModel(BasePlatform):
200
199
  return True
201
200
 
202
201
  headers = {
203
- 'Authorization': f'Bearer {self.token}',
204
- 'Content-Type': 'application/json',
205
- 'Accept': 'application/json, text/plain, */*',
206
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
207
- 'Origin': 'https://ai.rcouyi.com',
208
- 'Referer': 'https://ai.rcouyi.com/'
202
+ "Authorization": f"Bearer {self.token}",
203
+ "Content-Type": "application/json",
204
+ "Accept": "application/json, text/plain, */*",
205
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
206
+ "Origin": "https://ai.rcouyi.com",
207
+ "Referer": "https://ai.rcouyi.com/",
209
208
  }
210
209
 
211
- response = requests.post(
212
- f"{self.BASE_URL}/chatapi/chat/{self.conversation['result']['id']}",
213
- headers=headers,
214
- json={}
210
+ response = while_success(
211
+ lambda: http.post(
212
+ f"{self.BASE_URL}/chatapi/chat/{self.conversation['result']['id']}", # type: ignore
213
+ headers=headers,
214
+ json={},
215
+ ),
216
+ sleep_time=5,
215
217
  )
216
218
 
217
- if response.status_code == 200:
218
- data = response.json()
219
- if data['code'] == 200 and data['type'] == 'success':
220
- self.messages = []
221
- self.conversation = None
222
- self.first_chat = True
223
- return True
224
- else:
225
- error_msg = f"删除会话失败: {data.get('message', '未知错误')}"
226
- PrettyOutput.print(error_msg, OutputType.WARNING)
227
- return False
219
+ data = response.json()
220
+ if data["code"] == 200 and data["type"] == "success":
221
+ self.messages = []
222
+ self.conversation = None
223
+ self.first_chat = True
224
+ return True
228
225
  else:
229
- error_msg = f"删除会话请求失败: {response.status_code}"
226
+ error_msg = f"删除会话失败: {data.get('message', '未知错误')}"
230
227
  PrettyOutput.print(error_msg, OutputType.WARNING)
231
228
  return False
232
229
 
233
-
234
230
  except Exception as e:
235
231
  PrettyOutput.print(f"删除会话失败: {str(e)}", OutputType.ERROR)
236
232
  return False
@@ -246,55 +242,53 @@ class OyiModel(BasePlatform):
246
242
  return list(self.models.keys())
247
243
 
248
244
  headers = {
249
- 'Content-Type': 'application/json',
250
- 'Accept': 'application/json, text/plain, */*',
251
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
252
- 'Origin': 'https://ai.rcouyi.com',
253
- 'Referer': 'https://ai.rcouyi.com/'
245
+ "Content-Type": "application/json",
246
+ "Accept": "application/json, text/plain, */*",
247
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
248
+ "Origin": "https://ai.rcouyi.com",
249
+ "Referer": "https://ai.rcouyi.com/",
254
250
  }
255
251
 
256
- response = requests.get(
257
- "https://ai.rcouyi.com/config/system.json",
258
- headers=headers
252
+ response = while_success(
253
+ lambda: http.get(
254
+ "https://ai.rcouyi.com/config/system.json", headers=headers
255
+ ),
256
+ sleep_time=5,
259
257
  )
260
258
 
261
- if response.status_code != 200:
262
- PrettyOutput.print(f"获取模型列表失败: {response.status_code}", OutputType.WARNING)
263
- return []
264
-
265
259
  data = response.json()
266
260
 
267
261
  # 保存模型信息
268
262
  self.models = {
269
- model['value']: model
270
- for model in data.get('model', [])
271
- if model.get('enable', False) # 只保存启用的模型
263
+ model["value"]: model
264
+ for model in data.get("model", [])
265
+ if model.get("enable", False) # 只保存启用的模型
272
266
  }
273
267
 
274
268
  # 格式化显示
275
269
  models = []
276
270
  for model in self.models.values():
277
271
  # 基本信息
278
- model_name = model['value']
279
- model_str = model['label']
272
+ model_name = model["value"]
273
+ model_str = model["label"]
280
274
 
281
275
  # 添加后缀标签
282
- suffix = model.get('suffix', [])
276
+ suffix = model.get("suffix", [])
283
277
  if suffix:
284
278
  # 处理新格式的suffix (字典列表)
285
279
  if suffix and isinstance(suffix[0], dict):
286
- suffix_str = ', '.join(s.get('tag', '') for s in suffix)
280
+ suffix_str = ", ".join(s.get("tag", "") for s in suffix)
287
281
  # 处理旧格式的suffix (字符串列表)
288
282
  else:
289
- suffix_str = ', '.join(str(s) for s in suffix)
283
+ suffix_str = ", ".join(str(s) for s in suffix)
290
284
  model_str += f" ({suffix_str})"
291
285
 
292
286
  # 添加描述或提示
293
- info = model.get('tooltip') or model.get('description', '')
287
+ info = model.get("tooltip") or model.get("description", "")
294
288
  if info:
295
289
  model_str += f" - {info}"
296
290
 
297
- model['desc'] = model_str
291
+ model["desc"] = model_str
298
292
  models.append(model_name)
299
293
 
300
294
  return sorted(models)
@@ -305,10 +299,9 @@ class OyiModel(BasePlatform):
305
299
 
306
300
  def support_upload_files(self) -> bool:
307
301
  return False
308
-
309
-
302
+
310
303
  def support_web(self) -> bool:
311
304
  return False
312
-
305
+
313
306
  def upload_files(self, file_list: List[str]) -> bool:
314
307
  return False
@@ -38,7 +38,7 @@ def get_single_line_input(tip: str) -> str:
38
38
  返回:
39
39
  str: 用户的输入
40
40
  """
41
- session = PromptSession(history=None)
41
+ session: PromptSession = PromptSession(history=None)
42
42
  style = PromptStyle.from_dict(
43
43
  {
44
44
  "prompt": "ansicyan",
@@ -190,7 +190,7 @@ def get_multiline_input(tip: str) -> str:
190
190
  """
191
191
  # 显示输入说明
192
192
  PrettyOutput.section(
193
- "用户输入 - 使用 @ 触发文件补全,Tab 选择补全项,Ctrl+J 提交,Ctrl+L 复制最后一条消息,按 Ctrl+C 取消输入",
193
+ "用户输入 - 使用 @ 触发文件补全,Tab 选择补全项,Ctrl+J 提交,Ctrl+O 复制最后一条消息,按 Ctrl+C 取消输入",
194
194
  OutputType.USER,
195
195
  )
196
196
  print(f"{Fore.GREEN}{tip}{ColoramaStyle.RESET_ALL}")
@@ -212,9 +212,9 @@ def get_multiline_input(tip: str) -> str:
212
212
  """处理Ctrl+J以提交输入。"""
213
213
  event.current_buffer.validate_and_handle()
214
214
 
215
- @bindings.add("c-l")
215
+ @bindings.add("c-o")
216
216
  def _(event):
217
- """处理Ctrl+L以复制最后一条消息到剪贴板。"""
217
+ """处理Ctrl+O以复制最后一条消息到剪贴板。"""
218
218
  from jarvis.jarvis_utils.globals import get_last_message
219
219
  import subprocess
220
220
 
@@ -246,7 +246,7 @@ def get_multiline_input(tip: str) -> str:
246
246
  # 获取数据目录路径
247
247
  history_dir = get_data_dir()
248
248
  # 初始化带历史记录的会话
249
- session = PromptSession(
249
+ session: PromptSession = PromptSession(
250
250
  history=FileHistory(os.path.join(history_dir, "multiline_input_history")),
251
251
  completer=FileCompleter(),
252
252
  key_bindings=bindings,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jarvis-ai-assistant
3
- Version: 0.1.212
3
+ Version: 0.1.213
4
4
  Summary: Jarvis: An AI assistant that uses tools to interact with the system
5
5
  Home-page: https://github.com/skyfireitdiy/Jarvis
6
6
  Author: skyfire
@@ -54,8 +54,8 @@ Requires-Dist: pillow==10.2.0
54
54
  Requires-Dist: openai==1.78.1
55
55
  Requires-Dist: tabulate==0.9.0
56
56
  Requires-Dist: pyte==0.8.2
57
- Requires-Dist: pyyaml>=6.0.2
58
57
  Requires-Dist: httpx>=0.28.1
58
+ Requires-Dist: pyyaml>=5.3.1
59
59
  Provides-Extra: dev
60
60
  Requires-Dist: pytest; extra == "dev"
61
61
  Requires-Dist: black; extra == "dev"
@@ -1,4 +1,4 @@
1
- jarvis/__init__.py,sha256=kz-6zpmo_NPSLXBTjHQyhEg8Z5G5ayw0RFZS5KubWws,75
1
+ jarvis/__init__.py,sha256=-plSw2QooYexMaRlKIRHSdkQww5y9LDlUdoQ1gxFf2I,75
2
2
  jarvis/jarvis_agent/__init__.py,sha256=QbI5vkourPJZ2OR63RBZAtFptTYrZz_si8bIkc9EB2o,31709
3
3
  jarvis/jarvis_agent/builtin_input_handler.py,sha256=1V7kV5Zhw2HE3Xgjs1R-43RZ2huq3Kg-32NCdNnyZmA,2216
4
4
  jarvis/jarvis_agent/edit_file_handler.py,sha256=bIciBghx5maDz09x0XNTxdNsyrBbTND95GupVdJIVVg,16762
@@ -45,12 +45,12 @@ jarvis/jarvis_methodology/main.py,sha256=-PqsWvtpUJkkhiGgV-1JegEnEZBmv8SHnNMNNm_
45
45
  jarvis/jarvis_multi_agent/__init__.py,sha256=sDd3sK88dS7_qAz2ywIAaEWdQ4iRVCiuBu2rQQmrKbU,4512
46
46
  jarvis/jarvis_multi_agent/main.py,sha256=h7VUSwoPrES0XTK8z5kt3XLX1mmcm8UEuFEHQOUWPH4,1696
47
47
  jarvis/jarvis_platform/__init__.py,sha256=WLQHSiE87PPket2M50_hHzjdMIgPIBx2VF8JfB_NNRk,105
48
- jarvis/jarvis_platform/ai8.py,sha256=3LA4vSsaP-p9zXmj7o0jzL1WI8UMv4-P0YNz9s9r-6U,9115
48
+ jarvis/jarvis_platform/ai8.py,sha256=UWbe6kveQvOO8wMM9mh5YWyB0zapUEeFiYVPBMnhBAE,8845
49
49
  jarvis/jarvis_platform/base.py,sha256=CBFk1Kq7qzOwafOj22bacXChWvCnap3D4IacZCWC_Ss,7882
50
50
  jarvis/jarvis_platform/human.py,sha256=_WQtC5w6QJnHh-3KuW8T49C-HucXiHsBEVw-m51ykj4,3196
51
51
  jarvis/jarvis_platform/kimi.py,sha256=w0-OJ6xkOGPApcc2Jvc30BMjabwrnzcndmsJJsWOWJg,13419
52
52
  jarvis/jarvis_platform/openai.py,sha256=uEjBikfFj7kp5wondLvOx4WdkmTX0aqF6kixxAufcHg,4806
53
- jarvis/jarvis_platform/oyi.py,sha256=6SBAO-lhk6yoZvrglGF8rHIDA7SbcvjRy8sYYJ7ou0w,11241
53
+ jarvis/jarvis_platform/oyi.py,sha256=U6klSMESC69H9xTo44PXD1ZvdnMa5d7qE3jcPmPBspY,10662
54
54
  jarvis/jarvis_platform/registry.py,sha256=Sz4ADAaxuufpAQG0KSQZuL1yALzH-aF3FDapkNn5foE,8107
55
55
  jarvis/jarvis_platform/tongyi.py,sha256=juvzMjZ2mbNzSWzem8snmFuE28YVOjjE_YdHCZa9Qnw,20698
56
56
  jarvis/jarvis_platform/yuanbao.py,sha256=ZsKXWifESXGfvB9eOot1I6TnhlmgXwnaft3e2UXgSXk,21045
@@ -83,14 +83,14 @@ jarvis/jarvis_utils/file_processors.py,sha256=XiM248SHS7lLgQDCbORVFWqinbVDUawYxW
83
83
  jarvis/jarvis_utils/git_utils.py,sha256=7AZblSD4b76vXxaDFkmZOy5rNkwvkwQQxGUy3NAusDQ,21641
84
84
  jarvis/jarvis_utils/globals.py,sha256=WzZh_acNfHJj1LDulhyLQ7cojksBy0gdrITe0vH1XA0,3901
85
85
  jarvis/jarvis_utils/http.py,sha256=Uqt1kcz0HWnAfXHHi1fNGwLb2lcVUqpbrG2Uk_-kcIU,4882
86
- jarvis/jarvis_utils/input.py,sha256=Vd6Ksh9PYM8X0OvK2x22UoG0y3ejlssk-JIAv5X_kRM,8877
86
+ jarvis/jarvis_utils/input.py,sha256=D0fQ6sRHjBaMm8s1L8HccC09Qlt_JD_SB_EHPCoztyA,8907
87
87
  jarvis/jarvis_utils/methodology.py,sha256=-cvM6pwgJK7BXCYg2uVjIId_j3v5RUh2z2PBcK_2vj4,8155
88
88
  jarvis/jarvis_utils/output.py,sha256=PRCgudPOB8gMEP3u-g0FGD2c6tBgJhLXUMqNPglfjV8,10813
89
89
  jarvis/jarvis_utils/tag.py,sha256=f211opbbbTcSyzCDwuIK_oCnKhXPNK-RknYyGzY1yD0,431
90
90
  jarvis/jarvis_utils/utils.py,sha256=BoRwLcixdf7mU3Tawe95ygGhQpkMffrFYLYhPwIvw8A,14498
91
- jarvis_ai_assistant-0.1.212.dist-info/licenses/LICENSE,sha256=AGgVgQmTqFvaztRtCAXsAMryUymB18gZif7_l2e1XOg,1063
92
- jarvis_ai_assistant-0.1.212.dist-info/METADATA,sha256=ZlgX9X1Zd8T5cKIXuhfydCw9qszuXa_TUR6HnyJkAVc,19564
93
- jarvis_ai_assistant-0.1.212.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
94
- jarvis_ai_assistant-0.1.212.dist-info/entry_points.txt,sha256=SF46ViTZcQVZEfbqzJDKKVc9TrN1x-P1mQ6wup7u2HY,875
95
- jarvis_ai_assistant-0.1.212.dist-info/top_level.txt,sha256=1BOxyWfzOP_ZXj8rVTDnNCJ92bBGB0rwq8N1PCpoMIs,7
96
- jarvis_ai_assistant-0.1.212.dist-info/RECORD,,
91
+ jarvis_ai_assistant-0.1.213.dist-info/licenses/LICENSE,sha256=AGgVgQmTqFvaztRtCAXsAMryUymB18gZif7_l2e1XOg,1063
92
+ jarvis_ai_assistant-0.1.213.dist-info/METADATA,sha256=ihUbPrOcnHuEjAtbY2-IA3Tj_ZOM3Hj_YDT5wJcsH6M,19564
93
+ jarvis_ai_assistant-0.1.213.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
94
+ jarvis_ai_assistant-0.1.213.dist-info/entry_points.txt,sha256=SF46ViTZcQVZEfbqzJDKKVc9TrN1x-P1mQ6wup7u2HY,875
95
+ jarvis_ai_assistant-0.1.213.dist-info/top_level.txt,sha256=1BOxyWfzOP_ZXj8rVTDnNCJ92bBGB0rwq8N1PCpoMIs,7
96
+ jarvis_ai_assistant-0.1.213.dist-info/RECORD,,