Skip to content

Commit 3073669

Browse files
committed
feat(icons): orphan-icon sweep — patch stale OWUI rows not in current pipes() catalog
OWUI never cleans up its model table after a provider deprecates a model — the row stays with the default placeholder icon (or the old /static/favicon.png) because the existing _sync_model_icons() only iterates the current pipes() output. Six active models on the live deployment (baidu/ernie-4.5-21b-a3b, alfredpros/codellama-7b-instruct-solidity, minimax/minimax-m2.5:free, upstage/solar-pro-3, baidu/qianfan-ocr-fast, baidu/ernie-4.5-21b-a3b-thinking) were stuck like this. New _sync_orphan_db_icons() runs right after _sync_model_icons() and walks every active openrouter_pipe.* row in the model table. For each row whose icon is OWUI-managed (data:, /static/, our CDN list, etc.) it computes the right icon via _get_provider_icon() — same fallback chain as the regular sync — and patches the meta. User-set custom icons stay untouched. Uses Models.get_all_models() (returns ModelModel with is_active/meta/ params; the trimmed-down get_models() variant lacks is_active).
1 parent 908726d commit 3073669

1 file changed

Lines changed: 79 additions & 0 deletions

File tree

openrouter_pipe.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,6 +1345,11 @@ def pipes(self) -> List[dict]:
13451345
# Sync provider icons into Open WebUI's Models database
13461346
if self.valves.SYNC_PROVIDER_ICONS:
13471347
self._sync_model_icons(models)
1348+
# ALSO patch icons for active OWUI model rows whose ID has our
1349+
# manifold prefix but no longer appears in the current catalog
1350+
# (deprecated / withdrawn models OWUI didn't auto-clean). They
1351+
# otherwise stay on the OWUI default placeholder forever.
1352+
self._sync_orphan_db_icons()
13481353

13491354
return models
13501355

@@ -1566,6 +1571,80 @@ async def _wrap_stream():
15661571

15671572
return result
15681573

1574+
def _sync_orphan_db_icons(self) -> None:
1575+
"""Patch icons for active OWUI model rows whose ID has our manifold
1576+
prefix but no longer appears in the current pipes() catalog.
1577+
1578+
These are typically deprecated / withdrawn models that OpenRouter
1579+
removed from /models but OWUI never cleaned up — they still appear
1580+
in the user's model selector and otherwise stick to OWUI's default
1581+
placeholder icon forever because the regular per-catalog sync only
1582+
iterates the current pipes() output.
1583+
1584+
Reuses ``_get_provider_icon`` so the same fallback chain (registry
1585+
→ hardcoded → alias → domain favicon → letter-SVG) applies, and
1586+
``_is_owui_managed_icon`` so user-set custom icons are preserved.
1587+
"""
1588+
try:
1589+
from open_webui.models.models import (
1590+
ModelForm,
1591+
ModelMeta,
1592+
ModelParams,
1593+
Models,
1594+
)
1595+
except ImportError:
1596+
return
1597+
if not self._function_id:
1598+
return
1599+
function_id = self._function_id
1600+
# Iterate all active models in OWUI's DB that carry our manifold
1601+
# prefix. ``list_models`` returns ``ModelModel`` objects with
1602+
# ``id``, ``name``, ``meta``, ``params``, ``is_active`` attributes.
1603+
try:
1604+
all_rows = self._resolve_maybe_awaitable(Models.get_all_models())
1605+
except Exception as exc:
1606+
print(f"[OpenRouter Pipe] Orphan-icon sweep: list failed: {exc}")
1607+
return
1608+
prefix = f"{function_id}."
1609+
for row in all_rows or []:
1610+
db_model_id = getattr(row, "id", "") or ""
1611+
if not db_model_id.startswith(prefix):
1612+
continue
1613+
# Active filter when present; default True for older OWUI.
1614+
if hasattr(row, "is_active") and row.is_active is False:
1615+
continue
1616+
# Skip rows that the regular sync already handled this pass.
1617+
clean_id = db_model_id[len(prefix):]
1618+
if clean_id in self._icons_synced:
1619+
continue
1620+
existing_icon = ""
1621+
if hasattr(row, "meta") and row.meta:
1622+
existing_icon = getattr(row.meta, "profile_image_url", "") or ""
1623+
if existing_icon and not _is_owui_managed_icon(existing_icon):
1624+
continue
1625+
# Provider key derivation mirrors the regular sync path.
1626+
parts = clean_id.split("/", 1)
1627+
provider_key = parts[0].lstrip("~").lower() if len(parts) > 1 else ""
1628+
icon_url = self._get_provider_icon(provider_key)
1629+
if not icon_url or icon_url == existing_icon:
1630+
continue
1631+
try:
1632+
existing_params = ModelParams()
1633+
if hasattr(row, "params") and row.params:
1634+
existing_params = row.params
1635+
self._resolve_maybe_awaitable(Models.update_model_by_id(
1636+
db_model_id,
1637+
ModelForm(
1638+
id=db_model_id,
1639+
name=getattr(row, "name", "") or clean_id,
1640+
meta=ModelMeta(profile_image_url=icon_url),
1641+
params=existing_params,
1642+
),
1643+
))
1644+
self._icons_synced.add(clean_id)
1645+
except Exception as exc:
1646+
print(f"[OpenRouter Pipe] Orphan-icon update failed for {db_model_id}: {exc}")
1647+
15691648
@staticmethod
15701649
def _resolve_maybe_awaitable(value):
15711650
"""Resolve a value that may be an awaitable from OWUI's DB layer.

0 commit comments

Comments
 (0)