initial commit with gui

This commit is contained in:
Karl 2025-09-23 13:59:06 +01:00
parent 2143847985
commit 14ae65eb57
7 changed files with 801 additions and 71 deletions

View File

@ -25,7 +25,9 @@ from lib.general import (
from lib.logging import LOGGING_CONFIG
# from simple_term_menu import TerminalMenu
from comfy_api_simplified import ComfyApiWrapper, ComfyWorkflowWrapper
from diffusers import StableDiffusionPipeline, DPMSolverMultistepScheduler
import torch
from PIL import Image
logging.config.dictConfig(LOGGING_CONFIG)
@ -51,31 +53,78 @@ p = inflect.engine()
def generate_image(uid, comfy_prompt):
"""Generate an image using the Comfy API."""
"""Generate an image using local Stable Diffusion."""
try:
# Initialize API and workflow
api = ComfyApiWrapper(user_config["comfyui"]["comfyui_url"])
wf = ComfyWorkflowWrapper("./workflow_api.json")
# Initialize the pipeline (do this once and reuse)
if not hasattr(generate_image, 'pipeline'):
logging.info("Loading Stable Diffusion model...")
# Set workflow parameters
wf.set_node_param("KSampler", "seed", random.getrandbits(32))
# wf.set_node_param("KSampler", "steps", steps)
wf.set_node_param("positive", "text", comfy_prompt)
wf.set_node_param("Save Image", "filename_prefix", uid)
wf.set_node_param(
"Load Checkpoint", "ckpt_name", user_config["comfyui"]["model"]
)
# Queue your workflow for completion
# Get model configuration
try:
model_id = user_config["models"]["model_name"]
model_dir = user_config["models"].get("model_dir", None)
logging.info(f"Using model: {model_id}")
except KeyError:
model_id = "SG161222/Realistic_Vision_V6.0_B1"
model_dir = None
logging.warning(f"Model configuration not found, using default: {model_id}")
# Check if CUDA is available
device = "cuda" if torch.cuda.is_available() else "cpu"
logging.info(f"Using device: {device}")
# Load the pipeline
if model_dir:
pipe = StableDiffusionPipeline.from_pretrained(
model_id,
cache_dir=model_dir,
torch_dtype=torch.float16 if device == "cuda" else torch.float32,
safety_checker=None,
requires_safety_checker=False
)
else:
pipe = StableDiffusionPipeline.from_pretrained(
model_id,
torch_dtype=torch.float16 if device == "cuda" else torch.float32,
safety_checker=None,
requires_safety_checker=False
)
# Use DPMSolverMultistepScheduler for better quality/speed balance
pipe.scheduler = DPMSolverMultistepScheduler.from_config(pipe.scheduler.config)
if device == "cuda":
pipe = pipe.to("cuda")
pipe.enable_attention_slicing() # Reduce memory usage
generate_image.pipeline = pipe
logging.info("Model loaded successfully")
# Generate the image
logging.debug(f"Generating image for UID: {uid}")
results = api.queue_and_wait_images(wf, "Save Image")
for filename, image_data in results.items():
with open(
f"{user_config[selected_profile]['output_dir']}{uid}.png", "wb+"
) as f:
f.write(image_data)
# Set random seed for reproducibility
generator = torch.Generator(device=generate_image.pipeline.device)
generator.manual_seed(random.getrandbits(32))
# Generate image with parameters similar to ComfyUI workflow
image = generate_image.pipeline(
comfy_prompt,
num_inference_steps=6,
guidance_scale=1.5,
generator=generator,
width=512,
height=512
).images[0]
# Save the image
output_path = f"{user_config[selected_profile]['output_dir']}{uid}.png"
image.save(output_path)
logging.debug(f"Image generated successfully for UID: {uid}")
except Exception as e:
logging.error(f"Failed to generate image for UID: {uid}. Error: {e}")
raise
def get_country_name(app_config, country_code):

500
gui.py Normal file
View File

@ -0,0 +1,500 @@
#!/usr/bin/env python3
"""
Standalone FM NewGens - GUI Interface
A user-friendly graphical interface for generating Football Manager faces
"""
import tkinter as tk
from tkinter import ttk, filedialog, messagebox, scrolledtext
import os
import sys
import json
import configparser
import threading
import queue
import time
from pathlib import Path
from PIL import Image, ImageTk
import logging
# Import the main generation logic
from comfy_fm_newgen import generate_image, get_country_name, generate_prompts_for_players
try:
from lib.rtf_parser import RTF_Parser
except ImportError:
# Fallback for when striprtf is not available
class RTF_Parser:
def parse_rtf(self, file_path):
print(f"Warning: RTF parsing not available. Please install striprtf: pip install striprtf==0.0.28")
return []
from lib.generate_xml import create_config_xml, append_to_config_xml
from lib.xml_reader import extract_from_values
from lib.general import choose_profile, create_or_update, process_player_or_file, get_player_input
class FMFaceGeneratorGUI:
def __init__(self, root):
self.root = root
self.root.title("FM Face Generator - Standalone Version")
self.root.geometry("1000x700")
self.root.minsize(800, 600)
# Initialize variables
self.config = None
self.app_config = None
self.rtf = RTF_Parser()
self.generation_thread = None
self.stop_generation = False
self.image_queue = queue.Queue()
# Set up the GUI
self.setup_gui()
self.load_config()
# Start image preview update loop
self.update_image_preview()
def setup_gui(self):
"""Set up the main GUI components"""
# Create main notebook (tabs)
self.notebook = ttk.Notebook(self.root)
self.notebook.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# Configuration tab
self.config_frame = ttk.Frame(self.notebook)
self.notebook.add(self.config_frame, text="Configuration")
# Generation tab
self.generation_frame = ttk.Frame(self.notebook)
self.notebook.add(self.generation_frame, text="Generation")
# Preview tab
self.preview_frame = ttk.Frame(self.notebook)
self.notebook.add(self.preview_frame, text="Preview")
# Setup each tab
self.setup_config_tab()
self.setup_generation_tab()
self.setup_preview_tab()
# Status bar
self.status_var = tk.StringVar()
self.status_var.set("Ready")
self.status_bar = ttk.Label(self.root, textvariable=self.status_var, relief=tk.SUNKEN)
self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
# Progress bar
self.progress_var = tk.DoubleVar()
self.progress_bar = ttk.Progressbar(self.root, variable=self.progress_var, maximum=100)
self.progress_bar.pack(side=tk.BOTTOM, fill=tk.X)
def setup_config_tab(self):
"""Set up the configuration tab"""
# Model selection
model_frame = ttk.LabelFrame(self.config_frame, text="AI Model", padding=10)
model_frame.pack(fill=tk.X, padx=10, pady=5)
ttk.Label(model_frame, text="Model:").grid(row=0, column=0, sticky=tk.W, pady=5)
self.model_var = tk.StringVar()
model_combo = ttk.Combobox(model_frame, textvariable=self.model_var, width=50)
model_combo['values'] = [
'SG161222/Realistic_Vision_V6.0_B1',
'digiplay/AbsoluteReality',
'stabilityai/stable-diffusion-2-1',
'runwayml/stable-diffusion-v1-5'
]
model_combo.grid(row=0, column=1, sticky=tk.W, padx=5, pady=5)
model_combo.set('SG161222/Realistic_Vision_V6.0_B1')
# Model directory
ttk.Label(model_frame, text="Model Directory:").grid(row=1, column=0, sticky=tk.W, pady=5)
self.model_dir_var = tk.StringVar()
model_dir_entry = ttk.Entry(model_frame, textvariable=self.model_dir_var, width=50)
model_dir_entry.grid(row=1, column=1, sticky=tk.W, padx=5, pady=5)
ttk.Button(model_frame, text="Browse...", command=self.browse_model_dir).grid(row=1, column=2, padx=5, pady=5)
# FM Configuration
fm_frame = ttk.LabelFrame(self.config_frame, text="Football Manager", padding=10)
fm_frame.pack(fill=tk.X, padx=10, pady=5)
ttk.Label(fm_frame, text="FM Version:").grid(row=0, column=0, sticky=tk.W, pady=5)
self.fm_version_var = tk.StringVar(value="2024")
fm_version_entry = ttk.Entry(fm_frame, textvariable=self.fm_version_var, width=20)
fm_version_entry.grid(row=0, column=1, sticky=tk.W, padx=5, pady=5)
ttk.Label(fm_frame, text="RTF File:").grid(row=1, column=0, sticky=tk.W, pady=5)
self.rtf_file_var = tk.StringVar()
rtf_entry = ttk.Entry(fm_frame, textvariable=self.rtf_file_var, width=50)
rtf_entry.grid(row=1, column=1, sticky=tk.W, padx=5, pady=5)
ttk.Button(fm_frame, text="Browse...", command=self.browse_rtf_file).grid(row=1, column=2, padx=5, pady=5)
ttk.Label(fm_frame, text="Output Directory:").grid(row=2, column=0, sticky=tk.W, pady=5)
self.output_dir_var = tk.StringVar()
output_entry = ttk.Entry(fm_frame, textvariable=self.output_dir_var, width=50)
output_entry.grid(row=2, column=1, sticky=tk.W, padx=5, pady=5)
ttk.Button(fm_frame, text="Browse...", command=self.browse_output_dir).grid(row=2, column=2, padx=5, pady=5)
# Control buttons
button_frame = ttk.Frame(self.config_frame)
button_frame.pack(fill=tk.X, padx=10, pady=10)
ttk.Button(button_frame, text="Save Configuration", command=self.save_config).pack(side=tk.LEFT, padx=5)
ttk.Button(button_frame, text="Load Configuration", command=self.load_config).pack(side=tk.LEFT, padx=5)
ttk.Button(button_frame, text="Reset to Defaults", command=self.reset_config).pack(side=tk.LEFT, padx=5)
def setup_generation_tab(self):
"""Set up the generation tab"""
# Player selection
player_frame = ttk.LabelFrame(self.generation_frame, text="Player Selection", padding=10)
player_frame.pack(fill=tk.X, padx=10, pady=5)
self.player_mode_var = tk.StringVar(value="all")
ttk.Radiobutton(player_frame, text="Process all players", variable=self.player_mode_var, value="all", command=self.update_player_controls).grid(row=0, column=0, sticky=tk.W, pady=5)
ttk.Radiobutton(player_frame, text="Process specific player", variable=self.player_mode_var, value="specific", command=self.update_player_controls).grid(row=0, column=1, sticky=tk.W, pady=5)
ttk.Label(player_frame, text="Player UID:").grid(row=1, column=0, sticky=tk.W, pady=5)
self.player_uid_var = tk.StringVar()
self.player_uid_entry = ttk.Entry(player_frame, textvariable=self.player_uid_var, width=20, state=tk.DISABLED)
self.player_uid_entry.grid(row=1, column=1, sticky=tk.W, padx=5, pady=5)
# Generation options
gen_frame = ttk.LabelFrame(self.generation_frame, text="Generation Options", padding=10)
gen_frame.pack(fill=tk.X, padx=10, pady=5)
self.update_mode_var = tk.StringVar(value="false")
ttk.Checkbutton(gen_frame, text="Update existing (skip already processed)", variable=self.update_mode_var, onvalue="true", offvalue="false").grid(row=0, column=0, sticky=tk.W, pady=5)
# Progress display
progress_frame = ttk.LabelFrame(self.generation_frame, text="Progress", padding=10)
progress_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
# Status text
self.status_text = scrolledtext.ScrolledText(progress_frame, height=10, wrap=tk.WORD)
self.status_text.pack(fill=tk.BOTH, expand=True, pady=5)
# Control buttons
control_frame = ttk.Frame(self.generation_frame)
control_frame.pack(fill=tk.X, padx=10, pady=10)
self.start_button = ttk.Button(control_frame, text="Start Generation", command=self.start_generation)
self.start_button.pack(side=tk.LEFT, padx=5)
self.stop_button = ttk.Button(control_frame, text="Stop Generation", command=self.stop_generation_thread, state=tk.DISABLED)
self.stop_button.pack(side=tk.LEFT, padx=5)
ttk.Button(control_frame, text="Clear Log", command=self.clear_log).pack(side=tk.RIGHT, padx=5)
def setup_preview_tab(self):
"""Set up the preview tab"""
# Image preview
preview_frame = ttk.LabelFrame(self.preview_frame, text="Generated Images", padding=10)
preview_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
# Image display
self.image_label = ttk.Label(preview_frame, text="No images generated yet")
self.image_label.pack(pady=20)
# Image info
info_frame = ttk.Frame(preview_frame)
info_frame.pack(fill=tk.X, pady=10)
ttk.Label(info_frame, text="Current Image:").grid(row=0, column=0, sticky=tk.W)
self.current_image_var = tk.StringVar()
ttk.Label(info_frame, textvariable=self.current_image_var).grid(row=0, column=1, sticky=tk.W, padx=5)
ttk.Label(info_frame, text="Total Generated:").grid(row=1, column=0, sticky=tk.W)
self.total_generated_var = tk.StringVar(value="0")
ttk.Label(info_frame, textvariable=self.total_generated_var).grid(row=1, column=1, sticky=tk.W, padx=5)
# Navigation buttons
nav_frame = ttk.Frame(preview_frame)
nav_frame.pack(fill=tk.X, pady=10)
ttk.Button(nav_frame, text="Previous", command=self.show_previous_image).pack(side=tk.LEFT, padx=5)
ttk.Button(nav_frame, text="Next", command=self.show_next_image).pack(side=tk.LEFT, padx=5)
ttk.Button(nav_frame, text="Refresh", command=self.refresh_preview).pack(side=tk.RIGHT, padx=5)
def browse_model_dir(self):
"""Browse for model directory"""
directory = filedialog.askdirectory(title="Select Model Directory")
if directory:
self.model_dir_var.set(directory)
def browse_rtf_file(self):
"""Browse for RTF file"""
file_path = filedialog.askopenfilename(
title="Select RTF File",
filetypes=[("RTF files", "*.rtf"), ("All files", "*.*")]
)
if file_path:
self.rtf_file_var.set(file_path)
def browse_output_dir(self):
"""Browse for output directory"""
directory = filedialog.askdirectory(title="Select Output Directory")
if directory:
self.output_dir_var.set(directory)
def update_player_controls(self):
"""Update player selection controls based on mode"""
if self.player_mode_var.get() == "specific":
self.player_uid_entry.config(state=tk.NORMAL)
else:
self.player_uid_entry.config(state=tk.DISABLED)
self.player_uid_var.set("")
def save_config(self):
"""Save configuration to file"""
try:
# Update config object
if not self.config:
self.config = configparser.ConfigParser()
self.config.add_section('models')
self.config.add_section('profile:NewGens')
self.config.set('models', 'model_name', self.model_var.get())
if self.model_dir_var.get():
self.config.set('models', 'model_dir', self.model_dir_var.get())
self.config.set('profile:NewGens', 'football_manager_version', self.fm_version_var.get())
self.config.set('profile:NewGens', 'rtf_file', self.rtf_file_var.get())
self.config.set('profile:NewGens', 'output_dir', self.output_dir_var.get())
# Save to file
with open('user_config.cfg', 'w') as configfile:
self.config.write(configfile)
messagebox.showinfo("Success", "Configuration saved successfully!")
self.log_message("Configuration saved")
except Exception as e:
messagebox.showerror("Error", f"Failed to save configuration: {str(e)}")
self.log_message(f"Error saving configuration: {str(e)}")
def load_config(self):
"""Load configuration from file"""
try:
if os.path.exists('user_config.cfg'):
self.config = configparser.ConfigParser()
self.config.read('user_config.cfg')
# Load model settings
if 'models' in self.config:
self.model_var.set(self.config.get('models', 'model_name', fallback='SG161222/Realistic_Vision_V6.0_B1'))
self.model_dir_var.set(self.config.get('models', 'model_dir', fallback=''))
# Load FM settings
if 'profile:NewGens' in self.config:
self.fm_version_var.set(self.config.get('profile:NewGens', 'football_manager_version', fallback='2024'))
self.rtf_file_var.set(self.config.get('profile:NewGens', 'rtf_file', fallback=''))
self.output_dir_var.set(self.config.get('profile:NewGens', 'output_dir', fallback=''))
self.log_message("Configuration loaded")
else:
self.log_message("No configuration file found, using defaults")
except Exception as e:
messagebox.showerror("Error", f"Failed to load configuration: {str(e)}")
self.log_message(f"Error loading configuration: {str(e)}")
def reset_config(self):
"""Reset configuration to defaults"""
self.model_var.set('SG161222/Realistic_Vision_V6.0_B1')
self.model_dir_var.set('')
self.fm_version_var.set('2024')
self.rtf_file_var.set('')
self.output_dir_var.set('')
self.log_message("Configuration reset to defaults")
def log_message(self, message):
"""Add message to log"""
self.status_text.insert(tk.END, f"[{time.strftime('%H:%M:%S')}] {message}\n")
self.status_text.see(tk.END)
def clear_log(self):
"""Clear the log"""
self.status_text.delete(1.0, tk.END)
def start_generation(self):
"""Start the generation process"""
if not self.validate_config():
return
# Disable start button, enable stop button
self.start_button.config(state=tk.DISABLED)
self.stop_button.config(state=tk.NORMAL)
# Reset progress
self.progress_var.set(0)
self.stop_generation = False
# Start generation thread
self.generation_thread = threading.Thread(target=self.generation_worker)
self.generation_thread.daemon = True
self.generation_thread.start()
def stop_generation_thread(self):
"""Stop the generation process"""
self.stop_generation = True
self.stop_button.config(state=tk.DISABLED)
self.log_message("Stopping generation...")
def generation_worker(self):
"""Worker thread for generation process"""
try:
self.log_message("Starting generation process...")
# Load configurations
with open("app_config.json", "r") as f:
app_config = json.load(f)
# Parse RTF file
rtf_file = self.rtf.parse_rtf(self.rtf_file_var.get())
self.log_message(f"Parsed RTF file successfully. Found {len(rtf_file)} players.")
# Determine players to process
update = self.update_mode_var.get() == "true"
process_player = self.player_mode_var.get() == "specific"
if process_player:
player_uuid = int(self.player_uid_var.get())
players_to_process = [p for p in rtf_file if int(p[0]) == player_uuid]
elif update:
# Filter out already processed players
try:
values_from_config = extract_from_values(f"{self.output_dir_var.get()}/config.xml")
ids_in_b = [item for item in values_from_config]
players_to_process = [item for item in rtf_file if item[0] not in ids_in_b]
except FileNotFoundError:
players_to_process = rtf_file
else:
players_to_process = rtf_file
if len(players_to_process) == 0:
self.log_message("No players to process")
return
self.log_message(f"Processing {len(players_to_process)} players")
# Generate prompts
prompts = generate_prompts_for_players(players_to_process, app_config)
# Generate images
total_players = len(prompts)
for i, prompt in enumerate(prompts):
if self.stop_generation:
break
uid = prompt.split(":")[0]
comfy_prompt = prompt.split(":")[1]
self.log_message(f"Generating image for player {uid} ({i+1}/{total_players})")
generate_image(uid, comfy_prompt)
# Update progress
progress = (i + 1) / total_players * 100
self.progress_var.set(progress)
# Queue image for preview
self.image_queue.put(uid)
# Post-processing
if not self.stop_generation:
try:
if update:
append_to_config_xml(
self.output_dir_var.get(),
[item[0] for item in players_to_process],
self.fm_version_var.get()
)
else:
create_config_xml(
self.output_dir_var.get(),
[item[0] for item in players_to_process],
self.fm_version_var.get()
)
self.log_message("Configuration XML updated")
except Exception as e:
self.log_message(f"Post-processing failed: {e}")
self.log_message("Generation complete!")
except Exception as e:
self.log_message(f"Generation failed: {str(e)}")
import traceback
self.log_message(traceback.format_exc())
finally:
# Re-enable start button
self.start_button.config(state=tk.NORMAL)
self.stop_button.config(state=tk.DISABLED)
def validate_config(self):
"""Validate configuration before starting"""
if not self.rtf_file_var.get():
messagebox.showerror("Error", "Please select an RTF file")
return False
if not self.output_dir_var.get():
messagebox.showerror("Error", "Please select an output directory")
return False
if not os.path.exists(self.rtf_file_var.get()):
messagebox.showerror("Error", "RTF file does not exist")
return False
return True
def update_image_preview(self):
"""Update image preview periodically"""
try:
while not self.image_queue.empty():
uid = self.image_queue.get()
self.show_image(uid)
except:
pass
# Schedule next update
self.root.after(1000, self.update_image_preview)
def show_image(self, uid):
"""Show an image in the preview"""
try:
image_path = f"{self.output_dir_var.get()}/{uid}.png"
if os.path.exists(image_path):
# Load and resize image
image = Image.open(image_path)
image.thumbnail((300, 300), Image.Resampling.LANCZOS)
# Convert to PhotoImage
photo = ImageTk.PhotoImage(image)
# Update display
self.image_label.config(image=photo, text="")
self.image_label.image = photo # Keep reference
self.current_image_var.set(f"Player {uid}")
self.log_message(f"Preview updated: {uid}.png")
except Exception as e:
self.log_message(f"Failed to load image {uid}: {str(e)}")
def show_previous_image(self):
"""Show previous image"""
self.log_message("Previous image functionality not implemented yet")
def show_next_image(self):
"""Show next image"""
self.log_message("Next image functionality not implemented yet")
def refresh_preview(self):
"""Refresh the preview"""
self.log_message("Refreshing preview...")
# This would scan the output directory and show available images
def main():
"""Main function"""
root = tk.Tk()
app = FMFaceGeneratorGUI(root)
root.mainloop()
if __name__ == "__main__":
main()

214
readme.md
View File

@ -1,7 +1,9 @@
# Comfy UI NewGens
# Standalone FM NewGens
Use ComfyUI to generate NewGen images for Football Manager 2024
Generate NewGen images for Football Manager using local Stable Diffusion
**🖥️ GUI Available!** - Now includes a user-friendly graphical interface
# Intro
@ -15,31 +17,22 @@ Use ComfyUI to generate NewGen images for Football Manager 2024
These are some of the questions I think you are going to ask me, but I present to you somehting I have been working on, **Comfy FM24 NewGens**
These are some of the questions I think you are going to ask me, but I present to you something I have been working on, **Standalone FM NewGens**
# The Idea
Taking some inspiration from [fm-ai-face-generator](https://github.com/emilmirzayev/fm-ai-face-generator), but not wanting to pay for a hosted service (I already have AI _stuff_ setup on my home server) I started to rewrite chunks to make compatible with a hosted Comfy UI instance, after awhile, I had rewritten so much, that this is now a new beast in itself..
Taking inspiration from [fm-ai-face-generator](https://github.com/emilmirzayev/fm-ai-face-generator) and [NewGAN-Manager](https://github.com/franl08/NewGAN-Manager), this tool generates unique face images for Football Manager NewGens using local Stable Diffusion instead of requiring a separate ComfyUI server.
Thanks to both original projects for the inspiration!
So what does this do? Why would you want to use it? (you probably won't but personally, I like a bit more personalization from my NewGens, some I get quite attached to :) )
Also taking inspiration from [NewGAN-Manager](https://github.com/franl08/NewGAN-Manager) and reworking some of thier code for my uses.
Thanks to both!
So what does this do? Why would you want to use it? (you probably wont but personally, I like a bit more personallisation from my NewGens, some, I get quite attached to :) )
- This will create images for your NewGens, based off of information provided from the FM database, making a players image more unique to that player
- download the images to the specified output directory, all processed players image will be saved as their **uid** from the game
- remove all the background from the generated faces
- create the needed config file for FM to load the faces,
- you can then rename the generated folder and place it in your **graphics** folder as you would noramlly and voila!
- This will create images for your NewGens, based off of information provided from the FM database, making a player's image more unique to that player
- Generate images locally using Stable Diffusion (no external server required)
- Download the images to the specified output directory, all processed players images will be saved as their **uid** from the game
- Remove all the background from the generated faces
- Create the needed config file for FM to load the faces
- You can then rename the generated folder and place it in your **graphics** folder as you would normally and voila!
@ -48,33 +41,166 @@ So what does this do? Why would you want to use it? (you probably wont but perso
Things you will need that I will not be going over on how to setup.
- Python installed
- Git installed
- A ComfyUI installation (On hosted server, or [portable](https://github.com/YanWenKun/ComfyUI-Windows-Portable))
- My suggestion it to use the [Realistic Vision 6](https://civitai.com/models/4201/realistic-vision-v60-b1) model
- Python 3.8+ installed
- Git installed
- At least 4GB of RAM (8GB+ recommended for better performance)
- CUDA-compatible GPU (optional, but highly recommended for faster generation)
If you have that, then carry on for Windows instructions
- Use Git to checkout this repo
- You need to get a `rtf` file of the players you want to add images for, to do this you need the view and filter supplied with the project
- Copy the `filters` and `views` folder over to your `Football Manager 2024` data folder in `Documents`, this may create these folders, or may just add the contained files into your existing folders
- You can use `python INSTALL_VIEW_AND_FILTER.py` to do this automatically
- Included is the original `is newgen` filter created by the NewGAN-Manager team and a new view created by myself to get the needed data
- If you follow [this video](https://youtu.be/pmdIkhfmY6w?t=564) it will show you how to export the `rtf` file, you want to use our view, not the view in the video
- Once you have your `rtf` file add it to the root of the current repo
- Create a python virtual environment `python -m venv venv`
- Activate the venv `.\venv\Scripts\activate`
- Install the requirements `pip install -r requirements.txt`
- Copy the `user_config.cfg.sample` to `user_config.cfg` and make the needed changes
- football_manager_version - Version of FM to generate for. Defautls to `2024`
- output_dir - Where to save the generated set. Defaults to `./generated_images/`
- comfyui_url - HTTP location of your comfyui installation.
- model - Model to be used, by default `realisticVisionV60B1_v51HyperVAE.safetensors` is set, this is my suggested model at the moment.
- At this point you should be able to run and start to generate by running the command `python comfy_fm_newgen.py --rtf_file ExportedFile.rtf`
- ExportedFile is the name of the file that you exported and saved with your newgen list
## Setup Instructions
- Use Git to checkout this repo
- You need to get a `rtf` file of the players you want to add images for, to do this you need the view and filter supplied with the project
- Copy the `filters` and `views` folder over to your `Football Manager 2024` data folder in `Documents`, this may create these folders, or may just add the contained files into your existing folders
- You can use `python INSTALL_VIEW_AND_FILTER.py` to do this automatically
- Included is the original `is newgen` filter created by the NewGAN-Manager team and a new view created by myself to get the needed data
- If you follow [this video](https://youtu.be/pmdIkhfmY6w?t=564) it will show you how to export the `rtf` file, you want to use our view, not the view in the video
- Once you have your `rtf` file add it to the root of the current repo
- Create a python virtual environment `python -m venv venv`
- Activate the venv `.\venv\Scripts\activate` (Windows) or `source venv/bin/activate` (Linux/Mac)
- Install the requirements `pip install -r requirements.txt`
- Copy the `user_config.cfg.sample` to `user_config.cfg` and make the needed changes
- football_manager_version - Version of FM to generate for. Defaults to `2024`
- output_dir - Where to save the generated set. Defaults to `./generated_images/`
- rtf_file - Path to your exported RTF file with player data
- model_name - Hugging Face model to use (see Model Selection section below)
- model_dir - Custom directory to store models (optional)
## Usage Options
### **🖥️ GUI Mode (Recommended)**
For the best user experience, use the graphical interface:
```bash
python run_gui.py
```
**GUI Features:**
- Easy configuration with file browsers
- Real-time progress monitoring
- Live image preview
- Start/stop controls
- Comprehensive logging
### **📝 Command Line Mode**
For advanced users or automation:
```bash
python comfy_fm_newgen.py
```
**Command Line Features:**
- Fast batch processing
- Resume capability
- Detailed logging
- Script automation
## Model Selection
The tool uses Hugging Face models for image generation. You can specify which model to use in your `user_config.cfg`:
### **Recommended Models for Face Generation:**
- `SG161222/Realistic_Vision_V6.0_B1` - **Best choice** for realistic faces (default)
- `digiplay/AbsoluteReality` - Photorealistic faces and people
- `stabilityai/stable-diffusion-2-1` - General purpose, good for faces
- `runwayml/stable-diffusion-v1-5` - Classic SD 1.5, widely supported
### **Model Storage:**
- **Default**: Models are stored in Hugging Face cache (`~/.cache/huggingface/`)
- **Custom Directory**: Set `model_dir` in config to store models in a specific folder
- **Model Size**: Most face models are 2-5GB, ensure you have sufficient disk space
- **First Run**: Model downloads automatically when you first run the tool
### **Changing Models:**
1. Edit `model_name` in your `user_config.cfg`
2. Delete the old model from your cache/directory if desired
3. Restart the tool - it will download the new model automatically
## System Requirements
- **CPU Mode**: Requires at least 8GB RAM, expect 2-5 minutes per image
- **GPU Mode**: Requires CUDA-compatible GPU with at least 4GB VRAM, expect 10-30 seconds per image
- First run will download the Stable Diffusion model (~5GB), so ensure you have sufficient disk space
## Features
### **Core Features**
- **Local Generation**: No external servers or API keys required
- **Model Selection**: Choose from various face generation models via configuration
- **Automatic Processing**: Batch process multiple players from your RTF file
- **Background Removal**: Automatically removes backgrounds from generated faces
- **XML Configuration**: Generates proper Football Manager configuration files
- **Resume Support**: Can resume from previous runs without regenerating existing images
- **Model Caching**: Downloads and caches models locally for faster subsequent runs
### **🖥️ GUI Features**
- **User-Friendly Interface**: Modern tabbed interface with intuitive controls
- **File Browsers**: Easy selection of RTF files and output directories
- **Real-Time Progress**: Live progress bars and status updates
- **Image Preview**: View generated images as they're created
- **Configuration Management**: Save and load different configurations
- **Error Handling**: Clear error messages and troubleshooting tips
- **Multi-threaded**: Non-blocking interface during generation
## GUI Troubleshooting
### **Common Issues:**
**GUI won't start:**
- Ensure Python 3.8+ is installed
- Install requirements: `pip install -r requirements.txt`
- Check for missing dependencies: `python -c "import tkinter"`
**Dependency installation fails:**
- Try installing packages individually: `pip install torch torchvision diffusers transformers`
- For Python 3.11+, use: `pip install rembg==2.0.59` (instead of 2.0.60)
- If `striprtf` fails, try: `pip install striprtf==0.0.28`
- Use alternative requirements: `pip install -r requirements-gui.txt` for GUI-only
**Alternative installation methods:**
- **Conda**: `conda install pytorch torchvision torchaudio cpuonly -c pytorch`
- **GPU Support**: Replace `cpuonly` with `cudatoolkit=11.8` for CUDA support
- **Individual packages**: Install problematic packages one by one to identify issues
**Model download fails:**
- Check internet connection
- Verify disk space (models are 2-5GB)
- Try a different model from the recommended list
**Images not appearing in preview:**
- Check output directory permissions
- Ensure images are being generated successfully
- Try refreshing the preview tab
**Configuration not saving:**
- Check file permissions in the project directory
- Ensure no other instances are running
- Try running as administrator
### **Performance Tips:**
- **First run** takes longer due to model download
- **Close other applications** during generation for better performance
- **Use SSD storage** for faster model loading
- **Monitor system resources** - generation is CPU/GPU intensive
## Command Line Usage
For advanced users or automation, you can still use the original command-line interface:
```bash
python comfy_fm_newgen.py
```
The GUI and command-line versions share the same configuration files and generated data.
---
You should get some console output of the progress, good luck!
Open an issue here if your having problems
Open an issue here if you're having problems
Thanks

4
requirements-gui.txt Normal file
View File

@ -0,0 +1,4 @@
# Alternative requirements for GUI-only usage (without AI generation)
# Use this if you only want to run the GUI interface
tkinterdnd2==0.3.0
Pillow==10.4.0

Binary file not shown.

43
run_gui.py Normal file
View File

@ -0,0 +1,43 @@
#!/usr/bin/env python3
"""
FM Face Generator GUI Launcher
Simple launcher script for the GUI interface
"""
import sys
import os
def main():
"""Launch the GUI application"""
try:
# Add current directory to path for imports
current_dir = os.path.dirname(os.path.abspath(__file__))
if current_dir not in sys.path:
sys.path.insert(0, current_dir)
# Import and run the GUI
from gui import main as gui_main
print("Starting FM Face Generator GUI...")
print("If you encounter any import errors, make sure to install requirements:")
print("pip install -r requirements.txt")
print()
gui_main()
except ImportError as e:
print(f"Import Error: {e}")
print("\nPlease install the required dependencies:")
print("pip install -r requirements.txt")
sys.exit(1)
except Exception as e:
print(f"Error starting GUI: {e}")
print("\nTroubleshooting:")
print("1. Make sure Python 3.8+ is installed")
print("2. Install requirements: pip install -r requirements.txt")
print("3. Check that all dependencies are available")
sys.exit(1)
if __name__ == "__main__":
main()

View File

@ -1,8 +1,16 @@
[comfyui]
comfyui_url =
model = realisticVisionV60B1_v51HyperVAE.safetensors
[profile:NewGens]
football_manager_version = 2024
rtf_file = ./NewGen.rtf
output_dir = ./NewGens/
[models]
# Hugging Face model repository (format: username/model-name)
# Popular face generation models:
# SG161222/Realistic_Vision_V6.0_B1 - Realistic faces (recommended)
# stabilityai/stable-diffusion-2-1 - General purpose
# runwayml/stable-diffusion-v1-5 - Classic SD 1.5
# digiplay/AbsoluteReality - Photorealistic
model_name = SG161222/Realistic_Vision_V6.0_B1
# Model storage directory (optional - defaults to Hugging Face cache)
# model_dir = ./models/