serene-abyss commited on
Commit
2ec8814
·
verified ·
1 Parent(s): c4d9988

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +95 -52
app.py CHANGED
@@ -15,12 +15,20 @@ st.set_page_config(
15
  )
16
 
17
  # --------------------------------------------------
18
- # STYLING (PROFESSIONAL / JUDGE READY)
19
  # --------------------------------------------------
20
  st.markdown("""
21
  <style>
 
 
 
 
 
 
 
 
22
  .stApp {
23
- background: linear-gradient(180deg, #f8fafc 0%, #ffffff 100%);
24
  }
25
 
26
  .block-container {
@@ -29,55 +37,86 @@ st.markdown("""
29
  }
30
 
31
  .card {
32
- background: white;
33
- border-radius: 16px;
34
- padding: 1.5rem;
35
  margin-bottom: 1.5rem;
36
- border: 1px solid #e5e7eb;
37
- box-shadow: 0 10px 30px rgba(0,0,0,0.06);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  }
39
 
40
  .badge-success {
41
  background: #ecfdf5;
42
  color: #047857;
43
- padding: 0.35rem 0.75rem;
44
  border-radius: 999px;
45
- font-size: 0.8rem;
46
  font-weight: 600;
47
  }
48
 
49
  .badge-pending {
50
- background: #fffbeb;
51
- color: #92400e;
52
- padding: 0.35rem 0.75rem;
53
  border-radius: 999px;
54
- font-size: 0.8rem;
55
  font-weight: 600;
56
  }
57
 
58
- h1, h2, h3 {
59
- color: #0f172a;
 
 
60
  font-weight: 600;
 
61
  }
62
 
63
- .stButton > button {
 
 
 
 
64
  border-radius: 10px;
65
  font-weight: 600;
66
- padding: 0.5rem 1rem;
67
  }
68
  </style>
69
  """, unsafe_allow_html=True)
70
 
71
  # --------------------------------------------------
72
- # HERO
73
  # --------------------------------------------------
74
  st.markdown("""
75
  <div class="card">
76
  <h1>Invoice-Flow AI</h1>
77
- <p style="font-size:1.05rem;color:#475569;">
78
- Agentic invoice verification & on-chain trust registry for MSME finance
79
  </p>
80
- <span class="badge-success">LIVE HACKATHON PROTOTYPE</span>
81
  </div>
82
  """, unsafe_allow_html=True)
83
 
@@ -89,7 +128,7 @@ try:
89
  RPC_URL = st.secrets["RPC_URL"]
90
  PRIVATE_KEY = st.secrets["PRIVATE_KEY"]
91
  except Exception:
92
- st.error("Secrets missing. Add them in Hugging Face → Settings → Variables.")
93
  st.stop()
94
 
95
  # --------------------------------------------------
@@ -106,19 +145,19 @@ contract = w3.eth.contract(
106
  )
107
 
108
  # --------------------------------------------------
109
- # STATE
110
  # --------------------------------------------------
111
- if "invoice" not in st.session_state:
112
- st.session_state.invoice = None
113
- if "approved" not in st.session_state:
114
- st.session_state.approved = False
115
- if "minted" not in st.session_state:
116
- st.session_state.minted = False
117
- if "tx_hash" not in st.session_state:
118
- st.session_state.tx_hash = None
119
 
120
  # --------------------------------------------------
121
- # MOCK FALLBACK
122
  # --------------------------------------------------
123
  def mock_invoice():
124
  return {
@@ -129,23 +168,23 @@ def mock_invoice():
129
  }
130
 
131
  # --------------------------------------------------
132
- # LAYOUT
133
  # --------------------------------------------------
134
  col1, col2 = st.columns([1, 1])
135
 
136
- # -------------------- LEFT -------------------------
137
  with col1:
138
  st.markdown("<div class='card'>", unsafe_allow_html=True)
139
- st.subheader("1️⃣ Invoice Ingestion")
140
- st.caption("Upload a raw invoice PDF")
141
 
142
  uploaded = st.file_uploader("Invoice PDF", type=["pdf"])
143
 
144
  if uploaded:
145
  pdf_bytes = uploaded.getvalue()
146
 
147
- if st.button("🚀 Analyze with Gemini"):
148
- with st.spinner("Extracting invoice data..."):
149
  try:
150
  res = genai_client.models.generate_content(
151
  model="gemini-1.5-flash",
@@ -154,40 +193,41 @@ with col1:
154
  "Extract invoice as JSON with keys seller_name, seller_gstin, invoice_amount, invoice_number. Return ONLY JSON."
155
  ]
156
  )
157
- text = res.text.replace("```json", "").replace("```", "").strip()
158
- st.session_state.invoice = json.loads(text)
159
  except Exception:
160
- st.warning("AI parsing failed. Using demo-safe fallback.")
161
  st.session_state.invoice = mock_invoice()
162
  st.markdown("</div>", unsafe_allow_html=True)
163
 
164
- # -------------------- RIGHT ------------------------
165
  with col2:
166
  if st.session_state.invoice:
167
  st.markdown("<div class='card'>", unsafe_allow_html=True)
168
- st.subheader("2️⃣ Verification Dashboard")
169
  st.json(st.session_state.invoice)
170
  st.markdown("</div>", unsafe_allow_html=True)
171
 
172
  st.markdown("<div class='card'>", unsafe_allow_html=True)
173
- st.subheader("3️⃣ Buyer Consent")
174
 
175
  if not st.session_state.approved:
176
- st.markdown("<span class='badge-pending'>Awaiting Buyer Approval</span>", unsafe_allow_html=True)
177
- if st.button("Approve Invoice"):
178
  st.session_state.approved = True
179
  st.rerun()
180
  else:
181
  st.markdown("<span class='badge-success'>Buyer Approved</span>", unsafe_allow_html=True)
 
182
  st.markdown("</div>", unsafe_allow_html=True)
183
 
184
  if st.session_state.approved:
185
  st.markdown("<div class='card'>", unsafe_allow_html=True)
186
- st.subheader("4️⃣ On-Chain Settlement")
187
 
188
  if not st.session_state.minted:
189
- if st.button("⛓️ Mint Receipt on Polygon"):
190
- with st.spinner("Writing to blockchain..."):
191
  inv = st.session_state.invoice
192
  payload = f"{inv['invoice_number']}{inv['seller_gstin']}{inv['invoice_amount']}"
193
  receipt_hash = hashlib.sha256(payload.encode()).hexdigest()
@@ -211,9 +251,9 @@ with col2:
211
  st.rerun()
212
 
213
  if st.session_state.minted:
214
- st.success("Receipt Minted Successfully")
215
  st.link_button(
216
- "View on PolygonScan",
217
  f"https://amoy.polygonscan.com/tx/{st.session_state.tx_hash}"
218
  )
219
 
@@ -223,4 +263,7 @@ with col2:
223
  # FOOTER
224
  # --------------------------------------------------
225
  st.markdown("---")
226
- st.caption("East-India Blockchain Summit 2.0 • Agentic Trust Infrastructure • Polygon + Gemini")
 
 
 
 
15
  )
16
 
17
  # --------------------------------------------------
18
+ # PROFESSIONAL FINTECH STYLING
19
  # --------------------------------------------------
20
  st.markdown("""
21
  <style>
22
+ :root {
23
+ --primary: #0f2a44;
24
+ --secondary: #1e3a8a;
25
+ --accent: #047857;
26
+ --muted: #475569;
27
+ --bg: #f5f7fb;
28
+ }
29
+
30
  .stApp {
31
+ background-color: var(--bg);
32
  }
33
 
34
  .block-container {
 
37
  }
38
 
39
  .card {
40
+ background: #ffffff;
41
+ border-radius: 14px;
42
+ padding: 1.6rem;
43
  margin-bottom: 1.5rem;
44
+ border: 1px solid #e6eaf0;
45
+ box-shadow: 0 12px 28px rgba(15, 42, 68, 0.06);
46
+ }
47
+
48
+ h1 {
49
+ color: var(--primary);
50
+ font-weight: 700;
51
+ letter-spacing: -0.02em;
52
+ }
53
+
54
+ h2, h3 {
55
+ color: var(--primary);
56
+ font-weight: 600;
57
+ }
58
+
59
+ .caption {
60
+ color: var(--muted);
61
+ font-size: 0.95rem;
62
+ }
63
+
64
+ .badge-live {
65
+ background: #e0f2fe;
66
+ color: #0369a1;
67
+ padding: 0.35rem 0.8rem;
68
+ border-radius: 999px;
69
+ font-size: 0.75rem;
70
+ font-weight: 600;
71
  }
72
 
73
  .badge-success {
74
  background: #ecfdf5;
75
  color: #047857;
76
+ padding: 0.35rem 0.8rem;
77
  border-radius: 999px;
78
+ font-size: 0.75rem;
79
  font-weight: 600;
80
  }
81
 
82
  .badge-pending {
83
+ background: #fff7ed;
84
+ color: #9a3412;
85
+ padding: 0.35rem 0.8rem;
86
  border-radius: 999px;
87
+ font-size: 0.75rem;
88
  font-weight: 600;
89
  }
90
 
91
+ .stButton > button {
92
+ background-color: var(--secondary);
93
+ color: white;
94
+ border-radius: 10px;
95
  font-weight: 600;
96
+ border: none;
97
  }
98
 
99
+ .stButton > button:hover {
100
+ background-color: #1e40af;
101
+ }
102
+
103
+ .stLinkButton a {
104
  border-radius: 10px;
105
  font-weight: 600;
 
106
  }
107
  </style>
108
  """, unsafe_allow_html=True)
109
 
110
  # --------------------------------------------------
111
+ # HERO / BRAND HEADER
112
  # --------------------------------------------------
113
  st.markdown("""
