<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged discord-bot</title>
<link>https://coderlegion.com/tag/discord-bot</link>
<description>Powered by Question2Answer</description>
<item>
<title>Build a Discord python assistant with plain Langchain</title>
<link>https://coderlegion.com/309/build-a-discord-python-assistant-with-plain-langchain</link>
<description>&lt;h2&gt;1. Introduction&lt;/h2&gt;
&lt;p&gt;Discord is one of the most widespread instant-messaging services, especially when it comes to developers: its structure and internal organization into servers and channels made it easy to use with large community and extremely popular all across the world.&lt;/p&gt;
&lt;p&gt;But Discord &lt;strong&gt;is more than just the blue-ish icon on your desktop&lt;/strong&gt;: it indeed comes with lots of integrations for developers, such as applications and bots. In today's tutorial, we will see how we can build an AI-powered bot, in pure and simple &lt;strong&gt;python&lt;/strong&gt;, with the help of &lt;strong&gt;Langchain&lt;/strong&gt;, a widespread and appreciated library to build scalable AI products through &lt;strong&gt;composability&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;2. Setup&lt;/h2&gt;
&lt;h3&gt;2a. Folder&lt;/h3&gt;
&lt;p&gt;For the setup, let's begin with structuring our base folder. To do so, I strongly suggest you navigate to my &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/AstraBert/coderlegion&quot;&gt;GitHub repository&lt;/a&gt; and either take a look to &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/AstraBert/coderlegion/tree/main/article5/&quot;&gt;article5&lt;/a&gt; directory or you &lt;strong&gt;clone it&lt;/strong&gt; with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git clone https://github.com/AstraBert/coderlegion.git
cd coderlegion/article5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here you will see something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.
├── .env.example
├── bot.py
├── inference.py
├── requirements.txt
└── utils.py
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let's take a look to what these file do: &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.env.example&lt;/code&gt; (make sure to rename it to &lt;code&gt;.env&lt;/code&gt;) is thd file where you safely store and secure private &lt;strong&gt;environmental variables&lt;/strong&gt;. &lt;/li&gt;
&lt;li&gt;&lt;code&gt;bot.py&lt;/code&gt; is the script which &lt;strong&gt;builds the bot and makes it run&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;inference.py&lt;/code&gt; contains the actual &lt;strong&gt;Langchain&lt;/strong&gt; structure to power the bot with &lt;strong&gt;AI&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;requirements.txt&lt;/code&gt; contains the &lt;strong&gt;necessary packages&lt;/strong&gt; to be installed&lt;/li&gt;
&lt;li&gt;&lt;code&gt;utils.py&lt;/code&gt;defines a class to &lt;strong&gt;search the vector database&lt;/strong&gt; we will build in the next steps (more about vector databases at &lt;a rel=&quot;nofollow&quot; href=&quot;https://astrabert.github.io/hophop-science/Vector-databases-explained/&quot;&gt;&lt;em&gt;Vector databases explained&lt;/em&gt;&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2b. Dependencies&lt;/h3&gt;
&lt;p&gt;You will have to install the needed dependencies, and the easiest way to do it is to copy &lt;code&gt;requirements.txt&lt;/code&gt; to your local folder and run:&lt;/p&gt;
&lt;p&gt;python3 -m pip install -r requirements.txt&lt;/p&gt;
&lt;p&gt;Let's see what packages we need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;transformers&lt;/strong&gt; and &lt;strong&gt;sentence-transformers&lt;/strong&gt; are used to tokenize and encode (which means represent as multi-dimensional numerical arrays) users' messages to query the vector database&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;langchain-related&lt;/strong&gt; packages are needed to build the AI architecture, interact with Cohere and give the bot some conversational memory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;discord.py&lt;/strong&gt; is the Discord python SDK&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;vecs&lt;/strong&gt; is the python integration for Supabase (that we already used in the last tutorial)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;pydotenv&lt;/strong&gt; is used to load environmental variables from the &lt;code&gt;.env&lt;/code&gt; file.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2c. Vector Database&lt;/h3&gt;
&lt;p&gt;We will build our vector database with the help of Supabase and with the Hugging Face dataset &lt;code&gt;dipesh/python-code-ds-mini&lt;/code&gt;, by Dipesh Paul, which encompasses &lt;strong&gt;2200 python code instances&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In order to do it, we will follow &lt;a rel=&quot;nofollow&quot; href=&quot;https://gist.github.com/AstraBert/455badcbf24fac2ff65115d12374d301&quot;&gt;this GitHub Gist&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In order to make the Gist code run properly, you just need to: &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://supabase.com/dashboard/sign-up&quot;&gt;Register to Supabase&lt;/a&gt; (you can quickly sign up with GitHub)&lt;/li&gt;
&lt;li&gt;Create your first project&lt;/li&gt;
&lt;li&gt;Navigate to &lt;code&gt;Project Settings&lt;/code&gt; and then &lt;code&gt;Database&lt;/code&gt;, where you should copy the &lt;code&gt;Connection string&lt;/code&gt;, making sure to replace the &lt;code&gt;postgres://&lt;/code&gt; heading with &lt;code&gt;postgresql://&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Open the Gist in Google Colab&lt;/li&gt;
&lt;li&gt;Copy the &lt;code&gt;Connection string&lt;/code&gt; into a Colab Secret (under the key sign) named &quot;TINY_CODES_DB&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now just run all the blocks in Colab and you'll have the &lt;strong&gt;vector database built in 10 minutes' time&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;Make sure also to save the &lt;code&gt;Connection string&lt;/code&gt; under &lt;code&gt;supabase_database&lt;/code&gt; variable in your &lt;code&gt;.env&lt;/code&gt; file!&lt;/p&gt;
&lt;h3&gt;2d. Discord Bot&lt;/h3&gt;
&lt;p&gt;Follow these simple steps to build the Discord bot container:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go to &lt;a rel=&quot;nofollow&quot; href=&quot;https://discord.com/&quot;&gt;Discord&lt;/a&gt; and create an account (or log into yours, if you already have one)&lt;/li&gt;
&lt;li&gt;Create a new server by clicking on &quot;Add a server&quot; (a big green &quot;+&quot; button) and name it as you want&lt;/li&gt;
&lt;li&gt;Go to &lt;a rel=&quot;nofollow&quot; href=&quot;https://discord.com/developers/applications&quot;&gt;Discord developers portal&lt;/a&gt; and click on &quot;New application&quot;&lt;/li&gt;
&lt;li&gt;Name your application, then save the changes and click on &quot;Bot&quot;, on the left&lt;/li&gt;
&lt;li&gt;There you will get the chance to name your bot and copy its token&lt;/li&gt;
&lt;li&gt;After that, go on &quot;OAuth2&quot; &amp;gt; &quot;URL generator&quot; and generate a URL that you will paste in your navigation bar, to add the bot to your newly created server.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now paste the bot token and your server's channel ID (the last numeric combination you see in the URL of your channel) to your &lt;code&gt;.env&lt;/code&gt; file, as &lt;code&gt;discord_token&lt;/code&gt; and &lt;code&gt;discord_channel&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The bot is created, but it is &lt;strong&gt;unresponsive&lt;/strong&gt;; this is because we only generated an external facade, with no backbone to sustain it: it's now time to fill it with life thanks some python code.&lt;/p&gt;
&lt;h3&gt;2e. Cohere API key&lt;/h3&gt;
&lt;p&gt;Getting a Cohere free API key is really simple: you need to register &lt;a rel=&quot;nofollow&quot; href=&quot;https://dashboard.cohere.com/welcome/register&quot;&gt;on their website&lt;/a&gt; (you can exploit signing up with GitHub also here) and then head over to the &lt;code&gt;API keys&lt;/code&gt; section, where you could generate a free key that has a 100 calls/min limit.&lt;/p&gt;
&lt;p&gt;Copy the key and save it to your &lt;code&gt;.env&lt;/code&gt; file, as &lt;code&gt;cohere_api_key&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;3. Build with Langchain&lt;/h2&gt;
&lt;p&gt;In this section, we're gonna modify &lt;strong&gt;inference.py&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;3a. Build the Cohere model&lt;/h3&gt;
&lt;p&gt;In order to connect with Cohere, you need to import the &lt;strong&gt;needed packages&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_cohere import ChatCohere
from dotenv import load_dotenv
import os
from langchain_community.chat_message_histories import SQLChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then we load the environmental variables, get Cohere API key and load the chat model:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;load_dotenv()
os.environ[&quot;COHERE_API_KEY&quot;]  = os.getenv(&quot;cohere_api_key&quot;) 
model = ChatCohere()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We now need to actually build it into some sort of conversational chain, so we first define a system template (variables in brackets will be passed as arguments to the following block, so they get re-defined at every call):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;system_template = &quot;You are an helpful coding assistant that can rely on this code: {context} and on the previous message history as context, and from that you build a context and history-aware reply to this (DO NOT mention the fact that you are starting from a code snippet):&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;div-green&quot;&gt;
&lt;span class=&quot;alert-header&quot;&gt;TIP:&lt;/span&gt;
&lt;span class=&quot;alert-body&quot;&gt; This portion is critical for getting the best out of the chat model: customize it to your needs!&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;And then a prompt template and the chain:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;prompt_template = ChatPromptTemplate.from_messages(
    [(&quot;system&quot;, system_template),
    MessagesPlaceholder(variable_name=&quot;history&quot;),
    (&quot;human&quot;, &quot;{input}&quot;)]
)
chain = prompt_template | model
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3b. Chat Memory&lt;/h3&gt;
&lt;p&gt;Chat memory is crucial for the bot to &lt;strong&gt;remember the previous messages&lt;/strong&gt; during a conversation, so we need to add it with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def get_session_history(session_id):
    return SQLChatMessageHistory(session_id, &quot;sqlite:///memory1.db&quot;)
runnable_with_history = RunnableWithMessageHistory(
    chain,
    get_session_history,
    input_messages_key=&quot;input&quot;,
    history_messages_key=&quot;history&quot;,
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;session_id&lt;/code&gt; is an alphanumeric code associated with each session of activity of the bot: each session is independent and there is &lt;strong&gt;no common knowledge across them&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;3c. Inference&lt;/h3&gt;
&lt;p&gt;Now that we have all set, we can define a inference function with which we query Cohere's model and we retrieve the answers:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def infer_reply(context, text, sessionid):
    global chain
    r = runnable_with_history.invoke(
        {&quot;context&quot;: context, &quot;input&quot;: text},
        config={&quot;configurable&quot;: {&quot;session_id&quot;: sessionid}}
    )
    return r.content
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4. Vector Database Search&lt;/h2&gt;
&lt;p&gt;To search the vector database, we define a &lt;strong&gt;NeuralSearcher&lt;/strong&gt; class inside &lt;strong&gt;utils.py&lt;/strong&gt;, which is the same as the one we used in last tutorial:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class NeuralSearcher:
    def __init__(self, collection, encoder):
        self.collection = collection
        self.encoder = encoder
    def search(self, text):
        results = self.collection.query(
            data=self.encoder.encode(text).tolist(), limit=1, filters={}, measure=&quot;cosine_distance&quot;, include_value=True, include_metadata=True,
        )
        return results
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5. Discord Bot&lt;/h2&gt;
&lt;p&gt;We have everything in place now, so we can actually import the needed packages in &lt;strong&gt;bot.py&lt;/strong&gt; and define some global variables and the Discord client:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from discord import Client, Intents
from utils import NeuralSearcher
import os
import vecs
from dotenv import load_dotenv
from sentence_transformers import SentenceTransformer
from inference import infer_reply
import time
import random as r

load_dotenv()
collection_name = &quot;documents&quot;
encoder = SentenceTransformer(&quot;all-MiniLM-L6-v2&quot;)
client = os.getenv(&quot;supabase_database&quot;)
vx = vecs.create_client(client)
docs = vx.get_or_create_collection(name=collection_name, dimension=384)
rand_sess_id = str(r.randint(1,100)) + r.choice([&quot;a&quot;, &quot;e&quot;, &quot;i&quot;, &quot;o&quot;, &quot;u&quot;])
CHANNEL_ID = int(os.getenv(&quot;discord_channel&quot;))
TOKEN = os.getenv(&quot;discord_token&quot;)
intents = Intents.default()
intents.messages = True
bot = Client(intents=intents)
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;div-blue&quot;&gt;
&lt;span class=&quot;alert-header&quot;&gt;NOTE:&lt;/span&gt;
&lt;span class=&quot;alert-body&quot;&gt; A unique session_id is set here at the beginning of the code, and will be re-set every time we start the bot&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;Now let's tell the bot what to do when it connects to our channel:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@bot.event
async def on_ready():
    channel = bot.get_channel(CHANNEL_ID)
    if channel:
        # Send the welcome message
        await channel.send(f&quot;Hi, I'm here to assist you!&quot;)
    else:
        print(&quot;Unable to find the specified channel ID. Make sure the ID is correct and the bot has the necessary permissions.&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;div-blue&quot;&gt;
&lt;span class=&quot;alert-header&quot;&gt;NOTE:&lt;/span&gt;
&lt;span class=&quot;alert-body&quot;&gt; The expression starting with '@' is known as a decorator&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;Last but not least, we define a function that produces the context for Cohere chat model (which discards contexts with less than 25% similarity with the query), a function to reply to the users' query and we make the bot run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def get_context(results):
    if results[0][1] &amp;gt; 0.25:
        return results[0][2][&quot;Content&quot;]
    else:
        return &quot;There is no specific context for this query&quot;

def reply(message):
    global docs
    global encoder
    txt2txt = NeuralSearcher(docs, encoder)
    results = txt2txt.search(message)
    print(results)
    context = get_context(results)
    response = infer_reply(context, message, rand_sess_id)
    return response

@bot.event
async def on_message(message):
    if message.author == bot.user:
        return  
    elif message.content:
        response = reply(message.content)
        await message.channel.send(
            response
        )
bot.run(TOKEN)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ok, everything is ready! We go to the terminal and launch the bot with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;python3 bot.py
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we wait for the connection to be established and for the welcome message by the bot.&lt;/p&gt;
&lt;h2&gt;6. Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial, we learnt how to build a &lt;strong&gt;free&lt;/strong&gt;, personal &lt;strong&gt;coding assistant&lt;/strong&gt; that is able to help you &lt;strong&gt;fix python snippets&lt;/strong&gt;, all accessible through a popular messaging platform like &lt;strong&gt;Discord&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The bot was built using &lt;strong&gt;plain Langchain&lt;/strong&gt; and some other not-too-difficult python code, so it is &lt;strong&gt;beginner friendly&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;This article &lt;strong&gt;concludes the series dedicated to python-backed bots&lt;/strong&gt;: hope you enjoyed it!&lt;/p&gt;
</description>
<category>Project Dev</category>
<guid isPermaLink="true">https://coderlegion.com/309/build-a-discord-python-assistant-with-plain-langchain</guid>
<pubDate>Sat, 01 Jun 2024 22:25:10 +0000</pubDate>
</item>
</channel>
</rss>