cryogenic22 commited on
Commit
de3bd34
·
verified ·
1 Parent(s): c87abe1

Create analytics_viewer.py

Browse files
Files changed (1) hide show
  1. analytics_viewer.py +679 -0
analytics_viewer.py ADDED
@@ -0,0 +1,679 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Analysis Viewer Component for Pharmaceutical Analytics Application
3
+
4
+ This module provides a dedicated view for watching the agents work in real-time,
5
+ displaying generated code, SQL queries, and visualization steps as they happen.
6
+ """
7
+
8
+ import streamlit as st
9
+ import pandas as pd
10
+ import time
11
+ import plotly.graph_objects as go
12
+ from datetime import datetime
13
+ import json
14
+
15
+ def render_progress_bar(current_step, steps=None):
16
+ """Render a progress bar for the current workflow state"""
17
+ if steps is None:
18
+ steps = ["planning", "data_collection", "analysis", "validation", "insights", "complete"]
19
+
20
+ step_idx = steps.index(current_step) if current_step in steps else 0
21
+ progress = (step_idx + 1) / len(steps)
22
+
23
+ st.progress(progress)
24
+
25
+ # Step indicators with more detailed descriptions
26
+ cols = st.columns(5)
27
+
28
+ step_descriptions = {
29
+ "planning": "Decomposes problem & plans analysis approach",
30
+ "data_collection": "Translates to SQL & retrieves data",
31
+ "analysis": "Performs statistical analysis & modeling",
32
+ "validation": "Validates results & checks quality",
33
+ "insights": "Creates visualizations & recommendations"
34
+ }
35
+
36
+ with cols[0]:
37
+ check = "✅" if step_idx >= 0 else "🔄"
38
+ check = "🔄" if step_idx == 0 else check
39
+ st.markdown(f"{check} **Planning**")
40
+ if current_step == "planning":
41
+ st.caption(step_descriptions["planning"])
42
+
43
+ with cols[1]:
44
+ check = "✅" if step_idx >= 1 else "⏳"
45
+ check = "🔄" if step_idx == 1 else check
46
+ st.markdown(f"{check} **Data Collection**")
47
+ if current_step == "data_collection":
48
+ st.caption(step_descriptions["data_collection"])
49
+
50
+ with cols[2]:
51
+ check = "✅" if step_idx >= 2 else "⏳"
52
+ check = "🔄" if step_idx == 2 else check
53
+ st.markdown(f"{check} **Analysis**")
54
+ if current_step == "analysis":
55
+ st.caption(step_descriptions["analysis"])
56
+
57
+ with cols[3]:
58
+ check = "✅" if step_idx >= 3 else "⏳"
59
+ check = "🔄" if step_idx == 3 else check
60
+ st.markdown(f"{check} **Validation**")
61
+ if current_step == "validation":
62
+ st.caption(step_descriptions["validation"])
63
+
64
+ with cols[4]:
65
+ check = "✅" if step_idx >= 4 else "⏳"
66
+ check = "🔄" if step_idx == 4 else check
67
+ st.markdown(f"{check} **Insights**")
68
+ if current_step == "insights":
69
+ st.caption(step_descriptions["insights"])
70
+
71
+
72
+ def render_planning_agent_view(state):
73
+ """Render the Planning Agent activity view"""
74
+ st.markdown("### 🧠 Planning Agent")
75
+ st.markdown("The Planning Agent is decomposing the problem and creating an analysis plan.")
76
+
77
+ # Show input alert
78
+ alert_container = st.container(border=True)
79
+ with alert_container:
80
+ st.markdown("**Input Alert:**")
81
+ st.info(state.get("alert", ""))
82
+
83
+ # Thinking animation or finished plan
84
+ if state.get("plan") is None:
85
+ # Show thinking animation
86
+ thinking_messages = [
87
+ "Identifying required data sources...",
88
+ "Determining appropriate analytical approaches...",
89
+ "Creating task dependency graph...",
90
+ "Designing validation strategy..."
91
+ ]
92
+
93
+ thinking_placeholder = st.empty()
94
+ for i in range(len(thinking_messages)):
95
+ thinking_placeholder.info(thinking_messages[i % len(thinking_messages)])
96
+ time.sleep(0.5)
97
+ else:
98
+ # Show the created plan
99
+ plan = state.get("plan")
100
+
101
+ # Show problem statement
102
+ st.markdown("#### 🎯 Problem Statement")
103
+ st.markdown(plan.problem_statement)
104
+
105
+ # Show required data sources in a table
106
+ st.markdown("#### 📊 Required Data Sources")
107
+ data_sources_df = pd.DataFrame(plan.required_data_sources)
108
+ st.table(data_sources_df)
109
+
110
+ # Show analysis approaches
111
+ st.markdown("#### 🔍 Analysis Approaches")
112
+ approaches_df = pd.DataFrame(plan.analysis_approaches)
113
+ st.table(approaches_df)
114
+
115
+ # Show expected insights
116
+ st.markdown("#### 💡 Expected Insights")
117
+ for i, insight in enumerate(plan.expected_insights):
118
+ st.markdown(f"{i+1}. {insight}")
119
+
120
+
121
+ def render_data_agent_view(state):
122
+ """Render the Data Agent activity view"""
123
+ st.markdown("### 🗃️ Data Agent")
124
+ st.markdown("The Data Agent is translating requirements into SQL queries and collecting data.")
125
+
126
+ # Show data requests
127
+ st.markdown("#### 📋 Data Requests")
128
+ data_requests = state.get("data_requests", [])
129
+
130
+ if not data_requests:
131
+ st.info("Preparing data requests...")
132
+ else:
133
+ for i, request in enumerate(data_requests):
134
+ with st.expander(f"Request {i+1}: {request.description}", expanded=True):
135
+ st.markdown(f"**Tables:** {', '.join(request.tables)}")
136
+ st.markdown(f"**Purpose:** {request.purpose}")
137
+
138
+ # Show SQL generation and results
139
+ data_sources = state.get("data_sources", {})
140
+ if data_sources:
141
+ st.markdown("#### 📊 Generated Data Sources")
142
+
143
+ for source_id, source in data_sources.items():
144
+ with st.expander(f"Data Source: {source.name}", expanded=True):
145
+ # Show SQL query (mocked here - in real implementation you'd extract from the pipeline)
146
+ if st.session_state.show_sql:
147
+ mock_sql = f"""
148
+ -- Query for {source.name}
149
+ SELECT
150
+ r.region_name,
151
+ p.product_name,
152
+ strftime('%Y-%m', s.sale_date) as month,
153
+ SUM(s.units_sold) as total_units,
154
+ SUM(s.revenue) as total_revenue,
155
+ SUM(s.margin) as total_margin
156
+ FROM
157
+ sales s
158
+ JOIN
159
+ regions r ON s.region_id = r.region_id
160
+ JOIN
161
+ products p ON s.product_id = p.product_id
162
+ WHERE
163
+ p.product_id = 'DRX'
164
+ AND s.sale_date >= date('now', '-90 days')
165
+ GROUP BY
166
+ r.region_name, p.product_name, month
167
+ ORDER BY
168
+ r.region_name, month;
169
+ """
170
+ st.code(mock_sql, language="sql")
171
+
172
+ # Show data preview
173
+ st.markdown("**Data Preview:**")
174
+ st.dataframe(source.content.head(5), use_container_width=True)
175
+ st.caption(f"Shape: {source.content.shape[0]} rows, {source.content.shape[1]} columns")
176
+
177
+
178
+ def render_analytics_agent_view(state):
179
+ """Render the Analytics Agent activity view"""
180
+ st.markdown("### 📊 Analytics Agent")
181
+ st.markdown("The Analytics Agent is performing statistical analysis and modeling.")
182
+
183
+ # Show analytics requests
184
+ analysis_requests = state.get("analysis_requests", [])
185
+ if not analysis_requests:
186
+ st.info("Preparing analysis requests...")
187
+ else:
188
+ st.markdown("#### 📋 Analysis Requests")
189
+ for i, request in enumerate(analysis_requests):
190
+ st.markdown(f"**Request {i+1}:** {request.description} ({request.analysis_type})")
191
+
192
+ # Show analysis results
193
+ analysis_results = state.get("analysis_results", {})
194
+ if analysis_results:
195
+ st.markdown("#### 📈 Analysis Results")
196
+
197
+ for analysis_id, result in analysis_results.items():
198
+ with st.expander(f"Analysis: {result.name}", expanded=True):
199
+ # Show generated Python code
200
+ if st.session_state.show_code and result.code:
201
+ st.markdown("**Generated Python Code:**")
202
+ st.code(result.code, language="python")
203
+
204
+ # Show insights
205
+ if result.insights:
206
+ st.markdown("**Key Findings:**")
207
+ for insight in result.insights:
208
+ st.markdown(f"- **{insight.get('finding', '')}**: {insight.get('details', '')}")
209
+
210
+ # Show metrics
211
+ if result.metrics:
212
+ st.markdown("**Metrics:**")
213
+ metrics_df = pd.DataFrame([result.metrics])
214
+ st.table(metrics_df.T)
215
+
216
+ # Show attribution
217
+ if result.attribution:
218
+ st.markdown("**Attribution Analysis:**")
219
+ fig = go.Figure([
220
+ go.Bar(
221
+ x=list(result.attribution.values()),
222
+ y=list(result.attribution.keys()),
223
+ orientation='h'
224
+ )
225
+ ])
226
+ fig.update_layout(
227
+ title="Factor Attribution",
228
+ xaxis_title="Attribution (%)",
229
+ height=300
230
+ )
231
+ st.plotly_chart(fig, use_container_width=True)
232
+
233
+
234
+ def render_qa_agent_view(state):
235
+ """Render the QA Agent activity view"""
236
+ st.markdown("### 🔍 QA Agent")
237
+ st.markdown("The QA Agent is validating the analysis results for accuracy and completeness.")
238
+
239
+ # Show validation requests
240
+ validation_requests = state.get("validation_requests", [])
241
+ if not validation_requests:
242
+ st.info("Preparing validation requests...")
243
+
244
+ # Show validation results
245
+ validation_results = state.get("validation_results", {})
246
+ if validation_results:
247
+ st.markdown("#### 🧪 Validation Results")
248
+
249
+ for validation_id, validation in validation_results.items():
250
+ with st.expander(f"Validation: {validation_id}", expanded=True):
251
+ # Show validation scores
252
+ scores_col1, scores_col2, scores_col3 = st.columns(3)
253
+
254
+ with scores_col1:
255
+ st.metric("Data Quality", f"{validation.data_quality_score:.0%}")
256
+
257
+ with scores_col2:
258
+ st.metric("Analysis Quality", f"{validation.analysis_quality_score:.0%}")
259
+
260
+ with scores_col3:
261
+ st.metric("Insight Quality", f"{validation.insight_quality_score:.0%}")
262
+
263
+ # Show validation checks as a table
264
+ st.markdown("**Validation Checks:**")
265
+ checks_df = pd.DataFrame(validation.validation_checks)
266
+ checks_df = checks_df[["check", "result", "details", "score"]]
267
+ st.table(checks_df)
268
+
269
+ # Show recommendations
270
+ if validation.recommendations:
271
+ st.markdown("**Recommendations:**")
272
+ for rec in validation.recommendations:
273
+ st.markdown(f"- {rec}")
274
+
275
+ # Show critical issues if any
276
+ if validation.critical_issues:
277
+ st.error("**Critical Issues:**")
278
+ for issue in validation.critical_issues:
279
+ st.markdown(f"- {issue}")
280
+
281
+
282
+ def render_insights_agent_view(state):
283
+ """Render the Insights Agent activity view"""
284
+ st.markdown("### 💡 Insights Agent")
285
+ st.markdown("The Insights Agent is generating visualizations and actionable recommendations.")
286
+
287
+ # Show insight requests
288
+ insight_requests = state.get("insight_requests", [])
289
+ if not insight_requests:
290
+ st.info("Preparing insight requests...")
291
+
292
+ # Show insight cards
293
+ insight_cards = state.get("insight_cards", {})
294
+ visualizations = state.get("visualizations", [])
295
+
296
+ if insight_cards:
297
+ st.markdown("#### 📊 Generated Insights")
298
+
299
+ for card_id, card in insight_cards.items():
300
+ with st.expander(f"{card.title}", expanded=True):
301
+ st.markdown(card.description)
302
+
303
+ # Display visualizations if available
304
+ if card.charts and visualizations:
305
+ # Create sample visualizations based on chart names
306
+ st.markdown("**Visualizations:**")
307
+ cols = st.columns(min(len(card.charts), 2))
308
+
309
+ for i, chart_name in enumerate(card.charts[:2]):
310
+ with cols[i % 2]:
311
+ if "trend" in chart_name.lower():
312
+ # Create sample time series for demonstration
313
+ months = pd.date_range(start='2023-01-01', periods=12, freq='M')
314
+ sales = [1200, 1250, 1300, 1400, 1500, 1600, 1550, 1500, 1450, 1300, 1200, 1150]
315
+ targets = [1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550, 1600, 1650, 1700, 1750]
316
+
317
+ fig = go.Figure()
318
+ fig.add_trace(go.Scatter(
319
+ x=months, y=sales, mode='lines+markers', name='Actual Sales',
320
+ line=dict(color='blue', width=2)
321
+ ))
322
+ fig.add_trace(go.Scatter(
323
+ x=months, y=targets, mode='lines+markers', name='Target',
324
+ line=dict(color='green', width=2, dash='dash')
325
+ ))
326
+
327
+ # Add annotation
328
+ fig.add_vline(
329
+ x=months[9], line_dash="dash", line_color="red",
330
+ annotation_text="Competitor Launch"
331
+ )
332
+
333
+ fig.update_layout(
334
+ title="Sales Trend Analysis",
335
+ height=300
336
+ )
337
+
338
+ st.plotly_chart(fig, use_container_width=True)
339
+
340
+ elif "competitor" in chart_name.lower():
341
+ # Create sample competitor visualization
342
+ st.markdown(f"**{chart_name}**")
343
+ st.text("Visualization being generated...")
344
+
345
+ else:
346
+ st.markdown(f"**{chart_name}**")
347
+ st.text("Visualization being generated...")
348
+
349
+ # Display key findings
350
+ if card.key_findings:
351
+ st.markdown("**Key Findings:**")
352
+ for finding in card.key_findings:
353
+ st.markdown(f"- **{finding.get('finding', '')}**: {finding.get('details', '')}")
354
+ if 'impact' in finding:
355
+ st.markdown(f" *Impact: {finding.get('impact', '')}*")
356
+
357
+ # Display action items
358
+ if card.action_items:
359
+ st.markdown("**Recommended Actions:**")
360
+ action_df = []
361
+ for action in card.action_items:
362
+ action_df.append({
363
+ "Action": action.get("action", ""),
364
+ "Owner": action.get("owner", ""),
365
+ "Timeline": action.get("timeline", ""),
366
+ "Priority": action.get("priority", "Medium")
367
+ })
368
+ st.table(pd.DataFrame(action_df))
369
+
370
+
371
+ def render_complete_analysis_view(state):
372
+ """Render a complete view of the analysis results"""
373
+ st.markdown("### ✅ Analysis Complete")
374
+
375
+ # Display the alert
376
+ st.markdown("#### 📱 Alert Analyzed")
377
+ st.info(state["alert"])
378
+
379
+ # Display the problem statement
380
+ if state.get("plan"):
381
+ st.markdown("#### 🎯 Problem Analysis")
382
+ st.markdown(state["plan"].problem_statement)
383
+
384
+ # Display insight cards
385
+ st.markdown("---")
386
+ st.markdown("### 💡 Key Insights")
387
+
388
+ insight_cards = state.get("insight_cards", {})
389
+ visualizations = state.get("visualizations", [])
390
+
391
+ if not insight_cards:
392
+ st.warning("No insights were generated. Please check the logs for errors.")
393
+ else:
394
+ for card_id, card in insight_cards.items():
395
+ # Create a card-like container
396
+ with st.container():
397
+ st.subheader(card.title)
398
+ st.markdown(card.description)
399
+
400
+ # Display visualizations if available
401
+ if card.charts and len(visualizations) > 0:
402
+ # Create sample visualizations
403
+ cols = st.columns(min(len(card.charts), 2))
404
+
405
+ for i, chart_name in enumerate(card.charts[:2]):
406
+ with cols[i % 2]:
407
+ # Create a sample chart based on chart name
408
+ if "trend" in chart_name.lower():
409
+ # Create sample time series
410
+ months = pd.date_range(start='2023-01-01', periods=12, freq='M')
411
+ sales = [1200, 1250, 1300, 1400, 1500, 1600, 1550, 1500, 1450, 1300, 1200, 1150]
412
+ targets = [1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550, 1600, 1650, 1700, 1750]
413
+
414
+ fig = go.Figure()
415
+ fig.add_trace(go.Scatter(
416
+ x=months, y=sales, mode='lines+markers', name='Actual Sales',
417
+ line=dict(color='blue', width=2)
418
+ ))
419
+ fig.add_trace(go.Scatter(
420
+ x=months, y=targets, mode='lines+markers', name='Target',
421
+ line=dict(color='green', width=2, dash='dash')
422
+ ))
423
+
424
+ # Add competitor launch annotation
425
+ fig.add_vline(
426
+ x=months[9], line_dash="dash", line_color="red",
427
+ annotation_text="Competitor Launch"
428
+ )
429
+
430
+ fig.update_layout(
431
+ title="DrugX Sales Trend",
432
+ xaxis_title="Month",
433
+ yaxis_title="Sales ($K)",
434
+ height=300
435
+ )
436
+
437
+ st.plotly_chart(fig, use_container_width=True)
438
+
439
+ elif "competitor" in chart_name.lower():
440
+ # Create sample competitor comparison
441
+ fig = go.Figure()
442
+
443
+ # Market share data
444
+ months = pd.date_range(start='2023-01-01', periods=12, freq='M')
445
+ drugx_share = [65, 64, 66, 67, 68, 67, 66, 65, 64, 58, 54, 50]
446
+ competitor_share = [0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 10, 15]
447
+ other_share = [35, 36, 34, 33, 32, 33, 34, 35, 36, 37, 36, 35]
448
+
449
+ fig.add_trace(go.Bar(
450
+ x=months, y=drugx_share, name='DrugX',
451
+ marker_color='blue'
452
+ ))
453
+ fig.add_trace(go.Bar(
454
+ x=months, y=competitor_share, name='CompDrug2',
455
+ marker_color='red'
456
+ ))
457
+ fig.add_trace(go.Bar(
458
+ x=months, y=other_share, name='Others',
459
+ marker_color='gray'
460
+ ))
461
+
462
+ fig.update_layout(
463
+ title="Market Share Comparison",
464
+ xaxis_title="Month",
465
+ yaxis_title="Market Share (%)",
466
+ barmode='stack',
467
+ height=300
468
+ )
469
+
470
+ st.plotly_chart(fig, use_container_width=True)
471
+
472
+ elif "supply" in chart_name.lower():
473
+ # Create sample supply chain visualization
474
+ fig = go.Figure()
475
+
476
+ # Inventory data
477
+ months = pd.date_range(start='2023-01-01', periods=12, freq='M')
478
+ inventory = [40, 38, 42, 45, 43, 41, 39, 37, 35, 25, 20, 18]
479
+ stockouts = [0, 0, 0, 0, 0, 0, 0, 0, 5, 15, 22, 25]
480
+
481
+ fig.add_trace(go.Scatter(
482
+ x=months, y=inventory, mode='lines+markers', name='Inventory Days',
483
+ line=dict(color='blue', width=2)
484
+ ))
485
+
486
+ fig.add_trace(go.Bar(
487
+ x=months, y=stockouts, name='Stockout %',
488
+ marker_color='red'
489
+ ))
490
+
491
+ fig.update_layout(
492
+ title="Supply Chain Metrics",
493
+ xaxis_title="Month",
494
+ yaxis_title="Inventory Days / Stockout %",
495
+ height=300
496
+ )
497
+
498
+ st.plotly_chart(fig, use_container_width=True)
499
+
500
+ else:
501
+ # Create a generic chart placeholder
502
+ st.image("https://img.icons8.com/fluency/240/000000/graph.png", width=100)
503
+ st.markdown(f"*{chart_name}*")
504
+
505
+ # Display key findings
506
+ if card.key_findings:
507
+ st.markdown("#### Key Findings")
508
+ for i, finding in enumerate(card.key_findings):
509
+ expander = st.expander(f"{finding.get('finding', 'Finding')}")
510
+ with expander:
511
+ st.markdown(f"**Details:** {finding.get('details', '')}")
512
+ if 'evidence' in finding:
513
+ st.markdown(f"**Evidence:** {finding.get('evidence', '')}")
514
+ if 'impact' in finding:
515
+ st.markdown(f"**Impact:** {finding.get('impact', '')}")
516
+
517
+ # Display metrics
518
+ if card.metrics:
519
+ st.markdown("#### Key Metrics")
520
+ metric_cols = st.columns(min(len(card.metrics), 4))
521
+ for i, (metric_name, metric_value) in enumerate(card.metrics.items()):
522
+ with metric_cols[i % len(metric_cols)]:
523
+ st.metric(
524
+ label=metric_name.replace('_', ' ').title(),
525
+ value=metric_value
526
+ )
527
+
528
+ # Display action items
529
+ if card.action_items:
530
+ st.markdown("#### Recommended Actions")
531
+ for i, action in enumerate(card.action_items):
532
+ priority = action.get('priority', 'Medium')
533
+ priority_color = {
534
+ 'High': 'red',
535
+ 'Medium': 'orange',
536
+ 'Low': 'blue'
537
+ }.get(priority, 'gray')
538
+
539
+ st.markdown(f"**{i+1}. {action.get('action', 'Action')}** "
540
+ f"<span style='color:{priority_color};'>[{priority}]</span>",
541
+ unsafe_allow_html=True)
542
+
543
+ action_cols = st.columns(3)
544
+ with action_cols[0]:
545
+ st.markdown(f"**Owner:** {action.get('owner', 'TBD')}")
546
+ with action_cols[1]:
547
+ st.markdown(f"**Timeline:** {action.get('timeline', 'TBD')}")
548
+ with action_cols[2]:
549
+ st.markdown(f"**Expected Impact:** {action.get('expected_impact', 'TBD')}")
550
+
551
+ st.markdown("---")
552
+
553
+
554
+ def render_debug_info(state):
555
+ """Render debug information about the workflow state"""
556
+ with st.expander("🔧 Debug Information", expanded=False):
557
+ # Show workflow status
558
+ st.markdown(f"**Current Status:** {state.get('status', 'Unknown')}")
559
+
560
+ # Show state summary
561
+ state_summary = {
562
+ "alert": state.get("alert", "None"),
563
+ "data_requests": len(state.get("data_requests", [])),
564
+ "data_sources": len(state.get("data_sources", {})),
565
+ "analysis_requests": len(state.get("analysis_requests", [])),
566
+ "analysis_results": len(state.get("analysis_results", {})),
567
+ "validation_requests": len(state.get("validation_requests", [])),
568
+ "validation_results": len(state.get("validation_results", {})),
569
+ "insight_requests": len(state.get("insight_requests", [])),
570
+ "insight_cards": len(state.get("insight_cards", {})),
571
+ "visualizations": len(state.get("visualizations", [])),
572
+ }
573
+
574
+ st.json(state_summary)
575
+
576
+ # Show logs
577
+ if "logs" in state and state["logs"]:
578
+ st.markdown("**Workflow Logs:**")
579
+ for log in state["logs"]:
580
+ timestamp = log.get("timestamp", "")
581
+ message = log.get("message", "")
582
+ log_type = log.get("type", "info")
583
+
584
+ if log_type == "error":
585
+ st.error(f"{timestamp}: {message}")
586
+ else:
587
+ st.text(f"{timestamp}: {message}")
588
+
589
+
590
+ def render_analysis_viewer(state=None):
591
+ """Main function to render the analysis viewer"""
592
+ # If no state is provided, use the session state
593
+ if state is None:
594
+ state = st.session_state.workflow_state
595
+
596
+ # If no workflow state, show a message
597
+ if state is None:
598
+ st.info("No analysis is currently running. Start an analysis from the main tab.")
599
+ return
600
+
601
+ # Display header with current status
602
+ current_step = state.get("status", "planning")
603
+ st.markdown(f"## 🔬 Analysis Progress: {current_step.upper()}")
604
+
605
+ # Show progress bar
606
+ render_progress_bar(current_step)
607
+
608
+ # Show page tabs for different views
609
+ tab_names = ["Live View", "Planning", "Data", "Analysis", "Validation", "Insights", "Debug"]
610
+ tabs = st.tabs(tab_names)
611
+
612
+ # Live View Tab - shows current active agent
613
+ with tabs[0]:
614
+ if current_step == "planning":
615
+ render_planning_agent_view(state)
616
+ elif current_step == "data_collection":
617
+ render_data_agent_view(state)
618
+ elif current_step == "analysis":
619
+ render_analytics_agent_view(state)
620
+ elif current_step == "validation":
621
+ render_qa_agent_view(state)
622
+ elif current_step == "insights":
623
+ render_insights_agent_view(state)
624
+ elif current_step == "complete":
625
+ render_complete_analysis_view(state)
626
+ elif current_step == "error":
627
+ st.error(f"Analysis failed: {state.get('error', 'Unknown error')}")
628
+ if "error_details" in st.session_state:
629
+ for i, error in enumerate(st.session_state.error_details):
630
+ with st.expander(f"Error Detail {i+1}", expanded=True):
631
+ st.code(error)
632
+
633
+ # Planning Tab
634
+ with tabs[1]:
635
+ render_planning_agent_view(state)
636
+
637
+ # Data Tab
638
+ with tabs[2]:
639
+ render_data_agent_view(state)
640
+
641
+ # Analysis Tab
642
+ with tabs[3]:
643
+ render_analytics_agent_view(state)
644
+
645
+ # Validation Tab
646
+ with tabs[4]:
647
+ render_qa_agent_view(state)
648
+
649
+ # Insights Tab
650
+ with tabs[5]:
651
+ render_insights_agent_view(state)
652
+
653
+ # Debug Tab
654
+ with tabs[6]:
655
+ render_debug_info(state)
656
+
657
+ # Auto refresh if analysis is not complete
658
+ if current_step not in ["complete", "error"]:
659
+ time.sleep(1)
660
+ st.rerun()
661
+
662
+
663
+ if __name__ == "__main__":
664
+ # For testing standalone
665
+ st.title("Analysis Viewer (Test Mode)")
666
+ st.markdown("This is a standalone test of the Analysis Viewer component.")
667
+
668
+ # Create mock state
669
+ mock_state = {
670
+ "alert": "Sales of DrugX down 15% in Northeast region over past 30 days compared to forecast.",
671
+ "status": "planning",
672
+ "data_requests": [],
673
+ "data_sources": {},
674
+ "logs": [
675
+ {"timestamp": datetime.now().isoformat(), "message": "Workflow initialized", "type": "info"}
676
+ ]
677
+ }
678
+
679
+ render_analysis_viewer(mock_state)