Add comprehensive detailed design documents

This commit is contained in:
misyaguziya
2025-10-14 07:28:03 +09:00
parent fcb1295302
commit d1aef28c7a
20 changed files with 8590 additions and 0 deletions

View File

@@ -0,0 +1,659 @@
# transliteration_transliterator.py - 総合音写・転写システム
## 概要
SudachiPyを利用した日本語のローマ字転写システムのメインクラスです。形態素解析、漢字・送り仮名の分離、文脈依存ルールの適用、ヘボン式変換を統合し、高精度な日本語ローマ字化を提供します。
## 主要機能
### 統合転写システム
- SudachiPyによる高精度形態素解析
- 漢字・送り仮名の自動分離処理
- 文脈依存読み変更ルールの適用
### 多層変換処理
- カタカナ読み取得・分配
- ひらがな自動変換
- ヘボン式ローマ字生成
### 並行処理対応
- スレッドセーフなトークナイザー利用
- ロック機構による安全な並行実行
- 高負荷環境での安定動作
## クラス構造
### Transliterator クラス
```python
class Transliterator:
def __init__(self) -> None:
self.tokenizer_obj: tokenizer.Tokenizer
self.mode: tokenizer.Tokenizer.SplitMode
self._tokenizer_lock: threading.Lock
```
日本語転写処理の中核クラス
#### 属性
- **tokenizer_obj**: SudachiPyトークナイザーインスタンス
- **mode**: 分割モードSplitMode.C = 最長一致)
- **_tokenizer_lock**: 並行アクセス制御用ミューテックス
## 主要メソッド
### analyze
```python
def analyze(self, text: str, use_macron: bool = False) -> List[Dict[str, Any]]
```
テキストを解析して転写情報を生成
#### パラメータ
- **text**: 解析対象の日本語テキスト
- **use_macron**: マクロン使用フラグ(長音表記方式)
#### 戻り値
- **List[Dict[str, Any]]**: トークン転写情報のリスト
#### 出力辞書構造
```python
{
"orig": str, # 元の文字・文字列
"kana": str, # カタカナ読み
"hira": str, # ひらがな読み
"hepburn": str # ヘボン式ローマ字
}
```
### split_kanji_okurigana (静的メソッド)
```python
@staticmethod
def split_kanji_okurigana(surface: str, reading_kana: str, use_macron: bool = True) -> List[Dict[str, str]]
```
単語の表層形と読みを漢字・送り仮名ブロックに分割
#### パラメータ
- **surface**: 表層形(漢字+ひらがな混在可能)
- **reading_kana**: 全体のカタカナ読み
- **use_macron**: ヘボン式変換でのマクロン使用
#### 戻り値
- **List[Dict[str, str]]**: 分割された部分の転写情報
## 補助メソッド
### is_kanji (静的メソッド)
```python
@staticmethod
def is_kanji(ch: str) -> bool
```
文字が漢字かどうかを判定
#### パラメータ
- **ch**: 判定対象文字
#### 戻り値
- **bool**: 漢字判定結果
### kata_to_hira (静的メソッド)
```python
@staticmethod
def kata_to_hira(text: str) -> str
```
カタカナをひらがなに変換
#### パラメータ
- **text**: 変換対象のカタカナテキスト
#### 戻り値
- **str**: ひらがな変換結果
## 使用方法
### 基本的な転写処理
```python
from models.transliteration.transliteration_transliterator import Transliterator
# 転写システムの初期化
transliterator = Transliterator()
# 基本的な文章の転写
text = "向こうへ行く"
results = transliterator.analyze(text)
for token in results:
print(f"{token['orig']} -> {token['kana']} -> {token['hira']} -> {token['hepburn']}")
# 期待される出力例:
# 向こう -> ムコウ -> むこう -> mukou
# へ -> ヘ -> へ -> he
# 行く -> イク -> いく -> iku
```
### マクロン使用の長音処理
```python
# マクロンを使用した長音表記
text = "東京に行く"
results_macron = transliterator.analyze(text, use_macron=True)
results_normal = transliterator.analyze(text, use_macron=False)
print("=== マクロンあり ===")
for token in results_macron:
print(f"{token['orig']} -> {token['hepburn']}")
print("=== マクロンなし ===")
for token in results_normal:
print(f"{token['orig']} -> {token['hepburn']}")
# 期待される出力:
# === マクロンあり ===
# 東京 -> tōkyō
# に -> ni
# 行く -> iku
# === マクロンなし ===
# 東京 -> toukyou
# に -> ni
# 行く -> iku
```
### 複雑な文章の処理
```python
# 漢字・ひらがな・カタカナ・英語混在文の処理
complex_text = "パーティーで美しい花を見る"
results = transliterator.analyze(complex_text, use_macron=True)
for token in results:
print(f"原文: '{token['orig']}'")
print(f" カナ: {token['kana']}")
print(f" ひら: {token['hira']}")
print(f" ローマ: {token['hepburn']}")
print()
# 期待される出力:
# 原文: 'パーティー'
# カナ: パーティー
# ひら: ぱーてぃー
# ローマ: pātī
#
# 原文: 'で'
# カナ: デ
# ひら: で
# ローマ: de
#
# 原文: '美しい'
# カナ: ウツクシイ
# ひら: うつくしい
# ローマ: utsukushii
```
### 文脈依存ルールの効果確認
```python
# 文脈に依存する読み変更の例(「何」の読み分け)
test_cases = [
"何が好き?", # 何 -> ナニ (後続が「ガ」)
"何度も挑戦", # 何 -> ナン (後続が「ド」)
"何色ありますか?" # 何 -> ナニ (後続が「イ」)
]
for text in test_cases:
results = transliterator.analyze(text)
print(f"入力: {text}")
# 「何」トークンを探して読みを確認
for token in results:
if token['orig'] == '':
print(f"「何」の読み: {token['kana']} -> {token['hepburn']}")
break
print()
# 期待される出力:
# 入力: 何が好き?
# 「何」の読み: ナニ -> nani
#
# 入力: 何度も挑戦
# 「何」の読み: ナン -> nan
#
# 入力: 何色ありますか?
# 「何」の読み: ナニ -> nani
```
### 特殊文字・記号の処理
```python
# 記号・英数字混在テキストの処理
mixed_text = "ID12345、URLhttps://example.com"
results = transliterator.analyze(mixed_text)
for token in results:
print(f"'{token['orig']}' -> '{token['hepburn']}'")
# 期待される出力:
# 'ID' -> 'ID' # 英字はそのまま
# '' -> '' # 記号はそのまま
# '12345' -> '12345' # 数字はそのまま
# '、' -> '、' # 区切り記号はそのまま
# 'URL' -> 'URL' # 英字はそのまま
```
## 内部処理フロー
### 解析処理パイプライン
```python
def analyze_pipeline_explained(self, text):
"""転写処理パイプラインの詳細説明"""
# 1. SudachiPy形態素解析
with self._tokenizer_lock:
tokens = self.tokenizer_obj.tokenize(text, self.mode)
results = []
# 2. 各トークンの処理
for token in tokens:
surface = token.surface() # 表層形
reading = token.reading_form() # 読み(カタカナ)
pos = token.part_of_speech() # 品詞情報
# 3. 記号・空白の特別処理
if pos and pos[0] in ["記号", "補助記号", "空白"]:
reading = surface # 記号は表層形をそのまま使用
# 4. 表層形と読みが同じ場合(ひらがな・記号等)
if surface == reading:
results.append({
"orig": surface,
"kana": reading,
"hira": surface, # そのまま
"hepburn": surface # そのまま
})
continue
# 5. 単一文字の処理
if len(surface) == 1:
results.append({
"orig": surface,
"kana": reading,
"hira": self.kata_to_hira(reading),
"hepburn": katakana_to_hepburn(reading, use_macron)
})
else:
# 6. 複数文字の漢字・送り仮名分離
parts = self.split_kanji_okurigana(surface, reading, use_macron)
results.extend(parts)
# 7. 文脈依存ルールの適用
try:
results = apply_context_rules(results, use_macron) or results
except Exception:
pass # ルール適用失敗時は元の結果を使用
# 8. ルール適用後の再計算
for entry in results:
kana = entry.get("kana", "")
if kana:
entry["hira"] = self.kata_to_hira(kana)
entry["hepburn"] = katakana_to_hepburn(kana, use_macron)
return results
```
### 漢字・送り仮名分離アルゴリズム
```python
def split_algorithm_explained(surface, reading_kana):
"""分離アルゴリズムの詳細説明"""
# 1. 表層形のブロック分割
blocks = []
current_block = ""
prev_is_kanji = None
for char in surface:
is_kanji = Transliterator.is_kanji(char)
if prev_is_kanji is None or is_kanji == prev_is_kanji:
# 同じタイプの文字は同じブロックに
current_block += char
else:
# タイプが変わったら新しいブロック
blocks.append((prev_is_kanji, current_block))
current_block = char
prev_is_kanji = is_kanji
if current_block:
blocks.append((prev_is_kanji, current_block))
# 例: "向こう" -> [(True, "向"), (False, "こう")]
# "行く" -> [(True, "行"), (False, "く")]
# 2. 読みの分配
kana_len = len(reading_kana)
# 初期割当: 各ブロックの文字数に比例
allocations = [len(block_text) for _, block_text in blocks]
allocated_total = sum(allocations)
remaining = kana_len - allocated_total
# 3. 余った読みの分配(漢字ブロック優先)
if remaining > 0:
# まず漢字ブロックに分配
for i, (is_kanji, _) in enumerate(blocks):
if remaining <= 0:
break
if is_kanji:
allocations[i] += 1
remaining -= 1
# まだ余りがある場合は左から順に分配
i = 0
while remaining > 0 and len(blocks) > 0:
allocations[i] += 1
remaining -= 1
i = (i + 1) % len(blocks)
# 4. 読みが不足している場合は右から削減
if remaining < 0:
need_to_remove = -remaining
i = len(blocks) - 1
while need_to_remove > 0 and i >= 0:
can_remove = max(0, allocations[i] - 1)
remove_amount = min(can_remove, need_to_remove)
allocations[i] -= remove_amount
need_to_remove -= remove_amount
i -= 1
# 5. 最終的な読み分配
pos = 0
result = []
for (is_kanji, block_text), allocation in zip(blocks, allocations):
block_reading = reading_kana[pos:pos + allocation]
pos += allocation
result.append({
"orig": block_text,
"kana": block_reading,
"hira": Transliterator.kata_to_hira(block_reading),
"hepburn": katakana_to_hepburn(block_reading, use_macron)
})
return result
```
## 並行処理・スレッドセーフティ
### ロック機構
```python
class ThreadSafeUsage:
"""スレッドセーフな使用例"""
def __init__(self):
self.transliterator = Transliterator()
def process_texts_concurrently(self, texts):
"""複数テキストの並行処理"""
import concurrent.futures
def process_single(text):
return self.transliterator.analyze(text)
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
# 内部のロック機構により安全に並行実行
futures = [executor.submit(process_single, text) for text in texts]
results = [f.result() for f in futures]
return results
# 使用例
processor = ThreadSafeUsage()
texts = ["東京に行く", "大阪で食事", "名古屋を観光", "福岡に宿泊"]
results = processor.process_texts_concurrently(texts)
for i, result in enumerate(results):
print(f"テキスト{i+1}: {texts[i]}")
for token in result:
print(f" {token['orig']} -> {token['hepburn']}")
```
### パフォーマンス考慮事項
```python
# 大量テキスト処理のベストプラクティス
def efficient_batch_processing(texts, batch_size=100):
"""効率的なバッチ処理"""
transliterator = Transliterator()
results = []
for i in range(0, len(texts), batch_size):
batch = texts[i:i + batch_size]
batch_results = []
for text in batch:
# 各テキストを個別に処理(ロック制御あり)
result = transliterator.analyze(text)
batch_results.append(result)
results.extend(batch_results)
# バッチ間で少し休憩(メモリ管理)
if len(results) % 1000 == 0:
print(f"処理済み: {len(results)} テキスト")
return results
```
## エラーハンドリング
### 例外処理
```python
def safe_analyze(text):
"""安全な解析処理"""
transliterator = Transliterator()
try:
results = transliterator.analyze(text)
return results, None
except RuntimeError as e:
if "Already borrowed" in str(e):
# SudachiPyの並行アクセスエラー
print("並行アクセスエラーが発生しました。リトライします。")
return None, "RETRY_NEEDED"
else:
print(f"実行時エラー: {e}")
return None, "RUNTIME_ERROR"
except Exception as e:
print(f"予期しないエラー: {e}")
return None, "UNKNOWN_ERROR"
# 使用例(リトライ機構付き)
def analyze_with_retry(text, max_retries=3):
"""リトライ機構付き解析"""
for attempt in range(max_retries):
results, error = safe_analyze(text)
if results is not None:
return results
if error == "RETRY_NEEDED":
print(f"リトライ {attempt + 1}/{max_retries}")
import time
time.sleep(0.1 * (attempt + 1)) # 指数バックオフ
continue
else:
break
# 全てのリトライが失敗した場合のフォールバック
print("解析に失敗しました。フォールバック処理を実行します。")
return [{"orig": text, "kana": text, "hira": text, "hepburn": text}]
```
## 設定・カスタマイズ
### SudachiPy設定
```python
# カスタムSudachiPy設定での初期化
class CustomTransliterator(Transliterator):
def __init__(self, dict_type="full", split_mode="C"):
"""カスタム設定での初期化"""
# 辞書タイプの選択
dict_types = {
"small": dictionary.Dictionary.create(dict_type="small"),
"core": dictionary.Dictionary.create(dict_type="core"),
"full": dictionary.Dictionary.create(dict_type="full")
}
self.tokenizer_obj = dict_types.get(dict_type, dict_types["full"])
# 分割モードの選択
split_modes = {
"A": tokenizer.Tokenizer.SplitMode.A, # 短い単位
"B": tokenizer.Tokenizer.SplitMode.B, # 中間単位
"C": tokenizer.Tokenizer.SplitMode.C # 長い単位(デフォルト)
}
self.mode = split_modes.get(split_mode, split_modes["C"])
self._tokenizer_lock = threading.Lock()
# 使用例
# 短い単位での分割を使用
small_unit_transliterator = CustomTransliterator(dict_type="core", split_mode="A")
text = "取り敢えず検索してみる"
results = small_unit_transliterator.analyze(text)
for token in results:
print(f"{token['orig']} -> {token['hepburn']}")
```
## テスト・デバッグ
### 包括的テストセット
```python
def run_comprehensive_tests():
"""包括的な機能テスト"""
transliterator = Transliterator()
test_cases = [
# 基本的な文章
("向こうへ行く", "向こう", "ムコウ"),
("美しい花", "美しい", "ウツクシイ"),
# 文脈依存
("何度も", "", "ナン"),
("何が", "", "ナニ"),
# 外来語
("パーティー", "パーティー", "パーティー"),
("コンピューター", "コンピューター", "コンピューター"),
# 漢字・送り仮名
("取り敢えず", "取り", "トリ"),
("見知らぬ", "見知ら", "ミシラ"),
# 記号・英数字
("ID12345", "ID", "ID"),
("SessionIDを取得", "SessionID", "SessionID")
]
for text, target_orig, expected_kana in test_cases:
results = transliterator.analyze(text)
# 対象トークンを検索
target_token = None
for token in results:
if token['orig'] == target_orig:
target_token = token
break
if target_token:
actual_kana = target_token['kana']
status = "" if actual_kana == expected_kana else ""
print(f"{status} {text}: {target_orig} -> {actual_kana} (期待値: {expected_kana})")
else:
print(f"{text}: トークン '{target_orig}' が見つかりません")
run_comprehensive_tests()
```
## 依存関係
### 必須依存関係
- `sudachipy`: 形態素解析エンジン
- `threading`: 並行制御
- `typing`: 型ヒント
### 内部モジュール依存
- `transliteration_kana_to_hepburn`: ヘボン式変換
- `transliteration_context_rules`: 文脈依存ルール
### システム要件
- Python 3.7以上
- SudachiPy辞書ファイル自動ダウンロード
- 十分なメモリ(辞書読み込み用)
## 注意事項・制限
### 処理精度の制限
- 形態素解析結果に依存
- 未知語・固有名詞は読み推定
- 文脈によっては不正確な分割
### パフォーマンス制限
- 初回実行時の辞書読み込み時間
- 大量テキスト処理時のメモリ使用量
- 並行アクセス時のロック待機
### 出力形式の制限
```python
# 現在サポートしていない機能
unsupported_features = [
"アクセント記号(音調)",
"方言・古語の特殊読み",
"人名・地名の特殊読み",
"外国語の音写(中国語・韓国語等)",
"カスタム読み辞書",
"品詞情報の出力"
]
```
## 関連モジュール
- `transliteration_kana_to_hepburn.py`: ヘボン式変換処理
- `transliteration_context_rules.py`: 文脈依存ルール適用
- `config.py`: システム設定管理
- `utils.py`: ユーティリティ関数
## 将来の改善点
- カスタム読み辞書対応
- より高精度な文脈解析
- 他言語音写システムとの統合
- リアルタイム処理最適化
- 分散処理対応