Spaces:
Runtime error
Runtime error
File size: 5,985 Bytes
5752a28 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | """Generate synthetic fintech UI screenshots containing dark-pattern copy.
The screenshots are plain rendered UI with real text so Tesseract can read
them and the classifier has something genuine to detect. Run once:
python generate_samples.py
Outputs PNGs into ./samples/ (served by Flask at /api/samples/<name>).
"""
from PIL import Image, ImageDraw, ImageFont
import os
OUT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "samples")
os.makedirs(OUT_DIR, exist_ok=True)
W, H = 900, 640
BG = (248, 249, 252)
CARD = (255, 255, 255)
INK = (24, 28, 40)
MUTED = (110, 118, 135)
ACCENT = (79, 70, 229)
DANGER = (220, 53, 69)
WARN_BG = (255, 243, 205)
WARN_INK = (133, 100, 4)
GREEN = (25, 135, 84)
def font(size, bold=False):
names = ["arialbd.ttf"] if bold else ["arial.ttf"]
for name in names + ["DejaVuSans-Bold.ttf" if bold else "DejaVuSans.ttf"]:
try:
return ImageFont.truetype(name, size)
except OSError:
continue
return ImageFont.load_default()
def card(d, x0, y0, x1, y1, fill=CARD, outline=(225, 228, 235)):
d.rounded_rectangle([x0, y0, x1, y1], radius=12, fill=fill, outline=outline, width=1)
def button(d, x0, y0, x1, y1, label, fill=ACCENT, ink=(255, 255, 255), size=20, bold=True):
d.rounded_rectangle([x0, y0, x1, y1], radius=8, fill=fill)
f = font(size, bold)
tw = d.textlength(label, font=f)
d.text(((x0 + x1 - tw) / 2, (y0 + y1) / 2 - size / 2 - 2), label, font=f, fill=ink)
def make_checkout():
img = Image.new("RGB", (W, H), BG)
d = ImageDraw.Draw(img)
d.rectangle([0, 0, W, 64], fill=(30, 34, 50))
d.text((30, 20), "PayVault | Secure Checkout", font=font(22, True), fill=(255, 255, 255))
card(d, 30, 90, 560, 600)
d.text((55, 110), "Premium Trading Plan", font=font(26, True), fill=INK)
d.text((55, 150), "$29.99 / month", font=font(22), fill=MUTED)
d.rounded_rectangle([55, 195, 535, 245], radius=8, fill=WARN_BG)
d.text((70, 207), "Hurry! Offer expires in 04:59 minutes", font=font(20, True), fill=WARN_INK)
d.rounded_rectangle([55, 260, 535, 310], radius=8, fill=(253, 232, 232))
d.text((70, 272), "Only 2 spots left at this price!", font=font(20, True), fill=DANGER)
d.text((55, 335), "17 people are viewing this offer right now", font=font(18), fill=MUTED)
d.text((55, 370), "1,358 traders upgraded this week", font=font(18), fill=MUTED)
button(d, 55, 430, 535, 485, "CLAIM MY DISCOUNT NOW")
d.text((150, 510), "No thanks, I prefer losing money", font=font(15), fill=(180, 184, 195))
card(d, 590, 90, 870, 600)
d.text((615, 110), "Order Summary", font=font(20, True), fill=INK)
d.text((615, 155), "Plan", font=font(16), fill=MUTED)
d.text((800, 155), "$29.99", font=font(16), fill=INK)
d.text((615, 185), "Priority support", font=font(16), fill=MUTED)
d.text((800, 185), "$4.99", font=font(16), fill=INK)
d.line([615, 225, 845, 225], fill=(225, 228, 235), width=1)
d.text((615, 240), "Total today", font=font(18, True), fill=INK)
d.text((790, 240), "$34.98", font=font(18, True), fill=INK)
img.save(os.path.join(OUT_DIR, "checkout_urgency.png"))
def make_cancellation():
img = Image.new("RGB", (W, H), BG)
d = ImageDraw.Draw(img)
d.rectangle([0, 0, W, 64], fill=(30, 34, 50))
d.text((30, 20), "CoinNest | Account Settings", font=font(22, True), fill=(255, 255, 255))
card(d, 150, 110, 750, 560)
d.text((185, 140), "Wait! Before you go...", font=font(28, True), fill=INK)
d.text((185, 195), "Are you sure you want to cancel? You will lose all", font=font(19), fill=INK)
d.text((185, 225), "your rewards and your exclusive member benefits", font=font(19), fill=INK)
d.text((185, 255), "will be gone forever.", font=font(19), fill=INK)
d.text((185, 305), "93% of members regret cancelling within a month", font=font(17), fill=MUTED)
button(d, 185, 360, 715, 415, "KEEP MY BENEFITS", fill=GREEN)
button(d, 185, 430, 715, 480, "Remind me later", fill=(235, 237, 242), ink=MUTED, bold=False)
d.text((340, 505), "continue to cancellation step 1 of 6", font=font(13), fill=(195, 198, 207))
img.save(os.path.join(OUT_DIR, "cancel_confirmshaming.png"))
def make_signup():
img = Image.new("RGB", (W, H), BG)
d = ImageDraw.Draw(img)
d.rectangle([0, 0, W, 64], fill=(30, 34, 50))
d.text((30, 20), "LoanLeap | Create Account", font=font(22, True), fill=(255, 255, 255))
card(d, 120, 100, 780, 580)
d.text((155, 125), "You're almost done!", font=font(26, True), fill=INK)
def checkbox(y, label, sub, checked=True):
d.rounded_rectangle([155, y, 179, y + 24], radius=5,
fill=ACCENT if checked else CARD,
outline=(200, 203, 212), width=1)
if checked:
d.line([160, y + 12, 166, y + 18], fill=(255, 255, 255), width=3)
d.line([166, y + 18, 175, y + 6], fill=(255, 255, 255), width=3)
d.text((195, y), label, font=font(18, True), fill=INK)
d.text((195, y + 28), sub, font=font(15), fill=MUTED)
checkbox(180, "Add Payment Protection Plus (+$9.99/mo)",
"Automatically added to protect your transactions")
checkbox(255, "Enroll in Premium Credit Monitoring (+$14.99/mo)",
"Free trial converts to paid plan after 7 days")
checkbox(330, "Share my data with trusted marketing partners",
"By continuing you agree to receive personalised offers")
d.text((155, 410), "By clicking Continue you accept the Terms, the Fee Schedule,", font=font(14), fill=MUTED)
d.text((155, 432), "and authorise recurring charges to your saved card.", font=font(14), fill=MUTED)
button(d, 155, 475, 745, 530, "CONTINUE")
img.save(os.path.join(OUT_DIR, "signup_sneaking.png"))
if __name__ == "__main__":
make_checkout()
make_cancellation()
make_signup()
print(f"Saved 3 sample screenshots to {OUT_DIR}")
|