import streamlit as st
import json
import hashlib
from web3 import Web3
from google import genai
from google.genai import types
# --------------------------------------------------
# PAGE CONFIG
# --------------------------------------------------
st.set_page_config(
page_title="Invoice-Flow AI",
layout="wide",
initial_sidebar_state="collapsed"
)
# --------------------------------------------------
# PROFESSIONAL FINTECH STYLING
# --------------------------------------------------
st.markdown("""
""", unsafe_allow_html=True)
# --------------------------------------------------
# HERO / BRAND HEADER
# --------------------------------------------------
st.markdown("""
Invoice-Flow AI
Agentic invoice verification & on-chain trust infrastructure for MSME finance
HACKATHON LIVE PROTOTYPE
""", unsafe_allow_html=True)
# --------------------------------------------------
# SECRETS (HF SAFE)
# --------------------------------------------------
try:
GEMINI_API_KEY = st.secrets["GEMINI_API_KEY"]
RPC_URL = st.secrets["RPC_URL"]
PRIVATE_KEY = st.secrets["PRIVATE_KEY"]
except Exception:
st.error("Missing secrets. Add them in Hugging Face → Settings → Variables.")
st.stop()
# --------------------------------------------------
# CLIENT SETUP
# --------------------------------------------------
genai_client = genai.Client(api_key=GEMINI_API_KEY)
w3 = Web3(Web3.HTTPProvider(RPC_URL))
account = w3.eth.account.from_key(PRIVATE_KEY)
CONTRACT_ADDRESS = "0x3af7C33f4D0303E6eb94c2D24fB0bD82B54c6914"
contract = w3.eth.contract(
address=Web3.to_checksum_address(CONTRACT_ADDRESS),
abi=json.load(open("abi.json"))
)
# --------------------------------------------------
# SESSION STATE
# --------------------------------------------------
for key, default in {
"invoice": None,
"approved": False,
"minted": False,
"tx_hash": None
}.items():
if key not in st.session_state:
st.session_state[key] = default
# --------------------------------------------------
# FALLBACK
# --------------------------------------------------
def mock_invoice():
return {
"seller_name": "TechFlow Solutions Pvt Ltd",
"seller_gstin": "29AAACF5724R1Z5",
"invoice_amount": 75000,
"invoice_number": "INV-2024-001"
}
# --------------------------------------------------
# MAIN LAYOUT
# --------------------------------------------------
col1, col2 = st.columns([1, 1])
# ---------------- LEFT -----------------
with col1:
st.markdown("", unsafe_allow_html=True)
st.subheader("Invoice Ingestion")
st.markdown("
Upload an invoice PDF for automated trust verification
", unsafe_allow_html=True)
uploaded = st.file_uploader("Invoice PDF", type=["pdf"])
if uploaded:
pdf_bytes = uploaded.getvalue()
if st.button("Analyze Invoice"):
with st.spinner("Extracting structured data..."):
try:
res = genai_client.models.generate_content(
model="gemini-1.5-flash",
contents=[
types.Part.from_bytes(pdf_bytes, "application/pdf"),
"Extract invoice as JSON with keys seller_name, seller_gstin, invoice_amount, invoice_number. Return ONLY JSON."
]
)
clean = res.text.replace("```json", "").replace("```", "").strip()
st.session_state.invoice = json.loads(clean)
except Exception:
st.warning("AI extraction failed. Using demo-safe fallback.")
st.session_state.invoice = mock_invoice()
st.markdown("
", unsafe_allow_html=True)
# ---------------- RIGHT ----------------
with col2:
if st.session_state.invoice:
st.markdown("", unsafe_allow_html=True)
st.subheader("Verification Summary")
st.json(st.session_state.invoice)
st.markdown("
", unsafe_allow_html=True)
st.markdown("", unsafe_allow_html=True)
st.subheader("Buyer Consent")
if not st.session_state.approved:
st.markdown("Awaiting Buyer Confirmation", unsafe_allow_html=True)
if st.button("Approve Invoice"):
st.session_state.approved = True
st.rerun()
else:
st.markdown("Buyer Approved", unsafe_allow_html=True)
st.markdown("
", unsafe_allow_html=True)
if st.session_state.approved:
st.markdown("", unsafe_allow_html=True)
st.subheader("On-Chain Settlement")
if not st.session_state.minted:
if st.button("Mint Verified Receipt"):
with st.spinner("Finalizing on blockchain..."):
inv = st.session_state.invoice
payload = f"{inv['invoice_number']}{inv['seller_gstin']}{inv['invoice_amount']}"
receipt_hash = hashlib.sha256(payload.encode()).hexdigest()
tx = contract.functions.mintReceipt(
Web3.to_bytes(hexstr="0x" + receipt_hash),
inv["seller_gstin"],
int(inv["invoice_amount"])
).build_transaction({
"from": account.address,
"nonce": w3.eth.get_transaction_count(account.address),
"gas": 250000,
"gasPrice": w3.eth.gas_price,
"chainId": 80002
})
signed = w3.eth.account.sign_transaction(tx, PRIVATE_KEY)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
st.session_state.tx_hash = w3.to_hex(tx_hash)
st.session_state.minted = True
st.rerun()
if st.session_state.minted:
st.success("Receipt minted successfully")
st.link_button(
"View Transaction on PolygonScan",
f"https://amoy.polygonscan.com/tx/{st.session_state.tx_hash}"
)
st.markdown("
", unsafe_allow_html=True)
# --------------------------------------------------
# FOOTER
# --------------------------------------------------
st.markdown("---")
st.caption(
"Invoice-Flow AI • Trust Infrastructure for MSME Finance • "
"Gemini 1.5 Flash • Polygon Amoy"
)