Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
- Saves and loads user settings to/from a JSON file
- Option to format output as Markdown with code blocks, headings, and file separators
- Switch between dark and light mode, con pulsanti e campi scuri quando il tema è impostato su "dark"
- Supports chunked export quando il totale supera il limite di token impostato
- Possibilità di esportare anche in JSON strutturato

## Requirements

Expand Down Expand Up @@ -50,6 +52,7 @@ Il file `promptpack.py` avvia semplicemente l'applicazione.
- Markdown output
- Include file headings
- Use code blocks for each file
- Export JSON
4. **Live Preview**: Enables a real-time preview of the final output file.
5. **Destination Folder**: Choose where the final file will be saved.
6. **Generate**: Creates a Markdown or plain text file containing the selected source files, formatted according to your settings.
Expand All @@ -65,7 +68,8 @@ User preferences are saved in a file named `promptpack_settings.json` in the sam
"excluded_files": [".env", "README.md"],
"as_markdown": true,
"include_heading": true,
"use_code_block": true
"use_code_block": true,
"export_json": false
}
```

Expand Down Expand Up @@ -97,7 +101,7 @@ body {
- Hidden folders and ignored files are shown but deselected by default.
- All preview and configuration windows inherit the custom icon (`promptpack.ico`), if available.
- La finestra "Select Files to Include" adotta uno sfondo scuro quando è attivo il tema dark.
- Per evitare rallentamenti, l'anteprima e l'esportazione interrompono la raccolta dei contenuti al raggiungimento di 200 000 token.
- Per evitare rallentamenti, l'anteprima interrompe la raccolta dei contenuti al raggiungimento di 200 000 token. L'esportazione divide automaticamente l'output in più file quando viene superata questa soglia.

## License

Expand Down
13 changes: 10 additions & 3 deletions promptpack/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def __init__(self, root: tk.Tk):
self.include_heading = tk.BooleanVar(value=self.settings["include_heading"])
self.use_code_block = tk.BooleanVar(value=self.settings["use_code_block"])
self.theme = tk.StringVar(value=self.settings.get("theme", "dark"))
self.export_json = tk.BooleanVar(value=self.settings.get("export_json", False))
self.enable_preview = tk.BooleanVar(value=False)

self.start_folder = tk.StringVar()
Expand Down Expand Up @@ -238,6 +239,7 @@ def prompt_list(title, key):
ttk.Checkbutton(win, text="Markdown Format", variable=self.as_markdown).pack(pady=5)
ttk.Checkbutton(win, text="Include File Headings", variable=self.include_heading).pack(pady=5)
ttk.Checkbutton(win, text="Use Code Blocks", variable=self.use_code_block).pack(pady=5)
ttk.Checkbutton(win, text="Export JSON", variable=self.export_json).pack(pady=5)


ttk.Label(win, text="Theme", style="Heading.TLabel").pack(padx=10, pady=(20, 5))
Expand All @@ -250,6 +252,7 @@ def save_and_close():
"as_markdown": self.as_markdown.get(),
"include_heading": self.include_heading.get(),
"use_code_block": self.use_code_block.get(),
"export_json": self.export_json.get(),
"theme": self.theme.get(),
}
save_settings(new_settings)
Expand Down Expand Up @@ -457,7 +460,9 @@ def get_preview_text(self, included_files):
preview_lines = self.generate_preview_lines(self.start_folder.get(), included_files)
full_text = "\n".join(preview_lines)
token_count = estimate_token_count(full_text)
header = f"Token estimate: {token_count}\n{'='*40}\n"
max_tokens = self.settings.get("max_tokens", 200000)
remaining = max_tokens - token_count
header = f"Token estimate: {token_count} | Remaining: {remaining}\n{'='*40}\n"
return header + full_text

def generate_preview_lines(self, start_folder, included_files):
Expand Down Expand Up @@ -503,15 +508,17 @@ def generate(self):
messagebox.showerror("Error", "No files selected")
return
try:
output_path = generate_output(
output_files = generate_output(
self.start_folder.get(),
self.dest_folder.get(),
list(self.selected_files),
self.as_markdown.get(),
self.include_heading.get(),
self.use_code_block.get(),
self.settings.get("max_tokens", 200000),
self.export_json.get(),
)
messagebox.showinfo("Done", f"File generated: {output_path}")
msg = "\n".join(str(p) for p in output_files)
messagebox.showinfo("Done", f"File generated:\n{msg}")
except Exception as e:
messagebox.showerror("Error", str(e))
1 change: 1 addition & 0 deletions promptpack/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"theme": "dark",
# Numero massimo di token da elaborare in anteprima o export
"max_tokens": 200_000,
"export_json": False,
}


Expand Down
33 changes: 29 additions & 4 deletions promptpack/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
import json
from pathlib import Path
from datetime import datetime
from tempfile import NamedTemporaryFile
Expand Down Expand Up @@ -36,13 +37,27 @@ def generate_output(
include_heading: bool,
use_code_block: bool,
max_tokens: int = 200000,
export_json: bool = False,
):
lines = []
json_files = []
project_name = Path(start_folder).name
date_str = datetime.now().strftime('%Y%m%d')
header = f"Project: {project_name} - {date_str}\n\n"
lines.append(header)
token_count = estimate_token_count(header)
chunk_index = 1
output_paths = []

def write_chunk(data, index):
ext = 'md' if as_markdown else 'txt'
suffix = f"-{index}" if index > 1 else ""
out_path = Path(dest_folder) / f"{project_name}-{date_str}{suffix}.{ext}"
out_path.write_text(''.join(data), encoding='utf-8')
output_paths.append(out_path)
return [header]

json_entries = []

for path in included_files:
try:
Expand All @@ -61,11 +76,21 @@ def generate_output(
block = ''.join(new_lines)
block_tokens = estimate_token_count(block)
if token_count + block_tokens > max_tokens:
break
lines = write_chunk(lines, chunk_index)
chunk_index += 1
token_count = estimate_token_count(header)
lines.append(block)
token_count += block_tokens
json_entries.append({"path": str(rel_path), "content": content})

if lines:
write_chunk(lines, chunk_index)

if export_json:
json_path = Path(dest_folder) / f"{project_name}-{date_str}.json"
with open(json_path, "w", encoding="utf-8") as f:
json.dump({"project": project_name, "date": date_str, "files": json_entries}, f, indent=2)
output_paths.append(json_path)

output_file = Path(dest_folder) / f"{project_name}-{date_str}.{ 'md' if as_markdown else 'txt' }"
output_file.write_text(''.join(lines), encoding='utf-8')
return output_file
return output_paths