Elena-Berutti1 commited on
Commit
9abfcb5
Β·
verified Β·
1 Parent(s): efebd10

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +101 -54
app.py CHANGED
@@ -197,13 +197,34 @@ def on_table_select(choice: str):
197
  # =========================================================
198
 
199
  def load_kpis() -> Dict[str, Any]:
200
- for candidate in [PY_TAB_DIR / "kpis.json", PY_FIG_DIR / "kpis.json"]:
201
- if candidate.exists():
202
- try:
203
- return _read_json(candidate)
204
- except Exception:
205
- pass
206
- return {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
 
208
 
209
  # =========================================================
@@ -465,10 +486,10 @@ def render_kpi_cards() -> str:
465
  </div>"""
466
 
467
  kpi_config = [
468
- ("n_titles", "πŸ“š", "Book Titles", "#a48de8"),
469
- ("n_months", "πŸ“…", "Time Periods", "#7aa6f8"),
470
- ("total_units_sold", "πŸ“¦", "Units Sold", "#6ee7c7"),
471
- ("total_revenue", "πŸ’°", "Revenue", "#3dcba8"),
472
  ]
473
 
474
  html = (
@@ -532,74 +553,100 @@ def _empty_chart(title: str) -> go.Figure:
532
 
533
 
534
  def build_sales_chart() -> go.Figure:
535
- path = PY_TAB_DIR / "df_dashboard.csv"
536
  if not path.exists():
537
  return _empty_chart("Sales Trends β€” run the pipeline first")
 
538
  df = pd.read_csv(path)
539
- date_col = next((c for c in df.columns if "month" in c.lower() or "date" in c.lower()), None)
540
- val_cols = [c for c in df.columns if c != date_col and df[c].dtype in ("float64", "int64")]
541
- if not date_col or not val_cols:
542
- return _empty_chart("Could not auto-detect columns in df_dashboard.csv")
543
- df[date_col] = pd.to_datetime(df[date_col], errors="coerce")
 
544
  fig = go.Figure()
545
- for i, col in enumerate(val_cols):
546
- fig.add_trace(go.Scatter(
547
- x=df[date_col], y=df[col], name=col.replace("_", " ").title(),
548
- mode="lines+markers", line=dict(color=CHART_PALETTE[i % len(CHART_PALETTE)], width=2),
549
- marker=dict(size=4),
550
- hovertemplate=f"<b>{col.replace('_',' ').title()}</b><br>%{{x|%b %Y}}: %{{y:,.0f}}<extra></extra>",
551
- ))
552
- fig.update_layout(**_styled_layout(height=450, hovermode="x unified",
553
- title=dict(text="Monthly Overview")))
 
 
 
 
 
 
554
  fig.update_xaxes(gridcolor="rgba(124,92,191,0.15)", showgrid=True)
555
- fig.update_yaxes(gridcolor="rgba(124,92,191,0.15)", showgrid=True)
556
  return fig
557
 
558
 
559
  def build_sentiment_chart() -> go.Figure:
560
- path = PY_TAB_DIR / "sentiment_counts_sampled.csv"
561
  if not path.exists():
562
  return _empty_chart("Sentiment Distribution β€” run the pipeline first")
 
563
  df = pd.read_csv(path)
564
- title_col = df.columns[0]
565
- sent_cols = [c for c in ["negative", "neutral", "positive"] if c in df.columns]
566
- if not sent_cols:
567
- return _empty_chart("No sentiment columns found in CSV")
568
- colors = {"negative": "#e8537a", "neutral": "#5e8fef", "positive": "#2ec4a0"}
569
- fig = go.Figure()
570
- for col in sent_cols:
571
- fig.add_trace(go.Bar(
572
- name=col.title(), y=df[title_col], x=df[col],
573
- orientation="h", marker_color=colors.get(col, "#888"),
574
- hovertemplate=f"<b>{col.title()}</b>: %{{x}}<extra></extra>",
575
- ))
 
 
 
 
 
 
 
 
576
  fig.update_layout(**_styled_layout(
577
- height=max(400, len(df) * 28), barmode="stack",
578
- title=dict(text="Sentiment Distribution by Book"),
 
579
  ))
580
- fig.update_xaxes(title="Number of Reviews")
581
- fig.update_yaxes(autorange="reversed")
582
  return fig
583
 
584
 
585
  def build_top_sellers_chart() -> go.Figure:
586
- path = PY_TAB_DIR / "top_titles_by_units_sold.csv"
587
  if not path.exists():
588
- return _empty_chart("Top Sellers β€” run the pipeline first")
589
- df = pd.read_csv(path).head(15)
590
- title_col = next((c for c in df.columns if "title" in c.lower()), df.columns[0])
591
- val_col = next((c for c in df.columns if "unit" in c.lower() or "sold" in c.lower()), df.columns[-1])
 
 
 
 
592
  fig = go.Figure(go.Bar(
593
- y=df[title_col], x=df[val_col], orientation="h",
594
- marker=dict(color=df[val_col], colorscale=[[0, "#c5b4f0"], [1, "#7c5cbf"]]),
595
- hovertemplate="<b>%{y}</b><br>Units: %{x:,.0f}<extra></extra>",
 
 
596
  ))
 
597
  fig.update_layout(**_styled_layout(
598
  height=max(400, len(df) * 30),
599
- title=dict(text="Top Selling Titles"), showlegend=False,
 
600
  ))
601
  fig.update_yaxes(autorange="reversed")
602
- fig.update_xaxes(title="Total Units Sold")
603
  return fig
604
 
605
 
 
197
  # =========================================================
198
 
199
  def load_kpis() -> Dict[str, Any]:
200
+ try:
201
+ summary_path = BASE_DIR / "menu_item_summary.csv"
202
+ sales_path = BASE_DIR / "monthly_sales.csv"
203
+ final_path = BASE_DIR / "final_menu_recommendations.csv"
204
+
205
+ if not summary_path.exists() or not sales_path.exists():
206
+ return {}
207
+
208
+ summary_df = pd.read_csv(summary_path)
209
+ sales_df = pd.read_csv(sales_path)
210
+
211
+ kpis = {
212
+ "n_menu_items": int(summary_df["menu_item"].nunique()) if "menu_item" in summary_df.columns else 0,
213
+ "n_months": int(sales_df["month"].nunique()) if "month" in sales_df.columns else 0,
214
+ "total_orders": float(sales_df["orders"].sum()) if "orders" in sales_df.columns else 0,
215
+ "total_revenue": float(sales_df["revenue"].sum()) if "revenue" in sales_df.columns else 0,
216
+ }
217
+
218
+ if final_path.exists():
219
+ final_df = pd.read_csv(final_path)
220
+ if "recommended_action" in final_df.columns:
221
+ counts = final_df["recommended_action"].value_counts().to_dict()
222
+ for k, v in counts.items():
223
+ kpis[f"action_{str(k).lower()}"] = int(v)
224
+
225
+ return kpis
226
+ except Exception:
227
+ return {}
228
 
229
 
230
  # =========================================================
 
486
  </div>"""
487
 
488
  kpi_config = [
489
+ ("n_menu_items", "🍝", "Menu Items", "#a48de8"),
490
+ ("n_months", "πŸ“…", "Months", "#7aa6f8"),
491
+ ("total_orders", "🧾", "Total Orders", "#6ee7c7"),
492
+ ("total_revenue", "πŸ’°", "Revenue", "#3dcba8"),
493
  ]
494
 
495
  html = (
 
553
 
554
 
555
  def build_sales_chart() -> go.Figure:
556
+ path = BASE_DIR / "monthly_sales.csv"
557
  if not path.exists():
558
  return _empty_chart("Sales Trends β€” run the pipeline first")
559
+
560
  df = pd.read_csv(path)
561
+ if "month" not in df.columns or "revenue" not in df.columns:
562
+ return _empty_chart("monthly_sales.csv is missing required columns")
563
+
564
+ monthly = df.groupby("month", as_index=False)["revenue"].sum()
565
+ monthly["month"] = pd.to_datetime(monthly["month"], errors="coerce")
566
+
567
  fig = go.Figure()
568
+ fig.add_trace(go.Scatter(
569
+ x=monthly["month"],
570
+ y=monthly["revenue"],
571
+ mode="lines+markers",
572
+ name="Revenue",
573
+ line=dict(color=CHART_PALETTE[0], width=3),
574
+ marker=dict(size=6),
575
+ hovertemplate="<b>Revenue</b><br>%{x|%b %Y}: %{y:,.2f}<extra></extra>",
576
+ ))
577
+
578
+ fig.update_layout(**_styled_layout(
579
+ height=450,
580
+ hovermode="x unified",
581
+ title=dict(text="Monthly Revenue Trend"),
582
+ ))
583
  fig.update_xaxes(gridcolor="rgba(124,92,191,0.15)", showgrid=True)
584
+ fig.update_yaxes(title="Revenue", gridcolor="rgba(124,92,191,0.15)", showgrid=True)
585
  return fig
586
 
587
 
588
  def build_sentiment_chart() -> go.Figure:
589
+ path = BASE_DIR / "reviews.csv"
590
  if not path.exists():
591
  return _empty_chart("Sentiment Distribution β€” run the pipeline first")
592
+
593
  df = pd.read_csv(path)
594
+ if "rating" not in df.columns:
595
+ return _empty_chart("reviews.csv is missing the rating column")
596
+
597
+ def label_sentiment(x):
598
+ if x >= 4:
599
+ return "Positive"
600
+ elif x == 3:
601
+ return "Neutral"
602
+ return "Negative"
603
+
604
+ df["sentiment"] = df["rating"].apply(label_sentiment)
605
+ counts = df["sentiment"].value_counts().reindex(["Negative", "Neutral", "Positive"], fill_value=0)
606
+
607
+ fig = go.Figure(go.Bar(
608
+ x=counts.index,
609
+ y=counts.values,
610
+ marker_color=["#e8537a", "#5e8fef", "#2ec4a0"],
611
+ hovertemplate="<b>%{x}</b><br>Count: %{y}<extra></extra>",
612
+ ))
613
+
614
  fig.update_layout(**_styled_layout(
615
+ height=420,
616
+ title=dict(text="Review Sentiment Distribution"),
617
+ showlegend=False,
618
  ))
619
+ fig.update_xaxes(title="Sentiment")
620
+ fig.update_yaxes(title="Number of Reviews")
621
  return fig
622
 
623
 
624
  def build_top_sellers_chart() -> go.Figure:
625
+ path = BASE_DIR / "final_menu_recommendations.csv"
626
  if not path.exists():
627
+ return _empty_chart("Top Menu Items β€” run the pipeline first")
628
+
629
+ df = pd.read_csv(path)
630
+ if "menu_item" not in df.columns or "total_orders" not in df.columns:
631
+ return _empty_chart("final_menu_recommendations.csv is missing required columns")
632
+
633
+ df = df.sort_values("total_orders", ascending=False).head(10)
634
+
635
  fig = go.Figure(go.Bar(
636
+ y=df["menu_item"],
637
+ x=df["total_orders"],
638
+ orientation="h",
639
+ marker=dict(color=df["total_orders"], colorscale=[[0, "#c5b4f0"], [1, "#7c5cbf"]]),
640
+ hovertemplate="<b>%{y}</b><br>Total Orders: %{x}<extra></extra>",
641
  ))
642
+
643
  fig.update_layout(**_styled_layout(
644
  height=max(400, len(df) * 30),
645
+ title=dict(text="Top Menu Items by Orders"),
646
+ showlegend=False,
647
  ))
648
  fig.update_yaxes(autorange="reversed")
649
+ fig.update_xaxes(title="Total Orders")
650
  return fig
651
 
652