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
68406b99
Unverified
Commit
68406b99
authored
Jan 30, 2024
by
zxhlyh
Committed by
GitHub
Jan 30, 2024
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: multiple model configuration clear conversation by rerender (#2286)
parent
6f7fd661
Changes
22
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
817 additions
and
713 deletions
+817
-713
index.tsx
...components/app/annotation/edit-annotation-modal/index.tsx
+1
-0
index.tsx
...ents/app/configuration/config/agent/agent-tools/index.tsx
+6
-0
index.tsx
web/app/components/app/configuration/config/index.tsx
+5
-3
index.tsx
...app/components/app/configuration/dataset-config/index.tsx
+4
-3
chat-item.tsx
...nfiguration/debug/debug-with-multiple-model/chat-item.tsx
+11
-64
context.tsx
...configuration/debug/debug-with-multiple-model/context.tsx
+3
-0
debug-item.tsx
...figuration/debug/debug-with-multiple-model/debug-item.tsx
+7
-2
index.tsx
...p/configuration/debug/debug-with-multiple-model/index.tsx
+70
-43
index.tsx
...app/configuration/debug/debug-with-single-model/index.tsx
+143
-0
hooks.tsx
web/app/components/app/configuration/debug/hooks.tsx
+103
-0
index.tsx
web/app/components/app/configuration/debug/index.tsx
+46
-420
types.ts
web/app/components/app/configuration/debug/types.ts
+1
-0
index.tsx
web/app/components/app/configuration/index.tsx
+9
-7
index.tsx
...guration/toolbox/annotation/annotation-ctrl-btn/index.tsx
+14
-11
agent-content.tsx
web/app/components/base/chat/chat/answer/agent-content.tsx
+5
-2
index.tsx
web/app/components/base/chat/chat/answer/index.tsx
+14
-2
operation.tsx
web/app/components/base/chat/chat/answer/operation.tsx
+44
-1
context.tsx
web/app/components/base/chat/chat/context.tsx
+19
-16
hooks.ts
web/app/components/base/chat/chat/hooks.ts
+221
-103
index.tsx
web/app/components/base/chat/chat/index.tsx
+86
-34
types.ts
web/app/components/base/chat/types.ts
+4
-1
debug-configuration.ts
web/context/debug-configuration.ts
+1
-1
No files found.
web/app/components/app/annotation/edit-annotation-modal/index.tsx
View file @
68406b99
...
...
@@ -132,6 +132,7 @@ const EditAnnotationModal: FC<Props> = ({
onRemove=
{
()
=>
{
onRemove
()
setShowModal
(
false
)
onHide
()
}
}
text=
{
t
(
'appDebug.feature.annotation.removeConfirm'
)
as
string
}
/>
...
...
web/app/components/app/configuration/config/agent/agent-tools/index.tsx
View file @
68406b99
...
...
@@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next'
import
cn
from
'classnames'
import
{
useContext
}
from
'use-context-selector'
import
produce
from
'immer'
import
{
useFormattingChangedDispatcher
}
from
'../../../debug/hooks'
import
ChooseTool
from
'./choose-tool'
import
SettingBuiltInTool
from
'./setting-built-in-tool'
import
Panel
from
'@/app/components/app/configuration/base/feature-panel'
...
...
@@ -27,6 +28,7 @@ const AgentTools: FC = () => {
const
{
t
}
=
useTranslation
()
const
[
isShowChooseTool
,
setIsShowChooseTool
]
=
useState
(
false
)
const
{
modelConfig
,
setModelConfig
,
collectionList
}
=
useContext
(
ConfigContext
)
const
formattingChangedDispatcher
=
useFormattingChangedDispatcher
()
const
[
currentTool
,
setCurrentTool
]
=
useState
<
AgentToolWithMoreInfo
>
(
null
)
const
[
selectedProviderId
,
setSelectedProviderId
]
=
useState
<
string
|
undefined
>
(
undefined
)
...
...
@@ -49,6 +51,7 @@ const AgentTools: FC = () => {
})
setModelConfig
(
newModelConfig
)
setIsShowSettingTool
(
false
)
formattingChangedDispatcher
()
}
return
(
...
...
@@ -141,6 +144,7 @@ const AgentTools: FC = () => {
draft
.
agentConfig
.
tools
.
splice
(
index
,
1
)
})
setModelConfig
(
newModelConfig
)
formattingChangedDispatcher
()
}
}
>
<
Trash03
className=
'w-4 h-4 text-gray-500'
/>
</
div
>
...
...
@@ -167,6 +171,7 @@ const AgentTools: FC = () => {
draft
.
agentConfig
.
tools
.
splice
(
index
,
1
)
})
setModelConfig
(
newModelConfig
)
formattingChangedDispatcher
()
}
}
>
<
Trash03
className=
'w-4 h-4 text-gray-500'
/>
</
div
>
...
...
@@ -183,6 +188,7 @@ const AgentTools: FC = () => {
(
draft
.
agentConfig
.
tools
[
index
]
as
any
).
enabled
=
enabled
})
setModelConfig
(
newModelConfig
)
formattingChangedDispatcher
()
}
}
/>
</
div
>
</
div
>
...
...
web/app/components/app/configuration/config/index.tsx
View file @
68406b99
...
...
@@ -4,6 +4,7 @@ import React, { useRef } from 'react'
import
{
useContext
}
from
'use-context-selector'
import
produce
from
'immer'
import
{
useBoolean
,
useScroll
}
from
'ahooks'
import
{
useFormattingChangedDispatcher
}
from
'../debug/hooks'
import
DatasetConfig
from
'../dataset-config'
import
ChatGroup
from
'../features/chat-group'
import
ExperienceEnchanceGroup
from
'../features/experience-enchance-group'
...
...
@@ -44,7 +45,6 @@ const Config: FC = () => {
modelConfig
,
setModelConfig
,
setPrevPromptConfig
,
setFormattingChanged
,
moreLikeThisConfig
,
setMoreLikeThisConfig
,
suggestedQuestionsAfterAnswerConfig
,
...
...
@@ -64,6 +64,7 @@ const Config: FC = () => {
const
{
data
:
speech2textDefaultModel
}
=
useDefaultModel
(
4
)
const
{
data
:
text2speechDefaultModel
}
=
useDefaultModel
(
5
)
const
{
setShowModerationSettingModal
}
=
useModalContext
()
const
formattingChangedDispatcher
=
useFormattingChangedDispatcher
()
const
promptTemplate
=
modelConfig
.
configs
.
prompt_template
const
promptVariables
=
modelConfig
.
configs
.
prompt_variables
...
...
@@ -73,9 +74,8 @@ const Config: FC = () => {
draft
.
configs
.
prompt_template
=
newTemplate
draft
.
configs
.
prompt_variables
=
[...
draft
.
configs
.
prompt_variables
,
...
newVariables
]
})
if
(
modelConfig
.
configs
.
prompt_template
!==
newTemplate
)
setFormattingChanged
(
true
)
formattingChangedDispatcher
(
)
setPrevPromptConfig
(
modelConfig
.
configs
)
setModelConfig
(
newModelConfig
)
...
...
@@ -107,6 +107,7 @@ const Config: FC = () => {
setSuggestedQuestionsAfterAnswerConfig
(
produce
(
suggestedQuestionsAfterAnswerConfig
,
(
draft
:
SuggestedQuestionsAfterAnswerConfig
)
=>
{
draft
.
enabled
=
value
}))
formattingChangedDispatcher
()
},
speechToText
:
speechToTextConfig
.
enabled
,
setSpeechToText
:
(
value
)
=>
{
...
...
@@ -125,6 +126,7 @@ const Config: FC = () => {
setCitationConfig
(
produce
(
citationConfig
,
(
draft
:
CitationConfig
)
=>
{
draft
.
enabled
=
value
}))
formattingChangedDispatcher
()
},
annotation
:
annotationConfig
.
enabled
,
setAnnotation
:
async
(
value
)
=>
{
...
...
web/app/components/app/configuration/dataset-config/index.tsx
View file @
68406b99
...
...
@@ -4,6 +4,7 @@ import React from 'react'
import
{
useTranslation
}
from
'react-i18next'
import
{
useContext
}
from
'use-context-selector'
import
produce
from
'immer'
import
{
useFormattingChangedDispatcher
}
from
'../debug/hooks'
import
FeaturePanel
from
'../base/feature-panel'
import
OperationBtn
from
'../base/operation-btn'
import
CardItem
from
'./card-item/item'
...
...
@@ -26,25 +27,25 @@ const DatasetConfig: FC = () => {
mode
,
dataSets
:
dataSet
,
setDataSets
:
setDataSet
,
setFormattingChanged
,
modelConfig
,
setModelConfig
,
showSelectDataSet
,
isAgent
,
}
=
useContext
(
ConfigContext
)
const
formattingChangedDispatcher
=
useFormattingChangedDispatcher
()
const
hasData
=
dataSet
.
length
>
0
const
onRemove
=
(
id
:
string
)
=>
{
setDataSet
(
dataSet
.
filter
(
item
=>
item
.
id
!==
id
))
setFormattingChanged
(
true
)
formattingChangedDispatcher
(
)
}
const
handleSave
=
(
newDataset
:
DataSet
)
=>
{
const
index
=
dataSet
.
findIndex
(
item
=>
item
.
id
===
newDataset
.
id
)
setDataSet
([...
dataSet
.
slice
(
0
,
index
),
newDataset
,
...
dataSet
.
slice
(
index
+
1
)])
setFormattingChanged
(
true
)
formattingChangedDispatcher
(
)
}
const
promptVariables
=
modelConfig
.
configs
.
prompt_variables
...
...
web/app/components/app/configuration/debug/debug-with-multiple-model/chat-item.tsx
View file @
68406b99
import
type
{
FC
}
from
'react'
import
{
memo
,
useCallback
,
useMemo
,
}
from
'react'
import
type
{
ModelAndParameter
}
from
'../types'
...
...
@@ -9,16 +10,13 @@ import {
APP_CHAT_WITH_MULTIPLE_MODEL_RESTART
,
}
from
'../types'
import
{
AgentStrategy
,
ModelModeType
,
}
from
'
@/types/app
'
useConfigFromDebugContext
,
useFormattingChangedSubscription
,
}
from
'
../hooks
'
import
Chat
from
'@/app/components/base/chat/chat'
import
{
useChat
}
from
'@/app/components/base/chat/chat/hooks'
import
{
useDebugConfigurationContext
}
from
'@/context/debug-configuration'
import
type
{
ChatConfig
,
OnSend
,
}
from
'@/app/components/base/chat/types'
import
type
{
OnSend
}
from
'@/app/components/base/chat/types'
import
{
useEventEmitterContextContext
}
from
'@/context/event-emitter'
import
{
useProviderContext
}
from
'@/context/provider-context'
import
{
...
...
@@ -26,7 +24,6 @@ import {
fetchSuggestedQuestions
,
stopChatMessageResponding
,
}
from
'@/service/debug'
import
{
promptVariablesToUserInputsForm
}
from
'@/utils/model-config'
import
Avatar
from
'@/app/components/base/avatar'
import
{
useAppContext
}
from
'@/context/app-context'
import
{
ModelFeatureEnum
}
from
'@/app/components/header/account-setting/model-provider-page/declarations'
...
...
@@ -39,66 +36,14 @@ const ChatItem: FC<ChatItemProps> = ({
})
=>
{
const
{
userProfile
}
=
useAppContext
()
const
{
isAdvancedMode
,
modelConfig
,
appId
,
inputs
,
promptMode
,
speechToTextConfig
,
introduction
,
suggestedQuestions
:
openingSuggestedQuestions
,
suggestedQuestionsAfterAnswerConfig
,
citationConfig
,
moderationConfig
,
chatPromptConfig
,
completionPromptConfig
,
dataSets
,
datasetConfigs
,
visionConfig
,
annotationConfig
,
collectionList
,
textToSpeechConfig
,
}
=
useDebugConfigurationContext
()
const
{
textGenerationModelList
}
=
useProviderContext
()
const
postDatasets
=
dataSets
.
map
(({
id
})
=>
({
dataset
:
{
enabled
:
true
,
id
,
},
}))
const
contextVar
=
modelConfig
.
configs
.
prompt_variables
.
find
(
item
=>
item
.
is_context_var
)?.
key
const
config
:
ChatConfig
=
{
pre_prompt
:
!
isAdvancedMode
?
modelConfig
.
configs
.
prompt_template
:
''
,
prompt_type
:
promptMode
,
chat_prompt_config
:
isAdvancedMode
?
chatPromptConfig
:
{},
completion_prompt_config
:
isAdvancedMode
?
completionPromptConfig
:
{},
user_input_form
:
promptVariablesToUserInputsForm
(
modelConfig
.
configs
.
prompt_variables
),
dataset_query_variable
:
contextVar
||
''
,
opening_statement
:
introduction
,
more_like_this
:
{
enabled
:
false
,
},
suggested_questions
:
openingSuggestedQuestions
,
suggested_questions_after_answer
:
suggestedQuestionsAfterAnswerConfig
,
text_to_speech
:
textToSpeechConfig
,
speech_to_text
:
speechToTextConfig
,
retriever_resource
:
citationConfig
,
sensitive_word_avoidance
:
moderationConfig
,
agent_mode
:
{
...
modelConfig
.
agentConfig
,
strategy
:
(
modelAndParameter
.
provider
===
'openai'
&&
modelConfig
.
mode
===
ModelModeType
.
chat
)
?
AgentStrategy
.
functionCall
:
AgentStrategy
.
react
,
},
dataset_configs
:
{
...
datasetConfigs
,
datasets
:
{
datasets
:
[...
postDatasets
],
}
as
any
,
},
file_upload
:
{
image
:
visionConfig
,
},
annotation_reply
:
annotationConfig
,
}
const
config
=
useConfigFromDebugContext
()
const
{
chatList
,
isResponsing
,
...
...
@@ -114,8 +59,9 @@ const ChatItem: FC<ChatItemProps> = ({
[],
taskId
=>
stopChatMessageResponding
(
appId
,
taskId
),
)
useFormattingChangedSubscription
(
chatList
)
const
doSend
:
OnSend
=
(
message
,
files
)
=>
{
const
doSend
:
OnSend
=
useCallback
(
(
message
,
files
)
=>
{
const
currentProvider
=
textGenerationModelList
.
find
(
item
=>
item
.
provider
===
modelAndParameter
.
provider
)
const
currentModel
=
currentProvider
?.
models
.
find
(
model
=>
model
.
model
===
modelAndParameter
.
model
)
const
supportVision
=
currentModel
?.
features
?.
includes
(
ModelFeatureEnum
.
vision
)
...
...
@@ -147,7 +93,7 @@ const ChatItem: FC<ChatItemProps> = ({
onGetSuggestedQuestions
:
(
responseItemId
,
getAbortController
)
=>
fetchSuggestedQuestions
(
appId
,
responseItemId
,
getAbortController
),
},
)
}
}
,
[
appId
,
config
,
handleSend
,
inputs
,
modelAndParameter
,
textGenerationModelList
,
visionConfig
.
enabled
])
const
{
eventEmitter
}
=
useEventEmitterContextContext
()
eventEmitter
?.
useSubscription
((
v
:
any
)
=>
{
...
...
@@ -174,8 +120,9 @@ const ChatItem: FC<ChatItemProps> = ({
chatList=
{
chatList
}
isResponsing=
{
isResponsing
}
noChatInput
noStopResponding
chatContainerclassName=
'p-4'
chatFooterClassName=
'
!-bottom-4
'
chatFooterClassName=
'
p-4 pb-0
'
suggestedQuestions=
{
suggestedQuestions
}
onSend=
{
doSend
}
showPromptLog
...
...
web/app/components/app/configuration/debug/debug-with-multiple-model/context.tsx
View file @
68406b99
...
...
@@ -7,6 +7,7 @@ export type DebugWithMultipleModelContextType = {
multipleModelConfigs
:
ModelAndParameter
[]
onMultipleModelConfigsChange
:
(
multiple
:
boolean
,
modelConfigs
:
ModelAndParameter
[])
=>
void
onDebugWithMultipleModelChange
:
(
singleModelConfig
:
ModelAndParameter
)
=>
void
checkCanSend
?:
()
=>
boolean
}
const
DebugWithMultipleModelContext
=
createContext
<
DebugWithMultipleModelContextType
>
({
multipleModelConfigs
:
[],
...
...
@@ -24,12 +25,14 @@ export const DebugWithMultipleModelContextProvider = ({
onMultipleModelConfigsChange
,
multipleModelConfigs
,
onDebugWithMultipleModelChange
,
checkCanSend
,
}:
DebugWithMultipleModelContextProviderProps
)
=>
{
return
(
<
DebugWithMultipleModelContext
.
Provider
value=
{
{
onMultipleModelConfigsChange
,
multipleModelConfigs
,
onDebugWithMultipleModelChange
,
checkCanSend
,
}
}
>
{
children
}
</
DebugWithMultipleModelContext
.
Provider
>
...
...
web/app/components/app/configuration/debug/debug-with-multiple-model/debug-item.tsx
View file @
68406b99
import
type
{
FC
}
from
'react'
import
type
{
CSSProperties
,
FC
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
{
memo
}
from
'react'
import
type
{
ModelAndParameter
}
from
'../types'
...
...
@@ -15,10 +15,12 @@ import { ModelStatusEnum } from '@/app/components/header/account-setting/model-p
type
DebugItemProps
=
{
modelAndParameter
:
ModelAndParameter
className
?:
string
style
?:
CSSProperties
}
const
DebugItem
:
FC
<
DebugItemProps
>
=
({
modelAndParameter
,
className
,
style
,
})
=>
{
const
{
t
}
=
useTranslation
()
const
{
mode
}
=
useDebugConfigurationContext
()
...
...
@@ -61,7 +63,10 @@ const DebugItem: FC<DebugItemProps> = ({
}
return
(
<
div
className=
{
`flex flex-col min-w-[320px] rounded-xl bg-white border-[0.5px] border-black/5 ${className}`
}
>
<
div
className=
{
`flex flex-col min-w-[320px] rounded-xl bg-white border-[0.5px] border-black/5 ${className}`
}
style=
{
style
}
>
<
div
className=
'shrink-0 flex items-center justify-between h-10 px-3 border-b-[0.5px] border-b-black/5'
>
<
div
className=
'flex items-center justify-center w-6 h-5 font-medium italic text-gray-500'
>
#
{
index
+
1
}
...
...
web/app/components/app/configuration/debug/debug-with-multiple-model/index.tsx
View file @
68406b99
...
...
@@ -2,6 +2,7 @@ import type { FC } from 'react'
import
{
memo
,
useCallback
,
useMemo
,
}
from
'react'
import
{
APP_CHAT_WITH_MULTIPLE_MODEL
}
from
'../types'
import
DebugItem
from
'./debug-item'
...
...
@@ -21,10 +22,16 @@ const DebugWithMultipleModel = () => {
speechToTextConfig
,
visionConfig
,
}
=
useDebugConfigurationContext
()
const
{
multipleModelConfigs
}
=
useDebugWithMultipleModelContext
()
const
{
multipleModelConfigs
,
checkCanSend
,
}
=
useDebugWithMultipleModelContext
()
const
{
eventEmitter
}
=
useEventEmitterContextContext
()
const
handleSend
=
useCallback
((
message
:
string
,
files
?:
VisionFile
[])
=>
{
if
(
checkCanSend
&&
!
checkCanSend
())
return
eventEmitter
?.
emit
({
type
:
APP_CHAT_WITH_MULTIPLE_MODEL
,
payload
:
{
...
...
@@ -32,72 +39,90 @@ const DebugWithMultipleModel = () => {
files
,
},
}
as
any
)
},
[
eventEmitter
])
},
[
eventEmitter
,
checkCanSend
])
const
twoLine
=
multipleModelConfigs
.
length
===
2
const
threeLine
=
multipleModelConfigs
.
length
===
3
const
fourLine
=
multipleModelConfigs
.
length
===
4
const
size
=
useMemo
(()
=>
{
let
width
=
''
let
height
=
''
if
(
twoLine
)
{
width
=
'calc(50% - 4px - 24px)'
height
=
'100%'
}
if
(
threeLine
)
{
width
=
'calc(33.3% - 5.33px - 16px)'
height
=
'100%'
}
if
(
fourLine
)
{
width
=
'calc(50% - 4px - 24px)'
height
=
'calc(50% - 4px)'
}
return
{
width
,
height
,
}
},
[
twoLine
,
threeLine
,
fourLine
])
const
position
=
useCallback
((
idx
:
number
)
=>
{
let
translateX
=
'0'
let
translateY
=
'0'
if
(
twoLine
&&
idx
===
1
)
translateX
=
'calc(100% + 8px)'
if
(
threeLine
&&
idx
===
1
)
translateX
=
'calc(100% + 8px)'
if
(
threeLine
&&
idx
===
2
)
translateX
=
'calc(200% + 16px)'
if
(
fourLine
&&
idx
===
1
)
translateX
=
'calc(100% + 8px)'
if
(
fourLine
&&
idx
===
2
)
translateY
=
'calc(100% + 8px)'
if
(
fourLine
&&
idx
===
3
)
{
translateX
=
'calc(100% + 8px)'
translateY
=
'calc(100% + 8px)'
}
return
{
translateX
,
translateY
,
}
},
[
twoLine
,
threeLine
,
fourLine
])
return
(
<
div
className=
'flex flex-col h-full'
>
<
div
className=
{
`
mb-3 overflow-auto
${(twoLine || threeLine) && 'flex gap-2'}
grow mb-3 relative px-6 overflow-auto
`
}
style=
{
{
height
:
mode
===
'chat'
?
'calc(100% - 60px)'
:
'100%'
}
}
>
{
(
twoLine
||
threeLine
)
&&
multipleModelConfigs
.
map
(
modelConfig
=>
(
multipleModelConfigs
.
map
((
modelConfig
,
index
)
=>
(
<
DebugItem
key=
{
modelConfig
.
id
}
modelAndParameter=
{
modelConfig
}
className=
{
`
h-full min-h-[200px]
${twoLine && 'w-1/2'}
${threeLine && 'w-1/3'}
absolute left-6 top-0 min-h-[200px]
${twoLine && index === 0 && 'mr-2'}
${threeLine && (index === 0 || index === 1) && 'mr-2'}
${fourLine && (index === 0 || index === 2) && 'mr-2'}
${fourLine && (index === 0 || index === 1) && 'mb-2'}
`
}
style=
{
{
width
:
size
.
width
,
height
:
size
.
height
,
transform
:
`translateX(${position(index).translateX}) translateY(${position(index).translateY})`
,
}
}
/>
))
}
{
fourLine
&&
(
<>
<
div
className=
'flex space-x-2 mb-2 min-h-[200px]'
style=
{
{
height
:
'calc(50% - 4px)'
}
}
>
{
multipleModelConfigs
.
slice
(
0
,
2
).
map
(
modelConfig
=>
(
<
DebugItem
key=
{
modelConfig
.
id
}
modelAndParameter=
{
modelConfig
}
className=
'w-1/2 h-full'
/>
))
}
</
div
>
<
div
className=
'flex space-x-2 min-h-[200px]'
style=
{
{
height
:
'calc(50% - 4px)'
}
}
>
{
multipleModelConfigs
.
slice
(
2
,
4
).
map
(
modelConfig
=>
(
<
DebugItem
key=
{
modelConfig
.
id
}
modelAndParameter=
{
modelConfig
}
className=
'w-1/2 h-full'
/>
))
}
</
div
>
</>
)
}
</
div
>
{
mode
===
'chat'
&&
(
<
div
className=
'shrink-0'
>
<
div
className=
'shrink-0
pb-4 px-6
'
>
<
ChatInput
onSend=
{
handleSend
}
speechToTextConfig=
{
speechToTextConfig
}
...
...
@@ -116,12 +141,14 @@ const DebugWithMultipleModelWrapper: FC<DebugWithMultipleModelContextType> = ({
onMultipleModelConfigsChange
,
multipleModelConfigs
,
onDebugWithMultipleModelChange
,
checkCanSend
,
})
=>
{
return
(
<
DebugWithMultipleModelContextProvider
onMultipleModelConfigsChange=
{
onMultipleModelConfigsChange
}
multipleModelConfigs=
{
multipleModelConfigs
}
onDebugWithMultipleModelChange=
{
onDebugWithMultipleModelChange
}
checkCanSend=
{
checkCanSend
}
>
<
DebugWithMultipleModelMemoed
/>
</
DebugWithMultipleModelContextProvider
>
...
...
web/app/components/app/configuration/debug/debug-with-single-model/index.tsx
0 → 100644
View file @
68406b99
import
{
forwardRef
,
memo
,
useCallback
,
useImperativeHandle
,
useMemo
,
}
from
'react'
import
{
useConfigFromDebugContext
,
useFormattingChangedSubscription
,
}
from
'../hooks'
import
Chat
from
'@/app/components/base/chat/chat'
import
{
useChat
}
from
'@/app/components/base/chat/chat/hooks'
import
{
useDebugConfigurationContext
}
from
'@/context/debug-configuration'
import
type
{
OnSend
}
from
'@/app/components/base/chat/types'
import
{
useProviderContext
}
from
'@/context/provider-context'
import
{
fetchConvesationMessages
,
fetchSuggestedQuestions
,
stopChatMessageResponding
,
}
from
'@/service/debug'
import
Avatar
from
'@/app/components/base/avatar'
import
{
useAppContext
}
from
'@/context/app-context'
import
{
ModelFeatureEnum
}
from
'@/app/components/header/account-setting/model-provider-page/declarations'
type
DebugWithSingleModelProps
=
{
checkCanSend
?:
()
=>
boolean
}
export
type
DebugWithSingleModelRefType
=
{
handleRestart
:
()
=>
void
}
const
DebugWithSingleModel
=
forwardRef
<
DebugWithSingleModelRefType
,
DebugWithSingleModelProps
>
(({
checkCanSend
,
},
ref
)
=>
{
const
{
userProfile
}
=
useAppContext
()
const
{
modelConfig
,
appId
,
inputs
,
visionConfig
,
collectionList
,
completionParams
,
}
=
useDebugConfigurationContext
()
const
{
textGenerationModelList
}
=
useProviderContext
()
const
config
=
useConfigFromDebugContext
()
const
{
chatList
,
isResponsing
,
handleSend
,
suggestedQuestions
,
handleStop
,
handleRestart
,
handleAnnotationAdded
,
handleAnnotationEdited
,
handleAnnotationRemoved
,
}
=
useChat
(
{
...
config
,
supportAnnotation
:
true
,
appId
,
},
{
inputs
,
promptVariables
:
modelConfig
.
configs
.
prompt_variables
,
},
[],
taskId
=>
stopChatMessageResponding
(
appId
,
taskId
),
)
useFormattingChangedSubscription
(
chatList
)
const
doSend
:
OnSend
=
useCallback
((
message
,
files
)
=>
{
if
(
checkCanSend
&&
!
checkCanSend
())
return
const
currentProvider
=
textGenerationModelList
.
find
(
item
=>
item
.
provider
===
modelConfig
.
provider
)
const
currentModel
=
currentProvider
?.
models
.
find
(
model
=>
model
.
model
===
modelConfig
.
model_id
)
const
supportVision
=
currentModel
?.
features
?.
includes
(
ModelFeatureEnum
.
vision
)
const
configData
=
{
...
config
,
model
:
{
provider
:
modelConfig
.
provider
,
name
:
modelConfig
.
model_id
,
mode
:
modelConfig
.
mode
,
completion_params
:
completionParams
,
},
}
const
data
:
any
=
{
query
:
message
,
inputs
,
model_config
:
configData
,
}
if
(
visionConfig
.
enabled
&&
files
?.
length
&&
supportVision
)
data
.
files
=
files
handleSend
(
`apps/
${
appId
}
/chat-messages`
,
data
,
{
onGetConvesationMessages
:
(
conversationId
,
getAbortController
)
=>
fetchConvesationMessages
(
appId
,
conversationId
,
getAbortController
),
onGetSuggestedQuestions
:
(
responseItemId
,
getAbortController
)
=>
fetchSuggestedQuestions
(
appId
,
responseItemId
,
getAbortController
),
},
)
},
[
appId
,
checkCanSend
,
completionParams
,
config
,
handleSend
,
inputs
,
modelConfig
,
textGenerationModelList
,
visionConfig
.
enabled
])
const
allToolIcons
=
useMemo
(()
=>
{
const
icons
:
Record
<
string
,
any
>
=
{}
modelConfig
.
agentConfig
.
tools
?.
forEach
((
item
:
any
)
=>
{
icons
[
item
.
tool_name
]
=
collectionList
.
find
((
collection
:
any
)
=>
collection
.
id
===
item
.
provider_id
)?.
icon
})
return
icons
},
[
collectionList
,
modelConfig
.
agentConfig
.
tools
])
useImperativeHandle
(
ref
,
()
=>
{
return
{
handleRestart
,
}
},
[
handleRestart
])
return
(
<
Chat
config=
{
config
}
chatList=
{
chatList
}
isResponsing=
{
isResponsing
}
chatContainerclassName=
'p-6'
chatFooterClassName=
'px-6 pt-10 pb-4'
suggestedQuestions=
{
suggestedQuestions
}
onSend=
{
doSend
}
onStopResponding=
{
handleStop
}
showPromptLog
questionIcon=
{
<
Avatar
name=
{
userProfile
.
name
}
size=
{
40
}
/>
}
allToolIcons=
{
allToolIcons
}
onAnnotationEdited=
{
handleAnnotationEdited
}
onAnnotationAdded=
{
handleAnnotationAdded
}
onAnnotationRemoved=
{
handleAnnotationRemoved
}
/>
)
})
DebugWithSingleModel
.
displayName
=
'DebugWithSingleModel'
export
default
memo
(
DebugWithSingleModel
)
web/app/components/app/configuration/debug/hooks.tsx
View file @
68406b99
...
...
@@ -7,6 +7,17 @@ import type {
DebugWithSingleOrMultipleModelConfigs
,
ModelAndParameter
,
}
from
'./types'
import
{
ORCHESTRATE_CHANGED
}
from
'./types'
import
type
{
ChatConfig
,
ChatItem
,
}
from
'@/app/components/base/chat/types'
import
{
AgentStrategy
,
}
from
'@/types/app'
import
{
promptVariablesToUserInputsForm
}
from
'@/utils/model-config'
import
{
useDebugConfigurationContext
}
from
'@/context/debug-configuration'
import
{
useEventEmitterContextContext
}
from
'@/context/event-emitter'
export
const
useDebugWithSingleOrMultipleModel
=
(
appId
:
string
)
=>
{
const
localeDebugWithSingleOrMultipleModelConfigs
=
localStorage
.
getItem
(
'app-debug-with-single-or-multiple-models'
)
...
...
@@ -52,3 +63,95 @@ export const useDebugWithSingleOrMultipleModel = (appId: string) => {
handleMultipleModelConfigsChange
,
}
}
export
const
useConfigFromDebugContext
=
()
=>
{
const
{
isAdvancedMode
,
modelConfig
,
appId
,
promptMode
,
speechToTextConfig
,
introduction
,
suggestedQuestions
:
openingSuggestedQuestions
,
suggestedQuestionsAfterAnswerConfig
,
citationConfig
,
moderationConfig
,
chatPromptConfig
,
completionPromptConfig
,
dataSets
,
datasetConfigs
,
visionConfig
,
annotationConfig
,
textToSpeechConfig
,
isFunctionCall
,
}
=
useDebugConfigurationContext
()
const
postDatasets
=
dataSets
.
map
(({
id
})
=>
({
dataset
:
{
enabled
:
true
,
id
,
},
}))
const
contextVar
=
modelConfig
.
configs
.
prompt_variables
.
find
(
item
=>
item
.
is_context_var
)?.
key
const
config
:
ChatConfig
=
{
pre_prompt
:
!
isAdvancedMode
?
modelConfig
.
configs
.
prompt_template
:
''
,
prompt_type
:
promptMode
,
chat_prompt_config
:
isAdvancedMode
?
chatPromptConfig
:
{},
completion_prompt_config
:
isAdvancedMode
?
completionPromptConfig
:
{},
user_input_form
:
promptVariablesToUserInputsForm
(
modelConfig
.
configs
.
prompt_variables
),
dataset_query_variable
:
contextVar
||
''
,
opening_statement
:
introduction
,
more_like_this
:
{
enabled
:
false
,
},
suggested_questions
:
openingSuggestedQuestions
,
suggested_questions_after_answer
:
suggestedQuestionsAfterAnswerConfig
,
text_to_speech
:
textToSpeechConfig
,
speech_to_text
:
speechToTextConfig
,
retriever_resource
:
citationConfig
,
sensitive_word_avoidance
:
moderationConfig
,
agent_mode
:
{
...
modelConfig
.
agentConfig
,
strategy
:
isFunctionCall
?
AgentStrategy
.
functionCall
:
AgentStrategy
.
react
,
},
dataset_configs
:
{
...
datasetConfigs
,
datasets
:
{
datasets
:
[...
postDatasets
],
}
as
any
,
},
file_upload
:
{
image
:
visionConfig
,
},
annotation_reply
:
annotationConfig
,
supportAnnotation
:
true
,
appId
,
}
return
config
}
export
const
useFormattingChangedDispatcher
=
()
=>
{
const
{
eventEmitter
}
=
useEventEmitterContextContext
()
const
dispatcher
=
useCallback
(()
=>
{
eventEmitter
?.
emit
({
type
:
ORCHESTRATE_CHANGED
,
}
as
any
)
},
[
eventEmitter
])
return
dispatcher
}
export
const
useFormattingChangedSubscription
=
(
chatList
:
ChatItem
[])
=>
{
const
{
formattingChanged
,
setFormattingChanged
,
}
=
useDebugConfigurationContext
()
const
{
eventEmitter
}
=
useEventEmitterContextContext
()
eventEmitter
?.
useSubscription
((
v
:
any
)
=>
{
if
(
v
.
type
===
ORCHESTRATE_CHANGED
)
{
if
(
chatList
.
some
(
item
=>
item
.
isAnswer
)
&&
!
formattingChanged
)
setFormattingChanged
(
true
)
}
})
}
web/app/components/app/configuration/debug/index.tsx
View file @
68406b99
This diff is collapsed.
Click to expand it.
web/app/components/app/configuration/debug/types.ts
View file @
68406b99
...
...
@@ -16,3 +16,4 @@ export type DebugWithSingleOrMultipleModelConfigs = {
export
const
APP_CHAT_WITH_MULTIPLE_MODEL
=
'APP_CHAT_WITH_MULTIPLE_MODEL'
export
const
APP_CHAT_WITH_MULTIPLE_MODEL_RESTART
=
'APP_CHAT_WITH_MULTIPLE_MODEL_RESTART'
export
const
APP_SIDEBAR_SHOULD_COLLAPSE
=
'APP_SIDEBAR_SHOULD_COLLAPSE'
export
const
ORCHESTRATE_CHANGED
=
'ORCHESTRATE_CHANGED'
web/app/components/app/configuration/index.tsx
View file @
68406b99
...
...
@@ -13,7 +13,10 @@ import Button from '../../base/button'
import
Loading
from
'../../base/loading'
import
useAdvancedPromptConfig
from
'./hooks/use-advanced-prompt-config'
import
EditHistoryModal
from
'./config-prompt/conversation-histroy/edit-modal'
import
{
useDebugWithSingleOrMultipleModel
}
from
'./debug/hooks'
import
{
useDebugWithSingleOrMultipleModel
,
useFormattingChangedDispatcher
,
}
from
'./debug/hooks'
import
type
{
ModelAndParameter
}
from
'./debug/types'
import
{
APP_SIDEBAR_SHOULD_COLLAPSE
}
from
'./debug/types'
import
PublishWithMultipleModel
from
'./debug/debug-with-multiple-model/publish-with-multiple-model'
...
...
@@ -45,7 +48,6 @@ import { AgentStrategy, AppType, ModelModeType, RETRIEVE_TYPE, Resolution, Trans
import
{
PromptMode
}
from
'@/models/debug'
import
{
ANNOTATION_DEFAULT
,
DEFAULT_AGENT_SETTING
,
DEFAULT_CHAT_PROMPT_CONFIG
,
DEFAULT_COMPLETION_PROMPT_CONFIG
,
supportFunctionCallModels
}
from
'@/config'
import
SelectDataSet
from
'@/app/components/app/configuration/dataset-config/select-dataset'
import
I18n
from
'@/context/i18n'
import
{
useModalContext
}
from
'@/context/modal-context'
import
useBreakpoints
,
{
MediaType
}
from
'@/hooks/use-breakpoints'
import
Drawer
from
'@/app/components/base/drawer'
...
...
@@ -111,10 +113,11 @@ const Configuration: FC = () => {
embedding_model_name
:
''
,
},
})
const
formattingChangedDispatcher
=
useFormattingChangedDispatcher
()
const
setAnnotationConfig
=
(
config
:
AnnotationReplyConfig
,
notSetFormatChanged
?:
boolean
)
=>
{
doSetAnnotationConfig
(
config
)
if
(
!
notSetFormatChanged
)
setFormattingChanged
(
true
)
formattingChangedDispatcher
(
)
}
const
[
moderationConfig
,
setModerationConfig
]
=
useState
<
ModerationConfig
>
({
...
...
@@ -203,7 +206,7 @@ const Configuration: FC = () => {
return
}
setFormattingChanged
(
true
)
formattingChangedDispatcher
(
)
if
(
data
.
find
(
item
=>
!
item
.
name
))
{
// has not loaded selected dataset
const
newSelected
=
produce
(
data
,
(
draft
:
any
)
=>
{
data
.
forEach
((
item
,
index
)
=>
{
...
...
@@ -299,7 +302,7 @@ const Configuration: FC = () => {
transfer_methods
:
config
.
transfer_methods
||
[
TransferMethod
.
local_file
],
})
if
(
!
notNoticeFormattingChanged
)
setFormattingChanged
(
true
)
formattingChangedDispatcher
(
)
}
const
{
...
...
@@ -634,7 +637,6 @@ const Configuration: FC = () => {
}
const
[
showUseGPT4Confirm
,
setShowUseGPT4Confirm
]
=
useState
(
false
)
const
{
locale
}
=
useContext
(
I18n
)
const
{
eventEmitter
}
=
useEventEmitterContextContext
()
const
{
...
...
@@ -820,7 +822,7 @@ const Configuration: FC = () => {
)
}
</
div
>
<
div
className=
'flex flex-col grow h-0
px-6 py-4
rounded-tl-2xl border-t border-l bg-gray-50 '
>
<
div
className=
'flex flex-col grow h-0 rounded-tl-2xl border-t border-l bg-gray-50 '
>
<
Debug
hasSetAPIKEY=
{
hasSettedApiKey
}
onSetting=
{
()
=>
setShowAccountSettingModal
({
payload
:
'provider'
})
}
...
...
web/app/components/app/configuration/toolbox/annotation/annotation-ctrl-btn/index.tsx
View file @
68406b99
...
...
@@ -97,18 +97,21 @@ const CacheCtrlBtn: FC<Props> = ({
</
div
>
</
div
>
)
:
(
<
TooltipPlus
popupContent=
{
t
(
'appDebug.feature.annotation.add'
)
as
string
}
>
<
div
className=
'p-1 rounded-md hover:bg-[#EEF4FF] hover:text-[#444CE7] cursor-pointer'
onClick=
{
handleAdd
}
:
answer
?
(
<
TooltipPlus
popupContent=
{
t
(
'appDebug.feature.annotation.add'
)
as
string
}
>
<
MessageFastPlus
className=
'w-4 h-4'
/>
</
div
>
</
TooltipPlus
>
)
}
<
div
className=
'p-1 rounded-md hover:bg-[#EEF4FF] hover:text-[#444CE7] cursor-pointer'
onClick=
{
handleAdd
}
>
<
MessageFastPlus
className=
'w-4 h-4'
/>
</
div
>
</
TooltipPlus
>
)
:
null
}
<
TooltipPlus
popupContent=
{
t
(
'appDebug.feature.annotation.edit'
)
as
string
}
>
...
...
web/app/components/base/chat/chat/answer/agent-content.tsx
View file @
68406b99
...
...
@@ -14,7 +14,10 @@ type AgentContentProps = {
const
AgentContent
:
FC
<
AgentContentProps
>
=
({
item
,
})
=>
{
const
{
allToolIcons
}
=
useChatContext
()
const
{
allToolIcons
,
isResponsing
,
}
=
useChatContext
()
const
{
annotation
,
agent_thoughts
,
...
...
@@ -42,7 +45,7 @@ const AgentContent: FC<AgentContentProps> = ({
<
Thought
thought=
{
thought
}
allToolIcons=
{
allToolIcons
||
{}
}
isFinished=
{
!!
thought
.
observation
}
isFinished=
{
!!
thought
.
observation
||
!
isResponsing
}
/>
)
}
...
...
web/app/components/base/chat/chat/answer/index.tsx
View file @
68406b99
...
...
@@ -15,9 +15,13 @@ import { EditTitle } from '@/app/components/app/annotation/edit-annotation-modal
type
AnswerProps
=
{
item
:
ChatItem
question
:
string
index
:
number
}
const
Answer
:
FC
<
AnswerProps
>
=
({
item
,
question
,
index
,
})
=>
{
const
{
t
}
=
useTranslation
()
const
{
...
...
@@ -56,7 +60,15 @@ const Answer: FC<AnswerProps> = ({
<
div
className=
'relative pr-10'
>
<
AnswerTriangle
className=
'absolute -left-2 top-0 w-2 h-3 text-gray-100'
/>
<
div
className=
'group relative inline-block px-4 py-3 max-w-full bg-gray-100 rounded-b-2xl rounded-tr-2xl text-sm text-gray-900'
>
<
Operation
item=
{
item
}
/>
{
!
responsing
&&
(
<
Operation
item=
{
item
}
question=
{
question
}
index=
{
index
}
/>
)
}
{
responsing
&&
!
content
&&
!
hasAgentThoughts
&&
(
<
div
className=
'flex items-center justify-center w-6 h-5'
>
...
...
@@ -75,7 +87,7 @@ const Answer: FC<AnswerProps> = ({
)
}
{
annotation
?.
id
&&
!
annotation
?.
logAnnotation
&&
(
annotation
?.
id
&&
annotation
.
authorName
&&
(
<
EditTitle
className=
'mt-1'
title=
{
t
(
'appAnnotation.editBy'
,
{
author
:
annotation
.
authorName
})
}
...
...
web/app/components/base/chat/chat/answer/operation.tsx
View file @
68406b99
import
type
{
FC
}
from
'react'
import
{
useState
}
from
'react'
import
type
{
ChatItem
}
from
'../../types'
import
{
useCurrentAnswerIsResponsing
}
from
'../hooks'
import
{
useChatContext
}
from
'../context'
import
CopyBtn
from
'@/app/components/app/chat/copy-btn'
import
{
MessageFast
}
from
'@/app/components/base/icons/src/vender/solid/communication'
import
AudioBtn
from
'@/app/components/base/audio-btn'
import
AnnotationCtrlBtn
from
'@/app/components/app/configuration/toolbox/annotation/annotation-ctrl-btn'
import
EditReplyModal
from
'@/app/components/app/annotation/edit-annotation-modal'
type
OperationProps
=
{
item
:
ChatItem
question
:
string
index
:
number
}
const
Operation
:
FC
<
OperationProps
>
=
({
item
,
question
,
index
,
})
=>
{
const
{
config
}
=
useChatContext
()
const
{
config
,
onAnnotationAdded
,
onAnnotationEdited
,
onAnnotationRemoved
,
}
=
useChatContext
()
const
[
isShowReplyModal
,
setIsShowReplyModal
]
=
useState
(
false
)
const
responsing
=
useCurrentAnswerIsResponsing
(
item
.
id
)
const
{
id
,
isOpeningStatement
,
content
,
annotation
,
}
=
item
const
hasAnnotation
=
!!
annotation
?.
id
return
(
<
div
className=
'absolute top-[-14px] right-[-14px] flex justify-end gap-1'
>
...
...
@@ -36,6 +51,34 @@ const Operation: FC<OperationProps> = ({
className=
'hidden group-hover:block'
/>
)
}
{
(
!
isOpeningStatement
&&
config
?.
supportAnnotation
&&
config
.
annotation_reply
?.
enabled
)
&&
(
<
AnnotationCtrlBtn
appId=
{
config
?.
appId
||
''
}
messageId=
{
id
}
annotationId=
{
annotation
?.
id
||
''
}
className=
'hidden group-hover:block ml-1 shrink-0'
cached=
{
hasAnnotation
}
query=
{
question
}
answer=
{
content
}
onAdded=
{
(
id
,
authorName
)
=>
onAnnotationAdded
?.(
id
,
authorName
,
question
,
content
,
index
)
}
onEdit=
{
()
=>
setIsShowReplyModal
(
true
)
}
onRemoved=
{
()
=>
onAnnotationRemoved
?.(
index
)
}
/>
)
}
<
EditReplyModal
isShow=
{
isShowReplyModal
}
onHide=
{
()
=>
setIsShowReplyModal
(
false
)
}
query=
{
question
}
answer=
{
content
}
onEdited=
{
(
editedQuery
,
editedAnswer
)
=>
onAnnotationEdited
?.(
editedQuery
,
editedAnswer
,
index
)
}
onAdded=
{
(
annotationId
,
authorName
,
editedQuery
,
editedAnswer
)
=>
onAnnotationAdded
?.(
annotationId
,
authorName
,
editedQuery
,
editedAnswer
,
index
)
}
appId=
{
config
?.
appId
||
''
}
messageId=
{
id
}
annotationId=
{
annotation
?.
id
||
''
}
createdAt=
{
annotation
?.
created_at
}
onRemove=
{
()
=>
onAnnotationRemoved
?.(
index
)
}
/>
{
annotation
?.
id
&&
(
<
div
...
...
web/app/components/base/chat/chat/context.tsx
View file @
68406b99
...
...
@@ -2,23 +2,20 @@
import
type
{
ReactNode
}
from
'react'
import
{
createContext
,
useContext
}
from
'use-context-selector'
import
type
{
ChatConfig
,
ChatItem
,
OnSend
,
}
from
'../types'
import
type
{
Emoji
}
from
'@/app/components/tools/types'
import
type
{
ChatProps
}
from
'./index'
export
type
ChatContextValue
=
{
config
?:
ChatConfig
isResponsing
?:
boolean
chatList
:
ChatItem
[]
showPromptLog
?:
boolean
questionIcon
?:
ReactNode
answerIcon
?:
ReactNode
allToolIcons
?:
Record
<
string
,
string
|
Emoji
>
onSend
?:
OnSend
}
export
type
ChatContextValue
=
Pick
<
ChatProps
,
'config'
|
'isResponsing'
|
'chatList'
|
'showPromptLog'
|
'questionIcon'
|
'answerIcon'
|
'allToolIcons'
|
'onSend'
|
'onAnnotationEdited'
|
'onAnnotationAdded'
|
'onAnnotationRemoved'
>
const
ChatContext
=
createContext
<
ChatContextValue
>
({
chatList
:
[],
...
...
@@ -38,6 +35,9 @@ export const ChatContextProvider = ({
answerIcon
,
allToolIcons
,
onSend
,
onAnnotationEdited
,
onAnnotationAdded
,
onAnnotationRemoved
,
}:
ChatContextProviderProps
)
=>
{
return
(
<
ChatContext
.
Provider
value=
{
{
...
...
@@ -49,6 +49,9 @@ export const ChatContextProvider = ({
answerIcon
,
allToolIcons
,
onSend
,
onAnnotationEdited
,
onAnnotationAdded
,
onAnnotationRemoved
,
}
}
>
{
children
}
</
ChatContext
.
Provider
>
...
...
web/app/components/base/chat/chat/hooks.ts
View file @
68406b99
This diff is collapsed.
Click to expand it.
web/app/components/base/chat/chat/index.tsx
View file @
68406b99
...
...
@@ -4,8 +4,10 @@ import type {
}
from
'react'
import
{
memo
,
useEffect
,
useRef
,
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
{
useThrottleEffect
}
from
'ahooks'
import
type
{
ChatConfig
,
...
...
@@ -18,13 +20,17 @@ import ChatInput from './chat-input'
import
TryToAsk
from
'./try-to-ask'
import
{
ChatContextProvider
}
from
'./context'
import
type
{
Emoji
}
from
'@/app/components/tools/types'
import
Button
from
'@/app/components/base/button'
import
{
StopCircle
}
from
'@/app/components/base/icons/src/vender/solid/mediaAndDevices'
export
type
ChatProps
=
{
config
:
ChatConfig
onSend
?:
OnSend
chatList
:
ChatItem
[]
isResponsing
:
boolean
config
?:
ChatConfig
isResponsing
?:
boolean
noStopResponding
?:
boolean
onStopResponding
?:
()
=>
void
noChatInput
?:
boolean
onSend
?:
OnSend
chatContainerclassName
?:
string
chatFooterClassName
?:
string
suggestedQuestions
?:
string
[]
...
...
@@ -32,12 +38,17 @@ export type ChatProps = {
questionIcon
?:
ReactNode
answerIcon
?:
ReactNode
allToolIcons
?:
Record
<
string
,
string
|
Emoji
>
onAnnotationEdited
?:
(
question
:
string
,
answer
:
string
,
index
:
number
)
=>
void
onAnnotationAdded
?:
(
annotationId
:
string
,
authorName
:
string
,
question
:
string
,
answer
:
string
,
index
:
number
)
=>
void
onAnnotationRemoved
?:
(
index
:
number
)
=>
void
}
const
Chat
:
FC
<
ChatProps
>
=
({
config
,
onSend
,
chatList
,
isResponsing
,
noStopResponding
,
onStopResponding
,
noChatInput
,
chatContainerclassName
,
chatFooterClassName
,
...
...
@@ -46,16 +57,46 @@ const Chat: FC<ChatProps> = ({
questionIcon
,
answerIcon
,
allToolIcons
,
onAnnotationAdded
,
onAnnotationEdited
,
onAnnotationRemoved
,
})
=>
{
const
ref
=
useRef
<
HTMLDivElement
>
(
null
)
const
{
t
}
=
useTranslation
()
const
chatContainerRef
=
useRef
<
HTMLDivElement
>
(
null
)
const
chatFooterRef
=
useRef
<
HTMLDivElement
>
(
null
)
const
handleScrolltoBottom
=
()
=>
{
if
(
chatContainerRef
.
current
)
chatContainerRef
.
current
.
scrollTop
=
chatContainerRef
.
current
.
scrollHeight
}
useThrottleEffect
(()
=>
{
if
(
ref
.
current
)
ref
.
current
.
scrollTop
=
ref
.
current
.
scrollHeight
handleScrolltoBottom
()
if
(
chatContainerRef
.
current
&&
chatFooterRef
.
current
)
chatFooterRef
.
current
.
style
.
width
=
`
${
chatContainerRef
.
current
.
clientWidth
}
px`
},
[
chatList
],
{
wait
:
500
})
const
hasTryToAsk
=
config
.
suggested_questions_after_answer
?.
enabled
&&
!!
suggestedQuestions
?.
length
&&
onSend
useEffect
(()
=>
{
if
(
chatFooterRef
.
current
&&
chatContainerRef
.
current
)
{
const
resizeObserver
=
new
ResizeObserver
((
entries
)
=>
{
for
(
const
entry
of
entries
)
{
const
{
blockSize
}
=
entry
.
borderBoxSize
[
0
]
chatContainerRef
.
current
!
.
style
.
paddingBottom
=
`
${
blockSize
}
px`
handleScrolltoBottom
()
}
})
resizeObserver
.
observe
(
chatFooterRef
.
current
)
return
()
=>
{
resizeObserver
.
disconnect
()
}
}
},
[
chatFooterRef
,
chatContainerRef
])
const
hasTryToAsk
=
config
?.
suggested_questions_after_answer
?.
enabled
&&
!!
suggestedQuestions
?.
length
&&
onSend
return
(
<
ChatContextProvider
...
...
@@ -67,19 +108,24 @@ const Chat: FC<ChatProps> = ({
answerIcon=
{
answerIcon
}
allToolIcons=
{
allToolIcons
}
onSend=
{
onSend
}
onAnnotationAdded=
{
onAnnotationAdded
}
onAnnotationEdited=
{
onAnnotationEdited
}
onAnnotationRemoved=
{
onAnnotationRemoved
}
>
<
div
className=
'relative h-full'
>
<
div
ref=
{
r
ef
}
ref=
{
chatContainerR
ef
}
className=
{
`relative h-full overflow-y-auto ${chatContainerclassName}`
}
>
{
chatList
.
map
((
item
)
=>
{
chatList
.
map
((
item
,
index
)
=>
{
if
(
item
.
isAnswer
)
{
return
(
<
Answer
key=
{
item
.
id
}
item=
{
item
}
question=
{
chatList
[
index
-
1
]?.
content
}
index=
{
index
}
/>
)
}
...
...
@@ -91,35 +137,41 @@ const Chat: FC<ChatProps> = ({
)
})
}
</
div
>
<
div
className=
{
`absolute bottom-0 ${(hasTryToAsk || !noChatInput || !noStopResponding) && chatFooterClassName}`
}
ref=
{
chatFooterRef
}
style=
{
{
background
:
'linear-gradient(0deg, #F9FAFB 40%, rgba(255, 255, 255, 0.00) 100%)'
,
}
}
>
{
(
hasTryToAsk
||
!
noChatInput
)
&&
(
<
div
className=
{
`sticky bottom-0 w-full backdrop-blur-[20px] ${chatFooterClassName}`
}
ref=
{
chatFooterRef
}
style=
{
{
background
:
'linear-gradient(0deg, #FFF 0%, rgba(255, 255, 255, 0.40) 100%)'
,
}
}
>
{
hasTryToAsk
&&
(
<
TryToAsk
suggestedQuestions=
{
suggestedQuestions
}
onSend=
{
onSend
}
/>
)
}
{
!
noChatInput
&&
(
<
ChatInput
visionConfig=
{
config
?.
file_upload
?.
image
}
speechToTextConfig=
{
config
.
speech_to_text
}
onSend=
{
onSend
}
/>
)
}
!
noStopResponding
&&
isResponsing
&&
(
<
div
className=
'flex justify-center mb-2'
>
<
Button
className=
'py-0 px-3 h-7 bg-white shadow-xs'
onClick=
{
onStopResponding
}
>
<
StopCircle
className=
'mr-[5px] w-3.5 h-3.5 text-gray-500'
/>
<
span
className=
'text-xs text-gray-500 font-normal'
>
{
t
(
'appDebug.operation.stopResponding'
)
}
</
span
>
</
Button
>
</
div
>
)
}
{
hasTryToAsk
&&
(
<
TryToAsk
suggestedQuestions=
{
suggestedQuestions
}
onSend=
{
onSend
}
/>
)
}
{
!
noChatInput
&&
(
<
ChatInput
visionConfig=
{
config
?.
file_upload
?.
image
}
speechToTextConfig=
{
config
?.
speech_to_text
}
onSend=
{
onSend
}
/>
)
}
</
div
>
</
div
>
</
ChatContextProvider
>
...
...
web/app/components/base/chat/types.ts
View file @
68406b99
...
...
@@ -41,7 +41,10 @@ export type EnableType = {
enabled
:
boolean
}
export
type
ChatConfig
=
Omit
<
ModelConfig
,
'model'
>
export
type
ChatConfig
=
Omit
<
ModelConfig
,
'model'
>
&
{
supportAnnotation
?:
boolean
appId
?:
string
}
export
type
ChatItem
=
IChatItem
...
...
web/context/debug-configuration.ts
View file @
68406b99
...
...
@@ -96,7 +96,7 @@ type IDebugConfiguration = {
hasSetContextVar
:
boolean
isShowVisionConfig
:
boolean
visionConfig
:
VisionSettings
setVisionConfig
:
(
visionConfig
:
VisionSettings
)
=>
void
setVisionConfig
:
(
visionConfig
:
VisionSettings
,
noNotice
?:
boolean
)
=>
void
}
const
DebugConfigurationContext
=
createContext
<
IDebugConfiguration
>
({
...
...
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