Skip to main content

Overview

Justina’s AI analysis system processes surgical telemetry data through a sophisticated 5-step pipeline that transforms raw movement coordinates into actionable feedback and performance scores.
The analysis pipeline is implemented in Python using NumPy and Pandas for high-performance numerical computing.

Pipeline Architecture

The complete analysis pipeline is orchestrated by the run_pipeline function:
def run_pipeline(trajectory_data: Dict) -> Tuple[float, str]:
    """
    PIPELINE COMPLETO DE ANÁLISIS DE 5 PASOS
    """
    # PASO 1: Ingesta y Limpieza
    df = _paso1_ingestar_y_limpiar(trajectory_data)
    
    # PASO 2: Métricas de Destreza (Física)
    metricas = _paso2_calcular_destreza(df)
    
    # PASO 3: Comparación con Patrón Oro
    benchmarking = _paso3_benchmarking(df)
    
    # PASO 4: Análisis de Riesgo
    riesgo = _paso4_analizar_riesgo(df)
    
    # PASO 5: Feedback Inteligente
    score, feedback = _paso5_generar_feedback(metricas, benchmarking, riesgo)
    
    return score, feedback

Step 1: Data Ingestion & Cleaning

Raw telemetry data is converted into a structured DataFrame:
def _paso1_ingestar_y_limpiar(trajectory_data: Dict) -> pd.DataFrame:
    movements = trajectory_data["movements"]
    df = pd.DataFrame([{
        "x": m["coordinates"][0],
        "y": m["coordinates"][1],
        "z": m["coordinates"][2] if len(m["coordinates"]) > 2 else 0,
        "event": m["event"],
        "timestamp": m["timestamp"]
    } for m in movements])
    
    df = df.sort_values("timestamp").reset_index(drop=True)
    # Tiempo relativo en segundos
    df["t"] = (df["timestamp"] - df["timestamp"].iloc[0]) / 1000.0
    df["dt"] = df["t"].diff().fillna(0)
    
    return df
  • Coordinate Extraction: Parse [x, y, z] arrays into columns
  • Temporal Sorting: Order movements chronologically
  • Relative Time: Convert absolute timestamps to relative seconds
  • Time Deltas: Calculate inter-sample intervals for velocity computation

Step 2: Dexterity Metrics

Physics-based calculations measure surgical skill:
def _paso2_calcular_destreza(df: pd.DataFrame) -> Dict:
    # Diferencias de posición
    dx = df["x"].diff().fillna(0)
    dy = df["y"].diff().fillna(0)
    dz = df["z"].diff().fillna(0)
    dist = np.sqrt(dx**2 + dy**2 + dz**2)
    
    # Velocidad (v = ds/dt)
    v = dist / df["dt"].replace(0, np.inf)
    v = v.replace(np.inf, 0)
    
    # Aceleración (a = dv/dt)
    a = v.diff() / df["dt"].replace(0, np.inf)
    a = a.replace(np.inf, 0)
    
    # Jerk (j = da/dt) - Suavidad
    j = a.diff() / df["dt"].replace(0, np.inf)
    j = j.replace(np.inf, 0)
    
    # Economía de movimiento
    total_dist = dist.sum()
    p1 = np.array([df["x"].iloc[0], df["y"].iloc[0], df["z"].iloc[0]])
    p2 = np.array([df["x"].iloc[-1], df["y"].iloc[-1], df["z"].iloc[-1]])
    direct_dist = np.linalg.norm(p2 - p1)
    economia = total_dist / direct_dist if direct_dist > 0 else 1.0
    
    return {
        "economia": economia,
        "v_avg": v.mean(),
        "a_max": a.abs().max(),
        "j_avg": j.abs().mean(),
        "total_dist": total_dist,
        "duration": df["t"].iloc[-1]
    }

Key Metrics

Economy of Movement

Ratio of total distance traveled to direct path (ideal: < 1.2x)

Average Velocity

Mean speed of instrument movement (units/second)

Peak Acceleration

Maximum rate of velocity change (smoothness indicator)

Jerk (Smoothness)

