Spaces:
Sleeping
Sleeping
Update Dockerfile and Streamlit app; add additional system dependencies and improve audio processing error handling
Browse files- Dockerfile +4 -0
- src/streamlit_app.py +64 -20
Dockerfile
CHANGED
@@ -21,6 +21,10 @@ RUN apt-get update && \
|
|
21 |
git \
|
22 |
ffmpeg \
|
23 |
libsndfile1 \
|
|
|
|
|
|
|
|
|
24 |
&& apt-get clean \
|
25 |
&& rm -rf /var/lib/apt/lists/*
|
26 |
|
|
|
21 |
git \
|
22 |
ffmpeg \
|
23 |
libsndfile1 \
|
24 |
+
libgl1-mesa-glx \
|
25 |
+
python3-tk \
|
26 |
+
libavcodec-extra \
|
27 |
+
libavformat-dev \
|
28 |
&& apt-get clean \
|
29 |
&& rm -rf /var/lib/apt/lists/*
|
30 |
|
src/streamlit_app.py
CHANGED
@@ -491,10 +491,17 @@ def process_uploaded_audio(file_input):
|
|
491 |
Args:
|
492 |
file_input: Either a StreamlitUploadedFile object or a string path to a file
|
493 |
"""
|
|
|
|
|
|
|
494 |
try:
|
495 |
# Create a unique filename based on timestamp
|
496 |
timestamp = str(int(time.time()))
|
497 |
|
|
|
|
|
|
|
|
|
498 |
# Handle different input types
|
499 |
if isinstance(file_input, str):
|
500 |
# If it's already a file path
|
@@ -505,15 +512,12 @@ def process_uploaded_audio(file_input):
|
|
505 |
# If it's a StreamlitUploadedFile
|
506 |
file_extension = os.path.splitext(file_input.name)[1].lower()
|
507 |
|
508 |
-
# Create an uploads directory if it doesn't exist
|
509 |
-
uploads_dir = os.path.join(os.getcwd(), "uploads")
|
510 |
-
os.makedirs(uploads_dir, exist_ok=True)
|
511 |
-
|
512 |
# Write the uploaded file to disk with proper extension in the uploads directory
|
513 |
temp_input_path = os.path.join(uploads_dir, f"uploaded_audio_{timestamp}{file_extension}")
|
514 |
with open(temp_input_path, "wb") as f:
|
515 |
f.write(file_input.getbuffer())
|
516 |
-
|
|
|
517 |
if file_extension == ".mp4":
|
518 |
st.info("Extracting audio from video file...")
|
519 |
audio_path = os.path.join(uploads_dir, f"extracted_audio_{timestamp}.wav")
|
@@ -527,7 +531,8 @@ def process_uploaded_audio(file_input):
|
|
527 |
os.remove(temp_input_path)
|
528 |
except subprocess.CalledProcessError as e:
|
529 |
st.error(f"Error extracting audio: {e}")
|
530 |
-
|
|
|
531 |
raise
|
532 |
else:
|
533 |
# For audio files, process based on format
|
@@ -535,14 +540,23 @@ def process_uploaded_audio(file_input):
|
|
535 |
# Convert to WAV for better compatibility
|
536 |
audio_path = os.path.join(uploads_dir, f"converted_audio_{timestamp}.wav")
|
537 |
try:
|
538 |
-
|
539 |
-
|
|
|
540 |
check=True,
|
541 |
capture_output=True
|
542 |
)
|
543 |
-
|
|
|
|
|
|
|
|
|
|
|
544 |
except subprocess.CalledProcessError as e:
|
545 |
-
st.warning(f"Conversion warning: {e}
|
|
|
|
|
|
|
546 |
audio_path = temp_input_path
|
547 |
else:
|
548 |
# For already WAV files, use them directly
|
@@ -552,18 +566,47 @@ def process_uploaded_audio(file_input):
|
|
552 |
results = detector.analyze_audio(audio_path)
|
553 |
|
554 |
# Clean up
|
555 |
-
if os.path.exists(audio_path):
|
556 |
os.remove(audio_path)
|
557 |
|
558 |
return results
|
559 |
|
560 |
except Exception as e:
|
561 |
-
|
562 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
563 |
os.remove(temp_input_path)
|
564 |
-
|
|
|
|
|
|
|
|
|
|
|
565 |
os.remove(audio_path)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
566 |
raise
|
|
|
567 |
return results
|
568 |
|
569 |
# --- Streamlit App ---
|
@@ -690,14 +733,15 @@ with tab1:
|
|
690 |
# Show explanation in a box
|
691 |
st.markdown("### Expert Analysis")
|
692 |
st.info(results['explanation'])
|
693 |
-
|
694 |
-
with col2:
|
695 |
if results['audio_viz']:
|
696 |
try:
|
697 |
st.pyplot(results['audio_viz'])
|
698 |
except Exception as viz_error:
|
699 |
st.warning("Could not display visualization due to torchvision issue.")
|
700 |
-
st.info("Audio analysis was successful even though visualization failed.")
|
|
|
|
|
701 |
st.audio(audio_path)
|
702 |
|
703 |
# Clean up files
|
@@ -763,15 +807,15 @@ with tab2:
|
|
763 |
# First save the file to a known location to bypass 403 errors
|
764 |
# Create an uploads directory if it doesn't exist
|
765 |
uploads_dir = os.path.join(os.getcwd(), "uploads")
|
766 |
-
os.makedirs(uploads_dir, exist_ok=True)
|
767 |
-
# Save the file first to avoid streaming it multiple times
|
768 |
temp_file_path = os.path.join(uploads_dir, f"temp_{int(time.time())}_{uploaded_file.name}")
|
769 |
with open(temp_file_path, "wb") as f:
|
770 |
f.write(uploaded_file.getbuffer())
|
771 |
|
772 |
progress_bar.progress(50, text="Analyzing audio...")
|
773 |
|
774 |
-
# Process using the saved file path directly
|
|
|
775 |
|
776 |
progress_bar.progress(100, text="Analysis complete!")
|
777 |
# Display results
|
|
|
491 |
Args:
|
492 |
file_input: Either a StreamlitUploadedFile object or a string path to a file
|
493 |
"""
|
494 |
+
audio_path = None
|
495 |
+
temp_input_path = None
|
496 |
+
|
497 |
try:
|
498 |
# Create a unique filename based on timestamp
|
499 |
timestamp = str(int(time.time()))
|
500 |
|
501 |
+
# Create an uploads directory if it doesn't exist - we'll need this regardless
|
502 |
+
uploads_dir = os.path.join(os.getcwd(), "uploads")
|
503 |
+
os.makedirs(uploads_dir, exist_ok=True)
|
504 |
+
|
505 |
# Handle different input types
|
506 |
if isinstance(file_input, str):
|
507 |
# If it's already a file path
|
|
|
512 |
# If it's a StreamlitUploadedFile
|
513 |
file_extension = os.path.splitext(file_input.name)[1].lower()
|
514 |
|
|
|
|
|
|
|
|
|
515 |
# Write the uploaded file to disk with proper extension in the uploads directory
|
516 |
temp_input_path = os.path.join(uploads_dir, f"uploaded_audio_{timestamp}{file_extension}")
|
517 |
with open(temp_input_path, "wb") as f:
|
518 |
f.write(file_input.getbuffer())
|
519 |
+
|
520 |
+
# For MP4 files, extract the audio using ffmpeg
|
521 |
if file_extension == ".mp4":
|
522 |
st.info("Extracting audio from video file...")
|
523 |
audio_path = os.path.join(uploads_dir, f"extracted_audio_{timestamp}.wav")
|
|
|
531 |
os.remove(temp_input_path)
|
532 |
except subprocess.CalledProcessError as e:
|
533 |
st.error(f"Error extracting audio: {e}")
|
534 |
+
if e.stderr:
|
535 |
+
st.error(f"FFmpeg output: {e.stderr.decode('utf-8')}")
|
536 |
raise
|
537 |
else:
|
538 |
# For audio files, process based on format
|
|
|
540 |
# Convert to WAV for better compatibility
|
541 |
audio_path = os.path.join(uploads_dir, f"converted_audio_{timestamp}.wav")
|
542 |
try:
|
543 |
+
# Use a verbose ffmpeg command with detailed logging
|
544 |
+
process = subprocess.run(
|
545 |
+
['ffmpeg', '-i', temp_input_path, '-ar', '16000', '-ac', '1', '-c:a', 'pcm_s16le', '-y', audio_path],
|
546 |
check=True,
|
547 |
capture_output=True
|
548 |
)
|
549 |
+
|
550 |
+
# Verify the file was created
|
551 |
+
if not os.path.exists(audio_path) or os.path.getsize(audio_path) == 0:
|
552 |
+
st.warning("Conversion produced an empty file. Using original file.")
|
553 |
+
audio_path = temp_input_path
|
554 |
+
|
555 |
except subprocess.CalledProcessError as e:
|
556 |
+
st.warning(f"Conversion warning: {e}")
|
557 |
+
if e.stderr:
|
558 |
+
st.warning(f"FFmpeg error: {e.stderr.decode('utf-8')}")
|
559 |
+
st.info("Using original file instead.")
|
560 |
audio_path = temp_input_path
|
561 |
else:
|
562 |
# For already WAV files, use them directly
|
|
|
566 |
results = detector.analyze_audio(audio_path)
|
567 |
|
568 |
# Clean up
|
569 |
+
if audio_path and audio_path != temp_input_path and os.path.exists(audio_path):
|
570 |
os.remove(audio_path)
|
571 |
|
572 |
return results
|
573 |
|
574 |
except Exception as e:
|
575 |
+
error_msg = str(e)
|
576 |
+
st.error(f"Error processing audio: {error_msg}")
|
577 |
+
|
578 |
+
# Add detailed debugging info
|
579 |
+
import traceback
|
580 |
+
st.error(f"Error details: {traceback.format_exc()}")
|
581 |
+
|
582 |
+
# Show file info if available
|
583 |
+
if temp_input_path and os.path.exists(temp_input_path):
|
584 |
+
st.info(f"Input file exists: {temp_input_path}, size: {os.path.getsize(temp_input_path)} bytes")
|
585 |
os.remove(temp_input_path)
|
586 |
+
else:
|
587 |
+
if temp_input_path:
|
588 |
+
st.warning(f"Input file does not exist: {temp_input_path}")
|
589 |
+
|
590 |
+
if audio_path and os.path.exists(audio_path):
|
591 |
+
st.info(f"Audio file exists: {audio_path}, size: {os.path.getsize(audio_path)} bytes")
|
592 |
os.remove(audio_path)
|
593 |
+
else:
|
594 |
+
if audio_path:
|
595 |
+
st.warning(f"Audio file does not exist: {audio_path}")
|
596 |
+
|
597 |
+
# Check for common error types
|
598 |
+
if "ffmpeg" in error_msg.lower():
|
599 |
+
st.warning("FFmpeg error detected. The audio conversion failed.")
|
600 |
+
st.info("Try a different audio format or check if FFmpeg is installed correctly.")
|
601 |
+
elif "permission" in error_msg.lower():
|
602 |
+
st.warning("Permission error detected.")
|
603 |
+
st.info("Check that the uploads directory is writable.")
|
604 |
+
elif "no such file" in error_msg.lower():
|
605 |
+
st.warning("File not found error detected.")
|
606 |
+
st.info("The file may have been moved, deleted, or not saved correctly.")
|
607 |
+
|
608 |
raise
|
609 |
+
|
610 |
return results
|
611 |
|
612 |
# --- Streamlit App ---
|
|
|
733 |
# Show explanation in a box
|
734 |
st.markdown("### Expert Analysis")
|
735 |
st.info(results['explanation'])
|
736 |
+
with col2:
|
|
|
737 |
if results['audio_viz']:
|
738 |
try:
|
739 |
st.pyplot(results['audio_viz'])
|
740 |
except Exception as viz_error:
|
741 |
st.warning("Could not display visualization due to torchvision issue.")
|
742 |
+
st.info("Audio analysis was successful even though visualization failed.")
|
743 |
+
|
744 |
+
# Show audio playback
|
745 |
st.audio(audio_path)
|
746 |
|
747 |
# Clean up files
|
|
|
807 |
# First save the file to a known location to bypass 403 errors
|
808 |
# Create an uploads directory if it doesn't exist
|
809 |
uploads_dir = os.path.join(os.getcwd(), "uploads")
|
810 |
+
os.makedirs(uploads_dir, exist_ok=True) # Save the file first to avoid streaming it multiple times
|
|
|
811 |
temp_file_path = os.path.join(uploads_dir, f"temp_{int(time.time())}_{uploaded_file.name}")
|
812 |
with open(temp_file_path, "wb") as f:
|
813 |
f.write(uploaded_file.getbuffer())
|
814 |
|
815 |
progress_bar.progress(50, text="Analyzing audio...")
|
816 |
|
817 |
+
# Process using the saved file path directly
|
818 |
+
results = process_uploaded_audio(temp_file_path)
|
819 |
|
820 |
progress_bar.progress(100, text="Analysis complete!")
|
821 |
# Display results
|