ChatterBot 1.2.10__tar.gz → 1.2.12__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.10 → chatterbot-1.2.12}/ChatterBot.egg-info/PKG-INFO +10 -10
- {chatterbot-1.2.10 → chatterbot-1.2.12}/ChatterBot.egg-info/SOURCES.txt +1 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/ChatterBot.egg-info/requires.txt +7 -7
- {chatterbot-1.2.10 → chatterbot-1.2.12}/PKG-INFO +10 -10
- {chatterbot-1.2.10 → chatterbot-1.2.12}/README.md +2 -2
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/__init__.py +1 -1
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/constants.py +4 -4
- chatterbot-1.2.12/chatterbot/ext/django_chatterbot/migrations/0021_increase_text_max_length_to_1100.py +55 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/storage/redis.py +31 -137
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/storage/sql_storage.py +153 -112
- {chatterbot-1.2.10 → chatterbot-1.2.12}/pyproject.toml +7 -7
- {chatterbot-1.2.10 → chatterbot-1.2.12}/ChatterBot.egg-info/dependency_links.txt +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/ChatterBot.egg-info/top_level.txt +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/LICENSE +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/__main__.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/adapters.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/chatterbot.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/comparisons.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/components.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/conversation.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/corpus.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/exceptions.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/__init__.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/__init__.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/abstract_models.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/admin.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/apps.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/migrations/0001_initial.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/migrations/0002_statement_extra_data.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/migrations/0003_change_occurrence_default.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/migrations/0004_rename_in_response_to.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/migrations/0005_statement_created_at.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/migrations/0006_create_conversation.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/migrations/0007_response_created_at.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/migrations/0008_update_conversations.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/migrations/0009_tags.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/migrations/0010_statement_text.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/migrations/0011_blank_extra_data.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/migrations/0012_statement_created_at.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/migrations/0013_change_conversations.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/migrations/0014_remove_statement_extra_data.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/migrations/0015_statement_persona.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/migrations/0016_statement_stemmed_text.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/migrations/0017_tags_unique.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/migrations/0018_text_max_length.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/migrations/0019_alter_statement_id_alter_tag_id_and_more.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/migrations/0020_alter_statement_conversation_and_more.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/migrations/__init__.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/model_admin.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/models.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/settings.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/sqlalchemy_app/__init__.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/sqlalchemy_app/models.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/filters.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/languages.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/llm.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/logic/__init__.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/logic/best_match.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/logic/logic_adapter.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/logic/mathematical_evaluation.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/logic/specific_response.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/logic/time_adapter.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/logic/unit_conversion.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/parsing.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/preprocessors.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/response_selection.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/search.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/storage/__init__.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/storage/django_storage.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/storage/mongodb.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/storage/storage_adapter.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/tagging.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/trainers.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/utils.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/vectorstores.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/setup.cfg +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/tests/test_adapter_validation.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/tests/test_benchmarks.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/tests/test_chatbot.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/tests/test_cli.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/tests/test_comparisons.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/tests/test_conversations.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/tests/test_corpus.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/tests/test_examples.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/tests/test_filters.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/tests/test_initialization.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/tests/test_languages.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/tests/test_parsing.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/tests/test_preprocessors.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/tests/test_response_selection.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/tests/test_search.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/tests/test_tagging.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/tests/test_turing.py +0 -0
- {chatterbot-1.2.10 → chatterbot-1.2.12}/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.12
|
|
4
4
|
Summary: ChatterBot is a machine learning, conversational dialog engine
|
|
5
5
|
Author: Gunther Cox
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -39,7 +39,7 @@ Requires-Dist: tqdm
|
|
|
39
39
|
Provides-Extra: test
|
|
40
40
|
Requires-Dist: flake8; extra == "test"
|
|
41
41
|
Requires-Dist: coverage; extra == "test"
|
|
42
|
-
Requires-Dist: sphinx<
|
|
42
|
+
Requires-Dist: sphinx<9.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
45
|
Requires-Dist: django<6.0,<=4.1; extra == "test"
|
|
@@ -50,13 +50,13 @@ Requires-Dist: chatterbot-corpus<1.3.0,>=1.2.2; extra == "dev"
|
|
|
50
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]<7.0; extra == "redis"
|
|
54
|
-
Requires-Dist: langchain-redis
|
|
55
|
-
Requires-Dist: langchain-huggingface
|
|
56
|
-
Requires-Dist: accelerate
|
|
57
|
-
Requires-Dist: sentence-transformers
|
|
53
|
+
Requires-Dist: redis[hiredis]<7.2,>=7.0; extra == "redis"
|
|
54
|
+
Requires-Dist: langchain-redis<0.3.0; extra == "redis"
|
|
55
|
+
Requires-Dist: langchain-huggingface<1.3.0,>=0.1.2; extra == "redis"
|
|
56
|
+
Requires-Dist: accelerate<1.13,>=1.6.0; extra == "redis"
|
|
57
|
+
Requires-Dist: sentence-transformers<5.3.0,>=4.0.2; extra == "redis"
|
|
58
58
|
Provides-Extra: mongodb
|
|
59
|
-
Requires-Dist: pymongo<4.
|
|
59
|
+
Requires-Dist: pymongo<4.17,>=4.11; extra == "mongodb"
|
|
60
60
|
Dynamic: license-file
|
|
61
61
|
|
|
62
62
|

