fix(settings): show the live caption model under the dictation model
The caption model selector now sits directly under the dictation model in the STT tab's Local Whisper card, where people look for it, and stays in the General tab's caption section as well; both use one shared component. The first selector is renamed to 'Dictation model' so the two are told apart.
This commit is contained in:
parent
da0da98285
commit
ad6bb70c20
15 changed files with 68 additions and 35 deletions
41
apps/desktop/src/renderer/components/CaptionModelSelect.tsx
Normal file
41
apps/desktop/src/renderer/components/CaptionModelSelect.tsx
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// 실시간 자막 전용 로컬 Whisper 모델 선택 — STT 탭과 일반 탭 자막 섹션이 함께 쓴다.
|
||||
|
||||
import { FormControl, InputLabel, MenuItem, Select, Typography } from '@mui/material'
|
||||
import { d3roPalette, d3roTypo } from '@d3ro/ui/theme'
|
||||
import { useI18n } from '@d3ro/i18n'
|
||||
import type { STTModel } from '@d3ro/core/types'
|
||||
|
||||
/** "받아쓰기와 같게" — 설정에는 null 로 저장한다 */
|
||||
const SAME_AS_DICTATION = '__same__'
|
||||
|
||||
interface CaptionModelSelectProps {
|
||||
value: string | null | undefined
|
||||
/** 선택지로 보일 모델 — 받아 둔 모델만 넘긴다 */
|
||||
models: readonly STTModel[]
|
||||
onChange: (modelId: string | null) => void
|
||||
fullWidth?: boolean
|
||||
}
|
||||
|
||||
export function CaptionModelSelect({ value, models, onChange, fullWidth }: CaptionModelSelectProps): React.ReactElement {
|
||||
const { t } = useI18n()
|
||||
return (
|
||||
<FormControl size="small" fullWidth={fullWidth}>
|
||||
<InputLabel>{t('settings.captionModel')}</InputLabel>
|
||||
<Select
|
||||
label={t('settings.captionModel')}
|
||||
value={value ?? SAME_AS_DICTATION}
|
||||
onChange={(e) => onChange(e.target.value === SAME_AS_DICTATION ? null : e.target.value)}
|
||||
>
|
||||
<MenuItem value={SAME_AS_DICTATION}>{t('settings.captionModel.same')}</MenuItem>
|
||||
{models.map((m) => (
|
||||
<MenuItem key={m.id} value={m.id}>
|
||||
{m.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<Typography sx={{ mt: 0.5, fontSize: d3roTypo.meta.size, color: d3roPalette.text.secondary }}>
|
||||
{t('settings.captionModel.desc')}
|
||||
</Typography>
|
||||
</FormControl>
|
||||
)
|
||||
}
|
||||
|
|
@ -50,6 +50,7 @@ import type {
|
|||
STTModel,
|
||||
} from '@d3ro/core/types'
|
||||
import { CodexOAuthGuideModal } from './CodexOAuthGuideModal'
|
||||
import { CaptionModelSelect } from './CaptionModelSelect'
|
||||
|
||||
interface STTTabProps {
|
||||
config: Partial<AppConfig>
|
||||
|
|
@ -362,6 +363,14 @@ export function STTTab({ config, updateConfig }: STTTabProps): React.ReactElemen
|
|||
</Select>
|
||||
</FormControl>
|
||||
|
||||
{/* 실시간 자막 전용 모델 — 1초마다 다시 인식하므로 받아쓰기와 다른 모델이 나을 수 있다 */}
|
||||
<CaptionModelSelect
|
||||
fullWidth
|
||||
value={config.captionSttModelId}
|
||||
models={localModels.filter((m) => m.downloaded)}
|
||||
onChange={(modelId) => updateConfig('captionSttModelId', modelId)}
|
||||
/>
|
||||
|
||||
{/* 모델 다운로드 진행 바 또는 다운로드 버튼 */}
|
||||
{(() => {
|
||||
const selected = localModels.find((m) => m.id === (config.sttModelId ?? 'large-v3-turbo'))
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import { Led } from '@d3ro/ui/components/ds'
|
|||
import { LicenseTab } from './LicenseTab'
|
||||
import { CloudSyncSection } from './CloudSyncSection'
|
||||
import { STTTab } from './STTTab'
|
||||
import { CaptionModelSelect } from './CaptionModelSelect'
|
||||
import { InputConsentPanel } from './input-insights/InputConsentPanel'
|
||||
import { KeyBindingField } from './keybinding/KeyBindingField'
|
||||
import { asTranslationKey } from './keybinding/translation-key'
|
||||
|
|
@ -64,9 +65,6 @@ const ACTION_GROUP_LABEL_KEYS: Readonly<Record<KeyBindingActionGroup, string>> =
|
|||
|
||||
const ACTION_GROUP_ORDER: readonly KeyBindingActionGroup[] = ['voice', 'window', 'input']
|
||||
|
||||
/** 자막 모델 선택지 "받아쓰기와 같게" — 설정에는 null 로 저장한다 */
|
||||
const SAME_AS_DICTATION = '__same__'
|
||||
|
||||
export function SettingsModal({ open, initialTab = 0, onClose }: SettingsModalProps): React.ReactElement {
|
||||
const { t, locale, setLocale } = useI18n()
|
||||
const [activeTab, setActiveTab] = useState(initialTab)
|
||||
|
|
@ -493,26 +491,11 @@ export function SettingsModal({ open, initialTab = 0, onClose }: SettingsModalPr
|
|||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<FormControl size="small">
|
||||
<InputLabel>{t('settings.captionModel')}</InputLabel>
|
||||
<Select
|
||||
label={t('settings.captionModel')}
|
||||
value={config.captionSttModelId ?? SAME_AS_DICTATION}
|
||||
onChange={(e) =>
|
||||
updateConfig('captionSttModelId', e.target.value === SAME_AS_DICTATION ? null : e.target.value)
|
||||
}
|
||||
>
|
||||
<MenuItem value={SAME_AS_DICTATION}>{t('settings.captionModel.same')}</MenuItem>
|
||||
{downloadedSttModels.map((m) => (
|
||||
<MenuItem key={m.id} value={m.id}>
|
||||
{m.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<Typography sx={{ mt: 0.5, fontSize: d3roTypo.meta.size, color: d3roPalette.text.secondary }}>
|
||||
{t('settings.captionModel.desc')}
|
||||
</Typography>
|
||||
</FormControl>
|
||||
<CaptionModelSelect
|
||||
value={config.captionSttModelId}
|
||||
models={downloadedSttModels}
|
||||
onChange={(modelId) => updateConfig('captionSttModelId', modelId)}
|
||||
/>
|
||||
|
||||
<FormControlLabel
|
||||
sx={{ mr: 0, alignItems: 'flex-start' }}
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@
|
|||
"settings.insertMethod": "Einfügemethode",
|
||||
"settings.insertClipboard": "Zwischenablage (Ctrl+V)",
|
||||
"settings.insertKeyboard": "Tastatureingabe",
|
||||
"settings.whisperModel": "Whisper-Modell",
|
||||
"settings.whisperModel": "Diktiermodell",
|
||||
"settings.model.tiny": "tiny (39 MB, am schnellsten)",
|
||||
"settings.model.base": "base (74 MB, ausgewogen)",
|
||||
"settings.model.small": "small (244 MB, gut)",
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@
|
|||
"settings.sttProvider.custom": "Custom (OpenAI-Compatible)",
|
||||
"settings.sttFallbackToLocal": "Auto Fallback to Local Whisper",
|
||||
"settings.sttFallbackToLocalHint": "Automatically switch to offline local Whisper if cloud STT fails",
|
||||
"settings.whisperModel": "Whisper Model",
|
||||
"settings.whisperModel": "Dictation model",
|
||||
"settings.model.tiny": "tiny (39 MB, fastest)",
|
||||
"settings.model.base": "base (74 MB, balanced)",
|
||||
"settings.model.small": "small (244 MB, good)",
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@
|
|||
"settings.insertMethod": "Método de inserción",
|
||||
"settings.insertClipboard": "Portapapeles (Ctrl+V)",
|
||||
"settings.insertKeyboard": "Escritura con teclado",
|
||||
"settings.whisperModel": "Modelo Whisper",
|
||||
"settings.whisperModel": "Modelo de dictado",
|
||||
"settings.model.tiny": "tiny (39 MB, más rápido)",
|
||||
"settings.model.base": "base (74 MB, equilibrado)",
|
||||
"settings.model.small": "small (244 MB, bueno)",
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@
|
|||
"settings.insertMethod": "Méthode d'insertion",
|
||||
"settings.insertClipboard": "Presse-papiers (Ctrl+V)",
|
||||
"settings.insertKeyboard": "Frappe au clavier",
|
||||
"settings.whisperModel": "Modèle Whisper",
|
||||
"settings.whisperModel": "Modèle de dictée",
|
||||
"settings.model.tiny": "tiny (39 Mo, le plus rapide)",
|
||||
"settings.model.base": "base (74 Mo, équilibré)",
|
||||
"settings.model.small": "small (244 Mo, bon)",
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@
|
|||
"settings.insertMethod": "挿入方式",
|
||||
"settings.insertClipboard": "クリップボード (Ctrl+V)",
|
||||
"settings.insertKeyboard": "キーボード入力",
|
||||
"settings.whisperModel": "Whisperモデル",
|
||||
"settings.whisperModel": "音声入力モデル",
|
||||
"settings.model.tiny": "tiny (39 MB, 最速)",
|
||||
"settings.model.base": "base (74 MB, バランス)",
|
||||
"settings.model.small": "small (244 MB, 良好)",
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@
|
|||
"settings.sttProvider.custom": "커스텀 OpenAI 호환 엔드포인트",
|
||||
"settings.sttFallbackToLocal": "로컬 Whisper 자동 폴백",
|
||||
"settings.sttFallbackToLocalHint": "클라우드 STT 실패 시 오프라인 로컬 Whisper로 자동 전환",
|
||||
"settings.whisperModel": "Whisper 모델",
|
||||
"settings.whisperModel": "받아쓰기 모델",
|
||||
"settings.model.tiny": "tiny (39 MB, 가장 빠름)",
|
||||
"settings.model.base": "base (74 MB, 균형)",
|
||||
"settings.model.small": "small (244 MB, 양호)",
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@
|
|||
"settings.insertMethod": "Método de inserção",
|
||||
"settings.insertClipboard": "Área de transferência (Ctrl+V)",
|
||||
"settings.insertKeyboard": "Digitação pelo teclado",
|
||||
"settings.whisperModel": "Modelo Whisper",
|
||||
"settings.whisperModel": "Modelo de ditado",
|
||||
"settings.model.tiny": "tiny (39 MB, mais rápido)",
|
||||
"settings.model.base": "base (74 MB, equilibrado)",
|
||||
"settings.model.small": "small (244 MB, bom)",
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@
|
|||
"settings.insertMethod": "Метод вставки",
|
||||
"settings.insertClipboard": "Буфер обмена (Ctrl+V)",
|
||||
"settings.insertKeyboard": "Эмуляция клавиатуры",
|
||||
"settings.whisperModel": "Модель Whisper",
|
||||
"settings.whisperModel": "Модель диктовки",
|
||||
"settings.model.tiny": "tiny (39 МБ, самая быстрая)",
|
||||
"settings.model.base": "base (74 МБ, баланс)",
|
||||
"settings.model.small": "small (244 МБ, хорошая)",
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@
|
|||
"settings.insertMethod": "วิธีการแทรก",
|
||||
"settings.insertClipboard": "คลิปบอร์ด (Ctrl+V)",
|
||||
"settings.insertKeyboard": "จำลองการพิมพ์",
|
||||
"settings.whisperModel": "โมเดล Whisper",
|
||||
"settings.whisperModel": "โมเดลพิมพ์ด้วยเสียง",
|
||||
"settings.model.tiny": "tiny (39 MB, เร็วที่สุด)",
|
||||
"settings.model.base": "base (74 MB, สมดุล)",
|
||||
"settings.model.small": "small (244 MB, ดี)",
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@
|
|||
"settings.insertMethod": "Phương thức chèn",
|
||||
"settings.insertClipboard": "Bộ nhớ tạm (Ctrl+V)",
|
||||
"settings.insertKeyboard": "Giả lập bàn phím",
|
||||
"settings.whisperModel": "Mô hình Whisper",
|
||||
"settings.whisperModel": "Mô hình đọc chính tả",
|
||||
"settings.model.tiny": "tiny (39 MB, nhanh nhất)",
|
||||
"settings.model.base": "base (74 MB, cân bằng)",
|
||||
"settings.model.small": "small (244 MB, tốt)",
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@
|
|||
"settings.insertMethod": "插入方式",
|
||||
"settings.insertClipboard": "剪貼簿(Ctrl+V)",
|
||||
"settings.insertKeyboard": "鍵盤輸入",
|
||||
"settings.whisperModel": "Whisper模型",
|
||||
"settings.whisperModel": "聽寫模型",
|
||||
"settings.model.tiny": "tiny(39 MB,最快)",
|
||||
"settings.model.base": "base(74 MB,均衡)",
|
||||
"settings.model.small": "small(244 MB,良好)",
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@
|
|||
"settings.insertMethod": "插入方式",
|
||||
"settings.insertClipboard": "剪贴板(Ctrl+V)",
|
||||
"settings.insertKeyboard": "键盘输入",
|
||||
"settings.whisperModel": "Whisper模型",
|
||||
"settings.whisperModel": "听写模型",
|
||||
"settings.model.tiny": "tiny(39 MB,最快)",
|
||||
"settings.model.base": "base(74 MB,均衡)",
|
||||
"settings.model.small": "small(244 MB,良好)",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue