const API_BASE = process.env.NEXT_PUBLIC_API_URL || 'https://api.aaronnelson.studio'; async function request(path: string, options?: RequestInit): Promise { const res = await fetch(`${API_BASE}${path}`, { credentials: 'include', headers: { 'Content-Type': 'application/json' }, ...options, }); if (!res.ok) throw new Error(`API error: ${res.status}`); return res.json(); } export const api = { // Settings getSettings: () => request('/api/settings'), updateSettings: (s: Partial) => request('/api/settings', { method: 'POST', body: JSON.stringify(s) }), // Conversations getConversations: () => request('/api/conversations'), newConversation: (title = 'New conversation') => request('/api/conversations', { method: 'POST', body: JSON.stringify({ title }) }), getMessages: (id: string) => request(`/api/conversations/${id}/messages`), renameConversation: (id: string, title: string) => request(`/api/conversations/${id}`, { method: 'PATCH', body: JSON.stringify({ title }) }), deleteConversation: (id: string) => request<{ deleted: string }>(`/api/conversations/${id}`, { method: 'DELETE' }), clearAllConversations: () => request<{ cleared: boolean }>('/api/conversations', { method: 'DELETE' }), // Chat sendMessage: (message: string, conversation_id: string) => request('/api/chat', { method: 'POST', body: JSON.stringify({ message, conversation_id }) }), // Memory getMemory: () => request<{ content: string }>('/api/memory'), updateMemory: (content: string) => request<{ saved: boolean }>('/api/memory', { method: 'POST', body: JSON.stringify({ content }) }), // Status getStatus: () => request('/api/status'), // Reindex reindex: () => request<{ started: boolean }>('/api/reindex', { method: 'POST' }), // Transcribe transcribe: async (audio: Blob): Promise<{ text: string }> => { const form = new FormData(); form.append('audio', audio, 'recording.webm'); const res = await fetch(`${API_BASE}/api/transcribe`, { method: 'POST', credentials: 'include', body: form, }); if (!res.ok) throw new Error(`Transcribe error: ${res.status}`); return res.json(); }, // Capture capture: async (data: CapturePayload): Promise<{ saved: boolean }> => { const form = new FormData(); if (data.audio) form.append('audio', data.audio, 'capture.webm'); if (data.image) form.append('image', data.image); if (data.text) form.append('text', data.text); if (data.project) form.append('project', data.project); const res = await fetch(`${API_BASE}/api/capture`, { method: 'POST', credentials: 'include', body: form, }); if (!res.ok) throw new Error(`Capture error: ${res.status}`); return res.json(); }, }; // Types export interface Settings { theme: 'light' | 'dark'; font_size: 'small' | 'medium' | 'large'; web_search: boolean; show_sources: boolean; } export interface Conversation { id: string; title: string; created_at: string; updated_at: string; message_count: number; } export interface Message { role: 'user' | 'assistant'; content: string; sources: string[]; timestamp: string; } export interface ChatResponse { response: string; sources: string[]; conversation_id: string; } export interface Status { aaron_ai: string; watcher: string; chunk_count: number; file_count: number; last_indexed: string; conversation_count: number; model: string; nextcloud_path: string; } export interface CapturePayload { audio?: Blob; image?: File; text?: string; project?: string; }