gitmodelmujtaba commited on
Commit
440a59c
·
verified ·
1 Parent(s): 5f7de85

Deploy ReguAI: Neuro-Symbolic AI GRC & Automated Conformity Assessment Engine

Browse files
app.py CHANGED
@@ -33,25 +33,52 @@ DEFAULT_CASE_TITLES = [c["title"] for c in DEFAULT_CASES]
33
  DEFAULT_CASE_TITLE = DEFAULT_CASE_TITLES[0]
34
  DEFAULT_SPEC_TEXT = catalog.get_case_document_text(DEFAULT_CASE_TITLE)
35
  DEFAULT_FACTSHEET = catalog.render_factsheet_html(DEFAULT_CASE_TITLE)
 
36
 
37
 
38
  def on_domain_change(selected_domain_name: str):
39
  cases = catalog.get_cases_for_domain(selected_domain_name)
40
  if not cases:
41
- return gr.update(choices=[], value=None), "", "<div style='padding:15px;'>No cases found.</div>"
42
  titles = [c["title"] for c in cases]
43
  first_title = titles[0]
44
  text = catalog.get_case_document_text(first_title)
45
  factsheet = catalog.render_factsheet_html(first_title)
46
- return gr.update(choices=titles, value=first_title), text, factsheet
 
47
 
48
 
49
  def on_case_change(selected_case_title: str):
50
  if not selected_case_title:
51
- return "", "<div style='padding:15px;'>Select a case study.</div>"
52
  text = catalog.get_case_document_text(selected_case_title)
53
  factsheet = catalog.render_factsheet_html(selected_case_title)
54
- return text, factsheet
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
 
57
  def run_assessment(doc_text: str, auditor_id: str, annual_turnover: float = 50000000.0, is_sme: bool = False):
@@ -178,7 +205,7 @@ def run_assessment(doc_text: str, auditor_id: str, annual_turnover: float = 5000
178
  border = "#bbf7d0" if ceiling == 0.0 else "#fed7aa"
179
 
180
  fine_html = f"""
181
- <div style="background: {bg}; border: 1px solid {border}; padding: 20px; border-radius: 8px; margin-bottom: 15px;">
182
  <div style="font-size: 13px; font-weight: 700; color: {color}; text-transform: uppercase; letter-spacing: 0.5px;">Regulation (EU) 2024/1689 Article 99 Corporate Fine Exposure</div>
183
  <div style="font-size: 32px; font-weight: 800; color: {color}; margin: 8px 0;">
184
  €{ceiling:,.2f}
@@ -189,7 +216,7 @@ def run_assessment(doc_text: str, auditor_id: str, annual_turnover: float = 5000
189
  <div><strong>SME Discount (Art. 99(6)):</strong> {'✓ Active' if fine.get('is_sme_discount_applied') else '✗ Inactive (Standard Enterprise)'}</div>
190
  <div><strong>Simulated Turnover:</strong> €{float(annual_turnover):,.2f}</div>
191
  </div>
192
- <div style="font-size: 13px; color: #1e293b; line-height: 1.6; background: rgba(255,255,255,0.85); padding: 12px 16px; border-radius: 6px; border: 1px solid #e2e8f0;">
193
  <strong>Statutory Basis & Remediations:</strong> {fine.get('executive_liability_summary', '')}
194
  </div>
195
  </div>
@@ -233,6 +260,16 @@ def run_assessment(doc_text: str, auditor_id: str, annual_turnover: float = 5000
233
  )
234
 
235
 
 
 
 
 
 
 
 
 
 
 
236
  def record_triage(claim_id: str, new_status: str, new_category: str, notes: str, auditor_id: str):
237
  if not claim_id:
238
  return "⚠️ Please select a Claim ID to triage."
@@ -530,6 +567,128 @@ button:not(.primary):not([variant="primary"]) {
530
  border-color: #78350f !important;
531
  color: #fef3c7 !important;
532
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
533
  """
534
 
535
  with gr.Blocks(title="ReguAI: Neuro-Symbolic AI GRC Engine") as demo:
@@ -548,84 +707,146 @@ with gr.Blocks(title="ReguAI: Neuro-Symbolic AI GRC Engine") as demo:
548
  <span class="header-badge">🔗 W3C PROV-O Audit Ledger</span>
549
  <span class="header-badge">👤 Auditor-in-the-Loop Active Learning</span>
550
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
551
  """
552
  )
553
 
554
  with gr.Row():
555
  with gr.Column(scale=5):
 
 
 
 
 
 
 
 
556
  with gr.Row():
557
  domain_dropdown = gr.Dropdown(
558
- label="🌐 1. Select Regulatory Domain / Statutory Classification",
559
  choices=DOMAIN_OPTIONS,
560
  value=DEFAULT_DOMAIN,
561
  scale=6,
562
  interactive=True,
 
563
  )
564
  case_dropdown = gr.Dropdown(
565
- label="📁 2. Select Benchmark Case Study & Legal Scenario",
566
  choices=DEFAULT_CASE_TITLES,
567
  value=DEFAULT_CASE_TITLE,
568
  scale=6,
569
  interactive=True,
 
570
  )
571
- factsheet_box = gr.HTML(
572
- value=DEFAULT_FACTSHEET,
573
- label="Statutory Reference Factsheet & Cryptographic Provenance",
574
- )
575
- spec_input = gr.Textbox(
576
- label="📄 System Technical Specification / Model Card (Markdown or JSON)",
577
- lines=12,
578
- placeholder="Paste AI system architecture or model card text...",
579
- value=DEFAULT_SPEC_TEXT,
580
- )
581
- auditor_input = gr.Textbox(
582
- label="Auditor Credential Identifier",
583
- value="lead_compliance_auditor_01",
584
- placeholder="e.g. auditor@enterprise.org",
585
  )
586
- with gr.Accordion("💰 Article 99 Corporate Fine Modeling", open=False):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
587
  turnover_input = gr.Number(
588
- label="Worldwide Annual Turnover (EUR)",
589
  value=50000000.0,
590
  step=5000000.0,
591
- info="Used to calculate maximum turnover percentage ceilings under Article 99"
 
592
  )
593
  is_sme_input = gr.Checkbox(
594
- label="SME / Startup Status (Article 99(6) Special Ceiling)",
595
  value=False,
596
- info="Applies lower of fixed amount or turnover percentage"
 
597
  )
 
598
  assess_btn = gr.Button("⚡ Run Deterministic Conformity Assessment", variant="primary", size="lg")
599
 
600
  with gr.Column(scale=7):
601
- exec_output = gr.HTML(label="Executive Conformity Summary")
602
 
603
  with gr.Tabs():
604
- with gr.TabItem("🌐 Interactive Regulatory Graph"):
605
- graph_output = gr.HTML(label="Force-Directed Regulatory Dependency Network")
606
-
607
  with gr.TabItem("⚖️ SHACL Deterministic Violations"):
608
  violations_table = gr.Dataframe(
609
  headers=["Legal Article", "Normative Requirement", "Severity", "SHACL Path", "Remediation Guidance"],
610
  datatype=["str", "str", "str", "str", "str"],
 
611
  label="Mathematical Proof: Non-Conformities Found",
612
  )
613
 
614
- with gr.TabItem("🌐 Multi-Framework Crosswalk"):
615
  gr.Markdown("### 🇪🇺 EU AI Act ⟷ NIST AI RMF 1.0 ⟷ ISO/IEC 42001:2023 ⟷ GDPR")
616
  frameworks_table = gr.Dataframe(
617
  headers=["Target Framework", "Control ID", "Control Name", "Status", "Linked AI Act Article", "Audit Guidance"],
618
  datatype=["str", "str", "str", "str", "str", "str"],
 
619
  label="Automated Cross-Regulatory Control Status",
620
  )
621
 
622
  with gr.TabItem("💰 Article 99 Fine Liability"):
623
- fine_liability_output = gr.HTML(label="Corporate Balance Sheet Exposure")
 
 
 
624
 
625
  with gr.TabItem("🔍 Extracted Regulatory Claims"):
626
  claims_table = gr.Dataframe(
627
  headers=["Claim ID", "Category", "Status", "Confidence", "Target Article", "Evidence Span"],
628
  datatype=["str", "str", "str", "str", "str", "str"],
 
629
  label="Domain-Adapted Claim Extraction & NegEx Grounding",
630
  )
631
 
@@ -634,6 +855,7 @@ with gr.Blocks(title="ReguAI: Neuro-Symbolic AI GRC Engine") as demo:
634
  borderline_table = gr.Dataframe(
635
  headers=["Claim ID", "Category", "Status", "Confidence", "Evidence Quote"],
636
  datatype=["str", "str", "str", "str", "str"],
 
637
  )
638
  with gr.Row():
639
  triage_claim_id = gr.Textbox(label="Claim ID to Triage", placeholder="e.g. clm_001")
@@ -644,30 +866,79 @@ with gr.Blocks(title="ReguAI: Neuro-Symbolic AI GRC Engine") as demo:
644
  triage_result = gr.Markdown()
645
 
646
  with gr.TabItem("🔐 Cryptographic Audit Ledger"):
647
- token_display = gr.Textbox(label="Official Digital Conformity Token", interactive=False)
648
- ledger_display = gr.Markdown()
649
 
650
  with gr.TabItem("📑 Export Technical Documentation (Annex IV)"):
651
  with gr.Tabs():
652
  with gr.TabItem("📜 Official Print-Ready Certificate (HTML)"):
653
- cert_html_output = gr.HTML()
654
  with gr.TabItem("Annex IV Official Report (Markdown)"):
655
- report_markdown = gr.Markdown()
656
  with gr.TabItem("Machine-Readable JSON-LD"):
657
- jsonld_display = gr.Code(language="json", label="W3C JSON-LD Digital Certificate")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
658
 
659
- # Wire event handlers
660
  domain_dropdown.change(
661
  fn=on_domain_change,
662
  inputs=[domain_dropdown],
663
- outputs=[case_dropdown, spec_input, factsheet_box],
664
  )
665
  case_dropdown.change(
666
  fn=on_case_change,
667
  inputs=[case_dropdown],
668
- outputs=[spec_input, factsheet_box],
669
  )
670
 
 
671
  assess_btn.click(
672
  fn=run_assessment,
673
  inputs=[spec_input, auditor_input, turnover_input, is_sme_input],
@@ -695,3 +966,4 @@ with gr.Blocks(title="ReguAI: Neuro-Symbolic AI GRC Engine") as demo:
695
 
696
  if __name__ == "__main__":
697
  demo.launch(server_name="0.0.0.0", server_port=7860, share=False, theme=gr.themes.Soft(), css=CUSTOM_CSS)
 
 
33
  DEFAULT_CASE_TITLE = DEFAULT_CASE_TITLES[0]
34
  DEFAULT_SPEC_TEXT = catalog.get_case_document_text(DEFAULT_CASE_TITLE)
35
  DEFAULT_FACTSHEET = catalog.render_factsheet_html(DEFAULT_CASE_TITLE)
36
+ DEFAULT_QUICK_BAR = catalog.render_quick_bar(DEFAULT_CASE_TITLE)
37
 
38
 
39
  def on_domain_change(selected_domain_name: str):
40
  cases = catalog.get_cases_for_domain(selected_domain_name)
41
  if not cases:
42
+ return gr.update(choices=[], value=None), "", "", "<div style='padding:15px;'>No cases found.</div>"
43
  titles = [c["title"] for c in cases]
44
  first_title = titles[0]
45
  text = catalog.get_case_document_text(first_title)
46
  factsheet = catalog.render_factsheet_html(first_title)
47
+ quick_bar = catalog.render_quick_bar(first_title)
48
+ return gr.update(choices=titles, value=first_title), text, quick_bar, factsheet
49
 
50
 
51
  def on_case_change(selected_case_title: str):
52
  if not selected_case_title:
53
+ return "", "", "<div style='padding:15px;'>Select a case study.</div>"
54
  text = catalog.get_case_document_text(selected_case_title)
55
  factsheet = catalog.render_factsheet_html(selected_case_title)
56
+ quick_bar = catalog.render_quick_bar(selected_case_title)
57
+ return text, quick_bar, factsheet
58
+
59
+
60
+ def load_preset(domain_idx: int, case_idx: int = 0):
61
+ domains = catalog.list_domains()
62
+ if domain_idx >= len(domains):
63
+ domain_idx = 0
64
+ dom = domains[domain_idx]
65
+ dom_name = dom["domain_name"]
66
+ cases = dom.get("case_studies", [])
67
+ if not cases:
68
+ return gr.update(), gr.update(), "", "", ""
69
+ case = cases[min(case_idx, len(cases) - 1)]
70
+ case_title = case["title"]
71
+ case_titles = [c["title"] for c in cases]
72
+ text = catalog.get_case_document_text(case_title)
73
+ factsheet = catalog.render_factsheet_html(case_title)
74
+ quick_bar = catalog.render_quick_bar(case_title)
75
+ return (
76
+ gr.update(value=dom_name),
77
+ gr.update(choices=case_titles, value=case_title),
78
+ text,
79
+ quick_bar,
80
+ factsheet,
81
+ )
82
 
83
 
84
  def run_assessment(doc_text: str, auditor_id: str, annual_turnover: float = 50000000.0, is_sme: bool = False):
 
205
  border = "#bbf7d0" if ceiling == 0.0 else "#fed7aa"
206
 
207
  fine_html = f"""
208
+ <div class="fine-liability-card" style="background: {bg}; border: 1px solid {border}; padding: 20px; border-radius: 8px; margin-bottom: 15px;">
209
  <div style="font-size: 13px; font-weight: 700; color: {color}; text-transform: uppercase; letter-spacing: 0.5px;">Regulation (EU) 2024/1689 Article 99 Corporate Fine Exposure</div>
210
  <div style="font-size: 32px; font-weight: 800; color: {color}; margin: 8px 0;">
211
  €{ceiling:,.2f}
 
216
  <div><strong>SME Discount (Art. 99(6)):</strong> {'✓ Active' if fine.get('is_sme_discount_applied') else '✗ Inactive (Standard Enterprise)'}</div>
217
  <div><strong>Simulated Turnover:</strong> €{float(annual_turnover):,.2f}</div>
218
  </div>
219
+ <div class="fine-basis" style="font-size: 13px; color: #1e293b; line-height: 1.6; background: rgba(255,255,255,0.85); padding: 12px 16px; border-radius: 6px; border: 1px solid #e2e8f0;">
220
  <strong>Statutory Basis & Remediations:</strong> {fine.get('executive_liability_summary', '')}
221
  </div>
222
  </div>
 
260
  )
261
 
262
 
263
+ def load_preset_and_assess(domain_idx: int, case_idx: int, auditor_id: str, turnover: float, is_sme: bool):
264
+ dom_update, case_update, text, quick_bar, factsheet = load_preset(domain_idx, case_idx)
265
+ assessment_res = run_assessment(text, auditor_id, turnover, is_sme)
266
+ return (dom_update, case_update, text, quick_bar, factsheet, *assessment_res)
267
+
268
+
269
+ # Pre-compute live initial evaluation for default case study so dashboard opens fully populated
270
+ DEFAULT_ASSESSMENT = run_assessment(DEFAULT_SPEC_TEXT, "lead_compliance_auditor_01", 50000000.0, False)
271
+
272
+
273
  def record_triage(claim_id: str, new_status: str, new_category: str, notes: str, auditor_id: str):
274
  if not claim_id:
275
  return "⚠️ Please select a Claim ID to triage."
 
567
  border-color: #78350f !important;
568
  color: #fef3c7 !important;
569
  }
570
+
571
+ /* Quick Summary Bar */
572
+ .quick-summary-bar {
573
+ background: #f8fafc !important;
574
+ border: 1px solid #e2e8f0 !important;
575
+ border-radius: 6px !important;
576
+ }
577
+
578
+ .dark .quick-summary-bar {
579
+ background: #0f172a !important;
580
+ border-color: #334155 !important;
581
+ color: #cbd5e1 !important;
582
+ }
583
+
584
+ /* -------------------------------------------------------------
585
+ WORKFLOW STEPPER
586
+ ------------------------------------------------------------- */
587
+ .workflow-stepper {
588
+ display: flex;
589
+ align-items: center;
590
+ justify-content: space-between;
591
+ background: #f8fafc;
592
+ border: 1px solid #e2e8f0;
593
+ border-radius: 10px;
594
+ padding: 12px 18px;
595
+ margin: 12px 0 16px 0;
596
+ gap: 8px;
597
+ flex-wrap: wrap;
598
+ }
599
+
600
+ .dark .workflow-stepper {
601
+ background: #0f172a !important;
602
+ border-color: #334155 !important;
603
+ }
604
+
605
+ .step-card {
606
+ display: flex;
607
+ align-items: center;
608
+ gap: 10px;
609
+ }
610
+
611
+ .step-num {
612
+ background: #2563eb;
613
+ color: #ffffff !important;
614
+ font-weight: 800;
615
+ width: 26px;
616
+ height: 26px;
617
+ border-radius: 50%;
618
+ display: inline-flex;
619
+ align-items: center;
620
+ justify-content: center;
621
+ font-size: 12px;
622
+ }
623
+
624
+ .step-text {
625
+ font-size: 12px;
626
+ color: #475569;
627
+ line-height: 1.25;
628
+ }
629
+
630
+ .dark .step-text {
631
+ color: #94a3b8 !important;
632
+ }
633
+
634
+ .step-text strong {
635
+ display: block;
636
+ color: #0f172a;
637
+ font-size: 13px;
638
+ }
639
+
640
+ .dark .step-text strong {
641
+ color: #f8fafc !important;
642
+ }
643
+
644
+ .step-arrow {
645
+ color: #94a3b8;
646
+ font-weight: 700;
647
+ font-size: 15px;
648
+ }
649
+
650
+ /* -------------------------------------------------------------
651
+ PRESET BUTTONS
652
+ ------------------------------------------------------------- */
653
+ .preset-btn {
654
+ font-size: 12px !important;
655
+ font-weight: 600 !important;
656
+ padding: 6px 12px !important;
657
+ border-radius: 8px !important;
658
+ border: 1px solid #cbd5e1 !important;
659
+ background: #ffffff !important;
660
+ color: #1e293b !important;
661
+ transition: all 0.15s ease !important;
662
+ }
663
+
664
+ .preset-btn:hover {
665
+ transform: translateY(-1px) !important;
666
+ box-shadow: 0 2px 5px rgba(0,0,0,0.08) !important;
667
+ }
668
+
669
+ .dark .preset-btn {
670
+ background: #1e293b !important;
671
+ border-color: #334155 !important;
672
+ color: #f8fafc !important;
673
+ }
674
+
675
+ .dark .preset-btn:hover {
676
+ background: #334155 !important;
677
+ }
678
+
679
+ /* -------------------------------------------------------------
680
+ FINE LIABILITY CARD DARK MODE
681
+ ------------------------------------------------------------- */
682
+ .dark .fine-liability-card {
683
+ background: #1e293b !important;
684
+ border-color: #334155 !important;
685
+ }
686
+
687
+ .dark .fine-liability-card .fine-basis {
688
+ background: #0f172a !important;
689
+ color: #cbd5e1 !important;
690
+ border-color: #334155 !important;
691
+ }
692
  """
693
 
694
  with gr.Blocks(title="ReguAI: Neuro-Symbolic AI GRC Engine") as demo:
 
707
  <span class="header-badge">🔗 W3C PROV-O Audit Ledger</span>
708
  <span class="header-badge">👤 Auditor-in-the-Loop Active Learning</span>
709
  </div>
710
+
711
+ <div class="workflow-stepper">
712
+ <div class="step-card">
713
+ <span class="step-num">1</span>
714
+ <div class="step-text">
715
+ <strong>Select AI Scenario</strong>
716
+ 1-Click Preset or 11 EU Domains
717
+ </div>
718
+ </div>
719
+ <div class="step-arrow">➔</div>
720
+ <div class="step-card">
721
+ <span class="step-num">2</span>
722
+ <div class="step-text">
723
+ <strong>Review Legal Grounding</strong>
724
+ EUR-Lex CELEX & W3C PROV-O
725
+ </div>
726
+ </div>
727
+ <div class="step-arrow">➔</div>
728
+ <div class="step-card">
729
+ <span class="step-num">3</span>
730
+ <div class="step-text">
731
+ <strong>Run Deterministic Audit</strong>
732
+ W3C SHACL Mathematical Proofs
733
+ </div>
734
+ </div>
735
+ <div class="step-arrow">➔</div>
736
+ <div class="step-card">
737
+ <span class="step-num">4</span>
738
+ <div class="step-text">
739
+ <strong>Export Findings & Cert</strong>
740
+ Annex IV Certificate, Fines & Graph
741
+ </div>
742
+ </div>
743
+ </div>
744
  """
745
  )
746
 
747
  with gr.Row():
748
  with gr.Column(scale=5):
749
+ gr.Markdown("**⚡ 1-Click Quick Scenarios (Click to Instantly Evaluate):**")
750
+ with gr.Row():
751
+ preset_samd = gr.Button("🏥 Compliant SaMD", size="sm", elem_classes=["preset-btn"])
752
+ preset_hr = gr.Button("💼 Failed HR AI", size="sm", elem_classes=["preset-btn"])
753
+ preset_prohibited = gr.Button("🚫 Prohibited AI", size="sm", elem_classes=["preset-btn"])
754
+ preset_gpai = gr.Button("🌐 Frontier GPAI", size="sm", elem_classes=["preset-btn"])
755
+ preset_grid = gr.Button("⚡ Critical Grid", size="sm", elem_classes=["preset-btn"])
756
+
757
  with gr.Row():
758
  domain_dropdown = gr.Dropdown(
759
+ label="🌐 1. Select Regulatory Domain",
760
  choices=DOMAIN_OPTIONS,
761
  value=DEFAULT_DOMAIN,
762
  scale=6,
763
  interactive=True,
764
+ info="11 statutory sectors under EU AI Act",
765
  )
766
  case_dropdown = gr.Dropdown(
767
+ label="📁 2. Select AI Benchmark Case Study",
768
  choices=DEFAULT_CASE_TITLES,
769
  value=DEFAULT_CASE_TITLE,
770
  scale=6,
771
  interactive=True,
772
+ info="Canonical legal scenarios with EUR-Lex provenance",
773
  )
774
+
775
+ quick_bar_box = gr.HTML(
776
+ value=DEFAULT_QUICK_BAR,
777
+ label="Statutory Quick Summary",
 
 
 
 
 
 
 
 
 
 
778
  )
779
+
780
+ with gr.Tabs():
781
+ with gr.TabItem("📄 Technical Specification / Model Card"):
782
+ spec_input = gr.Textbox(
783
+ label="System Technical Specification (Markdown or JSON - Fully Editable)",
784
+ lines=12,
785
+ placeholder="Paste AI system architecture or model card text...",
786
+ value=DEFAULT_SPEC_TEXT,
787
+ info="Grounds natural language model cards into normative RDF knowledge graph",
788
+ )
789
+ with gr.TabItem("📚 Statutory Factsheet & Cryptographic Provenance"):
790
+ factsheet_box = gr.HTML(
791
+ value=DEFAULT_FACTSHEET,
792
+ label="Full Regulatory Factsheet & EUR-Lex Provenance",
793
+ )
794
+
795
+ with gr.Row():
796
+ auditor_input = gr.Textbox(
797
+ label="Auditor Identifier",
798
+ value="lead_compliance_auditor_01",
799
+ scale=5,
800
+ info="Embedded in W3C PROV-O audit ledger",
801
+ )
802
  turnover_input = gr.Number(
803
+ label="Annual Turnover ()",
804
  value=50000000.0,
805
  step=5000000.0,
806
+ scale=4,
807
+ info="For Art. 99 administrative fine modeling",
808
  )
809
  is_sme_input = gr.Checkbox(
810
+ label="SME Status",
811
  value=False,
812
+ scale=3,
813
+ info="Art. 99(6) reduced fine caps (whichever is lower)",
814
  )
815
+
816
  assess_btn = gr.Button("⚡ Run Deterministic Conformity Assessment", variant="primary", size="lg")
817
 
818
  with gr.Column(scale=7):
819
+ exec_output = gr.HTML(value=DEFAULT_ASSESSMENT[0], label="Executive Conformity Summary")
820
 
821
  with gr.Tabs():
 
 
 
822
  with gr.TabItem("⚖️ SHACL Deterministic Violations"):
823
  violations_table = gr.Dataframe(
824
  headers=["Legal Article", "Normative Requirement", "Severity", "SHACL Path", "Remediation Guidance"],
825
  datatype=["str", "str", "str", "str", "str"],
826
+ value=DEFAULT_ASSESSMENT[1],
827
  label="Mathematical Proof: Non-Conformities Found",
828
  )
829
 
830
+ with gr.TabItem("���� Multi-Framework Crosswalk"):
831
  gr.Markdown("### 🇪🇺 EU AI Act ⟷ NIST AI RMF 1.0 ⟷ ISO/IEC 42001:2023 ⟷ GDPR")
832
  frameworks_table = gr.Dataframe(
833
  headers=["Target Framework", "Control ID", "Control Name", "Status", "Linked AI Act Article", "Audit Guidance"],
834
  datatype=["str", "str", "str", "str", "str", "str"],
835
+ value=DEFAULT_ASSESSMENT[10],
836
  label="Automated Cross-Regulatory Control Status",
837
  )
838
 
839
  with gr.TabItem("💰 Article 99 Fine Liability"):
840
+ fine_liability_output = gr.HTML(value=DEFAULT_ASSESSMENT[11], label="Corporate Balance Sheet Exposure")
841
+
842
+ with gr.TabItem("🕸️ Interactive Regulatory Graph"):
843
+ graph_output = gr.HTML(value=DEFAULT_ASSESSMENT[3], label="Force-Directed Regulatory Dependency Network")
844
 
845
  with gr.TabItem("🔍 Extracted Regulatory Claims"):
846
  claims_table = gr.Dataframe(
847
  headers=["Claim ID", "Category", "Status", "Confidence", "Target Article", "Evidence Span"],
848
  datatype=["str", "str", "str", "str", "str", "str"],
849
+ value=DEFAULT_ASSESSMENT[2],
850
  label="Domain-Adapted Claim Extraction & NegEx Grounding",
851
  )
852
 
 
855
  borderline_table = gr.Dataframe(
856
  headers=["Claim ID", "Category", "Status", "Confidence", "Evidence Quote"],
857
  datatype=["str", "str", "str", "str", "str"],
858
+ value=DEFAULT_ASSESSMENT[9],
859
  )
860
  with gr.Row():
861
  triage_claim_id = gr.Textbox(label="Claim ID to Triage", placeholder="e.g. clm_001")
 
866
  triage_result = gr.Markdown()
867
 
868
  with gr.TabItem("🔐 Cryptographic Audit Ledger"):
869
+ token_display = gr.Textbox(value=DEFAULT_ASSESSMENT[4], label="Official Digital Conformity Token", interactive=False)
870
+ ledger_display = gr.Markdown(value=DEFAULT_ASSESSMENT[5])
871
 
872
  with gr.TabItem("📑 Export Technical Documentation (Annex IV)"):
873
  with gr.Tabs():
874
  with gr.TabItem("📜 Official Print-Ready Certificate (HTML)"):
875
+ cert_html_output = gr.HTML(value=DEFAULT_ASSESSMENT[8])
876
  with gr.TabItem("Annex IV Official Report (Markdown)"):
877
+ report_markdown = gr.Markdown(value=DEFAULT_ASSESSMENT[7])
878
  with gr.TabItem("Machine-Readable JSON-LD"):
879
+ jsonld_display = gr.Code(value=DEFAULT_ASSESSMENT[6], language="json", label="W3C JSON-LD Digital Certificate")
880
+
881
+ # Outputs list for 1-click preset execution (17 components)
882
+ preset_outputs = [
883
+ domain_dropdown,
884
+ case_dropdown,
885
+ spec_input,
886
+ quick_bar_box,
887
+ factsheet_box,
888
+ exec_output,
889
+ violations_table,
890
+ claims_table,
891
+ graph_output,
892
+ token_display,
893
+ ledger_display,
894
+ jsonld_display,
895
+ report_markdown,
896
+ cert_html_output,
897
+ borderline_table,
898
+ frameworks_table,
899
+ fine_liability_output,
900
+ ]
901
+
902
+ # Wire 1-Click Preset Scenario Buttons
903
+ preset_samd.click(
904
+ fn=lambda a, t, s: load_preset_and_assess(0, 0, a, t, s),
905
+ inputs=[auditor_input, turnover_input, is_sme_input],
906
+ outputs=preset_outputs,
907
+ )
908
+ preset_hr.click(
909
+ fn=lambda a, t, s: load_preset_and_assess(1, 0, a, t, s),
910
+ inputs=[auditor_input, turnover_input, is_sme_input],
911
+ outputs=preset_outputs,
912
+ )
913
+ preset_prohibited.click(
914
+ fn=lambda a, t, s: load_preset_and_assess(8, 1, a, t, s),
915
+ inputs=[auditor_input, turnover_input, is_sme_input],
916
+ outputs=preset_outputs,
917
+ )
918
+ preset_gpai.click(
919
+ fn=lambda a, t, s: load_preset_and_assess(7, 0, a, t, s),
920
+ inputs=[auditor_input, turnover_input, is_sme_input],
921
+ outputs=preset_outputs,
922
+ )
923
+ preset_grid.click(
924
+ fn=lambda a, t, s: load_preset_and_assess(4, 0, a, t, s),
925
+ inputs=[auditor_input, turnover_input, is_sme_input],
926
+ outputs=preset_outputs,
927
+ )
928
 
929
+ # Wire cascading dropdown event handlers
930
  domain_dropdown.change(
931
  fn=on_domain_change,
932
  inputs=[domain_dropdown],
933
+ outputs=[case_dropdown, spec_input, quick_bar_box, factsheet_box],
934
  )
935
  case_dropdown.change(
936
  fn=on_case_change,
937
  inputs=[case_dropdown],
938
+ outputs=[spec_input, quick_bar_box, factsheet_box],
939
  )
940
 
