mirror of
https://github.com/NovaOSS/nova-cord.git
synced 2024-11-25 17:43:57 +01:00
Added ToS verification, key system demo, embeds
This commit is contained in:
parent
d2857910d3
commit
b69d8bd67e
|
@ -1,3 +1,5 @@
|
||||||
# nova-discord
|
# nova-discord
|
||||||
🤖 Discord bot for project Nova, built using [NextCord](https://github.com/nextcord/nextcord) for Python.
|
🤖 Discord bot for project Nova, built using [NextCord](https://github.com/nextcord/nextcord) for Python.
|
||||||
|
|
||||||
|
You can find more information about the bot and how it works on [https://nova-oss.com/novacord](https://nova-oss.com/novacord).
|
||||||
|
|
||||||
|
|
1
cord/__main__.py
Normal file
1
cord/__main__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
import bot
|
96
cord/bot.py
96
cord/bot.py
|
@ -1,8 +1,13 @@
|
||||||
# This example requires the 'members' and 'message_content' privileged intents to function.
|
# This example requires the 'members' and 'message_content' privileged intents to function.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import openai
|
import asyncio
|
||||||
import nextcord
|
import nextcord
|
||||||
|
import requests
|
||||||
|
|
||||||
|
import keys
|
||||||
|
import chatbot
|
||||||
|
import embedder
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from nextcord.ext import commands
|
from nextcord.ext import commands
|
||||||
|
@ -28,45 +33,68 @@ async def on_message(message):
|
||||||
async def chat(interaction: nextcord.Interaction,
|
async def chat(interaction: nextcord.Interaction,
|
||||||
prompt: str = SlashOption(description='AI Prompt', required=True)
|
prompt: str = SlashOption(description='AI Prompt', required=True)
|
||||||
):
|
):
|
||||||
partial_message = await interaction.send('') # empty message
|
await chatbot.respond(interaction, prompt)
|
||||||
message = await partial_message.fetch()
|
|
||||||
|
|
||||||
openai.api_base = os.getenv('OPENAI_BASE', 'https://api.openai.com/v1')
|
@bot.slash_command(description='Sets your DMs up, so you can write the bot.')
|
||||||
openai.api_key = os.getenv('OPENAI_KEY')
|
async def dm(interaction: nextcord.Interaction):
|
||||||
|
try:
|
||||||
|
await interaction.user.create_dm()
|
||||||
|
await embedder.info(interaction.user.dm_channel, 'Hello!')
|
||||||
|
except nextcord.Forbidden:
|
||||||
|
await embedder.error(interaction, text='Please open this server\'s options, go to `Privacy Settings` and enable `Direct Messages` and `Message Requests`.')
|
||||||
|
else:
|
||||||
|
await embedder.ok(interaction, 'Great, DMs are set up successfully!')
|
||||||
|
|
||||||
model = os.getenv('OPENAI_MODEL')
|
@bot.slash_command(description='Get your secret NovaAI API key.')
|
||||||
|
async def key(interaction: nextcord.Interaction):
|
||||||
|
try:
|
||||||
|
resp = requests.post(
|
||||||
|
url='https://nova-oss.com/api/tos-verification',
|
||||||
|
timeout=5,
|
||||||
|
headers={'Content-Type': 'application/json', 'Authorization': os.getenv('TOS_VERIFICATION_KEY')}
|
||||||
|
).json()
|
||||||
|
except Exception as exc:
|
||||||
|
await embedder.error(interaction, """Sorry, the API server for the verification system is not functioning,
|
||||||
|
which means you can\'t create a new key right now. Please report this issue to the staff!""")
|
||||||
|
raise exc
|
||||||
|
|
||||||
async with interaction.channel.typing(): # show the "Typing..."
|
tos_code = resp['code']
|
||||||
completion = openai.ChatCompletion.create(
|
tos_emoji = resp['emoji']
|
||||||
model=model,
|
|
||||||
messages=[
|
tos_message = await embedder.warn(interaction, f"""You have to read the privacy policy and terms of service first.
|
||||||
{'role': 'system', 'content': f"""You are a helpful Discord AI bot based on OpenAI\'s {model} model called "Nova".
|
In the latter, there is a hidden emoji which you'll have to send (NOT react!) in here.
|
||||||
You were developed by NovaAI (website: nova-oss.com) in July of 2023, but your knowledge is limited to mid-2021.
|
|
||||||
Respond using Markdown. Keep things simple and short and directly do what the user says without any fluff.
|
https://nova-oss.com/legal/privacy
|
||||||
For programming code, always make use formatted code blocks like this:
|
https://nova-oss.com/legal/terms?verify={tos_code}
|
||||||
```py
|
|
||||||
print("Hello")
|
I know it's annoying, but it really helps combat spam bots and abuse.
|
||||||
```
|
|
||||||
"""},
|
This message will be deleted and your code will run out **after about 10 minutes**
|
||||||
{'role': 'user', 'content': prompt}
|
if you don't pass the verification, but **feel free to run this command again** at any time.
|
||||||
],
|
""", ephemeral=True)
|
||||||
temperature=0.6,
|
|
||||||
stream=True
|
def check(message): return interaction.user.id == message.author.id and message.content == tos_emoji
|
||||||
|
|
||||||
|
try:
|
||||||
|
answer = await bot.wait_for('message', timeout=666, check=check)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
await tos_message.delete()
|
||||||
|
requests.delete(
|
||||||
|
url=f'https://nova-oss.com/api/tos-verification/{tos_code}',
|
||||||
|
timeout=5,
|
||||||
|
headers={'Content-Type': 'application/json', 'Authorization': os.getenv('TOS_VERIFICATION_KEY')}
|
||||||
)
|
)
|
||||||
|
|
||||||
text = ''
|
else:
|
||||||
|
await answer.delete()
|
||||||
|
api_key = await keys.create(interaction.user)
|
||||||
|
await embedder.ok(interaction, f"""This is your **secret** API key. Don't paste it on untrusted websites, apps or programs.
|
||||||
|
Store it securely using a `.env` file in the environment variables or use a secure password manager like *KeePass*, *ProtonPass* or *Bitwarden*.
|
||||||
|
We reserve the right to __disable your API key at any time__ if you violate our terms of service.
|
||||||
|
If you accept the terms of service and privacy policy, feel free to use the following API key:
|
||||||
|
|
||||||
for event in completion: # loop through word generation in real time
|
## ||`{api_key}`||
|
||||||
try:
|
|
||||||
new_text = event['choices'][0]['delta']['content'] # newly generated word
|
|
||||||
except KeyError: # end
|
|
||||||
break
|
|
||||||
|
|
||||||
text += new_text
|
""", ephemeral=True)
|
||||||
|
|
||||||
if text:
|
|
||||||
await message.edit(content=text)
|
|
||||||
|
|
||||||
await message.add_reaction('✅')
|
|
||||||
|
|
||||||
bot.run(os.getenv('DISCORD_TOKEN'))
|
bot.run(os.getenv('DISCORD_TOKEN'))
|
||||||
|
|
54
cord/chatbot.py
Normal file
54
cord/chatbot.py
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import os
|
||||||
|
import openai
|
||||||
|
|
||||||
|
import embedder
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
async def respond(interaction, prompt):
|
||||||
|
partial_message = await interaction.send('') # empty message
|
||||||
|
message = await partial_message.fetch()
|
||||||
|
|
||||||
|
openai.api_base = os.getenv('OPENAI_BASE', 'https://api.openai.com/v1')
|
||||||
|
openai.api_key = os.getenv('OPENAI_KEY')
|
||||||
|
|
||||||
|
model = os.getenv('OPENAI_MODEL')
|
||||||
|
|
||||||
|
async with interaction.channel.typing(): # show the "Typing..."
|
||||||
|
try:
|
||||||
|
completion = openai.ChatCompletion.create(
|
||||||
|
model=model,
|
||||||
|
messages=[
|
||||||
|
{'role': 'system', 'content': f"""You are a helpful Discord AI bot based on OpenAI\'s {model} model called "Nova".
|
||||||
|
You were developed by NovaAI (website: nova-oss.com) in July of 2023, but your knowledge is limited to mid-2021.
|
||||||
|
Respond using Markdown. Keep things simple and short and directly do what the user says without any fluff.
|
||||||
|
For programming code, always make use formatted code blocks like this:
|
||||||
|
```py
|
||||||
|
print("Hello")
|
||||||
|
```
|
||||||
|
"""},
|
||||||
|
{'role': 'user', 'content': prompt}
|
||||||
|
],
|
||||||
|
temperature=0.6,
|
||||||
|
stream=True
|
||||||
|
)
|
||||||
|
except Exception as exc:
|
||||||
|
await embedder.error(interaction, 'Could not generate an AI response.', ephemeral=True)
|
||||||
|
raise exc
|
||||||
|
|
||||||
|
text = ''
|
||||||
|
|
||||||
|
for event in completion: # loop through word generation in real time
|
||||||
|
try:
|
||||||
|
new_text = event['choices'][0]['delta']['content'] # newly generated word
|
||||||
|
except KeyError: # end
|
||||||
|
break
|
||||||
|
|
||||||
|
text += new_text
|
||||||
|
|
||||||
|
if text:
|
||||||
|
await message.edit(content=text)
|
||||||
|
|
||||||
|
await message.add_reaction('✅')
|
40
cord/embedder.py
Normal file
40
cord/embedder.py
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import nextcord
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
async def send(
|
||||||
|
ctx,
|
||||||
|
title: str,
|
||||||
|
text: str,
|
||||||
|
ephemeral: bool = False,
|
||||||
|
color: nextcord.Color = nextcord.Color.blue()
|
||||||
|
):
|
||||||
|
embed = nextcord.Embed(
|
||||||
|
title=title,
|
||||||
|
description=text,
|
||||||
|
color=color
|
||||||
|
)
|
||||||
|
embed.set_footer(text='Powered by NovaAI', icon_url='https://i.ibb.co/LDyFcSh/fav-blurple.png')
|
||||||
|
embed.set_author(name='NovaCord', url='https://nova-oss.com/novacord')
|
||||||
|
|
||||||
|
if isinstance(ctx, nextcord.Message):
|
||||||
|
response = await ctx.reply(embed=embed)
|
||||||
|
elif isinstance(ctx, Union[nextcord.Interaction, nextcord.InteractionResponse]):
|
||||||
|
response = await ctx.send(embed=embed, ephemeral=ephemeral)
|
||||||
|
else:
|
||||||
|
response = await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
async def ok(ctx, text: str, title: str='Success', *args, **kwargs):
|
||||||
|
return await send(ctx, title, text, color=nextcord.Color.green(), *args, **kwargs)
|
||||||
|
|
||||||
|
async def info(ctx, text: str, title: str='Information', *args, **kwargs):
|
||||||
|
return await send(ctx, title, text, color=nextcord.Color.blue(), *args, **kwargs)
|
||||||
|
|
||||||
|
async def warn(ctx, text: str, title: str='Warning', *args, **kwargs):
|
||||||
|
return await send(ctx, title, text, color=nextcord.Color.orange(), *args, **kwargs)
|
||||||
|
|
||||||
|
async def error(ctx, text: str, title: str='Error - Command Failed', *args, **kwargs):
|
||||||
|
return await send(ctx, title, text, color=nextcord.Color.red(), *args, **kwargs)
|
4
cord/keys.py
Normal file
4
cord/keys.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import secrets
|
||||||
|
|
||||||
|
async def create(user):
|
||||||
|
return 'nv-' + secrets.token_urlsafe(32)
|
1
emojis.txt
Normal file
1
emojis.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
🥇🥈🥉📒📕📗📘📙💩👻💀👽👾🤖🎃💛💚💙💜💔🐶🐱🐭🐹🐰🦊🐻🐼🐨🐯🦁🐮🐷🐽🐸🐵🙊🙉🙊🐒🐔🐧🐦🐤🐣🐥🦆🦅🦉🦇🐺🐗🐴🦄🐝🐛🦋🐌🐚🐞🐢🐍🦎🦂🦀🦑🐙🦐🐠🐟🐡🐬🦈🐳🐋🐊🐆🐅🐂🐄🦌🐪🐫🐘🦏🦍🐎🐖🐐🐏🐑🐕🐩🐈🐓🦃🐇🐁🐀🐾🐉🐲🌵🎄🌲🌳🌴🌱🌿🍀🎍🎋🍃🍂🍁🍄🌾💐🌷🌹🥀🌻🌼🌸🌺🌎🌍🌏🌕🌖🌗🌘🌑🌒🌓🌔🌚🌝🌞🌛🌜🌙💫⭐️🌟✨🔥💥⛅️🌈⛄️💨🌪🌊💧💦🍏🍎🍐🍊🍋🍌🍉🍇🍓🍈🍒🍑🍍🥝🥑🍅🍆🥒🥕🌽🥔🍠🌰🥜🍯🥐🍞🥖🧀🥚🍳🥓🥞🍤🍗🍖🍕🌭🍔🍟🥙🌮🌯🥗🥘🍝🍜🍲🍥🍣🍱🍛🍚🍙🍘🍢🍡🍧🍨🍦🍰🎂🍮🍭🍬🍫🍿🍩🍪🥛🍼🍵🍶🍺🍻🥂🍷🥃🍸🍹🍾🥄🍴⚽️🏀🏈⚾️🎾🏐🏉🎱🏓🏸🥅🏒🏑🏏⛳️🏹🎣🥊🥋
|
Loading…
Reference in a new issue