diff --git a/generate_post.py b/generate_post.py new file mode 100644 index 0000000..c0e0161 --- /dev/null +++ b/generate_post.py @@ -0,0 +1,161 @@ +import os +import csv +import requests +from bs4 import BeautifulSoup +from fpdf import FPDF + +# ------------------------------------------------------------------------- +# CODE & CANVAS BRAND DESIGN TOKENS +# ------------------------------------------------------------------------- +COLOR_LINEN = (250, 248, 245) # #FAF8F5 - Default background canvas[span_2](start_span)[span_2](end_span) +COLOR_NAVY = (26, 35, 50) # #1A2332 - Deep structural headers[span_3](start_span)[span_3](end_span) +COLOR_TERRACOTTA = (211, 107, 77) # #D36B4D - Primary visual accents[span_4](start_span)[span_4](end_span) +COLOR_CHARCOAL = (43, 43, 43) # #2B2B2B - High-legibility body text[span_5](start_span)[span_5](end_span) +COLOR_BORDER = (229, 222, 201) # #E5DEC9 - Thin muted gridlines[span_6](start_span)[span_6](end_span) + +CSV_URL = "https://raw.githubusercontent.com/CodeAndCanvas728/repobase/refs/heads/main/RepoDatabase.csv" + +class CodeCanvasPDF(FPDF): + def header(self): + # Establish Editorial Minimalism and generous margins + self.set_fill_color(*COLOR_LINEN) + self.rect(0, 0, 210, 297, 'F') + + # Subtle top accent line instead of heavy borders + self.set_draw_color(*COLOR_BORDER) + self.set_line_width(0.5) + self.line(15, 15, 195, 15) + + # Standalone Ampersand Shorthand as the brand anchor + self.set_text_color(*COLOR_TERRACOTTA) + self.set_font("Times", "I", 16) # Elegant serif substitution for Georgia + self.text(15, 25, "&") + self.set_text_color(*COLOR_NAVY) + self.set_font("Helvetica", "B", 8) # Sans-serif for technical meta-tags + self.text(23, 23, "CODE & CANVAS | INSIGHTS") + + def footer(self): + self.set_text_color(*COLOR_CHARCOAL) + self.set_font("Helvetica", "", 8) + self.text(185, 285, f"Page {self.page_no()}") + +def clean_typography(text): + """Enforces the strict micro-styling rule: Absolutely no em-dashes.""" + return text.replace("—", " : ").replace("--", " - ") + +def fetch_subject(): + try: + response = requests.get(CSV_URL, timeout=10) + if response.status_code == 200 and response.text.strip(): + lines = response.text.splitlines() + reader = csv.DictReader(lines) + for row in reader: + if row.get('Used', '').lower() == 'no': + return { + "title": row['Title'], + "desc": row['Description'], + "points": [row['Point1'], row['Point2'], row['Point3']], + "url": row.get('URL', '') + } + except Exception: + pass + + # Fallback Logic: Scrape GitHub Trending AI/LLM Python/Go repositories + 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') + title = repo.find('h2', class_='h3').text.strip().replace('\n', '').replace(' ', '') + desc = repo.find('p', class_='col-9').text.strip() + return { + "title": title, + "desc": desc, + "points": ["Open-source community standard", "Highly scalable architecture", "Streamlined local environment deployment"], + "url": f"https://github.com/{title}" + } + except Exception: + return { + "title": "Model Context Protocol", + "desc": "An open standard enabling secure, structured data communication layers between local environments and LLMs.", + "points": ["Eliminates custom integration glue code", "Maintains clean architectural boundaries", "Built for developer tool interoperability"], + "url": "https://github.com/modelcontextprotocol" + } + +def generate_assets(): + data = fetch_subject() + title = clean_typography(data['title']) + desc = clean_typography(data['desc']) + points = [clean_typography(p) for p in data['points']] + + # ------------------------------------------------------------------------- + # 1. GENERATE THE BRANDED PDF + # ------------------------------------------------------------------------- + pdf = CodeCanvasPDF() + pdf.set_margins(15, 30, 15) + pdf.add_page() + + # Title Layout (High-contrast Serif Display Style) + pdf.set_y(40) + pdf.set_text_color(*COLOR_NAVY) + pdf.set_font("Times", "", 28) # Georgia alternative + pdf.multi_cell(180, 12, title) + + # Accent Divider Line + pdf.set_draw_color(*COLOR_BORDER) + pdf.line(15, pdf.get_y() + 5, 80, pdf.get_y() + 5) + + # Brief Informational Summary + pdf.set_y(pdf.get_y() + 15) + pdf.set_text_color(*COLOR_CHARCOAL) + pdf.set_font("Helvetica", "", 11) # Sans-serif structural body text + pdf.multi_cell(180, 7, desc) + + # Structured Grid for Key Highlights + 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) + # Structural thin-bordered card layouts + 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_filename = "linkedin_insight_asset.pdf" + pdf.output(pdf_filename) + + # ------------------------------------------------------------------------- + # 2. GENERATE LINKEDIN POST COPY + # ------------------------------------------------------------------------- + post_copy = f"""💡 Weekly AI Architecture Breakdown + +Looking closely at modern workflows, complexity often hides in plain sight. Today we are looking at {title}. + +What it is: +{desc} + +Key Architecture Considerations: +• {points[0]} +• {points[1]} +• {points[2]} + +The complete visual documentation is attached below as an editorial carousel blueprint. + +Repository Link: {data['url']} + +#SoftwareArchitecture #DeveloperTools #TechInsights #CodeAndCanvas""" + + print("--- LINKEDIN POST DRAFT ---") + print(post_copy) + print("\n--- ASSET STATUS ---") + print(f"Success: {pdf_filename} generated inside your directory following brand design guidelines.") + +if __name__ == "__main__": + generate_assets()