[ [ 'model_name' => 'fraud-detector', 'type' => 'supervised', 'versions' => [ [ 'version' => '1.0.0', 'created_at' => '2024-01-01T00:00:00Z', 'is_latest' => true, ], ], ], ], 'total_models' => 5, ], )] public function listModels(HttpRequest $request): JsonResult { $typeFilter = $request->query->get('type'); // Get all model names $modelNames = $this->registry->getAllModelNames(); // Get all versions for each model $allModels = []; foreach ($modelNames as $modelName) { $versions = $this->registry->getAll($modelName); $allModels = array_merge($allModels, $versions); } // Filter by type if specified if ($typeFilter !== null) { $allModels = array_filter($allModels, function (ModelMetadata $metadata) use ($typeFilter) { return strtolower($metadata->modelType->value) === strtolower($typeFilter); }); } // Group by model name $groupedModels = []; foreach ($allModels as $metadata) { $modelName = $metadata->modelName; if (!isset($groupedModels[$modelName])) { $groupedModels[$modelName] = [ 'model_name' => $modelName, 'type' => $metadata->modelType->value, 'versions' => [], ]; } $groupedModels[$modelName]['versions'][] = [ 'version' => $metadata->version->toString(), 'created_at' => $metadata->createdAt->format('Y-m-d\TH:i:s\Z'), 'configuration' => $metadata->configuration, ]; } return new JsonResult([ 'models' => array_values($groupedModels), 'total_models' => count($groupedModels), ]); } #[Route(path: '/api/ml/models/{modelName}', method: Method::GET)] #[ApiEndpoint( summary: 'Get model details', description: 'Retrieve detailed information about a specific ML model', tags: ['Machine Learning'], )] #[ApiParameter( name: 'modelName', in: 'path', description: 'Model identifier', required: true, type: 'string', example: 'fraud-detector', )] #[ApiParameter( name: 'version', in: 'query', description: 'Specific version (optional, defaults to latest)', required: false, type: 'string', example: '1.0.0', )] #[ApiResponse( statusCode: 200, description: 'Model details retrieved successfully', example: [ 'model_name' => 'fraud-detector', 'type' => 'supervised', 'version' => '1.0.0', 'configuration' => [ 'threshold' => 0.7, 'algorithm' => 'random_forest', ], 'created_at' => '2024-01-01T00:00:00Z', ], )] #[ApiResponse( statusCode: 404, description: 'Model not found', )] public function getModel(string $modelName, HttpRequest $request): JsonResult { $versionString = $request->query->get('version'); try { if ($versionString !== null) { $version = Version::fromString($versionString); $metadata = $this->registry->get($modelName, $version); } else { $metadata = $this->registry->getLatest($modelName); } if ($metadata === null) { return new JsonResult([ 'error' => 'Model not found', 'model_name' => $modelName, ], Status::NOT_FOUND); } return new JsonResult([ 'model_name' => $metadata->modelName, 'type' => $metadata->modelType->value, 'version' => $metadata->version->toString(), 'configuration' => $metadata->configuration, 'performance_metrics' => $metadata->performanceMetrics, 'created_at' => $metadata->createdAt->format('Y-m-d\TH:i:s\Z'), ]); } catch (\InvalidArgumentException $e) { return new JsonResult([ 'error' => 'Invalid version format', 'message' => $e->getMessage(), ], Status::BAD_REQUEST); } } #[Route(path: '/api/ml/models/{modelName}/metrics', method: Method::GET)] #[ApiEndpoint( summary: 'Get model performance metrics', description: 'Retrieve real-time performance metrics for a specific model', tags: ['Machine Learning'], )] #[ApiParameter( name: 'modelName', in: 'path', description: 'Model identifier', required: true, type: 'string', example: 'fraud-detector', )] #[ApiParameter( name: 'version', in: 'query', description: 'Model version', required: false, type: 'string', example: '1.0.0', )] #[ApiParameter( name: 'timeWindow', in: 'query', description: 'Time window in hours (default: 1)', required: false, type: 'integer', example: 24, )] #[ApiResponse( statusCode: 200, description: 'Performance metrics retrieved successfully', example: [ 'model_name' => 'fraud-detector', 'version' => '1.0.0', 'time_window_hours' => 24, 'metrics' => [ 'accuracy' => 0.92, 'precision' => 0.89, 'recall' => 0.94, 'f1_score' => 0.91, 'total_predictions' => 1523, 'average_confidence' => 0.85, ], 'confusion_matrix' => [ 'true_positive' => 1234, 'true_negative' => 156, 'false_positive' => 89, 'false_negative' => 44, ], ], )] #[ApiResponse( statusCode: 404, description: 'Model not found', )] public function getMetrics(string $modelName, HttpRequest $request): JsonResult { $versionString = $request->query->get('version'); $timeWindowHours = $request->query->getInt('timeWindow', 1); try { if ($versionString !== null) { $version = Version::fromString($versionString); } else { $metadata = $this->registry->getLatest($modelName); if ($metadata === null) { return new JsonResult([ 'error' => 'Model not found', 'model_name' => $modelName, ], Status::NOT_FOUND); } $version = $metadata->version; } $timeWindow = Duration::fromHours($timeWindowHours); $metrics = $this->performanceMonitor->getCurrentMetrics( $modelName, $version, $timeWindow ); return new JsonResult([ 'model_name' => $modelName, 'version' => $version->toString(), 'time_window_hours' => $timeWindowHours, 'metrics' => [ 'accuracy' => $metrics['accuracy'], 'precision' => $metrics['precision'] ?? null, 'recall' => $metrics['recall'] ?? null, 'f1_score' => $metrics['f1_score'] ?? null, 'total_predictions' => $metrics['total_predictions'], 'average_confidence' => $metrics['average_confidence'] ?? null, ], 'confusion_matrix' => $metrics['confusion_matrix'] ?? null, 'timestamp' => date('c'), ]); } catch (\InvalidArgumentException $e) { return new JsonResult([ 'error' => 'Invalid parameters', 'message' => $e->getMessage(), ], Status::BAD_REQUEST); } } #[Route(path: '/api/ml/models', method: Method::POST)] #[ApiEndpoint( summary: 'Register a new ML model', description: 'Register a new machine learning model or version in the system', tags: ['Machine Learning'], )] #[ApiRequestBody( description: 'Model metadata for registration', required: true, example: [ 'model_name' => 'fraud-detector', 'type' => 'supervised', 'version' => '2.0.0', 'configuration' => [ 'threshold' => 0.75, 'algorithm' => 'xgboost', 'features' => 30, ], 'performance_metrics' => [ 'accuracy' => 0.94, 'precision' => 0.91, 'recall' => 0.96, ], ], )] #[ApiResponse( statusCode: 201, description: 'Model registered successfully', example: [ 'model_name' => 'fraud-detector', 'version' => '2.0.0', 'created_at' => '2024-01-01T00:00:00Z', 'message' => 'Model registered successfully', ], )] #[ApiResponse( statusCode: 400, description: 'Invalid model data', )] #[ApiResponse( statusCode: 409, description: 'Model version already exists', )] public function registerModel(HttpRequest $request): JsonResult { try { $data = $request->parsedBody->toArray(); // Validate required fields if (!isset($data['model_name'], $data['type'], $data['version'])) { return new JsonResult([ 'error' => 'Missing required fields', 'required' => ['model_name', 'type', 'version'], ], Status::BAD_REQUEST); } // Parse model type $modelType = match (strtolower($data['type'])) { 'supervised' => ModelType::SUPERVISED, 'unsupervised' => ModelType::UNSUPERVISED, 'reinforcement' => ModelType::REINFORCEMENT, default => throw new \InvalidArgumentException("Invalid model type: {$data['type']}") }; // Create metadata $metadata = new ModelMetadata( modelName: $data['model_name'], modelType: $modelType, version: Version::fromString($data['version']), configuration: $data['configuration'] ?? [], createdAt: Timestamp::now(), performanceMetrics: $data['performance_metrics'] ?? [] ); // Check if already exists $existing = $this->registry->get($metadata->modelName, $metadata->version); if ($existing !== null) { return new JsonResult([ 'error' => 'Model version already exists', 'model_name' => $metadata->modelName, 'version' => $metadata->version->toString(), ], Status::CONFLICT); } // Register model $this->registry->register($metadata); return new JsonResult([ 'model_name' => $metadata->modelName, 'version' => $metadata->version->toString(), 'type' => $metadata->modelType->value, 'created_at' => $metadata->createdAt->format('Y-m-d\TH:i:s\Z'), 'message' => 'Model registered successfully', ], Status::CREATED); } catch (\InvalidArgumentException $e) { return new JsonResult([ 'error' => 'Invalid model data', 'message' => $e->getMessage(), ], Status::BAD_REQUEST); } catch (\Throwable $e) { return new JsonResult([ 'error' => 'Failed to register model', 'message' => $e->getMessage(), ], Status::INTERNAL_SERVER_ERROR); } } #[Route(path: '/api/ml/models/{modelName}', method: Method::DELETE)] #[ApiEndpoint( summary: 'Unregister ML model', description: 'Remove a specific version of an ML model from the registry', tags: ['Machine Learning'], )] #[ApiParameter( name: 'modelName', in: 'path', description: 'Model identifier', required: true, type: 'string', example: 'fraud-detector', )] #[ApiParameter( name: 'version', in: 'query', description: 'Model version to unregister', required: true, type: 'string', example: '1.0.0', )] #[ApiResponse( statusCode: 200, description: 'Model unregistered successfully', )] #[ApiResponse( statusCode: 404, description: 'Model not found', )] public function unregisterModel(string $modelName, HttpRequest $request): JsonResult { $versionString = $request->query->get('version'); if ($versionString === null) { return new JsonResult([ 'error' => 'Version parameter is required', ], Status::BAD_REQUEST); } try { $version = Version::fromString($versionString); // Check if model exists $metadata = $this->registry->get($modelName, $version); if ($metadata === null) { return new JsonResult([ 'error' => 'Model not found', 'model_name' => $modelName, 'version' => $versionString, ], Status::NOT_FOUND); } // Unregister $this->registry->unregister($modelName, $version); return new JsonResult([ 'message' => 'Model unregistered successfully', 'model_name' => $modelName, 'version' => $versionString, ]); } catch (\InvalidArgumentException $e) { return new JsonResult([ 'error' => 'Invalid version format', 'message' => $e->getMessage(), ], Status::BAD_REQUEST); } } }