yeq6x commited on
Commit
6118f2d
1 Parent(s): a0fc1c5

アンケート

Browse files
Files changed (1) hide show
  1. app.py +314 -60
app.py CHANGED
@@ -1,11 +1,12 @@
1
  import gradio as gr
2
  import io
 
3
  from PIL import Image
4
  import base64
5
  from scripts.process_utils import initialize, process_image_as_base64, image_to_base64
6
  from scripts.anime import init_model
7
  from scripts.generate_prompt import load_wd14_tagger_model
8
- import webbrowser
9
  from datetime import datetime
10
  from pytz import timezone
11
 
@@ -43,76 +44,329 @@ def mix_images(sotai_image_data, sketch_image_data, opacity1, opacity2):
43
 
44
  return mixed_image
45
 
46
- # X(Twitter)に投稿するリンクを生成
47
- def generate_twitter_link(image):
48
- image_base64 = image_to_base64(image)
49
- return f"https://twitter.com/intent/tweet?text=Image2Body&url={image_base64} #Image2Body"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
 
51
- def post_to_twitter(image):
52
- link = generate_twitter_link(image)
53
- webbrowser.open_new_tab(link)
54
 
55
  with gr.Blocks() as demo:
 
56
  # title
57
  gr.HTML("<h1>Image2Body demo</h1>")
58
  # description
59
  gr.HTML("<p>Upload an image and select processing options to generate body and sketch images.</p>")
60
- # interface
61
- submit = None
62
- with gr.Row():
63
- with gr.Column() as input_col:
64
- input_image = gr.Image(type="pil", label="Input Image", height=512)
65
- with gr.Tab("original"):
66
- original_mode = gr.Text("original", label="Mode", visible=False)
67
- original_submit = gr.Button("Submit", variant="primary")
68
- with gr.Tab("refine"):
69
- refine_input = [
70
- gr.Text("refine", label="Mode", visible=False),
71
- gr.Slider(0, 2, value=0.6, step=0.05, label="Weight 1 (Sketch)"),
72
- gr.Slider(0, 1, value=0.05, step=0.025, label="Weight 2 (Body)")
73
- ]
74
- refine_submit = gr.Button("Submit", variant="primary")
75
- gr.Examples(
76
- examples=[f"images/sample{i}.png" for i in [1, 2, 4, 5, 6, 7, 10, 16, 18, 19]],
77
- inputs=[input_image]
78
  )
79
- with gr.Column() as output_col:
80
- sotai_image_data = gr.Text(label="Sotai Image data", visible=False)
81
- sketch_image_data = gr.Text(label="Sketch Image data", visible=False)
82
- mixed_image = gr.Image(label="Output Image", elem_id="output_image")
83
- opacity_slider1 = gr.Slider(0, 1, value=0.5, step=0.05, label="Opacity (Sotai)")
84
- opacity_slider2 = gr.Slider(0, 1, value=0.5, step=0.05, label="Opacity (Sketch)")
85
- # post_button = gr.Button("Post to X(Twitter)", variant="secondary")
86
- # post_button.click(
87
- # post_to_twitter,
88
- # inputs=[mixed_image],
89
- # outputs=None
90
- # )
91
-
92
- original_submit.click(
93
- process_image,
94
- inputs=[input_image, original_mode],
95
- outputs=[sotai_image_data, sketch_image_data, mixed_image]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  )
97
- refine_submit.click(
98
- process_image,
99
- inputs=[input_image, refine_input[0], refine_input[1], refine_input[2]],
100
- outputs=[sotai_image_data, sketch_image_data, mixed_image]
 
 
 
 
 
 
101
  )
102
- sotai_image_data.change(
103
- mix_images,
104
- inputs=[sotai_image_data, sketch_image_data, opacity_slider1, opacity_slider2],
105
- outputs=mixed_image
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  )
107
- opacity_slider1.change(
108
- mix_images,
109
- inputs=[sotai_image_data, sketch_image_data, opacity_slider1, opacity_slider2],
110
- outputs=mixed_image
 
 
111
  )
