import gradio as gr import os from dotenv import load_dotenv from PIL import Image import io import base64 import requests from datetime import datetime from pytz import timezone import numpy as np load_dotenv() # 初回訪問のメッセージ welcome_message = """

このサービスは初めてご利用ですか?

以下から選択してください。

""" # Googleフォームの送信URL apps_script_url = os.environ["APPS_SCRIPT_URL"] # ローカライズ用辞書 translations = { "en": { "welcome_message": "

Is this your first time using this service?

Please select below.

", "visit_choices": ["First time", "Returning"], "returning_message": "

Thank you for returning!

Click the button below to proceed.

", "proceed_button": "Proceed", "survey_title": "

Please answer the survey

Fill out the form below and submit.

", "form": { "source": "1. Where did you learn about this Space?", "country": "2. Which country or region do you live in?", "ai_usage": "3. Have you used AI to generate illustrations?", "ai_usage_choices": ["Select...", "Frequently", "Sometimes", "Never"], "drawing_experience": "4. Have you practiced traditional hand-drawn illustrations?", "drawing_experience_choices": ["Select...", "As a hobby", "For work", "Never"], "issues": "5. (Optional) Tell us about any challenges you've faced while practicing illustrations.", "interest": "6. (Optional) What interested you in this Space?", "contact_info": "7. (Optional) Provide your contact information (e.g., SNS, URL, email)", "contact_info_placeholder": "e.g., Twitter, portfolio URL, email", "submit_button": "Submit" } }, "ja": { "welcome_message": "

このサービスは初めてご利用ですか?

以下から選択してください。

", "visit_choices": ["初めて利用する", "2回目以降"], "returning_message": "

再訪ありがとうございます!

以下のボタンをクリックして進んでください。

", "proceed_button": "進む", "survey_title": "

アンケートにご回答ください

以下のフォームに入力して送信してください。

", "form": { "source": "1. このSpaceをどこで知りましたか?", "country": "2. お住まいの国や地域を教えてください。", "ai_usage": "3. 生成AIでイラスト生成をしたことがありますか?", "ai_usage_choices": ["選択してください...", "よくする", "ある", "ない"], "drawing_experience": "4. 生成AIではない従来の手描きイラストを練習した経験はありますか?", "drawing_experience_choices": ["選択してください...", "趣味で", "仕事で", "ない"], "issues": "5. (任意)イラストの練習中に困った経験があれば教えてください", "interest": "6. (任意)このSpaceに興味を持った理由を教えてください。", "contact_info": "7. (任意)連絡先(SNS、URL、メールアドレスなど)を教えてください", "contact_info_placeholder": "例: Twitterアカウント、ポートフォリオURL、メールアドレスなど", "submit_button": "送信" } }, "zh": { "welcome_message": "

这是您第一次使用此服务吗?

请从下面选择。

", "visit_choices": ["第一次", "再次访问"], "returning_message": "

感谢您的再次访问!

请点击下面的按钮继续。

", "proceed_button": "继续", "survey_title": "

请回答问卷

填写以下表格并提交。

", "form": { "source": "1. 您是从哪里得知此服务的?", "country": "2. 您居住的国家或地区是?", "ai_usage": "3. 您是否使用过AI生成插图?", "ai_usage_choices": ["请选择...", "经常", "偶尔", "从未"], "drawing_experience": "4. 您是否练习过传统手绘插图?", "drawing_experience_choices": ["请选择...", "作为爱好", "为了工作", "从未"], "issues": "5. (可选)在练习插图过程中遇到的挑战是什么?", "interest": "6. (可选)是什么让您对这个Space感兴趣?", "contact_info": "7. (可选)提供您的联系方式(如:SNS、网址、电子邮件等)", "contact_info_placeholder": "例如:Twitter、作品集网址、电子邮件", "submit_button": "提交" } } } # 言語選択に応じてローカライズ def localize(language): t = translations[language] return { "welcome_message": t["welcome_message"], "visit_choices": t["visit_choices"], "returning_message": t["returning_message"], "proceed_button": t["proceed_button"], "form_html": f"""

{t['survey_title']}






















""" } # 初回訪問の選択肢に応じた処理 def handle_visit_choice(choice, language): if choice == localize(language)["visit_choices"][0]: return gr.update(visible=False), gr.update(visible=True), gr.update(visible=False) else: return gr.update(visible=False), gr.update(visible=False), gr.update(visible=True) # フォーム送信後の処理 def handle_form_submission(flag_value): print("form submitted") return gr.update(visible=False), gr.update(visible=True) # 進むボタンを押した後の処理 def handle_proceed(): print("more than once") return gr.update(visible=False), gr.update(visible=True) script = """ () => { function attachFormListener() { const form = document.getElementById("survey-form"); if (form) { function submitForm() { console.log('form submitted'); const flagInput = document.querySelector("#form_flag textarea"); flagInput.value = 'true'; flagInput.dispatchEvent(new Event('input')); } // イベントを削除 form.removeEventListener("submit", submitForm); // イベントを追加 form.addEventListener("submit", submitForm); } } // 初期ロード時にイベントリスナーを設定 attachFormListener(); // DOMが動的に更新された場合にもイベントリスナーを再設定 const observer = new MutationObserver(() => { attachFormListener(); }); observer.observe(document.body, { childList: true, subtree: true }); } """ # Google Apps ScriptのURL feedback_script_url = os.environ["FEEDBACK_SCRIPT_URL"] # 画像生成パラメータ def generate_image(mode, weight1, weight2): # ダミーの画像生成処理 image = Image.new("RGB", (256, 256), color=(int(255*weight1), int(255*weight2), int(255*weight1*weight2))) return image # Google Driveに保存する処理 def send_feedback(image, filename): # numpy.ndarray を PIL.Image に変換 if isinstance(image, np.ndarray): image = Image.fromarray(image) # 画像をBase64にエンコード buffered = io.BytesIO() image.save(buffered, format="PNG") img_str = base64.b64encode(buffered.getvalue()).decode() # Google Apps Scriptに送信 response = requests.post( feedback_script_url, json={"image": img_str, "filename": filename} ) if response.status_code == 200: return gr.update(value="Thank you for cooperation!/ご協力ありがとうございます!", interactive=False) else: return gr.update(value="Failed to send. Try again./送信に失敗しました。もう一度お試しください。", interactive=True)