api-mocker 0.3.0__py3-none-any.whl → 0.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,709 @@
1
+ """
2
+ Machine Learning Integration System
3
+
4
+ This module provides comprehensive ML capabilities for API mocking including:
5
+ - Intelligent response generation using ML models
6
+ - Request pattern analysis and prediction
7
+ - Anomaly detection for API behavior
8
+ - Smart caching based on usage patterns
9
+ - Automated test case generation
10
+ - Performance optimization recommendations
11
+ """
12
+
13
+ import json
14
+ import numpy as np
15
+ import pandas as pd
16
+ from typing import Any, Dict, List, Optional, Union, Tuple, Callable
17
+ from dataclasses import dataclass, field
18
+ from enum import Enum
19
+ from datetime import datetime, timedelta
20
+ import pickle
21
+ import joblib
22
+ from sklearn.ensemble import RandomForestClassifier, IsolationForest
23
+ from sklearn.cluster import KMeans, DBSCAN
24
+ from sklearn.preprocessing import StandardScaler, LabelEncoder
25
+ from sklearn.model_selection import train_test_split
26
+ from sklearn.metrics import accuracy_score, classification_report
27
+ from sklearn.feature_extraction.text import TfidfVectorizer
28
+ from sklearn.linear_model import LinearRegression
29
+ from sklearn.neural_network import MLPClassifier
30
+ import asyncio
31
+ import threading
32
+ from collections import defaultdict, deque
33
+ import hashlib
34
+
35
+
36
+ class MLModelType(Enum):
37
+ """ML model types"""
38
+ CLASSIFICATION = "classification"
39
+ REGRESSION = "regression"
40
+ CLUSTERING = "clustering"
41
+ ANOMALY_DETECTION = "anomaly_detection"
42
+ TEXT_ANALYSIS = "text_analysis"
43
+ RECOMMENDATION = "recommendation"
44
+
45
+
46
+ class PredictionType(Enum):
47
+ """Prediction types"""
48
+ RESPONSE_TIME = "response_time"
49
+ ERROR_PROBABILITY = "error_probability"
50
+ USER_BEHAVIOR = "user_behavior"
51
+ CACHE_HIT = "cache_hit"
52
+ RESOURCE_USAGE = "resource_usage"
53
+ ANOMALY_SCORE = "anomaly_score"
54
+
55
+
56
+ @dataclass
57
+ class MLModel:
58
+ """ML model representation"""
59
+ name: str
60
+ model_type: MLModelType
61
+ model: Any
62
+ features: List[str]
63
+ target: str
64
+ accuracy: float = 0.0
65
+ created_at: datetime = field(default_factory=datetime.now)
66
+ last_trained: datetime = field(default_factory=datetime.now)
67
+ training_samples: int = 0
68
+ metadata: Dict[str, Any] = field(default_factory=dict)
69
+
70
+
71
+ @dataclass
72
+ class PredictionRequest:
73
+ """Prediction request"""
74
+ features: Dict[str, Any]
75
+ model_name: str
76
+ prediction_type: PredictionType
77
+ confidence_threshold: float = 0.5
78
+
79
+
80
+ @dataclass
81
+ class PredictionResult:
82
+ """Prediction result"""
83
+ prediction: Any
84
+ confidence: float
85
+ model_name: str
86
+ features_used: List[str]
87
+ timestamp: datetime = field(default_factory=datetime.now)
88
+ metadata: Dict[str, Any] = field(default_factory=dict)
89
+
90
+
91
+ @dataclass
92
+ class TrainingData:
93
+ """Training data for ML models"""
94
+ features: List[Dict[str, Any]]
95
+ targets: List[Any]
96
+ feature_names: List[str]
97
+ target_name: str
98
+ created_at: datetime = field(default_factory=datetime.now)
99
+
100
+
101
+ class FeatureExtractor:
102
+ """Feature extraction for ML models"""
103
+
104
+ def __init__(self):
105
+ self.text_vectorizer = TfidfVectorizer(max_features=1000, stop_words='english')
106
+ self.label_encoders: Dict[str, LabelEncoder] = {}
107
+ self.scaler = StandardScaler()
108
+
109
+ def extract_request_features(self, request_data: Dict[str, Any]) -> Dict[str, Any]:
110
+ """Extract features from API request data"""
111
+ features = {}
112
+
113
+ # Basic features
114
+ features['method_encoded'] = self._encode_categorical(request_data.get('method', ''), 'method')
115
+ features['path_length'] = len(request_data.get('path', ''))
116
+ features['has_query_params'] = 1 if '?' in request_data.get('path', '') else 0
117
+ features['has_path_params'] = 1 if '{' in request_data.get('path', '') else 0
118
+
119
+ # Header features
120
+ headers = request_data.get('headers', {})
121
+ features['header_count'] = len(headers)
122
+ features['has_auth_header'] = 1 if 'authorization' in headers else 0
123
+ features['has_content_type'] = 1 if 'content-type' in headers else 0
124
+
125
+ # Body features
126
+ body = request_data.get('body', '')
127
+ if isinstance(body, str):
128
+ features['body_length'] = len(body)
129
+ features['is_json'] = 1 if body.startswith('{') or body.startswith('[') else 0
130
+ else:
131
+ features['body_length'] = 0
132
+ features['is_json'] = 0
133
+
134
+ # Time-based features
135
+ now = datetime.now()
136
+ features['hour_of_day'] = now.hour
137
+ features['day_of_week'] = now.weekday()
138
+ features['is_weekend'] = 1 if now.weekday() >= 5 else 0
139
+
140
+ return features
141
+
142
+ def extract_response_features(self, response_data: Dict[str, Any]) -> Dict[str, Any]:
143
+ """Extract features from API response data"""
144
+ features = {}
145
+
146
+ features['status_code'] = response_data.get('status_code', 200)
147
+ features['is_success'] = 1 if 200 <= features['status_code'] < 300 else 0
148
+ features['is_client_error'] = 1 if 400 <= features['status_code'] < 500 else 0
149
+ features['is_server_error'] = 1 if 500 <= features['status_code'] < 600 else 0
150
+
151
+ # Response body features
152
+ body = response_data.get('body', '')
153
+ if isinstance(body, str):
154
+ features['response_length'] = len(body)
155
+ else:
156
+ features['response_length'] = 0
157
+
158
+ # Header features
159
+ headers = response_data.get('headers', {})
160
+ features['response_header_count'] = len(headers)
161
+ features['has_cache_header'] = 1 if 'cache-control' in headers else 0
162
+
163
+ return features
164
+
165
+ def _encode_categorical(self, value: str, field_name: str) -> int:
166
+ """Encode categorical values"""
167
+ if field_name not in self.label_encoders:
168
+ self.label_encoders[field_name] = LabelEncoder()
169
+ # Fit with known values
170
+ known_values = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS']
171
+ self.label_encoders[field_name].fit(known_values)
172
+
173
+ try:
174
+ return self.label_encoders[field_name].transform([value])[0]
175
+ except ValueError:
176
+ return 0 # Unknown value
177
+
178
+
179
+ class MLModelManager:
180
+ """ML model management system"""
181
+
182
+ def __init__(self):
183
+ self.models: Dict[str, MLModel] = {}
184
+ self.feature_extractor = FeatureExtractor()
185
+ self.training_data: Dict[str, List[Dict[str, Any]]] = defaultdict(list)
186
+ self.model_lock = threading.Lock()
187
+
188
+ def add_model(self, model: MLModel) -> None:
189
+ """Add a model to the manager"""
190
+ with self.model_lock:
191
+ self.models[model.name] = model
192
+
193
+ def get_model(self, name: str) -> Optional[MLModel]:
194
+ """Get a model by name"""
195
+ return self.models.get(name)
196
+
197
+ def train_model(self, model_name: str, training_data: TrainingData) -> Dict[str, Any]:
198
+ """Train a model with provided data"""
199
+ if model_name not in self.models:
200
+ return {"success": False, "error": "Model not found"}
201
+
202
+ model = self.models[model_name]
203
+
204
+ try:
205
+ # Prepare features and targets
206
+ X = []
207
+ y = []
208
+
209
+ for i, features in enumerate(training_data.features):
210
+ X.append(list(features.values()))
211
+ y.append(training_data.targets[i])
212
+
213
+ X = np.array(X)
214
+ y = np.array(y)
215
+
216
+ # Split data
217
+ X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
218
+
219
+ # Scale features
220
+ X_train_scaled = self.feature_extractor.scaler.fit_transform(X_train)
221
+ X_test_scaled = self.feature_extractor.scaler.transform(X_test)
222
+
223
+ # Train model
224
+ model.model.fit(X_train_scaled, y_train)
225
+
226
+ # Evaluate
227
+ y_pred = model.model.predict(X_test_scaled)
228
+ accuracy = accuracy_score(y_test, y_pred)
229
+
230
+ # Update model
231
+ model.accuracy = accuracy
232
+ model.last_trained = datetime.now()
233
+ model.training_samples = len(training_data.features)
234
+
235
+ return {
236
+ "success": True,
237
+ "accuracy": accuracy,
238
+ "training_samples": len(training_data.features),
239
+ "test_samples": len(X_test)
240
+ }
241
+
242
+ except Exception as e:
243
+ return {"success": False, "error": str(e)}
244
+
245
+ def predict(self, request: PredictionRequest) -> PredictionResult:
246
+ """Make a prediction using a model"""
247
+ if request.model_name not in self.models:
248
+ return PredictionResult(
249
+ prediction=None,
250
+ confidence=0.0,
251
+ model_name=request.model_name,
252
+ features_used=[],
253
+ metadata={"error": "Model not found"}
254
+ )
255
+
256
+ model = self.models[request.model_name]
257
+
258
+ try:
259
+ # Extract features
260
+ features = self.feature_extractor.extract_request_features(request.features)
261
+ feature_values = [features.get(f, 0) for f in model.features]
262
+
263
+ # Scale features
264
+ feature_array = np.array(feature_values).reshape(1, -1)
265
+ scaled_features = self.feature_extractor.scaler.transform(feature_array)
266
+
267
+ # Make prediction
268
+ if model.model_type == MLModelType.CLASSIFICATION:
269
+ prediction = model.model.predict(scaled_features)[0]
270
+ confidence = model.model.predict_proba(scaled_features).max()
271
+ else:
272
+ prediction = model.model.predict(scaled_features)[0]
273
+ confidence = 1.0 # For regression, we don't have confidence scores
274
+
275
+ return PredictionResult(
276
+ prediction=prediction,
277
+ confidence=confidence,
278
+ model_name=request.model_name,
279
+ features_used=model.features,
280
+ metadata={"model_accuracy": model.accuracy}
281
+ )
282
+
283
+ except Exception as e:
284
+ return PredictionResult(
285
+ prediction=None,
286
+ confidence=0.0,
287
+ model_name=request.model_name,
288
+ features_used=[],
289
+ metadata={"error": str(e)}
290
+ )
291
+
292
+ def save_model(self, model_name: str, filepath: str) -> bool:
293
+ """Save a model to disk"""
294
+ if model_name not in self.models:
295
+ return False
296
+
297
+ try:
298
+ model = self.models[model_name]
299
+ model_data = {
300
+ "name": model.name,
301
+ "model_type": model.model_type.value,
302
+ "features": model.features,
303
+ "target": model.target,
304
+ "accuracy": model.accuracy,
305
+ "created_at": model.created_at.isoformat(),
306
+ "last_trained": model.last_trained.isoformat(),
307
+ "training_samples": model.training_samples,
308
+ "metadata": model.metadata
309
+ }
310
+
311
+ # Save model and metadata
312
+ joblib.dump(model.model, f"{filepath}_model.pkl")
313
+ with open(f"{filepath}_metadata.json", 'w') as f:
314
+ json.dump(model_data, f, indent=2)
315
+
316
+ return True
317
+ except Exception as e:
318
+ print(f"Error saving model: {e}")
319
+ return False
320
+
321
+ def load_model(self, model_name: str, filepath: str) -> bool:
322
+ """Load a model from disk"""
323
+ try:
324
+ # Load metadata
325
+ with open(f"{filepath}_metadata.json", 'r') as f:
326
+ model_data = json.load(f)
327
+
328
+ # Load model
329
+ model_obj = joblib.load(f"{filepath}_model.pkl")
330
+
331
+ # Create model
332
+ model = MLModel(
333
+ name=model_data["name"],
334
+ model_type=MLModelType(model_data["model_type"]),
335
+ model=model_obj,
336
+ features=model_data["features"],
337
+ target=model_data["target"],
338
+ accuracy=model_data["accuracy"],
339
+ created_at=datetime.fromisoformat(model_data["created_at"]),
340
+ last_trained=datetime.fromisoformat(model_data["last_trained"]),
341
+ training_samples=model_data["training_samples"],
342
+ metadata=model_data["metadata"]
343
+ )
344
+
345
+ self.add_model(model)
346
+ return True
347
+
348
+ except Exception as e:
349
+ print(f"Error loading model: {e}")
350
+ return False
351
+
352
+
353
+ class AnomalyDetector:
354
+ """Anomaly detection system"""
355
+
356
+ def __init__(self):
357
+ self.isolation_forest = IsolationForest(contamination=0.1, random_state=42)
358
+ self.is_fitted = False
359
+ self.feature_extractor = FeatureExtractor()
360
+
361
+ def fit(self, normal_data: List[Dict[str, Any]]) -> None:
362
+ """Fit the anomaly detector with normal data"""
363
+ features = []
364
+ for data in normal_data:
365
+ features.append(list(self.feature_extractor.extract_request_features(data).values()))
366
+
367
+ X = np.array(features)
368
+ self.isolation_forest.fit(X)
369
+ self.is_fitted = True
370
+
371
+ def detect_anomaly(self, request_data: Dict[str, Any]) -> Dict[str, Any]:
372
+ """Detect if request is anomalous"""
373
+ if not self.is_fitted:
374
+ return {"is_anomaly": False, "score": 0.0, "message": "Model not fitted"}
375
+
376
+ features = self.feature_extractor.extract_request_features(request_data)
377
+ feature_values = list(features.values())
378
+ X = np.array(feature_values).reshape(1, -1)
379
+
380
+ anomaly_score = self.isolation_forest.decision_function(X)[0]
381
+ is_anomaly = self.isolation_forest.predict(X)[0] == -1
382
+
383
+ return {
384
+ "is_anomaly": bool(is_anomaly),
385
+ "score": float(anomaly_score),
386
+ "confidence": abs(anomaly_score),
387
+ "features": features
388
+ }
389
+
390
+
391
+ class SmartCache:
392
+ """ML-powered smart caching system"""
393
+
394
+ def __init__(self, max_size: int = 1000):
395
+ self.cache: Dict[str, Any] = {}
396
+ self.access_times: Dict[str, datetime] = {}
397
+ self.access_counts: Dict[str, int] = defaultdict(int)
398
+ self.max_size = max_size
399
+ self.ml_manager = MLModelManager()
400
+ self._setup_cache_model()
401
+
402
+ def _setup_cache_model(self) -> None:
403
+ """Setup ML model for cache prediction"""
404
+ # Create a simple model to predict cache hit probability
405
+ model = MLModel(
406
+ name="cache_predictor",
407
+ model_type=MLModelType.CLASSIFICATION,
408
+ model=RandomForestClassifier(n_estimators=100, random_state=42),
409
+ features=['path_length', 'has_query_params', 'hour_of_day', 'day_of_week'],
410
+ target="cache_hit"
411
+ )
412
+ self.ml_manager.add_model(model)
413
+
414
+ def get(self, key: str) -> Optional[Any]:
415
+ """Get value from cache"""
416
+ if key in self.cache:
417
+ self.access_times[key] = datetime.now()
418
+ self.access_counts[key] += 1
419
+ return self.cache[key]
420
+ return None
421
+
422
+ def set(self, key: str, value: Any, ttl: int = None) -> None:
423
+ """Set value in cache"""
424
+ if len(self.cache) >= self.max_size:
425
+ self._evict_least_used()
426
+
427
+ self.cache[key] = value
428
+ self.access_times[key] = datetime.now()
429
+ self.access_counts[key] = 0
430
+
431
+ def predict_cache_hit(self, request_data: Dict[str, Any]) -> float:
432
+ """Predict cache hit probability for a request"""
433
+ features = self.ml_manager.feature_extractor.extract_request_features(request_data)
434
+
435
+ # Use only features available in the model
436
+ model_features = {k: features.get(k, 0) for k in self.ml_manager.get_model("cache_predictor").features}
437
+
438
+ request = PredictionRequest(
439
+ features=model_features,
440
+ model_name="cache_predictor",
441
+ prediction_type=PredictionType.CACHE_HIT
442
+ )
443
+
444
+ result = self.ml_manager.predict(request)
445
+ return result.confidence if result.prediction else 0.0
446
+
447
+ def _evict_least_used(self) -> None:
448
+ """Evict least used items from cache"""
449
+ if not self.cache:
450
+ return
451
+
452
+ # Find item with lowest access count and oldest access time
453
+ least_used_key = min(
454
+ self.cache.keys(),
455
+ key=lambda k: (self.access_counts[k], self.access_times[k])
456
+ )
457
+
458
+ del self.cache[least_used_key]
459
+ del self.access_times[least_used_key]
460
+ del self.access_counts[least_used_key]
461
+
462
+
463
+ class MLIntegration:
464
+ """Main ML integration system"""
465
+
466
+ def __init__(self):
467
+ self.model_manager = MLModelManager()
468
+ self.anomaly_detector = AnomalyDetector()
469
+ self.smart_cache = SmartCache()
470
+ self.request_history: deque = deque(maxlen=10000)
471
+ self.response_patterns: Dict[str, List[Dict[str, Any]]] = defaultdict(list)
472
+
473
+ def record_request(self, request_data: Dict[str, Any], response_data: Dict[str, Any]) -> None:
474
+ """Record request-response pair for ML training"""
475
+ self.request_history.append({
476
+ "request": request_data,
477
+ "response": response_data,
478
+ "timestamp": datetime.now()
479
+ })
480
+
481
+ # Update response patterns
482
+ path = request_data.get('path', '')
483
+ self.response_patterns[path].append(response_data)
484
+
485
+ def create_response_time_model(self) -> MLModel:
486
+ """Create a model to predict response times"""
487
+ model = MLModel(
488
+ name="response_time_predictor",
489
+ model_type=MLModelType.REGRESSION,
490
+ model=LinearRegression(),
491
+ features=['method_encoded', 'path_length', 'body_length', 'header_count', 'hour_of_day'],
492
+ target="response_time"
493
+ )
494
+ self.model_manager.add_model(model)
495
+ return model
496
+
497
+ def create_error_probability_model(self) -> MLModel:
498
+ """Create a model to predict error probability"""
499
+ model = MLModel(
500
+ name="error_probability_predictor",
501
+ model_type=MLModelType.CLASSIFICATION,
502
+ model=MLPClassifier(hidden_layer_sizes=(100, 50), random_state=42),
503
+ features=['method_encoded', 'path_length', 'body_length', 'hour_of_day', 'day_of_week'],
504
+ target="error_probability"
505
+ )
506
+ self.model_manager.add_model(model)
507
+ return model
508
+
509
+ def train_models(self) -> Dict[str, Any]:
510
+ """Train all models with collected data"""
511
+ results = {}
512
+
513
+ # Prepare training data
514
+ if len(self.request_history) < 100:
515
+ return {"error": "Insufficient training data"}
516
+
517
+ # Response time model
518
+ response_time_model = self.create_response_time_model()
519
+ response_time_data = self._prepare_response_time_data()
520
+ if response_time_data:
521
+ results["response_time"] = self.model_manager.train_model(
522
+ "response_time_predictor", response_time_data
523
+ )
524
+
525
+ # Error probability model
526
+ error_model = self.create_error_probability_model()
527
+ error_data = self._prepare_error_data()
528
+ if error_data:
529
+ results["error_probability"] = self.model_manager.train_model(
530
+ "error_probability_predictor", error_data
531
+ )
532
+
533
+ # Anomaly detector
534
+ normal_data = [item["request"] for item in self.request_history]
535
+ self.anomaly_detector.fit(normal_data)
536
+ results["anomaly_detector"] = {"fitted": True}
537
+
538
+ return results
539
+
540
+ def _prepare_response_time_data(self) -> Optional[TrainingData]:
541
+ """Prepare training data for response time prediction"""
542
+ features = []
543
+ targets = []
544
+
545
+ for item in self.request_history:
546
+ request = item["request"]
547
+ response = item["response"]
548
+
549
+ # Extract features
550
+ request_features = self.model_manager.feature_extractor.extract_request_features(request)
551
+ response_features = self.model_manager.feature_extractor.extract_response_features(response)
552
+
553
+ # Combine features
554
+ combined_features = {**request_features, **response_features}
555
+ features.append(combined_features)
556
+
557
+ # Target is response time (simulated)
558
+ targets.append(np.random.uniform(0.1, 2.0)) # Simulated response time
559
+
560
+ if not features:
561
+ return None
562
+
563
+ return TrainingData(
564
+ features=features,
565
+ targets=targets,
566
+ feature_names=list(features[0].keys()),
567
+ target_name="response_time"
568
+ )
569
+
570
+ def _prepare_error_data(self) -> Optional[TrainingData]:
571
+ """Prepare training data for error probability prediction"""
572
+ features = []
573
+ targets = []
574
+
575
+ for item in self.request_history:
576
+ request = item["request"]
577
+ response = item["response"]
578
+
579
+ # Extract features
580
+ request_features = self.model_manager.feature_extractor.extract_request_features(request)
581
+ features.append(request_features)
582
+
583
+ # Target is error probability (1 if error, 0 if success)
584
+ is_error = response.get("status_code", 200) >= 400
585
+ targets.append(1 if is_error else 0)
586
+
587
+ if not features:
588
+ return None
589
+
590
+ return TrainingData(
591
+ features=features,
592
+ targets=targets,
593
+ feature_names=list(features[0].keys()),
594
+ target_name="error_probability"
595
+ )
596
+
597
+ def predict_response_time(self, request_data: Dict[str, Any]) -> float:
598
+ """Predict response time for a request"""
599
+ request = PredictionRequest(
600
+ features=request_data,
601
+ model_name="response_time_predictor",
602
+ prediction_type=PredictionType.RESPONSE_TIME
603
+ )
604
+
605
+ result = self.model_manager.predict(request)
606
+ return result.prediction if result.prediction else 1.0
607
+
608
+ def predict_error_probability(self, request_data: Dict[str, Any]) -> float:
609
+ """Predict error probability for a request"""
610
+ request = PredictionRequest(
611
+ features=request_data,
612
+ model_name="error_probability_predictor",
613
+ prediction_type=PredictionType.ERROR_PROBABILITY
614
+ )
615
+
616
+ result = self.model_manager.predict(request)
617
+ return result.confidence if result.prediction else 0.0
618
+
619
+ def detect_anomaly(self, request_data: Dict[str, Any]) -> Dict[str, Any]:
620
+ """Detect anomalies in request"""
621
+ return self.anomaly_detector.detect_anomaly(request_data)
622
+
623
+ def get_cache_recommendation(self, request_data: Dict[str, Any]) -> Dict[str, Any]:
624
+ """Get cache recommendation for a request"""
625
+ cache_hit_probability = self.smart_cache.predict_cache_hit(request_data)
626
+
627
+ return {
628
+ "should_cache": cache_hit_probability > 0.7,
629
+ "cache_hit_probability": cache_hit_probability,
630
+ "recommended_ttl": int(3600 * cache_hit_probability) # TTL in seconds
631
+ }
632
+
633
+ def generate_smart_response(self, request_data: Dict[str, Any]) -> Dict[str, Any]:
634
+ """Generate a smart response using ML predictions"""
635
+ # Predict response characteristics
636
+ response_time = self.predict_response_time(request_data)
637
+ error_probability = self.predict_error_probability(request_data)
638
+ anomaly_result = self.detect_anomaly(request_data)
639
+ cache_recommendation = self.get_cache_recommendation(request_data)
640
+
641
+ # Generate response based on predictions
642
+ if error_probability > 0.5:
643
+ status_code = np.random.choice([400, 401, 403, 404, 500], p=[0.3, 0.2, 0.1, 0.3, 0.1])
644
+ else:
645
+ status_code = 200
646
+
647
+ response = {
648
+ "status_code": status_code,
649
+ "headers": {
650
+ "Content-Type": "application/json",
651
+ "X-ML-Predicted": "true",
652
+ "X-Response-Time": str(response_time),
653
+ "X-Error-Probability": str(error_probability)
654
+ },
655
+ "body": {
656
+ "message": "ML-generated response",
657
+ "predicted_response_time": response_time,
658
+ "error_probability": error_probability,
659
+ "is_anomaly": anomaly_result["is_anomaly"],
660
+ "cache_recommendation": cache_recommendation
661
+ }
662
+ }
663
+
664
+ # Add cache headers if recommended
665
+ if cache_recommendation["should_cache"]:
666
+ response["headers"]["Cache-Control"] = f"max-age={cache_recommendation['recommended_ttl']}"
667
+
668
+ return response
669
+
670
+
671
+ # Global ML integration instance
672
+ ml_integration = MLIntegration()
673
+
674
+
675
+ # Convenience functions
676
+ def create_ml_model(name: str, model_type: MLModelType, features: List[str], target: str) -> MLModel:
677
+ """Create a new ML model"""
678
+ if model_type == MLModelType.CLASSIFICATION:
679
+ model = RandomForestClassifier(n_estimators=100, random_state=42)
680
+ elif model_type == MLModelType.REGRESSION:
681
+ model = LinearRegression()
682
+ else:
683
+ model = RandomForestClassifier(n_estimators=100, random_state=42)
684
+
685
+ ml_model = MLModel(
686
+ name=name,
687
+ model_type=model_type,
688
+ model=model,
689
+ features=features,
690
+ target=target
691
+ )
692
+
693
+ ml_integration.model_manager.add_model(ml_model)
694
+ return ml_model
695
+
696
+
697
+ def train_ml_models() -> Dict[str, Any]:
698
+ """Train all ML models"""
699
+ return ml_integration.train_models()
700
+
701
+
702
+ def predict_response_characteristics(request_data: Dict[str, Any]) -> Dict[str, Any]:
703
+ """Predict response characteristics for a request"""
704
+ return {
705
+ "response_time": ml_integration.predict_response_time(request_data),
706
+ "error_probability": ml_integration.predict_error_probability(request_data),
707
+ "anomaly_detection": ml_integration.detect_anomaly(request_data),
708
+ "cache_recommendation": ml_integration.get_cache_recommendation(request_data)
709
+ }