PDFGenwithFileExplorer / src /streamlit_app.py
awacke1's picture
Update src/streamlit_app.py
ddd44f7 verified
import streamlit as st
from pathlib import Path
import base64
import datetime
import markdown2
from weasyprint import HTML, CSS
# --- Configuration & Setup ---
# Define the layouts based on the specification.
# The 'size' key uses CSS-compatible dimensions.
LAYOUTS = {
"A4 Portrait": {"size": "210mm 297mm", "icon": "πŸ“„"},
"A4 Landscape": {"size": "297mm 210mm", "icon": "πŸ“„"},
"Letter Portrait": {"size": "8.5in 11in", "icon": "πŸ“„"},
"Letter Landscape": {"size": "11in 8.5in", "icon": "πŸ“„"},
"Wide 16:9": {"aspect_ratio": "16/9", "icon": "πŸ“Ί"},
"Vertical 9:16": {"aspect_ratio": "9/16", "icon": "πŸ“±"},
"Square 1:1": {"aspect_ratio": "1/1", "icon": "πŸ–ΌοΈ"},
}
# Directory to save the generated PDFs
OUTPUT_DIR = Path("generated_pdfs")
OUTPUT_DIR.mkdir(exist_ok=True)
# --- Helper Functions ---
def get_file_download_link(file_path: Path) -> str:
"""Generates a base64-encoded download link for a file."""
with open(file_path, "rb") as f:
data = base64.b64encode(f.read()).decode()
return f'<a href="data:application/octet-stream;base64,{data}" download="{file_path.name}">Download</a>'
def display_file_explorer():
"""Renders a simple file explorer in the Streamlit app."""
st.header("πŸ“‚ File Explorer")
# Display Source Markdown files
st.subheader("Source Markdown Files (.md)")
md_files = list(Path(".").glob("*.md"))
if not md_files:
st.info("No Markdown files found in the current directory. Create a `.md` file to begin.")
else:
for md_file in md_files:
col1, col2 = st.columns([0.8, 0.2])
with col1:
st.write(f"πŸ“ `{md_file.name}`")
with col2:
st.markdown(get_file_download_link(md_file), unsafe_allow_html=True)
# Display Generated PDF files
st.subheader("Generated PDF Files")
pdf_files = sorted(list(OUTPUT_DIR.glob("*.pdf")), reverse=True)
if not pdf_files:
st.info("No PDFs generated yet. Click the button above.")
else:
for pdf_file in pdf_files:
col1, col2 = st.columns([0.8, 0.2])
with col1:
st.write(f"πŸ“„ `{pdf_file.name}`")
with col2:
st.markdown(get_file_download_link(pdf_file), unsafe_allow_html=True)
def generate_pdf_from_markdown(md_path: Path):
"""
Reads a markdown file and generates PDFs for all defined layouts.
"""
try:
md_content = md_path.read_text(encoding="utf-8")
html_content = markdown2.markdown(md_content, extras=["tables", "fenced-code-blocks", "cuddled-lists"])
# Basic styling for the PDF
base_css = """
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap');
body { font-family: 'Inter', sans-serif; line-height: 1.6; }
h1, h2, h3 { font-weight: 700; }
code {
background-color: #f0f0f0;
padding: 2px 4px;
border-radius: 3px;
font-family: monospace;
}
pre { background-color: #f0f0f0; padding: 1em; border-radius: 5px; overflow: auto; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; }
th { background-color: #f2f2f2; }
"""
date_str = datetime.datetime.now().strftime("%Y-%m-%d")
for name, properties in LAYOUTS.items():
st.write(f" - Generating `{name}` format...")
page_css = f"@page {{ size: {properties.get('size', 'A4')}; margin: 2cm; }}"
if 'aspect_ratio' in properties:
# For aspect ratio, we fix width and calculate height. This is an approximation.
# A more robust solution might require more complex CSS.
page_css = f"@page {{ size: 210mm calc(210mm * {properties['aspect_ratio']}); margin: 1cm; }}"
final_css = CSS(string=base_css + page_css)
output_filename = f"{md_path.stem}_{name.replace(' ', '-')}_{date_str}.pdf"
output_path = OUTPUT_DIR / output_filename
HTML(string=html_content).write_pdf(output_path, stylesheets=[final_css])
except Exception as e:
st.error(f"Failed to process {md_path.name}: {e}")
# --- Streamlit App UI ---
st.set_page_config(layout="wide", page_title="PDF Generator")
st.title("πŸ“„ Markdown to PDF Generator")
st.markdown("This tool finds all `.md` files in this directory, converts them to PDF in various layouts, and provides download links.")
# Create a sample markdown file if none exists
if not list(Path(".").glob("*.md")):
with open("sample.md", "w", encoding="utf-8") as f:
f.write("# Sample Document\n\n")
f.write("This is a sample markdown file created for you. You can edit this file or add your own `.md` files to this directory.\n\n")
f.write("- Item 1\n- Item 2\n\n")
f.write("`code snippet`\n\n")
f.write("Click the button below to start the PDF generation process.")
st.rerun()
if st.button("πŸš€ Generate PDFs from all Markdown Files", type="primary"):
markdown_files = list(Path(".").glob("*.md"))
if not markdown_files:
st.warning("No `.md` files found. Please add a markdown file to the directory.")
else:
with st.spinner("Generating PDFs... This may take a moment."):
progress_bar = st.progress(0)
total_steps = len(markdown_files)
for i, md_file in enumerate(markdown_files):
st.info(f"Processing: **{md_file.name}**")
generate_pdf_from_markdown(md_file)
progress_bar.progress((i + 1) / total_steps)
st.success("βœ… PDF generation complete!")
# Use st.rerun() to immediately refresh the file explorer
st.rerun()
# Display the file explorer section
display_file_explorer()