victor HF Staff commited on
Commit
bbc25a7
·
1 Parent(s): 11a2434

feat: Enhance video composition functionality with detailed docstring and improved command handling

Browse files
Files changed (1) hide show
  1. app.py +85 -22
app.py CHANGED
@@ -190,19 +190,29 @@ YOUR RESPONSE:
190
  # Find content between ```sh or ```bash and the next ```
191
  import re
192
 
193
- command_match = re.search(r"```(?:sh|bash)?\n(.*?)\n```", content, re.DOTALL)
 
 
194
  if command_match:
195
  command = command_match.group(1).strip()
196
  else:
197
  # Try to find a line that starts with ffmpeg
198
- ffmpeg_lines = [line.strip() for line in content.split('\n') if line.strip().startswith('ffmpeg')]
 
 
 
 
199
  if ffmpeg_lines:
200
  command = ffmpeg_lines[0]
201
  else:
202
  command = content.replace("\n", "")
203
  else:
204
  # Try to find a line that starts with ffmpeg
205
- ffmpeg_lines = [line.strip() for line in content.split('\n') if line.strip().startswith('ffmpeg')]
 
 
 
 
206
  if ffmpeg_lines:
207
  command = ffmpeg_lines[0]
208
  else:
@@ -220,13 +230,40 @@ YOUR RESPONSE:
220
  def execute_ffmpeg_command(args, temp_dir, output_file_path):
221
  """Execute FFmpeg command with GPU acceleration"""
222
  final_command = args + ["-y", output_file_path]
223
- print(
224
- f"\n=== EXECUTING FFMPEG COMMAND ===\nffmpeg {' '.join(final_command[1:])}\n"
225
- )
226
  subprocess.run(final_command, cwd=temp_dir)
227
  return output_file_path
228
 
