home · contact · privacy
Browser: Split prompt into two ellipsized subprompts. master
authorChristian Heller <c.heller@plomlompom.de>
Thu, 14 Nov 2024 14:28:37 +0000 (15:28 +0100)
committerChristian Heller <c.heller@plomlompom.de>
Thu, 14 Nov 2024 14:28:37 +0000 (15:28 +0100)
browser.py

index 89eabadfa7c5b80b14c2405b36c5909e122a82f3..f6ff73de4cb0a5e547a144a99cb5ebf8e3e89b1e 100755 (executable)
@@ -25,7 +25,6 @@ from stable.gen_params import (GenParams,  GEN_PARAMS_FLOAT,  # noqa: E402
                                GEN_PARAMS_INT, GEN_PARAMS_STR,  # noqa: E402
                                GEN_PARAMS)  # noqa: E402
 
-PromptsDiff = dict[str, str]
 BasicItemsAttrs = dict[str, set[str]]
 AttrVals: TypeAlias = list[str]
 AttrValsByVisibility: TypeAlias = dict[str, AttrVals]
@@ -388,6 +387,8 @@ class ImgItem(GalleryItem):
 
     def __init__(self, path: str, name: str, cache: Cache) -> None:
         super().__init__(path, name)
+        self.subprompt1: str = ''
+        self.subprompt2: str = ''
         mtime = getmtime(self.full_path)
         dt = datetime.fromtimestamp(mtime, tz=timezone.utc)
         iso8601_str: str = dt.isoformat(timespec='microseconds')
@@ -746,7 +747,6 @@ class Gallery:
         self.items_attrs: ItemsAttrs = {}
         self.selected_idx = 0
         self.slots: list[GallerySlot] = []
-        self._prompts_diff: PromptsDiff = {}
 
         self._grid = Gtk.Grid()
         self._force_width, self._force_height = 0, 0
@@ -814,63 +814,65 @@ class Gallery:
                 else:
                     self.request_update(build_grid=True)
 
-    def _prep_items_attrs(self,
-                          entries: list[GalleryItem]
-                          ) -> tuple[BasicItemsAttrs, PromptsDiff]:
-
-        def diff_prompts(basic_items_attrs: BasicItemsAttrs) -> PromptsDiff:
-            if 'prompt' not in basic_items_attrs:
-                return {}
-            prompts_diff: PromptsDiff = {}
-            prompts = list(basic_items_attrs['prompt'])
-
-            def find_longest_equal(prompts, j, matcher):
-                longest_total, temp_longest = '', ''
-                while j < len(prompts[0]):
-                    if 'end' == matcher:
-                        temp_longest = prompts[0][-j] + temp_longest
-                    else:
-                        temp_longest += prompts[0][j]
-                    if len(temp_longest) > len(longest_total):
-                        found_in_all = True
-                        for prompt in prompts[1:]:
-                            if ('start' == matcher
-                                and not prompt.startswith(temp_longest)) or\
-                                    ('end' == matcher
-                                     and not prompt.endswith(temp_longest)) or\
-                                    ('in' == matcher
-                                     and temp_longest not in prompt):
-                                found_in_all = False
-                                break
-                        if not found_in_all:
-                            break
-                        longest_total = temp_longest
-                    j += 1
-                return longest_total
-
-            prefix = find_longest_equal(prompts, 0, 'start')
-            suffix = find_longest_equal(prompts, 1, matcher='end')
-            cores = [p[len(prefix):] for p in prompts]
-            if suffix:
-                for i, p in enumerate(cores):
-                    cores[i] = p[:-len(suffix)]
-            longest_total = ''
-            for i in range(len(cores[0])):
-                temp_longest = find_longest_equal(cores, j=i, matcher='in')
+    @staticmethod
+    def _diff_prompts(prompts: list[str]) -> dict[str, tuple[str, str]]:
+        if not prompts:
+            return {}
+
+        def find_longest_equal(prompts, j, matcher):
+            longest_total, temp_longest = '', ''
+            while j < len(prompts[0]):
+                if 'end' == matcher:
+                    temp_longest = prompts[0][-j] + temp_longest
+                else:
+                    temp_longest += prompts[0][j]
                 if len(temp_longest) > len(longest_total):
+                    found_in_all = True
+                    for prompt in prompts[1:]:
+                        if ('start' == matcher
+                            and not prompt.startswith(temp_longest)) or\
+                                ('end' == matcher
+                                 and not prompt.endswith(temp_longest)) or\
+                                ('in' == matcher
+                                 and temp_longest not in prompt):
+                            found_in_all = False
+                            break
+                    if not found_in_all:
+                        break
                     longest_total = temp_longest
