poipoi300 / auto-sd-krita-ext-xl

Fork of auto-sd-paint-ext which is updated to work to the latest (1.7.0) release of A1111 WebUI, therefore allowing you to use SDXL in krita.
MIT License
39 stars 2 forks source link

txt2img and other tabs besides Upscaling doesn't show up #2

Closed rexelbartolome closed 10 months ago

rexelbartolome commented 10 months ago

I've installed SD.Next through StabilityMatrix, basically an SD installation manager. Installed https://github.com/poipoi300/auto-sd-krita-ext-xl in the extensions tab. Relinked/repasted the krita_diff/desktop to the Krita directory. Rechecked if Stable Diffusion plugin is checked in the Python Plugin Manager but the other tabs still don't show up.

These show up when I open Krita. The first one I pasted its entirety, the other two is just screenshot with the end of its log.

TypeError
Python 3.10.7: C:\Program Files\Krita (x64)\bin\krita.exe
Wed Aug 30 22:51:52 2023

A problem occurred in a Python script.  Here is the sequence of
function calls leading up to the error, in the order they occurred.

 C:\Program Files\Krita (x64)\lib\krita-python-libs\krita\dockwidgetfactory.py in createDockWidget(self=<krita.dockwidgetfactory.DockWidgetFactory object>)
   14         super(DockWidgetFactory, self).__init__(_id, _dockPosition)
   15         self.klass = _klass
   16 
   17     def createDockWidget(self):
   18         return self.klass()
self = <krita.dockwidgetfactory.DockWidgetFactory object>
self.klass = <class 'krita_diff.docker.create_docker.<locals>.Docker'>

 C:\Program Files\Krita (x64)\share\krita\pykrita\krita_diff\docker.py in __init__(self=<krita_diff.docker.create_docker.<locals>.Docker object>, *args=(), **kwargs={})
   11             self.setWindowTitle(page.name)
   12             self.create_interface()
   13             self.update_interface()
   14             self.connect_interface()
   15             self.setWidget(self.widget)
self = <krita_diff.docker.create_docker.<locals>.Docker object>
self.update_interface = <bound method create_docker.<locals>.Docker.upda...iff.docker.create_docker.<locals>.Docker object>>

 C:\Program Files\Krita (x64)\share\krita\pykrita\krita_diff\docker.py in update_interface(self=<krita_diff.docker.create_docker.<locals>.Docker object>)
   23 
   24         def update_interface(self):
   25             self.page_widget.cfg_init()
   26 
   27         def connect_interface(self):
self = <krita_diff.docker.create_docker.<locals>.Docker object>
self.page_widget = <krita_diff.pages.txt2img.Txt2ImgPage object>
self.page_widget.cfg_init = <bound method Txt2ImgPage.cfg_init of <krita_diff.pages.txt2img.Txt2ImgPage object>>

 C:\Program Files\Krita (x64)\share\krita\pykrita\krita_diff\pages\txt2img.py in cfg_init(self=<krita_diff.pages.txt2img.Txt2ImgPage object>)
   30 
   31     def cfg_init(self):
   32         super(Txt2ImgPage, self).cfg_init()
   33         self.highres.cfg_init()
   34 
builtinsuper = <class 'super'>
global Txt2ImgPage = <class 'krita_diff.pages.txt2img.Txt2ImgPage'>
self = <krita_diff.pages.txt2img.Txt2ImgPage object>
).cfg_init = <bound method Txt2ImgPage.cfg_init of <krita_diff.pages.txt2img.Txt2ImgPage object>>

 C:\Program Files\Krita (x64)\share\krita\pykrita\krita_diff\pages\img_base.py in cfg_init(self=<krita_diff.pages.txt2img.Txt2ImgPage object>)
   71 
   72     def cfg_init(self):
   73         self.ext_layout.cfg_init()
   74         self.prompt_layout.cfg_init()
   75         self.seed_layout.cfg_init()
