commit
48b6e1ed14
@ -1,5 +1,11 @@
|
||||
from .chatter import Chatter
|
||||
from . import chatterbot
|
||||
from .chat import Chatter
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(Chatter(bot))
|
||||
|
||||
|
||||
__all__ = (
|
||||
'chatterbot'
|
||||
)
|
||||
|
@ -5,8 +5,8 @@ import discord
|
||||
from discord.ext import commands
|
||||
from redbot.core import Config
|
||||
|
||||
from .source import ChatBot
|
||||
from .source.trainers import ListTrainer
|
||||
from chatter.chatterbot import ChatBot
|
||||
from chatter.chatterbot.trainers import ListTrainer
|
||||
|
||||
|
||||
class Chatter:
|
||||
@ -23,7 +23,11 @@ class Chatter:
|
||||
"days": 1
|
||||
}
|
||||
|
||||
self.chatbot = ChatBot("ChatterBot")
|
||||
self.chatbot = ChatBot(
|
||||
"ChatterBot",
|
||||
storage_adapter='chatter.chatterbot.storage.SQLStorageAdapter',
|
||||
database='./database.sqlite3'
|
||||
)
|
||||
self.chatbot.set_trainer(ListTrainer)
|
||||
|
||||
self.config.register_global(**default_global)
|
||||
@ -88,7 +92,20 @@ class Chatter:
|
||||
await ctx.send("Success")
|
||||
|
||||
@chatter.command()
|
||||
async def train(self, ctx: commands.Context, channel: discord.TextChannel = None):
|
||||
async def backup(self, ctx, backupname):
|
||||
"""
|
||||
Backup your training data to a json for later use
|
||||
"""
|
||||
await ctx.send("Backing up data, this may take a while")
|
||||
future = await self.loop.run_in_executor(None, self.chatbot.trainer.export_for_training, './{}.json'.format(backupname))
|
||||
|
||||
if future:
|
||||
await ctx.send("Backup successful!")
|
||||
else:
|
||||
await ctx.send("Error occurred :(")
|
||||
|
||||
@chatter.command()
|
||||
async def train(self, ctx: commands.Context, channel: discord.TextChannel):
|
||||
"""
|
||||
Trains the bot based on language in this guild
|
||||
"""
|
||||
@ -130,7 +147,9 @@ class Chatter:
|
||||
return
|
||||
text = text.replace(to_strip, "", 1)
|
||||
async with channel.typing():
|
||||
response = self.chatbot.get_response(text)
|
||||
if not response:
|
||||
response = ":thinking:"
|
||||
await channel.send(response)
|
||||
future = await self.loop.run_in_executor(None, self.chatbot.get_response, text)
|
||||
|
||||
if future:
|
||||
await channel.send(str(future))
|
||||
else:
|
||||
await channel.send(':thinking:')
|
@ -3,7 +3,7 @@ ChatterBot is a machine learning, conversational dialog engine.
|
||||
"""
|
||||
from .chatterbot import ChatBot
|
||||
|
||||
__version__ = '0.8.4'
|
||||
__version__ = '0.8.5'
|
||||
__author__ = 'Gunther Cox'
|
||||
__email__ = 'gunthercx@gmail.com'
|
||||
__url__ = 'https://github.com/gunthercox/ChatterBot'
|
@ -1,6 +1,5 @@
|
||||
import sys
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import importlib
|
||||
|
@ -16,7 +16,7 @@ class Adapter(object):
|
||||
"""
|
||||
Gives the adapter access to an instance of the ChatBot class.
|
||||
|
||||
:param chatbot: A chat bot instanse.
|
||||
:param chatbot: A chat bot instance.
|
||||
:type chatbot: ChatBot
|
||||
"""
|
||||
self.chatbot = chatbot
|
@ -1,9 +1,11 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import logging
|
||||
from .storage import StorageAdapter
|
||||
|
||||
from . import utils
|
||||
from .input import InputAdapter
|
||||
from .output import OutputAdapter
|
||||
from . import utils
|
||||
from .storage import StorageAdapter
|
||||
|
||||
|
||||
class ChatBot(object):
|
||||
@ -20,15 +22,15 @@ class ChatBot(object):
|
||||
|
||||
self.default_session = None
|
||||
|
||||
storage_adapter = kwargs.get('storage_adapter', 'chatter.source.storage.SQLStorageAdapter')
|
||||
storage_adapter = kwargs.get('storage_adapter', 'chatter.chatterbot.storage.SQLStorageAdapter')
|
||||
|
||||
logic_adapters = kwargs.get('logic_adapters', [
|
||||
'chatter.source.logic.BestMatch'
|
||||
'chatter.chatterbot.logic.BestMatch'
|
||||
])
|
||||
|
||||
input_adapter = kwargs.get('input_adapter', 'chatter.source.input.VariableInputTypeAdapter')
|
||||
input_adapter = kwargs.get('input_adapter', 'chatter.chatterbot.input.VariableInputTypeAdapter')
|
||||
|
||||
output_adapter = kwargs.get('output_adapter', 'chatter.source.output.OutputAdapter')
|
||||
output_adapter = kwargs.get('output_adapter', 'chatter.chatterbot.output.OutputAdapter')
|
||||
|
||||
# Check that each adapter is a valid subclass of it's respective parent
|
||||
utils.validate_adapter_class(storage_adapter, StorageAdapter)
|
||||
@ -45,7 +47,7 @@ class ChatBot(object):
|
||||
|
||||
# Add required system logic adapter
|
||||
self.logic.system_adapters.append(
|
||||
utils.initialize_class('chatter.source.logic.NoKnowledgeAdapter', **kwargs)
|
||||
utils.initialize_class('chatter.chatterbot.logic.NoKnowledgeAdapter', **kwargs)
|
||||
)
|
||||
|
||||
for adapter in logic_adapters:
|
||||
@ -59,7 +61,7 @@ class ChatBot(object):
|
||||
|
||||
preprocessors = kwargs.get(
|
||||
'preprocessors', [
|
||||
'chatter.source.preprocessors.clean_whitespace'
|
||||
'chatter.chatterbot.preprocessors.clean_whitespace'
|
||||
]
|
||||
)
|
||||
|
||||
@ -69,7 +71,7 @@ class ChatBot(object):
|
||||
self.preprocessors.append(utils.import_module(preprocessor))
|
||||
|
||||
# Use specified trainer or fall back to the default
|
||||
trainer = kwargs.get('trainer', 'chatter.source.trainers.Trainer')
|
||||
trainer = kwargs.get('trainer', 'chatter.chatterbot.trainers.Trainer')
|
||||
TrainerClass = utils.import_module(trainer)
|
||||
self.trainer = TrainerClass(self.storage, **kwargs)
|
||||
self.training_data = kwargs.get('training_data')
|
@ -1,5 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
|
||||
|
||||
"""
|
||||
@ -58,19 +57,14 @@ class LevenshteinDistance(Comparator):
|
||||
:rtype: float
|
||||
"""
|
||||
|
||||
PYTHON = sys.version_info[0]
|
||||
|
||||
# Return 0 if either statement has a falsy text value
|
||||
if not statement.text or not other_statement.text:
|
||||
return 0
|
||||
|
||||
# Get the lowercase version of both strings
|
||||
if PYTHON < 3:
|
||||
statement_text = unicode(statement.text.lower()) # NOQA
|
||||
other_statement_text = unicode(other_statement.text.lower()) # NOQA
|
||||
else:
|
||||
statement_text = str(statement.text.lower())
|
||||
other_statement_text = str(other_statement.text.lower())
|
||||
|
||||
statement_text = str(statement.text.lower())
|
||||
other_statement_text = str(other_statement.text.lower())
|
||||
|
||||
similarity = SequenceMatcher(
|
||||
None,
|
||||
@ -130,7 +124,7 @@ class SynsetDistance(Comparator):
|
||||
"""
|
||||
from nltk.corpus import wordnet
|
||||
from nltk import word_tokenize
|
||||
from . import utils
|
||||
from chatter.chatterbot import utils
|
||||
import itertools
|
||||
|
||||
tokens1 = word_tokenize(statement.text.lower())
|
@ -25,7 +25,6 @@ class Statement(StatementMixin):
|
||||
"""
|
||||
|
||||
def __init__(self, text, **kwargs):
|
||||
import sys
|
||||
|
||||
# Try not to allow non-string types to be passed to statements
|
||||
try:
|
||||
@ -33,13 +32,6 @@ class Statement(StatementMixin):
|
||||
except UnicodeEncodeError:
|
||||
pass
|
||||
|
||||
# Prefer decoded utf8-strings in Python 2.7
|
||||
if sys.version_info[0] < 3:
|
||||
try:
|
||||
text = text.decode('utf-8')
|
||||
except UnicodeEncodeError:
|
||||
pass
|
||||
|
||||
self.text = text
|
||||
self.tags = kwargs.pop('tags', [])
|
||||
self.in_response_to = kwargs.pop('in_response_to', [])
|
@ -5,7 +5,6 @@ View the corpus on GitHub at https://github.com/gunthercox/chatterbot-corpus
|
||||
|
||||
from chatterbot_corpus import Corpus
|
||||
|
||||
|
||||
__all__ = (
|
||||
'Corpus',
|
||||
)
|
@ -1,11 +1,11 @@
|
||||
from sqlalchemy import Table, Column, Integer, DateTime, ForeignKey, PickleType
|
||||
from sqlalchemy.ext.declarative import declared_attr, declarative_base
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.sql import func
|
||||
from sqlalchemy.ext.declarative import declared_attr, declarative_base
|
||||
|
||||
from ...constants import TAG_NAME_MAX_LENGTH, STATEMENT_TEXT_MAX_LENGTH
|
||||
from .types import UnicodeString
|
||||
from ...conversation import StatementMixin
|
||||
from chatter.chatterbot.constants import TAG_NAME_MAX_LENGTH, STATEMENT_TEXT_MAX_LENGTH
|
||||
from chatter.chatterbot.conversation import StatementMixin
|
||||
from chatter.chatterbot.ext.sqlalchemy_app.types import UnicodeString
|
||||
|
||||
|
||||
class ModelBase(object):
|
||||
@ -29,7 +29,6 @@ class ModelBase(object):
|
||||
|
||||
Base = declarative_base(cls=ModelBase)
|
||||
|
||||
|
||||
tag_association_table = Table(
|
||||
'tag_association',
|
||||
Base.metadata,
|
||||
@ -73,8 +72,8 @@ class Statement(Base, StatementMixin):
|
||||
return [tag.name for tag in self.tags]
|
||||
|
||||
def get_statement(self):
|
||||
from ...conversation import Statement as StatementObject
|
||||
from ...conversation import Response as ResponseObject
|
||||
from chatter.chatterbot.conversation import Statement as StatementObject
|
||||
from chatter.chatterbot.conversation import Response as ResponseObject
|
||||
|
||||
statement = StatementObject(
|
||||
self.text,
|
@ -13,9 +13,4 @@ class UnicodeString(TypeDecorator):
|
||||
Coerce Python bytestrings to unicode before
|
||||
saving them to the database.
|
||||
"""
|
||||
import sys
|
||||
|
||||
if sys.version_info[0] < 3:
|
||||
if isinstance(value, str):
|
||||
value = value.decode('utf-8')
|
||||
return value
|
@ -1,12 +1,11 @@
|
||||
from .input_adapter import InputAdapter
|
||||
from .microsoft import Microsoft
|
||||
from .gitter import Gitter
|
||||
from .hipchat import HipChat
|
||||
from .mailgun import Mailgun
|
||||
from .microsoft import Microsoft
|
||||
from .terminal import TerminalAdapter
|
||||
from .variable_input_type_adapter import VariableInputTypeAdapter
|
||||
|
||||
|
||||
__all__ = (
|
||||
'InputAdapter',
|
||||
'Microsoft',
|
@ -1,7 +1,9 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from time import sleep
|
||||
from . import InputAdapter
|
||||
from ..conversation import Statement
|
||||
|
||||
from chatter.chatterbot.conversation import Statement
|
||||
from chatter.chatterbot.input import InputAdapter
|
||||
|
||||
|
||||
class Gitter(InputAdapter):
|
@ -1,7 +1,9 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from time import sleep
|
||||
from . import InputAdapter
|
||||
from ..conversation import Statement
|
||||
|
||||
from chatter.chatterbot.conversation import Statement
|
||||
from chatter.chatterbot.input import InputAdapter
|
||||
|
||||
|
||||
class HipChat(InputAdapter):
|
@ -1,5 +1,6 @@
|
||||
from __future__ import unicode_literals
|
||||
from ..adapters import Adapter
|
||||
|
||||
from chatter.chatterbot.adapters import Adapter
|
||||
|
||||
|
||||
class InputAdapter(Adapter):
|
@ -1,7 +1,9 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
from . import InputAdapter
|
||||
from ..conversation import Statement
|
||||
|
||||
from chatter.chatterbot.conversation import Statement
|
||||
from chatter.chatterbot.input import InputAdapter
|
||||
|
||||
|
||||
class Mailgun(InputAdapter):
|
@ -1,7 +1,9 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from time import sleep
|
||||
from . import InputAdapter
|
||||
from ..conversation import Statement
|
||||
|
||||
from chatter.chatterbot.conversation import Statement
|
||||
from chatter.chatterbot.input import InputAdapter
|
||||
|
||||
|
||||
class Microsoft(InputAdapter):
|
||||
@ -21,10 +23,10 @@ class Microsoft(InputAdapter):
|
||||
|
||||
# NOTE: Direct Line client credentials are different from your bot's
|
||||
# credentials
|
||||
self.direct_line_token_or_secret = kwargs.\
|
||||
self.direct_line_token_or_secret = kwargs. \
|
||||
get('direct_line_token_or_secret')
|
||||
|
||||
authorization_header = 'BotConnector {}'.\
|
||||
authorization_header = 'BotConnector {}'. \
|
||||
format(self.direct_line_token_or_secret)
|
||||
|
||||
self.headers = {
|
||||
@ -62,7 +64,7 @@ class Microsoft(InputAdapter):
|
||||
def get_most_recent_message(self):
|
||||
import requests
|
||||
|
||||
endpoint = '{host}/api/conversations/{id}/messages'\
|
||||
endpoint = '{host}/api/conversations/{id}/messages' \
|
||||
.format(host=self.directline_host,
|
||||
id=self.conversation_id)
|
||||
|
@ -1,7 +1,8 @@
|
||||
from __future__ import unicode_literals
|
||||
from . import InputAdapter
|
||||
from ..conversation import Statement
|
||||
from ..utils import input_function
|
||||
|
||||
from chatter.chatterbot.conversation import Statement
|
||||
from chatter.chatterbot.input import InputAdapter
|
||||
from chatter.chatterbot.utils import input_function
|
||||
|
||||
|
||||
class TerminalAdapter(InputAdapter):
|
@ -1,22 +1,18 @@
|
||||
from __future__ import unicode_literals
|
||||
from . import InputAdapter
|
||||
from ..conversation import Statement
|
||||
|
||||
from chatter.chatterbot.conversation import Statement
|
||||
from chatter.chatterbot.input import InputAdapter
|
||||
|
||||
|
||||
class VariableInputTypeAdapter(InputAdapter):
|
||||
|
||||
JSON = 'json'
|
||||
TEXT = 'text'
|
||||
OBJECT = 'object'
|
||||
VALID_FORMATS = (JSON, TEXT, OBJECT, )
|
||||
VALID_FORMATS = (JSON, TEXT, OBJECT,)
|
||||
|
||||
def detect_type(self, statement):
|
||||
import sys
|
||||
|
||||
if sys.version_info[0] < 3:
|
||||
string_types = basestring # NOQA
|
||||
else:
|
||||
string_types = str
|
||||
string_types = str
|
||||
|
||||
if hasattr(statement, 'text'):
|
||||
return self.OBJECT
|
@ -1,5 +1,5 @@
|
||||
from .logic_adapter import LogicAdapter
|
||||
from .best_match import BestMatch
|
||||
from .logic_adapter import LogicAdapter
|
||||
from .low_confidence import LowConfidenceAdapter
|
||||
from .mathematical_evaluation import MathematicalEvaluation
|
||||
from .multi_adapter import MultiLogicAdapter
|
||||
@ -7,7 +7,6 @@ from .no_knowledge_adapter import NoKnowledgeAdapter
|
||||
from .specific_response import SpecificResponseAdapter
|
||||
from .time_adapter import TimeLogicAdapter
|
||||
|
||||
|
||||
__all__ = (
|
||||
'LogicAdapter',
|
||||
'BestMatch',
|
@ -1,4 +1,5 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .logic_adapter import LogicAdapter
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
from __future__ import unicode_literals
|
||||
from ..adapters import Adapter
|
||||
from ..utils import import_module
|
||||
|
||||
from chatter.chatterbot.adapters import Adapter
|
||||
from chatter.chatterbot.utils import import_module
|
||||
|
||||
|
||||
class LogicAdapter(Adapter):
|
||||
@ -17,8 +18,8 @@ class LogicAdapter(Adapter):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(LogicAdapter, self).__init__(**kwargs)
|
||||
from ..comparisons import levenshtein_distance
|
||||
from ..response_selection import get_first_response
|
||||
from chatter.chatterbot.comparisons import levenshtein_distance
|
||||
from chatter.chatterbot.response_selection import get_first_response
|
||||
|
||||
# Import string module parameters
|
||||
if 'statement_comparison_function' in kwargs:
|
@ -1,5 +1,6 @@
|
||||
from __future__ import unicode_literals
|
||||
from ..conversation import Statement
|
||||
|
||||
from chatter.chatterbot.conversation import Statement
|
||||
from .best_match import BestMatch
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
from __future__ import unicode_literals
|
||||
from . import LogicAdapter
|
||||
from ..conversation import Statement
|
||||
|
||||
from chatter.chatterbot.conversation import Statement
|
||||
from chatter.chatterbot.logic import LogicAdapter
|
||||
|
||||
|
||||
class MathematicalEvaluation(LogicAdapter):
|
@ -1,6 +1,8 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from collections import Counter
|
||||
from .. import utils
|
||||
|
||||
from chatter.chatterbot import utils
|
||||
from .logic_adapter import LogicAdapter
|
||||
|
||||
|
||||
@ -13,7 +15,7 @@ class MultiLogicAdapter(LogicAdapter):
|
||||
"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
super(MultiLogicAdapter, self).__init__(**kwargs)
|
||||
|
||||
# Logic adapters added by the chat bot
|
||||
self.adapters = []
|
||||
@ -49,7 +51,7 @@ class MultiLogicAdapter(LogicAdapter):
|
||||
if adapter.can_process(statement):
|
||||
|
||||
output = adapter.process(statement)
|
||||
results.append((output.confidence, output, ))
|
||||
results.append((output.confidence, output,))
|
||||
|
||||
self.logger.info(
|
||||
'{} selected "{}" as a response with a confidence of {}'.format(
|
@ -1,4 +1,5 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .logic_adapter import LogicAdapter
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .logic_adapter import LogicAdapter
|
||||
|
||||
|
||||
@ -15,7 +16,7 @@ class SpecificResponseAdapter(LogicAdapter):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(SpecificResponseAdapter, self).__init__(**kwargs)
|
||||
from ..conversation import Statement
|
||||
from chatter.chatterbot.conversation import Statement
|
||||
|
||||
self.input_text = kwargs.get('input_text')
|
||||
|
@ -1,5 +1,7 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from .logic_adapter import LogicAdapter
|
||||
|
||||
|
||||
@ -40,8 +42,8 @@ class TimeLogicAdapter(LogicAdapter):
|
||||
])
|
||||
|
||||
labeled_data = (
|
||||
[(name, 0) for name in self.negative] +
|
||||
[(name, 1) for name in self.positive]
|
||||
[(name, 0) for name in self.negative] +
|
||||
[(name, 1) for name in self.positive]
|
||||
)
|
||||
|
||||
train_set = [
|
||||
@ -79,7 +81,7 @@ class TimeLogicAdapter(LogicAdapter):
|
||||
return features
|
||||
|
||||
def process(self, statement):
|
||||
from ..conversation import Statement
|
||||
from chatter.chatterbot.conversation import Statement
|
||||
|
||||
now = datetime.now()
|
||||
|
@ -1,9 +1,9 @@
|
||||
from .output_adapter import OutputAdapter
|
||||
from .microsoft import Microsoft
|
||||
from .terminal import TerminalAdapter
|
||||
from .mailgun import Mailgun
|
||||
from .gitter import Gitter
|
||||
from .hipchat import HipChat
|
||||
from .mailgun import Mailgun
|
||||
from .microsoft import Microsoft
|
||||
from .output_adapter import OutputAdapter
|
||||
from .terminal import TerminalAdapter
|
||||
|
||||
__all__ = (
|
||||
'OutputAdapter',
|
@ -1,4 +1,5 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .output_adapter import OutputAdapter
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import json
|
||||
|
||||
from .output_adapter import OutputAdapter
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .output_adapter import OutputAdapter
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import json
|
||||
|
||||
from .output_adapter import OutputAdapter
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
from ..adapters import Adapter
|
||||
from chatter.chatterbot.adapters import Adapter
|
||||
|
||||
|
||||
class OutputAdapter(Adapter):
|
@ -1,4 +1,5 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .output_adapter import OutputAdapter
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import calendar
|
||||
import re
|
||||
from datetime import timedelta, datetime
|
||||
import calendar
|
||||
|
||||
# Variations of dates that the parser can capture
|
||||
year_variations = ['year', 'years', 'yrs']
|
@ -27,14 +27,9 @@ def unescape_html(chatbot, statement):
|
||||
Convert escaped html characters into unescaped html characters.
|
||||
For example: "<b>" becomes "<b>".
|
||||
"""
|
||||
import sys
|
||||
|
||||
# Replace HTML escape characters
|
||||
if sys.version_info[0] < 3:
|
||||
from HTMLParser import HTMLParser
|
||||
html = HTMLParser()
|
||||
else:
|
||||
import html
|
||||
import html
|
||||
|
||||
statement.text = html.unescape(statement.text)
|
||||
|
||||
@ -47,11 +42,6 @@ def convert_to_ascii(chatbot, statement):
|
||||
For example: "på fédéral" becomes "pa federal".
|
||||
"""
|
||||
import unicodedata
|
||||
import sys
|
||||
|
||||
# Normalize unicode characters
|
||||
if sys.version_info[0] < 3:
|
||||
statement.text = unicode(statement.text) # NOQA
|
||||
|
||||
text = unicodedata.normalize('NFKD', statement.text)
|
||||
text = text.encode('ascii', 'ignore').decode('utf-8')
|
@ -1,12 +1,9 @@
|
||||
from .storage_adapter import StorageAdapter
|
||||
from .django_storage import DjangoStorageAdapter
|
||||
from .mongodb import MongoDatabaseAdapter
|
||||
from .sql_storage import SQLStorageAdapter
|
||||
|
||||
|
||||
__all__ = (
|
||||
'StorageAdapter',
|
||||
'DjangoStorageAdapter',
|
||||
'MongoDatabaseAdapter',
|
||||
'SQLStorageAdapter',
|
||||
)
|
@ -1,10 +1,13 @@
|
||||
from . import StorageAdapter
|
||||
from chatter.chatterbot.storage import StorageAdapter
|
||||
|
||||
|
||||
class Query(object):
|
||||
|
||||
def __init__(self, query={}):
|
||||
self.query = query
|
||||
def __init__(self, query=None):
|
||||
if query is None:
|
||||
self.query = {}
|
||||
else:
|
||||
self.query = query
|
||||
|
||||
def value(self):
|
||||
return self.query.copy()
|
||||
@ -116,7 +119,7 @@ class MongoDatabaseAdapter(StorageAdapter):
|
||||
"""
|
||||
Return the class for the statement model.
|
||||
"""
|
||||
from ..conversation import Statement
|
||||
from chatter.chatterbot.conversation import Statement
|
||||
|
||||
# Create a storage-aware statement
|
||||
statement = Statement
|
||||
@ -128,7 +131,7 @@ class MongoDatabaseAdapter(StorageAdapter):
|
||||
"""
|
||||
Return the class for the response model.
|
||||
"""
|
||||
from ..conversation import Response
|
||||
from chatter.chatterbot.conversation import Response
|
||||
|
||||
# Create a storage-aware response
|
||||
response = Response
|
@ -1,8 +1,8 @@
|
||||
from . import StorageAdapter
|
||||
from chatter.chatterbot.storage import StorageAdapter
|
||||
|
||||
|
||||
def get_response_table(response):
|
||||
from ..ext.sqlalchemy_app.models import Response
|
||||
from chatter.chatterbot.ext.sqlalchemy_app.models import Response
|
||||
return Response(text=response.text, occurrence=response.occurrence)
|
||||
|
||||
|
||||
@ -86,28 +86,28 @@ class SQLStorageAdapter(StorageAdapter):
|
||||
"""
|
||||
Return the statement model.
|
||||
"""
|
||||
from ..ext.sqlalchemy_app.models import Statement
|
||||
from chatter.chatterbot.ext.sqlalchemy_app.models import Statement
|
||||
return Statement
|
||||
|
||||
def get_response_model(self):
|
||||
"""
|
||||
Return the response model.
|
||||
"""
|
||||
from ..ext.sqlalchemy_app.models import Response
|
||||
from chatter.chatterbot.ext.sqlalchemy_app.models import Response
|
||||
return Response
|
||||
|
||||
def get_conversation_model(self):
|
||||
"""
|
||||
Return the conversation model.
|
||||
"""
|
||||
from ..ext.sqlalchemy_app.models import Conversation
|
||||
from chatter.chatterbot.ext.sqlalchemy_app.models import Conversation
|
||||
return Conversation
|
||||
|
||||
def get_tag_model(self):
|
||||
"""
|
||||
Return the conversation model.
|
||||
"""
|
||||
from ..ext.sqlalchemy_app.models import Tag
|
||||
from chatter.chatterbot.ext.sqlalchemy_app.models import Tag
|
||||
return Tag
|
||||
|
||||
def count(self):
|
||||
@ -379,14 +379,14 @@ class SQLStorageAdapter(StorageAdapter):
|
||||
"""
|
||||
Drop the database attached to a given adapter.
|
||||
"""
|
||||
from ..ext.sqlalchemy_app.models import Base
|
||||
from chatter.chatterbot.ext.sqlalchemy_app.models import Base
|
||||
Base.metadata.drop_all(self.engine)
|
||||
|
||||
def create(self):
|
||||
"""
|
||||
Populate the database with the tables.
|
||||
"""
|
||||
from ..ext.sqlalchemy_app.models import Base
|
||||
from chatter.chatterbot.ext.sqlalchemy_app.models import Base
|
||||
Base.metadata.create_all(self.engine)
|
||||
|
||||
def _session_finish(self, session, statement_text=None):
|
@ -24,12 +24,12 @@ class StorageAdapter(object):
|
||||
# The string must be lowercase
|
||||
model_name = model_name.lower()
|
||||
|
||||
kwarg_model_key = '%s_model' % (model_name, )
|
||||
kwarg_model_key = '%s_model' % (model_name,)
|
||||
|
||||
if kwarg_model_key in self.kwargs:
|
||||
return self.kwargs.get(kwarg_model_key)
|
||||
|
||||
get_model_method = getattr(self, 'get_%s_model' % (model_name, ))
|
||||
get_model_method = getattr(self, 'get_%s_model' % (model_name,))
|
||||
|
||||
return get_model_method()
|
||||
|
||||
@ -157,7 +157,8 @@ class StorageAdapter(object):
|
||||
|
||||
class EmptyDatabaseException(Exception):
|
||||
|
||||
def __init__(self, value='The database currently contains no entries. At least one entry is expected. You may need to train your chat bot to populate your database.'):
|
||||
def __init__(self,
|
||||
value='The database currently contains no entries. At least one entry is expected. You may need to train your chat bot to populate your database.'):
|
||||
self.value = value
|
||||
|
||||
def __str__(self):
|
@ -1,8 +1,9 @@
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from .conversation import Statement, Response
|
||||
|
||||
from . import utils
|
||||
from .conversation import Statement, Response
|
||||
|
||||
|
||||
class Trainer(object):
|
||||
@ -60,8 +61,8 @@ class Trainer(object):
|
||||
|
||||
def __init__(self, value=None):
|
||||
default = (
|
||||
'A training class must be specified before calling train(). ' +
|
||||
'See http://chatterbot.readthedocs.io/en/stable/training.html'
|
||||
'A training class must be specified before calling train(). ' +
|
||||
'See http://chatterbot.readthedocs.io/en/stable/training.html'
|
||||
)
|
||||
self.value = value or default
|
||||
|
||||
@ -84,7 +85,7 @@ class Trainer(object):
|
||||
import json
|
||||
export = {'conversations': self._generate_export_data()}
|
||||
with open(file_path, 'w+') as jsonfile:
|
||||
json.dump(export, jsonfile, ensure_ascii=False)
|
||||
json.dump(export, jsonfile, ensure_ascii=True)
|
||||
|
||||
|
||||
class ListTrainer(Trainer):
|
||||
@ -392,10 +393,9 @@ class UbuntuCorpusTrainer(Trainer):
|
||||
|
||||
file_kwargs = {}
|
||||
|
||||
if sys.version_info[0] > 2:
|
||||
# Specify the encoding in Python versions 3 and up
|
||||
file_kwargs['encoding'] = 'utf-8'
|
||||
# WARNING: This might fail to read a unicode corpus file in Python 2.x
|
||||
# Specify the encoding in Python versions 3 and up
|
||||
file_kwargs['encoding'] = 'utf-8'
|
||||
# WARNING: This might fail to read a unicode corpus file in Python 2.x
|
||||
|
||||
for file in glob.iglob(extracted_corpus_path):
|
||||
self.logger.info('Training from: {}'.format(file))
|
@ -75,17 +75,8 @@ def input_function():
|
||||
Normalizes reading input between python 2 and 3.
|
||||
The function 'raw_input' becomes 'input' in Python 3.
|
||||
"""
|
||||
import sys
|
||||
|
||||
if sys.version_info[0] < 3:
|
||||
user_input = str(raw_input()) # NOQA
|
||||
|
||||
# Avoid problems using format strings with unicode characters
|
||||
if user_input:
|
||||
user_input = user_input.decode('utf-8')
|
||||
|
||||
else:
|
||||
user_input = input() # NOQA
|
||||
user_input = input() # NOQA
|
||||
|
||||
return user_input
|
||||
|
||||
@ -137,7 +128,7 @@ def remove_stopwords(tokens, language):
|
||||
Stop words are words like "is, the, a, ..."
|
||||
|
||||
Be sure to download the required NLTK corpus before calling this function:
|
||||
- from chatterbot.utils import nltk_download_corpus
|
||||
- from chatter.chatterbot.utils import nltk_download_corpus
|
||||
- nltk_download_corpus('corpora/stopwords')
|
||||
"""
|
||||
from nltk.corpus import stopwords
|
@ -1,10 +1,30 @@
|
||||
{
|
||||
"author" : ["Bobloy"],
|
||||
"bot_version" : [3,0,0],
|
||||
"description" : "Create an offline chatbot that talks like your average member using Machine Learning",
|
||||
"hidden" : false,
|
||||
"install_msg" : "Thank you for installing Chatter!",
|
||||
"requirements" : ["sqlalchemy<1.3,>=1.2", "python-twitter<4.0,>=3.0", "python-dateutil<2.7,>=2.6", "pymongo<4.0,>=3.3", "nltk<4.0,>=3.2", "mathparse<0.2,>=0.1", "chatterbot-corpus<1.2,>=1.1"],
|
||||
"short" : "Local Chatbot run on machine learning",
|
||||
"tags" : ["chat", "chatbot", "cleverbot", "clever","bobloy"]
|
||||
"author": [
|
||||
"Bobloy"
|
||||
],
|
||||
"bot_version": [
|
||||
3,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"description": "Create an offline chatbot that talks like your average member using Machine Learning",
|
||||
"hidden": false,
|
||||
"install_msg": "Thank you for installing Chatter!",
|
||||
"requirements": [
|
||||
"sqlalchemy<1.3,>=1.2",
|
||||
"python-twitter<4.0,>=3.0",
|
||||
"python-dateutil<2.7,>=2.6",
|
||||
"pymongo<4.0,>=3.3",
|
||||
"nltk<4.0,>=3.2",
|
||||
"mathparse<0.2,>=0.1",
|
||||
"chatterbot-corpus<1.2,>=1.1"
|
||||
],
|
||||
"short": "Local Chatbot run on machine learning",
|
||||
"tags": [
|
||||
"chat",
|
||||
"chatbot",
|
||||
"cleverbot",
|
||||
"clever",
|
||||
"bobloy"
|
||||
]
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
default_app_config = (
|
||||
'chatter.source.ext.django_chatterbot.apps.DjangoChatterBotConfig'
|
||||
)
|
@ -1,261 +0,0 @@
|
||||
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
|
@ -1,31 +0,0 @@
|
||||
from django.contrib import admin
|
||||
from .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 = 'chatter.source.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 . import models
|
||||
from ... 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 ..... import ChatBot
|
||||
from ... 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 .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 ... import constants
|
||||
|
||||
|
||||
CHATTERBOT_SETTINGS = getattr(settings, 'CHATTERBOT', {})
|
||||
|
||||
CHATTERBOT_DEFAULTS = {
|
||||
'name': 'ChatterBot',
|
||||
'storage_adapter': 'chatter.source.storage.DjangoStorageAdapter',
|
||||
'input_adapter': 'chatter.source.input.VariableInputTypeAdapter',
|
||||
'output_adapter': 'chatter.source.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 ... import ChatBot
|
||||
from . 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 .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,220 +0,0 @@
|
||||
from . import StorageAdapter
|
||||
from .. 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…
x
Reference in New Issue
Block a user