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
|