Implement FASE 3, 4, 6 - 15 new MCP tools, 76/110 tasks complete
FASE 3 - Human Feel & Dynamics (10/11 tasks): - apply_clip_fades() - T041: Fade automation per section - write_volume_automation() - T042: Curves (linear, exp, s_curve, punch) - apply_sidechain_pump() - T045: Sidechain by intensity/style - inject_pattern_fills() - T048: Snare rolls, fills by density - humanize_set() - T050: Timing + velocity + groove automation FASE 4 - Key Compatibility & Tonal (9/12 tasks): - audio_key_compatibility.py: Full KEY_COMPATIBILITY_MATRIX - analyze_key_compatibility() - T053: Harmonic compatibility scoring - suggest_key_change() - T054: Circle of fifths modulation - validate_sample_key() - T055: Sample key validation - analyze_spectral_fit() - T057/T062: Spectral role matching FASE 6 - Mastering & QA (8/13 tasks): - calibrate_gain_staging() - T079: Auto gain by bus targets - run_mix_quality_check() - T085: LUFS, peaks, L/R balance - export_stem_mixdown() - T087: 24-bit/44.1kHz stem export New files: - audio_key_compatibility.py (T052) - bus_routing_fix.py (T101-T104) - validation_system_fix.py (T105-T106) Total: 76/110 tasks (69%), 71 MCP tools exposed Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
205
AbletonMCP_AI/MCP_Server/health_check.py
Normal file
205
AbletonMCP_AI/MCP_Server/health_check.py
Normal file
@@ -0,0 +1,205 @@
|
||||
"""
|
||||
health_check.py - Verificación de salud del sistema
|
||||
T107-T110: Health checks
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
import socket
|
||||
import json
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import Dict, Any, List
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger("HealthCheck")
|
||||
|
||||
|
||||
class AbletonMCPHealthCheck:
|
||||
"""Verifica la salud del sistema AbletonMCP-AI."""
|
||||
|
||||
def __init__(self):
|
||||
self.checks: List[Dict[str, Any]] = []
|
||||
self.all_passed = True
|
||||
|
||||
def check_ableton_connection(self) -> bool:
|
||||
"""Verifica conexión a Ableton Live."""
|
||||
try:
|
||||
# Intentar conectar al socket de Ableton
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.settimeout(2)
|
||||
result = sock.connect_ex(('127.0.0.1', 9877))
|
||||
sock.close()
|
||||
|
||||
if result == 0:
|
||||
self._add_check("Ableton Connection", True, "Connected on port 9877")
|
||||
return True
|
||||
else:
|
||||
self._add_check("Ableton Connection", False, f"Port 9877 not available (code {result})")
|
||||
return False
|
||||
except Exception as e:
|
||||
self._add_check("Ableton Connection", False, str(e))
|
||||
return False
|
||||
|
||||
def check_mcp_server(self) -> bool:
|
||||
"""Verifica que el servidor MCP responde."""
|
||||
try:
|
||||
# Intentar importar el módulo
|
||||
from full_integration import AbletonMCPFullPipeline
|
||||
pipeline = AbletonMCPFullPipeline()
|
||||
|
||||
self._add_check("MCP Server", True, "Module imports successfully")
|
||||
return True
|
||||
except Exception as e:
|
||||
self._add_check("MCP Server", False, f"Import error: {e}")
|
||||
return False
|
||||
|
||||
def check_sample_library(self) -> bool:
|
||||
"""Verifica librería de samples."""
|
||||
lib_paths = [
|
||||
Path.home() / "embeddings" / "all_tracks",
|
||||
Path("librerias/all_tracks"),
|
||||
]
|
||||
|
||||
for path in lib_paths:
|
||||
if path.exists():
|
||||
wav_files = list(path.rglob("*.wav"))
|
||||
if len(wav_files) > 0:
|
||||
self._add_check("Sample Library", True, f"{len(wav_files)} samples at {path}")
|
||||
return True
|
||||
|
||||
self._add_check("Sample Library", False, "No sample library found")
|
||||
return False
|
||||
|
||||
def check_dependencies(self) -> bool:
|
||||
"""Verifica dependencias de Python."""
|
||||
required = [
|
||||
'numpy',
|
||||
'sklearn',
|
||||
'sentence_transformers',
|
||||
]
|
||||
|
||||
missing = []
|
||||
for dep in required:
|
||||
try:
|
||||
__import__(dep)
|
||||
except ImportError:
|
||||
missing.append(dep)
|
||||
|
||||
if missing:
|
||||
self._add_check("Dependencies", False, f"Missing: {', '.join(missing)}")
|
||||
return False
|
||||
|
||||
self._add_check("Dependencies", True, "All required packages available")
|
||||
return True
|
||||
|
||||
def check_vector_index(self) -> bool:
|
||||
"""Verifica índice de vectores."""
|
||||
index_paths = [
|
||||
Path.home() / "embeddings" / "all_tracks" / ".sample_embeddings.json",
|
||||
Path("librerias/all_tracks/.sample_embeddings.json"),
|
||||
]
|
||||
|
||||
for path in index_paths:
|
||||
if path.exists():
|
||||
self._add_check("Vector Index", True, f"Index at {path}")
|
||||
return True
|
||||
|
||||
self._add_check("Vector Index", False, "No index found - will be built on first run")
|
||||
return False
|
||||
|
||||
def check_persistence_files(self) -> bool:
|
||||
"""Verifica archivos de persistencia."""
|
||||
data_dir = Path.home() / ".abletonmcp_ai"
|
||||
|
||||
files_to_check = [
|
||||
"sample_history.json",
|
||||
"sample_fatigue.json",
|
||||
"collection_coverage.json",
|
||||
]
|
||||
|
||||
all_ok = True
|
||||
for file in files_to_check:
|
||||
path = data_dir / file
|
||||
if path.exists():
|
||||
self._add_check(f"Persistence: {file}", True, "File exists")
|
||||
else:
|
||||
self._add_check(f"Persistence: {file}", False, "Will be created")
|
||||
all_ok = False
|
||||
|
||||
return all_ok
|
||||
|
||||
def check_tests(self) -> bool:
|
||||
"""Verifica que los tests pasan."""
|
||||
try:
|
||||
import subprocess
|
||||
result = subprocess.run(
|
||||
[sys.executable, "-m", "unittest", "tests.test_human_feel", "-v"],
|
||||
capture_output=True,
|
||||
timeout=30,
|
||||
cwd=Path(__file__).parent
|
||||
)
|
||||
|
||||
if result.returncode == 0:
|
||||
self._add_check("Unit Tests", True, "All tests passing")
|
||||
return True
|
||||
else:
|
||||
self._add_check("Unit Tests", False, "Some tests failed")
|
||||
return False
|
||||
except Exception as e:
|
||||
self._add_check("Unit Tests", False, f"Error running tests: {e}")
|
||||
return False
|
||||
|
||||
def _add_check(self, name: str, passed: bool, message: str):
|
||||
"""Agrega un check al reporte."""
|
||||
self.checks.append({
|
||||
'name': name,
|
||||
'passed': passed,
|
||||
'message': message
|
||||
})
|
||||
if not passed:
|
||||
self.all_passed = False
|
||||
|
||||
def run_all_checks(self) -> Dict[str, Any]:
|
||||
"""Ejecuta todos los checks."""
|
||||
logger.info("Running health checks...")
|
||||
logger.info("=" * 50)
|
||||
|
||||
self.check_ableton_connection()
|
||||
self.check_mcp_server()
|
||||
self.check_sample_library()
|
||||
self.check_dependencies()
|
||||
self.check_vector_index()
|
||||
self.check_persistence_files()
|
||||
self.check_tests()
|
||||
|
||||
# Summary
|
||||
passed = sum(1 for c in self.checks if c['passed'])
|
||||
total = len(self.checks)
|
||||
|
||||
logger.info("=" * 50)
|
||||
logger.info(f"RESULT: {passed}/{total} checks passed")
|
||||
|
||||
return {
|
||||
'all_passed': self.all_passed,
|
||||
'passed': passed,
|
||||
'total': total,
|
||||
'checks': self.checks
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
"""Ejecuta health check desde línea de comandos."""
|
||||
checker = AbletonMCPHealthCheck()
|
||||
result = checker.run_all_checks()
|
||||
|
||||
# Guardar resultado
|
||||
output_path = Path("health_check_result.json")
|
||||
with open(output_path, 'w') as f:
|
||||
json.dump(result, f, indent=2)
|
||||
|
||||
# Exit code
|
||||
sys.exit(0 if result['all_passed'] else 1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user