2025年6月27日 星期五

OpenAI API 學習筆記 : 呼叫 Image API 生圖 (三)

在前一篇測試裡, 我們使用 Gradio 作為 WebUI 工具, 在頁面中輸入金鑰與提示詞呼叫 OpenAI Image API 來生成圖像, 本篇則是要改用 Streamlit 來實作功能相同的 Web app. 

本系列全部測試筆記參考 :


關於 Streamlit 套件用法參考 : 


本篇要改寫的對象是前一篇測試中, 模型選單與尺寸選單有連動功能的 gradio-openai-image-api-test-2.py 這個 web app :

import gradio as gr
from openai import OpenAI

# 圖片尺寸選項
size_options={
    'dall-e-2': ['256x256', '512x512', '1024x1024'],
    'dall-e-3': ['1024x1024', '1024x1792', '1792x1024']
    }

# 呼叫 OpenAI API 生圖
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  # Gallery 只能接收串列

# 執行按鈕時處理函式
def handler(api_key, prompt, model_sel, size_sel, image_count):
    if not api_key.strip():   # 處理使用者未輸入金鑰問題
        return [], '請輸入 OpenAI API Key'
    if not prompt.strip():   # 處理使用者未輸入提示詞問題
        return [], '請輸入提示詞 (prompt)'
    if model_sel == 'dall-e-2':
        size=size_sel
        n=image_count   # dall-e-2 允許生 1~10 張圖
    else:
        size=size_sel
        n=1   # dall-e-3 只允許生 1 張圖
    urls=generate_images(prompt, api_key, model=model_sel, n=n, size=size)
    msg=f'模型: {model_sel}\n尺寸: {size}\n張數: {n}'   # 輸出設定值
    return urls, msg  # 傳回生圖之網址串列給 Gallery, 設定值給狀態訊息

# 模型選單連動圖片尺寸選單 : 動態更新圖片尺寸選單
def update_size_options(selected_model):
    return gr.update(
        choices=size_options[selected_model],
        value=size_options[selected_model][0]
        )

# 使用 Blocks 語法 (才有元件連動功能)
with gr.Blocks(title='OpenAI Image API 測試') as blocks:
    gr.Markdown('## 🎨 使用 DALL·E 2 / 3 生圖')
    api_key=gr.Textbox(label='請輸入金鑰 (API key)', type='password')
    prompt=gr.TextArea(label='請輸入提示詞 (Prompt)', max_lines=10)
    model_sel=gr.Radio(
        label='選擇模型',
        choices=['dall-e-2', 'dall-e-3'],
        value='dall-e-3'
        )
    size_sel=gr.Radio(
        label='選擇圖片尺寸',
        choices=size_options['dall-e-3'],
        value=size_options['dall-e-3'][0]
        )
    image_count=gr.Slider(
        label='圖片張數 (DALL·E 2 專用)',
        minimum=1,
        maximum=10,
        step=1,
        value=1
        )
    submit_btn=gr.Button('開始生成')
    gallery=gr.Gallery(label='生成的圖片')
    status=gr.Textbox(label='狀態訊息', interactive=False) # 僅輸出
    # 連動更新圖片尺寸選單
    model_sel.change(
        fn=update_size_options,  # 呼叫自訂函式更新尺寸選單內容
        inputs=model_sel,  # 模型選單值
        outputs=size_sel   # 尺寸選單值
        )
    # 點擊按鈕觸發 handler
    submit_btn.click(
        fn=handler,
        inputs=[api_key, prompt, model_sel, size_sel, image_count],
        outputs=[gallery, status]
        )
blocks.launch()

此 Gradio 應用程式中利用 gr.update() 函式來動態更新 gr.Radio 元件的選項內容, 當選擇模型時會改變尺寸選擇器的選項. 在 Streamlit 並無類似的函式, 但可以利用 st.session_state 紀錄即時的選項狀態, 當主選單之選擇變化時重新渲染副選單之選項, 作法參考下面這篇的範例 7 :


Streamlit 版的 OpenAI Image API 生圖網頁介面程式如下 :


測試 1 : 模型與尺寸選擇器連動的 Streamlit 生圖介面 [看原始碼]