Rate of acceleration change - lower values indicate smoother motion
Economy of movement is the primary indicator of surgical efficiency. Values > 1.8x suggest poor path planning.

Step 3: Benchmarking Against Ideal

Compares the actual trajectory to an optimal straight-line path:
def _paso3_benchmarking(df: pd.DataFrame) -> Dict:
    # Benchmarking simple: Desviación vs Línea Recta Ideal
    p_start = np.array([df["x"].iloc[0], df["y"].iloc[0], df["z"].iloc[0]])
    p_end = np.array([df["x"].iloc[-1], df["y"].iloc[-1], df["z"].iloc[-1]])
    
    def dist_to_line(p, a, b):
        if np.all(a == b): return np.linalg.norm(p-a)
        return np.linalg.norm(np.cross(b-a, a-p)) / np.linalg.norm(b-a)
    
    desviaciones = [dist_to_line(
        np.array([r.x, r.y, r.z]), p_start, p_end
    ) for r in df.itertuples()]
    
    return {
        "desviacion_avg": np.mean(desviaciones),
        "precision": max(0, 100 - np.mean(desviaciones) * 10)
    }
The precision score measures how closely the surgeon follows the ideal path:
  • Calculate perpendicular distance from each point to the straight line
  • Average all deviations
  • Convert to 0-100 scale (10 units of deviation = 100 point penalty)
Precision > 70% indicates good trajectory control.

Step 4: Risk Analysis

Identifies critical surgical errors and danger zones:
def _paso4_analizar_riesgo(df: pd.DataFrame) -> Dict:
    tumor_touches = (df["event"] == "TUMOR_TOUCH").sum()
    hemorrhages = (df["event"] == "HEMORRHAGE").sum()
    
    # Análisis de cuadrantes (simple 2D para visualización)
    mid_x = (df["x"].max() + df["x"].min()) / 2
    mid_y = (df["y"].max() + df["y"].min()) / 2
    
    problemas = df[df["event"].isin(["TUMOR_TOUCH", "HEMORRHAGE"])]
    cuadrantes_criticos = []
    if not problemas.empty:
        for p in problemas.itertuples():
            pos = ""
            pos += "Sup" if p.y > mid_y else "Inf"
            pos += "-Der" if p.x > mid_x else "-Izq"
            if pos not in cuadrantes_criticos:
                cuadrantes_criticos.append(pos)
            
    return {
        "touches": int(tumor_touches),
        "hemorrhages": int(hemorrhages),
        "cuadrantes": cuadrantes_criticos
    }

Risk Categories

Tumor Touches

Count of tumor contact events (affects score)

Hemorrhages

Vascular damage incidents (critical errors)

Critical Quadrants

Spatial regions where errors occurred
Quadrant analysis helps surgeons identify specific areas where they need to improve precision.

Step 5: Intelligent Feedback Generation

Synthesizes all metrics into a score and actionable recommendations:
def _paso5_generar_feedback(m: Dict, b: Dict, r: Dict) -> Tuple[float, str]:
    score = 100.0
    score -= r["touches"] * 8
    score -= r["hemorrhages"] * 15
    if m["economia"] > 1.5: score -= 10
    score = max(0, min(100, score))
    
    status = (
        "🌟 EXCELENTE" if score >= 90 else
        "✅ BUENO" if score >= 75 else
        "⚠️ MEJORABLE" if score >= 60 else
        "❌ DEFICIENTE"
    )
    
    feedback = f"""### {status} - Score: {score:.1f}/100

#### 🚨 ALERTAS CRÍTICAS
- Hemorragias: {r["hemorrhages"]} {"(REVISAR TÉCNICA)" if r["hemorrhages"] > 0 else "(Ninguna)"}
- Contactos Tumor: {r["touches"]}
- Cuadrantes de Riesgo: {", ".join(r["cuadrantes"]) if r["cuadrantes"] else "Ninguno"}

#### 📊 MÉTRICAS DE DESTREZA
- **Economía de Movimiento:** {m["economia"]:.2f}x (Ideal < 1.2x)
- **Fluidez (Jerk Promedio):** {m["j_avg"]:.2f} 
- **Precisión vs Patrón Oro:** {b["precision"]:.1f}%

#### 📈 ESTADÍSTICAS
- **Duración Total:** {m["duration"]:.1f}s
- **Distancia Recorrida:** {m["total_dist"]:.2f} unidades
- **Velocidad Promedio:** {m["v_avg"]:.2f} u/s

#### 💡 RECOMENDACIONES
"""
    if r["hemorrhages"] > 0:
        feedback += "- Priorizar control vascular en cuadrantes críticos.\n"
    if m["economia"] > 1.8:
        feedback += "- Planificar trayectorias más directas para reducir fatiga.\n"
    if b["precision"] < 70:
        feedback += "- Mantener mayor estabilidad en la ejecución del path ideal.\n"
    if score < 80:
        feedback += "- Incrementar práctica en simulador para mejorar coordinación motora.\n"
    
    return score, feedback.strip()

