qinxuqiang1990's picture
Rename gradio_ach_parser.py to app.py
bf34d90 verified
import gradio as gr
import pandas as pd
import re
from datetime import datetime
from typing import Dict, List, Optional
import json
class ACHTransactionParser:
def __init__(self):
# Define patterns for different transaction fields
self.patterns = {
'orig_co_name': r'ORIG CO NAME:\s*([^:]+?)(?=\s+ORIG ID:|$)',
'orig_id': r'ORIG ID:\s*([^\s]+)',
'desc_date': r'DESC DATE:\s*([^\s]+)',
'co_entry_descr': r'CO ENTRY DESCR:\s*([^\s]+)',
'sec_code': r'SEC:\s*([^\s]+)',
'trace_number': r'TRACE#:\s*([^\s]+)',
'effective_date': r'EED:\s*([^\s]+)',
'ind_id': r'IND ID:\s*([^:]*?)(?=\s+IND NAME:|$)',
'ind_name': r'IND NAME:\s*([^:]+?)(?=\s+TRN:|$)',
'transaction_ref': r'TRN:\s*([^\s]+)'
}
def parse_transaction(self, transaction_text: str) -> Dict[str, str]:
"""Parse a single transaction string and extract structured data"""
transaction_data = {}
for field, pattern in self.patterns.items():
match = re.search(pattern, transaction_text, re.IGNORECASE)
if match:
transaction_data[field] = match.group(1).strip()
else:
transaction_data[field] = None
# Clean up and format the data
transaction_data = self._clean_data(transaction_data)
return transaction_data
def _clean_data(self, data: Dict[str, str]) -> Dict[str, str]:
"""Clean and format the extracted data"""
# Format effective date if present
if data.get('effective_date'):
try:
date_str = data['effective_date']
if len(date_str) == 6: # YYMMDD format
year = '20' + date_str[:2]
month = date_str[2:4]
day = date_str[4:6]
formatted_date = f"{year}-{month}-{day}"
data['effective_date_formatted'] = formatted_date
except:
data['effective_date_formatted'] = data['effective_date']
# Clean up company and individual names
for field in ['orig_co_name', 'ind_name']:
if data.get(field):
data[field] = data[field].strip()
return data
def parse_multiple_transactions(self, text: str) -> List[Dict[str, str]]:
"""Parse multiple transactions from a text block"""
transactions = []
# Split by lines and process each potential transaction
lines = text.strip().split('\n')
for line in lines:
line = line.strip()
if line and ('ORIG CO NAME' in line or 'TRACE#' in line):
parsed = self.parse_transaction(line)
if any(parsed.values()): # Only add if we found some data
transactions.append(parsed)
return transactions
# Initialize the parser
parser = ACHTransactionParser()
def process_transactions(input_text):
"""Process the input text and return formatted results"""
if not input_text.strip():
return "Please paste your ACH transaction data above.", "", ""
try:
# Parse the transactions
transactions = parser.parse_multiple_transactions(input_text)
if not transactions:
return "No valid transactions found. Please check your input format.", "", ""
# Create formatted output
formatted_output = []
csv_data = []
for i, trans in enumerate(transactions):
formatted_output.append(f"=== Transaction {i+1} ===")
for key, value in trans.items():
if value: # Only show fields with values
display_key = key.replace('_', ' ').title()
formatted_output.append(f"{display_key}: {value}")
formatted_output.append("") # Empty line between transactions
# Prepare CSV row
csv_row = [
trans.get('effective_date_formatted', ''),
trans.get('orig_co_name', ''),
trans.get('ind_name', ''),
trans.get('co_entry_descr', ''),
trans.get('trace_number', ''),
trans.get('sec_code', ''),
trans.get('orig_id', ''),
trans.get('transaction_ref', '')
]
csv_data.append(csv_row)
# Create DataFrame for table display
df = pd.DataFrame(csv_data, columns=[
'Date', 'Originating Company', 'Individual Name',
'Description', 'Trace Number', 'SEC Code',
'Originating ID', 'Transaction Ref'
])
# Summary statistics
summary = f"""
πŸ“Š PARSING SUMMARY
==================
Total Transactions Processed: {len(transactions)}
Date Range: {df['Date'].min() if not df['Date'].empty else 'N/A'} to {df['Date'].max() if not df['Date'].empty else 'N/A'}
SEC Codes Found: {', '.join(df['SEC Code'].dropna().unique()) if not df['SEC Code'].empty else 'N/A'}
"""
return "\n".join(formatted_output), df, summary
except Exception as e:
return f"Error processing transactions: {str(e)}", "", ""
def clear_inputs():
"""Clear all inputs and outputs"""
return "", "Ready to process new transactions...", "", ""
# Sample data for demonstration
sample_data = """ORIG CO NAME:SUNDAY ADE CHAND ORIG ID:BNIAIDJA DESC DATE: CO ENTRY DESCR:WIRE2ACH SEC:PPD TRACE#:021000029427563 EED:250804 IND ID: IND NAME:INTELLIGENCE SCIENCE A TRN: 2169427563TC
ORIG CO NAME:TECH SOLUTIONS INC ORIG ID:TECHSOL1 DESC DATE: CO ENTRY DESCR:PAYROLL SEC:PPD TRACE#:021000029427564 EED:250805 IND ID:EMP001 IND NAME:JOHN DOE TRN: 2169427564TC"""
# Create the Gradio interface
with gr.Blocks(
title="ACH Transaction Parser",
theme=gr.themes.Soft(),
css="""
.main-header {
text-align: center;
background: linear-gradient(90deg, #1f2937, #3b82f6);
color: white;
padding: 20px;
border-radius: 10px;
margin-bottom: 20px;
}
.info-box {
background-color: #f0f9ff;
border: 1px solid #0ea5e9;
border-radius: 8px;
padding: 15px;
margin: 10px 0;
}
"""
) as demo:
# Header
gr.HTML("""
<div class="main-header">
<h1>🏦 ACH Transaction Parser Dashboard</h1>
<p>Parse and analyze ACH transaction data with ease</p>
</div>
""")
# Instructions
gr.HTML("""
<div class="info-box">
<h3>πŸ“‹ How to Use:</h3>
<ol>
<li>Copy your ACH transaction data from your bank or payment system</li>
<li>Paste it in the input box below</li>
<li>Click "Parse Transactions" to process the data</li>
<li>View the formatted results in the output sections</li>
</ol>
<p><strong>Supported Format:</strong> ORIG CO NAME:... ORIG ID:... DESC DATE:... etc.</p>
</div>
""")
with gr.Row():
with gr.Column(scale=1):
# Input section
gr.HTML("<h3>πŸ“₯ Input Section</h3>")
input_text = gr.Textbox(
label="Paste ACH Transaction Data Here",
placeholder="Paste your transaction data here...\n\nExample:\nORIG CO NAME:SUNDAY ADE CHAND ORIG ID:BNIAIDJA...",
lines=8,
max_lines=15
)
with gr.Row():
parse_btn = gr.Button("πŸ” Parse Transactions", variant="primary", size="lg")
clear_btn = gr.Button("πŸ—‘οΈ Clear All", variant="secondary")
sample_btn = gr.Button("πŸ“‹ Load Sample Data", variant="secondary")
# Output sections
gr.HTML("<h3>πŸ“€ Output Sections</h3>")
with gr.Row():
with gr.Column(scale=1):
summary_output = gr.Textbox(
label="πŸ“Š Summary",
lines=6,
interactive=False
)
with gr.Column(scale=1):
formatted_output = gr.Textbox(
label="πŸ“‹ Parsed Transaction Details",
lines=15,
max_lines=25,
interactive=False
)
# Data table
with gr.Row():
data_table = gr.Dataframe(
label="πŸ“Š Transaction Table",
interactive=False,
wrap=True
)
# Button actions
parse_btn.click(
fn=process_transactions,
inputs=[input_text],
outputs=[formatted_output, data_table, summary_output]
)
clear_btn.click(
fn=clear_inputs,
outputs=[input_text, formatted_output, data_table, summary_output]
)
sample_btn.click(
fn=lambda: sample_data,
outputs=[input_text]
)
# Footer
gr.HTML("""
<div style="text-align: center; margin-top: 30px; padding: 20px; background-color: #f8fafc; border-radius: 10px;">
<h4>πŸš€ Features</h4>
<p>βœ… Parse multiple transactions at once | βœ… Clean and format data | βœ… Export-ready table view | βœ… Summary statistics</p>
<p><em>Built with Gradio for easy deployment and sharing</em></p>
</div>
""")
# Launch the application
if __name__ == "__main__":
demo.launch(
server_name="0.0.0.0", # Allow external access
server_port=7860, # Default Gradio port
share=True, # Create public link
debug=True # Enable debug mode
)