# Chapter10. 把 AI 帶到 Discord
:+1: 完整程式碼在 https://github.com/iamalex33329/chatgpt-develop-guide-zhtw
## 其他章節
[Chapter1. OpenAI API 入門](https://hackmd.io/@U3f2IzHERbymAst2-lDdjA/S1cNMYi6T)
[Chapter2. 使用 Python 呼叫 API](https://hackmd.io/@U3f2IzHERbymAst2-lDdjA/HyZBg5ia6)
[Chapter3. API 參數解析與錯誤處理](https://hackmd.io/@U3f2IzHERbymAst2-lDdjA/BJWNtsh6p)
[Chapter4. 打造自己的 ChatGPT](https://hackmd.io/@112356044/Hk81U96Tp)
[Chapter5. 突破時空限制 - 整合搜尋功能](https://hackmd.io/@112356044/HkbVM-ApT)
[Chapter6. 讓 AI 幫 AI - 自動串接流程](https://hackmd.io/@112356044/r1Ke-GR6T)
[Chapter7. 網頁版聊天程式與文字生圖 Image API](https://hackmd.io/@112356044/Hyf-AvgAT)
[Chapter8. 設計 LINE AI 聊天機器人](https://hackmd.io/@112356044/r1d6HsgAa)
[Chapter9. 自媒體業者必看!使用 AI 自動生成高品質字幕](https://hackmd.io/@112356044/rJ2T37V0T)
[Chapter11. AI 客製化投資理財應用實戰](https://hackmd.io/@112356044/HkUE0rER6)
[Chapter12. 用 LangChain 實作新書宣傳自動小編](https://hackmd.io/@112356044/SybvbdN0p)
## 目錄結構
[TOC]
## 建立第一個 Discord 機器人
### 前置作業
1. 註冊 Discord 帳號:進入[註冊頁面](https://discord.com/register),填寫個人資訊並完成驗證。
2. 建立伺服器:進入到[首頁](https://discord.com/channels/@me),點擊左側的**加號按鈕**來建立自己的伺服器。
### 建立 Discord 開發者應用程式
要建立開發者應用程式,才能開發 Discord 機器人
1. 輸入以下網址並登入 Discord 帳號::link: https://discord.com/developers/applications
2. 建立新的開發者應用:

3. 開始機器人權限(下滑並勾選這三個選項):

> 記得點選**儲存變更**按鈕
### 取得 TOKEN
點選左側菜單「BOT」,接著按下「Reset Token」按鈕,輸入完密碼會得到一串 TOKEN

### 將 Discord 機器人加入伺服器
加入機器人前需要建立 OAuth2 URL 的授權連結,來確定機器人進入伺服器可取得的權限。
點選左側菜單「OAuth2」,接著勾選以下選項,勾選完會得到一串 URL 連結



將網址複製下來,並開啟

回到伺服器會發現 BOT 已經加入到伺服器中了

## 建立回聲機器人
首先,先下載 `discord` 套件
``` python=
!pip install discord
import discord
import apikey
token = apikey.DISCORD_BOT_TOKEN
intents = discord.Intents.default() # 取得預設的 intent
intents.message_content = True # 啟用訊息內容
client = discord.Client(intents=intents)
@client.event
async def on_ready():
print(f'{client.user} is login!')
@client.event
async def on_message(message):
if message.author == client.user:
return
await message.channel.send(message.content)
client.run(token)
```

- 在 Discord 中,接收訊息、指令或是成員更新等等,稱之為「事件」,設定 intent 可以決定機器人該對哪些「事件」進行回覆。
- 使用 decorator 設定「當某事件發生時,程式該如何回應」
- 當接收到的訊息是機器人本人時**跳出函式**,避免陷入無窮迴圈
## 讓 Discord 機器人只處理指名給自己的訊息
若使用者越來越多時,每個人都呼叫機器人會讓版面變得很混亂,因此這邊多加一個設定:當 `@機器人` 時,才會進行回覆
``` python=
import discord
import apikey
import re
token = apikey.DISCORD_BOT_TOKEN
intents = discord.Intents.default() # 取得預設的 intent
intents.message_content = True # 啟用訊息內容
client = discord.Client(intents=intents)
# 標記使用者時在訊息中的格式為 <@username>
pattern_mention = re.compile(r'\s{0,1}<@\d+>\s')
@client.event
async def on_ready():
print(f'{client.user} is login!')
@client.event
async def on_message(message):
if message.author == client.user:
return
# 只處理 @機器人 的訊息
if client.user in message.mentions:
msg = re.sub(pattern_mention, '', message.content) # 移除訊息中指名的資訊
await message.channel.send(f'{message.author.mention} {msg}') # 回覆時指名原發言者
client.run(token)
```

## 加入 AI 的 Discord 機器人
``` python=
from googlesearch import search
import discord
import openai
import apikey
import re
openai.api_key = apikey.OPENAI_API_KEY
hist = []
backtrace = 2
def get_reply(messages):
try:
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo", messages=messages
)
reply = response["choices"][0]["message"]["content"]
except openai.OpenAIError as err:
reply = f"An {err.error.type} error occurred\n{err.error.message}"
return reply
def chat(sys_msg, user_msg, use_web):
web_res = []
if use_web:
content = "The following are established facts:\n"
for res in search(user_msg, advanced=True, num_results=5):
content += f"Title: {res.title}\nSummary: {res.description}\n\n"
content += "Please answer the following questions based on the above facts:\n"
web_res = [{"role": "user", "content": content}]
web_res.append({"role": "user", "content": user_msg})
while len(hist) >= 2 * backtrace:
hist.pop(0)
reply = get_reply(hist + web_res + [{"role": "system", "content": sys_msg}])
hist.append({"role": "user", "content": user_msg})
while len(hist) >= 2 * backtrace:
hist.pop(0)
hist.append({"role": "assistant", "content": reply})
if use_web:
reply = f"The following reply is based on internet information:\n\n{reply}"
return reply
prompt_for_check_web = """
{}
'''
{}
'''
If needed, please clearly reply with "Y"; if not, clearly reply with "N", do not add any extra words.
"""
def check_tool(prompt, msg):
reply = get_reply(
[{"role": "user", "content": prompt_for_check_web.format(prompt, msg)}]
)
print(reply)
return reply == "Y"
token = apikey.DISCORD_BOT_TOKEN
intents = discord.Intents.default()
intents.message_content = True
client = discord.Client(intents=intents)
pattern_mention = re.compile(r"\s{0,1}<@\d+>\s")
@client.event
async def on_ready():
print(f"{client.user} is logged in")
@client.event
async def on_message(message):
if message.author == client.user:
return
if not client.user in message.mentions:
return
msg = re.sub(pattern_mention, "", message.content)
draw_pict = check_tool(
"Confirm whether drawing a picture is required for the following:", msg
)
if draw_pict:
response = openai.Image.create(prompt=msg, n=1, size="1024x1024")
image_url = response["data"][0]["url"]
await message.channel.send(image_url)
return
use_web = check_tool(
"If I want to know the following, confirm if internet search is needed:", msg
)
reply_msg = chat("Assistant", msg, use_web)
await message.channel.send(f"{message.author.mention} {reply_msg}")
client.run(token)
```

1. 使用者發送訊息
2. AI 判斷訊息是否需要繪圖工具來完成
- if Y
- 呼叫繪圖工具並跳出函式
- else N
- AI 判斷訊息是否需要網路搜尋來完成
- if Y
- 搜尋網路資訊來回答
- if N
- AI 自行回答