Create app.py
Browse files
app.py
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
import types
|
| 3 |
+
import re
|
| 4 |
+
|
| 5 |
+
# π¨ DYNAMIC FIX: Python 3.13 Compatibility Patches
|
| 6 |
+
if 'audioop' not in sys.modules:
|
| 7 |
+
dummy_audioop = types.ModuleType('audioop')
|
| 8 |
+
dummy_audioop.error = Exception
|
| 9 |
+
sys.modules['audioop'] = dummy_audioop
|
| 10 |
+
|
| 11 |
+
import gradio as gr
|
| 12 |
+
|
| 13 |
+
def scan_dark_patterns(raw_html_or_text):
|
| 14 |
+
if not raw_html_or_text.strip():
|
| 15 |
+
return "β οΈ Error: Please paste website HTML or text content to audit!"
|
| 16 |
+
|
| 17 |
+
text_to_scan = raw_html_or_text.strip()
|
| 18 |
+
|
| 19 |
+
# π Technical Heuristics Matrix (Detecting E-Commerce Manipulation)
|
| 20 |
+
patterns = {
|
| 21 |
+
"False Urgency & Fake Timers": [
|
| 22 |
+
r"(?i)ends in \d+m", r"(?i)hurry up", r"(?i)limited time offer",
|
| 23 |
+
r"(?i)only \d+ left", r"(?i)demand is high", r"(?i)selling fast",
|
| 24 |
+
r"stock running low", r"buying right now"
|
| 25 |
+
],
|
| 26 |
+
"Social Proof Manipulation (Fake Reviews)": [
|
| 27 |
+
r"(?i)verified buyer", r"(?i)everyone else bought", r"(?i)someone from .* just purchased",
|
| 28 |
+
r"(?i)5-star rated by thousand", r"trusted by millions"
|
| 29 |
+
],
|
| 30 |
+
"Hidden Charges & Sneaking": [
|
| 31 |
+
r"(?i)hidden fee", r"(?i)service charge added", r"(?i)protection plan auto-renew",
|
| 32 |
+
r"(?i)convenience fee", r"handling charges apply at checkout"
|
| 33 |
+
],
|
| 34 |
+
"Forced Continuity & Misdirection": [
|
| 35 |
+
r"(?i)subscription auto-renews", r"(?i)no thanks, i hate saving money",
|
| 36 |
+
r"(?i)keep insurance active", r"cancel anytime\* condition"
|
| 37 |
+
]
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
detected_logs = []
|
| 41 |
+
total_violations = 0
|
| 42 |
+
risk_score = 0
|
| 43 |
+
|
| 44 |
+
# Analyze the data stream strings natively
|
| 45 |
+
for category, regex_list in patterns.items():
|
| 46 |
+
matched_triggers = []
|
| 47 |
+
for regex in regex_list:
|
| 48 |
+
matches = re.findall(regex, text_to_scan)
|
| 49 |
+
if matches:
|
| 50 |
+
matched_triggers.append(f"'{matches[0]}'")
|
| 51 |
+
total_violations += len(matches)
|
| 52 |
+
|
| 53 |
+
if matched_triggers:
|
| 54 |
+
icon = "π¨" if "Charges" in category or "Urgency" in category else "β οΈ"
|
| 55 |
+
detected_logs.append(
|
| 56 |
+
f"<li><b>{icon} {category}:</b> Detected manipulation markers: "
|
| 57 |
+
f"<span style='background-color: #fee2e2; color: #991b1b; padding: 2px 6px; border-radius: 4px; font-size: 13px;'>{', '.join(matched_triggers)}</span></li>"
|
| 58 |
+
)
|
| 59 |
+
|
| 60 |
+
# Calculate Data Risk Scoring Matrix
|
| 61 |
+
# Formula: Risk Index = (Violations * 25) capped at 100%
|
| 62 |
+
risk_score = min(100, total_violations * 25)
|
| 63 |
+
|
| 64 |
+
if risk_score >= 75:
|
| 65 |
+
verdict = "π΄ HIGH RISK (Highly Manipulative Dark Patterns Detected)"
|
| 66 |
+
verdict_color = "#ef4444"
|
| 67 |
+
elif risk_score >= 40:
|
| 68 |
+
verdict = "π‘ MEDIUM RISK (Deceptive Tactics Used)"
|
| 69 |
+
verdict_color = "#eab308"
|
| 70 |
+
else:
|
| 71 |
+
verdict = "π’ CLEAN / LOW RISK (Fair Consumer Practice Layout)"
|
| 72 |
+
verdict_color = "#22c55e"
|
| 73 |
+
|
| 74 |
+
# Render Report Outputs (Strict Inline Theme Protection)
|
| 75 |
+
if not detected_logs:
|
| 76 |
+
analysis_report = f"""
|
| 77 |
+
<div style='color: #0f172a !important;'>
|
| 78 |
+
<h3 style='color: #22c55e !important; margin-bottom: 5px;'>π‘οΈ Compliance Status: SECURE</h3>
|
| 79 |
+
<p style='color: #475569 !important; margin: 0;'>ββββββββββββββββββββββββββββββββββββββ</p>
|
| 80 |
+
<p style='margin-top: 15px; font-weight: bold; color: #1e293b;'>Risk Score: <span style='color: #22c55e;'>0%</span></p>
|
| 81 |
+
<p style='color: #334155;'>No consumer manipulation markers or deceptive hidden layers were identified in this web data snapshot.</p>
|
| 82 |
+
</div>
|
| 83 |
+
"""
|
| 84 |
+
else:
|
| 85 |
+
log_html = "".join(detected_logs)
|
| 86 |
+
analysis_report = f"""
|
| 87 |
+
<div style='color: #0f172a !important;'>
|
| 88 |
+
<h3 style='color: {verdict_color} !important; margin-bottom: 5px;'>π‘οΈ Audit Result: {verdict}</h3>
|
| 89 |
+
<p style='color: #475569 !important; margin: 0;'>ββββββββββββββββββββββββββββββββββββββ</p>
|
| 90 |
+
|
| 91 |
+
<p style='margin-top: 15px; font-weight: 100; color: #1e293b; font-size: 16px;'>
|
| 92 |
+
<b>Consumer Threat Index:</b>
|
| 93 |
+
<span style='background-color: {verdict_color}; color: #ffffff; padding: 3px 10px; border-radius: 6px; font-weight: bold;'>{risk_score}% Risk</span>
|
| 94 |
+
</p>
|
| 95 |
+
|
| 96 |
+
<h4 style='color: #1e293b; margin: 15px 0 5px 0;'>π Deceptive Breakdown (ΩΨ±ΫΨ¨ Ϊ©Ψ§Ψ±Ϋ Ϊ©Ϋ ΨͺΩΨ΅ΫΩ):</h4>
|
| 97 |
+
<ul style='padding-left: 20px; margin: 0; color: #334155;'>
|
| 98 |
+
{log_html}
|
| 99 |
+
</ul>
|
| 100 |
+
|
| 101 |
+
<p style='margin-top: 20px; font-size: 13px; color: #2563eb; font-style: italic; font-weight: 500;'>
|
| 102 |
+
π‘ Shield Advice: Do not make panic purchases based on countdown counters or pre-checked insurance tickboxes. Look out for unexpected costs on final verification pages.
|
| 103 |
+
</p>
|
| 104 |
+
</div>
|
| 105 |
+
"""
|
| 106 |
+
|
| 107 |
+
return analysis_report
|
| 108 |
+
|
| 109 |
+
# Clean White / Cyber Shield Theme CSS
|
| 110 |
+
custom_css = """
|
| 111 |
+
body, .gradio-container { background-color: #f8fafc !important; color: #0f172a !important; font-family: 'Segoe UI', system-ui, sans-serif; }
|
| 112 |
+
.shield-btn { background-color: #2563eb !important; color: #ffffff !important; font-weight: bold !important; border-radius: 8px !important; font-size: 16px !important; border: none !important; margin-top: 10px; }
|
| 113 |
+
.shield-btn:hover { background-color: #1d4ed8 !important; box-shadow: 0 4px 12px rgba(37,99,235,0.2); }
|
| 114 |
+
.panel-layout { border: 1px solid #e2e8f0 !important; border-radius: 12px; padding: 20px; background: #ffffff !important; box-shadow: 0 1px 3px rgba(0,0,0,0.05); }
|
| 115 |
+
textarea { background-color: #ffffff !important; color: #0f172a !important; border: 1px solid #cbd5e1 !important; font-family: monospace !important; }
|
| 116 |
+
label { color: #334155 !important; font-weight: 600 !important; }
|
| 117 |
+
.prose, .prose * { color: #0f172a !important; }
|
| 118 |
+
"""
|
| 119 |
+
|
| 120 |
+
with gr.Blocks(title="Consumer Shield v1.0", css=custom_css, theme=gr.themes.Default(primary_hue="blue", secondary_hue="slate")) as demo:
|
| 121 |
+
gr.HTML(
|
| 122 |
+
"""
|
| 123 |
+
<div style="text-align: center; margin-bottom: 25px; padding: 20px; background: #2563eb; border-radius: 12px; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1);">
|
| 124 |
+
<h1 style='margin: 0; font-size: 28px; color: #ffffff; letter-spacing: 0.5px; font-weight: 700;'>π‘οΈ DARK-PATTERNS CONSUMER SHIELD</h1>
|
| 125 |
+
<p style='margin: 6px 0 0 0; color: #dbeafe; font-size: 14px; font-weight: 500;'>Serverless E-Commerce Protection & Pattern Audit Matrix // Zero-Latency Scanner</p>
|
| 126 |
+
</div>
|
| 127 |
+
"""
|
| 128 |
+
)
|
| 129 |
+
|
| 130 |
+
with gr.Row():
|
| 131 |
+
with gr.Column(scale=5, elem_classes="panel-layout"):
|
| 132 |
+
gr.Markdown("### π Web Scraping & Ingestion Node")
|
| 133 |
+
source_input = gr.Textbox(
|
| 134 |
+
label="Paste Store Copy, Product Descriptions, or Web Raw HTML",
|
| 135 |
+
placeholder="Example:\nHurry up! Only 2 items left in stock. Verified buyers are purchasing right now! Subscription auto-renews with a handling fee.",
|
| 136 |
+
lines=12
|
| 137 |
+
)
|
| 138 |
+
scan_btn = gr.Button("π‘οΈ Launch Real-Time Forensic Audit", elem_classes="shield-btn")
|
| 139 |
+
|
| 140 |
+
with gr.Column(scale=4, elem_classes="panel-layout"):
|
| 141 |
+
gr.Markdown("### π Shield Compliance Output Dashboard")
|
| 142 |
+
audit_output = gr.Markdown("`Security Engine active. Waiting for raw e-commerce matrix data streams...`", elem_id="shield-output")
|
| 143 |
+
|
| 144 |
+
scan_btn.click(
|
| 145 |
+
fn=scan_dark_patterns,
|
| 146 |
+
inputs=[source_input],
|
| 147 |
+
outputs=[audit_output]
|
| 148 |
+
)
|
| 149 |
+
|
| 150 |
+
demo.launch()
|