Skip to content

Paso 4: Benchmark y Integración - whisper.cpp optimizado para AMD A4-9125 #9

Description

@Charly-bite

Paso 4: Benchmark y Integración - whisper.cpp optimizado para AMD A4-9125

Estado Actual ✅

  • whisper-amd compilado con OpenCL + OpenBLAS
  • Modelos TINY (75MB) y BASE (141MB) descargados
  • Configuración optimizada para 2 threads
  • Sistema listo para pruebas de rendimiento

Script de Benchmark Completo

#!/bin/bash
# benchmark_whisper_amd_final.sh

echo "⚡ BENCHMARK FINAL WHISPER-AMD EN AMD A4-9125"
echo "============================================="

source "$HOME/.whisper_amd_config" 2>/dev/null || {
    echo "❌ Configuración no encontrada"
    echo "💡 Ejecuta: source ~/.whisper_amd_config"
    exit 1
}

echo "🔧 Configuración actual:"
echo "📁 Modelos: $WHISPER_MODELS_DIR"
echo "🧵 Threads: $WHISPER_THREADS"
echo "🧠 Modelo por defecto: $WHISPER_DEFAULT_MODEL"

# Crear audio de prueba realista
echo -e "\n🎙️ Creando audio de prueba..."
TEST_AUDIO="/tmp/whisper_benchmark_test.wav"

# Crear audio sintético que simule habla (más realista que un tono)
if command -v ffmpeg >/dev/null 2>&1; then
    # Generar audio que simula habla humana con variaciones de frecuencia
    ffmpeg -f lavfi -i "sine=frequency=440:duration=1,sine=frequency=880:duration=1,sine=frequency=220:duration=1" \
           -filter_complex "aformat=channel_layouts=mono:sample_rates=16000" \
           -t 15 "$TEST_AUDIO" -y 2>/dev/null
    echo "✅ Audio de prueba creado: 15 segundos"
elif command -v sox >/dev/null 2>&1; then
    # Fallback con sox
    sox -n -r 16000 -c 1 "$TEST_AUDIO" synth 15 sine 440 sine 880 sine 220
    echo "✅ Audio de prueba creado con sox: 15 segundos"
else
    echo "❌ Necesitas ffmpeg o sox para crear audio de prueba"
    echo "💡 Instala: sudo apt install ffmpeg"
    exit 1
fi

# Función de benchmark mejorada
run_detailed_benchmark() {
    local model="$1"
    local model_file="$WHISPER_MODELS_DIR/ggml-${model}.bin"
    
    if [ ! -f "$model_file" ]; then
        echo "❌ Modelo $model no encontrado: $model_file"
        return 1
    fi
    
    echo -e "\n🧠 BENCHMARK MODELO: $model"
    echo "=============================="
    echo "📊 Archivo: $(basename "$model_file")"
    
    # Información del modelo
    model_size=$(stat -c%s "$model_file" 2>/dev/null | awk '{print int($1/1024/1024)"MB"}')
    echo "💾 Tamaño del modelo: $model_size"
    
    # Limpiar archivos previos
    rm -f /tmp/whisper_benchmark_test.* 2>/dev/null
    
    echo "🚀 Iniciando transcripción..."
    echo "⏱️ Midiendo rendimiento..."
    
    # Benchmark detallado con información del sistema
    start_time=$(date +%s.%N)
    start_mem=$(free -m | awk 'NR==2{printf "%.0f", $3}')
    
    # Ejecutar transcripción con parámetros optimizados para A4-9125
    if timeout 180s whisper-amd \
        -m "$model_file" \
        -t 2 \
        -p 1 \
        -l auto \
        --output-txt \
        --output-srt \
        --output-dir "/tmp" \
        --print-progress \
        "$TEST_AUDIO" > "/tmp/whisper_output_$model.log" 2>&1; then
        
        end_time=$(date +%s.%N)
        end_mem=$(free -m | awk 'NR==2{printf "%.0f", $3}')
        
        # Calcular métricas
        duration=$(echo "$end_time - $start_time" | bc 2>/dev/null || echo "N/A")
        mem_used=$((end_mem - start_mem))
        audio_duration=15 # segundos de audio
        
        echo "✅ Transcripción completada"
        echo "⏱️ Tiempo total: ${duration}s"
        echo "🧠 Memoria usada: ${mem_used}MB"
        
        # Calcular factor de tiempo real
        if [ "$duration" != "N/A" ]; then
            factor=$(echo "scale=2; $duration / $audio_duration" | bc 2>/dev/null || echo "N/A")
            echo "🚀 Factor tiempo real: ${factor}x"
            
            # Evaluación de rendimiento
            if (( $(echo "$factor < 0.5" | bc -l 2>/dev/null || echo 0) )); then
                echo "🏆 RENDIMIENTO: EXCELENTE (Más de 2x tiempo real)"
            elif (( $(echo "$factor < 1.0" | bc -l 2>/dev/null || echo 0) )); then
                echo "🎯 RENDIMIENTO: MUY BUENO (Más rápido que tiempo real)"
            elif (( $(echo "$factor < 2.0" | bc -l 2>/dev/null || echo 0) )); then
                echo "✅ RENDIMIENTO: BUENO (Hasta 2x tiempo real)"
            elif (( $(echo "$factor < 4.0" | bc -l 2>/dev/null || echo 0) )); then
                echo "👍 RENDIMIENTO: ACEPTABLE (Hasta 4x tiempo real)"
            else
                echo "⚠️ RENDIMIENTO: LENTO (Más de 4x tiempo real)"
            fi
            
            # Calcular velocidad de procesamiento
            speed=$(echo "scale=2; $audio_duration / $duration" | bc 2>/dev/null || echo "N/A")
            echo "📈 Velocidad de procesamiento: ${speed}x"
        fi
        
        # Mostrar resultado de transcripción
        result_file="/tmp/whisper_benchmark_test.txt"
        if [ -f "$result_file" ]; then
            result_text=$(cat "$result_file" | head -c 200)
            echo "📝 Resultado (primeros 200 chars): $result_text..."
            
            # Contar palabras transcritas
            word_count=$(cat "$result_file" | wc -w)
            echo "📊 Palabras transcritas: $word_count"
        fi
        
        # Mostrar log si hay errores
        if [ -f "/tmp/whisper_output_$model.log" ]; then
            if grep -q "error\|Error\|ERROR" "/tmp/whisper_output_$model.log"; then
                echo "⚠️ Errores encontrados en el log:"
                grep -i error "/tmp/whisper_output_$model.log" | head -3
            fi
        fi
        
        return 0
        
    else
        echo "❌ Transcripción falló o timeout (180s)"
        if [ -f "/tmp/whisper_output_$model.log" ]; then
            echo "📋 Últimas líneas del log:"
            tail -5 "/tmp/whisper_output_$model.log"
        fi
        return 1
    fi
}

# Información del sistema antes del benchmark
echo -e "\n🖥️ INFORMACIÓN DEL SISTEMA:"
echo "=========================="
echo "🔧 CPU: $(grep 'model name' /proc/cpuinfo | head -1 | cut -d: -f2 | xargs)"
echo "🧠 RAM total: $(free -h | awk 'NR==2{print $2}')"
echo "🧠 RAM disponible: $(free -h | awk 'NR==2{print $7}')"
echo "💿 Espacio /tmp: $(df -h /tmp | awk 'NR==2{print $4}')"
echo "🌡️ Temperatura CPU: $(sensors 2>/dev/null | grep -i 'core 0' | awk '{print $3}' || echo 'N/A')"

# Ejecutar benchmarks
echo -e "\n🏁 EJECUTANDO BENCHMARKS:"
echo "========================="

# Benchmark modelo TINY
run_detailed_benchmark "tiny"

# Pequeña pausa entre benchmarks
echo -e "\n⏸️ Pausa de 5 segundos entre benchmarks..."
sleep 5

# Benchmark modelo BASE
run_detailed_benchmark "base"

# Resumen final
echo -e "\n📊 RESUMEN FINAL - AMD A4-9125:"
echo "==============================="
echo "🎯 Mejor para velocidad: MODELO TINY"
echo "⚖️ Mejor equilibrio: MODELO BASE"
echo "🔧 Configuración óptima: 2 threads, 1 processor"
echo "🚀 OpenCL: Habilitado (Radeon R3)"
echo "⚡ OpenBLAS: Habilitado (matemáticas optimizadas)"

echo -e "\n💡 RECOMENDACIONES DE USO:"
echo "========================="
echo "📹 Transcripción en tiempo real: whisper-tiny"
echo "🎓 Clases/reuniones: whisper-base"
echo "📝 Documentos importantes: whisper-base"
echo "🎙️ Podcasts/entrevistas: whisper-base"

echo -e "\n🧹 Limpiando archivos temporales..."
rm -f /tmp/whisper_benchmark_test.* /tmp/whisper_output_*.log 2>/dev/null