self = <krita_diff.pages.txt2img.Txt2ImgPage object>
self.ext_layout = <krita_diff.pages.extension.ExtSectionLayout object>
self.ext_layout.cfg_init = <bound method ExtSectionLayout.cfg_init of <krita_diff.pages.extension.ExtSectionLayout object>>

 C:\Program Files\Krita (x64)\share\krita\pykrita\krita_diff\pages\extension.py in cfg_init(self=<krita_diff.pages.extension.ExtSectionLayout object>)
  118             self._init_ext_widgets()
  119         for widget in self.ext_widgets.values():
  120             widget.cfg_init()
  121 
  122     def cfg_connect(self):
widget = <krita_diff.pages.extension.ExtWidget object>
widget.cfg_init = <bound method ExtWidget.cfg_init of <krita_diff.pages.extension.ExtWidget object>>

 C:\Program Files\Krita (x64)\share\krita\pykrita\krita_diff\pages\extension.py in cfg_init(self=<krita_diff.pages.extension.ExtWidget object>)
   69     def cfg_init(self):
   70         for w in self.widgets:
   71             w.cfg_init()
   72 
   73     def cfg_connect(self):
w = <krita_diff.widgets.combo_box.QComboBoxLayout object>
w.cfg_init = <bound method QComboBoxLayout.cfg_init of <krita_diff.widgets.combo_box.QComboBoxLayout object>>

 C:\Program Files\Krita (x64)\share\krita\pykrita\krita_diff\widgets\combo_box.py in cfg_init(self=<krita_diff.widgets.combo_box.QComboBoxLayout object>)
   68     def cfg_init(self):
   69         opts = sorted(
   70             set(
   71                 self.cfg(self.options_cfg, "QStringList")
   72                 if isinstance(self.options_cfg, str)
builtinset = <class 'set'>
self = <krita_diff.widgets.combo_box.QComboBoxLayout object>
self.cfg = <krita_diff.config.Config object>
self.options_cfg = [['positive', 'positive'], ['negative', 'negative']]
builtinisinstance = <built-in function isinstance>
builtinstr = <class 'str'>
TypeError: unhashable type: 'list'
    __cause__ = None
    __class__ = <class 'TypeError'>
    __context__ = None
    __delattr__ = <method-wrapper '__delattr__' of TypeError object>
    __dict__ = {}
    __dir__ = <built-in method __dir__ of TypeError object>
    __doc__ = 'Inappropriate argument type.'
    __eq__ = <method-wrapper '__eq__' of TypeError object>
    __format__ = <built-in method __format__ of TypeError object>
    __ge__ = <method-wrapper '__ge__' of TypeError object>
    __getattribute__ = <method-wrapper '__getattribute__' of TypeError object>
    __gt__ = <method-wrapper '__gt__' of TypeError object>
    __hash__ = <method-wrapper '__hash__' of TypeError object>
    __init__ = <method-wrapper '__init__' of TypeError object>
    __init_subclass__ = <built-in method __init_subclass__ of type object>
    __le__ = <method-wrapper '__le__' of TypeError object>
    __lt__ = <method-wrapper '__lt__' of TypeError object>
    __ne__ = <method-wrapper '__ne__' of TypeError object>
    __new__ = <built-in method __new__ of type object>
    __reduce__ = <built-in method __reduce__ of TypeError object>
    __reduce_ex__ = <built-in method __reduce_ex__ of TypeError object>
    __repr__ = <method-wrapper '__repr__' of TypeError object>
    __setattr__ = <method-wrapper '__setattr__' of TypeError object>
    __setstate__ = <built-in method __setstate__ of TypeError object>
    __sizeof__ = <built-in method __sizeof__ of TypeError object>
    __str__ = <method-wrapper '__str__' of TypeError object>
    __subclasshook__ = <built-in method __subclasshook__ of type object>
    __suppress_context__ = False
    __traceback__ = <traceback object>
    args = ("unhashable type: 'list'",)
    with_traceback = <built-in method with_traceback of TypeError object>

The above is a description of an error in a Python program.  Here is
the original traceback:

Traceback (most recent call last):
  File "C:\Program Files\Krita (x64)\lib\krita-python-libs\krita\dockwidgetfactory.py", line 18, in createDockWidget
    return self.klass()
  File "C:\Program Files\Krita (x64)\share\krita\pykrita\krita_diff\docker.py", line 13, in __init__
    self.update_interface()
  File "C:\Program Files\Krita (x64)\share\krita\pykrita\krita_diff\docker.py", line 25, in update_interface
    self.page_widget.cfg_init()
  File "C:\Program Files\Krita (x64)\share\krita\pykrita\krita_diff\pages\txt2img.py", line 32, in cfg_init
    super(Txt2ImgPage, self).cfg_init()
  File "C:\Program Files\Krita (x64)\share\krita\pykrita\krita_diff\pages\img_base.py", line 73, in cfg_init
    self.ext_layout.cfg_init()
  File "C:\Program Files\Krita (x64)\share\krita\pykrita\krita_diff\pages\extension.py", line 120, in cfg_init
    widget.cfg_init()
  File "C:\Program Files\Krita (x64)\share\krita\pykrita\krita_diff\pages\extension.py", line 71, in cfg_init
    w.cfg_init()
  File "C:\Program Files\Krita (x64)\share\krita\pykrita\krita_diff\widgets\combo_box.py", line 70, in cfg_init
    set(
TypeError: unhashable type: 'list'

image image

rexelbartolome commented 10 months ago

upon checking, reverting to auto-sd's krita_diff brought the same krita errors, so it might be because of StabilityMatrix's reinstallation of my Python

poipoi300 commented 10 months ago

Thanks for opening a detailed issue. I think what StabilityMatrix is doing is likely the cause of the problem like you suspect, however fixing it is desirable nonetheless. I will test this myself to see if I can recreate the issue first. I can't give you a time estimate, but considering this is the only issue right now it's the priority haha.

If in the meantime you find a fix, more information, or some update from StabilityMatrix fixes it, please share that here.

rexelbartolome commented 10 months ago

So I reverted back successfully to Interpause/auto-sd + A1111 but not really sure what fixed it. Did lots of things but I think the events that happened before it worked was:

Thought it was a Python issue so I reinstalled/upgraded my Python 3.10.7 to 3.10.11 (which isn't recommended because I think A1111's Python recommends installing 3.10.7) but Krita startup errors still shows up I went back to the auto-sd-guide Installation tab to see how to do a fresh install, after fiddling I found out that turning off Stable Diffusion Plugin in the Python Plugin Manager in the Krita settings then closing Krita, then opening it again, would make the Krita startup errors disappear. Enabling the plugin, then closing, then opening Krita again would make the errors appear again if I remember correctly.

I realized after testing that, I haven't completely closed/terminated both my running A1111 instance and Krita simultaneously. One was always open when I was troubleshooting the other. So I did just that:

I disabled the plugin, closed Krita. Closed A1111. Opened Krita, no errors so far, then enabled the plugin, closed Krita. I opened Krita again, but this time no errors and I think this was the point the tabs showed up again. Opened A1111 and the plugin was working as normal.

So I think it's better to just delete the symlinks or the copy of krita_diff files in the Krita directory at the start OR disable the plugin while updating/replacing the extension. That way the plugin disappears (as well as the errors) from the Python Plugin Manager and you'd have to reenable it again as part of the installation process. Haven't encountered this issue when updating Interpause's before but I rarely updated that anyway (since it always broke w every A1111 update lol)

I'll report back once I have more time to have another go at poipoi300/auto-sd + SD.Next :)

rexelbartolome commented 10 months ago

After a round of troubleshooting again, disabling and enabling doesn't seem to be the one that fixed it.

The three Krita start up errors mainly show up if there's no running instance of SD that it can connect to. Once theres a running SD instance, some errors pop up but the tabs still show up but at first Krita doesn't show the img2img tab. Just restart Krita once again and all the tabs show up fine with no errors popping up.

It seems to consistently show those Krita errors if I use StabilityMatrix, then the tabs don't show up either. It works fine if I use a normal installation of SD.Next though.

ruizray commented 10 months ago

I spent a little time debugging this issue and found a possible cause. It seems that a common field options_cfg takes in either a single string or a list of strings. Somehow in the case of QComboBoxLayoutand QMultiCheckBoxLayout options_cfg sometimes gets set as a list of list of strings (list[list[str],...])

So i just made sure that if options_cfg is a list, we flatten it first. These values get set in the constructor so you can probably move the flattening there to be safer but im not even sure where these parameters get set in the first place so theres definitely an earlier place to do this. But i believe you should be able to get past the errors from there. I'm currently working on merging these fixes with the controlnet version of sd-krita and i dont remember if this fixed all the issues exactly but i think it should.

So in my QComboBoxLayout.init looks like:

 def __init__(
        self,
        cfg: Config,
        options_cfg: list,
        selected_cfg: str,
        label: str = None,
        *args,
        **kwargs
    ):
        """Layout for labelled multi-select CheckBox.

        Args:
            cfg (Config): Config to connect to.
            options_cfg (list): List of options.
            selected_cfg (str): Config key to read/write selected options to.
            label (str, optional): Label, uses `selected_cfg` if None. Defaults to None.
        """
        super(QMultiCheckBoxLayout, self).__init__(*args, **kwargs)

        self.cfg = cfg
        self.options_cfg = options_cfg
        self.selected_cfg = selected_cfg

        self.qlabel = QLabel(self.selected_cfg if label is None else label)

        # TODO: flexbox-like row breaking
        self.row = QHBoxLayout()
        self.qcheckboxes = []
        if isinstance(self.options_cfg, list):
            self.options_cfg = [item for row in self.options_cfg for item in row]
        for opt in self.options_cfg:
            checkbox = _QCheckBox(opt)
            self.qcheckboxes.append(checkbox)
            self.row.addWidget(checkbox)

        self.addWidget(self.qlabel)
        self.addLayout(self.row)

and the start of QMultiCheckBoxLayout.cfg_init looks like:

def cfg_init(self):
        if isinstance(self.options_cfg, list):
            self.options_cfg = [item for row in self.options_cfg for item in row]
poipoi300 commented 10 months ago

Hey thanks for that, that helped me out.

I've currently tracked down the problem further down to frontends/krita/krita_diff/client.py:278-289.

EDIT: Deleting these lines allows krita to open without errors and tabs to show up (scripts are missing options though, of course) but the extension still won't work, maybe because of the new way parameters are sent to the txt2img/img2img modules.

This file is where the frontend queries the backend for config options and sets them in the frontend config. The lines I mentioned are where the frontend sets values for script options like outpainting direction for instance.

Speaking of that, I've found that some of the data is duplicated. Here's a snippet from the json received from the A41 WebUI (I assume it's the raw data, but I would need to investigate more to be certain).

{
        "type": "multiselect",
        "label": "Outpainting direction",
        "val": [
            "left",
            "right",
            "up",
            "down"
        ],
        "is_index": false,
        "opts": [
            [
                "left",
                "left"
            ],
            [
                "right",
                "right"
            ],
            [
                "up",
                "up"
            ],
            [
                "down",
                "down"
            ]
        ]
    }

This is probably where our list of lists is coming from? Currently trying to resolve it there and probing around that area, although this may be all the time I have for today. Will have more tomorrow for sure.

poipoi300 commented 10 months ago

This is now fixed and the implementation should not break with older webUI versions. I also fixed an unrelated bug which would've prevented the extension to work. I'm not sure that I implemented the fix as deep as it could go, but my quick attempt at going a level deeper did not work. I hate the debugging (or lack of) for this.

Feel free to update WebUI to 1.6.0 and the extension using git pull. Release coming tomorrow.