codellama-bot / app.py
lunarflu's picture
lunarflu HF staff
Update app.py
c1276e2
import asyncio
import json
import os
import threading
from threading import Event
import discord
import gradio as gr
from discord.ext import commands
from gradio_client import Client
event = Event()
DISCORD_TOKEN = os.getenv("DISCORD_TOKEN")
HF_TOKEN = os.getenv("HF_TOKEN")
codellama_client = Client("https://huggingface-projects-codellama-13b-chat.hf.space/", HF_TOKEN)
codellama_threadid_userid_dictionary = {}
codellama_threadid_conversation = {}
intents = discord.Intents.all()
bot = commands.Bot(command_prefix="/", intents=intents)
@bot.event
async def on_ready():
print(f"Logged in as {bot.user} (ID: {bot.user.id})")
synced = await bot.tree.sync()
print(f"Synced commands: {', '.join([s.name for s in synced])}.")
event.set()
print("------")
@bot.hybrid_command(
name="codellama",
description="Enter a prompt to generate code!",
)
async def codellama(ctx, prompt: str):
"""Codellama generation"""
try:
await try_codellama(ctx, prompt)
except Exception as e:
print(f"Error: {e}")
@bot.event
async def on_message(message):
"""Checks channel and continues codellama conversation if it's the right Discord Thread"""
try:
if not message.author.bot:
await continue_codellama(message)
except Exception as e:
print(f"Error: {e}")
async def try_codellama(ctx, prompt):
"""Generates code based on a given prompt"""
try:
if ctx.guild.id == 879548962464493619:
if ctx.channel.id != 1147210106321256508:
return
global codellama_threadid_userid_dictionary
global codellama_threadid_conversation
message = await ctx.send(f"**{prompt}** - {ctx.author.mention}")
thread = await message.create_thread(name=prompt[:100])
loop = asyncio.get_running_loop()
output_code = await loop.run_in_executor(None, codellama_initial_generation, prompt, thread)
codellama_threadid_userid_dictionary[thread.id] = ctx.author.id
await thread.send(output_code)
except Exception as e:
print(f"Error: {e}")
def codellama_initial_generation(prompt, thread):
"""Job.submit inside of run_in_executor = more consistent bot behavior"""
global codellama_threadid_conversation
chat_history = f"{thread.id}.json"
conversation = []
with open(chat_history, "w") as json_file:
json.dump(conversation, json_file)
job = codellama_client.submit(prompt, chat_history, fn_index=0)
while job.done() is False:
pass
else:
result = job.outputs()[-1]
with open(result, "r") as json_file:
data = json.load(json_file)
response = data[-1][-1]
conversation.append((prompt, response))
with open(chat_history, "w") as json_file:
json.dump(conversation, json_file)
codellama_threadid_conversation[thread.id] = chat_history
if len(response) > 1300:
response = response[:1300] + "...\nTruncating response due to discord api limits."
return response
async def continue_codellama(message):
"""Continues a given conversation based on chat_history"""
try:
if not message.author.bot:
global codellama_threadid_userid_dictionary # tracks userid-thread existence
if message.channel.id in codellama_threadid_userid_dictionary: # is this a valid thread?
if codellama_threadid_userid_dictionary[message.channel.id] == message.author.id:
global codellama_threadid_conversation
prompt = message.content
chat_history = codellama_threadid_conversation[message.channel.id]
# Check to see if conversation is ongoing or ended (>15000 characters)
with open(chat_history, "r") as json_file:
conversation = json.load(json_file)
total_characters = 0
for item in conversation:
for string in item:
total_characters += len(string)
if total_characters < 15000:
job = codellama_client.submit(prompt, chat_history, fn_index=0)
while job.done() is False:
pass
else:
result = job.outputs()[-1]
with open(result, "r") as json_file:
data = json.load(json_file)
response = data[-1][-1]
with open(chat_history, "r") as json_file:
conversation = json.load(json_file)
conversation.append((prompt, response))
with open(chat_history, "w") as json_file:
json.dump(conversation, json_file)
codellama_threadid_conversation[message.channel.id] = chat_history
if len(response) > 1300:
response = response[:1300] + "...\nTruncating response due to discord api limits."
await message.reply(response)
total_characters = 0
for item in conversation:
for string in item:
total_characters += len(string)
if total_characters >= 15000:
await message.reply("Conversation ending due to length, feel free to start a new one!")
except Exception as e:
print(f"Error: {e}")
def run_bot():
if not DISCORD_TOKEN:
print("DISCORD_TOKEN NOT SET")
event.set()
else:
bot.run(DISCORD_TOKEN)
threading.Thread(target=run_bot).start()
event.wait()
welcome_message = """
## Add this bot to your server by clicking this link:
https://discord.com/api/oauth2/authorize?client_id=1152238037355474964&permissions=309237647360&scope=bot
## How to use it?
The bot can be triggered via `/codellama` followed by your text prompt.
This will generate text based on the text prompt and create a thread for the discussion.
To continue the conversation, simply ask additional questions in the thread - no need for repeating the command!
⚠️ Note ⚠️: Please make sure this bot's command does have the same name as another command in your server.
⚠️ Note ⚠️: Bot commands do not work in DMs with the bot as of now.
"""
with gr.Blocks() as demo:
gr.Markdown(f"""
# Discord bot of https://huggingface.co/spaces/codellama/codellama-13b-chat
{welcome_message}
""")
demo.launch()