Spaces:
Sleeping
Sleeping
Download app.py from jayanth-2005/ca_invoice: direct link, hf CLI and curl.
- Browser
- Download file 4.82 kB
-
https://huggingface.co/spaces/jayanth-2005/ca_invoice/resolve/main/app.py
- Command line
-
hf download hf://spaces/jayanth-2005/ca_invoice/app.py
-
curl -L -o app.py https://huggingface.co/spaces/jayanth-2005/ca_invoice/resolve/main/app.py
4.82 kB
| import streamlit as st | |
| import pdfplumber | |
| import pytesseract | |
| import pandas as pd | |
| from PIL import Image | |
| import cv2 | |
| import numpy as np | |
| import os | |
| import json | |
| from groq import Groq | |
| st.set_page_config(page_title="AI Invoice Intelligence Engine", layout="wide") | |
| st.title("π€ AI Financial Document Intelligence") | |
| st.write("Upload ANY invoice / receipt / subscription / purchase document") | |
| uploaded_file = st.file_uploader( | |
| "Upload File", | |
| type=["pdf", "jpg", "jpeg", "png"] | |
| ) | |
| # --------------------------------------------------------- | |
| # TEXT EXTRACTION | |
| # --------------------------------------------------------- | |
| def extract_text(uploaded_file): | |
| text = "" | |
| if uploaded_file.type == "application/pdf": | |
| with pdfplumber.open(uploaded_file) as pdf: | |
| for page in pdf.pages: | |
| page_text = page.extract_text() | |
| if page_text: | |
| text += page_text + "\n" | |
| else: | |
| image = Image.open(uploaded_file) | |
| img_np = np.array(image) | |
| gray = cv2.cvtColor(img_np, cv2.COLOR_BGR2GRAY) | |
| text = pytesseract.image_to_string(gray) | |
| return text | |
| # --------------------------------------------------------- | |
| # SAFE JSON LOADER | |
| # --------------------------------------------------------- | |
| def safe_json_load(text): | |
| text = text.strip() | |
| text = text.replace("```json", "") | |
| text = text.replace("```", "") | |
| try: | |
| return json.loads(text) | |
| except: | |
| return None | |
| # --------------------------------------------------------- | |
| # SPLIT LARGE DOCUMENT INTO CHUNKS | |
| # --------------------------------------------------------- | |
| def split_into_chunks(text, max_chars=4000): | |
| chunks = [] | |
| current = "" | |
| for line in text.split("\n"): | |
| if len(current) + len(line) > max_chars: | |
| chunks.append(current) | |
| current = "" | |
| current += line + "\n" | |
| if current: | |
| chunks.append(current) | |
| return chunks | |
| # --------------------------------------------------------- | |
| # AI EXTRACTION (GROQ) | |
| # --------------------------------------------------------- | |
| def ai_extract_invoice(text): | |
| client = Groq(api_key=os.getenv("GROQ_API_KEY")) | |
| chunks = split_into_chunks(text) | |
| invoices = [] | |
| for chunk in chunks: | |
| prompt = f""" | |
| You are a financial document extraction engine. | |
| If this text contains: | |
| - invoice | |
| - receipt | |
| - subscription | |
| - payment confirmation | |
| - order | |
| - tax invoice | |
| Extract structured JSON array. | |
| Format: | |
| [ | |
| {{ | |
| "document_type": "", | |
| "invoice_or_order_number": "", | |
| "invoice_date": "", | |
| "vendor_name": "", | |
| "vendor_gstin": null, | |
| "taxable_amount": null, | |
| "cgst": null, | |
| "sgst": null, | |
| "igst": null, | |
| "total_amount": null | |
| }} | |
| ] | |
| If no financial transaction, return []. | |
| TEXT: | |
| {chunk} | |
| """ | |
| try: | |
| completion = client.chat.completions.create( | |
| model="llama-3.1-8b-instant", | |
| messages=[{"role": "user", "content": prompt}], | |
| temperature=0 | |
| ) | |
| response_text = completion.choices[0].message.content | |
| parsed = safe_json_load(response_text) | |
| if parsed and isinstance(parsed, list): | |
| invoices.extend(parsed) | |
| except Exception as e: | |
| print("Chunk error:", e) | |
| continue | |
| return invoices | |
| # --------------------------------------------------------- | |
| # CONFIDENCE SCORE | |
| # --------------------------------------------------------- | |
| def calculate_confidence(row): | |
| total_fields = len(row) | |
| filled_fields = sum( | |
| 1 for v in row.values | |
| if v not in [None, "", "null"] | |
| ) | |
| return round((filled_fields / total_fields) * 100, 2) | |
| # --------------------------------------------------------- | |
| # MAIN EXECUTION | |
| # --------------------------------------------------------- | |
| if uploaded_file: | |
| raw_text = extract_text(uploaded_file) | |
| st.subheader("π Raw Text Preview") | |
| st.text_area("Preview", raw_text[:3000], height=250) | |
| with st.spinner("π€ AI Analyzing Document..."): | |
| invoices = ai_extract_invoice(raw_text) | |
| if invoices: | |
| df = pd.DataFrame(invoices).drop_duplicates() | |
| df["confidence_%"] = df.apply(calculate_confidence, axis=1) | |
| st.success(f"β {len(df)} document(s) detected") | |
| st.dataframe(df, use_container_width=True) | |
| st.download_button( | |
| "β¬ Download CSV", | |
| df.to_csv(index=False), | |
| "invoice_output.csv", | |
| "text/csv" | |
| ) | |
| else: | |
| st.warning("β No financial transaction detected.") |