Skip to content

Repository files navigation

Andromeda File Analyzer

Documented repository for the Andromeda File Analyzer: a Next.js front end, .NET 9 Web API, and Python invoice parsers that ingest files, extract invoice data, and store results in PostgreSQL.

In this web-based application, users can upload an invoice in the form of an image file. The image file will then be fed to an LLM (DonutAI or MinerU, the latter is a more functional option) of the user's choosing. The LLM will then extract all of the relevant information to a JSON format, which will then be available for the user to see. Once the user confirms that the information is correct, the JSON data will then be available to send to a database.

Users can upload multiple files to be fed into the LLM, and these can be viewed in a table or grid view on the main page. In addition, the user can sort these files by different values. On the backend, users can easily implement their own LLM to work with the web app through a python file.

Repository Map

  • api/ – ASP.NET Core Web API (Program.cs, EF Core models, controllers) that owns the database and file ingest endpoints.
  • api.Tests/ – xUnit tests that exercise the invoice workflow.
  • ai-demo/ – Python preprocessing scripts: app_mineru.py (MinerU pipeline) and app_donut.py (DonutAI sample).
  • ml-invoice-scraper/ – Next.js UI that uploads documents, reviews parsed results, and can send accepted invoices to another API.
  • Informational/API Contract.md – Original API contract and flows used to scope the project.

Prerequisites (new developer machine)

  • .NET 9 SDK
  • Node.js 18+ (for Next.js)
  • Python 3.10+ with pip (for MinerU/Donut scripts) and system dependencies required by MinerU
  • PostgreSQL 15+ running locally
  • git and a modern browser

