Skip to content

Commit 4cc8869

Browse files
Address PR feedback: revert unrelated changes in dashboard/app.py and scripts/quality_report.py
1 parent c4f5836 commit 4cc8869

2 files changed

Lines changed: 195 additions & 544 deletions

File tree

dashboard/app.py

Lines changed: 90 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import re
2-
from google.cloud import bigquery
1+
import streamlit as st
32
import pandas as pd
3+
from google.cloud import bigquery
44
import plotly.express as px
5-
import streamlit as st
6-
5+
import re
76

87
# --- 1. Page Configuration ---
98
st.set_page_config(page_title="Agent Analytics V2", layout="wide")
@@ -35,224 +34,172 @@
3534

3635
# --- 3. Sidebar Configuration ---
3736
with st.sidebar:
38-
st.header("Data Source")
39-
project_id = st.text_input("GCP Project ID", "REPLACE WITH YOUR PROJECT ID")
40-
dataset_id = st.text_input("Dataset ID", "REPLACE WITH YOUR DATASET ID")
41-
table_id = st.text_input("Table ID", "REPLACE WITH YOUR TABLE ID")
42-
43-
# Identifier Validation
44-
for val in [project_id, dataset_id, table_id]:
45-
if not re.match(r"^[\w.-]+$", val):
46-
st.error(f"Invalid identifier: {val}")
47-
st.stop()
37+
st.header("Data Source")
38+
project_id = st.text_input("GCP Project ID", "REPLACE WITH YOUR PROJECT ID")
39+
dataset_id = st.text_input("Dataset ID", "REPLACE WITH YOUR DATASET ID")
40+
table_id = st.text_input("Table ID", "REPLACE WITH YOUR TABLE ID")
4841

49-
table_ref = f"`{project_id}.{dataset_id}.{table_id}`"
42+
# Identifier Validation
43+
for val in [project_id, dataset_id, table_id]:
44+
if not re.match(r'^[\w.-]+$', val):
45+
st.error(f"Invalid identifier: {val}")
46+
st.stop()
5047

51-
st.divider()
52-
st.header("Global Filters")
53-
time_hours = st.slider("Time Range (Hours)", 1, 720, 72)
54-
agent_name = st.text_input("Filter by Agent Name", "")
48+
table_ref = f"`{project_id}.{dataset_id}.{table_id}`"
5549

50+
st.divider()
51+
st.header("Global Filters")
52+
time_hours = st.slider("Time Range (Hours)", 1, 720, 72)
53+
agent_name = st.text_input("Filter by Agent Name", "")
5654

5755
# --- 4. Data Connector ---
5856
@st.cache_resource
5957
def get_bq_client(p_id):
60-
return bigquery.Client(project=p_id)
61-
58+
return bigquery.Client(project=p_id)
6259

6360
client = get_bq_client(project_id)
6461

65-
6662
def safe_query(sql, params=None):
67-
try:
68-
job_config = (
69-
bigquery.QueryJobConfig(query_parameters=params) if params else None
70-
)
71-
formatted_sql = sql.replace("{table_ref}", table_ref)
72-
return client.query(formatted_sql, job_config=job_config).to_dataframe()
73-
except Exception as e:
74-
st.error(f"Query Failed: {e}")
75-
return pd.DataFrame()
76-
63+
try:
64+
job_config = bigquery.QueryJobConfig(query_parameters=params) if params else None
65+
formatted_sql = sql.replace("{table_ref}", table_ref)
66+
return client.query(formatted_sql, job_config=job_config).to_dataframe()
67+
except Exception as e:
68+
st.error(f"Query Failed: {e}")
69+
return pd.DataFrame()
7770

7871
# --- 5. Global Params (Resolved 400 Parameter Error) ---
7972

8073
global_params = [
8174
bigquery.ScalarQueryParameter("time_hours", "INT64", time_hours),
82-
bigquery.ScalarQueryParameter(
83-
"agent_name", "STRING", agent_name if agent_name else None
84-
),
75+
bigquery.ScalarQueryParameter("agent_name", "STRING", agent_name if agent_name else None)
8576
]
8677

8778
# WHERE clause for non-CTE queries (Executive Summary & Multimodal)
88-
where_clause = (
89-
"timestamp >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL @time_hours HOUR)"
90-
)
79+
where_clause = "timestamp >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL @time_hours HOUR)"
9180
if agent_name:
92-
where_clause += " AND agent = @agent_name"
81+
where_clause += " AND agent = @agent_name"
9382

9483
# --- 6. Executive Summary (Resolved PR Consistency Issue) ---
9584
st.header("📊 Executive Summary")
9685

97-
kpi_data = safe_query(
98-
f"""
86+
kpi_data = safe_query(f"""
9987
WITH enriched AS ({ENRICHED_EVENTS_CTE})
10088
SELECT
10189
COUNT(DISTINCT session_id) as sessions,
10290
COUNT(DISTINCT trace_id) as traces,
10391
COUNTIF(event_type = 'LLM_REQUEST') as llm_calls,
10492
SAFE_DIVIDE(COUNTIF(is_canonical_error = TRUE), COUNT(*)) as error_rate
10593
FROM enriched
106-
""",
107-
params=global_params,
108-
)
94+
""", params=global_params)
10995

11096
if not kpi_data.empty:
111-
c1, c2, c3, c4 = st.columns(4)
112-
c1.metric("Sessions", kpi_data["sessions"][0])
113-
c2.metric("Traces", kpi_data["traces"][0])
114-
c3.metric("LLM Calls", kpi_data["llm_calls"][0])
115-
# The rate now includes TOOL_ERROR and LLM_ERROR automatically
116-
c4.metric("Error Rate", f"{kpi_data['error_rate'][0]*100:.2f}%")
117-
97+
c1, c2, c3, c4 = st.columns(4)
98+
c1.metric("Sessions", kpi_data['sessions'][0])
99+
c2.metric("Traces", kpi_data['traces'][0])
100+
c3.metric("LLM Calls", kpi_data['llm_calls'][0])
101+
# The rate now includes TOOL_ERROR and LLM_ERROR automatically
102+
c4.metric("Error Rate", f"{kpi_data['error_rate'][0]*100:.2f}%")
103+
118104

119105
# --- 7. Detailed Tabs ---
120-
tabs = st.tabs([
121-
"📈 Usage",
122-
"⚡ Performance",
123-
"🛡️ Reliability",
124-
"🖼️ Multimodal",
125-
"🤝 HITL",
126-
"🔍 Trace Explorer",
127-
])
106+
tabs = st.tabs(["📈 Usage", "⚡ Performance", "🛡️ Reliability", "🖼️ Multimodal", "🤝 HITL", "🔍 Trace Explorer"])
128107

129108
# TAB 0: USAGE & VOLUME
130109
with tabs[0]:
131-
st.subheader("Token Consumption")
132-
token_trend = safe_query(
133-
f"""
110+
st.subheader("Token Consumption")
111+
token_trend = safe_query(f"""
134112
SELECT TIMESTAMP_TRUNC(timestamp, HOUR) as hour,
135113
SUM(CAST(JSON_VALUE(content, '$.usage.prompt') AS INT64)) as prompt,
136114
SUM(CAST(JSON_VALUE(content, '$.usage.completion') AS INT64)) as completion
137115
FROM {{table_ref}} WHERE event_type = 'LLM_RESPONSE' AND {where_clause}
138116
GROUP BY 1 ORDER BY 1
139-
""",
140-
params=global_params,
141-
)
142-
if not token_trend.empty:
143-
fig = px.area(
144-
token_trend,
145-
x="hour",
146-
y=["prompt", "completion"],
147-
title="Tokens over Time",
148-
)
149-
st.plotly_chart(fig, use_container_width=True)
150-
else:
151-
st.info("No token usage data found.")
117+
""", params=global_params)
118+
if not token_trend.empty:
119+
fig = px.area(token_trend, x="hour", y=["prompt", "completion"], title="Tokens over Time")
120+
st.plotly_chart(fig, use_container_width=True)
121+
else:
122+
st.info("No token usage data found.")
152123

153124
# TAB 1: PERFORMANCE
154125
with tabs[1]:
155-
st.subheader("Latency Metrics")
156-
lat_data = safe_query(
157-
f"""
126+
st.subheader("Latency Metrics")
127+
lat_data = safe_query(f"""
158128
WITH enriched AS ({ENRICHED_EVENTS_CTE})
159129
SELECT
160130
APPROX_QUANTILES(CAST(JSON_VALUE(latency_ms, '$.total_ms') AS FLOAT64), 100)[OFFSET(50)] as p50,
161131
APPROX_QUANTILES(CAST(JSON_VALUE(latency_ms, '$.total_ms') AS FLOAT64), 100)[OFFSET(90)] as p90,
162132
AVG(CAST(JSON_VALUE(latency_ms, '$.time_to_first_token_ms') AS FLOAT64)) as avg_ttft
163133
FROM enriched WHERE event_family = 'llm'
164-
""",
165-
params=global_params,
166-
)
167-
if not lat_data.empty and pd.notnull(lat_data["p50"][0]):
168-
p1, p2, p3 = st.columns(3)
169-
p1.metric("p50 Latency", f"{lat_data['p50'][0]:.0f}ms")
170-
p2.metric("p90 Latency", f"{lat_data['p90'][0]:.0f}ms")
171-
p3.metric("Avg TTFT", f"{lat_data['avg_ttft'][0]:.0f}ms")
172-
else:
173-
st.warning("No performance data found.")
134+
""", params=global_params)
135+
if not lat_data.empty and pd.notnull(lat_data['p50'][0]):
136+
p1, p2, p3 = st.columns(3)
137+
p1.metric("p50 Latency", f"{lat_data['p50'][0]:.0f}ms")
138+
p2.metric("p90 Latency", f"{lat_data['p90'][0]:.0f}ms")
139+
p3.metric("Avg TTFT", f"{lat_data['avg_ttft'][0]:.0f}ms")
140+
else:
141+
st.warning("No performance data found.")
174142

