skallewag commited on
Commit
ddecbbb
·
verified ·
1 Parent(s): 99f9460

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +51 -246
app.py CHANGED
@@ -5,7 +5,6 @@ import tempfile
5
  import logging
6
  import shutil
7
  import requests
8
- from huggingface_hub.utils import RepositoryNotFoundError
9
 
10
  # Configure logging
11
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
@@ -18,7 +17,7 @@ if not hf_token:
18
  logger.warning("Please set the HF_TOKEN environment variable with your Hugging Face token.")
19
 
20
  # Backend space name - update this to your private space
21
- BACKEND_SPACE = "skallewag/prepperoni-backend" # Using hyphen instead of underscore
22
 
23
  # Initialize client as None first
24
  client = None
@@ -38,7 +37,7 @@ except Exception as e:
38
  logger.error(f"Error connecting to backend space '{BACKEND_SPACE}': {str(e)}")
39
  logger.error("This might be due to a missing or invalid HF_TOKEN, or the backend space may be offline or private.")
40
 
41
- # Custom CSS for error box
42
  css = """
43
  .error-box {
44
  background-color: #ffebe9;
@@ -67,14 +66,11 @@ with gr.Blocks(title="Prepperoni - Premiere Pro to XML Converter", css=css) as a
67
  If you're the administrator, please make sure the HF_TOKEN environment variable is set correctly in Space settings.
68
  """, elem_classes=["error-box"])
69
 
70
- # State variables for sequence data
71
- sequence_list = gr.State([])
72
-
73
  with gr.Row():
74
  with gr.Column(scale=1):
75
  # Input components
76
  file_input = gr.File(label="Upload Premiere Pro Project File (.prproj)", file_types=[".prproj"])
77
- sequence_dropdown = gr.Dropdown(label="Select Sequence", choices=[], visible=False, interactive=True)
78
  convert_btn = gr.Button("Convert to XML", variant="primary")
79
  status = gr.Markdown("Upload a Premiere Pro project file to begin.")
80
 
@@ -94,7 +90,7 @@ with gr.Blocks(title="Prepperoni - Premiere Pro to XML Converter", css=css) as a
94
 
95
  ### How to use:
96
  1. Upload your Premiere Pro project file (.prproj)
97
- 2. Select a sequence from the dropdown
98
  3. Click "Convert to XML"
99
  4. Download the generated XML file
100
 
@@ -105,135 +101,6 @@ with gr.Blocks(title="Prepperoni - Premiere Pro to XML Converter", css=css) as a
105
  - Supports nested sequences
