mgbam commited on
Commit
092c2a9
ยท
verified ยท
1 Parent(s): e9cc996

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +44 -47
app.py CHANGED
@@ -1,6 +1,6 @@
1
  # app.py โ€” BizIntel AI Ultra
2
- # Supports: CSV/Excel/DB ingestion, any numeric metric + date, interactive Plotly, Gemini 1.5 Pro,
3
- # KPI cards, optional EDA, safe image writes, and updated use_container_width flag.
4
 
5
  import os
6
  import tempfile
@@ -12,29 +12,29 @@ import google.generativeai as genai
12
  import plotly.graph_objects as go
13
 
14
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
15
- # REDIRECT ALL write_image CALLS TO A WRITABLE TEMP DIRECTORY
16
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
17
- _tmp = tempfile.gettempdir()
18
  _original_write = go.Figure.write_image
19
 
20
  def _safe_write(self, path, *args, **kwargs):
21
- fname = os.path.basename(path)
22
- safe_path = os.path.join(_tmp, fname)
23
  return _original_write(self, safe_path, *args, **kwargs)
24
 
25
  go.Figure.write_image = _safe_write
26
 
27
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
28
- # TOOL IMPORTS (updated generic versions)
29
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
30
  from tools.csv_parser import parse_csv_tool
31
- from tools.plot_generator import plot_metric_tool # date_col, metric_col
32
- from tools.forecaster import forecast_metric_tool # date_col, metric_col
33
  from tools.visuals import histogram_tool, scatter_matrix_tool, corr_heatmap_tool
34
  from db_connector import fetch_data_from_db, list_tables, SUPPORTED_ENGINES
35
 
36
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
37
- # 1. GEMINI 1.5-PRO INITIALIZATION
38
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
39
  genai.configure(api_key=os.getenv("GEMINI_APIKEY"))
40
  gemini = genai.GenerativeModel(
@@ -47,71 +47,70 @@ gemini = genai.GenerativeModel(
47
  )
48
 
49
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
50
- # 2. STREAMLIT PAGE CONFIG
51
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
52
  st.set_page_config(page_title="BizIntel AI Ultra", layout="wide")
53
  st.title("๐Ÿ“Š BizIntel AI Ultra โ€“ Advanced Analytics + Gemini 1.5 Pro")
54
-
55
  TEMP_DIR = tempfile.gettempdir()
56
 
57
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
58
- # 3. DATA SOURCE: CSV / EXCEL / SQL DATABASE
59
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
60
  source = st.radio("Select data source", ["Upload CSV / Excel", "Connect to SQL Database"])
61
- csv_path: str | None = None
62
 
63
  if source == "Upload CSV / Excel":
64
- upload = st.file_uploader("Upload CSV or Excel (โ‰ค 500 MB)", type=["csv", "xlsx", "xls"])
65
  if upload:
66
- temp_path = os.path.join(TEMP_DIR, upload.name)
67
- with open(temp_path, "wb") as f:
68
  f.write(upload.read())
69
 
70
  if upload.name.lower().endswith(".csv"):
71
- csv_path = temp_path
72
  else:
73
  try:
74
- df_xl = pd.read_excel(temp_path, sheet_name=0)
75
- csv_path = os.path.splitext(temp_path)[0] + ".csv"
76
  df_xl.to_csv(csv_path, index=False)
77
  except Exception as e:
78
  st.error(f"Excel parsing failed: {e}")
79
  st.stop()
80
  st.success(f"{upload.name} saved โœ…")
81
 
82
- else: # SQL Database path
83
  engine = st.selectbox("DB engine", SUPPORTED_ENGINES)
84
  conn = st.text_input("SQLAlchemy connection string")
85
  if conn:
86
  try:
87
  tables = list_tables(conn)
88
- table = st.selectbox("Table", tables)
89
  if st.button("Fetch table"):
90
- csv_path = fetch_data_from_db(conn, table)
91
- st.success(f"Fetched **{table}** as CSV โœ…")
92
  except Exception as e:
93
  st.error(f"Connection failed: {e}")
94
  st.stop()
95
 
96
- if csv_path is None:
97
  st.stop()
98
 
99
- # Offer download of the working CSV
100
  with open(csv_path, "rb") as f:
101
  st.download_button("โฌ‡๏ธ Download working CSV", f, file_name=os.path.basename(csv_path))
102
 
103
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
104
- # 4. COLUMN SELECTION: DATE + METRIC
105
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
106
  df_head = pd.read_csv(csv_path, nrows=5)
107
  st.dataframe(df_head)
108
 
109
- date_col = st.selectbox("Select date/time column", df_head.columns)
110
  numeric_cols = df_head.select_dtypes("number").columns.tolist()
111
- metric_col = st.selectbox("Select numeric metric column", numeric_cols)
112
 
113
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
114
- # 5. LOCAL ANALYTICS: SUMMARY, TREND, FORECAST
115
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
116
  with st.spinner("Parsing datasetโ€ฆ"):
117
  summary_text = parse_csv_tool(csv_path)
@@ -119,14 +118,14 @@ with st.spinner("Parsing datasetโ€ฆ"):
119
  with st.spinner("Generating trend chartโ€ฆ"):
120
  trend_fig = plot_metric_tool(csv_path, date_col, metric_col)
121
  if isinstance(trend_fig, go.Figure):
 
122
  st.plotly_chart(trend_fig, use_container_width=True)
123
  else:
124
  st.warning(trend_fig)
125
 
126
- with st.spinner("Forecastingโ€ฆ"):
127
  forecast_text = forecast_metric_tool(csv_path, date_col, metric_col)
128
 
129
- # Display the forecast image saved under /tmp
130
  st.subheader(f"๐Ÿ”ฎ {metric_col} Forecast")
131
  forecast_png = os.path.join(TEMP_DIR, "forecast_plot.png")
132
  if os.path.exists(forecast_png):
@@ -135,7 +134,7 @@ else:
135
  st.warning("Forecast image not found.")
136
 
137
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
138
- # 6. GEMINI STRATEGY RECOMMENDATIONS
139
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
140
  prompt = (
141
  f"You are **BizIntel Strategist AI**.\n\n"
@@ -155,36 +154,34 @@ st.markdown(strategy_md)
155
  st.download_button("โฌ‡๏ธ Download Strategy (.md)", strategy_md, file_name="strategy.md")
156
 
157
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
158
- # 7. KPI CARDS + DETAILED STATS EXPANDER
159
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
160
  full_df = pd.read_csv(csv_path, low_memory=False)
161
  total_rows = len(full_df)
162
- num_cols = len(full_df.columns)
163
  missing_pct = full_df.isna().mean().mean() * 100
164
 
165
  st.markdown("---")
166
  st.subheader("๐Ÿ“‘ Dataset Overview")
167
- col1, col2, col3 = st.columns(3)
168
- col1.metric("Rows", f"{total_rows:,}")
169
- col2.metric("Columns", str(num_cols))
170
- col3.metric("Missing %", f"{missing_pct:.1f}%")
171
 
172
  with st.expander("๐Ÿ”Ž Detailed descriptive statistics"):
173
- stats_df = full_df.describe().T.reset_index().rename(columns={"index": "Feature"})
174
- st.dataframe(
175
- stats_df.style.format(precision=2).background_gradient(cmap="Blues"),
176
- use_container_width=True,
177
- )
178
 
179
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
180
- # 8. OPTIONAL EXPLORATORY VISUALS
181
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
182
  st.markdown("---")
183
  st.subheader("๐Ÿ” Optional Exploratory Visuals")
184
 
185
  if st.checkbox("Histogram"):
186
- hist_col = st.selectbox("Variable", numeric_cols, key="hist")
187
- st.plotly_chart(histogram_tool(csv_path, hist_col), use_container_width=True)
188
 
189
  if st.checkbox("Scatter-matrix"):
190
  sel = st.multiselect("Choose columns", numeric_cols, default=numeric_cols[:3])
 
1
  # app.py โ€” BizIntel AI Ultra
2
+ # Supports: CSV/Excel/DB ingestion, date+metric plotting, ARIMA forecasting,
3
+ # safe Plotly writes, Gemini 1.5 Pro strategy, KPI cards, optional EDA.
4
 
5
  import os
6
  import tempfile
 
12
  import plotly.graph_objects as go
13
 
14
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
15
+ # 0) Redirect all Plotly write_image() into a writable temp dir
16
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
17
+ TMP = tempfile.gettempdir()
18
  _original_write = go.Figure.write_image
19
 
20
  def _safe_write(self, path, *args, **kwargs):
21
+ filename = os.path.basename(path)
22
+ safe_path = os.path.join(TMP, filename)
23
  return _original_write(self, safe_path, *args, **kwargs)
24
 
25
  go.Figure.write_image = _safe_write
26
 
27
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
28
+ # 1) Imports for tools & DB connector
29
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
30
  from tools.csv_parser import parse_csv_tool
31
+ from tools.plot_generator import plot_metric_tool # (csv_path, date_col, metric_col) โ†’ Figure or error
32
+ from tools.forecaster import forecast_metric_tool # (csv_path, date_col, metric_col) โ†’ text + /tmp/forecast_plot.png
33
  from tools.visuals import histogram_tool, scatter_matrix_tool, corr_heatmap_tool
34
  from db_connector import fetch_data_from_db, list_tables, SUPPORTED_ENGINES
35
 
36
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
37
+ # 2) Gemini 1.5 Pro initialization
38
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
39
  genai.configure(api_key=os.getenv("GEMINI_APIKEY"))
40
  gemini = genai.GenerativeModel(
 
47
  )
48
 
49
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
50
+ # 3) Streamlit page setup
51
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
52
  st.set_page_config(page_title="BizIntel AI Ultra", layout="wide")
53
  st.title("๐Ÿ“Š BizIntel AI Ultra โ€“ Advanced Analytics + Gemini 1.5 Pro")
 
54
  TEMP_DIR = tempfile.gettempdir()
55
 
56
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
57
+ # 4) Data source selection: CSV/Excel or SQL Database
58
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
59
  source = st.radio("Select data source", ["Upload CSV / Excel", "Connect to SQL Database"])
60
+ csv_path = None
61
 
62
  if source == "Upload CSV / Excel":
63
+ upload = st.file_uploader("Upload CSV or Excel (โ‰ค 500 MB)", type=["csv","xlsx","xls"])
64
  if upload:
65
+ tmp_file = os.path.join(TEMP_DIR, upload.name)
66
+ with open(tmp_file, "wb") as f:
67
  f.write(upload.read())
68
 
69
  if upload.name.lower().endswith(".csv"):
70
+ csv_path = tmp_file
71
  else:
72
  try:
73
+ df_xl = pd.read_excel(tmp_file, sheet_name=0)
74
+ csv_path = os.path.splitext(tmp_file)[0] + ".csv"
75
  df_xl.to_csv(csv_path, index=False)
76
  except Exception as e:
77
  st.error(f"Excel parsing failed: {e}")
78
  st.stop()
79
  st.success(f"{upload.name} saved โœ…")
80
 
81
+ else:
82
  engine = st.selectbox("DB engine", SUPPORTED_ENGINES)
83
  conn = st.text_input("SQLAlchemy connection string")
84
  if conn:
85
  try:
86
  tables = list_tables(conn)
87
+ tbl = st.selectbox("Table", tables)
88
  if st.button("Fetch table"):
89
+ csv_path = fetch_data_from_db(conn, tbl)
90
+ st.success(f"Fetched **{tbl}** as CSV โœ…")
91
  except Exception as e:
92
  st.error(f"Connection failed: {e}")
93
  st.stop()
94
 
95
+ if not csv_path:
96
  st.stop()
97
 
98
+ # Download the working CSV
99
  with open(csv_path, "rb") as f:
100
  st.download_button("โฌ‡๏ธ Download working CSV", f, file_name=os.path.basename(csv_path))
101
 
102
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
103
+ # 5) Show first rows & let user pick date + numeric metric
104
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
105
  df_head = pd.read_csv(csv_path, nrows=5)
106
  st.dataframe(df_head)
107
 
108
+ date_col = st.selectbox("Select date/time column", df_head.columns)
109
  numeric_cols = df_head.select_dtypes("number").columns.tolist()
110
+ metric_col = st.selectbox("Select numeric metric column", numeric_cols)
111
 
112
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
113
+ # 6) Local analysis: summary, trend chart, forecast
114
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
115
  with st.spinner("Parsing datasetโ€ฆ"):
116
  summary_text = parse_csv_tool(csv_path)
 
118
  with st.spinner("Generating trend chartโ€ฆ"):
119
  trend_fig = plot_metric_tool(csv_path, date_col, metric_col)
120
  if isinstance(trend_fig, go.Figure):
121
+ st.subheader("๐Ÿ“ˆ Trend")
122
  st.plotly_chart(trend_fig, use_container_width=True)
123
  else:
124
  st.warning(trend_fig)
125
 
126
+ with st.spinner("Running forecastโ€ฆ"):
127
  forecast_text = forecast_metric_tool(csv_path, date_col, metric_col)
128
 
 
129
  st.subheader(f"๐Ÿ”ฎ {metric_col} Forecast")
130
  forecast_png = os.path.join(TEMP_DIR, "forecast_plot.png")
131
  if os.path.exists(forecast_png):
 
134
  st.warning("Forecast image not found.")
135
 
136
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
137
+ # 7) Gemini-driven strategy recommendations
138
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
139
  prompt = (
140
  f"You are **BizIntel Strategist AI**.\n\n"
 
154
  st.download_button("โฌ‡๏ธ Download Strategy (.md)", strategy_md, file_name="strategy.md")
155
 
156
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
157
+ # 8) KPI cards + detailed Stats
158
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
159
  full_df = pd.read_csv(csv_path, low_memory=False)
160
  total_rows = len(full_df)
161
+ num_cols = full_df.shape[1]
162
  missing_pct = full_df.isna().mean().mean() * 100
163
 
164
  st.markdown("---")
165
  st.subheader("๐Ÿ“‘ Dataset Overview")
166
+ c1, c2, c3 = st.columns(3)
167
+ c1.metric("Rows", f"{total_rows:,}")
168
+ c2.metric("Columns", str(num_cols))
169
+ c3.metric("Missing %", f"{missing_pct:.1f}%")
170
 
171
  with st.expander("๐Ÿ”Ž Detailed descriptive statistics"):
172
+ stats_df = full_df.describe().T.reset_index().rename(columns={"index":"Feature"})
173
+ st.dataframe(stats_df.style.format(precision=2).background_gradient(cmap="Blues"),
174
+ use_container_width=True)
 
 
175
 
176
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
177
+ # 9) Optional Exploratory Visuals
178
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
179
  st.markdown("---")
180
  st.subheader("๐Ÿ” Optional Exploratory Visuals")
181
 
182
  if st.checkbox("Histogram"):
183
+ hcol = st.selectbox("Variable", numeric_cols, key="hist")
184
+ st.plotly_chart(histogram_tool(csv_path, hcol), use_container_width=True)
185
 
186
  if st.checkbox("Scatter-matrix"):
187
  sel = st.multiselect("Choose columns", numeric_cols, default=numeric_cols[:3])