Merge branch 'master' into cogguide_develop
This commit is contained in:
commit
11f17e3eed
@ -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
|
||||
|
||||
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
|
||||
@ -89,62 +95,14 @@ NOTE: This method is not the intended use case for `pipinstall` and may stop wor
|
||||
```
|
||||
|
||||
### Windows - Manually
|
||||
#### Step 1: Built-in Downloader
|
||||
|
||||
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
|
||||
```
|
||||
Deprecated
|
||||
|
||||
### Linux - Manually
|
||||
|
||||
#### 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
|
||||
```
|
||||
Deprecated
|
||||
|
||||
# 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.
|
||||
|
||||
Initial training is recommended to speed up its learning.
|
||||
|
@ -1,8 +1,10 @@
|
||||
from .chat import Chatter
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(Chatter(bot))
|
||||
async def setup(bot):
|
||||
cog = Chatter(bot)
|
||||
await cog.initialize()
|
||||
bot.add_cog(cog)
|
||||
|
||||
|
||||
# __all__ = (
|
||||
|
@ -19,6 +19,7 @@ from redbot.core.utils.predicates import MessagePredicate
|
||||
|
||||
from chatter.trainers import MovieTrainer, TwitterCorpusTrainer, UbuntuCorpusTrainer2
|
||||
|
||||
chatterbot_log = logging.getLogger("red.fox_v3.chatterbot")
|
||||
log = logging.getLogger("red.fox_v3.chatter")
|
||||
|
||||
|
||||
@ -29,6 +30,12 @@ def my_local_get_prefix(prefixes, content):
|
||||
return None
|
||||
|
||||
|
||||
class ENG_TRF:
|
||||
ISO_639_1 = "en_core_web_trf"
|
||||
ISO_639 = "eng"
|
||||
ENGLISH_NAME = "English"
|
||||
|
||||
|
||||
class ENG_LG:
|
||||
ISO_639_1 = "en_core_web_lg"
|
||||
ISO_639 = "eng"
|
||||
@ -52,12 +59,15 @@ class Chatter(Cog):
|
||||
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):
|
||||
super().__init__()
|
||||
self.bot = bot
|
||||
self.config = Config.get_conf(self, identifier=6710497116116101114)
|
||||
default_global = {"learning": True}
|
||||
default_guild = {
|
||||
default_global = {"learning": True, "model_number": 0, "algo_number": 0, "threshold": 0.90}
|
||||
self.default_guild = {
|
||||
"whitelist": None,
|
||||
"days": 1,
|
||||
"convo_delta": 15,
|
||||
@ -70,16 +80,16 @@ class Chatter(Cog):
|
||||
# TODO: Move training_model and similarity_algo to config
|
||||
# TODO: Add an option to see current settings
|
||||
|
||||
self.tagger_language = ENG_MD
|
||||
self.tagger_language = ENG_SM
|
||||
self.similarity_algo = SpacySimilarity
|
||||
self.similarity_threshold = 0.90
|
||||
self.chatbot = self._create_chatbot()
|
||||
self.chatbot = None
|
||||
# self.chatbot.set_trainer(ListTrainer)
|
||||
|
||||
# self.trainer = ListTrainer(self.chatbot)
|
||||
|
||||
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()
|
||||
|
||||
@ -92,6 +102,18 @@ class Chatter(Cog):
|
||||
"""Nothing to delete"""
|
||||
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):
|
||||
|
||||
return ChatBot(
|
||||
@ -104,7 +126,7 @@ class Chatter(Cog):
|
||||
logic_adapters=["chatterbot.logic.BestMatch"],
|
||||
maximum_similarity_threshold=self.similarity_threshold,
|
||||
tagger_language=self.tagger_language,
|
||||
logger=log,
|
||||
logger=chatterbot_log,
|
||||
)
|
||||
|
||||
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
|
||||
):
|
||||
"""
|
||||
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
|
||||
1: Jaccard
|
||||
2: Levenshtein
|
||||
"""
|
||||
|
||||
algos = [SpacySimilarity, JaccardSimilarity, LevenshteinDistance]
|
||||
|
||||
if algo_number < 0 or algo_number > 2:
|
||||
await ctx.send_help()
|
||||
return
|
||||
@ -349,8 +368,11 @@ class Chatter(Cog):
|
||||
return
|
||||
else:
|
||||
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():
|
||||
self.chatbot = self._create_chatbot()
|
||||
|
||||
@ -360,20 +382,18 @@ class Chatter(Cog):
|
||||
@chatter.command(name="model")
|
||||
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
|
||||
1: Medium
|
||||
1: Medium (Requires additional setup)
|
||||
2: Large (Requires additional setup)
|
||||
3. Accurate (Requires additional setup)
|
||||
"""
|
||||
|
||||
models = [ENG_SM, ENG_MD, ENG_LG]
|
||||
|
||||
if model_number < 0 or model_number > 2:
|
||||
if model_number < 0 or model_number > 3:
|
||||
await ctx.send_help()
|
||||
return
|
||||
|
||||
if model_number == 2:
|
||||
if model_number >= 0:
|
||||
await ctx.maybe_send_embed(
|
||||
"Additional requirements needed. See guide before continuing.\n" "Continue?"
|
||||
)
|
||||
@ -386,7 +406,8 @@ class Chatter(Cog):
|
||||
if not pred.result:
|
||||
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():
|
||||
self.chatbot = self._create_chatbot()
|
||||
|
||||
@ -395,7 +416,13 @@ class Chatter(Cog):
|
||||
)
|
||||
|
||||
@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):
|
||||
"""
|
||||
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()
|
||||
|
||||
@commands.is_owner()
|
||||
@chatter.command(name="age")
|
||||
@chatter_trainset.command(name="age")
|
||||
async def age(self, ctx: commands.Context, days: int):
|
||||
"""
|
||||
Sets the number of days to look back
|
||||
@ -630,7 +657,7 @@ class Chatter(Cog):
|
||||
|
||||
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
|
||||
|
||||
ctx: commands.Context = await self.bot.get_context(message)
|
||||
@ -705,7 +732,9 @@ class Chatter(Cog):
|
||||
)
|
||||
|
||||
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:
|
||||
replying = message
|
||||
|
||||
|
@ -7,17 +7,7 @@
|
||||
"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`",
|
||||
"requirements": [
|
||||
"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",
|
||||
"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",
|
||||
"git+git://github.com/bobloy/ChatterBot@fox#egg=ChatterBot",
|
||||
"kaggle"
|
||||
],
|
||||
"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):
|
||||
super(SQLStorageAdapter, self).__init__(**kwargs)
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy import create_engine, inspect
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
self.database_uri = kwargs.get("database_uri", False)
|
||||
@ -18,9 +18,7 @@ class MyDumbSQLStorageAdapter(SQLStorageAdapter):
|
||||
if not self.database_uri:
|
||||
self.database_uri = "sqlite:///db.sqlite3"
|
||||
|
||||
self.engine = create_engine(
|
||||
self.database_uri, convert_unicode=True, connect_args={"check_same_thread": False}
|
||||
)
|
||||
self.engine = create_engine(self.database_uri, connect_args={"check_same_thread": False})
|
||||
|
||||
if self.database_uri.startswith("sqlite://"):
|
||||
from sqlalchemy.engine import Engine
|
||||
@ -31,7 +29,7 @@ class MyDumbSQLStorageAdapter(SQLStorageAdapter):
|
||||
dbapi_connection.execute("PRAGMA journal_mode=WAL")
|
||||
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.Session = sessionmaker(bind=self.engine, expire_on_commit=True)
|
||||
|
@ -142,7 +142,7 @@ class FakeMessage(discord.Message):
|
||||
self._update(
|
||||
{
|
||||
"mention_roles": self.raw_role_mentions,
|
||||
"mentions": self.raw_mentions,
|
||||
"mentions": [{"id": _id} for _id in self.raw_mentions],
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -49,7 +49,11 @@ class LoveCalculator(Cog):
|
||||
|
||||
result_image = soup_object.find("img", class_="result__image").get("src")
|
||||
|
||||
result_text = soup_object.find("div", class_="result-text").get_text()
|
||||
result_text = soup_object.find("div", class_="result-text")
|
||||
if result_text is None:
|
||||
result_text = f"{x} and {y} aren't compatible 😔"
|
||||
else:
|
||||
result_text = result_text.get_text()
|
||||
result_text = " ".join(result_text.split())
|
||||
|
||||
try:
|
||||
|
@ -32,6 +32,7 @@ class RecyclingPlant(Cog):
|
||||
|
||||
x = 0
|
||||
reward = 0
|
||||
timeoutcount = 0
|
||||
await ctx.send(
|
||||
"{0} has signed up for a shift at the Recycling Plant! Type ``exit`` to terminate it early.".format(
|
||||
ctx.author.display_name
|
||||
@ -53,14 +54,25 @@ class RecyclingPlant(Cog):
|
||||
return m.author == ctx.author and m.channel == ctx.channel
|
||||
|
||||
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:
|
||||
answer = None
|
||||
|
||||
if answer is None:
|
||||
await ctx.send(
|
||||
"``{}`` fell down the conveyor belt to be sorted again!".format(used["object"])
|
||||
)
|
||||
if timeoutcount == 2:
|
||||
await ctx.send(
|
||||
"{} 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"]:
|
||||
await ctx.send(
|
||||
"Congratulations! You put ``{}`` down the correct chute! (**+50**)".format(
|
||||
|
@ -177,7 +177,3 @@ class SCP(Cog):
|
||||
|
||||
msg = "http://www.scp-wiki.net/log-of-unexplained-locations"
|
||||
await ctx.maybe_send_embed(msg)
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(SCP(bot))
|
||||
|
@ -6,6 +6,7 @@ import discord
|
||||
from redbot.core import Config, checks, commands
|
||||
from redbot.core.bot import Red
|
||||
from redbot.core.commands import Cog
|
||||
from redbot.core.utils.chat_formatting import pagify
|
||||
|
||||
log = logging.getLogger("red.fox_v3.stealemoji")
|
||||
# Replaced with discord.Asset.read()
|
||||
@ -99,7 +100,8 @@ class StealEmoji(Cog):
|
||||
await ctx.maybe_send_embed("No stolen emojis yet")
|
||||
return
|
||||
|
||||
await ctx.maybe_send_embed(emoj)
|
||||
for page in pagify(emoj, delims=[" "]):
|
||||
await ctx.maybe_send_embed(page)
|
||||
|
||||
@checks.is_owner()
|
||||
@stealemoji.command(name="notify")
|
||||
|
@ -295,8 +295,11 @@ class Timerole(Cog):
|
||||
log.exception("Failed Adding Roles")
|
||||
add_results += f"{member.display_name} : **(Failed Adding Roles)**\n"
|
||||
else:
|
||||
add_results += " \n".join(
|
||||
f"{member.display_name} : {role.name}" for role in add_roles
|
||||
add_results += (
|
||||
" \n".join(
|
||||
f"{member.display_name} : {role.name}" for role in add_roles
|
||||
)
|
||||
+ "\n"
|
||||
)
|
||||
for role_id in addlist:
|
||||
await self.config.custom(
|
||||
@ -310,8 +313,11 @@ class Timerole(Cog):
|
||||
log.exception("Failed Removing Roles")
|
||||
remove_results += f"{member.display_name} : **(Failed Removing Roles)**\n"
|
||||
else:
|
||||
remove_results += " \n".join(
|
||||
f"{member.display_name} : {role.name}" for role in remove_roles
|
||||
remove_results += (
|
||||
" \n".join(
|
||||
f"{member.display_name} : {role.name}" for role in remove_roles
|
||||
)
|
||||
+ "\n"
|
||||
)
|
||||
for role_id in removelist:
|
||||
await self.config.custom(
|
||||
|
46
tts/tts.py
46
tts/tts.py
@ -1,11 +1,35 @@
|
||||
import io
|
||||
import logging
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
|
||||
import discord
|
||||
from discord.ext.commands import BadArgument, Converter
|
||||
from gtts import gTTS
|
||||
from gtts.lang import _fallback_deprecated_lang, tts_langs
|
||||
from redbot.core import Config, commands
|
||||
from redbot.core.bot import Red
|
||||
from redbot.core.commands import Cog
|
||||
|
||||
log = logging.getLogger("red.fox_v3.tts")
|
||||
|
||||
if TYPE_CHECKING:
|
||||
ISO639Converter = str
|
||||
else:
|
||||
|
||||
class ISO639Converter(Converter):
|
||||
async def convert(self, ctx, argument) -> str:
|
||||
lang = _fallback_deprecated_lang(argument)
|
||||
|
||||
try:
|
||||
langs = tts_langs()
|
||||
if lang not in langs:
|
||||
raise BadArgument("Language not supported: %s" % lang)
|
||||
except RuntimeError as e:
|
||||
log.debug(str(e), exc_info=True)
|
||||
log.warning(str(e))
|
||||
|
||||
return lang
|
||||
|
||||
|
||||
class TTS(Cog):
|
||||
"""
|
||||
@ -18,7 +42,7 @@ class TTS(Cog):
|
||||
|
||||
self.config = Config.get_conf(self, identifier=9811198108111121, force_registration=True)
|
||||
default_global = {}
|
||||
default_guild = {}
|
||||
default_guild = {"language": "en"}
|
||||
|
||||
self.config.register_global(**default_global)
|
||||
self.config.register_guild(**default_guild)
|
||||
@ -27,13 +51,29 @@ class TTS(Cog):
|
||||
"""Nothing to delete"""
|
||||
return
|
||||
|
||||
@commands.mod()
|
||||
@commands.command()
|
||||
async def ttslang(self, ctx: commands.Context, lang: ISO639Converter):
|
||||
"""
|
||||
Sets the default language for TTS in this guild.
|
||||
|
||||
Default is `en` for English
|
||||
"""
|
||||
await self.config.guild(ctx.guild).language.set(lang)
|
||||
await ctx.send(f"Default tts language set to {lang}")
|
||||
|
||||
@commands.command(aliases=["t2s", "text2"])
|
||||
async def tts(self, ctx: commands.Context, *, text: str):
|
||||
async def tts(
|
||||
self, ctx: commands.Context, lang: Optional[ISO639Converter] = None, *, text: str
|
||||
):
|
||||
"""
|
||||
Send Text to speech messages as an mp3
|
||||
"""
|
||||
if lang is None:
|
||||
lang = await self.config.guild(ctx.guild).language()
|
||||
|
||||
mp3_fp = io.BytesIO()
|
||||
tts = gTTS(text, lang="en")
|
||||
tts = gTTS(text, lang=lang)
|
||||
tts.write_to_fp(mp3_fp)
|
||||
mp3_fp.seek(0)
|
||||
await ctx.send(file=discord.File(mp3_fp, "text.mp3"))
|
||||
|
Loading…
x
Reference in New Issue
Block a user