Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NeuroCalc — CPU-Only Handwritten Math Solver

Lightweight, offline-first AI math assistant for Windows PCs without GPU.
Runs entirely on CPU · Uses <15MB model · Zero cloud API calls required


✨ Features

Feature Details
🖼 Image Upload Upload PNG/JPG of handwritten equations
✏️ Drawing Canvas Draw equations directly in browser
📷 Webcam Capture Point camera at paper, capture frame
⌨️ Text Input Type equations with quick-solve
🔢 Digit Recognition EMNIST-trained CNN via ONNX
➕ Operator Recognition +, −, ×, ÷, =, ^, √, (, )
📐 Step-by-Step Solving Full derivation with SymPy
📊 Confidence Scores Per-symbol and aggregate confidence
💾 History SQLite-backed solution history
🌙 Dark Mode Scientific dark theme

🚀 Quick Start (Windows)

Requirements

  • Windows 10 or 11
  • Python 3.9 or later (download)
  • No GPU required
  • No Docker required

One-Command Launch

git clone https://github.com/yourname/neurocalc
cd neurocalc
start.bat

That's it. The script will:

  1. Create a Python virtual environment
  2. Install all dependencies
  3. Launch the server at http://localhost:8000
  4. Open your browser automatically

Screenshot

Screenshot 2026-05-22 191929

🗂 Project Structure

neurocalc/
│
├── backend/
│   ├── main.py                  ← FastAPI app entry point
│   ├── api/
│   │   └── routes.py            ← All API endpoints
│   ├── preprocessing/
│   │   └── image_preprocessor.py  ← CV pipeline
│   ├── recognition/
│   │   ├── cnn_model.py         ← CNN architecture + symbol classes
│   │   ├── onnx_engine.py       ← ONNX CPU inference
│   │   └── recognizer.py        ← Full recognition pipeline
│   ├── parsing/
│   │   └── expression_parser.py ← String → SymPy
│   ├── solver/
│   │   └── equation_solver.py   ← Step-by-step solver
│   └── database/
│       └── db.py                ← SQLite operations
│
├── frontend/
│   └── index.html               ← Single-file React-free UI
│
├── ml/
│   └── train_cnn.py             ← Training + ONNX export script
│
├── models/
│   └── neurocalc_cnn.onnx       ← Trained model (generated by train_cnn.py)
│
├── tests/
│   └── test_neurocalc.py        ← pytest unit tests
│
├── requirements.txt
├── start.bat                    ← Windows one-click launch
├── start.sh                     ← Linux/macOS launch
└── README.md

🔌 API Reference

All endpoints are under http://localhost:8000/api/

GET /health

Health check and model status.

Response:

{
  "status": "ok",
  "version": "1.0.0",
  "mode": "CPU-only",
  "model_loaded": true
}

POST /predict

Recognize a handwritten equation from an image.

Request: multipart/form-data

  • file — image file (PNG, JPG, BMP)

Response:

{
  "equation": "2x + 4 = 10",
  "tokens": [
    { "symbol": "2", "bbox": [10, 5, 30, 40], "confidence": 0.94 },
    { "symbol": "x", "bbox": [42, 5, 62, 40], "confidence": 0.87 }
  ],
  "confidence": 0.91,
  "inference_ms": 48.2
}

POST /solve

Parse and solve an equation string.

Request body:

{
  "equation": "x^2 - 5*x + 6 = 0",
  "show_steps": true
}

Response:

{
  "equation": "x^2 - 5*x + 6 = 0",
  "result": "2, 3",
  "solutions": ["2", "3"],
  "steps": [
    { "step": 1, "description": "Write the equation", "expression": "x**2 - 5*x + 6 = 0", "latex": "x^{2} - 5 x + 6 = 0" },
    { "step": 2, "description": "Identify coefficients: a=1, b=-5, c=6", "expression": "1x² + -5x + 6 = 0", "latex": "..." },
    { "step": 3, "description": "Calculate discriminant Δ = b² - 4ac", "expression": "Δ = 25 - 24 = 1", "latex": "..." },
    { "step": 4, "description": "Apply quadratic formula", "expression": "x = (5 ± 1) / 2", "latex": "..." },
    { "step": 5, "description": "Solution", "expression": "x = 2, x = 3", "latex": "x = 2, x = 3" }
  ],
  "latex": "2, 3",
  "solve_ms": 12.3
}

POST /predict-and-solve

One-shot: recognize image then solve.

Request: multipart/form-data — file

Response: Combined predict + solve response.


POST /camera-frame

Process a webcam frame with frame-skipping support.

Request body:

{
  "frame": "<base64-encoded-image>",
  "skip_frames": 3
}

Response:

{
  "equation": "3x = 9",
  "confidence": 0.78,
  "skipped": false
}

GET /history?limit=20

Retrieve recent solution history.

Response:

{
  "history": [
    {
      "id": 42,
      "equation": "sqrt(144)",
      "result": "12",
      "steps": [...],
      "created_at": "2024-01-15T14:23:01"
    }
  ]
}

🧠 Supported Equations

Type Examples
Arithmetic 2 + 3 * 4, 100 / 5 - 8
Fractions 3/4 + 1/6, 12/8
Powers 2**10, x^3
Roots sqrt(144), sqrt(x+1)
Linear 2x + 4 = 10, 3y - 7 = 2
Quadratic x^2 - 5x + 6 = 0
Cubic x^3 - 6x^2 + 11x - 6 = 0
Simplification expand((x+1)^2), factor(x^2-1)
Calculus diff(x^3, x), d/dx(sin(x))

🤖 CNN Model

Architecture

Input (1×28×28)
  → Conv2d(1→16) + BN + ReLU → MaxPool (14×14)
  → Conv2d(16→32) + BN + ReLU → MaxPool (7×7)
  → Conv2d(32→64) + BN + ReLU → AdaptiveAvgPool (4×4)
  → Linear(1024→128) + ReLU + Dropout(0.3)
  → Linear(128→26)  ← output classes

~600K parameters · <5MB ONNX · <15MB quantized

Symbol Classes (26 total)

0-9 digits · + - * / = operators · x y z variables
( ) brackets · ^ sqrt . , math symbols · < >

Training

# Install training deps (optional)
pip install torch torchvision onnx

# Train on EMNIST (auto-downloads dataset)
python ml/train_cnn.py --epochs 20 --export

# Export existing weights to ONNX only
python ml/train_cnn.py --export-only

Fallback

If no ONNX model is found, NeuroCalc uses a lightweight rule-based fallback classifier based on pixel density heuristics. Recognition accuracy is reduced but the system still functions for demos and testing the solve pipeline.


⚡ Performance

Metric Value
Model size <5MB (ONNX), <2MB (quantized)
Startup time ~2 seconds
Inference per symbol <30ms on CPU
Memory usage ~80MB RAM
Python dependencies 8 packages
External API calls Zero

🧪 Running Tests

# Activate venv first
venv\Scripts\activate

# Run all tests
python -m pytest tests/ -v

# Run specific module
python -m pytest tests/test_neurocalc.py::TestEquationSolver -v

📦 Optional: Build EXE (PyInstaller)

pip install pyinstaller
pyinstaller --onefile --name neurocalc backend/main.py

The resulting dist/neurocalc.exe runs without Python installed.


🔧 Configuration

Edit backend/main.py to change:

  • port=8000 — server port
  • workers=1 — CPU workers (keep at 1 for low RAM)

📄 License

MIT License — free to use, modify, and distribute.


🙏 Acknowledgments

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages