@@ -53,11 +53,11 @@ const ChannelsTable = () => {
|
||||
for (let i = 0; i < CHANNEL_OPTIONS.length; i++) {
|
||||
type2label[CHANNEL_OPTIONS[i].value] = CHANNEL_OPTIONS[i];
|
||||
}
|
||||
type2label[0] = { value: 0, text: t('未知类型'), color: 'grey' };
|
||||
type2label[0] = { value: 0, label: t('未知类型'), color: 'grey' };
|
||||
}
|
||||
return (
|
||||
<Tag size="large" color={type2label[type]?.color}>
|
||||
{type2label[type]?.text}
|
||||
{type2label[type]?.label}
|
||||
</Tag>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,134 +1,123 @@
|
||||
export const CHANNEL_OPTIONS = [
|
||||
{ key: 1, text: 'OpenAI', value: 1, color: 'green', label: 'OpenAI' },
|
||||
{ key: 1, value: 1, color: 'green', label: 'OpenAI' },
|
||||
{
|
||||
key: 2,
|
||||
text: 'Midjourney Proxy',
|
||||
value: 2,
|
||||
color: 'light-blue',
|
||||
label: 'Midjourney Proxy'
|
||||
},
|
||||
{
|
||||
key: 5,
|
||||
text: 'Midjourney Proxy Plus',
|
||||
value: 5,
|
||||
color: 'blue',
|
||||
label: 'Midjourney Proxy Plus'
|
||||
},
|
||||
{
|
||||
key: 36,
|
||||
text: 'Suno API',
|
||||
value: 36,
|
||||
color: 'purple',
|
||||
label: 'Suno API'
|
||||
},
|
||||
{ key: 4, text: 'Ollama', value: 4, color: 'grey', label: 'Ollama' },
|
||||
{ key: 4, value: 4, color: 'grey', label: 'Ollama' },
|
||||
{
|
||||
key: 14,
|
||||
text: 'Anthropic Claude',
|
||||
value: 14,
|
||||
color: 'indigo',
|
||||
label: 'Anthropic Claude'
|
||||
},
|
||||
{
|
||||
key: 33,
|
||||
text: 'AWS Claude',
|
||||
value: 33,
|
||||
color: 'indigo',
|
||||
label: 'AWS Claude'
|
||||
},
|
||||
{ key: 41, text: 'Vertex AI', value: 41, color: 'blue', label: 'Vertex AI' },
|
||||
{ key: 41, value: 41, color: 'blue', label: 'Vertex AI' },
|
||||
{
|
||||
key: 3,
|
||||
text: 'Azure OpenAI',
|
||||
value: 3,
|
||||
color: 'teal',
|
||||
label: 'Azure OpenAI'
|
||||
},
|
||||
{
|
||||
key: 34,
|
||||
text: 'Cohere',
|
||||
value: 34,
|
||||
color: 'purple',
|
||||
label: 'Cohere'
|
||||
},
|
||||
{ key: 39, text: 'Cloudflare', value: 39, color: 'grey', label: 'Cloudflare' },
|
||||
{ key: 43, text: 'DeepSeek', value: 43, color: 'blue', label: 'DeepSeek' },
|
||||
{ key: 39, value: 39, color: 'grey', label: 'Cloudflare' },
|
||||
{ key: 43, value: 43, color: 'blue', label: 'DeepSeek' },
|
||||
{
|
||||
key: 15,
|
||||
text: '百度文心千帆',
|
||||
value: 15,
|
||||
color: 'blue',
|
||||
label: '百度文心千帆'
|
||||
},
|
||||
{
|
||||
key: 17,
|
||||
text: '阿里通义千问',
|
||||
value: 17,
|
||||
color: 'orange',
|
||||
label: '阿里通义千问'
|
||||
},
|
||||
{
|
||||
key: 18,
|
||||
text: '讯飞星火认知',
|
||||
value: 18,
|
||||
color: 'blue',
|
||||
label: '讯飞星火认知'
|
||||
},
|
||||
{
|
||||
key: 16,
|
||||
text: '智谱 ChatGLM',
|
||||
value: 16,
|
||||
color: 'violet',
|
||||
label: '智谱 ChatGLM'
|
||||
},
|
||||
{
|
||||
key: 26,
|
||||
text: '智谱 GLM-4V',
|
||||
value: 26,
|
||||
color: 'purple',
|
||||
label: '智谱 GLM-4V'
|
||||
},
|
||||
{
|
||||
key: 24,
|
||||
text: 'Google Gemini',
|
||||
value: 24,
|
||||
color: 'orange',
|
||||
label: 'Google Gemini'
|
||||
},
|
||||
{
|
||||
key: 11,
|
||||
text: 'Google PaLM2',
|
||||
value: 11,
|
||||
color: 'orange',
|
||||
label: 'Google PaLM2'
|
||||
},
|
||||
{ key: 25, text: 'Moonshot', value: 25, color: 'green', label: 'Moonshot' },
|
||||
{ key: 19, text: '360 智脑', value: 19, color: 'blue', label: '360 智脑' },
|
||||
{ key: 23, text: '腾讯混元', value: 23, color: 'teal', label: '腾讯混元' },
|
||||
{ key: 31, text: '零一万物', value: 31, color: 'green', label: '零一万物' },
|
||||
{ key: 35, text: 'MiniMax', value: 35, color: 'green', label: 'MiniMax' },
|
||||
{ key: 37, text: 'Dify', value: 37, color: 'teal', label: 'Dify' },
|
||||
{ key: 38, text: 'Jina', value: 38, color: 'blue', label: 'Jina' },
|
||||
{ key: 40, text: 'SiliconCloud', value: 40, color: 'purple', label: 'SiliconCloud' },
|
||||
{ key: 42, text: 'Mistral AI', value: 42, color: 'blue', label: 'Mistral AI' },
|
||||
{ key: 8, text: '自定义渠道', value: 8, color: 'pink', label: '自定义渠道' },
|
||||
{
|
||||
key: 48,
|
||||
value: 48,
|
||||
color: 'blue',
|
||||
label: '火山方舟(豆包)'
|
||||
},
|
||||
{ key: 25, value: 25, color: 'green', label: 'Moonshot' },
|
||||
{ key: 19, value: 19, color: 'blue', label: '360 智脑' },
|
||||
{ key: 23, value: 23, color: 'teal', label: '腾讯混元' },
|
||||
{ key: 31, value: 31, color: 'green', label: '零一万物' },
|
||||
{ key: 35, value: 35, color: 'green', label: 'MiniMax' },
|
||||
{ key: 37, value: 37, color: 'teal', label: 'Dify' },
|
||||
{ key: 38, value: 38, color: 'blue', label: 'Jina' },
|
||||
{ key: 40, value: 40, color: 'purple', label: 'SiliconCloud' },
|
||||
{ key: 42, value: 42, color: 'blue', label: 'Mistral AI' },
|
||||
{ key: 8, value: 8, color: 'pink', label: '自定义渠道' },
|
||||
{
|
||||
key: 22,
|
||||
text: '知识库:FastGPT',
|
||||
value: 22,
|
||||
color: 'blue',
|
||||
label: '知识库:FastGPT'
|
||||
},
|
||||
{
|
||||
key: 21,
|
||||
text: '知识库:AI Proxy',
|
||||
value: 21,
|
||||
color: 'purple',
|
||||
label: '知识库:AI Proxy'
|
||||
},
|
||||
{
|
||||
key: 47,
|
||||
text: '嵌入模型:MokaAI M3E',
|
||||
value: 47,
|
||||
color: 'purple',
|
||||
label: '嵌入模型:MokaAI M3E'
|
||||
|
||||
@@ -498,8 +498,7 @@
|
||||
"请输入用户名": "Please enter username",
|
||||
"请输入显示名称": "Please enter display name",
|
||||
"请输入密码": "Please enter password",
|
||||
"模型部署名称必须和模型名称保持一致": "The model deployment name must be consistent with the model name",
|
||||
",因为 One API 会把请求体中的 model": ", because One API will take the model in the request body",
|
||||
"注意,模型部署名称必须和模型名称保持一致": "Note that the model deployment name must be consistent with the model name",
|
||||
"请输入 AZURE_OPENAI_ENDPOINT": "Please enter AZURE_OPENAI_ENDPOINT",
|
||||
"请输入自定义渠道的 Base URL": "Please enter the Base URL of the custom channel",
|
||||
"Homepage URL 填": "Fill in the Homepage URL",
|
||||
|
||||
@@ -438,13 +438,16 @@ const EditChannel = (props) => {
|
||||
value={inputs.type}
|
||||
onChange={(value) => handleInputChange('type', value)}
|
||||
style={{ width: '50%' }}
|
||||
filter
|
||||
searchPosition='dropdown'
|
||||
placeholder={t('请选择渠道类型')}
|
||||
/>
|
||||
{inputs.type === 3 && (
|
||||
<>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Banner
|
||||
type={'warning'}
|
||||
description={t('注意,模型部署名称必须和模型名称保持一致,因为 One API 会把请求体中的 model 参数替换为你的部署名称(模型名称中的点会被剔除)')}
|
||||
description={t('注意,模型部署名称必须和模型名称保持一致')}
|
||||
></Banner>
|
||||
</div>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
@@ -501,6 +504,19 @@ const EditChannel = (props) => {
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>{t('名称')}:</Typography.Text>
|
||||
</div>
|
||||
<Input
|
||||
required
|
||||
name="name"
|
||||
placeholder={t('请为渠道命名')}
|
||||
onChange={(value) => {
|
||||
handleInputChange('name', value);
|
||||
}}
|
||||
value={inputs.name}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
{inputs.type !== 3 && inputs.type !== 8 && inputs.type !== 22 && inputs.type !== 36 && (
|
||||
<>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
@@ -518,6 +534,77 @@ const EditChannel = (props) => {
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>{t('密钥')}:</Typography.Text>
|
||||
</div>
|
||||
{batch ? (
|
||||
<TextArea
|
||||
label={t('密钥')}
|
||||
name="key"
|
||||
required
|
||||
placeholder={t('请输入密钥,一行一个')}
|
||||
onChange={(value) => {
|
||||
handleInputChange('key', value);
|
||||
}}
|
||||
value={inputs.key}
|
||||
style={{ minHeight: 150, fontFamily: 'JetBrains Mono, Consolas' }}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
{inputs.type === 41 ? (
|
||||
<TextArea
|
||||
label={t('鉴权json')}
|
||||
name="key"
|
||||
required
|
||||
placeholder={'{\n' +
|
||||
' "type": "service_account",\n' +
|
||||
' "project_id": "abc-bcd-123-456",\n' +
|
||||
' "private_key_id": "123xxxxx456",\n' +
|
||||
' "private_key": "-----BEGIN PRIVATE KEY-----xxxx\n' +
|
||||
' "client_email": "xxx@developer.gserviceaccount.com",\n' +
|
||||
' "client_id": "111222333",\n' +
|
||||
' "auth_uri": "https://accounts.google.com/o/oauth2/auth",\n' +
|
||||
' "token_uri": "https://oauth2.googleapis.com/token",\n' +
|
||||
' "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",\n' +
|
||||
' "client_x509_cert_url": "https://xxxxx.gserviceaccount.com",\n' +
|
||||
' "universe_domain": "googleapis.com"\n' +
|
||||
'}'}
|
||||
onChange={(value) => {
|
||||
handleInputChange('key', value);
|
||||
}}
|
||||
autosize={{ minRows: 10 }}
|
||||
value={inputs.key}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
) : (
|
||||
<Input
|
||||
label={t('密钥')}
|
||||
name="key"
|
||||
required
|
||||
placeholder={t(type2secretPrompt(inputs.type))}
|
||||
onChange={(value) => {
|
||||
handleInputChange('key', value);
|
||||
}}
|
||||
value={inputs.key}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{!isEdit && (
|
||||
<div style={{ marginTop: 10, display: 'flex' }}>
|
||||
<Space>
|
||||
<Checkbox
|
||||
checked={batch}
|
||||
label={t('批量创建')}
|
||||
name="batch"
|
||||
onChange={() => setBatch(!batch)}
|
||||
/>
|
||||
<Typography.Text strong>{t('批量创建')}</Typography.Text>
|
||||
</Space>
|
||||
</div>
|
||||
)}
|
||||
{inputs.type === 22 && (
|
||||
<>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
@@ -552,19 +639,6 @@ const EditChannel = (props) => {
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>{t('名称')}:</Typography.Text>
|
||||
</div>
|
||||
<Input
|
||||
required
|
||||
name="name"
|
||||
placeholder={t('请为渠道命名')}
|
||||
onChange={(value) => {
|
||||
handleInputChange('name', value);
|
||||
}}
|
||||
value={inputs.name}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>{t('分组')}:</Typography.Text>
|
||||
</div>
|
||||
@@ -640,7 +714,7 @@ const EditChannel = (props) => {
|
||||
{inputs.type === 21 && (
|
||||
<>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong><EFBFBD><EFBFBD>识库 ID:</Typography.Text>
|
||||
<Typography.Text strong>知识库 ID:</Typography.Text>
|
||||
</div>
|
||||
<Input
|
||||
label="知识库 ID"
|
||||
@@ -768,149 +842,6 @@ const EditChannel = (props) => {
|
||||
>
|
||||
{t('填入模板')}
|
||||
</Typography.Text>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>{t('密钥')}:</Typography.Text>
|
||||
</div>
|
||||
{batch ? (
|
||||
<TextArea
|
||||
label={t('密钥')}
|
||||
name="key"
|
||||
required
|
||||
placeholder={t('请输入密钥,一行一个')}
|
||||
onChange={(value) => {
|
||||
handleInputChange('key', value);
|
||||
}}
|
||||
value={inputs.key}
|
||||
style={{ minHeight: 150, fontFamily: 'JetBrains Mono, Consolas' }}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
{inputs.type === 41 ? (
|
||||
<TextArea
|
||||
label={t('鉴权json')}
|
||||
name="key"
|
||||
required
|
||||
placeholder={'{\n' +
|
||||
' "type": "service_account",\n' +
|
||||
' "project_id": "abc-bcd-123-456",\n' +
|
||||
' "private_key_id": "123xxxxx456",\n' +
|
||||
' "private_key": "-----BEGIN PRIVATE KEY-----xxxx\n' +
|
||||
' "client_email": "xxx@developer.gserviceaccount.com",\n' +
|
||||
' "client_id": "111222333",\n' +
|
||||
' "auth_uri": "https://accounts.google.com/o/oauth2/auth",\n' +
|
||||
' "token_uri": "https://oauth2.googleapis.com/token",\n' +
|
||||
' "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",\n' +
|
||||
' "client_x509_cert_url": "https://xxxxx.gserviceaccount.com",\n' +
|
||||
' "universe_domain": "googleapis.com"\n' +
|
||||
'}'}
|
||||
onChange={(value) => {
|
||||
handleInputChange('key', value);
|
||||
}}
|
||||
autosize={{ minRows: 10 }}
|
||||
value={inputs.key}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
) : (
|
||||
<Input
|
||||
label={t('密钥')}
|
||||
name="key"
|
||||
required
|
||||
placeholder={t(type2secretPrompt(inputs.type))}
|
||||
onChange={(value) => {
|
||||
handleInputChange('key', value);
|
||||
}}
|
||||
value={inputs.key}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{!isEdit && (
|
||||
<div style={{ marginTop: 10, display: 'flex' }}>
|
||||
<Space>
|
||||
<Checkbox
|
||||
checked={batch}
|
||||
label={t('批量创建')}
|
||||
name="batch"
|
||||
onChange={() => setBatch(!batch)}
|
||||
/>
|
||||
<Typography.Text strong>{t('批量创建')}</Typography.Text>
|
||||
</Space>
|
||||
</div>
|
||||
)}
|
||||
{inputs.type === 1 && (
|
||||
<>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>{t('组织')}:</Typography.Text>
|
||||
</div>
|
||||
<Input
|
||||
label={t('组织,可选,不填则为默认组织')}
|
||||
name="openai_organization"
|
||||
placeholder={t('请输入组织org-xxx')}
|
||||
onChange={(value) => {
|
||||
handleInputChange('openai_organization', value);
|
||||
}}
|
||||
value={inputs.openai_organization}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>{t('默认测试模型')}:</Typography.Text>
|
||||
</div>
|
||||
<Input
|
||||
name="test_model"
|
||||
placeholder={t('不填则为模型列表第一个')}
|
||||
onChange={(value) => {
|
||||
handleInputChange('test_model', value);
|
||||
}}
|
||||
value={inputs.test_model}
|
||||
/>
|
||||
<div style={{ marginTop: 10, display: 'flex' }}>
|
||||
<Space>
|
||||
<Checkbox
|
||||
name="auto_ban"
|
||||
checked={autoBan}
|
||||
onChange={() => {
|
||||
setAutoBan(!autoBan);
|
||||
}}
|
||||
/>
|
||||
<Typography.Text strong>
|
||||
{t('是否自动禁用(仅当自动禁用开启时有效),关闭后不会自动禁用该渠道:')}
|
||||
</Typography.Text>
|
||||
</Space>
|
||||
</div>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>
|
||||
{t('状态码复写(仅影响本地判断,不修改返回到上游的状态码)')}:
|
||||
</Typography.Text>
|
||||
</div>
|
||||
<TextArea
|
||||
placeholder={t('此项可选,用于复写返回的状态码,比如将claude渠道的400错误复写为500(用于重试),请勿滥用该功能,例如:') +
|
||||
'\n' + JSON.stringify(STATUS_CODE_MAPPING_EXAMPLE, null, 2)}
|
||||
name="status_code_mapping"
|
||||
onChange={(value) => {
|
||||
handleInputChange('status_code_mapping', value);
|
||||
}}
|
||||
autosize
|
||||
value={inputs.status_code_mapping}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
<Typography.Text
|
||||
style={{
|
||||
color: 'rgba(var(--semi-blue-5), 1)',
|
||||
userSelect: 'none',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
onClick={() => {
|
||||
handleInputChange(
|
||||
'status_code_mapping',
|
||||
JSON.stringify(STATUS_CODE_MAPPING_EXAMPLE, null, 2)
|
||||
);
|
||||
}}
|
||||
>
|
||||
{t('填入模板')}
|
||||
</Typography.Text>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>
|
||||
{t('渠道标签')}
|
||||
@@ -1014,6 +945,78 @@ const EditChannel = (props) => {
|
||||
</Typography.Text>
|
||||
</Space>
|
||||
</>
|
||||
{inputs.type === 1 && (
|
||||
<>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>{t('组织')}:</Typography.Text>
|
||||
</div>
|
||||
<Input
|
||||
label={t('组织,可选,不填则为默认组织')}
|
||||
name="openai_organization"
|
||||
placeholder={t('请输入组织org-xxx')}
|
||||
onChange={(value) => {
|
||||
handleInputChange('openai_organization', value);
|
||||
}}
|
||||
value={inputs.openai_organization}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>{t('默认测试模型')}:</Typography.Text>
|
||||
</div>
|
||||
<Input
|
||||
name="test_model"
|
||||
placeholder={t('不填则为模型列表第一个')}
|
||||
onChange={(value) => {
|
||||
handleInputChange('test_model', value);
|
||||
}}
|
||||
value={inputs.test_model}
|
||||
/>
|
||||
<div style={{ marginTop: 10, display: 'flex' }}>
|
||||
<Space>
|
||||
<Checkbox
|
||||
name="auto_ban"
|
||||
checked={autoBan}
|
||||
onChange={() => {
|
||||
setAutoBan(!autoBan);
|
||||
}}
|
||||
/>
|
||||
<Typography.Text strong>
|
||||
{t('是否自动禁用(仅当自动禁用开启时有效),关闭后不会自动禁用该渠道:')}
|
||||
</Typography.Text>
|
||||
</Space>
|
||||
</div>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>
|
||||
{t('状态码复写(仅影响本地判断,不修改返回到上游的状态码)')}:
|
||||
</Typography.Text>
|
||||
</div>
|
||||
<TextArea
|
||||
placeholder={t('此项可选,用于复写返回的状态码,比如将claude渠道的400错误复写为500(用于重试),请勿滥用该功能,例如:') +
|
||||
'\n' + JSON.stringify(STATUS_CODE_MAPPING_EXAMPLE, null, 2)}
|
||||
name="status_code_mapping"
|
||||
onChange={(value) => {
|
||||
handleInputChange('status_code_mapping', value);
|
||||
}}
|
||||
autosize
|
||||
value={inputs.status_code_mapping}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
<Typography.Text
|
||||
style={{
|
||||
color: 'rgba(var(--semi-blue-5), 1)',
|
||||
userSelect: 'none',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
onClick={() => {
|
||||
handleInputChange(
|
||||
'status_code_mapping',
|
||||
JSON.stringify(STATUS_CODE_MAPPING_EXAMPLE, null, 2)
|
||||
);
|
||||
}}
|
||||
>
|
||||
{t('填入模板')}
|
||||
</Typography.Text>
|
||||
</Spin>
|
||||
</SideSheet>
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user