100 lines
3.1 KiB
TypeScript
100 lines
3.1 KiB
TypeScript
import {
|
|
ChatCompletionRole,
|
|
ChatCompletionMessage,
|
|
EventName,
|
|
MessageRequest,
|
|
MessageStatus,
|
|
PluginType,
|
|
ThreadMessage,
|
|
events,
|
|
} from '@janhq/core'
|
|
import { ConversationalPlugin, InferencePlugin } from '@janhq/core/lib/plugins'
|
|
import { useAtomValue, useSetAtom } from 'jotai'
|
|
import { RefreshCcw, ClipboardCopy, Trash2Icon, StopCircle } from 'lucide-react'
|
|
|
|
import { toaster } from '@/containers/Toast'
|
|
|
|
import {
|
|
deleteMessage,
|
|
getCurrentChatMessagesAtom,
|
|
} from '@/helpers/atoms/ChatMessage.atom'
|
|
import { currentConversationAtom } from '@/helpers/atoms/Conversation.atom'
|
|
import { pluginManager } from '@/plugin'
|
|
|
|
const MessageToolbar = ({ message }: { message: ThreadMessage }) => {
|
|
const deleteAMessage = useSetAtom(deleteMessage)
|
|
const thread = useAtomValue(currentConversationAtom)
|
|
const messages = useAtomValue(getCurrentChatMessagesAtom)
|
|
const stopInference = async () => {
|
|
await pluginManager
|
|
.get<InferencePlugin>(PluginType.Inference)
|
|
?.stopInference()
|
|
setTimeout(() => {
|
|
events.emit(EventName.OnMessageResponseFinished, message)
|
|
}, 300)
|
|
}
|
|
return (
|
|
<div className="flex flex-row items-center">
|
|
{message.status === MessageStatus.Pending && (
|
|
<StopCircle
|
|
className="mx-1 cursor-pointer rounded-sm bg-gray-800 px-[3px]"
|
|
size={20}
|
|
onClick={() => stopInference()}
|
|
/>
|
|
)}
|
|
{message.status !== MessageStatus.Pending &&
|
|
message.id === messages[0]?.id && (
|
|
<RefreshCcw
|
|
className="mx-1 cursor-pointer rounded-sm bg-gray-800 px-[3px]"
|
|
size={20}
|
|
onClick={() => {
|
|
const messageRequest: MessageRequest = {
|
|
id: message.id ?? '',
|
|
messages: messages
|
|
.slice(1, messages.length)
|
|
.reverse()
|
|
.map((e) => {
|
|
return {
|
|
content: e.content,
|
|
role: e.role,
|
|
} as ChatCompletionMessage
|
|
}),
|
|
threadId: message.threadId ?? '',
|
|
}
|
|
if (message.role === ChatCompletionRole.Assistant) {
|
|
deleteAMessage(message.id ?? '')
|
|
}
|
|
events.emit(EventName.OnNewMessageRequest, messageRequest)
|
|
}}
|
|
/>
|
|
)}
|
|
<ClipboardCopy
|
|
className="mx-1 cursor-pointer rounded-sm bg-gray-800 px-[3px]"
|
|
size={20}
|
|
onClick={() => {
|
|
navigator.clipboard.writeText(message.content ?? '')
|
|
toaster({
|
|
title: 'Copied to clipboard',
|
|
})
|
|
}}
|
|
/>
|
|
<Trash2Icon
|
|
className="mx-1 cursor-pointer rounded-sm bg-gray-800 px-[3px]"
|
|
size={20}
|
|
onClick={async () => {
|
|
deleteAMessage(message.id ?? '')
|
|
if (thread)
|
|
await pluginManager
|
|
.get<ConversationalPlugin>(PluginType.Conversational)
|
|
?.saveConversation({
|
|
...thread,
|
|
messages: messages.filter((e) => e.id !== message.id),
|
|
})
|
|
}}
|
|
/>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default MessageToolbar
|