Spaces:
Sleeping
Sleeping
| import json | |
| import os | |
| import gradio as gr | |
| import spaces | |
| import torch | |
| import torchaudio | |
| from huggingface_hub import hf_hub_download | |
| from transformers import Wav2Vec2FeatureExtractor, Wav2Vec2ForSequenceClassification | |
| MODEL_ID = os.environ.get("HF_ASR_MODEL", "masumtechnonext/wav2vec2-arabic-letter-verifier") | |
| HF_TOKEN = os.environ.get("HF_TOKEN") | |
| SAMPLE_RATE = 16000 | |
| feature_extractor = Wav2Vec2FeatureExtractor.from_pretrained(MODEL_ID, token=HF_TOKEN) | |
| model = Wav2Vec2ForSequenceClassification.from_pretrained(MODEL_ID, token=HF_TOKEN) | |
| model.eval() | |
| id2label = {int(k): v for k, v in model.config.id2label.items()} | |
| calibration_path = hf_hub_download(MODEL_ID, "calibration.json", token=HF_TOKEN) | |
| with open(calibration_path) as f: | |
| THRESHOLD = json.load(f)["confidence_threshold"] | |
| UNKNOWN_ID = next(i for i, label in id2label.items() if label == "Unknown") | |
| LETTERS = sorted(label for label in id2label.values() if label != "Unknown") | |
| def predict(audio, target_letter): | |
| if audio is None: | |
| return "Record or upload audio first.", "" | |
| device = "cuda" if torch.cuda.is_available() else "cpu" | |
| model.to(device) | |
| sample_rate, waveform = audio | |
| waveform = torch.tensor(waveform, dtype=torch.float32) | |
| if waveform.ndim > 1: | |
| waveform = waveform.mean(dim=-1) | |
| if sample_rate != SAMPLE_RATE: | |
| waveform = torchaudio.functional.resample(waveform, sample_rate, SAMPLE_RATE) | |
| inputs = feature_extractor(waveform.numpy(), sampling_rate=SAMPLE_RATE, return_tensors="pt") | |
| inputs = {k: v.to(device) for k, v in inputs.items()} | |
| with torch.no_grad(): | |
| logits = model(**inputs).logits[0] | |
| probs = torch.softmax(logits, dim=-1) | |
| pred_id = int(torch.argmax(probs)) | |
| confidence = float(probs[pred_id]) | |
| accepted = confidence >= THRESHOLD and pred_id != UNKNOWN_ID | |
| predicted_label = id2label[pred_id] if accepted else "Unrecognized" | |
| prediction = f"{predicted_label} ({confidence:.1%} confidence)" | |
| if not target_letter: | |
| return prediction, "Pick an expected letter to verify." | |
| is_correct = accepted and predicted_label == target_letter | |
| verdict = "✅ Correct" if is_correct else "❌ Incorrect" | |
| return prediction, verdict | |
| demo = gr.Interface( | |
| fn=predict, | |
| inputs=[ | |
| gr.Audio(sources=["microphone", "upload"], type="numpy", label="Speak the letter"), | |
| gr.Dropdown(choices=LETTERS, label="Expected letter", value=LETTERS[0]), | |
| ], | |
| outputs=[ | |
| gr.Textbox(label="Prediction"), | |
| gr.Textbox(label="Verification"), | |
| ], | |
| title="Arabic Letter Verifier", | |
| description=f"Model: {MODEL_ID}", | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() | |