Skip to content

Instantly share code, notes, and snippets.

@Goatghosts
Last active July 16, 2025 21:03
Show Gist options
  • Save Goatghosts/d5d8e9dc1373eb29b3a7a4580b3a9d48 to your computer and use it in GitHub Desktop.
Save Goatghosts/d5d8e9dc1373eb29b3a7a4580b3a9d48 to your computer and use it in GitHub Desktop.
Простой помощник для быстрого создания промптов из содержимого каталога.
import os
import pickle
import threading
import tkinter as tk
from tkinter import filedialog, scrolledtext, messagebox
import logging
CONFIG_FILE = os.path.join(os.path.dirname(__file__), ".prompt_gui.pkl")
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s]: %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)
logger = logging.getLogger("prompt_gui")
def load_cfg():
if os.path.exists(CONFIG_FILE):
with open(CONFIG_FILE, "rb") as f:
cfg = pickle.load(f)
logger.info(f"Загружена конфигурация: {cfg}")
return cfg
cfg = {"dir": "", "exts": [".ts", ".svelte"], "bl": []}
logger.info(f"Создана новая конфигурация: {cfg}")
return cfg
def save_cfg(cfg):
with open(CONFIG_FILE, "wb") as f:
pickle.dump(cfg, f)
logger.info(f"Конфигурация сохранена: {cfg}")
def generate_prompt(path, exts, bl):
output = []
bl_set = set(bl)
count_files = 0
for root, dirs, files in os.walk(path):
parts = set(os.path.relpath(root, path).replace("\\", "/").split("/"))
if parts & bl_set:
continue
for file in files:
if any(file.endswith(ext) for ext in exts):
count_files += 1
full_path = os.path.abspath(os.path.join(root, file)).replace("\\", "/")
output.append(full_path)
output.append("```")
try:
with open(full_path, encoding="utf-8") as f:
for line in f:
if not line.lstrip().startswith("//"):
output.append(line.rstrip("\n"))
except Exception as e:
logger.error(f"Ошибка чтения {full_path}: {e}")
output.append("```")
output.append("")
result = "\n".join(output)
logger.info(f"Сгенерировано файлов: {count_files}, длина текста: {len(result)} символов")
return result
class App:
def __init__(self, root):
self.root = root
root.title("Prompt Builder")
root.geometry("950x600")
logger.info("Запуск приложения")
self.cfg = load_cfg()
tk.Label(root, text="Директория проекта:").pack(anchor="w", padx=5)
self.dir_var = tk.StringVar(value=self.cfg["dir"])
dir_frm = tk.Frame(root)
dir_frm.pack(fill="x", padx=5, pady=2)
tk.Entry(dir_frm, textvariable=self.dir_var).pack(side="left", fill="x", expand=True)
tk.Button(dir_frm, text="📁", command=self.choose_dir).pack(side="left", padx=2)
main_frm = tk.Frame(root)
main_frm.pack(fill="both", expand=True, padx=5, pady=5)
self.exts = self.create_column(main_frm, "Типы файлов", self.cfg["exts"])
self.bl = self.create_column(main_frm, "Чёрный список путей", self.cfg["bl"])
self.text = scrolledtext.ScrolledText(main_frm, wrap="none")
self.text.grid(row=0, column=2, sticky="nsew", rowspan=2, padx=(5, 0))
main_frm.columnconfigure(2, weight=3)
main_frm.rowconfigure(0, weight=1)
btn_frm = tk.Frame(root)
btn_frm.pack(fill="x", padx=5, pady=5)
tk.Button(btn_frm, text="Сгенерировать", command=self.generate).pack(side="left", expand=True, fill="x")
tk.Button(btn_frm, text="Копировать", command=self.copy).pack(side="left", expand=True, fill="x")
self.dir_var.trace_add("write", self.autosave)
def create_column(self, parent, title, items):
frm = tk.Frame(parent)
frm.grid(sticky="nswe", padx=2)
parent.columnconfigure(parent.grid_size()[0] - 1, weight=1)
tk.Label(frm, text=title).pack(anchor="w")
list_frm = tk.Frame(frm)
list_frm.pack(fill="both", expand=True)
lb = tk.Listbox(list_frm)
lb.pack(side="left", fill="both", expand=True)
sb = tk.Scrollbar(list_frm, command=lb.yview)
sb.pack(side="right", fill="y")
lb.config(yscrollcommand=sb.set)
for i in items:
lb.insert("end", i)
entry_frm = tk.Frame(frm)
entry_frm.pack(fill="x")
entry = tk.Entry(entry_frm)
entry.pack(side="left", fill="x", expand=True)
tk.Button(entry_frm, text="➕", command=lambda: self.add_item(lb, entry)).pack(side="left")
tk.Button(frm, text="❌ Удалить выбранное", command=lambda: self.del_item(lb)).pack(fill="x", pady=2)
lb.bind("<<ListboxSelect>>", lambda e: self.autosave())
return lb
def add_item(self, lb, entry):
txt = entry.get().strip()
if txt:
if lb == self.exts and not txt.startswith("."):
txt = "." + txt
lb.insert("end", txt)
entry.delete(0, "end")
logger.info(f"Добавлен элемент: {txt}")
self.autosave()
def del_item(self, lb):
sel = lb.curselection()
if sel:
txt = lb.get(sel[0])
lb.delete(sel[0])
logger.info(f"Удалён элемент: {txt}")
self.autosave()
def choose_dir(self):
p = filedialog.askdirectory()
if p:
self.dir_var.set(p)
logger.info(f"Выбрана директория: {p}")
def generate(self):
path = self.dir_var.get()
exts = self.exts.get(0, "end")
bl = self.bl.get(0, "end")
if not path or not os.path.isdir(path):
messagebox.showwarning("Ошибка", "Укажите корректный путь")
logger.warning("Попытка генерации с некорректным путём")
return
self.text.delete("1.0", "end")
logger.info(f"Запуск генерации для {path}, расширения: {exts}, blacklist: {bl}")
threading.Thread(target=self.worker, args=(path, exts, bl), daemon=True).start()
def worker(self, p, e, bl):
result = generate_prompt(p, e, bl)
self.text.after(0, lambda: self.text.insert("end", result))
logger.info("Генерация завершена успешно")
def copy(self):
txt = self.text.get("1.0", "end")
self.root.clipboard_clear()
self.root.clipboard_append(txt)
logger.info(f"Скопировано {len(txt.strip())} символов")
def autosave(self, *a):
self.cfg["dir"] = self.dir_var.get()
self.cfg["exts"] = self.exts.get(0, "end")
self.cfg["bl"] = self.bl.get(0, "end")
save_cfg(self.cfg)
if __name__ == "__main__":
root = tk.Tk()
App(root)
root.mainloop()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment