File size: 7,769 Bytes
564378d
 
 
 
 
6364f3e
 
 
564378d
6364f3e
 
564378d
 
 
 
 
 
 
 
 
6364f3e
564378d
6364f3e
 
564378d
 
 
 
31fe7cc
564378d
6364f3e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
564378d
 
6364f3e
 
 
 
 
 
564378d
6364f3e
 
564378d
6364f3e
 
31fe7cc
6364f3e
 
31fe7cc
6364f3e
 
31fe7cc
6364f3e
 
31fe7cc
 
 
 
 
 
 
 
 
 
 
6364f3e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31fe7cc
 
6364f3e
 
9bbea50
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
import gradio as gr
from PIL import Image
from PIL.ExifTags import TAGS
import numpy as np
import re
import json
import tempfile
import os

def get_image_metadata(img):
    """Extract metadata based on image format."""
    metadata = {}
    if img.format == 'PNG':
        metadata = img.info
    elif img.format in ['JPEG', 'TIFF']:
        exif_data = img._getexif()
        if exif_data:
            for tag, value in exif_data.items():
                tag_name = TAGS.get(tag, tag)
                metadata[tag_name] = value
    return metadata

def parse_parameters(parameters):
    """Parse the 'parameters' field to extract prompts and seed number."""
    prompt = 'N/A'
    negative_prompt = 'N/A'
    adetailer_prompt_1 = 'N/A'
    adetailer_prompt_2 = 'N/A'
    seed_number = -1

    # Extract the prompt
    prompt_match = re.search(r'(.*?)Negative prompt:', parameters, re.DOTALL | re.IGNORECASE)
    if prompt_match:
        prompt = prompt_match.group(1).strip()
    else:
        prompt_match = re.search(r'(.*?)(Steps:|$)', parameters, re.DOTALL | re.IGNORECASE)
        if prompt_match:
            prompt = prompt_match.group(1).strip()

    # Extract the negative prompt
    negative_prompt_match = re.search(r'Negative prompt:(.*?)(Steps:|$)', parameters, re.DOTALL | re.IGNORECASE)
    if negative_prompt_match:
        negative_prompt = negative_prompt_match.group(1).strip()

    # Extract ADetailer prompts
    adetailer_prompt_1_match = re.search(r'ADetailer prompt:\s*"(.*?)"', parameters, re.IGNORECASE)
    if adetailer_prompt_1_match:
        adetailer_prompt_1 = adetailer_prompt_1_match.group(1).strip()

    adetailer_prompt_2_match = re.search(r'ADetailer negative prompt 2nd:\s*"(.*?)"', parameters, re.IGNORECASE)
    if adetailer_prompt_2_match:
        adetailer_prompt_2 = adetailer_prompt_2_match.group(1).strip()

    # Extract Seed Number
    seed_match = re.search(r'Seed:\s*(\d+)', parameters, re.IGNORECASE)
    if seed_match:
        seed_number = seed_match.group(1).strip()

    return prompt, negative_prompt, adetailer_prompt_1, adetailer_prompt_2, seed_number

def extract_metadata(image_file):
    """Extract and parse metadata from the uploaded image."""
    try:
        img = Image.open(image_file)
    except Exception as e:
        # Return placeholders in case of error
        return (None, 'Error: Unable to open image.', *(['N/A'] * 7))

    metadata = get_image_metadata(img)
    img_display = np.array(img)

    # Convert metadata to string
    metadata_str = "\n".join([f"{key}: {value}" for key, value in metadata.items()])

    # Initialize default values
    prompt = negative_prompt = adetailer_prompt_1 = adetailer_prompt_2 = 'N/A'
    seed_number = -1
    comfy_prompt = comfy_workflow = 'N/A'

    # Parse parameters if available
    if 'parameters' in metadata:
        parsed = parse_parameters(metadata['parameters'])
        prompt, negative_prompt, adetailer_prompt_1, adetailer_prompt_2, seed_number = parsed

    # Direct extraction with validation for Comfy Prompt
    if 'prompt' in metadata and isinstance(metadata['prompt'], str):
        comfy_prompt = metadata['prompt'].strip()
    else:
        comfy_prompt = 'N/A'  # Fallback if prompt is missing or not a string

    # Direct extraction with validation for Comfy Workflow
    if 'workflow' in metadata and isinstance(metadata['workflow'], str):
        comfy_workflow = metadata['workflow'].strip()
    else:
        comfy_workflow = 'N/A'  # Fallback if workflow is missing or not a string

    return (
        img_display, 
        prompt, 
        negative_prompt, 
        seed_number, 
        adetailer_prompt_1, 
        adetailer_prompt_2, 
        metadata_str, 
        comfy_prompt, 
        comfy_workflow
    )

def export_workflow(workflow_text):
    """
    Converts the workflow text into JSON format and returns it as a downloadable file.
    """
    print("Export workflow function called.")
    if workflow_text == "N/A" or not workflow_text.strip():
        print("No workflow data to export.")
        return None, "No workflow data to export."

    # Structure the JSON data
    workflow_data = {
        "comfy_workflow": workflow_text
    }

    # Create a temporary JSON file
    try:
        with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.json') as tmp_file:
            json.dump(workflow_data, tmp_file, indent=4)
            tmp_file_path = tmp_file.name
        print(f"Temporary JSON file created at: {tmp_file_path}")
    except Exception as e:
        print(f"Error creating temporary file: {e}")
        return None, "Failed to create workflow JSON file."

    # Check if the file was created successfully
    if os.path.exists(tmp_file_path):
        message = "Workflow exported successfully."
        print(message)
        return tmp_file_path, message
    else:
        message = "Failed to export workflow."
        print(message)
        return None, message

def main():
    # Create Gradio User Interface
    with gr.Blocks() as iface:
        gr.Markdown("<h1>Automatic 1111/ Comfy Metadata Reader</h1>")
        gr.Markdown("<p>Upload an image (PNG, JPEG) to extract its metadata and parse it for prompts.</p>")
        with gr.Row():
            with gr.Column():  # First column for image upload and preview
                image_input = gr.File(label="Upload Image", type="filepath")
                image_output = gr.Image(label="Image Preview")
                original_metadata_output = gr.Textbox(label="Original Metadata", lines=20, interactive=False)

            with gr.Column():  # Second column for metadata outputs
                prompt_output = gr.Textbox(label="Prompt", lines=4, show_copy_button=True, interactive=False)
                negative_prompt_output = gr.Textbox(label="Negative Prompt", lines=4, show_copy_button=True, interactive=False)
                seed_output = gr.Textbox(label="Seed Number", lines=1, show_copy_button=True, interactive=False)
                adetailer_prompt_1_output = gr.Textbox(label="ADetailer Prompt 1", lines=3, show_copy_button=True, interactive=False)
                adetailer_prompt_2_output = gr.Textbox(label="ADetailer Prompt 2", lines=3, show_copy_button=True, interactive=False)

            with gr.Column():  # Third column for additional metadata outputs
                with gr.Row():
                    comfy_prompt_output = gr.Textbox(label="Comfy Prompt", lines=4, value="N/A", interactive=False)
                with gr.Row():
                    comfy_workflow_output = gr.Textbox(label="Comfy Workflow", lines=20, value="N/A", interactive=False)
                    export_button = gr.Button("Export Workflow as JSON")
                    workflow_file = gr.File(label="Download Workflow JSON", visible=False)
                with gr.Row():
                    export_message = gr.Textbox(label="Export Status", lines=1, interactive=False, visible=False)

        # Set up the input-output relationships
        image_input.change(
            fn=extract_metadata,
            inputs=image_input,
            outputs=[
                image_output,
                prompt_output,
                negative_prompt_output,
                seed_output,
                adetailer_prompt_1_output,
                adetailer_prompt_2_output,
                original_metadata_output,
                comfy_prompt_output, 
                comfy_workflow_output,
            ]
        )

        # Connect the export button to the export function
        export_button.click(
            fn=export_workflow,
            inputs=comfy_workflow_output,
            outputs=[workflow_file, export_message],
            queue=False
        )

    iface.launch()

if __name__ == "__main__":
    main()