2025-09-05 22:46:28 +02:00
|
|
|
/**
|
|
|
|
|
* Training service API implementation
|
|
|
|
|
* Handles all training-related backend communications
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
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';
|
|
|
|
|
|
|
|
|
|
// Training Jobs
|
|
|
|
|
async createTrainingJob(
|
|
|
|
|
tenantId: string,
|
|
|
|
|
request: TrainingJobRequest
|
|
|
|
|
): Promise<TrainingJobResponse> {
|
|
|
|
|
return apiClient.post<TrainingJobResponse>(
|
|
|
|
|
`${this.baseUrl}/${tenantId}/training/jobs`,
|
|
|
|
|
request
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async trainSingleProduct(
|
|
|
|
|
tenantId: string,
|
|
|
|
|
inventoryProductId: string,
|
|
|
|
|
request: SingleProductTrainingRequest
|
|
|
|
|
): Promise<TrainingJobResponse> {
|
|
|
|
|
return apiClient.post<TrainingJobResponse>(
|
|
|
|
|
`${this.baseUrl}/${tenantId}/training/products/${inventoryProductId}`,
|
|
|
|
|
request
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async getTrainingJobStatus(
|
|
|
|
|
tenantId: string,
|
|
|
|
|
jobId: string
|
|
|
|
|
): Promise<TrainingJobStatus> {
|
|
|
|
|
return apiClient.get<TrainingJobStatus>(
|
|
|
|
|
`${this.baseUrl}/${tenantId}/training/jobs/${jobId}/status`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Models Management
|
|
|
|
|
async getActiveModel(
|
|
|
|
|
tenantId: string,
|
|
|
|
|
inventoryProductId: string
|
|
|
|
|
): Promise<ActiveModelResponse> {
|
|
|
|
|
return apiClient.get<ActiveModelResponse>(
|
|
|
|
|
`${this.baseUrl}/${tenantId}/models/${inventoryProductId}/active`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async getModelMetrics(
|
|
|
|
|
tenantId: string,
|
|
|
|
|
modelId: string
|
|
|
|
|
): Promise<ModelMetricsResponse> {
|
|
|
|
|
return apiClient.get<ModelMetricsResponse>(
|
|
|
|
|
`${this.baseUrl}/${tenantId}/models/${modelId}/metrics`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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>>(
|
2025-09-20 22:11:05 +02:00
|
|
|
`${this.baseUrl}/${tenantId}/models/${queryString}`
|
2025-09-05 22:46:28 +02:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async getModelPerformance(
|
|
|
|
|
tenantId: string,
|
|
|
|
|
modelId: string
|
|
|
|
|
): Promise<ModelPerformanceResponse> {
|
|
|
|
|
return apiClient.get<ModelPerformanceResponse>(
|
|
|
|
|
`${this.baseUrl}/${tenantId}/models/${modelId}/performance`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Statistics and Analytics
|
|
|
|
|
async getTenantStatistics(tenantId: string): Promise<TenantStatistics> {
|
|
|
|
|
return apiClient.get<TenantStatistics>(
|
|
|
|
|
`${this.baseUrl}/${tenantId}/statistics`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Admin endpoints (requires admin role)
|
|
|
|
|
async deleteAllTenantModels(tenantId: string): Promise<{ message: string }> {
|
|
|
|
|
return apiClient.delete<{ message: string }>(`/models/tenant/${tenantId}`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// WebSocket connection helper (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;
|