---
# System prepended metadata

title: Chapter4. 打造自己的 ChatGPT
tags: [ChatGPT 開發手冊]

---

# Chapter4. 打造自己的 ChatGPT

:+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)

[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)

[Chapter10. 把 AI 帶到 Discord](https://hackmd.io/@112356044/Sy_L-B40T)

[Chapter11. AI 客製化投資理財應用實戰](https://hackmd.io/@112356044/HkUE0rER6)

[Chapter12. 用 LangChain 實作新書宣傳自動小編](https://hackmd.io/@112356044/SybvbdN0p)

## 目錄結構

[TOC]

## 文字模式簡易聊天程式

先把與 openai 傳送訊息的部分獨立成 `get_reply()` 函式

``` python=
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'Error Type: {err.error.type}\nError msg: {err.error.message}'

    return reply
```

接下來寫一個無窮迴圈，讓使用者能夠持續輸入文字，達到聊天的效果

``` python=+
while True:
    user_msg = input('=> ')
    if not user_msg.strip(): break
    user_messages = [{'role': 'user', 'content': user_msg}]
    ai_msg = get_reply(user_messages)
    print(f'=> {ai_msg}\n')
```

但這裡**有個問題**，openai 並不能延續先前的對話脈絡（因為每次對話都是呼叫新的）

## 加入聊天記錄維持聊天脈絡

我們可以定義兩個變數：`hist=[]` 和 `backtrace`，來記錄**歷史對話**以及最多**回朔到前幾次對話**

``` python=
import openai
import apikey

openai.api_key = apikey.OPENAI_API_KEY

hist = []       # 歷史對話紀錄
backtrace = 3   # 記錄幾組對話


def chat(sys_msg, user_msg):
    hist.append({"role": "user", "content": user_msg})
    reply = get_reply(hist + [{"role": "system", "content": sys_msg}])

    while len(hist) >= 2 * backtrace:
        hist.pop(0)

    hist.append({"role": "assistant", "content": reply})
    return reply


def get_reply(messages):
    try:
        response = openai.ChatCompletion.create(
            model='gpt-3.5-turbo',
            messages=messages,
            temperature=1.5,

        )
        reply = response['choices'][0]['message']['content']

    except openai.OpenAIError as err:
        reply = f'Error Type: {err.error.type}\nError msg: {err.error.message}'

    return reply


if __name__ == '__main__':
    sys_msg = input("AI Role: ")
    if not sys_msg.strip(): sys_msg = 'Assistant'
    print()

    while True:
        msg = input('=> ')
        if not msg.strip(): break
        ai_reply = chat(sys_msg, msg)
        print(f'=> {ai_reply}\n')

    hist = []

```

## 串流版本的聊天程式

前一章介紹過，若使用串流方式，會以 generator 的方式傳回，因此這邊示範如何用串流方式進行對話。

``` python=
import openai
import apikey

openai.api_key = apikey.OPENAI_API_KEY


hist = []       # 歷史對話紀錄
backtrace = 5   # 記錄幾組對話


def chat_stream(sys_msg, user_msg):
    hist.append({"role": "user", "content": user_msg})
    reply_full = ""

    for reply in get_reply_stream(
        hist + [{"role": "system", "content": sys_msg}]):
        reply_full += reply
        yield reply

    while len(hist) >= 2 * backtrace:
        hist.pop(0)

    hist.append({"role": "assistant", "content": reply_full})


def get_reply_stream(messages):
    try:
        response = openai.ChatCompletion.create(
            model="gpt-3.5-turbo",
            messages=messages,
            stream=True
        )
        for chunk in response:
            if 'content' in chunk['choices'][0]['delta']:
                yield chunk["choices"][0]["delta"]["content"]
    except openai.OpenAIError as err:
        reply = f'Error Type: {err.error.type}\nError msg: {err.error.message}'


if __name__ == '__main__':
    sys_msg = input("AI Role: ")
    if not sys_msg.strip(): sys_msg = 'Assistant'
    print()

    while True:
        msg = input('=> ')
        if not msg.strip(): break
        for reply in chat_stream(sys_msg, msg):
            print(f'{reply}', end='')

        print('\n')

```