[PR #24173] [CLOSED] feat: auto-assign provider logos to models by id #114845

Closed
opened 2026-05-18 15:41:21 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/open-webui/open-webui/pull/24173
Author: @ikamensh
Created: 4/27/2026
Status: Closed

Base: devHead: feat/auto-provider-logos


📝 Commits (1)

  • ad850f8 feat: auto-assign provider logos to models by id

📊 Changes

19 files changed (+334 additions, -0 deletions)

View changed files

📝 backend/open_webui/routers/models.py (+13 -0)
backend/open_webui/static/providers/LICENSE (+21 -0)
backend/open_webui/static/providers/README.md (+30 -0)
backend/open_webui/static/providers/claude-color.svg (+1 -0)
backend/open_webui/static/providers/cohere-color.svg (+1 -0)
backend/open_webui/static/providers/deepseek-color.svg (+1 -0)
backend/open_webui/static/providers/gemini-color.svg (+1 -0)
backend/open_webui/static/providers/groq.svg (+1 -0)
backend/open_webui/static/providers/meta-color.svg (+1 -0)
backend/open_webui/static/providers/mistral-color.svg (+1 -0)
backend/open_webui/static/providers/moonshot.svg (+1 -0)
backend/open_webui/static/providers/ollama.svg (+1 -0)
backend/open_webui/static/providers/openai.svg (+1 -0)
backend/open_webui/static/providers/perplexity-color.svg (+1 -0)
backend/open_webui/static/providers/qwen-color.svg (+1 -0)
backend/open_webui/static/providers/xai.svg (+1 -0)
backend/open_webui/static/providers/zhipu-color.svg (+1 -0)
backend/open_webui/test/util/test_provider_logos.py (+139 -0)
backend/open_webui/utils/provider_logos.py (+117 -0)

📄 Description

Pull Request Checklist

  • Target branch: Targets dev.
  • Description: See below.
  • Changelog: Entry below.
  • Documentation: No user-facing config; behaviour is automatic. Happy to add a docs PR if maintainers want one (the SVG directory has a README explaining the vendoring/license).
  • Dependencies: No new Python deps. Adds 14 vendored SVG files (~32 KB total) under backend/open_webui/static/providers/ from @lobehub/icons-static-svg (MIT, attribution preserved).
  • Testing: New pytest module with 42 cases (whitelist coverage, host/model precedence, unknown-id fallthrough, asset existence). Manually verified the fallback chain in the route locally.
  • Agentic AI Code: This PR was drafted with AI assistance and then manually reviewed, the regex set was hand-curated, the asset-vendoring tradeoff was made deliberately (see "judgment calls" below), and the test matrix was hand-written to cover real-world id shapes. Please flag anything that looks off and I'll address it.
  • Code review: Self-reviewed; ran ruff check and ruff format on the new files.
  • Design & Architecture: No new settings — the override path (admin-set meta.profile_image_url) keeps full control. The new lookup is a tail fallback, before the existing favicon fallback.
  • Git Hygiene: One atomic commit on feat/auto-provider-logos, rebased on dev.
  • Title Prefix: feat:

Changelog Entry

Description

Today, models supplied by an upstream connection (OpenAI, OpenRouter, Ollama, ...) show the grey OI placeholder unless an admin manually creates a model overlay row with a profile_image_url. With this change, adding gpt-5, anthropic/claude-opus-4, gemini-2.5-pro, deepseek-v3, etc. to a connection's allowed model list shows the right provider logo immediately. Zero config.

The override path is unchanged: an admin-supplied meta.profile_image_url always wins. The regex match runs only when no DB image is set, and before the existing favicon fallback — so unrecognised ids behave exactly like today.

Added

  • Auto-assigned provider logos in GET /api/v1/models/model/profile/image. When the database has no profile_image_url for a model, the route now matches the model id against a small regex table and redirects to a vendored brand SVG.
  • Vendored SVGs under backend/open_webui/static/providers/ (sourced from lobehub/lobe-icons, MIT — LICENSE and attribution README.md included). Covers OpenAI, Anthropic/Claude, Google/Gemini/Gemma, DeepSeek, Qwen, Zhipu/GLM, Mistral, xAI/Grok, Meta/Llama, Cohere, Perplexity, Moonshot/Kimi, Groq, Ollama (14 files, ~32 KB total).
  • backend/open_webui/utils/provider_logos.py — the matcher module. Documented matching philosophy and how to extend the rule set.
  • backend/open_webui/test/util/test_provider_logos.py — 42-case pytest suite.

Changed

  • backend/open_webui/routers/models.py::get_model_profile_image — adds the new fallback step between the DB-image lookup and the favicon fallback. No behaviour change for models that already have a profile_image_url.

Removed / Deprecated / Fixed / Security / Breaking Changes

None.


Judgment calls

A few things worth calling out for review:

  1. CDN vs bundled SVGs. I bundled. Lobe-icons is MIT-licensed, the SVGs are tiny (~32 KB total), and self-hosting avoids a runtime third-party dependency, works offline, and prevents leaking model identifiers in browser-side requests for default avatars. If you'd rather pull at request time from cdn.jsdelivr.net, happy to switch.

  2. Provider precedence in host/model ids. For ids like groq/llama3-70b the matcher returns the Llama (model brand) logo, not Groq (inference host). Reasoning: it's still a Llama model, just hosted by Groq. The inference-host rules are placed below the model-brand rules so they only fire when no model brand is in the id (e.g. the bare id groq). Pinned by tests.

  3. No new env var / setting. A toggle felt unnecessary — admins who want a specific image for a model already have the existing meta.profile_image_url override, which always wins. Happy to add one if you'd rather make the auto-fallback opt-in.

  4. Provider coverage scope. Conservative on purpose — covered the brands users are most likely to enable today. Adding a provider is one regex rule + one SVG + one test row; the matcher's docstring spells out the steps.

Additional Information

  • Implementation references the existing _safe_static_redirect_path pattern in the same file.
  • The new utility lives at open_webui/utils/provider_logos.py (top-level utils module, like headers.py / misc.py); it does not import from any router or model.
  • Related: changelog entry "Default model profile images now redirect to a shared static path" (#24015) — same direction (cheap static redirects instead of per-request file reads).

Screenshots or Videos

I don't have a deployed instance with an array of brand-named models to capture a clean before/after on. The behaviour is verifiable from the test matrix:

gpt-5                    -> /static/providers/openai.svg
anthropic/claude-opus-4  -> /static/providers/claude-color.svg
gemini-2.5-pro           -> /static/providers/gemini-color.svg
deepseek/deepseek-v3     -> /static/providers/deepseek-color.svg
qwen/qwen3-max           -> /static/providers/qwen-color.svg
groq/llama3-70b          -> /static/providers/meta-color.svg   (model wins)
ollama/mistral           -> /static/providers/mistral-color.svg
some-totally-unknown-id  -> /static/favicon.png                (unchanged)

Contributor License Agreement


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/open-webui/open-webui/pull/24173 **Author:** [@ikamensh](https://github.com/ikamensh) **Created:** 4/27/2026 **Status:** ❌ Closed **Base:** `dev` ← **Head:** `feat/auto-provider-logos` --- ### 📝 Commits (1) - [`ad850f8`](https://github.com/open-webui/open-webui/commit/ad850f872f67a607e26d20b8824427206a7757b8) feat: auto-assign provider logos to models by id ### 📊 Changes **19 files changed** (+334 additions, -0 deletions) <details> <summary>View changed files</summary> 📝 `backend/open_webui/routers/models.py` (+13 -0) ➕ `backend/open_webui/static/providers/LICENSE` (+21 -0) ➕ `backend/open_webui/static/providers/README.md` (+30 -0) ➕ `backend/open_webui/static/providers/claude-color.svg` (+1 -0) ➕ `backend/open_webui/static/providers/cohere-color.svg` (+1 -0) ➕ `backend/open_webui/static/providers/deepseek-color.svg` (+1 -0) ➕ `backend/open_webui/static/providers/gemini-color.svg` (+1 -0) ➕ `backend/open_webui/static/providers/groq.svg` (+1 -0) ➕ `backend/open_webui/static/providers/meta-color.svg` (+1 -0) ➕ `backend/open_webui/static/providers/mistral-color.svg` (+1 -0) ➕ `backend/open_webui/static/providers/moonshot.svg` (+1 -0) ➕ `backend/open_webui/static/providers/ollama.svg` (+1 -0) ➕ `backend/open_webui/static/providers/openai.svg` (+1 -0) ➕ `backend/open_webui/static/providers/perplexity-color.svg` (+1 -0) ➕ `backend/open_webui/static/providers/qwen-color.svg` (+1 -0) ➕ `backend/open_webui/static/providers/xai.svg` (+1 -0) ➕ `backend/open_webui/static/providers/zhipu-color.svg` (+1 -0) ➕ `backend/open_webui/test/util/test_provider_logos.py` (+139 -0) ➕ `backend/open_webui/utils/provider_logos.py` (+117 -0) </details> ### 📄 Description # Pull Request Checklist - [x] **Target branch:** Targets `dev`. - [x] **Description:** See below. - [x] **Changelog:** Entry below. - [ ] **Documentation:** No user-facing config; behaviour is automatic. Happy to add a docs PR if maintainers want one (the SVG directory has a README explaining the vendoring/license). - [x] **Dependencies:** No new Python deps. Adds 14 vendored SVG files (~32 KB total) under `backend/open_webui/static/providers/` from `@lobehub/icons-static-svg` (MIT, attribution preserved). - [x] **Testing:** New pytest module with 42 cases (whitelist coverage, host/model precedence, unknown-id fallthrough, asset existence). Manually verified the fallback chain in the route locally. - [ ] **Agentic AI Code:** This PR was drafted with AI assistance and then manually reviewed, the regex set was hand-curated, the asset-vendoring tradeoff was made deliberately (see "judgment calls" below), and the test matrix was hand-written to cover real-world id shapes. Please flag anything that looks off and I'll address it. - [x] **Code review:** Self-reviewed; ran `ruff check` and `ruff format` on the new files. - [x] **Design & Architecture:** No new settings — the override path (admin-set `meta.profile_image_url`) keeps full control. The new lookup is a tail fallback, before the existing favicon fallback. - [x] **Git Hygiene:** One atomic commit on `feat/auto-provider-logos`, rebased on `dev`. - [x] **Title Prefix:** `feat:` # Changelog Entry ### Description Today, models supplied by an upstream connection (OpenAI, OpenRouter, Ollama, ...) show the grey ``OI`` placeholder unless an admin manually creates a model overlay row with a `profile_image_url`. With this change, adding `gpt-5`, `anthropic/claude-opus-4`, `gemini-2.5-pro`, `deepseek-v3`, etc. to a connection's allowed model list shows the right provider logo immediately. Zero config. The override path is unchanged: an admin-supplied `meta.profile_image_url` always wins. The regex match runs *only* when no DB image is set, and *before* the existing favicon fallback — so unrecognised ids behave exactly like today. ### Added - **Auto-assigned provider logos** in `GET /api/v1/models/model/profile/image`. When the database has no `profile_image_url` for a model, the route now matches the model id against a small regex table and redirects to a vendored brand SVG. - **Vendored SVGs** under `backend/open_webui/static/providers/` (sourced from [lobehub/lobe-icons](https://github.com/lobehub/lobe-icons), MIT — `LICENSE` and attribution `README.md` included). Covers OpenAI, Anthropic/Claude, Google/Gemini/Gemma, DeepSeek, Qwen, Zhipu/GLM, Mistral, xAI/Grok, Meta/Llama, Cohere, Perplexity, Moonshot/Kimi, Groq, Ollama (14 files, ~32 KB total). - `backend/open_webui/utils/provider_logos.py` — the matcher module. Documented matching philosophy and how to extend the rule set. - `backend/open_webui/test/util/test_provider_logos.py` — 42-case pytest suite. ### Changed - `backend/open_webui/routers/models.py::get_model_profile_image` — adds the new fallback step between the DB-image lookup and the favicon fallback. No behaviour change for models that already have a `profile_image_url`. ### Removed / Deprecated / Fixed / Security / Breaking Changes None. --- ### Judgment calls A few things worth calling out for review: 1. **CDN vs bundled SVGs.** I bundled. Lobe-icons is MIT-licensed, the SVGs are tiny (~32 KB total), and self-hosting avoids a runtime third-party dependency, works offline, and prevents leaking model identifiers in browser-side requests for default avatars. If you'd rather pull at request time from `cdn.jsdelivr.net`, happy to switch. 2. **Provider precedence in `host/model` ids.** For ids like `groq/llama3-70b` the matcher returns the *Llama* (model brand) logo, not Groq (inference host). Reasoning: it's still a Llama model, just hosted by Groq. The inference-host rules are placed below the model-brand rules so they only fire when no model brand is in the id (e.g. the bare id `groq`). Pinned by tests. 3. **No new env var / setting.** A toggle felt unnecessary — admins who want a specific image for a model already have the existing `meta.profile_image_url` override, which always wins. Happy to add one if you'd rather make the auto-fallback opt-in. 4. **Provider coverage scope.** Conservative on purpose — covered the brands users are most likely to enable today. Adding a provider is one regex rule + one SVG + one test row; the matcher's docstring spells out the steps. ### Additional Information - Implementation references the existing `_safe_static_redirect_path` pattern in the same file. - The new utility lives at `open_webui/utils/provider_logos.py` (top-level utils module, like `headers.py` / `misc.py`); it does not import from any router or model. - Related: changelog entry "Default model profile images now redirect to a shared static path" (#24015) — same direction (cheap static redirects instead of per-request file reads). ### Screenshots or Videos I don't have a deployed instance with an array of brand-named models to capture a clean before/after on. The behaviour is verifiable from the test matrix: ``` gpt-5 -> /static/providers/openai.svg anthropic/claude-opus-4 -> /static/providers/claude-color.svg gemini-2.5-pro -> /static/providers/gemini-color.svg deepseek/deepseek-v3 -> /static/providers/deepseek-color.svg qwen/qwen3-max -> /static/providers/qwen-color.svg groq/llama3-70b -> /static/providers/meta-color.svg (model wins) ollama/mistral -> /static/providers/mistral-color.svg some-totally-unknown-id -> /static/favicon.png (unchanged) ``` ### Contributor License Agreement - [x] By submitting this pull request, I confirm that I have read and fully agree to the [Contributor License Agreement (CLA)](https://github.com/open-webui/open-webui/blob/main/CONTRIBUTOR_LICENSE_AGREEMENT), and I am providing my contributions under its terms. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-05-18 15:41:21 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/open-webui#114845