# streamlit_openai_image_api_test_1.py
import streamlit as st
from openai import OpenAI

# 生圖主函式
def generate_images(prompt, api_key, **kwargs):
    client=OpenAI(api_key=api_key)
    replies=client.images.generate(prompt=prompt, **kwargs)
    return [item.url for item in replies.data]

# UI 開始
st.set_page_config(page_title='OpenAI Image API 測試', layout='wide')
st.markdown('## 🎨 使用 DALL·E 2 / 3 生圖')
# 輸入金鑰與提示詞
api_key=st.text_input('請輸入金鑰 (API key)', type='password')
prompt=st.text_area('請輸入提示詞 (Prompt)', height=100)
# 圖片尺寸選項
size_options={
    'dall-e-2': ['256x256', '512x512', '1024x1024'],
    'dall-e-3': ['1024x1024', '1024x1792', '1792x1024']
    }
# 初始化 session 狀態
if 'model_sel' not in st.session_state:
    st.session_state.model_sel='dall-e-3'
if 'size_sel' not in st.session_state:
    st.session_state.size_sel=size_options['dall-e-3'][0]
# 模型選單(更新尺寸選單)
model=st.radio(
    '選擇模型',
    ['dall-e-2', 'dall-e-3'],
    index=['dall-e-2', 'dall-e-3'].index(st.session_state.model_sel)
    )
if model != st.session_state.model_sel:
    st.session_state.model_sel=model
    st.session_state.size_sel=size_options[model][0]
# 尺寸選單(依模型變化)
size_sel=st.radio(
    '選擇圖片尺寸',
    size_options[st.session_state.model_sel],
    index=size_options[st.session_state.model_sel].index(st.session_state.size_sel)
    )
st.session_state.size_sel=size_sel
# 圖片張數(僅限 dall-e-2)
image_count=1
if st.session_state.model_sel == 'dall-e-2':
    image_count=st.slider('圖片張數 (DALL·E 2 專用)', 1, 10, value=1)
sel_msg=f'模型: {st.session_state.model_sel} 尺寸: {st.session_state.size_sel}'
st.write(sel_msg)
# 按送出按鈕開始生成圖片
if st.button('開始生成', type='primary'):
    if not api_key.strip():  # 提醒必須輸入金鑰
        st.warning('⚠ 請輸入 OpenAI API Key')
    elif not prompt.strip():  # 提醒必須輸入提示詞
        st.warning('⚠️ 請輸入提示詞 (Prompt)')
    else:
        n=image_count if st.session_state.model_sel == 'dall-e-2' else 1
        with st.spinner('生成圖片中...'):
            try:
                urls=generate_images(prompt, api_key, model=st.session_state.model_sel, size=st.session_state.size_sel, n=n)
                st.success(f'✅ 成功產生 {len(urls)} 張圖片。')
                st.markdown(f'**模型**: {st.session_state.model_sel} **尺寸**: {st.session_state.size_sel} **張數**: {n}')
                cols=st.columns(min(len(urls), 3))
                for i, url in enumerate(urls):
                    with cols[i % len(cols)]:
                        st.image(url)
            except Exception as e:
                st.error(f'❌ 發生錯誤:{e}')

結果如下, 如果沒有輸入金鑰會出現提示訊息  :








輸入金鑰與下列提示詞 :

美麗的亞洲女性,優雅且高貴,柔和的自然光,細緻的五官,富有表情的雙眼配上自然的睫毛,光滑如瓷的肌膚,精緻的骨骼結構,自然的妝容,黑色亮麗的頭髮帶有柔和的波浪,神情寧靜,寫實風格,高解析度,專業人像攝影,淺景深,溫暖的色調,電影感燈光,傑作級品質,極致細緻。

用預設的 dall-e-3 模型生成 1024x1024 一張, 按生成鈕後 st.spinner 元件會在頁面顯示一個旋轉小圖表示正在生成圖片 :




當生成完畢時 st.spinner 元件會消失並展示生成之圖片 :




改選 dall-e-2 模型要求生成兩張 512x512 圖像 :





此 web app 我已佈署於 Hugging Face Spaces 平台 : 


沒有留言 :