941
+ # Wire manual assessment button
942
  assess_btn.click(
943
  fn=run_assessment,
944
  inputs=[spec_input, auditor_input, turnover_input, is_sme_input],
 
966
 
967
  if __name__ == "__main__":
968
  demo.launch(server_name="0.0.0.0", server_port=7860, share=False, theme=gr.themes.Soft(), css=CUSTOM_CSS)
969
+
data/active_learning_triplets.jsonl CHANGED
@@ -14,3 +14,4 @@
14
  {"timestamp": "2026-09-20T20:00:20.408608+00:00", "auditor_id": "compliance_lead_01", "claim_id": "clm_test_99", "anchor_text": "Verified operational override in production dashboard.", "positive_label": "HUMAN_OVERSIGHT", "negative_label": "IRRELEVANT_TEXT", "verified_assertion_status": "IMPLEMENTED", "auditor_notes": "Verified operational override in production dashboard."}
15
  {"timestamp": "2026-09-20T20:00:35.196971+00:00", "auditor_id": "compliance_lead_01", "claim_id": "clm_test_99", "anchor_text": "Verified operational override in production dashboard.", "positive_label": "HUMAN_OVERSIGHT", "negative_label": "IRRELEVANT_TEXT", "verified_assertion_status": "IMPLEMENTED", "auditor_notes": "Verified operational override in production dashboard."}
16
  {"timestamp": "2026-09-20T20:01:32.495427+00:00", "auditor_id": "compliance_lead_01", "claim_id": "clm_test_99", "anchor_text": "Verified operational override in production dashboard.", "positive_label": "HUMAN_OVERSIGHT", "negative_label": "IRRELEVANT_TEXT", "verified_assertion_status": "IMPLEMENTED", "auditor_notes": "Verified operational override in production dashboard."}
 
 
14
  {"timestamp": "2026-09-20T20:00:20.408608+00:00", "auditor_id": "compliance_lead_01", "claim_id": "clm_test_99", "anchor_text": "Verified operational override in production dashboard.", "positive_label": "HUMAN_OVERSIGHT", "negative_label": "IRRELEVANT_TEXT", "verified_assertion_status": "IMPLEMENTED", "auditor_notes": "Verified operational override in production dashboard."}
15
  {"timestamp": "2026-09-20T20:00:35.196971+00:00", "auditor_id": "compliance_lead_01", "claim_id": "clm_test_99", "anchor_text": "Verified operational override in production dashboard.", "positive_label": "HUMAN_OVERSIGHT", "negative_label": "IRRELEVANT_TEXT", "verified_assertion_status": "IMPLEMENTED", "auditor_notes": "Verified operational override in production dashboard."}
16
  {"timestamp": "2026-09-20T20:01:32.495427+00:00", "auditor_id": "compliance_lead_01", "claim_id": "clm_test_99", "anchor_text": "Verified operational override in production dashboard.", "positive_label": "HUMAN_OVERSIGHT", "negative_label": "IRRELEVANT_TEXT", "verified_assertion_status": "IMPLEMENTED", "auditor_notes": "Verified operational override in production dashboard."}
17
+ {"timestamp": "2026-09-20T20:12:47.133587+00:00", "auditor_id": "compliance_lead_01", "claim_id": "clm_test_99", "anchor_text": "Verified operational override in production dashboard.", "positive_label": "HUMAN_OVERSIGHT", "negative_label": "IRRELEVANT_TEXT", "verified_assertion_status": "IMPLEMENTED", "auditor_notes": "Verified operational override in production dashboard."}
src/core/case_catalog.py CHANGED
@@ -73,6 +73,52 @@ class CaseStudyCatalog:
73
  return data.get("raw_document_text", "")
74
  return ""
75
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  def render_factsheet_html(self, case_id_or_title: str) -> str:
77
  case = self.get_case(case_id_or_title) or self.get_case_by_title(case_id_or_title)
78
  if not case:
 
73
  return data.get("raw_document_text", "")
74
  return ""
75
 
76
+ def render_quick_bar(self, case_id_or_title: str) -> str:
77
+ case = self.get_case(case_id_or_title) or self.get_case_by_title(case_id_or_title)
78
+ if not case:
79
+ return ""
80
+
81
+ expected = case.get("expected_conformity", "UNKNOWN")
82
+ if "PASSED" in expected or "CONFORMANT" in expected:
83
+ pill_color = "#10b981"
84
+ pill_bg = "#ecfdf5"
85
+ pill_border = "#a7f3d0"
86
+ elif "PROHIBITED" in expected:
87
+ pill_color = "#991b1b"
88
+ pill_bg = "#fee2e2"
89
+ pill_border = "#f87171"
90
+ elif "FAILED" in expected or "NON-CONFORMANT" in expected:
91
+ pill_color = "#b91c1c"
92
+ pill_bg = "#fef2f2"
93
+ pill_border = "#fca5a5"
94
+ else:
95
+ pill_color = "#b45309"
96
+ pill_bg = "#fffbeb"
97
+ pill_border = "#fde68a"
98
+
99
+ reqs = case.get("regulatory_requirements", {})
100
+ fine = reqs.get("fine_exposure_tier", "N/A")
101
+ tier = case.get("statutory_tier", "AI System")
102
+ celex = case.get("provenance", {}).get("celex", "32024R1689")
103
+ eli_uri = case.get("provenance", {}).get("eli_uri", "http://data.europa.eu/eli/reg/2024/1689/oj")
104
+
105
+ return f"""
106
+ <div class="quick-summary-bar" style="display:flex; flex-wrap:wrap; gap:8px; align-items:center; padding:8px 12px; background:#f8fafc; border:1px solid #e2e8f0; border-radius:6px; margin:4px 0 10px 0; font-size:12px;">
107
+ <span style="background:{pill_bg}; color:{pill_color}; border:1px solid {pill_border}; padding:2px 8px; border-radius:4px; font-weight:700;">
108
+ {expected}
109
+ </span>
110
+ <span style="background:#e0f2fe; color:#0369a1; border:1px solid #bae6fd; padding:2px 8px; border-radius:4px; font-weight:600;">
111
+ ⚖️ {tier}
112
+ </span>
113
+ <span style="background:#fef2f2; color:#991b1b; border:1px solid #fecaca; padding:2px 8px; border-radius:4px; font-weight:600;">
114
+ 💰 {fine.split('(')[0].strip()}
115
+ </span>
116
+ <a href="{eli_uri}" target="_blank" style="margin-left:auto; color:#2563eb; text-decoration:none; font-weight:600; display:flex; align-items:center; gap:2px;">
117
+ 📜 EUR-Lex CELEX:{celex} ↗
118
+ </a>
119
+ </div>
120
+ """
121
+
122
  def render_factsheet_html(self, case_id_or_title: str) -> str:
123
  case = self.get_case(case_id_or_title) or self.get_case_by_title(case_id_or_title)
124
  if not case: