125 lines
3.3 KiB
TypeScript
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
|
|
};
|
|
}
|