feat(OCR): add recognition level and minimum confidence options for Mac system OCR provider
This commit is contained in:
@@ -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
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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": "翻訳",
|
||||
|
||||
@@ -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": "Перевести",
|
||||
|
||||
@@ -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": "黑名单",
|
||||
|
||||
@@ -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": "翻譯",
|
||||
|
||||
@@ -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<Props> = ({ 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<Props> = ({ 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<Props> = ({ provider: _provider }) => {
|
||||
}
|
||||
}
|
||||
|
||||
const onUpdateOptions = (key: string, value: any) => {
|
||||
const newOptions = { ...options, [key]: value }
|
||||
setOptions(newOptions)
|
||||
updateOcrProvider({ ...ocrProvider, options: newOptions })
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingTitle>
|
||||
@@ -102,6 +119,40 @@ const OcrProviderSetting: FC<Props> = ({ provider: _provider }) => {
|
||||
</Flex>
|
||||
</>
|
||||
)}
|
||||
|
||||
{hasObjectKey(ocrProvider, 'options') && ocrProvider.id === 'system' && (
|
||||
<>
|
||||
<SettingDivider style={{ marginTop: 15, marginBottom: 12 }} />
|
||||
<SettingRow>
|
||||
<SettingRowTitle>{t('settings.tool.ocr.mac_system_ocr_options.mode.title')}</SettingRowTitle>
|
||||
<Segmented
|
||||
options={[
|
||||
{
|
||||
label: t('settings.tool.ocr.mac_system_ocr_options.mode.accurate'),
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
label: t('settings.tool.ocr.mac_system_ocr_options.mode.fast'),
|
||||
value: 0
|
||||
}
|
||||
]}
|
||||
value={options.recognitionLevel}
|
||||
onChange={(value) => onUpdateOptions('recognitionLevel', value)}
|
||||
/>
|
||||
</SettingRow>
|
||||
<SettingDivider style={{ marginTop: 15, marginBottom: 12 }} />
|
||||
<SettingRow>
|
||||
<SettingRowTitle>{t('settings.tool.ocr.mac_system_ocr_options.min_confidence')}</SettingRowTitle>
|
||||
<InputNumber
|
||||
value={options.minConfidence}
|
||||
onChange={(value) => onUpdateOptions('minConfidence', value)}
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.1}
|
||||
/>
|
||||
</SettingRow>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ const persistedReducer = persistReducer(
|
||||
{
|
||||
key: 'cherry-studio',
|
||||
storage,
|
||||
version: 86,
|
||||
version: 87,
|
||||
blacklist: ['runtime', 'messages'],
|
||||
migrate
|
||||
},
|
||||
|
||||
@@ -23,7 +23,11 @@ const initialState: OcrState = {
|
||||
},
|
||||
{
|
||||
id: 'system',
|
||||
name: 'System(Mac Only)'
|
||||
name: 'System(Mac Only)',
|
||||
options: {
|
||||
recognitionLevel: 0,
|
||||
minConfidence: 0.5
|
||||
}
|
||||
}
|
||||
],
|
||||
defaultProvider: ''
|
||||
|
||||
@@ -349,6 +349,7 @@ export interface OcrProvider {
|
||||
apiKey?: string
|
||||
apiHost?: string
|
||||
model?: string
|
||||
options?: any
|
||||
}
|
||||
|
||||
export type GenerateImageParams = {
|
||||
|
||||
Reference in New Issue
Block a user