diff --git a/package.json b/package.json index 7eb9269ad8..d75bb0039e 100644 --- a/package.json +++ b/package.json @@ -140,7 +140,6 @@ "@google/genai": "patch:@google/genai@npm%3A1.0.1#~/.yarn/patches/@google-genai-npm-1.0.1-e26f0f9af7.patch", "@hello-pangea/dnd": "^18.0.1", "@heroui/react": "^2.8.3", - "@kangfenmao/keyv-storage": "^0.1.0", "@langchain/community": "^0.3.50", "@mistralai/mistralai": "^1.7.5", "@modelcontextprotocol/sdk": "^1.17.5", diff --git a/src/renderer/src/aiCore/legacy/clients/BaseApiClient.ts b/src/renderer/src/aiCore/legacy/clients/BaseApiClient.ts index 884499dfb1..5a2131a1f7 100644 --- a/src/renderer/src/aiCore/legacy/clients/BaseApiClient.ts +++ b/src/renderer/src/aiCore/legacy/clients/BaseApiClient.ts @@ -1,3 +1,4 @@ +import { cacheService } from '@data/CacheService' import { loggerService } from '@logger' import { isFunctionCallingModel, @@ -53,7 +54,6 @@ import { isEmpty } from 'lodash' import type { CompletionsContext } from '../middleware/types' import type { ApiClient, RequestTransformer, ResponseChunkTransformer } from './types' - const logger = loggerService.withContext('BaseApiClient') /** @@ -166,16 +166,16 @@ export abstract class BaseApiClient< return keys[0] } - const lastUsedKey = window.keyv.get(keyName) - if (!lastUsedKey) { - window.keyv.set(keyName, keys[0]) + const lastUsedKey = cacheService.getShared(keyName) as string | undefined + if (lastUsedKey === undefined) { + cacheService.setShared(keyName, keys[0]) return keys[0] } const currentIndex = keys.indexOf(lastUsedKey) const nextIndex = (currentIndex + 1) % keys.length const nextKey = keys[nextIndex] - window.keyv.set(keyName, nextKey) + cacheService.setShared(keyName, nextKey) return nextKey } @@ -331,7 +331,7 @@ export abstract class BaseApiClient< } private getMemoryReferencesFromCache(message: Message) { - const memories = window.keyv.get(`memory-search-${message.id}`) as MemoryItem[] | undefined + const memories = cacheService.get(`memory-search-${message.id}`) as MemoryItem[] | undefined if (memories) { const memoryReferences: KnowledgeReference[] = memories.map((mem, index) => ({ id: index + 1, @@ -349,10 +349,10 @@ export abstract class BaseApiClient< if (isEmpty(content)) { return [] } - const webSearch: WebSearchResponse = window.keyv.get(`web-search-${message.id}`) + const webSearch: WebSearchResponse | undefined = cacheService.get(`web-search-${message.id}`) if (webSearch) { - window.keyv.remove(`web-search-${message.id}`) + cacheService.delete(`web-search-${message.id}`) return (webSearch.results as WebSearchProviderResponse).results.map( (result, index) => ({ @@ -375,10 +375,10 @@ export abstract class BaseApiClient< if (isEmpty(content)) { return [] } - const knowledgeReferences: KnowledgeReference[] = window.keyv.get(`knowledge-search-${message.id}`) + const knowledgeReferences: KnowledgeReference[] | undefined = cacheService.get(`knowledge-search-${message.id}`) - if (!isEmpty(knowledgeReferences)) { - window.keyv.remove(`knowledge-search-${message.id}`) + if (knowledgeReferences && !isEmpty(knowledgeReferences)) { + cacheService.delete(`knowledge-search-${message.id}`) logger.debug(`Found ${knowledgeReferences.length} knowledge base references in cache for ID: ${message.id}`) return knowledgeReferences } diff --git a/src/renderer/src/aiCore/provider/providerConfig.ts b/src/renderer/src/aiCore/provider/providerConfig.ts index b91dad9cf7..b700a1f25f 100644 --- a/src/renderer/src/aiCore/provider/providerConfig.ts +++ b/src/renderer/src/aiCore/provider/providerConfig.ts @@ -5,6 +5,7 @@ import { type ProviderId, type ProviderSettingsMap } from '@cherrystudio/ai-core/provider' +import { cacheService } from '@data/CacheService' import { isOpenAIChatCompletionOnlyModel } from '@renderer/config/models' import { isNewApiProvider } from '@renderer/config/providers' import { @@ -22,7 +23,6 @@ import { cloneDeep, isEmpty } from 'lodash' import { aihubmixProviderCreator, newApiResolverCreator, vertexAnthropicProviderCreator } from './config' import { getAiSdkProviderId } from './factory' - const logger = loggerService.withContext('ProviderConfigProcessor') /** @@ -37,16 +37,16 @@ function getRotatedApiKey(provider: Provider): string { return keys[0] } - const lastUsedKey = window.keyv.get(keyName) - if (!lastUsedKey) { - window.keyv.set(keyName, keys[0]) + const lastUsedKey = cacheService.getShared(keyName) as string | undefined + if (lastUsedKey === undefined) { + cacheService.setShared(keyName, keys[0]) return keys[0] } const currentIndex = keys.indexOf(lastUsedKey) const nextIndex = (currentIndex + 1) % keys.length const nextKey = keys[nextIndex] - window.keyv.set(keyName, nextKey) + cacheService.setShared(keyName, nextKey) return nextKey } diff --git a/src/renderer/src/env.d.ts b/src/renderer/src/env.d.ts index eefc880a57..23b0ddebf2 100644 --- a/src/renderer/src/env.d.ts +++ b/src/renderer/src/env.d.ts @@ -1,7 +1,6 @@ /// import type { ToastUtilities } from '@cherrystudio/ui' -import type KeyvStorage from '@kangfenmao/keyv-storage' import type { HookAPI } from 'antd/es/modal/useModal' import type { NavigateFunction } from 'react-router-dom' @@ -17,7 +16,6 @@ declare global { interface Window { root: HTMLElement modal: HookAPI - keyv: KeyvStorage store: any navigate: NavigateFunction toast: ToastUtilities diff --git a/src/renderer/src/hooks/useScrollPosition.ts b/src/renderer/src/hooks/useScrollPosition.ts index 872004d58e..5a3bd38d7a 100644 --- a/src/renderer/src/hooks/useScrollPosition.ts +++ b/src/renderer/src/hooks/useScrollPosition.ts @@ -1,3 +1,4 @@ +import { cacheService } from '@data/CacheService' import { throttle } from 'lodash' import { useEffect, useRef } from 'react' @@ -9,12 +10,12 @@ export default function useScrollPosition(key: string) { const handleScroll = throttle(() => { const position = containerRef.current?.scrollTop ?? 0 window.requestAnimationFrame(() => { - window.keyv.set(scrollKey, position) + cacheService.set(scrollKey, position) }) }, 100) useEffect(() => { - const scroll = () => containerRef.current?.scrollTo({ top: window.keyv.get(scrollKey) || 0 }) + const scroll = () => containerRef.current?.scrollTo({ top: cacheService.get(scrollKey) || 0 }) scroll() clearTimeout(scrollTimerRef.current) scrollTimerRef.current = setTimeout(scroll, 50) diff --git a/src/renderer/src/init.ts b/src/renderer/src/init.ts index 456961f913..1a7693db63 100644 --- a/src/renderer/src/init.ts +++ b/src/renderer/src/init.ts @@ -1,5 +1,4 @@ import { preferenceService } from '@data/PreferenceService' -import KeyvStorage from '@kangfenmao/keyv-storage' import { loggerService } from '@logger' import { startAutoSync } from './services/BackupService' @@ -8,11 +7,6 @@ import storeSyncService from './services/StoreSyncService' import { webTraceService } from './services/WebTraceService' loggerService.initWindowSource('mainWindow') -function initKeyv() { - window.keyv = new KeyvStorage() - window.keyv.init() -} - function initAutoSync() { setTimeout(async () => { const autoSyncStates = await preferenceService.getMultiple({ @@ -39,7 +33,6 @@ function initWebTrace() { webTraceService.init() } -initKeyv() initAutoSync() initStoreSync() initWebTrace() diff --git a/src/renderer/src/pages/home/Tabs/TopicsTab.tsx b/src/renderer/src/pages/home/Tabs/TopicsTab.tsx index 4abf8f404a..5a2859ab15 100644 --- a/src/renderer/src/pages/home/Tabs/TopicsTab.tsx +++ b/src/renderer/src/pages/home/Tabs/TopicsTab.tsx @@ -137,7 +137,7 @@ const Topics: FC = ({ assistant: _assistant, activeTopic, setActiveTopic, const onClearMessages = useCallback( (topic: Topic) => { - // window.keyv.set(EVENT_NAMES.CHAT_COMPLETION_PAUSED, true) + // cacheService.set(EVENT_NAMES.CHAT_COMPLETION_PAUSED, true) setGenerating(false) EventEmitter.emit(EVENT_NAMES.CLEAR_MESSAGES, topic) }, diff --git a/src/renderer/src/pages/settings/MemorySettings/MemorySettings.tsx b/src/renderer/src/pages/settings/MemorySettings/MemorySettings.tsx index 86548fa637..c24f65cfb6 100644 --- a/src/renderer/src/pages/settings/MemorySettings/MemorySettings.tsx +++ b/src/renderer/src/pages/settings/MemorySettings/MemorySettings.tsx @@ -2,6 +2,7 @@ import { ExclamationCircleOutlined } from '@ant-design/icons' import { RowFlex } from '@cherrystudio/ui' import { Flex } from '@cherrystudio/ui' import { Switch } from '@cherrystudio/ui' +import { cacheService } from '@data/CacheService' import { loggerService } from '@logger' import { DeleteIcon, EditIcon, LoadingIcon, RefreshIcon } from '@renderer/components/Icons' import TextBadge from '@renderer/components/TextBadge' @@ -479,8 +480,8 @@ const MemorySettings = () => { const handleSettingsSubmit = async () => { setSettingsModalVisible(false) await memoryService.updateConfig() - if (window.keyv.get('memory.wait.settings')) { - window.keyv.remove('memory.wait.settings') + if (cacheService.get('memory.wait.settings')) { + cacheService.delete('memory.wait.settings') dispatch(setGlobalMemoryEnabled(true)) } } @@ -488,7 +489,7 @@ const MemorySettings = () => { const handleSettingsCancel = () => { setSettingsModalVisible(false) form.resetFields() - window.keyv.remove('memory.wait.settings') + cacheService.delete('memory.wait.settings') } const handleResetMemories = async (userId: string) => { @@ -554,7 +555,7 @@ const MemorySettings = () => { const handleGlobalMemoryToggle = async (enabled: boolean) => { if (enabled && !embedderModel) { - window.keyv.set('memory.wait.settings', true) + cacheService.set('memory.wait.settings', true) return setSettingsModalVisible(true) } diff --git a/src/renderer/src/providers/WebSearchProvider/BaseWebSearchProvider.ts b/src/renderer/src/providers/WebSearchProvider/BaseWebSearchProvider.ts index b3047dc7e1..0a02c71021 100644 --- a/src/renderer/src/providers/WebSearchProvider/BaseWebSearchProvider.ts +++ b/src/renderer/src/providers/WebSearchProvider/BaseWebSearchProvider.ts @@ -1,3 +1,4 @@ +import { cacheService } from '@data/CacheService' import type { WebSearchState } from '@renderer/store/websearch' import type { WebSearchProvider, WebSearchProviderResponse } from '@renderer/types' @@ -38,16 +39,16 @@ export default abstract class BaseWebSearchProvider { return keys[0] } - const lastUsedKey = window.keyv.get(keyName) - if (!lastUsedKey) { - window.keyv.set(keyName, keys[0]) + const lastUsedKey = cacheService.getShared(keyName) as string | undefined + if (lastUsedKey === undefined) { + cacheService.setShared(keyName, keys[0]) return keys[0] } const currentIndex = keys.indexOf(lastUsedKey) const nextIndex = (currentIndex + 1) % keys.length const nextKey = keys[nextIndex] - window.keyv.set(keyName, nextKey) + cacheService.setShared(keyName, nextKey) return nextKey } diff --git a/src/renderer/src/services/MemoryProcessor.ts b/src/renderer/src/services/MemoryProcessor.ts index 01ba5eeb77..c0d35de288 100644 --- a/src/renderer/src/services/MemoryProcessor.ts +++ b/src/renderer/src/services/MemoryProcessor.ts @@ -1,3 +1,4 @@ +import { cacheService } from '@data/CacheService' import { loggerService } from '@logger' import { getModel } from '@renderer/hooks/useModel' import type { AssistantMessage } from '@renderer/types' @@ -103,7 +104,7 @@ export class MemoryProcessor { if (!memoryConfig.llmApiClient) { throw new Error('No LLM model configured for memory processing') } - const existingMemoriesResult = (window.keyv.get(`memory-search-${lastMessageId}`) as MemoryItem[]) || [] + const existingMemoriesResult = (cacheService.get(`memory-search-${lastMessageId}`) as MemoryItem[]) || [] const existingMemories = existingMemoriesResult.map((memory) => ({ id: memory.id, diff --git a/src/renderer/src/services/ocr/clients/OcrBaseApiClient.ts b/src/renderer/src/services/ocr/clients/OcrBaseApiClient.ts index a81a3f972a..7394f7b475 100644 --- a/src/renderer/src/services/ocr/clients/OcrBaseApiClient.ts +++ b/src/renderer/src/services/ocr/clients/OcrBaseApiClient.ts @@ -1,5 +1,5 @@ +import { cacheService } from '@data/CacheService' import type { OcrApiProvider, OcrHandler } from '@renderer/types' - export abstract class OcrBaseApiClient { public provider: OcrApiProvider protected host: string @@ -27,16 +27,16 @@ export abstract class OcrBaseApiClient { return keys[0] } - const lastUsedKey = window.keyv.get(keyName) - if (!lastUsedKey) { - window.keyv.set(keyName, keys[0]) + const lastUsedKey = cacheService.getShared(keyName) as string | undefined + if (lastUsedKey === undefined) { + cacheService.setShared(keyName, keys[0]) return keys[0] } const currentIndex = keys.indexOf(lastUsedKey) const nextIndex = (currentIndex + 1) % keys.length const nextKey = keys[nextIndex] - window.keyv.set(keyName, nextKey) + cacheService.setShared(keyName, nextKey) return nextKey } diff --git a/src/renderer/src/store/thunk/messageThunk.ts b/src/renderer/src/store/thunk/messageThunk.ts index 8d7004ecc7..d506ab25ef 100644 --- a/src/renderer/src/store/thunk/messageThunk.ts +++ b/src/renderer/src/store/thunk/messageThunk.ts @@ -1,3 +1,4 @@ +import { cacheService } from '@data/CacheService' import { loggerService } from '@logger' import db from '@renderer/databases' import FileManager from '@renderer/services/FileManager' @@ -610,8 +611,8 @@ export const resendMessageThunk = // Clear cached search results for the user message being resent // This ensures that the regenerated responses will not use stale search results try { - window.keyv.remove(`web-search-${userMessageToResend.id}`) - window.keyv.remove(`knowledge-search-${userMessageToResend.id}`) + cacheService.delete(`web-search-${userMessageToResend.id}`) + cacheService.delete(`knowledge-search-${userMessageToResend.id}`) } catch (error) { logger.warn(`Failed to clear keyv cache for message ${userMessageToResend.id}:`, error as Error) } diff --git a/src/renderer/src/windows/mini/entryPoint.tsx b/src/renderer/src/windows/mini/entryPoint.tsx index 5974350c06..14ee738c93 100644 --- a/src/renderer/src/windows/mini/entryPoint.tsx +++ b/src/renderer/src/windows/mini/entryPoint.tsx @@ -2,7 +2,6 @@ import '@renderer/assets/styles/index.css' import '@renderer/assets/styles/tailwind.css' import '@ant-design/v5-patch-for-react-19' -import KeyvStorage from '@kangfenmao/keyv-storage' import { loggerService } from '@logger' import storeSyncService from '@renderer/services/StoreSyncService' import { createRoot } from 'react-dom/client' @@ -11,18 +10,6 @@ import MiniWindowApp from './MiniWindowApp' loggerService.initWindowSource('MiniWindow') -/** - * This function is required for model API - * eg. BaseProviders.ts - * Although the coupling is too strong, we have no choice but to load it - * In multi-window handling, decoupling is needed - */ -function initKeyv() { - window.keyv = new KeyvStorage() - window.keyv.init() -} -initKeyv() - //subscribe to store sync storeSyncService.subscribe() diff --git a/src/renderer/src/windows/selection/action/entryPoint.tsx b/src/renderer/src/windows/selection/action/entryPoint.tsx index 82cac5a5b2..a0f6d3459d 100644 --- a/src/renderer/src/windows/selection/action/entryPoint.tsx +++ b/src/renderer/src/windows/selection/action/entryPoint.tsx @@ -4,7 +4,6 @@ import '@ant-design/v5-patch-for-react-19' import { getToastUtilities } from '@cherrystudio/ui' import { preferenceService } from '@data/PreferenceService' -import KeyvStorage from '@kangfenmao/keyv-storage' import { loggerService } from '@logger' import { ToastPortal } from '@renderer/components/ToastPortal' import AntdProvider from '@renderer/context/AntdProvider' @@ -33,17 +32,6 @@ await preferenceService.preload([ 'feature.selection.action_window_opacity' ]) -/** - * fetchChatCompletion depends on this, - * which is not a good design, but we have to add it for now - */ -function initKeyv() { - window.keyv = new KeyvStorage() - window.keyv.init() -} - -initKeyv() - //subscribe to store sync storeSyncService.subscribe() diff --git a/yarn.lock b/yarn.lock index 18ed0cd83d..d3e4b44dbb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7188,13 +7188,6 @@ __metadata: languageName: node linkType: hard -"@kangfenmao/keyv-storage@npm:^0.1.0": - version: 0.1.0 - resolution: "@kangfenmao/keyv-storage@npm:0.1.0" - checksum: 10c0/647cf2d2f2e403ec91d1835546aa08bc6af1468a2823c3aa2cef883bacf67eb1a88bb97be1b4c0a09bc3ed69dba2ccbb8ecc3fd13242e84d4e234d5b77707156 - languageName: node - linkType: hard - "@langchain/community@npm:^0.3.50": version: 0.3.54 resolution: "@langchain/community@npm:0.3.54" @@ -14952,7 +14945,6 @@ __metadata: "@google/genai": "patch:@google/genai@npm%3A1.0.1#~/.yarn/patches/@google-genai-npm-1.0.1-e26f0f9af7.patch" "@hello-pangea/dnd": "npm:^18.0.1" "@heroui/react": "npm:^2.8.3" - "@kangfenmao/keyv-storage": "npm:^0.1.0" "@langchain/community": "npm:^0.3.50" "@libsql/client": "npm:0.14.0" "@libsql/win32-x64-msvc": "npm:^0.4.7"