fix: avoid lose title threads (#3307)

* fix: avoid lose title threads

* fix: create cont default thread title
This commit is contained in:
Faisal Amir 2024-08-09 09:39:04 +07:00 committed by GitHub
parent b43242b9b2
commit a4f5fda104
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 46 additions and 17 deletions

1
web/constants/Threads.ts Normal file
View File

@ -0,0 +1 @@
export const defaultThreadTitle = 'New Thread'

View File

@ -17,6 +17,8 @@ import {
import { useAtomValue } from 'jotai' import { useAtomValue } from 'jotai'
import { defaultThreadTitle } from '@/constants/Threads'
import { UpdateConfigMutationVariables } from './useEngineMutation' import { UpdateConfigMutationVariables } from './useEngineMutation'
import { MessageCreateMutationVariables } from './useMessageCreateMutation' import { MessageCreateMutationVariables } from './useMessageCreateMutation'
import { MessageDeleteMutationVariables } from './useMessageDeleteMutation' import { MessageDeleteMutationVariables } from './useMessageDeleteMutation'
@ -80,7 +82,7 @@ const useCortex = () => {
if (!assistants || assistants.length === 0) continue if (!assistants || assistants.length === 0) continue
// @ts-expect-error each thread must have a title, else default to 'New Thread' // @ts-expect-error each thread must have a title, else default to 'New Thread'
const title: string = thread['title'] ?? 'New Thread' const title: string = thread['title'] ?? defaultThreadTitle
threads.push({ threads.push({
...thread, ...thread,
@ -227,7 +229,7 @@ const useCortex = () => {
const thread: Thread = { const thread: Thread = {
...createThreadResponse, ...createThreadResponse,
// @ts-expect-error each thread will have a title, else default to 'New Thread' // @ts-expect-error each thread will have a title, else default to 'New Thread'
title: createThreadResponse.title ?? 'New Thread', title: createThreadResponse.title ?? defaultThreadTitle,
assistants: [assistant], assistants: [assistant],
} }
return thread return thread

View File

@ -1,6 +1,8 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import { useCallback } from 'react' import { useCallback } from 'react'
import { defaultThreadTitle } from '@/constants/Threads'
import useAssistantQuery from './useAssistantQuery' import useAssistantQuery from './useAssistantQuery'
import useCortex from './useCortex' import useCortex from './useCortex'
@ -43,7 +45,7 @@ const useMigratingData = () => {
console.error(`Ignore thread ${thread.id} because modelId is not found`) console.error(`Ignore thread ${thread.id} because modelId is not found`)
continue continue
} }
const threadTitle: string = thread.title ?? 'New Thread' const threadTitle: string = thread.title ?? defaultThreadTitle
const instructions: string = thread.assistants[0]?.instructions ?? '' const instructions: string = thread.assistants[0]?.instructions ?? ''
// currently, we don't have api support for creating thread with messages // currently, we don't have api support for creating thread with messages
const cortexThread = await createThread(modelId, assistants[0]) const cortexThread = await createThread(modelId, assistants[0])

View File

@ -18,6 +18,8 @@ import { currentPromptAtom, editPromptAtom } from '@/containers/Providers/Jotai'
import { toaster } from '@/containers/Toast' import { toaster } from '@/containers/Toast'
import { defaultThreadTitle } from '@/constants/Threads'
import { inferenceErrorAtom } from '@/screens/HubScreen2/components/InferenceErrorModal' import { inferenceErrorAtom } from '@/screens/HubScreen2/components/InferenceErrorModal'
import { showWarningMultipleModelModalAtom } from '@/screens/HubScreen2/components/WarningMultipleModelModal' import { showWarningMultipleModelModalAtom } from '@/screens/HubScreen2/components/WarningMultipleModelModal'
@ -512,7 +514,7 @@ const useSendMessage = () => {
if (!isValid) return if (!isValid) return
let shouldSummarize = let shouldSummarize =
activeThread!.title === 'New Thread' || activeThread!.title === defaultThreadTitle ||
activeThread!.title.trim() === '' activeThread!.title.trim() === ''
const modelId = activeThread!.assistants[0].model const modelId = activeThread!.assistants[0].model

View File

@ -1,23 +1,35 @@
import { useCallback, memo } from 'react' import { useCallback, memo } from 'react'
import { Thread } from '@janhq/core'
import { Button, Modal, ModalClose } from '@janhq/joi' import { Button, Modal, ModalClose } from '@janhq/joi'
import { useSetAtom } from 'jotai'
import { Paintbrush } from 'lucide-react' import { Paintbrush } from 'lucide-react'
import { defaultThreadTitle } from '@/constants/Threads'
import useCortex from '@/hooks/useCortex'
import useThreads from '@/hooks/useThreads' import useThreads from '@/hooks/useThreads'
import { updateThreadTitleAtom } from '@/helpers/atoms/Thread.atom'
type Props = { type Props = {
threadId: string thread: Thread
closeContextMenu?: () => void closeContextMenu?: () => void
} }
const ModalCleanThread = ({ threadId, closeContextMenu }: Props) => { const ModalCleanThread = ({ thread, closeContextMenu }: Props) => {
const { cleanThread } = useThreads() const { cleanThread } = useThreads()
const updateThreadTitle = useSetAtom(updateThreadTitleAtom)
const { updateThread } = useCortex()
const onCleanThreadClick = useCallback( const onCleanThreadClick = useCallback(
(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => { (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
e.stopPropagation() e.stopPropagation()
cleanThread(threadId) cleanThread(thread.id)
updateThreadTitle(thread.id, defaultThreadTitle)
updateThread({ ...thread, title: defaultThreadTitle })
}, },
[cleanThread, threadId] [cleanThread, thread, updateThread, updateThreadTitle]
) )
return ( return (

View File

@ -6,6 +6,8 @@ import { useAtomValue, useSetAtom } from 'jotai'
import { MoreHorizontalIcon } from 'lucide-react' import { MoreHorizontalIcon } from 'lucide-react'
import { twMerge } from 'tailwind-merge' import { twMerge } from 'tailwind-merge'
import { defaultThreadTitle } from '@/constants/Threads'
import useThreads from '@/hooks/useThreads' import useThreads from '@/hooks/useThreads'
import ModalCleanThread from '../ModalCleanThread' import ModalCleanThread from '../ModalCleanThread'
@ -29,6 +31,7 @@ const ThreadItem: React.FC<Props> = ({ thread }) => {
const getThreadIdsShouldAnimateTitle = useAtomValue( const getThreadIdsShouldAnimateTitle = useAtomValue(
getThreadIdsShouldAnimateTitleAtom getThreadIdsShouldAnimateTitleAtom
) )
const setEditMessage = useSetAtom(editMessageAtom) const setEditMessage = useSetAtom(editMessageAtom)
const { setActiveThread } = useThreads() const { setActiveThread } = useThreads()
const [contextMenu, setContextMenu] = useState<{ const [contextMenu, setContextMenu] = useState<{
@ -81,10 +84,13 @@ const ThreadItem: React.FC<Props> = ({ thread }) => {
> >
<div className="relative z-10 break-all p-2"> <div className="relative z-10 break-all p-2">
{getThreadIdsShouldAnimateTitle.includes(thread.id) ? ( {getThreadIdsShouldAnimateTitle.includes(thread.id) ? (
<TypingAnimated text={thread.title} speed={20} /> <TypingAnimated
text={thread.title || defaultThreadTitle}
speed={20}
/>
) : ( ) : (
<span className="line-clamp-1 group-hover/message:pr-6"> <span className="line-clamp-1 group-hover/message:pr-6">
{thread.title} {thread.title || defaultThreadTitle}
</span> </span>
)} )}
</div> </div>
@ -112,7 +118,7 @@ const ThreadItem: React.FC<Props> = ({ thread }) => {
closeContextMenu={closeContextMenu} closeContextMenu={closeContextMenu}
/> />
<ModalCleanThread <ModalCleanThread
threadId={thread.id} thread={thread}
closeContextMenu={closeContextMenu} closeContextMenu={closeContextMenu}
/> />
<ModalDeleteThread <ModalDeleteThread

View File

@ -10,15 +10,19 @@ const TypingAnimated: React.FC<Props> = ({ text, speed }) => {
const [index, setIndex] = useState(0) const [index, setIndex] = useState(0)
useEffect(() => { useEffect(() => {
if (index < text.length) { const typingEffect = setInterval(() => {
const timeout = setTimeout(() => { if (text.length) {
setDisplayedText(displayedText + text[index]) setDisplayedText(text.substring(0, index + 1))
setIndex(index + 1) setIndex(index + 1)
}, speed) } else {
clearInterval(typingEffect)
}
}, speed)
return () => clearTimeout(timeout) return () => {
clearInterval(typingEffect)
} }
}, [index, text, displayedText, speed]) }, [index, speed, text])
return ( return (
<span className="line-clamp-1 group-hover/message:pr-6"> <span className="line-clamp-1 group-hover/message:pr-6">