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 = """ <h2>このサービスは初めてご利用ですか?</h2> <p>以下から選択してください。</p> """ # Googleフォームの送信URL apps_script_url = os.environ["APPS_SCRIPT_URL"] # ローカライズ用辞書 translations = { "en": { "welcome_message": "<h2>Is this your first time using this service?</h2><p>Please select below.</p>", "visit_choices": ["First time", "Returning"], "returning_message": "<h2>Thank you for returning!</h2><p>Click the button below to proceed.</p>", "proceed_button": "Proceed", "survey_title": "<h2>Please answer the survey</h2><p>Fill out the form below and submit.</p>", "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": "<h2>このサービスは初めてご利用ですか?</h2><p>以下から選択してください。</p>", "visit_choices": ["初めて利用する", "2回目以降"], "returning_message": "<h2>再訪ありがとうございます!</h2><p>以下のボタンをクリックして進んでください。</p>", "proceed_button": "進む", "survey_title": "<h2>アンケートにご回答ください</h2><p>以下のフォームに入力して送信してください。</p>", "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": "<h2>这是您第一次使用此服务吗?</h2><p>请从下面选择。</p>", "visit_choices": ["第一次", "再次访问"], "returning_message": "<h2>感谢您的再次访问!</h2><p>请点击下面的按钮继续。</p>", "proceed_button": "继续", "survey_title": "<h2>请回答问卷</h2><p>填写以下表格并提交。</p>", "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""" <h2>{t['survey_title']}</h2> <form id="survey-form" action="{apps_script_url}" method="POST" target="hidden_iframe"> <label for="source">{t['form']['source']}</label><br> <input type="text" name="source" id="source" required><br><br> <label for="country">{t['form']['country']}</label><br> <input type="text" name="country" id="country" required><br><br> <label for="ai_usage">{t['form']['ai_usage']}</label><br> <select name="ai_usage" id="ai_usage" required> <option value="" selected disabled>{t['form']['ai_usage_choices'][0]}</option> {"".join([f'<option value="{choice}">{choice}</option>' for choice in t['form']['ai_usage_choices'][1:]])} </select><br><br> <label for="drawing_experience">{t['form']['drawing_experience']}</label><br> <select name="drawing_experience" id="drawing_experience" required> <option value="" selected disabled>{t['form']['drawing_experience_choices'][0]}</option> {"".join([f'<option value="{choice}">{choice}</option>' for choice in t['form']['drawing_experience_choices'][1:]])} </select><br><br> <label for="issues">{t['form']['issues']}</label><br> <textarea name="issues" id="issues"></textarea><br><br> <label for="interest">{t['form']['interest']}</label><br> <textarea name="interest" id="interest"></textarea><br><br> <label for="contact_info">{t['form']['contact_info']}</label><br> <input type="text" name="contact_info" id="contact_info" placeholder="{t['form']['contact_info_placeholder']}"><br><br> <button type="submit" id="submit-button">{t['form']['submit_button']}</button> </form> <iframe name="hidden_iframe" style="display:none;"></iframe> """ } # 初回訪問の選択肢に応じた処理 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)