diff --git a/src/main/ocr/MacSysOcrProvider.ts b/src/main/ocr/MacSysOcrProvider.ts index 1d9c9c40d..6155c24ba 100644 --- a/src/main/ocr/MacSysOcrProvider.ts +++ b/src/main/ocr/MacSysOcrProvider.ts @@ -12,6 +12,11 @@ export default class MacSysOcrProvider extends BaseOcrProvider { private readonly BATCH_SIZE = 4 private readonly CONCURRENCY = 2 private readonly MIN_TEXT_LENGTH = 1000 + + private getRecognitionLevel(level?: number) { + return level === 0 ? MacOCR.RECOGNITION_LEVEL_FAST : MacOCR.RECOGNITION_LEVEL_ACCURATE + } + constructor(provider: OcrProvider) { super(provider) } @@ -42,7 +47,8 @@ export default class MacSysOcrProvider extends BaseOcrProvider { const ocrResults = await MacOCR.recognizeBatchFromBuffer(pageBuffers, { maxThreads: 4, ocrOptions: { - recognitionLevel: MacOCR.RECOGNITION_LEVEL_ACCURATE + recognitionLevel: this.getRecognitionLevel(this.provider.options?.recognitionLevel), + minConfidence: this.provider.options?.minConfidence || 0.5 } }) diff --git a/src/main/services/KnowledgeService.ts b/src/main/services/KnowledgeService.ts index e157ded67..e21d5c2a6 100644 --- a/src/main/services/KnowledgeService.ts +++ b/src/main/services/KnowledgeService.ts @@ -497,7 +497,7 @@ class KnowledgeService { try { const ocrProvider = new OcrProvider(base.ocrProvider) Logger.info(`Starting OCR processing for file: ${file.path}`) - + Logger.info(`OCR provider: ${base.ocrProvider?.options}`) const { processedFile } = await ocrProvider.parseFile(item.id, file) Logger.info(`OCR processing completed: ${processedFile.path}`) fileToProcess = processedFile diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json index 54e56a87f..9c6a0c367 100644 --- a/src/renderer/src/i18n/locales/en-us.json +++ b/src/renderer/src/i18n/locales/en-us.json @@ -1213,8 +1213,15 @@ "ocr": { "title": "OCR", "provider": "OCR Provider", - "ocr": "OCR Settings", - "provider_placeholder": "Choose a OCR provider" + "provider_placeholder": "Choose a OCR provider", + "mac_system_ocr_options": { + "mode": { + "title": "Recognition Mode", + "accurate": "Accurate", + "fast": "Fast" + }, + "min_confidence": "Minimum Confidence" + } }, "title": "Tool Settings" }, diff --git a/src/renderer/src/i18n/locales/ja-jp.json b/src/renderer/src/i18n/locales/ja-jp.json index 715ffb4cb..f5a1302db 100644 --- a/src/renderer/src/i18n/locales/ja-jp.json +++ b/src/renderer/src/i18n/locales/ja-jp.json @@ -1188,10 +1188,16 @@ "title": "ツール設定", "ocr": { "title": "ナレッジベース設定", - "preprocessing": "預処理", - "preprocessing_tooltip": "アップロードされたファイルのOCR預処理", "provider": "OCRプロバイダー", - "provider_placeholder": "OCRプロバイダーを選択する" + "provider_placeholder": "OCRプロバイダーを選択する", + "mac_system_ocr_options": { + "mode": { + "title": "辨識モード", + "accurate": "正確な", + "fast": "速い" + }, + "min_confidence": "最小信頼度" + } }, "websearch": { "blacklist": "ブラックリスト", @@ -1225,33 +1231,8 @@ "tray.onclose": "閉じるときにトレイに最小化", "tray.show": "トレイアイコンを表示", "tray.title": "トレイ", - "websearch": { - "blacklist": "ブラックリスト", - "blacklist_description": "以下のウェブサイトの結果は検索結果に表示されません", - "blacklist_tooltip": "以下の形式を使用してください(改行区切り)\nexample.com\nhttps://www.example.com\nhttps://example.com\n*://*.example.com", - "check": "チェック", - "check_failed": "検証に失敗しました", - "check_success": "検証に成功しました", - "enhance_mode": "検索強化モード", - "enhance_mode_tooltip": "デフォルトモデルを使用して問題から検索キーワードを抽出し、検索を実行します", - "get_api_key": "APIキーを取得", - "no_provider_selected": "検索サービスプロバイダーを選択してから再確認してください。", - "search_max_result": "検索結果の数", - "search_provider": "検索サービスプロバイダー", - "search_provider_placeholder": "検索サービスプロバイダーを選択する", - "search_result_default": "デフォルト", - "search_with_time": "日付を含む検索", - "tavily": { - "api_key": "Tavily API キー", - "api_key.placeholder": "Tavily API キーを入力してください", - "description": "Tavily は、AI エージェントのために特別に開発された検索エンジンで、最新の結果、インテリジェントな検索提案、そして深い研究能力を提供します", - "title": "Tavily" - }, - "title": "ウェブ検索" - }, "general.auto_check_update.title": "自動更新チェックを有効にする" }, - "general.auto_check_update.title": "自動更新チェックを有効にする", "translate": { "any.language": "任意の言語", "button.translate": "翻訳", diff --git a/src/renderer/src/i18n/locales/ru-ru.json b/src/renderer/src/i18n/locales/ru-ru.json index e36c44196..201f1ea5b 100644 --- a/src/renderer/src/i18n/locales/ru-ru.json +++ b/src/renderer/src/i18n/locales/ru-ru.json @@ -1189,7 +1189,15 @@ "ocr": { "title": "Настройки OCR", "provider": "Поставщик OCR", - "provider_placeholder": "Выберите поставщика OCR" + "provider_placeholder": "Выберите поставщика OCR", + "mac_system_ocr_options": { + "mode": { + "title": "Режим распознавания", + "accurate": "Точный", + "fast": "Быстрый" + }, + "min_confidence": "Минимальная достоверность" + } }, "websearch": { "blacklist": "Черный список", @@ -1214,8 +1222,7 @@ "title": "Tavily" }, "title": "Поиск в Интернете" - }, - "general.auto_check_update.title": "Включить автоматическую проверку обновлений" + } }, "topic.position": "Позиция топиков", "topic.position.left": "Слева", @@ -1224,33 +1231,8 @@ "tray.onclose": "Свернуть в трей при закрытии", "tray.show": "Показать значок в трее", "tray.title": "Трей", - "websearch": { - "blacklist": "Черный список", - "blacklist_description": "Результаты из следующих веб-сайтов не будут отображаться в результатах поиска", - "blacklist_tooltip": "Пожалуйста, используйте следующий формат (разделенный переносами строк)\nexample.com\nhttps://www.example.com\nhttps://example.com\n*://*.example.com", - "check": "проверка", - "check_failed": "Проверка не прошла", - "check_success": "Проверка успешна", - "enhance_mode": "Режим улучшения поиска", - "enhance_mode_tooltip": "Используйте модель по умолчанию для извлечения ключевых слов из проблемы и поиска", - "get_api_key": "Получить ключ API", - "no_provider_selected": "Пожалуйста, выберите поставщика поисковых услуг, затем проверьте.", - "search_max_result": "Количество результатов поиска", - "search_provider": "поиск сервисного провайдера", - "search_provider_placeholder": "Выберите поставщика поисковых услуг", - "search_result_default": "По умолчанию", - "search_with_time": "Поиск, содержащий дату", - "tavily": { - "api_key": "Ключ API Tavily", - "api_key.placeholder": "Введите ключ API Tavily", - "description": "Tavily — это поисковая система, специально разработанная для ИИ-агентов, предоставляющая актуальные результаты, умные предложения по запросам и глубокие исследовательские возможности", - "title": "Tavily" - }, - "title": "Поиск в Интернете" - }, "general.auto_check_update.title": "Включить автоматическую проверку обновлений" }, - "general.auto_check_update.title": "Включить автоматическую проверку обновлений", "translate": { "any.language": "Любой язык", "button.translate": "Перевести", diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index a579a1836..f3c87112d 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -394,7 +394,11 @@ "rename": "重命名", "search": "搜索知识库", "search_placeholder": "输入查询内容", - "settings": "知识库设置", + "settings": { + "title": "知识库设置", + "preprocessing": "预处理", + "preprocessing_tooltip": "使用 OCR 预处理上传的文件" + }, "sitemap_placeholder": "请输入站点地图 URL", "sitemaps": "网站", "source": "来源", @@ -952,13 +956,6 @@ "launch.onboot": "开机自动启动", "launch.title": "启动", "launch.totray": "启动时最小化到托盘", - "knowledge": { - "title": "知识库", - "ocr": { - "title": "OCR设置", - "provider": "OCR服务商" - } - }, "mcp": { "actions": "操作", "active": "启用", @@ -1191,9 +1188,17 @@ "tool": { "title": "工具设置", "ocr": { - "title": "知识库设置", + "title": "OCR设置", "provider": "OCR服务商", - "provider_placeholder": "选择一个OCR服务商" + "provider_placeholder": "选择一个OCR服务商", + "mac_system_ocr_options": { + "mode": { + "title": "识别模式", + "accurate": "精准", + "fast": "快速" + }, + "min_confidence": "最小置信度" + } }, "websearch": { "blacklist": "黑名单", diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json index 4b23c266d..b04fde0d0 100644 --- a/src/renderer/src/i18n/locales/zh-tw.json +++ b/src/renderer/src/i18n/locales/zh-tw.json @@ -1188,9 +1188,16 @@ "title": "工具", "ocr": { "title": "OCR", - "description": "OCR 設定", "provider": "OCR 提供者", - "provider_placeholder": "選擇一個 OCR 提供者" + "provider_placeholder": "選擇一個 OCR 提供者", + "mac_system_ocr_options": { + "mode": { + "title": "辨識模式", + "accurate": "精確", + "fast": "快速" + }, + "min_confidence": "最小置信度" + } }, "websearch": { "blacklist": "黑名單", @@ -1224,33 +1231,8 @@ "tray.onclose": "關閉時最小化到系统匣", "tray.show": "顯示系统匣圖示", "tray.title": "系统匣", - "websearch": { - "blacklist": "黑名單", - "blacklist_description": "以下網站不會出現在搜尋結果中", - "blacklist_tooltip": "請使用以下格式 (換行符號分隔)\nexample.com\nhttps://www.example.com\nhttps://example.com\n*://*.example.com", - "check": "檢查", - "check_failed": "驗證失敗", - "check_success": "驗證成功", - "enhance_mode": "搜索增強模式", - "enhance_mode_tooltip": "使用預設模型提取關鍵詞後搜索", - "get_api_key": "點選這裡取得金鑰", - "no_provider_selected": "請選擇搜尋服務商後再檢查", - "search_max_result": "搜尋結果個數", - "search_provider": "搜尋服務商", - "search_provider_placeholder": "選擇一個搜尋服務商", - "search_result_default": "預設", - "search_with_time": "搜尋包含日期", - "tavily": { - "api_key": "Tavily API 金鑰", - "api_key.placeholder": "請輸入 Tavily API 金鑰", - "description": "Tavily 是一個為 AI 代理量身訂製的搜尋引擎,提供即時、準確的結果、智慧查詢建議和深入的研究能力", - "title": "Tavily" - }, - "title": "網路搜尋" - }, "general.auto_check_update.title": "啟用自動更新檢查" }, - "general.auto_check_update.title": "啟用自動更新檢查", "translate": { "any.language": "任意語言", "button.translate": "翻譯", diff --git a/src/renderer/src/pages/settings/ToolSettings/OcrSettings/OcrProviderSettings.tsx b/src/renderer/src/pages/settings/ToolSettings/OcrSettings/OcrProviderSettings.tsx index ed009aef8..2a56b3260 100644 --- a/src/renderer/src/pages/settings/ToolSettings/OcrSettings/OcrProviderSettings.tsx +++ b/src/renderer/src/pages/settings/ToolSettings/OcrSettings/OcrProviderSettings.tsx @@ -4,13 +4,22 @@ import { useOcrProvider } from '@renderer/hooks/useOcr' import { formatApiKeys } from '@renderer/services/ApiService' import { OcrProvider } from '@renderer/types' import { hasObjectKey } from '@renderer/utils' -import { Avatar, Divider, Flex, Input } from 'antd' +import { Avatar, Divider, Flex, Input, InputNumber, Segmented } from 'antd' import Link from 'antd/es/typography/Link' import { FC, useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' import styled from 'styled-components' -import { SettingHelpLink, SettingHelpText, SettingHelpTextRow, SettingSubtitle, SettingTitle } from '../..' +import { + SettingDivider, + SettingHelpLink, + SettingHelpText, + SettingHelpTextRow, + SettingRow, + SettingRowTitle, + SettingSubtitle, + SettingTitle +} from '../..' interface Props { provider: OcrProvider @@ -21,6 +30,7 @@ const OcrProviderSetting: FC = ({ provider: _provider }) => { const { t } = useTranslation() const [apiKey, setApiKey] = useState(ocrProvider.apiKey || '') const [apiHost, setApiHost] = useState(ocrProvider.apiHost || '') + const [options, setOptions] = useState(ocrProvider.options || {}) const ocrProviderConfig = OCR_PROVIDER_CONFIG[ocrProvider.id] const apiKeyWebsite = ocrProviderConfig?.websites?.apiKey @@ -29,7 +39,8 @@ const OcrProviderSetting: FC = ({ provider: _provider }) => { useEffect(() => { setApiKey(ocrProvider.apiKey ?? '') setApiHost(ocrProvider.apiHost ?? '') - }, [ocrProvider.apiKey, ocrProvider.apiHost]) + setOptions(ocrProvider.options ?? {}) + }, [ocrProvider.apiKey, ocrProvider.apiHost, ocrProvider.options]) const onUpdateApiKey = () => { if (apiKey !== ocrProvider.apiKey) { @@ -49,6 +60,12 @@ const OcrProviderSetting: FC = ({ provider: _provider }) => { } } + const onUpdateOptions = (key: string, value: any) => { + const newOptions = { ...options, [key]: value } + setOptions(newOptions) + updateOcrProvider({ ...ocrProvider, options: newOptions }) + } + return ( <> @@ -102,6 +119,40 @@ const OcrProviderSetting: FC = ({ provider: _provider }) => { )} + + {hasObjectKey(ocrProvider, 'options') && ocrProvider.id === 'system' && ( + <> + + + {t('settings.tool.ocr.mac_system_ocr_options.mode.title')} + onUpdateOptions('recognitionLevel', value)} + /> + + + + {t('settings.tool.ocr.mac_system_ocr_options.min_confidence')} + onUpdateOptions('minConfidence', value)} + min={0} + max={1} + step={0.1} + /> + + + )} ) } diff --git a/src/renderer/src/store/index.ts b/src/renderer/src/store/index.ts index 8bc53ed6b..8cce269b8 100644 --- a/src/renderer/src/store/index.ts +++ b/src/renderer/src/store/index.ts @@ -44,7 +44,7 @@ const persistedReducer = persistReducer( { key: 'cherry-studio', storage, - version: 86, + version: 87, blacklist: ['runtime', 'messages'], migrate }, diff --git a/src/renderer/src/store/ocr.ts b/src/renderer/src/store/ocr.ts index 1677f44b0..ec2c584c7 100644 --- a/src/renderer/src/store/ocr.ts +++ b/src/renderer/src/store/ocr.ts @@ -23,7 +23,11 @@ const initialState: OcrState = { }, { id: 'system', - name: 'System(Mac Only)' + name: 'System(Mac Only)', + options: { + recognitionLevel: 0, + minConfidence: 0.5 + } } ], defaultProvider: '' diff --git a/src/renderer/src/types/index.ts b/src/renderer/src/types/index.ts index d8cb45682..9ecba21a0 100644 --- a/src/renderer/src/types/index.ts +++ b/src/renderer/src/types/index.ts @@ -349,6 +349,7 @@ export interface OcrProvider { apiKey?: string apiHost?: string model?: string + options?: any } export type GenerateImageParams = {