import { api } from '@/lib/api' import type { GetModelsParams, GetModelsResponse, GetModelResponse, GetVendorsResponse, GetVendorResponse, Model, Vendor, SearchModelsParams, SyncUpstreamResponse, PreviewUpstreamDiffResponse, MissingModelsResponse, PrefillGroupsResponse, SyncLocale, SyncSource, SyncOverwritePayload, DeploymentSettingsResponse, ListDeploymentsResponse, } from './types' // ============================================================================ // Model CRUD Operations // ============================================================================ /** * Get paginated list of models */ export async function getModels( params: GetModelsParams = {} ): Promise { const res = await api.get('/api/models/', { params }) return res.data } /** * Search models with filters */ export async function searchModels( params: SearchModelsParams ): Promise { const res = await api.get('/api/models/search', { params }) return res.data } /** * Get single model by ID */ export async function getModel(id: number): Promise { const res = await api.get(`/api/models/${id}`) return res.data } /** * Create new model */ export async function createModel( data: Partial ): Promise<{ success: boolean; message?: string; data?: Model }> { const res = await api.post('/api/models/', data) return res.data } /** * Update existing model */ export async function updateModel( data: Partial & { id: number } ): Promise<{ success: boolean; message?: string; data?: Model }> { const res = await api.put('/api/models/', data) return res.data } /** * Update model status only */ export async function updateModelStatus( id: number, status: number ): Promise<{ success: boolean; message?: string }> { const res = await api.put('/api/models/?status_only=true', { id, status }) return res.data } /** * Delete model */ export async function deleteModel( id: number ): Promise<{ success: boolean; message?: string }> { const res = await api.delete(`/api/models/${id}`) return res.data } // ============================================================================ // Vendor Management // ============================================================================ /** * Get paginated list of vendors */ export async function getVendors(params?: { p?: number page_size?: number }): Promise { const res = await api.get('/api/vendors/', { params: params || { page_size: 1000 }, }) return res.data } /** * Search vendors */ export async function searchVendors(params: { keyword?: string p?: number page_size?: number }): Promise { const res = await api.get('/api/vendors/search', { params }) return res.data } /** * Get single vendor by ID */ export async function getVendor(id: number): Promise { const res = await api.get(`/api/vendors/${id}`) return res.data } /** * Create new vendor */ export async function createVendor( data: Partial ): Promise<{ success: boolean; message?: string; data?: Vendor }> { const res = await api.post('/api/vendors/', data) return res.data } /** * Update existing vendor */ export async function updateVendor( data: Partial & { id: number } ): Promise<{ success: boolean; message?: string; data?: Vendor }> { const res = await api.put('/api/vendors/', data) return res.data } /** * Delete vendor */ export async function deleteVendor( id: number ): Promise<{ success: boolean; message?: string }> { const res = await api.delete(`/api/vendors/${id}`) return res.data } // ============================================================================ // Sync Operations // ============================================================================ /** * Sync upstream models (missing only or with overwrite) */ export async function syncUpstream(params?: { locale?: SyncLocale source?: SyncSource overwrite?: SyncOverwritePayload[] }): Promise { const res = await api.post('/api/models/sync_upstream', params) return res.data } /** * Preview upstream diff */ export async function previewUpstreamDiff(params?: { locale?: SyncLocale source?: SyncSource }): Promise { const searchParams = new URLSearchParams() if (params?.locale) { searchParams.set('locale', params.locale) } if (params?.source) { searchParams.set('source', params.source) } const queryString = searchParams.toString() const url = queryString ? `/api/models/sync_upstream/preview?${queryString}` : '/api/models/sync_upstream/preview' const res = await api.get(url) return res.data } /** * Apply upstream overwrite */ export async function applyUpstreamOverwrite(params: { overwrite: SyncOverwritePayload[] locale?: SyncLocale source?: SyncSource }): Promise { return syncUpstream(params) } // ============================================================================ // Utility Operations // ============================================================================ /** * Get missing models (used but not configured) */ export async function getMissingModels(): Promise { const res = await api.get('/api/models/missing') return res.data } /** * Get prefill groups */ export async function getPrefillGroups( type?: 'model' | 'tag' | 'endpoint' ): Promise { const res = await api.get('/api/prefill_group', { params: type ? { type } : undefined, }) return res.data } /** * Create prefill group */ export async function createPrefillGroup(data: { name: string type: 'model' | 'tag' | 'endpoint' items: string | string[] description?: string }): Promise<{ success: boolean; message?: string }> { const res = await api.post('/api/prefill_group', data) return res.data } /** * Update prefill group */ export async function updatePrefillGroup(data: { id: number type?: 'model' | 'tag' | 'endpoint' name?: string items?: string | string[] description?: string }): Promise<{ success: boolean; message?: string }> { const res = await api.put('/api/prefill_group', data) return res.data } /** * Delete prefill group */ export async function deletePrefillGroup( id: number ): Promise<{ success: boolean; message?: string }> { const res = await api.delete(`/api/prefill_group/${id}`) return res.data } // ============================================================================ // Deployment Operations // ============================================================================ /** * Get deployment settings (io.net config) */ export async function getDeploymentSettings(): Promise { const res = await api.get('/api/deployments/settings') return res.data } /** * Test deployment connection */ export async function testDeploymentConnection(): Promise<{ success: boolean message?: string }> { const config = { skipErrorHandler: true } as unknown as Parameters< typeof api.post >[2] const res = await api.post( '/api/deployments/settings/test-connection', {}, config ) return res.data } /** * Test deployment connection with optional api_key (allow test before saving) */ export async function testDeploymentConnectionWithKey( apiKey?: string ): Promise<{ success: boolean message?: string }> { const payload = typeof apiKey === 'string' && apiKey.trim() ? { api_key: apiKey.trim() } : {} const config = { skipErrorHandler: true } as unknown as Parameters< typeof api.post >[2] const res = await api.post( '/api/deployments/settings/test-connection', payload, config ) return res.data } /** * List deployments */ export async function listDeployments(params: { p?: number page_size?: number status?: string }): Promise { const res = await api.get('/api/deployments/', { params }) return res.data } /** * Search deployments (keyword + status) * * Backend exposes a dedicated `/api/deployments/search` route that supports * filtering by keyword (and status). Use this when keyword is provided. */ export async function searchDeployments(params: { p?: number page_size?: number status?: string keyword?: string }): Promise { const res = await api.get('/api/deployments/search', { params }) return res.data } /** * Get deployment details */ export async function getDeployment(id: string | number): Promise<{ success: boolean message?: string data?: Record }> { const res = await api.get(`/api/deployments/${id}`) return res.data } /** * List deployment containers */ export async function listDeploymentContainers( deploymentId: string | number ): Promise<{ success: boolean message?: string data?: { total?: number containers?: Array> } }> { const res = await api.get(`/api/deployments/${deploymentId}/containers`) return res.data } /** * Get single container details */ export async function getDeploymentContainerDetails( deploymentId: string | number, containerId: string ): Promise<{ success: boolean message?: string data?: Record }> { const res = await api.get( `/api/deployments/${deploymentId}/containers/${encodeURIComponent(containerId)}` ) return res.data } /** * Delete deployment */ export async function deleteDeployment( id: string | number ): Promise<{ success: boolean; message?: string }> { const res = await api.delete(`/api/deployments/${id}`) return res.data } /** * Get deployment logs (raw) */ export async function getDeploymentLogs( deploymentId: string | number, params: { container_id: string stream?: 'stdout' | 'stderr' | 'all' | string level?: string cursor?: string limit?: number follow?: boolean start_time?: string end_time?: string } ): Promise<{ success: boolean; message?: string; data?: string }> { const res = await api.get(`/api/deployments/${deploymentId}/logs`, { params }) return res.data } /** * Get hardware types for deployment */ export async function getHardwareTypes(): Promise<{ success: boolean data?: { hardware_types?: Array> } }> { const res = await api.get('/api/deployments/hardware-types') return res.data } /** * Get locations for deployment */ export async function getDeploymentLocations(): Promise<{ success: boolean message?: string data?: { locations?: Array>; total?: number } }> { const res = await api.get('/api/deployments/locations') return res.data } /** * Get available replicas */ export async function getAvailableReplicas(params: { hardware_id: string gpu_count: number }): Promise<{ success: boolean data?: { replicas?: Array> } }> { const res = await api.get('/api/deployments/available-replicas', { params }) return res.data } /** * Estimate deployment price */ export async function estimatePrice(params: { location_ids: Array hardware_id: string | number gpus_per_container: number duration_hours: number replica_count: number currency?: string }): Promise<{ success: boolean message?: string data?: Record }> { const locationIds = (params.location_ids || []) .map((x) => Number(x)) .filter((n) => Number.isInteger(n) && n > 0) const hardwareId = Number(params.hardware_id) const duration = Number(params.duration_hours) const gpus = Number(params.gpus_per_container) const replicaCount = Number(params.replica_count) const currency = typeof params.currency === 'string' && params.currency.trim() ? params.currency.trim().toLowerCase() : 'usdc' const payload = { location_ids: locationIds, hardware_id: hardwareId, gpus_per_container: gpus, duration_hours: duration, replica_count: replicaCount, currency, duration_type: 'hour', duration_qty: duration, hardware_qty: gpus, } const res = await api.post('/api/deployments/price-estimation', payload) return res.data } /** * Create deployment */ export async function createDeployment(data: { resource_private_name: string duration_hours: number gpus_per_container: number hardware_id: number location_ids: number[] container_config: { replica_count: number env_variables?: Record secret_env_variables?: Record entrypoint?: string[] traffic_port?: number args?: string[] } registry_config: { image_url: string registry_username?: string registry_secret?: string } }): Promise<{ success: boolean message?: string data?: Record }> { const res = await api.post('/api/deployments/', data) return res.data } /** * Update deployment configuration */ export async function updateDeployment( id: string | number, data: { env_variables?: Record secret_env_variables?: Record entrypoint?: string[] traffic_port?: number | null image_url?: string registry_username?: string registry_secret?: string args?: string[] command?: string } ): Promise<{ success: boolean message?: string data?: Record }> { const payload: Record = { ...data } if (data.traffic_port === null) { delete payload.traffic_port } const res = await api.put(`/api/deployments/${id}`, payload) return res.data } /** * Update deployment name */ export async function updateDeploymentName( id: string | number, name: string ): Promise<{ success: boolean message?: string data?: Record }> { const res = await api.put(`/api/deployments/${id}/name`, { name }) return res.data } /** * Extend deployment duration */ export async function extendDeployment( id: string | number, durationHours: number ): Promise<{ success: boolean message?: string data?: Record }> { const res = await api.post(`/api/deployments/${id}/extend`, { duration_hours: durationHours, }) return res.data } /** * Check cluster name availability */ export async function checkClusterNameAvailability(name: string): Promise<{ success: boolean message?: string data?: { available?: boolean; name?: string } }> { const res = await api.get('/api/deployments/check-name', { params: { name }, }) return res.data }