AIタレント専門の事務所 ~ AIタレントエージェンシーでタレント募集中

mov2movのタブがない!すぐ直る解決策2つ紹介します

mov2movのタブが表示されない場合の解決策

ちゃんとインストールは完了しているはずなのにmov2movのタブがない…

mov2movのタブが表示されない画面

何が起きているのか?

コンソールに以下のようなエラーが出ています。modules.uiにcreate_sampler_and_steps_selectionがないのにimportしようとしているのが原因みたいですね。

2024-04-18 23:16:15,907 - ControlNet - INFO - ControlNet v1.1.422
*** Error loading script: m2m_ui.py
    Traceback (most recent call last):
      File "C:\Users\Astromeda\StableDiffusion\webui\webui\modules\scripts.py", line 508, in load_scripts
        script_module = script_loading.load_module(scriptfile.path)
      File "C:\Users\Astromeda\StableDiffusion\webui\webui\modules\script_loading.py", line 14, in load_module
        module_spec.loader.exec_module(module)
      File "<frozen importlib._bootstrap_external>", line 883, in exec_module
      File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
      File "C:\Users\Astromeda\StableDiffusion\webui\webui\extensions\sd-webui-mov2mov\scripts\m2m_ui.py", line 23, in <module>
        from modules.ui import (
    ImportError: cannot import name 'create_sampler_and_steps_selection' from 'modules.ui' (C:\Users\Astromeda\StableDiffusion\webui\webui\modules\ui.py)

解決策2つ

このためだけにStable Diffusionのバージョンを変えるのは微妙なので、m2m_ui.pyのファイルを編集するのがおすすめです。

Stable Diffusionのバージョンを1.7.0に戻す

Stable Diffusion Web UI 1.9.0以降でこのエラーが生じているようですので、Stable Diffusionを1.7.0に戻すのが一つの策です。
以下を参考にStable Diffusion WebUIのバージョンを下げてみてください。

m2m_ui.pyのファイルを編集する

原因のm2m_ui.pyファイル自体を書き換えることでもエラーが解消されます。
以下をコピーして、extensions/sd-webui-mov2mov/scripts/m2m_ui.pyを上書きしましょう。
編集後、Stable Diffusionの再起動が必要です。

m2m_ui.pyの編集画面
m2m_ui.py
import importlib
import os
import platform
import shutil
import subprocess as sp
import sys

import gradio as gr

import modules
import modules.scripts as scripts
from modules import (
    script_callbacks,
    shared,
    call_queue,
    sd_samplers,
    ui_prompt_styles,
    sd_models,
)
from modules.call_queue import wrap_gradio_gpu_call
from modules.images import image_data
from modules.shared import opts
from modules.ui import (
    ordered_ui_categories,
    #create_sampler_and_steps_selection,
    switch_values_symbol,
    create_override_settings_dropdown,
    detect_image_size_symbol,
    plaintext_to_html,
    paste_symbol,
    clear_prompt_symbol,
    restore_progress_symbol,
)
from modules.ui_common import (
    folder_symbol,
    update_generation_info,
    create_refresh_button,
)
from modules.ui_components import (
    ResizeHandleRow,
    FormRow,
    ToolButton,
    FormGroup,
    InputAccordion,
)
from scripts import m2m_hook as patches
from scripts import m2m_util
from scripts import mov2mov
from scripts.mov2mov import scripts_mov2mov
from scripts.m2m_config import mov2mov_outpath_samples, mov2mov_output_dir
from scripts.movie_editor import MovieEditor

id_part = "mov2mov"


def save_video(video):
    path = "logs/movies"
    if not os.path.exists(path):
        os.makedirs(path, exist_ok=True)
    index = len([path for path in os.listdir(path) if path.endswith(".mp4")]) + 1
    video_path = os.path.join(path, str(index).zfill(5) + ".mp4")
    shutil.copyfile(video, video_path)
    filename = os.path.relpath(video_path, path)
    return gr.File.update(value=video_path, visible=True), plaintext_to_html(
        f"Saved: {filename}"
    )


class Toprow:
    """Creates a top row UI with prompts, generate button, styles, extra little buttons for things, and enables some functionality related to their operation"""

    def __init__(self, is_img2img, id_part=None):
        if not id_part:
            id_part = "img2img" if is_img2img else "txt2img"
        self.id_part = id_part

        with gr.Row(elem_id=f"{id_part}_toprow", variant="compact"):
            with gr.Column(elem_id=f"{id_part}_prompt_container", scale=6):
                with gr.Row():
                    with gr.Column(scale=80):
                        with gr.Row():
                            self.prompt = gr.Textbox(
                                label="Prompt",
                                elem_id=f"{id_part}_prompt",
                                show_label=False,
                                lines=3,
                                placeholder="Prompt (press Ctrl+Enter or Alt+Enter to generate)",
                                elem_classes=["prompt"],
                            )
                            self.prompt_img = gr.File(
                                label="",
                                elem_id=f"{id_part}_prompt_image",
                                file_count="single",
                                type="binary",
                                visible=False,
                            )

                with gr.Row():
                    with gr.Column(scale=80):
                        with gr.Row():
                            self.negative_prompt = gr.Textbox(
                                label="Negative prompt",
                                elem_id=f"{id_part}_neg_prompt",
                                show_label=False,
                                lines=3,
                                placeholder="Negative prompt (press Ctrl+Enter or Alt+Enter to generate)",
                                elem_classes=["prompt"],
                            )

            self.button_interrogate = None
            self.button_deepbooru = None
            if is_img2img:
                with gr.Column(scale=1, elem_classes="interrogate-col"):
                    self.button_interrogate = gr.Button(
                        "Interrogate\nCLIP", elem_id="interrogate"
                    )
                    self.button_deepbooru = gr.Button(
                        "Interrogate\nDeepBooru", elem_id="deepbooru"
                    )

            with gr.Column(scale=1, elem_id=f"{id_part}_actions_column"):
                with gr.Row(
                    elem_id=f"{id_part}_generate_box", elem_classes="generate-box"
                ):
                    self.interrupt = gr.Button(
                        "Interrupt",
                        elem_id=f"{id_part}_interrupt",
                        elem_classes="generate-box-interrupt",
                    )
                    self.interrupting = gr.Button(
                        "Interrupting...",
                        elem_id=f"{id_part}_interrupting",
                        elem_classes="generate-box-interrupting", 
                        tooltip="Interrupting generation..."
                    )
                    self.skip = gr.Button(
                        "Skip",
                        elem_id=f"{id_part}_skip",
                        elem_classes="generate-box-skip",
                    )
                    self.submit = gr.Button(
                        "Generate", elem_id=f"{id_part}_generate", variant="primary"
                    )

                    self.skip.click(
                        fn=lambda: shared.state.skip(),
                        inputs=[],
                        outputs=[],
                    )

                    self.interrupt.click(
                        fn=lambda: shared.state.interrupt(),
                        inputs=[],
                        outputs=[],
                    )

                    self.interrupting.click(
                        fn=lambda: shared.state.interrupt(),
                        inputs=[],
                        outputs=[],
                    )

                with gr.Row(elem_id=f"{id_part}_tools"):
                    self.paste = ToolButton(value=paste_symbol, elem_id="paste")

                    self.clear_prompt_button = ToolButton(
                        value=clear_prompt_symbol, elem_id=f"{id_part}_clear_prompt"
                    )
                    self.restore_progress_button = ToolButton(
                        value=restore_progress_symbol,
                        elem_id=f"{id_part}_restore_progress",
                        visible=False,
                    )

                    self.token_counter = gr.HTML(
                        value="<span>0/75</span>",
                        elem_id=f"{id_part}_token_counter",
                        elem_classes=["token-counter"],
                    )
                    self.token_button = gr.Button(
                        visible=False, elem_id=f"{id_part}_token_button"
                    )
                    self.negative_token_counter = gr.HTML(
                        value="<span>0/75</span>",
                        elem_id=f"{id_part}_negative_token_counter",
                        elem_classes=["token-counter"],
                    )
                    self.negative_token_button = gr.Button(
                        visible=False, elem_id=f"{id_part}_negative_token_button"
                    )

                    self.clear_prompt_button.click(
                        fn=lambda *x: x,
                        _js="confirm_clear_prompt",
                        inputs=[self.prompt, self.negative_prompt],
                        outputs=[self.prompt, self.negative_prompt],
                    )

                self.ui_styles = ui_prompt_styles.UiPromptStyles(
                    id_part, self.prompt, self.negative_prompt
                )

        self.prompt_img.change(
            fn=modules.images.image_data,
            inputs=[self.prompt_img],
            outputs=[self.prompt, self.prompt_img],
            show_progress=False,
        )


def create_output_panel(tabname, outdir):
    def open_folder(f):
        if not os.path.exists(f):
            print(
                f'Folder "{f}" does not exist. After you create an image, the folder will be created.'
            )
            return
        elif not os.path.isdir(f):
            print(
                f"""
WARNING
An open_folder request was made with an argument that is not a folder.
This could be an error or a malicious attempt to run code on your computer.
Requested path was: {f}
""",
                file=sys.stderr,
            )
            return

        if not shared.cmd_opts.hide_ui_dir_config:
            path = os.path.normpath(f)
            if platform.system() == "Windows":
                os.startfile(path)
            elif platform.system() == "Darwin":
                sp.Popen(["open", path])
            elif "microsoft-standard-WSL2" in platform.uname().release:
                sp.Popen(["wsl-open", path])
            else:
                sp.Popen(["xdg-open", path])

    with gr.Column(variant="panel", elem_id=f"{tabname}_results"):
        with gr.Group(elem_id=f"{tabname}_gallery_container"):
            result_gallery = gr.Gallery(
                label="Output",
                show_label=False,
                elem_id=f"{tabname}_gallery",
                columns=4,
                preview=True,
                height=shared.opts.gallery_height or None,
            )
            result_video = gr.PlayableVideo(
                label="Output Video", show_label=False, elem_id=f"{tabname}_video"
            )

        generation_info = None
        with gr.Column():
            with gr.Row(
                elem_id=f"image_buttons_{tabname}", elem_classes="image-buttons"
            ):
                open_folder_button = ToolButton(
                    folder_symbol,
                    elem_id=f"{tabname}_open_folder",
                    visible=not shared.cmd_opts.hide_ui_dir_config,
                    tooltip="Open images output directory.",
                )

                if tabname != "extras":
                    save = ToolButton(
                        "💾",
                        elem_id=f"save_{tabname}",
                        tooltip=f"Save the image to a dedicated directory ({shared.opts.outdir_save}).",
                    )

            open_folder_button.click(
                fn=lambda: open_folder(shared.opts.outdir_samples or outdir),
                inputs=[],
                outputs=[],
            )

            download_files = gr.File(
                None,
                file_count="multiple",
                interactive=False,
                show_label=False,
                visible=False,
                elem_id=f"download_files_{tabname}",
            )

            with gr.Group():
                html_info = gr.HTML(
                    elem_id=f"html_info_{tabname}", elem_classes="infotext"
                )
                html_log = gr.HTML(
                    elem_id=f"html_log_{tabname}", elem_classes="html-log"
                )

                generation_info = gr.Textbox(
                    visible=False, elem_id=f"generation_info_{tabname}"
                )
                if tabname == "txt2img" or tabname == "img2img" or tabname == "mov2mov":
                    generation_info_button = gr.Button(
                        visible=False, elem_id=f"{tabname}_generation_info_button"
                    )
                    generation_info_button.click(
                        fn=update_generation_info,
                        _js="function(x, y, z){ return [x, y, selected_gallery_index()] }",
                        inputs=[generation_info, html_info, html_info],
                        outputs=[html_info, html_info],
                        show_progress=False,
                    )

                save.click(
                    fn=call_queue.wrap_gradio_call(save_video),
                    inputs=[result_video],
                    outputs=[
                        download_files,
                        html_log,
                    ],
                    show_progress=False,
                )

            return result_gallery, result_video, generation_info, html_info, html_log


def create_refiner():
    with InputAccordion(
        False, label="Refiner", elem_id=f"{id_part}_enable"
    ) as enable_refiner:
        with gr.Row():
            refiner_checkpoint = gr.Dropdown(
                label="Checkpoint",
                elem_id=f"{id_part}_checkpoint",
                choices=sd_models.checkpoint_tiles(),
                value="",
                tooltip="switch to another model in the middle of generation",
            )
            create_refresh_button(
                refiner_checkpoint,
                sd_models.list_models,
                lambda: {"choices": sd_models.checkpoint_tiles()},
                f"{id_part}_checkpoint_refresh",
            )

            refiner_switch_at = gr.Slider(
                value=0.8,
                label="Switch at",
                minimum=0.01,
                maximum=1.0,
                step=0.01,
                elem_id=f"{id_part}_switch_at",
                tooltip="fraction of sampling steps when the switch to refiner model should happen; 1=never, 0.5=switch in the middle of generation",
            )
    return enable_refiner, refiner_checkpoint, refiner_switch_at


def create_sampler_and_steps_selection(choices, tabname):
    return scripts.scripts_txt2img.script('Sampler').steps, scripts.scripts_txt2img.script('Sampler').sampler_name

def on_ui_tabs():
    scripts_mov2mov.initialize_scripts(is_img2img=True)

    # with gr.Blocks(analytics_enabled=False) as mov2mov_interface:
    with gr.TabItem(
        "mov2mov", id=f"tab_{id_part}", elem_id=f"tab_{id_part}"
    ) as mov2mov_interface:
        toprow = Toprow(is_img2img=False, id_part=id_part)
        dummy_component = gr.Label(visible=False)
        with gr.Tab(
            "Generation", id=f"{id_part}_generation"
        ) as mov2mov_generation_tab, ResizeHandleRow(equal_height=False):
            with gr.Column(variant="compact", elem_id="mov2mov_settings"):
                with gr.Tabs(elem_id=f"mode_{id_part}"):
                    init_mov = gr.Video(
                        label="Video for mov2mov",
                        elem_id=f"{id_part}_mov",
                        show_label=False,
                        source="upload",
                    )

                with FormRow():
                    resize_mode = gr.Radio(
                        label="Resize mode",
                        elem_id=f"{id_part}_resize_mode",
                        choices=[
                            "Just resize",
                            "Crop and resize",
                            "Resize and fill",
                            "Just resize (latent upscale)",
                        ],
                        type="index",
                        value="Just resize",
                    )
                scripts_mov2mov.prepare_ui()

                for category in ordered_ui_categories():
                    if category == "sampler":
                        steps, sampler_name = create_sampler_and_steps_selection(
                            sd_samplers.visible_sampler_names(), id_part
                        )
                    elif category == "dimensions":
                        with FormRow():
                            with gr.Column(elem_id=f"{id_part}_column_size", scale=4):
                                with gr.Tabs():
                                    with gr.Tab(
                                        label="Resize to",
                                        elem_id=f"{id_part}_tab_resize_to",
                                    ) as tab_scale_to:
                                        with FormRow():
                                            with gr.Column(
                                                elem_id=f"{id_part}_column_size",
                                                scale=4,
                                            ):
                                                width = gr.Slider(
                                                    minimum=64,
                                                    maximum=2048,
                                                    step=8,
                                                    label="Width",
                                                    value=512,
                                                    elem_id=f"{id_part}_width",
                                                )
                                                height = gr.Slider(
                                                    minimum=64,
                                                    maximum=2048,
                                                    step=8,
                                                    label="Height",
                                                    value=512,
                                                    elem_id=f"{id_part}_height",
                                                )
                                            with gr.Column(
                                                elem_id=f"{id_part}_dimensions_row",
                                                scale=1,
                                                elem_classes="dimensions-tools",
                                            ):
                                                res_switch_btn = ToolButton(
                                                    value=switch_values_symbol,
                                                    elem_id=f"{id_part}_res_switch_btn",
                                                )
                                                detect_image_size_btn = ToolButton(
                                                    value=detect_image_size_symbol,
                                                    elem_id=f"{id_part}_detect_image_size_btn",
                                                )
                    elif category == "denoising":
                        denoising_strength = gr.Slider(
                            minimum=0.0,
                            maximum=1.0,
                            step=0.01,
                            label="Denoising strength",
                            value=0.75,
                            elem_id=f"{id_part}_denoising_strength",
                        )

                        noise_multiplier = gr.Slider(
                            minimum=0,
                            maximum=1.5,
                            step=0.01,
                            label="Noise multiplier",
                            elem_id=f"{id_part}_noise_multiplier",
                            value=1,
                        )
                        with gr.Row(elem_id=f"{id_part}_frames_setting"):
                            movie_frames = gr.Slider(
                                minimum=10,
                                maximum=60,
                                step=1,
                                label="Movie FPS",
                                elem_id=f"{id_part}_movie_frames",
                                value=30,
                            )
                            max_frames = gr.Number(
                                label="Max FPS",
                                value=-1,
                                elem_id=f"{id_part}_max_frames",
                            )

                    elif category == "cfg":
                        with gr.Row():
                            cfg_scale = gr.Slider(
                                minimum=1.0,
                                maximum=30.0,
                                step=0.5,
                                label="CFG Scale",
                                value=7.0,
                                elem_id=f"{id_part}_cfg_scale",
                            )
                            image_cfg_scale = gr.Slider(
                                minimum=0,
                                maximum=3.0,
                                step=0.05,
                                label="Image CFG Scale",
                                value=1.5,
                                elem_id=f"{id_part}_image_cfg_scale",
                                visible=False,
                            )

                    elif category == "checkboxes":
                        with FormRow(elem_classes="checkboxes-row", variant="compact"):
                            pass

                    elif category == "accordions":
                        with gr.Row(
                            elem_id=f"{id_part}_accordions", elem_classes="accordions"
                        ):
                            scripts_mov2mov.setup_ui_for_section(category)

                    elif category == "override_settings":
                        with FormRow(elem_id=f"{id_part}_override_settings_row") as row:
                            override_settings = create_override_settings_dropdown(
                                "mov2mov", row
                            )

                    elif category == "scripts":
                        editor = MovieEditor(id_part, init_mov, movie_frames)
                        editor.render()
                        with FormGroup(elem_id=f"{id_part}_script_container"):
                            custom_inputs = scripts_mov2mov.setup_ui()

                    if category not in {"accordions"}:
                        scripts_mov2mov.setup_ui_for_section(category)

            (
                mov2mov_gallery,
                result_video,
                generation_info,
                html_info,
                html_log,
            ) = create_output_panel(id_part, opts.mov2mov_output_dir)

            res_switch_btn.click(
                fn=None,
                _js="function(){switchWidthHeight('mov2mov')}",
                inputs=None,
                outputs=None,
                show_progress=False,
            )

            # calc video size
            detect_image_size_btn.click(
                fn=calc_video_w_h,
                inputs=[init_mov, width, height],
                outputs=[width, height],
            )

            mov2mov_args = dict(
                fn=wrap_gradio_gpu_call(mov2mov.mov2mov, extra_outputs=[None, "", ""]),
                _js="submit_mov2mov",
                inputs=[
                    dummy_component,
                    toprow.prompt,
                    toprow.negative_prompt,
                    toprow.ui_styles.dropdown,
                    init_mov,
                    steps,
                    sampler_name,
                    cfg_scale,
                    image_cfg_scale,
                    denoising_strength,
                    height,
                    width,
                    resize_mode,
                    override_settings,
                    # refiner
                    # enable_refiner, refiner_checkpoint, refiner_switch_at,
                    # mov2mov params
                    noise_multiplier,
                    movie_frames,
                    max_frames,
                    # editor
                    editor.gr_enable_movie_editor,
                    editor.gr_df,
                    editor.gr_eb_weight,
                ]
                + custom_inputs,
                outputs=[
                    result_video,
                    generation_info,
                    html_info,
                    html_log,
                ],
                show_progress=False,
            )

            toprow.submit.click(**mov2mov_args)

    return [(mov2mov_interface, "mov2mov", f"{id_part}_tabs")]


def calc_video_w_h(video, width, height):
    if not video:
        return width, height

    return m2m_util.calc_video_w_h(video)


def on_ui_settings():
    section = ("mov2mov", "Mov2Mov")
    shared.opts.add_option(
        "mov2mov_outpath_samples",
        shared.OptionInfo(
            mov2mov_outpath_samples, "Mov2Mov output path for image", section=section
        ),
    )
    shared.opts.add_option(
        "mov2mov_output_dir",
        shared.OptionInfo(
            mov2mov_output_dir, "Mov2Mov output path for video", section=section
        ),
    )


img2img_toprow: gr.Row = None


def block_context_init(self, *args, **kwargs):
    origin_block_context_init(self, *args, **kwargs)

    if self.elem_id == "tab_img2img":
        self.parent.__enter__()
        on_ui_tabs()
        self.parent.__exit__()


def on_app_reload():
    global origin_block_context_init
    if origin_block_context_init:
        patches.undo(__name__, obj=gr.blocks.BlockContext, field="__init__")
        origin_block_context_init = None


origin_block_context_init = patches.patch(
    __name__,
    obj=gr.blocks.BlockContext,
    field="__init__",
    replacement=block_context_init,
)
script_callbacks.on_before_reload(on_app_reload)
script_callbacks.on_ui_settings(on_ui_settings)
# script_callbacks.on_ui_tabs(on_ui_tabs)