yeq6x commited on
Commit
1aaeb30
·
1 Parent(s): 465251b
Files changed (2) hide show
  1. app.py +22 -190
  2. scripts/survey.py +208 -0
app.py CHANGED
@@ -6,9 +6,9 @@ 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
 
13
  # 初期化
14
  initialize(_use_local=False, use_gpu=True, use_dotenv=True)
@@ -19,13 +19,17 @@ def process_image(input_image, mode, weight1=None, weight2=None):
19
  tokyo_time = datetime.now(timezone('Asia/Tokyo')).strftime("%Y-%m-%d %H:%M:%S") # 日本時間のタイムスタンプ
20
  print(f"[{tokyo_time}] Processing image with mode={mode}, weight1={weight1}, weight2={weight2}")
21
 
 
 
 
 
22
  # 既存の画像処理ロジック
23
  if mode == "original":
24
  sotai_image, sketch_image = process_image_as_base64(input_image, mode, None, None)
25
  elif mode == "refine":
26
  sotai_image, sketch_image = process_image_as_base64(input_image, mode, weight1, weight2)
27
 
28
- return sotai_image, sketch_image, None
29
 
30
  def mix_images(sotai_image_data, sketch_image_data, opacity1, opacity2):
31
  sotai_image = Image.open(io.BytesIO(base64.b64decode(sotai_image_data))).convert('RGBA')
@@ -44,155 +48,6 @@ def mix_images(sotai_image_data, sketch_image_data, opacity1, opacity2):
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
@@ -289,22 +144,23 @@ with gr.Blocks() as demo:
289
  mixed_image = gr.Image(label="Output Image", elem_id="output_image")
290
  opacity_slider1 = gr.Slider(0, 1, value=0.5, step=0.05, label="Opacity (Sotai)")
291
  opacity_slider2 = gr.Slider(0, 1, value=0.5, step=0.05, label="Opacity (Sketch)")
292
- # post_button = gr.Button("Post to X(Twitter)", variant="secondary")
293
- # post_button.click(
294
- # post_to_twitter,
295
- # inputs=[mixed_image],
296
- # outputs=None
297
- # )
 
298
 
299
  original_submit.click(
300
  process_image,
301
  inputs=[input_image, original_mode],
302
- outputs=[sotai_image_data, sketch_image_data, mixed_image]
303
  )
304
  refine_submit.click(
305
  process_image,
306
  inputs=[input_image, refine_input[0], refine_input[1], refine_input[2]],
307
- outputs=[sotai_image_data, sketch_image_data, mixed_image]
308
  )
309
  sotai_image_data.change(
310
  mix_images,
@@ -342,38 +198,14 @@ with gr.Blocks() as demo:
342
  inputs=[],
343
  outputs=[proceed_section, main_section]
344
  )
 
 
 
 
 
 
345
 
346
  # JavaScriptの読み込み
347
- demo.load(None, None, None, js="""
348
- () => {
349
- function attachFormListener() {
350
- const form = document.getElementById("survey-form");
351
- if (form) {
352
- function submitForm() {
353
-
354
- console.log('form submitted');
355
-
356
- const flagInput = document.querySelector("#form_flag textarea");
357
- flagInput.value = 'true';
358
- flagInput.dispatchEvent(new Event('input'));
359
- }
360
- // イベントを削除
361
- form.removeEventListener("submit", submitForm);
362
- // イベントを追加
363
- form.addEventListener("submit", submitForm);
364
- }
365
- }
366
-
367
- // 初期ロード時にイベントリスナーを設定
368
- attachFormListener();
369
-
370
- // DOMが動的に更新された場合にもイベントリスナーを再設定
371
- const observer = new MutationObserver(() => {
372
- attachFormListener();
373
- });
374
-
375
- observer.observe(document.body, { childList: true, subtree: true });
376
- }
377
- """)
378
 
379
  demo.launch()
 
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
  from datetime import datetime
10
  from pytz import timezone
11
+ from scripts.survey import handle_form_submission, handle_visit_choice, handle_proceed, localize, script, generate_image, send_feedback
12
 
13
  # 初期化
14
  initialize(_use_local=False, use_gpu=True, use_dotenv=True)
 
19
  tokyo_time = datetime.now(timezone('Asia/Tokyo')).strftime("%Y-%m-%d %H:%M:%S") # 日本時間のタイムスタンプ
20
  print(f"[{tokyo_time}] Processing image with mode={mode}, weight1={weight1}, weight2={weight2}")
21
 
22
+ # feedback用のファイル名
23
+ tokyo_time = datetime.now(timezone('Asia/Tokyo')).strftime("%Y%m%d_%H%M%S")
24
+ filename = f"{tokyo_time}_mode={mode}_weight1={weight1}_weight2={weight2}.png"
25
+
26
  # 既存の画像処理ロジック
27
  if mode == "original":
28
  sotai_image, sketch_image = process_image_as_base64(input_image, mode, None, None)
29
  elif mode == "refine":
30
  sotai_image, sketch_image = process_image_as_base64(input_image, mode, weight1, weight2)
31
 
32
+ return sotai_image, sketch_image, filename
33
 
34
  def mix_images(sotai_image_data, sketch_image_data, opacity1, opacity2):
35
  sotai_image = Image.open(io.BytesIO(base64.b64decode(sotai_image_data))).convert('RGBA')
 
48
 
49
  return mixed_image
50
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  with gr.Blocks() as demo:
52
  form_visible_flag = gr.Textbox(value="false", elem_id="form_flag", visible=False)
53
  # title
 
144
  mixed_image = gr.Image(label="Output Image", elem_id="output_image")
145
  opacity_slider1 = gr.Slider(0, 1, value=0.5, step=0.05, label="Opacity (Sotai)")
146
  opacity_slider2 = gr.Slider(0, 1, value=0.5, step=0.05, label="Opacity (Sketch)")
147
+ send_filename = gr.Textbox(label="Feedback", visible=False)
148
+ gr.HTML("<h3>Send Feedback Image/画像を送信</h3>")
149
+ gr.HTML("<p>Images are used only for developer review and will not be shared.</p>")
150
+ gr.HTML("<p>画像は開発者が確認するためだけに使用され、公開されません。</p>")
151
+ send_feedback_button = gr.Button("Contribute as Feedback to Developer/開発者へのフィードバックとして協力する")
152
+ feed_back_result = gr.Textbox(label="Feedback Result")
153
+
154
 
155
  original_submit.click(
156
  process_image,
157
  inputs=[input_image, original_mode],
158
+ outputs=[sotai_image_data, sketch_image_data, send_filename]
159
  )
160
  refine_submit.click(
161
  process_image,
162
  inputs=[input_image, refine_input[0], refine_input[1], refine_input[2]],
163
+ outputs=[sotai_image_data, sketch_image_data, send_filename]
164
  )
165
  sotai_image_data.change(
166
  mix_images,
 
198
  inputs=[],
199
  outputs=[proceed_section, main_section]
200
  )
201
+
202
+ send_feedback_button.click(
203
+ send_feedback,
204
+ inputs=[mixed_image, send_filename],
205
+ outputs=[feed_back_result],
206
+ )
207
 
208
  # JavaScriptの読み込み
209
+ demo.load(None, None, None, js=script)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
210
 
211
  demo.launch()
scripts/survey.py ADDED
@@ -0,0 +1,208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import os
3
+ from dotenv import load_dotenv
4
+ from PIL import Image
5
+ import io
6
+ import base64
7
+ import requests
8
+ from datetime import datetime
9
+ from pytz import timezone
10
+ import numpy as np
11
+
12
+ load_dotenv()
13
+
14
+ # 初回訪問のメッセージ
15
+ welcome_message = """
16
+ <h2>このサービスは初めてご利用ですか?</h2>
17
+ <p>以下から選択してください。</p>
18
+ """
19
+
20
+ # Googleフォームの送信URL
21
+ apps_script_url = os.environ["APPS_SCRIPT_URL"]
22
+
23
+ # ローカライズ用辞書
24
+ translations = {
25
+ "en": {
26
+ "welcome_message": "<h2>Is this your first time using this service?</h2><p>Please select below.</p>",
27
+ "visit_choices": ["First time", "Returning"],
28
+ "returning_message": "<h2>Thank you for returning!</h2><p>Click the button below to proceed.</p>",
29
+ "proceed_button": "Proceed",
30
+ "survey_title": "<h2>Please answer the survey</h2><p>Fill out the form below and submit.</p>",
31
+ "form": {
32
+ "source": "1. Where did you learn about this Space?",
33
+ "country": "2. Which country or region do you live in?",
34
+ "ai_usage": "3. Have you used AI to generate illustrations?",
35
+ "ai_usage_choices": ["Select...", "Frequently", "Sometimes", "Never"],
36
+ "drawing_experience": "4. Have you practiced traditional hand-drawn illustrations?",
37
+ "drawing_experience_choices": ["Select...", "As a hobby", "For work", "Never"],
38
+ "issues": "5. (Optional) Tell us about any challenges you've faced while practicing illustrations.",
39
+ "interest": "6. (Optional) What interested you in this Space?",
40
+ "contact_info": "7. (Optional) Provide your contact information (e.g., SNS, URL, email)",
41
+ "contact_info_placeholder": "e.g., Twitter, portfolio URL, email",
42
+ "submit_button": "Submit"
43
+ }
44
+ },
45
+ "ja": {
46
+ "welcome_message": "<h2>このサービスは初めてご利用ですか?</h2><p>以下から選択してください。</p>",
47
+ "visit_choices": ["初めて利用する", "2回目以降"],
48
+ "returning_message": "<h2>再訪ありがとうございます!</h2><p>以下のボタンをクリックして進んでください。</p>",
49
+ "proceed_button": "進む",
50
+ "survey_title": "<h2>アンケートにご回答ください</h2><p>以下のフォームに入力して送信してください。</p>",
51
+ "form": {
52
+ "source": "1. このSpaceをどこで知りましたか?",
53
+ "country": "2. お住まいの国や地域を教えてください。",
54
+ "ai_usage": "3. 生成AIでイラスト生成をしたことがありますか?",
55
+ "ai_usage_choices": ["選択してください...", "よくする", "ある", "ない"],
56
+ "drawing_experience": "4. 生成AIではない従来の手描きイラストを練習した経験はありますか?",
57
+ "drawing_experience_choices": ["選択してください...", "趣味で", "仕事で", "ない"],
58
+ "issues": "5. (任意)イラストの練習中に困った経験があれば教えてください",
59
+ "interest": "6. (任意)このSpaceに興味を持った理由を教えてください。",
60
+ "contact_info": "7. (任意)連絡先(SNS、URL、メールアドレスなど)を教えてください",
61
+ "contact_info_placeholder": "例: Twitterアカウント、ポートフォリオURL、メールアドレスなど",
62
+ "submit_button": "送信"
63
+ }
64
+ },
65
+ "zh": {
66
+ "welcome_message": "<h2>这是您第一次使用此服务吗?</h2><p>请从下面选择。</p>",
67
+ "visit_choices": ["第一次", "再次访问"],
68
+ "returning_message": "<h2>感谢您的再次访问!</h2><p>请点击下面的按钮继续。</p>",
69
+ "proceed_button": "继续",
70
+ "survey_title": "<h2>请回答问卷</h2><p>填写以下表格并提交。</p>",
71
+ "form": {
72
+ "source": "1. 您是从哪里得知此服务的?",
73
+ "country": "2. 您居住的国家或地区是?",
74
+ "ai_usage": "3. 您是否使用过AI生成插图?",
75
+ "ai_usage_choices": ["请选择...", "经常", "偶尔", "从未"],
76
+ "drawing_experience": "4. 您是否练习过传统手绘插图?",
77
+ "drawing_experience_choices": ["请选择...", "作为爱好", "为了工作", "从未"],
78
+ "issues": "5. (可选)在练习插图过程中遇到的挑战是什么?",
79
+ "interest": "6. (可选)是什么让您对这个Space感兴趣?",
80
+ "contact_info": "7. (可选)提供您的联系方式(如:SNS、网址、电子邮件等)",
81
+ "contact_info_placeholder": "例如:Twitter、作品集网址、电子邮件",
82
+ "submit_button": "提交"
83
+ }
84
+ }
85
+ }
86
+
87
+ # 言語選択に応じてローカライズ
88
+ def localize(language):
89
+ t = translations[language]
90
+ return {
91
+ "welcome_message": t["welcome_message"],
92
+ "visit_choices": t["visit_choices"],
93
+ "returning_message": t["returning_message"],
94
+ "proceed_button": t["proceed_button"],
95
+ "form_html": f"""
96
+ <h2>{t['survey_title']}</h2>
97
+ <form id="survey-form" action="{apps_script_url}" method="POST" target="hidden_iframe">
98
+ <label for="source">{t['form']['source']}</label><br>
99
+ <input type="text" name="source" id="source" required><br><br>
100
+
101
+ <label for="country">{t['form']['country']}</label><br>
102
+ <input type="text" name="country" id="country" required><br><br>
103
+
104
+ <label for="ai_usage">{t['form']['ai_usage']}</label><br>
105
+ <select name="ai_usage" id="ai_usage" required>
106
+ <option value="" selected disabled>{t['form']['ai_usage_choices'][0]}</option>
107
+ {"".join([f'<option value="{choice}">{choice}</option>' for choice in t['form']['ai_usage_choices'][1:]])}
108
+ </select><br><br>
109
+
110
+ <label for="drawing_experience">{t['form']['drawing_experience']}</label><br>
111
+ <select name="drawing_experience" id="drawing_experience" required>
112
+ <option value="" selected disabled>{t['form']['drawing_experience_choices'][0]}</option>
113
+ {"".join([f'<option value="{choice}">{choice}</option>' for choice in t['form']['drawing_experience_choices'][1:]])}
114
+ </select><br><br>
115
+
116
+ <label for="issues">{t['form']['issues']}</label><br>
117
+ <textarea name="issues" id="issues"></textarea><br><br>
118
+
119
+ <label for="interest">{t['form']['interest']}</label><br>
120
+ <textarea name="interest" id="interest"></textarea><br><br>
121
+
122
+ <label for="contact_info">{t['form']['contact_info']}</label><br>
123
+ <input type="text" name="contact_info" id="contact_info" placeholder="{t['form']['contact_info_placeholder']}"><br><br>
124
+
125
+ <button type="submit" id="submit-button">{t['form']['submit_button']}</button>
126
+ </form>
127
+ <iframe name="hidden_iframe" style="display:none;"></iframe>
128
+ """
129
+ }
130
+
131
+ # 初回訪問の選択肢に応じた処理
132
+ def handle_visit_choice(choice, language):
133
+ if choice == localize(language)["visit_choices"][0]:
134
+ return gr.update(visible=False), gr.update(visible=True), gr.update(visible=False)
135
+ else:
136
+ return gr.update(visible=False), gr.update(visible=False), gr.update(visible=True)
137
+
138
+ # フォーム送信後の処理
139
+ def handle_form_submission(flag_value):
140
+ print("form submitted")
141
+ return gr.update(visible=False), gr.update(visible=True)
142
+
143
+ # 進むボタンを押した後の処理
144
+ def handle_proceed():
145
+ print("more than once")
146
+ return gr.update(visible=False), gr.update(visible=True)
147
+
148
+ script = """
149
+ () => {
150
+ function attachFormListener() {
151
+ const form = document.getElementById("survey-form");
152
+ if (form) {
153
+ function submitForm() {
154
+
155
+ console.log('form submitted');
156
+
157
+ const flagInput = document.querySelector("#form_flag textarea");
158
+ flagInput.value = 'true';
159
+ flagInput.dispatchEvent(new Event('input'));
160
+ }
161
+ // イベントを削除
162
+ form.removeEventListener("submit", submitForm);
163
+ // イベントを追加
164
+ form.addEventListener("submit", submitForm);
165
+ }
166
+ }
167
+
168
+ // 初期ロード時にイベントリスナーを設定
169
+ attachFormListener();
170
+
171
+ // DOMが動的に更新された場合にもイベントリスナーを再設定
172
+ const observer = new MutationObserver(() => {
173
+ attachFormListener();
174
+ });
175
+
176
+ observer.observe(document.body, { childList: true, subtree: true });
177
+ }
178
+ """
179
+
180
+ # Google Apps ScriptのURL
181
+ feedback_script_url = "https://script.google.com/macros/s/AKfycbzg2Eqn-vhJABTRTSLiikDlXPuqC2FSk3_qYZMUkJ4oOeSbroEkQ4ZBspIO04bfymUfSA/exec"
182
+
183
+ # 画像生成パラメータ
184
+ def generate_image(mode, weight1, weight2):
185
+ # ダミーの画像生成処理
186
+ image = Image.new("RGB", (256, 256), color=(int(255*weight1), int(255*weight2), int(255*weight1*weight2)))
187
+ return image
188
+
189
+ # Google Driveに保存する処理
190
+ def send_feedback(image, filename):
191
+ # numpy.ndarray を PIL.Image に変換
192
+ if isinstance(image, np.ndarray):
193
+ image = Image.fromarray(image)
194
+ # 画像をBase64にエンコード
195
+ buffered = io.BytesIO()
196
+ image.save(buffered, format="PNG")
197
+ img_str = base64.b64encode(buffered.getvalue()).decode()
198
+
199
+ # Google Apps Scriptに送信
200
+ response = requests.post(
201
+ feedback_script_url,
202
+ json={"image": img_str, "filename": filename}
203
+ )
204
+
205
+ if response.status_code == 200:
206
+ return gr.update(value="Thank you for cooperation!/ご協力ありがとうございます!", interactive=False)
207
+ else:
208
+ return gr.update(value="Failed to send. Try again./送信に失敗しました。もう一度お試しください。", interactive=True)