refactor: replace keyv with cacheService

This commit is contained in:
fullex 2025-09-25 11:38:05 +08:00
parent 8a9b633af2
commit f6ff436294
15 changed files with 40 additions and 78 deletions

View File

@ -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",

View File

@ -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
}

View File

@ -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
}

View File

@ -1,7 +1,6 @@
/// <reference types="vite/client" />
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

View File

@ -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)

View File

@ -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()

View File

@ -137,7 +137,7 @@ const Topics: FC<Props> = ({ 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)
},

View File

@ -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)
}

View File

@ -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
}

View File

@ -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,

View File

@ -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
}

View File

@ -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)
}

View File

@ -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()

View File

@ -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()

View File

@ -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"