mgbam commited on
Commit
49d873b
ยท
verified ยท
1 Parent(s): 221fe0a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +40 -46
app.py CHANGED
@@ -1,4 +1,6 @@
1
- # app.py โ€” BizIntel AI Ultra (Any metric, CSV/Excel/DB, Plotly, Gemini 1.5 Pro)
 
 
2
 
3
  import os
4
  import tempfile
@@ -10,34 +12,29 @@ import google.generativeai as genai
10
  import plotly.graph_objects as go
11
 
12
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
13
- # SAFELY REDIRECT ALL write_image CALLS TO /tmp
14
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
15
  _tmp = tempfile.gettempdir()
16
- _orig_write = go.Figure.write_image
17
 
18
  def _safe_write(self, path, *args, **kwargs):
19
- # keep only filename, write into tempdir
20
  fname = os.path.basename(path)
21
  safe_path = os.path.join(_tmp, fname)
22
- return _orig_write(self, safe_path, *args, **kwargs)
23
 
24
  go.Figure.write_image = _safe_write
25
 
26
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
27
- # TOOL IMPORTS
28
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
29
- from tools.csv_parser import parse_csv_tool
30
- from tools.plot_generator import plot_metric_tool # generic: date + metric
31
- from tools.forecaster import forecast_metric_tool # generic: date + metric
32
- from tools.visuals import (
33
- histogram_tool,
34
- scatter_matrix_tool,
35
- corr_heatmap_tool,
36
- )
37
- from db_connector import fetch_data_from_db, list_tables, SUPPORTED_ENGINES
38
 
39
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
40
- # 1. GEMINI CONFIG
41
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
42
  genai.configure(api_key=os.getenv("GEMINI_APIKEY"))
