File size: 2,990 Bytes
e3bdc52
 
 
72892b6
e3bdc52
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72892b6
 
 
 
 
 
 
 
 
 
e3bdc52
 
 
 
 
 
72892b6
e3bdc52
 
 
 
 
 
 
72892b6
e3bdc52
 
 
 
 
72892b6
e3bdc52
 
 
 
 
 
72892b6
 
 
e3bdc52
 
72892b6
 
e3bdc52
72892b6
 
 
 
e3bdc52
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import torch
import librosa
import numpy as np
import sys
from transformers import AutoFeatureExtractor, ASTForAudioClassification

# Modelo AST (Audio Spectrogram Transformer)
# Usamos o modelo base do MIT como referência para análise espectral
MODEL_NAME = "MIT/ast-finetuned-audioset-10-10-0.4593"

# Singleton para carregar o modelo apenas uma vez
_extractor = None
_model = None

def get_ast_resources():
    global _extractor, _model
    if _extractor is None or _model is None:
        print(f"Carregando motor AST: {MODEL_NAME}...")
        _extractor = AutoFeatureExtractor.from_pretrained(MODEL_NAME)
        model = ASTForAudioClassification.from_pretrained(MODEL_NAME)
        
        # --- OTIMIZAÇÃO: Quantização Dinâmica (CPU) ---
        if not torch.cuda.is_available():
            print("Aplicando Quantização Dinâmica no AST...", file=sys.stderr)
            model = torch.quantization.quantize_dynamic(
                model, {torch.nn.Linear}, dtype=torch.qint8
            )
        
        _model = model
        _model.eval()
    return _extractor, _model

def run_ast_inference(file_path):
    """
    Executa a análise via Audio Spectrogram Transformer.
    Focado em detectar artefatos de compressão e texturas sintéticas.
    """
    try:
        extractor, model = get_ast_resources()

        # Carrega áudio (resample para 16kHz conforme exigido pelo AST)
        audio, _ = librosa.load(file_path, sr=16000)
        
        # Padronização para 10 segundos
        if len(audio) > 160000:
            audio = audio[:160000]
        else:
            audio = np.pad(audio, (0, 160000 - len(audio)), mode='constant')

        # Extração de Features
        inputs = extractor(audio, sampling_rate=16000, return_tensors="pt")

        with torch.no_grad():
            outputs = model(**inputs)
            logits = outputs.logits
            
        # Refinamento do Score Espectral:
        # Em vez de apenas variância, olhamos para a dispersão das top-k classes.
        # Vozes sintéticas tendem a gerar incerteza em modelos genéricos.
        probs = torch.nn.functional.softmax(logits, dim=-1)
        
        # Cálculo de Entropia como medida de 'estranheza' do sinal
        entropy = -torch.sum(probs * torch.log(probs + 1e-9)).item()
        
        # Normalização (Heurística baseada em observação do AudioSet)
        # Sinais naturais tendem a ter entropia mais baixa (classes mais claras)
        # Sinais sintéticos/ruidosos espalham a probabilidade.
        risk_score = min(max((entropy - 3.0) / 4.0, 0.0), 1.0) 

        return {
            "risk_score": risk_score,
            "engine": "AST-Transformer",
            "status": "success"
        }

    except Exception as e:
        print(f"Erro no motor AST: {e}")
        return {"error": str(e), "risk_score": 0.0}

if __name__ == "__main__":
    # Teste simples
    import sys
    if len(sys.argv) > 1:
        print(run_ast_inference(sys.argv[1]))