ChatterBot 1.2.7__tar.gz → 1.2.9__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.7 → chatterbot-1.2.9}/ChatterBot.egg-info/PKG-INFO +18 -7
- {chatterbot-1.2.7 → chatterbot-1.2.9}/ChatterBot.egg-info/requires.txt +6 -5
- {chatterbot-1.2.7 → chatterbot-1.2.9}/PKG-INFO +18 -7
- {chatterbot-1.2.7 → chatterbot-1.2.9}/README.md +10 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/__init__.py +1 -1
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/chatterbot.py +6 -4
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/comparisons.py +4 -1
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/components.py +3 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/abstract_models.py +46 -20
- chatterbot-1.2.9/chatterbot/ext/django_chatterbot/models.py +26 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/logic/best_match.py +0 -1
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/logic/specific_response.py +13 -3
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/logic/unit_conversion.py +1 -1
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/parsing.py +25 -15
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/response_selection.py +18 -7
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/search.py +8 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/storage/django_storage.py +45 -16
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/storage/mongodb.py +34 -10
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/storage/redis.py +198 -33
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/storage/sql_storage.py +43 -10
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/storage/storage_adapter.py +8 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/tagging.py +44 -7
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/trainers.py +118 -50
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/vectorstores.py +1 -2
- {chatterbot-1.2.7 → chatterbot-1.2.9}/pyproject.toml +7 -6
- {chatterbot-1.2.7 → chatterbot-1.2.9}/tests/test_chatbot.py +5 -4
- {chatterbot-1.2.7 → chatterbot-1.2.9}/tests/test_parsing.py +197 -0
- chatterbot-1.2.7/chatterbot/ext/django_chatterbot/models.py +0 -16
- {chatterbot-1.2.7 → chatterbot-1.2.9}/ChatterBot.egg-info/SOURCES.txt +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/ChatterBot.egg-info/dependency_links.txt +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/ChatterBot.egg-info/top_level.txt +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/LICENSE +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/__main__.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/adapters.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/constants.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/conversation.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/corpus.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/exceptions.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/__init__.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/__init__.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/admin.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/apps.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/migrations/0001_initial.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/migrations/0002_statement_extra_data.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/migrations/0003_change_occurrence_default.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/migrations/0004_rename_in_response_to.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/migrations/0005_statement_created_at.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/migrations/0006_create_conversation.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/migrations/0007_response_created_at.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/migrations/0008_update_conversations.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/migrations/0009_tags.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/migrations/0010_statement_text.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/migrations/0011_blank_extra_data.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/migrations/0012_statement_created_at.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/migrations/0013_change_conversations.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/migrations/0014_remove_statement_extra_data.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/migrations/0015_statement_persona.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/migrations/0016_statement_stemmed_text.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/migrations/0017_tags_unique.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/migrations/0018_text_max_length.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/migrations/0019_alter_statement_id_alter_tag_id_and_more.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/migrations/0020_alter_statement_conversation_and_more.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/migrations/__init__.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/model_admin.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/django_chatterbot/settings.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/sqlalchemy_app/__init__.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/ext/sqlalchemy_app/models.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/filters.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/languages.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/llm.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/logic/__init__.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/logic/logic_adapter.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/logic/mathematical_evaluation.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/logic/time_adapter.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/preprocessors.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/storage/__init__.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/chatterbot/utils.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/setup.cfg +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/tests/test_adapter_validation.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/tests/test_benchmarks.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/tests/test_cli.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/tests/test_comparisons.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/tests/test_conversations.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/tests/test_corpus.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/tests/test_examples.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/tests/test_filters.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/tests/test_initialization.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/tests/test_languages.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/tests/test_preprocessors.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/tests/test_response_selection.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/tests/test_search.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/tests/test_tagging.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/tests/test_turing.py +0 -0
- {chatterbot-1.2.7 → chatterbot-1.2.9}/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.9
|
|
4
4
|
Summary: ChatterBot is a machine learning, conversational dialog engine
|
|
5
5
|
Author: Gunther Cox
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -28,10 +28,10 @@ Classifier: Programming Language :: Python
|
|
|
28
28
|
Classifier: Programming Language :: Python :: 3
|
|
29
29
|
Classifier: Programming Language :: Python :: 3.9
|
|
30
30
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
31
|
-
Requires-Python: <3.
|
|
31
|
+
Requires-Python: <3.14,>=3.9
|
|
32
32
|
Description-Content-Type: text/markdown
|
|
33
33
|
License-File: LICENSE
|
|
34
|
-
Requires-Dist: mathparse<0.
|
|
34
|
+
Requires-Dist: mathparse<0.3,>=0.2
|
|
35
35
|
Requires-Dist: python-dateutil<2.10,>=2.9
|
|
36
36
|
Requires-Dist: sqlalchemy<2.1,>=2.0
|
|
37
37
|
Requires-Dist: spacy<3.9,>=3.8
|
|
@@ -42,20 +42,21 @@ Requires-Dist: coverage; extra == "test"
|
|
|
42
42
|
Requires-Dist: sphinx<8.2,>=5.3; extra == "test"
|
|
43
43
|
Requires-Dist: sphinx-sitemap>=2.6.0; extra == "test"
|
|
44
44
|
Requires-Dist: huggingface_hub; extra == "test"
|
|
45
|
+
Requires-Dist: django<6.0,<=4.1; extra == "test"
|
|
45
46
|
Provides-Extra: dev
|
|
46
47
|
Requires-Dist: pint>=0.8.1; extra == "dev"
|
|
47
48
|
Requires-Dist: pyyaml<7.0,>=6.0; extra == "dev"
|
|
48
49
|
Requires-Dist: chatterbot-corpus<1.3.0,>=1.2.2; extra == "dev"
|
|
49
|
-
Requires-Dist: ollama<1.0,>=0.
|
|
50
|
+
Requires-Dist: ollama<1.0,>=0.6.0; extra == "dev"
|
|
50
51
|
Requires-Dist: openai; extra == "dev"
|
|
51
52
|
Provides-Extra: redis
|
|
52
|
-
Requires-Dist: redis[hiredis]<
|
|
53
|
-
Requires-Dist: langchain-redis<=0.2.
|
|
53
|
+
Requires-Dist: redis[hiredis]<7.0; extra == "redis"
|
|
54
|
+
Requires-Dist: langchain-redis<=0.2.5; extra == "redis"
|
|
54
55
|
Requires-Dist: langchain-huggingface<=0.1.2; extra == "redis"
|
|
55
56
|
Requires-Dist: accelerate<=1.6.0; extra == "redis"
|
|
56
57
|
Requires-Dist: sentence-transformers<=4.0.2; extra == "redis"
|
|
57
58
|
Provides-Extra: mongodb
|
|
58
|
-
Requires-Dist: pymongo<4.
|
|
59
|
+
Requires-Dist: pymongo<4.16,>=4.11; extra == "mongodb"
|
|
59
60
|
Dynamic: license-file
|
|
60
61
|
|
|
61
62
|

|
|
@@ -163,6 +164,16 @@ See release notes for changes https://github.com/gunthercox/ChatterBot/releases
|
|
|
163
164
|
5. Use the projects [built-in automated testing](https://docs.chatterbot.us/testing/).
|
|
164
165
|
to help make sure that your contribution is free from errors.
|
|
165
166
|
|
|
167
|
+
# Sponsors
|
|
168
|
+
|
|
169
|
+
ChatterBot is sponsored by:
|
|
170
|
+
|
|
171
|
+
<p style="font-size:21px; color:black;">Browser testing via
|
|
172
|
+
<a href="https://www.lambdatest.com/?utm_source=chatterbot&utm_medium=sponsor" target="_blank">
|
|
173
|
+
<img src="https://www.lambdatest.com/blue-logo.png" style="vertical-align: middle;" width="250" height="45" />
|
|
174
|
+
</a>
|
|
175
|
+
</p>
|
|
176
|
+
|
|
166
177
|
# License
|
|
167
178
|
|
|
168
179
|
ChatterBot is licensed under the [BSD 3-clause license](https://opensource.org/licenses/BSD-3-Clause).
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
mathparse<0.
|
|
1
|
+
mathparse<0.3,>=0.2
|
|
2
2
|
python-dateutil<2.10,>=2.9
|
|
3
3
|
sqlalchemy<2.1,>=2.0
|
|
4
4
|
spacy<3.9,>=3.8
|
|
@@ -8,15 +8,15 @@ 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]<
|
|
19
|
-
langchain-redis<=0.2.
|
|
18
|
+
redis[hiredis]<7.0
|
|
19
|
+
langchain-redis<=0.2.5
|
|
20
20
|
langchain-huggingface<=0.1.2
|
|
21
21
|
accelerate<=1.6.0
|
|
22
22
|
sentence-transformers<=4.0.2
|
|
@@ -27,3 +27,4 @@ coverage
|
|
|
27
27
|
sphinx<8.2,>=5.3
|
|
28
28
|
sphinx-sitemap>=2.6.0
|
|
29
29
|
huggingface_hub
|
|
30
|
+
django<6.0,<=4.1
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ChatterBot
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.9
|
|
4
4
|
Summary: ChatterBot is a machine learning, conversational dialog engine
|
|
5
5
|
Author: Gunther Cox
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -28,10 +28,10 @@ Classifier: Programming Language :: Python
|
|
|
28
28
|
Classifier: Programming Language :: Python :: 3
|
|
29
29
|
Classifier: Programming Language :: Python :: 3.9
|
|
30
30
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
31
|
-
Requires-Python: <3.
|
|
31
|
+
Requires-Python: <3.14,>=3.9
|
|
32
32
|
Description-Content-Type: text/markdown
|
|
33
33
|
License-File: LICENSE
|
|
34
|
-
Requires-Dist: mathparse<0.
|
|
34
|
+
Requires-Dist: mathparse<0.3,>=0.2
|
|
35
35
|
Requires-Dist: python-dateutil<2.10,>=2.9
|
|
36
36
|
Requires-Dist: sqlalchemy<2.1,>=2.0
|
|
37
37
|
Requires-Dist: spacy<3.9,>=3.8
|
|
@@ -42,20 +42,21 @@ Requires-Dist: coverage; extra == "test"
|
|
|
42
42
|
Requires-Dist: sphinx<8.2,>=5.3; extra == "test"
|
|
43
43
|
Requires-Dist: sphinx-sitemap>=2.6.0; extra == "test"
|
|
44
44
|
Requires-Dist: huggingface_hub; extra == "test"
|
|
45
|
+
Requires-Dist: django<6.0,<=4.1; extra == "test"
|
|
45
46
|
Provides-Extra: dev
|
|
46
47
|
Requires-Dist: pint>=0.8.1; extra == "dev"
|
|
47
48
|
Requires-Dist: pyyaml<7.0,>=6.0; extra == "dev"
|
|
48
49
|
Requires-Dist: chatterbot-corpus<1.3.0,>=1.2.2; extra == "dev"
|
|
49
|
-
Requires-Dist: ollama<1.0,>=0.
|
|
50
|
+
Requires-Dist: ollama<1.0,>=0.6.0; extra == "dev"
|
|
50
51
|
Requires-Dist: openai; extra == "dev"
|
|
51
52
|
Provides-Extra: redis
|
|
52
|
-
Requires-Dist: redis[hiredis]<
|
|
53
|
-
Requires-Dist: langchain-redis<=0.2.
|
|
53
|
+
Requires-Dist: redis[hiredis]<7.0; extra == "redis"
|
|
54
|
+
Requires-Dist: langchain-redis<=0.2.5; extra == "redis"
|
|
54
55
|
Requires-Dist: langchain-huggingface<=0.1.2; extra == "redis"
|
|
55
56
|
Requires-Dist: accelerate<=1.6.0; extra == "redis"
|
|
56
57
|
Requires-Dist: sentence-transformers<=4.0.2; extra == "redis"
|
|
57
58
|
Provides-Extra: mongodb
|
|
58
|
-
Requires-Dist: pymongo<4.
|
|
59
|
+
Requires-Dist: pymongo<4.16,>=4.11; extra == "mongodb"
|
|
59
60
|
Dynamic: license-file
|
|
60
61
|
|
|
61
62
|

|
|
@@ -163,6 +164,16 @@ See release notes for changes https://github.com/gunthercox/ChatterBot/releases
|
|
|
163
164
|
5. Use the projects [built-in automated testing](https://docs.chatterbot.us/testing/).
|
|
164
165
|
to help make sure that your contribution is free from errors.
|
|
165
166
|
|
|
167
|
+
# Sponsors
|
|
168
|
+
|
|
169
|
+
ChatterBot is sponsored by:
|
|
170
|
+
|
|
171
|
+
<p style="font-size:21px; color:black;">Browser testing via
|
|
172
|
+
<a href="https://www.lambdatest.com/?utm_source=chatterbot&utm_medium=sponsor" target="_blank">
|
|
173
|
+
<img src="https://www.lambdatest.com/blue-logo.png" style="vertical-align: middle;" width="250" height="45" />
|
|
174
|
+
</a>
|
|
175
|
+
</p>
|
|
176
|
+
|
|
166
177
|
# License
|
|
167
178
|
|
|
168
179
|
ChatterBot is licensed under the [BSD 3-clause license](https://opensource.org/licenses/BSD-3-Clause).
|
|
@@ -103,6 +103,16 @@ See release notes for changes https://github.com/gunthercox/ChatterBot/releases
|
|
|
103
103
|
5. Use the projects [built-in automated testing](https://docs.chatterbot.us/testing/).
|
|
104
104
|
to help make sure that your contribution is free from errors.
|
|
105
105
|
|
|
106
|
+
# Sponsors
|
|
107
|
+
|
|
108
|
+
ChatterBot is sponsored by:
|
|
109
|
+
|
|
110
|
+
<p style="font-size:21px; color:black;">Browser testing via
|
|
111
|
+
<a href="https://www.lambdatest.com/?utm_source=chatterbot&utm_medium=sponsor" target="_blank">
|
|
112
|
+
<img src="https://www.lambdatest.com/blue-logo.png" style="vertical-align: middle;" width="250" height="45" />
|
|
113
|
+
</a>
|
|
114
|
+
</p>
|
|
115
|
+
|
|
106
116
|
# License
|
|
107
117
|
|
|
108
118
|
ChatterBot is licensed under the [BSD 3-clause license](https://opensource.org/licenses/BSD-3-Clause).
|
|
@@ -77,7 +77,12 @@ class ChatBot(object):
|
|
|
77
77
|
try:
|
|
78
78
|
Tagger = kwargs.get('tagger', PosLemmaTagger)
|
|
79
79
|
|
|
80
|
-
|
|
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)
|
|
81
86
|
except IOError as io_error:
|
|
82
87
|
# Return a more helpful error message if possible
|
|
83
88
|
if "Can't find model" in str(io_error):
|
|
@@ -224,7 +229,6 @@ class ChatBot(object):
|
|
|
224
229
|
# Save the response generated for the input
|
|
225
230
|
self.learn_response(response, previous_statement=input_statement)
|
|
226
231
|
|
|
227
|
-
|
|
228
232
|
return response
|
|
229
233
|
|
|
230
234
|
def generate_response(self, input_statement, additional_response_selection_parameters=None):
|
|
@@ -345,8 +349,6 @@ class ChatBot(object):
|
|
|
345
349
|
Returns the latest response in a conversation if it exists.
|
|
346
350
|
Returns None if a matching conversation cannot be found.
|
|
347
351
|
"""
|
|
348
|
-
from chatterbot.conversation import Statement as StatementObject
|
|
349
|
-
|
|
350
352
|
conversation_statements = list(self.storage.filter(
|
|
351
353
|
conversation=conversation,
|
|
352
354
|
order_by=['id']
|
|
@@ -85,7 +85,10 @@ class SpacySimilarity(Comparator):
|
|
|
85
85
|
python -m spacy download en_core_web_sm
|
|
86
86
|
python -m spacy download de_core_news_sm
|
|
87
87
|
|
|
88
|
-
Alternatively, the ``spacy`` models can be installed as Python
|
|
88
|
+
Alternatively, the ``spacy`` models can be installed as Python
|
|
89
|
+
packages. The following lines could be included in a
|
|
90
|
+
``requirements.txt`` or ``pyproject.yml`` file if you needed to pin
|
|
91
|
+
specific versions:
|
|
89
92
|
|
|
90
93
|
.. code-block:: text
|
|
91
94
|
|
|
@@ -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))
|
|
@@ -3,25 +3,15 @@ from chatterbot import constants
|
|
|
3
3
|
from django.db import models
|
|
4
4
|
from django.utils import timezone
|
|
5
5
|
from django.conf import settings
|
|
6
|
+
from django.apps import apps
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
DJANGO_APP_NAME = constants.DEFAULT_DJANGO_APP_NAME
|
|
9
|
-
STATEMENT_MODEL = 'Statement'
|
|
10
|
-
TAG_MODEL = 'Tag'
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"""
|
|
17
|
-
DJANGO_APP_NAME = settings.CHATTERBOT.get(
|
|
18
|
-
'django_app_name',
|
|
19
|
-
DJANGO_APP_NAME
|
|
20
|
-
)
|
|
21
|
-
STATEMENT_MODEL = settings.CHATTERBOT.get(
|
|
22
|
-
'statement_model',
|
|
23
|
-
STATEMENT_MODEL
|
|
24
|
-
)
|
|
11
|
+
# Default model paths for swappable models
|
|
12
|
+
# These can be overridden via CHATTERBOT_STATEMENT_MODEL and CHATTERBOT_TAG_MODEL settings
|
|
13
|
+
DEFAULT_STATEMENT_MODEL = f'{DJANGO_APP_NAME}.Statement'
|
|
14
|
+
DEFAULT_TAG_MODEL = f'{DJANGO_APP_NAME}.Tag'
|
|
25
15
|
|
|
26
16
|
|
|
27
17
|
class AbstractBaseTag(models.Model):
|
|
@@ -88,7 +78,9 @@ class AbstractBaseStatement(models.Model, StatementMixin):
|
|
|
88
78
|
)
|
|
89
79
|
|
|
90
80
|
tags = models.ManyToManyField(
|
|
91
|
-
|
|
81
|
+
settings.CHATTERBOT_TAG_MODEL if hasattr(
|
|
82
|
+
settings, 'CHATTERBOT_TAG_MODEL'
|
|
83
|
+
) else DEFAULT_TAG_MODEL,
|
|
92
84
|
related_name='statements',
|
|
93
85
|
help_text='The tags that are associated with this statement.'
|
|
94
86
|
)
|
|
@@ -117,17 +109,51 @@ class AbstractBaseStatement(models.Model, StatementMixin):
|
|
|
117
109
|
return self.text
|
|
118
110
|
return '<empty>'
|
|
119
111
|
|
|
112
|
+
@classmethod
|
|
113
|
+
def get_tag_model(cls):
|
|
114
|
+
"""
|
|
115
|
+
Return the Tag model class, respecting the swappable setting.
|
|
116
|
+
|
|
117
|
+
This method checks:
|
|
118
|
+
1. Django settings (CHATTERBOT_TAG_MODEL) - project-wide configuration
|
|
119
|
+
2. The model referenced by the 'tags' field - handles custom models via kwargs
|
|
120
|
+
3. Falls back to DEFAULT_TAG_MODEL if introspection fails
|
|
121
|
+
|
|
122
|
+
This ensures the correct Tag model is used even when custom models
|
|
123
|
+
are specified via storage adapter kwargs rather than Django settings.
|
|
124
|
+
"""
|
|
125
|
+
tag_model_path = getattr(settings, 'CHATTERBOT_TAG_MODEL', None)
|
|
126
|
+
|
|
127
|
+
if tag_model_path:
|
|
128
|
+
return apps.get_model(tag_model_path)
|
|
129
|
+
|
|
130
|
+
# If no setting, infer from the ManyToManyField relationship for
|
|
131
|
+
# cases where custom models are specified via kwargs
|
|
132
|
+
try:
|
|
133
|
+
# Get the model that this class's 'tags' field points to
|
|
134
|
+
tags_field = cls._meta.get_field('tags')
|
|
135
|
+
related_model = tags_field.related_model
|
|
136
|
+
|
|
137
|
+
# Resolve strings (lazy references)
|
|
138
|
+
if isinstance(related_model, str):
|
|
139
|
+
return apps.get_model(related_model)
|
|
140
|
+
return related_model
|
|
141
|
+
except Exception:
|
|
142
|
+
# Fallback to default if introspection fails
|
|
143
|
+
return apps.get_model(DEFAULT_TAG_MODEL)
|
|
144
|
+
|
|
120
145
|
def get_tags(self) -> list[str]:
|
|
121
146
|
"""
|
|
122
147
|
Return the list of tags for this statement.
|
|
123
|
-
(Overrides the method from StatementMixin)
|
|
124
148
|
"""
|
|
125
149
|
return list(self.tags.values_list('name', flat=True))
|
|
126
150
|
|
|
127
151
|
def add_tags(self, *tags):
|
|
128
152
|
"""
|
|
129
153
|
Add a list of strings to the statement as tags.
|
|
130
|
-
(Overrides the method from StatementMixin)
|
|
131
154
|
"""
|
|
132
|
-
|
|
133
|
-
|
|
155
|
+
TagModel = self.get_tag_model()
|
|
156
|
+
|
|
157
|
+
for tag_name in tags:
|
|
158
|
+
tag_obj, _created = TagModel.objects.get_or_create(name=tag_name)
|
|
159
|
+
self.tags.add(tag_obj)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from chatterbot.ext.django_chatterbot.abstract_models import AbstractBaseStatement, AbstractBaseTag
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Statement(AbstractBaseStatement):
|
|
5
|
+
"""
|
|
6
|
+
A statement represents a single spoken entity, sentence or
|
|
7
|
+
phrase that someone can say.
|
|
8
|
+
|
|
9
|
+
This model can be swapped for a custom model by setting
|
|
10
|
+
CHATTERBOT_STATEMENT_MODEL in your Django settings.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
class Meta:
|
|
14
|
+
swappable = 'CHATTERBOT_STATEMENT_MODEL'
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Tag(AbstractBaseTag):
|
|
18
|
+
"""
|
|
19
|
+
A label that categorizes a statement.
|
|
20
|
+
|
|
21
|
+
This model can be swapped for a custom model by setting
|
|
22
|
+
CHATTERBOT_TAG_MODEL in your Django settings.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
class Meta:
|
|
26
|
+
swappable = 'CHATTERBOT_TAG_MODEL'
|
|
@@ -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
|
"""
|
|
@@ -18,17 +18,28 @@ def get_most_frequent_response(input_statement: Statement, response_list: list[S
|
|
|
18
18
|
|
|
19
19
|
:return: The response statement with the greatest number of occurrences.
|
|
20
20
|
"""
|
|
21
|
-
matching_response = None
|
|
22
|
-
occurrence_count = -1
|
|
23
|
-
|
|
24
21
|
logger = logging.getLogger(__name__)
|
|
25
22
|
logger.info('Selecting response with greatest number of occurrences.')
|
|
26
23
|
|
|
24
|
+
# Collect all unique text values from response_list
|
|
25
|
+
response_texts = set(statement.text for statement in response_list)
|
|
26
|
+
|
|
27
|
+
# Fetch all statements matching the input in a single query
|
|
28
|
+
# Then count occurrences in memory
|
|
29
|
+
all_matching = list(storage.filter(in_response_to=input_statement.text))
|
|
30
|
+
|
|
31
|
+
# Count how many times each response text appears in the database
|
|
32
|
+
occurrence_counts = {}
|
|
33
|
+
for statement in all_matching:
|
|
34
|
+
if statement.text in response_texts:
|
|
35
|
+
occurrence_counts[statement.text] = occurrence_counts.get(statement.text, 0) + 1
|
|
36
|
+
|
|
37
|
+
# Find the response with the highest occurrence count
|
|
38
|
+
matching_response = None
|
|
39
|
+
occurrence_count = -1
|
|
40
|
+
|
|
27
41
|
for statement in response_list:
|
|
28
|
-
count =
|
|
29
|
-
text=statement.text,
|
|
30
|
-
in_response_to=input_statement.text)
|
|
31
|
-
))
|
|
42
|
+
count = occurrence_counts.get(statement.text, 0)
|
|
32
43
|
|
|
33
44
|
# Keep the more common statement
|
|
34
45
|
if count >= occurrence_count:
|
|
@@ -74,6 +74,10 @@ class IndexedTextSearch:
|
|
|
74
74
|
|
|
75
75
|
yield statement
|
|
76
76
|
|
|
77
|
+
if confidence >= 1.0:
|
|
78
|
+
self.chatbot.logger.info('Exact match found, stopping search')
|
|
79
|
+
break
|
|
80
|
+
|
|
77
81
|
|
|
78
82
|
class TextSearch:
|
|
79
83
|
"""
|
|
@@ -149,3 +153,7 @@ class TextSearch:
|
|
|
149
153
|
))
|
|
150
154
|
|
|
151
155
|
yield statement
|
|
156
|
+
|
|
157
|
+
if confidence >= 1.0:
|
|
158
|
+
self.chatbot.logger.info('Exact match found, stopping search')
|
|
159
|
+
break
|