106
  """)
107
 
108
- # Function to update the sequence dropdown when a file is uploaded
109
- def update_sequence_dropdown(file):
110
- if not file:
111
- return gr.Dropdown(choices=[], value=None, visible=False), [], "Please upload a Premiere Pro project file to begin."
112
-
113
- if not client:
114
- return gr.Dropdown(choices=[], value=None, visible=False), [], "Error: Cannot connect to backend service."
115
-
116
- try:
117
- # Save the uploaded file to a temporary path
118
- temp_dir = tempfile.mkdtemp()
119
- temp_file_path = os.path.join(temp_dir, "project.prproj")
120
-
121
- # Copy the uploaded file to our temp location
122
- shutil.copy(file.name, temp_file_path)
123
-
124
- # Try to get sequences from the backend
125
- try:
126
- # Try with update_dropdown endpoint
127
- result = client.predict(
128
- handle_file(temp_file_path),
129
- api_name="/update_dropdown"
130
- )
131
- except Exception as e1:
132
- logger.warning(f"Failed with api_name='/update_dropdown': {str(e1)}")
133
- try:
134
- # Try with index 0
135
- result = client.predict(
136
- handle_file(temp_file_path),
137
- fn_index=0
138
- )
139
- except Exception as e2:
140
- logger.error(f"Error getting sequences: {str(e2)}")
141
- return gr.Dropdown(choices=[], value=None, visible=False), [], f"Error loading sequences: {str(e2)}"
142
-
143
- # Clean up
144
- shutil.rmtree(temp_dir, ignore_errors=True)
145
-
146
- # Process the result based on format
147
- sequences = []
148
- error_msg = ""
149
-
150
- # Log the raw result for debugging
151
- logger.info(f"Raw sequence result: {result}")
152
-
153
- try:
154
- # Special handling for Gradio component update objects
155
- if isinstance(result, dict) and '__type__' in result and result.get('__type__') == 'update':
156
- # Extract sequence choices from the Gradio update object
157
- if 'choices' in result:
158
- choices = result['choices']
159
-
160
- # Handle nested lists or different formats of choices
161
- if isinstance(choices, list) and len(choices) > 0:
162
- if isinstance(choices[0], list):
163
- # Format is likely [['name1', 'value1'], ['name2', 'value2']]
164
- # or [['name1', 'name1'], ['name2', 'name2']]
165
- sequences = [item[0] for item in choices] # Take the first item (name)
166
- else:
167
- # Format is likely ['name1', 'name2', 'name3']
168
- sequences = choices
169
- else:
170
- # Standard response handling for non-update objects
171
- if isinstance(result, (list, tuple)):
172
- if len(result) > 0:
173
- if isinstance(result[0], (list, tuple)):
174
- # It's a list of sequences
175
- sequences = result[0]
176
- else:
177
- # The result itself is the list of sequences
178
- sequences = result
179
-
180
- if len(result) >= 2 and isinstance(result[1], str):
181
- error_msg = result[1]
182
- elif isinstance(result, dict):
183
- if 'choices' in result:
184
- choices = result['choices']
185
- if isinstance(choices, list) and len(choices) > 0:
186
- if isinstance(choices[0], list):
187
- # Format is likely [['name1', 'value1'], ['name2', 'value2']]
188
- sequences = [item[0] for item in choices]
189
- else:
190
- sequences = choices
191
- elif 'data' in result:
192
- if isinstance(result['data'], (list, tuple)) and len(result['data']) >= 1:
193
- sequences = result['data'][0]
194
- else:
195
- sequences = result['data']
196
- elif 'sequences' in result:
197
- sequences = result['sequences']
198
-
199
- if 'error' in result:
200
- error_msg = result['error']
201
-
202
- # Ensure sequences is a list and contains only unique values
203
- if not isinstance(sequences, (list, tuple)):
204
- # Try to convert to a list if it's something else
205
- if hasattr(sequences, 'items'): # It's a dictionary-like object
206
- sequences = list(sequences.values())
207
- else:
208
- # Try to make it a list with a single item
209
- sequences = [sequences]
210
-
211
- # Remove duplicates while preserving order
212
- unique_sequences = []
213
- for seq in sequences:
214
- if seq not in unique_sequences:
215
- unique_sequences.append(seq)
216
- sequences = unique_sequences
217
-
218
- # Convert any non-string items to strings
219
- sequences = [str(seq) for seq in sequences]
220
-
221
- logger.info(f"Processed sequences: {sequences}")
222
- except Exception as e:
223
- logger.exception(f"Error processing sequences result: {e}")
224
- return gr.Dropdown(choices=[], value=None, visible=False), [], f"Error processing sequences: {str(e)}"
225
-
226
- if not sequences:
227
- return gr.Dropdown(choices=[], value=None, visible=False), [], "No sequences found in the project."
228
-
229
- # Update the dropdown with sequence names
230
- first_value = sequences[0] if sequences and len(sequences) > 0 else None
231
- return gr.Dropdown(choices=sequences, value=first_value, visible=True), sequences, f"Found {len(sequences)} sequences. Select one to convert."
232
-
233
- except Exception as e:
234
- logger.exception("Error in update_sequence_dropdown")
235
- return gr.Dropdown(choices=[], value=None, visible=False), [], f"Error: {str(e)}"
236
-
237
  # Function to set the initial processing status
238
  def set_processing_status():
239
  return None, "Processing... This may take a minute. Please wait.", "Processing..."
@@ -258,44 +125,17 @@ with gr.Blocks(title="Prepperoni - Premiere Pro to XML Converter", css=css) as a
258
  shutil.copy(file.name, temp_file_path)
259
 
260
  # Prepare sequence name (None if empty)
261
- seq_name = sequence_name if sequence_name else None
262
 
263
  # Try predicting with the backend
264
  try:
265
- logger.info("Sending file to backend for processing...")
266
- # Check if client has multiple endpoints and handle appropriately
267
- if client.endpoints and len(client.endpoints) > 0:
268
- # First try with /process_file endpoint (with leading slash)
269
- try:
270
- result = client.predict(
271
- handle_file(temp_file_path),
272
- seq_name,
273
- api_name="/process_file"
274
- )
275
- except Exception as e1:
276
- logger.warning(f"Failed with api_name='/process_file': {str(e1)}")
277
- # Try with index 1 which appears to be the process_file endpoint
278
- try:
279
- result = client.predict(
280
- handle_file(temp_file_path),
281
- seq_name,
282
- fn_index=1
283
- )
284
- except Exception as e2:
285
- logger.warning(f"Failed with fn_index=1: {str(e2)}")
286
- # Try with index 0 as fallback
287
- result = client.predict(
288
- handle_file(temp_file_path),
289
- seq_name,
290
- fn_index=0
291
- )
292
- else:
293
- # Just try without specifying endpoint
294
- result = client.predict(
295
- handle_file(temp_file_path),
296
- seq_name
297
- )
298
-
299
  logger.info(f"Got result from backend: {result}")
300
  except Exception as e:
301
  logger.error(f"Error connecting to backend: {str(e)}")
@@ -305,97 +145,62 @@ with gr.Blocks(title="Prepperoni - Premiere Pro to XML Converter", css=css) as a
305
  shutil.rmtree(temp_dir, ignore_errors=True)
306
 
307
  # Handle the result
308
- # Check the format of the result and extract file path and message
309
- xml_path = None
310
- message = "Unknown response format"
311
-
312
  try:
313
- if isinstance(result, (list, tuple)) and len(result) >= 2:
314
- # Format: [file_path, message]
315
  xml_path = result[0]
316
- message = result[1]
317
- elif isinstance(result, dict):
318
- # Try to extract data from dictionary format
319
- if 'file' in result:
320
- xml_path = result['file']
321
- elif 'data' in result and isinstance(result['data'], (list, tuple)) and len(result['data']) >= 1:
322
- xml_path = result['data'][0]
323
-
324
- if 'message' in result:
325
- message = result['message']
326
- elif 'data' in result and isinstance(result['data'], (list, tuple)) and len(result['data']) >= 2:
327
- message = result['data'][1]
328
-
329
- # Log the extracted values
330
- logger.info(f"Extracted from result - xml_path: {xml_path}, message: {message}")
331
- except Exception as e:
332
- logger.exception(f"Error processing result: {e}")
333
- return None, f"Error processing result from backend: {str(e)}", "Error"
334
-
335
- if xml_path:
336
- # Check if xml_path is a string
337
- if not isinstance(xml_path, str):
338
- logger.warning(f"XML path is not a string: {type(xml_path)}")
339
- # If it's a dict or complex object, it's likely not a valid path
340
- if isinstance(xml_path, (dict, list, tuple)):
341
- logger.error(f"Invalid XML path, not a string: {xml_path}")
342
- return None, "Error: Invalid response format from backend server", "Error"
343
- # Try to convert to string if it's another type
344
- xml_path = str(xml_path)
345
 
346
- # Check if the path is actually a valid file path
347
- if xml_path.startswith("{") or xml_path.startswith("["):
348
- logger.error(f"XML path appears to be JSON or a data structure, not a path: {xml_path}")
349
- return None, "Error: Invalid response format from backend server", "Error"
350
 
351
- # Download the XML file if it's a URL
352
- if xml_path.startswith("http"):
353
- logger.info(f"Downloading XML file from {xml_path}")
354
- headers = {"Authorization": f"Bearer {hf_token}"} if hf_token else {}
355
- response = requests.get(xml_path, headers=headers)
356
-
357
- if response.status_code == 200:
358
- # Save to a temporary file
359
- temp_dir = tempfile.mkdtemp()
360
- xml_local_path = os.path.join(temp_dir, "sequence.xml")
361
- with open(xml_local_path, "wb") as f:
362
- f.write(response.content)
363
- logger.info(f"XML file saved to {xml_local_path}")
364
- return xml_local_path, message, "Success!"
 
 
 
 
 
 
 
 
 
365
  else:
366
- logger.error(f"Failed to download XML: {response.status_code}")
367
- return None, f"Error downloading XML: {response.status_code}", "Error"
368
  else:
369
- # Check if it's a local path that actually exists
370
- if not os.path.exists(xml_path):
371
- logger.error(f"XML path does not exist: {xml_path}")
372
- return None, f"Error: XML file not found at path {xml_path}", "Error"
373
-
374
- # It's a valid local path
375
- logger.info(f"XML file is at local path: {xml_path}")
376
- return xml_path, message, "Success!"
377
- else:
378
- logger.warning(f"No XML file generated. Response: {result}")
379
- return None, message or "Failed to generate XML", "Error"
380
 
381
  except Exception as e:
382
  logger.exception("Error in process_file")
383
  return None, f"Error occurred: {str(e)}", "Error"
384
 
385
- # Connect file upload to sequence dropdown update
386
- file_input.change(
387
- fn=update_sequence_dropdown,
388
- inputs=[file_input],
389
- outputs=[sequence_dropdown, sequence_list, status]
390
- )
391
-
392
  # Connect the button to first set status, then process
393
  convert_btn.click(
394
  fn=set_processing_status,
395
  outputs=[output_file, output_message, status]
396
  ).then(
397
  fn=process_file,
398
- inputs=[file_input, sequence_dropdown],
399
  outputs=[output_file, output_message, status]
400
  )
401
 
 
5
  import logging
6
  import shutil
7
  import requests
 
8
 
9
  # Configure logging
10
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
 
17
  logger.warning("Please set the HF_TOKEN environment variable with your Hugging Face token.")
18
 
19
  # Backend space name - update this to your private space
20
+ BACKEND_SPACE = "skallewag/prepperoni-backend"
21
 
22
  # Initialize client as None first
23
  client = None
 
37
  logger.error(f"Error connecting to backend space '{BACKEND_SPACE}': {str(e)}")
38
  logger.error("This might be due to a missing or invalid HF_TOKEN, or the backend space may be offline or private.")
39
 
40
+ # Custom CSS
41
  css = """
