jarvis-ai-assistant 0.1.213__py3-none-any.whl → 0.1.216__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/__init__.py +37 -0
- jarvis/jarvis_agent/builtin_input_handler.py +12 -1
- jarvis/jarvis_agent/edit_file_handler.py +44 -32
- jarvis/jarvis_agent/jarvis.py +17 -1
- jarvis/jarvis_code_agent/code_agent.py +18 -4
- jarvis/jarvis_platform/ai8.py +58 -6
- jarvis/jarvis_platform/base.py +37 -1
- jarvis/jarvis_platform/human.py +48 -3
- jarvis/jarvis_platform/kimi.py +54 -5
- jarvis/jarvis_platform/openai.py +48 -2
- jarvis/jarvis_platform/oyi.py +51 -1
- jarvis/jarvis_platform/registry.py +17 -7
- jarvis/jarvis_platform/tongyi.py +60 -3
- jarvis/jarvis_platform/yuanbao.py +51 -3
- jarvis/jarvis_platform_manager/main.py +65 -19
- jarvis/jarvis_platform_manager/service.py +66 -100
- jarvis/jarvis_utils/input.py +5 -3
- {jarvis_ai_assistant-0.1.213.dist-info → jarvis_ai_assistant-0.1.216.dist-info}/METADATA +1 -1
- {jarvis_ai_assistant-0.1.213.dist-info → jarvis_ai_assistant-0.1.216.dist-info}/RECORD +24 -24
- {jarvis_ai_assistant-0.1.213.dist-info → jarvis_ai_assistant-0.1.216.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.213.dist-info → jarvis_ai_assistant-0.1.216.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.213.dist-info → jarvis_ai_assistant-0.1.216.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.213.dist-info → jarvis_ai_assistant-0.1.216.dist-info}/top_level.txt +0 -0
jarvis/__init__.py
CHANGED
jarvis/jarvis_agent/__init__.py
CHANGED
@@ -356,6 +356,43 @@ class Agent:
|
|
356
356
|
"""
|
357
357
|
self.after_tool_call_cb = cb
|
358
358
|
|
359
|
+
def save_session(self) -> bool:
|
360
|
+
"""保存当前会话状态到文件"""
|
361
|
+
if not self.model:
|
362
|
+
PrettyOutput.print("没有可用的模型实例来保存会话。", OutputType.ERROR)
|
363
|
+
return False
|
364
|
+
session_dir = os.path.join(os.getcwd(), ".jarvis")
|
365
|
+
os.makedirs(session_dir, exist_ok=True)
|
366
|
+
platform_name = self.model.platform_name()
|
367
|
+
model_name = self.model.name().replace("/", "_").replace("\\", "_")
|
368
|
+
session_file = os.path.join(
|
369
|
+
session_dir, f"saved_session_{self.name}_{platform_name}_{model_name}.json"
|
370
|
+
)
|
371
|
+
return self.model.save(session_file)
|
372
|
+
|
373
|
+
def restore_session(self) -> bool:
|
374
|
+
"""从文件恢复会话状态"""
|
375
|
+
if not self.model:
|
376
|
+
return False # No model, cannot restore
|
377
|
+
platform_name = self.model.platform_name()
|
378
|
+
model_name = self.model.name().replace("/", "_").replace("\\", "_")
|
379
|
+
session_file = os.path.join(
|
380
|
+
os.getcwd(),
|
381
|
+
".jarvis",
|
382
|
+
f"saved_session_{self.name}_{platform_name}_{model_name}.json",
|
383
|
+
)
|
384
|
+
if not os.path.exists(session_file):
|
385
|
+
return False
|
386
|
+
|
387
|
+
if self.model.restore(session_file):
|
388
|
+
try:
|
389
|
+
os.remove(session_file)
|
390
|
+
PrettyOutput.print("会话已恢复,并已删除会话文件。", OutputType.SUCCESS)
|
391
|
+
except OSError as e:
|
392
|
+
PrettyOutput.print(f"删除会话文件失败: {e}", OutputType.ERROR)
|
393
|
+
return True
|
394
|
+
return False
|
395
|
+
|
359
396
|
def get_tool_registry(self) -> Optional[Any]:
|
360
397
|
"""获取工具注册表实例"""
|
361
398
|
from jarvis.jarvis_tools.registry import ToolRegistry
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
import re
|
3
|
+
import sys
|
3
4
|
from typing import Any, Tuple
|
4
5
|
|
5
6
|
from jarvis.jarvis_utils.config import get_replace_map
|
@@ -29,7 +30,6 @@ def builtin_input_handler(user_input: str, agent_: Any) -> Tuple[str, bool]:
|
|
29
30
|
replace_map = get_replace_map()
|
30
31
|
# 处理每个标记
|
31
32
|
for tag in special_tags:
|
32
|
-
|
33
33
|
# 优先处理特殊标记
|
34
34
|
if tag == "Summary":
|
35
35
|
agent._summarize_and_clear_history()
|
@@ -51,6 +51,17 @@ def builtin_input_handler(user_input: str, agent_: Any) -> Tuple[str, bool]:
|
|
51
51
|
|
52
52
|
load_config()
|
53
53
|
return "", True
|
54
|
+
elif tag == "SaveSession":
|
55
|
+
if agent.save_session():
|
56
|
+
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
57
|
+
|
58
|
+
PrettyOutput.print("会话已成功保存。正在退出...", OutputType.SUCCESS)
|
59
|
+
sys.exit(0)
|
60
|
+
else:
|
61
|
+
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
62
|
+
|
63
|
+
PrettyOutput.print("保存会话失败。", OutputType.ERROR)
|
64
|
+
return "", True
|
54
65
|
|
55
66
|
processed_tag = set()
|
56
67
|
add_on_prompt = ""
|
@@ -206,48 +206,60 @@ class EditFileHandler(OutputHandler):
|
|
206
206
|
exact_search = search_text
|
207
207
|
|
208
208
|
if exact_search in modified_content:
|
209
|
-
if modified_content.count(exact_search) > 1:
|
210
|
-
PrettyOutput.print(
|
211
|
-
f"搜索文本在文件中存在多处匹配:\n{exact_search}",
|
212
|
-
output_type=OutputType.WARNING,
|
213
|
-
)
|
214
|
-
return False, f"搜索文本在文件中存在多处匹配:\n{exact_search}"
|
215
|
-
|
216
209
|
# 直接执行替换(保留所有原始格式)
|
217
210
|
modified_content = modified_content.replace(
|
218
211
|
exact_search, replace_text
|
219
212
|
)
|
220
213
|
print(f"✅ 补丁 #{patch_count} 应用成功")
|
221
214
|
else:
|
222
|
-
# 尝试增加缩进重试
|
223
215
|
found = False
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
)
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
if
|
234
|
-
if modified_content.count(indented_search) > 1:
|
235
|
-
PrettyOutput.print(
|
236
|
-
f"搜索文本在文件中存在多处匹配:\n{indented_search}",
|
237
|
-
output_type=OutputType.WARNING,
|
238
|
-
)
|
239
|
-
return (
|
240
|
-
False,
|
241
|
-
f"搜索文本在文件中存在多处匹配:\n{indented_search}",
|
242
|
-
)
|
216
|
+
# 如果匹配不到,并且search与replace块的首尾都是换行,尝试去掉第一个和最后一个换行
|
217
|
+
if (
|
218
|
+
search_text.startswith("\n")
|
219
|
+
and search_text.endswith("\n")
|
220
|
+
and replace_text.startswith("\n")
|
221
|
+
and replace_text.endswith("\n")
|
222
|
+
):
|
223
|
+
stripped_search = search_text[1:-1]
|
224
|
+
stripped_replace = replace_text[1:-1]
|
225
|
+
if stripped_search in modified_content:
|
243
226
|
modified_content = modified_content.replace(
|
244
|
-
|
245
|
-
)
|
246
|
-
print(
|
247
|
-
f"✅ 补丁 #{patch_count} 应用成功 (自动增加 {space_count} 个空格缩进)"
|
227
|
+
stripped_search, stripped_replace
|
248
228
|
)
|
229
|
+
print(f"✅ 补丁 #{patch_count} 应用成功 (自动去除首尾换行)")
|
249
230
|
found = True
|
250
|
-
|
231
|
+
|
232
|
+
if not found:
|
233
|
+
# 尝试增加缩进重试
|
234
|
+
current_search = search_text
|
235
|
+
current_replace = replace_text
|
236
|
+
if (
|
237
|
+
current_search.startswith("\n")
|
238
|
+
and current_search.endswith("\n")
|
239
|
+
and current_replace.startswith("\n")
|
240
|
+
and current_replace.endswith("\n")
|
241
|
+
):
|
242
|
+
current_search = current_search[1:-1]
|
243
|
+
current_replace = current_replace[1:-1]
|
244
|
+
|
245
|
+
for space_count in range(1, 17):
|
246
|
+
indented_search = "\n".join(
|
247
|
+
" " * space_count + line if line.strip() else line
|
248
|
+
for line in current_search.split("\n")
|
249
|
+
)
|
250
|
+
indented_replace = "\n".join(
|
251
|
+
" " * space_count + line if line.strip() else line
|
252
|
+
for line in current_replace.split("\n")
|
253
|
+
)
|
254
|
+
if indented_search in modified_content:
|
255
|
+
modified_content = modified_content.replace(
|
256
|
+
indented_search, indented_replace
|
257
|
+
)
|
258
|
+
print(
|
259
|
+
f"✅ 补丁 #{patch_count} 应用成功 (自动增加 {space_count} 个空格缩进)"
|
260
|
+
)
|
261
|
+
found = True
|
262
|
+
break
|
251
263
|
|
252
264
|
if not found:
|
253
265
|
PrettyOutput.print(
|
jarvis/jarvis_agent/jarvis.py
CHANGED
@@ -112,9 +112,18 @@ def main() -> None:
|
|
112
112
|
parser.add_argument("-p", "--platform", type=str, help="Platform to use")
|
113
113
|
parser.add_argument("-m", "--model", type=str, help="Model to use")
|
114
114
|
parser.add_argument(
|
115
|
-
"-t",
|
115
|
+
"-t",
|
116
|
+
"--task",
|
117
|
+
type=str,
|
118
|
+
help="Directly input task content from command line",
|
116
119
|
)
|
117
120
|
parser.add_argument("-f", "--config", type=str, help="Path to custom config file")
|
121
|
+
parser.add_argument(
|
122
|
+
"--restore-session",
|
123
|
+
action="store_true",
|
124
|
+
help="Restore session from .jarvis/saved_session.json",
|
125
|
+
default=False,
|
126
|
+
)
|
118
127
|
args = parser.parse_args()
|
119
128
|
init_env(
|
120
129
|
"欢迎使用 Jarvis AI 助手,您的智能助理已准备就绪!", config_file=args.config
|
@@ -130,6 +139,13 @@ def main() -> None:
|
|
130
139
|
need_summary=False,
|
131
140
|
)
|
132
141
|
|
142
|
+
# 尝试恢复会话
|
143
|
+
if args.restore_session:
|
144
|
+
if agent.restore_session():
|
145
|
+
PrettyOutput.print("会话已成功恢复。", OutputType.SUCCESS)
|
146
|
+
else:
|
147
|
+
PrettyOutput.print("无法恢复会话。", OutputType.WARNING)
|
148
|
+
|
133
149
|
# 优先处理命令行直接传入的任务
|
134
150
|
if args.task:
|
135
151
|
agent.run(args.task)
|
@@ -131,7 +131,7 @@ class CodeAgent:
|
|
131
131
|
input_handler=[shell_input_handler, builtin_input_handler],
|
132
132
|
need_summary=need_summary,
|
133
133
|
use_methodology=False, # 禁用方法论
|
134
|
-
use_analysis=False
|
134
|
+
use_analysis=False, # 禁用分析
|
135
135
|
)
|
136
136
|
|
137
137
|
self.agent.set_after_tool_call_cb(self.after_tool_call_cb)
|
@@ -359,9 +359,7 @@ class CodeAgent:
|
|
359
359
|
|
360
360
|
# 添加提交信息到final_ret
|
361
361
|
if commits:
|
362
|
-
final_ret +=
|
363
|
-
f"\n\n代码已修改完成\n补丁内容:\n```diff\n{diff}\n```\n"
|
364
|
-
)
|
362
|
+
final_ret += f"\n\n代码已修改完成\n补丁内容:\n```diff\n{diff}\n```\n"
|
365
363
|
# 修改后的提示逻辑
|
366
364
|
lint_tools_info = "\n".join(
|
367
365
|
f" - {file}: 使用 {'、'.join(get_lint_tools(file))}"
|
@@ -380,6 +378,7 @@ class CodeAgent:
|
|
380
378
|
{file_list}
|
381
379
|
{tool_info}
|
382
380
|
如果本次修改引入了警告和错误,请根据警告和错误信息修复代码
|
381
|
+
注意:如果要进行静态检查,需要在所有的修改都完成之后进行集中检查
|
383
382
|
"""
|
384
383
|
agent.set_addon_prompt(addon_prompt)
|
385
384
|
else:
|
@@ -420,6 +419,9 @@ def main() -> None:
|
|
420
419
|
parser.add_argument(
|
421
420
|
"-r", "--requirement", type=str, help="Requirement to process", default=None
|
422
421
|
)
|
422
|
+
parser.add_argument(
|
423
|
+
"--restore-session", action="store_true", help="Restore session from .jarvis/saved_session.json", default=False
|
424
|
+
)
|
423
425
|
args = parser.parse_args()
|
424
426
|
|
425
427
|
curr_dir = os.getcwd()
|
@@ -428,6 +430,18 @@ def main() -> None:
|
|
428
430
|
|
429
431
|
try:
|
430
432
|
agent = CodeAgent(platform=args.platform, model=args.model, need_summary=False)
|
433
|
+
|
434
|
+
# 尝试恢复会话
|
435
|
+
if args.restore_session:
|
436
|
+
if agent.agent.restore_session():
|
437
|
+
PrettyOutput.print(
|
438
|
+
"已从 .jarvis/saved_session.json 恢复会话。", OutputType.SUCCESS
|
439
|
+
)
|
440
|
+
else:
|
441
|
+
PrettyOutput.print(
|
442
|
+
"无法从 .jarvis/saved_session.json 恢复会话。", OutputType.WARNING
|
443
|
+
)
|
444
|
+
|
431
445
|
if args.requirement:
|
432
446
|
agent.run(args.requirement)
|
433
447
|
else:
|
jarvis/jarvis_platform/ai8.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
import os
|
2
|
-
from typing import Generator, List, Tuple
|
2
|
+
from typing import Any, Dict, Generator, List, Tuple
|
3
|
+
|
3
4
|
from jarvis.jarvis_platform.base import BasePlatform
|
4
5
|
import json
|
5
6
|
|
@@ -11,7 +12,6 @@ from jarvis.jarvis_utils.utils import while_success
|
|
11
12
|
class AI8Model(BasePlatform):
|
12
13
|
"""AI8 model implementation"""
|
13
14
|
|
14
|
-
platform_name = "ai8"
|
15
15
|
BASE_URL = "https://ai8.rcouyi.com"
|
16
16
|
|
17
17
|
def get_model_list(self) -> List[Tuple[str, str]]:
|
@@ -57,7 +57,6 @@ class AI8Model(BasePlatform):
|
|
57
57
|
def create_conversation(self) -> bool:
|
58
58
|
"""Create a new conversation"""
|
59
59
|
try:
|
60
|
-
|
61
60
|
# 1. 创建会话
|
62
61
|
response = while_success(
|
63
62
|
lambda: http.post(
|
@@ -117,13 +116,12 @@ class AI8Model(BasePlatform):
|
|
117
116
|
def chat(self, message: str) -> Generator[str, None, None]:
|
118
117
|
"""Execute conversation"""
|
119
118
|
try:
|
120
|
-
|
121
119
|
# 确保有会话ID
|
122
120
|
if not self.conversation:
|
123
121
|
if not self.create_conversation():
|
124
122
|
raise Exception("Failed to create conversation")
|
125
123
|
|
126
|
-
payload = {
|
124
|
+
payload: Dict[str, Any] = {
|
127
125
|
"text": message,
|
128
126
|
"sessionId": self.conversation["id"] if self.conversation else None,
|
129
127
|
"files": [],
|
@@ -168,6 +166,11 @@ class AI8Model(BasePlatform):
|
|
168
166
|
"""Return model name"""
|
169
167
|
return self.model_name
|
170
168
|
|
169
|
+
@classmethod
|
170
|
+
def platform_name(cls) -> str:
|
171
|
+
"""Return platform name"""
|
172
|
+
return "ai8"
|
173
|
+
|
171
174
|
def delete_chat(self) -> bool:
|
172
175
|
"""Delete current chat session"""
|
173
176
|
try:
|
@@ -184,7 +187,7 @@ class AI8Model(BasePlatform):
|
|
184
187
|
|
185
188
|
data = response.json()
|
186
189
|
if data["code"] == 0:
|
187
|
-
self.conversation =
|
190
|
+
self.conversation = {}
|
188
191
|
return True
|
189
192
|
else:
|
190
193
|
error_msg = f"删除会话失败: {data.get('msg', '未知错误')}"
|
@@ -195,6 +198,55 @@ class AI8Model(BasePlatform):
|
|
195
198
|
PrettyOutput.print(f"删除会话失败: {str(e)}", OutputType.ERROR)
|
196
199
|
return False
|
197
200
|
|
201
|
+
def save(self, file_path: str) -> bool:
|
202
|
+
"""Save chat session to a file."""
|
203
|
+
if not self.conversation:
|
204
|
+
PrettyOutput.print("没有活动的会话可供保存", OutputType.WARNING)
|
205
|
+
return False
|
206
|
+
|
207
|
+
state = {
|
208
|
+
"conversation": self.conversation,
|
209
|
+
"model_name": self.model_name,
|
210
|
+
"system_prompt": self.system_prompt,
|
211
|
+
}
|
212
|
+
|
213
|
+
try:
|
214
|
+
with open(file_path, "w", encoding="utf-8") as f:
|
215
|
+
json.dump(state, f, ensure_ascii=False, indent=4)
|
216
|
+
self._saved = True
|
217
|
+
PrettyOutput.print(f"会话已成功保存到 {file_path}", OutputType.SUCCESS)
|
218
|
+
return True
|
219
|
+
except Exception as e:
|
220
|
+
PrettyOutput.print(f"保存会话失败: {str(e)}", OutputType.ERROR)
|
221
|
+
return False
|
222
|
+
|
223
|
+
def restore(self, file_path: str) -> bool:
|
224
|
+
"""Restore chat session from a file."""
|
225
|
+
try:
|
226
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
227
|
+
state = json.load(f)
|
228
|
+
|
229
|
+
self.conversation = state["conversation"]
|
230
|
+
self.model_name = state["model_name"]
|
231
|
+
self.system_prompt = state.get("system_prompt", "")
|
232
|
+
|
233
|
+
# A restored session should not be deleted on exit, as it's persistent.
|
234
|
+
self._saved = True
|
235
|
+
|
236
|
+
PrettyOutput.print(f"从 {file_path} 成功恢复会话", OutputType.SUCCESS)
|
237
|
+
return True
|
238
|
+
except FileNotFoundError:
|
239
|
+
PrettyOutput.print(f"会话文件未找到: {file_path}", OutputType.ERROR)
|
240
|
+
return False
|
241
|
+
except KeyError as e:
|
242
|
+
PrettyOutput.print(
|
243
|
+
f"恢复失败: 会话文件格式不正确,缺少键 {e}", OutputType.ERROR
|
244
|
+
)
|
245
|
+
return False
|
246
|
+
except Exception as e:
|
247
|
+
PrettyOutput.print(f"恢复会话失败: {str(e)}", OutputType.ERROR)
|
248
|
+
return False
|
249
|
+
|
198
250
|
def get_available_models(self) -> List[str]:
|
199
251
|
"""Get available model list
|
200
252
|
|
jarvis/jarvis_platform/base.py
CHANGED
@@ -27,10 +27,12 @@ class BasePlatform(ABC):
|
|
27
27
|
"""Initialize model"""
|
28
28
|
self.suppress_output = True # 添加输出控制标志
|
29
29
|
self.web = False # 添加web属性,默认false
|
30
|
+
self._saved = False
|
30
31
|
|
31
32
|
def __del__(self):
|
32
33
|
"""Destroy model"""
|
33
|
-
self.
|
34
|
+
if not self._saved:
|
35
|
+
self.delete_chat()
|
34
36
|
|
35
37
|
@abstractmethod
|
36
38
|
def set_model_name(self, model_name: str):
|
@@ -178,11 +180,45 @@ class BasePlatform(ABC):
|
|
178
180
|
"""Model name"""
|
179
181
|
raise NotImplementedError("name is not implemented")
|
180
182
|
|
183
|
+
@classmethod
|
184
|
+
@abstractmethod
|
185
|
+
def platform_name(cls) -> str:
|
186
|
+
"""Platform name"""
|
187
|
+
raise NotImplementedError("platform_name is not implemented")
|
188
|
+
|
181
189
|
@abstractmethod
|
182
190
|
def delete_chat(self) -> bool:
|
183
191
|
"""Delete chat"""
|
184
192
|
raise NotImplementedError("delete_chat is not implemented")
|
185
193
|
|
194
|
+
@abstractmethod
|
195
|
+
def save(self, file_path: str) -> bool:
|
196
|
+
"""Save chat session to a file.
|
197
|
+
|
198
|
+
Note:
|
199
|
+
Implementations of this method should set `self._saved = True` upon successful saving
|
200
|
+
to prevent the session from being deleted on object destruction.
|
201
|
+
|
202
|
+
Args:
|
203
|
+
file_path: The path to save the session file.
|
204
|
+
|
205
|
+
Returns:
|
206
|
+
True if saving is successful, False otherwise.
|
207
|
+
"""
|
208
|
+
raise NotImplementedError("save is not implemented")
|
209
|
+
|
210
|
+
@abstractmethod
|
211
|
+
def restore(self, file_path: str) -> bool:
|
212
|
+
"""Restore chat session from a file.
|
213
|
+
|
214
|
+
Args:
|
215
|
+
file_path: The path to restore the session file from.
|
216
|
+
|
217
|
+
Returns:
|
218
|
+
True if restoring is successful, False otherwise.
|
219
|
+
"""
|
220
|
+
raise NotImplementedError("restore is not implemented")
|
221
|
+
|
186
222
|
@abstractmethod
|
187
223
|
def set_system_prompt(self, message: str):
|
188
224
|
"""Set system message"""
|
jarvis/jarvis_platform/human.py
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
|
5
5
|
# 提供与真实人类交互的模拟接口
|
6
6
|
|
7
|
+
import json
|
7
8
|
import random
|
8
9
|
import string
|
9
10
|
from typing import Generator, List, Tuple
|
@@ -16,8 +17,6 @@ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
16
17
|
class HumanPlatform(BasePlatform):
|
17
18
|
"""人类交互平台实现,模拟大模型但实际上与人交互"""
|
18
19
|
|
19
|
-
platform_name = "human"
|
20
|
-
|
21
20
|
def get_model_list(self) -> List[Tuple[str, str]]:
|
22
21
|
"""获取支持的模型列表"""
|
23
22
|
return [("human", "Human Interaction")]
|
@@ -59,8 +58,9 @@ class HumanPlatform(BasePlatform):
|
|
59
58
|
|
60
59
|
# 将prompt复制到剪贴板
|
61
60
|
import subprocess
|
61
|
+
|
62
62
|
try:
|
63
|
-
subprocess.run([
|
63
|
+
subprocess.run(["xsel", "-ib"], input=prompt.encode("utf-8"), check=True)
|
64
64
|
PrettyOutput.print("提示已复制到剪贴板", OutputType.INFO)
|
65
65
|
except subprocess.CalledProcessError as e:
|
66
66
|
PrettyOutput.print(f"无法复制到剪贴板: {e}", OutputType.WARNING)
|
@@ -80,10 +80,55 @@ class HumanPlatform(BasePlatform):
|
|
80
80
|
self.first_message = True
|
81
81
|
return True
|
82
82
|
|
83
|
+
def save(self, file_path: str) -> bool:
|
84
|
+
"""Save chat session to a file."""
|
85
|
+
state = {
|
86
|
+
"conversation_id": self.conversation_id,
|
87
|
+
"model_name": self.model_name,
|
88
|
+
"system_message": self.system_message,
|
89
|
+
"first_message": self.first_message,
|
90
|
+
}
|
91
|
+
|
92
|
+
try:
|
93
|
+
with open(file_path, "w", encoding="utf-8") as f:
|
94
|
+
json.dump(state, f, ensure_ascii=False, indent=4)
|
95
|
+
self._saved = True
|
96
|
+
PrettyOutput.print(f"会话已成功保存到 {file_path}", OutputType.SUCCESS)
|
97
|
+
return True
|
98
|
+
except Exception as e:
|
99
|
+
PrettyOutput.print(f"保存会话失败: {str(e)}", OutputType.ERROR)
|
100
|
+
return False
|
101
|
+
|
102
|
+
def restore(self, file_path: str) -> bool:
|
103
|
+
"""Restore chat session from a file."""
|
104
|
+
try:
|
105
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
106
|
+
state = json.load(f)
|
107
|
+
|
108
|
+
self.conversation_id = state.get("conversation_id", "")
|
109
|
+
self.model_name = state.get("model_name", "human")
|
110
|
+
self.system_message = state.get("system_message", "")
|
111
|
+
self.first_message = state.get("first_message", True)
|
112
|
+
self._saved = True
|
113
|
+
|
114
|
+
PrettyOutput.print(f"从 {file_path} 成功恢复会话", OutputType.SUCCESS)
|
115
|
+
return True
|
116
|
+
except FileNotFoundError:
|
117
|
+
PrettyOutput.print(f"会话文件未找到: {file_path}", OutputType.ERROR)
|
118
|
+
return False
|
119
|
+
except Exception as e:
|
120
|
+
PrettyOutput.print(f"恢复会话失败: {str(e)}", OutputType.ERROR)
|
121
|
+
return False
|
122
|
+
|
83
123
|
def name(self) -> str:
|
84
124
|
"""平台名称"""
|
85
125
|
return self.model_name
|
86
126
|
|
127
|
+
@classmethod
|
128
|
+
def platform_name(cls) -> str:
|
129
|
+
"""平台名称"""
|
130
|
+
return "human"
|
131
|
+
|
87
132
|
def support_web(self) -> bool:
|
88
133
|
"""是否支持网页浏览功能"""
|
89
134
|
return False
|
jarvis/jarvis_platform/kimi.py
CHANGED
@@ -21,8 +21,6 @@ class KimiModel(BasePlatform):
|
|
21
21
|
- 消息收发
|
22
22
|
"""
|
23
23
|
|
24
|
-
platform_name = "kimi"
|
25
|
-
|
26
24
|
def get_model_list(self) -> List[Tuple[str, str]]:
|
27
25
|
"""Get model list"""
|
28
26
|
return [
|
@@ -158,7 +156,7 @@ class KimiModel(BasePlatform):
|
|
158
156
|
)
|
159
157
|
|
160
158
|
response_data = b""
|
161
|
-
|
159
|
+
|
162
160
|
# 处理流式响应
|
163
161
|
for chunk in response_stream:
|
164
162
|
response_data += chunk
|
@@ -298,9 +296,9 @@ class KimiModel(BasePlatform):
|
|
298
296
|
lambda: http.stream_post(url, headers=headers, json=payload),
|
299
297
|
sleep_time=5,
|
300
298
|
)
|
301
|
-
|
299
|
+
|
302
300
|
response_data = b""
|
303
|
-
|
301
|
+
|
304
302
|
# 处理流式响应
|
305
303
|
for chunk in response_stream:
|
306
304
|
response_data += chunk
|
@@ -367,10 +365,61 @@ class KimiModel(BasePlatform):
|
|
367
365
|
PrettyOutput.print(f"删除会话时发生错误: {str(e)}", OutputType.ERROR)
|
368
366
|
return False
|
369
367
|
|
368
|
+
def save(self, file_path: str) -> bool:
|
369
|
+
"""Save chat session to a file."""
|
370
|
+
if not self.chat_id:
|
371
|
+
PrettyOutput.print("没有活动的会话可供保存", OutputType.WARNING)
|
372
|
+
return False
|
373
|
+
|
374
|
+
state = {
|
375
|
+
"chat_id": self.chat_id,
|
376
|
+
"model_name": self.model_name,
|
377
|
+
"system_message": self.system_message,
|
378
|
+
"first_chat": self.first_chat,
|
379
|
+
"uploaded_files": self.uploaded_files,
|
380
|
+
}
|
381
|
+
|
382
|
+
try:
|
383
|
+
with open(file_path, "w", encoding="utf-8") as f:
|
384
|
+
json.dump(state, f, ensure_ascii=False, indent=4)
|
385
|
+
self._saved = True
|
386
|
+
PrettyOutput.print(f"会话已成功保存到 {file_path}", OutputType.SUCCESS)
|
387
|
+
return True
|
388
|
+
except Exception as e:
|
389
|
+
PrettyOutput.print(f"保存会话失败: {str(e)}", OutputType.ERROR)
|
390
|
+
return False
|
391
|
+
|
392
|
+
def restore(self, file_path: str) -> bool:
|
393
|
+
"""Restore chat session from a file."""
|
394
|
+
try:
|
395
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
396
|
+
state = json.load(f)
|
397
|
+
|
398
|
+
self.chat_id = state.get("chat_id", "")
|
399
|
+
self.model_name = state.get("model_name", "kimi")
|
400
|
+
self.system_message = state.get("system_message", "")
|
401
|
+
self.first_chat = state.get("first_chat", True)
|
402
|
+
self.uploaded_files = state.get("uploaded_files", [])
|
403
|
+
self._saved = True
|
404
|
+
|
405
|
+
PrettyOutput.print(f"从 {file_path} 成功恢复会话", OutputType.SUCCESS)
|
406
|
+
return True
|
407
|
+
except FileNotFoundError:
|
408
|
+
PrettyOutput.print(f"会话文件未找到: {file_path}", OutputType.ERROR)
|
409
|
+
return False
|
410
|
+
except Exception as e:
|
411
|
+
PrettyOutput.print(f"恢复会话失败: {str(e)}", OutputType.ERROR)
|
412
|
+
return False
|
413
|
+
|
370
414
|
def name(self) -> str:
|
371
415
|
"""Model name"""
|
372
416
|
return self.model_name
|
373
417
|
|
418
|
+
@classmethod
|
419
|
+
def platform_name(cls) -> str:
|
420
|
+
"""Platform name"""
|
421
|
+
return "kimi"
|
422
|
+
|
374
423
|
def support_web(self) -> bool:
|
375
424
|
"""Kimi平台支持web功能"""
|
376
425
|
return True
|