|
import { v4 } from 'uuid'; |
|
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'; |
|
import { parseConvo, getResponseSender } from 'librechat-data-provider'; |
|
import type { TMessage, TSubmission, TEndpointOption } from 'librechat-data-provider'; |
|
import type { TAskFunction } from '~/common'; |
|
import useUserKey from './useUserKey'; |
|
import store from '~/store'; |
|
|
|
const useMessageHandler = () => { |
|
const [latestMessage, setLatestMessage] = useRecoilState(store.latestMessage); |
|
const setSiblingIdx = useSetRecoilState( |
|
store.messagesSiblingIdxFamily(latestMessage?.parentMessageId), |
|
); |
|
const currentConversation = useRecoilValue(store.conversation) || { endpoint: null }; |
|
const setSubmission = useSetRecoilState(store.submission); |
|
const isSubmitting = useRecoilValue(store.isSubmitting); |
|
const endpointsConfig = useRecoilValue(store.endpointsConfig); |
|
const [messages, setMessages] = useRecoilState(store.messages); |
|
const { endpoint } = currentConversation; |
|
const { getExpiry } = useUserKey(endpoint ?? ''); |
|
|
|
const ask: TAskFunction = ( |
|
{ text, parentMessageId = null, conversationId = null, messageId = null }, |
|
{ |
|
editedText = null, |
|
editedMessageId = null, |
|
isRegenerate = false, |
|
isContinued = false, |
|
isEdited = false, |
|
} = {}, |
|
) => { |
|
if (!!isSubmitting || text === '') { |
|
return; |
|
} |
|
|
|
if (endpoint === null) { |
|
console.error('No endpoint available'); |
|
return; |
|
} |
|
|
|
conversationId = conversationId ?? currentConversation?.conversationId; |
|
if (conversationId == 'search') { |
|
console.error('cannot send any message under search view!'); |
|
return; |
|
} |
|
|
|
if (isContinued && !latestMessage) { |
|
console.error('cannot continue AI message without latestMessage!'); |
|
return; |
|
} |
|
|
|
const isEditOrContinue = isEdited || isContinued; |
|
|
|
|
|
const convo = parseConvo(endpoint, currentConversation); |
|
const endpointOption = { |
|
...convo, |
|
endpoint, |
|
key: getExpiry(), |
|
} as TEndpointOption; |
|
const responseSender = getResponseSender(endpointOption); |
|
|
|
let currentMessages: TMessage[] | null = messages ?? []; |
|
|
|
|
|
|
|
text = text.trim(); |
|
const fakeMessageId = v4(); |
|
parentMessageId = |
|
parentMessageId || latestMessage?.messageId || '00000000-0000-0000-0000-000000000000'; |
|
|
|
if (conversationId == 'new') { |
|
parentMessageId = '00000000-0000-0000-0000-000000000000'; |
|
currentMessages = []; |
|
conversationId = null; |
|
} |
|
const currentMsg: TMessage = { |
|
sender: 'User', |
|
text, |
|
current: true, |
|
isCreatedByUser: true, |
|
parentMessageId, |
|
conversationId, |
|
messageId: isContinued && messageId ? messageId : fakeMessageId, |
|
error: false, |
|
}; |
|
|
|
|
|
const generation = editedText ?? latestMessage?.text ?? ''; |
|
const responseText = isEditOrContinue |
|
? generation |
|
: '<span className="result-streaming">β</span>'; |
|
|
|
const responseMessageId = editedMessageId ?? latestMessage?.messageId ?? null; |
|
const initialResponse: TMessage = { |
|
sender: responseSender, |
|
text: responseText, |
|
parentMessageId: isRegenerate ? messageId : fakeMessageId, |
|
messageId: responseMessageId ?? `${isRegenerate ? messageId : fakeMessageId}_`, |
|
conversationId, |
|
unfinished: false, |
|
submitting: true, |
|
isCreatedByUser: false, |
|
isEdited: isEditOrContinue, |
|
error: false, |
|
}; |
|
|
|
if (isContinued) { |
|
currentMessages = currentMessages.filter((msg) => msg.messageId !== responseMessageId); |
|
} |
|
|
|
const submission: TSubmission = { |
|
conversation: { |
|
...currentConversation, |
|
conversationId, |
|
}, |
|
endpointOption, |
|
message: { |
|
...currentMsg, |
|
generation, |
|
responseMessageId, |
|
overrideParentMessageId: isRegenerate ? messageId : null, |
|
}, |
|
messages: currentMessages, |
|
isEdited: isEditOrContinue, |
|
isContinued, |
|
isRegenerate, |
|
initialResponse, |
|
}; |
|
|
|
if (isRegenerate) { |
|
setMessages([...submission.messages, initialResponse]); |
|
} else { |
|
setMessages([...submission.messages, currentMsg, initialResponse]); |
|
} |
|
setLatestMessage(initialResponse); |
|
setSubmission(submission); |
|
}; |
|
|
|
const regenerate = ({ parentMessageId }) => { |
|
const parentMessage = messages?.find((element) => element.messageId == parentMessageId); |
|
|
|
if (parentMessage && parentMessage.isCreatedByUser) { |
|
ask({ ...parentMessage }, { isRegenerate: true }); |
|
} else { |
|
console.error( |
|
'Failed to regenerate the message: parentMessage not found or not created by user.', |
|
); |
|
} |
|
}; |
|
|
|
const continueGeneration = () => { |
|
if (!latestMessage) { |
|
console.error('Failed to regenerate the message: latestMessage not found.'); |
|
return; |
|
} |
|
|
|
const parentMessage = messages?.find( |
|
(element) => element.messageId == latestMessage.parentMessageId, |
|
); |
|
|
|
if (parentMessage && parentMessage.isCreatedByUser) { |
|
ask({ ...parentMessage }, { isContinued: true, isRegenerate: true, isEdited: true }); |
|
} else { |
|
console.error( |
|
'Failed to regenerate the message: parentMessage not found, or not created by user.', |
|
); |
|
} |
|
}; |
|
|
|
const stopGenerating = () => { |
|
setSubmission(null); |
|
}; |
|
|
|
const handleStopGenerating = (e: React.MouseEvent<HTMLButtonElement>) => { |
|
e.preventDefault(); |
|
stopGenerating(); |
|
}; |
|
|
|
const handleRegenerate = (e: React.MouseEvent<HTMLButtonElement>) => { |
|
e.preventDefault(); |
|
const parentMessageId = latestMessage?.parentMessageId; |
|
if (!parentMessageId) { |
|
console.error('Failed to regenerate the message: parentMessageId not found.'); |
|
return; |
|
} |
|
regenerate({ parentMessageId }); |
|
}; |
|
|
|
const handleContinue = (e: React.MouseEvent<HTMLButtonElement>) => { |
|
e.preventDefault(); |
|
continueGeneration(); |
|
setSiblingIdx(0); |
|
}; |
|
|
|
return { |
|
ask, |
|
regenerate, |
|
stopGenerating, |
|
handleStopGenerating, |
|
handleRegenerate, |
|
handleContinue, |
|
endpointsConfig, |
|
latestMessage, |
|
isSubmitting, |
|
messages, |
|
}; |
|
}; |
|
|
|
export default useMessageHandler; |
|
|