aneela-pervez commited on
Commit
9a40160
·
verified ·
1 Parent(s): d18e0aa

Update fake_audio.py

Browse files
Files changed (1) hide show
  1. fake_audio.py +47 -37
fake_audio.py CHANGED
@@ -1,15 +1,14 @@
1
  # -*- coding: utf-8 -*-
2
  """
3
  Cleaned fake vs forged vs real audio module (Gradio UI & Notebook Magics removed)
 
4
  """
5
 
6
- # Note: In pure Python files, install requirements via terminal, not in the code.
7
- # pip install torch librosa numpy laion-clap groq openai-whisper transformers
8
- # apt-get install -y ffmpeg
9
-
10
  import os
 
11
  from huggingface_hub import login
12
  import torch
 
13
  import librosa
14
  import numpy as np
15
  import numpy
@@ -21,7 +20,6 @@ from transformers import AutoFeatureExtractor, AutoModelForAudioClassification,
21
  from groq import Groq
22
 
23
  # --- FETCH SECRETS & LOGIN ---
24
- # Hugging Face Secrets se keys fetch karna
25
  HF_TOKEN = os.environ.get("HF_TOKEN")
26
  GROQ_API_KEY = os.environ.get("GROQ_API_KEY")
27
 
@@ -36,7 +34,7 @@ client = Groq(api_key=GROQ_API_KEY)
36
  DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
37
  AST_MODEL_PATH = "aneela-pervez/FAKE-AUDIO"
38
 
