568 lines
17 KiB
TypeScript
568 lines
17 KiB
TypeScript
/**
|
|
* Forecasting hook for managing demand forecasting and ML models
|
|
*/
|
|
|
|
import { useState, useEffect, useCallback } from 'react';
|
|
import { ForecastingService } from '../../services/api/forecasting.service';
|
|
import {
|
|
ForecastModel,
|
|
ForecastModelCreate,
|
|
ForecastModelUpdate,
|
|
ForecastPrediction,
|
|
ForecastPredictionCreate,
|
|
ForecastBatch,
|
|
ModelTraining,
|
|
ModelEvaluation
|
|
} from '../../types/forecasting.types';
|
|
import { ApiResponse, PaginatedResponse, QueryParams } from '../../types/api.types';
|
|
|
|
interface ForecastingState {
|
|
models: ForecastModel[];
|
|
predictions: ForecastPrediction[];
|
|
batches: ForecastBatch[];
|
|
trainings: ModelTraining[];
|
|
evaluations: ModelEvaluation[];
|
|
isLoading: boolean;
|
|
error: string | null;
|
|
pagination: {
|
|
total: number;
|
|
page: number;
|
|
pages: number;
|
|
limit: number;
|
|
};
|
|
}
|
|
|
|
interface ForecastingActions {
|
|
// Models
|
|
fetchModels: (params?: QueryParams) => Promise<void>;
|
|
createModel: (data: ForecastModelCreate) => Promise<boolean>;
|
|
updateModel: (id: string, data: ForecastModelUpdate) => Promise<boolean>;
|
|
deleteModel: (id: string) => Promise<boolean>;
|
|
getModel: (id: string) => Promise<ForecastModel | null>;
|
|
trainModel: (id: string, parameters?: any) => Promise<boolean>;
|
|
deployModel: (id: string) => Promise<boolean>;
|
|
|
|
// Predictions
|
|
fetchPredictions: (params?: QueryParams) => Promise<void>;
|
|
createPrediction: (data: ForecastPredictionCreate) => Promise<boolean>;
|
|
getPrediction: (id: string) => Promise<ForecastPrediction | null>;
|
|
generateDemandForecast: (modelId: string, horizon: number, parameters?: any) => Promise<any>;
|
|
|
|
// Batch Predictions
|
|
fetchBatches: (params?: QueryParams) => Promise<void>;
|
|
createBatch: (modelId: string, data: any) => Promise<boolean>;
|
|
getBatch: (id: string) => Promise<ForecastBatch | null>;
|
|
downloadBatchResults: (id: string) => Promise<boolean>;
|
|
|
|
// Model Training
|
|
fetchTrainings: (modelId?: string) => Promise<void>;
|
|
getTraining: (id: string) => Promise<ModelTraining | null>;
|
|
cancelTraining: (id: string) => Promise<boolean>;
|
|
|
|
// Model Evaluation
|
|
fetchEvaluations: (modelId?: string) => Promise<void>;
|
|
createEvaluation: (modelId: string, testData: any) => Promise<boolean>;
|
|
getEvaluation: (id: string) => Promise<ModelEvaluation | null>;
|
|
|
|
// Analytics
|
|
getModelPerformance: (modelId: string, period?: string) => Promise<any>;
|
|
getAccuracyReport: (modelId: string, startDate?: string, endDate?: string) => Promise<any>;
|
|
getFeatureImportance: (modelId: string) => Promise<any>;
|
|
|
|
// Utilities
|
|
clearError: () => void;
|
|
refresh: () => Promise<void>;
|
|
}
|
|
|
|
export const useForecasting = (): ForecastingState & ForecastingActions => {
|
|
const [state, setState] = useState<ForecastingState>({
|
|
models: [],
|
|
predictions: [],
|
|
batches: [],
|
|
trainings: [],
|
|
evaluations: [],
|
|
isLoading: false,
|
|
error: null,
|
|
pagination: {
|
|
total: 0,
|
|
page: 1,
|
|
pages: 1,
|
|
limit: 20,
|
|
},
|
|
});
|
|
|
|
const forecastingService = new ForecastingService();
|
|
|
|
// Fetch forecast models
|
|
const fetchModels = useCallback(async (params?: QueryParams) => {
|
|
setState(prev => ({ ...prev, isLoading: true, error: null }));
|
|
|
|
try {
|
|
const response = await forecastingService.getModels(params);
|
|
|
|
if (response.success && response.data) {
|
|
setState(prev => ({
|
|
...prev,
|
|
models: Array.isArray(response.data) ? response.data : response.data.items || [],
|
|
pagination: response.data.pagination || prev.pagination,
|
|
isLoading: false,
|
|
}));
|
|
} else {
|
|
setState(prev => ({
|
|
...prev,
|
|
isLoading: false,
|
|
error: response.error || 'Error al cargar modelos de predicción',
|
|
}));
|
|
}
|
|
} catch (error) {
|
|
setState(prev => ({
|
|
...prev,
|
|
isLoading: false,
|
|
error: 'Error de conexión al servidor',
|
|
}));
|
|
}
|
|
}, [forecastingService]);
|
|
|
|
// Create forecast model
|
|
const createModel = useCallback(async (data: ForecastModelCreate): Promise<boolean> => {
|
|
setState(prev => ({ ...prev, error: null }));
|
|
|
|
try {
|
|
const response = await forecastingService.createModel(data);
|
|
|
|
if (response.success) {
|
|
await fetchModels();
|
|
return true;
|
|
} else {
|
|
setState(prev => ({
|
|
...prev,
|
|
error: response.error || 'Error al crear modelo de predicción',
|
|
}));
|
|
return false;
|
|
}
|
|
} catch (error) {
|
|
setState(prev => ({
|
|
...prev,
|
|
error: 'Error de conexión al servidor',
|
|
}));
|
|
return false;
|
|
}
|
|
}, [forecastingService, fetchModels]);
|
|
|
|
// Update forecast model
|
|
const updateModel = useCallback(async (id: string, data: ForecastModelUpdate): Promise<boolean> => {
|
|
setState(prev => ({ ...prev, error: null }));
|
|
|
|
try {
|
|
const response = await forecastingService.updateModel(id, data);
|
|
|
|
if (response.success) {
|
|
await fetchModels();
|
|
return true;
|
|
} else {
|
|
setState(prev => ({
|
|
...prev,
|
|
error: response.error || 'Error al actualizar modelo de predicción',
|
|
}));
|
|
return false;
|
|
}
|
|
} catch (error) {
|
|
setState(prev => ({
|
|
...prev,
|
|
error: 'Error de conexión al servidor',
|
|
}));
|
|
return false;
|
|
}
|
|
}, [forecastingService, fetchModels]);
|
|
|
|
// Delete forecast model
|
|
const deleteModel = useCallback(async (id: string): Promise<boolean> => {
|
|
setState(prev => ({ ...prev, error: null }));
|
|
|
|
try {
|
|
const response = await forecastingService.deleteModel(id);
|
|
|
|
if (response.success) {
|
|
setState(prev => ({
|
|
...prev,
|
|
models: prev.models.filter(model => model.id !== id),
|
|
}));
|
|
return true;
|
|
} else {
|
|
setState(prev => ({
|
|
...prev,
|
|
error: response.error || 'Error al eliminar modelo de predicción',
|
|
}));
|
|
return false;
|
|
}
|
|
} catch (error) {
|
|
setState(prev => ({
|
|
...prev,
|
|
error: 'Error de conexión al servidor',
|
|
}));
|
|
return false;
|
|
}
|
|
}, [forecastingService]);
|
|
|
|
// Get single forecast model
|
|
const getModel = useCallback(async (id: string): Promise<ForecastModel | null> => {
|
|
try {
|
|
const response = await forecastingService.getModel(id);
|
|
return response.success ? response.data : null;
|
|
} catch (error) {
|
|
console.error('Error fetching model:', error);
|
|
return null;
|
|
}
|
|
}, [forecastingService]);
|
|
|
|
// Train forecast model
|
|
const trainModel = useCallback(async (id: string, parameters?: any): Promise<boolean> => {
|
|
setState(prev => ({ ...prev, error: null }));
|
|
|
|
try {
|
|
const response = await forecastingService.trainModel(id, parameters);
|
|
|
|
if (response.success) {
|
|
await fetchModels();
|
|
return true;
|
|
} else {
|
|
setState(prev => ({
|
|
...prev,
|
|
error: response.error || 'Error al entrenar modelo',
|
|
}));
|
|
return false;
|
|
}
|
|
} catch (error) {
|
|
setState(prev => ({
|
|
...prev,
|
|
error: 'Error de conexión al servidor',
|
|
}));
|
|
return false;
|
|
}
|
|
}, [forecastingService, fetchModels]);
|
|
|
|
// Deploy forecast model
|
|
const deployModel = useCallback(async (id: string): Promise<boolean> => {
|
|
setState(prev => ({ ...prev, error: null }));
|
|
|
|
try {
|
|
const response = await forecastingService.deployModel(id);
|
|
|
|
if (response.success) {
|
|
await fetchModels();
|
|
return true;
|
|
} else {
|
|
setState(prev => ({
|
|
...prev,
|
|
error: response.error || 'Error al desplegar modelo',
|
|
}));
|
|
return false;
|
|
}
|
|
} catch (error) {
|
|
setState(prev => ({
|
|
...prev,
|
|
error: 'Error de conexión al servidor',
|
|
}));
|
|
return false;
|
|
}
|
|
}, [forecastingService, fetchModels]);
|
|
|
|
// Fetch predictions
|
|
const fetchPredictions = useCallback(async (params?: QueryParams) => {
|
|
setState(prev => ({ ...prev, isLoading: true, error: null }));
|
|
|
|
try {
|
|
const response = await forecastingService.getPredictions(params);
|
|
|
|
if (response.success && response.data) {
|
|
setState(prev => ({
|
|
...prev,
|
|
predictions: Array.isArray(response.data) ? response.data : response.data.items || [],
|
|
isLoading: false,
|
|
}));
|
|
} else {
|
|
setState(prev => ({
|
|
...prev,
|
|
isLoading: false,
|
|
error: response.error || 'Error al cargar predicciones',
|
|
}));
|
|
}
|
|
} catch (error) {
|
|
setState(prev => ({
|
|
...prev,
|
|
isLoading: false,
|
|
error: 'Error de conexión al servidor',
|
|
}));
|
|
}
|
|
}, [forecastingService]);
|
|
|
|
// Create prediction
|
|
const createPrediction = useCallback(async (data: ForecastPredictionCreate): Promise<boolean> => {
|
|
setState(prev => ({ ...prev, error: null }));
|
|
|
|
try {
|
|
const response = await forecastingService.createPrediction(data);
|
|
|
|
if (response.success) {
|
|
await fetchPredictions();
|
|
return true;
|
|
} else {
|
|
setState(prev => ({
|
|
...prev,
|
|
error: response.error || 'Error al crear predicción',
|
|
}));
|
|
return false;
|
|
}
|
|
} catch (error) {
|
|
setState(prev => ({
|
|
...prev,
|
|
error: 'Error de conexión al servidor',
|
|
}));
|
|
return false;
|
|
}
|
|
}, [forecastingService, fetchPredictions]);
|
|
|
|
// Get single prediction
|
|
const getPrediction = useCallback(async (id: string): Promise<ForecastPrediction | null> => {
|
|
try {
|
|
const response = await forecastingService.getPrediction(id);
|
|
return response.success ? response.data : null;
|
|
} catch (error) {
|
|
console.error('Error fetching prediction:', error);
|
|
return null;
|
|
}
|
|
}, [forecastingService]);
|
|
|
|
// Generate demand forecast
|
|
const generateDemandForecast = useCallback(async (modelId: string, horizon: number, parameters?: any) => {
|
|
try {
|
|
const response = await forecastingService.generateDemandForecast(modelId, horizon, parameters);
|
|
return response.success ? response.data : null;
|
|
} catch (error) {
|
|
console.error('Error generating demand forecast:', error);
|
|
return null;
|
|
}
|
|
}, [forecastingService]);
|
|
|
|
// Fetch batch predictions
|
|
const fetchBatches = useCallback(async (params?: QueryParams) => {
|
|
try {
|
|
const response = await forecastingService.getBatches(params);
|
|
|
|
if (response.success && response.data) {
|
|
setState(prev => ({
|
|
...prev,
|
|
batches: Array.isArray(response.data) ? response.data : response.data.items || [],
|
|
}));
|
|
}
|
|
} catch (error) {
|
|
console.error('Error fetching batches:', error);
|
|
}
|
|
}, [forecastingService]);
|
|
|
|
// Create batch prediction
|
|
const createBatch = useCallback(async (modelId: string, data: any): Promise<boolean> => {
|
|
try {
|
|
const response = await forecastingService.createBatch(modelId, data);
|
|
|
|
if (response.success) {
|
|
await fetchBatches();
|
|
return true;
|
|
}
|
|
return false;
|
|
} catch (error) {
|
|
console.error('Error creating batch:', error);
|
|
return false;
|
|
}
|
|
}, [forecastingService, fetchBatches]);
|
|
|
|
// Get single batch
|
|
const getBatch = useCallback(async (id: string): Promise<ForecastBatch | null> => {
|
|
try {
|
|
const response = await forecastingService.getBatch(id);
|
|
return response.success ? response.data : null;
|
|
} catch (error) {
|
|
console.error('Error fetching batch:', error);
|
|
return null;
|
|
}
|
|
}, [forecastingService]);
|
|
|
|
// Download batch results
|
|
const downloadBatchResults = useCallback(async (id: string): Promise<boolean> => {
|
|
try {
|
|
const response = await forecastingService.downloadBatchResults(id);
|
|
return response.success;
|
|
} catch (error) {
|
|
console.error('Error downloading batch results:', error);
|
|
return false;
|
|
}
|
|
}, [forecastingService]);
|
|
|
|
// Fetch model trainings
|
|
const fetchTrainings = useCallback(async (modelId?: string) => {
|
|
try {
|
|
const response = await forecastingService.getTrainings(modelId);
|
|
|
|
if (response.success && response.data) {
|
|
setState(prev => ({
|
|
...prev,
|
|
trainings: Array.isArray(response.data) ? response.data : response.data.items || [],
|
|
}));
|
|
}
|
|
} catch (error) {
|
|
console.error('Error fetching trainings:', error);
|
|
}
|
|
}, [forecastingService]);
|
|
|
|
// Get single training
|
|
const getTraining = useCallback(async (id: string): Promise<ModelTraining | null> => {
|
|
try {
|
|
const response = await forecastingService.getTraining(id);
|
|
return response.success ? response.data : null;
|
|
} catch (error) {
|
|
console.error('Error fetching training:', error);
|
|
return null;
|
|
}
|
|
}, [forecastingService]);
|
|
|
|
// Cancel model training
|
|
const cancelTraining = useCallback(async (id: string): Promise<boolean> => {
|
|
try {
|
|
const response = await forecastingService.cancelTraining(id);
|
|
|
|
if (response.success) {
|
|
await fetchTrainings();
|
|
return true;
|
|
}
|
|
return false;
|
|
} catch (error) {
|
|
console.error('Error canceling training:', error);
|
|
return false;
|
|
}
|
|
}, [forecastingService, fetchTrainings]);
|
|
|
|
// Fetch model evaluations
|
|
const fetchEvaluations = useCallback(async (modelId?: string) => {
|
|
try {
|
|
const response = await forecastingService.getEvaluations(modelId);
|
|
|
|
if (response.success && response.data) {
|
|
setState(prev => ({
|
|
...prev,
|
|
evaluations: Array.isArray(response.data) ? response.data : response.data.items || [],
|
|
}));
|
|
}
|
|
} catch (error) {
|
|
console.error('Error fetching evaluations:', error);
|
|
}
|
|
}, [forecastingService]);
|
|
|
|
// Create model evaluation
|
|
const createEvaluation = useCallback(async (modelId: string, testData: any): Promise<boolean> => {
|
|
try {
|
|
const response = await forecastingService.createEvaluation(modelId, testData);
|
|
|
|
if (response.success) {
|
|
await fetchEvaluations(modelId);
|
|
return true;
|
|
}
|
|
return false;
|
|
} catch (error) {
|
|
console.error('Error creating evaluation:', error);
|
|
return false;
|
|
}
|
|
}, [forecastingService, fetchEvaluations]);
|
|
|
|
// Get single evaluation
|
|
const getEvaluation = useCallback(async (id: string): Promise<ModelEvaluation | null> => {
|
|
try {
|
|
const response = await forecastingService.getEvaluation(id);
|
|
return response.success ? response.data : null;
|
|
} catch (error) {
|
|
console.error('Error fetching evaluation:', error);
|
|
return null;
|
|
}
|
|
}, [forecastingService]);
|
|
|
|
// Get model performance
|
|
const getModelPerformance = useCallback(async (modelId: string, period?: string) => {
|
|
try {
|
|
const response = await forecastingService.getModelPerformance(modelId, period);
|
|
return response.success ? response.data : null;
|
|
} catch (error) {
|
|
console.error('Error fetching model performance:', error);
|
|
return null;
|
|
}
|
|
}, [forecastingService]);
|
|
|
|
// Get accuracy report
|
|
const getAccuracyReport = useCallback(async (modelId: string, startDate?: string, endDate?: string) => {
|
|
try {
|
|
const response = await forecastingService.getAccuracyReport(modelId, startDate, endDate);
|
|
return response.success ? response.data : null;
|
|
} catch (error) {
|
|
console.error('Error fetching accuracy report:', error);
|
|
return null;
|
|
}
|
|
}, [forecastingService]);
|
|
|
|
// Get feature importance
|
|
const getFeatureImportance = useCallback(async (modelId: string) => {
|
|
try {
|
|
const response = await forecastingService.getFeatureImportance(modelId);
|
|
return response.success ? response.data : null;
|
|
} catch (error) {
|
|
console.error('Error fetching feature importance:', error);
|
|
return null;
|
|
}
|
|
}, [forecastingService]);
|
|
|
|
// Clear error
|
|
const clearError = useCallback(() => {
|
|
setState(prev => ({ ...prev, error: null }));
|
|
}, []);
|
|
|
|
// Refresh all data
|
|
const refresh = useCallback(async () => {
|
|
await Promise.all([
|
|
fetchModels(),
|
|
fetchPredictions(),
|
|
fetchBatches(),
|
|
]);
|
|
}, [fetchModels, fetchPredictions, fetchBatches]);
|
|
|
|
// Initialize data on mount
|
|
useEffect(() => {
|
|
refresh();
|
|
}, []);
|
|
|
|
return {
|
|
...state,
|
|
fetchModels,
|
|
createModel,
|
|
updateModel,
|
|
deleteModel,
|
|
getModel,
|
|
trainModel,
|
|
deployModel,
|
|
fetchPredictions,
|
|
createPrediction,
|
|
getPrediction,
|
|
generateDemandForecast,
|
|
fetchBatches,
|
|
createBatch,
|
|
getBatch,
|
|
downloadBatchResults,
|
|
fetchTrainings,
|
|
getTraining,
|
|
cancelTraining,
|
|
fetchEvaluations,
|
|
createEvaluation,
|
|
getEvaluation,
|
|
getModelPerformance,
|
|
getAccuracyReport,
|
|
getFeatureImportance,
|
|
clearError,
|
|
refresh,
|
|
};
|
|
}; |