42
  .error-box {
43
  background-color: #ffebe9;
 
66
  If you're the administrator, please make sure the HF_TOKEN environment variable is set correctly in Space settings.
67
  """, elem_classes=["error-box"])
68
 
 
 
 
69
  with gr.Row():
70
  with gr.Column(scale=1):
71
  # Input components
72
  file_input = gr.File(label="Upload Premiere Pro Project File (.prproj)", file_types=[".prproj"])
73
+ sequence_input = gr.Textbox(label="Sequence Name (optional)", placeholder="Leave blank to use first sequence")
74
  convert_btn = gr.Button("Convert to XML", variant="primary")
75
  status = gr.Markdown("Upload a Premiere Pro project file to begin.")
76
 
 
90
 
91
  ### How to use:
92
  1. Upload your Premiere Pro project file (.prproj)
93
+ 2. Optionally enter a sequence name (leave blank to use the first sequence)
94
  3. Click "Convert to XML"
95
  4. Download the generated XML file
96
 
 
101
  - Supports nested sequences
102
  """)
103
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  # Function to set the initial processing status
105
  def set_processing_status():
106
  return None, "Processing... This may take a minute. Please wait.", "Processing..."
 
125
  shutil.copy(file.name, temp_file_path)
126
 
127
  # Prepare sequence name (None if empty)
