jarvis-ai-assistant 0.1.132__py3-none-any.whl → 0.1.138__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.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +330 -347
- jarvis/jarvis_agent/builtin_input_handler.py +16 -6
- jarvis/jarvis_agent/file_input_handler.py +9 -9
- jarvis/jarvis_agent/jarvis.py +143 -0
- jarvis/jarvis_agent/main.py +12 -13
- jarvis/jarvis_agent/output_handler.py +3 -3
- jarvis/jarvis_agent/patch.py +92 -64
- jarvis/jarvis_agent/shell_input_handler.py +5 -3
- jarvis/jarvis_code_agent/code_agent.py +263 -177
- jarvis/jarvis_code_agent/file_select.py +24 -24
- jarvis/jarvis_dev/main.py +45 -59
- jarvis/jarvis_git_details/__init__.py +0 -0
- jarvis/jarvis_git_details/main.py +179 -0
- jarvis/jarvis_git_squash/main.py +7 -7
- jarvis/jarvis_lsp/base.py +11 -53
- jarvis/jarvis_lsp/cpp.py +13 -28
- jarvis/jarvis_lsp/go.py +13 -28
- jarvis/jarvis_lsp/python.py +8 -27
- jarvis/jarvis_lsp/registry.py +21 -83
- jarvis/jarvis_lsp/rust.py +15 -30
- jarvis/jarvis_methodology/main.py +101 -0
- jarvis/jarvis_multi_agent/__init__.py +10 -51
- jarvis/jarvis_multi_agent/main.py +43 -0
- jarvis/jarvis_platform/__init__.py +1 -1
- jarvis/jarvis_platform/ai8.py +67 -89
- jarvis/jarvis_platform/base.py +14 -13
- jarvis/jarvis_platform/kimi.py +25 -28
- jarvis/jarvis_platform/ollama.py +24 -26
- jarvis/jarvis_platform/openai.py +15 -19
- jarvis/jarvis_platform/oyi.py +48 -50
- jarvis/jarvis_platform/registry.py +29 -44
- jarvis/jarvis_platform/yuanbao.py +39 -43
- jarvis/jarvis_platform_manager/main.py +81 -81
- jarvis/jarvis_platform_manager/openai_test.py +21 -21
- jarvis/jarvis_rag/file_processors.py +18 -18
- jarvis/jarvis_rag/main.py +262 -278
- jarvis/jarvis_smart_shell/main.py +12 -12
- jarvis/jarvis_tools/ask_codebase.py +85 -78
- jarvis/jarvis_tools/ask_user.py +8 -8
- jarvis/jarvis_tools/base.py +4 -4
- jarvis/jarvis_tools/chdir.py +9 -9
- jarvis/jarvis_tools/code_review.py +40 -21
- jarvis/jarvis_tools/create_code_agent.py +15 -15
- jarvis/jarvis_tools/create_sub_agent.py +0 -1
- jarvis/jarvis_tools/execute_python_script.py +3 -3
- jarvis/jarvis_tools/execute_shell.py +11 -11
- jarvis/jarvis_tools/execute_shell_script.py +3 -3
- jarvis/jarvis_tools/file_analyzer.py +116 -105
- jarvis/jarvis_tools/file_operation.py +22 -20
- jarvis/jarvis_tools/find_caller.py +105 -40
- jarvis/jarvis_tools/find_methodolopy.py +65 -0
- jarvis/jarvis_tools/find_symbol.py +123 -39
- jarvis/jarvis_tools/function_analyzer.py +140 -57
- jarvis/jarvis_tools/git_commiter.py +10 -10
- jarvis/jarvis_tools/lsp_get_diagnostics.py +19 -19
- jarvis/jarvis_tools/methodology.py +22 -67
- jarvis/jarvis_tools/project_analyzer.py +137 -53
- jarvis/jarvis_tools/rag.py +15 -20
- jarvis/jarvis_tools/read_code.py +25 -23
- jarvis/jarvis_tools/read_webpage.py +31 -31
- jarvis/jarvis_tools/registry.py +72 -52
- jarvis/jarvis_tools/search_web.py +23 -353
- jarvis/jarvis_tools/tool_generator.py +19 -19
- jarvis/jarvis_utils/config.py +36 -96
- jarvis/jarvis_utils/embedding.py +83 -83
- jarvis/jarvis_utils/git_utils.py +20 -20
- jarvis/jarvis_utils/globals.py +18 -6
- jarvis/jarvis_utils/input.py +10 -9
- jarvis/jarvis_utils/methodology.py +141 -140
- jarvis/jarvis_utils/output.py +13 -13
- jarvis/jarvis_utils/utils.py +23 -71
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/METADATA +6 -15
- jarvis_ai_assistant-0.1.138.dist-info/RECORD +85 -0
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/entry_points.txt +4 -3
- jarvis/jarvis_tools/lsp_find_definition.py +0 -150
- jarvis/jarvis_tools/lsp_find_references.py +0 -127
- jarvis/jarvis_tools/select_code_files.py +0 -62
- jarvis_ai_assistant-0.1.132.dist-info/RECORD +0 -82
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/top_level.txt +0 -0
jarvis/jarvis_platform/kimi.py
CHANGED
|
@@ -15,7 +15,7 @@ class KimiModel(BasePlatform):
|
|
|
15
15
|
def get_model_list(self) -> List[Tuple[str, str]]:
|
|
16
16
|
"""Get model list"""
|
|
17
17
|
return [("kimi", "Based on the web Kimi, free interface")]
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
def __init__(self):
|
|
20
20
|
"""
|
|
21
21
|
Initialize Kimi model
|
|
@@ -28,7 +28,7 @@ class KimiModel(BasePlatform):
|
|
|
28
28
|
"需要设置 KIMI_API_KEY 才能使用 Jarvis。请按照以下步骤操作:\n"
|
|
29
29
|
"1. 获取 Kimi API Key:\n"
|
|
30
30
|
" • 访问 Kimi AI 平台: https://kimi.moonshot.cn\n"
|
|
31
|
-
" • 登录您的账户\n"
|
|
31
|
+
" • 登录您的账户\n"
|
|
32
32
|
" • 打开浏览器开发者工具 (F12 或右键 -> 检查)\n"
|
|
33
33
|
" • 切换到网络标签\n"
|
|
34
34
|
" • 发送任意消息\n"
|
|
@@ -84,9 +84,9 @@ class KimiModel(BasePlatform):
|
|
|
84
84
|
raise Exception("Failed to create chat session")
|
|
85
85
|
|
|
86
86
|
url = f"https://kimi.moonshot.cn/api/chat/{self.chat_id}/completion/stream"
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
90
|
payload = {
|
|
91
91
|
"messages": [{"role": "user", "content": message}],
|
|
92
92
|
"use_search": True,
|
|
@@ -106,23 +106,23 @@ class KimiModel(BasePlatform):
|
|
|
106
106
|
try:
|
|
107
107
|
response = while_success(lambda: requests.post(url, headers=headers, json=payload, stream=True), sleep_time=5)
|
|
108
108
|
full_response = ""
|
|
109
|
-
|
|
109
|
+
|
|
110
110
|
# 收集搜索和引用结果
|
|
111
111
|
search_results = []
|
|
112
112
|
ref_sources = []
|
|
113
|
-
|
|
113
|
+
|
|
114
114
|
for line in response.iter_lines():
|
|
115
115
|
if not line:
|
|
116
116
|
continue
|
|
117
|
-
|
|
117
|
+
|
|
118
118
|
line = line.decode('utf-8')
|
|
119
119
|
if not line.startswith("data: "):
|
|
120
120
|
continue
|
|
121
|
-
|
|
121
|
+
|
|
122
122
|
try:
|
|
123
123
|
data = json.loads(line[6:])
|
|
124
124
|
event = data.get("event")
|
|
125
|
-
|
|
125
|
+
|
|
126
126
|
if event == "cmpl":
|
|
127
127
|
# 处理补全文本
|
|
128
128
|
text = data.get("text", "")
|
|
@@ -130,7 +130,7 @@ class KimiModel(BasePlatform):
|
|
|
130
130
|
if not self.suppress_output:
|
|
131
131
|
PrettyOutput.print_stream(text)
|
|
132
132
|
full_response += text
|
|
133
|
-
|
|
133
|
+
|
|
134
134
|
elif event == "search_plus":
|
|
135
135
|
# 收集搜索结果
|
|
136
136
|
msg = data.get("msg", {})
|
|
@@ -143,7 +143,7 @@ class KimiModel(BasePlatform):
|
|
|
143
143
|
"type": msg.get("type", ""),
|
|
144
144
|
"url": msg.get("url", "")
|
|
145
145
|
})
|
|
146
|
-
|
|
146
|
+
|
|
147
147
|
elif event == "ref_docs":
|
|
148
148
|
# 收集引用来源
|
|
149
149
|
ref_cards = data.get("ref_cards", [])
|
|
@@ -159,13 +159,13 @@ class KimiModel(BasePlatform):
|
|
|
159
159
|
"rag_segments": card.get("rag_segments", []),
|
|
160
160
|
"origin": card.get("origin", {})
|
|
161
161
|
})
|
|
162
|
-
|
|
162
|
+
|
|
163
163
|
except json.JSONDecodeError:
|
|
164
164
|
continue
|
|
165
|
-
|
|
165
|
+
|
|
166
166
|
if not self.suppress_output:
|
|
167
167
|
PrettyOutput.print_stream_end()
|
|
168
|
-
|
|
168
|
+
|
|
169
169
|
|
|
170
170
|
# 显示搜索结果摘要
|
|
171
171
|
if search_results and not self.suppress_output:
|
|
@@ -180,7 +180,7 @@ class KimiModel(BasePlatform):
|
|
|
180
180
|
output.append(f" 链接: {result['url']}")
|
|
181
181
|
output.append("")
|
|
182
182
|
PrettyOutput.print("\n".join(output), OutputType.PROGRESS)
|
|
183
|
-
|
|
183
|
+
|
|
184
184
|
# 显示引用来源
|
|
185
185
|
if ref_sources and not self.suppress_output:
|
|
186
186
|
output = ["引用来源:"]
|
|
@@ -189,7 +189,7 @@ class KimiModel(BasePlatform):
|
|
|
189
189
|
output.append(f" 链接: {source['url']}")
|
|
190
190
|
if source['abstract']:
|
|
191
191
|
output.append(f" 摘要: {source['abstract']}")
|
|
192
|
-
|
|
192
|
+
|
|
193
193
|
# 显示相关段落
|
|
194
194
|
if source['rag_segments']:
|
|
195
195
|
output.append(" 相关段落:")
|
|
@@ -197,18 +197,18 @@ class KimiModel(BasePlatform):
|
|
|
197
197
|
text = segment.get('text', '').replace('\n', ' ').strip()
|
|
198
198
|
if text:
|
|
199
199
|
output.append(f" - {text}")
|
|
200
|
-
|
|
200
|
+
|
|
201
201
|
# 显示原文引用
|
|
202
202
|
origin = source['origin']
|
|
203
203
|
if origin:
|
|
204
204
|
text = origin.get('text', '')
|
|
205
205
|
if text:
|
|
206
206
|
output.append(f" 原文: {text}")
|
|
207
|
-
|
|
207
|
+
|
|
208
208
|
output.append("")
|
|
209
209
|
|
|
210
210
|
PrettyOutput.print("\n".join(output), OutputType.PROGRESS)
|
|
211
|
-
|
|
211
|
+
|
|
212
212
|
return full_response
|
|
213
213
|
|
|
214
214
|
except Exception as e:
|
|
@@ -218,17 +218,19 @@ class KimiModel(BasePlatform):
|
|
|
218
218
|
"""Delete current session"""
|
|
219
219
|
if not self.chat_id:
|
|
220
220
|
return True # 如果没有会话ID,视为删除成功
|
|
221
|
-
|
|
221
|
+
|
|
222
222
|
url = f"https://kimi.moonshot.cn/api/chat/{self.chat_id}"
|
|
223
223
|
headers = {
|
|
224
224
|
'Authorization': self.auth_header,
|
|
225
225
|
'Content-Type': 'application/json'
|
|
226
226
|
}
|
|
227
|
-
|
|
227
|
+
|
|
228
228
|
try:
|
|
229
229
|
response = while_success(lambda: requests.delete(url, headers=headers), sleep_time=5)
|
|
230
230
|
if response.status_code == 200:
|
|
231
|
-
self.
|
|
231
|
+
self.chat_id = ""
|
|
232
|
+
self.uploaded_files = []
|
|
233
|
+
self.first_chat = True # 重置first_chat标记
|
|
232
234
|
return True
|
|
233
235
|
else:
|
|
234
236
|
PrettyOutput.print(f"删除会话失败: HTTP {response.status_code}", OutputType.WARNING)
|
|
@@ -237,11 +239,6 @@ class KimiModel(BasePlatform):
|
|
|
237
239
|
PrettyOutput.print(f"删除会话时发生错误: {str(e)}", OutputType.ERROR)
|
|
238
240
|
return False
|
|
239
241
|
|
|
240
|
-
def reset(self):
|
|
241
|
-
"""Reset chat"""
|
|
242
|
-
self.chat_id = ""
|
|
243
|
-
self.uploaded_files = []
|
|
244
|
-
self.first_chat = True # 重置first_chat标记
|
|
245
242
|
|
|
246
243
|
def name(self) -> str:
|
|
247
244
|
"""Model name"""
|
jarvis/jarvis_platform/ollama.py
CHANGED
|
@@ -9,25 +9,25 @@ import ollama
|
|
|
9
9
|
|
|
10
10
|
class OllamaPlatform(BasePlatform):
|
|
11
11
|
"""Ollama platform implementation"""
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
platform_name = "ollama"
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
def __init__(self):
|
|
16
16
|
"""Initialize model"""
|
|
17
17
|
super().__init__()
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
# Check environment variables and provide help information
|
|
20
20
|
self.api_base = os.getenv("OLLAMA_API_BASE", "http://localhost:11434")
|
|
21
21
|
self.model_name = os.getenv("JARVIS_MODEL") or "deepseek-r1:1.5b"
|
|
22
|
-
|
|
22
|
+
|
|
23
23
|
# Setup client based on availability
|
|
24
24
|
self.client = None
|
|
25
25
|
self.client = ollama.Client(host=self.api_base)
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
# Check if Ollama service is available
|
|
28
28
|
try:
|
|
29
29
|
available_models = self._get_available_models()
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
if not available_models:
|
|
32
32
|
message = (
|
|
33
33
|
"需要先下载 Ollama 模型才能使用:\n"
|
|
@@ -37,7 +37,7 @@ class OllamaPlatform(BasePlatform):
|
|
|
37
37
|
)
|
|
38
38
|
PrettyOutput.print(message, OutputType.INFO)
|
|
39
39
|
PrettyOutput.print("Ollama 没有可用的模型", OutputType.WARNING)
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
except Exception as e:
|
|
42
42
|
message = (
|
|
43
43
|
f"Ollama 服务未启动或无法连接: {str(e)}\n"
|
|
@@ -47,8 +47,8 @@ class OllamaPlatform(BasePlatform):
|
|
|
47
47
|
"3. 正确配置服务地址 (默认: http://localhost:11434)"
|
|
48
48
|
)
|
|
49
49
|
PrettyOutput.print(message, OutputType.WARNING)
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
|
|
51
|
+
|
|
52
52
|
self.messages = []
|
|
53
53
|
self.system_message = ""
|
|
54
54
|
|
|
@@ -81,7 +81,7 @@ class OllamaPlatform(BasePlatform):
|
|
|
81
81
|
messages.append({"role": "user", "content": message})
|
|
82
82
|
|
|
83
83
|
return self._chat_with_package(messages)
|
|
84
|
-
|
|
84
|
+
|
|
85
85
|
except Exception as e:
|
|
86
86
|
PrettyOutput.print(f"对话失败: {str(e)}", OutputType.ERROR)
|
|
87
87
|
raise Exception(f"Chat failed: {str(e)}")
|
|
@@ -91,14 +91,14 @@ class OllamaPlatform(BasePlatform):
|
|
|
91
91
|
# The client should not be None here due to the check in the chat method
|
|
92
92
|
if not self.client:
|
|
93
93
|
raise ValueError("Ollama client is not initialized")
|
|
94
|
-
|
|
94
|
+
|
|
95
95
|
# Use ollama-python's streaming API
|
|
96
96
|
stream = self.client.chat(
|
|
97
97
|
model=self.model_name,
|
|
98
98
|
messages=messages,
|
|
99
99
|
stream=True
|
|
100
100
|
)
|
|
101
|
-
|
|
101
|
+
|
|
102
102
|
# Process the streaming response
|
|
103
103
|
full_response = ""
|
|
104
104
|
for chunk in stream:
|
|
@@ -107,33 +107,31 @@ class OllamaPlatform(BasePlatform):
|
|
|
107
107
|
if not self.suppress_output:
|
|
108
108
|
PrettyOutput.print_stream(text)
|
|
109
109
|
full_response += text
|
|
110
|
-
|
|
110
|
+
|
|
111
111
|
if not self.suppress_output:
|
|
112
112
|
PrettyOutput.print_stream_end()
|
|
113
|
-
|
|
113
|
+
|
|
114
114
|
# Update message history
|
|
115
115
|
self.messages.append({"role": "user", "content": messages[-1]["content"]})
|
|
116
116
|
self.messages.append({"role": "assistant", "content": full_response})
|
|
117
|
-
|
|
117
|
+
|
|
118
118
|
return full_response
|
|
119
119
|
|
|
120
|
-
|
|
121
|
-
def reset(self):
|
|
122
|
-
"""Reset model state"""
|
|
123
|
-
self.messages = []
|
|
124
|
-
if self.system_message:
|
|
125
|
-
self.messages.append({"role": "system", "content": self.system_message})
|
|
126
|
-
|
|
120
|
+
|
|
127
121
|
def name(self) -> str:
|
|
128
122
|
"""Return model name"""
|
|
129
123
|
return self.model_name
|
|
130
|
-
|
|
124
|
+
|
|
131
125
|
def delete_chat(self) -> bool:
|
|
132
126
|
"""Delete current chat session"""
|
|
133
|
-
self.
|
|
127
|
+
self.messages = []
|
|
128
|
+
if self.system_message:
|
|
129
|
+
self.messages.append({"role": "system", "content": self.system_message})
|
|
134
130
|
return True
|
|
135
|
-
|
|
131
|
+
|
|
136
132
|
def set_system_message(self, message: str):
|
|
137
133
|
"""Set system message"""
|
|
138
134
|
self.system_message = message
|
|
139
|
-
self.
|
|
135
|
+
self.messages = []
|
|
136
|
+
if self.system_message:
|
|
137
|
+
self.messages.append({"role": "system", "content": self.system_message})
|
jarvis/jarvis_platform/openai.py
CHANGED
|
@@ -17,12 +17,12 @@ class OpenAIModel(BasePlatform):
|
|
|
17
17
|
if not self.api_key:
|
|
18
18
|
message = (
|
|
19
19
|
"需要设置以下环境变量才能使用 OpenAI 模型:\n"
|
|
20
|
-
" • OPENAI_API_KEY: API 密钥\n"
|
|
20
|
+
" • OPENAI_API_KEY: API 密钥\n"
|
|
21
21
|
" • OPENAI_API_BASE: (可选) API 基础地址, 默认使用 https://api.openai.com/v1\n"
|
|
22
22
|
"您可以通过以下方式设置它们:\n"
|
|
23
23
|
"1. 创建或编辑 ~/.jarvis/env 文件:\n"
|
|
24
24
|
" OPENAI_API_KEY=your_api_key\n"
|
|
25
|
-
" OPENAI_API_BASE=your_api_base\n"
|
|
25
|
+
" OPENAI_API_BASE=your_api_base\n"
|
|
26
26
|
" OPENAI_MODEL_NAME=your_model_name\n"
|
|
27
27
|
"2. 直接设置环境变量:\n"
|
|
28
28
|
" export OPENAI_API_KEY=your_api_key\n"
|
|
@@ -31,11 +31,11 @@ class OpenAIModel(BasePlatform):
|
|
|
31
31
|
)
|
|
32
32
|
PrettyOutput.print(message, OutputType.INFO)
|
|
33
33
|
PrettyOutput.print("OPENAI_API_KEY 未设置", OutputType.WARNING)
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
self.base_url = os.getenv("OPENAI_API_BASE", "https://api.openai.com/v1")
|
|
36
36
|
self.model_name = os.getenv("JARVIS_MODEL") or "gpt-4o"
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
self.client = OpenAI(
|
|
40
40
|
api_key=self.api_key,
|
|
41
41
|
base_url=self.base_url
|
|
@@ -68,33 +68,33 @@ class OpenAIModel(BasePlatform):
|
|
|
68
68
|
def chat(self, message: str) -> str:
|
|
69
69
|
"""Execute conversation"""
|
|
70
70
|
try:
|
|
71
|
-
|
|
71
|
+
|
|
72
72
|
# Add user message to history
|
|
73
73
|
self.messages.append({"role": "user", "content": message})
|
|
74
|
-
|
|
74
|
+
|
|
75
75
|
response = self.client.chat.completions.create(
|
|
76
76
|
model=self.model_name, # Use the configured model name
|
|
77
77
|
messages=self.messages, # type: ignore
|
|
78
78
|
stream=True
|
|
79
79
|
) # type: ignore
|
|
80
|
-
|
|
80
|
+
|
|
81
81
|
full_response = ""
|
|
82
|
-
|
|
82
|
+
|
|
83
83
|
for chunk in response:
|
|
84
84
|
if chunk.choices and chunk.choices[0].delta.content:
|
|
85
85
|
text = chunk.choices[0].delta.content
|
|
86
86
|
if not self.suppress_output:
|
|
87
87
|
PrettyOutput.print_stream(text)
|
|
88
88
|
full_response += text
|
|
89
|
-
|
|
89
|
+
|
|
90
90
|
if not self.suppress_output:
|
|
91
91
|
PrettyOutput.print_stream_end()
|
|
92
|
-
|
|
92
|
+
|
|
93
93
|
# Add assistant reply to history
|
|
94
94
|
self.messages.append({"role": "assistant", "content": full_response})
|
|
95
|
-
|
|
95
|
+
|
|
96
96
|
return full_response
|
|
97
|
-
|
|
97
|
+
|
|
98
98
|
except Exception as e:
|
|
99
99
|
PrettyOutput.print(f"对话失败:{str(e)}", OutputType.ERROR)
|
|
100
100
|
raise Exception(f"Chat failed: {str(e)}")
|
|
@@ -103,15 +103,11 @@ class OpenAIModel(BasePlatform):
|
|
|
103
103
|
"""Return model name"""
|
|
104
104
|
return self.model_name
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
|
|
107
|
+
def delete_chat(self)->bool:
|
|
108
|
+
"""Delete conversation"""
|
|
109
109
|
if self.system_message:
|
|
110
110
|
self.messages = [{"role": "system", "content": self.system_message}]
|
|
111
111
|
else:
|
|
112
112
|
self.messages = []
|
|
113
|
-
|
|
114
|
-
def delete_chat(self)->bool:
|
|
115
|
-
"""Delete conversation"""
|
|
116
|
-
self.reset()
|
|
117
113
|
return True
|
jarvis/jarvis_platform/oyi.py
CHANGED
|
@@ -9,7 +9,7 @@ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
|
9
9
|
|
|
10
10
|
class OyiModel(BasePlatform):
|
|
11
11
|
"""Oyi model implementation"""
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
platform_name = "oyi"
|
|
14
14
|
BASE_URL = "https://api-10086.rcouyi.com"
|
|
15
15
|
|
|
@@ -17,31 +17,31 @@ class OyiModel(BasePlatform):
|
|
|
17
17
|
"""Get model list"""
|
|
18
18
|
self.get_available_models()
|
|
19
19
|
return [(name,info['desc']) for name,info in self.models.items()]
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
def __init__(self):
|
|
22
22
|
"""Initialize model"""
|
|
23
23
|
super().__init__()
|
|
24
|
-
self.models = {}
|
|
24
|
+
self.models = {}
|
|
25
25
|
self.messages = []
|
|
26
26
|
self.system_message = ""
|
|
27
27
|
self.conversation = None
|
|
28
28
|
self.first_chat = True
|
|
29
|
-
|
|
29
|
+
|
|
30
30
|
self.token = os.getenv("OYI_API_KEY")
|
|
31
31
|
if not self.token:
|
|
32
32
|
PrettyOutput.print("OYI_API_KEY 未设置", OutputType.WARNING)
|
|
33
|
-
|
|
33
|
+
|
|
34
34
|
self.model_name = os.getenv("JARVIS_MODEL") or "deepseek-chat"
|
|
35
35
|
if self.model_name not in [m.split()[0] for m in self.get_available_models()]:
|
|
36
36
|
PrettyOutput.print(f"警告: 选择的模型 {self.model_name} 不在可用列表中", OutputType.WARNING)
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
|
|
39
39
|
def set_model_name(self, model_name: str):
|
|
40
40
|
"""Set model name"""
|
|
41
41
|
|
|
42
42
|
self.model_name = model_name
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
|
|
45
45
|
def create_conversation(self) -> bool:
|
|
46
46
|
"""Create a new conversation"""
|
|
47
47
|
try:
|
|
@@ -51,7 +51,7 @@ class OyiModel(BasePlatform):
|
|
|
51
51
|
'Accept': 'application/json',
|
|
52
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
53
|
}
|
|
54
|
-
|
|
54
|
+
|
|
55
55
|
payload = {
|
|
56
56
|
"id": 0,
|
|
57
57
|
"roleId": 0,
|
|
@@ -70,13 +70,13 @@ class OyiModel(BasePlatform):
|
|
|
70
70
|
"chatPluginIds": []
|
|
71
71
|
})
|
|
72
72
|
}
|
|
73
|
-
|
|
73
|
+
|
|
74
74
|
response = requests.post(
|
|
75
75
|
f"{self.BASE_URL}/chatapi/chat/save",
|
|
76
76
|
headers=headers,
|
|
77
77
|
json=payload
|
|
78
78
|
)
|
|
79
|
-
|
|
79
|
+
|
|
80
80
|
if response.status_code == 200:
|
|
81
81
|
data = response.json()
|
|
82
82
|
if data['code'] == 200 and data['type'] == 'success':
|
|
@@ -88,21 +88,21 @@ class OyiModel(BasePlatform):
|
|
|
88
88
|
else:
|
|
89
89
|
PrettyOutput.print(f"创建会话失败: {response.status_code}", OutputType.WARNING)
|
|
90
90
|
return False
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
except Exception as e:
|
|
93
93
|
PrettyOutput.print(f"创建会话失败: {str(e)}", OutputType.ERROR)
|
|
94
94
|
return False
|
|
95
|
-
|
|
95
|
+
|
|
96
96
|
def set_system_message(self, message: str):
|
|
97
97
|
"""Set system message"""
|
|
98
98
|
self.system_message = message
|
|
99
|
-
|
|
99
|
+
|
|
100
100
|
def chat(self, message: str) -> str:
|
|
101
101
|
"""Execute chat with the model
|
|
102
|
-
|
|
102
|
+
|
|
103
103
|
Args:
|
|
104
104
|
message: User input message
|
|
105
|
-
|
|
105
|
+
|
|
106
106
|
Returns:
|
|
107
107
|
str: Model response
|
|
108
108
|
"""
|
|
@@ -111,7 +111,7 @@ class OyiModel(BasePlatform):
|
|
|
111
111
|
if not self.conversation:
|
|
112
112
|
if not self.create_conversation():
|
|
113
113
|
raise Exception("Failed to create conversation")
|
|
114
|
-
|
|
114
|
+
|
|
115
115
|
# 1. 发送消息
|
|
116
116
|
headers = {
|
|
117
117
|
'Authorization': f'Bearer {self.token}',
|
|
@@ -121,14 +121,14 @@ class OyiModel(BasePlatform):
|
|
|
121
121
|
'Origin': 'https://ai.rcouyi.com',
|
|
122
122
|
'Referer': 'https://ai.rcouyi.com/'
|
|
123
123
|
}
|
|
124
|
-
|
|
124
|
+
|
|
125
125
|
payload = {
|
|
126
126
|
"topicId": self.conversation['result']['id'] if self.conversation else None,
|
|
127
127
|
"messages": self.messages,
|
|
128
128
|
"content": message,
|
|
129
129
|
"contentFiles": []
|
|
130
130
|
}
|
|
131
|
-
|
|
131
|
+
|
|
132
132
|
# 如果有上传的文件,添加到请求中
|
|
133
133
|
if self.first_chat:
|
|
134
134
|
message = self.system_message + "\n" + message
|
|
@@ -136,34 +136,34 @@ class OyiModel(BasePlatform):
|
|
|
136
136
|
self.first_chat = False
|
|
137
137
|
|
|
138
138
|
self.messages.append({"role": "user", "content": message})
|
|
139
|
-
|
|
139
|
+
|
|
140
140
|
# 发送消息
|
|
141
141
|
response = requests.post(
|
|
142
142
|
f"{self.BASE_URL}/chatapi/chat/message",
|
|
143
143
|
headers=headers,
|
|
144
144
|
json=payload
|
|
145
145
|
)
|
|
146
|
-
|
|
146
|
+
|
|
147
147
|
if response.status_code != 200:
|
|
148
148
|
error_msg = f"聊天请求失败: {response.status_code}"
|
|
149
149
|
PrettyOutput.print(error_msg, OutputType.WARNING)
|
|
150
150
|
raise Exception(error_msg)
|
|
151
|
-
|
|
151
|
+
|
|
152
152
|
data = response.json()
|
|
153
153
|
if data['code'] != 200 or data['type'] != 'success':
|
|
154
154
|
error_msg = f"聊天失败: {data.get('message', '未知错误')}"
|
|
155
155
|
PrettyOutput.print(error_msg, OutputType.WARNING)
|
|
156
156
|
raise Exception(error_msg)
|
|
157
|
-
|
|
157
|
+
|
|
158
158
|
message_id = data['result'][-1]
|
|
159
|
-
|
|
159
|
+
|
|
160
160
|
# 获取响应内容
|
|
161
161
|
response = requests.post(
|
|
162
162
|
f"{self.BASE_URL}/chatapi/chat/message/{message_id}",
|
|
163
163
|
headers=headers,
|
|
164
164
|
stream=True
|
|
165
165
|
)
|
|
166
|
-
|
|
166
|
+
|
|
167
167
|
if response.status_code == 200:
|
|
168
168
|
full_response = ""
|
|
169
169
|
bin = b""
|
|
@@ -180,7 +180,7 @@ class OyiModel(BasePlatform):
|
|
|
180
180
|
bin = b""
|
|
181
181
|
|
|
182
182
|
PrettyOutput.print_stream_end()
|
|
183
|
-
|
|
183
|
+
|
|
184
184
|
self.messages.append({"role": "assistant", "content": full_response})
|
|
185
185
|
return full_response
|
|
186
186
|
else:
|
|
@@ -190,23 +190,18 @@ class OyiModel(BasePlatform):
|
|
|
190
190
|
except Exception as e:
|
|
191
191
|
PrettyOutput.print(f"聊天失败: {str(e)}", OutputType.ERROR)
|
|
192
192
|
raise e
|
|
193
|
-
|
|
193
|
+
|
|
194
194
|
def name(self) -> str:
|
|
195
195
|
"""Return model name"""
|
|
196
196
|
return self.model_name
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
"""Reset model state"""
|
|
200
|
-
self.messages = []
|
|
201
|
-
self.conversation = None
|
|
202
|
-
self.first_chat = True
|
|
203
|
-
|
|
197
|
+
|
|
198
|
+
|
|
204
199
|
def delete_chat(self) -> bool:
|
|
205
200
|
"""Delete current chat session"""
|
|
206
201
|
try:
|
|
207
202
|
if not self.conversation:
|
|
208
203
|
return True
|
|
209
|
-
|
|
204
|
+
|
|
210
205
|
headers = {
|
|
211
206
|
'Authorization': f'Bearer {self.token}',
|
|
212
207
|
'Content-Type': 'application/json',
|
|
@@ -215,17 +210,19 @@ class OyiModel(BasePlatform):
|
|
|
215
210
|
'Origin': 'https://ai.rcouyi.com',
|
|
216
211
|
'Referer': 'https://ai.rcouyi.com/'
|
|
217
212
|
}
|
|
218
|
-
|
|
213
|
+
|
|
219
214
|
response = requests.post(
|
|
220
215
|
f"{self.BASE_URL}/chatapi/chat/{self.conversation['result']['id']}",
|
|
221
216
|
headers=headers,
|
|
222
217
|
json={}
|
|
223
218
|
)
|
|
224
|
-
|
|
219
|
+
|
|
225
220
|
if response.status_code == 200:
|
|
226
221
|
data = response.json()
|
|
227
222
|
if data['code'] == 200 and data['type'] == 'success':
|
|
228
|
-
self.
|
|
223
|
+
self.messages = []
|
|
224
|
+
self.conversation = None
|
|
225
|
+
self.first_chat = True
|
|
229
226
|
return True
|
|
230
227
|
else:
|
|
231
228
|
error_msg = f"删除会话失败: {data.get('message', '未知错误')}"
|
|
@@ -235,21 +232,22 @@ class OyiModel(BasePlatform):
|
|
|
235
232
|
error_msg = f"删除会话请求失败: {response.status_code}"
|
|
236
233
|
PrettyOutput.print(error_msg, OutputType.WARNING)
|
|
237
234
|
return False
|
|
238
|
-
|
|
235
|
+
|
|
236
|
+
|
|
239
237
|
except Exception as e:
|
|
240
238
|
PrettyOutput.print(f"删除会话失败: {str(e)}", OutputType.ERROR)
|
|
241
239
|
return False
|
|
242
240
|
|
|
243
241
|
def get_available_models(self) -> List[str]:
|
|
244
242
|
"""Get available model list
|
|
245
|
-
|
|
243
|
+
|
|
246
244
|
Returns:
|
|
247
245
|
List[str]: Available model name list
|
|
248
246
|
"""
|
|
249
247
|
try:
|
|
250
248
|
if self.models:
|
|
251
249
|
return list(self.models.keys())
|
|
252
|
-
|
|
250
|
+
|
|
253
251
|
headers = {
|
|
254
252
|
'Content-Type': 'application/json',
|
|
255
253
|
'Accept': 'application/json, text/plain, */*',
|
|
@@ -257,32 +255,32 @@ class OyiModel(BasePlatform):
|
|
|
257
255
|
'Origin': 'https://ai.rcouyi.com',
|
|
258
256
|
'Referer': 'https://ai.rcouyi.com/'
|
|
259
257
|
}
|
|
260
|
-
|
|
258
|
+
|
|
261
259
|
response = requests.get(
|
|
262
260
|
"https://ai.rcouyi.com/config/system.json",
|
|
263
261
|
headers=headers
|
|
264
262
|
)
|
|
265
|
-
|
|
263
|
+
|
|
266
264
|
if response.status_code != 200:
|
|
267
265
|
PrettyOutput.print(f"获取模型列表失败: {response.status_code}", OutputType.WARNING)
|
|
268
266
|
return []
|
|
269
|
-
|
|
267
|
+
|
|
270
268
|
data = response.json()
|
|
271
|
-
|
|
269
|
+
|
|
272
270
|
# 保存模型信息
|
|
273
271
|
self.models = {
|
|
274
272
|
model['value']: model
|
|
275
273
|
for model in data.get('model', [])
|
|
276
274
|
if model.get('enable', False) # 只保存启用的模型
|
|
277
275
|
}
|
|
278
|
-
|
|
276
|
+
|
|
279
277
|
# 格式化显示
|
|
280
278
|
models = []
|
|
281
279
|
for model in self.models.values():
|
|
282
280
|
# 基本信息
|
|
283
281
|
model_name = model['value']
|
|
284
282
|
model_str = model['label']
|
|
285
|
-
|
|
283
|
+
|
|
286
284
|
# 添加后缀标签
|
|
287
285
|
suffix = model.get('suffix', [])
|
|
288
286
|
if suffix:
|
|
@@ -293,17 +291,17 @@ class OyiModel(BasePlatform):
|
|
|
293
291
|
else:
|
|
294
292
|
suffix_str = ', '.join(str(s) for s in suffix)
|
|
295
293
|
model_str += f" ({suffix_str})"
|
|
296
|
-
|
|
294
|
+
|
|
297
295
|
# 添加描述或提示
|
|
298
296
|
info = model.get('tooltip') or model.get('description', '')
|
|
299
297
|
if info:
|
|
300
298
|
model_str += f" - {info}"
|
|
301
|
-
|
|
299
|
+
|
|
302
300
|
model['desc'] = model_str
|
|
303
301
|
models.append(model_name)
|
|
304
|
-
|
|
302
|
+
|
|
305
303
|
return sorted(models)
|
|
306
|
-
|
|
304
|
+
|
|
307
305
|
except Exception as e:
|
|
308
306
|
PrettyOutput.print(f"获取模型列表失败: {str(e)}", OutputType.WARNING)
|
|
309
307
|
return []
|