112
- opacity_slider2.change(
113
- mix_images,
114
- inputs=[sotai_image_data, sketch_image_data, opacity_slider1, opacity_slider2],
115
- outputs=mixed_image
 
 
116
  )
117
 
118
- demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
  import io
3
+ import os
4
  from PIL import Image
5
  import base64
6
  from scripts.process_utils import initialize, process_image_as_base64, image_to_base64
7
  from scripts.anime import init_model
8
  from scripts.generate_prompt import load_wd14_tagger_model
9
+ # import webbrowser
10
  from datetime import datetime
11
  from pytz import timezone
12
 
 
44
 
45
  return mixed_image
46
 
47
+ # # X(Twitter)に投稿するリンクを生成
48
+ # def generate_twitter_link(image):
49
+ # image_base64 = image_to_base64(image)
50
+ # return f"https://twitter.com/intent/tweet?text=Image2Body&url={image_base64} #Image2Body"
51
+
52
+ # def post_to_twitter(image):
53
+ # link = generate_twitter_link(image)
54
+ # webbrowser.open_new_tab(link)
55
+
56
+ import gradio as gr
57
+
58
+ # 初回訪問のメッセージ
59
+ welcome_message = """
60
+ <h2>このサービスは初めてご利用ですか?</h2>
61
+ <p>以下から選択してください。</p>
62
+ """
63
+
64
+ from dotenv import load_dotenv
65
+ load_dotenv()
66
+
67
+ # Googleフォームの送信URL
68
+ apps_script_url = os.environ["APPS_SCRIPT_URL"]
69
+
70
+ # ローカライズ用辞書
71
+ translations = {
72
+ "en": {
73
+ "welcome_message": "<h2>Is this your first time using this service?</h2><p>Please select below.</p>",
74
+ "visit_choices": ["First time", "Returning"],
75
+ "returning_message": "<h2>Thank you for returning!</h2><p>Click the button below to proceed.</p>",
76
+ "proceed_button": "Proceed",
77
+ "survey_title": "<h2>Please answer the survey</h2><p>Fill out the form below and submit.</p>",
78
+ "form": {
79
+ "source": "1. Where did you learn about this Space?",
80
+ "country": "2. Which country or region do you live in?",
81
+ "ai_usage": "3. Have you used AI to generate illustrations?",
82
+ "ai_usage_choices": ["Select...", "Frequently", "Sometimes", "Never"],
83
+ "drawing_experience": "4. Have you practiced traditional hand-drawn illustrations?",
84
+ "drawing_experience_choices": ["Select...", "As a hobby", "For work", "Never"],
85
+ "issues": "5. (Optional) Tell us about any challenges you've faced while practicing illustrations.",
86
+ "interest": "6. (Optional) What interested you in this Space?",
87
+ "contact_info": "7. (Optional) Provide your contact information (e.g., SNS, URL, email)",
88
+ "contact_info_placeholder": "e.g., Twitter, portfolio URL, email",
89
+ "submit_button": "Submit"
90
+ }
91
+ },
92
+ "ja": {
93
+ "welcome_message": "<h2>このサービスは初めてご利用ですか?</h2><p>以下から選択してください。</p>",
94
+ "visit_choices": ["初めて利用する", "2回目以降"],
95
+ "returning_message": "<h2>再訪ありがとうございます!</h2><p>以下のボタンをクリックして進んでください。</p>",
96
+ "proceed_button": "進む",
97
+ "survey_title": "<h2>アンケートにご回答ください</h2><p>以下のフォームに入力して送信してください。</p>",
98
+ "form": {
99
+ "source": "1. このSpaceをどこで知りましたか?",
100
+ "country": "2. お住まいの国や地域を教えてください。",
101
+ "ai_usage": "3. 生成AIでイラスト生成をしたことがありますか?",
102
+ "ai_usage_choices": ["選択してください...", "よくする", "ある", "ない"],
103
+ "drawing_experience": "4. 生成AIではない従来の手描きイラストを練習した経験はありますか?",
104
+ "drawing_experience_choices": ["選択してください...", "趣味で", "仕事で", "ない"],
105
+ "issues": "5. (任意)イラストの練習中に困った経験があれば教えてください",
106
+ "interest": "6. (任意)このSpaceに興味を持った理由を教えてください。",
107
+ "contact_info": "7. (任意)連絡先(SNS、URL、メールアドレスなど)を教えてください",
108
+ "contact_info_placeholder": "例: Twitterアカウント、ポートフォリオURL、メールアドレスなど",
109
+ "submit_button": "送信"
110
+ }
111
+ },
112
+ "zh": {
113
+ "welcome_message": "<h2>这是您第一次使用此服务吗?</h2><p>请从下面选择。</p>",
114
+ "visit_choices": ["第一次", "再次访问"],
115
+ "returning_message": "<h2>感谢您的再次访问!</h2><p>请点击下面的按钮继续。</p>",
116
+ "proceed_button": "继续",
117
+ "survey_title": "<h2>请回答问卷</h2><p>填写以下表格并提交。</p>",
118
+ "form": {
119
+ "source": "1. 您是从哪里得知此服务的?",
120
+ "country": "2. 您居住的国家或地区是?",
121
+ "ai_usage": "3. 您是否使用过AI生成插图?",
122
+ "ai_usage_choices": ["请选择...", "经常", "偶尔", "从未"],
123
+ "drawing_experience": "4. 您是否练习过传统手绘插图?",
124
+ "drawing_experience_choices": ["请选择...", "作为爱好", "为了工作", "从未"],
125
+ "issues": "5. (可选)在练习插图过程中遇到的挑战是什么?",
126
+ "interest": "6. (可选)是什么让您对这个Space感兴趣?",
127
+ "contact_info": "7. (可选)提供您的联系方式(如:SNS、网址、电子邮件等)",
128
+ "contact_info_placeholder": "例如:Twitter、作品集网址、电子邮件",
129
+ "submit_button": "提交"
130
+ }
131
+ }
132
+ }
133
+
134
+ # 言語選択に応じてローカライズ
135
+ def localize(language):
136
+ t = translations[language]
137
+ return {
138
+ "welcome_message": t["welcome_message"],
139
+ "visit_choices": t["visit_choices"],
140
+ "returning_message": t["returning_message"],
141
+ "proceed_button": t["proceed_button"],
142
+ "form_html": f"""
143
+ <h2>{t['survey_title']}</h2>
144
+ <form id="survey-form" action="{apps_script_url}" method="POST" target="hidden_iframe">
145
+ <label for="source">{t['form']['source']}</label><br>
146
+ <input type="text" name="source" id="source" required><br><br>
147
+
148
+ <label for="country">{t['form']['country']}</label><br>
149
+ <input type="text" name="country" id="country" required><br><br>
150
+
151
+ <label for="ai_usage">{t['form']['ai_usage']}</label><br>
152
+ <select name="ai_usage" id="ai_usage" required>
153
+ <option value="" selected disabled>{t['form']['ai_usage_choices'][0]}</option>
154
+ {"".join([f'<option value="{choice}">{choice}</option>' for choice in t['form']['ai_usage_choices'][1:]])}
155
+ </select><br><br>
156
+
157
+ <label for="drawing_experience">{t['form']['drawing_experience']}</label><br>
158
+ <select name="drawing_experience" id="drawing_experience" required>
159
+ <option value="" selected disabled>{t['form']['drawing_experience_choices'][0]}</option>
160
+ {"".join([f'<option value="{choice}">{choice}</option>' for choice in t['form']['drawing_experience_choices'][1:]])}
161
+ </select><br><br>
162
+
163
+ <label for="issues">{t['form']['issues']}</label><br>
164
+ <textarea name="issues" id="issues"></textarea><br><br>
165
+
166
+ <label for="interest">{t['form']['interest']}</label><br>
167
+ <textarea name="interest" id="interest"></textarea><br><br>
168
+
169
+ <label for="contact_info">{t['form']['contact_info']}</label><br>
170
+ <input type="text" name="contact_info" id="contact_info" placeholder="{t['form']['contact_info_placeholder']}"><br><br>
171
+
172
+ <button type="submit" id="submit-button">{t['form']['submit_button']}</button>
173
+ </form>
174
+ <iframe name="hidden_iframe" style="display:none;"></iframe>
175
+ """
176
+ }
177
+
178
+ # 初回訪問の選択肢に応じた処理
179
+ def handle_visit_choice(choice, language):
180
+ if choice == localize(language)["visit_choices"][0]:
181
+ return gr.update(visible=False), gr.update(visible=True), gr.update(visible=False)
182
+ else:
183
+ return gr.update(visible=False), gr.update(visible=False), gr.update(visible=True)
184
+
185
+ # フォーム送信後の処理
186
+ def handle_form_submission(flag_value):
187
+ print("form submitted")
188
+ return gr.update(visible=False), gr.update(visible=True)
189
+
190
+ # 進むボタンを押した後の処理
191
+ def handle_proceed():
192
+ print("more than once")
193
+ return gr.update(visible=False), gr.update(visible=True)
194
 
 
 
 
195
 
