Skip to content

kklaeger/grade-ai

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GradeAI

GradeAI is a desktop app for teachers to upload one or more text-based student exam PDFs, extract their text, analyze them with a local Ollama model, and display structured grades, feedback, and detected issues.

This is a vibe-coding project built with Codex.

Data Privacy Notice

This application is intended for local use only. Do not use real personal or student data unless you have proper consent and comply with applicable data protection laws.

For testing and development, use anonymized or synthetic data only.

Stack

  • Frontend: Electron + React + TypeScript
  • Backend: Python + FastAPI
  • LLM: Ollama with qwen3:8b by default
  • Communication: REST API on localhost
  • Grading scale: German grades 1-6, including half grades and decimal-comma grades

Project Structure

.
├── backend
│   ├── app
│   │   ├── api
│   │   │   └── routes
│   │   ├── clients
│   │   ├── core
│   │   ├── resources
│   │   ├── schemas
│   │   ├── services
│   │   ├── utils
│   │   ├── main.py
│   │   └── standalone.py
│   ├── tests
│   │   ├── api
│   │   ├── clients
│   │   ├── core
│   │   ├── schemas
│   │   ├── services
│   │   └── utils
│   ├── requirements-dev.txt
│   └── requirements.txt
├── frontend
│   ├── electron
│   │   └── ipc
│   ├── e2e
│   ├── resources
│   ├── src
│   │   ├── app
│   │   ├── components
│   │   ├── features
│   │   ├── services
│   │   ├── styles
│   │   ├── types
│   │   └── utils
│   └── package.json
├── scripts
│   ├── setup.mjs
│   ├── dev.mjs
│   ├── check.mjs
│   └── backend-dev.mjs
├── package.json
├── .gitignore
└── README.md

Prerequisites

  • Git
  • Node.js 20+
  • Python 3.11+
  • Ollama installed locally for development, unless you provide a bundled runtime under frontend/resources/bin/ollama

Ollama Setup

GradeAI integrates with Ollama through Ollama's local HTTP API. In development, install Ollama locally. For a packaged desktop app, you can bundle the Ollama runtime binary under frontend/resources/bin/ollama, and GradeAI will use that before falling back to a system installation. The app tries to start ollama serve automatically and checks whether the configured model is available.

Start Ollama manually if you are running the backend without Electron, or if the automatic startup cannot find the ollama command:

ollama serve

Pull the default model:

ollama pull qwen3:8b

You can use another local Ollama model by setting GRADEAI_OLLAMA_MODEL.

If Ollama is running but the model is missing, GradeAI can download the configured model from the desktop UI.

Setup

Run the project setup from the repository root:

npm run setup

This creates backend/.venv, installs Python dependencies, and installs frontend dependencies.

Run the Desktop App

npm run dev

The root dev script starts Electron and points it at the Python executable in backend/.venv. Electron then starts the FastAPI backend as a child process.

Default local services:

  • FastAPI backend: http://127.0.0.1:8000
  • Ollama: http://127.0.0.1:11434

Run Backend Manually

Useful for API debugging:

npm run backend:dev

Then open the API docs at http://127.0.0.1:8000/docs.

Checks

Run Python bytecode compilation and TypeScript checking:

npm run check

Build And Packaging

GradeAI packages the desktop app with electron-builder and bundles the Python backend with PyInstaller.

Build the frontend only:

npm run build:frontend

Bundle the backend into a standalone executable for the current platform:

npm run bundle:backend

The backend binary is written to:

frontend/resources/backend/<platform>-<arch>/

Examples:

frontend/resources/backend/darwin-arm64/gradeai-backend
frontend/resources/backend/win32-x64/gradeai-backend.exe

Package the final desktop app for the current platform:

npm run package:desktop

Build a macOS .dmg on macOS:

npm run package:mac

Build a Windows NSIS .exe installer on Windows:

npm run package:win

Installers are written to:

frontend/release/

For release builds, run the packaging command on the target platform. Build macOS installers on macOS and Windows installers on Windows.

Tests

Run backend and frontend unit tests:

npm run test:unit

npm test is an alias for npm run test:unit.

Run the full suite, including unit, integration, and Electron E2E tests:

npm run test:all

Run tests with coverage:

npm run test:coverage

Coverage reports are written to:

  • backend/htmlcov/index.html
  • frontend/coverage/index.html

Run one side only:

npm run backend:test
npm run frontend:test
npm run backend:test:unit
npm run frontend:test:unit
npm run backend:test:coverage
npm run frontend:test:coverage

Run backend integration tests:

npm run test:integration

Run Electron E2E smoke tests:

npm run test:e2e

The E2E suite launches the built Electron app against a fake local backend. It does not require a real Ollama model.

Configuration

Environment variables:

  • GRADEAI_PYTHON: Python executable used by Electron to start the backend
  • GRADEAI_BACKEND_EXECUTABLE: standalone backend executable used by Electron instead of Python
  • GRADEAI_BACKEND_PORT: backend port, default 8000
  • GRADEAI_OLLAMA_URL: Ollama base URL, default http://127.0.0.1:11434
  • GRADEAI_OLLAMA_MODEL: Ollama model, default qwen3:8b
  • GRADEAI_MAX_PDF_SIZE_MB: maximum upload size, default 20
  • GRADEAI_OLLAMA_BINARY: Ollama executable path, default ollama
  • GRADEAI_SKIP_OLLAMA=1: do not try to start ollama serve from Electron
  • GRADEAI_SKIP_BACKEND=1: do not start FastAPI from Electron

Copy backend/.env.example to backend/.env for local backend configuration.

API

GET /api/ollama/status

Returns whether Ollama is reachable and whether the configured model exists locally.

POST /api/ollama/pull

Downloads the configured Ollama model when Ollama is reachable.

POST /api/upload/extract-text

Multipart form field:

  • file: PDF file

Returns extracted text for a text-based PDF.

POST /api/analyze

Multipart form field:

  • file: PDF file

Response:

{
  "student_name": "Jane Smith",
  "grade": "2,5",
  "feedback": "The exam is generally clearly structured...",
  "issues": ["Reasoning is too brief in two places", "The solution path for task 3 is missing"],
  "points_summary": "42 out of 50 points were detected; subtask 3b carried significant weight."
}

POST /api/analyze/batch

Multipart form field:

  • files: one or more PDF files

Response:

{
  "results": [
    {
      "filename": "student-a.pdf",
      "status": "success",
      "analysis": {
        "student_name": "Jane Smith",
        "grade": "2,5",
        "feedback": "The exam is generally clearly structured...",
        "issues": ["Reasoning is too brief in two places"],
        "points_summary": "42 out of 50 points were detected."
      },
      "error": null
    },
    {
      "filename": "scan.pdf",
      "status": "error",
      "analysis": null,
      "error": "No selectable text was found in the PDF. Scanned PDFs need OCR, which is not implemented yet."
    }
  ]
}

Limitations

  • Only text-based PDFs are supported.
  • Scanned documents and handwriting are not processed yet.
  • The grade is model-generated feedback and should be reviewed by the teacher.
  • LLM output can still vary slightly. GradeAI uses deterministic Ollama options and a fixed grade scale to reduce variation.

Desktop Distribution

For development, installing Ollama separately is acceptable. For a production desktop app, GradeAI is prepared to use a bundled Ollama runtime before falling back to the system ollama command.

Place platform-specific Ollama binaries here before building an installer:

frontend/resources/bin/ollama/
├── darwin-arm64/ollama
├── darwin-x64/ollama
├── linux-x64/ollama
└── win32-x64/ollama.exe

Build a packaged app:

npm run package:desktop

Recommended production strategy:

  • Build the Python backend into a platform-specific executable with PyInstaller.
  • Bundle the small Ollama runtime binary with the app.
  • Store model files in the app data directory through OLLAMA_MODELS.
  • Let the user download the configured model on first run from inside the app.

Runtime behavior:

  • Electron starts the bundled backend automatically when the app launches.
  • If no bundled backend exists, Electron falls back to the development Python environment.
  • If Ollama is missing or not running, the UI shows "Please install Ollama" with a link to https://ollama.com/download.
  • If the configured model is missing, the UI shows the required ollama pull ... command and a download button.
  • If the backend cannot be reached, the UI shows a backend startup error panel.

Fully offline installers are possible, but they become very large because models such as qwen3:8b are multiple GB. In that case, ship a separate offline installer artifact that preloads the Ollama model directory instead of committing model files to Git.

Future Ideas

See ROADMAP.md.

Planned next features include:

  • Configurable grade scale with whole grades, half grades, and decimal-comma grades
  • Optional model answer upload
  • Free-text field for additional grading criteria passed to the LLM
  • Multiple languages for UI, prompts, and feedback
  • OCR for scanned documents
  • Handwriting recognition
  • Email sending

Git

Initialize version control if this directory is not already a repository:

git init
git add .
git commit -m "Initial GradeAI app"

License

MIT. See LICENSE.

About

GradeAI is a cross-platform desktop application that analyzes and grades student exams from PDF files using a locally running LLM.

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors