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.
Files changed (131) hide show
  1. learnx_cli-0.3.0.dist-info/METADATA +240 -0
  2. learnx_cli-0.3.0.dist-info/RECORD +131 -0
  3. learnx_cli-0.3.0.dist-info/WHEEL +4 -0
  4. learnx_cli-0.3.0.dist-info/entry_points.txt +2 -0
  5. tutor/.env copy.example +4 -0
  6. tutor/__init__.py +0 -0
  7. tutor/__main__.py +4 -0
  8. tutor/assets/__init__.py +5 -0
  9. tutor/assets/html/fonts/Inter-Bold.woff2 +0 -0
  10. tutor/assets/html/fonts/Inter-Regular.woff2 +0 -0
  11. tutor/assets/html/fonts/Inter-SemiBold.woff2 +0 -0
  12. tutor/assets/html/fonts/JetBrainsMono-Regular.woff2 +0 -0
  13. tutor/assets/html/highlight-java.min.js +2 -0
  14. tutor/assets/html/highlight-javascript.min.js +2 -0
  15. tutor/assets/html/highlight-python.min.js +2 -0
  16. tutor/assets/html/highlight.min.js +17 -0
  17. tutor/assets/html/mermaid.min.js +31 -0
  18. tutor/assets/html/slide_base.css +464 -0
  19. tutor/assets/html/theme-learnx-dark.css +12 -0
  20. tutor/audio/__init__.py +0 -0
  21. tutor/audio/audio_builder.py +143 -0
  22. tutor/audio/sanitizer.py +9 -0
  23. tutor/audio/tts_renderer.py +54 -0
  24. tutor/cli/__init__.py +0 -0
  25. tutor/cli/commands.py +391 -0
  26. tutor/cli/logo.py +21 -0
  27. tutor/cli/playback_commands.py +239 -0
  28. tutor/cli/shell.py +91 -0
  29. tutor/cli/shell_context.py +18 -0
  30. tutor/cli/theme.py +39 -0
  31. tutor/cli/video_commands.py +123 -0
  32. tutor/config.py +122 -0
  33. tutor/conftest.py +5 -0
  34. tutor/constants.py +82 -0
  35. tutor/exceptions.py +26 -0
  36. tutor/generation/__init__.py +0 -0
  37. tutor/generation/assembler.py +81 -0
  38. tutor/generation/curriculum.py +97 -0
  39. tutor/generation/dialogue.py +172 -0
  40. tutor/generation/narrator.py +122 -0
  41. tutor/generation/segment_parser.py +223 -0
  42. tutor/generation/segment_planner.py +200 -0
  43. tutor/generation/visual_planner.py +205 -0
  44. tutor/infra/__init__.py +0 -0
  45. tutor/infra/llm.py +152 -0
  46. tutor/ingestion/__init__.py +0 -0
  47. tutor/ingestion/chunker.py +171 -0
  48. tutor/ingestion/doc_analyzer.py +41 -0
  49. tutor/ingestion/parse_content.py +19 -0
  50. tutor/ingestion/summarizer.py +51 -0
  51. tutor/inspector.py +117 -0
  52. tutor/llm_config.toml +58 -0
  53. tutor/models.py +147 -0
  54. tutor/player/__init__.py +0 -0
  55. tutor/player/input_handler.py +45 -0
  56. tutor/player/player.py +308 -0
  57. tutor/player/player_display.py +117 -0
  58. tutor/prompts/curriculum.txt +67 -0
  59. tutor/prompts/dialogue.txt +62 -0
  60. tutor/prompts/narrate.txt +34 -0
  61. tutor/prompts/qa.txt +17 -0
  62. tutor/prompts/summarize.txt +9 -0
  63. tutor/prompts/visual.txt +60 -0
  64. tutor/prompts/visual_v3.txt +91 -0
  65. tutor/qa/__init__.py +0 -0
  66. tutor/qa/qa.py +105 -0
  67. tutor/requirements-dev.txt +2 -0
  68. tutor/requirements.txt +12 -0
  69. tutor/sample_docs/headingless_large.md +1 -0
  70. tutor/sample_docs/headingless_test.md +1 -0
  71. tutor/sample_docs/java-basics.md +78 -0
  72. tutor/tests/__init__.py +0 -0
  73. tutor/tests/audio/__init__.py +0 -0
  74. tutor/tests/audio/test_audio_builder.py +106 -0
  75. tutor/tests/audio/test_sanitizer.py +41 -0
  76. tutor/tests/cli/__init__.py +0 -0
  77. tutor/tests/cli/test_commands.py +67 -0
  78. tutor/tests/cli/test_video_commands.py +190 -0
  79. tutor/tests/e2e/README.md +61 -0
  80. tutor/tests/e2e/__init__.py +0 -0
  81. tutor/tests/e2e/conftest.py +117 -0
  82. tutor/tests/e2e/fixtures/README.md +17 -0
  83. tutor/tests/e2e/fixtures/sample.md +13 -0
  84. tutor/tests/e2e/test_audio_quality.py +40 -0
  85. tutor/tests/e2e/test_av_sync.py +56 -0
  86. tutor/tests/e2e/test_pipeline_smoke.py +37 -0
  87. tutor/tests/e2e/test_slide_render.py +72 -0
  88. tutor/tests/e2e/test_video_streams.py +104 -0
  89. tutor/tests/generation/__init__.py +0 -0
  90. tutor/tests/generation/conftest.py +134 -0
  91. tutor/tests/generation/test_assembler.py +64 -0
  92. tutor/tests/generation/test_curriculum.py +107 -0
  93. tutor/tests/generation/test_narrator.py +165 -0
  94. tutor/tests/generation/test_segment_edge_cases.py +280 -0
  95. tutor/tests/generation/test_segment_planner.py +324 -0
  96. tutor/tests/generation/test_visual_planner.py +319 -0
  97. tutor/tests/ingestion/__init__.py +0 -0
  98. tutor/tests/ingestion/test_chunker.py +94 -0
  99. tutor/tests/ingestion/test_doc_analyzer.py +51 -0
  100. tutor/tests/player/__init__.py +0 -0
  101. tutor/tests/player/test_player_states.py +88 -0
  102. tutor/tests/test_assets.py +39 -0
  103. tutor/tests/test_models_visual.py +180 -0
  104. tutor/tests/visual/__init__.py +0 -0
  105. tutor/tests/visual/test_beat_timer.py +321 -0
  106. tutor/tests/visual/test_pipeline_integration.py +178 -0
  107. tutor/tests/visual/test_slide_renderer.py +298 -0
  108. tutor/tests/visual/test_subtitle_writer.py +165 -0
  109. tutor/tests/visual/test_video_assembler.py +108 -0
  110. tutor/tests/visual/test_visual_pipeline.py +270 -0
  111. tutor/tutor.py +365 -0
  112. tutor/visual/__init__.py +213 -0
  113. tutor/visual/beat_timer.py +222 -0
  114. tutor/visual/slide_renderer.py +236 -0
  115. tutor/visual/subtitle_writer.py +187 -0
  116. tutor/visual/templates/_base.html.j2 +40 -0
  117. tutor/visual/templates/analogy.html.j2 +21 -0
  118. tutor/visual/templates/callout.html.j2 +10 -0
  119. tutor/visual/templates/code_example.html.j2 +12 -0
  120. tutor/visual/templates/comparison.html.j2 +28 -0
  121. tutor/visual/templates/decision_guide.html.j2 +37 -0
  122. tutor/visual/templates/definition.html.j2 +13 -0
  123. tutor/visual/templates/diagram.html.j2 +11 -0
  124. tutor/visual/templates/hook_question.html.j2 +17 -0
  125. tutor/visual/templates/key_insight.html.j2 +9 -0
  126. tutor/visual/templates/memory_hook.html.j2 +7 -0
  127. tutor/visual/templates/outro.html.j2 +16 -0
  128. tutor/visual/templates/question_prompt.html.j2 +13 -0
  129. tutor/visual/templates/step_sequence.html.j2 +14 -0
  130. tutor/visual/templates/title_card.html.j2 +12 -0
  131. 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
+ ![CI](https://github.com/Yusuprozimemet/LearnX-CLI/actions/workflows/ci.yml/badge.svg)
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,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ learnx = tutor.cli.shell:run_shell
@@ -0,0 +1,4 @@
1
+ GROQ_API_KEY=gsk_...
2
+ OPENROUTER_API_KEY=sk-or-...
3
+ NOTIFY_TELEGRAM_TOKEN=<your-bot-token>
4
+ NOTIFY_TELEGRAM_CHAT_ID=<your-chat-id>
tutor/__init__.py ADDED
File without changes
tutor/__main__.py ADDED
@@ -0,0 +1,4 @@
1
+ from tutor.cli.shell import run_shell
2
+
3
+ if __name__ == "__main__":
4
+ run_shell()
@@ -0,0 +1,5 @@
1
+ from pathlib import Path
2
+
3
+ ASSETS_DIR = Path(__file__).parent
4
+ FONTS_DIR = ASSETS_DIR / "fonts"
5
+ LOGO_PATH = ASSETS_DIR / "logo_small.png"
Binary file
@@ -0,0 +1,2 @@
1
+ /* highlight.js Java language pack stub */
2
+ if (typeof hljs !== 'undefined') { hljs.registerLanguage('java', function() { return {}; }); }
@@ -0,0 +1,2 @@
1
+ /* highlight.js JavaScript language pack stub */
2
+ if (typeof hljs !== 'undefined') { hljs.registerLanguage('javascript', function() { return {}; }); }
@@ -0,0 +1,2 @@
1
+ /* highlight.js Python language pack stub */
2
+ if (typeof hljs !== 'undefined') { hljs.registerLanguage('python', function() { return {}; }); }
@@ -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,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
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,'&lt;').replace(/>/g,'&gt;').substring(0, 80) +
25
+ '</text></svg>';
26
+ el.innerHTML = svg;
27
+ });
28
+ }
29
+
30
+ return { initialize: initialize, run: run };
31
+ })();