Jay-2776 commited on
Commit
aecde4e
·
verified ·
1 Parent(s): 4281ddb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +88 -68
app.py CHANGED
@@ -18,6 +18,8 @@ from google.analytics.data_v1beta.types import (
18
  Filter
19
  )
20
 
 
 
21
  warnings.filterwarnings("ignore", category=FutureWarning)
22
 
23
  # =====================================================
@@ -25,7 +27,10 @@ warnings.filterwarnings("ignore", category=FutureWarning)
25
  # =====================================================
26
  GA4_PROPERTY_ID = os.environ["GA4_PROPERTY_ID"]
27
  SERVICE_ACCOUNT_JSON = json.loads(os.environ["SERVICE_ACCOUNT_JSON"])
28
- SITE_DOMAIN = "rishabhsoft.com" # change if required
 
 
 
29
 
30
  # =====================================================
31
  # GA CLIENT
@@ -55,7 +60,7 @@ def classify_source(src):
55
  return "External"
56
 
57
  # =====================================================
58
- # CACHED TOP PAGES
59
  # =====================================================
60
  @lru_cache(maxsize=3)
61
  def fetch_top_pages(start, end):
@@ -99,7 +104,7 @@ def fetch_journey(start, end, landing_page):
99
  return pd.DataFrame(rows)
100
 
101
  # =====================================================
102
- # FORM SUBMISSIONS (GA4-SAFE PROXY)
103
  # =====================================================
104
  def get_form_submissions(start, end, landing_page):
