mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-08-29 03:56:43 +08:00
refactor(schemas): 统一 message/notification 命名边界,旧名收敛至兼容映射表
- notification 域:渠道能力(MessageChannel→NotificationChannel、ChannelCapability* 迁入 notification.py) - message 域:消息收发(Notification→Message、NotificationType→MessageType、CommingMessage→IncomingMessage、NotificationHistoryItem→MessageHistoryItem、NotificationClear*→MessageClear*) - Agent 工具契约:send_notification_message→send_message、notification_callback→message_callback - 源码不保留旧名物理别名,旧导入经 app/runtime/compat/manifest.py SYMBOL_ALIASES 惰性解析 - API 路径与持久化键冻结不变,前端零改动 - 新增兼容守护测试与 docs/rules/07 命名边界规范
This commit is contained in:
+98
-98
@@ -44,7 +44,7 @@ from app.application.messaging.agent import (
|
||||
from app.application.messaging.router import has_pending_interaction
|
||||
from app.runtime.localization import LocaleHelper
|
||||
from app.runtime.log import logger
|
||||
from app.schemas.types import EventType, MessageChannel
|
||||
from app.schemas.types import EventType, NotificationChannel
|
||||
|
||||
router = ResponseAPIRouter()
|
||||
|
||||
@@ -62,9 +62,9 @@ WEB_AGENT_STREAM_COALESCE_MAX_CHARS = 256
|
||||
WEB_AGENT_STREAM_HEARTBEAT_SECONDS = 15.0
|
||||
WEB_AGENT_STREAM_QUEUE_MAX_SIZE = 64
|
||||
_WEB_AGENT_FILE_REGISTRY: dict[str, dict[str, Any]] = {}
|
||||
_WEB_AGENT_NOTICE_QUEUES: dict[str, list[Queue[schemas.Notification]]] = {}
|
||||
_WEB_AGENT_NOTICE_LOCK = Lock()
|
||||
_WEB_AGENT_NOTICE_LISTENER_REGISTERED = False
|
||||
_WEB_AGENT_MESSAGE_QUEUES: dict[str, list[Queue[schemas.Message]]] = {}
|
||||
_WEB_AGENT_MESSAGE_LOCK = Lock()
|
||||
_WEB_AGENT_MESSAGE_LISTENER_REGISTERED = False
|
||||
_WEB_AGENT_BACKGROUND_TASKS: set[asyncio.Task] = set()
|
||||
|
||||
|
||||
@@ -350,11 +350,11 @@ class _WebAgentMoviePilotAgent(MoviePilotAgent):
|
||||
def __init__(
|
||||
self,
|
||||
*args: Any,
|
||||
notification_callback: Optional[Callable[[schemas.Notification], None]] = None,
|
||||
message_callback: Optional[Callable[[schemas.Message], None]] = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
super().__init__(*args, **kwargs)
|
||||
self._notification_callback = notification_callback
|
||||
self._message_callback = message_callback
|
||||
self.stream_handler = _WebAgentStreamingHandler(self._emit_output)
|
||||
|
||||
def _should_stream(self) -> bool:
|
||||
@@ -363,16 +363,16 @@ class _WebAgentMoviePilotAgent(MoviePilotAgent):
|
||||
return False
|
||||
return True
|
||||
|
||||
def set_notification_callback(
|
||||
def set_message_callback(
|
||||
self,
|
||||
notification_callback: Optional[Callable[[schemas.Notification], None]],
|
||||
message_callback: Optional[Callable[[schemas.Message], None]],
|
||||
) -> None:
|
||||
"""
|
||||
更新 Web SSE 通知回调,复用 Agent 实例时指向当前请求队列。
|
||||
|
||||
:param notification_callback: 当前请求的 Web 通知回调
|
||||
:param message_callback: 当前请求的 Web 通知回调
|
||||
"""
|
||||
self._notification_callback = notification_callback
|
||||
self._message_callback = message_callback
|
||||
|
||||
def set_output_callback(self, output_callback: Optional[Callable[[str], None]]) -> None:
|
||||
"""
|
||||
@@ -400,7 +400,7 @@ class _WebAgentMoviePilotAgent(MoviePilotAgent):
|
||||
async def _build_tool_context(self, should_dispatch_reply: bool) -> dict[str, object]:
|
||||
"""向工具上下文注入 Web SSE 通知回调。"""
|
||||
context = await super()._build_tool_context(should_dispatch_reply)
|
||||
context["notification_callback"] = self._notification_callback
|
||||
context["message_callback"] = self._message_callback
|
||||
return context
|
||||
|
||||
def _handle_stream_text(self, text: str) -> None:
|
||||
@@ -582,7 +582,7 @@ def _save_web_agent_display_snapshot(
|
||||
channel=(
|
||||
existing_chat.channel
|
||||
if existing_chat and existing_chat.channel
|
||||
else MessageChannel.WebAgent
|
||||
else NotificationChannel.WebAgent
|
||||
),
|
||||
source=(
|
||||
existing_chat.source
|
||||
@@ -982,14 +982,14 @@ def _merge_web_agent_prompt_with_transcript(prompt: str, transcript: Optional[st
|
||||
return "\n".join(merged_parts).strip()
|
||||
|
||||
|
||||
def _build_web_agent_choice_event(notification: schemas.Notification) -> Optional[dict]:
|
||||
def _build_web_agent_choice_event(message: schemas.Message) -> Optional[dict]:
|
||||
"""
|
||||
将带按钮通知转换为 Web Agent 选择卡片事件。
|
||||
|
||||
:param notification: Agent 工具发出的按钮通知
|
||||
:param message: Agent 工具发出的按钮通知
|
||||
:return: 选择卡片事件,按钮为空时返回 None
|
||||
"""
|
||||
button_rows = normalize_web_agent_button_rows(notification.buttons)
|
||||
button_rows = normalize_web_agent_button_rows(message.buttons)
|
||||
buttons = [button for row in button_rows for button in row]
|
||||
if not buttons:
|
||||
return None
|
||||
@@ -1003,8 +1003,8 @@ def _build_web_agent_choice_event(notification: schemas.Notification) -> Optiona
|
||||
"type": "choice",
|
||||
"choice": {
|
||||
"id": choice_id or uuid.uuid4().hex,
|
||||
"title": notification.title,
|
||||
"prompt": notification.text or "",
|
||||
"title": message.title,
|
||||
"prompt": message.text or "",
|
||||
"buttons": buttons,
|
||||
"button_rows": button_rows,
|
||||
},
|
||||
@@ -1062,30 +1062,30 @@ def _resolve_web_agent_choice_payload(callback_data: str, user_id: str) -> Optio
|
||||
}
|
||||
|
||||
|
||||
def _build_web_agent_notification_events(
|
||||
notification: schemas.Notification,
|
||||
def _build_web_agent_message_events(
|
||||
message: schemas.Message,
|
||||
) -> list[dict]:
|
||||
"""
|
||||
将 Agent 工具通知转换为 Web SSE 事件。
|
||||
|
||||
:param notification: 工具产生的通知消息
|
||||
:param message: 工具产生的通知消息
|
||||
:return: 前端可直接应用到当前助手消息的事件列表
|
||||
"""
|
||||
events = []
|
||||
choice_event = _build_web_agent_choice_event(notification)
|
||||
choice_event = _build_web_agent_choice_event(message)
|
||||
if choice_event:
|
||||
events.append(choice_event)
|
||||
|
||||
text_parts = [
|
||||
str(item).strip()
|
||||
for item in (notification.title, notification.text)
|
||||
for item in (message.title, message.text)
|
||||
if str(item or "").strip()
|
||||
]
|
||||
if text_parts and not choice_event:
|
||||
events.append({"type": "delta", "content": "\n\n".join(text_parts)})
|
||||
|
||||
if notification.image:
|
||||
image_ref = notification.image
|
||||
if message.image:
|
||||
image_ref = message.image
|
||||
image_path = Path(image_ref).expanduser()
|
||||
attachment = None
|
||||
if not image_ref.startswith(("http://", "https://", "data:", "blob:")):
|
||||
@@ -1096,12 +1096,12 @@ def _build_web_agent_notification_events(
|
||||
attachment = _build_web_agent_url_attachment(
|
||||
image_ref,
|
||||
kind="image",
|
||||
name=notification.title or image_path.name or "image",
|
||||
name=message.title or image_path.name or "image",
|
||||
)
|
||||
events.append({"type": "attachment", "attachment": attachment})
|
||||
|
||||
if notification.voice_path:
|
||||
audio_path = _prepare_web_agent_audio_attachment_path(notification.voice_path)
|
||||
if message.voice_path:
|
||||
audio_path = _prepare_web_agent_audio_attachment_path(message.voice_path)
|
||||
attachment = _register_web_agent_file(
|
||||
str(audio_path),
|
||||
file_name=audio_path.name,
|
||||
@@ -1111,10 +1111,10 @@ def _build_web_agent_notification_events(
|
||||
if attachment:
|
||||
events.append({"type": "attachment", "attachment": attachment})
|
||||
|
||||
if notification.file_path:
|
||||
if message.file_path:
|
||||
attachment = _register_web_agent_file(
|
||||
notification.file_path,
|
||||
file_name=notification.file_name or Path(notification.file_path).name,
|
||||
message.file_path,
|
||||
file_name=message.file_name or Path(message.file_path).name,
|
||||
)
|
||||
if attachment:
|
||||
events.append({"type": "attachment", "attachment": attachment})
|
||||
@@ -1162,9 +1162,9 @@ def _has_web_agent_traditional_interaction(user_id: str) -> bool:
|
||||
return has_pending_interaction(user_id)
|
||||
|
||||
|
||||
def _extract_web_agent_notification_from_event_data(
|
||||
def _extract_web_agent_message_from_event_data(
|
||||
data: dict,
|
||||
) -> Optional[schemas.Notification]:
|
||||
) -> Optional[schemas.Message]:
|
||||
"""
|
||||
从 NoticeMessage 事件数据中提取 WebAgent 通知。
|
||||
|
||||
@@ -1176,133 +1176,133 @@ def _extract_web_agent_notification_from_event_data(
|
||||
|
||||
try:
|
||||
message = data.get("message")
|
||||
if isinstance(message, schemas.Notification):
|
||||
notification = message
|
||||
if isinstance(message, schemas.Message):
|
||||
message = message
|
||||
elif isinstance(message, dict):
|
||||
notification_data = copy.deepcopy(message)
|
||||
notification_data.pop("type", None)
|
||||
notification = schemas.Notification(**notification_data)
|
||||
message_data = copy.deepcopy(message)
|
||||
message_data.pop("type", None)
|
||||
message = schemas.Message(**message_data)
|
||||
else:
|
||||
notification_data = copy.deepcopy(data)
|
||||
notification_data.pop("type", None)
|
||||
notification_data.pop("current_time", None)
|
||||
notification = schemas.Notification(**notification_data)
|
||||
message_data = copy.deepcopy(data)
|
||||
message_data.pop("type", None)
|
||||
message_data.pop("current_time", None)
|
||||
message = schemas.Message(**message_data)
|
||||
except Exception as err:
|
||||
logger.debug(f"解析WebAgent通知事件失败: {err}")
|
||||
return None
|
||||
|
||||
channel = notification.channel
|
||||
channel_value = channel.value if isinstance(channel, MessageChannel) else channel
|
||||
if channel_value != MessageChannel.WebAgent.value:
|
||||
channel = message.channel
|
||||
channel_value = channel.value if isinstance(channel, NotificationChannel) else channel
|
||||
if channel_value != NotificationChannel.WebAgent.value:
|
||||
return None
|
||||
return notification
|
||||
return message
|
||||
|
||||
|
||||
def _is_web_agent_notice_for_user(
|
||||
notification: schemas.Notification,
|
||||
def _is_web_agent_message_for_user(
|
||||
message: schemas.Message,
|
||||
user_id: str,
|
||||
) -> bool:
|
||||
"""
|
||||
判断 NoticeMessage 事件是否属于当前 WebAgent 用户。
|
||||
|
||||
:param notification: NoticeMessage 中的通知消息
|
||||
:param message: NoticeMessage 中的通知消息
|
||||
:param user_id: 当前登录用户 ID
|
||||
:return: 可被本次 WebAgent 请求消费时返回 True
|
||||
"""
|
||||
try:
|
||||
target_user = notification.userid
|
||||
target_user = message.userid
|
||||
return target_user is None or str(target_user) == str(user_id)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def _get_web_agent_notice_user_id(notification: schemas.Notification) -> Optional[str]:
|
||||
def _get_web_agent_message_user_id(message: schemas.Message) -> Optional[str]:
|
||||
"""
|
||||
从 NoticeMessage 事件中解析 WebAgent 目标用户。
|
||||
|
||||
:param notification: NoticeMessage 中的通知消息
|
||||
:param message: NoticeMessage 中的通知消息
|
||||
:return: 用户 ID 字符串,事件不属于 WebAgent 时返回 None
|
||||
"""
|
||||
try:
|
||||
channel = notification.channel
|
||||
channel_value = channel.value if isinstance(channel, MessageChannel) else channel
|
||||
if channel_value != MessageChannel.WebAgent.value:
|
||||
channel = message.channel
|
||||
channel_value = channel.value if isinstance(channel, NotificationChannel) else channel
|
||||
if channel_value != NotificationChannel.WebAgent.value:
|
||||
return None
|
||||
user_id = notification.userid
|
||||
user_id = message.userid
|
||||
return str(user_id) if user_id is not None else None
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def _dispatch_web_agent_notice_event(event: Event) -> None:
|
||||
def _dispatch_web_agent_message_event(event: Event) -> None:
|
||||
"""
|
||||
将 WebAgent NoticeMessage 分发给正在等待的请求队列。
|
||||
|
||||
:param event: NoticeMessage 广播事件
|
||||
"""
|
||||
data = event.event_data if isinstance(event.event_data, dict) else {}
|
||||
notification = _extract_web_agent_notification_from_event_data(data)
|
||||
if not notification:
|
||||
message = _extract_web_agent_message_from_event_data(data)
|
||||
if not message:
|
||||
return
|
||||
with _WEB_AGENT_NOTICE_LOCK:
|
||||
user_id = _get_web_agent_notice_user_id(notification)
|
||||
with _WEB_AGENT_MESSAGE_LOCK:
|
||||
user_id = _get_web_agent_message_user_id(message)
|
||||
if user_id is None:
|
||||
queues = [
|
||||
notice_queue
|
||||
for user_queues in _WEB_AGENT_NOTICE_QUEUES.values()
|
||||
for notice_queue in user_queues
|
||||
message_queue
|
||||
for user_queues in _WEB_AGENT_MESSAGE_QUEUES.values()
|
||||
for message_queue in user_queues
|
||||
]
|
||||
else:
|
||||
queues = list(_WEB_AGENT_NOTICE_QUEUES.get(user_id) or [])
|
||||
for notice_queue in queues:
|
||||
notice_queue.put(notification)
|
||||
queues = list(_WEB_AGENT_MESSAGE_QUEUES.get(user_id) or [])
|
||||
for message_queue in queues:
|
||||
message_queue.put(message)
|
||||
|
||||
|
||||
def _ensure_web_agent_notice_listener() -> None:
|
||||
def _ensure_web_agent_message_listener() -> None:
|
||||
"""
|
||||
确保 WebAgent NoticeMessage 全局监听器已注册。
|
||||
"""
|
||||
global _WEB_AGENT_NOTICE_LISTENER_REGISTERED
|
||||
if _WEB_AGENT_NOTICE_LISTENER_REGISTERED:
|
||||
global _WEB_AGENT_MESSAGE_LISTENER_REGISTERED
|
||||
if _WEB_AGENT_MESSAGE_LISTENER_REGISTERED:
|
||||
return
|
||||
with _WEB_AGENT_NOTICE_LOCK:
|
||||
if _WEB_AGENT_NOTICE_LISTENER_REGISTERED:
|
||||
with _WEB_AGENT_MESSAGE_LOCK:
|
||||
if _WEB_AGENT_MESSAGE_LISTENER_REGISTERED:
|
||||
return
|
||||
EventManager().add_event_listener(
|
||||
EventType.NoticeMessage,
|
||||
_dispatch_web_agent_notice_event,
|
||||
_dispatch_web_agent_message_event,
|
||||
)
|
||||
_WEB_AGENT_NOTICE_LISTENER_REGISTERED = True
|
||||
_WEB_AGENT_MESSAGE_LISTENER_REGISTERED = True
|
||||
|
||||
|
||||
def _attach_web_agent_notice_queue(user_id: str, notice_queue: Queue[schemas.Notification]) -> None:
|
||||
def _attach_web_agent_message_queue(user_id: str, message_queue: Queue[schemas.Message]) -> None:
|
||||
"""
|
||||
为当前 WebAgent 请求挂载通知收集队列。
|
||||
|
||||
:param user_id: 当前用户 ID
|
||||
:param notice_queue: 用于接收通知事件的队列
|
||||
:param message_queue: 用于接收通知事件的队列
|
||||
"""
|
||||
_ensure_web_agent_notice_listener()
|
||||
with _WEB_AGENT_NOTICE_LOCK:
|
||||
_WEB_AGENT_NOTICE_QUEUES.setdefault(str(user_id), []).append(notice_queue)
|
||||
_ensure_web_agent_message_listener()
|
||||
with _WEB_AGENT_MESSAGE_LOCK:
|
||||
_WEB_AGENT_MESSAGE_QUEUES.setdefault(str(user_id), []).append(message_queue)
|
||||
|
||||
|
||||
def _detach_web_agent_notice_queue(user_id: str, notice_queue: Queue[schemas.Notification]) -> None:
|
||||
def _detach_web_agent_message_queue(user_id: str, message_queue: Queue[schemas.Message]) -> None:
|
||||
"""
|
||||
移除当前 WebAgent 请求的通知收集队列。
|
||||
|
||||
:param user_id: 当前用户 ID
|
||||
:param notice_queue: 需要移除的队列
|
||||
:param message_queue: 需要移除的队列
|
||||
"""
|
||||
with _WEB_AGENT_NOTICE_LOCK:
|
||||
queues = _WEB_AGENT_NOTICE_QUEUES.get(str(user_id))
|
||||
with _WEB_AGENT_MESSAGE_LOCK:
|
||||
queues = _WEB_AGENT_MESSAGE_QUEUES.get(str(user_id))
|
||||
if not queues:
|
||||
return
|
||||
_WEB_AGENT_NOTICE_QUEUES[str(user_id)] = [
|
||||
item for item in queues if item is not notice_queue
|
||||
_WEB_AGENT_MESSAGE_QUEUES[str(user_id)] = [
|
||||
item for item in queues if item is not message_queue
|
||||
]
|
||||
if not _WEB_AGENT_NOTICE_QUEUES[str(user_id)]:
|
||||
_WEB_AGENT_NOTICE_QUEUES.pop(str(user_id), None)
|
||||
if not _WEB_AGENT_MESSAGE_QUEUES[str(user_id)]:
|
||||
_WEB_AGENT_MESSAGE_QUEUES.pop(str(user_id), None)
|
||||
|
||||
|
||||
def _build_web_agent_command_items() -> list[dict]:
|
||||
@@ -1387,16 +1387,16 @@ async def _collect_web_agent_traditional_events(
|
||||
:param original_chat_id: WebAgent 原聊天 ID
|
||||
:return: 可直接发送给前端的 SSE 事件列表
|
||||
"""
|
||||
notice_queue: Queue[schemas.Notification] = Queue()
|
||||
message_queue: Queue[schemas.Message] = Queue()
|
||||
edit_queue: Queue[dict] = Queue()
|
||||
user_id = str(current_user.id)
|
||||
|
||||
_attach_web_agent_notice_queue(user_id, notice_queue)
|
||||
_attach_web_agent_message_queue(user_id, message_queue)
|
||||
attach_web_agent_edit_queue(user_id, edit_queue)
|
||||
try:
|
||||
await run_in_threadpool(
|
||||
MessageChain().handle_message,
|
||||
channel=MessageChannel.WebAgent,
|
||||
channel=NotificationChannel.WebAgent,
|
||||
source=WEB_AGENT_SOURCE,
|
||||
userid=user_id,
|
||||
username=current_user.name or user_id,
|
||||
@@ -1424,19 +1424,19 @@ async def _collect_web_agent_traditional_events(
|
||||
wait_until = idle_deadline or deadline
|
||||
timeout = max(0.05, min(0.25, wait_until - now, deadline - now))
|
||||
try:
|
||||
notification = await asyncio.to_thread(notice_queue.get, True, timeout)
|
||||
message = await asyncio.to_thread(message_queue.get, True, timeout)
|
||||
except Empty:
|
||||
if idle_deadline and time.monotonic() >= idle_deadline:
|
||||
break
|
||||
continue
|
||||
|
||||
if not _is_web_agent_notice_for_user(notification, user_id):
|
||||
if not _is_web_agent_message_for_user(message, user_id):
|
||||
continue
|
||||
events.extend(_build_web_agent_notification_events(notification))
|
||||
events.extend(_build_web_agent_message_events(message))
|
||||
idle_deadline = time.monotonic() + WEB_AGENT_TRADITIONAL_IDLE_TIMEOUT_SECONDS
|
||||
return events
|
||||
finally:
|
||||
_detach_web_agent_notice_queue(user_id, notice_queue)
|
||||
_detach_web_agent_message_queue(user_id, message_queue)
|
||||
detach_web_agent_edit_queue(user_id, edit_queue)
|
||||
|
||||
|
||||
@@ -1884,7 +1884,7 @@ async def web_agent_stream(
|
||||
and agent_manager.matches_secret_confirmation(
|
||||
session_id,
|
||||
str(current_user.id),
|
||||
channel=MessageChannel.WebAgent.value,
|
||||
channel=NotificationChannel.WebAgent.value,
|
||||
source=WEB_AGENT_SOURCE,
|
||||
)
|
||||
)
|
||||
@@ -2099,11 +2099,11 @@ async def web_agent_stream(
|
||||
_apply_web_agent_display_event(item, assistant_display_message)
|
||||
event_publisher.publish(item)
|
||||
|
||||
def notification_callback(notification: schemas.Notification) -> None:
|
||||
def message_callback(message: schemas.Message) -> None:
|
||||
"""
|
||||
接收 Agent 工具主动发送的 Web 通知。
|
||||
"""
|
||||
for item in _build_web_agent_notification_events(notification):
|
||||
for item in _build_web_agent_message_events(message):
|
||||
_apply_web_agent_display_event(item, assistant_display_message)
|
||||
event_publisher.publish(item)
|
||||
|
||||
@@ -2139,7 +2139,7 @@ async def web_agent_stream(
|
||||
images=payload.images or [],
|
||||
files=files or None,
|
||||
has_audio_input=has_audio_input,
|
||||
channel=MessageChannel.WebAgent.value,
|
||||
channel=NotificationChannel.WebAgent.value,
|
||||
source=WEB_AGENT_SOURCE,
|
||||
username=current_user.name,
|
||||
reply_mode=ReplyMode.CAPTURE_ONLY,
|
||||
@@ -2150,7 +2150,7 @@ async def web_agent_stream(
|
||||
if protected_transport_supported
|
||||
else None
|
||||
),
|
||||
notification_callback=notification_callback,
|
||||
message_callback=message_callback,
|
||||
agent_factory=_WebAgentMoviePilotAgent,
|
||||
wait_for_completion=True,
|
||||
)
|
||||
|
||||
@@ -18,7 +18,7 @@ from app.api.openai_utils import (
|
||||
)
|
||||
from app.runtime.config import settings
|
||||
from app.application.security.access import anthropic_api_key_header
|
||||
from app.schemas.types import MessageChannel
|
||||
from app.schemas.types import NotificationChannel
|
||||
|
||||
ANTHROPIC_ERROR_RESPONSES = {
|
||||
400: {"model": schemas.AnthropicErrorResponse, "description": "请求格式错误"},
|
||||
@@ -145,7 +145,7 @@ async def messages(
|
||||
agent = _CollectingMoviePilotAgent(
|
||||
session_id=session_id,
|
||||
user_id=session_id,
|
||||
channel=MessageChannel.Web.value,
|
||||
channel=NotificationChannel.Web.value,
|
||||
source="anthropic",
|
||||
username="anthropic-client",
|
||||
stream_mode=payload.stream,
|
||||
|
||||
@@ -20,7 +20,7 @@ from app.api.deps import get_current_active_superuser
|
||||
from app.runtime.extensions.service_registry import ServiceConfigHelper
|
||||
from app.runtime.log import logger
|
||||
from app.adapters.external.wechat_crypt import WXBizMsgCrypt
|
||||
from app.schemas.types import MessageChannel, SystemConfigKey
|
||||
from app.schemas.types import NotificationChannel, SystemConfigKey
|
||||
|
||||
router = ResponseAPIRouter()
|
||||
|
||||
@@ -64,18 +64,18 @@ def _normalize_notification_clear_timestamp(value: Any) -> int:
|
||||
return normalized_value if normalized_value > 0 else 0
|
||||
|
||||
|
||||
def _get_notification_clear_before() -> schemas.NotificationClearBefore:
|
||||
def _get_notification_clear_before() -> schemas.MessageClearBefore:
|
||||
"""
|
||||
读取通知中心清理时间配置。
|
||||
"""
|
||||
value = SystemConfigOper().get(SystemConfigKey.NotificationClearBefore)
|
||||
if isinstance(value, dict):
|
||||
return schemas.NotificationClearBefore(
|
||||
return schemas.MessageClearBefore(
|
||||
all=_normalize_notification_clear_timestamp(value.get("all")),
|
||||
system=_normalize_notification_clear_timestamp(value.get("system")),
|
||||
media=_normalize_notification_clear_timestamp(value.get("media")),
|
||||
)
|
||||
return schemas.NotificationClearBefore(
|
||||
return schemas.MessageClearBefore(
|
||||
all=_normalize_notification_clear_timestamp(value),
|
||||
)
|
||||
|
||||
@@ -166,7 +166,7 @@ async def web_message(
|
||||
images = [images]
|
||||
|
||||
MessageChain().handle_message(
|
||||
channel=MessageChannel.Web,
|
||||
channel=NotificationChannel.Web,
|
||||
source=current_user.name,
|
||||
userid=current_user.name,
|
||||
username=current_user.name,
|
||||
@@ -197,7 +197,7 @@ async def get_web_message(
|
||||
return ret_messages
|
||||
|
||||
|
||||
@router.get("/notification", summary="获取通知消息", response_model=List[schemas.NotificationHistoryItem])
|
||||
@router.get("/notification", summary="获取通知消息", response_model=List[schemas.MessageHistoryItem])
|
||||
async def get_notification_message(
|
||||
_: schemas.TokenPayload = Depends(verify_token),
|
||||
db: AsyncSession = Depends(get_async_db),
|
||||
@@ -215,16 +215,16 @@ async def get_notification_message(
|
||||
system_clear_before=_format_notification_clear_time(clear_before.system),
|
||||
media_clear_before=_format_notification_clear_time(clear_before.media),
|
||||
)
|
||||
return [schemas.NotificationHistoryItem(**message.to_dict()) for message in messages]
|
||||
return [schemas.MessageHistoryItem(**message.to_dict()) for message in messages]
|
||||
|
||||
|
||||
@router.delete(
|
||||
"/notification",
|
||||
summary="清理通知消息",
|
||||
response_model=schemas.Response[schemas.NotificationClearData],
|
||||
response_model=schemas.Response[schemas.MessageClearData],
|
||||
)
|
||||
async def clear_notification_message(
|
||||
scope: schemas.NotificationClearScope = schemas.NotificationClearScope.All,
|
||||
scope: schemas.MessageClearScope = schemas.MessageClearScope.All,
|
||||
_: schemas.TokenPayload = Depends(verify_token),
|
||||
):
|
||||
"""
|
||||
|
||||
@@ -19,7 +19,7 @@ from app.agent.callback import StreamingHandler
|
||||
from app.agent.orchestrator import MoviePilotAgent
|
||||
from app.runtime.config import settings
|
||||
from app.application.security.access import openai_bearer_scheme
|
||||
from app.schemas.types import MessageChannel
|
||||
from app.schemas.types import NotificationChannel
|
||||
|
||||
OPENAI_ERROR_RESPONSES = {
|
||||
400: {"model": schemas.OpenAIErrorResponse, "description": "请求格式错误"},
|
||||
@@ -341,7 +341,7 @@ async def chat_completions(
|
||||
agent = _CollectingMoviePilotAgent(
|
||||
session_id=session_id,
|
||||
user_id=session_key,
|
||||
channel=MessageChannel.Web.value,
|
||||
channel=NotificationChannel.Web.value,
|
||||
source="openai",
|
||||
username=username,
|
||||
stream_mode=payload.stream,
|
||||
@@ -434,7 +434,7 @@ async def responses(
|
||||
agent = _CollectingMoviePilotAgent(
|
||||
session_id=session_id,
|
||||
user_id=session_key,
|
||||
channel=MessageChannel.Web.value,
|
||||
channel=NotificationChannel.Web.value,
|
||||
source="openai.responses",
|
||||
username=str(payload.user or "openai-client"),
|
||||
stream_mode=False,
|
||||
|
||||
Reference in New Issue
Block a user