Spaces:
Running
on
Zero
Running
on
Zero
File size: 17,537 Bytes
b7cfcd0 641c88c 6118f2d 641c88c 6118f2d 3c811bc a0fc1c5 641c88c eca7532 6d52164 a0fc1c5 3c811bc 6d52164 641c88c 6d52164 641c88c 6d52164 6118f2d 8419fce 320761b 6118f2d 320761b 4503ce7 6118f2d 641c88c 6118f2d 641c88c 6118f2d 641c88c 6118f2d 641c88c 6118f2d 641c88c 6118f2d 641c88c 320761b 6118f2d |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 |
import gradio as gr
import io
import os
from PIL import Image
import base64
from scripts.process_utils import initialize, process_image_as_base64, image_to_base64
from scripts.anime import init_model
from scripts.generate_prompt import load_wd14_tagger_model
# import webbrowser
from datetime import datetime
from pytz import timezone
# 初期化
initialize(_use_local=False, use_gpu=True, use_dotenv=True)
init_model(use_local=False)
load_wd14_tagger_model()
def process_image(input_image, mode, weight1=None, weight2=None):
tokyo_time = datetime.now(timezone('Asia/Tokyo')).strftime("%Y-%m-%d %H:%M:%S") # 日本時間のタイムスタンプ
print(f"[{tokyo_time}] Processing image with mode={mode}, weight1={weight1}, weight2={weight2}")
# 既存の画像処理ロジック
if mode == "original":
sotai_image, sketch_image = process_image_as_base64(input_image, mode, None, None)
elif mode == "refine":
sotai_image, sketch_image = process_image_as_base64(input_image, mode, weight1, weight2)
return sotai_image, sketch_image, None
def mix_images(sotai_image_data, sketch_image_data, opacity1, opacity2):
sotai_image = Image.open(io.BytesIO(base64.b64decode(sotai_image_data))).convert('RGBA')
sketch_image = Image.open(io.BytesIO(base64.b64decode(sketch_image_data))).convert('RGBA')
if sotai_image.size != sketch_image.size:
sketch_image = sketch_image.resize(sotai_image.size, Image.Resampling.LANCZOS)
mixed_image = Image.new('RGBA', sotai_image.size, (255, 255, 255, 255))
sotai_alpha = sotai_image.getchannel('A').point(lambda x: int(x * opacity1))
sketch_alpha = sketch_image.getchannel('A').point(lambda x: int(x * opacity2))
mixed_image.paste(sketch_image, (0, 0), mask=sketch_alpha)
mixed_image.paste(sotai_image, (0, 0), mask=sotai_alpha)
return mixed_image
# # X(Twitter)に投稿するリンクを生成
# def generate_twitter_link(image):
# image_base64 = image_to_base64(image)
# return f"https://twitter.com/intent/tweet?text=Image2Body&url={image_base64} #Image2Body"
# def post_to_twitter(image):
# link = generate_twitter_link(image)
# webbrowser.open_new_tab(link)
import gradio as gr
# 初回訪問のメッセージ
welcome_message = """
<h2>このサービスは初めてご利用ですか?</h2>
<p>以下から選択してください。</p>
"""
from dotenv import load_dotenv
load_dotenv()
# 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)
with gr.Blocks() as demo:
form_visible_flag = gr.Textbox(value="false", elem_id="form_flag", visible=False)
# title
gr.HTML("<h1>Image2Body demo</h1>")
# description with translations and additional notes
gr.HTML("""
<p>Upload an image and select processing options to generate body and sketch images.</p>
<p>まだstandingタグのついた1000枚の画像しか学習していないため、他のポーズは上手くできないことをご了承ください。</p>
<p>さらなる情報は<a href="https://x.com/Yeq6X" target="_blank">@Yeq6X</a>までお問い合わせください。</p>
<p>Note: Currently, the model has been trained on only 1000 images with the 'standing' tag, so other poses may not be processed accurately.</p>
<p>For more information, please contact <a href="https://x.com/Yeq6X" target="_blank">@Yeq6X</a>.</p>
<p>注意:目前模型仅使用带有“standing”标签的1000张图像进行训练,因此其他姿势可能无法准确处理。</p>
<p>如需更多信息,请联系<a href="https://x.com/Yeq6X" target="_blank">@Yeq6X</a>。</p>
""")
# 訪問回数の選択
with gr.Column() as visit_section:
# 言語選択セクション
with gr.Row():
language_choice = gr.Radio(
choices=["en", "ja", "zh"],
label="Select Language / 言語を選択 / 选择语言",
value="en"
)
localized = localize("en")
welcome_message = gr.HTML(localized["welcome_message"])
visit_choice = gr.Radio(choices=localized["visit_choices"], label="")
# 初回訪問のアンケートセクション
with gr.Column(visible=False) as survey_section:
# フォームセクション
form_section = gr.HTML(localize("en")["form_html"])
# 2回目以降の進むボタンセクション
with gr.Column(visible=False) as proceed_section:
# gr.HTML("<h2>再訪ありがとうございます!</h2>")
# proceed_button = gr.Button("進む")
proceed_message = gr.HTML(localize("en")["returning_message"])
proceed_button = gr.Button(localize("en")["proceed_button"], variant="primary")
# 言語選択変更時の更新
def update_language(language):
localized = localize(language)
return (
gr.update(value=localized["welcome_message"]),
gr.update(choices=localized["visit_choices"]),
gr.update(value=localized["returning_message"]),
gr.update(value=localized["proceed_button"]),
gr.update(value=localized["form_html"])
)
language_choice.change(
update_language,
inputs=[language_choice],
outputs=[welcome_message, visit_choice, proceed_message, proceed_button, form_section]
)
# フォーム送信時の画面切り替え
def handle_submit():
return gr.update(visible=False), gr.update(visible=True)
submit_flag = gr.Textbox(visible=False, value="false")
submit_flag.change(
handle_submit,
inputs=[],
outputs=[form_section]
)
# メイン画面セクション
with gr.Column(visible=False) as main_section:
# interface
submit = None
with gr.Row():
with gr.Column() as input_col:
input_image = gr.Image(type="pil", label="Input Image", height=512)
with gr.Tab("original"):
original_mode = gr.Text("original", label="Mode", visible=False)
original_submit = gr.Button("Submit", variant="primary")
with gr.Tab("refine"):
refine_input = [
gr.Text("refine", label="Mode", visible=False),
gr.Slider(0, 2, value=0.6, step=0.05, label="Weight 1 (Sketch)"),
gr.Slider(0, 1, value=0.05, step=0.025, label="Weight 2 (Body)")
]
refine_submit = gr.Button("Submit", variant="primary")
gr.Examples(
examples=[f"images/sample{i}.png" for i in [1, 2, 4, 5, 6, 7, 10, 16, 18, 19]],
inputs=[input_image]
)
with gr.Column() as output_col:
sotai_image_data = gr.Text(label="Sotai Image data", visible=False)
sketch_image_data = gr.Text(label="Sketch Image data", visible=False)
mixed_image = gr.Image(label="Output Image", elem_id="output_image")
opacity_slider1 = gr.Slider(0, 1, value=0.5, step=0.05, label="Opacity (Sotai)")
opacity_slider2 = gr.Slider(0, 1, value=0.5, step=0.05, label="Opacity (Sketch)")
# post_button = gr.Button("Post to X(Twitter)", variant="secondary")
# post_button.click(
# post_to_twitter,
# inputs=[mixed_image],
# outputs=None
# )
original_submit.click(
process_image,
inputs=[input_image, original_mode],
outputs=[sotai_image_data, sketch_image_data, mixed_image]
)
refine_submit.click(
process_image,
inputs=[input_image, refine_input[0], refine_input[1], refine_input[2]],
outputs=[sotai_image_data, sketch_image_data, mixed_image]
)
sotai_image_data.change(
mix_images,
inputs=[sotai_image_data, sketch_image_data, opacity_slider1, opacity_slider2],
outputs=mixed_image
)
opacity_slider1.change(
mix_images,
inputs=[sotai_image_data, sketch_image_data, opacity_slider1, opacity_slider2],
outputs=mixed_image
)
opacity_slider2.change(
mix_images,
inputs=[sotai_image_data, sketch_image_data, opacity_slider1, opacity_slider2],
outputs=mixed_image
)
# フラグ変更時に画面切り替え
form_visible_flag.change(
handle_form_submission,
inputs=[form_visible_flag],
outputs=[survey_section, main_section]
)
# 選択肢に応じてセクションを切り替え
visit_choice.change(
handle_visit_choice,
inputs=[visit_choice, language_choice],
outputs=[visit_section, survey_section, proceed_section]
)
# 進むボタン押下時の画面遷移
proceed_button.click(
handle_proceed,
inputs=[],
outputs=[proceed_section, main_section]
)
# JavaScriptの読み込み
demo.load(None, None, None, js="""
() => {
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 });
}
""")
demo.launch()
|