Files
meeting-minutes/src/lib/providers/presets.ts
T
352ac2ffd1 feat: OpenAI 호환 프로바이더 지원 (OrcaRouter · OpenAI · 로컬 모델) (#12)
* feat: OpenAI 호환 프로바이더 지원 (OrcaRouter · OpenAI · 로컬 모델)

Gemini 직접 호출만 가능하던 구조를 프로바이더 레이어로 분리.
base URL과 모델 ID만 지정하면 OpenAI Chat Completions 형식을 따르는
엔드포인트는 모두 연결된다 (OrcaRouter, OpenAI, Ollama, LM Studio, vLLM).

- src/lib/providers/ 신설 (gemini / openai-compatible 어댑터 + 프리셋)
- /settings에 프로바이더 선택 UI 추가, 기존 Gemini 키는 자동 승계
- LLM_PROVIDER / LLM_BASE_URL / LLM_MODEL / LLM_API_KEY 환경변수 지원
- base URL은 http/https만 허용 (서버가 대신 fetch하므로 SSRF 방어)
- SECURITY.md에 프로바이더별 전송 경로와 SSRF 주의사항 문서화
- 테스트 102 → 141

DB에 저장되는 summaryMode 값('gemini')은 기존 레코드 호환을 위해 유지하고
UI 라벨만 "AI 요약"으로 변경했다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* chore: 기본 Gemini 모델을 3.5 Flash Lite로 갱신

gemini-2.5-flash-lite → gemini-3.5-flash-lite. 같은 저비용·고속 티어의
최신 세대이며, 무료 등급 중심의 사용 프로필을 그대로 유지한다.

- providers/gemini.ts: DEFAULT_GEMINI_MODEL
- presets.ts: OrcaRouter 기본 모델과 모델 힌트 문구
- .env.example, README 참조 갱신

참고: 화자 분리를 지원하는 gemini-3.5-transcribe는 오디오 입력 전용
음성인식 모델이라 이 자리(텍스트 → 회의록 요약)에 넣을 수 없다.
오디오 캡처가 들어오는 시점에 STT 경로로 별도 추가해야 한다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: csbae <csbae@RP-002.local>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 18:14:30 +09:00

99 lines
3.2 KiB
TypeScript

import { DEFAULT_GEMINI_MODEL } from './gemini'
import type { ProviderId } from './types'
export interface ProviderPreset {
id: string
label: string
provider: ProviderId
/** openai-compatible 프리셋의 기본 base URL. 사용자가 수정할 수 있다. */
baseUrl: string
defaultModel: string
description: string
apiKeyLabel: string
apiKeyPlaceholder: string
/** 키 없이도 동작하는 엔드포인트(로컬 모델 서버)인지 여부 */
apiKeyOptional?: boolean
docsUrl?: string
docsLabel?: string
modelHint?: string
}
export const PROVIDER_PRESETS: ProviderPreset[] = [
{
id: 'gemini',
label: 'Google Gemini',
provider: 'gemini',
baseUrl: '',
defaultModel: DEFAULT_GEMINI_MODEL,
description: 'Google에 직접 호출합니다. 무료 티어가 있어 가장 간단합니다.',
apiKeyLabel: 'Gemini API 키',
apiKeyPlaceholder: 'AIzaSy...',
docsUrl: 'https://aistudio.google.com/apikey',
docsLabel: 'Google AI Studio',
modelHint:
'예: gemini-3.5-flash-lite(저렴·빠름), gemini-3.6-flash, gemini-2.5-pro',
},
{
id: 'openai',
label: 'OpenAI',
provider: 'openai-compatible',
baseUrl: 'https://api.openai.com/v1',
defaultModel: 'gpt-4o-mini',
description: 'OpenAI Chat Completions API를 사용합니다.',
apiKeyLabel: 'OpenAI API 키',
apiKeyPlaceholder: 'sk-...',
docsUrl: 'https://platform.openai.com/api-keys',
docsLabel: 'OpenAI 대시보드',
modelHint: '예: gpt-4o-mini, gpt-4o',
},
{
id: 'orcarouter',
label: 'OrcaRouter',
provider: 'openai-compatible',
baseUrl: 'https://api.orcarouter.ai/v1',
defaultModel: 'google/gemini-3.5-flash-lite',
description:
'하나의 키로 여러 제공사 모델을 사용합니다. 별도 가입과 크레딧 충전(또는 BYOK 등록)이 필요합니다.',
apiKeyLabel: 'OrcaRouter API 키',
apiKeyPlaceholder: 'sk-...',
docsUrl: 'https://www.orcarouter.ai/',
docsLabel: 'OrcaRouter',
modelHint:
'예: google/gemini-3.5-flash-lite, openai/gpt-4o-mini, orcarouter/auto',
},
{
id: 'local',
label: '로컬 모델',
provider: 'openai-compatible',
baseUrl: 'http://localhost:11434/v1',
defaultModel: 'llama3.1',
description:
'Ollama · LM Studio · vLLM 등 내 PC에서 도는 모델. 회의 내용이 외부로 나가지 않습니다.',
apiKeyLabel: 'API 키 (보통 불필요)',
apiKeyPlaceholder: '비워두세요',
apiKeyOptional: true,
modelHint: 'Ollama 기본 포트는 11434, LM Studio는 1234입니다.',
},
{
id: 'custom',
label: '직접 입력',
provider: 'openai-compatible',
baseUrl: '',
defaultModel: '',
description: 'OpenAI 호환 엔드포인트라면 무엇이든 연결할 수 있습니다.',
apiKeyLabel: 'API 키',
apiKeyPlaceholder: 'sk-...',
apiKeyOptional: true,
modelHint: '엔드포인트가 제공하는 모델 ID를 그대로 입력하세요.',
},
]
export const DEFAULT_PRESET_ID = 'gemini'
export function findPreset(presetId: string | null | undefined): ProviderPreset {
return (
PROVIDER_PRESETS.find((preset) => preset.id === presetId) ??
PROVIDER_PRESETS[0]
)
}