114
  <div class="card">
115
  <h1>Invoice-Flow AI</h1>
116
+ <p class="caption">
117
+ Agentic invoice verification & on-chain trust infrastructure for MSME finance
118
  </p>
119
+ <span class="badge-live">HACKATHON LIVE PROTOTYPE</span>
120
  </div>
121
  """, unsafe_allow_html=True)
122
 
 
128
  RPC_URL = st.secrets["RPC_URL"]
129
  PRIVATE_KEY = st.secrets["PRIVATE_KEY"]
130
  except Exception:
131
+ st.error("Missing secrets. Add them in Hugging Face → Settings → Variables.")
132
  st.stop()
133
 
134
  # --------------------------------------------------
 
145
  )
146
 
147
  # --------------------------------------------------
148
+ # SESSION STATE
149
  # --------------------------------------------------
150
+ for key, default in {
151
+ "invoice": None,
152
+ "approved": False,
153
+ "minted": False,
154
+ "tx_hash": None
155
+ }.items():
156
+ if key not in st.session_state:
157
+ st.session_state[key] = default
158
 
159
  # --------------------------------------------------
160
+ # FALLBACK
161
  # --------------------------------------------------
162
  def mock_invoice():
163
  return {
 
168
  }
169
 
170
  # --------------------------------------------------
171
+ # MAIN LAYOUT
172
  # --------------------------------------------------
173
  col1, col2 = st.columns([1, 1])
174
 
175
+ # ---------------- LEFT -----------------
176
  with col1:
177
  st.markdown("<div class='card'>", unsafe_allow_html=True)
178
+ st.subheader("Invoice Ingestion")
179
+ st.markdown("<p class='caption'>Upload an invoice PDF for automated trust verification</p>", unsafe_allow_html=True)
180
 
181
  uploaded = st.file_uploader("Invoice PDF", type=["pdf"])
182
 
183
  if uploaded:
184
  pdf_bytes = uploaded.getvalue()
185
 
186
+ if st.button("Analyze Invoice"):
187
+ with st.spinner("Extracting structured data..."):
188
  try:
189
  res = genai_client.models.generate_content(
190
  model="gemini-1.5-flash",
 
193
  "Extract invoice as JSON with keys seller_name, seller_gstin, invoice_amount, invoice_number. Return ONLY JSON."
194
  ]
195
  )
196
+ clean = res.text.replace("```json", "").replace("```", "").strip()
197
+ st.session_state.invoice = json.loads(clean)
198
  except Exception:
199
+ st.warning("AI extraction failed. Using demo-safe fallback.")
200
  st.session_state.invoice = mock_invoice()
201
  st.markdown("</div>", unsafe_allow_html=True)
202
 
203
+ # ---------------- RIGHT ----------------
204
  with col2:
205
  if st.session_state.invoice:
206
  st.markdown("<div class='card'>", unsafe_allow_html=True)
207
+ st.subheader("Verification Summary")
208
  st.json(st.session_state.invoice)
209
  st.markdown("</div>", unsafe_allow_html=True)
210
 
211
  st.markdown("<div class='card'>", unsafe_allow_html=True)
212
+ st.subheader("Buyer Consent")
213
 
214
  if not st.session_state.approved:
215
+ st.markdown("<span class='badge-pending'>Awaiting Buyer Confirmation</span>", unsafe_allow_html=True)
216
+ if st.button("Approve Invoice"):
217
  st.session_state.approved = True
218
  st.rerun()
219
  else:
220
  st.markdown("<span class='badge-success'>Buyer Approved</span>", unsafe_allow_html=True)
221
+
222
  st.markdown("</div>", unsafe_allow_html=True)
223
 
224
  if st.session_state.approved:
225
  st.markdown("<div class='card'>", unsafe_allow_html=True)
226
+ st.subheader("On-Chain Settlement")
227
 
228
  if not st.session_state.minted:
229
+ if st.button("Mint Verified Receipt"):
230
+ with st.spinner("Finalizing on blockchain..."):
231
  inv = st.session_state.invoice
232
  payload = f"{inv['invoice_number']}{inv['seller_gstin']}{inv['invoice_amount']}"
233
  receipt_hash = hashlib.sha256(payload.encode()).hexdigest()
 
251
  st.rerun()
252
 
253
  if st.session_state.minted:
254
+ st.success("Receipt minted successfully")
255
  st.link_button(
256
+ "View Transaction on PolygonScan",
257
  f"https://amoy.polygonscan.com/tx/{st.session_state.tx_hash}"
258
  )
259
 
 
263
  # FOOTER
264
  # --------------------------------------------------
265
  st.markdown("---")
266
+ st.caption(
267
+ "Invoice-Flow AI • Trust Infrastructure for MSME Finance • "
268
+ "Gemini 1.5 Flash • Polygon Amoy"
269
+ )