mirror of
https://github.com/zhayujie/chatgpt-on-wechat.git
synced 2026-07-17 11:07:11 +08:00
feat(web): integrate custom providers into the provider credentials section
- Merge the separate custom-providers section into the unified provider grid; "Custom" in the add-provider picker now acts as an add-new action (trailing + mark) and opens the dedicated modal, supporting multiple OpenAI-compatible endpoints - Simplify the custom provider modal: drop the default-model field, add an inline delete button, align colors with the theme - Keep the legacy single "custom" card visible (models page, chat dropdown and legacy config page) while custom_api_key/custom_api_base is still in use, so existing single-provider setups don't disappear - Unify user-facing wording from "vendor" to "provider" in UI and docs - Restructure custom provider docs (zh/en/ja) around Web console and config file usage
This commit is contained in:
@@ -1643,6 +1643,32 @@ class ConfigHandler:
|
||||
"api_key_field": p.get("api_key_field"),
|
||||
}
|
||||
|
||||
# Expose user-defined custom providers as "custom:<id>" entries so
|
||||
# the legacy config page can display and select them. Credentials
|
||||
# are managed on the Models page, hence the null key/base fields.
|
||||
# Mirrors the Models page: when expanded entries exist, the bare
|
||||
# legacy "custom" entry is hidden — unless the flat single-provider
|
||||
# custom config is still active or filled in.
|
||||
try:
|
||||
from models.custom_provider import get_custom_providers
|
||||
custom_list = get_custom_providers()
|
||||
legacy_custom_in_use = ModelsHandler._legacy_custom_in_use(local_config)
|
||||
if custom_list and not legacy_custom_in_use:
|
||||
providers.pop("custom", None)
|
||||
for cp in custom_list:
|
||||
cid = f"custom:{cp.get('id')}"
|
||||
cname = cp.get("name") or cp.get("id")
|
||||
providers[cid] = {
|
||||
"label": {"zh": cname, "en": cname},
|
||||
"models": [cp["model"]] if cp.get("model") else [],
|
||||
"api_base_key": None,
|
||||
"api_base_default": None,
|
||||
"api_base_placeholder": "",
|
||||
"api_key_field": None,
|
||||
}
|
||||
except Exception as cp_err:
|
||||
logger.warning(f"[ConfigHandler] failed to expand custom providers: {cp_err}")
|
||||
|
||||
raw_pwd = str(local_config.get("web_password", "") or "")
|
||||
masked_pwd = ("*" * len(raw_pwd)) if raw_pwd else ""
|
||||
|
||||
@@ -2189,6 +2215,17 @@ class ModelsHandler:
|
||||
})
|
||||
return cards
|
||||
|
||||
@classmethod
|
||||
def _legacy_custom_in_use(cls, local_config: dict) -> bool:
|
||||
"""True when the flat single-provider custom config is still relevant:
|
||||
either it is the active bot_type, or its key/base fields are filled.
|
||||
In that case the legacy "custom" card must stay visible even when
|
||||
multi ``custom_providers`` entries exist."""
|
||||
if (local_config.get("bot_type") or "") == "custom":
|
||||
return True
|
||||
return (cls._is_real_key(local_config.get("custom_api_key") or "")
|
||||
or bool(local_config.get("custom_api_base")))
|
||||
|
||||
@classmethod
|
||||
def _provider_overview(cls) -> List[dict]:
|
||||
"""All known providers (configured first, unconfigured after).
|
||||
@@ -2202,13 +2239,18 @@ class ModelsHandler:
|
||||
"""
|
||||
local_config = conf()
|
||||
custom_cards = cls._custom_provider_cards(local_config)
|
||||
# Keep the legacy single "custom" card visible alongside the expanded
|
||||
# ones when the flat custom_api_key/base config is active or filled,
|
||||
# so existing single-provider setups never disappear from the UI.
|
||||
keep_legacy_custom = cls._legacy_custom_in_use(local_config)
|
||||
items = []
|
||||
for pid, p in ConfigHandler.PROVIDER_MODELS.items():
|
||||
if pid == "custom" and custom_cards:
|
||||
# Multi-provider mode: emit the expanded cards instead of the
|
||||
# single legacy custom card.
|
||||
# Multi-provider mode: emit the expanded cards, plus the
|
||||
# legacy card when it is still in use.
|
||||
items.extend(custom_cards)
|
||||
continue
|
||||
if not keep_legacy_custom:
|
||||
continue
|
||||
key_field = p.get("api_key_field")
|
||||
base_field = p.get("api_base_key")
|
||||
raw_key = local_config.get(key_field, "") if key_field else ""
|
||||
@@ -2253,11 +2295,15 @@ class ModelsHandler:
|
||||
provider_id = "linkai"
|
||||
# In multi-provider mode, replace the single "custom" entry with the
|
||||
# expanded "custom:<id>" ids so the chat dropdown matches the cards.
|
||||
# The legacy "custom" entry stays when its flat config is still used.
|
||||
provider_ids = []
|
||||
custom_cards = cls._custom_provider_cards(local_config)
|
||||
keep_legacy_custom = cls._legacy_custom_in_use(local_config)
|
||||
for pid in ConfigHandler.PROVIDER_MODELS.keys():
|
||||
if pid == "custom" and custom_cards:
|
||||
provider_ids.extend(c["id"] for c in custom_cards)
|
||||
if keep_legacy_custom:
|
||||
provider_ids.append(pid)
|
||||
else:
|
||||
provider_ids.append(pid)
|
||||
return {
|
||||
@@ -2881,11 +2927,14 @@ class ModelsHandler:
|
||||
existing["api_base"] = api_base
|
||||
if api_key:
|
||||
existing["api_key"] = api_key
|
||||
# model is always overwritten (empty clears the default model).
|
||||
if model:
|
||||
existing["model"] = model
|
||||
else:
|
||||
existing.pop("model", None)
|
||||
# Only touch model when explicitly provided in the payload; an
|
||||
# explicit empty string clears it, a missing key keeps it (the
|
||||
# UI modal no longer sends model, so manual config survives edits).
|
||||
if "model" in data:
|
||||
if model:
|
||||
existing["model"] = model
|
||||
else:
|
||||
existing.pop("model", None)
|
||||
created = False
|
||||
|
||||
# Decide bot_type — only switch when explicitly requested.
|
||||
|
||||
Reference in New Issue
Block a user