Spaces:
Running
Running
Enhance Dockerfile and Streamlit configuration; add upload directory, max upload size, and XSRF protection; update README with troubleshooting tips for file uploads
Browse files- .streamlit/config.toml +2 -0
- Dockerfile +4 -1
- README.md +16 -1
- src/streamlit_app.py +115 -23
.streamlit/config.toml
CHANGED
@@ -3,6 +3,8 @@ port = 8501
|
|
3 |
address = "0.0.0.0"
|
4 |
headless = true
|
5 |
enableCORS = false
|
|
|
|
|
6 |
|
7 |
[browser]
|
8 |
gatherUsageStats = false
|
|
|
3 |
address = "0.0.0.0"
|
4 |
headless = true
|
5 |
enableCORS = false
|
6 |
+
maxUploadSize = 200
|
7 |
+
enableXsrfProtection = false
|
8 |
|
9 |
[browser]
|
10 |
gatherUsageStats = false
|
Dockerfile
CHANGED
@@ -19,7 +19,8 @@ RUN apt-get update && \
|
|
19 |
&& rm -rf /var/lib/apt/lists/*
|
20 |
|
21 |
# Create necessary directories
|
22 |
-
RUN mkdir -p /app/tmp_model /tmp/matplotlib
|
|
|
23 |
|
24 |
# Copy requirements first (for better caching)
|
25 |
COPY requirements.txt .
|
@@ -39,6 +40,8 @@ RUN echo "[server]" > ./.streamlit/config.toml && \
|
|
39 |
echo "port = 8501" >> ./.streamlit/config.toml && \
|
40 |
echo "address = \"0.0.0.0\"" >> ./.streamlit/config.toml && \
|
41 |
echo "headless = true" >> ./.streamlit/config.toml && \
|
|
|
|
|
42 |
echo "" >> ./.streamlit/config.toml && \
|
43 |
echo "[browser]" >> ./.streamlit/config.toml && \
|
44 |
echo "gatherUsageStats = false" >> ./.streamlit/config.toml && \
|
|
|
19 |
&& rm -rf /var/lib/apt/lists/*
|
20 |
|
21 |
# Create necessary directories
|
22 |
+
RUN mkdir -p /app/tmp_model /tmp/matplotlib /app/uploads
|
23 |
+
RUN chmod -R 777 /app/uploads /app/tmp_model /tmp/matplotlib
|
24 |
|
25 |
# Copy requirements first (for better caching)
|
26 |
COPY requirements.txt .
|
|
|
40 |
echo "port = 8501" >> ./.streamlit/config.toml && \
|
41 |
echo "address = \"0.0.0.0\"" >> ./.streamlit/config.toml && \
|
42 |
echo "headless = true" >> ./.streamlit/config.toml && \
|
43 |
+
echo "maxUploadSize = 200" >> ./.streamlit/config.toml && \
|
44 |
+
echo "enableXsrfProtection = false" >> ./.streamlit/config.toml && \
|
45 |
echo "" >> ./.streamlit/config.toml && \
|
46 |
echo "[browser]" >> ./.streamlit/config.toml && \
|
47 |
echo "gatherUsageStats = false" >> ./.streamlit/config.toml && \
|
README.md
CHANGED
@@ -73,10 +73,25 @@ If you encounter errors like `Sign in to confirm you're not a bot` when using Yo
|
|
73 |
The app is containerized with Docker for easy deployment. Use the included Dockerfile to build and run:
|
74 |
|
75 |
```bash
|
|
|
76 |
docker build -t accent-detector .
|
77 |
-
|
|
|
|
|
|
|
|
|
|
|
78 |
```
|
79 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
## Powered By
|
81 |
- [SpeechBrain](https://huggingface.co/speechbrain/lang-id-commonlanguage_ecapa)
|
82 |
- [Hugging Face Transformers](https://huggingface.co/speechbrain/lang-id-voxlingua107-ecapa)
|
|
|
73 |
The app is containerized with Docker for easy deployment. Use the included Dockerfile to build and run:
|
74 |
|
75 |
```bash
|
76 |
+
# Build the Docker image
|
77 |
docker build -t accent-detector .
|
78 |
+
|
79 |
+
# Run the container with volume mounting for better file handling
|
80 |
+
docker run -p 8501:8501 --volume /tmp/accent-detector:/app/uploads accent-detector
|
81 |
+
|
82 |
+
# For Windows users:
|
83 |
+
docker run -p 8501:8501 --volume C:\temp\accent-detector:/app/uploads accent-detector
|
84 |
```
|
85 |
|
86 |
+
### Troubleshooting Upload Issues
|
87 |
+
|
88 |
+
If you encounter 403 Forbidden errors when uploading files:
|
89 |
+
|
90 |
+
1. Make sure your audio file is under 200MB
|
91 |
+
2. Try converting your audio to a WAV or MP3 format
|
92 |
+
3. For longer files, consider extracting just the speech segment
|
93 |
+
4. If uploading an MP4 video, ensure it's not encrypted or DRM-protected
|
94 |
+
|
95 |
## Powered By
|
96 |
- [SpeechBrain](https://huggingface.co/speechbrain/lang-id-commonlanguage_ecapa)
|
97 |
- [Hugging Face Transformers](https://huggingface.co/speechbrain/lang-id-voxlingua107-ecapa)
|
src/streamlit_app.py
CHANGED
@@ -43,17 +43,23 @@ import matplotlib.pyplot as plt
|
|
43 |
import tempfile
|
44 |
import time
|
45 |
|
46 |
-
#
|
47 |
# To deploy this app:
|
48 |
# 1. Make sure Docker is installed
|
49 |
# 2. Build the Docker image: docker build -t accent-detector .
|
50 |
-
# 3. Run the container: docker run -p 8501:8501 accent-detector
|
|
|
51 |
# 4. Access the app at http://localhost:8501
|
52 |
#
|
53 |
# For cloud deployment:
|
54 |
# - Streamlit Cloud: Connect your GitHub repository to Streamlit Cloud
|
55 |
-
# - Hugging Face Spaces: Use the Docker deployment option
|
56 |
-
# - Azure/AWS/GCP: Deploy the container using their container services
|
|
|
|
|
|
|
|
|
|
|
57 |
|
58 |
# Load environment variables (if .env file exists)
|
59 |
try:
|
@@ -323,15 +329,52 @@ class AccentDetector:
|
|
323 |
|
324 |
def process_uploaded_audio(uploaded_file):
|
325 |
"""Process uploaded audio file"""
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
335 |
return results
|
336 |
|
337 |
# --- Streamlit App ---
|
@@ -479,9 +522,16 @@ with tab2:
|
|
479 |
st.markdown("### 🎵 Upload Audio File")
|
480 |
st.caption("**Recommended option!** Direct audio upload is more reliable than video URLs.")
|
481 |
|
|
|
|
|
|
|
|
|
|
|
|
|
482 |
uploaded_file = st.file_uploader("Upload an audio file",
|
483 |
-
type=["wav", "mp3", "m4a", "ogg", "flac"],
|
484 |
-
help="Support for WAV, MP3, M4A, OGG and
|
|
|
485 |
|
486 |
if uploaded_file is not None:
|
487 |
# Show a preview of the audio
|
@@ -494,14 +544,25 @@ with tab2:
|
|
494 |
analyze_button = st.button("Analyze Audio", type="primary", use_container_width=True)
|
495 |
with col2:
|
496 |
st.caption("Tip: 15-30 seconds of clear speech works best for accent detection")
|
497 |
-
|
498 |
if analyze_button:
|
499 |
with st.spinner("Analyzing audio... (this may take 15-30 seconds)"):
|
500 |
try:
|
501 |
-
|
502 |
-
|
503 |
-
#
|
504 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
505 |
|
506 |
# Create columns for results
|
507 |
col1, col2 = st.columns([2, 1])
|
@@ -511,8 +572,7 @@ with tab2:
|
|
511 |
st.markdown(f"**Detected Accent:** {results['accent']}")
|
512 |
st.markdown(f"**English Proficiency:** {results['english_confidence']:.1f}%")
|
513 |
st.markdown(f"**Accent Confidence:** {results['accent_confidence']:.1f}%")
|
514 |
-
|
515 |
-
# Show explanation in a box
|
516 |
st.markdown("### Expert Analysis")
|
517 |
st.info(results['explanation'])
|
518 |
|
@@ -520,8 +580,40 @@ with tab2:
|
|
520 |
if results['audio_viz']:
|
521 |
st.pyplot(results['audio_viz'])
|
522 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
523 |
except Exception as e:
|
524 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
525 |
|
526 |
# Add footer with deployment info
|
527 |
st.markdown("---")
|
|
|
43 |
import tempfile
|
44 |
import time
|
45 |
|
46 |
+
# Deployment instructions:
|
47 |
# To deploy this app:
|
48 |
# 1. Make sure Docker is installed
|
49 |
# 2. Build the Docker image: docker build -t accent-detector .
|
50 |
+
# 3. Run the container: docker run -p 8501:8501 --volume /tmp/accent-detector:/app/uploads accent-detector
|
51 |
+
# For Windows: docker run -p 8501:8501 --volume C:\temp\accent-detector:/app/uploads accent-detector
|
52 |
# 4. Access the app at http://localhost:8501
|
53 |
#
|
54 |
# For cloud deployment:
|
55 |
# - Streamlit Cloud: Connect your GitHub repository to Streamlit Cloud
|
56 |
+
# - Hugging Face Spaces: Use the Docker deployment option with proper volume mounts
|
57 |
+
# - Azure/AWS/GCP: Deploy the container using their container services with persistent storage
|
58 |
+
#
|
59 |
+
# Troubleshooting file uploads:
|
60 |
+
# - Set maxUploadSize in .streamlit/config.toml
|
61 |
+
# - Ensure write permissions on upload directories
|
62 |
+
# - For 403 errors, check file size and format compatibility
|
63 |
|
64 |
# Load environment variables (if .env file exists)
|
65 |
try:
|
|
|
329 |
|
330 |
def process_uploaded_audio(uploaded_file):
|
331 |
"""Process uploaded audio file"""
|
332 |
+
try:
|
333 |
+
# Create a unique filename based on timestamp
|
334 |
+
timestamp = str(int(time.time()))
|
335 |
+
file_extension = os.path.splitext(uploaded_file.name)[1].lower()
|
336 |
+
|
337 |
+
# Write the uploaded file to disk with proper extension
|
338 |
+
temp_input_path = f"uploaded_audio_{timestamp}{file_extension}"
|
339 |
+
with open(temp_input_path, "wb") as f:
|
340 |
+
f.write(uploaded_file.getbuffer())
|
341 |
+
|
342 |
+
# For MP4 files, extract the audio using ffmpeg
|
343 |
+
if file_extension == ".mp4":
|
344 |
+
st.info("Extracting audio from video file...")
|
345 |
+
audio_path = f"extracted_audio_{timestamp}.wav"
|
346 |
+
try:
|
347 |
+
subprocess.run(
|
348 |
+
['ffmpeg', '-i', temp_input_path, '-vn', '-acodec', 'pcm_s16le', '-ar', '16000', '-ac', '1', audio_path],
|
349 |
+
check=True,
|
350 |
+
capture_output=True
|
351 |
+
)
|
352 |
+
# Remove the original video file
|
353 |
+
os.remove(temp_input_path)
|
354 |
+
except subprocess.CalledProcessError as e:
|
355 |
+
st.error(f"Error extracting audio: {e}")
|
356 |
+
st.error(f"ffmpeg output: {e.stderr.decode('utf-8')}")
|
357 |
+
raise
|
358 |
+
else:
|
359 |
+
# For audio files, use them directly
|
360 |
+
audio_path = temp_input_path
|
361 |
+
|
362 |
+
detector = AccentDetector()
|
363 |
+
results = detector.analyze_audio(audio_path)
|
364 |
+
|
365 |
+
# Clean up
|
366 |
+
if os.path.exists(audio_path):
|
367 |
+
os.remove(audio_path)
|
368 |
+
|
369 |
+
return results
|
370 |
+
|
371 |
+
except Exception as e:
|
372 |
+
st.error(f"Error processing audio: {str(e)}")
|
373 |
+
if 'temp_input_path' in locals() and os.path.exists(temp_input_path):
|
374 |
+
os.remove(temp_input_path)
|
375 |
+
if 'audio_path' in locals() and os.path.exists(audio_path):
|
376 |
+
os.remove(audio_path)
|
377 |
+
raise
|
378 |
return results
|
379 |
|
380 |
# --- Streamlit App ---
|
|
|
522 |
st.markdown("### 🎵 Upload Audio File")
|
523 |
st.caption("**Recommended option!** Direct audio upload is more reliable than video URLs.")
|
524 |
|
525 |
+
# Add some information about file size limits
|
526 |
+
st.info("📝 **File Requirements**: \n"
|
527 |
+
"• Maximum file size: 200MB \n"
|
528 |
+
"• Supported formats: WAV, MP3, M4A, OGG, FLAC, MP4 \n"
|
529 |
+
"• Recommended length: 15-60 seconds of clear speech")
|
530 |
+
|
531 |
uploaded_file = st.file_uploader("Upload an audio file",
|
532 |
+
type=["wav", "mp3", "m4a", "ogg", "flac", "mp4"],
|
533 |
+
help="Support for WAV, MP3, M4A, OGG, FLAC and MP4 formats",
|
534 |
+
accept_multiple_files=False)
|
535 |
|
536 |
if uploaded_file is not None:
|
537 |
# Show a preview of the audio
|
|
|
544 |
analyze_button = st.button("Analyze Audio", type="primary", use_container_width=True)
|
545 |
with col2:
|
546 |
st.caption("Tip: 15-30 seconds of clear speech works best for accent detection")
|
|
|
547 |
if analyze_button:
|
548 |
with st.spinner("Analyzing audio... (this may take 15-30 seconds)"):
|
549 |
try:
|
550 |
+
# Check file size before processing
|
551 |
+
file_size_mb = len(uploaded_file.getvalue()) / (1024 * 1024)
|
552 |
+
if file_size_mb > 190: # Stay below the 200MB limit with some buffer
|
553 |
+
st.error(f"File size ({file_size_mb:.1f}MB) is too large. Maximum allowed is 190MB.")
|
554 |
+
st.info("Tip: Try trimming your audio to just the speech segment for better results.")
|
555 |
+
else:
|
556 |
+
# Check the file type and inform user about processing steps
|
557 |
+
file_extension = os.path.splitext(uploaded_file.name)[1].lower()
|
558 |
+
if file_extension == '.mp4':
|
559 |
+
st.info("Processing video file - extracting audio track...")
|
560 |
+
|
561 |
+
# Process the file
|
562 |
+
results = process_uploaded_audio(uploaded_file)
|
563 |
+
|
564 |
+
# Display results
|
565 |
+
st.success("✅ Analysis Complete!")
|
566 |
|
567 |
# Create columns for results
|
568 |
col1, col2 = st.columns([2, 1])
|
|
|
572 |
st.markdown(f"**Detected Accent:** {results['accent']}")
|
573 |
st.markdown(f"**English Proficiency:** {results['english_confidence']:.1f}%")
|
574 |
st.markdown(f"**Accent Confidence:** {results['accent_confidence']:.1f}%")
|
575 |
+
# Show explanation in a box
|
|
|
576 |
st.markdown("### Expert Analysis")
|
577 |
st.info(results['explanation'])
|
578 |
|
|
|
580 |
if results['audio_viz']:
|
581 |
st.pyplot(results['audio_viz'])
|
582 |
|
583 |
+
except subprocess.CalledProcessError as e:
|
584 |
+
st.error("Error processing audio file")
|
585 |
+
st.error(f"FFmpeg error: {e.stderr.decode('utf-8') if e.stderr else str(e)}")
|
586 |
+
st.info("Troubleshooting tips:\n"
|
587 |
+
"• Try a different audio file format (WAV or MP3 recommended)\n"
|
588 |
+
"• Make sure the file is not corrupted\n"
|
589 |
+
"• Try a shorter audio clip")
|
590 |
+
|
591 |
+
except PermissionError as e:
|
592 |
+
st.error(f"Permission error: {str(e)}")
|
593 |
+
st.info("The app doesn't have permission to access or create temporary files. "
|
594 |
+
"This could be due to Docker container permissions. "
|
595 |
+
"Contact the administrator or try using a different file.")
|
596 |
+
|
597 |
+
except OSError as e:
|
598 |
+
st.error(f"System error: {str(e)}")
|
599 |
+
st.info("Check that the file isn't corrupted and try with a smaller audio clip.")
|
600 |
+
|
601 |
except Exception as e:
|
602 |
+
error_msg = str(e)
|
603 |
+
st.error(f"Error during analysis: {error_msg}")
|
604 |
+
|
605 |
+
if "403" in error_msg:
|
606 |
+
st.warning("Received a 403 Forbidden error. This may be due to: \n"
|
607 |
+
"• File size exceeding limits\n"
|
608 |
+
"• Temporary file permission issues\n"
|
609 |
+
"• Network restrictions")
|
610 |
+
st.info("Try a smaller audio file (less than 50MB) or a different format.")
|
611 |
+
elif "timeout" in error_msg.lower():
|
612 |
+
st.warning("The request timed out. Try a shorter audio clip or check your internet connection.")
|
613 |
+
elif "memory" in error_msg.lower():
|
614 |
+
st.warning("Out of memory error. Try a shorter audio clip.")
|
615 |
+
else:
|
616 |
+
st.info("If the problem persists, try a different audio file format such as MP3 or WAV.")
|
617 |
|
618 |
# Add footer with deployment info
|
619 |
st.markdown("---")
|