From d8350ef83ed0f1edb40509e25f4b2fde67f2683c Mon Sep 17 00:00:00 2001 From: CodeAndCanvas728 Date: Wed, 17 Jun 2026 17:14:21 +0200 Subject: [PATCH] Refactor PDF generation and update class structure --- generate_post.py | 239 ++++++++++++++++++++++++++--------------------- 1 file changed, 132 insertions(+), 107 deletions(-) diff --git a/generate_post.py b/generate_post.py index 1b8e612..f89f656 100644 --- a/generate_post.py +++ b/generate_post.py @@ -1,6 +1,5 @@ import os import csv -import re import requests from bs4 import BeautifulSoup from fpdf import FPDF @@ -17,48 +16,55 @@ COLOR_BORDER = (229, 222, 201) # #E5DEC9 - Thin muted gridlines LOCAL_CSV_PATH = "RepoDatabase.csv" REMOTE_CSV_URL = "https://raw.githubusercontent.com/CodeAndCanvas728/repobase/refs/heads/main/RepoDatabase.csv" -class CodeCanvasPDF(FPDF): - def header(self): - self.set_fill_color(*COLOR_LINEN) - self.rect(0, 0, 210, 297, 'F') - - self.set_draw_color(*COLOR_BORDER) - self.set_line_width(0.5) - self.line(15, 15, 195, 15) - - # Standalone Ampersand Shorthand - self.set_text_color(*COLOR_TERRACOTTA) - self.set_font("Times", "I", 16) # Classic serif - self.text(15, 25, "&") - self.set_text_color(*COLOR_NAVY) - self.set_font("Helvetica", "B", 8) # Sans-serif technical data - self.text(23, 23, "CODE & CANVAS | INSIGHTS") +class CodeCanvasCarousel(FPDF): + def __init__(self): + # Initialize in Landscape mode ('L') using millimeters, explicitly custom sizing (A5 Landscape) + super().__init__(orientation='L', unit='mm', format='A5') + self.set_margins(20, 25, 20) + self.set_auto_page_break(False) - def footer(self): + def draw_brand_canvas(self): + """Fills background with Linen Canvas and draws the minimal header framework.""" + self.set_fill_color(*COLOR_LINEN) + self.rect(0, 0, 210, 148, 'F') # A5 Landscape boundary dimensions + + # Thin editorial top rule + self.set_draw_color(*COLOR_BORDER) + self.set_line_width(0.4) + self.line(20, 15, 190, 15) + + # Standalone Ampersand Shorthand as visual anchor + self.set_text_color(*COLOR_TERRACOTTA) + self.set_font("Times", "I", 16) + self.text(20, 24, "&") + + # Sans-serif technical meta-tag + self.set_text_color(*COLOR_NAVY) + self.set_font("Helvetica", "B", 7) + self.text(28, 22, "CODE & CANVAS | INSIGHTS") + + def draw_footer(self, current_slide, total_slides): + """Draws page numbering following clean, minimal layout scales.""" self.set_text_color(*COLOR_CHARCOAL) self.set_font("Helvetica", "", 8) - self.text(185, 285, f"Page {self.page_no()}") + self.text(180, 138, f"{current_slide} / {total_slides}") def clean_typography(text): - """Enforces absolute purity of text: No unicode or markdown em-dashes.""" + """Enforces absolute micro-styling purity: completely strips out em-dashes.""" return text.replace("—", " : ").replace("--", " - ") def fetch_and_update_subject(): - """Reads local repository CSV to find an unused row, updates it to 'yes', - and writes it back immediately to prevent duplicate scheduling entries.""" rows = [] selected_subject = None file_exists_locally = os.path.exists(LOCAL_CSV_PATH) - # 1. Read Database Data if file_exists_locally: with open(LOCAL_CSV_PATH, mode='r', newline='', encoding='utf-8') as f: reader = csv.DictReader(f) fieldnames = reader.fieldnames for row in reader: - # Find the first unused item matching criteria if not selected_subject and row.get('Used', '').strip().lower() == 'no': - row['Used'] = 'yes' # State Update Mutation + row['Used'] = 'yes' selected_subject = { "title": row['Title'], "desc": row['Description'], @@ -66,27 +72,7 @@ def fetch_and_update_subject(): "url": row.get('URL', f"https://github.com/search?q={row['Title']}") } rows.append(row) - else: - # Fallback tracking if working outside local repository layout - print("Warning: Local RepoDatabase.csv not found. Reverting to remote live endpoint.") - try: - res = requests.get(REMOTE_CSV_URL, timeout=10) - if res.status_code == 200: - lines = res.text.splitlines() - reader = csv.DictReader(lines) - fieldnames = reader.fieldnames - for row in reader: - if not selected_subject and row.get('Used', '').strip().lower() == 'no': - selected_subject = { - "title": row['Title'], - "desc": row['Description'], - "points": [row['Point1'], row['Point2'], row['Point3']], - "url": row.get('URL', '') - } - except Exception: - pass - - # 2. Save Updated Database State if modified locally + if selected_subject and file_exists_locally: with open(LOCAL_CSV_PATH, mode='w', newline='', encoding='utf-8') as f: writer = csv.DictWriter(f, fieldnames=fieldnames) @@ -94,29 +80,13 @@ def fetch_and_update_subject(): writer.writerows(rows) return selected_subject - # 3. Dynamic GitHub Scraping Fallback Routine - if not selected_subject: - print("Database exhausted or unreachable. Querying trending open-source indexes...") - try: - fb_res = requests.get("https://github.com/trending", timeout=10) - soup = BeautifulSoup(fb_res.text, 'html.parser') - repo = soup.find('article', class_='Box-row') - raw_title = repo.find('h2', class_='h3').text.strip().replace('\n', '').replace(' ', '') - desc = repo.find('p', class_='col-9').text.strip() - return { - "title": raw_title.split('/')[-1], - "desc": desc, - "points": ["Open-source workflow standard", "Highly modular architectural design", "Streamlined environment footprint"], - "url": f"https://github.com/{raw_title}" - } - except Exception: - # Absolute hard-fail recovery state - return { - "title": "Model Context Protocol", - "desc": "An open standard enabling secure, structured data communication layers between local environments and generative applications.", - "points": ["Eliminates custom integration glue code", "Maintains clear architectural boundaries", "Built for cross-tool interoperability"], - "url": "https://github.com/modelcontextprotocol" - } + # Ultimate fallback logic if CSV down or empty + return { + "title": "Model Context Protocol", + "desc": "An open standard enabling secure, structured data communication layers between local environments and generative applications.", + "points": ["Eliminates custom integration glue code", "Maintains clean architectural boundaries", "Built for cross-tool interoperability"], + "url": "https://github.com/modelcontextprotocol" + } def generate_assets(): data = fetch_and_update_subject() @@ -124,55 +94,113 @@ def generate_assets(): desc = clean_typography(data['desc']) points = [clean_typography(p) for p in data['points']] - # Target path configuration os.makedirs("_drafts", exist_ok=True) - safe_date = "weekly-draft" + TOTAL_SLIDES = 4 + + pdf = CodeCanvasCarousel() # ------------------------------------------------------------------------- - # PDF COMPILATION BLOCK + # SLIDE 1: DISPLAY TITLE CARD # ------------------------------------------------------------------------- - pdf = CodeCanvasPDF() - pdf.set_margins(15, 30, 15) pdf.add_page() + pdf.draw_brand_canvas() + + pdf.set_y(45) + pdf.set_text_color(*COLOR_NAVY) + pdf.set_font("Times", "", 32) # Editorial high-contrast serif display + pdf.multi_cell(170, 14, title) + + pdf.set_y(pdf.get_y() + 6) + pdf.set_text_color(*COLOR_CHARCOAL) + pdf.set_font("Helvetica", "", 12) # Sans-serif structural subtitle + pdf.multi_cell(170, 6, "An architectural breakdown of engineering utility and integration footprints.") + pdf.draw_footer(1, TOTAL_SLIDES) + + # ------------------------------------------------------------------------- + # SLIDE 2: THE CORE PROBLEMATIQUE / OVERVIEW + # ------------------------------------------------------------------------- + pdf.add_page() + pdf.draw_brand_canvas() - # Header display layout pdf.set_y(40) pdf.set_text_color(*COLOR_NAVY) - pdf.set_font("Times", "", 26) - pdf.multi_cell(180, 12, title) + pdf.set_font("Times", "", 18) + pdf.cell(170, 8, "Core Structural Objective", ln=True) - # Layout dividing grid rules + # Subtle geometric divider line pdf.set_draw_color(*COLOR_BORDER) - pdf.line(15, pdf.get_y() + 5, 80, pdf.get_y() + 5) + pdf.line(20, pdf.get_y() + 2, 60, pdf.get_y() + 2) - # Copy layout execution - pdf.set_y(pdf.get_y() + 15) + pdf.set_y(pdf.get_y() + 12) pdf.set_text_color(*COLOR_CHARCOAL) pdf.set_font("Helvetica", "", 11) - pdf.multi_cell(180, 7, desc) - - # Balanced spacing grids for parameters - pdf.set_y(pdf.get_y() + 15) - for idx, pt in enumerate(points, 1): - pdf.set_draw_color(*COLOR_BORDER) - pdf.set_fill_color(*COLOR_LINEN) - pdf.rect(15, pdf.get_y(), 180, 18, 'DF') - - pdf.set_x(20) - pdf.set_text_color(*COLOR_TERRACOTTA) - pdf.set_font("Times", "I", 12) - pdf.cell(10, 18, f"0{idx}") - - pdf.set_text_color(*COLOR_CHARCOAL) - pdf.set_font("Helvetica", "", 10) - pdf.cell(160, 18, pt) - pdf.set_y(pdf.get_y() + 22) - - pdf_path = f"_drafts/{safe_date}.pdf" - pdf.output(pdf_path) + pdf.multi_cell(170, 7, desc) + pdf.draw_footer(2, TOTAL_SLIDES) # ------------------------------------------------------------------------- - # MARKDOWN CONVERSION BLOCK + # SLIDE 3: TECHNICAL CONSIDERATIONS (GRID BLOCK) + # ------------------------------------------------------------------------- + pdf.add_page() + pdf.draw_brand_canvas() + + pdf.set_y(38) + pdf.set_text_color(*COLOR_NAVY) + pdf.set_font("Times", "", 18) + pdf.cell(170, 8, "Key Architecture Vectors", ln=True) + + start_y = pdf.get_y() + 8 + for idx, pt in enumerate(points): + current_item_y = start_y + (idx * 22) + + # Structural card containers using thin borders + pdf.set_draw_color(*COLOR_BORDER) + pdf.set_fill_color(*COLOR_LINEN) + pdf.rect(20, current_item_y, 170, 16, 'DF') + + # Terracotta index anchor points + pdf.set_y(current_item_y + 4) + pdf.set_x(24) + pdf.set_text_color(*COLOR_TERRACOTTA) + pdf.set_font("Times", "I", 11) + pdf.cell(10, 8, f"0{idx+1}") + + # Clean structural sans body text + pdf.set_x(36) + pdf.set_text_color(*COLOR_CHARCOAL) + pdf.set_font("Helvetica", "", 10) + pdf.cell(150, 8, pt) + + pdf.draw_footer(3, TOTAL_SLIDES) + + # ------------------------------------------------------------------------- + # SLIDE 4: THE CALL TO ACTION / ARCHITECTURE ROOT + # ------------------------------------------------------------------------- + pdf.add_page() + pdf.draw_brand_canvas() + + pdf.set_y(45) + pdf.set_text_color(*COLOR_NAVY) + pdf.set_font("Times", "", 24) + pdf.multi_cell(170, 10, f"Explore the Open-Source Blueprint") + + pdf.set_y(pdf.get_y() + 10) + pdf.set_text_color(*COLOR_CHARCOAL) + pdf.set_font("Helvetica", "", 11) + pdf.multi_cell(170, 6, "Review the configuration patterns, track the baseline execution logs, and implement the layout block directly into your development container environments.") + + # High-contrast action footer block + pdf.set_y(pdf.get_y() + 12) + pdf.set_text_color(*COLOR_TERRACOTTA) + pdf.set_font("Helvetica", "B", 10) + pdf.cell(170, 6, f"Source Index: {data['url']}", ln=True) + + pdf.draw_footer(4, TOTAL_SLIDES) + + # Output file generation paths + pdf.output("_drafts/weekly-draft.pdf") + + # ------------------------------------------------------------------------- + # GENERATE MARKDOWN TEXT FILE # ------------------------------------------------------------------------- post_copy = f"""💡 Weekly AI Architecture Breakdown @@ -192,11 +220,8 @@ Repository Link: {data['url']} #SoftwareArchitecture #DeveloperTools #TechInsights #CodeAndCanvas""" - md_path = f"_drafts/{safe_date}.md" - with open(md_path, mode='w', encoding='utf-8') as f: + with open("_drafts/weekly-draft.md", mode='w', encoding='utf-8') as f: f.write(post_copy) - print(f"Workflow Complete: Created tracking drafts inside configuration paths.") - if __name__ == "__main__": generate_assets()