1. Introduction
This tutorial will guide you through using the JamAI Base SDK to create a simple receipt information extraction system.
What We'll Build
Snap a photo of your receipt and let AI do the expense report for you!
In this tutorial, we'll create a receipt processing system that:
Takes a receipt image as input
Uploads it to JamAI Base action table
Extracts key information like:
Prerequisites
Before starting, you'll need:
Python 3.10 or higher installed
Project ID and Personal Access Token (PAT)
2. Installation and Setup
Installing the SDK
Copy pip install jamaibase
Basic Configuration
Get your Personal Access Token (PAT) here:
Get your Project ID here:
Copy from jamaibase import JamAI, protocol as p
PROJECT_ID = "your_project_id"
PAT = "your_PAT"
client = JamAI(
project_id=PROJECT_ID,
token=PAT
)
3. Creating Your Action Table
For simplicity, you can set up your action table in the JamAI Base platform:
Navigate to your JamAI Base action table tab
Create a new action table named "receipt"
Configure the following columns:
Copy Input Column:
- Name: "Image"
- Type: FILE
Output Columns:
- Name: "Shop Name"
Type: str
☑️ Output checkbox enabled
- Name: "Total"
Type: str
☑️ Output checkbox enabled
4. Basic Implementation
4.1 Simple Receipt Processor
Copy def process_single_receipt(image_path):
# Upload image file
file_response = client.file.upload_file(image_path)
# Process in action table
response = client.table.add_table_rows(
table_type=p.TableType.action,
request=p.RowAddRequest(
table_id="receipt",
data=[{"Image": file_response.uri}],
stream=False,
),
)
# Extract results
return {
"shop_name": response.rows[0].columns["Shop Name"].text,
"total": response.rows[0].columns["Total"].text
}
4.2 Complete Implementation with Error Handling
Copy import os
from typing import Dict, Optional
class ReceiptProcessor:
def __init__(self, project_id: str, pat: str):
self.client = JamAI(
project_id=project_id,
token=pat
)
def validate_image(self, image_path: str) -> bool:
"""Validate if file exists and has correct extension"""
if not os.path.exists(image_path):
raise FileNotFoundError(f"Image not found: {image_path}")
valid_extensions = ['.jpg', '.jpeg', '.png', '.webp', '.gif']
file_ext = os.path.splitext(image_path)[1].lower()
if file_ext not in valid_extensions:
raise ValueError(f"Unsupported file format. Use: {valid_extensions}")
return True
def process_receipt(self, image_path: str) -> Optional[Dict[str, str]]:
"""Process a single receipt image"""
try:
# Validate image
self.validate_image(image_path)
# Upload file
print("Uploading image...")
file_response = self.client.file.upload_file(image_path)
print(f"Upload successful: {file_response.uri}")
# Process in action table
print("Processing receipt...")
response = self.client.table.add_table_rows(
table_type=p.TableType.action,
request=p.RowAddRequest(
table_id="receipt",
data=[{"Image": file_response.uri}],
stream=False,
),
)
# Extract and return results
results = {
"shop_name": response.rows[0].columns["Shop Name"].text,
"total": response.rows[0].columns["Total"].text
}
print("Processing complete!")
return results
except Exception as e:
print(f"Error processing receipt: {str(e)}")
return None
5. Usage Examples
5.1 Basic Usage
Copy # Initialize processor
processor = ReceiptProcessor(PROJECT_ID, PAT)
# Process single receipt
result = processor.process_receipt("path/to/receipt.jpg")
if result:
print(f"Shop Name: {result['shop_name']}")
print(f"Total: {result['total']}")
5.2 Batch Processing
Copy def process_receipt_batch(receipt_folder: str):
processor = ReceiptProcessor(PROJECT_ID, PAT)
results = []
for filename in os.listdir(receipt_folder):
if filename.lower().endswith(('.jpg', '.jpeg', '.png', '.webp', '.gif')):
image_path = os.path.join(receipt_folder, filename)
result = processor.process_receipt(image_path)
if result:
results.append({
"filename": filename,
**result
})
return results
# Usage
results = process_receipt_batch("path/to/receipt/folder")
for result in results:
print(f"File: {result['filename']}")
print(f"Shop: {result['shop_name']}")
print(f"Total: {result['total']}")
print("---")
6. Best Practices
Error Handling
Always validate input files
Handle network errors gracefully
Performance
Reuse the client instance
Consider batch processing for multiple files
Implement rate limiting for large batches
Security
Use environment variables for credentials
Complete Standalone Example
Save this as receipt_processor.py
:
Copy import os
import argparse
from jamaibase import JamAI, protocol as p
from typing import Dict, Optional
class ReceiptProcessor:
def __init__(self, project_id: str, pat: str):
self.client = JamAI(
project_id=project_id,
token=pat
)
def validate_image(self, image_path: str) -> bool:
if not os.path.exists(image_path):
raise FileNotFoundError(f"Image not found: {image_path}")
valid_extensions = ['.jpg', '.jpeg', '.png']
file_ext = os.path.splitext(image_path)[1].lower()
if file_ext not in valid_extensions:
raise ValueError(f"Unsupported file format. Use: {valid_extensions}")
return True
def process_receipt(self, image_path: str) -> Optional[Dict[str, str]]:
try:
self.validate_image(image_path)
print(f"Processing receipt: {image_path}")
print("Uploading image...")
file_response = self.client.file.upload_file(image_path)
print(f"Upload successful!")
print("Extracting information...")
response = self.client.add_table_rows(
table_type=p.TableType.action,
request=p.RowAddRequest(
table_id="receipt",
data=[{"Image": file_response.uri}],
stream=False,
),
)
results = {
"shop_name": response.rows[0].columns["Shop Name"].text,
"total": response.rows[0].columns["Total"].text
}
return results
except Exception as e:
print(f"Error: {str(e)}")
return None
def process_folder(folder_path: str, processor: ReceiptProcessor) -> None:
"""Process all receipts in a folder"""
if not os.path.exists(folder_path):
print(f"Folder not found: {folder_path}")
return
results = []
for filename in os.listdir(folder_path):
if filename.lower().endswith(('.jpg', '.jpeg', '.png')):
image_path = os.path.join(folder_path, filename)
result = processor.process_receipt(image_path)
if result:
results.append({
"filename": filename,
**result
})
# Print results in a formatted way
print("\nProcessing Results:")
print("-" * 50)
for result in results:
print(f"File: {result['filename']}")
print(f"Shop Name: {result['shop_name']}")
print(f"Total: {result['total']}")
print("-" * 50)
def main():
# Set up argument parser
parser = argparse.ArgumentParser(description='Process receipt images using JamAIBase')
parser.add_argument('--project-id', required=True, help='Your JamAIBase project ID')
parser.add_argument('--pat', required=True, help='Your Personal Access Token')
parser.add_argument('--input', required=True, help='Path to image file or folder')
args = parser.parse_args()
# Initialize processor
processor = ReceiptProcessor(args.project_id, args.pat)
# Process input
if os.path.isfile(args.input):
# Single file processing
result = processor.process_receipt(args.input)
if result:
print("\nResults:")
print("-" * 50)
print(f"Shop Name: {result['shop_name']}")
print(f"Total: {result['total']}")
print("-" * 50)
else:
# Folder processing
process_folder(args.input, processor)
if __name__ == "__main__":
main()
How to Run
Save the code above as receipt_processor.py
Install required package:
Copy pip install jamaibase
Run for a single receipt:
Copy python receipt_processor.py --project-id "your_project_id" --pat "your_pat" --input "path/to/receipt.jpg"
Run for a folder of receipts:
Copy python receipt_processor.py --project-id "your_project_id" --pat "your_pat" --input "path/to/receipt/folder"
Example Output
Copy Processing receipt: 20240920_033000.jpg
Uploading image...
Upload successful!
Extracting information...
Results:
--------------------------------------------------
Shop Name: Burger King
Total: 523
--------------------------------------------------
Features
Processes single images or entire folders
Validates file types and existence
Provides clear progress feedback
Formats results in an easy-to-read way
Command-line argument support
This standalone example provides a complete, working implementation that you can use as a starting point for your own projects or modify according to your needs.