import streamlit as st import pandas as pd import plotly.express as px from io import StringIO from datetime import date # ------------------------------- # Helpers # ------------------------------- def format_rs(amount): """Format numeric amount into Rupee string with thousands separators.""" try: # show no decimals for rupee amounts return f"Rs {int(round(float(amount))):,}" except Exception: return str(amount) def ensure_numeric_amount(col): """Convert amount column to numeric (int) safely.""" return pd.to_numeric(col, errors="coerce").fillna(0).astype(int) # ------------------------------- # Page config & CSS # ------------------------------- st.set_page_config(page_title="💸 Expensive Tracker", page_icon="💳", layout="centered") st.markdown( """ """, unsafe_allow_html=True, ) st.title("💸 Expensive Tracker") st.caption("Track expenses in Rupees (Rs). Enter whole numbers like 100, 500, 10000.") # ------------------------------- # Initialize in-memory storage # ------------------------------- if "expenses" not in st.session_state: # columns: Date, Category, Amount, Notes st.session_state.expenses = pd.DataFrame( columns=["Date", "Category", "Amount", "Notes"] ) # Ensure Amount column numeric if loaded previously if not st.session_state.expenses.empty: st.session_state.expenses["Amount"] = ensure_numeric_amount(st.session_state.expenses["Amount"]) # ------------------------------- # Sidebar navigation # ------------------------------- st.sidebar.header("⚙️ Menu") page = st.sidebar.radio("Choose view", ["Add Expense", "View Expenses", "Summary", "Import / Export"]) # Common categories CATEGORIES = ["Food", "Travel", "Shopping", "Bills", "Entertainment", "Health", "Other"] # ------------------------------- # Add Expense # ------------------------------- if page == "Add Expense": st.header("Add a new expense (Amount in Rs)") with st.form("add_expense_form", clear_on_submit=True): c1, c2, c3 = st.columns([1, 1, 1]) with c1: exp_date = st.date_input("Date", value=date.today()) with c2: category = st.selectbox("Category", options=CATEGORIES) with c3: # Integer rupee input amount = st.number_input("Amount (Rs)", min_value=0, step=1, format="%d", value=0) notes = st.text_area("Notes (optional)", max_chars=200, placeholder="Where/what for?") submitted = st.form_submit_button("➕ Add Expense") if submitted: new_row = { "Date": pd.to_datetime(exp_date).date(), "Category": category, "Amount": int(amount), "Notes": notes } st.session_state.expenses = pd.concat([st.session_state.expenses, pd.DataFrame([new_row])], ignore_index=True) st.success(f"Expense added ✅ {format_rs(amount)}") st.balloons() if not st.session_state.expenses.empty: st.markdown("**Quick preview of latest expenses**") preview = st.session_state.expenses.tail(6).reset_index(drop=True).copy() # Format Amount column for display preview["Amount (Rs)"] = preview["Amount"].apply(format_rs) st.dataframe(preview[["Date", "Category", "Amount (Rs)", "Notes"]]) # ------------------------------- # View Expenses # ------------------------------- elif page == "View Expenses": st.header("All Expenses (Amounts in Rs)") if st.session_state.expenses.empty: st.info("No expenses yet — add some from the 'Add Expense' tab.") else: df = st.session_state.expenses.copy() df["Amount"] = ensure_numeric_amount(df["Amount"]) # Allow filtering st.markdown("Filter") cols = st.columns([1, 1, 1]) with cols[0]: min_date = st.date_input("From", value=pd.to_datetime(df["Date"]).min().date()) with cols[1]: max_date = st.date_input("To", value=pd.to_datetime(df["Date"]).max().date()) with cols[2]: sel_cat = st.multiselect("Category", options=["All"] + CATEGORIES, default=["All"]) filtered = df[ (pd.to_datetime(df["Date"]) >= pd.to_datetime(min_date)) & (pd.to_datetime(df["Date"]) <= pd.to_datetime(max_date)) ] if sel_cat and "All" not in sel_cat: filtered = filtered[filtered["Category"].isin(sel_cat)] display_df = filtered.sort_values(by="Date", ascending=False).reset_index(drop=True).copy() display_df["Amount (Rs)"] = display_df["Amount"].apply(format_rs) st.dataframe(display_df[["Date", "Category", "Amount (Rs)", "Notes"]]) # Option to delete last entry or clear all st.markdown("---") cdel, cclear = st.columns(2) with cdel: if st.button("🗑️ Delete last entry"): st.session_state.expenses = st.session_state.expenses[:-1].reset_index(drop=True) st.success("Last entry removed.") with cclear: if st.button("⚠️ Clear all expenses"): st.session_state.expenses = pd.DataFrame(columns=["Date", "Category", "Amount", "Notes"]) st.success("All expenses cleared.") # ------------------------------- # Summary Dashboard # ------------------------------- elif page == "Summary": st.header("Summary Dashboard (Rs)") if st.session_state.expenses.empty: st.info("No data yet — add expenses to see the summary.") else: df = st.session_state.expenses.copy() df["Date"] = pd.to_datetime(df["Date"]) df["Amount"] = ensure_numeric_amount(df["Amount"]) total = df["Amount"].sum() avg = df["Amount"].mean() max_exp = df["Amount"].max() st.markdown("