File size: 3,354 Bytes
0447f30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
"""
ModelAdapter - マルチモデル対応アダプター
新しいAIインターフェース(BaseAI)に対応
"""
from typing import Any, Dict, List, Optional
from .word_processor import WordDeterminer, WordPiece
from .ai.base import BaseAI


class ModelAdapter:
    """
    マルチモデル対応アダプター
    - 初期化コストの高いコンポーネント(WordDeterminer, AIモデル)を1回だけ生成して保持
    - メソッドでビルド処理を提供
    - 返却はシリアライズしやすい dict/list 形式
    """
    
    def __init__(self, ai_model: BaseAI):
        """
        初期化
        
        Args:
            ai_model: BaseAIを実装したモデルインスタンス
        """
        # WordDeterminer(内部で Sudachi C モードの WordCounter を使用)
        self.determiner = WordDeterminer()
        
        # AIモデルを保持
        self.model = ai_model
    
    def _clean_text(self, text: str) -> str:
        """制御文字・不可視文字・置換文字を厳密に取り除く(最終出力用)"""
        if not text:
            return ""
        
        # 制御文字(0x00-0x1F、0x7F-0x9F)を除去
        # ただし、改行・タブ・復帰は許可
        cleaned = []
        for ch in text:
            code = ord(ch)
            # 許可する制御文字: 改行(0x0A), タブ(0x09), 復帰(0x0D)
            if code in [0x09, 0x0A, 0x0D]:
                cleaned.append(ch)
            # 通常の印刷可能文字
            elif ch.isprintable():
                # 置換文字(U+FFFD)を除去
                if ch != "\uFFFD":
                    cleaned.append(ch)
            # その他の制御文字や不可視文字は除去
        
        result = "".join(cleaned)
        # ゼロ幅文字を除去
        result = result.replace("\u200B", "")  # Zero-width space
        result = result.replace("\u200C", "")  # Zero-width non-joiner
        result = result.replace("\u200D", "")  # Zero-width joiner
        result = result.replace("\uFEFF", "")  # Zero-width no-break space
        return result.strip()

    def build_word_tree(
        self, 
        prompt_text: str, 
        root_text: str = "", 
        top_k: int = 5, 
        max_depth: int = 10
    ) -> List[Dict[str, Any]]:
        """
        単語ツリーを構築して、完成ピースを dict の配列で返す。
        各要素: { text: str, probability: float }
        """
        pieces: List[WordPiece] = self.determiner.build_word_tree(
            prompt_text=prompt_text,
            root_text=root_text,
            model=self.model,
            top_k=top_k,
            max_depth=max_depth,
        )
        return [
            {"text": self._clean_text(p.get_full_word()), "probability": float(p.probability)}
            for p in pieces
        ]

    def build_chat_prompt(
        self, 
        user_content: str, 
        system_content: str = "あなたは親切で役に立つAIアシスタントです。"
    ) -> str:
        """チャットプロンプト文字列を返す。"""
        return self.model.build_chat_prompt(user_content, system_content)

    def count_words(self, text: str) -> int:
        """Sudachi(C) ベースでの語数カウント。"""
        return self.determiner._count_words(text)