39
- # --- 🏷️ CATEGORIZED FORENSIC LABELS ---
40
  FORENSIC_CATEGORIES = {
41
  "AUTHENTIC": ["Natural human speech", "Human voice with natural breathing", "Consistent room ambiance"],
42
  "AI_SYNTHETIC": ["AI voice clone robotic smoothness", "Synthetic neural vocoder", "Deepfake metallic resonance"],
@@ -57,46 +55,60 @@ try:
57
  except Exception as e:
58
  print(f"⚠️ AST Model issue (using default logic if fails): {e}")
59
 
60
- # Note: laion_clap loads weights during initialization.
61
- # PyTorch 2.6+ compatibility fix for CLAP checkpoint loading
62
- import torch.serialization
63
- torch.serialization.add_safe_globals([numpy.core.multiarray.scalar])
64
 
65
- # Monkey-patch torch.load to force weights_only=False for CLAP
66
- _orig_load = torch.load
67
- def _safe_load(f, map_location=None, pickle_module=None, weights_only=True, **kwargs):
68
- return _orig_load(f, map_location=map_location, weights_only=False, **kwargs)
69
- torch.load = _safe_load
 
 
 
 
70
 
 
71
  clap_model = laion_clap.CLAP_Module(enable_fusion=False, amodel='HTSAT-tiny').to(DEVICE)
72
- clap_model.load_ckpt(
73
- ckpt="https://huggingface.co/lukewys/laion_clap/resolve/main/music_audioset_epoch_15_esc_90.14.pt"
74
- )
75
 
76
- # Restore original torch.load after CLAP is loaded
77
- torch.load = _orig_load
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
  def extract_dna_embeddings(y):
80
- # Ensure standard numpy array shape before processing
81
  y = np.ascontiguousarray(y)
82
  inputs = id_extractor(y, sampling_rate=16000, return_tensors="pt")
83
-
84
- # 🛡️ EXPLICIT TENSOR CONVERSION FIX:
85
  inputs = {k: (v.clone().detach() if isinstance(v, torch.Tensor) else torch.tensor(v)).to(DEVICE) for k, v in inputs.items()}
86
-
87
  with torch.no_grad():
88
  logits = id_model(**inputs).logits
89
  emb = torch.mean(logits, dim=1).cpu().numpy()
90
  return normalize(emb)
91
 
 
92
  def analyze_voice_forensics(audio_path):
93
  try:
94
  y, sr = librosa.load(audio_path, sr=16000)
95
  y_48, _ = librosa.load(audio_path, sr=48000)
96
  y = y / (np.max(np.abs(y)) + 1e-9)
97
- y = np.ascontiguousarray(y) # Data alignment safety
98
 
99
- # 1. 🛡️ SEGMENT-WISE CROSS VALIDATION
100
  segments = np.array_split(y, 3)
101
  seg_embs = [extract_dna_embeddings(s) for s in segments]
102
  cos_sim = cosine_similarity(seg_embs[0], seg_embs[-1])[0][0]
@@ -105,23 +117,18 @@ def analyze_voice_forensics(audio_path):
105
  # 2. FEATURE EXTRACTION
106
  transcription = whisper_model.transcribe(audio_path)["text"]
107
  inputs = ast_extractor(y, sampling_rate=16000, return_tensors="pt")
108
-
109
- # 🛡️ EXPLICIT TENSOR CONVERSION FIX:
110
  inputs = {k: (v.clone().detach() if isinstance(v, torch.Tensor) else torch.tensor(v)).to(DEVICE) for k, v in inputs.items()}
111
-
112
  with torch.no_grad():
113
  ast_prob = torch.nn.functional.softmax(ast_model(**inputs).logits, dim=-1).cpu().numpy()[0][1]
114
  ast_score = ast_prob * 100
115
 
116
- # 🛡️ CLAP TENSOR FIX: Reverted to your strict `torch.from_numpy` logic to prevent errors
117
  audio_emb_np = clap_model.get_audio_embedding_from_data(x=[y_48])
118
  text_emb_np = clap_model.get_text_embedding(ALL_LABELS)
119
-
120
- # Explicitly converting NumPy arrays to PyTorch Tensors before calculating similarity
121
  audio_emb = torch.from_numpy(audio_emb_np).to(DEVICE)
122
  text_emb = torch.from_numpy(text_emb_np).to(DEVICE)
123
  c_sims = torch.nn.functional.cosine_similarity(audio_emb, text_emb)
124
-
125
  top_idx = torch.argmax(c_sims).item()
126
  clap_label = ALL_LABELS[top_idx]
127
 
@@ -133,14 +140,14 @@ def analyze_voice_forensics(audio_path):
133
 
134
  num_edits = len(np.where(np.diff(librosa.onset.onset_strength(y=y, sr=16000)) > 6.5)[0])
135
 
136
- # --- 🧠 STEP 3: FUZZY LOGIC MEMBERSHIP SCORING ---
137
  mu_ai = min(1.0, max(0.0, (ast_score - 40) / 45))
138
  mu_spliced = min(1.0, max(0.0, (num_edits - 8) / 10))
139
  dna_conf = (cos_sim - 0.85) / 0.10
140
  cat_conf = 1.0 if category == "AUTHENTIC" else 0.0
141
  mu_auth = min(1.0, max(0.0, (dna_conf + cat_conf) / 2))
142
 
143
- # --- 🛡️ STEP 4: BALANCED FUZZY DECISION ENGINE (V4.0) ---
144
  if mu_auth > 0.80 and mu_spliced < 0.75:
145
  verdict = "✅ AUTHENTIC HUMAN VOICE"
146
  category_override = "AUTHENTIC"
@@ -151,7 +158,7 @@ def analyze_voice_forensics(audio_path):
151
  verdict = "⚠️ MANIPULATED REAL VOICE (Spliced)"
152
  category_override = "MANIPULATED"
153
 
154
- # --- 🔥 ALIGNED PROFESSIONAL REASONING ---
155
  audit_context = (f"Verdict: {verdict}. Category: {category_override}. Metrics: ID {cos_sim:.2f}, "
156
  f"Texture {ast_score:.1f}%, Cuts {num_edits}. "
157
  f"Fuzzy Scores: AI={mu_ai:.2f}, Spliced={mu_spliced:.2f}, Auth={mu_auth:.2f}")
@@ -161,7 +168,10 @@ def analyze_voice_forensics(audio_path):
161
  "emphasize that DNA integrity confirms human origin despite high spectral texture. "
162
  "Give a 2-line direct forensic conclusion.")
163
 
164
- res = client.chat.completions.create(model="llama-3.3-70b-versatile", messages=[{"role": "user", "content": prompt}])
 
 
 