175143
# TAB 2: RELIABILITY
176144
with tabs[2]:
177-
st.subheader("Error Distribution")
178-
err_data = safe_query(
179-
f"""
145+
st.subheader("Error Distribution")
146+
err_data = safe_query(f"""
180147
WITH enriched AS ({ENRICHED_EVENTS_CTE})
181148
SELECT event_family, event_type, COUNT(*) as errors
182149
FROM enriched WHERE is_canonical_error = TRUE
183150
GROUP BY 1, 2 ORDER BY errors DESC
184-
""",
185-
params=global_params,
186-
)
187-
if not err_data.empty:
188-
fig = px.bar(err_data, x="event_type", y="errors", color="event_family")
189-
st.plotly_chart(fig, use_container_width=True)
190-
else:
191-
st.success("No errors detected.")
151+
""", params=global_params)
152+
if not err_data.empty:
153+
fig = px.bar(err_data, x="event_type", y="errors", color="event_family")
154+
st.plotly_chart(fig, use_container_width=True)
155+
else:
156+
st.success("No errors detected.")
192157

193158
# TAB 3: MULTIMODAL
194159
with tabs[3]:
195-
st.subheader("Media Parts")
196-
multi_data = safe_query(
197-
f"""
160+
st.subheader("Media Parts")
161+
multi_data = safe_query(f"""
198162
SELECT cp.mime_type, COUNT(*) as count
199163
FROM {{table_ref}}, UNNEST(content_parts) as cp
200164
WHERE {where_clause} GROUP BY 1
201-
""",
202-
params=global_params,
203-
)
204-
if not multi_data.empty:
205-
fig = px.pie(multi_data, values="count", names="mime_type")
206-
st.plotly_chart(fig, use_container_width=True)
207-
else:
208-
st.info("No multimodal content found.")
165+
""", params=global_params)
166+
if not multi_data.empty:
167+
fig = px.pie(multi_data, values='count', names='mime_type')
168+
st.plotly_chart(fig, use_container_width=True)
169+
else:
170+
st.info("No multimodal content found.")
209171

210172
# TAB 4: HITL
211173
with tabs[4]:
212-
st.subheader("Human-in-the-Loop Activity")
213-
hitl_data = safe_query(
214-
f"""
174+
st.subheader("Human-in-the-Loop Activity")
175+
hitl_data = safe_query(f"""
215176
WITH enriched AS ({ENRICHED_EVENTS_CTE})
216177
SELECT event_type, COUNT(*) as count
217178
FROM enriched WHERE event_family = 'hitl'
218179
GROUP BY 1
219-
""",
220-
params=global_params,
221-
)
222-
if not hitl_data.empty:
223-
st.table(hitl_data)
224-
else:
225-
st.info("No HITL events found.")
180+
""", params=global_params)
181+
if not hitl_data.empty:
182+
st.table(hitl_data)
183+
else:
184+
st.info("No HITL events found.")
226185

227186
# TAB 5: TRACE EXPLORER
228187
with tabs[5]:
229-
st.subheader("Session Explorer")
230-
sessions = safe_query(
231-
f"""
188+
st.subheader("Session Explorer")
189+
sessions = safe_query(f"""
232190
SELECT session_id, agent, MIN(timestamp) as ts,
233191
FORMAT_TIMESTAMP('%m-%d %H:%M', MIN(timestamp)) as f_ts
234192
FROM {{table_ref}} WHERE {where_clause} GROUP BY 1, 2 ORDER BY ts DESC LIMIT 50
235-
""",
236-
params=global_params,
237-
)
193+
""", params=global_params)
238194

239-
if not sessions.empty:
240-
sessions["label"] = (
241-
sessions["f_ts"]
242-
+ " | "
243-
+ sessions["agent"].fillna("?")
244-
+ " | "
245-
+ sessions["session_id"].str[:8]
246-
)
247-
label_map = dict(zip(sessions["label"], sessions["session_id"]))
248-
sel_label = st.selectbox("Select Session", sessions["label"])
249-
sel_id = label_map[sel_label]
195+
if not sessions.empty:
196+
sessions['label'] = sessions['f_ts'] + " | " + sessions['agent'].fillna("?") + " | " + sessions['session_id'].str[:8]
197+
label_map = dict(zip(sessions['label'], sessions['session_id']))
198+
sel_label = st.selectbox("Select Session", sessions['label'])
199+
sel_id = label_map[sel_label]
250200

251-
trace_detail = safe_query(
252-
"""
201+
trace_detail = safe_query("""
253202
SELECT timestamp, event_type, agent, status, error_message
254203
FROM {table_ref} WHERE session_id = @sid ORDER BY timestamp
255-
""",
256-
params=[bigquery.ScalarQueryParameter("sid", "STRING", sel_id)],
257-
)
258-
st.dataframe(trace_detail, use_container_width=True)
204+
""", params=[bigquery.ScalarQueryParameter("sid", "STRING", sel_id)])
205+
st.dataframe(trace_detail, use_container_width=True)

0 commit comments

Comments
 (0)