Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions messages/en/dashboard.json
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,12 @@
"defaultDescription": "default includes providers without groupTag.",
"descriptionWithUserGroup": "Provider groups for this key (user groups: {group}; default: default)."
},
"successTitle": "Key Created Successfully",
"successDescription": "Your API key has been created successfully.",
"generatedKey": {
"label": "Generated Key",
"hint": "You can view and copy this key anytime from the key list."
},
"errors": {
"userIdMissing": "User ID does not exist",
"createFailed": "Failed to create, please try again later",
Expand Down Expand Up @@ -1142,6 +1148,9 @@
"defaultGroup": "default",
"userStatus": {
"disabled": "Disabled"
},
"actions": {
"addKey": "Add Key"
}
},
"keyFullDisplay": {
Expand Down Expand Up @@ -1210,8 +1219,8 @@
"editKeyTitle": "Edit Key"
},
"editDialog": {
"title": "Edit user and keys",
"description": "Edit user information and API key settings",
"title": "Edit user",
"description": "Edit user information",
"userSection": "User settings",
"keysSection": "Key settings",
"scrollToKey": "Scroll to key",
Expand Down Expand Up @@ -1310,6 +1319,10 @@
"saveFailed": "Failed to create user",
"keyCreateFailed": "Failed to create key",
"createSuccess": "User created successfully",
"successTitle": "Created Successfully",
"successDescription": "User and key have been created",
"generatedKey": "Generated Key",
"keyHint": "You can view and copy this key anytime from the user management page",
"keysSection": "Keys",
"addKey": "Add key",
"removeKey": "Remove key",
Expand Down Expand Up @@ -1404,7 +1417,7 @@
"label": "Enable dedicated balance page",
"description": "Allow users to view their balance via a dedicated page",
"descriptionEnabled": "When enabled, this key will access an independent personal usage page upon login. However, it cannot modify its own key's provider group.",
"descriptionDisabled": "When disabled, the user cannot access the personal usage page UI. However, they can modify their own key's provider group in the restricted Web UI."
"descriptionDisabled": "When disabled, the user cannot access the personal usage page UI. Instead, they will use the restricted Web UI."
},
"cacheTtlOverride": {
"label": "Cache TTL override",
Expand Down Expand Up @@ -1529,7 +1542,7 @@
"label": "Independent Personal Usage Page",
"description": "When enabled, this key can access an independent personal usage page",
"descriptionEnabled": "When enabled, this key will access an independent personal usage page upon login. However, it cannot modify its own key's provider group.",
"descriptionDisabled": "When disabled, the user cannot access the personal usage page UI. However, they can modify their own key's provider group in the restricted Web UI."
"descriptionDisabled": "When disabled, the user cannot access the personal usage page UI. Instead, they will use the restricted Web UI."
},
"providerGroup": {
"label": "Provider Group",
Expand Down
19 changes: 16 additions & 3 deletions messages/ja/dashboard.json
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,12 @@
"defaultDescription": "default は groupTag 未設定のプロバイダーを含みます",
"descriptionWithUserGroup": "このキーのプロバイダーグループ(ユーザーのグループ: {group}、既定: default)"
},
"successTitle": "キーが正常に作成されました",
"successDescription": "APIキーが正常に作成されました。",
"generatedKey": {
"label": "生成されたキー",
"hint": "このキーはキー一覧からいつでも確認・コピーできます。"
},
"errors": {
"userIdMissing": "ユーザーIDが存在しません",
"createFailed": "作成に失敗しました。後でもう一度お試しください",
Expand Down Expand Up @@ -1113,6 +1119,9 @@
"defaultGroup": "default",
"userStatus": {
"disabled": "無効"
},
"actions": {
"addKey": "キーを追加"
}
},
"keyFullDisplay": {
Expand Down Expand Up @@ -1172,8 +1181,8 @@
"failed": "更新に失敗しました"
},
"editDialog": {
"title": "ユーザーとキーを編集",
"description": "ユーザー情報とAPIキーの設定を編集",
"title": "ユーザーを編集",
"description": "ユーザー情報を編集",
"userSection": "ユーザー設定",
"keysSection": "キー設定",
"scrollToKey": "キーへスクロール",
Expand Down Expand Up @@ -1272,6 +1281,10 @@
"saveFailed": "ユーザーの作成に失敗しました",
"keyCreateFailed": "キーの作成に失敗しました",
"createSuccess": "ユーザーが作成されました",
"successTitle": "作成完了",
"successDescription": "ユーザーとキーが作成されました",
"generatedKey": "生成されたキー",
"keyHint": "このキーはユーザー管理ページからいつでも確認・コピーできます",
"keysSection": "キー",
"addKey": "キーを追加",
"removeKey": "キーを削除",
Expand Down Expand Up @@ -1489,7 +1502,7 @@
"label": "独立した個人使用量ページ",
"description": "有効にすると、このキーで独立した個人使用量ページにアクセスできます",
"descriptionEnabled": "有効にすると、このキーはログイン時に独立した個人使用量ページにアクセスします。ただし、自分のキーのプロバイダーグループは変更できません。",
"descriptionDisabled": "無効にすると、ユーザーは個人使用量ページUIにアクセスできません。ただし、制限されたWeb UIで自分のキーのプロバイダーグループを変更できます。"
"descriptionDisabled": "無効にすると、ユーザーは個人使用量ページUIにアクセスできません。代わりに制限されたWeb UIを使用します。"
},
"providerGroup": {
"label": "プロバイダーグループ",
Expand Down
19 changes: 16 additions & 3 deletions messages/ru/dashboard.json
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,12 @@
"defaultDescription": "default включает провайдеров без groupTag.",
"descriptionWithUserGroup": "Группы провайдеров для этого ключа (группы пользователя: {group}; по умолчанию: default)."
},
"successTitle": "Ключ успешно создан",
"successDescription": "Ваш API-ключ был успешно создан.",
"generatedKey": {
"label": "Сгенерированный ключ",
"hint": "Вы можете просмотреть и скопировать этот ключ в любое время из списка ключей."
},
"errors": {
"userIdMissing": "ID пользователя не существует",
"createFailed": "Не удалось создать, попробуйте позже",
Expand Down Expand Up @@ -1120,6 +1126,9 @@
"defaultGroup": "default",
"userStatus": {
"disabled": "Отключен"
},
"actions": {
"addKey": "Добавить ключ"
}
},
"keyFullDisplay": {
Expand Down Expand Up @@ -1183,8 +1192,8 @@
"editKeyTitle": "Редактировать ключ"
},
"editDialog": {
"title": "Редактировать пользователя и ключи",
"description": "Редактирование данных пользователя и настроек API-ключей",
"title": "Редактировать пользователя",
"description": "Редактирование данных пользователя",
"userSection": "Настройки пользователя",
"keysSection": "Настройки ключей",
"scrollToKey": "Прокрутить к ключу",
Expand Down Expand Up @@ -1283,6 +1292,10 @@
"saveFailed": "Не удалось создать пользователя",
"keyCreateFailed": "Не удалось создать ключ",
"createSuccess": "Пользователь создан",
"successTitle": "Успешно создано",
"successDescription": "Пользователь и ключ успешно созданы",
"generatedKey": "Сгенерированный ключ",
"keyHint": "Вы можете просмотреть и скопировать этот ключ в любое время на странице управления пользователями",
"keysSection": "Ключи",
"addKey": "Добавить ключ",
"removeKey": "Удалить ключ",
Expand Down Expand Up @@ -1377,7 +1390,7 @@
"label": "Включить отдельную страницу проверки баланса",
"description": "Разрешить пользователю просматривать баланс на отдельной странице",
"descriptionEnabled": "При включении этот ключ будет использовать независимую страницу личного использования при входе. Однако он не может изменять группу провайдеров собственного ключа.",
"descriptionDisabled": "При отключении пользователь не сможет получить доступ к странице личного использования. Однако он может изменять группу провайдеров своего ключа в ограниченном Web UI."
"descriptionDisabled": "При отключении пользователь не сможет получить доступ к странице личного использования. Вместо этого будет использоваться ограниченный Web UI."
},
"cacheTtlOverride": {
"label": "Переопределение Cache TTL",
Expand Down
19 changes: 16 additions & 3 deletions messages/zh-CN/dashboard.json
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,12 @@
"defaultDescription": "default 分组包含所有未设置 groupTag 的供应商",
"descriptionWithUserGroup": "供应商分组(默认:default;用户分组:{group})"
},
"successTitle": "密钥创建成功",
"successDescription": "您的 API 密钥已成功创建。",
"generatedKey": {
"label": "生成的密钥",
"hint": "您可以随时在密钥列表中查看和复制此密钥"
},
"errors": {
"userIdMissing": "用户ID不存在",
"createFailed": "创建失败,请稍后重试",
Expand Down Expand Up @@ -1143,6 +1149,9 @@
"defaultGroup": "default",
"userStatus": {
"disabled": "已禁用"
},
"actions": {
"addKey": "新增密钥"
}
},
"keyFullDisplay": {
Expand Down Expand Up @@ -1211,8 +1220,8 @@
"editKeyTitle": "编辑 Key"
},
"editDialog": {
"title": "编辑用户与密钥",
"description": "编辑用户信息和 API 密钥设置",
"title": "编辑用户",
"description": "编辑用户信息",
"userSection": "用户设置",
"keysSection": "密钥设置",
"scrollToKey": "滚动到密钥",
Expand Down Expand Up @@ -1311,6 +1320,10 @@
"saveFailed": "创建用户失败",
"keyCreateFailed": "创建密钥失败",
"createSuccess": "用户创建成功",
"successTitle": "创建成功",
"successDescription": "用户和密钥已成功创建",
"generatedKey": "生成的密钥",
"keyHint": "您可以随时在用户管理页面查看和复制此密钥",
"keysSection": "密钥",
"addKey": "添加密钥",
"removeKey": "删除密钥",
Expand Down Expand Up @@ -1528,7 +1541,7 @@
"label": "独立个人用量页面",
"description": "启用后,此密钥可使用独立的个人用量查询页面",
"descriptionEnabled": "启用后,此密钥在登录时将进入独立的个人用量页面。但不可修改自己密钥的供应商分组。",
"descriptionDisabled": "关闭后,用户将无法进入个人独立用量页面 UI。但可在受限的 Web UI功能中修改自己密钥的供应商分组。"
"descriptionDisabled": "关闭后,用户将无法进入个人独立用量页面 UI,而是进入受限的 Web UI。"
},
"providerGroup": {
"label": "供应商分组",
Expand Down
19 changes: 16 additions & 3 deletions messages/zh-TW/dashboard.json
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,12 @@
"defaultDescription": "default 分組包含所有未設定 groupTag 的供應商",
"descriptionWithUserGroup": "供應商分組(預設:default;使用者分組:{group})"
},
"successTitle": "金鑰建立成功",
"successDescription": "您的 API 金鑰已成功建立。",
"generatedKey": {
"label": "產生的金鑰",
"hint": "您可以隨時在金鑰列表中查看和複製此金鑰"
},
"errors": {
"userIdMissing": "使用者 ID 不存在",
"createFailed": "建立失敗,請稍後重試",
Expand Down Expand Up @@ -1118,6 +1124,9 @@
"defaultGroup": "default",
"userStatus": {
"disabled": "已停用"
},
"actions": {
"addKey": "新增金鑰"
}
},
"keyFullDisplay": {
Expand Down Expand Up @@ -1181,8 +1190,8 @@
"editKeyTitle": "編輯 Key"
},
"editDialog": {
"title": "編輯使用者與金鑰",
"description": "編輯使用者資訊和 API 金鑰設定",
"title": "編輯使用者",
"description": "編輯使用者資訊",
"userSection": "使用者設定",
"keysSection": "金鑰設定",
"scrollToKey": "捲動到金鑰",
Expand Down Expand Up @@ -1281,6 +1290,10 @@
"saveFailed": "建立使用者失敗",
"keyCreateFailed": "建立金鑰失敗",
"createSuccess": "使用者建立成功",
"successTitle": "建立成功",
"successDescription": "使用者和金鑰已成功建立",
"generatedKey": "產生的金鑰",
"keyHint": "您可以隨時在使用者管理頁面查看和複製此金鑰",
"keysSection": "金鑰",
"addKey": "新增金鑰",
"removeKey": "刪除金鑰",
Expand Down Expand Up @@ -1498,7 +1511,7 @@
"label": "獨立個人用量頁面",
"description": "啟用後,此金鑰可使用獨立的個人用量查詢頁面",
"descriptionEnabled": "啟用後,此金鑰在登入時將進入獨立的個人用量頁面。但不可修改自己金鑰的供應商分組。",
"descriptionDisabled": "關閉後,使用者將無法進入個人獨立用量頁面 UI。但可在受限的 Web UI功能中修改自己金鑰的供應商分組。"
"descriptionDisabled": "關閉後,使用者將無法進入個人獨立用量頁面 UI,而是進入受限的 Web UI。"
},
"providerGroup": {
"label": "供應商分組",
Expand Down
76 changes: 76 additions & 0 deletions src/actions/providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3090,3 +3090,79 @@ async function fetchAnthropicModels(
return handleFetchException(error, "fetchAnthropicModels");
}
}