Scoring Algorithm

Starting from a base score of 100:
  • -8 points per tumor touch
  • -15 points per hemorrhage (critical error)
  • -10 points if economy of movement > 1.5x
Final score is clamped to [0, 100] range.
  • 90-100: 🌟 EXCELENTE - Expert level
  • 75-89: ✅ BUENO - Proficient
  • 60-74: ⚠️ MEJORABLE - Needs improvement
  • 0-59: ❌ DEFICIENTE - Requires significant practice

Feedback Structure

The generated feedback includes:
  1. Critical Alerts: Hemorrhages and tumor contacts with severity indicators
  2. Dexterity Metrics: Economy, smoothness, and precision measurements
  3. Statistics: Duration, distance, and velocity summaries
  4. Personalized Recommendations: Specific advice based on performance gaps
Recommendations are conditionally included based on specific metric thresholds, ensuring feedback is relevant and actionable.

AI Pipeline Integration

The analysis is triggered when the backend saves a surgery:
if (movement.event() == SurgeryEvent.FINISH) {
    surgery.endSurgery();
    surgeryRepository.save(surgery);
    activeSessions.remove(session.getId());
    
    AIWebSocketHandler.notificarNuevaCirugia(surgery.getId());
}
The AI service:
  1. Receives notification via WebSocket
  2. Fetches trajectory data from database
  3. Runs the 5-step pipeline
  4. Updates surgery record with score and feedback
  5. Notifies frontend that analysis is complete

Performance Characteristics

Processing Time

Typical analysis completes in < 2 seconds for 5-minute simulation

Data Volume

Handles 10,000+ movement points efficiently

Accuracy

Physics-based metrics provide objective measurements

Scalability

Pandas vectorization enables batch processing

Example Analysis Output

### ✅ BUENO - Score: 78.0/100

#### 🚨 ALERTAS CRÍTICAS
- Hemorragias: 1 (REVISAR TÉCNICA)
- Contactos Tumor: 3
- Cuadrantes de Riesgo: Sup-Der, Inf-Izq

#### 📊 MÉTRICAS DE DESTREZA
- **Economía de Movimiento:** 1.42x (Ideal < 1.2x)
- **Fluidez (Jerk Promedio):** 0.15
- **Precisión vs Patrón Oro:** 72.3%

#### 📈 ESTADÍSTICAS
- **Duración Total:** 287.3s
- **Distancia Recorrida:** 42.78 unidades
- **Velocidad Promedio:** 0.15 u/s

#### 💡 RECOMENDACIONES
- Priorizar control vascular en cuadrantes críticos.
- Planificar trayectorias más directas para reducir fatiga.

Machine Learning Future Enhancements

Planned improvements to the AI pipeline:
  • Pattern Recognition: Identify common error patterns using clustering
  • Comparative Analysis: Benchmark against cohort of similar skill levels
  • Predictive Modeling: Forecast areas of difficulty before they occur
  • Adaptive Feedback: Personalize recommendations based on learning history

Next Steps

Real-Time Telemetry

Learn how movement data is captured and transmitted

Performance Scoring

Deep dive into the scoring algorithm

Build docs developers (and LLMs) love