repobase/generate_post.py
CodeAndCanvas728 3af56857c2
Add generate_post.py for PDF and LinkedIn post generation
This script generates a branded PDF and a LinkedIn post draft based on data fetched from a CSV or GitHub trending repositories. It includes functions for cleaning text, fetching subjects, and creating a PDF layout with specific design tokens.
2026-06-17 16:56:05 +02:00

161 lines
6.3 KiB
Python

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()