Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
D
dify
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ai-tech
dify
Commits
85df761a
Commit
85df761a
authored
Jul 15, 2023
by
Joel
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'feat/support-claude' into deploy/dev
parents
62d3eeb4
8083df00
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
324 additions
and
7 deletions
+324
-7
index.module.css
.../provider-page/anthropic-hosted-provider/index.module.css
+24
-0
index.tsx
...setting/provider-page/anthropic-hosted-provider/index.tsx
+65
-0
index.module.css
...setting/provider-page/anthropic-provider/index.module.css
+0
-0
index.tsx
...ccount-setting/provider-page/anthropic-provider/index.tsx
+90
-0
index.tsx
...components/header/account-setting/provider-page/index.tsx
+18
-0
index.tsx
...der/account-setting/provider-page/provider-item/index.tsx
+88
-5
common.en.ts
web/i18n/lang/common.en.ts
+16
-0
common.zh.ts
web/i18n/lang/common.zh.ts
+16
-0
common.ts
web/models/common.ts
+5
-0
common.ts
web/service/common.ts
+2
-2
No files found.
web/app/components/header/account-setting/provider-page/anthropic-hosted-provider/index.module.css
0 → 100644
View file @
85df761a
.icon
{
width
:
24px
;
height
:
24px
;
margin-right
:
12px
;
background
:
url(../../../assets/anthropic.svg)
center
center
no-repeat
;
background-size
:
contain
;
}
.bar
{
background
:
linear-gradient
(
90deg
,
rgba
(
41
,
112
,
255
,
0.9
)
0%
,
rgba
(
21
,
94
,
239
,
0.9
)
100%
);
}
.bar-error
{
background
:
linear-gradient
(
90deg
,
rgba
(
240
,
68
,
56
,
0.72
)
0%
,
rgba
(
217
,
45
,
32
,
0.9
)
100%
);
}
.bar-item
{
width
:
10%
;
border-right
:
1px
solid
rgba
(
255
,
255
,
255
,
0.5
);
}
.bar-item
:last-of-type
{
border-right
:
0
;
}
\ No newline at end of file
web/app/components/header/account-setting/provider-page/anthropic-hosted-provider/index.tsx
0 → 100644
View file @
85df761a
import
{
useTranslation
}
from
'react-i18next'
import
cn
from
'classnames'
import
s
from
'./index.module.css'
import
type
{
ProviderHosted
}
from
'@/models/common'
type
AnthropicHostedProviderProps
=
{
provider
:
ProviderHosted
}
const
AnthropicHostedProvider
=
({
provider
,
}:
AnthropicHostedProviderProps
)
=>
{
const
{
t
}
=
useTranslation
()
const
exhausted
=
provider
.
quota_used
>
provider
.
quota_limit
return
(
<
div
className=
{
`
border-[0.5px] border-gray-200 rounded-xl
${exhausted ? 'bg-[#FFFBFA]' : 'bg-gray-50'}
`
}
>
<
div
className=
'pt-4 px-4 pb-3'
>
<
div
className=
'flex items-center mb-3'
>
<
div
className=
{
s
.
icon
}
/>
<
div
className=
'grow text-sm font-medium text-gray-800'
>
{
t
(
'common.provider.anthropicHosted.anthropicHosted'
)
}
</
div
>
<
div
className=
{
`
px-2 h-[22px] flex items-center rounded-md border
text-xs font-semibold
${exhausted ? 'border-[#D92D20] text-[#D92D20]' : 'border-primary-600 text-primary-600'}
`
}
>
{
exhausted
?
t
(
'common.provider.anthropicHosted.exhausted'
)
:
t
(
'common.provider.anthropicHosted.onTrial'
)
}
</
div
>
</
div
>
<
div
className=
'text-[13px] text-gray-500'
>
{
t
(
'common.provider.anthropicHosted.desc'
)
}
</
div
>
</
div
>
<
div
className=
'flex items-center h-[42px] px-4 border-t-[0.5px] border-t-[rgba(0, 0, 0, 0.05)]'
>
<
div
className=
'text-[13px] text-gray-700'
>
{
t
(
'common.provider.anthropicHosted.callTimes'
)
}
</
div
>
<
div
className=
'relative grow h-2 flex bg-gray-200 rounded-md mx-2 overflow-hidden'
>
<
div
className=
{
cn
(
s
.
bar
,
exhausted
&&
s
[
'bar-error'
],
'absolute top-0 left-0 right-0 bottom-0'
)
}
style=
{
{
width
:
`${(provider.quota_used / provider.quota_limit * 100).toFixed(2)}%`
}
}
/>
{
Array
(
10
).
fill
(
0
).
map
((
i
,
k
)
=>
(
<
div
key=
{
k
}
className=
{
s
[
'bar-item'
]
}
/>
))
}
</
div
>
<
div
className=
{
`
text-[13px] font-medium ${exhausted ? 'text-[#D92D20]' : 'text-gray-700'}
`
}
>
{
provider
.
quota_used
}
/
{
provider
.
quota_limit
}
</
div
>
</
div
>
{
exhausted
&&
(
<
div
className=
'
px-4 py-3 leading-[18px] flex items-center text-[13px] text-gray-700 font-medium
bg-[#FFFAEB] border-t border-t-[rgba(0, 0, 0, 0.05)] rounded-b-xl
'
>
{
t
(
'common.provider.anthropicHosted.usedUp'
)
}
</
div
>
)
}
</
div
>
)
}
export
default
AnthropicHostedProvider
web/app/components/header/account-setting/provider-page/anthropic-provider/index.module.css
0 → 100644
View file @
85df761a
web/app/components/header/account-setting/provider-page/anthropic-provider/index.tsx
0 → 100644
View file @
85df761a
import
{
useEffect
,
useState
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
Link
from
'next/link'
import
{
ArrowTopRightOnSquareIcon
}
from
'@heroicons/react/24/outline'
import
ProviderInput
from
'../provider-input'
import
type
{
ValidatedStatusState
}
from
'../provider-input/useValidateToken'
import
useValidateToken
,
{
ValidatedStatus
}
from
'../provider-input/useValidateToken'
import
{
ValidatedErrorIcon
,
ValidatedErrorOnOpenaiTip
,
ValidatedSuccessIcon
,
ValidatingTip
,
}
from
'../provider-input/Validate'
import
type
{
Provider
,
ProviderAnthropicToken
}
from
'@/models/common'
type
AnthropicProviderProps
=
{
provider
:
Provider
onValidatedStatus
:
(
status
?:
ValidatedStatusState
)
=>
void
onTokenChange
:
(
token
:
ProviderAnthropicToken
)
=>
void
}
const
AnthropicProvider
=
({
provider
,
onValidatedStatus
,
onTokenChange
,
}:
AnthropicProviderProps
)
=>
{
const
{
t
}
=
useTranslation
()
const
[
token
,
setToken
]
=
useState
<
ProviderAnthropicToken
>
((
provider
.
token
as
ProviderAnthropicToken
)
||
{
anthropic_api_key
:
''
})
const
[
validating
,
validatedStatus
,
setValidatedStatus
,
validate
]
=
useValidateToken
(
provider
.
provider_name
)
const
handleFocus
=
()
=>
{
if
(
token
.
anthropic_api_key
===
(
provider
.
token
as
ProviderAnthropicToken
).
anthropic_api_key
)
{
setToken
({
anthropic_api_key
:
''
})
onTokenChange
({
anthropic_api_key
:
''
})
setValidatedStatus
({})
}
}
const
handleChange
=
(
v
:
string
)
=>
{
const
apiKey
=
{
anthropic_api_key
:
v
}
setToken
(
apiKey
)
onTokenChange
(
apiKey
)
validate
(
apiKey
,
{
beforeValidating
:
()
=>
{
if
(
!
v
)
{
setValidatedStatus
({})
return
false
}
return
true
},
})
}
useEffect
(()
=>
{
if
(
typeof
onValidatedStatus
===
'function'
)
onValidatedStatus
(
validatedStatus
)
},
[
validatedStatus
])
const
getValidatedIcon
=
()
=>
{
if
(
validatedStatus
?.
status
===
ValidatedStatus
.
Error
||
validatedStatus
.
status
===
ValidatedStatus
.
Exceed
)
return
<
ValidatedErrorIcon
/>
if
(
validatedStatus
.
status
===
ValidatedStatus
.
Success
)
return
<
ValidatedSuccessIcon
/>
}
const
getValidatedTip
=
()
=>
{
if
(
validating
)
return
<
ValidatingTip
/>
if
(
validatedStatus
?.
status
===
ValidatedStatus
.
Error
)
return
<
ValidatedErrorOnOpenaiTip
errorMessage=
{
validatedStatus
.
message
??
''
}
/>
}
return
(
<
div
className=
'px-4 pt-3 pb-4'
>
<
ProviderInput
value=
{
token
.
anthropic_api_key
}
name=
{
t
(
'common.provider.apiKey'
)
}
placeholder=
{
t
(
'common.provider.enterYourKey'
)
}
onChange=
{
handleChange
}
onFocus=
{
handleFocus
}
validatedIcon=
{
getValidatedIcon
()
}
validatedTip=
{
getValidatedTip
()
}
/>
<
Link
className=
"inline-flex items-center mt-3 text-xs font-normal cursor-pointer text-primary-600 w-fit"
href=
"https://platform.openai.com/account/api-keys"
target=
{
'_blank'
}
>
{
t
(
'common.provider.anthropic.keyFrom'
)
}
<
ArrowTopRightOnSquareIcon
className=
'w-3 h-3 ml-1 text-primary-600'
aria
-
hidden=
"true"
/>
</
Link
>
</
div
>
)
}
export
default
AnthropicProvider
web/app/components/header/account-setting/provider-page/index.tsx
View file @
85df761a
...
...
@@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next'
import
Link
from
'next/link'
import
ProviderItem
from
'./provider-item'
import
OpenaiHostedProvider
from
'./openai-hosted-provider'
import
AnthropicHostedProvider
from
'./anthropic-hosted-provider'
import
type
{
ProviderHosted
}
from
'@/models/common'
import
{
fetchProviders
}
from
'@/service/common'
import
{
IS_CE_EDITION
}
from
'@/config'
...
...
@@ -18,6 +19,10 @@ const providersMap: { [k: string]: any } = {
icon
:
'azure'
,
name
:
'Azure OpenAI Service'
,
},
'anthropic-custom'
:
{
icon
:
'anthropic'
,
name
:
'Anthropic'
,
},
}
// const providersList = [
...
...
@@ -65,6 +70,8 @@ const ProviderPage = () => {
}
})
const
providerHosted
=
data
?.
filter
(
provider
=>
provider
.
provider_name
===
'openai'
&&
provider
.
provider_type
===
'system'
)?.[
0
]
const
anthropicHosted
=
data
?.
filter
(
provider
=>
provider
.
provider_name
===
'anthropic'
&&
provider
.
provider_type
===
'system'
)?.[
0
]
const
providedOpenaiProvider
=
data
?.
find
(
provider
=>
provider
.
is_enabled
&&
(
provider
.
provider_name
===
'openai'
||
provider
.
provider_name
===
'azure_openai'
))
return
(
<
div
className=
'pb-7'
>
...
...
@@ -78,6 +85,16 @@ const ProviderPage = () => {
</>
)
}
{
anthropicHosted
&&
!
IS_CE_EDITION
&&
(
<>
<
div
>
<
AnthropicHostedProvider
provider=
{
anthropicHosted
as
ProviderHosted
}
/>
</
div
>
<
div
className=
'my-5 w-full h-0 border-[0.5px] border-gray-100'
/>
</>
)
}
<
div
>
{
providers
?.
map
(
providerItem
=>
(
...
...
@@ -89,6 +106,7 @@ const ProviderPage = () => {
activeId=
{
activeProviderId
}
onActive=
{
aid
=>
setActiveProviderId
(
aid
)
}
onSave=
{
()
=>
mutate
()
}
providedOpenaiProvider=
{
providedOpenaiProvider
}
/>
))
}
...
...
web/app/components/header/account-setting/provider-page/provider-item/index.tsx
View file @
85df761a
...
...
@@ -5,14 +5,20 @@ import { useTranslation } from 'react-i18next'
import
Indicator
from
'../../../indicator'
import
OpenaiProvider
from
'../openai-provider'
import
AzureProvider
from
'../azure-provider'
import
AnthropicProvider
from
'../anthropic-provider'
import
type
{
ValidatedStatusState
}
from
'../provider-input/useValidateToken'
import
{
ValidatedStatus
}
from
'../provider-input/useValidateToken'
import
s
from
'./index.module.css'
import
type
{
Provider
,
ProviderAzureToken
}
from
'@/models/common'
import
type
{
Provider
,
ProviderA
nthropicToken
,
ProviderA
zureToken
}
from
'@/models/common'
import
{
ProviderName
}
from
'@/models/common'
import
{
updateProviderAIKey
}
from
'@/service/common'
import
{
ToastContext
}
from
'@/app/components/base/toast'
import
Tooltip
from
'@/app/components/base/tooltip'
const
providerNameMap
:
Record
<
string
,
string
>
=
{
openai
:
'OpenAI'
,
azure_openai
:
'Azure OpenAI Service'
,
}
type
IProviderItemProps
=
{
icon
:
string
name
:
string
...
...
@@ -20,6 +26,7 @@ type IProviderItemProps = {
activeId
:
string
onActive
:
(
v
:
string
)
=>
void
onSave
:
()
=>
void
providedOpenaiProvider
?:
Provider
}
const
ProviderItem
=
({
activeId
,
...
...
@@ -28,15 +35,18 @@ const ProviderItem = ({
provider
,
onActive
,
onSave
,
providedOpenaiProvider
,
}:
IProviderItemProps
)
=>
{
const
{
t
}
=
useTranslation
()
const
[
validatedStatus
,
setValidatedStatus
]
=
useState
<
ValidatedStatusState
>
()
const
[
loading
,
setLoading
]
=
useState
(
false
)
const
{
notify
}
=
useContext
(
ToastContext
)
const
[
token
,
setToken
]
=
useState
<
ProviderAzureToken
|
string
>
(
const
[
token
,
setToken
]
=
useState
<
ProviderAzureToken
|
string
|
ProviderAnthropicToken
>
(
provider
.
provider_name
===
'azure_openai'
?
{
openai_api_base
:
''
,
openai_api_key
:
''
}
:
''
,
:
provider
.
provider_name
===
'anthropic'
?
{
anthropic_api_key
:
''
}
:
''
,
)
const
id
=
`
${
provider
.
provider_name
}
-
${
provider
.
provider_type
}
`
const
isOpen
=
id
===
activeId
...
...
@@ -54,6 +64,8 @@ const ProviderItem = ({
}
if
(
provider
.
provider_name
===
ProviderName
.
OPENAI
)
return
provider
.
token
if
(
provider
.
provider_name
===
ProviderName
.
ANTHROPIC
)
return
provider
.
token
?.
anthropic_api_key
}
const
handleUpdateToken
=
async
()
=>
{
if
(
loading
)
...
...
@@ -81,7 +93,7 @@ const ProviderItem = ({
<
div
className=
{
cn
(
s
[
`icon-${icon}`
],
'mr-3 w-6 h-6 rounded-md'
)
}
/>
<
div
className=
'grow text-sm font-medium text-gray-800'
>
{
name
}
</
div
>
{
providerTokenHasSetted
()
&&
!
comingSoon
&&
!
isOpen
&&
(
providerTokenHasSetted
()
&&
!
comingSoon
&&
!
isOpen
&&
provider
.
provider_name
!==
ProviderName
.
ANTHROPIC
&&
(
<
div
className=
'flex items-center mr-4'
>
{
!
isValid
&&
<
div
className=
'text-xs text-[#D92D20]'
>
{
t
(
'common.provider.invalidApiKey'
)
}
</
div
>
}
<
Indicator
color=
{
!
isValid
?
'red'
:
'green'
}
className=
'ml-2'
/>
...
...
@@ -89,7 +101,27 @@ const ProviderItem = ({
)
}
{
!
comingSoon
&&
!
isOpen
&&
(
(
providerTokenHasSetted
()
&&
!
comingSoon
&&
!
isOpen
&&
provider
.
provider_name
===
ProviderName
.
ANTHROPIC
)
&&
(
<
div
className=
'flex items-center mr-4'
>
{
providedOpenaiProvider
?.
is_valid
?
!
isValid
?
<
div
className=
'text-xs text-[#D92D20]'
>
{
t
(
'common.provider.invalidApiKey'
)
}
</
div
>
:
null
:
<
div
className=
'text-xs text-[#DC6803]'
>
{
t
(
'common.provider.anthropic.notEnabled'
)
}
</
div
>
}
<
Indicator
color=
{
providedOpenaiProvider
?.
is_valid
?
isValid
?
'green'
:
'red'
:
'yellow'
}
className=
'ml-2'
/>
</
div
>
)
}
{
!
comingSoon
&&
!
isOpen
&&
provider
.
provider_name
!==
ProviderName
.
ANTHROPIC
&&
(
<
div
className=
'
px-3 h-[28px] bg-white border border-gray-200 rounded-md cursor-pointer
text-xs font-medium text-gray-700 flex items-center
...
...
@@ -98,6 +130,34 @@ const ProviderItem = ({
</
div
>
)
}
{
(
!
comingSoon
&&
!
isOpen
&&
provider
.
provider_name
===
ProviderName
.
ANTHROPIC
)
?
providedOpenaiProvider
?.
is_enabled
?
(
<
div
className=
'
px-3 h-[28px] bg-white border border-gray-200 rounded-md cursor-pointer
text-xs font-medium text-gray-700 flex items-center
'
onClick=
{
()
=>
providedOpenaiProvider
.
is_valid
&&
onActive
(
id
)
}
>
{
providerTokenHasSetted
()
?
t
(
'common.provider.editKey'
)
:
t
(
'common.provider.addKey'
)
}
</
div
>
)
:
(
<
Tooltip
htmlContent=
{
<
div
className=
'w-[320px]'
>
{
t
(
'common.provider.anthropic.enableTip'
)
}
</
div
>
}
position=
'bottom'
selector=
'anthropic-provider-enable-top-tooltip'
>
<
div
className=
'
px-3 h-[28px] bg-white border border-gray-200 rounded-md cursor-not-allowed
text-xs font-medium text-gray-700 flex items-center opacity-50
'
>
{
t
(
'common.provider.addKey'
)
}
</
div
>
</
Tooltip
>
)
:
null
}
{
comingSoon
&&
!
isOpen
&&
(
<
div
className=
'
...
...
@@ -147,6 +207,29 @@ const ProviderItem = ({
/>
)
}
{
provider
.
provider_name
===
ProviderName
.
ANTHROPIC
&&
isOpen
&&
(
<
AnthropicProvider
provider=
{
provider
}
onValidatedStatus=
{
v
=>
setValidatedStatus
(
v
)
}
onTokenChange=
{
v
=>
setToken
(
v
)
}
/>
)
}
{
provider
.
provider_name
===
ProviderName
.
ANTHROPIC
&&
!
isOpen
&&
providerTokenHasSetted
()
&&
providedOpenaiProvider
?.
is_valid
&&
(
<
div
className=
'px-4 py-3 text-[13px] font-medium text-gray-700'
>
{
t
(
'common.provider.anthropic.using'
)
}
{
providerNameMap
[
providedOpenaiProvider
.
provider_name
as
string
]
}
</
div
>
)
}
{
provider
.
provider_name
===
ProviderName
.
ANTHROPIC
&&
!
isOpen
&&
providerTokenHasSetted
()
&&
!
providedOpenaiProvider
?.
is_valid
&&
(
<
div
className=
'px-4 py-3 bg-[#FFFAEB] text-[13px] font-medium text-gray-700'
>
{
t
(
'common.provider.anthropic.enableTip'
)
}
</
div
>
)
}
</
div
>
)
}
...
...
web/i18n/lang/common.en.ts
View file @
85df761a
...
...
@@ -180,6 +180,22 @@ const translation = {
useYourModel
:
'Currently using own Model Provider.'
,
close
:
'Close'
,
},
anthropicHosted
:
{
anthropicHosted
:
'Anthropic Claude'
,
onTrial
:
'ON TRIAL'
,
exhausted
:
'QUOTA EXHAUSTED'
,
desc
:
'Powerful model, which excels at a wide range of tasks from sophisticated dialogue and creative content generation to detailed instruction.'
,
callTimes
:
'Call times'
,
usedUp
:
'Trial quota used up. Add own Model Provider.'
,
useYourModel
:
'Currently using own Model Provider.'
,
close
:
'Close'
,
},
anthropic
:
{
using
:
'The embedding capability is using'
,
enableTip
:
'To enable the Anthropic model, you need to bind to OpenAI or Azure OpenAI Service first.'
,
notEnabled
:
'Not enabled'
,
keyFrom
:
'Get your API key from Anthropic'
,
},
encrypted
:
{
front
:
'Your API KEY will be encrypted and stored using'
,
back
:
' technology.'
,
...
...
web/i18n/lang/common.zh.ts
View file @
85df761a
...
...
@@ -180,6 +180,22 @@ const translation = {
useYourModel
:
'当前正在使用你自己的模型供应商。'
,
close
:
'关闭'
,
},
anthropicHosted
:
{
anthropicHosted
:
'Anthropic Claude'
,
onTrial
:
'体验'
,
exhausted
:
'超出限额'
,
desc
:
'功能强大的模型,擅长执行从复杂对话和创意内容生成到详细指导的各种任务。'
,
callTimes
:
'调用次数'
,
usedUp
:
'试用额度已用完,请在下方添加自己的模型供应商'
,
useYourModel
:
'当前正在使用你自己的模型供应商。'
,
close
:
'关闭'
,
},
anthropic
:
{
using
:
'嵌入能力正在使用'
,
enableTip
:
'要启用 Anthropic 模型,您需要先绑定 OpenAI 或 Azure OpenAI 服务。'
,
notEnabled
:
'未启用'
,
keyFrom
:
'从 Anthropic 获取您的 API 密钥'
,
},
encrypted
:
{
front
:
'密钥将使用 '
,
back
:
' 技术进行加密和存储。'
,
...
...
web/models/common.ts
View file @
85df761a
...
...
@@ -59,14 +59,19 @@ export type Member = Pick<UserProfileResponse, 'id' | 'name' | 'email' | 'last_l
export
enum
ProviderName
{
OPENAI
=
'openai'
,
AZURE_OPENAI
=
'azure_openai'
,
ANTHROPIC
=
'anthropic'
,
}
export
type
ProviderAzureToken
=
{
openai_api_base
?:
string
openai_api_key
?:
string
}
export
type
ProviderAnthropicToken
=
{
anthropic_api_key
?:
string
}
export
type
ProviderTokenType
=
{
[
ProviderName
.
OPENAI
]:
string
[
ProviderName
.
AZURE_OPENAI
]:
ProviderAzureToken
[
ProviderName
.
ANTHROPIC
]:
ProviderAnthropicToken
}
export
type
Provider
=
{
[
Name
in
ProviderName
]:
{
...
...
web/service/common.ts
View file @
85df761a
...
...
@@ -3,7 +3,7 @@ import { del, get, patch, post, put } from './base'
import
type
{
AccountIntegrate
,
CommonResponse
,
DataSourceNotion
,
IWorkspace
,
LangGeniusVersionResponse
,
Member
,
OauthResponse
,
Provider
,
ProviderAzureToken
,
TenantInfoResponse
,
OauthResponse
,
Provider
,
ProviderA
nthropicToken
,
ProviderA
zureToken
,
TenantInfoResponse
,
UserProfileOriginResponse
,
}
from
'@/models/common'
import
type
{
...
...
@@ -58,7 +58,7 @@ export const fetchProviders: Fetcher<Provider[] | null, { url: string; params: R
export
const
validateProviderKey
:
Fetcher
<
ValidateOpenAIKeyResponse
,
{
url
:
string
;
body
:
{
token
:
string
}
}
>
=
({
url
,
body
})
=>
{
return
post
(
url
,
{
body
})
as
Promise
<
ValidateOpenAIKeyResponse
>
}
export
const
updateProviderAIKey
:
Fetcher
<
UpdateOpenAIKeyResponse
,
{
url
:
string
;
body
:
{
token
:
string
|
ProviderAzureToken
}
}
>
=
({
url
,
body
})
=>
{
export
const
updateProviderAIKey
:
Fetcher
<
UpdateOpenAIKeyResponse
,
{
url
:
string
;
body
:
{
token
:
string
|
ProviderAzureToken
|
ProviderAnthropicToken
}
}
>
=
({
url
,
body
})
=>
{
return
post
(
url
,
{
body
})
as
Promise
<
UpdateOpenAIKeyResponse
>
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment