import gradio as gr from PIL import Image import requests from io import BytesIO import json import html css = """ .html-container span { color: var(--color-accent); } .json-node { --string-color: #b5bd68; --separator-color: var(--block-border-color); } .json-node .null { color: var(--body-text-color-subdued); } .json-node .bool { color: #cc99cc; } """ NL = "\n" def parse_key_value_pairs(input_string): pairs = [] key = None value = "" brace_count = 0 in_string = False escaping = False for i, char in enumerate(input_string): if char == '"' and not escaping: in_string = not in_string elif char == "\\" and not escaping: escaping = True else: escaping = False if char == "{" and not in_string: brace_count += 1 elif char == "}" and not in_string: brace_count -= 1 if (char == "," and brace_count == 0 and not in_string) or i == len(input_string) - 1: if i == len(input_string) - 1: value += char if key is not None and value: pairs.append((key, value)) elif key is None and value and pairs: prev_key, prev_value = pairs.pop() pairs.append((prev_key, f"{prev_value},{value}")) key, value = None, "" elif char == ":" and brace_count == 0 and not in_string: key, value = value, "" else: value += char return [(k.strip(), v.strip()) for k, v in pairs] def process_webui(info_data): lines = info_data.split("\n") positive_prompt = [] negative_prompt = [] settings_params = [] current_section = "positive" for line in lines: if current_section == "positive" and line.startswith("Negative prompt: "): current_section = "negative" line = line[len("Negative prompt: "):] elif current_section != "settings" and line.startswith("Steps: "): current_section = "settings" if current_section == "positive": positive_prompt.append(line) elif current_section == "negative": negative_prompt.append(line) elif current_section == "settings": settings_params.append(line) html_data = f"""

Prompt: {html.escape(NL.join(positive_prompt)).replace(NL, '
')}

Negative prompt: {html.escape(NL.join(negative_prompt)).replace(NL, '
')}

""" for key, value in parse_key_value_pairs("\n".join(settings_params)): html_data += f"

{html.escape(key).replace(NL, '
')}:
{html.escape(value).replace(NL, '
')}

" return html_data def process_nai(info_data): comment = json.loads(info_data["Comment"]) html_data = f"""

Prompt: {html.escape(comment.get('prompt', '')).replace(NL, '
')}

Undesired Content: {html.escape(comment.get('uc', '')).replace(NL, '
')}

Resolution: {comment.get('width', '')}x{comment.get('height', '')}

Seed: {comment.get('seed', '')}

Steps: {comment.get('steps', '')}

Sampler: {comment.get('sampler', '')} ({comment.get('noise_schedule', '')})

Prompt Guidance: {comment.get('scale', '')}

Prompt Guidance Rescale: {comment.get('cfg_rescale', '')}

Undesired Content Strength: {comment.get('uncond_scale', '')}

Request Type: {comment.get('request_type', '')}

Software: {info_data.get('Software', '')}

Source: {info_data.get('Source', '')}

Title: {info_data.get('Title', '')}

Generation Time: {info_data.get('Generation time', info_data.get('Generation_time', ''))}

""" return html_data, comment def process_image(file=None, url=None): try: if url: response = requests.get(url) response.raise_for_status() img = Image.open(BytesIO(response.content)) elif file: img = file else: return ( "No input provided.", gr.update(visible=False), gr.update(visible=False), gr.update(visible=False) ) info_data = img.info if info_data: if "parameters" in info_data: parameters = info_data["parameters"] html_data = process_webui(parameters) return ( html_data, gr.update(visible=True, value=f"

{html.escape(parameters).replace(NL, '
')}

"), gr.update(visible=False), gr.update(visible=True, value=img) if url else gr.update(visible=False) ) elif "Comment" in info_data and info_data.get("Software") == "NovelAI": simple, raw = process_nai(info_data) return ( simple, gr.update(visible=False), gr.update(visible=True, value=raw), gr.update(visible=True, value=img) if url else gr.update(visible=False) ) else: return ( "No metadata found.", gr.update(visible=False), gr.update(visible=False), gr.update(visible=True, value=img) if url else gr.update(visible=False) ) else: return ( "No metadata found.", gr.update(visible=False), gr.update(visible=False), gr.update(visible=True, value=img) if url else gr.update(visible=False) ) except Exception as e: return ( f"Error: {str(e)}", gr.update(visible=False), gr.update(visible=False), gr.update(visible=False) ) with gr.Blocks(css=css) as demo: with gr.Row(): with gr.Column(): gr.Markdown("### Upload an Image or Provide a URL") input_url = gr.Textbox(label="Source Image URL") btn = gr.Button("Submit", variant="primary") input_img = gr.Image(label="Source Image", type="pil", sources="upload", height=240) with gr.Column(): gr.Markdown("### Image Info") output_img = gr.Image(label="URL Image", interactive=False, visible=False, height=240) with gr.Tabs(): with gr.Tab("Metadata"): output_html = gr.HTML() with gr.Tab("Raw Parameters"): output_json = gr.JSON(container=False, visible=False) output_params = gr.HTML(visible=False) input_img.change( fn=process_image, inputs=input_img, outputs=[output_html, output_params, output_json, output_img], api_name="interrogate" ) btn.click(process_image, inputs=[input_img, input_url], outputs=[output_html, output_params, output_json, output_img]) demo.launch()