yeq6x's picture
.
43a7729
raw
history blame
9.96 kB
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)