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,314 @@
1
+ """
2
+ Multi-cloud sync testing commands for mcli workflow system.
3
+ Provides comprehensive connectivity and validation testing.
4
+ """
5
+
6
+ import json
7
+ import subprocess
8
+ import sys
9
+ from datetime import datetime
10
+ from pathlib import Path
11
+ from typing import Dict, Optional
12
+
13
+ import click
14
+
15
+ from mcli.lib.logger.logger import get_logger
16
+
17
+ logger = get_logger(__name__)
18
+
19
+
20
+ class McliSyncTester:
21
+ """MCLI-integrated sync testing functionality."""
22
+
23
+ def __init__(self, vault_path: str = "."):
24
+ self.vault_path = Path(vault_path).resolve()
25
+ self.test_script = self.vault_path / "test_sync_connectivity.py"
26
+
27
+ def run_connectivity_test(self, quick: bool = False, output_file: Optional[str] = None) -> Dict:
28
+ """Run connectivity tests using the standalone test script."""
29
+
30
+ if not self.test_script.exists():
31
+ raise FileNotFoundError(f"Test script not found: {self.test_script}")
32
+
33
+ # Build command
34
+ cmd = [sys.executable, str(self.test_script), "--vault-path", str(self.vault_path)]
35
+
36
+ if quick:
37
+ cmd.append("--quick")
38
+
39
+ if output_file:
40
+ cmd.extend(["--output", output_file])
41
+
42
+ try:
43
+ # Run the test script
44
+ result = subprocess.run(
45
+ cmd,
46
+ cwd=self.vault_path,
47
+ capture_output=True,
48
+ text=True,
49
+ timeout=300, # 5 minute timeout
50
+ )
51
+
52
+ # Parse output if JSON report was generated
53
+ report = None
54
+ if output_file and Path(output_file).exists():
55
+ try:
56
+ with open(output_file, "r") as f:
57
+ report = json.load(f)
58
+ except Exception as e:
59
+ logger.warning(f"Could not parse test report: {e}")
60
+
61
+ return {
62
+ "returncode": result.returncode,
63
+ "stdout": result.stdout,
64
+ "stderr": result.stderr,
65
+ "report": report,
66
+ "success": result.returncode == 0,
67
+ }
68
+
69
+ except subprocess.TimeoutExpired:
70
+ return {
71
+ "returncode": -1,
72
+ "stdout": "",
73
+ "stderr": "Test timed out after 5 minutes",
74
+ "report": None,
75
+ "success": False,
76
+ }
77
+ except Exception as e:
78
+ return {
79
+ "returncode": -1,
80
+ "stdout": "",
81
+ "stderr": str(e),
82
+ "report": None,
83
+ "success": False,
84
+ }
85
+
86
+ def validate_cloud_connectivity(self) -> Dict[str, bool]:
87
+ """Quick validation of cloud service connectivity."""
88
+
89
+ cloud_paths = {
90
+ "onedrive": Path.home() / "Library/CloudStorage/OneDrive-Personal",
91
+ "icloud": Path.home() / "Library/Mobile Documents/com~apple~CloudDocs",
92
+ "googledrive": Path.home() / "Library/CloudStorage/GoogleDrive-luis@lefv.io/My Drive",
93
+ }
94
+
95
+ results = {}
96
+
97
+ for service, path in cloud_paths.items():
98
+ try:
99
+ if path.exists() and path.is_dir():
100
+ # Test write access
101
+ test_file = path / ".mcli_connectivity_test"
102
+ test_file.write_text(f"Connectivity test - {datetime.now().isoformat()}")
103
+
104
+ if test_file.exists():
105
+ test_file.unlink()
106
+ results[service] = True
107
+ else:
108
+ results[service] = False
109
+ else:
110
+ results[service] = False
111
+
112
+ except Exception as e:
113
+ logger.debug(f"Connectivity test failed for {service}: {e}")
114
+ results[service] = False
115
+
116
+ return results
117
+
118
+ def check_sync_health(self) -> Dict[str, any]:
119
+ """Check overall sync system health."""
120
+
121
+ health = {
122
+ "timestamp": datetime.now().isoformat(),
123
+ "vault_path": str(self.vault_path),
124
+ "system_ready": True,
125
+ "issues": [],
126
+ }
127
+
128
+ # Check vault directory
129
+ if not self.vault_path.exists():
130
+ health["system_ready"] = False
131
+ health["issues"].append(f"Vault directory not found: {self.vault_path}")
132
+
133
+ # Check git repository
134
+ git_dir = self.vault_path / ".git"
135
+ if not git_dir.exists():
136
+ health["issues"].append("Not a git repository")
137
+
138
+ # Check sync configuration
139
+ config_file = self.vault_path / ".vault_sync_config.json"
140
+ if not config_file.exists():
141
+ health["system_ready"] = False
142
+ health["issues"].append("Sync configuration not found")
143
+
144
+ # Check cloud connectivity
145
+ cloud_status = self.validate_cloud_connectivity()
146
+ health["cloud_connectivity"] = cloud_status
147
+
148
+ offline_services = [service for service, online in cloud_status.items() if not online]
149
+ if offline_services:
150
+ health["issues"].extend([f"{service} not accessible" for service in offline_services])
151
+
152
+ return health
153
+
154
+
155
+ @click.group(name="test")
156
+ def test():
157
+ """Testing commands for sync functionality."""
158
+ pass
159
+
160
+
161
+ @test.command()
162
+ @click.option("--vault-path", default=".", help="Path to vault directory")
163
+ @click.option("--quick", is_flag=True, help="Run quick tests only")
164
+ @click.option("--output", help="Save detailed report to JSON file")
165
+ def connectivity(vault_path, quick, output):
166
+ """Run comprehensive connectivity tests for all cloud services."""
167
+
168
+ tester = McliSyncTester(vault_path)
169
+
170
+ click.echo("🧪 Running Multi-Cloud Sync Connectivity Tests...")
171
+ click.echo("=" * 50)
172
+
173
+ # Run the tests
174
+ result = tester.run_connectivity_test(quick=quick, output_file=output)
175
+
176
+ # Display results
177
+ if result["stdout"]:
178
+ click.echo(result["stdout"])
179
+
180
+ if result["stderr"]:
181
+ click.echo(f"\n❌ Errors:\n{result['stderr']}")
182
+
183
+ # Show summary from report if available
184
+ if result["report"]:
185
+ report = result["report"]
186
+ stats = report.get("statistics", {})
187
+ success_rate = report.get("success_rate", 0)
188
+
189
+ click.echo("\n" + "=" * 50)
190
+ click.echo("📊 MCLI Test Summary")
191
+ click.echo("=" * 50)
192
+ click.echo(f"Success Rate: {success_rate:.1f}%")
193
+ click.echo(f"Total Tests: {stats.get('total_tests', 0)}")
194
+ click.echo(f"✅ Passed: {stats.get('passed', 0)}")
195
+ click.echo(f"❌ Failed: {stats.get('failed', 0)}")
196
+
197
+ if success_rate >= 90:
198
+ click.echo("\n🎉 Excellent! Your sync system is working perfectly.")
199
+ elif success_rate >= 70:
200
+ click.echo("\n✅ Good! Minor issues may need attention.")
201
+ else:
202
+ click.echo("\n⚠️ Issues detected. Please review the detailed output above.")
203
+
204
+ # Exit with appropriate code
205
+ if not result["success"]:
206
+ sys.exit(1)
207
+
208
+
209
+ @test.command()
210
+ @click.option("--vault-path", default=".", help="Path to vault directory")
211
+ def health(vault_path):
212
+ """Check sync system health status."""
213
+
214
+ tester = McliSyncTester(vault_path)
215
+
216
+ click.echo("🏥 Checking Sync System Health...")
217
+
218
+ health = tester.check_sync_health()
219
+
220
+ # Display health status
221
+ if health["system_ready"]:
222
+ click.echo("✅ System Ready")
223
+ else:
224
+ click.echo("❌ System Issues Detected")
225
+
226
+ click.echo(f"📁 Vault: {health['vault_path']}")
227
+ click.echo(f"🕒 Checked: {health['timestamp']}")
228
+
229
+ # Cloud connectivity status
230
+ click.echo("\n☁️ Cloud Service Status:")
231
+ cloud_status = health.get("cloud_connectivity", {})
232
+ for service, online in cloud_status.items():
233
+ status = "✅ Online" if online else "❌ Offline"
234
+ click.echo(f" {service.title()}: {status}")
235
+
236
+ # Issues
237
+ if health["issues"]:
238
+ click.echo("\n⚠️ Issues Found:")
239
+ for i, issue in enumerate(health["issues"], 1):
240
+ click.echo(f" {i}. {issue}")
241
+ else:
242
+ click.echo("\n🎉 No issues detected!")
243
+
244
+ # Exit with error if system not ready
245
+ if not health["system_ready"]:
246
+ sys.exit(1)
247
+
248
+
249
+ @test.command()
250
+ @click.option("--vault-path", default=".", help="Path to vault directory")
251
+ @click.option(
252
+ "--service",
253
+ type=click.Choice(["github", "onedrive", "icloud", "googledrive", "all"]),
254
+ default="all",
255
+ help="Service to test",
256
+ )
257
+ def sync(vault_path, service):
258
+ """Test sync functionality for specific service or all services."""
259
+
260
+ # Import the sync functionality
261
+ try:
262
+ sys.path.insert(0, vault_path)
263
+ from vault_sync_standalone import VaultSync
264
+ except ImportError:
265
+ click.echo(
266
+ "❌ Could not import sync functionality. Ensure vault_sync_standalone.py is available."
267
+ )
268
+ sys.exit(1)
269
+
270
+ syncer = VaultSync(vault_path)
271
+
272
+ click.echo(f"🔄 Testing Sync Functionality - {service.title()}...")
273
+
274
+ services_to_test = (
275
+ [service] if service != "all" else ["github", "onedrive", "icloud", "googledrive"]
276
+ )
277
+
278
+ results = {}
279
+
280
+ for svc in services_to_test:
281
+ click.echo(f"\n🔄 Testing {svc.title()}...")
282
+
283
+ try:
284
+ if svc == "github":
285
+ success = syncer.git_sync()
286
+ else:
287
+ success = syncer.cloud_sync(svc)
288
+
289
+ if success:
290
+ click.echo(f"✅ {svc.title()}: Sync successful")
291
+ results[svc] = True
292
+ else:
293
+ click.echo(f"❌ {svc.title()}: Sync failed")
294
+ results[svc] = False
295
+
296
+ except Exception as e:
297
+ click.echo(f"💥 {svc.title()}: Error - {e}")
298
+ results[svc] = False
299
+
300
+ # Summary
301
+ successful = sum(results.values())
302
+ total = len(results)
303
+
304
+ click.echo(f"\n📊 Sync Test Results: {successful}/{total} successful")
305
+
306
+ if successful == total:
307
+ click.echo("🎉 All sync tests passed!")
308
+ else:
309
+ click.echo("⚠️ Some sync tests failed. Check configuration and connectivity.")
310
+ sys.exit(1)
311
+
312
+
313
+ if __name__ == "__main__":
314
+ test()
@@ -0,0 +1,242 @@
1
+ import os
2
+ import sys
3
+ from pathlib import Path
4
+
5
+ import click
6
+
7
+ # Add the app/video directory to the path so we can import the video processor
8
+ app_video_path = Path(__file__).parent.parent.parent / "app" / "video"
9
+ sys.path.insert(0, str(app_video_path))
10
+
11
+ # Lazy import variables
12
+ _video_module = None
13
+ _import_error = None
14
+
15
+
16
+ def _get_video_module():
17
+ """Lazy import of video processing module."""
18
+ global _video_module, _import_error
19
+
20
+ if _video_module is not None:
21
+ return _video_module
22
+
23
+ if _import_error is not None:
24
+ raise _import_error
25
+
26
+ try:
27
+ from mcli.app.video.video import (
28
+ CONFIG,
29
+ EnhancedVideoProcessor,
30
+ IntelligentVideoProcessor,
31
+ VideoProcessor,
32
+ )
33
+
34
+ _video_module = {
35
+ "VideoProcessor": VideoProcessor,
36
+ "EnhancedVideoProcessor": EnhancedVideoProcessor,
37
+ "IntelligentVideoProcessor": IntelligentVideoProcessor,
38
+ "CONFIG": CONFIG,
39
+ }
40
+ except ImportError:
41
+ try:
42
+ # Fallback import
43
+ import importlib.util
44
+
45
+ spec = importlib.util.spec_from_file_location("video", app_video_path / "video.py")
46
+ video_module = importlib.util.module_from_spec(spec)
47
+ spec.loader.exec_module(video_module)
48
+
49
+ _video_module = {
50
+ "VideoProcessor": video_module.VideoProcessor,
51
+ "EnhancedVideoProcessor": video_module.EnhancedVideoProcessor,
52
+ "IntelligentVideoProcessor": video_module.IntelligentVideoProcessor,
53
+ "CONFIG": video_module.CONFIG,
54
+ }
55
+ except Exception as e:
56
+ _import_error = ImportError(f"Could not import video processing modules: {e}")
57
+ # Return basic fallback
58
+ _video_module = {
59
+ "VideoProcessor": None,
60
+ "EnhancedVideoProcessor": None,
61
+ "IntelligentVideoProcessor": None,
62
+ "CONFIG": {"temp_dir": "./temp", "output_dir": "./output"},
63
+ }
64
+
65
+ return _video_module
66
+
67
+
68
+ @click.group()
69
+ def videos():
70
+ """Video processing and overlay removal tools."""
71
+ pass
72
+
73
+
74
+ @videos.command()
75
+ @click.argument("input_video", type=click.Path(exists=True))
76
+ @click.option("--output", "-o", type=click.Path(), help="Output video path")
77
+ @click.option("--fps", "-f", default=30, help="Frame extraction rate (default: 30)")
78
+ @click.option("--context", "-c", default=3, help="Temporal context window size (default: 3)")
79
+ @click.option(
80
+ "--method",
81
+ type=click.Choice(["intelligent", "basic"]),
82
+ default="intelligent",
83
+ help="Processing method (default: intelligent)",
84
+ )
85
+ @click.option("--dry-run", is_flag=True, help="Only extract frames and analyze video")
86
+ def remove_overlay(input_video, output, fps, context, method, dry_run):
87
+ """Remove overlays from videos with intelligent content reconstruction."""
88
+
89
+ try:
90
+ video_module = _get_video_module()
91
+ except ImportError as e:
92
+ click.echo(click.style(f"❌ Video processing modules not available: {e}", fg="red"))
93
+ return
94
+
95
+ VideoProcessor = video_module["VideoProcessor"]
96
+ EnhancedVideoProcessor = video_module["EnhancedVideoProcessor"]
97
+ IntelligentVideoProcessor = video_module["IntelligentVideoProcessor"]
98
+
99
+ if VideoProcessor is None:
100
+ click.echo(
101
+ click.style(
102
+ "❌ Video processing modules not available. Please install required dependencies.",
103
+ fg="red",
104
+ )
105
+ )
106
+ return
107
+
108
+ if method == "intelligent":
109
+ if IntelligentVideoProcessor is None:
110
+ click.echo(
111
+ click.style(
112
+ "❌ Intelligent video processor not available. Using basic processor.",
113
+ fg="yellow",
114
+ )
115
+ )
116
+ processor = EnhancedVideoProcessor() if EnhancedVideoProcessor else VideoProcessor()
117
+ else:
118
+ processor = IntelligentVideoProcessor()
119
+
120
+ if dry_run:
121
+ click.echo(
122
+ click.style(
123
+ "🔍 Dry run mode - extracting frames and analyzing video only", fg="cyan"
124
+ )
125
+ )
126
+ frame_paths = processor.extract_frames(input_video, fps)
127
+ click.echo(
128
+ click.style(
129
+ f"✅ Dry run complete. Extracted {len(frame_paths)} frames to {processor.temp_dir}",
130
+ fg="green",
131
+ )
132
+ )
133
+ click.echo(click.style(f"📁 Temp directory: {processor.temp_dir}", fg="blue"))
134
+ if hasattr(processor, "video_info"):
135
+ click.echo(click.style(f"🎬 Video info: {processor.video_info}", fg="blue"))
136
+ return
137
+
138
+ if hasattr(processor, "remove_overlay_from_video_intelligent"):
139
+ result = processor.remove_overlay_from_video_intelligent(
140
+ video_path=input_video, output_path=output, fps=fps, context_window=context
141
+ )
142
+ else:
143
+ result = processor.remove_overlay_from_video(
144
+ video_path=input_video, output_path=output, fps=fps
145
+ )
146
+ else:
147
+ processor = EnhancedVideoProcessor() if EnhancedVideoProcessor else VideoProcessor()
148
+ if hasattr(processor, "remove_overlay_from_video"):
149
+ result = processor.remove_overlay_from_video(
150
+ video_path=input_video, output_path=output, fps=fps
151
+ )
152
+ else:
153
+ click.echo(
154
+ click.style("❌ Overlay removal not available with current processor.", fg="red")
155
+ )
156
+ return
157
+
158
+ click.echo(f"Video processed successfully: {result}")
159
+
160
+
161
+ @videos.command()
162
+ @click.argument("input_video", type=click.Path(exists=True))
163
+ @click.option("--output", "-o", type=click.Path(), help="Output directory path")
164
+ @click.option("--fps", "-f", default=8, help="Frame extraction rate (default: 8)")
165
+ def extract_frames(input_video, output, fps):
166
+ """Extract frames from video to timestamped directory."""
167
+
168
+ try:
169
+ video_module = _get_video_module()
170
+ except ImportError as e:
171
+ click.echo(click.style(f"❌ Video processing modules not available: {e}", fg="red"))
172
+ return
173
+
174
+ VideoProcessor = video_module["VideoProcessor"]
175
+
176
+ if VideoProcessor is None:
177
+ click.echo(
178
+ click.style(
179
+ "❌ Video processing modules not available. Please install required dependencies.",
180
+ fg="red",
181
+ )
182
+ )
183
+ return
184
+
185
+ processor = VideoProcessor()
186
+
187
+ result_dir = processor.extract_frames_to_directory(
188
+ video_path=input_video, output_dir=output, fps=fps
189
+ )
190
+
191
+ click.echo(click.style(f"✅ Frame extraction complete!", fg="bright_green"))
192
+ click.echo(click.style(f"📁 Output directory: {result_dir}", fg="green"))
193
+
194
+
195
+ @videos.command()
196
+ @click.argument("frame_directory", type=click.Path(exists=True))
197
+ @click.option("--output", "-o", type=click.Path(), help="Output video path")
198
+ @click.option("--fps", "-f", default=30.0, help="Output video FPS (default: 30)")
199
+ def frames_to_video(frame_directory, output, fps):
200
+ """Convert frames back to video."""
201
+
202
+ try:
203
+ video_module = _get_video_module()
204
+ except ImportError as e:
205
+ click.echo(click.style(f"❌ Video processing modules not available: {e}", fg="red"))
206
+ return
207
+
208
+ VideoProcessor = video_module["VideoProcessor"]
209
+
210
+ if VideoProcessor is None:
211
+ click.echo(
212
+ click.style(
213
+ "❌ Video processing modules not available. Please install required dependencies.",
214
+ fg="red",
215
+ )
216
+ )
217
+ return
218
+
219
+ processor = VideoProcessor()
220
+
221
+ # Get all frame files from directory
222
+ frame_dir = Path(frame_directory)
223
+ frame_files = sorted([f for f in frame_dir.glob("*.png")])
224
+
225
+ if not frame_files:
226
+ click.echo(click.style("❌ No PNG frames found in directory", fg="red"))
227
+ return
228
+
229
+ if output is None:
230
+ output = str(frame_dir.parent / f"{frame_dir.name}_reconstructed.mp4")
231
+
232
+ frame_paths = [str(f) for f in frame_files]
233
+
234
+ # Set video info manually for frames_to_video
235
+ processor.video_info = {"original_fps": fps}
236
+
237
+ result = processor.frames_to_video(frame_paths, output, fps)
238
+ click.echo(f"Video created successfully: {result}")
239
+
240
+
241
+ if __name__ == "__main__":
242
+ videos()
@@ -0,0 +1,11 @@
1
+ import click
2
+
3
+
4
+ @click.group(name="wakatime")
5
+ def wakatime():
6
+ """WakaTime commands"""
7
+ pass
8
+
9
+
10
+ if __name__ == "__main__":
11
+ wakatime()
@@ -0,0 +1,37 @@
1
+ import click
2
+
3
+ from .daemon.api_daemon import api_daemon
4
+ from .daemon.commands import daemon
5
+ from .dashboard.dashboard_cmd import dashboard
6
+ from .file.file import file
7
+ from .git_commit.commands import git_commit_cli
8
+ from .politician_trading.commands import politician_trading_cli
9
+ from .scheduler.commands import scheduler
10
+ from .sync.sync_cmd import sync
11
+ from .videos.videos import videos
12
+
13
+
14
+ @click.group(name="workflow")
15
+ def workflow():
16
+ """Workflow commands"""
17
+ pass
18
+
19
+
20
+ # Add subcommands
21
+ def register_workflow_commands():
22
+ workflow.add_command(file)
23
+ workflow.add_command(videos)
24
+ workflow.add_command(daemon)
25
+ workflow.add_command(api_daemon)
26
+ workflow.add_command(dashboard)
27
+ workflow.add_command(git_commit_cli)
28
+ workflow.add_command(scheduler)
29
+ workflow.add_command(sync)
30
+ workflow.add_command(politician_trading_cli)
31
+
32
+
33
+ register_workflow_commands()
34
+
35
+
36
+ if __name__ == "__main__":
37
+ workflow()