- 增加全局智能助手设置,开启后所有消息通过智能助手回答而无需使用 `/ai` 指令
- 问题修复与细节优化
This commit is contained in:
jxxghp
2025-11-23 13:55:16 +08:00
parent fd422d7446
commit 9b5f863832
6 changed files with 338 additions and 331 deletions
+1 -2
View File
@@ -1,7 +1,7 @@
"""查询媒体库工具""" """查询媒体库工具"""
import json import json
from typing import Optional, List, Type from typing import Optional, Type
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
@@ -9,7 +9,6 @@ from app.agent.tools.base import MoviePilotTool
from app.chain.mediaserver import MediaServerChain from app.chain.mediaserver import MediaServerChain
from app.core.context import MediaInfo from app.core.context import MediaInfo
from app.log import logger from app.log import logger
from app.schemas import MediaServerItem
from app.schemas.types import MediaType from app.schemas.types import MediaType
@@ -35,8 +35,6 @@ class SearchPersonCreditsTool(MoviePilotTool):
logger.info(f"执行工具: {self.name}, 参数: person_id={person_id}, source={source}, page={page}") logger.info(f"执行工具: {self.name}, 参数: person_id={person_id}, source={source}, page={page}")
try: try:
medias = None
# 根据source选择相应的chain # 根据source选择相应的chain
if source.lower() == "tmdb": if source.lower() == "tmdb":
tmdb_chain = TmdbChain() tmdb_chain = TmdbChain()
+4 -2
View File
@@ -64,7 +64,8 @@ class SearchWebTool(MoviePilotTool):
logger.error(f"搜索网络内容失败: {e}", exc_info=True) logger.error(f"搜索网络内容失败: {e}", exc_info=True)
return error_message return error_message
async def _search_duckduckgo_api(self, query: str, max_results: int) -> list: @staticmethod
async def _search_duckduckgo_api(query: str, max_results: int) -> list:
""" """
使用DuckDuckGo API进行搜索 使用DuckDuckGo API进行搜索
@@ -143,7 +144,8 @@ class SearchWebTool(MoviePilotTool):
logger.warning(f"DuckDuckGo API搜索失败: {e}") logger.warning(f"DuckDuckGo API搜索失败: {e}")
return [] return []
def _format_and_truncate_results(self, results: list, max_results: int) -> dict: @staticmethod
def _format_and_truncate_results(results: list, max_results: int) -> dict:
""" """
格式化并裁剪搜索结果以避免占用过多上下文 格式化并裁剪搜索结果以避免占用过多上下文
+329 -323
View File
@@ -164,19 +164,15 @@ class MessageChain(ChainBase):
) )
# 处理消息 # 处理消息
if text.startswith('CALLBACK:'): if text.startswith('CALLBACK:'):
# 处理按钮回调(适配支持回调的渠 # 处理按钮回调(适配支持回调的渠),优先级最高
if ChannelCapabilityManager.supports_callbacks(channel): if ChannelCapabilityManager.supports_callbacks(channel):
self._handle_callback(text=text, channel=channel, source=source, self._handle_callback(text=text, channel=channel, source=source,
userid=userid, username=username, userid=userid, username=username,
original_message_id=original_message_id, original_chat_id=original_chat_id) original_message_id=original_message_id, original_chat_id=original_chat_id)
else: else:
logger.warning(f"渠道 {channel.value} 不支持回调,但收到了回调消息:{text}") logger.warning(f"渠道 {channel.value} 不支持回调,但收到了回调消息:{text}")
elif text.startswith('/ai') or text.startswith('/AI'): elif text.startswith('/') and not text.lower().startswith('/ai'):
# AI智能体处理 # 执行特定命令命令(但不是/ai
self._handle_ai_message(text=text, channel=channel, source=source,
userid=userid, username=username)
elif text.startswith('/'):
# 执行命令
self.eventmanager.send_event( self.eventmanager.send_event(
EventType.CommandExcute, EventType.CommandExcute,
{ {
@@ -186,266 +182,226 @@ class MessageChain(ChainBase):
"source": source "source": source
} }
) )
elif text.isdigit(): elif text.lower().startswith('/ai'):
# 用户选择了具体的条目 # 用户指定AI智能体消息响应
# 缓存 self._handle_ai_message(text=text, channel=channel, source=source,
cache_data: dict = user_cache.get(userid).copy() userid=userid, username=username)
# 选择项目 elif settings.AI_AGENT_ENABLE and settings.AI_AGENT_GLOBAL:
if not cache_data \ # 普通消息,全局智能体响应
or not cache_data.get('items') \ self._handle_ai_message(text=text, channel=channel, source=source,
or len(cache_data.get('items')) < int(text): userid=userid, username=username)
# 发送消息 else:
self.post_message(Notification(channel=channel, source=source, title="输入有误!", userid=userid)) # 非智能体普通消息响应
return if text.isdigit():
try: # 用户选择了具体的条目
# 选择的序号 # 缓存
_choice = int(text) + _current_page * self._page_size - 1 cache_data: dict = user_cache.get(userid).copy()
# 缓存类型 # 选择项目
cache_type: str = cache_data.get('type') if not cache_data \
# 缓存列表 or not cache_data.get('items') \
cache_list: list = cache_data.get('items').copy() or len(cache_data.get('items')) < int(text):
# 选择 # 发送消息
self.post_message(Notification(channel=channel, source=source, title="输入有误!", userid=userid))
return
try: try:
if cache_type in ["Search", "ReSearch"]: # 选择的序号
# 当前媒体信息 _choice = int(text) + _current_page * self._page_size - 1
mediainfo: MediaInfo = cache_list[_choice] # 缓存类型
_current_media = mediainfo cache_type: str = cache_data.get('type')
# 查询缺失的媒体信息 # 缓存列表
exist_flag, no_exists = DownloadChain().get_no_exists_info(meta=_current_meta, cache_list: list = cache_data.get('items').copy()
mediainfo=_current_media) # 选择
if exist_flag and cache_type == "Search": try:
# 媒体库中已存在 if cache_type in ["Search", "ReSearch"]:
# 当前媒体信息
mediainfo: MediaInfo = cache_list[_choice]
_current_media = mediainfo
# 查询缺失的媒体信息
exist_flag, no_exists = DownloadChain().get_no_exists_info(meta=_current_meta,
mediainfo=_current_media)
if exist_flag and cache_type == "Search":
# 媒体库中已存在
self.post_message(
Notification(channel=channel,
source=source,
title=f"{_current_media.title_year}"
f"{_current_meta.sea} 媒体库中已存在,如需重新下载请发送:搜索 名称 或 下载 名称】",
userid=userid))
return
elif exist_flag:
# 没有缺失,但要全量重新搜索和下载
no_exists = self.__get_noexits_info(_current_meta, _current_media)
# 发送缺失的媒体信息
messages = []
if no_exists and cache_type == "Search":
# 发送缺失消息
mediakey = mediainfo.tmdb_id or mediainfo.douban_id
messages = [
f"{sea} 季缺失 {StringUtils.str_series(no_exist.episodes) if no_exist.episodes else no_exist.total_episode}"
for sea, no_exist in no_exists.get(mediakey).items()]
elif no_exists:
# 发送总集数的消息
mediakey = mediainfo.tmdb_id or mediainfo.douban_id
messages = [
f"{sea} 季总 {no_exist.total_episode}"
for sea, no_exist in no_exists.get(mediakey).items()]
if messages:
self.post_message(Notification(channel=channel,
source=source,
title=f"{mediainfo.title_year}\n" + "\n".join(messages),
userid=userid))
# 搜索种子,过滤掉不需要的剧集,以便选择
logger.info(f"开始搜索 {mediainfo.title_year} ...")
self.post_message( self.post_message(
Notification(channel=channel, Notification(channel=channel,
source=source, source=source,
title=f"{_current_media.title_year}" title=f"开始搜索 {mediainfo.type.value} {mediainfo.title_year} ...",
f"{_current_meta.sea} 媒体库中已存在,如需重新下载请发送:搜索 名称 或 下载 名称】",
userid=userid)) userid=userid))
return # 开始搜索
elif exist_flag: contexts = SearchChain().process(mediainfo=mediainfo,
# 没有缺失,但要全量重新搜索和下载 no_exists=no_exists)
no_exists = self.__get_noexits_info(_current_meta, _current_media) if not contexts:
# 发送缺失的媒体信息 # 没有数据
messages = []
if no_exists and cache_type == "Search":
# 发送缺失消息
mediakey = mediainfo.tmdb_id or mediainfo.douban_id
messages = [
f"{sea} 季缺失 {StringUtils.str_series(no_exist.episodes) if no_exist.episodes else no_exist.total_episode}"
for sea, no_exist in no_exists.get(mediakey).items()]
elif no_exists:
# 发送总集数的消息
mediakey = mediainfo.tmdb_id or mediainfo.douban_id
messages = [
f"{sea} 季总 {no_exist.total_episode}"
for sea, no_exist in no_exists.get(mediakey).items()]
if messages:
self.post_message(Notification(channel=channel,
source=source,
title=f"{mediainfo.title_year}\n" + "\n".join(messages),
userid=userid))
# 搜索种子,过滤掉不需要的剧集,以便选择
logger.info(f"开始搜索 {mediainfo.title_year} ...")
self.post_message(
Notification(channel=channel,
source=source,
title=f"开始搜索 {mediainfo.type.value} {mediainfo.title_year} ...",
userid=userid))
# 开始搜索
contexts = SearchChain().process(mediainfo=mediainfo,
no_exists=no_exists)
if not contexts:
# 没有数据
self.post_message(Notification(
channel=channel,
source=source,
title=f"{mediainfo.title}"
f"{_current_meta.sea} 未搜索到需要的资源!",
userid=userid))
return
# 搜索结果排序
contexts = TorrentHelper().sort_torrents(contexts)
try:
# 判断是否设置自动下载
auto_download_user = settings.AUTO_DOWNLOAD_USER
# 匹配到自动下载用户
if auto_download_user \
and (auto_download_user == "all"
or any(userid == user for user in auto_download_user.split(","))):
logger.info(f"用户 {userid} 在自动下载用户中,开始自动择优下载 ...")
# 自动选择下载
self.__auto_download(channel=channel,
source=source,
cache_list=contexts,
userid=userid,
username=username,
no_exists=no_exists)
else:
# 更新缓存
user_cache[userid] = {
"type": "Torrent",
"items": contexts
}
_current_page = 0
# 保存缓存
self.save_cache(user_cache, self._cache_file)
# 删除原消息
if (original_message_id and original_chat_id and
ChannelCapabilityManager.supports_deletion(channel)):
self.delete_message(
channel=channel,
source=source,
message_id=original_message_id,
chat_id=original_chat_id
)
# 发送种子数据
logger.info(f"搜索到 {len(contexts)} 条数据,开始发送选择消息 ...")
self.__post_torrents_message(channel=channel,
source=source,
title=mediainfo.title,
items=contexts[:self._page_size],
userid=userid,
total=len(contexts))
finally:
contexts.clear()
del contexts
elif cache_type in ["Subscribe", "ReSubscribe"]:
# 订阅或洗版媒体
mediainfo: MediaInfo = cache_list[_choice]
# 洗版标识
best_version = False
# 查询缺失的媒体信息
if cache_type == "Subscribe":
exist_flag, _ = DownloadChain().get_no_exists_info(meta=_current_meta,
mediainfo=mediainfo)
if exist_flag:
self.post_message(Notification( self.post_message(Notification(
channel=channel, channel=channel,
source=source, source=source,
title=f"{mediainfo.title_year}" title=f"{mediainfo.title}"
f"{_current_meta.sea} 媒体库中已存在,如需洗版请发送:洗版 XXX】", f"{_current_meta.sea} 未搜索到需要的资源!",
userid=userid)) userid=userid))
return return
else: # 搜索结果排序
best_version = True contexts = TorrentHelper().sort_torrents(contexts)
# 转换用户名 try:
mp_name = UserOper().get_name( # 判断是否设置自动下载
**{f"{channel.name.lower()}_userid": userid}) if channel else None auto_download_user = settings.AUTO_DOWNLOAD_USER
# 添加订阅,状态为N # 匹配到自动下载用户
SubscribeChain().add(title=mediainfo.title, if auto_download_user \
year=mediainfo.year, and (auto_download_user == "all"
mtype=mediainfo.type, or any(userid == user for user in auto_download_user.split(","))):
tmdbid=mediainfo.tmdb_id, logger.info(f"用户 {userid} 在自动下载用户中,开始自动择优下载 ...")
season=_current_meta.begin_season, # 自动选择下载
channel=channel, self.__auto_download(channel=channel,
source=source, source=source,
userid=userid, cache_list=contexts,
username=mp_name or username, userid=userid,
best_version=best_version) username=username,
elif cache_type == "Torrent": no_exists=no_exists)
if int(text) == 0: else:
# 自动选择下载,强制下载模式 # 更新缓存
self.__auto_download(channel=channel, user_cache[userid] = {
"type": "Torrent",
"items": contexts
}
_current_page = 0
# 保存缓存
self.save_cache(user_cache, self._cache_file)
# 删除原消息
if (original_message_id and original_chat_id and
ChannelCapabilityManager.supports_deletion(channel)):
self.delete_message(
channel=channel,
source=source,
message_id=original_message_id,
chat_id=original_chat_id
)
# 发送种子数据
logger.info(f"搜索到 {len(contexts)} 条数据,开始发送选择消息 ...")
self.__post_torrents_message(channel=channel,
source=source,
title=mediainfo.title,
items=contexts[:self._page_size],
userid=userid,
total=len(contexts))
finally:
contexts.clear()
del contexts
elif cache_type in ["Subscribe", "ReSubscribe"]:
# 订阅或洗版媒体
mediainfo: MediaInfo = cache_list[_choice]
# 洗版标识
best_version = False
# 查询缺失的媒体信息
if cache_type == "Subscribe":
exist_flag, _ = DownloadChain().get_no_exists_info(meta=_current_meta,
mediainfo=mediainfo)
if exist_flag:
self.post_message(Notification(
channel=channel,
source=source,
title=f"{mediainfo.title_year}"
f"{_current_meta.sea} 媒体库中已存在,如需洗版请发送:洗版 XXX】",
userid=userid))
return
else:
best_version = True
# 转换用户名
mp_name = UserOper().get_name(
**{f"{channel.name.lower()}_userid": userid}) if channel else None
# 添加订阅,状态为N
SubscribeChain().add(title=mediainfo.title,
year=mediainfo.year,
mtype=mediainfo.type,
tmdbid=mediainfo.tmdb_id,
season=_current_meta.begin_season,
channel=channel,
source=source, source=source,
cache_list=cache_list,
userid=userid, userid=userid,
username=username) username=mp_name or username,
else: best_version=best_version)
# 下载种子 elif cache_type == "Torrent":
context: Context = cache_list[_choice] if int(text) == 0:
# 下载 # 自动选择下载,强制下载模式
DownloadChain().download_single(context, channel=channel, source=source, self.__auto_download(channel=channel,
userid=userid, username=username) source=source,
cache_list=cache_list,
userid=userid,
username=username)
else:
# 下载种子
context: Context = cache_list[_choice]
# 下载
DownloadChain().download_single(context, channel=channel, source=source,
userid=userid, username=username)
finally:
cache_list.clear()
del cache_list
finally: finally:
cache_list.clear() cache_data.clear()
del cache_list del cache_data
finally: elif text.lower() == "p":
cache_data.clear() # 上一页
del cache_data cache_data: dict = user_cache.get(userid).copy()
elif text.lower() == "p": if not cache_data:
# 上一页 # 没有缓存
cache_data: dict = user_cache.get(userid).copy()
if not cache_data:
# 没有缓存
self.post_message(Notification(
channel=channel, source=source, title="输入有误!", userid=userid))
return
try:
if _current_page == 0:
# 第一页
self.post_message(Notification( self.post_message(Notification(
channel=channel, source=source, title="已经是第一页了", userid=userid)) channel=channel, source=source, title="输入有误", userid=userid))
return return
# 减一页
_current_page -= 1
cache_type: str = cache_data.get('type')
# 产生副本,避免修改原值
cache_list: list = cache_data.get('items').copy()
try: try:
if _current_page == 0: if _current_page == 0:
start = 0 # 第一页
end = self._page_size self.post_message(Notification(
else: channel=channel, source=source, title="已经是第一页了!", userid=userid))
start = _current_page * self._page_size return
end = start + self._page_size # 减一页
if cache_type == "Torrent": _current_page -= 1
# 发送种子数据 cache_type: str = cache_data.get('type')
self.__post_torrents_message(channel=channel, # 产生副本,避免修改原值
source=source, cache_list: list = cache_data.get('items').copy()
title=_current_media.title,
items=cache_list[start:end],
userid=userid,
total=len(cache_list),
original_message_id=original_message_id,
original_chat_id=original_chat_id)
else:
# 发送媒体数据
self.__post_medias_message(channel=channel,
source=source,
title=_current_meta.name,
items=cache_list[start:end],
userid=userid,
total=len(cache_list),
original_message_id=original_message_id,
original_chat_id=original_chat_id)
finally:
cache_list.clear()
del cache_list
finally:
cache_data.clear()
del cache_data
elif text.lower() == "n":
# 下一页
cache_data: dict = user_cache.get(userid).copy()
if not cache_data:
# 没有缓存
self.post_message(Notification(
channel=channel, source=source, title="输入有误!", userid=userid))
return
try:
cache_type: str = cache_data.get('type')
# 产生副本,避免修改原值
cache_list: list = cache_data.get('items').copy()
total = len(cache_list)
# 加一页
cache_list = cache_list[(_current_page + 1) * self._page_size:(_current_page + 2) * self._page_size]
if not cache_list:
# 没有数据
self.post_message(Notification(
channel=channel, source=source, title="已经是最后一页了!", userid=userid))
return
else:
try: try:
# 加一页 if _current_page == 0:
_current_page += 1 start = 0
end = self._page_size
else:
start = _current_page * self._page_size
end = start + self._page_size
if cache_type == "Torrent": if cache_type == "Torrent":
# 发送种子数据 # 发送种子数据
self.__post_torrents_message(channel=channel, self.__post_torrents_message(channel=channel,
source=source, source=source,
title=_current_media.title, title=_current_media.title,
items=cache_list, items=cache_list[start:end],
userid=userid, userid=userid,
total=total, total=len(cache_list),
original_message_id=original_message_id, original_message_id=original_message_id,
original_chat_id=original_chat_id) original_chat_id=original_chat_id)
else: else:
@@ -453,94 +409,144 @@ class MessageChain(ChainBase):
self.__post_medias_message(channel=channel, self.__post_medias_message(channel=channel,
source=source, source=source,
title=_current_meta.name, title=_current_meta.name,
items=cache_list, items=cache_list[start:end],
userid=userid, userid=userid,
total=total, total=len(cache_list),
original_message_id=original_message_id, original_message_id=original_message_id,
original_chat_id=original_chat_id) original_chat_id=original_chat_id)
finally: finally:
cache_list.clear() cache_list.clear()
del cache_list del cache_list
finally:
cache_data.clear()
del cache_data
else:
# 搜索或订阅
if text.startswith("订阅"):
# 订阅
content = re.sub(r"订阅[:\s]*", "", text)
action = "Subscribe"
elif text.startswith("洗版"):
# 洗版
content = re.sub(r"洗版[:\s]*", "", text)
action = "ReSubscribe"
elif text.startswith("搜索") or text.startswith("下载"):
# 重新搜索/下载
content = re.sub(r"(搜索|下载)[:\s]*", "", text)
action = "ReSearch"
elif text.startswith("#") \
or re.search(r"^请[问帮你]", text) \
or re.search(r"[?]$", text) \
or StringUtils.count_words(text) > 10 \
or text.find("继续") != -1:
# 聊天
content = text
action = "Chat"
elif StringUtils.is_link(text):
# 链接
content = text
action = "Link"
else:
# 搜索
content = text
action = "Search"
if action in ["Search", "ReSearch", "Subscribe", "ReSubscribe"]:
# 搜索
meta, medias = MediaChain().search(content)
# 识别
if not meta.name:
self.post_message(Notification(
channel=channel, source=source, title="无法识别输入内容!", userid=userid))
return
# 开始搜索
if not medias:
self.post_message(Notification(
channel=channel, source=source, title=f"{meta.name} 没有找到对应的媒体信息!",
userid=userid))
return
logger.info(f"搜索到 {len(medias)} 条相关媒体信息")
try:
# 记录当前状态
_current_meta = meta
# 保存缓存
user_cache[userid] = {
'type': action,
'items': medias
}
self.save_cache(user_cache, self._cache_file)
_current_page = 0
_current_media = None
# 发送媒体列表
self.__post_medias_message(channel=channel,
source=source,
title=meta.name,
items=medias[:self._page_size],
userid=userid, total=len(medias))
finally: finally:
medias.clear() cache_data.clear()
del medias del cache_data
elif text.lower() == "n":
# 下一页
cache_data: dict = user_cache.get(userid).copy()
if not cache_data:
# 没有缓存
self.post_message(Notification(
channel=channel, source=source, title="输入有误!", userid=userid))
return
try:
cache_type: str = cache_data.get('type')
# 产生副本,避免修改原值
cache_list: list = cache_data.get('items').copy()
total = len(cache_list)
# 加一页
cache_list = cache_list[(_current_page + 1) * self._page_size:(_current_page + 2) * self._page_size]
if not cache_list:
# 没有数据
self.post_message(Notification(
channel=channel, source=source, title="已经是最后一页了!", userid=userid))
return
else:
try:
# 加一页
_current_page += 1
if cache_type == "Torrent":
# 发送种子数据
self.__post_torrents_message(channel=channel,
source=source,
title=_current_media.title,
items=cache_list,
userid=userid,
total=total,
original_message_id=original_message_id,
original_chat_id=original_chat_id)
else:
# 发送媒体数据
self.__post_medias_message(channel=channel,
source=source,
title=_current_meta.name,
items=cache_list,
userid=userid,
total=total,
original_message_id=original_message_id,
original_chat_id=original_chat_id)
finally:
cache_list.clear()
del cache_list
finally:
cache_data.clear()
del cache_data
else: else:
# 广播事件 # 搜索或订阅
self.eventmanager.send_event( if text.startswith("订阅"):
EventType.UserMessage, # 订阅
{ content = re.sub(r"订阅[:\s]*", "", text)
"text": content, action = "Subscribe"
"userid": userid, elif text.startswith("洗版"):
"channel": channel, # 洗版
"source": source content = re.sub(r"洗版[:\s]*", "", text)
} action = "ReSubscribe"
) elif text.startswith("搜索") or text.startswith("下载"):
# 重新搜索/下载
content = re.sub(r"(搜索|下载)[:\s]*", "", text)
action = "ReSearch"
elif text.startswith("#") \
or re.search(r"^请[问帮你]", text) \
or re.search(r"[?]$", text) \
or StringUtils.count_words(text) > 10 \
or text.find("继续") != -1:
# 聊天
content = text
action = "Chat"
elif StringUtils.is_link(text):
# 链接
content = text
action = "Link"
else:
# 搜索
content = text
action = "Search"
if action in ["Search", "ReSearch", "Subscribe", "ReSubscribe"]:
# 搜索
meta, medias = MediaChain().search(content)
# 识别
if not meta.name:
self.post_message(Notification(
channel=channel, source=source, title="无法识别输入内容!", userid=userid))
return
# 开始搜索
if not medias:
self.post_message(Notification(
channel=channel, source=source, title=f"{meta.name} 没有找到对应的媒体信息!",
userid=userid))
return
logger.info(f"搜索到 {len(medias)} 条相关媒体信息")
try:
# 记录当前状态
_current_meta = meta
# 保存缓存
user_cache[userid] = {
'type': action,
'items': medias
}
self.save_cache(user_cache, self._cache_file)
_current_page = 0
_current_media = None
# 发送媒体列表
self.__post_medias_message(channel=channel,
source=source,
title=meta.name,
items=medias[:self._page_size],
userid=userid, total=len(medias))
finally:
medias.clear()
del medias
else:
# 广播事件
self.eventmanager.send_event(
EventType.UserMessage,
{
"text": content,
"userid": userid,
"channel": channel,
"source": source
}
)
finally: finally:
user_cache.clear() user_cache.clear()
del user_cache del user_cache
+2
View File
@@ -411,6 +411,8 @@ class ConfigModel(BaseModel):
# ==================== AI智能体配置 ==================== # ==================== AI智能体配置 ====================
# AI智能体开关 # AI智能体开关
AI_AGENT_ENABLE: bool = False AI_AGENT_ENABLE: bool = False
# 合局AI智能体
AI_AGENT_GLOBAL: bool = False
# LLM提供商 (openai/google/deepseek) # LLM提供商 (openai/google/deepseek)
LLM_PROVIDER: str = "deepseek" LLM_PROVIDER: str = "deepseek"
# LLM模型名称 # LLM模型名称
+2 -2
View File
@@ -1,2 +1,2 @@
APP_VERSION = 'v2.8.5' APP_VERSION = 'v2.8.6'
FRONTEND_VERSION = 'v2.8.5' FRONTEND_VERSION = 'v2.8.6'