yukichant 3.0.4 → 3.1.0-beta.10

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 (95) hide show
  1. package/.cursor/rules +58 -0
  2. package/.vscode/settings.json +2 -0
  3. package/AGENTS.md +470 -0
  4. package/README.md +38 -12
  5. package/__tests__/cli.js +20 -0
  6. package/__tests__/data.js +41 -0
  7. package/__tests__/fuzzy-kanji-match.js +24 -0
  8. package/__tests__/index.js +42 -0
  9. package/__tests__/machine-encrypt.js +49 -0
  10. package/__tests__/typo-correction.js +33 -0
  11. package/benchmark/CHATGPT_BENCHMARK.md +90 -0
  12. package/benchmark/README.md +90 -0
  13. package/benchmark/magi_ocr_data/README.md +53 -0
  14. package/benchmark/magi_ocr_data/dataset.tsv +836 -0
  15. package/benchmark/results/.gitkeep +0 -0
  16. package/benchmark/results/chatgpt/2025-12-30T09-51-35_result.tsv +10 -0
  17. package/benchmark/results/chatgpt/2025-12-30T09-54-27_result.tsv +10 -0
  18. package/benchmark/results/chatgpt/2025-12-30T09-56-57_result.tsv +2 -0
  19. package/benchmark/results/chatgpt/2025-12-30T09-57-52_result.tsv +2 -0
  20. package/benchmark/results/chatgpt/2025-12-30T09-58-47_result.tsv +2 -0
  21. package/benchmark/results/chatgpt/2025-12-30T09-59-54_result.tsv +2 -0
  22. package/benchmark/results/chatgpt/2025-12-30T10-02-27_result.tsv +4 -0
  23. package/benchmark/results/chatgpt/2025-12-30T10-06-03_result.tsv +4 -0
  24. package/benchmark/results/chatgpt/2025-12-30T10-12-18_result.tsv +4 -0
  25. package/benchmark/results/chatgpt/2025-12-30T10-14-55_result.tsv +4 -0
  26. package/benchmark/results/chatgpt/2025-12-30T10-16-47_result.tsv +4 -0
  27. package/benchmark/results/chatgpt/2025-12-30T10-20-11_result.tsv +11 -0
  28. package/benchmark/results/chatgpt/2025-12-30T10-31-23_result.tsv +51 -0
  29. package/benchmark/results/chatgpt/20251230T104154.tsv +59 -0
  30. package/benchmark/results/chatgpt/20251230T105039.tsv +11 -0
  31. package/benchmark/results/chatgpt/20251230T105403.tsv +51 -0
  32. package/benchmark/results/chatgpt/20251230T105717.tsv +51 -0
  33. package/benchmark/results/jaro-winkler/2025-12-30T09-06-35_result.tsv +4 -0
  34. package/benchmark/results/jaro-winkler/2025-12-30T09-15-10_result.tsv +101 -0
  35. package/benchmark/results/jaro-winkler/2025-12-30T09-16-17_result.tsv +101 -0
  36. package/benchmark/results/jaro-winkler/2025-12-30T09-18-44_result.tsv +101 -0
  37. package/benchmark/results/jaro-winkler/2025-12-30T09-18-54_result.tsv +101 -0
  38. package/benchmark/results/jaro-winkler/2025-12-30T09-19-02_result.tsv +101 -0
  39. package/benchmark/results/jaro-winkler/2025-12-30T09-23-18_result.tsv +836 -0
  40. package/benchmark/results/jaro-winkler/2025-12-30T09-26-26_result.tsv +836 -0
  41. package/benchmark/results/jaro-winkler/2025-12-30T09-29-03_result.tsv +836 -0
  42. package/benchmark/results/jaro-winkler/2025-12-30T09-29-05_result.tsv +836 -0
  43. package/benchmark/results/jaro-winkler/2025-12-30T09-29-18_result.tsv +836 -0
  44. package/benchmark/results/jaro-winkler/2025-12-30T09-30-11_result.tsv +836 -0
  45. package/benchmark/results/jaro-winkler/20251230T103918.tsv +836 -0
  46. package/benchmark/results/levenshtein/2025-12-30T09-06-36_result.tsv +4 -0
  47. package/benchmark/results/levenshtein/2025-12-30T09-15-11_result.tsv +101 -0
  48. package/benchmark/results/levenshtein/2025-12-30T09-19-03_result.tsv +101 -0
  49. package/benchmark/results/levenshtein/2025-12-30T09-23-19_result.tsv +836 -0
  50. package/benchmark/results/levenshtein/2025-12-30T09-26-27_result.tsv +836 -0
  51. package/benchmark/results/levenshtein/2025-12-30T09-29-04_result.tsv +836 -0
  52. package/benchmark/results/levenshtein/2025-12-30T09-29-06_result.tsv +836 -0
  53. package/benchmark/results/levenshtein/2025-12-30T09-30-12_result.tsv +836 -0
  54. package/benchmark/results/levenshtein/20251230T103919.tsv +836 -0
  55. package/benchmark/results/summary/latest_comparison.tsv +7 -0
  56. package/benchmark/results/tfidf/2025-12-30T09-06-36_result.tsv +4 -0
  57. package/benchmark/results/tfidf/2025-12-30T09-15-12_result.tsv +101 -0
  58. package/benchmark/results/tfidf/2025-12-30T09-19-04_result.tsv +101 -0
  59. package/benchmark/results/tfidf/2025-12-30T09-23-23_result.tsv +836 -0
  60. package/benchmark/results/tfidf/2025-12-30T09-26-31_result.tsv +836 -0
  61. package/benchmark/results/tfidf/2025-12-30T09-29-08_result.tsv +836 -0
  62. package/benchmark/results/tfidf/2025-12-30T09-29-10_result.tsv +836 -0
  63. package/benchmark/results/tfidf/2025-12-30T09-30-15_result.tsv +836 -0
  64. package/benchmark/results/tfidf/20251230T103922.tsv +836 -0
  65. package/benchmark/results/tfidf-levenshtein/2025-12-30T09-06-37_result.tsv +4 -0
  66. package/benchmark/results/tfidf-levenshtein/2025-12-30T09-15-13_result.tsv +101 -0
  67. package/benchmark/results/tfidf-levenshtein/2025-12-30T09-19-04_result.tsv +101 -0
  68. package/benchmark/results/tfidf-levenshtein/2025-12-30T09-23-25_result.tsv +836 -0
  69. package/benchmark/results/tfidf-levenshtein/2025-12-30T09-26-33_result.tsv +836 -0
  70. package/benchmark/results/tfidf-levenshtein/2025-12-30T09-29-10_result.tsv +836 -0
  71. package/benchmark/results/tfidf-levenshtein/2025-12-30T09-29-12_result.tsv +836 -0
  72. package/benchmark/results/tfidf-levenshtein/2025-12-30T09-30-17_result.tsv +836 -0
  73. package/benchmark/results/tfidf-levenshtein/20251230T103924.tsv +836 -0
  74. package/benchmark/scripts/compare-algorithms.js +54 -0
  75. package/benchmark/scripts/compare-and-report.js +35 -0
  76. package/benchmark/scripts/generate-report.js +236 -0
  77. package/benchmark/scripts/prompt-template.txt +118 -0
  78. package/benchmark/scripts/run-accuracy-test.js +155 -0
  79. package/benchmark/scripts/run-chatgpt-test.js +282 -0
  80. package/data/meisi.json +1 -0
  81. package/doc/develop.md +108 -0
  82. package/package.json +17 -3
  83. package/raw_data/json_generator +49 -0
  84. package/raw_data/meisi_json_generator +53 -0
  85. package/raw_data/spell.txt +1011 -0
  86. package/raw_data/spell_NG_word.txt +4 -0
  87. package/src/cli.js +15 -1
  88. package/src/fuzzy-kanji-match.js +103 -0
  89. package/src/index.js +69 -9
  90. package/src/jaro-winkler.js +120 -0
  91. package/src/logger.js +19 -0
  92. package/src/typo-correction.js +370 -0
  93. package/test_data/help_message.js +6 -0
  94. package/.github/workflows/app-test.yml +0 -57
  95. package/.github/workflows/npm-publish.yml +0 -36
package/.cursor/rules ADDED
@@ -0,0 +1,58 @@
1
+ # yukichant プロジェクトルール
2
+
3
+ ## 言語設定
4
+
5
+ **このプロジェクトでは、すべてのコミュニケーションを日本語で行ってください。**
6
+
7
+ - すべての説明・応答は日本語で記述する
8
+ - コミットメッセージは日本語で記述する
9
+ - コードコメントは日本語で記述する
10
+ - レビューコメントは日本語で記述する
11
+ - エラーメッセージの説明は日本語で記述する
12
+
13
+ ## コミットメッセージフォーマット
14
+
15
+ コミットメッセージは以下のフォーマットで記述してください:
16
+
17
+ ```
18
+ [種別] 簡潔な説明
19
+ ```
20
+
21
+ ### 種別の例
22
+ - `[feat]`: 新機能追加
23
+ - `[fix]`: バグ修正
24
+ - `[perf]`: パフォーマンス改善
25
+ - `[refactor]`: コード整理
26
+ - `[test]`: テスト追加/修正
27
+ - `[docs]`: ドキュメント更新
28
+ - `[deps]`: 依存関係の更新
29
+ - `[chore]`: その他の変更
30
+
31
+ ### 例
32
+ ```
33
+ [feat] Levenshtein距離アルゴリズムを追加
34
+ [fix] デコード時の形態素解析エラーを修正
35
+ [docs] 誤字修正アルゴリズムの使い方を追加
36
+ [refactor] 類似度計算処理を関数化
37
+ [test] typo-correctionのテストケースを追加
38
+ ```
39
+
40
+ ## コーディング規約
41
+
42
+ - ES Modules(`import`/`export`)を使用
43
+ - 非同期処理は`async`/`await`を使用
44
+ - 関数型プログラミングスタイル(`map`, `filter`, `reduce`を活用)
45
+ - Unicode正規表現(`\p{scx=Han}`など)を積極的に使用
46
+
47
+ ## プロジェクト概要
48
+
49
+ yukichantは、テキストを日本語の詠唱呪文に変換し、元に戻すことができるNode.js製CLIツールです。
50
+
51
+ ### 主要コンポーネント
52
+ - `src/index.js`: エンコード/デコードのコアロジック
53
+ - `src/typo-correction.js`: 誤字修正機能(Jaro-Winkler / Levenshtein)
54
+ - `src/machine-encrypt.js`: ローター型暗号実装
55
+ - `data/meisi.json`, `data/dousi.json`: 名詞・動詞辞書
56
+
57
+ 詳細は `AGENTS.md` を参照してください。
58
+
@@ -0,0 +1,2 @@
1
+ {
2
+ }
package/AGENTS.md ADDED
@@ -0,0 +1,470 @@
1
+ # AGENTS.md
2
+
3
+ このドキュメントは、AIエージェント(コーディングアシスタント)がyukichantプロジェクトを理解し、効果的に開発支援を行うためのガイドです。
4
+
5
+ ## 重要な指示
6
+
7
+ **このプロジェクトでは、すべてのコミュニケーションを日本語で行ってください。**
8
+
9
+ - コード提案時の説明は日本語で記述する
10
+ - コミットメッセージは日本語で記述する
11
+ - レビューコメントは日本語で記述する
12
+ - エラーメッセージの説明は日本語で記述する
13
+ - ドキュメント・コメントは日本語で記述する
14
+
15
+ ## プロジェクト概要
16
+
17
+ **yukichant**は、テキストデータを日本語の詠唱呪文(魔法の言葉)に変換し、元のテキストに復号できるNode.js製のCLIツールです。
18
+
19
+ ### 主な機能
20
+ - **エンコード**: 任意のテキストを呪文風の日本語文章に変換
21
+ - **デコード**: 呪文を元のテキストに復号
22
+ - **誤字修正**: 呪文のタイポを自動修正してデコード(Jaro-Winkler / Levenshtein)
23
+ - **ランダム生成**: ランダムな呪文を生成
24
+
25
+ ### 技術スタック
26
+ - **言語**: JavaScript (ES Modules)
27
+ - **形態素解析**: kuromoji(yukidic辞書使用)
28
+ - **文字列類似度**: Jaro-Winkler(独自実装)、fastest-levenshtein
29
+ - **暗号化**: 独自のローター型暗号実装
30
+
31
+ ## アーキテクチャ
32
+
33
+ ### ディレクトリ構造
34
+
35
+ ```
36
+ yukichant/
37
+ ├── src/ # ソースコード
38
+ │ ├── cli.js # CLIエントリーポイント(commander使用)
39
+ │ ├── index.js # メインロジック(encode/decode/generate)
40
+ │ ├── machine-encrypt.js # ローター型暗号実装
41
+ │ ├── typo-correction.js # 誤字修正ロジック
42
+ │ ├── fuzzy-kanji-match.js # 漢字類似度マッチング
43
+ │ └── jaro-winkler.js # Jaro-Winkler実装
44
+ ├── data/ # 名詞・動詞データ(JSON)
45
+ │ ├── meisi.json # 名詞辞書(16進数コード→名詞リスト)
46
+ │ └── dousi.json # 動詞辞書(16進数コード→動詞リスト)
47
+ ├── dic/ # kuromoji用辞書(yukidic)
48
+ ├── benchmark/ # ベンチマーク・精度測定
49
+ │ ├── magi_ocr_data/ # Magiプロジェクトから取得したOCRテストデータ
50
+ │ ├── results/ # 検証結果の保存先(.gitignore対象)
51
+ │ └── scripts/ # ベンチマーク実行スクリプト
52
+ ├── __tests__/ # Jest単体テスト
53
+ └── raw_data/ # 辞書生成用スクリプト・元データ
54
+ ```
55
+
56
+ ### データフロー
57
+
58
+ #### エンコード
59
+ ```
60
+ テキスト
61
+ → UTF-8バイト配列
62
+ → ローター暗号でスクランブル
63
+ → 16進数(2桁)に変換
64
+ → 名詞/動詞マッピング(4語ごとに動詞)
65
+ → 呪文文字列
66
+ ```
67
+
68
+ #### デコード
69
+ ```
70
+ 呪文文字列
71
+ → kuromoji形態素解析
72
+ → 辞書マッチング(正規表現)
73
+ → (オプション)誤字修正
74
+ → 16進数コード復元
75
+ → ローター暗号で復号
76
+ → UTF-8テキスト
77
+ ```
78
+
79
+ ## 重要なコンポーネント
80
+
81
+ ### 1. `src/index.js` - コアロジック
82
+
83
+ #### `encode(text, option, data, encoder)`
84
+ - テキストをUTF-8バイト配列に変換
85
+ - `simpleEnigma`でスクランブル
86
+ - 16進数コードを名詞・動詞にマッピング
87
+ - パターン: `名詞 名詞 名詞 動詞。` の繰り返し
88
+
89
+ #### `decode(text, option, data, decoder)`
90
+ - `kuromoji`で形態素解析
91
+ - 辞書から逆引き(名詞/動詞 → 16進数コード)
92
+ - オプションで誤字修正(`typo-correction.js`)
93
+ - `simpleEnigma`で復号
94
+
95
+ #### `generate(length, data, generater)`
96
+ - ランダムバイト配列を生成
97
+ - エンコードして呪文を生成
98
+
99
+ ### 2. `src/typo-correction.js` - 誤字修正
100
+
101
+ #### 主要関数
102
+
103
+ ##### `exec(text, option)`
104
+ 誤字修正のメインエントリーポイント
105
+ - `kuromoji`で形態素解析
106
+ - 未知の形態素を検出・修正
107
+ - オプションに応じて類似度アルゴリズムを選択
108
+
109
+ ##### `findClosestWord(word, wordList, useLevenshtein, option)`
110
+ 最も近い単語を辞書から検索
111
+ - `useLevenshtein=true`: Levenshtein距離
112
+ - `useLevenshtein=false`: Jaro-Winkler距離(デフォルト)
113
+
114
+ ##### `nearTokenMatch(tokenStr, option)`
115
+ TF-IDF重み付けを使った高度なマッチング
116
+ - 漢字の部首・構造情報を活用
117
+ - `fuzzy-kanji-match.js`と連携
118
+
119
+ ##### `organizeUnknownTokens(ntokens, option)`
120
+ 連続する未知の形態素をまとめる
121
+ - 副詞・助詞の処理
122
+ - 形態素の位置情報を保持
123
+
124
+ #### オプション
125
+ - `is_tfidf`: TF-IDF重み付けを使用(デフォルト: false)
126
+ - `Levenshtein`: Levenshtein距離を使用(デフォルト: false、Jaro-Winkler)
127
+ - `v`: デバッグ出力(修正前後を表示)
128
+ - `Vv`: 詳細デバッグ出力(類似度スコアなど)
129
+
130
+ ### 3. `src/machine-encrypt.js` - ローター型暗号
131
+
132
+ Enigma機を模した暗号化アルゴリズム
133
+ - バイトコードの頻度分布を均等化
134
+ - 同じ入力に対して異なる暗号文を生成可能
135
+
136
+ ### 4. `src/jaro-winkler.js` - 文字列類似度
137
+
138
+ #### `JaroWinklerDistance`クラス
139
+ - `similarity(s1, s2)`: 0~1の類似度スコア(1が完全一致)
140
+ - 接頭辞一致に高い重みを与える(日本語に適している)
141
+ - パラメータ:
142
+ - `prefixScale`: 0.1(接頭辞の重み)
143
+ - `boostThreshold`: 0.7
144
+ - `prefixLength`: 4
145
+
146
+ ### 5. データ形式
147
+
148
+ #### `data/meisi.json`, `data/dousi.json`
149
+ ```json
150
+ {
151
+ "00": ["単語1", "単語2", ...],
152
+ "01": [...],
153
+ ...
154
+ "FF": [...]
155
+ }
156
+ ```
157
+ - キー: 2桁16進数(00~FF、256種類)
158
+ - 値: その16進数に対応する単語のリスト
159
+
160
+ ## 開発ガイドライン
161
+
162
+ ### コーディング規約
163
+ - ES Modules(`import`/`export`)を使用
164
+ - 非同期処理は`async`/`await`
165
+ - 関数型プログラミングスタイル(`map`, `filter`, `reduce`多用)
166
+ - Unicode正規表現(`\p{scx=Han}`など)を積極的に使用
167
+
168
+ ### テスト
169
+ ```bash
170
+ npm test # Jestで単体テスト実行
171
+ ```
172
+
173
+ テストファイル: `__tests__/*.js`
174
+
175
+ ### ビルド・実行
176
+ ```bash
177
+ # 開発モード(エンコード)
178
+ npm run dev unko
179
+
180
+ # 開発モード(デコード)
181
+ echo "呪文" | npm run dev -- -d
182
+
183
+ # 誤字修正付きデコード
184
+ echo "呪文" | npm run dev -- -d -s
185
+
186
+ # Levenshteinアルゴリズム使用
187
+ echo "呪文" | npm run dev -- -d -s --levenshtein
188
+
189
+ # デバッグ出力
190
+ echo "呪文" | npm run dev -- -d -s -vv
191
+ ```
192
+
193
+ ### 辞書データ更新
194
+ ```bash
195
+ # meisi.jsonを再生成
196
+ ./raw_data/meisi_json_generator
197
+
198
+ # dousi.jsonの生成
199
+ ./raw_data/json_generator
200
+ ```
201
+
202
+ ### ベンチマーク
203
+ ```bash
204
+ # 全アルゴリズム比較 + レポート生成(デフォルト)
205
+ npm run benchmark
206
+
207
+ # 単一アルゴリズムのテスト
208
+ npm run benchmark:single [algorithm]
209
+
210
+ # 全アルゴリズムの比較(レポートなし)
211
+ npm run benchmark:compare
212
+
213
+ # レポート生成のみ(既存のサマリーから)
214
+ npm run benchmark:report
215
+
216
+ # 最新結果を収集してレポート生成
217
+ npm run benchmark:report:latest
218
+
219
+ # ChatGPT APIを使用したテスト(上位50件)
220
+ export OPENAI_API_KEY="sk-..."
221
+ npm run benchmark:chatgpt
222
+ npm run benchmark:chatgpt -- --model gpt-4 --limit 30
223
+ ```
224
+
225
+ ## よくある変更タスク
226
+
227
+ ### 1. 新しい名詞・動詞を追加
228
+ - `raw_data/spell.txt`を編集
229
+ - `npm run json-generate`で再生成
230
+ - テストで動作確認
231
+
232
+ ### 2. 誤字修正アルゴリズムの調整
233
+ - `src/jaro-winkler.js`のパラメータ調整
234
+ - または`src/typo-correction.js`の閾値調整
235
+ - `__tests__/typo-correction.js`でテスト
236
+
237
+ ### 3. 新しい類似度アルゴリズムの追加
238
+ - `src/typo-correction.js`の`calculateSimilarity()`に条件分岐追加
239
+ - `src/cli.js`にコマンドラインオプション追加
240
+ - テストケース追加
241
+
242
+ ### 4. 暗号化方式の変更
243
+ - `src/machine-encrypt.js`を編集
244
+ - エンコード/デコード両方で一貫性を保つ
245
+ - バージョン互換性に注意
246
+
247
+ ### 5. ベンチマークデータの追加
248
+ - `benchmark/magi_ocr_data/dataset.tsv`にテストケースを追加
249
+ - TSV形式: `id`, `ocr_result`, `expected`, `description`, `image_file`
250
+ - `npm run benchmark:compare`で全アルゴリズムの精度を測定
251
+
252
+ ## デバッグ Tips
253
+
254
+ ### 形態素解析の確認
255
+ ```javascript
256
+ // typo-correction.jsのexec()内
257
+ if (option.Vv === true) {
258
+ console.log('ntokens', ntokens); // 形態素リスト表示
259
+ }
260
+ ```
261
+
262
+ ### 類似度スコアの確認
263
+ ```bash
264
+ echo "罹刹に烙印を秘術を帰ら。" | npm run dev -- -d -s -vv
265
+ # → アルゴリズム名、類似度スコア、候補単語数を表示
266
+ ```
267
+
268
+ ### 辞書マッチング確認
269
+ ```javascript
270
+ // index.jsのdecode()内
271
+ console.log('decodeHash', Object.keys(decodeHash).length); // 辞書サイズ
272
+ console.log('textCodeList', textCodeList); // マッチした単語リスト
273
+ ```
274
+
275
+ ## 依存関係
276
+
277
+ ### 重要な外部ライブラリ
278
+ - **kuromoji**: 日本語形態素解析(辞書: yukidic)
279
+ - **yukidic**: カスタム形態素解析辞書(git submodule)
280
+ - **fastest-levenshtein**: 高速Levenshtein距離計算
281
+ - **natural**: TF-IDF計算(NLP)
282
+ - **commander**: CLIフレームワーク
283
+ - **picocolors**: ターミナル色付け
284
+
285
+ ### インストール時の注意
286
+ ```bash
287
+ npm install
288
+ # → postinstallでyukidicをgit cloneする
289
+ ```
290
+
291
+ ## パフォーマンス考慮事項
292
+
293
+ ### ボトルネック
294
+ 1. **kuromoji初期化**: 初回起動時に辞書読み込みが発生
295
+ 2. **形態素解析**: 長文のデコード時に時間がかかる
296
+ 3. **類似度計算**: 辞書サイズ×未知語数に比例
297
+
298
+ ### 最適化ポイント
299
+ - kuromojiのtokenizerをキャッシュ(`typo-correction.js`でモジュールスコープ変数)
300
+ - `fastest-levenshtein`を使用(C++バインディングで高速)
301
+ - 正規表現を事前コンパイル
302
+
303
+ ## セキュリティ考慮事項
304
+
305
+ ### 制限事項
306
+ - **暗号学的に安全ではない**: 暗号化は難読化目的のみ
307
+ - **既知平文攻撃に弱い**: 辞書が公開されているため
308
+ - **機密情報の保護には使用しない**
309
+
310
+ ### 適切な用途
311
+ - ✅ テキストの難読化・遊び
312
+ - ✅ データのエンコード(可逆圧縮的用途)
313
+ - ❌ パスワード保存
314
+ - ❌ 暗号通信
315
+
316
+ ## トラブルシューティング
317
+
318
+ ### 問題: デコードが失敗する
319
+ - 誤字修正モード(`-s`)を試す
320
+ - `-vv`オプションで詳細ログを確認
321
+ - 辞書に単語が存在するか確認
322
+
323
+ ### 問題: 形態素解析エラー
324
+ - `yukidic`辞書が正しくインストールされているか確認
325
+ - `npm install`を再実行
326
+
327
+ ### 問題: テストが失敗する
328
+ - Node.jsバージョン確認(>=12.22.8)
329
+ - `NODE_OPTIONS=--experimental-vm-modules jest`が必要
330
+
331
+ ## レビュー・コミットガイドライン
332
+
333
+ ### レビュー時のチェックポイント
334
+ - エンコード/デコードの一貫性が保たれているか
335
+ - 既存の呪文がデコード可能か(後方互換性)
336
+ - ユニットテストが追加/更新されているか
337
+ - パフォーマンスへの影響
338
+ - 日本語のドキュメント・コメントが適切か
339
+
340
+ ### コミットメッセージ
341
+ **日本語で記載する**こと。
342
+
343
+ 推奨フォーマット: `[種別] 簡潔な説明`
344
+
345
+ 種別の例:
346
+ - `[feat]`: 新機能追加
347
+ - `[fix]`: バグ修正
348
+ - `[perf]`: パフォーマンス改善
349
+ - `[refactor]`: コード整理
350
+ - `[test]`: テスト追加/修正
351
+ - `[docs]`: ドキュメント更新
352
+ - `[deps]`: 依存関係の更新
353
+ - `[chore]`: その他の変更
354
+
355
+ 例:
356
+ ```
357
+ [feat] Levenshtein距離アルゴリズムを追加
358
+ [fix] デコード時の形態素解析エラーを修正
359
+ [docs] 誤字修正アルゴリズムの使い方を追加
360
+ [refactor] 類似度計算処理を関数化
361
+ [test] typo-correctionのテストケースを追加
362
+ ```
363
+
364
+ ## ベンチマーク機能
365
+
366
+ ### 概要
367
+
368
+ `benchmark/`ディレクトリには、誤字修正機能の精度を測定するためのテストデータとスクリプトが含まれています。
369
+
370
+ ### データソース
371
+
372
+ - **Magi OCRデータ**: [Chantプロジェクト](https://github.com/xztaityozx/Chant)から取得したOCRテストデータ
373
+ - 画像に書かれた呪文をOCRで読み取った結果と正解データのペア
374
+ - yukichantの誤字修正機能の精度評価に使用
375
+
376
+ ### ディレクトリ構造
377
+
378
+ ```
379
+ benchmark/
380
+ ├── magi_ocr_data/ # Magiプロジェクトから取得したOCRテストデータ
381
+ │ ├── dataset.tsv # テストデータ(TSV形式)
382
+ │ └── images/ # OCR元画像(オプション)
383
+ ├── results/ # 検証結果の保存先(.gitignore対象)
384
+ │ ├── jaro-winkler/ # Jaro-Winklerアルゴリズムの結果
385
+ │ ├── levenshtein/ # Levenshteinアルゴリズムの結果
386
+ │ ├── tfidf/ # TF-IDF使用時の結果
387
+ │ ├── tfidf-levenshtein/ # TF-IDF + Levenshteinの結果
388
+ │ ├── chatgpt/ # ChatGPT APIを使用した結果
389
+ │ └── summary/ # 全体サマリー
390
+ └── scripts/ # ベンチマーク実行スクリプト
391
+ ├── run-accuracy-test.js # 単一アルゴリズムのテスト
392
+ ├── compare-algorithms.js # 全アルゴリズムの比較
393
+ ├── generate-report.js # レポート生成
394
+ ├── run-chatgpt-test.js # ChatGPT APIテスト
395
+ ├── prompt-template.txt # ChatGPT用プロンプトテンプレート
396
+ └── README_CHATGPT.md # ChatGPTテストの詳細ドキュメント
397
+ ```
398
+
399
+ ### データフォーマット
400
+
401
+ #### 入力データ(dataset.tsv)
402
+ ```tsv
403
+ id ocr_result expected description image_file
404
+ 001 罹刹に烙印を秘術を帰ら。 羅刹に烙印を秘術を刻ら。 漢字の誤認識(罹→羅、帰→刻) test001.png
405
+ ```
406
+
407
+ #### 検証結果(results/{algorithm}/YYYYMMDD_HHMMSS_result.tsv)
408
+ ```tsv
409
+ id input expected corrected is_correct algorithm options execution_time_ms
410
+ 001 罹刹に烙印を秘術を帰ら。 羅刹に烙印を秘術を刻ら。 羅刹に烙印を秘術を刻ら。 true jaro-winkler {"is_tfidf":false} 45.2
411
+ ```
412
+
413
+ ### 使用方法
414
+
415
+ ```bash
416
+ # 全アルゴリズム比較 + レポート生成(デフォルト)
417
+ npm run benchmark
418
+
419
+ # 単一アルゴリズムのテスト
420
+ npm run benchmark:single [algorithm]
421
+
422
+ # 全アルゴリズムの比較(レポートなし)
423
+ npm run benchmark:compare
424
+
425
+ # レポート生成のみ(精度順にソート、最速・バランス推奨を表示)
426
+ npm run benchmark:report
427
+
428
+ # ChatGPT APIを使用したテスト(上位50件、コスト削減のため)
429
+ export OPENAI_API_KEY="sk-..."
430
+ npm run benchmark:chatgpt
431
+ npm run benchmark:chatgpt -- --model gpt-4 --limit 30
432
+ ```
433
+
434
+ ### ChatGPT APIテスト
435
+
436
+ ChatGPT APIを使用したプロンプトベースの誤字修正テストも利用可能です。
437
+
438
+ **特徴**:
439
+ - プロンプトテンプレートをカスタマイズ可能(`benchmark/scripts/prompt-template.txt`)
440
+ - 予算の都合上、デフォルトで上位50件のみテスト
441
+ - 複数のモデル(gpt-4o-mini, gpt-4o, gpt-4)をサポート
442
+ - 結果は他のアルゴリズムと同様にサマリーに統合される
443
+
444
+ **詳細**: `benchmark/scripts/README_CHATGPT.md` を参照
445
+
446
+ ### 精度指標
447
+
448
+ - **正解率(Accuracy)**: 完全一致した割合
449
+ - **平均実行時間**: 1件あたりの平均処理時間(ミリ秒)
450
+
451
+ ### ベンチマーク結果の活用
452
+
453
+ 1. **アルゴリズムの比較**: 各アルゴリズムの精度と速度を比較
454
+ 2. **パラメータ調整**: アルゴリズムのパラメータを調整して精度向上
455
+ 3. **リグレッションテスト**: コード変更後の精度低下を検出
456
+ 4. **デフォルトアルゴリズムの選定**: 最適なアルゴリズムを選択
457
+
458
+ ## 参考リンク
459
+
460
+ - [kuromoji.js](https://github.com/takuyaa/kuromoji.js)
461
+ - [yukidic辞書](https://github.com/amanoese/yukidic)
462
+ - [Jaro-Winkler距離](https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance)
463
+ - [Levenshtein距離](https://en.wikipedia.org/wiki/Levenshtein_distance)
464
+ - [Enigma暗号機](https://en.wikipedia.org/wiki/Enigma_machine)
465
+ - [Chantプロジェクト(Magi)](https://github.com/xztaityozx/Chant) - OCRテストデータの出典
466
+
467
+ ---
468
+
469
+ **このドキュメントは、AIエージェントがプロジェクトを理解し、コンテキストに沿った提案を行うためのガイドです。人間の開発者が読む場合は、まず[README.md](./README.md)と[develop.md](./doc/develop.md)を参照してください。**
470
+
package/README.md CHANGED
@@ -28,25 +28,51 @@ $ chant
28
28
  水面も灰塵に蒼穹を抗え。
29
29
  ```
30
30
 
31
- ## Develop
31
+ ## 高度な使い方
32
32
 
33
- install dependency
34
- ```bash
35
- $ npm install
36
- ```
33
+ ### 厳密デコードモードと誤字修正
34
+
35
+ yukichantは、類似度アルゴリズムを使用した誤字修正機能付きの厳密デコードモードをサポートしています。
37
36
 
38
- execute command
39
37
  ```bash
40
- ## run encode
41
- $ npm run dev unko
42
- ## run decode
43
- $ npm run dev unko | npm run dev -- -d
38
+ ## 厳密デコードモード(デフォルト: Jaro-Winklerアルゴリズム)
39
+ $ echo 罹刹に烙印を秘術を帰ら。 | chant -d -s
40
+ # 自動的に誤字を修正: 罹刹 → 羅刹
41
+
42
+ ## Levenshtein距離アルゴリズムを使用
43
+ $ echo 罹刹に烙印を秘術を帰ら。 | chant -d -s --levenshtein
44
+ # 異なるアルゴリズムで同様の修正を実行
45
+
46
+ ## TF-IDF重み付けを無効化
47
+ $ echo 罹刹に烙印を秘術を帰ら。 | chant -d -s --no-tfidf
48
+
49
+ ## 詳細モードで修正内容を表示
50
+ $ echo 罹刹に烙印を秘術を帰ら。 | chant -d -s -v
51
+ # どの単語が修正されたかを表示
52
+
53
+ ## より詳細な出力
54
+ $ echo 罹刹に烙印を秘術を帰ら。 | chant -d -s -vv
55
+ # 類似度スコアと使用されたアルゴリズムの詳細を表示
44
56
  ```
45
57
 
46
- ## LICENSE
47
- Apache-2.0
58
+ ### アルゴリズムの比較
59
+
60
+ yukichantは誤字修正のために2つの文字列類似度アルゴリズムを提供しています:
61
+
62
+ - **Jaro-Winkler(デフォルト)**: 日本語テキストに適しており、接頭辞の一致に高い重みを与えます
63
+ - **Levenshtein**: 古典的な編集距離アルゴリズムで、必要な最小編集回数をカウントします
64
+
65
+ 用途に応じてアルゴリズムを選択してください:
66
+ - 一般的な日本語テキストには **Jaro-Winkler** を使用(推奨)
67
+ - より厳密なマッチングには `--levenshtein` フラグで **Levenshtein** を使用
68
+
69
+ ## Documentation for Developers
70
+ [develop](/doc/develop.md)
48
71
 
49
72
  ## Thanks
50
73
  I named "yukichant" by Nagato Yuki-chan + chant .
51
74
  because I want to chant magic words like her.
52
75
 
76
+ ## LICENSE
77
+ Apache-2.0
78
+
@@ -0,0 +1,20 @@
1
+ const chant_cmd = `./src/cli.js`
2
+
3
+ import fs from 'fs';
4
+ import { execSync } from 'child_process';
5
+ import help_message from '../test_data/help_message';
6
+
7
+ describe('chant',()=>{
8
+ test('generate',async ()=>{
9
+ let result = execSync(`${chant_cmd}`)
10
+ expect(result.toString()).toEqual(expect.anything())
11
+ })
12
+ test('--help',async ()=>{
13
+ let result = execSync(`${chant_cmd} --help`)
14
+ expect(result.toString()).toEqual(help_message)
15
+ })
16
+ test('encode to decode',async ()=>{
17
+ let result = execSync(`echo -n unko | ${chant_cmd} | ${chant_cmd} -d`)
18
+ expect(result.toString()).toEqual('unko')
19
+ })
20
+ })
@@ -0,0 +1,41 @@
1
+ /*
2
+
3
+ このテストではdata/*.jsonのバリューの重複がないことを検証する。
4
+
5
+ data/dousi.jsonとdata/meisi.jsonのバリュー(呪文)の文字列は重複してはならない。
6
+ 後から要素を追加した際に、重複が発生すると正常にdecodeできなくなる懸念があるためである。
7
+
8
+ */
9
+ import fs from 'fs'
10
+ const meisi = JSON.parse(fs.readFileSync('./data/meisi.json', 'utf8'));
11
+ const dousi = JSON.parse(fs.readFileSync('./data/dousi.json', 'utf8'));
12
+
13
+ describe('meisi', () => {
14
+ test('meisiの値に重複するものが存在しない', () => {
15
+ let valueCount = 0
16
+ let valueHash = {}
17
+ Object.entries(meisi).forEach(([k,v])=> {
18
+ valueCount += v.length
19
+ v.forEach(v2=> {
20
+ valueHash[v2] = true
21
+ })
22
+ })
23
+
24
+ expect(Object.keys(valueHash).length === valueCount).toBeTruthy()
25
+ })
26
+ })
27
+
28
+ describe('dousi', () => {
29
+ test('dousiの値に重複するものが存在しない', () => {
30
+ let valueCount = 0
31
+ let valueHash = {}
32
+ Object.entries(dousi).forEach(([k,v])=> {
33
+ valueCount += v.length
34
+ v.forEach(v2=> {
35
+ valueHash[v2] = true
36
+ })
37
+ })
38
+
39
+ expect(Object.keys(valueHash).length === valueCount).toBeTruthy()
40
+ })
41
+ })
@@ -0,0 +1,24 @@
1
+ import simpleEnigma from '../src/machine-encrypt.js'
2
+ import fkm from '../src/fuzzy-kanji-match.js';
3
+
4
+ describe('fuzzyKanjiMatch', () => {
5
+ test('minDistances 正しい漢字の距離は最も短い', () => {
6
+ expect(fkm.minDistances('羅').length).toBe(1);
7
+ })
8
+ test('minDistances', () => {
9
+ expect(fkm.minDistances('罹').map(v=>v.kanji)).toContain('羅');
10
+ })
11
+ // これはテストが通らない
12
+ //test('fuzzyKanjiMatch', () => {
13
+ // expect(fkm.minDistances('剤').map(v=>v.kanji)).toContain('刹');
14
+ //})
15
+ test('maxTfidfSocres 正しい漢字のスコアは最も高い', () => {
16
+ expect(fkm.maxTfidfSocres('羅').length).toBe(1);
17
+ })
18
+ test('maxTfidfSocres', () => {
19
+ expect(fkm.maxTfidfSocres('罹').map(v=>v.kanji)).toContain('羅');
20
+ })
21
+ test('maxTfidfSocres', () => {
22
+ expect(fkm.maxTfidfSocres('剤').map(v=>v.kanji)).toContain('刹');
23
+ })
24
+ });