diff --git a/src/main/ipc.ts b/src/main/ipc.ts index 333114ecac..f2b71267b4 100644 --- a/src/main/ipc.ts +++ b/src/main/ipc.ts @@ -18,7 +18,7 @@ import type { AgentPersistedMessage, FileMetadata, Notification, - OcrProvider, + OcrParams, Provider, Shortcut, SupportedOcrFile @@ -872,9 +872,7 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) { ) // OCR - ipcMain.handle(IpcChannel.OCR_Ocr, (_, file: SupportedOcrFile, provider: OcrProvider) => - ocrService.ocr(file, provider) - ) + ipcMain.handle(IpcChannel.OCR_Ocr, (_, file: SupportedOcrFile, params: OcrParams) => ocrService.ocr(file, params)) // OVMS ipcMain.handle(IpcChannel.Ovms_AddModel, (_, modelName: string, modelId: string, modelSource: string, task: string) => diff --git a/src/main/services/ocr/OcrService.ts b/src/main/services/ocr/OcrService.ts index 0dc188e0a8..6a71002411 100644 --- a/src/main/services/ocr/OcrService.ts +++ b/src/main/services/ocr/OcrService.ts @@ -1,5 +1,5 @@ import { loggerService } from '@logger' -import type { OcrProvider, OcrResult, SupportedOcrFile } from '@types' +import type { OcrParams, OcrResult, SupportedOcrFile } from '@types' import { BuiltinOcrProviderIds } from '@types' import type { OcrBaseService } from './builtin/OcrBaseService' @@ -28,12 +28,12 @@ export class OcrService { return Array.from(this.registry.keys()) } - public async ocr(file: SupportedOcrFile, provider: OcrProvider): Promise { - const service = this.registry.get(provider.id) + public async ocr(file: SupportedOcrFile, params: OcrParams): Promise { + const service = this.registry.get(params.providerId) if (!service) { - throw new Error(`Provider ${provider.id} is not registered`) + throw new Error(`Provider ${params.providerId} is not registered`) } - return service.ocr(file, provider.config) + return service.ocr(file) } } diff --git a/src/preload/index.ts b/src/preload/index.ts index 0bba78905f..f7578ecaea 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -12,7 +12,7 @@ import type { } from '@shared/data/preference/preferenceTypes' import type { UpgradeChannel } from '@shared/data/preference/preferenceTypes' import { IpcChannel } from '@shared/IpcChannel' -import type { Notification } from '@types' +import type { Notification, OcrParams } from '@types' import type { AddMemoryOptions, AssistantMessage, @@ -27,7 +27,6 @@ import type { MemoryConfig, MemoryListOptions, MemorySearchOptions, - OcrProvider, OcrResult, Provider, RestartApiServerStatusResult, @@ -476,8 +475,8 @@ const api = { ipcRenderer.invoke(IpcChannel.CodeTools_RemoveCustomTerminalPath, terminalId) }, ocr: { - ocr: (file: SupportedOcrFile, provider: OcrProvider): Promise => - ipcRenderer.invoke(IpcChannel.OCR_Ocr, file, provider) + ocr: (file: SupportedOcrFile, params: OcrParams): Promise => + ipcRenderer.invoke(IpcChannel.OCR_Ocr, file, params) }, cherryai: { generateSignature: (params: { method: string; path: string; query: string; body: Record }) => diff --git a/src/renderer/src/hooks/ocr/useOcr.ts b/src/renderer/src/hooks/ocr/useOcr.ts index 4c43f9250a..5534839e9b 100644 --- a/src/renderer/src/hooks/ocr/useOcr.ts +++ b/src/renderer/src/hooks/ocr/useOcr.ts @@ -26,8 +26,10 @@ export const useOcr = () => { const ocrImage = useCallback( async (image: ImageFileMetadata) => { if (isProviderAvailable(imageProvider)) { - logger.debug('ocrImage', { config: imageProvider.config }) - return OcrService.ocr(image, imageProvider) + logger.debug('ocrImage', { provider: imageProvider }) + return OcrService.ocr(image, { + providerId: imageProvider.id + }) } else { throw new Error(t('ocr.error.provider.')) } diff --git a/src/renderer/src/services/ocr/OcrService.ts b/src/renderer/src/services/ocr/OcrService.ts index ba4122fa16..98f4559a69 100644 --- a/src/renderer/src/services/ocr/OcrService.ts +++ b/src/renderer/src/services/ocr/OcrService.ts @@ -1,8 +1,5 @@ import { loggerService } from '@logger' -import type { OcrProvider, OcrResult, SupportedOcrFile } from '@renderer/types' -import { isOcrApiProvider } from '@renderer/types' - -import { OcrApiClientFactory } from './clients/OcrApiClientFactory' +import type { OcrParams, OcrResult, SupportedOcrFile } from '@renderer/types' const logger = loggerService.withContext('renderer:OcrService') @@ -13,12 +10,7 @@ const logger = loggerService.withContext('renderer:OcrService') * @returns ocr result * @throws {Error} */ -export const ocr = async (file: SupportedOcrFile, provider: OcrProvider): Promise => { +export const ocr = async (file: SupportedOcrFile, params: OcrParams): Promise => { logger.info(`ocr file ${file.path}`) - if (isOcrApiProvider(provider)) { - const client = OcrApiClientFactory.create(provider) - return client.ocr(file, provider.config) - } else { - return window.api.ocr.ocr(file, provider) - } + return window.api.ocr.ocr(file, params) } diff --git a/src/renderer/src/services/ocr/clients/OcrApiClientFactory.ts b/src/renderer/src/services/ocr/clients/OcrApiClientFactory.ts index 1685d1764b..0522a0b5b2 100644 --- a/src/renderer/src/services/ocr/clients/OcrApiClientFactory.ts +++ b/src/renderer/src/services/ocr/clients/OcrApiClientFactory.ts @@ -1,27 +1,29 @@ import { loggerService } from '@logger' -import type { OcrApiProvider } from '@renderer/types' +import type { OcrApiProvider, OcrApiProviderConfig } from '@renderer/types' import type { OcrBaseApiClient } from './OcrBaseApiClient' import { OcrExampleApiClient } from './OcrExampleApiClient' const logger = loggerService.withContext('OcrApiClientFactory') +// Not being used for now. +// TODO: Migrate to main in the future. export class OcrApiClientFactory { /** * Create an ApiClient instance for the given provider * 为给定的提供者创建ApiClient实例 */ - static create(provider: OcrApiProvider): OcrBaseApiClient { + static create(provider: OcrApiProvider, config: OcrApiProviderConfig): OcrBaseApiClient { logger.debug(`Creating ApiClient for provider:`, { id: provider.id, - config: provider.config + config }) let instance: OcrBaseApiClient // Extend other clients here // eslint-disable-next-line prefer-const - instance = new OcrExampleApiClient(provider) + instance = new OcrExampleApiClient(provider, config) return instance } diff --git a/src/renderer/src/services/ocr/clients/OcrBaseApiClient.ts b/src/renderer/src/services/ocr/clients/OcrBaseApiClient.ts index 7394f7b475..7eb8bdfd9e 100644 --- a/src/renderer/src/services/ocr/clients/OcrBaseApiClient.ts +++ b/src/renderer/src/services/ocr/clients/OcrBaseApiClient.ts @@ -1,26 +1,31 @@ import { cacheService } from '@data/CacheService' -import type { OcrApiProvider, OcrHandler } from '@renderer/types' +import type { OcrApiProvider, OcrApiProviderConfig, OcrHandler } from '@renderer/types' + +// Not being used for now. +// TODO: Migrate to main in the future. export abstract class OcrBaseApiClient { public provider: OcrApiProvider + public config: OcrApiProviderConfig protected host: string protected apiKey: string - constructor(provider: OcrApiProvider) { + constructor(provider: OcrApiProvider, config: OcrApiProviderConfig) { this.provider = provider this.host = this.getHost() this.apiKey = this.getApiKey() + this.config = config } abstract ocr: OcrHandler // copy from BaseApiClient public getHost(): string { - return this.provider.config.api.apiHost + return this.config.api.apiHost } // copy from BaseApiClient public getApiKey() { - const keys = this.provider.config.api.apiKey.split(',').map((key) => key.trim()) + const keys = this.config.api.apiKey.split(',').map((key) => key.trim()) const keyName = `ocr_provider:${this.provider.id}:last_used_key` if (keys.length === 1) { diff --git a/src/renderer/src/services/ocr/clients/OcrExampleApiClient.ts b/src/renderer/src/services/ocr/clients/OcrExampleApiClient.ts index 76a404cf9f..6c7a896751 100644 --- a/src/renderer/src/services/ocr/clients/OcrExampleApiClient.ts +++ b/src/renderer/src/services/ocr/clients/OcrExampleApiClient.ts @@ -1,12 +1,14 @@ -import type { OcrApiProvider, SupportedOcrFile } from '@renderer/types' +import type { OcrApiProvider, OcrApiProviderConfig, SupportedOcrFile } from '@renderer/types' import { OcrBaseApiClient } from './OcrBaseApiClient' export type OcrExampleProvider = OcrApiProvider +// Not being used for now. +// TODO: Migrate to main in the future. export class OcrExampleApiClient extends OcrBaseApiClient { - constructor(provider: OcrApiProvider) { - super(provider) + constructor(provider: OcrApiProvider, config: OcrApiProviderConfig) { + super(provider, config) } public ocr = async (file: SupportedOcrFile) => { diff --git a/src/renderer/src/types/ocr.ts b/src/renderer/src/types/ocr.ts index 5dc915f3ea..d2a0a72d25 100644 --- a/src/renderer/src/types/ocr.ts +++ b/src/renderer/src/types/ocr.ts @@ -104,18 +104,23 @@ export const isOcrProvider = (p: unknown): p is OcrProvider => { return OcrProviderSchema.safeParse(p).success } -export type OcrApiProviderConfig = OcrProviderBaseConfig & { - api: OcrProviderApiConfig +export const OcrApiProviderConfigSchema = OcrProviderBaseConfigSchema.extend({ + api: OcrProviderApiConfigSchema +}) + +export type OcrApiProviderConfig = z.infer + +export const isOcrApiProviderConfig = (config: unknown): config is OcrApiProviderConfig => { + return OcrApiProviderConfigSchema.safeParse(config).success } -/** This type is not being used. */ -export type OcrApiProvider = OcrProvider & { - config: OcrApiProviderConfig -} +export const OcrApiProviderSchema = OcrProviderSchema -/** This function is not being used. */ -export const isOcrApiProvider = (p: OcrProvider): p is OcrApiProvider => { - return !!(p.config && p.config.api && isOcrProviderApiConfig(p.config.api)) +/** Currently, there is no API provider yet, but we've left room for expansion. */ +export type OcrApiProvider = z.infer + +export const isOcrApiProvider = (p: unknown): p is OcrApiProvider => { + return OcrApiProviderSchema.safeParse(p).success } export type BuiltinOcrProvider = OcrProvider & { @@ -153,13 +158,17 @@ export const isSupportedOcrFile = (file: FileMetadata): file is SupportedOcrFile return isImageFileMetadata(file) } +export type OcrParams = { + providerId: string +} + export type OcrResult = { text: string } -export type OcrHandler = (file: SupportedOcrFile, options?: OcrProviderBaseConfig) => Promise +export type OcrHandler = (file: SupportedOcrFile) => Promise -export type OcrImageHandler = (file: ImageFileMetadata, options?: OcrProviderBaseConfig) => Promise +export type OcrImageHandler = (file: ImageFileMetadata) => Promise // Tesseract Types export type OcrTesseractConfig = OcrProviderBaseConfig & {