tlam commited on
Commit
6364f3e
·
verified ·
1 Parent(s): 9bbea50

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +155 -90
app.py CHANGED
@@ -3,53 +3,13 @@ from PIL import Image
3
  from PIL.ExifTags import TAGS
4
  import numpy as np
5
  import re
 
 
 
6
 
7
- def main():
8
- # Create Gradio User Interface
9
- with gr.Blocks() as iface:
10
- gr.Markdown("# Image Metadata Extractor")
11
- gr.Markdown("Upload an image (PNG, JPEG, TIFF) to extract its metadata and parse it for prompts.")
12
- with gr.Row():
13
- with gr.Column(): # First column for image upload and preview
14
- image_input = gr.File(label="Upload Image", type="filepath")
15
- image_output = gr.Image(label="Image Preview")
16
- original_metadata_output = gr.Textbox(label="Original Metadata", lines=20)
17
-
18
- with gr.Column(): # Second column for metadata outputs
19
- prompt_output = gr.Textbox(label="Prompt", lines=4, show_copy_button=True)
20
- negative_prompt_output = gr.Textbox(label="Negative Prompt", lines=4, show_copy_button=True)
21
- seed_output = gr.Textbox(label="Seed Number", lines=1, show_copy_button=True)
22
- adetailer_prompt_1_output = gr.Textbox(label="ADetailer Prompt 1", lines=3, show_copy_button=True)
23
- adetailer_prompt_2_output = gr.Textbox(label="ADetailer Prompt 2", lines=3, show_copy_button=True)
24
- with gr.Column(): # Second column for metadata outputs
25
- with gr.Row():
26
- comfy_prompt_output = gr.Textbox(label="Comfy Prompt", lines=20)
27
- with gr.Row():
28
- comfy_workflow_output = gr.Textbox(label="Comfy Workflow", lines=20)
29
-
30
- # Set up the input-output relationships
31
- image_input.change(
32
- fn=extract_metadata,
33
- inputs=image_input,
34
- outputs=[
35
- image_output,
36
- prompt_output,
37
- negative_prompt_output,
38
- seed_output,
39
- adetailer_prompt_1_output,
40
- adetailer_prompt_2_output,
41
- original_metadata_output,
42
- comfy_prompt_output,
43
- comfy_workflow_output,
44
- ]
45
- )
46
- iface.launch()
47
-
48
- def extract_metadata(image_file):
49
- img = Image.open(image_file)
50
  metadata = {}
51
-
52
- # Extract metadata
53
  if img.format == 'PNG':
54
  metadata = img.info
55
  elif img.format in ['JPEG', 'TIFF']:
@@ -58,66 +18,82 @@ def extract_metadata(image_file):
58
  for tag, value in exif_data.items():
59
  tag_name = TAGS.get(tag, tag)
60
  metadata[tag_name] = value
 
61
 
62
- # Convert image to NumPy array for display
63
- img_display = np.array(img)
64
-
65
- # Initialize outputs
66
  prompt = 'N/A'
67
  negative_prompt = 'N/A'
68
  adetailer_prompt_1 = 'N/A'
69
  adetailer_prompt_2 = 'N/A'
70
  seed_number = -1
71
- comfy_prompt = 'N/A'
72
- comfy_workflow = 'N/A'
73
 
74
- # Convert the entire metadata dictionary to a readable string
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  metadata_str = "\n".join([f"{key}: {value}" for key, value in metadata.items()])
76
 
77
- # Parse metadata to extract prompts
 
 
 
 
 
78
  if 'parameters' in metadata:
79
- parameters = metadata['parameters']
 
80
 
81
- # Use regular expressions to extract prompts
82
- # Extract the prompt (before 'Negative prompt:')
83
- prompt_match = re.search(r'(.*?)Negative prompt:', parameters, re.DOTALL)
84
- if prompt_match:
85
- prompt = prompt_match.group(1).strip()
86
- else:
87
- # If 'Negative prompt:' not found, try to extract prompt up to 'Steps:' or end of string
88
- prompt_match = re.search(r'(.*?)(Steps:|$)', parameters, re.DOTALL)
89
- if prompt_match:
90
- prompt = prompt_match.group(1).strip()
91
-
92
- # Extract the negative prompt
93
- negative_prompt_match = re.search(r'Negative prompt:(.*?)(Steps:|$)', parameters, re.DOTALL)
94
- if negative_prompt_match:
95
- negative_prompt = negative_prompt_match.group(1).strip()
96
-
97
- # Extract ADetailer prompt 1
98
- adetailer_prompt_1_match = re.search(r'ADetailer prompt:\s*"(.*?)"', parameters)
99
- if adetailer_prompt_1_match:
100
- adetailer_prompt_1 = adetailer_prompt_1_match.group(1).strip()
101
-
102
- # Extract ADetailer prompt 2
103
- adetailer_prompt_2_match = re.search(r'ADetailer negative prompt 2nd:\s*"(.*?)"', parameters)
104
- if adetailer_prompt_2_match:
105
- adetailer_prompt_2 = adetailer_prompt_2_match.group(1).strip()
106
-
107
- seed_match = re.search(r'Seed:\s*(\d+)', parameters)
108
- if seed_match:
109
- seed_number = seed_match.group(1).strip()
110
-
111
- # Extract additional metadata fields directly if they exist
112
- if 'prompt' in metadata:
113
  comfy_prompt = metadata['prompt'].strip()
 
 
114
 
115
-
116
- if 'workflow' in metadata:
117
  comfy_workflow = metadata['workflow'].strip()
 
 
118
 
119
-
120
- # Return the outputs, replacing 'original_metadata_output' with 'metadata_str'
121
  return (
122
  img_display,
123
  prompt,
@@ -128,7 +104,96 @@ def extract_metadata(image_file):
128
  metadata_str,
129
  comfy_prompt,
130
  comfy_workflow
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  )
132
 
 
 
133
  if __name__ == "__main__":
134
  main()
 
3
  from PIL.ExifTags import TAGS
4
  import numpy as np
5
  import re
6
+ import json
7
+ import tempfile
8
+ import os
9
 
10
+ def get_image_metadata(img):
11
+ """Extract metadata based on image format."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  metadata = {}
 
 
13
  if img.format == 'PNG':
14
  metadata = img.info
15
  elif img.format in ['JPEG', 'TIFF']:
 
18
  for tag, value in exif_data.items():
19
  tag_name = TAGS.get(tag, tag)
20
  metadata[tag_name] = value
21
+ return metadata
22
 
23
+ def parse_parameters(parameters):
24
+ """Parse the 'parameters' field to extract prompts and seed number."""
 
 
25
  prompt = 'N/A'
26
  negative_prompt = 'N/A'
27
  adetailer_prompt_1 = 'N/A'
28
  adetailer_prompt_2 = 'N/A'
29
  seed_number = -1
 
 
30
 
31
+ # Extract the prompt
32
+ prompt_match = re.search(r'(.*?)Negative prompt:', parameters, re.DOTALL | re.IGNORECASE)
33
+ if prompt_match:
34
+ prompt = prompt_match.group(1).strip()
35
+ else:
36
+ prompt_match = re.search(r'(.*?)(Steps:|$)', parameters, re.DOTALL | re.IGNORECASE)
37
+ if prompt_match:
38
+ prompt = prompt_match.group(1).strip()
39
+
40
+ # Extract the negative prompt
41
+ negative_prompt_match = re.search(r'Negative prompt:(.*?)(Steps:|$)', parameters, re.DOTALL | re.IGNORECASE)
42
+ if negative_prompt_match:
43
+ negative_prompt = negative_prompt_match.group(1).strip()
44
+
45
+ # Extract ADetailer prompts
46
+ adetailer_prompt_1_match = re.search(r'ADetailer prompt:\s*"(.*?)"', parameters, re.IGNORECASE)
47
+ if adetailer_prompt_1_match:
48
+ adetailer_prompt_1 = adetailer_prompt_1_match.group(1).strip()
49
+
50
+ adetailer_prompt_2_match = re.search(r'ADetailer negative prompt 2nd:\s*"(.*?)"', parameters, re.IGNORECASE)
51
+ if adetailer_prompt_2_match:
52
+ adetailer_prompt_2 = adetailer_prompt_2_match.group(1).strip()
53
+
54
+ # Extract Seed Number
55
+ seed_match = re.search(r'Seed:\s*(\d+)', parameters, re.IGNORECASE)
56
+ if seed_match:
57
+ seed_number = seed_match.group(1).strip()
58
+
59
+ return prompt, negative_prompt, adetailer_prompt_1, adetailer_prompt_2, seed_number
60
+
61
+ def extract_metadata(image_file):
62
+ """Extract and parse metadata from the uploaded image."""
63
+ try:
64
+ img = Image.open(image_file)
65
+ except Exception as e:
66
+ # Return placeholders in case of error
67
+ return (None, 'Error: Unable to open image.', *(['N/A'] * 7))
68
+
69
+ metadata = get_image_metadata(img)
70
+ img_display = np.array(img)
71
+
72
+ # Convert metadata to string
73
  metadata_str = "\n".join([f"{key}: {value}" for key, value in metadata.items()])
74
 
75
+ # Initialize default values
76
+ prompt = negative_prompt = adetailer_prompt_1 = adetailer_prompt_2 = 'N/A'
77
+ seed_number = -1
78
+ comfy_prompt = comfy_workflow = 'N/A'
79
+
80
+ # Parse parameters if available
81
  if 'parameters' in metadata:
82
+ parsed = parse_parameters(metadata['parameters'])
83
+ prompt, negative_prompt, adetailer_prompt_1, adetailer_prompt_2, seed_number = parsed
84
 
85
+ # Direct extraction with validation for Comfy Prompt
86
+ if 'prompt' in metadata and isinstance(metadata['prompt'], str):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  comfy_prompt = metadata['prompt'].strip()
88
+ else:
89
+ comfy_prompt = 'N/A' # Fallback if prompt is missing or not a string
90
 
91
+ # Direct extraction with validation for Comfy Workflow
92
+ if 'workflow' in metadata and isinstance(metadata['workflow'], str):
93
  comfy_workflow = metadata['workflow'].strip()
94
+ else:
95
+ comfy_workflow = 'N/A' # Fallback if workflow is missing or not a string
96
 
 
 
97
  return (
98
  img_display,
99
  prompt,
 
104
  metadata_str,
105
  comfy_prompt,
106
  comfy_workflow
107
+ )
108
+
109
+ def export_workflow(workflow_text):
110
+ """
111
+ Converts the workflow text into JSON format and returns it as a downloadable file.
112
+ """
113
+ print("Export workflow function called.")
114
+ if workflow_text == "N/A" or not workflow_text.strip():
115
+ print("No workflow data to export.")
116
+ return None, "No workflow data to export."
117
+
118
+ # Structure the JSON data
119
+ workflow_data = {
120
+ "comfy_workflow": workflow_text
121
+ }
122
+
123
+ # Create a temporary JSON file
124
+ try:
125
+ with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.json') as tmp_file:
126
+ json.dump(workflow_data, tmp_file, indent=4)
127
+ tmp_file_path = tmp_file.name
128
+ print(f"Temporary JSON file created at: {tmp_file_path}")
129
+ except Exception as e:
130
+ print(f"Error creating temporary file: {e}")
131
+ return None, "Failed to create workflow JSON file."
132
+
133
+ # Check if the file was created successfully
134
+ if os.path.exists(tmp_file_path):
135
+ message = "Workflow exported successfully."
136
+ print(message)
137
+ return tmp_file_path, message
138
+ else:
139
+ message = "Failed to export workflow."
140
+ print(message)
141
+ return None, message
142
+
143
+ def main():
144
+ # Create Gradio User Interface
145
+ with gr.Blocks() as iface:
146
+ gr.Markdown("<h1>Automatic 1111/ Comfy Metadata Reader</h1>")
147
+ gr.Markdown("<p>Upload an image (PNG, JPEG) to extract its metadata and parse it for prompts.</p>")
148
+ with gr.Row():
149
+ with gr.Column(): # First column for image upload and preview
150
+ image_input = gr.File(label="Upload Image", type="filepath")
151
+ image_output = gr.Image(label="Image Preview")
152
+ original_metadata_output = gr.Textbox(label="Original Metadata", lines=20, interactive=False)
153
+
154
+ with gr.Column(): # Second column for metadata outputs
155
+ prompt_output = gr.Textbox(label="Prompt", lines=4, show_copy_button=True, interactive=False)
156
+ negative_prompt_output = gr.Textbox(label="Negative Prompt", lines=4, show_copy_button=True, interactive=False)
157
+ seed_output = gr.Textbox(label="Seed Number", lines=1, show_copy_button=True, interactive=False)
158
+ adetailer_prompt_1_output = gr.Textbox(label="ADetailer Prompt 1", lines=3, show_copy_button=True, interactive=False)
159
+ adetailer_prompt_2_output = gr.Textbox(label="ADetailer Prompt 2", lines=3, show_copy_button=True, interactive=False)
160
+
161
+ with gr.Column(): # Third column for additional metadata outputs
162
+ with gr.Row():
163
+ comfy_prompt_output = gr.Textbox(label="Comfy Prompt", lines=4, value="N/A", interactive=False)
164
+ with gr.Row():
165
+ comfy_workflow_output = gr.Textbox(label="Comfy Workflow", lines=20, value="N/A", interactive=False)
166
+ export_button = gr.Button("Export Workflow as JSON")
167
+ workflow_file = gr.File(label="Download Workflow JSON", visible=False)
168
+ with gr.Row():
169
+ export_message = gr.Textbox(label="Export Status", lines=1, interactive=False, visible=False)
170
+
171
+ # Set up the input-output relationships
172
+ image_input.change(
173
+ fn=extract_metadata,
174
+ inputs=image_input,
175
+ outputs=[
176
+ image_output,
177
+ prompt_output,
178
+ negative_prompt_output,
179
+ seed_output,
180
+ adetailer_prompt_1_output,
181
+ adetailer_prompt_2_output,
182
+ original_metadata_output,
183
+ comfy_prompt_output,
184
+ comfy_workflow_output,
185
+ ]
186
+ )
187
+
188
+ # Connect the export button to the export function
189
+ export_button.click(
190
+ fn=export_workflow,
191
+ inputs=comfy_workflow_output,
192
+ outputs=[workflow_file, export_message],
193
+ queue=False
194
  )
195
 
196
+ iface.launch()
197
+
198
  if __name__ == "__main__":
199
  main()