Ranjit0034 commited on
Commit
656419f
Β·
verified Β·
1 Parent(s): e729c58

Upload src/finee/ui.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. src/finee/ui.py +452 -0
src/finee/ui.py ADDED
@@ -0,0 +1,452 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ FinEE UI - Gradio Interface
3
+ ============================
4
+
5
+ Beautiful web UI for financial entity extraction with:
6
+ - Message extraction demo
7
+ - Batch processing
8
+ - File upload (PDF/Image)
9
+ - Analytics dashboard
10
+ - Chat interface
11
+
12
+ Author: Ranjit Behera
13
+ """
14
+
15
+ import json
16
+ from typing import Optional
17
+
18
+ try:
19
+ import gradio as gr
20
+ except ImportError:
21
+ raise ImportError("Please install gradio: pip install gradio")
22
+
23
+
24
+ # ============================================================================
25
+ # EXTRACTION FUNCTIONS
26
+ # ============================================================================
27
+
28
+ def extract_entities(
29
+ message: str,
30
+ use_rag: bool = True,
31
+ use_llm: bool = False
32
+ ) -> tuple:
33
+ """Extract entities from a message."""
34
+ if not message.strip():
35
+ return "{}", "", "Please enter a message"
36
+
37
+ try:
38
+ # Try to import FinEE
39
+ try:
40
+ from finee import FinancialExtractor
41
+ from finee.rag import RAGEngine
42
+
43
+ extractor = FinancialExtractor(use_llm=use_llm)
44
+ result = extractor.extract(message)
45
+
46
+ # RAG enhancement
47
+ rag_info = ""
48
+ if use_rag:
49
+ rag = RAGEngine()
50
+ context = rag.retrieve(message)
51
+
52
+ if context.merchant_info:
53
+ if not result.get("merchant"):
54
+ result["merchant"] = context.merchant_info["name"]
55
+ if not result.get("category"):
56
+ result["category"] = context.merchant_info["category"]
57
+
58
+ rag_info = f"""
59
+ ### RAG Context
60
+ - **Merchant**: {context.merchant_info['name']}
61
+ - **Category**: {context.merchant_info['category']}
62
+ - **Confidence Boost**: +{context.confidence_boost:.0%}
63
+ """
64
+
65
+ # Format output
66
+ json_output = json.dumps(result, indent=2, ensure_ascii=False)
67
+
68
+ # Create summary
69
+ summary_parts = []
70
+ if result.get("amount"):
71
+ summary_parts.append(f"πŸ’° **Amount**: β‚Ή{result['amount']:,.2f}")
72
+ if result.get("type"):
73
+ emoji = "πŸ“€" if result["type"] == "debit" else "πŸ“₯"
74
+ summary_parts.append(f"{emoji} **Type**: {result['type'].upper()}")
75
+ if result.get("merchant"):
76
+ summary_parts.append(f"πŸͺ **Merchant**: {result['merchant']}")
77
+ if result.get("beneficiary"):
78
+ summary_parts.append(f"πŸ‘€ **Beneficiary**: {result['beneficiary']}")
79
+ if result.get("category"):
80
+ summary_parts.append(f"πŸ“‚ **Category**: {result['category']}")
81
+ if result.get("bank"):
82
+ summary_parts.append(f"🏦 **Bank**: {result['bank']}")
83
+ if result.get("reference"):
84
+ summary_parts.append(f"πŸ”— **Reference**: {result['reference']}")
85
+
86
+ summary = "\n".join(summary_parts) if summary_parts else "No entities extracted"
87
+ summary += rag_info
88
+
89
+ return json_output, summary, "βœ… Extraction successful!"
90
+
91
+ except ImportError:
92
+ # Fallback mock extraction
93
+ import re
94
+ result = {}
95
+
96
+ # Amount
97
+ amount_match = re.search(r'Rs\.?\s*([\d,]+(?:\.\d{2})?)', message)
98
+ if amount_match:
99
+ result['amount'] = float(amount_match.group(1).replace(',', ''))
100
+
101
+ # Type
102
+ if any(w in message.lower() for w in ['debit', 'debited', 'paid']):
103
+ result['type'] = 'debit'
104
+ elif any(w in message.lower() for w in ['credit', 'credited']):
105
+ result['type'] = 'credit'
106
+
107
+ # Bank
108
+ banks = ['HDFC', 'ICICI', 'SBI', 'Axis', 'Kotak']
109
+ for bank in banks:
110
+ if bank.lower() in message.lower():
111
+ result['bank'] = bank
112
+ break
113
+
114
+ json_output = json.dumps(result, indent=2)
115
+ summary = f"πŸ’° Amount: β‚Ή{result.get('amount', 'N/A')}\nπŸ“€ Type: {result.get('type', 'N/A')}"
116
+
117
+ return json_output, summary, "⚠️ Using mock extractor (install finee for full functionality)"
118
+
119
+ except Exception as e:
120
+ return "{}", "", f"❌ Error: {str(e)}"
121
+
122
+
123
+ def batch_extract(messages_text: str, use_rag: bool = True) -> str:
124
+ """Extract from multiple messages."""
125
+ if not messages_text.strip():
126
+ return "Please enter messages (one per line)"
127
+
128
+ messages = [m.strip() for m in messages_text.split('\n') if m.strip()]
129
+ results = []
130
+
131
+ for i, msg in enumerate(messages, 1):
132
+ json_out, summary, status = extract_entities(msg, use_rag, False)
133
+ try:
134
+ data = json.loads(json_out)
135
+ data['_message'] = msg[:50] + '...' if len(msg) > 50 else msg
136
+ results.append(data)
137
+ except:
138
+ results.append({'error': status, '_message': msg[:50]})
139
+
140
+ return json.dumps(results, indent=2, ensure_ascii=False)
141
+
142
+
143
+ def analyze_transactions(transactions_json: str) -> str:
144
+ """Analyze transactions and generate insights."""
145
+ try:
146
+ transactions = json.loads(transactions_json)
147
+
148
+ if not isinstance(transactions, list):
149
+ return "Please provide a list of transactions"
150
+
151
+ # Calculate stats
152
+ total_debit = sum(t.get('amount', 0) for t in transactions if t.get('type') == 'debit')
153
+ total_credit = sum(t.get('amount', 0) for t in transactions if t.get('type') == 'credit')
154
+
155
+ # Category breakdown
156
+ categories = {}
157
+ for t in transactions:
158
+ cat = t.get('category', 'other')
159
+ if cat not in categories:
160
+ categories[cat] = {'total': 0, 'count': 0}
161
+ categories[cat]['total'] += t.get('amount', 0)
162
+ categories[cat]['count'] += 1
163
+
164
+ # Format report
165
+ report = f"""
166
+ ## πŸ“Š Transaction Analysis
167
+
168
+ ### Summary
169
+ - **Total Transactions**: {len(transactions)}
170
+ - **Total Debits**: β‚Ή{total_debit:,.2f}
171
+ - **Total Credits**: β‚Ή{total_credit:,.2f}
172
+ - **Net Flow**: β‚Ή{total_credit - total_debit:,.2f}
173
+
174
+ ### Category Breakdown
175
+ """
176
+
177
+ sorted_cats = sorted(categories.items(), key=lambda x: x[1]['total'], reverse=True)
178
+ for cat, data in sorted_cats:
179
+ pct = (data['total'] / total_debit * 100) if total_debit > 0 else 0
180
+ report += f"- **{cat.title()}**: β‚Ή{data['total']:,.2f} ({pct:.1f}%) - {data['count']} txns\n"
181
+
182
+ return report
183
+
184
+ except json.JSONDecodeError:
185
+ return "❌ Invalid JSON. Please paste valid transaction data."
186
+ except Exception as e:
187
+ return f"❌ Analysis error: {str(e)}"
188
+
189
+
190
+ def chat_response(message: str, history: list) -> str:
191
+ """Handle chat messages."""
192
+ if not message.strip():
193
+ return ""
194
+
195
+ message_lower = message.lower()
196
+
197
+ # Intent detection
198
+ if any(w in message_lower for w in ['extract', 'parse', 'analyze this']):
199
+ # Try to extract from the message
200
+ _, summary, _ = extract_entities(message)
201
+ return f"I extracted these entities:\n\n{summary}"
202
+
203
+ elif any(w in message_lower for w in ['how much', 'spent', 'spending']):
204
+ return "To analyze your spending, please share your transaction messages or paste extracted JSON data."
205
+
206
+ elif any(w in message_lower for w in ['help', 'what can']):
207
+ return """I can help you with:
208
+
209
+ 1. **Extract Entities** - Paste a bank SMS/email and I'll extract the details
210
+ 2. **Batch Processing** - Process multiple messages at once
211
+ 3. **Analyze Spending** - Get insights from your transactions
212
+ 4. **Categorize** - Understand your spending categories
213
+
214
+ Try pasting a bank message like:
215
+ `HDFC Bank: Rs.2,500 debited from A/c XX1234 on 12-Jan-26. UPI:swiggy@ybl`"""
216
+
217
+ elif 'hello' in message_lower or 'hi' in message_lower:
218
+ return "Hello! πŸ‘‹ I'm FinEE, your financial entity extraction assistant. Paste a bank message and I'll extract the details!"
219
+
220
+ else:
221
+ # Try extraction as default
222
+ json_out, summary, status = extract_entities(message)
223
+ if summary and "No entities" not in summary:
224
+ return f"I found these in your message:\n\n{summary}"
225
+ else:
226
+ return "I'm not sure what you mean. Try pasting a bank SMS or email, or type 'help' for more options."
227
+
228
+
229
+ # ============================================================================
230
+ # GRADIO UI
231
+ # ============================================================================
232
+
233
+ def create_ui():
234
+ """Create the Gradio interface."""
235
+
236
+ # Custom CSS
237
+ custom_css = """
238
+ .gradio-container {
239
+ font-family: 'Inter', sans-serif !important;
240
+ }
241
+ .main-header {
242
+ text-align: center;
243
+ margin-bottom: 20px;
244
+ }
245
+ .output-json {
246
+ font-family: 'Monaco', 'Menlo', monospace !important;
247
+ }
248
+ """
249
+
250
+ with gr.Blocks(
251
+ title="FinEE - Financial Entity Extractor",
252
+ theme=gr.themes.Soft(
253
+ primary_hue="blue",
254
+ secondary_hue="gray",
255
+ ),
256
+ css=custom_css
257
+ ) as demo:
258
+
259
+ # Header
260
+ gr.Markdown("""
261
+ # 🏦 FinEE - Financial Entity Extractor
262
+
263
+ Extract structured data from Indian banking SMS, emails, and statements.
264
+
265
+ [![GitHub](https://img.shields.io/badge/GitHub-Repo-blue)](https://github.com/Ranjitbehera0034/Finance-Entity-Extractor)
266
+ [![HuggingFace](https://img.shields.io/badge/πŸ€—-Dataset-yellow)](https://huggingface.co/datasets/Ranjit0034/finee-dataset)
267
+ [![PyPI](https://img.shields.io/badge/PyPI-finee-orange)](https://pypi.org/project/finee/)
268
+ """)
269
+
270
+ with gr.Tabs():
271
+ # Tab 1: Single Extraction
272
+ with gr.Tab("πŸ” Extract", id="extract"):
273
+ with gr.Row():
274
+ with gr.Column(scale=1):
275
+ input_message = gr.Textbox(
276
+ label="Bank Message",
277
+ placeholder="Paste your bank SMS, email, or notification here...",
278
+ lines=4,
279
+ )
280
+
281
+ with gr.Row():
282
+ use_rag = gr.Checkbox(label="Use RAG", value=True, info="Context-aware extraction")
283
+ use_llm = gr.Checkbox(label="Use LLM", value=False, info="For complex cases")
284
+
285
+ extract_btn = gr.Button("Extract Entities", variant="primary")
286
+
287
+ # Examples
288
+ gr.Examples(
289
+ examples=[
290
+ "HDFC Bank: Rs.2,500 debited from A/c XX1234 on 12-Jan-26. UPI:swiggy@ybl. Ref:123456789012",
291
+ "SBI: Rs.15,000 credited to A/c XX4567 from rahul.sharma@oksbi. NEFT Ref: N987654321",
292
+ "ICICI: Your EMI of Rs.12,500 for Loan A/c XX8901 debited on 01-Jan-26",
293
+ "Axis Bank: Rs.999 debited for Netflix subscription. Card XX5678",
294
+ "Kotak: Rs.50,000 transferred to Zerodha Broking. Ref: 456789012345",
295
+ ],
296
+ inputs=input_message,
297
+ )
298
+
299
+ with gr.Column(scale=1):
300
+ status_output = gr.Textbox(label="Status", interactive=False)
301
+ summary_output = gr.Markdown(label="Summary")
302
+ json_output = gr.Code(label="JSON Output", language="json")
303
+
304
+ extract_btn.click(
305
+ extract_entities,
306
+ inputs=[input_message, use_rag, use_llm],
307
+ outputs=[json_output, summary_output, status_output]
308
+ )
309
+
310
+ # Tab 2: Batch Processing
311
+ with gr.Tab("πŸ“‹ Batch", id="batch"):
312
+ with gr.Row():
313
+ with gr.Column():
314
+ batch_input = gr.Textbox(
315
+ label="Messages (one per line)",
316
+ placeholder="Paste multiple messages, one per line...",
317
+ lines=10,
318
+ )
319
+ batch_rag = gr.Checkbox(label="Use RAG", value=True)
320
+ batch_btn = gr.Button("Process All", variant="primary")
321
+
322
+ with gr.Column():
323
+ batch_output = gr.Code(label="Results", language="json", lines=20)
324
+
325
+ batch_btn.click(
326
+ batch_extract,
327
+ inputs=[batch_input, batch_rag],
328
+ outputs=batch_output
329
+ )
330
+
331
+ # Tab 3: Analytics
332
+ with gr.Tab("πŸ“Š Analytics", id="analytics"):
333
+ with gr.Row():
334
+ with gr.Column():
335
+ analytics_input = gr.Code(
336
+ label="Transaction Data (JSON)",
337
+ language="json",
338
+ lines=15,
339
+ value="""[
340
+ {"amount": 2500, "type": "debit", "category": "food", "merchant": "Swiggy"},
341
+ {"amount": 15000, "type": "credit", "category": "transfer"},
342
+ {"amount": 999, "type": "debit", "category": "entertainment", "merchant": "Netflix"},
343
+ {"amount": 5000, "type": "debit", "category": "shopping", "merchant": "Amazon"}
344
+ ]"""
345
+ )
346
+ analyze_btn = gr.Button("Analyze", variant="primary")
347
+
348
+ with gr.Column():
349
+ analytics_output = gr.Markdown(label="Analysis Report")
350
+
351
+ analyze_btn.click(
352
+ analyze_transactions,
353
+ inputs=analytics_input,
354
+ outputs=analytics_output
355
+ )
356
+
357
+ # Tab 4: Chat
358
+ with gr.Tab("πŸ’¬ Chat", id="chat"):
359
+ chatbot = gr.Chatbot(
360
+ label="FinEE Assistant",
361
+ height=400,
362
+ placeholder="Ask me to extract entities or analyze your transactions..."
363
+ )
364
+
365
+ with gr.Row():
366
+ chat_input = gr.Textbox(
367
+ label="Message",
368
+ placeholder="Type a message or paste a bank SMS...",
369
+ scale=4
370
+ )
371
+ send_btn = gr.Button("Send", variant="primary", scale=1)
372
+
373
+ def respond(message, history):
374
+ if not message.strip():
375
+ return "", history
376
+ response = chat_response(message, history)
377
+ history.append((message, response))
378
+ return "", history
379
+
380
+ send_btn.click(respond, [chat_input, chatbot], [chat_input, chatbot])
381
+ chat_input.submit(respond, [chat_input, chatbot], [chat_input, chatbot])
382
+
383
+ # Tab 5: About
384
+ with gr.Tab("ℹ️ About", id="about"):
385
+ gr.Markdown("""
386
+ ## About FinEE
387
+
388
+ **FinEE (Financial Entity Extractor)** is a specialized NLP tool for extracting
389
+ structured information from Indian banking messages.
390
+
391
+ ### Features
392
+
393
+ - βœ… **Multi-Bank Support**: HDFC, ICICI, SBI, Axis, Kotak, and 20+ banks
394
+ - βœ… **All Transaction Types**: UPI, NEFT, IMPS, Credit Card, EMI
395
+ - βœ… **Multilingual**: English, Hindi, Tamil, Telugu, Bengali, Kannada
396
+ - βœ… **RAG Enhanced**: Context-aware extraction with merchant knowledge base
397
+ - βœ… **High Accuracy**: 95%+ on standard benchmarks
398
+
399
+ ### Output Schema
400
+
401
+ | Field | Type | Description |
402
+ |-------|------|-------------|
403
+ | amount | float | Transaction amount in INR |
404
+ | type | string | "debit" or "credit" |
405
+ | merchant | string | Business name (P2M) |
406
+ | beneficiary | string | Person name (P2P) |
407
+ | category | string | Transaction category |
408
+ | bank | string | Bank name |
409
+ | reference | string | UPI/NEFT reference |
410
+ | vpa | string | UPI VPA address |
411
+
412
+ ### Links
413
+
414
+ - πŸ“¦ **PyPI**: `pip install finee`
415
+ - πŸ€— **Dataset**: [Ranjit0034/finee-dataset](https://huggingface.co/datasets/Ranjit0034/finee-dataset)
416
+ - πŸ’» **GitHub**: [Ranjitbehera0034/Finance-Entity-Extractor](https://github.com/Ranjitbehera0034/Finance-Entity-Extractor)
417
+
418
+ ### Author
419
+
420
+ Built by **Ranjit Behera** | MIT License
421
+ """)
422
+
423
+ # Footer
424
+ gr.Markdown("""
425
+ ---
426
+ <center>
427
+ Made with ❀️ for the Indian fintech ecosystem
428
+ </center>
429
+ """)
430
+
431
+ return demo
432
+
433
+
434
+ # ============================================================================
435
+ # MAIN
436
+ # ============================================================================
437
+
438
+ def launch(share: bool = False, port: int = 7860):
439
+ """Launch the Gradio app."""
440
+ demo = create_ui()
441
+ demo.launch(share=share, server_port=port)
442
+
443
+
444
+ if __name__ == "__main__":
445
+ import argparse
446
+
447
+ parser = argparse.ArgumentParser(description="FinEE Gradio UI")
448
+ parser.add_argument("--share", action="store_true", help="Create public link")
449
+ parser.add_argument("--port", type=int, default=7860, help="Port to run on")
450
+
451
+ args = parser.parse_args()
452
+ launch(share=args.share, port=args.port)