Quick / app.py
Gowthamgokul's picture
Update app.py
0474977 verified
import streamlit as st
import pandas as pd
from config.db import get_collection
from utils.text_cleaner import clean_text
from utils.search import rank_results
st.set_page_config(page_title="Expense Search System", layout="wide")
st.title("πŸ” Expense Search Dashboard")
# --- 1️⃣ Input/Search Layer ---
user_input = st.text_input("Search (Date / Company / Remark / Description / Amount)")
if user_input:
clean_input = clean_text(user_input)
collection = get_collection()
# --- Build query WITHOUT $text to avoid MongoDB error ---
query = {
"$or": [
{"date": {"$regex": clean_input, "$options": "i"}}, # Date search
{"home company": {"$regex": clean_input, "$options": "i"}}, # Company search
{"description": {"$regex": clean_input, "$options": "i"}}, # Description search
{"remarks": {"$regex": clean_input, "$options": "i"}}, # Remarks search
{"description_clean": {"$regex": clean_input, "$options": "i"}}, # Cleaned description
]
}
# Try to match amount if input is numeric
try:
amount_value = float(clean_input.replace(",", ""))
query["$or"].append({"amount": amount_value})
except ValueError:
pass # Not a number, skip amount matching
# --- Fetch ALL matching records from MongoDB ---
docs = list(collection.find(
query,
{
"date": 1,
"description": 1,
"remarks": 1,
"amount": 1,
"home company": 1,
"description_clean": 1
}
)) # Removed limit to fetch ALL records
if docs:
# --- Rank using fuzzy search ---
ranked = rank_results(clean_input, docs)
df = pd.DataFrame(ranked)
df = df[['date', 'description', 'remarks', 'home company', 'amount']]
df.rename(columns={"home company": "Company"}, inplace=True)
# --- 2️⃣ Quick Summary Metrics ---
total_transactions = len(df)
total_amount = df['amount'].sum()
inward_total = df[df['remarks'].str.lower().str.contains("inward", na=False)]['amount'].sum()
outward_total = df[df['remarks'].str.lower().str.contains("outward", na=False)]['amount'].sum()
net_total = inward_total - outward_total
st.subheader("πŸ“Š Quick Summary")
c1, c2, c3, c4, c5 = st.columns(5)
c1.metric("Transactions", total_transactions)
c2.metric("Total Amount", f"{total_amount:,.2f}")
c3.metric("Inward", f"{inward_total:,.2f}")
c4.metric("Outward", f"{outward_total:,.2f}")
c5.metric("Net Total", f"{net_total:,.2f}")
# --- 3️⃣ Matched Transactions Table ---
st.subheader("🧾 Matched Transactions")
st.dataframe(df, use_container_width=True)
# --- 4️⃣ Remarks Breakup ---
st.subheader("🏷️ Remarks Breakup")
remarks_summary = df.groupby('remarks')['amount'].agg(['count', 'sum']).reset_index()
remarks_summary.rename(columns={"count": "Transactions", "sum": "Total Amount", "remarks": "Remark"}, inplace=True)
st.table(remarks_summary)
# --- 5️⃣ Company Involvement ---
st.subheader("🏒 Company Summary")
company_summary = df.groupby('Company')['amount'].agg(['count', 'sum']).reset_index()
company_summary.rename(columns={"count": "Transactions", "sum": "Total Amount"}, inplace=True)
st.table(company_summary)
# --- 6️⃣ Date Summary (if multiple dates present) ---
st.subheader("πŸ“… Date-wise Summary")
date_summary = df.groupby('date')['amount'].agg(['count', 'sum']).reset_index()
date_summary.rename(columns={"count": "Transactions", "sum": "Total Amount", "date": "Date"}, inplace=True)
st.table(date_summary)
# --- 7️⃣ Optional Visuals ---
st.subheader("πŸ“Š Visual Insights")
col1, col2 = st.columns(2)
with col1:
st.markdown("**πŸ₯§ Inward vs Outward Pie Chart**")
pie_data = pd.DataFrame({
"Type": ["Inward", "Outward"],
"Amount": [inward_total, outward_total]
})
st.bar_chart(pie_data.set_index("Type"))
with col2:
st.markdown("**πŸ“Š Amount by Company**")
st.bar_chart(company_summary.set_index("Company")["Total Amount"])
else:
st.warning("No confident match found")