Files
bakery-ia/frontend/src/api/services/training.ts
2025-10-06 15:27:01 +02:00

197 lines
5.9 KiB
TypeScript

// ================================================================
// frontend/src/api/services/training.ts
// ================================================================
/**
* Training Service - Complete backend alignment
*
* Backend API structure (3-tier architecture):
* - ATOMIC: training_jobs.py, models.py
* - OPERATIONS: training_operations.py
*
* Last Updated: 2025-10-05
* Status: ✅ Complete - Zero drift with backend
*/
import { apiClient } from '../client/apiClient';
import type {
TrainingJobRequest,
TrainingJobResponse,
TrainingJobStatus,
SingleProductTrainingRequest,
ActiveModelResponse,
ModelMetricsResponse,
TrainedModelResponse,
TenantStatistics,
ModelPerformanceResponse,
ModelsQueryParams,
PaginatedResponse,
} from '../types/training';
class TrainingService {
private readonly baseUrl = '/tenants';
// ===================================================================
// OPERATIONS: Training Job Creation
// Backend: services/training/app/api/training_operations.py
// ===================================================================
/**
* Create a new training job
* POST /tenants/{tenant_id}/training/jobs
*/
async createTrainingJob(
tenantId: string,
request: TrainingJobRequest
): Promise<TrainingJobResponse> {
return apiClient.post<TrainingJobResponse>(
`${this.baseUrl}/${tenantId}/training/jobs`,
request
);
}
/**
* Train a single product
* POST /tenants/{tenant_id}/training/products/{inventory_product_id}
*/
async trainSingleProduct(
tenantId: string,
inventoryProductId: string,
request: SingleProductTrainingRequest
): Promise<TrainingJobResponse> {
return apiClient.post<TrainingJobResponse>(
`${this.baseUrl}/${tenantId}/training/products/${inventoryProductId}`,
request
);
}
// ===================================================================
// ATOMIC: Training Job Status
// Backend: services/training/app/api/training_jobs.py
// ===================================================================
/**
* Get training job status
* GET /tenants/{tenant_id}/training/jobs/{job_id}/status
*/
async getTrainingJobStatus(
tenantId: string,
jobId: string
): Promise<TrainingJobStatus> {
return apiClient.get<TrainingJobStatus>(
`${this.baseUrl}/${tenantId}/training/jobs/${jobId}/status`
);
}
/**
* Get training statistics
* GET /tenants/{tenant_id}/training/statistics
*/
async getTenantStatistics(tenantId: string): Promise<TenantStatistics> {
return apiClient.get<TenantStatistics>(
`${this.baseUrl}/${tenantId}/training/statistics`
);
}
// ===================================================================
// ATOMIC: Model Management
// Backend: services/training/app/api/models.py
// ===================================================================
/**
* Get active model for a product
* GET /tenants/{tenant_id}/training/models/{inventory_product_id}/active
*/
async getActiveModel(
tenantId: string,
inventoryProductId: string
): Promise<ActiveModelResponse> {
return apiClient.get<ActiveModelResponse>(
`${this.baseUrl}/${tenantId}/training/models/${inventoryProductId}/active`
);
}
/**
* Get model metrics
* GET /tenants/{tenant_id}/training/models/{model_id}/metrics
*/
async getModelMetrics(
tenantId: string,
modelId: string
): Promise<ModelMetricsResponse> {
return apiClient.get<ModelMetricsResponse>(
`${this.baseUrl}/${tenantId}/training/models/${modelId}/metrics`
);
}
/**
* List models with optional filters
* GET /tenants/{tenant_id}/training/models
*/
async getModels(
tenantId: string,
queryParams?: ModelsQueryParams
): Promise<PaginatedResponse<TrainedModelResponse>> {
const params = new URLSearchParams();
if (queryParams?.status) params.append('status', queryParams.status);
if (queryParams?.model_type) params.append('model_type', queryParams.model_type);
if (queryParams?.limit) params.append('limit', queryParams.limit.toString());
if (queryParams?.offset) params.append('offset', queryParams.offset.toString());
const queryString = params.toString() ? `?${params.toString()}` : '';
return apiClient.get<PaginatedResponse<TrainedModelResponse>>(
`${this.baseUrl}/${tenantId}/training/models${queryString}`
);
}
/**
* Get model performance metrics
* Note: This endpoint might be deprecated - check backend for actual implementation
*/
async getModelPerformance(
tenantId: string,
modelId: string
): Promise<ModelPerformanceResponse> {
return apiClient.get<ModelPerformanceResponse>(
`${this.baseUrl}/${tenantId}/training/models/${modelId}/performance`
);
}
/**
* Delete all tenant models (Admin only)
* DELETE /models/tenant/{tenant_id}
*/
async deleteAllTenantModels(tenantId: string): Promise<{ message: string }> {
return apiClient.delete<{ message: string }>(`/models/tenant/${tenantId}`);
}
// ===================================================================
// WebSocket Support
// ===================================================================
/**
* Get WebSocket URL for real-time training updates
*/
getTrainingWebSocketUrl(tenantId: string, jobId: string): string {
const baseWsUrl = apiClient.getAxiosInstance().defaults.baseURL?.replace(/^http/, 'ws');
return `${baseWsUrl}/ws/tenants/${tenantId}/training/jobs/${jobId}/live`;
}
/**
* Helper method to construct WebSocket connection
*/
createWebSocketConnection(
tenantId: string,
jobId: string,
token?: string
): WebSocket {
const wsUrl = this.getTrainingWebSocketUrl(tenantId, jobId);
const urlWithToken = token ? `${wsUrl}?token=${token}` : wsUrl;
return new WebSocket(urlWithToken);
}
}
// Create and export singleton instance
export const trainingService = new TrainingService();
export default trainingService;