I get no models found in directory and then also incorporate this into it after renaming  import os
import time
import zlib


def calculate_checksum(file_path):
	with open(file_path, 'rb') as f:
		content = f.read()
	return format(zlib.crc32(content), '08x')


def generate_checksums(directory):
	for filename in sorted(os.listdir(directory)):
		file_path = os.path.join(directory, filename)

		# Process only .onnx files
		if os.path.isfile(file_path) and filename.lower().endswith('.dfm'):
			hash_file_path = os.path.join(directory, f"{os.path.splitext(filename)[0]}.hash")

			checksum = calculate_checksum(file_path)
			with open(hash_file_path, 'w') as hash_file:
				hash_file.write(checksum)
			print(f"Checksum for '{filename}' written to '{hash_file_path}'")


if __name__ == "__main__":
	start_time = time.time()
	# Replace 'your_directory_path_here' with the path to the directory you want to process
	directory_path = '.assets/models'
	generate_checksums(directory_path)
	print("--- %s seconds ---" % (time.time() - start_time))
 And update this with it 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.backup_filename = "rename_backup.json"
        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)

        # Notebook for tabs
        notebook = ttk.Notebook(self.root)
        notebook.grid(row=1, 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)

        # Rename Files Tab
        self.rename_frame = ttk.Frame(notebook)
        notebook.add(self.rename_frame, text="Rename Files")

        self.create_rename_tab(self.rename_frame)

        # Frame for updating resolution
        update_frame = ttk.Frame(self.root, padding="10")
        update_frame.grid(row=2, 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=3, 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(1, 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 create_rename_tab(self, parent):
        # Frame for renaming controls
        controls_frame = ttk.LabelFrame(parent, text="Rename .dfm Files (Spaces to Underscores)", padding="10")
        controls_frame.pack(fill="x", padx=10, pady=10)

        # Buttons for preview, rename, and revert
        preview_button = ttk.Button(controls_frame, text="Preview Changes", command=self.preview_changes)
        preview_button.pack(side="left", padx=5, pady=5)

        rename_button = ttk.Button(controls_frame, text="Rename Files", command=self.rename_files)
        rename_button.pack(side="left", padx=5, pady=5)

        revert_button = ttk.Button(controls_frame, text="Revert Rename", command=self.revert_changes)
        revert_button.pack(side="left", padx=5, pady=5)

        # Treeview for displaying file changes
        tree_frame = ttk.Frame(parent)
        tree_frame.pack(fill="both", expand=True, padx=10, pady=10)

        columns = ("Original Filename", "New Filename")
        self.rename_tree = ttk.Treeview(tree_frame, columns=columns, show="headings")
        self.rename_tree.heading("Original Filename", text="Original Filename")
        self.rename_tree.heading("New Filename", text="New Filename")
        self.rename_tree.column("Original Filename", width=300)
        self.rename_tree.column("New Filename", width=300)
        self.rename_tree.pack(side="left", fill="both", expand=True)

        scrollbar = ttk.Scrollbar(tree_frame, orient="vertical", command=self.rename_tree.yview)
        self.rename_tree.configure(yscroll=scrollbar.set)
        scrollbar.pack(side="right", fill="y")

    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"],
                            self.format_size(model_data["size"])  # Displaying as "width x height"
                        ))

        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 format_size(self, size_tuple):
        return f"{size_tuple[0]} x {size_tuple[1]}"

    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"],
                    self.format_size(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.format_size(self.models[item]["size"])  # Display as "width x height"
            ))

        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, '/')

            # 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"
            )

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

            # 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

    ### Renaming Functionality Begins Here ###

    def get_dfm_files(self):
        folder = self.dfmpath
        if not folder:
            messagebox.showwarning("No Folder Selected", "Please select a folder first.")
            return []

        dfm_files = []
        for root_dir, dirs, files in os.walk(folder):
            for filename in files:
                if filename.lower().endswith(".dfm"):
                    filepath = os.path.join(root_dir, filename)
                    mod_time = os.path.getmtime(filepath)
                    atime = os.path.getatime(filepath)
                    dfm_files.append((filename, mod_time, atime, root_dir))
        
        if not dfm_files:
            messagebox.showinfo("No DFM Files", "No .dfm files found in the selected folder.")
        
        return dfm_files

    def preview_changes(self):
        self.rename_tree.delete(*self.rename_tree.get_children())
        dfm_files = self.get_dfm_files()
        if not dfm_files:
            return

        # Sort files based on modification time (newest first by default)
        dfm_files.sort(key=lambda x: x[1], reverse=True)

        self.rename_preview_list = []
        for original, mod_time, atime, root_dir in dfm_files:
            new_name = original.replace(" ", "_")
            if original != new_name:
                self.rename_preview_list.append((original, new_name, mod_time, atime, root_dir))
                self.rename_tree.insert("", "end", values=(original, new_name))

        if not self.rename_preview_list:
            messagebox.showinfo("No Changes Needed", "No filenames contain spaces to replace.")

    def rename_files(self):
        if not hasattr(self, 'rename_preview_list') or not self.rename_preview_list:
            messagebox.showinfo("No Changes", "There are no changes to apply. Please preview first.")
            return

        confirm = messagebox.askyesno("Confirm Rename", f"Are you sure you want to rename {len(self.rename_preview_list)} files?")
        if not confirm:
            return

        folder = self.dfmpath
        backup_path = os.path.join(folder, self.backup_filename)
        errors = []
        backup_data = {}

        for original, new, mod_time, atime, root_dir in self.rename_preview_list:
            original_path = os.path.join(root_dir, original)
            new_path = os.path.join(root_dir, new)
            try:
                if os.path.exists(new_path):
                    raise FileExistsError(f"Cannot rename '{original}' to '{new}': Destination file already exists.")
                os.rename(original_path, new_path)
                # Restore original modification and access times
                os.utime(new_path, (atime, mod_time))
                # Save to backup data
                relative_new_path = os.path.relpath(new_path, folder).replace("\\", "/")
                backup_data[relative_new_path] = {
                    "original": original,
                    "mod_time": mod_time,
                    "atime": atime,
                    "root_dir": root_dir
                }
            except Exception as e:
                errors.append(str(e))

        if backup_data:
            try:
                with open(backup_path, 'w') as backup_file:
                    json.dump(backup_data, backup_file, indent=4)
            except Exception as e:
                messagebox.showerror("Backup Error", f"Failed to create backup file:\n{str(e)}")
                # Optionally, you might want to undo the renames if backup fails
                return

        if errors:
            error_message = "\n".join(errors)
            messagebox.showerror("Errors Occurred", f"Some files could not be renamed:\n{error_message}")
        else:
            messagebox.showinfo("Success", "All files have been renamed successfully.")

        self.preview_changes()  # Refresh the preview after renaming

    def revert_changes(self):
        folder = self.dfmpath
        if not folder:
            messagebox.showwarning("No Folder Selected", "Please select a folder first.")
            return

        backup_path = os.path.join(folder, self.backup_filename)
        if not os.path.exists(backup_path):
            messagebox.showinfo("No Backup Found", "No backup file found to revert changes.")
            return

        try:
            with open(backup_path, 'r') as backup_file:
                backup_data = json.load(backup_file)
        except Exception as e:
            messagebox.showerror("Backup Error", f"Failed to read backup file:\n{str(e)}")
            return

        if not backup_data:
            messagebox.showinfo("Empty Backup", "Backup file is empty. Nothing to revert.")
            return

        confirm = messagebox.askyesno("Confirm Revert", f"Are you sure you want to revert {len(backup_data)} files?")
        if not confirm:
            return

        errors = []
        for relative_new_path, info in backup_data.items():
            new_path = os.path.join(folder, relative_new_path)
            original = info["original"]
            mod_time = info["mod_time"]
            atime = info["atime"]
            root_dir = info["root_dir"]
            original_path = os.path.join(root_dir, original)

            try:
                if os.path.exists(original_path):
                    raise FileExistsError(f"Cannot revert '{new_path}' to '{original}': Original filename already exists.")
                os.rename(new_path, original_path)
                # Restore original modification and access times
                os.utime(original_path, (atime, mod_time))
            except Exception as e:
                errors.append(str(e))

        if errors:
            error_message = "\n".join(errors)
            messagebox.showerror("Errors Occurred", f"Some files could not be reverted:\n{error_message}")
        else:
            messagebox.showinfo("Success", "All files have been reverted successfully.")
            # Remove the backup file after successful revert
            try:
                os.remove(backup_path)
            except Exception as e:
                messagebox.showwarning("Cleanup Warning", f"Could not delete backup file:\n{str(e)}")

        self.rename_changes_post_revert()

    def rename_changes_post_revert(self):
        """Refresh the rename preview after reverting."""
        self.rename_tree.delete(*self.rename_tree.get_children())
        messagebox.showinfo("Revert Completed", "Renaming changes have been reverted.")

    ### Renaming Functionality Ends Here ###


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


if __name__ == "__main__":
    main()