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.
- mcli/app/chat_cmd.py +42 -0
- mcli/app/commands_cmd.py +226 -0
- mcli/app/completion_cmd.py +216 -0
- mcli/app/completion_helpers.py +288 -0
- mcli/app/cron_test_cmd.py +697 -0
- mcli/app/logs_cmd.py +419 -0
- mcli/app/main.py +492 -0
- mcli/app/model/model.py +1060 -0
- mcli/app/model_cmd.py +227 -0
- mcli/app/redis_cmd.py +269 -0
- mcli/app/video/video.py +1114 -0
- mcli/app/visual_cmd.py +303 -0
- mcli/chat/chat.py +2409 -0
- mcli/chat/command_rag.py +514 -0
- mcli/chat/enhanced_chat.py +652 -0
- mcli/chat/system_controller.py +1010 -0
- mcli/chat/system_integration.py +1016 -0
- mcli/cli.py +25 -0
- mcli/config.toml +20 -0
- mcli/lib/api/api.py +586 -0
- mcli/lib/api/daemon_client.py +203 -0
- mcli/lib/api/daemon_client_local.py +44 -0
- mcli/lib/api/daemon_decorator.py +217 -0
- mcli/lib/api/mcli_decorators.py +1032 -0
- mcli/lib/auth/auth.py +85 -0
- mcli/lib/auth/aws_manager.py +85 -0
- mcli/lib/auth/azure_manager.py +91 -0
- mcli/lib/auth/credential_manager.py +192 -0
- mcli/lib/auth/gcp_manager.py +93 -0
- mcli/lib/auth/key_manager.py +117 -0
- mcli/lib/auth/mcli_manager.py +93 -0
- mcli/lib/auth/token_manager.py +75 -0
- mcli/lib/auth/token_util.py +1011 -0
- mcli/lib/config/config.py +47 -0
- mcli/lib/discovery/__init__.py +1 -0
- mcli/lib/discovery/command_discovery.py +274 -0
- mcli/lib/erd/erd.py +1345 -0
- mcli/lib/erd/generate_graph.py +453 -0
- mcli/lib/files/files.py +76 -0
- mcli/lib/fs/fs.py +109 -0
- mcli/lib/lib.py +29 -0
- mcli/lib/logger/logger.py +611 -0
- mcli/lib/performance/optimizer.py +409 -0
- mcli/lib/performance/rust_bridge.py +502 -0
- mcli/lib/performance/uvloop_config.py +154 -0
- mcli/lib/pickles/pickles.py +50 -0
- mcli/lib/search/cached_vectorizer.py +479 -0
- mcli/lib/services/data_pipeline.py +460 -0
- mcli/lib/services/lsh_client.py +441 -0
- mcli/lib/services/redis_service.py +387 -0
- mcli/lib/shell/shell.py +137 -0
- mcli/lib/toml/toml.py +33 -0
- mcli/lib/ui/styling.py +47 -0
- mcli/lib/ui/visual_effects.py +634 -0
- mcli/lib/watcher/watcher.py +185 -0
- mcli/ml/api/app.py +215 -0
- mcli/ml/api/middleware.py +224 -0
- mcli/ml/api/routers/admin_router.py +12 -0
- mcli/ml/api/routers/auth_router.py +244 -0
- mcli/ml/api/routers/backtest_router.py +12 -0
- mcli/ml/api/routers/data_router.py +12 -0
- mcli/ml/api/routers/model_router.py +302 -0
- mcli/ml/api/routers/monitoring_router.py +12 -0
- mcli/ml/api/routers/portfolio_router.py +12 -0
- mcli/ml/api/routers/prediction_router.py +267 -0
- mcli/ml/api/routers/trade_router.py +12 -0
- mcli/ml/api/routers/websocket_router.py +76 -0
- mcli/ml/api/schemas.py +64 -0
- mcli/ml/auth/auth_manager.py +425 -0
- mcli/ml/auth/models.py +154 -0
- mcli/ml/auth/permissions.py +302 -0
- mcli/ml/backtesting/backtest_engine.py +502 -0
- mcli/ml/backtesting/performance_metrics.py +393 -0
- mcli/ml/cache.py +400 -0
- mcli/ml/cli/main.py +398 -0
- mcli/ml/config/settings.py +394 -0
- mcli/ml/configs/dvc_config.py +230 -0
- mcli/ml/configs/mlflow_config.py +131 -0
- mcli/ml/configs/mlops_manager.py +293 -0
- mcli/ml/dashboard/app.py +532 -0
- mcli/ml/dashboard/app_integrated.py +738 -0
- mcli/ml/dashboard/app_supabase.py +560 -0
- mcli/ml/dashboard/app_training.py +615 -0
- mcli/ml/dashboard/cli.py +51 -0
- mcli/ml/data_ingestion/api_connectors.py +501 -0
- mcli/ml/data_ingestion/data_pipeline.py +567 -0
- mcli/ml/data_ingestion/stream_processor.py +512 -0
- mcli/ml/database/migrations/env.py +94 -0
- mcli/ml/database/models.py +667 -0
- mcli/ml/database/session.py +200 -0
- mcli/ml/experimentation/ab_testing.py +845 -0
- mcli/ml/features/ensemble_features.py +607 -0
- mcli/ml/features/political_features.py +676 -0
- mcli/ml/features/recommendation_engine.py +809 -0
- mcli/ml/features/stock_features.py +573 -0
- mcli/ml/features/test_feature_engineering.py +346 -0
- mcli/ml/logging.py +85 -0
- mcli/ml/mlops/data_versioning.py +518 -0
- mcli/ml/mlops/experiment_tracker.py +377 -0
- mcli/ml/mlops/model_serving.py +481 -0
- mcli/ml/mlops/pipeline_orchestrator.py +614 -0
- mcli/ml/models/base_models.py +324 -0
- mcli/ml/models/ensemble_models.py +675 -0
- mcli/ml/models/recommendation_models.py +474 -0
- mcli/ml/models/test_models.py +487 -0
- mcli/ml/monitoring/drift_detection.py +676 -0
- mcli/ml/monitoring/metrics.py +45 -0
- mcli/ml/optimization/portfolio_optimizer.py +834 -0
- mcli/ml/preprocessing/data_cleaners.py +451 -0
- mcli/ml/preprocessing/feature_extractors.py +491 -0
- mcli/ml/preprocessing/ml_pipeline.py +382 -0
- mcli/ml/preprocessing/politician_trading_preprocessor.py +569 -0
- mcli/ml/preprocessing/test_preprocessing.py +294 -0
- mcli/ml/scripts/populate_sample_data.py +200 -0
- mcli/ml/tasks.py +400 -0
- mcli/ml/tests/test_integration.py +429 -0
- mcli/ml/tests/test_training_dashboard.py +387 -0
- mcli/public/oi/oi.py +15 -0
- mcli/public/public.py +4 -0
- mcli/self/self_cmd.py +1246 -0
- mcli/workflow/daemon/api_daemon.py +800 -0
- mcli/workflow/daemon/async_command_database.py +681 -0
- mcli/workflow/daemon/async_process_manager.py +591 -0
- mcli/workflow/daemon/client.py +530 -0
- mcli/workflow/daemon/commands.py +1196 -0
- mcli/workflow/daemon/daemon.py +905 -0
- mcli/workflow/daemon/daemon_api.py +59 -0
- mcli/workflow/daemon/enhanced_daemon.py +571 -0
- mcli/workflow/daemon/process_cli.py +244 -0
- mcli/workflow/daemon/process_manager.py +439 -0
- mcli/workflow/daemon/test_daemon.py +275 -0
- mcli/workflow/dashboard/dashboard_cmd.py +113 -0
- mcli/workflow/docker/docker.py +0 -0
- mcli/workflow/file/file.py +100 -0
- mcli/workflow/gcloud/config.toml +21 -0
- mcli/workflow/gcloud/gcloud.py +58 -0
- mcli/workflow/git_commit/ai_service.py +328 -0
- mcli/workflow/git_commit/commands.py +430 -0
- mcli/workflow/lsh_integration.py +355 -0
- mcli/workflow/model_service/client.py +594 -0
- mcli/workflow/model_service/download_and_run_efficient_models.py +288 -0
- mcli/workflow/model_service/lightweight_embedder.py +397 -0
- mcli/workflow/model_service/lightweight_model_server.py +714 -0
- mcli/workflow/model_service/lightweight_test.py +241 -0
- mcli/workflow/model_service/model_service.py +1955 -0
- mcli/workflow/model_service/ollama_efficient_runner.py +425 -0
- mcli/workflow/model_service/pdf_processor.py +386 -0
- mcli/workflow/model_service/test_efficient_runner.py +234 -0
- mcli/workflow/model_service/test_example.py +315 -0
- mcli/workflow/model_service/test_integration.py +131 -0
- mcli/workflow/model_service/test_new_features.py +149 -0
- mcli/workflow/openai/openai.py +99 -0
- mcli/workflow/politician_trading/commands.py +1790 -0
- mcli/workflow/politician_trading/config.py +134 -0
- mcli/workflow/politician_trading/connectivity.py +490 -0
- mcli/workflow/politician_trading/data_sources.py +395 -0
- mcli/workflow/politician_trading/database.py +410 -0
- mcli/workflow/politician_trading/demo.py +248 -0
- mcli/workflow/politician_trading/models.py +165 -0
- mcli/workflow/politician_trading/monitoring.py +413 -0
- mcli/workflow/politician_trading/scrapers.py +966 -0
- mcli/workflow/politician_trading/scrapers_california.py +412 -0
- mcli/workflow/politician_trading/scrapers_eu.py +377 -0
- mcli/workflow/politician_trading/scrapers_uk.py +350 -0
- mcli/workflow/politician_trading/scrapers_us_states.py +438 -0
- mcli/workflow/politician_trading/supabase_functions.py +354 -0
- mcli/workflow/politician_trading/workflow.py +852 -0
- mcli/workflow/registry/registry.py +180 -0
- mcli/workflow/repo/repo.py +223 -0
- mcli/workflow/scheduler/commands.py +493 -0
- mcli/workflow/scheduler/cron_parser.py +238 -0
- mcli/workflow/scheduler/job.py +182 -0
- mcli/workflow/scheduler/monitor.py +139 -0
- mcli/workflow/scheduler/persistence.py +324 -0
- mcli/workflow/scheduler/scheduler.py +679 -0
- mcli/workflow/sync/sync_cmd.py +437 -0
- mcli/workflow/sync/test_cmd.py +314 -0
- mcli/workflow/videos/videos.py +242 -0
- mcli/workflow/wakatime/wakatime.py +11 -0
- mcli/workflow/workflow.py +37 -0
- mcli_framework-7.0.0.dist-info/METADATA +479 -0
- mcli_framework-7.0.0.dist-info/RECORD +186 -0
- mcli_framework-7.0.0.dist-info/WHEEL +5 -0
- mcli_framework-7.0.0.dist-info/entry_points.txt +7 -0
- mcli_framework-7.0.0.dist-info/licenses/LICENSE +21 -0
- 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,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()
|