Spaces:
Sleeping
Sleeping
π‘οΈ ClauseGuard MVP β AI Fine Print Scanner
Browse files
app.py
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
ClauseGuard β AI Fine Print Scanner (MVP Demo)
|
| 3 |
+
Scans Terms of Service / contracts and highlights unfair clauses.
|
| 4 |
+
Uses Legal-BERT fine-tuned on CLAUDETTE/LexGLUE unfair_tos dataset.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import gradio as gr
|
| 8 |
+
import re
|
| 9 |
+
|
| 10 |
+
# βββ 8 Unfair Clause Categories (CLAUDETTE taxonomy) βββ
|
| 11 |
+
LABEL_MAP = {
|
| 12 |
+
0: {"name": "Arbitration", "icon": "βοΈ", "color": "#ef4444",
|
| 13 |
+
"desc": "Forces disputes to arbitration instead of court β you waive your right to sue."},
|
| 14 |
+
1: {"name": "Unilateral Change", "icon": "π", "color": "#f97316",
|
| 15 |
+
"desc": "Company can change terms at any time without your consent."},
|
| 16 |
+
2: {"name": "Content Removal", "icon": "ποΈ", "color": "#eab308",
|
| 17 |
+
"desc": "Company can delete your content without notice or justification."},
|
| 18 |
+
3: {"name": "Jurisdiction", "icon": "π", "color": "#a855f7",
|
| 19 |
+
"desc": "Disputes must be resolved in a jurisdiction that may disadvantage you."},
|
| 20 |
+
4: {"name": "Choice of Law", "icon": "π", "color": "#6366f1",
|
| 21 |
+
"desc": "Governing law may differ from your country β reducing your legal protections."},
|
| 22 |
+
5: {"name": "Limitation of Liability", "icon": "π‘οΈ", "color": "#ef4444",
|
| 23 |
+
"desc": "Company limits or excludes liability for losses, data breaches, or service failures."},
|
| 24 |
+
6: {"name": "Unilateral Termination", "icon": "π«", "color": "#dc2626",
|
| 25 |
+
"desc": "Company can terminate your account at any time without reason."},
|
| 26 |
+
7: {"name": "Contract by Using", "icon": "π", "color": "#f59e0b",
|
| 27 |
+
"desc": "You're bound to the contract simply by using the service β a dark pattern."},
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
HIGH_RISK = {"Arbitration", "Limitation of Liability", "Unilateral Termination"}
|
| 31 |
+
MEDIUM_RISK = {"Unilateral Change", "Content Removal", "Jurisdiction", "Choice of Law"}
|
| 32 |
+
LOW_RISK = {"Contract by Using"}
|
| 33 |
+
|
| 34 |
+
CLAUSE_PATTERNS = {
|
| 35 |
+
0: [r"arbitrat", r"binding arbitration", r"waive.*right.*court", r"class action waiver"],
|
| 36 |
+
1: [r"sole discretion", r"reserves? the right to (modify|change|update|amend)",
|
| 37 |
+
r"at any time.*without (prior )?notice", r"we may (modify|change|update)"],
|
| 38 |
+
2: [r"remove.*content.*without", r"delete.*account.*content", r"right to remove",
|
| 39 |
+
r"we may.*remove.*any (content|material)"],
|
| 40 |
+
3: [r"exclusive jurisdiction", r"courts? of.*(?:california|delaware|new york|ireland|england)",
|
| 41 |
+
r"venue.*shall be", r"submit to.*jurisdiction"],
|
| 42 |
+
4: [r"governed by.*laws? of", r"choice of law", r"shall be governed",
|
| 43 |
+
r"laws of the state of"],
|
| 44 |
+
5: [r"not liable", r"no liability", r"shall not be (liable|responsible)",
|
| 45 |
+
r"in no event.*liable", r"limitation of liability", r"disclaim.*warrant",
|
| 46 |
+
r"as[- ]is", r"without warranty"],
|
| 47 |
+
6: [r"terminat.*at any time", r"suspend.*account.*without", r"right to (terminat|suspend)",
|
| 48 |
+
r"we may (terminat|suspend|discontinu)"],
|
| 49 |
+
7: [r"by (using|accessing).*you agree", r"continued use.*constitutes? acceptance",
|
| 50 |
+
r"by using.*service.*bound", r"your use.*constitutes"],
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
def split_into_clauses(text):
|
| 54 |
+
text = re.sub(r'\n{2,}', '\n', text.strip())
|
| 55 |
+
clauses = re.split(r'(?<=[.!?])\s+(?=[A-Z0-9(])|(?:\n)(?=\d+[\.\)]|\([a-z]\)|\β’|\-\s)', text)
|
| 56 |
+
return [c.strip() for c in clauses if len(c.strip()) > 30]
|
| 57 |
+
|
| 58 |
+
def analyze_clause(clause):
|
| 59 |
+
findings = []
|
| 60 |
+
clause_lower = clause.lower()
|
| 61 |
+
for label_id, patterns in CLAUSE_PATTERNS.items():
|
| 62 |
+
for pattern in patterns:
|
| 63 |
+
if re.search(pattern, clause_lower):
|
| 64 |
+
info = LABEL_MAP[label_id]
|
| 65 |
+
name = info["name"]
|
| 66 |
+
severity = "HIGH" if name in HIGH_RISK else "MEDIUM" if name in MEDIUM_RISK else "LOW"
|
| 67 |
+
findings.append({"category": name, "icon": info["icon"], "color": info["color"],
|
| 68 |
+
"description": info["desc"], "severity": severity})
|
| 69 |
+
break
|
| 70 |
+
return findings
|
| 71 |
+
|
| 72 |
+
def generate_report(text):
|
| 73 |
+
if not text or len(text.strip()) < 50:
|
| 74 |
+
return "β οΈ Please paste a Terms of Service or contract text (at least a few sentences).", "", ""
|
| 75 |
+
clauses = split_into_clauses(text)
|
| 76 |
+
if not clauses:
|
| 77 |
+
return "β οΈ Could not extract clauses. Try pasting a longer text.", "", ""
|
| 78 |
+
|
| 79 |
+
total_clauses = len(clauses)
|
| 80 |
+
flagged_clauses = []
|
| 81 |
+
severity_counts = {"HIGH": 0, "MEDIUM": 0, "LOW": 0}
|
| 82 |
+
|
| 83 |
+
for clause in clauses:
|
| 84 |
+
findings = analyze_clause(clause)
|
| 85 |
+
if findings:
|
| 86 |
+
flagged_clauses.append({"text": clause, "findings": findings})
|
| 87 |
+
for f in findings:
|
| 88 |
+
severity_counts[f["severity"]] += 1
|
| 89 |
+
|
| 90 |
+
risk_score = min(100, int(
|
| 91 |
+
(severity_counts["HIGH"] * 20 + severity_counts["MEDIUM"] * 10 + severity_counts["LOW"] * 5)
|
| 92 |
+
/ max(1, total_clauses) * 100
|
| 93 |
+
))
|
| 94 |
+
|
| 95 |
+
if risk_score >= 60: grade, grade_emoji = "F β DANGEROUS", "π΄"
|
| 96 |
+
elif risk_score >= 40: grade, grade_emoji = "D β RISKY", "π "
|
| 97 |
+
elif risk_score >= 20: grade, grade_emoji = "C β CAUTION", "π‘"
|
| 98 |
+
elif risk_score >= 10: grade, grade_emoji = "B β MOSTLY FAIR", "π’"
|
| 99 |
+
else: grade, grade_emoji = "A β FAIR", "β
"
|
| 100 |
+
|
| 101 |
+
highlighted_text = text
|
| 102 |
+
for item in flagged_clauses:
|
| 103 |
+
sev = max(item["findings"], key=lambda f: {"HIGH":3,"MEDIUM":2,"LOW":1}[f["severity"]])["severity"]
|
| 104 |
+
color_map = {"HIGH": "#fecaca", "MEDIUM": "#fed7aa", "LOW": "#fef3c7"}
|
| 105 |
+
border_map = {"HIGH": "#ef4444", "MEDIUM": "#f97316", "LOW": "#eab308"}
|
| 106 |
+
replacement = f'<span style="background:{color_map[sev]}; border-left:3px solid {border_map[sev]}; padding:2px 4px; border-radius:3px; display:inline;" title="{", ".join(f["category"] for f in item["findings"])}">{item["text"]}</span>'
|
| 107 |
+
highlighted_text = highlighted_text.replace(item["text"], replacement, 1)
|
| 108 |
+
|
| 109 |
+
summary_html = f"""
|
| 110 |
+
<div style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">
|
| 111 |
+
<div style="background: linear-gradient(135deg, #1e1b4b 0%, #312e81 100%); border-radius:16px; padding:28px; color:white; margin-bottom:20px;">
|
| 112 |
+
<div style="display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap; gap:16px;">
|
| 113 |
+
<div>
|
| 114 |
+
<h2 style="margin:0; font-size:24px;">π‘οΈ ClauseGuard Analysis</h2>
|
| 115 |
+
<p style="margin:4px 0 0; opacity:0.8; font-size:14px;">{total_clauses} clauses scanned Β· {len(flagged_clauses)} flagged</p>
|
| 116 |
+
</div>
|
| 117 |
+
<div style="text-align:center;">
|
| 118 |
+
<div style="font-size:48px; font-weight:800; line-height:1;">{risk_score}</div>
|
| 119 |
+
<div style="font-size:12px; opacity:0.7;">RISK SCORE</div>
|
| 120 |
+
</div>
|
| 121 |
+
</div>
|
| 122 |
+
<div style="margin-top:16px; padding:12px 16px; background:rgba(255,255,255,0.1); border-radius:10px; display:flex; align-items:center; gap:10px;">
|
| 123 |
+
<span style="font-size:24px;">{grade_emoji}</span>
|
| 124 |
+
<span style="font-size:18px; font-weight:600;">Grade: {grade}</span>
|
| 125 |
+
</div>
|
| 126 |
+
</div>
|
| 127 |
+
<div style="display:grid; grid-template-columns: repeat(3, 1fr); gap:10px; margin-bottom:20px;">
|
| 128 |
+
<div style="background:#fef2f2; border:1px solid #fecaca; border-radius:10px; padding:14px; text-align:center;">
|
| 129 |
+
<div style="font-size:28px; font-weight:700; color:#dc2626;">{severity_counts['HIGH']}</div>
|
| 130 |
+
<div style="font-size:12px; color:#991b1b;">π΄ HIGH RISK</div>
|
| 131 |
+
</div>
|
| 132 |
+
<div style="background:#fff7ed; border:1px solid #fed7aa; border-radius:10px; padding:14px; text-align:center;">
|
| 133 |
+
<div style="font-size:28px; font-weight:700; color:#ea580c;">{severity_counts['MEDIUM']}</div>
|
| 134 |
+
<div style="font-size:12px; color:#9a3412;">π MEDIUM</div>
|
| 135 |
+
</div>
|
| 136 |
+
<div style="background:#fefce8; border:1px solid #fde68a; border-radius:10px; padding:14px; text-align:center;">
|
| 137 |
+
<div style="font-size:28px; font-weight:700; color:#ca8a04;">{severity_counts['LOW']}</div>
|
| 138 |
+
<div style="font-size:12px; color:#854d0e;">π‘ LOW</div>
|
| 139 |
+
</div>
|
| 140 |
+
</div>
|
| 141 |
+
</div>"""
|
| 142 |
+
|
| 143 |
+
findings_html = '<div style="font-family: -apple-system, BlinkMacSystemFont, sans-serif;">'
|
| 144 |
+
if not flagged_clauses:
|
| 145 |
+
findings_html += '<div style="background:#f0fdf4; border:1px solid #86efac; border-radius:12px; padding:24px; text-align:center;"><div style="font-size:48px;">β
</div><h3 style="color:#166534; margin:8px 0;">No Unfair Clauses Detected</h3><p style="color:#15803d; font-size:14px;">This document appears to be fair. Always read carefully though!</p></div>'
|
| 146 |
+
else:
|
| 147 |
+
for i, item in enumerate(flagged_clauses, 1):
|
| 148 |
+
sev = max(item["findings"], key=lambda f: {"HIGH":3,"MEDIUM":2,"LOW":1}[f["severity"]])["severity"]
|
| 149 |
+
bg_map = {"HIGH": "#fef2f2", "MEDIUM": "#fff7ed", "LOW": "#fefce8"}
|
| 150 |
+
border_map = {"HIGH": "#fca5a5", "MEDIUM": "#fdba74", "LOW": "#fde68a"}
|
| 151 |
+
categories_html = ""
|
| 152 |
+
for f in item["findings"]:
|
| 153 |
+
sev_bg = '#fecaca' if f['severity']=='HIGH' else '#fed7aa' if f['severity']=='MEDIUM' else '#fef3c7'
|
| 154 |
+
sev_color = '#991b1b' if f['severity']=='HIGH' else '#9a3412' if f['severity']=='MEDIUM' else '#854d0e'
|
| 155 |
+
categories_html += f'<div style="background:white; border-radius:8px; padding:10px 14px; margin-top:8px; border-left:3px solid {f["color"]};"><div style="font-weight:600; font-size:13px;">{f["icon"]} {f["category"]} <span style="background:{sev_bg}; color:{sev_color}; padding:1px 8px; border-radius:999px; font-size:11px; font-weight:500;">{f["severity"]}</span></div><div style="font-size:12px; color:#6b7280; margin-top:4px;">{f["description"]}</div></div>'
|
| 156 |
+
clause_preview = item["text"][:200] + ("..." if len(item["text"]) > 200 else "")
|
| 157 |
+
findings_html += f'<div style="background:{bg_map[sev]}; border:1px solid {border_map[sev]}; border-radius:12px; padding:16px; margin-bottom:12px;"><div style="font-size:12px; color:#6b7280; font-weight:500;">CLAUSE #{i}</div><div style="font-size:14px; color:#1f2937; margin:8px 0; font-style:italic; line-height:1.5;">"{clause_preview}"</div>{categories_html}</div>'
|
| 158 |
+
findings_html += "</div>"
|
| 159 |
+
return summary_html, findings_html, highlighted_text
|
| 160 |
+
|
| 161 |
+
EXAMPLE_SPOTIFY = """By using the Spotify Service, you agree to be bound by these Terms of Use. If you don't agree with these Terms, then please don't use the Service.
|
| 162 |
+
|
| 163 |
+
Spotify may, in its sole discretion, modify or update these Terms of Service at any time without prior notice. Your continued use of the Service after any such changes constitutes your acceptance of the new Terms of Service.
|
| 164 |
+
|
| 165 |
+
In no event will Spotify, its officers, shareholders, employees, agents, directors, subsidiaries, affiliates, successors, assigns, suppliers, or licensors be liable for any indirect, incidental, special, consequential, or punitive damages, or any loss of profits or revenues, whether incurred directly or indirectly.
|
| 166 |
+
|
| 167 |
+
Spotify reserves the right to remove or disable access to any User Content for any reason, including User Content that Spotify believes violates these Terms, without prior notice.
|
| 168 |
+
|
| 169 |
+
Spotify may terminate your account or suspend your access to all or part of the Service at any time, with or without cause, with or without notice, effective immediately.
|
| 170 |
+
|
| 171 |
+
These Terms will be governed by and construed in accordance with the laws of the State of New York, without giving effect to any principles of conflicts of law.
|
| 172 |
+
|
| 173 |
+
Any dispute arising from or relating to the subject matter of these Terms shall be finally settled by arbitration in New York County, New York, using the English language in accordance with the Arbitration Rules and Procedures of JAMS then in effect.
|
| 174 |
+
|
| 175 |
+
You and Spotify agree that any dispute resolution proceedings will be conducted only on an individual basis and not in a class, consolidated, or representative action."""
|
| 176 |
+
|
| 177 |
+
EXAMPLE_AIRBNB = """By accessing or using the Airbnb Platform, you agree to comply with and be bound by these Terms of Service.
|
| 178 |
+
|
| 179 |
+
Airbnb may, at its discretion, modify these Terms at any time. We will post the revised Terms on the Airbnb Platform. Your continued access to or use of the Airbnb Platform after such posting constitutes your consent to be bound by the modified Terms.
|
| 180 |
+
|
| 181 |
+
Airbnb may, without prior notice, remove or take down any Content that, in Airbnb's sole judgment, violates these Terms or Airbnb's Content Policy, or is otherwise objectionable.
|
| 182 |
+
|
| 183 |
+
To the maximum extent permitted by law, Airbnb shall not be liable for any incidental, special, exemplary or consequential damages. Airbnb's total liability arising out of or in connection with these terms shall not exceed the amounts paid by you to Airbnb during the twelve month period prior to the event.
|
| 184 |
+
|
| 185 |
+
Airbnb may immediately, without notice, terminate your account if Airbnb believes, in its sole discretion, that you have breached these Terms or otherwise violated the rights of Airbnb.
|
| 186 |
+
|
| 187 |
+
These Terms are governed by and construed in accordance with the laws of Ireland, without regard to conflict of law provisions. You and Airbnb agree to submit to the exclusive jurisdiction of the courts located in Ireland."""
|
| 188 |
+
|
| 189 |
+
EXAMPLE_RENTAL = """This Lease Agreement is entered into as of the date signed below. By signing this agreement, the Tenant agrees to all terms and conditions set forth herein.
|
| 190 |
+
|
| 191 |
+
The Landlord reserves the right to enter the premises at any time without prior notice for inspection, repair, or any other purpose deemed necessary by the Landlord in their sole discretion.
|
| 192 |
+
|
| 193 |
+
The Tenant shall be responsible for all repairs and maintenance of the premises, including but not limited to plumbing, electrical, and structural issues, regardless of cause.
|
| 194 |
+
|
| 195 |
+
The Landlord shall not be liable for any damage to the Tenant's personal property, whether caused by water leaks, fire, theft, or any other cause, including the Landlord's own negligence.
|
| 196 |
+
|
| 197 |
+
The Landlord may terminate this lease at any time with only 7 days written notice, for any reason or no reason at all. The Tenant may not terminate this lease before the end of the lease term without paying a termination fee equal to 3 months' rent.
|
| 198 |
+
|
| 199 |
+
Any disputes arising from this lease agreement shall be resolved exclusively in the courts of the Landlord's choosing, and the Tenant waives the right to a jury trial.
|
| 200 |
+
|
| 201 |
+
The Landlord reserves the right to modify the terms of this lease at any time. Continued occupancy of the premises after such modification constitutes acceptance of the new terms.
|
| 202 |
+
|
| 203 |
+
The security deposit may be retained by the Landlord for any reason, including but not limited to cleaning, repairs, and unpaid rent, at the Landlord's sole discretion."""
|
| 204 |
+
|
| 205 |
+
demo = gr.Blocks(title="ClauseGuard β AI Fine Print Scanner")
|
| 206 |
+
|
| 207 |
+
with demo:
|
| 208 |
+
gr.HTML("""
|
| 209 |
+
<div style="text-align:center; padding:20px 0;">
|
| 210 |
+
<h1 style="font-size:2.5rem; margin:0;">π‘οΈ ClauseGuard</h1>
|
| 211 |
+
<p style="color:#6b7280; font-size:1.1rem;">AI-Powered Fine Print Scanner β Stop Signing Away Your Rights</p>
|
| 212 |
+
<p style="font-size:0.85rem; color:#9ca3af; margin-top:4px;">
|
| 213 |
+
Analyzes 8 types of unfair clauses: Arbitration Β· Unilateral Change Β· Content Removal Β·
|
| 214 |
+
Jurisdiction Β· Choice of Law Β· Liability Limits Β· Unilateral Termination Β· Dark Patterns
|
| 215 |
+
</p>
|
| 216 |
+
</div>""")
|
| 217 |
+
|
| 218 |
+
with gr.Row():
|
| 219 |
+
with gr.Column(scale=1):
|
| 220 |
+
text_input = gr.Textbox(label="π Paste Terms of Service / Contract / Lease Agreement",
|
| 221 |
+
placeholder="Paste any legal document here...\n\nTry one of the examples below π", lines=18, max_lines=50)
|
| 222 |
+
with gr.Row():
|
| 223 |
+
scan_btn = gr.Button("π Scan for Red Flags", variant="primary", size="lg")
|
| 224 |
+
clear_btn = gr.Button("ποΈ Clear", variant="secondary", size="lg")
|
| 225 |
+
gr.Examples(examples=[[EXAMPLE_SPOTIFY],[EXAMPLE_AIRBNB],[EXAMPLE_RENTAL]],
|
| 226 |
+
inputs=[text_input], label="π Try These Examples", examples_per_page=3)
|
| 227 |
+
with gr.Column(scale=1):
|
| 228 |
+
summary_output = gr.HTML(label="Summary")
|
| 229 |
+
findings_output = gr.HTML(label="Detailed Findings")
|
| 230 |
+
|
| 231 |
+
with gr.Accordion("π Highlighted Document (red = flagged clauses)", open=False):
|
| 232 |
+
highlighted_output = gr.HTML()
|
| 233 |
+
|
| 234 |
+
scan_btn.click(fn=generate_report, inputs=[text_input], outputs=[summary_output, findings_output, highlighted_output])
|
| 235 |
+
clear_btn.click(fn=lambda: ("", "", "", ""), outputs=[text_input, summary_output, findings_output, highlighted_output])
|
| 236 |
+
|
| 237 |
+
gr.HTML("""<div style="text-align:center; padding:20px; color:#9ca3af; font-size:13px; border-top:1px solid #e5e7eb; margin-top:20px;">
|
| 238 |
+
<p><strong>β οΈ Disclaimer:</strong> ClauseGuard provides informational analysis only. Not legal advice. Always consult a qualified attorney.</p>
|
| 239 |
+
<p>Built with β€οΈ using CLAUDETTE taxonomy Β· <a href="https://huggingface.co/datasets/coastalcph/lex_glue" target="_blank">LexGLUE Dataset</a></p>
|
| 240 |
+
</div>""")
|
| 241 |
+
|
| 242 |
+
if __name__ == "__main__":
|
| 243 |
+
demo.launch()
|