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 = """

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

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

""" from dotenv import load_dotenv load_dotenv() # 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) with gr.Blocks() as demo: form_visible_flag = gr.Textbox(value="false", elem_id="form_flag", visible=False) # title gr.HTML("

Image2Body demo

") # description with translations and additional notes gr.HTML("""

Upload an image and select processing options to generate body and sketch images.

まだstandingタグのついた女性キャラクターの1000枚の画像しか学習していないため、他のポーズは上手くできないことをご了承ください。

さらなる情報は@Yeq6Xまでお問い合わせください。

Note: Currently, the model has been trained on only 1000 images of female characters with the 'standing' tag, so other poses may not be processed accurately.

For more information, please contact @Yeq6X.

注意:目前模型仅使用带有“standing”标签的1000张女性角色图像进行训练,因此其他姿势可能无法准确处理。

如需更多信息,请联系@Yeq6X

""") # 訪問回数の選択 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("

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

") # 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()