Files
docs/plugins/docuservix/hooks/useChat.ts
T
2026-06-18 14:42:26 +03:00

89 lines
2.6 KiB
TypeScript

import { useLocation } from '@docusaurus/router';
import { useCallback, useEffect, useRef, useState } from 'react';
import { useOptions } from '@docuservix/hooks/useOptions';
import { IChat, IChatMessage, IChatSource } from '@docuservix/models/chat';
interface UseChatResult {
dialog: IChat;
typing: boolean;
statusMessage?: string;
sendMessage: (text: string) => void;
}
function useQuery(): string {
const location = useLocation();
const params = new URLSearchParams(location.search);
return params.get('q') ?? '';
}
export function useChat(): UseChatResult {
const chatEndpoint = useOptions().api + '/chat';
const urlQuery = useQuery();
const [messages, setMessages] = useState<IChatMessage[]>([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const initialSentRef = useRef(false);
const messagesEndRef = useRef(messages);
messagesEndRef.current = messages;
const sendMessage = useCallback(
async (text: string) => {
const content = text.trim();
if (!content) {
return;
}
const userMessage: IChatMessage = { role: 'user', content };
const newHistory = [...messagesEndRef.current, userMessage];
setMessages(newHistory);
setLoading(true);
setError(null);
try {
const res = await fetch(chatEndpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ messages: newHistory }),
});
if (!res.ok) {
throw new Error(`HTTP ${res.status}`);
}
const data: { answer: string; sources?: IChatSource[] } = await res.json();
setMessages((prev) => [
...prev,
{ role: 'assistant', content: data.answer, sources: data.sources },
]);
} catch (err) {
setError(err instanceof Error ? err.message : 'Ошибка при обращении к серверу');
} finally {
setLoading(false);
}
},
[chatEndpoint],
);
useEffect(() => {
if (urlQuery && !initialSentRef.current) {
initialSentRef.current = true;
sendMessage(urlQuery);
}
}, [urlQuery, sendMessage]);
return {
dialog: { messages },
typing: loading,
statusMessage: error ?? undefined,
sendMessage,
};
}