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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c8124d9ca11c2259790dfabfb10f1fab725cfa4889300d6bf91353cce45b9604
4
- data.tar.gz: 6be84b8c3d8d430c91ad7c02f0fb063cc3e5ea27c35ee946d2c3ea091aedb994
3
+ metadata.gz: b5a70e0ea5175cfd6c2b76421bf969d170d80cabc73f1a621d781b297d006365
4
+ data.tar.gz: 35f411b4e13dcf03b6ffe5a674394ed1521618c260e8f12019b6609d85e714c4
5
5
  SHA512:
6
- metadata.gz: 1bae0bd4aad23ab158031ab876385a10660559b5a9acca2be6a4ba932a2851e7c468e5b18d5db33f57724198fe8fda3e6478dfec05718f1a15703fd3a188bf1b
7
- data.tar.gz: 25c74048b6dcd2428aab8f879cfebd41b81d7264bd3a5f8e8805530563b7099b9ee72be220e97fe1af070aa44460a084d20fa8010ea658e686a031415c1c2f90
6
+ metadata.gz: e960819a79d0870a346234ccb110cb3476a794b6d568f4093ea73a4557290556244b0f4b1510d47865c6119192f8e7c160f9f95a49c63f30c1dcb44e88bd43a1
7
+ data.tar.gz: 11efe7e80b4fd146ca8ceef017fb6c7f558696dee1f76bad2d18de41f3f2908bf57a2f5497bedf20aa4158d931d7b39c60380139a6e2949a7384c1589ddf965d
data/.gitignore ADDED
@@ -0,0 +1,59 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+
13
+ # Used by dotenv library to load environment variables.
14
+ .env
15
+
16
+ # Ignore Byebug command history file.
17
+ .byebug_history
18
+
19
+ ## Specific to RubyMotion:
20
+ .dat*
21
+ .repl_history
22
+ build/
23
+ *.bridgesupport
24
+ build-iPhoneOS/
25
+ build-iPhoneSimulator/
26
+
27
+ ## Specific to RubyMotion (use of CocoaPods):
28
+ #
29
+ # We recommend against adding the Pods directory to your .gitignore. However
30
+ # you should judge for yourself, the pros and cons are mentioned at:
31
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
32
+ #
33
+ # vendor/Pods/
34
+
35
+ ## Documentation cache and generated files:
36
+ /.yardoc/
37
+ /_yardoc/
38
+ /doc/
39
+ /rdoc/
40
+
41
+ ## Environment normalization:
42
+ /.bundle/
43
+ /vendor/bundle
44
+ /lib/bundler/man/
45
+
46
+ # for a library or gem, you might want to ignore these files since the code is
47
+ # intended to run in multiple environments; otherwise, check them in:
48
+ # Gemfile.lock
49
+ # .ruby-version
50
+ # .ruby-gemset
51
+
52
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
53
+ .rvmrc
54
+
55
+ # Used by RuboCop. Remote config files pulled in from inherit_from directive.
56
+ # .rubocop-https?--*
57
+ #
58
+ input/*.yaml
59
+ *.apkg
data/.rubocop.yml ADDED
@@ -0,0 +1,79 @@
1
+ AllCops:
2
+ TargetRubyVersion: 3.1
3
+ NewCops: enable
4
+ SuggestExtensions: false
5
+ Exclude:
6
+ - 'examples/**/*'
7
+ - 'scripts/**/*'
8
+
9
+ Layout/LineLength:
10
+ Max: 120
11
+ Exclude:
12
+ - '*.gemspec'
13
+
14
+ Metrics/MethodLength:
15
+ Max: 20
16
+ Exclude:
17
+ - 'tests/**/*'
18
+ # Static Anki data blobs; length is driven by the format, not design.
19
+ - 'lib/anki_generator/apkg_schema.rb'
20
+
21
+ Metrics/ClassLength:
22
+ Max: 150
23
+ Exclude:
24
+ - 'tests/**/*'
25
+ # The server class embeds the single-page UI as one static HTML heredoc;
26
+ # its size is data, not design.
27
+ - 'lib/anki_generator/server.rb'
28
+
29
+ Metrics/BlockLength:
30
+ Max: 30
31
+ Exclude:
32
+ - 'tests/**/*'
33
+ - '*.gemspec'
34
+ - 'Rakefile'
35
+
36
+ Metrics/AbcSize:
37
+ Max: 30
38
+ Exclude:
39
+ - 'tests/**/*'
40
+
41
+ Metrics/CyclomaticComplexity:
42
+ Max: 10
43
+
44
+ Metrics/PerceivedComplexity:
45
+ Max: 10
46
+
47
+ # The schema module is static Anki data (SQL + default JSON blobs); its size is
48
+ # driven by the format, not by design choices.
49
+ Metrics/ModuleLength:
50
+ Exclude:
51
+ - 'lib/anki_generator/apkg_schema.rb'
52
+
53
+ # Command initializers take their full option surface as keyword arguments;
54
+ # counting them against the positional-parameter limit is meaningless.
55
+ Metrics/ParameterLists:
56
+ CountKeywordArgs: false
57
+
58
+ # Short parameter names that are unambiguous in this codebase.
59
+ Naming/MethodParameterName:
60
+ AllowedNames:
61
+ - ui
62
+ - io
63
+ - id
64
+ - db
65
+ - e
66
+
67
+ # WEBrick dispatches to servlets via the camelCase do_GET/do_POST contract.
68
+ Naming/MethodName:
69
+ Exclude:
70
+ - 'lib/anki_generator/server.rb'
71
+
72
+ # Test class names are self-describing.
73
+ Style/Documentation:
74
+ Exclude:
75
+ - 'tests/**/*'
76
+
77
+ # CLI output strings legitimately use double quotes for interpolation.
78
+ Style/StringLiterals:
79
+ EnforcedStyle: single_quotes
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.3.10
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 3.3.10
data/CHANGELOG.md ADDED
@@ -0,0 +1,173 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.4.0] - 2026-10-01
9
+
10
+ ### Breaking
11
+ - **Provider-agnostic LLM layer** — the hand-rolled `OpenRouterClient` and `OllamaClient` (Faraday) are replaced by a single `AnkiGenerator::LlmClient` backed by [ruby_llm](https://github.com/crmne/ruby_llm). Gemini is now the default provider (`gemini-3.8-flash`); OpenAI, Anthropic, OpenRouter, and local Ollama (plus any other ruby_llm provider) work through the same client
12
+ - API keys move to provider env vars — `GOOGLE_API_KEY` / `GEMINI_API_KEY` (default), `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `OPENROUTER_API_KEY`, `OLLAMA_URL` for local Ollama; `OPENROUTER_API_KEY` alone no longer drives the tool
13
+ - `--provider` is now free-form (any ruby_llm provider name) and defaults to auto-resolution from the model name; `--provider openrouter|ollama` enum is gone
14
+ - `--api-key` now requires an explicit `--provider`
15
+ - `--structured` flag removed — structured output is always on (see below)
16
+ - Dependencies: `faraday` / `faraday-retry` dropped; `ruby_llm ~> 2.0` and `sinatra ~> 4.0` added
17
+
18
+ ### Added
19
+ - **Structured outputs** — card generation now uses ruby_llm/Schematist JSON Schema (`AnkiGenerator::SingleCardSchema` / `MultipleCardsSchema`), so providers validate the card shape at the API level; non-conforming responses raise `ResponseParseError`
20
+ - `GOOGLE_API_KEY` acts as a fallback for the Gemini key when `GEMINI_API_KEY` is unset (bridged into `RubyLLM.configure` by `LlmClient`)
21
+ - `AnkiGenerator::TEMPERATURE` constant (0.7) exposed on the client
22
+ - `anki_generator serve [--provider PROVIDER]` — the web editor can now default to a chosen LLM provider
23
+
24
+ ### Changed
25
+ - **Web server rewritten on Sinatra 4** (was WEBrick servlets + inline HTML heredoc): routes live in `AnkiGenerator::Server`, the UI page moved to `lib/anki_generator/server/public/index.html`, YAML parsing extracted to `AnkiGenerator::Importers::Yaml`, and `.apkg` building to `AnkiGenerator::ApkgExporter` — each concern is now independently testable
26
+ - Default model: `gemini-3.8-flash`
27
+ - `--model` / `ANKI_GENERATOR_MODEL` override the default as before
28
+ - README rewritten for the new provider model
29
+
30
+ ### Technical
31
+ - Test suite: 125 tests, 0 failures, 94% line coverage — server tests moved to rack-test (no real sockets); LLM tests webmock-stub the Gemini `generateContent` endpoint including schema request-body assertions
32
+ - RuboCop zero offenses
33
+ - Note: ruby_llm 2.0 does not auto-detect provider ENV vars — `LlmClient` bridges them
34
+
35
+ ## [1.3.0] - 2026-09-30
36
+
37
+ ### Added
38
+ - **Markdown & CSV importers** (`AnkiGenerator::Importers::Markdown` / `Importers::Csv`) — turn study notes into decks:
39
+ - Markdown: `Q:`/`A:` pairs, `- **front** — back` bullets, headings become tags
40
+ - CSV: `front,back[,tags]` (tags pipe-separated)
41
+ - New command: `anki_generator import DECK_NAME INPUT_FILE OUTPUT_FILE [--reverse]`
42
+ - **Cloze deletion cards** — YAML cards with a `cloze:` key (`cloze: "{{c1::Paris}} is the capital of {{c2::France}}"`) export as a proper Anki cloze note; one card per `{{cN::...}}` ordinal, with a dedicated `AnkiGenerator Cloze` model in the package
43
+ - **Per-card tags** — `tags: [ruby, basics]` in YAML lands in the note's tag column; `--reverse` and importers compose with tags
44
+ - **Reverse cards** — `--reverse` on `generate`/`import` appends a front↔back copy of every basic card (cloze cards are skipped)
45
+ - **Parallel AI generation** — `--jobs N` on `generate` fans one API call per topic out across N threads (Mutex + Queue worker pool)
46
+ - **Ollama provider** — `--provider ollama` talks to a local Ollama server (`OLLAMA_URL`, default `http://localhost:11434`, no API key); provider selection unified behind `AnkiGenerator::ClientFactory`
47
+ - **Automatic retries** — Faraday retry middleware on OpenRouter (3 attempts, exponential backoff, honors `Retry-After` on 429/5xx)
48
+ - **Structured output** — `--structured` requests JSON mode (`response_format: json_object`) from providers that support it
49
+ - **AnkiConnect push** — `anki_generator push DECK_NAME YAML_FILE` sends cards straight into a running Anki (`AnkiConnect` addon, default `http://localhost:8765`), reporting added/duplicate counts
50
+ - **Web UI** — `anki_generator serve [--port]` starts a localhost editor (WEBrick, no build step): paste Markdown/YAML, generate via AI, edit the card table, download `.apkg`
51
+
52
+ ### Changed
53
+ - `--model` now defaults per provider (`OllamaClient::DEFAULT_MODEL` for Ollama, `gpt-4o-mini` for OpenRouter) instead of a single global default
54
+ - OpenRouter client accepts `structured:` and retry configuration; Ollama client mirrors the same interface
55
+
56
+ ### Technical
57
+ - Test suite: 131 tests, 415 assertions, 96.85% line coverage (floor remains 75%)
58
+ - RuboCop zero offenses; `Metrics/ClassLength` / `Naming/MethodName` exclusions documented for the WEBrick servlet contract and the static HTML page heredoc
59
+ - `.apkg` writer uses per-table id sequences (`@note_seq`/`@card_seq`) — fixes a primary-key collision when a cloze note expands into multiple card rows
60
+
61
+ ## [1.2.0] - 2026-09-30
62
+
63
+ ### Breaking
64
+ - All classes are now namespaced under `AnkiGenerator::` (`AnkiGenerator::DeckBuilder`, `AnkiGenerator::OpenRouterClient`, `AnkiGenerator::FileProcessor`, `AnkiGenerator::CLI`)
65
+ - Library API returns `AnkiGenerator::Card` value objects instead of raw hashes (`card.front` / `card.back`)
66
+ - `AnkiGenerator` class renamed to `AnkiGenerator::DeckBuilder`; `sync_with_existing_deck` is now `sync_with`
67
+ - Default model changed from the retired `openai/gpt-3.5-turbo` to `openai/gpt-4o-mini`
68
+
69
+ ### Added
70
+ - Native `.apkg` writer (`AnkiGenerator::ApkgWriter` + `AnkiGenerator::ApkgSchema`) — replaces the unmaintained `anki2` gem and its deprecated sqlite3 bind-param style
71
+ - Error hierarchy: `AnkiGenerator::Error` with `ConfigurationError`, `ApiError`, `ResponseParseError`, `ValidationError`, `FileProcessingError`
72
+ - `AnkiGenerator::UI` presentation boundary — library code no longer writes to `$stdout` directly; commands accept an injectable UI for quiet/testable output
73
+ - `AnkiGenerator::PromptBuilder` — prompt construction extracted from the HTTP client and unit-tested
74
+ - `anki_generator version` command
75
+ - CLI errors are reported as clean messages with exit code 1 instead of raw backtraces
76
+ - Faraday request timeouts (10s open / 120s read)
77
+ - Resilient JSON parsing: markdown fences and model commentary are stripped before parsing
78
+ - `.ruby-version` / `.tool-versions` pinned to Ruby 3.3
79
+ - SimpleCov coverage (line floor 75%) and WebMock-based HTTP tests
80
+
81
+ ### Fixed
82
+ - **API URL bug**: the client posted to `/chat/completions` (leading slash replaced the base path), dropping `/api/v1` — every AI request would have 404'd
83
+ - `prompt_to_deck` no longer sends the prompt through the API a second time when building the deck from generated cards
84
+ - `prompt_to_deck` temp files no longer leak `temp_<timestamp>.yaml` into the working directory (uses `Tempfile`)
85
+ - Deck YAML is loaded with `YAML.safe_load_file` (aliases rejected, typed errors on bad input)
86
+ - Sync deduplication is now case-insensitive and trims whitespace
87
+ - Previously dead test methods (defined outside their test classes) are collected and run — test count 38 → 80
88
+
89
+ ### Technical
90
+ - Thor CLI is now a thin shell over `AnkiGenerator::Commands::*` service objects with dependency injection
91
+ - RuboCop enforced in CI with zero offenses (`rake lint`)
92
+ - HTTP client tested with WebMock against real request shapes
93
+ - Test suite: 80 tests, 284 assertions
94
+
95
+ ## [1.1.0] - 2026-01-01
96
+
97
+ ### Added
98
+ - **File Attachment Support**: Attach individual files or entire directories for context-aware flashcard generation
99
+ - **Prompt File Support**: Use text files as prompts instead of command-line strings
100
+ - **Intelligent File Processing**: Automatic text file detection with support for 20+ file types
101
+ - **File Size Management**: Configurable limits (1MB per file, 5MB total) with automatic filtering
102
+ - **Enhanced CLI Options**:
103
+ - `--attach` option for file/directory attachments
104
+ - `--prompt-file` option to read prompts from files
105
+ - **Comprehensive Test Suite**: Added `test_file_processor.rb` with full coverage
106
+ - **Enhanced Rake Tasks**: 15+ development tasks including demos, examples, and utilities
107
+ - **Developer Experience**:
108
+ - `rake examples` - Create example files for testing
109
+ - `rake demo_attachments` - Demo file attachment features
110
+ - `rake setup` - Full development environment setup
111
+
112
+ ### Enhanced
113
+ - **OpenRouter Client**: Extended to support file attachments in AI prompts
114
+ - **Anki Generator**: Updated to pass attachments through the generation pipeline
115
+ - **CLI Interface**: Both `generate_yaml` and `prompt_to_deck` commands support new options
116
+ - **Documentation**: Comprehensive README updates with file attachment examples
117
+ - **Error Handling**: Improved file processing with detailed warnings and graceful failures
118
+
119
+ ### Technical
120
+ - Added `FileProcessor` class for robust file and directory handling
121
+ - Enhanced prompt building with attachment content integration
122
+ - Maintained full backward compatibility with existing functionality
123
+ - All tests passing (38 tests, 128 assertions)
124
+
125
+ ## [1.0.0] - 2025-12-XX
126
+
127
+ ### Added
128
+ - **AI-Powered Generation**: OpenRouter API integration with multiple model support
129
+ - **Direct Prompt-to-Deck**: One-command flashcard generation from prompts
130
+ - **Multiple Input Methods**: Support for YAML files and direct prompts
131
+ - **Sync Functionality**: Merge new AI-generated cards with existing decks
132
+ - **Comprehensive CLI**: Full command-line interface with Thor
133
+ - **Model Selection**: Support for GPT, Claude, Llama, and other OpenRouter models
134
+ - **Difficulty Levels**: Easy, medium, hard difficulty settings
135
+ - **Context Support**: Additional context for better AI generation
136
+ - **YAML Formats**: Both traditional and AI-generation YAML formats
137
+
138
+ ### Core Features
139
+ - `prompt_to_deck` - Generate flashcards and create deck in one step
140
+ - `generate_yaml` - Generate YAML from prompts for later use
141
+ - `generate` - Create Anki decks from YAML files
142
+ - `create_ai_template` - Create template files for AI generation
143
+ - `test_api` - Test OpenRouter API connection
144
+
145
+ ### Technical
146
+ - Built with Ruby, Thor, Faraday, and anki2 gem
147
+ - Comprehensive test suite with minitest
148
+ - Environment variable support with dotenv
149
+ - Flexible configuration and error handling
150
+
151
+ ## [0.x.x] - Earlier Versions
152
+
153
+ ### Initial Development
154
+ - Basic YAML to Anki deck conversion
155
+ - Simple flashcard generation
156
+ - Core functionality development
157
+
158
+ ---
159
+
160
+ ## Version Numbering
161
+
162
+ This project follows [Semantic Versioning](https://semver.org/):
163
+ - **MAJOR** version for incompatible API changes
164
+ - **MINOR** version for backwards-compatible functionality additions
165
+ - **PATCH** version for backwards-compatible bug fixes
166
+
167
+ ## Contributing
168
+
169
+ When contributing, please:
170
+ 1. Update this changelog with your changes
171
+ 2. Follow the existing format and categorization
172
+ 3. Add entries under "Unreleased" section
173
+ 4. Move entries to versioned section when releasing
data/Gemfile ADDED
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec
6
+
7
+ group :development do
8
+ gem 'rake', '~> 13.0'
9
+ gem 'rubocop', '~> 1.60', require: false
10
+ gem 'ruby-lsp', require: false
11
+ end
12
+
13
+ group :test do
14
+ gem 'minitest', '~> 5.20'
15
+ gem 'rack-test', '~> 2.1'
16
+ gem 'simplecov', '~> 0.22', require: false
17
+ gem 'webmock', '~> 3.23'
18
+ end
19
+
20
+ # Ruby 3.3+ compatibility (faraday dependency)
21
+ gem 'mutex_m' if RUBY_VERSION >= '3.3.0'
data/Makefile ADDED
@@ -0,0 +1,20 @@
1
+ RUBY = bundle exec ruby
2
+ RAKE = bundle exec rake
3
+ BUNDLE = bundle
4
+ TEST_FILES = test_*.rb
5
+
6
+ install:
7
+ $(BUNDLE) install
8
+
9
+ test:
10
+ $(RAKE)
11
+
12
+ build:
13
+ $(RUBY) build.rbgenerate_apkg
14
+
15
+ clean:
16
+ rm -f *.apkg
17
+
18
+ all: install test build
19
+
20
+ .PHONY: install test build clean all