128
+ seq_name = sequence_name.strip() if sequence_name and sequence_name.strip() else None
129
 
130
  # Try predicting with the backend
131
  try:
132
+ logger.info(f"Sending file to backend for processing with sequence name: {seq_name}")
133
+ # Use the /process_file endpoint with index 1
134
+ result = client.predict(
135
+ handle_file(temp_file_path),
136
+ seq_name,
137
+ fn_index=1 # Use fn_index instead of api_name
138
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  logger.info(f"Got result from backend: {result}")
140
  except Exception as e:
141
  logger.error(f"Error connecting to backend: {str(e)}")
 
145
  shutil.rmtree(temp_dir, ignore_errors=True)
146
 
147
  # Handle the result
148
+ # The backend returns [file_path, message]
 
 
 
149
  try:
150
+ # Extract file path and message from the result
151
+ if isinstance(result, (list, tuple)) and len(result) >= 1:
152
  xml_path = result[0]
153
+ message = result[1] if len(result) >= 2 else "Conversion successful"
154
+ else:
155
+ logger.error(f"Unexpected result format: {result}")
156
+ return None, "Error: Unexpected response format from backend", "Error"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
 
158
+ logger.info(f"Extracted XML path: {xml_path}, Message: {message}")
 
 
 
159
 
160
+ # Handle the XML file
161
+ if xml_path:
162
+ # Download the XML file if it's a URL
163
+ if isinstance(xml_path, str) and xml_path.startswith("http"):
164
+ logger.info(f"Downloading XML file from {xml_path}")
165
+ headers = {"Authorization": f"Bearer {hf_token}"} if hf_token else {}
166
+ response = requests.get(xml_path, headers=headers)
167
+
168
+ if response.status_code == 200:
169
+ # Save to a temporary file
170
+ temp_dir = tempfile.mkdtemp()
171
+ xml_local_path = os.path.join(temp_dir, "sequence.xml")
172
+ with open(xml_local_path, "wb") as f:
173
+ f.write(response.content)
174
+ logger.info(f"XML file saved to {xml_local_path}")
175
+ return xml_local_path, message, "Success!"
176
+ else:
177
+ logger.error(f"Failed to download XML: {response.status_code}")
178
+ return None, f"Error downloading XML: {response.status_code}", "Error"
179
+ elif isinstance(xml_path, str) and os.path.exists(xml_path):
180
+ # It's a local file path that exists
181
+ logger.info(f"XML file is at local path: {xml_path}")
182
+ return xml_path, message, "Success!"
183
  else:
184
+ logger.error(f"Invalid XML path: {xml_path}")
185
+ return None, "Error: Invalid XML file path returned from backend", "Error"
186
  else:
187
+ logger.warning("No XML file generated")
188
+ return None, "No XML file was generated", "Error"
189
+ except Exception as e:
190
+ logger.exception(f"Error processing result: {e}")
191
+ return None, f"Error processing backend response: {str(e)}", "Error"
 
 
 
 
 
 
192
 
193
  except Exception as e:
194
  logger.exception("Error in process_file")
195
  return None, f"Error occurred: {str(e)}", "Error"
196
 
 
 
 
 
 
 
 
197
  # Connect the button to first set status, then process
198
  convert_btn.click(
199
  fn=set_processing_status,
200
  outputs=[output_file, output_message, status]
201
  ).then(
202
  fn=process_file,
203
+ inputs=[file_input, sequence_input],
204
  outputs=[output_file, output_message, status]
205
  )
206