victor HF Staff commited on
Commit
b68b18f
Β·
1 Parent(s): f5cf7aa

feat: Enhance slideshow error guidance and increase command attempts for multiple images

Browse files
Files changed (1) hide show
  1. app.py +90 -29
app.py CHANGED
@@ -96,7 +96,15 @@ def get_files_infos(files):
96
  return results
97
 
98
 
99
- def get_completion(prompt, files_info, top_p, temperature, model_choice, previous_error=None, previous_command=None):
 
 
 
 
 
 
 
 
100
  # Create table header
101
  files_info_string = "| Type | Name | Dimensions | Duration | Audio Channels |\n"
102
  files_info_string += "|------|------|------------|-----------|--------|\n"
@@ -140,7 +148,13 @@ PREVIOUS COMMAND (FAILED):
140
  ERROR MESSAGE:
141
  {previous_error}
142
 
143
- Please analyze the error and generate a corrected command that addresses the specific issue."""
 
 
 
 
 
 
144
 
145
  user_content += "\n\nYOUR RESPONSE:"
146
 
@@ -169,6 +183,39 @@ Key requirements:
169
  - For image sequences: Use -framerate and pattern matching (like 'img%d.jpg') when possible, falling back to individual image processing with -loop 1 and appropriate filters only when necessary.
170
  - When showing file operations or commands, always use explicit paths and filenames without wildcards - avoid using asterisk (*) or glob patterns. Instead, use specific numbered sequences (like %d), explicit file lists, or show the full filename.
171
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  Remember: Simpler is better. Only use advanced ffmpeg features if absolutely necessary for the requested output.
173
  """,
174
  },
@@ -305,12 +352,18 @@ def update(
305
  command_attempts = []
306
  previous_error = None
307
  previous_command = None
308
-
309
  while attempts < 2:
310
  print("ATTEMPT", attempts + 1)
311
  try:
312
  command_string = get_completion(
313
- prompt, files_info, top_p, temperature, model_choice, previous_error, previous_command
 
 
 
 
 
 
314
  )
315
  print(
316
  f"""///PROMPT {prompt} \n\n/// START OF COMMAND ///:\n\n{command_string}\n\n/// END OF COMMAND ///\n\n"""
@@ -334,51 +387,59 @@ def update(
334
  text=True,
335
  cwd=temp_dir,
336
  )
337
-
338
  # Extract command for display
339
  command_for_display = f"ffmpeg {' '.join(args[1:])} -y output.mp4"
340
-
341
  if ffmpeg_dry_run.returncode == 0:
342
  print("Command is valid.")
343
  # Add successful command to attempts
344
- command_attempts.append({
345
- "command": command_for_display,
346
- "status": "βœ… Valid",
347
- "attempt": attempts + 1
348
- })
 
 
349
  else:
350
  print("Command is not valid. Error output:")
351
  print(ffmpeg_dry_run.stderr)
352
-
353
  # Add failed command to attempts with error
354
- command_attempts.append({
355
- "command": command_for_display,
356
- "status": "❌ Invalid",
357
- "error": ffmpeg_dry_run.stderr,
358
- "attempt": attempts + 1
359
- })
360
-
 
 
361
  # Store error details for next retry
362
  previous_error = ffmpeg_dry_run.stderr
363
  previous_command = command_for_display
364
-
365
- raise Exception(f"FFMPEG command validation failed: {ffmpeg_dry_run.stderr}")
 
 
366
 
367
  output_file_name = f"output_{uuid.uuid4()}.mp4"
368
  output_file_path = str((Path(temp_dir) / output_file_name).resolve())
369
  execute_ffmpeg_command(args, temp_dir, output_file_path)
370
-
371
  # Generate command display with all attempts
372
  command_display = generate_command_display(command_attempts)
373
  return output_file_path, gr.update(value=command_display)
374
-
375
  except Exception as e:
376
  attempts += 1
377
  if attempts >= 2:
378
  print("FROM UPDATE", e)
379
  # Show all attempted commands even on final failure
380
  command_display = generate_command_display(command_attempts)
381
- command_display += f"\n\n### Final Error\n❌ All attempts failed. Last error: {str(e)}"
 
 
382
  return None, gr.update(value=command_display)
383
 
384
 
@@ -386,18 +447,18 @@ def generate_command_display(command_attempts):
386
  """Generate a markdown display of all command attempts"""
387
  if not command_attempts:
388
  return "### No commands generated"
389
-
390
  display = "### Generated Commands\n\n"
391
-
392
  for attempt in command_attempts:
393
  display += f"**Attempt {attempt['attempt']}** {attempt['status']}\n"
394
  display += f"```bash\n{attempt['command']}\n```\n"
395
-
396
- if attempt['status'] == "❌ Invalid" and 'error' in attempt:
397
  display += f"<details>\n<summary>πŸ” Error Details</summary>\n\n```\n{attempt['error']}\n```\n</details>\n\n"
398
  else:
399
  display += "\n"
400
-
401
  return display
402
 
403
 
 
96
  return results
97
 
98
 
99
+ def get_completion(
100
+ prompt,
101
+ files_info,
102
+ top_p,
103
+ temperature,
104
+ model_choice,
105
+ previous_error=None,
106
+ previous_command=None,
107
+ ):
108
  # Create table header
109
  files_info_string = "| Type | Name | Dimensions | Duration | Audio Channels |\n"
110
  files_info_string += "|------|------|------------|-----------|--------|\n"
 
148
  ERROR MESSAGE:
149
  {previous_error}
150
 
151
+ Please analyze the error and generate a corrected command that addresses the specific issue.
152
+
153
+ COMMON SLIDESHOW ERROR FIXES:
154
+ - If you see "do not match the corresponding output link" β†’ Images have different dimensions, use scale+pad approach
155
+ - If you see "Padded dimensions cannot be smaller than input dimensions" β†’ Fix pad calculation or use 1920x1080 standard
156
+ - If you see "Failed to configure input pad" β†’ Check scale and pad syntax, ensure proper filter chain
157
+ - If you see "Invalid argument" in filters β†’ Simplify filter_complex syntax and check parentheses"""
158
 
159
  user_content += "\n\nYOUR RESPONSE:"
160
 
 
183
  - For image sequences: Use -framerate and pattern matching (like 'img%d.jpg') when possible, falling back to individual image processing with -loop 1 and appropriate filters only when necessary.
184
  - When showing file operations or commands, always use explicit paths and filenames without wildcards - avoid using asterisk (*) or glob patterns. Instead, use specific numbered sequences (like %d), explicit file lists, or show the full filename.
185
 
186
+ CRITICAL SLIDESHOW GUIDANCE:
187
+ When creating slideshows from multiple images with different dimensions, ALWAYS follow this proven pattern:
188
+
189
+ 1. CHOOSE A STANDARD RESOLUTION: Pick 1920x1080 (1080p) as the target resolution for all slideshows
190
+ 2. USE SIMPLE SCALE+PAD APPROACH: For each image, scale to fit within 1920x1080 maintaining aspect ratio, then pad with black bars
191
+ 3. PROVEN SLIDESHOW PATTERN:
192
+ ```
193
+ ffmpeg -loop 1 -t 3 -i image1.jpg -loop 1 -t 3 -i image2.jpg -filter_complex "[0]scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2,setsar=1[v0];[1]scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2,setsar=1[v1];[v0][v1]concat=n=2:v=1:a=0" -c:v libx264 -pix_fmt yuv420p -movflags +faststart output.mp4
194
+ ```
195
+
196
+ 4. SLIDESHOW RULES:
197
+ - Always use 1920x1080 as target resolution for consistency
198
+ - Always use scale=1920:1080:force_original_aspect_ratio=decrease
199
+ - Always use pad=1920:1080:(ow-iw)/2:(oh-ih)/2 for centering
200
+ - Always add setsar=1 after padding to fix aspect ratio issues
201
+ - Use 3-second duration per image by default (-t 3)
202
+ - For 3+ images, extend the pattern: [v0][v1][v2]concat=n=3:v=1:a=0
203
+
204
+ 5. DIMENSION MISMATCH FIXES:
205
+ - Never try to concat images with different dimensions directly
206
+ - Always normalize dimensions first with scale+pad
207
+ - Black padding is preferable to stretching/distorting images
208
+
209
+ 6. SLIDESHOW TRANSITIONS:
210
+ - For fade transitions, add fade=t=in:st=0:d=0.5,fade=t=out:st=2.5:d=0.5 after setsar=1
211
+ - Keep transitions simple - complex transitions often fail
212
+ - Only add transitions if specifically requested
213
+
214
+ 7. SLIDESHOW TIMING:
215
+ - Default to 3 seconds per image
216
+ - Adjust timing based on user request (e.g., "5 seconds per image")
217
+ - Total duration = (number of images Γ— seconds per image)
218
+
219
  Remember: Simpler is better. Only use advanced ffmpeg features if absolutely necessary for the requested output.
220
  """,
221
  },
 
352
  command_attempts = []
353
  previous_error = None
354
  previous_command = None
355
+
356
  while attempts < 2:
357
  print("ATTEMPT", attempts + 1)
358
  try:
359
  command_string = get_completion(
360
+ prompt,
361
+ files_info,
362
+ top_p,
363
+ temperature,
364
+ model_choice,
365
+ previous_error,
366
+ previous_command,
367
  )
368
  print(
369
  f"""///PROMPT {prompt} \n\n/// START OF COMMAND ///:\n\n{command_string}\n\n/// END OF COMMAND ///\n\n"""
 
387
  text=True,
388
  cwd=temp_dir,
389
  )
390
+
391
  # Extract command for display
392
  command_for_display = f"ffmpeg {' '.join(args[1:])} -y output.mp4"
393
+
394
  if ffmpeg_dry_run.returncode == 0:
395
  print("Command is valid.")
396
  # Add successful command to attempts
397
+ command_attempts.append(
398
+ {
399
+ "command": command_for_display,
400
+ "status": "βœ… Valid",
401
+ "attempt": attempts + 1,
402
+ }
403
+ )
404
  else:
405
  print("Command is not valid. Error output:")
406
  print(ffmpeg_dry_run.stderr)
407
+
408
  # Add failed command to attempts with error
409
+ command_attempts.append(
410
+ {
411
+ "command": command_for_display,
412
+ "status": "❌ Invalid",
413
+ "error": ffmpeg_dry_run.stderr,
414
+ "attempt": attempts + 1,
415
+ }
416
+ )
417
+
418
  # Store error details for next retry
419
  previous_error = ffmpeg_dry_run.stderr
420
  previous_command = command_for_display
421
+
422
+ raise Exception(
423
+ f"FFMPEG command validation failed: {ffmpeg_dry_run.stderr}"
424
+ )
425
 
426
  output_file_name = f"output_{uuid.uuid4()}.mp4"
427
  output_file_path = str((Path(temp_dir) / output_file_name).resolve())
428
  execute_ffmpeg_command(args, temp_dir, output_file_path)
429
+
430
  # Generate command display with all attempts
431
  command_display = generate_command_display(command_attempts)
432
  return output_file_path, gr.update(value=command_display)
433
+
434
  except Exception as e:
435
  attempts += 1
436
  if attempts >= 2:
437
  print("FROM UPDATE", e)
438
  # Show all attempted commands even on final failure
439
  command_display = generate_command_display(command_attempts)
440
+ command_display += (
441
+ f"\n\n### Final Error\n❌ All attempts failed. Last error: {str(e)}"
442
+ )
443
  return None, gr.update(value=command_display)
444
 
445
 
 
447
  """Generate a markdown display of all command attempts"""
448
  if not command_attempts:
449
  return "### No commands generated"
450
+
451
  display = "### Generated Commands\n\n"
452
+
453
  for attempt in command_attempts:
454
  display += f"**Attempt {attempt['attempt']}** {attempt['status']}\n"
455
  display += f"```bash\n{attempt['command']}\n```\n"
456
+
457
+ if attempt["status"] == "❌ Invalid" and "error" in attempt:
458
  display += f"<details>\n<summary>πŸ” Error Details</summary>\n\n```\n{attempt['error']}\n```\n</details>\n\n"
459
  else:
460
  display += "\n"
461
+
462
  return display
463
 
464