Improve ondobarding steps
This commit is contained in:
@@ -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';
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
Reference in New Issue
Block a user