|
|
@@ -162,9 +162,9 @@ https://docs.chatterbot.us/contributing/
|
|
|
162
162
|
|
|
163
163
|
ChatterBot is sponsored by:
|
|
164
164
|
|
|
165
|
-
<p
|
|
165
|
+
<p>
|
|
166
166
|
<a href="https://www.lambdatest.com/?utm_source=chatterbot&utm_medium=sponsor" target="_blank">
|
|
167
|
-
<img src="
|
|
167
|
+
<img src="docs/_static/testmu-ai-white-logo.png" style="vertical-align: middle;" width="250" height="80" />
|
|
168
168
|
</a>
|
|
169
169
|
</p>
|
|
170
170
|
|
|
@@ -56,6 +56,7 @@ chatterbot/ext/django_chatterbot/migrations/0017_tags_unique.py
|
|
|
56
56
|
chatterbot/ext/django_chatterbot/migrations/0018_text_max_length.py
|
|
57
57
|
chatterbot/ext/django_chatterbot/migrations/0019_alter_statement_id_alter_tag_id_and_more.py
|
|
58
58
|
chatterbot/ext/django_chatterbot/migrations/0020_alter_statement_conversation_and_more.py
|
|
59
|
+
chatterbot/ext/django_chatterbot/migrations/0021_increase_text_max_length_to_1100.py
|
|
59
60
|
chatterbot/ext/django_chatterbot/migrations/__init__.py
|
|
60
61
|
chatterbot/ext/sqlalchemy_app/__init__.py
|
|
61
62
|
chatterbot/ext/sqlalchemy_app/models.py
|
|
@@ -12,19 +12,19 @@ ollama<1.0,>=0.6.0
|
|
|
12
12
|
openai
|
|
13
13
|
|
|
14
14
|
[mongodb]
|
|
15
|
-
pymongo<4.
|
|
15
|
+
pymongo<4.17,>=4.11
|
|
16
16
|
|
|
17
17
|
[redis]
|
|
18
|
-
redis[hiredis]<7.0
|
|
19
|
-
langchain-redis
|
|
20
|
-
langchain-huggingface
|
|
21
|
-
accelerate
|
|
22
|
-
sentence-transformers
|
|
18
|
+
redis[hiredis]<7.2,>=7.0
|
|
19
|
+
langchain-redis<0.3.0
|
|
20
|
+
langchain-huggingface<1.3.0,>=0.1.2
|
|
21
|
+
accelerate<1.13,>=1.6.0
|
|
22
|
+
sentence-transformers<5.3.0,>=4.0.2
|
|
23
23
|
|
|
24
24
|
[test]
|
|
25
25
|
flake8
|
|
26
26
|
coverage
|
|
27
|
-
sphinx<
|
|
27
|
+
sphinx<9.2,>=5.3
|
|
28
28
|
sphinx-sitemap>=2.6.0
|
|
29
29
|
huggingface_hub
|
|
30
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.12
|
|
4
4
|
Summary: ChatterBot is a machine learning, conversational dialog engine
|
|
5
5
|
Author: Gunther Cox
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -39,7 +39,7 @@ Requires-Dist: tqdm
|
|
|
39
39
|
Provides-Extra: test
|
|
40
40
|
Requires-Dist: flake8; extra == "test"
|
|
41
41
|
Requires-Dist: coverage; extra == "test"
|
|
42
|
-
Requires-Dist: sphinx<
|
|
42
|
+
Requires-Dist: sphinx<9.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
45
|
Requires-Dist: django<6.0,<=4.1; extra == "test"
|
|
@@ -50,13 +50,13 @@ Requires-Dist: chatterbot-corpus<1.3.0,>=1.2.2; extra == "dev"
|
|
|
50
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]<7.0; extra == "redis"
|
|
54
|
-
Requires-Dist: langchain-redis
|
|
55
|
-
Requires-Dist: langchain-huggingface
|
|
56
|
-
Requires-Dist: accelerate
|
|
57
|
-
Requires-Dist: sentence-transformers
|
|
53
|
+
Requires-Dist: redis[hiredis]<7.2,>=7.0; extra == "redis"
|
|
54
|
+
Requires-Dist: langchain-redis<0.3.0; extra == "redis"
|
|
55
|
+
Requires-Dist: langchain-huggingface<1.3.0,>=0.1.2; extra == "redis"
|
|
56
|
+
Requires-Dist: accelerate<1.13,>=1.6.0; extra == "redis"
|
|
57
|
+
Requires-Dist: sentence-transformers<5.3.0,>=4.0.2; extra == "redis"
|
|
58
58
|
Provides-Extra: mongodb
|
|
59
|
-
Requires-Dist: pymongo<4.
|
|
59
|
+
Requires-Dist: pymongo<4.17,>=4.11; extra == "mongodb"
|
|
60
60
|
Dynamic: license-file
|
|
61
61
|
|
|
62
62
|

