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
f2b2effc
Unverified
Commit
f2b2effc
authored
Jan 25, 2024
by
zxhlyh
Committed by
GitHub
Jan 25, 2024
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: typing delay (#2200)
parent
301e0496
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
201 additions
and
161 deletions
+201
-161
index.tsx
web/app/components/app/chat/answer/index.tsx
+9
-7
index.tsx
web/app/components/app/chat/index.tsx
+76
-73
index.tsx
web/app/components/app/chat/question/index.tsx
+2
-2
use-conversation.ts
web/app/components/share/chat/hooks/use-conversation.ts
+3
-3
index.tsx
web/app/components/share/chat/index.tsx
+101
-73
index.tsx
web/app/components/share/chat/sidebar/index.tsx
+10
-3
No files found.
web/app/components/app/chat/answer/index.tsx
View file @
f2b2effc
...
...
@@ -43,6 +43,7 @@ const IconWrapper: FC<{ children: React.ReactNode | string }> = ({ children }) =
}
export
type
IAnswerProps
=
{
item
:
IChatItem
index
:
number
feedbackDisabled
:
boolean
isHideFeedbackEdit
:
boolean
onQueryChange
:
(
query
:
string
)
=>
void
...
...
@@ -59,14 +60,15 @@ export type IAnswerProps = {
supportAnnotation
?:
boolean
appId
?:
string
question
:
string
onAnnotationEdited
?:
(
question
:
string
,
answer
:
string
)
=>
void
onAnnotationAdded
?:
(
annotationId
:
string
,
authorName
:
string
,
question
:
string
,
answer
:
string
)
=>
void
onAnnotationRemoved
?:
()
=>
void
onAnnotationEdited
?:
(
question
:
string
,
answer
:
string
,
index
:
number
)
=>
void
onAnnotationAdded
?:
(
annotationId
:
string
,
authorName
:
string
,
question
:
string
,
answer
:
string
,
index
:
number
)
=>
void
onAnnotationRemoved
?:
(
index
:
number
)
=>
void
allToolIcons
?:
Record
<
string
,
string
|
Emoji
>
}
// The component needs to maintain its own state to control whether to display input component
const
Answer
:
FC
<
IAnswerProps
>
=
({
item
,
index
,
onQueryChange
,
feedbackDisabled
=
false
,
isHideFeedbackEdit
=
false
,
...
...
@@ -340,9 +342,9 @@ const Answer: FC<IAnswerProps> = ({
cached=
{
hasAnnotation
}
query=
{
question
}
answer=
{
content
}
onAdded=
{
(
id
,
authorName
)
=>
onAnnotationAdded
?.(
id
,
authorName
,
question
,
content
)
}
onAdded=
{
(
id
,
authorName
)
=>
onAnnotationAdded
?.(
id
,
authorName
,
question
,
content
,
index
)
}
onEdit=
{
()
=>
setIsShowReplyModal
(
true
)
}
onRemoved=
{
onAnnotationRemoved
!
}
onRemoved=
{
()
=>
onAnnotationRemoved
!
(
index
)
}
/>
)
}
...
...
@@ -351,8 +353,8 @@ const Answer: FC<IAnswerProps> = ({
onHide=
{
()
=>
setIsShowReplyModal
(
false
)
}
query=
{
question
}
answer=
{
content
}
onEdited=
{
onAnnotationEdited
!
}
onAdded=
{
onAnnotationAdded
!
}
onEdited=
{
(
editedQuery
,
editedAnswer
)
=>
onAnnotationEdited
!
(
editedQuery
,
editedAnswer
,
index
)
}
onAdded=
{
(
annotationId
,
authorName
,
editedQuery
,
editedAnswer
)
=>
onAnnotationAdded
!
(
annotationId
,
authorName
,
editedQuery
,
editedAnswer
,
index
)
}
appId=
{
appId
!
}
messageId=
{
id
}
annotationId=
{
annotation
?.
id
||
''
}
...
...
web/app/components/app/chat/index.tsx
View file @
f2b2effc
'use client'
import
type
{
FC
,
ReactNode
}
from
'react'
import
React
,
{
useEffect
,
useLayoutEffect
,
useRef
,
useState
}
from
'react'
import
React
,
{
use
Callback
,
use
Effect
,
useLayoutEffect
,
useRef
,
useState
}
from
'react'
import
Textarea
from
'rc-textarea'
import
{
useContext
}
from
'use-context-selector'
import
cn
from
'classnames'
...
...
@@ -197,6 +197,76 @@ const Chat: FC<IChatProps> = ({
logError
(
t
(
'common.voiceInput.notAllow'
))
})
}
const
handleQueryChangeFromAnswer
=
useCallback
((
val
:
string
)
=>
{
onQueryChange
(
val
)
handleSend
(
val
)
},
[])
const
handleAnnotationEdited
=
useCallback
((
query
:
string
,
answer
:
string
,
index
:
number
)
=>
{
onChatListChange
?.(
chatList
.
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
)
=>
{
onChatListChange
?.(
chatList
.
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
)
=>
{
onChatListChange
?.(
chatList
.
map
((
item
,
i
)
=>
{
if
(
i
===
index
)
{
return
{
...
item
,
content
:
item
.
content
,
annotation
:
{
...(
item
.
annotation
||
{}),
id
:
''
,
}
as
Annotation
,
}
}
return
item
}))
},
[])
return
(
<
div
className=
{
cn
(
'px-3.5'
,
'h-full'
)
}
>
...
...
@@ -210,10 +280,8 @@ const Chat: FC<IChatProps> = ({
return
<
Answer
key=
{
item
.
id
}
item=
{
item
}
onQueryChange=
{
(
val
)
=>
{
onQueryChange
(
val
)
handleSend
(
val
)
}
}
index=
{
index
}
onQueryChange=
{
handleQueryChangeFromAnswer
}
feedbackDisabled=
{
feedbackDisabled
}
isHideFeedbackEdit=
{
isHideFeedbackEdit
}
onFeedback=
{
onFeedback
}
...
...
@@ -228,72 +296,9 @@ const Chat: FC<IChatProps> = ({
supportAnnotation=
{
supportAnnotation
}
appId=
{
appId
}
question=
{
chatList
[
index
-
1
]?.
content
}
onAnnotationEdited=
{
(
query
,
answer
)
=>
{
onChatListChange
?.(
chatList
.
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
}))
}
}
onAnnotationAdded=
{
(
annotationId
,
authorName
,
query
,
answer
)
=>
{
onChatListChange
?.(
chatList
.
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
}))
}
}
onAnnotationRemoved=
{
()
=>
{
onChatListChange
?.(
chatList
.
map
((
item
,
i
)
=>
{
if
(
i
===
index
)
{
return
{
...
item
,
content
:
item
.
content
,
annotation
:
{
...(
item
.
annotation
||
{}),
id
:
''
,
}
as
Annotation
,
}
}
return
item
}))
}
}
onAnnotationEdited=
{
handleAnnotationEdited
}
onAnnotationAdded=
{
handleAnnotationAdded
}
onAnnotationRemoved=
{
handleAnnotationRemoved
}
allToolIcons=
{
allToolIcons
}
/>
}
...
...
@@ -307,8 +312,6 @@ const Chat: FC<IChatProps> = ({
item=
{
item
}
isShowPromptLog=
{
isShowPromptLog
}
isResponsing=
{
isResponsing
}
// ['https://placekitten.com/360/360', 'https://placekitten.com/360/640']
imgSrcs=
{
(
item
.
message_files
&&
item
.
message_files
?.
length
>
0
)
?
item
.
message_files
.
map
(
item
=>
item
.
url
)
:
[]
}
/>
)
})
}
...
...
web/app/components/app/chat/question/index.tsx
View file @
f2b2effc
...
...
@@ -13,14 +13,14 @@ import ImageGallery from '@/app/components/base/image-gallery'
type
IQuestionProps
=
Pick
<
IChatItem
,
'id'
|
'content'
|
'more'
|
'useCurrentUserAvatar'
>
&
{
isShowPromptLog
?:
boolean
item
:
IChatItem
imgSrcs
?:
string
[]
isResponsing
?:
boolean
}
const
Question
:
FC
<
IQuestionProps
>
=
({
id
,
content
,
imgSrcs
,
more
,
useCurrentUserAvatar
,
isShowPromptLog
,
item
,
isResponsing
})
=>
{
const
Question
:
FC
<
IQuestionProps
>
=
({
id
,
content
,
more
,
useCurrentUserAvatar
,
isShowPromptLog
,
item
,
isResponsing
})
=>
{
const
{
userProfile
}
=
useContext
(
AppContext
)
const
userName
=
userProfile
?.
name
const
ref
=
useRef
(
null
)
const
imgSrcs
=
item
.
message_files
?.
map
(
item
=>
item
.
url
)
return
(
<
div
className=
{
`flex items-start justify-end ${isShowPromptLog && 'first-of-type:pt-[14px]'}`
}
key=
{
id
}
ref=
{
ref
}
>
...
...
web/app/components/share/chat/hooks/use-conversation.ts
View file @
f2b2effc
import
{
useState
}
from
'react'
import
{
use
Callback
,
use
State
}
from
'react'
import
produce
from
'immer'
import
{
useGetState
}
from
'ahooks'
import
type
{
ConversationItem
}
from
'@/models/share'
...
...
@@ -11,7 +11,7 @@ function useConversation() {
const
[
pinnedConversationList
,
setPinnedConversationList
]
=
useState
<
ConversationItem
[]
>
([])
const
[
currConversationId
,
doSetCurrConversationId
,
getCurrConversationId
]
=
useGetState
<
string
>
(
'-1'
)
// when set conversation id, we do not have set appId
const
setCurrConversationId
=
(
id
:
string
,
appId
:
string
,
isSetToLocalStroge
=
true
,
newConversationName
=
''
)
=>
{
const
setCurrConversationId
=
useCallback
(
(
id
:
string
,
appId
:
string
,
isSetToLocalStroge
=
true
,
newConversationName
=
''
)
=>
{
doSetCurrConversationId
(
id
)
if
(
isSetToLocalStroge
&&
id
!==
'-1'
)
{
// conversationIdInfo: {[appId1]: conversationId1, [appId2]: conversationId2}
...
...
@@ -19,7 +19,7 @@ function useConversation() {
conversationIdInfo
[
appId
]
=
id
globalThis
.
localStorage
?.
setItem
(
storageConversationIdKey
,
JSON
.
stringify
(
conversationIdInfo
))
}
}
}
,
[
doSetCurrConversationId
])
const
getConversationIdFromStorage
=
(
appId
:
string
)
=>
{
const
conversationIdInfo
=
globalThis
.
localStorage
?.
getItem
(
storageConversationIdKey
)
?
JSON
.
parse
(
globalThis
.
localStorage
?.
getItem
(
storageConversationIdKey
)
||
''
)
:
{}
...
...
web/app/components/share/chat/index.tsx
View file @
f2b2effc
/* eslint-disable @typescript-eslint/no-use-before-define */
'use client'
import
type
{
FC
}
from
'react'
import
React
,
{
useEffect
,
useRef
,
useState
}
from
'react'
import
React
,
{
use
Callback
,
use
Effect
,
useRef
,
useState
}
from
'react'
import
cn
from
'classnames'
import
useSWR
from
'swr'
import
{
useTranslation
}
from
'react-i18next'
...
...
@@ -65,6 +65,7 @@ const Main: FC<IMainProps> = ({
installedAppInfo
,
})
=>
{
const
{
t
}
=
useTranslation
()
const
{
notify
}
=
useContext
(
ToastContext
)
const
media
=
useBreakpoints
()
const
isMobile
=
media
===
MediaType
.
mobile
...
...
@@ -123,7 +124,8 @@ const Main: FC<IMainProps> = ({
const
[
suggestedQuestions
,
setSuggestQuestions
]
=
useState
<
string
[]
>
([])
const
[
hasMore
,
setHasMore
]
=
useState
<
boolean
>
(
true
)
const
[
hasPinnedMore
,
setHasPinnedMore
]
=
useState
<
boolean
>
(
true
)
const
onMoreLoaded
=
({
data
:
conversations
,
has_more
}:
any
)
=>
{
const
[
isShowSuggestion
,
setIsShowSuggestion
]
=
useState
(
false
)
const
onMoreLoaded
=
useCallback
(({
data
:
conversations
,
has_more
}:
any
)
=>
{
setHasMore
(
has_more
)
if
(
isClearConversationList
)
{
setConversationList
(
conversations
)
...
...
@@ -132,8 +134,8 @@ const Main: FC<IMainProps> = ({
else
{
setConversationList
([...
conversationList
,
...
conversations
])
}
}
const
onPinnedMoreLoaded
=
({
data
:
conversations
,
has_more
}:
any
)
=>
{
}
,
[
conversationList
,
setConversationList
,
isClearConversationList
,
clearConversationListFalse
])
const
onPinnedMoreLoaded
=
useCallback
(
({
data
:
conversations
,
has_more
}:
any
)
=>
{
setHasPinnedMore
(
has_more
)
if
(
isClearPinnedConversationList
)
{
setPinnedConversationList
(
conversations
)
...
...
@@ -142,9 +144,9 @@ const Main: FC<IMainProps> = ({
else
{
setPinnedConversationList
([...
pinnedConversationList
,
...
conversations
])
}
}
}
,
[
pinnedConversationList
,
setPinnedConversationList
,
isClearPinnedConversationList
,
clearPinnedConversationListFalse
])
const
[
controlUpdateConversationList
,
setControlUpdateConversationList
]
=
useState
(
0
)
const
noticeUpdateList
=
()
=>
{
const
noticeUpdateList
=
useCallback
(
()
=>
{
setHasMore
(
true
)
clearConversationListTrue
()
...
...
@@ -152,25 +154,25 @@ const Main: FC<IMainProps> = ({
clearPinnedConversationListTrue
()
setControlUpdateConversationList
(
Date
.
now
())
}
const
handlePin
=
async
(
id
:
string
)
=>
{
}
,
[
clearConversationListTrue
,
clearPinnedConversationListTrue
])
const
handlePin
=
useCallback
(
async
(
id
:
string
)
=>
{
await
pinConversation
(
isInstalledApp
,
installedAppInfo
?.
id
,
id
)
notify
({
type
:
'success'
,
message
:
t
(
'common.api.success'
)
})
noticeUpdateList
()
}
}
,
[
isInstalledApp
,
installedAppInfo
?.
id
,
t
,
notify
,
noticeUpdateList
])
const
handleUnpin
=
async
(
id
:
string
)
=>
{
const
handleUnpin
=
useCallback
(
async
(
id
:
string
)
=>
{
await
unpinConversation
(
isInstalledApp
,
installedAppInfo
?.
id
,
id
)
notify
({
type
:
'success'
,
message
:
t
(
'common.api.success'
)
})
noticeUpdateList
()
}
}
,
[
isInstalledApp
,
installedAppInfo
?.
id
,
t
,
notify
,
noticeUpdateList
])
const
[
isShowConfirm
,
{
setTrue
:
showConfirm
,
setFalse
:
hideConfirm
}]
=
useBoolean
(
false
)
const
[
toDeleteConversationId
,
setToDeleteConversationId
]
=
useState
(
''
)
const
handleDelete
=
(
id
:
string
)
=>
{
const
handleDelete
=
useCallback
(
(
id
:
string
)
=>
{
setToDeleteConversationId
(
id
)
hideSidebar
()
// mobile
showConfirm
()
}
}
,
[
hideSidebar
,
showConfirm
])
const
didDelete
=
async
()
=>
{
await
delConversation
(
isInstalledApp
,
installedAppInfo
?.
id
,
toDeleteConversationId
)
...
...
@@ -186,17 +188,51 @@ const Main: FC<IMainProps> = ({
const
[
speechToTextConfig
,
setSpeechToTextConfig
]
=
useState
<
SpeechToTextConfig
|
null
>
(
null
)
const
[
textToSpeechConfig
,
setTextToSpeechConfig
]
=
useState
<
TextToSpeechConfig
|
null
>
(
null
)
const
[
citationConfig
,
setCitationConfig
]
=
useState
<
CitationConfig
|
null
>
(
null
)
const
[
chatList
,
setChatList
,
getChatList
]
=
useGetState
<
IChatItem
[]
>
([])
const
chatListDomRef
=
useRef
<
HTMLDivElement
>
(
null
)
const
[
isResponsing
,
{
setTrue
:
setResponsingTrue
,
setFalse
:
setResponsingFalse
}]
=
useBoolean
(
false
)
const
[
abortController
,
setAbortController
]
=
useState
<
AbortController
|
null
>
(
null
)
const
[
conversationIdChangeBecauseOfNew
,
setConversationIdChangeBecauseOfNew
,
getConversationIdChangeBecauseOfNew
]
=
useGetState
(
false
)
const
[
isChatStarted
,
{
setTrue
:
setChatStarted
,
setFalse
:
setChatNotStarted
}]
=
useBoolean
(
false
)
const
handleStartChat
=
(
inputs
:
Record
<
string
,
any
>
)
=>
{
const
conversationIntroduction
=
currConversationInfo
?.
introduction
||
''
const
createNewChat
=
useCallback
(
async
()
=>
{
// if new chat is already exist, do not create new chat
abortController
?.
abort
()
setResponsingFalse
()
if
(
conversationList
.
some
(
item
=>
item
.
id
===
'-1'
))
return
setConversationList
(
produce
(
conversationList
,
(
draft
)
=>
{
draft
.
unshift
({
id
:
'-1'
,
name
:
t
(
'share.chat.newChatDefaultName'
),
inputs
:
newConversationInputs
,
introduction
:
conversationIntroduction
,
})
}))
},
[
abortController
,
setResponsingFalse
,
setConversationList
,
conversationList
,
newConversationInputs
,
conversationIntroduction
,
t
,
])
const
handleStartChat
=
useCallback
((
inputs
:
Record
<
string
,
any
>
)
=>
{
createNewChat
()
setConversationIdChangeBecauseOfNew
(
true
)
setCurrInputs
(
inputs
)
setChatStarted
()
// parse variables in introduction
setChatList
(
generateNewChatListWithOpenstatement
(
''
,
inputs
))
}
},
[
createNewChat
,
setConversationIdChangeBecauseOfNew
,
setCurrInputs
,
setChatStarted
,
setChatList
,
])
const
hasSetInputs
=
(()
=>
{
if
(
!
isNewConversation
)
return
true
...
...
@@ -205,7 +241,6 @@ const Main: FC<IMainProps> = ({
})()
const
conversationName
=
currConversationInfo
?.
name
||
t
(
'share.chat.newChatDefaultName'
)
as
string
const
conversationIntroduction
=
currConversationInfo
?.
introduction
||
''
const
[
controlChatUpdateAllConversation
,
setControlChatUpdateAllConversation
]
=
useState
(
0
)
// onData change thought (the produce obj). https://github.com/immerjs/immer/issues/576
...
...
@@ -293,25 +328,9 @@ const Main: FC<IMainProps> = ({
}
useEffect
(
handleConversationSwitch
,
[
currConversationId
,
inited
])
const
handleConversationIdChange
=
(
id
:
string
)
=>
{
if
(
id
===
'-1'
)
{
createNewChat
()
setConversationIdChangeBecauseOfNew
(
true
)
}
else
{
setConversationIdChangeBecauseOfNew
(
false
)
}
// trigger handleConversationSwitch
setCurrConversationId
(
id
,
appId
)
setIsShowSuggestion
(
false
)
hideSidebar
()
}
/*
* chat info. chat is under conversation.
*/
const
[
chatList
,
setChatList
,
getChatList
]
=
useGetState
<
IChatItem
[]
>
([])
const
chatListDomRef
=
useRef
<
HTMLDivElement
>
(
null
)
useEffect
(()
=>
{
// scroll to bottom
if
(
chatListDomRef
.
current
)
...
...
@@ -319,22 +338,27 @@ const Main: FC<IMainProps> = ({
},
[
chatList
,
currConversationId
])
// user can not edit inputs if user had send message
const
canEditInpus
=
!
chatList
.
some
(
item
=>
item
.
isAnswer
===
false
)
&&
isNewConversation
const
createNewChat
=
async
()
=>
{
// if new chat is already exist, do not create new chat
abortController
?.
abort
()
setResponsingFalse
()
if
(
conversationList
.
some
(
item
=>
item
.
id
===
'-1'
))
return
setConversationList
(
produce
(
conversationList
,
(
draft
)
=>
{
draft
.
unshift
({
id
:
'-1'
,
name
:
t
(
'share.chat.newChatDefaultName'
),
inputs
:
newConversationInputs
,
introduction
:
conversationIntroduction
,
})
}))
}
const
handleConversationIdChange
=
useCallback
((
id
:
string
)
=>
{
if
(
id
===
'-1'
)
{
createNewChat
()
setConversationIdChangeBecauseOfNew
(
true
)
}
else
{
setConversationIdChangeBecauseOfNew
(
false
)
}
// trigger handleConversationSwitch
setCurrConversationId
(
id
,
appId
)
setIsShowSuggestion
(
false
)
hideSidebar
()
},
[
appId
,
createNewChat
,
hideSidebar
,
setCurrConversationId
,
setIsShowSuggestion
,
setConversationIdChangeBecauseOfNew
,
])
// sometime introduction is not applied to state
const
generateNewChatListWithOpenstatement
=
(
introduction
?:
string
,
inputs
?:
Record
<
string
,
any
>
|
null
)
=>
{
...
...
@@ -446,14 +470,11 @@ const Main: FC<IMainProps> = ({
})()
},
[])
const
[
isResponsing
,
{
setTrue
:
setResponsingTrue
,
setFalse
:
setResponsingFalse
}]
=
useBoolean
(
false
)
const
[
abortController
,
setAbortController
]
=
useState
<
AbortController
|
null
>
(
null
)
const
{
notify
}
=
useContext
(
ToastContext
)
const
logError
=
(
message
:
string
)
=>
{
const
logError
=
useCallback
((
message
:
string
)
=>
{
notify
({
type
:
'error'
,
message
})
}
}
,
[
notify
])
const
checkCanSend
=
()
=>
{
const
checkCanSend
=
useCallback
(
()
=>
{
if
(
currConversationId
!==
'-1'
)
return
true
...
...
@@ -480,10 +501,9 @@ const Main: FC<IMainProps> = ({
return
false
}
return
!
hasEmptyInput
}
}
,
[
currConversationId
,
currInputs
,
promptConfig
,
t
,
logError
])
const
[
controlFocus
,
setControlFocus
]
=
useState
(
0
)
const
[
isShowSuggestion
,
setIsShowSuggestion
]
=
useState
(
false
)
const
doShowSuggestion
=
isShowSuggestion
&&
!
isResponsing
const
[
openingSuggestedQuestions
,
setOpeningSuggestedQuestions
]
=
useState
<
string
[]
>
([])
const
[
messageTaskId
,
setMessageTaskId
]
=
useState
(
''
)
...
...
@@ -755,7 +775,7 @@ const Main: FC<IMainProps> = ({
},
isInstalledApp
,
installedAppInfo
?.
id
)
}
const
handleFeedback
=
async
(
messageId
:
string
,
feedback
:
Feedbacktype
)
=>
{
const
handleFeedback
=
useCallback
(
async
(
messageId
:
string
,
feedback
:
Feedbacktype
)
=>
{
await
updateFeedback
({
url
:
`/messages/
${
messageId
}
/feedbacks`
,
body
:
{
rating
:
feedback
.
rating
}
},
isInstalledApp
,
installedAppInfo
?.
id
)
const
newChatList
=
chatList
.
map
((
item
)
=>
{
if
(
item
.
id
===
messageId
)
{
...
...
@@ -768,7 +788,19 @@ const Main: FC<IMainProps> = ({
})
setChatList
(
newChatList
)
notify
({
type
:
'success'
,
message
:
t
(
'common.api.success'
)
})
}
},
[
isInstalledApp
,
installedAppInfo
?.
id
,
chatList
,
t
,
notify
,
setChatList
])
const
handleListChanged
=
useCallback
((
list
:
ConversationItem
[])
=>
{
setConversationList
(
list
)
setControlChatUpdateAllConversation
(
Date
.
now
())
},
[
setConversationList
,
setControlChatUpdateAllConversation
])
const
handlePinnedListChanged
=
useCallback
((
list
:
ConversationItem
[])
=>
{
setPinnedConversationList
(
list
)
setControlChatUpdateAllConversation
(
Date
.
now
())
},
[
setPinnedConversationList
,
setControlChatUpdateAllConversation
])
const
handleStartChatOnSidebar
=
useCallback
(()
=>
{
handleConversationIdChange
(
'-1'
)
},
[
handleConversationIdChange
])
const
renderSidebar
=
()
=>
{
if
(
!
appId
||
!
siteInfo
||
!
promptConfig
)
...
...
@@ -776,16 +808,10 @@ const Main: FC<IMainProps> = ({
return
(
<
Sidebar
list=
{
conversationList
}
onListChanged=
{
(
list
)
=>
{
setConversationList
(
list
)
setControlChatUpdateAllConversation
(
Date
.
now
())
}
}
onListChanged=
{
handleListChanged
}
isClearConversationList=
{
isClearConversationList
}
pinnedList=
{
pinnedConversationList
}
onPinnedListChanged=
{
(
list
)
=>
{
setPinnedConversationList
(
list
)
setControlChatUpdateAllConversation
(
Date
.
now
())
}
}
onPinnedListChanged=
{
handlePinnedListChanged
}
isClearPinnedConversationList=
{
isClearPinnedConversationList
}
onMoreLoaded=
{
onMoreLoaded
}
onPinnedMoreLoaded=
{
onPinnedMoreLoaded
}
...
...
@@ -801,11 +827,17 @@ const Main: FC<IMainProps> = ({
onUnpin=
{
handleUnpin
}
controlUpdateList=
{
controlUpdateConversationList
}
onDelete=
{
handleDelete
}
onStartChat=
{
()
=>
handleConversationIdChange
(
'-1'
)
}
onStartChat=
{
handleStartChatOnSidebar
}
/>
)
}
const
handleAbortResponsing
=
useCallback
(
async
()
=>
{
await
stopChatMessageResponding
(
appId
,
messageTaskId
,
isInstalledApp
,
installedAppInfo
?.
id
)
setHasStopResponded
(
true
)
setResponsingFalse
()
},
[
appId
,
messageTaskId
,
isInstalledApp
,
installedAppInfo
?.
id
])
if
(
appUnavailable
)
return
<
AppUnavailable
isUnknwonReason=
{
isUnknwonReason
}
/>
...
...
@@ -824,7 +856,7 @@ const Main: FC<IMainProps> = ({
icon_background=
{
siteInfo
.
icon_background
}
isMobile=
{
isMobile
}
onShowSideBar=
{
showSidebar
}
onCreateNewChat=
{
()
=>
handleConversationIdChange
(
'-1'
)
}
onCreateNewChat=
{
handleStartChatOnSidebar
}
/>
)
}
...
...
@@ -884,11 +916,7 @@ const Main: FC<IMainProps> = ({
onFeedback=
{
handleFeedback
}
isResponsing=
{
isResponsing
}
canStopResponsing=
{
!!
messageTaskId
&&
isResponsingConIsCurrCon
}
abortResponsing=
{
async
()
=>
{
await
stopChatMessageResponding
(
appId
,
messageTaskId
,
isInstalledApp
,
installedAppInfo
?.
id
)
setHasStopResponded
(
true
)
setResponsingFalse
()
}
}
abortResponsing=
{
handleAbortResponsing
}
checkCanSend=
{
checkCanSend
}
controlFocus=
{
controlFocus
}
isShowSuggestion=
{
doShowSuggestion
}
...
...
web/app/components/share/chat/sidebar/index.tsx
View file @
f2b2effc
import
React
,
{
useEffect
,
useState
}
from
'react'
import
React
,
{
use
Callback
,
use
Effect
,
useState
}
from
'react'
import
type
{
FC
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
{
...
...
@@ -76,6 +76,13 @@ const Sidebar: FC<ISidebarProps> = ({
checkHasPinned
()
},
[
controlUpdateList
])
const
handleUnpin
=
useCallback
((
id
:
string
)
=>
{
onUnpin
(
id
)
},
[
onUnpin
])
const
handlePin
=
useCallback
((
id
:
string
)
=>
{
onPin
(
id
)
},
[
onPin
])
const
maxListHeight
=
(
isInstalledApp
)
?
'max-h-[30vh]'
:
'max-h-[40vh]'
return
(
...
...
@@ -119,7 +126,7 @@ const Sidebar: FC<ISidebarProps> = ({
onMoreLoaded=
{
onPinnedMoreLoaded
}
isNoMore=
{
isPinnedNoMore
}
isPinned=
{
true
}
onPinChanged=
{
id
=>
onUnpin
(
id
)
}
onPinChanged=
{
handleUnpin
}
controlUpdate=
{
controlUpdateList
+
1
}
onDelete=
{
onDelete
}
/>
...
...
@@ -142,7 +149,7 @@ const Sidebar: FC<ISidebarProps> = ({
onMoreLoaded=
{
onMoreLoaded
}
isNoMore=
{
isNoMore
}
isPinned=
{
false
}
onPinChanged=
{
id
=>
onPin
(
id
)
}
onPinChanged=
{
handlePin
}
controlUpdate=
{
controlUpdateList
+
1
}
onDelete=
{
onDelete
}
/>
...
...
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