Spaces:
Sleeping
Sleeping
File size: 4,745 Bytes
6242ddb | 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 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | import type { AnalysisResult, ComparisonResult, FilterParams, JobStatus } from '../types';
const API_BASE = '/api/v1';
class ApiError extends Error {
constructor(
public status: number,
message: string,
public correlationId?: string,
) {
super(message);
this.name = 'ApiError';
}
}
function getHeaders(): Record<string, string> {
const apiKey = localStorage.getItem('api_key') || 'dev-key-1';
return {
'X-API-Key': apiKey,
'Content-Type': 'application/json',
};
}
async function handleResponse<T>(response: Response): Promise<T> {
if (!response.ok) {
const body = await response.json().catch(() => ({ detail: response.statusText }));
throw new ApiError(response.status, body.detail || 'Request failed', body.correlation_id);
}
return response.json();
}
export const api = {
async uploadFile(file: File, source?: string): Promise<JobStatus> {
const formData = new FormData();
formData.append('file', file);
const params = new URLSearchParams();
if (source) params.set('source', source);
const apiKey = localStorage.getItem('api_key') || 'dev-key-1';
const response = await fetch(`${API_BASE}/upload?${params}`, {
method: 'POST',
headers: { 'X-API-Key': apiKey },
body: formData,
});
return handleResponse<JobStatus>(response);
},
async uploadChunked(
file: File,
onProgress?: (progress: number) => void,
): Promise<JobStatus> {
const CHUNK_SIZE = 10 * 1024 * 1024; // 10MB
const totalChunks = Math.ceil(file.size / CHUNK_SIZE);
let uploadId: string | undefined;
let lastStatus: JobStatus | undefined;
for (let i = 0; i < totalChunks; i++) {
const start = i * CHUNK_SIZE;
const end = Math.min(start + CHUNK_SIZE, file.size);
const chunk = file.slice(start, end);
const formData = new FormData();
formData.append('file', chunk, file.name);
const params = new URLSearchParams({
chunk_index: String(i),
total_chunks: String(totalChunks),
});
if (uploadId) params.set('upload_id', uploadId);
const apiKey = localStorage.getItem('api_key') || 'dev-key-1';
const response = await fetch(`${API_BASE}/upload/chunked?${params}`, {
method: 'POST',
headers: { 'X-API-Key': apiKey },
body: formData,
});
lastStatus = await handleResponse<JobStatus>(response);
uploadId = lastStatus.job_id;
onProgress?.((i + 1) / totalChunks);
}
return lastStatus!;
},
async getJobs(): Promise<JobStatus[]> {
const response = await fetch(`${API_BASE}/jobs`, { headers: getHeaders() });
return handleResponse<JobStatus[]>(response);
},
async getJobResult(jobId: string): Promise<AnalysisResult> {
const response = await fetch(`${API_BASE}/jobs/${jobId}`, { headers: getHeaders() });
return handleResponse<AnalysisResult>(response);
},
async getJobStatus(jobId: string): Promise<JobStatus> {
const response = await fetch(`${API_BASE}/jobs/${jobId}/status`, { headers: getHeaders() });
return handleResponse<JobStatus>(response);
},
async filterResults(jobId: string, filters: FilterParams) {
const response = await fetch(`${API_BASE}/jobs/${jobId}/filter`, {
method: 'POST',
headers: getHeaders(),
body: JSON.stringify(filters),
});
return handleResponse<{ total: number; page: number; entries: AnalysisResult['entries'] }>(response);
},
async compareSegments(jobId: string, segmentA: FilterParams, segmentB: FilterParams): Promise<ComparisonResult> {
const response = await fetch(`${API_BASE}/jobs/${jobId}/compare`, {
method: 'POST',
headers: getHeaders(),
body: JSON.stringify({ segment_a: segmentA, segment_b: segmentB }),
});
return handleResponse<ComparisonResult>(response);
},
async exportResults(jobId: string, format: 'csv' | 'json' | 'pdf', filters?: FilterParams): Promise<Blob> {
const response = await fetch(`${API_BASE}/jobs/${jobId}/export?fmt=${format}`, {
method: 'POST',
headers: getHeaders(),
body: filters ? JSON.stringify(filters) : '{}',
});
if (!response.ok) {
throw new ApiError(response.status, 'Export failed');
}
return response.blob();
},
subscribeToEvents(onMessage: (data: Record<string, unknown>) => void): EventSource {
const apiKey = localStorage.getItem('api_key') || 'dev-key-1';
const es = new EventSource(`${API_BASE}/events/analysis?api_key=${apiKey}`);
es.addEventListener('analysis_update', (event) => {
try {
const data = JSON.parse(event.data);
onMessage(data);
} catch {
// ignore parse errors
}
});
return es;
},
};
|