94 lines
3.6 KiB
Python
94 lines
3.6 KiB
Python
"""Aperçu design hors-ligne : rend dashboard.html avec des données fictives en PNG
|
|
paysage (1680x1264, niveaux de gris, sans rotation), pour itérer sur le design sans
|
|
dépendre des intégrations réseau (Claude, météo, NAS, HA).
|
|
|
|
Usage: .venv/bin/python ../dev/preview.py [sortie.png]
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
import io
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
|
from PIL import Image
|
|
from playwright.async_api import async_playwright
|
|
|
|
BACKEND = Path(__file__).resolve().parent.parent / "backend"
|
|
TEMPLATES = BACKEND / "templates"
|
|
WIDTH, HEIGHT = 1680, 1264
|
|
|
|
sys.path.insert(0, str(BACKEND))
|
|
from fonts import font_face_css # noqa: E402
|
|
|
|
env = Environment(
|
|
loader=FileSystemLoader(str(TEMPLATES)),
|
|
autoescape=select_autoescape(["html"]),
|
|
)
|
|
|
|
CTX = {
|
|
"width": WIDTH,
|
|
"height": HEIGHT,
|
|
"fonts": font_face_css(),
|
|
"time": "14:32",
|
|
"dow": "lundi",
|
|
"date": "15 juin",
|
|
"updated": "14:32",
|
|
"stale": False,
|
|
"weather": {
|
|
"ok": True, "kind": "partly", "temp": 21.4, "feels_like": 20.1,
|
|
"temp_min": 14.0, "temp_max": 24.0, "precip_prob": 20,
|
|
"label": "Peu nuageux",
|
|
},
|
|
"claude": {
|
|
"ok": True,
|
|
"extra": {"label": "Crédits API : 38 % restant"},
|
|
"burn_rate": 1820,
|
|
},
|
|
"gauges": [
|
|
{"name": "Session (5 h)", "remaining": 64, "resets_in": "2 h 10", "extra": ""},
|
|
{"name": "Hebdo (7 j)", "remaining": 12, "resets_in": "3 j", "extra": "Opus 41% rest."},
|
|
],
|
|
"codex": {
|
|
"ok": True, "plan_type": "plus", "limited": False,
|
|
"gauges": [
|
|
{"name": "Session (5 h)", "remaining": 78, "resets_in": "1 h 40"},
|
|
{"name": "Hebdo (7 j)", "remaining": 33, "resets_in": "4 j"},
|
|
],
|
|
},
|
|
"nas": {
|
|
"ok": True,
|
|
"disks": [
|
|
{"label": "Volume 1", "percent": 72, "free_human": "1,4 To"},
|
|
{"label": "Volume 2", "percent": 41, "free_human": "5,8 To"},
|
|
],
|
|
"docker_running": 18, "docker_total": 19, "docker_unhealthy": 1,
|
|
"vpn_ok": True, "vpn_port": 51820,
|
|
},
|
|
"trackers": [
|
|
{"ok": True, "label": "c411", "ratio_h": "1,04", "has_io": True, "up_h": "378 Go", "down_h": "365 Go", "tokens": None},
|
|
{"ok": True, "label": "torr9", "ratio_h": "1,62", "has_io": True, "up_h": "226 Go", "down_h": "140 Go", "tokens": 2168, "tokens_h": "2 168", "tokens_label": "token"},
|
|
{"ok": True, "label": "tr4ker", "ratio_h": "5233,52", "has_io": True, "up_h": "5,62 To", "down_h": "1 Go", "tokens": 223, "tokens_h": "223", "tokens_label": "token"},
|
|
{"ok": True, "label": "yggreborn", "ratio_h": "7,63", "has_io": True, "up_h": "60,55 Go", "down_h": "7,94 Go", "tokens": None},
|
|
],
|
|
"kobo": {"ok": True, "percent": 63, "charging": False, "low": False, "stale": False},
|
|
}
|
|
|
|
|
|
async def main() -> None:
|
|
out = Path(sys.argv[1]) if len(sys.argv) > 1 else Path(__file__).parent / "preview.png"
|
|
html = env.get_template("dashboard.html").render(**CTX)
|
|
async with async_playwright() as p:
|
|
browser = await p.chromium.launch(args=["--no-sandbox", "--disable-dev-shm-usage"])
|
|
page = await browser.new_page(viewport={"width": WIDTH, "height": HEIGHT}, device_scale_factor=1)
|
|
await page.set_content(html, wait_until="networkidle")
|
|
png = await page.screenshot(type="png", clip={"x": 0, "y": 0, "width": WIDTH, "height": HEIGHT})
|
|
await browser.close()
|
|
Image.open(io.BytesIO(png)).convert("L").save(out)
|
|
print(f"écrit {out}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|