196
  with gr.Blocks() as demo:
197
+ form_visible_flag = gr.Textbox(value="false", elem_id="form_flag", visible=False)
198
  # title
199
  gr.HTML("<h1>Image2Body demo</h1>")
200
  # description
201
  gr.HTML("<p>Upload an image and select processing options to generate body and sketch images.</p>")
202
+
203
+
204
+ # 訪問回数の選択
205
+ with gr.Column() as visit_section:
206
+ # 言語選択セクション
207
+ with gr.Row():
208
+ language_choice = gr.Radio(
209
+ choices=["en", "ja", "zh"],
210
+ label="Select Language / 言語を選択 / 选择语言",
211
+ value="en"
 
 
 
 
 
 
 
 
212
  )
213
+
214
+ localized = localize("en")
215
+ welcome_message = gr.HTML(localized["welcome_message"])
216
+ visit_choice = gr.Radio(choices=localized["visit_choices"], label="")
217
+
218
+ # 初回訪問のアンケートセクション
219
+ with gr.Column(visible=False) as survey_section:
220
+ # フォームセクション
221
+ form_section = gr.HTML(localize("en")["form_html"])
222
+
223
+ # 2回目以降の進むボタンセクション
224
+ with gr.Column(visible=False) as proceed_section:
225
+ # gr.HTML("<h2>再訪ありがとうございます!</h2>")
226
+ # proceed_button = gr.Button("進む")
227
+ proceed_message = gr.HTML(localize("en")["returning_message"])
228
+ proceed_button = gr.Button(localize("en")["proceed_button"], variant="primary")
229
+
230
+ # 言語選択変更時の更新
231
+ def update_language(language):
232
+ localized = localize(language)
233
+ return (
234
+ gr.update(value=localized["welcome_message"]),
235
+ gr.update(choices=localized["visit_choices"]),
236
+ gr.update(value=localized["returning_message"]),
237
+ gr.update(value=localized["proceed_button"]),
238
+ gr.update(value=localized["form_html"])
239
+ )
240
+
241
+ language_choice.change(
242
+ update_language,
243
+ inputs=[language_choice],
244
+ outputs=[welcome_message, visit_choice, proceed_message, proceed_button, form_section]
245
  )
