feat(bootstrap): Whisper large-v3-turbo 기본 전환 + 온보딩 2단계 다운로드 진행률

- 기본 STT 모델 base → large-v3-turbo (6배 빠름, 1.6GB)
- 사이드카: /download, /download/status, /download/cancel + --models-dir
- LocalSTTService: downloadModel/cancelDownload + download-progress 이벤트
- IPC: 설계서 02의 stt:downloadModel/cancelDownload/downloadProgress 구현
- OnboardingModal: LLM(gemma4:e4b) → STT(turbo) 2단계 순차 다운로드 UI
- SettingsModal turbo 선택지 + settings.model.largeTurbo 12 locale
- 테스트: 모노레포 잔재 import 수정 (src/shared → @d3ro/core), 41/41 통과
This commit is contained in:
Yun Chan 2026-07-21 11:59:49 +09:00
parent 9dc8b26c11
commit 983c60cda2
27 changed files with 688 additions and 76 deletions

View file

@ -2,12 +2,29 @@
import { ipcMain } from 'electron'
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
import { ipcSuccess, ipcError, ErrorCode } from '@d3ro/core/errors'
import { ipcSuccess, ipcError, ErrorCode, D3ROError } from '@d3ro/core/errors'
import { getLocalSTTService } from '../services/LocalSTTService'
import { configGet, configSet } from '../services/ConfigService'
import type { SetSTTModelParams, SetSTTLanguageParams } from '@d3ro/core/types'
import { getMainWindow } from '../windows/WindowManager'
import type {
SetSTTModelParams,
SetSTTLanguageParams,
DownloadModelParams,
} from '@d3ro/core/types'
function safeSendToRenderer(channel: string, data: unknown): void {
const win = getMainWindow()
if (win && !win.isDestroyed()) {
win.webContents.send(channel, data)
}
}
export function registerSTTHandlers(): void {
// 다운로드 진행률 → 렌더러
getLocalSTTService().on('download-progress', (payload) => {
safeSendToRenderer(IPC_CHANNELS.STT.DOWNLOAD_PROGRESS, payload)
})
ipcMain.handle(IPC_CHANNELS.STT.GET_STATUS, async () => {
try {
const stt = getLocalSTTService()
@ -41,6 +58,27 @@ export function registerSTTHandlers(): void {
}
})
ipcMain.handle(
IPC_CHANNELS.STT.DOWNLOAD_MODEL,
async (_event, params: DownloadModelParams) => {
try {
await getLocalSTTService().downloadModel(params.modelId)
return ipcSuccess(undefined)
} catch (err) {
if (err instanceof D3ROError) {
return ipcError(err.code, err.message)
}
const msg = err instanceof Error ? err.message : String(err)
return ipcError(ErrorCode.STTModelDownloadFailed, `Model download failed: ${msg}`)
}
},
)
ipcMain.handle(IPC_CHANNELS.STT.CANCEL_DOWNLOAD, async () => {
await getLocalSTTService().cancelDownload()
return ipcSuccess(undefined)
})
ipcMain.handle(IPC_CHANNELS.STT.GET_LANGUAGE, async () => {
return ipcSuccess(configGet('sttLanguage'))
})