rairo commited on
Commit
a36fb46
·
verified ·
1 Parent(s): 571cfa5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +131 -112
app.py CHANGED
@@ -1,25 +1,18 @@
1
  import streamlit as st
2
- import os
3
  import pandas as pd
4
- from pandasai import SmartDataframe
5
  from pandasai.responses.response_parser import ResponseParser
6
  from pandasai.llm import GoogleGemini
7
- import plotly.graph_objects as go
8
  from PIL import Image
9
  import io
10
  import base64
11
- import requests
12
  import google.generativeai as genai
13
  from fpdf import FPDF
14
  import markdown2
15
  import re
16
-
17
- # API Endpoint and payload
18
- API_URL = "https://irisplus.elixir.co.zw/public/api/profile/reporting/stock-card/genericReports"
19
- PAYLOAD = {
20
- "stock_card_report_id": "d2f1a0e1-7be1-472c-9610-94287154e544"
21
- }
22
-
23
 
24
  # Configure Gemini API
25
  gemini_api_key = os.environ.get('GOOGLE_API_KEY')
@@ -30,37 +23,67 @@ if not gemini_api_key:
30
  genai.configure(api_key=gemini_api_key)
31
 
32
  generation_config = {
33
- "temperature": 0.2,
34
- "top_p": 0.95,
35
- "max_output_tokens": 5000,
36
  }
37
 
38
  model = genai.GenerativeModel(
39
- model_name="gemini-2.0-flash-thinking-exp",
40
- generation_config=generation_config,
41
  )
42
 
43
- def fetch_data():
44
- """Fetch stock card report data from API and return cleaned DataFrame"""
45
- response = requests.post(API_URL, data=PAYLOAD)
46
- if response.status_code == 200:
47
- try:
48
- data = response.json()
49
- if isinstance(data, dict) and 'actual_report' in data and isinstance(data['actual_report'], list):
50
- df = pd.DataFrame(data['actual_report']) # Convert list to DataFrame
51
- # Remove columns where all values are None
52
- df.dropna(axis=1, how='all', inplace=True)
53
- return df
54
- else:
55
- st.error("Unexpected response format from API.")
56
- return None
57
- except ValueError:
58
- st.error("Error: Response is not valid JSON.")
59
- return None
60
- else:
61
- st.error(f"Error fetching data: {response.status_code} - {response.text}")
62
  return None
63
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  def md_to_pdf(md_text, pdf):
65
  """Renders basic Markdown to PDF using fpdf text functions (limited formatting)."""
66
  md = markdown2.markdown(md_text) # Parse Markdown
@@ -155,50 +178,29 @@ class StreamLitResponse(ResponseParser):
155
  'value': str(result['value'])
156
  }
157
 
158
- def generateResponse(prompt, df):
159
- """Generate response using PandasAI with SmartDataframe"""
160
  llm = GoogleGemini(api_key=gemini_api_key)
161
- pandas_agent = SmartDataframe(df, config={
162
- "llm": llm,
163
- "response_parser": StreamLitResponse
164
- })
 
 
 
165
  return pandas_agent.chat(prompt)
166
 
167
- def render_chat_message(message):
168
- """Render different types of chat messages"""
169
- if "dataframe" in message:
170
- st.dataframe(message["dataframe"])
171
- elif "plot" in message:
172
- try:
173
- plot_data = message["plot"]
174
- if isinstance(plot_data, str):
175
- st.image(f"data:image/png;base64,{plot_data}")
176
- elif isinstance(plot_data, Image.Image):
177
- st.image(plot_data)
178
- elif isinstance(plot_data, go.Figure):
179
- st.plotly_chart(plot_data)
180
- elif isinstance(plot_data, bytes):
181
- image = Image.open(io.BytesIO(plot_data))
182
- st.image(image)
183
- else:
184
- st.write("Unsupported plot format")
185
- except Exception as e:
186
- st.error(f"Error rendering plot: {e}")
187
- if "content" in message:
188
- st.markdown(message["content"])
189
-
190
- def handle_userinput(question, df):
191
- """Enhanced input handling with robust content processing"""
192
  try:
