You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Fox-V3/chatter/source/ext/django_chatterbot/abstract_models.py

262 lines
6.8 KiB

7 years ago
from ...conversation import StatementMixin
from ... 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