|
|
|
|
|
|
|
|
import numpy as np |
|
|
import librosa |
|
|
import librosa.display |
|
|
import matplotlib.pyplot as plt |
|
|
import noisereduce as nr |
|
|
import soundfile as sf |
|
|
import hashlib |
|
|
import os |
|
|
import gradio as gr |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AudioManipulator: |
|
|
def charger_audio(self, path): |
|
|
return librosa.load(path, sr=44100) |
|
|
|
|
|
def reduire_bruit(self, y, sr): |
|
|
return nr.reduce_noise(y=y, sr=sr, prop_decrease=0.8) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AuthenticMusicShield: |
|
|
def __init__(self): |
|
|
print("🚀 Lancement du Bouclier v4.2 (Expert Radio & Jury)...") |
|
|
self.ia = None |
|
|
|
|
|
def load_model(self): |
|
|
if self.ia is None: |
|
|
try: |
|
|
from transformers import pipeline |
|
|
self.ia = pipeline("audio-classification", model="MIT/ast-finetuned-audioset-10-10-0.4593") |
|
|
print("✅ Modèle IA chargé.") |
|
|
except Exception as e: |
|
|
print(f"⚠️ Échec du chargement du modèle IA : {e}") |
|
|
self.ia = None |
|
|
|
|
|
def get_sha256(self, path): |
|
|
with open(path, "rb") as f: |
|
|
return hashlib.sha256(f.read()).hexdigest() |
|
|
|
|
|
def generer_spectrogramme(self, y, sr): |
|
|
plt.figure(figsize=(10, 4)) |
|
|
S = librosa.feature.melspectrogram(y=y, sr=sr, n_mels=128) |
|
|
S_dB = librosa.power_to_db(S, ref=np.max) |
|
|
librosa.display.specshow(S_dB, sr=sr, x_axis='time', y_axis='mel', cmap='magma') |
|
|
plt.colorbar(format='%+2.0f dB') |
|
|
plt.title('Empreinte Spectrale (Texture)') |
|
|
plt.tight_layout() |
|
|
plot_path = "spectrum.png" |
|
|
plt.savefig(plot_path) |
|
|
plt.close() |
|
|
return plot_path |
|
|
|
|
|
def analyser_expert(self, path): |
|
|
if path is None: |
|
|
return None, "En attente...", None |
|
|
|
|
|
try: |
|
|
|
|
|
self.load_model() |
|
|
|
|
|
file_name = os.path.basename(path) |
|
|
file_hash = self.get_sha256(path) |
|
|
|
|
|
y, sr = librosa.load(path, sr=44100) |
|
|
y_denoised = nr.reduce_noise(y=y, sr=sr) |
|
|
|
|
|
|
|
|
pitches, _ = librosa.piptrack(y=y, sr=sr) |
|
|
jitter = np.std(pitches[pitches > 0]) / 1000 if np.any(pitches > 0) else 0 |
|
|
stft = np.abs(librosa.stft(y_denoised)) |
|
|
score_sid = 95.0 if np.mean(stft[-1]) > 0.0003 else 15.0 |
|
|
|
|
|
|
|
|
top_label = "Inconnu" |
|
|
score_ia = 0 |
|
|
if self.ia: |
|
|
res_ia = self.ia(path) |
|
|
top_label = res_ia[0]['label'] |
|
|
score_ia = res_ia[0]['score'] * 100 |
|
|
|
|
|
|
|
|
is_radio_speech = any(tag in top_label for tag in ["Speech", "Conversation", "Hum", "Radio"]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if score_sid > 80: |
|
|
verdict = "✅ AUTHENTIQUE CERTIFIÉ (SID)" |
|
|
note = "Badge SID détecté. Intégrité et provenance garanties." |
|
|
elif is_radio_speech: |
|
|
if 0.01 < jitter < 1.5: |
|
|
verdict = "✅ AUTHENTIQUE (Humain/Radio)" |
|
|
note = f"Source réelle confirmée par IA ({top_label})." |
|
|
else: |
|
|
verdict = "🔴 DEEPFAKE DÉTECTÉ" |
|
|
note = "Anomalie physique extrême sur voix humaine." |
|
|
elif "Music" in top_label or "Singing" in top_label or "Inconnu" in top_label: |
|
|
if 0.12 < jitter < 0.85: |
|
|
verdict = "✅ AUTHENTIQUE (Artiste)" |
|
|
note = "Vibration humaine naturelle validée." |
|
|
else: |
|
|
verdict = "🔴 AI COVER / DEEPFAKE DÉTECTÉ" |
|
|
note = f"Instabilité ou perfection artificielle. Jitter: {jitter:.4f}" |
|
|
else: |
|
|
verdict = "⚠️ ANALYSE INCONCLUSIVE" |
|
|
note = "Signal non identifié par le bouclier." |
|
|
|
|
|
|
|
|
spec_img = self.generer_spectrogramme(y, sr) |
|
|
|
|
|
|
|
|
report = f"\n{'='*45}\n🛡️ RAPPORT D'EXPERTISE v4.2 JURY\n{'='*45}\n" |
|
|
report += f" 📂 NOM FICHIER : {file_name}\n" |
|
|
report += f" 🔑 ID SHA-256 : {file_hash[:16]}...\n" |
|
|
report += f" 🎙️ SOURCE IA : {top_label} ({score_ia:.1f}%)\n" |
|
|
report += f" 🧬 INDICE VIE : {jitter:.4f}\n" |
|
|
report += f"{'-'*45}\n" |
|
|
report += f" >>> VERDICT : {verdict}\n" |
|
|
report += f" >>> NOTE : {note}\n{'='*45}\n" |
|
|
|
|
|
return spec_img, report, {"Verdict": verdict, "Jitter": round(jitter, 4), "SID": score_sid} |
|
|
|
|
|
except Exception as e: |
|
|
return None, f"Erreur : {str(e)}", None |
|
|
|
|
|
|
|
|
shield = AuthenticMusicShield() |
|
|
with gr.Blocks(theme=gr.themes.Soft()) as demo: |
|
|
gr.Markdown("# 🛡️ Antigravity Shield v4.2 PRO (Jury Edition Optimized)") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(): |
|
|
audio_input = gr.Audio(type="filepath", label="Audio Input") |
|
|
run_btn = gr.Button("🔍 ANALYSER L'AUTHENTICITÉ", variant="primary") |
|
|
|
|
|
with gr.Column(): |
|
|
image_output = gr.Image(label="Spectrogramme (Preuve Visuelle)") |
|
|
report_output = gr.Textbox(label="Rapport Officiel", lines=10) |
|
|
metrics_output = gr.Json(label="Métriques Techniques") |
|
|
|
|
|
run_btn.click( |
|
|
fn=shield.analyser_expert, |
|
|
inputs=audio_input, |
|
|
outputs=[image_output, report_output, metrics_output] |
|
|
) |
|
|
|
|
|
|
|
|
demo.launch(ssr_mode=False) |
|
|
|