File size: 6,420 Bytes
127bd92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3426677
127bd92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fc0b46d
127bd92
 
 
 
 
 
fc0b46d
127bd92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3426677
127bd92
 
 
 
 
 
 
 
 
 
 
 
fc0b46d
127bd92
 
 
 
fc0b46d
127bd92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fc0b46d
 
 
 
 
127bd92
 
 
 
 
 
 
 
 
 
 
fc0b46d
127bd92
 
fc0b46d
127bd92
 
 
 
 
 
 
 
 
 
 
 
 
 
fc0b46d
127bd92
 
 
 
 
 
 
 
 
 
 
 
 
3426677
127bd92
3426677
 
127bd92
 
 
 
 
 
3c43af7
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
import os
from openai import OpenAI, BadRequestError
import gradio as gr
from datetime import datetime
from zoneinfo import ZoneInfo
import shutil
from io import BytesIO
import base64
from PIL import Image

PLACEHOLDER = "ここに画像を生成するための文章を入力してください…"

# 設定用リスト
size_list = ["1024x1024" ,"1024x1792" ,"1792x1024"]
quality_list = ["standard" ,"hd"]
style_list = ["vivid", "natural"]


def set_state(state, openai_key, size, quality, style):

    state["openai_key"]= openai_key
    state["size"] = size
    state["quality"] = quality
    state["style"] = style

    return state

def request_dalle(client, prompt, size, quality, style, image_path):

    err_msg = ""
    revised_prompt = ""

    try:

        response = client.images.generate(
        model="dall-e-3",
        prompt=prompt,
        size=size,
        quality=quality,
        style=style,
        n=1,
        response_format="b64_json"
        )

        # データを受け取りデコード
        image_data_json = response.data[0].b64_json
        image_data = base64.b64decode(image_data_json)

        # 画像として扱えるように保存
        image_stream = BytesIO(image_data)
        image = Image.open(image_stream)
        image.save(image_path)

        # dalle内部のプロンプト
        revised_prompt = response.data[0].revised_prompt

    except BadRequestError as e:
        print(e)
        out_image_path = ""
        err_msg = "リクエストエラーです。著作権侵害などプロンプトを確認して下さい。"
    except Exception as e:
        print(e)
        out_image_path = ""
        err_msg = "その他のエラーが発生しました。OpenAI APIキーが正しいか、クレジット残高があるか確認して下さい。"
    finally:
        return err_msg, revised_prompt

def create_image(state, text):

    err_msg = ""

    user_id = state["user_id"]
    client = state["client"]
    size = state["size"]
    quality = state["quality"]
    style = state["style"]

    # OpenAIキーチェック
    if state["openai_key"] == "":

        err_msg = "OpenAIキーを入力してください。(設定タブ)"

        return None, "", err_msg

    # 入力チェック
    if text.strip() == "":

        err_msg = "プロンプトを入力してください。"

        return None, "", err_msg

    if user_id == "":

        # IDとして現在時刻をセット
        dt = datetime.now(ZoneInfo("Asia/Tokyo"))
        user_id = dt.strftime("%Y%m%d%H%M%S")

        # ユーザIDでフォルダ作成
        os.makedirs(user_id, exist_ok=True)

        state["user_id"] = user_id

    # ファイル名は現在時刻に
    dt = datetime.now(ZoneInfo("Asia/Tokyo"))
    image_name = dt.strftime("%Y%m%d%H%M%S") + ".png"

    # ファイルパスは手動設定(誤りがないように)
    image_path = user_id + "/" + image_name

    if client is None:

        os.environ["OPENAI_API_KEY"] = state["openai_key"]

        # クライアント作成
        client = OpenAI()

        # client作成後は消す
        os.environ["OPENAI_API_KEY"] = ""

        state["client"] = client

    return_msg, prompt = request_dalle(client, text, size, quality, style, image_path)

    if return_msg == "":

        return image_path, prompt, ""

    else:
        err_msg = "画像の作成に失敗しました。\n" + return_msg

        return None, "", err_msg

def make_archive(state):
    """ 画像のZIP化・一括ダウンロード用関数 """

    dir = state["user_id"]

    if dir is None or dir == "":

        return None, ""

    if len(os.listdir(dir)) == 0:

        return None, ""

    shutil.make_archive(dir, format='zip', root_dir=dir)

    return dir + ".zip", "下部の出力ファイルからダウンロードして下さい。"

with gr.Blocks() as demo:

    title = "<h2>DALL-E3デモアプリ</h2>"
    message = "<h3>最初に[設定]タブからOpenAIキーを入力してください。"
    message += "</h3>"

    gr.Markdown(title + message)

    # セッションの宣言
    state = gr.State({
        "openai_key" : "",
        "client" : None,
        "user_id" : "",
        "size" : "",
        "quality" : "",
        "style" : "",
    })

    with gr.Tab("DALLE3を利用する") as maintab:

      # 出力画像
      out_image = gr.Image(label="生成画像", type="filepath", interactive=False)

      # 各コンポーネント定義
      text = gr.Textbox(label="プロンプト", lines=4, placeholder=PLACEHOLDER)

      # ボタン類
      with gr.Row():
        btn = gr.Button("画像作成")
        btn_dl = gr.Button(value="画像の一括ダウンロード")
        # btn_clear = gr.ClearButton(value="リセット", components=[chatbot, text_msg])

      out_prompt = gr.Text(label="Dalle-3内部プロンプト")
      sys_msg = gr.Text(label="システムメッセージ")
      out_file = gr.File(label="出力ファイル", type="filepath",interactive = False)

      btn.click(create_image, [state, text], [out_image, out_prompt, sys_msg])
      btn_dl.click(make_archive, state, [out_file, sys_msg])

    with gr.Tab("設定") as settab:
        openai_key = gr.Textbox(label="OpenAI API Key", interactive = True)
        size = gr.Dropdown(label="サイズ", choices=size_list, value = "1024x1024", interactive = True)
        quality = gr.Dropdown(label="クオリティ", choices=quality_list, value = "standard", interactive = True)
        style = gr.Dropdown(label="スタイル", choices=style_list, value = "vivid", interactive = True)

    # 設定変更時
    maintab.select(set_state, [state, openai_key, size, quality, style], state)

    with gr.Tab("利用上の注意"):

        caution = "利用上の注意<br>・1枚当たりの料金はサイズ:1024x1024で0.04ドル、それ以外のサイズは0.080ドルです。<br>"
        caution += "・こちらはクオリティがStandardの場合で、hdの場合は1.5~2倍とかかります。"
        caution += " 料金の詳細→https://openai.com/pricing<br>"
        caution += "<br>免責事項<br>・本アプリはOpenAIのAPIで製作されており、利用で生じた損害について一切の責任を負えません。"
        gr.Markdown("<h3>" + caution + "</h3>")


if __name__ == '__main__':

    demo.queue()
    demo.launch(debug=False)