Arabic-first reading tutor for ages 6–9.
نقرأ سوا. والإجابة تيجي منك.
Fahman doesn’t read it for them. It teaches them to read it.
Hackathon: GDG on Campus ECU × Union Mindz — Build AI that earns its impact.

A generic bot sees بَابْ and says the word. The child copies. That is not reading.
Fahman never says or writes the full word first. It shows the word, asks Socratic questions about letter shape and dots, then (only after the child succeeds) speaks the word and gives the meaning.
Do this path. Do not start with photo or microphone.
بَابْ → it reads the word. That is the gap.Photo / mic / upload use the same lesson. If they fail, the list still works. JSON questions work even if Nile-Chat is down.
| Rule | What we do |
|---|---|
| Never spoil the word | No correct full-word button. Choices are letters only (ث / ت / ب). |
| Whole word | Child walks letter by letter. Full word is spoken only at the end. |
| 3 wrongs on one letter | Play that letter’s sound, show it, stay on the same letter. Do not skip to the next word. |
| New / unknown words | Still a lesson (unknownItem). No crash on empty JSON match. |
| OCR mistakes | Confirm/edit screen. We do not train OCR. |
| Vowels | Mishkal only. Dataset JSON is the question bank, not the vocalizer. |
| Voice | Edge TTS ar-EG-SalmaNeural. No MMS-TTS. |
| Tutor LLM | Nile-Chat via Ollama /api/generate. If it fails or says the blocked word → JSON q_level_*. |
Dropped on purpose (do not bring back): MMS-TTS, Tashkeel-50M, fine-tuning Qari/Whisper/Edge on the 189-row sheet.
Browser (Next.js :3000, RTL, Cairo + Amiri)
│
├─ / photo, mic, upload, 22-word list
├─ /lesson letter walk + Nile/JSON questions
└─ /dashboard حروفي (localStorage memory)
│
▼
FastAPI (Python :8001)
├─ /tashkeel Mishkal (+ JSON tashkeel fallback for known words)
├─ /ocr Qari-OCR-v0.3 (CPU, first call is slow)
├─ /transcribe Whisper-small (ffmpeg → WAV → numpy)
├─ /tutor Ollama Nile-Chat-4B generate, else fallback
└─ /tts Edge TTS (internet). ?slow=1 → slower rate
│
▼
Ollama :11434 model: hf.co/mradermacher/Nile-Chat-4B-GGUF:Q4_K_M
UI: paper #F6F0E6, indigo #1B2A4A, teal #0F7B6C, gold #E8A838, terracotta #D4654A.
word_tashkeel), OCR confirm, mic, or upload.letter_true + letter_wrong) and shows:
q_level_1 (dots above/below, how many)q_level_2 (e.g. نقطة واحدة فوق. يبقى الحرف إيه؟)q_level_3 (ن ولا ت؟)localStorage key fahman-memory-v1) marks letters weak/strong for حروفي.Nile-Chat is asked on the first question of a letter (flavor). After a wrong tap, JSON is the source of truth so the demo does not depend on Ollama latency.
| File | Role |
|---|---|
data/fahman.json | App + tutor. 189 rows, 22 unique words. |
data/fahman_dataset.xlsx | Same curriculum in Excel. |
Each row includes: word_tashkeel, error_code, letter_true / letter_wrong, q_level_1…q_level_4, blocked_word, nile_facts, meaning.
This JSON is not used to train OCR or Whisper.
| Piece | Model | Notes |
|---|---|---|
| Tutor | Nile-Chat-4B GGUF Q4_K_M via Ollama | Must use /api/generate (chat returns empty). |
| OCR | NAMAA-Space/Qari-OCR-v0.3-VL-2B-Instruct | First call loads ~2B on CPU. Can confuse س/ش, ع/غ. Confirm/edit. |
| ASR | openai/whisper-small | Arabic transcribe. First load is slow. |
| Diacritize | Mishkal | Do not swap. |
| TTS | Edge ar-EG-SalmaNeural | Needs internet. |
| ffmpeg | Bundled imageio-ffmpeg in the venv | Converts uploads to WAV. |
Weights for OCR/Whisper live in the Hugging Face cache (not inside this repo), usually:
C:\Users\<you>\.cache\huggingface
Ollama weights live in Ollama’s own directory, not this repo.
Teammates: double-click setup.cmd once, then run.cmd every time. Details in HOW-TO-RUN.md.
Need Node, Python 3.12, Ollama, and internet (TTS).
Leave three processes running.
Terminal A — Ollama
ollama serve
If you see bind: Only one usage of each socket address on port 11434, Ollama is already running. Skip this terminal.
Pull once (if missing):
ollama pull hf.co/mradermacher/Nile-Chat-4B-GGUF:Q4_K_M
Terminal B — API (port 8001, not 8000)
cd C:\Users\Mosta\OneDrive\Documents\Education-system
.venv\Scripts\activate
python -m uvicorn server.main:app --port 8001
Wait for: Uvicorn running on http://127.0.0.1:8001
Terminal C — website
cd C:\Users\Mosta\OneDrive\Documents\Education-system
npm run dev
If npm is missing: "C:\Program Files\nodejs\npm.cmd" run dev
.env.local:
NEXT_PUBLIC_API_URL=http://127.0.0.1:8001
Copying this folder alone is not enough.
Copy
app/, lib/, data/, server/, package.json, package-lock.json, .env.local, setup.cmd, run.cmd, HOW-TO-RUN.mdnode_modules, .next, .venv (recreate them with setup.cmd)Does not live in the repo (copy separately or re-download)
On the new Windows PC
.venv paths):python -m venv .venv
.venv\Scripts\activate
pip install -r server\requirements.txt
server/requirements.txt lists the direct packages. If install is incomplete, on the original PC run pip freeze > server\full-freeze.txt and install that file.
npm install then npm run devollama pull hf.co/mradermacher/Nile-Chat-4B-GGUF:Q4_K_MEdge TTS still needs internet on the new machine.
| Method | Path | Role |
|---|---|---|
| GET | /health | { ok, ollama } |
| POST | /tashkeel | Mishkal diacritics |
| POST | /ocr | Image → Arabic word |
| POST | /transcribe | Audio → text |
| POST | /tutor | Nile question or JSON fallback |
| GET | /tts?text= | Speak. Add letter=1 for a single letter. Add slow=1 for slow word. |
fahman.json with q_level_*, blocked_word, error_code./api/chat returned empty; switched to /api/generate./tashkeel; if the API hiccuped, all 22 words failed. List now opens from JSON word_tashkeel.app/page.tsx Home: photo, mic, upload, word list
app/lesson/ui.tsx Letter lesson
app/dashboard/page.tsx حروفي
lib/engine.ts JSON, memory, unknown words
lib/letters.ts Letter choices + JSON guiding questions
lib/mic.ts WAV recording
lib/api.ts FastAPI client
server/main.py OCR, Whisper, Mishkal, Edge, Nile
data/fahman.json Question bank
Fahman is an Arabic reading tutor that refuses to say the word first — it teaches the child to read it, letter by letter, with questions from a real error dataset and a local Arabic tutor model as backup.
Arabic-first reading tutor for ages 6–9.
نقرأ سوا. والإجابة تيجي منك.
Fahman doesn’t read it for them. It teaches them to read it.
Hackathon: GDG on Campus ECU × Union Mindz — Build AI that earns its impact.

A generic bot sees بَابْ and says the word. The child copies. That is not reading.
Fahman never says or writes the full word first. It shows the word, asks Socratic questions about letter shape and dots, then (only after the child succeeds) speaks the word and gives the meaning.
Do this path. Do not start with photo or microphone.
بَابْ → it reads the word. That is the gap.Photo / mic / upload use the same lesson. If they fail, the list still works. JSON questions work even if Nile-Chat is down.
| Rule | What we do |
|---|---|
| Never spoil the word | No correct full-word button. Choices are letters only (ث / ت / ب). |
| Whole word | Child walks letter by letter. Full word is spoken only at the end. |
| 3 wrongs on one letter | Play that letter’s sound, show it, stay on the same letter. Do not skip to the next word. |
| New / unknown words | Still a lesson (unknownItem). No crash on empty JSON match. |
| OCR mistakes | Confirm/edit screen. We do not train OCR. |
| Vowels | Mishkal only. Dataset JSON is the question bank, not the vocalizer. |
| Voice | Edge TTS ar-EG-SalmaNeural. No MMS-TTS. |
| Tutor LLM | Nile-Chat via Ollama /api/generate. If it fails or says the blocked word → JSON q_level_*. |
Dropped on purpose (do not bring back): MMS-TTS, Tashkeel-50M, fine-tuning Qari/Whisper/Edge on the 189-row sheet.
Browser (Next.js :3000, RTL, Cairo + Amiri)
│
├─ / photo, mic, upload, 22-word list
├─ /lesson letter walk + Nile/JSON questions
└─ /dashboard حروفي (localStorage memory)
│
▼
FastAPI (Python :8001)
├─ /tashkeel Mishkal (+ JSON tashkeel fallback for known words)
├─ /ocr Qari-OCR-v0.3 (CPU, first call is slow)
├─ /transcribe Whisper-small (ffmpeg → WAV → numpy)
├─ /tutor Ollama Nile-Chat-4B generate, else fallback
└─ /tts Edge TTS (internet). ?slow=1 → slower rate
│
▼
Ollama :11434 model: hf.co/mradermacher/Nile-Chat-4B-GGUF:Q4_K_M
UI: paper #F6F0E6, indigo #1B2A4A, teal #0F7B6C, gold #E8A838, terracotta #D4654A.
word_tashkeel), OCR confirm, mic, or upload.letter_true + letter_wrong) and shows:
q_level_1 (dots above/below, how many)q_level_2 (e.g. نقطة واحدة فوق. يبقى الحرف إيه؟)q_level_3 (ن ولا ت؟)localStorage key fahman-memory-v1) marks letters weak/strong for حروفي.Nile-Chat is asked on the first question of a letter (flavor). After a wrong tap, JSON is the source of truth so the demo does not depend on Ollama latency.
| File | Role |
|---|---|
data/fahman.json | App + tutor. 189 rows, 22 unique words. |
data/fahman_dataset.xlsx | Same curriculum in Excel. |
Each row includes: word_tashkeel, error_code, letter_true / letter_wrong, q_level_1…q_level_4, blocked_word, nile_facts, meaning.
This JSON is not used to train OCR or Whisper.
| Piece | Model | Notes |
|---|---|---|
| Tutor | Nile-Chat-4B GGUF Q4_K_M via Ollama | Must use /api/generate (chat returns empty). |
| OCR | NAMAA-Space/Qari-OCR-v0.3-VL-2B-Instruct | First call loads ~2B on CPU. Can confuse س/ش, ع/غ. Confirm/edit. |
| ASR | openai/whisper-small | Arabic transcribe. First load is slow. |
| Diacritize | Mishkal | Do not swap. |
| TTS | Edge ar-EG-SalmaNeural | Needs internet. |
| ffmpeg | Bundled imageio-ffmpeg in the venv | Converts uploads to WAV. |
Weights for OCR/Whisper live in the Hugging Face cache (not inside this repo), usually:
C:\Users\<you>\.cache\huggingface
Ollama weights live in Ollama’s own directory, not this repo.
Teammates: double-click setup.cmd once, then run.cmd every time. Details in HOW-TO-RUN.md.
Need Node, Python 3.12, Ollama, and internet (TTS).
Leave three processes running.
Terminal A — Ollama
ollama serve
If you see bind: Only one usage of each socket address on port 11434, Ollama is already running. Skip this terminal.
Pull once (if missing):
ollama pull hf.co/mradermacher/Nile-Chat-4B-GGUF:Q4_K_M
Terminal B — API (port 8001, not 8000)
cd C:\Users\Mosta\OneDrive\Documents\Education-system
.venv\Scripts\activate
python -m uvicorn server.main:app --port 8001
Wait for: Uvicorn running on http://127.0.0.1:8001
Terminal C — website
cd C:\Users\Mosta\OneDrive\Documents\Education-system
npm run dev
If npm is missing: "C:\Program Files\nodejs\npm.cmd" run dev
.env.local:
NEXT_PUBLIC_API_URL=http://127.0.0.1:8001
Copying this folder alone is not enough.
Copy
app/, lib/, data/, server/, package.json, package-lock.json, .env.local, setup.cmd, run.cmd, HOW-TO-RUN.mdnode_modules, .next, .venv (recreate them with setup.cmd)Does not live in the repo (copy separately or re-download)
On the new Windows PC
.venv paths):python -m venv .venv
.venv\Scripts\activate
pip install -r server\requirements.txt
server/requirements.txt lists the direct packages. If install is incomplete, on the original PC run pip freeze > server\full-freeze.txt and install that file.
npm install then npm run devollama pull hf.co/mradermacher/Nile-Chat-4B-GGUF:Q4_K_MEdge TTS still needs internet on the new machine.
| Method | Path | Role |
|---|---|---|
| GET | /health | { ok, ollama } |
| POST | /tashkeel | Mishkal diacritics |
| POST | /ocr | Image → Arabic word |
| POST | /transcribe | Audio → text |
| POST | /tutor | Nile question or JSON fallback |
| GET | /tts?text= | Speak. Add letter=1 for a single letter. Add slow=1 for slow word. |
fahman.json with q_level_*, blocked_word, error_code./api/chat returned empty; switched to /api/generate./tashkeel; if the API hiccuped, all 22 words failed. List now opens from JSON word_tashkeel.app/page.tsx Home: photo, mic, upload, word list
app/lesson/ui.tsx Letter lesson
app/dashboard/page.tsx حروفي
lib/engine.ts JSON, memory, unknown words
lib/letters.ts Letter choices + JSON guiding questions
lib/mic.ts WAV recording
lib/api.ts FastAPI client
server/main.py OCR, Whisper, Mishkal, Edge, Nile
data/fahman.json Question bank
Fahman is an Arabic reading tutor that refuses to say the word first — it teaches the child to read it, letter by letter, with questions from a real error dataset and a local Arabic tutor model as backup.