BACK
Featured image of post 用 Node.js 建立你的第一個 OpenAI LINE Bot 聊天機器人

用 Node.js 建立你的第一個 OpenAI LINE Bot 聊天機器人

最近 OpenAI 的 ChatGPT 非常的火紅,剛好這個 ChatGPT 是有提供 API 可以串接的,也非常適合整合到 Line Bot 上,所以這一篇我就來介紹如何使用 Node.js 基於 OpenAI 的 ChatGPT API 來建立一個 Line 聊天機器人吧!

參考網站
參考網站

最近 OpenAI 的 ChatGPT 非常的火紅,剛好這個 ChatGPT 是有提供 API 可以串接的,也非常適合整合到 Line Bot 上,所以這一篇我就來介紹如何使用 Node.js 基於 OpenAI 的 ChatGPT API 來建立一個 Line 聊天機器人吧!


申請 OpenAI API

首先,請你先進入 OpenAI 的網站註冊會員,這邊你可以選擇第三方服務帳號(如:Google、Microsoft)或是 Email 帳號註冊。

註冊完後,你就可以開始申請 API 了!

如果你本身有帳號的話,那就直接登入 OpenAI 吧。

登入後,你應該會看到這個畫面

接著找到你的頭像點它,找到「View API keys」。

找到後你會看到「API keys」的申請畫面,點一下下方的「Create New Secret key」,這樣你就拿到串接 OpenAI 的 key,請先把它記下來,後面會用到。

API key generated 是非常重要的,因此請不要隨意提供給他人,以免造成不必要的損失。

那麼我們申請這個是 API Key 要幹嘛呢?主要是稍後後面會串接 OpenAI 所提供的 API 來使用 ChatGPT,如果你還不知道什麼是 ChatGPT 的話,你可以試著玩一下 ChatGPT,簡單來講 ChatGPT 是一個非常聰明且厲害的聊天機器人,它可以做到的事情非常多,例如像是…

  • 請它規劃日本旅遊行程
  • 寫一篇行銷文案
  • 幫忙找出程式碼錯誤
  • 程式碼解題

…等等,非常多

因此我們申請這個 API Key 就是用來串接 ChatGPT 的!

OpenAI 本身有提供免費的額度,三個月 18 美金,除此之外,OpenAI 的計算方式會因你使用的 model 不同而有不同的計算方式,例如像是「Davinci」的計算方式是 $0.0200(美金) / 1K tokens,如果你想要了解更多的話,可以參考這邊

額外補充
什麼是 tokens?
tokens 是指你輸入的字數,例如:「我想要去日本旅遊」,這句話有 8 個字,因此 tokens 就是 8。


申請 Line Developer

接下來我們要來申請 Line Developer 帳號,你可以透過這個連結快速進入 Line Developer 網站,登入方式,基本上就是使用 LINE 帳號登入。

登入後,你可以透過這個連結,進入 LINE 的開發者後台。

接著,你會看到畫面上什麼都沒有,所以這邊你要點一下中間的「Create a new provider」,這個類似於一個公司帳號的概念,底下會有許多的專案,所以你可以把它想像成一個公司,而這個公司底下有許多的專案,例如:Line Bot、Line MUSIC 等等之類你的服務。

這邊的話,範例我們就叫做「Wayne’s OpenAI Bot」。

建立的過程是非常快的,因此當你點下「Create」 之後,你就可以馬上看到 Wayne’s OpenAI Bot 的畫面。

接著,點一下畫面上的 「Create a Messaging API channel」,因為我們要來申請一個聊天機器人,所以我們要使用「Messaging API」。

進入「Create a Messaging API channel」後,會有一些欄位要填寫:

  • Channel type:
    • 保持預設 Messages API。
  • Provider:
    • 保持預設 「Wayne’s OpenAI Bot」 即可。
  • Company or owner’s country or region:
    • 依據你的公司所在地選擇,這邊我選擇台灣。
  • Channel icon:
    • 你可以之後再上傳,所以這邊先不用管。
  • Channel name:
    • 這邊我們就叫「Wayne’s AI」吧。
  • Channel description:
    • 你可以簡單描述一下,這個聊天機器人的功能,例如:「用於串接 OpenAI 的偉恩 Line 機器人」。
  • Category:
    • 就選擇…「其他媒體」。
  • Subcategory:
    • 接著一樣選「媒體(其他)」。
  • Email address:
    • 這是當你的聊天機器人有問題時,信箱聯絡你的方式。
  • Privacy policy URL 與 Terms of use URL:
    • 這兩個就不用理它,因為我們目前用不到。。

