---
# System prepended metadata

title: line聊天機器人
tags: [line bot]

---

如果已經會使用python跟OPENAI聊天了
可以套用到line上, 以生活化及簡單的方式跟OPENAI聊天
並且可以創造個人特色的AI機器人

這裡使用Nogrk建立一個暫時的公有網址, 連接到私有ip
再將Nogrk產生的網址存到line message api
這樣就可以實現用line和AI對話囉~

### 建立Line機器人的聊天帳號
首先, 到line developers註冊或登入
https://developers.line.biz/zh-hant/
![image](https://hackmd.io/_uploads/r1HCJFJ30.png)


如果有line可以直接選擇line帳號登入(一般都會有吧?)
![image](https://hackmd.io/_uploads/ByEckF1nA.png =50%x)

創建Provider
![image](https://hackmd.io/_uploads/SkpFltJnR.png)
輸入Provider name => Create

![image](https://hackmd.io/_uploads/S1XeVBx3C.png =60%x)

選擇創建"Message API", 並依內容填寫
![image](https://hackmd.io/_uploads/HJMYVSeh0.png)
![image](https://hackmd.io/_uploads/BylhPPtk30.png)
![image](https://hackmd.io/_uploads/B1Dl_tyh0.png)

創建完成Message API後, 在Basic setting頁面, 下方有個Your user ID需要記下來
![image](https://hackmd.io/_uploads/rJsT5Y1nR.png)

![image](https://hackmd.io/_uploads/B1rZtSJ6A.png)

然後再到Messaging API頁面, 掃描下面QRcode可以加入好友
![image](https://hackmd.io/_uploads/BkF5_qJ2C.png)


在Webhook URL點選Edit修改為openai發布的網址, 並點選開啟Use webhook
![image](https://hackmd.io/_uploads/BJJWyFW00.png)

再下方Channel access taken點選issue會出現一串字, 這個需要設定在openai的程式內, 可以點選旁的的小方框"複製"
![image](https://hackmd.io/_uploads/Sk4Xx9k3A.png)

接下來到line管理頁面, 停止系統自動回復功能
https://tw.linebiz.com/login/
![image](https://hackmd.io/_uploads/SkqfWrlhC.png)
選擇帳號
![image](https://hackmd.io/_uploads/SkOpZSl2R.png)
在左邊欄位選擇"自動回覆訊息", 在點選右邊內容的按鈕, 停止自動回覆
![image](https://hackmd.io/_uploads/BycKzBg30.png)
以上line部分就設置完成囉~

### 執行程式
第9~10行, auth_token和YouruserID為前面line messaging API的資訊, 複製後放在這裡
第21, 22行可以設AI角色, 有很多條件的話可以一直往後加, 或是寫在一起
※ 此聊天機器人沒有記錄訊息, 每次回應都是都是對當次的訊息回覆
```py=
import flask     
from flask import  request
import requests
from openai import OpenAI

app = flask.Flask(__name__)

# line環境變數
auth_token=*****
YouruserID=*****


# 初始化, 如果有設環境變數
client = OpenAI()

# 設定AI機器人
def aichat(msg):
    completion = client.chat.completions.create(
        model="gpt-4o-mini-2024-07-18",
        messages = [
        {"role": "system", "content": "請用繁體中文回答"},    
        {"role": "system", "content": "你是承太郎, 請用嚴厲的語氣, 性格叛逆，口頭禪是'Yare Yare Daze', 絕招是'歐拉歐拉歐拉~', 替身使者是白金之星},    
        {"role": "user", "content": msg}    # 設定使用者訊息
        ]
    )
    # 將AI回應的訊息指派給ai_msg
    ai_msg= completion.choices[0].message.content

    # 顯示AI訊息
    print(ai_msg)    
    
    return ai_msg


# 將AI回應的訊息傳到line
def LineText(replyToken,str1):
    global auth_token
    global YouruserID

    message = {
        "replyToken": replyToken,
        "messages": [
            {
                "type": "text",
                "text": str1,
            }
        ]
    }

    hed = {'Authorization': 'Bearer ' + auth_token}
    url = 'https://api.line.me/v2/bot/message/reply'
    response = requests.post(url, json=message, headers=hed)
    return ""


# 接收 Line 的 POST 請求，將輸入的訊息回傳給AI
@app.route("/", methods=[ 'POST'])
def LinePOST():
    data = request.json
    replyToken = data['events'][0]['replyToken']  # 代幣
    text = data['events'][0]['message']['text']  # 訊息內容
    
    # 呼叫聊天機器人的函式, 並將回傳的訊息存到變數ai_msg
    ai_msg = aichat(text)    

    LineText(replyToken, ai_msg)
    return ""

if __name__ == '__main__':
    app.run(port=8080)
```

### 儲存聊天紀錄
如果想要保存之前聊天紀錄, 可以建立一個全域變數的list, 這個list用來保存所有對話訊息。每次接收到新的訊息後，並使用.append將每次聊天的紀錄加到這個list中，然後將整個list發送給 OpenAI。

```py=
import flask     
from flask import request
import requests
from openai import OpenAI

app = flask.Flask(__name__)

# Line 環境變數
auth_token = '*****"
YouruserID = "*****"

# 初始化 OpenAI 客戶端
client = OpenAI()

# 初始化對話列表
conversation = [{"role": "system", "content": "請用繁體中文回答"},
                {"role": "system", "content": "你是承太郎, 請用嚴厲的語氣, 性格叛逆，口頭禪是'Yare Yare Daze', 絕招是'歐拉歐拉歐拉~', 替身使者是白金之星}]

def aichat(msg):
    global conversation

    # 將訊息添加到對話中
    conversation.append({"role": "user", "content": msg})

    # 發送請求給 OpenAI
    completion = client.chat.completions.create(
        model="gpt-4o-mini-2024-07-18",
        messages=conversation
    )

    # 將AI 的回應指派給ai_msg
    ai_msg = completion.choices[0].message.content

    # 將 AI 的回應添加到對話中
    conversation.append({"role": "assistant", "content": ai_msg})

    print(ai_msg)
    return ai_msg

# 將 AI 回應的訊息傳到 Line
def LineText(replyToken, str1):
    global auth_token
    global YouruserID

    message = {
        "replyToken": replyToken,
        "messages": [
            {
                "type": "text",
                "text": str1,
            }
        ]
    }

    hed = {'Authorization': 'Bearer ' + auth_token}
    url = 'https://api.line.me/v2/bot/message/reply'
    response = requests.post(url, json=message, headers=hed)
    return ""

# 接收 Line 的 POST 請求，將輸入的訊息回傳給 AI
@app.route("/", methods=['POST'])
def LinePOST():
    data = request.json

    replyToken = data['events'][0]['replyToken']  # 代幣
    text = data['events'][0]['message']['text']  # 訊息內容
    ai_msg = aichat(text)

    LineText(replyToken, ai_msg)
    return ""

if __name__ == '__main__':
    app.run(port=8080)
```

### 儲存不同使用者的聊天訊息
上面程式可以儲存聊天紀錄了, 但是如果將私有ip發布公有網址上, 讓其他人也可以使用你的line聊天機器人, 這樣會有個問題, 因為建立了全域變數的list可以儲存聊天紀錄, 其他人一起使用的話聊天紀錄會混合在一起, 這會導致AI在回應時參考到不相關的訊息，結果可能會令人困惑。

因此修改為, 建立一個全域變數字典可以儲存每個使用者的聊天訊息, 以user_id 為key，這樣可以確保每個使用者的對話都是獨立的。

另外, 避免儲存訊息的全域變數資料量過大, 加入判斷式, 若對話紀錄超過10筆，使用刪除最舊的兩筆
(一次傳送及回應訊息是兩筆資料, 且第0和第1是我設定AI的訊息, 所以刪除第2~3筆資料)


```py=
import flask     
from flask import request
import requests
from openai import OpenAI

app = flask.Flask(__name__)

# Line 環境變數,  "*****"替換為自己的
auth_token="*****"
YouruserID="*****"

# 初始化 OpenAI 客戶端
client = OpenAI()

# 儲存每個使用者的對話歷史
user_conversations = {}

def aichat(user_id, msg):
    global user_conversations

    # 確認使用者是否已有對話記錄，若無則初始化
    if user_id not in user_conversations:
        user_conversations[user_id] = [{"role": "system", "content": "請用繁體中文回答"}, 
                                      {"role": "system", "content": "你是承太郎, 請用嚴厲的語氣, 性格叛逆，口頭禪是'Yare Yare Daze', 絕招是'歐拉歐拉歐拉~', 替身使者是白金之星"}]

    # 將新的使用者訊息添加到對話中
    user_conversations[user_id].append({"role": "user", "content": msg})

    # 發送請求給 OpenAI
    completion = client.chat.completions.create(
        model="gpt-4o-mini-2024-07-18",
        messages=user_conversations[user_id]
    )

    # 獲取 AI 的回應
    ai_msg = completion.choices[0].message.content

    # 將 AI 的回應添加到對話中
    user_conversations[user_id].append({"role": "assistant", "content": ai_msg})

    # 若對話紀錄超過10筆，刪除最舊的兩筆
    if len(user_conversations[user_id]) > 10:
        del user_conversations[user_id][2:4]

    print(ai_msg)
    return ai_msg

# 將 AI 回應的訊息傳到 Line
def LineText(replyToken, str1):
    global auth_token
    global YouruserID

    message = {
        "replyToken": replyToken,
        "messages": [
            {
                "type": "text",
                "text": str1,
            }
        ]
    }

    hed = {'Authorization': 'Bearer ' + auth_token}
    url = 'https://api.line.me/v2/bot/message/reply'
    response = requests.post(url, json=message, headers=hed)
    return ""

# 接收 Line 的 POST 請求，將輸入的訊息回傳給 AI
@app.route("/", methods=['POST'])
def LinePOST():
    data = request.json

    replyToken = data['events'][0]['replyToken']  # 代幣
    text = data['events'][0]['message']['text']  # 訊息內容
    user_id = data['events'][0]['source']['userId']  # 使用者 ID
    ai_msg = aichat(user_id, text)
   
    LineText(replyToken, ai_msg)
    return ""

if __name__ == '__main__':
    app.run(port=8080)
```

### 來看看聊天結果
![螢幕擷取畫面 2024-09-12 004835](https://hackmd.io/_uploads/ryie9H16C.jpg)




