aura-web/src/pages/chat/hooks/useChatData.ts

125 lines
3.3 KiB
TypeScript

import { useEffect, useRef, useState } from 'react';
import type { Agent, BranchInfo, ChatMessage, ModelOverrides } from '../../../api';
import { AgentAPI, ChatAPI } from '../../../api';
import { useAuth } from '../../../store/auth';
import { parseAgentModels } from '../utils/agentModels';
export function useChatData(args: {
agentId?: string;
roomId: string | null;
highlightId: string | null;
setHighlightId: (v: string | null) => void;
scrollBottom: (force?: boolean) => void;
initialScrollDoneRef: { current: boolean };
setOverrides: (updater: (prev: ModelOverrides) => ModelOverrides) => void;
abort: () => void;
}) {
const { user } = useAuth();
const { agentId, roomId, highlightId, setHighlightId, scrollBottom, initialScrollDoneRef, setOverrides, abort } = args;
const [agent, setAgent] = useState<Agent | null>(null);
const [agentList, setAgentList] = useState<Agent[]>([]);
const [messages, setMessages] = useState<ChatMessage[]>([]);
const [branches, setBranches] = useState<Record<string, BranchInfo>>({});
const loadSeqRef = useRef(0);
const loadAgent = async () => {
if (!agentId) {
setAgent(null);
setMessages([]);
return;
}
const a = await AgentAPI.detail(agentId);
setAgent(a);
const models = parseAgentModels(a.model);
const firstModel = models[0];
if (firstModel) {
setOverrides((o) => ({
...o,
model: o.model || firstModel.name,
model_id: o.model_id || firstModel.id
}));
}
};
const loadAgentList = async () => {
if (!user?.phone) return;
try {
const list = await AgentAPI.list(user.phone);
setAgentList(list);
} catch {
// ignore
}
};
const loadMessages = async () => {
if (!roomId) return;
const seq = ++loadSeqRef.current;
const rid = roomId;
const his = await ChatAPI.history(rid);
if (seq !== loadSeqRef.current) return;
if (rid !== roomId) return;
setMessages(Array.isArray(his.messages) ? his.messages : []);
setBranches(his.branches || {});
const checkScroll = () => {
if (!initialScrollDoneRef.current) {
scrollBottom(true);
initialScrollDoneRef.current = true;
} else {
scrollBottom();
}
};
requestAnimationFrame(checkScroll);
setTimeout(checkScroll, 100);
setTimeout(checkScroll, 500);
};
useEffect(() => {
loadAgentList();
}, [user?.phone]);
useEffect(() => {
if (!agentId) {
setAgent(null);
setMessages([]);
setBranches({});
setOverrides(() => ({}));
return abort;
}
setMessages([]);
setBranches({});
loadAgent();
setOverrides(() => ({}));
return abort;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [agentId]);
useEffect(() => {
initialScrollDoneRef.current = false;
}, [agentId, roomId]);
useEffect(() => {
if (!roomId) return;
loadMessages();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [roomId]);
useEffect(() => {
if (!highlightId) return;
const el = document.getElementById('msg-' + highlightId);
if (!el) return;
el.scrollIntoView({ behavior: 'smooth', block: 'start' });
}, [highlightId]);
return {
agent,
agentList,
messages,
setMessages,
branches,
setBranches,
loadMessages
};
}