| 32 | } |
| 33 | |
| 34 | export function useMessageQueue({ |
| 35 | pageId, |
| 36 | isStreaming, |
| 37 | onSendMessage |
| 38 | }: UseMessageQueueOptions): UseMessageQueueResult { |
| 39 | const { getQueue, addItem, removeItem, updateItem, clearQueue, shiftItem, pause, resume, init } = |
| 40 | useMessageQueueStore() |
| 41 | |
| 42 | const queue = getQueue(pageId) |
| 43 | const items = useMemo(() => queue.items, [queue.items]) |
| 44 | const count = items.length |
| 45 | const isPaused = queue.paused |
| 46 | |
| 47 | // 初始化 store |
| 48 | useEffect(() => { |
| 49 | init() |
| 50 | }, [init]) |
| 51 | |
| 52 | // 追踪上一次的 isStreaming 状态 |
| 53 | const prevStreamingRef = useRef(isStreaming) |
| 54 | // 是否正在处理队列(防止重复触发) |
| 55 | const processingRef = useRef(false) |
| 56 | |
| 57 | // 监听 streaming 结束,自动处理队列 |
| 58 | useEffect(() => { |
| 59 | const wasStreaming = prevStreamingRef.current |
| 60 | prevStreamingRef.current = isStreaming |
| 61 | |
| 62 | // streaming 从 true 变为 false 时 |
| 63 | if (wasStreaming && !isStreaming && !processingRef.current) { |
| 64 | // 直接从 store 获取最新状态,避免闭包问题 |
| 65 | const currentQueue = useMessageQueueStore.getState().getQueue(pageId) |
| 66 | // 如果未暂停且队列有内容,自动处理下一条 |
| 67 | if (!currentQueue.paused && currentQueue.items.length > 0) { |
| 68 | processingRef.current = true |
| 69 | shiftItem(pageId).then((item) => { |
| 70 | if (item) { |
| 71 | onSendMessage(item.content).finally(() => { |
| 72 | processingRef.current = false |
| 73 | }) |
| 74 | } else { |
| 75 | processingRef.current = false |
| 76 | } |
| 77 | }) |
| 78 | } |
| 79 | } |
| 80 | }, [isStreaming, pageId, shiftItem, onSendMessage]) |
| 81 | |
| 82 | const enqueue = useCallback( |
| 83 | async (content: string) => { |
| 84 | await addItem(pageId, content) |
| 85 | }, |
| 86 | [pageId, addItem] |
| 87 | ) |
| 88 | |
| 89 | const remove = useCallback( |
| 90 | async (itemId: string) => { |
| 91 | await removeItem(pageId, itemId) |