@priyadarship4/coursy 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +210 -2
- package/bin/coursy.mjs +1432 -0
- package/client/dist/assets/index-Do3gCYxi.css +1 -0
- package/client/dist/assets/index-DxuZ2Pwp.js +69 -0
- package/client/dist/index.html +13 -0
- package/docs/BEST_PRACTICES.md +382 -0
- package/docs/DEPENDENCIES_AND_PLATFORM_LLD.md +219 -0
- package/docs/ENRICHMENT_MERGE_LLD.md +546 -0
- package/docs/LEARNING_ENGINE_LLD.md +161 -0
- package/docs/OPENCODE_GO_LLD.md +214 -0
- package/docs/PROJECT_STRUCTURE.md +193 -0
- package/docs/TEXT_COURSE_LLD.md +190 -0
- package/docs/WEBSITE_LLD.md +477 -0
- package/package.json +51 -4
- package/server/dist/cli-data.js +336 -0
- package/server/dist/config.js +89 -0
- package/server/dist/db/db.js +79 -0
- package/server/dist/features/courses/course.service.js +235 -0
- package/server/dist/features/courses/courses.controller.js +137 -0
- package/server/dist/features/courses/courses.repository.js +77 -0
- package/server/dist/features/courses/scan.service.js +164 -0
- package/server/dist/features/courses/section.repository.js +39 -0
- package/server/dist/features/enrichment/enrichment.config.js +119 -0
- package/server/dist/features/enrichment/enrichment.controller.js +642 -0
- package/server/dist/features/enrichment/enrichment.repository.js +289 -0
- package/server/dist/features/enrichment/enrichment.service.js +1038 -0
- package/server/dist/features/enrichment/events.service.js +55 -0
- package/server/dist/features/enrichment/pipeline/align.js +23 -0
- package/server/dist/features/enrichment/pipeline/concepts.js +72 -0
- package/server/dist/features/enrichment/pipeline/concepts.test.js +64 -0
- package/server/dist/features/enrichment/pipeline/export.js +29 -0
- package/server/dist/features/enrichment/pipeline/extract.js +104 -0
- package/server/dist/features/enrichment/pipeline/interview.js +82 -0
- package/server/dist/features/enrichment/pipeline/plan.js +109 -0
- package/server/dist/features/enrichment/pipeline/practice.js +107 -0
- package/server/dist/features/enrichment/pipeline/rollup.js +46 -0
- package/server/dist/features/enrichment/pipeline/summarize.js +70 -0
- package/server/dist/features/enrichment/pipeline/transcribe.js +64 -0
- package/server/dist/features/enrichment/prompts/templates.js +54 -0
- package/server/dist/features/enrichment/providers/llm.js +160 -0
- package/server/dist/features/enrichment/providers/llm.test.js +83 -0
- package/server/dist/features/enrichment/providers/media/subproc.js +48 -0
- package/server/dist/features/enrichment/providers/transcriber/fluidaudio.js +55 -0
- package/server/dist/features/enrichment/providers/transcriber/subtitle.js +51 -0
- package/server/dist/features/enrichment/providers/transcriber/types.js +9 -0
- package/server/dist/features/enrichment/providers/transcriber/whisper-api.js +29 -0
- package/server/dist/features/fs/fs.controller.js +36 -0
- package/server/dist/features/fs/fs.service.js +74 -0
- package/server/dist/features/learning/concept-materializer.js +104 -0
- package/server/dist/features/learning/engines/mastery.js +27 -0
- package/server/dist/features/learning/engines/mastery.test.js +39 -0
- package/server/dist/features/learning/engines/review-engine.js +48 -0
- package/server/dist/features/learning/engines/review-engine.test.js +59 -0
- package/server/dist/features/learning/engines/scheduler.js +60 -0
- package/server/dist/features/learning/engines/scheduler.test.js +61 -0
- package/server/dist/features/learning/learning.config.js +53 -0
- package/server/dist/features/learning/learning.config.test.js +34 -0
- package/server/dist/features/learning/learning.controller.js +145 -0
- package/server/dist/features/learning/learning.repository.js +334 -0
- package/server/dist/features/learning/learning.service.js +496 -0
- package/server/dist/features/learning/learning.types.js +1 -0
- package/server/dist/features/lessons/lessons.controller.js +126 -0
- package/server/dist/features/lessons/lessons.repository.js +56 -0
- package/server/dist/features/lessons/lessons.service.js +155 -0
- package/server/dist/features/lessons/stream.service.js +94 -0
- package/server/dist/features/lessons/text-content.js +294 -0
- package/server/dist/features/lessons/text-content.test.js +278 -0
- package/server/dist/features/notes/notes.controller.js +91 -0
- package/server/dist/features/notes/notes.repository.js +50 -0
- package/server/dist/features/notes/notes.service.js +78 -0
- package/server/dist/features/profile/profile.controller.js +81 -0
- package/server/dist/features/profile/profile.repository.js +41 -0
- package/server/dist/features/profile/profile.service.js +128 -0
- package/server/dist/features/progress/progress.controller.js +58 -0
- package/server/dist/features/progress/progress.repository.js +64 -0
- package/server/dist/features/progress/progress.service.js +39 -0
- package/server/dist/features/settings/settings.controller.js +54 -0
- package/server/dist/features/settings/settings.repository.js +33 -0
- package/server/dist/features/settings/settings.service.js +173 -0
- package/server/dist/features/settings/text-mode.js +21 -0
- package/server/dist/features/settings/text-mode.test.js +28 -0
- package/server/dist/features/stats/stats.controller.js +32 -0
- package/server/dist/features/stats/stats.repository.js +39 -0
- package/server/dist/features/stats/stats.service.js +114 -0
- package/server/dist/features/system/system.controller.js +86 -0
- package/server/dist/index.js +144 -0
- package/server/dist/shared/api-error.js +7 -0
- package/server/dist/shared/app-lifecycle.js +11 -0
- package/server/dist/shared/binary.js +90 -0
- package/server/dist/shared/dependencies.js +90 -0
- package/server/dist/shared/logging.js +295 -0
- package/server/dist/shared/natural-sort.js +11 -0
- package/server/dist/shared/server-info.js +70 -0
- package/server/dist/shared/slug.js +20 -0
- package/server/dist/shared/uuid.js +41 -0
- package/server/dist/shared/uuid.test.js +23 -0
- package/server/dist/types.js +1 -0
- package/server/migrations/0001_baseline.up.sql +82 -0
- package/server/migrations/0002_enrichment.down.sql +11 -0
- package/server/migrations/0002_enrichment.up.sql +143 -0
- package/server/migrations/0003_course_enrich_opt_in.down.sql +1 -0
- package/server/migrations/0003_course_enrich_opt_in.up.sql +1 -0
- package/server/migrations/0004_learning_engine.down.sql +7 -0
- package/server/migrations/0004_learning_engine.up.sql +101 -0
- package/server/migrations/0005_text_progress.down.sql +1 -0
- package/server/migrations/0005_text_progress.up.sql +2 -0
package/README.md
CHANGED
|
@@ -1,3 +1,211 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Coursy
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Local-first AI study companion for downloaded video and text courses. Point it at a folder of
|
|
4
|
+
course videos; it plays them like a curriculum, tracks progress, and builds an AI layer on top:
|
|
5
|
+
per-lesson summaries, scene navigation, practice questions, voice mock interviews, and a
|
|
6
|
+
personalized study plan.
|
|
7
|
+
|
|
8
|
+
## Requirements
|
|
9
|
+
|
|
10
|
+
- Node.js **22.13+**
|
|
11
|
+
- `ffmpeg` + `ffprobe` on PATH — needed for AI enrichment only; playback works without them:
|
|
12
|
+
- macOS: `brew install ffmpeg`
|
|
13
|
+
- Windows: `winget install Gyan.FFmpeg` (or `choco install ffmpeg`)
|
|
14
|
+
- Linux: `sudo apt install ffmpeg` (Fedora: `sudo dnf install ffmpeg`, Arch: `sudo pacman -S ffmpeg`)
|
|
15
|
+
- Custom installs: `COURSY_FFMPEG_PATH` / `COURSY_FFPROBE_PATH` (file or directory)
|
|
16
|
+
- Optional: an OpenAI-compatible LLM key (DeepSeek, OpenCode Go, OpenAI, OpenRouter, Ollama, …)
|
|
17
|
+
- Optional transcription: subtitles (`.srt`/`.vtt`) next to videos, a Whisper-compatible API key, or
|
|
18
|
+
FluidAudio on macOS for fully local transcription
|
|
19
|
+
|
|
20
|
+
Missing dependencies never break playback: Coursy shows a warning with the exact fix in
|
|
21
|
+
`coursy doctor`, `coursy status`, the web UI, and disables enrichment actions with the
|
|
22
|
+
reason.
|
|
23
|
+
|
|
24
|
+
## Data directory
|
|
25
|
+
|
|
26
|
+
Everything lives in one folder — `~/.coursy` on every OS (override with
|
|
27
|
+
`COURSY_DATA_DIR` or `--data-dir`):
|
|
28
|
+
|
|
29
|
+
| OS | Path |
|
|
30
|
+
|---|---|
|
|
31
|
+
| macOS | `/Users/<user>/.coursy` |
|
|
32
|
+
| Linux | `/home/<user>/.coursy` |
|
|
33
|
+
| Windows | `C:\Users\<user>\.coursy` (cmd/PowerShell: `%USERPROFILE%\.coursy`) |
|
|
34
|
+
|
|
35
|
+
It contains `coursy.db`, `media/`, `artifacts/`, `thumbs/`, `coursy.log` and
|
|
36
|
+
`server.json`. Course folders are never written to.
|
|
37
|
+
|
|
38
|
+
Upgrading from Opencourser: the first run after the rename copies `~/.opencourser` into
|
|
39
|
+
`~/.coursy` automatically (database, media, artifacts, thumbnails). Legacy `OPENCOURSER_*`
|
|
40
|
+
environment variables are still honored, and the `opencourser` command keeps working as an alias
|
|
41
|
+
for `coursy`.
|
|
42
|
+
|
|
43
|
+
## Quick start
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npx @priyadarship4/coursy # start the server and open the UI (foreground)
|
|
47
|
+
npx @priyadarship4/coursy start --d # start in the background (daemon)
|
|
48
|
+
npx @priyadarship4/coursy play ~/courses # add/scan a course folder and open it
|
|
49
|
+
npx @priyadarship4/coursy status # server, queue, storage and setup status
|
|
50
|
+
npx @priyadarship4/coursy stats # learning, ai and server stats
|
|
51
|
+
npx @priyadarship4/coursy logs -f # tail the log (JSON lines on disk)
|
|
52
|
+
npx @priyadarship4/coursy doctor # check ffmpeg, transcription and LLM setup
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Keep a course folder anywhere on disk — Coursy never writes to it. All state lives in
|
|
56
|
+
`~/.coursy` (override with `COURSY_DATA_DIR` or `--data-dir`).
|
|
57
|
+
|
|
58
|
+
The server runs on **`:4257`** by default (`http://127.0.0.1:4257`). If that port is taken by
|
|
59
|
+
another app, the CLI picks the next free one and tells you (`port 4257 is in use — using 4258`);
|
|
60
|
+
passing `--port` explicitly is strict and fails instead of shifting. The Vite dev client proxies
|
|
61
|
+
to `COURSY_PORT` (default `4257`).
|
|
62
|
+
|
|
63
|
+
## CLI reference
|
|
64
|
+
|
|
65
|
+
| Command | What it does |
|
|
66
|
+
|---|---|
|
|
67
|
+
| `start` | Foreground server; `--detach` / `-d` / `--d` runs it in the background |
|
|
68
|
+
| `stop` / `restart` | Manage the background server (pid file: `~/.coursy/server.json`) |
|
|
69
|
+
| `status` | Version, uptime, memory, storage, queue, readiness, recent failures |
|
|
70
|
+
| `stats [learning\|ai\|server]` | Sections: watch time/streaks/practice, LLM + transcription usage, disk/queue health |
|
|
71
|
+
| `logs` | Tail logs; `-f` follow, `-n` lines, `--date`, `--level`, `--grep`, `--path`, `--prune`, `--json` |
|
|
72
|
+
| `config list\|get\|set\|unset` | Read/write settings (secrets masked); same whitelist as the Settings UI |
|
|
73
|
+
| `courses` | Course list with progress, enrichment and practice counts |
|
|
74
|
+
| `revisions [days]` | Due and upcoming spaced-repetition reviews (default 7 days) |
|
|
75
|
+
| `play <path>` | Scan a folder and open the course |
|
|
76
|
+
| `enrich <path\|id>` | Run enrichment for a whole course (`-f` to watch progress) |
|
|
77
|
+
| `remove <id\|slug>` | Delete a course with its AI artifacts, media cache and thumbnails |
|
|
78
|
+
| `export <id\|slug>` | Write summaries, rollups, master notes and the plan as markdown (`--out <dir>`) |
|
|
79
|
+
| `open` / `doctor` / `version` / `help` | Open the UI, environment checks, help |
|
|
80
|
+
|
|
81
|
+
Global flags: `--data-dir`, `--port`, `--host`, `--json`, `--quiet`, `--no-color`.
|
|
82
|
+
Long options accept unambiguous prefixes (`--det` → `--detach`); command-specific flags win
|
|
83
|
+
(`coursy start --d` → detach, `coursy logs --d` → date, `coursy stats --d` → days).
|
|
84
|
+
|
|
85
|
+
## Logging
|
|
86
|
+
|
|
87
|
+
Server logs are JSON lines in `~/.coursy/coursy.log` (requests, enrichment pipeline,
|
|
88
|
+
LLM retries, slow SQLite queries, errors). Daily archives roll to `coursy-YYYY-MM-DD.log`;
|
|
89
|
+
files older than 3 days are gzipped and archives older than 30 days are deleted
|
|
90
|
+
(`COURSY_LOG_RETENTION_DAYS`, `COURSY_LOG_KEEP_DAYS`). Detached servers also pipe
|
|
91
|
+
stdout to `~/.coursy/coursy.out.log`.
|
|
92
|
+
|
|
93
|
+
## AI setup
|
|
94
|
+
|
|
95
|
+
Open **Settings → AI enrichment**:
|
|
96
|
+
|
|
97
|
+
- **LLM**: base URL + model + API key (stored locally in SQLite, never sent anywhere except the
|
|
98
|
+
provider you configure). Use *Test* to verify. OpenCode Go works out of the box: base URL
|
|
99
|
+
`https://opencode.ai/zen/go/v1`, model `deepseek-v4.1-flash`; Coursy adds the required
|
|
100
|
+
`x-opencode-session` header automatically ([design](docs/OPENCODE_GO_LLD.md)).
|
|
101
|
+
- **Transcription** order in `auto` mode: existing subtitles → local FluidAudio (macOS) → Whisper API.
|
|
102
|
+
- **Interview**: prep timer, max answer length, strictness.
|
|
103
|
+
|
|
104
|
+
Enrichment is opt-in per course: check **Enrich this course** in the study setup (or start it from
|
|
105
|
+
the Enrichment tab). Once a course is opted in, opening a lesson enqueues it and prefetches the next
|
|
106
|
+
two, with an optional **Enrich course** batch run. Pause/resume/cancel and retry are always available;
|
|
107
|
+
the home page shows a live queue for every active course.
|
|
108
|
+
|
|
109
|
+
## What it generates
|
|
110
|
+
|
|
111
|
+
| Artifact | Where |
|
|
112
|
+
|---|---|
|
|
113
|
+
| Lesson summary + key points | Enrichment tab |
|
|
114
|
+
| Scene thumbnails (click to seek) | Enrichment tab |
|
|
115
|
+
| Practice: MCQs (instant feedback) | Enrichment tab |
|
|
116
|
+
| Voice/typed mock interview with follow-ups and grading | Enrichment tab |
|
|
117
|
+
| Study plan from your goals and time budget | Plan drawer |
|
|
118
|
+
| Section rollups + master notes | Plan drawer → Notes |
|
|
119
|
+
| Markdown export bundle | Plan drawer → Export |
|
|
120
|
+
|
|
121
|
+
## Spaced repetition
|
|
122
|
+
|
|
123
|
+
Practice generation also extracts 3–8 **concepts** per lesson and tags every question with
|
|
124
|
+
one. Finishing a quick check records per-concept evidence; concepts then resurface on a
|
|
125
|
+
`1/3/7/14/30/60`-day schedule (adaptive by default, `fail → tomorrow`, `hard → ×0.6`,
|
|
126
|
+
`good → next`, `easy → skip one`). Practice sessions never move the schedule — only
|
|
127
|
+
scheduled/manual reviews do.
|
|
128
|
+
|
|
129
|
+
| Surface | Where |
|
|
130
|
+
|---|---|
|
|
131
|
+
| Revision schedule rail (due now + 14-day agenda) | Home → right rail |
|
|
132
|
+
| Review dialog (MCQ + confidence → mastery/next due) | Home → Revision schedule · `coursy revisions` in the terminal |
|
|
133
|
+
| Concept mastery, performance curve, improvement insights | Stats |
|
|
134
|
+
|
|
135
|
+
Settings (`/api/settings`, `settings` table): `learning_preset`
|
|
136
|
+
(`relaxed|standard|intensive|custom`), `learning_steps`, `learning_adaptive`,
|
|
137
|
+
`learning_daily_target_min`, `learning_preferred_time` — global with per-course overrides.
|
|
138
|
+
Full design: [`docs/LEARNING_ENGINE_LLD.md`](docs/LEARNING_ENGINE_LLD.md).
|
|
139
|
+
|
|
140
|
+
## Development
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
npm install
|
|
144
|
+
npm run dev # server on :4257 + Vite dev client
|
|
145
|
+
npm run build # production build (client + server)
|
|
146
|
+
npm run doctor
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Data model and architecture: [`docs/ENRICHMENT_MERGE_LLD.md`](docs/ENRICHMENT_MERGE_LLD.md).
|
|
150
|
+
|
|
151
|
+
## Testing
|
|
152
|
+
|
|
153
|
+
**Unit (no API keys needed).** Scheduler, mastery EMA, review engine, concept
|
|
154
|
+
normalization and UUIDv7:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
npm run test:unit
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**Automated (no API keys needed).** Builds both workspaces, generates a synthetic course with
|
|
161
|
+
ffmpeg (2 scene cuts, an `.srt` sidecar, a text lesson), runs a local mock OpenAI-compatible
|
|
162
|
+
server, and exercises the full pipeline through the real HTTP API:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
npm run test:e2e
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
90+ checks cover: scan → queue → extract → subtitle/Whisper transcription → align → summarize →
|
|
169
|
+
practice; persona/goal prompt injection; study plan; typed and voice interview turns with
|
|
170
|
+
follow-ups; pause/resume; dry-run without a key; section rollups; master notes; export; plus
|
|
171
|
+
enrichment consent gating (prefetch skipped until opt-in), the live queue payload, and course
|
|
172
|
+
deletion (DB cascade + on-disk cleanup).
|
|
173
|
+
Fixtures and the test database are kept under `$TMPDIR/coursy-e2e` for inspection.
|
|
174
|
+
|
|
175
|
+
CLI lifecycle, logging, rotation and config round-trips are covered by:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
npm run test:cli
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**Manual (real browser).**
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
npm run dev
|
|
185
|
+
# open http://localhost:5173
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
1. `Settings → AI enrichment`: add your LLM key and press *Test*. Optionally set the FluidAudio
|
|
189
|
+
binary path for local macOS transcription.
|
|
190
|
+
2. Drop a course folder path on the home page (or run `node bin/coursy.mjs play <path>`).
|
|
191
|
+
3. The full-screen **study setup** opens: persona (level, weak areas), course goal (struggles,
|
|
192
|
+
deadline), then the enrichment opt-in with a first-lesson or whole-course scope, and finally the
|
|
193
|
+
study plan. Nothing is enriched until you check the opt-in.
|
|
194
|
+
4. Open the first lesson — enrichment follows your opt-in. Watch `Enrichment` for the summary, scene
|
|
195
|
+
thumbnails (click one to seek the video), MCQs and the mock interview (allow microphone access
|
|
196
|
+
to answer out loud). Use `Plan` for rollups, master notes and the markdown export, and `Setup` to
|
|
197
|
+
change your profile, goal or consent later.
|
|
198
|
+
5. Check `node bin/coursy.mjs doctor` for ffmpeg/FluidAudio/LLM readiness, and
|
|
199
|
+
`node bin/coursy.mjs enrich <path>` for a headless full-course run. Remove courses from the
|
|
200
|
+
card `⋯ → Remove course` menu or with `coursy remove <id|slug>`.
|
|
201
|
+
|
|
202
|
+
To test the real FluidAudio path, set the binary once:
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
export FLUIDAUDIO_BIN="/path/to/course-extractor/vendor/FluidAudio/.build/release/fluidaudiocli"
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
## License
|
|
210
|
+
|
|
211
|
+
MIT
|