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
8e112003
Unverified
Commit
8e112003
authored
Jul 16, 2023
by
Joel
Committed by
GitHub
Jul 16, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: frontend support claude (#573)
Co-authored-by:
StyleZhang
<
jasonapring2015@outlook.com
>
parent
7599f79a
Changes
17
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
401 additions
and
35 deletions
+401
-35
index.tsx
web/app/components/app/configuration/config-model/index.tsx
+53
-19
index.tsx
web/app/components/app/configuration/debug/index.tsx
+1
-1
index.tsx
web/app/components/app/configuration/index.tsx
+4
-2
index.tsx
web/app/components/base/auto-height-textarea/index.tsx
+10
-2
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
index.tsx
web/app/components/share/chat/index.tsx
+1
-1
index.tsx
web/app/components/share/chatbot/index.tsx
+1
-1
common.en.ts
web/i18n/lang/common.en.ts
+17
-1
common.zh.ts
web/i18n/lang/common.zh.ts
+17
-1
common.ts
web/models/common.ts
+5
-0
common.ts
web/service/common.ts
+2
-2
app.ts
web/types/app.ts
+5
-0
No files found.
web/app/components/app/configuration/config-model/index.tsx
View file @
8e112003
This diff is collapsed.
Click to expand it.
web/app/components/app/configuration/debug/index.tsx
View file @
8e112003
...
...
@@ -372,7 +372,7 @@ const Debug: FC<IDebug> = ({
{
/* Chat */
}
{
mode
===
AppType
.
chat
&&
(
<
div
className=
"mt-[34px] h-full flex flex-col"
>
<
div
className=
{
cn
(
doShowSuggestion
?
'pb-[140px]'
:
(
isResponsing
?
'pb-[113px]'
:
'pb-[
6
6px]'
),
'relative mt-1.5 grow h-[200px] overflow-hidden'
)
}
>
<
div
className=
{
cn
(
doShowSuggestion
?
'pb-[140px]'
:
(
isResponsing
?
'pb-[113px]'
:
'pb-[
7
6px]'
),
'relative mt-1.5 grow h-[200px] overflow-hidden'
)
}
>
<
div
className=
"h-full overflow-y-auto overflow-x-hidden"
ref=
{
chatListDomRef
}
>
<
Chat
chatList=
{
chatList
}
...
...
web/app/components/app/configuration/index.tsx
View file @
8e112003
...
...
@@ -16,6 +16,7 @@ import ConfigModel from '@/app/components/app/configuration/config-model'
import
Config
from
'@/app/components/app/configuration/config'
import
Debug
from
'@/app/components/app/configuration/debug'
import
Confirm
from
'@/app/components/base/confirm'
import
{
ProviderType
}
from
'@/types/app'
import
type
{
AppDetailResponse
}
from
'@/models/app'
import
{
ToastContext
}
from
'@/app/components/base/toast'
import
{
fetchTenantInfo
}
from
'@/service/common'
...
...
@@ -67,7 +68,7 @@ const Configuration: FC = () => {
frequency_penalty
:
1
,
// -2-2
})
const
[
modelConfig
,
doSetModelConfig
]
=
useState
<
ModelConfig
>
({
provider
:
'openai'
,
provider
:
ProviderType
.
openai
,
model_id
:
'gpt-3.5-turbo'
,
configs
:
{
prompt_template
:
''
,
...
...
@@ -84,8 +85,9 @@ const Configuration: FC = () => {
doSetModelConfig
(
newModelConfig
)
}
const
setModelId
=
(
modelId
:
string
)
=>
{
const
setModelId
=
(
modelId
:
string
,
provider
:
ProviderType
)
=>
{
const
newModelConfig
=
produce
(
modelConfig
,
(
draft
:
any
)
=>
{
draft
.
provider
=
provider
draft
.
model_id
=
modelId
})
setModelConfig
(
newModelConfig
)
...
...
web/app/components/base/auto-height-textarea/index.tsx
View file @
8e112003
...
...
@@ -19,6 +19,7 @@ const AutoHeightTextarea = forwardRef(
{
value
,
onChange
,
placeholder
,
className
,
minHeight
=
36
,
maxHeight
=
96
,
autoFocus
,
controlFocus
,
onKeyDown
,
onKeyUp
}:
IProps
,
outerRef
:
any
,
)
=>
{
// eslint-disable-next-line react-hooks/rules-of-hooks
const
ref
=
outerRef
||
useRef
<
HTMLTextAreaElement
>
(
null
)
const
doFocus
=
()
=>
{
...
...
@@ -54,13 +55,20 @@ const AutoHeightTextarea = forwardRef(
return
(
<
div
className=
'relative'
>
<
div
className=
{
cn
(
className
,
'invisible whitespace-pre-wrap break-all overflow-y-auto'
)
}
style=
{
{
minHeight
,
maxHeight
}
}
>
<
div
className=
{
cn
(
className
,
'invisible whitespace-pre-wrap break-all overflow-y-auto'
)
}
style=
{
{
minHeight
,
maxHeight
,
paddingRight
:
(
value
&&
value
.
trim
().
length
>
10000
)
?
140
:
130
,
}
}
>
{
!
value
?
placeholder
:
value
.
replace
(
/
\n
$/
,
'
\
n '
)
}
</
div
>
<
textarea
ref=
{
ref
}
autoFocus=
{
autoFocus
}
className=
{
cn
(
className
,
'absolute inset-0 resize-none overflow-hidden'
)
}
className=
{
cn
(
className
,
'absolute inset-0 resize-none overflow-auto'
)
}
style=
{
{
paddingRight
:
(
value
&&
value
.
trim
().
length
>
10000
)
?
140
:
130
,
}
}
placeholder=
{
placeholder
}
onChange=
{
onChange
}
onKeyDown=
{
onKeyDown
}
...
...
web/app/components/header/account-setting/provider-page/anthropic-hosted-provider/index.module.css
0 → 100644
View file @
8e112003
.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 @
8e112003
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 @
8e112003
web/app/components/header/account-setting/provider-page/anthropic-provider/index.tsx
0 → 100644
View file @
8e112003
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://docs.anthropic.com/claude/reference/getting-started-with-the-api"
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 @
8e112003
...
...
@@ -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 @
8e112003
...
...
@@ -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,14 +35,17 @@ 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
}
`
...
...
@@ -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/app/components/share/chat/index.tsx
View file @
8e112003
...
...
@@ -620,7 +620,7 @@ const Main: FC<IMainProps> = ({
{
hasSetInputs
&&
(
<
div
className=
{
cn
(
doShowSuggestion
?
'pb-[140px]'
:
(
isResponsing
?
'pb-[113px]'
:
'pb-[
6
6px]'
),
'relative grow h-[200px] pc:w-[794px] max-w-full mobile:w-full mx-auto mb-3.5 overflow-hidden'
)
}
>
<
div
className=
{
cn
(
doShowSuggestion
?
'pb-[140px]'
:
(
isResponsing
?
'pb-[113px]'
:
'pb-[
7
6px]'
),
'relative grow h-[200px] pc:w-[794px] max-w-full mobile:w-full mx-auto mb-3.5 overflow-hidden'
)
}
>
<
div
className=
'h-full overflow-y-auto'
ref=
{
chatListDomRef
}
>
<
Chat
chatList=
{
chatList
}
...
...
web/app/components/share/chatbot/index.tsx
View file @
8e112003
...
...
@@ -609,7 +609,7 @@ const Main: FC<IMainProps> = ({
{
hasSetInputs
&&
(
<
div
className=
{
cn
(
doShowSuggestion
?
'pb-[140px]'
:
(
isResponsing
?
'pb-[113px]'
:
'pb-[
6
6px]'
),
'relative grow h-[200px] pc:w-[794px] max-w-full mobile:w-full mx-auto mb-3.5 overflow-hidden'
)
}
>
<
div
className=
{
cn
(
doShowSuggestion
?
'pb-[140px]'
:
(
isResponsing
?
'pb-[113px]'
:
'pb-[
7
6px]'
),
'relative grow h-[200px] pc:w-[794px] max-w-full mobile:w-full mx-auto mb-3.5 overflow-hidden'
)
}
>
<
div
className=
'h-full overflow-y-auto'
ref=
{
chatListDomRef
}
>
<
Chat
chatList=
{
chatList
}
...
...
web/i18n/lang/common.en.ts
View file @
8e112003
...
...
@@ -54,7 +54,7 @@ const translation = {
maxTokenTip
:
'Max tokens depending on the model. Prompt and completion share this limit. One token is roughly 1 English character.'
,
maxTokenSettingTip
:
'Your max token setting is high, potentially limiting space for prompts, queries, and data. Consider setting it below 2/3.'
,
setToCurrentModelMaxTokenTip
:
'Max token is updated to the maximum token of the current model
4,000
.'
,
setToCurrentModelMaxTokenTip
:
'Max token is updated to the maximum token of the current model
{{maxToken}}
.'
,
},
tone
:
{
Creative
:
'Creative'
,
...
...
@@ -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 @
8e112003
...
...
@@ -54,7 +54,7 @@ const translation = {
maxTokenTip
:
'生成的最大令牌数取决于模型。提示和完成共享令牌数限制。一个令牌约等于 1 个英文或 半个中文字符。'
,
maxTokenSettingTip
:
'您设置的最大 tokens 数较大,可能会导致 prompt、用户问题、数据集内容没有 token 空间进行处理,建议设置到 2/3 以下。'
,
setToCurrentModelMaxTokenTip
:
'最大令牌数更新为当前模型最大的令牌数
4,000
。'
,
setToCurrentModelMaxTokenTip
:
'最大令牌数更新为当前模型最大的令牌数
{{maxToken}}
。'
,
},
tone
:
{
Creative
:
'创意'
,
...
...
@@ -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 @
8e112003
...
...
@@ -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 @
8e112003
...
...
@@ -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
>
}
...
...
web/types/app.ts
View file @
8e112003
export
enum
ProviderType
{
openai
=
'openai'
,
anthropic
=
'anthropic'
,
}
export
enum
AppType
{
'chat'
=
'chat'
,
'completion'
=
'completion'
,
...
...
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