|
|
@@ -162,9 +162,9 @@ https://docs.chatterbot.us/contributing/
|
|
|
162
162
|
|
|
163
163
|
ChatterBot is sponsored by:
|
|
164
164
|
|
|
165
|
-
<p
|
|
165
|
+
<p>
|
|
166
166
|
<a href="https://www.lambdatest.com/?utm_source=chatterbot&utm_medium=sponsor" target="_blank">
|
|
167
|
-
<img src="
|
|
167
|
+
<img src="docs/_static/testmu-ai-white-logo.png" style="vertical-align: middle;" width="250" height="80" />
|
|
168
168
|
</a>
|
|
169
169
|
</p>
|
|
170
170
|
|
|
@@ -101,9 +101,9 @@ https://docs.chatterbot.us/contributing/
|
|
|
101
101
|
|
|
102
102
|
ChatterBot is sponsored by:
|
|
103
103
|
|
|
104
|
-
<p
|
|
104
|
+
<p>
|
|
105
105
|
<a href="https://www.lambdatest.com/?utm_source=chatterbot&utm_medium=sponsor" target="_blank">
|
|
106
|
-
<img src="
|
|
106
|
+
<img src="docs/_static/testmu-ai-white-logo.png" style="vertical-align: middle;" width="250" height="80" />
|
|
107
107
|
</a>
|
|
108
108
|
</p>
|
|
109
109
|
|
|
@@ -5,11 +5,11 @@ from chatterbot import languages
|
|
|
5
5
|
|
|
6
6
|
'''
|
|
7
7
|
The maximum length of characters that the text of a statement can contain.
|
|
8
|
-
The number
|
|
9
|
-
|
|
10
|
-
the data model for each storage adapter.
|
|
8
|
+
The number 1100 is used to support longer conversational statements while
|
|
9
|
+
remaining within VARCHAR limits for most databases. This value should be
|
|
10
|
+
enforced on a per-model basis by the data model for each storage adapter.
|
|
11
11
|
'''
|
|
12
|
-
STATEMENT_TEXT_MAX_LENGTH =
|
|
12
|
+
STATEMENT_TEXT_MAX_LENGTH = 1100
|
|
13
13
|
|
|
14
14
|
'''
|
|
15
15
|
The maximum length of characters that the text label of a conversation can contain.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Django migration to increase text field max_length from 255 to 1100.
|
|
3
|
+
|
|
4
|
+
This migration alters all text-related fields in the Statement model:
|
|
5
|
+
- text
|
|
6
|
+
- search_text
|
|
7
|
+
- in_response_to
|
|
8
|
+
- search_in_response_to
|
|
9
|
+
|
|
10
|
+
This change supports longer conversational statements while remaining
|
|
11
|
+
within VARCHAR limits for most databases.
|
|
12
|
+
"""
|
|
13
|
+
from django.db import migrations, models
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Migration(migrations.Migration):
|
|
17
|
+
|
|
18
|
+
dependencies = [
|
|
19
|
+
('django_chatterbot', '0020_alter_statement_conversation_and_more'),
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
operations = [
|
|
23
|
+
migrations.AlterField(
|
|
24
|
+
model_name='statement',
|
|
25
|
+
name='text',
|
|
26
|
+
field=models.CharField(max_length=1100, help_text='The text of the statement.'),
|
|
27
|
+
),
|
|
28
|
+
migrations.AlterField(
|
|
29
|
+
model_name='statement',
|
|
30
|
+
name='search_text',
|
|
31
|
+
field=models.CharField(
|
|
32
|
+
blank=True,
|
|
33
|
+
max_length=1100,
|
|
34
|
+
help_text='A modified version of the statement text optimized for searching.'
|
|
35
|
+
),
|
|
36
|
+
),
|
|
37
|
+
migrations.AlterField(
|
|
38
|
+
model_name='statement',
|
|
39
|
+
name='in_response_to',
|
|
40
|
+
field=models.CharField(
|
|
41
|
+
max_length=1100,
|
|
42
|
+
null=True,
|
|
43
|
+
help_text='The text of the statement that this statement is in response to.'
|
|
44
|
+
),
|
|
45
|
+
),
|
|
46
|
+
migrations.AlterField(
|
|
47
|
+
model_name='statement',
|
|
48
|
+
name='search_in_response_to',
|
|
49
|
+
field=models.CharField(
|
|
50
|
+
blank=True,
|
|
51
|
+
max_length=1100,
|
|
52
|
+
help_text='A modified version of the in_response_to text optimized for searching.'
|
|
53
|
+
),
|
|
54
|
+
),
|
|
55
|
+
]
|
|
@@ -65,6 +65,7 @@ class RedisVectorStorageAdapter(StorageAdapter):
|
|
|
65
65
|
index_name='chatterbot',
|
|
66
66
|
redis_url=self.database_uri,
|
|
67
67
|
content_field='in_response_to',
|
|
68
|
+
legacy_key_format=False,
|
|
68
69
|
metadata_schema=[
|
|
69
70
|
{
|
|
70
71
|
'name': 'conversation',
|
|
@@ -212,12 +213,16 @@ class RedisVectorStorageAdapter(StorageAdapter):
|
|
|
212
213
|
- search_in_response_to_contains
|
|
213
214
|
- order_by
|
|
214
215
|
"""
|
|
215
|
-
from redisvl.query import VectorQuery
|
|
216
216
|
from redisvl.query.filter import Tag, Text
|
|
217
217
|
|
|
218
218
|
# https://redis.io/docs/latest/develop/interact/search-and-query/advanced-concepts/query_syntax/
|
|
219
219
|
filter_condition = None
|
|
220
220
|
|
|
221
|
+
ordering = kwargs.get('order_by', None)
|
|
222
|
+
|
|
223
|
+
if ordering:
|
|
224
|
+
ordering = ','.join(ordering)
|
|
225
|
+
|
|
221
226
|
if 'in_response_to' in kwargs:
|
|
222
227
|
filter_condition = Text('in_response_to') == kwargs['in_response_to']
|
|
223
228
|
|
|
@@ -255,7 +260,7 @@ class RedisVectorStorageAdapter(StorageAdapter):
|
|
|
255
260
|
_query = '|'.join([
|
|
256
261
|
f'%%{text}%%' for text in kwargs['exclude_text_words']
|
|
257
262
|
])
|
|
258
|
-
query = Text('text') % f'-({
|
|
263
|
+
query = Text('text') % f'-({_query})'
|
|
259
264
|
if filter_condition:
|
|
260
265
|
filter_condition &= query
|
|
261
266
|
else:
|
|
@@ -290,67 +295,20 @@ class RedisVectorStorageAdapter(StorageAdapter):
|
|
|
290
295
|
# similar responses.
|
|
291
296
|
_search_query = kwargs['search_text_contains']
|
|
292
297
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
query = VectorQuery(
|
|
301
|
-
vector=embedding,
|
|
302
|
-
vector_field_name='embedding',
|
|
303
|
-
return_fields=return_fields,
|
|
304
|
-
num_results=page_size,
|
|
305
|
-
filter_expression=filter_condition
|
|
298
|
+
documents = self.vector_store.similarity_search(
|
|
299
|
+
_search_query,
|
|
300
|
+
k=page_size, # The number of results to return
|
|
301
|
+
return_all=True, # Include the full document with IDs
|
|
302
|
+
filter=filter_condition,
|
|
303
|
+
sort_by=ordering
|
|
306
304
|
)
|
|
307
305
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
Document = self.get_statement_model()
|
|
311
|
-
documents = []
|
|
312
|
-
|
|
313
|
-
# Calculate confidence from vector distances
|
|
306
|
+
# Add confidence scores based on similarity ordering
|
|
314
307
|
# Results are ordered by similarity (best match first)
|
|
315
|
-
for idx,
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
# Convert to confidence: confidence = 1 - distance
|
|
320
|
-
# If vector_score not available, use result order
|
|
321
|
-
vector_score = result.get('vector_score')
|
|
322
|
-
if vector_score is not None:
|
|
323
|
-
# Cosine distance ranges from 0 (identical) to 2 (opposite)
|
|
324
|
-
# Normalize to confidence: 1.0 (identical) to 0.0 (opposite)
|
|
325
|
-
confidence = max(0.0, 1.0 - (float(vector_score) / 2.0))
|
|
326
|
-
else:
|
|
327
|
-
# Fallback: use result order (first result = highest confidence)
|
|
328
|
-
# Start at 0.95 for first result, decay by 0.05 per position
|
|
329
|
-
confidence = max(0.0, 0.95 - (idx * 0.05))
|
|
330
|
-
|
|
331
|
-
# Parse timestamp
|
|
332
|
-
created_at_value = result.get('created_at', 0)
|
|
333
|
-
if isinstance(created_at_value, str):
|
|
334
|
-
created_at = datetime.fromtimestamp(float(created_at_value))
|
|
335
|
-
elif created_at_value:
|
|
336
|
-
created_at = datetime.fromtimestamp(float(created_at_value))
|
|
337
|
-
else:
|
|
338
|
-
created_at = datetime.now()
|
|
339
|
-
|
|
340
|
-
metadata = {
|
|
341
|
-
'text': result.get('text', ''),
|
|
342
|
-
'conversation': result.get('conversation', ''),
|
|
343
|
-
'persona': result.get('persona', ''),
|
|
344
|
-
'tags': result.get('tags', ''),
|
|
345
|
-
'created_at': created_at,
|
|
346
|
-
'confidence': confidence,
|
|
347
|
-
}
|
|
348
|
-
doc = Document(
|
|
349
|
-
page_content=in_response_to,
|
|
350
|
-
metadata=metadata,
|
|
351
|
-
id=result['id']
|
|
352
|
-
)
|
|
353
|
-
documents.append(doc)
|
|
308
|
+
for idx, doc in enumerate(documents):
|
|
309
|
+
# Start at 0.95 for first result, decay by 0.05 per position
|
|
310
|
+
confidence = max(0.0, 0.95 - (idx * 0.05))
|
|
311
|
+
doc.metadata['confidence'] = confidence
|
|
354
312
|
|
|
355
313
|
return [self.model_to_object(document) for document in documents]
|
|
356
314
|
|
|
@@ -379,74 +337,20 @@ class RedisVectorStorageAdapter(StorageAdapter):
|
|
|
379
337
|
if 'search_in_response_to_contains' in kwargs:
|
|
380
338
|
_search_text = kwargs.get('search_in_response_to_contains', '')
|
|
381
339
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
]
|
|
389
|
-
|
|
390
|
-
# Use direct index query via RedisVL
|
|
391
|
-
# langchain's similarity_search has issues with filters in v0.2.4
|
|
392
|
-
# and may not work properly with existing indexes
|
|
393
|
-
# TODO: Look into similarity_search_with_score implementation
|
|
394
|
-
query = VectorQuery(
|
|
395
|
-
vector=embedding,
|
|
396
|
-
vector_field_name='embedding',
|
|
397
|
-
return_fields=return_fields,
|
|
398
|
-
num_results=page_size,
|
|
399
|
-
filter_expression=filter_condition
|
|
340
|
+
documents = self.vector_store.similarity_search(
|
|
341
|
+
_search_text,
|
|
342
|
+
k=page_size, # The number of results to return
|
|
343
|
+
return_all=True, # Include the full document with IDs
|
|
344
|
+
filter=filter_condition,
|
|
345
|
+
sort_by=ordering
|
|
400
346
|
)
|
|
401
347
|
|
|
402
|
-
#
|
|
403
|
-
results = self.vector_store.index.query(query)
|
|
404
|
-
|
|
405
|
-
# Convert results to Document objects
|
|
406
|
-
Document = self.get_statement_model()
|
|
407
|
-
documents = []
|
|
408
|
-
|
|
409
|
-
# Calculate confidence from vector distances
|
|
348
|
+
# Add confidence scores based on similarity ordering
|
|
410
349
|
# Results are ordered by similarity (best match first)
|
|
411
|
-
for idx,
|
|
412
|
-
#
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
# Redis vector_score is cosine distance (lower is better)
|
|
416
|
-
# Convert to confidence: confidence = 1 - distance
|
|
417
|
-
# If vector_score not available, use result order
|
|
418
|
-
vector_score = result.get('vector_score')
|
|
419
|
-
if vector_score is not None:
|
|
420
|
-
# Cosine distance ranges from 0 (identical) to 2 (opposite)
|
|
421
|
-
# Normalize to confidence: 1.0 (identical) to 0.0 (opposite)
|
|
422
|
-
confidence = max(0.0, 1.0 - (float(vector_score) / 2.0))
|
|
423
|
-
else:
|
|
424
|
-
# Fallback: use result order (first result = highest confidence)
|
|
425
|
-
# Start at 0.95 for first result, decay by 0.05 per position
|
|
426
|
-
confidence = max(0.0, 0.95 - (idx * 0.05))
|
|
427
|
-
|
|
428
|
-
# Convert Unix timestamp back to datetime
|
|
429
|
-
# Redis returns numeric fields as strings
|
|
430
|
-
created_at_timestamp = result.get('created_at', '0')
|
|
431
|
-
if created_at_timestamp and created_at_timestamp != '0':
|
|
432
|
-
created_at = datetime.fromtimestamp(float(created_at_timestamp))
|
|
433
|
-
else:
|
|
434
|
-
created_at = datetime.now()
|
|
435
|
-
|
|
436
|
-
metadata = {
|
|
437
|
-
'text': result.get('text', ''),
|
|
438
|
-
'conversation': result.get('conversation', ''),
|
|
439
|
-
'persona': result.get('persona', ''),
|
|
440
|
-
'tags': result.get('tags', ''),
|
|
441
|
-
'created_at': created_at,
|
|
442
|
-
'confidence': confidence,
|
|
443
|
-
}
|
|
444
|
-
doc = Document(
|
|
445
|
-
page_content=in_response_to,
|
|
446
|
-
metadata=metadata,
|
|
447
|
-
id=result['id']
|
|
448
|
-
)
|
|
449
|
-
documents.append(doc)
|
|
350
|
+
for idx, doc in enumerate(documents):
|
|
351
|
+
# Start at 0.95 for first result, decay by 0.05 per position
|
|
352
|
+
confidence = max(0.0, 0.95 - (idx * 0.05))
|
|
353
|
+
doc.metadata['confidence'] = confidence
|
|
450
354
|
else:
|
|
451
355
|
documents = self.vector_store.query_search(
|
|
452
356
|
k=page_size,
|
|
@@ -551,11 +455,8 @@ class RedisVectorStorageAdapter(StorageAdapter):
|
|
|
551
455
|
client = self.vector_store.index.client
|
|
552
456
|
client.delete(statement.id)
|
|
553
457
|
|
|
554
|
-
#
|
|
555
|
-
|
|
556
|
-
if '::' in statement.id:
|
|
557
|
-
key = statement.id.split('::', 1)[1]
|
|
558
|
-
elif ':' in statement.id:
|
|
458
|
+
# Extract the key from the full ID (format: prefix:key)
|
|
459
|
+
if ':' in statement.id:
|
|
559
460
|
key = statement.id.split(':', 1)[1]
|
|
560
461
|
else:
|
|
561
462
|
# If no delimiter found, use the entire ID as the key
|
|
@@ -564,13 +465,6 @@ class RedisVectorStorageAdapter(StorageAdapter):
|
|
|
564
465
|
ids = self.vector_store.add_texts(
|
|
565
466
|
[document.page_content], [metadata], keys=[key]
|
|
566
467
|
)
|
|
567
|
-
|
|
568
|
-
# Normalize the ID to use :: delimiter (if langchain-redis returned single colon)
|
|
569
|
-
if ids and ':' in ids[0] and '::' not in ids[0]:
|
|
570
|
-
# Replace first occurrence of single colon with double colon
|
|
571
|
-
normalized_id = ids[0].replace(':', '::', 1)
|
|
572
|
-
# Update the key in Redis to use the correct format
|
|
573
|
-
client.rename(ids[0], normalized_id)
|
|
574
468
|
else:
|
|
575
469
|
self.vector_store.add_documents([document])
|
|
576
470
|
|
|
@@ -23,7 +23,7 @@ class SQLStorageAdapter(StorageAdapter):
|
|
|
23
23
|
from sqlalchemy import create_engine, inspect, event
|
|
24
24
|
from sqlalchemy import Index
|
|
25
25
|
from sqlalchemy.engine import Engine
|
|
26
|
-
from sqlalchemy.orm import sessionmaker
|
|
26
|
+
from sqlalchemy.orm import sessionmaker, scoped_session
|
|
27
27
|
|
|
28
28
|
self.database_uri = kwargs.get('database_uri', False)
|
|
29
29
|
|
|
@@ -35,7 +35,10 @@ class SQLStorageAdapter(StorageAdapter):
|
|
|
35
35
|
if not self.database_uri:
|
|
36
36
|
self.database_uri = 'sqlite:///db.sqlite3'
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
# Configure connection pool with safe defaults to prevent exhaustion
|
|
39
|
+
# Note: SQLite uses SingletonThreadPool which doesn't support these params
|
|
40
|
+
# PostgreSQL, MySQL, etc. use QueuePool which does support them
|
|
41
|
+
pool_config = {}
|
|
39
42
|
|
|
40
43
|
if self.database_uri.startswith('sqlite://'):
|
|
41
44
|
|
|
@@ -66,6 +69,23 @@ class SQLStorageAdapter(StorageAdapter):
|
|
|
66
69
|
cursor.execute('PRAGMA synchronous=NORMAL')
|
|
67
70
|
cursor.close()
|
|
68
71
|
|
|
72
|
+
else:
|
|
73
|
+
# Only apply pool configuration for databases that support QueuePool
|
|
74
|
+
# pool_size: Maximum persistent connections (10)
|
|
75
|
+
# max_overflow: Additional connections during peak load (20)
|
|
76
|
+
# pool_timeout: Seconds to wait for connection before error (30)
|
|
77
|
+
# pool_recycle: Recycle connections after 1 hour to prevent stale connections
|
|
78
|
+
# pool_pre_ping: Test connections before using to detect disconnects
|
|
79
|
+
pool_config = {
|
|
80
|
+
'pool_size': kwargs.get('pool_size', 10),
|
|
81
|
+
'max_overflow': kwargs.get('max_overflow', 20),
|
|
82
|
+
'pool_timeout': kwargs.get('pool_timeout', 30),
|
|
83
|
+
'pool_recycle': kwargs.get('pool_recycle', 3600),
|
|
84
|
+
'pool_pre_ping': kwargs.get('pool_pre_ping', True),
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
self.engine = create_engine(self.database_uri, **pool_config)
|
|
88
|
+
|
|
69
89
|
if not inspect(self.engine).has_table('statement'):
|
|
70
90
|
self.create_database()
|
|
71
91
|
|
|
@@ -91,7 +111,10 @@ class SQLStorageAdapter(StorageAdapter):
|
|
|
91
111
|
|
|
92
112
|
search_in_response_to_index.create(bind=self.engine)
|
|
93
113
|
|
|
94
|
-
|
|
114
|
+
# Use a scoped session for thread-safe session management
|
|
115
|
+
# This provides thread-local session storage to prevent session sharing across threads
|
|
116
|
+
session_factory = sessionmaker(bind=self.engine, expire_on_commit=True)
|
|
117
|
+
self.Session = scoped_session(session_factory)
|
|
95
118
|
|
|
96
119
|
def get_statement_model(self):
|
|
97
120
|
"""
|
|
@@ -119,9 +142,11 @@ class SQLStorageAdapter(StorageAdapter):
|
|
|
119
142
|
Statement = self.get_model('statement')
|
|
120
143
|
|
|
121
144
|
session = self.Session()
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
145
|
+
try:
|
|
146
|
+
statement_count = session.query(Statement).count()
|
|
147
|
+
return statement_count
|
|
148
|
+
finally:
|
|
149
|
+
session.close()
|
|
125
150
|
|
|
126
151
|
def remove(self, statement_text):
|
|
127
152
|
"""
|
|
@@ -131,13 +156,14 @@ class SQLStorageAdapter(StorageAdapter):
|
|
|
131
156
|
"""
|
|
132
157
|
Statement = self.get_model('statement')
|
|
133
158
|
session = self.Session()
|
|
159
|
+
try:
|
|
160
|
+
query = session.query(Statement).filter_by(text=statement_text)
|
|
161
|
+
record = query.first()
|
|
134
162
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
session.commit()
|
|
140
|
-
session.close()
|
|
163
|
+
session.delete(record)
|
|
164
|
+
session.commit()
|
|
165
|
+
finally:
|
|
166
|
+
session.close()
|
|
141
167
|
|
|
142
168
|
def filter(self, **kwargs):
|
|
143
169
|
"""
|
|
@@ -152,8 +178,6 @@ class SQLStorageAdapter(StorageAdapter):
|
|
|
152
178
|
Statement = self.get_model('statement')
|
|
153
179
|
Tag = self.get_model('tag')
|
|
154
180
|
|
|
155
|
-
session = self.Session()
|
|
156
|
-
|
|
157
181
|
page_size = kwargs.pop('page_size', 1000)
|
|
158
182
|
order_by = kwargs.pop('order_by', None)
|
|
159
183
|
tags = kwargs.pop('tags', [])
|
|
@@ -167,65 +191,69 @@ class SQLStorageAdapter(StorageAdapter):
|
|
|
167
191
|
if isinstance(tags, str):
|
|
168
192
|
tags = [tags]
|
|
169
193
|
|
|
170
|
-
if
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
~Statement.text.in_(exclude_text)
|
|
183
|
-
)
|
|
194
|
+
# Use context manager to ensure session cleanup even if generator is partially consumed
|
|
195
|
+
session = self.Session()
|
|
196
|
+
try:
|
|
197
|
+
if len(kwargs) == 0:
|
|
198
|
+
statements = session.query(Statement).filter()
|
|
199
|
+
else:
|
|
200
|
+
statements = session.query(Statement).filter_by(**kwargs)
|
|
201
|
+
|
|
202
|
+
if tags:
|
|
203
|
+
statements = statements.join(Statement.tags).filter(
|
|
204
|
+
Tag.name.in_(tags)
|
|
205
|
+
)
|
|
184
206
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
statements = statements.filter(
|
|
190
|
-
~or_(*or_word_query)
|
|
191
|
-
)
|
|
207
|
+
if exclude_text:
|
|
208
|
+
statements = statements.filter(
|
|
209
|
+
~Statement.text.in_(exclude_text)
|
|
210
|
+
)
|
|
192
211
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
212
|
+
if exclude_text_words:
|
|
213
|
+
or_word_query = [
|
|
214
|
+
Statement.text.ilike('%' + word + '%') for word in exclude_text_words
|
|
215
|
+
]
|
|
216
|
+
statements = statements.filter(
|
|
217
|
+
~or_(*or_word_query)
|
|
218
|
+
)
|
|
197
219
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
statements = statements.filter(
|
|
203
|
-
or_(*or_query)
|
|
204
|
-
)
|
|
220
|
+
if persona_not_startswith:
|
|
221
|
+
statements = statements.filter(
|
|
222
|
+
~Statement.persona.startswith('bot:')
|
|
223
|
+
)
|
|
205
224
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
225
|
+
if search_text_contains:
|
|
226
|
+
or_query = [
|
|
227
|
+
Statement.search_text.contains(word) for word in search_text_contains.split(' ')
|
|
228
|
+
]
|
|
229
|
+
statements = statements.filter(
|
|
230
|
+
or_(*or_query)
|
|
231
|
+
)
|
|
213
232
|
|
|
214
|
-
|
|
233
|
+
if search_in_response_to_contains:
|
|
234
|
+
or_query = [
|
|
235
|
+
Statement.search_in_response_to.contains(word) for word in search_in_response_to_contains.split(' ')
|
|
236
|
+
]
|
|
237
|
+
statements = statements.filter(
|
|
238
|
+
or_(*or_query)
|
|
239
|
+
)
|
|
215
240
|
|
|
216
|
-
if
|
|
217
|
-
index = order_by.index('created_at')
|
|
218
|
-
order_by[index] = Statement.created_at.asc()
|
|
241
|
+
if order_by:
|
|
219
242
|
|
|
220
|
-
|
|
243
|
+
if 'created_at' in order_by:
|
|
244
|
+
index = order_by.index('created_at')
|
|
245
|
+
order_by[index] = Statement.created_at.asc()
|
|
221
246
|
|
|
222
|
-
|
|
247
|
+
statements = statements.order_by(*order_by)
|
|
223
248
|
|
|
224
|
-
|
|
225
|
-
for statement in statements.slice(start_index, start_index + page_size):
|
|
226
|
-
yield self.model_to_object(statement)
|
|
249
|
+
total_statements = statements.count()
|
|
227
250
|
|
|
228
|
-
|
|
251
|
+
for start_index in range(0, total_statements, page_size):
|
|
252
|
+
for statement in statements.slice(start_index, start_index + page_size):
|
|
253
|
+
yield self.model_to_object(statement)
|
|
254
|
+
finally:
|
|
255
|
+
# Always close session, even if generator is abandoned or exception occurs
|
|
256
|
+
session.close()
|
|
229
257
|
|
|
230
258
|
def create(
|
|
231
259
|
self,
|
|
@@ -336,8 +364,11 @@ class SQLStorageAdapter(StorageAdapter):
|
|
|
336
364
|
statement_model_object.tags.append(tag)
|
|
337
365
|
create_statements.append(statement_model_object)
|
|
338
366
|
|
|
339
|
-
|
|
340
|
-
|
|
367
|
+
try:
|
|
368
|
+
session.add_all(create_statements)
|
|
369
|
+
session.commit()
|
|
370
|
+
finally:
|
|
371
|
+
session.close()
|
|
341
372
|
|
|
342
373
|
def update(self, statement):
|
|
343
374
|
"""
|
|
@@ -348,49 +379,51 @@ class SQLStorageAdapter(StorageAdapter):
|
|
|
348
379
|
Tag = self.get_model('tag')
|
|
349
380
|
|
|
350
381
|
session = self.Session()
|
|
351
|
-
|
|
382
|
+
try:
|
|
383
|
+
record = None
|
|
352
384
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
# Create a new statement entry if one does not already exist
|
|
362
|
-
if not record:
|
|
363
|
-
record = Statement(
|
|
364
|
-
text=statement.text,
|
|
365
|
-
conversation=statement.conversation,
|
|
366
|
-
persona=statement.persona
|
|
367
|
-
)
|
|
385
|
+
if hasattr(statement, 'id') and statement.id is not None:
|
|
386
|
+
record = session.get(Statement, statement.id)
|
|
387
|
+
else:
|
|
388
|
+
record = session.query(Statement).filter(
|
|
389
|
+
Statement.text == statement.text,
|
|
390
|
+
Statement.conversation == statement.conversation,
|
|
391
|
+
).first()
|
|
368
392
|
|
|
369
|
-
|
|
370
|
-
|
|
393
|
+
# Create a new statement entry if one does not already exist
|
|
394
|
+
if not record:
|
|
395
|
+
record = Statement(
|
|
396
|
+
text=statement.text,
|
|
397
|
+
conversation=statement.conversation,
|
|
398
|
+
persona=statement.persona
|
|
399
|
+
)
|
|
371
400
|
|
|
372
|
-
|
|
401
|
+
# Update the response value
|
|
402
|
+
record.in_response_to = statement.in_response_to
|
|
373
403
|
|
|
374
|
-
|
|
375
|
-
if self.raise_on_missing_search_text:
|
|
376
|
-
raise Exception('update issued without search_text value')
|
|
404
|
+
record.created_at = statement.created_at
|
|
377
405
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
406
|
+
if not statement.search_text:
|
|
407
|
+
if self.raise_on_missing_search_text:
|
|
408
|
+
raise Exception('update issued without search_text value')
|
|
381
409
|
|
|
382
|
-
|
|
383
|
-
|
|
410
|
+
if statement.in_response_to and not statement.search_in_response_to:
|
|
411
|
+
if self.raise_on_missing_search_text:
|
|
412
|
+
raise Exception('update issued without search_in_response_to value')
|
|
384
413
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
tag = Tag(name=tag_name)
|
|
414
|
+
for tag_name in statement.get_tags():
|
|
415
|
+
tag = session.query(Tag).filter_by(name=tag_name).first()
|
|
388
416
|
|
|
389
|
-
|
|
417
|
+
if not tag:
|
|
418
|
+
# Create the record
|
|
419
|
+
tag = Tag(name=tag_name)
|
|
390
420
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
421
|
+
record.tags.append(tag)
|
|
422
|
+
|
|
423
|
+
session.add(record)
|
|
424
|
+
session.commit()
|
|
425
|
+
finally:
|
|
426
|
+
session.close()
|
|
394
427
|
|
|
395
428
|
def get_random(self):
|
|
396
429
|
"""
|
|
@@ -399,17 +432,19 @@ class SQLStorageAdapter(StorageAdapter):
|
|
|
399
432
|
Statement = self.get_model('statement')
|
|
400
433
|
|
|
401
434
|
session = self.Session()
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
435
|
+
try:
|
|
436
|
+
count = self.count()
|
|
437
|
+
if count < 1:
|
|
438
|
+
raise self.EmptyDatabaseException()
|
|
405
439
|
|
|
406
|
-
|
|
407
|
-
|
|
440
|
+
random_index = random.randrange(0, count)
|
|
441
|
+
random_statement = session.query(Statement)[random_index]
|
|
408
442
|
|
|
409
|
-
|
|
443
|
+
statement = self.model_to_object(random_statement)
|
|
410
444
|
|
|
411
|
-
|
|
412
|
-
|
|
445
|
+
return statement
|
|
446
|
+
finally:
|
|
447
|
+
session.close()
|
|
413
448
|
|
|
414
449
|
def drop(self):
|
|
415
450
|
"""
|
|
@@ -419,12 +454,13 @@ class SQLStorageAdapter(StorageAdapter):
|
|
|
419
454
|
Tag = self.get_model('tag')
|
|
420
455
|
|
|
421
456
|
session = self.Session()
|
|
457
|
+
try:
|
|
458
|
+
session.query(Statement).delete()
|
|
459
|
+
session.query(Tag).delete()
|
|
422
460
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
session.commit()
|
|
427
|
-
session.close()
|
|
461
|
+
session.commit()
|
|
462
|
+
finally:
|
|
463
|
+
session.close()
|
|
428
464
|
|
|
429
465
|
def create_database(self):
|
|
430
466
|
"""
|
|
@@ -438,5 +474,10 @@ class SQLStorageAdapter(StorageAdapter):
|
|
|
438
474
|
Close the database connection and dispose of the engine.
|
|
439
475
|
This ensures proper cleanup of resources.
|
|
440
476
|
"""
|
|
477
|
+
# Remove thread-local sessions from scoped_session registry
|
|
478
|
+
if hasattr(self, 'Session'):
|
|
479
|
+
self.Session.remove()
|
|
480
|
+
|
|
481
|
+
# Dispose of the connection pool
|
|
441
482
|
if hasattr(self, 'engine'):
|
|
442
483
|
self.engine.dispose()
|
|
@@ -71,7 +71,7 @@ dependencies = [
|
|
|
71
71
|
test = [
|
|
72
72
|
"flake8",
|
|
73
73
|
"coverage",
|
|
74
|
-
"sphinx>=5.3,<
|
|
74
|
+
"sphinx>=5.3,<9.2",
|
|
75
75
|
"sphinx-sitemap>=2.6.0",
|
|
76
76
|
"huggingface_hub",
|
|
77
77
|
"django<=4.1,<6.0"
|
|
@@ -84,12 +84,12 @@ dev = [
|
|
|
84
84
|
"openai"
|
|
85
85
|
]
|
|
86
86
|
redis = [
|
|
87
|
-
"redis[hiredis]
|
|
88
|
-
"langchain-redis
|
|
89
|
-
"langchain-huggingface
|
|
90
|
-
"accelerate
|
|
91
|
-
"sentence-transformers
|
|
87
|
+
"redis[hiredis]>=7.0,<7.2",
|
|
88
|
+
"langchain-redis<0.3.0",
|
|
89
|
+
"langchain-huggingface>=0.1.2,<1.3.0",
|
|
90
|
+
"accelerate>=1.6.0,<1.13",
|
|
91
|
+
"sentence-transformers>=4.0.2,<5.3.0",
|
|
92
92
|
]
|
|
93
93
|
mongodb = [
|
|
94
|
-
"pymongo>=4.11,<4.
|
|
94
|
+
"pymongo>=4.11,<4.17",
|
|
95
95
|
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/migrations/0001_initial.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/migrations/0009_tags.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{chatterbot-1.2.10 → chatterbot-1.2.12}/chatterbot/ext/django_chatterbot/migrations/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|