246
+
247
+ # フォーム送信時の画面切り替え
248
+ def handle_submit():
249
+ return gr.update(visible=False), gr.update(visible=True)
250
+
251
+ submit_flag = gr.Textbox(visible=False, value="false")
252
+ submit_flag.change(
253
+ handle_submit,
254
+ inputs=[],
255
+ outputs=[form_section]
256
  )
257
+
258
+ # メイン画面セクション
259
+ with gr.Column(visible=False) as main_section:
260
+ # interface
261
+ submit = None
262
+ with gr.Row():
263
+ with gr.Column() as input_col:
264
+ input_image = gr.Image(type="pil", label="Input Image", height=512)
265
+ with gr.Tab("original"):
266
+ original_mode = gr.Text("original", label="Mode", visible=False)
267
+ original_submit = gr.Button("Submit", variant="primary")
268
+ with gr.Tab("refine"):
269
+ refine_input = [
270
+ gr.Text("refine", label="Mode", visible=False),
271
+ gr.Slider(0, 2, value=0.6, step=0.05, label="Weight 1 (Sketch)"),
272
+ gr.Slider(0, 1, value=0.05, step=0.025, label="Weight 2 (Body)")
273
+ ]
274
+ refine_submit = gr.Button("Submit", variant="primary")
275
+ gr.Examples(
276
+ examples=[f"images/sample{i}.png" for i in [1, 2, 4, 5, 6, 7, 10, 16, 18, 19]],
277
+ inputs=[input_image]
278
+ )
279
+ with gr.Column() as output_col:
280
+ sotai_image_data = gr.Text(label="Sotai Image data", visible=False)
281
+ sketch_image_data = gr.Text(label="Sketch Image data", visible=False)
282
+ mixed_image = gr.Image(label="Output Image", elem_id="output_image")
283
+ opacity_slider1 = gr.Slider(0, 1, value=0.5, step=0.05, label="Opacity (Sotai)")
284
+ opacity_slider2 = gr.Slider(0, 1, value=0.5, step=0.05, label="Opacity (Sketch)")
285
+ # post_button = gr.Button("Post to X(Twitter)", variant="secondary")
286
+ # post_button.click(
287
+ # post_to_twitter,
288
+ # inputs=[mixed_image],
289
+ # outputs=None
290
+ # )
291
+
292
+ original_submit.click(
293
+ process_image,
294
+ inputs=[input_image, original_mode],
295
+ outputs=[sotai_image_data, sketch_image_data, mixed_image]
296
+ )
297
+ refine_submit.click(
298
+ process_image,
299
+ inputs=[input_image, refine_input[0], refine_input[1], refine_input[2]],
300
+ outputs=[sotai_image_data, sketch_image_data, mixed_image]
301
+ )
302
+ sotai_image_data.change(
303
+ mix_images,
304
+ inputs=[sotai_image_data, sketch_image_data, opacity_slider1, opacity_slider2],
305
+ outputs=mixed_image
306
+ )
307
+ opacity_slider1.change(
308
+ mix_images,
309
+ inputs=[sotai_image_data, sketch_image_data, opacity_slider1, opacity_slider2],
310
+ outputs=mixed_image
311
+ )
312
+ opacity_slider2.change(
313
+ mix_images,
314
+ inputs=[sotai_image_data, sketch_image_data, opacity_slider1, opacity_slider2],
315
+ outputs=mixed_image
316
+ )
317
+
318
+ # フラグ変更時に画面切り替え
319
+ form_visible_flag.change(
320
+ handle_form_submission,
321
+ inputs=[form_visible_flag],
322
+ outputs=[survey_section, main_section]
323
  )
