"""SSE generator 辅助. 提供 ping / retry / error 处理.""" from __future__ import annotations import asyncio import json import logging from collections.abc import AsyncIterator from app.streaming.events import sse_format, sse_heartbeat logger = logging.getLogger(__name__) async def heartbeat_pinger(interval: float = 15.0) -> AsyncIterator[str]: """无限流式发送 SSE 注释保活. 配合 `asyncio.Queue` 一起使用.""" try: while True: await asyncio.sleep(interval) yield sse_heartbeat() except asyncio.CancelledError: return async def event_stream( queue: asyncio.Queue[tuple[str, dict] | None], ) -> AsyncIterator[str]: """从 asyncio.Queue 读取事件并序列化为 SSE. 收到 None 表示结束.""" while True: item = await queue.get() if item is None: break event, data = item yield sse_format(event, data) def safe_json(data: dict) -> str: """防御性 JSON 序列化.""" return json.dumps(data, ensure_ascii=False, default=str)