uptime / browser /visual_regression.py
HuB
Deploy webguard to Hugging Face Space
b987c84
import os
import hashlib
from PIL import Image, ImageChops
import io
from browser.screenshot import take
_baselines: dict[str, str] = {} # url β†’ baseline screenshot path
async def check(url: str) -> dict:
"""Compare current screenshot with baseline. Returns diff report."""
current_path = await take(url, label="regression")
if current_path.startswith("screenshot_error"):
return {"check": "visual_regression", "overall": "error", "summary": current_path}
if url not in _baselines:
_baselines[url] = current_path
return {
"check": "visual_regression",
"overall": "ok",
"baseline_set": True,
"summary": "βœ… Baseline screenshot saved β€” will compare next run",
}
baseline_path = _baselines[url]
if not os.path.exists(baseline_path):
_baselines[url] = current_path
return {
"check": "visual_regression",
"overall": "ok",
"summary": "βœ… Baseline reset (previous file missing)",
}
try:
img_base = Image.open(baseline_path).convert("RGB")
img_current = Image.open(current_path).convert("RGB")
# Resize to same dimensions for comparison
if img_base.size != img_current.size:
img_current = img_current.resize(img_base.size, Image.LANCZOS)
diff = ImageChops.difference(img_base, img_current)
diff_pixels = sum(sum(row) for row in diff.getdata())
total_pixels= img_base.width * img_base.height * 3 * 255
diff_pct = round((diff_pixels / total_pixels) * 100, 2)
if diff_pct > 20:
status = "error"
summary = f"🚨 Visual change detected: {diff_pct}% of page changed!"
elif diff_pct > 5:
status = "warning"
summary = f"⚠️ Minor visual change: {diff_pct}% of page changed"
else:
status = "ok"
summary = f"βœ… No significant visual change ({diff_pct}%)"
# Update baseline on major accepted change
_baselines[url] = current_path
return {
"check": "visual_regression",
"overall": status,
"diff_percent": diff_pct,
"baseline_path": baseline_path,
"current_path": current_path,
"summary": summary,
}
except Exception as e:
return {
"check": "visual_regression",
"overall": "error",
"summary": f"❌ Visual comparison failed: {e}",
}