jarvis-ai-assistant 0.1.211__py3-none-any.whl → 0.1.212__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_platform/ai8.py +270 -0
- jarvis/jarvis_platform/base.py +3 -0
- jarvis/jarvis_platform/kimi.py +67 -48
- jarvis/jarvis_platform/oyi.py +314 -0
- jarvis/jarvis_platform_manager/main.py +31 -23
- jarvis/jarvis_utils/globals.py +31 -0
- jarvis/jarvis_utils/input.py +34 -12
- {jarvis_ai_assistant-0.1.211.dist-info → jarvis_ai_assistant-0.1.212.dist-info}/METADATA +1 -1
- {jarvis_ai_assistant-0.1.211.dist-info → jarvis_ai_assistant-0.1.212.dist-info}/RECORD +14 -12
- {jarvis_ai_assistant-0.1.211.dist-info → jarvis_ai_assistant-0.1.212.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.211.dist-info → jarvis_ai_assistant-0.1.212.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.211.dist-info → jarvis_ai_assistant-0.1.212.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.211.dist-info → jarvis_ai_assistant-0.1.212.dist-info}/top_level.txt +0 -0
jarvis/__init__.py
CHANGED
@@ -0,0 +1,270 @@
|
|
1
|
+
import os
|
2
|
+
from typing import Dict, Generator, List, Tuple
|
3
|
+
from jarvis.jarvis_platform.base import BasePlatform
|
4
|
+
import requests
|
5
|
+
import json
|
6
|
+
import base64
|
7
|
+
|
8
|
+
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
9
|
+
|
10
|
+
class AI8Model(BasePlatform):
|
11
|
+
"""AI8 model implementation"""
|
12
|
+
|
13
|
+
platform_name = "ai8"
|
14
|
+
BASE_URL = "https://ai8.rcouyi.com"
|
15
|
+
|
16
|
+
def get_model_list(self) -> List[Tuple[str, str]]:
|
17
|
+
"""获取模型列表"""
|
18
|
+
self.get_available_models()
|
19
|
+
return [(name,info['desc']) for name,info in self.models.items()]
|
20
|
+
|
21
|
+
def __init__(self):
|
22
|
+
"""Initialize model"""
|
23
|
+
super().__init__()
|
24
|
+
self.system_prompt = ""
|
25
|
+
self.conversation = {}
|
26
|
+
self.models = {} # 存储模型信息
|
27
|
+
|
28
|
+
self.token = os.getenv("AI8_API_KEY")
|
29
|
+
if not self.token:
|
30
|
+
PrettyOutput.print("未设置 AI8_API_KEY", OutputType.WARNING)
|
31
|
+
|
32
|
+
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',
|
43
|
+
}
|
44
|
+
|
45
|
+
self.model_name = os.getenv("JARVIS_MODEL") or "deepseek-chat"
|
46
|
+
if self.model_name not in self.get_available_models():
|
47
|
+
PrettyOutput.print(f"警告: 选择的模型 {self.model_name} 不在可用列表中", OutputType.WARNING)
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
def set_model_name(self, model_name: str):
|
53
|
+
"""Set model name"""
|
54
|
+
|
55
|
+
self.model_name = model_name
|
56
|
+
|
57
|
+
def create_conversation(self) -> bool:
|
58
|
+
"""Create a new conversation"""
|
59
|
+
try:
|
60
|
+
|
61
|
+
|
62
|
+
# 1. 创建会话
|
63
|
+
response = requests.post(
|
64
|
+
f"{self.BASE_URL}/api/chat/session",
|
65
|
+
headers=self.headers,
|
66
|
+
json={}
|
67
|
+
)
|
68
|
+
|
69
|
+
if response.status_code != 200:
|
70
|
+
PrettyOutput.print(f"创建会话失败: {response.status_code}", OutputType.WARNING)
|
71
|
+
return False
|
72
|
+
|
73
|
+
data = response.json()
|
74
|
+
if data['code'] != 0:
|
75
|
+
PrettyOutput.print(f"创建会话失败: {data.get('msg', '未知错误')}", OutputType.WARNING)
|
76
|
+
return False
|
77
|
+
|
78
|
+
self.conversation = data['data']
|
79
|
+
|
80
|
+
# 2. 更新会话设置
|
81
|
+
session_data = {
|
82
|
+
**self.conversation,
|
83
|
+
"model": self.model_name,
|
84
|
+
"contextCount": 65536,
|
85
|
+
"prompt": self.system_prompt,
|
86
|
+
"plugins": [],
|
87
|
+
"localPlugins": None,
|
88
|
+
"useAppId": 0
|
89
|
+
}
|
90
|
+
|
91
|
+
response = requests.put(
|
92
|
+
f"{self.BASE_URL}/api/chat/session/{self.conversation['id']}",
|
93
|
+
headers=self.headers,
|
94
|
+
json=session_data
|
95
|
+
)
|
96
|
+
|
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
|
105
|
+
else:
|
106
|
+
PrettyOutput.print(f"更新会话设置失败: {response.status_code}", OutputType.WARNING)
|
107
|
+
return False
|
108
|
+
|
109
|
+
except Exception as e:
|
110
|
+
PrettyOutput.print(f"创建会话失败: {str(e)}", OutputType.ERROR)
|
111
|
+
return False
|
112
|
+
|
113
|
+
def set_system_prompt(self, message: str):
|
114
|
+
"""Set system message"""
|
115
|
+
self.system_prompt = message
|
116
|
+
|
117
|
+
def chat(self, message: str) -> Generator[str, None, None]:
|
118
|
+
"""Execute conversation"""
|
119
|
+
try:
|
120
|
+
|
121
|
+
# 确保有会话ID
|
122
|
+
if not self.conversation:
|
123
|
+
if not self.create_conversation():
|
124
|
+
raise Exception("Failed to create conversation")
|
125
|
+
|
126
|
+
|
127
|
+
|
128
|
+
payload = {
|
129
|
+
"text": message,
|
130
|
+
"sessionId": self.conversation['id'] if self.conversation else None,
|
131
|
+
"files": []
|
132
|
+
}
|
133
|
+
|
134
|
+
|
135
|
+
response = requests.post(
|
136
|
+
f"{self.BASE_URL}/api/chat/completions",
|
137
|
+
headers=self.headers,
|
138
|
+
json=payload,
|
139
|
+
stream=True
|
140
|
+
)
|
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
|
+
# 处理流式响应
|
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
|
161
|
+
|
162
|
+
return None
|
163
|
+
|
164
|
+
except Exception as e:
|
165
|
+
PrettyOutput.print(f"对话异常: {str(e)}", OutputType.ERROR)
|
166
|
+
raise e
|
167
|
+
|
168
|
+
def name(self) -> str:
|
169
|
+
"""Return model name"""
|
170
|
+
return self.model_name
|
171
|
+
|
172
|
+
|
173
|
+
def delete_chat(self) -> bool:
|
174
|
+
"""Delete current chat session"""
|
175
|
+
try:
|
176
|
+
if not self.conversation:
|
177
|
+
return True
|
178
|
+
|
179
|
+
|
180
|
+
response = requests.delete(
|
181
|
+
f"{self.BASE_URL}/api/chat/session/{self.conversation['id']}",
|
182
|
+
headers=self.headers
|
183
|
+
)
|
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
|
194
|
+
else:
|
195
|
+
error_msg = f"删除会话请求失败: {response.status_code}"
|
196
|
+
PrettyOutput.print(error_msg, OutputType.WARNING)
|
197
|
+
return False
|
198
|
+
|
199
|
+
except Exception as e:
|
200
|
+
PrettyOutput.print(f"删除会话失败: {str(e)}", OutputType.ERROR)
|
201
|
+
return False
|
202
|
+
|
203
|
+
def get_available_models(self) -> List[str]:
|
204
|
+
"""Get available model list
|
205
|
+
|
206
|
+
Returns:
|
207
|
+
List[str]: Available model name list
|
208
|
+
"""
|
209
|
+
try:
|
210
|
+
if self.models:
|
211
|
+
return list(self.models.keys())
|
212
|
+
|
213
|
+
response = requests.get(
|
214
|
+
f"{self.BASE_URL}/api/chat/tmpl",
|
215
|
+
headers=self.headers
|
216
|
+
)
|
217
|
+
|
218
|
+
if response.status_code != 200:
|
219
|
+
PrettyOutput.print(f"获取模型列表失败: {response.status_code}", OutputType.WARNING)
|
220
|
+
return []
|
221
|
+
|
222
|
+
data = response.json()
|
223
|
+
if data['code'] != 0:
|
224
|
+
PrettyOutput.print(f"获取模型列表失败: {data.get('msg', '未知错误')}", OutputType.WARNING)
|
225
|
+
return []
|
226
|
+
|
227
|
+
# 保存模型信息
|
228
|
+
self.models = {
|
229
|
+
model['value']: model
|
230
|
+
for model in data['data']['models']
|
231
|
+
}
|
232
|
+
|
233
|
+
for model in self.models.values():
|
234
|
+
# 添加标签
|
235
|
+
model_str = f"{model['label']}"
|
236
|
+
|
237
|
+
# 添加特性标记
|
238
|
+
features = []
|
239
|
+
if model['attr'].get('multimodal'):
|
240
|
+
features.append("Multimodal")
|
241
|
+
if model['attr'].get('plugin'):
|
242
|
+
features.append("Plugin support")
|
243
|
+
if model['attr'].get('onlyImg'):
|
244
|
+
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'])
|
249
|
+
# 添加备注
|
250
|
+
if model['attr'].get('note'):
|
251
|
+
model_str += f" - {model['attr']['note']}"
|
252
|
+
if features:
|
253
|
+
model_str += f" [{'|'.join(features)}]"
|
254
|
+
|
255
|
+
model['desc'] = model_str
|
256
|
+
|
257
|
+
return list(self.models.keys())
|
258
|
+
|
259
|
+
except Exception as e:
|
260
|
+
PrettyOutput.print(f"获取模型列表失败: {str(e)}", OutputType.ERROR)
|
261
|
+
return []
|
262
|
+
|
263
|
+
def support_upload_files(self) -> bool:
|
264
|
+
return False
|
265
|
+
|
266
|
+
def support_web(self) -> bool:
|
267
|
+
return False
|
268
|
+
|
269
|
+
def upload_files(self, file_list: List[str]) -> bool:
|
270
|
+
return False
|
jarvis/jarvis_platform/base.py
CHANGED
@@ -166,6 +166,9 @@ class BasePlatform(ABC):
|
|
166
166
|
result: str = while_true(
|
167
167
|
lambda: while_success(lambda: self._chat(message), 5), 5
|
168
168
|
)
|
169
|
+
from jarvis.jarvis_utils.globals import set_last_message
|
170
|
+
|
171
|
+
set_last_message(result)
|
169
172
|
return result
|
170
173
|
finally:
|
171
174
|
set_in_chat(False)
|
jarvis/jarvis_platform/kimi.py
CHANGED
@@ -151,34 +151,43 @@ class KimiModel(BasePlatform):
|
|
151
151
|
retry_count = 0
|
152
152
|
|
153
153
|
while retry_count < max_retries:
|
154
|
-
payload =
|
155
|
-
|
156
|
-
lambda: http.
|
154
|
+
payload = {"ids": [file_id]}
|
155
|
+
response_stream = while_success(
|
156
|
+
lambda: http.stream_post(url, headers=headers, json=payload),
|
157
157
|
sleep_time=5,
|
158
158
|
)
|
159
159
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
if isinstance(line, bytes):
|
166
|
-
line = line.decode("utf-8")
|
167
|
-
else:
|
168
|
-
line = str(line)
|
169
|
-
|
170
|
-
if not line.startswith("data: "):
|
171
|
-
continue
|
160
|
+
response_data = b""
|
161
|
+
|
162
|
+
# 处理流式响应
|
163
|
+
for chunk in response_stream:
|
164
|
+
response_data += chunk
|
172
165
|
|
166
|
+
# 尝试解析SSE格式的数据
|
173
167
|
try:
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
168
|
+
# 查找完整的数据行
|
169
|
+
lines = response_data.decode("utf-8").split("\n")
|
170
|
+
response_data = b"" # 重置缓冲区
|
171
|
+
|
172
|
+
for line in lines:
|
173
|
+
if not line.strip():
|
174
|
+
continue
|
175
|
+
|
176
|
+
# SSE格式的行通常以"data: "开头
|
177
|
+
if line.startswith("data: "):
|
178
|
+
try:
|
179
|
+
data = json.loads(line[6:])
|
180
|
+
if data.get("event") == "resp":
|
181
|
+
status = data.get("file_info", {}).get("status")
|
182
|
+
if status == "parsed":
|
183
|
+
return True
|
184
|
+
elif status == "failed":
|
185
|
+
return False
|
186
|
+
except json.JSONDecodeError:
|
187
|
+
continue
|
188
|
+
|
189
|
+
except UnicodeDecodeError:
|
190
|
+
# 如果解码失败,继续累积数据
|
182
191
|
continue
|
183
192
|
|
184
193
|
retry_count += 1
|
@@ -284,34 +293,44 @@ class KimiModel(BasePlatform):
|
|
284
293
|
}
|
285
294
|
|
286
295
|
try:
|
287
|
-
|
288
|
-
|
296
|
+
# 使用新的stream_post接口发送消息请求,获取流式响应
|
297
|
+
response_stream = while_success(
|
298
|
+
lambda: http.stream_post(url, headers=headers, json=payload),
|
289
299
|
sleep_time=5,
|
290
300
|
)
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
else:
|
300
|
-
line = str(line)
|
301
|
-
|
302
|
-
if not line.startswith("data: "):
|
303
|
-
continue
|
304
|
-
|
301
|
+
|
302
|
+
response_data = b""
|
303
|
+
|
304
|
+
# 处理流式响应
|
305
|
+
for chunk in response_stream:
|
306
|
+
response_data += chunk
|
307
|
+
|
308
|
+
# 尝试解析SSE格式的数据
|
305
309
|
try:
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
310
|
+
# 查找完整的数据行
|
311
|
+
lines = response_data.decode("utf-8").split("\n")
|
312
|
+
response_data = b"" # 重置缓冲区
|
313
|
+
|
314
|
+
for line in lines:
|
315
|
+
if not line.strip():
|
316
|
+
continue
|
317
|
+
|
318
|
+
# SSE格式的行通常以"data: "开头
|
319
|
+
if line.startswith("data: "):
|
320
|
+
try:
|
321
|
+
data = json.loads(line[6:])
|
322
|
+
event = data.get("event")
|
323
|
+
|
324
|
+
if event == "cmpl":
|
325
|
+
# 处理补全文本
|
326
|
+
text = data.get("text", "")
|
327
|
+
if text:
|
328
|
+
yield text
|
329
|
+
except json.JSONDecodeError:
|
330
|
+
continue
|
331
|
+
|
332
|
+
except UnicodeDecodeError:
|
333
|
+
# 如果解码失败,继续累积数据
|
315
334
|
continue
|
316
335
|
|
317
336
|
return None
|
@@ -0,0 +1,314 @@
|
|
1
|
+
import mimetypes
|
2
|
+
import os
|
3
|
+
from typing import Dict, Generator, List, Tuple
|
4
|
+
from jarvis.jarvis_platform.base import BasePlatform
|
5
|
+
import requests
|
6
|
+
import json
|
7
|
+
|
8
|
+
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
9
|
+
|
10
|
+
class OyiModel(BasePlatform):
|
11
|
+
"""Oyi model implementation"""
|
12
|
+
|
13
|
+
platform_name = "oyi"
|
14
|
+
BASE_URL = "https://api-10086.rcouyi.com"
|
15
|
+
|
16
|
+
def get_model_list(self) -> List[Tuple[str, str]]:
|
17
|
+
"""Get model list"""
|
18
|
+
self.get_available_models()
|
19
|
+
return [(name,info['desc']) for name,info in self.models.items()]
|
20
|
+
|
21
|
+
def __init__(self):
|
22
|
+
"""Initialize model"""
|
23
|
+
super().__init__()
|
24
|
+
self.models = {}
|
25
|
+
self.messages = []
|
26
|
+
self.system_prompt = ""
|
27
|
+
self.conversation = None
|
28
|
+
self.first_chat = True
|
29
|
+
|
30
|
+
self.token = os.getenv("OYI_API_KEY")
|
31
|
+
if not self.token:
|
32
|
+
PrettyOutput.print("OYI_API_KEY 未设置", OutputType.WARNING)
|
33
|
+
|
34
|
+
self.model_name = os.getenv("JARVIS_MODEL") or "deepseek-chat"
|
35
|
+
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
|
+
|
39
|
+
def set_model_name(self, model_name: str):
|
40
|
+
"""Set model name"""
|
41
|
+
|
42
|
+
self.model_name = model_name
|
43
|
+
|
44
|
+
|
45
|
+
def create_conversation(self) -> bool:
|
46
|
+
"""Create a new conversation"""
|
47
|
+
try:
|
48
|
+
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'
|
53
|
+
}
|
54
|
+
|
55
|
+
payload = {
|
56
|
+
"id": 0,
|
57
|
+
"roleId": 0,
|
58
|
+
"title": "New conversation",
|
59
|
+
"isLock": False,
|
60
|
+
"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
|
+
})
|
72
|
+
}
|
73
|
+
|
74
|
+
response = requests.post(
|
75
|
+
f"{self.BASE_URL}/chatapi/chat/save",
|
76
|
+
headers=headers,
|
77
|
+
json=payload
|
78
|
+
)
|
79
|
+
|
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
|
88
|
+
else:
|
89
|
+
PrettyOutput.print(f"创建会话失败: {response.status_code}", OutputType.WARNING)
|
90
|
+
return False
|
91
|
+
|
92
|
+
except Exception as e:
|
93
|
+
PrettyOutput.print(f"创建会话失败: {str(e)}", OutputType.ERROR)
|
94
|
+
return False
|
95
|
+
|
96
|
+
def set_system_prompt(self, message: str):
|
97
|
+
"""Set system message"""
|
98
|
+
self.system_prompt = message
|
99
|
+
|
100
|
+
def chat(self, message: str) -> Generator[str, None, None]:
|
101
|
+
"""Execute chat with the model
|
102
|
+
|
103
|
+
Args:
|
104
|
+
message: User input message
|
105
|
+
|
106
|
+
Returns:
|
107
|
+
str: Model response
|
108
|
+
"""
|
109
|
+
try:
|
110
|
+
# 确保有会话ID
|
111
|
+
if not self.conversation:
|
112
|
+
if not self.create_conversation():
|
113
|
+
raise Exception("Failed to create conversation")
|
114
|
+
|
115
|
+
# 1. 发送消息
|
116
|
+
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/'
|
123
|
+
}
|
124
|
+
|
125
|
+
payload = {
|
126
|
+
"topicId": self.conversation['result']['id'] if self.conversation else None,
|
127
|
+
"messages": self.messages,
|
128
|
+
"content": message,
|
129
|
+
"contentFiles": []
|
130
|
+
}
|
131
|
+
|
132
|
+
# 如果有上传的文件,添加到请求中
|
133
|
+
if self.first_chat:
|
134
|
+
message = self.system_prompt + "\n" + message
|
135
|
+
payload["content"] = message
|
136
|
+
self.first_chat = False
|
137
|
+
|
138
|
+
self.messages.append({"role": "user", "content": message})
|
139
|
+
|
140
|
+
# 发送消息
|
141
|
+
response = requests.post(
|
142
|
+
f"{self.BASE_URL}/chatapi/chat/message",
|
143
|
+
headers=headers,
|
144
|
+
json=payload
|
145
|
+
)
|
146
|
+
|
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
|
+
data = response.json()
|
153
|
+
if data['code'] != 200 or data['type'] != 'success':
|
154
|
+
error_msg = f"聊天失败: {data.get('message', '未知错误')}"
|
155
|
+
PrettyOutput.print(error_msg, OutputType.WARNING)
|
156
|
+
raise Exception(error_msg)
|
157
|
+
|
158
|
+
message_id = data['result'][-1]
|
159
|
+
|
160
|
+
# 获取响应内容
|
161
|
+
response = requests.post(
|
162
|
+
f"{self.BASE_URL}/chatapi/chat/message/{message_id}",
|
163
|
+
headers=headers,
|
164
|
+
stream=True
|
165
|
+
)
|
166
|
+
|
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)
|
187
|
+
except Exception as e:
|
188
|
+
PrettyOutput.print(f"聊天失败: {str(e)}", OutputType.ERROR)
|
189
|
+
raise e
|
190
|
+
|
191
|
+
def name(self) -> str:
|
192
|
+
"""Return model name"""
|
193
|
+
return self.model_name
|
194
|
+
|
195
|
+
|
196
|
+
def delete_chat(self) -> bool:
|
197
|
+
"""Delete current chat session"""
|
198
|
+
try:
|
199
|
+
if not self.conversation:
|
200
|
+
return True
|
201
|
+
|
202
|
+
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/'
|
209
|
+
}
|
210
|
+
|
211
|
+
response = requests.post(
|
212
|
+
f"{self.BASE_URL}/chatapi/chat/{self.conversation['result']['id']}",
|
213
|
+
headers=headers,
|
214
|
+
json={}
|
215
|
+
)
|
216
|
+
|
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
|
228
|
+
else:
|
229
|
+
error_msg = f"删除会话请求失败: {response.status_code}"
|
230
|
+
PrettyOutput.print(error_msg, OutputType.WARNING)
|
231
|
+
return False
|
232
|
+
|
233
|
+
|
234
|
+
except Exception as e:
|
235
|
+
PrettyOutput.print(f"删除会话失败: {str(e)}", OutputType.ERROR)
|
236
|
+
return False
|
237
|
+
|
238
|
+
def get_available_models(self) -> List[str]:
|
239
|
+
"""Get available model list
|
240
|
+
|
241
|
+
Returns:
|
242
|
+
List[str]: Available model name list
|
243
|
+
"""
|
244
|
+
try:
|
245
|
+
if self.models:
|
246
|
+
return list(self.models.keys())
|
247
|
+
|
248
|
+
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/'
|
254
|
+
}
|
255
|
+
|
256
|
+
response = requests.get(
|
257
|
+
"https://ai.rcouyi.com/config/system.json",
|
258
|
+
headers=headers
|
259
|
+
)
|
260
|
+
|
261
|
+
if response.status_code != 200:
|
262
|
+
PrettyOutput.print(f"获取模型列表失败: {response.status_code}", OutputType.WARNING)
|
263
|
+
return []
|
264
|
+
|
265
|
+
data = response.json()
|
266
|
+
|
267
|
+
# 保存模型信息
|
268
|
+
self.models = {
|
269
|
+
model['value']: model
|
270
|
+
for model in data.get('model', [])
|
271
|
+
if model.get('enable', False) # 只保存启用的模型
|
272
|
+
}
|
273
|
+
|
274
|
+
# 格式化显示
|
275
|
+
models = []
|
276
|
+
for model in self.models.values():
|
277
|
+
# 基本信息
|
278
|
+
model_name = model['value']
|
279
|
+
model_str = model['label']
|
280
|
+
|
281
|
+
# 添加后缀标签
|
282
|
+
suffix = model.get('suffix', [])
|
283
|
+
if suffix:
|
284
|
+
# 处理新格式的suffix (字典列表)
|
285
|
+
if suffix and isinstance(suffix[0], dict):
|
286
|
+
suffix_str = ', '.join(s.get('tag', '') for s in suffix)
|
287
|
+
# 处理旧格式的suffix (字符串列表)
|
288
|
+
else:
|
289
|
+
suffix_str = ', '.join(str(s) for s in suffix)
|
290
|
+
model_str += f" ({suffix_str})"
|
291
|
+
|
292
|
+
# 添加描述或提示
|
293
|
+
info = model.get('tooltip') or model.get('description', '')
|
294
|
+
if info:
|
295
|
+
model_str += f" - {info}"
|
296
|
+
|
297
|
+
model['desc'] = model_str
|
298
|
+
models.append(model_name)
|
299
|
+
|
300
|
+
return sorted(models)
|
301
|
+
|
302
|
+
except Exception as e:
|
303
|
+
PrettyOutput.print(f"获取模型列表失败: {str(e)}", OutputType.WARNING)
|
304
|
+
return []
|
305
|
+
|
306
|
+
def support_upload_files(self) -> bool:
|
307
|
+
return False
|
308
|
+
|
309
|
+
|
310
|
+
def support_web(self) -> bool:
|
311
|
+
return False
|
312
|
+
|
313
|
+
def upload_files(self, file_list: List[str]) -> bool:
|
314
|
+
return False
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
-
"""Jarvis
|
2
|
+
"""Jarvis平台管理器主模块。
|
3
3
|
|
4
|
-
|
4
|
+
该模块提供了Jarvis平台管理器的主要入口点。
|
5
5
|
"""
|
6
6
|
import argparse
|
7
7
|
import os
|
@@ -15,7 +15,7 @@ from jarvis.jarvis_platform_manager.service import start_service
|
|
15
15
|
|
16
16
|
|
17
17
|
def list_platforms() -> None:
|
18
|
-
"""
|
18
|
+
"""列出所有支持的平台和模型。"""
|
19
19
|
registry = PlatformRegistry.get_global_platform_registry()
|
20
20
|
platforms = registry.get_available_platforms()
|
21
21
|
|
@@ -53,7 +53,7 @@ def list_platforms() -> None:
|
|
53
53
|
|
54
54
|
|
55
55
|
def chat_with_model(platform_name: str, model_name: str, system_prompt: str) -> None:
|
56
|
-
"""
|
56
|
+
"""与指定平台和模型进行对话。"""
|
57
57
|
registry = PlatformRegistry.get_global_platform_registry()
|
58
58
|
conversation_history: List[Dict[str, str]] = [] # 存储对话记录
|
59
59
|
|
@@ -190,9 +190,13 @@ def chat_with_model(platform_name: str, model_name: str, system_prompt: str) ->
|
|
190
190
|
for entry in conversation_history:
|
191
191
|
file_obj.write(f"{entry['role']}: {entry['content']}\n\n")
|
192
192
|
|
193
|
-
PrettyOutput.print(
|
193
|
+
PrettyOutput.print(
|
194
|
+
f"所有对话已保存到 {file_path}", OutputType.SUCCESS
|
195
|
+
)
|
194
196
|
except Exception as exc:
|
195
|
-
PrettyOutput.print(
|
197
|
+
PrettyOutput.print(
|
198
|
+
f"保存所有对话失败: {str(exc)}", OutputType.ERROR
|
199
|
+
)
|
196
200
|
continue
|
197
201
|
|
198
202
|
# Check if it is a shell command
|
@@ -242,13 +246,13 @@ def chat_with_model(platform_name: str, model_name: str, system_prompt: str) ->
|
|
242
246
|
|
243
247
|
|
244
248
|
def validate_platform_model(args: argparse.Namespace) -> bool:
|
245
|
-
"""
|
249
|
+
"""验证平台和模型参数。
|
246
250
|
|
247
|
-
|
248
|
-
args:
|
251
|
+
参数:
|
252
|
+
args: 命令行参数。
|
249
253
|
|
250
|
-
|
251
|
-
bool: True
|
254
|
+
返回:
|
255
|
+
bool: 如果平台和模型有效返回True,否则返回False。
|
252
256
|
"""
|
253
257
|
if not args.platform or not args.model:
|
254
258
|
PrettyOutput.print(
|
@@ -260,10 +264,10 @@ def validate_platform_model(args: argparse.Namespace) -> bool:
|
|
260
264
|
|
261
265
|
|
262
266
|
def chat_command(args: argparse.Namespace) -> None:
|
263
|
-
"""
|
267
|
+
"""处理聊天子命令。
|
264
268
|
|
265
|
-
|
266
|
-
args:
|
269
|
+
参数:
|
270
|
+
args: 命令行参数。
|
267
271
|
"""
|
268
272
|
if not validate_platform_model(args):
|
269
273
|
return
|
@@ -271,19 +275,19 @@ def chat_command(args: argparse.Namespace) -> None:
|
|
271
275
|
|
272
276
|
|
273
277
|
def info_command(args: argparse.Namespace) -> None:
|
274
|
-
"""
|
278
|
+
"""处理信息子命令。
|
275
279
|
|
276
|
-
|
277
|
-
args:
|
280
|
+
参数:
|
281
|
+
args: 命令行参数。
|
278
282
|
"""
|
279
283
|
list_platforms()
|
280
284
|
|
281
285
|
|
282
286
|
def service_command(args: argparse.Namespace) -> None:
|
283
|
-
"""
|
287
|
+
"""处理服务子命令 - 启动OpenAI兼容的API服务。
|
284
288
|
|
285
|
-
|
286
|
-
args:
|
289
|
+
参数:
|
290
|
+
args: 命令行参数。
|
287
291
|
"""
|
288
292
|
start_service(
|
289
293
|
host=args.host,
|
@@ -357,7 +361,7 @@ def role_command(args: argparse.Namespace) -> None:
|
|
357
361
|
|
358
362
|
|
359
363
|
def main() -> None:
|
360
|
-
"""
|
364
|
+
"""Jarvis平台管理器的主入口点。"""
|
361
365
|
init_env("欢迎使用 Jarvis-PlatformManager,您的平台管理助手已准备就绪!")
|
362
366
|
|
363
367
|
parser = argparse.ArgumentParser(description="Jarvis AI 平台")
|
@@ -381,8 +385,12 @@ def main() -> None:
|
|
381
385
|
service_parser.add_argument(
|
382
386
|
"--port", type=int, default=8000, help="服务端口 (默认: 8000)"
|
383
387
|
)
|
384
|
-
service_parser.add_argument(
|
385
|
-
|
388
|
+
service_parser.add_argument(
|
389
|
+
"--platform", "-p", help="指定默认平台,当客户端未指定平台时使用"
|
390
|
+
)
|
391
|
+
service_parser.add_argument(
|
392
|
+
"--model", "-m", help="指定默认模型,当客户端未指定平台时使用"
|
393
|
+
)
|
386
394
|
service_parser.set_defaults(func=service_command)
|
387
395
|
|
388
396
|
# role subcommand
|
jarvis/jarvis_utils/globals.py
CHANGED
@@ -8,6 +8,9 @@
|
|
8
8
|
- 环境初始化
|
9
9
|
"""
|
10
10
|
import os
|
11
|
+
|
12
|
+
# 全局变量:保存最后一条消息
|
13
|
+
last_message: str = ""
|
11
14
|
from typing import Any, Set
|
12
15
|
|
13
16
|
import colorama
|
@@ -149,3 +152,31 @@ def get_interrupt() -> int:
|
|
149
152
|
int: 当前中断计数
|
150
153
|
"""
|
151
154
|
return g_interrupt
|
155
|
+
|
156
|
+
|
157
|
+
def set_last_message(message: str) -> None:
|
158
|
+
"""
|
159
|
+
设置最后一条消息。
|
160
|
+
|
161
|
+
参数:
|
162
|
+
message: 要保存的消息
|
163
|
+
"""
|
164
|
+
global last_message
|
165
|
+
last_message = message
|
166
|
+
|
167
|
+
|
168
|
+
def get_last_message() -> str:
|
169
|
+
"""
|
170
|
+
获取最后一条消息。
|
171
|
+
|
172
|
+
返回:
|
173
|
+
str: 最后一条消息
|
174
|
+
"""
|
175
|
+
return last_message
|
176
|
+
"""
|
177
|
+
获取当前中断信号状态。
|
178
|
+
|
179
|
+
返回:
|
180
|
+
int: 当前中断计数
|
181
|
+
"""
|
182
|
+
return g_interrupt
|
jarvis/jarvis_utils/input.py
CHANGED
@@ -8,16 +8,20 @@
|
|
8
8
|
- 带有模糊匹配的文件路径补全
|
9
9
|
- 用于输入控制的自定义键绑定
|
10
10
|
"""
|
11
|
-
from colorama import Fore
|
12
|
-
from colorama import Style as ColoramaStyle
|
13
|
-
from fuzzywuzzy import process
|
14
|
-
from prompt_toolkit import PromptSession
|
15
|
-
from prompt_toolkit.completion import (
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
11
|
+
from colorama import Fore # type: ignore
|
12
|
+
from colorama import Style as ColoramaStyle # type: ignore
|
13
|
+
from fuzzywuzzy import process # type: ignore
|
14
|
+
from prompt_toolkit import PromptSession # type: ignore
|
15
|
+
from prompt_toolkit.completion import (
|
16
|
+
CompleteEvent,
|
17
|
+
Completer,
|
18
|
+
Completion, # type: ignore
|
19
|
+
PathCompleter,
|
20
|
+
) # type: ignore
|
21
|
+
from prompt_toolkit.document import Document # type: ignore
|
22
|
+
from prompt_toolkit.formatted_text import FormattedText # type: ignore
|
23
|
+
from prompt_toolkit.key_binding import KeyBindings # type: ignore
|
24
|
+
from prompt_toolkit.styles import Style as PromptStyle # type: ignore
|
21
25
|
|
22
26
|
from jarvis.jarvis_utils.config import get_replace_map
|
23
27
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
@@ -186,7 +190,7 @@ def get_multiline_input(tip: str) -> str:
|
|
186
190
|
"""
|
187
191
|
# 显示输入说明
|
188
192
|
PrettyOutput.section(
|
189
|
-
"用户输入 - 使用 @ 触发文件补全,Tab 选择补全项,Ctrl+J
|
193
|
+
"用户输入 - 使用 @ 触发文件补全,Tab 选择补全项,Ctrl+J 提交,Ctrl+L 复制最后一条消息,按 Ctrl+C 取消输入",
|
190
194
|
OutputType.USER,
|
191
195
|
)
|
192
196
|
print(f"{Fore.GREEN}{tip}{ColoramaStyle.RESET_ALL}")
|
@@ -208,6 +212,24 @@ def get_multiline_input(tip: str) -> str:
|
|
208
212
|
"""处理Ctrl+J以提交输入。"""
|
209
213
|
event.current_buffer.validate_and_handle()
|
210
214
|
|
215
|
+
@bindings.add("c-l")
|
216
|
+
def _(event):
|
217
|
+
"""处理Ctrl+L以复制最后一条消息到剪贴板。"""
|
218
|
+
from jarvis.jarvis_utils.globals import get_last_message
|
219
|
+
import subprocess
|
220
|
+
|
221
|
+
last_msg = get_last_message()
|
222
|
+
if last_msg:
|
223
|
+
try:
|
224
|
+
# 使用xsel将内容复制到剪贴板
|
225
|
+
process = subprocess.Popen(["xsel", "-b", "-i"], stdin=subprocess.PIPE)
|
226
|
+
process.communicate(input=last_msg.encode("utf-8"))
|
227
|
+
PrettyOutput.print("已将最后一条消息复制到剪贴板", OutputType.INFO)
|
228
|
+
except Exception as e:
|
229
|
+
PrettyOutput.print(f"复制到剪贴板失败: {e}", OutputType.ERROR)
|
230
|
+
else:
|
231
|
+
PrettyOutput.print("没有可复制的消息", OutputType.INFO)
|
232
|
+
|
211
233
|
# 配置提示会话
|
212
234
|
style = PromptStyle.from_dict(
|
213
235
|
{
|
@@ -217,7 +239,7 @@ def get_multiline_input(tip: str) -> str:
|
|
217
239
|
try:
|
218
240
|
import os
|
219
241
|
|
220
|
-
from prompt_toolkit.history import FileHistory
|
242
|
+
from prompt_toolkit.history import FileHistory # type: ignore
|
221
243
|
|
222
244
|
from jarvis.jarvis_utils.config import get_data_dir
|
223
245
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
jarvis/__init__.py,sha256=
|
1
|
+
jarvis/__init__.py,sha256=kz-6zpmo_NPSLXBTjHQyhEg8Z5G5ayw0RFZS5KubWws,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,15 +45,17 @@ 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/
|
48
|
+
jarvis/jarvis_platform/ai8.py,sha256=3LA4vSsaP-p9zXmj7o0jzL1WI8UMv4-P0YNz9s9r-6U,9115
|
49
|
+
jarvis/jarvis_platform/base.py,sha256=CBFk1Kq7qzOwafOj22bacXChWvCnap3D4IacZCWC_Ss,7882
|
49
50
|
jarvis/jarvis_platform/human.py,sha256=_WQtC5w6QJnHh-3KuW8T49C-HucXiHsBEVw-m51ykj4,3196
|
50
|
-
jarvis/jarvis_platform/kimi.py,sha256=
|
51
|
+
jarvis/jarvis_platform/kimi.py,sha256=w0-OJ6xkOGPApcc2Jvc30BMjabwrnzcndmsJJsWOWJg,13419
|
51
52
|
jarvis/jarvis_platform/openai.py,sha256=uEjBikfFj7kp5wondLvOx4WdkmTX0aqF6kixxAufcHg,4806
|
53
|
+
jarvis/jarvis_platform/oyi.py,sha256=6SBAO-lhk6yoZvrglGF8rHIDA7SbcvjRy8sYYJ7ou0w,11241
|
52
54
|
jarvis/jarvis_platform/registry.py,sha256=Sz4ADAaxuufpAQG0KSQZuL1yALzH-aF3FDapkNn5foE,8107
|
53
55
|
jarvis/jarvis_platform/tongyi.py,sha256=juvzMjZ2mbNzSWzem8snmFuE28YVOjjE_YdHCZa9Qnw,20698
|
54
56
|
jarvis/jarvis_platform/yuanbao.py,sha256=ZsKXWifESXGfvB9eOot1I6TnhlmgXwnaft3e2UXgSXk,21045
|
55
57
|
jarvis/jarvis_platform_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
56
|
-
jarvis/jarvis_platform_manager/main.py,sha256=
|
58
|
+
jarvis/jarvis_platform_manager/main.py,sha256=tIb3jUuMF0ErislPjo8TkEUqL04snfEJwMPSZiOkMmY,15659
|
57
59
|
jarvis/jarvis_platform_manager/service.py,sha256=rY1FmNl-tmbkkke_3SlH9h6ckyPIgmSwbaRorURp9Cc,14916
|
58
60
|
jarvis/jarvis_smart_shell/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
59
61
|
jarvis/jarvis_smart_shell/main.py,sha256=DbhRSP1sZfSIaTltP1YWVDSQOTYEsbiOnfO9kSYwcNs,6959
|
@@ -79,16 +81,16 @@ jarvis/jarvis_utils/config.py,sha256=MO2-1z_7f3KkSrv7heGK1650Zb0SjnljO2hzLE2jA5c
|
|
79
81
|
jarvis/jarvis_utils/embedding.py,sha256=oEOEM2qf16DMYwPsQe6srET9BknyjOdY2ef0jsp3Or8,2714
|
80
82
|
jarvis/jarvis_utils/file_processors.py,sha256=XiM248SHS7lLgQDCbORVFWqinbVDUawYxWDOsLXDxP8,3043
|
81
83
|
jarvis/jarvis_utils/git_utils.py,sha256=7AZblSD4b76vXxaDFkmZOy5rNkwvkwQQxGUy3NAusDQ,21641
|
82
|
-
jarvis/jarvis_utils/globals.py,sha256=
|
84
|
+
jarvis/jarvis_utils/globals.py,sha256=WzZh_acNfHJj1LDulhyLQ7cojksBy0gdrITe0vH1XA0,3901
|
83
85
|
jarvis/jarvis_utils/http.py,sha256=Uqt1kcz0HWnAfXHHi1fNGwLb2lcVUqpbrG2Uk_-kcIU,4882
|
84
|
-
jarvis/jarvis_utils/input.py,sha256=
|
86
|
+
jarvis/jarvis_utils/input.py,sha256=Vd6Ksh9PYM8X0OvK2x22UoG0y3ejlssk-JIAv5X_kRM,8877
|
85
87
|
jarvis/jarvis_utils/methodology.py,sha256=-cvM6pwgJK7BXCYg2uVjIId_j3v5RUh2z2PBcK_2vj4,8155
|
86
88
|
jarvis/jarvis_utils/output.py,sha256=PRCgudPOB8gMEP3u-g0FGD2c6tBgJhLXUMqNPglfjV8,10813
|
87
89
|
jarvis/jarvis_utils/tag.py,sha256=f211opbbbTcSyzCDwuIK_oCnKhXPNK-RknYyGzY1yD0,431
|
88
90
|
jarvis/jarvis_utils/utils.py,sha256=BoRwLcixdf7mU3Tawe95ygGhQpkMffrFYLYhPwIvw8A,14498
|
89
|
-
jarvis_ai_assistant-0.1.
|
90
|
-
jarvis_ai_assistant-0.1.
|
91
|
-
jarvis_ai_assistant-0.1.
|
92
|
-
jarvis_ai_assistant-0.1.
|
93
|
-
jarvis_ai_assistant-0.1.
|
94
|
-
jarvis_ai_assistant-0.1.
|
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,,
|
File without changes
|
{jarvis_ai_assistant-0.1.211.dist-info → jarvis_ai_assistant-0.1.212.dist-info}/entry_points.txt
RENAMED
File without changes
|
{jarvis_ai_assistant-0.1.211.dist-info → jarvis_ai_assistant-0.1.212.dist-info}/licenses/LICENSE
RENAMED
File without changes
|
{jarvis_ai_assistant-0.1.211.dist-info → jarvis_ai_assistant-0.1.212.dist-info}/top_level.txt
RENAMED
File without changes
|