Spaces:
Runtime error
Runtime error
import gradio as gr | |
import os | |
import tempfile | |
import requests | |
from moviepy.editor import VideoFileClip | |
import random | |
import json | |
# --- Lightweight AccentAnalyzer class (from your paste) --- | |
class AccentAnalyzer: | |
def __init__(self): | |
self.accent_profiles = { | |
"American": { | |
"features": ["rhotic", "flapped_t", "cot_caught_merger"], | |
"description": "American English accent with rhotic pronunciation and typical North American features." | |
}, | |
"British": { | |
"features": ["non_rhotic", "t_glottalization", "trap_bath_split"], | |
"description": "British English accent with non-rhotic pronunciation and typical UK features." | |
}, | |
"Australian": { | |
"features": ["non_rhotic", "flat_a", "high_rising_terminal"], | |
"description": "Australian English accent with distinctive vowel sounds and intonation patterns." | |
}, | |
"Canadian": { | |
"features": ["rhotic", "canadian_raising", "eh_tag"], | |
"description": "Canadian English accent with features of both American and British English." | |
}, | |
"Indian": { | |
"features": ["retroflex_consonants", "monophthongization", "syllable_timing"], | |
"description": "Indian English accent influenced by native Indian languages." | |
}, | |
"Irish": { | |
"features": ["dental_fricatives", "alveolar_l", "soft_consonants"], | |
"description": "Irish English accent with distinctive rhythm and consonant patterns." | |
}, | |
"Scottish": { | |
"features": ["rolled_r", "monophthongs", "glottal_stops"], | |
"description": "Scottish English accent with strong consonants and distinctive vowel patterns." | |
}, | |
"South African": { | |
"features": ["non_rhotic", "kit_split", "kw_hw_distinction"], | |
"description": "South African English accent with influences from Afrikaans and other local languages." | |
} | |
} | |
self._load_or_create_accent_data() | |
def _load_or_create_accent_data(self): | |
# For demo: just create simulated data in-memory | |
self.accent_data = self._create_simulated_accent_data() | |
def _create_simulated_accent_data(self): | |
accent_data = {} | |
for accent, profile in self.accent_profiles.items(): | |
accent_data[accent] = { | |
"primary_features": profile["features"], | |
"feature_probabilities": {} | |
} | |
for feature in profile["features"]: | |
accent_data[accent]["feature_probabilities"][feature] = random.uniform(0.7, 0.9) | |
all_features = set() | |
for a, p in self.accent_profiles.items(): | |
all_features.update(p["features"]) | |
for feature in all_features: | |
if feature not in profile["features"]: | |
accent_data[accent]["feature_probabilities"][feature] = random.uniform(0.1, 0.4) | |
return accent_data | |
def _extract_features(self, audio_path): | |
all_features = set() | |
for accent, profile in self.accent_profiles.items(): | |
all_features.update(profile["features"]) | |
detected_features = {} | |
for feature in all_features: | |
detected_features[feature] = random.uniform(0.1, 0.9) | |
return detected_features | |
def _calculate_accent_scores(self, detected_features): | |
accent_scores = {} | |
for accent, data in self.accent_data.items(): | |
score = 0 | |
total_weight = 0 | |
for feature, probability in detected_features.items(): | |
expected_prob = data["feature_probabilities"].get(feature, 0.1) | |
weight = 3.0 if feature in data["primary_features"] else 1.0 | |
feature_score = probability * expected_prob * weight | |
score += feature_score | |
total_weight += weight | |
if total_weight > 0: | |
accent_scores[accent] = (score / total_weight) * 100 | |
else: | |
accent_scores[accent] = 0 | |
return accent_scores | |
def _generate_explanation(self, accent_type, confidence): | |
if confidence >= 70: | |
confidence_level = "high confidence" | |
certainty = "is very clear" | |
elif confidence >= 50: | |
confidence_level = "moderate confidence" | |
certainty = "is present" | |
else: | |
confidence_level = "low confidence" | |
certainty = "may be present" | |
description = self.accent_profiles[accent_type]["description"] | |
second_accent = self._get_second_most_likely_accent(accent_type) | |
explanation = f"The speaker has a {confidence_level} {accent_type} English accent. The {accent_type} accent {certainty}, with features of both {accent_type} and {second_accent} English present." | |
return explanation | |
def _get_second_most_likely_accent(self, primary_accent): | |
accent_similarities = { | |
"American": ["Canadian", "British"], | |
"British": ["Australian", "Irish"], | |
"Australian": ["British", "South African"], | |
"Canadian": ["American", "British"], | |
"Indian": ["British", "South African"], | |
"Irish": ["Scottish", "British"], | |
"Scottish": ["Irish", "British"], | |
"South African": ["Australian", "British"] | |
} | |
return random.choice(accent_similarities[primary_accent]) | |
def analyze_accent(self, audio_path): | |
detected_features = self._extract_features(audio_path) | |
accent_scores = self._calculate_accent_scores(detected_features) | |
accent_type = max(accent_scores, key=accent_scores.get) | |
confidence = accent_scores[accent_type] | |
explanation = self._generate_explanation(accent_type, confidence) | |
return { | |
"accent_type": accent_type, | |
"confidence": confidence, | |
"explanation": explanation, | |
"all_scores": accent_scores | |
} | |
# --- Utility: Download video and extract audio --- | |
def download_and_extract_audio(url): | |
temp_dir = tempfile.mkdtemp() | |
video_path = os.path.join(temp_dir, "video.mp4") | |
audio_path = os.path.join(temp_dir, "audio.wav") | |
# Download video | |
if "youtube.com" in url or "youtu.be" in url: | |
# Use pytubefix for YouTube | |
from pytubefix import YouTube | |
yt = YouTube(url) | |
stream = yt.streams.filter(progressive=True, file_extension='mp4').first() | |
if not stream: | |
raise RuntimeError("No suitable video stream found.") | |
stream.download(output_path=temp_dir, filename="video.mp4") | |
else: | |
# Direct MP4 download | |
r = requests.get(url, stream=True) | |
r.raise_for_status() | |
with open(video_path, "wb") as f: | |
for chunk in r.iter_content(chunk_size=8192): | |
f.write(chunk) | |
# Extract audio | |
clip = VideoFileClip(video_path) | |
clip.audio.write_audiofile(audio_path, logger=None) | |
clip.close() | |
return audio_path | |
# --- Gradio interface --- | |
def analyze_from_url(url): | |
try: | |
audio_path = download_and_extract_audio(url) | |
analyzer = AccentAnalyzer() | |
results = analyzer.analyze_accent(audio_path) | |
os.remove(audio_path) | |
return ( | |
results["accent_type"], | |
f"{results['confidence']:.1f}%", | |
results["explanation"] | |
) | |
except Exception as e: | |
return ( | |
"Error", | |
"0%", | |
f"Error processing video/audio: {e}" | |
) | |
iface = gr.Interface( | |
fn=analyze_from_url, | |
inputs=gr.Textbox(label="Enter Public Video URL (YouTube or direct MP4)"), | |
outputs=[ | |
gr.Textbox(label="Detected Accent"), | |
gr.Textbox(label="Confidence Score"), | |
gr.Textbox(label="Explanation") | |
], | |
title="English Accent Analyzer (Rule-Based Demo)", | |
description="Paste a public video URL to detect the English accent and confidence score. (Demo: uses simulated accent features, not real ML audio analysis.)" | |
) | |
if __name__ == "__main__": | |
iface.launch() | |