1 of 49

2/26/2025

DocRouter.AI

Smart Doc Router

AI-powered document processing

that connects directly to your ERP

Andrei Radulescu-Banu

andrei@analytiqhub.com

DocRouter.AI

2 of 49

Consulting Background

Engineering Background

PhD in Mathematics, MIT

  • Digital Health
  • FinTech
  • Robotics
  • Large Language Models
  • Natural Language Processing
  • Computer Vision
  • Cloud Infrastructure
  • Data Lakes
  • Robotics, Self-Driving Cars

Andrei Radulescu-Banu

DocRouter.AI

3 of 49

Smart Document Router

  • The DocRouter.AI is a Document Understanding Tool (github)
  • It performs data extraction, at scale, for intelligent automation
  • It works with faxes, emails, and existing ERP systems, reducing processing time by up to 90% and eliminating costly errors.

DocRouter.AI

4 of 49

  • Versioned JsonSchema: key-values, arrays….
  • Prompts with:
    • Associated schema
    • LLM choice
    • Tags

Define Schema & Prompt

DocRouter.AI

5 of 49

Upload File -> Get Extraction

  • Upload docs, assign tag
  • … Runs OCR, LLM with prompt & schema (for all tagged prompts)
  • … Extraction can be highlighted and corrected

DocRouter.AI

6 of 49

Other ERP

Fax queue

Manual Workflows

DocRouter

Email queue

System of Record (e.g. ERP)

AI Workflows

  • Ingest selected documents and send to AI
  • AI enriches docs
  • Human performs review of data
  • DocRouter updates ERP

Human Review

AI

Workflows

A lightweight DocRouter installation

DocRouter.AI

7 of 49

DocRouter Architecture

Next.js

Client

Next.js

Server

MongoDB

FastAPI

(python)

Python

workers

Python

workers

Python

workers

LiteLLM

OCR

OpenAI

Anthropic

Gemini…

DocRouter.AI

8 of 49

Tech Stack

👉 React, TailwindCSS, Next,js, NextAuth

👉 FastAPI, Pydantic

👉 AWS, MongoDB

👉 LiteLLM

👉 OpenAI, Anthropic, Gemini, Groq/DeepSeek

Text editor: Cursor

DocRouter.AI

9 of 49

React in Smart Doc Router

Component-Based Architecture

  • UI is built from reusable, independent components
  • Example: The extraction page combines Layout, PDFLeftSidebar and PDFViewer components

State Management & Hooks

  • Components maintain their own state using useState and useEffect
  • Example: PDFViewer manages:

Real-Time UI Updates

  • React's virtual DOM efficiently updates only what changes
  • Example: The PDFViewer updates in real-time as users:
    • Search extractions
    • Adjust document zoom/rotation
    • Page up/down

PDFLeftSidebar

PDFViewer

Layout

DocRouter.AI

10 of 49

Layout.tsx

PDFLeftSidebar

PDFViewer

Layout

XML-like tags are called JSX

Can be referenced elsewhere as

<Layout> </Layout>

Contents is {children} prop

DocRouter.AI

11 of 49

JSX in React

Component Tags

  • Capitalized tags represent React components

HTML Tags

  • Lowercase tags represent HTML elements

JSX gets transformed into regular JavaScript function calls during the build process. For example:

Use className instead of class b/c class is reserved in JavaScript

Tailwind utility classes

npm run build

DocRouter.AI

12 of 49

  • Built-in responsive design

  • Cursor AI editor very familiar with Tailwind

Tailwind vs CSS

  • Tailwind is CSS, but utility-first
  • Consistent spacing/color values

  • A more efficient way to to write CSS for most use cases, while still allowing traditional CSS when needed

DocRouter.AI

13 of 49

Essential Tailwind in the Doc Router

  • Basic layout

  • State & responsiveness

That's it! These cover 80% of the layout patterns in the codebase. Everything else builds on these basics.

Key Points:

  • Flex for layout structure
  • m/p for spacing
  • hover: for interactions
  • md: for responsive
  • Dynamic classes with template literals

