실시간 녹음 + 타임스탬프 메모 + STT 전사 + LLM 구조화 회의록 + PDF/MD 내보내기. CaptionService 연동, 동시 사용 충돌 방지, 긴 회의 2-pass 요약 지원. DB 2테이블, IPC 15채널, UI 3뷰(목록/녹음/상세), 12개 locale i18n.
1360 lines
28 KiB
TypeScript
1360 lines
28 KiB
TypeScript
// src/shared/types.ts
|
|
// 모든 IPC 파라미터/반환 타입 정의
|
|
|
|
// ============================================================
|
|
// Common
|
|
// ============================================================
|
|
|
|
export type ThemeMode = 'light' | 'dark' | 'auto' | 'nord' | 'solarized' | 'catppuccin' | 'dracula'
|
|
|
|
export type VoiceMode = 'dictation' | 'hands-free'
|
|
|
|
export type PermissionStatus = 'granted' | 'denied' | 'unknown'
|
|
|
|
// ============================================================
|
|
// Voice (음성 오케스트레이션)
|
|
// ============================================================
|
|
|
|
export enum RecognitionState {
|
|
IDLE = 'idle',
|
|
PREPARING = 'preparing',
|
|
CONNECTING = 'connecting',
|
|
READY = 'ready',
|
|
RECOGNIZING = 'recognizing',
|
|
COMPLETED = 'completed',
|
|
CANCELLED = 'cancelled',
|
|
ERROR = 'error',
|
|
DESTROYED = 'destroyed'
|
|
}
|
|
|
|
export enum AudioState {
|
|
IDLE = 'idle',
|
|
INITIALIZING = 'initializing',
|
|
STREAMING = 'streaming',
|
|
STOPPED = 'stopped'
|
|
}
|
|
|
|
export interface VoiceState {
|
|
recognitionState: RecognitionState
|
|
audioState: AudioState
|
|
mode: VoiceMode
|
|
sessionId: string | null
|
|
recordingStartedAt: number | null
|
|
}
|
|
|
|
export interface StartRecordingParams {
|
|
sessionId?: string
|
|
deviceId?: string
|
|
}
|
|
|
|
export interface StartRecordingResult {
|
|
sessionId: string
|
|
}
|
|
|
|
export interface StopRecordingParams {
|
|
sessionId: string
|
|
}
|
|
|
|
export interface StopRecordingResult {
|
|
sessionId: string
|
|
text: string
|
|
durationMs: number
|
|
}
|
|
|
|
export interface CancelRecordingParams {
|
|
sessionId: string
|
|
}
|
|
|
|
export interface SetVoiceModeParams {
|
|
mode: VoiceMode
|
|
}
|
|
|
|
// Voice events (Main → Renderer)
|
|
|
|
export interface VoiceStateChangedEvent {
|
|
previousState: RecognitionState
|
|
currentState: RecognitionState
|
|
audioState: AudioState
|
|
sessionId: string | null
|
|
}
|
|
|
|
export interface TranscriptionDeltaEvent {
|
|
sessionId: string
|
|
text: string
|
|
delta: string
|
|
isFinal: boolean
|
|
}
|
|
|
|
export interface TranscriptionCompleteEvent {
|
|
sessionId: string
|
|
text: string
|
|
durationMs: number
|
|
language: string
|
|
}
|
|
|
|
export interface VoiceErrorEvent {
|
|
sessionId: string | null
|
|
errorCode: number
|
|
message: string
|
|
}
|
|
|
|
export interface AudioLevelEvent {
|
|
level: number
|
|
}
|
|
|
|
// ============================================================
|
|
// Audio (디바이스 & 캡처)
|
|
// ============================================================
|
|
|
|
export interface AudioDevice {
|
|
deviceId: string
|
|
label: string
|
|
isDefault: boolean
|
|
}
|
|
|
|
export interface SetDeviceParams {
|
|
deviceId: string
|
|
}
|
|
|
|
export interface TestDeviceParams {
|
|
deviceId: string
|
|
durationMs?: number
|
|
}
|
|
|
|
export interface TestDeviceResult {
|
|
averageLevel: number
|
|
peakLevel: number
|
|
hasAudio: boolean
|
|
}
|
|
|
|
export interface AudioDeviceChangedEvent {
|
|
devices: AudioDevice[]
|
|
type: 'added' | 'removed' | 'default-changed'
|
|
}
|
|
|
|
// ============================================================
|
|
// STT (로컬 Whisper)
|
|
// ============================================================
|
|
|
|
export enum STTEngineState {
|
|
NOT_INSTALLED = 'not-installed',
|
|
DOWNLOADING = 'downloading',
|
|
LOADING = 'loading',
|
|
READY = 'ready',
|
|
PROCESSING = 'processing',
|
|
ERROR = 'error'
|
|
}
|
|
|
|
export interface STTStatus {
|
|
engineState: STTEngineState
|
|
activeModel: string | null
|
|
engineVersion: string | null
|
|
gpuAccelerated: boolean
|
|
}
|
|
|
|
export interface STTModel {
|
|
id: string
|
|
name: string
|
|
sizeBytes: number
|
|
downloaded: boolean
|
|
languages: string[]
|
|
accuracy: number
|
|
speed: number
|
|
}
|
|
|
|
export interface SetSTTModelParams {
|
|
modelId: string
|
|
}
|
|
|
|
export interface DownloadModelParams {
|
|
modelId: string
|
|
}
|
|
|
|
export interface SetSTTLanguageParams {
|
|
language: string
|
|
}
|
|
|
|
export interface STTStatusChangedEvent {
|
|
status: STTStatus
|
|
}
|
|
|
|
export interface DownloadProgressEvent {
|
|
modelId: string
|
|
percent: number
|
|
downloadedBytes: number
|
|
totalBytes: number
|
|
bytesPerSecond: number
|
|
}
|
|
|
|
// ============================================================
|
|
// TTS (로컬 TTS)
|
|
// ============================================================
|
|
|
|
export enum TTSEngineState {
|
|
NOT_INSTALLED = 'not-installed',
|
|
LOADING = 'loading',
|
|
READY = 'ready',
|
|
SPEAKING = 'speaking',
|
|
ERROR = 'error'
|
|
}
|
|
|
|
export interface TTSStatus {
|
|
engineState: TTSEngineState
|
|
activeVoice: string | null
|
|
engineVersion: string | null
|
|
}
|
|
|
|
export interface TTSVoice {
|
|
id: string
|
|
name: string
|
|
language: string
|
|
gender: 'male' | 'female' | 'neutral'
|
|
downloaded: boolean
|
|
sizeBytes: number
|
|
}
|
|
|
|
export interface TTSSpeakParams {
|
|
text: string
|
|
voiceId?: string
|
|
speed?: number
|
|
}
|
|
|
|
export interface TTSSpeakResult {
|
|
durationMs: number
|
|
}
|
|
|
|
export interface SetTTSVoiceParams {
|
|
voiceId: string
|
|
}
|
|
|
|
export interface DownloadVoiceParams {
|
|
voiceId: string
|
|
}
|
|
|
|
export interface TTSStatusChangedEvent {
|
|
status: TTSStatus
|
|
}
|
|
|
|
export interface SpeakingStateChangedEvent {
|
|
isSpeaking: boolean
|
|
text: string
|
|
}
|
|
|
|
// ============================================================
|
|
// LLM (Ollama)
|
|
// ============================================================
|
|
|
|
export enum LLMConnectionState {
|
|
DISCONNECTED = 'disconnected',
|
|
CONNECTING = 'connecting',
|
|
CONNECTED = 'connected',
|
|
ERROR = 'error'
|
|
}
|
|
|
|
export interface LLMStatus {
|
|
connectionState: LLMConnectionState
|
|
serverUrl: string
|
|
activeModel: string | null
|
|
serverVersion: string | null
|
|
}
|
|
|
|
export interface LLMModel {
|
|
id: string
|
|
name: string
|
|
sizeBytes: number
|
|
parameterSize: string
|
|
quantization: string
|
|
modifiedAt: string
|
|
}
|
|
|
|
export type LLMAction = 'refine' | 'translate' | 'summarize' | 'expand' | 'grammar' | 'custom' | 'chain'
|
|
|
|
export interface LLMProcessParams {
|
|
text: string
|
|
action: LLMAction
|
|
targetLanguage?: string
|
|
customPrompt?: string
|
|
modelId?: string
|
|
}
|
|
|
|
export interface LLMProcessResult {
|
|
originalText: string
|
|
processedText: string
|
|
action: LLMAction
|
|
processingTimeMs: number
|
|
tokenCount: number
|
|
}
|
|
|
|
export interface SetLLMModelParams {
|
|
modelId: string
|
|
}
|
|
|
|
export interface SetServerUrlParams {
|
|
url: string
|
|
}
|
|
|
|
export interface PullModelParams {
|
|
modelName: string
|
|
}
|
|
|
|
export interface LLMStatusChangedEvent {
|
|
status: LLMStatus
|
|
}
|
|
|
|
export interface LLMProcessProgressEvent {
|
|
text: string
|
|
token: string
|
|
done: boolean
|
|
}
|
|
|
|
export interface LLMPullProgressEvent {
|
|
modelName: string
|
|
status: string
|
|
percent: number
|
|
downloadedBytes: number
|
|
totalBytes: number
|
|
}
|
|
|
|
// ============================================================
|
|
// Hotkey (핫키)
|
|
// ============================================================
|
|
|
|
export interface HotkeyBinding {
|
|
keyCode: number
|
|
ctrl: boolean
|
|
alt: boolean
|
|
shift: boolean
|
|
meta: boolean
|
|
displayLabel: string
|
|
}
|
|
|
|
export interface SetHotkeyParams {
|
|
binding: HotkeyBinding
|
|
}
|
|
|
|
export interface SetEnabledParams {
|
|
enabled: boolean
|
|
}
|
|
|
|
export type HotkeyAction = 'dictation' | 'hands-free' | 'command' | 'caption'
|
|
|
|
export interface HotkeyTriggeredEvent {
|
|
action: HotkeyAction
|
|
type: 'pressed' | 'released'
|
|
isDoublePress: boolean
|
|
}
|
|
|
|
export interface HotkeyRecordingResultEvent {
|
|
binding: HotkeyBinding | null
|
|
conflictReason: string | null
|
|
}
|
|
|
|
// ============================================================
|
|
// Config (설정)
|
|
// ============================================================
|
|
|
|
export interface AppConfig {
|
|
theme: ThemeMode
|
|
language: string
|
|
closeToTray: boolean
|
|
autoLaunch: boolean
|
|
soundEnabled: boolean
|
|
selectedDeviceId: string | null
|
|
sttModelId: string
|
|
sttLanguage: string
|
|
ttsVoiceId: string | null
|
|
ttsSpeed: number
|
|
ollamaServerUrl: string
|
|
llmModelId: string | null
|
|
defaultLLMAction: LLMAction
|
|
dictationShortcut: HotkeyBinding
|
|
handsFreeShortcut: HotkeyBinding
|
|
commandShortcut: HotkeyBinding
|
|
/** 실시간 자막 토글 핫키 (Phase 10.1) */
|
|
captionShortcut: HotkeyBinding
|
|
hotkeyEnabled: boolean
|
|
insertMethod: 'clipboard' | 'keyboard'
|
|
autoInsert: boolean
|
|
maxHistoryEntries: number
|
|
/** 받아쓰기 모드 활성화 (hold-to-talk) */
|
|
dictationEnabled: boolean
|
|
/** Agent 모드 활성화 (더블프레스, dictation 의존) */
|
|
agentModeEnabled: boolean
|
|
/** 핸즈프리 모드 활성화 (토글) */
|
|
handsFreeEnabled: boolean
|
|
/** 스크린 컨텍스트 캡처 활성화 (Phase 10.2) */
|
|
screenContextEnabled: boolean
|
|
}
|
|
|
|
export interface ConfigGetParams {
|
|
key: keyof AppConfig
|
|
}
|
|
|
|
export interface ConfigSetParams {
|
|
key: keyof AppConfig
|
|
value: AppConfig[keyof AppConfig]
|
|
}
|
|
|
|
export interface ConfigResetParams {
|
|
key?: keyof AppConfig
|
|
}
|
|
|
|
export interface SetThemeParams {
|
|
theme: ThemeMode
|
|
}
|
|
|
|
export interface SetLanguageParams {
|
|
language: string
|
|
}
|
|
|
|
export interface SetAutoLaunchParams {
|
|
enabled: boolean
|
|
}
|
|
|
|
export interface SetCloseToTrayParams {
|
|
enabled: boolean
|
|
}
|
|
|
|
export interface ConfigChangedEvent {
|
|
key: keyof AppConfig
|
|
value: AppConfig[keyof AppConfig]
|
|
previousValue: AppConfig[keyof AppConfig]
|
|
}
|
|
|
|
// ============================================================
|
|
// History (히스토리)
|
|
// ============================================================
|
|
|
|
export interface HistoryEntry {
|
|
id: string
|
|
originalText: string
|
|
polishedText: string | null
|
|
focusedApp: string | null
|
|
focusedAppName: string | null
|
|
focusedAppWindowTitle: string | null
|
|
mode: 'dictation' | 'translate' | 'command' | 'caption' | 'file-transcription'
|
|
status: 'completed' | 'cancelled' | 'error'
|
|
errorCode: string | null
|
|
audioLocalPath: string | null
|
|
duration: number
|
|
detectedLanguage: string | null
|
|
micDevice: string | null
|
|
wordCount: number
|
|
sttModel: string | null
|
|
llmModel: string | null
|
|
sttLatencyMs: number | null
|
|
llmLatencyMs: number | null
|
|
createdAt: number
|
|
updatedAt: number
|
|
appVersion: string
|
|
/** Phase 12.2: 회의록 요약 마크다운 */
|
|
summaryText: string | null
|
|
}
|
|
|
|
export interface HistoryQueryParams {
|
|
page: number
|
|
pageSize: number
|
|
sortBy?: 'createdAt' | 'durationMs' | 'wordCount'
|
|
sortOrder?: 'asc' | 'desc'
|
|
}
|
|
|
|
export interface HistoryPage {
|
|
entries: HistoryEntry[]
|
|
total: number
|
|
page: number
|
|
pageSize: number
|
|
totalPages: number
|
|
}
|
|
|
|
export interface HistoryGetByIdParams {
|
|
id: string
|
|
}
|
|
|
|
export interface HistoryDeleteParams {
|
|
id: string
|
|
}
|
|
|
|
export interface HistorySearchParams {
|
|
query: string
|
|
page: number
|
|
pageSize: number
|
|
}
|
|
|
|
export interface HistoryExportParams {
|
|
format: 'json' | 'csv'
|
|
from?: string
|
|
to?: string
|
|
}
|
|
|
|
// ============================================================
|
|
// Dictionary (사전)
|
|
// ============================================================
|
|
|
|
export interface DictionaryEntry {
|
|
id: string
|
|
word: string
|
|
pronunciation: string | null
|
|
category: 'user' | 'auto' | 'technical'
|
|
usageCount: number
|
|
lastUsedAt: number | null
|
|
createdAt: number
|
|
updatedAt: number
|
|
}
|
|
|
|
export interface DictionaryQueryParams {
|
|
page: number
|
|
pageSize: number
|
|
sortBy?: 'word' | 'category' | 'usageCount' | 'createdAt'
|
|
sortOrder?: 'asc' | 'desc'
|
|
}
|
|
|
|
export interface DictionaryPage {
|
|
entries: DictionaryEntry[]
|
|
total: number
|
|
page: number
|
|
pageSize: number
|
|
totalPages: number
|
|
}
|
|
|
|
export interface DictionaryAddParams {
|
|
word: string
|
|
pronunciation?: string
|
|
category?: 'user' | 'auto' | 'technical'
|
|
}
|
|
|
|
export interface DictionaryUpdateParams {
|
|
id: string
|
|
word?: string
|
|
pronunciation?: string
|
|
category?: 'user' | 'auto' | 'technical'
|
|
}
|
|
|
|
export interface DictionaryDeleteParams {
|
|
id: string
|
|
}
|
|
|
|
export interface DictionaryImportParams {
|
|
filePath: string
|
|
format: 'json' | 'csv'
|
|
}
|
|
|
|
export interface DictionaryImportResult {
|
|
imported: number
|
|
skipped: number
|
|
errors: number
|
|
}
|
|
|
|
export interface DictionaryExportParams {
|
|
format: 'json' | 'csv'
|
|
}
|
|
|
|
export interface DictionarySearchParams {
|
|
query: string
|
|
page: number
|
|
pageSize: number
|
|
}
|
|
|
|
// ============================================================
|
|
// Window (윈도우 제어)
|
|
// ============================================================
|
|
|
|
export type RecordingTipState = 'opening' | 'recording' | 'thinking' | 'result' | 'error'
|
|
|
|
export interface ShowRecordingTipParams {
|
|
state: RecordingTipState
|
|
text?: string
|
|
errorMessage?: string
|
|
}
|
|
|
|
export interface ShowResultPopupParams {
|
|
text: string
|
|
autoHideMs?: number
|
|
}
|
|
|
|
export interface TipMeasuredParams {
|
|
width: number
|
|
height: number
|
|
}
|
|
|
|
export interface TipStateChangedEvent {
|
|
state: RecordingTipState
|
|
text?: string
|
|
errorMessage?: string
|
|
}
|
|
|
|
export interface TipPrepareEvent {
|
|
state: RecordingTipState
|
|
text?: string
|
|
}
|
|
|
|
export interface TipShowEvent {
|
|
state: RecordingTipState
|
|
}
|
|
|
|
// ============================================================
|
|
// System (시스템)
|
|
// ============================================================
|
|
|
|
export interface ActiveAppInfo {
|
|
name: string
|
|
title: string
|
|
pid: number
|
|
}
|
|
|
|
export interface ShowNotificationParams {
|
|
title: string
|
|
body: string
|
|
type?: 'info' | 'warning' | 'error'
|
|
}
|
|
|
|
export interface OpenExternalParams {
|
|
url: string
|
|
}
|
|
|
|
export interface InsertTextParams {
|
|
text: string
|
|
method?: 'clipboard' | 'keyboard'
|
|
}
|
|
|
|
export interface InsertTextResult {
|
|
success: boolean
|
|
insertedLength: number
|
|
}
|
|
|
|
export type SoundEffect =
|
|
| 'recording-start'
|
|
| 'recording-stop'
|
|
| 'transcription-complete'
|
|
| 'error'
|
|
| 'notification'
|
|
|
|
export interface PlaySoundParams {
|
|
sound: SoundEffect
|
|
}
|
|
|
|
export interface SetSoundEnabledParams {
|
|
enabled: boolean
|
|
}
|
|
|
|
// ============================================================
|
|
// Stats (통계)
|
|
// ============================================================
|
|
|
|
export interface StatsSummary {
|
|
totalRecordingTimeMs: number
|
|
totalWordCount: number
|
|
totalSessionCount: number
|
|
todayRecordingTimeMs: number
|
|
todayWordCount: number
|
|
todaySessionCount: number
|
|
streakDays: number
|
|
}
|
|
|
|
export interface StatsQueryParams {
|
|
from: string
|
|
to: string
|
|
}
|
|
|
|
export interface DailyStats {
|
|
date: string
|
|
recordingTimeMs: number
|
|
wordCount: number
|
|
sessionCount: number
|
|
}
|
|
|
|
export interface WeeklyStats {
|
|
weekStart: string
|
|
recordingTimeMs: number
|
|
wordCount: number
|
|
sessionCount: number
|
|
}
|
|
|
|
// ============================================================
|
|
// Phase 10: Memo Tags (10.3)
|
|
// ============================================================
|
|
|
|
export interface MemoTag {
|
|
id: string
|
|
historyId: string
|
|
tag: string
|
|
createdAt: number
|
|
}
|
|
|
|
export interface AddTagParams {
|
|
historyId: string
|
|
tag: string
|
|
}
|
|
|
|
export interface RemoveTagParams {
|
|
historyId: string
|
|
tag: string
|
|
}
|
|
|
|
export interface GetTagsParams {
|
|
historyId: string
|
|
}
|
|
|
|
export interface SearchByTagParams {
|
|
tag: string
|
|
page: number
|
|
pageSize: number
|
|
}
|
|
|
|
export interface ExportMemoParams {
|
|
format: 'markdown'
|
|
tag?: string
|
|
from?: string
|
|
to?: string
|
|
}
|
|
|
|
export interface TagCount {
|
|
tag: string
|
|
count: number
|
|
}
|
|
|
|
// ============================================================
|
|
// Phase 10: Voice Commands (10.5)
|
|
// ============================================================
|
|
|
|
export type KeywordMatchMode = 'prefix' | 'suffix' | 'contains'
|
|
|
|
export interface VoiceCommandKeyword {
|
|
keyword: string
|
|
matchMode: KeywordMatchMode
|
|
}
|
|
|
|
export interface VoiceCommandRule {
|
|
id: string
|
|
instructionId: string
|
|
keywords: VoiceCommandKeyword[]
|
|
enabled: boolean
|
|
priority: number
|
|
}
|
|
|
|
export interface VoiceCommandMatch {
|
|
matched: boolean
|
|
ruleId: string | null
|
|
instructionId: string | null
|
|
/** 키워드 제거 후 남은 텍스트 */
|
|
cleanedText: string
|
|
/** 매칭된 키워드 */
|
|
matchedKeyword: string | null
|
|
}
|
|
|
|
export interface SetVoiceCommandKeywordsParams {
|
|
instructionId: string
|
|
keywords: VoiceCommandKeyword[]
|
|
}
|
|
|
|
export interface SetVoiceCommandEnabledParams {
|
|
enabled: boolean
|
|
}
|
|
|
|
// ============================================================
|
|
// Phase 10: Screen Context (10.2)
|
|
// ============================================================
|
|
|
|
export interface ScreenContext {
|
|
appName: string | null
|
|
windowTitle: string | null
|
|
selectedText: string | null
|
|
capturedAt: number
|
|
}
|
|
|
|
export interface CaptureContextResult {
|
|
context: ScreenContext
|
|
/** 선택 텍스트 캡처 시도 여부 */
|
|
selectedTextAttempted: boolean
|
|
}
|
|
|
|
// ============================================================
|
|
// Phase 10: LLM Chain (10.4)
|
|
// ============================================================
|
|
|
|
export interface ChainStep {
|
|
instructionId: string
|
|
/** 이전 단계 결과 사용 or 원본 텍스트 사용 */
|
|
inputSource: 'previous' | 'original'
|
|
}
|
|
|
|
export interface LLMChain {
|
|
id: string
|
|
name: string
|
|
steps: ChainStep[]
|
|
createdAt: number
|
|
updatedAt: number
|
|
}
|
|
|
|
export interface CreateChainParams {
|
|
name: string
|
|
steps: ChainStep[]
|
|
}
|
|
|
|
export interface UpdateChainParams {
|
|
id: string
|
|
name?: string
|
|
steps?: ChainStep[]
|
|
}
|
|
|
|
export interface DeleteChainParams {
|
|
id: string
|
|
}
|
|
|
|
export interface ExecuteChainParams {
|
|
chainId: string
|
|
text: string
|
|
}
|
|
|
|
export interface ChainProgress {
|
|
chainId: string
|
|
currentStep: number
|
|
totalSteps: number
|
|
stepName: string
|
|
intermediateText: string
|
|
}
|
|
|
|
export interface ChainExecutionResult {
|
|
chainId: string
|
|
finalText: string
|
|
steps: Array<{ instructionId: string; output: string; durationMs: number }>
|
|
totalDurationMs: number
|
|
}
|
|
|
|
// ============================================================
|
|
// Phase 10: Live Caption (10.1)
|
|
// ============================================================
|
|
|
|
export type CaptionState = 'inactive' | 'starting' | 'active' | 'stopping'
|
|
|
|
export interface CaptionSegment {
|
|
id: string
|
|
text: string
|
|
timestamp: number
|
|
isFinal: boolean
|
|
}
|
|
|
|
export type CaptionAudioSource = 'mic' | 'system' | 'both'
|
|
|
|
export interface CaptionConfig {
|
|
fontSize: number
|
|
opacity: number
|
|
maxLines: number
|
|
autoClearMs: number
|
|
/** 오디오 소스: 마이크 / 시스템 오디오 / 둘 다 */
|
|
audioSource: CaptionAudioSource
|
|
}
|
|
|
|
export interface CaptionSessionSummary {
|
|
sessionId: string
|
|
segments: CaptionSegment[]
|
|
startedAt: number
|
|
endedAt: number
|
|
totalDurationMs: number
|
|
}
|
|
|
|
// ============================================================
|
|
// Phase 11: License & Monetization
|
|
// ============================================================
|
|
|
|
/** 라이센스 티어 */
|
|
export type LicenseTier = 'free' | 'pro' | 'pro_plus'
|
|
|
|
/** 기능 게이팅 대상 */
|
|
export enum Feature {
|
|
// 쿼터 제한 기능 (Free에서 횟수 제한)
|
|
DICTATION = 'dictation',
|
|
LLM_PROCESS = 'llm_process',
|
|
|
|
// Pro 이상
|
|
HISTORY_UNLIMITED = 'history_unlimited',
|
|
HISTORY_EXPORT = 'history_export',
|
|
CUSTOM_INSTRUCTION_CREATE = 'custom_instruction_create',
|
|
LIVE_CAPTION = 'live_caption',
|
|
SCREEN_CONTEXT = 'screen_context',
|
|
VOICE_MEMO = 'voice_memo',
|
|
VOICE_COMMAND = 'voice_command',
|
|
LLM_CHAIN = 'llm_chain',
|
|
|
|
// Pro+ 이상
|
|
FILE_TRANSCRIPTION = 'file_transcription',
|
|
VOICE_CONVERSATION = 'voice_conversation',
|
|
DICTATION_TEMPLATE = 'dictation_template',
|
|
MEETING_SUMMARY = 'meeting_summary',
|
|
LOCAL_RAG = 'local_rag',
|
|
OS_AUTOMATION = 'os_automation',
|
|
}
|
|
|
|
/** 라이센스 정보 (electron-store에 저장) */
|
|
export interface LicenseInfo {
|
|
tier: LicenseTier
|
|
licenseKey: string | null
|
|
activatedAt: number | null
|
|
machineId: string
|
|
/** 마지막 온라인 검증 시각 */
|
|
lastVerifiedAt: number | null
|
|
/** 오프라인 유예 만료 (lastVerifiedAt + 30일) */
|
|
offlineGraceUntil: number | null
|
|
}
|
|
|
|
/** 일일 사용량 */
|
|
export interface DailyUsage {
|
|
date: string // 'YYYY-MM-DD'
|
|
feature: string
|
|
count: number
|
|
}
|
|
|
|
/** 쿼터 정보 */
|
|
export interface UsageQuota {
|
|
feature: Feature
|
|
used: number
|
|
limit: number // -1 = 무제한
|
|
remaining: number // -1 = 무제한
|
|
resetAt: string // 다음 리셋 시각 (내일 00:00) ISO 8601
|
|
}
|
|
|
|
/** 기능 접근 결과 */
|
|
export interface FeatureAccess {
|
|
allowed: boolean
|
|
reason: 'ok' | 'quota_exceeded' | 'tier_required' | 'license_expired'
|
|
requiredTier?: LicenseTier
|
|
quota?: UsageQuota
|
|
}
|
|
|
|
/** 업그레이드 유도 이벤트 */
|
|
export interface UpgradePromptEvent {
|
|
feature: Feature
|
|
reason: 'quota_exceeded' | 'tier_required'
|
|
currentTier: LicenseTier
|
|
requiredTier: LicenseTier
|
|
quota?: UsageQuota
|
|
}
|
|
|
|
/** 라이센스 활성화 파라미터 */
|
|
export interface ActivateLicenseParams {
|
|
licenseKey: string
|
|
}
|
|
|
|
/** 라이센스 활성화 결과 */
|
|
export interface ActivateLicenseResult {
|
|
success: boolean
|
|
tier: LicenseTier
|
|
message: string
|
|
}
|
|
|
|
/** 티어별 기능 비교 항목 */
|
|
export interface TierComparison {
|
|
feature: Feature
|
|
featureLabel: string
|
|
free: boolean | string
|
|
pro: boolean | string
|
|
proPlus: boolean | string
|
|
}
|
|
|
|
// ============================================================
|
|
// Phase 12: File Transcription (12.1)
|
|
// ============================================================
|
|
|
|
export type FileTranscriptionState = 'idle' | 'converting' | 'transcribing' | 'completed' | 'error'
|
|
|
|
export interface FileTranscriptionStartParams {
|
|
filePath: string
|
|
language?: string
|
|
}
|
|
|
|
export interface FileTranscriptionProgress {
|
|
jobId: string
|
|
currentChunk: number
|
|
totalChunks: number
|
|
percent: number
|
|
currentText: string
|
|
}
|
|
|
|
export interface FileTranscriptionSegment {
|
|
text: string
|
|
start: number
|
|
end: number
|
|
confidence: number
|
|
}
|
|
|
|
export interface FileTranscriptionResult {
|
|
jobId: string
|
|
filePath: string
|
|
fileName: string
|
|
fullText: string
|
|
segments: FileTranscriptionSegment[]
|
|
totalDurationSec: number
|
|
processingTimeMs: number
|
|
}
|
|
|
|
export interface FileTranscriptionStateInfo {
|
|
state: FileTranscriptionState
|
|
jobId: string | null
|
|
progress: FileTranscriptionProgress | null
|
|
}
|
|
|
|
// ============================================================
|
|
// Phase 12: Meeting Summary (12.2)
|
|
// ============================================================
|
|
|
|
export interface MeetingSummaryResult {
|
|
historyId: string
|
|
summary: string
|
|
decisions: string[]
|
|
actionItems: string[]
|
|
rawMarkdown: string
|
|
generatedAt: number
|
|
}
|
|
|
|
export interface MeetingSummarizeParams {
|
|
historyId: string
|
|
}
|
|
|
|
export interface MeetingSummaryGetParams {
|
|
historyId: string
|
|
}
|
|
|
|
export interface MeetingSummaryExportParams {
|
|
historyId: string
|
|
}
|
|
|
|
export interface MeetingSummaryProgress {
|
|
historyId: string
|
|
status: 'generating' | 'done' | 'error'
|
|
}
|
|
|
|
// ============================================================
|
|
// Phase 12: Dictation Templates (12.3)
|
|
// ============================================================
|
|
|
|
export interface TemplateField {
|
|
id: string
|
|
name: string
|
|
label: string
|
|
promptText: string
|
|
required: boolean
|
|
maxDurationSec: number
|
|
}
|
|
|
|
export interface DictationTemplate {
|
|
id: string
|
|
name: string
|
|
description: string
|
|
fields: TemplateField[]
|
|
outputFormat: string
|
|
isBuiltin: boolean
|
|
createdAt: number
|
|
updatedAt: number
|
|
}
|
|
|
|
export interface CreateTemplateParams {
|
|
name: string
|
|
description: string
|
|
fields: TemplateField[]
|
|
outputFormat: string
|
|
}
|
|
|
|
export interface UpdateTemplateParams {
|
|
id: string
|
|
name?: string
|
|
description?: string
|
|
fields?: TemplateField[]
|
|
outputFormat?: string
|
|
}
|
|
|
|
export interface DeleteTemplateParams {
|
|
id: string
|
|
}
|
|
|
|
export type TemplateSessionState =
|
|
| 'idle'
|
|
| 'field-prompting'
|
|
| 'field-recording'
|
|
| 'completing'
|
|
|
|
export interface TemplateSessionInfo {
|
|
templateId: string
|
|
templateName: string
|
|
state: TemplateSessionState
|
|
currentFieldIndex: number
|
|
totalFields: number
|
|
currentField: TemplateField | null
|
|
fieldValues: Record<string, string>
|
|
}
|
|
|
|
export interface StartTemplateSessionParams {
|
|
templateId: string
|
|
}
|
|
|
|
export interface SetFieldValueParams {
|
|
fieldId: string
|
|
value: string
|
|
}
|
|
|
|
export interface TemplateFieldCompletedEvent {
|
|
fieldId: string
|
|
fieldName: string
|
|
value: string
|
|
nextField: TemplateField | null
|
|
}
|
|
|
|
export interface TemplateSessionCompletedEvent {
|
|
templateId: string
|
|
outputText: string
|
|
fieldValues: Record<string, string>
|
|
}
|
|
|
|
// ============================================================
|
|
// Phase 13: Voice Conversation (13.1)
|
|
// ============================================================
|
|
|
|
export type ConversationState =
|
|
| 'idle'
|
|
| 'listening'
|
|
| 'thinking'
|
|
| 'speaking'
|
|
|
|
export type ConversationRole = 'user' | 'assistant' | 'system'
|
|
|
|
export interface ConversationMessage {
|
|
id: string
|
|
role: ConversationRole
|
|
content: string
|
|
timestamp: number
|
|
}
|
|
|
|
export interface ConversationSessionInfo {
|
|
state: ConversationState
|
|
messages: ConversationMessage[]
|
|
isActive: boolean
|
|
}
|
|
|
|
export interface ConversationSendParams {
|
|
text: string
|
|
}
|
|
|
|
export interface ConversationAssistantDelta {
|
|
messageId: string
|
|
delta: string
|
|
accumulated: string
|
|
}
|
|
|
|
export interface ConversationAssistantMessage {
|
|
messageId: string
|
|
content: string
|
|
}
|
|
|
|
export interface ConversationError {
|
|
message: string
|
|
phase: 'stt' | 'llm' | 'tts'
|
|
}
|
|
|
|
// ============================================================
|
|
// Phase 13: Local RAG (13.2)
|
|
// ============================================================
|
|
|
|
export interface RAGDocument {
|
|
id: string
|
|
fileName: string
|
|
filePath: string
|
|
fileType: 'txt' | 'md' | 'pdf' | 'docx'
|
|
chunkCount: number
|
|
indexed: boolean
|
|
indexedAt: number | null
|
|
addedAt: number
|
|
}
|
|
|
|
export interface RAGChunk {
|
|
id: string
|
|
documentId: string
|
|
content: string
|
|
embedding: number[]
|
|
chunkIndex: number
|
|
}
|
|
|
|
export interface RAGQueryParams {
|
|
query: string
|
|
topK?: number
|
|
}
|
|
|
|
export interface RAGQueryResult {
|
|
query: string
|
|
results: Array<{
|
|
documentId: string
|
|
fileName: string
|
|
content: string
|
|
similarity: number
|
|
}>
|
|
/** LLM 답변 (컨텍스트 주입 후) */
|
|
answer: string
|
|
}
|
|
|
|
export interface RAGAddDocumentParams {
|
|
filePath: string
|
|
}
|
|
|
|
export interface RAGRemoveDocumentParams {
|
|
documentId: string
|
|
}
|
|
|
|
export interface RAGIndexProgress {
|
|
documentId: string
|
|
fileName: string
|
|
currentChunk: number
|
|
totalChunks: number
|
|
percent: number
|
|
}
|
|
|
|
export type RAGState = 'idle' | 'indexing' | 'querying'
|
|
|
|
export interface RAGStateInfo {
|
|
state: RAGState
|
|
documentCount: number
|
|
totalChunks: number
|
|
}
|
|
|
|
// ============================================================
|
|
// Phase 13: Voice Action / OS Automation (13.3)
|
|
// ============================================================
|
|
|
|
export type VoiceActionType =
|
|
| 'open_app'
|
|
| 'open_url'
|
|
| 'open_file'
|
|
| 'keyboard_shortcut'
|
|
| 'type_text'
|
|
| 'system_command'
|
|
|
|
export interface VoiceActionPlan {
|
|
action: VoiceActionType
|
|
target: string
|
|
description: string
|
|
safe: boolean
|
|
}
|
|
|
|
export interface VoiceActionExecuteParams {
|
|
text: string
|
|
}
|
|
|
|
export interface VoiceActionPreset {
|
|
keywords: string[]
|
|
action: VoiceActionPlan
|
|
}
|
|
|
|
export interface VoiceActionHistoryEntry {
|
|
id: string
|
|
userText: string
|
|
plan: VoiceActionPlan
|
|
executed: boolean
|
|
timestamp: number
|
|
}
|
|
|
|
export interface VoiceActionPlannedEvent {
|
|
plan: VoiceActionPlan
|
|
userText: string
|
|
}
|
|
|
|
export interface VoiceActionExecutedEvent {
|
|
plan: VoiceActionPlan
|
|
success: boolean
|
|
}
|
|
|
|
export interface VoiceActionErrorEvent {
|
|
message: string
|
|
userText: string
|
|
}
|
|
|
|
// ============================================================
|
|
// Phase 14: Meeting Mode
|
|
// ============================================================
|
|
|
|
export type MeetingModeState = 'idle' | 'recording' | 'processing' | 'completed' | 'error'
|
|
|
|
export interface MeetingMemo {
|
|
id: string
|
|
sessionId: string
|
|
content: string
|
|
/** 녹음 시작 기준 상대 타임스탬프 (ms) */
|
|
timestampMs: number
|
|
createdAt: number
|
|
}
|
|
|
|
export interface MeetingSessionSummary {
|
|
id: string
|
|
title: string | null
|
|
status: 'recording' | 'processing' | 'completed' | 'error'
|
|
startedAt: number
|
|
endedAt: number | null
|
|
durationMs: number | null
|
|
memoCount: number
|
|
}
|
|
|
|
export interface MeetingSessionDetail extends MeetingSessionSummary {
|
|
rawTranscript: string | null
|
|
minutesMarkdown: string | null
|
|
minutes: MeetingMinutes | null
|
|
memos: MeetingMemo[]
|
|
sttModel: string | null
|
|
llmModel: string | null
|
|
errorMessage: string | null
|
|
}
|
|
|
|
export interface MeetingMinutes {
|
|
summary: string
|
|
decisions: string[]
|
|
actionItems: Array<{ task: string; assignee?: string; deadline?: string }>
|
|
timeline: Array<{ time: string; content: string; type: 'transcript' | 'memo' }>
|
|
}
|
|
|
|
export interface MeetingSessionPage {
|
|
sessions: MeetingSessionSummary[]
|
|
total: number
|
|
page: number
|
|
pageSize: number
|
|
totalPages: number
|
|
}
|
|
|
|
export interface MeetingStartResult {
|
|
sessionId: string
|
|
}
|
|
|
|
export interface MeetingAddMemoParams {
|
|
content: string
|
|
}
|
|
|
|
export interface MeetingGetSessionsParams {
|
|
page: number
|
|
pageSize: number
|
|
}
|
|
|
|
export interface MeetingGetSessionParams {
|
|
sessionId: string
|
|
}
|
|
|
|
export interface MeetingDeleteSessionParams {
|
|
sessionId: string
|
|
}
|
|
|
|
export interface MeetingExportParams {
|
|
sessionId: string
|
|
}
|
|
|
|
export interface MeetingModeStateInfo {
|
|
state: MeetingModeState
|
|
sessionId: string | null
|
|
elapsedMs: number
|
|
memoCount: number
|
|
segmentCount: number
|
|
}
|
|
|
|
export type MeetingProcessingStep =
|
|
| 'merging'
|
|
| 'generating'
|
|
| 'parsing'
|
|
| 'saving'
|
|
| 'notifying'
|
|
|
|
export interface MeetingProcessingProgress {
|
|
sessionId: string
|
|
step: MeetingProcessingStep
|
|
percent: number
|
|
}
|