learnx-cli 0.3.0__py3-none-any.whl
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.
- learnx_cli-0.3.0.dist-info/METADATA +240 -0
- learnx_cli-0.3.0.dist-info/RECORD +131 -0
- learnx_cli-0.3.0.dist-info/WHEEL +4 -0
- learnx_cli-0.3.0.dist-info/entry_points.txt +2 -0
- tutor/.env copy.example +4 -0
- tutor/__init__.py +0 -0
- tutor/__main__.py +4 -0
- tutor/assets/__init__.py +5 -0
- tutor/assets/html/fonts/Inter-Bold.woff2 +0 -0
- tutor/assets/html/fonts/Inter-Regular.woff2 +0 -0
- tutor/assets/html/fonts/Inter-SemiBold.woff2 +0 -0
- tutor/assets/html/fonts/JetBrainsMono-Regular.woff2 +0 -0
- tutor/assets/html/highlight-java.min.js +2 -0
- tutor/assets/html/highlight-javascript.min.js +2 -0
- tutor/assets/html/highlight-python.min.js +2 -0
- tutor/assets/html/highlight.min.js +17 -0
- tutor/assets/html/mermaid.min.js +31 -0
- tutor/assets/html/slide_base.css +464 -0
- tutor/assets/html/theme-learnx-dark.css +12 -0
- tutor/audio/__init__.py +0 -0
- tutor/audio/audio_builder.py +143 -0
- tutor/audio/sanitizer.py +9 -0
- tutor/audio/tts_renderer.py +54 -0
- tutor/cli/__init__.py +0 -0
- tutor/cli/commands.py +391 -0
- tutor/cli/logo.py +21 -0
- tutor/cli/playback_commands.py +239 -0
- tutor/cli/shell.py +91 -0
- tutor/cli/shell_context.py +18 -0
- tutor/cli/theme.py +39 -0
- tutor/cli/video_commands.py +123 -0
- tutor/config.py +122 -0
- tutor/conftest.py +5 -0
- tutor/constants.py +82 -0
- tutor/exceptions.py +26 -0
- tutor/generation/__init__.py +0 -0
- tutor/generation/assembler.py +81 -0
- tutor/generation/curriculum.py +97 -0
- tutor/generation/dialogue.py +172 -0
- tutor/generation/narrator.py +122 -0
- tutor/generation/segment_parser.py +223 -0
- tutor/generation/segment_planner.py +200 -0
- tutor/generation/visual_planner.py +205 -0
- tutor/infra/__init__.py +0 -0
- tutor/infra/llm.py +152 -0
- tutor/ingestion/__init__.py +0 -0
- tutor/ingestion/chunker.py +171 -0
- tutor/ingestion/doc_analyzer.py +41 -0
- tutor/ingestion/parse_content.py +19 -0
- tutor/ingestion/summarizer.py +51 -0
- tutor/inspector.py +117 -0
- tutor/llm_config.toml +58 -0
- tutor/models.py +147 -0
- tutor/player/__init__.py +0 -0
- tutor/player/input_handler.py +45 -0
- tutor/player/player.py +308 -0
- tutor/player/player_display.py +117 -0
- tutor/prompts/curriculum.txt +67 -0
- tutor/prompts/dialogue.txt +62 -0
- tutor/prompts/narrate.txt +34 -0
- tutor/prompts/qa.txt +17 -0
- tutor/prompts/summarize.txt +9 -0
- tutor/prompts/visual.txt +60 -0
- tutor/prompts/visual_v3.txt +91 -0
- tutor/qa/__init__.py +0 -0
- tutor/qa/qa.py +105 -0
- tutor/requirements-dev.txt +2 -0
- tutor/requirements.txt +12 -0
- tutor/sample_docs/headingless_large.md +1 -0
- tutor/sample_docs/headingless_test.md +1 -0
- tutor/sample_docs/java-basics.md +78 -0
- tutor/tests/__init__.py +0 -0
- tutor/tests/audio/__init__.py +0 -0
- tutor/tests/audio/test_audio_builder.py +106 -0
- tutor/tests/audio/test_sanitizer.py +41 -0
- tutor/tests/cli/__init__.py +0 -0
- tutor/tests/cli/test_commands.py +67 -0
- tutor/tests/cli/test_video_commands.py +190 -0
- tutor/tests/e2e/README.md +61 -0
- tutor/tests/e2e/__init__.py +0 -0
- tutor/tests/e2e/conftest.py +117 -0
- tutor/tests/e2e/fixtures/README.md +17 -0
- tutor/tests/e2e/fixtures/sample.md +13 -0
- tutor/tests/e2e/test_audio_quality.py +40 -0
- tutor/tests/e2e/test_av_sync.py +56 -0
- tutor/tests/e2e/test_pipeline_smoke.py +37 -0
- tutor/tests/e2e/test_slide_render.py +72 -0
- tutor/tests/e2e/test_video_streams.py +104 -0
- tutor/tests/generation/__init__.py +0 -0
- tutor/tests/generation/conftest.py +134 -0
- tutor/tests/generation/test_assembler.py +64 -0
- tutor/tests/generation/test_curriculum.py +107 -0
- tutor/tests/generation/test_narrator.py +165 -0
- tutor/tests/generation/test_segment_edge_cases.py +280 -0
- tutor/tests/generation/test_segment_planner.py +324 -0
- tutor/tests/generation/test_visual_planner.py +319 -0
- tutor/tests/ingestion/__init__.py +0 -0
- tutor/tests/ingestion/test_chunker.py +94 -0
- tutor/tests/ingestion/test_doc_analyzer.py +51 -0
- tutor/tests/player/__init__.py +0 -0
- tutor/tests/player/test_player_states.py +88 -0
- tutor/tests/test_assets.py +39 -0
- tutor/tests/test_models_visual.py +180 -0
- tutor/tests/visual/__init__.py +0 -0
- tutor/tests/visual/test_beat_timer.py +321 -0
- tutor/tests/visual/test_pipeline_integration.py +178 -0
- tutor/tests/visual/test_slide_renderer.py +298 -0
- tutor/tests/visual/test_subtitle_writer.py +165 -0
- tutor/tests/visual/test_video_assembler.py +108 -0
- tutor/tests/visual/test_visual_pipeline.py +270 -0
- tutor/tutor.py +365 -0
- tutor/visual/__init__.py +213 -0
- tutor/visual/beat_timer.py +222 -0
- tutor/visual/slide_renderer.py +236 -0
- tutor/visual/subtitle_writer.py +187 -0
- tutor/visual/templates/_base.html.j2 +40 -0
- tutor/visual/templates/analogy.html.j2 +21 -0
- tutor/visual/templates/callout.html.j2 +10 -0
- tutor/visual/templates/code_example.html.j2 +12 -0
- tutor/visual/templates/comparison.html.j2 +28 -0
- tutor/visual/templates/decision_guide.html.j2 +37 -0
- tutor/visual/templates/definition.html.j2 +13 -0
- tutor/visual/templates/diagram.html.j2 +11 -0
- tutor/visual/templates/hook_question.html.j2 +17 -0
- tutor/visual/templates/key_insight.html.j2 +9 -0
- tutor/visual/templates/memory_hook.html.j2 +7 -0
- tutor/visual/templates/outro.html.j2 +16 -0
- tutor/visual/templates/question_prompt.html.j2 +13 -0
- tutor/visual/templates/step_sequence.html.j2 +14 -0
- tutor/visual/templates/title_card.html.j2 +12 -0
- tutor/visual/video_assembler.py +299 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: learnx-cli
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Turn any Markdown document into an audio tutorial and MP4 video
|
|
5
|
+
License: MIT
|
|
6
|
+
Requires-Python: >=3.11
|
|
7
|
+
Requires-Dist: edge-tts>=6.1
|
|
8
|
+
Requires-Dist: jinja2>=3.1
|
|
9
|
+
Requires-Dist: openai>=1.30
|
|
10
|
+
Requires-Dist: pillow>=10.0
|
|
11
|
+
Requires-Dist: playwright>=1.44
|
|
12
|
+
Requires-Dist: pydub>=0.25
|
|
13
|
+
Requires-Dist: pygame-ce>=2.5
|
|
14
|
+
Requires-Dist: python-dotenv>=1.0
|
|
15
|
+
Requires-Dist: tqdm>=4.60
|
|
16
|
+
Provides-Extra: dev
|
|
17
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
18
|
+
Requires-Dist: pre-commit>=3.7; extra == 'dev'
|
|
19
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
20
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
21
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
22
|
+
Requires-Dist: types-pillow; extra == 'dev'
|
|
23
|
+
Requires-Dist: types-tqdm; extra == 'dev'
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# LearnX
|
|
27
|
+
|
|
28
|
+

|
|
29
|
+
|
|
30
|
+
Turn any Markdown document into an audio tutorial and MP4 video from a terminal shell.
|
|
31
|
+
|
|
32
|
+
<p align="center">
|
|
33
|
+
<a href="https://youtu.be/q2ugLYZxHSI">
|
|
34
|
+
<img src="https://img.youtube.com/vi/q2ugLYZxHSI/maxresdefault.jpg" alt="LearnX demo — Java Concepts tutorial" width="720" />
|
|
35
|
+
</a>
|
|
36
|
+
<br/>
|
|
37
|
+
<em>Example output: <a href="https://youtu.be/q2ugLYZxHSI">Java Concepts tutorial</a> generated from <code>learning/javaConcept.md</code></em>
|
|
38
|
+
</p>
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
.md file → LLM curriculum → TTS audio → interactive player + Q&A
|
|
42
|
+
→ LLM segment plan → HTML slides → MP4 video
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
<p align="center">
|
|
46
|
+
<img src="learnX.png" alt="LearnX CLI output" />
|
|
47
|
+
</p>
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Quick start
|
|
52
|
+
|
|
53
|
+
```powershell
|
|
54
|
+
pip install -r requirements.txt
|
|
55
|
+
echo "GROQ_API_KEY=gsk_..." > tutor/.env
|
|
56
|
+
playwright install chromium
|
|
57
|
+
python -m tutor
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Requires Python 3.12+, [ffmpeg](https://ffmpeg.org/download.html) in PATH.
|
|
61
|
+
Free API key at [console.groq.com](https://console.groq.com).
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
LearnX > /generate notes.md # markdown → dialogue → audio
|
|
65
|
+
LearnX > /play # interactive player with live Q&A
|
|
66
|
+
LearnX > /video # render slides + assemble MP4
|
|
67
|
+
LearnX > /help # all commands
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## How it was built
|
|
73
|
+
|
|
74
|
+
Two layers share this repository:
|
|
75
|
+
|
|
76
|
+
- **LearnX CLI** (`tutor/`) — the product. Audio tutorial generator.
|
|
77
|
+
- **DevLoop** (`scripts/`) — the build system. Runs Claude in Docker, manages the spec-driven development loop, orchestrates a 5-agent review pipeline.
|
|
78
|
+
|
|
79
|
+
Spec-driven development — every feature started as a written specification before any
|
|
80
|
+
code was written. 31 spec days across v0–v11. Full spec chain in [`specs/`](specs/).
|
|
81
|
+
Full workflow documentation in [`DEVLOOP.md`](DEVLOOP.md).
|
|
82
|
+
|
|
83
|
+
<p align="center">
|
|
84
|
+
<img src="agile.png" alt="Dev loop" />
|
|
85
|
+
</p>
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Dev workflow
|
|
90
|
+
|
|
91
|
+
Each spec day follows this loop:
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
write spec → create branch → devloop launch → review report → merge
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Claude implements the spec inside a Docker container. When it exits, E2E tests and a
|
|
98
|
+
two-phase 5-agent review run automatically. Phase 1 discovers issues and applies fixes;
|
|
99
|
+
Phase 2 verifies resolution.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## One-time setup
|
|
104
|
+
|
|
105
|
+
Do this once on a new machine.
|
|
106
|
+
|
|
107
|
+
**1. Install Docker Desktop**
|
|
108
|
+
|
|
109
|
+
Download from [docker.com/products/docker-desktop](https://www.docker.com/products/docker-desktop/).
|
|
110
|
+
Open Docker Desktop and wait for the status bar to show **"Engine running"**.
|
|
111
|
+
|
|
112
|
+
**2. Build the Docker image** (from the project root)
|
|
113
|
+
|
|
114
|
+
```powershell
|
|
115
|
+
docker build -t learnx-dev .
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Takes 2–5 minutes. Only re-run when `requirements.txt` changes.
|
|
119
|
+
|
|
120
|
+
**3. Activate the Python venv**
|
|
121
|
+
|
|
122
|
+
```powershell
|
|
123
|
+
.\.venv\Scripts\Activate.ps1
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
> If blocked by execution policy:
|
|
127
|
+
> `Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser`
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Running a spec day
|
|
132
|
+
|
|
133
|
+
### Step 1 — Open Docker Desktop
|
|
134
|
+
|
|
135
|
+
Make sure the status bar shows **"Engine running"** before continuing.
|
|
136
|
+
|
|
137
|
+
### Step 2 — Open a PowerShell window
|
|
138
|
+
|
|
139
|
+
> Must be a real PowerShell window — not inside a Claude Code session.
|
|
140
|
+
|
|
141
|
+
```powershell
|
|
142
|
+
cd C:\Users\yusup\LearnX-CLI
|
|
143
|
+
.\.venv\Scripts\Activate.ps1
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Step 3 — Create the branch
|
|
147
|
+
|
|
148
|
+
```powershell
|
|
149
|
+
git checkout main
|
|
150
|
+
git checkout -b sandbox/dayN
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Replace `dayN` with the actual day number (e.g. `day32`).
|
|
154
|
+
|
|
155
|
+
### Step 4 — Dry run
|
|
156
|
+
|
|
157
|
+
```powershell
|
|
158
|
+
python scripts/devloop.py --spec specs/v11/dayN.md --review --dry-run
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Prints the commands that will run without executing anything. Check it looks right.
|
|
162
|
+
|
|
163
|
+
### Step 5 — Launch
|
|
164
|
+
|
|
165
|
+
```powershell
|
|
166
|
+
python scripts/devloop.py --spec specs/v11/dayN.md --review
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Claude Code opens inside the container. When you see the `>` prompt, paste the
|
|
170
|
+
handoff from [`dev_setup/handoff_template.md`](dev_setup/handoff_template.md).
|
|
171
|
+
|
|
172
|
+
Then walk away.
|
|
173
|
+
|
|
174
|
+
### Step 6 — What happens automatically
|
|
175
|
+
|
|
176
|
+
After Claude finishes and exits the container:
|
|
177
|
+
|
|
178
|
+
1. **E2E smoke tests** run inside the container (ffmpeg + Playwright available)
|
|
179
|
+
2. **Phase 1 review** — 3 agents discover issues and apply fixes
|
|
180
|
+
3. **Phase 2 review** — 2 agents verify the fixes and check for regressions
|
|
181
|
+
4. A consolidated report prints with `MERGE READY` or `NEEDS FIXES`
|
|
182
|
+
|
|
183
|
+
### Step 7 — After the report
|
|
184
|
+
|
|
185
|
+
If `MERGE READY`:
|
|
186
|
+
|
|
187
|
+
```powershell
|
|
188
|
+
git checkout main
|
|
189
|
+
git pull origin main
|
|
190
|
+
gh pr create --title "dayN: ..." --body "..."
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
If `NEEDS FIXES`: read the findings, fix the issues, re-run the merge gate:
|
|
194
|
+
|
|
195
|
+
```powershell
|
|
196
|
+
python -m pytest tutor/tests/ --ignore=tutor/tests/e2e/ -v
|
|
197
|
+
python -m ruff check tutor/
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Launcher modes
|
|
203
|
+
|
|
204
|
+
Docker is the default. Always.
|
|
205
|
+
|
|
206
|
+
| Command | Effect |
|
|
207
|
+
|---|---|
|
|
208
|
+
| `python scripts/devloop.py --spec X` | Docker — implement spec X, no review |
|
|
209
|
+
| `python scripts/devloop.py --spec X --review` | Docker — implement X, then E2E + two-phase review |
|
|
210
|
+
| `python scripts/devloop.py --version vN --review` | Docker — run all specs in vN sequentially with review |
|
|
211
|
+
| `python scripts/devloop.py --version vN --serve` | Same, with live dashboard at localhost:8080 |
|
|
212
|
+
| `python scripts/devloop.py --explore` | Host only — read-only, no code changes |
|
|
213
|
+
| `python scripts/devloop.py --dry-run` | Print commands without executing |
|
|
214
|
+
|
|
215
|
+
**`--version`** runs every spec in `specs/vN/` in day-number order. Each spec gets
|
|
216
|
+
its own sandbox branch (`sandbox/vN-dayN`). Rate-limit retries and session/idle
|
|
217
|
+
timeouts are handled automatically.
|
|
218
|
+
|
|
219
|
+
**`--serve`** (with `--version`) starts a dashboard at `http://localhost:8080` showing
|
|
220
|
+
live container output and per-spec status as the run progresses. Port is configurable
|
|
221
|
+
via `--port N` or `LEARNX_DASHBOARD_PORT` env var or `devloop.toml`.
|
|
222
|
+
|
|
223
|
+
**`--explore`** starts Claude on the host with read-only permissions (Read, Grep, Glob,
|
|
224
|
+
git read commands). Use it to ask questions about the codebase without risking
|
|
225
|
+
accidental edits.
|
|
226
|
+
|
|
227
|
+
> Always use forward slashes in `--spec`: `specs/v11/day1.md` not `specs\v11\day1.md`.
|
|
228
|
+
> Backslashes corrupt the path (`\v` is a vertical-tab character).
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Which model?
|
|
233
|
+
|
|
234
|
+
Change model inside any Claude session with `/model`:
|
|
235
|
+
|
|
236
|
+
| Model | Speed | Best for |
|
|
237
|
+
|-------|-------|----------|
|
|
238
|
+
| `claude-sonnet-4-6` | fast | default — most tasks |
|
|
239
|
+
| `claude-opus-4-7` | slower, smarter | complex reasoning, hard bugs |
|
|
240
|
+
| `claude-haiku-4-5` | fastest | simple tasks, quick lookups |
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
tutor/.env copy.example,sha256=dcROn6jMU2dHKVOPUc_i5JpKBhHXJqWsE1BHSneOTq4,128
|
|
2
|
+
tutor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
tutor/__main__.py,sha256=LwdZqbL6h-u-5_FfyCDR0AiH6R5cKruWndS1bkoLVgs,82
|
|
4
|
+
tutor/config.py,sha256=CJ0xCXVMU3EgESjPIsHxXfcL1xB4YhmlV07WPt7yjqI,4075
|
|
5
|
+
tutor/conftest.py,sha256=JXlsocp46uFoEFua74DJzCAzulfaCnE83-WN5gyivhI,175
|
|
6
|
+
tutor/constants.py,sha256=zbjruRK5eaBq-qQ3dKkLY3hbtlS0LR6VhcwkQua1Cg0,2277
|
|
7
|
+
tutor/exceptions.py,sha256=2eXh9TMt6YjNQqZ7YwHMg-dkud2h3EsFGUKBpXHo3m4,640
|
|
8
|
+
tutor/inspector.py,sha256=AOmW2COmGWmXpksy56epnB3WK_sfNOsYJlsYUNlZfn4,4174
|
|
9
|
+
tutor/llm_config.toml,sha256=iUJomVSEYvxVERQGoYZXofd_ghbwmiINQSsQDHJs89A,2426
|
|
10
|
+
tutor/models.py,sha256=jcTo67vOvc91pgwTUDyYHsfOZjGP50uj6DaVgIbr5qo,3170
|
|
11
|
+
tutor/requirements-dev.txt,sha256=5voM8T0d6MyXIv402vAuc9I0_M9C2IpUsOGGL-uhCzE,37
|
|
12
|
+
tutor/requirements.txt,sha256=8Aq8zm9Md9shhOjwduIs3nKSlLnTRurGU6Yt_SKb8Hg,230
|
|
13
|
+
tutor/tutor.py,sha256=5b4vEiKXefm_jKgZMaKtw0P_WAn-7sKvG1lkA9i91U8,13582
|
|
14
|
+
tutor/assets/__init__.py,sha256=rPnbm4W-eDFlf_FOFmfSMRvb2yeeHIYk5ihJMJ5IvRc,136
|
|
15
|
+
tutor/assets/html/highlight-java.min.js,sha256=Fdtmy2Wmsi857HXuf2BP_WNDw_-po1eqeUdhioogqJ0,138
|
|
16
|
+
tutor/assets/html/highlight-javascript.min.js,sha256=rY4Ts3W0u9v8mi5kanl-wlS7i1gElgEPBYxbQ-kPgFo,150
|
|
17
|
+
tutor/assets/html/highlight-python.min.js,sha256=laW43FNREEvCXWi7wCL6tQKcfAe3bkmpneNKq6qTcNw,142
|
|
18
|
+
tutor/assets/html/highlight.min.js,sha256=tRnA8YxUvcS74N8ro0nqDaDXJWAJPomnkS8VnEHP2wQ,650
|
|
19
|
+
tutor/assets/html/mermaid.min.js,sha256=-LUKGnpXsOWFky3rCbwkxSxZwo_awzWR0uD2XCGEiDU,1050
|
|
20
|
+
tutor/assets/html/slide_base.css,sha256=Kg9VdryXw5zLk7GVO5nvW7ibpSNc1_Og1YLbCpvhmuo,13143
|
|
21
|
+
tutor/assets/html/theme-learnx-dark.css,sha256=a0OLl9rDGRWrDVBoht0rh45WIPGQa2Wf-KOK7DEfA1A,659
|
|
22
|
+
tutor/assets/html/fonts/Inter-Bold.woff2,sha256=Igl2cF--wQn0PFz9zspjnpms5-UfPrZykrEF01des5s,111040
|
|
23
|
+
tutor/assets/html/fonts/Inter-Regular.woff2,sha256=tvnbnkW-IPPBMSyX--5-w2t9goD4yqTVPJugQIzJmXo,108488
|
|
24
|
+
tutor/assets/html/fonts/Inter-SemiBold.woff2,sha256=jlKoYdwm_0YIxQvX_4m2XQ1iFqKv57R85dhFRIEcpAA,111588
|
|
25
|
+
tutor/assets/html/fonts/JetBrainsMono-Regular.woff2,sha256=qcsc2CMysjpH46EjnSXRPIbRbEIgaV40skPv-pmfRfI,92164
|
|
26
|
+
tutor/audio/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
27
|
+
tutor/audio/audio_builder.py,sha256=xj_2HNVR_6S__E1-P79aJIFMlxUIKtfK-nwTy1duEOM,4625
|
|
28
|
+
tutor/audio/sanitizer.py,sha256=8xd0c0ld_br-xuCanHSKc3n3GZbUPgy6WoOCP-PhmGM,207
|
|
29
|
+
tutor/audio/tts_renderer.py,sha256=yvvEdxc0aro_23oxBZ5kSZkuLCTHYB8Ue9gWlsDb40U,1482
|
|
30
|
+
tutor/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
31
|
+
tutor/cli/commands.py,sha256=N6-mDhbDXnynVzyv_QyYD4N0tNefnEqKKdysKbz2bOQ,15269
|
|
32
|
+
tutor/cli/logo.py,sha256=kUMPwf3-e3f1lkRNqcVncGqohVSo0cJTJUc4nPUrCsE,1183
|
|
33
|
+
tutor/cli/playback_commands.py,sha256=tpA2xXGhgZSFgtLNEhUfXT7kdhtVdtQ6_VhSHAN5xlA,7602
|
|
34
|
+
tutor/cli/shell.py,sha256=LGrxwdvzgj6pxeJSehlN3U98GkDJMTD4jU57mxoG2g0,2690
|
|
35
|
+
tutor/cli/shell_context.py,sha256=Ca8sz2eD_XH20hzcj-srG3p-32n0R6aydYsPt8IKLCQ,446
|
|
36
|
+
tutor/cli/theme.py,sha256=PScWvpj6IAcAiByUlON0nqJNVhqcZ71lx2bDVwNGOlM,587
|
|
37
|
+
tutor/cli/video_commands.py,sha256=Bd-hL3dZktKe1axw4iwpharo8SKvNdkb-RiTj6sa7y4,4280
|
|
38
|
+
tutor/generation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
39
|
+
tutor/generation/assembler.py,sha256=90koNOPYCxaXTIBcBe7DH5ly0eVKs85bdWUFrhLC0gg,3170
|
|
40
|
+
tutor/generation/curriculum.py,sha256=Wg3svWsGQftluGrSpYroFTr9kq_HklsjBOyfQzBtbNw,3575
|
|
41
|
+
tutor/generation/dialogue.py,sha256=7t-5EryQ3W86XzKqS9AkZTAdKCaAsOMZvG3qyu_aBcM,5797
|
|
42
|
+
tutor/generation/narrator.py,sha256=RCov_lFhhxQcQDtTMpVVG3wJDdqm9UWTty4ahmv0Xe4,3856
|
|
43
|
+
tutor/generation/segment_parser.py,sha256=jBeXkm4DKg1XDGw2_kpTrSCCoLVNDQZxRJoLgde5cD0,6552
|
|
44
|
+
tutor/generation/segment_planner.py,sha256=RlBoRn5uXI1xQFMhfYHfjKSGg_zbD5020W_sDaek-DI,6882
|
|
45
|
+
tutor/generation/visual_planner.py,sha256=Lx2s8-AAruloccUfAgVjV3-tTv_tAgGGJK5_GM54wsQ,6811
|
|
46
|
+
tutor/infra/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
47
|
+
tutor/infra/llm.py,sha256=Bl-aQuy8TmOH_v1Ll7O0Te7VYHAioNtXc7aXA1ejnkU,5145
|
|
48
|
+
tutor/ingestion/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
49
|
+
tutor/ingestion/chunker.py,sha256=0oLMF9YzWHDcZbFvNn940axoPdTlDMPrxUriwoz2Ars,4887
|
|
50
|
+
tutor/ingestion/doc_analyzer.py,sha256=Z37UJ6hP1GcNp1fAVLpGsK4AB2WZqn2cdvHArwlSvtk,1226
|
|
51
|
+
tutor/ingestion/parse_content.py,sha256=9Yyd2vuwpZbsqYXqBBRXXKHxqjO6-PCiFZg4l17Yn64,454
|
|
52
|
+
tutor/ingestion/summarizer.py,sha256=Ecthib5nt8NqQVYMaQrIXRGx4G30VeeU1720tNxtWK0,1599
|
|
53
|
+
tutor/player/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
54
|
+
tutor/player/input_handler.py,sha256=XEtqlFeTgdQpVxslIat4CmvTK5pxCZ6fzGFBY_H2eys,1023
|
|
55
|
+
tutor/player/player.py,sha256=itca5HjxMxJ5l7Y6kf_NTrh0pktC0fVAi-R6LAnoeHM,9778
|
|
56
|
+
tutor/player/player_display.py,sha256=5Cxo7d8jbUmb54DKoYv0OYEe7Jc17WydO8_93R7sMUI,3358
|
|
57
|
+
tutor/prompts/curriculum.txt,sha256=0vUhJIndOWWe8iCwQGMVep7UX_NmebAGDvhZcVhIkAo,3298
|
|
58
|
+
tutor/prompts/dialogue.txt,sha256=NjKbxqSD8FRS3h74K07Rx0vnz5qFfhaj-AvP16LB7Ac,3090
|
|
59
|
+
tutor/prompts/narrate.txt,sha256=nJMt8szIk4Ejm2D1tVIDxcsbk6MM1JtCQuL2dJa-4PE,1754
|
|
60
|
+
tutor/prompts/qa.txt,sha256=wCBitdjVbTBK7JjgRa3bNBOXOE4LMPEDpIw_F04QflE,1064
|
|
61
|
+
tutor/prompts/summarize.txt,sha256=TFaUeXR_Rw_u5kF3GYgy9G4vyQebwBg2HmSjrdVFt60,943
|
|
62
|
+
tutor/prompts/visual.txt,sha256=_A1hnKiLll8gIlEaH9aTnp94w-xBV5vWJc-ZNhTedK4,3101
|
|
63
|
+
tutor/prompts/visual_v3.txt,sha256=VIkr9jhgfOpQ8noyLdHgC39lchBtsJXsGH9h28F37Ac,5346
|
|
64
|
+
tutor/qa/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
65
|
+
tutor/qa/qa.py,sha256=XcD-s1zp1om0mY2w1lBbWSqYQjG73YWEZYpLNlqEcIs,3097
|
|
66
|
+
tutor/sample_docs/headingless_large.md,sha256=mXry8uIZZGo4xjChoDX7Z3hkbIJCcZiosgNsmoABieQ,219302
|
|
67
|
+
tutor/sample_docs/headingless_test.md,sha256=EPLN4XOgb74YBVyMvRy074MlcWkTcDt7b6foA3Eze-g,24752
|
|
68
|
+
tutor/sample_docs/java-basics.md,sha256=flmhdF0hxE5Cxa8i2AXNSVuYuBlIf9pLVqN-jvpXZCM,3046
|
|
69
|
+
tutor/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
70
|
+
tutor/tests/test_assets.py,sha256=m3EoJG8ek9VHcV7PR-dxxgdiNT6GStLWwpPsRCc8E6Y,842
|
|
71
|
+
tutor/tests/test_models_visual.py,sha256=avIEvKt5tYR7ez7r4xdizi6Lm-7VnOhRIapWWaU89pg,5619
|
|
72
|
+
tutor/tests/audio/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
73
|
+
tutor/tests/audio/test_audio_builder.py,sha256=Ak7YoLE0DgB4n5AvthO34rMMG_cg55Yc64D1s0hUjLY,3734
|
|
74
|
+
tutor/tests/audio/test_sanitizer.py,sha256=pZ-NgYBdyEMI35jU6gUBNhOf5WbAFiYmsNBhKn80SWA,1025
|
|
75
|
+
tutor/tests/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
76
|
+
tutor/tests/cli/test_commands.py,sha256=KU0dfHEVvoV0o8PrM00rkcIMEsNK6fkNvm4cpZlMtC8,1890
|
|
77
|
+
tutor/tests/cli/test_video_commands.py,sha256=RyBNshE7GnXrS_Dj8Va89ma40uHvAJYj3K5bVlFlX1I,6550
|
|
78
|
+
tutor/tests/e2e/README.md,sha256=AtweOmDAZrhgz2mOQ2dmCF6_6IA7SiXM2hfeH6sCgIc,2498
|
|
79
|
+
tutor/tests/e2e/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
80
|
+
tutor/tests/e2e/conftest.py,sha256=ZOZ2xOM9ZxGQE0dSxZbmNpmrEczHqFRAbcpnY8ajZgw,3921
|
|
81
|
+
tutor/tests/e2e/test_audio_quality.py,sha256=oQwRDjWweszCNNPa-3d4RiElC9FkKpDN4OW_RejVgiE,1568
|
|
82
|
+
tutor/tests/e2e/test_av_sync.py,sha256=JRZp9go6ryS_AhjawIxD1bSM5qoKkX03WZ6YXZ-CMgk,2297
|
|
83
|
+
tutor/tests/e2e/test_pipeline_smoke.py,sha256=OG-UsXiuzUt2ypZ7rfRYaS4rbpC86hiAajB6SynmguA,1639
|
|
84
|
+
tutor/tests/e2e/test_slide_render.py,sha256=ON9560Aqucs9GXuZNKqdLwu2CnHk8OSFhacUSKF7n6k,2852
|
|
85
|
+
tutor/tests/e2e/test_video_streams.py,sha256=m6QUeQkl2gWMGM8CNit-VZVce7jeVyW5XQmEE9NbfXs,3747
|
|
86
|
+
tutor/tests/e2e/fixtures/README.md,sha256=hc0UKUcpthL_0Q5uPPDJ3MwEU7u9GVQtIHlgAzMXNwc,740
|
|
87
|
+
tutor/tests/e2e/fixtures/sample.md,sha256=YMBSiM0BJkTgCEWGgPx5AnvOp91no3vJ8gFaRkAAMlA,688
|
|
88
|
+
tutor/tests/generation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
89
|
+
tutor/tests/generation/conftest.py,sha256=1VXd8IF9CqFO8ICIydhBnGvJUwEgaLaEzf4Tio3VY_o,3355
|
|
90
|
+
tutor/tests/generation/test_assembler.py,sha256=lj8aY81zuv0aXI1Pcs40Ygjs1Dk7MWTVyrzivBRgbhU,2137
|
|
91
|
+
tutor/tests/generation/test_curriculum.py,sha256=Vkgk7sdieKCsEwcyRxlNty2Pu0tgcOwGKM8EUD-qXWM,3067
|
|
92
|
+
tutor/tests/generation/test_narrator.py,sha256=kV1va0r3e2qoEBsIn3BF_hc_w5uEziXGB-xL1ZVZjFA,5607
|
|
93
|
+
tutor/tests/generation/test_segment_edge_cases.py,sha256=4kjkAtRuF1d20BXPPCzoUQDlARy99enbgWRbhZ-QV2U,9011
|
|
94
|
+
tutor/tests/generation/test_segment_planner.py,sha256=Vv2yjNhCSE7zuvjt0Bv5nJLKVcut4qIkAcDYDHOIMsE,9957
|
|
95
|
+
tutor/tests/generation/test_visual_planner.py,sha256=usGF-naxBSD2-7TCBcC8oXhTQPJUQE3PLYOAdvmYXTs,10155
|
|
96
|
+
tutor/tests/ingestion/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
97
|
+
tutor/tests/ingestion/test_chunker.py,sha256=deS4xRkMialSk8Tf6JXcKeUHnVZVcCMeq7Lzxi-pku4,3318
|
|
98
|
+
tutor/tests/ingestion/test_doc_analyzer.py,sha256=5Z1r_8Aw7c7a-VysjssVfjK4tJiAYMJuD9dzO2ybMak,1466
|
|
99
|
+
tutor/tests/player/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
100
|
+
tutor/tests/player/test_player_states.py,sha256=Nx0J2JydBLmkOqjqidLWCDTHrrx9vikW1dRhl9JzMsU,2356
|
|
101
|
+
tutor/tests/visual/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
102
|
+
tutor/tests/visual/test_beat_timer.py,sha256=hYOVJnpklxN2dDdlVHJVw6zy-SkxvO7udfvOQ2w8V5o,10908
|
|
103
|
+
tutor/tests/visual/test_pipeline_integration.py,sha256=4U1Pklv55WcDBWYXlKMcDBjS3VYYMqnUtqGQXAeNMsg,6781
|
|
104
|
+
tutor/tests/visual/test_slide_renderer.py,sha256=B_ydEb8geo17QwtzY7WldG-W59UgHyWBs6W0iUt8dE0,10396
|
|
105
|
+
tutor/tests/visual/test_subtitle_writer.py,sha256=jf3lPhTHZMY2tFT_BA1C9UflGXKYYf8OhmcWdtE8mxs,6070
|
|
106
|
+
tutor/tests/visual/test_video_assembler.py,sha256=7L4TOiyMCEy32bzvaLylc6kjw4Cbpw0OBbk4Dp5tYxg,3632
|
|
107
|
+
tutor/tests/visual/test_visual_pipeline.py,sha256=jRU0ycw11-kQ4JRmu_kpcddS5iA-cD_UdSBskLPxg1Q,9093
|
|
108
|
+
tutor/visual/__init__.py,sha256=aZV5pzgtcRtvSAimQM7MODVZ62fTUGqepWPNviq2mcg,7471
|
|
109
|
+
tutor/visual/beat_timer.py,sha256=RxAx82i27VqUdu05VKAMhZ-VMKOB3gksA0jRxgLvgiA,8112
|
|
110
|
+
tutor/visual/slide_renderer.py,sha256=-l_ewdDvefQCXOblnxGYC_jdOsyTqPBwWm_A0TOR1fQ,8105
|
|
111
|
+
tutor/visual/subtitle_writer.py,sha256=nY-LZFHaTngiCwoMumBJoU4698h301oPzqsj87QQYt4,6264
|
|
112
|
+
tutor/visual/video_assembler.py,sha256=9j9B8oiHfd7asTYmhc1fXFCfij9NM7RxBRXn3whuFio,7815
|
|
113
|
+
tutor/visual/templates/_base.html.j2,sha256=Ck5WQHUfGTGsK6hFlF4xAEMvLNRxNCTOyAf1R6k1rHU,1384
|
|
114
|
+
tutor/visual/templates/analogy.html.j2,sha256=4LOcD0nGoJSPWMdAJPDssZCti-Phojgc-eEgAcKyyE0,773
|
|
115
|
+
tutor/visual/templates/callout.html.j2,sha256=ED7S5KBIFmzKcvI5khfWRCBu0SumajTnjKPXNVuqeJ4,325
|
|
116
|
+
tutor/visual/templates/code_example.html.j2,sha256=doEBkQx4YjdqvlTpK6vvN8vkYZV63FI4dRxS6HvKbxs,382
|
|
117
|
+
tutor/visual/templates/comparison.html.j2,sha256=xMTzdcpLyfH1jXG-Mnu3j5wsp4otxnf7sQ2qvWSLl8o,738
|
|
118
|
+
tutor/visual/templates/decision_guide.html.j2,sha256=-J-frUoyk2Vgr8QL3NMlWNy76UAwejh0vUNNWOIOiAE,984
|
|
119
|
+
tutor/visual/templates/definition.html.j2,sha256=88Cnrujg2jIVmKOINX7tICd9ZJsj4Lg6U1aKEhCJCIg,450
|
|
120
|
+
tutor/visual/templates/diagram.html.j2,sha256=-7j8A_eKMrZW8Su8qOjPXvCHT744kXku-8Sw27yHNMo,353
|
|
121
|
+
tutor/visual/templates/hook_question.html.j2,sha256=N5IfQSKLuY1ZFqIRGzd9aOa9xGPE9SPYKVaNSbFa84M,487
|
|
122
|
+
tutor/visual/templates/key_insight.html.j2,sha256=uRWi7IEs77c4pmZXa7dDl5Pzz7KrXaMlNxCOIRBlSus,345
|
|
123
|
+
tutor/visual/templates/memory_hook.html.j2,sha256=5qSUBbr1vLa8n5jRhNOdZDFv05SKRVkb86ZXyCP_lC4,263
|
|
124
|
+
tutor/visual/templates/outro.html.j2,sha256=YqvnRe4u4RDQbpuYKCs8OS5vR9Fjr9HRgTMqqvAKk90,559
|
|
125
|
+
tutor/visual/templates/question_prompt.html.j2,sha256=9Msg3BI7gPFNIPM_qi7Y8BT1jusTHKL51LfMXeK1UWo,558
|
|
126
|
+
tutor/visual/templates/step_sequence.html.j2,sha256=thigDwqvbu3lP1zNCmUCzqbORSi6towWlvS5YFUOdrM,429
|
|
127
|
+
tutor/visual/templates/title_card.html.j2,sha256=aRv3Gt3GRZaI6mk402dwe70dOs8wgMwVl9yidK6c_uA,451
|
|
128
|
+
learnx_cli-0.3.0.dist-info/METADATA,sha256=mwJQlZClXi1FsRg0rhI5HcTo24psoM6Q4g1pemgxsDg,7123
|
|
129
|
+
learnx_cli-0.3.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
130
|
+
learnx_cli-0.3.0.dist-info/entry_points.txt,sha256=aOv3umCathBACadIds6Fc0mM48Ir_lLeAWYYqP2LJEw,53
|
|
131
|
+
learnx_cli-0.3.0.dist-info/RECORD,,
|
tutor/.env copy.example
ADDED
tutor/__init__.py
ADDED
|
File without changes
|
tutor/__main__.py
ADDED
tutor/assets/__init__.py
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/* highlight.js 11.x minimal stub — sufficient for test rendering */
|
|
2
|
+
var hljs = (function() {
|
|
3
|
+
'use strict';
|
|
4
|
+
function highlight(code, opts) {
|
|
5
|
+
var escaped = code.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
|
6
|
+
return { value: escaped };
|
|
7
|
+
}
|
|
8
|
+
function highlightAll() {
|
|
9
|
+
document.querySelectorAll('pre code').forEach(function(block) {
|
|
10
|
+
var result = highlight(block.textContent, {});
|
|
11
|
+
block.innerHTML = result.value;
|
|
12
|
+
block.classList.add('hljs');
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
function registerLanguage(name, fn) {}
|
|
16
|
+
return { highlight: highlight, highlightAll: highlightAll, registerLanguage: registerLanguage };
|
|
17
|
+
})();
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/* Mermaid v10 minimal stub — renders SVG placeholder for testing */
|
|
2
|
+
var mermaid = (function() {
|
|
3
|
+
'use strict';
|
|
4
|
+
var config = { startOnLoad: true, theme: 'dark' };
|
|
5
|
+
|
|
6
|
+
function initialize(cfg) {
|
|
7
|
+
Object.assign(config, cfg);
|
|
8
|
+
if (config.startOnLoad) {
|
|
9
|
+
if (document.readyState === 'loading') {
|
|
10
|
+
document.addEventListener('DOMContentLoaded', run);
|
|
11
|
+
} else {
|
|
12
|
+
setTimeout(run, 0);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function run() {
|
|
18
|
+
document.querySelectorAll('.mermaid').forEach(function(el) {
|
|
19
|
+
if (el.querySelector('svg')) return;
|
|
20
|
+
var text = el.textContent.trim();
|
|
21
|
+
var svg = '<svg xmlns="http://www.w3.org/2000/svg" width="600" height="300">' +
|
|
22
|
+
'<rect width="600" height="300" fill="#161b22" rx="8"/>' +
|
|
23
|
+
'<text x="300" y="160" text-anchor="middle" fill="#e6edf3" font-size="20" font-family="monospace">' +
|
|
24
|
+
text.replace(/</g,'<').replace(/>/g,'>').substring(0, 80) +
|
|
25
|
+
'</text></svg>';
|
|
26
|
+
el.innerHTML = svg;
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return { initialize: initialize, run: run };
|
|
31
|
+
})();
|