DocRouter.AI

14 of 49

Design UI with Cursor

Just prompt Cursor explaining the problem, and ask for 3 options for solutions

Pick specific files that Cursor can focus on

I want ability to edit field description

DocRouter.AI

15 of 49

1st option

Description field not editable… More prompting needed to solve this.

DocRouter.AI

16 of 49

2nd option

Description field did not expand… More prompting needed to solve this.

DocRouter.AI

17 of 49

3rd option

Modal button is functional!

DocRouter.AI

18 of 49

Tech Stack - Next.js

👉 React, TailwindCSS, Next.js, NextAuth

👉 FastAPI, Pydantic

👉 AWS, MongoDB

👉 LiteLLM

👉 OpenAI, Anthropic, Gemini, Groq/DeepSeek

Text editor: Cursor

DocRouter.AI

19 of 49

DocRouter Architecture

Next.js

Client

Next.js

Server

MongoDB

FastAPI

(python)

Python

workers

Python

workers

Python

workers

LiteLLM

OCR

OpenAI

Anthropic

Gemini…

DocRouter.AI

20 of 49

Next.js Benefits Over Plain React

1. Server-Side Rendering (SSR) & Static Site Generation (SSG)

  • Pre-2020 React Limitation: Only client-side rendering, leading to slower initial loads and poor SEO
  • Next.js Solution: Pages can be pre-rendered on the server, providing:
    • Faster page loads
    • Better SEO as search engines see complete HTML
    • Reduced client-side JavaScript

2. File-based Routing

  • React Limitation: Requires manual route setup with React Router
  • Next.js Solution: Automatic routing based on file structure in app/ directory

3. API Routes

  • React Limitation: Needs separate backend server
  • Next.js Solution: Built-in API routes in app/api/ directory

DocRouter.AI

21 of 49

DocRouter Project Structure

Next.js frontend

FastAPI backend

Why FastAPI as back end?

  • Next.js has its own server-side back end
  • … However, this is a data science tool
  • … Python more appropriate

DocRouter.AI

22 of 49

Server vs. Client Component Example

Upload page (server)

DocumentUpload component (client)

DocumentUpload component (client)

Upload page (server)

DocRouter.AI

23 of 49

When to use Server vs. Client Components?

DocRouter.AI

24 of 49

Tech Stack - NextAuth

👉 React, TailwindCSS, Next.js, NextAuth

👉 FastAPI, Pydantic

👉 AWS, MongoDB

👉 LiteLLM

👉 OpenAI, Anthropic, Gemini, Groq/DeepSeek

Text editor: Cursor

DocRouter.AI

25 of 49

NextAuth.js

  • NextAuth provides template auth.ts
  • Implement signIn(), jwt(), session()
  • Set up OAuth in
    • Google cloud
    • Github organization
  • Save user/pass/OAuth token in MongoDB
  • JWT session token verified by
    • Middleware (Next.js route protection)
    • FastAPI
  • … Be careful with NextAuth version!

DocRouter.AI

26 of 49

Flow of Events: NextAuth.js Login

User logs in

Next.js server checks Mongo for creds, creates JWT and session. NextAuth callbacks are called.

Next.js

Client

Next.js

Server

MongoDB

FastAPI

(python)

Python

workers

Python

workers

Python

workers

LiteLLM

OCR

OpenAI

Anthropic

Gemini…

1

2

1

2

DocRouter.AI

27 of 49

Tech Stack - FastAPI

👉 React, TailwindCSS, Next.js, NextAuth

👉 FastAPI, Pydantic

👉 AWS, MongoDB

👉 LiteLLM

👉 OpenAI, Anthropic, Gemini, Groq/DeepSeek

Text editor: Cursor

DocRouter.AI

28 of 49

FastAPI

Next.js

Client

Next.js

Server

MongoDB

FastAPI

(python)

Python

workers

Python

workers

Python

workers

LiteLLM

OCR

