From 07b2fd58d646817e597bd6edceabb1c12e57ed38 Mon Sep 17 00:00:00 2001
From: Buer <42402987+MartialBE@users.noreply.github.com>
Date: Tue, 28 May 2024 01:22:40 +0800
Subject: [PATCH] feat: berry theme update & bug fix (#1471)
* feat: load channel models from server
* chore: support AWS Claude/Cloudflare/Coze
* fix: Popup message when copying fails
* chore: Optimize tips
---
web/berry/src/constants/ChannelConstants.js | 30 +-
web/berry/src/constants/SnackbarConstants.js | 42 +-
web/berry/src/utils/common.js | 37 ++
.../AuthForms/ResetPasswordForm.js | 43 +-
.../src/views/Channel/component/EditModal.js | 502 +++++++-----------
.../src/views/Channel/component/NameLabel.js | 27 +-
web/berry/src/views/Channel/index.js | 8 +-
web/berry/src/views/Channel/type/Config.js | 196 ++++---
web/berry/src/views/Profile/index.js | 5 +-
.../views/Redemption/component/TableRow.js | 5 +-
.../src/views/Token/component/TableRow.js | 14 +-
.../src/views/Topup/component/InviteCard.js | 8 +-
12 files changed, 448 insertions(+), 469 deletions(-)
diff --git a/web/berry/src/constants/ChannelConstants.js b/web/berry/src/constants/ChannelConstants.js
index e6b0aed5..589ef1fb 100644
--- a/web/berry/src/constants/ChannelConstants.js
+++ b/web/berry/src/constants/ChannelConstants.js
@@ -11,12 +11,18 @@ export const CHANNEL_OPTIONS = {
value: 14,
color: 'primary'
},
- // 33: {
- // key: 33,
- // text: 'AWS Claude',
- // value: 33,
- // color: 'primary'
- // },
+ 33: {
+ key: 33,
+ text: 'AWS Claude',
+ value: 33,
+ color: 'primary'
+ },
+ 37: {
+ key: 37,
+ text: 'Cloudflare',
+ value: 37,
+ color: 'success'
+ },
3: {
key: 3,
text: 'Azure OpenAI',
@@ -119,12 +125,12 @@ export const CHANNEL_OPTIONS = {
value: 32,
color: 'primary'
},
- // 34: {
- // key: 34,
- // text: 'Coze',
- // value: 34,
- // color: 'primary'
- // },
+ 34: {
+ key: 34,
+ text: 'Coze',
+ value: 34,
+ color: 'primary'
+ },
35: {
key: 35,
text: 'Cohere',
diff --git a/web/berry/src/constants/SnackbarConstants.js b/web/berry/src/constants/SnackbarConstants.js
index 19523da1..05f79231 100644
--- a/web/berry/src/constants/SnackbarConstants.js
+++ b/web/berry/src/constants/SnackbarConstants.js
@@ -1,24 +1,56 @@
+import { closeSnackbar } from 'notistack';
+import { IconX } from '@tabler/icons-react';
+import { IconButton } from '@mui/material';
+const action = (snackbarId) => (
+ <>
+ {
+ closeSnackbar(snackbarId);
+ }}
+ >
+
+
+ >
+);
+
export const snackbarConstants = {
Common: {
ERROR: {
variant: 'error',
- autoHideDuration: 5000
+ autoHideDuration: 5000,
+ preventDuplicate: true,
+ action
},
WARNING: {
variant: 'warning',
- autoHideDuration: 10000
+ autoHideDuration: 10000,
+ preventDuplicate: true,
+ action
},
SUCCESS: {
variant: 'success',
- autoHideDuration: 1500
+ autoHideDuration: 1500,
+ preventDuplicate: true,
+ action
},
INFO: {
variant: 'info',
- autoHideDuration: 3000
+ autoHideDuration: 3000,
+ preventDuplicate: true,
+ action
},
NOTICE: {
variant: 'info',
- autoHideDuration: 7000
+ autoHideDuration: 20000,
+ preventDuplicate: true,
+ action
+ },
+ COPY: {
+ variant: 'copy',
+ persist: true,
+ preventDuplicate: true,
+ allowDownload: true,
+ action
}
},
Mobile: {
diff --git a/web/berry/src/utils/common.js b/web/berry/src/utils/common.js
index 947df3bf..d74d032e 100644
--- a/web/berry/src/utils/common.js
+++ b/web/berry/src/utils/common.js
@@ -193,3 +193,40 @@ export function removeTrailingSlash(url) {
return url;
}
}
+
+let channelModels = undefined;
+export async function loadChannelModels() {
+ const res = await API.get('/api/models');
+ const { success, data } = res.data;
+ if (!success) {
+ return;
+ }
+ channelModels = data;
+ localStorage.setItem('channel_models', JSON.stringify(data));
+}
+
+export function getChannelModels(type) {
+ if (channelModels !== undefined && type in channelModels) {
+ return channelModels[type];
+ }
+ let models = localStorage.getItem('channel_models');
+ if (!models) {
+ return [];
+ }
+ channelModels = JSON.parse(models);
+ if (type in channelModels) {
+ return channelModels[type];
+ }
+ return [];
+}
+
+export function copy(text, name = '') {
+ try {
+ navigator.clipboard.writeText(text);
+ } catch (error) {
+ text = `复制${name}失败,请手动复制:
${text}`;
+ enqueueSnackbar(, getSnackbarOptions('COPY'));
+ return;
+ }
+ showSuccess(`复制${name}成功!`);
+}
diff --git a/web/berry/src/views/Authentication/AuthForms/ResetPasswordForm.js b/web/berry/src/views/Authentication/AuthForms/ResetPasswordForm.js
index eaa8dc95..a9f0f9e3 100644
--- a/web/berry/src/views/Authentication/AuthForms/ResetPasswordForm.js
+++ b/web/berry/src/views/Authentication/AuthForms/ResetPasswordForm.js
@@ -1,22 +1,22 @@
-import { useState, useEffect } from "react";
-import { useSearchParams } from "react-router-dom";
+import { useState, useEffect } from 'react';
+import { useSearchParams } from 'react-router-dom';
// material-ui
-import { Button, Stack, Typography, Alert } from "@mui/material";
+import { Button, Stack, Typography, Alert } from '@mui/material';
// assets
-import { showError, showInfo } from "utils/common";
-import { API } from "utils/api";
+import { showError, copy } from 'utils/common';
+import { API } from 'utils/api';
// ===========================|| FIREBASE - REGISTER ||=========================== //
const ResetPasswordForm = () => {
const [searchParams] = useSearchParams();
const [inputs, setInputs] = useState({
- email: "",
- token: "",
+ email: '',
+ token: ''
});
- const [newPassword, setNewPassword] = useState("");
+ const [newPassword, setNewPassword] = useState('');
const submit = async () => {
const res = await API.post(`/api/user/reset`, inputs);
@@ -24,31 +24,25 @@ const ResetPasswordForm = () => {
if (success) {
let password = res.data.data;
setNewPassword(password);
- navigator.clipboard.writeText(password);
- showInfo(`新密码已复制到剪贴板:${password}`);
+ copy(password, '新密码');
} else {
showError(message);
}
};
useEffect(() => {
- let email = searchParams.get("email");
- let token = searchParams.get("token");
+ let email = searchParams.get('email');
+ let token = searchParams.get('token');
setInputs({
token,
- email,
+ email
});
}, []);
return (
-
+
{!inputs.email || !inputs.token ? (
-
+
无效的链接
) : newPassword ? (
@@ -57,14 +51,7 @@ const ResetPasswordForm = () => {
请登录后及时修改密码
) : (
-
-
+
{matchUpMd ? (
-
+
}>
刷新
diff --git a/web/berry/src/views/Channel/type/Config.js b/web/berry/src/views/Channel/type/Config.js
index 7e42ca8d..88e1ea92 100644
--- a/web/berry/src/views/Channel/type/Config.js
+++ b/web/berry/src/views/Channel/type/Config.js
@@ -1,177 +1,209 @@
const defaultConfig = {
input: {
- name: "",
+ name: '',
type: 1,
- key: "",
- base_url: "",
- other: "",
- model_mapping: "",
+ key: '',
+ base_url: '',
+ other: '',
+ model_mapping: '',
models: [],
- groups: ["default"],
+ groups: ['default'],
+ config: {}
},
inputLabel: {
- name: "渠道名称",
- type: "渠道类型",
- base_url: "渠道API地址",
- key: "密钥",
- other: "其他参数",
- models: "模型",
- model_mapping: "模型映射关系",
- groups: "用户组",
+ name: '渠道名称',
+ type: '渠道类型',
+ base_url: '渠道API地址',
+ key: '密钥',
+ other: '其他参数',
+ models: '模型',
+ model_mapping: '模型映射关系',
+ groups: '用户组',
+ config: null
},
prompt: {
- type: "请选择渠道类型",
- name: "请为渠道命名",
- base_url: "可空,请输入中转API地址,例如通过cloudflare中转",
- key: "请输入渠道对应的鉴权密钥",
- other: "",
- models: "请选择该渠道所支持的模型",
+ type: '请选择渠道类型',
+ name: '请为渠道命名',
+ base_url: '可空,请输入中转API地址,例如通过cloudflare中转',
+ key: '请输入渠道对应的鉴权密钥',
+ other: '',
+ models: '请选择该渠道所支持的模型',
model_mapping:
'请输入要修改的模型映射关系,格式为:api请求模型ID:实际转发给渠道的模型ID,使用JSON数组表示,例如:{"gpt-3.5": "gpt-35"}',
- groups: "请选择该渠道所支持的用户组",
+ groups: '请选择该渠道所支持的用户组',
+ config: null
},
- modelGroup: "openai",
+ modelGroup: 'openai'
};
const typeConfig = {
3: {
inputLabel: {
- base_url: "AZURE_OPENAI_ENDPOINT",
- other: "默认 API 版本",
+ base_url: 'AZURE_OPENAI_ENDPOINT',
+ other: '默认 API 版本'
},
prompt: {
- base_url: "请填写AZURE_OPENAI_ENDPOINT",
- other: "请输入默认API版本,例如:2024-03-01-preview",
- },
+ base_url: '请填写AZURE_OPENAI_ENDPOINT',
+ other: '请输入默认API版本,例如:2024-03-01-preview'
+ }
},
11: {
input: {
- models: ["PaLM-2"],
+ models: ['PaLM-2']
},
- modelGroup: "google palm",
+ modelGroup: 'google palm'
},
14: {
input: {
- models: ["claude-instant-1", "claude-2", "claude-2.0", "claude-2.1"],
+ models: ['claude-instant-1', 'claude-2', 'claude-2.0', 'claude-2.1']
},
- modelGroup: "anthropic",
+ modelGroup: 'anthropic'
},
15: {
input: {
- models: ["ERNIE-Bot", "ERNIE-Bot-turbo", "ERNIE-Bot-4", "Embedding-V1"],
+ models: ['ERNIE-Bot', 'ERNIE-Bot-turbo', 'ERNIE-Bot-4', 'Embedding-V1']
},
prompt: {
- key: "按照如下格式输入:APIKey|SecretKey",
+ key: '按照如下格式输入:APIKey|SecretKey'
},
- modelGroup: "baidu",
+ modelGroup: 'baidu'
},
16: {
input: {
- models: ["glm-4", "glm-4v", "glm-3-turbo", "chatglm_turbo", "chatglm_pro", "chatglm_std", "chatglm_lite"],
+ models: ['glm-4', 'glm-4v', 'glm-3-turbo', 'chatglm_turbo', 'chatglm_pro', 'chatglm_std', 'chatglm_lite']
},
- modelGroup: "zhipu",
+ modelGroup: 'zhipu'
},
17: {
inputLabel: {
- other: "插件参数",
+ other: '插件参数'
},
input: {
- models: [
- "qwen-turbo",
- "qwen-plus",
- "qwen-max",
- "qwen-max-longcontext",
- "text-embedding-v1",
- ],
+ models: ['qwen-turbo', 'qwen-plus', 'qwen-max', 'qwen-max-longcontext', 'text-embedding-v1']
},
prompt: {
- other: "请输入插件参数,即 X-DashScope-Plugin 请求头的取值",
+ other: '请输入插件参数,即 X-DashScope-Plugin 请求头的取值'
},
- modelGroup: "ali",
+ modelGroup: 'ali'
},
18: {
inputLabel: {
- other: "版本号",
+ other: '版本号'
},
input: {
- models: [
- "SparkDesk",
- 'SparkDesk-v1.1',
- 'SparkDesk-v2.1',
- 'SparkDesk-v3.1',
- 'SparkDesk-v3.5'
- ],
+ models: ['SparkDesk', 'SparkDesk-v1.1', 'SparkDesk-v2.1', 'SparkDesk-v3.1', 'SparkDesk-v3.5']
},
prompt: {
- key: "按照如下格式输入:APPID|APISecret|APIKey",
- other: "请输入版本号,例如:v3.1",
+ key: '按照如下格式输入:APPID|APISecret|APIKey',
+ other: '请输入版本号,例如:v3.1'
},
- modelGroup: "xunfei",
+ modelGroup: 'xunfei'
},
19: {
input: {
- models: [
- "360GPT_S2_V9",
- "embedding-bert-512-v1",
- "embedding_s1_v1",
- "semantic_similarity_s1_v1",
- ],
+ models: ['360GPT_S2_V9', 'embedding-bert-512-v1', 'embedding_s1_v1', 'semantic_similarity_s1_v1']
},
- modelGroup: "360",
+ modelGroup: '360'
},
22: {
prompt: {
- key: "按照如下格式输入:APIKey-AppId,例如:fastgpt-0sp2gtvfdgyi4k30jwlgwf1i-64f335d84283f05518e9e041",
- },
+ key: '按照如下格式输入:APIKey-AppId,例如:fastgpt-0sp2gtvfdgyi4k30jwlgwf1i-64f335d84283f05518e9e041'
+ }
},
23: {
input: {
- models: ["hunyuan"],
+ models: ['hunyuan']
},
prompt: {
- key: "按照如下格式输入:AppId|SecretId|SecretKey",
+ key: '按照如下格式输入:AppId|SecretId|SecretKey'
},
- modelGroup: "tencent",
+ modelGroup: 'tencent'
},
24: {
inputLabel: {
- other: "版本号",
+ other: '版本号'
},
input: {
- models: ["gemini-pro"],
+ models: ['gemini-pro']
},
prompt: {
- other: "请输入版本号,例如:v1",
+ other: '请输入版本号,例如:v1'
},
- modelGroup: "google gemini",
+ modelGroup: 'google gemini'
},
25: {
input: {
- models: ['moonshot-v1-8k', 'moonshot-v1-32k', 'moonshot-v1-128k'],
+ models: ['moonshot-v1-8k', 'moonshot-v1-32k', 'moonshot-v1-128k']
},
- modelGroup: "moonshot",
+ modelGroup: 'moonshot'
},
26: {
input: {
- models: ['Baichuan2-Turbo', 'Baichuan2-Turbo-192k', 'Baichuan-Text-Embedding'],
+ models: ['Baichuan2-Turbo', 'Baichuan2-Turbo-192k', 'Baichuan-Text-Embedding']
},
- modelGroup: "baichuan",
+ modelGroup: 'baichuan'
},
27: {
input: {
- models: ['abab5.5s-chat', 'abab5.5-chat', 'abab6-chat'],
+ models: ['abab5.5s-chat', 'abab5.5-chat', 'abab6-chat']
},
- modelGroup: "minimax",
+ modelGroup: 'minimax'
},
29: {
- modelGroup: "groq",
+ modelGroup: 'groq'
},
30: {
- modelGroup: "ollama",
+ modelGroup: 'ollama'
},
31: {
- modelGroup: "lingyiwanwu",
+ modelGroup: 'lingyiwanwu'
},
+ 33: {
+ inputLabel: {
+ key: '',
+ config: {
+ region: 'Region',
+ ak: 'Access Key',
+ sk: 'Secret Key'
+ }
+ },
+ prompt: {
+ key: '',
+ config: {
+ region: 'region,e.g. us-west-2',
+ ak: 'AWS IAM Access Key',
+ sk: 'AWS IAM Secret Key'
+ }
+ },
+ modelGroup: 'anthropic'
+ },
+ 37: {
+ inputLabel: {
+ config: {
+ user_id: 'Account ID'
+ }
+ },
+ prompt: {
+ config: {
+ user_id: '请输入 Account ID,例如:d8d7c61dbc334c32d3ced580e4bf42b4'
+ }
+ },
+ modelGroup: 'Cloudflare'
+ },
+ 34: {
+ inputLabel: {
+ config: {
+ user_id: 'User ID'
+ }
+ },
+ prompt: {
+ models: '对于 Coze 而言,模型名称即 Bot ID,你可以添加一个前缀 `bot-`,例如:`bot-123456`',
+ config: {
+ user_id: '生成该密钥的用户 ID'
+ }
+ },
+ modelGroup: 'Coze'
+ }
};
export { defaultConfig, typeConfig };
diff --git a/web/berry/src/views/Profile/index.js b/web/berry/src/views/Profile/index.js
index 483e3141..4705d8af 100644
--- a/web/berry/src/views/Profile/index.js
+++ b/web/berry/src/views/Profile/index.js
@@ -21,7 +21,7 @@ import { IconBrandWechat, IconBrandGithub, IconMail } from '@tabler/icons-react'
import Label from 'ui-component/Label';
import { API } from 'utils/api';
import { showError, showSuccess } from 'utils/common';
-import { onGitHubOAuthClicked, onLarkOAuthClicked } from 'utils/common';
+import { onGitHubOAuthClicked, onLarkOAuthClicked, copy } from 'utils/common';
import * as Yup from 'yup';
import WechatModal from 'views/Authentication/AuthForms/WechatModal';
import { useSelector } from 'react-redux';
@@ -90,8 +90,7 @@ export default function Profile() {
const { success, message, data } = res.data;
if (success) {
setInputs((inputs) => ({ ...inputs, access_token: data }));
- navigator.clipboard.writeText(data);
- showSuccess(`令牌已重置并已复制到剪贴板`);
+ copy(data, '访问令牌');
} else {
showError(message);
}
diff --git a/web/berry/src/views/Redemption/component/TableRow.js b/web/berry/src/views/Redemption/component/TableRow.js
index 68c9a505..380af037 100644
--- a/web/berry/src/views/Redemption/component/TableRow.js
+++ b/web/berry/src/views/Redemption/component/TableRow.js
@@ -18,7 +18,7 @@ import {
import Label from 'ui-component/Label';
import TableSwitch from 'ui-component/Switch';
-import { timestamp2string, renderQuota, showSuccess } from 'utils/common';
+import { timestamp2string, renderQuota, copy } from 'utils/common';
import { IconDotsVertical, IconEdit, IconTrash } from '@tabler/icons-react';
@@ -83,8 +83,7 @@ export default function RedemptionTableRow({ item, manageRedemption, handleOpenM
variant="contained"
color="primary"
onClick={() => {
- navigator.clipboard.writeText(item.key);
- showSuccess('已复制到剪贴板!');
+ copy(item.key, '兑换码');
}}
>
复制
diff --git a/web/berry/src/views/Token/component/TableRow.js b/web/berry/src/views/Token/component/TableRow.js
index 51ab0d4b..6a197e69 100644
--- a/web/berry/src/views/Token/component/TableRow.js
+++ b/web/berry/src/views/Token/component/TableRow.js
@@ -20,7 +20,7 @@ import {
} from '@mui/material';
import TableSwitch from 'ui-component/Switch';
-import { renderQuota, showSuccess, timestamp2string } from 'utils/common';
+import { renderQuota, timestamp2string, copy } from 'utils/common';
import { IconDotsVertical, IconEdit, IconTrash, IconCaretDownFilled } from '@tabler/icons-react';
@@ -141,8 +141,7 @@ export default function TokensTableRow({ item, manageToken, handleOpenModal, set
if (type === 'link') {
window.open(text);
} else {
- navigator.clipboard.writeText(text);
- showSuccess('已复制到剪贴板!');
+ copy(text);
}
handleCloseMenu();
};
@@ -192,7 +191,7 @@ export default function TokensTableRow({ item, manageToken, handleOpenModal, set
id={`switch-${item.id}`}
checked={statusSwitch === 1}
onChange={handleStatus}
- // disabled={statusSwitch !== 1 && statusSwitch !== 2}
+ // disabled={statusSwitch !== 1 && statusSwitch !== 2}
/>
@@ -211,8 +210,7 @@ export default function TokensTableRow({ item, manageToken, handleOpenModal, set
{
- navigator.clipboard.writeText(`sk-${item.key}`);
- showSuccess('已复制到剪贴板!');
+ copy(`sk-${item.key}`);
}}
>
复制
@@ -222,7 +220,9 @@ export default function TokensTableRow({ item, manageToken, handleOpenModal, set
- handleCopy(COPY_OPTIONS[0], 'link')}>聊天
+ handleCopy(COPY_OPTIONS[0], 'link')}>
+ 聊天
+
handleOpenMenu(e, 'link')}>
diff --git a/web/berry/src/views/Topup/component/InviteCard.js b/web/berry/src/views/Topup/component/InviteCard.js
index a95f85e5..73c9670f 100644
--- a/web/berry/src/views/Topup/component/InviteCard.js
+++ b/web/berry/src/views/Topup/component/InviteCard.js
@@ -4,7 +4,7 @@ import SubCard from 'ui-component/cards/SubCard';
import inviteImage from 'assets/images/invite/cwok_casual_19.webp';
import { useState } from 'react';
import { API } from 'utils/api';
-import { showError, showSuccess } from 'utils/common';
+import { showError, copy } from 'utils/common';
const InviteCard = () => {
const theme = useTheme();
@@ -12,8 +12,7 @@ const InviteCard = () => {
const handleInviteUrl = async () => {
if (inviteUl) {
- navigator.clipboard.writeText(inviteUl);
- showSuccess(`邀请链接已复制到剪切板`);
+ copy(inviteUl, '邀请链接');
return;
}
const res = await API.get('/api/user/aff');
@@ -21,8 +20,7 @@ const InviteCard = () => {
if (success) {
let link = `${window.location.origin}/register?aff=${data}`;
setInviteUrl(link);
- navigator.clipboard.writeText(link);
- showSuccess(`邀请链接已复制到剪切板`);
+ copy(link, '邀请链接');
} else {
showError(message);
}