Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AI Finance Officer

An autonomous AI agent that handles customer quotation workflows end-to-end, with a mandatory human-in-the-loop approval gate before any email is sent.

A customer sends a quote request by email. The AI Finance Officer reads it, searches inventory, calculates pricing with bulk discounts, drafts a professional quotation email, and pauses for human approval via Telegram. Only after explicit approval does it send the email.

Every action is logged to an auditable step trace.


What It Does

  1. Ingests requests — Reads quote requests from incoming emails or manual triggers
  2. Checks inventory — Semantic search over a product catalog stored in Qdrant Cloud
  3. Calculates quotes — Applies line-item pricing and automatic 5% bulk discounts for quantities over 100
  4. Drafts emails — Generates professional HTML quotation emails with styled tables
  5. Requests approval — Sends a structured summary to a human approver via Telegram with Approve/Reject buttons
  6. Sends on approval — Dispatches the email via Gmail SMTP only after explicit human consent
  7. Logs everything — Every tool call is recorded as a step in Neon Postgres for full auditability

Architecture

Customer Request
      |
      v
FastAPI Backend  ------>  Ollama (External LLM)
      |                          |
      |----> Qdrant Cloud        |
      |----> Neon PostgreSQL     |
      |----> Upstash Redis       |
      |
      v
Telegram Bot  <----  Human Approver
      |
      v
Gmail SMTP  ------>  Customer Inbox

Tech Stack

Layer Technology
Backend API FastAPI, SQLAlchemy, Alembic, Pydantic Settings
AI / LLM Ollama (kimi-k2.6:cloud) with tool-calling and text-parsing fallback
Vector Search Qdrant Cloud (product embedding and semantic search)
Database Neon PostgreSQL (tasks, employees, approvals, audit steps)
Cache Upstash Redis
Embedding External OpenAI-compatible Embedding API
Approval Channel Telegram Bot API (inline keyboard buttons)
Email Delivery Gmail SMTP with multipart HTML + plain text
Dashboard Next.js 14, TypeScript, Tailwind CSS, lucide-react
Infrastructure Managed cloud services (Neon, Qdrant Cloud, Upstash)

Prerequisites

Requirement How to Obtain
Ollama host ollama.com — run ollama pull kimi-k2.6:cloud on a reachable host
Neon account neon.tech — create a PostgreSQL project
Qdrant Cloud account qdrant.tech/cloud — create a cluster
Upstash Redis account upstash.com — create a Redis database
Embedding API provider OpenAI, Jina AI, Cohere, etc. — obtain an API key
Telegram Bot Token Message @BotFather on Telegram
Telegram Chat ID Message @userinfobot on Telegram
Gmail App Password Google Account → Security → 2-Step Verification → App Passwords

Setup

1. Clone and Configure

git clone https://github.com/Ladychka/Orchestrix.git
cd Orchestrix
cp .env.example .env

Edit .env and fill in your credentials:

# Ollama (must be reachable over the network)
OLLAMA_URL=https://your-ollama-host.example.com
OLLAMA_MODEL=kimi-k2.6:cloud

# Neon PostgreSQL
DATABASE_URL=postgresql://user:password@your-project.neon.tech/dbname?sslmode=require

# Qdrant Cloud
QDRANT_URL=https://your-cluster.qdrant.io
QDRANT_API_KEY=your_qdrant_api_key_here

# Upstash Redis
UPSTASH_REDIS_REST_URL=https://your-project.upstash.io
UPSTASH_REDIS_REST_TOKEN=your_upstash_token_here

# Embedding API (OpenAI-compatible)
EMBEDDING_BASE_URL=https://api.openai.com/v1
EMBEDDING_API_KEY=your_embedding_api_key_here
EMBEDDING_MODEL=text-embedding-3-small

# Telegram Bot
TELEGRAM_BOT_TOKEN=your_bot_token_here
TELEGRAM_APPROVER_CHAT_ID=your_chat_id_here

# Gmail SMTP
EMAIL_USER=your@gmail.com
EMAIL_PASS=your_app_password_here

2. Install Backend Dependencies

cd backend
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
pip install -r requirements.txt

3. Run the Backend

uvicorn main:app --port 8000

4. Install Frontend Dependencies

cd ../frontend
npm install

5. Run the Frontend

Set API_URL to your backend endpoint (e.g. http://localhost:8000 for local development):

export API_URL=http://localhost:8000
npm run dev

The frontend will be available at http://localhost:3000 and proxies API requests to the backend.

6. Initialize Data

cd backend
python init_db.py
python -m ingestion.ingest

7. Verify

curl http://localhost:8000/health
# Expected: {"status": "ok"}

How to Use

Trigger a Task

curl -X POST http://localhost:8000/tasks \
  -H "Content-Type: application/json" \
  -d '{"from_email":"customer@example.com","subject":"Quote request","body":"Please quote 200 units of SKU-101.","employee_id":1}'

Or use the dashboard at http://localhost:3000 and click Trigger Demo Task.

Watch the Agent Work

Poll the task to see the step trace grow:

curl http://localhost:8000/tasks/1

The agent runs these tools in order:

Step Tool Purpose
0 check_inventory Searches Qdrant Cloud for the requested SKU
1 calculate_quote Computes line items, discounts, and total
2 draft_quotation_email Generates HTML + plain text email body
3 request_approval Pauses and sends Telegram approval request

Approve via Telegram

You will receive a message like:

APPROVAL REQUEST — Task #1
━━━━━━━━━━━━━━━━━━━━

Quotation Summary
- Customer: customer@example.com
- Product: ProBook 15-inch Laptop (SKU-101)
- Quantity: 200 units
- Unit Price: $899.00
- Bulk Discount: -$8,990.00
- Total: $170,810.00 USD

Warning: Only 45 units currently in stock.

[ Approve & Send ]  [ Reject ]

Tap Approve & Send — the email is dispatched immediately.

Verify Completion

The task status changes to completed. A new send_email step appears in the trace. The HTML quotation email arrives in the customer's inbox with a styled table, gradient header, and validity banner.


Key Design Decisions

Decision Rationale
Human-in-the-Loop Approval The AI cannot send emails autonomously. Every quotation requires explicit human approval via Telegram, creating a trust and safety boundary.
Full Audit Trail Every tool call is persisted as a TaskStep in Neon Postgres. The dashboard renders this as a live timeline for complete transparency.
External LLM (Ollama) No external API keys or rate limits for the LLM layer. Runs on a host you control. The agent uses tool-calling when supported, with a text-parsing fallback.
Exact SKU Lookup Semantic search alone matched wrong products for SKU codes. We added payload-filtered exact lookup for SKU strings while keeping semantic search for product descriptions.
Multipart HTML Emails Plain text emails look unprofessional. The system sends both HTML (styled table, gradient header, validity banner) and plain text (fallback) in a single MIME message.
Managed Cloud Infrastructure PostgreSQL (Neon), vector search (Qdrant Cloud), and cache (Upstash Redis) are fully managed, eliminating operational overhead of self-hosted containers.

Troubleshooting

Problem Solution
Backend returns 500 on tasks Verify Ollama is reachable at OLLAMA_URL. Check that QDRANT_URL, QDRANT_API_KEY, DATABASE_URL, and embedding API credentials are correct.
Telegram messages not arriving Verify TELEGRAM_BOT_TOKEN and TELEGRAM_APPROVER_CHAT_ID. The bot starts automatically when the backend boots.
Emails not sending Use a Gmail App Password, not your regular account password. Requires 2-Step Verification to be enabled first.
Tasks stuck at "received" The orchestrator crashed before calling tools. Check backend logs for Ollama connection or model errors.
Frontend is unstyled white page The Next.js build failed. Check npm run build output and reinstall dependencies with npm install.
Embedding API errors Ensure EMBEDDING_BASE_URL points to an OpenAI-compatible endpoint and EMBEDDING_API_KEY is valid.

Project Structure

Orchestrix/
├── backend/
│   ├── app/
│   │   ├── api/              # REST endpoints (tasks, employees)
│   │   ├── core/             # Pydantic Settings configuration
│   │   ├── orchestrator/     # Ollama agent loop with tool routing
│   │   ├── services/         # Qdrant, Telegram, Ollama, Embedding, Redis clients
│   │   ├── tools/            # check_inventory, calculate_quote, draft_email, send_email, log_step
│   │   └── models/           # SQLAlchemy: Task, TaskStep, Approval, AIEmployee
│   ├── ingestion/            # products.json → Qdrant embedding pipeline
│   └── init_db.py            # Seeds the AI Finance Officer
├── frontend/
│   └── src/app/
│       ├── page.tsx          # Dashboard: employee card + recent tasks
│       ├── tasks/page.tsx    # Full task list with status filters
│       └── tasks/[id]/       # Task detail with live step timeline
├── .env.example              # Cloud environment variable template
└── README.md

Testing

# Verify tools in isolation
cd backend
python test_tools.py

# Trigger a task via API
curl -X POST http://localhost:8000/tasks -H "Content-Type: application/json" \
  -d '{"from_email":"test@test.com","subject":"Quote","body":"Quote 50 units of SKU-102","employee_id":1}'

# Poll task status
curl http://localhost:8000/tasks/1

License

MIT

About

FirstWave-We're building an AI Digital Employee Platform where companies create AI employees that automate real business tasks. Our first AI Trade Operations Officer reads trade documents, uses RAG to retrieve knowledge, classifies products, calculates duties, and drafts customs documents.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages