Spaces:
Sleeping
Sleeping
Update src/streamlit_app.py
Browse files- src/streamlit_app.py +20 -7
src/streamlit_app.py
CHANGED
|
@@ -2,7 +2,7 @@ import streamlit as st
|
|
| 2 |
import pandas as pd
|
| 3 |
import matplotlib.pyplot as plt
|
| 4 |
import google.generativeai as genai
|
| 5 |
-
import json
|
| 6 |
import os
|
| 7 |
from datetime import datetime
|
| 8 |
|
|
@@ -27,10 +27,12 @@ def process_loan_data(df: pd.DataFrame):
|
|
| 27 |
return ecl_df
|
| 28 |
|
| 29 |
def get_gemini_decision(segment, pd_val, lgd_val, ead_val, ecl_val):
|
| 30 |
-
"""Ask Gemini to decide
|
| 31 |
model = genai.GenerativeModel("gemini-1.5-pro")
|
| 32 |
system_prompt = """You are a financial risk advisor.
|
| 33 |
-
Return only JSON
|
|
|
|
|
|
|
| 34 |
user_prompt = f"""
|
| 35 |
Segment: {segment}
|
| 36 |
PD: {pd_val:.3f}
|
|
@@ -42,16 +44,27 @@ Rules:
|
|
| 42 |
- PD > 0.20 and ECL rising ⇒ reduce_disbursement
|
| 43 |
- PD < 0.15 ⇒ maintain
|
| 44 |
"""
|
|
|
|
| 45 |
try:
|
| 46 |
response = model.generate_content(
|
| 47 |
[{"role": "system", "parts": [system_prompt]},
|
| 48 |
{"role": "user", "parts": [user_prompt]}],
|
| 49 |
-
generation_config={"temperature": 0.
|
| 50 |
)
|
| 51 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
except Exception:
|
| 53 |
-
|
| 54 |
-
return result
|
| 55 |
|
| 56 |
# ====== UI ======
|
| 57 |
st.title("📊 Expected Credit Loss (ECL) Risk Dashboard")
|
|
|
|
| 2 |
import pandas as pd
|
| 3 |
import matplotlib.pyplot as plt
|
| 4 |
import google.generativeai as genai
|
| 5 |
+
import json, re
|
| 6 |
import os
|
| 7 |
from datetime import datetime
|
| 8 |
|
|
|
|
| 27 |
return ecl_df
|
| 28 |
|
| 29 |
def get_gemini_decision(segment, pd_val, lgd_val, ead_val, ecl_val):
|
| 30 |
+
"""Ask Gemini to decide and sanitize any invalid JSON output."""
|
| 31 |
model = genai.GenerativeModel("gemini-1.5-pro")
|
| 32 |
system_prompt = """You are a financial risk advisor.
|
| 33 |
+
Return only valid JSON in this exact schema:
|
| 34 |
+
{"action":"increase_interest"|"reduce_disbursement"|"maintain","rationale":"string","confidence":float}
|
| 35 |
+
No text outside the JSON."""
|
| 36 |
user_prompt = f"""
|
| 37 |
Segment: {segment}
|
| 38 |
PD: {pd_val:.3f}
|
|
|
|
| 44 |
- PD > 0.20 and ECL rising ⇒ reduce_disbursement
|
| 45 |
- PD < 0.15 ⇒ maintain
|
| 46 |
"""
|
| 47 |
+
|
| 48 |
try:
|
| 49 |
response = model.generate_content(
|
| 50 |
[{"role": "system", "parts": [system_prompt]},
|
| 51 |
{"role": "user", "parts": [user_prompt]}],
|
| 52 |
+
generation_config={"temperature": 0.1}
|
| 53 |
)
|
| 54 |
+
text = response.text.strip()
|
| 55 |
+
|
| 56 |
+
# extract JSON substring if extra text exists
|
| 57 |
+
match = re.search(r'\{.*\}', text, re.DOTALL)
|
| 58 |
+
if match:
|
| 59 |
+
text = match.group(0)
|
| 60 |
+
|
| 61 |
+
data = json.loads(text)
|
| 62 |
+
if not all(k in data for k in ["action", "rationale", "confidence"]):
|
| 63 |
+
raise ValueError("Missing keys")
|
| 64 |
+
return data
|
| 65 |
+
|
| 66 |
except Exception:
|
| 67 |
+
return {"action": "maintain", "rationale": "Fallback - cleaned JSON failed", "confidence": 0.0}
|
|
|
|
| 68 |
|
| 69 |
# ====== UI ======
|
| 70 |
st.title("📊 Expected Credit Loss (ECL) Risk Dashboard")
|