Local Setup (new user path)

  1. Clone and install tools
    • Install the prerequisites above.
    • Optional: dotnet tool install --global dotnet-ef (to run migrations manually).
  2. Database
    • Create a local database/user, e.g.:
      • createdb MyAppDb
      • createuser user (or your own role) and give it access.
    • Set the connection string via either:
      • api/appsettings.Development.json -> ConnectionStrings.Postgres
      • or environment variable ConnectionStrings__Postgres="Host=localhost;Port=5433;Database=MyAppDb;Username=davis;Password=<pw>"
    • Tables are auto-created at API startup through db.Database.MigrateAsync(). You can also run cd api && dotnet ef database update.
    • (Optional Lakebase) To enable Databricks Lakehouse inserts, also set ConnectionStrings:Lakebase (or env ConnectionStrings__Lakebase) to a Databricks/Postgres connection string, e.g. Host=<databricks_host>;Port=5432;Database=databricks_postgres;Username=<user>;Password=<pw>;SSL Mode=Require.
  3. Python model helpers
    • cd ai-demo
    • Install dependencies for the chosen model (MinerU: pip install mineru loguru bs4 python-dateutil; Donut: pip install transformers accelerate pillow datasets). GPU acceleration is optional but recommended for performance.
    • If Python is not on PATH or scripts move, set env vars:
      • PYTHON_EXE=/full/path/to/python
      • PYTHON_SCRIPT=/full/path/to/app_mineru.py (or override in appsettings.* via PythonProcessing:ScriptPath).
  4. Run the API
    • cd api
    • dotnet restore
    • dotnet run --launch-profile http
  5. Run the Next.js UI
    • cd ml-invoice-scraper
    • Update .env.local NEXT_PUBLIC_API_BASE_URL to match the API base (defaults to http://localhost:5207/api).
    • npm install
    • npm run dev then open http://localhost:3000.

Backend API Highlights (api/)

  • Configuration: Program.cs reads ConnectionStrings:Postgres; optional PythonProcessing:PythonExecutable and PythonProcessing:ScriptPath override Python.
  • Entities / Tables (snake_cased in Postgres):
    • invoices: vendor/recipient contact info, description, date fields (invoice_date, due_date, discount_date, fee_date, file_date, ingest_date), money fields (subtotal, discount_percent, discount_amount, tax_percent, tax_amount). Defaults are "N/A" strings and 0 numerics; ingest_date defaults to now() at time zone 'utc'.
    • invoice_items: per-line items with item_name, quantity, price, total, description, and timestamp mirrors.
    • file_names: stored binaries and metadata (file_name, consolidated_file_name, content_type, file_data, FK invoice_id). Cascade delete removes children with their invoice.
  • Controllers:
    • POST /api/invoice-files - Upload a file (file form field) and optional model (MinerU or DonutAI). Stores binary, runs Python parser, and seeds invoice + items from the JSON output.
    • GET /api/invoice-files - List stored files (metadata only).
    • GET /api/invoice-files/{id} - Download a stored file.
    • DELETE /api/invoice-files/{id} - Remove file (and invoice if no other files remain).
    • POST /api/invoice-files/{id}/rescan - Re-run parsing on an already stored file.
    • POST /api/invoices - Create a blank invoice with defaults.
    • GET /api/invoices/{id} - Fetch invoice with items.
    • PUT /api/invoices/{id} - Update invoice fields and replace items.
  • Databricks Lakehouse / Lakebase bridge (from POC_dbricks_lakebase): LakebaseClient opens an Npgsql connection using ConnectionStrings:Lakebase (or env ConnectionStrings__Lakebase) and inserts into an invoices table that must expose: invoice_id, vendor_name, recipient_name, vendor_email, vendor_phone, recipient_email, recipient_phone, invoice_date, due_date, discount_date, fee_date, ingest_date, file_date, vendor_address, recipient_address, subtotal, discount_percent, discount_amount, tax_percent, tax_amount, description, created_at. Date fields are sent as ISO 8601 strings.
    • POST /api/lakebase/invoices writes whatever invoice payload you send and returns the Lakehouse id. Example: curl -X POST http://localhost:5207/api/lakebase/invoices -H "Content-Type: application/json" -d "{\"invoiceId\":\"123\",\"vendorName\":\"ACME\",\"recipientName\":\"Contoso\"}"
    • POST /api/lakebase/invoices/{invoiceId}/sync loads the invoice from the local Postgres database and forwards it to Lakebase with the same insert routine.

Front End (ml-invoice-scraper/)

  • Landing page lets users pick AI model (MinerU or DonutAI) and upload files; uploads hit /api/invoice-files.
  • Scans view pulls /api/invoice-files, shows previews, allows delete/rescan, and exposes "Upload Selected" to forward accepted invoices to Lakebase (or another target if you swap out the handler).
  • Uses NEXT_PUBLIC_API_BASE_URL for all backend calls; adjust when pointing to hosted APIs.
  • Assets (logos/background) live in public/; styling is primarily tailwind-based in React components.
  • Model options can be provided via NEXT_PUBLIC_MODELS as JSON (e.g., [{"label":"MinerU","value":"MinerU"},{"label":"Donut AI","value":"DonutAI"}]); otherwise the UI falls back to MinerU/Donut AI defaults.

Python Parsers (ai-demo/)

  • app_mineru.py runs the MinerU pipeline and normalizes invoice fields; defaults to resolving script from ../ai-demo/app_mineru.py.
  • app_donut.py loads the Donut model to extract invoice JSON from an image.
  • API resolves Python via PYTHON_EXE or PATH; logs stdout/stderr to help debug parser issues.

Adding Another AI Model

  • Flow: the UI sends a model form field to POST /api/invoice-files; InvoiceFilesController.ResolvePythonScriptPath picks the Python entrypoint based on that value and runs it with arguments <inputPath> <outputPath>. The API reads the JSON at outputPath (or falls back to stdout) and maps it into invoice fields.
  • Build a script: add a new CLI entrypoint in ai-demo/ (e.g., app_newmodel.py) that accepts the two args above and writes JSON. Aim to emit a data object with keys like vendor_name, vendor_email, vendor_phone, vendor_address, customer_name/recipient_name, invoice_date, due_date, subtotal, tax_amount, and an items array where each item has name, description, quantity, unitprice, and total. The extractor is tolerant of slight key differences (see InvoiceFilesController.TryExtractInvoiceDetails).
  • Wire it into the API: extend the switch in ResolvePythonScriptPath (api/Controllers/InvoiceFilesController.cs) to map your new model value to the new script name. If you prefer not to change code, you can temporarily point the existing PYTHON_SCRIPT or PythonProcessing:ScriptPath to your script and reuse an existing model name.
  • Update the UI: add the new model option to the dropdowns and TypeScript unions in ml-invoice-scraper/src/app/page.tsx and ml-invoice-scraper/src/app/scans/page.tsx. Ensure the model string you send matches the API switch case (case-insensitive).
  • Dependencies: document the new model's Python packages under the Python setup step and install them in ai-demo (e.g., pip install <packages>). Test with a local curl -F "file=@sample.pdf" -F "model=NewModel" http://localhost:5207/api/invoice-files.

Lakebase Uploads from the UI

  • The "Upload Selected" button (see ml-invoice-scraper/src/app/scans/page.tsx) now calls ${NEXT_PUBLIC_API_BASE_URL}/lakebase/invoices/{invoiceId}/sync for each accepted invoice ID, reusing the backend Lakebase sync endpoint.
  • Success/failure is surfaced via alerts; make sure the API base URL points to a backend with a valid ConnectionStrings:Lakebase or uploads will fail.
  • If you need to target a different downstream system, replace the fetch in handleUploadSelected with your own endpoint (optionally driven by an env var such as NEXT_PUBLIC_UPLOAD_ENDPOINT).

Operational Notes

  • Ports: API defaults to http://localhost:5207 (http profile) and https://localhost:5001 (https profile). UI defaults to http://localhost:3000.
  • CORS is permissive in Development; tighten policies before production.
  • Large files: POST /api/invoice-files allows up to ~50 MB via [RequestSizeLimit(50_000_000)].
  • Python temp files are cleaned after each request; ensure the service account has permission to write to the OS temp directory.

About

KE Andrews x SMU ML Invoice Scraper. Document scraper designed to scrape invoice data from receipts to structured PostGres data and post to Data Bricks Server

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages