mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-04-19 19:48:39 +00:00
Merge pull request #2238 from seefs001/feature/doubao-coding-plan
feat: support doubao coding plan
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -17,6 +17,7 @@ tiktoken_cache
|
|||||||
.eslintcache
|
.eslintcache
|
||||||
.gocache
|
.gocache
|
||||||
.cache
|
.cache
|
||||||
|
web/bun.lock
|
||||||
|
|
||||||
electron/node_modules
|
electron/node_modules
|
||||||
electron/dist
|
electron/dist
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/QuantumNous/new-api/constant"
|
"github.com/QuantumNous/new-api/constant"
|
||||||
"github.com/QuantumNous/new-api/dto"
|
"github.com/QuantumNous/new-api/dto"
|
||||||
"github.com/QuantumNous/new-api/model"
|
"github.com/QuantumNous/new-api/model"
|
||||||
|
"github.com/QuantumNous/new-api/relay/channel/volcengine"
|
||||||
"github.com/QuantumNous/new-api/service"
|
"github.com/QuantumNous/new-api/service"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@@ -192,6 +193,12 @@ func FetchUpstreamModels(c *gin.Context) {
|
|||||||
url = fmt.Sprintf("%s/compatible-mode/v1/models", baseURL)
|
url = fmt.Sprintf("%s/compatible-mode/v1/models", baseURL)
|
||||||
case constant.ChannelTypeZhipu_v4:
|
case constant.ChannelTypeZhipu_v4:
|
||||||
url = fmt.Sprintf("%s/api/paas/v4/models", baseURL)
|
url = fmt.Sprintf("%s/api/paas/v4/models", baseURL)
|
||||||
|
case constant.ChannelTypeVolcEngine:
|
||||||
|
if baseURL == volcengine.DoubaoCodingPlan {
|
||||||
|
url = fmt.Sprintf("%s/v1/models", volcengine.DoubaoCodingPlanOpenAIBaseURL)
|
||||||
|
} else {
|
||||||
|
url = fmt.Sprintf("%s/v1/models", baseURL)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
url = fmt.Sprintf("%s/v1/models", baseURL)
|
url = fmt.Sprintf("%s/v1/models", baseURL)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ import (
|
|||||||
const (
|
const (
|
||||||
contextKeyTTSRequest = "volcengine_tts_request"
|
contextKeyTTSRequest = "volcengine_tts_request"
|
||||||
contextKeyResponseFormat = "response_format"
|
contextKeyResponseFormat = "response_format"
|
||||||
|
DoubaoCodingPlan = "doubao-coding-plan"
|
||||||
|
DoubaoCodingPlanClaudeBaseURL = "https://ark.cn-beijing.volces.com/api/coding"
|
||||||
|
DoubaoCodingPlanOpenAIBaseURL = "https://ark.cn-beijing.volces.com/api/coding/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Adaptor struct {
|
type Adaptor struct {
|
||||||
@@ -238,6 +241,9 @@ func (a *Adaptor) GetRequestURL(info *relaycommon.RelayInfo) (string, error) {
|
|||||||
|
|
||||||
switch info.RelayFormat {
|
switch info.RelayFormat {
|
||||||
case types.RelayFormatClaude:
|
case types.RelayFormatClaude:
|
||||||
|
if baseUrl == DoubaoCodingPlan {
|
||||||
|
return fmt.Sprintf("%s/v1/messages", DoubaoCodingPlanClaudeBaseURL), nil
|
||||||
|
}
|
||||||
if strings.HasPrefix(info.UpstreamModelName, "bot") {
|
if strings.HasPrefix(info.UpstreamModelName, "bot") {
|
||||||
return fmt.Sprintf("%s/api/v3/bots/chat/completions", baseUrl), nil
|
return fmt.Sprintf("%s/api/v3/bots/chat/completions", baseUrl), nil
|
||||||
}
|
}
|
||||||
@@ -245,6 +251,9 @@ func (a *Adaptor) GetRequestURL(info *relaycommon.RelayInfo) (string, error) {
|
|||||||
default:
|
default:
|
||||||
switch info.RelayMode {
|
switch info.RelayMode {
|
||||||
case constant.RelayModeChatCompletions:
|
case constant.RelayModeChatCompletions:
|
||||||
|
if baseUrl == DoubaoCodingPlan {
|
||||||
|
return fmt.Sprintf("%s/chat/completions", DoubaoCodingPlanOpenAIBaseURL), nil
|
||||||
|
}
|
||||||
if strings.HasPrefix(info.UpstreamModelName, "bot") {
|
if strings.HasPrefix(info.UpstreamModelName, "bot") {
|
||||||
return fmt.Sprintf("%s/api/v3/bots/chat/completions", baseUrl), nil
|
return fmt.Sprintf("%s/api/v3/bots/chat/completions", baseUrl), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -189,6 +189,7 @@ const EditChannelModal = (props) => {
|
|||||||
const [useManualInput, setUseManualInput] = useState(false); // 是否使用手动输入模式
|
const [useManualInput, setUseManualInput] = useState(false); // 是否使用手动输入模式
|
||||||
const [keyMode, setKeyMode] = useState('append'); // 密钥模式:replace(覆盖)或 append(追加)
|
const [keyMode, setKeyMode] = useState('append'); // 密钥模式:replace(覆盖)或 append(追加)
|
||||||
const [isEnterpriseAccount, setIsEnterpriseAccount] = useState(false); // 是否为企业账户
|
const [isEnterpriseAccount, setIsEnterpriseAccount] = useState(false); // 是否为企业账户
|
||||||
|
const [doubaoApiEditUnlocked, setDoubaoApiEditUnlocked] = useState(false); // 豆包渠道自定义 API 地址隐藏入口
|
||||||
|
|
||||||
// 密钥显示状态
|
// 密钥显示状态
|
||||||
const [keyDisplayState, setKeyDisplayState] = useState({
|
const [keyDisplayState, setKeyDisplayState] = useState({
|
||||||
@@ -218,6 +219,7 @@ const EditChannelModal = (props) => {
|
|||||||
'channelExtraSettings',
|
'channelExtraSettings',
|
||||||
];
|
];
|
||||||
const formContainerRef = useRef(null);
|
const formContainerRef = useRef(null);
|
||||||
|
const doubaoApiClickCountRef = useRef(0);
|
||||||
|
|
||||||
// 2FA状态更新辅助函数
|
// 2FA状态更新辅助函数
|
||||||
const updateTwoFAState = (updates) => {
|
const updateTwoFAState = (updates) => {
|
||||||
@@ -306,6 +308,20 @@ const EditChannelModal = (props) => {
|
|||||||
scrollToSection(availableSections[newIndex]);
|
scrollToSection(availableSections[newIndex]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleApiConfigSecretClick = () => {
|
||||||
|
if (inputs.type !== 45) return;
|
||||||
|
const next = doubaoApiClickCountRef.current + 1;
|
||||||
|
doubaoApiClickCountRef.current = next;
|
||||||
|
if (next >= 10) {
|
||||||
|
setDoubaoApiEditUnlocked((unlocked) => {
|
||||||
|
if (!unlocked) {
|
||||||
|
showInfo(t('已解锁豆包自定义 API 地址编辑'));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 渠道额外设置状态
|
// 渠道额外设置状态
|
||||||
const [channelSettings, setChannelSettings] = useState({
|
const [channelSettings, setChannelSettings] = useState({
|
||||||
force_format: false,
|
force_format: false,
|
||||||
@@ -724,6 +740,13 @@ const EditChannelModal = (props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (inputs.type !== 45) {
|
||||||
|
doubaoApiClickCountRef.current = 0;
|
||||||
|
setDoubaoApiEditUnlocked(false);
|
||||||
|
}
|
||||||
|
}, [inputs.type]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const modelMap = new Map();
|
const modelMap = new Map();
|
||||||
|
|
||||||
@@ -823,6 +846,9 @@ const EditChannelModal = (props) => {
|
|||||||
setKeyMode('append');
|
setKeyMode('append');
|
||||||
// 重置企业账户状态
|
// 重置企业账户状态
|
||||||
setIsEnterpriseAccount(false);
|
setIsEnterpriseAccount(false);
|
||||||
|
// 重置豆包隐藏入口状态
|
||||||
|
setDoubaoApiEditUnlocked(false);
|
||||||
|
doubaoApiClickCountRef.current = 0;
|
||||||
// 清空表单中的key_mode字段
|
// 清空表单中的key_mode字段
|
||||||
if (formApiRef.current) {
|
if (formApiRef.current) {
|
||||||
formApiRef.current.setValue('key_mode', undefined);
|
formApiRef.current.setValue('key_mode', undefined);
|
||||||
@@ -1959,7 +1985,10 @@ const EditChannelModal = (props) => {
|
|||||||
<div ref={(el) => (formSectionRefs.current.apiConfig = el)}>
|
<div ref={(el) => (formSectionRefs.current.apiConfig = el)}>
|
||||||
<Card className='!rounded-2xl shadow-sm border-0 mb-6'>
|
<Card className='!rounded-2xl shadow-sm border-0 mb-6'>
|
||||||
{/* Header: API Config */}
|
{/* Header: API Config */}
|
||||||
<div className='flex items-center mb-2'>
|
<div
|
||||||
|
className='flex items-center mb-2'
|
||||||
|
onClick={handleApiConfigSecretClick}
|
||||||
|
>
|
||||||
<Avatar
|
<Avatar
|
||||||
size='small'
|
size='small'
|
||||||
color='green'
|
color='green'
|
||||||
@@ -2094,7 +2123,7 @@ const EditChannelModal = (props) => {
|
|||||||
inputs.type !== 8 &&
|
inputs.type !== 8 &&
|
||||||
inputs.type !== 22 &&
|
inputs.type !== 22 &&
|
||||||
inputs.type !== 36 &&
|
inputs.type !== 36 &&
|
||||||
inputs.type !== 45 && (
|
(inputs.type !== 45 || doubaoApiEditUnlocked) && (
|
||||||
<div>
|
<div>
|
||||||
<Form.Input
|
<Form.Input
|
||||||
field='base_url'
|
field='base_url'
|
||||||
@@ -2147,7 +2176,7 @@ const EditChannelModal = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{inputs.type === 45 && (
|
{inputs.type === 45 && !doubaoApiEditUnlocked && (
|
||||||
<div>
|
<div>
|
||||||
<Form.Select
|
<Form.Select
|
||||||
field='base_url'
|
field='base_url'
|
||||||
@@ -2167,6 +2196,10 @@ const EditChannelModal = (props) => {
|
|||||||
label:
|
label:
|
||||||
'https://ark.ap-southeast.bytepluses.com',
|
'https://ark.ap-southeast.bytepluses.com',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
value: 'doubao-coding-plan',
|
||||||
|
label: 'Doubao Coding Plan',
|
||||||
|
},
|
||||||
]}
|
]}
|
||||||
defaultValue='https://ark.cn-beijing.volces.com'
|
defaultValue='https://ark.cn-beijing.volces.com'
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user