jarvis-ai-assistant 0.2.1__py3-none-any.whl → 0.2.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/jarvis.py +61 -59
- jarvis/jarvis_agent/main.py +42 -40
- jarvis/jarvis_agent/prompts.py +26 -4
- jarvis/jarvis_code_agent/code_agent.py +35 -31
- jarvis/jarvis_code_analysis/code_review.py +73 -39
- jarvis/jarvis_data/config_schema.json +67 -12
- jarvis/jarvis_git_squash/main.py +16 -12
- jarvis/jarvis_git_utils/git_commiter.py +25 -20
- jarvis/jarvis_methodology/main.py +34 -49
- jarvis/jarvis_multi_agent/main.py +28 -23
- jarvis/jarvis_platform/ai8.py +31 -22
- jarvis/jarvis_platform/kimi.py +31 -61
- jarvis/jarvis_platform/tongyi.py +71 -85
- jarvis/jarvis_platform/yuanbao.py +44 -50
- jarvis/jarvis_platform_manager/main.py +55 -90
- jarvis/jarvis_rag/cli.py +79 -23
- jarvis/jarvis_rag/query_rewriter.py +61 -12
- jarvis/jarvis_rag/rag_pipeline.py +143 -34
- jarvis/jarvis_rag/retriever.py +5 -5
- jarvis/jarvis_smart_shell/main.py +58 -87
- jarvis/jarvis_tools/cli/main.py +120 -153
- jarvis/jarvis_tools/generate_new_tool.py +22 -1
- jarvis/jarvis_tools/registry.py +1 -7
- jarvis/jarvis_tools/search_web.py +12 -10
- jarvis/jarvis_utils/config.py +92 -11
- jarvis/jarvis_utils/globals.py +29 -8
- jarvis/jarvis_utils/http.py +58 -79
- jarvis/jarvis_utils/input.py +114 -121
- jarvis/jarvis_utils/output.py +1 -1
- jarvis/jarvis_utils/utils.py +3 -0
- jarvis_ai_assistant-0.2.3.dist-info/METADATA +301 -0
- {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.3.dist-info}/RECORD +37 -40
- {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.3.dist-info}/entry_points.txt +0 -2
- jarvis/jarvis_git_details/__init__.py +0 -0
- jarvis/jarvis_git_details/main.py +0 -265
- jarvis/jarvis_platform/oyi.py +0 -357
- jarvis_ai_assistant-0.2.1.dist-info/METADATA +0 -845
- {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.3.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.3.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.3.dist-info}/top_level.txt +0 -0
jarvis/jarvis_platform/oyi.py
DELETED
@@ -1,357 +0,0 @@
|
|
1
|
-
import mimetypes
|
2
|
-
import os
|
3
|
-
from typing import Dict, Generator, List, Tuple
|
4
|
-
from jarvis.jarvis_platform.base import BasePlatform
|
5
|
-
import json
|
6
|
-
|
7
|
-
from jarvis.jarvis_utils import http
|
8
|
-
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
9
|
-
from jarvis.jarvis_utils.utils import while_success
|
10
|
-
|
11
|
-
|
12
|
-
class OyiModel(BasePlatform):
|
13
|
-
"""Oyi model implementation"""
|
14
|
-
|
15
|
-
BASE_URL = "https://api-10086.rcouyi.com"
|
16
|
-
|
17
|
-
def get_model_list(self) -> List[Tuple[str, str]]:
|
18
|
-
"""Get model list"""
|
19
|
-
self.get_available_models()
|
20
|
-
return [(name, info["desc"]) for name, info in self.models.items()]
|
21
|
-
|
22
|
-
def __init__(self):
|
23
|
-
"""Initialize model"""
|
24
|
-
super().__init__()
|
25
|
-
self.models = {}
|
26
|
-
self.messages = []
|
27
|
-
self.system_prompt = ""
|
28
|
-
self.conversation = None
|
29
|
-
self.first_chat = True
|
30
|
-
|
31
|
-
self.token = os.getenv("OYI_API_KEY")
|
32
|
-
if not self.token:
|
33
|
-
PrettyOutput.print("OYI_API_KEY 未设置", OutputType.WARNING)
|
34
|
-
|
35
|
-
self.model_name = os.getenv("JARVIS_MODEL") or "deepseek-chat"
|
36
|
-
if self.model_name not in [m.split()[0] for m in self.get_available_models()]:
|
37
|
-
PrettyOutput.print(
|
38
|
-
f"警告: 选择的模型 {self.model_name} 不在可用列表中", OutputType.WARNING
|
39
|
-
)
|
40
|
-
|
41
|
-
def set_model_name(self, model_name: str):
|
42
|
-
"""Set model name"""
|
43
|
-
|
44
|
-
self.model_name = model_name
|
45
|
-
|
46
|
-
def create_conversation(self) -> bool:
|
47
|
-
"""Create a new conversation"""
|
48
|
-
try:
|
49
|
-
headers = {
|
50
|
-
"Authorization": f"Bearer {self.token}",
|
51
|
-
"Content-Type": "application/json",
|
52
|
-
"Accept": "application/json",
|
53
|
-
"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",
|
54
|
-
}
|
55
|
-
|
56
|
-
payload = {
|
57
|
-
"id": 0,
|
58
|
-
"roleId": 0,
|
59
|
-
"title": "New conversation",
|
60
|
-
"isLock": False,
|
61
|
-
"systemMessage": "",
|
62
|
-
"params": json.dumps(
|
63
|
-
{
|
64
|
-
"model": self.model_name,
|
65
|
-
"is_webSearch": True,
|
66
|
-
"message": [],
|
67
|
-
"systemMessage": None,
|
68
|
-
"requestMsgCount": 65536,
|
69
|
-
"temperature": 0.8,
|
70
|
-
"speechVoice": "Alloy",
|
71
|
-
"max_tokens": 8192,
|
72
|
-
"chatPluginIds": [],
|
73
|
-
}
|
74
|
-
),
|
75
|
-
}
|
76
|
-
|
77
|
-
response = while_success(
|
78
|
-
lambda: http.post(
|
79
|
-
f"{self.BASE_URL}/chatapi/chat/save", headers=headers, json=payload
|
80
|
-
),
|
81
|
-
sleep_time=5,
|
82
|
-
)
|
83
|
-
|
84
|
-
data = response.json()
|
85
|
-
if data["code"] == 200 and data["type"] == "success":
|
86
|
-
self.conversation = data
|
87
|
-
return True
|
88
|
-
else:
|
89
|
-
PrettyOutput.print(
|
90
|
-
f"创建会话失败: {data['message']}", OutputType.WARNING
|
91
|
-
)
|
92
|
-
return False
|
93
|
-
|
94
|
-
except Exception as e:
|
95
|
-
PrettyOutput.print(f"创建会话失败: {str(e)}", OutputType.ERROR)
|
96
|
-
return False
|
97
|
-
|
98
|
-
def set_system_prompt(self, message: str):
|
99
|
-
"""Set system message"""
|
100
|
-
self.system_prompt = message
|
101
|
-
|
102
|
-
def chat(self, message: str) -> Generator[str, None, None]:
|
103
|
-
"""Execute chat with the model
|
104
|
-
|
105
|
-
Args:
|
106
|
-
message: User input message
|
107
|
-
|
108
|
-
Returns:
|
109
|
-
str: Model response
|
110
|
-
"""
|
111
|
-
try:
|
112
|
-
# 确保有会话ID
|
113
|
-
if not self.conversation:
|
114
|
-
if not self.create_conversation():
|
115
|
-
raise Exception("Failed to create conversation")
|
116
|
-
|
117
|
-
# 1. 发送消息
|
118
|
-
headers = {
|
119
|
-
"Authorization": f"Bearer {self.token}",
|
120
|
-
"Content-Type": "application/json",
|
121
|
-
"Accept": "application/json, text/plain, */*",
|
122
|
-
"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",
|
123
|
-
"Origin": "https://ai.rcouyi.com",
|
124
|
-
"Referer": "https://ai.rcouyi.com/",
|
125
|
-
}
|
126
|
-
|
127
|
-
payload = {
|
128
|
-
"topicId": (
|
129
|
-
self.conversation["result"]["id"] if self.conversation else None
|
130
|
-
),
|
131
|
-
"messages": self.messages,
|
132
|
-
"content": message,
|
133
|
-
"contentFiles": [],
|
134
|
-
}
|
135
|
-
|
136
|
-
# 如果有上传的文件,添加到请求中
|
137
|
-
if self.first_chat:
|
138
|
-
message = self.system_prompt + "\n" + message
|
139
|
-
payload["content"] = message
|
140
|
-
self.first_chat = False
|
141
|
-
|
142
|
-
self.messages.append({"role": "user", "content": message})
|
143
|
-
|
144
|
-
# 发送消息
|
145
|
-
response = while_success(
|
146
|
-
lambda: http.post(
|
147
|
-
f"{self.BASE_URL}/chatapi/chat/message",
|
148
|
-
headers=headers,
|
149
|
-
json=payload,
|
150
|
-
),
|
151
|
-
sleep_time=5,
|
152
|
-
)
|
153
|
-
|
154
|
-
data = response.json()
|
155
|
-
if data["code"] != 200 or data["type"] != "success":
|
156
|
-
error_msg = f"聊天失败: {data.get('message', '未知错误')}"
|
157
|
-
PrettyOutput.print(error_msg, OutputType.WARNING)
|
158
|
-
raise Exception(error_msg)
|
159
|
-
|
160
|
-
message_id = data["result"][-1]
|
161
|
-
|
162
|
-
# 获取响应内容
|
163
|
-
response = while_success(
|
164
|
-
lambda: http.stream_post(
|
165
|
-
f"{self.BASE_URL}/chatapi/chat/message/{message_id}",
|
166
|
-
headers=headers,
|
167
|
-
),
|
168
|
-
sleep_time=5,
|
169
|
-
)
|
170
|
-
|
171
|
-
full_response = ""
|
172
|
-
bin = b""
|
173
|
-
for chunk in response:
|
174
|
-
if chunk:
|
175
|
-
bin += chunk
|
176
|
-
try:
|
177
|
-
text = bin.decode("utf-8")
|
178
|
-
except UnicodeDecodeError:
|
179
|
-
continue
|
180
|
-
full_response += text
|
181
|
-
bin = b""
|
182
|
-
yield text
|
183
|
-
|
184
|
-
self.messages.append({"role": "assistant", "content": full_response})
|
185
|
-
return None
|
186
|
-
except Exception as e:
|
187
|
-
PrettyOutput.print(f"聊天失败: {str(e)}", OutputType.ERROR)
|
188
|
-
raise e
|
189
|
-
|
190
|
-
def name(self) -> str:
|
191
|
-
"""Return model name"""
|
192
|
-
return self.model_name
|
193
|
-
|
194
|
-
@classmethod
|
195
|
-
def platform_name(cls) -> str:
|
196
|
-
"""Return platform name"""
|
197
|
-
return "oyi"
|
198
|
-
|
199
|
-
def delete_chat(self) -> bool:
|
200
|
-
"""Delete current chat session"""
|
201
|
-
try:
|
202
|
-
if not self.conversation:
|
203
|
-
return True
|
204
|
-
|
205
|
-
headers = {
|
206
|
-
"Authorization": f"Bearer {self.token}",
|
207
|
-
"Content-Type": "application/json",
|
208
|
-
"Accept": "application/json, text/plain, */*",
|
209
|
-
"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",
|
210
|
-
"Origin": "https://ai.rcouyi.com",
|
211
|
-
"Referer": "https://ai.rcouyi.com/",
|
212
|
-
}
|
213
|
-
|
214
|
-
response = while_success(
|
215
|
-
lambda: http.post(
|
216
|
-
f"{self.BASE_URL}/chatapi/chat/{self.conversation['result']['id']}", # type: ignore
|
217
|
-
headers=headers,
|
218
|
-
json={},
|
219
|
-
),
|
220
|
-
sleep_time=5,
|
221
|
-
)
|
222
|
-
|
223
|
-
data = response.json()
|
224
|
-
if data["code"] == 200 and data["type"] == "success":
|
225
|
-
self.messages = []
|
226
|
-
self.conversation = None
|
227
|
-
self.first_chat = True
|
228
|
-
return True
|
229
|
-
else:
|
230
|
-
error_msg = f"删除会话失败: {data.get('message', '未知错误')}"
|
231
|
-
PrettyOutput.print(error_msg, OutputType.WARNING)
|
232
|
-
return False
|
233
|
-
|
234
|
-
except Exception as e:
|
235
|
-
PrettyOutput.print(f"删除会话失败: {str(e)}", OutputType.ERROR)
|
236
|
-
return False
|
237
|
-
|
238
|
-
def save(self, file_path: str) -> bool:
|
239
|
-
"""Save chat session to a file."""
|
240
|
-
if not self.conversation:
|
241
|
-
PrettyOutput.print("没有活动的会话可供保存", OutputType.WARNING)
|
242
|
-
return False
|
243
|
-
|
244
|
-
state = {
|
245
|
-
"conversation": self.conversation,
|
246
|
-
"messages": self.messages,
|
247
|
-
"model_name": self.model_name,
|
248
|
-
"system_prompt": self.system_prompt,
|
249
|
-
"first_chat": self.first_chat,
|
250
|
-
}
|
251
|
-
|
252
|
-
try:
|
253
|
-
with open(file_path, "w", encoding="utf-8") as f:
|
254
|
-
json.dump(state, f, ensure_ascii=False, indent=4)
|
255
|
-
self._saved = True
|
256
|
-
PrettyOutput.print(f"会话已成功保存到 {file_path}", OutputType.SUCCESS)
|
257
|
-
return True
|
258
|
-
except Exception as e:
|
259
|
-
PrettyOutput.print(f"保存会话失败: {str(e)}", OutputType.ERROR)
|
260
|
-
return False
|
261
|
-
|
262
|
-
def restore(self, file_path: str) -> bool:
|
263
|
-
"""Restore chat session from a file."""
|
264
|
-
try:
|
265
|
-
with open(file_path, "r", encoding="utf-8") as f:
|
266
|
-
state = json.load(f)
|
267
|
-
|
268
|
-
self.conversation = state.get("conversation")
|
269
|
-
self.messages = state.get("messages", [])
|
270
|
-
self.model_name = state.get("model_name", "deepseek-chat")
|
271
|
-
self.system_prompt = state.get("system_prompt", "")
|
272
|
-
self.first_chat = state.get("first_chat", True)
|
273
|
-
self._saved = True
|
274
|
-
|
275
|
-
PrettyOutput.print(f"从 {file_path} 成功恢复会话", OutputType.SUCCESS)
|
276
|
-
return True
|
277
|
-
except FileNotFoundError:
|
278
|
-
PrettyOutput.print(f"会话文件未找到: {file_path}", OutputType.ERROR)
|
279
|
-
return False
|
280
|
-
except Exception as e:
|
281
|
-
PrettyOutput.print(f"恢复会话失败: {str(e)}", OutputType.ERROR)
|
282
|
-
return False
|
283
|
-
|
284
|
-
def get_available_models(self) -> List[str]:
|
285
|
-
"""Get available model list
|
286
|
-
|
287
|
-
Returns:
|
288
|
-
List[str]: Available model name list
|
289
|
-
"""
|
290
|
-
try:
|
291
|
-
if self.models:
|
292
|
-
return list(self.models.keys())
|
293
|
-
|
294
|
-
headers = {
|
295
|
-
"Content-Type": "application/json",
|
296
|
-
"Accept": "application/json, text/plain, */*",
|
297
|
-
"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",
|
298
|
-
"Origin": "https://ai.rcouyi.com",
|
299
|
-
"Referer": "https://ai.rcouyi.com/",
|
300
|
-
}
|
301
|
-
|
302
|
-
response = while_success(
|
303
|
-
lambda: http.get(
|
304
|
-
"https://ai.rcouyi.com/config/system.json", headers=headers
|
305
|
-
),
|
306
|
-
sleep_time=5,
|
307
|
-
)
|
308
|
-
|
309
|
-
data = response.json()
|
310
|
-
|
311
|
-
# 保存模型信息
|
312
|
-
self.models = {
|
313
|
-
model["value"]: model
|
314
|
-
for model in data.get("model", [])
|
315
|
-
if model.get("enable", False) # 只保存启用的模型
|
316
|
-
}
|
317
|
-
|
318
|
-
# 格式化显示
|
319
|
-
models = []
|
320
|
-
for model in self.models.values():
|
321
|
-
# 基本信息
|
322
|
-
model_name = model["value"]
|
323
|
-
model_str = model["label"]
|
324
|
-
|
325
|
-
# 添加后缀标签
|
326
|
-
suffix = model.get("suffix", [])
|
327
|
-
if suffix:
|
328
|
-
# 处理新格式的suffix (字典列表)
|
329
|
-
if suffix and isinstance(suffix[0], dict):
|
330
|
-
suffix_str = ", ".join(s.get("tag", "") for s in suffix)
|
331
|
-
# 处理旧格式的suffix (字符串列表)
|
332
|
-
else:
|
333
|
-
suffix_str = ", ".join(str(s) for s in suffix)
|
334
|
-
model_str += f" ({suffix_str})"
|
335
|
-
|
336
|
-
# 添加描述或提示
|
337
|
-
info = model.get("tooltip") or model.get("description", "")
|
338
|
-
if info:
|
339
|
-
model_str += f" - {info}"
|
340
|
-
|
341
|
-
model["desc"] = model_str
|
342
|
-
models.append(model_name)
|
343
|
-
|
344
|
-
return sorted(models)
|
345
|
-
|
346
|
-
except Exception as e:
|
347
|
-
PrettyOutput.print(f"获取模型列表失败: {str(e)}", OutputType.WARNING)
|
348
|
-
return []
|
349
|
-
|
350
|
-
def support_upload_files(self) -> bool:
|
351
|
-
return False
|
352
|
-
|
353
|
-
def support_web(self) -> bool:
|
354
|
-
return False
|
355
|
-
|
356
|
-
def upload_files(self, file_list: List[str]) -> bool:
|
357
|
-
return False
|