feat: complete release preparation, 10+ ad mediation, CI/CD, and docker deployment
Some checks failed
CI Pipeline / Code Quality & Typecheck (push) Waiting to run
CI Pipeline / Test Suite (macos-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (ubuntu-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (windows-latest) (push) Blocked by required conditions
CI Pipeline / Build Validation (admin) (push) Blocked by required conditions
CI Pipeline / Build Validation (desktop) (push) Blocked by required conditions
Deploy Landing Page / deploy (push) Blocked by required conditions
Deploy Landing Page / build (push) Waiting to run
Release & Packaging Pipeline / Build & Publish Admin Docker Image (push) Failing after 8s
Release & Code Signing CA Pipeline / build-and-sign-windows (push) Failing after 1m51s
Build macOS / Build & Package (macOS) (push) Failing after 4s
Build macOS / Build & Package (macOS)-1 (push) Failing after 5s
Release & Code Signing CA Pipeline / build-and-sign-macos (push) Failing after 3s
Release & Packaging Pipeline / Package macOS Desktop App (push) Failing after 4s
Release & Packaging Pipeline / Package Windows Desktop App (push) Failing after 2m28s
Release & Packaging Pipeline / Publish Official GitHub Release (push) Has been skipped

This commit is contained in:
Yun Chan 2026-08-20 11:12:05 +09:00
parent 5cd1de6859
commit 708e20f747
406 changed files with 42464 additions and 6199 deletions

View file

@ -21,15 +21,30 @@ const CONFIG_DEFAULTS: AppConfig = {
autoLaunch: false,
soundEnabled: true,
selectedDeviceId: null,
/** 기본 STT 공급자는 로컬 Whisper (오프라인/무료) */
sttProvider: 'local' as const,
sttProviderConfigs: {
local: { modelId: 'large-v3-turbo' },
openai: { modelId: 'whisper-1', apiKey: '', baseUrl: 'https://api.openai.com/v1' },
groq: { modelId: 'whisper-large-v3-turbo', apiKey: '', baseUrl: 'https://api.groq.com/openai/v1' },
deepgram: { modelId: 'nova-3', apiKey: '', baseUrl: 'https://api.deepgram.com' },
assemblyai: { modelId: 'best', apiKey: '', baseUrl: 'https://api.assemblyai.com/v2' },
google: { modelId: 'gemini-2.0-flash', apiKey: '', baseUrl: 'https://generativelanguage.googleapis.com/v1beta' },
custom: { modelId: 'whisper-1', apiKey: '', baseUrl: 'http://localhost:8000/v1' },
},
sttFallbackToLocal: true,
// large-v3 대비 6배 빠르고 정확도 손실 1~2%, 다운로드 1.6GB (온보딩에서 사전 다운로드)
sttModelId: 'large-v3-turbo',
sttLanguage: 'auto',
ttsVoiceId: null,
ttsSpeed: 1.0,
onlineApiUrl: 'http://localhost:5000',
localModelsDir: '',
llmModelId: 'gemma-2-2b-it.Q4_K_M.gguf',
ollamaServerUrl: 'http://localhost:11434',
llmModelId: null,
// Phase 3.2: 기본값은 'local' — 누구나 로그인 없이 로컬 Ollama로 쓸 수 있는
// 엔트리 전략. 사용자가 Settings에서 'premium'으로 전환 시 로그인 + 구독 필요.
appUsageMode: null,
authToken: null,
userEmail: null,
llmBackend: 'local' as const,
// 라이브 음성 대화 백엔드 — 'realtime'은 로그인+구독 필요 (OpenAI Realtime WebRTC)
conversationBackend: 'local' as const,
@ -96,6 +111,33 @@ const CONFIG_DEFAULTS: AppConfig = {
let store: ElectronStore<AppConfig> | null = null
const emitter = new EventEmitter()
function createMemoryStore(initial: AppConfig): ElectronStore<AppConfig> {
let data: AppConfig = { ...initial }
return {
get<K extends keyof AppConfig>(key: K): AppConfig[K] {
return data[key]
},
set<K extends keyof AppConfig>(key: K, value: AppConfig[K]): void {
data[key] = value
},
get store(): AppConfig {
return data
},
set store(next: AppConfig) {
data = { ...next }
},
}
}
/** electron-store 없이 설정 CRUD를 가능하게 한다 (테스트 + 초기화 전 안전망). */
export function initInMemoryConfig(overrides?: Partial<AppConfig>): void {
store = createMemoryStore({ ...CONFIG_DEFAULTS, ...overrides })
}
export function resetInMemoryConfig(): void {
store = null
}
export async function initConfigService(): Promise<void> {
const { default: Store } = await import('electron-store')
store = new Store<AppConfig>({
@ -119,8 +161,8 @@ export function configGet<K extends keyof AppConfig>(key: K): AppConfig[K] {
export function configSet<K extends keyof AppConfig>(key: K, value: AppConfig[K]): void {
if (!store) {
logger.warn(`ConfigService not initialized, cannot set "${key}"`)
return
logger.warn(`ConfigService not initialized — using in-memory store for "${key}"`)
initInMemoryConfig()
}
const previousValue = store.get(key)
store.set(key, value)