File size: 6,439 Bytes
4346e8f
9438a57
4346e8f
 
 
 
 
 
 
 
 
 
 
9438a57
 
 
 
 
4346e8f
 
 
 
 
 
 
 
9438a57
4346e8f
 
 
 
 
 
 
 
9438a57
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4346e8f
9438a57
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4346e8f
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import type {
  AgentEvent, BenchItem, CompareResult, EvalListItem, EvalState, Experiment, ExpPlan, GpuStatus, Health, CloudProvider, Device, Providers, AutoRun, AutoSettings, LibItem, LibItemIn, ProbeResult, TrackDetail, TrackSummary, Translation, JobRequest, JobState, JobSummary, Sample,
} from './types';

async function req<T>(url: string, init?: RequestInit): Promise<T> {
  const r = await fetch(url, {
    ...init,
    headers: { 'Content-Type': 'application/json', ...(init?.headers || {}) },
  });
  if (!r.ok) {
    let msg = `${r.status} ${r.statusText}`;
    try {
      const body = await r.json();
      // FastAPI doğrulama hataları bir liste olarak gelir: ham JSON yerine okunur iletiler gösterilir
      msg = typeof body.detail === 'string' ? body.detail
        : Array.isArray(body.detail) ? body.detail.map((d: { loc?: unknown[]; msg?: string }) =>
          `${(d.loc || []).filter((x) => x !== 'body').join('.')}: ${d.msg}`).join(' · ')
        : JSON.stringify(body.detail ?? body);
    } catch { /* yoksay */ }
    throw new Error(msg);
  }
  return r.json() as Promise<T>;
}