229
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
  def update(
231
  files,
232
  prompt,
@@ -291,7 +328,9 @@ def update(
291
  execute_ffmpeg_command(args, temp_dir, output_file_path)
292
  # Extract just the command for display
293
  command_for_display = f"ffmpeg {' '.join(args[1:])} -y output.mp4"
294
- generated_command = f"### Generated Command\n```bash\n{command_for_display}\n```"
 
 
295
  return output_file_path, gr.update(value=generated_command)
296
  except Exception as e:
297
  attempts += 1
@@ -300,6 +339,26 @@ def update(
300
  raise gr.Error(e)
301
 
302
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
303
  with gr.Blocks() as demo:
304
  gr.Markdown(
305
  """
@@ -358,13 +417,13 @@ with gr.Blocks() as demo:
358
  examples=[
359
  [
360
  ["./examples/ai_talk.wav", "./examples/bg-image.png"],
361
- "Use the image as the background with a waveform visualization for the audio positioned in center of the video.",
362
- 0.7,
363
- 0.1,
364
- list(MODELS.keys())[0],
365
- ],
366
- [
367
- ["./examples/ai_talk.wav", "./examples/bg-image.png"],
368
  "Use the image as the background with a waveform visualization for the audio positioned in center of the video. Make sure the waveform has a max height of 250 pixels.",
369
  0.7,
370
  0.1,
@@ -380,13 +439,13 @@ with gr.Blocks() as demo:
380
  "./examples/cat6.jpeg",
381
  "./examples/heat-wave.mp3",
382
  ],
383
- "Create a 3x2 grid of the cat images with the audio as background music. Make the video duration match the audio duration.",
384
- 0.7,
385
- 0.1,
386
- list(MODELS.keys())[0],
387
- ],
388
- ],
389
- inputs=[user_files, user_prompt, top_p, temperature, model_choice],
390
  outputs=[generated_video, generated_command],
391
  fn=update,
392
  run_on_click=True,
@@ -402,5 +461,9 @@ with gr.Blocks() as demo:
402
  """,
403
  )
404
 
 
 
 
 
405
  demo.queue(default_concurrency_limit=200)
406
- demo.launch(show_api=False, ssr_mode=False)
 
190
  # Find content between ```sh or ```bash and the next ```
191
  import re
192
 
193
+ command_match = re.search(
194
+ r"```(?:sh|bash)?\n(.*?)\n```", content, re.DOTALL
195
+ )
196
  if command_match:
197
  command = command_match.group(1).strip()
198
  else:
199
  # Try to find a line that starts with ffmpeg
200
+ ffmpeg_lines = [
201
+ line.strip()
202
+ for line in content.split("\n")
203
+ if line.strip().startswith("ffmpeg")
204
+ ]
205
  if ffmpeg_lines:
206
  command = ffmpeg_lines[0]
207
  else:
208
  command = content.replace("\n", "")
209
  else:
210
  # Try to find a line that starts with ffmpeg
211
+ ffmpeg_lines = [
212
+ line.strip()
213
+ for line in content.split("\n")
214
+ if line.strip().startswith("ffmpeg")
215
+ ]
216
  if ffmpeg_lines:
217
  command = ffmpeg_lines[0]
218
  else:
 
230
  def execute_ffmpeg_command(args, temp_dir, output_file_path):
231
  """Execute FFmpeg command with GPU acceleration"""
232
  final_command = args + ["-y", output_file_path]
233
+ print(f"\n=== EXECUTING FFMPEG COMMAND ===\nffmpeg {' '.join(final_command[1:])}\n")
 
 
234
  subprocess.run(final_command, cwd=temp_dir)
235
  return output_file_path
236
 
237
 
238
+ def compose_video(
239
+ prompt: str,
240
+ files: list = None,
241
+ top_p: float = 0.7,
242
+ temperature: float = 0.1,
243
+ model_choice: str = "deepseek-ai/DeepSeek-V3",
244
+ ) -> str:
245
+ """
246
+ Compose a video from media assets using natural language instructions.
247
+
248
+ This tool generates FFmpeg commands using AI and executes them to create videos
249
+ from uploaded images, videos, and audio files based on natural language descriptions.
250
+
251
+ Args:
252
+ prompt (str): Natural language instructions for video composition (e.g., "Create a slideshow with background music")
253
+ files (list, optional): List of media files (images, videos, audio) to use
254
+ top_p (float): Top-p sampling parameter for AI model (0.0-1.0, default: 0.7)
255
+ temperature (float): Temperature parameter for AI model creativity (0.0-5.0, default: 0.1)
256
+ model_choice (str): AI model to use for command generation (default: "deepseek-ai/DeepSeek-V3")
257
+
258
+ Returns:
259
+ str: Path to the generated video file
260
+
261
+ Example:
262
+ compose_video("Create a 10-second slideshow from the images with fade transitions", files=[img1, img2, img3])
263
+ """
264
+ return update(files or [], prompt, top_p, temperature, model_choice)
265
+
266
+
267
  def update(
268
  files,
269
  prompt,
 
328
  execute_ffmpeg_command(args, temp_dir, output_file_path)
329
  # Extract just the command for display
330
  command_for_display = f"ffmpeg {' '.join(args[1:])} -y output.mp4"
331
+ generated_command = (
332
+ f"### Generated Command\n```bash\n{command_for_display}\n```"
333
+ )
334
  return output_file_path, gr.update(value=generated_command)
335
  except Exception as e:
336
  attempts += 1
 
339
  raise gr.Error(e)
340
 
341
 
342
+ # Create MCP-compatible interface
343
+ mcp_interface = gr.Interface(
344
+ fn=compose_video,
345
+ inputs=[
346
+ gr.Textbox(
347
+ value="Create a slideshow with background music",
348
+ label="Video Composition Instructions",
349
+ ),
350
+ gr.File(file_count="multiple", label="Media Files", file_types=allowed_medias),
351
+ gr.Slider(0.0, 1.0, value=0.7, label="Top-p"),
352
+ gr.Slider(0.0, 5.0, value=0.1, label="Temperature"),
353
+ gr.Radio(
354
+ choices=list(MODELS.keys()), value=list(MODELS.keys())[0], label="Model"
355
+ ),
356
+ ],
357
+ outputs=gr.Video(label="Generated Video"),
358
+ title="AI Video Composer MCP Tool",
359
+ description="Compose videos from media assets using natural language",
360
+ )
361
+
362
  with gr.Blocks() as demo:
363
  gr.Markdown(
364
  """
 
417
  examples=[
418
  [
419
  ["./examples/ai_talk.wav", "./examples/bg-image.png"],
420
+ "Use the image as the background with a waveform visualization for the audio positioned in center of the video.",
421
+ 0.7,
422
+ 0.1,
423
+ list(MODELS.keys())[0],
424
+ ],
425
+ [
426
+ ["./examples/ai_talk.wav", "./examples/bg-image.png"],
427
  "Use the image as the background with a waveform visualization for the audio positioned in center of the video. Make sure the waveform has a max height of 250 pixels.",
428
  0.7,
429
  0.1,
 
439
  "./examples/cat6.jpeg",
440
  "./examples/heat-wave.mp3",
441
  ],
442
+ "Create a 3x2 grid of the cat images with the audio as background music. Make the video duration match the audio duration.",
443
+ 0.7,
444
+ 0.1,
445
+ list(MODELS.keys())[0],
446
+ ],
447
+ ],
448
+ inputs=[user_files, user_prompt, top_p, temperature, model_choice],
449
  outputs=[generated_video, generated_command],
450
  fn=update,
451
  run_on_click=True,
 
461
  """,
462
  )
463
 
464
+ # Launch MCP interface for tool access
465
+ mcp_interface.queue(default_concurrency_limit=200)
466
+
467
+ # Launch main demo
468
  demo.queue(default_concurrency_limit=200)
469
+ demo.launch(show_api=False, ssr_mode=False, mcp_server=True)