Download handler.py from kripasree/ai-voice-detector: direct link, hf CLI and curl.
- Browser
- Download file 2.41 kB
-
https://huggingface.co/kripasree/ai-voice-detector/resolve/main/handler.py
- Command line
-
hf download hf://kripasree/ai-voice-detector/handler.py
-
curl -L -o handler.py https://huggingface.co/kripasree/ai-voice-detector/resolve/main/handler.py
2.41 kB
| import base64 | |
| import io | |
| import numpy as np | |
| import librosa | |
| import torch | |
| from transformers import Wav2Vec2FeatureExtractor, Wav2Vec2ForSequenceClassification | |
| THRESHOLD = 0.75 | |
| device = "cpu" | |
| class EndpointHandler: | |
| def __init__(self, model_dir): | |
| self.feature_extractor = Wav2Vec2FeatureExtractor.from_pretrained(model_dir) | |
| self.model = Wav2Vec2ForSequenceClassification.from_pretrained( | |
| model_dir, | |
| low_cpu_mem_usage=True | |
| ).to(device) | |
| self.model.eval() | |
| def load_mp3_from_base64(self, b64): | |
| audio_bytes = base64.b64decode(b64) | |
| with io.BytesIO(audio_bytes) as f: | |
| y, sr = librosa.load(f, sr=16000) | |
| return y | |
| def predict_chunked(self, y): | |
| chunk_len = 16000 | |
| probs = [] | |
| for start in range(0, len(y), chunk_len): | |
| chunk = y[start:start + chunk_len] | |
| if len(chunk) < 4000: | |
| continue | |
| inputs = self.feature_extractor( | |
| chunk, | |
| sampling_rate=16000, | |
| return_tensors="pt" | |
| ) | |
| inputs = {k: v.to(device) for k, v in inputs.items()} | |
| with torch.no_grad(): | |
| logits = self.model(**inputs).logits | |
| p = torch.softmax(logits, dim=1)[0][1].item() | |
| probs.append(p) | |
| return float(np.mean(probs)) if probs else 0.0 | |
| def __call__(self, data): | |
| # Accept both formats | |
| if "inputs" in data: | |
| req = data["inputs"] | |
| else: | |
| req = data | |
| language = req.get("language") | |
| audio_base64 = req.get("audioBase64") | |
| y = self.load_mp3_from_base64(audio_base64) | |
| ai_prob = self.predict_chunked(y) | |
| if ai_prob >= THRESHOLD: | |
| return { | |
| "status": "success", | |
| "language": language, | |
| "classification": "AI_GENERATED", | |
| "confidenceScore": round(ai_prob, 4), | |
| "explanation": "Unnatural pitch consistency and synthetic speech patterns detected" | |
| } | |
| else: | |
| return { | |
| "status": "success", | |
| "language": language, | |
| "classification": "HUMAN", | |
| "confidenceScore": round(1 - ai_prob, 4), | |
| "explanation": "Natural pitch variation and human speech characteristics detected" | |
| } | |