echo -e "\n🎉 ¡BENCHMARK COMPLETADO!"
echo "whisper-amd optimizado para AMD A4-9125 ✅"

Actualización del ProcessingAgent para usar whisper-amd nativo

# agents/processing_agent_whisper_amd.py

import os
import subprocess
import sys
from pathlib import Path
import datetime

# Add the project root to Python path
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))

from mcp.agent_framework import AgentFramework

class ProcessingAgentWhisperAMD(AgentFramework):
    """
    ProcessingAgent optimizado para AMD A4-9125 usando whisper-amd nativo.
    Reemplaza completamente el uso de openai-whisper por whisper.cpp compilado.
    """
    def __init__(self):
        super().__init__("ProcessingAgentWhisperAMD")
        
        self.config = self._load_config()
        self.audio_settings = self.config.get('audio_settings', {})
        
        # Paths
        self.transcripts_dir = Path('recordings/transcripts')
        self.transcripts_dir.mkdir(parents=True, exist_ok=True)
        
        # Configuración whisper-amd
        self.whisper_amd_binary = "/usr/local/bin/whisper-amd"
        self.whisper_models_dir = Path.home() / "whisper_models"
        
        # Modelos disponibles (en orden de preferencia para A4-9125)
        self.available_models = {
            "tiny": "ggml-tiny.bin",      # Más rápido, buena precisión
            "base": "ggml-base.bin",      # Equilibrado (recomendado)
            "small": "ggml-small.bin"     # Mejor precisión, más lento
        }
        
        # Verificar instalación
        self._verify_whisper_amd_installation()
        
        print(f"[{self.agent_name}] Initialized with whisper-amd native support.")
        print(f"[{self.agent_name}] Models directory: {self.whisper_models_dir}")
        print(f"[{self.agent_name}] Available models: {list(self.available_models.keys())}")

    def _verify_whisper_amd_installation(self):
        """Verifica que whisper-amd esté instalado y funcional."""
        if not Path(self.whisper_amd_binary).exists():
            print(f"[{self.agent_name}] ERROR: whisper-amd not found at {self.whisper_amd_binary}")
            print(f"[{self.agent_name}] Please install whisper-amd first.")
            self.whisper_amd_available = False
            return
            
        try:
            # Probar que whisper-amd responde
            result = subprocess.run([self.whisper_amd_binary, "--help"], 
                                  capture_output=True, text=True, timeout=10)
            if result.returncode == 0:
                print(f"[{self.agent_name}] whisper-amd verified and functional.")
                self.whisper_amd_available = True
            else:
                print(f"[{self.agent_name}] WARNING: whisper-amd exists but not responding correctly.")
                self.whisper_amd_available = False
        except Exception as e:
            print(f"[{self.agent_name}] ERROR testing whisper-amd: {e}")
            self.whisper_amd_available = False

    def _get_model_path(self, model_name: str) -> Path:
        """Obtiene la ruta completa del modelo especificado."""
        if model_name not in self.available_models:
            print(f"[{self.agent_name}] WARNING: Unknown model '{model_name}', using 'base'")
            model_name = "base"
            
        model_file = self.available_models[model_name]
        model_path = self.whisper_models_dir / model_file
        
        if not model_path.exists():
            print(f"[{self.agent_name}] ERROR: Model file not found: {model_path}")
            print(f"[{self.agent_name}] Please download models first.")
            return None
            
        return model_path

    def transcribe_audio_amd_optimized(self, audio_filepath: Path, 
                                     output_filename: str = None, 
                                     language: str = None,
                                     model: str = "base") -> dict:
        """
        Transcripción optimizada usando whisper-amd nativo para AMD A4-9125.
        
        Args:
            audio_filepath (Path): Ruta del archivo de audio
            output_filename (str): Nombre base para archivos de salida
            language (str): Código de idioma ('es', 'en', etc.) o None para auto-detect
            model (str): Modelo a usar ('tiny', 'base', 'small')
        
        Returns:
            dict: Información de la transcripción o None si falla
        """
        if not self.whisper_amd_available:
            print(f"[{self.agent_name}] whisper-amd not available, cannot transcribe.")
            return None
            
        if not audio_filepath.exists():
            print(f"[{self.agent_name}] Audio file not found: {audio_filepath}")
            return None

        # Obtener ruta del modelo
        model_path = self._get_model_path(model)
        if not model_path:
            return None

        print(f"[{self.agent_name}] Starting AMD-optimized transcription...")
        print(f"[{self.agent_name}] Audio: {audio_filepath.name}")
        print(f"[{self.agent_name}] Model: {model} ({model_path.name})")
        print(f"[{self.agent_name}] Language: {language or 'auto-detect'}")
        
        # Preparar comando whisper-amd optimizado para A4-9125
        whisper_cmd = [
            self.whisper_amd_binary,
            "-m", str(model_path),
            "-t", "2",                    # 2 threads óptimo para A4-9125
            "-p", "1",                    # 1 processor
            "--output-txt",               # Generar archivo .txt
            "--output-srt",               # Generar subtítulos .srt
            "--output-vtt",               # Generar subtítulos .vtt
            "--output-dir", str(self.transcripts_dir),
        ]
        
        # Agregar idioma si se especifica
        if language:
            whisper_cmd.extend(["-l", language])
        
        # Agregar archivo de audio
        whisper_cmd.append(str(audio_filepath))
        
        try:
            print(f"[{self.agent_name}] Executing: {' '.join(whisper_cmd[:8])}... [truncated]")
            
            # Ejecutar transcripción
            start_time = datetime.datetime.now()
            result = subprocess.run(
                whisper_cmd,
                capture_output=True,
                text=True,
                timeout=600  # 10 minutos máximo
            )
            end_time = datetime.datetime.now()
            duration = (end_time - start_time).total_seconds()
            
            if result.returncode == 0:
                # Buscar archivo de texto generado
                base_name = audio_filepath.stem
                txt_file = self.transcripts_dir / f"{base_name}.txt"
                srt_file = self.transcripts_dir / f"{base_name}.srt"
                
                transcript_text = ""
                if txt_file.exists():
                    with open(txt_file, 'r', encoding='utf-8') as f:
                        transcript_text = f.read().strip()
                
                if transcript_text:
                    print(f"[{self.agent_name}] AMD transcription successful!")
                    print(f"[{self.agent_name}] Duration: {duration:.2f}s")
                    print(f"[{self.agent_name}] Output files: {txt_file.name}")
                    if srt_file.exists():
                        print(f"[{self.agent_name}] Subtitles: {srt_file.name}")
                    
                    # Calcular estadísticas
                    word_count = len(transcript_text.split())
                    char_count = len(transcript_text)
                    
                    return {
                        "text": transcript_text,
                        "path": str(txt_file),
                        "srt_path": str(srt_file) if srt_file.exists() else None,
                        "language": language or "auto-detected",
                        "model": model,
                        "method": "whisper-amd-native",
                        "duration_seconds": duration,
                        "word_count": word_count,
                        "char_count": char_count,
                        "processing_speed": f"{duration:.2f}s"
                    }
                else:
                    print(f"[{self.agent_name}] Transcription completed but no text found.")
            else:
                print(f"[{self.agent_name}] whisper-amd failed with return code: {result.returncode}")
                print(f"[{self.agent_name}] Error output: {result.stderr}")
                
        except subprocess.TimeoutExpired:
            print(f"[{self.agent_name}] Transcription timeout (10 minutes exceeded)")
        except Exception as e:
            print(f"[{self.agent_name}] Error during AMD transcription: {e}")
            
        return None

    def run(self):
        """Ejecución de prueba del ProcessingAgent optimizado."""
        print(f"[{self.agent_name}] Running AMD-optimized ProcessingAgent test...")
        
        # Buscar archivo de audio para probar
        raw_recordings_path = Path('recordings/raw')
        if not raw_recordings_path.exists():
            print(f"[{self.agent_name}] No recordings directory found. Creating test audio...")
            # Aquí podrías crear un audio de prueba o usar el del benchmark
            test_audio = Path("/tmp/whisper_benchmark_test.wav")
            if test_audio.exists():
                print(f"[{self.agent_name}] Using benchmark test audio for demonstration.")
                self._test_transcription(test_audio)
            else:
                print(f"[{self.agent_name}] No test audio available.")
            return
            
        # Buscar archivos de audio existentes
        audio_files = list(raw_recordings_path.glob('*.wav'))
        if not audio_files:
            print(f"[{self.agent_name}] No audio files found in {raw_recordings_path}")
            return
            
        # Usar el archivo más reciente
        latest_audio = max(audio_files, key=lambda x: x.stat().st_mtime)
        print(f"[{self.agent_name}] Testing with latest audio: {latest_audio.name}")
        
        self._test_transcription(latest_audio)

    def _test_transcription(self, audio_file: Path):
        """Prueba de transcripción con diferentes modelos."""
        print(f"[{self.agent_name}] Testing transcription with different models...")
        
        # Probar modelo tiny (más rápido)
        print(f"\n[{self.agent_name}] Testing TINY model...")
        result_tiny = self.transcribe_audio_amd_optimized(
            audio_file, 
            language="es", 
            model="tiny"
        )
        
        if result_tiny:
            print(f"[{self.agent_name}] TINY result: {result_tiny['text'][:100]}...")
            print(f"[{self.agent_name}] TINY speed: {result_tiny['processing_speed']}")
        
        # Probar modelo base (equilibrado)
        print(f"\n[{self.agent_name}] Testing BASE model...")
        result_base = self.transcribe_audio_amd_optimized(
            audio_file, 
            language="es", 
            model="base"
        )
        
        if result_base:
            print(f"[{self.agent_name}] BASE result: {result_base['text'][:100]}...")
            print(f"[{self.agent_name}] BASE speed: {result_base['processing_speed']}")
            
        print(f"[{self.agent_name}] AMD ProcessingAgent test completed!")


