Update app.py
Browse files
app.py
CHANGED
|
@@ -1,3 +1,209 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
#!/usr/bin/env python3
|
| 2 |
"""
|
| 3 |
Final Fixed Video Background Replacement
|
|
@@ -6,6 +212,7 @@
|
|
| 6 |
improved error handling, and better resource management
|
| 7 |
FIXED: All issues identified by Grok4 - robust error handling, variable scope, codec fallbacks
|
| 8 |
FIXED: Added SSR mode disable for Gradio compatibility
|
|
|
|
| 9 |
"""
|
| 10 |
import cv2
|
| 11 |
import numpy as np
|
|
@@ -519,16 +726,44 @@ def _prog(pct: float, desc: str):
|
|
| 519 |
if result is None:
|
| 520 |
return None, message
|
| 521 |
|
| 522 |
-
# Add audio back -
|
| 523 |
_prog(0.9, "Adding audio...")
|
| 524 |
final_with_audio = f"/tmp/twostage_audio_{timestamp}.mp4"
|
| 525 |
|
| 526 |
-
|
| 527 |
-
|
| 528 |
-
'
|
| 529 |
-
'-
|
| 530 |
-
|
| 531 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 532 |
|
| 533 |
if audio_success and os.path.exists(final_with_audio):
|
| 534 |
try:
|
|
@@ -735,19 +970,47 @@ def _prog(pct: float, desc: str):
|
|
| 735 |
if preview_mask or preview_greenscreen:
|
| 736 |
final_output = output_path
|
| 737 |
else:
|
| 738 |
-
# Add audio back for final output -
|
| 739 |
_prog(0.9, "Adding audio...")
|
| 740 |
final_output = f"/tmp/final_{timestamp}.mp4"
|
| 741 |
|
| 742 |
-
|
| 743 |
-
|
| 744 |
-
'
|
| 745 |
-
'-
|
| 746 |
-
|
| 747 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 748 |
|
| 749 |
if not audio_success or not os.path.exists(final_output):
|
| 750 |
-
logger.warning("
|
| 751 |
try:
|
| 752 |
shutil.copy2(output_path, final_output)
|
| 753 |
except Exception as e:
|
|
@@ -818,4 +1081,5 @@ def main():
|
|
| 818 |
print(f"Startup failed: {e}")
|
| 819 |
|
| 820 |
if __name__ == "__main__":
|
| 821 |
-
main()
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
|
| 3 |
+
RetryMAnd can we add the AI build backgrounds that I have in one of the previous app's? And more different Gradiant choicesEditRelevant chats4 resultsBackgroundFX Pro: Video Processing PipelineBackgroundFX Pro App DevelopmentGradio App Version Compatibility FixRetrieving Previous App.py CodeAbsolut
|
| 4 |
+
|
| 5 |
+
pasted
|
| 6 |
+
|
| 7 |
+
Dont code just yet
|
| 8 |
+
|
| 9 |
+
I can see you have an enhanced BackgroundFX Pro app with AI-generated backgrounds and extended gradient choices! Looking at the document, it shows a comprehensive system with:
|
| 10 |
+
|
| 11 |
+
Four background methods:
|
| 12 |
+
|
| 13 |
+
Professional - Pre-made backgrounds
|
| 14 |
+
Upload - Custom image upload
|
| 15 |
+
Colors - Enhanced gradients (15+ styles, 3-color support)
|
| 16 |
+
AI - Text-to-background generation
|
| 17 |
+
AI Background Features:
|
| 18 |
+
|
| 19 |
+
4 different styles: Abstract, Gradient, Geometric, Texture
|
| 20 |
+
Smart color mapping based on keywords (sunset, ocean, forest, neon, space, etc.)
|
| 21 |
+
Procedural generation from text prompts like "sunset over mountains" or "neon cyberpunk city"
|
| 22 |
+
Enhanced Gradients:
|
| 23 |
+
|
| 24 |
+
15+ gradient styles (vertical, horizontal, diagonal, radial, sunset, ocean, forest, neon, space, fire, ice, desert, purple dream, gold rush)
|
| 25 |
+
3-color gradient support with custom color pickers
|
| 26 |
+
This looks like a really comprehensive background system! What would you like me to help you with regarding this app? Are you looking to:
|
| 27 |
+
|
| 28 |
+
Modify or enhance any of these features?
|
| 29 |
+
Add new background generation capabilities?
|
| 30 |
+
Improve the UI/UX?
|
| 31 |
+
Debug any issues?
|
| 32 |
+
Deploy or test the current version?
|
| 33 |
+
Just let me know what direction you'd like to take this!
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
image.png
|
| 39 |
+
Just 2 smallish issues
|
| 40 |
+
|
| 41 |
+
1) Audio has gone missing..
|
| 42 |
+
2) Still slightly rough around the edges
|
| 43 |
+
and occational "blibs"
|
| 44 |
+
|
| 45 |
+
I can see the issues! Looking at your processed video:
|
| 46 |
+
|
| 47 |
+
Issue 1: Missing Audio 🔇 This is likely happening in the video processing pipeline where the audio track isn't being preserved during background replacement. The background removal/replacement process is probably only handling the video stream and dropping the audio.
|
| 48 |
+
|
| 49 |
+
Issue 2: Rough Edges & Blips 👤 I can see some edge artifacts around the person - the background replacement isn't perfectly clean. There are some rough transitions and occasional "blips" where the segmentation isn't smooth.
|
| 50 |
+
|
| 51 |
+
Quick fixes needed:
|
| 52 |
+
|
| 53 |
+
For Audio:
|
| 54 |
+
|
| 55 |
+
Ensure audio track preservation during processing
|
| 56 |
+
Add audio passthrough in the video pipeline
|
| 57 |
+
Check if audio codec compatibility issues
|
| 58 |
+
For Edge Quality:
|
| 59 |
+
|
| 60 |
+
Improve edge smoothing/feathering
|
| 61 |
+
Add temporal consistency between frames
|
| 62 |
+
Better segmentation model or post-processing
|
| 63 |
+
Edge refinement algorithms
|
| 64 |
+
Would you like me to:
|
| 65 |
+
|
| 66 |
+
Fix the audio preservation first (probably the easier fix)
|
| 67 |
+
Improve the edge detection/smoothing algorithms
|
| 68 |
+
Both simultaneously
|
| 69 |
+
Look at the current processing pipeline to diagnose exactly where these issues are occurring
|
| 70 |
+
Which would you prefer to tackle first? The audio fix might be quicker to implement, while the edge quality will need more sophisticated processing improvements.
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
Yes, lets start with getting audio back
|
| 76 |
+
|
| 77 |
+
What file do you need to see
|
| 78 |
+
|
| 79 |
+
To fix the audio issue, I'll need to see the video processing pipeline file. This is likely where the audio is getting dropped during background replacement.
|
| 80 |
+
|
| 81 |
+
Could you show me:
|
| 82 |
+
|
| 83 |
+
The main video processing function - probably in a file like:
|
| 84 |
+
video_processor.py
|
| 85 |
+
background_processor.py
|
| 86 |
+
The processing function in ui_components.py (the safe_process_video function)
|
| 87 |
+
Or whatever file handles the actual video manipulation
|
| 88 |
+
Any OpenCV/FFmpeg video writing code - where the output video is being saved
|
| 89 |
+
The audio loss typically happens in one of these places:
|
| 90 |
+
|
| 91 |
+
When reading the video (not extracting audio track)
|
| 92 |
+
During frame-by-frame processing (only processing video frames)
|
| 93 |
+
When writing the output video (not including audio stream)
|
| 94 |
+
Which file contains your video processing logic? That's where we'll likely find and fix the audio issue.
|
| 95 |
+
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
#!/usr/bin/env python3 """ Enhanced UI Components - BackgroundFX Pro with AI Backgrounds & Extended Gradients """ import gradio as gr import os import time import traceback import cv2 import numpy as np from typing import Optional, Tuple from PIL import Image import requests import random # Apply G
|
| 101 |
+
|
| 102 |
+
pasted
|
| 103 |
+
|
| 104 |
+
So this one
|
| 105 |
+
|
| 106 |
+
Found it! I can see the issue with the audio. Looking at your ui_components.py, the problem is that the video processing calls process_video_fixed from app.py, but I don't see the actual video processing pipeline code here.
|
| 107 |
+
|
| 108 |
+
The audio is likely being lost in the process_video_fixed function. To fix this, I need to see:
|
| 109 |
+
|
| 110 |
+
The app.py file - specifically the process_video_fixed function
|
| 111 |
+
|
| 112 |
+
This is where the actual video processing happens, and that's where we need to ensure audio preservation. The current flow is:
|
| 113 |
+
|
| 114 |
+
ui_components.py calls process_video_fixed()
|
| 115 |
+
process_video_fixed() does the background replacement
|
| 116 |
+
Audio gets dropped somewhere in this process
|
| 117 |
+
Could you show me the app.py file, particularly the process_video_fixed function? That's where we'll need to:
|
| 118 |
+
|
| 119 |
+
Extract the audio track from the input video
|
| 120 |
+
Process only the video frames for background replacement
|
| 121 |
+
Recombine the processed video with the original audio track
|
| 122 |
+
The fix will likely involve using FFmpeg to preserve audio during the processing pipeline.
|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
#!/usr/bin/env python3 """ Final Fixed Video Background Replacement Uses proper functions from utilities.py to avoid transparency issues NEW: Added automatic device detection for Hugging Face Spaces compatibility, improved error handling, and better resource management FIXED: All issues identif
|
| 129 |
+
|
| 130 |
+
pasted
|
| 131 |
+
|
| 132 |
+
Found the audio issue! Looking at your process_video_fixed function in app.py, I can see exactly where the audio is getting lost.
|
| 133 |
+
|
| 134 |
+
The problem is in line 681-692 where the audio processing happens:
|
| 135 |
+
|
| 136 |
+
python
|
| 137 |
+
# Add audio back for final output - ROBUST VERSION
|
| 138 |
+
_prog(0.9, "Adding audio...")
|
| 139 |
+
final_output = f"/tmp/final_{timestamp}.mp4"
|
| 140 |
+
|
| 141 |
+
audio_success = run_ffmpeg_command([
|
| 142 |
+
'ffmpeg', '-y', '-i', output_path, '-i', video_path,
|
| 143 |
+
'-c:v', 'libx264', '-crf', '18', '-preset', 'medium',
|
| 144 |
+
'-c:a', 'aac', '-b:a', '192k', '-ac', '2', '-ar', '48000',
|
| 145 |
+
'-map', '0:v:0', '-map', '1:a:0?', '-shortest', final_output
|
| 146 |
+
], "Audio processing")
|
| 147 |
+
The issue is the -map '1:a:0?' parameter. The ? makes the audio stream optional, so if there's any issue finding the audio stream, FFmpeg just continues without audio instead of failing.
|
| 148 |
+
|
| 149 |
+
Here's the fix:
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
Fixed Audio Processing Function
|
| 153 |
+
Code
|
| 154 |
+
The key changes to fix the audio issue:
|
| 155 |
+
|
| 156 |
+
Check for audio first - Use ffprobe to verify the input video actually has an audio stream
|
| 157 |
+
Remove the optional mapping - Changed -map '1:a:0?' to -map '1:a:0' so FFmpeg will fail if it can't find audio (alerting us to the problem)
|
| 158 |
+
Use -c:v copy - Copies the processed video without re-encoding (faster and preserves quality)
|
| 159 |
+
Fallback method - If the first method fails, try swapping the input order
|
| 160 |
+
Better error handling - Provides clear feedback when audio processing fails
|
| 161 |
+
To implement this fix:
|
| 162 |
+
|
| 163 |
+
Replace the audio processing section in your app.py file (around lines 681-692) with the code from the artifact above.
|
| 164 |
+
|
| 165 |
+
This should resolve the missing audio issue. The fix ensures that:
|
| 166 |
+
|
| 167 |
+
Audio is preserved when present in the source video
|
| 168 |
+
Clear logging when audio is missing or fails to process
|
| 169 |
+
Fallback methods if the primary audio processing fails
|
| 170 |
+
No silent failures that drop audio without warning
|
| 171 |
+
Want me to help you implement this fix, or do you have any questions about how it works?
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
CAn you please print the full app.py ( all the lines of code)
|
| 177 |
+
|
| 178 |
+
|
| 179 |
+
Complete app.py with Audio Fix
|
| 180 |
+
Code
|
| 181 |
+
Here's the complete app.py file with the audio fix implemented. The key changes I made to fix the missing audio issue:
|
| 182 |
+
|
| 183 |
+
Audio Fix Highlights:
|
| 184 |
+
|
| 185 |
+
Added audio detection - Lines 560-564: Uses ffprobe to check if the input video actually has an audio stream before trying to copy it
|
| 186 |
+
Removed optional audio mapping - Changed -map '1:a:0?' to -map '1:a:0' so FFmpeg will fail if it can't find audio instead of silently continuing without it
|
| 187 |
+
Used -c:v copy - Lines 566-569: Copies the processed video without re-encoding for faster processing and better quality
|
| 188 |
+
Added fallback method - Lines 571-578: If the primary audio method fails, tries a different input order mapping
|
| 189 |
+
Better error handling - Lines 580-589: Handles cases where input has no audio and provides clear logging
|
| 190 |
+
Applied to both modes - The fix is implemented for both single-stage (lines 687-726) and two-stage processing (lines 560-590)
|
| 191 |
+
The audio processing now:
|
| 192 |
+
|
| 193 |
+
Detects if the source video has audio
|
| 194 |
+
Preserves audio when present
|
| 195 |
+
Logs clearly when audio is missing or processing fails
|
| 196 |
+
Falls back gracefully if the primary method doesn't work
|
| 197 |
+
Never silently drops audio without warning
|
| 198 |
+
This should completely resolve the missing audio issue. The processed videos will now retain their original audio tracks.
|
| 199 |
+
|
| 200 |
+
|
| 201 |
+
|
| 202 |
+
|
| 203 |
+
|
| 204 |
+
|
| 205 |
+
|
| 206 |
+
|
| 207 |
#!/usr/bin/env python3
|
| 208 |
"""
|
| 209 |
Final Fixed Video Background Replacement
|
|
|
|
| 212 |
improved error handling, and better resource management
|
| 213 |
FIXED: All issues identified by Grok4 - robust error handling, variable scope, codec fallbacks
|
| 214 |
FIXED: Added SSR mode disable for Gradio compatibility
|
| 215 |
+
FIXED: Audio preservation - no more missing audio in processed videos
|
| 216 |
"""
|
| 217 |
import cv2
|
| 218 |
import numpy as np
|
|
|
|
| 726 |
if result is None:
|
| 727 |
return None, message
|
| 728 |
|
| 729 |
+
# Add audio back - FIXED VERSION
|
| 730 |
_prog(0.9, "Adding audio...")
|
| 731 |
final_with_audio = f"/tmp/twostage_audio_{timestamp}.mp4"
|
| 732 |
|
| 733 |
+
# First, check if input video has audio
|
| 734 |
+
audio_check_success = run_ffmpeg_command([
|
| 735 |
+
'ffprobe', '-v', 'quiet', '-select_streams', 'a:0',
|
| 736 |
+
'-show_entries', 'stream=codec_name', '-of', 'csv=p=0', video_path
|
| 737 |
+
], "Checking for audio stream")
|
| 738 |
+
|
| 739 |
+
if audio_check_success:
|
| 740 |
+
# Input has audio - copy it with video
|
| 741 |
+
audio_success = run_ffmpeg_command([
|
| 742 |
+
'ffmpeg', '-y', '-i', final_output, '-i', video_path,
|
| 743 |
+
'-c:v', 'copy', # Copy video without re-encoding (faster)
|
| 744 |
+
'-c:a', 'aac', '-b:a', '192k', '-ac', '2', '-ar', '48000',
|
| 745 |
+
'-map', '0:v:0', '-map', '1:a:0', '-shortest', final_with_audio # Removed the '?'
|
| 746 |
+
], "Two-stage audio processing with original audio")
|
| 747 |
+
|
| 748 |
+
if not audio_success or not os.path.exists(final_with_audio):
|
| 749 |
+
logger.warning("Failed with original audio, trying fallback method...")
|
| 750 |
+
# Fallback: try different mapping
|
| 751 |
+
audio_success = run_ffmpeg_command([
|
| 752 |
+
'ffmpeg', '-y', '-i', video_path, '-i', final_output,
|
| 753 |
+
'-c:v', 'libx264', '-crf', '18', '-preset', 'fast',
|
| 754 |
+
'-c:a', 'copy', # Copy audio without re-encoding
|
| 755 |
+
'-map', '1:v:0', '-map', '0:a:0', '-shortest', final_with_audio
|
| 756 |
+
], "Fallback two-stage audio processing")
|
| 757 |
+
else:
|
| 758 |
+
logger.info("Input video has no audio stream")
|
| 759 |
+
# No audio in source - just use processed video
|
| 760 |
+
try:
|
| 761 |
+
shutil.copy2(final_output, final_with_audio)
|
| 762 |
+
audio_success = True
|
| 763 |
+
except Exception as e:
|
| 764 |
+
logger.error(f"Failed to copy video: {e}")
|
| 765 |
+
audio_success = False
|
| 766 |
+
final_with_audio = final_output
|
| 767 |
|
| 768 |
if audio_success and os.path.exists(final_with_audio):
|
| 769 |
try:
|
|
|
|
| 970 |
if preview_mask or preview_greenscreen:
|
| 971 |
final_output = output_path
|
| 972 |
else:
|
| 973 |
+
# Add audio back for final output - FIXED VERSION
|
| 974 |
_prog(0.9, "Adding audio...")
|
| 975 |
final_output = f"/tmp/final_{timestamp}.mp4"
|
| 976 |
|
| 977 |
+
# First, check if input video has audio
|
| 978 |
+
audio_check_success = run_ffmpeg_command([
|
| 979 |
+
'ffprobe', '-v', 'quiet', '-select_streams', 'a:0',
|
| 980 |
+
'-show_entries', 'stream=codec_name', '-of', 'csv=p=0', video_path
|
| 981 |
+
], "Checking for audio stream")
|
| 982 |
+
|
| 983 |
+
if audio_check_success:
|
| 984 |
+
# Input has audio - copy it with video
|
| 985 |
+
audio_success = run_ffmpeg_command([
|
| 986 |
+
'ffmpeg', '-y', '-i', output_path, '-i', video_path,
|
| 987 |
+
'-c:v', 'copy', # Copy video without re-encoding (faster)
|
| 988 |
+
'-c:a', 'aac', '-b:a', '192k', '-ac', '2', '-ar', '48000',
|
| 989 |
+
'-map', '0:v:0', '-map', '1:a:0', '-shortest', final_output # Removed the '?'
|
| 990 |
+
], "Audio processing with original audio")
|
| 991 |
+
|
| 992 |
+
if not audio_success or not os.path.exists(final_output):
|
| 993 |
+
logger.warning("Failed with original audio, trying fallback method...")
|
| 994 |
+
# Fallback: try different mapping
|
| 995 |
+
audio_success = run_ffmpeg_command([
|
| 996 |
+
'ffmpeg', '-y', '-i', video_path, '-i', output_path,
|
| 997 |
+
'-c:v', 'libx264', '-crf', '18', '-preset', 'fast',
|
| 998 |
+
'-c:a', 'copy', # Copy audio without re-encoding
|
| 999 |
+
'-map', '1:v:0', '-map', '0:a:0', '-shortest', final_output
|
| 1000 |
+
], "Fallback audio processing")
|
| 1001 |
+
else:
|
| 1002 |
+
logger.info("Input video has no audio stream")
|
| 1003 |
+
# No audio in source - just use processed video
|
| 1004 |
+
try:
|
| 1005 |
+
shutil.copy2(output_path, final_output)
|
| 1006 |
+
audio_success = True
|
| 1007 |
+
except Exception as e:
|
| 1008 |
+
logger.error(f"Failed to copy video: {e}")
|
| 1009 |
+
audio_success = False
|
| 1010 |
+
final_output = output_path
|
| 1011 |
|
| 1012 |
if not audio_success or not os.path.exists(final_output):
|
| 1013 |
+
logger.warning("All audio processing failed, using video without audio")
|
| 1014 |
try:
|
| 1015 |
shutil.copy2(output_path, final_output)
|
| 1016 |
except Exception as e:
|
|
|
|
| 1081 |
print(f"Startup failed: {e}")
|
| 1082 |
|
| 1083 |
if __name__ == "__main__":
|
| 1084 |
+
main()
|
| 1085 |
+
BackgroundFX Pro App Features - Claude
|