Skip to content

Commit efa62bd

Browse files
Merge pull request #1 from DDMAL/ic_reimplementation
The initial stage of IC re-implementation. Features: - Similar data structure as legacy (Image, glyph, etc) - Same KNN algorithm - Independent KNN model (library free) - Primary API ports
2 parents 67a0ea2 + d687576 commit efa62bd

25 files changed

Lines changed: 7336 additions & 115 deletions

README.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# ic_new
2+
3+
A modern rewrite of the **Interactive Classifier** — a tool for interactively classifying chant-manuscript neumes using a k-Nearest Neighbors model.
4+
5+
This project replaces the legacy Rodan job (Django + Celery + Gamera + Backbone.Marionette) at [`/Rodan-lite/backend/django/code/jobs/interactive_classifier/`] with a non-Django Python service, a React + Vite frontend, and no Gamera dependency.
6+
7+
## Key differences from the legacy IC
8+
9+
- **Input is a full page image plus a bounding-box annotation file** (for example, MOTHRA JSON or YOLO), not page-level GameraXML. Neume crops are derived from those annotations rather than supplied as pre-cropped glyph images.
10+
- **Manual split (CCA on a single glyph) is deferred.** Reintroduce only if real data shows crops that contain multiple neumes.
11+
- **Output stays as GameraXML** so downstream MEI pipelines keep working.
12+
13+
## Status
14+
15+
| Layer | Path | Status |
16+
|-------------|--------------|---------------------------------------|
17+
| Algorithm core | `core/ic_core/` | In progress — scaffolded, partial impl |
18+
| API | `api/` | In progress, open to future change |
19+
| Frontend | `frontend/` | Not started |
20+
21+
## Repository layout
22+
23+
```
24+
ic_new/
25+
├── core/
26+
│ ├── ic_core/ # Phase 1: algorithm core (uv-managed Python package)
27+
│ └── tests/ # Pytest suite + fixtures
28+
├── api/ # Phase 2: FastAPI service (planned)
29+
├── frontend/ # Phase 3: React + Vite UI (planned)
30+
└── docs/
31+
├── CLAUDE.md # Guidance for Claude Code working in this repo
32+
├── migration_plan.md
33+
└── KNN_ALGORITHM.md
34+
```
35+
36+
## Quickstart (algorithm core)
37+
38+
The core package uses [uv](https://docs.astral.sh/uv/) for environment and dependency management.
39+
40+
```bash
41+
cd core/ic_core
42+
uv sync # install dependencies
43+
uv run pytest ../tests # run tests
44+
uv run ruff check . # lint
45+
```
46+
47+
## Documentation
48+
49+
- [docs/migration_plan.md](docs/migration_plan.md) — full migration strategy, phasing, and risks
50+
- [docs/KNN_ALGORITHM.md](docs/KNN_ALGORITHM.md) — algorithm spec and invariants
51+
- [docs/CLAUDE.md](docs/CLAUDE.md) — architecture notes and conventions for AI-assisted development

api/README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# ic-api
2+
3+
FastAPI service that wraps [`ic_core`](../core/ic_core) and exposes
4+
the Interactive Classifier as HTTP endpoints for the frontend.
5+
6+
This is Phase 2 of the migration plan (`../docs/migration_plan.md`).
7+
The service stores session state in-memory only — sessions are lost
8+
on restart, which is fine for the single-user / local-tool target.
9+
Swap [`store.py`](src/ic_api/store.py) for a SQLite-backed store
10+
when persistence becomes a requirement.
11+
12+
## Run
13+
14+
```bash
15+
uv sync
16+
uv run ic-api # binds to 127.0.0.1:8000
17+
```
18+
19+
## Endpoints
20+
21+
| Method | Path | Purpose |
22+
|--------|------|---------|
23+
| `POST` | `/sessions` | Create a session and ingest a page + bbox file |
24+
| `GET` | `/sessions/{id}` | Fetch the current session state |
25+
| `POST` | `/sessions/{id}/classify` | Run a classify round |
26+
| `POST` | `/sessions/{id}/glyphs/{gid}` | Update a single glyph |
27+
| `DELETE` | `/sessions/{id}/glyphs/{gid}` | Delete a glyph |
28+
| `POST` | `/sessions/{id}/group` | Manual group (union N glyphs) |
29+
| `POST` | `/sessions/{id}/auto-group` | **501** — deferred (needs page-coord input) |
30+
| `POST` | `/sessions/{id}/classes/{name}/rename` | Rename a class |
31+
| `DELETE` | `/sessions/{id}/classes/{name}` | Delete a class from autocomplete |
32+
| `POST` | `/sessions/{id}/save` | No-op for the in-memory store; returns current state |
33+
| `POST` | `/sessions/{id}/complete` | Transition to EXPORT, returns GameraXML |
34+
| `DELETE` | `/sessions/{id}` | Discard the session |
35+
36+
See [`src/ic_api/main.py`](src/ic_api/main.py) for the full schemas.

api/pyproject.toml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
[project]
2+
name = "ic-api"
3+
version = "0.1.0"
4+
description = "FastAPI service for the Interactive Classifier"
5+
readme = "README.md"
6+
authors = [
7+
{ name = "Yueqiao Zhang", email = "yueqiao.zhang@mail.mcgill.ca" }
8+
]
9+
requires-python = ">=3.11"
10+
dependencies = [
11+
"fastapi>=0.118.0",
12+
"uvicorn[standard]>=0.32.0",
13+
"pydantic>=2.10.0",
14+
# Required by FastAPI's UploadFile/Form parsing for the
15+
# multipart POST /sessions endpoint.
16+
"python-multipart>=0.0.20",
17+
"ic-core",
18+
]
19+
20+
[project.scripts]
21+
ic-api = "ic_api.main:run"
22+
23+
[tool.uv.sources]
24+
# Use the sibling core package directly during dev so changes there
25+
# are picked up without re-publishing.
26+
ic-core = { path = "../core/ic_core", editable = true }
27+
28+
[build-system]
29+
requires = ["uv_build>=0.11.14,<0.12.0"]
30+
build-backend = "uv_build"
31+
32+
[dependency-groups]
33+
dev = [
34+
"httpx>=0.27.0",
35+
"pytest>=9.0.3",
36+
"pytest-asyncio>=1.0.0",
37+
"ruff>=0.15.12",
38+
]

api/src/ic_api/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
"""ic-api — FastAPI service wrapping the ic_core algorithm package."""
2+
from ic_api.main import app, run
3+
4+
__all__ = ["app", "run"]

0 commit comments

Comments
 (0)