from pathlib import Path import argparse import csv from jinja2 import Environment, FileSystemLoader from weasyprint import HTML def load_csv(csv_path): categories = {} with open(csv_path, newline="", encoding="utf-8-sig") as f: sample = f.read(4096) f.seek(0) dialect = csv.Sniffer().sniff(sample, delimiters=",;") reader = csv.DictReader(f, dialect=dialect) for row in reader: normalized = { (key or "").strip().lower().replace(" ", "_"): (value or "").strip() for key, value in row.items() } category = ( normalized.get("category") or normalized.get("catagory") or normalized.get("kategorie") or "Ostatní" ) name = ( normalized.get("name") or normalized.get("nazev") or normalized.get("název") or "" ) price = ( normalized.get("price") or normalized.get("cena") or "" ) image = ( normalized.get("image") or normalized.get("foto") or normalized.get("fotka") or normalized.get("obrazek") or normalized.get("obrázek") or "" ) show_allergen_icon = ( normalized.get("show_alergen_icon") or normalized.get("show_allergen_icon") or normalized.get("alergen_icon") or normalized.get("allergen_icon") or "" ).lower() in ("1", "true", "yes", "ano", "y") note = ( normalized.get("note") or normalized.get("description") or normalized.get("poznamka") or normalized.get("poznámka") or "" ) if category not in categories: categories[category] = [] categories[category].append({ "name": name, "price": price, "image": image, "show_allergen_icon": show_allergen_icon, "description": note, }) return categories def build_catalog_data(title, subtitle, categories): return { "title": title, "subtitle": subtitle, "categories": [ { "name": name, "products": products, } for name, products in categories.items() ], } def render_html(data, template_dir, images_dir): env = Environment( loader=FileSystemLoader(template_dir) ) template = env.get_template("catalog.html.j2") return template.render( catalog=data, brand=data, settings={ "columns": 4, "page_size": "1024px 768px", "margin": "0", }, images_dir=images_dir.as_posix(), assets_dir=(Path(__file__).resolve().parent / "assets").as_posix(), logo_exists=(Path(__file__).resolve().parent / "assets" / "logo.png").exists(), ) def generate_pdf(html_content, output_path): HTML(string=html_content).write_pdf(output_path) def main(): parser = argparse.ArgumentParser() parser.add_argument( "-i", "--input", required=True, help="CSV input file" ) parser.add_argument( "--output", default="output/catalog.pdf", help="Output PDF path" ) parser.add_argument( "--images-dir", default="images", help="Directory with product images" ) parser.add_argument( "--title", default="Bistro Ušky", ) parser.add_argument( "--subtitle", default="Cake & Patisserie", ) args = parser.parse_args() base_dir = Path(__file__).resolve().parent csv_path = Path(args.input) output_path = Path(args.output) images_dir = Path(args.images_dir) output_path.parent.mkdir(parents=True, exist_ok=True) categories = load_csv(csv_path) catalog_data = build_catalog_data( args.title, args.subtitle, categories, ) html = render_html( catalog_data, base_dir / "templates", images_dir, ) generate_pdf(html, output_path) print(f"PDF generated: {output_path}") if __name__ == "__main__": main()