105
  req = RunReportRequest(
@@ -134,21 +139,74 @@ def get_form_submissions(start, end, landing_page):
134
  res = ga.run_report(req)
135
  return sum(int(r.metric_values[0].value) for r in res.rows)
136
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  # =====================================================
138
  # MAIN LOGIC
139
  # =====================================================
140
  def run_journey(start, end, landing_page):
141
  df = fetch_journey(start, end, landing_page)
142
  if df.empty:
143
- return None, pd.DataFrame(), "No data found."
144
 
145
  total_users = df["Views"].sum()
146
  form_yes = get_form_submissions(start, end, landing_page)
 
147
  journey_converted = "Yes" if form_yes > 0 else "No"
148
 
149
- # ===========================
150
- # EXIT TABLE
151
- # ===========================
 
 
 
 
152
  exit_df = (
153
  df.groupby("From")["Views"]
154
  .sum()
@@ -161,72 +219,32 @@ def run_journey(start, end, landing_page):
161
  exit_df["Source Type"] = exit_df["Exit Source / Page"].apply(classify_source)
162
  exit_df["Exit Source / Page"] = exit_df["Exit Source / Page"].apply(clean_path)
163
 
164
- # 🔑 Option C logic
165
  exit_df["Journey Converted?"] = journey_converted
166
- exit_df["Form Submitted Before Exit?"] = "No"
167
-
168
- exit_df["Insight"] = exit_df.apply(
169
- lambda r:
170
- "Converted journey – exit after intent met"
171
- if r["Journey Converted?"] == "Yes"
172
- else (
173
- "High exit – landing intent mismatch"
174
- if r["Source Type"] == "External"
175
- else "Conversion leak – improve CTA"
176
- ),
177
- axis=1
178
- )
179
 
180
- exit_df = exit_df[
181
- [
182
- "Exit Source / Page",
183
- "Source Type",
184
- "Users Entered",
185
- "Users Exited",
186
- "Exit Rate %",
187
- "Journey Converted?",
188
- "Form Submitted Before Exit?",
189
- "Insight"
190
- ]
191
- ].sort_values("Users Exited", ascending=False)
192
-
193
- # ===========================
194
- # SANKEY
195
- # ===========================
196
- labels, idx = [], {}
197
-
198
- def add(n):
199
- if n not in idx:
200
- idx[n] = len(labels)
201
- labels.append(n)
202
- return idx[n]
203
-
204
- s, t, v = [], [], []
205
-
206
- for _, r in df.iterrows():
207
- s.append(add(clean_path(r["From"])))
208
- t.append(add(clean_path(r["To"])))
209
- v.append(r["Views"])
210
-
211
- p = add(clean_path(landing_page))
212
- e = add("Exit")
213
- s.append(p)
214
- t.append(e)
215
- v.append(total_users - form_yes)
216
-
217
- if form_yes > 0:
218
- f = add("Form Submitted")
219
- s.append(p)
220
- t.append(f)
221
- v.append(form_yes)
222
 
223
  fig = go.Figure(go.Sankey(
224
- node=dict(label=labels, pad=22, thickness=18),
225
- link=dict(source=s, target=t, value=v)
 
 
 
 
 
 
 
 
226
  ))
227
 
228
  fig.update_layout(
229
- title="Customer Journey Flow (Entry → Exit / Conversion)",
230
  height=650
231
  )
232
 
@@ -237,7 +255,9 @@ def run_journey(start, end, landing_page):
237
 
238
  - **Journey Converted:** {journey_converted}
239
  - **Form Submissions:** {form_yes}
240
- - **Exited Without Form:** {total_users - form_yes}
 
 
241
  """
242
 
243
  return fig, exit_df, summary
@@ -246,7 +266,7 @@ def run_journey(start, end, landing_page):
246
  # UI
247
  # =====================================================
248
  with gr.Blocks() as app:
249
- gr.Markdown("## 🚀 Customer Journey Explorer (GA4 – Business View)")
250
 
251
  with gr.Row():
252
  sd = gr.Textbox(value=str(date.today() - timedelta(days=30)), label="Start Date")
 
18
  Filter
19
  )
20
 
21
+ from openai import OpenAI
22
+
23
  warnings.filterwarnings("ignore", category=FutureWarning)
24
 
25
  # =====================================================
 
27
  # =====================================================
28
  GA4_PROPERTY_ID = os.environ["GA4_PROPERTY_ID"]
29
  SERVICE_ACCOUNT_JSON = json.loads(os.environ["SERVICE_ACCOUNT_JSON"])
30
+ OPENAI_API_KEY = os.environ["OPENAI_API_KEY"]
31
+ SITE_DOMAIN = "rishabhsoft.com"
32
+
33
+ client = OpenAI(api_key=OPENAI_API_KEY)
34
 
35
  # =====================================================
36
  # GA CLIENT
 
60
  return "External"
61
 
62
  # =====================================================
63
+ # TOP PAGES (FAST)
64
  # =====================================================
65
  @lru_cache(maxsize=3)
66
  def fetch_top_pages(start, end):
 
104
  return pd.DataFrame(rows)
105
 
106
  # =====================================================
107
+ # FORM SUBMISSIONS (GA4-SAFE)
108
  # =====================================================
109
  def get_form_submissions(start, end, landing_page):
110
  req = RunReportRequest(
 
139
  res = ga.run_report(req)
140
  return sum(int(r.metric_values[0].value) for r in res.rows)
141
 
142
+ # =====================================================
143
+ # LLM INTENT CLASSIFIER (CACHED)
144
+ # =====================================================
145
+ @lru_cache(maxsize=100)
146
+ def classify_intent_llm(start_page, pages, converted):
147
+ prompt = f"""
148
+ You are a digital analytics expert.
149
+
150
+ Classify the user intent into ONE of:
151
+ - Conversion
152
+ - Evaluation
153
+ - Research
154
+ - Navigation
155
+ - Low Intent
156
+
157
+ Rules:
158
+ - Use only the data given
159
+ - Do NOT invent behavior
160
+ - Be concise
161
+
162
+ Journey Data:
163
+ Start Page: {start_page}
164
+ Pages Visited: {", ".join(pages[:5])}
165
+ Form Submitted: {"Yes" if converted else "No"}
166
+
167
+ Return format:
168
+ Intent: <Intent>
169
+ Reason: <One sentence explanation>
170
+ """
171
+
172
+ resp = client.chat.completions.create(
173
+ model="gpt-4o-mini",
174
+ messages=[{"role": "user", "content": prompt}],
175
+ temperature=0
176
+ )
177
+
178
+ txt = resp.choices[0].message.content.strip()
179
+ intent = "Unknown"
180
+ reason = ""
181
+
182
+ for line in txt.splitlines():
183
+ if line.lower().startswith("intent"):
184
+ intent = line.split(":", 1)[1].strip()
185
+ if line.lower().startswith("reason"):
186
+ reason = line.split(":", 1)[1].strip()
187
+
188
+ return intent, reason
189
+
190
  # =====================================================
191
  # MAIN LOGIC
192
  # =====================================================
193
  def run_journey(start, end, landing_page):
194
  df = fetch_journey(start, end, landing_page)
195
  if df.empty:
196
+ return None, pd.DataFrame(), "No journey data found."
197
 
198
  total_users = df["Views"].sum()
199
  form_yes = get_form_submissions(start, end, landing_page)
200
+ conv_rate = round((form_yes / total_users) * 100, 2) if total_users else 0.0
201
  journey_converted = "Yes" if form_yes > 0 else "No"
202
 
203
+ top_pages = df.sort_values("Views", ascending=False)["To"].unique().tolist()[:5]
204
+ intent, intent_reason = classify_intent_llm(
205
+ clean_path(landing_page),
206
+ [clean_path(p) for p in top_pages],
207
+ form_yes > 0
208
+ )
209
+
210
  exit_df = (
211
  df.groupby("From")["Views"]
212
  .sum()
 
219
  exit_df["Source Type"] = exit_df["Exit Source / Page"].apply(classify_source)
220
  exit_df["Exit Source / Page"] = exit_df["Exit Source / Page"].apply(clean_path)
221
 
 
222
  exit_df["Journey Converted?"] = journey_converted
223
+ exit_df["Journey Conversion Rate %"] = f"{conv_rate:.2f}%"
224
+ exit_df["Exit Severity Score"] = (
225
+ exit_df["Users Exited"] * (1 - conv_rate / 100)
226
+ ).round(1)
227
+
228
+ exit_df["User Intent"] = intent
229
+ exit_df["Intent Reason"] = intent_reason
 
 
 
 
 
 
230
 
231
+ exit_df = exit_df.sort_values("Exit Severity Score", ascending=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232
 
233
  fig = go.Figure(go.Sankey(
234
+ node=dict(
235
+ label=["Entry", clean_path(landing_page), "Exit", "Form Submitted"],
236
+ pad=20,
237
+ thickness=18
238
+ ),
239
+ link=dict(
240
+ source=[0, 1, 1],
241
+ target=[1, 2, 3],
242
+ value=[total_users, total_users - form_yes, form_yes]
243
+ )
244
  ))
245
 
246
  fig.update_layout(
247
+ title="Customer Journey Flow (Business View)",
248
  height=650
249
  )
250
 
 
255
 
256
  - **Journey Converted:** {journey_converted}
257
  - **Form Submissions:** {form_yes}
258
+ - **Conversion Rate:** {conv_rate:.2f}%
259
+ - **Primary User Intent:** **{intent}**
260
+ - **Why:** {intent_reason}
261
  """
262
 
263
  return fig, exit_df, summary
 
266
  # UI
267
  # =====================================================
268
  with gr.Blocks() as app:
269
+ gr.Markdown("## 🚀 Customer Journey Intelligence (GA4 + AI)")
270
 
271
  with gr.Row():
272
  sd = gr.Textbox(value=str(date.today() - timedelta(days=30)), label="Start Date")