// src/shared/constants.ts import type { LicenseTier } from './types' /** 타이밍 상수 (Speakly 리버스엔지니어링 기반) */ export const TIMING = { /** 더블프레스 감지 간격 (ms) */ DOUBLE_PRESS_DURATION: 300, /** 최소 녹음 시간 (ms) — 이하 자동 취소 */ MIN_AUDIO_DURATION: 700, /** 녹음 후 STT 대기 시간 (ms) */ POST_RECORDING_WAIT: 4000, /** 녹음 후 STT 대기 (버퍼 있을 때) (ms) */ POST_RECORDING_WAIT_BUFFERED: 6000, /** STT 아이들 타임아웃 (ms) */ STT_IDLE_TIMEOUT: 30000, /** 절대 최대 대기 시간 (ms) */ ABSOLUTE_MAX_WAIT: 120000, /** 오디오 레벨 전송 간격 (ms) */ AUDIO_LEVEL_INTERVAL: 100, /** 서비스 종료 타임아웃 (ms) */ SERVICE_DESTROY_TIMEOUT: 3000, /** 사이드카 헬스체크 지연 (ms) */ SIDECAR_HEALTH_DELAY: 3000, /** LLM 요청 타임아웃 (ms) */ LLM_REQUEST_TIMEOUT: 30000 } as const /** 웨이브 바 상수 (RecordingTip) */ export const WAVE_BAR = { COUNT: 9, ANIMATION_INTERVAL: 100, /** 코사인 분포 가중치 (Speakly 패턴) */ COS_WEIGHTS: Array.from({ length: 9 }, (_, i) => Math.cos((i - 4) * (Math.PI / 9))) } as const /** 오디오 포맷 */ export const AUDIO_FORMAT = { SAMPLE_RATE: 16000, CHANNELS: 1, BIT_DEPTH: 16, BYTES_PER_SAMPLE: 2 } as const /** Premium 모델별 쿼터 한도 (LicenseService QUOTA_LIMITS, 서버 quota.ts와 동기) */ export interface PremiumModelQuota { readonly model: string readonly i18nKey: string readonly limit: number // -1 = 무제한 readonly period: 'daily' | 'weekly' } export const PREMIUM_MODEL_LIMITS: Record = { free: [ { model: 'llm_haiku', i18nKey: 'license.modelHaiku', limit: 250, period: 'weekly' }, ], pro: [ { model: 'llm_haiku', i18nKey: 'license.modelHaiku', limit: 1500, period: 'daily' }, { model: 'llm_sonnet', i18nKey: 'license.modelSonnet', limit: 300, period: 'daily' }, { model: 'llm_opus', i18nKey: 'license.modelOpus', limit: 50, period: 'daily' }, ], pro_plus: [ { model: 'llm_haiku', i18nKey: 'license.modelHaiku', limit: -1, period: 'daily' }, { model: 'llm_sonnet', i18nKey: 'license.modelSonnet', limit: 1500, period: 'daily' }, { model: 'llm_opus', i18nKey: 'license.modelOpus', limit: 300, period: 'daily' }, ], team: [ { model: 'llm_haiku', i18nKey: 'license.modelHaiku', limit: -1, period: 'daily' }, { model: 'llm_sonnet', i18nKey: 'license.modelSonnet', limit: 3000, period: 'daily' }, { model: 'llm_opus', i18nKey: 'license.modelOpus', limit: 600, period: 'daily' }, ], enterprise: [ { model: 'llm_haiku', i18nKey: 'license.modelHaiku', limit: -1, period: 'daily' }, { model: 'llm_sonnet', i18nKey: 'license.modelSonnet', limit: -1, period: 'daily' }, { model: 'llm_opus', i18nKey: 'license.modelOpus', limit: -1, period: 'daily' }, ], } as const /** 윈도우 크기 */ export const WINDOW_SIZE = { MAIN: { width: 1104, height: 816 }, RECORDING_TIP: { width: 280, height: 80 }, RESULT_POPUP: { width: 400, height: 200 } } as const