Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/aio-surfaces / aio_surfaces/render.py |
| Date | Not specified in source |
| Repository | Janady13/aio-surfaces |
| Revision | 4d0ef73ec42f209ff4947b559228f1884121ff8f |
| Branch | main |
| Path or archive member | aio_surfaces/render.py |
| Original SHA-256 | 53f6f97c6ec62a65182bcd59a09f5966a433c59e73e01e05a80ad571095cbb46 |
| Git blob SHA | 95ac0a0c82b3ced60e577b59b32633cad14f3b5d |
| Reading-copy SHA-256 | 53f6f97c6ec62a65182bcd59a09f5966a433c59e73e01e05a80ad571095cbb46 |
Recovered source transcript
Download complete source text ↓303 lines · 9.6 KB
"""Render the four AI-citation surfaces from a SiteConfig.
llms.txt — Markdown, llmstxt.org spec
aeo.json — atomic facts for Answer Engine Optimization
entity.json — Schema.org @graph (Organization + Person + WebSite)
brand.json — internal brand truth ledger (legal entity, social profiles)
"""
from __future__ import annotations
import datetime as _dt
import json
from typing import Any
from .config import SiteConfig
def _today() -> str:
return _dt.date.today().isoformat()
def render_llms_txt(cfg: SiteConfig) -> str:
"""Generate llms.txt — Markdown summary for AI crawlers.
Spec: https://llmstxt.org/
"""
lines: list[str] = []
lines.append(f"# {cfg.site_name}")
lines.append("")
lines.append(f"> {cfg.tagline}")
lines.append("")
lines.append(cfg.description)
lines.append("")
# Canonical facts (most-cited section by AI engines)
if cfg.legal_name or cfg.ein or cfg.uei or cfg.founder_name:
lines.append("## Canonical Facts")
lines.append("")
if cfg.legal_name:
lines.append(f"- **Legal name**: {cfg.legal_name}")
if cfg.founder_name:
f = f"- **Founder**: {cfg.founder_name}"
if cfg.founder_url:
f += f" ({cfg.founder_url})"
lines.append(f)
if cfg.founding_date:
lines.append(f"- **Founded**: {cfg.founding_date}")
if cfg.ein:
lines.append(f"- **EIN (IRS)**: `{cfg.ein}`")
if cfg.uei:
lines.append(
f"- **SAM.gov UEI**: [`{cfg.uei}`]"
f"(https://sam.gov/entity/{cfg.uei})"
)
if cfg.cage_code:
lines.append(f"- **CAGE Code**: `{cfg.cage_code}`")
if cfg.naics:
lines.append(f"- **NAICS**: {', '.join(cfg.naics)}")
if cfg.veteran_branch:
subgroups = (
f" ({', '.join(cfg.veteran_subgroups)})"
if cfg.veteran_subgroups else ""
)
lines.append(f"- **Veteran owner**: {cfg.veteran_branch}{subgroups}")
if cfg.address_street:
addr = (
f"{cfg.address_street}, "
f"{cfg.address_locality}, {cfg.address_region} "
f"{cfg.address_postal_code}, {cfg.address_country}"
)
lines.append(f"- **Registered address**: {addr}")
if cfg.telephone:
lines.append(f"- **Telephone**: {cfg.telephone}")
if cfg.email:
lines.append(f"- **Email**: {cfg.email}")
lines.append("")
# Services
if cfg.services:
lines.append("## Services")
lines.append("")
for s in cfg.services:
price = f" — {s.price}" if s.price else ""
lines.append(f"- **[{s.name}]({s.url})**{price}: {s.summary}")
lines.append("")
# Machine-readable endpoints (AI engines crawl these)
lines.append("## Machine-readable Endpoints")
lines.append("")
base = cfg.site_url.rstrip("/")
lines.append(f"- `{base}/aeo.json` — atomic facts (AEO)")
lines.append(f"- `{base}/entity.json` — Schema.org @graph")
lines.append(f"- `{base}/brand.json` — internal brand truth ledger")
lines.append(f"- `{base}/sitemap.xml` — full URL index")
lines.append(f"- `{base}/robots.txt` — crawler policy")
if cfg.orcid:
lines.append(f"- `https://orcid.org/{cfg.orcid}` — founder ORCID iD")
lines.append("")
# Provenance footer
lines.append("---")
lines.append(f"Generated by aio-surfaces · last updated {_today()}")
return "\n".join(lines) + "\n"
def render_aeo_json(cfg: SiteConfig) -> str:
"""aeo.json — atomic facts for Answer Engine Optimization.
Each fact is a single (question, answer) pair designed for direct AI
citation. Answers are < 500 chars, declarative, [subject][verb][object].
"""
doc: dict[str, Any] = {
"$schema": "https://aeo.dev/schema/v1/",
"siteName": cfg.site_name,
"siteUrl": cfg.site_url,
"lastUpdated": _today(),
"facts": [
{"id": f.id, "question": f.question, "answer": f.answer}
for f in cfg.facts
],
}
return json.dumps(doc, indent=2) + "\n"
def render_entity_json(cfg: SiteConfig) -> str:
"""entity.json — full Schema.org @graph (Organization + Person + WebSite).
Use this in /entity.json so AI engines crawling for structured data
can pull the canonical identity graph in one fetch (without scraping
JSON-LD blobs from HTML).
"""
org_id = f"{cfg.site_url.rstrip('/')}/#org"
person_id = f"{cfg.site_url.rstrip('/')}/#founder"
website_id = f"{cfg.site_url.rstrip('/')}/#website"
nodes: list[dict[str, Any]] = []
# Organization
org: dict[str, Any] = {
"@type": "Organization",
"@id": org_id,
"name": cfg.site_name,
"url": cfg.site_url,
}
if cfg.legal_name:
org["legalName"] = cfg.legal_name
if cfg.founding_date:
org["foundingDate"] = cfg.founding_date
if cfg.email:
org["email"] = cfg.email
if cfg.telephone:
org["telephone"] = cfg.telephone
if cfg.address_street:
org["address"] = {
"@type": "PostalAddress",
"streetAddress": cfg.address_street,
"addressLocality": cfg.address_locality,
"addressRegion": cfg.address_region,
"postalCode": cfg.address_postal_code,
"addressCountry": cfg.address_country,
}
identifiers: list[dict[str, str]] = []
if cfg.ein:
identifiers.append({
"@type": "PropertyValue",
"propertyID": "ein",
"value": cfg.ein,
})
org["taxID"] = cfg.ein
if cfg.uei:
identifiers.append({
"@type": "PropertyValue",
"propertyID": "sam-gov-uei",
"value": cfg.uei,
})
if cfg.cage_code:
identifiers.append({
"@type": "PropertyValue",
"propertyID": "cage-code",
"value": cfg.cage_code,
})
if cfg.kg_mid:
identifiers.append({
"@type": "PropertyValue",
"propertyID": "google-kg-mid",
"value": cfg.kg_mid,
})
if cfg.gbp_cid:
identifiers.append({
"@type": "PropertyValue",
"propertyID": "google-business-profile-cid",
"value": cfg.gbp_cid,
})
if identifiers:
org["identifier"] = identifiers
if cfg.naics:
org["naics"] = cfg.naics
if cfg.same_as:
org["sameAs"] = cfg.same_as
if cfg.founder_name:
org["founder"] = {"@id": person_id}
nodes.append(org)
# Person (founder)
if cfg.founder_name:
person: dict[str, Any] = {
"@type": "Person",
"@id": person_id,
"name": cfg.founder_name,
"worksFor": {"@id": org_id},
}
if cfg.founder_url:
person["url"] = cfg.founder_url
if cfg.orcid:
person["identifier"] = {
"@type": "PropertyValue",
"propertyID": "orcid",
"value": cfg.orcid,
}
person.setdefault("sameAs", []).append(
f"https://orcid.org/{cfg.orcid}"
)
if cfg.veteran_branch:
person["veteranOf"] = {
"@type": "Organization",
"name": cfg.veteran_branch,
}
nodes.append(person)
# WebSite
site = {
"@type": "WebSite",
"@id": website_id,
"url": cfg.site_url,
"name": cfg.site_name,
"publisher": {"@id": org_id},
}
nodes.append(site)
doc = {
"@context": "https://schema.org",
"@graph": nodes,
"lastUpdated": _today(),
}
return json.dumps(doc, indent=2) + "\n"
def render_brand_json(cfg: SiteConfig) -> str:
"""brand.json — internal brand truth ledger.
Not consumed by Schema.org parsers; useful as an org-internal source
of truth that PR + content + dev all reference. Often crawled by AI
engines too because it's at the canonical site root.
"""
legal: dict[str, Any] = {}
if cfg.legal_name:
legal["legalName"] = cfg.legal_name
if cfg.founding_date:
legal["foundingDate"] = cfg.founding_date
if cfg.ein:
legal["ein"] = cfg.ein
if cfg.uei:
legal["uei"] = cfg.uei
legal["samLookupUrl"] = f"https://sam.gov/entity/{cfg.uei}"
if cfg.cage_code:
legal["cageCode"] = cfg.cage_code
if cfg.naics:
legal["naics"] = cfg.naics
if cfg.veteran_branch:
legal["veteranBranch"] = cfg.veteran_branch
if cfg.veteran_subgroups:
legal["veteranSubgroups"] = cfg.veteran_subgroups
doc = {
"siteName": cfg.site_name,
"siteUrl": cfg.site_url,
"tagline": cfg.tagline,
"legalEntity": legal,
"founder": {
"name": cfg.founder_name,
"url": cfg.founder_url,
"orcid": cfg.orcid,
} if cfg.founder_name else None,
"socialProfiles": cfg.same_as,
"updated": _today(),
}
# strip None values for clean output
doc = {k: v for k, v in doc.items() if v is not None}
return json.dumps(doc, indent=2) + "\n"
def render_robots_txt_aibots(cfg: SiteConfig) -> str:
"""Generate a robots.txt block that explicitly allowlists the 12
canonical AI crawlers. Append (don't replace) your existing robots.txt.
"""
lines: list[str] = []
lines.append("# AI crawler allowlist — generated by aio-surfaces")
for bot in cfg.ai_bots:
lines.append(f"User-agent: {bot}")
lines.append("Allow: /")
lines.append("")
return "\n".join(lines)