Merge branch 'master' into werewolf_develop
This commit is contained in:
commit
877a08d3a6
38
README.md
38
README.md
@ -2,31 +2,21 @@
|
|||||||
|
|
||||||
Cog Function
|
Cog Function
|
||||||
|
|
||||||
| Name | Status | Description
|
| Name | Status | Description (Click to see full status)
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| ccrole | **Beta** | Create custom commands that also assign roles |
|
| ccrole | **Beta** | <details><summary>Create custom commands that also assign roles</summary>May have some bugs, please create an issue if you find any</details> |
|
||||||
| chatter | **Alpha** | Chat-bot trained to talk like your guild
|
| chatter | **Alpha** | <details><summary>Chat-bot trained to talk like your guild</summary>Missing some key features, but currently functional</details> |
|
||||||
| fight | **Incomplete** | Organize bracket tournaments within discord |
|
| fight | **Incomplete** | <details><summary>Organize bracket tournaments within discord</summary>Still in-progress, a massive project</details> |
|
||||||
| flag | **Beta** | Create temporary marks on users that expire after specified time |
|
| flag | **Incomplete** | <details><summary>Create temporary marks on users that expire after specified time</summary>Not yet ported to v3</details> |
|
||||||
| hangman | **Incomplete** | Play a game of hangman |
|
| hangman | **Alpha** | <details><summary>Play a game of hangman</summary>Some visual glitches and needs more customization</details> |
|
||||||
| immortal | **Private** | Cog designed for a specific server, not recommended to install |
|
| howdoi | **Incomplete** | <details><summary>Create temporary marks on users that expire after specified time</summary>Not yet ported to v3</details> |
|
||||||
| leaver | **Incomplete** | Send a message in a channel when a user leaves the server |
|
| leaver | **Incomplete** | <details><summary>Send a message in a channel when a user leaves the server</summary>Not yet ported to v3</details> |
|
||||||
| reactrestrict | **Alpha** | Removes reactions by role per channel |
|
| reactrestrict | **Alpha** | <details><summary>Removes reactions by role per channel</summary>A bit clunky, but functional</details> |
|
||||||
| stealemoji | **Alpha** | Steals any custom emoji it sees |
|
| secrethitler | **Incomplete** | <details><summary>Play the Secret Hitler game</summary>Concept, no work done yet</details> |
|
||||||
| werewolf | **Incomplete** | Play the classic party game Werewolf within discord |
|
| stealemoji | **Alpha** | <details><summary>Steals any custom emoji it sees in a reaction</summary>Some planned upgrades for server generation</details> |
|
||||||
|
| werewolf | **Incomplete** | <details><summary>Play the classic party game Werewolf within discord</summary>Another massive project, will be fully customizable</details> |
|
||||||
|
|
||||||
Cog Status Descriptions
|
|
||||||
|
|
||||||
- ccrole: May have some bugs, please create an issue if you find any
|
Check out my V2 cogs at [Fox-Cogs v2](https://github.com/bobloy/Fox-Cogs)
|
||||||
- chatter: Missing some key features, but currently functional
|
|
||||||
- fight: Still in-progress, a massive project
|
|
||||||
- flag: Not yet ported to v3
|
|
||||||
- hangman: Not yet ported to v3
|
|
||||||
- immortal: Designed for a specific server, not recommended to install
|
|
||||||
- leaver: Not yet ported to v3
|
|
||||||
- reactrestrict: A bit clunky, but functional
|
|
||||||
- stealemoji: Some planned upgrades for server generation
|
|
||||||
- werewolf: Another massive project, will be fully customizable
|
|
||||||
|
|
||||||
Many of these are functional in my V2 cogs at [Fox-Cogs v2](https://github.com/bobloy/Fox-Cogs)
|
|
||||||
|
|
||||||
|
Get support on the [Third Party Cog Server](https://discord.gg/GET4DVk)
|
||||||
|
196
ccrole/ccrole.py
196
ccrole/ccrole.py
@ -1,14 +1,11 @@
|
|||||||
import discord
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from discord.ext import commands
|
|
||||||
|
|
||||||
from redbot.core import Config, checks
|
|
||||||
|
|
||||||
from redbot.core.utils.chat_formatting import pagify, box
|
|
||||||
import os
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from redbot.core import Config, checks
|
||||||
|
from redbot.core.utils.chat_formatting import pagify, box
|
||||||
|
|
||||||
|
|
||||||
class CCRole:
|
class CCRole:
|
||||||
"""
|
"""
|
||||||
@ -20,23 +17,27 @@ class CCRole:
|
|||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.config = Config.get_conf(self, identifier=9999114111108101)
|
self.config = Config.get_conf(self, identifier=9999114111108101)
|
||||||
default_guild = {
|
default_guild = {
|
||||||
"cmdlist" : {},
|
"cmdlist": {},
|
||||||
"settings": {}
|
"settings": {}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.config.register_guild(**default_guild)
|
self.config.register_guild(**default_guild)
|
||||||
|
|
||||||
|
|
||||||
@commands.group(no_pm=True)
|
@commands.group(no_pm=True)
|
||||||
async def ccrole(self, ctx):
|
async def ccrole(self, ctx):
|
||||||
"""Custom commands management"""
|
"""Custom commands management with roles
|
||||||
|
|
||||||
|
Highly customizable custom commands with role management."""
|
||||||
if not ctx.invoked_subcommand:
|
if not ctx.invoked_subcommand:
|
||||||
await ctx.send_help()
|
await ctx.send_help()
|
||||||
|
|
||||||
@ccrole.command(name="add")
|
@ccrole.command(name="add")
|
||||||
@checks.mod_or_permissions(administrator=True)
|
@checks.mod_or_permissions(administrator=True)
|
||||||
async def ccrole_add(self, ctx, command : str):
|
async def ccrole_add(self, ctx, command: str):
|
||||||
"""Adds a custom command with roles"""
|
"""Adds a custom command with roles
|
||||||
|
|
||||||
|
When adding text, put arguments in `{}` to eval them
|
||||||
|
Options: `{author}`, `{target}`, `{server}`, `{channel}`, `{message}`"""
|
||||||
command = command.lower()
|
command = command.lower()
|
||||||
if command in self.bot.all_commands:
|
if command in self.bot.all_commands:
|
||||||
await ctx.send("That command is already a standard command.")
|
await ctx.send("That command is already a standard command.")
|
||||||
@ -46,9 +47,9 @@ class CCRole:
|
|||||||
author = ctx.author
|
author = ctx.author
|
||||||
channel = ctx.channel
|
channel = ctx.channel
|
||||||
|
|
||||||
cmdlist = self.config.guild(ctx.guild).cmdlist
|
cmd_list = self.config.guild(guild).cmdlist
|
||||||
|
|
||||||
if await cmdlist.get_raw(command, default=None):
|
if await cmd_list.get_raw(command, default=None):
|
||||||
await ctx.send("This command already exists. Delete it with `{}ccrole delete` first.".format(ctx.prefix))
|
await ctx.send("This command already exists. Delete it with `{}ccrole delete` first.".format(ctx.prefix))
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -56,15 +57,16 @@ class CCRole:
|
|||||||
await ctx.send('What roles should it add? (Must be **comma separated**)\nSay `None` to skip adding roles')
|
await ctx.send('What roles should it add? (Must be **comma separated**)\nSay `None` to skip adding roles')
|
||||||
|
|
||||||
def check(m):
|
def check(m):
|
||||||
return m.author == author and m.channel==channel
|
return m.author == author and m.channel == channel
|
||||||
|
|
||||||
try:
|
try:
|
||||||
answer = await self.bot.wait_for('message', timeout=120, check=check)
|
answer = await self.bot.wait_for('message', timeout=120, check=check)
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
await ctx.send("Timed out, canceling")
|
await ctx.send("Timed out, canceling")
|
||||||
|
return
|
||||||
|
|
||||||
arole_list = []
|
arole_list = []
|
||||||
if answer.content.upper()!="NONE":
|
if answer.content.upper() != "NONE":
|
||||||
arole_list = await self._get_roles_from_content(ctx, answer.content)
|
arole_list = await self._get_roles_from_content(ctx, answer.content)
|
||||||
if arole_list is None:
|
if arole_list is None:
|
||||||
await ctx.send("Invalid answer, canceling")
|
await ctx.send("Invalid answer, canceling")
|
||||||
@ -76,24 +78,27 @@ class CCRole:
|
|||||||
answer = await self.bot.wait_for('message', timeout=120, check=check)
|
answer = await self.bot.wait_for('message', timeout=120, check=check)
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
await ctx.send("Timed out, canceling")
|
await ctx.send("Timed out, canceling")
|
||||||
|
return
|
||||||
|
|
||||||
rrole_list = []
|
rrole_list = []
|
||||||
if answer.content.upper()!="NONE":
|
if answer.content.upper() != "NONE":
|
||||||
rrole_list = await self._get_roles_from_content(ctx, answer.content)
|
rrole_list = await self._get_roles_from_content(ctx, answer.content)
|
||||||
if rrole_list is None:
|
if rrole_list is None:
|
||||||
await ctx.send("Invalid answer, canceling")
|
await ctx.send("Invalid answer, canceling")
|
||||||
return
|
return
|
||||||
|
|
||||||
# Roles to use
|
# Roles to use
|
||||||
await ctx.send('What roles are allowed to use this command? (Must be comma separated)\nSay `None` to allow all roles')
|
await ctx.send(
|
||||||
|
'What roles are allowed to use this command? (Must be comma separated)\nSay `None` to allow all roles')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
answer = await self.bot.wait_for('message', timeout=120, check=check)
|
answer = await self.bot.wait_for('message', timeout=120, check=check)
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
await ctx.send("Timed out, canceling")
|
await ctx.send("Timed out, canceling")
|
||||||
|
return
|
||||||
|
|
||||||
prole_list = []
|
prole_list = []
|
||||||
if answer.content.upper()!="NONE":
|
if answer.content.upper() != "NONE":
|
||||||
prole_list = await self._get_roles_from_content(ctx, answer.content)
|
prole_list = await self._get_roles_from_content(ctx, answer.content)
|
||||||
if prole_list is None:
|
if prole_list is None:
|
||||||
await ctx.send("Invalid answer, canceling")
|
await ctx.send("Invalid answer, canceling")
|
||||||
@ -106,6 +111,7 @@ class CCRole:
|
|||||||
answer = await self.bot.wait_for('message', timeout=120, check=check)
|
answer = await self.bot.wait_for('message', timeout=120, check=check)
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
await ctx.send("Timed out, canceling")
|
await ctx.send("Timed out, canceling")
|
||||||
|
return
|
||||||
|
|
||||||
if answer.content.upper() in ["Y", "YES"]:
|
if answer.content.upper() in ["Y", "YES"]:
|
||||||
targeted = True
|
targeted = True
|
||||||
@ -115,55 +121,89 @@ class CCRole:
|
|||||||
await ctx.send("This command will be **`selfrole`**")
|
await ctx.send("This command will be **`selfrole`**")
|
||||||
|
|
||||||
# Message to send
|
# Message to send
|
||||||
await ctx.send('What message should the bot say when using this command?\nSay `None` to send the default `Success!` message')
|
await ctx.send(
|
||||||
|
'What message should the bot say when using this command?\n'
|
||||||
|
'Say `None` to send the default `Success!` message\n'
|
||||||
|
'Eval Options: `{author}`, `{target}`, `{server}`, `{channel}`, `{message}`\n'
|
||||||
|
'For example: `Welcome {target.mention} to {server.name}!`')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
answer = await self.bot.wait_for('message', timeout=120, check=check)
|
answer = await self.bot.wait_for('message', timeout=120, check=check)
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
await ctx.send("Timed out, canceling")
|
await ctx.send("Timed out, canceling")
|
||||||
|
return
|
||||||
|
|
||||||
text = "Success!"
|
text = "Success!"
|
||||||
if answer.content.upper()!="NONE":
|
if answer.content.upper() != "NONE":
|
||||||
text = answer.content
|
text = answer.content
|
||||||
|
|
||||||
# Save the command
|
# Save the command
|
||||||
|
|
||||||
out = {'text': text, 'aroles': arole_list, 'rroles': rrole_list, "proles": prole_list, "targeted": targeted}
|
out = {'text': text, 'aroles': arole_list, 'rroles': rrole_list, "proles": prole_list, "targeted": targeted}
|
||||||
|
|
||||||
await cmdlist.set_raw(command, value=out)
|
await cmd_list.set_raw(command, value=out)
|
||||||
|
|
||||||
ctx.send("Custom Command **`{}`** successfully added".format(command))
|
await ctx.send("Custom Command **`{}`** successfully added".format(command))
|
||||||
|
|
||||||
@ccrole.command(name="delete")
|
@ccrole.command(name="delete")
|
||||||
@checks.mod_or_permissions(administrator=True)
|
@checks.mod_or_permissions(administrator=True)
|
||||||
async def ccrole_delete(self, ctx, command : str):
|
async def ccrole_delete(self, ctx, command: str):
|
||||||
"""Deletes a custom command
|
"""Deletes a custom command
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
[p]ccrole delete yourcommand"""
|
`[p]ccrole delete yourcommand`"""
|
||||||
guild = ctx.guild
|
guild = ctx.guild
|
||||||
command = command.lower()
|
command = command.lower()
|
||||||
if not await self.config.guild(ctx.guild).cmdlist.get_raw(command, default=None):
|
if not await self.config.guild(guild).cmdlist.get_raw(command, default=None):
|
||||||
await ctx.send("That command doesn't exist")
|
await ctx.send("That command doesn't exist")
|
||||||
else:
|
else:
|
||||||
await self.config.guild(ctx.guild).cmdlist.set_raw(command, value=None)
|
await self.config.guild(guild).cmdlist.set_raw(command, value=None)
|
||||||
await ctx.send("Custom command successfully deleted.")
|
await ctx.send("Custom command successfully deleted.")
|
||||||
|
|
||||||
|
@ccrole.command(name="details")
|
||||||
|
async def ccrole_details(self, ctx, command: str):
|
||||||
|
"""Provide details about passed custom command"""
|
||||||
|
guild = ctx.guild
|
||||||
|
command = command.lower()
|
||||||
|
cmd = await self.config.guild(guild).cmdlist.get_raw(command, default=None)
|
||||||
|
if cmd is None:
|
||||||
|
await ctx.send("That command doesn't exist")
|
||||||
|
return
|
||||||
|
|
||||||
|
embed = discord.Embed(title=command,
|
||||||
|
description="{} custom command".format("Targeted" if cmd['targeted'] else "Non-Targeted"))
|
||||||
|
|
||||||
|
def process_roles(role_list):
|
||||||
|
if not role_list:
|
||||||
|
return "None"
|
||||||
|
return ", ".join([discord.utils.get(ctx.guild.roles, id=roleid).name for roleid in role_list])
|
||||||
|
|
||||||
|
embed.add_field(name="Text", value="```{}```".format(cmd['text']))
|
||||||
|
embed.add_field(name="Adds Roles", value=process_roles(cmd['aroles']), inline=True)
|
||||||
|
embed.add_field(name="Removes Roles", value=process_roles(cmd['rroles']), inline=True)
|
||||||
|
embed.add_field(name="Role Restrictions", value=process_roles(cmd['proles']), inline=True)
|
||||||
|
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
@ccrole.command(name="list")
|
@ccrole.command(name="list")
|
||||||
async def ccrole_list(self, ctx):
|
async def ccrole_list(self, ctx):
|
||||||
"""Shows custom commands list"""
|
"""Shows custom commands list"""
|
||||||
guild = ctx.guild
|
guild = ctx.guild
|
||||||
commands = await self.config.guild(ctx.guild).cmdlist()
|
cmd_list = await self.config.guild(guild).cmdlist()
|
||||||
|
cmd_list = {k: v for k,v in cmd_list.items() if v}
|
||||||
if not commands:
|
if not cmd_list:
|
||||||
await ctx.send("There are no custom commands in this server. Use `{}ccrole add` to start adding some.".format(ctx.prefix))
|
await ctx.send(
|
||||||
|
"There are no custom commands in this server. Use `{}ccrole add` to start adding some.".format(
|
||||||
|
ctx.prefix))
|
||||||
return
|
return
|
||||||
|
|
||||||
commands = ", ".join([ctx.prefix + c for c in sorted(commands.keys())])
|
cmd_list = ", ".join([ctx.prefix + c for c in sorted(cmd_list.keys())])
|
||||||
commands = "Custom commands:\n\n" + commands
|
cmd_list = "Custom commands:\n\n" + cmd_list
|
||||||
|
|
||||||
if len(commands) < 1500:
|
if len(cmd_list) < 1500: # I'm allowed to have arbitrary numbers for when it's too much to dm dammit
|
||||||
await ctx.send(box(commands))
|
await ctx.send(box(cmd_list))
|
||||||
else:
|
else:
|
||||||
for page in pagify(commands, delims=[" ", "\n"]):
|
for page in pagify(cmd_list, delims=[" ", "\n"]):
|
||||||
await ctx.author.send(box(page))
|
await ctx.author.send(box(page))
|
||||||
await ctx.send("Command list DM'd")
|
await ctx.send("Command list DM'd")
|
||||||
|
|
||||||
@ -177,20 +217,18 @@ class CCRole:
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
cmdlist = self.config.guild(guild).cmdlist
|
cmdlist = self.config.guild(guild).cmdlist
|
||||||
cmd = message.content[len(prefix):].split()[0]
|
cmd = message.content[len(prefix):].split()[0].lower()
|
||||||
cmd = await cmdlist.get_raw(cmd.lower(), default=None)
|
cmd = await cmdlist.get_raw(cmd, default=None)
|
||||||
|
|
||||||
if cmd:
|
if cmd is not None:
|
||||||
await self.eval_cc(cmd, message)
|
await self.eval_cc(cmd, message)
|
||||||
|
|
||||||
async def _get_roles_from_content(self, ctx, content):
|
async def _get_roles_from_content(self, ctx, content):
|
||||||
content_list = content.split(",")
|
content_list = content.split(",")
|
||||||
role_list = []
|
|
||||||
try:
|
try:
|
||||||
role_list = [discord.utils.get(ctx.guild.roles, name=role.strip(' ')).id for role in content_list]
|
role_list = [discord.utils.get(ctx.guild.roles, name=role.strip(' ')).id for role in content_list]
|
||||||
except:
|
except (discord.HTTPException, AttributeError): # None.id is attribute error
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
return role_list
|
return role_list
|
||||||
@ -223,14 +261,13 @@ class CCRole:
|
|||||||
if cmd['targeted']:
|
if cmd['targeted']:
|
||||||
try:
|
try:
|
||||||
target = discord.utils.get(message.guild.members, mention=message.content.split()[1])
|
target = discord.utils.get(message.guild.members, mention=message.content.split()[1])
|
||||||
except:
|
except IndexError: # .split() return list of len<2
|
||||||
target = None
|
target = None
|
||||||
|
|
||||||
if not target:
|
if not target:
|
||||||
out_message = "This command is targeted! @mention a target\n`{} <target>`".format(message.content.split()[0])
|
out_message = "This custom command is targeted! @mention a target\n`{} <target>`".format(
|
||||||
|
message.content.split()[0])
|
||||||
await message.channel.send(out_message)
|
await message.channel.send(out_message)
|
||||||
|
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
target = message.author
|
target = message.author
|
||||||
@ -251,37 +288,40 @@ class CCRole:
|
|||||||
await target.remove_roles(*rrole_list)
|
await target.remove_roles(*rrole_list)
|
||||||
except discord.Forbidden:
|
except discord.Forbidden:
|
||||||
await message.channel.send("Permission error: Unable to remove roles")
|
await message.channel.send("Permission error: Unable to remove roles")
|
||||||
await message.channel.send(cmd['text'])
|
|
||||||
|
|
||||||
# {'text': text, 'aroles': arole_list, 'rroles': rrole_list, "proles", prole_list, "targeted": targeted}
|
out_message = self.format_cc(cmd, message, target)
|
||||||
|
await message.channel.send(out_message)
|
||||||
|
|
||||||
# def format_cc(self, command, message):
|
def format_cc(self, cmd, message, target):
|
||||||
# results = re.findall("\{([^}]+)\}", command)
|
out = cmd['text']
|
||||||
# for result in results:
|
results = re.findall("{([^}]+)\}", out)
|
||||||
# param = self.transform_parameter(result, message)
|
for result in results:
|
||||||
# command = command.replace("{" + result + "}", param)
|
param = self.transform_parameter(result, message, target)
|
||||||
# return command
|
out = out.replace("{" + result + "}", param)
|
||||||
|
return out
|
||||||
|
|
||||||
# def transform_parameter(self, result, message):
|
def transform_parameter(self, result, message, target):
|
||||||
# """
|
"""
|
||||||
# For security reasons only specific objects are allowed
|
For security reasons only specific objects are allowed
|
||||||
# Internals are ignored
|
Internals are ignored
|
||||||
# """
|
"""
|
||||||
# raw_result = "{" + result + "}"
|
raw_result = "{" + result + "}"
|
||||||
# objects = {
|
objects = {
|
||||||
# "message" : message,
|
"message": message,
|
||||||
# "author" : message.author,
|
"author": message.author,
|
||||||
# "channel" : message.channel,
|
"channel": message.channel,
|
||||||
# "server" : message.server
|
"server": message.guild,
|
||||||
# }
|
"guild": message.guild,
|
||||||
# if result in objects:
|
"target": target
|
||||||
# return str(objects[result])
|
}
|
||||||
# try:
|
if result in objects:
|
||||||
# first, second = result.split(".")
|
return str(objects[result])
|
||||||
# except ValueError:
|
try:
|
||||||
# return raw_result
|
first, second = result.split(".")
|
||||||
# if first in objects and not second.startswith("_"):
|
except ValueError:
|
||||||
# first = objects[first]
|
return raw_result
|
||||||
# else:
|
if first in objects and not second.startswith("_"):
|
||||||
# return raw_result
|
first = objects[first]
|
||||||
# return str(getattr(first, second, raw_result))
|
else:
|
||||||
|
return raw_result
|
||||||
|
return str(getattr(first, second, raw_result))
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
from .chatter import Chatter
|
from . import chatterbot
|
||||||
|
from .chat import Chatter
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot):
|
||||||
bot.add_cog(Chatter(bot))
|
bot.add_cog(Chatter(bot))
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
'chatterbot'
|
||||||
|
)
|
||||||
|
@ -1,16 +1,13 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
from typing import List, Union
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
|
from redbot.core import Config
|
||||||
|
|
||||||
from redbot.core import Config, RedContext
|
from chatter.chatterbot import ChatBot
|
||||||
from redbot.core.bot import Red
|
from chatter.chatterbot.trainers import ListTrainer
|
||||||
|
|
||||||
from .source import ChatBot
|
|
||||||
from .source.trainers import ListTrainer
|
|
||||||
|
|
||||||
from datetime import datetime,timedelta
|
|
||||||
|
|
||||||
|
|
||||||
class Chatter:
|
class Chatter:
|
||||||
@ -25,9 +22,13 @@ class Chatter:
|
|||||||
default_guild = {
|
default_guild = {
|
||||||
"whitelist": None,
|
"whitelist": None,
|
||||||
"days": 1
|
"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.chatbot.set_trainer(ListTrainer)
|
||||||
|
|
||||||
self.config.register_global(**default_global)
|
self.config.register_global(**default_global)
|
||||||
@ -35,7 +36,7 @@ class Chatter:
|
|||||||
|
|
||||||
self.loop = asyncio.get_event_loop()
|
self.loop = asyncio.get_event_loop()
|
||||||
|
|
||||||
async def _get_conversation(self, ctx, in_channel: discord.TextChannel=None):
|
async def _get_conversation(self, ctx, in_channel: discord.TextChannel = None):
|
||||||
"""
|
"""
|
||||||
Compiles all conversation in the Guild this bot can get it's hands on
|
Compiles all conversation in the Guild this bot can get it's hands on
|
||||||
Currently takes a stupid long time
|
Currently takes a stupid long time
|
||||||
@ -44,7 +45,6 @@ class Chatter:
|
|||||||
out = []
|
out = []
|
||||||
after = datetime.today() - timedelta(days=(await self.config.guild(ctx.guild).days()))
|
after = datetime.today() - timedelta(days=(await self.config.guild(ctx.guild).days()))
|
||||||
|
|
||||||
|
|
||||||
for channel in ctx.guild.text_channels:
|
for channel in ctx.guild.text_channels:
|
||||||
if in_channel:
|
if in_channel:
|
||||||
channel = in_channel
|
channel = in_channel
|
||||||
@ -53,7 +53,7 @@ class Chatter:
|
|||||||
try:
|
try:
|
||||||
async for message in channel.history(limit=None, reverse=True, after=after):
|
async for message in channel.history(limit=None, reverse=True, after=after):
|
||||||
if user == message.author:
|
if user == message.author:
|
||||||
out[-1] += "\n"+message.clean_content
|
out[-1] += "\n" + message.clean_content
|
||||||
else:
|
else:
|
||||||
user = message.author
|
user = message.author
|
||||||
out.append(message.clean_content)
|
out.append(message.clean_content)
|
||||||
@ -81,6 +81,7 @@ class Chatter:
|
|||||||
"""
|
"""
|
||||||
if ctx.invoked_subcommand is None:
|
if ctx.invoked_subcommand is None:
|
||||||
await ctx.send_help()
|
await ctx.send_help()
|
||||||
|
|
||||||
@chatter.command()
|
@chatter.command()
|
||||||
async def age(self, ctx: RedContext, days: int):
|
async def age(self, ctx: RedContext, days: int):
|
||||||
"""
|
"""
|
||||||
@ -92,7 +93,20 @@ class Chatter:
|
|||||||
await ctx.send("Success")
|
await ctx.send("Success")
|
||||||
|
|
||||||
@chatter.command()
|
@chatter.command()
|
||||||
async def train(self, ctx: RedContext, 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
|
Trains the bot based on language in this guild
|
||||||
"""
|
"""
|
||||||
@ -104,7 +118,7 @@ class Chatter:
|
|||||||
return
|
return
|
||||||
|
|
||||||
await ctx.send("Gather successful! Training begins now\n(**This will take a long time, be patient**)")
|
await ctx.send("Gather successful! Training begins now\n(**This will take a long time, be patient**)")
|
||||||
embed=discord.Embed(title="Loading")
|
embed = discord.Embed(title="Loading")
|
||||||
embed.set_image(url="http://www.loop.universaleverything.com/animations/1295.gif")
|
embed.set_image(url="http://www.loop.universaleverything.com/animations/1295.gif")
|
||||||
temp_message = await ctx.send(embed=embed)
|
temp_message = await ctx.send(embed=embed)
|
||||||
future = await self.loop.run_in_executor(None, self._train, conversation)
|
future = await self.loop.run_in_executor(None, self._train, conversation)
|
||||||
@ -119,7 +133,7 @@ class Chatter:
|
|||||||
else:
|
else:
|
||||||
await ctx.send("Error occurred :(")
|
await ctx.send("Error occurred :(")
|
||||||
|
|
||||||
async def on_message(self, message: discord.Message):
|
async def on_message(self, message):
|
||||||
"""
|
"""
|
||||||
Credit to https://github.com/Twentysix26/26-Cogs/blob/master/cleverbot/cleverbot.py
|
Credit to https://github.com/Twentysix26/26-Cogs/blob/master/cleverbot/cleverbot.py
|
||||||
for on_message recognition of @bot
|
for on_message recognition of @bot
|
||||||
@ -135,9 +149,9 @@ class Chatter:
|
|||||||
return
|
return
|
||||||
text = text.replace(to_strip, "", 1)
|
text = text.replace(to_strip, "", 1)
|
||||||
async with channel.typing():
|
async with channel.typing():
|
||||||
response = self.chatbot.get_response(text)
|
future = await self.loop.run_in_executor(None, self.chatbot.get_response, text)
|
||||||
if not response:
|
|
||||||
response = ":thinking:"
|
|
||||||
await channel.send(response)
|
|
||||||
|
|
||||||
|
|
||||||
|
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
|
from .chatterbot import ChatBot
|
||||||
|
|
||||||
__version__ = '0.8.4'
|
__version__ = '0.8.5'
|
||||||
__author__ = 'Gunther Cox'
|
__author__ = 'Gunther Cox'
|
||||||
__email__ = 'gunthercx@gmail.com'
|
__email__ = 'gunthercx@gmail.com'
|
||||||
__url__ = 'https://github.com/gunthercox/ChatterBot'
|
__url__ = 'https://github.com/gunthercox/ChatterBot'
|
@ -1,6 +1,5 @@
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import importlib
|
import importlib
|
||||||
|
|
@ -16,7 +16,7 @@ class Adapter(object):
|
|||||||
"""
|
"""
|
||||||
Gives the adapter access to an instance of the ChatBot class.
|
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
|
:type chatbot: ChatBot
|
||||||
"""
|
"""
|
||||||
self.chatbot = chatbot
|
self.chatbot = chatbot
|
@ -1,9 +1,11 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from .storage import StorageAdapter
|
|
||||||
|
from . import utils
|
||||||
from .input import InputAdapter
|
from .input import InputAdapter
|
||||||
from .output import OutputAdapter
|
from .output import OutputAdapter
|
||||||
from . import utils
|
from .storage import StorageAdapter
|
||||||
|
|
||||||
|
|
||||||
class ChatBot(object):
|
class ChatBot(object):
|
||||||
@ -20,15 +22,15 @@ class ChatBot(object):
|
|||||||
|
|
||||||
self.default_session = None
|
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', [
|
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
|
# Check that each adapter is a valid subclass of it's respective parent
|
||||||
utils.validate_adapter_class(storage_adapter, StorageAdapter)
|
utils.validate_adapter_class(storage_adapter, StorageAdapter)
|
||||||
@ -45,7 +47,7 @@ class ChatBot(object):
|
|||||||
|
|
||||||
# Add required system logic adapter
|
# Add required system logic adapter
|
||||||
self.logic.system_adapters.append(
|
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:
|
for adapter in logic_adapters:
|
||||||
@ -59,7 +61,7 @@ class ChatBot(object):
|
|||||||
|
|
||||||
preprocessors = kwargs.get(
|
preprocessors = kwargs.get(
|
||||||
'preprocessors', [
|
'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))
|
self.preprocessors.append(utils.import_module(preprocessor))
|
||||||
|
|
||||||
# Use specified trainer or fall back to the default
|
# 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)
|
TrainerClass = utils.import_module(trainer)
|
||||||
self.trainer = TrainerClass(self.storage, **kwargs)
|
self.trainer = TrainerClass(self.storage, **kwargs)
|
||||||
self.training_data = kwargs.get('training_data')
|
self.training_data = kwargs.get('training_data')
|
@ -1,5 +1,4 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -58,19 +57,14 @@ class LevenshteinDistance(Comparator):
|
|||||||
:rtype: float
|
:rtype: float
|
||||||
"""
|
"""
|
||||||
|
|
||||||
PYTHON = sys.version_info[0]
|
|
||||||
|
|
||||||
# Return 0 if either statement has a falsy text value
|
# Return 0 if either statement has a falsy text value
|
||||||
if not statement.text or not other_statement.text:
|
if not statement.text or not other_statement.text:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# Get the lowercase version of both strings
|
# Get the lowercase version of both strings
|
||||||
if PYTHON < 3:
|
|
||||||
statement_text = unicode(statement.text.lower()) # NOQA
|
statement_text = str(statement.text.lower())
|
||||||
other_statement_text = unicode(other_statement.text.lower()) # NOQA
|
other_statement_text = str(other_statement.text.lower())
|
||||||
else:
|
|
||||||
statement_text = str(statement.text.lower())
|
|
||||||
other_statement_text = str(other_statement.text.lower())
|
|
||||||
|
|
||||||
similarity = SequenceMatcher(
|
similarity = SequenceMatcher(
|
||||||
None,
|
None,
|
||||||
@ -130,7 +124,7 @@ class SynsetDistance(Comparator):
|
|||||||
"""
|
"""
|
||||||
from nltk.corpus import wordnet
|
from nltk.corpus import wordnet
|
||||||
from nltk import word_tokenize
|
from nltk import word_tokenize
|
||||||
from . import utils
|
from chatter.chatterbot import utils
|
||||||
import itertools
|
import itertools
|
||||||
|
|
||||||
tokens1 = word_tokenize(statement.text.lower())
|
tokens1 = word_tokenize(statement.text.lower())
|
@ -25,7 +25,6 @@ class Statement(StatementMixin):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, text, **kwargs):
|
def __init__(self, text, **kwargs):
|
||||||
import sys
|
|
||||||
|
|
||||||
# Try not to allow non-string types to be passed to statements
|
# Try not to allow non-string types to be passed to statements
|
||||||
try:
|
try:
|
||||||
@ -33,13 +32,6 @@ class Statement(StatementMixin):
|
|||||||
except UnicodeEncodeError:
|
except UnicodeEncodeError:
|
||||||
pass
|
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.text = text
|
||||||
self.tags = kwargs.pop('tags', [])
|
self.tags = kwargs.pop('tags', [])
|
||||||
self.in_response_to = kwargs.pop('in_response_to', [])
|
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
|
from chatterbot_corpus import Corpus
|
||||||
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'Corpus',
|
'Corpus',
|
||||||
)
|
)
|
@ -1,11 +1,11 @@
|
|||||||
from sqlalchemy import Table, Column, Integer, DateTime, ForeignKey, PickleType
|
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.orm import relationship
|
||||||
from sqlalchemy.sql import func
|
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 chatter.chatterbot.constants import TAG_NAME_MAX_LENGTH, STATEMENT_TEXT_MAX_LENGTH
|
||||||
from .types import UnicodeString
|
from chatter.chatterbot.conversation import StatementMixin
|
||||||
from ...conversation import StatementMixin
|
from chatter.chatterbot.ext.sqlalchemy_app.types import UnicodeString
|
||||||
|
|
||||||
|
|
||||||
class ModelBase(object):
|
class ModelBase(object):
|
||||||
@ -29,7 +29,6 @@ class ModelBase(object):
|
|||||||
|
|
||||||
Base = declarative_base(cls=ModelBase)
|
Base = declarative_base(cls=ModelBase)
|
||||||
|
|
||||||
|
|
||||||
tag_association_table = Table(
|
tag_association_table = Table(
|
||||||
'tag_association',
|
'tag_association',
|
||||||
Base.metadata,
|
Base.metadata,
|
||||||
@ -73,8 +72,8 @@ class Statement(Base, StatementMixin):
|
|||||||
return [tag.name for tag in self.tags]
|
return [tag.name for tag in self.tags]
|
||||||
|
|
||||||
def get_statement(self):
|
def get_statement(self):
|
||||||
from ...conversation import Statement as StatementObject
|
from chatter.chatterbot.conversation import Statement as StatementObject
|
||||||
from ...conversation import Response as ResponseObject
|
from chatter.chatterbot.conversation import Response as ResponseObject
|
||||||
|
|
||||||
statement = StatementObject(
|
statement = StatementObject(
|
||||||
self.text,
|
self.text,
|
@ -13,9 +13,4 @@ class UnicodeString(TypeDecorator):
|
|||||||
Coerce Python bytestrings to unicode before
|
Coerce Python bytestrings to unicode before
|
||||||
saving them to the database.
|
saving them to the database.
|
||||||
"""
|
"""
|
||||||
import sys
|
|
||||||
|
|
||||||
if sys.version_info[0] < 3:
|
|
||||||
if isinstance(value, str):
|
|
||||||
value = value.decode('utf-8')
|
|
||||||
return value
|
return value
|
@ -1,12 +1,11 @@
|
|||||||
from .input_adapter import InputAdapter
|
from .input_adapter import InputAdapter
|
||||||
from .microsoft import Microsoft
|
|
||||||
from .gitter import Gitter
|
from .gitter import Gitter
|
||||||
from .hipchat import HipChat
|
from .hipchat import HipChat
|
||||||
from .mailgun import Mailgun
|
from .mailgun import Mailgun
|
||||||
|
from .microsoft import Microsoft
|
||||||
from .terminal import TerminalAdapter
|
from .terminal import TerminalAdapter
|
||||||
from .variable_input_type_adapter import VariableInputTypeAdapter
|
from .variable_input_type_adapter import VariableInputTypeAdapter
|
||||||
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'InputAdapter',
|
'InputAdapter',
|
||||||
'Microsoft',
|
'Microsoft',
|
@ -1,7 +1,9 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from time import sleep
|
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):
|
class Gitter(InputAdapter):
|
@ -1,7 +1,9 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from time import sleep
|
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):
|
class HipChat(InputAdapter):
|
@ -1,5 +1,6 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
from ..adapters import Adapter
|
|
||||||
|
from chatter.chatterbot.adapters import Adapter
|
||||||
|
|
||||||
|
|
||||||
class InputAdapter(Adapter):
|
class InputAdapter(Adapter):
|
@ -1,7 +1,9 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
from . import InputAdapter
|
|
||||||
from ..conversation import Statement
|
from chatter.chatterbot.conversation import Statement
|
||||||
|
from chatter.chatterbot.input import InputAdapter
|
||||||
|
|
||||||
|
|
||||||
class Mailgun(InputAdapter):
|
class Mailgun(InputAdapter):
|
@ -1,7 +1,9 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from time import sleep
|
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):
|
class Microsoft(InputAdapter):
|
||||||
@ -21,10 +23,10 @@ class Microsoft(InputAdapter):
|
|||||||
|
|
||||||
# NOTE: Direct Line client credentials are different from your bot's
|
# NOTE: Direct Line client credentials are different from your bot's
|
||||||
# credentials
|
# credentials
|
||||||
self.direct_line_token_or_secret = kwargs.\
|
self.direct_line_token_or_secret = kwargs. \
|
||||||
get('direct_line_token_or_secret')
|
get('direct_line_token_or_secret')
|
||||||
|
|
||||||
authorization_header = 'BotConnector {}'.\
|
authorization_header = 'BotConnector {}'. \
|
||||||
format(self.direct_line_token_or_secret)
|
format(self.direct_line_token_or_secret)
|
||||||
|
|
||||||
self.headers = {
|
self.headers = {
|
||||||
@ -62,7 +64,7 @@ class Microsoft(InputAdapter):
|
|||||||
def get_most_recent_message(self):
|
def get_most_recent_message(self):
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
endpoint = '{host}/api/conversations/{id}/messages'\
|
endpoint = '{host}/api/conversations/{id}/messages' \
|
||||||
.format(host=self.directline_host,
|
.format(host=self.directline_host,
|
||||||
id=self.conversation_id)
|
id=self.conversation_id)
|
||||||
|
|
@ -1,7 +1,8 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
from . import InputAdapter
|
|
||||||
from ..conversation import Statement
|
from chatter.chatterbot.conversation import Statement
|
||||||
from ..utils import input_function
|
from chatter.chatterbot.input import InputAdapter
|
||||||
|
from chatter.chatterbot.utils import input_function
|
||||||
|
|
||||||
|
|
||||||
class TerminalAdapter(InputAdapter):
|
class TerminalAdapter(InputAdapter):
|
@ -1,22 +1,18 @@
|
|||||||
from __future__ import unicode_literals
|
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):
|
class VariableInputTypeAdapter(InputAdapter):
|
||||||
|
|
||||||
JSON = 'json'
|
JSON = 'json'
|
||||||
TEXT = 'text'
|
TEXT = 'text'
|
||||||
OBJECT = 'object'
|
OBJECT = 'object'
|
||||||
VALID_FORMATS = (JSON, TEXT, OBJECT, )
|
VALID_FORMATS = (JSON, TEXT, OBJECT,)
|
||||||
|
|
||||||
def detect_type(self, statement):
|
def detect_type(self, statement):
|
||||||
import sys
|
|
||||||
|
|
||||||
if sys.version_info[0] < 3:
|
string_types = str
|
||||||
string_types = basestring # NOQA
|
|
||||||
else:
|
|
||||||
string_types = str
|
|
||||||
|
|
||||||
if hasattr(statement, 'text'):
|
if hasattr(statement, 'text'):
|
||||||
return self.OBJECT
|
return self.OBJECT
|
@ -1,5 +1,5 @@
|
|||||||
from .logic_adapter import LogicAdapter
|
|
||||||
from .best_match import BestMatch
|
from .best_match import BestMatch
|
||||||
|
from .logic_adapter import LogicAdapter
|
||||||
from .low_confidence import LowConfidenceAdapter
|
from .low_confidence import LowConfidenceAdapter
|
||||||
from .mathematical_evaluation import MathematicalEvaluation
|
from .mathematical_evaluation import MathematicalEvaluation
|
||||||
from .multi_adapter import MultiLogicAdapter
|
from .multi_adapter import MultiLogicAdapter
|
||||||
@ -7,7 +7,6 @@ from .no_knowledge_adapter import NoKnowledgeAdapter
|
|||||||
from .specific_response import SpecificResponseAdapter
|
from .specific_response import SpecificResponseAdapter
|
||||||
from .time_adapter import TimeLogicAdapter
|
from .time_adapter import TimeLogicAdapter
|
||||||
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'LogicAdapter',
|
'LogicAdapter',
|
||||||
'BestMatch',
|
'BestMatch',
|
@ -1,4 +1,5 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from .logic_adapter import LogicAdapter
|
from .logic_adapter import LogicAdapter
|
||||||
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
|||||||
from __future__ import unicode_literals
|
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):
|
class LogicAdapter(Adapter):
|
||||||
@ -17,8 +18,8 @@ class LogicAdapter(Adapter):
|
|||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super(LogicAdapter, self).__init__(**kwargs)
|
super(LogicAdapter, self).__init__(**kwargs)
|
||||||
from ..comparisons import levenshtein_distance
|
from chatter.chatterbot.comparisons import levenshtein_distance
|
||||||
from ..response_selection import get_first_response
|
from chatter.chatterbot.response_selection import get_first_response
|
||||||
|
|
||||||
# Import string module parameters
|
# Import string module parameters
|
||||||
if 'statement_comparison_function' in kwargs:
|
if 'statement_comparison_function' in kwargs:
|
@ -1,5 +1,6 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
from ..conversation import Statement
|
|
||||||
|
from chatter.chatterbot.conversation import Statement
|
||||||
from .best_match import BestMatch
|
from .best_match import BestMatch
|
||||||
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
|||||||
from __future__ import unicode_literals
|
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):
|
class MathematicalEvaluation(LogicAdapter):
|
@ -1,6 +1,8 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
from .. import utils
|
|
||||||
|
from chatter.chatterbot import utils
|
||||||
from .logic_adapter import LogicAdapter
|
from .logic_adapter import LogicAdapter
|
||||||
|
|
||||||
|
|
||||||
@ -13,7 +15,7 @@ class MultiLogicAdapter(LogicAdapter):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super().__init__(**kwargs)
|
super(MultiLogicAdapter, self).__init__(**kwargs)
|
||||||
|
|
||||||
# Logic adapters added by the chat bot
|
# Logic adapters added by the chat bot
|
||||||
self.adapters = []
|
self.adapters = []
|
||||||
@ -49,7 +51,7 @@ class MultiLogicAdapter(LogicAdapter):
|
|||||||
if adapter.can_process(statement):
|
if adapter.can_process(statement):
|
||||||
|
|
||||||
output = adapter.process(statement)
|
output = adapter.process(statement)
|
||||||
results.append((output.confidence, output, ))
|
results.append((output.confidence, output,))
|
||||||
|
|
||||||
self.logger.info(
|
self.logger.info(
|
||||||
'{} selected "{}" as a response with a confidence of {}'.format(
|
'{} selected "{}" as a response with a confidence of {}'.format(
|
@ -1,4 +1,5 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from .logic_adapter import LogicAdapter
|
from .logic_adapter import LogicAdapter
|
||||||
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from .logic_adapter import LogicAdapter
|
from .logic_adapter import LogicAdapter
|
||||||
|
|
||||||
|
|
||||||
@ -15,7 +16,7 @@ class SpecificResponseAdapter(LogicAdapter):
|
|||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super(SpecificResponseAdapter, self).__init__(**kwargs)
|
super(SpecificResponseAdapter, self).__init__(**kwargs)
|
||||||
from ..conversation import Statement
|
from chatter.chatterbot.conversation import Statement
|
||||||
|
|
||||||
self.input_text = kwargs.get('input_text')
|
self.input_text = kwargs.get('input_text')
|
||||||
|
|
@ -1,5 +1,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from .logic_adapter import LogicAdapter
|
from .logic_adapter import LogicAdapter
|
||||||
|
|
||||||
|
|
||||||
@ -40,8 +42,8 @@ class TimeLogicAdapter(LogicAdapter):
|
|||||||
])
|
])
|
||||||
|
|
||||||
labeled_data = (
|
labeled_data = (
|
||||||
[(name, 0) for name in self.negative] +
|
[(name, 0) for name in self.negative] +
|
||||||
[(name, 1) for name in self.positive]
|
[(name, 1) for name in self.positive]
|
||||||
)
|
)
|
||||||
|
|
||||||
train_set = [
|
train_set = [
|
||||||
@ -79,7 +81,7 @@ class TimeLogicAdapter(LogicAdapter):
|
|||||||
return features
|
return features
|
||||||
|
|
||||||
def process(self, statement):
|
def process(self, statement):
|
||||||
from ..conversation import Statement
|
from chatter.chatterbot.conversation import Statement
|
||||||
|
|
||||||
now = datetime.now()
|
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 .gitter import Gitter
|
||||||
from .hipchat import HipChat
|
from .hipchat import HipChat
|
||||||
|
from .mailgun import Mailgun
|
||||||
|
from .microsoft import Microsoft
|
||||||
|
from .output_adapter import OutputAdapter
|
||||||
|
from .terminal import TerminalAdapter
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'OutputAdapter',
|
'OutputAdapter',
|
@ -1,4 +1,5 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from .output_adapter import OutputAdapter
|
from .output_adapter import OutputAdapter
|
||||||
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from .output_adapter import OutputAdapter
|
from .output_adapter import OutputAdapter
|
||||||
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from .output_adapter import OutputAdapter
|
from .output_adapter import OutputAdapter
|
||||||
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from .output_adapter import OutputAdapter
|
from .output_adapter import OutputAdapter
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
from ..adapters import Adapter
|
from chatter.chatterbot.adapters import Adapter
|
||||||
|
|
||||||
|
|
||||||
class OutputAdapter(Adapter):
|
class OutputAdapter(Adapter):
|
@ -1,4 +1,5 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from .output_adapter import OutputAdapter
|
from .output_adapter import OutputAdapter
|
||||||
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
import calendar
|
||||||
import re
|
import re
|
||||||
from datetime import timedelta, datetime
|
from datetime import timedelta, datetime
|
||||||
import calendar
|
|
||||||
|
|
||||||
# Variations of dates that the parser can capture
|
# Variations of dates that the parser can capture
|
||||||
year_variations = ['year', 'years', 'yrs']
|
year_variations = ['year', 'years', 'yrs']
|
@ -27,14 +27,9 @@ def unescape_html(chatbot, statement):
|
|||||||
Convert escaped html characters into unescaped html characters.
|
Convert escaped html characters into unescaped html characters.
|
||||||
For example: "<b>" becomes "<b>".
|
For example: "<b>" becomes "<b>".
|
||||||
"""
|
"""
|
||||||
import sys
|
|
||||||
|
|
||||||
# Replace HTML escape characters
|
# Replace HTML escape characters
|
||||||
if sys.version_info[0] < 3:
|
import html
|
||||||
from HTMLParser import HTMLParser
|
|
||||||
html = HTMLParser()
|
|
||||||
else:
|
|
||||||
import html
|
|
||||||
|
|
||||||
statement.text = html.unescape(statement.text)
|
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".
|
For example: "på fédéral" becomes "pa federal".
|
||||||
"""
|
"""
|
||||||
import unicodedata
|
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 = unicodedata.normalize('NFKD', statement.text)
|
||||||
text = text.encode('ascii', 'ignore').decode('utf-8')
|
text = text.encode('ascii', 'ignore').decode('utf-8')
|
@ -1,12 +1,9 @@
|
|||||||
from .storage_adapter import StorageAdapter
|
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
|
||||||
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'StorageAdapter',
|
'StorageAdapter',
|
||||||
'DjangoStorageAdapter',
|
|
||||||
'MongoDatabaseAdapter',
|
'MongoDatabaseAdapter',
|
||||||
'SQLStorageAdapter',
|
'SQLStorageAdapter',
|
||||||
)
|
)
|
@ -1,10 +1,13 @@
|
|||||||
from . import StorageAdapter
|
from chatter.chatterbot.storage import StorageAdapter
|
||||||
|
|
||||||
|
|
||||||
class Query(object):
|
class Query(object):
|
||||||
|
|
||||||
def __init__(self, query={}):
|
def __init__(self, query=None):
|
||||||
self.query = query
|
if query is None:
|
||||||
|
self.query = {}
|
||||||
|
else:
|
||||||
|
self.query = query
|
||||||
|
|
||||||
def value(self):
|
def value(self):
|
||||||
return self.query.copy()
|
return self.query.copy()
|
||||||
@ -116,7 +119,7 @@ class MongoDatabaseAdapter(StorageAdapter):
|
|||||||
"""
|
"""
|
||||||
Return the class for the statement model.
|
Return the class for the statement model.
|
||||||
"""
|
"""
|
||||||
from ..conversation import Statement
|
from chatter.chatterbot.conversation import Statement
|
||||||
|
|
||||||
# Create a storage-aware statement
|
# Create a storage-aware statement
|
||||||
statement = Statement
|
statement = Statement
|
||||||
@ -128,7 +131,7 @@ class MongoDatabaseAdapter(StorageAdapter):
|
|||||||
"""
|
"""
|
||||||
Return the class for the response model.
|
Return the class for the response model.
|
||||||
"""
|
"""
|
||||||
from ..conversation import Response
|
from chatter.chatterbot.conversation import Response
|
||||||
|
|
||||||
# Create a storage-aware response
|
# Create a storage-aware response
|
||||||
response = Response
|
response = Response
|
@ -1,8 +1,8 @@
|
|||||||
from . import StorageAdapter
|
from chatter.chatterbot.storage import StorageAdapter
|
||||||
|
|
||||||
|
|
||||||
def get_response_table(response):
|
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)
|
return Response(text=response.text, occurrence=response.occurrence)
|
||||||
|
|
||||||
|
|
||||||
@ -86,28 +86,28 @@ class SQLStorageAdapter(StorageAdapter):
|
|||||||
"""
|
"""
|
||||||
Return the statement model.
|
Return the statement model.
|
||||||
"""
|
"""
|
||||||
from ..ext.sqlalchemy_app.models import Statement
|
from chatter.chatterbot.ext.sqlalchemy_app.models import Statement
|
||||||
return Statement
|
return Statement
|
||||||
|
|
||||||
def get_response_model(self):
|
def get_response_model(self):
|
||||||
"""
|
"""
|
||||||
Return the response model.
|
Return the response model.
|
||||||
"""
|
"""
|
||||||
from ..ext.sqlalchemy_app.models import Response
|
from chatter.chatterbot.ext.sqlalchemy_app.models import Response
|
||||||
return Response
|
return Response
|
||||||
|
|
||||||
def get_conversation_model(self):
|
def get_conversation_model(self):
|
||||||
"""
|
"""
|
||||||
Return the conversation model.
|
Return the conversation model.
|
||||||
"""
|
"""
|
||||||
from ..ext.sqlalchemy_app.models import Conversation
|
from chatter.chatterbot.ext.sqlalchemy_app.models import Conversation
|
||||||
return Conversation
|
return Conversation
|
||||||
|
|
||||||
def get_tag_model(self):
|
def get_tag_model(self):
|
||||||
"""
|
"""
|
||||||
Return the conversation model.
|
Return the conversation model.
|
||||||
"""
|
"""
|
||||||
from ..ext.sqlalchemy_app.models import Tag
|
from chatter.chatterbot.ext.sqlalchemy_app.models import Tag
|
||||||
return Tag
|
return Tag
|
||||||
|
|
||||||
def count(self):
|
def count(self):
|
||||||
@ -379,14 +379,14 @@ class SQLStorageAdapter(StorageAdapter):
|
|||||||
"""
|
"""
|
||||||
Drop the database attached to a given adapter.
|
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)
|
Base.metadata.drop_all(self.engine)
|
||||||
|
|
||||||
def create(self):
|
def create(self):
|
||||||
"""
|
"""
|
||||||
Populate the database with the tables.
|
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)
|
Base.metadata.create_all(self.engine)
|
||||||
|
|
||||||
def _session_finish(self, session, statement_text=None):
|
def _session_finish(self, session, statement_text=None):
|
@ -24,12 +24,12 @@ class StorageAdapter(object):
|
|||||||
# The string must be lowercase
|
# The string must be lowercase
|
||||||
model_name = model_name.lower()
|
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:
|
if kwarg_model_key in self.kwargs:
|
||||||
return self.kwargs.get(kwarg_model_key)
|
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()
|
return get_model_method()
|
||||||
|
|
||||||
@ -157,7 +157,8 @@ class StorageAdapter(object):
|
|||||||
|
|
||||||
class EmptyDatabaseException(Exception):
|
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
|
self.value = value
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
@ -1,8 +1,9 @@
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from .conversation import Statement, Response
|
|
||||||
from . import utils
|
from . import utils
|
||||||
|
from .conversation import Statement, Response
|
||||||
|
|
||||||
|
|
||||||
class Trainer(object):
|
class Trainer(object):
|
||||||
@ -60,8 +61,8 @@ class Trainer(object):
|
|||||||
|
|
||||||
def __init__(self, value=None):
|
def __init__(self, value=None):
|
||||||
default = (
|
default = (
|
||||||
'A training class must be specified before calling train(). ' +
|
'A training class must be specified before calling train(). ' +
|
||||||
'See http://chatterbot.readthedocs.io/en/stable/training.html'
|
'See http://chatterbot.readthedocs.io/en/stable/training.html'
|
||||||
)
|
)
|
||||||
self.value = value or default
|
self.value = value or default
|
||||||
|
|
||||||
@ -84,7 +85,7 @@ class Trainer(object):
|
|||||||
import json
|
import json
|
||||||
export = {'conversations': self._generate_export_data()}
|
export = {'conversations': self._generate_export_data()}
|
||||||
with open(file_path, 'w+') as jsonfile:
|
with open(file_path, 'w+') as jsonfile:
|
||||||
json.dump(export, jsonfile, ensure_ascii=False)
|
json.dump(export, jsonfile, ensure_ascii=True)
|
||||||
|
|
||||||
|
|
||||||
class ListTrainer(Trainer):
|
class ListTrainer(Trainer):
|
||||||
@ -392,10 +393,9 @@ class UbuntuCorpusTrainer(Trainer):
|
|||||||
|
|
||||||
file_kwargs = {}
|
file_kwargs = {}
|
||||||
|
|
||||||
if sys.version_info[0] > 2:
|
# Specify the encoding in Python versions 3 and up
|
||||||
# Specify the encoding in Python versions 3 and up
|
file_kwargs['encoding'] = 'utf-8'
|
||||||
file_kwargs['encoding'] = 'utf-8'
|
# WARNING: This might fail to read a unicode corpus file in Python 2.x
|
||||||
# WARNING: This might fail to read a unicode corpus file in Python 2.x
|
|
||||||
|
|
||||||
for file in glob.iglob(extracted_corpus_path):
|
for file in glob.iglob(extracted_corpus_path):
|
||||||
self.logger.info('Training from: {}'.format(file))
|
self.logger.info('Training from: {}'.format(file))
|
@ -75,17 +75,8 @@ def input_function():
|
|||||||
Normalizes reading input between python 2 and 3.
|
Normalizes reading input between python 2 and 3.
|
||||||
The function 'raw_input' becomes 'input' in Python 3.
|
The function 'raw_input' becomes 'input' in Python 3.
|
||||||
"""
|
"""
|
||||||
import sys
|
|
||||||
|
|
||||||
if sys.version_info[0] < 3:
|
user_input = input() # NOQA
|
||||||
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
|
|
||||||
|
|
||||||
return user_input
|
return user_input
|
||||||
|
|
||||||
@ -137,7 +128,7 @@ def remove_stopwords(tokens, language):
|
|||||||
Stop words are words like "is, the, a, ..."
|
Stop words are words like "is, the, a, ..."
|
||||||
|
|
||||||
Be sure to download the required NLTK corpus before calling this function:
|
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')
|
- nltk_download_corpus('corpora/stopwords')
|
||||||
"""
|
"""
|
||||||
from nltk.corpus import stopwords
|
from nltk.corpus import stopwords
|
@ -1,10 +1,30 @@
|
|||||||
{
|
{
|
||||||
"author" : ["Bobloy"],
|
"author": [
|
||||||
"bot_version" : [3,0,0],
|
"Bobloy"
|
||||||
"description" : "Create an offline chatbot that talks like your average member using Machine Learning",
|
],
|
||||||
"hidden" : false,
|
"bot_version": [
|
||||||
"install_msg" : "Thank you for installing Chatter!",
|
3,
|
||||||
"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"],
|
0,
|
||||||
"short" : "Local Chatbot run on machine learning",
|
0
|
||||||
"tags" : ["chat", "chatbot", "cleverbot", "clever","bobloy"]
|
],
|
||||||
|
"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"
|
||||||
|
]
|
||||||
}
|
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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)
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user