if __name__ == "__main__":
    # Test del ProcessingAgent optimizado
    processing_agent = ProcessingAgentWhisperAMD()
    processing_agent.run()

Script de Prueba Completa de Integración

#!/bin/bash
# test_complete_integration.sh

echo "🚀 PRUEBA COMPLETA DE INTEGRACIÓN WHISPER-AMD"
echo "============================================="

source "$HOME/.whisper_amd_config" 2>/dev/null || {
    echo "❌ Configuración no encontrada"
    exit 1
}

echo "✅ Configuración cargada"
echo "📁 Modelos en: $WHISPER_MODELS_DIR"

# Crear audio de prueba realista
echo -e "\n🎙️ Creando audio de prueba con texto en español..."
TEST_AUDIO="/tmp/test_integration_spanish.wav"

if command -v espeak >/dev/null 2>&1; then
    # Crear audio con texto en español usando espeak
    echo "Hola, esta es una prueba de transcripción en español para verificar el funcionamiento de whisper en AMD A4-9125. La ciberseguridad es importante." | \
    espeak -v es -s 150 -w "$TEST_AUDIO"
    echo "✅ Audio de prueba creado con espeak"
elif command -v ffmpeg >/dev/null 2>&1; then
    # Fallback con ffmpeg
    ffmpeg -f lavfi -i "sine=frequency=440:duration=10" -ar 16000 -ac 1 "$TEST_AUDIO" -y 2>/dev/null
    echo "✅ Audio sintético creado"
