- LicenseTab/LicenseModal: LemonSqueezy 키 입력 삭제, Payple 구독 UI로 전환 - useLicenseState 훅: 라이선스+클라우드 인증 공용 상태 관리 추출 - PREMIUM_MODEL_LIMITS: 3곳 중복 → @d3ro/core/constants 단일 소스 - i18n: LemonSqueezy 전용 키 18개 삭제, 구독 관련 키 13개 추가 (12 locale) - DashboardPage: dashboard.model* → license.model* 키 통일
82 lines
2.5 KiB
TypeScript
82 lines
2.5 KiB
TypeScript
// src/shared/constants.ts
|
|
|
|
/** 타이밍 상수 (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' | 'pro' | 'pro_plus', readonly PremiumModelQuota[]> = {
|
|
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' },
|
|
],
|
|
} 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
|