Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
赵月辉
/
fastgpt-migrated
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
a510f96b
authored
Jul 18, 2023
by
archer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
markdown guide
parent
505aff3d
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
136 additions
and
38 deletions
+136
-38
client/src/api/fetch.ts
+0
-2
client/src/components/ChatBox/index.tsx
+37
-16
client/src/components/Markdown/chat/Guide.tsx
+49
-0
client/src/components/Markdown/constant.ts
+3
-0
client/src/components/Markdown/index.tsx
+32
-13
client/src/pages/app/detail/components/Settings.tsx
+1
-1
client/src/pages/app/detail/components/edit/components/Nodes/NodeUserGuide.tsx
+1
-1
client/src/pages/chat/components/ToolMenu.tsx
+13
-5
No files found.
client/src/api/fetch.ts
View file @
a510f96b
...
@@ -89,8 +89,6 @@ export const streamFetch = ({
...
@@ -89,8 +89,6 @@ export const streamFetch = ({
});
});
read
();
read
();
}
catch
(
err
:
any
)
{
}
catch
(
err
:
any
)
{
console
.
log
(
111111111111111111
);
if
(
err
?.
message
===
'The user aborted a request.'
)
{
if
(
err
?.
message
===
'The user aborted a request.'
)
{
return
resolve
({
return
resolve
({
responseText
,
responseText
,
...
...
client/src/components/ChatBox/index.tsx
View file @
a510f96b
...
@@ -17,6 +17,7 @@ import { useUserStore } from '@/store/user';
...
@@ -17,6 +17,7 @@ import { useUserStore } from '@/store/user';
import
{
Types
}
from
'mongoose'
;
import
{
Types
}
from
'mongoose'
;
import
{
HUMAN_ICON
,
quoteLenKey
,
rawSearchKey
}
from
'@/constants/chat'
;
import
{
HUMAN_ICON
,
quoteLenKey
,
rawSearchKey
}
from
'@/constants/chat'
;
import
Markdown
from
'@/components/Markdown'
;
import
Markdown
from
'@/components/Markdown'
;
import
{
EventNameEnum
}
from
'../Markdown/constant'
;
import
MyIcon
from
'@/components/Icon'
;
import
MyIcon
from
'@/components/Icon'
;
import
Avatar
from
'@/components/Avatar'
;
import
Avatar
from
'@/components/Avatar'
;
...
@@ -236,7 +237,7 @@ const ChatBox = (
...
@@ -236,7 +237,7 @@ const ChatBox = (
* user confirm send prompt
* user confirm send prompt
*/
*/
const
sendPrompt
=
useCallback
(
const
sendPrompt
=
useCallback
(
async
(
data
:
Record
<
string
,
any
>
=
{})
=>
{
async
(
data
:
Record
<
string
,
any
>
=
{}
,
inputVal
=
''
)
=>
{
if
(
isChatting
)
{
if
(
isChatting
)
{
toast
({
toast
({
title
:
'正在聊天中...请等待结束'
,
title
:
'正在聊天中...请等待结束'
,
...
@@ -245,8 +246,7 @@ const ChatBox = (
...
@@ -245,8 +246,7 @@ const ChatBox = (
return
;
return
;
}
}
// get input value
// get input value
const
value
=
TextareaDom
.
current
?.
value
||
''
;
const
val
=
inputVal
.
trim
().
replace
(
/
\n\s
*/g
,
'\n'
);
const
val
=
value
.
trim
().
replace
(
/
\n\s
*/g
,
'\n'
);
if
(
!
val
)
{
if
(
!
val
)
{
toast
({
toast
({
...
@@ -320,7 +320,7 @@ const ChatBox = (
...
@@ -320,7 +320,7 @@ const ChatBox = (
});
});
if
(
!
err
?.
responseText
)
{
if
(
!
err
?.
responseText
)
{
resetInputVal
(
value
);
resetInputVal
(
inputVal
);
setChatHistory
(
newChatList
.
slice
(
0
,
newChatList
.
length
-
2
));
setChatHistory
(
newChatList
.
slice
(
0
,
newChatList
.
length
-
2
));
}
}
...
@@ -403,12 +403,26 @@ const ChatBox = (
...
@@ -403,12 +403,26 @@ const ChatBox = (
{
/* avatar */
}
{
/* avatar */
}
<
ChatAvatar
src=
{
appAvatar
}
order=
{
1
}
mr=
{
[
'6px'
,
2
]
}
/>
<
ChatAvatar
src=
{
appAvatar
}
order=
{
1
}
mr=
{
[
'6px'
,
2
]
}
/>
{
/* message */
}
{
/* message */
}
<
Flex
order=
{
2
}
pt=
{
2
}
maxW=
{
`calc(100% - ${isLargeWidth ? '75px' : '58px'})`
}
>
<
Card
<
Card
bg=
{
'white'
}
px=
{
4
}
py=
{
3
}
borderRadius=
{
'0 8px 8px 8px'
}
>
order=
{
2
}
{
welcomeText
}
mt=
{
2
}
px=
{
4
}
py=
{
3
}
bg=
{
'white'
}
maxW=
{
`calc(100% - ${isLargeWidth ? '75px' : '58px'})`
}
borderRadius=
{
'0 8px 8px 8px'
}
>
<
Markdown
source=
{
`~~~guide \n${welcomeText}`
}
isChatting=
{
false
}
onClick=
{
(
e
)
=>
{
const
val
=
e
?.
data
;
if
(
e
?.
event
!==
EventNameEnum
.
guideClick
||
!
val
)
return
;
handleSubmit
((
data
)
=>
sendPrompt
(
data
,
val
))();
}
}
/>
</
Card
>
</
Card
>
</
Flex
>
</
Flex
>
</
Flex
>
)
}
)
}
{
/* variable input */
}
{
/* variable input */
}
{
!!
variableModules
?.
length
&&
(
{
!!
variableModules
?.
length
&&
(
...
@@ -416,11 +430,18 @@ const ChatBox = (
...
@@ -416,11 +430,18 @@ const ChatBox = (
{
/* avatar */
}
{
/* avatar */
}
<
ChatAvatar
src=
{
appAvatar
}
order=
{
1
}
mr=
{
[
'6px'
,
2
]
}
/>
<
ChatAvatar
src=
{
appAvatar
}
order=
{
1
}
mr=
{
[
'6px'
,
2
]
}
/>
{
/* message */
}
{
/* message */
}
<
Flex
order=
{
2
}
pt=
{
2
}
maxW=
{
`calc(100% - ${isLargeWidth ? '75px' : '58px'})`
}
>
<
Card
<
Card
bg=
{
'white'
}
px=
{
4
}
py=
{
3
}
borderRadius=
{
'0 8px 8px 8px'
}
>
order=
{
2
}
<
Box
>
mt=
{
2
}
flex=
{
1
}
bg=
{
'white'
}
px=
{
4
}
py=
{
3
}
borderRadius=
{
'0 8px 8px 8px'
}
maxW=
{
'min(100%,400px)'
}
>
{
variableModules
.
map
((
item
)
=>
(
{
variableModules
.
map
((
item
)
=>
(
<
Box
w=
{
'min(100%,300px)'
}
key=
{
item
.
id
}
mb=
{
4
}
>
<
Box
key=
{
item
.
id
}
mb=
{
4
}
>
<
VariableLabel
required=
{
item
.
required
}
>
{
item
.
label
}
</
VariableLabel
>
<
VariableLabel
required=
{
item
.
required
}
>
{
item
.
label
}
</
VariableLabel
>
{
item
.
type
===
VariableInputEnum
.
input
&&
(
{
item
.
type
===
VariableInputEnum
.
input
&&
(
<
Input
<
Input
...
@@ -461,10 +482,8 @@ const ChatBox = (
...
@@ -461,10 +482,8 @@ const ChatBox = (
{
'开始对话'
}
{
'开始对话'
}
</
Button
>
</
Button
>
)
}
)
}
</
Box
>
</
Card
>
</
Card
>
</
Flex
>
</
Flex
>
</
Flex
>
)
}
)
}
{
/* chat history */
}
{
/* chat history */
}
...
@@ -650,7 +669,7 @@ const ChatBox = (
...
@@ -650,7 +669,7 @@ const ChatBox = (
onKeyDown=
{
(
e
)
=>
{
onKeyDown=
{
(
e
)
=>
{
// 触发快捷发送
// 触发快捷发送
if
(
e
.
keyCode
===
13
&&
!
e
.
shiftKey
)
{
if
(
e
.
keyCode
===
13
&&
!
e
.
shiftKey
)
{
handleSubmit
(
sendPrompt
)();
handleSubmit
(
(
data
)
=>
sendPrompt
(
data
,
TextareaDom
.
current
?.
value
)
)();
e
.
preventDefault
();
e
.
preventDefault
();
}
}
// 全选内容
// 全选内容
...
@@ -685,7 +704,9 @@ const ChatBox = (
...
@@ -685,7 +704,9 @@ const ChatBox = (
height=
{
[
'18px'
,
'20px'
]
}
height=
{
[
'18px'
,
'20px'
]
}
cursor=
{
'pointer'
}
cursor=
{
'pointer'
}
color=
{
'gray.500'
}
color=
{
'gray.500'
}
onClick=
{
handleSubmit
(
sendPrompt
)
}
onClick=
{
()
=>
{
handleSubmit
((
data
)
=>
sendPrompt
(
data
,
TextareaDom
.
current
?.
value
))();
}
}
/>
/>
)
}
)
}
</
Flex
>
</
Flex
>
...
...
client/src/components/Markdown/chat/Guide.tsx
0 → 100644
View file @
a510f96b
import
React
,
{
useMemo
}
from
'react'
;
import
{
Box
}
from
'@chakra-ui/react'
;
import
ReactMarkdown
from
'react-markdown'
;
import
RemarkGfm
from
'remark-gfm'
;
import
RemarkMath
from
'remark-math'
;
import
RehypeKatex
from
'rehype-katex'
;
import
'katex/dist/katex.min.css'
;
import
styles
from
'../index.module.scss'
;
import
{
EventNameEnum
}
from
'../constant'
;
const
Guide
=
({
text
,
onClick
}:
{
text
:
string
;
onClick
?:
(
e
:
any
)
=>
void
})
=>
{
const
formatText
=
useMemo
(()
=>
text
.
replace
(
/
\[(
.*
?)\]
/g
,
'[$1]()'
),
[
text
]);
return
(
<
ReactMarkdown
className=
{
`markdown ${styles.markdown}`
}
remarkPlugins=
{
[
RemarkGfm
,
RemarkMath
]
}
rehypePlugins=
{
[
RehypeKatex
]
}
components=
{
{
a
({
children
}:
any
)
{
return
(
<
Box
as=
{
'li'
}
py=
{
1
}
m=
{
0
}
>
<
Box
as=
{
'span'
}
color=
{
'blue.600'
}
textDecoration=
{
'underline'
}
cursor=
{
'pointer'
}
onClick=
{
()
=>
{
if
(
!
onClick
)
return
;
onClick
({
event
:
EventNameEnum
.
guideClick
,
data
:
String
(
children
)
});
}
}
>
{
String
(
children
)
}
</
Box
>
</
Box
>
);
}
}
}
>
{
formatText
}
</
ReactMarkdown
>
);
};
export
default
React
.
memo
(
Guide
);
client/src/components/Markdown/constant.ts
0 → 100644
View file @
a510f96b
export
enum
EventNameEnum
{
guideClick
=
'guideClick'
}
client/src/components/Markdown/index.tsx
View file @
a510f96b
import
React
from
'react'
;
import
React
,
{
useRef
}
from
'react'
;
import
ReactMarkdown
from
'react-markdown'
;
import
ReactMarkdown
from
'react-markdown'
;
import
RemarkGfm
from
'remark-gfm'
;
import
RemarkGfm
from
'remark-gfm'
;
import
RemarkMath
from
'remark-math'
;
import
RemarkMath
from
'remark-math'
;
...
@@ -7,19 +7,27 @@ import RemarkBreaks from 'remark-breaks';
...
@@ -7,19 +7,27 @@ import RemarkBreaks from 'remark-breaks';
import
'katex/dist/katex.min.css'
;
import
'katex/dist/katex.min.css'
;
import
styles
from
'./index.module.scss'
;
import
styles
from
'./index.module.scss'
;
import
dynamic
from
'next/dynamic'
;
import
Link
from
'./Link'
;
import
Link
from
'./Link'
;
import
CodeLight
from
'./CodeLight'
;
import
CodeLight
from
'./CodeLight'
;
import
MermaidCodeBlock
from
'./img/MermaidCodeBlock'
;
import
MdImage
from
'./img/Image'
;
function
Code
({
inline
,
className
,
children
}:
any
)
{
const
MermaidCodeBlock
=
dynamic
(()
=>
import
(
'./img/MermaidCodeBlock'
));
const
MdImage
=
dynamic
(()
=>
import
(
'./img/Image'
));
const
ChatGuide
=
dynamic
(()
=>
import
(
'./chat/Guide'
));
function
Code
({
inline
,
className
,
children
,
onClick
}:
any
)
{
const
match
=
/language-
(\w
+
)
/
.
exec
(
className
||
''
);
const
match
=
/language-
(\w
+
)
/
.
exec
(
className
||
''
);
const
codeType
=
match
?.[
1
];
if
(
match
?.[
1
]
===
'mermaid'
)
{
if
(
codeType
===
'mermaid'
)
{
return
<
MermaidCodeBlock
code=
{
String
(
children
)
}
/>;
return
<
MermaidCodeBlock
code=
{
String
(
children
)
}
/>;
}
}
if
(
codeType
===
'guide'
)
{
return
<
ChatGuide
text=
{
String
(
children
)
}
onClick=
{
onClick
}
/>;
}
return
(
return
(
<
CodeLight
className=
{
className
}
inline=
{
inline
}
match=
{
match
}
>
<
CodeLight
className=
{
className
}
inline=
{
inline
}
match=
{
match
}
>
{
children
}
{
children
}
...
@@ -31,7 +39,23 @@ function Image({ src }: { src?: string }) {
...
@@ -31,7 +39,23 @@ function Image({ src }: { src?: string }) {
return
<
MdImage
src=
{
src
}
/>;
return
<
MdImage
src=
{
src
}
/>;
}
}
const
Markdown
=
({
source
,
isChatting
=
false
}:
{
source
:
string
;
isChatting
?:
boolean
})
=>
{
const
Markdown
=
({
source
,
isChatting
=
false
,
onClick
}:
{
source
:
string
;
isChatting
?:
boolean
;
onClick
?:
(
e
:
any
)
=>
void
;
})
=>
{
const
components
=
useRef
({
a
:
Link
,
img
:
Image
,
pre
:
'div'
,
p
:
'div'
,
code
:
(
props
:
any
)
=>
<
Code
{
...
props
}
onClick=
{
onClick
}
/>
});
return
(
return
(
<
ReactMarkdown
<
ReactMarkdown
className=
{
`markdown ${styles.markdown}
className=
{
`markdown ${styles.markdown}
...
@@ -39,13 +63,8 @@ const Markdown = ({ source, isChatting = false }: { source: string; isChatting?:
...
@@ -39,13 +63,8 @@ const Markdown = ({ source, isChatting = false }: { source: string; isChatting?:
`
}
`
}
remarkPlugins=
{
[
RemarkGfm
,
RemarkMath
,
RemarkBreaks
]
}
remarkPlugins=
{
[
RemarkGfm
,
RemarkMath
,
RemarkBreaks
]
}
rehypePlugins=
{
[
RehypeKatex
]
}
rehypePlugins=
{
[
RehypeKatex
]
}
components=
{
{
// @ts-ignore
a
:
Link
,
components=
{
components
.
current
}
img
:
Image
,
pre
:
'div'
,
p
:
'div'
,
code
:
Code
}
}
>
>
{
source
}
{
source
}
</
ReactMarkdown
>
</
ReactMarkdown
>
...
...
client/src/pages/app/detail/components/Settings.tsx
View file @
a510f96b
...
@@ -28,7 +28,7 @@ const Settings = ({ appId }: { appId: string }) => {
...
@@ -28,7 +28,7 @@ const Settings = ({ appId }: { appId: string }) => {
content
:
'确认删除该应用?'
content
:
'确认删除该应用?'
});
});
const
[
settingAppInfo
,
setSettingAppInfo
]
=
useState
<
AppSchema
>
();
const
[
settingAppInfo
,
setSettingAppInfo
]
=
useState
<
AppSchema
>
();
const
[
fullScreen
,
setFullScreen
]
=
useState
(
tru
e
);
const
[
fullScreen
,
setFullScreen
]
=
useState
(
fals
e
);
/* 点击删除 */
/* 点击删除 */
const
handleDelModel
=
useCallback
(
async
()
=>
{
const
handleDelModel
=
useCallback
(
async
()
=>
{
...
...
client/src/pages/app/detail/components/edit/components/Nodes/NodeUserGuide.tsx
View file @
a510f96b
...
@@ -12,7 +12,7 @@ const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6);
...
@@ -12,7 +12,7 @@ const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 6);
import
MyTooltip
from
'@/components/MyTooltip'
;
import
MyTooltip
from
'@/components/MyTooltip'
;
const
welcomePlaceholder
=
const
welcomePlaceholder
=
'每次对话开始前,发送一个初始内容。
可使用的特殊
标记:\n[快捷按键]: 用户点击后可以直接发送该问题'
;
'每次对话开始前,发送一个初始内容。
支持标准 Markdown 语法,可使用的额外
标记:\n[快捷按键]: 用户点击后可以直接发送该问题'
;
const
NodeUserGuide
=
({
const
NodeUserGuide
=
({
data
:
{
inputs
,
outputs
,
onChangeNode
,
...
props
}
data
:
{
inputs
,
outputs
,
onChangeNode
,
...
props
}
...
...
client/src/pages/chat/components/ToolMenu.tsx
View file @
a510f96b
...
@@ -3,15 +3,23 @@ import { useChatBox } from '@/components/ChatBox';
...
@@ -3,15 +3,23 @@ import { useChatBox } from '@/components/ChatBox';
import
{
ChatItemType
}
from
'@/types/chat'
;
import
{
ChatItemType
}
from
'@/types/chat'
;
import
{
Menu
,
MenuButton
,
MenuList
,
MenuItem
,
Box
}
from
'@chakra-ui/react'
;
import
{
Menu
,
MenuButton
,
MenuList
,
MenuItem
,
Box
}
from
'@chakra-ui/react'
;
import
MyIcon
from
'@/components/Icon'
;
import
MyIcon
from
'@/components/Icon'
;
import
{
useRouter
}
from
'next/router'
;
const
ToolMenu
=
({
history
}:
{
history
:
ChatItemType
[]
})
=>
{
const
ToolMenu
=
({
history
}:
{
history
:
ChatItemType
[]
})
=>
{
const
{
onExportChat
}
=
useChatBox
();
const
{
onExportChat
}
=
useChatBox
();
const
router
=
useRouter
();
const
menuList
=
useRef
([
const
menuList
=
useRef
([
// {
{
// icon: 'shareLight',
icon
:
'chatLight'
,
// label: '分享对话',
label
:
'新对话'
,
// onClick: () => {}
onClick
:
()
=>
{
// },
router
.
push
({
query
:
{
appId
:
router
.
query
?.
appId
}
});
}
},
{
{
icon
:
'apiLight'
,
icon
:
'apiLight'
,
label
:
'HTML导出'
,
label
:
'HTML导出'
,
...
...
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