OpenAI

Anthropic

Gemini…

Any UI function is available

as REST Api in FastAPI

DocRouter.AI

29 of 49

FastAPI

FastAPI is a Python web framework typically used for RestAPIs.

It auto-generates OpenAPI (Swagger) documentation.

Basic Structure

Starts web server for FastAPI

@app

decorator

async keyword

DocRouter.AI

30 of 49

async, await, coroutines

  • async: Marks a function as asynchronous
  • await: Used inside async functions to wait for other async operations to complete
  • Background event loop keeps track of everything awaited.
  • Foreground thread yields to background thread until async operation completes

Async routines are called coroutines.

  • Always await a coroutine.

DocRouter.AI

31 of 49

await Is Syntactic Sugar For yield

  • Python generators can pause/resume execution with yield
  • Coroutines are built on top of generators
  • await is syntactic sugar for yielding to the event loop
  • The event loop manages the task scheduling

The event loop:

  1. Runs this until it hits a yield
  2. Switches to other tasks
  3. Comes back when the operation completes
  4. Resumes from where it left off

This is why async code can handle many operations efficiently without using multiple threads - it's all running in a single thread, just intelligently switching between tasks whenever they're waiting for I/O.

Async/await ultimately relies on non-blocking system calls, primarily select(), poll(), or epoll() (on Linux) for network operations.

DocRouter.AI

32 of 49

async - How To Start The Event Loop

In FastAPI:

  • Event loop started implicitly by uvicorn.run()

In workers:

  • Event loop manually started by asyncio.run()

Starts async event loop

Calls coroutines in parallel,

Returns when all have completed

DocRouter.AI

33 of 49

Workers

Next.js

Client

Next.js

Server

MongoDB

FastAPI

(python)

Python

workers

Python

workers

Python

workers

LiteLLM

OCR

OpenAI

Anthropic

Gemini…

worker_ocr

  • Calls AWS Textract
  • Saves OCR output in Mongo
  • Posts message to worker_llm when done

worker_llm

  • Polls for messages from worker_ocr
  • Gets prompt, schema, OCR output from Mongo
  • Calls LiteLLM
  • Saves LLM output in Mongo

DocRouter.AI

34 of 49

FastAPI - The @app Decorator

  • First, app = FastAPI() creates a new FastAPI application instance
  • @app.get("/version") is a decorator that tells FastAPI:
    • This is a route/endpoint
    • It should respond to GET requests
    • The URL path is "/version"

Here's what it looks like without the decorator syntax:

DocRouter.AI

35 of 49

Tech Stack - Pydantic

👉 React, TailwindCSS, Next.js, NextAuth

👉 FastAPI, Pydantic

👉 AWS, MongoDB

👉 LiteLLM

👉 OpenAI, Anthropic, Gemini, Groq/DeepSeek

Text editor: Cursor

DocRouter.AI

36 of 49

  • FastAPI handler for uploading docs

FastAPI - @app handlers and Pydantic Schema

  • CURL command to upload docs

Pydantic schema for DocumentsUpload body

organization_id parsed automatically and passed in as arg

DocRouter.AI

37 of 49

Pydantic Schema Is Also Used For LLM Structured Output

  • All major LLMs support Structured Output
  • LLM output schema specified as JSON Schema
  • Pydantic classes:
    • SchemaConfig, for the named schema
    • ResponseFormat, for schema contents
      • Uses validate_json_schema() to validate OpenAI format

DocRouter.AI

38 of 49

Tech Stack - AWS, MongoDB

👉 React, TailwindCSS, Next.js, NextAuth

👉 FastAPI, Pydantic

👉 AWS, MongoDB

👉 LiteLLM

👉 OpenAI, Anthropic, Gemini, Groq/DeepSeek

Text editor: Cursor

DocRouter.AI

39 of 49

Tech Stack - AWS

AWS

  • Services: Textract for OCR, SES for email, S3 for storage, Lightsail for hosting
  • Configured through Terraform

In a nutshell:

  • I can do everything in AWS (there’s a service for everything!)
  • Problems
    • 2-3 ways to solve every problem
    • Permissions are hard

DocRouter.AI

40 of 49

Tech Stack - MongoDB

MongoDB

  • Collections of json objects
  • Scales horizontally very well
  • Eventually consistent
  • Supports transactions
  • Python, JavaScript APIs
  • Sync and async APIs
  • Can implement queues, pub/sub with Mongo primitives

Compass UI Front-End

DocRouter.AI

41 of 49

Tech Stack - MongoDB

MongoDB

  • Can implement document store (like AWS S3) using GridFS
  • Can implement queues, pub/sub with Mongo primitives

Example send_msg()

Example rcv_msg()

(Supports horizontal scaling of readers)

DocRouter.AI

42 of 49

Diagram Flow: Schema and Prompt config

User adds schema in the UI

Next.JS client calls FastAPI

FastAPI saves schema in Mongo

Same steps for adding prompts, except prompts have associated schema, LLM and tags.

Next.js

Client

Next.js

Server

MongoDB

FastAPI

(python)

Python

workers

Python

workers

Python

workers

LiteLLM

OCR

OpenAI

Anthropic

Gemini…

1

2

3

1

2

3

DocRouter.AI

43 of 49

Diagram Flow: Doc upload, LLM run

Tagged document is uploaded

Next.JS client calls FastAPI

Message posted to workers to run OCR

OCR is run, output saved in Mongo

Worker retrieves prompt, schema, OCR output and runs LLM

LLM output saved to Mongo then displayed in UI

Next.js

Client

Next.js

Server

MongoDB

FastAPI

(python)

Python

workers

Python

workers

Python

workers

LiteLLM

OCR

OpenAI

Anthropic

Gemini…

1

2

5

1

2

3

3

4

4

5

DocRouter.AI

44 of 49

Tech Stack - LiteLLM

👉 React, TailwindCSS, Next.js, NextAuth

👉 FastAPI, Pydantic

👉 AWS, MongoDB

👉 LiteLLM

👉 OpenAI, Anthropic, Gemini, Groq/DeepSeek

Text editor: Cursor

DocRouter.AI

45 of 49

  • Call 100+ LLMs using an OpenAI-like API
  • Can be used as python module, or LLM Gateway
    • We use it as python module
  • Supports structured output, pdf attachments, img attachments…
  • Supports embeddings, image generation…

LiteLLM

Using sync litellm API

Using async litellm API

DocRouter workers use async API, to handle docs in parallel

  • LiteLLM = minimal portable interface to all LLMs
  • DocRouter = minimal schema & prompt mgmt over LiteLLM

DocRouter.AI

46 of 49

LLM Model Choice (Feb ‘24)

  • gpt-4.0: start with this
    • …But in production, move to less expensive models!
    • Users are rate-limited until they spend more $$
  • gemini-2.0-flash:
    • Fraction of the cost of gpt-4.0
    • Almost as good
    • Best choice in most cases
  • gpt-4.0-mini: less expensive, large context window, usually solves problem
  • groq/deepseek-r1-distill-llama-70b
    • Almost as good as gpt-4.0
    • Groq is very fast
  • claude-3.5 (soon 3.7)
    • Cursor uses them! Great for coding, also great for everything!

LiteLLM supports over 100 models

DocRouter.AI

47 of 49

Example Cursor Prompts

  • I keep all FastAPIs in main.py and wrap all JavaScript FastAPI calls in api.ts
    • Not best ‘manual’ programming practice
    • Better ‘classic’ design is to break large main.py, api.ts into multiple files.
  • Single large file makes it simpler for Cursor to locate all code.
    • ‘Index lookup’ step skipped

I discovered one JavaScript API call was not in api.ts… Had to be fixed manually.

Prompt Cursor to make all FastAPI paths start with “/v0/…”

DocRouter.AI

48 of 49

Thank you!

DocRouter.AI

49 of 49

References

DocRouter.AI