victor HF Staff commited on
Commit
73bb102
Β·
1 Parent(s): 68be92b

feat: Enhance get_completion and update functions with error handling and command display for FFMPEG execution

Browse files
Files changed (1) hide show
  1. app.py +93 -31
app.py CHANGED
@@ -96,7 +96,7 @@ def get_files_infos(files):
96
  return results
97
 
98
 
99
- def get_completion(prompt, files_info, top_p, temperature, model_choice):
100
  # Create table header
101
  files_info_string = "| Type | Name | Dimensions | Duration | Audio Channels |\n"
102
  files_info_string += "|------|------|------------|-----------|--------|\n"
@@ -115,6 +115,35 @@ def get_completion(prompt, files_info, top_p, temperature, model_choice):
115
 
116
  files_info_string += f"| {file_info['type']} | {file_info['name']} | {dimensions} | {duration} | {audio} |\n"
117
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  messages = [
119
  {
120
  "role": "system",
@@ -145,20 +174,7 @@ Remember: Simpler is better. Only use advanced ffmpeg features if absolutely nec
145
  },
146
  {
147
  "role": "user",
148
- "content": f"""Always output the media as video/mp4 and output file with "output.mp4".
149
- The current assets and objective follow.
150
-
151
- AVAILABLE ASSETS LIST:
152
-
153
- {files_info_string}
154
-
155
- OBJECTIVE: {prompt} and output at "output.mp4"
156
-
157
- First, think step-by-step about what I'm asking for and reformulate it into a clear technical specification.
158
- Then provide the FFMPEG command that will accomplish this task.
159
-
160
- YOUR RESPONSE:
161
- """,
162
  },
163
  ]
164
  try:
@@ -286,14 +302,18 @@ def update(
286
  raise gr.Error("Please make sure all files are less than 100MB in size.")
287
 
288
  attempts = 0
 
 
 
 
289
  while attempts < 2:
290
- print("ATTEMPT", attempts)
291
  try:
292
  command_string = get_completion(
293
- prompt, files_info, top_p, temperature, model_choice
294
  )
295
  print(
296
- f"""///PROMTP {prompt} \n\n/// START OF COMMAND ///:\n\n{command_string}\n\n/// END OF COMMAND ///\n\n"""
297
  )
298
 
299
  # split command string into list of arguments
@@ -308,35 +328,77 @@ def update(
308
  shutil.copy(file_path, Path(temp_dir) / sanitized_name)
309
 
310
  # test if ffmpeg command is valid dry run
311
- ffmpg_dry_run = subprocess.run(
312
  args + ["-f", "null", "-"],
313
  stderr=subprocess.PIPE,
314
  text=True,
315
  cwd=temp_dir,
316
  )
317
- if ffmpg_dry_run.returncode == 0:
 
 
 
 
318
  print("Command is valid.")
 
 
 
 
 
 
319
  else:
320
  print("Command is not valid. Error output:")
321
- print(ffmpg_dry_run.stderr)
322
- raise Exception(
323
- "FFMPEG generated command is not valid. Please try something else."
324
- )
 
 
 
 
 
 
 
 
 
 
 
325
 
326
  output_file_name = f"output_{uuid.uuid4()}.mp4"
327
  output_file_path = str((Path(temp_dir) / output_file_name).resolve())
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
337
  if attempts >= 2:
338
  print("FROM UPDATE", e)
339
- raise gr.Error(e)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
340
 
341
 
342
  # Create MCP-compatible interface
 
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"
 
115
 
116
  files_info_string += f"| {file_info['type']} | {file_info['name']} | {dimensions} | {duration} | {audio} |\n"
117
 
118
+ # Build the user message with optional error feedback
119
+ user_content = f"""Always output the media as video/mp4 and output file with "output.mp4".
120
+ The current assets and objective follow.
121
+
122
+ AVAILABLE ASSETS LIST:
123
+
124
+ {files_info_string}
125
+
126
+ OBJECTIVE: {prompt} and output at "output.mp4"
127
+
128
+ First, think step-by-step about what I'm asking for and reformulate it into a clear technical specification.
129
+ Then provide the FFMPEG command that will accomplish this task."""
130
+
131
+ # Add error feedback if this is a retry
132
+ if previous_error and previous_command:
133
+ user_content += f"""
134
+
135
+ IMPORTANT: This is a retry attempt. The previous command failed with the following error:
136
+
137
+ PREVIOUS COMMAND (FAILED):
138
+ {previous_command}
139
+
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
+
147
  messages = [
148
  {
149
  "role": "system",
 
174
  },
175
  {
176
  "role": "user",
177
+ "content": user_content,
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  },
179
  ]
180
  try:
 
302
  raise gr.Error("Please make sure all files are less than 100MB in size.")
303
 
304
  attempts = 0
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"""
317
  )
318
 
319
  # split command string into list of arguments
 
328
  shutil.copy(file_path, Path(temp_dir) / sanitized_name)
329
 
330
  # test if ffmpeg command is valid dry run
331
+ ffmpeg_dry_run = subprocess.run(
332
  args + ["-f", "null", "-"],
333
  stderr=subprocess.PIPE,
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
+
385
+ 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
 
404
  # Create MCP-compatible interface