# Project export: OptiMATE

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: TreeHacks 2026
- Tagline: We provide large-scale business operations teams with an instantaneous access to PhD-level mathematical solutions to their everyday optimization problems (routing parcels, scheduling workforce, etc.).
- Devpost: https://devpost.com/software/optimax
- GitHub: https://github.com/hindyros/OptiMATE
- Demo: https://optimate.onrender.com/
- Video: https://www.youtube.com/embed/0999Z3X5AbI?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 4 GitHub contributor(s) — Cursor (16 commits), Mildness10 (13 commits), Hindy (13 commits), Emmanuel (13 commits)

## Devpost submission (written by the team)

### Inspiration

While working with a large-scale company facing complex optimization challenges, MIT student Hindy Rossignol observed a clear gap: Businesses urgently need optimization solutions — yet access to operations research expertise is extremely limited. Optimization problems are common across industries (logistics, healthcare, energy, finance), but solving them typically requires: A team of specialized researchers or technical consultants Engagements costing $50,000–$100,000+ Timelines lasting 6–9+ months per problem Meanwhile, top applied mathematicians are concentrated in a small number of labs and firms, creating a structural supply–demand imbalance. Optimization is powerful — but not accessible. What It Does Simply describe your business problem in natural language. Our AI agents: Convert it into a mathematical optimization model Solve it using Gurobi (licensed, state-of-the-art solver) Deliver the optimal strategy back to you in clear, jargon-free English No equations. No modeling expertise required. How We Built It Together with Emmanuel Zheng (Stanford), Mildness Akomoize (Howard), Benjamin Furragganan (Berkeley), and Hindy Rossignol (MIT) we built OptiMATE. Dual-Solver Pipeline Two independent solvers run in parallel: OptiMUS Multi-step decomposition using Claude Sonnet GurobiPy code generation Execution with retry logic OptiMUS Multi-step decomposition using Claude Sonnet GurobiPy code generation Execution with retry logic OptiMind (Microsoft, Jan 2026) Fine-tuned optimization model Single-pass code generation Debug retries via Claude Haiku OptiMind (Microsoft, Jan 2026) Fine-tuned optimization model Single-pass code generation Debug retries via Claude Haiku GPT-4o judge evaluates both outputs and selects the best solution. GPT-4o judge evaluates both outputs and selects the best solution. OptiMind Deployment The full-precision OptiMind-SFT model (~40GB BF16) exceeded the memory capacity of a single L4 GPU (24GB VRAM). We: Converted HuggingFace weights → GGUF format Quantized using llama.cpp (Q8_0 → Q4_K_M) Deployed with llama-server Successfully served the model on a single L4 GPU End-to-End Flow Claude Opus pre-processes input (raw_to_model.py) Both solvers generate GurobiPy models Models execute under a licensed Gurobi environment GPT-4o judge compares solutions Claude Opus (consultant.py) generates final Markdown report: Executive summary Baseline comparison Recommendations Technical appendix Executive summary Baseline comparison Recommendations Technical appendix Frontend Built with Next.js Submits problems via API routes Triggers backend Python pipeline Tracks progress via polling Renders final optimization report Optional HeyGen video generation for executive briefings Challenges We Ran Into Designing a complex multi-agent backend architecture Handling ambiguity in natural language descriptions Quantizing and deploying Microsoft’s newly released OptiMind model Combining multimodal inputs (CSV operational data + natural language) Evaluating correctness of complex mathematical formulations Optimization modeling is unforgiving — small formulation errors can invalidate entire solutions. Accomplishments We're Proud Of Built a robust system capable of solving easy to medium difficulty optimization problems across industries: Healthcare E-commerce Supply chain logistics Energy management Built a robust system capable of solving easy to medium difficulty optimization problems across industries: Healthcare E-commerce Supply chain logistics Energy management Extended SOTA research (OptiMUS + OptiMind) Improved syntactic correctness of generated optimization code Combined multiple research approaches into one orchestrated system Added solution validation via independent judging Extended SOTA research (OptiMUS + OptiMind) Improved syntactic correctness of generated optimization code Combined multiple research approaches into one orchestrated system Added solution validation via independent judging We went beyond simple LLM-wrapping to build a structured decision engine. What We Learned How to design a multi-agent system targeting PhD-level applied mathematics reasoning How to enforce solver-feasible outputs beyond text generation Exposure to new optimization problem classes and industries How to align interdisciplinary expertise under extreme time constraints (24-hour build) We learned that coordination and structured reasoning matter more than raw model size. What’s Next for OptiMATE Gather first user feedback to guide product refinement Benchmark OptiMATE against large optimization datasets Improve robustness for: Noisy data Incomplete data Heterogeneous structured inputs Noisy data Incomplete data Heterogeneous structured inputs Our goal: Make optimization accessible to every business — not just those with in-house operations researchers.

## README (from the GitHub repository)

# OptiMATE

An ensemble natural-language optimization solver that runs **OptiMUS** and **OptiMind** in parallel, uses an LLM judge to pick the best solution, and generates a professional consultant-grade optimization report.

Built during **Stanford TreeHacks 2026**, with credit to the original creators of [OptiMUS](https://github.com/teshnizi/OptiMUS) and [OptiMind](https://arxiv.org/abs/2509.22979).

---

## Architecture

![OptiMATE System Architecture](backend/architecture_diagram.png)

The pipeline flows left to right through five stages:

1. **User Input** — A problem description (`.txt`) and optional data files (`.csv`) are uploaded through the frontend.
2. **Pre-Processing** — `raw_to_model.py` uses an LLM to extract structured parameters from raw inputs, producing `desc.txt`, `params.json`, and an optional `baseline.txt`.
3. **Dual Solvers (parallel)** — Two independent solvers race to solve the problem:
   - **OptiMUS** — A structured, multi-step pipeline that decomposes the problem into parameters, objectives, and constraints, formulates each mathematically, generates GurobiPy code, and executes it with an LLM-assisted debug loop (×3 retries).
   - **OptiMind** — Microsoft Research's fine-tuned LLM (`OptiMind-SFT`) that reasons step-by-step and generates executable GurobiPy code in a single pass, with its own debug loop (×5 retries).
4. **Judge** — Classifies solver statuses, uses a programmatic fast-path for clear winners, and falls back to GPT-4o for nuanced comparison of formulation correctness, implementation fidelity, and objective values.
5. **Consultant Report** — Generates a professional Markdown report with an executive summary, baseline comparison, key recommendations, and a technical appendix.

### LLM Models

| Stage | Provider | Model |
|-------|----------|-------|
| Pre-Processing | Anthropic | `claude-opus-4-20250514` |
| OptiMUS (all steps) | Anthropic | `claude-sonnet-4-20250514` |
| OptiMind (solver) | Self-hosted (GCP) | `microsoft/OptiMind-SFT` |
| OptiMind (debug) | Anthropic | `claude-haiku` |
| Judge | OpenAI | `gpt-4o` |
| Consultant | Anthropic | `claude-opus-4-20250514` |

---

## Project Structure

```
OptiMATE/
├── frontend/                  Next.js web interface
│   ├── app/                   App router pages & API routes
│   ├── components/            React components
│   └── public/                Static assets
│
├── backend/                   Python optimization pipeline
│   ├── main.py                Entry point — runs the full pipeline
│   ├── raw_to_model.py        Converts raw inputs → structured model inputs
│   ├── optimus.py             OptiMUS solver entry point
│   ├── optimind.py            OptiMind solver entry point
│   ├── judge.py               Compares solutions, picks a winner
│   ├── consultant.py          Generates the final report
│   ├── query_manager.py       Workspace archiving & cleanup
│   ├── optimus_pipeline/      OptiMUS step implementations (steps 1–8)
│   ├── data_upload/           Drop input files here
│   ├── current_query/         Working directory (managed automatically)
│   │   ├── raw_input/
│   │   ├── model_input/
│   │   ├── optimus_output/
│   │   ├── optimind_output/
│   │   └── final_output/      verdict.json + report.md
│   └── query_history/         Archived runs (<timestamp>/)
│
└── README.md                  ← You are here
```

---

## Setup

### Prerequisites

- Python 3.10+
- Node.js 18+ and npm
- A valid [Gurobi license](https://www.gurobi.com/academia/academic-program-and-licenses/) (academic licenses are free)

### Environment Variables

Create a `.env` file in the `backend/` directory (gitignored):

```
OPENAI_API_KEY=your-openai-key
ANTHROPIC_API_KEY=your-anthropic-key
OPTIMIND_SERVER_URL=http://<VM_IP>/v1

# Gurobi WLS (cloud license — works on any machine)
GRB_WLSACCESSID=your-access-id
GRB_WLSSECRET=your-secret
GRB_LICENSEID=your-license-id
```

### Backend

```bash
cd backend
conda activate optima
pip install -r requirements.txt
```

### Frontend

```bash
cd frontend
npm install
```

### Gurobi License

The pipeline generates and executes GurobiPy code. You need a valid license:

- **Get one:** [Academic (free)](https://www.gurobi.com/academia/academic-program-and-licenses/) or [commercial](https://www.gurobi.com/licenses/). Retrieve your key from the [Gurobi User Portal](https://portal.gurobi.com/iam/licenses/list).
- **Option A — WLS (recommended):** Add your Web License Service credentials to `.env` (see above). Works on any machine.
- **Option B — Local license file:** Run `grbgetkey` to download `gurobi.lic` to `~/gurobi.lic`. Only works on that machine.

---

## Quick Start

### Backend (CLI)

```bash
cd backend

# 1. Place your files in data_upload/
#    - A .txt file with the problem description (required)
#    - A .csv file with parameter data          (optional)

# 2. Run the pipeline
python main.py
```

The script clears the workspace, processes inputs, runs both solvers in parallel, judges the results, and writes the final output to `current_query/final_output/`.

#### Alternative: explicit file paths

```bash
python main.py --desc path/to/problem.txt
python main.py --desc path/to/problem.txt --data path/to/params.csv
```

#### CLI options

```
python main.py                                    # use data_upload/
python main.py --desc problem.txt                 # explicit desc file
python main.py --desc problem.txt --data data.csv # desc + CSV
python main.py --no-archive                       # skip archiving old results
python main.py --dir other_dir                    # different workspace
```

### Frontend

```bash
cd frontend
npm run dev
```

Open [http://localhost:3000](http://localhost:3000) to use the web interface.

---

## Pipeline Detail

### What `main.py` does

| Step | What happens |
|------|-------------|
| 1 | Archive + clear `current_query/` |
| 2 | Copy uploaded files into `current_query/raw_input/` |
| 3 | `raw_to_model` — LLM converts raw inputs to `model_input/desc.txt` + `params.json` |
| 4 | `optimus` + `optimind` — **run in parallel** (structured multi-step solver + single-pass LLM solver) |
| 5 | `judge` — compares both solutions, picks a winner |
| 6 | `consultant` — generates a professional Markdown report with baseline comparison |

If one solver fails, the other's result is still judged. If both fail, you get a clear error.

---

## Backend Components

### `raw_to_model.py` — Pre-Processing

Converts `raw_input/` into `model_input/`. Two modes, chosen automatically:

- **CSV+Text mode** (raw_desc.txt + CSVs): LLM maps CSV columns to optimization parameters, then extracts additional numeric constants from the description text. Merges both sources.
- **Text mode** (raw_desc.txt only): LLM extracts parameters directly from prose.

### OptiMUS — Multi-Step Structured Pipeline

Decomposes the problem into parameters, objectives, and constraints, formulates each mathematically, generates code, then executes and debugs it. Steps 2 and 3 run **in parallel**.

| Step | File | What it does |
|------|------|--------------|
| 1 | `step01_parameters.py` | Extract parameters from the problem description |
| 2 | `step02_objective.py` | Identify the optimization objective (**parallel with 3**) |
| 3 | `step03_constraints.py` | Extract constraints (**parallel with 2**) |
| 4 | `step04_constraint_model.py` | Formulate constraints in LaTeX |
| 5 | `step05_objective_model.py` | Formulate objective in LaTeX |
| 6 | `step06_target_code.py` | Generate GurobiPy code for each constraint/objective |
| 7 | `step07_generate_code.py` | Assemble the complete solver script |
| 8 | `step08_execute_code.py` | Execute the script; if it errors, reflect and retry |

All step files live in `optimus_pipeline/`.

### OptiMind — Single-Pass LLM Solver

Microsoft Research's fine-tuned LLM for optimization. Given a natural-language problem, it reasons step-by-step and generates executable GurobiPy code in a single pass.

- **Model:** `microsoft/OptiMind-

[README truncated for size]

## Detected evidence (automated analysis)

Indexed codebase: 55 recognized source files, 383 KB.
- Anthropic (technology) — detected in the code
- CSS (language) — detected in the code
- Next.js (technology) — detected in the code
- OpenAI (technology) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code
- Vercel (technology) — claimed on Devpost, not found in the code
- AI coding agent: Cursor — evidence: commit authorship or trailers

## Codebase structure (from repository index)

### Files (87 of 87)

```
.gitignore
backend/.gitignore
backend/architecture_diagram.py
backend/backend_readme.md
backend/consultant.py
backend/current_query/final_output/report.md
backend/current_query/final_output/verdict.json
backend/current_query/model_input/desc.txt
backend/current_query/model_input/params.json
backend/current_query/optimind_output/code_output.txt
backend/current_query/optimind_output/optimind_code.py
backend/current_query/optimind_output/optimind_response.txt
backend/current_query/optimind_output/output_solution.txt
backend/current_query/optimus_output/code_1.py
backend/current_query/optimus_output/code_2.py
backend/current_query/optimus_output/code_output.txt
backend/current_query/optimus_output/code.py
backend/current_query/optimus_output/data.json
backend/current_query/optimus_output/error_0.txt
backend/current_query/optimus_output/error_1.txt
backend/current_query/optimus_output/log.txt
backend/current_query/optimus_output/output_solution.txt
backend/current_query/optimus_output/state_1_params.json
backend/current_query/optimus_output/state_2_objective.json
backend/current_query/optimus_output/state_3_constraints.json
backend/current_query/optimus_output/state_4_constraints_modeled.json
backend/current_query/optimus_output/state_5_objective_modeled.json
backend/current_query/optimus_output/state_6_code.json
backend/current_query/raw_input/raw_desc.txt
backend/judge.py
backend/main.py
backend/optimind.py
backend/optimus_pipeline/__init__.py
backend/optimus_pipeline/optimus_utils.py
backend/optimus_pipeline/step01_parameters.py
backend/optimus_pipeline/step02_objective.py
backend/optimus_pipeline/step03_constraints.py
backend/optimus_pipeline/step04_constraint_model.py
backend/optimus_pipeline/step05_objective_model.py
backend/optimus_pipeline/step06_target_code.py
backend/optimus_pipeline/step07_generate_code.py
backend/optimus_pipeline/step08_execute_code.py
backend/optimus.py
backend/query_manager.py
backend/raw_to_model.py
backend/requirements.txt
DEPLOYMENT.md
Dockerfile
frontend/.gitignore
frontend/app/api/generate-pdf/route.ts
frontend/app/api/heygen/generate/route.ts
frontend/app/api/heygen/status/route.ts
frontend/app/api/optimize/[jobId]/result/route.ts
frontend/app/api/optimize/[jobId]/status/route.ts
frontend/app/api/optimize/route.ts
frontend/app/api/refine/continue/route.ts
frontend/app/api/refine/start/route.ts
frontend/app/api/refine/upload/route.ts
frontend/app/api/summarize/route.ts
frontend/app/globals.css
frontend/app/layout.tsx
frontend/app/optimize/[jobId]/page.tsx
frontend/app/page.tsx
frontend/app/refine/page.tsx
frontend/app/results/[jobId]/page.tsx
frontend/components/Navbar.tsx
frontend/components/ThemeProvider.tsx
frontend/components/ThemeToggle.tsx
frontend/eslint.config.mjs
frontend/lib/heygen-api.ts
frontend/lib/types.ts
frontend/lib/utils/file-ops.ts
frontend/lib/utils/llm.ts
frontend/lib/utils/python-runner.ts
frontend/lib/utils/store.ts
frontend/next.config.ts
frontend/package.json
frontend/postcss.config.mjs
frontend/sample_data/healthcare_resources.csv
frontend/sample_data/production_planning.csv
frontend/sample_data/README.md
frontend/sample_data/resource_allocation.csv
frontend/sample_data/transportation.csv
frontend/tsconfig.json
README.md
render.yaml
test-deployment.sh
```

### Dependencies

- backend/requirements.txt: anthropic, groq, gurobipy, langchain_chroma, langchain_openai, numpy, openai, openpyxl, pandas, python-dotenv
- frontend/package.json: @tailwindcss/postcss@^4, @types/katex@^0.16.8, @types/node@^20, @types/react@^19, @types/react-dom@^19, @types/react-katex@^3.0.4, @types/react-syntax-highlighter@^15.5.13, eslint@^9, eslint-config-next@16.1.6, framer-motion@^12.34.0, katex@^0.16.28, marked@^17.0.2, nanoid@^5.1.6, next@16.1.6, next-themes@^0.4.6, openai@^6.22.0, pdf-lib@^1.17.1, prism-react-renderer@^2.4.1, react@19.2.3, react-dom@19.2.3, react-katex@^3.1.0, react-markdown@^10.1.0, react-syntax-highlighter@^16.1.0, recharts@^3.7.0, rehype-katex@^7.0.1, remark-gfm@^4.0.1, remark-math@^6.0.0, tailwindcss@^4, typescript@^5, zustand@^5.0.11

### Recent commits (newest first)

- Update event name from TreeHacks to Stanford TreeHacks
- Fix typo in README.md about project creation
- Update README.md
- Fix remaining openai.chat references in llm.ts
- Fix OpenAI initialization for Next.js build
- Fix build error: force dynamic rendering for API routes with env vars
- Upgrade to Node.js 20.18.1 for Next.js 16 compatibility
- Add cache bust to force clean rebuild on Render
- Fix Node.js installation in Docker by using direct binary download
- Comment out persistent disk for free tier compatibility
- Add deployment configuration for Render with Docker runtime
- updated fe interface
- HeyGen API
- frontend changes coupled with backend
- Add root README and architecture diagram for OptiMATE
- Add debug agent to OptiMind pipeline for automatic code fixing
- Agent demo version
- Update llama-server ctx-size to 35K in backend readme
- Agenttt
- Rename backend README to backend_readme.md

## Key source files (fetched from GitHub, selected and truncated for size)

### DEPLOYMENT.md

```markdown
# OptiMATE Deployment Guide

## 🎯 Overview

This guide covers deploying OptiMATE to **Render** (recommended) and **Vercel** (frontend only).

### Quick Architecture Summary

- **Frontend**: Next.js app (API routes call Python backend)
- **Backend**: Python pipeline (5-15 min optimization cycles)
- **Dependencies**: Gurobi, OpenAI, Anthropic, OptiMind server, HeyGen
- **Storage**: File-based communication (`current_query/`, `data_upload/`)

---

## 🚀 Option 1: Full Stack on Render (RECOMMENDED)

### Why Render?

✅ Supports both Python and Node.js
✅ No timeout limits (critical for 15-min processes)
✅ Persistent disk for file storage
✅ Simple deployment
✅ Free tier available ($7/mo recommended for disk)

### Prerequisites

1. GitHub repository pushed
2. [Render account](https://render.com) created
3. API keys ready:
   - `OPENAI_API_KEY`
   - `ANTHROPIC_API_KEY`
   - `GRB_WLSACCESSID`, `GRB_WLSSECRET`, `GRB_LICENSEID` (Gurobi WLS)
   - `OPTIMIND_SERVER_URL`
   - `NEXT_PUBLIC_HEYGEN_API_KEY`

### Deployment Steps

#### Step 1: Push to GitHub

```bash
cd /home/mildness/Documents/treehacks/OptiMax
git add .
git commit -m "Prepare for Render deployment"
git push origin master
```

#### Step 2: Create Service on Render

1. Go to [Render Dashboard](https://dashboard.render.com/)
2. Click **New +** → **Web Service**
3. Connect your GitHub repo
4. Configure:
   - **Name**: `optimate`
   - **Region**: Oregon (US West) - lowest latency
   - **Branch**: `master` or `main`
   - **Runtime**: `Python 3`
   - **Build Command**:
     ```bash
     cd backend && pip install -r requirements.txt && cd ../frontend && curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && apt-get install -y nodejs && npm install && npm run build
     ```
   - **Start Command**:
     ```bash
     cd frontend && npm start
     ```
   - **Plan**: Select **Starter** ($7/month) for persistent disk

#### Step 3: Add Environment Variables

In Render dashboard → Environment:

**Backend Python:**

- `OPENAI_API_KEY` = `your-key`
- `ANTHROPIC_API_KEY` = `your-key`
- `OPTIMIND_SERVER_URL` = `http://your-vm-ip/v1`

**Gurobi (Cloud License):**

- `GRB_WLSACCESSID` = `your-access-id`
- `GRB_WLSSECRET` = `your-secret`
- `GRB_LICENSEID` = `your-license-id`

**Frontend:**

- `NEXT_PUBLIC_HEYGEN_API_KEY` = `your-key`
- `NODE_ENV` = `production`

#### Step 4: Add Persistent Disk (IMPORTANT!)

1. In service settings → **Disks**
2. Click **Add Disk**
3. Configure:
   - **Name**: `optimate-data`
   - **Mount Path**: `/opt/render/project/src/backend`
   - **Size**: 10 GB
4. This ensures `current_query/` and file storage persists

#### Step 5: Deploy

1. Click **Create Web Service**
2. Wait 5-10 minutes for build
3. Monitor logs for errors
4. Once deployed, test at `https://optimate.onrender.com`

### Troubleshooting Render

**Build fails:**

- Check build logs for Python/Node errors
- Ensure all requirements.txt packages install
- Verify Gurobi license keys are correct

**App crashes on startup:**

- C
[truncated — 6863 more characters]
```

### backend/backend_readme.md

```markdown
# Optima

An ensemble NL-based optimization solver that compares solutions from OptiMUS and OptiMind, then uses an LLM judge to pick the best one.

Built for Treehacks 2026, with credit to original creators of OptiMUS and OptiMind.

## Setup

```bash
conda activate optima
pip install -r requirements.txt
```

Create a `.env` file in the project root (gitignored). Copy from `.env.example` and fill in your keys:

```
OPENAI_API_KEY=your-openai-key
ANTHROPIC_API_KEY=your-anthropic-key
OPTIMIND_SERVER_URL=http://<VM_IP>/v1

# Gurobi WLS (cloud license — works on any machine)
GRB_WLSACCESSID=your-access-id
GRB_WLSSECRET=your-secret
GRB_LICENSEID=your-license-id
```

### Gurobi license (for running generated solver code)

The pipeline generates and runs Gurobi (Python) code. You need a valid **Gurobi license** for that to work.

- **Get a license:** [Academic (free)](https://www.gurobi.com/academia/academic-program-and-licenses/) or [commercial](https://www.gurobi.com/licenses/). Use the [Gurobi User Portal](https://portal.gurobi.com/iam/licenses/list) to retrieve your license key.
- **Set it up** — two options:
  - **Option A — WLS (recommended for teams/deployment):** Add your Web License Service credentials to `.env` (see above). Works on any machine without a local license file.
  - **Option B — Local license file:** Run `grbgetkey` to download `gurobi.lic` to `~/gurobi.lic`. Only works on that machine.

If the license is not set up, running the pipeline or executing generated code will fail with a Gurobi license error.

---

## Quick Start

```bash
# 1. Place your files in data_upload/
#    - A .txt file with the problem description (required)
#    - A .csv file with parameter data          (optional)

# 2. Run the pipeline
python main.py
```

That's it. The script clears the workspace, processes your inputs, runs both solvers, judges the results, and writes the final verdict to `current_query/final_output/`.

### Alternative: explicit file paths

```bash
python main.py --desc path/to/problem.txt
python main.py --desc path/to/problem.txt --data path/to/params.csv
```

### Pipeline steps (what `main.py` does)

| Step | What happens |
|------|-------------|
| 1 | Archive + clear `current_query/` |
| 2 | Copy uploaded files into `current_query/raw_input/` (renamed to `raw_desc.txt` / `raw_params.csv`) |
| 3 | `raw_to_model` — LLM converts raw inputs to `model_input/desc.txt` + `params.json` |
| 4 | `optimus` + `optimind` — **run in parallel** (structured multi-step solver + single-pass LLM solver) |
| 5 | `judge` — compares both solutions, picks a winner |
| 6 | `consultant` — generates a professional Markdown report with baseline comparison |

If one solver fails, the other's result is still judged. If both fail, you get a clear error.

### LLM models

| Stage | Provider | Model |
|-------|----------|-------|
| raw_to_model | OpenAI | `gpt-4o` |
| OptiMUS (all pipeline steps) | Anthropic | `claude-sonnet-4-20250514` |
| OptiMind (solver) | Self-hoste
[truncated — 16328 more characters]
```

### Dockerfile

```
# Multi-stage Dockerfile for OptiMATE
FROM python:3.10-slim as python-base

# Install system dependencies
RUN apt-get update && apt-get install -y \
    curl \
    build-essential \
    ca-certificates \
    xz-utils \
    && rm -rf /var/lib/apt/lists/*

# Install Node.js 20.x manually (avoids apt permission issues)
# Cache bust: 2026-02-15-v3
ENV NODE_VERSION=20.18.1
RUN curl -fsSL https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz -o node.tar.xz \
    && tar -xf node.tar.xz -C /usr/local --strip-components=1 \
    && rm node.tar.xz \
    && node --version \
    && npm --version

# Set working directory
WORKDIR /app

# Copy backend requirements and install Python dependencies
COPY backend/requirements.txt ./backend/
RUN cd backend && pip install --no-cache-dir -r requirements.txt

# Copy frontend package files and install Node dependencies
COPY frontend/package*.json ./frontend/
RUN cd frontend && npm ci

# Copy entire project
COPY . .

# Build frontend
RUN cd frontend && npm run build

# Expose port (Render will assign PORT env var)
EXPOSE 3000

# Start command
CMD cd frontend && npm start

```

### backend/requirements.txt

```
anthropic
openai
groq
python-dotenv
pandas
numpy
gurobipy
openpyxl
langchain_chroma
langchain_openai

```

### frontend/package.json

```
{
  "name": "frontend",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "eslint"
  },
  "dependencies": {
    "@types/react-syntax-highlighter": "^15.5.13",
    "framer-motion": "^12.34.0",
    "katex": "^0.16.28",
    "marked": "^17.0.2",
    "nanoid": "^5.1.6",
    "next": "16.1.6",
    "next-themes": "^0.4.6",
    "openai": "^6.22.0",
    "pdf-lib": "^1.17.1",
    "prism-react-renderer": "^2.4.1",
    "react": "19.2.3",
    "react-dom": "19.2.3",
    "react-katex": "^3.1.0",
    "react-markdown": "^10.1.0",
    "react-syntax-highlighter": "^16.1.0",
    "recharts": "^3.7.0",
    "rehype-katex": "^7.0.1",
    "remark-gfm": "^4.0.1",
    "remark-math": "^6.0.0",
    "zustand": "^5.0.11"
  },
  "devDependencies": {
    "@tailwindcss/postcss": "^4",
    "@types/katex": "^0.16.8",
    "@types/node": "^20",
    "@types/react": "^19",
    "@types/react-dom": "^19",
    "@types/react-katex": "^3.0.4",
    "eslint": "^9",
    "eslint-config-next": "16.1.6",
    "tailwindcss": "^4",
    "typescript": "^5"
  }
}

```

### backend/main.py

```python
#!/usr/bin/env python3
"""
Optima — end-to-end optimization pipeline.

Place your input files in data_upload/:
    - A .txt file with the problem description     (required)
    - One or more .csv files with parameter data   (optional)

Then run:
    python main.py

The script will:
    1. Clear the workspace (archive previous results)
    2. Copy uploaded files into current_query/raw_input/
    3. Convert raw inputs to structured model inputs (raw_to_model)
    4. Run OptiMUS and OptiMind solvers in parallel
    5. Judge and compare both solutions
    6. Generate a professional consultant report (report.md + enriched verdict.json)

You can also point directly at files instead of using data_upload/:
    python main.py --desc path/to/problem.txt
    python main.py --desc path/to/problem.txt --data a.csv b.csv c.csv
"""

from __future__ import annotations

import argparse
import glob
import os
import shutil
import sys
import time
import traceback
from concurrent.futures import ThreadPoolExecutor, as_completed

# ── Pipeline imports ──
from query_manager import prepare_workspace
from raw_to_model import run_pipeline as raw_to_model
from optimus import run_pipeline as run_optimus
from optimind import run_pipeline as run_optimind
from judge import compare_solutions
from consultant import generate_report

# ── Constants ──
QUERY_DIR = "current_query"
UPLOAD_DIR = "data_upload"

# ── ANSI colours for terminal output ──
_GREEN = "\033[92m"
_RED = "\033[91m"
_YELLOW = "\033[93m"
_CYAN = "\033[96m"
_BOLD = "\033[1m"
_RESET = "\033[0m"


# ═══════════════════════════════════════════════════════════════════════════
# Helpers
# ═══════════════════════════════════════════════════════════════════════════


def _banner(title: str) -> None:
    width = 60
    print(f"\n{_CYAN}{'═' * width}")
    print(f"  {_BOLD}{title}{_RESET}{_CYAN}")
    print(f"{'═' * width}{_RESET}\n")


def _step(n: int, total: int, label: str) -> None:
    print(f"{_BOLD}[{n}/{total}]{_RESET} {label}")


def _ok(msg: str) -> None:
    print(f"  {_GREEN}✓ {msg}{_RESET}")


def _warn(msg: str) -> None:
    print(f"  {_YELLOW}⚠ {msg}{_RESET}")


def _fail(msg: str) -> None:
    print(f"  {_RED}✗ {msg}{_RESET}")


# ═══════════════════════════════════════════════════════════════════════════
# File discovery
# ═══════════════════════════════════════════════════════════════════════════


def _find_upload_files(upload_dir: str) -> tuple[str, list[str]]:
    """
    Locate the required .txt and any .csv files in the upload directory.

    Returns (txt_path, [csv_paths]).
    Exits with a clear error if inputs are invalid.
    """
    if not os.path.isdir(upload_dir):
        _fail(f"Upload directory not found: {upload_dir}/")
        print(f"  Create it and place your .txt file inside.")
        sys.exit(1)

    txt_files = sorted(glob.glob(os.path.join(upload_dir, "*.txt")))
    csv_files = sorted(glob.glob(os.path.join(upload_dir, "*.csv")))

    if not txt_files:
        _fail(f"No .txt file found in {upload_dir}/")
        print(f"  Place your problem description as a .txt file in {upload_dir}/")
        sys.exit(1)

    if len(txt_files) > 1:
        _fail(f"Multiple .txt files found in {upload_dir}/:")
        for f in txt_files:
            print(f"    - {f}")
        print(f"  Keep only one .txt file (the problem description).")
        sys.exit(1)

    return txt_files[0], csv_files


def _copy_to_raw_input(
    txt_path: str,
    csv_paths: list[str],
    query_dir: str,
) -> None:
    """Copy user files into current_query/raw_input/.
    The description is renamed to raw_desc.txt; CSVs keep their original names."""
    raw_dir = os.path.join(query_dir, "raw_input")
    os.makedirs(raw_dir, exist_ok=True)

    dest_txt = os.path.join(raw_dir, "raw_desc.txt")
    shutil.copy2(txt_path, dest_txt)
    _ok(f"{os.path.basename(txt_path)}  →  raw_input/raw_desc.txt")

    if csv_paths:
        for csv_path in csv_paths:
            basename = os.path.basename(csv_path)
            dest_csv = os.path.join(raw_dir, basename)
            shutil.copy2(csv_path, dest_csv)
            _ok(f"{basename}  →  raw_input/{basename}")
    else:
        print(f"  (no CSVs — text-only mode)")


# ═══════════════════════════════════════════════════════════════════════════
# Pipeline
# ═══════════════════════════════════════════════════════════════════════════


def run(
    desc_path: str | None = None,
    data_paths: list[str] | None = None,
    upload_dir: str = UPLOAD_DIR,
    query_dir: str = QUERY_DIR,
    no_archive: bool = False,
) -> dict | None:
    """
    Run the full Optima pipeline end-to-end.

    Args:
        desc_path:  Explicit path to a .txt description file.
                    If None, discovers from upload_dir.
        data_paths: Explicit paths to .csv data files (optional).
        upload_dir: Directory to scan for uploaded files.
        query_dir:  Working directory for the pipeline.
        no_archive: If True, skip archiving previous results.

    Returns:
        The verdict dict from judge.compare_solutions(), or None if
        both solvers failed and no verdict could be produced.
    """
    total_steps = 6
    t0 = time.time()

    _banner("Optima Pipeline")

    # ── Resolve input files ──
    if desc_path:
        # Explicit paths provided via CLI
        if not os.path.isfile(desc_path):
            _fail(f"Description file not found: {desc_path}")
            sys.exit(1)
        txt_path = desc_path
        csv_paths = data_paths or []
        for cp in csv_paths:
            if not os.path.isfile(cp):
                _fail(f"Data file not found: {cp}")
                sys.exit(1)
    else:
        # Discover from data_upload/
        txt_path, csv_paths = _find_upload_files(upload_dir)

    print(f"  Description: {txt_path}")
    if csv_paths:
        print(f"  Data:        {len(csv_paths)} CSV(s)")
        for cp in csv_paths:
            print(f"               - {os.path.basename(cp)}")
    else:
        print(
[truncated — 6163 more characters]
```

### frontend/app/layout.tsx

```typescript
import type { Metadata } from "next";
import { Inter, JetBrains_Mono } from "next/font/google";
import "./globals.css";
import Navbar from "@/components/Navbar";
import { ThemeProvider } from "@/components/ThemeProvider";

const inter = Inter({
  variable: "--font-inter",
  subsets: ["latin"],
  display: "swap",
});

const jetbrainsMono = JetBrains_Mono({
  variable: "--font-jetbrains",
  subsets: ["latin"],
  display: "swap",
});

export const metadata: Metadata = {
  title: "OptiMATE - AI-Powered Optimization",
  description: "Transform natural language into mathematical optimization solutions using advanced LLM-guided problem solving.",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body className={`${inter.variable} ${jetbrainsMono.variable}`} suppressHydrationWarning>
        <ThemeProvider
          attribute="class"
          defaultTheme="dark"
          enableSystem
          disableTransitionOnChange
        >
          <Navbar />
          {children}
        </ThemeProvider>
      </body>
    </html>
  );
}

```

### frontend/app/page.tsx

```typescript
/**
 * Landing Page (/)
 *
 * Sophisticated hero section with advanced animations and effects
 */

'use client';

import { useEffect } from 'react';
import Link from 'next/link';
import { motion } from 'framer-motion';

export default function LandingPage() {
  useEffect(() => {
    window.scrollTo(0, 0);
  }, []);

  return (
    <div className="min-h-screen flex flex-col items-center justify-center p-8 relative overflow-hidden bg-app-gradient">

      {/* Hero Section */}
      <motion.div
        initial={{ opacity: 0, y: 20 }}
        animate={{ opacity: 1, y: 0 }}
        transition={{ duration: 0.8 }}
        className="max-w-5xl mx-auto text-center space-y-12 relative z-10"
      >
        {/* Logo/Title with glow effect */}
        <div className="space-y-6">
          <motion.div
            initial={{ scale: 0.5, opacity: 0 }}
            animate={{ scale: 1, opacity: 1 }}
            transition={{ duration: 0.8, delay: 0.2 }}
            className="inline-block"
          >
            <h1 className="text-8xl font-bold">
              <span className="text-foreground">Opti</span>
              <span className="text-primary italic">MATE</span>
            </h1>
          </motion.div>

          <motion.p
            initial={{ opacity: 0, y: 20 }}
            animate={{ opacity: 1, y: 0 }}
            transition={{ duration: 0.8, delay: 0.3 }}
            className="text-2xl text-foreground-dim font-light tracking-wide"
          >
            AI-Powered Mathematical Optimization
          </motion.p>

          <motion.div
            initial={{ width: 0 }}
            animate={{ width: '200px' }}
            transition={{ duration: 1, delay: 0.5 }}
            className="h-1 mx-auto bg-gradient-to-r from-transparent via-primary to-transparent"
          />
        </div>

        {/* Description with glassmorphism */}
        <motion.div
          initial={{ opacity: 0, y: 20 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ duration: 0.8, delay: 0.6 }}
          className="glass-card p-12 rounded-2xl max-w-5xl mx-auto"
        >
          <p className="text-lg text-foreground leading-relaxed">
            Transform natural language into optimal solutions. Describe your problem, and watch as our AI
            agents formulate mathematical models, generate solver code, and deliver
            <span className="text-primary font-semibold"> proven optimal results</span>.
          </p>
        </motion.div>

        {/* Features Grid */}
        <motion.div
          initial={{ opacity: 0, y: 20 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ duration: 0.8, delay: 0.7 }}
          className="grid grid-cols-1 md:grid-cols-3 gap-6 mt-16"
        >
          <FeatureCard
            title="Natural Language"
            description="No math expertise required. Describe your optimization problem in plain English."
            icon="💬"
            delay={0.8}
          />
          <FeatureCard
            title="Dual-Solver Intelligence"
            description="Two AI agents compete to find the best solution, validated by an autonomous judge."
            icon="🤖"
            delay={0.9}
          />
          <FeatureCard
            title="Production-Ready Code"
            description="Get complete formulations, solver code, and detailed reports ready to deploy."
            icon="📊"
            delay={1.0}
          />
        </motion.div>

        {/* CTA Button with gradient */}
        <motion.div
          initial={{ opacity: 0, scale: 0.9 }}
          animate={{ opacity: 1, scale: 1 }}
          transition={{ duration: 0.6, delay: 1.1 }}
          className="mt-16"
        >
          <Link href="/refine">
            <button className="btn-gradient px-12 py-5 text-background font-bold text-xl rounded-2xl shadow-2xl relative overflow-hidden group">
              <span className="relative z-10 flex items-center justify-center gap-3">
                <span>Start Optimizing</span>
                <span className="group-hover:translate-x-1 transition-transform">→</span>
              </span>
            </button>
          </Link>
        </motion.div>

        {/* Use Cases */}
        <motion.div
          initial={{ opacity: 0 }}
          animate={{ opacity: 1 }}
          transition={{ duration: 0.8, delay: 1.2 }}
          className="mt-20 pt-12"
        >
          <p className="text-sm text-foreground-dim mb-6 uppercase tracking-wider">Trusted For</p>
          <div className="flex flex-wrap justify-center gap-4">
            {[
              { icon: '🏭', text: 'Production Planning' },
              { icon: '🏥', text: 'Resource Allocation' },
              { icon: '🚚', text: 'Supply Chain' },
              { icon: '💼', text: 'Portfolio Management' },
              { icon: '📅', text: 'Scheduling' },
            ].map((useCase, index) => (
              <motion.span
                key={index}
                initial={{ opacity: 0, scale: 0.8 }}
                animate={{ opacity: 1, scale: 1 }}
                transition={{ duration: 0.5, delay: 1.3 + index * 0.1 }}
                className="px-5 py-3 glass-card rounded-xl text-foreground text-sm font-medium flex items-center gap-2 cursor-default"
              >
                <span className="text-xl">{useCase.icon}</span>
                {useCase.text}
              </motion.span>
            ))}
          </div>
        </motion.div>
      </motion.div>

      {/* Footer */}
      <motion.footer
        initial={{ opacity: 0 }}
        animate={{ opacity: 1 }}
        transition={{ duration: 0.8, delay: 1.5 }}
        className="mt-20 text-center text-sm text-foreground-dim relative z-10"
      >
        <p className="flex items-center justify-center gap-2">
          <span>Powered by</span>
          <span className="text-primary font-semibold">OptiMUS & OptiMind</span>
          <span>•</span>
          <span>Built with GPT-4 & Gurobi</span>
        </p>
      </mot
[truncated — 840 more characters]
```

### frontend/app/refine/page.tsx

```typescript
/**
 * Refinement Page (/refine)
 *
 * SIMPLIFIED WORKFLOW (Updated):
 * 1. User enters problem description in one textarea
 * 2. Submit directly to optimization (no CSV, no baseline questions)
 * 3. Description saved as desc.txt in data_upload/
 * 4. Backend runs main.py to process
 *
 * NOTE: CSV upload and baseline assessment features commented out for potential future use
 */

'use client';

import { useState } from 'react';
import { useRouter } from 'next/navigation';
import { motion } from 'framer-motion';

export default function RefinePage() {
  const router = useRouter();

  // State
  const [problemDescription, setProblemDescription] = useState('');
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [error, setError] = useState<string | null>(null);

  /**
   * Handle optimization submission
   */
  const handleSubmit = async () => {
    if (!problemDescription.trim()) {
      setError('Please enter a problem description');
      return;
    }

    setIsSubmitting(true);
    setError(null);

    try {
      // Submit directly to optimization
      const formData = new FormData();
      formData.append('conversation_id', Date.now().toString()); // Simple ID
      formData.append('problem_description', problemDescription);
      formData.append('refined_description', problemDescription); // No refinement, same text

      const response = await fetch('/api/optimize', {
        method: 'POST',
        body: formData,
      });

      const data = await response.json();

      if (!response.ok) {
        throw new Error(data.error || 'Failed to start optimization');
      }

      // Redirect to processing page
      router.push(`/optimize/${data.job_id}`);
    } catch (err: any) {
      console.error('Submission error:', err);
      setError(err.message || 'Failed to submit. Please try again.');
      setIsSubmitting(false);
    }
  };

  return (
    <div className="min-h-screen flex items-center justify-center p-4 sm:p-6 md:p-8 relative overflow-hidden bg-app-gradient">
      <motion.div
        initial={{ opacity: 0, y: 20 }}
        animate={{ opacity: 1, y: 0 }}
        className="w-full max-w-xl md:max-w-2xl lg:max-w-4xl xl:max-w-5xl"
      >
        {/* Header */}
        <div className="text-center mb-8 sm:mb-12 px-4">
          <motion.h1
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            transition={{ delay: 0.2 }}
            className="text-3xl sm:text-4xl md:text-5xl lg:text-6xl font-bold text-foreground mb-3 sm:mb-4 bg-gradient-to-r from-primary via-accent to-primary bg-clip-text text-transparent"
          >
            Describe Your Optimization Problem
          </motion.h1>
          <motion.p
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            transition={{ delay: 0.3 }}
            className="text-base sm:text-lg md:text-xl text-foreground-dim max-w-2xl mx-auto"
          >
            Enter your optimization challenge below and let Opti<span className="text-primary italic font-bold">MATE</span> find the optimal solution
          </motion.p>
        </div>

        {/* Input Card */}
        <motion.div
          initial={{ opacity: 0, y: 20 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ delay: 0.4 }}
          className="glass-card gradient-border rounded-2xl p-4 sm:p-6 md:p-8 shadow-2xl"
        >
          <div className="space-y-4 sm:space-y-6">
            {/* Textarea */}
            <div>
              <label className="block text-sm font-semibold text-foreground mb-3">
                Problem Description
              </label>
              <textarea
                value={problemDescription}
                onChange={(e) => setProblemDescription(e.target.value)}
                placeholder="Example: I need to optimize hospital bed allocation across 7 departments to maximize patient care while minimizing costs. Each department has different capacities, staffing levels, and patient demands..."
                className="w-full h-48 sm:h-56 md:h-64 lg:h-80 px-3 sm:px-4 py-3 bg-code-bg border-2 border-border rounded-xl text-foreground text-sm sm:text-base placeholder-foreground-dim focus:outline-none focus:border-primary focus:ring-2 focus:ring-primary/20 transition-all resize-none"
                disabled={isSubmitting}
              />
              <p className="text-xs sm:text-sm text-foreground-dim mt-2">
                Be as detailed as possible about your constraints, objectives, and data
              </p>
            </div>

            {/* Error Message */}
            {error && (
              <motion.div
                initial={{ opacity: 0, scale: 0.95 }}
                animate={{ opacity: 1, scale: 1 }}
                className="p-4 bg-error/10 border border-error rounded-lg"
              >
                <p className="text-error text-sm">{error}</p>
              </motion.div>
            )}

            {/* Submit Button */}
            <button
              onClick={handleSubmit}
              disabled={isSubmitting || !problemDescription.trim()}
              className="w-full py-3 sm:py-4 btn-gradient text-background font-bold text-base sm:text-lg rounded-xl hover:shadow-2xl hover:scale-[1.02] disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:scale-100 transition-all duration-300"
            >
              {isSubmitting ? (
                <span className="flex items-center justify-center gap-2 sm:gap-3">
                  <span className="inline-block animate-spin">⚙️</span>
                  <span className="hidden sm:inline">Processing...</span>
                  <span className="sm:hidden">...</span>
                </span>
              ) : (
                <span className="flex items-center justify-center gap-2 sm:gap-3">
                  Optimize Now
                </span>
              )}
            </button>

            {/* Example Problems Cards */}
            <div className="pt-4">
            
[truncated — 5231 more characters]
```

### frontend/app/api/summarize/route.ts

```typescript
/**
 * API Route: POST /api/summarize
 * 
 * Generates a concise executive summary of the optimization report using OpenAI
 */

import { NextRequest, NextResponse } from 'next/server';
import OpenAI from 'openai';

// Force dynamic rendering - don't pre-render during build
export const dynamic = 'force-dynamic';

// Lazy-initialize OpenAI client (only when needed, not at module load)
let openai: OpenAI | null = null;

function getOpenAIClient(): OpenAI {
  if (!openai) {
    openai = new OpenAI({
      apiKey: process.env.OPENAI_API_KEY,
    });
  }
  return openai;
}

export async function POST(request: NextRequest) {
  console.log('\n[API] POST /api/summarize');

  try {
    const body = await request.json();
    const { report } = body;

    if (!report) {
      return NextResponse.json(
        { error: 'Report content is required' },
        { status: 400 }
      );
    }

    console.log('[API] Generating summary for report...');

    // Call OpenAI to generate a concise summary
    const completion = await getOpenAIClient().chat.completions.create({
      model: 'gpt-4o',
      messages: [
        {
          role: 'system',
          content: `You are an expert at summarizing optimization reports. Generate a concise, executive-level summary that highlights:
1. The key objective and what was being optimized
2. The most important results (objective value, key decision variables)
3. Main recommendations or insights

Keep the summary to 3-5 bullet points. Be specific with numbers and concrete outcomes. Focus on business value and actionable insights.`
        },
        {
          role: 'user',
          content: `Summarize this optimization report:\n\n${report}`
        }
      ],
      temperature: 0.7,
      max_tokens: 500,
    });

    const summary = completion.choices[0]?.message?.content || '';

    console.log('[API] ✓ Summary generated');

    return NextResponse.json({
      summary,
      success: true,
    });

  } catch (error) {
    console.error('[API] Error generating summary:', error);
    const errorMessage = error instanceof Error ? error.message : 'Unknown error';
    return NextResponse.json(
      {
        error: 'Failed to generate summary',
        details: errorMessage,
        // Return a fallback message if OpenAI fails
        summary: 'Summary generation unavailable. Please review the full report below for details.'
      },
      { status: 500 }
    );
  }
}

```

[46 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]