Hi guys,
After a while not posting, now I’ve found more time to be active once again. I’ve been working closely on image generation with Flux1. So I’ve been doing some productivity scripts that will help me on this.
So I came up with the idea of comparing ChatGPT5, latest OpenAI model, with Claude’s Sonnet4. It is a very simple script. This is the prompt I used:
Prompt: Create a python script with a tkinter GUI that obtains multiple txt (positive) prompt files that include a prompt text. Process all text and create a new .txt in the following format (as an example, below) you have the “——-” as a marker between prompt files. Negative prompts will go blank unless specified in a separate text box in the GUI :
positive: candid street photo of carl0s, a young man walking through a rainy Tokyo street at night, neon reflections on wet pavement, cinematic mood, 35mm lens
negative: lowres, bad, bad anatomy, bad hands, extra digits
———————–
positive: carl0s, a young man wearing a tailored black tuxedo, standing at a gala event, champagne in hand, dramatic lighting, high-resolution professional photography negative: lowres, bad, bad anatomy, bad hands, extra digits
———————–
positive: close-up portrait of carl0s, a young man in natural sunlight, freckles and skin texture visible, 85mm lens, bokeh background, hyperrealistic detail
negative: lowres, bad, bad anatomy, bad hands, extra digits
This was the code written by ChatGPT5:
import tkinter as tk
from tkinter import filedialog, messagebox
from tkinter import ttk
import os
import sys
SEPARATOR_LINE = "-----------------------" # exactly as requested
class PromptBatcher(tk.Tk):
def __init__(self):
super().__init__()
self.title("Prompt Batcher — Positive/Negative Formatter")
self.geometry("760x520")
self.minsize(720, 480)
# State
self.selected_files = []
self.output_path = tk.StringVar(value="")
self.collapse_newlines = tk.BooleanVar(value=True)
# UI
self.create_widgets()
def create_widgets(self):
# Top controls (file actions)
top_frame = ttk.Frame(self, padding=(10, 10, 10, 0))
top_frame.pack(fill="x")
ttk.Label(top_frame, text="Selected positive prompt files:").grid(row=0, column=0, sticky="w")
btn_frame = ttk.Frame(top_frame)
btn_frame.grid(row=0, column=1, sticky="e")
ttk.Button(btn_frame, text="Add Files…", command=self.add_files).grid(row=0, column=0, padx=(0, 5))
ttk.Button(btn_frame, text="Remove Selected", command=self.remove_selected).grid(row=0, column=1, padx=(0, 5))
ttk.Button(btn_frame, text="Clear List", command=self.clear_list).grid(row=0, column=2)
# Listbox for files
list_frame = ttk.Frame(self, padding=10)
list_frame.pack(fill="both", expand=True)
self.file_list = tk.Listbox(list_frame, selectmode=tk.EXTENDED, activestyle="dotbox")
self.file_list_scroll = ttk.Scrollbar(list_frame, orient="vertical", command=self.file_list.yview)
self.file_list.config(yscrollcommand=self.file_list_scroll.set)
self.file_list.pack(side="left", fill="both", expand=True)
self.file_list_scroll.pack(side="right", fill="y")
# Middle: Negative prompt and options
middle = ttk.LabelFrame(self, text="Negative prompt (optional — leave blank for empty)", padding=10)
middle.pack(fill="x", padx=10, pady=(0, 10))
self.negative_entry = tk.Text(middle, height=4, wrap="word")
self.negative_entry.pack(fill="x")
opts = ttk.Frame(self, padding=(10, 0, 10, 10))
opts.pack(fill="x")
ttk.Checkbutton(opts, text="Collapse newlines inside each positive prompt into spaces",
variable=self.collapse_newlines).pack(side="left")
# Output path chooser
out_frame = ttk.Frame(self, padding=(10, 0, 10, 10))
out_frame.pack(fill="x")
ttk.Label(out_frame, text="Output file:").pack(side="left")
self.out_entry = ttk.Entry(out_frame, textvariable=self.output_path)
self.out_entry.pack(side="left", fill="x", expand=True, padx=6)
ttk.Button(out_frame, text="Save As…", command=self.choose_output).pack(side="left")
# Generate button
action_frame = ttk.Frame(self, padding=(10, 0, 10, 10))
action_frame.pack(fill="x")
ttk.Button(action_frame, text="Generate Combined .txt", command=self.generate_output).pack(side="right")
# Status
self.status = tk.StringVar(value="Ready.")
status_bar = ttk.Label(self, textvariable=self.status, anchor="w", relief="sunken")
status_bar.pack(fill="x", side="bottom")
# Styling (optional nicer padding)
for child in top_frame.winfo_children():
child.grid_configure(pady=4)
self.bind_shortcuts()
def bind_shortcuts(self):
self.bind("<Control-o>", lambda e: self.add_files())
self.bind("<Control-s>", lambda e: self.choose_output())
self.bind("<F5>", lambda e: self.generate_output())
self.bind("<Delete>", lambda e: self.remove_selected())
def add_files(self):
paths = filedialog.askopenfilenames(
title="Choose positive prompt .txt files",
filetypes=[("Text files", "*.txt"), ("All files", "*.*")]
)
if not paths:
return
added = 0
for p in paths:
p = os.path.abspath(p)
if p not in self.selected_files and os.path.isfile(p):
self.selected_files.append(p)
self.file_list.insert("end", p)
added += 1
self.set_status(f"Added {added} file(s). Total: {len(self.selected_files)}")
def remove_selected(self):
sel = list(self.file_list.curselection())
if not sel:
self.set_status("No selection to remove.")
return
# Remove from bottom to top to keep indices valid
for idx in reversed(sel):
path = self.file_list.get(idx)
self.file_list.delete(idx)
try:
self.selected_files.remove(path)
except ValueError:
pass
self.set_status(f"Removed {len(sel)} file(s). Total: {len(self.selected_files)}")
def clear_list(self):
self.file_list.delete(0, "end")
self.selected_files.clear()
self.set_status("List cleared.")
def choose_output(self):
default_name = "combined_prompts.txt"
path = filedialog.asksaveasfilename(
title="Save output as",
defaultextension=".txt",
initialfile=default_name,
filetypes=[("Text files", "*.txt"), ("All files", "*.*")]
)
if path:
self.output_path.set(path)
self.set_status(f"Output set to: {path}")
def generate_output(self):
if not self.selected_files:
messagebox.showwarning("No files", "Please add at least one positive prompt file.")
return
out_path = self.output_path.get().strip()
if not out_path:
# If no explicit path, suggest a default next to first file
first_dir = os.path.dirname(self.selected_files[0]) if self.selected_files else os.getcwd()
out_path = os.path.join(first_dir, "combined_prompts.txt")
self.output_path.set(out_path)
neg_text = self.negative_entry.get("1.0", "end").strip()
try:
blocks = []
for fpath in self.selected_files:
with open(fpath, "r", encoding="utf-8", errors="replace") as fh:
content = fh.read().strip()
if self.collapse_newlines.get():
# turn any internal newlines/tabs into single spaces
one_line = " ".join(content.split())
else:
# preserve internal newlines exactly
one_line = content
# Build the block
block_lines = []
block_lines.append(f"positive: {one_line}")
# Negative: blank unless provided
if neg_text:
block_lines.append(f"negative: {neg_text}")
else:
block_lines.append("negative:")
blocks.append("\n".join(block_lines))
final_text = f"\n{SEPARATOR_LINE}\n".join(blocks) + "\n"
# Ensure directory exists
os.makedirs(os.path.dirname(out_path) or ".", exist_ok=True)
with open(out_path, "w", encoding="utf-8", errors="ignore") as out:
out.write(final_text)
self.set_status(f"Done. Wrote {len(blocks)} block(s) to: {out_path}")
messagebox.showinfo("Success", f"Generated file:\n{out_path}")
except Exception as e:
self.set_status("Error during generation.")
messagebox.showerror("Error", f"Something went wrong:\n{e}")
def set_status(self, msg):
self.status.set(msg)
def main():
# High-DPI scaling on Windows for sharper UI
if sys.platform.startswith("win"):
try:
import ctypes
ctypes.windll.shcore.SetProcessDpiAwareness(1) # SYSTEM_AWARE
except Exception:
pass
app = PromptBatcher()
app.mainloop()
if __name__ == "__main__":
main()
And this is the result:

After a few tests, it worked like a charm.
Noe let’s see what’s the result for the same prompt on Claude:
This was the code written by Sonnet 4:
import tkinter as tk
from tkinter import ttk, filedialog, messagebox, scrolledtext
import os
class PromptProcessor:
def __init__(self, root):
self.root = root
self.root.title("Prompt File Processor")
self.root.geometry("800x600")
# Store selected files
self.selected_files = []
# Create main frame
main_frame = ttk.Frame(root, padding="10")
main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
# Configure grid weights
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
main_frame.columnconfigure(1, weight=1)
main_frame.rowconfigure(2, weight=1)
# File selection section
ttk.Label(main_frame, text="Select Positive Prompt Files:", font=("Arial", 12, "bold")).grid(
row=0, column=0, columnspan=2, sticky=tk.W, pady=(0, 5)
)
file_frame = ttk.Frame(main_frame)
file_frame.grid(row=1, column=0, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=(0, 10))
file_frame.columnconfigure(0, weight=1)
ttk.Button(file_frame, text="Browse Files", command=self.browse_files).grid(
row=0, column=0, sticky=tk.W, padx=(0, 10)
)
ttk.Button(file_frame, text="Clear Selection", command=self.clear_files).grid(
row=0, column=1, sticky=tk.W
)
# File list display
self.file_listbox = tk.Listbox(file_frame, height=6)
self.file_listbox.grid(row=1, column=0, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=(5, 0))
# Scrollbar for file list
file_scrollbar = ttk.Scrollbar(file_frame, orient="vertical", command=self.file_listbox.yview)
file_scrollbar.grid(row=1, column=2, sticky=(tk.N, tk.S), pady=(5, 0))
self.file_listbox.configure(yscrollcommand=file_scrollbar.set)
# Negative prompt section
ttk.Label(main_frame, text="Negative Prompt (optional):", font=("Arial", 12, "bold")).grid(
row=2, column=0, sticky=(tk.W, tk.N), pady=(10, 5)
)
# Text area for negative prompt
self.negative_text = scrolledtext.ScrolledText(main_frame, height=4, width=60)
self.negative_text.grid(row=3, column=0, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=(0, 10))
# Default negative prompt
default_negative = "lowres, bad, bad anatomy, bad hands, extra digits"
self.negative_text.insert("1.0", default_negative)
# Process button
process_frame = ttk.Frame(main_frame)
process_frame.grid(row=4, column=0, columnspan=2, pady=(10, 0))
ttk.Button(process_frame, text="Process Files", command=self.process_files,
style="Accent.TButton").pack(side=tk.LEFT, padx=(0, 10))
ttk.Button(process_frame, text="Save Output", command=self.save_output).pack(side=tk.LEFT)
# Output preview section
ttk.Label(main_frame, text="Output Preview:", font=("Arial", 12, "bold")).grid(
row=5, column=0, sticky=(tk.W, tk.N), pady=(20, 5)
)
# Output text area
self.output_text = scrolledtext.ScrolledText(main_frame, height=15, width=80, state=tk.DISABLED)
self.output_text.grid(row=6, column=0, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=(0, 10))
# Configure grid weights for resizing
main_frame.rowconfigure(6, weight=1)
# Status bar
self.status_var = tk.StringVar()
self.status_var.set("Ready - Select prompt files to begin")
status_bar = ttk.Label(main_frame, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W)
status_bar.grid(row=7, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=(5, 0))
# Store processed output
self.processed_output = ""
def browse_files(self):
"""Open file dialog to select multiple txt files"""
files = filedialog.askopenfilenames(
title="Select Positive Prompt Files",
filetypes=[("Text files", "*.txt"), ("All files", "*.*")]
)
if files:
self.selected_files = list(files)
self.update_file_list()
self.status_var.set(f"Selected {len(self.selected_files)} file(s)")
def clear_files(self):
"""Clear the selected files"""
self.selected_files = []
self.update_file_list()
self.status_var.set("Files cleared - Select new files")
def update_file_list(self):
"""Update the file listbox display"""
self.file_listbox.delete(0, tk.END)
for file_path in self.selected_files:
filename = os.path.basename(file_path)
self.file_listbox.insert(tk.END, filename)
def process_files(self):
"""Process the selected files and generate formatted output"""
if not self.selected_files:
messagebox.showwarning("No Files", "Please select at least one prompt file first.")
return
try:
# Get negative prompt text
negative_prompt = self.negative_text.get("1.0", tk.END).strip()
# Process each file
output_lines = []
for i, file_path in enumerate(self.selected_files):
try:
# Read the file content
with open(file_path, 'r', encoding='utf-8') as f:
positive_content = f.read().strip()
# Skip empty files
if not positive_content:
continue
# Add positive prompt line
output_lines.append(f"positive: {positive_content}")
# Add negative prompt line
if negative_prompt:
output_lines.append(f"negative: {negative_prompt}")
else:
output_lines.append("negative: ")
# Add separator (except for the last file)
if i < len(self.selected_files) - 1:
output_lines.append("-" * 23)
except Exception as e:
messagebox.showerror("File Error", f"Error reading file {os.path.basename(file_path)}: {str(e)}")
return
# Join all lines
self.processed_output = "\n".join(output_lines)
# Display in output text area
self.output_text.config(state=tk.NORMAL)
self.output_text.delete("1.0", tk.END)
self.output_text.insert("1.0", self.processed_output)
self.output_text.config(state=tk.DISABLED)
self.status_var.set(f"Successfully processed {len(self.selected_files)} file(s)")
except Exception as e:
messagebox.showerror("Processing Error", f"An error occurred while processing: {str(e)}")
def save_output(self):
"""Save the processed output to a new file"""
if not self.processed_output:
messagebox.showwarning("No Output", "Please process files first before saving.")
return
# Ask user where to save
save_path = filedialog.asksaveasfilename(
title="Save Processed Output",
defaultextension=".txt",
filetypes=[("Text files", "*.txt"), ("All files", "*.*")]
)
if save_path:
try:
with open(save_path, 'w', encoding='utf-8') as f:
f.write(self.processed_output)
messagebox.showinfo("Success", f"Output saved successfully to:\n{save_path}")
self.status_var.set(f"Output saved to {os.path.basename(save_path)}")
except Exception as e:
messagebox.showerror("Save Error", f"Error saving file: {str(e)}")
def main():
root = tk.Tk()
app = PromptProcessor(root)
root.mainloop()
if __name__ == "__main__":
main()
And this is the result:

As you can see, GUI’s window is fairly similar. Results were also positive.
So for this simple script, both of them work flawlessly!
However, where I appreciate an edge on favor of ChatGPT over Sonnet is other areas beside coding (where Claude might be slightly better). For instance, ChatGPT offer image generation (with many limitations compared to other Stable Diffusion models), whereas Claude does’t offer this. Claude offers Claude Code, it’s agentic solution, which came out months before ChatGPT5’s agentic solution. However, I feel like ChatGPT is smart on everyday usage for the average public, and its response is usually faster. So at similar prices, I’d definitely pick ChatGPT over Claude as a basic/intermediate user.







бонуси казіно казіно з бонусами
321chat not working 321 sexchat
HondroLife para qué sirve: alivio articular natural y efectivo.
sintomas artrosis rodilla
Votre guide parifoot rdc: picks quotidiens, cotes comparees, tickets securises, gestion de mise, cash-out et promos. Depots via mobile money, retraits rapides, support francophone. LINAFOOT, CAF, ligues europeennes. Pariez avec moderation.