193
- # Ensure data is loaded and not empty
194
- if df is not None and not df.empty:
195
- # Append user input to chat history
196
  st.session_state.chat_history.append({
197
  "role": "user",
198
  "content": question
199
  })
200
- # Generate response with PandasAI
201
- result = generateResponse(question, df)
 
202
  if isinstance(result, dict):
203
  response_type = result.get('type', 'text')
204
  response_value = result.get('value')
@@ -229,22 +231,30 @@ def handle_userinput(question, df):
229
  except Exception as e:
230
  st.error(f"Error processing input: {e}")
231
 
 
232
  def main():
233
- st.set_page_config(page_title="AI Chat with Your Data", page_icon="📊")
234
 
235
- # Initialize session state variables if not present
236
  if "chat_history" not in st.session_state:
237
  st.session_state.chat_history = []
238
- if "dfs" not in st.session_state:
239
- st.session_state.dfs = fetch_data() # Load DataFrame at startup
240
 
241
- # Create two tabs: Chat and Reports
242
- tab_chat, tab_reports = st.tabs(["Chat", "Reports"])
243
 
244
- # --- Chat Tab ---
 
 
 
 
 
 
 
245
  with tab_chat:
246
- st.title("AI Chat with Your Data 📊")
247
- # Container for chat messages so they update smoothly
248
  chat_container = st.container()
249
  with chat_container:
250
  for message in st.session_state.chat_history:
@@ -260,32 +270,44 @@ def main():
260
  for message in st.session_state.chat_history:
261
  with st.chat_message(message["role"]):
262
  render_chat_message(message)
263
-
264
- # --- Reports Tab ---
265
- # --- Reports Tab ---
266
  with tab_reports:
267
- st.title("Reports")
268
- st.write("Filter by product to generate a report")
269
- df_report = fetch_data()
270
- if df_report is not None and not df_report.empty:
271
- product_names = df_report["product"].unique().tolist() if "product" in df_report.columns else []
272
- selected_products = st.multiselect("Select Product(s)", product_names, default=product_names)
273
- if st.button("Apply Filters and Generate Report"):
274
- filtered_df = df_report.copy()
275
- if selected_products:
276
- filtered_df = filtered_df[filtered_df["product"].isin(selected_products)]
277
-
278
- st.write("Filtered DataFrame Preview:")
279
- with st.expander("Preview"):
280
- st.dataframe(filtered_df.head())
281
-
282
- with st.spinner("Generating Report, Please Wait...."):
 
 
 
 
 
 
 
 
 
 
283
  prompt = f"""
284
- You are an expert business analyst. Analyze the following data and generate a comprehensive and insightful business report including key performance indicators and recommendations.\n\nData:\n{filtered_df.to_markdown(index=False)}
285
- """ # Use to_markdown for better formatting
 
 
286
  response = model.generate_content(prompt)
287
  report = response.text
288
-
 
 
289
  try:
290
  pdf_bytes = generate_pdf(report) # Use generate_pdf
291
  st.download_button(
@@ -297,20 +319,17 @@ def main():
297
  st.markdown(report) # Display the report below the download button
298
  except Exception as e:
299
  st.error(f"Error generating PDF: {e}")
300
- st.markdown(report) # Fallback to displaying report in markdown if PDF fails
301
  else:
302
- st.error("No data available for reports.")
303
 
304
- # --- Sidebar Options ---
305
  with st.sidebar:
306
- st.subheader("Options")
307
  if st.button("Reload Data"):
308
- with st.spinner("Fetching latest data..."):
309
- st.session_state.dfs = fetch_data()
310
- st.success("Data refreshed!")
311
  if st.button("Clear Chat"):
312
  st.session_state.chat_history = []
313
- st.experimental_rerun()
314
-
315
  if __name__ == "__main__":
316
  main()
 
1
  import streamlit as st
 
2
  import pandas as pd
3
+ from pandasai import SmartDataLake
4
  from pandasai.responses.response_parser import ResponseParser
5
  from pandasai.llm import GoogleGemini
6
+ import plotly.express as px
7
  from PIL import Image
8
  import io
9
  import base64
 
10
  import google.generativeai as genai
11
  from fpdf import FPDF
12
  import markdown2
13
  import re
14
+ import json
15
+ import os
 
 
 
 
 
16
 
17
  # Configure Gemini API
18
  gemini_api_key = os.environ.get('GOOGLE_API_KEY')
 
23
  genai.configure(api_key=gemini_api_key)
24
 
25
  generation_config = {
26
+ "temperature": 0.2,
27
+ "top_p": 0.95,
28
+ "max_output_tokens": 5000,
29
  }
30
 
31
  model = genai.GenerativeModel(
32
+ model_name="gemini-2.0-flash-thinking-exp",
33
+ generation_config=generation_config,
34
  )
35
 
36
+ def load_data():
37
+ """Load data from CSV files"""
38
+ try:
39
+ events_df = pd.read_csv("Delta-Events.csv")
40
+ customers_df = pd.read_csv("delta_customers.csv")
41
+ products_df = pd.read_csv("Customer_Products.csv")
42
+ return {
43
+ 'events': events_df,
44
+ 'customers': customers_df,
45
+ 'products': products_df
46
+ }
47
+ except Exception as e:
48
+ st.error(f"Error loading data: {e}")
 
 
 
 
 
 
49
  return None
50
+
51
+ # Dashboard Tab Functions
52
+ def create_dashboard(data):
53
+ """Create dashboard visualizations"""
54
+ st.header("Business Insights Dashboard")
55
+
56
+ # Merge relevant data
57
+ merged_orders = pd.concat([
58
+ data['events'][['Surbub', 'Order Value $']].rename(columns={'Surbub': 'Suburb'}),
59
+ data['customers'][['Surburb', 'Order_Value']].rename(columns={'Surburb': 'Suburb', 'Order_Value': 'Order Value $'})
60
+ ])
61
+
62
+ with st.container():
63
+ col1, col2 = st.columns(2)
64
+ with col1:
65
+ # Total Orders by Suburb
66
+ suburb_orders = merged_orders.groupby('Suburb')['Order Value $'].sum().reset_index()
67
+ fig = px.bar(suburb_orders, x='Suburb', y='Order Value $',
68
+ title='Total Order Value by Suburb')
69
+ st.plotly_chart(fig, use_container_width=True)
70
+
71
+ with col2:
72
+ # Event Types Distribution
73
+ event_counts = data['events']['Event'].value_counts().reset_index()
74
+ fig = px.pie(event_counts, names='Event', values='count',
75
+ title='Event Type Distribution')
76
+ st.plotly_chart(fig, use_container_width=True)
77
+
78
+ # Top Products Analysis
79
+ with st.container():
80
+ st.subheader("Product Performance")
81
+ product_sales = data['products'].groupby('Product')['Quantity'].sum().nlargest(10).reset_index()
82
+ fig = px.bar(product_sales, x='Product', y='Quantity',
83
+ title='Top 10 Products by Quantity Sold')
84
+ st.plotly_chart(fig, use_container_width=True)
85
+
86
+ # ... [Keep the md_to_pdf, generate_pdf, StreamLitResponse, and generateResponse functions same as before but update generateResponse]
87
  def md_to_pdf(md_text, pdf):
88
  """Renders basic Markdown to PDF using fpdf text functions (limited formatting)."""
89
  md = markdown2.markdown(md_text) # Parse Markdown
 
178
  'value': str(result['value'])
179
  }
180
 
181
+ def generateResponse(prompt, data):
182
+ """Generate response using PandasAI with SmartDataLake"""
183
  llm = GoogleGemini(api_key=gemini_api_key)
184
+ pandas_agent = SmartDataLake(
185
+ data.values(),
186
+ config={
187
+ "llm": llm,
188
+ "response_parser": StreamLitResponse
189
+ }
190
+ )
191
  return pandas_agent.chat(prompt)
192
 
193
+ def handle_userinput(question, data):
194
+ """Handle user input with SmartDataLake"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
  try:
196
+ if data and all(not df.empty for df in data.values()):
 
 
197
  st.session_state.chat_history.append({
198
  "role": "user",
199
  "content": question
200
  })
201
+
202
+ result = generateResponse(question, data)
203
+ # ... [Keep the rest of handle_userinput same as before]
204
  if isinstance(result, dict):
205
  response_type = result.get('type', 'text')
206
  response_value = result.get('value')
 
231
  except Exception as e:
232
  st.error(f"Error processing input: {e}")
233
 
234
+
235
  def main():
236
+ st.set_page_config(page_title="Business Analytics Suite", page_icon="📊", layout="wide")
237
 
238
+ # Initialize session state
239
  if "chat_history" not in st.session_state:
240
  st.session_state.chat_history = []
241
+ if "data" not in st.session_state:
242
+ st.session_state.data = load_data()
243
 
244
+ # Create tabs
245
+ tab_dashboard, tab_chat, tab_reports = st.tabs(["📊 Dashboard", "💬 Chat", "📈 Reports"])
246
 
247
+ # Dashboard Tab
248
+ with tab_dashboard:
249
+ if st.session_state.data:
250
+ create_dashboard(st.session_state.data)
251
+ else:
252
+ st.error("Failed to load data for dashboard")
253
+
254
+ # Chat Tab
255
  with tab_chat:
256
+ st.title("AI Data Analyst")
257
+ # ... [Keep chat interface similar but update handle_userinput calls to use st.session_state.data]
258
  chat_container = st.container()
259
  with chat_container:
260
  for message in st.session_state.chat_history:
 
270
  for message in st.session_state.chat_history:
271
  with st.chat_message(message["role"]):
272
  render_chat_message(message)
273
+ # Reports Tab
 
 
274
  with tab_reports:
275
+ st.title("Custom Reports")
276
+ if st.session_state.data:
277
+ # Suburb Filter
278
+ suburbs = pd.concat([
279
+ st.session_state.data['events']['Surbub'],
280
+ st.session_state.data['customers']['Surburb']
281
+ ]).unique()
282
+ selected_suburbs = st.multiselect("Select Suburbs", suburbs)
283
+
284
+ if st.button("Generate Report"):
285
+ with st.spinner("Analyzing data..."):
286
+ # Prepare filtered data
287
+ filtered_data = {
288
+ 'events': st.session_state.data['events'][
289
+ st.session_state.data['events']['Surbub'].isin(selected_suburbs)
290
+ ] if selected_suburbs else st.session_state.data['events'],
291
+ 'customers': st.session_state.data['customers'][
292
+ st.session_state.data['customers']['Surburb'].isin(selected_suburbs)
293
+ ] if selected_suburbs else st.session_state.data['customers'],
294
+ 'products': st.session_state.data['products']
295
+ }
296
+
297
+ # Convert to JSON
298
+ json_data = {k: v.to_json(orient='records') for k, v in filtered_data.items()}
299
+
300
+ # Generate report
301
  prompt = f"""
302
+ Analyze this business data and generate a comprehensive report with key insights and recommendations.
303
+ Data:
304
+ {json.dumps(json_data, indent=2)}
305
+ """
306
  response = model.generate_content(prompt)
307
  report = response.text
308
+
309
+ # PDF Generation and display
310
+ # ... [Keep the PDF generation code from original]
311
  try:
312
  pdf_bytes = generate_pdf(report) # Use generate_pdf
313
  st.download_button(
 
319
  st.markdown(report) # Display the report below the download button
320
  except Exception as e:
321
  st.error(f"Error generating PDF: {e}")
322
+ st.markdown(report)
323
  else:
324
+ st.error("No data available for reports")
325
 
326
+ # Sidebar
327
  with st.sidebar:
328
+ st.header("Data Management")
329
  if st.button("Reload Data"):
330
+ st.session_state.data = load_data()
 
 
331
  if st.button("Clear Chat"):
332
  st.session_state.chat_history = []
333
+
 
334
  if __name__ == "__main__":
335
  main()