Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
S
sdream-ai-fe
Overview
Overview
Details
Activity
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
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
侯明涛
sdream-ai-fe
Commits
898f1d23
Commit
898f1d23
authored
Aug 13, 2024
by
HoMeTown
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 推荐问题
parent
e60b07fe
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
108 additions
and
22 deletions
+108
-22
src/assets/svg/sendBlack.svg
+22
-0
src/pages/Chat/Chat.tsx
+1
-1
src/pages/Chat/components/ChatItem/ChatAnswerAttchment.tsx
+11
-15
src/pages/Chat/components/ChatItem/ChatAnswerBox.tsx
+13
-3
src/pages/Chat/components/ChatItem/ChatAnswerParser.tsx
+7
-3
src/pages/Chat/components/ChatItem/ChatAnswerRecommend.tsx
+53
-0
src/types/chat.ts
+1
-0
No files found.
src/assets/svg/sendBlack.svg
0 → 100644
View file @
898f1d23
<?xml version="1.0" encoding="UTF-8"?>
<svg
width=
"14px"
height=
"14px"
viewBox=
"0 0 24 24"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
>
<title>
蒙版
</title>
<defs>
<rect
id=
"path-1"
x=
"0"
y=
"0"
width=
"24"
height=
"24"
></rect>
</defs>
<g
id=
"晓得---PC端页面-草稿"
stroke=
"none"
stroke-width=
"1"
fill=
"none"
fill-rule=
"evenodd"
>
<g
id=
"晓得-PC端---当前对话提问"
transform=
"translate(-1446.000000, -972.000000)"
>
<g
id=
"输入框"
transform=
"translate(498.000000, 948.000000)"
>
<g
id=
"发送-点击"
transform=
"translate(940.000000, 16.000000)"
>
<g
id=
"编组-9"
transform=
"translate(8.000000, 8.000000)"
>
<mask
id=
"mask-2"
fill=
"white"
>
<use
xlink:href=
"#path-1"
></use>
</mask>
<g
id=
"蒙版"
></g>
<path
d=
"M6.11031748,17.8599937 C6.89136606,18.6410423 6.89136606,19.9073723 6.11031748,20.6884209 L5.16750844,21.6312299 C4.38645986,22.4122785 3.1201299,22.4122785 2.33908131,21.6312299 C1.55803273,20.8501813 1.55803273,19.5838514 2.33908131,18.8028028 L3.28189036,17.8599937 C4.06293894,17.0789452 5.3292689,17.0789452 6.11031748,17.8599937 Z M18.5659347,2.66666667 C20.0386941,2.66666667 21.2326014,3.860574 21.2326014,5.33333333 L21.2326014,16.6666667 C21.2326014,17.7712362 20.3371709,18.6666667 19.2326014,18.6666667 C18.1280319,18.6666667 17.2326014,17.7712362 17.2326014,16.6666667 L17.2322949,9.56566667 L11.0531265,15.7456118 C10.2720779,16.5266604 9.00574798,16.5266604 8.2246994,15.7456118 C7.44365081,14.9645632 7.44365081,13.6982333 8.2246994,12.9171847 L14.4742949,6.66666667 L7.23260141,6.66666667 C6.12803191,6.66666667 5.23260141,5.77123617 5.23260141,4.66666667 C5.23260141,3.56209717 6.12803191,2.66666667 7.23260141,2.66666667 L18.5659347,2.66666667 Z"
id=
"形状结合"
fill=
"#666"
mask=
"url(#mask-2)"
></path>
</g>
</g>
</g>
</g>
</g>
</svg>
src/pages/Chat/Chat.tsx
View file @
898f1d23
...
...
@@ -146,7 +146,7 @@ export const Chat: React.FC = () => {
<
div
className=
"w-full chatItem max-w-[1000px] mx-auto"
key=
{
index
}
>
{
record
.
role
===
'system'
&&
<
ChatWelcome
/>
}
{
record
.
role
===
'user'
&&
<
ChatItemUser
record=
{
record
}
/>
}
{
record
.
role
===
'ai'
&&
<
ChatAnswerBox
isLastAnswer=
{
index
===
allItems
.
length
-
1
}
showIndex=
{
0
}
record=
{
record
}
index=
{
index
}
/>
}
{
record
.
role
===
'ai'
&&
<
ChatAnswerBox
onSubmitQuestion=
{
handleSubmitQuestion
}
isLastAnswer=
{
index
===
allItems
.
length
-
1
}
showIndex=
{
0
}
record=
{
record
}
index=
{
index
}
/>
}
</
div
>
))
}
</
div
>
...
...
src/pages/Chat/components/ChatItem/ChatAnswerAttchment.tsx
View file @
898f1d23
import
{
Button
}
from
'@nextui-org/react'
import
{
Link
}
from
'@nextui-org/react'
import
type
{
Answer
}
from
'@/types/chat'
import
AnswerProDetailIcon
from
'@/assets/svg/answerProDetail.svg?react'
import
LinkIcon
from
'@/assets/svg/link.svg?react'
interface
ChatAnswerAttachmentProps
{
answer
:
Answer
}
export
const
ChatAnswerAttachment
:
React
.
FC
<
ChatAnswerAttachmentProps
>
=
({
answer
})
=>
{
const
handleReferenceLink
=
(
link
:
string
)
=>
{
window
.
open
(
link
)
}
return
(
<
div
className=
"attachmentList flex flex-col gap-[20px] mt-[20px]"
>
{
answer
.
attachmentList
&&
answer
.
attachmentList
.
map
((
attachment
,
index
)
=>
(
...
...
@@ -29,19 +25,19 @@ export const ChatAnswerAttachment: React.FC<ChatAnswerAttachmentProps> = ({ answ
{
/* 附件:引用文件 */
}
{
attachment
.
type
===
'reference'
&&
(
<
div
>
<
p
className=
"text-[14px] text-[#8D9795] mb-[12px]
pl-[14px]
"
>
<
p
className=
"text-[14px] text-[#8D9795] mb-[12px]"
>
已为您找到
{
attachment
.
content
.
docList
.
length
}
篇资料作为参考
篇资料作为参考
:
</
p
>
<
div
className=
"flex flex-col gap-[
12
px]"
>
{
attachment
.
content
.
docList
.
map
(
doc
=>
(
<
Button
onClick=
{
()
=>
handleReferenceLink
(
doc
.
docId
)
}
key=
{
doc
.
docId
}
color=
"primary"
variant=
"light"
className=
"text-left bg-[#F6F6F8] w-fit text-[#333] rounded-[8px] data-[hover=true]:bg-[#E5F6FF] data-[hover=true]:text-primary
"
>
<
LinkIcon
/>
<
div
className=
"w-[150px] sm:w-full text-nowrap text-ellipsis overflow-hidden"
>
{
doc
.
docName
}
</
div
>
</
Button
>
<
div
className=
"flex flex-col gap-[
9
px]"
>
{
attachment
.
content
.
docList
.
map
(
(
doc
,
docIdx
)
=>
(
<
Link
size=
"sm"
key=
{
doc
.
docId
}
isExternal
href=
{
doc
.
docId
}
showAnchorIcon
underline=
"hover
"
>
{
docIdx
+
1
}
.
{
' '
}
{
doc
.
docName
}
</
Link
>
))
}
</
div
>
</
div
>
...
...
src/pages/Chat/components/ChatItem/ChatAnswerBox.tsx
View file @
898f1d23
import
{
Avatar
,
Spinner
}
from
'@nextui-org/react'
import
{
motion
}
from
'framer-motion'
import
{
useState
}
from
'react'
import
{
ChatAnswerShower
}
from
'./ChatAnswerShower'
import
{
ChatAnswerParser
}
from
'./ChatAnswerParser'
import
type
{
ChatRecord
}
from
'@/types/chat'
import
{
ChatAnswerRecommend
}
from
'./ChatAnswerRecommend'
import
type
{
Answer
,
ChatRecord
}
from
'@/types/chat'
import
AvatarBot
from
'@/assets/avatarBot.png'
interface
ChatAnswerBoxProps
{
...
...
@@ -10,9 +12,16 @@ interface ChatAnswerBoxProps {
showIndex
:
number
isLastAnswer
:
boolean
index
:
number
onSubmitQuestion
:
(
question
:
string
)
=>
void
}
export
const
ChatAnswerBox
:
React
.
FC
<
ChatAnswerBoxProps
>
=
({
record
,
showIndex
})
=>
{
export
const
ChatAnswerBox
:
React
.
FC
<
ChatAnswerBoxProps
>
=
({
record
,
showIndex
,
isLastAnswer
,
onSubmitQuestion
})
=>
{
const
[
isShowRecommend
,
setIsShowRecommend
]
=
useState
(
false
)
const
[
recommendUseAnswer
,
setRecommendUseAnswer
]
=
useState
<
Answer
>
()
const
handleComplate
=
(
answer
:
Answer
)
=>
{
setIsShowRecommend
(
true
)
setRecommendUseAnswer
(
answer
)
}
return
(
<
div
>
{
record
.
answerList
.
map
((
item
,
index
)
=>
{
...
...
@@ -27,7 +36,7 @@ export const ChatAnswerBox: React.FC<ChatAnswerBoxProps> = ({ record, showIndex
{
item
.
answer
&&
(
<
div
className=
"content"
>
{
item
.
isShow
&&
<
ChatAnswerShower
answer=
{
item
}
/>
}
{
!
item
.
isShow
&&
<
ChatAnswerParser
answer=
{
item
}
/>
}
{
!
item
.
isShow
&&
<
ChatAnswerParser
onComplate=
{
()
=>
handleComplate
(
item
)
}
answer=
{
item
}
/>
}
</
div
>
)
}
{
!
item
.
answer
&&
(
...
...
@@ -36,6 +45,7 @@ export const ChatAnswerBox: React.FC<ChatAnswerBoxProps> = ({ record, showIndex
</
motion
.
div
>
<
div
className=
"w-[130px]"
></
div
>
</
div
>
{
isLastAnswer
&&
isShowRecommend
&&
recommendUseAnswer
&&
<
ChatAnswerRecommend
onSubmitQuestion=
{
onSubmitQuestion
}
answer=
{
recommendUseAnswer
}
/>
}
<
div
className=
"h-[32px] w-full"
></
div
>
</
div
>
)
...
...
src/pages/Chat/components/ChatItem/ChatAnswerParser.tsx
View file @
898f1d23
...
...
@@ -5,22 +5,25 @@ import rehypeSanitize from 'rehype-sanitize'
import
remarkGfm
from
'remark-gfm'
import
{
ChatAnswerAttachment
}
from
'./ChatAnswerAttchment'
import
{
ChatAnswerOperate
}
from
'./ChatAnswerOperate'
import
{
formatMarkdown
}
from
'./markdownFormatter'
import
type
{
Answer
}
from
'@/types/chat'
interface
ChatAnswerParserProps
{
answer
:
Answer
onComplate
:
()
=>
void
}
export
const
ChatAnswerParser
:
React
.
FC
<
ChatAnswerParserProps
>
=
({
answer
})
=>
{
export
const
ChatAnswerParser
:
React
.
FC
<
ChatAnswerParserProps
>
=
({
onComplate
,
answer
})
=>
{
const
formatAnswer
=
formatMarkdown
(
answer
.
answer
||
''
)
const
[
displayedText
,
setDisplayedText
]
=
useState
(
''
)
const
[
currentIndex
,
setCurrentIndex
]
=
useState
(
0
)
const
[
isTyping
,
setIsTyping
]
=
useState
(
false
)
useEffect
(()
=>
{
setIsTyping
(
true
)
if
(
currentIndex
<
answer
.
a
nswer
.
length
)
{
if
(
currentIndex
<
formatA
nswer
.
length
)
{
const
timer
=
setTimeout
(()
=>
{
setDisplayedText
(
answer
.
a
nswer
.
slice
(
0
,
currentIndex
+
1
))
setDisplayedText
(
formatA
nswer
.
slice
(
0
,
currentIndex
+
1
))
setCurrentIndex
(
prevIndex
=>
prevIndex
+
1
)
},
10
)
// 调整此值以改变打字速度
...
...
@@ -28,6 +31,7 @@ export const ChatAnswerParser: React.FC<ChatAnswerParserProps> = ({ answer }) =>
}
else
{
setIsTyping
(
false
)
onComplate
()
}
},
[
answer
,
currentIndex
])
...
...
src/pages/Chat/components/ChatItem/ChatAnswerRecommend.tsx
0 → 100644
View file @
898f1d23
import
{
useEffect
,
useState
}
from
'react'
import
{
Button
,
Skeleton
}
from
'@nextui-org/react'
import
type
{
Answer
}
from
'@/types/chat'
import
{
fetchQueryRecommendQuestion
}
from
'@/api/chat'
import
SendIcon
from
'@/assets/svg/sendBlack.svg?react'
interface
ChatAnswerRecommendProps
{
answer
:
Answer
onSubmitQuestion
:
(
question
:
string
)
=>
void
}
export
const
ChatAnswerRecommend
:
React
.
FC
<
ChatAnswerRecommendProps
>
=
({
answer
,
onSubmitQuestion
})
=>
{
const
[
questionList
,
setQuestionList
]
=
useState
<
string
[]
>
([])
const
getAnswerRecommend
=
async
()
=>
{
const
res
=
await
fetchQueryRecommendQuestion
(
answer
.
conversationId
||
''
,
answer
.
recordId
||
''
)
if
(
res
.
ok
)
{
setQuestionList
(
res
.
data
.
questionList
)
}
}
useEffect
(()
=>
{
getAnswerRecommend
()
})
return
(
<
div
className=
"pl-[62px] mt-[12px] flex flex-col"
>
{
questionList
.
length
!==
0
&&
(
<
div
className=
"flex flex-col gap-[8px]"
>
{
questionList
.
map
((
item
,
index
)
=>
(
<
Button
onClick=
{
()
=>
onSubmitQuestion
(
item
)
}
key=
{
index
}
color=
"primary"
variant=
"light"
className=
"text-left bg-[#fff] w-fit text-[#333] rounded-[8px] data-[hover=true]:bg-[#F6F6F8] data-[hover=true]:text-[#333]"
>
<
div
className=
"w-[150px] sm:w-full text-nowrap text-ellipsis overflow-hidden"
>
{
item
}
</
div
>
<
SendIcon
/>
</
Button
>
))
}
</
div
>
)
}
{
questionList
.
length
===
0
&&
(
<
div
className=
"flex flex-col gap-[8px]"
>
<
Skeleton
className=
"w-[300px] rounded-lg"
>
<
div
className=
"h-[40px] w-full rounded-lg bg-[#fff]"
></
div
>
</
Skeleton
>
<
Skeleton
className=
"w-[300px] rounded-lg"
>
<
div
className=
"h-[40px] w-full rounded-lg bg-[#fff]"
></
div
>
</
Skeleton
>
</
div
>
)
}
</
div
>
)
}
src/types/chat.ts
View file @
898f1d23
...
...
@@ -22,6 +22,7 @@ export interface Answer {
groupId
?:
string
question
?:
string
recordId
?:
string
conversationId
?:
string
terminateFlag
?:
boolean
toolName
?:
string
attachmentList
:
Attachment
[]
...
...
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