mgbam commited on
Commit
221fe0a
ยท
verified ยท
1 Parent(s): 9414ba2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +80 -50
app.py CHANGED
@@ -1,4 +1,4 @@
1
- # app.py โ€” BizIntelย AIย Ultraย (Any metric, CSV/Excel/DB, Plotly, Geminiย 1.5โ€ฏPro)
2
 
3
  import os
4
  import tempfile
@@ -9,11 +9,32 @@ import streamlit as st
9
  import google.generativeai as genai
10
  import plotly.graph_objects as go
11
 
12
- from tools.csv_parser import parse_csv_tool
13
- from tools.plot_generator import plot_metric_tool # NEW generic
14
- from tools.forecaster import forecast_metric_tool # NEW generic
15
- from tools.visuals import histogram_tool, scatter_matrix_tool, corr_heatmap_tool
16
- from db_connector import fetch_data_from_db, list_tables, SUPPORTED_ENGINES
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
19
  # 1. GEMINI CONFIG
@@ -21,55 +42,58 @@ from db_connector import fetch_data_from_db, list_tables, SUPPORTED_ENG
21
  genai.configure(api_key=os.getenv("GEMINI_APIKEY"))
22
  gemini = genai.GenerativeModel(
23
  "gemini-1.5-pro-latest",
24
- generation_config={"temperature": 0.7, "top_p": 0.9, "response_mime_type": "text/plain"},
 
 
 
 
25
  )
26
 
27
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
28
- # 2. PAGE CONFIG
29
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
30
- st.set_page_config(page_title="BizIntelย AIย Ultra", layout="wide")
31
- st.title("๐Ÿ“Š BizIntelย AIย Ultraย โ€“ Advanced Analytics + Geminiย 1.5ย Pro")
32
 
33
  TEMP_DIR = tempfile.gettempdir()
34
 
35
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
36
- # 3. DATA SOURCE (CSV, Excel, or DB)
37
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
38
- src = st.radio("Select data source", ["Upload CSV / Excel", "Connect to SQL Database"])
39
  csv_path: str | None = None
40
- file_kind: Literal["csv", "excel"] | None = None
41
 
42
- if src == "Upload CSV / Excel":
43
- up = st.file_uploader("Upload CSV or Excel (โ‰คโ€ฏ500โ€ฏMB)", type=["csv", "xlsx", "xls"])
44
  if up:
45
  temp_path = os.path.join(TEMP_DIR, up.name)
46
  with open(temp_path, "wb") as f:
47
  f.write(up.read())
48
 
49
- if up.name.lower().endswith("csv"):
50
- csv_path, file_kind = temp_path, "csv"
51
- else: # Excel โ†’ convert first sheet to CSV
 
52
  try:
53
  df_xl = pd.read_excel(temp_path, sheet_name=0)
54
  csv_path = os.path.splitext(temp_path)[0] + ".csv"
55
  df_xl.to_csv(csv_path, index=False)
56
- file_kind = "excel"
57
  except Exception as e:
58
  st.error(f"Excel parsing failed: {e}")
59
  st.stop()
 
60
  st.success(f"{up.name} saved โœ…")
61
 
62
- else: # SQL DB
63
  engine = st.selectbox("DB engine", SUPPORTED_ENGINES)
64
  conn = st.text_input("SQLAlchemy connection string")
65
  if conn:
66
  try:
67
- tbls = list_tables(conn)
68
- tbl = st.selectbox("Table", tbls)
69
  if st.button("Fetch table"):
70
- csv_path = fetch_data_from_db(conn, tbl)
71
- file_kind = "csv"
72
- st.success(f"Fetched **{tbl}** as CSV โœ…")
73
  except Exception as e:
74
  st.error(f"Connection failed: {e}")
75
  st.stop()
@@ -78,60 +102,66 @@ if csv_path is None:
78
  st.stop()
79
 
80
  with open(csv_path, "rb") as f:
81
- st.download_button("โฌ‡๏ธย Download working CSV", f, file_name=os.path.basename(csv_path))
82
 
83
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
84
- # 4. COLUMN PICKERS
85
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
86
  df_head = pd.read_csv(csv_path, nrows=5)
87
  st.dataframe(df_head)
88
 
89
- date_col = st.selectbox("Select date/time column", df_head.columns)
90
  numeric_cols = df_head.select_dtypes("number").columns
91
- metric_col = st.selectbox("Select numeric metric column", numeric_cols)
92
 
93
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
94
- # 5. LOCAL TOOLS (TREND + FORECAST)
95
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
96
  with st.spinner("Parsing datasetโ€ฆ"):
97
  summary_text = parse_csv_tool(csv_path)
98
 
99
- with st.spinner("๐Ÿ“ˆ Building trend chartโ€ฆ"):
100
  trend_fig = plot_metric_tool(csv_path, date_col, metric_col)
101
  if isinstance(trend_fig, go.Figure):
102
  st.plotly_chart(trend_fig, use_container_width=True)
103
  else:
104
  st.warning(trend_fig)
105
 
106
- with st.spinner("๐Ÿ”ฎ Forecastingโ€ฆ"):
107
  forecast_text = forecast_metric_tool(csv_path, date_col, metric_col)
108
- forecast_png = "forecast_plot.png" if os.path.exists("forecast_plot.png") else None
109
 
110
- if forecast_png:
111
- st.image(forecast_png, caption=f"{metric_col} Forecast", use_column_width=True)
 
 
 
 
 
 
 
112
 
113
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
114
- # 6. GEMINI INSIGHTS
115
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
116
  prompt = (
117
  f"You are **BizIntel Strategist AI**.\n\n"
118
  f"### Dataset Summary\n```\n{summary_text}\n```\n\n"
119
  f"### {metric_col} Forecast\n```\n{forecast_text}\n```\n\n"
120
- "Deliver **Markdown** with:\n"
121
- f"1. Five key insights focused on **{metric_col}**\n"
122
- "2. Three actionable strategies (impactโ€‘oriented)\n"
123
  "3. Risk factors or anomalies\n"
124
  "4. Suggested additional visuals\n"
125
  )
126
 
127
- st.subheader("๐Ÿš€ Strategy Recommendations (Geminiย 1.5ย Pro)")
128
  with st.spinner("Generating insightsโ€ฆ"):
129
  strategy_md = gemini.generate_content(prompt).text
130
  st.markdown(strategy_md)
131
- st.download_button("๏ฟฝ๏ฟฝ๏ฟฝ๏ธย Download Strategy (.md)", strategy_md, file_name="strategy.md")
132
 
133
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
134
- # 7. KPI CARDS + STAT EXPANDER
135
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
136
  full_df = pd.read_csv(csv_path, low_memory=False)
137
  total_rows = len(full_df)
@@ -141,11 +171,11 @@ missing_pct = full_df.isna().mean().mean() * 100
141
  st.markdown("---")
142
  st.subheader("๐Ÿ“‘ Dataset Overview")
143
  c1, c2, c3 = st.columns(3)
144
- c1.metric("Rows", f"{total_rows:,}")
145
- c2.metric("Columns", str(num_cols))
146
- c3.metric("Missingย %", f"{missing_pct:.1f}%")
147
 
148
- with st.expander("๐Ÿ”Žย Detailed descriptive statistics"):
149
  stats_df = full_df.describe().T.reset_index().rename(columns={"index": "Feature"})
150
  st.dataframe(
151
  stats_df.style.format(precision=2).background_gradient(cmap="Blues"),
@@ -159,13 +189,13 @@ st.markdown("---")
159
  st.subheader("๐Ÿ” Optional Exploratory Visuals")
160
 
161
  if st.checkbox("Histogram"):
162
- hist_col = st.selectbox("Variable", numeric_cols, key="hist")
163
- st.plotly_chart(histogram_tool(csv_path, hist_col), use_container_width=True)
164
 
165
- if st.checkbox("Scatterโ€‘matrix"):
166
  sel = st.multiselect("Choose columns", numeric_cols, default=numeric_cols[:3])
167
  if sel:
168
  st.plotly_chart(scatter_matrix_tool(csv_path, sel), use_container_width=True)
169
 
170
- if st.checkbox("Correlation heatโ€‘map"):
171
  st.plotly_chart(corr_heatmap_tool(csv_path), use_container_width=True)
 
1
+ # app.py โ€” BizIntel AI Ultra (Any metric, CSV/Excel/DB, Plotly, Gemini 1.5 Pro)
2
 
3
  import os
4
  import tempfile
 
9
  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
 
42
  genai.configure(api_key=os.getenv("GEMINI_APIKEY"))
43
  gemini = genai.GenerativeModel(
44
  "gemini-1.5-pro-latest",
45
+ generation_config={
46
+ "temperature": 0.7,
47
+ "top_p": 0.9,
48
+ "response_mime_type": "text/plain",
49
+ },
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")
57
 
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"
80
  df_xl.to_csv(csv_path, index=False)
 
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:
91
  try:
92
+ tables = list_tables(conn)
93
+ table = st.selectbox("Table", tables)
94
  if st.button("Fetch table"):
95
+ csv_path = fetch_data_from_db(conn, table)
96
+ st.success(f"Fetched **{table}** as CSV โœ…")
 
97
  except Exception as e:
98
  st.error(f"Connection failed: {e}")
99
  st.stop()
 
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
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
118
+ # 5. LOCAL ANALYTICS: SUMMARY, TREND, FORECAST
119
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
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)
127
  else:
128
  st.warning(trend_fig)
129
 
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"
148
  f"### Dataset Summary\n```\n{summary_text}\n```\n\n"
149
  f"### {metric_col} Forecast\n```\n{forecast_text}\n```\n\n"
150
+ "Return **Markdown** with:\n"
151
+ "1. Five key insights\n"
152
+ "2. Three actionable strategies\n"
153
  "3. Risk factors or anomalies\n"
154
  "4. Suggested additional visuals\n"
155
  )
156
 
157
+ st.subheader("๐Ÿš€ Strategy Recommendations (Gemini 1.5 Pro)")
158
  with st.spinner("Generating insightsโ€ฆ"):
159
  strategy_md = gemini.generate_content(prompt).text
160
  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)
 
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"})
180
  st.dataframe(
181
  stats_df.style.format(precision=2).background_gradient(cmap="Blues"),
 
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])
197
  if sel:
198
  st.plotly_chart(scatter_matrix_tool(csv_path, sel), use_container_width=True)
199
 
200
+ if st.checkbox("Correlation heat-map"):
201
  st.plotly_chart(corr_heatmap_tool(csv_path), use_container_width=True)