mirror of
https://github.com/PR0M3TH3AN/RePrompt.git
synced 2025-09-08 06:58:42 +00:00
272 lines
9.4 KiB
Python
272 lines
9.4 KiB
Python
import streamlit as st
|
|
from pathlib import Path
|
|
import os
|
|
import yaml
|
|
from tkinter import Tk
|
|
from tkinter.filedialog import askdirectory
|
|
import subprocess
|
|
import sys
|
|
import pyperclip
|
|
|
|
# Initialize session state variables
|
|
if 'copied' not in st.session_state:
|
|
st.session_state.copied = False
|
|
|
|
# Configuration
|
|
CONFIG_FILE = "config.yaml"
|
|
SCRIPT_DIR = Path(__file__).parent
|
|
|
|
# Default exclusions
|
|
DEFAULT_EXCLUDED_DIRS = ["node_modules", "venv", "__pycache__", ".git", "logs", ".idea", ".vscode"]
|
|
DEFAULT_EXCLUDED_FILES = [
|
|
"repo-context.txt",
|
|
"package-lock.json",
|
|
"yarn.lock",
|
|
".gitattributes",
|
|
".gitignore",
|
|
".dockerignore",
|
|
"*.pem",
|
|
"*.crt",
|
|
"*.key",
|
|
".eslintrc",
|
|
".prettierrc",
|
|
".browserslistrc",
|
|
".editorconfig",
|
|
"client.crt",
|
|
"client-key.pem"
|
|
]
|
|
|
|
# Load saved configuration from repository directory
|
|
def load_saved_config(repo_path):
|
|
saved_config_path = repo_path / "saved_config.yaml"
|
|
try:
|
|
if saved_config_path.exists():
|
|
with open(saved_config_path, "r") as f:
|
|
saved_config = yaml.safe_load(f)
|
|
return saved_config if saved_config else {}
|
|
return {}
|
|
except Exception:
|
|
return {}
|
|
|
|
# Save configuration to repository directory
|
|
def save_config(config, repo_path):
|
|
try:
|
|
if not config: # Don't save empty configs
|
|
return
|
|
saved_config_path = repo_path / "saved_config.yaml"
|
|
with open(saved_config_path, "w") as f:
|
|
yaml.dump(config, f, default_flow_style=False)
|
|
except Exception:
|
|
pass
|
|
|
|
# Load application configuration
|
|
def load_config():
|
|
config_path = SCRIPT_DIR / CONFIG_FILE
|
|
if not config_path.exists():
|
|
st.error(f"Configuration file {CONFIG_FILE} not found.")
|
|
st.stop()
|
|
try:
|
|
with open(config_path, "r") as f:
|
|
return yaml.safe_load(f)
|
|
except yaml.YAMLError as e:
|
|
st.error(f"Error parsing configuration file: {e}")
|
|
st.stop()
|
|
|
|
# Clear config.yaml
|
|
def clear_config():
|
|
config_path = SCRIPT_DIR / CONFIG_FILE
|
|
with open(config_path, "w") as f:
|
|
yaml.dump({}, f)
|
|
|
|
app_config = load_config()
|
|
exclude_dirs = app_config.get("exclude_dirs", DEFAULT_EXCLUDED_DIRS)
|
|
|
|
# Initialize session state for selected_repo_path if not present
|
|
if "selected_repo_path" not in st.session_state:
|
|
st.session_state["selected_repo_path"] = None
|
|
|
|
# Streamlit App
|
|
st.title("RePrompt: A Context Generator")
|
|
|
|
# Folder Selection
|
|
st.sidebar.header("Select a Folder")
|
|
|
|
def select_folder():
|
|
try:
|
|
root = Tk()
|
|
root.withdraw() # Hide the main window
|
|
root.wm_attributes('-topmost', True) # Keep on top
|
|
folder_path = askdirectory(parent=root) # Specify parent window
|
|
if folder_path:
|
|
st.session_state["selected_repo_path"] = folder_path
|
|
return True
|
|
return False
|
|
except Exception as e:
|
|
st.error(f"Error selecting folder: {str(e)}")
|
|
return False
|
|
finally:
|
|
try:
|
|
root.destroy() # Ensure window is destroyed
|
|
except:
|
|
pass # Ignore any errors during cleanup
|
|
|
|
if st.sidebar.button("Choose Folder"):
|
|
if select_folder():
|
|
st.sidebar.success(f"Selected folder: {st.session_state['selected_repo_path']}")
|
|
else:
|
|
st.sidebar.error("No folder selected.")
|
|
|
|
# Load previously selected folder
|
|
selected_repo_path = st.session_state.get("selected_repo_path", None)
|
|
|
|
if selected_repo_path:
|
|
st.header(f"Selected Repository: {selected_repo_path}")
|
|
repo_path = Path(selected_repo_path)
|
|
current_config = load_saved_config(repo_path) # Load config from repo directory
|
|
|
|
st.subheader("File Filtering")
|
|
# Retrieve directories and files in the repository
|
|
all_directories = []
|
|
all_files = []
|
|
for root_dir, dirs, files in os.walk(repo_path):
|
|
rel_root = Path(root_dir).relative_to(repo_path)
|
|
# Exclude default directories
|
|
dirs[:] = [d for d in dirs if d not in DEFAULT_EXCLUDED_DIRS]
|
|
|
|
# Add directories
|
|
for d in dirs:
|
|
all_directories.append(str(rel_root / d) + "/")
|
|
|
|
# Add files (including root files)
|
|
for f in files:
|
|
# Skip files that match any of the default excluded patterns
|
|
if any(f.endswith(excluded.replace('*', '')) for excluded in DEFAULT_EXCLUDED_FILES if '*' in excluded) or \
|
|
f in DEFAULT_EXCLUDED_FILES:
|
|
continue
|
|
|
|
file_path = str(rel_root / f)
|
|
if file_path.startswith('.'): # Handle root files
|
|
file_path = file_path[2:] # Remove './'
|
|
all_files.append(file_path)
|
|
|
|
# Directory selection for Directory Tree
|
|
# Filter out any saved directories that don't exist in current options
|
|
saved_directories = current_config.get("selected_directories", [])
|
|
valid_saved_directories = [d for d in saved_directories if d in all_directories]
|
|
|
|
selected_directories = st.multiselect(
|
|
"Include in Directory Tree",
|
|
options=all_directories,
|
|
default=valid_saved_directories
|
|
)
|
|
|
|
# Include all files in selected directories AND root files
|
|
included_files = [
|
|
f for f in all_files if (
|
|
any(str(Path(f).parent) in d for d in selected_directories) or # Files in selected directories
|
|
str(Path(f).parent) == '.' or # Root files
|
|
str(Path(f).parent) == '' # Also handles root files
|
|
)
|
|
]
|
|
|
|
# File exclusions
|
|
available_files = [f for f in included_files if f not in DEFAULT_EXCLUDED_FILES]
|
|
saved_exclusions = [f for f in current_config.get("excluded_files", [])
|
|
if f in available_files and f not in DEFAULT_EXCLUDED_FILES]
|
|
|
|
excluded_files = st.multiselect(
|
|
"Exclude Specific Files",
|
|
options=available_files,
|
|
default=saved_exclusions
|
|
)
|
|
|
|
st.write("### Final Included Files")
|
|
final_included_files = [f for f in included_files if f not in excluded_files]
|
|
st.write(final_included_files)
|
|
|
|
st.subheader("Generate Context File")
|
|
if st.button("Generate Context File"):
|
|
try:
|
|
# Update config.yaml based on user selections
|
|
updated_config = {
|
|
"source_directory": str(repo_path),
|
|
"exclude_dirs": DEFAULT_EXCLUDED_DIRS,
|
|
"important_files": final_included_files,
|
|
"custom_sections": app_config.get("custom_sections", [])
|
|
}
|
|
|
|
# Write updated config.yaml
|
|
with open(SCRIPT_DIR / CONFIG_FILE, "w") as f:
|
|
yaml.dump(updated_config, f)
|
|
|
|
# Run the script as a subprocess
|
|
result = subprocess.run(
|
|
[sys.executable, str(SCRIPT_DIR / "generate_repo_context.py")],
|
|
cwd=SCRIPT_DIR,
|
|
check=True,
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
|
|
# Clear config.yaml after generation
|
|
clear_config()
|
|
|
|
st.success("Context file generated successfully.")
|
|
st.write(f"Script output:\n{result.stdout}")
|
|
|
|
# Check if the file was created in script directory first
|
|
generated_file = SCRIPT_DIR / "repo-context.txt"
|
|
if generated_file.exists():
|
|
# Read content
|
|
with open(generated_file, "r", encoding="utf-8") as f:
|
|
context_content = f.read()
|
|
|
|
# Copy file to repository directory
|
|
repo_context_file = repo_path / "repo-context.txt"
|
|
with open(repo_context_file, "w", encoding="utf-8") as f:
|
|
f.write(context_content)
|
|
|
|
# Delete the file from script directory
|
|
generated_file.unlink()
|
|
|
|
if context_content.strip(): # Ensure content is not empty
|
|
# Add Download Button with unique key
|
|
st.download_button(
|
|
label="Download repo-context.txt",
|
|
data=context_content,
|
|
file_name="repo-context.txt",
|
|
mime="text/plain",
|
|
key="download_button_1"
|
|
)
|
|
|
|
st.info("To copy: Click in the text area, press Ctrl+A (Cmd+A on Mac) to select all, then Ctrl+C (Cmd+C on Mac) to copy.")
|
|
|
|
# Create a text area with the content
|
|
text_area = st.text_area(
|
|
"Generated Context File",
|
|
value=context_content,
|
|
height=400,
|
|
key="context_content"
|
|
)
|
|
|
|
st.success(f"Context file saved to: {repo_context_file}")
|
|
else:
|
|
st.error("Generated content is empty. Please review your repository and configurations.")
|
|
else:
|
|
st.error("Context file not found after script execution.")
|
|
except subprocess.CalledProcessError as e:
|
|
st.error("Error generating context file:")
|
|
if e.stdout:
|
|
st.text(f"Standard Output:\n{e.stdout}")
|
|
if e.stderr:
|
|
st.text(f"Standard Error:\n{e.stderr}")
|
|
|
|
# Save configuration for future use
|
|
if st.button("Save Configuration"):
|
|
save_config({
|
|
"selected_directories": selected_directories,
|
|
"excluded_files": excluded_files,
|
|
}, repo_path)
|
|
st.success("Configuration saved successfully.")
|
|
else:
|
|
st.write("Please select a folder to begin.") |