bpmredacademy commited on
Commit
479168e
·
verified ·
1 Parent(s): 77cc896

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +9 -203
app.py CHANGED
@@ -1,208 +1,14 @@
1
- import os
2
- import re
3
- import textwrap
4
- import gradio as gr
5
 
6
- ENGAGEMENT_EMAIL = os.getenv("ENGAGEMENT_EMAIL", "engagement@bpm.ba")
7
- GOVERNANCE_EMAIL = os.getenv("GOVERNANCE_EMAIL", "governance@bpm.ba")
8
 
9
- # Optional gating (comma-separated)
10
- ACCESS_CODES_RAW = os.getenv("FINC2E_ACCESS_CODES", "").strip()
11
- ACCESS_CODES = {c.strip() for c in ACCESS_CODES_RAW.split(",") if c.strip()}
12
 
13
- TITLE = "FinC2E — Governance Gateway"
14
- TAGLINE = "Structured, audit-oriented reasoning for regulated decision support (preview)."
15
-
16
- DISCLAIMER = (
17
- "FinC2E outputs are informational and non-executive. "
18
- "No legal advice, financial advice, trading signals, or decision execution is provided. "
19
- "Users remain responsible for compliance, policies, and final decisions."
20
- )
21
-
22
- RISK_DOMAINS = [
23
- "AML / CFT",
24
- "KYC / CDD",
25
- "Sanctions screening",
26
- "Fraud / transaction anomaly",
27
- "Market conduct / suitability",
28
- "Operational risk",
29
- "Model risk / AI governance",
30
- "Data privacy / security",
31
- "Other (specify)"
32
- ]
33
-
34
- def normalize(s: str) -> str:
35
- return (s or "").strip()
36
-
37
- def valid_access(code: str) -> bool:
38
- if not ACCESS_CODES:
39
- return True # no gate
40
- return normalize(code) in ACCESS_CODES
41
-
42
- def ensure_min_len(field: str, n: int, label: str):
43
- if len(normalize(field)) < n:
44
- return f"[Missing/too short] {label} (min {n} chars)"
45
- return None
46
-
47
- def finc2e_reason(case_id, jurisdiction, domain, other_domain, objective, facts, constraints, decision_stage, access_code):
48
- # Gate
49
- if not valid_access(access_code):
50
- return (
51
- "ACCESS DENIED\n"
52
- "------------\n"
53
- "This preview requires a valid FinC2E access code.\n"
54
- f"Request access: {ENGAGEMENT_EMAIL}\n"
55
- )
56
-
57
- domain_final = other_domain if domain == "Other (specify)" else domain
58
- domain_final = normalize(domain_final) or domain
59
-
60
- # Basic validation
61
- issues = []
62
- for (val, n, label) in [
63
- (objective, 25, "Objective"),
64
- (facts, 40, "Case Facts / Data"),
65
- (constraints, 20, "Constraints / Policies"),
66
- (jurisdiction, 2, "Jurisdiction"),
67
- ]:
68
- m = ensure_min_len(val, n, label)
69
- if m:
70
- issues.append(m)
71
-
72
- if issues:
73
- return "INPUT QUALITY WARNING\n---------------------\n" + "\n".join(f"- {i}" for i in issues) + "\n\nProvide clearer inputs for higher analytical value."
74
-
75
- # Produce a structured, audit-oriented "preview" (still non-executive)
76
- out = f"""
77
- FINC2E GOVERNANCE OUTPUT (PREVIEW) — NON-EXECUTIVE
78
- =================================================
79
-
80
- Case Header
81
- -----------
82
- - Case ID: {normalize(case_id) or "N/A"}
83
- - Jurisdiction: {normalize(jurisdiction)}
84
- - Domain: {domain_final}
85
- - Decision Stage: {normalize(decision_stage) or "N/A"}
86
-
87
- 1) Decision Objective (What must be decided?)
88
- --------------------------------------------
89
- {normalize(objective)}
90
-
91
- 2) Known Facts / Inputs (What is observed?)
92
- ------------------------------------------
93
- {normalize(facts)}
94
-
95
- 3) Constraints & Policies (What must be respected?)
96
- --------------------------------------------------
97
- {normalize(constraints)}
98
-
99
- 4) Risk Framing (What can go wrong?)
100
- -----------------------------------
101
- - Primary risk vectors (domain-dependent)
102
- - Irreversibility / tail risk considerations
103
- - Compliance exposure and evidentiary needs
104
-
105
- 5) Minimum Evidence Checklist (Audit-oriented)
106
- ---------------------------------------------
107
- - Identity / entity attributes sufficient for the domain
108
- - Source of funds / source of wealth (if relevant)
109
- - Transaction narrative coherence (if relevant)
110
- - Sanctions/PEP screening artifacts (if relevant)
111
- - Data provenance + timestamps + responsible reviewer
112
-
113
- 6) Structured Questions (What must be clarified next?)
114
- -----------------------------------------------------
115
- - What assumptions are being made due to missing data?
116
- - Which policy threshold(s) apply in this jurisdiction?
117
- - What would change the classification outcome?
118
- - What is the acceptable false-positive / false-negative posture?
119
-
120
- 7) Suggested Review Path (Human-in-the-loop)
121
- -------------------------------------------
122
- - Step A: Normalize inputs and verify provenance
123
- - Step B: Apply policy thresholds to classify risk band
124
- - Step C: Collect missing evidence (if required)
125
- - Step D: Document rationale and reviewer accountability
126
- - Step E: Escalate if any high-severity triggers are present
127
-
128
- Governance Notes
129
- ----------------
130
- - Output is informational; no decision is executed.
131
- - For production pilots: policy binding, audit logs, and access controls are mandatory.
132
-
133
- DISCLAIMER
134
- ----------
135
- {DISCLAIMER}
136
-
137
- © 2026 BPM RED Academy — All rights reserved.
138
- """
139
- return textwrap.dedent(out).strip()
140
-
141
- with gr.Blocks(theme=gr.themes.Soft(), title=TITLE) as demo:
142
- gr.Markdown(
143
- f"""
144
- # {TITLE}
145
- **{TAGLINE}**
146
-
147
- ⚠️ **Preview only.** {DISCLAIMER}
148
-
149
- ---
150
- """
151
- )
152
-
153
- # Optional gate UI
154
- if ACCESS_CODES:
155
- access_code = gr.Textbox(label="FinC2E Access Code (Licensed)", placeholder="e.g., FINC2E-CLIENT-001")
156
- else:
157
- access_code = gr.Textbox(label="FinC2E Access Code (optional)", placeholder="(optional)")
158
-
159
- with gr.Row():
160
- case_id = gr.Textbox(label="Case ID (optional)", placeholder="e.g., CASE-2026-0007")
161
- jurisdiction = gr.Textbox(label="Jurisdiction", placeholder="e.g., EU / UK / BiH / UAE")
162
-
163
- with gr.Row():
164
- domain = gr.Dropdown(label="Domain", choices=RISK_DOMAINS, value="AML / CFT")
165
- other_domain = gr.Textbox(label="If Other, specify domain", placeholder="e.g., Payments monitoring, UBO risk, etc.")
166
-
167
- decision_stage = gr.Textbox(label="Decision stage (optional)", placeholder="e.g., onboarding / ongoing monitoring / escalation review")
168
-
169
- objective = gr.Textbox(
170
- label="Decision objective",
171
- lines=2,
172
- placeholder="Describe the decision to be supported (not executed). Example: classify risk level and define what evidence is required for review."
173
- )
174
-
175
- facts = gr.Textbox(
176
- label="Case facts / inputs",
177
- lines=6,
178
- placeholder="Provide relevant facts only (no unnecessary personal data). Include amounts, timelines, entity types, triggers, and what is already verified."
179
- )
180
-
181
- constraints = gr.Textbox(
182
- label="Constraints / policies",
183
- lines=4,
184
- placeholder="List policy constraints: thresholds, prohibited conditions, escalation triggers, documentation requirements, and any jurisdictional rules you must respect."
185
- )
186
-
187
- run = gr.Button("Generate Governance Output (Preview)", variant="primary")
188
- output = gr.Textbox(label="FinC2E Output (Non-Executive)", lines=20)
189
-
190
- run.click(
191
- finc2e_reason,
192
- inputs=[case_id, jurisdiction, domain, other_domain, objective, facts, constraints, decision_stage, access_code],
193
- outputs=[output]
194
- )
195
-
196
- gr.Markdown(
197
- f"""
198
- ---
199
- ### Request access / enterprise pilots
200
- - Engagement: **{ENGAGEMENT_EMAIL}**
201
- - Governance: **{GOVERNANCE_EMAIL}**
202
-
203
- © 2026 BPM RED Academy — All rights reserved.
204
- """
205
- )
206
 
207
  if __name__ == "__main__":
208
- demo.launch()
 
1
+ from flask import Flask, send_from_directory
 
 
 
2
 
3
+ app = Flask(__name__, static_folder=".", static_url_path="")
 
4
 
5
+ @app.route("/")
6
+ def root():
7
+ return send_from_directory(".", "index.html")
8
 
9
+ @app.route("/<path:path>")
10
+ def static_files(path):
11
+ return send_from_directory(".", path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
  if __name__ == "__main__":
14
+ app.run(host="0.0.0.0", port=7860)