43
  gemini = genai.GenerativeModel(
@@ -50,7 +47,7 @@ gemini = genai.GenerativeModel(
50
  )
51
 
52
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
53
- # 2. PAGE SETUP
54
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
55
  st.set_page_config(page_title="BizIntel AI Ultra", layout="wide")
56
  st.title("๐Ÿ“Š BizIntel AI Ultra โ€“ Advanced Analytics + Gemini 1.5 Pro")
@@ -58,22 +55,21 @@ st.title("๐Ÿ“Š BizIntel AI Ultra โ€“ Advanced Analytics + Gemini 1.5 Pro")
58
  TEMP_DIR = tempfile.gettempdir()
59
 
60
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
61
- # 3. DATA SOURCE (CSV, Excel, or DB)
62
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
63
  source = st.radio("Select data source", ["Upload CSV / Excel", "Connect to SQL Database"])
64
  csv_path: str | None = None
65
 
66
  if source == "Upload CSV / Excel":
67
- up = st.file_uploader("Upload CSV or Excel (โ‰ค 500 MB)", type=["csv", "xlsx", "xls"])
68
- if up:
69
- temp_path = os.path.join(TEMP_DIR, up.name)
70
  with open(temp_path, "wb") as f:
71
- f.write(up.read())
72
 
73
- if up.name.lower().endswith(".csv"):
74
  csv_path = temp_path
75
  else:
76
- # Excel โ†’ load sheet0 โ†’ write out to CSV
77
  try:
78
  df_xl = pd.read_excel(temp_path, sheet_name=0)
79
  csv_path = os.path.splitext(temp_path)[0] + ".csv"
@@ -81,10 +77,9 @@ if source == "Upload CSV / Excel":
81
  except Exception as e:
82
  st.error(f"Excel parsing failed: {e}")
83
  st.stop()
 
84
 
85
- st.success(f"{up.name} saved โœ…")
86
-
87
- else:
88
  engine = st.selectbox("DB engine", SUPPORTED_ENGINES)
89
  conn = st.text_input("SQLAlchemy connection string")
90
  if conn:
@@ -101,17 +96,18 @@ else:
101
  if csv_path is None:
102
  st.stop()
103
 
 
104
  with open(csv_path, "rb") as f:
105
  st.download_button("โฌ‡๏ธ Download working CSV", f, file_name=os.path.basename(csv_path))
106
 
107
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
108
- # 4. COLUMN SELECTION
109
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
110
  df_head = pd.read_csv(csv_path, nrows=5)
111
  st.dataframe(df_head)
112
 
113
  date_col = st.selectbox("Select date/time column", df_head.columns)
114
- numeric_cols = df_head.select_dtypes("number").columns
115
  metric_col = st.selectbox("Select numeric metric column", numeric_cols)
116
 
117
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
@@ -120,7 +116,7 @@ metric_col = st.selectbox("Select numeric metric column", numeric_cols)
120
  with st.spinner("Parsing datasetโ€ฆ"):
121
  summary_text = parse_csv_tool(csv_path)
122
 
123
- with st.spinner("Building trend chartโ€ฆ"):
124
  trend_fig = plot_metric_tool(csv_path, date_col, metric_col)
125
  if isinstance(trend_fig, go.Figure):
126
  st.plotly_chart(trend_fig, use_container_width=True)
@@ -130,18 +126,16 @@ else:
130
  with st.spinner("Forecastingโ€ฆ"):
131
  forecast_text = forecast_metric_tool(csv_path, date_col, metric_col)
132
 
133
- # Show forecast interactive (PNG saved safely in /tmp)
134
  st.subheader(f"๐Ÿ”ฎ {metric_col} Forecast")
135
- with st.spinner("Rendering forecastโ€ฆ"):
136
- # read PNG from tempdir if exists
137
- png_path = os.path.join(TEMP_DIR, "forecast_plot.png")
138
- if os.path.exists(png_path):
139
- st.image(png_path, use_column_width=True)
140
- else:
141
- st.warning("Forecast image not found.")
142
 
143
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
144
- # 6. GEMINI STRATEGY
145
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
146
  prompt = (
147
  f"You are **BizIntel Strategist AI**.\n\n"
@@ -161,7 +155,7 @@ st.markdown(strategy_md)
161
  st.download_button("โฌ‡๏ธ Download Strategy (.md)", strategy_md, file_name="strategy.md")
162
 
163
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
164
- # 7. KPI CARDS + DETAILED STATS
165
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
166
  full_df = pd.read_csv(csv_path, low_memory=False)
167
  total_rows = len(full_df)
@@ -170,10 +164,10 @@ missing_pct = full_df.isna().mean().mean() * 100
170
 
171
  st.markdown("---")
172
  st.subheader("๐Ÿ“‘ Dataset Overview")
173
- c1, c2, c3 = st.columns(3)
174
- c1.metric("Rows", f"{total_rows:,}")
175
- c2.metric("Columns", str(num_cols))
176
- c3.metric("Missing %", f"{missing_pct:.1f}%")
177
 
178
  with st.expander("๐Ÿ”Ž Detailed descriptive statistics"):
179
  stats_df = full_df.describe().T.reset_index().rename(columns={"index": "Feature"})
@@ -189,8 +183,8 @@ st.markdown("---")
189
  st.subheader("๐Ÿ” Optional Exploratory Visuals")
190
 
191
  if st.checkbox("Histogram"):
192
- hcol = st.selectbox("Variable", numeric_cols, key="hist")
193
- st.plotly_chart(histogram_tool(csv_path, hcol), use_container_width=True)
194
 
195
  if st.checkbox("Scatter-matrix"):
196
  sel = st.multiselect("Choose columns", numeric_cols, default=numeric_cols[:3])
 
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
  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
  )
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")
 
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"
 
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:
 
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
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
 
116
  with st.spinner("Parsing datasetโ€ฆ"):
117
  summary_text = parse_csv_tool(csv_path)
118
 
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)
 
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):
133
+ st.image(forecast_png, use_container_width=True)
134
+ 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
  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)
 
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"})
 
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])