Spaces:
Sleeping
Sleeping
File size: 4,458 Bytes
8c33e8e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | """
Cost tracking utility for Invoice OCR system
Tracks Document AI and Gemini API usage costs
"""
from typing import Dict, Any
from datetime import datetime
import json
from pathlib import Path
class CostTracker:
"""Track and calculate costs for Document AI + Gemini usage"""
# Pricing (as of 2025)
# Document AI OCR: $1.50 per 1,000 pages = $0.0015 per page
DOCUMENT_AI_PER_PAGE = 0.0015 # Document OCR: $1.50 per 1,000 pages
# Gemini 2.0 Flash (includes text, images, and videos)
GEMINI_INPUT_PER_TOKEN = 0.10 / 1_000_000 # $0.10 per 1M tokens (input)
GEMINI_OUTPUT_PER_TOKEN = 0.40 / 1_000_000 # $0.40 per 1M tokens (output)
def __init__(self):
self.usage_log = []
self.log_file = Path("usage_costs.json")
self.load_usage()
def estimate_tokens(self, text: str) -> int:
"""Estimate token count (roughly 1 token per 4 characters)"""
return len(text) // 4
def calculate_invoice_cost(
self,
input_tokens: int = None,
output_tokens: int = None,
input_text: str = None,
output_text: str = None,
includes_image: bool = True
) -> Dict[str, float]:
"""
Calculate cost for processing one invoice
Args:
input_tokens: Number of input tokens (if known)
output_tokens: Number of output tokens (if known)
input_text: Input text to estimate tokens from
output_text: Output text to estimate tokens from
includes_image: Whether image is sent to Gemini (adds ~258 tokens)
Returns:
Dictionary with cost breakdown
"""
# Estimate tokens if not provided
if input_tokens is None and input_text:
input_tokens = self.estimate_tokens(input_text)
# Add image tokens if image is included
if includes_image:
input_tokens += 258 # Approximate tokens for image vision
if output_tokens is None and output_text:
output_tokens = self.estimate_tokens(json.dumps(output_text))
# Default estimates if nothing provided (invoices typically larger)
input_tokens = input_tokens or 2000 # Invoices have more text
output_tokens = output_tokens or 800 # More line items
# Calculate costs
docai_cost = self.DOCUMENT_AI_PER_PAGE
gemini_input_cost = input_tokens * self.GEMINI_INPUT_PER_TOKEN
gemini_output_cost = output_tokens * self.GEMINI_OUTPUT_PER_TOKEN
gemini_total = gemini_input_cost + gemini_output_cost
total_cost = docai_cost + gemini_total
return {
"document_ai": docai_cost,
"gemini_input": gemini_input_cost,
"gemini_output": gemini_output_cost,
"gemini_total": gemini_total,
"total": total_cost,
"tokens": {
"input": input_tokens,
"output": output_tokens,
"total": input_tokens + output_tokens
}
}
def print_invoice_cost(self, costs: Dict[str, float]):
"""Pretty print cost for an invoice"""
print("\n" + "="*70)
print("💰 INVOICE PROCESSING COST")
print("="*70)
print(f"Document AI OCR: ${costs['document_ai']:.6f}")
print(f"Gemini Input: ${costs['gemini_input']:.6f} ({costs['tokens']['input']:,} tokens)")
print(f"Gemini Output: ${costs['gemini_output']:.6f} ({costs['tokens']['output']:,} tokens)")
print("-" * 70)
print(f"TOTAL COST: ${costs['total']:.6f} ({costs['tokens']['total']:,} tokens)")
print("="*70 + "\n")
def save_usage(self):
"""Save usage log to file"""
try:
with open(self.log_file, 'w') as f:
json.dump(self.usage_log, f, indent=2)
except Exception as e:
print(f"Warning: Could not save usage log: {e}")
def load_usage(self):
"""Load usage log from file"""
try:
if self.log_file.exists():
with open(self.log_file, 'r') as f:
self.usage_log = json.load(f)
except Exception as e:
print(f"Warning: Could not load usage log: {e}")
self.usage_log = []
|