else
    echo "❌ Necesitas espeak o ffmpeg"
    exit 1
fi

# Prueba completa con ambos modelos
echo -e "\n🧪 PRUEBA COMPLETA DE TRANSCRIPCIÓN:"
echo "=================================="

for model in tiny base; do
    echo -e "\n🧠 Probando modelo: $model"
    echo "----------------------"
    
    output_dir="/tmp/whisper_test_$model"
    mkdir -p "$output_dir"
    
    start_time=$(date +%s)
    
    if whisper-amd \
        -m "$WHISPER_MODELS_DIR/ggml-$model.bin" \
        -t 2 \
        -p 1 \
        -l es \
        --output-txt \
        --output-srt \
        --output-dir "$output_dir" \
        "$TEST_AUDIO"; then
        
        end_time=$(date +%s)
        duration=$((end_time - start_time))
        
        echo "✅ Transcripción $model completada en ${duration}s"
        
        # Mostrar resultado
        txt_file="$output_dir/$(basename "$TEST_AUDIO" .wav).txt"
        if [ -f "$txt_file" ]; then
            echo "📝 Resultado:"
            cat "$txt_file"
            
            # Contar palabras
            word_count=$(cat "$txt_file" | wc -w)
            echo "📊 Palabras: $word_count"
        fi
        
        # Verificar subtítulos
        srt_file="$output_dir/$(basename "$TEST_AUDIO" .wav).srt"
        if [ -f "$srt_file" ]; then
            echo "📹 Subtítulos SRT generados"
        fi
        
    else
        echo "❌ Error en transcripción $model"
    fi
done

# Limpiar
rm -f "$TEST_AUDIO" 2>/dev/null
rm -rf /tmp/whisper_test_* 2>/dev/null

echo -e "\n🎉 ¡INTEGRACIÓN COMPLETADA!"
echo "whisper-amd listo para usar en producción ✅"

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions