| import os |
| import json |
| import csv |
| import pandas as pd |
| from datetime import datetime |
|
|
| DATA_DIR = os.path.dirname(os.path.abspath(__file__)) + "/data" |
| LEDGER_FILE = DATA_DIR + "/ledger.csv" |
|
|
| |
| PARSING_SYSTEM_PROMPT = ( |
| "You are a precise data extractor. Your task is to extract financial transaction details from " |
| "the farmer's text and return them in EXACTLY the following JSON format. Do not return any other text, " |
| "explanation, or markdown blocks. Just the raw JSON.\n\n" |
| "JSON Format:\n" |
| "{\n" |
| " \"date\": \"string (e.g., today, yesterday, 5 June)\",\n" |
| " \"item\": \"string (e.g., wheat, potato, urea)\",\n" |
| " \"qty\": \"string (e.g., 40kg, 2 bags, 1 unit)\",\n" |
| " \"price\": \"integer (only numbers, e.g. 1200)\",\n" |
| " \"type\": \"string (must be either 'sale' or 'purchase')\"\n" |
| "}\n\n" |
| "Examples:\n" |
| "1. Input: \"sold 40kg wheat for 1200 rupees today\"\n" |
| " Output: {\"date\": \"today\", \"item\": \"wheat\", \"qty\": \"40kg\", \"price\": 1200, \"type\": \"sale\"}\n" |
| "2. Input: \"आज मैंने 500 रुपये का यूरिया खरीदा\"\n" |
| " Output: {\"date\": \"today\", \"item\": \"urea\", \"qty\": \"1 unit\", \"price\": 500, \"type\": \"purchase\"}\n" |
| "3. Input: \"कल 6000 रुपये का आलू बेचा\"\n" |
| " Output: {\"date\": \"yesterday\", \"item\": \"potato\", \"qty\": \"1 unit\", \"price\": 6000, \"type\": \"sale\"}\n" |
| ) |
|
|
| def init_ledger(): |
| """Create ledger file with headers if it doesn't exist.""" |
| os.makedirs(DATA_DIR, exist_ok=True) |
| if not os.path.exists(LEDGER_FILE): |
| with open(LEDGER_FILE, "w", encoding="utf-8", newline="") as f: |
| writer = csv.writer(f) |
| writer.writerow(["Date", "Item (सामग्री)", "Quantity (मात्रा)", "Price (मूल्य)", "Type (प्रकार)", "Timestamp"]) |
| print(f"[ledger.py] Initialized new ledger CSV at {LEDGER_FILE}") |
|
|
| def parse_transaction(text, generate_fn): |
| """ |
| Calls the LLM generation function to parse transaction details. |
| Returns a dictionary of parsed details. |
| """ |
| prompt = f"Extract details from this text: \"{text}\"" |
| response = generate_fn(prompt, system=PARSING_SYSTEM_PROMPT, stream=False) |
| |
| |
| cleaned = response.strip() |
| if cleaned.startswith("```json"): |
| cleaned = cleaned[7:] |
| if cleaned.startswith("```"): |
| cleaned = cleaned[3:] |
| if cleaned.endswith("```"): |
| cleaned = cleaned[:-3] |
| cleaned = cleaned.strip() |
| |
| |
| json_match = re.search(r"\{.*\}", cleaned, re.DOTALL) |
| if json_match: |
| cleaned = json_match.group(0) |
| |
| try: |
| data = json.loads(cleaned) |
| |
| if "price" in data: |
| price_str = str(data["price"]).replace(",", "").strip() |
| |
| digits = "".join(filter(str.isdigit, price_str)) |
| data["price"] = int(digits) if digits else 0 |
| return data |
| except Exception as e: |
| print(f"[ledger.py] Error parsing JSON from LLM response: {e}. Raw response: {response}") |
| |
| return { |
| "date": "today", |
| "item": "", |
| "qty": "", |
| "price": 0, |
| "type": "sale" |
| } |
|
|
| import src.db as db |
|
|
| def add_entry(date, item, qty, price, trans_type): |
| """Append a transaction entry to the database.""" |
| try: |
| db.add_ledger_entry(date, trans_type, item, qty, "", float(price)) |
| return True |
| except Exception as e: |
| print(f"[ledger.py] Error adding entry to ledger: {e}") |
| return False |
|
|
| def get_ledger_data(): |
| """Read ledger and return (dataframe, summary_dict)""" |
| try: |
| entries, summary = db.get_ledger_entries() |
| |
| |
| df_data = [] |
| for r in entries: |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| df_data.append({ |
| "Id": r["id"], |
| "Date": r["date"], |
| "Item": r["item"], |
| "Quantity": r["qty"], |
| "Price": r["price"], |
| "Type": r["type"], |
| "Timestamp": r["created_at"] |
| }) |
| df = pd.DataFrame(df_data) |
| return df, summary |
| except Exception as e: |
| print(f"[ledger.py] Error reading ledger: {e}") |
| return pd.DataFrame(), {"income": 0, "expense": 0, "balance": 0} |
|
|
| import re |
|
|