324
+
325
+ # 選択肢に応じてセクションを切り替え
326
+ visit_choice.change(
327
+ handle_visit_choice,
328
+ inputs=[visit_choice, language_choice],
329
+ outputs=[visit_section, survey_section, proceed_section]
330
  )
331
+
332
+ # 進むボタン押下時の画面遷移
333
+ proceed_button.click(
334
+ handle_proceed,
335
+ inputs=[],
336
+ outputs=[proceed_section, main_section]
337
  )
338
 
339
+ # JavaScriptの読み込み
340
+ demo.load(None, None, None, js="""
341
+ () => {
342
+ function attachFormListener() {
343
+ const form = document.getElementById("survey-form");
344
+ if (form) {
345
+ function submitForm() {
346
+
347
+ console.log('form submitted');
348
+
349
+ const flagInput = document.querySelector("#form_flag textarea");
350
+ flagInput.value = 'true';
351
+ flagInput.dispatchEvent(new Event('input'));
352
+ }
353
+ // イベントを削除
354
+ form.removeEventListener("submit", submitForm);
355
+ // イベントを追加
356
+ form.addEventListener("submit", submitForm);
357
+ }
358
+ }
359
+
360
+ // 初期ロード時にイベントリスナーを設定
361
+ attachFormListener();
362
+
363
+ // DOMが動的に更新された場合にもイベントリスナーを再設定
364
+ const observer = new MutationObserver(() => {
365
+ attachFormListener();
366
+ });
367
+
368
+ observer.observe(document.body, { childList: true, subtree: true });
369
+ }
370
+ """)
371
+
372
+ demo.launch()