最後再打勾兩個條管,你就可以點下「Create」建立你的聊天機器人了。

由於這個頁面圖片太大張了,所以就不額外截圖。

當你按下「Create」之後,它會出現一個視窗,主要是告知你一些資訊,所以你可以按下 OK 關閉它。

到目前為止,我們只是申請好了一個 Line Bot,接著要來取得一些資訊,首先在「Base settings」中找到以下資訊並複製起來。

  • Channel ID
  • Channel secret

接著切換到「Messaging API」,找到「Channel access token」。

接著按下 「issue」,你會取得一串很長的 Token,請複製起來,後面我們會使用到。

到目前為止,我們已經準備好了 Line Bot 的申請以及 OpenAI API 的申請,接下來就是準備進入撰寫程式碼的部分囉。


建立一個專案

建立專案方式我就不多述了,相信大家應該都很熟悉怎麼建立專案以及安裝 Node.js,而這邊我稍微會有一點特別,我會使用 pnpm 來建立,如果你真的完全沒想法,你可以參考我以下指令來建立一個專案,當然你也可以使用 npm 或是 yarn 來建立。

提示:以下指令適用於 Mac 系統,若為 Mac 建議額外 Google 一下指令。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 若尚未安裝pnpm,可使用此指令先進行安裝
# npm install -g pnpm

# 建立一個資料夾
mkdir line-bot

# 進入資料夾
cd line-bot

# 初始化專案
pnpm init

基本上到這邊就算是初始化好一個專案了,接著就是準備要來安裝 Line Bot 的套件了。

安裝相關套件

接下來我們要安裝 @line/bot-sdk 這個套件,請在專案終端機下輸入以下:

1
pnpm i @line/bot-sdk express dotenv

安裝好之後,你可以先在專案底下建立一個 app.js 的檔案,稍後我們就會開始撰寫 LINE Bot 的程式碼囉。

撰寫 LINE Bot

前面我們已經準備好了 app.js 檔案,接著就是要撰寫程式碼,不外乎前面就是引入 @line/bot-sdkexpressdotenv 這三個套件。

app.js
1
2
3
4
require('dotenv').config();

const express = require('express');
const line = require('@line/bot-sdk');

接著呢?其實 Line 官方有提供範例程式碼,因此我們是可以直接嘗試挪過來測試看看。

app.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
require('dotenv').config();

const line = require('@line/bot-sdk');
const express = require('express');

// create LINE SDK config from env variables
const config = {
  channelAccessToken: process.env.CHANNEL_ACCESS_TOKEN,
  channelSecret: process.env.CHANNEL_SECRET,
};

// create LINE SDK client
const client = new line.Client(config);

// create Express app
// about Express itself: https://expressjs.com/
const app = express();

// register a webhook handler with middleware
// about the middleware, please refer to doc
app.post('/callback', line.middleware(config), (req, res) => {
  Promise
    .all(req.body.events.map(handleEvent))
    .then((result) => res.json(result))
    .catch((err) => {
      console.error(err);
      res.status(500).end();
    });
});

// event handler
function handleEvent(event) {
  if (event.type !== 'message' || event.message.type !== 'text') {
    // ignore non-text-message event
    return Promise.resolve(null);
  }

  // create a echoing text message
  const echo = { type: 'text', text: event.message.text };

  // use reply API
  return client.replyMessage(event.replyToken, echo);
}

// listen on port
const port = process.env.PORT || 3000;
app.listen(port, () => {
  console.log(`listening on ${port}`);
});

記得在專案底下建立一個 .env 並填寫以下資訊跟 Key。

1
2
CHANNEL_ACCESS_TOKEN=
CHANNEL_SECRET=

理論上來講,你目前專案應該是已經可以輸入 node app.js 啟動了,所以你可以嘗試啟動看看,如果無法啟動的話,會建議你往前面的步驟再檢查一下。

部屬到 Render

到目前為止我們要先嘗試將專案部署到 Render 上面,否則我們並不清楚專案是否可以正常運作,因為在使用 Render 之前,我們需要先建立一個 Render 的帳號,如果你還沒有的話,可以先到這邊註冊一個帳號。

建立好後,會建議你將專案程式碼上傳到 GitHub 上,因為 Render 有提供 GitHub 的整合,這樣可以讓我們更方便的部署專案,而上傳到 GitHub 這流程就不再贅述了,因此我這邊假使你已經完成了將程式碼上傳到 GitHub 這個動作後,接著就是直接進入到 Render 後台

這邊請選擇 「Web Services」。

接著你可以在這個畫面上選擇專案,如果你發現你的畫面上一個專案都沒有的話,可以點一下旁邊的「Configure account」。

接著你可以在這邊選擇專案,懶一點的話你可以乾脆給它全部的權限,因為我們只是要部署一個簡單的專案,所以我就選擇我要的單一專案即可。

接下來畫面上應該就可以看到你的專案了,接著點選你要部署的專案。

在這邊點一下「Connect」。

這邊會要求你填一些欄位,我就不多說明了,我直接附上我的設定。

接著往下滾,就選擇 「Free」專案即可,然後再點一下下方的「Advanced」。

因為我們要在「Advanced」區塊填入環境變數

接著點一下「Add Environment Variable」,依照欄位填入。

最後其他設定可以不用管,直接點一下最後的「Create Web Service」。

預設 Render 會去偵測 Commit 紀錄,所以如果有新的 Commit,Render 會自動重新部署,如果你不想要這個功能的話,可以在「Advanced」區塊裡面,將「Auto Deploy」關閉。

那麼由於為了方便示範,因此我這邊預設會採用「Yes」。

接著你就可以看到你的專案正在部署了。

這個過程稍微會比較久一點,因為 Render 會將它打包成一個 Docker Image,然後再部署到它的伺服器上,所以這個過程會稍微比較久一點,但是不用擔心,因為它會自動幫你做這些事情,你只要等待它完成即可。

部署完畢的話,你可以在畫面看到他提示你專案已經運行起來並且開始部署。

而你的專案的網址,就會在這邊:

不出意外的話,應該是無法開啟的,因為我們只有做一個 post 的 API,那麼到這邊我們專案就正式部署出去了,基本上都不用理會它了。

這邊請記住網址,因為後面我們會在使用到。


加入 Line Bot 好友

接下來我們就要來實際測試一下,我們的 Line Bot 是否可以正常運作,而取得這個 LINE Bot 的 ID 方式就在 Developer Console 的「Messaging API」裡面。

加入好友後,你應該就會立刻看到好友歡迎的訊息通知。

接著你可以試著發送訊息給它,例如「Test」,但是你會發現它沒有辦法正常回應你。

因此接下來,我們要做一點調整,讓它可以正常回應你。

調整 Line Bot

這邊請你回到 Line Bot 的後台,點一下「Messaging API」,然後找到「Webhook settings」。

接著點一下「Edit」,然後將「Webhook URL」填入你的專案網址,例如 https://example.com/callback

callback 是因為我們 Express 專案的路由是 /callback,如果你的路由不是這個的話,請自行修改。

app.js

按下儲存後,你可以點一下「Verify」,來驗證你的網址是否正確以及專案是否正常,只要能看到「Success」就代表你的網址以及專案是正確的。

接著將下方的 「Use webhook」打開。

打開後,你再去試著發送訊息給你的 Line Bot,你就會發現它可以正常回應你了,而且是不論你打什麼,他都會回應你剛剛打的字。

恭喜你,截至為止,我們終於把 Line Bot 正式處理好了。

關掉預設回饋

接下來你可能會想要把那段該死的提示回饋:

1
2
3
4
感謝您的訊息!

很抱歉,本帳號無法個別回覆用戶的訊息。
敬請期待我們下次發送的內容喔(moon smile)

以及加入好友通知:

1
2
3
4
5
6
XXX您好!
我是Wayne\'s AI。
感謝您加入好友

此官方帳號將定期發放最新資訊給您
敬請期待

這兩個關掉,關掉方式很簡單,一樣回到 Line Bot 的後台,點一下「Messaging API」,然後找到「Auto-reply messages」。

你會跳到 LINE@ 管理介面,將「加入好友歡迎訊息」以及「自動回覆訊息」關掉就搞定囉!


串接 OpenAI API

終於到了我們的重頭戲了,前面你可以發現 LINE Bot 的流程與申請非常的多且繁瑣,因此前面花很多時間在介紹,主要是希望你可以順利建立好你的 LINE Bot,確保你接下來的步驟不會有問題。

安裝 OpenAI 套件

首先我們要先安裝 OpenAI 的套件,請在專案底下輸入以下指令:

1
pnpm i openai

接著 openai 本身有提供範例程式碼:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
const { Configuration, OpenAIApi } = require("openai");

const configuration = new Configuration({
  apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);

const completion = await openai.createCompletion({
  model: "text-davinci-002",
  prompt: "Hello world",
});
console.log(completion.data.choices[0].text);

因此基於上方這一段,我們稍候可以來修改一下,讓它可以跟我們的 LINE Bot 串接。

openAI 有提供多個 model 可以選擇,分別是:

  • text-davinci-003
  • text-curie-001
  • text-babbage-001
  • text-ada-001

其中目前(2022年)最紅的就是 text-davinci-003,因此我們這邊也會使用這個 model,每一個 model 都有不同的特性,你可以在這裡找到它的介紹。

調整 app.js 的程式碼

首先我們要先在 app.js 中引入 OpenAI 的套件。

app.js
1
const { Configuration, OpenAIApi } = require("openai");

接下來我們要來實例化 OpenAI

app.js
1
2
3
4
const configuration = new Configuration({
  apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);

apiKey 就是我們最早前面所申請的 OpenAI API Key,而這一段一樣是放在 .env 的。

如果你沒申請的話你會無法往下繼續的,請務必申請 OpenAI API Key 唷。

目前來講,你的 .env 應該長這樣:

1
2
3
4
CHANNEL_ACCESS_TOKEN=
CHANNEL_SECRET=

OPENAI_API_KEY=

接下來呢?我們就要將原本 Line 官方所提供的範例程式碼稍微調整一下,主要調整的範圍是 handleEvent 的程式碼:

app.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
async function handleEvent(event) {
  if (event.type !== 'message' || event.message.type !== 'text') {
    // ignore non-text-message event
    return Promise.resolve(null);
  }

  const completion = await openai.createCompletion({
    model: "text-davinci-003",
    prompt: event.message.text ,
  });

  // create a echoing text message
  const echo = { type: 'text', text: completion.data.choices[0].text };

  // use reply API
  return client.replyMessage(event.replyToken, echo);
}

這邊我們將原本的 prompt 改成 event.message.text,也就是使用者輸入的訊息,而 completion.data.choices[0].text 就是 OpenAI 所回傳的訊息。

沒問題後就儲存檔案,並 commit push 出去到 GitHub 上,屆時 Render 就會自動幫你重新部署了。

記得要去 Render 上面增加 OPENAI_API_KEY 的環境變數,否則會出現錯誤唷。

當部署完畢後,你再去試著跟你的 LINE Bot 聊天,你會發現它已經會講話囉!

只是你會發現它好像沒辦法回你很多話,這原因是我們沒有告知它要使用多少 Tokens,因此這邊我們調整一下:

app.js
1
2
3
4
5
const completion = await openai.createCompletion({
  model: "text-davinci-003",
  prompt: event.message.text,
  max_tokens: 200,
});

這個 max_tokens 會影響到 OpenAI 所回傳的訊息長度,因此我們這邊設定為200,這樣就可以讓它回很多話了。

調整 OpenAI 的回傳訊息

那麼這邊也有一件很有趣的事情,也就是 OpenAI 的訊息都有一大推空白,這是因為 OpenAI 會將你的訊息分成一個個的段落,而每個段落之間都會有一個空白,因此我們也要來調整一下。

app.js
1
2
3
4
5
6
7
const completion = await openai.createCompletion({
  model: "text-davinci-003",
  prompt: event.message.text ,
  max_tokens: 200,
});

const echo = { type: 'text', text: completion.data.choices[0].text.trim() };

再重新上傳程式碼後,你就可以看到機器人正常的回你了。

恭喜你,完成了一個可以跟你聊天的機器人!而且是串接了 OpenAI 的機器人!


結語

相信你應該發現這個 Line Bot 的建立流程超級無敵的長,而且非常的多流程跟細節,但是你也可以因此認識到如何串接第三方服務,以及如何將你的程式碼部署到 Render 上面,所以我覺得是一個相當不錯的小練習,所以如果你想嘗試做一個聊天機器人,是可以考慮使用這個方法的。

但是要注意一件事情 OpenAIGPT 有一個重點使用,如果你要讓你聰明一點的回覆你,那麼你就要將它的上下文(包含你的回覆)一起撈出來丟給它,否則你會發現它有點笨,可是 LINE 的聊天機器人不太適合這種方式,因為過程你可能會問很多事情,這樣子訊息量會非常龐大且沒辦法刪除,因此這邊我們就不做這件事情了,而是讓它針對你每個問題去回覆即可,而不包含前一個問題的回覆。

最後這邊我也附上範例程式碼,如果你想直接拉回去用也是可以的,因為這一份程式碼基本上都是以官方所提供的為主,很少有大幅度調整的部分,所以你可以直接拿來用。

希望這一篇可以讓你快快樂樂做出一個 LINE Bot。

如果你覺得部署到 Render 很難去除錯,其實是可以考慮使用 ngrok 的,ngrok 的使用方法可以參考這裡


comments powered by Disqus