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
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> = ({
...
@@ -132,6 +132,7 @@ const EditAnnotationModal: FC<Props> = ({
onRemove=
{
()
=>
{
onRemove=
{
()
=>
{
onRemove
()
onRemove
()
setShowModal
(
false
)
setShowModal
(
false
)
onHide
()
}
}
}
}
text=
{
t
(
'appDebug.feature.annotation.removeConfirm'
)
as
string
}
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'
...
@@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next'
import
cn
from
'classnames'
import
cn
from
'classnames'
import
{
useContext
}
from
'use-context-selector'
import
{
useContext
}
from
'use-context-selector'
import
produce
from
'immer'
import
produce
from
'immer'
import
{
useFormattingChangedDispatcher
}
from
'../../../debug/hooks'
import
ChooseTool
from
'./choose-tool'
import
ChooseTool
from
'./choose-tool'
import
SettingBuiltInTool
from
'./setting-built-in-tool'
import
SettingBuiltInTool
from
'./setting-built-in-tool'
import
Panel
from
'@/app/components/app/configuration/base/feature-panel'
import
Panel
from
'@/app/components/app/configuration/base/feature-panel'
...
@@ -27,6 +28,7 @@ const AgentTools: FC = () => {
...
@@ -27,6 +28,7 @@ const AgentTools: FC = () => {
const
{
t
}
=
useTranslation
()
const
{
t
}
=
useTranslation
()
const
[
isShowChooseTool
,
setIsShowChooseTool
]
=
useState
(
false
)
const
[
isShowChooseTool
,
setIsShowChooseTool
]
=
useState
(
false
)
const
{
modelConfig
,
setModelConfig
,
collectionList
}
=
useContext
(
ConfigContext
)
const
{
modelConfig
,
setModelConfig
,
collectionList
}
=
useContext
(
ConfigContext
)
const
formattingChangedDispatcher
=
useFormattingChangedDispatcher
()
const
[
currentTool
,
setCurrentTool
]
=
useState
<
AgentToolWithMoreInfo
>
(
null
)
const
[
currentTool
,
setCurrentTool
]
=
useState
<
AgentToolWithMoreInfo
>
(
null
)
const
[
selectedProviderId
,
setSelectedProviderId
]
=
useState
<
string
|
undefined
>
(
undefined
)
const
[
selectedProviderId
,
setSelectedProviderId
]
=
useState
<
string
|
undefined
>
(
undefined
)
...
@@ -49,6 +51,7 @@ const AgentTools: FC = () => {
...
@@ -49,6 +51,7 @@ const AgentTools: FC = () => {
})
})
setModelConfig
(
newModelConfig
)
setModelConfig
(
newModelConfig
)
setIsShowSettingTool
(
false
)
setIsShowSettingTool
(
false
)
formattingChangedDispatcher
()
}
}
return
(
return
(
...
@@ -141,6 +144,7 @@ const AgentTools: FC = () => {
...
@@ -141,6 +144,7 @@ const AgentTools: FC = () => {
draft
.
agentConfig
.
tools
.
splice
(
index
,
1
)
draft
.
agentConfig
.
tools
.
splice
(
index
,
1
)
})
})
setModelConfig
(
newModelConfig
)
setModelConfig
(
newModelConfig
)
formattingChangedDispatcher
()
}
}
>
}
}
>
<
Trash03
className=
'w-4 h-4 text-gray-500'
/>
<
Trash03
className=
'w-4 h-4 text-gray-500'
/>
</
div
>
</
div
>
...
@@ -167,6 +171,7 @@ const AgentTools: FC = () => {
...
@@ -167,6 +171,7 @@ const AgentTools: FC = () => {
draft
.
agentConfig
.
tools
.
splice
(
index
,
1
)
draft
.
agentConfig
.
tools
.
splice
(
index
,
1
)
})
})
setModelConfig
(
newModelConfig
)
setModelConfig
(
newModelConfig
)
formattingChangedDispatcher
()
}
}
>
}
}
>
<
Trash03
className=
'w-4 h-4 text-gray-500'
/>
<
Trash03
className=
'w-4 h-4 text-gray-500'
/>
</
div
>
</
div
>
...
@@ -183,6 +188,7 @@ const AgentTools: FC = () => {
...
@@ -183,6 +188,7 @@ const AgentTools: FC = () => {
(
draft
.
agentConfig
.
tools
[
index
]
as
any
).
enabled
=
enabled
(
draft
.
agentConfig
.
tools
[
index
]
as
any
).
enabled
=
enabled
})
})
setModelConfig
(
newModelConfig
)
setModelConfig
(
newModelConfig
)
formattingChangedDispatcher
()
}
}
/>
}
}
/>
</
div
>
</
div
>
</
div
>
</
div
>
...
...
web/app/components/app/configuration/config/index.tsx
View file @
68406b99
...
@@ -4,6 +4,7 @@ import React, { useRef } from 'react'
...
@@ -4,6 +4,7 @@ import React, { useRef } from 'react'
import
{
useContext
}
from
'use-context-selector'
import
{
useContext
}
from
'use-context-selector'
import
produce
from
'immer'
import
produce
from
'immer'
import
{
useBoolean
,
useScroll
}
from
'ahooks'
import
{
useBoolean
,
useScroll
}
from
'ahooks'
import
{
useFormattingChangedDispatcher
}
from
'../debug/hooks'
import
DatasetConfig
from
'../dataset-config'
import
DatasetConfig
from
'../dataset-config'
import
ChatGroup
from
'../features/chat-group'
import
ChatGroup
from
'../features/chat-group'
import
ExperienceEnchanceGroup
from
'../features/experience-enchance-group'
import
ExperienceEnchanceGroup
from
'../features/experience-enchance-group'
...
@@ -44,7 +45,6 @@ const Config: FC = () => {
...
@@ -44,7 +45,6 @@ const Config: FC = () => {
modelConfig
,
modelConfig
,
setModelConfig
,
setModelConfig
,
setPrevPromptConfig
,
setPrevPromptConfig
,
setFormattingChanged
,
moreLikeThisConfig
,
moreLikeThisConfig
,
setMoreLikeThisConfig
,
setMoreLikeThisConfig
,
suggestedQuestionsAfterAnswerConfig
,
suggestedQuestionsAfterAnswerConfig
,
...
@@ -64,6 +64,7 @@ const Config: FC = () => {
...
@@ -64,6 +64,7 @@ const Config: FC = () => {
const
{
data
:
speech2textDefaultModel
}
=
useDefaultModel
(
4
)
const
{
data
:
speech2textDefaultModel
}
=
useDefaultModel
(
4
)
const
{
data
:
text2speechDefaultModel
}
=
useDefaultModel
(
5
)
const
{
data
:
text2speechDefaultModel
}
=
useDefaultModel
(
5
)
const
{
setShowModerationSettingModal
}
=
useModalContext
()
const
{
setShowModerationSettingModal
}
=
useModalContext
()
const
formattingChangedDispatcher
=
useFormattingChangedDispatcher
()
const
promptTemplate
=
modelConfig
.
configs
.
prompt_template
const
promptTemplate
=
modelConfig
.
configs
.
prompt_template
const
promptVariables
=
modelConfig
.
configs
.
prompt_variables
const
promptVariables
=
modelConfig
.
configs
.
prompt_variables
...
@@ -73,9 +74,8 @@ const Config: FC = () => {
...
@@ -73,9 +74,8 @@ const Config: FC = () => {
draft
.
configs
.
prompt_template
=
newTemplate
draft
.
configs
.
prompt_template
=
newTemplate
draft
.
configs
.
prompt_variables
=
[...
draft
.
configs
.
prompt_variables
,
...
newVariables
]
draft
.
configs
.
prompt_variables
=
[...
draft
.
configs
.
prompt_variables
,
...
newVariables
]
})
})
if
(
modelConfig
.
configs
.
prompt_template
!==
newTemplate
)
if
(
modelConfig
.
configs
.
prompt_template
!==
newTemplate
)
setFormattingChanged
(
true
)
formattingChangedDispatcher
(
)
setPrevPromptConfig
(
modelConfig
.
configs
)
setPrevPromptConfig
(
modelConfig
.
configs
)
setModelConfig
(
newModelConfig
)
setModelConfig
(
newModelConfig
)
...
@@ -107,6 +107,7 @@ const Config: FC = () => {
...
@@ -107,6 +107,7 @@ const Config: FC = () => {
setSuggestedQuestionsAfterAnswerConfig
(
produce
(
suggestedQuestionsAfterAnswerConfig
,
(
draft
:
SuggestedQuestionsAfterAnswerConfig
)
=>
{
setSuggestedQuestionsAfterAnswerConfig
(
produce
(
suggestedQuestionsAfterAnswerConfig
,
(
draft
:
SuggestedQuestionsAfterAnswerConfig
)
=>
{
draft
.
enabled
=
value
draft
.
enabled
=
value
}))
}))
formattingChangedDispatcher
()
},
},
speechToText
:
speechToTextConfig
.
enabled
,
speechToText
:
speechToTextConfig
.
enabled
,
setSpeechToText
:
(
value
)
=>
{
setSpeechToText
:
(
value
)
=>
{
...
@@ -125,6 +126,7 @@ const Config: FC = () => {
...
@@ -125,6 +126,7 @@ const Config: FC = () => {
setCitationConfig
(
produce
(
citationConfig
,
(
draft
:
CitationConfig
)
=>
{
setCitationConfig
(
produce
(
citationConfig
,
(
draft
:
CitationConfig
)
=>
{
draft
.
enabled
=
value
draft
.
enabled
=
value
}))
}))
formattingChangedDispatcher
()
},
},
annotation
:
annotationConfig
.
enabled
,
annotation
:
annotationConfig
.
enabled
,
setAnnotation
:
async
(
value
)
=>
{
setAnnotation
:
async
(
value
)
=>
{
...
...
web/app/components/app/configuration/dataset-config/index.tsx
View file @
68406b99
...
@@ -4,6 +4,7 @@ import React from 'react'
...
@@ -4,6 +4,7 @@ import React from 'react'
import
{
useTranslation
}
from
'react-i18next'
import
{
useTranslation
}
from
'react-i18next'
import
{
useContext
}
from
'use-context-selector'
import
{
useContext
}
from
'use-context-selector'
import
produce
from
'immer'
import
produce
from
'immer'
import
{
useFormattingChangedDispatcher
}
from
'../debug/hooks'
import
FeaturePanel
from
'../base/feature-panel'
import
FeaturePanel
from
'../base/feature-panel'
import
OperationBtn
from
'../base/operation-btn'
import
OperationBtn
from
'../base/operation-btn'
import
CardItem
from
'./card-item/item'
import
CardItem
from
'./card-item/item'
...
@@ -26,25 +27,25 @@ const DatasetConfig: FC = () => {
...
@@ -26,25 +27,25 @@ const DatasetConfig: FC = () => {
mode
,
mode
,
dataSets
:
dataSet
,
dataSets
:
dataSet
,
setDataSets
:
setDataSet
,
setDataSets
:
setDataSet
,
setFormattingChanged
,
modelConfig
,
modelConfig
,
setModelConfig
,
setModelConfig
,
showSelectDataSet
,
showSelectDataSet
,
isAgent
,
isAgent
,
}
=
useContext
(
ConfigContext
)
}
=
useContext
(
ConfigContext
)
const
formattingChangedDispatcher
=
useFormattingChangedDispatcher
()
const
hasData
=
dataSet
.
length
>
0
const
hasData
=
dataSet
.
length
>
0
const
onRemove
=
(
id
:
string
)
=>
{
const
onRemove
=
(
id
:
string
)
=>
{
setDataSet
(
dataSet
.
filter
(
item
=>
item
.
id
!==
id
))
setDataSet
(
dataSet
.
filter
(
item
=>
item
.
id
!==
id
))
setFormattingChanged
(
true
)
formattingChangedDispatcher
(
)
}
}
const
handleSave
=
(
newDataset
:
DataSet
)
=>
{
const
handleSave
=
(
newDataset
:
DataSet
)
=>
{
const
index
=
dataSet
.
findIndex
(
item
=>
item
.
id
===
newDataset
.
id
)
const
index
=
dataSet
.
findIndex
(
item
=>
item
.
id
===
newDataset
.
id
)
setDataSet
([...
dataSet
.
slice
(
0
,
index
),
newDataset
,
...
dataSet
.
slice
(
index
+
1
)])
setDataSet
([...
dataSet
.
slice
(
0
,
index
),
newDataset
,
...
dataSet
.
slice
(
index
+
1
)])
setFormattingChanged
(
true
)
formattingChangedDispatcher
(
)
}
}
const
promptVariables
=
modelConfig
.
configs
.
prompt_variables
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
type
{
FC
}
from
'react'
import
{
import
{
memo
,
memo
,
useCallback
,
useMemo
,
useMemo
,
}
from
'react'
}
from
'react'
import
type
{
ModelAndParameter
}
from
'../types'
import
type
{
ModelAndParameter
}
from
'../types'
...
@@ -9,16 +10,13 @@ import {
...
@@ -9,16 +10,13 @@ import {
APP_CHAT_WITH_MULTIPLE_MODEL_RESTART
,
APP_CHAT_WITH_MULTIPLE_MODEL_RESTART
,
}
from
'../types'
}
from
'../types'
import
{
import
{
AgentStrategy
,
useConfigFromDebugContext
,
ModelModeType
,
useFormattingChangedSubscription
,
}
from
'
@/types/app
'
}
from
'
../hooks
'
import
Chat
from
'@/app/components/base/chat/chat'
import
Chat
from
'@/app/components/base/chat/chat'
import
{
useChat
}
from
'@/app/components/base/chat/chat/hooks'
import
{
useChat
}
from
'@/app/components/base/chat/chat/hooks'
import
{
useDebugConfigurationContext
}
from
'@/context/debug-configuration'
import
{
useDebugConfigurationContext
}
from
'@/context/debug-configuration'
import
type
{
import
type
{
OnSend
}
from
'@/app/components/base/chat/types'
ChatConfig
,
OnSend
,
}
from
'@/app/components/base/chat/types'
import
{
useEventEmitterContextContext
}
from
'@/context/event-emitter'
import
{
useEventEmitterContextContext
}
from
'@/context/event-emitter'
import
{
useProviderContext
}
from
'@/context/provider-context'
import
{
useProviderContext
}
from
'@/context/provider-context'
import
{
import
{
...
@@ -26,7 +24,6 @@ import {
...
@@ -26,7 +24,6 @@ import {
fetchSuggestedQuestions
,
fetchSuggestedQuestions
,
stopChatMessageResponding
,
stopChatMessageResponding
,
}
from
'@/service/debug'
}
from
'@/service/debug'
import
{
promptVariablesToUserInputsForm
}
from
'@/utils/model-config'
import
Avatar
from
'@/app/components/base/avatar'
import
Avatar
from
'@/app/components/base/avatar'
import
{
useAppContext
}
from
'@/context/app-context'
import
{
useAppContext
}
from
'@/context/app-context'
import
{
ModelFeatureEnum
}
from
'@/app/components/header/account-setting/model-provider-page/declarations'
import
{
ModelFeatureEnum
}
from
'@/app/components/header/account-setting/model-provider-page/declarations'
...
@@ -39,66 +36,14 @@ const ChatItem: FC<ChatItemProps> = ({
...
@@ -39,66 +36,14 @@ const ChatItem: FC<ChatItemProps> = ({
})
=>
{
})
=>
{
const
{
userProfile
}
=
useAppContext
()
const
{
userProfile
}
=
useAppContext
()
const
{
const
{
isAdvancedMode
,
modelConfig
,
modelConfig
,
appId
,
appId
,
inputs
,
inputs
,
promptMode
,
speechToTextConfig
,
introduction
,
suggestedQuestions
:
openingSuggestedQuestions
,
suggestedQuestionsAfterAnswerConfig
,
citationConfig
,
moderationConfig
,
chatPromptConfig
,
completionPromptConfig
,
dataSets
,
datasetConfigs
,
visionConfig
,
visionConfig
,
annotationConfig
,
collectionList
,
collectionList
,
textToSpeechConfig
,
}
=
useDebugConfigurationContext
()
}
=
useDebugConfigurationContext
()
const
{
textGenerationModelList
}
=
useProviderContext
()
const
{
textGenerationModelList
}
=
useProviderContext
()
const
postDatasets
=
dataSets
.
map
(({
id
})
=>
({
const
config
=
useConfigFromDebugContext
()
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
{
const
{
chatList
,
chatList
,
isResponsing
,
isResponsing
,
...
@@ -114,8 +59,9 @@ const ChatItem: FC<ChatItemProps> = ({
...
@@ -114,8 +59,9 @@ const ChatItem: FC<ChatItemProps> = ({
[],
[],
taskId
=>
stopChatMessageResponding
(
appId
,
taskId
),
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
currentProvider
=
textGenerationModelList
.
find
(
item
=>
item
.
provider
===
modelAndParameter
.
provider
)
const
currentModel
=
currentProvider
?.
models
.
find
(
model
=>
model
.
model
===
modelAndParameter
.
model
)
const
currentModel
=
currentProvider
?.
models
.
find
(
model
=>
model
.
model
===
modelAndParameter
.
model
)
const
supportVision
=
currentModel
?.
features
?.
includes
(
ModelFeatureEnum
.
vision
)
const
supportVision
=
currentModel
?.
features
?.
includes
(
ModelFeatureEnum
.
vision
)
...
@@ -147,7 +93,7 @@ const ChatItem: FC<ChatItemProps> = ({
...
@@ -147,7 +93,7 @@ const ChatItem: FC<ChatItemProps> = ({
onGetSuggestedQuestions
:
(
responseItemId
,
getAbortController
)
=>
fetchSuggestedQuestions
(
appId
,
responseItemId
,
getAbortController
),
onGetSuggestedQuestions
:
(
responseItemId
,
getAbortController
)
=>
fetchSuggestedQuestions
(
appId
,
responseItemId
,
getAbortController
),
},
},
)
)
}
}
,
[
appId
,
config
,
handleSend
,
inputs
,
modelAndParameter
,
textGenerationModelList
,
visionConfig
.
enabled
])
const
{
eventEmitter
}
=
useEventEmitterContextContext
()
const
{
eventEmitter
}
=
useEventEmitterContextContext
()
eventEmitter
?.
useSubscription
((
v
:
any
)
=>
{
eventEmitter
?.
useSubscription
((
v
:
any
)
=>
{
...
@@ -174,8 +120,9 @@ const ChatItem: FC<ChatItemProps> = ({
...
@@ -174,8 +120,9 @@ const ChatItem: FC<ChatItemProps> = ({
chatList=
{
chatList
}
chatList=
{
chatList
}
isResponsing=
{
isResponsing
}
isResponsing=
{
isResponsing
}
noChatInput
noChatInput
noStopResponding
chatContainerclassName=
'p-4'
chatContainerclassName=
'p-4'
chatFooterClassName=
'
!-bottom-4
'
chatFooterClassName=
'
p-4 pb-0
'
suggestedQuestions=
{
suggestedQuestions
}
suggestedQuestions=
{
suggestedQuestions
}
onSend=
{
doSend
}
onSend=
{
doSend
}
showPromptLog
showPromptLog
...
...
web/app/components/app/configuration/debug/debug-with-multiple-model/context.tsx
View file @
68406b99
...
@@ -7,6 +7,7 @@ export type DebugWithMultipleModelContextType = {
...
@@ -7,6 +7,7 @@ export type DebugWithMultipleModelContextType = {
multipleModelConfigs
:
ModelAndParameter
[]
multipleModelConfigs
:
ModelAndParameter
[]
onMultipleModelConfigsChange
:
(
multiple
:
boolean
,
modelConfigs
:
ModelAndParameter
[])
=>
void
onMultipleModelConfigsChange
:
(
multiple
:
boolean
,
modelConfigs
:
ModelAndParameter
[])
=>
void
onDebugWithMultipleModelChange
:
(
singleModelConfig
:
ModelAndParameter
)
=>
void
onDebugWithMultipleModelChange
:
(
singleModelConfig
:
ModelAndParameter
)
=>
void
checkCanSend
?:
()
=>
boolean
}
}
const
DebugWithMultipleModelContext
=
createContext
<
DebugWithMultipleModelContextType
>
({
const
DebugWithMultipleModelContext
=
createContext
<
DebugWithMultipleModelContextType
>
({
multipleModelConfigs
:
[],
multipleModelConfigs
:
[],
...
@@ -24,12 +25,14 @@ export const DebugWithMultipleModelContextProvider = ({
...
@@ -24,12 +25,14 @@ export const DebugWithMultipleModelContextProvider = ({
onMultipleModelConfigsChange
,
onMultipleModelConfigsChange
,
multipleModelConfigs
,
multipleModelConfigs
,
onDebugWithMultipleModelChange
,
onDebugWithMultipleModelChange
,
checkCanSend
,
}:
DebugWithMultipleModelContextProviderProps
)
=>
{
}:
DebugWithMultipleModelContextProviderProps
)
=>
{
return
(
return
(
<
DebugWithMultipleModelContext
.
Provider
value=
{
{
<
DebugWithMultipleModelContext
.
Provider
value=
{
{
onMultipleModelConfigsChange
,
onMultipleModelConfigsChange
,
multipleModelConfigs
,
multipleModelConfigs
,
onDebugWithMultipleModelChange
,
onDebugWithMultipleModelChange
,
checkCanSend
,
}
}
>
}
}
>
{
children
}
{
children
}
</
DebugWithMultipleModelContext
.
Provider
>
</
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
{
useTranslation
}
from
'react-i18next'
import
{
memo
}
from
'react'
import
{
memo
}
from
'react'
import
type
{
ModelAndParameter
}
from
'../types'
import
type
{
ModelAndParameter
}
from
'../types'
...
@@ -15,10 +15,12 @@ import { ModelStatusEnum } from '@/app/components/header/account-setting/model-p
...
@@ -15,10 +15,12 @@ import { ModelStatusEnum } from '@/app/components/header/account-setting/model-p
type
DebugItemProps
=
{
type
DebugItemProps
=
{
modelAndParameter
:
ModelAndParameter
modelAndParameter
:
ModelAndParameter
className
?:
string
className
?:
string
style
?:
CSSProperties
}
}
const
DebugItem
:
FC
<
DebugItemProps
>
=
({
const
DebugItem
:
FC
<
DebugItemProps
>
=
({
modelAndParameter
,
modelAndParameter
,
className
,
className
,
style
,
})
=>
{
})
=>
{
const
{
t
}
=
useTranslation
()
const
{
t
}
=
useTranslation
()
const
{
mode
}
=
useDebugConfigurationContext
()
const
{
mode
}
=
useDebugConfigurationContext
()
...
@@ -61,7 +63,10 @@ const DebugItem: FC<DebugItemProps> = ({
...
@@ -61,7 +63,10 @@ const DebugItem: FC<DebugItemProps> = ({
}
}
return
(
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=
'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'
>
<
div
className=
'flex items-center justify-center w-6 h-5 font-medium italic text-gray-500'
>
#
{
index
+
1
}
#
{
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'
...
@@ -2,6 +2,7 @@ import type { FC } from 'react'
import
{
import
{
memo
,
memo
,
useCallback
,
useCallback
,
useMemo
,
}
from
'react'
}
from
'react'
import
{
APP_CHAT_WITH_MULTIPLE_MODEL
}
from
'../types'
import
{
APP_CHAT_WITH_MULTIPLE_MODEL
}
from
'../types'
import
DebugItem
from
'./debug-item'
import
DebugItem
from
'./debug-item'
...
@@ -21,10 +22,16 @@ const DebugWithMultipleModel = () => {
...
@@ -21,10 +22,16 @@ const DebugWithMultipleModel = () => {
speechToTextConfig
,
speechToTextConfig
,
visionConfig
,
visionConfig
,
}
=
useDebugConfigurationContext
()
}
=
useDebugConfigurationContext
()
const
{
multipleModelConfigs
}
=
useDebugWithMultipleModelContext
()
const
{
multipleModelConfigs
,
checkCanSend
,
}
=
useDebugWithMultipleModelContext
()
const
{
eventEmitter
}
=
useEventEmitterContextContext
()
const
{
eventEmitter
}
=
useEventEmitterContextContext
()
const
handleSend
=
useCallback
((
message
:
string
,
files
?:
VisionFile
[])
=>
{
const
handleSend
=
useCallback
((
message
:
string
,
files
?:
VisionFile
[])
=>
{
if
(
checkCanSend
&&
!
checkCanSend
())
return
eventEmitter
?.
emit
({
eventEmitter
?.
emit
({
type
:
APP_CHAT_WITH_MULTIPLE_MODEL
,
type
:
APP_CHAT_WITH_MULTIPLE_MODEL
,
payload
:
{
payload
:
{
...
@@ -32,72 +39,90 @@ const DebugWithMultipleModel = () => {
...
@@ -32,72 +39,90 @@ const DebugWithMultipleModel = () => {
files
,
files
,
},
},
}
as
any
)
}
as
any
)
},
[
eventEmitter
])
},
[
eventEmitter
,
checkCanSend
])
const
twoLine
=
multipleModelConfigs
.
length
===
2
const
twoLine
=
multipleModelConfigs
.
length
===
2
const
threeLine
=
multipleModelConfigs
.
length
===
3
const
threeLine
=
multipleModelConfigs
.
length
===
3
const
fourLine
=
multipleModelConfigs
.
length
===
4
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
(
return
(
<
div
className=
'flex flex-col h-full'
>
<
div
className=
'flex flex-col h-full'
>
<
div
<
div
className=
{
`
className=
{
`
mb-3 overflow-auto
grow mb-3 relative px-6 overflow-auto
${(twoLine || threeLine) && 'flex gap-2'}
`
}
`
}
style=
{
{
height
:
mode
===
'chat'
?
'calc(100% - 60px)'
:
'100%'
}
}
style=
{
{
height
:
mode
===
'chat'
?
'calc(100% - 60px)'
:
'100%'
}
}
>
>
{
{
(
twoLine
||
threeLine
)
&&
multipleModelConfigs
.
map
(
modelConfig
=>
(
multipleModelConfigs
.
map
((
modelConfig
,
index
)
=>
(
<
DebugItem
<
DebugItem
key=
{
modelConfig
.
id
}
key=
{
modelConfig
.
id
}
modelAndParameter=
{
modelConfig
}
modelAndParameter=
{
modelConfig
}
className=
{
`
className=
{
`
h-full min-h-[200px]
absolute left-6 top-0 min-h-[200px]
${twoLine && 'w-1/2'}
${twoLine && index === 0 && 'mr-2'}
${threeLine && 'w-1/3'}
${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
>
</
div
>
{
{
mode
===
'chat'
&&
(
mode
===
'chat'
&&
(
<
div
className=
'shrink-0'
>
<
div
className=
'shrink-0
pb-4 px-6
'
>
<
ChatInput
<
ChatInput
onSend=
{
handleSend
}
onSend=
{
handleSend
}
speechToTextConfig=
{
speechToTextConfig
}
speechToTextConfig=
{
speechToTextConfig
}
...
@@ -116,12 +141,14 @@ const DebugWithMultipleModelWrapper: FC<DebugWithMultipleModelContextType> = ({
...
@@ -116,12 +141,14 @@ const DebugWithMultipleModelWrapper: FC<DebugWithMultipleModelContextType> = ({
onMultipleModelConfigsChange
,
onMultipleModelConfigsChange
,
multipleModelConfigs
,
multipleModelConfigs
,
onDebugWithMultipleModelChange
,
onDebugWithMultipleModelChange
,
checkCanSend
,
})
=>
{
})
=>
{
return
(
return
(
<
DebugWithMultipleModelContextProvider
<
DebugWithMultipleModelContextProvider
onMultipleModelConfigsChange=
{
onMultipleModelConfigsChange
}
onMultipleModelConfigsChange=
{
onMultipleModelConfigsChange
}
multipleModelConfigs=
{
multipleModelConfigs
}
multipleModelConfigs=
{
multipleModelConfigs
}
onDebugWithMultipleModelChange=
{
onDebugWithMultipleModelChange
}
onDebugWithMultipleModelChange=
{
onDebugWithMultipleModelChange
}
checkCanSend=
{
checkCanSend
}
>
>
<
DebugWithMultipleModelMemoed
/>
<
DebugWithMultipleModelMemoed
/>
</
DebugWithMultipleModelContextProvider
>
</
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 {
...
@@ -7,6 +7,17 @@ import type {
DebugWithSingleOrMultipleModelConfigs
,
DebugWithSingleOrMultipleModelConfigs
,
ModelAndParameter
,
ModelAndParameter
,
}
from
'./types'
}
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
)
=>
{
export
const
useDebugWithSingleOrMultipleModel
=
(
appId
:
string
)
=>
{
const
localeDebugWithSingleOrMultipleModelConfigs
=
localStorage
.
getItem
(
'app-debug-with-single-or-multiple-models'
)
const
localeDebugWithSingleOrMultipleModelConfigs
=
localStorage
.
getItem
(
'app-debug-with-single-or-multiple-models'
)
...
@@ -52,3 +63,95 @@ export const useDebugWithSingleOrMultipleModel = (appId: string) => {
...
@@ -52,3 +63,95 @@ export const useDebugWithSingleOrMultipleModel = (appId: string) => {
handleMultipleModelConfigsChange
,
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
...
@@ -2,29 +2,27 @@
...
@@ -2,29 +2,27 @@
import
type
{
FC
}
from
'react'
import
type
{
FC
}
from
'react'
import
useSWR
from
'swr'
import
useSWR
from
'swr'
import
{
useTranslation
}
from
'react-i18next'
import
{
useTranslation
}
from
'react-i18next'
import
React
,
{
useEffect
,
useRef
,
useState
}
from
'react'
import
React
,
{
useCallback
,
useEffect
,
useState
}
from
'react'
import
cn
from
'classnames'
import
{
setAutoFreeze
}
from
'immer'
import
produce
,
{
setAutoFreeze
}
from
'immer'
import
{
useBoolean
}
from
'ahooks'
import
{
useBoolean
,
useGetState
}
from
'ahooks'
import
{
useContext
}
from
'use-context-selector'
import
{
useContext
}
from
'use-context-selector'
import
dayjs
from
'dayjs'
import
HasNotSetAPIKEY
from
'../base/warning-mask/has-not-set-api'
import
HasNotSetAPIKEY
from
'../base/warning-mask/has-not-set-api'
import
FormattingChanged
from
'../base/warning-mask/formatting-changed'
import
FormattingChanged
from
'../base/warning-mask/formatting-changed'
import
GroupName
from
'../base/group-name'
import
GroupName
from
'../base/group-name'
import
CannotQueryDataset
from
'../base/warning-mask/cannot-query-dataset'
import
CannotQueryDataset
from
'../base/warning-mask/cannot-query-dataset'
import
DebugWithMultipleModel
from
'./debug-with-multiple-model'
import
DebugWithMultipleModel
from
'./debug-with-multiple-model'
import
DebugWithSingleModel
from
'./debug-with-single-model'
import
type
{
DebugWithSingleModelRefType
}
from
'./debug-with-single-model'
import
type
{
ModelAndParameter
}
from
'./types'
import
type
{
ModelAndParameter
}
from
'./types'
import
{
import
{
APP_CHAT_WITH_MULTIPLE_MODEL
,
APP_CHAT_WITH_MULTIPLE_MODEL
,
APP_CHAT_WITH_MULTIPLE_MODEL_RESTART
,
APP_CHAT_WITH_MULTIPLE_MODEL_RESTART
,
}
from
'./types'
}
from
'./types'
import
{
AgentStrategy
,
AppType
,
ModelModeType
,
TransferMethod
}
from
'@/types/app'
import
{
AppType
,
ModelModeType
,
TransferMethod
}
from
'@/types/app'
import
PromptValuePanel
,
{
replaceStringWithValues
}
from
'@/app/components/app/configuration/prompt-value-panel'
import
PromptValuePanel
from
'@/app/components/app/configuration/prompt-value-panel'
import
type
{
IChatItem
}
from
'@/app/components/app/chat/type'
import
Chat
from
'@/app/components/app/chat'
import
ConfigContext
from
'@/context/debug-configuration'
import
ConfigContext
from
'@/context/debug-configuration'
import
{
ToastContext
}
from
'@/app/components/base/toast'
import
{
ToastContext
}
from
'@/app/components/base/toast'
import
{
fetchConvesationMessages
,
fetchSuggestedQuestions
,
sendChatMessage
,
sendCompletionMessage
,
stopChatMessageResponding
}
from
'@/service/debug'
import
{
sendCompletionMessage
}
from
'@/service/debug'
import
Button
from
'@/app/components/base/button'
import
Button
from
'@/app/components/base/button'
import
type
{
ModelConfig
as
BackendModelConfig
,
VisionFile
}
from
'@/types/app'
import
type
{
ModelConfig
as
BackendModelConfig
,
VisionFile
}
from
'@/types/app'
import
{
promptVariablesToUserInputsForm
}
from
'@/utils/model-config'
import
{
promptVariablesToUserInputsForm
}
from
'@/utils/model-config'
...
@@ -32,7 +30,6 @@ import TextGeneration from '@/app/components/app/text-generate/item'
...
@@ -32,7 +30,6 @@ import TextGeneration from '@/app/components/app/text-generate/item'
import
{
IS_CE_EDITION
}
from
'@/config'
import
{
IS_CE_EDITION
}
from
'@/config'
import
type
{
Inputs
}
from
'@/models/debug'
import
type
{
Inputs
}
from
'@/models/debug'
import
{
fetchFileUploadConfig
}
from
'@/service/common'
import
{
fetchFileUploadConfig
}
from
'@/service/common'
import
type
{
Annotation
as
AnnotationType
}
from
'@/models/log'
import
{
useDefaultModel
}
from
'@/app/components/header/account-setting/model-provider-page/hooks'
import
{
useDefaultModel
}
from
'@/app/components/header/account-setting/model-provider-page/hooks'
import
{
ModelFeatureEnum
}
from
'@/app/components/header/account-setting/model-provider-page/declarations'
import
{
ModelFeatureEnum
}
from
'@/app/components/header/account-setting/model-provider-page/declarations'
import
type
{
ModelParameterModalProps
}
from
'@/app/components/header/account-setting/model-provider-page/model-parameter-modal'
import
type
{
ModelParameterModalProps
}
from
'@/app/components/header/account-setting/model-provider-page/model-parameter-modal'
...
@@ -63,8 +60,6 @@ const Debug: FC<IDebug> = ({
...
@@ -63,8 +60,6 @@ const Debug: FC<IDebug> = ({
const
{
const
{
appId
,
appId
,
mode
,
mode
,
isFunctionCall
,
collectionList
,
modelModeType
,
modelModeType
,
hasSetBlockStatus
,
hasSetBlockStatus
,
isAdvancedMode
,
isAdvancedMode
,
...
@@ -72,7 +67,6 @@ const Debug: FC<IDebug> = ({
...
@@ -72,7 +67,6 @@ const Debug: FC<IDebug> = ({
chatPromptConfig
,
chatPromptConfig
,
completionPromptConfig
,
completionPromptConfig
,
introduction
,
introduction
,
suggestedQuestions
,
suggestedQuestionsAfterAnswerConfig
,
suggestedQuestionsAfterAnswerConfig
,
speechToTextConfig
,
speechToTextConfig
,
textToSpeechConfig
,
textToSpeechConfig
,
...
@@ -81,79 +75,36 @@ const Debug: FC<IDebug> = ({
...
@@ -81,79 +75,36 @@ const Debug: FC<IDebug> = ({
moreLikeThisConfig
,
moreLikeThisConfig
,
formattingChanged
,
formattingChanged
,
setFormattingChanged
,
setFormattingChanged
,
conversationId
,
setConversationId
,
controlClearChatMessage
,
dataSets
,
dataSets
,
modelConfig
,
modelConfig
,
completionParams
,
completionParams
,
hasSetContextVar
,
hasSetContextVar
,
datasetConfigs
,
datasetConfigs
,
visionConfig
,
visionConfig
,
annotationConfig
,
setVisionConfig
,
setVisionConfig
,
}
=
useContext
(
ConfigContext
)
}
=
useContext
(
ConfigContext
)
const
{
eventEmitter
}
=
useEventEmitterContextContext
()
const
{
eventEmitter
}
=
useEventEmitterContextContext
()
const
{
data
:
speech2textDefaultModel
}
=
useDefaultModel
(
4
)
const
{
data
:
text2speechDefaultModel
}
=
useDefaultModel
(
5
)
const
{
data
:
text2speechDefaultModel
}
=
useDefaultModel
(
5
)
const
[
chatList
,
setChatList
,
getChatList
]
=
useGetState
<
IChatItem
[]
>
([])
const
chatListDomRef
=
useRef
<
HTMLDivElement
>
(
null
)
const
{
data
:
fileUploadConfigResponse
}
=
useSWR
({
url
:
'/files/upload'
},
fetchFileUploadConfig
)
const
{
data
:
fileUploadConfigResponse
}
=
useSWR
({
url
:
'/files/upload'
},
fetchFileUploadConfig
)
// onData change thought (the produce obj). https://github.com/immerjs/immer/issues/576
useEffect
(()
=>
{
useEffect
(()
=>
{
setAutoFreeze
(
false
)
setAutoFreeze
(
false
)
return
()
=>
{
return
()
=>
{
setAutoFreeze
(
true
)
setAutoFreeze
(
true
)
}
}
},
[])
},
[])
useEffect
(()
=>
{
// scroll to bottom
if
(
chatListDomRef
.
current
)
chatListDomRef
.
current
.
scrollTop
=
chatListDomRef
.
current
.
scrollHeight
},
[
chatList
])
const
getIntroduction
=
()
=>
replaceStringWithValues
(
introduction
,
modelConfig
.
configs
.
prompt_variables
,
inputs
)
useEffect
(()
=>
{
if
(
introduction
&&
!
chatList
.
some
(
item
=>
!
item
.
isAnswer
))
{
setChatList
([{
id
:
`
${
Date
.
now
()}
`
,
content
:
getIntroduction
(),
isAnswer
:
true
,
isOpeningStatement
:
true
,
suggestedQuestions
,
}])
}
},
[
introduction
,
suggestedQuestions
,
modelConfig
.
configs
.
prompt_variables
,
inputs
])
const
[
isResponsing
,
{
setTrue
:
setResponsingTrue
,
setFalse
:
setResponsingFalse
}]
=
useBoolean
(
false
)
const
[
isResponsing
,
{
setTrue
:
setResponsingTrue
,
setFalse
:
setResponsingFalse
}]
=
useBoolean
(
false
)
const
[
abortController
,
setAbortController
]
=
useState
<
AbortController
|
null
>
(
null
)
const
[
isShowFormattingChangeConfirm
,
setIsShowFormattingChangeConfirm
]
=
useState
(
false
)
const
[
isShowFormattingChangeConfirm
,
setIsShowFormattingChangeConfirm
]
=
useState
(
false
)
const
[
isShowCannotQueryDataset
,
setShowCannotQueryDataset
]
=
useState
(
false
)
const
[
isShowCannotQueryDataset
,
setShowCannotQueryDataset
]
=
useState
(
false
)
const
[
isShowSuggestion
,
setIsShowSuggestion
]
=
useState
(
false
)
const
[
messageTaskId
,
setMessageTaskId
]
=
useState
(
''
)
const
[
hasStopResponded
,
setHasStopResponded
,
getHasStopResponded
]
=
useGetState
(
false
)
useEffect
(()
=>
{
useEffect
(()
=>
{
if
(
formattingChanged
&&
chatList
.
some
(
item
=>
!
item
.
isAnswer
)
)
if
(
formattingChanged
)
setIsShowFormattingChangeConfirm
(
true
)
setIsShowFormattingChangeConfirm
(
true
)
setFormattingChanged
(
false
)
},
[
formattingChanged
])
},
[
formattingChanged
])
const
debugWithSingleModelRef
=
React
.
useRef
<
DebugWithSingleModelRefType
|
null
>
(
null
)
const
handleClearConversation
=
()
=>
{
const
handleClearConversation
=
()
=>
{
setConversationId
(
null
)
debugWithSingleModelRef
.
current
?.
handleRestart
()
abortController
?.
abort
()
setResponsingFalse
()
setChatList
(
introduction
?
[{
id
:
`
${
Date
.
now
()}
`
,
content
:
getIntroduction
(),
isAnswer
:
true
,
isOpeningStatement
:
true
,
suggestedQuestions
,
}]
:
[])
setIsShowSuggestion
(
false
)
}
}
const
clearConversation
=
async
()
=>
{
const
clearConversation
=
async
()
=>
{
if
(
debugWithMultipleModel
)
{
if
(
debugWithMultipleModel
)
{
...
@@ -169,18 +120,21 @@ const Debug: FC<IDebug> = ({
...
@@ -169,18 +120,21 @@ const Debug: FC<IDebug> = ({
const
handleConfirm
=
()
=>
{
const
handleConfirm
=
()
=>
{
clearConversation
()
clearConversation
()
setIsShowFormattingChangeConfirm
(
false
)
setIsShowFormattingChangeConfirm
(
false
)
setFormattingChanged
(
false
)
}
}
const
handleCancel
=
()
=>
{
const
handleCancel
=
()
=>
{
setIsShowFormattingChangeConfirm
(
false
)
setIsShowFormattingChangeConfirm
(
false
)
setFormattingChanged
(
false
)
}
}
const
{
notify
}
=
useContext
(
ToastContext
)
const
{
notify
}
=
useContext
(
ToastContext
)
const
logError
=
(
message
:
string
)
=>
{
const
logError
=
useCallback
(
(
message
:
string
)
=>
{
notify
({
type
:
'error'
,
message
})
notify
({
type
:
'error'
,
message
})
}
},
[
notify
])
const
[
completionFiles
,
setCompletionFiles
]
=
useState
<
VisionFile
[]
>
([])
const
checkCanSend
=
()
=>
{
const
checkCanSend
=
useCallback
(
()
=>
{
if
(
isAdvancedMode
&&
mode
===
AppType
.
chat
)
{
if
(
isAdvancedMode
&&
mode
===
AppType
.
chat
)
{
if
(
modelModeType
===
ModelModeType
.
completion
)
{
if
(
modelModeType
===
ModelModeType
.
completion
)
{
if
(
!
hasSetBlockStatus
.
history
)
{
if
(
!
hasSetBlockStatus
.
history
)
{
...
@@ -214,319 +168,28 @@ const Debug: FC<IDebug> = ({
...
@@ -214,319 +168,28 @@ const Debug: FC<IDebug> = ({
return
false
return
false
}
}
// eslint-disable-next-line @typescript-eslint/no-use-before-define
if
(
completionFiles
.
find
(
item
=>
item
.
transfer_method
===
TransferMethod
.
local_file
&&
!
item
.
upload_file_id
))
{
if
(
completionFiles
.
find
(
item
=>
item
.
transfer_method
===
TransferMethod
.
local_file
&&
!
item
.
upload_file_id
))
{
notify
({
type
:
'info'
,
message
:
t
(
'appDebug.errorMessage.waitForImgUpload'
)
})
notify
({
type
:
'info'
,
message
:
t
(
'appDebug.errorMessage.waitForImgUpload'
)
})
return
false
return
false
}
}
return
!
hasEmptyInput
return
!
hasEmptyInput
}
},
[
completionFiles
,
const
doShowSuggestion
=
isShowSuggestion
&&
!
isResponsing
hasSetBlockStatus
.
history
,
const
[
suggestQuestions
,
setSuggestQuestions
]
=
useState
<
string
[]
>
([])
hasSetBlockStatus
.
query
,
const
[
userQuery
,
setUserQuery
]
=
useState
(
''
)
inputs
,
const
onSend
=
async
(
message
:
string
,
files
?:
VisionFile
[])
=>
{
isAdvancedMode
,
if
(
isResponsing
)
{
mode
,
notify
({
type
:
'info'
,
message
:
t
(
'appDebug.errorMessage.waitForResponse'
)
})
modelConfig
.
configs
.
prompt_variables
,
return
false
t
,
}
logError
,
notify
,
if
(
files
?.
find
(
item
=>
item
.
transfer_method
===
TransferMethod
.
local_file
&&
!
item
.
upload_file_id
))
{
modelModeType
,
notify
({
type
:
'info'
,
message
:
t
(
'appDebug.errorMessage.waitForImgUpload'
)
})
])
return
false
}
const
postDatasets
=
dataSets
.
map
(({
id
})
=>
({
dataset
:
{
enabled
:
true
,
id
,
},
}))
const
contextVar
=
modelConfig
.
configs
.
prompt_variables
.
find
(
item
=>
item
.
is_context_var
)?.
key
const
updateCurrentQA
=
({
responseItem
,
questionId
,
placeholderAnswerId
,
questionItem
,
}:
{
responseItem
:
IChatItem
questionId
:
string
placeholderAnswerId
:
string
questionItem
:
IChatItem
})
=>
{
// closesure new list is outdated.
const
newListWithAnswer
=
produce
(
getChatList
().
filter
(
item
=>
item
.
id
!==
responseItem
.
id
&&
item
.
id
!==
placeholderAnswerId
),
(
draft
)
=>
{
if
(
!
draft
.
find
(
item
=>
item
.
id
===
questionId
))
draft
.
push
({
...
questionItem
})
draft
.
push
({
...
responseItem
})
})
setChatList
(
newListWithAnswer
)
}
const
postModelConfig
:
BackendModelConfig
=
{
text_to_speech
:
{
enabled
:
false
,
},
pre_prompt
:
!
isAdvancedMode
?
modelConfig
.
configs
.
prompt_template
:
''
,
prompt_type
:
promptMode
,
chat_prompt_config
:
{},
completion_prompt_config
:
{},
user_input_form
:
promptVariablesToUserInputsForm
(
modelConfig
.
configs
.
prompt_variables
),
dataset_query_variable
:
contextVar
||
''
,
opening_statement
:
introduction
,
more_like_this
:
{
enabled
:
false
,
},
suggested_questions_after_answer
:
suggestedQuestionsAfterAnswerConfig
,
speech_to_text
:
speechToTextConfig
,
retriever_resource
:
citationConfig
,
sensitive_word_avoidance
:
moderationConfig
,
agent_mode
:
{
...
modelConfig
.
agentConfig
,
strategy
:
isFunctionCall
?
AgentStrategy
.
functionCall
:
AgentStrategy
.
react
,
},
model
:
{
provider
:
modelConfig
.
provider
,
name
:
modelConfig
.
model_id
,
mode
:
modelConfig
.
mode
,
completion_params
:
completionParams
as
any
,
},
dataset_configs
:
{
...
datasetConfigs
,
datasets
:
{
datasets
:
[...
postDatasets
],
}
as
any
,
},
file_upload
:
{
image
:
visionConfig
,
},
annotation_reply
:
annotationConfig
,
}
if
(
isAdvancedMode
)
{
postModelConfig
.
chat_prompt_config
=
chatPromptConfig
postModelConfig
.
completion_prompt_config
=
completionPromptConfig
}
const
data
:
Record
<
string
,
any
>
=
{
conversation_id
:
conversationId
,
inputs
,
query
:
message
,
model_config
:
postModelConfig
,
}
if
(
visionConfig
.
enabled
&&
files
&&
files
?.
length
>
0
)
{
data
.
files
=
files
.
map
((
item
)
=>
{
if
(
item
.
transfer_method
===
TransferMethod
.
local_file
)
{
return
{
...
item
,
url
:
''
,
}
}
return
item
})
}
// qustion
const
questionId
=
`question-
${
Date
.
now
()}
`
const
questionItem
=
{
id
:
questionId
,
content
:
message
,
isAnswer
:
false
,
message_files
:
files
,
}
const
placeholderAnswerId
=
`answer-placeholder-
${
Date
.
now
()}
`
const
placeholderAnswerItem
=
{
id
:
placeholderAnswerId
,
content
:
''
,
isAnswer
:
true
,
}
const
newList
=
[...
getChatList
(),
questionItem
,
placeholderAnswerItem
]
setChatList
(
newList
)
let
isAgentMode
=
false
// answer
const
responseItem
:
IChatItem
=
{
id
:
`
${
Date
.
now
()}
`
,
content
:
''
,
agent_thoughts
:
[],
message_files
:
[],
isAnswer
:
true
,
}
let
hasSetResponseId
=
false
let
_newConversationId
:
null
|
string
=
null
setHasStopResponded
(
false
)
setResponsingTrue
()
setIsShowSuggestion
(
false
)
sendChatMessage
(
appId
,
data
,
{
getAbortController
:
(
abortController
)
=>
{
setAbortController
(
abortController
)
},
onData
:
(
message
:
string
,
isFirstMessage
:
boolean
,
{
conversationId
:
newConversationId
,
messageId
,
taskId
}:
any
)
=>
{
// console.log('onData', message)
if
(
!
isAgentMode
)
{
responseItem
.
content
=
responseItem
.
content
+
message
}
else
{
const
lastThought
=
responseItem
.
agent_thoughts
?.[
responseItem
.
agent_thoughts
?.
length
-
1
]
if
(
lastThought
)
lastThought
.
thought
=
lastThought
.
thought
+
message
// need immer setAutoFreeze
}
if
(
messageId
&&
!
hasSetResponseId
)
{
responseItem
.
id
=
messageId
hasSetResponseId
=
true
}
if
(
isFirstMessage
&&
newConversationId
)
{
setConversationId
(
newConversationId
)
_newConversationId
=
newConversationId
}
setMessageTaskId
(
taskId
)
updateCurrentQA
({
responseItem
,
questionId
,
placeholderAnswerId
,
questionItem
,
})
},
async
onCompleted
(
hasError
?:
boolean
)
{
setResponsingFalse
()
if
(
hasError
)
return
if
(
_newConversationId
)
{
const
{
data
}:
any
=
await
fetchConvesationMessages
(
appId
,
_newConversationId
as
string
)
const
newResponseItem
=
data
.
find
((
item
:
any
)
=>
item
.
id
===
responseItem
.
id
)
if
(
!
newResponseItem
)
return
setChatList
(
produce
(
getChatList
(),
(
draft
)
=>
{
const
index
=
draft
.
findIndex
(
item
=>
item
.
id
===
responseItem
.
id
)
if
(
index
!==
-
1
)
{
const
requestion
=
draft
[
index
-
1
]
draft
[
index
-
1
]
=
{
...
requestion
,
log
:
newResponseItem
.
message
,
}
draft
[
index
]
=
{
...
draft
[
index
],
more
:
{
time
:
dayjs
.
unix
(
newResponseItem
.
created_at
).
format
(
'hh:mm A'
),
tokens
:
newResponseItem
.
answer_tokens
+
newResponseItem
.
message_tokens
,
latency
:
newResponseItem
.
provider_response_latency
.
toFixed
(
2
),
},
}
}
}))
}
if
(
suggestedQuestionsAfterAnswerConfig
.
enabled
&&
!
getHasStopResponded
())
{
const
{
data
}:
any
=
await
fetchSuggestedQuestions
(
appId
,
responseItem
.
id
)
setSuggestQuestions
(
data
)
setIsShowSuggestion
(
true
)
}
},
onFile
(
file
)
{
const
lastThought
=
responseItem
.
agent_thoughts
?.[
responseItem
.
agent_thoughts
?.
length
-
1
]
if
(
lastThought
)
responseItem
.
agent_thoughts
!
[
responseItem
.
agent_thoughts
!
.
length
-
1
].
message_files
=
[...(
lastThought
as
any
).
message_files
,
file
]
updateCurrentQA
({
responseItem
,
questionId
,
placeholderAnswerId
,
questionItem
,
})
},
onThought
(
thought
)
{
isAgentMode
=
true
const
response
=
responseItem
as
any
if
(
thought
.
message_id
&&
!
hasSetResponseId
)
response
.
id
=
thought
.
message_id
if
(
response
.
agent_thoughts
.
length
===
0
)
{
response
.
agent_thoughts
.
push
(
thought
)
}
else
{
const
lastThought
=
response
.
agent_thoughts
[
response
.
agent_thoughts
.
length
-
1
]
// thought changed but still the same thought, so update.
if
(
lastThought
.
id
===
thought
.
id
)
{
thought
.
thought
=
lastThought
.
thought
thought
.
message_files
=
lastThought
.
message_files
responseItem
.
agent_thoughts
!
[
response
.
agent_thoughts
.
length
-
1
]
=
thought
}
else
{
responseItem
.
agent_thoughts
!
.
push
(
thought
)
}
}
updateCurrentQA
({
responseItem
,
questionId
,
placeholderAnswerId
,
questionItem
,
})
},
onMessageEnd
:
(
messageEnd
)
=>
{
if
(
messageEnd
.
metadata
?.
annotation_reply
)
{
responseItem
.
id
=
messageEnd
.
id
responseItem
.
annotation
=
({
id
:
messageEnd
.
metadata
.
annotation_reply
.
id
,
authorName
:
messageEnd
.
metadata
.
annotation_reply
.
account
.
name
,
}
as
AnnotationType
)
const
newListWithAnswer
=
produce
(
getChatList
().
filter
(
item
=>
item
.
id
!==
responseItem
.
id
&&
item
.
id
!==
placeholderAnswerId
),
(
draft
)
=>
{
if
(
!
draft
.
find
(
item
=>
item
.
id
===
questionId
))
draft
.
push
({
...
questionItem
})
draft
.
push
({
...
responseItem
,
})
})
setChatList
(
newListWithAnswer
)
return
}
responseItem
.
citation
=
messageEnd
.
metadata
?.
retriever_resources
||
[]
const
newListWithAnswer
=
produce
(
getChatList
().
filter
(
item
=>
item
.
id
!==
responseItem
.
id
&&
item
.
id
!==
placeholderAnswerId
),
(
draft
)
=>
{
if
(
!
draft
.
find
(
item
=>
item
.
id
===
questionId
))
draft
.
push
({
...
questionItem
})
draft
.
push
({
...
responseItem
})
})
setChatList
(
newListWithAnswer
)
},
onMessageReplace
:
(
messageReplace
)
=>
{
responseItem
.
content
=
messageReplace
.
answer
},
onError
()
{
setResponsingFalse
()
// role back placeholder answer
setChatList
(
produce
(
getChatList
(),
(
draft
)
=>
{
draft
.
splice
(
draft
.
findIndex
(
item
=>
item
.
id
===
placeholderAnswerId
),
1
)
}))
},
})
return
true
}
useEffect
(()
=>
{
if
(
controlClearChatMessage
)
setChatList
([])
},
[
controlClearChatMessage
])
const
[
completionRes
,
setCompletionRes
]
=
useState
(
''
)
const
[
completionRes
,
setCompletionRes
]
=
useState
(
''
)
const
[
messageId
,
setMessageId
]
=
useState
<
string
|
null
>
(
null
)
const
[
messageId
,
setMessageId
]
=
useState
<
string
|
null
>
(
null
)
const
[
completionFiles
,
setCompletionFiles
]
=
useState
<
VisionFile
[]
>
([])
const
sendTextCompletion
=
async
()
=>
{
const
sendTextCompletion
=
async
()
=>
{
if
(
isResponsing
)
{
if
(
isResponsing
)
{
notify
({
type
:
'info'
,
message
:
t
(
'appDebug.errorMessage.waitForResponse'
)
})
notify
({
type
:
'info'
,
message
:
t
(
'appDebug.errorMessage.waitForResponse'
)
})
...
@@ -685,13 +348,13 @@ const Debug: FC<IDebug> = ({
...
@@ -685,13 +348,13 @@ const Debug: FC<IDebug> = ({
setVisionConfig
({
setVisionConfig
({
...
visionConfig
,
...
visionConfig
,
enabled
:
true
,
enabled
:
true
,
})
}
,
true
)
}
}
else
{
else
{
setVisionConfig
({
setVisionConfig
({
...
visionConfig
,
...
visionConfig
,
enabled
:
false
,
enabled
:
false
,
})
}
,
true
)
}
}
}
}
}
}
...
@@ -699,17 +362,10 @@ const Debug: FC<IDebug> = ({
...
@@ -699,17 +362,10 @@ const Debug: FC<IDebug> = ({
useEffect
(()
=>
{
useEffect
(()
=>
{
handleVisionConfigInMultipleModel
()
handleVisionConfigInMultipleModel
()
},
[
multipleModelConfigs
,
mode
])
},
[
multipleModelConfigs
,
mode
])
const
allToolIcons
=
(()
=>
{
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
})()
return
(
return
(
<>
<>
<
div
className=
"shrink-0"
>
<
div
className=
"shrink-0
pt-4 px-6
"
>
<
div
className=
'flex items-center justify-between mb-2'
>
<
div
className=
'flex items-center justify-between mb-2'
>
<
div
className=
'h2 '
>
{
t
(
'appDebug.inputs.title'
)
}
</
div
>
<
div
className=
'h2 '
>
{
t
(
'appDebug.inputs.title'
)
}
</
div
>
<
div
className=
'flex items-center'
>
<
div
className=
'flex items-center'
>
...
@@ -761,6 +417,7 @@ const Debug: FC<IDebug> = ({
...
@@ -761,6 +417,7 @@ const Debug: FC<IDebug> = ({
multipleModelConfigs=
{
multipleModelConfigs
}
multipleModelConfigs=
{
multipleModelConfigs
}
onMultipleModelConfigsChange=
{
onMultipleModelConfigsChange
}
onMultipleModelConfigsChange=
{
onMultipleModelConfigsChange
}
onDebugWithMultipleModelChange=
{
handleChangeToSingleModel
}
onDebugWithMultipleModelChange=
{
handleChangeToSingleModel
}
checkCanSend=
{
checkCanSend
}
/>
/>
</
div
>
</
div
>
)
)
...
@@ -770,47 +427,16 @@ const Debug: FC<IDebug> = ({
...
@@ -770,47 +427,16 @@ const Debug: FC<IDebug> = ({
<
div
className=
"flex flex-col grow"
>
<
div
className=
"flex flex-col grow"
>
{
/* Chat */
}
{
/* Chat */
}
{
mode
===
AppType
.
chat
&&
(
{
mode
===
AppType
.
chat
&&
(
<
div
className=
"mt-[34px] h-full flex flex-col"
>
<
div
className=
'grow h-0 overflow-hidden'
>
<
div
className=
{
cn
(
doShowSuggestion
?
'pb-[140px]'
:
(
isResponsing
?
'pb-[113px]'
:
'pb-[76px]'
),
'relative mt-1.5 grow h-[200px] overflow-hidden'
)
}
>
<
DebugWithSingleModel
<
div
className=
"h-full overflow-y-auto overflow-x-hidden"
ref=
{
chatListDomRef
}
>
ref=
{
debugWithSingleModelRef
}
<
Chat
checkCanSend=
{
checkCanSend
}
chatList=
{
chatList
}
/>
query=
{
userQuery
}
onQueryChange=
{
setUserQuery
}
onSend=
{
onSend
}
checkCanSend=
{
checkCanSend
}
feedbackDisabled
useCurrentUserAvatar
isResponsing=
{
isResponsing
}
canStopResponsing=
{
!!
messageTaskId
}
abortResponsing=
{
async
()
=>
{
await
stopChatMessageResponding
(
appId
,
messageTaskId
)
setHasStopResponded
(
true
)
setResponsingFalse
()
}
}
isShowSuggestion=
{
doShowSuggestion
}
suggestionList=
{
suggestQuestions
}
isShowSpeechToText=
{
speechToTextConfig
.
enabled
&&
!!
speech2textDefaultModel
}
isShowTextToSpeech=
{
textToSpeechConfig
.
enabled
&&
!!
text2speechDefaultModel
}
isShowCitation=
{
citationConfig
.
enabled
}
isShowCitationHitInfo
isShowPromptLog
visionConfig=
{
{
...
visionConfig
,
image_file_size_limit
:
fileUploadConfigResponse
?.
image_file_size_limit
,
}
}
supportAnnotation
appId=
{
appId
}
onChatListChange=
{
setChatList
}
allToolIcons=
{
allToolIcons
}
/>
</
div
>
</
div
>
</
div
>
</
div
>
)
}
)
}
{
/* Text Generation */
}
{
/* Text Generation */
}
{
mode
===
AppType
.
completion
&&
(
{
mode
===
AppType
.
completion
&&
(
<
div
className=
"mt-6"
>
<
div
className=
"mt-6
px-6 pb-4
"
>
<
GroupName
name=
{
t
(
'appDebug.result'
)
}
/>
<
GroupName
name=
{
t
(
'appDebug.result'
)
}
/>
{
(
completionRes
||
isResponsing
)
&&
(
{
(
completionRes
||
isResponsing
)
&&
(
<
TextGeneration
<
TextGeneration
...
@@ -830,12 +456,6 @@ const Debug: FC<IDebug> = ({
...
@@ -830,12 +456,6 @@ const Debug: FC<IDebug> = ({
)
}
)
}
</
div
>
</
div
>
)
}
)
}
{
isShowFormattingChangeConfirm
&&
(
<
FormattingChanged
onConfirm=
{
handleConfirm
}
onCancel=
{
handleCancel
}
/>
)
}
{
isShowCannotQueryDataset
&&
(
{
isShowCannotQueryDataset
&&
(
<
CannotQueryDataset
<
CannotQueryDataset
onConfirm=
{
()
=>
setShowCannotQueryDataset
(
false
)
}
onConfirm=
{
()
=>
setShowCannotQueryDataset
(
false
)
}
...
@@ -844,6 +464,12 @@ const Debug: FC<IDebug> = ({
...
@@ -844,6 +464,12 @@ const Debug: FC<IDebug> = ({
</
div
>
</
div
>
)
)
}
}
{
isShowFormattingChangeConfirm
&&
(
<
FormattingChanged
onConfirm=
{
handleConfirm
}
onCancel=
{
handleCancel
}
/>
)
}
{
!
hasSetAPIKEY
&&
(<
HasNotSetAPIKEY
isTrailFinished=
{
!
IS_CE_EDITION
}
onSetting=
{
onSetting
}
/>)
}
{
!
hasSetAPIKEY
&&
(<
HasNotSetAPIKEY
isTrailFinished=
{
!
IS_CE_EDITION
}
onSetting=
{
onSetting
}
/>)
}
</>
</>
)
)
...
...
web/app/components/app/configuration/debug/types.ts
View file @
68406b99
...
@@ -16,3 +16,4 @@ export type DebugWithSingleOrMultipleModelConfigs = {
...
@@ -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
=
'APP_CHAT_WITH_MULTIPLE_MODEL'
export
const
APP_CHAT_WITH_MULTIPLE_MODEL_RESTART
=
'APP_CHAT_WITH_MULTIPLE_MODEL_RESTART'
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
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'
...
@@ -13,7 +13,10 @@ import Button from '../../base/button'
import
Loading
from
'../../base/loading'
import
Loading
from
'../../base/loading'
import
useAdvancedPromptConfig
from
'./hooks/use-advanced-prompt-config'
import
useAdvancedPromptConfig
from
'./hooks/use-advanced-prompt-config'
import
EditHistoryModal
from
'./config-prompt/conversation-histroy/edit-modal'
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
type
{
ModelAndParameter
}
from
'./debug/types'
import
{
APP_SIDEBAR_SHOULD_COLLAPSE
}
from
'./debug/types'
import
{
APP_SIDEBAR_SHOULD_COLLAPSE
}
from
'./debug/types'
import
PublishWithMultipleModel
from
'./debug/debug-with-multiple-model/publish-with-multiple-model'
import
PublishWithMultipleModel
from
'./debug/debug-with-multiple-model/publish-with-multiple-model'
...
@@ -45,7 +48,6 @@ import { AgentStrategy, AppType, ModelModeType, RETRIEVE_TYPE, Resolution, Trans
...
@@ -45,7 +48,6 @@ import { AgentStrategy, AppType, ModelModeType, RETRIEVE_TYPE, Resolution, Trans
import
{
PromptMode
}
from
'@/models/debug'
import
{
PromptMode
}
from
'@/models/debug'
import
{
ANNOTATION_DEFAULT
,
DEFAULT_AGENT_SETTING
,
DEFAULT_CHAT_PROMPT_CONFIG
,
DEFAULT_COMPLETION_PROMPT_CONFIG
,
supportFunctionCallModels
}
from
'@/config'
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
SelectDataSet
from
'@/app/components/app/configuration/dataset-config/select-dataset'
import
I18n
from
'@/context/i18n'
import
{
useModalContext
}
from
'@/context/modal-context'
import
{
useModalContext
}
from
'@/context/modal-context'
import
useBreakpoints
,
{
MediaType
}
from
'@/hooks/use-breakpoints'
import
useBreakpoints
,
{
MediaType
}
from
'@/hooks/use-breakpoints'
import
Drawer
from
'@/app/components/base/drawer'
import
Drawer
from
'@/app/components/base/drawer'
...
@@ -111,10 +113,11 @@ const Configuration: FC = () => {
...
@@ -111,10 +113,11 @@ const Configuration: FC = () => {
embedding_model_name
:
''
,
embedding_model_name
:
''
,
},
},
})
})
const
formattingChangedDispatcher
=
useFormattingChangedDispatcher
()
const
setAnnotationConfig
=
(
config
:
AnnotationReplyConfig
,
notSetFormatChanged
?:
boolean
)
=>
{
const
setAnnotationConfig
=
(
config
:
AnnotationReplyConfig
,
notSetFormatChanged
?:
boolean
)
=>
{
doSetAnnotationConfig
(
config
)
doSetAnnotationConfig
(
config
)
if
(
!
notSetFormatChanged
)
if
(
!
notSetFormatChanged
)
setFormattingChanged
(
true
)
formattingChangedDispatcher
(
)
}
}
const
[
moderationConfig
,
setModerationConfig
]
=
useState
<
ModerationConfig
>
({
const
[
moderationConfig
,
setModerationConfig
]
=
useState
<
ModerationConfig
>
({
...
@@ -203,7 +206,7 @@ const Configuration: FC = () => {
...
@@ -203,7 +206,7 @@ const Configuration: FC = () => {
return
return
}
}
setFormattingChanged
(
true
)
formattingChangedDispatcher
(
)
if
(
data
.
find
(
item
=>
!
item
.
name
))
{
// has not loaded selected dataset
if
(
data
.
find
(
item
=>
!
item
.
name
))
{
// has not loaded selected dataset
const
newSelected
=
produce
(
data
,
(
draft
:
any
)
=>
{
const
newSelected
=
produce
(
data
,
(
draft
:
any
)
=>
{
data
.
forEach
((
item
,
index
)
=>
{
data
.
forEach
((
item
,
index
)
=>
{
...
@@ -299,7 +302,7 @@ const Configuration: FC = () => {
...
@@ -299,7 +302,7 @@ const Configuration: FC = () => {
transfer_methods
:
config
.
transfer_methods
||
[
TransferMethod
.
local_file
],
transfer_methods
:
config
.
transfer_methods
||
[
TransferMethod
.
local_file
],
})
})
if
(
!
notNoticeFormattingChanged
)
if
(
!
notNoticeFormattingChanged
)
setFormattingChanged
(
true
)
formattingChangedDispatcher
(
)
}
}
const
{
const
{
...
@@ -634,7 +637,6 @@ const Configuration: FC = () => {
...
@@ -634,7 +637,6 @@ const Configuration: FC = () => {
}
}
const
[
showUseGPT4Confirm
,
setShowUseGPT4Confirm
]
=
useState
(
false
)
const
[
showUseGPT4Confirm
,
setShowUseGPT4Confirm
]
=
useState
(
false
)
const
{
locale
}
=
useContext
(
I18n
)
const
{
eventEmitter
}
=
useEventEmitterContextContext
()
const
{
eventEmitter
}
=
useEventEmitterContextContext
()
const
{
const
{
...
@@ -820,7 +822,7 @@ const Configuration: FC = () => {
...
@@ -820,7 +822,7 @@ const Configuration: FC = () => {
)
)
}
}
</
div
>
</
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
<
Debug
hasSetAPIKEY=
{
hasSettedApiKey
}
hasSetAPIKEY=
{
hasSettedApiKey
}
onSetting=
{
()
=>
setShowAccountSettingModal
({
payload
:
'provider'
})
}
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> = ({
...
@@ -97,18 +97,21 @@ const CacheCtrlBtn: FC<Props> = ({
</
div
>
</
div
>
</
div
>
</
div
>
)
)
:
(
:
answer
<
TooltipPlus
?
(
popupContent=
{
t
(
'appDebug.feature.annotation.add'
)
as
string
}
<
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
}
>
>
<
MessageFastPlus
className=
'w-4 h-4'
/>
<
div
</
div
>
className=
'p-1 rounded-md hover:bg-[#EEF4FF] hover:text-[#444CE7] cursor-pointer'
</
TooltipPlus
>
onClick=
{
handleAdd
}
)
}
>
<
MessageFastPlus
className=
'w-4 h-4'
/>
</
div
>
</
TooltipPlus
>
)
:
null
}
<
TooltipPlus
<
TooltipPlus
popupContent=
{
t
(
'appDebug.feature.annotation.edit'
)
as
string
}
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 = {
...
@@ -14,7 +14,10 @@ type AgentContentProps = {
const
AgentContent
:
FC
<
AgentContentProps
>
=
({
const
AgentContent
:
FC
<
AgentContentProps
>
=
({
item
,
item
,
})
=>
{
})
=>
{
const
{
allToolIcons
}
=
useChatContext
()
const
{
allToolIcons
,
isResponsing
,
}
=
useChatContext
()
const
{
const
{
annotation
,
annotation
,
agent_thoughts
,
agent_thoughts
,
...
@@ -42,7 +45,7 @@ const AgentContent: FC<AgentContentProps> = ({
...
@@ -42,7 +45,7 @@ const AgentContent: FC<AgentContentProps> = ({
<
Thought
<
Thought
thought=
{
thought
}
thought=
{
thought
}
allToolIcons=
{
allToolIcons
||
{}
}
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
...
@@ -15,9 +15,13 @@ import { EditTitle } from '@/app/components/app/annotation/edit-annotation-modal
type
AnswerProps
=
{
type
AnswerProps
=
{
item
:
ChatItem
item
:
ChatItem
question
:
string
index
:
number
}
}
const
Answer
:
FC
<
AnswerProps
>
=
({
const
Answer
:
FC
<
AnswerProps
>
=
({
item
,
item
,
question
,
index
,
})
=>
{
})
=>
{
const
{
t
}
=
useTranslation
()
const
{
t
}
=
useTranslation
()
const
{
const
{
...
@@ -56,7 +60,15 @@ const Answer: FC<AnswerProps> = ({
...
@@ -56,7 +60,15 @@ const Answer: FC<AnswerProps> = ({
<
div
className=
'relative pr-10'
>
<
div
className=
'relative pr-10'
>
<
AnswerTriangle
className=
'absolute -left-2 top-0 w-2 h-3 text-gray-100'
/>
<
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'
>
<
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
&&
(
responsing
&&
!
content
&&
!
hasAgentThoughts
&&
(
<
div
className=
'flex items-center justify-center w-6 h-5'
>
<
div
className=
'flex items-center justify-center w-6 h-5'
>
...
@@ -75,7 +87,7 @@ const Answer: FC<AnswerProps> = ({
...
@@ -75,7 +87,7 @@ const Answer: FC<AnswerProps> = ({
)
)
}
}
{
{
annotation
?.
id
&&
!
annotation
?.
logAnnotation
&&
(
annotation
?.
id
&&
annotation
.
authorName
&&
(
<
EditTitle
<
EditTitle
className=
'mt-1'
className=
'mt-1'
title=
{
t
(
'appAnnotation.editBy'
,
{
author
:
annotation
.
authorName
})
}
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
type
{
FC
}
from
'react'
import
{
useState
}
from
'react'
import
type
{
ChatItem
}
from
'../../types'
import
type
{
ChatItem
}
from
'../../types'
import
{
useCurrentAnswerIsResponsing
}
from
'../hooks'
import
{
useCurrentAnswerIsResponsing
}
from
'../hooks'
import
{
useChatContext
}
from
'../context'
import
{
useChatContext
}
from
'../context'
import
CopyBtn
from
'@/app/components/app/chat/copy-btn'
import
CopyBtn
from
'@/app/components/app/chat/copy-btn'
import
{
MessageFast
}
from
'@/app/components/base/icons/src/vender/solid/communication'
import
{
MessageFast
}
from
'@/app/components/base/icons/src/vender/solid/communication'
import
AudioBtn
from
'@/app/components/base/audio-btn'
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
=
{
type
OperationProps
=
{
item
:
ChatItem
item
:
ChatItem
question
:
string
index
:
number
}
}
const
Operation
:
FC
<
OperationProps
>
=
({
const
Operation
:
FC
<
OperationProps
>
=
({
item
,
item
,
question
,
index
,
})
=>
{
})
=>
{
const
{
config
}
=
useChatContext
()
const
{
config
,
onAnnotationAdded
,
onAnnotationEdited
,
onAnnotationRemoved
,
}
=
useChatContext
()
const
[
isShowReplyModal
,
setIsShowReplyModal
]
=
useState
(
false
)
const
responsing
=
useCurrentAnswerIsResponsing
(
item
.
id
)
const
responsing
=
useCurrentAnswerIsResponsing
(
item
.
id
)
const
{
const
{
id
,
isOpeningStatement
,
isOpeningStatement
,
content
,
content
,
annotation
,
annotation
,
}
=
item
}
=
item
const
hasAnnotation
=
!!
annotation
?.
id
return
(
return
(
<
div
className=
'absolute top-[-14px] right-[-14px] flex justify-end gap-1'
>
<
div
className=
'absolute top-[-14px] right-[-14px] flex justify-end gap-1'
>
...
@@ -36,6 +51,34 @@ const Operation: FC<OperationProps> = ({
...
@@ -36,6 +51,34 @@ const Operation: FC<OperationProps> = ({
className=
'hidden group-hover:block'
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
&&
(
annotation
?.
id
&&
(
<
div
<
div
...
...
web/app/components/base/chat/chat/context.tsx
View file @
68406b99
...
@@ -2,23 +2,20 @@
...
@@ -2,23 +2,20 @@
import
type
{
ReactNode
}
from
'react'
import
type
{
ReactNode
}
from
'react'
import
{
createContext
,
useContext
}
from
'use-context-selector'
import
{
createContext
,
useContext
}
from
'use-context-selector'
import
type
{
import
type
{
ChatProps
}
from
'./index'
ChatConfig
,
ChatItem
,
OnSend
,
}
from
'../types'
import
type
{
Emoji
}
from
'@/app/components/tools/types'
export
type
ChatContextValue
=
{
export
type
ChatContextValue
=
Pick
<
ChatProps
,
'config'
config
?:
ChatConfig
|
'isResponsing'
isResponsing
?:
boolean
|
'chatList'
chatList
:
ChatItem
[]
|
'showPromptLog'
showPromptLog
?:
boolean
|
'questionIcon'
questionIcon
?:
ReactNode
|
'answerIcon'
answerIcon
?:
ReactNode
|
'allToolIcons'
allToolIcons
?:
Record
<
string
,
string
|
Emoji
>
|
'onSend'
onSend
?:
OnSend
|
'onAnnotationEdited'
}
|
'onAnnotationAdded'
|
'onAnnotationRemoved'
>
const
ChatContext
=
createContext
<
ChatContextValue
>
({
const
ChatContext
=
createContext
<
ChatContextValue
>
({
chatList
:
[],
chatList
:
[],
...
@@ -38,6 +35,9 @@ export const ChatContextProvider = ({
...
@@ -38,6 +35,9 @@ export const ChatContextProvider = ({
answerIcon
,
answerIcon
,
allToolIcons
,
allToolIcons
,
onSend
,
onSend
,
onAnnotationEdited
,
onAnnotationAdded
,
onAnnotationRemoved
,
}:
ChatContextProviderProps
)
=>
{
}:
ChatContextProviderProps
)
=>
{
return
(
return
(
<
ChatContext
.
Provider
value=
{
{
<
ChatContext
.
Provider
value=
{
{
...
@@ -49,6 +49,9 @@ export const ChatContextProvider = ({
...
@@ -49,6 +49,9 @@ export const ChatContextProvider = ({
answerIcon
,
answerIcon
,
allToolIcons
,
allToolIcons
,
onSend
,
onSend
,
onAnnotationEdited
,
onAnnotationAdded
,
onAnnotationRemoved
,
}
}
>
}
}
>
{
children
}
{
children
}
</
ChatContext
.
Provider
>
</
ChatContext
.
Provider
>
...
...
web/app/components/base/chat/chat/hooks.ts
View file @
68406b99
import
{
import
{
useCallback
,
useEffect
,
useEffect
,
useRef
,
useRef
,
useState
,
useState
,
}
from
'react'
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
{
useTranslation
}
from
'react-i18next'
import
{
produce
}
from
'immer'
import
{
produce
}
from
'immer'
import
{
useGetState
}
from
'ahooks'
import
dayjs
from
'dayjs'
import
dayjs
from
'dayjs'
import
type
{
import
type
{
ChatConfig
,
ChatConfig
,
...
@@ -19,12 +19,53 @@ import { TransferMethod } from '@/types/app'
...
@@ -19,12 +19,53 @@ import { TransferMethod } from '@/types/app'
import
{
useToastContext
}
from
'@/app/components/base/toast'
import
{
useToastContext
}
from
'@/app/components/base/toast'
import
{
ssePost
}
from
'@/service/base'
import
{
ssePost
}
from
'@/service/base'
import
{
replaceStringWithValues
}
from
'@/app/components/app/configuration/prompt-value-panel'
import
{
replaceStringWithValues
}
from
'@/app/components/app/configuration/prompt-value-panel'
import
type
{
Annotation
}
from
'@/models/log'
type
GetAbortController
=
(
abortController
:
AbortController
)
=>
void
type
GetAbortController
=
(
abortController
:
AbortController
)
=>
void
type
SendCallback
=
{
type
SendCallback
=
{
onGetConvesationMessages
:
(
conversationId
:
string
,
getAbortController
:
GetAbortController
)
=>
Promise
<
any
>
onGetConvesationMessages
:
(
conversationId
:
string
,
getAbortController
:
GetAbortController
)
=>
Promise
<
any
>
onGetSuggestedQuestions
?:
(
responseItemId
:
string
,
getAbortController
:
GetAbortController
)
=>
Promise
<
any
>
onGetSuggestedQuestions
?:
(
responseItemId
:
string
,
getAbortController
:
GetAbortController
)
=>
Promise
<
any
>
}
}
export
const
useCheckPromptVariables
=
()
=>
{
const
{
t
}
=
useTranslation
()
const
{
notify
}
=
useToastContext
()
const
checkPromptVariables
=
useCallback
((
promptVariablesConfig
:
{
inputs
:
Inputs
promptVariables
:
PromptVariable
[]
})
=>
{
const
{
promptVariables
,
inputs
,
}
=
promptVariablesConfig
let
hasEmptyInput
=
''
const
requiredVars
=
promptVariables
.
filter
(({
key
,
name
,
required
,
type
})
=>
{
if
(
type
===
'api'
)
return
false
const
res
=
(
!
key
||
!
key
.
trim
())
||
(
!
name
||
!
name
.
trim
())
||
(
required
||
required
===
undefined
||
required
===
null
)
return
res
})
if
(
requiredVars
?.
length
)
{
requiredVars
.
forEach
(({
key
,
name
})
=>
{
if
(
hasEmptyInput
)
return
if
(
!
inputs
[
key
])
hasEmptyInput
=
name
})
}
if
(
hasEmptyInput
)
{
notify
({
type
:
'error'
,
message
:
t
(
'appDebug.errorMessage.valueOfVarRequired'
,
{
key
:
hasEmptyInput
})
})
return
false
}
},
[
notify
,
t
])
return
checkPromptVariables
}
export
const
useChat
=
(
export
const
useChat
=
(
config
:
ChatConfig
,
config
:
ChatConfig
,
promptVariablesConfig
?:
{
promptVariablesConfig
?:
{
...
@@ -39,19 +80,31 @@ export const useChat = (
...
@@ -39,19 +80,31 @@ export const useChat = (
const
connversationId
=
useRef
(
''
)
const
connversationId
=
useRef
(
''
)
const
hasStopResponded
=
useRef
(
false
)
const
hasStopResponded
=
useRef
(
false
)
const
[
isResponsing
,
setIsResponsing
]
=
useState
(
false
)
const
[
isResponsing
,
setIsResponsing
]
=
useState
(
false
)
const
[
chatList
,
setChatList
,
getChatList
]
=
useGetState
<
ChatItem
[]
>
(
prevChatList
||
[])
const
isResponsingRef
=
useRef
(
false
)
const
[
taskId
,
setTaskId
]
=
useState
(
''
)
const
[
chatList
,
setChatList
]
=
useState
<
ChatItem
[]
>
(
prevChatList
||
[])
const
chatListRef
=
useRef
<
ChatItem
[]
>
(
prevChatList
||
[])
const
taskIdRef
=
useRef
(
''
)
const
[
suggestedQuestions
,
setSuggestQuestions
]
=
useState
<
string
[]
>
([])
const
[
suggestedQuestions
,
setSuggestQuestions
]
=
useState
<
string
[]
>
([])
const
[
abortController
,
setAbortController
]
=
useState
<
AbortController
|
null
>
(
null
)
const
abortControllerRef
=
useRef
<
AbortController
|
null
>
(
null
)
const
[
conversationMessagesAbortController
,
setConversationMessagesAbortController
]
=
useState
<
AbortController
|
null
>
(
null
)
const
conversationMessagesAbortControllerRef
=
useRef
<
AbortController
|
null
>
(
null
)
const
[
suggestedQuestionsAbortController
,
setSuggestedQuestionsAbortController
]
=
useState
<
AbortController
|
null
>
(
null
)
const
suggestedQuestionsAbortControllerRef
=
useRef
<
AbortController
|
null
>
(
null
)
const
checkPromptVariables
=
useCheckPromptVariables
()
const
getIntroduction
=
(
str
:
string
)
=>
{
const
handleUpdateChatList
=
useCallback
((
newChatList
:
ChatItem
[])
=>
{
setChatList
(
newChatList
)
chatListRef
.
current
=
newChatList
},
[])
const
handleResponsing
=
useCallback
((
isResponsing
:
boolean
)
=>
{
setIsResponsing
(
isResponsing
)
isResponsingRef
.
current
=
isResponsing
},
[])
const
getIntroduction
=
useCallback
((
str
:
string
)
=>
{
return
replaceStringWithValues
(
str
,
promptVariablesConfig
?.
promptVariables
||
[],
promptVariablesConfig
?.
inputs
||
{})
return
replaceStringWithValues
(
str
,
promptVariablesConfig
?.
promptVariables
||
[],
promptVariablesConfig
?.
inputs
||
{})
}
}
,
[
promptVariablesConfig
?.
inputs
,
promptVariablesConfig
?.
promptVariables
])
useEffect
(()
=>
{
useEffect
(()
=>
{
if
(
config
.
opening_statement
&&
!
chatList
.
some
(
item
=>
!
item
.
isAnswer
)
)
{
if
(
config
.
opening_statement
&&
!
chatList
.
length
)
{
set
ChatList
([{
handleUpdate
ChatList
([{
id
:
`
${
Date
.
now
()}
`
,
id
:
`
${
Date
.
now
()}
`
,
content
:
getIntroduction
(
config
.
opening_statement
),
content
:
getIntroduction
(
config
.
opening_statement
),
isAnswer
:
true
,
isAnswer
:
true
,
...
@@ -59,25 +112,31 @@ export const useChat = (
...
@@ -59,25 +112,31 @@ export const useChat = (
suggestedQuestions
:
config
.
suggested_questions
,
suggestedQuestions
:
config
.
suggested_questions
,
}])
}])
}
}
},
[
config
.
opening_statement
,
config
.
suggested_questions
,
promptVariablesConfig
?.
inputs
])
},
[
config
.
opening_statement
,
const
handleStop
=
()
=>
{
config
.
suggested_questions
,
if
(
stopChat
&&
taskId
)
getIntroduction
,
stopChat
(
taskId
)
chatList
,
if
(
abortController
)
handleUpdateChatList
,
abortController
.
abort
()
])
if
(
conversationMessagesAbortController
)
conversationMessagesAbortController
.
abort
()
if
(
suggestedQuestionsAbortController
)
suggestedQuestionsAbortController
.
abort
()
}
const
handleRestart
=
()
=>
{
const
handleStop
=
useCallback
(()
=>
{
handleStop
()
hasStopResponded
.
current
=
true
hasStopResponded
.
current
=
true
handleResponsing
(
false
)
if
(
stopChat
&&
taskIdRef
.
current
)
stopChat
(
taskIdRef
.
current
)
if
(
abortControllerRef
.
current
)
abortControllerRef
.
current
.
abort
()
if
(
conversationMessagesAbortControllerRef
.
current
)
conversationMessagesAbortControllerRef
.
current
.
abort
()
if
(
suggestedQuestionsAbortControllerRef
.
current
)
suggestedQuestionsAbortControllerRef
.
current
.
abort
()
},
[
stopChat
,
handleResponsing
])
const
handleRestart
=
useCallback
(()
=>
{
handleStop
()
connversationId
.
current
=
''
connversationId
.
current
=
''
setIsResponsing
(
false
)
const
newChatList
=
config
.
opening_statement
setChatList
(
config
.
opening_statement
?
[{
?
[{
id
:
`
${
Date
.
now
()}
`
,
id
:
`
${
Date
.
now
()}
`
,
content
:
config
.
opening_statement
,
content
:
config
.
opening_statement
,
...
@@ -85,10 +144,38 @@ export const useChat = (
...
@@ -85,10 +144,38 @@ export const useChat = (
isOpeningStatement
:
true
,
isOpeningStatement
:
true
,
suggestedQuestions
:
config
.
suggested_questions
,
suggestedQuestions
:
config
.
suggested_questions
,
}]
}]
:
[])
:
[]
handleUpdateChatList
(
newChatList
)
setSuggestQuestions
([])
setSuggestQuestions
([])
}
},
[
const
handleSend
=
async
(
config
,
handleStop
,
handleUpdateChatList
,
])
const
updateCurrentQA
=
useCallback
(({
responseItem
,
questionId
,
placeholderAnswerId
,
questionItem
,
}:
{
responseItem
:
ChatItem
questionId
:
string
placeholderAnswerId
:
string
questionItem
:
ChatItem
})
=>
{
const
newListWithAnswer
=
produce
(
chatListRef
.
current
.
filter
(
item
=>
item
.
id
!==
responseItem
.
id
&&
item
.
id
!==
placeholderAnswerId
),
(
draft
)
=>
{
if
(
!
draft
.
find
(
item
=>
item
.
id
===
questionId
))
draft
.
push
({
...
questionItem
})
draft
.
push
({
...
responseItem
})
})
handleUpdateChatList
(
newListWithAnswer
)
},
[
handleUpdateChatList
])
const
handleSend
=
useCallback
(
async
(
url
:
string
,
url
:
string
,
data
:
any
,
data
:
any
,
{
{
...
@@ -97,62 +184,13 @@ export const useChat = (
...
@@ -97,62 +184,13 @@ export const useChat = (
}:
SendCallback
,
}:
SendCallback
,
)
=>
{
)
=>
{
setSuggestQuestions
([])
setSuggestQuestions
([])
if
(
isResponsing
)
{
if
(
isResponsing
Ref
.
current
)
{
notify
({
type
:
'info'
,
message
:
t
(
'appDebug.errorMessage.waitForResponse'
)
})
notify
({
type
:
'info'
,
message
:
t
(
'appDebug.errorMessage.waitForResponse'
)
})
return
false
return
false
}
}
if
(
promptVariablesConfig
?.
inputs
&&
promptVariablesConfig
?.
promptVariables
)
{
if
(
promptVariablesConfig
?.
inputs
&&
promptVariablesConfig
?.
promptVariables
)
const
{
checkPromptVariables
(
promptVariablesConfig
)
promptVariables
,
inputs
,
}
=
promptVariablesConfig
let
hasEmptyInput
=
''
const
requiredVars
=
promptVariables
.
filter
(({
key
,
name
,
required
,
type
})
=>
{
if
(
type
===
'api'
)
return
false
const
res
=
(
!
key
||
!
key
.
trim
())
||
(
!
name
||
!
name
.
trim
())
||
(
required
||
required
===
undefined
||
required
===
null
)
return
res
})
if
(
requiredVars
?.
length
)
{
requiredVars
.
forEach
(({
key
,
name
})
=>
{
if
(
hasEmptyInput
)
return
if
(
!
inputs
[
key
])
hasEmptyInput
=
name
})
}
if
(
hasEmptyInput
)
{
notify
({
type
:
'error'
,
message
:
t
(
'appDebug.errorMessage.valueOfVarRequired'
,
{
key
:
hasEmptyInput
})
})
return
false
}
}
const
updateCurrentQA
=
({
responseItem
,
questionId
,
placeholderAnswerId
,
questionItem
,
}:
{
responseItem
:
ChatItem
questionId
:
string
placeholderAnswerId
:
string
questionItem
:
ChatItem
})
=>
{
// closesure new list is outdated.
const
newListWithAnswer
=
produce
(
getChatList
().
filter
(
item
=>
item
.
id
!==
responseItem
.
id
&&
item
.
id
!==
placeholderAnswerId
),
(
draft
)
=>
{
if
(
!
draft
.
find
(
item
=>
item
.
id
===
questionId
))
draft
.
push
({
...
questionItem
})
draft
.
push
({
...
responseItem
})
})
setChatList
(
newListWithAnswer
)
}
const
questionId
=
`question-
${
Date
.
now
()}
`
const
questionId
=
`question-
${
Date
.
now
()}
`
const
questionItem
=
{
const
questionItem
=
{
...
@@ -169,8 +207,8 @@ export const useChat = (
...
@@ -169,8 +207,8 @@ export const useChat = (
isAnswer
:
true
,
isAnswer
:
true
,
}
}
const
newList
=
[...
getChatList
()
,
questionItem
,
placeholderAnswerItem
]
const
newList
=
[...
chatListRef
.
current
,
questionItem
,
placeholderAnswerItem
]
set
ChatList
(
newList
)
handleUpdate
ChatList
(
newList
)
// answer
// answer
const
responseItem
:
ChatItem
=
{
const
responseItem
:
ChatItem
=
{
...
@@ -181,7 +219,7 @@ export const useChat = (
...
@@ -181,7 +219,7 @@ export const useChat = (
isAnswer
:
true
,
isAnswer
:
true
,
}
}
setIs
Responsing
(
true
)
handle
Responsing
(
true
)
hasStopResponded
.
current
=
false
hasStopResponded
.
current
=
false
const
bodyParams
=
{
const
bodyParams
=
{
...
@@ -211,7 +249,7 @@ export const useChat = (
...
@@ -211,7 +249,7 @@ export const useChat = (
},
},
{
{
getAbortController
:
(
abortController
)
=>
{
getAbortController
:
(
abortController
)
=>
{
setAbortController
(
abortController
)
abortControllerRef
.
current
=
abortController
},
},
onData
:
(
message
:
string
,
isFirstMessage
:
boolean
,
{
conversationId
:
newConversationId
,
messageId
,
taskId
}:
any
)
=>
{
onData
:
(
message
:
string
,
isFirstMessage
:
boolean
,
{
conversationId
:
newConversationId
,
messageId
,
taskId
}:
any
)
=>
{
if
(
!
isAgentMode
)
{
if
(
!
isAgentMode
)
{
...
@@ -231,7 +269,7 @@ export const useChat = (
...
@@ -231,7 +269,7 @@ export const useChat = (
if
(
isFirstMessage
&&
newConversationId
)
if
(
isFirstMessage
&&
newConversationId
)
connversationId
.
current
=
newConversationId
connversationId
.
current
=
newConversationId
setTaskId
(
taskId
)
taskIdRef
.
current
=
taskId
if
(
messageId
)
if
(
messageId
)
responseItem
.
id
=
messageId
responseItem
.
id
=
messageId
...
@@ -243,21 +281,21 @@ export const useChat = (
...
@@ -243,21 +281,21 @@ export const useChat = (
})
})
},
},
async
onCompleted
(
hasError
?:
boolean
)
{
async
onCompleted
(
hasError
?:
boolean
)
{
setIs
Responsing
(
false
)
handle
Responsing
(
false
)
if
(
hasError
)
if
(
hasError
)
return
return
if
(
connversationId
.
current
)
{
if
(
connversationId
.
current
&&
!
hasStopResponded
.
current
)
{
const
{
data
}:
any
=
await
onGetConvesationMessages
(
const
{
data
}:
any
=
await
onGetConvesationMessages
(
connversationId
.
current
,
connversationId
.
current
,
newAbortController
=>
setConversationMessagesAbortController
(
newAbortController
)
,
newAbortController
=>
conversationMessagesAbortControllerRef
.
current
=
newAbortController
,
)
)
const
newResponseItem
=
data
.
find
((
item
:
any
)
=>
item
.
id
===
responseItem
.
id
)
const
newResponseItem
=
data
.
find
((
item
:
any
)
=>
item
.
id
===
responseItem
.
id
)
if
(
!
newResponseItem
)
if
(
!
newResponseItem
)
return
return
setChatList
(
produce
(
getChatList
()
,
(
draft
)
=>
{
const
newChatList
=
produce
(
chatListRef
.
current
,
(
draft
)
=>
{
const
index
=
draft
.
findIndex
(
item
=>
item
.
id
===
responseItem
.
id
)
const
index
=
draft
.
findIndex
(
item
=>
item
.
id
===
responseItem
.
id
)
if
(
index
!==
-
1
)
{
if
(
index
!==
-
1
)
{
const
requestion
=
draft
[
index
-
1
]
const
requestion
=
draft
[
index
-
1
]
...
@@ -274,12 +312,13 @@ export const useChat = (
...
@@ -274,12 +312,13 @@ export const useChat = (
},
},
}
}
}
}
}))
})
handleUpdateChatList
(
newChatList
)
}
}
if
(
config
.
suggested_questions_after_answer
?.
enabled
&&
!
hasStopResponded
.
current
&&
onGetSuggestedQuestions
)
{
if
(
config
.
suggested_questions_after_answer
?.
enabled
&&
!
hasStopResponded
.
current
&&
onGetSuggestedQuestions
)
{
const
{
data
}:
any
=
await
onGetSuggestedQuestions
(
const
{
data
}:
any
=
await
onGetSuggestedQuestions
(
responseItem
.
id
,
responseItem
.
id
,
newAbortController
=>
s
etSuggestedQuestionsAbortController
(
newAbortController
)
,
newAbortController
=>
s
uggestedQuestionsAbortControllerRef
.
current
=
newAbortController
,
)
)
setSuggestQuestions
(
data
)
setSuggestQuestions
(
data
)
}
}
...
@@ -330,8 +369,9 @@ export const useChat = (
...
@@ -330,8 +369,9 @@ export const useChat = (
id
:
messageEnd
.
metadata
.
annotation_reply
.
id
,
id
:
messageEnd
.
metadata
.
annotation_reply
.
id
,
authorName
:
messageEnd
.
metadata
.
annotation_reply
.
account
.
name
,
authorName
:
messageEnd
.
metadata
.
annotation_reply
.
account
.
name
,
})
})
const
baseState
=
chatListRef
.
current
.
filter
(
item
=>
item
.
id
!==
responseItem
.
id
&&
item
.
id
!==
placeholderAnswerId
)
const
newListWithAnswer
=
produce
(
const
newListWithAnswer
=
produce
(
getChatList
().
filter
(
item
=>
item
.
id
!==
responseItem
.
id
&&
item
.
id
!==
placeholderAnswerId
)
,
baseState
,
(
draft
)
=>
{
(
draft
)
=>
{
if
(
!
draft
.
find
(
item
=>
item
.
id
===
questionId
))
if
(
!
draft
.
find
(
item
=>
item
.
id
===
questionId
))
draft
.
push
({
...
questionItem
})
draft
.
push
({
...
questionItem
})
...
@@ -340,38 +380,113 @@ export const useChat = (
...
@@ -340,38 +380,113 @@ export const useChat = (
...
responseItem
,
...
responseItem
,
})
})
})
})
set
ChatList
(
newListWithAnswer
)
handleUpdate
ChatList
(
newListWithAnswer
)
return
return
}
}
responseItem
.
citation
=
messageEnd
.
metadata
?.
retriever_resources
||
[]
responseItem
.
citation
=
messageEnd
.
metadata
?.
retriever_resources
||
[]
const
newListWithAnswer
=
produce
(
const
newListWithAnswer
=
produce
(
getChatList
()
.
filter
(
item
=>
item
.
id
!==
responseItem
.
id
&&
item
.
id
!==
placeholderAnswerId
),
chatListRef
.
current
.
filter
(
item
=>
item
.
id
!==
responseItem
.
id
&&
item
.
id
!==
placeholderAnswerId
),
(
draft
)
=>
{
(
draft
)
=>
{
if
(
!
draft
.
find
(
item
=>
item
.
id
===
questionId
))
if
(
!
draft
.
find
(
item
=>
item
.
id
===
questionId
))
draft
.
push
({
...
questionItem
})
draft
.
push
({
...
questionItem
})
draft
.
push
({
...
responseItem
})
draft
.
push
({
...
responseItem
})
})
})
set
ChatList
(
newListWithAnswer
)
handleUpdate
ChatList
(
newListWithAnswer
)
},
},
onMessageReplace
:
(
messageReplace
)
=>
{
onMessageReplace
:
(
messageReplace
)
=>
{
responseItem
.
content
=
messageReplace
.
answer
responseItem
.
content
=
messageReplace
.
answer
},
},
onError
()
{
onError
()
{
setIsResponsing
(
false
)
handleResponsing
(
false
)
// role back placeholder answer
const
newChatList
=
produce
(
chatListRef
.
current
,
(
draft
)
=>
{
setChatList
(
produce
(
getChatList
(),
(
draft
)
=>
{
draft
.
splice
(
draft
.
findIndex
(
item
=>
item
.
id
===
placeholderAnswerId
),
1
)
draft
.
splice
(
draft
.
findIndex
(
item
=>
item
.
id
===
placeholderAnswerId
),
1
)
}))
})
handleUpdateChatList
(
newChatList
)
},
},
})
})
return
true
return
true
}
},
[
checkPromptVariables
,
config
.
suggested_questions_after_answer
,
updateCurrentQA
,
t
,
notify
,
promptVariablesConfig
,
handleUpdateChatList
,
handleResponsing
,
])
const
handleAnnotationEdited
=
useCallback
((
query
:
string
,
answer
:
string
,
index
:
number
)
=>
{
setChatList
(
chatListRef
.
current
.
map
((
item
,
i
)
=>
{
if
(
i
===
index
-
1
)
{
return
{
...
item
,
content
:
query
,
}
}
if
(
i
===
index
)
{
return
{
...
item
,
content
:
answer
,
annotation
:
{
...
item
.
annotation
,
logAnnotation
:
undefined
,
}
as
any
,
}
}
return
item
}))
},
[])
const
handleAnnotationAdded
=
useCallback
((
annotationId
:
string
,
authorName
:
string
,
query
:
string
,
answer
:
string
,
index
:
number
)
=>
{
setChatList
(
chatListRef
.
current
.
map
((
item
,
i
)
=>
{
if
(
i
===
index
-
1
)
{
return
{
...
item
,
content
:
query
,
}
}
if
(
i
===
index
)
{
const
answerItem
=
{
...
item
,
content
:
item
.
content
,
annotation
:
{
id
:
annotationId
,
authorName
,
logAnnotation
:
{
content
:
answer
,
account
:
{
id
:
''
,
name
:
authorName
,
email
:
''
,
},
},
}
as
Annotation
,
}
return
answerItem
}
return
item
}))
},
[])
const
handleAnnotationRemoved
=
useCallback
((
index
:
number
)
=>
{
setChatList
(
chatListRef
.
current
.
map
((
item
,
i
)
=>
{
if
(
i
===
index
)
{
return
{
...
item
,
content
:
item
.
content
,
annotation
:
{
...(
item
.
annotation
||
{}),
id
:
''
,
}
as
Annotation
,
}
}
return
item
}))
},
[])
return
{
return
{
chatList
,
chatList
,
getChatList
,
setChatList
,
setChatList
,
conversationId
:
connversationId
.
current
,
conversationId
:
connversationId
.
current
,
isResponsing
,
isResponsing
,
...
@@ -380,6 +495,9 @@ export const useChat = (
...
@@ -380,6 +495,9 @@ export const useChat = (
suggestedQuestions
,
suggestedQuestions
,
handleRestart
,
handleRestart
,
handleStop
,
handleStop
,
handleAnnotationEdited
,
handleAnnotationAdded
,
handleAnnotationRemoved
,
}
}
}
}
...
...
web/app/components/base/chat/chat/index.tsx
View file @
68406b99
...
@@ -4,8 +4,10 @@ import type {
...
@@ -4,8 +4,10 @@ import type {
}
from
'react'
}
from
'react'
import
{
import
{
memo
,
memo
,
useEffect
,
useRef
,
useRef
,
}
from
'react'
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
{
useThrottleEffect
}
from
'ahooks'
import
{
useThrottleEffect
}
from
'ahooks'
import
type
{
import
type
{
ChatConfig
,
ChatConfig
,
...
@@ -18,13 +20,17 @@ import ChatInput from './chat-input'
...
@@ -18,13 +20,17 @@ import ChatInput from './chat-input'
import
TryToAsk
from
'./try-to-ask'
import
TryToAsk
from
'./try-to-ask'
import
{
ChatContextProvider
}
from
'./context'
import
{
ChatContextProvider
}
from
'./context'
import
type
{
Emoji
}
from
'@/app/components/tools/types'
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
=
{
export
type
ChatProps
=
{
config
:
ChatConfig
onSend
?:
OnSend
chatList
:
ChatItem
[]
chatList
:
ChatItem
[]
isResponsing
:
boolean
config
?:
ChatConfig
isResponsing
?:
boolean
noStopResponding
?:
boolean
onStopResponding
?:
()
=>
void
noChatInput
?:
boolean
noChatInput
?:
boolean
onSend
?:
OnSend
chatContainerclassName
?:
string
chatContainerclassName
?:
string
chatFooterClassName
?:
string
chatFooterClassName
?:
string
suggestedQuestions
?:
string
[]
suggestedQuestions
?:
string
[]
...
@@ -32,12 +38,17 @@ export type ChatProps = {
...
@@ -32,12 +38,17 @@ export type ChatProps = {
questionIcon
?:
ReactNode
questionIcon
?:
ReactNode
answerIcon
?:
ReactNode
answerIcon
?:
ReactNode
allToolIcons
?:
Record
<
string
,
string
|
Emoji
>
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
>
=
({
const
Chat
:
FC
<
ChatProps
>
=
({
config
,
config
,
onSend
,
onSend
,
chatList
,
chatList
,
isResponsing
,
isResponsing
,
noStopResponding
,
onStopResponding
,
noChatInput
,
noChatInput
,
chatContainerclassName
,
chatContainerclassName
,
chatFooterClassName
,
chatFooterClassName
,
...
@@ -46,16 +57,46 @@ const Chat: FC<ChatProps> = ({
...
@@ -46,16 +57,46 @@ const Chat: FC<ChatProps> = ({
questionIcon
,
questionIcon
,
answerIcon
,
answerIcon
,
allToolIcons
,
allToolIcons
,
onAnnotationAdded
,
onAnnotationEdited
,
onAnnotationRemoved
,
})
=>
{
})
=>
{
const
ref
=
useRef
<
HTMLDivElement
>
(
null
)
const
{
t
}
=
useTranslation
()
const
chatContainerRef
=
useRef
<
HTMLDivElement
>
(
null
)
const
chatFooterRef
=
useRef
<
HTMLDivElement
>
(
null
)
const
chatFooterRef
=
useRef
<
HTMLDivElement
>
(
null
)
const
handleScrolltoBottom
=
()
=>
{
if
(
chatContainerRef
.
current
)
chatContainerRef
.
current
.
scrollTop
=
chatContainerRef
.
current
.
scrollHeight
}
useThrottleEffect
(()
=>
{
useThrottleEffect
(()
=>
{
if
(
ref
.
current
)
handleScrolltoBottom
()
ref
.
current
.
scrollTop
=
ref
.
current
.
scrollHeight
if
(
chatContainerRef
.
current
&&
chatFooterRef
.
current
)
chatFooterRef
.
current
.
style
.
width
=
`
${
chatContainerRef
.
current
.
clientWidth
}
px`
},
[
chatList
],
{
wait
:
500
})
},
[
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
(
return
(
<
ChatContextProvider
<
ChatContextProvider
...
@@ -67,19 +108,24 @@ const Chat: FC<ChatProps> = ({
...
@@ -67,19 +108,24 @@ const Chat: FC<ChatProps> = ({
answerIcon=
{
answerIcon
}
answerIcon=
{
answerIcon
}
allToolIcons=
{
allToolIcons
}
allToolIcons=
{
allToolIcons
}
onSend=
{
onSend
}
onSend=
{
onSend
}
onAnnotationAdded=
{
onAnnotationAdded
}
onAnnotationEdited=
{
onAnnotationEdited
}
onAnnotationRemoved=
{
onAnnotationRemoved
}
>
>
<
div
className=
'relative h-full'
>
<
div
className=
'relative h-full'
>
<
div
<
div
ref=
{
r
ef
}
ref=
{
chatContainerR
ef
}
className=
{
`relative h-full overflow-y-auto ${chatContainerclassName}`
}
className=
{
`relative h-full overflow-y-auto ${chatContainerclassName}`
}
>
>
{
{
chatList
.
map
((
item
)
=>
{
chatList
.
map
((
item
,
index
)
=>
{
if
(
item
.
isAnswer
)
{
if
(
item
.
isAnswer
)
{
return
(
return
(
<
Answer
<
Answer
key=
{
item
.
id
}
key=
{
item
.
id
}
item=
{
item
}
item=
{
item
}
question=
{
chatList
[
index
-
1
]?.
content
}
index=
{
index
}
/>
/>
)
)
}
}
...
@@ -91,35 +137,41 @@ const Chat: FC<ChatProps> = ({
...
@@ -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
)
&&
(
!
noStopResponding
&&
isResponsing
&&
(
<
div
<
div
className=
'flex justify-center mb-2'
>
className=
{
`sticky bottom-0 w-full backdrop-blur-[20px] ${chatFooterClassName}`
}
<
Button
className=
'py-0 px-3 h-7 bg-white shadow-xs'
onClick=
{
onStopResponding
}
>
ref=
{
chatFooterRef
}
<
StopCircle
className=
'mr-[5px] w-3.5 h-3.5 text-gray-500'
/>
style=
{
{
<
span
className=
'text-xs text-gray-500 font-normal'
>
{
t
(
'appDebug.operation.stopResponding'
)
}
</
span
>
background
:
'linear-gradient(0deg, #FFF 0%, rgba(255, 255, 255, 0.40) 100%)'
,
</
Button
>
}
}
>
{
hasTryToAsk
&&
(
<
TryToAsk
suggestedQuestions=
{
suggestedQuestions
}
onSend=
{
onSend
}
/>
)
}
{
!
noChatInput
&&
(
<
ChatInput
visionConfig=
{
config
?.
file_upload
?.
image
}
speechToTextConfig=
{
config
.
speech_to_text
}
onSend=
{
onSend
}
/>
)
}
</
div
>
</
div
>
)
)
}
}
{
hasTryToAsk
&&
(
<
TryToAsk
suggestedQuestions=
{
suggestedQuestions
}
onSend=
{
onSend
}
/>
)
}
{
!
noChatInput
&&
(
<
ChatInput
visionConfig=
{
config
?.
file_upload
?.
image
}
speechToTextConfig=
{
config
?.
speech_to_text
}
onSend=
{
onSend
}
/>
)
}
</
div
>
</
div
>
</
div
>
</
div
>
</
ChatContextProvider
>
</
ChatContextProvider
>
...
...
web/app/components/base/chat/types.ts
View file @
68406b99
...
@@ -41,7 +41,10 @@ export type EnableType = {
...
@@ -41,7 +41,10 @@ export type EnableType = {
enabled
:
boolean
enabled
:
boolean
}
}
export
type
ChatConfig
=
Omit
<
ModelConfig
,
'model'
>
export
type
ChatConfig
=
Omit
<
ModelConfig
,
'model'
>
&
{
supportAnnotation
?:
boolean
appId
?:
string
}
export
type
ChatItem
=
IChatItem
export
type
ChatItem
=
IChatItem
...
...
web/context/debug-configuration.ts
View file @
68406b99
...
@@ -96,7 +96,7 @@ type IDebugConfiguration = {
...
@@ -96,7 +96,7 @@ type IDebugConfiguration = {
hasSetContextVar
:
boolean
hasSetContextVar
:
boolean
isShowVisionConfig
:
boolean
isShowVisionConfig
:
boolean
visionConfig
:
VisionSettings
visionConfig
:
VisionSettings
setVisionConfig
:
(
visionConfig
:
VisionSettings
)
=>
void
setVisionConfig
:
(
visionConfig
:
VisionSettings
,
noNotice
?:
boolean
)
=>
void
}
}
const
DebugConfigurationContext
=
createContext
<
IDebugConfiguration
>
({
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