-            middle = longest_total
-            for i, p in enumerate(prompts):
-                remains = p[len(prefix):]
-                idx_middle = remains.index(middle)
-                second = remains[:idx_middle]
-                remains = remains[idx_middle + len(middle):]
-                first = remains[:-len(suffix)] if suffix else remains
-                pre_ell = '…' if prefix else ''
-                post_ell = '…' if suffix else ''
-                prompts_diff[p] = f'{pre_ell}{first}…{second}{post_ell}'
-            return prompts_diff
-
+                j += 1
+            return longest_total
+
+        prefix = find_longest_equal(prompts, 0, 'start')
+        suffix = find_longest_equal(prompts, 1, matcher='end')
+        cores = [p[len(prefix):] for p in prompts]
+        if suffix:
+            for i, p in enumerate(cores):
+                cores[i] = p[:-len(suffix)]
+        longest_total = ''
+        for i in range(len(cores[0])):
+            temp_longest = find_longest_equal(cores, j=i, matcher='in')
+            if len(temp_longest) > len(longest_total):
+                longest_total = temp_longest
+        middle = longest_total
+        prompts_diff = {}
+        for i, p in enumerate(prompts):
+            remains = p[len(prefix):] if prefix else p
+            idx_middle = remains.index(middle)
+            first = remains[:idx_middle] if idx_middle else ''
+            remains = remains[idx_middle + len(middle):]
+            second = remains[:-len(suffix)] if suffix else remains
+            if first:
+                first = f'…{first}' if prefix else first
+                first = f'{first}…' if suffix or middle else first
+            if second:
+                second = f'…{second}' if prefix or middle else second
+                second = f'{second}…' if suffix else second
+            prompts_diff[p] = (first if first else '…',
+                               second if second else '…')
+        return prompts_diff
+
+    def _prep_items_attrs(self, entries: list[GalleryItem]) -> BasicItemsAttrs:
         basic_items_attrs = {}
         for attr_name in (s.name for s in self._sort_order):
             vals: set[str] = set()
@@ -880,8 +882,7 @@ class Gallery:
                 if val is not None:
                     vals.add(val)
             basic_items_attrs[attr_name] = vals
-        prompts_diff = diff_prompts(basic_items_attrs)
-        return basic_items_attrs, prompts_diff
+        return basic_items_attrs
 
     def _load_directory(self) -> None:
         """(Re-)build .dir_entries from ._img_dir_path, ._basic_items_attrs."""
@@ -928,8 +929,19 @@ class Gallery:
                     read_directory(path)
 
         read_directory(self._img_dir_path, make_parent=True)
-        self._basic_items_attrs, self._prompts_diff = self._prep_items_attrs(
-                self.dir_entries)
+        prompts_set: set[str] = set()
+        for entry in [e for e in self.dir_entries
+                      if isinstance(e, ImgItem) and hasattr(e, 'prompt')]:
+            prompts_set.add(entry.prompt)
+        prompts_diff = self._diff_prompts(list(prompts_set))
+        for entry in [e for e in self.dir_entries if isinstance(e, ImgItem)]:
+            entry.subprompt1 = prompts_diff[entry.prompt][0]
+            entry.subprompt2 = prompts_diff[entry.prompt][1]
+        if self._sort_order.by_name('prompt'):
+            self._sort_order.remove('prompt')
+            self._sort_order._list.append(SorterAndFilterer('subprompt1'))
+            self._sort_order._list.append(SorterAndFilterer('subprompt2'))
+        self._basic_items_attrs = self._prep_items_attrs(self.dir_entries)
         ignorable_attrs = []
         for attr_name, attr_vals in self._basic_items_attrs.items():
             if len(attr_vals) < 2:
@@ -989,7 +1001,7 @@ class Gallery:
 
             items_attrs_tmp_1 = separate_items_attrs(self._basic_items_attrs)
             filtered = filter_entries(items_attrs_tmp_1)
-            reduced_basic_items_attrs = self._prep_items_attrs(filtered)[0]
+            reduced_basic_items_attrs = self._prep_items_attrs(filtered)
             items_attrs_tmp_2 = separate_items_attrs(reduced_basic_items_attrs)
             for attr_name in (s.name for s in self._sort_order):
                 final_values: AttrValsByVisibility = {'incl': [], 'semi': []}
@@ -1040,11 +1052,7 @@ class Gallery:
                 attr_name, attr_values = remaining[0]
                 if 1 == len(remaining):
                     for i, attr in enumerate(ancestors):
-                        parent_attr_name, parent_attr_value = attr
-                        if 'prompt' == parent_attr_name:
-                            parent_attr_value = self\
-                                    ._prompts_diff[parent_attr_value]
-                        txt = f'<b>{parent_attr_name}</b>: {parent_attr_value}'
+                        txt = f'<b>{attr[0]}</b>: {attr[1]}'
                         vlabel = VerticalLabel(txt, self._slots_geometry)
                         self._grid.attach(vlabel, i, i_row_ref[0], 1, 1)
                     row: list[Optional[GalleryItem]]
@@ -1088,8 +1096,6 @@ class Gallery:
                 self._col_headers_grid.attach(Gtk.Box(), 0, 0, 1, 1)
                 top_attr_name: str = sort_attrs[-1][0]
                 for i, val in enumerate(sort_attrs[-1][1]):
-                    if 'prompt' == top_attr_name:
-                        val = self._prompts_diff[val]
                     label = Gtk.Label(label=f'<b>{top_attr_name}</b>: {val}',
                                       xalign=0,
                                       ellipsize=Pango.EllipsizeMode.MIDDLE)