Merge branch 'bobloy:master' into master
This commit is contained in:
commit
a7ce815e14
@ -74,12 +74,18 @@ If you get an error at this step, stop and skip to one of the manual methods bel
|
|||||||
|
|
||||||
#### Step 2: Install additional dependencies
|
#### Step 2: Install additional dependencies
|
||||||
|
|
||||||
Assuming the previous commands had no error, you can now use `pipinstall` to add the remaining dependencies.
|
Here you need to decide which training models you want to have available to you.
|
||||||
|
|
||||||
NOTE: This method is not the intended use case for `pipinstall` and may stop working in the future.
|
Shutdown the bot and run any number of these in the console:
|
||||||
|
|
||||||
```
|
```
|
||||||
[p]pipinstall --no-deps chatterbot>=1.1
|
python -m spacy download en_core_web_sm # ~15 MB
|
||||||
|
|
||||||
|
python -m spacy download en_core_web_md # ~50 MB
|
||||||
|
|
||||||
|
python -m spacy download en_core_web_lg # ~750 MB (CPU Optimized)
|
||||||
|
|
||||||
|
python -m spacy download en_core_web_trf # ~500 MB (GPU Optimized)
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Step 3: Load the cog and get started
|
#### Step 3: Load the cog and get started
|
||||||
@ -89,62 +95,14 @@ NOTE: This method is not the intended use case for `pipinstall` and may stop wor
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Windows - Manually
|
### Windows - Manually
|
||||||
#### Step 1: Built-in Downloader
|
Deprecated
|
||||||
|
|
||||||
You need to get a copy of the requirements.txt provided with chatter, I recommend this method.
|
|
||||||
|
|
||||||
```
|
|
||||||
[p]repo add Fox https://github.com/bobloy/Fox-V3
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Step 2: Install Requirements
|
|
||||||
|
|
||||||
Make sure you have your virtual environment that you installed Red on activated before starting this step. See the Red Docs for details on how.
|
|
||||||
|
|
||||||
In a terminal running as an admin, navigate to the directory containing this repo.
|
|
||||||
|
|
||||||
I've used my install directory as an example.
|
|
||||||
|
|
||||||
```
|
|
||||||
cd C:\Users\Bobloy\AppData\Local\Red-DiscordBot\Red-DiscordBot\data\bobbot\cogs\RepoManager\repos\Fox\chatter
|
|
||||||
pip install -r requirements.txt
|
|
||||||
pip install --no-deps "chatterbot>=1.1"
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Step 3: Load Chatter
|
|
||||||
|
|
||||||
```
|
|
||||||
[p]repo add Fox https://github.com/bobloy/Fox-V3 # If you didn't already do this in step 1
|
|
||||||
[p]cog install Fox chatter
|
|
||||||
[p]load chatter
|
|
||||||
```
|
|
||||||
|
|
||||||
### Linux - Manually
|
### Linux - Manually
|
||||||
|
Deprecated
|
||||||
#### Step 1: Built-in Downloader
|
|
||||||
|
|
||||||
```
|
|
||||||
[p]repo add Fox https://github.com/bobloy/Fox-V3
|
|
||||||
[p]cog install Fox chatter
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Step 2: Install Requirements
|
|
||||||
|
|
||||||
In your console with your virtual environment activated:
|
|
||||||
|
|
||||||
```
|
|
||||||
pip install --no-deps "chatterbot>=1.1"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 3: Load Chatter
|
|
||||||
|
|
||||||
```
|
|
||||||
[p]load chatter
|
|
||||||
```
|
|
||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
|
|
||||||
Chatter works out the the box without any training by learning as it goes,
|
Chatter works out the box without any training by learning as it goes,
|
||||||
but will have very poor and repetitive responses at first.
|
but will have very poor and repetitive responses at first.
|
||||||
|
|
||||||
Initial training is recommended to speed up its learning.
|
Initial training is recommended to speed up its learning.
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
from .chat import Chatter
|
from .chat import Chatter
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
async def setup(bot):
|
||||||
bot.add_cog(Chatter(bot))
|
cog = Chatter(bot)
|
||||||
|
await cog.initialize()
|
||||||
|
bot.add_cog(cog)
|
||||||
|
|
||||||
|
|
||||||
# __all__ = (
|
# __all__ = (
|
||||||
|
@ -19,6 +19,7 @@ from redbot.core.utils.predicates import MessagePredicate
|
|||||||
|
|
||||||
from chatter.trainers import MovieTrainer, TwitterCorpusTrainer, UbuntuCorpusTrainer2
|
from chatter.trainers import MovieTrainer, TwitterCorpusTrainer, UbuntuCorpusTrainer2
|
||||||
|
|
||||||
|
chatterbot_log = logging.getLogger("red.fox_v3.chatterbot")
|
||||||
log = logging.getLogger("red.fox_v3.chatter")
|
log = logging.getLogger("red.fox_v3.chatter")
|
||||||
|
|
||||||
|
|
||||||
@ -29,6 +30,12 @@ def my_local_get_prefix(prefixes, content):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class ENG_TRF:
|
||||||
|
ISO_639_1 = "en_core_web_trf"
|
||||||
|
ISO_639 = "eng"
|
||||||
|
ENGLISH_NAME = "English"
|
||||||
|
|
||||||
|
|
||||||
class ENG_LG:
|
class ENG_LG:
|
||||||
ISO_639_1 = "en_core_web_lg"
|
ISO_639_1 = "en_core_web_lg"
|
||||||
ISO_639 = "eng"
|
ISO_639 = "eng"
|
||||||
@ -52,12 +59,15 @@ class Chatter(Cog):
|
|||||||
This cog trains a chatbot that will talk like members of your Guild
|
This cog trains a chatbot that will talk like members of your Guild
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
models = [ENG_SM, ENG_MD, ENG_LG, ENG_TRF]
|
||||||
|
algos = [SpacySimilarity, JaccardSimilarity, LevenshteinDistance]
|
||||||
|
|
||||||
def __init__(self, bot):
|
def __init__(self, bot):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.config = Config.get_conf(self, identifier=6710497116116101114)
|
self.config = Config.get_conf(self, identifier=6710497116116101114)
|
||||||
default_global = {"learning": True}
|
default_global = {"learning": True, "model_number": 0, "algo_number": 0, "threshold": 0.90}
|
||||||
default_guild = {
|
self.default_guild = {
|
||||||
"whitelist": None,
|
"whitelist": None,
|
||||||
"days": 1,
|
"days": 1,
|
||||||
"convo_delta": 15,
|
"convo_delta": 15,
|
||||||
@ -70,16 +80,16 @@ class Chatter(Cog):
|
|||||||
# TODO: Move training_model and similarity_algo to config
|
# TODO: Move training_model and similarity_algo to config
|
||||||
# TODO: Add an option to see current settings
|
# TODO: Add an option to see current settings
|
||||||
|
|
||||||
self.tagger_language = ENG_MD
|
self.tagger_language = ENG_SM
|
||||||
self.similarity_algo = SpacySimilarity
|
self.similarity_algo = SpacySimilarity
|
||||||
self.similarity_threshold = 0.90
|
self.similarity_threshold = 0.90
|
||||||
self.chatbot = self._create_chatbot()
|
self.chatbot = None
|
||||||
# self.chatbot.set_trainer(ListTrainer)
|
# self.chatbot.set_trainer(ListTrainer)
|
||||||
|
|
||||||
# self.trainer = ListTrainer(self.chatbot)
|
# self.trainer = ListTrainer(self.chatbot)
|
||||||
|
|
||||||
self.config.register_global(**default_global)
|
self.config.register_global(**default_global)
|
||||||
self.config.register_guild(**default_guild)
|
self.config.register_guild(**self.default_guild)
|
||||||
|
|
||||||
self.loop = asyncio.get_event_loop()
|
self.loop = asyncio.get_event_loop()
|
||||||
|
|
||||||
@ -92,6 +102,18 @@ class Chatter(Cog):
|
|||||||
"""Nothing to delete"""
|
"""Nothing to delete"""
|
||||||
return
|
return
|
||||||
|
|
||||||
|
async def initialize(self):
|
||||||
|
all_config = dict(self.config.defaults["GLOBAL"])
|
||||||
|
all_config.update(await self.config.all())
|
||||||
|
model_number = all_config["model_number"]
|
||||||
|
algo_number = all_config["algo_number"]
|
||||||
|
threshold = all_config["threshold"]
|
||||||
|
|
||||||
|
self.tagger_language = self.models[model_number]
|
||||||
|
self.similarity_algo = self.algos[algo_number]
|
||||||
|
self.similarity_threshold = threshold
|
||||||
|
self.chatbot = self._create_chatbot()
|
||||||
|
|
||||||
def _create_chatbot(self):
|
def _create_chatbot(self):
|
||||||
|
|
||||||
return ChatBot(
|
return ChatBot(
|
||||||
@ -104,7 +126,7 @@ class Chatter(Cog):
|
|||||||
logic_adapters=["chatterbot.logic.BestMatch"],
|
logic_adapters=["chatterbot.logic.BestMatch"],
|
||||||
maximum_similarity_threshold=self.similarity_threshold,
|
maximum_similarity_threshold=self.similarity_threshold,
|
||||||
tagger_language=self.tagger_language,
|
tagger_language=self.tagger_language,
|
||||||
logger=log,
|
logger=chatterbot_log,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def _get_conversation(self, ctx, in_channels: List[discord.TextChannel]):
|
async def _get_conversation(self, ctx, in_channels: List[discord.TextChannel]):
|
||||||
@ -328,15 +350,12 @@ class Chatter(Cog):
|
|||||||
self, ctx: commands.Context, algo_number: int, threshold: float = None
|
self, ctx: commands.Context, algo_number: int, threshold: float = None
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Switch the active logic algorithm to one of the three. Default after reload is Spacy
|
Switch the active logic algorithm to one of the three. Default is Spacy
|
||||||
|
|
||||||
0: Spacy
|
0: Spacy
|
||||||
1: Jaccard
|
1: Jaccard
|
||||||
2: Levenshtein
|
2: Levenshtein
|
||||||
"""
|
"""
|
||||||
|
|
||||||
algos = [SpacySimilarity, JaccardSimilarity, LevenshteinDistance]
|
|
||||||
|
|
||||||
if algo_number < 0 or algo_number > 2:
|
if algo_number < 0 or algo_number > 2:
|
||||||
await ctx.send_help()
|
await ctx.send_help()
|
||||||
return
|
return
|
||||||
@ -349,8 +368,11 @@ class Chatter(Cog):
|
|||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
self.similarity_threshold = threshold
|
self.similarity_threshold = threshold
|
||||||
|
await self.config.threshold.set(self.similarity_threshold)
|
||||||
|
|
||||||
|
self.similarity_algo = self.algos[algo_number]
|
||||||
|
await self.config.algo_number.set(algo_number)
|
||||||
|
|
||||||
self.similarity_algo = algos[algo_number]
|
|
||||||
async with ctx.typing():
|
async with ctx.typing():
|
||||||
self.chatbot = self._create_chatbot()
|
self.chatbot = self._create_chatbot()
|
||||||
|
|
||||||
@ -360,20 +382,18 @@ class Chatter(Cog):
|
|||||||
@chatter.command(name="model")
|
@chatter.command(name="model")
|
||||||
async def chatter_model(self, ctx: commands.Context, model_number: int):
|
async def chatter_model(self, ctx: commands.Context, model_number: int):
|
||||||
"""
|
"""
|
||||||
Switch the active model to one of the three. Default after reload is Medium
|
Switch the active model to one of the three. Default is Small
|
||||||
|
|
||||||
0: Small
|
0: Small
|
||||||
1: Medium
|
1: Medium (Requires additional setup)
|
||||||
2: Large (Requires additional setup)
|
2: Large (Requires additional setup)
|
||||||
|
3. Accurate (Requires additional setup)
|
||||||
"""
|
"""
|
||||||
|
if model_number < 0 or model_number > 3:
|
||||||
models = [ENG_SM, ENG_MD, ENG_LG]
|
|
||||||
|
|
||||||
if model_number < 0 or model_number > 2:
|
|
||||||
await ctx.send_help()
|
await ctx.send_help()
|
||||||
return
|
return
|
||||||
|
|
||||||
if model_number == 2:
|
if model_number >= 0:
|
||||||
await ctx.maybe_send_embed(
|
await ctx.maybe_send_embed(
|
||||||
"Additional requirements needed. See guide before continuing.\n" "Continue?"
|
"Additional requirements needed. See guide before continuing.\n" "Continue?"
|
||||||
)
|
)
|
||||||
@ -386,7 +406,8 @@ class Chatter(Cog):
|
|||||||
if not pred.result:
|
if not pred.result:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.tagger_language = models[model_number]
|
self.tagger_language = self.models[model_number]
|
||||||
|
await self.config.model_number.set(model_number)
|
||||||
async with ctx.typing():
|
async with ctx.typing():
|
||||||
self.chatbot = self._create_chatbot()
|
self.chatbot = self._create_chatbot()
|
||||||
|
|
||||||
@ -395,7 +416,13 @@ class Chatter(Cog):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@commands.is_owner()
|
@commands.is_owner()
|
||||||
@chatter.command(name="minutes")
|
@chatter.group(name="trainset")
|
||||||
|
async def chatter_trainset(self, ctx: commands.Context):
|
||||||
|
"""Commands for configuring training"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@commands.is_owner()
|
||||||
|
@chatter_trainset.command(name="minutes")
|
||||||
async def minutes(self, ctx: commands.Context, minutes: int):
|
async def minutes(self, ctx: commands.Context, minutes: int):
|
||||||
"""
|
"""
|
||||||
Sets the number of minutes the bot will consider a break in a conversation during training
|
Sets the number of minutes the bot will consider a break in a conversation during training
|
||||||
@ -411,7 +438,7 @@ class Chatter(Cog):
|
|||||||
await ctx.tick()
|
await ctx.tick()
|
||||||
|
|
||||||
@commands.is_owner()
|
@commands.is_owner()
|
||||||
@chatter.command(name="age")
|
@chatter_trainset.command(name="age")
|
||||||
async def age(self, ctx: commands.Context, days: int):
|
async def age(self, ctx: commands.Context, days: int):
|
||||||
"""
|
"""
|
||||||
Sets the number of days to look back
|
Sets the number of days to look back
|
||||||
@ -630,7 +657,7 @@ class Chatter(Cog):
|
|||||||
|
|
||||||
guild: discord.Guild = getattr(message, "guild", None)
|
guild: discord.Guild = getattr(message, "guild", None)
|
||||||
|
|
||||||
if await self.bot.cog_disabled_in_guild(self, guild):
|
if guild is None or await self.bot.cog_disabled_in_guild(self, guild):
|
||||||
return
|
return
|
||||||
|
|
||||||
ctx: commands.Context = await self.bot.get_context(message)
|
ctx: commands.Context = await self.bot.get_context(message)
|
||||||
@ -705,7 +732,9 @@ class Chatter(Cog):
|
|||||||
)
|
)
|
||||||
|
|
||||||
replying = None
|
replying = None
|
||||||
if self._guild_cache[guild.id]["reply"]:
|
if (
|
||||||
|
"reply" not in self._guild_cache[guild.id] and self.default_guild["reply"]
|
||||||
|
) or self._guild_cache[guild.id]["reply"]:
|
||||||
if message != ctx.channel.last_message:
|
if message != ctx.channel.last_message:
|
||||||
replying = message
|
replying = message
|
||||||
|
|
||||||
|
@ -7,17 +7,7 @@
|
|||||||
"hidden": false,
|
"hidden": false,
|
||||||
"install_msg": "Thank you for installing Chatter! Please make sure you check the install instructions at https://github.com/bobloy/Fox-V3/blob/master/chatter/README.md\nAfter that, get started ith `[p]load chatter` and `[p]help Chatter`",
|
"install_msg": "Thank you for installing Chatter! Please make sure you check the install instructions at https://github.com/bobloy/Fox-V3/blob/master/chatter/README.md\nAfter that, get started ith `[p]load chatter` and `[p]help Chatter`",
|
||||||
"requirements": [
|
"requirements": [
|
||||||
"git+git://github.com/gunthercox/chatterbot-corpus@master#egg=chatterbot_corpus",
|
"git+git://github.com/bobloy/ChatterBot@fox#egg=ChatterBot",
|
||||||
"mathparse>=0.1,<0.2",
|
|
||||||
"nltk>=3.2,<4.0",
|
|
||||||
"pint>=0.8.1",
|
|
||||||
"python-dateutil>=2.8,<2.9",
|
|
||||||
"pyyaml>=5.3,<5.4",
|
|
||||||
"sqlalchemy>=1.3,<1.4",
|
|
||||||
"pytz",
|
|
||||||
"https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-2.3.1/en_core_web_sm-2.3.1.tar.gz#egg=en_core_web_sm",
|
|
||||||
"https://github.com/explosion/spacy-models/releases/download/en_core_web_md-2.3.1/en_core_web_md-2.3.1.tar.gz#egg=en_core_web_md",
|
|
||||||
"spacy>=2.3,<2.4",
|
|
||||||
"kaggle"
|
"kaggle"
|
||||||
],
|
],
|
||||||
"short": "Local Chatbot run on machine learning",
|
"short": "Local Chatbot run on machine learning",
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
git+git://github.com/gunthercox/chatterbot-corpus@master#egg=chatterbot_corpus
|
|
||||||
mathparse>=0.1,<0.2
|
|
||||||
nltk>=3.2,<4.0
|
|
||||||
pint>=0.8.1
|
|
||||||
python-dateutil>=2.8,<2.9
|
|
||||||
pyyaml>=5.3,<5.4
|
|
||||||
sqlalchemy>=1.3,<1.4
|
|
||||||
pytz
|
|
||||||
spacy>=2.3,<2.4
|
|
||||||
https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-2.3.1/en_core_web_sm-2.3.1.tar.gz#egg=en_core_web_sm
|
|
||||||
https://github.com/explosion/spacy-models/releases/download/en_core_web_md-2.3.1/en_core_web_md-2.3.1.tar.gz#egg=en_core_web_md
|
|
||||||
# https://github.com/explosion/spacy-models/releases/download/en_core_web_lg-2.3.1/en_core_web_lg-2.3.1.tar.gz#egg=en_core_web_lg
|
|
@ -5,7 +5,7 @@ class MyDumbSQLStorageAdapter(SQLStorageAdapter):
|
|||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super(SQLStorageAdapter, self).__init__(**kwargs)
|
super(SQLStorageAdapter, self).__init__(**kwargs)
|
||||||
|
|
||||||
from sqlalchemy import create_engine
|
from sqlalchemy import create_engine, inspect
|
||||||
from sqlalchemy.orm import sessionmaker
|
from sqlalchemy.orm import sessionmaker
|
||||||
|
|
||||||
self.database_uri = kwargs.get("database_uri", False)
|
self.database_uri = kwargs.get("database_uri", False)
|
||||||
@ -18,9 +18,7 @@ class MyDumbSQLStorageAdapter(SQLStorageAdapter):
|
|||||||
if not self.database_uri:
|
if not self.database_uri:
|
||||||
self.database_uri = "sqlite:///db.sqlite3"
|
self.database_uri = "sqlite:///db.sqlite3"
|
||||||
|
|
||||||
self.engine = create_engine(
|
self.engine = create_engine(self.database_uri, connect_args={"check_same_thread": False})
|
||||||
self.database_uri, convert_unicode=True, connect_args={"check_same_thread": False}
|
|
||||||
)
|
|
||||||
|
|
||||||
if self.database_uri.startswith("sqlite://"):
|
if self.database_uri.startswith("sqlite://"):
|
||||||
from sqlalchemy.engine import Engine
|
from sqlalchemy.engine import Engine
|
||||||
@ -31,7 +29,7 @@ class MyDumbSQLStorageAdapter(SQLStorageAdapter):
|
|||||||
dbapi_connection.execute("PRAGMA journal_mode=WAL")
|
dbapi_connection.execute("PRAGMA journal_mode=WAL")
|
||||||
dbapi_connection.execute("PRAGMA synchronous=NORMAL")
|
dbapi_connection.execute("PRAGMA synchronous=NORMAL")
|
||||||
|
|
||||||
if not self.engine.dialect.has_table(self.engine, "Statement"):
|
if not inspect(self.engine).has_table("Statement"):
|
||||||
self.create_database()
|
self.create_database()
|
||||||
|
|
||||||
self.Session = sessionmaker(bind=self.engine, expire_on_commit=True)
|
self.Session = sessionmaker(bind=self.engine, expire_on_commit=True)
|
||||||
|
@ -32,6 +32,7 @@ class RecyclingPlant(Cog):
|
|||||||
|
|
||||||
x = 0
|
x = 0
|
||||||
reward = 0
|
reward = 0
|
||||||
|
timeoutcount = 0
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"{0} has signed up for a shift at the Recycling Plant! Type ``exit`` to terminate it early.".format(
|
"{0} has signed up for a shift at the Recycling Plant! Type ``exit`` to terminate it early.".format(
|
||||||
ctx.author.display_name
|
ctx.author.display_name
|
||||||
@ -53,14 +54,25 @@ class RecyclingPlant(Cog):
|
|||||||
return m.author == ctx.author and m.channel == ctx.channel
|
return m.author == ctx.author and m.channel == ctx.channel
|
||||||
|
|
||||||
try:
|
try:
|
||||||
answer = await self.bot.wait_for("message", timeout=120, check=check)
|
answer = await self.bot.wait_for("message", timeout=20, check=check)
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
answer = None
|
answer = None
|
||||||
|
|
||||||
if answer is None:
|
if answer is None:
|
||||||
|
if timeoutcount == 2:
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"``{}`` fell down the conveyor belt to be sorted again!".format(used["object"])
|
"{} slacked off at work, so they were sacked with no pay.".format(
|
||||||
|
ctx.author.display_name
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
await ctx.send(
|
||||||
|
"{} is slacking, and if they carry on not working, they'll be fired.".format(
|
||||||
|
ctx.author.display_name
|
||||||
|
)
|
||||||
|
)
|
||||||
|
timeoutcount += 1
|
||||||
elif answer.content.lower().strip() == used["action"]:
|
elif answer.content.lower().strip() == used["action"]:
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"Congratulations! You put ``{}`` down the correct chute! (**+50**)".format(
|
"Congratulations! You put ``{}`` down the correct chute! (**+50**)".format(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user