File size: 2,032 Bytes
fbf73ff |
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 |
import type { CasesResponse, SegmentResponse } from '../types'
function getApiBase(): string {
const url = import.meta.env.VITE_API_URL
// In production, VITE_API_URL must be set - fail fast with clear error
if (import.meta.env.PROD && !url) {
throw new Error(
'VITE_API_URL environment variable is required in production. ' +
'Set it to the backend API URL (e.g., https://your-app.hf.space).'
)
}
// In development, fall back to localhost
return url || 'http://localhost:7860'
}
const API_BASE = getApiBase()
export class ApiError extends Error {
status: number
detail?: string
constructor(message: string, status: number, detail?: string) {
super(message)
this.name = 'ApiError'
this.status = status
this.detail = detail
}
}
class ApiClient {
private baseUrl: string
constructor(baseUrl: string) {
this.baseUrl = baseUrl
}
async getCases(signal?: AbortSignal): Promise<CasesResponse> {
const response = await fetch(`${this.baseUrl}/api/cases`, { signal })
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new ApiError(
`Failed to fetch cases: ${response.statusText}`,
response.status,
error.detail
)
}
return response.json()
}
async runSegmentation(
caseId: string,
fastMode: boolean = true,
signal?: AbortSignal
): Promise<SegmentResponse> {
const response = await fetch(`${this.baseUrl}/api/segment`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
case_id: caseId,
fast_mode: fastMode,
}),
signal,
})
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new ApiError(
`Segmentation failed: ${error.detail || response.statusText}`,
response.status,
error.detail
)
}
return response.json()
}
}
export const apiClient = new ApiClient(API_BASE)
|