五月初做完 Function Calling 測試後便暫停去學習 Streamlit, 今天終於可以回頭來玩 OpenAI API 了. 本篇旨在測試 OpenAI 的 Image API.
本系列全部測試筆記參考 :
OpenAI 的圖像生成模型稱為 DALLE, 名稱源自畫家達利 (Salvador Dalí) 與皮克斯動畫角色瓦力 ( WALL·E), 係基於 GPT-3 發展而成的深度學習模型, 可以根據自然語言提示生成圖像, 使用者只需輸入描述圖像的提示詞 (prompt) 即可生成圖片, 版本演進如下表 :
| 版本 | 發表時間 | 特色與重點 |
|---|---|---|
| DALL·E 1 | 2021 | 初代模型,基於 GPT 架構,展示文字生圖能力 |
| DALL·E 2 | 2022 | 畫質更高,可進行影像修改與風格變換,支援 inpainting |
| DALL·E 3 | 2023/10 | 與 ChatGPT 緊密整合理解力大幅提升,可生成細膩細節之圖像 |
目前可用的是 DALLE 2 與 DALLE 3 模型.
DALLE 生成的圖片尺寸是固定的, 且只能生成 PNG 圖檔 :
| 模型版本 | 可用尺寸 | 說明 |
|---|---|---|
| DALL·E 2 | 256×256 512×512 1024×1024 |
僅支援正方形尺寸,解析度較低,生成速度快。 |
| DALL·E 3 | 1024×1024 1024×1792(直式) 1792×1024(橫式) |
支援橫式與直式圖像,適合更複雜的構圖與應用。 |
DALLE 2 與 DALLE 3 價格如下表 :
| 模型版本 | 圖片尺寸 | 畫質等級 | 價格(每張圖) |
|---|---|---|---|
| DALL·E 2 | 256×256 | Standard | $0.016 |
| 512×512 | Standard | $0.018 | |
| 1024×1024 | Standard | $0.020 | |
| DALL·E 3 | 1024×1024 | Standard | $0.040 |
| 1024×1792 | Standard | $0.080 | |
| 1792×1024 | HD | $0.120 |
雖然 DALLE 3 價格較貴, 但生圖效果較好.
不過 DALLE 只是生圖的模型 (相當於畫家), 用它來生圖必須透過 OpenAI Image API (相當於畫家的助理), 生圖程序可以比喻為, 我們先將圖像的描述 (提示詞) 交給畫家的助理, 然後助理再轉交給畫家去畫圖.
OpenAI 的 Image API 具體而言就是 OpenAI 物件的 images 子物件的 generate() 方法, 其參數結構如下 :
reply=client.images.generate(prompt, model="dall-e-3", n=1, quality="standard", size="1024x1024", style="vivid", response_format="url", user=None)
可見它只有一個必要參數 prompt, 其餘都是有欲設值的關鍵字參數, 預設使用 DALLE 3 生成 1024x1024 尺寸鮮明風格的圖像.
參數說明如下 :
| generate() 參數 | 說明 |
|---|---|
| prompt | 圖像的提示詞 (必要參數),最高 1K (DALLE 2) 或 4K 字元 (DALLE 3)。 |
| model | 指定使用的模型,如 "dall-e-3"(預設)或 "dall-e-2"。 |
| n | 要產生的圖像數量 (1~10),預設 1。對 dall-e-3 只能設為 1。 |
| quality | 圖像品質,可為 "standard" (標準, 預設) 或 "hd"(高畫質)。 |
| size | dall-e-3 圖像尺寸 : "1024x1024" (預設)、"1024x1792"、"1792x1024"。 |
| style | 風格類型 : "vivid"(鮮明,預設)或 "natural"(自然),僅 dall-e-3 支援。 |
| response_format | 回傳格式,可為 "url"(預設)或 "b64_json"(base64 編碼)。 |
| user | 用戶識別字串,有助於使用者追蹤與濫用偵測。 |
注意, 在 OpenAI Python SDK v1.x 之後的所有物件方法都被設計成只接受關鍵字引數, 因此呼叫generate() 時第一個參數必須傳入 prompt 關鍵字, 不可直接傳入提示詞本身 (prompt 不是位置參數). 其次, 由於 DALLE 以 GPT 為基礎, 故提示詞可接受中文.
呼叫 OpenAI API 需要 API Key, 我已將其儲存在環境變數檔案 .env 裡面, 先用 dotenv 套件讀取出來 :
>>> from dotenv import dotenv_values
config=dotenv_values('.env')
openai_api_key=config.get('OPENAI_API')
用 Image API 來生圖首先要匯入 openai.OpenAI 類別 :
>>> from openai import OpenAI
然後呼叫 OpenAI() 建構式並傳入 API Key 來建立 OpenAI 物件 :
>>> client=OpenAI(api_key=openai_api_key)
接著呼叫 client.images.generate() 並傳入提示詞即可 :
>>> reply=client.images.generate(prompt='兩隻可愛的貓咪')
傳回值是一個 ImagesResponse 物件 :
>>> type(reply)
<class 'openai.types.images_response.ImagesResponse'>
可以用 rich.print() 函式來檢視物件內容, 關於 rich 套件用法參考 :
>>> from rich import print as pprint
>>> pprint(reply)
ImagesResponse(
created=1750782201,
data=[
Image(
b64_json=None,
revised_prompt=None,
url='https://oaidalleapiprodscus.blob.core.windows.net/private/org-
AfvkWFxjqqTuopkcXEpNP4zc/user-elj0Uq9QlNHVCP9wMr4EHPiE/img-x2YUhdIf0OxNKLRtq14D
fURw.png?st=2025-06-24T15%3A23%3A21Z&se=2025-06-24T17%3A23%3A21Z&sp=r&sv=2024-0
8-04&sr=b&rscd=inline&rsct=image/png&skoid=475fd488-6c59-44a5-9aa9-31c4db451bea
&sktid=a48cca56-e6da-484e-a814-9c849652bcb3&skt=2025-06-24T13%3A18%3A36Z&ske=20
25-06-25T13%3A18%3A36Z&sks=b&skv=2024-08-04&sig=q5Zz4IONpcZk8Im493Pz5rr%2BNOacY
AG6fdS6F9CKGYw%3D'
)
],
usage=None
)
生成的圖片放在此物件的 data 屬性中, 其值為 Image 物件之串列, 圖片的 URL 放在其 url 屬性中 :
>>> reply.data[0].url
'https://oaidalleapiprodscus.blob.core.windows.net/private/org-AfvkWFxjqqTuopkcXEpNP4zc/user-elj0Uq9QlNHVCP9wMr4EHPiE/img-x2YUhdIf0OxNKLRtq14DfURw.png?st=2025-06-24T15%3A23%3A21Z&se=2025-06-24T17%3A23%3A21Z&sp=r&sv=2024-08-04&sr=b&rscd=inline&rsct=image/png&skoid=475fd488-6c59-44a5-9aa9-31c4db451bea&sktid=a48cca56-e6da-484e-a814-9c849652bcb3&skt=2025-06-24T13%3A18%3A36Z&ske=2025-06-25T13%3A18%3A36Z&sks=b&skv=2024-08-04&sig=q5Zz4IONpcZk8Im493Pz5rr%2BNOacYAG6fdS6F9CKGYw%3D'
將此 URL 複製貼到瀏覽器網址列即可看到所生成的 PNG 圖像 :
這與提示詞 '兩隻可愛的貓咪' 有落差啊! 要兩隻卻只給一隻, 而且面相看來並不可愛呵呵.
也可以用 PIL 來顯示此圖片 :
>>> import requests
from PIL import Image
from io import BytesIO
用 requests 下載圖像資料後轉成 ByteIO 物件再用 PIL.Image() 開啟 :
>>> img_data=requests.get(reply.data[0].url).content
>>> image=Image.open(BytesIO(img_data))
>>> image.show()
結果如下 :
注意, 圖像的網址是臨時的, 有效期限大約是一小時, 超過時限會出現錯誤訊息 :
<Error>
<Code>AuthenticationFailed</Code>
<Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:803b2a51-b01e-00b4-405a-e573e3000000 Time:2025-06-24T22:49:16.6768107Z</Message>
<AuthenticationErrorDetail>Signature not valid in the specified time frame: Start [Tue, 24 Jun 2025 15:23:21 GMT] - Expiry [Tue, 24 Jun 2025 17:23:21 GMT] - Current [Tue, 24 Jun 2025 22:49:16 GMT]</AuthenticationErrorDetail>
</Error>
這時檢查儲值餘額還剩下 9.61 美元, 用掉了 0.02 美元 (生圖前是 9.63 美元), 約 0.6 元台幣, 似乎比上面價格表的 0.04 美元少一半 (降價?), 但生圖比起文字回應要貴多了 :
如果使用 DALLE 2 模型可以用 n 參數指定生成幾張圖片 (至多 10 張), 例如 :
>>> prompt='兩隻可愛的貓咪'
>>> replies=client.images.generate(prompt=prompt, model='dall-e-2', n=2)
>>> pprint(replies)
ImagesResponse(
created=1750822980,
data=[
Image(
b64_json=None,
revised_prompt=None,
url='https://oaidalleapiprodscus.blob.core.windows.net/private/org-
AfvkWFxjqqTuopkcXEpNP4zc/user-elj0Uq9QlNHVCP9wMr4EHPiE/img-7Z9RQVJ4cjrE4f6U04sY
v1Hq.png?st=2025-06-25T02%3A43%3A00Z&se=2025-06-25T04%3A43%3A00Z&sp=r&sv=2024-0
8-04&sr=b&rscd=inline&rsct=image/png&skoid=475fd488-6c59-44a5-9aa9-31c4db451bea
&sktid=a48cca56-e6da-484e-a814-9c849652bcb3&skt=2025-06-24T19%3A41%3A07Z&ske=20
25-06-25T19%3A41%3A07Z&sks=b&skv=2024-08-04&sig=MAxypb1ouM%2BIPTGr/8Fhq8OT5uFgV
inWZOJmd%2BWfrpo%3D'
),
Image(
b64_json=None,
revised_prompt=None,
url='https://oaidalleapiprodscus.blob.core.windows.net/private/org-
AfvkWFxjqqTuopkcXEpNP4zc/user-elj0Uq9QlNHVCP9wMr4EHPiE/img-h3KdAGmq7lI6LDricCCw
Xhdu.png?st=2025-06-25T02%3A43%3A00Z&se=2025-06-25T04%3A43%3A00Z&sp=r&sv=2024-0
8-04&sr=b&rscd=inline&rsct=image/png&skoid=475fd488-6c59-44a5-9aa9-31c4db451bea
&sktid=a48cca56-e6da-484e-a814-9c849652bcb3&skt=2025-06-24T19%3A41%3A07Z&ske=20
25-06-25T19%3A41%3A07Z&sks=b&skv=2024-08-04&sig=1UM/daA1vxsuaIPEZahy6HOg%2B5pPv
RpNaQq/L8Ov8No%3D'
)
],
usage=None
)
此例用 n=2 指定生成兩張圖像, 可見 data 串列這時包含兩個 Image 物件, 可以用串列生成式取出這兩張圖片的網址 :
>>> urls=[item.url for item in replies.data]
>>> len(urls)
2
>>> urls
['https://oaidalleapiprodscus.blob.core.windows.net/private/org-AfvkWFxjqqTuopkcXEpNP4zc/user-elj0Uq9QlNHVCP9wMr4EHPiE/img-7Z9RQVJ4cjrE4f6U04sYv1Hq.png?st=2025-06-25T02%3A43%3A00Z&se=2025-06-25T04%3A43%3A00Z&sp=r&sv=2024-08-04&sr=b&rscd=inline&rsct=image/png&skoid=475fd488-6c59-44a5-9aa9-31c4db451bea&sktid=a48cca56-e6da-484e-a814-9c849652bcb3&skt=2025-06-24T19%3A41%3A07Z&ske=2025-06-25T19%3A41%3A07Z&sks=b&skv=2024-08-04&sig=MAxypb1ouM%2BIPTGr/8Fhq8OT5uFgVinWZOJmd%2BWfrpo%3D', 'https://oaidalleapiprodscus.blob.core.windows.net/private/org-AfvkWFxjqqTuopkcXEpNP4zc/user-elj0Uq9QlNHVCP9wMr4EHPiE/img-h3KdAGmq7lI6LDricCCwXhdu.png?st=2025-06-25T02%3A43%3A00Z&se=2025-06-25T04%3A43%3A00Z&sp=r&sv=2024-08-04&sr=b&rscd=inline&rsct=image/png&skoid=475fd488-6c59-44a5-9aa9-31c4db451bea&sktid=a48cca56-e6da-484e-a814-9c849652bcb3&skt=2025-06-24T19%3A41%3A07Z&ske=2025-06-25T19%3A41%3A07Z&sks=b&skv=2024-08-04&sig=1UM/daA1vxsuaIPEZahy6HOg%2B5pPvRpNaQq/L8Ov8No%3D']
將這兩個網址分別貼到瀏覽器檢視所生成的圖片 :
結果每張圖片裡仍然只有一隻貓, 提示詞 '兩隻可愛的貓咪' 的意思應該要理解為一張圖片裡要有兩隻貓才對.
可以將上面生圖的程序寫成如下函式 :
>>> def generate_images(prompt, api_key, **kwargs):
client=OpenAI(api_key=api_key)
replies=client.images.generate(prompt=prompt, **kwargs)
urls=[item.url for item in replies.data]
return urls[0] if len(urls) == 1 else urls
此函式 generate_images() 須傳入兩個必要的位置參數 prompt 與 api_key, 若有其餘關鍵字參數則會透過 **kwargs 傳給 client.images.generate(). 此函式綜合考量了 'dall-e-2' 模型可以生成 1~10 張圖片, 以及 'dall-e-3' 模型只能生成 1 張圖片的限制, 使用串列生成式擷取生成圖片的網址組成串列傳回, 若只有一個網址就傳回字串. 例如 :
>>> prompt='可愛的小貓'
>>> image=generate_images(prompt, openai_api_key, model='dall-e-2')
>>> image
'https://oaidalleapiprodscus.blob.core.windows.net/private/org-AfvkWFxjqqTuopkcXEpNP4zc/user-elj0Uq9QlNHVCP9wMr4EHPiE/img-89LspBLuhIgJrFvX8jJFNUPP.png?st=2025-06-25T06%3A19%3A19Z&se=2025-06-25T08%3A19%3A19Z&sp=r&sv=2024-08-04&sr=b&rscd=inline&rsct=image/png&skoid=475fd488-6c59-44a5-9aa9-31c4db451bea&sktid=a48cca56-e6da-484e-a814-9c849652bcb3&skt=2025-06-24T08%3A31%3A34Z&ske=2025-06-25T08%3A31%3A34Z&sks=b&skv=2024-08-04&sig=L2X9V4FLZN8S7gPYhtGtJ12JCISm9gMA5tD7HJP5MRE%3D'
生圖結果如下 :
坦白說我對上面生成的貓貓圖都不滿意, 所以最後想讓它生成一張美女圖片, 於是請 AI 給我一個描繪漂亮亞洲女性的提示詞 :
美麗的亞洲女性,優雅且高貴,柔和的自然光,細緻的五官,富有表情的雙眼配上自然的睫毛,光滑如瓷的肌膚,精緻的骨骼結構,自然的妝容,黑色亮麗的頭髮帶有柔和的波浪,神情寧靜,寫實風格,高解析度,專業人像攝影,淺景深,溫暖的色調,電影感燈光,傑作級品質,極致細緻。
翻成英文後呼叫生圖函式 :
>>> prompt='''
Beautiful Asian woman, elegant and graceful, soft natural lighting, detailed facial features, expressive eyes with natural eyelashes, smooth porcelain skin, delicate bone structure, natural makeup, glossy black hair with soft waves, serene expression, photorealistic, high resolution, professional portrait photography, shallow depth of field, warm color palette, cinematic lighting, masterpiece quality, ultra detailed'''
>>> image=generate_images(prompt, openai_api_key)
>>> image
'https://oaidalleapiprodscus.blob.core.windows.net/private/org-AfvkWFxjqqTuopkcXEpNP4zc/user-elj0Uq9QlNHVCP9wMr4EHPiE/img-m17jLgHLYuD24Im02leGfwYH.png?st=2025-06-25T06%3A54%3A46Z&se=2025-06-25T08%3A54%3A46Z&sp=r&sv=2024-08-04&sr=b&rscd=inline&rsct=image/png&skoid=475fd488-6c59-44a5-9aa9-31c4db451bea&sktid=a48cca56-e6da-484e-a814-9c849652bcb3&skt=2025-06-25T06%3A25%3A03Z&ske=2025-06-26T06%3A25%3A03Z&sks=b&skv=2024-08-04&sig=W6yP3rnhEZArGjNjkP5/ppr%2BfX9rmU%2BzUv5AzjXhqoY%3D'
結果如下 :
嗯, 單眼皮, 算了, 也總比上面的貓貓圖要好.
經過上面的折騰, 我的儲值餘額剩下 :
雖然畫圖用得較兇, 但自從玩 OpenAI API 至今還花不到台幣 15 元耶!








沒有留言 :
張貼留言