parent
d7b91c4f4f
commit
bb6a336e0e
@ -1,3 +0,0 @@
|
|||||||
default_app_config = (
|
|
||||||
'chatterbot.ext.django_chatterbot.apps.DjangoChatterBotConfig'
|
|
||||||
)
|
|
@ -1,261 +0,0 @@
|
|||||||
from chatterbot.conversation import StatementMixin
|
|
||||||
from chatterbot import constants
|
|
||||||
from django.db import models
|
|
||||||
from django.apps import apps
|
|
||||||
from django.utils import timezone
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
|
|
||||||
DJANGO_APP_NAME = constants.DEFAULT_DJANGO_APP_NAME
|
|
||||||
STATEMENT_MODEL = 'Statement'
|
|
||||||
RESPONSE_MODEL = 'Response'
|
|
||||||
|
|
||||||
if hasattr(settings, 'CHATTERBOT'):
|
|
||||||
"""
|
|
||||||
Allow related models to be overridden in the project settings.
|
|
||||||
Default to the original settings if one is not defined.
|
|
||||||
"""
|
|
||||||
DJANGO_APP_NAME = settings.CHATTERBOT.get(
|
|
||||||
'django_app_name',
|
|
||||||
DJANGO_APP_NAME
|
|
||||||
)
|
|
||||||
STATEMENT_MODEL = settings.CHATTERBOT.get(
|
|
||||||
'statement_model',
|
|
||||||
STATEMENT_MODEL
|
|
||||||
)
|
|
||||||
RESPONSE_MODEL = settings.CHATTERBOT.get(
|
|
||||||
'response_model',
|
|
||||||
RESPONSE_MODEL
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class AbstractBaseStatement(models.Model, StatementMixin):
|
|
||||||
"""
|
|
||||||
The abstract base statement allows other models to
|
|
||||||
be created using the attributes that exist on the
|
|
||||||
default models.
|
|
||||||
"""
|
|
||||||
|
|
||||||
text = models.CharField(
|
|
||||||
unique=True,
|
|
||||||
blank=False,
|
|
||||||
null=False,
|
|
||||||
max_length=constants.STATEMENT_TEXT_MAX_LENGTH
|
|
||||||
)
|
|
||||||
|
|
||||||
extra_data = models.CharField(
|
|
||||||
max_length=500,
|
|
||||||
blank=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# This is the confidence with which the chat bot believes
|
|
||||||
# this is an accurate response. This value is set when the
|
|
||||||
# statement is returned by the chat bot.
|
|
||||||
confidence = 0
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
abstract = True
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
if len(self.text.strip()) > 60:
|
|
||||||
return '{}...'.format(self.text[:57])
|
|
||||||
elif len(self.text.strip()) > 0:
|
|
||||||
return self.text
|
|
||||||
return '<empty>'
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super(AbstractBaseStatement, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
# Responses to be saved if the statement is updated with the storage adapter
|
|
||||||
self.response_statement_cache = []
|
|
||||||
|
|
||||||
@property
|
|
||||||
def in_response_to(self):
|
|
||||||
"""
|
|
||||||
Return the response objects that are for this statement.
|
|
||||||
"""
|
|
||||||
ResponseModel = apps.get_model(DJANGO_APP_NAME, RESPONSE_MODEL)
|
|
||||||
return ResponseModel.objects.filter(statement=self)
|
|
||||||
|
|
||||||
def add_extra_data(self, key, value):
|
|
||||||
"""
|
|
||||||
Add extra data to the extra_data field.
|
|
||||||
"""
|
|
||||||
import json
|
|
||||||
|
|
||||||
if not self.extra_data:
|
|
||||||
self.extra_data = '{}'
|
|
||||||
|
|
||||||
extra_data = json.loads(self.extra_data)
|
|
||||||
extra_data[key] = value
|
|
||||||
|
|
||||||
self.extra_data = json.dumps(extra_data)
|
|
||||||
|
|
||||||
def add_tags(self, tags):
|
|
||||||
"""
|
|
||||||
Add a list of strings to the statement as tags.
|
|
||||||
(Overrides the method from StatementMixin)
|
|
||||||
"""
|
|
||||||
for tag in tags:
|
|
||||||
self.tags.create(
|
|
||||||
name=tag
|
|
||||||
)
|
|
||||||
|
|
||||||
def add_response(self, statement):
|
|
||||||
"""
|
|
||||||
Add a response to this statement.
|
|
||||||
"""
|
|
||||||
self.response_statement_cache.append(statement)
|
|
||||||
|
|
||||||
def remove_response(self, response_text):
|
|
||||||
"""
|
|
||||||
Removes a response from the statement's response list based
|
|
||||||
on the value of the response text.
|
|
||||||
|
|
||||||
:param response_text: The text of the response to be removed.
|
|
||||||
:type response_text: str
|
|
||||||
"""
|
|
||||||
is_deleted = False
|
|
||||||
response = self.in_response.filter(response__text=response_text)
|
|
||||||
|
|
||||||
if response.exists():
|
|
||||||
is_deleted = True
|
|
||||||
|
|
||||||
return is_deleted
|
|
||||||
|
|
||||||
def get_response_count(self, statement):
|
|
||||||
"""
|
|
||||||
Find the number of times that the statement has been used
|
|
||||||
as a response to the current statement.
|
|
||||||
|
|
||||||
:param statement: The statement object to get the count for.
|
|
||||||
:type statement: chatterbot.conversation.Statement
|
|
||||||
|
|
||||||
:returns: Return the number of times the statement has been used as a response.
|
|
||||||
:rtype: int
|
|
||||||
"""
|
|
||||||
return self.in_response.filter(response__text=statement.text).count()
|
|
||||||
|
|
||||||
def serialize(self):
|
|
||||||
"""
|
|
||||||
:returns: A dictionary representation of the statement object.
|
|
||||||
:rtype: dict
|
|
||||||
"""
|
|
||||||
import json
|
|
||||||
data = {}
|
|
||||||
|
|
||||||
if not self.extra_data:
|
|
||||||
self.extra_data = '{}'
|
|
||||||
|
|
||||||
data['text'] = self.text
|
|
||||||
data['in_response_to'] = []
|
|
||||||
data['extra_data'] = json.loads(self.extra_data)
|
|
||||||
|
|
||||||
for response in self.in_response.all():
|
|
||||||
data['in_response_to'].append(response.serialize())
|
|
||||||
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
class AbstractBaseResponse(models.Model):
|
|
||||||
"""
|
|
||||||
The abstract base response allows other models to
|
|
||||||
be created using the attributes that exist on the
|
|
||||||
default models.
|
|
||||||
"""
|
|
||||||
|
|
||||||
statement = models.ForeignKey(
|
|
||||||
STATEMENT_MODEL,
|
|
||||||
related_name='in_response',
|
|
||||||
on_delete=models.CASCADE
|
|
||||||
)
|
|
||||||
|
|
||||||
response = models.ForeignKey(
|
|
||||||
STATEMENT_MODEL,
|
|
||||||
related_name='responses',
|
|
||||||
on_delete=models.CASCADE
|
|
||||||
)
|
|
||||||
|
|
||||||
created_at = models.DateTimeField(
|
|
||||||
default=timezone.now,
|
|
||||||
help_text='The date and time that this response was created at.'
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
abstract = True
|
|
||||||
|
|
||||||
@property
|
|
||||||
def occurrence(self):
|
|
||||||
"""
|
|
||||||
Return a count of the number of times this response has occurred.
|
|
||||||
"""
|
|
||||||
ResponseModel = apps.get_model(DJANGO_APP_NAME, RESPONSE_MODEL)
|
|
||||||
|
|
||||||
return ResponseModel.objects.filter(
|
|
||||||
statement__text=self.statement.text,
|
|
||||||
response__text=self.response.text
|
|
||||||
).count()
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
statement = self.statement.text
|
|
||||||
response = self.response.text
|
|
||||||
return '{} => {}'.format(
|
|
||||||
statement if len(statement) <= 20 else statement[:17] + '...',
|
|
||||||
response if len(response) <= 40 else response[:37] + '...'
|
|
||||||
)
|
|
||||||
|
|
||||||
def serialize(self):
|
|
||||||
"""
|
|
||||||
:returns: A dictionary representation of the statement object.
|
|
||||||
:rtype: dict
|
|
||||||
"""
|
|
||||||
data = {}
|
|
||||||
|
|
||||||
data['text'] = self.response.text
|
|
||||||
data['created_at'] = self.created_at.isoformat()
|
|
||||||
data['occurrence'] = self.occurrence
|
|
||||||
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
class AbstractBaseConversation(models.Model):
|
|
||||||
"""
|
|
||||||
The abstract base conversation allows other models to
|
|
||||||
be created using the attributes that exist on the
|
|
||||||
default models.
|
|
||||||
"""
|
|
||||||
|
|
||||||
responses = models.ManyToManyField(
|
|
||||||
RESPONSE_MODEL,
|
|
||||||
related_name='conversations',
|
|
||||||
help_text='The responses in this conversation.'
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
abstract = True
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return str(self.id)
|
|
||||||
|
|
||||||
|
|
||||||
class AbstractBaseTag(models.Model):
|
|
||||||
"""
|
|
||||||
The abstract base tag allows other models to
|
|
||||||
be created using the attributes that exist on the
|
|
||||||
default models.
|
|
||||||
"""
|
|
||||||
|
|
||||||
name = models.SlugField(
|
|
||||||
max_length=constants.TAG_NAME_MAX_LENGTH
|
|
||||||
)
|
|
||||||
|
|
||||||
statements = models.ManyToManyField(
|
|
||||||
STATEMENT_MODEL,
|
|
||||||
related_name='tags'
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
abstract = True
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
@ -1,31 +0,0 @@
|
|||||||
from django.contrib import admin
|
|
||||||
from chatterbot.ext.django_chatterbot.models import (
|
|
||||||
Statement, Response, Conversation, Tag
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class StatementAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ('text', )
|
|
||||||
list_filter = ('text', )
|
|
||||||
search_fields = ('text', )
|
|
||||||
|
|
||||||
|
|
||||||
class ResponseAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ('statement', 'response', 'occurrence', )
|
|
||||||
search_fields = ['statement__text', 'response__text']
|
|
||||||
|
|
||||||
|
|
||||||
class ConversationAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ('id', )
|
|
||||||
|
|
||||||
|
|
||||||
class TagAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ('name', )
|
|
||||||
list_filter = ('name', )
|
|
||||||
search_fields = ('name', )
|
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Statement, StatementAdmin)
|
|
||||||
admin.site.register(Response, ResponseAdmin)
|
|
||||||
admin.site.register(Conversation, ConversationAdmin)
|
|
||||||
admin.site.register(Tag, TagAdmin)
|
|
@ -1,8 +0,0 @@
|
|||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class DjangoChatterBotConfig(AppConfig):
|
|
||||||
|
|
||||||
name = 'chatterbot.ext.django_chatterbot'
|
|
||||||
label = 'django_chatterbot'
|
|
||||||
verbose_name = 'Django ChatterBot'
|
|
@ -1,42 +0,0 @@
|
|||||||
"""
|
|
||||||
These factories are used to generate fake data for testing.
|
|
||||||
"""
|
|
||||||
import factory
|
|
||||||
from chatterbot.ext.django_chatterbot import models
|
|
||||||
from chatterbot import constants
|
|
||||||
from factory.django import DjangoModelFactory
|
|
||||||
|
|
||||||
|
|
||||||
class StatementFactory(DjangoModelFactory):
|
|
||||||
|
|
||||||
text = factory.Faker(
|
|
||||||
'text',
|
|
||||||
max_nb_chars=constants.STATEMENT_TEXT_MAX_LENGTH
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = models.Statement
|
|
||||||
|
|
||||||
|
|
||||||
class ResponseFactory(DjangoModelFactory):
|
|
||||||
|
|
||||||
statement = factory.SubFactory(StatementFactory)
|
|
||||||
|
|
||||||
response = factory.SubFactory(StatementFactory)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = models.Response
|
|
||||||
|
|
||||||
|
|
||||||
class ConversationFactory(DjangoModelFactory):
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = models.Conversation
|
|
||||||
|
|
||||||
|
|
||||||
class TagFactory(DjangoModelFactory):
|
|
||||||
|
|
||||||
name = factory.Faker('word')
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = models.Tag
|
|
@ -1,29 +0,0 @@
|
|||||||
from django.core.management.base import BaseCommand
|
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
|
||||||
"""
|
|
||||||
A Django management command for calling a
|
|
||||||
chat bot's training method.
|
|
||||||
"""
|
|
||||||
|
|
||||||
help = 'Trains the database used by the chat bot'
|
|
||||||
can_import_settings = True
|
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
|
||||||
from chatterbot import ChatBot
|
|
||||||
from chatterbot.ext.django_chatterbot import settings
|
|
||||||
|
|
||||||
chatterbot = ChatBot(**settings.CHATTERBOT)
|
|
||||||
|
|
||||||
chatterbot.train(chatterbot.training_data)
|
|
||||||
|
|
||||||
# Django 1.8 does not define SUCCESS
|
|
||||||
if hasattr(self.style, 'SUCCESS'):
|
|
||||||
style = self.style.SUCCESS
|
|
||||||
else:
|
|
||||||
style = self.style.NOTICE
|
|
||||||
|
|
||||||
self.stdout.write(style('Starting training...'))
|
|
||||||
training_class = chatterbot.trainer.__class__.__name__
|
|
||||||
self.stdout.write(style('ChatterBot trained using "%s"' % training_class))
|
|
@ -1,39 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = []
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Response',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('occurrence', models.PositiveIntegerField(default=0)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Statement',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('text', models.CharField(max_length=255, unique=True)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='response',
|
|
||||||
name='response',
|
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='django_chatterbot.Statement'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='response',
|
|
||||||
name='statement',
|
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='in_response_to', to='django_chatterbot.Statement'),
|
|
||||||
),
|
|
||||||
]
|
|
@ -1,21 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Generated by Django 1.10.2 on 2016-10-30 12:13
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('django_chatterbot', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='statement',
|
|
||||||
name='extra_data',
|
|
||||||
field=models.CharField(default='{}', max_length=500),
|
|
||||||
preserve_default=False,
|
|
||||||
),
|
|
||||||
]
|
|
@ -1,20 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Generated by Django 1.9 on 2016-12-12 00:06
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('django_chatterbot', '0002_statement_extra_data'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='response',
|
|
||||||
name='occurrence',
|
|
||||||
field=models.PositiveIntegerField(default=1),
|
|
||||||
),
|
|
||||||
]
|
|
@ -1,26 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Generated by Django 1.10.3 on 2016-12-04 23:52
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('django_chatterbot', '0003_change_occurrence_default'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='response',
|
|
||||||
name='statement',
|
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='in_response', to='django_chatterbot.Statement'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='response',
|
|
||||||
name='response',
|
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='responses', to='django_chatterbot.Statement'),
|
|
||||||
),
|
|
||||||
]
|
|
@ -1,24 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Generated by Django 1.10.1 on 2016-12-29 19:20
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.utils.timezone
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('django_chatterbot', '0004_rename_in_response_to'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='statement',
|
|
||||||
name='created_at',
|
|
||||||
field=models.DateTimeField(
|
|
||||||
default=django.utils.timezone.now,
|
|
||||||
help_text='The date and time that this statement was created at.'
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
@ -1,33 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Generated by Django 1.9 on 2017-01-17 07:02
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
import django.utils.timezone
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('django_chatterbot', '0005_statement_created_at'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Conversation',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='statement',
|
|
||||||
name='created_at',
|
|
||||||
field=models.DateTimeField(default=django.utils.timezone.now, help_text='The date and time that this statement was created at.'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='conversation',
|
|
||||||
name='statements',
|
|
||||||
field=models.ManyToManyField(help_text='The statements in this conversation.', related_name='conversation', to='django_chatterbot.Statement'),
|
|
||||||
),
|
|
||||||
]
|
|
@ -1,24 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Generated by Django 1.11 on 2017-07-18 00:16
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.utils.timezone
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('django_chatterbot', '0006_create_conversation'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='response',
|
|
||||||
name='created_at',
|
|
||||||
field=models.DateTimeField(
|
|
||||||
default=django.utils.timezone.now,
|
|
||||||
help_text='The date and time that this response was created at.'
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
@ -1,32 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Generated by Django 1.11 on 2017-07-18 11:25
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('django_chatterbot', '0007_response_created_at'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='conversation',
|
|
||||||
name='statements',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='response',
|
|
||||||
name='occurrence',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='statement',
|
|
||||||
name='created_at',
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='conversation',
|
|
||||||
name='responses',
|
|
||||||
field=models.ManyToManyField(help_text='The responses in this conversation.', related_name='conversations', to='django_chatterbot.Response'),
|
|
||||||
),
|
|
||||||
]
|
|
@ -1,35 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Generated by Django 1.11a1 on 2017-07-07 00:12
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('django_chatterbot', '0008_update_conversations'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Tag',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('name', models.SlugField()),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'abstract': False,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='statement',
|
|
||||||
name='text',
|
|
||||||
field=models.CharField(max_length=255, unique=True),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='tag',
|
|
||||||
name='statements',
|
|
||||||
field=models.ManyToManyField(related_name='tags', to='django_chatterbot.Statement'),
|
|
||||||
),
|
|
||||||
]
|
|
@ -1,20 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Generated by Django 1.11.4 on 2017-08-16 00:56
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('django_chatterbot', '0009_tags'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='statement',
|
|
||||||
name='text',
|
|
||||||
field=models.CharField(max_length=400, unique=True),
|
|
||||||
),
|
|
||||||
]
|
|
@ -1,20 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Generated by Django 1.11.4 on 2017-08-20 13:55
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('django_chatterbot', '0010_statement_text'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='statement',
|
|
||||||
name='extra_data',
|
|
||||||
field=models.CharField(blank=True, max_length=500),
|
|
||||||
),
|
|
||||||
]
|
|
@ -1,34 +0,0 @@
|
|||||||
from chatterbot.ext.django_chatterbot.abstract_models import (
|
|
||||||
AbstractBaseConversation, AbstractBaseResponse,
|
|
||||||
AbstractBaseStatement, AbstractBaseTag
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class Statement(AbstractBaseStatement):
|
|
||||||
"""
|
|
||||||
A statement represents a single spoken entity, sentence or
|
|
||||||
phrase that someone can say.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class Response(AbstractBaseResponse):
|
|
||||||
"""
|
|
||||||
A connection between a statement and anther statement
|
|
||||||
that response to it.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class Conversation(AbstractBaseConversation):
|
|
||||||
"""
|
|
||||||
A sequence of statements representing a conversation.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class Tag(AbstractBaseTag):
|
|
||||||
"""
|
|
||||||
A label that categorizes a statement.
|
|
||||||
"""
|
|
||||||
pass
|
|
@ -1,19 +0,0 @@
|
|||||||
"""
|
|
||||||
Default ChatterBot settings for Django.
|
|
||||||
"""
|
|
||||||
from django.conf import settings
|
|
||||||
from chatterbot import constants
|
|
||||||
|
|
||||||
|
|
||||||
CHATTERBOT_SETTINGS = getattr(settings, 'CHATTERBOT', {})
|
|
||||||
|
|
||||||
CHATTERBOT_DEFAULTS = {
|
|
||||||
'name': 'ChatterBot',
|
|
||||||
'storage_adapter': 'chatterbot.storage.DjangoStorageAdapter',
|
|
||||||
'input_adapter': 'chatterbot.input.VariableInputTypeAdapter',
|
|
||||||
'output_adapter': 'chatterbot.output.OutputAdapter',
|
|
||||||
'django_app_name': constants.DEFAULT_DJANGO_APP_NAME
|
|
||||||
}
|
|
||||||
|
|
||||||
CHATTERBOT = CHATTERBOT_DEFAULTS.copy()
|
|
||||||
CHATTERBOT.update(CHATTERBOT_SETTINGS)
|
|
@ -1,11 +0,0 @@
|
|||||||
from django.conf.urls import url
|
|
||||||
from .views import ChatterBotView
|
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
url(
|
|
||||||
r'^$',
|
|
||||||
ChatterBotView.as_view(),
|
|
||||||
name='chatterbot',
|
|
||||||
),
|
|
||||||
]
|
|
@ -1,118 +0,0 @@
|
|||||||
import json
|
|
||||||
from django.views.generic import View
|
|
||||||
from django.http import JsonResponse
|
|
||||||
from chatterbot import ChatBot
|
|
||||||
from chatterbot.ext.django_chatterbot import settings
|
|
||||||
|
|
||||||
|
|
||||||
class ChatterBotViewMixin(object):
|
|
||||||
"""
|
|
||||||
Subclass this mixin for access to the 'chatterbot' attribute.
|
|
||||||
"""
|
|
||||||
|
|
||||||
chatterbot = ChatBot(**settings.CHATTERBOT)
|
|
||||||
|
|
||||||
def validate(self, data):
|
|
||||||
"""
|
|
||||||
Validate the data recieved from the client.
|
|
||||||
|
|
||||||
* The data should contain a text attribute.
|
|
||||||
"""
|
|
||||||
from django.core.exceptions import ValidationError
|
|
||||||
|
|
||||||
if 'text' not in data:
|
|
||||||
raise ValidationError('The attribute "text" is required.')
|
|
||||||
|
|
||||||
def get_conversation(self, request):
|
|
||||||
"""
|
|
||||||
Return the conversation for the session if one exists.
|
|
||||||
Create a new conversation if one does not exist.
|
|
||||||
"""
|
|
||||||
from chatterbot.ext.django_chatterbot.models import Conversation, Response
|
|
||||||
|
|
||||||
class Obj(object):
|
|
||||||
def __init__(self):
|
|
||||||
self.id = None
|
|
||||||
self.statements = []
|
|
||||||
|
|
||||||
conversation = Obj()
|
|
||||||
|
|
||||||
conversation.id = request.session.get('conversation_id', 0)
|
|
||||||
existing_conversation = False
|
|
||||||
try:
|
|
||||||
Conversation.objects.get(id=conversation.id)
|
|
||||||
existing_conversation = True
|
|
||||||
|
|
||||||
except Conversation.DoesNotExist:
|
|
||||||
conversation_id = self.chatterbot.storage.create_conversation()
|
|
||||||
request.session['conversation_id'] = conversation_id
|
|
||||||
conversation.id = conversation_id
|
|
||||||
|
|
||||||
if existing_conversation:
|
|
||||||
responses = Response.objects.filter(
|
|
||||||
conversations__id=conversation.id
|
|
||||||
)
|
|
||||||
|
|
||||||
for response in responses:
|
|
||||||
conversation.statements.append(response.statement.serialize())
|
|
||||||
conversation.statements.append(response.response.serialize())
|
|
||||||
|
|
||||||
return conversation
|
|
||||||
|
|
||||||
|
|
||||||
class ChatterBotView(ChatterBotViewMixin, View):
|
|
||||||
"""
|
|
||||||
Provide an API endpoint to interact with ChatterBot.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
Return a response to the statement in the posted data.
|
|
||||||
"""
|
|
||||||
input_data = json.loads(request.read().decode('utf-8'))
|
|
||||||
|
|
||||||
self.validate(input_data)
|
|
||||||
|
|
||||||
conversation = self.get_conversation(request)
|
|
||||||
|
|
||||||
response = self.chatterbot.get_response(input_data, conversation.id)
|
|
||||||
response_data = response.serialize()
|
|
||||||
|
|
||||||
return JsonResponse(response_data, status=200)
|
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
Return data corresponding to the current conversation.
|
|
||||||
"""
|
|
||||||
conversation = self.get_conversation(request)
|
|
||||||
|
|
||||||
data = {
|
|
||||||
'detail': 'You should make a POST request to this endpoint.',
|
|
||||||
'name': self.chatterbot.name,
|
|
||||||
'conversation': conversation.statements
|
|
||||||
}
|
|
||||||
|
|
||||||
# Return a method not allowed response
|
|
||||||
return JsonResponse(data, status=405)
|
|
||||||
|
|
||||||
def patch(self, request, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
The patch method is not allowed for this endpoint.
|
|
||||||
"""
|
|
||||||
data = {
|
|
||||||
'detail': 'You should make a POST request to this endpoint.'
|
|
||||||
}
|
|
||||||
|
|
||||||
# Return a method not allowed response
|
|
||||||
return JsonResponse(data, status=405)
|
|
||||||
|
|
||||||
def delete(self, request, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
The delete method is not allowed for this endpoint.
|
|
||||||
"""
|
|
||||||
data = {
|
|
||||||
'detail': 'You should make a POST request to this endpoint.'
|
|
||||||
}
|
|
||||||
|
|
||||||
# Return a method not allowed response
|
|
||||||
return JsonResponse(data, status=405)
|
|
@ -1,12 +1,9 @@
|
|||||||
from .storage_adapter import StorageAdapter
|
|
||||||
from .django_storage import DjangoStorageAdapter
|
|
||||||
from .mongodb import MongoDatabaseAdapter
|
from .mongodb import MongoDatabaseAdapter
|
||||||
from .sql_storage import SQLStorageAdapter
|
from .sql_storage import SQLStorageAdapter
|
||||||
|
from .storage_adapter import StorageAdapter
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'StorageAdapter',
|
'StorageAdapter',
|
||||||
'DjangoStorageAdapter',
|
|
||||||
'MongoDatabaseAdapter',
|
'MongoDatabaseAdapter',
|
||||||
'SQLStorageAdapter',
|
'SQLStorageAdapter',
|
||||||
)
|
)
|
||||||
|
@ -1,220 +0,0 @@
|
|||||||
from chatter.chatterbot.storage import StorageAdapter
|
|
||||||
from chatter.chatterbot import constants
|
|
||||||
|
|
||||||
|
|
||||||
class DjangoStorageAdapter(StorageAdapter):
|
|
||||||
"""
|
|
||||||
Storage adapter that allows ChatterBot to interact with
|
|
||||||
Django storage backends.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
super(DjangoStorageAdapter, self).__init__(**kwargs)
|
|
||||||
|
|
||||||
self.adapter_supports_queries = False
|
|
||||||
self.django_app_name = kwargs.get(
|
|
||||||
'django_app_name',
|
|
||||||
constants.DEFAULT_DJANGO_APP_NAME
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_statement_model(self):
|
|
||||||
from django.apps import apps
|
|
||||||
return apps.get_model(self.django_app_name, 'Statement')
|
|
||||||
|
|
||||||
def get_response_model(self):
|
|
||||||
from django.apps import apps
|
|
||||||
return apps.get_model(self.django_app_name, 'Response')
|
|
||||||
|
|
||||||
def get_conversation_model(self):
|
|
||||||
from django.apps import apps
|
|
||||||
return apps.get_model(self.django_app_name, 'Conversation')
|
|
||||||
|
|
||||||
def get_tag_model(self):
|
|
||||||
from django.apps import apps
|
|
||||||
return apps.get_model(self.django_app_name, 'Tag')
|
|
||||||
|
|
||||||
def count(self):
|
|
||||||
Statement = self.get_model('statement')
|
|
||||||
return Statement.objects.count()
|
|
||||||
|
|
||||||
def find(self, statement_text):
|
|
||||||
Statement = self.get_model('statement')
|
|
||||||
try:
|
|
||||||
return Statement.objects.get(text=statement_text)
|
|
||||||
except Statement.DoesNotExist as e:
|
|
||||||
self.logger.info(str(e))
|
|
||||||
return None
|
|
||||||
|
|
||||||
def filter(self, **kwargs):
|
|
||||||
"""
|
|
||||||
Returns a list of statements in the database
|
|
||||||
that match the parameters specified.
|
|
||||||
"""
|
|
||||||
from django.db.models import Q
|
|
||||||
Statement = self.get_model('statement')
|
|
||||||
|
|
||||||
order = kwargs.pop('order_by', None)
|
|
||||||
|
|
||||||
RESPONSE_CONTAINS = 'in_response_to__contains'
|
|
||||||
|
|
||||||
if RESPONSE_CONTAINS in kwargs:
|
|
||||||
value = kwargs[RESPONSE_CONTAINS]
|
|
||||||
del kwargs[RESPONSE_CONTAINS]
|
|
||||||
kwargs['in_response__response__text'] = value
|
|
||||||
|
|
||||||
kwargs_copy = kwargs.copy()
|
|
||||||
|
|
||||||
for kwarg in kwargs_copy:
|
|
||||||
value = kwargs[kwarg]
|
|
||||||
del kwargs[kwarg]
|
|
||||||
kwarg = kwarg.replace('in_response_to', 'in_response')
|
|
||||||
kwargs[kwarg] = value
|
|
||||||
|
|
||||||
if 'in_response' in kwargs:
|
|
||||||
responses = kwargs['in_response']
|
|
||||||
del kwargs['in_response']
|
|
||||||
|
|
||||||
if responses:
|
|
||||||
kwargs['in_response__response__text__in'] = []
|
|
||||||
for response in responses:
|
|
||||||
kwargs['in_response__response__text__in'].append(response)
|
|
||||||
else:
|
|
||||||
kwargs['in_response'] = None
|
|
||||||
|
|
||||||
parameters = {}
|
|
||||||
if 'in_response__response__text' in kwargs:
|
|
||||||
value = kwargs['in_response__response__text']
|
|
||||||
parameters['responses__statement__text'] = value
|
|
||||||
|
|
||||||
statements = Statement.objects.filter(Q(**kwargs) | Q(**parameters))
|
|
||||||
|
|
||||||
if order:
|
|
||||||
statements = statements.order_by(order)
|
|
||||||
|
|
||||||
return statements
|
|
||||||
|
|
||||||
def update(self, statement):
|
|
||||||
"""
|
|
||||||
Update the provided statement.
|
|
||||||
"""
|
|
||||||
Statement = self.get_model('statement')
|
|
||||||
Response = self.get_model('response')
|
|
||||||
|
|
||||||
response_statement_cache = statement.response_statement_cache
|
|
||||||
|
|
||||||
statement, created = Statement.objects.get_or_create(text=statement.text)
|
|
||||||
statement.extra_data = getattr(statement, 'extra_data', '')
|
|
||||||
statement.save()
|
|
||||||
|
|
||||||
for _response_statement in response_statement_cache:
|
|
||||||
|
|
||||||
response_statement, created = Statement.objects.get_or_create(
|
|
||||||
text=_response_statement.text
|
|
||||||
)
|
|
||||||
response_statement.extra_data = getattr(_response_statement, 'extra_data', '')
|
|
||||||
response_statement.save()
|
|
||||||
|
|
||||||
Response.objects.create(
|
|
||||||
statement=response_statement,
|
|
||||||
response=statement
|
|
||||||
)
|
|
||||||
|
|
||||||
return statement
|
|
||||||
|
|
||||||
def get_random(self):
|
|
||||||
"""
|
|
||||||
Returns a random statement from the database
|
|
||||||
"""
|
|
||||||
Statement = self.get_model('statement')
|
|
||||||
return Statement.objects.order_by('?').first()
|
|
||||||
|
|
||||||
def remove(self, statement_text):
|
|
||||||
"""
|
|
||||||
Removes the statement that matches the input text.
|
|
||||||
Removes any responses from statements if the response text matches the
|
|
||||||
input text.
|
|
||||||
"""
|
|
||||||
from django.db.models import Q
|
|
||||||
|
|
||||||
Statement = self.get_model('statement')
|
|
||||||
Response = self.get_model('response')
|
|
||||||
|
|
||||||
statements = Statement.objects.filter(text=statement_text)
|
|
||||||
|
|
||||||
responses = Response.objects.filter(
|
|
||||||
Q(statement__text=statement_text) | Q(response__text=statement_text)
|
|
||||||
)
|
|
||||||
|
|
||||||
responses.delete()
|
|
||||||
statements.delete()
|
|
||||||
|
|
||||||
def get_latest_response(self, conversation_id):
|
|
||||||
"""
|
|
||||||
Returns the latest response in a conversation if it exists.
|
|
||||||
Returns None if a matching conversation cannot be found.
|
|
||||||
"""
|
|
||||||
Response = self.get_model('response')
|
|
||||||
|
|
||||||
response = Response.objects.filter(
|
|
||||||
conversations__id=conversation_id
|
|
||||||
).order_by(
|
|
||||||
'created_at'
|
|
||||||
).last()
|
|
||||||
|
|
||||||
if not response:
|
|
||||||
return None
|
|
||||||
|
|
||||||
return response.response
|
|
||||||
|
|
||||||
def create_conversation(self):
|
|
||||||
"""
|
|
||||||
Create a new conversation.
|
|
||||||
"""
|
|
||||||
Conversation = self.get_model('conversation')
|
|
||||||
conversation = Conversation.objects.create()
|
|
||||||
return conversation.id
|
|
||||||
|
|
||||||
def add_to_conversation(self, conversation_id, statement, response):
|
|
||||||
"""
|
|
||||||
Add the statement and response to the conversation.
|
|
||||||
"""
|
|
||||||
Statement = self.get_model('statement')
|
|
||||||
Response = self.get_model('response')
|
|
||||||
|
|
||||||
first_statement, created = Statement.objects.get_or_create(text=statement.text)
|
|
||||||
first_response, created = Statement.objects.get_or_create(text=response.text)
|
|
||||||
|
|
||||||
response = Response.objects.create(
|
|
||||||
statement=first_statement,
|
|
||||||
response=first_response
|
|
||||||
)
|
|
||||||
|
|
||||||
response.conversations.add(conversation_id)
|
|
||||||
|
|
||||||
def drop(self):
|
|
||||||
"""
|
|
||||||
Remove all data from the database.
|
|
||||||
"""
|
|
||||||
Statement = self.get_model('statement')
|
|
||||||
Response = self.get_model('response')
|
|
||||||
Conversation = self.get_model('conversation')
|
|
||||||
Tag = self.get_model('tag')
|
|
||||||
|
|
||||||
Statement.objects.all().delete()
|
|
||||||
Response.objects.all().delete()
|
|
||||||
Conversation.objects.all().delete()
|
|
||||||
Tag.objects.all().delete()
|
|
||||||
|
|
||||||
def get_response_statements(self):
|
|
||||||
"""
|
|
||||||
Return only statements that are in response to another statement.
|
|
||||||
A statement must exist which lists the closest matching statement in the
|
|
||||||
in_response_to field. Otherwise, the logic adapter may find a closest
|
|
||||||
matching statement that does not have a known response.
|
|
||||||
"""
|
|
||||||
Statement = self.get_model('statement')
|
|
||||||
Response = self.get_model('response')
|
|
||||||
|
|
||||||
responses = Response.objects.all()
|
|
||||||
|
|
||||||
return Statement.objects.filter(in_response__in=responses)
|
|
Loading…
Reference in new issue