GenAICoder commited on
Commit
08b90d4
·
verified ·
1 Parent(s): 885bddc

Update analytics/ai_assistant.py

Browse files
Files changed (1) hide show
  1. analytics/ai_assistant.py +72 -1
analytics/ai_assistant.py CHANGED
@@ -123,6 +123,77 @@ def build_portfolio_context(df: pd.DataFrame, as_of_month: str | None = None, se
123
 
124
  return "\n".join(lines)
125
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
 
127
  def _get_inference_client():
128
  if not HF_TOKEN:
@@ -136,7 +207,7 @@ def _get_inference_client():
136
 
137
 
138
  def generate_ai_answer(question: str, df: pd.DataFrame, as_of_month: str | None = None, segment: str | None = None):
139
- summary = build_portfolio_context(df, as_of_month=as_of_month, segment=segment)
140
  prompt = (
141
  "You are a senior risk manager assistant responding to portfolio analytics questions. "
142
  "Use the risk context below and answer the user clearly, describing what is happening, why it is happening, and what actions should be considered. "
 
123
 
124
  return "\n".join(lines)
125
 
126
+ def build_calendar_performance_context(df: pd.DataFrame, as_of_month: str | None = None):
127
+ if not as_of_month or as_of_month == "All":
128
+ return ""
129
+
130
+ month_df = _filter_by_month(df, as_of_month)
131
+ if month_df.empty:
132
+ return f"No data found for {as_of_month}."
133
+
134
+ lines = [f"Calendar month snapshot for {as_of_month}:"]
135
+ if "balance" in month_df.columns:
136
+ lines.append(f" - Total balance: {month_df['balance'].sum(skipna=True):.0f}")
137
+ lines.append(f" - Total accounts: {month_df['account_id'].nunique() if 'account_id' in month_df.columns else 0}")
138
+ if "dpd" in month_df.columns:
139
+ lines.append(f" - Accounts with dpd>=30: {month_df.loc[month_df['dpd'].fillna(0) >= 30, 'account_id'].nunique() if 'account_id' in month_df.columns else 0}")
140
+
141
+ for metric in RISK_METRICS:
142
+ try:
143
+ view = generate_metric_view(month_df, metric_name=metric, group_col=None)
144
+ rate_col = [c for c in view.columns if "rate" in c.lower()][0]
145
+ metric_rate = view.loc[0, rate_col]
146
+ lines.append(f" - {metric} rate: {_fmt_pct(metric_rate)}")
147
+ except Exception:
148
+ continue
149
+
150
+ return "\n".join(lines)
151
+
152
+
153
+ def build_vintage_performance_context(df: pd.DataFrame):
154
+ if "booking_vintage" not in df.columns:
155
+ return ""
156
+
157
+ lines = ["Vintage performance summary:"]
158
+ for metric in RISK_METRICS:
159
+ try:
160
+ view = generate_metric_view(df, metric_name=metric, group_col="booking_vintage")
161
+ rate_col = [c for c in view.columns if "rate" in c.lower()][0]
162
+ if view.empty:
163
+ continue
164
+ top = view.sort_values(rate_col, ascending=False).head(2)
165
+ bottom = view.sort_values(rate_col, ascending=True).head(1)
166
+ lines.append(
167
+ f" - {metric}: highest risk vintage {top.iloc[0]['booking_vintage']} at {_fmt_pct(top.iloc[0][rate_col])}, "
168
+ f"lowest risk vintage {bottom.iloc[0]['booking_vintage']} at {_fmt_pct(bottom.iloc[0][rate_col])}."
169
+ )
170
+ except Exception:
171
+ continue
172
+
173
+ return "\n".join(lines)
174
+
175
+
176
+ def build_context_for_question(df: pd.DataFrame, as_of_month: str | None = None, segment: str | None = None, question: str | None = None):
177
+ sections = [build_portfolio_context(df, as_of_month=as_of_month, segment=segment)]
178
+ q = (question or "").lower()
179
+
180
+ if "month" in q or "calendar" in q or "as of" in q:
181
+ month_context = build_calendar_performance_context(df, as_of_month=as_of_month)
182
+ if month_context:
183
+ sections.append(month_context)
184
+
185
+ if "vintage" in q or "trend" in q or "booking vintage" in q or "compare" in q:
186
+ vintage_context = build_vintage_performance_context(df)
187
+ if vintage_context:
188
+ sections.append(vintage_context)
189
+
190
+ if segment and segment in df.columns:
191
+ segment_context = build_portfolio_context(df, as_of_month=as_of_month, segment=segment)
192
+ if segment_context:
193
+ sections.append(segment_context)
194
+
195
+ return "\n\n".join(section for section in sections if section)
196
+
197
 
198
  def _get_inference_client():
199
  if not HF_TOKEN:
 
207
 
208
 
209
  def generate_ai_answer(question: str, df: pd.DataFrame, as_of_month: str | None = None, segment: str | None = None):
210
+ summary = build_context_for_question(df, as_of_month=as_of_month, segment=segment, question=question)
211
  prompt = (
212
  "You are a senior risk manager assistant responding to portfolio analytics questions. "
213
  "Use the risk context below and answer the user clearly, describing what is happening, why it is happening, and what actions should be considered. "