CoolFace
Apppublic

Akshaya0810/invoice-processing-env

sourceHugging Faceupdated 5mo agoView on Hugging Face
0likes
App README

InvoiceProcessingEnv ๐Ÿงพ

OpenEnv benchmark for Accounts Payable Automation โ€” the first open environment that mirrors the full SAP Ariba / Coupa AP clerk workflow: extract โ†’ match โ†’ verify โ†’ approve/flag/reject.

![OpenEnv](https://openenv.dev) ![Python](https://python.org) ![FastAPI](https://fastapi.tiangolo.com)


๐ŸŽฏ Motivation

Every company's finance team processes hundreds of invoices daily. Real-world AP automation platforms (SAP Ariba, Coupa, Oracle Fusion) handle exactly this workflow โ€” yet no existing OpenEnv environment touches document-to-payment pipelines.

InvoiceProcessingEnv fills that gap:

FeatureDetail
Realistic dataIndian GST (GSTIN, HSN codes), real tax-rate schedules, FX rates
Fraud taxonomyOver-invoicing, fake vendor, duplicate invoice, currency mismatch
Dense RL signalPartial credit every step โ€” no sparse end-of-episode surprise
3-way PO matchInvoice โ†” PO โ†” vendor master (the SAP standard)

๐Ÿ—๏ธ Architecture

Agent (inference.py)
    โ”‚  OpenAI API (JSON actions)
    โ–ผ
FastAPI Server  POST /reset  POST /step  GET /state  GET /health
    โ”‚
    โ–ผ
InvoiceProcessingEnv  (app/env.py)
    โ”œโ”€โ”€ State machine per invoice  (PENDING โ†’ โ€ฆ โ†’ APPROVED/REJECTED/FLAGGED)
    โ”œโ”€โ”€ 6 automatic fraud detectors
    โ”œโ”€โ”€ RewardCalculator  (app/reward.py)
    โ””โ”€โ”€ Deterministic graders  (app/graders/)

๐Ÿ“‹ Observation Space

Every call to /step returns a structured Observation:

FieldTypeDescription
task_idstrCurrent task: easy, medium, hard
inboxlist[InvoiceMetadata]All invoices in this batch (full detail)
current_invoice_idstr \nullInvoice the agent is currently working on
extracted_fieldsExtractedFields \nullFields extracted so far
matched_poPurchaseOrder \nullMatched purchase order
compliance_flagslist[ComplianceFlag]Flags raised for current invoice
current_balancefloatRunning AP ledger balance (INR)
step_numberintSteps taken so far
invoices_resolvedintInvoices that reached a terminal state
invoices_remainingintInvoices still pending
messagestrHuman-readable status
last_action_errorstr \nullError from last action (if any)

โšก Action Space

Seven typed actions with an optional JSON payload:

ActionWhen to usePayload
EXTRACT_FIELDSFirst action on any PENDING invoiceoptional: field overrides
MATCH_TO_POAfter extraction{"po_id": "PO-XXX"}
VERIFY_TAX_COMPLIANCEAfter PO matchโ€”
APPROVE_PAYMENTAfter verification, if cleanโ€”
FLAG_DISCREPANCYWhen anomaly found{"flag_reason": "TAX_RATE_MISMATCH"}
REQUEST_MORE_INFOWhen data is missing{"message": "..."}
REJECTUnregistered vendor, confirmed fraudโ€”

Valid flag reasons: TAX_RATE_MISMATCH ยท DUPLICATE_INVOICE ยท OVER_INVOICING ยท UNREGISTERED_VENDOR ยท CURRENCY_MISMATCH ยท EXCEEDS_PO_AMOUNT ยท MISSING_PO_REFERENCE

Sequence enforcement: The environment validates action order. Attempting APPROVE_PAYMENT on a PENDING invoice returns a โˆ’0.05 penalty and an error in last_action_error.


๐Ÿ“Š Tasks

๐ŸŸข Easy (max 10 steps)

Single clean invoice (INV-EASY-001) from registered vendor Acme Supplies Ltd. Correct 18% GST on HSN 2710. Matching PO within budget. Perfect score = 1.0 if all key fields extracted and payment approved with zero flags.

๐ŸŸก Medium (max 20 steps)

Three invoices designed to test anomaly detection:

InvoiceIssueCorrect Decision
INV-MED-001CleanAPPROVE_PAYMENT
INV-MED-002HSN 5205 (cotton yarn) charged at 12% GST; correct rate is 5%FLAG_DISCREPANCY (TAXRATEMISMATCH)
INV-MED-003Same vendor, PO, total as INV-MED-001 โ€” 6-day date shiftFLAG_DISCREPANCY (DUPLICATE_INVOICE)

Grader: Extraction 40% ยท Correct decisions 40% ยท No false positives 20%

๐Ÿ”ด Hard (max 40 steps)

Eight-invoice batch with intentional fraud and FX edge cases:

InvoiceScenarioCorrect Decision
INV-HARD-001Clean INRAPPROVE_PAYMENT
INV-HARD-002Clean INRAPPROVE_PAYMENT
INV-HARD-003Over-invoiced 120 units (PO = 80)FLAG_DISCREPANCY (OVER_INVOICING)
INV-HARD-004Fake vendor V_FAKE, no POREJECT
INV-HARD-005Legitimate USD @ FX 83.50 โœ“APPROVE_PAYMENT
INV-HARD-006EUR @ 78.00 (correct 90.20, 13.5% off)FLAG_DISCREPANCY (CURRENCY_MISMATCH)
INV-HARD-007Subtle duplicate of INV-HARD-001 (8-day gap)FLAG_DISCREPANCY (DUPLICATE_INVOICE)
INV-HARD-008Legitimate USD @ FX 83.50 โœ“APPROVE_PAYMENT

Grader: 0.125 per correct decision ยท โˆ’0.30 missed fraud ยท โˆ’0.10 false positive ยท +0.15 bonus if under 30 steps


๐Ÿ’ฐ Reward Function

Dense signal every step โ€” agents get feedback on every action, not just at episode end.

EventDelta
Correct field extraction (ร— 5 key fields)+0.03 each โ†’ max +0.15
All 5 fields perfectbonus +0.05
PO match correct+0.10
Tax verification correct (no false alarm)+0.05
APPROVE on clean invoice+0.25
FLAG / REJECT on fraudulent invoice+0.25
False positive (flag on clean invoice)โˆ’0.10
Missed fraud (APPROVE on fraudulent)โˆ’0.20
Invalid action sequenceโˆ’0.05
Complete batch under step budget+0.30

Final score = grader_score from /state (independent of cumulative reward). Always in (0, 1).


๐Ÿš€ Setup & Usage

Local (no Docker)

bash
cd invoice-processing-env
pip install -r requirements.txt
uvicorn app.main:app --host 0.0.0.0 --port 7860

Docker

bash
docker build -t invoice-processing-env .
docker run -p 7860:7860 invoice-processing-env

Run inference

Note: The inference script connects to a running environment server. Start the server first (in a separate terminal), then run inference.
bash
# Terminal 1 โ€” start the environment server
uvicorn app.main:app --host 0.0.0.0 --port 7860
bash
# Terminal 2 โ€” run the inference agent
export HF_TOKEN=hf_xxxx
export MODEL_NAME=Qwen/Qwen2.5-72B-Instruct
export TASK_NAME=easy          # easy | medium | hard
export ENV_BASE_URL=http://localhost:7860
python inference.py

Run all three tasks:

bash
RUN_ALL_TASKS=true python inference.py

Run tests

bash
pip install pytest
python -m pytest tests/ -v

๐Ÿ“ก API Reference

EndpointMethodBodyDescription
/healthGETโ€”Liveness probe
/tasksGETโ€”List all tasks
/resetPOST{"task_id": "easy"}Start new episode
/stepPOSTAction JSONExecute one action
/stateGETโ€”Full state + grader score

`/reset` accepts empty body `{}` โ€” defaults to easy, satisfying the OpenEnv validator ping.


๐Ÿ“ˆ Baseline Scores (Qwen2.5-72B Zero-shot)

TaskScoreNotes
easy~0.85Rarely misses a field; occasionally skips verify step
medium~0.58Catches tax mismatch; misses subtle duplicate ~30% of the time
hard~0.38Hard fraud scenarios require multi-step reasoning; FX check is the key bottleneck

๐Ÿ—‚๏ธ Repository Structure

invoice-processing-env/
โ”œโ”€โ”€ openenv.yaml               # OpenEnv spec
โ”œโ”€โ”€ Dockerfile                 # HF Space container (port 7860)
โ”œโ”€โ”€ requirements.txt
โ”œโ”€โ”€ inference.py               # Mandatory inference script
โ”œโ”€โ”€ README.md
โ”œโ”€โ”€ app/
โ”‚   โ”œโ”€โ”€ main.py                # FastAPI app
โ”‚   โ”œโ”€โ”€ env.py                 # Core state machine
โ”‚   โ”œโ”€โ”€ models.py              # Pydantic models
โ”‚   โ”œโ”€โ”€ actions.py             # Action enum + sequence rules
โ”‚   โ”œโ”€โ”€ reward.py              # Reward calculator
โ”‚   โ”œโ”€โ”€ graders/
โ”‚   โ”‚   โ”œโ”€โ”€ __init__.py        # Grader dispatcher
โ”‚   โ”‚   โ”œโ”€โ”€ easy_grader.py
โ”‚   โ”‚   โ”œโ”€โ”€ medium_grader.py
โ”‚   โ”‚   โ””โ”€โ”€ hard_grader.py
โ”‚   โ””โ”€โ”€ data/
โ”‚       โ”œโ”€โ”€ vendors.json       # Vendor master (5 registered, V_FAKE absent)
โ”‚       โ”œโ”€โ”€ currency_rates.json
โ”‚       โ””โ”€โ”€ invoices/
โ”‚           โ”œโ”€โ”€ easy_task.json
โ”‚           โ”œโ”€โ”€ medium_task.json
โ”‚           โ””โ”€โ”€ hard_task.json
โ””โ”€โ”€ tests/
    โ””โ”€โ”€ test_env.py            # 15 pytest tests

title: Invoice Processing Env emoji: ๐Ÿ”ฅ colorFrom: purple colorTo: purple sdk: docker pinned: false license: mit ---

Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference