# Chapter2. 使用 Python 呼叫 API
:+1: 完整程式碼在 https://github.com/iamalex33329/chatgpt-develop-guide-zhtw
## 其他章節
[Chapter1. OpenAI API 入門](https://hackmd.io/@U3f2IzHERbymAst2-lDdjA/S1cNMYi6T)
[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)
[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 套件
### 安裝與使用 openai 套件
``` python=
!pip install openai
import openai
openai.api_key = "XXXXXXXXXXX"
```
#### openai 套件有三種設定金鑰的方法:
1. 透過套件本身的 `openai.api_key` 來設定
2. 將金鑰儲存在某個檔案,並透過 `openai.api_key_path` 指定路徑
3. 若不使用上述兩個設定方式,預設會自動尋找 `OPENAI_API_KEY` 的**環境變數**
#### 接著透過 `openai.ChatCompletion.create()` 連線使用 API,這個函式有兩個必要參數
1. model: 指定採用的模型,這裡使用穩定的 gpt-3.5-turbo
2. messages: 這是訊息串,每個元素都是 **dict**,`role` 是發言角色(**user**, **assistant**, **system** 其中之一);`content` 是訊息內容
``` python=
import openai
openai.api_key = "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"
reply = openai.ChatCompletion.create(
model='gpt-3.5-turbo',
messages=[
{'role': 'user', 'content': 'how are you'}
]
)
print(reply)
```
這時會傳回一個 OpenAIObject 類別的物件,可以直接以 `dict` 來操作
``` json=
{
"id": "chatcmpl-91JjP1r7ol57AMszxbDTlkrCqNlz9",
"object": "chat.completion",
"created": 1710101203,
// 實際使用的模型
"model": "gpt-3.5-turbo-0125",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
// API 回覆的訊息內容
"content": "I'm just a computer program, so I don't have feelings or emotions, but I'm here to help you with any questions or tasks you have. How can I assist you today?"
},
"logprobs": null,
// 訊息終止的原因
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 10,
"completion_tokens": 38,
// 本次 API 的 token 用量
"total_tokens": 48
},
"system_fingerprint": "fp_4f0b692a78"
}
```
- model: 本次使用 API 的模型
- usage: 本次 API 的用量
| 項目 | 說明 |
| -------- | -------- |
| prompt_tokens | 傳送 API 訊息的 token 數量 |
| completion_tokens | API 回覆訊息的 token 數量 |
| total_tokens | prompt_tokens + completion_tokens |
- choices: 是 list type,代表 API 回覆的訊息
- finish_reason: 表示該回覆訊息是否完整,有兩種可能
- stop: 正常結束,回覆內容為完整語句
- length: 因長度限制,回覆內容並不完整
[查詢 OpenAI 各個模型價格 ::: Pricing](https://openai.com/pricing)
### 傳送多筆訊息
``` python=
reply = openai.ChatCompletion.create(
model='gpt-3.5-turbo',
messages=[
{'role': 'system', 'content': 'Your name is Alex.'},
{'role': 'user', 'content': 'how are you, what\'s your name?'}
]
)
```
我們可以發現,API 確實有按照 `system` 暗示,名稱變成 Alex
## 認識 token
> OpenAI API 的計價單位就是 **token**,不論是傳送給 API 的文字,或是回傳的內容都是以 token 為單位
### 使用 tokenizer 頁面檢視 token
[OpenAI Platform ::: Tokenizer](https://platform.openai.com/tokenizer)

- 每個字段都有其 Token ID,而中文字的 token 會比英文還來得多!
- 大略的計算方式為:length of words = total_token * 0.75
### 使用 tokenizer 套件計算精確 token 數
取得模型的編碼器名稱
``` python=
!pip install tiktoken
import tiktoken
encoder = tiktoken.encoding_for_model('gpt-3.5-turbo')
print(encoder.name)
encoder = tiktoken.encoding_for_model('gpt-4')
print(encoder.name)
```
利用 `encode()` 轉為 token,可以看到是一樣的
``` python=
tokens = encoder.encode('how are you')
print('tokens: ' + str(tokens))
print('length of token: ' + str(len(tokens)))
print('decode tokens: ' + encoder.decode(tokens))
# tokens: [5269, 527, 499, 30]
# length of token: 4
# decode tokens: how are you?
```

### ChatML 標記語言
以前面示範的 `how are you` 為例,透過查詢 token 數量可以發現僅有 3 個單位,但 API 所傳回的 token 卻有 10 個單位,是什麼造成的?
``` json=
"prompt_tokens": 10
```
實際上在傳送字串時,模型會轉換成 Chat Markup Language(ChatML)的格式,會轉換成以下格式:
``` =
<|im_start|>角色\n訊息內容<|im_end|>
```
`<|im_start|>` 與 `<|im_end|>` 都是特殊的 token,代表單一訊息的開頭/結尾。`"\n"` 以及各個角色都會被轉換成 1 個 token。
因此上述例子會轉換成:
```
{'role': 'user', 'content': 'how are you'}
```
```
<|im_start|>user\nhow are you<|im_end|>
```
最後還會加上結尾,表示接下來交給 AI 回覆
```
<|start|>assistant\n
```
也就是說,每一則訊息除了本身內容轉換的 token 之外,還會加上 4 個(2 個特殊 token、1 個換行符號、1 個角色)token,以及 3 個 token 的結尾訊息。
3 (how are you) + 4 (2 + 1 + 1) + 3 = 10
## 使用 Python requests 模組呼叫 API
OpenAI API 是走 http protocol,因此也不一定要透過 openai 模組才能使用,甚至只要簡單的 command line,就可以取用 OpenAI 的 API。
### OpenAI API 的 HTTP 規格
OpenAI Chat API 主要透過 HTTP POST 方法提供服務,API 存取網址為
:link: https://api.openai.com/v1/chat/completions
使用時必須在 header 加上以下兩項資料
| 表頭 | 內容 | 說明 |
| -------- | -------- | -------- |
| Content-Type | application/json | 表實際傳輸的內容(JSON) |
| Authorization | Bearer 金鑰 | 金鑰來提供 API 認證 |
### 使用 Python requests 模組
在 Python 中透過 http 協定傳輸資料,最簡單的方式就是用 `requests` 套件
``` python=
!pip install requests
import requests
import apikey
openai_api_url = 'https://api.openai.com/v1/chat/completions'
response = requests.post(
openai_api_url,
headers={
'Content-Type': 'application/json',
'Authorization': f'Bearer {apikey.OPENAI_API_KEY}'
},
json={
'model': 'gpt-3.5-turbo',
'messages': [
{'role': 'user', 'content': 'how are you'}
]
}
)
reply = response.json()
print(reply['choices'][0]['message']['content'])
```
> 通常在一些無法下載 openai 套件的環境,或是沒有足夠空間安裝的嵌入式系統,會直接透過 HTTP POST 來呼叫。
### 利用 curl 工具快速測試 API
``` bash=
curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_OPENAI_API_KEY" \
-d '{
"model": "gpt-3.5-turbo",
"messages": [
{"role": "user", "content": "how are you"}
]
}' \
https://api.openai.com/v1/chat/completions
```
