anki_generator 1.1.0 → 1.4.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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +59 -0
  3. data/.rubocop.yml +79 -0
  4. data/.ruby-version +1 -0
  5. data/.tool-versions +1 -0
  6. data/CHANGELOG.md +173 -0
  7. data/Gemfile +21 -0
  8. data/Makefile +20 -0
  9. data/README.md +160 -32
  10. data/Rakefile +174 -0
  11. data/anki_generator.gemspec +42 -0
  12. data/bin/anki_generator +3 -2
  13. data/docs/CI_SETUP.md +120 -0
  14. data/docs/architecture/current-v1.3.0.architecture.json +315 -0
  15. data/docs/architecture/current-v1.3.0.html +14990 -0
  16. data/docs/architecture/current-v1.3.0.visual-check.json +548 -0
  17. data/docs/architecture/phase3-proposed.architecture.json +310 -0
  18. data/docs/architecture/phase3-proposed.html +15001 -0
  19. data/docs/architecture/phase3-proposed.visual-check.json +548 -0
  20. data/docs/phase3-draft.md +86 -0
  21. data/examples/example_class.rb +13 -0
  22. data/examples/manual_cards.yaml +5 -0
  23. data/examples/study_prompt.txt +3 -0
  24. data/input/input.yaml.example +3 -0
  25. data/lib/anki_generator/anki_connect_client.rb +85 -0
  26. data/lib/anki_generator/apkg_schema.rb +257 -0
  27. data/lib/anki_generator/apkg_writer.rb +149 -0
  28. data/lib/anki_generator/card.rb +83 -0
  29. data/lib/anki_generator/cli.rb +183 -0
  30. data/lib/anki_generator/client_factory.rb +20 -0
  31. data/lib/anki_generator/commands/create_ai_template.rb +39 -0
  32. data/lib/anki_generator/commands/generate_deck.rb +43 -0
  33. data/lib/anki_generator/commands/generate_yaml.rb +63 -0
  34. data/lib/anki_generator/commands/import.rb +75 -0
  35. data/lib/anki_generator/commands/prompt_based.rb +74 -0
  36. data/lib/anki_generator/commands/prompt_to_deck.rb +84 -0
  37. data/lib/anki_generator/commands/push.rb +32 -0
  38. data/lib/anki_generator/commands/serve.rb +99 -0
  39. data/lib/anki_generator/commands/test_api.rb +33 -0
  40. data/lib/anki_generator/deck_builder.rb +184 -0
  41. data/lib/anki_generator/errors.rb +22 -0
  42. data/lib/anki_generator/file_processor.rb +154 -0
  43. data/lib/anki_generator/importers/csv.rb +52 -0
  44. data/lib/anki_generator/importers/markdown.rb +72 -0
  45. data/lib/anki_generator/prompt_builder.rb +77 -0
  46. data/lib/anki_generator/server.rb +98 -0
  47. data/lib/anki_generator/ui.rb +28 -0
  48. data/lib/anki_generator/version.rb +5 -0
  49. data/lib/anki_generator.rb +18 -114
  50. data/prompt.txt +5 -0
  51. metadata +100 -43
  52. data/lib/anki_cli.rb +0 -259
  53. data/lib/file_processor.rb +0 -156
  54. data/lib/openrouter_client.rb +0 -158
@@ -0,0 +1,315 @@
1
+ {
2
+ "schema_version": 1,
3
+ "diagram_type": "architecture",
4
+ "meta": {
5
+ "title": "Anki Generator v1.3.0 — Current Architecture",
6
+ "output": "current-architecture.html",
7
+ "quality_profile": "showcase",
8
+ "locale": "en",
9
+ "repository": {
10
+ "url": "https://github.com/pinkfloydsito/anki-generator",
11
+ "provider": "github",
12
+ "link_mode": "web",
13
+ "revision": "02ae43a749820e5658d9790fa12a4a77f8a3f501"
14
+ },
15
+ "views": [
16
+ {
17
+ "id": "main-path",
18
+ "label": "Deck build path",
19
+ "focus": [
20
+ "cli",
21
+ "webui",
22
+ "core",
23
+ "apkgwriter",
24
+ "apkgfile"
25
+ ],
26
+ "note": "YAML, Markdown, or AI-generated cards become a native .apkg without any server."
27
+ },
28
+ {
29
+ "id": "ai-and-push",
30
+ "label": "AI generation and push",
31
+ "focus": [
32
+ "cli",
33
+ "core",
34
+ "providers",
35
+ "ankiconnect",
36
+ "anki"
37
+ ],
38
+ "note": "Providers are pluggable behind ClientFactory; push talks to a local Anki over HTTP."
39
+ }
40
+ ]
41
+ },
42
+ "components": [
43
+ {
44
+ "id": "cli",
45
+ "type": "backend",
46
+ "label": "anki_generator CLI",
47
+ "sublabel": "Thor commands",
48
+ "pos": [
49
+ 40,
50
+ 140
51
+ ],
52
+ "size": [
53
+ 150,
54
+ 64
55
+ ],
56
+ "sources": [
57
+ {
58
+ "path": "lib/anki_generator/cli.rb",
59
+ "label": "Thor CLI"
60
+ }
61
+ ]
62
+ },
63
+ {
64
+ "id": "webui",
65
+ "type": "frontend",
66
+ "label": "serve Web UI",
67
+ "sublabel": "WEBrick 127.0.0.1:8787",
68
+ "pos": [
69
+ 40,
70
+ 320
71
+ ],
72
+ "size": [
73
+ 150,
74
+ 64
75
+ ],
76
+ "sources": [
77
+ {
78
+ "path": "lib/anki_generator/server.rb",
79
+ "label": "WEBrick servlets"
80
+ }
81
+ ]
82
+ },
83
+ {
84
+ "id": "importers",
85
+ "type": "backend",
86
+ "label": "Importers",
87
+ "sublabel": "Markdown · CSV",
88
+ "pos": [
89
+ 40,
90
+ 424
91
+ ],
92
+ "size": [
93
+ 150,
94
+ 64
95
+ ],
96
+ "sources": [
97
+ {
98
+ "path": "lib/anki_generator/importers/markdown.rb",
99
+ "label": "Markdown importer"
100
+ }
101
+ ]
102
+ },
103
+ {
104
+ "id": "core",
105
+ "type": "backend",
106
+ "label": "anki_generator gem",
107
+ "sublabel": "Commands · DeckBuilder · Card",
108
+ "pos": [
109
+ 360,
110
+ 270
111
+ ],
112
+ "size": [
113
+ 170,
114
+ 70
115
+ ],
116
+ "sources": [
117
+ {
118
+ "path": "lib/anki_generator/deck_builder.rb",
119
+ "label": "DeckBuilder"
120
+ }
121
+ ]
122
+ },
123
+ {
124
+ "id": "providers",
125
+ "type": "cloud",
126
+ "label": "LLM Providers",
127
+ "sublabel": "OpenRouter · Ollama",
128
+ "pos": [
129
+ 360,
130
+ 96
131
+ ],
132
+ "size": [
133
+ 170,
134
+ 64
135
+ ],
136
+ "sources": [
137
+ {
138
+ "path": "lib/anki_generator/client_factory.rb",
139
+ "label": "ClientFactory"
140
+ }
141
+ ]
142
+ },
143
+ {
144
+ "id": "apkgwriter",
145
+ "type": "backend",
146
+ "label": "ApkgWriter + Schema",
147
+ "sublabel": "zip + SQLite",
148
+ "pos": [
149
+ 620,
150
+ 270
151
+ ],
152
+ "size": [
153
+ 170,
154
+ 70
155
+ ],
156
+ "sources": [
157
+ {
158
+ "path": "lib/anki_generator/apkg_writer.rb",
159
+ "label": "ApkgWriter"
160
+ }
161
+ ]
162
+ },
163
+ {
164
+ "id": "apkgfile",
165
+ "type": "database",
166
+ "label": ".apkg file",
167
+ "sublabel": "import into Anki",
168
+ "pos": [
169
+ 870,
170
+ 270
171
+ ],
172
+ "size": [
173
+ 140,
174
+ 60
175
+ ]
176
+ },
177
+ {
178
+ "id": "ankiconnect",
179
+ "type": "external",
180
+ "label": "AnkiConnect",
181
+ "sublabel": "localhost:8765",
182
+ "pos": [
183
+ 620,
184
+ 424
185
+ ],
186
+ "size": [
187
+ 170,
188
+ 64
189
+ ]
190
+ },
191
+ {
192
+ "id": "anki",
193
+ "type": "external",
194
+ "label": "Anki Desktop",
195
+ "sublabel": "review + sync",
196
+ "pos": [
197
+ 870,
198
+ 424
199
+ ],
200
+ "size": [
201
+ 140,
202
+ 60
203
+ ]
204
+ }
205
+ ],
206
+ "boundaries": [
207
+ {
208
+ "kind": "region",
209
+ "label": "Local machine — no server required",
210
+ "wraps": [
211
+ "cli",
212
+ "webui",
213
+ "importers",
214
+ "core",
215
+ "apkgwriter",
216
+ "apkgfile",
217
+ "ankiconnect",
218
+ "anki"
219
+ ]
220
+ }
221
+ ],
222
+ "connections": [
223
+ {
224
+ "id": "cli-to-core",
225
+ "from": "cli",
226
+ "to": "core",
227
+ "label": "Thor commands",
228
+ "variant": "emphasis"
229
+ },
230
+ {
231
+ "id": "webui-to-core",
232
+ "from": "webui",
233
+ "to": "core",
234
+ "label": "parse / generate / export"
235
+ },
236
+ {
237
+ "id": "importers-to-core",
238
+ "from": "importers",
239
+ "to": "core",
240
+ "label": "card hashes",
241
+ "fromSide": "right",
242
+ "toSide": "bottom",
243
+ "via": [
244
+ [
245
+ 445,
246
+ 456
247
+ ]
248
+ ]
249
+ },
250
+ {
251
+ "id": "core-to-providers",
252
+ "from": "core",
253
+ "to": "providers",
254
+ "label": "chat completions",
255
+ "fromSide": "top",
256
+ "toSide": "bottom",
257
+ "variant": "dashed"
258
+ },
259
+ {
260
+ "id": "core-to-writer",
261
+ "from": "core",
262
+ "to": "apkgwriter",
263
+ "label": "cards",
264
+ "variant": "emphasis"
265
+ },
266
+ {
267
+ "id": "writer-to-file",
268
+ "from": "apkgwriter",
269
+ "to": "apkgfile",
270
+ "label": "write archive"
271
+ },
272
+ {
273
+ "id": "core-to-ankiconnect",
274
+ "from": "core",
275
+ "to": "ankiconnect",
276
+ "label": "push_deck",
277
+ "variant": "dashed"
278
+ },
279
+ {
280
+ "id": "ankiconnect-to-anki",
281
+ "from": "ankiconnect",
282
+ "to": "anki",
283
+ "label": "addNotes"
284
+ }
285
+ ],
286
+ "cards": [
287
+ {
288
+ "dot": "cyan",
289
+ "title": "Input surface",
290
+ "items": [
291
+ "CLI: generate, import, push, serve, prompt_to_deck",
292
+ "Web editor: paste Markdown, AI-generate, export",
293
+ "Importers turn Markdown / CSV notes into cards"
294
+ ]
295
+ },
296
+ {
297
+ "dot": "emerald",
298
+ "title": "Core library",
299
+ "items": [
300
+ "Namespaced AnkiGenerator::* service objects with DI",
301
+ "Native .apkg writer (zip + SQLite), cloze model, tags",
302
+ "Pluggable providers: OpenRouter (retries) or local Ollama"
303
+ ]
304
+ },
305
+ {
306
+ "dot": "rose",
307
+ "title": "Quality bar",
308
+ "items": [
309
+ "132 tests, 417 assertions, 96.85% line coverage",
310
+ "RuboCop zero offenses enforced in CI",
311
+ "Documented cop exclusions only for data blobs and WEBrick contracts"
312
+ ]
313
+ }
314
+ ]
315
+ }