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
23e34136
Unverified
Commit
23e34136
authored
Jul 27, 2023
by
Joel
Committed by
GitHub
Jul 27, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: chat in explore support agent (#647)
Co-authored-by:
StyleZhang
<
jasonapring2015@outlook.com
>
parent
4fdb3777
Changes
121
Hide whitespace changes
Inline
Side-by-side
Showing
121 changed files
with
4081 additions
and
527 deletions
+4081
-527
page.tsx
web/app/(commonLayout)/explore/chat/page.tsx
+13
-0
layout.tsx
web/app/(commonLayout)/layout.tsx
+10
-4
index.tsx
web/app/components/app/chat/answer/index.tsx
+262
-0
index.tsx
web/app/components/app/chat/icon-component/index.tsx
+37
-0
index.tsx
web/app/components/app/chat/index.tsx
+21
-370
index.tsx
web/app/components/app/chat/more-info/index.tsx
+19
-0
index.tsx
web/app/components/app/chat/operation/index.tsx
+14
-0
index.tsx
web/app/components/app/chat/question/index.tsx
+40
-0
index.tsx
web/app/components/app/chat/thought/index.tsx
+86
-0
style.module.css
web/app/components/app/chat/thought/style.module.css
+7
-0
type.ts
web/app/components/app/chat/type.ts
+53
-0
index.tsx
...components/app/configuration/base/feature-panel/index.tsx
+11
-8
index.tsx
web/app/components/app/configuration/config-model/index.tsx
+6
-42
model-icon.tsx
.../components/app/configuration/config-model/model-icon.tsx
+26
-0
index.tsx
web/app/components/app/configuration/config/index.tsx
+5
-7
index.tsx
...ents/app/configuration/dataset-config/card-item/index.tsx
+9
-8
index.tsx
...app/configuration/dataset-config/select-dataset/index.tsx
+6
-2
index.tsx
web/app/components/app/configuration/debug/index.tsx
+3
-2
list.tsx
web/app/components/app/log/list.tsx
+2
-2
anthropic.svg
...app/components/base/icons/assets/public/llm/anthropic.svg
+12
-0
gpt-3.svg
web/app/components/base/icons/assets/public/llm/gpt-3.svg
+5
-0
gpt-4.svg
web/app/components/base/icons/assets/public/llm/gpt-4.svg
+5
-0
checked.svg
...app/components/base/icons/assets/public/model/checked.svg
+3
-0
google.svg
...pp/components/base/icons/assets/public/plugins/google.svg
+6
-0
web-reader.svg
...omponents/base/icons/assets/public/plugins/web-reader.svg
+4
-0
wikipedia.svg
...components/base/icons/assets/public/plugins/wikipedia.svg
+3
-0
data-set.svg
.../components/base/icons/assets/public/thought/data-set.svg
+10
-0
loading.svg
...p/components/base/icons/assets/public/thought/loading.svg
+10
-0
search.svg
...pp/components/base/icons/assets/public/thought/search.svg
+10
-0
thought-list.svg
...ponents/base/icons/assets/public/thought/thought-list.svg
+8
-0
web-reader.svg
...omponents/base/icons/assets/public/thought/web-reader.svg
+10
-0
link-external-02.svg
...ase/icons/assets/vender/line/general/link-external-02.svg
+5
-0
alert-circle.svg
...ns/assets/vender/solid/alertsAndFeedback/alert-circle.svg
+5
-0
check-circle.svg
...s/base/icons/assets/vender/solid/general/check-circle.svg
+5
-0
Anthropic.json
web/app/components/base/icons/src/public/llm/Anthropic.json
+87
-0
Anthropic.tsx
web/app/components/base/icons/src/public/llm/Anthropic.tsx
+14
-0
Gpt3.json
web/app/components/base/icons/src/public/llm/Gpt3.json
+51
-0
Gpt3.tsx
web/app/components/base/icons/src/public/llm/Gpt3.tsx
+14
-0
Gpt4.json
web/app/components/base/icons/src/public/llm/Gpt4.json
+51
-0
Gpt4.tsx
web/app/components/base/icons/src/public/llm/Gpt4.tsx
+14
-0
index.ts
web/app/components/base/icons/src/public/llm/index.ts
+3
-0
Checked.json
web/app/components/base/icons/src/public/model/Checked.json
+29
-0
Checked.tsx
web/app/components/base/icons/src/public/model/Checked.tsx
+14
-0
index.ts
web/app/components/base/icons/src/public/model/index.ts
+1
-0
Google.json
web/app/components/base/icons/src/public/plugins/Google.json
+53
-0
Google.tsx
web/app/components/base/icons/src/public/plugins/Google.tsx
+14
-0
WebReader.json
...p/components/base/icons/src/public/plugins/WebReader.json
+39
-0
WebReader.tsx
...pp/components/base/icons/src/public/plugins/WebReader.tsx
+14
-0
Wikipedia.json
...p/components/base/icons/src/public/plugins/Wikipedia.json
+26
-0
Wikipedia.tsx
...pp/components/base/icons/src/public/plugins/Wikipedia.tsx
+14
-0
index.ts
web/app/components/base/icons/src/public/plugins/index.ts
+3
-0
DataSet.json
...app/components/base/icons/src/public/thought/DataSet.json
+64
-0
DataSet.tsx
web/app/components/base/icons/src/public/thought/DataSet.tsx
+14
-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
Search.json
web/app/components/base/icons/src/public/thought/Search.json
+64
-0
Search.tsx
web/app/components/base/icons/src/public/thought/Search.tsx
+14
-0
ThoughtList.json
...components/base/icons/src/public/thought/ThoughtList.json
+83
-0
ThoughtList.tsx
.../components/base/icons/src/public/thought/ThoughtList.tsx
+14
-0
WebReader.json
...p/components/base/icons/src/public/thought/WebReader.json
+64
-0
WebReader.tsx
...pp/components/base/icons/src/public/thought/WebReader.tsx
+14
-0
index.ts
web/app/components/base/icons/src/public/thought/index.ts
+5
-0
LinkExternal02.json
...ts/base/icons/src/vender/line/general/LinkExternal02.json
+38
-0
LinkExternal02.tsx
...nts/base/icons/src/vender/line/general/LinkExternal02.tsx
+14
-0
index.ts
...pp/components/base/icons/src/vender/line/general/index.ts
+1
-0
AlertCircle.json
...icons/src/vender/solid/alertsAndFeedback/AlertCircle.json
+38
-0
AlertCircle.tsx
.../icons/src/vender/solid/alertsAndFeedback/AlertCircle.tsx
+14
-0
index.ts
...ts/base/icons/src/vender/solid/alertsAndFeedback/index.ts
+1
-0
CheckCircle.json
...ents/base/icons/src/vender/solid/general/CheckCircle.json
+38
-0
CheckCircle.tsx
...nents/base/icons/src/vender/solid/general/CheckCircle.tsx
+14
-0
index.ts
...p/components/base/icons/src/vender/solid/general/index.ts
+1
-0
markdown.tsx
web/app/components/base/markdown.tsx
+51
-39
index.tsx
web/app/components/base/toast/index.tsx
+4
-3
index.tsx
web/app/components/base/voice-input/index.tsx
+1
-1
index.tsx
web/app/components/explore/sidebar/index.tsx
+23
-2
index.tsx
...nents/explore/universal-chat/config-view/detail/index.tsx
+34
-0
style.module.css
...xplore/universal-chat/config-view/detail/style.module.css
+9
-0
index.tsx
...ents/explore/universal-chat/config-view/summary/index.tsx
+84
-0
style.module.css
...plore/universal-chat/config-view/summary/style.module.css
+21
-0
index.tsx
...nents/explore/universal-chat/config/data-config/index.tsx
+95
-0
index.tsx
web/app/components/explore/universal-chat/config/index.tsx
+51
-0
index.tsx
...ents/explore/universal-chat/config/model-config/index.tsx
+61
-0
index.tsx
...ts/explore/universal-chat/config/plugins-config/index.tsx
+111
-0
item.module.css
...lore/universal-chat/config/plugins-config/item.module.css
+3
-0
item.tsx
...nts/explore/universal-chat/config/plugins-config/item.tsx
+43
-0
use-conversation.ts
...mponents/explore/universal-chat/hooks/use-conversation.ts
+72
-0
index.tsx
web/app/components/explore/universal-chat/index.tsx
+725
-0
index.tsx
web/app/components/explore/universal-chat/init/index.tsx
+43
-0
style.module.css
...p/components/explore/universal-chat/init/style.module.css
+9
-0
style.module.css
web/app/components/explore/universal-chat/style.module.css
+3
-0
index.tsx
web/app/components/header/account-setting/index.tsx
+10
-2
KeyInput.tsx
...ponents/header/account-setting/key-validator/KeyInput.tsx
+77
-0
Operate.tsx
...mponents/header/account-setting/key-validator/Operate.tsx
+85
-0
ValidateStatus.tsx
...s/header/account-setting/key-validator/ValidateStatus.tsx
+30
-0
declarations.ts
...ents/header/account-setting/key-validator/declarations.ts
+43
-0
hooks.ts
.../components/header/account-setting/key-validator/hooks.ts
+32
-0
index.tsx
...components/header/account-setting/key-validator/index.tsx
+119
-0
SerpapiPlugin.tsx
...ents/header/account-setting/plugin-page/SerpapiPlugin.tsx
+77
-0
index.tsx
...p/components/header/account-setting/plugin-page/index.tsx
+38
-0
utils.ts
...pp/components/header/account-setting/plugin-page/utils.ts
+34
-0
serpapi.png
web/app/components/header/assets/serpapi.png
+0
-0
use-conversation.ts
web/app/components/share/chat/hooks/use-conversation.ts
+3
-1
index.tsx
web/app/components/share/chat/index.tsx
+15
-5
index.tsx
web/app/components/share/chat/sidebar/index.tsx
+22
-9
index.tsx
web/app/components/share/chat/sidebar/list/index.tsx
+10
-3
index.tsx
web/app/components/share/chat/welcome/index.tsx
+1
-1
index.tsx
web/app/components/share/chatbot/sidebar/list/index.tsx
+1
-1
markdown.scss
web/app/styles/markdown.scss
+2
-2
index.ts
web/config/index.ts
+17
-0
event-emitter.tsx
web/context/event-emitter.tsx
+28
-0
provider-context.tsx
web/context/provider-context.tsx
+35
-0
common.en.ts
web/i18n/lang/common.en.ts
+8
-0
common.zh.ts
web/i18n/lang/common.zh.ts
+8
-0
explore.en.ts
web/i18n/lang/explore.en.ts
+38
-0
explore.zh.ts
web/i18n/lang/explore.zh.ts
+38
-0
common.ts
web/models/common.ts
+8
-0
base.ts
web/service/base.ts
+22
-11
common.ts
web/service/common.ts
+12
-1
explore.ts
web/service/explore.ts
+4
-0
share.ts
web/service/share.ts
+1
-1
universal-chat.ts
web/service/universal-chat.ts
+75
-0
No files found.
web/app/(commonLayout)/explore/chat/page.tsx
0 → 100644
View file @
23e34136
import
type
{
FC
}
from
'react'
import
React
from
'react'
import
UniversalChat
from
'@/app/components/explore/universal-chat'
const
Chat
:
FC
=
()
=>
{
return
(
<
div
className=
'h-full p-2'
>
<
UniversalChat
/>
</
div
>
)
}
export
default
React
.
memo
(
Chat
)
web/app/(commonLayout)/layout.tsx
View file @
23e34136
...
...
@@ -5,6 +5,8 @@ import { AppContextProvider } from '@/context/app-context'
import
GA
,
{
GaType
}
from
'@/app/components/base/ga'
import
HeaderWrapper
from
'@/app/components/header/HeaderWrapper'
import
Header
from
'@/app/components/header'
import
{
EventEmitterContextProvider
}
from
'@/context/event-emitter'
import
{
ProviderContextProvider
}
from
'@/context/provider-context'
const
Layout
=
({
children
}:
{
children
:
ReactNode
})
=>
{
return
(
...
...
@@ -12,10 +14,14 @@ const Layout = ({ children }: { children: ReactNode }) => {
<
GA
gaType=
{
GaType
.
admin
}
/>
<
SwrInitor
>
<
AppContextProvider
>
<
HeaderWrapper
>
<
Header
/>
</
HeaderWrapper
>
{
children
}
<
EventEmitterContextProvider
>
<
ProviderContextProvider
>
<
HeaderWrapper
>
<
Header
/>
</
HeaderWrapper
>
{
children
}
</
ProviderContextProvider
>
</
EventEmitterContextProvider
>
</
AppContextProvider
>
</
SwrInitor
>
</>
...
...
web/app/components/app/chat/answer/index.tsx
0 → 100644
View file @
23e34136
'use client'
import
type
{
FC
}
from
'react'
import
React
,
{
useState
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
{
useContext
}
from
'use-context-selector'
import
{
UserCircleIcon
}
from
'@heroicons/react/24/solid'
import
cn
from
'classnames'
import
type
{
DisplayScene
,
FeedbackFunc
,
Feedbacktype
,
IChatItem
,
SubmitAnnotationFunc
,
ThoughtItem
}
from
'../type'
import
{
randomString
}
from
'../../../app-sidebar/basic'
import
OperationBtn
from
'../operation'
import
LoadingAnim
from
'../loading-anim'
import
{
EditIcon
,
EditIconSolid
,
OpeningStatementIcon
,
RatingIcon
}
from
'../icon-component'
import
s
from
'../style.module.css'
import
MoreInfo
from
'../more-info'
import
CopyBtn
from
'../copy-btn'
import
Thought
from
'../thought'
import
type
{
Annotation
,
MessageRating
}
from
'@/models/log'
import
AppContext
from
'@/context/app-context'
import
Tooltip
from
'@/app/components/base/tooltip'
import
{
Markdown
}
from
'@/app/components/base/markdown'
import
AutoHeightTextarea
from
'@/app/components/base/auto-height-textarea'
import
Button
from
'@/app/components/base/button'
import
type
{
DataSet
}
from
'@/models/datasets'
const
Divider
:
FC
<
{
name
:
string
}
>
=
({
name
})
=>
{
const
{
t
}
=
useTranslation
()
return
<
div
className=
'flex items-center my-2'
>
<
span
className=
'text-xs text-gray-500 inline-flex items-center mr-2'
>
<
EditIconSolid
className=
'mr-1'
/>
{
t
(
'appLog.detail.annotationTip'
,
{
user
:
name
})
}
</
span
>
<
div
className=
'h-[1px] bg-gray-200 flex-1'
></
div
>
</
div
>
}
const
IconWrapper
:
FC
<
{
children
:
React
.
ReactNode
|
string
}
>
=
({
children
})
=>
{
return
<
div
className=
{
'rounded-lg h-6 w-6 flex items-center justify-center hover:bg-gray-100'
}
>
{
children
}
</
div
>
}
export
type
IAnswerProps
=
{
item
:
IChatItem
feedbackDisabled
:
boolean
isHideFeedbackEdit
:
boolean
onFeedback
?:
FeedbackFunc
onSubmitAnnotation
?:
SubmitAnnotationFunc
displayScene
:
DisplayScene
isResponsing
?:
boolean
answerIconClassName
?:
string
thoughts
?:
ThoughtItem
[]
isThinking
?:
boolean
dataSets
?:
DataSet
[]
}
// 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
,
isThinking
,
dataSets
})
=>
{
const
{
id
,
content
,
more
,
feedback
,
adminFeedback
,
annotation
:
initAnnotation
}
=
item
const
[
showEdit
,
setShowEdit
]
=
useState
(
false
)
const
[
loading
,
setLoading
]
=
useState
(
false
)
const
[
annotation
,
setAnnotation
]
=
useState
<
Annotation
|
undefined
|
null
>
(
initAnnotation
)
const
[
inputValue
,
setInputValue
]
=
useState
<
string
>
(
initAnnotation
?.
content
??
''
)
const
[
localAdminFeedback
,
setLocalAdminFeedback
]
=
useState
<
Feedbacktype
|
undefined
|
null
>
(
adminFeedback
)
const
{
userProfile
}
=
useContext
(
AppContext
)
const
{
t
}
=
useTranslation
()
/**
* Render feedback results (distinguish between users and administrators)
* User reviews cannot be cancelled in Console
* @param rating feedback result
* @param isUserFeedback Whether it is user's feedback
* @param isWebScene Whether it is web scene
* @returns comp
*/
const
renderFeedbackRating
=
(
rating
:
MessageRating
|
undefined
,
isUserFeedback
=
true
,
isWebScene
=
true
)
=>
{
if
(
!
rating
)
return
null
const
isLike
=
rating
===
'like'
const
ratingIconClassname
=
isLike
?
'text-primary-600 bg-primary-100 hover:bg-primary-200'
:
'text-red-600 bg-red-100 hover:bg-red-200'
const
UserSymbol
=
<
UserCircleIcon
className=
'absolute top-[-2px] left-[18px] w-3 h-3 rounded-lg text-gray-400 bg-white'
/>
// The tooltip is always displayed, but the content is different for different scenarios.
return
(
<
Tooltip
selector=
{
`user-feedback-${randomString(16)}`
}
content=
{
((
isWebScene
||
(
!
isUserFeedback
&&
!
isWebScene
))
?
isLike
?
t
(
'appDebug.operation.cancelAgree'
)
:
t
(
'appDebug.operation.cancelDisagree'
)
:
(
!
isWebScene
&&
isUserFeedback
)
?
`${t('appDebug.operation.userAction')}${isLike ? t('appDebug.operation.agree') : t('appDebug.operation.disagree')}`
:
''
)
as
string
}
>
<
div
className=
{
`relative box-border flex items-center justify-center h-7 w-7 p-0.5 rounded-lg bg-white cursor-pointer text-gray-500 hover:text-gray-800 ${(!isWebScene && isUserFeedback) ? '!cursor-default' : ''}`
}
style=
{
{
boxShadow
:
'0px 4px 6px -1px rgba(0, 0, 0, 0.1), 0px 2px 4px -2px rgba(0, 0, 0, 0.05)'
}
}
{
...
((
isWebScene
||
(!
isUserFeedback
&&
!
isWebScene
))
?
{
onClick
:
async
()
=
>
{
const
res
=
await
onFeedback
?.(
id
,
{
rating
:
null
})
if
(
res
&&
!
isWebScene
)
setLocalAdminFeedback
({
rating
:
null
})
}
,
}
:
{}
)}
>
<
div
className=
{
`${ratingIconClassname} rounded-lg h-6 w-6 flex items-center justify-center`
}
>
<
RatingIcon
isLike=
{
isLike
}
/>
</
div
>
{
!
isWebScene
&&
isUserFeedback
&&
UserSymbol
}
</
div
>
</
Tooltip
>
)
}
/**
* Different scenarios have different operation items.
* @param isWebScene Whether it is web scene
* @returns comp
*/
const
renderItemOperation
=
(
isWebScene
=
true
)
=>
{
const
userOperation
=
()
=>
{
return
feedback
?.
rating
?
null
:
<
div
className=
'flex gap-1'
>
<
Tooltip
selector=
{
`user-feedback-${randomString(16)}`
}
content=
{
t
(
'appLog.detail.operation.like'
)
as
string
}
>
{
OperationBtn
({
innerContent
:
<
IconWrapper
><
RatingIcon
isLike=
{
true
}
/></
IconWrapper
>,
onClick
:
()
=>
onFeedback
?.(
id
,
{
rating
:
'like'
})
})
}
</
Tooltip
>
<
Tooltip
selector=
{
`user-feedback-${randomString(16)}`
}
content=
{
t
(
'appLog.detail.operation.dislike'
)
as
string
}
>
{
OperationBtn
({
innerContent
:
<
IconWrapper
><
RatingIcon
isLike=
{
false
}
/></
IconWrapper
>,
onClick
:
()
=>
onFeedback
?.(
id
,
{
rating
:
'dislike'
})
})
}
</
Tooltip
>
</
div
>
}
const
adminOperation
=
()
=>
{
return
<
div
className=
'flex gap-1'
>
<
Tooltip
selector=
{
`user-feedback-${randomString(16)}`
}
content=
{
t
(
'appLog.detail.operation.addAnnotation'
)
as
string
}
>
{
OperationBtn
({
innerContent
:
<
IconWrapper
><
EditIcon
className=
'hover:text-gray-800'
/></
IconWrapper
>,
onClick
:
()
=>
setShowEdit
(
true
),
})
}
</
Tooltip
>
{
!
localAdminFeedback
?.
rating
&&
<>
<
Tooltip
selector=
{
`user-feedback-${randomString(16)}`
}
content=
{
t
(
'appLog.detail.operation.like'
)
as
string
}
>
{
OperationBtn
({
innerContent
:
<
IconWrapper
><
RatingIcon
isLike=
{
true
}
/></
IconWrapper
>,
onClick
:
async
()
=>
{
const
res
=
await
onFeedback
?.(
id
,
{
rating
:
'like'
})
if
(
res
)
setLocalAdminFeedback
({
rating
:
'like'
})
},
})
}
</
Tooltip
>
<
Tooltip
selector=
{
`user-feedback-${randomString(16)}`
}
content=
{
t
(
'appLog.detail.operation.dislike'
)
as
string
}
>
{
OperationBtn
({
innerContent
:
<
IconWrapper
><
RatingIcon
isLike=
{
false
}
/></
IconWrapper
>,
onClick
:
async
()
=>
{
const
res
=
await
onFeedback
?.(
id
,
{
rating
:
'dislike'
})
if
(
res
)
setLocalAdminFeedback
({
rating
:
'dislike'
})
},
})
}
</
Tooltip
>
</>
}
</
div
>
}
return
(
<
div
className=
{
`${s.itemOperation} flex gap-2`
}
>
{
isWebScene
?
userOperation
()
:
adminOperation
()
}
</
div
>
)
}
return
(
<
div
key=
{
id
}
>
<
div
className=
'flex items-start'
>
<
div
className=
{
`${s.answerIcon} ${answerIconClassName} w-10 h-10 shrink-0`
}
>
{
isResponsing
&&
<
div
className=
{
s
.
typeingIcon
}
>
<
LoadingAnim
type=
'avatar'
/>
</
div
>
}
</
div
>
<
div
className=
{
s
.
answerWrapWrap
}
>
<
div
className=
{
`${s.answerWrap} ${showEdit ? 'w-full' : ''}`
}
>
<
div
className=
{
`${s.answer} relative text-sm text-gray-900`
}
>
<
div
className=
{
'ml-2 py-3 px-4 bg-gray-100 rounded-tr-2xl rounded-b-2xl'
}
>
{
item
.
isOpeningStatement
&&
(
<
div
className=
'flex items-center mb-1 gap-1'
>
<
OpeningStatementIcon
/>
<
div
className=
'text-xs text-gray-500'
>
{
t
(
'appDebug.openingStatement.title'
)
}
</
div
>
</
div
>
)
}
{
(
thoughts
&&
thoughts
.
length
>
0
)
&&
(
<
Thought
list=
{
thoughts
||
[]
}
isThinking=
{
isThinking
}
dataSets=
{
dataSets
}
/>
)
}
{
(
isResponsing
&&
!
content
)
?
(
<
div
className=
'flex items-center justify-center w-6 h-5'
>
<
LoadingAnim
type=
'text'
/>
</
div
>
)
:
(
<
div
>
<
Markdown
content=
{
content
}
/>
</
div
>
)
}
{
!
showEdit
?
(
annotation
?.
content
&&
<>
<
Divider
name=
{
annotation
?.
account
?.
name
||
userProfile
?.
name
}
/>
{
annotation
.
content
}
</>)
:
<>
<
Divider
name=
{
annotation
?.
account
?.
name
||
userProfile
?.
name
}
/>
<
AutoHeightTextarea
placeholder=
{
t
(
'appLog.detail.operation.annotationPlaceholder'
)
as
string
}
value=
{
inputValue
}
onChange=
{
e
=>
setInputValue
(
e
.
target
.
value
)
}
minHeight=
{
58
}
className=
{
`${cn(s.textArea)} !py-2 resize-none block w-full !px-3 bg-gray-50 border border-gray-200 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm text-gray-700 tracking-[0.2px]`
}
/>
<
div
className=
"mt-2 flex flex-row"
>
<
Button
type=
'primary'
className=
'mr-2'
loading=
{
loading
}
onClick=
{
async
()
=>
{
if
(
!
inputValue
)
return
setLoading
(
true
)
const
res
=
await
onSubmitAnnotation
?.(
id
,
inputValue
)
if
(
res
)
setAnnotation
({
...
annotation
,
content
:
inputValue
}
as
any
)
setLoading
(
false
)
setShowEdit
(
false
)
}
}
>
{
t
(
'common.operation.confirm'
)
}
</
Button
>
<
Button
onClick=
{
()
=>
{
setInputValue
(
annotation
?.
content
??
''
)
setShowEdit
(
false
)
}
}
>
{
t
(
'common.operation.cancel'
)
}
</
Button
>
</
div
>
</>
}
</
div
>
<
div
className=
'absolute top-[-14px] right-[-14px] flex flex-row justify-end gap-1'
>
{
!
item
.
isOpeningStatement
&&
(
<
CopyBtn
value=
{
content
}
className=
{
cn
(
s
.
copyBtn
,
'mr-1'
)
}
/>
)
}
{
!
feedbackDisabled
&&
!
item
.
feedbackDisabled
&&
renderItemOperation
(
displayScene
!==
'console'
)
}
{
/* Admin feedback is displayed only in the background. */
}
{
!
feedbackDisabled
&&
renderFeedbackRating
(
localAdminFeedback
?.
rating
,
false
,
false
)
}
{
/* User feedback must be displayed */
}
{
!
feedbackDisabled
&&
renderFeedbackRating
(
feedback
?.
rating
,
!
isHideFeedbackEdit
,
displayScene
!==
'console'
)
}
</
div
>
</
div
>
{
more
&&
<
MoreInfo
more=
{
more
}
isQuestion=
{
false
}
/>
}
</
div
>
</
div
>
</
div
>
</
div
>
)
}
export
default
React
.
memo
(
Answer
)
web/app/components/app/chat/icon-component/index.tsx
0 → 100644
View file @
23e34136
import
type
{
FC
}
from
'react'
import
{
HandThumbDownIcon
,
HandThumbUpIcon
}
from
'@heroicons/react/24/outline'
export
const
stopIcon
=
(
<
svg
width=
"14"
height=
"14"
viewBox=
"0 0 14 14"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<
path
fillRule=
"evenodd"
clipRule=
"evenodd"
d=
"M7.00004 0.583313C3.45621 0.583313 0.583374 3.45615 0.583374 6.99998C0.583374 10.5438 3.45621 13.4166 7.00004 13.4166C10.5439 13.4166 13.4167 10.5438 13.4167 6.99998C13.4167 3.45615 10.5439 0.583313 7.00004 0.583313ZM4.73029 4.98515C4.66671 5.10993 4.66671 5.27328 4.66671 5.59998V8.39998C4.66671 8.72668 4.66671 8.89003 4.73029 9.01481C4.78621 9.12457 4.87545 9.21381 4.98521 9.26973C5.10999 9.33331 5.27334 9.33331 5.60004 9.33331H8.40004C8.72674 9.33331 8.89009 9.33331 9.01487 9.26973C9.12463 9.21381 9.21387 9.12457 9.2698 9.01481C9.33337 8.89003 9.33337 8.72668 9.33337 8.39998V5.59998C9.33337 5.27328 9.33337 5.10993 9.2698 4.98515C9.21387 4.87539 9.12463 4.78615 9.01487 4.73023C8.89009 4.66665 8.72674 4.66665 8.40004 4.66665H5.60004C5.27334 4.66665 5.10999 4.66665 4.98521 4.73023C4.87545 4.78615 4.78621 4.87539 4.73029 4.98515Z"
fill=
"#667085"
/>
</
svg
>
)
export
const
OpeningStatementIcon
:
FC
<
{
className
?:
string
}
>
=
({
className
})
=>
(
<
svg
className=
{
className
}
width=
"12"
height=
"12"
viewBox=
"0 0 12 12"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<
path
fillRule=
"evenodd"
clipRule=
"evenodd"
d=
"M6.25002 1C3.62667 1 1.50002 3.12665 1.50002 5.75C1.50002 6.28 1.58702 6.79071 1.7479 7.26801C1.7762 7.35196 1.79285 7.40164 1.80368 7.43828L1.80722 7.45061L1.80535 7.45452C1.79249 7.48102 1.77339 7.51661 1.73766 7.58274L0.911727 9.11152C0.860537 9.20622 0.807123 9.30503 0.770392 9.39095C0.733879 9.47635 0.674738 9.63304 0.703838 9.81878C0.737949 10.0365 0.866092 10.2282 1.05423 10.343C1.21474 10.4409 1.38213 10.4461 1.475 10.4451C1.56844 10.444 1.68015 10.4324 1.78723 10.4213L4.36472 10.1549C4.406 10.1506 4.42758 10.1484 4.44339 10.1472L4.44542 10.147L4.45161 10.1492C4.47103 10.1562 4.49738 10.1663 4.54285 10.1838C5.07332 10.3882 5.64921 10.5 6.25002 10.5C8.87338 10.5 11 8.37335 11 5.75C11 3.12665 8.87338 1 6.25002 1ZM4.48481 4.29111C5.04844 3.81548 5.7986 3.9552 6.24846 4.47463C6.69831 3.9552 7.43879 3.82048 8.01211 4.29111C8.58544 4.76175 8.6551 5.562 8.21247 6.12453C7.93825 6.47305 7.24997 7.10957 6.76594 7.54348C6.58814 7.70286 6.49924 7.78255 6.39255 7.81466C6.30103 7.84221 6.19589 7.84221 6.10436 7.81466C5.99767 7.78255 5.90878 7.70286 5.73098 7.54348C5.24694 7.10957 4.55867 6.47305 4.28444 6.12453C3.84182 5.562 3.92117 4.76675 4.48481 4.29111Z"
fill=
"#667085"
/>
</
svg
>
)
export
const
RatingIcon
:
FC
<
{
isLike
:
boolean
}
>
=
({
isLike
})
=>
{
return
isLike
?
<
HandThumbUpIcon
className=
'w-4 h-4'
/>
:
<
HandThumbDownIcon
className=
'w-4 h-4'
/>
}
export
const
EditIcon
:
FC
<
{
className
?:
string
}
>
=
({
className
})
=>
{
return
<
svg
width=
"16"
height=
"16"
viewBox=
"0 0 16 16"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
className=
{
className
}
>
<
path
d=
"M14 11.9998L13.3332 12.7292C12.9796 13.1159 12.5001 13.3332 12.0001 13.3332C11.5001 13.3332 11.0205 13.1159 10.6669 12.7292C10.3128 12.3432 9.83332 12.1265 9.33345 12.1265C8.83359 12.1265 8.35409 12.3432 7.99998 12.7292M2 13.3332H3.11636C3.44248 13.3332 3.60554 13.3332 3.75899 13.2963C3.89504 13.2637 4.0251 13.2098 4.1444 13.1367C4.27895 13.0542 4.39425 12.9389 4.62486 12.7083L13 4.33316C13.5523 3.78087 13.5523 2.88544 13 2.33316C12.4477 1.78087 11.5523 1.78087 11 2.33316L2.62484 10.7083C2.39424 10.9389 2.27894 11.0542 2.19648 11.1888C2.12338 11.3081 2.0695 11.4381 2.03684 11.5742C2 11.7276 2 11.8907 2 12.2168V13.3332Z"
stroke=
"#6B7280"
strokeLinecap=
"round"
strokeLinejoin=
"round"
/>
</
svg
>
}
export
const
EditIconSolid
:
FC
<
{
className
?:
string
}
>
=
({
className
})
=>
{
return
<
svg
width=
"12"
height=
"12"
viewBox=
"0 0 12 12"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
className=
{
className
}
>
<
path
fillRule=
"evenodd"
clipRule=
"evenodd"
d=
"M10.8374 8.63108C11.0412 8.81739 11.0554 9.13366 10.8691 9.33747L10.369 9.88449C10.0142 10.2725 9.52293 10.5001 9.00011 10.5001C8.47746 10.5001 7.98634 10.2727 7.63157 9.8849C7.45561 9.69325 7.22747 9.59515 7.00014 9.59515C6.77271 9.59515 6.54446 9.69335 6.36846 9.88517C6.18177 10.0886 5.86548 10.1023 5.66201 9.91556C5.45853 9.72888 5.44493 9.41259 5.63161 9.20911C5.98678 8.82201 6.47777 8.59515 7.00014 8.59515C7.52251 8.59515 8.0135 8.82201 8.36867 9.20911L8.36924 9.20974C8.54486 9.4018 8.77291 9.50012 9.00011 9.50012C9.2273 9.50012 9.45533 9.40182 9.63095 9.20979L10.131 8.66276C10.3173 8.45895 10.6336 8.44476 10.8374 8.63108Z"
fill=
"#6B7280"
/>
<
path
fillRule=
"evenodd"
clipRule=
"evenodd"
d=
"M7.89651 1.39656C8.50599 0.787085 9.49414 0.787084 10.1036 1.39656C10.7131 2.00604 10.7131 2.99419 10.1036 3.60367L3.82225 9.88504C3.81235 9.89494 3.80254 9.90476 3.79281 9.91451C3.64909 10.0585 3.52237 10.1855 3.3696 10.2791C3.23539 10.3613 3.08907 10.4219 2.93602 10.4587C2.7618 10.5005 2.58242 10.5003 2.37897 10.5001C2.3652 10.5001 2.35132 10.5001 2.33732 10.5001H1.50005C1.22391 10.5001 1.00005 10.2763 1.00005 10.0001V9.16286C1.00005 9.14886 1.00004 9.13497 1.00003 9.1212C0.999836 8.91776 0.999669 8.73838 1.0415 8.56416C1.07824 8.4111 1.13885 8.26479 1.22109 8.13058C1.31471 7.97781 1.44166 7.85109 1.58566 7.70736C1.5954 7.69764 1.60523 7.68783 1.61513 7.67793L7.89651 1.39656Z"
fill=
"#6B7280"
/>
</
svg
>
}
export
const
TryToAskIcon
=
(
<
svg
width=
"11"
height=
"10"
viewBox=
"0 0 11 10"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<
path
d=
"M5.88889 0.683718C5.827 0.522805 5.67241 0.416626 5.5 0.416626C5.3276 0.416626 5.173 0.522805 5.11111 0.683718L4.27279 2.86334C4.14762 3.18877 4.10829 3.28255 4.05449 3.35821C4.00051 3.43413 3.93418 3.50047 3.85826 3.55445C3.78259 3.60825 3.68881 3.64758 3.36338 3.77275L1.18376 4.61106C1.02285 4.67295 0.916668 4.82755 0.916668 4.99996C0.916668 5.17236 1.02285 5.32696 1.18376 5.38885L3.36338 6.22717C3.68881 6.35234 3.78259 6.39167 3.85826 6.44547C3.93418 6.49945 4.00051 6.56578 4.05449 6.6417C4.10829 6.71737 4.14762 6.81115 4.27279 7.13658L5.11111 9.3162C5.173 9.47711 5.3276 9.58329 5.5 9.58329C5.67241 9.58329 5.82701 9.47711 5.8889 9.3162L6.72721 7.13658C6.85238 6.81115 6.89171 6.71737 6.94551 6.6417C6.99949 6.56578 7.06583 6.49945 7.14175 6.44547C7.21741 6.39167 7.31119 6.35234 7.63662 6.22717L9.81624 5.38885C9.97715 5.32696 10.0833 5.17236 10.0833 4.99996C10.0833 4.82755 9.97715 4.67295 9.81624 4.61106L7.63662 3.77275C7.31119 3.64758 7.21741 3.60825 7.14175 3.55445C7.06583 3.50047 6.99949 3.43413 6.94551 3.35821C6.89171 3.28255 6.85238 3.18877 6.72721 2.86334L5.88889 0.683718Z"
fill=
"#667085"
/>
</
svg
>
)
web/app/components/app/chat/index.tsx
View file @
23e34136
...
...
@@ -4,43 +4,25 @@ import React, { useEffect, useLayoutEffect, useRef, useState } from 'react'
import
{
useContext
}
from
'use-context-selector'
import
cn
from
'classnames'
import
Recorder
from
'js-audio-recorder'
import
{
HandThumbDownIcon
,
HandThumbUpIcon
}
from
'@heroicons/react/24/outline'
import
{
UserCircleIcon
}
from
'@heroicons/react/24/solid'
import
{
useTranslation
}
from
'react-i18next'
import
{
randomString
}
from
'../../app-sidebar/basic'
import
s
from
'./style.module.css'
import
LoadingAnim
from
'./loading-anim'
import
CopyBtn
from
'./copy-btn'
import
type
{
DisplayScene
,
FeedbackFunc
,
IChatItem
,
SubmitAnnotationFunc
}
from
'./type'
import
{
TryToAskIcon
,
stopIcon
}
from
'./icon-component'
import
Answer
from
'./answer'
import
Question
from
'./question'
import
Tooltip
from
'@/app/components/base/tooltip'
import
{
ToastContext
}
from
'@/app/components/base/toast'
import
AutoHeightTextarea
from
'@/app/components/base/auto-height-textarea'
import
Button
from
'@/app/components/base/button'
import
type
{
Annotation
,
MessageRating
}
from
'@/models/log'
import
AppContext
from
'@/context/app-context'
import
{
Markdown
}
from
'@/app/components/base/markdown'
import
{
formatNumber
}
from
'@/utils/format'
import
useBreakpoints
,
{
MediaType
}
from
'@/hooks/use-breakpoints'
import
VoiceInput
from
'@/app/components/base/voice-input'
import
{
Microphone01
}
from
'@/app/components/base/icons/src/vender/line/mediaAndDevices'
import
{
Microphone01
as
Microphone01Solid
}
from
'@/app/components/base/icons/src/vender/solid/mediaAndDevices'
import
{
XCircle
}
from
'@/app/components/base/icons/src/vender/solid/general'
const
stopIcon
=
(
<
svg
width=
"14"
height=
"14"
viewBox=
"0 0 14 14"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<
path
fillRule=
"evenodd"
clipRule=
"evenodd"
d=
"M7.00004 0.583313C3.45621 0.583313 0.583374 3.45615 0.583374 6.99998C0.583374 10.5438 3.45621 13.4166 7.00004 13.4166C10.5439 13.4166 13.4167 10.5438 13.4167 6.99998C13.4167 3.45615 10.5439 0.583313 7.00004 0.583313ZM4.73029 4.98515C4.66671 5.10993 4.66671 5.27328 4.66671 5.59998V8.39998C4.66671 8.72668 4.66671 8.89003 4.73029 9.01481C4.78621 9.12457 4.87545 9.21381 4.98521 9.26973C5.10999 9.33331 5.27334 9.33331 5.60004 9.33331H8.40004C8.72674 9.33331 8.89009 9.33331 9.01487 9.26973C9.12463 9.21381 9.21387 9.12457 9.2698 9.01481C9.33337 8.89003 9.33337 8.72668 9.33337 8.39998V5.59998C9.33337 5.27328 9.33337 5.10993 9.2698 4.98515C9.21387 4.87539 9.12463 4.78615 9.01487 4.73023C8.89009 4.66665 8.72674 4.66665 8.40004 4.66665H5.60004C5.27334 4.66665 5.10999 4.66665 4.98521 4.73023C4.87545 4.78615 4.78621 4.87539 4.73029 4.98515Z"
fill=
"#667085"
/>
</
svg
>
)
export
type
Feedbacktype
=
{
rating
:
MessageRating
content
?:
string
|
null
}
export
type
FeedbackFunc
=
(
messageId
:
string
,
feedback
:
Feedbacktype
)
=>
Promise
<
any
>
export
type
SubmitAnnotationFunc
=
(
messageId
:
string
,
content
:
string
)
=>
Promise
<
any
>
export
type
DisplayScene
=
'web'
|
'console'
import
type
{
DataSet
}
from
'@/models/datasets'
export
type
IChatProps
=
{
configElem
?:
React
.
ReactNode
chatList
:
IChatItem
[]
/**
* Whether to display the editing area and rating status
...
...
@@ -66,352 +48,12 @@ export type IChatProps = {
suggestionList
?:
string
[]
isShowSpeechToText
?:
boolean
answerIconClassName
?:
string
}
export
type
MessageMore
=
{
time
:
string
tokens
:
number
latency
:
number
|
string
}
export
type
IChatItem
=
{
id
:
string
content
:
string
/**
* Specific message type
*/
isAnswer
:
boolean
/**
* The user feedback result of this message
*/
feedback
?:
Feedbacktype
/**
* The admin feedback result of this message
*/
adminFeedback
?:
Feedbacktype
/**
* Whether to hide the feedback area
*/
feedbackDisabled
?:
boolean
/**
* More information about this message
*/
more
?:
MessageMore
annotation
?:
Annotation
useCurrentUserAvatar
?:
boolean
isOpeningStatement
?:
boolean
}
const
OperationBtn
=
({
innerContent
,
onClick
,
className
}:
{
innerContent
:
React
.
ReactNode
;
onClick
?:
()
=>
void
;
className
?:
string
})
=>
(
<
div
className=
{
`relative box-border flex items-center justify-center h-7 w-7 p-0.5 rounded-lg bg-white cursor-pointer text-gray-500 hover:text-gray-800 ${className ?? ''}`
}
style=
{
{
boxShadow
:
'0px 4px 6px -1px rgba(0, 0, 0, 0.1), 0px 2px 4px -2px rgba(0, 0, 0, 0.05)'
}
}
onClick=
{
onClick
&&
onClick
}
>
{
innerContent
}
</
div
>
)
const
MoreInfo
:
FC
<
{
more
:
MessageMore
;
isQuestion
:
boolean
}
>
=
({
more
,
isQuestion
})
=>
{
const
{
t
}
=
useTranslation
()
return
(<
div
className=
{
`mt-1 space-x-2 text-xs text-gray-400 ${isQuestion ? 'mr-2 text-right ' : 'ml-2 text-left float-right'}`
}
>
<
span
>
{
`${t('appLog.detail.timeConsuming')} ${more.latency}${t('appLog.detail.second')}`
}
</
span
>
<
span
>
{
`${t('appLog.detail.tokenCost')} ${formatNumber(more.tokens)}`
}
</
span
>
<
span
>
·
</
span
>
<
span
>
{
more
.
time
}
</
span
>
</
div
>)
}
const
OpeningStatementIcon
:
FC
<
{
className
?:
string
}
>
=
({
className
})
=>
(
<
svg
width=
"12"
height=
"12"
viewBox=
"0 0 12 12"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<
path
fillRule=
"evenodd"
clipRule=
"evenodd"
d=
"M6.25002 1C3.62667 1 1.50002 3.12665 1.50002 5.75C1.50002 6.28 1.58702 6.79071 1.7479 7.26801C1.7762 7.35196 1.79285 7.40164 1.80368 7.43828L1.80722 7.45061L1.80535 7.45452C1.79249 7.48102 1.77339 7.51661 1.73766 7.58274L0.911727 9.11152C0.860537 9.20622 0.807123 9.30503 0.770392 9.39095C0.733879 9.47635 0.674738 9.63304 0.703838 9.81878C0.737949 10.0365 0.866092 10.2282 1.05423 10.343C1.21474 10.4409 1.38213 10.4461 1.475 10.4451C1.56844 10.444 1.68015 10.4324 1.78723 10.4213L4.36472 10.1549C4.406 10.1506 4.42758 10.1484 4.44339 10.1472L4.44542 10.147L4.45161 10.1492C4.47103 10.1562 4.49738 10.1663 4.54285 10.1838C5.07332 10.3882 5.64921 10.5 6.25002 10.5C8.87338 10.5 11 8.37335 11 5.75C11 3.12665 8.87338 1 6.25002 1ZM4.48481 4.29111C5.04844 3.81548 5.7986 3.9552 6.24846 4.47463C6.69831 3.9552 7.43879 3.82048 8.01211 4.29111C8.58544 4.76175 8.6551 5.562 8.21247 6.12453C7.93825 6.47305 7.24997 7.10957 6.76594 7.54348C6.58814 7.70286 6.49924 7.78255 6.39255 7.81466C6.30103 7.84221 6.19589 7.84221 6.10436 7.81466C5.99767 7.78255 5.90878 7.70286 5.73098 7.54348C5.24694 7.10957 4.55867 6.47305 4.28444 6.12453C3.84182 5.562 3.92117 4.76675 4.48481 4.29111Z"
fill=
"#667085"
/>
</
svg
>
)
const
RatingIcon
:
FC
<
{
isLike
:
boolean
}
>
=
({
isLike
})
=>
{
return
isLike
?
<
HandThumbUpIcon
className=
'w-4 h-4'
/>
:
<
HandThumbDownIcon
className=
'w-4 h-4'
/>
}
const
EditIcon
:
FC
<
{
className
?:
string
}
>
=
({
className
})
=>
{
return
<
svg
width=
"16"
height=
"16"
viewBox=
"0 0 16 16"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
className=
{
className
}
>
<
path
d=
"M14 11.9998L13.3332 12.7292C12.9796 13.1159 12.5001 13.3332 12.0001 13.3332C11.5001 13.3332 11.0205 13.1159 10.6669 12.7292C10.3128 12.3432 9.83332 12.1265 9.33345 12.1265C8.83359 12.1265 8.35409 12.3432 7.99998 12.7292M2 13.3332H3.11636C3.44248 13.3332 3.60554 13.3332 3.75899 13.2963C3.89504 13.2637 4.0251 13.2098 4.1444 13.1367C4.27895 13.0542 4.39425 12.9389 4.62486 12.7083L13 4.33316C13.5523 3.78087 13.5523 2.88544 13 2.33316C12.4477 1.78087 11.5523 1.78087 11 2.33316L2.62484 10.7083C2.39424 10.9389 2.27894 11.0542 2.19648 11.1888C2.12338 11.3081 2.0695 11.4381 2.03684 11.5742C2 11.7276 2 11.8907 2 12.2168V13.3332Z"
stroke=
"#6B7280"
strokeLinecap=
"round"
strokeLinejoin=
"round"
/>
</
svg
>
}
export
const
EditIconSolid
:
FC
<
{
className
?:
string
}
>
=
({
className
})
=>
{
return
<
svg
width=
"12"
height=
"12"
viewBox=
"0 0 12 12"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
className=
{
className
}
>
<
path
fillRule=
"evenodd"
clipRule=
"evenodd"
d=
"M10.8374 8.63108C11.0412 8.81739 11.0554 9.13366 10.8691 9.33747L10.369 9.88449C10.0142 10.2725 9.52293 10.5001 9.00011 10.5001C8.47746 10.5001 7.98634 10.2727 7.63157 9.8849C7.45561 9.69325 7.22747 9.59515 7.00014 9.59515C6.77271 9.59515 6.54446 9.69335 6.36846 9.88517C6.18177 10.0886 5.86548 10.1023 5.66201 9.91556C5.45853 9.72888 5.44493 9.41259 5.63161 9.20911C5.98678 8.82201 6.47777 8.59515 7.00014 8.59515C7.52251 8.59515 8.0135 8.82201 8.36867 9.20911L8.36924 9.20974C8.54486 9.4018 8.77291 9.50012 9.00011 9.50012C9.2273 9.50012 9.45533 9.40182 9.63095 9.20979L10.131 8.66276C10.3173 8.45895 10.6336 8.44476 10.8374 8.63108Z"
fill=
"#6B7280"
/>
<
path
fillRule=
"evenodd"
clipRule=
"evenodd"
d=
"M7.89651 1.39656C8.50599 0.787085 9.49414 0.787084 10.1036 1.39656C10.7131 2.00604 10.7131 2.99419 10.1036 3.60367L3.82225 9.88504C3.81235 9.89494 3.80254 9.90476 3.79281 9.91451C3.64909 10.0585 3.52237 10.1855 3.3696 10.2791C3.23539 10.3613 3.08907 10.4219 2.93602 10.4587C2.7618 10.5005 2.58242 10.5003 2.37897 10.5001C2.3652 10.5001 2.35132 10.5001 2.33732 10.5001H1.50005C1.22391 10.5001 1.00005 10.2763 1.00005 10.0001V9.16286C1.00005 9.14886 1.00004 9.13497 1.00003 9.1212C0.999836 8.91776 0.999669 8.73838 1.0415 8.56416C1.07824 8.4111 1.13885 8.26479 1.22109 8.13058C1.31471 7.97781 1.44166 7.85109 1.58566 7.70736C1.5954 7.69764 1.60523 7.68783 1.61513 7.67793L7.89651 1.39656Z"
fill=
"#6B7280"
/>
</
svg
>
}
const
TryToAskIcon
=
(
<
svg
width=
"11"
height=
"10"
viewBox=
"0 0 11 10"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<
path
d=
"M5.88889 0.683718C5.827 0.522805 5.67241 0.416626 5.5 0.416626C5.3276 0.416626 5.173 0.522805 5.11111 0.683718L4.27279 2.86334C4.14762 3.18877 4.10829 3.28255 4.05449 3.35821C4.00051 3.43413 3.93418 3.50047 3.85826 3.55445C3.78259 3.60825 3.68881 3.64758 3.36338 3.77275L1.18376 4.61106C1.02285 4.67295 0.916668 4.82755 0.916668 4.99996C0.916668 5.17236 1.02285 5.32696 1.18376 5.38885L3.36338 6.22717C3.68881 6.35234 3.78259 6.39167 3.85826 6.44547C3.93418 6.49945 4.00051 6.56578 4.05449 6.6417C4.10829 6.71737 4.14762 6.81115 4.27279 7.13658L5.11111 9.3162C5.173 9.47711 5.3276 9.58329 5.5 9.58329C5.67241 9.58329 5.82701 9.47711 5.8889 9.3162L6.72721 7.13658C6.85238 6.81115 6.89171 6.71737 6.94551 6.6417C6.99949 6.56578 7.06583 6.49945 7.14175 6.44547C7.21741 6.39167 7.31119 6.35234 7.63662 6.22717L9.81624 5.38885C9.97715 5.32696 10.0833 5.17236 10.0833 4.99996C10.0833 4.82755 9.97715 4.67295 9.81624 4.61106L7.63662 3.77275C7.31119 3.64758 7.21741 3.60825 7.14175 3.55445C7.06583 3.50047 6.99949 3.43413 6.94551 3.35821C6.89171 3.28255 6.85238 3.18877 6.72721 2.86334L5.88889 0.683718Z"
fill=
"#667085"
/>
</
svg
>
)
const
Divider
:
FC
<
{
name
:
string
}
>
=
({
name
})
=>
{
const
{
t
}
=
useTranslation
()
return
<
div
className=
'flex items-center my-2'
>
<
span
className=
'text-xs text-gray-500 inline-flex items-center mr-2'
>
<
EditIconSolid
className=
'mr-1'
/>
{
t
(
'appLog.detail.annotationTip'
,
{
user
:
name
})
}
</
span
>
<
div
className=
'h-[1px] bg-gray-200 flex-1'
></
div
>
</
div
>
}
const
IconWrapper
:
FC
<
{
children
:
React
.
ReactNode
|
string
}
>
=
({
children
})
=>
{
return
<
div
className=
{
'rounded-lg h-6 w-6 flex items-center justify-center hover:bg-gray-100'
}
>
{
children
}
</
div
>
}
type
IAnswerProps
=
{
item
:
IChatItem
feedbackDisabled
:
boolean
isHideFeedbackEdit
:
boolean
onFeedback
?:
FeedbackFunc
onSubmitAnnotation
?:
SubmitAnnotationFunc
displayScene
:
DisplayScene
isResponsing
?:
boolean
answerIconClassName
?:
string
}
// 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
})
=>
{
const
{
id
,
content
,
more
,
feedback
,
adminFeedback
,
annotation
:
initAnnotation
}
=
item
const
[
showEdit
,
setShowEdit
]
=
useState
(
false
)
const
[
loading
,
setLoading
]
=
useState
(
false
)
const
[
annotation
,
setAnnotation
]
=
useState
<
Annotation
|
undefined
|
null
>
(
initAnnotation
)
const
[
inputValue
,
setInputValue
]
=
useState
<
string
>
(
initAnnotation
?.
content
??
''
)
const
[
localAdminFeedback
,
setLocalAdminFeedback
]
=
useState
<
Feedbacktype
|
undefined
|
null
>
(
adminFeedback
)
const
{
userProfile
}
=
useContext
(
AppContext
)
const
{
t
}
=
useTranslation
()
/**
* Render feedback results (distinguish between users and administrators)
* User reviews cannot be cancelled in Console
* @param rating feedback result
* @param isUserFeedback Whether it is user's feedback
* @param isWebScene Whether it is web scene
* @returns comp
*/
const
renderFeedbackRating
=
(
rating
:
MessageRating
|
undefined
,
isUserFeedback
=
true
,
isWebScene
=
true
)
=>
{
if
(
!
rating
)
return
null
const
isLike
=
rating
===
'like'
const
ratingIconClassname
=
isLike
?
'text-primary-600 bg-primary-100 hover:bg-primary-200'
:
'text-red-600 bg-red-100 hover:bg-red-200'
const
UserSymbol
=
<
UserCircleIcon
className=
'absolute top-[-2px] left-[18px] w-3 h-3 rounded-lg text-gray-400 bg-white'
/>
// The tooltip is always displayed, but the content is different for different scenarios.
return
(
<
Tooltip
selector=
{
`user-feedback-${randomString(16)}`
}
content=
{
((
isWebScene
||
(
!
isUserFeedback
&&
!
isWebScene
))
?
isLike
?
t
(
'appDebug.operation.cancelAgree'
)
:
t
(
'appDebug.operation.cancelDisagree'
)
:
(
!
isWebScene
&&
isUserFeedback
)
?
`${t('appDebug.operation.userAction')}${isLike ? t('appDebug.operation.agree') : t('appDebug.operation.disagree')}`
:
''
)
as
string
}
>
<
div
className=
{
`relative box-border flex items-center justify-center h-7 w-7 p-0.5 rounded-lg bg-white cursor-pointer text-gray-500 hover:text-gray-800 ${(!isWebScene && isUserFeedback) ? '!cursor-default' : ''}`
}
style=
{
{
boxShadow
:
'0px 4px 6px -1px rgba(0, 0, 0, 0.1), 0px 2px 4px -2px rgba(0, 0, 0, 0.05)'
}
}
{
...
((
isWebScene
||
(!
isUserFeedback
&&
!
isWebScene
))
?
{
onClick
:
async
()
=
>
{
const
res
=
await
onFeedback
?.(
id
,
{
rating
:
null
})
if
(
res
&&
!
isWebScene
)
setLocalAdminFeedback
({
rating
:
null
})
}
,
}
:
{}
)}
>
<
div
className=
{
`${ratingIconClassname} rounded-lg h-6 w-6 flex items-center justify-center`
}
>
<
RatingIcon
isLike=
{
isLike
}
/>
</
div
>
{
!
isWebScene
&&
isUserFeedback
&&
UserSymbol
}
</
div
>
</
Tooltip
>
)
}
/**
* Different scenarios have different operation items.
* @param isWebScene Whether it is web scene
* @returns comp
*/
const
renderItemOperation
=
(
isWebScene
=
true
)
=>
{
const
userOperation
=
()
=>
{
return
feedback
?.
rating
?
null
:
<
div
className=
'flex gap-1'
>
<
Tooltip
selector=
{
`user-feedback-${randomString(16)}`
}
content=
{
t
(
'appLog.detail.operation.like'
)
as
string
}
>
{
OperationBtn
({
innerContent
:
<
IconWrapper
><
RatingIcon
isLike=
{
true
}
/></
IconWrapper
>,
onClick
:
()
=>
onFeedback
?.(
id
,
{
rating
:
'like'
})
})
}
</
Tooltip
>
<
Tooltip
selector=
{
`user-feedback-${randomString(16)}`
}
content=
{
t
(
'appLog.detail.operation.dislike'
)
as
string
}
>
{
OperationBtn
({
innerContent
:
<
IconWrapper
><
RatingIcon
isLike=
{
false
}
/></
IconWrapper
>,
onClick
:
()
=>
onFeedback
?.(
id
,
{
rating
:
'dislike'
})
})
}
</
Tooltip
>
</
div
>
}
const
adminOperation
=
()
=>
{
return
<
div
className=
'flex gap-1'
>
<
Tooltip
selector=
{
`user-feedback-${randomString(16)}`
}
content=
{
t
(
'appLog.detail.operation.addAnnotation'
)
as
string
}
>
{
OperationBtn
({
innerContent
:
<
IconWrapper
><
EditIcon
className=
'hover:text-gray-800'
/></
IconWrapper
>,
onClick
:
()
=>
setShowEdit
(
true
),
})
}
</
Tooltip
>
{
!
localAdminFeedback
?.
rating
&&
<>
<
Tooltip
selector=
{
`user-feedback-${randomString(16)}`
}
content=
{
t
(
'appLog.detail.operation.like'
)
as
string
}
>
{
OperationBtn
({
innerContent
:
<
IconWrapper
><
RatingIcon
isLike=
{
true
}
/></
IconWrapper
>,
onClick
:
async
()
=>
{
const
res
=
await
onFeedback
?.(
id
,
{
rating
:
'like'
})
if
(
res
)
setLocalAdminFeedback
({
rating
:
'like'
})
},
})
}
</
Tooltip
>
<
Tooltip
selector=
{
`user-feedback-${randomString(16)}`
}
content=
{
t
(
'appLog.detail.operation.dislike'
)
as
string
}
>
{
OperationBtn
({
innerContent
:
<
IconWrapper
><
RatingIcon
isLike=
{
false
}
/></
IconWrapper
>,
onClick
:
async
()
=>
{
const
res
=
await
onFeedback
?.(
id
,
{
rating
:
'dislike'
})
if
(
res
)
setLocalAdminFeedback
({
rating
:
'dislike'
})
},
})
}
</
Tooltip
>
</>
}
</
div
>
}
return
(
<
div
className=
{
`${s.itemOperation} flex gap-2`
}
>
{
isWebScene
?
userOperation
()
:
adminOperation
()
}
</
div
>
)
}
return
(
<
div
key=
{
id
}
>
<
div
className=
'flex items-start'
>
<
div
className=
{
`${s.answerIcon} ${answerIconClassName} w-10 h-10 shrink-0`
}
>
{
isResponsing
&&
<
div
className=
{
s
.
typeingIcon
}
>
<
LoadingAnim
type=
'avatar'
/>
</
div
>
}
</
div
>
<
div
className=
{
s
.
answerWrapWrap
}
>
<
div
className=
{
`${s.answerWrap} ${showEdit ? 'w-full' : ''}`
}
>
<
div
className=
{
`${s.answer} relative text-sm text-gray-900`
}
>
<
div
className=
{
'ml-2 py-3 px-4 bg-gray-100 rounded-tr-2xl rounded-b-2xl'
}
>
{
item
.
isOpeningStatement
&&
(
<
div
className=
'flex items-center mb-1 gap-1'
>
<
OpeningStatementIcon
/>
<
div
className=
'text-xs text-gray-500'
>
{
t
(
'appDebug.openingStatement.title'
)
}
</
div
>
</
div
>
)
}
{
(
isResponsing
&&
!
content
)
?
(
<
div
className=
'flex items-center justify-center w-6 h-5'
>
<
LoadingAnim
type=
'text'
/>
</
div
>
)
:
(
<
Markdown
content=
{
content
}
/>
)
}
{
!
showEdit
?
(
annotation
?.
content
&&
<>
<
Divider
name=
{
annotation
?.
account
?.
name
||
userProfile
?.
name
}
/>
{
annotation
.
content
}
</>)
:
<>
<
Divider
name=
{
annotation
?.
account
?.
name
||
userProfile
?.
name
}
/>
<
AutoHeightTextarea
placeholder=
{
t
(
'appLog.detail.operation.annotationPlaceholder'
)
as
string
}
value=
{
inputValue
}
onChange=
{
e
=>
setInputValue
(
e
.
target
.
value
)
}
minHeight=
{
58
}
className=
{
`${cn(s.textArea)} !py-2 resize-none block w-full !px-3 bg-gray-50 border border-gray-200 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm text-gray-700 tracking-[0.2px]`
}
/>
<
div
className=
"mt-2 flex flex-row"
>
<
Button
type=
'primary'
className=
'mr-2'
loading=
{
loading
}
onClick=
{
async
()
=>
{
if
(
!
inputValue
)
return
setLoading
(
true
)
const
res
=
await
onSubmitAnnotation
?.(
id
,
inputValue
)
if
(
res
)
setAnnotation
({
...
annotation
,
content
:
inputValue
}
as
any
)
setLoading
(
false
)
setShowEdit
(
false
)
}
}
>
{
t
(
'common.operation.confirm'
)
}
</
Button
>
<
Button
onClick=
{
()
=>
{
setInputValue
(
annotation
?.
content
??
''
)
setShowEdit
(
false
)
}
}
>
{
t
(
'common.operation.cancel'
)
}
</
Button
>
</
div
>
</>
}
</
div
>
<
div
className=
'absolute top-[-14px] right-[-14px] flex flex-row justify-end gap-1'
>
{
!
item
.
isOpeningStatement
&&
(
<
CopyBtn
value=
{
content
}
className=
{
cn
(
s
.
copyBtn
,
'mr-1'
)
}
/>
)
}
{
!
feedbackDisabled
&&
!
item
.
feedbackDisabled
&&
renderItemOperation
(
displayScene
!==
'console'
)
}
{
/* Admin feedback is displayed only in the background. */
}
{
!
feedbackDisabled
&&
renderFeedbackRating
(
localAdminFeedback
?.
rating
,
false
,
false
)
}
{
/* User feedback must be displayed */
}
{
!
feedbackDisabled
&&
renderFeedbackRating
(
feedback
?.
rating
,
!
isHideFeedbackEdit
,
displayScene
!==
'console'
)
}
</
div
>
</
div
>
{
more
&&
<
MoreInfo
more=
{
more
}
isQuestion=
{
false
}
/>
}
</
div
>
</
div
>
</
div
>
</
div
>
)
}
type
IQuestionProps
=
Pick
<
IChatItem
,
'id'
|
'content'
|
'more'
|
'useCurrentUserAvatar'
>
const
Question
:
FC
<
IQuestionProps
>
=
({
id
,
content
,
more
,
useCurrentUserAvatar
})
=>
{
const
{
userProfile
}
=
useContext
(
AppContext
)
const
userName
=
userProfile
?.
name
return
(
<
div
className=
'flex items-start justify-end'
key=
{
id
}
>
<
div
className=
{
s
.
questionWrapWrap
}
>
<
div
className=
{
`${s.question} relative text-sm text-gray-900`
}
>
<
div
className=
{
'mr-2 py-3 px-4 bg-blue-500 rounded-tl-2xl rounded-b-2xl'
}
>
<
Markdown
content=
{
content
}
/>
</
div
>
</
div
>
{
more
&&
<
MoreInfo
more=
{
more
}
isQuestion=
{
true
}
/>
}
</
div
>
{
useCurrentUserAvatar
?
(
<
div
className=
'w-10 h-10 shrink-0 leading-10 text-center mr-2 rounded-full bg-primary-600 text-white'
>
{
userName
?.[
0
].
toLocaleUpperCase
()
}
</
div
>
)
:
(
<
div
className=
{
`${s.questionIcon} w-10 h-10 shrink-0 `
}
></
div
>
)
}
</
div
>
)
isShowConfigElem
?:
boolean
dataSets
?:
DataSet
[]
}
const
Chat
:
FC
<
IChatProps
>
=
({
configElem
,
chatList
,
feedbackDisabled
=
false
,
isHideFeedbackEdit
=
false
,
...
...
@@ -431,6 +73,8 @@ const Chat: FC<IChatProps> = ({
suggestionList
,
isShowSpeechToText
,
answerIconClassName
,
isShowConfigElem
,
dataSets
,
})
=>
{
const
{
t
}
=
useTranslation
()
const
{
notify
}
=
useContext
(
ToastContext
)
...
...
@@ -509,11 +153,14 @@ const Chat: FC<IChatProps> = ({
return
(
<
div
className=
{
cn
(
'px-3.5'
,
'h-full'
)
}
>
{
isShowConfigElem
&&
(
configElem
||
null
)
}
{
/* Chat List */
}
<
div
className=
"h-full space-y-[30px]"
>
<
div
className=
{
cn
((
isShowConfigElem
&&
configElem
)
?
'h-0'
:
'h-full'
,
'space-y-[30px]'
)
}
>
{
chatList
.
map
((
item
)
=>
{
if
(
item
.
isAnswer
)
{
const
isLast
=
item
.
id
===
chatList
[
chatList
.
length
-
1
].
id
const
thoughts
=
item
.
agent_thoughts
?.
filter
(
item
=>
item
.
thought
!==
'[DONE]'
)
const
isThinking
=
!
item
.
content
&&
item
.
agent_thoughts
&&
item
.
agent_thoughts
?.
length
>
0
&&
!
item
.
agent_thoughts
.
some
(
item
=>
item
.
thought
===
'[DONE]'
)
return
<
Answer
key=
{
item
.
id
}
item=
{
item
}
...
...
@@ -524,6 +171,9 @@ const Chat: FC<IChatProps> = ({
displayScene=
{
displayScene
??
'web'
}
isResponsing=
{
isResponsing
&&
isLast
}
answerIconClassName=
{
answerIconClassName
}
thoughts=
{
thoughts
}
isThinking=
{
isThinking
}
dataSets=
{
dataSets
}
/>
}
return
<
Question
key=
{
item
.
id
}
id=
{
item
.
id
}
content=
{
item
.
content
}
more=
{
item
.
more
}
useCurrentUserAvatar=
{
useCurrentUserAvatar
}
/>
...
...
@@ -532,7 +182,8 @@ const Chat: FC<IChatProps> = ({
{
!
isHideSendInput
&&
(
<
div
className=
{
cn
(
!
feedbackDisabled
&&
'!left-3.5 !right-3.5'
,
'absolute z-10 bottom-0 left-0 right-0'
)
}
>
{
(
isResponsing
&&
canStopResponsing
)
&&
(
{
/* Thinking is sync and can not be stopped */
}
{
(
isResponsing
&&
canStopResponsing
&&
!!
chatList
[
chatList
.
length
-
1
]?.
content
)
&&
(
<
div
className=
'flex justify-center mb-4'
>
<
Button
className=
'flex items-center space-x-1 bg-white'
onClick=
{
()
=>
abortResponsing
?.()
}
>
{
stopIcon
}
...
...
@@ -560,7 +211,7 @@ const Chat: FC<IChatProps> = ({
{
/* has scrollbar would hide part of first item */
}
<
div
ref=
{
suggestionListRef
}
className=
{
cn
(
!
hasScrollbar
&&
'justify-center'
,
'flex overflow-x-auto pb-2'
)
}
>
{
suggestionList
?.
map
((
item
,
index
)
=>
(
<
div
className=
'shrink-0 flex justify-center mr-2'
>
<
div
key=
{
item
}
className=
'shrink-0 flex justify-center mr-2'
>
<
Button
key=
{
index
}
onClick=
{
()
=>
setQuery
(
item
)
}
...
...
web/app/components/app/chat/more-info/index.tsx
0 → 100644
View file @
23e34136
'use client'
import
type
{
FC
}
from
'react'
import
React
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
type
{
MessageMore
}
from
'../type'
import
{
formatNumber
}
from
'@/utils/format'
export
type
IMoreInfoProps
=
{
more
:
MessageMore
;
isQuestion
:
boolean
}
const
MoreInfo
:
FC
<
IMoreInfoProps
>
=
({
more
,
isQuestion
})
=>
{
const
{
t
}
=
useTranslation
()
return
(<
div
className=
{
`mt-1 space-x-2 text-xs text-gray-400 ${isQuestion ? 'mr-2 text-right ' : 'ml-2 text-left float-right'}`
}
>
<
span
>
{
`${t('appLog.detail.timeConsuming')} ${more.latency}${t('appLog.detail.second')}`
}
</
span
>
<
span
>
{
`${t('appLog.detail.tokenCost')} ${formatNumber(more.tokens)}`
}
</
span
>
<
span
>
·
</
span
>
<
span
>
{
more
.
time
}
</
span
>
</
div
>)
}
export
default
React
.
memo
(
MoreInfo
)
web/app/components/app/chat/operation/index.tsx
0 → 100644
View file @
23e34136
'use client'
import
React
from
'react'
const
OperationBtn
=
({
innerContent
,
onClick
,
className
}:
{
innerContent
:
React
.
ReactNode
;
onClick
?:
()
=>
void
;
className
?:
string
})
=>
(
<
div
className=
{
`relative box-border flex items-center justify-center h-7 w-7 p-0.5 rounded-lg bg-white cursor-pointer text-gray-500 hover:text-gray-800 ${className ?? ''}`
}
style=
{
{
boxShadow
:
'0px 4px 6px -1px rgba(0, 0, 0, 0.1), 0px 2px 4px -2px rgba(0, 0, 0, 0.05)'
}
}
onClick=
{
onClick
&&
onClick
}
>
{
innerContent
}
</
div
>
)
export
default
OperationBtn
web/app/components/app/chat/question/index.tsx
0 → 100644
View file @
23e34136
'use client'
import
type
{
FC
}
from
'react'
import
React
from
'react'
import
{
useContext
}
from
'use-context-selector'
import
s
from
'../style.module.css'
import
type
{
IChatItem
}
from
'../type'
import
MoreInfo
from
'../more-info'
import
AppContext
from
'@/context/app-context'
import
{
Markdown
}
from
'@/app/components/base/markdown'
type
IQuestionProps
=
Pick
<
IChatItem
,
'id'
|
'content'
|
'more'
|
'useCurrentUserAvatar'
>
const
Question
:
FC
<
IQuestionProps
>
=
({
id
,
content
,
more
,
useCurrentUserAvatar
})
=>
{
const
{
userProfile
}
=
useContext
(
AppContext
)
const
userName
=
userProfile
?.
name
return
(
<
div
className=
'flex items-start justify-end'
key=
{
id
}
>
<
div
className=
{
s
.
questionWrapWrap
}
>
<
div
className=
{
`${s.question} relative text-sm text-gray-900`
}
>
<
div
className=
{
'mr-2 py-3 px-4 bg-blue-500 rounded-tl-2xl rounded-b-2xl'
}
>
<
Markdown
content=
{
content
}
/>
</
div
>
</
div
>
{
more
&&
<
MoreInfo
more=
{
more
}
isQuestion=
{
true
}
/>
}
</
div
>
{
useCurrentUserAvatar
?
(
<
div
className=
'w-10 h-10 shrink-0 leading-10 text-center mr-2 rounded-full bg-primary-600 text-white'
>
{
userName
?.[
0
].
toLocaleUpperCase
()
}
</
div
>
)
:
(
<
div
className=
{
`${s.questionIcon} w-10 h-10 shrink-0 `
}
></
div
>
)
}
</
div
>
)
}
export
default
React
.
memo
(
Question
)
web/app/components/app/chat/thought/index.tsx
0 → 100644
View file @
23e34136
'use client'
import
type
{
FC
}
from
'react'
import
React
from
'react'
import
cn
from
'classnames'
import
{
useTranslation
}
from
'react-i18next'
import
type
{
ThoughtItem
}
from
'../type'
import
s
from
'./style.module.css'
import
{
DataSet
as
DataSetIcon
,
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
type
{
DataSet
}
from
'@/models/datasets'
export
type
IThoughtProps
=
{
list
:
ThoughtItem
[]
isThinking
?:
boolean
dataSets
?:
DataSet
[]
}
const
getIcon
=
(
toolId
:
string
)
=>
{
switch
(
toolId
)
{
case
'dataset'
:
return
<
DataSetIcon
/>
case
'web_reader'
:
return
<
WebReader
/>
default
:
return
<
Search
/>
}
}
const
Thought
:
FC
<
IThoughtProps
>
=
({
list
,
isThinking
,
dataSets
,
})
=>
{
const
{
t
}
=
useTranslation
()
const
[
isShowDetail
,
setIsShowDetail
]
=
React
.
useState
(
false
)
const
getThoughtText
=
(
item
:
ThoughtItem
)
=>
{
try
{
const
input
=
JSON
.
parse
(
item
.
tool_input
)
switch
(
item
.
tool
)
{
case
'dataset'
:
// eslint-disable-next-line no-case-declarations
const
datasetName
=
dataSets
?.
find
(
item
=>
item
.
id
===
input
.
dataset_id
)?.
name
||
'unknown dataset'
return
t
(
'explore.universalChat.thought.res.dataset'
).
replace
(
'{datasetName}'
,
`<span class="text-gray-700">
${
datasetName
}
</span>`
)
case
'web_reader'
:
return
t
(
`explore.universalChat.thought.res.webReader.
${
!
input
.
cursor
?
'normal'
:
'hasPageInfo'
}
`
).
replace
(
'{url}'
,
`<a href="
${
input
.
url
}
" class="text-[#155EEF]">
${
input
.
url
}
</a>`
)
default
:
// google, wikipedia
return
t
(
'explore.universalChat.thought.res.search'
,
{
query
:
input
.
query
})
}
}
catch
(
error
)
{
console
.
error
(
error
)
return
item
}
}
const
renderItem
=
(
item
:
ThoughtItem
)
=>
(
<
div
className=
'flex space-x-1 py-[3px] leading-[18px]'
key=
{
item
.
id
}
>
<
div
className=
'flex items-center h-[18px] shrink-0'
>
{
getIcon
(
item
.
tool
)
}
</
div
>
<
div
dangerouslySetInnerHTML=
{
{
__html
:
getThoughtText
(
item
),
// item.thought.replace(urlRegex, (url) =>
{
// return `<a href="$
{
url
}
" class="
text
-
[
#
155
EEF
]
">${url}</a>`
// }),
}
}
></
div
>
</
div
>
)
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=
'flex items-center h-6 space-x-1 cursor-pointer'
onClick=
{
()
=>
setIsShowDetail
(
!
isShowDetail
)
}
>
{
!
isThinking
?
<
ThoughtList
/>
:
<
div
className=
'animate-spin'
><
LodingIcon
/></
div
>
}
<
div
dangerouslySetInnerHTML=
{
{
__html
:
isThinking
?
getThoughtText
(
list
[
list
.
length
-
1
])
:
(
t
(
`explore.universalChat.thought.${isShowDetail ? 'hide' : 'show'}`
)
+
t
(
'explore.universalChat.thought.processOfThought'
)),
}
}
></
div
>
<
ChevronDown
className=
{
isShowDetail
?
'rotate-180'
:
''
}
/>
</
div
>
{
isShowDetail
&&
(
<
div
>
{
list
.
map
(
item
=>
renderItem
(
item
))
}
</
div
>
)
}
</
div
>
)
}
export
default
React
.
memo
(
Thought
)
web/app/components/app/chat/thought/style.module.css
0 → 100644
View file @
23e34136
.wrap
{
background-color
:
rgba
(
255
,
255
,
255
,
0.92
);
}
.wrapHoverEffect
:hover
{
box-shadow
:
0px
1px
2px
0px
rgba
(
16
,
24
,
40
,
0.06
),
0px
1px
3px
0px
rgba
(
16
,
24
,
40
,
0.1
);
}
\ No newline at end of file
web/app/components/app/chat/type.ts
0 → 100644
View file @
23e34136
import
type
{
Annotation
,
MessageRating
}
from
'@/models/log'
export
type
MessageMore
=
{
time
:
string
tokens
:
number
latency
:
number
|
string
}
export
type
Feedbacktype
=
{
rating
:
MessageRating
content
?:
string
|
null
}
export
type
FeedbackFunc
=
(
messageId
:
string
,
feedback
:
Feedbacktype
)
=>
Promise
<
any
>
export
type
SubmitAnnotationFunc
=
(
messageId
:
string
,
content
:
string
)
=>
Promise
<
any
>
export
type
DisplayScene
=
'web'
|
'console'
export
type
ThoughtItem
=
{
id
:
string
tool
:
string
// plugin or dataset
thought
:
string
tool_input
:
string
message_id
:
string
}
export
type
IChatItem
=
{
id
:
string
content
:
string
agent_thoughts
?:
ThoughtItem
[]
/**
* Specific message type
*/
isAnswer
:
boolean
/**
* The user feedback result of this message
*/
feedback
?:
Feedbacktype
/**
* The admin feedback result of this message
*/
adminFeedback
?:
Feedbacktype
/**
* Whether to hide the feedback area
*/
feedbackDisabled
?:
boolean
/**
* More information about this message
*/
more
?:
MessageMore
annotation
?:
Annotation
useCurrentUserAvatar
?:
boolean
isOpeningStatement
?:
boolean
}
web/app/components/app/configuration/base/feature-panel/index.tsx
View file @
23e34136
'use client'
import
React
,
{
FC
,
ReactNode
}
from
'react'
import
type
{
FC
,
ReactNode
}
from
'react'
import
React
from
'react'
import
cn
from
'classnames'
export
interface
IFeaturePanelProps
{
export
type
IFeaturePanelProps
=
{
className
?:
string
headerIcon
:
ReactNode
headerIcon
?
:
ReactNode
title
:
ReactNode
headerRight
:
ReactNode
headerRight
?
:
ReactNode
hasHeaderBottomBorder
?:
boolean
isFocus
?:
boolean
noBodySpacing
?:
boolean
...
...
@@ -26,15 +27,17 @@ const FeaturePanel: FC<IFeaturePanelProps> = ({
return
(
<
div
className=
{
cn
(
className
,
isFocus
&&
'border border-[#2D0DEE]'
,
'rounded-xl bg-gray-50 pt-2 pb-3'
,
noBodySpacing
&&
'!pb-0'
)
}
style=
{
isFocus
?
{
boxShadow
:
'0px 4px 8px -2px rgba(16, 24, 40, 0.1), 0px 2px 4px -2px rgba(16, 24, 40, 0.06)'
,
}
:
{}
}
style=
{
isFocus
?
{
boxShadow
:
'0px 4px 8px -2px rgba(16, 24, 40, 0.1), 0px 2px 4px -2px rgba(16, 24, 40, 0.06)'
,
}
:
{}
}
>
{
/* Header */
}
<
div
className=
{
cn
(
'pb-2 px-3'
,
hasHeaderBottomBorder
&&
'border-b border-gray-100'
)
}
>
<
div
className=
'flex justify-between items-center h-8'
>
<
div
className=
'flex items-center space-x-1 shrink-0'
>
<
div
className=
'flex items-center justify-center w-4 h-4'
>
{
headerIcon
}
</
div
>
{
headerIcon
&&
<
div
className=
'flex items-center justify-center w-4 h-4'
>
{
headerIcon
}
</
div
>
}
<
div
className=
'text-sm font-semibold text-gray-800'
>
{
title
}
</
div
>
</
div
>
<
div
>
...
...
web/app/components/app/configuration/config-model/index.tsx
View file @
23e34136
...
...
@@ -6,15 +6,15 @@ import { useTranslation } from 'react-i18next'
import
{
useBoolean
,
useClickAway
}
from
'ahooks'
import
{
ChevronDownIcon
,
Cog8ToothIcon
,
InformationCircleIcon
}
from
'@heroicons/react/24/outline'
import
ParamItem
from
'./param-item'
import
ModelIcon
from
'./model-icon'
import
Radio
from
'@/app/components/base/radio'
import
Panel
from
'@/app/components/base/panel'
import
type
{
CompletionParams
}
from
'@/models/debug'
import
{
AppType
,
ProviderType
}
from
'@/types/app'
import
{
TONE_LIST
}
from
'@/config'
import
{
MODEL_LIST
,
TONE_LIST
}
from
'@/config'
import
Toast
from
'@/app/components/base/toast'
import
{
AlertTriangle
}
from
'@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
import
{
formatNumber
}
from
'@/utils/format'
export
type
IConifgModelProps
=
{
mode
:
string
modelId
:
string
...
...
@@ -26,19 +26,7 @@ export type IConifgModelProps = {
onShowUseGPT4Confirm
:
()
=>
void
}
const
options
=
[
{
id
:
'gpt-3.5-turbo'
,
name
:
'gpt-3.5-turbo'
,
type
:
AppType
.
chat
},
{
id
:
'gpt-3.5-turbo-16k'
,
name
:
'gpt-3.5-turbo-16k'
,
type
:
AppType
.
chat
},
{
id
:
'gpt-4'
,
name
:
'gpt-4'
,
type
:
AppType
.
chat
},
// 8k version
{
id
:
'claude-instant-1'
,
name
:
'claude-instant-1'
,
type
:
AppType
.
chat
,
provider
:
ProviderType
.
anthropic
},
// set 30k
{
id
:
'claude-2'
,
name
:
'claude-2'
,
type
:
AppType
.
chat
,
provider
:
ProviderType
.
anthropic
},
// set 30k
{
id
:
'gpt-3.5-turbo'
,
name
:
'gpt-3.5-turbo'
,
type
:
AppType
.
completion
},
{
id
:
'gpt-3.5-turbo-16k'
,
name
:
'gpt-3.5-turbo-16k'
,
type
:
AppType
.
completion
},
{
id
:
'text-davinci-003'
,
name
:
'text-davinci-003'
,
type
:
AppType
.
completion
},
{
id
:
'gpt-4'
,
name
:
'gpt-4'
,
type
:
AppType
.
completion
},
// 8k version
{
id
:
'claude-instant-1'
,
name
:
'claude-instant-1'
,
type
:
AppType
.
completion
,
provider
:
ProviderType
.
anthropic
},
// set 30k
{
id
:
'claude-2'
,
name
:
'claude-2'
,
type
:
AppType
.
completion
,
provider
:
ProviderType
.
anthropic
},
// set 30k
]
const
options
=
MODEL_LIST
const
getMaxToken
=
(
modelId
:
string
)
=>
{
if
([
'claude-instant-1'
,
'claude-2'
].
includes
(
modelId
))
...
...
@@ -50,30 +38,6 @@ const getMaxToken = (modelId: string) => {
return
4000
}
const
ModelIcon
=
({
provider
,
className
}:
{
provider
?:
ProviderType
;
className
?:
string
})
=>
{
if
(
provider
===
ProviderType
.
anthropic
)
{
return
(
<
svg
className=
{
`w-4 h-4 ${className}`
}
width=
"24"
height=
"24"
viewBox=
"0 0 24 24"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<
rect
width=
"24"
height=
"24"
rx=
"6"
fill=
"#CA9F7B"
/>
<
g
clip
-
path=
"url(#clip0_3907_39360)"
>
<
path
d=
"M14.9613 7.13043H12.8476L16.7022 16.8696H18.8159L14.9613 7.13043ZM8.85457 7.13043L5 16.8696H7.15539L7.94365 14.8243H11.9763L12.7645 16.8696H14.9199L11.0653 7.13043H8.85457ZM8.64091 13.0156L9.95996 9.59291L11.279 13.0156H8.64091Z"
fill=
"#191918"
/>
</
g
>
<
defs
>
<
clipPath
id=
"clip0_3907_39360"
>
<
rect
width=
"14"
height=
"9.73913"
fill=
"white"
transform=
"translate(5 7.13043)"
/>
</
clipPath
>
</
defs
>
</
svg
>
)
}
return
(
<
svg
className=
{
`w-4 h-4 ${className}`
}
width=
"20"
height=
"20"
viewBox=
"0 0 20 20"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<
rect
width=
"20"
height=
"20"
rx=
"6"
fill=
"black"
/>
<
path
d=
"M16.5963 9.65729C16.748 9.99569 16.8443 10.3574 16.8836 10.7265C16.9216 11.0955 16.9026 11.4689 16.8238 11.8321C16.7465 12.1953 16.6123 12.5439 16.4256 12.8648C16.3031 13.0793 16.1587 13.2805 15.9924 13.4658C15.8276 13.6496 15.6438 13.8159 15.444 13.9617C15.2427 14.1076 15.0283 14.2301 14.8007 14.3308C14.5746 14.4299 14.3383 14.5058 14.0962 14.5554C13.9824 14.9084 13.8132 15.2424 13.5944 15.5429C13.3771 15.8434 13.1131 16.1074 12.8126 16.3247C12.5121 16.5435 12.1795 16.7127 11.8266 16.8265C11.4736 16.9417 11.1045 16.9986 10.7326 16.9986C10.4861 17.0001 10.2381 16.9738 9.99596 16.9242C9.75529 16.8732 9.51899 16.7959 9.2929 16.6952C9.06681 16.5946 8.85239 16.4691 8.65256 16.3233C8.45418 16.1774 8.2704 16.0097 8.10703 15.8244C7.74237 15.9032 7.36896 15.9221 6.99992 15.8842C6.63089 15.8448 6.26914 15.7486 5.92928 15.5969C5.59088 15.4466 5.27727 15.2424 5.00159 14.993C4.72591 14.7436 4.49107 14.4518 4.30582 14.1309C4.18184 13.9165 4.07973 13.6904 4.00242 13.4556C3.92511 13.2207 3.87406 12.9786 3.84781 12.7321C3.82155 12.487 3.82301 12.2391 3.84927 11.9926C3.87552 11.7475 3.92949 11.5054 4.0068 11.2705C3.75883 10.9949 3.55462 10.6813 3.40292 10.3428C3.25268 10.003 3.15495 9.6427 3.11703 9.27367C3.07765 8.90463 3.09807 8.53122 3.17538 8.16802C3.25268 7.80482 3.38688 7.4562 3.57358 7.1353C3.69611 6.92088 3.84051 6.71813 4.00534 6.53434C4.17017 6.35056 4.35541 6.18427 4.55525 6.03841C4.75508 5.89254 4.97096 5.76856 5.19705 5.66937C5.42459 5.56873 5.66089 5.49434 5.90303 5.44474C6.0168 5.09029 6.186 4.75772 6.40334 4.45725C6.62213 4.15677 6.88615 3.89275 7.18663 3.67396C7.48711 3.45662 7.81968 3.28742 8.17267 3.17219C8.52566 3.05841 8.89469 3.00007 9.26664 3.00153C9.51315 3.00007 9.76112 3.02486 10.0033 3.07592C10.2454 3.12697 10.4817 3.20282 10.7078 3.30346C10.9339 3.40557 11.1483 3.52955 11.3481 3.67542C11.548 3.82274 11.7317 3.98902 11.8951 4.17427C12.2583 4.09696 12.6317 4.078 13.0008 4.11592C13.3698 4.15385 13.7301 4.25158 14.0699 4.40182C14.4083 4.55352 14.7219 4.75627 14.9976 5.00569C15.2733 5.25366 15.5082 5.54393 15.6934 5.86629C15.8174 6.07925 15.9195 6.30534 15.9968 6.54164C16.0741 6.77648 16.1266 7.01861 16.1514 7.26512C16.1777 7.51163 16.1777 7.7596 16.15 8.00611C16.1237 8.25262 16.0697 8.49475 15.9924 8.72959C16.2418 9.00528 16.4446 9.31742 16.5963 9.65729ZM11.7361 15.8842C12.0541 15.7529 12.3429 15.5589 12.5865 15.3153C12.8301 15.0717 13.0241 14.7829 13.1554 14.4635C13.2866 14.1455 13.3552 13.8042 13.3552 13.46V10.2072C13.3542 10.2043 13.3533 10.2009 13.3523 10.197C13.3513 10.1941 13.3499 10.1911 13.3479 10.1882C13.346 10.1853 13.3435 10.1829 13.3406 10.1809C13.3377 10.178 13.3348 10.1761 13.3319 10.1751L12.1547 9.49538V13.4249C12.1547 13.4643 12.1489 13.5052 12.1387 13.5431C12.1285 13.5825 12.1139 13.6189 12.0935 13.654C12.0731 13.689 12.0497 13.7211 12.0206 13.7488C11.9922 13.777 11.9603 13.8015 11.9257 13.8217L9.13828 15.4306C9.11495 15.4452 9.07556 15.4656 9.05514 15.4772C9.17037 15.575 9.29582 15.661 9.42709 15.7369C9.55983 15.8127 9.69694 15.8769 9.83989 15.9294C9.98284 15.9805 10.1302 16.0199 10.2789 16.0461C10.4292 16.0724 10.5809 16.0855 10.7326 16.0855C11.0768 16.0855 11.4181 16.0169 11.7361 15.8842ZM5.09786 13.6758C5.27144 13.9749 5.50044 14.2345 5.77321 14.4445C6.04743 14.6546 6.35812 14.8077 6.69069 14.8967C7.02326 14.9857 7.37042 15.009 7.71174 14.9638C8.05306 14.9186 8.38125 14.8077 8.68027 14.6356L11.4984 13.0092L11.5057 13.0019C11.5076 13 11.5091 12.9971 11.51 12.9932C11.512 12.9903 11.5134 12.9874 11.5144 12.9844V11.6133L8.11286 13.581C8.07786 13.6014 8.04139 13.616 8.00346 13.6277C7.96408 13.6379 7.9247 13.6423 7.88386 13.6423C7.84447 13.6423 7.80509 13.6379 7.76571 13.6277C7.72778 13.616 7.68986 13.6014 7.65485 13.581L4.86739 11.9707C4.8426 11.9561 4.80613 11.9342 4.78571 11.9211C4.75946 12.0713 4.74633 12.223 4.74633 12.3747C4.74633 12.5264 4.76091 12.6781 4.78717 12.8284C4.81342 12.9771 4.85427 13.1245 4.90532 13.2674C4.95783 13.4104 5.02201 13.5475 5.09786 13.6788V13.6758ZM4.36562 7.59332C4.1935 7.89234 4.08265 8.22199 4.03743 8.56331C3.99221 8.90463 4.01555 9.25033 4.10453 9.58436C4.1935 9.91692 4.34666 10.2276 4.5567 10.5018C4.76675 10.7746 5.02784 11.0036 5.32541 11.1757L8.14204 12.8036C8.14495 12.8045 8.14836 12.8055 8.15225 12.8065H8.16246C8.16635 12.8065 8.16975 12.8055 8.17267 12.8036C8.17558 12.8026 8.1785 12.8011 8.18142 12.7992L9.36291 12.1165L5.96137 10.1532C5.92782 10.1328 5.89573 10.108 5.86656 10.0803C5.8383 10.0519 5.81379 10.0201 5.79363 9.98548C5.77467 9.95047 5.75862 9.91401 5.74841 9.87462C5.7382 9.8367 5.73237 9.79732 5.73383 9.75647V6.44391C5.59088 6.49642 5.45231 6.5606 5.32103 6.63645C5.18975 6.71376 5.06577 6.80128 4.94908 6.899C4.83385 6.99673 4.72591 7.10467 4.62818 7.22136C4.53045 7.3366 4.44439 7.46204 4.36854 7.59332H4.36562ZM14.0408 9.84545C14.0758 9.86587 14.1079 9.88921 14.137 9.91838C14.1647 9.9461 14.1895 9.97819 14.21 10.0132C14.2289 10.0482 14.245 10.0861 14.2552 10.1241C14.2639 10.1634 14.2698 10.2028 14.2683 10.2437V13.5562C14.7365 13.3841 15.145 13.0822 15.4469 12.6854C15.7503 12.2887 15.9326 11.8146 15.9749 11.3187C16.0172 10.8227 15.918 10.3239 15.6876 9.88192C15.4571 9.43995 15.1056 9.07237 14.6738 8.82441L11.8572 7.19657C11.8543 7.19559 11.8509 7.19462 11.847 7.19365H11.8368C11.8338 7.19462 11.8304 7.19559 11.8266 7.19657C11.8236 7.19754 11.8207 7.199 11.8178 7.20094L10.6421 7.88067L14.0437 9.84545H14.0408ZM15.215 8.0805H15.2135V8.08196L15.215 8.0805ZM15.2135 8.07904C15.2981 7.58894 15.2412 7.08425 15.0487 6.62478C14.8576 6.16531 14.5382 5.77002 14.1297 5.48413C13.7213 5.19969 13.24 5.03632 12.7426 5.01445C12.2437 4.99402 11.7507 5.11509 11.3189 5.36306L8.50232 6.98944C8.4994 6.99138 8.49697 6.99382 8.49503 6.99673L8.48919 7.00549C8.48822 7.0084 8.48725 7.01181 8.48627 7.0157C8.4853 7.01861 8.48482 7.02202 8.48482 7.02591V8.38536L11.8864 6.42057C11.9214 6.40015 11.9593 6.38556 11.9972 6.37389C12.0366 6.36368 12.076 6.35931 12.1154 6.35931C12.1562 6.35931 12.1956 6.36368 12.235 6.37389C12.2729 6.38556 12.3094 6.40015 12.3444 6.42057L15.1318 8.03091C15.1566 8.04549 15.1931 8.06591 15.2135 8.07904ZM7.84301 6.57373C7.84301 6.53434 7.84885 6.49496 7.85906 6.45558C7.86927 6.41765 7.88386 6.37973 7.90428 6.34472C7.9247 6.31117 7.94804 6.27908 7.97721 6.24991C8.00492 6.2222 8.03701 6.1974 8.07202 6.17844L10.8595 4.56956C10.8857 4.55352 10.9222 4.53309 10.9426 4.52288C10.5605 4.20344 10.0937 3.99923 9.59921 3.93651C9.10474 3.87233 8.60296 3.9511 8.15225 4.1626C7.70007 4.3741 7.3179 4.71105 7.05097 5.13114C6.78404 5.55268 6.64256 6.03987 6.64256 6.53872V9.79148C6.64353 9.79537 6.6445 9.79878 6.64547 9.80169C6.64645 9.80461 6.6479 9.80753 6.64985 9.81044C6.65179 9.81336 6.65422 9.81628 6.65714 9.8192C6.65909 9.82114 6.662 9.82309 6.66589 9.82503L7.84301 10.5048V6.57373ZM8.4819 10.8723L9.99742 11.7475L11.5129 10.8723V9.12343L9.99888 8.24824L8.48336 9.12343L8.4819 10.8723Z"
fill=
"white"
/>
</
svg
>
)
}
const
ConifgModel
:
FC
<
IConifgModelProps
>
=
({
mode
,
modelId
,
...
...
@@ -227,7 +191,7 @@ const ConifgModel: FC<IConifgModelProps> = ({
className=
{
cn
(
'flex items-center border h-8 px-2.5 space-x-2 rounded-lg'
,
disabled
?
diabledStyle
:
ableStyle
)
}
onClick=
{
()
=>
!
disabled
&&
toogleShowConfig
()
}
>
<
ModelIcon
provider=
{
currModel
?.
provider
}
/>
<
ModelIcon
modelId=
{
currModel
?.
id
as
string
}
/>
<
div
className=
'text-[13px] text-gray-900 font-medium'
>
{
selectedModel
.
name
}
</
div
>
{
disabled
?
<
InformationCircleIcon
className=
'w-3.5 h-3.5 text-[#F79009]'
/>
:
<
Cog8ToothIcon
className=
'w-3.5 h-3.5 text-gray-500'
/>
}
</
div
>
...
...
@@ -254,7 +218,7 @@ const ConifgModel: FC<IConifgModelProps> = ({
{
/* model selector */
}
<
div
className=
"relative"
style=
{
{
zIndex
:
30
}
}
>
<
div
ref=
{
triggerRef
}
onClick=
{
()
=>
!
selectModelDisabled
&&
toogleOption
()
}
className=
{
cn
(
selectModelDisabled
?
'cursor-not-allowed'
:
'cursor-pointer'
,
'flex items-center h-9 px-3 space-x-2 rounded-lg bg-gray-50 '
)
}
>
<
ModelIcon
provider=
{
currModel
?.
provider
}
/>
<
ModelIcon
modelId=
{
currModel
?.
id
as
string
}
/>
<
div
className=
"text-sm gray-900"
>
{
selectedModel
?.
name
}
</
div
>
{
!
selectModelDisabled
&&
<
ChevronDownIcon
className=
{
cn
(
isShowOption
&&
'rotate-180'
,
'w-[14px] h-[14px] text-gray-500'
)
}
/>
}
</
div
>
...
...
@@ -262,7 +226,7 @@ const ConifgModel: FC<IConifgModelProps> = ({
<
div
className=
{
cn
(
isChatApp
?
'min-w-[159px]'
:
'w-[179px]'
,
'absolute right-0 bg-gray-50 rounded-lg shadow'
)
}
>
{
availableModels
.
map
(
item
=>
(
<
div
key=
{
item
.
id
}
onClick=
{
handleSelectModel
(
item
.
id
,
item
.
provider
)
}
className=
"flex items-center h-9 px-3 rounded-lg cursor-pointer hover:bg-gray-100"
>
<
ModelIcon
className=
'shrink-0 mr-2'
provider=
{
item
?.
provider
}
/>
<
ModelIcon
className=
'shrink-0 mr-2'
modelId=
{
item
?.
id
}
/>
<
div
className=
"text-sm gray-900 whitespace-nowrap"
>
{
item
.
name
}
</
div
>
</
div
>
))
}
...
...
web/app/components/app/configuration/config-model/model-icon.tsx
0 → 100644
View file @
23e34136
'use client'
import
type
{
FC
}
from
'react'
import
React
from
'react'
import
{
ProviderType
}
from
'@/types/app'
import
{
MODEL_LIST
}
from
'@/config'
import
{
Anthropic
,
Gpt3
,
Gpt4
}
from
'@/app/components/base/icons/src/public/llm'
export
type
IModelIconProps
=
{
modelId
:
string
;
className
?:
string
}
const
ModelIcon
:
FC
<
IModelIconProps
>
=
({
modelId
,
className
})
=>
{
const
resClassName
=
`w-4 h-4
${
className
}
`
const
model
=
MODEL_LIST
.
find
(
item
=>
item
.
id
===
modelId
)
if
(
model
?.
id
===
'gpt-4'
)
return
<
Gpt4
className=
{
resClassName
}
/>
if
(
model
?.
provider
===
ProviderType
.
anthropic
)
{
return
(
<
Anthropic
className=
{
resClassName
}
/>
)
}
return
(
<
Gpt3
className=
{
resClassName
}
/>
)
}
export
default
React
.
memo
(
ModelIcon
)
web/app/components/app/configuration/config/index.tsx
View file @
23e34136
...
...
@@ -4,7 +4,6 @@ import React from 'react'
import
{
useContext
}
from
'use-context-selector'
import
produce
from
'immer'
import
{
useBoolean
}
from
'ahooks'
import
useSWR
from
'swr'
import
DatasetConfig
from
'../dataset-config'
import
ChatGroup
from
'../features/chat-group'
import
ExperienceEnchanceGroup
from
'../features/experience-enchance-group'
...
...
@@ -20,7 +19,7 @@ import ConfigPrompt from '@/app/components/app/configuration/config-prompt'
import
ConfigVar
from
'@/app/components/app/configuration/config-var'
import
type
{
PromptVariable
}
from
'@/models/debug'
import
{
AppType
}
from
'@/types/app'
import
{
fetchTenantInfo
}
from
'@/service/common
'
import
{
useProviderContext
}
from
'@/context/provider-context
'
const
Config
:
FC
=
()
=>
{
const
{
...
...
@@ -39,8 +38,7 @@ const Config: FC = () => {
setSpeechToTextConfig
,
}
=
useContext
(
ConfigContext
)
const
isChatApp
=
mode
===
AppType
.
chat
const
{
data
:
userInfo
}
=
useSWR
({
url
:
'/info'
},
fetchTenantInfo
)
const
openaiProvider
=
userInfo
?.
providers
?.
find
(({
token_is_set
,
is_valid
,
provider_name
})
=>
token_is_set
&&
is_valid
&&
provider_name
===
'openai'
)
const
{
currentProvider
}
=
useProviderContext
()
const
promptTemplate
=
modelConfig
.
configs
.
prompt_template
const
promptVariables
=
modelConfig
.
configs
.
prompt_variables
...
...
@@ -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
[
showAutomatic
,
{
setTrue
:
showAutomaticTrue
,
setFalse
:
showAutomaticFalse
}]
=
useBoolean
(
false
)
...
...
@@ -122,7 +120,7 @@ const Config: FC = () => {
isChatApp=
{
isChatApp
}
config=
{
featureConfig
}
onChange=
{
handleFeatureChange
}
showSpeechToTextItem=
{
!!
openaiProvider
}
showSpeechToTextItem=
{
currentProvider
?.
provider_name
===
'openai'
}
/>
)
}
{
showAutomatic
&&
(
...
...
@@ -162,7 +160,7 @@ const Config: FC = () => {
}
}
isShowSuggestedQuestionsAfterAnswer=
{
featureConfig
.
suggestedQuestionsAfterAnswer
}
isShowSpeechText=
{
featureConfig
.
speechToText
}
isShowSpeechText=
{
featureConfig
.
speechToText
&&
currentProvider
?.
provider_name
===
'openai'
}
/>
)
}
...
...
web/app/components/app/configuration/dataset-config/card-item/index.tsx
View file @
23e34136
'use client'
import
React
,
{
FC
}
from
'react'
import
type
{
FC
}
from
'react'
import
React
from
'react'
import
cn
from
'classnames'
import
TypeIcon
from
'../type-icon'
import
{
useTranslation
}
from
'react-i18next'
import
{
formatNumber
}
from
'@/utils/format
'
import
TypeIcon
from
'../type-icon
'
import
RemoveIcon
from
'../../base/icons/remove-icon'
import
s
from
'./style.module.css'
import
{
formatNumber
}
from
'@/utils/format'
export
interface
ICardItemProps
{
export
type
ICardItemProps
=
{
className
?:
string
config
:
any
onRemove
:
(
id
:
string
)
=>
void
readonly
?:
boolean
}
// const RemoveIcon = ({ className, onClick }: { className: string, onClick: () => void }) => (
// <svg className={className} onClick={onClick} width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
// <path d="M10 6H14M6 8H18M16.6667 8L16.1991 15.0129C16.129 16.065 16.0939 16.5911 15.8667 16.99C15.6666 17.3412 15.3648 17.6235 15.0011 17.7998C14.588 18 14.0607 18 13.0062 18H10.9938C9.93927 18 9.41202 18 8.99889 17.7998C8.63517 17.6235 8.33339 17.3412 8.13332 16.99C7.90607 16.5911 7.871 16.065 7.80086 15.0129L7.33333 8M10.6667 11V14.3333M13.3333 11V14.3333" stroke="#667085" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
...
...
@@ -24,7 +24,8 @@ export interface ICardItemProps {
const
CardItem
:
FC
<
ICardItemProps
>
=
({
className
,
config
,
onRemove
onRemove
,
readonly
,
})
=>
{
const
{
t
}
=
useTranslation
()
...
...
@@ -44,7 +45,7 @@ const CardItem: FC<ICardItemProps> = ({
</
div
>
</
div
>
<
RemoveIcon
className=
{
`${s.deleteBtn} shrink-0`
}
onClick=
{
()
=>
onRemove
(
config
.
id
)
}
/>
{
!
readonly
&&
<
RemoveIcon
className=
{
`${s.deleteBtn} shrink-0`
}
onClick=
{
()
=>
onRemove
(
config
.
id
)
}
/>
}
</
div
>
)
}
...
...
web/app/components/app/configuration/dataset-config/select-dataset/index.tsx
View file @
23e34136
...
...
@@ -128,8 +128,12 @@ const SelectDataSet: FC<ISelectDataSetProps> = ({
<
div
className=
'max-w-[200px] text-[13px] font-medium text-gray-800 overflow-hidden text-ellipsis whitespace-nowrap'
>
{
item
.
name
}
</
div
>
</
div
>
<
div
className=
'max-w-[140px] flex text-xs text-gray-500 overflow-hidden text-ellipsis whitespace-nowrap'
>
{
formatNumber
(
item
.
word_count
)
}
{
t
(
'appDebug.feature.dataSet.words'
)
}
·
{
formatNumber
(
item
.
document_count
)
}
{
t
(
'appDebug.feature.dataSet.textBlocks'
)
}
<
div
className=
'flex text-xs text-gray-500 overflow-hidden whitespace-nowrap'
>
<
span
className=
'max-w-[100px] overflow-hidden text-ellipsis whitespace-nowrap'
>
{
formatNumber
(
item
.
word_count
)
}
</
span
>
{
t
(
'appDebug.feature.dataSet.words'
)
}
<
span
className=
'px-0.5'
>
·
</
span
>
<
span
className=
'max-w-[100px] min-w-[8px] overflow-hidden text-ellipsis whitespace-nowrap'
>
{
formatNumber
(
item
.
document_count
)
}
</
span
>
{
t
(
'appDebug.feature.dataSet.textBlocks'
)
}
</
div
>
</
div
>
))
}
...
...
web/app/components/app/configuration/debug/index.tsx
View file @
23e34136
...
...
@@ -22,6 +22,7 @@ import type { ModelConfig as BackendModelConfig } from '@/types/app'
import
{
promptVariablesToUserInputsForm
}
from
'@/utils/model-config'
import
TextGeneration
from
'@/app/components/app/text-generate/item'
import
{
IS_CE_EDITION
}
from
'@/config'
import
{
useProviderContext
}
from
'@/context/provider-context'
type
IDebug
=
{
hasSetAPIKEY
:
boolean
...
...
@@ -51,7 +52,7 @@ const Debug: FC<IDebug> = ({
modelConfig
,
completionParams
,
}
=
useContext
(
ConfigContext
)
const
{
currentProvider
}
=
useProviderContext
()
const
[
chatList
,
setChatList
,
getChatList
]
=
useGetState
<
IChatItem
[]
>
([])
const
chatListDomRef
=
useRef
<
HTMLDivElement
>
(
null
)
useEffect
(()
=>
{
...
...
@@ -389,7 +390,7 @@ const Debug: FC<IDebug> = ({
}
}
isShowSuggestion=
{
doShowSuggestion
}
suggestionList=
{
suggestQuestions
}
isShowSpeechToText=
{
speechToTextConfig
.
enabled
}
isShowSpeechToText=
{
speechToTextConfig
.
enabled
&&
currentProvider
?.
provider_name
===
'openai'
}
/>
</
div
>
</
div
>
...
...
web/app/components/app/log/list.tsx
View file @
23e34136
...
...
@@ -16,10 +16,10 @@ import dayjs from 'dayjs'
import
{
createContext
,
useContext
}
from
'use-context-selector'
import
classNames
from
'classnames'
import
{
useTranslation
}
from
'react-i18next'
import
{
EditIconSolid
}
from
'../chat'
import
{
randomString
}
from
'../../app-sidebar/basic'
import
s
from
'./style.module.css'
import
type
{
FeedbackFunc
,
Feedbacktype
,
IChatItem
,
SubmitAnnotationFunc
}
from
'@/app/components/app/chat'
import
{
EditIconSolid
}
from
'@/app/components/app/chat/icon-component'
import
type
{
FeedbackFunc
,
Feedbacktype
,
IChatItem
,
SubmitAnnotationFunc
}
from
'@/app/components/app/chat/type'
import
type
{
Annotation
,
ChatConversationFullDetailResponse
,
ChatConversationGeneralDetail
,
ChatConversationsResponse
,
ChatMessage
,
ChatMessagesRequest
,
CompletionConversationFullDetailResponse
,
CompletionConversationGeneralDetail
,
CompletionConversationsResponse
}
from
'@/models/log'
import
type
{
App
}
from
'@/types/app'
import
Loading
from
'@/app/components/base/loading'
...
...
web/app/components/base/icons/assets/public/llm/anthropic.svg
0 → 100644
View file @
23e34136
<svg
width=
"24"
height=
"24"
viewBox=
"0 0 24 24"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<rect
width=
"24"
height=
"24"
rx=
"6"
fill=
"#CA9F7B"
/>
<g
clip-path=
"url(#clip0_7672_55906)"
>
<path
d=
"M15.3843 6.43457H12.9687L17.3739 17.565H19.7896L15.3843 6.43457ZM8.40522 6.43457L4 17.565H6.4633L7.36417 15.2276H11.9729L12.8737 17.565H15.337L10.9318 6.43457H8.40522ZM8.16104 13.1605L9.66852 9.24883L11.176 13.1605H8.16104Z"
fill=
"#191918"
/>
</g>
<rect
x=
"0.5"
y=
"0.5"
width=
"23"
height=
"23"
rx=
"5.5"
stroke=
"black"
stroke-opacity=
"0.05"
/>
<defs>
<clipPath
id=
"clip0_7672_55906"
>
<rect
width=
"16"
height=
"11.1304"
fill=
"white"
transform=
"translate(4 6.43457)"
/>
</clipPath>
</defs>
</svg>
web/app/components/base/icons/assets/public/llm/gpt-3.svg
0 → 100644
View file @
23e34136
<svg
width=
"24"
height=
"24"
viewBox=
"0 0 24 24"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<rect
width=
"24"
height=
"24"
rx=
"6"
fill=
"#19C37D"
/>
<path
d=
"M19.6451 11.6028C19.8209 11.995 19.9325 12.4142 19.9781 12.8419C20.0221 13.2696 20.0001 13.7024 19.9088 14.1234C19.8192 14.5443 19.6637 14.9484 19.4473 15.3203C19.3053 15.5688 19.1379 15.8021 18.9452 16.0168C18.7542 16.2298 18.5412 16.4225 18.3096 16.5916C18.0763 16.7606 17.8278 16.9027 17.564 17.0193C17.302 17.1343 17.0281 17.2222 16.7475 17.2796C16.6156 17.6888 16.4195 18.0759 16.1659 18.4242C15.914 18.7724 15.6081 19.0784 15.2598 19.3303C14.9115 19.5839 14.5261 19.78 14.117 19.9118C13.7079 20.0454 13.2802 20.1113 12.8491 20.1113C12.5634 20.113 12.276 20.0826 11.9953 20.0251C11.7164 19.9659 11.4425 19.8763 11.1805 19.7597C10.9184 19.643 10.6699 19.4977 10.4383 19.3286C10.2084 19.1595 9.99541 18.9651 9.80606 18.7504C9.38342 18.8417 8.95064 18.8637 8.52293 18.8197C8.09522 18.7741 7.67596 18.6625 7.28206 18.4867C6.88985 18.3126 6.52638 18.0759 6.20687 17.7868C5.88735 17.4977 5.61517 17.1596 5.40047 16.7877C5.25677 16.5392 5.13843 16.2771 5.04883 16.005C4.95924 15.7328 4.90007 15.4522 4.86964 15.1665C4.83921 14.8824 4.8409 14.595 4.87133 14.3093C4.90176 14.0253 4.96431 13.7447 5.05391 13.4725C4.76651 13.153 4.52983 12.7895 4.35402 12.3973C4.17989 12.0034 4.06662 11.5859 4.02267 11.1581C3.97702 10.7304 4.00069 10.2976 4.09029 9.8767C4.17989 9.45575 4.33542 9.05171 4.55181 8.67978C4.69382 8.43127 4.86118 8.19628 5.05222 7.98327C5.24325 7.77026 5.45795 7.57754 5.68956 7.40848C5.92116 7.23943 6.17136 7.09573 6.4334 6.98077C6.69713 6.86412 6.971 6.77791 7.25163 6.72043C7.38349 6.30962 7.5796 5.92417 7.83149 5.57592C8.08508 5.22766 8.39107 4.92167 8.73932 4.66809C9.08758 4.4162 9.47302 4.22009 9.88214 4.08654C10.2913 3.95467 10.719 3.88705 11.1501 3.88874C11.4358 3.88705 11.7232 3.91579 12.0038 3.97496C12.2844 4.03413 12.5583 4.12204 12.8203 4.23869C13.0824 4.35703 13.3309 4.50072 13.5625 4.66978C13.7941 4.84053 14.0071 5.03325 14.1964 5.24795C14.6174 5.15835 15.0502 5.13637 15.4779 5.18033C15.9056 5.22428 16.3232 5.33755 16.7171 5.51168C17.1093 5.6875 17.4727 5.92248 17.7923 6.21157C18.1118 6.49896 18.384 6.83538 18.5987 7.209C18.7423 7.45582 18.8607 7.71786 18.9503 7.99173C19.0399 8.26391 19.1007 8.54454 19.1295 8.83024C19.1599 9.11595 19.1599 9.40334 19.1278 9.68905C19.0974 9.97475 19.0348 10.2554 18.9452 10.5276C19.2343 10.8471 19.4693 11.2089 19.6451 11.6028ZM14.0122 18.8197C14.3807 18.6676 14.7154 18.4428 14.9978 18.1604C15.2801 17.8781 15.5049 17.5434 15.6571 17.1731C15.8092 16.8046 15.8887 16.409 15.8887 16.01V12.2401C15.8876 12.2367 15.8864 12.2328 15.8853 12.2283C15.8842 12.2249 15.8825 12.2215 15.8802 12.2181C15.878 12.2147 15.8752 12.2119 15.8718 12.2097C15.8684 12.2063 15.865 12.204 15.8616 12.2029L14.4974 11.4151V15.9695C14.4974 16.0151 14.4906 16.0624 14.4788 16.1064C14.4669 16.152 14.45 16.1943 14.4264 16.2349C14.4027 16.2755 14.3756 16.3126 14.3418 16.3448C14.309 16.3775 14.272 16.4059 14.2319 16.4293L11.0013 18.294C10.9742 18.3109 10.9286 18.3346 10.9049 18.3481C11.0385 18.4613 11.1839 18.5611 11.336 18.649C11.4899 18.7369 11.6488 18.8113 11.8144 18.8722C11.9801 18.9313 12.1509 18.977 12.3233 19.0074C12.4974 19.0378 12.6732 19.053 12.8491 19.053C13.248 19.053 13.6436 18.9736 14.0122 18.8197ZM6.31844 16.2602C6.51962 16.6068 6.78504 16.9077 7.10117 17.1512C7.419 17.3946 7.77908 17.5721 8.16453 17.6752C8.54998 17.7784 8.95233 17.8054 9.34792 17.753C9.74351 17.7006 10.1239 17.5721 10.4705 17.3726L13.7366 15.4877L13.7451 15.4792C13.7473 15.477 13.749 15.4736 13.7501 15.4691C13.7524 15.4657 13.7541 15.4623 13.7552 15.4589V13.8698L9.81283 16.1504C9.77225 16.174 9.72999 16.1909 9.68603 16.2045C9.64039 16.2163 9.59474 16.2214 9.54741 16.2214C9.50176 16.2214 9.45612 16.2163 9.41047 16.2045C9.36652 16.1909 9.32256 16.174 9.28199 16.1504L6.05133 14.284C6.0226 14.2671 5.98033 14.2417 5.95666 14.2265C5.92623 14.4006 5.91102 14.5764 5.91102 14.7523C5.91102 14.9281 5.92792 15.1039 5.95835 15.278C5.98878 15.4505 6.03612 15.6212 6.09529 15.7869C6.15615 15.9526 6.23053 16.1115 6.31844 16.2636V16.2602ZM5.46978 9.21062C5.2703 9.55718 5.14182 9.93925 5.08941 10.3348C5.037 10.7304 5.06405 11.1311 5.16717 11.5182C5.2703 11.9037 5.44781 12.2638 5.69125 12.5816C5.93469 12.8977 6.2373 13.1631 6.58217 13.3626L9.84664 15.2493C9.85002 15.2504 9.85396 15.2515 9.85847 15.2527H9.8703C9.87481 15.2527 9.87876 15.2515 9.88214 15.2493C9.88552 15.2482 9.8889 15.2465 9.89228 15.2442L11.2616 14.453L7.31925 12.1775C7.28037 12.1539 7.24318 12.1251 7.20937 12.093C7.17661 12.0602 7.1482 12.0232 7.12484 11.9831C7.10286 11.9426 7.08427 11.9003 7.07243 11.8547C7.0606 11.8107 7.05384 11.7651 7.05553 11.7177V7.87846C6.88985 7.93932 6.72925 8.0137 6.5771 8.10161C6.42495 8.19121 6.28125 8.29265 6.14601 8.40591C6.01245 8.51918 5.88735 8.64428 5.77408 8.77953C5.66082 8.91308 5.56107 9.05847 5.47316 9.21062H5.46978ZM16.6832 11.8208C16.7238 11.8445 16.761 11.8716 16.7948 11.9054C16.8269 11.9375 16.8557 11.9747 16.8794 12.0153C16.9013 12.0558 16.9199 12.0998 16.9318 12.1437C16.9419 12.1894 16.9487 12.235 16.947 12.2824V16.1216C17.4896 15.9221 17.963 15.5722 18.3129 15.1124C18.6646 14.6525 18.8759 14.1031 18.9249 13.5283C18.974 12.9535 18.859 12.3753 18.5919 11.8631C18.3248 11.3509 17.9174 10.9248 17.417 10.6374L14.1525 8.75079C14.1491 8.74966 14.1452 8.74853 14.1407 8.74741H14.1288C14.1254 8.74853 14.1215 8.74966 14.117 8.75079C14.1136 8.75191 14.1102 8.7536 14.1068 8.75586L12.7443 9.54366L16.6866 11.8208H16.6832ZM18.0441 9.77526H18.0425V9.77695L18.0441 9.77526ZM18.0425 9.77357C18.1405 9.20555 18.0746 8.62061 17.8514 8.08809C17.63 7.55556 17.2597 7.09742 16.7864 6.76607C16.313 6.43641 15.7551 6.24707 15.1787 6.22171C14.6005 6.19804 14.0291 6.33836 13.5287 6.62575L10.2642 8.51073C10.2608 8.51298 10.258 8.5158 10.2558 8.51918L10.249 8.52932C10.2479 8.5327 10.2467 8.53665 10.2456 8.54116C10.2445 8.54454 10.2439 8.54848 10.2439 8.55299V10.1286L14.1863 7.85141C14.2269 7.82774 14.2708 7.81084 14.3148 7.79731C14.3604 7.78548 14.4061 7.78041 14.4517 7.78041C14.499 7.78041 14.5447 7.78548 14.5903 7.79731C14.6343 7.81084 14.6766 7.82774 14.7171 7.85141L17.9478 9.71778C17.9765 9.73469 18.0188 9.75836 18.0425 9.77357ZM9.50007 8.02892C9.50007 7.98327 9.50683 7.93763 9.51867 7.89198C9.5305 7.84803 9.54741 7.80407 9.57108 7.7635C9.59474 7.72462 9.62179 7.68743 9.6556 7.65361C9.68772 7.62149 9.72492 7.59275 9.76549 7.57078L12.9961 5.70609C13.0266 5.6875 13.0688 5.66383 13.0925 5.65199C12.6496 5.28176 12.1086 5.04508 11.5355 4.97239C10.9624 4.89801 10.3809 4.9893 9.85847 5.23443C9.3344 5.47956 8.89147 5.87008 8.5821 6.35696C8.27273 6.84553 8.10874 7.41017 8.10874 7.98834V11.7583C8.10987 11.7628 8.111 11.7667 8.11212 11.7701C8.11325 11.7735 8.11494 11.7769 8.1172 11.7803C8.11945 11.7836 8.12227 11.787 8.12565 11.7904C8.1279 11.7927 8.13128 11.7949 8.13579 11.7972L9.50007 12.585V8.02892ZM10.2405 13.011L11.997 14.0253L13.7535 13.011V10.984L11.9987 9.96968L10.2422 10.984L10.2405 13.011Z"
fill=
"white"
/>
<rect
x=
"0.5"
y=
"0.5"
width=
"23"
height=
"23"
rx=
"5.5"
stroke=
"black"
stroke-opacity=
"0.05"
/>
</svg>
web/app/components/base/icons/assets/public/llm/gpt-4.svg
0 → 100644
View file @
23e34136
<svg
width=
"24"
height=
"24"
viewBox=
"0 0 24 24"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<rect
width=
"24"
height=
"24"
rx=
"6"
fill=
"#AB68FF"
/>
<path
d=
"M19.6451 11.6028C19.8209 11.995 19.9325 12.4142 19.9781 12.8419C20.0221 13.2696 20.0001 13.7024 19.9088 14.1234C19.8192 14.5443 19.6637 14.9484 19.4473 15.3203C19.3053 15.5688 19.1379 15.8021 18.9452 16.0168C18.7542 16.2298 18.5412 16.4225 18.3096 16.5916C18.0763 16.7606 17.8278 16.9027 17.564 17.0193C17.302 17.1343 17.0281 17.2222 16.7475 17.2796C16.6156 17.6888 16.4195 18.0759 16.1659 18.4242C15.914 18.7724 15.6081 19.0784 15.2598 19.3303C14.9115 19.5839 14.5261 19.78 14.117 19.9118C13.7079 20.0454 13.2802 20.1113 12.8491 20.1113C12.5634 20.113 12.276 20.0826 11.9953 20.0251C11.7164 19.9659 11.4425 19.8763 11.1805 19.7597C10.9184 19.643 10.6699 19.4977 10.4383 19.3286C10.2084 19.1595 9.99541 18.9651 9.80606 18.7504C9.38342 18.8417 8.95064 18.8637 8.52293 18.8197C8.09522 18.7741 7.67596 18.6625 7.28206 18.4867C6.88985 18.3126 6.52638 18.0759 6.20687 17.7868C5.88735 17.4977 5.61517 17.1596 5.40047 16.7877C5.25677 16.5392 5.13843 16.2771 5.04883 16.005C4.95924 15.7328 4.90007 15.4522 4.86964 15.1665C4.83921 14.8824 4.8409 14.595 4.87133 14.3093C4.90176 14.0253 4.96431 13.7447 5.05391 13.4725C4.76651 13.153 4.52983 12.7895 4.35402 12.3973C4.17989 12.0034 4.06662 11.5859 4.02267 11.1581C3.97702 10.7304 4.00069 10.2976 4.09029 9.8767C4.17989 9.45575 4.33542 9.05171 4.55181 8.67978C4.69382 8.43127 4.86118 8.19628 5.05222 7.98327C5.24325 7.77026 5.45795 7.57754 5.68956 7.40848C5.92116 7.23943 6.17136 7.09573 6.4334 6.98077C6.69713 6.86412 6.971 6.77791 7.25163 6.72043C7.38349 6.30962 7.5796 5.92417 7.83149 5.57592C8.08508 5.22766 8.39107 4.92167 8.73932 4.66809C9.08758 4.4162 9.47302 4.22009 9.88214 4.08654C10.2913 3.95467 10.719 3.88705 11.1501 3.88874C11.4358 3.88705 11.7232 3.91579 12.0038 3.97496C12.2844 4.03413 12.5583 4.12204 12.8203 4.23869C13.0824 4.35703 13.3309 4.50072 13.5625 4.66978C13.7941 4.84053 14.0071 5.03325 14.1964 5.24795C14.6174 5.15835 15.0502 5.13637 15.4779 5.18033C15.9056 5.22428 16.3232 5.33755 16.7171 5.51168C17.1093 5.6875 17.4727 5.92248 17.7923 6.21157C18.1118 6.49896 18.384 6.83538 18.5987 7.209C18.7423 7.45582 18.8607 7.71786 18.9503 7.99173C19.0399 8.26391 19.1007 8.54454 19.1295 8.83024C19.1599 9.11595 19.1599 9.40334 19.1278 9.68905C19.0974 9.97475 19.0348 10.2554 18.9452 10.5276C19.2343 10.8471 19.4693 11.2089 19.6451 11.6028ZM14.0122 18.8197C14.3807 18.6676 14.7154 18.4428 14.9978 18.1604C15.2801 17.8781 15.5049 17.5434 15.6571 17.1731C15.8092 16.8046 15.8887 16.409 15.8887 16.01V12.2401C15.8876 12.2367 15.8864 12.2328 15.8853 12.2283C15.8842 12.2249 15.8825 12.2215 15.8802 12.2181C15.878 12.2147 15.8752 12.2119 15.8718 12.2097C15.8684 12.2063 15.865 12.204 15.8616 12.2029L14.4974 11.4151V15.9695C14.4974 16.0151 14.4906 16.0624 14.4788 16.1064C14.4669 16.152 14.45 16.1943 14.4264 16.2349C14.4027 16.2755 14.3756 16.3126 14.3418 16.3448C14.309 16.3775 14.272 16.4059 14.2319 16.4293L11.0013 18.294C10.9742 18.3109 10.9286 18.3346 10.9049 18.3481C11.0385 18.4613 11.1839 18.5611 11.336 18.649C11.4899 18.7369 11.6488 18.8113 11.8144 18.8722C11.9801 18.9313 12.1509 18.977 12.3233 19.0074C12.4974 19.0378 12.6732 19.053 12.8491 19.053C13.248 19.053 13.6436 18.9736 14.0122 18.8197ZM6.31844 16.2602C6.51962 16.6068 6.78504 16.9077 7.10117 17.1512C7.419 17.3946 7.77908 17.5721 8.16453 17.6752C8.54998 17.7784 8.95233 17.8054 9.34792 17.753C9.74351 17.7006 10.1239 17.5721 10.4705 17.3726L13.7366 15.4877L13.7451 15.4792C13.7473 15.477 13.749 15.4736 13.7501 15.4691C13.7524 15.4657 13.7541 15.4623 13.7552 15.4589V13.8698L9.81283 16.1504C9.77225 16.174 9.72999 16.1909 9.68603 16.2045C9.64039 16.2163 9.59474 16.2214 9.54741 16.2214C9.50176 16.2214 9.45612 16.2163 9.41047 16.2045C9.36652 16.1909 9.32256 16.174 9.28199 16.1504L6.05133 14.284C6.0226 14.2671 5.98033 14.2417 5.95666 14.2265C5.92623 14.4006 5.91102 14.5764 5.91102 14.7523C5.91102 14.9281 5.92792 15.1039 5.95835 15.278C5.98878 15.4505 6.03612 15.6212 6.09529 15.7869C6.15615 15.9526 6.23053 16.1115 6.31844 16.2636V16.2602ZM5.46978 9.21062C5.2703 9.55718 5.14182 9.93925 5.08941 10.3348C5.037 10.7304 5.06405 11.1311 5.16717 11.5182C5.2703 11.9037 5.44781 12.2638 5.69125 12.5816C5.93469 12.8977 6.2373 13.1631 6.58217 13.3626L9.84664 15.2493C9.85002 15.2504 9.85396 15.2515 9.85847 15.2527H9.8703C9.87481 15.2527 9.87876 15.2515 9.88214 15.2493C9.88552 15.2482 9.8889 15.2465 9.89228 15.2442L11.2616 14.453L7.31925 12.1775C7.28037 12.1539 7.24318 12.1251 7.20937 12.093C7.17661 12.0602 7.1482 12.0232 7.12484 11.9831C7.10286 11.9426 7.08427 11.9003 7.07243 11.8547C7.0606 11.8107 7.05384 11.7651 7.05553 11.7177V7.87846C6.88985 7.93932 6.72925 8.0137 6.5771 8.10161C6.42495 8.19121 6.28125 8.29265 6.14601 8.40591C6.01245 8.51918 5.88735 8.64428 5.77408 8.77953C5.66082 8.91308 5.56107 9.05847 5.47316 9.21062H5.46978ZM16.6832 11.8208C16.7238 11.8445 16.761 11.8716 16.7948 11.9054C16.8269 11.9375 16.8557 11.9747 16.8794 12.0153C16.9013 12.0558 16.9199 12.0998 16.9318 12.1437C16.9419 12.1894 16.9487 12.235 16.947 12.2824V16.1216C17.4896 15.9221 17.963 15.5722 18.3129 15.1124C18.6646 14.6525 18.8759 14.1031 18.9249 13.5283C18.974 12.9535 18.859 12.3753 18.5919 11.8631C18.3248 11.3509 17.9174 10.9248 17.417 10.6374L14.1525 8.75079C14.1491 8.74966 14.1452 8.74853 14.1407 8.74741H14.1288C14.1254 8.74853 14.1215 8.74966 14.117 8.75079C14.1136 8.75191 14.1102 8.7536 14.1068 8.75586L12.7443 9.54366L16.6866 11.8208H16.6832ZM18.0441 9.77526H18.0425V9.77695L18.0441 9.77526ZM18.0425 9.77357C18.1405 9.20555 18.0746 8.62061 17.8514 8.08809C17.63 7.55556 17.2597 7.09742 16.7864 6.76607C16.313 6.43641 15.7551 6.24707 15.1787 6.22171C14.6005 6.19804 14.0291 6.33836 13.5287 6.62575L10.2642 8.51073C10.2608 8.51298 10.258 8.5158 10.2558 8.51918L10.249 8.52932C10.2479 8.5327 10.2467 8.53665 10.2456 8.54116C10.2445 8.54454 10.2439 8.54848 10.2439 8.55299V10.1286L14.1863 7.85141C14.2269 7.82774 14.2708 7.81084 14.3148 7.79731C14.3604 7.78548 14.4061 7.78041 14.4517 7.78041C14.499 7.78041 14.5447 7.78548 14.5903 7.79731C14.6343 7.81084 14.6766 7.82774 14.7171 7.85141L17.9478 9.71778C17.9765 9.73469 18.0188 9.75836 18.0425 9.77357ZM9.50007 8.02892C9.50007 7.98327 9.50683 7.93763 9.51867 7.89198C9.5305 7.84803 9.54741 7.80407 9.57108 7.7635C9.59474 7.72462 9.62179 7.68743 9.6556 7.65361C9.68772 7.62149 9.72492 7.59275 9.76549 7.57078L12.9961 5.70609C13.0266 5.6875 13.0688 5.66383 13.0925 5.65199C12.6496 5.28176 12.1086 5.04508 11.5355 4.97239C10.9624 4.89801 10.3809 4.9893 9.85847 5.23443C9.3344 5.47956 8.89147 5.87008 8.5821 6.35696C8.27273 6.84553 8.10874 7.41017 8.10874 7.98834V11.7583C8.10987 11.7628 8.111 11.7667 8.11212 11.7701C8.11325 11.7735 8.11494 11.7769 8.1172 11.7803C8.11945 11.7836 8.12227 11.787 8.12565 11.7904C8.1279 11.7927 8.13128 11.7949 8.13579 11.7972L9.50007 12.585V8.02892ZM10.2405 13.011L11.997 14.0253L13.7535 13.011V10.984L11.9987 9.96968L10.2422 10.984L10.2405 13.011Z"
fill=
"white"
/>
<rect
x=
"0.5"
y=
"0.5"
width=
"23"
height=
"23"
rx=
"5.5"
stroke=
"black"
stroke-opacity=
"0.05"
/>
</svg>
web/app/components/base/icons/assets/public/model/checked.svg
0 → 100644
View file @
23e34136
<svg
width=
"16"
height=
"16"
viewBox=
"0 0 16 16"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<path
d=
"M13.3332 4L5.99984 11.3333L2.6665 8"
stroke=
"#155EEF"
stroke-width=
"2"
stroke-linecap=
"round"
stroke-linejoin=
"round"
/>
</svg>
web/app/components/base/icons/assets/public/plugins/google.svg
0 → 100644
View file @
23e34136
<svg
width=
"24"
height=
"24"
viewBox=
"0 0 24 24"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<path
d=
"M22.501 12.2331C22.501 11.3698 22.4296 10.7398 22.2748 10.0864H12.2153V13.983H18.12C18.001 14.9514 17.3582 16.4097 15.9296 17.3897L15.9096 17.5202L19.0902 19.9349L19.3106 19.9564C21.3343 18.1247 22.501 15.4297 22.501 12.2331Z"
fill=
"#4285F4"
/>
<path
d=
"M12.2147 22.5001C15.1075 22.5001 17.5361 21.5667 19.3099 19.9567L15.929 17.39C15.0242 18.0083 13.8099 18.44 12.2147 18.44C9.38142 18.44 6.97669 16.6083 6.11947 14.0767L5.99382 14.0871L2.68656 16.5955L2.64331 16.7133C4.40519 20.1433 8.02423 22.5001 12.2147 22.5001Z"
fill=
"#34A853"
/>
<path
d=
"M6.11997 14.0765C5.89379 13.4232 5.76289 12.7231 5.76289 11.9998C5.76289 11.2764 5.89379 10.5765 6.10807 9.92313L6.10208 9.78398L2.75337 7.23535L2.64381 7.28642C1.91765 8.70977 1.50098 10.3081 1.50098 11.9998C1.50098 13.6915 1.91765 15.2897 2.64381 16.7131L6.11997 14.0765Z"
fill=
"#FBBC05"
/>
<path
d=
"M12.2148 5.55997C14.2267 5.55997 15.5838 6.41163 16.3576 7.12335L19.3814 4.23C17.5243 2.53834 15.1076 1.5 12.2148 1.5C8.02426 1.5 4.4052 3.85665 2.64331 7.28662L6.10759 9.92332C6.97672 7.39166 9.38146 5.55997 12.2148 5.55997Z"
fill=
"#EB4335"
/>
</svg>
web/app/components/base/icons/assets/public/plugins/web-reader.svg
0 → 100644
View file @
23e34136
<svg
width=
"24"
height=
"24"
viewBox=
"0 0 24 24"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<path
fill-rule=
"evenodd"
clip-rule=
"evenodd"
d=
"M9.59235 3.32566C10.3587 3.11341 11.1661 3 12 3C13.962 3 15.7773 3.62779 17.2561 4.69345C16.4693 5.21349 15.8824 5.77819 15.4756 6.38193C14.854 7.30445 14.6947 8.25844 14.8234 9.12887C14.9484 9.97416 15.3366 10.696 15.7446 11.2301C16.1402 11.7479 16.6256 12.181 17.0531 12.3946C18.1294 12.9327 19.3714 13.2022 20.2999 13.341C21.1399 13.4667 22.9206 13.8871 22.9865 12.5492C22.9955 12.3672 23 12.1841 23 12C23 5.92487 18.0751 1 12 1C5.92487 1 1 5.92487 1 12C1 18.0751 5.92487 23 12 23C12.1841 23 12.3672 22.9955 12.5492 22.9865C13.1008 22.9593 13.526 22.4902 13.4988 21.9385C13.4716 21.3869 13.0024 20.9618 12.4508 20.9889C12.3015 20.9963 12.1512 21 12 21C8.49063 21 5.45038 18.9914 3.96619 16.0611L4.93474 15.502L8.50745 16.1706C9.43309 16.3439 10.2876 15.6313 10.2834 14.6896L10.2694 11.5365L12.0952 8.41051C12.3911 7.90404 12.3646 7.27161 12.0274 6.79167L9.59235 3.32566Z"
fill=
"#444CE7"
/>
<path
fill-rule=
"evenodd"
clip-rule=
"evenodd"
d=
"M13.9456 12.6561C13.5777 12.5165 13.1621 12.6057 12.8839 12.884C12.6056 13.1623 12.5164 13.5778 12.656 13.9458L15.8228 22.2945C15.969 22.68 16.3367 22.9362 16.7489 22.9399C17.1611 22.9435 17.5333 22.6938 17.6863 22.3111L19.007 19.0071L22.311 17.6865C22.6937 17.5334 22.9434 17.1612 22.9397 16.749C22.9361 16.3368 22.6799 15.9691 22.2944 15.8229L13.9456 12.6561Z"
fill=
"#444CE7"
/>
</svg>
web/app/components/base/icons/assets/public/plugins/wikipedia.svg
0 → 100644
View file @
23e34136
<svg
width=
"24"
height=
"24"
viewBox=
"0 0 24 24"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<path
d=
"M23.8431 5.0001H19.2179H19.0609V5.15706V5.66001V5.81696H19.2179H19.5393C19.9131 5.81696 20.2502 6.00882 20.4411 6.33021C20.632 6.65161 20.6392 7.0394 20.4603 7.36765L15.3174 16.8077L12.9751 11.2238L15.1813 7.17527C15.6379 6.33743 16.5143 5.81696 17.4684 5.81696H17.5726H17.7296V5.66001V5.15706V5.0001H17.5726H12.9474H12.7905V5.15706V5.66001V5.81696H12.9474H13.2688C13.6426 5.81696 13.9797 6.00882 14.1706 6.33021C14.3615 6.65161 14.3687 7.0394 14.1899 7.36765L12.5896 10.305L11.1634 6.9051C11.0601 6.65867 11.0856 6.38965 11.2336 6.16714C11.3816 5.94462 11.6197 5.81696 11.887 5.81696H12.2526H12.4095V5.66001V5.15706V5.0001H12.2526H6.72092H6.56396V5.15706V5.66001V5.81696H6.72092H6.79699C7.88821 5.81696 8.866 6.46719 9.28817 7.47344L11.3954 12.497L9.04698 16.8077L4.89304 6.9051C4.78966 6.65867 4.81525 6.38965 4.9632 6.16714C5.11116 5.94462 5.34932 5.81696 5.61657 5.81696H6.17832H6.33527V5.66001V5.15706V5.0001H6.17832H0.156957H0V5.15706V5.66001V5.81696H0.156957H0.52654C1.61776 5.81696 2.59561 6.46719 3.01772 7.47344L7.80628 18.889C7.89004 19.0887 8.08425 19.2177 8.30111 19.2177C8.50014 19.2177 8.67588 19.1131 8.77125 18.9381L9.39589 17.7918L11.7807 13.4155L14.0767 18.889C14.1604 19.0886 14.3547 19.2176 14.5715 19.2176C14.7705 19.2176 14.9463 19.1131 15.0417 18.938L15.6663 17.7917L21.4517 7.17517C21.9083 6.33733 22.7847 5.81686 23.7388 5.81686H23.843H24V5.6599V5.15696V5H23.8431V5.0001Z"
fill=
"#222A30"
/>
</svg>
web/app/components/base/icons/assets/public/thought/data-set.svg
0 → 100644
View file @
23e34136
<svg
width=
"12"
height=
"12"
viewBox=
"0 0 12 12"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<g
clip-path=
"url(#clip0_7847_32895)"
>
<path
d=
"M10.5 2.5C10.5 3.32843 8.48528 4 6 4C3.51472 4 1.5 3.32843 1.5 2.5M10.5 2.5C10.5 1.67157 8.48528 1 6 1C3.51472 1 1.5 1.67157 1.5 2.5M10.5 2.5V9.5C10.5 10.33 8.5 11 6 11C3.5 11 1.5 10.33 1.5 9.5V2.5M10.5 6C10.5 6.83 8.5 7.5 6 7.5C3.5 7.5 1.5 6.83 1.5 6"
stroke=
"#667085"
stroke-width=
"1.25"
stroke-linecap=
"round"
stroke-linejoin=
"round"
/>
</g>
<defs>
<clipPath
id=
"clip0_7847_32895"
>
<rect
width=
"12"
height=
"12"
fill=
"white"
/>
</clipPath>
</defs>
</svg>
web/app/components/base/icons/assets/public/thought/loading.svg
0 → 100644
View file @
23e34136
<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/assets/public/thought/search.svg
0 → 100644
View file @
23e34136
<svg
width=
"12"
height=
"12"
viewBox=
"0 0 12 12"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<g
clip-path=
"url(#clip0_7847_32899)"
>
<path
d=
"M10.5 10.5L8.75005 8.75M10 5.75C10 8.09721 8.09721 10 5.75 10C3.40279 10 1.5 8.09721 1.5 5.75C1.5 3.40279 3.40279 1.5 5.75 1.5C8.09721 1.5 10 3.40279 10 5.75Z"
stroke=
"#667085"
stroke-width=
"1.25"
stroke-linecap=
"round"
stroke-linejoin=
"round"
/>
</g>
<defs>
<clipPath
id=
"clip0_7847_32899"
>
<rect
width=
"12"
height=
"12"
fill=
"white"
/>
</clipPath>
</defs>
</svg>
web/app/components/base/icons/assets/public/thought/thought-list.svg
0 → 100644
View file @
23e34136
<svg
width=
"12"
height=
"12"
viewBox=
"0 0 12 12"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<path
fill-rule=
"evenodd"
clip-rule=
"evenodd"
d=
"M4 6C4 5.72386 4.22386 5.5 4.5 5.5L10.5 5.5C10.7761 5.5 11 5.72386 11 6C11 6.27614 10.7761 6.5 10.5 6.5L4.5 6.5C4.22386 6.5 4 6.27614 4 6Z"
fill=
"#667085"
/>
<path
fill-rule=
"evenodd"
clip-rule=
"evenodd"
d=
"M4 3C4 2.72386 4.22386 2.5 4.5 2.5L10.5 2.5C10.7761 2.5 11 2.72386 11 3C11 3.27614 10.7761 3.5 10.5 3.5L4.5 3.5C4.22386 3.5 4 3.27614 4 3Z"
fill=
"#667085"
/>
<path
fill-rule=
"evenodd"
clip-rule=
"evenodd"
d=
"M4 9C4 8.72386 4.22386 8.5 4.5 8.5L10.5 8.5C10.7761 8.5 11 8.72386 11 9C11 9.27614 10.7761 9.5 10.5 9.5L4.5 9.5C4.22386 9.5 4 9.27614 4 9Z"
fill=
"#667085"
/>
<path
fill-rule=
"evenodd"
clip-rule=
"evenodd"
d=
"M1 6C1 5.44772 1.44772 5 2 5C2.55228 5 3 5.44772 3 6C3 6.55228 2.55228 7 2 7C1.44772 7 1 6.55228 1 6Z"
fill=
"#667085"
/>
<path
fill-rule=
"evenodd"
clip-rule=
"evenodd"
d=
"M1 3C1 2.44772 1.44772 2 2 2C2.55228 2 3 2.44772 3 3C3 3.55228 2.55228 4 2 4C1.44772 4 1 3.55228 1 3Z"
fill=
"#667085"
/>
<path
fill-rule=
"evenodd"
clip-rule=
"evenodd"
d=
"M1 9C1 8.44772 1.44772 8 2 8C2.55228 8 3 8.44772 3 9C3 9.55228 2.55228 10 2 10C1.44772 10 1 9.55228 1 9Z"
fill=
"#667085"
/>
</svg>
web/app/components/base/icons/assets/public/thought/web-reader.svg
0 → 100644
View file @
23e34136
<svg
width=
"12"
height=
"12"
viewBox=
"0 0 12 12"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<g
clip-path=
"url(#clip0_7847_32887)"
>
<path
d=
"M4.5 1.75V1M2.53033 2.53033L2 2M2.53033 6.5L2 7.03033M6.5 2.53033L7.03033 2M1.75 4.5H1M7.93224 8.09479L6.68637 10.4085C6.54404 10.6728 6.47287 10.805 6.38725 10.8384C6.31295 10.8674 6.22926 10.8592 6.16199 10.8164C6.08447 10.767 6.04028 10.6235 5.95191 10.3366L4.22259 4.72263C4.1504 4.48825 4.1143 4.37107 4.14335 4.29192C4.16865 4.22298 4.22298 4.16865 4.29192 4.14335C4.37107 4.1143 4.48825 4.1504 4.72262 4.2226L10.3366 5.95192C10.6235 6.0403 10.767 6.08449 10.8164 6.16201C10.8592 6.22928 10.8674 6.31297 10.8384 6.38727C10.805 6.47289 10.6728 6.54406 10.4085 6.68639L8.09479 7.93224C8.05551 7.95339 8.03587 7.96396 8.01868 7.97755C8.00341 7.98961 7.98961 8.00341 7.97755 8.01868C7.96396 8.03587 7.95339 8.05551 7.93224 8.09479Z"
stroke=
"#667085"
stroke-width=
"1.25"
stroke-linecap=
"round"
stroke-linejoin=
"round"
/>
</g>
<defs>
<clipPath
id=
"clip0_7847_32887"
>
<rect
width=
"12"
height=
"12"
fill=
"white"
/>
</clipPath>
</defs>
</svg>
web/app/components/base/icons/assets/vender/line/general/link-external-02.svg
0 → 100644
View file @
23e34136
<svg
width=
"12"
height=
"12"
viewBox=
"0 0 12 12"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<g
id=
"link-external-02"
>
<path
id=
"Icon"
d=
"M10.5 4.5L10.5 1.5M10.5 1.5H7.49999M10.5 1.5L6 6M5 1.5H3.9C3.05992 1.5 2.63988 1.5 2.31901 1.66349C2.03677 1.8073 1.8073 2.03677 1.66349 2.31901C1.5 2.63988 1.5 3.05992 1.5 3.9V8.1C1.5 8.94008 1.5 9.36012 1.66349 9.68099C1.8073 9.96323 2.03677 10.1927 2.31901 10.3365C2.63988 10.5 3.05992 10.5 3.9 10.5H8.1C8.94008 10.5 9.36012 10.5 9.68099 10.3365C9.96323 10.1927 10.1927 9.96323 10.3365 9.68099C10.5 9.36012 10.5 8.94008 10.5 8.1V7"
stroke=
"#155EEF"
stroke-linecap=
"round"
stroke-linejoin=
"round"
/>
</g>
</svg>
web/app/components/base/icons/assets/vender/solid/alertsAndFeedback/alert-circle.svg
0 → 100644
View file @
23e34136
<svg
width=
"16"
height=
"16"
viewBox=
"0 0 16 16"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<g
id=
"alert-circle"
>
<path
id=
"Solid"
fill-rule=
"evenodd"
clip-rule=
"evenodd"
d=
"M8 0.666626C3.94992 0.666626 0.666672 3.94987 0.666672 7.99996C0.666672 12.05 3.94992 15.3333 8 15.3333C12.0501 15.3333 15.3333 12.05 15.3333 7.99996C15.3333 3.94987 12.0501 0.666626 8 0.666626ZM8.66667 5.33329C8.66667 4.9651 8.36819 4.66663 8 4.66663C7.63181 4.66663 7.33334 4.9651 7.33334 5.33329V7.99996C7.33334 8.36815 7.63181 8.66663 8 8.66663C8.36819 8.66663 8.66667 8.36815 8.66667 7.99996V5.33329ZM8 9.99996C7.63181 9.99996 7.33334 10.2984 7.33334 10.6666C7.33334 11.0348 7.63181 11.3333 8 11.3333H8.00667C8.37486 11.3333 8.67334 11.0348 8.67334 10.6666C8.67334 10.2984 8.37486 9.99996 8.00667 9.99996H8Z"
fill=
"#D92D20"
/>
</g>
</svg>
web/app/components/base/icons/assets/vender/solid/general/check-circle.svg
0 → 100644
View file @
23e34136
<svg
width=
"16"
height=
"16"
viewBox=
"0 0 16 16"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<g
id=
"check-circle"
>
<path
id=
"Solid"
fill-rule=
"evenodd"
clip-rule=
"evenodd"
d=
"M8 0.666626C3.94992 0.666626 0.666672 3.94987 0.666672 7.99996C0.666672 12.05 3.94992 15.3333 8 15.3333C12.0501 15.3333 15.3333 12.05 15.3333 7.99996C15.3333 3.94987 12.0501 0.666626 8 0.666626ZM11.4714 6.47136C11.7318 6.21101 11.7318 5.7889 11.4714 5.52855C11.2111 5.26821 10.7889 5.26821 10.5286 5.52855L7 9.05715L5.47141 7.52855C5.21106 7.2682 4.78895 7.2682 4.5286 7.52855C4.26825 7.7889 4.26825 8.21101 4.5286 8.47136L6.5286 10.4714C6.78895 10.7317 7.21106 10.7317 7.47141 10.4714L11.4714 6.47136Z"
fill=
"#039855"
/>
</g>
</svg>
web/app/components/base/icons/src/public/llm/Anthropic.json
0 → 100644
View file @
23e34136
{
"icon"
:
{
"type"
:
"element"
,
"isRootNode"
:
true
,
"name"
:
"svg"
,
"attributes"
:
{
"width"
:
"24"
,
"height"
:
"24"
,
"viewBox"
:
"0 0 24 24"
,
"fill"
:
"none"
,
"xmlns"
:
"http://www.w3.org/2000/svg"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"rect"
,
"attributes"
:
{
"width"
:
"24"
,
"height"
:
"24"
,
"rx"
:
"6"
,
"fill"
:
"#CA9F7B"
},
"children"
:
[]
},
{
"type"
:
"element"
,
"name"
:
"g"
,
"attributes"
:
{
"clip-path"
:
"url(#clip0_7672_55906)"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"d"
:
"M15.3843 6.43457H12.9687L17.3739 17.565H19.7896L15.3843 6.43457ZM8.40522 6.43457L4 17.565H6.4633L7.36417 15.2276H11.9729L12.8737 17.565H15.337L10.9318 6.43457H8.40522ZM8.16104 13.1605L9.66852 9.24883L11.176 13.1605H8.16104Z"
,
"fill"
:
"#191918"
},
"children"
:
[]
}
]
},
{
"type"
:
"element"
,
"name"
:
"rect"
,
"attributes"
:
{
"x"
:
"0.5"
,
"y"
:
"0.5"
,
"width"
:
"23"
,
"height"
:
"23"
,
"rx"
:
"5.5"
,
"stroke"
:
"black"
,
"stroke-opacity"
:
"0.05"
},
"children"
:
[]
},
{
"type"
:
"element"
,
"name"
:
"defs"
,
"attributes"
:
{},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"clipPath"
,
"attributes"
:
{
"id"
:
"clip0_7672_55906"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"rect"
,
"attributes"
:
{
"width"
:
"16"
,
"height"
:
"11.1304"
,
"fill"
:
"white"
,
"transform"
:
"translate(4 6.43457)"
},
"children"
:
[]
}
]
}
]
}
]
},
"name"
:
"Anthropic"
}
\ No newline at end of file
web/app/components/base/icons/src/public/llm/Anthropic.tsx
0 → 100644
View file @
23e34136
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./Anthropic.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/llm/Gpt3.json
0 → 100644
View file @
23e34136
{
"icon"
:
{
"type"
:
"element"
,
"isRootNode"
:
true
,
"name"
:
"svg"
,
"attributes"
:
{
"width"
:
"24"
,
"height"
:
"24"
,
"viewBox"
:
"0 0 24 24"
,
"fill"
:
"none"
,
"xmlns"
:
"http://www.w3.org/2000/svg"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"rect"
,
"attributes"
:
{
"width"
:
"24"
,
"height"
:
"24"
,
"rx"
:
"6"
,
"fill"
:
"#19C37D"
},
"children"
:
[]
},
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"d"
:
"M19.6451 11.6028C19.8209 11.995 19.9325 12.4142 19.9781 12.8419C20.0221 13.2696 20.0001 13.7024 19.9088 14.1234C19.8192 14.5443 19.6637 14.9484 19.4473 15.3203C19.3053 15.5688 19.1379 15.8021 18.9452 16.0168C18.7542 16.2298 18.5412 16.4225 18.3096 16.5916C18.0763 16.7606 17.8278 16.9027 17.564 17.0193C17.302 17.1343 17.0281 17.2222 16.7475 17.2796C16.6156 17.6888 16.4195 18.0759 16.1659 18.4242C15.914 18.7724 15.6081 19.0784 15.2598 19.3303C14.9115 19.5839 14.5261 19.78 14.117 19.9118C13.7079 20.0454 13.2802 20.1113 12.8491 20.1113C12.5634 20.113 12.276 20.0826 11.9953 20.0251C11.7164 19.9659 11.4425 19.8763 11.1805 19.7597C10.9184 19.643 10.6699 19.4977 10.4383 19.3286C10.2084 19.1595 9.99541 18.9651 9.80606 18.7504C9.38342 18.8417 8.95064 18.8637 8.52293 18.8197C8.09522 18.7741 7.67596 18.6625 7.28206 18.4867C6.88985 18.3126 6.52638 18.0759 6.20687 17.7868C5.88735 17.4977 5.61517 17.1596 5.40047 16.7877C5.25677 16.5392 5.13843 16.2771 5.04883 16.005C4.95924 15.7328 4.90007 15.4522 4.86964 15.1665C4.83921 14.8824 4.8409 14.595 4.87133 14.3093C4.90176 14.0253 4.96431 13.7447 5.05391 13.4725C4.76651 13.153 4.52983 12.7895 4.35402 12.3973C4.17989 12.0034 4.06662 11.5859 4.02267 11.1581C3.97702 10.7304 4.00069 10.2976 4.09029 9.8767C4.17989 9.45575 4.33542 9.05171 4.55181 8.67978C4.69382 8.43127 4.86118 8.19628 5.05222 7.98327C5.24325 7.77026 5.45795 7.57754 5.68956 7.40848C5.92116 7.23943 6.17136 7.09573 6.4334 6.98077C6.69713 6.86412 6.971 6.77791 7.25163 6.72043C7.38349 6.30962 7.5796 5.92417 7.83149 5.57592C8.08508 5.22766 8.39107 4.92167 8.73932 4.66809C9.08758 4.4162 9.47302 4.22009 9.88214 4.08654C10.2913 3.95467 10.719 3.88705 11.1501 3.88874C11.4358 3.88705 11.7232 3.91579 12.0038 3.97496C12.2844 4.03413 12.5583 4.12204 12.8203 4.23869C13.0824 4.35703 13.3309 4.50072 13.5625 4.66978C13.7941 4.84053 14.0071 5.03325 14.1964 5.24795C14.6174 5.15835 15.0502 5.13637 15.4779 5.18033C15.9056 5.22428 16.3232 5.33755 16.7171 5.51168C17.1093 5.6875 17.4727 5.92248 17.7923 6.21157C18.1118 6.49896 18.384 6.83538 18.5987 7.209C18.7423 7.45582 18.8607 7.71786 18.9503 7.99173C19.0399 8.26391 19.1007 8.54454 19.1295 8.83024C19.1599 9.11595 19.1599 9.40334 19.1278 9.68905C19.0974 9.97475 19.0348 10.2554 18.9452 10.5276C19.2343 10.8471 19.4693 11.2089 19.6451 11.6028ZM14.0122 18.8197C14.3807 18.6676 14.7154 18.4428 14.9978 18.1604C15.2801 17.8781 15.5049 17.5434 15.6571 17.1731C15.8092 16.8046 15.8887 16.409 15.8887 16.01V12.2401C15.8876 12.2367 15.8864 12.2328 15.8853 12.2283C15.8842 12.2249 15.8825 12.2215 15.8802 12.2181C15.878 12.2147 15.8752 12.2119 15.8718 12.2097C15.8684 12.2063 15.865 12.204 15.8616 12.2029L14.4974 11.4151V15.9695C14.4974 16.0151 14.4906 16.0624 14.4788 16.1064C14.4669 16.152 14.45 16.1943 14.4264 16.2349C14.4027 16.2755 14.3756 16.3126 14.3418 16.3448C14.309 16.3775 14.272 16.4059 14.2319 16.4293L11.0013 18.294C10.9742 18.3109 10.9286 18.3346 10.9049 18.3481C11.0385 18.4613 11.1839 18.5611 11.336 18.649C11.4899 18.7369 11.6488 18.8113 11.8144 18.8722C11.9801 18.9313 12.1509 18.977 12.3233 19.0074C12.4974 19.0378 12.6732 19.053 12.8491 19.053C13.248 19.053 13.6436 18.9736 14.0122 18.8197ZM6.31844 16.2602C6.51962 16.6068 6.78504 16.9077 7.10117 17.1512C7.419 17.3946 7.77908 17.5721 8.16453 17.6752C8.54998 17.7784 8.95233 17.8054 9.34792 17.753C9.74351 17.7006 10.1239 17.5721 10.4705 17.3726L13.7366 15.4877L13.7451 15.4792C13.7473 15.477 13.749 15.4736 13.7501 15.4691C13.7524 15.4657 13.7541 15.4623 13.7552 15.4589V13.8698L9.81283 16.1504C9.77225 16.174 9.72999 16.1909 9.68603 16.2045C9.64039 16.2163 9.59474 16.2214 9.54741 16.2214C9.50176 16.2214 9.45612 16.2163 9.41047 16.2045C9.36652 16.1909 9.32256 16.174 9.28199 16.1504L6.05133 14.284C6.0226 14.2671 5.98033 14.2417 5.95666 14.2265C5.92623 14.4006 5.91102 14.5764 5.91102 14.7523C5.91102 14.9281 5.92792 15.1039 5.95835 15.278C5.98878 15.4505 6.03612 15.6212 6.09529 15.7869C6.15615 15.9526 6.23053 16.1115 6.31844 16.2636V16.2602ZM5.46978 9.21062C5.2703 9.55718 5.14182 9.93925 5.08941 10.3348C5.037 10.7304 5.06405 11.1311 5.16717 11.5182C5.2703 11.9037 5.44781 12.2638 5.69125 12.5816C5.93469 12.8977 6.2373 13.1631 6.58217 13.3626L9.84664 15.2493C9.85002 15.2504 9.85396 15.2515 9.85847 15.2527H9.8703C9.87481 15.2527 9.87876 15.2515 9.88214 15.2493C9.88552 15.2482 9.8889 15.2465 9.89228 15.2442L11.2616 14.453L7.31925 12.1775C7.28037 12.1539 7.24318 12.1251 7.20937 12.093C7.17661 12.0602 7.1482 12.0232 7.12484 11.9831C7.10286 11.9426 7.08427 11.9003 7.07243 11.8547C7.0606 11.8107 7.05384 11.7651 7.05553 11.7177V7.87846C6.88985 7.93932 6.72925 8.0137 6.5771 8.10161C6.42495 8.19121 6.28125 8.29265 6.14601 8.40591C6.01245 8.51918 5.88735 8.64428 5.77408 8.77953C5.66082 8.91308 5.56107 9.05847 5.47316 9.21062H5.46978ZM16.6832 11.8208C16.7238 11.8445 16.761 11.8716 16.7948 11.9054C16.8269 11.9375 16.8557 11.9747 16.8794 12.0153C16.9013 12.0558 16.9199 12.0998 16.9318 12.1437C16.9419 12.1894 16.9487 12.235 16.947 12.2824V16.1216C17.4896 15.9221 17.963 15.5722 18.3129 15.1124C18.6646 14.6525 18.8759 14.1031 18.9249 13.5283C18.974 12.9535 18.859 12.3753 18.5919 11.8631C18.3248 11.3509 17.9174 10.9248 17.417 10.6374L14.1525 8.75079C14.1491 8.74966 14.1452 8.74853 14.1407 8.74741H14.1288C14.1254 8.74853 14.1215 8.74966 14.117 8.75079C14.1136 8.75191 14.1102 8.7536 14.1068 8.75586L12.7443 9.54366L16.6866 11.8208H16.6832ZM18.0441 9.77526H18.0425V9.77695L18.0441 9.77526ZM18.0425 9.77357C18.1405 9.20555 18.0746 8.62061 17.8514 8.08809C17.63 7.55556 17.2597 7.09742 16.7864 6.76607C16.313 6.43641 15.7551 6.24707 15.1787 6.22171C14.6005 6.19804 14.0291 6.33836 13.5287 6.62575L10.2642 8.51073C10.2608 8.51298 10.258 8.5158 10.2558 8.51918L10.249 8.52932C10.2479 8.5327 10.2467 8.53665 10.2456 8.54116C10.2445 8.54454 10.2439 8.54848 10.2439 8.55299V10.1286L14.1863 7.85141C14.2269 7.82774 14.2708 7.81084 14.3148 7.79731C14.3604 7.78548 14.4061 7.78041 14.4517 7.78041C14.499 7.78041 14.5447 7.78548 14.5903 7.79731C14.6343 7.81084 14.6766 7.82774 14.7171 7.85141L17.9478 9.71778C17.9765 9.73469 18.0188 9.75836 18.0425 9.77357ZM9.50007 8.02892C9.50007 7.98327 9.50683 7.93763 9.51867 7.89198C9.5305 7.84803 9.54741 7.80407 9.57108 7.7635C9.59474 7.72462 9.62179 7.68743 9.6556 7.65361C9.68772 7.62149 9.72492 7.59275 9.76549 7.57078L12.9961 5.70609C13.0266 5.6875 13.0688 5.66383 13.0925 5.65199C12.6496 5.28176 12.1086 5.04508 11.5355 4.97239C10.9624 4.89801 10.3809 4.9893 9.85847 5.23443C9.3344 5.47956 8.89147 5.87008 8.5821 6.35696C8.27273 6.84553 8.10874 7.41017 8.10874 7.98834V11.7583C8.10987 11.7628 8.111 11.7667 8.11212 11.7701C8.11325 11.7735 8.11494 11.7769 8.1172 11.7803C8.11945 11.7836 8.12227 11.787 8.12565 11.7904C8.1279 11.7927 8.13128 11.7949 8.13579 11.7972L9.50007 12.585V8.02892ZM10.2405 13.011L11.997 14.0253L13.7535 13.011V10.984L11.9987 9.96968L10.2422 10.984L10.2405 13.011Z"
,
"fill"
:
"white"
},
"children"
:
[]
},
{
"type"
:
"element"
,
"name"
:
"rect"
,
"attributes"
:
{
"x"
:
"0.5"
,
"y"
:
"0.5"
,
"width"
:
"23"
,
"height"
:
"23"
,
"rx"
:
"5.5"
,
"stroke"
:
"black"
,
"stroke-opacity"
:
"0.05"
},
"children"
:
[]
}
]
},
"name"
:
"Gpt3"
}
\ No newline at end of file
web/app/components/base/icons/src/public/llm/Gpt3.tsx
0 → 100644
View file @
23e34136
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./Gpt3.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/llm/Gpt4.json
0 → 100644
View file @
23e34136
{
"icon"
:
{
"type"
:
"element"
,
"isRootNode"
:
true
,
"name"
:
"svg"
,
"attributes"
:
{
"width"
:
"24"
,
"height"
:
"24"
,
"viewBox"
:
"0 0 24 24"
,
"fill"
:
"none"
,
"xmlns"
:
"http://www.w3.org/2000/svg"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"rect"
,
"attributes"
:
{
"width"
:
"24"
,
"height"
:
"24"
,
"rx"
:
"6"
,
"fill"
:
"#AB68FF"
},
"children"
:
[]
},
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"d"
:
"M19.6451 11.6028C19.8209 11.995 19.9325 12.4142 19.9781 12.8419C20.0221 13.2696 20.0001 13.7024 19.9088 14.1234C19.8192 14.5443 19.6637 14.9484 19.4473 15.3203C19.3053 15.5688 19.1379 15.8021 18.9452 16.0168C18.7542 16.2298 18.5412 16.4225 18.3096 16.5916C18.0763 16.7606 17.8278 16.9027 17.564 17.0193C17.302 17.1343 17.0281 17.2222 16.7475 17.2796C16.6156 17.6888 16.4195 18.0759 16.1659 18.4242C15.914 18.7724 15.6081 19.0784 15.2598 19.3303C14.9115 19.5839 14.5261 19.78 14.117 19.9118C13.7079 20.0454 13.2802 20.1113 12.8491 20.1113C12.5634 20.113 12.276 20.0826 11.9953 20.0251C11.7164 19.9659 11.4425 19.8763 11.1805 19.7597C10.9184 19.643 10.6699 19.4977 10.4383 19.3286C10.2084 19.1595 9.99541 18.9651 9.80606 18.7504C9.38342 18.8417 8.95064 18.8637 8.52293 18.8197C8.09522 18.7741 7.67596 18.6625 7.28206 18.4867C6.88985 18.3126 6.52638 18.0759 6.20687 17.7868C5.88735 17.4977 5.61517 17.1596 5.40047 16.7877C5.25677 16.5392 5.13843 16.2771 5.04883 16.005C4.95924 15.7328 4.90007 15.4522 4.86964 15.1665C4.83921 14.8824 4.8409 14.595 4.87133 14.3093C4.90176 14.0253 4.96431 13.7447 5.05391 13.4725C4.76651 13.153 4.52983 12.7895 4.35402 12.3973C4.17989 12.0034 4.06662 11.5859 4.02267 11.1581C3.97702 10.7304 4.00069 10.2976 4.09029 9.8767C4.17989 9.45575 4.33542 9.05171 4.55181 8.67978C4.69382 8.43127 4.86118 8.19628 5.05222 7.98327C5.24325 7.77026 5.45795 7.57754 5.68956 7.40848C5.92116 7.23943 6.17136 7.09573 6.4334 6.98077C6.69713 6.86412 6.971 6.77791 7.25163 6.72043C7.38349 6.30962 7.5796 5.92417 7.83149 5.57592C8.08508 5.22766 8.39107 4.92167 8.73932 4.66809C9.08758 4.4162 9.47302 4.22009 9.88214 4.08654C10.2913 3.95467 10.719 3.88705 11.1501 3.88874C11.4358 3.88705 11.7232 3.91579 12.0038 3.97496C12.2844 4.03413 12.5583 4.12204 12.8203 4.23869C13.0824 4.35703 13.3309 4.50072 13.5625 4.66978C13.7941 4.84053 14.0071 5.03325 14.1964 5.24795C14.6174 5.15835 15.0502 5.13637 15.4779 5.18033C15.9056 5.22428 16.3232 5.33755 16.7171 5.51168C17.1093 5.6875 17.4727 5.92248 17.7923 6.21157C18.1118 6.49896 18.384 6.83538 18.5987 7.209C18.7423 7.45582 18.8607 7.71786 18.9503 7.99173C19.0399 8.26391 19.1007 8.54454 19.1295 8.83024C19.1599 9.11595 19.1599 9.40334 19.1278 9.68905C19.0974 9.97475 19.0348 10.2554 18.9452 10.5276C19.2343 10.8471 19.4693 11.2089 19.6451 11.6028ZM14.0122 18.8197C14.3807 18.6676 14.7154 18.4428 14.9978 18.1604C15.2801 17.8781 15.5049 17.5434 15.6571 17.1731C15.8092 16.8046 15.8887 16.409 15.8887 16.01V12.2401C15.8876 12.2367 15.8864 12.2328 15.8853 12.2283C15.8842 12.2249 15.8825 12.2215 15.8802 12.2181C15.878 12.2147 15.8752 12.2119 15.8718 12.2097C15.8684 12.2063 15.865 12.204 15.8616 12.2029L14.4974 11.4151V15.9695C14.4974 16.0151 14.4906 16.0624 14.4788 16.1064C14.4669 16.152 14.45 16.1943 14.4264 16.2349C14.4027 16.2755 14.3756 16.3126 14.3418 16.3448C14.309 16.3775 14.272 16.4059 14.2319 16.4293L11.0013 18.294C10.9742 18.3109 10.9286 18.3346 10.9049 18.3481C11.0385 18.4613 11.1839 18.5611 11.336 18.649C11.4899 18.7369 11.6488 18.8113 11.8144 18.8722C11.9801 18.9313 12.1509 18.977 12.3233 19.0074C12.4974 19.0378 12.6732 19.053 12.8491 19.053C13.248 19.053 13.6436 18.9736 14.0122 18.8197ZM6.31844 16.2602C6.51962 16.6068 6.78504 16.9077 7.10117 17.1512C7.419 17.3946 7.77908 17.5721 8.16453 17.6752C8.54998 17.7784 8.95233 17.8054 9.34792 17.753C9.74351 17.7006 10.1239 17.5721 10.4705 17.3726L13.7366 15.4877L13.7451 15.4792C13.7473 15.477 13.749 15.4736 13.7501 15.4691C13.7524 15.4657 13.7541 15.4623 13.7552 15.4589V13.8698L9.81283 16.1504C9.77225 16.174 9.72999 16.1909 9.68603 16.2045C9.64039 16.2163 9.59474 16.2214 9.54741 16.2214C9.50176 16.2214 9.45612 16.2163 9.41047 16.2045C9.36652 16.1909 9.32256 16.174 9.28199 16.1504L6.05133 14.284C6.0226 14.2671 5.98033 14.2417 5.95666 14.2265C5.92623 14.4006 5.91102 14.5764 5.91102 14.7523C5.91102 14.9281 5.92792 15.1039 5.95835 15.278C5.98878 15.4505 6.03612 15.6212 6.09529 15.7869C6.15615 15.9526 6.23053 16.1115 6.31844 16.2636V16.2602ZM5.46978 9.21062C5.2703 9.55718 5.14182 9.93925 5.08941 10.3348C5.037 10.7304 5.06405 11.1311 5.16717 11.5182C5.2703 11.9037 5.44781 12.2638 5.69125 12.5816C5.93469 12.8977 6.2373 13.1631 6.58217 13.3626L9.84664 15.2493C9.85002 15.2504 9.85396 15.2515 9.85847 15.2527H9.8703C9.87481 15.2527 9.87876 15.2515 9.88214 15.2493C9.88552 15.2482 9.8889 15.2465 9.89228 15.2442L11.2616 14.453L7.31925 12.1775C7.28037 12.1539 7.24318 12.1251 7.20937 12.093C7.17661 12.0602 7.1482 12.0232 7.12484 11.9831C7.10286 11.9426 7.08427 11.9003 7.07243 11.8547C7.0606 11.8107 7.05384 11.7651 7.05553 11.7177V7.87846C6.88985 7.93932 6.72925 8.0137 6.5771 8.10161C6.42495 8.19121 6.28125 8.29265 6.14601 8.40591C6.01245 8.51918 5.88735 8.64428 5.77408 8.77953C5.66082 8.91308 5.56107 9.05847 5.47316 9.21062H5.46978ZM16.6832 11.8208C16.7238 11.8445 16.761 11.8716 16.7948 11.9054C16.8269 11.9375 16.8557 11.9747 16.8794 12.0153C16.9013 12.0558 16.9199 12.0998 16.9318 12.1437C16.9419 12.1894 16.9487 12.235 16.947 12.2824V16.1216C17.4896 15.9221 17.963 15.5722 18.3129 15.1124C18.6646 14.6525 18.8759 14.1031 18.9249 13.5283C18.974 12.9535 18.859 12.3753 18.5919 11.8631C18.3248 11.3509 17.9174 10.9248 17.417 10.6374L14.1525 8.75079C14.1491 8.74966 14.1452 8.74853 14.1407 8.74741H14.1288C14.1254 8.74853 14.1215 8.74966 14.117 8.75079C14.1136 8.75191 14.1102 8.7536 14.1068 8.75586L12.7443 9.54366L16.6866 11.8208H16.6832ZM18.0441 9.77526H18.0425V9.77695L18.0441 9.77526ZM18.0425 9.77357C18.1405 9.20555 18.0746 8.62061 17.8514 8.08809C17.63 7.55556 17.2597 7.09742 16.7864 6.76607C16.313 6.43641 15.7551 6.24707 15.1787 6.22171C14.6005 6.19804 14.0291 6.33836 13.5287 6.62575L10.2642 8.51073C10.2608 8.51298 10.258 8.5158 10.2558 8.51918L10.249 8.52932C10.2479 8.5327 10.2467 8.53665 10.2456 8.54116C10.2445 8.54454 10.2439 8.54848 10.2439 8.55299V10.1286L14.1863 7.85141C14.2269 7.82774 14.2708 7.81084 14.3148 7.79731C14.3604 7.78548 14.4061 7.78041 14.4517 7.78041C14.499 7.78041 14.5447 7.78548 14.5903 7.79731C14.6343 7.81084 14.6766 7.82774 14.7171 7.85141L17.9478 9.71778C17.9765 9.73469 18.0188 9.75836 18.0425 9.77357ZM9.50007 8.02892C9.50007 7.98327 9.50683 7.93763 9.51867 7.89198C9.5305 7.84803 9.54741 7.80407 9.57108 7.7635C9.59474 7.72462 9.62179 7.68743 9.6556 7.65361C9.68772 7.62149 9.72492 7.59275 9.76549 7.57078L12.9961 5.70609C13.0266 5.6875 13.0688 5.66383 13.0925 5.65199C12.6496 5.28176 12.1086 5.04508 11.5355 4.97239C10.9624 4.89801 10.3809 4.9893 9.85847 5.23443C9.3344 5.47956 8.89147 5.87008 8.5821 6.35696C8.27273 6.84553 8.10874 7.41017 8.10874 7.98834V11.7583C8.10987 11.7628 8.111 11.7667 8.11212 11.7701C8.11325 11.7735 8.11494 11.7769 8.1172 11.7803C8.11945 11.7836 8.12227 11.787 8.12565 11.7904C8.1279 11.7927 8.13128 11.7949 8.13579 11.7972L9.50007 12.585V8.02892ZM10.2405 13.011L11.997 14.0253L13.7535 13.011V10.984L11.9987 9.96968L10.2422 10.984L10.2405 13.011Z"
,
"fill"
:
"white"
},
"children"
:
[]
},
{
"type"
:
"element"
,
"name"
:
"rect"
,
"attributes"
:
{
"x"
:
"0.5"
,
"y"
:
"0.5"
,
"width"
:
"23"
,
"height"
:
"23"
,
"rx"
:
"5.5"
,
"stroke"
:
"black"
,
"stroke-opacity"
:
"0.05"
},
"children"
:
[]
}
]
},
"name"
:
"Gpt4"
}
\ No newline at end of file
web/app/components/base/icons/src/public/llm/Gpt4.tsx
0 → 100644
View file @
23e34136
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./Gpt4.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/llm/index.ts
0 → 100644
View file @
23e34136
export
{
default
as
Anthropic
}
from
'./Anthropic'
export
{
default
as
Gpt3
}
from
'./Gpt3'
export
{
default
as
Gpt4
}
from
'./Gpt4'
web/app/components/base/icons/src/public/model/Checked.json
0 → 100644
View file @
23e34136
{
"icon"
:
{
"type"
:
"element"
,
"isRootNode"
:
true
,
"name"
:
"svg"
,
"attributes"
:
{
"width"
:
"16"
,
"height"
:
"16"
,
"viewBox"
:
"0 0 16 16"
,
"fill"
:
"none"
,
"xmlns"
:
"http://www.w3.org/2000/svg"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"d"
:
"M13.3332 4L5.99984 11.3333L2.6665 8"
,
"stroke"
:
"#155EEF"
,
"stroke-width"
:
"2"
,
"stroke-linecap"
:
"round"
,
"stroke-linejoin"
:
"round"
},
"children"
:
[]
}
]
},
"name"
:
"Checked"
}
\ No newline at end of file
web/app/components/base/icons/src/public/model/Checked.tsx
0 → 100644
View file @
23e34136
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./Checked.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/model/index.ts
0 → 100644
View file @
23e34136
export
{
default
as
Checked
}
from
'./Checked'
web/app/components/base/icons/src/public/plugins/Google.json
0 → 100644
View file @
23e34136
{
"icon"
:
{
"type"
:
"element"
,
"isRootNode"
:
true
,
"name"
:
"svg"
,
"attributes"
:
{
"width"
:
"24"
,
"height"
:
"24"
,
"viewBox"
:
"0 0 24 24"
,
"fill"
:
"none"
,
"xmlns"
:
"http://www.w3.org/2000/svg"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"d"
:
"M22.501 12.2331C22.501 11.3698 22.4296 10.7398 22.2748 10.0864H12.2153V13.983H18.12C18.001 14.9514 17.3582 16.4097 15.9296 17.3897L15.9096 17.5202L19.0902 19.9349L19.3106 19.9564C21.3343 18.1247 22.501 15.4297 22.501 12.2331Z"
,
"fill"
:
"#4285F4"
},
"children"
:
[]
},
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"d"
:
"M12.2147 22.5001C15.1075 22.5001 17.5361 21.5667 19.3099 19.9567L15.929 17.39C15.0242 18.0083 13.8099 18.44 12.2147 18.44C9.38142 18.44 6.97669 16.6083 6.11947 14.0767L5.99382 14.0871L2.68656 16.5955L2.64331 16.7133C4.40519 20.1433 8.02423 22.5001 12.2147 22.5001Z"
,
"fill"
:
"#34A853"
},
"children"
:
[]
},
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"d"
:
"M6.11997 14.0765C5.89379 13.4232 5.76289 12.7231 5.76289 11.9998C5.76289 11.2764 5.89379 10.5765 6.10807 9.92313L6.10208 9.78398L2.75337 7.23535L2.64381 7.28642C1.91765 8.70977 1.50098 10.3081 1.50098 11.9998C1.50098 13.6915 1.91765 15.2897 2.64381 16.7131L6.11997 14.0765Z"
,
"fill"
:
"#FBBC05"
},
"children"
:
[]
},
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"d"
:
"M12.2148 5.55997C14.2267 5.55997 15.5838 6.41163 16.3576 7.12335L19.3814 4.23C17.5243 2.53834 15.1076 1.5 12.2148 1.5C8.02426 1.5 4.4052 3.85665 2.64331 7.28662L6.10759 9.92332C6.97672 7.39166 9.38146 5.55997 12.2148 5.55997Z"
,
"fill"
:
"#EB4335"
},
"children"
:
[]
}
]
},
"name"
:
"Google"
}
\ No newline at end of file
web/app/components/base/icons/src/public/plugins/Google.tsx
0 → 100644
View file @
23e34136
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./Google.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/plugins/WebReader.json
0 → 100644
View file @
23e34136
{
"icon"
:
{
"type"
:
"element"
,
"isRootNode"
:
true
,
"name"
:
"svg"
,
"attributes"
:
{
"width"
:
"24"
,
"height"
:
"24"
,
"viewBox"
:
"0 0 24 24"
,
"fill"
:
"none"
,
"xmlns"
:
"http://www.w3.org/2000/svg"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"fill-rule"
:
"evenodd"
,
"clip-rule"
:
"evenodd"
,
"d"
:
"M9.59235 3.32566C10.3587 3.11341 11.1661 3 12 3C13.962 3 15.7773 3.62779 17.2561 4.69345C16.4693 5.21349 15.8824 5.77819 15.4756 6.38193C14.854 7.30445 14.6947 8.25844 14.8234 9.12887C14.9484 9.97416 15.3366 10.696 15.7446 11.2301C16.1402 11.7479 16.6256 12.181 17.0531 12.3946C18.1294 12.9327 19.3714 13.2022 20.2999 13.341C21.1399 13.4667 22.9206 13.8871 22.9865 12.5492C22.9955 12.3672 23 12.1841 23 12C23 5.92487 18.0751 1 12 1C5.92487 1 1 5.92487 1 12C1 18.0751 5.92487 23 12 23C12.1841 23 12.3672 22.9955 12.5492 22.9865C13.1008 22.9593 13.526 22.4902 13.4988 21.9385C13.4716 21.3869 13.0024 20.9618 12.4508 20.9889C12.3015 20.9963 12.1512 21 12 21C8.49063 21 5.45038 18.9914 3.96619 16.0611L4.93474 15.502L8.50745 16.1706C9.43309 16.3439 10.2876 15.6313 10.2834 14.6896L10.2694 11.5365L12.0952 8.41051C12.3911 7.90404 12.3646 7.27161 12.0274 6.79167L9.59235 3.32566Z"
,
"fill"
:
"#444CE7"
},
"children"
:
[]
},
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"fill-rule"
:
"evenodd"
,
"clip-rule"
:
"evenodd"
,
"d"
:
"M13.9456 12.6561C13.5777 12.5165 13.1621 12.6057 12.8839 12.884C12.6056 13.1623 12.5164 13.5778 12.656 13.9458L15.8228 22.2945C15.969 22.68 16.3367 22.9362 16.7489 22.9399C17.1611 22.9435 17.5333 22.6938 17.6863 22.3111L19.007 19.0071L22.311 17.6865C22.6937 17.5334 22.9434 17.1612 22.9397 16.749C22.9361 16.3368 22.6799 15.9691 22.2944 15.8229L13.9456 12.6561Z"
,
"fill"
:
"#444CE7"
},
"children"
:
[]
}
]
},
"name"
:
"WebReader"
}
\ No newline at end of file
web/app/components/base/icons/src/public/plugins/WebReader.tsx
0 → 100644
View file @
23e34136
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./WebReader.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/plugins/Wikipedia.json
0 → 100644
View file @
23e34136
{
"icon"
:
{
"type"
:
"element"
,
"isRootNode"
:
true
,
"name"
:
"svg"
,
"attributes"
:
{
"width"
:
"24"
,
"height"
:
"24"
,
"viewBox"
:
"0 0 24 24"
,
"fill"
:
"none"
,
"xmlns"
:
"http://www.w3.org/2000/svg"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"d"
:
"M23.8431 5.0001H19.2179H19.0609V5.15706V5.66001V5.81696H19.2179H19.5393C19.9131 5.81696 20.2502 6.00882 20.4411 6.33021C20.632 6.65161 20.6392 7.0394 20.4603 7.36765L15.3174 16.8077L12.9751 11.2238L15.1813 7.17527C15.6379 6.33743 16.5143 5.81696 17.4684 5.81696H17.5726H17.7296V5.66001V5.15706V5.0001H17.5726H12.9474H12.7905V5.15706V5.66001V5.81696H12.9474H13.2688C13.6426 5.81696 13.9797 6.00882 14.1706 6.33021C14.3615 6.65161 14.3687 7.0394 14.1899 7.36765L12.5896 10.305L11.1634 6.9051C11.0601 6.65867 11.0856 6.38965 11.2336 6.16714C11.3816 5.94462 11.6197 5.81696 11.887 5.81696H12.2526H12.4095V5.66001V5.15706V5.0001H12.2526H6.72092H6.56396V5.15706V5.66001V5.81696H6.72092H6.79699C7.88821 5.81696 8.866 6.46719 9.28817 7.47344L11.3954 12.497L9.04698 16.8077L4.89304 6.9051C4.78966 6.65867 4.81525 6.38965 4.9632 6.16714C5.11116 5.94462 5.34932 5.81696 5.61657 5.81696H6.17832H6.33527V5.66001V5.15706V5.0001H6.17832H0.156957H0V5.15706V5.66001V5.81696H0.156957H0.52654C1.61776 5.81696 2.59561 6.46719 3.01772 7.47344L7.80628 18.889C7.89004 19.0887 8.08425 19.2177 8.30111 19.2177C8.50014 19.2177 8.67588 19.1131 8.77125 18.9381L9.39589 17.7918L11.7807 13.4155L14.0767 18.889C14.1604 19.0886 14.3547 19.2176 14.5715 19.2176C14.7705 19.2176 14.9463 19.1131 15.0417 18.938L15.6663 17.7917L21.4517 7.17517C21.9083 6.33733 22.7847 5.81686 23.7388 5.81686H23.843H24V5.6599V5.15696V5H23.8431V5.0001Z"
,
"fill"
:
"#222A30"
},
"children"
:
[]
}
]
},
"name"
:
"Wikipedia"
}
\ No newline at end of file
web/app/components/base/icons/src/public/plugins/Wikipedia.tsx
0 → 100644
View file @
23e34136
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./Wikipedia.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/plugins/index.ts
0 → 100644
View file @
23e34136
export
{
default
as
Google
}
from
'./Google'
export
{
default
as
WebReader
}
from
'./WebReader'
export
{
default
as
Wikipedia
}
from
'./Wikipedia'
web/app/components/base/icons/src/public/thought/DataSet.json
0 → 100644
View file @
23e34136
{
"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_7847_32895)"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"d"
:
"M10.5 2.5C10.5 3.32843 8.48528 4 6 4C3.51472 4 1.5 3.32843 1.5 2.5M10.5 2.5C10.5 1.67157 8.48528 1 6 1C3.51472 1 1.5 1.67157 1.5 2.5M10.5 2.5V9.5C10.5 10.33 8.5 11 6 11C3.5 11 1.5 10.33 1.5 9.5V2.5M10.5 6C10.5 6.83 8.5 7.5 6 7.5C3.5 7.5 1.5 6.83 1.5 6"
,
"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_7847_32895"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"rect"
,
"attributes"
:
{
"width"
:
"12"
,
"height"
:
"12"
,
"fill"
:
"white"
},
"children"
:
[]
}
]
}
]
}
]
},
"name"
:
"DataSet"
}
\ No newline at end of file
web/app/components/base/icons/src/public/thought/DataSet.tsx
0 → 100644
View file @
23e34136
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./DataSet.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/Loading.json
0 → 100644
View file @
23e34136
{
"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 @
23e34136
// 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/Search.json
0 → 100644
View file @
23e34136
{
"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_7847_32899)"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"d"
:
"M10.5 10.5L8.75005 8.75M10 5.75C10 8.09721 8.09721 10 5.75 10C3.40279 10 1.5 8.09721 1.5 5.75C1.5 3.40279 3.40279 1.5 5.75 1.5C8.09721 1.5 10 3.40279 10 5.75Z"
,
"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_7847_32899"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"rect"
,
"attributes"
:
{
"width"
:
"12"
,
"height"
:
"12"
,
"fill"
:
"white"
},
"children"
:
[]
}
]
}
]
}
]
},
"name"
:
"Search"
}
\ No newline at end of file
web/app/components/base/icons/src/public/thought/Search.tsx
0 → 100644
View file @
23e34136
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./Search.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/ThoughtList.json
0 → 100644
View file @
23e34136
{
"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"
:
"path"
,
"attributes"
:
{
"fill-rule"
:
"evenodd"
,
"clip-rule"
:
"evenodd"
,
"d"
:
"M4 6C4 5.72386 4.22386 5.5 4.5 5.5L10.5 5.5C10.7761 5.5 11 5.72386 11 6C11 6.27614 10.7761 6.5 10.5 6.5L4.5 6.5C4.22386 6.5 4 6.27614 4 6Z"
,
"fill"
:
"#667085"
},
"children"
:
[]
},
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"fill-rule"
:
"evenodd"
,
"clip-rule"
:
"evenodd"
,
"d"
:
"M4 3C4 2.72386 4.22386 2.5 4.5 2.5L10.5 2.5C10.7761 2.5 11 2.72386 11 3C11 3.27614 10.7761 3.5 10.5 3.5L4.5 3.5C4.22386 3.5 4 3.27614 4 3Z"
,
"fill"
:
"#667085"
},
"children"
:
[]
},
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"fill-rule"
:
"evenodd"
,
"clip-rule"
:
"evenodd"
,
"d"
:
"M4 9C4 8.72386 4.22386 8.5 4.5 8.5L10.5 8.5C10.7761 8.5 11 8.72386 11 9C11 9.27614 10.7761 9.5 10.5 9.5L4.5 9.5C4.22386 9.5 4 9.27614 4 9Z"
,
"fill"
:
"#667085"
},
"children"
:
[]
},
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"fill-rule"
:
"evenodd"
,
"clip-rule"
:
"evenodd"
,
"d"
:
"M1 6C1 5.44772 1.44772 5 2 5C2.55228 5 3 5.44772 3 6C3 6.55228 2.55228 7 2 7C1.44772 7 1 6.55228 1 6Z"
,
"fill"
:
"#667085"
},
"children"
:
[]
},
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"fill-rule"
:
"evenodd"
,
"clip-rule"
:
"evenodd"
,
"d"
:
"M1 3C1 2.44772 1.44772 2 2 2C2.55228 2 3 2.44772 3 3C3 3.55228 2.55228 4 2 4C1.44772 4 1 3.55228 1 3Z"
,
"fill"
:
"#667085"
},
"children"
:
[]
},
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"fill-rule"
:
"evenodd"
,
"clip-rule"
:
"evenodd"
,
"d"
:
"M1 9C1 8.44772 1.44772 8 2 8C2.55228 8 3 8.44772 3 9C3 9.55228 2.55228 10 2 10C1.44772 10 1 9.55228 1 9Z"
,
"fill"
:
"#667085"
},
"children"
:
[]
}
]
},
"name"
:
"ThoughtList"
}
\ No newline at end of file
web/app/components/base/icons/src/public/thought/ThoughtList.tsx
0 → 100644
View file @
23e34136
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./ThoughtList.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/WebReader.json
0 → 100644
View file @
23e34136
{
"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_7847_32887)"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"d"
:
"M4.5 1.75V1M2.53033 2.53033L2 2M2.53033 6.5L2 7.03033M6.5 2.53033L7.03033 2M1.75 4.5H1M7.93224 8.09479L6.68637 10.4085C6.54404 10.6728 6.47287 10.805 6.38725 10.8384C6.31295 10.8674 6.22926 10.8592 6.16199 10.8164C6.08447 10.767 6.04028 10.6235 5.95191 10.3366L4.22259 4.72263C4.1504 4.48825 4.1143 4.37107 4.14335 4.29192C4.16865 4.22298 4.22298 4.16865 4.29192 4.14335C4.37107 4.1143 4.48825 4.1504 4.72262 4.2226L10.3366 5.95192C10.6235 6.0403 10.767 6.08449 10.8164 6.16201C10.8592 6.22928 10.8674 6.31297 10.8384 6.38727C10.805 6.47289 10.6728 6.54406 10.4085 6.68639L8.09479 7.93224C8.05551 7.95339 8.03587 7.96396 8.01868 7.97755C8.00341 7.98961 7.98961 8.00341 7.97755 8.01868C7.96396 8.03587 7.95339 8.05551 7.93224 8.09479Z"
,
"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_7847_32887"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"rect"
,
"attributes"
:
{
"width"
:
"12"
,
"height"
:
"12"
,
"fill"
:
"white"
},
"children"
:
[]
}
]
}
]
}
]
},
"name"
:
"WebReader"
}
\ No newline at end of file
web/app/components/base/icons/src/public/thought/WebReader.tsx
0 → 100644
View file @
23e34136
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./WebReader.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
0 → 100644
View file @
23e34136
export
{
default
as
DataSet
}
from
'./DataSet'
export
{
default
as
Loading
}
from
'./Loading'
export
{
default
as
Search
}
from
'./Search'
export
{
default
as
ThoughtList
}
from
'./ThoughtList'
export
{
default
as
WebReader
}
from
'./WebReader'
web/app/components/base/icons/src/vender/line/general/LinkExternal02.json
0 → 100644
View file @
23e34136
{
"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"
:
{
"id"
:
"link-external-02"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"id"
:
"Icon"
,
"d"
:
"M10.5 4.5L10.5 1.5M10.5 1.5H7.49999M10.5 1.5L6 6M5 1.5H3.9C3.05992 1.5 2.63988 1.5 2.31901 1.66349C2.03677 1.8073 1.8073 2.03677 1.66349 2.31901C1.5 2.63988 1.5 3.05992 1.5 3.9V8.1C1.5 8.94008 1.5 9.36012 1.66349 9.68099C1.8073 9.96323 2.03677 10.1927 2.31901 10.3365C2.63988 10.5 3.05992 10.5 3.9 10.5H8.1C8.94008 10.5 9.36012 10.5 9.68099 10.3365C9.96323 10.1927 10.1927 9.96323 10.3365 9.68099C10.5 9.36012 10.5 8.94008 10.5 8.1V7"
,
"stroke"
:
"currentColor"
,
"stroke-linecap"
:
"round"
,
"stroke-linejoin"
:
"round"
},
"children"
:
[]
}
]
}
]
},
"name"
:
"LinkExternal02"
}
\ No newline at end of file
web/app/components/base/icons/src/vender/line/general/LinkExternal02.tsx
0 → 100644
View file @
23e34136
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./LinkExternal02.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/vender/line/general/index.ts
View file @
23e34136
export
{
default
as
Check
}
from
'./Check'
export
{
default
as
LinkExternal02
}
from
'./LinkExternal02'
export
{
default
as
Loading02
}
from
'./Loading02'
export
{
default
as
LogOut01
}
from
'./LogOut01'
export
{
default
as
Trash03
}
from
'./Trash03'
...
...
web/app/components/base/icons/src/vender/solid/alertsAndFeedback/AlertCircle.json
0 → 100644
View file @
23e34136
{
"icon"
:
{
"type"
:
"element"
,
"isRootNode"
:
true
,
"name"
:
"svg"
,
"attributes"
:
{
"width"
:
"16"
,
"height"
:
"16"
,
"viewBox"
:
"0 0 16 16"
,
"fill"
:
"none"
,
"xmlns"
:
"http://www.w3.org/2000/svg"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"g"
,
"attributes"
:
{
"id"
:
"alert-circle"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"id"
:
"Solid"
,
"fill-rule"
:
"evenodd"
,
"clip-rule"
:
"evenodd"
,
"d"
:
"M8 0.666626C3.94992 0.666626 0.666672 3.94987 0.666672 7.99996C0.666672 12.05 3.94992 15.3333 8 15.3333C12.0501 15.3333 15.3333 12.05 15.3333 7.99996C15.3333 3.94987 12.0501 0.666626 8 0.666626ZM8.66667 5.33329C8.66667 4.9651 8.36819 4.66663 8 4.66663C7.63181 4.66663 7.33334 4.9651 7.33334 5.33329V7.99996C7.33334 8.36815 7.63181 8.66663 8 8.66663C8.36819 8.66663 8.66667 8.36815 8.66667 7.99996V5.33329ZM8 9.99996C7.63181 9.99996 7.33334 10.2984 7.33334 10.6666C7.33334 11.0348 7.63181 11.3333 8 11.3333H8.00667C8.37486 11.3333 8.67334 11.0348 8.67334 10.6666C8.67334 10.2984 8.37486 9.99996 8.00667 9.99996H8Z"
,
"fill"
:
"currentColor"
},
"children"
:
[]
}
]
}
]
},
"name"
:
"AlertCircle"
}
\ No newline at end of file
web/app/components/base/icons/src/vender/solid/alertsAndFeedback/AlertCircle.tsx
0 → 100644
View file @
23e34136
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./AlertCircle.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/vender/solid/alertsAndFeedback/index.ts
View file @
23e34136
export
{
default
as
AlertCircle
}
from
'./AlertCircle'
export
{
default
as
AlertTriangle
}
from
'./AlertTriangle'
web/app/components/base/icons/src/vender/solid/general/CheckCircle.json
0 → 100644
View file @
23e34136
{
"icon"
:
{
"type"
:
"element"
,
"isRootNode"
:
true
,
"name"
:
"svg"
,
"attributes"
:
{
"width"
:
"16"
,
"height"
:
"16"
,
"viewBox"
:
"0 0 16 16"
,
"fill"
:
"none"
,
"xmlns"
:
"http://www.w3.org/2000/svg"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"g"
,
"attributes"
:
{
"id"
:
"check-circle"
},
"children"
:
[
{
"type"
:
"element"
,
"name"
:
"path"
,
"attributes"
:
{
"id"
:
"Solid"
,
"fill-rule"
:
"evenodd"
,
"clip-rule"
:
"evenodd"
,
"d"
:
"M8 0.666626C3.94992 0.666626 0.666672 3.94987 0.666672 7.99996C0.666672 12.05 3.94992 15.3333 8 15.3333C12.0501 15.3333 15.3333 12.05 15.3333 7.99996C15.3333 3.94987 12.0501 0.666626 8 0.666626ZM11.4714 6.47136C11.7318 6.21101 11.7318 5.7889 11.4714 5.52855C11.2111 5.26821 10.7889 5.26821 10.5286 5.52855L7 9.05715L5.47141 7.52855C5.21106 7.2682 4.78895 7.2682 4.5286 7.52855C4.26825 7.7889 4.26825 8.21101 4.5286 8.47136L6.5286 10.4714C6.78895 10.7317 7.21106 10.7317 7.47141 10.4714L11.4714 6.47136Z"
,
"fill"
:
"currentColor"
},
"children"
:
[]
}
]
}
]
},
"name"
:
"CheckCircle"
}
\ No newline at end of file
web/app/components/base/icons/src/vender/solid/general/CheckCircle.tsx
0 → 100644
View file @
23e34136
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import
*
as
React
from
'react'
import
data
from
'./CheckCircle.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/vender/solid/general/index.ts
View file @
23e34136
export
{
default
as
CheckCircle
}
from
'./CheckCircle'
export
{
default
as
Download02
}
from
'./Download02'
export
{
default
as
XCircle
}
from
'./XCircle'
web/app/components/base/markdown.tsx
View file @
23e34136
import
ReactMarkdown
from
"react-markdown"
;
import
"katex/dist/katex.min.css"
;
import
RemarkMath
from
"remark-math"
;
import
RemarkBreaks
from
"remark-breaks"
;
import
RehypeKatex
from
"rehype-katex"
;
import
RemarkGfm
from
"remark-gfm"
;
import
ReactMarkdown
from
'react-markdown'
import
'katex/dist/katex.min.css'
import
RemarkMath
from
'remark-math'
import
RemarkBreaks
from
'remark-breaks'
import
RehypeKatex
from
'rehype-katex'
import
RemarkGfm
from
'remark-gfm'
import
SyntaxHighlighter
from
'react-syntax-highlighter'
import
{
atelierHeathLight
}
from
'react-syntax-highlighter/dist/esm/styles/hljs'
import
{
useRef
,
useState
,
RefObject
,
useEffect
}
from
"react"
;
import
type
{
RefObject
}
from
'react'
import
{
useEffect
,
useRef
,
useState
}
from
'react'
// import { copyToClipboard } from "../utils";
// https://txtfiddle.com/~hlshwya/extract-urls-from-text
// const urlRegex = /\b((https?|ftp|file):\/\/|(www|ftp)\.)[-A-Z0-9+&@#\/%?=~_|$!:,.;]*[A-Z0-9+&@#\/%=~_|$]/ig
// function highlightURL(content: string) {
// return content.replace(urlRegex, (url) => {
// // fix http:// in [] will be parsed to link agin
// const res = `[${url.replace('://', '://')}](${url})`
// return res
// })
// }
export
function
PreCode
(
props
:
{
children
:
any
})
{
const
ref
=
useRef
<
HTMLPreElement
>
(
null
)
;
const
ref
=
useRef
<
HTMLPreElement
>
(
null
)
return
(
<
pre
ref=
{
ref
}
>
...
...
@@ -18,38 +28,37 @@ export function PreCode(props: { children: any }) {
className=
"copy-code-button"
onClick=
{
()
=>
{
if
(
ref
.
current
)
{
const
code
=
ref
.
current
.
innerText
;
const
code
=
ref
.
current
.
innerText
// copyToClipboard(code);
}
}
}
></
span
>
{
props
.
children
}
</
pre
>
)
;
)
}
const
useLazyLoad
=
(
ref
:
RefObject
<
Element
>
):
boolean
=>
{
const
[
isIntersecting
,
setIntersecting
]
=
useState
<
boolean
>
(
false
)
;
const
[
isIntersecting
,
setIntersecting
]
=
useState
<
boolean
>
(
false
)
useEffect
(()
=>
{
const
observer
=
new
IntersectionObserver
(([
entry
])
=>
{
if
(
entry
.
isIntersecting
)
{
setIntersecting
(
true
)
;
observer
.
disconnect
()
;
setIntersecting
(
true
)
observer
.
disconnect
()
}
})
;
})
if
(
ref
.
current
)
{
observer
.
observe
(
ref
.
current
);
}
if
(
ref
.
current
)
observer
.
observe
(
ref
.
current
)
return
()
=>
{
observer
.
disconnect
()
;
}
;
},
[
ref
])
;
observer
.
disconnect
()
}
},
[
ref
])
return
isIntersecting
;
}
;
return
isIntersecting
}
export
function
Markdown
(
props
:
{
content
:
string
})
{
return
(
...
...
@@ -62,26 +71,29 @@ export function Markdown(props: { content: string }) {
components=
{
{
code
({
node
,
inline
,
className
,
children
,
...
props
})
{
const
match
=
/language-
(\w
+
)
/
.
exec
(
className
||
''
)
return
!
inline
&&
match
?
(
<
SyntaxHighlighter
{
...
props
}
children=
{
String
(
children
).
replace
(
/
\n
$/
,
''
)
}
style=
{
atelierHeathLight
}
language=
{
match
[
1
]
}
showLineNumbers
PreTag=
"div"
/>
)
:
(
<
code
{
...
props
}
className=
{
className
}
>
{
children
}
</
code
>
)
}
return
(
!
inline
&&
match
)
?
(
<
SyntaxHighlighter
{
...
props
}
children=
{
String
(
children
).
replace
(
/
\n
$/
,
''
)
}
style=
{
atelierHeathLight
}
language=
{
match
[
1
]
}
showLineNumbers
PreTag=
"div"
/>
)
:
(
<
code
{
...
props
}
className=
{
className
}
>
{
children
}
</
code
>
)
},
}
}
linkTarget=
{
"_blank"
}
linkTarget=
{
'_blank'
}
>
{
/* Markdown detect has problem. */
}
{
props
.
content
}
</
ReactMarkdown
>
</
div
>
)
;
)
}
web/app/components/base/toast/index.tsx
View file @
23e34136
...
...
@@ -9,7 +9,7 @@ import {
InformationCircleIcon
,
XCircleIcon
,
}
from
'@heroicons/react/20/solid'
import
{
createContext
}
from
'use-context-selector'
import
{
createContext
,
useContext
}
from
'use-context-selector'
export
type
IToastProps
=
{
type
?:
'success'
|
'error'
|
'warning'
|
'info'
...
...
@@ -24,6 +24,7 @@ type IToastContext = {
const
defaultDuring
=
3000
export
const
ToastContext
=
createContext
<
IToastContext
>
({}
as
IToastContext
)
export
const
useToastContext
=
()
=>
useContext
(
ToastContext
)
const
Toast
=
({
type
=
'info'
,
duration
,
...
...
@@ -31,9 +32,9 @@ const Toast = ({
children
,
}:
IToastProps
)
=>
{
// sometimes message is react node array. Not handle it.
if
(
typeof
message
!==
'string'
)
{
if
(
typeof
message
!==
'string'
)
return
null
}
return
<
div
className=
{
classNames
(
'fixed rounded-md p-4 my-4 mx-8 z-50'
,
'top-0'
,
...
...
web/app/components/base/voice-input/index.tsx
View file @
23e34136
...
...
@@ -86,7 +86,7 @@ const VoiceInput = ({
const
formData
=
new
FormData
()
formData
.
append
(
'file'
,
mp3File
)
let
url
=
''
let
url
=
'
/universal-chat/audio-to-text
'
let
isPublic
=
false
if
(
params
.
token
)
{
...
...
web/app/components/explore/sidebar/index.tsx
View file @
23e34136
...
...
@@ -14,13 +14,25 @@ import Confirm from '@/app/components/base/confirm'
const
SelectedDiscoveryIcon
=
()
=>
(
<
svg
width=
"16"
height=
"16"
viewBox=
"0 0 16 16"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<
path
fillRule=
"evenodd"
clipRule=
"evenodd"
d=
"M13.4135 1.11725C13.5091 1.09983 13.6483 1.08355 13.8078 1.11745C14.0143 1.16136 14.2017 1.26953 14.343 1.42647C14.4521 1.54766 14.5076 1.67634 14.5403 1.76781C14.5685 1.84673 14.593 1.93833 14.6136 2.01504L15.5533 5.5222C15.5739 5.5989 15.5985 5.69049 15.6135 5.77296C15.6309 5.86852 15.6472 6.00771 15.6133 6.16722C15.5694 6.37378 15.4612 6.56114 15.3043 6.70245C15.1831 6.81157 15.0544 6.86706 14.9629 6.89975C14.884 6.92796 14.7924 6.95247 14.7157 6.97299L14.676 6.98364C14.3365 7.07461 14.0437 7.15309 13.7972 7.19802C13.537 7.24543 13.2715 7.26736 12.9946 7.20849C12.7513 7.15677 12.5213 7.06047 12.3156 6.92591L9.63273 7.64477C9.86399 7.97104 9.99992 8.36965 9.99992 8.80001C9.99992 9.2424 9.85628 9.65124 9.6131 9.98245L12.5508 14.291C12.7582 14.5952 12.6797 15.01 12.3755 15.2174C12.0713 15.4248 11.6566 15.3464 11.4492 15.0422L8.51171 10.7339C8.34835 10.777 8.17682 10.8 7.99992 10.8C7.82305 10.8 7.65155 10.777 7.48823 10.734L4.5508 15.0422C4.34338 15.3464 3.92863 15.4248 3.62442 15.2174C3.32021 15.01 3.24175 14.5952 3.44916 14.291L6.3868 9.98254C6.14358 9.65132 5.99992 9.24244 5.99992 8.80001C5.99992 8.73795 6.00274 8.67655 6.00827 8.61594L4.59643 8.99424C4.51973 9.01483 4.42813 9.03941 4.34567 9.05444C4.25011 9.07185 4.11092 9.08814 3.95141 9.05423C3.74485 9.01033 3.55748 8.90215 3.41618 8.74522C3.38535 8.71097 3.3588 8.67614 3.33583 8.64171L2.49206 8.8678C2.41536 8.88838 2.32376 8.91296 2.2413 8.92799C2.14574 8.94541 2.00655 8.96169 1.84704 8.92779C1.64048 8.88388 1.45311 8.77571 1.31181 8.61877C1.20269 8.49759 1.1472 8.3689 1.1145 8.27744C1.08629 8.1985 1.06177 8.10689 1.04125 8.03018L0.791701 7.09885C0.771119 7.02215 0.746538 6.93055 0.731508 6.84809C0.714092 6.75253 0.697808 6.61334 0.731712 6.45383C0.775619 6.24726 0.883793 6.0599 1.04073 5.9186C1.16191 5.80948 1.2906 5.75399 1.38206 5.72129C1.461 5.69307 1.55261 5.66856 1.62932 5.64804L2.47318 5.42193C2.47586 5.38071 2.48143 5.33735 2.49099 5.29237C2.5349 5.08581 2.64307 4.89844 2.80001 4.75714C2.92119 4.64802 3.04988 4.59253 3.14134 4.55983C3.22027 4.53162 3.31189 4.50711 3.3886 4.48658L11.1078 2.41824C11.2186 2.19888 11.3697 2.00049 11.5545 1.83406C11.7649 1.64462 12.0058 1.53085 12.2548 1.44183C12.4907 1.35749 12.7836 1.27904 13.123 1.18809L13.1628 1.17744C13.2395 1.15686 13.3311 1.13228 13.4135 1.11725ZM13.3642 2.5039C13.0648 2.58443 12.8606 2.64126 12.7036 2.69735C12.5325 2.75852 12.4742 2.80016 12.4467 2.82492C12.3421 2.91912 12.2699 3.04403 12.2407 3.18174C12.233 3.21793 12.2261 3.28928 12.2587 3.46805C12.2927 3.6545 12.3564 3.89436 12.4559 4.26563L12.5594 4.652C12.6589 5.02328 12.7236 5.26287 12.7874 5.44133C12.8486 5.61244 12.8902 5.67079 12.915 5.69829C13.0092 5.80291 13.1341 5.87503 13.2718 5.9043C13.308 5.91199 13.3793 5.91887 13.5581 5.88629C13.7221 5.85641 13.9273 5.80352 14.2269 5.72356L13.3642 2.5039Z"
fill=
"#155EEF"
/>
<
path
fillRule=
"evenodd"
clipRule=
"evenodd"
d=
"M13.4135 1.11725C13.5091 1.09983 13.6483 1.08355 13.8078 1.11745C14.0143 1.16136 14.2017 1.26953 14.343 1.42647C14.4521 1.54766 14.5076 1.67634 14.5403 1.76781C14.5685 1.84673 14.593 1.93833 14.6136 2.01504L15.5533 5.5222C15.5739 5.5989 15.5985 5.69049 15.6135 5.77296C15.6309 5.86852 15.6472 6.00771 15.6133 6.16722C15.5694 6.37378 15.4612 6.56114 15.3043 6.70245C15.1831 6.81157 15.0544 6.86706 14.9629 6.89975C14.884 6.92796 14.7924 6.95247 14.7157 6.97299L14.676 6.98364C14.3365 7.07461 14.0437 7.15309 13.7972 7.19802C13.537 7.24543 13.2715 7.26736 12.9946 7.20849C12.7513 7.15677 12.5213 7.06047 12.3156 6.92591L9.63273 7.64477C9.86399 7.97104 9.99992 8.36965 9.99992 8.80001C9.99992 9.2424 9.85628 9.65124 9.6131 9.98245L12.5508 14.291C12.7582 14.5952 12.6797 15.01 12.3755 15.2174C12.0713 15.4248 11.6566 15.3464 11.4492 15.0422L8.51171 10.7339C8.34835 10.777 8.17682 10.8 7.99992 10.8C7.82305 10.8 7.65155 10.777 7.48823 10.734L4.5508 15.0422C4.34338 15.3464 3.92863 15.4248 3.62442 15.2174C3.32021 15.01 3.24175 14.5952 3.44916 14.291L6.3868 9.98254C6.14358 9.65132 5.99992 9.24244 5.99992 8.80001C5.99992 8.73795 6.00274 8.67655 6.00827 8.61594L4.59643 8.99424C4.51973 9.01483 4.42813 9.03941 4.34567 9.05444C4.25011 9.07185 4.11092 9.08814 3.95141 9.05423C3.74485 9.01033 3.55748 8.90215 3.41618 8.74522C3.38535 8.71097 3.3588 8.67614 3.33583 8.64171L2.49206 8.8678C2.41536 8.88838 2.32376 8.91296 2.2413 8.92799C2.14574 8.94541 2.00655 8.96169 1.84704 8.92779C1.64048 8.88388 1.45311 8.77571 1.31181 8.61877C1.20269 8.49759 1.1472 8.3689 1.1145 8.27744C1.08629 8.1985 1.06177 8.10689 1.04125 8.03018L0.791701 7.09885C0.771119 7.02215 0.746538 6.93055 0.731508 6.84809C0.714092 6.75253 0.697808 6.61334 0.731712 6.45383C0.775619 6.24726 0.883793 6.0599 1.04073 5.9186C1.16191 5.80948 1.2906 5.75399 1.38206 5.72129C1.461 5.69307 1.55261 5.66856 1.62932 5.64804L2.47318 5.42193C2.47586 5.38071 2.48143 5.33735 2.49099 5.29237C2.5349 5.08581 2.64307 4.89844 2.80001 4.75714C2.92119 4.64802 3.04988 4.59253 3.14134 4.55983C3.22027 4.53162 3.31189 4.50711 3.3886 4.48658L11.1078 2.41824C11.2186 2.19888 11.3697 2.00049 11.5545 1.83406C11.7649 1.64462 12.0058 1.53085 12.2548 1.44183C12.4907 1.35749 12.7836 1.27904 13.123 1.18809L13.1628 1.17744C13.2395 1.15686 13.3311 1.13228 13.4135 1.11725ZM13.3642 2.5039C13.0648 2.58443 12.8606 2.64126 12.7036 2.69735C12.5325 2.75852 12.4742 2.80016 12.4467 2.82492C12.3421 2.91912 12.2699 3.04403 12.2407 3.18174C12.233 3.21793 12.2261 3.28928 12.2587 3.46805C12.2927 3.6545 12.3564 3.89436 12.4559 4.26563L12.5594 4.652C12.6589 5.02328 12.7236 5.26287 12.7874 5.44133C12.8486 5.61244 12.8902 5.67079 12.915 5.69829C13.0092 5.80291 13.1341 5.87503 13.2718 5.9043C13.308 5.91199 13.3793 5.91887 13.5581 5.88629C13.7221 5.85641 13.9273 5.80352 14.2269 5.72356L13.3642 2.5039Z"
fill=
"#155EEF"
/>
</
svg
>
)
const
DiscoveryIcon
=
()
=>
(
<
svg
width=
"16"
height=
"16"
viewBox=
"0 0 16 16"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<
path
d=
"M8.74786 9.89676L12.0003 14.6669M7.25269 9.89676L4.00027 14.6669M9.3336 8.80031C9.3336 9.53669 8.73665 10.1336 8.00027 10.1336C7.26389 10.1336 6.66694 9.53669 6.66694 8.80031C6.66694 8.06393 7.26389 7.46698 8.00027 7.46698C8.73665 7.46698 9.3336 8.06393 9.3336 8.80031ZM11.4326 3.02182L3.57641 5.12689C3.39609 5.1752 3.30593 5.19936 3.24646 5.25291C3.19415 5.30001 3.15809 5.36247 3.14345 5.43132C3.12681 5.5096 3.15097 5.59976 3.19929 5.78008L3.78595 7.96951C3.83426 8.14984 3.85842 8.24 3.91197 8.29947C3.95907 8.35178 4.02153 8.38784 4.09038 8.40248C4.16866 8.41911 4.25882 8.39496 4.43914 8.34664L12.2953 6.24158L11.4326 3.02182ZM14.5285 6.33338C13.8072 6.52665 13.4466 6.62328 13.1335 6.55673C12.8581 6.49819 12.6082 6.35396 12.4198 6.14471C12.2056 5.90682 12.109 5.54618 11.9157 4.82489L11.8122 4.43852C11.6189 3.71722 11.5223 3.35658 11.5889 3.04347C11.6474 2.76805 11.7916 2.51823 12.0009 2.32982C12.2388 2.11563 12.5994 2.019 13.3207 1.82573C13.501 1.77741 13.5912 1.75325 13.6695 1.76989C13.7383 1.78452 13.8008 1.82058 13.8479 1.87289C13.9014 1.93237 13.9256 2.02253 13.9739 2.20285L14.9057 5.68018C14.954 5.86051 14.9781 5.95067 14.9615 6.02894C14.9469 6.0978 14.9108 6.16025 14.8585 6.20736C14.799 6.2609 14.7088 6.28506 14.5285 6.33338ZM2.33475 8.22033L3.23628 7.97876C3.4166 7.93044 3.50676 7.90628 3.56623 7.85274C3.61854 7.80563 3.6546 7.74318 3.66924 7.67433C3.68588 7.59605 3.66172 7.50589 3.6134 7.32556L3.37184 6.42403C3.32352 6.24371 3.29936 6.15355 3.24581 6.09408C3.19871 6.04176 3.13626 6.00571 3.0674 5.99107C2.98912 5.97443 2.89896 5.99859 2.71864 6.04691L1.81711 6.28847C1.63678 6.33679 1.54662 6.36095 1.48715 6.4145C1.43484 6.4616 1.39878 6.52405 1.38415 6.59291C1.36751 6.67119 1.39167 6.76135 1.43998 6.94167L1.68155 7.8432C1.72987 8.02352 1.75402 8.11369 1.80757 8.17316C1.85467 8.22547 1.91713 8.26153 1.98598 8.27616C2.06426 8.2928 2.15442 8.26864 2.33475 8.22033Z"
stroke=
"#344054"
strokeWidth=
"1.25"
strokeLinecap=
"round"
strokeLinejoin=
"round"
/>
<
path
d=
"M8.74786 9.89676L12.0003 14.6669M7.25269 9.89676L4.00027 14.6669M9.3336 8.80031C9.3336 9.53669 8.73665 10.1336 8.00027 10.1336C7.26389 10.1336 6.66694 9.53669 6.66694 8.80031C6.66694 8.06393 7.26389 7.46698 8.00027 7.46698C8.73665 7.46698 9.3336 8.06393 9.3336 8.80031ZM11.4326 3.02182L3.57641 5.12689C3.39609 5.1752 3.30593 5.19936 3.24646 5.25291C3.19415 5.30001 3.15809 5.36247 3.14345 5.43132C3.12681 5.5096 3.15097 5.59976 3.19929 5.78008L3.78595 7.96951C3.83426 8.14984 3.85842 8.24 3.91197 8.29947C3.95907 8.35178 4.02153 8.38784 4.09038 8.40248C4.16866 8.41911 4.25882 8.39496 4.43914 8.34664L12.2953 6.24158L11.4326 3.02182ZM14.5285 6.33338C13.8072 6.52665 13.4466 6.62328 13.1335 6.55673C12.8581 6.49819 12.6082 6.35396 12.4198 6.14471C12.2056 5.90682 12.109 5.54618 11.9157 4.82489L11.8122 4.43852C11.6189 3.71722 11.5223 3.35658 11.5889 3.04347C11.6474 2.76805 11.7916 2.51823 12.0009 2.32982C12.2388 2.11563 12.5994 2.019 13.3207 1.82573C13.501 1.77741 13.5912 1.75325 13.6695 1.76989C13.7383 1.78452 13.8008 1.82058 13.8479 1.87289C13.9014 1.93237 13.9256 2.02253 13.9739 2.20285L14.9057 5.68018C14.954 5.86051 14.9781 5.95067 14.9615 6.02894C14.9469 6.0978 14.9108 6.16025 14.8585 6.20736C14.799 6.2609 14.7088 6.28506 14.5285 6.33338ZM2.33475 8.22033L3.23628 7.97876C3.4166 7.93044 3.50676 7.90628 3.56623 7.85274C3.61854 7.80563 3.6546 7.74318 3.66924 7.67433C3.68588 7.59605 3.66172 7.50589 3.6134 7.32556L3.37184 6.42403C3.32352 6.24371 3.29936 6.15355 3.24581 6.09408C3.19871 6.04176 3.13626 6.00571 3.0674 5.99107C2.98912 5.97443 2.89896 5.99859 2.71864 6.04691L1.81711 6.28847C1.63678 6.33679 1.54662 6.36095 1.48715 6.4145C1.43484 6.4616 1.39878 6.52405 1.38415 6.59291C1.36751 6.67119 1.39167 6.76135 1.43998 6.94167L1.68155 7.8432C1.72987 8.02352 1.75402 8.11369 1.80757 8.17316C1.85467 8.22547 1.91713 8.26153 1.98598 8.27616C2.06426 8.2928 2.15442 8.26864 2.33475 8.22033Z"
stroke=
"#344054"
strokeWidth=
"1.25"
strokeLinecap=
"round"
strokeLinejoin=
"round"
/>
</
svg
>
)
const
SelectedChatIcon
=
()
=>
(
<
svg
width=
"16"
height=
"16"
viewBox=
"0 0 16 16"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<
path
fillRule=
"evenodd"
clipRule=
"evenodd"
d=
"M8.00016 1.3335C4.31826 1.3335 1.3335 4.31826 1.3335 8.00016C1.3335 8.88571 1.50651 9.7325 1.8212 10.5074C1.84962 10.5773 1.86597 10.6178 1.87718 10.6476L1.88058 10.6568L1.88016 10.66C1.87683 10.6846 1.87131 10.7181 1.86064 10.7821L1.46212 13.1732C1.44424 13.2803 1.42423 13.4001 1.41638 13.5041C1.40782 13.6176 1.40484 13.7981 1.48665 13.9888C1.58779 14.2246 1.77569 14.4125 2.0115 14.5137C2.20224 14.5955 2.38274 14.5925 2.49619 14.5839C2.60025 14.5761 2.72006 14.5561 2.82715 14.5382L5.2182 14.1397C5.28222 14.129 5.31576 14.1235 5.34036 14.1202L5.34353 14.1197L5.35274 14.1231C5.38258 14.1344 5.42298 14.1507 5.49297 14.1791C6.26783 14.4938 7.11462 14.6668 8.00016 14.6668C11.6821 14.6668 14.6668 11.6821 14.6668 8.00016C14.6668 4.31826 11.6821 1.3335 8.00016 1.3335ZM4.00016 8.00016C4.00016 7.44788 4.44788 7.00016 5.00016 7.00016C5.55245 7.00016 6.00016 7.44788 6.00016 8.00016C6.00016 8.55245 5.55245 9.00016 5.00016 9.00016C4.44788 9.00016 4.00016 8.55245 4.00016 8.00016ZM7.00016 8.00016C7.00016 7.44788 7.44788 7.00016 8.00016 7.00016C8.55245 7.00016 9.00016 7.44788 9.00016 8.00016C9.00016 8.55245 8.55245 9.00016 8.00016 9.00016C7.44788 9.00016 7.00016 8.55245 7.00016 8.00016ZM11.0002 7.00016C10.4479 7.00016 10.0002 7.44788 10.0002 8.00016C10.0002 8.55245 10.4479 9.00016 11.0002 9.00016C11.5524 9.00016 12.0002 8.55245 12.0002 8.00016C12.0002 7.44788 11.5524 7.00016 11.0002 7.00016Z"
fill=
"#155EEF"
/>
</
svg
>
)
const
ChatIcon
=
()
=>
(
<
svg
width=
"16"
height=
"16"
viewBox=
"0 0 16 16"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<
path
d=
"M5 8H5.00667M8 8H8.00667M11 8H11.0067M8 14C11.3137 14 14 11.3137 14 8C14 4.68629 11.3137 2 8 2C4.68629 2 2 4.68629 2 8C2 8.7981 2.15582 9.5598 2.43871 10.2563C2.49285 10.3897 2.51992 10.4563 2.532 10.5102C2.54381 10.5629 2.54813 10.6019 2.54814 10.6559C2.54814 10.7111 2.53812 10.7713 2.51807 10.8916L2.12275 13.2635C2.08135 13.5119 2.06065 13.6361 2.09917 13.7259C2.13289 13.8045 2.19552 13.8671 2.27412 13.9008C2.36393 13.9393 2.48812 13.9186 2.73651 13.8772L5.10843 13.4819C5.22872 13.4619 5.28887 13.4519 5.34409 13.4519C5.3981 13.4519 5.43711 13.4562 5.48981 13.468C5.54369 13.4801 5.61035 13.5072 5.74366 13.5613C6.4402 13.8442 7.2019 14 8 14ZM5.33333 8C5.33333 8.1841 5.1841 8.33333 5 8.33333C4.81591 8.33333 4.66667 8.1841 4.66667 8C4.66667 7.81591 4.81591 7.66667 5 7.66667C5.1841 7.66667 5.33333 7.81591 5.33333 8ZM8.33333 8C8.33333 8.1841 8.1841 8.33333 8 8.33333C7.81591 8.33333 7.66667 8.1841 7.66667 8C7.66667 7.81591 7.81591 7.66667 8 7.66667C8.1841 7.66667 8.33333 7.81591 8.33333 8ZM11.3333 8C11.3333 8.1841 11.1841 8.33333 11 8.33333C10.8159 8.33333 10.6667 8.1841 10.6667 8C10.6667 7.81591 10.8159 7.66667 11 7.66667C11.1841 7.66667 11.3333 7.81591 11.3333 8Z"
stroke=
"#344054"
stroke
-
width=
"1.25"
stroke
-
linecap=
"round"
stroke
-
linejoin=
"round"
/>
</
svg
>
)
...
...
@@ -33,6 +45,7 @@ const SideBar: FC<{
const
segments
=
useSelectedLayoutSegments
()
const
lastSegment
=
segments
.
slice
(
-
1
)[
0
]
const
isDiscoverySelected
=
lastSegment
===
'apps'
const
isChatSelected
=
lastSegment
===
'chat'
const
{
installedApps
,
setInstalledApps
}
=
useContext
(
ExploreContext
)
const
fetchInstalledAppList
=
async
()
=>
{
...
...
@@ -81,6 +94,14 @@ const SideBar: FC<{
{
isDiscoverySelected
?
<
SelectedDiscoveryIcon
/>
:
<
DiscoveryIcon
/>
}
<
div
className=
'text-sm'
>
{
t
(
'explore.sidebar.discovery'
)
}
</
div
>
</
Link
>
<
Link
href=
'/explore/chat'
className=
{
cn
(
isChatSelected
?
'text-primary-600 bg-white font-semibold'
:
'text-gray-700 font-medium'
,
'flex items-center h-9 pl-3 space-x-2 rounded-lg'
)
}
style=
{
isChatSelected
?
{
boxShadow
:
'0px 1px 2px rgba(16, 24, 40, 0.05)'
}
:
{}
}
>
{
isChatSelected
?
<
SelectedChatIcon
/>
:
<
ChatIcon
/>
}
<
div
className=
'text-sm'
>
{
t
(
'explore.sidebar.chat'
)
}
</
div
>
</
Link
>
</
div
>
{
installedApps
.
length
>
0
&&
(
<
div
className=
'mt-10'
>
...
...
web/app/components/explore/universal-chat/config-view/detail/index.tsx
0 → 100644
View file @
23e34136
'use client'
import
type
{
FC
}
from
'react'
import
React
from
'react'
import
cn
from
'classnames'
import
{
useTranslation
}
from
'react-i18next'
import
s
from
'./style.module.css'
import
Config
from
'@/app/components/explore/universal-chat/config'
type
Props
=
{
modelId
:
string
plugins
:
Record
<
string
,
boolean
>
dataSets
:
any
[]
}
const
ConfigViewPanel
:
FC
<
Props
>
=
({
modelId
,
plugins
,
dataSets
,
})
=>
{
const
{
t
}
=
useTranslation
()
return
(
<
div
className=
{
cn
(
'absolute top-9 right-0 z-20 p-4 bg-white rounded-2xl shadow-md'
,
s
.
panelBorder
)
}
>
<
div
className=
'w-[368px]'
>
<
Config
readonly
modelId=
{
modelId
}
plugins=
{
plugins
}
dataSets=
{
dataSets
}
/>
<
div
className=
'mt-3 text-xs leading-[18px] text-500 font-normal'
>
{
t
(
'explore.universalChat.viewConfigDetailTip'
)
}
</
div
>
</
div
>
</
div
>
)
}
export
default
React
.
memo
(
ConfigViewPanel
)
web/app/components/explore/universal-chat/config-view/detail/style.module.css
0 → 100644
View file @
23e34136
.btn
{
background
:
url(~@/app/components/datasets/documents/assets/action.svg)
center
center
no-repeat
transparent
;
background-size
:
16px
16px
;
/* mask-image: ; */
}
.panelBorder
{
border
:
0.5px
solid
rgba
(
0
,
0
,
0
,
.05
);
}
\ No newline at end of file
web/app/components/explore/universal-chat/config-view/summary/index.tsx
0 → 100644
View file @
23e34136
'use client'
import
type
{
FC
}
from
'react'
import
React
from
'react'
import
cn
from
'classnames'
import
{
useBoolean
,
useClickAway
}
from
'ahooks'
import
s
from
'./style.module.css'
import
ModelIcon
from
'@/app/components/app/configuration/config-model/model-icon'
import
{
Google
,
WebReader
,
Wikipedia
}
from
'@/app/components/base/icons/src/public/plugins'
import
ConfigDetail
from
'@/app/components/explore/universal-chat/config-view/detail'
export
type
ISummaryProps
=
{
modelId
:
string
plugins
:
Record
<
string
,
boolean
>
dataSets
:
any
[]
}
const
getColorInfo
=
(
modelId
:
string
)
=>
{
if
(
modelId
===
'gpt-4'
)
return
s
.
gpt4
if
(
modelId
===
'claude-2'
)
return
s
.
claude
return
s
.
gpt3
}
const
getPlugIcon
=
(
pluginId
:
string
)
=>
{
const
className
=
'w-4 h-4'
switch
(
pluginId
)
{
case
'google_search'
:
return
<
Google
className=
{
className
}
/>
case
'web_reader'
:
return
<
WebReader
className=
{
className
}
/>
case
'wikipedia'
:
return
<
Wikipedia
className=
{
className
}
/>
default
:
return
null
}
}
const
Summary
:
FC
<
ISummaryProps
>
=
({
modelId
,
plugins
,
dataSets
,
})
=>
{
const
pluginIds
=
Object
.
keys
(
plugins
).
filter
(
key
=>
plugins
[
key
])
const
[
isShowConfig
,
{
setFalse
:
hideConfig
,
toggle
:
toggleShowConfig
}]
=
useBoolean
(
false
)
const
configContentRef
=
React
.
useRef
(
null
)
useClickAway
(()
=>
{
hideConfig
()
},
configContentRef
)
return
(
<
div
ref=
{
configContentRef
}
className=
'relative'
>
<
div
onClick=
{
toggleShowConfig
}
className=
{
cn
(
getColorInfo
(
modelId
),
'flex items-center px-1 h-8 rounded-lg border cursor-pointer'
)
}
>
<
ModelIcon
modelId=
{
modelId
}
className=
'!w-6 !h-6'
/>
<
div
className=
'ml-2 text-[13px] font-medium text-gray-900'
>
{
modelId
}
</
div
>
{
pluginIds
.
length
>
0
&&
(
<
div
className=
'ml-1.5 flex items-center'
>
<
div
className=
'mr-1 h-3 w-[1px] bg-[#000] opacity-[0.05]'
></
div
>
<
div
className=
'flex space-x-1'
>
{
pluginIds
.
map
(
pluginId
=>
(
<
div
key=
{
pluginId
}
className=
{
`flex items-center justify-center w-6 h-6 rounded-md ${s.border} bg-white`
}
>
{
getPlugIcon
(
pluginId
)
}
</
div
>
))
}
</
div
>
</
div
>
)
}
</
div
>
{
isShowConfig
&&
(
<
ConfigDetail
modelId=
{
modelId
}
plugins=
{
plugins
}
dataSets=
{
dataSets
}
/>
)
}
</
div
>
)
}
export
default
React
.
memo
(
Summary
)
web/app/components/explore/universal-chat/config-view/summary/style.module.css
0 → 100644
View file @
23e34136
.border
{
border
:
1px
solid
rgba
(
0
,
0
,
0
,
0.05
);
}
.gpt3
{
background
:
linear-gradient
(
0deg
,
#D3F8DF
,
#D3F8DF
),
linear-gradient
(
0deg
,
#EDFCF2
,
#EDFCF2
);
border
:
1px
solid
rgba
(
211
,
248
,
223
,
1
)
}
.gpt4
{
background
:
linear-gradient
(
0deg
,
#EBE9FE
,
#EBE9FE
),
linear-gradient
(
0deg
,
#F4F3FF
,
#F4F3FF
);
border
:
1px
solid
rgba
(
235
,
233
,
254
,
1
)
}
.claude
{
background
:
linear-gradient
(
0deg
,
#F9EBDF
,
#F9EBDF
),
linear-gradient
(
0deg
,
#FCF3EB
,
#FCF3EB
);
border
:
1px
solid
rgba
(
249
,
235
,
223
,
1
)
}
\ No newline at end of file
web/app/components/explore/universal-chat/config/data-config/index.tsx
0 → 100644
View file @
23e34136
'use client'
import
type
{
FC
}
from
'react'
import
React
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
{
useBoolean
}
from
'ahooks'
import
{
isEqual
}
from
'lodash-es'
import
produce
from
'immer'
import
FeaturePanel
from
'@/app/components/app/configuration/base/feature-panel'
import
OperationBtn
from
'@/app/components/app/configuration/base/operation-btn'
import
CardItem
from
'@/app/components/app/configuration/dataset-config/card-item'
import
SelectDataSet
from
'@/app/components/app/configuration/dataset-config/select-dataset'
import
type
{
DataSet
}
from
'@/models/datasets'
type
Props
=
{
readonly
?:
boolean
dataSets
:
DataSet
[]
onChange
?:
(
data
:
DataSet
[])
=>
void
}
const
DatasetConfig
:
FC
<
Props
>
=
({
readonly
,
dataSets
,
onChange
,
})
=>
{
const
{
t
}
=
useTranslation
()
const
selectedIds
=
dataSets
.
map
(
item
=>
item
.
id
)
const
hasData
=
dataSets
.
length
>
0
const
[
isShowSelectDataSet
,
{
setTrue
:
showSelectDataSet
,
setFalse
:
hideSelectDataSet
}]
=
useBoolean
(
false
)
const
handleSelect
=
(
data
:
DataSet
[])
=>
{
if
(
isEqual
(
data
.
map
(
item
=>
item
.
id
),
dataSets
.
map
(
item
=>
item
.
id
)))
{
hideSelectDataSet
()
return
}
if
(
data
.
find
(
item
=>
!
item
.
name
))
{
// has not loaded selected dataset
const
newSelected
=
produce
(
data
,
(
draft
)
=>
{
data
.
forEach
((
item
,
index
)
=>
{
if
(
!
item
.
name
)
{
// not fetched database
const
newItem
=
dataSets
.
find
(
i
=>
i
.
id
===
item
.
id
)
if
(
newItem
)
draft
[
index
]
=
newItem
}
})
})
onChange
?.(
newSelected
)
}
else
{
onChange
?.(
data
)
}
hideSelectDataSet
()
}
const
onRemove
=
(
id
:
string
)
=>
{
onChange
?.(
dataSets
.
filter
(
item
=>
item
.
id
!==
id
))
}
return
(
<
FeaturePanel
className=
'mt-3'
title=
{
t
(
'appDebug.feature.dataSet.title'
)
}
headerRight=
{
!
readonly
&&
<
OperationBtn
type=
"add"
onClick=
{
showSelectDataSet
}
/>
}
hasHeaderBottomBorder=
{
!
hasData
}
>
{
hasData
?
(
<
div
className=
'max-h-[220px] overflow-y-auto'
>
{
dataSets
.
map
(
item
=>
(
<
CardItem
className=
"mb-2 !w-full"
key=
{
item
.
id
}
config=
{
item
}
onRemove=
{
onRemove
}
readonly=
{
readonly
}
// TODO: readonly remove btn
/>
))
}
</
div
>
)
:
(
<
div
className=
'pt-2 pb-1 text-xs text-gray-500'
>
{
t
(
'appDebug.feature.dataSet.noData'
)
}
</
div
>
)
}
{
isShowSelectDataSet
&&
(
<
SelectDataSet
isShow=
{
isShowSelectDataSet
}
onClose=
{
hideSelectDataSet
}
selectedIds=
{
selectedIds
}
onSelect=
{
handleSelect
}
/>
)
}
</
FeaturePanel
>
)
}
export
default
React
.
memo
(
DatasetConfig
)
web/app/components/explore/universal-chat/config/index.tsx
0 → 100644
View file @
23e34136
'use client'
import
type
{
FC
}
from
'react'
import
React
from
'react'
import
ModelConfig
from
'./model-config'
import
DataConfig
from
'./data-config'
import
PluginConfig
from
'./plugins-config'
export
type
IConfigProps
=
{
className
?:
string
readonly
?:
boolean
modelId
:
string
onModelChange
?:
(
modelId
:
string
)
=>
void
plugins
:
Record
<
string
,
boolean
>
onPluginChange
?:
(
key
:
string
,
value
:
boolean
)
=>
void
dataSets
:
any
[]
onDataSetsChange
?:
(
contexts
:
any
[])
=>
void
}
const
Config
:
FC
<
IConfigProps
>
=
({
className
,
readonly
,
modelId
,
onModelChange
,
plugins
,
onPluginChange
,
dataSets
,
onDataSetsChange
,
})
=>
{
return
(
<
div
className=
{
className
}
>
<
ModelConfig
readonly=
{
readonly
}
modelId=
{
modelId
}
onChange=
{
onModelChange
}
/>
<
PluginConfig
readonly=
{
readonly
}
config=
{
plugins
}
onChange=
{
onPluginChange
}
/>
{
(
!
readonly
||
(
readonly
&&
dataSets
.
length
>
0
))
&&
(
<
DataConfig
readonly=
{
readonly
}
dataSets=
{
dataSets
}
onChange=
{
onDataSetsChange
}
/>
)
}
</
div
>
)
}
export
default
React
.
memo
(
Config
)
web/app/components/explore/universal-chat/config/model-config/index.tsx
0 → 100644
View file @
23e34136
'use client'
import
type
{
FC
}
from
'react'
import
React
from
'react'
import
cn
from
'classnames'
import
{
useBoolean
,
useClickAway
}
from
'ahooks'
import
{
ChevronDownIcon
}
from
'@heroicons/react/24/outline'
import
{
useTranslation
}
from
'react-i18next'
import
ModelIcon
from
'@/app/components/app/configuration/config-model/model-icon'
import
{
UNIVERSAL_CHAT_MODEL_LIST
as
MODEL_LIST
}
from
'@/config'
import
{
Checked
as
CheckedIcon
}
from
'@/app/components/base/icons/src/public/model'
export
type
IModelConfigProps
=
{
modelId
:
string
onChange
?:
(
model
:
string
)
=>
void
readonly
?:
boolean
}
const
ModelConfig
:
FC
<
IModelConfigProps
>
=
({
modelId
,
onChange
,
readonly
,
})
=>
{
const
{
t
}
=
useTranslation
()
const
currModel
=
MODEL_LIST
.
find
(
item
=>
item
.
id
===
modelId
)
const
[
isShowOption
,
{
setFalse
:
hideOption
,
toggle
:
toogleOption
}]
=
useBoolean
(
false
)
const
triggerRef
=
React
.
useRef
(
null
)
useClickAway
(()
=>
{
hideOption
()
},
triggerRef
)
return
(
<
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'
>
{
t
(
'explore.universalChat.model'
)
}
</
div
>
<
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'
,
isShowOption
&&
'bg-gray-100'
,
)
}
>
<
ModelIcon
modelId=
{
currModel
?.
id
as
string
}
/>
<
div
className=
"text-sm gray-900"
>
{
currModel
?.
name
}
</
div
>
{
!
readonly
&&
<
ChevronDownIcon
className=
{
cn
(
isShowOption
&&
'rotate-180'
,
'w-[14px] h-[14px] text-gray-500'
)
}
/>
}
</
div
>
{
isShowOption
&&
(
<
div
className=
{
cn
(
'absolute top-10 right-0 bg-white rounded-lg shadow'
)
}
>
{
MODEL_LIST
.
map
(
item
=>
(
<
div
key=
{
item
.
id
}
onClick=
{
()
=>
onChange
?.(
item
.
id
)
}
className=
"w-[232px] flex items-center h-9 px-4 rounded-lg cursor-pointer hover:bg-gray-100"
>
<
ModelIcon
className=
'shrink-0 mr-2'
modelId=
{
item
?.
id
}
/>
<
div
className=
"text-sm gray-900 whitespace-nowrap"
>
{
item
.
name
}
</
div
>
{
(
item
.
id
===
currModel
?.
id
)
&&
<
CheckedIcon
className=
'absolute right-4'
/>
}
</
div
>
))
}
</
div
>
)
}
</
div
>
</
div
>
)
}
export
default
React
.
memo
(
ModelConfig
)
web/app/components/explore/universal-chat/config/plugins-config/index.tsx
0 → 100644
View file @
23e34136
'use client'
import
type
{
FC
}
from
'react'
import
React
,
{
useEffect
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
Item
from
'./item'
import
FeaturePanel
from
'@/app/components/app/configuration/base/feature-panel'
import
{
Google
,
WebReader
,
Wikipedia
}
from
'@/app/components/base/icons/src/public/plugins'
import
{
getToolProviders
}
from
'@/service/explore'
import
Loading
from
'@/app/components/base/loading'
import
AccountSetting
from
'@/app/components/header/account-setting'
export
type
IPluginsProps
=
{
readonly
?:
boolean
config
:
Record
<
string
,
boolean
>
onChange
?:
(
key
:
string
,
value
:
boolean
)
=>
void
}
const
plugins
=
[
{
key
:
'google_search'
,
icon
:
<
Google
/>
},
{
key
:
'web_reader'
,
icon
:
<
WebReader
/>
},
{
key
:
'wikipedia'
,
icon
:
<
Wikipedia
/>
},
]
const
Plugins
:
FC
<
IPluginsProps
>
=
({
readonly
,
config
,
onChange
,
})
=>
{
const
{
t
}
=
useTranslation
()
const
[
isLoading
,
setIsLoading
]
=
React
.
useState
(
!
readonly
)
const
[
isSerpApiValid
,
setIsSerpApiValid
]
=
React
.
useState
(
false
)
const
checkSerpApiKey
=
async
()
=>
{
if
(
readonly
)
return
const
provides
:
any
=
await
getToolProviders
()
const
isSerpApiValid
=
!!
provides
.
find
((
v
:
any
)
=>
v
.
tool_name
===
'serpapi'
&&
v
.
is_enabled
)
setIsSerpApiValid
(
isSerpApiValid
)
setIsLoading
(
false
)
}
useEffect
(()
=>
{
checkSerpApiKey
()
},
[])
const
[
showSetSerpAPIKeyModal
,
setShowSetAPIKeyModal
]
=
React
.
useState
(
false
)
const
itemConfigs
=
plugins
.
map
((
plugin
)
=>
{
const
res
:
Record
<
string
,
any
>
=
{
...
plugin
}
const
{
key
}
=
plugin
res
.
name
=
t
(
`explore.universalChat.plugins.
${
key
}
.name`
)
if
(
key
===
'web_reader'
)
res
.
description
=
t
(
`explore.universalChat.plugins.
${
key
}
.description`
)
if
(
key
===
'google_search'
&&
!
isSerpApiValid
&&
!
readonly
)
{
res
.
readonly
=
true
res
.
more
=
(
<
div
className=
'border-t border-[#FEF0C7] flex items-center h-[34px] pl-2 bg-[#FFFAEB] text-gray-700 text-xs '
>
<
span
className=
'whitespace-pre'
>
{
t
(
'explore.universalChat.plugins.google_search.more.left'
)
}
</
span
>
<
span
className=
'cursor-pointer text-[#155EEF]'
onClick=
{
()
=>
setShowSetAPIKeyModal
(
true
)
}
>
{
t
(
'explore.universalChat.plugins.google_search.more.link'
)
}
</
span
>
<
span
className=
'whitespace-pre'
>
{
t
(
'explore.universalChat.plugins.google_search.more.right'
)
}
</
span
>
</
div
>
)
}
return
res
})
const
enabledPluginNum
=
Object
.
values
(
config
).
filter
(
v
=>
v
).
length
return
(
<>
<
FeaturePanel
className=
'mt-3'
title=
{
<
div
className=
'flex space-x-1'
>
<
div
>
{
t
(
'explore.universalChat.plugins.name'
)
}
</
div
>
<
div
className=
'text-[13px] font-normal text-gray-500'
>
(
{
enabledPluginNum
}
/
{
plugins
.
length
}
)
</
div
>
</
div
>
}
hasHeaderBottomBorder=
{
false
}
>
{
isLoading
?
(
<
div
className=
'flex items-center h-[166px]'
>
<
Loading
type=
'area'
/>
</
div
>
)
:
(<
div
className=
'space-y-2'
>
{
itemConfigs
.
map
(
item
=>
(
<
Item
key=
{
item
.
key
}
icon=
{
item
.
icon
}
name=
{
item
.
name
}
description=
{
item
.
description
}
more=
{
item
.
more
}
enabled=
{
config
[
item
.
key
]
}
onChange=
{
enabled
=>
onChange
?.(
item
.
key
,
enabled
)
}
readonly=
{
readonly
||
item
.
readonly
}
/>
))
}
</
div
>)
}
</
FeaturePanel
>
{
showSetSerpAPIKeyModal
&&
(
<
AccountSetting
activeTab=
"plugin"
onCancel=
{
async
()
=>
{
setShowSetAPIKeyModal
(
false
)
await
checkSerpApiKey
()
}
}
/>
)
}
</>
)
}
export
default
React
.
memo
(
Plugins
)
web/app/components/explore/universal-chat/config/plugins-config/item.module.css
0 → 100644
View file @
23e34136
.shadow
{
box-shadow
:
0px
1px
2px
0px
rgba
(
16
,
24
,
40
,
0.05
);
}
\ No newline at end of file
web/app/components/explore/universal-chat/config/plugins-config/item.tsx
0 → 100644
View file @
23e34136
'use client'
import
type
{
FC
}
from
'react'
import
React
from
'react'
import
cn
from
'classnames'
import
s
from
'./item.module.css'
import
Switch
from
'@/app/components/base/switch'
export
type
IItemProps
=
{
icon
:
React
.
ReactNode
name
:
string
description
?:
string
more
?:
React
.
ReactNode
enabled
:
boolean
onChange
:
(
enabled
:
boolean
)
=>
void
readonly
?:
boolean
}
const
Item
:
FC
<
IItemProps
>
=
({
icon
,
name
,
description
,
more
,
enabled
,
onChange
,
readonly
,
})
=>
{
return
(
<
div
className=
{
cn
(
'bg-white rounded-xl border border-gray-200 overflow-hidden'
,
s
.
shadow
)
}
>
<
div
className=
'flex justify-between items-center min-h-[48px] px-2'
>
<
div
className=
'flex items-center space-x-2'
>
{
icon
}
<
div
className=
'leading-[18px]'
>
<
div
className=
'text-[13px] font-medium text-gray-800'
>
{
name
}
</
div
>
{
description
&&
<
div
className=
'text-xs leading-[18px] text-gray-500'
>
{
description
}
</
div
>
}
</
div
>
</
div
>
<
Switch
size=
'md'
defaultValue=
{
enabled
}
onChange=
{
onChange
}
disabled=
{
readonly
}
/>
</
div
>
{
more
}
</
div
>
)
}
export
default
React
.
memo
(
Item
)
web/app/components/explore/universal-chat/hooks/use-conversation.ts
0 → 100644
View file @
23e34136
import
{
useState
}
from
'react'
import
produce
from
'immer'
import
{
useGetState
}
from
'ahooks'
import
type
{
ConversationItem
}
from
'@/models/share'
const
storageConversationIdKey
=
'conversationIdInfo'
type
ConversationInfoType
=
Omit
<
ConversationItem
,
'inputs'
|
'id'
>
function
useConversation
()
{
const
[
conversationList
,
setConversationList
]
=
useState
<
ConversationItem
[]
>
([])
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
=
''
)
=>
{
doSetCurrConversationId
(
id
)
if
(
isSetToLocalStroge
&&
id
!==
'-1'
)
{
// conversationIdInfo: {[appId1]: conversationId1, [appId2]: conversationId2}
const
conversationIdInfo
=
globalThis
.
localStorage
?.
getItem
(
storageConversationIdKey
)
?
JSON
.
parse
(
globalThis
.
localStorage
?.
getItem
(
storageConversationIdKey
)
||
''
)
:
{}
conversationIdInfo
[
appId
]
=
id
globalThis
.
localStorage
?.
setItem
(
storageConversationIdKey
,
JSON
.
stringify
(
conversationIdInfo
))
}
}
const
getConversationIdFromStorage
=
(
appId
:
string
)
=>
{
const
conversationIdInfo
=
globalThis
.
localStorage
?.
getItem
(
storageConversationIdKey
)
?
JSON
.
parse
(
globalThis
.
localStorage
?.
getItem
(
storageConversationIdKey
)
||
''
)
:
{}
const
id
=
conversationIdInfo
[
appId
]
return
id
}
const
isNewConversation
=
currConversationId
===
'-1'
// input can be updated by user
const
[
newConversationInputs
,
setNewConversationInputs
]
=
useState
<
Record
<
string
,
any
>
|
null
>
(
null
)
const
resetNewConversationInputs
=
()
=>
{
if
(
!
newConversationInputs
)
return
setNewConversationInputs
(
produce
(
newConversationInputs
,
(
draft
)
=>
{
Object
.
keys
(
draft
).
forEach
((
key
)
=>
{
draft
[
key
]
=
''
})
}))
}
const
[
existConversationInputs
,
setExistConversationInputs
]
=
useState
<
Record
<
string
,
any
>
|
null
>
(
null
)
const
currInputs
=
isNewConversation
?
newConversationInputs
:
existConversationInputs
const
setCurrInputs
=
isNewConversation
?
setNewConversationInputs
:
setExistConversationInputs
// info is muted
const
[
newConversationInfo
,
setNewConversationInfo
]
=
useState
<
ConversationInfoType
|
null
>
(
null
)
const
[
existConversationInfo
,
setExistConversationInfo
]
=
useState
<
ConversationInfoType
|
null
>
(
null
)
const
currConversationInfo
=
isNewConversation
?
newConversationInfo
:
existConversationInfo
return
{
conversationList
,
setConversationList
,
pinnedConversationList
,
setPinnedConversationList
,
currConversationId
,
getCurrConversationId
,
setCurrConversationId
,
getConversationIdFromStorage
,
isNewConversation
,
currInputs
,
newConversationInputs
,
existConversationInputs
,
resetNewConversationInputs
,
setCurrInputs
,
currConversationInfo
,
setNewConversationInfo
,
setExistConversationInfo
,
}
}
export
default
useConversation
web/app/components/explore/universal-chat/index.tsx
0 → 100644
View file @
23e34136
/* eslint-disable react-hooks/exhaustive-deps */
/* eslint-disable @typescript-eslint/no-use-before-define */
'use client'
import
type
{
FC
}
from
'react'
import
React
,
{
useEffect
,
useRef
,
useState
}
from
'react'
import
cn
from
'classnames'
import
{
useTranslation
}
from
'react-i18next'
import
{
useContext
}
from
'use-context-selector'
import
produce
from
'immer'
import
{
useBoolean
,
useGetState
}
from
'ahooks'
import
AppUnavailable
from
'../../base/app-unavailable'
import
useConversation
from
'./hooks/use-conversation'
import
s
from
'./style.module.css'
import
Init
from
'./init'
import
{
ToastContext
}
from
'@/app/components/base/toast'
import
Sidebar
from
'@/app/components/share/chat/sidebar'
import
{
delConversation
,
fetchAppParams
,
fetchChatList
,
fetchConversations
,
fetchSuggestedQuestions
,
pinConversation
,
sendChatMessage
,
stopChatMessageResponding
,
unpinConversation
,
updateFeedback
,
}
from
'@/service/universal-chat'
import
type
{
ConversationItem
,
SiteInfo
}
from
'@/models/share'
import
type
{
PromptConfig
,
SuggestedQuestionsAfterAnswerConfig
}
from
'@/models/debug'
import
type
{
Feedbacktype
,
IChatItem
}
from
'@/app/components/app/chat/type'
import
Chat
from
'@/app/components/app/chat'
import
useBreakpoints
,
{
MediaType
}
from
'@/hooks/use-breakpoints'
import
Loading
from
'@/app/components/base/loading'
import
{
replaceStringWithValues
}
from
'@/app/components/app/configuration/prompt-value-panel'
import
{
userInputsFormToPromptVariables
}
from
'@/utils/model-config'
import
Confirm
from
'@/app/components/base/confirm'
import
type
{
DataSet
}
from
'@/models/datasets'
import
ConfigSummary
from
'@/app/components/explore/universal-chat/config-view/summary'
import
{
fetchDatasets
}
from
'@/service/datasets'
import
ItemOperation
from
'@/app/components/explore/item-operation'
const
APP_ID
=
'universal-chat'
const
DEFAULT_MODEL_ID
=
'gpt-3.5-turbo'
// gpt-4, claude-2
const
DEFAULT_PLUGIN
=
{
google_search
:
false
,
web_reader
:
true
,
wikipedia
:
true
,
}
export
type
IMainProps
=
{}
const
Main
:
FC
<
IMainProps
>
=
()
=>
{
const
{
t
}
=
useTranslation
()
const
media
=
useBreakpoints
()
const
isMobile
=
media
===
MediaType
.
mobile
/*
* app info
*/
const
[
appUnavailable
,
setAppUnavailable
]
=
useState
<
boolean
>
(
false
)
const
[
isUnknwonReason
,
setIsUnknwonReason
]
=
useState
<
boolean
>
(
false
)
const
siteInfo
:
SiteInfo
=
(
{
title
:
'universal Chatbot'
,
icon
:
''
,
icon_background
:
''
,
description
:
''
,
default_language
:
'en'
,
// TODO
prompt_public
:
true
,
}
)
const
[
promptConfig
,
setPromptConfig
]
=
useState
<
PromptConfig
|
null
>
(
null
)
const
[
inited
,
setInited
]
=
useState
<
boolean
>
(
false
)
// in mobile, show sidebar by click button
const
[
isShowSidebar
,
{
setTrue
:
showSidebar
,
setFalse
:
hideSidebar
}]
=
useBoolean
(
false
)
/*
* conversation info
*/
const
[
allConversationList
,
setAllConversationList
]
=
useState
<
ConversationItem
[]
>
([])
const
[
isClearConversationList
,
{
setTrue
:
clearConversationListTrue
,
setFalse
:
clearConversationListFalse
}]
=
useBoolean
(
false
)
const
[
isClearPinnedConversationList
,
{
setTrue
:
clearPinnedConversationListTrue
,
setFalse
:
clearPinnedConversationListFalse
}]
=
useBoolean
(
false
)
const
{
conversationList
,
setConversationList
,
pinnedConversationList
,
setPinnedConversationList
,
currConversationId
,
getCurrConversationId
,
setCurrConversationId
,
getConversationIdFromStorage
,
isNewConversation
,
currConversationInfo
,
currInputs
,
newConversationInputs
,
// existConversationInputs,
resetNewConversationInputs
,
setCurrInputs
,
setNewConversationInfo
,
setExistConversationInfo
,
}
=
useConversation
()
const
[
hasMore
,
setHasMore
]
=
useState
<
boolean
>
(
true
)
const
[
hasPinnedMore
,
setHasPinnedMore
]
=
useState
<
boolean
>
(
true
)
const
onMoreLoaded
=
({
data
:
conversations
,
has_more
}:
any
)
=>
{
setHasMore
(
has_more
)
if
(
isClearConversationList
)
{
setConversationList
(
conversations
)
clearConversationListFalse
()
}
else
{
setConversationList
([...
conversationList
,
...
conversations
])
}
}
const
onPinnedMoreLoaded
=
({
data
:
conversations
,
has_more
}:
any
)
=>
{
setHasPinnedMore
(
has_more
)
if
(
isClearPinnedConversationList
)
{
setPinnedConversationList
(
conversations
)
clearPinnedConversationListFalse
()
}
else
{
setPinnedConversationList
([...
pinnedConversationList
,
...
conversations
])
}
}
const
[
controlUpdateConversationList
,
setControlUpdateConversationList
]
=
useState
(
0
)
const
noticeUpdateList
=
()
=>
{
setHasMore
(
true
)
clearConversationListTrue
()
setHasPinnedMore
(
true
)
clearPinnedConversationListTrue
()
setControlUpdateConversationList
(
Date
.
now
())
}
const
handlePin
=
async
(
id
:
string
)
=>
{
await
pinConversation
(
id
)
setControlItemOpHide
(
Date
.
now
())
notify
({
type
:
'success'
,
message
:
t
(
'common.api.success'
)
})
noticeUpdateList
()
}
const
handleUnpin
=
async
(
id
:
string
)
=>
{
await
unpinConversation
(
id
)
setControlItemOpHide
(
Date
.
now
())
notify
({
type
:
'success'
,
message
:
t
(
'common.api.success'
)
})
noticeUpdateList
()
}
const
[
isShowConfirm
,
{
setTrue
:
showConfirm
,
setFalse
:
hideConfirm
}]
=
useBoolean
(
false
)
const
[
toDeleteConversationId
,
setToDeleteConversationId
]
=
useState
(
''
)
const
handleDelete
=
(
id
:
string
)
=>
{
setToDeleteConversationId
(
id
)
hideSidebar
()
// mobile
showConfirm
()
}
const
didDelete
=
async
()
=>
{
await
delConversation
(
toDeleteConversationId
)
setControlItemOpHide
(
Date
.
now
())
notify
({
type
:
'success'
,
message
:
t
(
'common.api.success'
)
})
hideConfirm
()
if
(
currConversationId
===
toDeleteConversationId
)
handleConversationIdChange
(
'-1'
)
noticeUpdateList
()
}
const
[
suggestedQuestionsAfterAnswerConfig
,
setSuggestedQuestionsAfterAnswerConfig
]
=
useState
<
SuggestedQuestionsAfterAnswerConfig
|
null
>
(
null
)
const
[
speechToTextConfig
,
setSpeechToTextConfig
]
=
useState
<
SuggestedQuestionsAfterAnswerConfig
|
null
>
(
null
)
const
[
conversationIdChangeBecauseOfNew
,
setConversationIdChangeBecauseOfNew
,
getConversationIdChangeBecauseOfNew
]
=
useGetState
(
false
)
const
conversationName
=
currConversationInfo
?.
name
||
t
(
'share.chat.newChatDefaultName'
)
as
string
const
conversationIntroduction
=
currConversationInfo
?.
introduction
||
''
const
handleConversationSwitch
=
async
()
=>
{
if
(
!
inited
)
return
// update inputs of current conversation
let
notSyncToStateIntroduction
=
''
let
notSyncToStateInputs
:
Record
<
string
,
any
>
|
undefined
|
null
=
{}
// debugger
if
(
!
isNewConversation
)
{
const
item
=
allConversationList
.
find
(
item
=>
item
.
id
===
currConversationId
)
as
any
notSyncToStateInputs
=
item
?.
inputs
||
{}
// setCurrInputs(notSyncToStateInputs)
notSyncToStateIntroduction
=
item
?.
introduction
||
''
setExistConversationInfo
({
name
:
item
?.
name
||
''
,
introduction
:
notSyncToStateIntroduction
,
})
const
modelConfig
=
item
?.
model_config
if
(
modelConfig
)
{
setModeId
(
modelConfig
.
model_id
)
const
pluginConfig
:
Record
<
string
,
boolean
>
=
{}
const
datasetIds
:
string
[]
=
[]
modelConfig
.
agent_mode
.
tools
.
forEach
((
item
:
any
)
=>
{
const
pluginName
=
Object
.
keys
(
item
)[
0
]
if
(
pluginName
===
'dataset'
)
datasetIds
.
push
(
item
.
dataset
.
id
)
else
pluginConfig
[
pluginName
]
=
item
[
pluginName
].
enabled
})
setPlugins
(
pluginConfig
)
if
(
datasetIds
.
length
>
0
)
{
const
{
data
}
=
await
fetchDatasets
({
url
:
'/datasets'
,
params
:
{
page
:
1
,
ids
:
datasetIds
}
})
setDateSets
(
data
)
}
else
{
setDateSets
([])
}
}
else
{
configSetDefaultValue
()
}
}
else
{
configSetDefaultValue
()
notSyncToStateInputs
=
newConversationInputs
setCurrInputs
(
notSyncToStateInputs
)
}
// update chat list of current conversation
if
(
!
isNewConversation
&&
!
conversationIdChangeBecauseOfNew
)
{
fetchChatList
(
currConversationId
).
then
((
res
:
any
)
=>
{
const
{
data
}
=
res
const
newChatList
:
IChatItem
[]
=
generateNewChatListWithOpenstatement
(
notSyncToStateIntroduction
,
notSyncToStateInputs
)
data
.
forEach
((
item
:
any
)
=>
{
newChatList
.
push
({
id
:
`question-
${
item
.
id
}
`
,
content
:
item
.
query
,
isAnswer
:
false
,
})
newChatList
.
push
({
...
item
,
id
:
item
.
id
,
content
:
item
.
answer
,
feedback
:
item
.
feedback
,
isAnswer
:
true
,
})
})
setChatList
(
newChatList
)
setErrorHappened
(
false
)
})
}
if
(
isNewConversation
)
{
setChatList
(
generateNewChatListWithOpenstatement
())
setErrorHappened
(
false
)
}
setControlFocus
(
Date
.
now
())
}
useEffect
(()
=>
{
handleConversationSwitch
()
},
[
currConversationId
,
inited
])
const
handleConversationIdChange
=
(
id
:
string
)
=>
{
if
(
id
===
'-1'
)
{
createNewChat
()
setConversationIdChangeBecauseOfNew
(
true
)
}
else
{
setConversationIdChangeBecauseOfNew
(
false
)
}
// trigger handleConversationSwitch
setCurrConversationId
(
id
,
APP_ID
)
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
)
chatListDomRef
.
current
.
scrollTop
=
chatListDomRef
.
current
.
scrollHeight
},
[
chatList
,
currConversationId
])
// user can not edit inputs if user had send message
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
,
})
}))
configSetDefaultValue
()
}
// sometime introduction is not applied to state
const
generateNewChatListWithOpenstatement
=
(
introduction
?:
string
,
inputs
?:
Record
<
string
,
any
>
|
null
)
=>
{
let
caculatedIntroduction
=
introduction
||
conversationIntroduction
||
''
const
caculatedPromptVariables
=
inputs
||
currInputs
||
null
if
(
caculatedIntroduction
&&
caculatedPromptVariables
)
caculatedIntroduction
=
replaceStringWithValues
(
caculatedIntroduction
,
promptConfig
?.
prompt_variables
||
[],
caculatedPromptVariables
)
const
openstatement
=
{
id
:
`
${
Date
.
now
()}
`
,
content
:
caculatedIntroduction
,
isAnswer
:
true
,
feedbackDisabled
:
true
,
isOpeningStatement
:
true
,
}
if
(
caculatedIntroduction
)
return
[
openstatement
]
return
[]
}
const
fetchAllConversations
=
()
=>
{
return
fetchConversations
(
undefined
,
undefined
,
100
)
}
const
fetchInitData
=
async
()
=>
{
return
Promise
.
all
([
fetchAllConversations
(),
fetchAppParams
()])
}
// init
useEffect
(()
=>
{
(
async
()
=>
{
try
{
const
[
conversationData
,
appParams
]:
any
=
await
fetchInitData
()
const
prompt_template
=
''
// handle current conversation id
const
{
data
:
allConversations
}
=
conversationData
as
{
data
:
ConversationItem
[];
has_more
:
boolean
}
const
_conversationId
=
getConversationIdFromStorage
(
APP_ID
)
const
isNotNewConversation
=
allConversations
.
some
(
item
=>
item
.
id
===
_conversationId
)
setAllConversationList
(
allConversations
)
// fetch new conversation info
const
{
user_input_form
,
opening_statement
:
introduction
,
suggested_questions_after_answer
,
speech_to_text
}:
any
=
appParams
const
prompt_variables
=
userInputsFormToPromptVariables
(
user_input_form
)
setNewConversationInfo
({
name
:
t
(
'share.chat.newChatDefaultName'
),
introduction
,
})
setPromptConfig
({
prompt_template
,
prompt_variables
,
}
as
PromptConfig
)
setSuggestedQuestionsAfterAnswerConfig
(
suggested_questions_after_answer
)
setSpeechToTextConfig
(
speech_to_text
)
if
(
isNotNewConversation
)
setCurrConversationId
(
_conversationId
,
APP_ID
,
false
)
setInited
(
true
)
}
catch
(
e
:
any
)
{
if
(
e
.
status
===
404
)
{
setAppUnavailable
(
true
)
}
else
{
setIsUnknwonReason
(
true
)
setAppUnavailable
(
true
)
}
}
})()
},
[])
const
[
isResponsing
,
{
setTrue
:
setResponsingTrue
,
setFalse
:
setResponsingFalse
}]
=
useBoolean
(
false
)
const
[
abortController
,
setAbortController
]
=
useState
<
AbortController
|
null
>
(
null
)
const
{
notify
}
=
useContext
(
ToastContext
)
const
logError
=
(
message
:
string
)
=>
{
notify
({
type
:
'error'
,
message
})
}
const
checkCanSend
=
()
=>
{
if
(
currConversationId
!==
'-1'
)
return
true
const
prompt_variables
=
promptConfig
?.
prompt_variables
const
inputs
=
currInputs
if
(
!
inputs
||
!
prompt_variables
||
prompt_variables
?.
length
===
0
)
return
true
let
hasEmptyInput
=
false
const
requiredVars
=
prompt_variables
?.
filter
(({
key
,
name
,
required
})
=>
{
const
res
=
(
!
key
||
!
key
.
trim
())
||
(
!
name
||
!
name
.
trim
())
||
(
required
||
required
===
undefined
||
required
===
null
)
return
res
})
||
[]
// compatible with old version
requiredVars
.
forEach
(({
key
})
=>
{
if
(
hasEmptyInput
)
return
if
(
!
inputs
?.[
key
])
hasEmptyInput
=
true
})
if
(
hasEmptyInput
)
{
logError
(
t
(
'appDebug.errorMessage.valueOfVarRequired'
))
return
false
}
return
!
hasEmptyInput
}
const
[
controlFocus
,
setControlFocus
]
=
useState
(
0
)
const
[
isShowSuggestion
,
setIsShowSuggestion
]
=
useState
(
false
)
const
doShowSuggestion
=
isShowSuggestion
&&
!
isResponsing
const
[
suggestQuestions
,
setSuggestQuestions
]
=
useState
<
string
[]
>
([])
const
[
messageTaskId
,
setMessageTaskId
]
=
useState
(
''
)
const
[
hasStopResponded
,
setHasStopResponded
,
getHasStopResponded
]
=
useGetState
(
false
)
const
[
errorHappened
,
setErrorHappened
]
=
useState
(
false
)
const
[
isResponsingConIsCurrCon
,
setIsResponsingConCurrCon
,
getIsResponsingConIsCurrCon
]
=
useGetState
(
true
)
const
handleSend
=
async
(
message
:
string
)
=>
{
if
(
isResponsing
)
{
notify
({
type
:
'info'
,
message
:
t
(
'appDebug.errorMessage.waitForResponse'
)
})
return
}
const
formattedPlugins
=
Object
.
keys
(
plugins
).
map
(
key
=>
({
[
key
]:
{
enabled
:
plugins
[
key
],
},
}))
const
formattedDataSets
=
dataSets
.
map
(({
id
})
=>
{
return
{
dataset
:
{
enabled
:
true
,
id
,
},
}
})
const
data
=
{
query
:
message
,
conversation_id
:
isNewConversation
?
null
:
currConversationId
,
model
:
modelId
,
tools
:
[...
formattedPlugins
,
...
formattedDataSets
],
}
// qustion
const
questionId
=
`question-
${
Date
.
now
()}
`
const
questionItem
=
{
id
:
questionId
,
content
:
message
,
agent_thoughts
:
[],
isAnswer
:
false
,
}
const
placeholderAnswerId
=
`answer-placeholder-
${
Date
.
now
()}
`
const
placeholderAnswerItem
=
{
id
:
placeholderAnswerId
,
content
:
''
,
isAnswer
:
true
,
}
const
newList
=
[...
getChatList
(),
questionItem
,
placeholderAnswerItem
]
setChatList
(
newList
)
// answer
const
responseItem
:
IChatItem
=
{
id
:
`
${
Date
.
now
()}
`
,
content
:
''
,
agent_thoughts
:
[],
isAnswer
:
true
,
}
const
prevTempNewConversationId
=
getCurrConversationId
()
||
'-1'
let
tempNewConversationId
=
prevTempNewConversationId
setHasStopResponded
(
false
)
setResponsingTrue
()
setErrorHappened
(
false
)
setIsShowSuggestion
(
false
)
setIsResponsingConCurrCon
(
true
)
sendChatMessage
(
data
,
{
getAbortController
:
(
abortController
)
=>
{
setAbortController
(
abortController
)
},
onData
:
(
message
:
string
,
isFirstMessage
:
boolean
,
{
conversationId
:
newConversationId
,
messageId
,
taskId
}:
any
)
=>
{
responseItem
.
content
=
responseItem
.
content
+
message
responseItem
.
id
=
messageId
if
(
isFirstMessage
&&
newConversationId
)
tempNewConversationId
=
newConversationId
setMessageTaskId
(
taskId
)
// has switched to other conversation
if
(
prevTempNewConversationId
!==
getCurrConversationId
())
{
setIsResponsingConCurrCon
(
false
)
return
}
// 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
}
as
any
)
draft
.
push
({
...
responseItem
})
})
setChatList
(
newListWithAnswer
)
},
async
onCompleted
(
hasError
?:
boolean
)
{
if
(
hasError
)
{
setResponsingFalse
()
return
}
if
(
getConversationIdChangeBecauseOfNew
())
{
const
{
data
:
allConversations
}:
any
=
await
fetchAllConversations
()
setAllConversationList
(
allConversations
)
noticeUpdateList
()
}
setConversationIdChangeBecauseOfNew
(
false
)
resetNewConversationInputs
()
setCurrConversationId
(
tempNewConversationId
,
APP_ID
,
true
)
if
(
getIsResponsingConIsCurrCon
()
&&
suggestedQuestionsAfterAnswerConfig
?.
enabled
&&
!
getHasStopResponded
())
{
const
{
data
}:
any
=
await
fetchSuggestedQuestions
(
responseItem
.
id
)
setSuggestQuestions
(
data
)
setIsShowSuggestion
(
true
)
}
setResponsingFalse
()
},
onThought
(
thought
)
{
// thought finished then start to return message. Warning: use push agent_thoughts.push would caused problem when the thought is more then 2
responseItem
.
id
=
thought
.
message_id
;
(
responseItem
as
any
).
agent_thoughts
=
[...(
responseItem
as
any
).
agent_thoughts
,
thought
]
// .push(thought)
// has switched to other conversation
if
(
prevTempNewConversationId
!==
getCurrConversationId
())
{
setIsResponsingConCurrCon
(
false
)
return
}
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
)
},
onError
()
{
setErrorHappened
(
true
)
// role back placeholder answer
setChatList
(
produce
(
getChatList
(),
(
draft
)
=>
{
draft
.
splice
(
draft
.
findIndex
(
item
=>
item
.
id
===
placeholderAnswerId
),
1
)
}))
setResponsingFalse
()
},
})
}
const
handleFeedback
=
async
(
messageId
:
string
,
feedback
:
Feedbacktype
)
=>
{
await
updateFeedback
({
url
:
`/messages/
${
messageId
}
/feedbacks`
,
body
:
{
rating
:
feedback
.
rating
}
})
const
newChatList
=
chatList
.
map
((
item
)
=>
{
if
(
item
.
id
===
messageId
)
{
return
{
...
item
,
feedback
,
}
}
return
item
})
setChatList
(
newChatList
)
notify
({
type
:
'success'
,
message
:
t
(
'common.api.success'
)
})
}
const
renderSidebar
=
()
=>
{
if
(
!
APP_ID
||
!
promptConfig
)
return
null
return
(
<
Sidebar
list=
{
conversationList
}
isClearConversationList=
{
isClearConversationList
}
pinnedList=
{
pinnedConversationList
}
isClearPinnedConversationList=
{
isClearPinnedConversationList
}
onMoreLoaded=
{
onMoreLoaded
}
onPinnedMoreLoaded=
{
onPinnedMoreLoaded
}
isNoMore=
{
!
hasMore
}
isPinnedNoMore=
{
!
hasPinnedMore
}
onCurrentIdChange=
{
handleConversationIdChange
}
currentId=
{
currConversationId
}
copyRight=
{
''
}
isInstalledApp=
{
false
}
isUniversalChat
installedAppId=
{
''
}
siteInfo=
{
siteInfo
}
onPin=
{
handlePin
}
onUnpin=
{
handleUnpin
}
controlUpdateList=
{
controlUpdateConversationList
}
onDelete=
{
handleDelete
}
/>
)
}
const
[
modelId
,
setModeId
]
=
useState
(
DEFAULT_MODEL_ID
)
// const currModel = MODEL_LIST.find(item => item.id === modelId)
const
[
plugins
,
setPlugins
]
=
useState
<
Record
<
string
,
boolean
>>
(
DEFAULT_PLUGIN
)
const
handlePluginsChange
=
(
key
:
string
,
value
:
boolean
)
=>
{
setPlugins
({
...
plugins
,
[
key
]:
value
,
})
}
const
[
dataSets
,
setDateSets
]
=
useState
<
DataSet
[]
>
([])
const
configSetDefaultValue
=
()
=>
{
setModeId
(
DEFAULT_MODEL_ID
)
setPlugins
(
DEFAULT_PLUGIN
)
setDateSets
([])
}
const
isCurrConversationPinned
=
!!
pinnedConversationList
.
find
(
item
=>
item
.
id
===
currConversationId
)
const
[
controlItemOpHide
,
setControlItemOpHide
]
=
useState
(
0
)
if
(
appUnavailable
)
return
<
AppUnavailable
isUnknwonReason=
{
isUnknwonReason
}
/>
if
(
!
promptConfig
)
return
<
Loading
type=
'app'
/>
return
(
<
div
className=
'bg-gray-100'
>
<
div
className=
{
cn
(
'flex rounded-t-2xl bg-white overflow-hidden rounded-b-2xl'
,
)
}
style=
{
{
boxShadow
:
'0px 12px 16px -4px rgba(16, 24, 40, 0.08), 0px 4px 6px -2px rgba(16, 24, 40, 0.03)'
,
}
}
>
{
/* sidebar */
}
{
!
isMobile
&&
renderSidebar
()
}
{
isMobile
&&
isShowSidebar
&&
(
<
div
className=
'fixed inset-0 z-50'
style=
{
{
backgroundColor
:
'rgba(35, 56, 118, 0.2)'
}
}
onClick=
{
hideSidebar
}
>
<
div
className=
'inline-block'
onClick=
{
e
=>
e
.
stopPropagation
()
}
>
{
renderSidebar
()
}
</
div
>
</
div
>
)
}
{
/* main */
}
<
div
className=
{
cn
(
s
.
installedApp
,
'flex-grow flex flex-col overflow-y-auto'
,
)
}
>
{
(
!
isNewConversation
||
isResponsing
||
errorHappened
)
&&
(
<
div
className=
'mb-5 antialiased font-sans shrink-0 relative mobile:min-h-[48px] tablet:min-h-[64px]'
>
<
div
className=
'absolute z-10 top-0 left-0 right-0 flex items-center justify-between border-b border-gray-100 mobile:h-12 tablet:h-16 px-8 bg-white'
>
<
div
className=
'text-gray-900'
>
{
conversationName
}
</
div
>
<
div
className=
'flex items-center shrink-0 ml-2 space-x-2'
>
<
ConfigSummary
modelId=
{
modelId
}
plugins=
{
plugins
}
dataSets=
{
dataSets
}
/>
<
div
className=
{
cn
(
'flex w-8 h-8 justify-center items-center shrink-0 rounded-lg border border-gray-200'
)
}
onClick=
{
e
=>
e
.
stopPropagation
()
}
>
<
ItemOperation
key=
{
controlItemOpHide
}
className=
'!w-8 !h-8'
isPinned=
{
isCurrConversationPinned
}
togglePin=
{
()
=>
isCurrConversationPinned
?
handleUnpin
(
currConversationId
)
:
handlePin
(
currConversationId
)
}
isShowDelete
onDelete=
{
()
=>
handleDelete
(
currConversationId
)
}
/>
</
div
>
</
div
>
</
div
>
</
div
>
)
}
<
div
className=
{
cn
(
doShowSuggestion
?
'pb-[140px]'
:
(
isResponsing
?
'pb-[113px]'
:
'pb-[76px]'
),
'relative grow h-[200px] pc:w-[794px] max-w-full mobile:w-full mx-auto mb-3.5 overflow-hidden'
)
}
>
<
div
className=
{
cn
(
'pc:w-[794px] max-w-full mobile:w-full mx-auto h-full overflow-y-auto'
)
}
ref=
{
chatListDomRef
}
>
<
Chat
isShowConfigElem=
{
isNewConversation
&&
chatList
.
length
===
0
}
configElem=
{
<
Init
modelId=
{
modelId
}
onModelChange=
{
setModeId
}
plugins=
{
plugins
}
onPluginChange=
{
handlePluginsChange
}
dataSets=
{
dataSets
}
onDataSetsChange=
{
setDateSets
}
/>
}
chatList=
{
chatList
}
onSend=
{
handleSend
}
isHideFeedbackEdit
onFeedback=
{
handleFeedback
}
isResponsing=
{
isResponsing
}
canStopResponsing=
{
!!
messageTaskId
&&
isResponsingConIsCurrCon
}
abortResponsing=
{
async
()
=>
{
await
stopChatMessageResponding
(
messageTaskId
)
setHasStopResponded
(
true
)
setResponsingFalse
()
}
}
checkCanSend=
{
checkCanSend
}
controlFocus=
{
controlFocus
}
isShowSuggestion=
{
doShowSuggestion
}
suggestionList=
{
suggestQuestions
}
isShowSpeechToText=
{
speechToTextConfig
?.
enabled
}
dataSets=
{
dataSets
}
/>
</
div
>
</
div
>
{
isShowConfirm
&&
(
<
Confirm
title=
{
t
(
'share.chat.deleteConversation.title'
)
}
content=
{
t
(
'share.chat.deleteConversation.content'
)
}
isShow=
{
isShowConfirm
}
onClose=
{
hideConfirm
}
onConfirm=
{
didDelete
}
onCancel=
{
hideConfirm
}
/>
)
}
</
div
>
</
div
>
</
div
>
)
}
export
default
React
.
memo
(
Main
)
web/app/components/explore/universal-chat/init/index.tsx
0 → 100644
View file @
23e34136
'use client'
import
type
{
FC
}
from
'react'
import
React
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
cn
from
'classnames'
import
type
{
IConfigProps
}
from
'../config'
import
Config
from
'../config'
import
s
from
'./style.module.css'
const
Line
=
(
<
svg
width=
"720"
height=
"1"
viewBox=
"0 0 720 1"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
>
<
line
y1=
"0.5"
x2=
"720"
y2=
"0.5"
stroke=
"url(#paint0_linear_6845_53470)"
/>
<
defs
>
<
linearGradient
id=
"paint0_linear_6845_53470"
x1=
"0"
y1=
"1"
x2=
"720"
y2=
"1"
gradientUnits=
"userSpaceOnUse"
>
<
stop
stopColor=
"#F2F4F7"
stopOpacity=
"0"
/>
<
stop
offset=
"0.491667"
stopColor=
"#F2F4F7"
/>
<
stop
offset=
"1"
stopColor=
"#F2F4F7"
stopOpacity=
"0"
/>
</
linearGradient
>
</
defs
>
</
svg
>
)
const
Init
:
FC
<
IConfigProps
>
=
({
...
configProps
})
=>
{
const
{
t
}
=
useTranslation
()
return
(
<
div
className=
'h-full flex items-center'
>
<
div
>
<
div
className=
'w-[480px] mx-auto text-center'
>
<
div
className=
{
cn
(
s
.
textGradient
,
'mb-2 leading-[32px] font-semibold text-[24px]'
)
}
>
{
t
(
'explore.universalChat.welcome'
)
}
</
div
>
<
div
className=
'mb-2 font-normal text-sm text-gray-500'
>
{
t
(
'explore.universalChat.welcomeDescribe'
)
}
</
div
>
</
div
>
<
div
className=
'flex mb-2 mx-auto h-8 items-center'
>
{
Line
}
</
div
>
<
Config
className=
'w-[480px] mx-auto'
{
...
configProps
}
/>
</
div
>
</
div
>
)
}
export
default
React
.
memo
(
Init
)
web/app/components/explore/universal-chat/init/style.module.css
0 → 100644
View file @
23e34136
.textGradient
{
background
:
linear-gradient
(
to
right
,
rgba
(
16
,
74
,
225
,
1
)
0
,
rgba
(
0
,
152
,
238
,
1
)
100%
);
-webkit-background-clip
:
text
;
-webkit-text-fill-color
:
transparent
;
background-clip
:
text
;
text-fill-color
:
transparent
;
}
web/app/components/explore/universal-chat/style.module.css
0 → 100644
View file @
23e34136
.installedApp
{
height
:
calc
(
100vh
-
74px
);
}
\ No newline at end of file
web/app/components/header/account-setting/index.tsx
View file @
23e34136
...
...
@@ -9,11 +9,12 @@ import MembersPage from './members-page'
import
IntegrationsPage
from
'./Integrations-page'
import
LanguagePage
from
'./language-page'
import
ProviderPage
from
'./provider-page'
import
PluginPage
from
'./plugin-page'
import
DataSourcePage
from
'./data-source-page'
import
s
from
'./index.module.css'
import
Modal
from
'@/app/components/base/modal'
import
{
Database03
}
from
'@/app/components/base/icons/src/vender/line/development'
import
{
Database03
as
Database03Solid
}
from
'@/app/components/base/icons/src/vender/solid/development'
import
{
Database03
,
PuzzlePiece01
}
from
'@/app/components/base/icons/src/vender/line/development'
import
{
Database03
as
Database03Solid
,
PuzzlePiece01
as
PuzzlePiece01Solid
}
from
'@/app/components/base/icons/src/vender/solid/development'
const
iconClassName
=
`
w-4 h-4 ml-3 mr-2
...
...
@@ -80,6 +81,12 @@ export default function AccountSetting({
icon
:
<
Database03
className=
{
iconClassName
}
/>,
activeIcon
:
<
Database03Solid
className=
{
iconClassName
}
/>,
},
{
key
:
'plugin'
,
name
:
t
(
'common.settings.plugin'
),
icon
:
<
PuzzlePiece01
className=
{
iconClassName
}
/>,
activeIcon
:
<
PuzzlePiece01Solid
className=
{
iconClassName
}
/>,
},
],
},
]
...
...
@@ -148,6 +155,7 @@ export default function AccountSetting({
{
activeMenu
===
'language'
&&
<
LanguagePage
/>
}
{
activeMenu
===
'provider'
&&
<
ProviderPage
/>
}
{
activeMenu
===
'data-source'
&&
<
DataSourcePage
/>
}
{
activeMenu
===
'plugin'
&&
<
PluginPage
/>
}
</
div
>
</
div
>
</
div
>
...
...
web/app/components/header/account-setting/key-validator/KeyInput.tsx
0 → 100644
View file @
23e34136
import
type
{
ChangeEvent
}
from
'react'
import
{
ValidatedErrorIcon
,
ValidatedErrorMessage
,
ValidatedSuccessIcon
,
ValidatingTip
,
}
from
'./ValidateStatus'
import
{
ValidatedStatus
}
from
'./declarations'
import
type
{
ValidatedStatusState
}
from
'./declarations'
type
KeyInputProps
=
{
value
?:
string
name
:
string
placeholder
:
string
className
?:
string
onChange
:
(
v
:
string
)
=>
void
onFocus
?:
()
=>
void
validating
:
boolean
validatedStatusState
:
ValidatedStatusState
}
const
KeyInput
=
({
value
,
name
,
placeholder
,
className
,
onChange
,
onFocus
,
validating
,
validatedStatusState
,
}:
KeyInputProps
)
=>
{
const
handleChange
=
(
e
:
ChangeEvent
<
HTMLInputElement
>
)
=>
{
const
inputValue
=
e
.
target
.
value
onChange
(
inputValue
)
}
const
getValidatedIcon
=
()
=>
{
if
(
validatedStatusState
.
status
===
ValidatedStatus
.
Error
||
validatedStatusState
.
status
===
ValidatedStatus
.
Exceed
)
return
<
ValidatedErrorIcon
/>
if
(
validatedStatusState
.
status
===
ValidatedStatus
.
Success
)
return
<
ValidatedSuccessIcon
/>
}
const
getValidatedTip
=
()
=>
{
if
(
validating
)
return
<
ValidatingTip
/>
if
(
validatedStatusState
.
status
===
ValidatedStatus
.
Error
)
return
<
ValidatedErrorMessage
errorMessage=
{
validatedStatusState
.
message
??
''
}
/>
}
return
(
<
div
className=
{
className
}
>
<
div
className=
"mb-2 text-[13px] font-medium text-gray-800"
>
{
name
}
</
div
>
<
div
className=
'
flex items-center px-3 bg-white rounded-lg
shadow-[0_1px_2px_rgba(16,24,40,0.05)]
'
>
<
input
className=
'
w-full py-[9px] mr-2
text-xs font-medium text-gray-700 leading-[18px]
appearance-none outline-none bg-transparent
'
value=
{
value
}
placeholder=
{
placeholder
}
onChange=
{
handleChange
}
onFocus=
{
onFocus
}
/>
{
getValidatedIcon
()
}
</
div
>
{
getValidatedTip
()
}
</
div
>
)
}
export
default
KeyInput
web/app/components/header/account-setting/key-validator/Operate.tsx
0 → 100644
View file @
23e34136
import
{
useTranslation
}
from
'react-i18next'
import
Indicator
from
'../../indicator'
import
type
{
Status
}
from
'./declarations'
type
OperateProps
=
{
isOpen
:
boolean
status
:
Status
onCancel
:
()
=>
void
onSave
:
()
=>
void
onAdd
:
()
=>
void
onEdit
:
()
=>
void
}
const
Operate
=
({
isOpen
,
status
,
onCancel
,
onSave
,
onAdd
,
onEdit
,
}:
OperateProps
)
=>
{
const
{
t
}
=
useTranslation
()
if
(
isOpen
)
{
return
(
<
div
className=
'flex items-center'
>
<
div
className=
'
flex items-center
mr-[5px] px-3 h-7 rounded-md cursor-pointer
text-xs font-medium text-gray-700
'
onClick=
{
onCancel
}
>
{
t
(
'common.operation.cancel'
)
}
</
div
>
<
div
className=
'
flex items-center
px-3 h-7 rounded-md cursor-pointer bg-primary-700
text-xs font-medium text-white
'
onClick=
{
onSave
}
>
{
t
(
'common.operation.save'
)
}
</
div
>
</
div
>
)
}
if
(
status
===
'add'
)
{
return
(
<
div
className=
'
px-3 h-[28px] bg-white border border-gray-200 rounded-md cursor-pointer
text-xs font-medium text-gray-700 flex items-center
'
onClick=
{
onAdd
}
>
{
t
(
'common.provider.addKey'
)
}
</
div
>
)
}
if
(
status
===
'fail'
||
status
===
'success'
)
{
return
(
<
div
className=
'flex items-center'
>
{
status
===
'fail'
&&
(
<
div
className=
'flex items-center mr-4'
>
<
div
className=
'text-xs text-[#D92D20]'
>
{
t
(
'common.provider.invalidApiKey'
)
}
</
div
>
<
Indicator
color=
'red'
className=
'ml-2'
/>
</
div
>
)
}
{
status
===
'success'
&&
(
<
Indicator
color=
'green'
className=
'mr-4'
/>
)
}
<
div
className=
'
px-3 h-[28px] bg-white border border-gray-200 rounded-md cursor-pointer
text-xs font-medium text-gray-700 flex items-center
'
onClick=
{
onEdit
}
>
{
t
(
'common.provider.editKey'
)
}
</
div
>
</
div
>
)
}
return
null
}
export
default
Operate
web/app/components/header/account-setting/key-validator/ValidateStatus.tsx
0 → 100644
View file @
23e34136
import
{
useTranslation
}
from
'react-i18next'
import
{
AlertCircle
}
from
'@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
import
{
CheckCircle
}
from
'@/app/components/base/icons/src/vender/solid/general'
export
const
ValidatedErrorIcon
=
()
=>
{
return
<
AlertCircle
className=
'w-4 h-4 text-[#D92D20]'
/>
}
export
const
ValidatedSuccessIcon
=
()
=>
{
return
<
CheckCircle
className=
'w-4 h-4 text-[#039855]'
/>
}
export
const
ValidatingTip
=
()
=>
{
const
{
t
}
=
useTranslation
()
return
(
<
div
className=
{
'mt-2 text-primary-600 text-xs font-normal'
}
>
{
t
(
'common.provider.validating'
)
}
</
div
>
)
}
export
const
ValidatedErrorMessage
=
({
errorMessage
}:
{
errorMessage
:
string
})
=>
{
const
{
t
}
=
useTranslation
()
return
(
<
div
className=
{
'mt-2 text-[#D92D20] text-xs font-normal'
}
>
{
t
(
'common.provider.validatedError'
)
}{
errorMessage
}
</
div
>
)
}
web/app/components/header/account-setting/key-validator/declarations.ts
0 → 100644
View file @
23e34136
import
type
{
Dispatch
,
SetStateAction
}
from
'react'
export
enum
ValidatedStatus
{
Success
=
'success'
,
Error
=
'error'
,
Exceed
=
'exceed'
,
}
export
type
ValidatedStatusState
=
{
status
?:
ValidatedStatus
message
?:
string
}
export
type
Status
=
'add'
|
'fail'
|
'success'
export
type
ValidateValue
=
Record
<
string
,
string
|
undefined
>
export
type
ValidateCallback
=
{
before
:
(
v
?:
ValidateValue
)
=>
boolean
|
undefined
run
?:
(
v
?:
ValidateValue
)
=>
Promise
<
ValidatedStatusState
>
}
export
type
Form
=
{
key
:
string
title
:
string
placeholder
:
string
value
?:
string
validate
?:
ValidateCallback
handleFocus
?:
(
v
:
ValidateValue
,
dispatch
:
Dispatch
<
SetStateAction
<
ValidateValue
>>
)
=>
void
}
export
type
KeyFrom
=
{
text
:
string
link
:
string
}
export
type
KeyValidatorProps
=
{
type
:
string
title
:
React
.
ReactNode
status
:
Status
forms
:
Form
[]
keyFrom
:
KeyFrom
}
web/app/components/header/account-setting/key-validator/hooks.ts
0 → 100644
View file @
23e34136
import
{
useState
}
from
'react'
import
{
useDebounceFn
}
from
'ahooks'
import
type
{
DebouncedFunc
}
from
'lodash-es'
import
{
ValidatedStatus
}
from
'./declarations'
import
type
{
ValidateCallback
,
ValidateValue
,
ValidatedStatusState
}
from
'./declarations'
export
const
useValidate
:
(
value
:
ValidateValue
)
=>
[
DebouncedFunc
<
(
validateCallback
:
ValidateCallback
)
=>
Promise
<
void
>>
,
boolean
,
ValidatedStatusState
]
=
(
value
)
=>
{
const
[
validating
,
setValidating
]
=
useState
(
false
)
const
[
validatedStatus
,
setValidatedStatus
]
=
useState
<
ValidatedStatusState
>
({})
const
{
run
}
=
useDebounceFn
(
async
(
validateCallback
:
ValidateCallback
)
=>
{
if
(
!
validateCallback
.
before
(
value
))
{
setValidating
(
false
)
setValidatedStatus
({})
return
}
setValidating
(
true
)
if
(
validateCallback
.
run
)
{
const
res
=
await
validateCallback
?.
run
(
value
)
setValidatedStatus
(
res
.
status
===
'success'
?
{
status
:
ValidatedStatus
.
Success
}
:
{
status
:
ValidatedStatus
.
Error
,
message
:
res
.
message
})
setValidating
(
false
)
}
},
{
wait
:
500
})
return
[
run
,
validating
,
validatedStatus
]
}
web/app/components/header/account-setting/key-validator/index.tsx
0 → 100644
View file @
23e34136
import
{
useState
}
from
'react'
import
Operate
from
'./Operate'
import
KeyInput
from
'./KeyInput'
import
{
useValidate
}
from
'./hooks'
import
type
{
Form
,
KeyFrom
,
Status
,
ValidateValue
}
from
'./declarations'
import
{
useEventEmitterContextContext
}
from
'@/context/event-emitter'
import
{
LinkExternal02
}
from
'@/app/components/base/icons/src/vender/line/general'
export
type
KeyValidatorProps
=
{
type
:
string
title
:
React
.
ReactNode
status
:
Status
forms
:
Form
[]
keyFrom
:
KeyFrom
onSave
:
(
v
:
ValidateValue
)
=>
Promise
<
boolean
|
undefined
>
}
const
KeyValidator
=
({
type
,
title
,
status
,
forms
,
keyFrom
,
onSave
,
}:
KeyValidatorProps
)
=>
{
const
triggerKey
=
`plugins/
${
type
}
`
const
{
eventEmitter
}
=
useEventEmitterContextContext
()
const
[
isOpen
,
setIsOpen
]
=
useState
(
false
)
const
prevValue
=
forms
.
reduce
((
prev
:
ValidateValue
,
next
:
Form
)
=>
{
prev
[
next
.
key
]
=
next
.
value
return
prev
},
{})
const
[
value
,
setValue
]
=
useState
(
prevValue
)
const
[
validate
,
validating
,
validatedStatusState
]
=
useValidate
(
value
)
eventEmitter
?.
useSubscription
((
v
)
=>
{
if
(
v
!==
triggerKey
)
{
setIsOpen
(
false
)
setValue
(
prevValue
)
validate
({
before
:
()
=>
false
})
}
})
const
handleCancel
=
()
=>
{
eventEmitter
?.
emit
(
''
)
}
const
handleSave
=
async
()
=>
{
if
(
await
onSave
(
value
))
eventEmitter
?.
emit
(
''
)
}
const
handleAdd
=
()
=>
{
setIsOpen
(
true
)
eventEmitter
?.
emit
(
triggerKey
)
}
const
handleEdit
=
()
=>
{
setIsOpen
(
true
)
eventEmitter
?.
emit
(
triggerKey
)
}
const
handleChange
=
(
form
:
Form
,
val
:
string
)
=>
{
setValue
({
...
value
,
[
form
.
key
]:
val
})
if
(
form
.
validate
)
validate
(
form
.
validate
)
}
const
handleFocus
=
(
form
:
Form
)
=>
{
if
(
form
.
handleFocus
)
form
.
handleFocus
(
value
,
setValue
)
}
return
(
<
div
className=
'mb-2 border-[0.5px] border-gray-200 bg-gray-50 rounded-md'
>
<
div
className=
{
`flex items-center justify-between px-4 h-[52px] cursor-pointer ${isOpen && 'border-b-[0.5px] border-b-gray-200'}`
}
>
{
title
}
<
Operate
isOpen=
{
isOpen
}
status=
{
status
}
onCancel=
{
handleCancel
}
onSave=
{
handleSave
}
onAdd=
{
handleAdd
}
onEdit=
{
handleEdit
}
/>
</
div
>
{
isOpen
&&
(
<
div
className=
'px-4 py-3'
>
{
forms
.
map
(
form
=>
(
<
KeyInput
key=
{
form
.
key
}
className=
'mb-4'
name=
{
form
.
title
}
placeholder=
{
form
.
placeholder
}
value=
{
value
[
form
.
key
]
||
''
}
onChange=
{
v
=>
handleChange
(
form
,
v
)
}
onFocus=
{
()
=>
handleFocus
(
form
)
}
validating=
{
validating
}
validatedStatusState=
{
validatedStatusState
}
/>
))
}
<
a
className=
"flex items-center text-xs cursor-pointer text-primary-600"
href=
{
keyFrom
.
link
}
target=
{
'_blank'
}
>
{
keyFrom
.
text
}
<
LinkExternal02
className=
'w-3 h-3 ml-1 text-primary-600'
/>
</
a
>
</
div
>
)
}
</
div
>
)
}
export
default
KeyValidator
web/app/components/header/account-setting/plugin-page/SerpapiPlugin.tsx
0 → 100644
View file @
23e34136
import
{
useTranslation
}
from
'react-i18next'
import
Image
from
'next/image'
import
SerpapiLogo
from
'../../assets/serpapi.png'
import
KeyValidator
from
'../key-validator'
import
type
{
Form
,
ValidateValue
}
from
'../key-validator/declarations'
import
{
updatePluginKey
,
validatePluginKey
}
from
'./utils'
import
{
useToastContext
}
from
'@/app/components/base/toast'
import
type
{
PluginProvider
}
from
'@/models/common'
type
SerpapiPluginProps
=
{
plugin
:
PluginProvider
onUpdate
:
()
=>
void
}
const
SerpapiPlugin
=
({
plugin
,
onUpdate
,
}:
SerpapiPluginProps
)
=>
{
const
{
t
}
=
useTranslation
()
const
{
notify
}
=
useToastContext
()
const
forms
:
Form
[]
=
[{
key
:
'api_key'
,
title
:
t
(
'common.plugin.serpapi.apiKey'
),
placeholder
:
t
(
'common.plugin.serpapi.apiKeyPlaceholder'
),
value
:
plugin
.
credentials
?.
api_key
,
validate
:
{
before
:
(
v
)
=>
{
if
(
v
?.
api_key
)
return
true
},
run
:
async
(
v
)
=>
{
return
validatePluginKey
(
'serpapi'
,
{
credentials
:
{
api_key
:
v
?.
api_key
,
},
})
},
},
handleFocus
:
(
v
,
dispatch
)
=>
{
if
(
v
.
api_key
===
plugin
.
credentials
?.
api_key
)
dispatch
({
...
v
,
api_key
:
''
})
},
}]
const
handleSave
=
async
(
v
:
ValidateValue
)
=>
{
if
(
!
v
?.
api_key
||
v
?.
api_key
===
plugin
.
credentials
?.
api_key
)
return
const
res
=
await
updatePluginKey
(
'serpapi'
,
{
credentials
:
{
api_key
:
v
?.
api_key
,
},
})
if
(
res
.
status
===
'success'
)
{
notify
({
type
:
'success'
,
message
:
t
(
'common.actionMsg.modifiedSuccessfully'
)
})
onUpdate
()
return
true
}
}
return
(
<
KeyValidator
type=
'serpapi'
title=
{
<
Image
alt=
'serpapi logo'
src=
{
SerpapiLogo
}
width=
{
64
}
/>
}
status=
{
plugin
.
credentials
?.
api_key
?
'success'
:
'add'
}
forms=
{
forms
}
keyFrom=
{
{
text
:
t
(
'common.plugin.serpapi.keyFrom'
),
link
:
'https://serpapi.com/manage-api-key'
,
}
}
onSave=
{
handleSave
}
/>
)
}
export
default
SerpapiPlugin
web/app/components/header/account-setting/plugin-page/index.tsx
0 → 100644
View file @
23e34136
import
useSWR
from
'swr'
import
{
LockClosedIcon
}
from
'@heroicons/react/24/solid'
import
{
useTranslation
}
from
'react-i18next'
import
Link
from
'next/link'
import
SerpapiPlugin
from
'./SerpapiPlugin'
import
{
fetchPluginProviders
}
from
'@/service/common'
import
type
{
PluginProvider
}
from
'@/models/common'
const
PluginPage
=
()
=>
{
const
{
t
}
=
useTranslation
()
const
{
data
:
plugins
,
mutate
}
=
useSWR
(
'/workspaces/current/tool-providers'
,
fetchPluginProviders
)
const
Plugin_MAP
:
Record
<
string
,
any
>
=
{
serpapi
:
(
plugin
:
PluginProvider
)
=>
<
SerpapiPlugin
key=
'serpapi'
plugin=
{
plugin
}
onUpdate=
{
()
=>
mutate
()
}
/>,
}
return
(
<
div
className=
'pb-7'
>
<
div
>
{
plugins
?.
map
(
plugin
=>
Plugin_MAP
[
plugin
.
tool_name
](
plugin
))
}
</
div
>
<
div
className=
'fixed bottom-0 w-[472px] h-[42px] flex items-center bg-white text-xs text-gray-500'
>
<
LockClosedIcon
className=
'w-3 h-3 mr-1'
/>
{
t
(
'common.provider.encrypted.front'
)
}
<
Link
className=
'text-primary-600 mx-1'
target=
{
'_blank'
}
href=
'https://pycryptodome.readthedocs.io/en/latest/src/cipher/oaep.html'
>
PKCS1_OAEP
</
Link
>
{
t
(
'common.provider.encrypted.back'
)
}
</
div
>
</
div
>
)
}
export
default
PluginPage
web/app/components/header/account-setting/plugin-page/utils.ts
0 → 100644
View file @
23e34136
import
{
ValidatedStatus
}
from
'../key-validator/declarations'
import
{
updatePluginProviderAIKey
,
validatePluginProviderKey
}
from
'@/service/common'
export
const
validatePluginKey
=
async
(
pluginType
:
string
,
body
:
any
)
=>
{
try
{
const
res
=
await
validatePluginProviderKey
({
url
:
`/workspaces/current/tool-providers/
${
pluginType
}
/credentials-validate`
,
body
,
})
if
(
res
.
result
===
'success'
)
return
Promise
.
resolve
({
status
:
ValidatedStatus
.
Success
})
else
return
Promise
.
resolve
({
status
:
ValidatedStatus
.
Error
,
message
:
res
.
error
})
}
catch
(
e
:
any
)
{
return
Promise
.
resolve
({
status
:
ValidatedStatus
.
Error
,
message
:
e
.
message
})
}
}
export
const
updatePluginKey
=
async
(
pluginType
:
string
,
body
:
any
)
=>
{
try
{
const
res
=
await
updatePluginProviderAIKey
({
url
:
`/workspaces/current/tool-providers/
${
pluginType
}
/credentials`
,
body
,
})
if
(
res
.
result
===
'success'
)
return
Promise
.
resolve
({
status
:
ValidatedStatus
.
Success
})
else
return
Promise
.
resolve
({
status
:
ValidatedStatus
.
Error
,
message
:
res
.
error
})
}
catch
(
e
:
any
)
{
return
Promise
.
resolve
({
status
:
ValidatedStatus
.
Error
,
message
:
e
.
message
})
}
}
web/app/components/header/assets/serpapi.png
0 → 100644
View file @
23e34136
2.97 KB
web/app/components/share/chat/hooks/use-conversation.ts
View file @
23e34136
import
{
useState
}
from
'react'
import
produce
from
'immer'
import
{
useGetState
}
from
'ahooks'
import
type
{
ConversationItem
}
from
'@/models/share'
const
storageConversationIdKey
=
'conversationIdInfo'
...
...
@@ -8,7 +9,7 @@ type ConversationInfoType = Omit<ConversationItem, 'inputs' | 'id'>
function
useConversation
()
{
const
[
conversationList
,
setConversationList
]
=
useState
<
ConversationItem
[]
>
([])
const
[
pinnedConversationList
,
setPinnedConversationList
]
=
useState
<
ConversationItem
[]
>
([])
const
[
currConversationId
,
doSetCurrConversationId
]
=
use
State
<
string
>
(
'-1'
)
const
[
currConversationId
,
doSetCurrConversationId
,
getCurrConversationId
]
=
useGet
State
<
string
>
(
'-1'
)
// when set conversation id, we do not have set appId
const
setCurrConversationId
=
(
id
:
string
,
appId
:
string
,
isSetToLocalStroge
=
true
,
newConversationName
=
''
)
=>
{
doSetCurrConversationId
(
id
)
...
...
@@ -53,6 +54,7 @@ function useConversation() {
pinnedConversationList
,
setPinnedConversationList
,
currConversationId
,
getCurrConversationId
,
setCurrConversationId
,
getConversationIdFromStorage
,
isNewConversation
,
...
...
web/app/components/share/chat/index.tsx
View file @
23e34136
...
...
@@ -43,6 +43,8 @@ import Confirm from '@/app/components/base/confirm'
export
type
IMainProps
=
{
isInstalledApp
?:
boolean
installedAppInfo
?:
InstalledApp
isSupportPlugin
?:
boolean
isUniversalChat
?:
boolean
}
const
Main
:
FC
<
IMainProps
>
=
({
...
...
@@ -88,6 +90,7 @@ const Main: FC<IMainProps> = ({
pinnedConversationList
,
setPinnedConversationList
,
currConversationId
,
getCurrConversationId
,
setCurrConversationId
,
getConversationIdFromStorage
,
isNewConversation
,
...
...
@@ -212,7 +215,7 @@ const Main: FC<IMainProps> = ({
}
// update chat list of current conversation
if
(
!
isNewConversation
&&
!
conversationIdChangeBecauseOfNew
&&
!
isResponsing
)
{
if
(
!
isNewConversation
&&
!
conversationIdChangeBecauseOfNew
)
{
fetchChatList
(
currConversationId
,
isInstalledApp
,
installedAppInfo
?.
id
).
then
((
res
:
any
)
=>
{
const
{
data
}
=
res
const
newChatList
:
IChatItem
[]
=
generateNewChatListWithOpenstatement
(
notSyncToStateIntroduction
,
notSyncToStateInputs
)
...
...
@@ -421,6 +424,7 @@ const Main: FC<IMainProps> = ({
const
[
suggestQuestions
,
setSuggestQuestions
]
=
useState
<
string
[]
>
([])
const
[
messageTaskId
,
setMessageTaskId
]
=
useState
(
''
)
const
[
hasStopResponded
,
setHasStopResponded
,
getHasStopResponded
]
=
useGetState
(
false
)
const
[
isResponsingConIsCurrCon
,
setIsResponsingConCurrCon
,
getIsResponsingConIsCurrCon
]
=
useGetState
(
true
)
const
handleSend
=
async
(
message
:
string
)
=>
{
if
(
isResponsing
)
{
...
...
@@ -457,12 +461,13 @@ const Main: FC<IMainProps> = ({
content
:
''
,
isAnswer
:
true
,
}
let
tempNewConversationId
=
''
const
prevTempNewConversationId
=
getCurrConversationId
()
||
'-1'
let
tempNewConversationId
=
prevTempNewConversationId
setHasStopResponded
(
false
)
setResponsingTrue
()
setIsShowSuggestion
(
false
)
setIsResponsingConCurrCon
(
true
)
sendChatMessage
(
data
,
{
getAbortController
:
(
abortController
)
=>
{
setAbortController
(
abortController
)
...
...
@@ -474,6 +479,11 @@ const Main: FC<IMainProps> = ({
tempNewConversationId
=
newConversationId
setMessageTaskId
(
taskId
)
// has switched to other conversation
if
(
prevTempNewConversationId
!==
getCurrConversationId
())
{
setIsResponsingConCurrCon
(
false
)
return
}
// closesure new list is outdated.
const
newListWithAnswer
=
produce
(
getChatList
().
filter
(
item
=>
item
.
id
!==
responseItem
.
id
&&
item
.
id
!==
placeholderAnswerId
),
...
...
@@ -499,7 +509,7 @@ const Main: FC<IMainProps> = ({
resetNewConversationInputs
()
setChatNotStarted
()
setCurrConversationId
(
tempNewConversationId
,
appId
,
true
)
if
(
suggestedQuestionsAfterAnswerConfig
?.
enabled
&&
!
getHasStopResponded
())
{
if
(
getIsResponsingConIsCurrCon
()
&&
suggestedQuestionsAfterAnswerConfig
?.
enabled
&&
!
getHasStopResponded
())
{
const
{
data
}:
any
=
await
fetchSuggestedQuestions
(
responseItem
.
id
,
isInstalledApp
,
installedAppInfo
?.
id
)
setSuggestQuestions
(
data
)
setIsShowSuggestion
(
true
)
...
...
@@ -628,7 +638,7 @@ const Main: FC<IMainProps> = ({
isHideFeedbackEdit
onFeedback=
{
handleFeedback
}
isResponsing=
{
isResponsing
}
canStopResponsing=
{
!!
messageTaskId
}
canStopResponsing=
{
!!
messageTaskId
&&
isResponsingConIsCurrCon
}
abortResponsing=
{
async
()
=>
{
await
stopChatMessageResponding
(
appId
,
messageTaskId
,
isInstalledApp
,
installedAppInfo
?.
id
)
setHasStopResponded
(
true
)
...
...
web/app/components/share/chat/sidebar/index.tsx
View file @
23e34136
...
...
@@ -11,6 +11,7 @@ import AppInfo from '@/app/components/share/chat/sidebar/app-info'
// import Card from './card'
import
type
{
ConversationItem
,
SiteInfo
}
from
'@/models/share'
import
{
fetchConversations
}
from
'@/service/share'
import
{
fetchConversations
as
fetchUniversalConversations
}
from
'@/service/universal-chat'
export
type
ISidebarProps
=
{
copyRight
:
string
...
...
@@ -22,6 +23,7 @@ export type ISidebarProps = {
isClearPinnedConversationList
:
boolean
isInstalledApp
:
boolean
installedAppId
?:
string
isUniversalChat
?:
boolean
siteInfo
:
SiteInfo
onMoreLoaded
:
(
res
:
{
data
:
ConversationItem
[];
has_more
:
boolean
})
=>
void
onPinnedMoreLoaded
:
(
res
:
{
data
:
ConversationItem
[];
has_more
:
boolean
})
=>
void
...
...
@@ -43,6 +45,7 @@ const Sidebar: FC<ISidebarProps> = ({
isClearPinnedConversationList
,
isInstalledApp
,
installedAppId
,
isUniversalChat
,
siteInfo
,
onMoreLoaded
,
onPinnedMoreLoaded
,
...
...
@@ -57,8 +60,14 @@ const Sidebar: FC<ISidebarProps> = ({
const
[
hasPinned
,
setHasPinned
]
=
useState
(
false
)
const
checkHasPinned
=
async
()
=>
{
const
{
data
}:
any
=
await
fetchConversations
(
isInstalledApp
,
installedAppId
,
undefined
,
true
)
setHasPinned
(
data
.
length
>
0
)
let
res
:
any
if
(
isUniversalChat
)
res
=
await
fetchUniversalConversations
(
undefined
,
true
)
else
res
=
await
fetchConversations
(
isInstalledApp
,
installedAppId
,
undefined
,
true
)
setHasPinned
(
res
.
data
.
length
>
0
)
}
useEffect
(()
=>
{
...
...
@@ -70,13 +79,13 @@ const Sidebar: FC<ISidebarProps> = ({
checkHasPinned
()
},
[
controlUpdateList
])
const
maxListHeight
=
isInstalledApp
?
'max-h-[30vh]'
:
'max-h-[40vh]'
const
maxListHeight
=
(
isInstalledApp
||
isUniversalChat
)
?
'max-h-[30vh]'
:
'max-h-[40vh]'
return
(
<
div
className=
{
cn
(
isInstalledApp
?
'tablet:h-[calc(100vh_-_74px)]'
:
'tablet:h-[calc(100vh_-_3rem)]'
,
(
isInstalledApp
||
isUniversalChat
)
?
'tablet:h-[calc(100vh_-_74px)]'
:
'tablet:h-[calc(100vh_-_3rem)]'
,
'shrink-0 flex flex-col bg-white pc:w-[244px] tablet:w-[192px] mobile:w-[240px] border-r border-gray-200 mobile:h-screen'
,
)
}
...
...
@@ -109,6 +118,7 @@ const Sidebar: FC<ISidebarProps> = ({
isClearConversationList=
{
isClearPinnedConversationList
}
isInstalledApp=
{
isInstalledApp
}
installedAppId=
{
installedAppId
}
isUniversalChat=
{
isUniversalChat
}
onMoreLoaded=
{
onPinnedMoreLoaded
}
isNoMore=
{
isPinnedNoMore
}
isPinned=
{
true
}
...
...
@@ -119,18 +129,19 @@ const Sidebar: FC<ISidebarProps> = ({
</
div
>
)
}
{
/* unpinned list */
}
<
div
className=
{
cn
(
'mt-4 px-4'
,
!
hasPinned
&&
'flex flex-col flex-grow'
)
}
>
<
div
className=
{
cn
(
'
grow flex flex-col
mt-4 px-4'
,
!
hasPinned
&&
'flex flex-col flex-grow'
)
}
>
{
(
hasPinned
&&
list
.
length
>
0
)
&&
(
<
div
className=
'mb-1.5 leading-[18px] text-xs text-gray-500 font-medium uppercase'
>
{
t
(
'share.chat.unpinnedTitle'
)
}
</
div
>
)
}
<
List
className=
{
cn
(
hasPinned
?
maxListHeight
:
'flex-grow
'
)
}
className=
{
cn
(
'flex-grow h-0
'
)
}
currentId=
{
currentId
}
onCurrentIdChange=
{
onCurrentIdChange
}
list=
{
list
}
isClearConversationList=
{
isClearConversationList
}
isInstalledApp=
{
isInstalledApp
}
installedAppId=
{
installedAppId
}
isUniversalChat=
{
isUniversalChat
}
onMoreLoaded=
{
onMoreLoaded
}
isNoMore=
{
isNoMore
}
isPinned=
{
false
}
...
...
@@ -141,9 +152,11 @@ const Sidebar: FC<ISidebarProps> = ({
</
div
>
</
div
>
<
div
className=
"flex flex-shrink-0 pr-4 pb-4 pl-4"
>
<
div
className=
"text-gray-400 font-normal text-xs"
>
©
{
copyRight
}
{
(
new
Date
()).
getFullYear
()
}
</
div
>
</
div
>
{
!
isUniversalChat
&&
(
<
div
className=
"flex flex-shrink-0 pr-4 pb-4 pl-4"
>
<
div
className=
"text-gray-400 font-normal text-xs"
>
©
{
copyRight
}
{
(
new
Date
()).
getFullYear
()
}
</
div
>
</
div
>
)
}
</
div
>
)
}
...
...
web/app/components/share/chat/sidebar/list/index.tsx
View file @
23e34136
...
...
@@ -10,6 +10,7 @@ import cn from 'classnames'
import
s
from
'./style.module.css'
import
type
{
ConversationItem
}
from
'@/models/share'
import
{
fetchConversations
}
from
'@/service/share'
import
{
fetchConversations
as
fetchUniversalConversations
}
from
'@/service/universal-chat'
import
ItemOperation
from
'@/app/components/explore/item-operation'
export
type
IListProps
=
{
...
...
@@ -19,6 +20,7 @@ export type IListProps = {
list
:
ConversationItem
[]
isClearConversationList
:
boolean
isInstalledApp
:
boolean
isUniversalChat
?:
boolean
installedAppId
?:
string
onMoreLoaded
:
(
res
:
{
data
:
ConversationItem
[];
has_more
:
boolean
})
=>
void
isNoMore
:
boolean
...
...
@@ -35,6 +37,7 @@ const List: FC<IListProps> = ({
list
,
isClearConversationList
,
isInstalledApp
,
isUniversalChat
,
installedAppId
,
onMoreLoaded
,
isNoMore
,
...
...
@@ -51,8 +54,12 @@ const List: FC<IListProps> = ({
let
lastId
=
!
isClearConversationList
?
list
[
list
.
length
-
1
]?.
id
:
undefined
if
(
lastId
===
'-1'
)
lastId
=
undefined
const
{
data
:
conversations
,
has_more
}:
any
=
await
fetchConversations
(
isInstalledApp
,
installedAppId
,
lastId
,
isPinned
)
let
res
:
any
if
(
isUniversalChat
)
res
=
await
fetchUniversalConversations
(
lastId
,
isPinned
)
else
res
=
await
fetchConversations
(
isInstalledApp
,
installedAppId
,
lastId
,
isPinned
)
const
{
data
:
conversations
,
has_more
}:
any
=
res
onMoreLoaded
({
data
:
conversations
,
has_more
})
}
return
{
list
:
[]
}
...
...
@@ -68,7 +75,7 @@ const List: FC<IListProps> = ({
return
(
<
nav
ref=
{
listRef
}
className=
{
cn
(
className
,
'shrink-0 space-y-1 bg-white
pb-[85px] overflow-y-auto
'
)
}
className=
{
cn
(
className
,
'shrink-0 space-y-1 bg-white
overflow-y-auto overflow-x-hidden
'
)
}
>
{
list
.
map
((
item
)
=>
{
const
isCurrent
=
item
.
id
===
currentId
...
...
web/app/components/share/chat/welcome/index.tsx
View file @
23e34136
...
...
@@ -25,7 +25,7 @@ export type IWelcomeProps = {
canEidtInpus
:
boolean
savedInputs
:
Record
<
string
,
any
>
onInputsChange
:
(
inputs
:
Record
<
string
,
any
>
)
=>
void
plan
:
string
plan
?
:
string
}
const
Welcome
:
FC
<
IWelcomeProps
>
=
({
...
...
web/app/components/share/chatbot/sidebar/list/index.tsx
View file @
23e34136
...
...
@@ -65,7 +65,7 @@ const List: FC<IListProps> = ({
return
(
<
nav
ref=
{
listRef
}
className=
{
cn
(
className
,
'shrink-0 space-y-1 bg-white
pb-[85px]
overflow-y-auto'
)
}
className=
{
cn
(
className
,
'shrink-0 space-y-1 bg-white overflow-y-auto'
)
}
>
{
list
.
map
((
item
)
=>
{
const
isCurrent
=
item
.
id
===
currentId
...
...
web/app/styles/markdown.scss
View file @
23e34136
...
...
@@ -109,7 +109,7 @@
.markdown-body
a
{
background-color
:
transparent
;
color
:
var
(
--
color-accent-fg
)
;
color
:
#155EEF
;
text-decoration
:
none
;
}
...
...
@@ -1042,4 +1042,4 @@
.
markdown-body
:
:-
webkit-calendar-picker-indicator
{
filter
:
invert
(
50%
);
}
}
\ No newline at end of file
web/config/index.ts
View file @
23e34136
/* eslint-disable import/no-mutable-exports */
import
{
AppType
,
ProviderType
}
from
'@/types/app'
const
isDevelopment
=
process
.
env
.
NODE_ENV
===
'development'
export
let
apiPrefix
=
''
...
...
@@ -37,6 +39,21 @@ export const PUBLIC_API_PREFIX: string = publicApiPrefix
const
EDITION
=
process
.
env
.
NEXT_PUBLIC_EDITION
||
globalThis
.
document
?.
body
?.
getAttribute
(
'data-public-edition'
)
export
const
IS_CE_EDITION
=
EDITION
===
'SELF_HOSTED'
export
const
MODEL_LIST
=
[
{
id
:
'gpt-3.5-turbo'
,
name
:
'gpt-3.5-turbo'
,
type
:
AppType
.
chat
},
{
id
:
'gpt-3.5-turbo-16k'
,
name
:
'gpt-3.5-turbo-16k'
,
type
:
AppType
.
chat
},
{
id
:
'gpt-4'
,
name
:
'gpt-4'
,
type
:
AppType
.
chat
},
// 8k version
{
id
:
'claude-instant-1'
,
name
:
'claude-instant-1'
,
type
:
AppType
.
chat
,
provider
:
ProviderType
.
anthropic
},
// set 30k
{
id
:
'claude-2'
,
name
:
'claude-2'
,
type
:
AppType
.
chat
,
provider
:
ProviderType
.
anthropic
},
// set 30k
{
id
:
'gpt-3.5-turbo'
,
name
:
'gpt-3.5-turbo'
,
type
:
AppType
.
completion
},
{
id
:
'gpt-3.5-turbo-16k'
,
name
:
'gpt-3.5-turbo-16k'
,
type
:
AppType
.
completion
},
{
id
:
'text-davinci-003'
,
name
:
'text-davinci-003'
,
type
:
AppType
.
completion
},
{
id
:
'gpt-4'
,
name
:
'gpt-4'
,
type
:
AppType
.
completion
},
// 8k version
{
id
:
'claude-instant-1'
,
name
:
'claude-instant-1'
,
type
:
AppType
.
completion
,
provider
:
ProviderType
.
anthropic
},
// set 30k
{
id
:
'claude-2'
,
name
:
'claude-2'
,
type
:
AppType
.
completion
,
provider
:
ProviderType
.
anthropic
},
// set 30k
]
const
UNIVERSAL_CHAT_MODEL_ID_LIST
=
[
'gpt-3.5-turbo'
,
'gpt-3.5-turbo-16k'
,
'gpt-4'
,
'claude-2'
]
export
const
UNIVERSAL_CHAT_MODEL_LIST
=
MODEL_LIST
.
filter
(({
id
,
type
})
=>
UNIVERSAL_CHAT_MODEL_ID_LIST
.
includes
(
id
)
&&
(
type
===
AppType
.
chat
))
export
const
TONE_LIST
=
[
{
id
:
1
,
...
...
web/context/event-emitter.tsx
0 → 100644
View file @
23e34136
'use client'
import
{
createContext
,
useContext
}
from
'use-context-selector'
import
{
useEventEmitter
}
from
'ahooks'
import
type
{
EventEmitter
}
from
'ahooks/lib/useEventEmitter'
const
EventEmitterContext
=
createContext
<
{
eventEmitter
:
EventEmitter
<
string
>
|
null
}
>
({
eventEmitter
:
null
,
})
export
const
useEventEmitterContextContext
=
()
=>
useContext
(
EventEmitterContext
)
type
EventEmitterContextProviderProps
=
{
children
:
React
.
ReactNode
}
export
const
EventEmitterContextProvider
=
({
children
,
}:
EventEmitterContextProviderProps
)
=>
{
const
eventEmitter
=
useEventEmitter
<
string
>
()
return
(
<
EventEmitterContext
.
Provider
value=
{
{
eventEmitter
}
}
>
{
children
}
</
EventEmitterContext
.
Provider
>
)
}
export
default
EventEmitterContext
web/context/provider-context.tsx
0 → 100644
View file @
23e34136
'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/common.en.ts
View file @
23e34136
...
...
@@ -91,6 +91,7 @@ const translation = {
language
:
'Language'
,
provider
:
'Model Provider'
,
dataSource
:
'Data Source'
,
plugin
:
'Plugins'
,
},
account
:
{
avatar
:
'Avatar'
,
...
...
@@ -224,6 +225,13 @@ const translation = {
},
},
},
plugin
:
{
serpapi
:
{
apiKey
:
'API Key'
,
apiKeyPlaceholder
:
'Enter your API key'
,
keyFrom
:
'Get your SerpAPI key from SerpAPI Account Page'
,
},
},
about
:
{
changeLog
:
'Changlog'
,
updateNow
:
'Update now'
,
...
...
web/i18n/lang/common.zh.ts
View file @
23e34136
...
...
@@ -91,6 +91,7 @@ const translation = {
language
:
'语言'
,
provider
:
'模型供应商'
,
dataSource
:
'数据来源'
,
plugin
:
'插件'
,
},
account
:
{
avatar
:
'头像'
,
...
...
@@ -224,6 +225,13 @@ const translation = {
},
},
},
plugin
:
{
serpapi
:
{
apiKey
:
'API Key'
,
apiKeyPlaceholder
:
'输入你的 API 密钥'
,
keyFrom
:
'从 SerpAPI 帐户页面获取您的 SerpAPI 密钥'
,
},
},
about
:
{
changeLog
:
'更新日志'
,
updateNow
:
'现在更新'
,
...
...
web/i18n/lang/explore.en.ts
View file @
23e34136
...
...
@@ -2,6 +2,7 @@ const translation = {
title
:
'My Apps'
,
sidebar
:
{
discovery
:
'Discovery'
,
chat
:
'Chat'
,
workspace
:
'Workspace'
,
action
:
{
pin
:
'Pin'
,
...
...
@@ -34,6 +35,43 @@ const translation = {
Programming
:
'Programming'
,
HR
:
'HR'
,
},
universalChat
:
{
welcome
:
'Start chat with Dify'
,
welcomeDescribe
:
'Your AI conversation companion for personalized assistance'
,
model
:
'Model'
,
plugins
:
{
name
:
'Plugins'
,
google_search
:
{
name
:
'Google Search'
,
more
:
{
left
:
'Enable the plugin, '
,
link
:
'set up your SerpAPI key'
,
right
:
' first.'
,
},
},
web_reader
:
{
name
:
'Web Reader'
,
description
:
'Get needed information from any web link'
,
},
wikipedia
:
{
name
:
'Wikipedia'
,
},
},
thought
:
{
show
:
'Show'
,
hide
:
'Hide'
,
processOfThought
:
' the process of thinking'
,
res
:
{
webReader
:
{
normal
:
'Reading {url}'
,
hasPageInfo
:
'Reading next page of {url}'
,
},
search
:
'Searching {{query}}'
,
dataset
:
'Retrieving dataset {datasetName}'
,
},
},
viewConfigDetailTip
:
'In conversation, cannot change above settings'
,
},
}
export
default
translation
web/i18n/lang/explore.zh.ts
View file @
23e34136
...
...
@@ -2,6 +2,7 @@ const translation = {
title
:
'我的应用'
,
sidebar
:
{
discovery
:
'发现'
,
chat
:
'智聊'
,
workspace
:
'工作区'
,
action
:
{
pin
:
'置顶'
,
...
...
@@ -34,6 +35,43 @@ const translation = {
Programming
:
'编程'
,
HR
:
'人力资源'
,
},
universalChat
:
{
welcome
:
'开始和 Dify 聊天吧'
,
welcomeDescribe
:
'您的 AI 对话伴侣,为您提供个性化的帮助'
,
model
:
'模型'
,
plugins
:
{
name
:
'插件'
,
google_search
:
{
name
:
'谷歌搜索'
,
more
:
{
left
:
'启用插件,首先'
,
link
:
'设置您的 SerpAPI 密钥'
,
right
:
''
,
},
},
web_reader
:
{
name
:
'解析链接'
,
description
:
'从任何网页链接获取所需信息'
,
},
wikipedia
:
{
name
:
'维基百科'
,
},
},
thought
:
{
show
:
'显示'
,
hide
:
'隐藏'
,
processOfThought
:
'思考过程'
,
res
:
{
webReader
:
{
normal
:
'解析链接 {url}'
,
hasPageInfo
:
'解析链接 {url} 的下一页'
,
},
search
:
'搜索 {{query}}'
,
dataset
:
'检索数据集 {datasetName}'
,
},
},
viewConfigDetailTip
:
'在对话中,无法更改上述设置'
,
},
}
export
default
translation
web/models/common.ts
View file @
23e34136
...
...
@@ -142,3 +142,11 @@ export type DataSourceNotion = {
export
type
GithubRepo
=
{
stargazers_count
:
number
}
export
type
PluginProvider
=
{
tool_name
:
string
is_enabled
:
boolean
credentials
:
{
api_key
:
string
}
|
null
}
web/service/base.ts
View file @
23e34136
/* eslint-disable no-new, prefer-promise-reject-errors */
import
{
API_PREFIX
,
IS_CE_EDITION
,
PUBLIC_API_PREFIX
}
from
'@/config'
import
Toast
from
'@/app/components/base/toast'
import
type
{
ThoughtItem
}
from
'@/app/components/app/chat/type'
const
TIME_OUT
=
100000
...
...
@@ -30,6 +31,7 @@ export type IOnDataMoreInfo = {
}
export
type
IOnData
=
(
message
:
string
,
isFirstMessage
:
boolean
,
moreInfo
:
IOnDataMoreInfo
)
=>
void
export
type
IOnThought
=
(
though
:
ThoughtItem
)
=>
void
export
type
IOnCompleted
=
(
hasError
?:
boolean
)
=>
void
export
type
IOnError
=
(
msg
:
string
)
=>
void
...
...
@@ -39,12 +41,16 @@ type IOtherOptions = {
needAllResponseContent
?:
boolean
deleteContentType
?:
boolean
onData
?:
IOnData
// for stream
onThought
?:
IOnThought
onError
?:
IOnError
onCompleted
?:
IOnCompleted
// for stream
getAbortController
?:
(
abortController
:
AbortController
)
=>
void
}
function
unicodeToChar
(
text
:
string
)
{
if
(
!
text
)
return
''
return
text
.
replace
(
/
\\
u
[
0-9a-f
]{4}
/g
,
(
_match
,
p1
)
=>
{
return
String
.
fromCharCode
(
parseInt
(
p1
,
16
))
})
...
...
@@ -58,7 +64,7 @@ export function format(text: string) {
return
res
.
replaceAll
(
'
\
n'
,
'<br/>'
).
replaceAll
(
'```'
,
''
)
}
const
handleStream
=
(
response
:
any
,
onData
:
IOnData
,
onCompleted
?:
IOnCompleted
)
=>
{
const
handleStream
=
(
response
:
any
,
onData
:
IOnData
,
onCompleted
?:
IOnCompleted
,
onThought
?:
IOnThought
)
=>
{
if
(
!
response
.
ok
)
throw
new
Error
(
'Network response was not ok'
)
...
...
@@ -101,13 +107,18 @@ const handleStream = (response: any, onData: IOnData, onCompleted?: IOnCompleted
onCompleted
&&
onCompleted
(
true
)
return
}
// can not use format here. Because message is splited.
onData
(
unicodeToChar
(
bufferObj
.
answer
),
isFirstMessage
,
{
conversationId
:
bufferObj
.
conversation_id
,
taskId
:
bufferObj
.
task_id
,
messageId
:
bufferObj
.
id
,
})
isFirstMessage
=
false
if
(
bufferObj
.
event
===
'message'
)
{
// can not use format here. Because message is splited.
onData
(
unicodeToChar
(
bufferObj
.
answer
),
isFirstMessage
,
{
conversationId
:
bufferObj
.
conversation_id
,
taskId
:
bufferObj
.
task_id
,
messageId
:
bufferObj
.
id
,
})
isFirstMessage
=
false
}
else
if
(
bufferObj
.
event
===
'agent_thought'
)
{
onThought
?.(
bufferObj
as
any
)
}
}
})
buffer
=
lines
[
lines
.
length
-
1
]
...
...
@@ -298,7 +309,7 @@ export const upload = (options: any): Promise<any> => {
})
}
export
const
ssePost
=
(
url
:
string
,
fetchOptions
:
any
,
{
isPublicAPI
=
false
,
onData
,
onCompleted
,
onError
,
getAbortController
}:
IOtherOptions
)
=>
{
export
const
ssePost
=
(
url
:
string
,
fetchOptions
:
any
,
{
isPublicAPI
=
false
,
onData
,
onCompleted
,
on
Thought
,
on
Error
,
getAbortController
}:
IOtherOptions
)
=>
{
const
abortController
=
new
AbortController
()
const
options
=
Object
.
assign
({},
baseOptions
,
{
...
...
@@ -333,17 +344,17 @@ export const ssePost = (url: string, fetchOptions: any, { isPublicAPI = false, o
}
return
handleStream
(
res
,
(
str
:
string
,
isFirstMessage
:
boolean
,
moreInfo
:
IOnDataMoreInfo
)
=>
{
if
(
moreInfo
.
errorMessage
)
{
// debugger
onError
?.(
moreInfo
.
errorMessage
)
if
(
moreInfo
.
errorMessage
!==
'AbortError: The user aborted a request.'
)
Toast
.
notify
({
type
:
'error'
,
message
:
moreInfo
.
errorMessage
})
return
}
onData
?.(
str
,
isFirstMessage
,
moreInfo
)
},
onCompleted
)
},
onCompleted
,
onThought
)
}).
catch
((
e
)
=>
{
if
(
e
.
toString
()
!==
'AbortError: The user aborted a request.'
)
Toast
.
notify
({
type
:
'error'
,
message
:
e
})
onError
?.(
e
)
})
}
...
...
web/service/common.ts
View file @
23e34136
...
...
@@ -3,7 +3,7 @@ import { del, get, patch, post, put } from './base'
import
type
{
AccountIntegrate
,
CommonResponse
,
DataSourceNotion
,
IWorkspace
,
LangGeniusVersionResponse
,
Member
,
OauthResponse
,
Provider
,
ProviderAnthropicToken
,
ProviderAzureToken
,
TenantInfoResponse
,
OauthResponse
,
P
luginProvider
,
P
rovider
,
ProviderAnthropicToken
,
ProviderAzureToken
,
TenantInfoResponse
,
UserProfileOriginResponse
,
}
from
'@/models/common'
import
type
{
...
...
@@ -102,6 +102,17 @@ export const updateDataSourceNotionAction: Fetcher<CommonResponse, { url: string
return
patch
(
url
)
as
Promise
<
CommonResponse
>
}
export
const
fetchPluginProviders
:
Fetcher
<
PluginProvider
[]
|
null
,
string
>
=
(
url
)
=>
{
return
get
(
url
)
as
Promise
<
PluginProvider
[]
|
null
>
}
export
const
validatePluginProviderKey
:
Fetcher
<
ValidateOpenAIKeyResponse
,
{
url
:
string
;
body
:
{
credentials
:
any
}
}
>
=
({
url
,
body
})
=>
{
return
post
(
url
,
{
body
})
as
Promise
<
ValidateOpenAIKeyResponse
>
}
export
const
updatePluginProviderAIKey
:
Fetcher
<
UpdateOpenAIKeyResponse
,
{
url
:
string
;
body
:
{
credentials
:
any
}
}
>
=
({
url
,
body
})
=>
{
return
post
(
url
,
{
body
})
as
Promise
<
UpdateOpenAIKeyResponse
>
}
export
const
invitationCheck
:
Fetcher
<
CommonResponse
&
{
is_valid
:
boolean
;
workspace_name
:
string
},
{
url
:
string
;
params
:
{
workspace_id
:
string
;
email
:
string
;
token
:
string
}
}
>
=
({
url
,
params
})
=>
{
return
get
(
url
,
{
params
})
as
Promise
<
CommonResponse
&
{
is_valid
:
boolean
;
workspace_name
:
string
}
>
}
...
...
web/service/explore.ts
View file @
23e34136
...
...
@@ -31,3 +31,7 @@ export const updatePinStatus = (id: string, isPinned: boolean) => {
},
})
}
export
const
getToolProviders
=
()
=>
{
return
get
(
'/workspaces/current/tool-providers'
)
}
web/service/share.ts
View file @
23e34136
...
...
@@ -3,7 +3,7 @@ import {
del
as
consoleDel
,
get
as
consoleGet
,
patch
as
consolePatch
,
post
as
consolePost
,
delPublic
as
del
,
getPublic
as
get
,
patchPublic
as
patch
,
postPublic
as
post
,
ssePost
,
}
from
'./base'
import
type
{
Feedbacktype
}
from
'@/app/components/app/chat'
import
type
{
Feedbacktype
}
from
'@/app/components/app/chat
/type
'
function
getAction
(
action
:
'get'
|
'post'
|
'del'
|
'patch'
,
isInstalledApp
:
boolean
)
{
switch
(
action
)
{
...
...
web/service/universal-chat.ts
0 → 100644
View file @
23e34136
import
type
{
IOnCompleted
,
IOnData
,
IOnError
,
IOnThought
}
from
'./base'
import
{
del
,
get
,
patch
,
post
,
ssePost
,
}
from
'./base'
import
type
{
Feedbacktype
}
from
'@/app/components/app/chat/type'
const
baseUrl
=
'universal-chat'
function
getUrl
(
url
:
string
)
{
return
`
${
baseUrl
}
/
${
url
.
startsWith
(
'/'
)
?
url
.
slice
(
1
)
:
url
}
`
}
export
const
sendChatMessage
=
async
(
body
:
Record
<
string
,
any
>
,
{
onData
,
onCompleted
,
onError
,
onThought
,
getAbortController
}:
{
onData
:
IOnData
onCompleted
:
IOnCompleted
onError
:
IOnError
onThought
:
IOnThought
getAbortController
?:
(
abortController
:
AbortController
)
=>
void
})
=>
{
return
ssePost
(
getUrl
(
'messages'
),
{
body
:
{
...
body
,
response_mode
:
'streaming'
,
},
},
{
onData
,
onCompleted
,
onThought
,
onError
,
getAbortController
})
}
export
const
stopChatMessageResponding
=
async
(
taskId
:
string
)
=>
{
return
post
(
getUrl
(
`messages/
${
taskId
}
/stop`
))
}
export
const
fetchConversations
=
async
(
last_id
?:
string
,
pinned
?:
boolean
,
limit
?:
number
)
=>
{
return
get
(
getUrl
(
'conversations'
),
{
params
:
{
...{
limit
:
limit
||
20
},
...(
last_id
?
{
last_id
}
:
{}),
...(
pinned
!==
undefined
?
{
pinned
}
:
{})
}
})
}
export
const
pinConversation
=
async
(
id
:
string
)
=>
{
return
patch
(
getUrl
(
`conversations/
${
id
}
/pin`
))
}
export
const
unpinConversation
=
async
(
id
:
string
)
=>
{
return
patch
(
getUrl
(
`conversations/
${
id
}
/unpin`
))
}
export
const
delConversation
=
async
(
id
:
string
)
=>
{
return
del
(
getUrl
(
`conversations/
${
id
}
`
))
}
export
const
fetchChatList
=
async
(
conversationId
:
string
)
=>
{
return
get
(
getUrl
(
'messages'
),
{
params
:
{
conversation_id
:
conversationId
,
limit
:
20
,
last_id
:
''
}
})
}
// init value. wait for server update
export
const
fetchAppParams
=
async
()
=>
{
return
get
(
getUrl
(
'parameters'
))
}
export
const
updateFeedback
=
async
({
url
,
body
}:
{
url
:
string
;
body
:
Feedbacktype
})
=>
{
return
post
(
getUrl
(
url
),
{
body
})
}
export
const
fetchMoreLikeThis
=
async
(
messageId
:
string
)
=>
{
return
get
(
getUrl
(
`/messages/
${
messageId
}
/more-like-this`
),
{
params
:
{
response_mode
:
'blocking'
,
},
})
}
export
const
fetchSuggestedQuestions
=
(
messageId
:
string
)
=>
{
return
get
(
getUrl
(
`/messages/
${
messageId
}
/suggested-questions`
))
}
export
const
audioToText
=
(
url
:
string
,
body
:
FormData
)
=>
{
return
post
(
url
,
{
body
},
{
bodyStringify
:
false
,
deleteContentType
:
true
})
as
Promise
<
{
text
:
string
}
>
}
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