165
  reasoning = res.choices[0].message.content
166
 
167
  evidence = f"Category: {category} | ID: {cos_sim:.2f} | Texture: {ast_score:.1f}% | Cuts: {num_edits}"
 
1
  # -*- coding: utf-8 -*-
2
  """
3
  Cleaned fake vs forged vs real audio module (Gradio UI & Notebook Magics removed)
4
+ Fixed for PyTorch 2.6+ compatibility with LAION-CLAP checkpoints
5
  """
6
 
 
 
 
 
7
  import os
8
+ import urllib.request
9
  from huggingface_hub import login
10
  import torch
11
+ import torch.serialization
12
  import librosa
13
  import numpy as np
14
  import numpy
 
20
  from groq import Groq
21
 
22
  # --- FETCH SECRETS & LOGIN ---
 
23
  HF_TOKEN = os.environ.get("HF_TOKEN")
24
  GROQ_API_KEY = os.environ.get("GROQ_API_KEY")
25
 
 
34
  DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
35
  AST_MODEL_PATH = "aneela-pervez/FAKE-AUDIO"
36
 
37
+ # --- CATEGORIZED FORENSIC LABELS ---
38
  FORENSIC_CATEGORIES = {
39
  "AUTHENTIC": ["Natural human speech", "Human voice with natural breathing", "Consistent room ambiance"],
40
  "AI_SYNTHETIC": ["AI voice clone robotic smoothness", "Synthetic neural vocoder", "Deepfake metallic resonance"],
 
55
  except Exception as e:
56
  print(f"⚠️ AST Model issue (using default logic if fails): {e}")
57
 
58
+ # --- CLAP MODEL LOADING (PyTorch 2.6+ Full Fix) ---
59
+ # Step 1: Checkpoint pehle local mein download karein
60
+ CLAP_CKPT_URL = "https://huggingface.co/lukewys/laion_clap/resolve/main/music_audioset_epoch_15_esc_90.14.pt"
61
+ CLAP_CKPT_PATH = "/tmp/clap_music_audioset.pt"
62
 
63
+ if not os.path.exists(CLAP_CKPT_PATH):
64
+ print("Downloading CLAP checkpoint to local disk...")
65
+ urllib.request.urlretrieve(CLAP_CKPT_URL, CLAP_CKPT_PATH)
66
+ print("✅ CLAP checkpoint downloaded!")
67
+ else:
68
+ print("✅ CLAP checkpoint already cached.")
69
+
70
+ # Step 2: PyTorch 2.6+ safe globals fix
71
+ torch.serialization.add_safe_globals([numpy.core.multiarray.scalar])
72
 
73
+ # Step 3: CLAP model initialize karein
74
  clap_model = laion_clap.CLAP_Module(enable_fusion=False, amodel='HTSAT-tiny').to(DEVICE)
 
 
 
75
 
76
+ # Step 4: Manually load checkpoint with strict=False
77
+ # strict=False: unexpected/missing keys jaise position_ids ko ignore karta hai
78
+ print("🔄 Loading CLAP checkpoint (strict=False)...")
79
+ ckpt = torch.load(CLAP_CKPT_PATH, map_location=DEVICE, weights_only=False)
80
+
81
+ # Checkpoint structure check
82
+ if "state_dict" in ckpt:
83
+ state_dict = ckpt["state_dict"]
84
+ elif "model" in ckpt:
85
+ state_dict = ckpt["model"]
86
+ else:
87
+ state_dict = ckpt
88
+
89
+ clap_model.model.load_state_dict(state_dict, strict=False)
90
+ clap_model.eval()
91
+ print("✅ CLAP model loaded successfully!")
92
+
93
 
94
  def extract_dna_embeddings(y):
 
95
  y = np.ascontiguousarray(y)
96
  inputs = id_extractor(y, sampling_rate=16000, return_tensors="pt")
 
 
97
  inputs = {k: (v.clone().detach() if isinstance(v, torch.Tensor) else torch.tensor(v)).to(DEVICE) for k, v in inputs.items()}
 
98
  with torch.no_grad():
99
  logits = id_model(**inputs).logits
100
  emb = torch.mean(logits, dim=1).cpu().numpy()
101
  return normalize(emb)
102
 
103
+
104
  def analyze_voice_forensics(audio_path):
105
  try:
106
  y, sr = librosa.load(audio_path, sr=16000)
107
  y_48, _ = librosa.load(audio_path, sr=48000)
108
  y = y / (np.max(np.abs(y)) + 1e-9)
109
+ y = np.ascontiguousarray(y)
110
 
111
+ # 1. SEGMENT-WISE CROSS VALIDATION
112
  segments = np.array_split(y, 3)
113
  seg_embs = [extract_dna_embeddings(s) for s in segments]
114
  cos_sim = cosine_similarity(seg_embs[0], seg_embs[-1])[0][0]
 
117
  # 2. FEATURE EXTRACTION
118
  transcription = whisper_model.transcribe(audio_path)["text"]
119
  inputs = ast_extractor(y, sampling_rate=16000, return_tensors="pt")
 
 
120
  inputs = {k: (v.clone().detach() if isinstance(v, torch.Tensor) else torch.tensor(v)).to(DEVICE) for k, v in inputs.items()}
121
+
122
  with torch.no_grad():
123
  ast_prob = torch.nn.functional.softmax(ast_model(**inputs).logits, dim=-1).cpu().numpy()[0][1]
124
  ast_score = ast_prob * 100
125
 
126
+ # CLAP EMBEDDINGS
127
  audio_emb_np = clap_model.get_audio_embedding_from_data(x=[y_48])
128
  text_emb_np = clap_model.get_text_embedding(ALL_LABELS)
 
 
129
  audio_emb = torch.from_numpy(audio_emb_np).to(DEVICE)
130
  text_emb = torch.from_numpy(text_emb_np).to(DEVICE)
131
  c_sims = torch.nn.functional.cosine_similarity(audio_emb, text_emb)
 
132
  top_idx = torch.argmax(c_sims).item()
133
  clap_label = ALL_LABELS[top_idx]
134
 
 
140
 
141
  num_edits = len(np.where(np.diff(librosa.onset.onset_strength(y=y, sr=16000)) > 6.5)[0])
142
 
143
+ # FUZZY LOGIC MEMBERSHIP SCORING
144
  mu_ai = min(1.0, max(0.0, (ast_score - 40) / 45))
145
  mu_spliced = min(1.0, max(0.0, (num_edits - 8) / 10))
146
  dna_conf = (cos_sim - 0.85) / 0.10
147
  cat_conf = 1.0 if category == "AUTHENTIC" else 0.0
148
  mu_auth = min(1.0, max(0.0, (dna_conf + cat_conf) / 2))
149
 
150
+ # FUZZY DECISION ENGINE (V4.0)
151
  if mu_auth > 0.80 and mu_spliced < 0.75:
152
  verdict = "✅ AUTHENTIC HUMAN VOICE"
153
  category_override = "AUTHENTIC"
 
158
  verdict = "⚠️ MANIPULATED REAL VOICE (Spliced)"
159
  category_override = "MANIPULATED"
160
 
161
+ # LLM REASONING
162
  audit_context = (f"Verdict: {verdict}. Category: {category_override}. Metrics: ID {cos_sim:.2f}, "
163
  f"Texture {ast_score:.1f}%, Cuts {num_edits}. "
164
  f"Fuzzy Scores: AI={mu_ai:.2f}, Spliced={mu_spliced:.2f}, Auth={mu_auth:.2f}")
 
168
  "emphasize that DNA integrity confirms human origin despite high spectral texture. "
169
  "Give a 2-line direct forensic conclusion.")
170
 
171
+ res = client.chat.completions.create(
172
+ model="llama-3.3-70b-versatile",
173
+ messages=[{"role": "user", "content": prompt}]
174
+ )
175
  reasoning = res.choices[0].message.content
176
 
177
  evidence = f"Category: {category} | ID: {cos_sim:.2f} | Texture: {ast_score:.1f}% | Cuts: {num_edits}"