Also create another file on output that uses the model name and follows this format [ 'codeformer', 'gfpgan_1.2', 'gfpgan_1.3', 'gfpgan_1.4', 'gpen_bfr_256', 'gpen_bfr_512', 'gpen_bfr_1024', 'gpen_bfr_2048', 'restoreformer_plus_plus' ] and update this code import os
import re
import json
import tkinter as tk
from tkinter import filedialog, messagebox, ttk

# Ensure resolve_relative_path is defined. If not, define it as needed.
# For demonstration, here's a placeholder implementation.
def resolve_relative_path(relative_path):
    # Implement the actual logic for resolving relative paths as needed.
    return relative_path

class DFMModelManager:
    def __init__(self, root):
        self.root = root
        self.root.title("DFM Models Manager")
        self.models = {}
        self.dfmpath = ""
        self.create_widgets()
        self.setup_grid_weights()

    def create_widgets(self):
        # Frame for path selection
        path_frame = ttk.Frame(self.root, padding="10")
        path_frame.grid(row=0, column=0, sticky="ew")

        self.path_var = tk.StringVar()
        path_label = ttk.Label(path_frame, text="DFM Models Path:")
        path_label.pack(side=tk.LEFT, padx=(0, 5))

        path_entry = ttk.Entry(path_frame, textvariable=self.path_var)
        path_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 5))

        browse_button = ttk.Button(path_frame, text="Browse", command=self.browse_path)
        browse_button.pack(side=tk.LEFT, padx=(0, 5))

        load_button = ttk.Button(path_frame, text="Load Models", command=self.load_models)
        load_button.pack(side=tk.LEFT)

        # Frame for search
        search_frame = ttk.Frame(self.root, padding="10")
        search_frame.grid(row=1, column=0, sticky="ew")

        search_label = ttk.Label(search_frame, text="Search:")
        search_label.pack(side=tk.LEFT, padx=(0, 5))

        self.search_var = tk.StringVar()
        search_entry = ttk.Entry(search_frame, textvariable=self.search_var)
        search_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 5))
        search_entry.bind("<KeyRelease>", self.update_search)

        clear_search_button = ttk.Button(search_frame, text="Clear", command=self.clear_search)
        clear_search_button.pack(side=tk.LEFT)

        # Notebook for tabs
        notebook = ttk.Notebook(self.root)
        notebook.grid(row=2, column=0, sticky="nsew", padx=10, pady=5)

        # Completed Models Tab
        self.completed_frame = ttk.Frame(notebook)
        notebook.add(self.completed_frame, text="Completed Models")

        self.create_treeview(self.completed_frame, is_completed=True)

        # Pending Models Tab
        self.pending_frame = ttk.Frame(notebook)
        notebook.add(self.pending_frame, text="Pending Models")

        self.create_treeview(self.pending_frame, is_completed=False)

        # Frame for updating resolution
        update_frame = ttk.Frame(self.root, padding="10")
        update_frame.grid(row=3, column=0, sticky="ew")

        size_label = ttk.Label(update_frame, text="Update Size (width, height):")
        size_label.pack(side=tk.LEFT, padx=(0, 5))

        self.size_entry = ttk.Entry(update_frame)
        self.size_entry.pack(side=tk.LEFT, padx=(0, 5))
        self.size_entry.insert(0, "e.g., 256, 256")  # Placeholder text
        self.size_entry.bind("<FocusIn>", self.clear_placeholder)

        update_button = ttk.Button(update_frame, text="Update Selected", command=self.update_selected)
        update_button.pack(side=tk.LEFT, padx=(5, 0))

        # Frame for save button
        save_frame = ttk.Frame(self.root, padding="10")
        save_frame.grid(row=4, column=0, sticky="ew")

        save_button = ttk.Button(save_frame, text="Save Changes", command=self.save_changes)
        save_button.pack(side=tk.RIGHT)

    def clear_placeholder(self, event):
        if self.size_entry.get() == "e.g., 256, 256":
            self.size_entry.delete(0, tk.END)

    def setup_grid_weights(self):
        # Configure grid weights for responsiveness
        self.root.rowconfigure(2, weight=1)  # Notebook row
        self.root.columnconfigure(0, weight=1)  # Single column

    def create_treeview(self, parent, is_completed=True):
        columns = ("Model Name", "Hash URL", "Source URL", "Template", "Size")
        tree = ttk.Treeview(parent, columns=columns, show='headings', selectmode="extended")
        for col in columns:
            tree.heading(col, text=col)
            tree.column(col, anchor='center', width=200)
        tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        scrollbar = ttk.Scrollbar(parent, orient=tk.VERTICAL, command=tree.yview)
        tree.configure(yscroll=scrollbar.set)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

        if is_completed:
            self.tree_completed = tree
        else:
            self.tree_pending = tree

    def browse_path(self):
        directory = filedialog.askdirectory()
        if directory:
            self.path_var.set(directory)

    def load_models(self):
        self.dfmpath = self.path_var.get()
        if not os.path.isdir(self.dfmpath):
            messagebox.showerror("Error", "Invalid directory path.")
            return

        # Clear existing models
        self.models.clear()
        for item in self.tree_completed.get_children():
            self.tree_completed.delete(item)
        for item in self.tree_pending.get_children():
            self.tree_pending.delete(item)

        # Define possible resolutions
        # Resolutions are any 3 or 4-digit numbers not followed by 'k' or 'K'
        resolution_pattern = re.compile(r'(\d{3,4})(?![kK])')

        # Walk through the directory to find .dfm files
        for root_dir, dirs, files in os.walk(self.dfmpath):
            for file in files:
                if file.lower().endswith(".dfm"):
                    full_path = os.path.join(root_dir, file)
                    relative_path = os.path.relpath(full_path, self.dfmpath)
                    # Replace backslashes with forward slashes for consistency
                    relative_path = relative_path.replace("\\", "/")
                    model_name = os.path.splitext(relative_path)[0]  # Removes .dfm extension

                    dfm_path = full_path
                    hash_file = model_name + ".hash"
                    hash_path = os.path.join(self.dfmpath, hash_file).replace("\\", "/")  # Ensure correct path

                    if os.path.exists(hash_path):
                        # Attempt to detect resolution(s) from model name
                        matches = resolution_pattern.findall(model_name)
                        # Take the first detected resolution
                        if matches:
                            res_value = int(matches[0])
                            size = (res_value, res_value)  # Ensuring tuple format
                            completed = True
                        else:
                            size = (224, 224)  # Default size as tuple
                            completed = False

                        model_key = model_name  # Includes any subdirectories like 'iperov/jackie_chan_224'

                        model_data = {
                            "hashes": {
                                "deep_swapper": {
                                    "url": None,  # Initialize as None
                                    "path": hash_path
                                }
                            },
                            "sources": {
                                "deep_swapper": {
                                    "url": None,  # Initialize as None
                                    "path": dfm_path.replace("\\", "/")
                                }
                            },
                            "template": "arcface_128_v2",
                            "size": size,  # Tuple format
                            "completed": completed
                        }

                        self.models[model_key] = model_data

                        # Insert into appropriate treeview
                        tree = self.tree_completed if completed else self.tree_pending
                        tree.insert("", "end", iid=model_key, values=(
                            model_key,
                            model_data["hashes"]["deep_swapper"]["url"],
                            model_data["sources"]["deep_swapper"]["url"],
                            model_data["template"],
                            model_data["size"]  # Displaying tuple
                        ))

        if not self.models:
            messagebox.showinfo("Info", "No models found in the specified directory.")
        else:
            messagebox.showinfo("Success", f"Loaded {len(self.models)} models successfully.")

    def update_search(self, event=None):
        query = self.search_var.get().lower()
        # Clear existing treeviews
        for tree in [self.tree_completed, self.tree_pending]:
            for item in tree.get_children():
                tree.delete(item)

        # Re-insert based on search
        for model_key, model_data in self.models.items():
            if query in model_key.lower():
                tree = self.tree_completed if model_data.get("completed", False) else self.tree_pending
                tree.insert("", "end", iid=model_key, values=(
                    model_key,
                    model_data["hashes"]["deep_swapper"]["url"],
                    model_data["sources"]["deep_swapper"]["url"],
                    model_data["template"],
                    model_data["size"]  # Ensuring tuple display
                ))

    def clear_search(self):
        self.search_var.set("")
        # Reload models to reset the treeviews
        self.load_models()

    def update_selected(self):
        # Determine which tab is currently active
        current_tab = self.get_current_tab()
        tree = self.tree_completed if current_tab == "Completed Models" else self.tree_pending

        selected = tree.selection()
        if not selected:
            messagebox.showwarning("Warning", "No model selected.")
            return
        new_size = self.size_entry.get().strip()
        if not new_size or new_size == "e.g., 256, 256":
            messagebox.showwarning("Warning", "Size cannot be empty.")
            return
        try:
            # Extract all numbers from the input
            numbers = re.findall(r'\d+', new_size)
            if len(numbers) != 2:
                raise ValueError
            size_tuple = tuple(map(int, numbers))
            if any(n <= 0 for n in size_tuple):
                raise ValueError
        except ValueError:
            messagebox.showerror("Error", "Invalid size format. Enter two positive integers separated by a comma (e.g., 256, 256).")
            return

        for item in selected:
            self.models[item]["size"] = size_tuple  # Updating to tuple
            self.models[item]["completed"] = True  # Mark as completed

            # Update the treeview item
            # Remove from current treeview and add to Completed if not already there
            tree.delete(item)
            self.tree_completed.insert("", "end", iid=item, values=(
                item,
                self.models[item]["hashes"]["deep_swapper"]["url"],
                self.models[item]["sources"]["deep_swapper"]["url"],
                self.models[item]["template"],
                self.models[item]["size"]  # Display as tuple
            ))

        messagebox.showinfo("Success", "Selected models have been updated and moved to Completed Models.")

    def get_current_tab(self):
        # Get the name of the currently selected tab
        notebook = self.completed_frame.master  # Assuming notebook is the parent of completed_frame
        return notebook.tab(notebook.select(), "text")

    def save_changes(self):
        if not self.dfmpath:
            messagebox.showerror("Error", "DFM Models Path not set.")
            return

        # Building the MODEL_SET dictionary as a string
        models_str = "MODEL_SET : ModelSet =\n{\n"
        for model_key, model_data in self.models.items():
            # Normalize the model_key to use '/' as separator
            prefixed_key = model_key.replace(os.path.sep, '/')

            # Prepare the hashes and sources dictionaries as strings
            hashes_str = json.dumps(model_data["hashes"], indent=12)
            sources_str = json.dumps(model_data["sources"], indent=12)

            # Format the template and size
            template_str = f'        "template": "{model_data["template"]}",\n'
            size_tuple_str = f'        "size": {model_data["size"]}\n'  # Tuple format

            # Determine if paths are relative or absolute and use resolve_relative_path accordingly
            # Here, assuming paths within the DFM path are relative
            hash_path = model_data["hashes"]["deep_swapper"]["path"]
            source_path = model_data["sources"]["deep_swapper"]["path"]

            # Check if the path is inside the dfmpath to make it relative
            if os.path.commonpath([hash_path, self.dfmpath]) == self.dfmpath:
                rel_hash_path = os.path.relpath(hash_path, self.dfmpath).replace("\\", "/")
                hash_path_str = f"resolve_relative_path('../{rel_hash_path}')"
            else:
                hash_path_str = f'"{hash_path}"'

            if os.path.commonpath([source_path, self.dfmpath]) == self.dfmpath:
                rel_source_path = os.path.relpath(source_path, self.dfmpath).replace("\\", "/")
                source_path_str = f"resolve_relative_path('../{rel_source_path}')"
            else:
                source_path_str = f'"{source_path}"'

            # Manually construct hashes and sources with url=None and path
            hashes_managed_str = (
                "        \"hashes\": {\n"
                "            \"deep_swapper\": {\n"
                "                \"url\": None,\n"
                f"                \"path\": {hash_path_str}\n"
                "            }\n"
                "        },\n"
            )

            sources_managed_str = (
                "        \"sources\": {\n"
                "            \"deep_swapper\": {\n"
                "                \"url\": None,\n"
                f"                \"path\": {source_path_str}\n"
                "            }\n"
                "        },\n"
            )

            # Concatenate all parts for the current model
            model_entry = f'    "{prefixed_key}": {{\n'
            model_entry += hashes_managed_str
            model_entry += sources_managed_str
            model_entry += template_str
            model_entry += size_tuple_str
            model_entry += "    },\n"

            models_str += model_entry

        models_str += "}\n"

        # Combine all parts into the final content
        file_content = models_str

        # Define the path for the .py file
        python_file_path = os.path.join(self.dfmpath, "updated_models.py")

        try:
            with open(python_file_path, 'w', encoding='utf-8') as f:
                f.write(file_content)
            messagebox.showinfo("Success", f"Changes saved to {python_file_path}")
        except Exception as e:
            messagebox.showerror("Error", f"Failed to save changes.\n{e}")
            return

    # Removed the additional file creation as per the instruction to "get rid of model list and the end"

def main():
    root = tk.Tk()
    root.geometry("1200x700")
    root.minsize(800, 600)
    app = DFMModelManager(root)
    root.mainloop()

if __name__ == "__main__":
        main()