import pyperclip import os import io from PIL import Image from sd_parsers import ParserManager import gradio as gr import re import json parser_manager = ParserManager() TITLE = "

Workflow Info Reader - By Andy N Le 0908 23 11 81

\n" def extract_lora_info(prompt): lora_pattern = r"" loras = re.findall(lora_pattern, prompt) if not loras: return "Không xác định" lora_info = [f" {name} - Weight: {weight}" for name, weight in loras] return "\n".join(lora_info) def generate_workflow_from_metadata(metadata): nodes = [] connections = [] if 'nodes' in metadata: for node in metadata['nodes']: nodes.append({ 'id': node['id'], 'title': node.get('title', 'Unnamed Node'), 'pos': node.get('pos', [0, 0]), 'type': node.get('type', 'basic/node') }) if 'connections' in metadata: for conn in metadata['connections']: connections.append({ 'from': conn['from'], 'to': conn['to'] }) return { 'nodes': nodes, 'connections': connections } def format_sampler_params(sampler_params): try: params = json.loads(sampler_params) except (json.JSONDecodeError, TypeError): return "Không xác định" scheduler = params.get("scheduler", "Không xác định") cfg_scale = params.get("cfg_scale", "Không xác định") steps = params.get("steps", "Không xác định") return f"scheduler: {scheduler}\nCFG: {cfg_scale}\nSteps: {steps}" download_file = gr.File(label="Tải file đã tạo", visible=False) def save_metadata_to_file(image_input, prompt, neg_prompt, model, loras, seed, sampler, sampler_params, metadata): if not any([prompt, neg_prompt, model, loras, seed, sampler, sampler_params, metadata]): return None, gr.Info("Không có thông tin để lưu!", duration=2) if image_input is None: return None, gr.Info("Không thể lưu tệp: Không có ảnh nào được tải lên.", duration=2) # Lấy tên file ảnh và đặt tên cho file txt image_filename = os.path.basename(image_input) txt_filename = os.path.splitext(image_filename)[0] + ".txt" txt_filepath = os.path.join("outputs", txt_filename) # Ghi thông tin metadata vào file txt with open(txt_filepath, "w", encoding="utf-8") as f: f.write(f"Prompt: {prompt}\n") f.write(f"Negative Prompt: {neg_prompt}\n") f.write(f"Model: {model}\n") f.write(f"Loras: {loras}\n") f.write(f"Seed: {seed}\n") f.write(f"Sampler: {sampler}\n") f.write(f"Sampler Parameters: {sampler_params}\n") f.write(f"Other Metadata:\n{metadata}\n") return txt_filepath, gr.Info(f"Đã lưu thông tin vào file: {txt_filename}", duration=2) def read_image_metadata(image_path): try: if not image_path: raise ValueError("Không có ảnh được tải lên.") with Image.open(image_path) as img: prompt_info = parser_manager.parse(img) if not prompt_info: raise ValueError("Không thể đọc thông tin từ ảnh.") # Kiểm tra loại generator if prompt_info.generator == "AUTOMATIC1111": return handle_automatic1111(prompt_info) elif prompt_info.generator == "ComfyUI": return handle_comfyui(prompt_info) else: raise ValueError("Loại generator không được hỗ trợ.") except Exception as e: print(f"Lỗi khi xử lý ảnh: {str(e)}") return "Không tìm thấy thông tin!", "", "", "", "", "", "", "" def handle_automatic1111(prompt_info): prompt = prompt_info.full_prompt negative_prompt = prompt_info.full_negative_prompt if prompt_info.full_negative_prompt else "N/A" models_list = list(prompt_info.models) if isinstance(prompt_info.models, set) else prompt_info.models model = models_list[0].name if models_list else "Không xác định" loras = extract_lora_info(prompt) samplers_list = list(prompt_info.samplers) if isinstance(prompt_info.samplers, set) else prompt_info.samplers if samplers_list and len(samplers_list) > 0: sampler = samplers_list[0].name if samplers_list[0].name else "N/A" sampler_params = json.dumps(samplers_list[0].parameters) if samplers_list[0].parameters else "N/A" seed = samplers_list[0].parameters.get('seed', 'Không xác định') else: sampler = "N/A" sampler_params = "N/A" seed = "Không xác định" formatted_sampler_params = format_sampler_params(sampler_params) other_metadata = "\n".join([ f"{key}: {value}" for key, value in prompt_info.metadata.items() if isinstance(key, str) and not key.startswith("Module") ]) return prompt, negative_prompt, model, loras, seed, sampler, formatted_sampler_params, other_metadata def format_metadata(metadata): formatted_output = "" for key, value in metadata.items(): node_title, node_id = key formatted_output += f"Node '{node_title}'\n" for prop_key, prop_value in value.items(): formatted_output += f" {prop_key}: {prop_value}\n" return formatted_output def handle_comfyui(prompt_info): prompt = prompt_info.full_prompt or "Không xác định" negative_prompt = prompt_info.full_negative_prompt if prompt_info.full_negative_prompt else "N/A" models_list = list(prompt_info.models) if isinstance(prompt_info.models, set) else prompt_info.models model = models_list[0].name if models_list else "Không xác định" samplers_list = list(prompt_info.samplers) if isinstance(prompt_info.samplers, set) else prompt_info.samplers if samplers_list and len(samplers_list) > 0: sampler = samplers_list[0].name if samplers_list[0].name else "N/A" sampler_params = json.dumps(samplers_list[0].parameters) if samplers_list[0].parameters else "N/A" seed = samplers_list[0].parameters.get('seed', 'Không xác định') else: sampler = "N/A" sampler_params = "N/A" seed = "Không xác định" formatted_sampler_params = format_sampler_params(sampler_params) converted_metadata = {} for key, value in prompt_info.metadata.items(): if isinstance(key, tuple): key = str(key) converted_metadata[key] = value other_metadata = format_metadata(prompt_info.metadata) if not other_metadata: other_metadata = "Không có metadata bổ sung." return prompt, negative_prompt, model, None, seed, sampler, formatted_sampler_params, other_metadata output_dir = "outputs" if not os.path.exists(output_dir): os.mkdir(output_dir) def copy_to_clipboard(prompt, neg_prompt, seed, copy_prompt, copy_neg_prompt, copy_seed): copied_text = "" if copy_prompt: copied_text += f"Prompt: {prompt}\n" if copy_neg_prompt: copied_text += f"Negative Prompt: {neg_prompt}\n" if copy_seed: copied_text += f"Seed: {seed}\n" if copied_text: try: pyperclip.copy(copied_text) return gr.Info("Sao chép thành công!", duration=2) except pyperclip.PyperclipException: return gr.Info("Không hỗ trợ tính năng này trong bản demo. Vui lòng liên hệ tác giả để biết chi tiết !", duration=2) else: return gr.Info("Không có gì để sao chép!", duration=2) # Hàm hủy bỏ sao chép def cancel_copy(): try: pyperclip.copy("") # Xóa clipboard return ( gr.update(value=False), # Uncheck all checkboxes gr.update(value=False), gr.update(value=False), gr.Info("Đã hủy bỏ sao chép!", duration=2) ) except pyperclip.PyperclipException: # Nếu không thể sử dụng clipboard trên hệ thống, hiển thị thông báo return ( gr.update(value=False), # Uncheck all checkboxes gr.update(value=False), gr.update(value=False), gr.Info("Hệ thống không hỗ trợ chức năng sao chép tự động.", duration=2) ) output_dir = "outputs" if not os.path.exists(output_dir): os.mkdir(output_dir) def check_image_size(image_input): try: if not image_input: raise ValueError("Không có ảnh được tải lên.") with Image.open(image_input) as img: width, height = img.size if width > 5000 or height > 5000: raise ValueError("Kích thước ảnh vượt quá 5000 px ở chiều ngang hoặc chiều dọc.") return image_input, gr.Info("Ảnh hợp lệ.", duration=1) except Exception as e: return None, gr.Info(f"Lỗi khi xử lý ảnh: {str(e)}", duration=2) def gradio_interface(image_input): try: # Đọc dữ liệu từ ảnh prompt, negative_prompt, model, loras, seed, sampler, formatted_sampler_params, other_metadata = read_image_metadata(image_input) # Kiểm tra xem dữ liệu có bị thiếu không cho từng trường hợp if prompt == "Không thể đọc thông tin" or not any([prompt, negative_prompt, model, seed]): raise ValueError("Thiếu dữ liệu khi xử lý ảnh.") return prompt, negative_prompt, model, loras, seed, sampler, formatted_sampler_params, other_metadata except Exception as e: # In ra lỗi và trả về nội dung lỗi print(f"Lỗi trong gradio_interface: {str(e)}") return "Không tìm thấy thông tin ", "", "", "", "", "", "", "" js_func = """ function refresh() { const url = new URL(window.location); if (url.searchParams.get('__theme') !== 'dark') { url.searchParams.set('__theme', 'dark'); window.location.href = url.href; } } """ with gr.Blocks(js = js_func) as demo: gr.HTML(TITLE) with gr.Row(): with gr.Column(): image_input = gr.Image(type="filepath", label="Tải lên hình ảnh") read_button = gr.Button("Đọc thông tin") copy_prompt = gr.Checkbox(label="Sao chép lời mô tả", value=False) copy_neg_prompt = gr.Checkbox(label="Sao chép mô tả loại trừ", value=False) copy_seed = gr.Checkbox(label="Sao Chép Seed", value=False) with gr.Row(): copy_button = gr.Button("Sao chép") cancel_button = gr.Button("Hủy sao chép") download_button = gr.Button("Lưu file .txt") message_output = gr.HTML() with gr.Column(): prompt_output = gr.Textbox(label="Lời mô tả (prompt)") negative_prompt_output = gr.Textbox(label="Mô tả loại trừ (Negative Prompt)") model_output = gr.Textbox(label="Mô hình (Model)") lora_output = gr.Textbox(label="Lora (Tên & Trọng số)") seed_output = gr.Textbox(label="Seed") sampler_output = gr.Textbox(label="Phương pháp lấy mẫu") sampler_params_output = gr.Textbox(label="Thông số lấy mẫu") other_metadata_output = gr.Textbox(label="Thông tin khác", lines=10) download_file = gr.File(label="Tải file đã tạo", visible=False) read_button.click( fn=check_image_size, inputs=image_input, outputs=[image_input, message_output], show_progress=False ) # Sau khi kiểm tra kích thước, nếu hợp lệ, đọc metadata từ ảnh read_button.click( fn=gradio_interface, inputs=image_input, outputs=[prompt_output, negative_prompt_output, model_output, lora_output, seed_output, sampler_output, sampler_params_output, other_metadata_output] ) copy_button.click( copy_to_clipboard, inputs=None, outputs=message_output, show_progress=False ) # Gắn sự kiện click cho nút hủy sao chép cancel_button.click( cancel_copy, inputs=None, outputs=message_output, show_progress=False ) def notify_download(): return gr.Info("Không hỗ trợ tính năng này trong bản demo. Vui lòng liên hệ tác giả để biết chi tiết!", duration=3) # Gắn sự kiện click cho nút download download_button.click( fn=notify_download, inputs=None, # Không cần inputs outputs=message_output, # Chỉ hiển thị thông báo show_progress=False ) if __name__ == "__main__": demo.launch(inbrowser=True)