| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 |
- import sonnerMessage from '@/components/ui/message';
- import { MessageType } from '@/constants/chat';
- import {
- useHandleMessageInputChange,
- useSelectDerivedMessages,
- } from '@/hooks/logic-hooks';
- import {
- IEventList,
- IInputEvent,
- IMessageEndData,
- IMessageEndEvent,
- IMessageEvent,
- MessageEventType,
- useSendMessageBySSE,
- } from '@/hooks/use-send-message';
- import { Message } from '@/interfaces/database/chat';
- import i18n from '@/locales/config';
- import api from '@/utils/api';
- import { get } from 'lodash';
- import trim from 'lodash/trim';
- import { useCallback, useContext, useEffect, useMemo, useState } from 'react';
- import { useParams } from 'umi';
- import { v4 as uuid } from 'uuid';
- import { BeginId } from '../constant';
- import { AgentChatLogContext } from '../context';
- import { transferInputsArrayToObject } from '../form/begin-form/use-watch-change';
- import { useSelectBeginNodeDataInputs } from '../hooks/use-get-begin-query';
- import { BeginQuery } from '../interface';
- import useGraphStore from '../store';
- import { receiveMessageError } from '../utils';
-
- export function findMessageFromList(eventList: IEventList) {
- const messageEventList = eventList.filter(
- (x) => x.event === MessageEventType.Message,
- ) as IMessageEvent[];
-
- let nextContent = '';
-
- let startIndex = -1;
- let endIndex = -1;
-
- messageEventList.forEach((x, idx) => {
- const { data } = x;
- const { content, start_to_think, end_to_think } = data;
- if (start_to_think === true) {
- nextContent += '<think>' + content;
- startIndex = idx;
- return;
- }
-
- if (end_to_think === true) {
- endIndex = idx;
- nextContent += content + '</think>';
- return;
- }
-
- nextContent += content;
- });
-
- const currentIdx = messageEventList.length - 1;
-
- // Make sure that after start_to_think === true and before end_to_think === true, add a </think> tag at the end.
- if (startIndex >= 0 && startIndex <= currentIdx && endIndex === -1) {
- nextContent += '</think>';
- }
-
- return {
- id: eventList[0]?.message_id,
- content: nextContent,
- };
- }
-
- export function findInputFromList(eventList: IEventList) {
- const inputEvent = eventList.find(
- (x) => x.event === MessageEventType.UserInputs,
- ) as IInputEvent;
-
- if (!inputEvent) {
- return {};
- }
-
- return {
- id: inputEvent?.message_id,
- data: inputEvent?.data,
- };
- }
-
- export function getLatestError(eventList: IEventList) {
- return get(eventList.at(-1), 'data.outputs._ERROR');
- }
-
- export const useGetBeginNodePrologue = () => {
- const getNode = useGraphStore((state) => state.getNode);
-
- return useMemo(() => {
- const formData = get(getNode(BeginId), 'data.form', {});
- if (formData?.enablePrologue) {
- return formData?.prologue;
- }
- }, [getNode]);
- };
-
- export function useFindMessageReference(answerList: IEventList) {
- const [messageEndEventList, setMessageEndEventList] = useState<
- IMessageEndEvent[]
- >([]);
-
- const findReferenceByMessageId = useCallback(
- (messageId: string) => {
- const event = messageEndEventList.find(
- (item) => item.message_id === messageId,
- );
- if (event) {
- return (event?.data as IMessageEndData)?.reference;
- }
- },
- [messageEndEventList],
- );
-
- useEffect(() => {
- const messageEndEvent = answerList.find(
- (x) => x.event === MessageEventType.MessageEnd,
- );
- if (messageEndEvent) {
- setMessageEndEventList((list) => {
- const nextList = [...list];
- if (
- nextList.every((x) => x.message_id !== messageEndEvent.message_id)
- ) {
- nextList.push(messageEndEvent as IMessageEndEvent);
- }
- return nextList;
- });
- }
- }, [answerList]);
-
- return { findReferenceByMessageId };
- }
-
- interface UploadResponseDataType {
- created_at: number;
- created_by: string;
- extension: string;
- id: string;
- mime_type: string;
- name: string;
- preview_url: null;
- size: number;
- }
-
- export function useSetUploadResponseData() {
- const [uploadResponseList, setUploadResponseList] = useState<
- UploadResponseDataType[]
- >([]);
- const [fileList, setFileList] = useState<File[]>([]);
-
- const append = useCallback((data: UploadResponseDataType, files: File[]) => {
- setUploadResponseList((prev) => [...prev, data]);
- setFileList((pre) => [...pre, ...files]);
- }, []);
-
- const clear = useCallback(() => {
- setUploadResponseList([]);
- setFileList([]);
- }, []);
-
- return {
- uploadResponseList,
- fileList,
- setUploadResponseList,
- appendUploadResponseList: append,
- clearUploadResponseList: clear,
- };
- }
-
- export const useSendAgentMessage = (
- url?: string,
- addEventList?: (data: IEventList, messageId: string) => void,
- beginParams?: any[],
- ) => {
- const { id: agentId } = useParams();
- const { handleInputChange, value, setValue } = useHandleMessageInputChange();
- const inputs = useSelectBeginNodeDataInputs();
- const [sessionId, setSessionId] = useState<string | null>(null);
- const { send, answerList, done, stopOutputMessage, resetAnswerList } =
- useSendMessageBySSE(url || api.runCanvas);
- const messageId = useMemo(() => {
- return answerList[0]?.message_id;
- }, [answerList]);
-
- useEffect(() => {
- if (answerList[0]?.session_id) {
- setSessionId(answerList[0]?.session_id);
- }
- }, [answerList]);
-
- const { findReferenceByMessageId } = useFindMessageReference(answerList);
- const prologue = useGetBeginNodePrologue();
- const {
- derivedMessages,
- scrollRef,
- messageContainerRef,
- removeLatestMessage,
- removeMessageById,
- addNewestOneQuestion,
- addNewestOneAnswer,
- removeAllMessages,
- scrollToBottom,
- } = useSelectDerivedMessages();
- const { addEventList: addEventListFun } = useContext(AgentChatLogContext);
- const {
- appendUploadResponseList,
- clearUploadResponseList,
- uploadResponseList,
- fileList,
- } = useSetUploadResponseData();
-
- const sendMessage = useCallback(
- async ({ message }: { message: Message; messages?: Message[] }) => {
- const params: Record<string, unknown> = {
- id: agentId,
- };
-
- params.running_hint_text = i18n.t('flow.runningHintText', {
- defaultValue: 'is running...🕞',
- });
- if (message.content) {
- const query = inputs;
-
- params.query = message.content;
- // params.message_id = message.id;
- params.inputs = transferInputsArrayToObject(
- beginParams ? beginParams : query,
- ); // begin operator inputs
-
- params.files = uploadResponseList;
-
- params.session_id = sessionId;
- }
-
- try {
- const res = await send(params);
-
- clearUploadResponseList();
-
- if (receiveMessageError(res)) {
- sonnerMessage.error(res?.data?.message);
-
- // cancel loading
- setValue(message.content);
- removeLatestMessage();
- } else {
- // refetch(); // pull the message list after sending the message successfully
- }
- } catch (error) {
- console.log('🚀 ~ useSendAgentMessage ~ error:', error);
- }
- },
- [
- agentId,
- sessionId,
- send,
- clearUploadResponseList,
- inputs,
- beginParams,
- uploadResponseList,
- setValue,
- removeLatestMessage,
- ],
- );
-
- const sendFormMessage = useCallback(
- (body: { id?: string; inputs: Record<string, BeginQuery> }) => {
- send({ ...body, session_id: sessionId });
- addNewestOneQuestion({
- content: Object.entries(body.inputs)
- .map(([key, val]) => `${key}: ${val.value}`)
- .join('<br/>'),
- role: MessageType.User,
- });
- },
- [addNewestOneQuestion, send, sessionId],
- );
-
- // reset session
- const resetSession = useCallback(() => {
- stopOutputMessage();
- resetAnswerList();
- setSessionId(null);
- removeAllMessages();
- }, [resetAnswerList, removeAllMessages, stopOutputMessage]);
-
- const handlePressEnter = useCallback(() => {
- if (trim(value) === '') return;
- const id = uuid();
- const msgBody = {
- id,
- content: value.trim(),
- role: MessageType.User,
- };
- if (done) {
- setValue('');
- sendMessage({
- message: msgBody,
- });
- }
- addNewestOneQuestion({ ...msgBody, files: fileList });
- setTimeout(() => {
- scrollToBottom();
- }, 100);
- }, [
- value,
- done,
- addNewestOneQuestion,
- fileList,
- setValue,
- sendMessage,
- scrollToBottom,
- ]);
-
- useEffect(() => {
- const { content, id } = findMessageFromList(answerList);
- const inputAnswer = findInputFromList(answerList);
- if (answerList.length > 0) {
- addNewestOneAnswer({
- answer: content || getLatestError(answerList),
- id: id,
- ...inputAnswer,
- });
- }
- }, [answerList, addNewestOneAnswer]);
-
- useEffect(() => {
- if (prologue) {
- addNewestOneAnswer({
- answer: prologue,
- });
- }
- }, [addNewestOneAnswer, agentId, prologue, send, sendFormMessage]);
-
- useEffect(() => {
- if (typeof addEventList === 'function') {
- addEventList(answerList, messageId);
- } else if (typeof addEventListFun === 'function') {
- addEventListFun(answerList, messageId);
- }
- }, [addEventList, answerList, addEventListFun, messageId]);
-
- return {
- value,
- sendLoading: !done,
- derivedMessages,
- scrollRef,
- messageContainerRef,
- handlePressEnter,
- handleInputChange,
- removeMessageById,
- stopOutputMessage,
- send,
- sendFormMessage,
- resetSession,
- findReferenceByMessageId,
- appendUploadResponseList,
- addNewestOneAnswer,
- };
- };
|