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.
- package/.cursor/rules +58 -0
- package/.vscode/settings.json +2 -0
- package/AGENTS.md +470 -0
- package/README.md +38 -12
- package/__tests__/cli.js +20 -0
- package/__tests__/data.js +41 -0
- package/__tests__/fuzzy-kanji-match.js +24 -0
- package/__tests__/index.js +42 -0
- package/__tests__/machine-encrypt.js +49 -0
- package/__tests__/typo-correction.js +33 -0
- package/benchmark/CHATGPT_BENCHMARK.md +90 -0
- package/benchmark/README.md +90 -0
- package/benchmark/magi_ocr_data/README.md +53 -0
- package/benchmark/magi_ocr_data/dataset.tsv +836 -0
- package/benchmark/results/.gitkeep +0 -0
- package/benchmark/results/chatgpt/2025-12-30T09-51-35_result.tsv +10 -0
- package/benchmark/results/chatgpt/2025-12-30T09-54-27_result.tsv +10 -0
- package/benchmark/results/chatgpt/2025-12-30T09-56-57_result.tsv +2 -0
- package/benchmark/results/chatgpt/2025-12-30T09-57-52_result.tsv +2 -0
- package/benchmark/results/chatgpt/2025-12-30T09-58-47_result.tsv +2 -0
- package/benchmark/results/chatgpt/2025-12-30T09-59-54_result.tsv +2 -0
- package/benchmark/results/chatgpt/2025-12-30T10-02-27_result.tsv +4 -0
- package/benchmark/results/chatgpt/2025-12-30T10-06-03_result.tsv +4 -0
- package/benchmark/results/chatgpt/2025-12-30T10-12-18_result.tsv +4 -0
- package/benchmark/results/chatgpt/2025-12-30T10-14-55_result.tsv +4 -0
- package/benchmark/results/chatgpt/2025-12-30T10-16-47_result.tsv +4 -0
- package/benchmark/results/chatgpt/2025-12-30T10-20-11_result.tsv +11 -0
- package/benchmark/results/chatgpt/2025-12-30T10-31-23_result.tsv +51 -0
- package/benchmark/results/chatgpt/20251230T104154.tsv +59 -0
- package/benchmark/results/chatgpt/20251230T105039.tsv +11 -0
- package/benchmark/results/chatgpt/20251230T105403.tsv +51 -0
- package/benchmark/results/chatgpt/20251230T105717.tsv +51 -0
- package/benchmark/results/jaro-winkler/2025-12-30T09-06-35_result.tsv +4 -0
- package/benchmark/results/jaro-winkler/2025-12-30T09-15-10_result.tsv +101 -0
- package/benchmark/results/jaro-winkler/2025-12-30T09-16-17_result.tsv +101 -0
- package/benchmark/results/jaro-winkler/2025-12-30T09-18-44_result.tsv +101 -0
- package/benchmark/results/jaro-winkler/2025-12-30T09-18-54_result.tsv +101 -0
- package/benchmark/results/jaro-winkler/2025-12-30T09-19-02_result.tsv +101 -0
- package/benchmark/results/jaro-winkler/2025-12-30T09-23-18_result.tsv +836 -0
- package/benchmark/results/jaro-winkler/2025-12-30T09-26-26_result.tsv +836 -0
- package/benchmark/results/jaro-winkler/2025-12-30T09-29-03_result.tsv +836 -0
- package/benchmark/results/jaro-winkler/2025-12-30T09-29-05_result.tsv +836 -0
- package/benchmark/results/jaro-winkler/2025-12-30T09-29-18_result.tsv +836 -0
- package/benchmark/results/jaro-winkler/2025-12-30T09-30-11_result.tsv +836 -0
- package/benchmark/results/jaro-winkler/20251230T103918.tsv +836 -0
- package/benchmark/results/levenshtein/2025-12-30T09-06-36_result.tsv +4 -0
- package/benchmark/results/levenshtein/2025-12-30T09-15-11_result.tsv +101 -0
- package/benchmark/results/levenshtein/2025-12-30T09-19-03_result.tsv +101 -0
- package/benchmark/results/levenshtein/2025-12-30T09-23-19_result.tsv +836 -0
- package/benchmark/results/levenshtein/2025-12-30T09-26-27_result.tsv +836 -0
- package/benchmark/results/levenshtein/2025-12-30T09-29-04_result.tsv +836 -0
- package/benchmark/results/levenshtein/2025-12-30T09-29-06_result.tsv +836 -0
- package/benchmark/results/levenshtein/2025-12-30T09-30-12_result.tsv +836 -0
- package/benchmark/results/levenshtein/20251230T103919.tsv +836 -0
- package/benchmark/results/summary/latest_comparison.tsv +7 -0
- package/benchmark/results/tfidf/2025-12-30T09-06-36_result.tsv +4 -0
- package/benchmark/results/tfidf/2025-12-30T09-15-12_result.tsv +101 -0
- package/benchmark/results/tfidf/2025-12-30T09-19-04_result.tsv +101 -0
- package/benchmark/results/tfidf/2025-12-30T09-23-23_result.tsv +836 -0
- package/benchmark/results/tfidf/2025-12-30T09-26-31_result.tsv +836 -0
- package/benchmark/results/tfidf/2025-12-30T09-29-08_result.tsv +836 -0
- package/benchmark/results/tfidf/2025-12-30T09-29-10_result.tsv +836 -0
- package/benchmark/results/tfidf/2025-12-30T09-30-15_result.tsv +836 -0
- package/benchmark/results/tfidf/20251230T103922.tsv +836 -0
- package/benchmark/results/tfidf-levenshtein/2025-12-30T09-06-37_result.tsv +4 -0
- package/benchmark/results/tfidf-levenshtein/2025-12-30T09-15-13_result.tsv +101 -0
- package/benchmark/results/tfidf-levenshtein/2025-12-30T09-19-04_result.tsv +101 -0
- package/benchmark/results/tfidf-levenshtein/2025-12-30T09-23-25_result.tsv +836 -0
- package/benchmark/results/tfidf-levenshtein/2025-12-30T09-26-33_result.tsv +836 -0
- package/benchmark/results/tfidf-levenshtein/2025-12-30T09-29-10_result.tsv +836 -0
- package/benchmark/results/tfidf-levenshtein/2025-12-30T09-29-12_result.tsv +836 -0
- package/benchmark/results/tfidf-levenshtein/2025-12-30T09-30-17_result.tsv +836 -0
- package/benchmark/results/tfidf-levenshtein/20251230T103924.tsv +836 -0
- package/benchmark/scripts/compare-algorithms.js +54 -0
- package/benchmark/scripts/compare-and-report.js +35 -0
- package/benchmark/scripts/generate-report.js +236 -0
- package/benchmark/scripts/prompt-template.txt +118 -0
- package/benchmark/scripts/run-accuracy-test.js +155 -0
- package/benchmark/scripts/run-chatgpt-test.js +282 -0
- package/data/meisi.json +1 -0
- package/doc/develop.md +108 -0
- package/package.json +17 -3
- package/raw_data/json_generator +49 -0
- package/raw_data/meisi_json_generator +53 -0
- package/raw_data/spell.txt +1011 -0
- package/raw_data/spell_NG_word.txt +4 -0
- package/src/cli.js +15 -1
- package/src/fuzzy-kanji-match.js +103 -0
- package/src/index.js +69 -9
- package/src/jaro-winkler.js +120 -0
- package/src/logger.js +19 -0
- package/src/typo-correction.js +370 -0
- package/test_data/help_message.js +6 -0
- package/.github/workflows/app-test.yml +0 -57
- 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
|
+
|
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
|
-
##
|
|
31
|
+
## 高度な使い方
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
```
|
|
33
|
+
### 厳密デコードモードと誤字修正
|
|
34
|
+
|
|
35
|
+
yukichantは、類似度アルゴリズムを使用した誤字修正機能付きの厳密デコードモードをサポートしています。
|
|
37
36
|
|
|
38
|
-
execute command
|
|
39
37
|
```bash
|
|
40
|
-
##
|
|
41
|
-
$
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
47
|
-
|
|
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
|
+
|
package/__tests__/cli.js
ADDED
|
@@ -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
|
+
});
|