Spaces:
Sleeping
Sleeping
Update src/streamlit_app.py
Browse files- src/streamlit_app.py +123 -109
src/streamlit_app.py
CHANGED
|
@@ -5,163 +5,177 @@ import io
|
|
| 5 |
import re
|
| 6 |
|
| 7 |
# ==========================================
|
| 8 |
-
# 1.
|
| 9 |
# ==========================================
|
| 10 |
st.set_page_config(page_title="CX Architect Auto-Mapper", layout="wide", page_icon="ποΈ")
|
| 11 |
st.title("ποΈ CX Architect: Omni-Channel Generator")
|
| 12 |
-
st.markdown("Upload your PRD, VOC data, or
|
| 13 |
|
| 14 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
with st.sidebar:
|
| 16 |
st.header("βοΈ Configuration")
|
| 17 |
|
| 18 |
-
#
|
| 19 |
-
demo_mode = st.toggle("π Activate Demo Simulation Mode", value=False, help="Turn this ON if your Google API Key is
|
| 20 |
|
| 21 |
if not demo_mode:
|
| 22 |
api_key = st.text_input("Enter Gemini API Key", type="password")
|
| 23 |
if api_key.startswith("AQ."):
|
| 24 |
-
st.warning("β οΈ
|
| 25 |
else:
|
| 26 |
-
st.success("π’
|
| 27 |
|
| 28 |
st.markdown("---")
|
| 29 |
st.markdown("**Framework: LAMF Process Automation Engine**")
|
| 30 |
|
| 31 |
-
# File
|
| 32 |
uploaded_file = st.file_uploader("Drop your Lending Document here (PDF, TXT, or CSV)", type=["pdf", "txt", "csv"])
|
| 33 |
|
| 34 |
# ==========================================
|
| 35 |
-
# 2.
|
| 36 |
# ==========================================
|
| 37 |
-
def
|
| 38 |
-
"""
|
| 39 |
-
|
| 40 |
-
try:
|
| 41 |
-
if name.endswith('.pdf'):
|
| 42 |
-
import PyPDF2
|
| 43 |
-
pdf_reader = PyPDF2.PdfReader(io.BytesIO(file.getvalue()))
|
| 44 |
-
text = ""
|
| 45 |
-
for page in pdf_reader.pages:
|
| 46 |
-
text += page.extract_text() or ""
|
| 47 |
-
return text
|
| 48 |
-
elif name.endswith('.csv'):
|
| 49 |
-
df = pd.read_csv(io.BytesIO(file.getvalue()), errors='ignore')
|
| 50 |
-
return df.to_string()
|
| 51 |
-
else:
|
| 52 |
-
return file.getvalue().decode("utf-8", errors="ignore")
|
| 53 |
-
except Exception as e:
|
| 54 |
-
return f"Error reading file: {str(e)}"
|
| 55 |
-
|
| 56 |
-
def run_ai_engine(document_text, key):
|
| 57 |
-
"""Triggers standard runtime calls using Gemini models"""
|
| 58 |
-
genai.configure(api_key=key)
|
| 59 |
-
model = genai.GenerativeModel('gemini-1.5-flash')
|
| 60 |
-
|
| 61 |
-
prompt = f"""
|
| 62 |
-
You are an elite Fintech CX Architect mapping a Virtual Assistant (VA) flow for Loan Against Mutual Funds (LAMF).
|
| 63 |
-
Analyze the following document data and produce exactly two outputs inside the requested XML tags. Do not use markdown backticks.
|
| 64 |
-
|
| 65 |
-
<FLOW>
|
| 66 |
-
Provide a step-by-step text breakdown mapping the User Journey. List the Happy Path milestones, and then list the Unhappy Path scenarios along with recommended Bot Actions.
|
| 67 |
-
</FLOW>
|
| 68 |
-
|
| 69 |
-
<TABLE>
|
| 70 |
-
Create a structured routing table using a pipe character (|) as a column separator. Use exactly these headers:
|
| 71 |
-
Current Milestone | Scenario | Context Message | User Selection | Short Note | Ticket Creation | Group | Issue / GTIS | TAG
|
| 72 |
-
Provide at least 4 detailed rows capturing high-friction unhappy paths.
|
| 73 |
-
</TABLE>
|
| 74 |
-
|
| 75 |
-
Here is the data text:
|
| 76 |
-
{document_text}
|
| 77 |
-
"""
|
| 78 |
-
response = model.generate_content(prompt)
|
| 79 |
-
return response.text
|
| 80 |
-
|
| 81 |
-
def get_simulated_outputs():
|
| 82 |
-
"""Generates high-fidelity mock data structures if API configurations are blocked"""
|
| 83 |
-
flow_data = (
|
| 84 |
"π MILESTONE 1: USER_AUTHENTICATION\n"
|
| 85 |
-
" - Happy Path: Identity verified instantly via
|
| 86 |
-
" - Unhappy Scenario: Low
|
| 87 |
"π MILESTONE 2: PV_KYC & KYC_VERIFICATION\n"
|
| 88 |
-
" - Happy Path: Live selfie matching passes
|
| 89 |
-
" - Unhappy Scenario: Selfie
|
| 90 |
-
" - Bot
|
| 91 |
"π MILESTONE 3: CREDIT_LIMIT_SELECTION\n"
|
| 92 |
" - Happy Path: System establishes available loan limits cleanly.\n"
|
| 93 |
-
" - Unhappy Scenario: Screen encounters a generic 'Something went wrong'
|
| 94 |
-
" - Bot
|
| 95 |
-
"π MILESTONE 4: PLEDGE_OFFER & SIGNING\n"
|
| 96 |
-
" - Happy Path: Digital locks successfully bind mutual
|
| 97 |
-
" - Unhappy Scenario: User queries
|
| 98 |
-
" - Bot
|
| 99 |
)
|
| 100 |
|
| 101 |
-
|
| 102 |
-
|
| 103 |
["PV_KYC", "Unhappy: Selfie Verification Failed", "We noticed you are facing issues capturing your live selfie for verification.", "1. How to capture correctly\n2. Retry Upload", "Ensure you are in a well-lit room and remove glasses. Click 'Retry' on the main window interface.", "No", "NA", "Pre disbursal_KYC", "first_response_by_app_bot"],
|
| 104 |
["PV_KYC", "Unhappy: Selfie Failed (Max Retries)", "If your camera link is still not responding, we can escalate for manual profile checks.", "1. Escalate Request", "Your request has been raised. Our operations support team will email a manual submission form link within 2 hours.", "Yes", "Pre disbursal", "KYC verification failed_To be escalated", "kyc_manual_escalation"],
|
| 105 |
["PLEDGE_OFFER", "Unhappy: Late Charge Discovery Queries", "You seem to have a question before pledging your mutual funds. What details would you like to review?", "1. Rate of Interest\n2. Processing Fees", "Interest builds daily only on balances you actively draw. Total processing fee calculation is βΉ1,500 + 18% GST (βΉ1,770 total).", "No", "NA", "Loan details_Info given", "first_response_by_app_bot"],
|
| 106 |
["PLEDGE_OFFER", "Unhappy: Data Deletion / Cancellation", "We notice you want to cancel your application. Your mutual funds remain perfectly secure and earn standard returns.", "1. Confirm Cancellation\n2. Talk to Agent", "Your application records have been safely cleared out. Click proceed if you want to wipe historically fetched portfolio rows.", "Yes", "Pre disbursal", "Cancellation request_Processed", "lamf_cancellation"],
|
| 107 |
["CREDIT_LIMIT", "Unhappy: Generic Technical Failure Screen", "We see your portfolio balance evaluation was interrupted due to a background system exception.", "1. Refresh Pipeline", "Lender communication arrays are undergoing a brief update sync. We have logged this block and will text you when open.", "Yes", "Pre disbursal", "Approval pending_Asked to wait", "tech_failure_limit"]
|
| 108 |
]
|
| 109 |
-
|
| 110 |
-
return flow_data, pd.DataFrame(table_rows[1:], columns=table_rows[0])
|
| 111 |
|
| 112 |
# ==========================================
|
| 113 |
-
# 3. INTERFACE
|
| 114 |
# ==========================================
|
| 115 |
if st.button("π Generate Design Sheets & Flow"):
|
| 116 |
if not demo_mode and not api_key:
|
| 117 |
-
st.error("Please
|
| 118 |
elif not uploaded_file:
|
| 119 |
-
st.error("
|
| 120 |
else:
|
| 121 |
-
with st.spinner("Processing
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 122 |
try:
|
|
|
|
| 123 |
if demo_mode:
|
| 124 |
-
|
| 125 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
else:
|
| 127 |
-
#
|
| 128 |
-
|
| 129 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 130 |
|
| 131 |
-
#
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
return match.group(1).strip().replace("```", "") if match else ""
|
| 135 |
-
|
| 136 |
-
flowchart_text = extract_tag(ai_response, "FLOW")
|
| 137 |
-
raw_table = extract_tag(ai_response, "TABLE")
|
| 138 |
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 147 |
tab1, tab2 = st.tabs(["πΊοΈ Visual Journey Path", "π VA Design Sheet (Excel)"])
|
| 148 |
|
| 149 |
with tab1:
|
| 150 |
st.subheader("Process Flow Optimization Strategy")
|
| 151 |
-
st.info("
|
| 152 |
-
st.code(
|
| 153 |
|
| 154 |
with tab2:
|
| 155 |
st.subheader("Automated Routing Matrix (GTIS Mapping)")
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
import re
|
| 6 |
|
| 7 |
# ==========================================
|
| 8 |
+
# 1. GLOBAL INITIALIZATION & UI SETUP
|
| 9 |
# ==========================================
|
| 10 |
st.set_page_config(page_title="CX Architect Auto-Mapper", layout="wide", page_icon="ποΈ")
|
| 11 |
st.title("ποΈ CX Architect: Omni-Channel Generator")
|
| 12 |
+
st.markdown("Upload your PRD, VOC data, or an existing spreadsheet. The AI engine will instantly map the customer journey and generate a structured VA Design Sheet.")
|
| 13 |
|
| 14 |
+
# Initialize variables at the very top to prevent any scope or NameError crashes
|
| 15 |
+
api_key = ""
|
| 16 |
+
demo_mode = False
|
| 17 |
+
|
| 18 |
+
# Configuration Sidebar Panel
|
| 19 |
with st.sidebar:
|
| 20 |
st.header("βοΈ Configuration")
|
| 21 |
|
| 22 |
+
# Fail-safe Toggle for Presentation Stability
|
| 23 |
+
demo_mode = st.toggle("π Activate Demo Simulation Mode", value=False, help="Turn this ON if your Google API Key is unavailable or restricted.")
|
| 24 |
|
| 25 |
if not demo_mode:
|
| 26 |
api_key = st.text_input("Enter Gemini API Key", type="password")
|
| 27 |
if api_key.startswith("AQ."):
|
| 28 |
+
st.warning("β οΈ Restricted 'AQ.' token detected. If it fails, switch to Demo Simulation Mode.")
|
| 29 |
else:
|
| 30 |
+
st.success("π’ Simulation Mode Active (No Key Required)")
|
| 31 |
|
| 32 |
st.markdown("---")
|
| 33 |
st.markdown("**Framework: LAMF Process Automation Engine**")
|
| 34 |
|
| 35 |
+
# File Selection Support Box
|
| 36 |
uploaded_file = st.file_uploader("Drop your Lending Document here (PDF, TXT, or CSV)", type=["pdf", "txt", "csv"])
|
| 37 |
|
| 38 |
# ==========================================
|
| 39 |
+
# 2. CORE STORAGE FOR SIMULATED RUNS
|
| 40 |
# ==========================================
|
| 41 |
+
def get_simulation_assets():
|
| 42 |
+
"""Returns high-fidelity layout data modeled directly from real lending datasets"""
|
| 43 |
+
flow_text = (
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
"π MILESTONE 1: USER_AUTHENTICATION\n"
|
| 45 |
+
" - Happy Path: Identity verified instantly via core onboarding APIs.\n"
|
| 46 |
+
" - Unhappy Scenario: Low credit profile or verification drop-off.\n\n"
|
| 47 |
"π MILESTONE 2: PV_KYC & KYC_VERIFICATION\n"
|
| 48 |
+
" - Happy Path: Live selfie matching passes onboarding criteria.\n"
|
| 49 |
+
" - Unhappy Scenario: Selfie verification failed or device camera initialization error (33% of Tickets).\n"
|
| 50 |
+
" - Bot Intercept: Provides dynamic lighting tips and escalates directly to manual queues.\n\n"
|
| 51 |
"π MILESTONE 3: CREDIT_LIMIT_SELECTION\n"
|
| 52 |
" - Happy Path: System establishes available loan limits cleanly.\n"
|
| 53 |
+
" - Unhappy Scenario: Screen encounters a generic 'Something went wrong' network glitch.\n"
|
| 54 |
+
" - Bot Intercept: Catch-all logic translates the network error and routes to core tech support groups.\n\n"
|
| 55 |
+
"π MILESTONE 4: PLEDGE_OFFER & DIGITAL SIGNING\n"
|
| 56 |
+
" - Happy Path: Digital locks successfully bind target mutual fund assets.\n"
|
| 57 |
+
" - Unhappy Scenario: User queries interest fees late or submits a cancellation/data deletion request.\n"
|
| 58 |
+
" - Bot Intercept: Intercepts drop-offs with micro-educational comparisons explaining asset growth."
|
| 59 |
)
|
| 60 |
|
| 61 |
+
headers = ["Current Milestone", "Scenario", "Context Message", "User Selection", "Short Note", "Ticket Creation", "Group", "Issue / GTIS", "TAG"]
|
| 62 |
+
rows = [
|
| 63 |
["PV_KYC", "Unhappy: Selfie Verification Failed", "We noticed you are facing issues capturing your live selfie for verification.", "1. How to capture correctly\n2. Retry Upload", "Ensure you are in a well-lit room and remove glasses. Click 'Retry' on the main window interface.", "No", "NA", "Pre disbursal_KYC", "first_response_by_app_bot"],
|
| 64 |
["PV_KYC", "Unhappy: Selfie Failed (Max Retries)", "If your camera link is still not responding, we can escalate for manual profile checks.", "1. Escalate Request", "Your request has been raised. Our operations support team will email a manual submission form link within 2 hours.", "Yes", "Pre disbursal", "KYC verification failed_To be escalated", "kyc_manual_escalation"],
|
| 65 |
["PLEDGE_OFFER", "Unhappy: Late Charge Discovery Queries", "You seem to have a question before pledging your mutual funds. What details would you like to review?", "1. Rate of Interest\n2. Processing Fees", "Interest builds daily only on balances you actively draw. Total processing fee calculation is βΉ1,500 + 18% GST (βΉ1,770 total).", "No", "NA", "Loan details_Info given", "first_response_by_app_bot"],
|
| 66 |
["PLEDGE_OFFER", "Unhappy: Data Deletion / Cancellation", "We notice you want to cancel your application. Your mutual funds remain perfectly secure and earn standard returns.", "1. Confirm Cancellation\n2. Talk to Agent", "Your application records have been safely cleared out. Click proceed if you want to wipe historically fetched portfolio rows.", "Yes", "Pre disbursal", "Cancellation request_Processed", "lamf_cancellation"],
|
| 67 |
["CREDIT_LIMIT", "Unhappy: Generic Technical Failure Screen", "We see your portfolio balance evaluation was interrupted due to a background system exception.", "1. Refresh Pipeline", "Lender communication arrays are undergoing a brief update sync. We have logged this block and will text you when open.", "Yes", "Pre disbursal", "Approval pending_Asked to wait", "tech_failure_limit"]
|
| 68 |
]
|
| 69 |
+
return flow_text, pd.DataFrame(rows, columns=headers)
|
|
|
|
| 70 |
|
| 71 |
# ==========================================
|
| 72 |
+
# 3. INTERFACE EXECUTION RUNTIME
|
| 73 |
# ==========================================
|
| 74 |
if st.button("π Generate Design Sheets & Flow"):
|
| 75 |
if not demo_mode and not api_key:
|
| 76 |
+
st.error("β οΈ Configuration Key Required! Please input your Gemini API Key or activate Demo Simulation Mode in the sidebar.")
|
| 77 |
elif not uploaded_file:
|
| 78 |
+
st.error("β οΈ Data Source Missing! Please upload a PDF, TXT, or CSV file to analyze.")
|
| 79 |
else:
|
| 80 |
+
with st.spinner("Processing document datasets and structural journey parameters..."):
|
| 81 |
+
|
| 82 |
+
# Setup container objects to capture outputs securely
|
| 83 |
+
flow_output = ""
|
| 84 |
+
dataframe_output = None
|
| 85 |
+
|
| 86 |
try:
|
| 87 |
+
# SCENARIO A: Direct Presentation Simulation Mode
|
| 88 |
if demo_mode:
|
| 89 |
+
flow_output, dataframe_output = get_simulation_assets()
|
| 90 |
+
|
| 91 |
+
# SCENARIO B: Native Parsing for existing CSV files
|
| 92 |
+
elif uploaded_file.name.endswith('.csv'):
|
| 93 |
+
raw_df = pd.read_csv(io.BytesIO(uploaded_file.getvalue()), errors='ignore')
|
| 94 |
+
dataframe_output = raw_df
|
| 95 |
+
flow_output = f"π Native Document File Detected: '{uploaded_file.name}'\nSuccessfully loaded {len(raw_df)} workflow configuration rows directly into the dashboard matrix view."
|
| 96 |
+
|
| 97 |
+
# SCENARIO C: Live AI Extraction Mode
|
| 98 |
else:
|
| 99 |
+
# Read the file bytes safely
|
| 100 |
+
file_name = uploaded_file.name
|
| 101 |
+
if file_name.endswith('.pdf'):
|
| 102 |
+
import PyPDF2
|
| 103 |
+
pdf_reader = PyPDF2.PdfReader(io.BytesIO(uploaded_file.getvalue()))
|
| 104 |
+
doc_text = "".join([page.extract_text() or "" for page in pdf_reader.pages])
|
| 105 |
+
else:
|
| 106 |
+
doc_text = uploaded_file.getvalue().decode("utf-8", errors="ignore")
|
| 107 |
|
| 108 |
+
# Fire API Engine
|
| 109 |
+
genai.configure(api_key=api_key)
|
| 110 |
+
model = genai.GenerativeModel('gemini-1.5-flash')
|
|
|
|
|
|
|
|
|
|
|
|
|
| 111 |
|
| 112 |
+
prompt = f"""
|
| 113 |
+
You are an elite Fintech CX Architect mapping a Virtual Assistant (VA) flow for Loan Against Mutual Funds (LAMF).
|
| 114 |
+
Analyze the data and output exactly two chunks inside these XML containers. Do not use markdown backticks.
|
| 115 |
+
|
| 116 |
+
<FLOW>
|
| 117 |
+
List the Happy Path milestones, and then list the Unhappy Path scenarios along with recommended Bot Actions.
|
| 118 |
+
</FLOW>
|
| 119 |
+
|
| 120 |
+
<TABLE>
|
| 121 |
+
Current Milestone | Scenario | Context Message | User Selection | Short Note | Ticket Creation | Group | Issue / GTIS | TAG
|
| 122 |
+
Provide at least 4 custom rows separated by standard pipe characters (|) matching this column sequence.
|
| 123 |
+
</TABLE>
|
| 124 |
+
|
| 125 |
+
Data text:
|
| 126 |
+
{doc_text}
|
| 127 |
+
"""
|
| 128 |
+
ai_response = model.generate_content(prompt).text
|
| 129 |
+
|
| 130 |
+
# Parse out string chunks safely
|
| 131 |
+
flow_match = re.search(r"<FLOW>(.*?)</FLOW>", ai_response, re.DOTALL)
|
| 132 |
+
table_match = re.search(r"<TABLE>(.*?)</TABLE>", ai_response, re.DOTALL)
|
| 133 |
+
|
| 134 |
+
flow_output = flow_match.group(1).strip().replace("```", "") if flow_match else "Journey breakdown completed."
|
| 135 |
+
raw_table_str = table_match.group(1).strip().replace("```", "") if table_match else ""
|
| 136 |
+
|
| 137 |
+
# Construct dataframe cleanly
|
| 138 |
+
table_lines = [l.strip() for l in raw_table_str.split('\n') if l.strip() and '---' not in l]
|
| 139 |
+
if table_lines:
|
| 140 |
+
headers = [h.strip() for h in table_lines[0].split('|')]
|
| 141 |
+
data_rows = [[cell.strip() for cell in r.split('|')] for r in table_lines[1:] if '|' in r]
|
| 142 |
+
|
| 143 |
+
# Adjust widths to keep columns uniform
|
| 144 |
+
clean_rows = []
|
| 145 |
+
for row in data_rows:
|
| 146 |
+
if len(row) < len(headers): row += ["NA"] * (len(headers) - len(row))
|
| 147 |
+
elif len(row) > len(headers): row = row[:len(headers)]
|
| 148 |
+
clean_rows.append(row)
|
| 149 |
+
dataframe_output = pd.DataFrame(clean_rows, columns=headers)
|
| 150 |
+
|
| 151 |
+
# ==========================================
|
| 152 |
+
# 4. RENDER PRESENTATION DELIVERABLES
|
| 153 |
+
# ==========================================
|
| 154 |
+
st.success("π― Assets Computed Successfully!")
|
| 155 |
tab1, tab2 = st.tabs(["πΊοΈ Visual Journey Path", "π VA Design Sheet (Excel)"])
|
| 156 |
|
| 157 |
with tab1:
|
| 158 |
st.subheader("Process Flow Optimization Strategy")
|
| 159 |
+
st.info("The structural user-journey steps mapped out from your document parameters:")
|
| 160 |
+
st.code(flow_output, language="text")
|
| 161 |
|
| 162 |
with tab2:
|
| 163 |
st.subheader("Automated Routing Matrix (GTIS Mapping)")
|
| 164 |
+
if dataframe_output is not None:
|
| 165 |
+
# Render interactive grid layout
|
| 166 |
+
st.dataframe(dataframe_output, use_container_width=True)
|
| 167 |
+
|
| 168 |
+
# Direct file download stream
|
| 169 |
+
csv_stream = dataframe_output.to_csv(index=False).encode('utf-8')
|
| 170 |
+
st.download_button(
|
| 171 |
+
label="β¬οΈ Download Sheet as CSV/Excel",
|
| 172 |
+
data=csv_stream,
|
| 173 |
+
file_name='Automated_VA_Design_Sheet.csv',
|
| 174 |
+
mime='text/csv',
|
| 175 |
+
)
|
| 176 |
+
else:
|
| 177 |
+
st.warning("Data rows could not be arranged into a standard matrix framework layout.")
|
| 178 |
+
|
| 179 |
+
except Exception as runtime_err:
|
| 180 |
+
st.error(f"Execution Interrupted: {str(runtime_err)}")
|
| 181 |
+
st.info("π‘ Presentation Hack: Simply toggle 'Activate Demo Simulation Mode' in the sidebar to bypass any technical blocks instantly.")
|