mcli-framework 7.0.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.

Potentially problematic release.


This version of mcli-framework might be problematic. Click here for more details.

Files changed (186) hide show
  1. mcli/app/chat_cmd.py +42 -0
  2. mcli/app/commands_cmd.py +226 -0
  3. mcli/app/completion_cmd.py +216 -0
  4. mcli/app/completion_helpers.py +288 -0
  5. mcli/app/cron_test_cmd.py +697 -0
  6. mcli/app/logs_cmd.py +419 -0
  7. mcli/app/main.py +492 -0
  8. mcli/app/model/model.py +1060 -0
  9. mcli/app/model_cmd.py +227 -0
  10. mcli/app/redis_cmd.py +269 -0
  11. mcli/app/video/video.py +1114 -0
  12. mcli/app/visual_cmd.py +303 -0
  13. mcli/chat/chat.py +2409 -0
  14. mcli/chat/command_rag.py +514 -0
  15. mcli/chat/enhanced_chat.py +652 -0
  16. mcli/chat/system_controller.py +1010 -0
  17. mcli/chat/system_integration.py +1016 -0
  18. mcli/cli.py +25 -0
  19. mcli/config.toml +20 -0
  20. mcli/lib/api/api.py +586 -0
  21. mcli/lib/api/daemon_client.py +203 -0
  22. mcli/lib/api/daemon_client_local.py +44 -0
  23. mcli/lib/api/daemon_decorator.py +217 -0
  24. mcli/lib/api/mcli_decorators.py +1032 -0
  25. mcli/lib/auth/auth.py +85 -0
  26. mcli/lib/auth/aws_manager.py +85 -0
  27. mcli/lib/auth/azure_manager.py +91 -0
  28. mcli/lib/auth/credential_manager.py +192 -0
  29. mcli/lib/auth/gcp_manager.py +93 -0
  30. mcli/lib/auth/key_manager.py +117 -0
  31. mcli/lib/auth/mcli_manager.py +93 -0
  32. mcli/lib/auth/token_manager.py +75 -0
  33. mcli/lib/auth/token_util.py +1011 -0
  34. mcli/lib/config/config.py +47 -0
  35. mcli/lib/discovery/__init__.py +1 -0
  36. mcli/lib/discovery/command_discovery.py +274 -0
  37. mcli/lib/erd/erd.py +1345 -0
  38. mcli/lib/erd/generate_graph.py +453 -0
  39. mcli/lib/files/files.py +76 -0
  40. mcli/lib/fs/fs.py +109 -0
  41. mcli/lib/lib.py +29 -0
  42. mcli/lib/logger/logger.py +611 -0
  43. mcli/lib/performance/optimizer.py +409 -0
  44. mcli/lib/performance/rust_bridge.py +502 -0
  45. mcli/lib/performance/uvloop_config.py +154 -0
  46. mcli/lib/pickles/pickles.py +50 -0
  47. mcli/lib/search/cached_vectorizer.py +479 -0
  48. mcli/lib/services/data_pipeline.py +460 -0
  49. mcli/lib/services/lsh_client.py +441 -0
  50. mcli/lib/services/redis_service.py +387 -0
  51. mcli/lib/shell/shell.py +137 -0
  52. mcli/lib/toml/toml.py +33 -0
  53. mcli/lib/ui/styling.py +47 -0
  54. mcli/lib/ui/visual_effects.py +634 -0
  55. mcli/lib/watcher/watcher.py +185 -0
  56. mcli/ml/api/app.py +215 -0
  57. mcli/ml/api/middleware.py +224 -0
  58. mcli/ml/api/routers/admin_router.py +12 -0
  59. mcli/ml/api/routers/auth_router.py +244 -0
  60. mcli/ml/api/routers/backtest_router.py +12 -0
  61. mcli/ml/api/routers/data_router.py +12 -0
  62. mcli/ml/api/routers/model_router.py +302 -0
  63. mcli/ml/api/routers/monitoring_router.py +12 -0
  64. mcli/ml/api/routers/portfolio_router.py +12 -0
  65. mcli/ml/api/routers/prediction_router.py +267 -0
  66. mcli/ml/api/routers/trade_router.py +12 -0
  67. mcli/ml/api/routers/websocket_router.py +76 -0
  68. mcli/ml/api/schemas.py +64 -0
  69. mcli/ml/auth/auth_manager.py +425 -0
  70. mcli/ml/auth/models.py +154 -0
  71. mcli/ml/auth/permissions.py +302 -0
  72. mcli/ml/backtesting/backtest_engine.py +502 -0
  73. mcli/ml/backtesting/performance_metrics.py +393 -0
  74. mcli/ml/cache.py +400 -0
  75. mcli/ml/cli/main.py +398 -0
  76. mcli/ml/config/settings.py +394 -0
  77. mcli/ml/configs/dvc_config.py +230 -0
  78. mcli/ml/configs/mlflow_config.py +131 -0
  79. mcli/ml/configs/mlops_manager.py +293 -0
  80. mcli/ml/dashboard/app.py +532 -0
  81. mcli/ml/dashboard/app_integrated.py +738 -0
  82. mcli/ml/dashboard/app_supabase.py +560 -0
  83. mcli/ml/dashboard/app_training.py +615 -0
  84. mcli/ml/dashboard/cli.py +51 -0
  85. mcli/ml/data_ingestion/api_connectors.py +501 -0
  86. mcli/ml/data_ingestion/data_pipeline.py +567 -0
  87. mcli/ml/data_ingestion/stream_processor.py +512 -0
  88. mcli/ml/database/migrations/env.py +94 -0
  89. mcli/ml/database/models.py +667 -0
  90. mcli/ml/database/session.py +200 -0
  91. mcli/ml/experimentation/ab_testing.py +845 -0
  92. mcli/ml/features/ensemble_features.py +607 -0
  93. mcli/ml/features/political_features.py +676 -0
  94. mcli/ml/features/recommendation_engine.py +809 -0
  95. mcli/ml/features/stock_features.py +573 -0
  96. mcli/ml/features/test_feature_engineering.py +346 -0
  97. mcli/ml/logging.py +85 -0
  98. mcli/ml/mlops/data_versioning.py +518 -0
  99. mcli/ml/mlops/experiment_tracker.py +377 -0
  100. mcli/ml/mlops/model_serving.py +481 -0
  101. mcli/ml/mlops/pipeline_orchestrator.py +614 -0
  102. mcli/ml/models/base_models.py +324 -0
  103. mcli/ml/models/ensemble_models.py +675 -0
  104. mcli/ml/models/recommendation_models.py +474 -0
  105. mcli/ml/models/test_models.py +487 -0
  106. mcli/ml/monitoring/drift_detection.py +676 -0
  107. mcli/ml/monitoring/metrics.py +45 -0
  108. mcli/ml/optimization/portfolio_optimizer.py +834 -0
  109. mcli/ml/preprocessing/data_cleaners.py +451 -0
  110. mcli/ml/preprocessing/feature_extractors.py +491 -0
  111. mcli/ml/preprocessing/ml_pipeline.py +382 -0
  112. mcli/ml/preprocessing/politician_trading_preprocessor.py +569 -0
  113. mcli/ml/preprocessing/test_preprocessing.py +294 -0
  114. mcli/ml/scripts/populate_sample_data.py +200 -0
  115. mcli/ml/tasks.py +400 -0
  116. mcli/ml/tests/test_integration.py +429 -0
  117. mcli/ml/tests/test_training_dashboard.py +387 -0
  118. mcli/public/oi/oi.py +15 -0
  119. mcli/public/public.py +4 -0
  120. mcli/self/self_cmd.py +1246 -0
  121. mcli/workflow/daemon/api_daemon.py +800 -0
  122. mcli/workflow/daemon/async_command_database.py +681 -0
  123. mcli/workflow/daemon/async_process_manager.py +591 -0
  124. mcli/workflow/daemon/client.py +530 -0
  125. mcli/workflow/daemon/commands.py +1196 -0
  126. mcli/workflow/daemon/daemon.py +905 -0
  127. mcli/workflow/daemon/daemon_api.py +59 -0
  128. mcli/workflow/daemon/enhanced_daemon.py +571 -0
  129. mcli/workflow/daemon/process_cli.py +244 -0
  130. mcli/workflow/daemon/process_manager.py +439 -0
  131. mcli/workflow/daemon/test_daemon.py +275 -0
  132. mcli/workflow/dashboard/dashboard_cmd.py +113 -0
  133. mcli/workflow/docker/docker.py +0 -0
  134. mcli/workflow/file/file.py +100 -0
  135. mcli/workflow/gcloud/config.toml +21 -0
  136. mcli/workflow/gcloud/gcloud.py +58 -0
  137. mcli/workflow/git_commit/ai_service.py +328 -0
  138. mcli/workflow/git_commit/commands.py +430 -0
  139. mcli/workflow/lsh_integration.py +355 -0
  140. mcli/workflow/model_service/client.py +594 -0
  141. mcli/workflow/model_service/download_and_run_efficient_models.py +288 -0
  142. mcli/workflow/model_service/lightweight_embedder.py +397 -0
  143. mcli/workflow/model_service/lightweight_model_server.py +714 -0
  144. mcli/workflow/model_service/lightweight_test.py +241 -0
  145. mcli/workflow/model_service/model_service.py +1955 -0
  146. mcli/workflow/model_service/ollama_efficient_runner.py +425 -0
  147. mcli/workflow/model_service/pdf_processor.py +386 -0
  148. mcli/workflow/model_service/test_efficient_runner.py +234 -0
  149. mcli/workflow/model_service/test_example.py +315 -0
  150. mcli/workflow/model_service/test_integration.py +131 -0
  151. mcli/workflow/model_service/test_new_features.py +149 -0
  152. mcli/workflow/openai/openai.py +99 -0
  153. mcli/workflow/politician_trading/commands.py +1790 -0
  154. mcli/workflow/politician_trading/config.py +134 -0
  155. mcli/workflow/politician_trading/connectivity.py +490 -0
  156. mcli/workflow/politician_trading/data_sources.py +395 -0
  157. mcli/workflow/politician_trading/database.py +410 -0
  158. mcli/workflow/politician_trading/demo.py +248 -0
  159. mcli/workflow/politician_trading/models.py +165 -0
  160. mcli/workflow/politician_trading/monitoring.py +413 -0
  161. mcli/workflow/politician_trading/scrapers.py +966 -0
  162. mcli/workflow/politician_trading/scrapers_california.py +412 -0
  163. mcli/workflow/politician_trading/scrapers_eu.py +377 -0
  164. mcli/workflow/politician_trading/scrapers_uk.py +350 -0
  165. mcli/workflow/politician_trading/scrapers_us_states.py +438 -0
  166. mcli/workflow/politician_trading/supabase_functions.py +354 -0
  167. mcli/workflow/politician_trading/workflow.py +852 -0
  168. mcli/workflow/registry/registry.py +180 -0
  169. mcli/workflow/repo/repo.py +223 -0
  170. mcli/workflow/scheduler/commands.py +493 -0
  171. mcli/workflow/scheduler/cron_parser.py +238 -0
  172. mcli/workflow/scheduler/job.py +182 -0
  173. mcli/workflow/scheduler/monitor.py +139 -0
  174. mcli/workflow/scheduler/persistence.py +324 -0
  175. mcli/workflow/scheduler/scheduler.py +679 -0
  176. mcli/workflow/sync/sync_cmd.py +437 -0
  177. mcli/workflow/sync/test_cmd.py +314 -0
  178. mcli/workflow/videos/videos.py +242 -0
  179. mcli/workflow/wakatime/wakatime.py +11 -0
  180. mcli/workflow/workflow.py +37 -0
  181. mcli_framework-7.0.0.dist-info/METADATA +479 -0
  182. mcli_framework-7.0.0.dist-info/RECORD +186 -0
  183. mcli_framework-7.0.0.dist-info/WHEEL +5 -0
  184. mcli_framework-7.0.0.dist-info/entry_points.txt +7 -0
  185. mcli_framework-7.0.0.dist-info/licenses/LICENSE +21 -0
  186. mcli_framework-7.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,131 @@
1
+ """MLflow Configuration for Stock Recommendation System"""
2
+
3
+ import os
4
+ from pathlib import Path
5
+ from typing import Any, Dict, Optional
6
+
7
+ import mlflow
8
+ from mlflow.tracking import MlflowClient
9
+
10
+
11
+ class MLflowConfig:
12
+ """Configuration class for MLflow tracking and model registry"""
13
+
14
+ def __init__(
15
+ self,
16
+ tracking_uri: Optional[str] = None,
17
+ experiment_name: str = "politician-trading-stock-recommendations",
18
+ artifact_root: Optional[str] = None,
19
+ ):
20
+ self.tracking_uri = tracking_uri or self._default_tracking_uri()
21
+ self.experiment_name = experiment_name
22
+ self.artifact_root = artifact_root or self._default_artifact_root()
23
+ self._client = None
24
+
25
+ def _default_tracking_uri(self) -> str:
26
+ """Get default MLflow tracking URI"""
27
+ project_root = Path(__file__).parent.parent.parent.parent.parent
28
+ return f"file://{project_root}/mlruns"
29
+
30
+ def _default_artifact_root(self) -> str:
31
+ """Get default artifact storage location"""
32
+ project_root = Path(__file__).parent.parent.parent.parent.parent
33
+ return f"{project_root}/artifacts"
34
+
35
+ def setup_tracking(self) -> None:
36
+ """Initialize MLflow tracking configuration"""
37
+ mlflow.set_tracking_uri(self.tracking_uri)
38
+
39
+ # Create or get experiment
40
+ try:
41
+ experiment = mlflow.get_experiment_by_name(self.experiment_name)
42
+ if experiment is None:
43
+ experiment_id = mlflow.create_experiment(
44
+ name=self.experiment_name, artifact_location=self.artifact_root
45
+ )
46
+ print(f"Created new experiment: {self.experiment_name} (ID: {experiment_id})")
47
+ else:
48
+ experiment_id = experiment.experiment_id
49
+ print(f"Using existing experiment: {self.experiment_name} (ID: {experiment_id})")
50
+
51
+ mlflow.set_experiment(self.experiment_name)
52
+
53
+ except Exception as e:
54
+ print(f"Error setting up MLflow experiment: {e}")
55
+ raise
56
+
57
+ @property
58
+ def client(self) -> MlflowClient:
59
+ """Get MLflow client instance"""
60
+ if self._client is None:
61
+ self._client = MlflowClient(tracking_uri=self.tracking_uri)
62
+ return self._client
63
+
64
+ def get_model_registry_uri(self) -> str:
65
+ """Get model registry URI"""
66
+ return self.tracking_uri
67
+
68
+ def log_model_metadata(self, run_id: str, metadata: Dict[str, Any]) -> None:
69
+ """Log additional metadata for a model"""
70
+ for key, value in metadata.items():
71
+ self.client.log_param(run_id, key, value)
72
+
73
+ def register_model(
74
+ self,
75
+ model_uri: str,
76
+ model_name: str,
77
+ tags: Optional[Dict[str, str]] = None,
78
+ description: Optional[str] = None,
79
+ ) -> None:
80
+ """Register a model in MLflow Model Registry"""
81
+ try:
82
+ model_version = mlflow.register_model(model_uri=model_uri, name=model_name, tags=tags)
83
+
84
+ if description:
85
+ self.client.update_model_version(
86
+ name=model_name, version=model_version.version, description=description
87
+ )
88
+
89
+ print(f"Registered model: {model_name}, version: {model_version.version}")
90
+ return model_version
91
+
92
+ except Exception as e:
93
+ print(f"Error registering model: {e}")
94
+ raise
95
+
96
+ def transition_model_stage(
97
+ self, model_name: str, version: str, stage: str, archive_existing_versions: bool = False
98
+ ) -> None:
99
+ """Transition model to a different stage"""
100
+ try:
101
+ self.client.transition_model_version_stage(
102
+ name=model_name,
103
+ version=version,
104
+ stage=stage,
105
+ archive_existing_versions=archive_existing_versions,
106
+ )
107
+ print(f"Transitioned {model_name} v{version} to {stage}")
108
+
109
+ except Exception as e:
110
+ print(f"Error transitioning model stage: {e}")
111
+ raise
112
+
113
+
114
+ # Global configuration instance
115
+ mlflow_config = MLflowConfig()
116
+
117
+
118
+ def get_mlflow_config() -> MLflowConfig:
119
+ """Get the global MLflow configuration instance"""
120
+ return mlflow_config
121
+
122
+
123
+ def setup_mlflow() -> None:
124
+ """Setup MLflow tracking and experiment"""
125
+ mlflow_config.setup_tracking()
126
+ print(f"MLflow tracking URI: {mlflow_config.tracking_uri}")
127
+ print(f"Artifact root: {mlflow_config.artifact_root}")
128
+
129
+
130
+ if __name__ == "__main__":
131
+ setup_mlflow()
@@ -0,0 +1,293 @@
1
+ """Unified MLOps Manager for Stock Recommendation System"""
2
+
3
+ import json
4
+ import os
5
+ import pickle
6
+ from datetime import datetime
7
+ from pathlib import Path
8
+ from typing import Any, Dict, List, Optional
9
+
10
+ import joblib
11
+ import mlflow
12
+ import mlflow.pytorch
13
+ import mlflow.sklearn
14
+ from mlflow.tracking import MlflowClient
15
+
16
+ from .dvc_config import DVCConfig, get_dvc_config
17
+ from .mlflow_config import MLflowConfig, get_mlflow_config
18
+
19
+
20
+ class MLOpsManager:
21
+ """Unified manager for MLflow and DVC operations"""
22
+
23
+ def __init__(
24
+ self, mlflow_config: Optional[MLflowConfig] = None, dvc_config: Optional[DVCConfig] = None
25
+ ):
26
+ self.mlflow_config = mlflow_config or get_mlflow_config()
27
+ self.dvc_config = dvc_config or get_dvc_config()
28
+ self._setup_completed = False
29
+
30
+ def setup(self) -> None:
31
+ """Initialize MLOps infrastructure"""
32
+ if self._setup_completed:
33
+ return
34
+
35
+ print("Setting up MLOps infrastructure...")
36
+
37
+ # Setup MLflow
38
+ self.mlflow_config.setup_tracking()
39
+
40
+ # Setup DVC
41
+ self.dvc_config.setup_data_directories()
42
+
43
+ self._setup_completed = True
44
+ print("✅ MLOps infrastructure setup completed")
45
+
46
+ def start_experiment_run(
47
+ self,
48
+ run_name: Optional[str] = None,
49
+ tags: Optional[Dict[str, str]] = None,
50
+ description: Optional[str] = None,
51
+ ) -> str:
52
+ """Start a new MLflow experiment run"""
53
+ if not self._setup_completed:
54
+ self.setup()
55
+
56
+ run_tags = tags or {}
57
+ if description:
58
+ run_tags["description"] = description
59
+
60
+ run = mlflow.start_run(run_name=run_name, tags=run_tags)
61
+ print(f"Started MLflow run: {run.info.run_id}")
62
+ return run.info.run_id
63
+
64
+ def log_parameters(self, params: Dict[str, Any]) -> None:
65
+ """Log parameters to MLflow"""
66
+ for key, value in params.items():
67
+ mlflow.log_param(key, value)
68
+
69
+ def log_metrics(self, metrics: Dict[str, float], step: Optional[int] = None) -> None:
70
+ """Log metrics to MLflow"""
71
+ for key, value in metrics.items():
72
+ mlflow.log_metric(key, value, step=step)
73
+
74
+ def log_artifacts(self, artifact_path: Path, artifact_name: Optional[str] = None) -> None:
75
+ """Log artifacts to MLflow"""
76
+ if artifact_path.is_file():
77
+ mlflow.log_artifact(str(artifact_path), artifact_name)
78
+ else:
79
+ mlflow.log_artifacts(str(artifact_path), artifact_name)
80
+
81
+ def save_and_log_model(
82
+ self,
83
+ model: Any,
84
+ model_name: str,
85
+ model_type: str = "pytorch",
86
+ signature: Optional[Any] = None,
87
+ input_example: Optional[Any] = None,
88
+ metadata: Optional[Dict[str, Any]] = None,
89
+ ) -> str:
90
+ """Save model locally and log to MLflow"""
91
+ # Create model directory
92
+ model_dir = self.dvc_config.models_dir / model_type / model_name
93
+ model_dir.mkdir(parents=True, exist_ok=True)
94
+
95
+ # Save model based on type
96
+ if model_type == "pytorch":
97
+ import torch
98
+
99
+ model_path = model_dir / "model.pt"
100
+ torch.save(model.state_dict(), model_path)
101
+
102
+ # Log to MLflow
103
+ mlflow.pytorch.log_model(
104
+ pytorch_model=model,
105
+ artifact_path=f"models/{model_name}",
106
+ signature=signature,
107
+ input_example=input_example,
108
+ extra_files=[str(model_path)] if model_path.exists() else None,
109
+ )
110
+
111
+ elif model_type == "sklearn":
112
+ model_path = model_dir / "model.pkl"
113
+ joblib.dump(model, model_path)
114
+
115
+ # Log to MLflow
116
+ mlflow.sklearn.log_model(
117
+ sk_model=model,
118
+ artifact_path=f"models/{model_name}",
119
+ signature=signature,
120
+ input_example=input_example,
121
+ )
122
+
123
+ else:
124
+ # Generic pickle save
125
+ model_path = model_dir / "model.pkl"
126
+ with open(model_path, "wb") as f:
127
+ pickle.dump(model, f)
128
+
129
+ # Log as generic artifact
130
+ mlflow.log_artifact(str(model_path), f"models/{model_name}")
131
+
132
+ # Save metadata
133
+ if metadata:
134
+ metadata_path = model_dir / "metadata.json"
135
+ with open(metadata_path, "w") as f:
136
+ json.dump(metadata, f, indent=2, default=str)
137
+ mlflow.log_artifact(str(metadata_path), f"models/{model_name}")
138
+
139
+ # Add to DVC tracking
140
+ self.dvc_config.add_data_to_dvc(model_dir)
141
+
142
+ print(f"Model saved and logged: {model_name} ({model_type})")
143
+ return str(model_path)
144
+
145
+ def register_model(
146
+ self,
147
+ model_name: str,
148
+ stage: str = "Staging",
149
+ description: Optional[str] = None,
150
+ tags: Optional[Dict[str, str]] = None,
151
+ ) -> str:
152
+ """Register model in MLflow Model Registry"""
153
+ # Get the current run
154
+ run = mlflow.active_run()
155
+ if not run:
156
+ raise Exception("No active MLflow run. Start a run first.")
157
+
158
+ model_uri = f"runs:/{run.info.run_id}/models/{model_name}"
159
+
160
+ # Register model
161
+ model_version = self.mlflow_config.register_model(
162
+ model_uri=model_uri, model_name=model_name, tags=tags, description=description
163
+ )
164
+
165
+ # Transition to requested stage
166
+ if stage != "None":
167
+ self.mlflow_config.transition_model_stage(
168
+ model_name=model_name, version=model_version.version, stage=stage
169
+ )
170
+
171
+ return model_version.version
172
+
173
+ def load_model(
174
+ self, model_name: str, version: Optional[str] = None, stage: Optional[str] = None
175
+ ) -> Any:
176
+ """Load model from MLflow Model Registry"""
177
+ if version:
178
+ model_uri = f"models:/{model_name}/{version}"
179
+ elif stage:
180
+ model_uri = f"models:/{model_name}/{stage}"
181
+ else:
182
+ model_uri = f"models:/{model_name}/latest"
183
+
184
+ return mlflow.pytorch.load_model(model_uri)
185
+
186
+ def end_run(self, status: str = "FINISHED") -> None:
187
+ """End the current MLflow run"""
188
+ mlflow.end_run(status=status)
189
+
190
+ def version_data(self, data_path: Path, message: Optional[str] = None) -> str:
191
+ """Version data using DVC"""
192
+ self.dvc_config.add_data_to_dvc(data_path, message)
193
+ return self.dvc_config.get_data_version(data_path) or "unknown"
194
+
195
+ def create_ml_pipeline_stage(
196
+ self,
197
+ stage_name: str,
198
+ script_path: str,
199
+ dependencies: List[str],
200
+ outputs: List[str],
201
+ parameters: Optional[List[str]] = None,
202
+ ) -> None:
203
+ """Create a DVC pipeline stage for ML workflow"""
204
+ command = f"python {script_path}"
205
+
206
+ self.dvc_config.create_pipeline_stage(
207
+ stage_name=stage_name,
208
+ command=command,
209
+ dependencies=dependencies,
210
+ outputs=outputs,
211
+ parameters=parameters,
212
+ )
213
+
214
+ def run_ml_pipeline(self, stage_name: Optional[str] = None) -> None:
215
+ """Run DVC ML pipeline"""
216
+ self.dvc_config.run_pipeline(stage_name)
217
+
218
+ def get_experiment_metrics(self, experiment_name: str) -> List[Dict[str, Any]]:
219
+ """Get metrics from all runs in an experiment"""
220
+ experiment = mlflow.get_experiment_by_name(experiment_name)
221
+ if not experiment:
222
+ return []
223
+
224
+ runs = mlflow.search_runs(experiment_ids=[experiment.experiment_id])
225
+ return runs.to_dict("records")
226
+
227
+ def compare_models(
228
+ self, model_names: List[str], metric_name: str = "accuracy"
229
+ ) -> Dict[str, Any]:
230
+ """Compare models by a specific metric"""
231
+ comparison = {}
232
+
233
+ for model_name in model_names:
234
+ try:
235
+ # Get latest version metrics
236
+ latest_versions = self.mlflow_config.client.get_latest_versions(
237
+ model_name, stages=["Production", "Staging"]
238
+ )
239
+
240
+ if latest_versions:
241
+ version = latest_versions[0]
242
+ run = self.mlflow_config.client.get_run(version.run_id)
243
+ comparison[model_name] = {
244
+ "version": version.version,
245
+ "stage": version.current_stage,
246
+ "metric_value": run.data.metrics.get(metric_name, 0.0),
247
+ "run_id": version.run_id,
248
+ }
249
+ except Exception as e:
250
+ comparison[model_name] = {"error": str(e)}
251
+
252
+ return comparison
253
+
254
+ def cleanup_old_runs(self, days_old: int = 30) -> None:
255
+ """Clean up old experiment runs"""
256
+ # This would implement cleanup logic for old runs
257
+ # For now, just a placeholder
258
+ print(f"Cleanup of runs older than {days_old} days would be implemented here")
259
+
260
+ def get_system_info(self) -> Dict[str, Any]:
261
+ """Get MLOps system information"""
262
+ return {
263
+ "mlflow_tracking_uri": self.mlflow_config.tracking_uri,
264
+ "mlflow_experiment": self.mlflow_config.experiment_name,
265
+ "dvc_project_root": str(self.dvc_config.project_root),
266
+ "data_directory": str(self.dvc_config.data_dir),
267
+ "models_directory": str(self.dvc_config.models_dir),
268
+ "setup_completed": self._setup_completed,
269
+ "timestamp": datetime.now().isoformat(),
270
+ }
271
+
272
+
273
+ # Global MLOps manager instance
274
+ mlops_manager = MLOpsManager()
275
+
276
+
277
+ def get_mlops_manager() -> MLOpsManager:
278
+ """Get the global MLOps manager instance"""
279
+ return mlops_manager
280
+
281
+
282
+ if __name__ == "__main__":
283
+ # Test the MLOps setup
284
+ manager = get_mlops_manager()
285
+ manager.setup()
286
+
287
+ print("\n" + "=" * 50)
288
+ print("MLOPs System Information:")
289
+ print("=" * 50)
290
+
291
+ system_info = manager.get_system_info()
292
+ for key, value in system_info.items():
293
+ print(f"{key}: {value}")