fix: decouple thread summary update (#1994)

This commit is contained in:
Louis 2024-02-11 20:22:12 +07:00 committed by GitHub
parent bcf6103da3
commit ac18fc1181
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -14,6 +14,7 @@ import {
MessageEvent, MessageEvent,
MessageRequestType, MessageRequestType,
ModelEvent, ModelEvent,
Thread,
} from '@janhq/core' } from '@janhq/core'
import { useAtomValue, useSetAtom } from 'jotai' import { useAtomValue, useSetAtom } from 'jotai'
import { ulid } from 'ulid' import { ulid } from 'ulid'
@ -80,39 +81,7 @@ export default function EventHandler({ children }: { children: ReactNode }) {
const onNewMessageResponse = useCallback( const onNewMessageResponse = useCallback(
(message: ThreadMessage) => { (message: ThreadMessage) => {
const thread = threadsRef.current?.find((e) => e.id == message.thread_id) if (message.type === MessageRequestType.Thread) {
// If this is the first ever prompt in the thread
if (thread && thread.title.trim() == 'New Thread') {
// This is the first time message comes in on a new thread
// Summarize the first message, and make that the title of the Thread
// 1. Get the summary of the first prompt using whatever engine user is currently using
const firstPrompt = messagesRef?.current[0].content[0].text.value.trim()
const summarizeFirstPrompt =
'Summarize "' + firstPrompt + '" in 5 words as a title'
// Prompt: Given this query from user {query}, return to me the summary in 5 words as the title
const msgId = ulid()
const messages: ChatCompletionMessage[] = [
{
role: ChatCompletionRole.User,
content: summarizeFirstPrompt,
} as ChatCompletionMessage,
]
const firstPromptRequest: MessageRequest = {
id: msgId,
threadId: message.thread_id,
type: MessageRequestType.Summary,
messages,
model: activeModelRef?.current,
}
// 2. Update the title with the result of the inference
// the title will be updated as part of the `EventName.OnFirstPromptUpdate`
events.emit(MessageEvent.OnMessageSent, firstPromptRequest)
}
if (message.type !== MessageRequestType.Summary) {
addNewMessage(message) addNewMessage(message)
} }
}, },
@ -158,7 +127,34 @@ export default function EventHandler({ children }: { children: ReactNode }) {
[setStateModel, setQueuedMessage, setLoadModelError] [setStateModel, setQueuedMessage, setLoadModelError]
) )
const onMessageResponseUpdate = useCallback( const updateThreadTitle = useCallback(
(message: ThreadMessage) => {
// Update only when it's finished
if (message.status === MessageStatus.Pending) {
return
}
const thread = threadsRef.current?.find((e) => e.id == message.thread_id)
const messageContent = message.content[0]?.text?.value
if (thread && messageContent) {
// Update the Thread title with the response of the inference on the 1st prompt
updateThread({
...thread,
title: messageContent,
metadata: thread.metadata,
})
extensionManager
.get<ConversationalExtension>(ExtensionTypeEnum.Conversational)
?.saveThread({
...thread,
})
}
},
[updateThread]
)
const updateThreadMessage = useCallback(
(message: ThreadMessage) => { (message: ThreadMessage) => {
updateMessage( updateMessage(
message.id, message.id,
@ -186,11 +182,6 @@ export default function EventHandler({ children }: { children: ReactNode }) {
...(messageContent && { lastMessage: messageContent }), ...(messageContent && { lastMessage: messageContent }),
} }
// Update the Thread title with the response of the inference on the 1st prompt
if (message.type === MessageRequestType.Summary) {
thread.title = messageContent
}
updateThread({ updateThread({
...thread, ...thread,
metadata, metadata,
@ -204,16 +195,79 @@ export default function EventHandler({ children }: { children: ReactNode }) {
}) })
// If this is not the summary of the Thread, don't need to add it to the Thread // If this is not the summary of the Thread, don't need to add it to the Thread
if (message.type !== MessageRequestType.Summary) { extensionManager
extensionManager .get<ConversationalExtension>(ExtensionTypeEnum.Conversational)
.get<ConversationalExtension>(ExtensionTypeEnum.Conversational) ?.addNewMessage(message)
?.addNewMessage(message)
} // Attempt to generate the title of the Thread when needed
generateThreadTitle(message, thread)
} }
}, },
[updateMessage, updateThreadWaiting, setIsGeneratingResponse, updateThread] [setIsGeneratingResponse, updateMessage, updateThread, updateThreadWaiting]
) )
const onMessageResponseUpdate = useCallback(
(message: ThreadMessage) => {
switch (message.type) {
case MessageRequestType.Summary:
updateThreadTitle(message)
break
default:
updateThreadMessage(message)
}
},
[updateThreadMessage, updateThreadTitle]
)
const generateThreadTitle = (message: ThreadMessage, thread: Thread) => {
// If this is the first ever prompt in the thread
if (
thread &&
thread.title?.trim() === 'New Thread' &&
activeModelRef.current
) {
// This is the first time message comes in on a new thread
// Summarize the first message, and make that the title of the Thread
// 1. Get the summary of the first prompt using whatever engine user is currently using
const threadMessages = messagesRef?.current
const summarizeFirstPrompt =
'Summarize the conversation above in 5 words as a title'
// Prompt: Given this query from user {query}, return to me the summary in 5 words as the title
const msgId = ulid()
const messages: ChatCompletionMessage[] = [
...threadMessages.map((msg) => {
return {
role: msg.role,
content: msg.content[0]?.text.value,
}
}),
{
role: ChatCompletionRole.User,
content: summarizeFirstPrompt,
} as ChatCompletionMessage,
]
const firstPromptRequest: MessageRequest = {
id: msgId,
threadId: message.thread_id,
type: MessageRequestType.Summary,
messages,
model: {
...activeModelRef.current,
parameters: {
stream: false,
},
},
}
// 2. Update the title with the result of the inference
setTimeout(() => {
events.emit(MessageEvent.OnMessageSent, firstPromptRequest)
}, 1000)
}
}
useEffect(() => { useEffect(() => {
console.log('Registering events') console.log('Registering events')
if (window.core?.events) { if (window.core?.events) {