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
b5695337
Commit
b5695337
authored
Jul 24, 2023
by
StyleZhang
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'feat/universal-chat-fe' into deploy/dev
parents
10376aba
e828217c
Changes
17
Show whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
178 additions
and
24 deletions
+178
-24
layout.tsx
web/app/(commonLayout)/layout.tsx
+7
-4
index.tsx
web/app/components/app/chat/answer/index.tsx
+3
-2
index.tsx
web/app/components/app/chat/index.tsx
+3
-0
index.tsx
web/app/components/app/chat/thought/index.tsx
+8
-3
type.ts
web/app/components/app/chat/type.ts
+1
-0
index.tsx
web/app/components/app/configuration/config/index.tsx
+5
-7
index.tsx
web/app/components/app/configuration/debug/index.tsx
+3
-2
loading.svg
...p/components/base/icons/assets/public/thought/loading.svg
+10
-0
Loading.json
...app/components/base/icons/src/public/thought/Loading.json
+64
-0
Loading.tsx
web/app/components/base/icons/src/public/thought/Loading.tsx
+14
-0
index.ts
web/app/components/base/icons/src/public/thought/index.ts
+1
-0
index.tsx
...ents/explore/universal-chat/config/model-config/index.tsx
+4
-1
index.tsx
web/app/components/explore/universal-chat/index.tsx
+14
-3
provider-context.tsx
web/context/provider-context.tsx
+35
-0
explore.en.ts
web/i18n/lang/explore.en.ts
+1
-0
explore.zh.ts
web/i18n/lang/explore.zh.ts
+3
-1
base.ts
web/service/base.ts
+2
-1
No files found.
web/app/(commonLayout)/layout.tsx
View file @
b5695337
...
@@ -6,6 +6,7 @@ import GA, { GaType } from '@/app/components/base/ga'
...
@@ -6,6 +6,7 @@ import GA, { GaType } from '@/app/components/base/ga'
import
HeaderWrapper
from
'@/app/components/header/HeaderWrapper'
import
HeaderWrapper
from
'@/app/components/header/HeaderWrapper'
import
Header
from
'@/app/components/header'
import
Header
from
'@/app/components/header'
import
{
EventEmitterContextProvider
}
from
'@/context/event-emitter'
import
{
EventEmitterContextProvider
}
from
'@/context/event-emitter'
import
{
ProviderContextProvider
}
from
'@/context/provider-context'
const
Layout
=
({
children
}:
{
children
:
ReactNode
})
=>
{
const
Layout
=
({
children
}:
{
children
:
ReactNode
})
=>
{
return
(
return
(
...
@@ -14,10 +15,12 @@ const Layout = ({ children }: { children: ReactNode }) => {
...
@@ -14,10 +15,12 @@ const Layout = ({ children }: { children: ReactNode }) => {
<
SwrInitor
>
<
SwrInitor
>
<
AppContextProvider
>
<
AppContextProvider
>
<
EventEmitterContextProvider
>
<
EventEmitterContextProvider
>
<
ProviderContextProvider
>
<
HeaderWrapper
>
<
HeaderWrapper
>
<
Header
/>
<
Header
/>
</
HeaderWrapper
>
</
HeaderWrapper
>
{
children
}
{
children
}
</
ProviderContextProvider
>
</
EventEmitterContextProvider
>
</
EventEmitterContextProvider
>
</
AppContextProvider
>
</
AppContextProvider
>
</
SwrInitor
>
</
SwrInitor
>
...
...
web/app/components/app/chat/answer/index.tsx
View file @
b5695337
...
@@ -44,9 +44,10 @@ export type IAnswerProps = {
...
@@ -44,9 +44,10 @@ export type IAnswerProps = {
isResponsing
?:
boolean
isResponsing
?:
boolean
answerIconClassName
?:
string
answerIconClassName
?:
string
thoughts
?:
ThoughtItem
[]
thoughts
?:
ThoughtItem
[]
isThinking
?:
boolean
}
}
// The component needs to maintain its own state to control whether to display input component
// The component needs to maintain its own state to control whether to display input component
const
Answer
:
FC
<
IAnswerProps
>
=
({
item
,
feedbackDisabled
=
false
,
isHideFeedbackEdit
=
false
,
onFeedback
,
onSubmitAnnotation
,
displayScene
=
'web'
,
isResponsing
,
answerIconClassName
,
thoughts
})
=>
{
const
Answer
:
FC
<
IAnswerProps
>
=
({
item
,
feedbackDisabled
=
false
,
isHideFeedbackEdit
=
false
,
onFeedback
,
onSubmitAnnotation
,
displayScene
=
'web'
,
isResponsing
,
answerIconClassName
,
thoughts
,
isThinking
})
=>
{
const
{
id
,
content
,
more
,
feedback
,
adminFeedback
,
annotation
:
initAnnotation
}
=
item
const
{
id
,
content
,
more
,
feedback
,
adminFeedback
,
annotation
:
initAnnotation
}
=
item
const
[
showEdit
,
setShowEdit
]
=
useState
(
false
)
const
[
showEdit
,
setShowEdit
]
=
useState
(
false
)
const
[
loading
,
setLoading
]
=
useState
(
false
)
const
[
loading
,
setLoading
]
=
useState
(
false
)
...
@@ -204,7 +205,7 @@ const Answer: FC<IAnswerProps> = ({ item, feedbackDisabled = false, isHideFeedba
...
@@ -204,7 +205,7 @@ const Answer: FC<IAnswerProps> = ({ item, feedbackDisabled = false, isHideFeedba
:
(
:
(
<
div
>
<
div
>
{
(
thoughts
&&
thoughts
.
length
>
0
)
&&
(
{
(
thoughts
&&
thoughts
.
length
>
0
)
&&
(
<
Thought
list=
{
thoughts
||
[]
}
/>
<
Thought
list=
{
thoughts
||
[]
}
isThinking=
{
isThinking
}
/>
)
}
)
}
<
Markdown
content=
{
content
}
/>
<
Markdown
content=
{
content
}
/>
</
div
>
</
div
>
...
...
web/app/components/app/chat/index.tsx
View file @
b5695337
...
@@ -47,6 +47,7 @@ export type IChatProps = {
...
@@ -47,6 +47,7 @@ export type IChatProps = {
isShowSpeechToText
?:
boolean
isShowSpeechToText
?:
boolean
answerIconClassName
?:
string
answerIconClassName
?:
string
isShowConfigElem
?:
boolean
isShowConfigElem
?:
boolean
isThoughting
?:
boolean
}
}
const
Chat
:
FC
<
IChatProps
>
=
({
const
Chat
:
FC
<
IChatProps
>
=
({
...
@@ -156,6 +157,7 @@ const Chat: FC<IChatProps> = ({
...
@@ -156,6 +157,7 @@ const Chat: FC<IChatProps> = ({
if
(
item
.
isAnswer
)
{
if
(
item
.
isAnswer
)
{
const
isLast
=
item
.
id
===
chatList
[
chatList
.
length
-
1
].
id
const
isLast
=
item
.
id
===
chatList
[
chatList
.
length
-
1
].
id
const
thoughts
=
item
.
agent_thoughts
?.
filter
(
item
=>
item
.
thought
!==
'[DONE]'
)
const
thoughts
=
item
.
agent_thoughts
?.
filter
(
item
=>
item
.
thought
!==
'[DONE]'
)
const
isThinking
=
item
.
agent_thoughts
&&
item
.
agent_thoughts
?.
length
>
0
&&
!
item
.
agent_thoughts
.
find
(
item
=>
item
.
thought
!==
'[DONE]'
)
return
<
Answer
return
<
Answer
key=
{
item
.
id
}
key=
{
item
.
id
}
item=
{
item
}
item=
{
item
}
...
@@ -167,6 +169,7 @@ const Chat: FC<IChatProps> = ({
...
@@ -167,6 +169,7 @@ const Chat: FC<IChatProps> = ({
isResponsing=
{
isResponsing
&&
isLast
}
isResponsing=
{
isResponsing
&&
isLast
}
answerIconClassName=
{
answerIconClassName
}
answerIconClassName=
{
answerIconClassName
}
thoughts=
{
thoughts
}
thoughts=
{
thoughts
}
isThinking=
{
isThinking
}
/>
/>
}
}
return
<
Question
key=
{
item
.
id
}
id=
{
item
.
id
}
content=
{
item
.
content
}
more=
{
item
.
more
}
useCurrentUserAvatar=
{
useCurrentUserAvatar
}
/>
return
<
Question
key=
{
item
.
id
}
id=
{
item
.
id
}
content=
{
item
.
content
}
more=
{
item
.
more
}
useCurrentUserAvatar=
{
useCurrentUserAvatar
}
/>
...
...
web/app/components/app/chat/thought/index.tsx
View file @
b5695337
...
@@ -5,13 +5,14 @@ import cn from 'classnames'
...
@@ -5,13 +5,14 @@ import cn from 'classnames'
import
{
useTranslation
}
from
'react-i18next'
import
{
useTranslation
}
from
'react-i18next'
import
type
{
ThoughtItem
}
from
'../type'
import
type
{
ThoughtItem
}
from
'../type'
import
s
from
'./style.module.css'
import
s
from
'./style.module.css'
import
{
DataSet
,
Search
,
ThoughtList
,
WebReader
}
from
'@/app/components/base/icons/src/public/thought'
import
{
DataSet
,
Loading
as
LodingIcon
,
Search
,
ThoughtList
,
WebReader
}
from
'@/app/components/base/icons/src/public/thought'
import
{
ChevronDown
}
from
'@/app/components/base/icons/src/vender/line/arrows'
import
{
ChevronDown
}
from
'@/app/components/base/icons/src/vender/line/arrows'
// https://www.freecodecamp.org/news/how-to-write-a-regular-expression-for-a-url/
// https://www.freecodecamp.org/news/how-to-write-a-regular-expression-for-a-url/
const
urlRegex
=
/
(
https:
\/\/
www
\.
|http:
\/\/
www
\.
|https:
\/\/
|http:
\/\/)?[
a-zA-Z
]{2,}(\.[
a-zA-Z
]{2,})(\.[
a-zA-Z
]{2,})?\/[
a-zA-Z0-9
]{2,}
|
((
https:
\/\/
www
\.
|http:
\/\/
www
\.
|https:
\/\/
|http:
\/\/)?[
a-zA-Z
]{2,}(\.[
a-zA-Z
]{2,})(\.[
a-zA-Z
]{2,})?)
|
(
https:
\/\/
www
\.
|http:
\/\/
www
\.
|https:
\/\/
|http:
\/\/)?[
a-zA-Z0-9
]{2,}\.[
a-zA-Z0-9
]{2,}\.[
a-zA-Z0-9
]{2,}(\.[
a-zA-Z0-9
]{2,})?
/gi
const
urlRegex
=
/
(
https:
\/\/
www
\.
|http:
\/\/
www
\.
|https:
\/\/
|http:
\/\/)?[
a-zA-Z
]{2,}(\.[
a-zA-Z
]{2,})(\.[
a-zA-Z
]{2,})?\/[
a-zA-Z0-9
]{2,}
|
((
https:
\/\/
www
\.
|http:
\/\/
www
\.
|https:
\/\/
|http:
\/\/)?[
a-zA-Z
]{2,}(\.[
a-zA-Z
]{2,})(\.[
a-zA-Z
]{2,})?)
|
(
https:
\/\/
www
\.
|http:
\/\/
www
\.
|https:
\/\/
|http:
\/\/)?[
a-zA-Z0-9
]{2,}\.[
a-zA-Z0-9
]{2,}\.[
a-zA-Z0-9
]{2,}(\.[
a-zA-Z0-9
]{2,})?
/gi
export
type
IThoughtProps
=
{
export
type
IThoughtProps
=
{
list
:
ThoughtItem
[]
list
:
ThoughtItem
[]
isThinking
?:
boolean
}
}
const
getIcon
=
(
toolId
:
string
)
=>
{
const
getIcon
=
(
toolId
:
string
)
=>
{
...
@@ -27,6 +28,7 @@ const getIcon = (toolId: string) => {
...
@@ -27,6 +28,7 @@ const getIcon = (toolId: string) => {
const
Thought
:
FC
<
IThoughtProps
>
=
({
const
Thought
:
FC
<
IThoughtProps
>
=
({
list
,
list
,
isThinking
,
})
=>
{
})
=>
{
const
{
t
}
=
useTranslation
()
const
{
t
}
=
useTranslation
()
const
[
isShowDetail
,
setIsShowDetail
]
=
React
.
useState
(
false
)
const
[
isShowDetail
,
setIsShowDetail
]
=
React
.
useState
(
false
)
...
@@ -62,8 +64,11 @@ const Thought: FC<IThoughtProps> = ({
...
@@ -62,8 +64,11 @@ const Thought: FC<IThoughtProps> = ({
return
(
return
(
<
div
className=
{
cn
(
s
.
wrap
,
!
isShowDetail
&&
s
.
wrapHoverEffect
,
'inline-block mb-2 px-2 py-0.5 rounded-md text-xs text-gray-500 font-medium'
)
}
>
<
div
className=
{
cn
(
s
.
wrap
,
!
isShowDetail
&&
s
.
wrapHoverEffect
,
'inline-block mb-2 px-2 py-0.5 rounded-md text-xs text-gray-500 font-medium'
)
}
>
<
div
className=
'flex items-center h-6 space-x-1 cursor-pointer'
onClick=
{
()
=>
setIsShowDetail
(
!
isShowDetail
)
}
>
<
div
className=
'flex items-center h-6 space-x-1 cursor-pointer'
onClick=
{
()
=>
setIsShowDetail
(
!
isShowDetail
)
}
>
<
ThoughtList
/>
{
!
isThinking
?
<
ThoughtList
/>
:
<
div
className=
'animate-spin'
><
LodingIcon
/></
div
>
}
<
div
>
{
t
(
`explore.universalChat.thought.${isShowDetail ? 'hide' : 'show'}`
)
}{
t
(
'explore.universalChat.thought.processOfThought'
)
}
</
div
>
<
div
dangerouslySetInnerHTML=
{
{
__html
:
isThinking
?
getThoughtText
(
list
[
0
])
:
(
t
(
`explore.universalChat.thought.${isShowDetail ? 'hide' : 'show'}`
)
+
t
(
'explore.universalChat.thought.processOfThought'
)),
}
}
></
div
>
<
ChevronDown
className=
{
isShowDetail
?
'rotate-180'
:
''
}
/>
<
ChevronDown
className=
{
isShowDetail
?
'rotate-180'
:
''
}
/>
</
div
>
</
div
>
{
isShowDetail
&&
(
{
isShowDetail
&&
(
...
...
web/app/components/app/chat/type.ts
View file @
b5695337
...
@@ -21,6 +21,7 @@ export type ThoughtItem = {
...
@@ -21,6 +21,7 @@ export type ThoughtItem = {
tool
:
string
// plugin or dataset
tool
:
string
// plugin or dataset
thought
:
string
thought
:
string
tool_input
:
string
tool_input
:
string
message_id
:
string
}
}
export
type
IChatItem
=
{
export
type
IChatItem
=
{
id
:
string
id
:
string
...
...
web/app/components/app/configuration/config/index.tsx
View file @
b5695337
...
@@ -4,7 +4,6 @@ import React from 'react'
...
@@ -4,7 +4,6 @@ import React from 'react'
import
{
useContext
}
from
'use-context-selector'
import
{
useContext
}
from
'use-context-selector'
import
produce
from
'immer'
import
produce
from
'immer'
import
{
useBoolean
}
from
'ahooks'
import
{
useBoolean
}
from
'ahooks'
import
useSWR
from
'swr'
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'
...
@@ -20,7 +19,7 @@ import ConfigPrompt from '@/app/components/app/configuration/config-prompt'
...
@@ -20,7 +19,7 @@ import ConfigPrompt from '@/app/components/app/configuration/config-prompt'
import
ConfigVar
from
'@/app/components/app/configuration/config-var'
import
ConfigVar
from
'@/app/components/app/configuration/config-var'
import
type
{
PromptVariable
}
from
'@/models/debug'
import
type
{
PromptVariable
}
from
'@/models/debug'
import
{
AppType
}
from
'@/types/app'
import
{
AppType
}
from
'@/types/app'
import
{
fetchTenantInfo
}
from
'@/service/common
'
import
{
useProviderContext
}
from
'@/context/provider-context
'
const
Config
:
FC
=
()
=>
{
const
Config
:
FC
=
()
=>
{
const
{
const
{
...
@@ -39,8 +38,7 @@ const Config: FC = () => {
...
@@ -39,8 +38,7 @@ const Config: FC = () => {
setSpeechToTextConfig
,
setSpeechToTextConfig
,
}
=
useContext
(
ConfigContext
)
}
=
useContext
(
ConfigContext
)
const
isChatApp
=
mode
===
AppType
.
chat
const
isChatApp
=
mode
===
AppType
.
chat
const
{
data
:
userInfo
}
=
useSWR
({
url
:
'/info'
},
fetchTenantInfo
)
const
{
currentProvider
}
=
useProviderContext
()
const
openaiProvider
=
userInfo
?.
providers
?.
find
(({
token_is_set
,
is_valid
,
provider_name
})
=>
token_is_set
&&
is_valid
&&
provider_name
===
'openai'
)
const
promptTemplate
=
modelConfig
.
configs
.
prompt_template
const
promptTemplate
=
modelConfig
.
configs
.
prompt_template
const
promptVariables
=
modelConfig
.
configs
.
prompt_variables
const
promptVariables
=
modelConfig
.
configs
.
prompt_variables
...
@@ -92,7 +90,7 @@ const Config: FC = () => {
...
@@ -92,7 +90,7 @@ const Config: FC = () => {
},
},
})
})
const
hasChatConfig
=
isChatApp
&&
(
featureConfig
.
openingStatement
||
featureConfig
.
suggestedQuestionsAfterAnswer
||
(
featureConfig
.
speechToText
&&
openaiProvider
))
const
hasChatConfig
=
isChatApp
&&
(
featureConfig
.
openingStatement
||
featureConfig
.
suggestedQuestionsAfterAnswer
||
(
featureConfig
.
speechToText
&&
currentProvider
?.
provider_name
===
'openai'
))
const
hasToolbox
=
false
const
hasToolbox
=
false
const
[
showAutomatic
,
{
setTrue
:
showAutomaticTrue
,
setFalse
:
showAutomaticFalse
}]
=
useBoolean
(
false
)
const
[
showAutomatic
,
{
setTrue
:
showAutomaticTrue
,
setFalse
:
showAutomaticFalse
}]
=
useBoolean
(
false
)
...
@@ -122,7 +120,7 @@ const Config: FC = () => {
...
@@ -122,7 +120,7 @@ const Config: FC = () => {
isChatApp=
{
isChatApp
}
isChatApp=
{
isChatApp
}
config=
{
featureConfig
}
config=
{
featureConfig
}
onChange=
{
handleFeatureChange
}
onChange=
{
handleFeatureChange
}
showSpeechToTextItem=
{
!!
openaiProvider
}
showSpeechToTextItem=
{
currentProvider
?.
provider_name
===
'openai'
}
/>
/>
)
}
)
}
{
showAutomatic
&&
(
{
showAutomatic
&&
(
...
@@ -162,7 +160,7 @@ const Config: FC = () => {
...
@@ -162,7 +160,7 @@ const Config: FC = () => {
}
}
}
}
isShowSuggestedQuestionsAfterAnswer=
{
featureConfig
.
suggestedQuestionsAfterAnswer
}
isShowSuggestedQuestionsAfterAnswer=
{
featureConfig
.
suggestedQuestionsAfterAnswer
}
isShowSpeechText=
{
featureConfig
.
speechToText
}
isShowSpeechText=
{
featureConfig
.
speechToText
&&
currentProvider
?.
provider_name
===
'openai'
}
/>
/>
)
)
}
}
...
...
web/app/components/app/configuration/debug/index.tsx
View file @
b5695337
...
@@ -22,6 +22,7 @@ import type { ModelConfig as BackendModelConfig } from '@/types/app'
...
@@ -22,6 +22,7 @@ import type { ModelConfig as BackendModelConfig } from '@/types/app'
import
{
promptVariablesToUserInputsForm
}
from
'@/utils/model-config'
import
{
promptVariablesToUserInputsForm
}
from
'@/utils/model-config'
import
TextGeneration
from
'@/app/components/app/text-generate/item'
import
TextGeneration
from
'@/app/components/app/text-generate/item'
import
{
IS_CE_EDITION
}
from
'@/config'
import
{
IS_CE_EDITION
}
from
'@/config'
import
{
useProviderContext
}
from
'@/context/provider-context'
type
IDebug
=
{
type
IDebug
=
{
hasSetAPIKEY
:
boolean
hasSetAPIKEY
:
boolean
...
@@ -51,7 +52,7 @@ const Debug: FC<IDebug> = ({
...
@@ -51,7 +52,7 @@ const Debug: FC<IDebug> = ({
modelConfig
,
modelConfig
,
completionParams
,
completionParams
,
}
=
useContext
(
ConfigContext
)
}
=
useContext
(
ConfigContext
)
const
{
currentProvider
}
=
useProviderContext
()
const
[
chatList
,
setChatList
,
getChatList
]
=
useGetState
<
IChatItem
[]
>
([])
const
[
chatList
,
setChatList
,
getChatList
]
=
useGetState
<
IChatItem
[]
>
([])
const
chatListDomRef
=
useRef
<
HTMLDivElement
>
(
null
)
const
chatListDomRef
=
useRef
<
HTMLDivElement
>
(
null
)
useEffect
(()
=>
{
useEffect
(()
=>
{
...
@@ -389,7 +390,7 @@ const Debug: FC<IDebug> = ({
...
@@ -389,7 +390,7 @@ const Debug: FC<IDebug> = ({
}
}
}
}
isShowSuggestion=
{
doShowSuggestion
}
isShowSuggestion=
{
doShowSuggestion
}
suggestionList=
{
suggestQuestions
}
suggestionList=
{
suggestQuestions
}
isShowSpeechToText=
{
speechToTextConfig
.
enabled
}
isShowSpeechToText=
{
speechToTextConfig
.
enabled
&&
currentProvider
?.
provider_name
===
'openai'
}
/>
/>
</
div
>
</
div
>
</
div
>
</
div
>
...
...
web/app/components/base/icons/assets/public/thought/loading.svg
0 → 100644
View file @
b5695337
<svg
width=
"12"
height=
"12"
viewBox=
"0 0 12 12"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<g
clip-path=
"url(#clip0_7998_4025)"
>
<path
d=
"M6 1.125V2.375M6 9V11M2.875 6H1.125M10.625 6H9.875M9.22855 9.22855L8.875 8.875M9.33211 2.70789L8.625 3.415M2.46079 9.53921L3.875 8.125M2.56434 2.60434L3.625 3.665"
stroke=
"#667085"
stroke-width=
"1.25"
stroke-linecap=
"round"
stroke-linejoin=
"round"
/>
</g>
<defs>
<clipPath
id=
"clip0_7998_4025"
>
<rect
width=
"12"
height=
"12"
fill=
"white"
/>
</clipPath>
</defs>
</svg>
web/app/components/base/icons/src/public/thought/Loading.json
0 → 100644
View file @
b5695337
{
"icon"
:
{
"type"
:
"element"
,
"isRootNode"
:
true
,
"name"
:
"svg"
,
"attributes"
:
{
"width"
:
"12"
,
"height"
:
"12"
,
"viewBox"
:
"0 0 12 12"
,
"fill"
:
"none"
,
"xmlns"
:
"http://www.w3.org/2000/svg"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"g"
,
"attributes"
:
{
"clip-path"
:
"url(#clip0_7998_4025)"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"d"
:
"M6 1.125V2.375M6 9V11M2.875 6H1.125M10.625 6H9.875M9.22855 9.22855L8.875 8.875M9.33211 2.70789L8.625 3.415M2.46079 9.53921L3.875 8.125M2.56434 2.60434L3.625 3.665"
,
"stroke"
:
"#667085"
,
"stroke-width"
:
"1.25"
,
"stroke-linecap"
:
"round"
,
"stroke-linejoin"
:
"round"
},
"children"
:
[]
}
]
},
{
"type"
:
"element"
,
"name"
:
"defs"
,
"attributes"
:
{},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"clipPath"
,
"attributes"
:
{
"id"
:
"clip0_7998_4025"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"rect"
,
"attributes"
:
{
"width"
:
"12"
,
"height"
:
"12"
,
"fill"
:
"white"
},
"children"
:
[]
}
]
}
]
}
]
},
"name"
:
"Loading"
}
\ No newline at end of file
web/app/components/base/icons/src/public/thought/Loading.tsx
0 → 100644
View file @
b5695337
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./Loading.json'
import
IconBase
from
'@/app/components/base/icons/IconBase'
import
type
{
IconBaseProps
,
IconData
}
from
'@/app/components/base/icons/IconBase'
const
Icon
=
React
.
forwardRef
<
React
.
MutableRefObject
<
SVGElement
>
,
Omit
<
IconBaseProps
,
'data'
>>
((
props
,
ref
,
)
=>
<
IconBase
{
...
props
}
ref=
{
ref
}
data=
{
data
as
IconData
}
/>)
export
default
Icon
web/app/components/base/icons/src/public/thought/index.ts
View file @
b5695337
export
{
default
as
DataSet
}
from
'./DataSet'
export
{
default
as
DataSet
}
from
'./DataSet'
export
{
default
as
Loading
}
from
'./Loading'
export
{
default
as
Search
}
from
'./Search'
export
{
default
as
Search
}
from
'./Search'
export
{
default
as
ThoughtList
}
from
'./ThoughtList'
export
{
default
as
ThoughtList
}
from
'./ThoughtList'
export
{
default
as
WebReader
}
from
'./WebReader'
export
{
default
as
WebReader
}
from
'./WebReader'
web/app/components/explore/universal-chat/config/model-config/index.tsx
View file @
b5695337
...
@@ -4,6 +4,7 @@ import React from 'react'
...
@@ -4,6 +4,7 @@ import React from 'react'
import
cn
from
'classnames'
import
cn
from
'classnames'
import
{
useBoolean
,
useClickAway
}
from
'ahooks'
import
{
useBoolean
,
useClickAway
}
from
'ahooks'
import
{
ChevronDownIcon
}
from
'@heroicons/react/24/outline'
import
{
ChevronDownIcon
}
from
'@heroicons/react/24/outline'
import
{
useTranslation
}
from
'react-i18next'
import
ModelIcon
from
'@/app/components/app/configuration/config-model/model-icon'
import
ModelIcon
from
'@/app/components/app/configuration/config-model/model-icon'
import
{
UNIVERSAL_CHAT_MODEL_LIST
as
MODEL_LIST
}
from
'@/config'
import
{
UNIVERSAL_CHAT_MODEL_LIST
as
MODEL_LIST
}
from
'@/config'
...
@@ -18,6 +19,8 @@ const ModelConfig: FC<IModelConfigProps> = ({
...
@@ -18,6 +19,8 @@ const ModelConfig: FC<IModelConfigProps> = ({
onChange
,
onChange
,
readonly
,
readonly
,
})
=>
{
})
=>
{
const
{
t
}
=
useTranslation
()
const
currModel
=
MODEL_LIST
.
find
(
item
=>
item
.
id
===
modelId
)
const
currModel
=
MODEL_LIST
.
find
(
item
=>
item
.
id
===
modelId
)
const
[
isShowOption
,
{
setFalse
:
hideOption
,
toggle
:
toogleOption
}]
=
useBoolean
(
false
)
const
[
isShowOption
,
{
setFalse
:
hideOption
,
toggle
:
toogleOption
}]
=
useBoolean
(
false
)
const
triggerRef
=
React
.
useRef
(
null
)
const
triggerRef
=
React
.
useRef
(
null
)
...
@@ -27,7 +30,7 @@ const ModelConfig: FC<IModelConfigProps> = ({
...
@@ -27,7 +30,7 @@ const ModelConfig: FC<IModelConfigProps> = ({
return
(
return
(
<
div
className=
'flex items-center justify-between h-[52px] px-3 rounded-xl bg-gray-50'
>
<
div
className=
'flex items-center justify-between h-[52px] px-3 rounded-xl bg-gray-50'
>
<
div
className=
'text-sm font-semibold text-gray-800'
>
Model
</
div
>
<
div
className=
'text-sm font-semibold text-gray-800'
>
{
t
(
'explore.universalChat.model'
)
}
</
div
>
<
div
className=
"relative z-10"
>
<
div
className=
"relative z-10"
>
<
div
ref=
{
triggerRef
}
onClick=
{
()
=>
!
readonly
&&
toogleOption
()
}
className=
{
cn
(
readonly
?
'cursor-not-allowed'
:
'cursor-pointer'
,
'flex items-center h-9 px-3 space-x-2 rounded-lg bg-gray-50 '
)
}
>
<
div
ref=
{
triggerRef
}
onClick=
{
()
=>
!
readonly
&&
toogleOption
()
}
className=
{
cn
(
readonly
?
'cursor-not-allowed'
:
'cursor-pointer'
,
'flex items-center h-9 px-3 space-x-2 rounded-lg bg-gray-50 '
)
}
>
<
ModelIcon
modelId=
{
currModel
?.
id
as
string
}
/>
<
ModelIcon
modelId=
{
currModel
?.
id
as
string
}
/>
...
...
web/app/components/explore/universal-chat/index.tsx
View file @
b5695337
...
@@ -480,7 +480,7 @@ const Main: FC<IMainProps> = () => {
...
@@ -480,7 +480,7 @@ const Main: FC<IMainProps> = () => {
getChatList
().
filter
(
item
=>
item
.
id
!==
responseItem
.
id
&&
item
.
id
!==
placeholderAnswerId
),
getChatList
().
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
}
as
any
)
draft
.
push
({
...
responseItem
})
draft
.
push
({
...
responseItem
})
})
})
...
@@ -506,9 +506,20 @@ const Main: FC<IMainProps> = () => {
...
@@ -506,9 +506,20 @@ const Main: FC<IMainProps> = () => {
}
}
},
},
onThought
(
thought
)
{
onThought
(
thought
)
{
// debugger
if
(
thought
.
thought
===
'[DONE]'
)
// thought then start to return message
return
responseItem
.
id
=
thought
.
message_id
;
// thought finished then start to return message
(
responseItem
as
any
).
agent_thoughts
.
push
(
thought
)
(
responseItem
as
any
).
agent_thoughts
.
push
(
thought
)
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
})
})
// console.log('start render thought')
setChatList
(
newListWithAnswer
)
},
},
onError
()
{
onError
()
{
setResponsingFalse
()
setResponsingFalse
()
...
...
web/context/provider-context.tsx
0 → 100644
View file @
b5695337
'use client'
import
{
createContext
,
useContext
}
from
'use-context-selector'
import
useSWR
from
'swr'
import
{
fetchTenantInfo
}
from
'@/service/common'
const
ProviderContext
=
createContext
<
{
currentProvider
:
{
provider
:
string
provider_name
:
string
token_is_set
:
boolean
is_valid
:
boolean
token_is_valid
:
boolean
}
|
null
|
undefined
}
>
({
currentProvider
:
null
,
})
export
const
useProviderContext
=
()
=>
useContext
(
ProviderContext
)
type
ProviderContextProviderProps
=
{
children
:
React
.
ReactNode
}
export
const
ProviderContextProvider
=
({
children
,
}:
ProviderContextProviderProps
)
=>
{
const
{
data
:
userInfo
}
=
useSWR
({
url
:
'/info'
},
fetchTenantInfo
)
const
currentProvider
=
userInfo
?.
providers
?.
find
(({
token_is_set
,
is_valid
})
=>
token_is_set
&&
is_valid
)
return
(
<
ProviderContext
.
Provider
value=
{
{
currentProvider
}
}
>
{
children
}
</
ProviderContext
.
Provider
>
)
}
export
default
ProviderContext
web/i18n/lang/explore.en.ts
View file @
b5695337
...
@@ -38,6 +38,7 @@ const translation = {
...
@@ -38,6 +38,7 @@ const translation = {
universalChat
:
{
universalChat
:
{
welcome
:
'Start chat with Dify'
,
welcome
:
'Start chat with Dify'
,
welcomeDescribe
:
'Your AI conversation companion for personalized assistance'
,
welcomeDescribe
:
'Your AI conversation companion for personalized assistance'
,
model
:
'Model'
,
plugins
:
{
plugins
:
{
name
:
'Plugins'
,
name
:
'Plugins'
,
google_search
:
{
google_search
:
{
...
...
web/i18n/lang/explore.zh.ts
View file @
b5695337
...
@@ -2,7 +2,7 @@ const translation = {
...
@@ -2,7 +2,7 @@ const translation = {
title
:
'我的应用'
,
title
:
'我的应用'
,
sidebar
:
{
sidebar
:
{
discovery
:
'发现'
,
discovery
:
'发现'
,
chat
:
'
聊天
'
,
chat
:
'
智聊
'
,
workspace
:
'工作区'
,
workspace
:
'工作区'
,
action
:
{
action
:
{
pin
:
'置顶'
,
pin
:
'置顶'
,
...
@@ -38,7 +38,9 @@ const translation = {
...
@@ -38,7 +38,9 @@ const translation = {
universalChat
:
{
universalChat
:
{
welcome
:
'开始和 Dify 聊天吧'
,
welcome
:
'开始和 Dify 聊天吧'
,
welcomeDescribe
:
'您的 AI 对话伴侣,为您提供个性化的帮助'
,
welcomeDescribe
:
'您的 AI 对话伴侣,为您提供个性化的帮助'
,
model
:
'模型'
,
plugins
:
{
plugins
:
{
name
:
'插件'
,
google_search
:
{
google_search
:
{
name
:
'谷歌搜索'
,
name
:
'谷歌搜索'
,
more
:
{
more
:
{
...
...
web/service/base.ts
View file @
b5695337
/* eslint-disable no-new, prefer-promise-reject-errors */
/* eslint-disable no-new, prefer-promise-reject-errors */
import
{
API_PREFIX
,
IS_CE_EDITION
,
PUBLIC_API_PREFIX
}
from
'@/config'
import
{
API_PREFIX
,
IS_CE_EDITION
,
PUBLIC_API_PREFIX
}
from
'@/config'
import
Toast
from
'@/app/components/base/toast'
import
Toast
from
'@/app/components/base/toast'
import
type
{
ThoughtItem
}
from
'@/app/components/app/chat/type'
const
TIME_OUT
=
100000
const
TIME_OUT
=
100000
...
@@ -30,7 +31,7 @@ export type IOnDataMoreInfo = {
...
@@ -30,7 +31,7 @@ export type IOnDataMoreInfo = {
}
}
export
type
IOnData
=
(
message
:
string
,
isFirstMessage
:
boolean
,
moreInfo
:
IOnDataMoreInfo
)
=>
void
export
type
IOnData
=
(
message
:
string
,
isFirstMessage
:
boolean
,
moreInfo
:
IOnDataMoreInfo
)
=>
void
export
type
IOnThought
=
(
though
:
{
id
:
string
;
tool
:
string
;
thought
:
string
}
)
=>
void
export
type
IOnThought
=
(
though
:
ThoughtItem
)
=>
void
export
type
IOnCompleted
=
(
hasError
?:
boolean
)
=>
void
export
type
IOnCompleted
=
(
hasError
?:
boolean
)
=>
void
export
type
IOnError
=
(
msg
:
string
)
=>
void
export
type
IOnError
=
(
msg
:
string
)
=>
void
...
...
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