export const api = {
  health: () => req<Health>('/api/health'),
  gpu: () => req<GpuStatus>('/api/gpu'),
  samples: () => req<Sample[]>('/api/samples'),
  createJob: (body: JobRequest) => req<{ id: string }>('/api/jobs', { method: 'POST', body: JSON.stringify(body) }),
  job: (id: string) => req<JobState>(`/api/jobs/${id}`),
  jobs: () => req<JobSummary[]>('/api/jobs'),
  cancel: (id: string) => req<{ ok: boolean }>(`/api/jobs/${id}/cancel`, { method: 'POST' }),
  benchmark: () => req<BenchItem[]>('/api/benchmark'),
  startEval: (body: Record<string, unknown>) =>
    req<{ id: string }>('/api/evals', { method: 'POST', body: JSON.stringify(body) }),
  evals: () => req<EvalListItem[]>('/api/evals'),
  resumeEval: (id: string) => req<{ ok: boolean }>(`/api/evals/${id}/resume`, { method: 'POST' }),
  pauseEval: (id: string) => req<{ ok: boolean }>(`/api/evals/${id}/pause`, { method: 'POST' }),
  compare: (a: string, b: string) => req<CompareResult>(`/api/compare?a=${a}&b=${b}`),
  expPlan: (profile: string, models: string[]) => req<ExpPlan>(`/api/experiments/plan?profile=${profile}&models=${encodeURIComponent(models.join(','))}`),
  experiments: () => req<Experiment[]>('/api/experiments/runs'),
  experiment: (id: string) => req<Experiment>(`/api/experiments/runs/${id}`),
  startExperiment: (body: { profile: string; models: string[]; max_mutants: number }) =>
    req<{ id: string }>('/api/experiments/runs', { method: 'POST', body: JSON.stringify(body) }),
  translate: (id: string, lang: string) =>
    req<Partial<Translation> & { lang: string; original?: boolean }>(`/api/jobs/${id}/translate`, { method: 'POST', body: JSON.stringify({ lang }) }),
  cancelExperiment: (id: string) => req<{ ok: boolean }>(`/api/experiments/runs/${id}/cancel`, { method: 'POST' }),
  cancelEval: (id: string) => req<{ ok: boolean }>(`/api/evals/${id}/cancel`, { method: 'POST' }),
  pauseExperiment: (id: string) => req<{ ok: boolean }>(`/api/experiments/runs/${id}/pause`, { method: 'POST' }),
  retryExperiment: (id: string) => req<{ ok: boolean }>(`/api/experiments/runs/${id}/retry-failed`, { method: 'POST' }),
  resumeExperiment: (id: string) => req<{ ok: boolean }>(`/api/experiments/runs/${id}/resume`, { method: 'POST' }),
  evalState: (id: string) => req<EvalState>(`/api/evals/${id}`),
  providers: () => req<Providers>('/api/providers'),
  autoRuns: () => req<AutoRun[]>('/api/automation/runs'),
  tracking: () => req<TrackSummary[]>('/api/tracking'),
  trackingDetail: (key: string) => req<TrackDetail>(`/api/tracking/${key}`),
  probeModels: (models: string[], force = true) =>
    req<Record<string, ProbeResult>>('/api/models/probe', { method: 'POST', body: JSON.stringify({ models, force }) }),
  library: () => req<LibItem[]>('/api/automation/library'),
  addLibrary: (items: LibItemIn[]) => req<{ ids: string[] }>('/api/automation/library', { method: 'POST', body: JSON.stringify(items) }),
  deleteLibrary: (id: string) => req<{ ok: boolean }>(`/api/automation/library/${encodeURIComponent(id)}`, { method: 'DELETE' }),
  startAuto: (sample_ids: string[], settings: AutoSettings) =>
    req<{ id: string }>('/api/automation/runs', { method: 'POST', body: JSON.stringify({ sample_ids, settings }) }),
  pauseAuto: (id: string) => req<{ ok: boolean }>(`/api/automation/runs/${id}/pause`, { method: 'POST' }),
  resumeAuto: (id: string) => req<{ ok: boolean }>(`/api/automation/runs/${id}/resume`, { method: 'POST' }),
  cancelAuto: (id: string) => req<{ ok: boolean }>(`/api/automation/runs/${id}/cancel`, { method: 'POST' }),
  seenAuto: (id: string) => req<{ ok: boolean }>(`/api/automation/runs/${id}/seen`, { method: 'POST' }),
  rebuildAuto: (id: string) => req<unknown>(`/api/automation/runs/${id}/rebuild-reports`, { method: 'POST' }),
  deleteAuto: (id: string) => req<{ ok: boolean }>(`/api/automation/runs/${id}`, { method: 'DELETE' }),
  settings: () => req<{ prefs: Record<string, unknown>; file_name: string; folder: string; exists: boolean; docker: boolean }>('/api/settings'),
  savePrefs: (values: Record<string, unknown>) =>
    req<{ prefs: Record<string, unknown> }>('/api/settings/prefs', { method: 'PUT', body: JSON.stringify(values), keepalive: true }),
  importSettings: (doc: unknown) =>
    req<{ prefs: Record<string, unknown>; providers: Providers }>('/api/settings/import', { method: 'POST', body: JSON.stringify(doc) }),
  connectProvider: (id: string, body: { api_key?: string; base_url?: string }) =>
    req<CloudProvider>(`/api/providers/${id}`, { method: 'PUT', body: JSON.stringify(body) }),
  syncProvider: (id: string) => req<CloudProvider>(`/api/providers/${id}/sync`, { method: 'POST' }),
  disconnectProvider: (id: string) => req<CloudProvider>(`/api/providers/${id}`, { method: 'DELETE' }),
  setDevice: (device: Device) => req<{ device: Device }>('/api/providers/device', { method: 'PUT', body: JSON.stringify({ device }) }),
};

/** Sunucu olay akışına (SSE) abone olur; kapatma fonksiyonu döndürür. */
export function subscribe(jobId: string, onEvent: (e: AgentEvent) => void, onEnd: () => void): () => void {
  const es = new EventSource(`/api/jobs/${jobId}/events`);
  es.onmessage = (m) => onEvent(JSON.parse(m.data));
  es.addEventListener('end', () => { es.close(); onEnd(); });
  es.onerror = () => { es.close(); onEnd(); };
  return () => es.close();
}