chore: support AWS Claude/Cloudflare/Coze
This commit is contained in:
parent
ec9b6d1039
commit
2e7e563d75
@ -11,12 +11,18 @@ export const CHANNEL_OPTIONS = {
|
|||||||
value: 14,
|
value: 14,
|
||||||
color: 'primary'
|
color: 'primary'
|
||||||
},
|
},
|
||||||
// 33: {
|
33: {
|
||||||
// key: 33,
|
key: 33,
|
||||||
// text: 'AWS Claude',
|
text: 'AWS Claude',
|
||||||
// value: 33,
|
value: 33,
|
||||||
// color: 'primary'
|
color: 'primary'
|
||||||
// },
|
},
|
||||||
|
37: {
|
||||||
|
key: 37,
|
||||||
|
text: 'Cloudflare',
|
||||||
|
value: 37,
|
||||||
|
color: 'success'
|
||||||
|
},
|
||||||
3: {
|
3: {
|
||||||
key: 3,
|
key: 3,
|
||||||
text: 'Azure OpenAI',
|
text: 'Azure OpenAI',
|
||||||
@ -119,12 +125,12 @@ export const CHANNEL_OPTIONS = {
|
|||||||
value: 32,
|
value: 32,
|
||||||
color: 'primary'
|
color: 'primary'
|
||||||
},
|
},
|
||||||
// 34: {
|
34: {
|
||||||
// key: 34,
|
key: 34,
|
||||||
// text: 'Coze',
|
text: 'Coze',
|
||||||
// value: 34,
|
value: 34,
|
||||||
// color: 'primary'
|
color: 'primary'
|
||||||
// },
|
},
|
||||||
35: {
|
35: {
|
||||||
key: 35,
|
key: 35,
|
||||||
text: 'Cohere',
|
text: 'Cohere',
|
||||||
|
@ -40,8 +40,8 @@ const validationSchema = Yup.object().shape({
|
|||||||
is_edit: Yup.boolean(),
|
is_edit: Yup.boolean(),
|
||||||
name: Yup.string().required('名称 不能为空'),
|
name: Yup.string().required('名称 不能为空'),
|
||||||
type: Yup.number().required('渠道 不能为空'),
|
type: Yup.number().required('渠道 不能为空'),
|
||||||
key: Yup.string().when('is_edit', {
|
key: Yup.string().when(['is_edit', 'type'], {
|
||||||
is: false,
|
is: (is_edit, type) => !is_edit && type !== 33,
|
||||||
then: Yup.string().required('密钥 不能为空')
|
then: Yup.string().required('密钥 不能为空')
|
||||||
}),
|
}),
|
||||||
other: Yup.string(),
|
other: Yup.string(),
|
||||||
@ -107,6 +107,8 @@ const EditModal = ({ open, channelId, onCancel, onOk }) => {
|
|||||||
if (localModels.length > 0 && Array.isArray(values['models']) && values['models'].length == 0) {
|
if (localModels.length > 0 && Array.isArray(values['models']) && values['models'].length == 0) {
|
||||||
setFieldValue('models', initialModel(localModels));
|
setFieldValue('models', initialModel(localModels));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setFieldValue('config', {});
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchGroups = async () => {
|
const fetchGroups = async () => {
|
||||||
@ -160,17 +162,25 @@ const EditModal = ({ open, channelId, onCancel, onOk }) => {
|
|||||||
if (values.type === 18 && values.other === '') {
|
if (values.type === 18 && values.other === '') {
|
||||||
values.other = 'v2.1';
|
values.other = 'v2.1';
|
||||||
}
|
}
|
||||||
|
if (values.key === '') {
|
||||||
|
if (values.config.ak !== '' && values.config.sk !== '' && values.config.region !== '') {
|
||||||
|
values.key = `${values.config.ak}|${values.config.sk}|${values.config.region}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let res;
|
let res;
|
||||||
const modelsStr = values.models.map((model) => model.id).join(',');
|
const modelsStr = values.models.map((model) => model.id).join(',');
|
||||||
|
const configStr = JSON.stringify(values.config);
|
||||||
values.group = values.groups.join(',');
|
values.group = values.groups.join(',');
|
||||||
if (channelId) {
|
if (channelId) {
|
||||||
res = await API.put(`/api/channel/`, {
|
res = await API.put(`/api/channel/`, {
|
||||||
...values,
|
...values,
|
||||||
id: parseInt(channelId),
|
id: parseInt(channelId),
|
||||||
models: modelsStr
|
models: modelsStr,
|
||||||
|
config: configStr
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res = await API.post(`/api/channel/`, { ...values, models: modelsStr });
|
res = await API.post(`/api/channel/`, { ...values, models: modelsStr, config: configStr });
|
||||||
}
|
}
|
||||||
const { success, message } = res.data;
|
const { success, message } = res.data;
|
||||||
if (success) {
|
if (success) {
|
||||||
@ -225,6 +235,10 @@ const EditModal = ({ open, channelId, onCancel, onOk }) => {
|
|||||||
if (data.model_mapping !== '') {
|
if (data.model_mapping !== '') {
|
||||||
data.model_mapping = JSON.stringify(JSON.parse(data.model_mapping), null, 2);
|
data.model_mapping = JSON.stringify(JSON.parse(data.model_mapping), null, 2);
|
||||||
}
|
}
|
||||||
|
if (data.config !== '') {
|
||||||
|
data.config = JSON.parse(data.config);
|
||||||
|
}
|
||||||
|
|
||||||
data.base_url = data.base_url ?? '';
|
data.base_url = data.base_url ?? '';
|
||||||
data.is_edit = true;
|
data.is_edit = true;
|
||||||
initChannel(data.type);
|
initChannel(data.type);
|
||||||
@ -485,55 +499,78 @@ const EditModal = ({ open, channelId, onCancel, onOk }) => {
|
|||||||
</Button>
|
</Button>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
</Container>
|
</Container>
|
||||||
<FormControl fullWidth error={Boolean(touched.key && errors.key)} sx={{ ...theme.typography.otherInput }}>
|
{inputLabel.key && (
|
||||||
{!batchAdd ? (
|
<>
|
||||||
<>
|
<FormControl fullWidth error={Boolean(touched.key && errors.key)} sx={{ ...theme.typography.otherInput }}>
|
||||||
<InputLabel htmlFor="channel-key-label">{inputLabel.key}</InputLabel>
|
{!batchAdd ? (
|
||||||
<OutlinedInput
|
<>
|
||||||
id="channel-key-label"
|
<InputLabel htmlFor="channel-key-label">{inputLabel.key}</InputLabel>
|
||||||
label={inputLabel.key}
|
<OutlinedInput
|
||||||
type="text"
|
id="channel-key-label"
|
||||||
value={values.key}
|
label={inputLabel.key}
|
||||||
name="key"
|
type="text"
|
||||||
onBlur={handleBlur}
|
value={values.key}
|
||||||
onChange={handleChange}
|
name="key"
|
||||||
inputProps={{}}
|
onBlur={handleBlur}
|
||||||
aria-describedby="helper-text-channel-key-label"
|
onChange={handleChange}
|
||||||
/>
|
inputProps={{}}
|
||||||
</>
|
aria-describedby="helper-text-channel-key-label"
|
||||||
) : (
|
/>
|
||||||
<TextField
|
</>
|
||||||
multiline
|
) : (
|
||||||
id="channel-key-label"
|
<TextField
|
||||||
label={inputLabel.key}
|
multiline
|
||||||
value={values.key}
|
id="channel-key-label"
|
||||||
name="key"
|
label={inputLabel.key}
|
||||||
onBlur={handleBlur}
|
value={values.key}
|
||||||
onChange={handleChange}
|
name="key"
|
||||||
aria-describedby="helper-text-channel-key-label"
|
onBlur={handleBlur}
|
||||||
minRows={5}
|
onChange={handleChange}
|
||||||
placeholder={inputPrompt.key + ',一行一个密钥'}
|
aria-describedby="helper-text-channel-key-label"
|
||||||
/>
|
minRows={5}
|
||||||
)}
|
placeholder={inputPrompt.key + ',一行一个密钥'}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{touched.key && errors.key ? (
|
{touched.key && errors.key ? (
|
||||||
<FormHelperText error id="helper-tex-channel-key-label">
|
<FormHelperText error id="helper-tex-channel-key-label">
|
||||||
{errors.key}
|
{errors.key}
|
||||||
</FormHelperText>
|
</FormHelperText>
|
||||||
) : (
|
) : (
|
||||||
<FormHelperText id="helper-tex-channel-key-label"> {inputPrompt.key} </FormHelperText>
|
<FormHelperText id="helper-tex-channel-key-label"> {inputPrompt.key} </FormHelperText>
|
||||||
)}
|
)}
|
||||||
</FormControl>
|
</FormControl>
|
||||||
{channelId === 0 && (
|
{channelId === 0 && (
|
||||||
<Container
|
<Container
|
||||||
sx={{
|
sx={{
|
||||||
textAlign: 'right'
|
textAlign: 'right'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Switch checked={batchAdd} onChange={(e) => setBatchAdd(e.target.checked)} />
|
<Switch checked={batchAdd} onChange={(e) => setBatchAdd(e.target.checked)} />
|
||||||
批量添加
|
批量添加
|
||||||
</Container>
|
</Container>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{inputLabel.config &&
|
||||||
|
Object.keys(inputLabel.config).map((configName) => {
|
||||||
|
return (
|
||||||
|
<FormControl key={'config.' + configName} fullWidth sx={{ ...theme.typography.otherInput }}>
|
||||||
|
<TextField
|
||||||
|
multiline
|
||||||
|
key={'config.' + configName}
|
||||||
|
name={'config.' + configName}
|
||||||
|
value={values.config?.[configName] || ''}
|
||||||
|
label={configName}
|
||||||
|
placeholder={inputPrompt.config[configName]}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
<FormHelperText id={`helper-tex-config.${configName}-label`}> {inputPrompt.config[configName]} </FormHelperText>
|
||||||
|
</FormControl>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
<FormControl fullWidth error={Boolean(touched.model_mapping && errors.model_mapping)} sx={{ ...theme.typography.otherInput }}>
|
<FormControl fullWidth error={Boolean(touched.model_mapping && errors.model_mapping)} sx={{ ...theme.typography.otherInput }}>
|
||||||
{/* <InputLabel htmlFor="channel-model_mapping-label">{inputLabel.model_mapping}</InputLabel> */}
|
{/* <InputLabel htmlFor="channel-model_mapping-label">{inputLabel.model_mapping}</InputLabel> */}
|
||||||
<TextField
|
<TextField
|
||||||
|
@ -1,177 +1,209 @@
|
|||||||
const defaultConfig = {
|
const defaultConfig = {
|
||||||
input: {
|
input: {
|
||||||
name: "",
|
name: '',
|
||||||
type: 1,
|
type: 1,
|
||||||
key: "",
|
key: '',
|
||||||
base_url: "",
|
base_url: '',
|
||||||
other: "",
|
other: '',
|
||||||
model_mapping: "",
|
model_mapping: '',
|
||||||
models: [],
|
models: [],
|
||||||
groups: ["default"],
|
groups: ['default'],
|
||||||
|
config: {}
|
||||||
},
|
},
|
||||||
inputLabel: {
|
inputLabel: {
|
||||||
name: "渠道名称",
|
name: '渠道名称',
|
||||||
type: "渠道类型",
|
type: '渠道类型',
|
||||||
base_url: "渠道API地址",
|
base_url: '渠道API地址',
|
||||||
key: "密钥",
|
key: '密钥',
|
||||||
other: "其他参数",
|
other: '其他参数',
|
||||||
models: "模型",
|
models: '模型',
|
||||||
model_mapping: "模型映射关系",
|
model_mapping: '模型映射关系',
|
||||||
groups: "用户组",
|
groups: '用户组',
|
||||||
|
config: null
|
||||||
},
|
},
|
||||||
prompt: {
|
prompt: {
|
||||||
type: "请选择渠道类型",
|
type: '请选择渠道类型',
|
||||||
name: "请为渠道命名",
|
name: '请为渠道命名',
|
||||||
base_url: "可空,请输入中转API地址,例如通过cloudflare中转",
|
base_url: '可空,请输入中转API地址,例如通过cloudflare中转',
|
||||||
key: "请输入渠道对应的鉴权密钥",
|
key: '请输入渠道对应的鉴权密钥',
|
||||||
other: "",
|
other: '',
|
||||||
models: "请选择该渠道所支持的模型",
|
models: '请选择该渠道所支持的模型',
|
||||||
model_mapping:
|
model_mapping:
|
||||||
'请输入要修改的模型映射关系,格式为:api请求模型ID:实际转发给渠道的模型ID,使用JSON数组表示,例如:{"gpt-3.5": "gpt-35"}',
|
'请输入要修改的模型映射关系,格式为:api请求模型ID:实际转发给渠道的模型ID,使用JSON数组表示,例如:{"gpt-3.5": "gpt-35"}',
|
||||||
groups: "请选择该渠道所支持的用户组",
|
groups: '请选择该渠道所支持的用户组',
|
||||||
|
config: null
|
||||||
},
|
},
|
||||||
modelGroup: "openai",
|
modelGroup: 'openai'
|
||||||
};
|
};
|
||||||
|
|
||||||
const typeConfig = {
|
const typeConfig = {
|
||||||
3: {
|
3: {
|
||||||
inputLabel: {
|
inputLabel: {
|
||||||
base_url: "AZURE_OPENAI_ENDPOINT",
|
base_url: 'AZURE_OPENAI_ENDPOINT',
|
||||||
other: "默认 API 版本",
|
other: '默认 API 版本'
|
||||||
},
|
},
|
||||||
prompt: {
|
prompt: {
|
||||||
base_url: "请填写AZURE_OPENAI_ENDPOINT",
|
base_url: '请填写AZURE_OPENAI_ENDPOINT',
|
||||||
other: "请输入默认API版本,例如:2024-03-01-preview",
|
other: '请输入默认API版本,例如:2024-03-01-preview'
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
11: {
|
11: {
|
||||||
input: {
|
input: {
|
||||||
models: ["PaLM-2"],
|
models: ['PaLM-2']
|
||||||
},
|
},
|
||||||
modelGroup: "google palm",
|
modelGroup: 'google palm'
|
||||||
},
|
},
|
||||||
14: {
|
14: {
|
||||||
input: {
|
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: {
|
15: {
|
||||||
input: {
|
input: {
|
||||||
models: ["ERNIE-Bot", "ERNIE-Bot-turbo", "ERNIE-Bot-4", "Embedding-V1"],
|
models: ['ERNIE-Bot', 'ERNIE-Bot-turbo', 'ERNIE-Bot-4', 'Embedding-V1']
|
||||||
},
|
},
|
||||||
prompt: {
|
prompt: {
|
||||||
key: "按照如下格式输入:APIKey|SecretKey",
|
key: '按照如下格式输入:APIKey|SecretKey'
|
||||||
},
|
},
|
||||||
modelGroup: "baidu",
|
modelGroup: 'baidu'
|
||||||
},
|
},
|
||||||
16: {
|
16: {
|
||||||
input: {
|
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: {
|
17: {
|
||||||
inputLabel: {
|
inputLabel: {
|
||||||
other: "插件参数",
|
other: '插件参数'
|
||||||
},
|
},
|
||||||
input: {
|
input: {
|
||||||
models: [
|
models: ['qwen-turbo', 'qwen-plus', 'qwen-max', 'qwen-max-longcontext', 'text-embedding-v1']
|
||||||
"qwen-turbo",
|
|
||||||
"qwen-plus",
|
|
||||||
"qwen-max",
|
|
||||||
"qwen-max-longcontext",
|
|
||||||
"text-embedding-v1",
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
prompt: {
|
prompt: {
|
||||||
other: "请输入插件参数,即 X-DashScope-Plugin 请求头的取值",
|
other: '请输入插件参数,即 X-DashScope-Plugin 请求头的取值'
|
||||||
},
|
},
|
||||||
modelGroup: "ali",
|
modelGroup: 'ali'
|
||||||
},
|
},
|
||||||
18: {
|
18: {
|
||||||
inputLabel: {
|
inputLabel: {
|
||||||
other: "版本号",
|
other: '版本号'
|
||||||
},
|
},
|
||||||
input: {
|
input: {
|
||||||
models: [
|
models: ['SparkDesk', 'SparkDesk-v1.1', 'SparkDesk-v2.1', 'SparkDesk-v3.1', 'SparkDesk-v3.5']
|
||||||
"SparkDesk",
|
|
||||||
'SparkDesk-v1.1',
|
|
||||||
'SparkDesk-v2.1',
|
|
||||||
'SparkDesk-v3.1',
|
|
||||||
'SparkDesk-v3.5'
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
prompt: {
|
prompt: {
|
||||||
key: "按照如下格式输入:APPID|APISecret|APIKey",
|
key: '按照如下格式输入:APPID|APISecret|APIKey',
|
||||||
other: "请输入版本号,例如:v3.1",
|
other: '请输入版本号,例如:v3.1'
|
||||||
},
|
},
|
||||||
modelGroup: "xunfei",
|
modelGroup: 'xunfei'
|
||||||
},
|
},
|
||||||
19: {
|
19: {
|
||||||
input: {
|
input: {
|
||||||
models: [
|
models: ['360GPT_S2_V9', 'embedding-bert-512-v1', 'embedding_s1_v1', 'semantic_similarity_s1_v1']
|
||||||
"360GPT_S2_V9",
|
|
||||||
"embedding-bert-512-v1",
|
|
||||||
"embedding_s1_v1",
|
|
||||||
"semantic_similarity_s1_v1",
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
modelGroup: "360",
|
modelGroup: '360'
|
||||||
},
|
},
|
||||||
22: {
|
22: {
|
||||||
prompt: {
|
prompt: {
|
||||||
key: "按照如下格式输入:APIKey-AppId,例如:fastgpt-0sp2gtvfdgyi4k30jwlgwf1i-64f335d84283f05518e9e041",
|
key: '按照如下格式输入:APIKey-AppId,例如:fastgpt-0sp2gtvfdgyi4k30jwlgwf1i-64f335d84283f05518e9e041'
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
23: {
|
23: {
|
||||||
input: {
|
input: {
|
||||||
models: ["hunyuan"],
|
models: ['hunyuan']
|
||||||
},
|
},
|
||||||
prompt: {
|
prompt: {
|
||||||
key: "按照如下格式输入:AppId|SecretId|SecretKey",
|
key: '按照如下格式输入:AppId|SecretId|SecretKey'
|
||||||
},
|
},
|
||||||
modelGroup: "tencent",
|
modelGroup: 'tencent'
|
||||||
},
|
},
|
||||||
24: {
|
24: {
|
||||||
inputLabel: {
|
inputLabel: {
|
||||||
other: "版本号",
|
other: '版本号'
|
||||||
},
|
},
|
||||||
input: {
|
input: {
|
||||||
models: ["gemini-pro"],
|
models: ['gemini-pro']
|
||||||
},
|
},
|
||||||
prompt: {
|
prompt: {
|
||||||
other: "请输入版本号,例如:v1",
|
other: '请输入版本号,例如:v1'
|
||||||
},
|
},
|
||||||
modelGroup: "google gemini",
|
modelGroup: 'google gemini'
|
||||||
},
|
},
|
||||||
25: {
|
25: {
|
||||||
input: {
|
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: {
|
26: {
|
||||||
input: {
|
input: {
|
||||||
models: ['Baichuan2-Turbo', 'Baichuan2-Turbo-192k', 'Baichuan-Text-Embedding'],
|
models: ['Baichuan2-Turbo', 'Baichuan2-Turbo-192k', 'Baichuan-Text-Embedding']
|
||||||
},
|
},
|
||||||
modelGroup: "baichuan",
|
modelGroup: 'baichuan'
|
||||||
},
|
},
|
||||||
27: {
|
27: {
|
||||||
input: {
|
input: {
|
||||||
models: ['abab5.5s-chat', 'abab5.5-chat', 'abab6-chat'],
|
models: ['abab5.5s-chat', 'abab5.5-chat', 'abab6-chat']
|
||||||
},
|
},
|
||||||
modelGroup: "minimax",
|
modelGroup: 'minimax'
|
||||||
},
|
},
|
||||||
29: {
|
29: {
|
||||||
modelGroup: "groq",
|
modelGroup: 'groq'
|
||||||
},
|
},
|
||||||
30: {
|
30: {
|
||||||
modelGroup: "ollama",
|
modelGroup: 'ollama'
|
||||||
},
|
},
|
||||||
31: {
|
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 };
|
export { defaultConfig, typeConfig };
|
||||||
|
Loading…
Reference in New Issue
Block a user