Improve ondobarding steps

This commit is contained in:
Urtzi Alfaro
2025-09-02 08:38:49 +02:00
parent 6346c4bcb9
commit b55da883c5
23 changed files with 1469 additions and 4725 deletions

View File

@@ -9,11 +9,11 @@ export * from './inventory.service';
export * from './production.service';
export * from './sales.service';
export * from './forecasting.service';
export * from './training.service';
export * from './orders.service';
export * from './procurement.service';
export * from './pos.service';
export * from './data.service';
export * from './training.service';
export * from './notification.service';
export * from './subscription.service';
@@ -28,7 +28,6 @@ export { ordersService } from './orders.service';
export { procurementService } from './procurement.service';
export { posService } from './pos.service';
export { dataService } from './data.service';
export { trainingService } from './training.service';
export { notificationService } from './notification.service';
export { subscriptionService } from './subscription.service';

View File

@@ -1,447 +1,70 @@
import { apiClient, ApiResponse } from './client';
/**
* Training service for ML model training operations
*/
import { ApiClient } from './client';
import { ApiResponse } from '../../types/api.types';
// Model and training types
export interface TrainingJob {
id: string;
tenant_id: string;
name: string;
model_type: 'demand_forecasting' | 'sales_prediction' | 'inventory_optimization' | 'production_planning';
status: 'pending' | 'initializing' | 'training' | 'validating' | 'completed' | 'failed' | 'cancelled';
model_id: string;
status: 'pending' | 'running' | 'completed' | 'failed';
progress: number;
parameters: {
data_start_date: string;
data_end_date: string;
validation_split: number;
hyperparameters: Record<string, any>;
};
metrics?: {
accuracy: number;
mse: number;
mae: number;
r2_score: number;
validation_accuracy: number;
};
training_duration_seconds?: number;
model_size_mb?: number;
created_at: string;
started_at?: string;
completed_at?: string;
error_message?: string;
created_by: string;
parameters: Record<string, any>;
metrics?: Record<string, number>;
}
export interface ModelInfo {
id: string;
tenant_id: string;
name: string;
model_type: string;
version: string;
status: 'training' | 'active' | 'deprecated' | 'archived';
is_production: boolean;
performance_metrics: {
accuracy: number;
precision: number;
recall: number;
f1_score: number;
last_evaluated: string;
};
training_data_info: {
record_count: number;
date_range: {
start: string;
end: string;
};
features_used: string[];
};
deployment_info?: {
deployed_at: string;
prediction_count: number;
avg_response_time_ms: number;
};
created_at: string;
updated_at: string;
export interface TrainingJobCreate {
model_id: string;
parameters?: Record<string, any>;
}
export interface TrainingConfiguration {
id: string;
tenant_id: string;
model_type: string;
name: string;
description?: string;
is_default: boolean;
parameters: {
algorithm: string;
hyperparameters: Record<string, any>;
feature_selection: string[];
validation_method: string;
cross_validation_folds?: number;
};
data_requirements: {
minimum_records: number;
required_columns: string[];
date_range_days: number;
};
created_at: string;
updated_at: string;
export interface TrainingJobUpdate {
parameters?: Record<string, any>;
}
class TrainingService {
private readonly baseUrl = '/training';
// Training job management
async getTrainingJobs(params?: {
page?: number;
size?: number;
status?: string;
model_type?: string;
}): Promise<ApiResponse<{ items: TrainingJob[]; total: number; page: number; size: number; pages: number }>> {
const queryParams = new URLSearchParams();
if (params) {
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined) {
queryParams.append(key, value.toString());
}
});
}
const url = queryParams.toString()
? `${this.baseUrl}/jobs?${queryParams.toString()}`
: `${this.baseUrl}/jobs`;
return apiClient.get(url);
export class TrainingService extends ApiClient {
constructor() {
super('/ml/training');
}
async getTrainingJob(jobId: string): Promise<ApiResponse<TrainingJob>> {
return apiClient.get(`${this.baseUrl}/jobs/${jobId}`);
async getTrainingJobs(modelId?: string): Promise<ApiResponse<TrainingJob[]>> {
const params = modelId ? { model_id: modelId } : {};
return this.get('/', params);
}
async createTrainingJob(jobData: {
name: string;
model_type: string;
config_id?: string;
parameters: {
data_start_date: string;
data_end_date: string;
validation_split?: number;
hyperparameters?: Record<string, any>;
};
}): Promise<ApiResponse<TrainingJob>> {
return apiClient.post(`${this.baseUrl}/jobs`, jobData);
async getTrainingJob(id: string): Promise<ApiResponse<TrainingJob>> {
return this.get(`/${id}`);
}
async cancelTrainingJob(jobId: string): Promise<ApiResponse<{ message: string }>> {
return apiClient.post(`${this.baseUrl}/jobs/${jobId}/cancel`);
async createTrainingJob(data: TrainingJobCreate): Promise<ApiResponse<TrainingJob>> {
return this.post('/', data);
}
async retryTrainingJob(jobId: string): Promise<ApiResponse<TrainingJob>> {
return apiClient.post(`${this.baseUrl}/jobs/${jobId}/retry`);
async updateTrainingJob(id: string, data: TrainingJobUpdate): Promise<ApiResponse<TrainingJob>> {
return this.put(`/${id}`, data);
}
async getTrainingLogs(jobId: string, params?: {
level?: 'debug' | 'info' | 'warning' | 'error';
limit?: number;
}): Promise<ApiResponse<Array<{
timestamp: string;
level: string;
message: string;
details?: Record<string, any>;
}>>> {
const queryParams = new URLSearchParams();
if (params) {
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined) {
queryParams.append(key, value.toString());
}
});
}
const url = queryParams.toString()
? `${this.baseUrl}/jobs/${jobId}/logs?${queryParams.toString()}`
: `${this.baseUrl}/jobs/${jobId}/logs`;
return apiClient.get(url);
async deleteTrainingJob(id: string): Promise<ApiResponse<void>> {
return this.delete(`/${id}`);
}
// Model management
async getModels(params?: {
page?: number;
size?: number;
model_type?: string;
status?: string;
is_production?: boolean;
}): Promise<ApiResponse<{ items: ModelInfo[]; total: number; page: number; size: number; pages: number }>> {
const queryParams = new URLSearchParams();
if (params) {
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined) {
queryParams.append(key, value.toString());
}
});
}
const url = queryParams.toString()
? `${this.baseUrl}/models?${queryParams.toString()}`
: `${this.baseUrl}/models`;
return apiClient.get(url);
async startTraining(id: string): Promise<ApiResponse<TrainingJob>> {
return this.post(`/${id}/start`);
}
async getModel(modelId: string): Promise<ApiResponse<ModelInfo>> {
return apiClient.get(`${this.baseUrl}/models/${modelId}`);
async stopTraining(id: string): Promise<ApiResponse<TrainingJob>> {
return this.post(`/${id}/stop`);
}
async deployModel(modelId: string): Promise<ApiResponse<{ message: string; deployment_id: string }>> {
return apiClient.post(`${this.baseUrl}/models/${modelId}/deploy`);
async getTrainingLogs(id: string): Promise<ApiResponse<string[]>> {
return this.get(`/${id}/logs`);
}
async undeployModel(modelId: string): Promise<ApiResponse<{ message: string }>> {
return apiClient.post(`${this.baseUrl}/models/${modelId}/undeploy`);
async getTrainingMetrics(id: string): Promise<ApiResponse<Record<string, number>>> {
return this.get(`/${id}/metrics`);
}
async deleteModel(modelId: string): Promise<ApiResponse<{ message: string }>> {
return apiClient.delete(`${this.baseUrl}/models/${modelId}`);
}
async compareModels(modelIds: string[]): Promise<ApiResponse<{
models: ModelInfo[];
comparison: {
accuracy_comparison: Array<{ model_id: string; accuracy: number; rank: number }>;
performance_metrics: Record<string, Array<{ model_id: string; value: number }>>;
recommendation: {
best_model_id: string;
reason: string;
confidence: number;
};
};
}>> {
return apiClient.post(`${this.baseUrl}/models/compare`, { model_ids: modelIds });
}
// Model evaluation
async evaluateModel(modelId: string, evaluationData?: {
test_data_start?: string;
test_data_end?: string;
metrics?: string[];
}): Promise<ApiResponse<{
evaluation_id: string;
status: 'pending' | 'running' | 'completed' | 'failed';
}>> {
return apiClient.post(`${this.baseUrl}/models/${modelId}/evaluate`, evaluationData);
}
async getEvaluationResults(evaluationId: string): Promise<ApiResponse<{
model_id: string;
status: string;
metrics: Record<string, number>;
predictions_sample: Array<{
actual: number;
predicted: number;
date: string;
error: number;
}>;
feature_importance?: Array<{
feature: string;
importance: number;
}>;
completed_at: string;
}>> {
return apiClient.get(`${this.baseUrl}/evaluations/${evaluationId}`);
}
// Training configuration
async getTrainingConfigs(modelType?: string): Promise<ApiResponse<TrainingConfiguration[]>> {
const url = modelType
? `${this.baseUrl}/configs?model_type=${encodeURIComponent(modelType)}`
: `${this.baseUrl}/configs`;
return apiClient.get(url);
}
async getTrainingConfig(configId: string): Promise<ApiResponse<TrainingConfiguration>> {
return apiClient.get(`${this.baseUrl}/configs/${configId}`);
}
async createTrainingConfig(configData: {
model_type: string;
name: string;
description?: string;
parameters: TrainingConfiguration['parameters'];
data_requirements?: Partial<TrainingConfiguration['data_requirements']>;
}): Promise<ApiResponse<TrainingConfiguration>> {
return apiClient.post(`${this.baseUrl}/configs`, configData);
}
async updateTrainingConfig(configId: string, configData: Partial<TrainingConfiguration>): Promise<ApiResponse<TrainingConfiguration>> {
return apiClient.put(`${this.baseUrl}/configs/${configId}`, configData);
}
async deleteTrainingConfig(configId: string): Promise<ApiResponse<{ message: string }>> {
return apiClient.delete(`${this.baseUrl}/configs/${configId}`);
}
// Data analysis and preparation
async analyzeTrainingData(params: {
model_type: string;
data_start_date: string;
data_end_date: string;
}): Promise<ApiResponse<{
data_quality: {
total_records: number;
complete_records: number;
missing_data_percentage: number;
duplicate_records: number;
};
feature_analysis: Array<{
feature: string;
data_type: string;
completeness: number;
unique_values: number;
correlation_with_target?: number;
}>;
recommendations: Array<{
type: 'data_cleaning' | 'feature_engineering' | 'model_selection';
message: string;
priority: 'high' | 'medium' | 'low';
}>;
training_feasibility: {
can_train: boolean;
minimum_requirements_met: boolean;
estimated_training_time_minutes: number;
};
}>> {
return apiClient.post(`${this.baseUrl}/analyze-data`, params);
}
async getDataAlignmentStatus(): Promise<ApiResponse<{
status: 'aligned' | 'misaligned' | 'processing';
last_alignment: string;
data_sources: Array<{
source: string;
status: 'synced' | 'out_of_sync' | 'error';
last_sync: string;
record_count: number;
}>;
issues?: Array<{
source: string;
issue_type: string;
description: string;
severity: 'low' | 'medium' | 'high';
}>;
}>> {
return apiClient.get(`${this.baseUrl}/data-alignment/status`);
}
async triggerDataAlignment(): Promise<ApiResponse<{ message: string; task_id: string }>> {
return apiClient.post(`${this.baseUrl}/data-alignment/trigger`);
}
// Training insights and recommendations
async getTrainingInsights(): Promise<ApiResponse<{
model_performance_trends: Array<{
model_type: string;
accuracy_trend: 'improving' | 'stable' | 'declining';
last_training_date: string;
recommendation: string;
}>;
training_frequency_suggestions: Array<{
model_type: string;
current_frequency: string;
suggested_frequency: string;
reason: string;
}>;
data_quality_alerts: Array<{
alert_type: string;
severity: 'info' | 'warning' | 'critical';
message: string;
affected_models: string[];
}>;
}>> {
return apiClient.get(`${this.baseUrl}/insights`);
}
// Utility methods
getModelTypes(): { value: string; label: string; description: string }[] {
return [
{
value: 'demand_forecasting',
label: 'Demand Forecasting',
description: 'Predict future demand for products based on historical sales and external factors'
},
{
value: 'sales_prediction',
label: 'Sales Prediction',
description: 'Forecast sales revenue and patterns'
},
{
value: 'inventory_optimization',
label: 'Inventory Optimization',
description: 'Optimize inventory levels and reorder points'
},
{
value: 'production_planning',
label: 'Production Planning',
description: 'Optimize production schedules and capacity planning'
}
];
}
getAlgorithmOptions(): { value: string; label: string; suitable_for: string[] }[] {
return [
{
value: 'prophet',
label: 'Prophet',
suitable_for: ['demand_forecasting', 'sales_prediction']
},
{
value: 'arima',
label: 'ARIMA',
suitable_for: ['demand_forecasting', 'sales_prediction']
},
{
value: 'random_forest',
label: 'Random Forest',
suitable_for: ['inventory_optimization', 'production_planning']
},
{
value: 'xgboost',
label: 'XGBoost',
suitable_for: ['demand_forecasting', 'inventory_optimization']
},
{
value: 'lstm',
label: 'LSTM Neural Network',
suitable_for: ['demand_forecasting', 'sales_prediction']
}
];
}
getValidationMethods(): { value: string; label: string; description: string }[] {
return [
{
value: 'time_series_split',
label: 'Time Series Split',
description: 'Split data chronologically for time series validation'
},
{
value: 'k_fold',
label: 'K-Fold Cross Validation',
description: 'Standard k-fold cross validation'
},
{
value: 'stratified_k_fold',
label: 'Stratified K-Fold',
description: 'Stratified sampling for cross validation'
},
{
value: 'holdout',
label: 'Holdout Validation',
description: 'Simple train/validation split'
}
];
}
}
export const trainingService = new TrainingService();
}