Pre-moderations, language detection

Kaveen Kumarasinghe 1 year ago
parent 449bb29f19
commit 3f983913ba

@ -29,6 +29,7 @@ SUPPORT SERVER FOR BOT SETUP: https://discord.gg/WvAHXDMS7Q (You can try out the
- [Translations](https://github.com/Kav-K/GPT3Discord/blob/main/detailed_guides/TRANSLATIONS.md)
- [User-Input API Keys](https://github.com/Kav-K/GPT3Discord/blob/main/detailed_guides/USER-INPUT-KEYS.md)
- [Permissions](https://github.com/Kav-K/GPT3Discord/blob/main/detailed_guides/PERMISSIONS.md)
- [Language Detection](https://github.com/Kav-K/GPT3Discord/blob/main/detailed_guides/LANGUAGE-DETECTION.md)
- [Other Minor Features](https://github.com/Kav-K/GPT3Discord/blob/main/detailed_guides/OTHER-MINOR-FEATURES.md)

@ -9,6 +9,7 @@ from sqlitedict import SqliteDict
from services.environment_service import EnvService
from services.image_service import ImageService
from services.moderations_service import Moderation
from services.text_service import TextService
users_to_interactions = {}
@ -16,6 +17,7 @@ ALLOWED_GUILDS = EnvService.get_allowed_guilds()
USER_INPUT_API_KEYS = EnvService.get_user_input_api_keys()
USER_KEY_DB = EnvService.get_api_db()
PRE_MODERATE = EnvService.get_premoderate()
class DrawDallEService(discord.Cog, name="DrawDallEService"):
@ -48,6 +50,11 @@ class DrawDallEService(discord.Cog, name="DrawDallEService"):
await ctx.defer()
# Check the opener for bad content.
if PRE_MODERATE:
if await Moderation.simple_moderate_and_respond(prompt, ctx):
return
user = ctx.user
if user == self.bot.user:

@ -3,11 +3,13 @@ import traceback
import discord
from services.environment_service import EnvService
from services.moderations_service import Moderation
from services.text_service import TextService
from models.index_model import Index_handler
USER_INPUT_API_KEYS = EnvService.get_user_input_api_keys()
USER_KEY_DB = EnvService.get_api_db()
PRE_MODERATE = EnvService.get_premoderate()
class IndexService(discord.Cog, name="IndexService"):
@ -146,6 +148,11 @@ class IndexService(discord.Cog, name="IndexService"):
if not user_api_key:
return
# Check the opener for bad content.
if PRE_MODERATE:
if await Moderation.simple_moderate_and_respond(query, ctx):
return
await self.index_handler.query(ctx, query, response_mode, nodes, user_api_key)
async def compose_command(self, ctx, name):

@ -8,12 +8,14 @@ from models.openai_model import Override
from services.environment_service import EnvService
from models.user_model import RedoUser
from services.image_service import ImageService
from services.moderations_service import Moderation
from services.text_service import TextService
ALLOWED_GUILDS = EnvService.get_allowed_guilds()
USER_INPUT_API_KEYS = EnvService.get_user_input_api_keys()
USER_KEY_DB = EnvService.get_api_db()
PRE_MODERATE = EnvService.get_premoderate()
class ImgPromptOptimizer(discord.Cog, name="ImgPromptOptimizer"):
@ -76,6 +78,11 @@ class ImgPromptOptimizer(discord.Cog, name="ImgPromptOptimizer"):
if not final_prompt.endswith("."):
final_prompt += "."
# Check the opener for bad content.
if PRE_MODERATE:
if await Moderation.simple_moderate_and_respond(prompt, ctx):
return
# Get the token amount for the prompt
# tokens = self.usage_service.count_tokens(final_prompt)

@ -8,12 +8,13 @@ from discord.ext import pages
from models.deepl_model import TranslationModel
from models.search_model import Search
from services.environment_service import EnvService
from services.moderations_service import Moderation
from services.text_service import TextService
ALLOWED_GUILDS = EnvService.get_allowed_guilds()
USER_INPUT_API_KEYS = EnvService.get_user_input_api_keys()
USER_KEY_DB = EnvService.get_api_db()
PRE_MODERATE = EnvService.get_premoderate()
class RedoSearchUser:
def __init__(self, ctx, query, search_scope, nodes):
@ -93,6 +94,11 @@ class SearchService(discord.Cog, name="SearchService"):
"""Command handler for the search command"""
await ctx.defer() if not redo else None
# Check the opener for bad content.
if PRE_MODERATE:
if await Moderation.simple_moderate_and_respond(query, ctx):
return
user_api_key = None
if USER_INPUT_API_KEYS:
user_api_key = await TextService.get_user_api_key(

@ -10,6 +10,7 @@ import json
import discord
from models.deepl_model import TranslationModel
from models.embed_statics_model import EmbedStatics
from models.openai_model import Override
from services.environment_service import EnvService
@ -34,6 +35,8 @@ else:
USER_INPUT_API_KEYS = EnvService.get_user_input_api_keys()
USER_KEY_DB = EnvService.get_api_db()
CHAT_BYPASS_ROLES = EnvService.get_bypass_roles()
PRE_MODERATE = EnvService.get_premoderate()
FORCE_ENGLISH = EnvService.get_force_english()
#
# Obtain the Moderation table and the General table, these are two SQLite tables that contain
@ -77,6 +80,7 @@ class GPT3ComCon(discord.Cog, name="GPT3ComCon"):
self.bot = bot
self.usage_service = usage_service
self.model = model
self.translation_model = TranslationModel()
self.deletion_queue = deletion_queue
# Data specific to all text based GPT interactions
@ -111,6 +115,17 @@ class GPT3ComCon(discord.Cog, name="GPT3ComCon"):
)
assert self.CONVERSATION_STARTER_TEXT is not None
language_detect_file_path = EnvService.find_shared_file(
"language_detection_pretext.txt"
)
# Attempt to read a conversation starter text string from the file.
with language_detect_file_path.open("r") as f:
self.LANGUAGE_DETECT_STARTER_TEXT = f.read()
print(
f"Language detection starter text loaded from {language_detect_file_path}."
)
assert self.LANGUAGE_DETECT_STARTER_TEXT is not None
conversation_file_path_minimal = EnvService.find_shared_file(
"conversation_starter_pretext_minimal.txt"
)
@ -541,6 +556,7 @@ class GPT3ComCon(discord.Cog, name="GPT3ComCon"):
if message.author == self.bot.user:
return
# Moderations service is done here.
if (
hasattr(message, "guild")
@ -560,7 +576,13 @@ class GPT3ComCon(discord.Cog, name="GPT3ComCon"):
).timestamp()
await Moderation.moderation_queues[message.guild.id].put(
Moderation(message, timestamp)
) # TODO Don't proceed to conversation processing if the message is deleted by moderations.
)
# Language check
if FORCE_ENGLISH and len(message.content.split(" ")) > 3:
if not await Moderation.force_english_and_respond(message.content, self.LANGUAGE_DETECT_STARTER_TEXT, message):
await message.delete()
return
# Process the message if the user is in a conversation
if await TextService.process_conversation_message(
@ -778,6 +800,11 @@ class GPT3ComCon(discord.Cog, name="GPT3ComCon"):
await ctx.defer(ephemeral=private) if is_context else None
# If premoderation is enabled, check
if PRE_MODERATE:
if await Moderation.simple_moderate_and_respond(prompt, ctx):
return
overrides = Override(temperature, top_p, frequency_penalty, presence_penalty)
await TextService.encapsulated_send(
@ -826,6 +853,10 @@ class GPT3ComCon(discord.Cog, name="GPT3ComCon"):
await ctx.defer(ephemeral=private)
if PRE_MODERATE:
if await Moderation.simple_moderate_and_respond(instruction + text, ctx):
return
overrides = Override(temperature, top_p, 0, 0)
await TextService.encapsulated_send(
@ -894,6 +925,11 @@ class GPT3ComCon(discord.Cog, name="GPT3ComCon"):
elif not private:
await ctx.defer()
# Check the opener for bad content.
if PRE_MODERATE and opener is not None:
if await Moderation.simple_moderate_and_respond(opener, ctx):
return
# if user.id in self.conversation_thread_owners:
# await ctx.respond(
# "You've already created a thread, end it before creating a new one",
@ -989,6 +1025,7 @@ class GPT3ComCon(discord.Cog, name="GPT3ComCon"):
# Append the starter text for gpt3 to the user's history so it gets concatenated with the prompt later
if minimal or opener_file or opener:
self.conversation_threads[thread.id].history.append(
EmbeddedConversationItem(self.CONVERSATION_STARTER_TEXT_MINIMAL, 0)
)

@ -21,6 +21,8 @@ There are two thresholds for the bot, there are instances in which the bot will
If you'd like to help us test and fine tune our thresholds for the moderation service, please join this test server: https://discord.gg/CWhsSgNdrP. You can let off some steam in a controlled environment ;)
To set a certain role immune to moderations, add the line `CHAT_BYPASS_ROLES="Role1,Role2,etc"` to your `.env file.
If you want to have the bot pre-moderate things sent to commands like /gpt ask, /gpt edit, /dalle draw, etc, you can set `PRE_MODERATE="True"` in the `.env` file.
**The above server is NOT for support or discussions about GPT3Discord**

@ -0,0 +1,7 @@
## Language Detection
Using GPT, this bot can force everybody on your server to speak English. Simply add the environment variable `FORCE_ENGLISH="True"` to your `.env` file and the bot will automatically delete foreign language messages.
This feature is in beta and may be buggy, so we're looking for your feedback on it to help us improve.
This feature currently using `text-davinci-003`, so this is certainly an expensive feature to run if you have a lot of people in your server. Be careful.

@ -31,7 +31,7 @@ from services.environment_service import EnvService
from models.openai_model import Model
__version__ = "10.5.0"
__version__ = "10.6.0"
PID_FILE = Path("bot.pid")

@ -0,0 +1,63 @@
You are to be given some text in an unspecified language. Detect if the primary language of the text is english. Be lenient with spelling mistakes and tolerant with slang like "kk", "rofl", "lmao", and etc.. The text will likely be informal, with slurring of text and slang. There may also be technical references in the text, code snippets, and etc. These are usually already in English. Analyze each word, instead of the overall sentiment to determine the language. Return 'True' if the text is in English, otherwise return 'False'.
Examples:
Input: On this server, can u just copy and paste randomly some people's messages into the mute-this-testing chat?
Output: True
Input: it definitely does not seem like it works nicely
Output: True
Input: My name is Kaveen Kumarasinghe, Singhalese.
Output: True
Input: heeeeeeeeeeeeeeeey guys my name is Kaveen
Output: True
Input: but it could have something due with how long she waits before releasing the crack
Output: True
Input: me mande uma index.html com sistema de Login
Output: False
Input: oi tudo bem?
Output: False
Input: bonsoir, je m'appelle Kav
Output: False
Input: create a basic phyton code
Output: True
Input: not helping ukraine is nati patriotism, ure actively going agaisnt the idea of being a chad nato country legit walking up to russias borders
Output: True
Input: torch==1.9.1+cpu torchvision==0.10.1+cpu
Output: True
Input: sounds good kk, lmao
Output: True
Input: where tf is the pricing for text-davinci-002
Output: True
Input: https://clips.twitch.tv/GrossAdorableWolfStrawBeary-m2cXYk0Z89_UPojL
Output: True
Input:
def detect_language(text):
"""Detects the text's language."""
from google.cloud import translate_v2 as translate
translate_client = translate.Client()
# Text can also be a sequence of strings, in which case this method
# will return a sequence of results for each text.
result = translate_client.detect_language(text)
print("Text: {}".format(text))
print("Confidence: {}".format(result["confidence"]))
print("Language: {}".format(result["language"]))
Output: True
Now, detect the language.
Input:

@ -204,6 +204,10 @@ class Model:
else 5
)
print("Building language detector")
#self.detector = LanguageDetectorBuilder.from_languages(*Language.all()).build()
print("Language detector built")
def reset_settings(self):
keys = [
"temp",
@ -750,6 +754,58 @@ class Model:
return response
# async def send_language_detect_request_local(self, text):
# detected = await asyncio.get_running_loop().run_in_executor(
# None, self.detector.compute_language_confidence, text, Language.ENGLISH
# )
# if detected < 0.03:
# return False
# return True
@backoff.on_exception(
backoff.expo,
ValueError,
factor=3,
base=5,
max_tries=4,
on_backoff=backoff_handler_request,
)
async def send_language_detect_request(
self,
text,
pretext,
) -> (
Tuple[dict, bool]
): # The response, and a boolean indicating whether or not the context limit was reached.
# Validate that all the parameters are in a good state before we send the request
prompt = f"{pretext}{text}\nOutput:"
max_tokens = Models.get_max_tokens(Models.DAVINCI) - self.usage_service.count_tokens(prompt)
print(f"Language detection request for {text}")
async with aiohttp.ClientSession(raise_for_status=False) as session:
payload = {
"model": Models.DAVINCI,
"prompt": prompt,
"temperature": 0,
"top_p": 1,
"max_tokens": max_tokens
}
headers = {
"Authorization": f"Bearer {self.openai_key}"
}
async with session.post(
"https://api.openai.com/v1/completions", json=payload, headers=headers
) as resp:
response = await resp.json()
await self.valid_text_request(response)
print(f"Response -> {response}")
return response
@backoff.on_exception(
backoff.expo,
ValueError,

@ -22,4 +22,10 @@ USER_INPUT_API_KEYS="False" # If True, users must use their own API keys for Ope
MODERATIONS_ALERT_CHANNEL = "977697652147892304"
# User API key db path configuration. This is where the user API keys will be stored.
USER_KEY_DB_PATH = "user_key_db.sqlite"
USER_KEY_DB_PATH = "user_key_db.sqlite"
# Moderate things sent to /gpt ask and etc
PRE_MODERATE = "False"
# Force only english to be spoken in the server
FORCE_ENGLISH = "False"

@ -248,6 +248,26 @@ class EnvService:
except Exception:
return False
@staticmethod
def get_premoderate():
try:
pre_moderate = os.getenv("PRE_MODERATE")
if pre_moderate.lower().strip() == "true":
return True
return False
except Exception:
return False
@staticmethod
def get_force_english():
try:
force_english = os.getenv("FORCE_ENGLISH")
if force_english.lower().strip() == "true":
return True
return False
except Exception:
return False
@staticmethod
def get_custom_bot_name():
try:

@ -106,6 +106,69 @@ class Moderation:
)
return embed
@staticmethod
def build_safety_blocked_message():
# Create a discord embed to send to the user when their message gets moderated
embed = discord.Embed(
title="Your request was blocked by the safety system",
description="Our automatic moderation systems detected that your request was inappropriate and it has not been sent. Please review the usage guidelines.",
colour=discord.Colour.red(),
)
# Set the embed thumbnail
embed.set_thumbnail(url="https://i.imgur.com/2oL8JSp.png")
embed.set_footer(
text="If you think this was a mistake, please contact the server admins."
)
return embed
@staticmethod
def build_non_english_message():
# Create a discord embed to send to the user when their message gets moderated
embed = discord.Embed(
title="Your message was moderated",
description="Our automatic moderation systems detected that your message was not in English and has been deleted. Please review the rules.",
colour=discord.Colour.red(),
)
# Set the embed thumbnail
embed.set_thumbnail(url="https://i.imgur.com/2oL8JSp.png")
embed.set_footer(
text="If you think this was a mistake, please contact the server admins."
)
return embed
@staticmethod
async def force_english_and_respond(text, pretext, ctx):
response = await model.send_language_detect_request(text, pretext)
response_text = response['choices'][0]['text']
if "false" in response_text.lower().strip():
if isinstance(ctx, discord.Message):
await ctx.reply(embed=Moderation.build_non_english_message())
else:
await ctx.respond(embed=Moderation.build_non_english_message())
return False
return True
@staticmethod
async def simple_moderate(text):
return await model.send_moderations_request(text)
@staticmethod
async def simple_moderate_and_respond(text, ctx):
pre_mod_set = ThresholdSet(0.26, 0.26, 0.1, 0.95, 0.03, 0.95, 0.4)
response = await Moderation.simple_moderate(text)
print(response)
flagged = True if Moderation.determine_moderation_result(text, response, pre_mod_set, pre_mod_set) == ModerationResult.DELETE else False
if flagged:
if isinstance(ctx, discord.Message):
await ctx.reply(embed=Moderation.build_safety_blocked_message())
else:
await ctx.respond(embed=Moderation.build_safety_blocked_message())
return True
return False
@staticmethod
def build_admin_warning_message(
moderated_message, deleted_message=None, timed_out=None

@ -11,8 +11,10 @@ from services.deletion_service import Deletion
from models.openai_model import Model, Override
from models.user_model import EmbeddedConversationItem, RedoUser
from services.environment_service import EnvService
from services.moderations_service import Moderation
BOT_NAME = EnvService.get_custom_bot_name()
PRE_MODERATE = EnvService.get_premoderate()
class TextService:
@ -261,6 +263,7 @@ class TextService:
await converser_cog.end_conversation(ctx)
return
# Send the request to the model
if from_edit_command:
response = await converser_cog.model.send_edit_request(
@ -533,6 +536,12 @@ class TextService:
return
if conversing:
# Pre-moderation check
if PRE_MODERATE:
if await Moderation.simple_moderate_and_respond(message.content, message):
await message.delete()
return
user_api_key = None
if USER_INPUT_API_KEYS:
user_api_key = await TextService.get_user_api_key(

Loading…
Cancel
Save