Team Ai
Apppublic

AffordableAI/Handwritten_Invoice_Processor

sourceHugging Facemitupdated 2y agoView on Hugging Face
0likes
app.py194 linesDownload Raw Back to root
1import gradio as gr2import os3from dotenv import load_dotenv4import pandas as pd5from groq import Groq6from PIL import Image7import base648import io9import openpyxl10from datetime import datetime11import httpx12 13# Load environment variables from .env file14load_dotenv()15 16def create_groq_client():17    api_key = os.environ.get("GROQ_API_KEY", "")18    return httpx.Client(19        base_url="https://api.groq.com/openai/v1",20        headers={"Authorization": f"Bearer {api_key}"}21    )22 23def encode_image_to_base64(image_path):24    """Convert image to base64 string"""25    with open(image_path, "rb") as image_file:26        return base64.b64encode(image_file.read()).decode('utf-8')27 28def extract_invoice_details(image):29    """Extract invoice details using Groq's vision model"""30    # Save the uploaded image temporarily31    temp_path = "temp_invoice.png"32    image.save(temp_path)33    34    # Convert image to base6435    base64_image = encode_image_to_base64(temp_path)36    37    # Remove temporary file38    os.remove(temp_path)39    40    # Prepare the prompt41    prompt = """Analyze this invoice image and provide ONLY ONE dictionary with the following format, including all line items. Remove any special characters (*, #, $) and format numbers as plain decimal values:42 43    {44        "Invoice Number": "inv-00",  # Remove special chars, keep alphanumeric only45        "Invoice Date": "07/07/2025",  # Use MM/DD/YYYY format46        "Items": [47            {48                "Item Name": "Product 1",  # Clean text only49                "Price/Rate": "40.00",  # Numeric only50                "Quantity": "2",  # Numeric only51                "Amount": "80.00"  # Numeric only52            }53        ],54        "Total Invoice Value": "2555.00"  # Numeric only, total amount55    }56 57    Provide ONLY the dictionary, no additional text or formatting."""58    59    # Make API call to Groq60    client = create_groq_client()61    response = client.post(62        "/chat/completions",63        json={64            "model": "llama-3.2-90b-vision-preview",65            "messages": [66                {67                    "role": "user",68                    "content": [69                        {70                            "type": "image_url",71                            "image_url": {72                                "url": f"data:image/png;base64,{base64_image}"73                            }74                        },75                        {76                            "type": "text",77                            "text": prompt78                        }79                    ]80                }81            ]82        }83    )84    response_data = response.json()85    return response_data['choices'][0]['message']['content']86 87def parse_response(response_text):88    """Parse the model's response into structured data"""89    try:90        # Find the dictionary part of the response91        start_idx = response_text.find('{')92        end_idx = response_text.rfind('}') + 193        if start_idx != -1 and end_idx != -1:94            dict_str = response_text[start_idx:end_idx]95            # Safely evaluate the dictionary string96            data = eval(dict_str)97            98            # Create rows for each item in the items list99            rows = []100            for item in data.get('Items', []):101                row = {102                    'Invoice Number': data.get('Invoice Number', ''),103                    'Invoice Date': data.get('Invoice Date', ''),104                    'Item Name': item.get('Item Name', ''),105                    'Price/Rate': item.get('Price/Rate', ''),106                    'Quantity': item.get('Quantity', ''),107                    'Amount': item.get('Amount', ''),108                    'Total Invoice Value': data.get('Total Invoice Value', '')109                }110                rows.append(row)111            112            return rows113    except Exception as e:114        print(f"Error parsing response: {e}")115        return [{116            'Invoice Number': '',117            'Invoice Date': '',118            'Item Name': '',119            'Price/Rate': '',120            'Quantity': '',121            'Amount': '',122            'Total Invoice Value': ''123        }]124 125def save_to_excel(data_rows):126    """Save cleaned extracted data to Excel file"""127    excel_file = "invoice_data.xlsx"128    129    # Create new DataFrame with the current data only130    df = pd.DataFrame(data_rows, columns=[131        'Invoice Number', 'Invoice Date', 'Item Name',132        'Price/Rate', 'Quantity', 'Amount', 'Total Invoice Value'133    ])134    135    # Apply number formatting for currency columns136    currency_columns = ['Price/Rate', 'Amount', 'Total Invoice Value']137    for col in currency_columns:138        df[col] = pd.to_numeric(df[col], errors='ignore')139    140    # Save to Excel with formatting141    with pd.ExcelWriter(excel_file, engine='openpyxl') as writer:142        df.to_excel(writer, index=False, sheet_name='Invoice Data')143        144        # Get the workbook and worksheet145        workbook = writer.book146        worksheet = writer.sheets['Invoice Data']147        148        # Apply currency formatting to relevant columns149        for col_idx, col_name in enumerate(df.columns):150            if col_name in currency_columns:151                for row in range(2, len(df) + 2):  # Start from row 2 to skip header152                    cell = worksheet.cell(row=row, column=col_idx + 1)153                    cell.number_format = '$#,##0.00'154    155    return excel_file156 157def process_invoice(image):158    """Main function to process invoice image"""159    try:160        # Extract text from image161        extracted_text = extract_invoice_details(image)162        163        # Parse the response164        data = parse_response(extracted_text)165        166        # Save to Excel167        excel_path = save_to_excel(data)168        169        return (170            f"Successfully processed invoice!\n\n"171            f"Extracted Information:\n{extracted_text}",172            excel_path173        )174    175    except Exception as e:176        return f"Error processing invoice: {str(e)}", None177 178# Create Gradio interface179iface = gr.Interface(180    fn=process_invoice,181    inputs=gr.Image(type="pil", label="Upload Handwritten Invoice"),182    outputs=[183        gr.Textbox(label="Processing Result"),184        gr.File(label="Download Excel File")185    ],186    title="Handwritten Invoice Processor",187    description="Upload a handwritten invoice to extract key information and save it to Excel.",188    examples=[],189    theme=gr.themes.Base()190)191 192# Launch the application193if __name__ == "__main__":194    iface.launch(server_name="0.0.0.0", server_port=7860)