kendrickfff commited on
Commit
d691203
·
verified ·
1 Parent(s): bfd59f2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +184 -61
app.py CHANGED
@@ -1,6 +1,7 @@
1
  """
2
  Agent Ken — PM + Social Impact Copilot
3
- Hugging Face Space (Gradio) Azure AI Foundry Agent Service
 
4
  """
5
 
6
  import os
@@ -9,14 +10,14 @@ from azure.ai.projects import AIProjectClient
9
  from azure.identity import ClientSecretCredential
10
  from azure.ai.agents.models import ListSortOrder
11
 
12
- # ── Azure config (from HF Space secrets) ──────────────────────────
13
  PROJECT_ENDPOINT = os.environ["PROJECT_ENDPOINT"]
14
  AGENT_ID = os.environ["AGENT_ID"]
15
  AZURE_TENANT_ID = os.environ["AZURE_TENANT_ID"]
16
  AZURE_CLIENT_ID = os.environ["AZURE_CLIENT_ID"]
17
  AZURE_CLIENT_SECRET = os.environ["AZURE_CLIENT_SECRET"]
18
 
19
- # ── Azure client (singleton) ──────────────────────────────────────
20
  credential = ClientSecretCredential(
21
  tenant_id=AZURE_TENANT_ID,
22
  client_id=AZURE_CLIENT_ID,
@@ -24,7 +25,6 @@ credential = ClientSecretCredential(
24
  )
25
  project = AIProjectClient(credential=credential, endpoint=PROJECT_ENDPOINT)
26
 
27
- # ── Lazy agent fetch ──────────────────────────────────────────────
28
  _agent = None
29
 
30
  def get_agent():
@@ -91,140 +91,264 @@ def new_conversation():
91
 
92
  # ── CSS ───────────────────────────────────────────────────────────
93
  CSS = """
94
- /* Force clean sans-serif font */
 
95
  * {
96
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif !important;
97
  }
98
 
99
  .gradio-container {
100
- max-width: 860px !important;
101
  margin: 0 auto !important;
102
  }
103
 
104
  footer { display: none !important; }
105
 
106
  /* Header */
107
- .header-section {
108
  text-align: center;
109
- padding: 24px 16px 12px 16px;
110
  }
111
- .header-section h1 {
112
- font-size: 1.6rem;
113
  font-weight: 700;
114
- margin-bottom: 2px;
115
- color: #2D3748;
116
  }
117
- .header-section .subtitle {
118
- font-size: 0.85rem;
119
  color: #718096;
120
  margin: 0;
121
  }
122
 
123
- /* Welcome card — shows in empty chat state */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  .welcome-card {
125
- background: linear-gradient(135deg, #EBF4FF 0%, #F0F7FF 50%, #F5F0FF 100%);
126
  border: 1px solid #D6E4F0;
127
  border-radius: 16px;
128
- padding: 28px 32px;
129
- margin: 8px 0 16px 0;
130
  text-align: center;
131
  }
132
  .welcome-card .wave {
133
- font-size: 2.2rem;
134
  display: block;
135
- margin-bottom: 8px;
136
  }
137
  .welcome-card h2 {
138
- font-size: 1.15rem;
139
  font-weight: 600;
140
  color: #2D3748;
141
- margin: 0 0 8px 0;
142
  }
143
  .welcome-card p {
144
- font-size: 0.88rem;
145
  color: #4A5568;
146
- margin: 0 0 16px 0;
147
- line-height: 1.5;
148
  }
149
  .welcome-tags {
150
  display: flex;
151
  flex-wrap: wrap;
152
- gap: 8px;
153
  justify-content: center;
154
  }
155
  .welcome-tags span {
156
  background: white;
157
  border: 1px solid #E2E8F0;
158
  border-radius: 20px;
159
- padding: 6px 14px;
160
- font-size: 0.78rem;
161
  color: #4A5568;
 
162
  }
163
 
164
- /* Input row */
165
- .input-row { padding-top: 8px; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
 
167
  /* Footer */
168
  .footer-info {
169
  text-align: center;
170
  padding: 10px 0;
171
- font-size: 0.72rem;
172
  color: #A0AEC0;
 
173
  }
174
  """
175
 
176
  # ── Examples ──────────────────────────────────────────────────────
177
  EXAMPLES = [
178
- ["Help me write a PRD for a mobile mental health check-in feature"],
179
- ["Score these 3 features using RICE: onboarding revamp, dark mode, referral program"],
180
- ["Design an A/B test for our new checkout flow"],
181
- ["What metrics should I track for a community-driven marketplace?"],
182
- ["Help me draft a stakeholder memo about delaying our launch by 2 weeks"],
 
 
 
183
  ]
184
 
185
- # ── Gradio UI ─────────────────────────────────────────────────────
186
- with gr.Blocks(title="Agent Ken — PM Copilot") as demo:
187
 
188
  # Header
189
  gr.HTML("""
190
- <div class="header-section">
191
  <h1>🤖 Agent Ken</h1>
192
- <p class="subtitle">PM + Social Impact Copilot · Built on Azure AI Foundry</p>
 
 
 
 
 
 
 
 
 
 
193
  </div>
194
  """)
195
 
196
- # Welcome card — visual intro instead of broken placeholder
197
  gr.HTML("""
198
  <div class="welcome-card">
199
  <span class="wave">👋</span>
200
- <h2>Hi, I'm Agent Ken — your Product Manager Copilot</h2>
201
- <p>I combine rigorous product thinking with a social worker's empathy.<br>
202
- Ask me anything about product management, strategy, or inclusive design.</p>
203
  <div class="welcome-tags">
204
- <span>🔍 Discovery & JTBD</span>
205
- <span>📊 RICE Prioritization</span>
206
- <span>📝 PRDs & User Stories</span>
207
- <span>🧪 A/B Test Design</span>
208
- <span>📈 Metrics & OKRs</span>
209
- <span>🤝 Stakeholder Comms</span>
210
  <span>♿ Inclusive Design</span>
211
  </div>
212
  </div>
213
  """)
214
 
215
- # Chat clean, no placeholder
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
216
  chatbot = gr.Chatbot(
217
  label="Agent Ken",
218
- height=450,
219
  )
220
 
221
- # Thread state (invisible)
222
  thread_state = gr.State(value=None)
223
 
224
- # Input row
225
- with gr.Row(elem_classes="input-row"):
226
  msg_input = gr.Textbox(
227
- placeholder="Ask Agent Ken anything...",
228
  label="",
229
  show_label=False,
230
  scale=5,
@@ -234,11 +358,9 @@ with gr.Blocks(title="Agent Ken — PM Copilot") as demo:
234
  )
235
  send_btn = gr.Button("Send 🚀", variant="primary", scale=1, min_width=100)
236
 
237
- # Actions
238
  with gr.Row():
239
  clear_btn = gr.Button("🗑️ New Conversation", variant="secondary", size="sm")
240
 
241
- # Examples
242
  with gr.Accordion("💡 Try an example", open=False):
243
  gr.Examples(
244
  examples=EXAMPLES,
@@ -249,7 +371,9 @@ with gr.Blocks(title="Agent Ken — PM Copilot") as demo:
249
  # Footer
250
  gr.HTML("""
251
  <div class="footer-info">
252
- Created by Kendrick Filbert · Powered by Azure AI Foundry
 
 
253
  </div>
254
  """)
255
 
@@ -271,6 +395,5 @@ with gr.Blocks(title="Agent Ken — PM Copilot") as demo:
271
  outputs=[chatbot, thread_state],
272
  )
273
 
274
- # ── Launch ────────────────────────────────────────────────────────
275
  if __name__ == "__main__":
276
  demo.launch(server_name="0.0.0.0", server_port=7860, css=CSS, theme=gr.themes.Soft())
 
1
  """
2
  Agent Ken — PM + Social Impact Copilot
3
+ Data-Informed Product Manager powered by Azure AI Foundry + Microsoft Fabric
4
+ Hugging Face Space (Gradio)
5
  """
6
 
7
  import os
 
10
  from azure.identity import ClientSecretCredential
11
  from azure.ai.agents.models import ListSortOrder
12
 
13
+ # ── Azure config ──────────────────────────────────────────────────
14
  PROJECT_ENDPOINT = os.environ["PROJECT_ENDPOINT"]
15
  AGENT_ID = os.environ["AGENT_ID"]
16
  AZURE_TENANT_ID = os.environ["AZURE_TENANT_ID"]
17
  AZURE_CLIENT_ID = os.environ["AZURE_CLIENT_ID"]
18
  AZURE_CLIENT_SECRET = os.environ["AZURE_CLIENT_SECRET"]
19
 
20
+ # ── Azure client ──────────────────────────────────────────────────
21
  credential = ClientSecretCredential(
22
  tenant_id=AZURE_TENANT_ID,
23
  client_id=AZURE_CLIENT_ID,
 
25
  )
26
  project = AIProjectClient(credential=credential, endpoint=PROJECT_ENDPOINT)
27
 
 
28
  _agent = None
29
 
30
  def get_agent():
 
91
 
92
  # ── CSS ───────────────────────────────────────────────────────────
93
  CSS = """
94
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
95
+
96
  * {
97
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
98
  }
99
 
100
  .gradio-container {
101
+ max-width: 880px !important;
102
  margin: 0 auto !important;
103
  }
104
 
105
  footer { display: none !important; }
106
 
107
  /* Header */
108
+ .header-main {
109
  text-align: center;
110
+ padding: 28px 16px 6px 16px;
111
  }
112
+ .header-main h1 {
113
+ font-size: 1.7rem;
114
  font-weight: 700;
115
+ color: #1A202C;
116
+ margin: 0 0 4px 0;
117
  }
118
+ .header-main .tagline {
119
+ font-size: 0.88rem;
120
  color: #718096;
121
  margin: 0;
122
  }
123
 
124
+ /* Architecture badge */
125
+ .arch-badge {
126
+ display: flex;
127
+ justify-content: center;
128
+ gap: 8px;
129
+ flex-wrap: wrap;
130
+ margin: 14px auto 6px auto;
131
+ max-width: 640px;
132
+ }
133
+ .arch-badge .chip {
134
+ display: inline-flex;
135
+ align-items: center;
136
+ gap: 5px;
137
+ padding: 5px 13px;
138
+ border-radius: 8px;
139
+ font-size: 0.72rem;
140
+ font-weight: 600;
141
+ letter-spacing: 0.02em;
142
+ }
143
+ .chip-foundry {
144
+ background: #EBF4FF;
145
+ color: #2B6CB0;
146
+ border: 1px solid #BEE3F8;
147
+ }
148
+ .chip-fabric {
149
+ background: #F0FFF4;
150
+ color: #276749;
151
+ border: 1px solid #C6F6D5;
152
+ }
153
+ .chip-ml {
154
+ background: #FAF5FF;
155
+ color: #6B46C1;
156
+ border: 1px solid #E9D8FD;
157
+ }
158
+ .chip-model {
159
+ background: #FFFAF0;
160
+ color: #C05621;
161
+ border: 1px solid #FEEBC8;
162
+ }
163
+
164
+ /* Welcome card */
165
  .welcome-card {
166
+ background: linear-gradient(135deg, #EBF4FF 0%, #F7FAFC 40%, #F0FFF4 100%);
167
  border: 1px solid #D6E4F0;
168
  border-radius: 16px;
169
+ padding: 24px 28px 20px 28px;
170
+ margin: 10px 0 14px 0;
171
  text-align: center;
172
  }
173
  .welcome-card .wave {
174
+ font-size: 2rem;
175
  display: block;
176
+ margin-bottom: 6px;
177
  }
178
  .welcome-card h2 {
179
+ font-size: 1.1rem;
180
  font-weight: 600;
181
  color: #2D3748;
182
+ margin: 0 0 6px 0;
183
  }
184
  .welcome-card p {
185
+ font-size: 0.84rem;
186
  color: #4A5568;
187
+ margin: 0 0 14px 0;
188
+ line-height: 1.55;
189
  }
190
  .welcome-tags {
191
  display: flex;
192
  flex-wrap: wrap;
193
+ gap: 6px;
194
  justify-content: center;
195
  }
196
  .welcome-tags span {
197
  background: white;
198
  border: 1px solid #E2E8F0;
199
  border-radius: 20px;
200
+ padding: 5px 13px;
201
+ font-size: 0.74rem;
202
  color: #4A5568;
203
+ font-weight: 500;
204
  }
205
 
206
+ /* Data section */
207
+ .data-section {
208
+ background: #F7FAFC;
209
+ border: 1px solid #E2E8F0;
210
+ border-radius: 12px;
211
+ padding: 14px 20px;
212
+ margin: 0 0 14px 0;
213
+ }
214
+ .data-section h3 {
215
+ font-size: 0.82rem;
216
+ font-weight: 600;
217
+ color: #2D3748;
218
+ margin: 0 0 8px 0;
219
+ }
220
+ .data-grid {
221
+ display: grid;
222
+ grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
223
+ gap: 8px;
224
+ }
225
+ .data-card {
226
+ background: white;
227
+ border: 1px solid #E2E8F0;
228
+ border-radius: 10px;
229
+ padding: 10px 12px;
230
+ text-align: center;
231
+ }
232
+ .data-card .number {
233
+ font-size: 1.15rem;
234
+ font-weight: 700;
235
+ color: #2B6CB0;
236
+ display: block;
237
+ }
238
+ .data-card .label {
239
+ font-size: 0.68rem;
240
+ color: #718096;
241
+ margin-top: 2px;
242
+ display: block;
243
+ }
244
 
245
  /* Footer */
246
  .footer-info {
247
  text-align: center;
248
  padding: 10px 0;
249
+ font-size: 0.7rem;
250
  color: #A0AEC0;
251
+ line-height: 1.6;
252
  }
253
  """
254
 
255
  # ── Examples ──────────────────────────────────────────────────────
256
  EXAMPLES = [
257
+ ["What's our D7 retention rate?"],
258
+ ["Which acquisition channel has the highest LTV?"],
259
+ ["How did our checkout experiment perform?"],
260
+ ["Which user segments are at highest churn risk?"],
261
+ ["Help me write a PRD for a referral program feature"],
262
+ ["Score these features using RICE: push notifications, dark mode, onboarding revamp"],
263
+ ["Design an A/B test for our new premium pricing"],
264
+ ["Were there any anomalies in our metrics recently?"],
265
  ]
266
 
267
+ # ── UI ────────────────────────────────────────────────────────────
268
+ with gr.Blocks(title="Agent Ken — Data-Informed PM Copilot") as demo:
269
 
270
  # Header
271
  gr.HTML("""
272
+ <div class="header-main">
273
  <h1>🤖 Agent Ken</h1>
274
+ <p class="tagline">Data-Informed PM + Social Impact Copilot</p>
275
+ </div>
276
+ """)
277
+
278
+ # Architecture chips
279
+ gr.HTML("""
280
+ <div class="arch-badge">
281
+ <span class="chip chip-foundry">☁️ Azure AI Foundry</span>
282
+ <span class="chip chip-fabric">🏭 Microsoft Fabric</span>
283
+ <span class="chip chip-ml">🧠 3 ML Models</span>
284
+ <span class="chip chip-model">⚡ GPT-5</span>
285
  </div>
286
  """)
287
 
288
+ # Welcome card
289
  gr.HTML("""
290
  <div class="welcome-card">
291
  <span class="wave">👋</span>
292
+ <h2>Hi, I'm Agent Ken — your Data-Informed Product Manager Copilot</h2>
293
+ <p>I combine rigorous product thinking with a social worker's empathy — powered by
294
+ real product analytics from Microsoft Fabric and ML models for churn, LTV, and anomaly detection.</p>
295
  <div class="welcome-tags">
296
+ <span>📊 Live Product Data</span>
297
+ <span>🔮 Churn Prediction</span>
298
+ <span>💰 LTV Analysis</span>
299
+ <span>⚠️ Anomaly Detection</span>
300
+ <span>🧪 A/B Test Results</span>
301
+ <span>📝 PRDs & Strategy</span>
302
  <span>♿ Inclusive Design</span>
303
  </div>
304
  </div>
305
  """)
306
 
307
+ # Data overview cards
308
+ gr.HTML("""
309
+ <div class="data-section">
310
+ <h3>📊 Connected Product Data (Fabric → Foundry)</h3>
311
+ <div class="data-grid">
312
+ <div class="data-card">
313
+ <span class="number">5,000</span>
314
+ <span class="label">Users Tracked</span>
315
+ </div>
316
+ <div class="data-card">
317
+ <span class="number">204K</span>
318
+ <span class="label">Events Analyzed</span>
319
+ </div>
320
+ <div class="data-card">
321
+ <span class="number">90 Days</span>
322
+ <span class="label">Data Window</span>
323
+ </div>
324
+ <div class="data-card">
325
+ <span class="number">25.6%</span>
326
+ <span class="label">D7 Retention</span>
327
+ </div>
328
+ <div class="data-card">
329
+ <span class="number">$19.87</span>
330
+ <span class="label">Avg LTV</span>
331
+ </div>
332
+ <div class="data-card">
333
+ <span class="number">5</span>
334
+ <span class="label">A/B Tests Run</span>
335
+ </div>
336
+ </div>
337
+ </div>
338
+ """)
339
+
340
+ # Chat
341
  chatbot = gr.Chatbot(
342
  label="Agent Ken",
343
+ height=440,
344
  )
345
 
 
346
  thread_state = gr.State(value=None)
347
 
348
+ # Input
349
+ with gr.Row():
350
  msg_input = gr.Textbox(
351
+ placeholder="Ask about metrics, churn, LTV, experiments, or any PM question...",
352
  label="",
353
  show_label=False,
354
  scale=5,
 
358
  )
359
  send_btn = gr.Button("Send 🚀", variant="primary", scale=1, min_width=100)
360
 
 
361
  with gr.Row():
362
  clear_btn = gr.Button("🗑️ New Conversation", variant="secondary", size="sm")
363
 
 
364
  with gr.Accordion("💡 Try an example", open=False):
365
  gr.Examples(
366
  examples=EXAMPLES,
 
371
  # Footer
372
  gr.HTML("""
373
  <div class="footer-info">
374
+ Built by <strong>Kendrick Filbert</strong><br>
375
+ Azure AI Foundry (GPT-5) · Microsoft Fabric (OneLake + MLflow) · 3 ML Models (Churn · LTV · Anomaly)<br>
376
+ Data: 5K users · 204K events · 90 days · 5 experiments
377
  </div>
378
  """)
379
 
 
395
  outputs=[chatbot, thread_state],
396
  )
397
 
 
398
  if __name__ == "__main__":
399
  demo.launch(server_name="0.0.0.0", server_port=7860, css=CSS, theme=gr.themes.Soft())