KSvend Claude Happy commited on
Commit ·
73b5679
1
Parent(s): ae74af5
rebrand: apply full MERLx Aperture identity per design spec
Browse filesUpdates all user-facing copy (landing page, PDF reports, emails, README)
and backend metadata to use "MERLx Aperture" branding consistently,
per the approved 2026-03-26 rebrand design specification.
Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
- README.md +5 -3
- app/core/email.py +3 -3
- app/main.py +2 -2
- app/outputs/report.py +6 -6
- frontend/index.html +9 -4
- pyproject.toml +1 -1
README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
---
|
| 2 |
-
title: Aperture
|
| 3 |
emoji: 🛰️
|
| 4 |
colorFrom: green
|
| 5 |
colorTo: blue
|
|
@@ -7,6 +7,8 @@ sdk: docker
|
|
| 7 |
app_port: 7860
|
| 8 |
---
|
| 9 |
|
| 10 |
-
# Aperture
|
| 11 |
|
| 12 |
-
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: MERLx Aperture
|
| 3 |
emoji: 🛰️
|
| 4 |
colorFrom: green
|
| 5 |
colorTo: blue
|
|
|
|
| 7 |
app_port: 7860
|
| 8 |
---
|
| 9 |
|
| 10 |
+
# MERLx Aperture
|
| 11 |
|
| 12 |
+
AI-enhanced satellite analysis for humanitarian programme teams. Part of the MERLx Optics Suite.
|
| 13 |
+
|
| 14 |
+
Built on methods developed in the SR4S research project.
|
app/core/email.py
CHANGED
|
@@ -6,7 +6,7 @@ import httpx
|
|
| 6 |
logger = logging.getLogger(__name__)
|
| 7 |
|
| 8 |
RESEND_API_KEY = os.environ.get("RESEND_API_KEY", "")
|
| 9 |
-
FROM_EMAIL = "Aperture <noreply@aperture.merlx.org>"
|
| 10 |
|
| 11 |
async def send_completion_email(to_email: str, job_id: str, aoi_name: str) -> bool:
|
| 12 |
if not RESEND_API_KEY:
|
|
@@ -21,7 +21,7 @@ async def send_completion_email(to_email: str, job_id: str, aoi_name: str) -> bo
|
|
| 21 |
The satellite analysis for <strong>{aoi_name}</strong> is complete.
|
| 22 |
</p>
|
| 23 |
<p style="font-size: 11px; color: #6B6B6B; margin-top: 20px;">
|
| 24 |
-
Generated by
|
| 25 |
</p>
|
| 26 |
</div>
|
| 27 |
"""
|
|
@@ -30,6 +30,6 @@ async def send_completion_email(to_email: str, job_id: str, aoi_name: str) -> bo
|
|
| 30 |
resp = await client.post(
|
| 31 |
"https://api.resend.com/emails",
|
| 32 |
headers={"Authorization": f"Bearer {RESEND_API_KEY}"},
|
| 33 |
-
json={"from": FROM_EMAIL, "to": [to_email], "subject": f"Aperture: Analysis ready — {aoi_name}", "html": html},
|
| 34 |
)
|
| 35 |
return resp.status_code == 200
|
|
|
|
| 6 |
logger = logging.getLogger(__name__)
|
| 7 |
|
| 8 |
RESEND_API_KEY = os.environ.get("RESEND_API_KEY", "")
|
| 9 |
+
FROM_EMAIL = "MERLx Aperture <noreply@aperture.merlx.org>"
|
| 10 |
|
| 11 |
async def send_completion_email(to_email: str, job_id: str, aoi_name: str) -> bool:
|
| 12 |
if not RESEND_API_KEY:
|
|
|
|
| 21 |
The satellite analysis for <strong>{aoi_name}</strong> is complete.
|
| 22 |
</p>
|
| 23 |
<p style="font-size: 11px; color: #6B6B6B; margin-top: 20px;">
|
| 24 |
+
Generated by MERLx Aperture using open satellite data.
|
| 25 |
</p>
|
| 26 |
</div>
|
| 27 |
"""
|
|
|
|
| 30 |
resp = await client.post(
|
| 31 |
"https://api.resend.com/emails",
|
| 32 |
headers={"Authorization": f"Bearer {RESEND_API_KEY}"},
|
| 33 |
+
json={"from": FROM_EMAIL, "to": [to_email], "subject": f"MERLx Aperture: Analysis ready — {aoi_name}", "html": html},
|
| 34 |
)
|
| 35 |
return resp.status_code == 200
|
app/main.py
CHANGED
|
@@ -30,7 +30,7 @@ def create_app(db_path: str = "aperture.db", run_worker: bool = False) -> FastAP
|
|
| 30 |
if worker_task is not None:
|
| 31 |
worker_task.cancel()
|
| 32 |
|
| 33 |
-
app = FastAPI(title="Aperture", lifespan=lifespan)
|
| 34 |
init_jobs(db)
|
| 35 |
app.include_router(jobs_router)
|
| 36 |
app.include_router(indicators_router)
|
|
@@ -77,7 +77,7 @@ def create_app(db_path: str = "aperture.db", run_worker: bool = False) -> FastAP
|
|
| 77 |
async def serve_index():
|
| 78 |
if _INDEX_HTML.exists():
|
| 79 |
return HTMLResponse(content=_INDEX_HTML.read_text(encoding="utf-8"))
|
| 80 |
-
return HTMLResponse(content="<h1>Aperture</h1><p>Frontend not found.</p>")
|
| 81 |
|
| 82 |
return app
|
| 83 |
|
|
|
|
| 30 |
if worker_task is not None:
|
| 31 |
worker_task.cancel()
|
| 32 |
|
| 33 |
+
app = FastAPI(title="MERLx Aperture", lifespan=lifespan)
|
| 34 |
init_jobs(db)
|
| 35 |
app.include_router(jobs_router)
|
| 36 |
app.include_router(indicators_router)
|
|
|
|
| 77 |
async def serve_index():
|
| 78 |
if _INDEX_HTML.exists():
|
| 79 |
return HTMLResponse(content=_INDEX_HTML.read_text(encoding="utf-8"))
|
| 80 |
+
return HTMLResponse(content="<h1>MERLx Aperture</h1><p>Frontend not found.</p>")
|
| 81 |
|
| 82 |
return app
|
| 83 |
|
app/outputs/report.py
CHANGED
|
@@ -229,7 +229,7 @@ def generate_pdf_report(
|
|
| 229 |
canvas.setFont("Helvetica", 7)
|
| 230 |
canvas.setFillColor(INK_MUTED)
|
| 231 |
footer_text = (
|
| 232 |
-
f"Aperture Situation Report \u2014 {aoi.name} \u2014 "
|
| 233 |
f"{time_range.start} to {time_range.end} \u2014 "
|
| 234 |
f"Page {doc.page}"
|
| 235 |
)
|
|
@@ -242,8 +242,8 @@ def generate_pdf_report(
|
|
| 242 |
output_path,
|
| 243 |
pagesize=A4,
|
| 244 |
pageTemplates=[template],
|
| 245 |
-
title=f"Aperture Report — {aoi.name}",
|
| 246 |
-
author="
|
| 247 |
)
|
| 248 |
doc.pageBackgrounds = [colors.white]
|
| 249 |
|
|
@@ -255,7 +255,7 @@ def generate_pdf_report(
|
|
| 255 |
from datetime import datetime as _dt, timezone as _tz
|
| 256 |
generated_at = _dt.now(_tz.utc).strftime("%Y-%m-%d %H:%M UTC")
|
| 257 |
|
| 258 |
-
story.append(Paragraph("Aperture Situation Report", styles["title"]))
|
| 259 |
story.append(Paragraph(aoi.name, styles["subtitle"]))
|
| 260 |
story.append(
|
| 261 |
Paragraph(
|
|
@@ -397,10 +397,10 @@ def generate_pdf_report(
|
|
| 397 |
story.append(HRFlowable(width="100%", thickness=0.5, color=colors.HexColor("#D8D5CF")))
|
| 398 |
story.append(Spacer(1, 3 * mm))
|
| 399 |
disclaimer = (
|
| 400 |
-
"This report has been generated automatically by
|
| 401 |
"remote sensing data. Results are intended to support humanitarian situation analysis "
|
| 402 |
"and should be interpreted alongside ground-truth information and expert judgement. "
|
| 403 |
-
"Aperture makes no warranty as to the accuracy or completeness of the data presented. "
|
| 404 |
"All indicators are based on open-source satellite imagery and publicly available "
|
| 405 |
"geospatial datasets. Temporal coverage, cloud contamination, and sensor resolution "
|
| 406 |
"may affect the reliability of individual indicators. Users are encouraged to review "
|
|
|
|
| 229 |
canvas.setFont("Helvetica", 7)
|
| 230 |
canvas.setFillColor(INK_MUTED)
|
| 231 |
footer_text = (
|
| 232 |
+
f"MERLx Aperture \u2014 Situation Report \u2014 {aoi.name} \u2014 "
|
| 233 |
f"{time_range.start} to {time_range.end} \u2014 "
|
| 234 |
f"Page {doc.page}"
|
| 235 |
)
|
|
|
|
| 242 |
output_path,
|
| 243 |
pagesize=A4,
|
| 244 |
pageTemplates=[template],
|
| 245 |
+
title=f"MERLx Aperture — Situation Report — {aoi.name}",
|
| 246 |
+
author="MERLx Aperture",
|
| 247 |
)
|
| 248 |
doc.pageBackgrounds = [colors.white]
|
| 249 |
|
|
|
|
| 255 |
from datetime import datetime as _dt, timezone as _tz
|
| 256 |
generated_at = _dt.now(_tz.utc).strftime("%Y-%m-%d %H:%M UTC")
|
| 257 |
|
| 258 |
+
story.append(Paragraph("MERLx Aperture — Situation Report", styles["title"]))
|
| 259 |
story.append(Paragraph(aoi.name, styles["subtitle"]))
|
| 260 |
story.append(
|
| 261 |
Paragraph(
|
|
|
|
| 397 |
story.append(HRFlowable(width="100%", thickness=0.5, color=colors.HexColor("#D8D5CF")))
|
| 398 |
story.append(Spacer(1, 3 * mm))
|
| 399 |
disclaimer = (
|
| 400 |
+
"This report has been generated automatically by MERLx Aperture using satellite "
|
| 401 |
"remote sensing data. Results are intended to support humanitarian situation analysis "
|
| 402 |
"and should be interpreted alongside ground-truth information and expert judgement. "
|
| 403 |
+
"MERLx Aperture makes no warranty as to the accuracy or completeness of the data presented. "
|
| 404 |
"All indicators are based on open-source satellite imagery and publicly available "
|
| 405 |
"geospatial datasets. Temporal coverage, cloud contamination, and sensor resolution "
|
| 406 |
"may affect the reliability of individual indicators. Users are encouraged to review "
|
frontend/index.html
CHANGED
|
@@ -3,7 +3,7 @@
|
|
| 3 |
<head>
|
| 4 |
<meta charset="UTF-8" />
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 6 |
-
<title>Aperture</title>
|
| 7 |
|
| 8 |
<!-- MERLx Design System -->
|
| 9 |
<link rel="stylesheet" href="/static/css/merlx.css" />
|
|
@@ -86,15 +86,20 @@
|
|
| 86 |
MERL<span style="color: var(--iris)">x</span>
|
| 87 |
</div>
|
| 88 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 89 |
<!-- Headline -->
|
| 90 |
<h1 class="landing-headline">
|
| 91 |
-
|
| 92 |
</h1>
|
| 93 |
|
| 94 |
<!-- Sub-copy -->
|
| 95 |
<p class="landing-sub">
|
| 96 |
-
|
| 97 |
-
|
| 98 |
</p>
|
| 99 |
|
| 100 |
<!-- CTA -->
|
|
|
|
| 3 |
<head>
|
| 4 |
<meta charset="UTF-8" />
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 6 |
+
<title>MERLx Aperture</title>
|
| 7 |
|
| 8 |
<!-- MERLx Design System -->
|
| 9 |
<link rel="stylesheet" href="/static/css/merlx.css" />
|
|
|
|
| 86 |
MERL<span style="color: var(--iris)">x</span>
|
| 87 |
</div>
|
| 88 |
|
| 89 |
+
<!-- Subtitle -->
|
| 90 |
+
<div class="landing-subtitle" style="font-family: 'DM Serif Display', serif; font-style: italic; font-size: var(--text-lg); color: var(--ink-muted); margin-top: var(--space-3);">
|
| 91 |
+
Aperture
|
| 92 |
+
</div>
|
| 93 |
+
|
| 94 |
<!-- Headline -->
|
| 95 |
<h1 class="landing-headline">
|
| 96 |
+
AI-enhanced satellite analysis for humanitarian programme teams.
|
| 97 |
</h1>
|
| 98 |
|
| 99 |
<!-- Sub-copy -->
|
| 100 |
<p class="landing-sub">
|
| 101 |
+
Draw your area, choose your indicators, get evidence-grade
|
| 102 |
+
satellite analysis delivered — using free, open data.
|
| 103 |
</p>
|
| 104 |
|
| 105 |
<!-- CTA -->
|
pyproject.toml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
[project]
|
| 2 |
name = "aperture"
|
| 3 |
version = "0.1.0"
|
| 4 |
-
description = "
|
| 5 |
requires-python = ">=3.11"
|
| 6 |
dependencies = [
|
| 7 |
"fastapi>=0.110.0",
|
|
|
|
| 1 |
[project]
|
| 2 |
name = "aperture"
|
| 3 |
version = "0.1.0"
|
| 4 |
+
description = "MERLx Aperture — AI-enhanced satellite analysis for humanitarian programme teams"
|
| 5 |
requires-python = ">=3.11"
|
| 6 |
dependencies = [
|
| 7 |
"fastapi>=0.110.0",
|