AstrBot 4.3.2__py3-none-any.whl → 4.3.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.
- astrbot/core/config/default.py +19 -7
- astrbot/core/db/sqlite.py +7 -0
- astrbot/core/pipeline/context_utils.py +1 -0
- astrbot/core/pipeline/result_decorate/stage.py +44 -45
- astrbot/core/provider/provider.py +2 -1
- astrbot/core/provider/sources/anthropic_source.py +13 -7
- astrbot/core/provider/sources/dashscope_tts.py +120 -12
- astrbot/core/provider/sources/gemini_source.py +21 -17
- astrbot/core/provider/sources/openai_source.py +1 -1
- astrbot/dashboard/routes/session_management.py +6 -6
- astrbot/dashboard/routes/update.py +8 -5
- {astrbot-4.3.2.dist-info → astrbot-4.3.3.dist-info}/METADATA +1 -1
- {astrbot-4.3.2.dist-info → astrbot-4.3.3.dist-info}/RECORD +16 -16
- {astrbot-4.3.2.dist-info → astrbot-4.3.3.dist-info}/WHEEL +0 -0
- {astrbot-4.3.2.dist-info → astrbot-4.3.3.dist-info}/entry_points.txt +0 -0
- {astrbot-4.3.2.dist-info → astrbot-4.3.3.dist-info}/licenses/LICENSE +0 -0
astrbot/core/config/default.py
CHANGED
|
@@ -6,7 +6,7 @@ import os
|
|
|
6
6
|
|
|
7
7
|
from astrbot.core.utils.astrbot_path import get_astrbot_data_path
|
|
8
8
|
|
|
9
|
-
VERSION = "4.3.
|
|
9
|
+
VERSION = "4.3.3"
|
|
10
10
|
DB_PATH = os.path.join(get_astrbot_data_path(), "data_v4.db")
|
|
11
11
|
|
|
12
12
|
# 默认配置
|
|
@@ -775,7 +775,7 @@ CONFIG_METADATA_2 = {
|
|
|
775
775
|
"timeout": 120,
|
|
776
776
|
"model_config": {"model": "deepseek-chat", "temperature": 0.4},
|
|
777
777
|
"custom_extra_body": {},
|
|
778
|
-
"modalities": ["text", "
|
|
778
|
+
"modalities": ["text", "tool_use"],
|
|
779
779
|
},
|
|
780
780
|
"302.AI": {
|
|
781
781
|
"id": "302ai",
|
|
@@ -821,6 +821,21 @@ CONFIG_METADATA_2 = {
|
|
|
821
821
|
},
|
|
822
822
|
"custom_extra_body": {},
|
|
823
823
|
},
|
|
824
|
+
"小马算力": {
|
|
825
|
+
"id": "tokenpony",
|
|
826
|
+
"provider": "tokenpony",
|
|
827
|
+
"type": "openai_chat_completion",
|
|
828
|
+
"provider_type": "chat_completion",
|
|
829
|
+
"enable": True,
|
|
830
|
+
"key": [],
|
|
831
|
+
"api_base": "https://api.tokenpony.cn/v1",
|
|
832
|
+
"timeout": 120,
|
|
833
|
+
"model_config": {
|
|
834
|
+
"model": "kimi-k2-instruct-0905",
|
|
835
|
+
"temperature": 0.7,
|
|
836
|
+
},
|
|
837
|
+
"custom_extra_body": {},
|
|
838
|
+
},
|
|
824
839
|
"优云智算": {
|
|
825
840
|
"id": "compshare",
|
|
826
841
|
"provider": "compshare",
|
|
@@ -1041,6 +1056,7 @@ CONFIG_METADATA_2 = {
|
|
|
1041
1056
|
"timeout": "20",
|
|
1042
1057
|
},
|
|
1043
1058
|
"阿里云百炼 TTS(API)": {
|
|
1059
|
+
"hint": "API Key 从 https://bailian.console.aliyun.com/?tab=model#/api-key 获取。模型和音色的选择文档请参考: 阿里云百炼语音合成音色名称。具体可参考 https://help.aliyun.com/zh/model-studio/speech-synthesis-and-speech-recognition",
|
|
1044
1060
|
"id": "dashscope_tts",
|
|
1045
1061
|
"provider": "dashscope",
|
|
1046
1062
|
"type": "dashscope_tts",
|
|
@@ -1420,11 +1436,7 @@ CONFIG_METADATA_2 = {
|
|
|
1420
1436
|
"description": "服务订阅密钥",
|
|
1421
1437
|
"hint": "Azure_TTS 服务的订阅密钥(注意不是令牌)",
|
|
1422
1438
|
},
|
|
1423
|
-
"dashscope_tts_voice": {
|
|
1424
|
-
"description": "语音合成模型",
|
|
1425
|
-
"type": "string",
|
|
1426
|
-
"hint": "阿里云百炼语音合成模型名称。具体可参考 https://help.aliyun.com/zh/model-studio/developer-reference/cosyvoice-python-api 等内容",
|
|
1427
|
-
},
|
|
1439
|
+
"dashscope_tts_voice": {"description": "音色", "type": "string"},
|
|
1428
1440
|
"gm_resp_image_modal": {
|
|
1429
1441
|
"description": "启用图片模态",
|
|
1430
1442
|
"type": "bool",
|
astrbot/core/db/sqlite.py
CHANGED
|
@@ -32,6 +32,12 @@ class SQLiteDatabase(BaseDatabase):
|
|
|
32
32
|
"""Initialize the database by creating tables if they do not exist."""
|
|
33
33
|
async with self.engine.begin() as conn:
|
|
34
34
|
await conn.run_sync(SQLModel.metadata.create_all)
|
|
35
|
+
await conn.execute(text("PRAGMA journal_mode=WAL"))
|
|
36
|
+
await conn.execute(text("PRAGMA synchronous=NORMAL"))
|
|
37
|
+
await conn.execute(text("PRAGMA cache_size=20000"))
|
|
38
|
+
await conn.execute(text("PRAGMA temp_store=MEMORY"))
|
|
39
|
+
await conn.execute(text("PRAGMA mmap_size=134217728"))
|
|
40
|
+
await conn.execute(text("PRAGMA optimize"))
|
|
35
41
|
await conn.commit()
|
|
36
42
|
|
|
37
43
|
# ====
|
|
@@ -160,6 +166,7 @@ class SQLiteDatabase(BaseDatabase):
|
|
|
160
166
|
col(ConversationV2.title).ilike(f"%{search_query}%"),
|
|
161
167
|
col(ConversationV2.content).ilike(f"%{search_query}%"),
|
|
162
168
|
col(ConversationV2.user_id).ilike(f"%{search_query}%"),
|
|
169
|
+
col(ConversationV2.conversation_id).ilike(f"%{search_query}%"),
|
|
163
170
|
)
|
|
164
171
|
)
|
|
165
172
|
if "message_types" in kwargs and len(kwargs["message_types"]) > 0:
|
|
@@ -189,54 +189,54 @@ class ResultDecorateStage(Stage):
|
|
|
189
189
|
logger.warning(
|
|
190
190
|
f"会话 {event.unified_msg_origin} 未配置文本转语音模型。"
|
|
191
191
|
)
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
192
|
+
else:
|
|
193
|
+
new_chain = []
|
|
194
|
+
for comp in result.chain:
|
|
195
|
+
if isinstance(comp, Plain) and len(comp.text) > 1:
|
|
196
|
+
try:
|
|
197
|
+
logger.info(f"TTS 请求: {comp.text}")
|
|
198
|
+
audio_path = await tts_provider.get_audio(comp.text)
|
|
199
|
+
logger.info(f"TTS 结果: {audio_path}")
|
|
200
|
+
if not audio_path:
|
|
201
|
+
logger.error(
|
|
202
|
+
f"由于 TTS 音频文件未找到,消息段转语音失败: {comp.text}"
|
|
203
|
+
)
|
|
204
|
+
new_chain.append(comp)
|
|
205
|
+
continue
|
|
206
206
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
207
|
+
use_file_service = self.ctx.astrbot_config[
|
|
208
|
+
"provider_tts_settings"
|
|
209
|
+
]["use_file_service"]
|
|
210
|
+
callback_api_base = self.ctx.astrbot_config[
|
|
211
|
+
"callback_api_base"
|
|
212
|
+
]
|
|
213
|
+
dual_output = self.ctx.astrbot_config[
|
|
214
|
+
"provider_tts_settings"
|
|
215
|
+
]["dual_output"]
|
|
216
216
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
217
|
+
url = None
|
|
218
|
+
if use_file_service and callback_api_base:
|
|
219
|
+
token = await file_token_service.register_file(
|
|
220
|
+
audio_path
|
|
221
|
+
)
|
|
222
|
+
url = f"{callback_api_base}/api/file/{token}"
|
|
223
|
+
logger.debug(f"已注册:{url}")
|
|
224
224
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
225
|
+
new_chain.append(
|
|
226
|
+
Record(
|
|
227
|
+
file=url or audio_path,
|
|
228
|
+
url=url or audio_path,
|
|
229
|
+
)
|
|
229
230
|
)
|
|
230
|
-
|
|
231
|
-
|
|
231
|
+
if dual_output:
|
|
232
|
+
new_chain.append(comp)
|
|
233
|
+
except Exception:
|
|
234
|
+
logger.error(traceback.format_exc())
|
|
235
|
+
logger.error("TTS 失败,使用文本发送。")
|
|
232
236
|
new_chain.append(comp)
|
|
233
|
-
|
|
234
|
-
logger.error(traceback.format_exc())
|
|
235
|
-
logger.error("TTS 失败,使用文本发送。")
|
|
237
|
+
else:
|
|
236
238
|
new_chain.append(comp)
|
|
237
|
-
|
|
238
|
-
new_chain.append(comp)
|
|
239
|
-
result.chain = new_chain
|
|
239
|
+
result.chain = new_chain
|
|
240
240
|
|
|
241
241
|
# 文本转图片
|
|
242
242
|
elif (
|
|
@@ -279,7 +279,6 @@ class ResultDecorateStage(Stage):
|
|
|
279
279
|
result.chain = [Image.fromFileSystem(url)]
|
|
280
280
|
|
|
281
281
|
# 触发转发消息
|
|
282
|
-
has_forwarded = False
|
|
283
282
|
if event.get_platform_name() == "aiocqhttp":
|
|
284
283
|
word_cnt = 0
|
|
285
284
|
for comp in result.chain:
|
|
@@ -290,9 +289,9 @@ class ResultDecorateStage(Stage):
|
|
|
290
289
|
uin=event.get_self_id(), name="AstrBot", content=[*result.chain]
|
|
291
290
|
)
|
|
292
291
|
result.chain = [node]
|
|
293
|
-
has_forwarded = True
|
|
294
292
|
|
|
295
|
-
|
|
293
|
+
has_plain = any(isinstance(item, Plain) for item in result.chain)
|
|
294
|
+
if has_plain:
|
|
296
295
|
# at 回复
|
|
297
296
|
if (
|
|
298
297
|
self.reply_with_mention
|
|
@@ -68,7 +68,8 @@ class Provider(AbstractProvider):
|
|
|
68
68
|
|
|
69
69
|
def get_keys(self) -> List[str]:
|
|
70
70
|
"""获得提供商 Key"""
|
|
71
|
-
|
|
71
|
+
keys = self.provider_config.get("key", [""])
|
|
72
|
+
return keys or [""]
|
|
72
73
|
|
|
73
74
|
@abc.abstractmethod
|
|
74
75
|
def set_key(self, key: str):
|
|
@@ -33,7 +33,7 @@ class ProviderAnthropic(Provider):
|
|
|
33
33
|
)
|
|
34
34
|
|
|
35
35
|
self.chosen_api_key: str = ""
|
|
36
|
-
self.api_keys: List =
|
|
36
|
+
self.api_keys: List = super().get_keys()
|
|
37
37
|
self.chosen_api_key = self.api_keys[0] if len(self.api_keys) > 0 else ""
|
|
38
38
|
self.base_url = provider_config.get("api_base", "https://api.anthropic.com")
|
|
39
39
|
self.timeout = provider_config.get("timeout", 120)
|
|
@@ -70,9 +70,13 @@ class ProviderAnthropic(Provider):
|
|
|
70
70
|
{
|
|
71
71
|
"type": "tool_use",
|
|
72
72
|
"name": tool_call["function"]["name"],
|
|
73
|
-
"input":
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
"input": (
|
|
74
|
+
json.loads(tool_call["function"]["arguments"])
|
|
75
|
+
if isinstance(
|
|
76
|
+
tool_call["function"]["arguments"], str
|
|
77
|
+
)
|
|
78
|
+
else tool_call["function"]["arguments"]
|
|
79
|
+
),
|
|
76
80
|
"id": tool_call["id"],
|
|
77
81
|
}
|
|
78
82
|
)
|
|
@@ -355,9 +359,11 @@ class ProviderAnthropic(Provider):
|
|
|
355
359
|
"source": {
|
|
356
360
|
"type": "base64",
|
|
357
361
|
"media_type": mime_type,
|
|
358
|
-
"data":
|
|
359
|
-
|
|
360
|
-
|
|
362
|
+
"data": (
|
|
363
|
+
image_data.split("base64,")[1]
|
|
364
|
+
if "base64," in image_data
|
|
365
|
+
else image_data
|
|
366
|
+
),
|
|
361
367
|
},
|
|
362
368
|
}
|
|
363
369
|
)
|
|
@@ -1,10 +1,22 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import base64
|
|
3
|
+
import logging
|
|
1
4
|
import os
|
|
2
|
-
import dashscope
|
|
3
5
|
import uuid
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
from typing import Optional, Tuple
|
|
7
|
+
import aiohttp
|
|
8
|
+
import dashscope
|
|
9
|
+
from dashscope.audio.tts_v2 import AudioFormat, SpeechSynthesizer
|
|
10
|
+
|
|
11
|
+
try:
|
|
12
|
+
from dashscope.aigc.multimodal_conversation import MultiModalConversation
|
|
13
|
+
except (
|
|
14
|
+
ImportError
|
|
15
|
+
): # pragma: no cover - older dashscope versions without Qwen TTS support
|
|
16
|
+
MultiModalConversation = None
|
|
17
|
+
|
|
7
18
|
from ..entities import ProviderType
|
|
19
|
+
from ..provider import TTSProvider
|
|
8
20
|
from ..register import register_provider_adapter
|
|
9
21
|
from astrbot.core.utils.astrbot_path import get_astrbot_data_path
|
|
10
22
|
|
|
@@ -26,16 +38,112 @@ class ProviderDashscopeTTSAPI(TTSProvider):
|
|
|
26
38
|
dashscope.api_key = self.chosen_api_key
|
|
27
39
|
|
|
28
40
|
async def get_audio(self, text: str) -> str:
|
|
41
|
+
model = self.get_model()
|
|
42
|
+
if not model:
|
|
43
|
+
raise RuntimeError("Dashscope TTS model is not configured.")
|
|
44
|
+
|
|
29
45
|
temp_dir = os.path.join(get_astrbot_data_path(), "temp")
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
46
|
+
os.makedirs(temp_dir, exist_ok=True)
|
|
47
|
+
|
|
48
|
+
if self._is_qwen_tts_model(model):
|
|
49
|
+
audio_bytes, ext = await self._synthesize_with_qwen_tts(model, text)
|
|
50
|
+
else:
|
|
51
|
+
audio_bytes, ext = await self._synthesize_with_cosyvoice(model, text)
|
|
52
|
+
|
|
53
|
+
if not audio_bytes:
|
|
54
|
+
raise RuntimeError(
|
|
55
|
+
"Audio synthesis failed, returned empty content. The model may not be supported or the service is unavailable."
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
path = os.path.join(temp_dir, f"dashscope_tts_{uuid.uuid4()}{ext}")
|
|
59
|
+
with open(path, "wb") as f:
|
|
60
|
+
f.write(audio_bytes)
|
|
61
|
+
return path
|
|
62
|
+
|
|
63
|
+
def _call_qwen_tts(self, model: str, text: str):
|
|
64
|
+
if MultiModalConversation is None:
|
|
65
|
+
raise RuntimeError(
|
|
66
|
+
"dashscope SDK missing MultiModalConversation. Please upgrade the dashscope package to use Qwen TTS models."
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
kwargs = {
|
|
70
|
+
"model": model,
|
|
71
|
+
"text": text,
|
|
72
|
+
"api_key": self.chosen_api_key,
|
|
73
|
+
"voice": self.voice or "Cherry",
|
|
74
|
+
}
|
|
75
|
+
if not self.voice:
|
|
76
|
+
logging.warning(
|
|
77
|
+
"No voice specified for Qwen TTS model, using default 'Cherry'."
|
|
78
|
+
)
|
|
79
|
+
return MultiModalConversation.call(**kwargs)
|
|
80
|
+
|
|
81
|
+
async def _synthesize_with_qwen_tts(
|
|
82
|
+
self, model: str, text: str
|
|
83
|
+
) -> Tuple[Optional[bytes], str]:
|
|
84
|
+
loop = asyncio.get_event_loop()
|
|
85
|
+
response = await loop.run_in_executor(None, self._call_qwen_tts, model, text)
|
|
86
|
+
audio_bytes = await self._extract_audio_from_response(response)
|
|
87
|
+
if not audio_bytes:
|
|
88
|
+
raise RuntimeError(
|
|
89
|
+
f"Audio synthesis failed for model '{model}'. {response}"
|
|
90
|
+
)
|
|
91
|
+
ext = ".wav"
|
|
92
|
+
return audio_bytes, ext
|
|
93
|
+
|
|
94
|
+
async def _extract_audio_from_response(self, response) -> Optional[bytes]:
|
|
95
|
+
output = getattr(response, "output", None)
|
|
96
|
+
audio_obj = getattr(output, "audio", None) if output is not None else None
|
|
97
|
+
if not audio_obj:
|
|
98
|
+
return None
|
|
99
|
+
|
|
100
|
+
data_b64 = getattr(audio_obj, "data", None)
|
|
101
|
+
if data_b64:
|
|
102
|
+
try:
|
|
103
|
+
return base64.b64decode(data_b64)
|
|
104
|
+
except (ValueError, TypeError):
|
|
105
|
+
logging.error("Failed to decode base64 audio data.")
|
|
106
|
+
return None
|
|
107
|
+
|
|
108
|
+
url = getattr(audio_obj, "url", None)
|
|
109
|
+
if url:
|
|
110
|
+
return await self._download_audio_from_url(url)
|
|
111
|
+
return None
|
|
112
|
+
|
|
113
|
+
async def _download_audio_from_url(self, url: str) -> Optional[bytes]:
|
|
114
|
+
if not url:
|
|
115
|
+
return None
|
|
116
|
+
timeout = max(self.timeout_ms / 1000, 1) if self.timeout_ms else 20
|
|
117
|
+
try:
|
|
118
|
+
async with aiohttp.ClientSession() as session:
|
|
119
|
+
async with session.get(
|
|
120
|
+
url, timeout=aiohttp.ClientTimeout(total=timeout)
|
|
121
|
+
) as response:
|
|
122
|
+
return await response.read()
|
|
123
|
+
except (aiohttp.ClientError, asyncio.TimeoutError, OSError) as e:
|
|
124
|
+
logging.error(f"Failed to download audio from URL {url}: {e}")
|
|
125
|
+
return None
|
|
126
|
+
|
|
127
|
+
async def _synthesize_with_cosyvoice(
|
|
128
|
+
self, model: str, text: str
|
|
129
|
+
) -> Tuple[Optional[bytes], str]:
|
|
130
|
+
synthesizer = SpeechSynthesizer(
|
|
131
|
+
model=model,
|
|
33
132
|
voice=self.voice,
|
|
34
133
|
format=AudioFormat.WAV_24000HZ_MONO_16BIT,
|
|
35
134
|
)
|
|
36
|
-
|
|
37
|
-
|
|
135
|
+
loop = asyncio.get_event_loop()
|
|
136
|
+
audio_bytes = await loop.run_in_executor(
|
|
137
|
+
None, synthesizer.call, text, self.timeout_ms
|
|
38
138
|
)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
139
|
+
if not audio_bytes:
|
|
140
|
+
resp = synthesizer.get_response()
|
|
141
|
+
if resp and isinstance(resp, dict):
|
|
142
|
+
raise RuntimeError(
|
|
143
|
+
f"Audio synthesis failed for model '{model}'. {resp}".strip()
|
|
144
|
+
)
|
|
145
|
+
return audio_bytes, ".wav"
|
|
146
|
+
|
|
147
|
+
def _is_qwen_tts_model(self, model: str) -> bool:
|
|
148
|
+
model_lower = model.lower()
|
|
149
|
+
return "tts" in model_lower and model_lower.startswith("qwen")
|
|
@@ -3,7 +3,7 @@ import base64
|
|
|
3
3
|
import json
|
|
4
4
|
import logging
|
|
5
5
|
import random
|
|
6
|
-
from typing import Optional
|
|
6
|
+
from typing import Optional, List
|
|
7
7
|
from collections.abc import AsyncGenerator
|
|
8
8
|
|
|
9
9
|
from google import genai
|
|
@@ -60,7 +60,7 @@ class ProviderGoogleGenAI(Provider):
|
|
|
60
60
|
provider_settings,
|
|
61
61
|
default_persona,
|
|
62
62
|
)
|
|
63
|
-
self.api_keys:
|
|
63
|
+
self.api_keys: List = super().get_keys()
|
|
64
64
|
self.chosen_api_key: str = self.api_keys[0] if len(self.api_keys) > 0 else ""
|
|
65
65
|
self.timeout: int = int(provider_config.get("timeout", 180))
|
|
66
66
|
|
|
@@ -218,19 +218,21 @@ class ProviderGoogleGenAI(Provider):
|
|
|
218
218
|
response_modalities=modalities,
|
|
219
219
|
tools=tool_list,
|
|
220
220
|
safety_settings=self.safety_settings if self.safety_settings else None,
|
|
221
|
-
thinking_config=
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
"
|
|
226
|
-
|
|
221
|
+
thinking_config=(
|
|
222
|
+
types.ThinkingConfig(
|
|
223
|
+
thinking_budget=min(
|
|
224
|
+
int(
|
|
225
|
+
self.provider_config.get("gm_thinking_config", {}).get(
|
|
226
|
+
"budget", 0
|
|
227
|
+
)
|
|
228
|
+
),
|
|
229
|
+
24576,
|
|
227
230
|
),
|
|
228
|
-
|
|
229
|
-
)
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
else None,
|
|
231
|
+
)
|
|
232
|
+
if "gemini-2.5-flash" in self.get_model()
|
|
233
|
+
and hasattr(types.ThinkingConfig, "thinking_budget")
|
|
234
|
+
else None
|
|
235
|
+
),
|
|
234
236
|
automatic_function_calling=types.AutomaticFunctionCallingConfig(
|
|
235
237
|
disable=True
|
|
236
238
|
),
|
|
@@ -274,9 +276,11 @@ class ProviderGoogleGenAI(Provider):
|
|
|
274
276
|
if role == "user":
|
|
275
277
|
if isinstance(content, list):
|
|
276
278
|
parts = [
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
279
|
+
(
|
|
280
|
+
types.Part.from_text(text=item["text"] or " ")
|
|
281
|
+
if item["type"] == "text"
|
|
282
|
+
else process_image_url(item["image_url"])
|
|
283
|
+
)
|
|
280
284
|
for item in content
|
|
281
285
|
]
|
|
282
286
|
else:
|
|
@@ -38,7 +38,7 @@ class ProviderOpenAIOfficial(Provider):
|
|
|
38
38
|
default_persona,
|
|
39
39
|
)
|
|
40
40
|
self.chosen_api_key = None
|
|
41
|
-
self.api_keys: List =
|
|
41
|
+
self.api_keys: List = super().get_keys()
|
|
42
42
|
self.chosen_api_key = self.api_keys[0] if len(self.api_keys) > 0 else None
|
|
43
43
|
self.timeout = provider_config.get("timeout", 120)
|
|
44
44
|
if isinstance(self.timeout, str):
|
|
@@ -65,12 +65,12 @@ class SessionManagementRoute(Route):
|
|
|
65
65
|
persona_name = data["persona_name"]
|
|
66
66
|
|
|
67
67
|
# 处理 persona 显示
|
|
68
|
-
if
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
persona_name =
|
|
68
|
+
if persona_name is None:
|
|
69
|
+
if conv_persona_id is None:
|
|
70
|
+
if default_persona := persona_mgr.selected_default_persona_v3:
|
|
71
|
+
persona_name = default_persona["name"]
|
|
72
|
+
else:
|
|
73
|
+
persona_name = "[%None]"
|
|
74
74
|
|
|
75
75
|
session_info = {
|
|
76
76
|
"session_id": session_id,
|
|
@@ -9,6 +9,8 @@ from astrbot.core.config.default import VERSION
|
|
|
9
9
|
from astrbot.core import DEMO_MODE
|
|
10
10
|
from astrbot.core.db.migration.helper import do_migration_v4, check_migration_needed_v4
|
|
11
11
|
|
|
12
|
+
CLEAR_SITE_DATA_HEADERS = {"Clear-Site-Data": '"cache"'}
|
|
13
|
+
|
|
12
14
|
|
|
13
15
|
class UpdateRoute(Route):
|
|
14
16
|
def __init__(
|
|
@@ -113,17 +115,19 @@ class UpdateRoute(Route):
|
|
|
113
115
|
|
|
114
116
|
if reboot:
|
|
115
117
|
await self.core_lifecycle.restart()
|
|
116
|
-
|
|
118
|
+
ret = (
|
|
117
119
|
Response()
|
|
118
120
|
.ok(None, "更新成功,AstrBot 将在 2 秒内全量重启以应用新的代码。")
|
|
119
121
|
.__dict__
|
|
120
122
|
)
|
|
123
|
+
return ret, 200, CLEAR_SITE_DATA_HEADERS
|
|
121
124
|
else:
|
|
122
|
-
|
|
125
|
+
ret = (
|
|
123
126
|
Response()
|
|
124
127
|
.ok(None, "更新成功,AstrBot 将在下次启动时应用新的代码。")
|
|
125
128
|
.__dict__
|
|
126
129
|
)
|
|
130
|
+
return ret, 200, CLEAR_SITE_DATA_HEADERS
|
|
127
131
|
except Exception as e:
|
|
128
132
|
logger.error(f"/api/update_project: {traceback.format_exc()}")
|
|
129
133
|
return Response().error(e.__str__()).__dict__
|
|
@@ -135,9 +139,8 @@ class UpdateRoute(Route):
|
|
|
135
139
|
except Exception as e:
|
|
136
140
|
logger.error(f"下载管理面板文件失败: {e}。")
|
|
137
141
|
return Response().error(f"下载管理面板文件失败: {e}").__dict__
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
)
|
|
142
|
+
ret = Response().ok(None, "更新成功。刷新页面即可应用新版本面板。").__dict__
|
|
143
|
+
return ret, 200, CLEAR_SITE_DATA_HEADERS
|
|
141
144
|
except Exception as e:
|
|
142
145
|
logger.error(f"/api/update_dashboard: {traceback.format_exc()}")
|
|
143
146
|
return Response().error(e.__str__()).__dict__
|
|
@@ -45,10 +45,10 @@ astrbot/core/agent/runners/base.py,sha256=exZS_d2BsrLz-xgeY9ZUPuXikBDUnKxO-dU3ZF
|
|
|
45
45
|
astrbot/core/agent/runners/tool_loop_agent_runner.py,sha256=O4sYg1V3dbUcZFLek5Izi-aEJb983tk9DJOCBQvQjro,13558
|
|
46
46
|
astrbot/core/config/__init__.py,sha256=0CO_3sKtI3WOwWT0k4i6TleWq1SAWJFfB8KjnYB8Zig,172
|
|
47
47
|
astrbot/core/config/astrbot_config.py,sha256=X-b3c5m4msgJrdYFH2LXic5XKY0ViuUMdNZ335zqSBw,6335
|
|
48
|
-
astrbot/core/config/default.py,sha256=
|
|
48
|
+
astrbot/core/config/default.py,sha256=PVNeFncOfO1yksdRDUl2_LJWpAQRaxYYuikZnR9lSco,124015
|
|
49
49
|
astrbot/core/db/__init__.py,sha256=JOAMt7_j0y96CuArXJ-YY_qXisSartOZwyDTKf9ZDn8,8844
|
|
50
50
|
astrbot/core/db/po.py,sha256=NDOJpUXI1i4BF1uymCj07opwXM0gdHBtwCoL16Xj4jc,7798
|
|
51
|
-
astrbot/core/db/sqlite.py,sha256=
|
|
51
|
+
astrbot/core/db/sqlite.py,sha256=_5-B2Jlare4twLG0TlO95bVTaLu0HAXsfpX5LOcoVWA,26082
|
|
52
52
|
astrbot/core/db/migration/helper.py,sha256=FcwpvBANNeyBSrRhXyd3hudHYEyhTyrcRg9mU9lZtqY,1935
|
|
53
53
|
astrbot/core/db/migration/migra_3_to_4.py,sha256=I1CesaBbf5wj9agtNWxDl1V-qixmwdURbBQf5Vzagrk,15025
|
|
54
54
|
astrbot/core/db/migration/shared_preferences_v3.py,sha256=tE11WIpwT-Q8yVBkw4eveRr1PmFdNRJQSprH4xdO3G4,1245
|
|
@@ -63,7 +63,7 @@ astrbot/core/message/components.py,sha256=AzJACQYgw0Yo1iwSIyQWtfE8Xyo-6Q8KcQPE9y
|
|
|
63
63
|
astrbot/core/message/message_event_result.py,sha256=dooPyzDVV4danPNQBvZsSXemGsihnBjW3qYByYUEa1s,7248
|
|
64
64
|
astrbot/core/pipeline/__init__.py,sha256=-jo6a9lKmwY8oPoifJi0IMLPOVdknQKG30ppIyCs5Bg,1461
|
|
65
65
|
astrbot/core/pipeline/context.py,sha256=3ySHVzhjdT54kTDMMKPse1EFdvb7XfmscNEp3YCJLVM,503
|
|
66
|
-
astrbot/core/pipeline/context_utils.py,sha256=
|
|
66
|
+
astrbot/core/pipeline/context_utils.py,sha256=CmR45Er5yFpI-IPwDfbJA1rOhzgNybkZg149dpgtl6w,3548
|
|
67
67
|
astrbot/core/pipeline/scheduler.py,sha256=8N6QuLV55gR1jQZDEOUDrvcf42ify8EDmw1aDU3Y4nE,3270
|
|
68
68
|
astrbot/core/pipeline/stage.py,sha256=dqEhUuQIhAZpPV4dULmVN39R0pIPjyw8Ftvs4Y1C4lY,1352
|
|
69
69
|
astrbot/core/pipeline/content_safety_check/stage.py,sha256=yUF2h_E41VZQt70pCtIqr1-pgobbJ49omSnKUgg_G-M,1379
|
|
@@ -77,7 +77,7 @@ astrbot/core/pipeline/process_stage/method/llm_request.py,sha256=NaWr0eRhuxqb4ZI
|
|
|
77
77
|
astrbot/core/pipeline/process_stage/method/star_request.py,sha256=IuPP7qnxvBgKV6a9D3wLU4_KU3Ec3Ml7IOADQCXDgqk,2501
|
|
78
78
|
astrbot/core/pipeline/rate_limit_check/stage.py,sha256=I_GkpSgioN0-T_catMwpRKtxx-TiMmvu8vV_FE5ORIA,4072
|
|
79
79
|
astrbot/core/pipeline/respond/stage.py,sha256=XE5yGsHGxESP0zAGmx3qHovP1wGaJDXUgfLb5Z4wasE,10837
|
|
80
|
-
astrbot/core/pipeline/result_decorate/stage.py,sha256=
|
|
80
|
+
astrbot/core/pipeline/result_decorate/stage.py,sha256=mxTBH5jDWDrfQV2H6XCWMYJLCuPiTAZut4-Gqrpufk4,13847
|
|
81
81
|
astrbot/core/pipeline/session_status_check/stage.py,sha256=woucuVbzzQoi62MDoP3lTha4es_fUu4p-IPCzSiYDBw,1262
|
|
82
82
|
astrbot/core/pipeline/waking_check/stage.py,sha256=URBFmfid1CKhtCGjH7OzFmxBE-Gt9vv1eYlp6msIv_Q,8240
|
|
83
83
|
astrbot/core/pipeline/whitelist_check/stage.py,sha256=VcmLs0VfmspNTsitL_WrZXfv2lR2Nktrb5JEWc1VJuw,2403
|
|
@@ -133,25 +133,25 @@ astrbot/core/provider/entites.py,sha256=-353AdRDA6ST4AS48cQ1RRAXHSy3F7pVS_28hW4c
|
|
|
133
133
|
astrbot/core/provider/entities.py,sha256=CkC-U9nafBKo2n2kLZqzukosDX7RuZWAK4DMBHQkasA,11238
|
|
134
134
|
astrbot/core/provider/func_tool_manager.py,sha256=NuWMmAJaEwoJ3XCSvhwtmzDPdzX4K4BIRKuKgF0FlQk,20881
|
|
135
135
|
astrbot/core/provider/manager.py,sha256=GoRR4hTRyYaaWH6_ICx0tflqG1Lng72dVOuq6pagb5k,21729
|
|
136
|
-
astrbot/core/provider/provider.py,sha256=
|
|
136
|
+
astrbot/core/provider/provider.py,sha256=3R0xWAYuUQ0VXWja1TZtVVfqN8d3f9VhhYdpdqj5uaA,7239
|
|
137
137
|
astrbot/core/provider/register.py,sha256=bWAF9zWNnSYQWjmZIXiWgxFaeWIiWjEoEIN_xhmq3mM,1830
|
|
138
|
-
astrbot/core/provider/sources/anthropic_source.py,sha256=
|
|
138
|
+
astrbot/core/provider/sources/anthropic_source.py,sha256=GQY8TUw56V6pIGfqwT7KeJ-8dBSDZi7jjCwbhSsVekQ,15184
|
|
139
139
|
astrbot/core/provider/sources/azure_tts_source.py,sha256=V8WGpMFeYn-DhmE2FtYYYir-51T1S81XKvP08tslm8E,9350
|
|
140
140
|
astrbot/core/provider/sources/coze_api_client.py,sha256=dr2QpON0I83eIyadh5XDEVnGl26Jm5rbXGzQKkLBBcc,10820
|
|
141
141
|
astrbot/core/provider/sources/coze_source.py,sha256=KddH9Ryl-cuaobjVBY5ar_cPEb5MUDvc7Pqx9BTp9Oo,25215
|
|
142
142
|
astrbot/core/provider/sources/dashscope_source.py,sha256=HPzMCI-x5Ht76KxxvWHSwffW5tq6gWJQl48O_YKCTcc,7321
|
|
143
|
-
astrbot/core/provider/sources/dashscope_tts.py,sha256=
|
|
143
|
+
astrbot/core/provider/sources/dashscope_tts.py,sha256=gMm876jMiL15bmMbkAaQSP-XKjSdL1rBLrXCFVQXJhQ,5522
|
|
144
144
|
astrbot/core/provider/sources/dify_source.py,sha256=Q0VmnacKwD-fOnvwYqbrRMspDYOlJZAHnjBawRzshw4,11472
|
|
145
145
|
astrbot/core/provider/sources/edge_tts_source.py,sha256=foO2E0Wdc2wJy8yMbLUyX0cjkP6MD4vPCbc8q3Ckkug,4716
|
|
146
146
|
astrbot/core/provider/sources/fishaudio_tts_api_source.py,sha256=Tu4wHh5txKDWn3_Z57hWgzTU8QUw1oVFBndAqmp4aLY,5439
|
|
147
147
|
astrbot/core/provider/sources/gemini_embedding_source.py,sha256=FlVlacBLlxo4ZZgrBhurDQRuDYRGtR8Du35XuXEY9nI,2307
|
|
148
|
-
astrbot/core/provider/sources/gemini_source.py,sha256=
|
|
148
|
+
astrbot/core/provider/sources/gemini_source.py,sha256=U7imSkoR1kQyTZN_ueCnbMlJ3bi6cjSNdKivLeOUGeU,28787
|
|
149
149
|
astrbot/core/provider/sources/gemini_tts_source.py,sha256=mNcb9G6Lb58L2zoSYzroQGyASGrv3k4ZjmOIVvhii_o,2886
|
|
150
150
|
astrbot/core/provider/sources/gsv_selfhosted_source.py,sha256=7wSQ32AJv4cisjnedENfpThd1kHDqYvnMSCpwbpNNM4,5936
|
|
151
151
|
astrbot/core/provider/sources/gsvi_tts_source.py,sha256=EoYuAf85NVcPPbyRWkE_doWF-7R8IM5o9ozxbbvaFRk,2025
|
|
152
152
|
astrbot/core/provider/sources/minimax_tts_api_source.py,sha256=jNLP_4-UHq_Iekvjn3h7G6YZjTCGuII-hq-1RhzjSlE,5877
|
|
153
153
|
astrbot/core/provider/sources/openai_embedding_source.py,sha256=IIz25EksuIWINKpLqfKG-9Qc4bJ398w24oMjoArXFUA,1669
|
|
154
|
-
astrbot/core/provider/sources/openai_source.py,sha256=
|
|
154
|
+
astrbot/core/provider/sources/openai_source.py,sha256=_koDL9xmsFb4Gf2r-1VWzKMGTwQcgs00RKtWOZqcfck,20944
|
|
155
155
|
astrbot/core/provider/sources/openai_tts_api_source.py,sha256=ClRxEuBJ2-vM5rpMwwhOZXXJanq6asEAVPRvD9wYFrI,1626
|
|
156
156
|
astrbot/core/provider/sources/sensevoice_selfhosted_source.py,sha256=2-NUDRiJJs3onxnrovdoVqUMI8bxGu2J2n3ZgwjxEm0,3828
|
|
157
157
|
astrbot/core/provider/sources/vllm_rerank_source.py,sha256=Gv_veniilJ5v9lPGlQG_zmQYmHfhNggYIwj5p02CoLE,2275
|
|
@@ -212,14 +212,14 @@ astrbot/dashboard/routes/log.py,sha256=hDl6Niz_Vs4xb64USjCBzdOcm68GDpEsQrNrLr8yK
|
|
|
212
212
|
astrbot/dashboard/routes/persona.py,sha256=6icnNNE8A0Yy1WI0INWD9ZPKC7VcZG-xHDfYElhaP8M,7857
|
|
213
213
|
astrbot/dashboard/routes/plugin.py,sha256=cGGJVEM55uRiPo-EeD5apZQISzPw9vux7a-U2dE4fZQ,19429
|
|
214
214
|
astrbot/dashboard/routes/route.py,sha256=V-Wm88D0BmxSYAUbedunykbWy5p7Tggae9nDhxm7LZU,1545
|
|
215
|
-
astrbot/dashboard/routes/session_management.py,sha256=
|
|
215
|
+
astrbot/dashboard/routes/session_management.py,sha256=yYcaXDwOiNYoLrseCxazLoFpxj_rsOUQ9-_8zifAAXE,26811
|
|
216
216
|
astrbot/dashboard/routes/stat.py,sha256=KCtP0-f9g664gM2SOBgnU8uKx6zt93-5Kut-d7wd7zk,6910
|
|
217
217
|
astrbot/dashboard/routes/static_file.py,sha256=7KnNcOb1BVqSTft114LhGsDkfg69X2jHEm0tOK0kW0Y,1169
|
|
218
218
|
astrbot/dashboard/routes/t2i.py,sha256=scp05AxoJM9cubrkSMBu1BbIWP1BMS50eFEPZ9S6WKM,8893
|
|
219
219
|
astrbot/dashboard/routes/tools.py,sha256=FvWgjzImgeIGFWJM_r2tku3UTj0J5LwZXfmZJxfJWHM,13975
|
|
220
|
-
astrbot/dashboard/routes/update.py,sha256=
|
|
221
|
-
astrbot-4.3.
|
|
222
|
-
astrbot-4.3.
|
|
223
|
-
astrbot-4.3.
|
|
224
|
-
astrbot-4.3.
|
|
225
|
-
astrbot-4.3.
|
|
220
|
+
astrbot/dashboard/routes/update.py,sha256=cFeb0EGA69afhSB4o1HJYsvlBQGQotQXQJsp_juJ6ck,6707
|
|
221
|
+
astrbot-4.3.3.dist-info/METADATA,sha256=7SX8mVXZ5Mok98mqaH7vN0LYZlO4di7RSHnsyiLfgZE,11095
|
|
222
|
+
astrbot-4.3.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
223
|
+
astrbot-4.3.3.dist-info/entry_points.txt,sha256=OEF09YmhBWYuViXrvTLLpstF4ccmNwDL8r7nnFD0pfI,53
|
|
224
|
+
astrbot-4.3.3.dist-info/licenses/LICENSE,sha256=zPfQj5Mq8-gThIiBcxETr7t8gND9bZWOjTGQAr80TQI,34500
|
|
225
|
+
astrbot-4.3.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|