/** * GUARDiA Messenger — Ollama 온프레미스 AI 클라이언트 * * 보안 원칙 (불변): * - 외부 AI API 절대 사용 금지. localhost:11434 (온프레미스 Ollama)만 사용. * - 서버 자격증명(IP/SSH 계정/비밀번호)을 프롬프트에 포함 금지. * - Ollama 미가동/오프라인 시 안전하게 빈 값/폴백 반환 (앱 크래시 방지). */ // 외부 AI API 절대 사용 금지 — localhost:11434만 사용 const OLLAMA_BASE = 'http://localhost:11434' // 기본 모델 (온프레미스 sLLM) export const DEFAULT_TEXT_MODEL = 'llama3' export const DEFAULT_VISION_MODEL = 'llava' interface OllamaResponse { response?: string done?: boolean } /** 단순 텍스트 생성. 실패 시 빈 문자열 반환. */ export async function generate(model: string, prompt: string): Promise { try { const res = await fetch(`${OLLAMA_BASE}/api/generate`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ model, prompt, stream: false }), }) const data: OllamaResponse = await res.json() return data.response ?? '' } catch { return '' // 오프라인/Ollama 미가동 시 빈 문자열 반환 } } /** * JSON 응답 생성. sLLM 응답에서 JSON 블록을 추출/파싱. * 파싱 실패 시 fallback 반환. */ export async function generateJSON(model: string, prompt: string, fallback: T): Promise { const raw = await generate(model, prompt) if (!raw) return fallback try { return JSON.parse(raw) as T } catch { // 모델이 부연 설명과 함께 JSON을 출력한 경우 JSON 블록만 추출 시도 const match = raw.match(/[\[{][\s\S]*[\]}]/) if (match) { try { return JSON.parse(match[0]) as T } catch { return fallback } } return fallback } } /** 이미지 + 텍스트 멀티모달 생성 (llava). imageBase64는 data URI 접두어 없는 순수 base64. */ export async function generateWithImage( model: string, prompt: string, imageBase64: string, ): Promise { try { const clean = imageBase64.replace(/^data:image\/\w+;base64,/, '') const res = await fetch(`${OLLAMA_BASE}/api/generate`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ model, prompt, images: [clean], stream: false }), }) const data: OllamaResponse = await res.json() return data.response ?? '' } catch { return '' } } /** Ollama 서버 가동 여부 확인. */ export async function isOllamaAvailable(): Promise { try { const res = await fetch(`${OLLAMA_BASE}/api/tags`, { method: 'GET' }) return res.ok } catch { return false } }