shukdevdatta123 commited on
Commit
3de8e15
·
verified ·
1 Parent(s): ddae684

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +480 -108
app.py CHANGED
@@ -4,10 +4,20 @@ import re
4
  from groq import Groq
5
  import pandas as pd
6
  import matplotlib.pyplot as plt
 
7
  import io
8
  import base64
9
  from datetime import datetime, timedelta
10
  import json
 
 
 
 
 
 
 
 
 
11
 
12
  def validate_api_key(api_key):
13
  """Validate if the API key has the correct format."""
@@ -41,18 +51,44 @@ def test_api_connection(api_key):
41
  # Ensure analytics directory exists
42
  os.makedirs("analytics", exist_ok=True)
43
 
44
- def log_chat_interaction(model, tokens_used, response_time, user_message_length):
45
- """Log chat interactions for analytics"""
46
  timestamp = datetime.now().isoformat()
47
 
 
 
 
 
48
  log_file = "analytics/chat_log.json"
49
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  log_entry = {
51
  "timestamp": timestamp,
52
  "model": model,
53
  "tokens_used": tokens_used,
54
  "response_time_sec": response_time,
55
- "user_message_length": user_message_length
 
 
 
 
 
56
  }
57
 
58
  # Append to existing log or create new file
@@ -69,6 +105,8 @@ def log_chat_interaction(model, tokens_used, response_time, user_message_length)
69
 
70
  with open(log_file, "w") as f:
71
  json.dump(logs, f, indent=2)
 
 
72
 
73
  def get_template_prompt(template_name):
74
  """Get system prompt for a given template name"""
@@ -82,7 +120,7 @@ def get_template_prompt(template_name):
82
 
83
  return templates.get(template_name, "")
84
 
85
- def enhanced_chat_with_groq(api_key, model, user_message, temperature, max_tokens, top_p, chat_history, template_name=""):
86
  """Enhanced chat function with analytics logging"""
87
  start_time = datetime.now()
88
 
@@ -92,11 +130,11 @@ def enhanced_chat_with_groq(api_key, model, user_message, temperature, max_token
92
  # Validate and process as before
93
  is_valid, message = validate_api_key(api_key)
94
  if not is_valid:
95
- return chat_history + [[user_message, f"Error: {message}"]]
96
 
97
  connection_valid, connection_message = test_api_connection(api_key)
98
  if not connection_valid:
99
- return chat_history + [[user_message, f"Error: {connection_message}"]]
100
 
101
  try:
102
  # Format history
@@ -126,55 +164,137 @@ def enhanced_chat_with_groq(api_key, model, user_message, temperature, max_token
126
  response_time = (end_time - start_time).total_seconds()
127
  tokens_used = response.usage.total_tokens
128
 
 
 
 
129
  # Log the interaction
130
- log_chat_interaction(
131
  model=model,
132
  tokens_used=tokens_used,
133
  response_time=response_time,
134
- user_message_length=len(user_message)
 
 
135
  )
136
 
137
  # Extract response
138
  assistant_response = response.choices[0].message.content
139
 
140
- return chat_history + [[user_message, assistant_response]]
141
 
142
  except Exception as e:
143
  error_message = f"Error: {str(e)}"
144
- return chat_history + [[user_message, error_message]]
145
 
146
  def clear_conversation():
147
  """Clear the conversation history."""
148
- return []
149
 
150
  def plt_to_html(fig):
151
  """Convert matplotlib figure to HTML img tag"""
152
  buf = io.BytesIO()
153
- fig.savefig(buf, format="png", bbox_inches="tight")
154
  buf.seek(0)
155
  img_str = base64.b64encode(buf.read()).decode("utf-8")
156
  plt.close(fig)
157
  return f'<img src="data:image/png;base64,{img_str}" alt="Chart">'
158
 
159
- def generate_analytics():
160
- """Generate analytics from the chat log"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  log_file = "analytics/chat_log.json"
162
 
163
  if not os.path.exists(log_file):
164
- return "No analytics data available yet.", None, None, None, []
165
 
166
  try:
167
  with open(log_file, "r") as f:
168
  logs = json.load(f)
169
 
170
  if not logs:
171
- return "No analytics data available yet.", None, None, None, []
172
 
173
  # Convert to DataFrame
174
  df = pd.DataFrame(logs)
175
  df["timestamp"] = pd.to_datetime(df["timestamp"])
176
 
177
- # Generate usage by model chart
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  model_usage = df.groupby("model").agg({
179
  "tokens_used": "sum",
180
  "timestamp": "count"
@@ -182,48 +302,226 @@ def generate_analytics():
182
  model_usage.columns = ["model", "total_tokens", "request_count"]
183
 
184
  fig1 = plt.figure(figsize=(10, 6))
185
- plt.bar(model_usage["model"], model_usage["total_tokens"])
186
- plt.title("Token Usage by Model")
187
- plt.xlabel("Model")
188
- plt.ylabel("Total Tokens Used")
189
  plt.xticks(rotation=45)
 
 
 
 
 
190
  plt.tight_layout()
191
  model_usage_img = plt_to_html(fig1)
192
 
193
- # Generate usage over time chart
194
  df["date"] = df["timestamp"].dt.date
195
  daily_usage = df.groupby("date").agg({
196
  "tokens_used": "sum"
197
  }).reset_index()
198
 
199
  fig2 = plt.figure(figsize=(10, 6))
200
- plt.plot(daily_usage["date"], daily_usage["tokens_used"], marker="o")
201
- plt.title("Daily Token Usage")
202
- plt.xlabel("Date")
203
- plt.ylabel("Tokens Used")
204
- plt.grid(True)
 
 
 
 
 
 
205
  plt.tight_layout()
206
  daily_usage_img = plt_to_html(fig2)
207
 
208
- # Generate response time chart
209
  model_response_time = df.groupby("model").agg({
210
- "response_time_sec": "mean"
211
  }).reset_index()
 
212
 
213
  fig3 = plt.figure(figsize=(10, 6))
214
- plt.bar(model_response_time["model"], model_response_time["response_time_sec"])
215
- plt.title("Average Response Time by Model")
216
- plt.xlabel("Model")
217
- plt.ylabel("Response Time (seconds)")
 
 
 
 
 
 
 
218
  plt.xticks(rotation=45)
 
 
 
 
 
219
  plt.tight_layout()
220
  response_time_img = plt_to_html(fig3)
221
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
  # Summary statistics
223
  total_tokens = df["tokens_used"].sum()
224
  total_requests = len(df)
225
  avg_response_time = df["response_time_sec"].mean()
226
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  # Handling the case where there might not be enough data
228
  if not model_usage.empty:
229
  most_used_model = model_usage.iloc[model_usage["request_count"].argmax()]["model"]
@@ -233,18 +531,30 @@ def generate_analytics():
233
  summary = f"""
234
  ## Analytics Summary
235
 
236
- - **Total API Requests**: {total_requests}
 
237
  - **Total Tokens Used**: {total_tokens:,}
 
238
  - **Average Response Time**: {avg_response_time:.2f} seconds
239
  - **Most Used Model**: {most_used_model}
240
  - **Date Range**: {df["timestamp"].min().date()} to {df["timestamp"].max().date()}
 
 
 
 
 
 
 
 
 
 
241
  """
242
 
243
- return summary, model_usage_img, daily_usage_img, response_time_img, df.to_dict("records")
244
 
245
  except Exception as e:
246
  error_message = f"Error generating analytics: {str(e)}"
247
- return error_message, None, None, None, []
248
 
249
  # Define available models
250
  models = [
@@ -258,11 +568,17 @@ models = [
258
  # Define templates
259
  templates = ["General Assistant", "Code Helper", "Creative Writer", "Technical Expert", "Data Analyst"]
260
 
 
 
 
261
  # Create the Gradio interface
262
- with gr.Blocks(title="Groq AI Chat Playground") as app:
 
 
 
263
  gr.Markdown("# Groq AI Chat Playground")
264
 
265
- # Create tabs for Chat and Analytics
266
  with gr.Tabs():
267
  with gr.Tab("Chat"):
268
  # New model information accordion
@@ -360,82 +676,138 @@ with gr.Blocks(title="Groq AI Chat Playground") as app:
360
  submit_button = gr.Button("Send", variant="primary")
361
  clear_button = gr.Button("Clear Conversation")
362
 
363
- # Analytics Dashboard Tab
364
  with gr.Tab("Analytics Dashboard"):
365
  with gr.Column():
366
- gr.Markdown("# Usage Analytics Dashboard")
367
- refresh_analytics_button = gr.Button("Refresh Analytics")
368
-
369
- analytics_summary = gr.Markdown()
370
 
371
  with gr.Row():
372
- with gr.Column():
373
- model_usage_chart = gr.HTML(label="Token Usage by Model")
374
- with gr.Column():
375
- daily_usage_chart = gr.HTML(label="Daily Token Usage")
 
 
 
 
376
 
377
- response_time_chart = gr.HTML(label="Response Time by Model")
378
 
379
- with gr.Accordion("Raw Data", open=False):
380
- analytics_table = gr.DataFrame(label="Raw Analytics Data")
381
-
382
- # Connect components with functions
383
- submit_button.click(
384
- fn=enhanced_chat_with_groq,
385
- inputs=[
386
- api_key_input,
387
- model_dropdown,
388
- message_input,
389
- temperature_slider,
390
- max_tokens_slider,
391
- top_p_slider,
392
- chatbot,
393
- template_dropdown
394
- ],
395
- outputs=chatbot
396
- ).then(
397
- fn=lambda: "",
398
- inputs=None,
399
- outputs=message_input
400
- )
401
-
402
- message_input.submit(
403
- fn=enhanced_chat_with_groq,
404
- inputs=[
405
- api_key_input,
406
- model_dropdown,
407
- message_input,
408
- temperature_slider,
409
- max_tokens_slider,
410
- top_p_slider,
411
- chatbot,
412
- template_dropdown
413
- ],
414
- outputs=chatbot
415
- ).then(
416
- fn=lambda: "",
417
- inputs=None,
418
- outputs=message_input
419
- )
420
-
421
- clear_button.click(
422
- fn=clear_conversation,
423
- inputs=None,
424
- outputs=chatbot
425
- )
426
-
427
- test_button.click(
428
- fn=test_api_connection,
429
- inputs=[api_key_input],
430
- outputs=[api_status]
431
- )
432
 
433
- refresh_analytics_button.click(
434
- fn=generate_analytics,
435
- inputs=[],
436
- outputs=[analytics_summary, model_usage_chart, daily_usage_chart, response_time_chart, analytics_table]
437
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
438
 
439
- # Launch the app
440
  if __name__ == "__main__":
441
- app.launch(share=False)
 
4
  from groq import Groq
5
  import pandas as pd
6
  import matplotlib.pyplot as plt
7
+ import seaborn as sns
8
  import io
9
  import base64
10
  from datetime import datetime, timedelta
11
  import json
12
+ import numpy as np
13
+ from statsmodels.tsa.arima.model import ARIMA
14
+ from sklearn.linear_model import LinearRegression
15
+ import calendar
16
+ import matplotlib.dates as mdates
17
+
18
+ # Set the style for better looking charts
19
+ plt.style.use('ggplot')
20
+ sns.set_palette("pastel")
21
 
22
  def validate_api_key(api_key):
23
  """Validate if the API key has the correct format."""
 
51
  # Ensure analytics directory exists
52
  os.makedirs("analytics", exist_ok=True)
53
 
54
+ def log_chat_interaction(model, tokens_used, response_time, user_message_length, message_type, session_id=None):
55
+ """Enhanced log chat interactions for analytics"""
56
  timestamp = datetime.now().isoformat()
57
 
58
+ # Generate a session ID if none is provided
59
+ if session_id is None:
60
+ session_id = f"session_{datetime.now().strftime('%Y%m%d%H%M%S')}_{hash(timestamp) % 1000}"
61
+
62
  log_file = "analytics/chat_log.json"
63
 
64
+ # Extract message intent/category through simple keyword matching
65
+ intent_categories = {
66
+ "code": ["code", "programming", "function", "class", "algorithm", "debug"],
67
+ "creative": ["story", "poem", "creative", "imagine", "write", "generate"],
68
+ "technical": ["explain", "how does", "technical", "details", "documentation"],
69
+ "data": ["data", "analysis", "statistics", "graph", "chart", "dataset"],
70
+ "general": [] # Default category
71
+ }
72
+
73
+ message_content = user_message_length.lower() if isinstance(user_message_length, str) else ""
74
+ message_intent = "general"
75
+
76
+ for intent, keywords in intent_categories.items():
77
+ if any(keyword in message_content for keyword in keywords):
78
+ message_intent = intent
79
+ break
80
+
81
  log_entry = {
82
  "timestamp": timestamp,
83
  "model": model,
84
  "tokens_used": tokens_used,
85
  "response_time_sec": response_time,
86
+ "message_length": len(message_content) if isinstance(message_content, str) else user_message_length,
87
+ "message_type": message_type,
88
+ "message_intent": message_intent,
89
+ "session_id": session_id,
90
+ "day_of_week": datetime.now().strftime("%A"),
91
+ "hour_of_day": datetime.now().hour
92
  }
93
 
94
  # Append to existing log or create new file
 
105
 
106
  with open(log_file, "w") as f:
107
  json.dump(logs, f, indent=2)
108
+
109
+ return session_id
110
 
111
  def get_template_prompt(template_name):
112
  """Get system prompt for a given template name"""
 
120
 
121
  return templates.get(template_name, "")
122
 
123
+ def enhanced_chat_with_groq(api_key, model, user_message, temperature, max_tokens, top_p, chat_history, template_name="", session_id=None):
124
  """Enhanced chat function with analytics logging"""
125
  start_time = datetime.now()
126
 
 
130
  # Validate and process as before
131
  is_valid, message = validate_api_key(api_key)
132
  if not is_valid:
133
+ return chat_history + [[user_message, f"Error: {message}"]], session_id
134
 
135
  connection_valid, connection_message = test_api_connection(api_key)
136
  if not connection_valid:
137
+ return chat_history + [[user_message, f"Error: {connection_message}"]], session_id
138
 
139
  try:
140
  # Format history
 
164
  response_time = (end_time - start_time).total_seconds()
165
  tokens_used = response.usage.total_tokens
166
 
167
+ # Determine message type based on template or content
168
+ message_type = template_name if template_name else "general"
169
+
170
  # Log the interaction
171
+ session_id = log_chat_interaction(
172
  model=model,
173
  tokens_used=tokens_used,
174
  response_time=response_time,
175
+ user_message_length=user_message,
176
+ message_type=message_type,
177
+ session_id=session_id
178
  )
179
 
180
  # Extract response
181
  assistant_response = response.choices[0].message.content
182
 
183
+ return chat_history + [[user_message, assistant_response]], session_id
184
 
185
  except Exception as e:
186
  error_message = f"Error: {str(e)}"
187
+ return chat_history + [[user_message, error_message]], session_id
188
 
189
  def clear_conversation():
190
  """Clear the conversation history."""
191
+ return [], None # Return empty chat history and reset session ID
192
 
193
  def plt_to_html(fig):
194
  """Convert matplotlib figure to HTML img tag"""
195
  buf = io.BytesIO()
196
+ fig.savefig(buf, format="png", bbox_inches="tight", dpi=100)
197
  buf.seek(0)
198
  img_str = base64.b64encode(buf.read()).decode("utf-8")
199
  plt.close(fig)
200
  return f'<img src="data:image/png;base64,{img_str}" alt="Chart">'
201
 
202
+ def predict_future_usage(df, days_ahead=7):
203
+ """Predict future token usage based on historical data"""
204
+ if len(df) < 5: # Need a minimum amount of data for prediction
205
+ return None, "Insufficient data for prediction"
206
+
207
+ # Group by date and get total tokens per day
208
+ df['date'] = pd.to_datetime(df['timestamp']).dt.date
209
+ daily_data = df.groupby('date')['tokens_used'].sum().reset_index()
210
+ daily_data['date'] = pd.to_datetime(daily_data['date'])
211
+
212
+ # Sort by date
213
+ daily_data = daily_data.sort_values('date')
214
+
215
+ try:
216
+ # Simple linear regression for prediction
217
+ X = np.array(range(len(daily_data))).reshape(-1, 1)
218
+ y = daily_data['tokens_used'].values
219
+
220
+ model = LinearRegression()
221
+ model.fit(X, y)
222
+
223
+ # Predict future days
224
+ future_days = pd.date_range(
225
+ start=daily_data['date'].max() + timedelta(days=1),
226
+ periods=days_ahead
227
+ )
228
+
229
+ future_X = np.array(range(len(daily_data), len(daily_data) + days_ahead)).reshape(-1, 1)
230
+ predictions = model.predict(future_X)
231
+
232
+ # Create prediction dataframe
233
+ prediction_df = pd.DataFrame({
234
+ 'date': future_days,
235
+ 'predicted_tokens': np.maximum(predictions, 0) # Ensure no negative predictions
236
+ })
237
+
238
+ # Create visualization
239
+ fig = plt.figure(figsize=(12, 6))
240
+ plt.plot(daily_data['date'], daily_data['tokens_used'], 'o-', label='Historical Usage')
241
+ plt.plot(prediction_df['date'], prediction_df['predicted_tokens'], 'o--', label='Predicted Usage')
242
+ plt.title('Token Usage Forecast (Next 7 Days)')
243
+ plt.xlabel('Date')
244
+ plt.ylabel('Token Usage')
245
+ plt.legend()
246
+ plt.grid(True)
247
+ plt.xticks(rotation=45)
248
+ plt.tight_layout()
249
+
250
+ return plt_to_html(fig), prediction_df
251
+
252
+ except Exception as e:
253
+ return None, f"Error in prediction: {str(e)}"
254
+
255
+ def export_analytics_csv(df):
256
+ """Export analytics data to CSV"""
257
+ try:
258
+ output_path = "analytics/export_" + datetime.now().strftime("%Y%m%d_%H%M%S") + ".csv"
259
+ df.to_csv(output_path, index=False)
260
+ return f"Data exported to {output_path}"
261
+ except Exception as e:
262
+ return f"Error exporting data: {str(e)}"
263
+
264
+ def generate_enhanced_analytics(date_range=None):
265
+ """Generate enhanced analytics from the chat log"""
266
  log_file = "analytics/chat_log.json"
267
 
268
  if not os.path.exists(log_file):
269
+ return "No analytics data available yet.", None, None, None, None, None, None, None, None, []
270
 
271
  try:
272
  with open(log_file, "r") as f:
273
  logs = json.load(f)
274
 
275
  if not logs:
276
+ return "No analytics data available yet.", None, None, None, None, None, None, None, None, []
277
 
278
  # Convert to DataFrame
279
  df = pd.DataFrame(logs)
280
  df["timestamp"] = pd.to_datetime(df["timestamp"])
281
 
282
+ # Apply date filter if provided
283
+ if date_range and date_range != "all":
284
+ end_date = datetime.now()
285
+
286
+ if date_range == "last_7_days":
287
+ start_date = end_date - timedelta(days=7)
288
+ elif date_range == "last_30_days":
289
+ start_date = end_date - timedelta(days=30)
290
+ elif date_range == "last_90_days":
291
+ start_date = end_date - timedelta(days=90)
292
+ else: # Default to all time if unrecognized option
293
+ start_date = df["timestamp"].min()
294
+
295
+ df = df[(df["timestamp"] >= start_date) & (df["timestamp"] <= end_date)]
296
+
297
+ # 1. Generate usage by model chart
298
  model_usage = df.groupby("model").agg({
299
  "tokens_used": "sum",
300
  "timestamp": "count"
 
302
  model_usage.columns = ["model", "total_tokens", "request_count"]
303
 
304
  fig1 = plt.figure(figsize=(10, 6))
305
+ ax1 = sns.barplot(x="model", y="total_tokens", data=model_usage)
306
+ plt.title("Token Usage by Model", fontsize=14)
307
+ plt.xlabel("Model", fontsize=12)
308
+ plt.ylabel("Total Tokens Used", fontsize=12)
309
  plt.xticks(rotation=45)
310
+
311
+ # Add values on top of bars
312
+ for i, v in enumerate(model_usage["total_tokens"]):
313
+ ax1.text(i, v + 0.1, f"{v:,}", ha='center')
314
+
315
  plt.tight_layout()
316
  model_usage_img = plt_to_html(fig1)
317
 
318
+ # 2. Generate usage over time chart
319
  df["date"] = df["timestamp"].dt.date
320
  daily_usage = df.groupby("date").agg({
321
  "tokens_used": "sum"
322
  }).reset_index()
323
 
324
  fig2 = plt.figure(figsize=(10, 6))
325
+ plt.plot(daily_usage["date"], daily_usage["tokens_used"], marker="o", linestyle="-", linewidth=2)
326
+ plt.title("Daily Token Usage", fontsize=14)
327
+ plt.xlabel("Date", fontsize=12)
328
+ plt.ylabel("Tokens Used", fontsize=12)
329
+ plt.grid(True, alpha=0.3)
330
+
331
+ # Format x-axis dates
332
+ plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
333
+ plt.gca().xaxis.set_major_locator(mdates.AutoDateLocator())
334
+
335
+ plt.xticks(rotation=45)
336
  plt.tight_layout()
337
  daily_usage_img = plt_to_html(fig2)
338
 
339
+ # 3. Generate response time chart by model
340
  model_response_time = df.groupby("model").agg({
341
+ "response_time_sec": ["mean", "median", "std"]
342
  }).reset_index()
343
+ model_response_time.columns = ["model", "mean_time", "median_time", "std_time"]
344
 
345
  fig3 = plt.figure(figsize=(10, 6))
346
+ ax3 = sns.barplot(x="model", y="mean_time", data=model_response_time)
347
+
348
+ # Add error bars
349
+ for i, v in enumerate(model_response_time["mean_time"]):
350
+ std = model_response_time.iloc[i]["std_time"]
351
+ if not np.isnan(std):
352
+ plt.errorbar(i, v, yerr=std, fmt='none', color='black', capsize=5)
353
+
354
+ plt.title("Response Time by Model", fontsize=14)
355
+ plt.xlabel("Model", fontsize=12)
356
+ plt.ylabel("Average Response Time (seconds)", fontsize=12)
357
  plt.xticks(rotation=45)
358
+
359
+ # Add values on top of bars
360
+ for i, v in enumerate(model_response_time["mean_time"]):
361
+ ax3.text(i, v + 0.1, f"{v:.2f}s", ha='center')
362
+
363
  plt.tight_layout()
364
  response_time_img = plt_to_html(fig3)
365
 
366
+ # 4. Usage by time of day and day of week
367
+ if "hour_of_day" in df.columns and "day_of_week" in df.columns:
368
+ # Map day of week to ensure correct order
369
+ day_order = {day: i for i, day in enumerate(['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'])}
370
+ df['day_num'] = df['day_of_week'].map(day_order)
371
+
372
+ hourly_usage = df.groupby("hour_of_day").agg({
373
+ "tokens_used": "sum"
374
+ }).reset_index()
375
+
376
+ daily_usage_by_weekday = df.groupby("day_of_week").agg({
377
+ "tokens_used": "sum"
378
+ }).reset_index()
379
+
380
+ # Sort by day of week
381
+ daily_usage_by_weekday['day_num'] = daily_usage_by_weekday['day_of_week'].map(day_order)
382
+ daily_usage_by_weekday = daily_usage_by_weekday.sort_values('day_num')
383
+
384
+ fig4 = plt.figure(figsize=(18, 8))
385
+
386
+ # Hourly usage chart
387
+ plt.subplot(1, 2, 1)
388
+ sns.barplot(x="hour_of_day", y="tokens_used", data=hourly_usage)
389
+ plt.title("Token Usage by Hour of Day", fontsize=14)
390
+ plt.xlabel("Hour of Day", fontsize=12)
391
+ plt.ylabel("Total Tokens Used", fontsize=12)
392
+ plt.xticks(ticks=range(0, 24, 2))
393
+
394
+ # Daily usage chart
395
+ plt.subplot(1, 2, 2)
396
+ sns.barplot(x="day_of_week", y="tokens_used", data=daily_usage_by_weekday)
397
+ plt.title("Token Usage by Day of Week", fontsize=14)
398
+ plt.xlabel("Day of Week", fontsize=12)
399
+ plt.ylabel("Total Tokens Used", fontsize=12)
400
+ plt.xticks(rotation=45)
401
+
402
+ plt.tight_layout()
403
+ time_pattern_img = plt_to_html(fig4)
404
+ else:
405
+ time_pattern_img = None
406
+
407
+ # 5. Message intent/type analysis
408
+ if "message_intent" in df.columns:
409
+ intent_usage = df.groupby("message_intent").agg({
410
+ "tokens_used": "sum",
411
+ "timestamp": "count"
412
+ }).reset_index()
413
+ intent_usage.columns = ["intent", "total_tokens", "request_count"]
414
+
415
+ fig5 = plt.figure(figsize=(12, 10))
416
+
417
+ # Pie chart for intent distribution
418
+ plt.subplot(2, 1, 1)
419
+ plt.pie(intent_usage["request_count"], labels=intent_usage["intent"], autopct='%1.1f%%', startangle=90)
420
+ plt.axis('equal')
421
+ plt.title("Message Intent Distribution", fontsize=14)
422
+
423
+ # Bar chart for tokens by intent
424
+ plt.subplot(2, 1, 2)
425
+ sns.barplot(x="intent", y="total_tokens", data=intent_usage)
426
+ plt.title("Token Usage by Message Intent", fontsize=14)
427
+ plt.xlabel("Intent", fontsize=12)
428
+ plt.ylabel("Total Tokens Used", fontsize=12)
429
+
430
+ plt.tight_layout()
431
+ intent_analysis_img = plt_to_html(fig5)
432
+ else:
433
+ intent_analysis_img = None
434
+
435
+ # 6. Model comparison chart
436
+ if len(model_usage) > 1:
437
+ fig6 = plt.figure(figsize=(12, 8))
438
+
439
+ # Create metrics for comparison
440
+ model_comparison = df.groupby("model").agg({
441
+ "tokens_used": ["mean", "median", "sum"],
442
+ "response_time_sec": ["mean", "median"]
443
+ }).reset_index()
444
+
445
+ # Flatten column names
446
+ model_comparison.columns = [
447
+ f"{col[0]}_{col[1]}" if col[1] else col[0]
448
+ for col in model_comparison.columns
449
+ ]
450
+
451
+ # Calculate token efficiency (tokens per second)
452
+ model_comparison["tokens_per_second"] = model_comparison["tokens_used_mean"] / model_comparison["response_time_sec_mean"]
453
+
454
+ # Normalize for radar chart
455
+ metrics = ['tokens_used_mean', 'response_time_sec_mean', 'tokens_per_second']
456
+ model_comparison_norm = model_comparison.copy()
457
+
458
+ for metric in metrics:
459
+ max_val = model_comparison[metric].max()
460
+ if max_val > 0: # Avoid division by zero
461
+ model_comparison_norm[f"{metric}_norm"] = model_comparison[metric] / max_val
462
+
463
+ # Bar chart comparison
464
+ plt.subplot(1, 2, 1)
465
+ x = np.arange(len(model_comparison["model"]))
466
+ width = 0.35
467
+
468
+ plt.bar(x - width/2, model_comparison["tokens_used_mean"], width, label="Avg Tokens")
469
+ plt.bar(x + width/2, model_comparison["response_time_sec_mean"], width, label="Avg Time (s)")
470
+
471
+ plt.xlabel("Model")
472
+ plt.ylabel("Value")
473
+ plt.title("Model Performance Comparison")
474
+ plt.xticks(x, model_comparison["model"], rotation=45)
475
+ plt.legend()
476
+
477
+ # Scatter plot for efficiency
478
+ plt.subplot(1, 2, 2)
479
+ sns.scatterplot(
480
+ x="response_time_sec_mean",
481
+ y="tokens_used_mean",
482
+ size="tokens_per_second",
483
+ hue="model",
484
+ data=model_comparison,
485
+ sizes=(100, 500)
486
+ )
487
+
488
+ plt.xlabel("Average Response Time (s)")
489
+ plt.ylabel("Average Tokens Used")
490
+ plt.title("Model Efficiency")
491
+
492
+ plt.tight_layout()
493
+ model_comparison_img = plt_to_html(fig6)
494
+ else:
495
+ model_comparison_img = None
496
+
497
+ # 7. Usage prediction chart
498
+ forecast_chart, prediction_data = predict_future_usage(df)
499
+
500
  # Summary statistics
501
  total_tokens = df["tokens_used"].sum()
502
  total_requests = len(df)
503
  avg_response_time = df["response_time_sec"].mean()
504
 
505
+ # Cost estimation (assuming average pricing)
506
+ # These rates are estimates and should be updated with actual rates
507
+ estimated_cost_rates = {
508
+ "llama3-70b-8192": 0.0001, # per token
509
+ "llama3-8b-8192": 0.00005,
510
+ "mistral-saba-24b": 0.00008,
511
+ "gemma2-9b-it": 0.00006,
512
+ "allam-2-7b": 0.00005
513
+ }
514
+
515
+ total_estimated_cost = 0
516
+ model_costs = []
517
+
518
+ for model_name in df["model"].unique():
519
+ model_tokens = df[df["model"] == model_name]["tokens_used"].sum()
520
+ rate = estimated_cost_rates.get(model_name, 0.00007) # Default to average rate if unknown
521
+ cost = model_tokens * rate
522
+ total_estimated_cost += cost
523
+ model_costs.append({"model": model_name, "tokens": model_tokens, "cost": cost})
524
+
525
  # Handling the case where there might not be enough data
526
  if not model_usage.empty:
527
  most_used_model = model_usage.iloc[model_usage["request_count"].argmax()]["model"]
 
531
  summary = f"""
532
  ## Analytics Summary
533
 
534
+ ### Overview
535
+ - **Total API Requests**: {total_requests:,}
536
  - **Total Tokens Used**: {total_tokens:,}
537
+ - **Estimated Cost**: ${total_estimated_cost:.2f}
538
  - **Average Response Time**: {avg_response_time:.2f} seconds
539
  - **Most Used Model**: {most_used_model}
540
  - **Date Range**: {df["timestamp"].min().date()} to {df["timestamp"].max().date()}
541
+
542
+ ### Model Costs Breakdown
543
+ {''.join([f"- **{cost['model']}**: {cost['tokens']:,} tokens / ${cost['cost']:.2f}\n" for cost in model_costs])}
544
+
545
+ ### Usage Patterns
546
+ - **Busiest Day**: {df.groupby("date")["tokens_used"].sum().idxmax()} ({df[df["date"] == df.groupby("date")["tokens_used"].sum().idxmax()]["tokens_used"].sum():,} tokens)
547
+ - **Most Efficient Model**: {df.groupby("model")["response_time_sec"].mean().idxmin()} ({df.groupby("model")["response_time_sec"].mean().min():.2f}s avg response)
548
+
549
+ ### Forecast
550
+ - **Projected Usage (Next 7 Days)**: {prediction_data["predicted_tokens"].sum():,.0f} tokens (estimated)
551
  """
552
 
553
+ return summary, model_usage_img, daily_usage_img, response_time_img, time_pattern_img, intent_analysis_img, model_comparison_img, forecast_chart, export_analytics_csv(df), df.to_dict("records")
554
 
555
  except Exception as e:
556
  error_message = f"Error generating analytics: {str(e)}"
557
+ return error_message, None, None, None, None, None, None, None, None, []
558
 
559
  # Define available models
560
  models = [
 
568
  # Define templates
569
  templates = ["General Assistant", "Code Helper", "Creative Writer", "Technical Expert", "Data Analyst"]
570
 
571
+ # Define date range options for analytics filtering
572
+ date_ranges = ["all", "last_7_days", "last_30_days", "last_90_days"]
573
+
574
  # Create the Gradio interface
575
+ with gr.Blocks(title="Enhanced Groq AI Chat Playground") as app:
576
+ # Store session ID (hidden from UI)
577
+ session_id = gr.State(None)
578
+
579
  gr.Markdown("# Groq AI Chat Playground")
580
 
581
+ # Create tabs for Chat, Analytics and Settings
582
  with gr.Tabs():
583
  with gr.Tab("Chat"):
584
  # New model information accordion
 
676
  submit_button = gr.Button("Send", variant="primary")
677
  clear_button = gr.Button("Clear Conversation")
678
 
679
+ # Enhanced Analytics Dashboard Tab
680
  with gr.Tab("Analytics Dashboard"):
681
  with gr.Column():
682
+ gr.Markdown("# Enhanced Usage Analytics Dashboard")
 
 
 
683
 
684
  with gr.Row():
685
+ refresh_analytics_button = gr.Button("Refresh Analytics", variant="primary")
686
+ date_filter = gr.Dropdown(
687
+ choices=date_ranges,
688
+ value="all",
689
+ label="Date Range Filter",
690
+ info="Filter analytics by time period"
691
+ )
692
+ export_button = gr.Button("Export Data to CSV")
693
 
694
+ analytics_summary = gr.Markdown()
695
 
696
+ with gr.Tabs():
697
+ with gr.Tab("Overview"):
698
+ with gr.Row():
699
+ with gr.Column():
700
+ model_usage_chart = gr.HTML(label="Token Usage by Model")
701
+ with gr.Column():
702
+ daily_usage_chart = gr.HTML(label="Daily Token Usage")
703
+
704
+ response_time_chart = gr.HTML(label="Response Time by Model")
705
+
706
+ with gr.Tab("Usage Patterns"):
707
+ time_pattern_chart = gr.HTML(label="Usage by Time and Day")
708
+ intent_analysis_chart = gr.HTML(label="Message Intent Analysis")
709
+
710
+ with gr.Tab("Model Comparison"):
711
+ model_comparison_chart = gr.HTML(label="Model Performance Comparison")
712
+
713
+ with gr.Tab("Forecast"):
714
+ forecast_chart = gr.HTML(label="Token Usage Forecast")
715
+ gr.Markdown("""This forecast uses linear regression on your historical data to predict token usage for the next 7 days.
716
+ Note that predictions become more accurate with more usage data.""")
717
+
718
+ with gr.Tab("Raw Data"):
719
+ raw_data_table = gr.DataFrame(label="Raw Analytics Data")
720
+ export_status = gr.Textbox(label="Export Status")
721
+
722
+ # Define functions for button callbacks
723
+ def test_api_connection_btn(api_key):
724
+ """Callback for testing API connection"""
725
+ is_valid, validation_message = validate_api_key(api_key)
726
+ if not is_valid:
727
+ return validation_message
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
728
 
729
+ connection_valid, connection_message = test_api_connection(api_key)
730
+ return connection_message
731
+
732
+ def refresh_analytics_callback(date_range):
733
+ """Callback for refreshing analytics dashboard"""
734
+ return generate_enhanced_analytics(date_range)
735
+
736
+ def export_data_callback(df_records):
737
+ """Callback for exporting data to CSV"""
738
+ try:
739
+ df = pd.DataFrame(df_records)
740
+ return export_analytics_csv(df)
741
+ except Exception as e:
742
+ return f"Error exporting data: {str(e)}"
743
+
744
+ # Set up event handlers
745
+ test_button.click(
746
+ test_api_connection_btn,
747
+ inputs=[api_key_input],
748
+ outputs=[api_status]
749
+ )
750
+
751
+ submit_button.click(
752
+ enhanced_chat_with_groq,
753
+ inputs=[
754
+ api_key_input,
755
+ model_dropdown,
756
+ message_input,
757
+ temperature_slider,
758
+ max_tokens_slider,
759
+ top_p_slider,
760
+ chatbot,
761
+ template_dropdown,
762
+ session_id
763
+ ],
764
+ outputs=[chatbot, session_id]
765
+ )
766
+
767
+ message_input.submit(
768
+ enhanced_chat_with_groq,
769
+ inputs=[
770
+ api_key_input,
771
+ model_dropdown,
772
+ message_input,
773
+ temperature_slider,
774
+ max_tokens_slider,
775
+ top_p_slider,
776
+ chatbot,
777
+ template_dropdown,
778
+ session_id
779
+ ],
780
+ outputs=[chatbot, session_id]
781
+ )
782
+
783
+ clear_button.click(
784
+ clear_conversation,
785
+ outputs=[chatbot, session_id]
786
+ )
787
+
788
+ refresh_analytics_button.click(
789
+ refresh_analytics_callback,
790
+ inputs=[date_filter],
791
+ outputs=[
792
+ analytics_summary,
793
+ model_usage_chart,
794
+ daily_usage_chart,
795
+ response_time_chart,
796
+ time_pattern_chart,
797
+ intent_analysis_chart,
798
+ model_comparison_chart,
799
+ forecast_chart,
800
+ export_status,
801
+ raw_data_table
802
+ ]
803
+ )
804
+
805
+ export_button.click(
806
+ export_data_callback,
807
+ inputs=[raw_data_table],
808
+ outputs=[export_status]
809
+ )
810
 
811
+ # Launch the application
812
  if __name__ == "__main__":
813
+ app.launch(share=False) # Set share=True for public URL