Build Anki vocabulary decks from Japanese text file
  • Python 71.9%
  • Just 28.1%
Find a file
Benoit e5ce6eea66 Fix pyproject.toml: move dependencies back under [project] table
Previous commit accidentally placed `dependencies` inside [project.urls],
breaking the build (hatchling rejected non-string URL value).

Co-Authored-By: OpenCode + GLM-5.2
2026-07-05 03:49:43 +02:00
tests AnkiGenerator: build Anki decks from the most-used words in a Japanese text file 2026-07-05 03:42:46 +02:00
.gitignore AnkiGenerator: build Anki decks from the most-used words in a Japanese text file 2026-07-05 03:42:46 +02:00
ankanigen.py AnkiGenerator: build Anki decks from the most-used words in a Japanese text file 2026-07-05 03:42:46 +02:00
Justfile AnkiGenerator: build Anki decks from the most-used words in a Japanese text file 2026-07-05 03:42:46 +02:00
LICENSE AnkiGenerator: build Anki decks from the most-used words in a Japanese text file 2026-07-05 03:42:46 +02:00
pyproject.toml Fix pyproject.toml: move dependencies back under [project] table 2026-07-05 03:49:43 +02:00
README.md AnkiGenerator: build Anki decks from the most-used words in a Japanese text file 2026-07-05 03:42:46 +02:00
uv.lock Fix pyproject.toml: move dependencies back under [project] table 2026-07-05 03:49:43 +02:00

AnkiGenerator

Build Anki vocabulary decks from the most-used words in a Japanese text file.

Give it any Japanese text — a chat log, a novel, an article, song lyrics — and it counts how often each word appears, then turns the top N most frequent words into Anki cards ordered by usage frequency. The words you encounter most in the source end up first in the deck.

100% vibe-coded by OpenCode + GLM-5.2. 0% human code. No human wrote or edited a line of the implementation — every instruction was given in natural language and the code was generated end-to-end by an AI agent.

Pairs tokenization (MeCab/UniDic via fugashi) with the JMdict dictionary (via jamdict) and emits an importable .apkg using genanki.

Each card looks like:

Side Content
Front the word (kanji or kana, as actually written in the source)
Back furigana (hiragana) + brief English senses

Card order = usage frequency in the source text (most-used word first).

Setup

Requires uv (the fast Python package manager).

uv sync                        # create .venv and install deps
uv run python -m unidic download   # one-off: extract UniDic (~526 MB)

jamdict-data bundles a prebuilt JMdict SQLite DB and is installed automatically by uv sync. On first lookup jamdict copies/uses it from ~/.jamdict/data/jamdict.db.

Usage

uv run ankanigen somefileinjp.txt -o output.apkg \
    --limit 500 --deck-name "Top Vocab"

You can also invoke the module directly without installing the entry point:

uv run python ankanigen.py somefileinjp.txt -o output.apkg

Then File → Import the .apkg in Anki Desktop.

Tests

An end-to-end test lives in tests/sample_jp.txt + the test-e2e recipe in the Justfile:

just test-e2e

It builds a small deck from the sample, checks the .apkg is a valid non-empty zip, asserts kana-only words (ありがとう, おはよう) stay kana (no ateji substitution), and asserts verbs are normalised to dictionary form (no bare stems like / on the front).

Input format

Any plain-text file containing Japanese. As a convenience, chat-export style lines prefixed by HH:MM<Tab>Name<Tab> are stripped down to the message body, and [Sticker] placeholders / http(s)://… URLs are removed before tokenization:

13:54	Alice	今夜は何を食べますか?
14:51	Bob	[Sticker]
14:52	Bob	お寿司が食べたい!

Plain prose, articles, lyrics, etc. work just as well — every line that contains kana or kanji is tokenized.

How it works

  1. Filter the file down to Japanese-bearing lines.
  2. Tokenize each line with MeCab/UniDic, keeping tokens whose coarse POS is in 名詞 / 動詞 / 形容詞 / 副詞 / 連体詞 / 感動詞.
  3. Count dictionary lemmas (falling back to surface form when no lemma is available), and remember which surface forms the writer actually used for each lemma.
  4. Look up each top lemma in JMdict, preferring the entry whose kanji/kana form matches the surface form or the lemma.
  5. Build cards:
    • Verbs & adjectives → normalised to their dictionary form (食べた → 食べる, すごく → すごい), honouring the writer's kanji/kana choice. Wrote 食べた → card shows 食べる; wrote すごい → card shows すごい (not 凄い).
    • Other parts of speech (名詞, 副詞, 感動詞, 連体詞) → the card front honours how the writer actually wrote the word:
      • wrote it in kanji → show kanji (the dictionary kanji form);
      • wrote it in kana → keep kana. Rare ateji kanji listings in JMdict (有り難う for ありがとうござる, 御早う for おはよう, …) are not substituted.
    • Reading → furigana (hiragana-converted kana); meanings → first four English sense glosses.
  6. Package with genanki using stable model/deck IDs so re-imports update cards in place.

Notes / limitations

  • Verbs and adjectives are stored in dictionary form (辞書形), e.g. 食べる, すごい. The script (kanji vs kana) follows how the writer most often wrote the word, so すごい stays すごい even though JMdict lists 凄い.
  • Particles (助詞), auxiliaries (助動詞), symbols and pure-Latin tokens are excluded.
  • Kana-written words like ありがとう, おはよう, うん are kept in kana — JMdict's rare ateji kanji forms are not forced onto the card front.
  • Proper nouns (place names, people) show up as 名詞, so anything that recurs often in the source text will rank high.
  • Default limit is 500 cards; bump with --limit.

License

Public Domain (Creative Commons Zero v1.0 Universal / CC0). See LICENSE.

This project is 100% vibe-coded — every line was generated by an AI agent (OpenCode + GLM-5.2) from natural-language prompts, with no human-authored code. See the header note above.