| import { useState, useCallback, useEffect, useRef } from 'react' |
| import type { |
| ChatResponse, Metrics, TeachResponse, MemorySamples, Stats |
| } from '../types' |
|
|
| const API_BASE = import.meta.env.DEV ? '' : '' |
|
|
| async function fetchJson<T>(url: string, options?: RequestInit): Promise<T> { |
| const res = await fetch(`${API_BASE}${url}`, { |
| headers: { 'Content-Type': 'application/json' }, |
| ...options, |
| }) |
| if (!res.ok) throw new Error(`API ${url}: ${res.status}`) |
| return res.json() |
| } |
|
|
| export function useApi() { |
| const [connected, setConnected] = useState(false) |
| const [metrics, setMetrics] = useState<Metrics | null>(null) |
| const [stats, setStats] = useState<Stats | null>(null) |
| const [memorySamples, setMemorySamples] = useState<MemorySamples | null>(null) |
| const [loading, setLoading] = useState(false) |
| const pollRef = useRef<number | null>(null) |
|
|
| const checkHealth = useCallback(async () => { |
| try { |
| await fetchJson('/health') |
| setConnected(true) |
| } catch { |
| setConnected(false) |
| } |
| }, []) |
|
|
| const refreshMetrics = useCallback(async () => { |
| try { |
| const m = await fetchJson<Metrics>('/metrics') |
| setMetrics(m) |
| const s = await fetchJson<Stats>('/stats') |
| setStats(s) |
| const ms = await fetchJson<MemorySamples>('/memory/samples?limit=100') |
| setMemorySamples(ms) |
| setConnected(true) |
| } catch { |
| setConnected(false) |
| } |
| }, []) |
|
|
| const sendMessage = useCallback(async ( |
| message: string, temperature?: number, maxTokens?: number |
| ): Promise<ChatResponse> => { |
| setLoading(true) |
| try { |
| const resp = await fetchJson<ChatResponse>('/chat', { |
| method: 'POST', |
| body: JSON.stringify({ |
| message, |
| temperature: temperature ?? 0.3, |
| max_tokens: maxTokens ?? 200, |
| }), |
| }) |
| |
| refreshMetrics() |
| return resp |
| } finally { |
| setLoading(false) |
| } |
| }, [refreshMetrics]) |
|
|
| const teachModel = useCallback(async ( |
| question: string, answer: string |
| ): Promise<TeachResponse> => { |
| setLoading(true) |
| try { |
| const resp = await fetchJson<TeachResponse>('/teach', { |
| method: 'POST', |
| body: JSON.stringify({ question, answer }), |
| }) |
| refreshMetrics() |
| return resp |
| } finally { |
| setLoading(false) |
| } |
| }, [refreshMetrics]) |
|
|
| const learnText = useCallback(async (text: string): Promise<any> => { |
| setLoading(true) |
| try { |
| const resp = await fetchJson('/learn-text', { |
| method: 'POST', |
| body: JSON.stringify({ text }), |
| }) |
| refreshMetrics() |
| return resp |
| } finally { |
| setLoading(false) |
| } |
| }, [refreshMetrics]) |
|
|
| const dream = useCallback(async (cycles: number): Promise<any> => { |
| setLoading(true) |
| try { |
| const resp = await fetchJson('/dream', { |
| method: 'POST', |
| body: JSON.stringify({ cycles, replay_batch: 200 }), |
| }) |
| refreshMetrics() |
| return resp |
| } finally { |
| setLoading(false) |
| } |
| }, [refreshMetrics]) |
|
|
| const reason = useCallback(async (question: string): Promise<any> => { |
| setLoading(true) |
| try { |
| const resp = await fetchJson('/reason', { |
| method: 'POST', |
| body: JSON.stringify({ message: question }), |
| }) |
| return resp |
| } finally { |
| setLoading(false) |
| } |
| }, []) |
|
|
| |
| useEffect(() => { |
| checkHealth() |
| refreshMetrics() |
| pollRef.current = window.setInterval(() => { |
| refreshMetrics() |
| }, 5000) |
| return () => { |
| if (pollRef.current) clearInterval(pollRef.current) |
| } |
| }, [checkHealth, refreshMetrics]) |
|
|
| return { |
| connected, |
| metrics, |
| stats, |
| memorySamples, |
| loading, |
| sendMessage, |
| teachModel, |
| learnText, |
| dream, |
| reason, |
| refreshMetrics, |
| checkHealth, |
| } |
| } |
|
|