Ahmedsh93 commited on
Commit
6f6cd40
Β·
verified Β·
1 Parent(s): ab686f8
Files changed (3) hide show
  1. Dockerfile +19 -21
  2. app.py +100 -0
  3. requirements.txt +80 -3
Dockerfile CHANGED
@@ -1,21 +1,19 @@
1
- FROM python:3.9-slim
2
-
3
- WORKDIR /app
4
-
5
- RUN apt-get update && apt-get install -y \
6
- build-essential \
7
- curl \
8
- software-properties-common \
9
- git \
10
- && rm -rf /var/lib/apt/lists/*
11
-
12
- COPY requirements.txt ./
13
- COPY src/ ./src/
14
-
15
- RUN pip3 install -r requirements.txt
16
-
17
- EXPOSE 8501
18
-
19
- HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health
20
-
21
- ENTRYPOINT ["streamlit", "run", "src/streamlit_app.py", "--server.port=8501", "--server.address=0.0.0.0"]
 
1
+ # Use official Python slim image
2
+ FROM python:3.10-slim
3
+
4
+ # Set working directory
5
+ WORKDIR /app
6
+
7
+ # Copy requirements and install
8
+ COPY requirements.txt .
9
+ RUN pip install --upgrade pip
10
+ RUN pip install -r requirements.txt
11
+
12
+ # Copy app files
13
+ COPY . .
14
+
15
+ # Expose port Streamlit uses
16
+ EXPOSE 8501
17
+
18
+ # Run Streamlit app
19
+ CMD ["streamlit", "run", "app.py", "--server.port=8501", "--server.address=0.0.0.0"]
 
 
app.py ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import requests
3
+ import tempfile
4
+ import streamlit as st
5
+ from moviepy.editor import VideoFileClip
6
+ from speechbrain.inference.classifiers import EncoderClassifier
7
+
8
+ st.set_page_config(page_title="Accent Classifier", page_icon="πŸ—£οΈ", layout="centered")
9
+
10
+ # Custom CSS to change background color and style input box
11
+ st.markdown(
12
+ """
13
+ <style>
14
+ .stApp {
15
+ background-color: #f0f0f0;
16
+ }
17
+ input[type="text"] {
18
+ background-color: white;
19
+ color: black;
20
+ border: 1px solid #ccc;
21
+ padding: 0.5rem;
22
+ border-radius: 5px;
23
+ }
24
+ .stTextInput > div > div > input {
25
+ background-color: white !important;
26
+ color: black !important;
27
+ border: 1px solid #ccc !important;
28
+ }
29
+ </style>
30
+ """,
31
+ unsafe_allow_html=True
32
+ )
33
+
34
+ MODEL_ID = "Jzuluaga/accent-id-commonaccent_ecapa"
35
+
36
+ def download_video(url, output_path):
37
+ response = requests.get(url, stream=True)
38
+ if response.status_code == 200:
39
+ with open(output_path, "wb") as f:
40
+ for chunk in response.iter_content(1024):
41
+ f.write(chunk)
42
+ if not os.path.exists(output_path) or os.path.getsize(output_path) < 1024:
43
+ raise Exception("❌ Video download failed or file too small.")
44
+ else:
45
+ raise Exception("❌ Failed to download video.")
46
+
47
+ def extract_audio(video_path, audio_path):
48
+ clip = VideoFileClip(video_path)
49
+ audio = clip.audio
50
+ audio.write_audiofile(audio_path, fps=16000, nbytes=2, codec='pcm_s16le', ffmpeg_params=["-ac", "1"])
51
+ clip.close()
52
+ audio.close()
53
+
54
+ @st.cache_resource(show_spinner="Loading model...")
55
+ def load_model():
56
+ classifier = EncoderClassifier.from_hparams(
57
+ source=MODEL_ID,
58
+ savedir=os.path.join(os.getcwd(), "accent-id-model")
59
+ )
60
+ return classifier
61
+
62
+ def classify_accent(audio_path, classifier):
63
+ audio_path_clean = os.path.abspath(audio_path).replace('\\', '/')
64
+ if not os.path.exists(audio_path_clean):
65
+ raise FileNotFoundError(f"Audio file not found: {audio_path_clean}")
66
+ out_prob, score, index, label = classifier.classify_file(audio_path_clean)
67
+ return label, round(score.item() * 100, 2)
68
+
69
+ # ---------------- UI ----------------
70
+ st.title("πŸ—£οΈ Accent Classifier from Video")
71
+ st.markdown("Paste a direct **video URL (MP4)** and then press **Enter** or click **Identify the Accent**.")
72
+
73
+ with st.form("url_form", clear_on_submit=False):
74
+ video_url = st.text_input("πŸ”— Video URL", placeholder="https://...")
75
+ submitted = st.form_submit_button("πŸ—£οΈ Identify the Accent")
76
+
77
+ if submitted:
78
+ if not video_url:
79
+ st.warning("⚠️ Please enter a video URL.")
80
+ else:
81
+ try:
82
+ if "dropbox.com" in video_url and "raw=1" not in video_url:
83
+ video_url = video_url.replace("dl=0", "raw=1").replace("?dl=0", "?raw=1")
84
+
85
+ with st.spinner("πŸ”„ Downloading and processing video..."):
86
+ with tempfile.TemporaryDirectory() as tmpdir:
87
+ video_path = os.path.join(tmpdir, "input_video.mp4")
88
+ audio_path = os.path.join(tmpdir, "output_audio.wav")
89
+
90
+ download_video(video_url, video_path)
91
+ extract_audio(video_path, audio_path)
92
+ classifier = load_model()
93
+ label, confidence = classify_accent(audio_path, classifier)
94
+
95
+ st.success("βœ… Accent classified successfully!")
96
+ st.markdown(f"### 🎯 Prediction: **{label}**")
97
+ st.markdown(f"🧠 Confidence: **{confidence}%**")
98
+ st.info(f"The speaker's accent is predicted to be **{label}** with **{confidence}%** confidence.")
99
+ except Exception as e:
100
+ st.error(f"❌ Error: {e}")
requirements.txt CHANGED
@@ -1,3 +1,80 @@
1
- altair
2
- pandas
3
- streamlit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ altair==5.5.0
2
+ attrs==25.3.0
3
+ audioread==3.0.1
4
+ blinker==1.9.0
5
+ cachetools==5.5.2
6
+ certifi==2025.4.26
7
+ cffi==1.17.1
8
+ charset-normalizer==3.4.2
9
+ click==8.2.1
10
+ colorama==0.4.6
11
+ decorator==4.4.2
12
+ filelock==3.18.0
13
+ fsspec==2025.5.1
14
+ gitdb==4.0.12
15
+ GitPython==3.1.44
16
+ huggingface-hub==0.32.2
17
+ HyperPyYAML==1.2.2
18
+ idna==3.10
19
+ imageio==2.37.0
20
+ imageio-ffmpeg==0.6.0
21
+ Jinja2==3.1.6
22
+ joblib==1.5.1
23
+ jsonschema==4.24.0
24
+ jsonschema-specifications==2025.4.1
25
+ lazy_loader==0.4
26
+ librosa==0.11.0
27
+ llvmlite==0.44.0
28
+ MarkupSafe==3.0.2
29
+ moviepy==1.0.3
30
+ mpmath==1.3.0
31
+ msgpack==1.1.0
32
+ narwhals==1.41.0
33
+ networkx==3.4.2
34
+ numba==0.61.2
35
+ numpy==2.2.6
36
+ packaging==24.2
37
+ pandas==2.2.3
38
+ pillow==11.2.1
39
+ platformdirs==4.3.8
40
+ pooch==1.8.2
41
+ proglog==0.1.12
42
+ protobuf==6.31.1
43
+ pyarrow==20.0.0
44
+ pycparser==2.22
45
+ pydeck==0.9.1
46
+ pydub==0.25.1
47
+ python-dateutil==2.9.0.post0
48
+ python-dotenv==1.1.0
49
+ pytz==2025.2
50
+ PyYAML==6.0.2
51
+ referencing==0.36.2
52
+ regex==2024.11.6
53
+ requests==2.32.3
54
+ rpds-py==0.25.1
55
+ ruamel.yaml==0.18.11
56
+ ruamel.yaml.clib==0.2.12
57
+ safetensors==0.5.3
58
+ scikit-learn==1.6.1
59
+ scipy==1.15.3
60
+ sentencepiece==0.1.99
61
+ six==1.17.0
62
+ smmap==5.0.2
63
+ soundfile==0.13.1
64
+ soxr==0.5.0.post1
65
+ speechbrain==1.0.3
66
+ streamlit==1.45.1
67
+ sympy==1.14.0
68
+ tenacity==9.1.2
69
+ threadpoolctl==3.6.0
70
+ tokenizers==0.21.1
71
+ toml==0.10.2
72
+ torch==2.7.0
73
+ torchaudio==2.7.0
74
+ tornado==6.5.1
75
+ tqdm==4.67.1
76
+ transformers==4.52.3
77
+ typing_extensions==4.13.2
78
+ tzdata==2025.2
79
+ urllib3==2.4.0
80
+ watchdog==6.0.0