|
2 | 2 | from typing import Union |
3 | 3 | from chatterbot.storage import StorageAdapter |
4 | 4 | from chatterbot.logic import LogicAdapter |
5 | | -from chatterbot.search import TextSearch, IndexedTextSearch |
| 5 | +from chatterbot.search import TextSearch, IndexedTextSearch, SemanticVectorSearch |
6 | 6 | from chatterbot.tagging import PosLemmaTagger |
7 | 7 | from chatterbot.conversation import Statement |
8 | 8 | from chatterbot import languages |
@@ -74,41 +74,60 @@ def __init__(self, name, stream=False, **kwargs): |
74 | 74 |
|
75 | 75 | tagger_language = kwargs.get('tagger_language', languages.ENG) |
76 | 76 |
|
77 | | - try: |
78 | | - Tagger = kwargs.get('tagger', PosLemmaTagger) |
79 | | - |
80 | | - # Allow instances to be provided for performance optimization |
81 | | - # (Example: a pre-loaded model in a tagger when unit testing) |
82 | | - if not isinstance(Tagger, type): |
83 | | - self.tagger = Tagger |
84 | | - else: |
85 | | - self.tagger = Tagger(language=tagger_language) |
86 | | - except IOError as io_error: |
87 | | - # Return a more helpful error message if possible |
88 | | - if "Can't find model" in str(io_error): |
89 | | - model_name = utils.get_model_for_language(tagger_language) |
90 | | - if hasattr(tagger_language, 'ENGLISH_NAME'): |
91 | | - language_name = tagger_language.ENGLISH_NAME |
| 77 | + # Check if storage adapter has a preferred tagger |
| 78 | + PreferredTagger = self.storage.get_preferred_tagger() |
| 79 | + |
| 80 | + if PreferredTagger is not None: |
| 81 | + # Storage adapter specifies its own tagger |
| 82 | + self.tagger = PreferredTagger(language=tagger_language) |
| 83 | + else: |
| 84 | + # Use default or user-specified tagger |
| 85 | + try: |
| 86 | + Tagger = kwargs.get('tagger', PosLemmaTagger) |
| 87 | + |
| 88 | + # Allow instances to be provided for performance optimization |
| 89 | + # (Example: a pre-loaded model in a tagger when unit testing) |
| 90 | + if not isinstance(Tagger, type): |
| 91 | + self.tagger = Tagger |
92 | 92 | else: |
93 | | - language_name = tagger_language |
94 | | - raise self.ChatBotException( |
95 | | - 'Setup error:\n' |
96 | | - f'The Spacy model for "{language_name}" language is missing.\n' |
97 | | - 'Please install the model using the command:\n\n' |
98 | | - f'python -m spacy download {model_name}\n\n' |
99 | | - 'See https://spacy.io/usage/models for more information about available models.' |
100 | | - ) from io_error |
101 | | - else: |
102 | | - raise io_error |
| 93 | + self.tagger = Tagger(language=tagger_language) |
| 94 | + except IOError as io_error: |
| 95 | + # Return a more helpful error message if possible |
| 96 | + if "Can't find model" in str(io_error): |
| 97 | + model_name = utils.get_model_for_language(tagger_language) |
| 98 | + if hasattr(tagger_language, 'ENGLISH_NAME'): |
| 99 | + language_name = tagger_language.ENGLISH_NAME |
| 100 | + else: |
| 101 | + language_name = tagger_language |
| 102 | + raise self.ChatBotException( |
| 103 | + 'Setup error:\n' |
| 104 | + f'The Spacy model for "{language_name}" language is missing.\n' |
| 105 | + 'Please install the model using the command:\n\n' |
| 106 | + f'python -m spacy download {model_name}\n\n' |
| 107 | + 'See https://spacy.io/usage/models for more information about available models.' |
| 108 | + ) from io_error |
| 109 | + else: |
| 110 | + raise io_error |
103 | 111 |
|
| 112 | + # Initialize search algorithms |
104 | 113 | primary_search_algorithm = IndexedTextSearch(self, **kwargs) |
105 | 114 | text_search_algorithm = TextSearch(self, **kwargs) |
| 115 | + semantic_vector_search_algorithm = SemanticVectorSearch(self, **kwargs) |
106 | 116 |
|
107 | 117 | self.search_algorithms = { |
108 | 118 | primary_search_algorithm.name: primary_search_algorithm, |
109 | | - text_search_algorithm.name: text_search_algorithm |
| 119 | + text_search_algorithm.name: text_search_algorithm, |
| 120 | + semantic_vector_search_algorithm.name: semantic_vector_search_algorithm |
110 | 121 | } |
111 | 122 |
|
| 123 | + # Check if storage adapter has a preferred search algorithm |
| 124 | + preferred_search_algorithm = self.storage.get_preferred_search_algorithm() |
| 125 | + if preferred_search_algorithm and preferred_search_algorithm in self.search_algorithms: |
| 126 | + # Set as default for logic adapters that don't specify their own search algorithm |
| 127 | + # This ensures BestMatch and other adapters use the optimal search method |
| 128 | + self.logger.info(f'Storage adapter prefers search algorithm: {preferred_search_algorithm}') |
| 129 | + kwargs.setdefault('search_algorithm_name', preferred_search_algorithm) |
| 130 | + |
112 | 131 | for adapter in logic_adapters: |
113 | 132 | utils.validate_adapter_class(adapter, LogicAdapter) |
114 | 133 | logic_adapter = utils.initialize_class(adapter, self, **kwargs) |
@@ -191,15 +210,22 @@ def get_response(self, statement: Union[Statement, str, dict] = None, **kwargs) |
191 | 210 | input_statement.in_response_to = previous_statement.text |
192 | 211 |
|
193 | 212 | # Make sure the input statement has its search text saved |
194 | | - |
195 | | - if not input_statement.search_text: |
196 | | - _search_text = self.tagger.get_text_index_string(input_statement.text) |
197 | | - input_statement.search_text = _search_text |
198 | | - |
199 | | - if not input_statement.search_in_response_to and input_statement.in_response_to: |
200 | | - input_statement.search_in_response_to = self.tagger.get_text_index_string( |
201 | | - input_statement.in_response_to |
202 | | - ) |
| 213 | + if not self.tagger.needs_text_indexing(): |
| 214 | + # Tagger doesn't transform text, use it directly |
| 215 | + if not input_statement.search_text: |
| 216 | + input_statement.search_text = input_statement.text |
| 217 | + if not input_statement.search_in_response_to and input_statement.in_response_to: |
| 218 | + input_statement.search_in_response_to = input_statement.in_response_to |
| 219 | + else: |
| 220 | + # Use tagger for text indexing or transformations |
| 221 | + if not input_statement.search_text: |
| 222 | + _search_text = self.tagger.get_text_index_string(input_statement.text) |
| 223 | + input_statement.search_text = _search_text |
| 224 | + |
| 225 | + if not input_statement.search_in_response_to and input_statement.in_response_to: |
| 226 | + input_statement.search_in_response_to = self.tagger.get_text_index_string( |
| 227 | + input_statement.in_response_to |
| 228 | + ) |
203 | 229 |
|
204 | 230 | response = self.generate_response( |
205 | 231 | input_statement, |
|
0 commit comments