refactor(desktop): session-scoped voice runtime, STT/LLM ports, caption ownership and meeting export fixes

This commit is contained in:
Yun Chan 2026-09-28 00:53:43 +09:00
parent 0adedf5e7b
commit 83cf9133ac
39 changed files with 4787 additions and 1061 deletions

View file

@ -7,7 +7,8 @@ import path from 'path'
import fs from 'fs'
import { asc, eq } from 'drizzle-orm'
import { getLogger } from './LoggerService'
import { getPremiumLLMService } from './PremiumLLMService'
import { getLlmGateway } from './llm/LlmGateway'
import { extractDocxText } from './rag/docx-text'
import { getOllamaServerUrl } from './LocalLLMService'
import { getDatabase } from '../db'
import { ragDocuments, ragChunks } from '../db/schema'
@ -291,8 +292,8 @@ class RAGService extends EventEmitter {
Documents:
${context}`
const llmService = getPremiumLLMService()
const result = await llmService.generate(queryText, { systemPrompt })
// 답변 LLM 은 사용자가 고른 백엔드를 따른다(로컬 선택 시 문서 조각을 클라우드로 보내지 않는다)
const result = await getLlmGateway().generate(queryText, { systemPrompt })
return {
query: queryText,
@ -487,18 +488,11 @@ ${context}`
if (fileType === 'docx') {
try {
const buffer = await fsp.readFile(filePath)
// DOCX는 ZIP 내 XML — w:t 태그에서 텍스트 추출
const raw = buffer.toString('utf-8')
const matches = raw.match(/<w:t[^>]*>([^<]*)<\/w:t>/g)
if (matches) {
const text = matches
.map((m) => m.replace(/<[^>]+>/g, ''))
.join(' ')
return text.trim()
}
// XML 태그 제거 폴백
return raw.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim().slice(0, 500000)
} catch {
// DOCX는 ZIP 안의 (deflate 압축된) word/document.xml — 압축을 풀어 문단 텍스트를 뽑는다.
// 텍스트를 찾지 못하면 바이너리 잡음을 색인하지 않고 실패시킨다.
return extractDocxText(buffer).slice(0, 500000)
} catch (err) {
logger.warn(`DOCX parsing failed: ${err instanceof Error ? err.message : String(err)}`)
throw new D3ROError(ErrorCode.RAGUnsupportedFormat, 'DOCX parsing failed')
}
}