mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-30 15:59:09 +08:00
Backport: PR 11558 to v2
This commit is contained in:
parent
4f0cba15a0
commit
13abc2d653
@ -2,6 +2,7 @@ import { loggerService } from '@logger'
|
||||
import type { QuickPanelTriggerInfo } from '@renderer/components/QuickPanel'
|
||||
import { QuickPanelReservedSymbol, useQuickPanel } from '@renderer/components/QuickPanel'
|
||||
import { isGenerateImageModel, isVisionModel } from '@renderer/config/models'
|
||||
import { cacheService } from '@renderer/data/CacheService'
|
||||
import { useSession } from '@renderer/hooks/agents/useSession'
|
||||
import { useInputText } from '@renderer/hooks/useInputText'
|
||||
import { selectNewTopicLoading } from '@renderer/hooks/useMessageOperations'
|
||||
@ -41,19 +42,10 @@ import { getInputbarConfig } from './registry'
|
||||
import { TopicType } from './types'
|
||||
|
||||
const logger = loggerService.withContext('AgentSessionInputbar')
|
||||
const agentSessionDraftCache = new Map<string, string>()
|
||||
|
||||
const readDraftFromCache = (key: string): string => {
|
||||
return agentSessionDraftCache.get(key) ?? ''
|
||||
}
|
||||
const DRAFT_CACHE_TTL = 24 * 60 * 60 * 1000 // 24 hours
|
||||
|
||||
const writeDraftToCache = (key: string, value: string) => {
|
||||
if (!value) {
|
||||
agentSessionDraftCache.delete(key)
|
||||
} else {
|
||||
agentSessionDraftCache.set(key, value)
|
||||
}
|
||||
}
|
||||
const getAgentDraftCacheKey = (agentId: string) => `agent.session.draft.${agentId}`
|
||||
|
||||
type Props = {
|
||||
agentId: string
|
||||
@ -170,16 +162,15 @@ const AgentSessionInputbarInner: FC<InnerProps> = ({ assistant, agentId, session
|
||||
const scope = TopicType.Session
|
||||
const config = getInputbarConfig(scope)
|
||||
|
||||
// Use shared hooks for text and textarea management
|
||||
const initialDraft = useMemo(() => readDraftFromCache(agentId), [agentId])
|
||||
const persistDraft = useCallback((next: string) => writeDraftToCache(agentId, next), [agentId])
|
||||
// Use shared hooks for text and textarea management with draft persistence
|
||||
const draftCacheKey = getAgentDraftCacheKey(agentId)
|
||||
const {
|
||||
text,
|
||||
setText,
|
||||
isEmpty: inputEmpty
|
||||
} = useInputText({
|
||||
initialValue: initialDraft,
|
||||
onChange: persistDraft
|
||||
initialValue: cacheService.get<string>(draftCacheKey) ?? '',
|
||||
onChange: (value) => cacheService.set(draftCacheKey, value, DRAFT_CACHE_TTL)
|
||||
})
|
||||
const {
|
||||
textareaRef,
|
||||
|
||||
@ -9,6 +9,7 @@ import {
|
||||
isVisionModels,
|
||||
isWebSearchModel
|
||||
} from '@renderer/config/models'
|
||||
import { cacheService } from '@renderer/data/CacheService'
|
||||
import db from '@renderer/databases'
|
||||
import { useAssistant } from '@renderer/hooks/useAssistant'
|
||||
import { useInputText } from '@renderer/hooks/useInputText'
|
||||
@ -39,7 +40,7 @@ import { getSendMessageShortcutLabel } from '@renderer/utils/input'
|
||||
import { documentExts, imageExts, textExts } from '@shared/config/constant'
|
||||
import { debounce } from 'lodash'
|
||||
import type { FC } from 'react'
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import React, { useCallback, useEffect, useEffectEvent, useMemo, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import { InputbarCore } from './components/InputbarCore'
|
||||
@ -51,6 +52,17 @@ import TokenCount from './TokenCount'
|
||||
|
||||
const logger = loggerService.withContext('Inputbar')
|
||||
|
||||
const INPUTBAR_DRAFT_CACHE_KEY = 'inputbar.draft.text'
|
||||
const DRAFT_CACHE_TTL = 24 * 60 * 60 * 1000 // 24 hours
|
||||
|
||||
const getMentionedModelsCacheKey = (assistantId: string) => `inputbar.mentioned.models.${assistantId}`
|
||||
|
||||
const getValidatedCachedModels = (assistantId: string): Model[] => {
|
||||
const cached = cacheService.get<Model[]>(getMentionedModelsCacheKey(assistantId))
|
||||
if (!Array.isArray(cached)) return []
|
||||
return cached.filter((model) => model?.id && model?.name)
|
||||
}
|
||||
|
||||
interface Props {
|
||||
assistant: Assistant
|
||||
setActiveTopic: (topic: Topic) => void
|
||||
@ -80,16 +92,18 @@ const Inputbar: FC<Props> = ({ assistant: initialAssistant, setActiveTopic, topi
|
||||
toggleExpanded: () => {}
|
||||
})
|
||||
|
||||
const [initialMentionedModels] = useState(() => getValidatedCachedModels(initialAssistant.id))
|
||||
|
||||
const initialState = useMemo(
|
||||
() => ({
|
||||
files: [] as FileType[],
|
||||
mentionedModels: [] as Model[],
|
||||
mentionedModels: initialMentionedModels,
|
||||
selectedKnowledgeBases: initialAssistant.knowledge_bases ?? [],
|
||||
isExpanded: false,
|
||||
couldAddImageFile: false,
|
||||
extensions: [] as string[]
|
||||
}),
|
||||
[initialAssistant.knowledge_bases]
|
||||
[initialMentionedModels, initialAssistant.knowledge_bases]
|
||||
)
|
||||
|
||||
return (
|
||||
@ -121,7 +135,10 @@ const InputbarInner: FC<InputbarInnerProps> = ({ assistant: initialAssistant, se
|
||||
const { setFiles, setMentionedModels, setSelectedKnowledgeBases } = useInputbarToolsDispatch()
|
||||
const { setCouldAddImageFile } = useInputbarToolsInternalDispatch()
|
||||
|
||||
const { text, setText } = useInputText()
|
||||
const { text, setText } = useInputText({
|
||||
initialValue: cacheService.get<string>(INPUTBAR_DRAFT_CACHE_KEY) ?? '',
|
||||
onChange: (value) => cacheService.set(INPUTBAR_DRAFT_CACHE_KEY, value, DRAFT_CACHE_TTL)
|
||||
})
|
||||
const {
|
||||
textareaRef,
|
||||
resize: resizeTextArea,
|
||||
@ -192,6 +209,14 @@ const InputbarInner: FC<InputbarInnerProps> = ({ assistant: initialAssistant, se
|
||||
setCouldAddImageFile(canAddImageFile)
|
||||
}, [canAddImageFile, setCouldAddImageFile])
|
||||
|
||||
const onUnmount = useEffectEvent((id: string) => {
|
||||
cacheService.set(getMentionedModelsCacheKey(id), mentionedModels, DRAFT_CACHE_TTL)
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
return () => onUnmount(assistant.id)
|
||||
}, [assistant.id, onUnmount])
|
||||
|
||||
const placeholderText = enableQuickPanelTriggers
|
||||
? t('chat.input.placeholder', { key: getSendMessageShortcutLabel(sendMessageShortcut) })
|
||||
: t('chat.input.placeholder_without_triggers', {
|
||||
|
||||
@ -151,11 +151,8 @@ export const InputbarCore: FC<InputbarCoreProps> = ({
|
||||
|
||||
const setText = useCallback<React.Dispatch<React.SetStateAction<string>>>(
|
||||
(value) => {
|
||||
if (typeof value === 'function') {
|
||||
onTextChange(value(textRef.current))
|
||||
} else {
|
||||
onTextChange(value)
|
||||
}
|
||||
const newText = typeof value === 'function' ? value(textRef.current) : value
|
||||
onTextChange(newText)
|
||||
},
|
||||
[onTextChange]
|
||||
)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user