Repository navigation
Expand file tree
/
Copy pathapp.py
More file actions
96 lines (83 loc) · 3.22 KB
/
Copy pathapp.py
File metadata and controls
96 lines (83 loc) · 3.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import os
import pandas as pd
from pydantic import BaseModel
import needle
import streamlit as st
# Define schema for Needle 2 on-device extraction
class ExpenseRecord(BaseModel):
merchant: str
amount: float
category: str
payment_method: str
CSV_FILE = "expenses.csv"
def initialize_csv():
"""Ensure expenses.csv exists with correct columns."""
if not os.path.exists(CSV_FILE):
df = pd.DataFrame({
"merchant": pd.Series(dtype="str"),
"amount": pd.Series(dtype="float"),
"category": pd.Series(dtype="str"),
"payment_method": pd.Series(dtype="str")
})
df.to_csv(CSV_FILE, index=False)
def extract_expense(note_text: str) -> ExpenseRecord:
"""Extract structured financial data using Needle 2."""
try:
extracted = needle.extract(note_text, ExpenseRecord)
return extracted
except Exception:
return ExpenseRecord(
merchant="Uncategorized",
amount=0.0,
category="Miscellaneous",
payment_method="Unknown"
)
def save_expense(record: ExpenseRecord):
"""Save an expense record to local CSV."""
initialize_csv()
df = pd.read_csv(CSV_FILE)
new_row = pd.DataFrame([{
"merchant": str(record.merchant),
"amount": round(float(record.amount), 2),
"category": str(record.category),
"payment_method": str(record.payment_method)
}])
if df.empty:
df = new_row
else:
df = pd.concat([df, new_row], ignore_index=True)
df.to_csv(CSV_FILE, index=False)
def main():
"""Streamlit dashboard interface."""
st.set_page_config(page_title="Needle 2 Finance Parser", page_icon="💳", layout="wide")
st.title("💳 Needle 2 Offline Finance Parser")
st.caption("Zero-cloud, high-speed expense extraction powered by 45M Parameter Needle 2 Engine")
col1, col2 = st.columns([1, 1])
with col1:
st.subheader("📥 Input Financial Note")
note_input = st.text_area("Type or paste raw expense note:", placeholder="e.g. Spent Rs 450 at Blinkit for groceries using UPI")
if st.button("⚡ Extract & Save Expense", type="primary"):
if note_input.strip():
with st.spinner("Extracting with Needle 2..."):
record = extract_expense(note_input)
save_expense(record)
st.success(f"Extracted: {record.merchant} - ₹{record.amount:,.2f} ({record.category})")
else:
st.warning("Please enter an expense note first.")
with col2:
st.subheader("📊 Spending Summary")
initialize_csv()
df = pd.read_csv(CSV_FILE)
if not df.empty:
st.metric("Total Expenses", f"₹{df['amount'].sum():,.2f}", delta=f"{len(df)} transactions")
category_totals = df.groupby("category")["amount"].sum()
st.bar_chart(category_totals)
else:
st.info("No expenses recorded yet. Input a note to start tracking.")
st.divider()
st.subheader("🧾 Recent Transactions")
if os.path.exists(CSV_FILE):
df_display = pd.read_csv(CSV_FILE)
st.dataframe(df_display, use_container_width=True)
if __name__ == "__main__":
main()