ADMLab commited on
Commit
f6d2933
Β·
verified Β·
1 Parent(s): 185d632

Upload 3 files

Browse files
Files changed (3) hide show
  1. README.md +47 -7
  2. app.py +164 -0
  3. requirements.txt +9 -0
README.md CHANGED
@@ -1,12 +1,52 @@
1
  ---
2
- title: Admc
3
- emoji: 🌍
4
- colorFrom: green
5
- colorTo: yellow
6
  sdk: gradio
7
- sdk_version: 6.9.0
8
  app_file: app.py
9
- pinned: false
 
10
  ---
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: ADMC – AI Music Detection
3
+ emoji: 🎡
4
+ colorFrom: red
5
+ colorTo: indigo
6
  sdk: gradio
7
+ sdk_version: "4.0"
8
  app_file: app.py
9
+ pinned: true
10
+ license: apache-2.0
11
  ---
12
 
13
+ # 🎡 ADMC – Rilevamento AutorialitΓ  AI nella Musica
14
+
15
+ Parte del sistema di certificazione **ADMC (Artigiani della Musica Code)**.
16
+
17
+ Analizza brani musicali per rilevare la presenza di generazione AI, supportando
18
+ il rilascio del **Certificato di PaternitΓ  Umana dell'Opera Musicale**.
19
+
20
+ ## API REST
21
+
22
+ ### POST /analyze
23
+ Invia audio grezzo e riceve lo score AI:
24
+
25
+ ```bash
26
+ curl -X POST https://YOUR-SPACE.hf.space/analyze \
27
+ -H "Content-Type: audio/mpeg" \
28
+ --data-binary @brano.mp3
29
+ ```
30
+
31
+ Risposta:
32
+ ```json
33
+ [
34
+ {"label": "AI", "score": 0.12},
35
+ {"label": "Human", "score": 0.88}
36
+ ]
37
+ ```
38
+
39
+ ### GET /health
40
+ Verifica stato del servizio.
41
+
42
+ ## Configurazione nel Plugin WordPress
43
+
44
+ 1. Copia l'URL del tuo Space (es. `https://artigianidellamusica-admc.hf.space`)
45
+ 2. Incollalo nel campo **Endpoint personalizzato** nelle impostazioni del plugin ADMC
46
+ 3. Aggiungi il tuo **Hugging Face API Token** per autenticarti
47
+
48
+ ## Modello
49
+
50
+ Il modello predefinito Γ¨ `motheecreator/ai-music-detection`.
51
+ È consigliato addestrare un modello custom su dataset di musica umana vs AI
52
+ per massimizzare la precisione nel contesto specifico di ADMC.
app.py ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ ADMC – AI Music Detection API
3
+ Hugging Face Space (Gradio + FastAPI)
4
+
5
+ Questo Space espone un endpoint REST che il plugin WordPress ADMC puΓ² chiamare
6
+ per analizzare se un brano musicale Γ¨ stato generato da AI o creato da un umano.
7
+
8
+ Deploy su Hugging Face Spaces:
9
+ 1. Crea un nuovo Space (tipo: Gradio, SDK: Python)
10
+ 2. Carica questo file come app.py
11
+ 3. Aggiungi requirements.txt (vedi sotto)
12
+ 4. Configura l'URL del Space nelle impostazioni del plugin WordPress
13
+
14
+ Il plugin WP invia il file audio grezzo in POST e riceve una risposta JSON
15
+ nel formato standard HF audio-classification:
16
+ [{"label": "AI", "score": 0.87}, {"label": "Human", "score": 0.13}]
17
+ """
18
+
19
+ import gradio as gr
20
+ import numpy as np
21
+ import librosa
22
+ import torch
23
+ from fastapi import FastAPI, Request, HTTPException
24
+ from fastapi.responses import JSONResponse
25
+ from transformers import pipeline
26
+ import tempfile, os, io
27
+
28
+ # ── Model loading ──────────────────────────────────────────────────────────
29
+
30
+ MODEL_ID = "motheecreator/ai-music-detection" # Change to your fine-tuned model
31
+
32
+ print(f"Loading model: {MODEL_ID}")
33
+ try:
34
+ classifier = pipeline(
35
+ "audio-classification",
36
+ model=MODEL_ID,
37
+ device=0 if torch.cuda.is_available() else -1,
38
+ )
39
+ print("Model loaded successfully βœ…")
40
+ except Exception as e:
41
+ print(f"Warning: Could not load primary model ({e}). Using fallback feature extractor.")
42
+ classifier = None
43
+
44
+
45
+ def extract_features(audio_path: str) -> np.ndarray:
46
+ """Extract mel-spectrogram features from audio file (30s excerpt)."""
47
+ y, sr = librosa.load(audio_path, sr=22050, duration=30.0, mono=True)
48
+ mel = librosa.feature.melspectrogram(y=y, sr=sr, n_mels=128, fmax=8000)
49
+ mel_db = librosa.power_to_db(mel, ref=np.max)
50
+ return mel_db
51
+
52
+
53
+ def analyze_audio(audio_path: str) -> list[dict]:
54
+ """
55
+ Run AI detection on an audio file.
56
+ Returns list of {label, score} dicts.
57
+ """
58
+ if classifier is not None:
59
+ # Use HF pipeline directly
60
+ result = classifier(audio_path, top_k=2)
61
+ # Normalise labels to 'AI' / 'Human'
62
+ normalised = []
63
+ for item in result:
64
+ lbl = item["label"].upper()
65
+ if any(k in lbl for k in ["AI", "GENERATED", "FAKE", "SYNTH"]):
66
+ normalised.append({"label": "AI", "score": float(item["score"])})
67
+ else:
68
+ normalised.append({"label": "Human", "score": float(item["score"])})
69
+ return normalised
70
+
71
+ # ── Fallback: simple spectral analysis heuristic ──────────────────────
72
+ # This is a placeholder. Replace with a trained model for production use.
73
+ features = extract_features(audio_path)
74
+
75
+ # Heuristic: AI music often has very uniform spectral distribution
76
+ spectral_std = float(np.std(features))
77
+ spectral_mean = float(np.mean(np.abs(features)))
78
+
79
+ # Lower std relative to mean β†’ more "uniform" β†’ higher AI probability
80
+ # This is a very rough heuristic – fine-tune a real model for production!
81
+ ratio = spectral_std / (spectral_mean + 1e-6)
82
+ ai_score = max(0.0, min(1.0, 1.0 - (ratio / 3.0)))
83
+
84
+ return [
85
+ {"label": "AI", "score": round(ai_score, 4)},
86
+ {"label": "Human", "score": round(1.0 - ai_score, 4)},
87
+ ]
88
+
89
+
90
+ # ── Gradio UI (for human testing) ─────────────────────────────────────────
91
+
92
+ def gradio_analyze(audio_file):
93
+ if audio_file is None:
94
+ return "Nessun file caricato."
95
+ result = analyze_audio(audio_file)
96
+ ai_score = next((r["score"] for r in result if r["label"] == "AI"), 0.0)
97
+ human_score = next((r["score"] for r in result if r["label"] == "Human"), 1.0)
98
+ verdict = "πŸ€– Probabile AI" if ai_score > 0.5 else "βœ… Probabile umano"
99
+ return (
100
+ f"{verdict}\n\n"
101
+ f"AI Score: {ai_score*100:.1f}%\n"
102
+ f"Human Score: {human_score*100:.1f}%\n\n"
103
+ f"Soglia ADMC: 50% (configurabile nel plugin WP)"
104
+ )
105
+
106
+ demo = gr.Interface(
107
+ fn=gradio_analyze,
108
+ inputs=gr.Audio(type="filepath", label="Carica brano musicale (MP3/WAV/FLAC)"),
109
+ outputs=gr.Textbox(label="Risultato analisi ADMC"),
110
+ title="🎡 ADMC – Rilevamento AutorialitΓ  AI",
111
+ description=(
112
+ "Analizza un brano musicale per rilevare se Γ¨ stato generato da sistemi AI generativi. "
113
+ "Parte del sistema di certificazione ADMC – Artigiani della Musica."
114
+ ),
115
+ examples=[],
116
+ allow_flagging="never",
117
+ )
118
+
119
+ # ── FastAPI endpoint (called by WordPress plugin) ─────────────────────────
120
+
121
+ app = gr.mount_gradio_app(FastAPI(), demo, path="/")
122
+
123
+ @app.post("/analyze")
124
+ async def api_analyze(request: Request):
125
+ """
126
+ POST /analyze
127
+ Body: raw audio bytes (Content-Type: audio/mpeg | audio/wav | audio/flac ...)
128
+ Returns: [{"label": "AI", "score": 0.87}, {"label": "Human", "score": 0.13}]
129
+ """
130
+ content_type = request.headers.get("content-type", "")
131
+ ext_map = {
132
+ "audio/mpeg": ".mp3",
133
+ "audio/wav": ".wav",
134
+ "audio/x-wav": ".wav",
135
+ "audio/flac": ".flac",
136
+ "audio/ogg": ".ogg",
137
+ "audio/aiff": ".aiff",
138
+ }
139
+ ext = ext_map.get(content_type.split(";")[0].strip(), ".mp3")
140
+
141
+ audio_bytes = await request.body()
142
+ if len(audio_bytes) == 0:
143
+ raise HTTPException(status_code=400, detail="Nessun file audio ricevuto.")
144
+ if len(audio_bytes) > 100 * 1024 * 1024:
145
+ raise HTTPException(status_code=413, detail="File troppo grande (max 100 MB).")
146
+
147
+ # Save to temp file
148
+ with tempfile.NamedTemporaryFile(suffix=ext, delete=False) as tmp:
149
+ tmp.write(audio_bytes)
150
+ tmp_path = tmp.name
151
+
152
+ try:
153
+ result = analyze_audio(tmp_path)
154
+ except Exception as e:
155
+ raise HTTPException(status_code=500, detail=f"Errore analisi: {str(e)}")
156
+ finally:
157
+ os.unlink(tmp_path)
158
+
159
+ return JSONResponse(content=result)
160
+
161
+
162
+ @app.get("/health")
163
+ async def health():
164
+ return {"status": "ok", "model": MODEL_ID, "gpu": torch.cuda.is_available()}
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ gradio>=4.0.0
2
+ fastapi>=0.104.0
3
+ uvicorn>=0.24.0
4
+ transformers>=4.35.0
5
+ torch>=2.0.0
6
+ torchaudio>=2.0.0
7
+ librosa>=0.10.0
8
+ numpy>=1.24.0
9
+ soundfile>=0.12.0