feat(desktop+server): Phase 3.2 Premium LLM — Anthropic Claude 프리미엄 파이프라인 + 모델별 쿼터 + SaaS UI
빅뱅 8/8 마지막 성공 기준 달성. Supabase Edge Function(llm-proxy)을 통해 Anthropic Claude를 호출하는 PremiumLLMService 신규 구현. 사용자가 Settings에서 Local/Premium 백엔드를 선택하면 VoiceModeService가 자동 분기하고, Premium 실패 시 Local로 silent fallback + 상단 중앙 배너 알림. 실측: Claude Haiku refine 1.6~3.2초 (이전 qwen3 42.9초 → 13~27배 빠름). 주요 변경: - PremiumLLMService 신규 (싱글톤+EventEmitter, processText/chatStream, Supabase functions.invoke 기반, _ensureAuth 가드) - llm-prompts.ts: SYSTEM_PROMPTS를 Local/Premium 공유 모듈로 추출 (resolveSystemPrompt 헬퍼) - VoiceModeService: _getLLMProcessor → _runProcessorWithFallback 라우터 + premium-llm-fallback 이벤트 - CloudSyncService: getAccessToken(async), getAnonKey, invokeFunction(auth 헤더 자동 처리, 에러 body 파싱) - IPC: LLM.PREMIUM_* 채널 6개 + preload API + llm-handlers 이벤트 전달 (safeSendToRenderer 헬퍼) - AppConfig.llmBackend: 'local' | 'premium' (기본 'local') - Settings UI: Backend 드롭다운 + Premium 선택 시 Ollama UI 숨김 + 라이선스 모달 자동 오픈 - AppLayout: 상단 중앙 Snackbar fallback 배너 (8초, warning filled) - LicenseModal: 라이선스 키 입력 제거 → SaaS 구독 관리 UI 전환 (Free/Pro/Pro+ 업그레이드 버튼, Payple 준비 중 스텁) - 등급 비교 표: featureLabel i18n 번역 수정 서버 (Supabase Edge Functions): - quota.ts: 모델별 쿼터 구조 (llm_haiku/sonnet/opus × free/pro/pro_plus), 주간/일간 기간 분리, modelToQuotaKey 매핑, consumeQuota baseLimit 파라미터화 - llm-proxy: 모델별 쿼터 체크 + 소비 (checkQuota → consumeQuota 원자적), verify_jwt=false (2026 sb_publishable_ 키 호환) - config.toml: llm-proxy verify_jwt = false - migration 20260412000001: tier team→pro_plus 통일, subscriptions.overage_credits 컬럼, consume_quota RPC (원자적 base→overage fallback) Tier/쿼터: - free: Haiku 250/주간, Sonnet/Opus 불가 - pro ₩9,900: Haiku 1500/일, Sonnet 300/일, Opus 50/일 - pro_plus ₩29,900: Haiku 무제한, Sonnet 1500/일, Opus 300/일 - api-client SubscriptionTier: team→pro_plus, overage_credits 필드 추가
This commit is contained in:
parent
d397bcbf57
commit
6e52c18e5b
23 changed files with 1111 additions and 311 deletions
|
|
@ -24,7 +24,7 @@ import type {
|
|||
|
||||
describe('api-client types', () => {
|
||||
it('SubscriptionTier 리터럴 union', () => {
|
||||
const tiers: SubscriptionTier[] = ['free', 'pro', 'team']
|
||||
const tiers: SubscriptionTier[] = ['free', 'pro', 'pro_plus']
|
||||
expect(tiers).toHaveLength(3)
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// packages/api-client/src/types.ts
|
||||
// Supabase DB row 타입 — V2-2 스키마와 동기화된 수동 정의.
|
||||
|
||||
export type SubscriptionTier = 'free' | 'pro' | 'team'
|
||||
export type SubscriptionTier = 'free' | 'pro' | 'pro_plus'
|
||||
|
||||
export type Profile = {
|
||||
id: string
|
||||
|
|
@ -148,7 +148,11 @@ export type Subscription = {
|
|||
id: string
|
||||
user_id: string
|
||||
tier: SubscriptionTier
|
||||
/** Phase 3.2: 베이스 쿼터 소진 시 차감되는 추가 크레딧 */
|
||||
overage_credits: number
|
||||
/** @deprecated Phase 3.2-B (Payple 이관 예정) */
|
||||
stripe_customer_id: string | null
|
||||
/** @deprecated Phase 3.2-B (Payple 이관 예정) */
|
||||
stripe_subscription_id: string | null
|
||||
status: string | null
|
||||
current_period_start: string | null
|
||||
|
|
|
|||
|
|
@ -63,10 +63,19 @@ export const IPC_CHANNELS = {
|
|||
GET_SERVER_URL: 'llm:getServerUrl',
|
||||
SET_SERVER_URL: 'llm:setServerUrl',
|
||||
PULL_MODEL: 'llm:pullModel',
|
||||
// Phase 3.2: Premium LLM (Supabase llm-proxy → Claude)
|
||||
PREMIUM_GET_STATUS: 'llm:premium:getStatus',
|
||||
PREMIUM_GET_QUOTA: 'llm:premium:getQuota',
|
||||
// Main → Renderer events
|
||||
STATUS_CHANGED: 'llm:statusChanged',
|
||||
PROCESS_PROGRESS: 'llm:processProgress',
|
||||
PULL_PROGRESS: 'llm:pullProgress'
|
||||
PULL_PROGRESS: 'llm:pullProgress',
|
||||
/** Phase 3.2: Premium LLM 호출 실패 → Local 자동 fallback 알림 */
|
||||
PREMIUM_FALLBACK: 'llm:premiumFallback',
|
||||
/** Phase 3.2: 쿼터 경고 (80%+ 또는 초과) */
|
||||
PREMIUM_QUOTA_WARNING: 'llm:premiumQuotaWarning',
|
||||
/** Phase 3.2: 업그레이드 요구 (쿼터 초과 / 모델 권한 / 인증) */
|
||||
PREMIUM_UPGRADE_REQUIRED: 'llm:premiumUpgradeRequired'
|
||||
},
|
||||
|
||||
HOTKEY: {
|
||||
|
|
|
|||
|
|
@ -366,6 +366,12 @@ export interface AppConfig {
|
|||
ttsSpeed: number
|
||||
ollamaServerUrl: string
|
||||
llmModelId: string | null
|
||||
/**
|
||||
* Phase 3.2: LLM 백엔드 선택.
|
||||
* 'local' — LocalLLMService (Ollama, 기본값, 무료)
|
||||
* 'premium' — PremiumLLMService (Supabase llm-proxy → Claude, 로그인+구독 필요)
|
||||
*/
|
||||
llmBackend: 'local' | 'premium'
|
||||
defaultLLMAction: LLMAction
|
||||
dictationShortcut: HotkeyBinding
|
||||
handsFreeShortcut: HotkeyBinding
|
||||
|
|
|
|||
|
|
@ -123,6 +123,11 @@
|
|||
"settings.ollamaServer": "Ollama Server",
|
||||
"settings.ollamaUrl": "Ollama Server URL",
|
||||
"settings.ollamaHint": "Connects automatically when Ollama is running. Pull models directly in Ollama (e.g. ollama pull gemma4:e4b).",
|
||||
"settings.llmBackend": "LLM Engine",
|
||||
"settings.backend.local": "Local (Ollama, Free)",
|
||||
"settings.backend.premium": "Premium (Claude AI, Subscription)",
|
||||
"settings.backend.localHint": "Polish text with local Ollama server. Fully free, no internet needed.",
|
||||
"settings.backend.premiumHint": "High-quality polishing with Anthropic Claude AI. Login + subscription required. Auto-fallback to Local on network failure.",
|
||||
"settings.llmModel": "LLM Model",
|
||||
"settings.postProcess": "Voice Post-Processing",
|
||||
"settings.defaultAction": "Default Post-Processing Command",
|
||||
|
|
@ -276,7 +281,12 @@
|
|||
"license.machineId": "Machine ID",
|
||||
"license.activatedAt": "Activated At",
|
||||
"license.manageLicense": "Manage License",
|
||||
"license.subscribe": "Subscribe",
|
||||
"license.upgrade": "Upgrade",
|
||||
"license.currentPlan": "Current Plan",
|
||||
"license.proPlan": "Pro — ₩9,900/mo",
|
||||
"license.proPlusPlan": "Pro+ — ₩29,900/mo",
|
||||
"license.paymentPending": "Payment integration coming soon (Payple)",
|
||||
"license.upgradeTitle": "Upgrade to Pro",
|
||||
"license.upgradeDesc": "Unlock all features",
|
||||
"license.quotaUsed": "{{used}}/{{limit}} used",
|
||||
|
|
|
|||
|
|
@ -124,6 +124,11 @@
|
|||
"settings.ollamaServer": "Ollama 서버",
|
||||
"settings.ollamaUrl": "Ollama 서버 URL",
|
||||
"settings.ollamaHint": "Ollama가 실행 중이면 자동으로 연결됩니다. 모델은 Ollama에서 직접 pull하세요 (예: ollama pull gemma4:e4b).",
|
||||
"settings.llmBackend": "LLM 엔진",
|
||||
"settings.backend.local": "Local (Ollama, 무료)",
|
||||
"settings.backend.premium": "Premium (Claude AI, 구독)",
|
||||
"settings.backend.localHint": "로컬 Ollama 서버로 텍스트를 다듬습니다. 완전 무료, 인터넷 불필요.",
|
||||
"settings.backend.premiumHint": "Anthropic Claude AI로 고품질 다듬기. 로그인 + 구독 필요. 네트워크 실패 시 Local로 자동 전환.",
|
||||
"settings.llmModel": "LLM 모델",
|
||||
"settings.postProcess": "음성 후처리",
|
||||
"settings.defaultAction": "기본 후처리 명령어",
|
||||
|
|
@ -277,7 +282,12 @@
|
|||
"license.machineId": "기기 ID",
|
||||
"license.activatedAt": "활성화 일시",
|
||||
"license.manageLicense": "라이선스 관리",
|
||||
"license.subscribe": "구독하기",
|
||||
"license.upgrade": "업그레이드",
|
||||
"license.currentPlan": "현재 구독 중",
|
||||
"license.proPlan": "Pro — ₩9,900/월",
|
||||
"license.proPlusPlan": "Pro+ — ₩29,900/월",
|
||||
"license.paymentPending": "결제 연동 준비 중 (Payple)",
|
||||
"license.upgradeTitle": "Pro로 업그레이드",
|
||||
"license.upgradeDesc": "모든 기능을 잠금 해제하세요",
|
||||
"license.quotaUsed": "{{used}}/{{limit}} 사용",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue