ChatterBot 1.2.8__tar.gz → 1.2.10__tar.gz
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.
- {chatterbot-1.2.8 → chatterbot-1.2.10}/ChatterBot.egg-info/PKG-INFO +17 -13
- {chatterbot-1.2.8 → chatterbot-1.2.10}/ChatterBot.egg-info/requires.txt +3 -3
- {chatterbot-1.2.8 → chatterbot-1.2.10}/PKG-INFO +17 -13
- {chatterbot-1.2.8 → chatterbot-1.2.10}/README.md +14 -10
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/__init__.py +1 -1
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/chatterbot.py +62 -36
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/components.py +3 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/logic/specific_response.py +13 -3
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/parsing.py +25 -15
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/search.py +70 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/storage/redis.py +120 -40
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/storage/sql_storage.py +24 -2
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/storage/storage_adapter.py +81 -0
- chatterbot-1.2.10/chatterbot/tagging.py +182 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/trainers.py +116 -49
- {chatterbot-1.2.8 → chatterbot-1.2.10}/pyproject.toml +3 -3
- {chatterbot-1.2.8 → chatterbot-1.2.10}/tests/test_chatbot.py +5 -4
- {chatterbot-1.2.8 → chatterbot-1.2.10}/tests/test_parsing.py +197 -0
- chatterbot-1.2.8/chatterbot/tagging.py +0 -77
- {chatterbot-1.2.8 → chatterbot-1.2.10}/ChatterBot.egg-info/SOURCES.txt +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/ChatterBot.egg-info/dependency_links.txt +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/ChatterBot.egg-info/top_level.txt +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/LICENSE +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/__main__.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/adapters.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/comparisons.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/constants.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/conversation.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/corpus.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/exceptions.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/__init__.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/__init__.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/abstract_models.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/admin.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/apps.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/migrations/0001_initial.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/migrations/0002_statement_extra_data.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/migrations/0003_change_occurrence_default.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/migrations/0004_rename_in_response_to.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/migrations/0005_statement_created_at.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/migrations/0006_create_conversation.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/migrations/0007_response_created_at.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/migrations/0008_update_conversations.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/migrations/0009_tags.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/migrations/0010_statement_text.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/migrations/0011_blank_extra_data.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/migrations/0012_statement_created_at.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/migrations/0013_change_conversations.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/migrations/0014_remove_statement_extra_data.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/migrations/0015_statement_persona.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/migrations/0016_statement_stemmed_text.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/migrations/0017_tags_unique.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/migrations/0018_text_max_length.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/migrations/0019_alter_statement_id_alter_tag_id_and_more.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/migrations/0020_alter_statement_conversation_and_more.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/migrations/__init__.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/model_admin.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/models.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/django_chatterbot/settings.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/sqlalchemy_app/__init__.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/ext/sqlalchemy_app/models.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/filters.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/languages.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/llm.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/logic/__init__.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/logic/best_match.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/logic/logic_adapter.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/logic/mathematical_evaluation.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/logic/time_adapter.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/logic/unit_conversion.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/preprocessors.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/response_selection.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/storage/__init__.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/storage/django_storage.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/storage/mongodb.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/utils.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/chatterbot/vectorstores.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/setup.cfg +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/tests/test_adapter_validation.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/tests/test_benchmarks.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/tests/test_cli.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/tests/test_comparisons.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/tests/test_conversations.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/tests/test_corpus.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/tests/test_examples.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/tests/test_filters.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/tests/test_initialization.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/tests/test_languages.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/tests/test_preprocessors.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/tests/test_response_selection.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/tests/test_search.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/tests/test_tagging.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/tests/test_turing.py +0 -0
- {chatterbot-1.2.8 → chatterbot-1.2.10}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ChatterBot
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.10
|
|
4
4
|
Summary: ChatterBot is a machine learning, conversational dialog engine
|
|
5
5
|
Author: Gunther Cox
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -47,16 +47,16 @@ Provides-Extra: dev
|
|
|
47
47
|
Requires-Dist: pint>=0.8.1; extra == "dev"
|
|
48
48
|
Requires-Dist: pyyaml<7.0,>=6.0; extra == "dev"
|
|
49
49
|
Requires-Dist: chatterbot-corpus<1.3.0,>=1.2.2; extra == "dev"
|
|
50
|
-
Requires-Dist: ollama<1.0,>=0.
|
|
50
|
+
Requires-Dist: ollama<1.0,>=0.6.0; extra == "dev"
|
|
51
51
|
Requires-Dist: openai; extra == "dev"
|
|
52
52
|
Provides-Extra: redis
|
|
53
|
-
Requires-Dist: redis[hiredis]<
|
|
53
|
+
Requires-Dist: redis[hiredis]<7.0; extra == "redis"
|
|
54
54
|
Requires-Dist: langchain-redis<=0.2.5; extra == "redis"
|
|
55
55
|
Requires-Dist: langchain-huggingface<=0.1.2; extra == "redis"
|
|
56
56
|
Requires-Dist: accelerate<=1.6.0; extra == "redis"
|
|
57
57
|
Requires-Dist: sentence-transformers<=4.0.2; extra == "redis"
|
|
58
58
|
Provides-Extra: mongodb
|
|
59
|
-
Requires-Dist: pymongo<4.
|
|
59
|
+
Requires-Dist: pymongo<4.16,>=4.11; extra == "mongodb"
|
|
60
60
|
Dynamic: license-file
|
|
61
61
|
|
|
62
62
|

|
|
@@ -153,16 +153,20 @@ section of the documentation.
|
|
|
153
153
|
|
|
154
154
|
See release notes for changes https://github.com/gunthercox/ChatterBot/releases
|
|
155
155
|
|
|
156
|
-
#
|
|
156
|
+
# Contributing
|
|
157
157
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
158
|
+
Contributions are welcomed, to help ensure a smooth process please start with the contributing guidelines in our documentation:
|
|
159
|
+
https://docs.chatterbot.us/contributing/
|
|
160
|
+
|
|
161
|
+
# Sponsors
|
|
162
|
+
|
|
163
|
+
ChatterBot is sponsored by:
|
|
164
|
+
|
|
165
|
+
<p style="font-size:21px; color:black;">Browser testing via
|
|
166
|
+
<a href="https://www.lambdatest.com/?utm_source=chatterbot&utm_medium=sponsor" target="_blank">
|
|
167
|
+
<img src="https://www.lambdatest.com/blue-logo.png" style="vertical-align: middle;" width="250" height="45" />
|
|
168
|
+
</a>
|
|
169
|
+
</p>
|
|
166
170
|
|
|
167
171
|
# License
|
|
168
172
|
|
|
@@ -8,14 +8,14 @@ tqdm
|
|
|
8
8
|
pint>=0.8.1
|
|
9
9
|
pyyaml<7.0,>=6.0
|
|
10
10
|
chatterbot-corpus<1.3.0,>=1.2.2
|
|
11
|
-
ollama<1.0,>=0.
|
|
11
|
+
ollama<1.0,>=0.6.0
|
|
12
12
|
openai
|
|
13
13
|
|
|
14
14
|
[mongodb]
|
|
15
|
-
pymongo<4.
|
|
15
|
+
pymongo<4.16,>=4.11
|
|
16
16
|
|
|
17
17
|
[redis]
|
|
18
|
-
redis[hiredis]<
|
|
18
|
+
redis[hiredis]<7.0
|
|
19
19
|
langchain-redis<=0.2.5
|
|
20
20
|
langchain-huggingface<=0.1.2
|
|
21
21
|
accelerate<=1.6.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ChatterBot
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.10
|
|
4
4
|
Summary: ChatterBot is a machine learning, conversational dialog engine
|
|
5
5
|
Author: Gunther Cox
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -47,16 +47,16 @@ Provides-Extra: dev
|
|
|
47
47
|
Requires-Dist: pint>=0.8.1; extra == "dev"
|
|
48
48
|
Requires-Dist: pyyaml<7.0,>=6.0; extra == "dev"
|
|
49
49
|
Requires-Dist: chatterbot-corpus<1.3.0,>=1.2.2; extra == "dev"
|
|
50
|
-
Requires-Dist: ollama<1.0,>=0.
|
|
50
|
+
Requires-Dist: ollama<1.0,>=0.6.0; extra == "dev"
|
|
51
51
|
Requires-Dist: openai; extra == "dev"
|
|
52
52
|
Provides-Extra: redis
|
|
53
|
-
Requires-Dist: redis[hiredis]<
|
|
53
|
+
Requires-Dist: redis[hiredis]<7.0; extra == "redis"
|
|
54
54
|
Requires-Dist: langchain-redis<=0.2.5; extra == "redis"
|
|
55
55
|
Requires-Dist: langchain-huggingface<=0.1.2; extra == "redis"
|
|
56
56
|
Requires-Dist: accelerate<=1.6.0; extra == "redis"
|
|
57
57
|
Requires-Dist: sentence-transformers<=4.0.2; extra == "redis"
|
|
58
58
|
Provides-Extra: mongodb
|
|
59
|
-
Requires-Dist: pymongo<4.
|
|
59
|
+
Requires-Dist: pymongo<4.16,>=4.11; extra == "mongodb"
|
|
60
60
|
Dynamic: license-file
|
|
61
61
|
|
|
62
62
|

|
|
@@ -153,16 +153,20 @@ section of the documentation.
|
|
|
153
153
|
|
|
154
154
|
See release notes for changes https://github.com/gunthercox/ChatterBot/releases
|
|
155
155
|
|
|
156
|
-
#
|
|
156
|
+
# Contributing
|
|
157
157
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
158
|
+
Contributions are welcomed, to help ensure a smooth process please start with the contributing guidelines in our documentation:
|
|
159
|
+
https://docs.chatterbot.us/contributing/
|
|
160
|
+
|
|
161
|
+
# Sponsors
|
|
162
|
+
|
|
163
|
+
ChatterBot is sponsored by:
|
|
164
|
+
|
|
165
|
+
<p style="font-size:21px; color:black;">Browser testing via
|
|
166
|
+
<a href="https://www.lambdatest.com/?utm_source=chatterbot&utm_medium=sponsor" target="_blank">
|
|
167
|
+
<img src="https://www.lambdatest.com/blue-logo.png" style="vertical-align: middle;" width="250" height="45" />
|
|
168
|
+
</a>
|
|
169
|
+
</p>
|
|
166
170
|
|
|
167
171
|
# License
|
|
168
172
|
|
|
@@ -92,16 +92,20 @@ section of the documentation.
|
|
|
92
92
|
|
|
93
93
|
See release notes for changes https://github.com/gunthercox/ChatterBot/releases
|
|
94
94
|
|
|
95
|
-
#
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
95
|
+
# Contributing
|
|
96
|
+
|
|
97
|
+
Contributions are welcomed, to help ensure a smooth process please start with the contributing guidelines in our documentation:
|
|
98
|
+
https://docs.chatterbot.us/contributing/
|
|
99
|
+
|
|
100
|
+
# Sponsors
|
|
101
|
+
|
|
102
|
+
ChatterBot is sponsored by:
|
|
103
|
+
|
|
104
|
+
<p style="font-size:21px; color:black;">Browser testing via
|
|
105
|
+
<a href="https://www.lambdatest.com/?utm_source=chatterbot&utm_medium=sponsor" target="_blank">
|
|
106
|
+
<img src="https://www.lambdatest.com/blue-logo.png" style="vertical-align: middle;" width="250" height="45" />
|
|
107
|
+
</a>
|
|
108
|
+
</p>
|
|
105
109
|
|
|
106
110
|
# License
|
|
107
111
|
|
|
@@ -2,7 +2,7 @@ import logging
|
|
|
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 @@ class ChatBot(object):
|
|
|
74
74
|
|
|
75
75
|
tagger_language = kwargs.get('tagger_language', languages.ENG)
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
#
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
if
|
|
91
|
-
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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 @@ class ChatBot(object):
|
|
|
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
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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,
|
|
@@ -29,6 +29,9 @@ def chatterbot_bigram_indexer(document):
|
|
|
29
29
|
token for token in document if not (token.is_punct)
|
|
30
30
|
]
|
|
31
31
|
|
|
32
|
+
# Pairs consist of the part-of-speech of the first token and the
|
|
33
|
+
# lemma of the second token in the bigram. This provides a good
|
|
34
|
+
# balance of generalization and specificity for matching.
|
|
32
35
|
bigram_pairs = [
|
|
33
36
|
f"{tokens[i - 1].pos_}:{tokens[i].lemma_.lower()}"
|
|
34
37
|
for i in range(1, len(tokens))
|
|
@@ -20,7 +20,19 @@ class SpecificResponseAdapter(LogicAdapter):
|
|
|
20
20
|
def __init__(self, chatbot, **kwargs):
|
|
21
21
|
super().__init__(chatbot, **kwargs)
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
try:
|
|
24
|
+
self.input_text = kwargs['input_text']
|
|
25
|
+
except KeyError:
|
|
26
|
+
raise chatbot.ChatBotException(
|
|
27
|
+
'The SpecificResponseAdapter requires an input_text parameter.'
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
try:
|
|
31
|
+
self._output_text = kwargs['output_text']
|
|
32
|
+
except KeyError:
|
|
33
|
+
raise chatbot.ChatBotException(
|
|
34
|
+
'The SpecificResponseAdapter requires an output_text parameter.'
|
|
35
|
+
)
|
|
24
36
|
|
|
25
37
|
self.matcher = None
|
|
26
38
|
|
|
@@ -33,8 +45,6 @@ class SpecificResponseAdapter(LogicAdapter):
|
|
|
33
45
|
|
|
34
46
|
self.matcher.add('SpecificResponse', [self.input_text])
|
|
35
47
|
|
|
36
|
-
self._output_text = kwargs.get('output_text')
|
|
37
|
-
|
|
38
48
|
def _initialize_nlp(self, language):
|
|
39
49
|
model = get_model_for_language(language)
|
|
40
50
|
|
|
@@ -503,7 +503,7 @@ regex = [
|
|
|
503
503
|
]
|
|
504
504
|
|
|
505
505
|
|
|
506
|
-
def convert_string_to_number(value):
|
|
506
|
+
def convert_string_to_number(value: str) -> int:
|
|
507
507
|
"""
|
|
508
508
|
Convert strings to numbers
|
|
509
509
|
"""
|
|
@@ -517,7 +517,7 @@ def convert_string_to_number(value):
|
|
|
517
517
|
return sum(num_list)
|
|
518
518
|
|
|
519
519
|
|
|
520
|
-
def convert_time_to_hour_minute(hour, minute, convention):
|
|
520
|
+
def convert_time_to_hour_minute(hour: str, minute: str, convention: str) -> dict:
|
|
521
521
|
"""
|
|
522
522
|
Convert time to hour, minute
|
|
523
523
|
"""
|
|
@@ -532,12 +532,19 @@ def convert_time_to_hour_minute(hour, minute, convention):
|
|
|
532
532
|
minute = int(minute)
|
|
533
533
|
|
|
534
534
|
if convention.lower() == 'pm':
|
|
535
|
-
|
|
535
|
+
# Handle 12 PM (noon) - it stays as 12
|
|
536
|
+
# Handle 1-11 PM - add 12
|
|
537
|
+
if hour != 12:
|
|
538
|
+
hour += 12
|
|
539
|
+
else:
|
|
540
|
+
# Handle 12 AM (midnight) - convert to 0
|
|
541
|
+
if hour == 12:
|
|
542
|
+
hour = 0
|
|
536
543
|
|
|
537
544
|
return {'hours': hour, 'minutes': minute}
|
|
538
545
|
|
|
539
546
|
|
|
540
|
-
def date_from_quarter(base_date, ordinal, year):
|
|
547
|
+
def date_from_quarter(base_date: datetime, ordinal: int, year: int) -> list[datetime]:
|
|
541
548
|
"""
|
|
542
549
|
Extract date from quarter of a year
|
|
543
550
|
"""
|
|
@@ -554,7 +561,7 @@ def date_from_quarter(base_date, ordinal, year):
|
|
|
554
561
|
]
|
|
555
562
|
|
|
556
563
|
|
|
557
|
-
def date_from_relative_day(base_date, time, dow):
|
|
564
|
+
def date_from_relative_day(base_date: datetime, time: str, dow: str) -> datetime:
|
|
558
565
|
"""
|
|
559
566
|
Converts relative day to time
|
|
560
567
|
Ex: this tuesday, last tuesday
|
|
@@ -577,7 +584,7 @@ def date_from_relative_day(base_date, time, dow):
|
|
|
577
584
|
return next_week_day(base_date, num)
|
|
578
585
|
|
|
579
586
|
|
|
580
|
-
def date_from_relative_week_year(base_date, time, dow, ordinal=1):
|
|
587
|
+
def date_from_relative_week_year(base_date: datetime, time: str, dow: str, ordinal: int = 1) -> datetime:
|
|
581
588
|
"""
|
|
582
589
|
Converts relative day to time
|
|
583
590
|
Eg. this tuesday, last tuesday
|
|
@@ -608,7 +615,10 @@ def date_from_relative_week_year(base_date, time, dow, ordinal=1):
|
|
|
608
615
|
day = min(relative_date.day, calendar.monthrange(year, month)[1])
|
|
609
616
|
return datetime(year, month, day)
|
|
610
617
|
else:
|
|
611
|
-
|
|
618
|
+
# Base the day to valid range on the target month
|
|
619
|
+
target_month = relative_date.month + ord
|
|
620
|
+
day = min(relative_date.day, calendar.monthrange(relative_date.year, target_month)[1])
|
|
621
|
+
return datetime(relative_date.year, target_month, day)
|
|
612
622
|
elif time == 'end of the':
|
|
613
623
|
return datetime(
|
|
614
624
|
relative_date.year,
|
|
@@ -636,7 +646,7 @@ def date_from_relative_week_year(base_date, time, dow, ordinal=1):
|
|
|
636
646
|
return datetime(relative_date.year, relative_date.month, relative_date.day, 23, 59, 59)
|
|
637
647
|
|
|
638
648
|
|
|
639
|
-
def date_from_adverb(base_date, name):
|
|
649
|
+
def date_from_adverb(base_date: datetime, name: str) -> datetime:
|
|
640
650
|
"""
|
|
641
651
|
Convert Day adverbs to dates
|
|
642
652
|
Tomorrow => Date
|
|
@@ -645,14 +655,14 @@ def date_from_adverb(base_date, name):
|
|
|
645
655
|
# Reset date to start of the day
|
|
646
656
|
adverb_date = datetime(base_date.year, base_date.month, base_date.day)
|
|
647
657
|
if name == 'today' or name == 'tonite' or name == 'tonight':
|
|
648
|
-
return adverb_date
|
|
658
|
+
return adverb_date
|
|
649
659
|
elif name == 'yesterday':
|
|
650
660
|
return adverb_date - timedelta(days=1)
|
|
651
661
|
elif name == 'tomorrow' or name == 'tom':
|
|
652
662
|
return adverb_date + timedelta(days=1)
|
|
653
663
|
|
|
654
664
|
|
|
655
|
-
def date_from_duration(base_date, number_as_string, unit, duration, base_time=None):
|
|
665
|
+
def date_from_duration(base_date: datetime, number_as_string: str, unit: str, duration: str, base_time: str = None) -> datetime:
|
|
656
666
|
"""
|
|
657
667
|
Find dates from duration
|
|
658
668
|
Eg: 20 days from now
|
|
@@ -682,7 +692,7 @@ def date_from_duration(base_date, number_as_string, unit, duration, base_time=No
|
|
|
682
692
|
return base_date + timedelta(**args)
|
|
683
693
|
|
|
684
694
|
|
|
685
|
-
def this_week_day(base_date, weekday):
|
|
695
|
+
def this_week_day(base_date: datetime, weekday: int) -> datetime:
|
|
686
696
|
"""
|
|
687
697
|
Finds coming weekday
|
|
688
698
|
"""
|
|
@@ -698,7 +708,7 @@ def this_week_day(base_date, weekday):
|
|
|
698
708
|
return day
|
|
699
709
|
|
|
700
710
|
|
|
701
|
-
def previous_week_day(base_date, weekday):
|
|
711
|
+
def previous_week_day(base_date: datetime, weekday: int) -> datetime:
|
|
702
712
|
"""
|
|
703
713
|
Finds previous weekday
|
|
704
714
|
"""
|
|
@@ -708,9 +718,9 @@ def previous_week_day(base_date, weekday):
|
|
|
708
718
|
return day
|
|
709
719
|
|
|
710
720
|
|
|
711
|
-
def next_week_day(base_date, weekday):
|
|
721
|
+
def next_week_day(base_date: datetime, weekday: int) -> datetime:
|
|
712
722
|
"""
|
|
713
|
-
Finds next weekday
|
|
723
|
+
Finds the next weekday.
|
|
714
724
|
"""
|
|
715
725
|
day_of_week = base_date.weekday()
|
|
716
726
|
end_of_this_week = base_date + timedelta(days=6 - day_of_week)
|
|
@@ -720,7 +730,7 @@ def next_week_day(base_date, weekday):
|
|
|
720
730
|
return day
|
|
721
731
|
|
|
722
732
|
|
|
723
|
-
def datetime_parsing(text, base_date=datetime.now()):
|
|
733
|
+
def datetime_parsing(text: str, base_date: datetime = datetime.now()) -> list[tuple[str, datetime, tuple[int, int]]]:
|
|
724
734
|
"""
|
|
725
735
|
Extract datetime objects from a string of text.
|
|
726
736
|
"""
|
|
@@ -157,3 +157,73 @@ class TextSearch:
|
|
|
157
157
|
if confidence >= 1.0:
|
|
158
158
|
self.chatbot.logger.info('Exact match found, stopping search')
|
|
159
159
|
break
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
class SemanticVectorSearch:
|
|
163
|
+
"""
|
|
164
|
+
Semantic vector search for storage adapters that use vector embeddings.
|
|
165
|
+
Does not require a tagger or comparison function - relies on the storage
|
|
166
|
+
adapter's native vector similarity search capabilities.
|
|
167
|
+
|
|
168
|
+
:param search_page_size:
|
|
169
|
+
The maximum number of records to load into memory at a time when searching.
|
|
170
|
+
Defaults to 1000
|
|
171
|
+
"""
|
|
172
|
+
|
|
173
|
+
name = 'semantic_vector_search'
|
|
174
|
+
|
|
175
|
+
def __init__(self, chatbot, **kwargs):
|
|
176
|
+
self.chatbot = chatbot
|
|
177
|
+
|
|
178
|
+
self.search_page_size = kwargs.get(
|
|
179
|
+
'search_page_size', 1000
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
def search(self, input_statement, **additional_parameters):
|
|
183
|
+
"""
|
|
184
|
+
Search for semantically similar statements using vector similarity.
|
|
185
|
+
Confidence scores are calculated by the storage adapter based on
|
|
186
|
+
vector distances and returned in the results.
|
|
187
|
+
|
|
188
|
+
:param input_statement: A statement.
|
|
189
|
+
:type input_statement: chatterbot.conversation.Statement
|
|
190
|
+
|
|
191
|
+
:param **additional_parameters: Additional parameters to be passed
|
|
192
|
+
to the ``filter`` method of the storage adapter when searching.
|
|
193
|
+
|
|
194
|
+
:rtype: Generator yielding one closest matching statement at a time.
|
|
195
|
+
"""
|
|
196
|
+
self.chatbot.logger.info('Beginning semantic vector search')
|
|
197
|
+
|
|
198
|
+
search_parameters = {
|
|
199
|
+
'search_in_response_to_contains': input_statement.text,
|
|
200
|
+
'persona_not_startswith': 'bot:',
|
|
201
|
+
'page_size': self.search_page_size
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if additional_parameters:
|
|
205
|
+
search_parameters.update(additional_parameters)
|
|
206
|
+
|
|
207
|
+
statement_list = self.chatbot.storage.filter(**search_parameters)
|
|
208
|
+
|
|
209
|
+
best_confidence_so_far = 0
|
|
210
|
+
|
|
211
|
+
self.chatbot.logger.info('Processing search results')
|
|
212
|
+
|
|
213
|
+
# Yield statements with confidence scores from vector similarity
|
|
214
|
+
for statement in statement_list:
|
|
215
|
+
# Confidence should already be set by the storage adapter
|
|
216
|
+
confidence = getattr(statement, 'confidence', 0.0)
|
|
217
|
+
|
|
218
|
+
if confidence > best_confidence_so_far:
|
|
219
|
+
best_confidence_so_far = confidence
|
|
220
|
+
|
|
221
|
+
self.chatbot.logger.info('Similar statement found: {} {}'.format(
|
|
222
|
+
statement.in_response_to, confidence
|
|
223
|
+
))
|
|
224
|
+
|
|
225
|
+
yield statement
|
|
226
|
+
|
|
227
|
+
if confidence >= 1.0:
|
|
228
|
+
self.chatbot.logger.info('Exact match found, stopping search')
|
|
229
|
+
break
|