Spaces:
Runtime error
Runtime error
Updated app.py with mixing and mastering functionality
Browse files
app.py
CHANGED
|
@@ -7,7 +7,18 @@ from apiTest import sas_token_1
|
|
| 7 |
from apiTest import sas_url_1
|
| 8 |
from apiTest import videoAnalysis
|
| 9 |
from apiTest import instance_1
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
|
| 12 |
def predict_video(input_video, input_audio=None, input_choice="Explosions"):
|
| 13 |
global filename, file_size # Use the global keyword to refer to the global variables
|
|
@@ -25,10 +36,30 @@ def predict_video(input_video, input_audio=None, input_choice="Explosions"):
|
|
| 25 |
|
| 26 |
if file_size > 20 * 1024 * 1024:
|
| 27 |
return [None, "Error: The upload exceeds file size 16MB. Please upload a smaller file."]
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
"""
|
| 33 |
Processes the uploaded video (replace with your video analysis logic).
|
| 34 |
|
|
@@ -40,17 +71,101 @@ def predict_video(input_video, input_audio=None, input_choice="Explosions"):
|
|
| 40 |
A list containing the processed video and a message string.
|
| 41 |
"""
|
| 42 |
|
| 43 |
-
videoAnalysis(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
|
| 45 |
-
#
|
| 46 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
|
| 48 |
# You can optionally add a progress bar or loading indicator here
|
| 49 |
|
| 50 |
-
if input_audio is None:
|
| 51 |
-
return [input_video, message + " Generated Audio will be used"]
|
| 52 |
-
AzureBlobStorageAudio.uploadUserAudioToBlobStorage(input_audio,"test8")
|
| 53 |
-
return [input_video, message + f" Using uploaded audio: {input_audio.name}"]
|
| 54 |
|
| 55 |
css = """
|
| 56 |
#col-container {
|
|
@@ -101,19 +216,7 @@ with gr.Blocks(css=css) as demo:
|
|
| 101 |
outputs=[video_out, text_out],
|
| 102 |
#cache_examples=True # Cache examples for faster loading
|
| 103 |
)
|
| 104 |
-
|
| 105 |
-
gr.HTML("""
|
| 106 |
-
<h3> Audio Library </h2>
|
| 107 |
-
<p> <a href="https://audiolibrary.blob.core.windows.net/audiolibrary/1_seconds_haptic_audio.mp3"> Explosion Audio Track 1 </a>
|
| 108 |
-
<br> <a href="https://audiolibrary.blob.core.windows.net/audiolibrary/5_seconds_haptic_videos.mp3"> Explosion Audio Track 2 </a>
|
| 109 |
-
<br> <a href="https://audiolibrary.blob.core.windows.net/audiolibrary/6_seconds_haptic_audio.mp3"> Explosion Audio Track 3 </a>
|
| 110 |
-
<br> <a href="https://audiolibrary.blob.core.windows.net/audiolibrary/7_seconds_haptic_audio.mp3"> Explosion Audio Track 4 </a>
|
| 111 |
-
<br> <a href="https://audiolibrary.blob.core.windows.net/audiolibrary/9_seconds_haptic_videos.mp3"> Explosion Audio Track 5 </a>
|
| 112 |
-
<br> <a href="https://audiolibrary.blob.core.windows.net/audiolibrary/5_seconds_vehicle_audio.mp3"> Vehicle Audio Track 1 </a>
|
| 113 |
-
<br> <a href="https://audiolibrary.blob.core.windows.net/audiolibrary/30_seconds_vehicle_audio.mp3"> Vehicle Audio Track 2 </a>
|
| 114 |
-
</p>
|
| 115 |
-
""")
|
| 116 |
-
|
| 117 |
btn_in.click(
|
| 118 |
fn=predict_video,
|
| 119 |
inputs=[video_in,audio_in,choice_in],
|
|
|
|
| 7 |
from apiTest import sas_url_1
|
| 8 |
from apiTest import videoAnalysis
|
| 9 |
from apiTest import instance_1
|
| 10 |
+
import Moviepy
|
| 11 |
+
from Moviepy import extract_audio_from_video
|
| 12 |
+
from Moviepy import load_json_output
|
| 13 |
+
from Moviepy import get_explosion_segments
|
| 14 |
+
from Moviepy import create_final_audio
|
| 15 |
+
from Moviepy import save_audio
|
| 16 |
+
from Moviepy import without_audio
|
| 17 |
+
from Moviepy import combine_video_audio
|
| 18 |
+
from Moviepy import save_video
|
| 19 |
+
import subprocess
|
| 20 |
+
from moviepy.editor import *
|
| 21 |
+
import json
|
| 22 |
|
| 23 |
def predict_video(input_video, input_audio=None, input_choice="Explosions"):
|
| 24 |
global filename, file_size # Use the global keyword to refer to the global variables
|
|
|
|
| 36 |
|
| 37 |
if file_size > 20 * 1024 * 1024:
|
| 38 |
return [None, "Error: The upload exceeds file size 16MB. Please upload a smaller file."]
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
# 1. Upload user video file to azure blob storage
|
| 43 |
+
|
| 44 |
+
#AzureBlobStorageVideo.uploadUserVideoToBlobStorage(input_video, filename)
|
| 45 |
+
|
| 46 |
+
#return [input_video, f" Using uploaded audio: {input_audio.name}"]
|
| 47 |
+
# IF user uploads audio file: upload audio file to blob storage
|
| 48 |
+
# ELSE use default audio file from blob storage
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
# message = "**Placeholder:** Video processing not implemented yet."
|
| 52 |
+
#
|
| 53 |
+
# if input_audio is not None:
|
| 54 |
+
# AzureBlobStorageAudio.uploadUserAudioToBlobStorage(input_audio, "test8")
|
| 55 |
+
# return [input_video, message + f" Using uploaded audio: {input_audio.name}"]
|
| 56 |
+
# else:
|
| 57 |
+
# return [input_video, message + " Generated Audio will be used"]
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
# 2. Analyze video and predict timestamps
|
| 62 |
+
|
| 63 |
"""
|
| 64 |
Processes the uploaded video (replace with your video analysis logic).
|
| 65 |
|
|
|
|
| 71 |
A list containing the processed video and a message string.
|
| 72 |
"""
|
| 73 |
|
| 74 |
+
#responseQueryText = videoAnalysis(sas_url_1, sas_token_1, input_choice)
|
| 75 |
+
|
| 76 |
+
# IF method returns error: run analysis again
|
| 77 |
+
#if responseQueryText == """{"error":{"code":"InvalidRequest","message":"Value for indexName is invalid."}}""":
|
| 78 |
+
# responseQueryText = videoAnalysis(sas_url_1, sas_token_1, input_choice)
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
# 3. Use moviepy to add haptics to video
|
| 83 |
+
|
| 84 |
+
#install masteringModule dependencies
|
| 85 |
+
#os.chdir("masteringModule")
|
| 86 |
+
#npminstall = subprocess.run(["npm", "install", "masteringModule/package.json"])
|
| 87 |
+
#os.chdir("..")
|
| 88 |
|
| 89 |
+
# install moviepy dependency
|
| 90 |
+
moviepy = subprocess.run(["pip", "install", "moviepy"])
|
| 91 |
+
|
| 92 |
+
# 3.1. Extract audio from video
|
| 93 |
+
#extractedAudioPath = extract_audio_from_video(input_video)
|
| 94 |
+
|
| 95 |
+
# 3.2. Mix extracted audio with haptic audio
|
| 96 |
+
|
| 97 |
+
# Load JSON output
|
| 98 |
+
output_query_response = '{"value":[{"documentId":"sp=r&st=2024-02-09T12:33:24Z&se=2025-08-06T20:33:24Z&spr=https&sv=2022-11-02&sr=b&sig=V%2Fq56JjGcL60r0vt3oAPjzx%2FZMu5%2BJo%2BfjKkJF2ccgo%3D","documentKind":"VideoInterval","start":"00:00:16","end":"00:00:26","best":"00:00:21","relevance":0.4005849361419678},{"documentId":"sp=r&st=2024-02-09T12:33:24Z&se=2025-08-06T20:33:24Z&spr=https&sv=2022-11-02&sr=b&sig=V%2Fq56JjGcL60r0vt3oAPjzx%2FZMu5%2BJo%2BfjKkJF2ccgo%3D","documentKind":"VideoInterval","start":"00:00:06","end":"00:00:16","best":"00:00:09","relevance":0.38852864503860474},{"documentId":"sp=r&st=2024-02-09T12:33:24Z&se=2025-08-06T20:33:24Z&spr=https&sv=2022-11-02&sr=b&sig=V%2Fq56JjGcL60r0vt3oAPjzx%2FZMu5%2BJo%2BfjKkJF2ccgo%3D","documentKind":"VideoInterval","start":"00:01:42","end":"00:01:58","best":"00:01:43","relevance":0.38718080520629883},{"documentId":"sp=r&st=2024-02-09T12:33:24Z&se=2025-08-06T20:33:24Z&spr=https&sv=2022-11-02&sr=b&sig=V%2Fq56JjGcL60r0vt3oAPjzx%2FZMu5%2BJo%2BfjKkJF2ccgo%3D","documentKind":"VideoInterval","start":"00:01:58","end":"00:02:14","best":"00:02:03","relevance":0.3811851143836975},{"documentId":"sp=r&st=2024-02-09T12:33:24Z&se=2025-08-06T20:33:24Z&spr=https&sv=2022-11-02&sr=b&sig=V%2Fq56JjGcL60r0vt3oAPjzx%2FZMu5%2BJo%2BfjKkJF2ccgo%3D","documentKind":"VideoInterval","start":"00:00:42","end":"00:00:52","best":"00:00:42","relevance":0.3765566647052765},{"documentId":"sp=r&st=2024-02-09T12:33:24Z&se=2025-08-06T20:33:24Z&spr=https&sv=2022-11-02&sr=b&sig=V%2Fq56JjGcL60r0vt3oAPjzx%2FZMu5%2BJo%2BfjKkJF2ccgo%3D","documentKind":"VideoInterval","start":"00:00:26","end":"00:00:42","best":"00:00:28","relevance":0.3718773126602173},{"documentId":"sp=r&st=2024-02-09T12:33:24Z&se=2025-08-06T20:33:24Z&spr=https&sv=2022-11-02&sr=b&sig=V%2Fq56JjGcL60r0vt3oAPjzx%2FZMu5%2BJo%2BfjKkJF2ccgo%3D","documentKind":"VideoInterval","start":"00:01:08","end":"00:01:24","best":"00:01:10","relevance":0.3707084357738495},{"documentId":"sp=r&st=2024-02-09T12:33:24Z&se=2025-08-06T20:33:24Z&spr=https&sv=2022-11-02&sr=b&sig=V%2Fq56JjGcL60r0vt3oAPjzx%2FZMu5%2BJo%2BfjKkJF2ccgo%3D","documentKind":"VideoInterval","start":"00:01:37","end":"00:01:42","best":"00:01:38","relevance":0.36235538125038147},{"documentId":"sp=r&st=2024-02-09T12:33:24Z&se=2025-08-06T20:33:24Z&spr=https&sv=2022-11-02&sr=b&sig=V%2Fq56JjGcL60r0vt3oAPjzx%2FZMu5%2BJo%2BfjKkJF2ccgo%3D","documentKind":"VideoInterval","start":"00:01:29","end":"00:01:37","best":"00:01:33","relevance":0.3606133460998535},{"documentId":"sp=r&st=2024-02-09T12:33:24Z&se=2025-08-06T20:33:24Z&spr=https&sv=2022-11-02&sr=b&sig=V%2Fq56JjGcL60r0vt3oAPjzx%2FZMu5%2BJo%2BfjKkJF2ccgo%3D","documentKind":"VideoInterval","start":"00:01:03","end":"00:01:08","best":"00:01:04","relevance":0.3513660728931427},{"documentId":"sp=r&st=2024-02-09T12:33:24Z&se=2025-08-06T20:33:24Z&spr=https&sv=2022-11-02&sr=b&sig=V%2Fq56JjGcL60r0vt3oAPjzx%2FZMu5%2BJo%2BfjKkJF2ccgo%3D","documentKind":"VideoInterval","start":"00:00:00","end":"00:00:06","best":"00:00:05","relevance":0.3378048241138458}]}' # JSON response
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
json_data = load_json_output(output_query_response)
|
| 102 |
+
|
| 103 |
+
# Extract audio from the video
|
| 104 |
+
audio_path = extract_audio_from_video(input_video)
|
| 105 |
+
# Get explosion segments
|
| 106 |
+
explosion_segments = get_explosion_segments(json_data)
|
| 107 |
+
|
| 108 |
+
# Create final audio
|
| 109 |
+
final_audio = create_final_audio(audio_path, explosion_segments)
|
| 110 |
+
|
| 111 |
+
# Save enhanced audio
|
| 112 |
+
finalAudioPath = "audio/finalAudio.mp3"
|
| 113 |
+
save_audio(final_audio, finalAudioPath)
|
| 114 |
+
|
| 115 |
+
# Apply audio mastering
|
| 116 |
+
|
| 117 |
+
master = subprocess.run(["node", "masteringModule/main.js", "--input", finalAudioPath, "--output", finalAudioPath])
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
# Extract video without audio
|
| 122 |
+
current_video = without_audio(VideoFileClip(input_video))
|
| 123 |
+
|
| 124 |
+
# Combine video with final audio
|
| 125 |
+
final_video = combine_video_audio(current_video, final_audio)
|
| 126 |
+
|
| 127 |
+
# Save final video
|
| 128 |
+
save_video(final_video, "video/final_enhanced_video.mp4")
|
| 129 |
+
finalVideoPath = "video/final_enhanced_video.mp4"
|
| 130 |
+
|
| 131 |
+
# 3.2.1. modify query response
|
| 132 |
+
#hard-coded query response
|
| 133 |
+
# output_query_response = '{"value":[{"documentId":"sp=r&st=2024-02-09T12:33:24Z&se=2025-08-06T20:33:24Z&spr=https&sv=2022-11-02&sr=b&sig=V%2Fq56JjGcL60r0vt3oAPjzx%2FZMu5%2BJo%2BfjKkJF2ccgo%3D","documentKind":"VideoInterval","start":"00:00:16","end":"00:00:26","best":"00:00:21","relevance":0.4005849361419678},{"documentId":"sp=r&st=2024-02-09T12:33:24Z&se=2025-08-06T20:33:24Z&spr=https&sv=2022-11-02&sr=b&sig=V%2Fq56JjGcL60r0vt3oAPjzx%2FZMu5%2BJo%2BfjKkJF2ccgo%3D","documentKind":"VideoInterval","start":"00:00:06","end":"00:00:16","best":"00:00:09","relevance":0.38852864503860474},{"documentId":"sp=r&st=2024-02-09T12:33:24Z&se=2025-08-06T20:33:24Z&spr=https&sv=2022-11-02&sr=b&sig=V%2Fq56JjGcL60r0vt3oAPjzx%2FZMu5%2BJo%2BfjKkJF2ccgo%3D","documentKind":"VideoInterval","start":"00:01:42","end":"00:01:58","best":"00:01:43","relevance":0.38718080520629883},{"documentId":"sp=r&st=2024-02-09T12:33:24Z&se=2025-08-06T20:33:24Z&spr=https&sv=2022-11-02&sr=b&sig=V%2Fq56JjGcL60r0vt3oAPjzx%2FZMu5%2BJo%2BfjKkJF2ccgo%3D","documentKind":"VideoInterval","start":"00:01:58","end":"00:02:14","best":"00:02:03","relevance":0.3811851143836975},{"documentId":"sp=r&st=2024-02-09T12:33:24Z&se=2025-08-06T20:33:24Z&spr=https&sv=2022-11-02&sr=b&sig=V%2Fq56JjGcL60r0vt3oAPjzx%2FZMu5%2BJo%2BfjKkJF2ccgo%3D","documentKind":"VideoInterval","start":"00:00:42","end":"00:00:52","best":"00:00:42","relevance":0.3765566647052765},{"documentId":"sp=r&st=2024-02-09T12:33:24Z&se=2025-08-06T20:33:24Z&spr=https&sv=2022-11-02&sr=b&sig=V%2Fq56JjGcL60r0vt3oAPjzx%2FZMu5%2BJo%2BfjKkJF2ccgo%3D","documentKind":"VideoInterval","start":"00:00:26","end":"00:00:42","best":"00:00:28","relevance":0.3718773126602173},{"documentId":"sp=r&st=2024-02-09T12:33:24Z&se=2025-08-06T20:33:24Z&spr=https&sv=2022-11-02&sr=b&sig=V%2Fq56JjGcL60r0vt3oAPjzx%2FZMu5%2BJo%2BfjKkJF2ccgo%3D","documentKind":"VideoInterval","start":"00:01:08","end":"00:01:24","best":"00:01:10","relevance":0.3707084357738495},{"documentId":"sp=r&st=2024-02-09T12:33:24Z&se=2025-08-06T20:33:24Z&spr=https&sv=2022-11-02&sr=b&sig=V%2Fq56JjGcL60r0vt3oAPjzx%2FZMu5%2BJo%2BfjKkJF2ccgo%3D","documentKind":"VideoInterval","start":"00:01:37","end":"00:01:42","best":"00:01:38","relevance":0.36235538125038147},{"documentId":"sp=r&st=2024-02-09T12:33:24Z&se=2025-08-06T20:33:24Z&spr=https&sv=2022-11-02&sr=b&sig=V%2Fq56JjGcL60r0vt3oAPjzx%2FZMu5%2BJo%2BfjKkJF2ccgo%3D","documentKind":"VideoInterval","start":"00:01:29","end":"00:01:37","best":"00:01:33","relevance":0.3606133460998535},{"documentId":"sp=r&st=2024-02-09T12:33:24Z&se=2025-08-06T20:33:24Z&spr=https&sv=2022-11-02&sr=b&sig=V%2Fq56JjGcL60r0vt3oAPjzx%2FZMu5%2BJo%2BfjKkJF2ccgo%3D","documentKind":"VideoInterval","start":"00:01:03","end":"00:01:08","best":"00:01:04","relevance":0.3513660728931427},{"documentId":"sp=r&st=2024-02-09T12:33:24Z&se=2025-08-06T20:33:24Z&spr=https&sv=2022-11-02&sr=b&sig=V%2Fq56JjGcL60r0vt3oAPjzx%2FZMu5%2BJo%2BfjKkJF2ccgo%3D","documentKind":"VideoInterval","start":"00:00:00","end":"00:00:06","best":"00:00:05","relevance":0.3378048241138458}]}' # JSON response
|
| 134 |
+
# modifiedQueryResponse = load_json_output(output_query_response)
|
| 135 |
+
#
|
| 136 |
+
# # 3.2.2. get timestamps of haptics segments
|
| 137 |
+
# hapticSegments = get_explosion_segments(modifiedQueryResponse)
|
| 138 |
+
#
|
| 139 |
+
# # 3.2.3. create final audio
|
| 140 |
+
# finalAudio = create_final_audio(extractedAudioPath, hapticSegments)
|
| 141 |
+
# finalAudioPath = "audio/finalAudio.mp3"
|
| 142 |
+
# save_audio(finalAudio, finalAudioPath)
|
| 143 |
+
#
|
| 144 |
+
# # 3.3. Master final audio file
|
| 145 |
+
# #master = subprocess.run(["node", "masteringModule/main.js", "--input", finalAudioPath, "--output", finalAudioPath])
|
| 146 |
+
#
|
| 147 |
+
# # 3.4. Prepare video file
|
| 148 |
+
# #muteVideo = without_audio(input_video)
|
| 149 |
+
# # currentVideoPath = "video/currentVideo.mp4"
|
| 150 |
+
# # save_video(input_video, currentVideoPath)
|
| 151 |
+
# # muteVideo = VideoFileClip(currentVideoPath)
|
| 152 |
+
# # muteVideo = muteVideo.without_audio()
|
| 153 |
+
# # mutevideoPath = "video/muteVideo.mp4"
|
| 154 |
+
# # save_video(muteVideo, mutevideoPath)
|
| 155 |
+
#
|
| 156 |
+
# # 3.5. Combine audio with video
|
| 157 |
+
# inputVideoPath = input_video
|
| 158 |
+
# currentVideoPath = "video/currentVideo.mp4"
|
| 159 |
+
# currentVideo = VideoFileClip(currentVideoPath)
|
| 160 |
+
#
|
| 161 |
+
# finalVideo = combine_video_audio(currentVideo,finalAudio)
|
| 162 |
+
# finalVideoPath = "video/finalEnhancedVideo.mp4"
|
| 163 |
+
# save_video(finalVideo, finalVideoPath)
|
| 164 |
+
|
| 165 |
+
return [finalVideoPath, f"Video enhancement successful"]
|
| 166 |
|
| 167 |
# You can optionally add a progress bar or loading indicator here
|
| 168 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 169 |
|
| 170 |
css = """
|
| 171 |
#col-container {
|
|
|
|
| 216 |
outputs=[video_out, text_out],
|
| 217 |
#cache_examples=True # Cache examples for faster loading
|
| 218 |
)
|
| 219 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 220 |
btn_in.click(
|
| 221 |
fn=predict_video,
|
| 222 |
inputs=[video_in,audio_in,choice_in],
|