/**
* 解析分组字符串为数组
*/
function parseGroupString(groupString: string): string[] {
return groupString
.split(",")
.map((g) => g.trim())
.filter(Boolean);
}

/**
* 检查供应商分组是否匹配用户分组
*/
function checkProviderGroupMatch(providerGroupTag: string | null, userGroups: string[]): boolean {
if (userGroups.includes(PROVIDER_GROUP.ALL)) {
return true;
}

const providerTags = providerGroupTag
? parseGroupString(providerGroupTag)
: [PROVIDER_GROUP.DEFAULT];

return providerTags.some((tag) => userGroups.includes(tag));
}

/**
* 根据供应商分组获取模型建议列表
*
* 用于用户/密钥编辑时的模型限制下拉建议。
* 从匹配分组的启用供应商中收集 allowedModels 并去重。
*
* @param providerGroup - 可选的供应商分组(逗号分隔),默认为 "default"
* @returns 去重后的模型列表
*/
export async function getModelSuggestionsByProviderGroup(
providerGroup?: string | null
): Promise<ActionResult<string[]>> {
try {
const session = await getSession();
if (!session) {
return { ok: false, error: "未登录" };
}

// 获取所有启用的供应商
const providers = await findAllProviders();
const enabledProviders = providers.filter((p) => p.isEnabled);

// 解析用户分组
const userGroups = providerGroup ? parseGroupString(providerGroup) : [PROVIDER_GROUP.DEFAULT];

// 过滤匹配分组的供应商并收集 allowedModels
const modelSet = new Set<string>();

for (const provider of enabledProviders) {
if (checkProviderGroupMatch(provider.groupTag, userGroups)) {
const models = provider.allowedModels;
if (models && Array.isArray(models)) {
for (const model of models) {
if (model) {
modelSet.add(model);
}
}
}
}
}

// 转换为数组并排序
const sortedModels = Array.from(modelSet).sort();

return { ok: true, data: sortedModels };
} catch (error) {
logger.error("获取模型建议列表失败:", error);
return { ok: false, error: "获取模型建议列表失败" };
}
}
Loading
Loading