2023-06-05 19:27:25 +08:00
|
|
|
import { keyframes } from "@emotion/react";
|
2023-06-06 15:13:49 +08:00
|
|
|
import { Center, Text, Flex, Avatar, Accordion, Box, Stack, Container, Divider, ActionIcon, Tooltip } from "@mantine/core";
|
2023-06-05 19:27:25 +08:00
|
|
|
import React from "react";
|
2023-06-13 17:03:48 +08:00
|
|
|
import CodeBlock from "@/views/CodeBlock";
|
2023-06-05 19:27:25 +08:00
|
|
|
|
|
|
|
// @ts-ignore
|
2023-06-13 17:03:48 +08:00
|
|
|
import SvgAvatarDevChat from '@/views/avatar_devchat.svg';
|
2023-06-05 19:27:25 +08:00
|
|
|
// @ts-ignore
|
2023-06-13 17:03:48 +08:00
|
|
|
import SvgAvatarUser from '@/views/avatar_spaceman.png';
|
2023-06-06 15:13:49 +08:00
|
|
|
import { IconCheck, IconCopy } from "@tabler/icons-react";
|
2023-06-05 19:27:25 +08:00
|
|
|
|
2023-06-13 17:03:48 +08:00
|
|
|
import { useAppDispatch, useAppSelector } from '@/views/hooks';
|
2023-06-08 19:28:15 +08:00
|
|
|
import {
|
|
|
|
selectGenerating,
|
2023-06-08 19:54:21 +08:00
|
|
|
selectResponsed,
|
|
|
|
selectMessages,
|
2023-06-08 19:28:15 +08:00
|
|
|
} from './chatSlice';
|
2023-06-08 20:40:05 +08:00
|
|
|
import {
|
|
|
|
setContexts,
|
|
|
|
setValue,
|
|
|
|
} from './inputSlice';
|
2023-06-05 19:27:25 +08:00
|
|
|
|
2023-06-08 19:28:15 +08:00
|
|
|
|
|
|
|
const MessageBlink = (props: any) => {
|
|
|
|
const { messageType, lastMessage } = props;
|
|
|
|
|
2023-06-09 09:26:37 +08:00
|
|
|
const generating = useAppSelector(selectGenerating);
|
|
|
|
const responsed = useAppSelector(selectResponsed);
|
2023-06-08 19:28:15 +08:00
|
|
|
|
|
|
|
const blink = keyframes({
|
|
|
|
'50%': { opacity: 0 },
|
|
|
|
});
|
|
|
|
|
|
|
|
return (generating && messageType === 'bot' && lastMessage
|
|
|
|
? <Text sx={{
|
|
|
|
animation: `${blink} 0.5s infinite;`,
|
|
|
|
width: 5,
|
|
|
|
marginTop: responsed ? 0 : '1em',
|
|
|
|
backgroundColor: 'black',
|
|
|
|
display: 'block'
|
|
|
|
|
|
|
|
}}>|</Text>
|
|
|
|
: <></>);
|
|
|
|
};
|
|
|
|
|
|
|
|
const MessageContext = (props: any) => {
|
|
|
|
const { contexts } = props;
|
|
|
|
return (contexts &&
|
|
|
|
<Accordion variant="contained" chevronPosition="left"
|
|
|
|
sx={{
|
|
|
|
marginTop: 5,
|
|
|
|
borderRadius: 5,
|
|
|
|
backgroundColor: 'var(--vscode-menu-background)',
|
|
|
|
}}
|
|
|
|
styles={{
|
|
|
|
item: {
|
|
|
|
borderColor: 'var(--vscode-menu-border)',
|
2023-06-05 19:27:25 +08:00
|
|
|
backgroundColor: 'var(--vscode-menu-background)',
|
2023-06-08 19:28:15 +08:00
|
|
|
'&[data-active]': {
|
2023-06-05 19:27:25 +08:00
|
|
|
backgroundColor: 'var(--vscode-menu-background)',
|
2023-06-08 19:28:15 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
control: {
|
|
|
|
height: 30,
|
|
|
|
borderRadius: 3,
|
|
|
|
backgroundColor: 'var(--vscode-menu-background)',
|
|
|
|
'&[aria-expanded="true"]': {
|
|
|
|
borderBottomLeftRadius: 0,
|
|
|
|
borderBottomRightRadius: 0,
|
2023-06-05 19:27:25 +08:00
|
|
|
},
|
2023-06-08 19:28:15 +08:00
|
|
|
'&:hover': {
|
2023-06-05 19:27:25 +08:00
|
|
|
backgroundColor: 'var(--vscode-menu-background)',
|
|
|
|
}
|
2023-06-08 19:28:15 +08:00
|
|
|
},
|
|
|
|
chevron: {
|
|
|
|
color: 'var(--vscode-menu-foreground)',
|
|
|
|
},
|
|
|
|
icon: {
|
|
|
|
color: 'var(--vscode-menu-foreground)',
|
|
|
|
},
|
|
|
|
label: {
|
|
|
|
color: 'var(--vscode-menu-foreground)',
|
|
|
|
},
|
|
|
|
panel: {
|
|
|
|
color: 'var(--vscode-menu-foreground)',
|
|
|
|
backgroundColor: 'var(--vscode-menu-background)',
|
|
|
|
},
|
|
|
|
content: {
|
|
|
|
borderRadius: 3,
|
|
|
|
backgroundColor: 'var(--vscode-menu-background)',
|
2023-06-05 19:27:25 +08:00
|
|
|
}
|
2023-06-08 19:28:15 +08:00
|
|
|
}}
|
|
|
|
>
|
|
|
|
{
|
|
|
|
contexts?.map((item: any, index: number) => {
|
|
|
|
const { context } = item;
|
|
|
|
return (
|
2023-06-09 11:16:20 +08:00
|
|
|
<Accordion.Item key={`item-${index}`} value={`item-value-${index}`} mah='200'>
|
2023-06-08 19:28:15 +08:00
|
|
|
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
|
|
|
<Accordion.Control >
|
2023-06-08 23:18:59 +08:00
|
|
|
<Text truncate='end'>{'command' in context ? context.command : context.path}</Text>
|
2023-06-08 19:28:15 +08:00
|
|
|
</Accordion.Control>
|
|
|
|
</Box>
|
|
|
|
<Accordion.Panel>
|
|
|
|
{
|
|
|
|
context.content
|
|
|
|
? <pre style={{ overflowWrap: 'normal' }}>{context.content}</pre>
|
|
|
|
: <Center>
|
|
|
|
<Text c='gray.3'>No content</Text>
|
|
|
|
</Center>
|
|
|
|
}
|
|
|
|
|
|
|
|
</Accordion.Panel>
|
|
|
|
</Accordion.Item>
|
|
|
|
);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
</Accordion>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
const MessageHeader = (props: any) => {
|
2023-06-08 20:40:05 +08:00
|
|
|
const { type, message, contexts } = props;
|
2023-06-09 09:26:37 +08:00
|
|
|
const dispatch = useAppDispatch();
|
2023-06-08 19:28:15 +08:00
|
|
|
const [refilled, setRefilled] = React.useState(false);
|
|
|
|
return (<Flex
|
|
|
|
m='10px 0 10px 0'
|
|
|
|
gap="sm"
|
|
|
|
justify="flex-start"
|
|
|
|
align="center"
|
|
|
|
direction="row"
|
|
|
|
wrap="wrap">
|
|
|
|
{
|
|
|
|
type === 'bot'
|
|
|
|
? <Avatar
|
|
|
|
color="indigo"
|
|
|
|
size={25}
|
|
|
|
radius="xl"
|
|
|
|
src={SvgAvatarDevChat} />
|
|
|
|
: <Avatar
|
|
|
|
color="cyan"
|
|
|
|
size={25}
|
|
|
|
radius="xl"
|
|
|
|
src={SvgAvatarUser} />
|
|
|
|
}
|
|
|
|
<Text weight='bold'>{type === 'bot' ? 'DevChat' : 'User'}</Text>
|
|
|
|
{type === 'user'
|
|
|
|
? <Tooltip sx={{ padding: '3px', fontSize: 'var(--vscode-editor-font-size)' }} label={refilled ? 'Refilled' : 'Refill prompt'} withArrow position="left" color="gray">
|
|
|
|
<ActionIcon size='sm' style={{ marginLeft: 'auto' }}
|
|
|
|
onClick={() => {
|
2023-06-08 20:40:05 +08:00
|
|
|
dispatch(setValue(message));
|
|
|
|
dispatch(setContexts(contexts));
|
2023-06-08 19:28:15 +08:00
|
|
|
setRefilled(true);
|
|
|
|
setTimeout(() => { setRefilled(false); }, 2000);
|
|
|
|
}}>
|
|
|
|
{refilled ? <IconCheck size="1rem" /> : <IconCopy size="1.125rem" />}
|
|
|
|
</ActionIcon>
|
|
|
|
</Tooltip>
|
|
|
|
: <></>
|
|
|
|
}
|
|
|
|
</Flex>);
|
|
|
|
};
|
|
|
|
|
|
|
|
const MessageContainer = (props: any) => {
|
2023-06-08 20:40:05 +08:00
|
|
|
const { width } = props;
|
2023-06-08 19:28:15 +08:00
|
|
|
|
2023-06-09 09:26:37 +08:00
|
|
|
const messages = useAppSelector(selectMessages);
|
2023-06-05 19:27:25 +08:00
|
|
|
|
2023-06-14 12:28:03 +08:00
|
|
|
return messages.map((item: any, index: number) => {
|
|
|
|
const { message: messageText, type: messageType, contexts } = item;
|
|
|
|
// setMessage(messageText);
|
|
|
|
return <Stack
|
|
|
|
spacing={0}
|
|
|
|
key={`message-${index}`}
|
|
|
|
sx={{
|
|
|
|
width: width,
|
|
|
|
padding: 0,
|
|
|
|
margin: 0,
|
|
|
|
}}>
|
|
|
|
<MessageHeader
|
|
|
|
key={`message-header-${index}`}
|
|
|
|
type={messageType}
|
|
|
|
message={messageText}
|
|
|
|
contexts={contexts} />
|
|
|
|
<Container
|
|
|
|
key={`message-container-${index}`}
|
2023-06-05 19:27:25 +08:00
|
|
|
sx={{
|
|
|
|
margin: 0,
|
2023-06-14 12:28:03 +08:00
|
|
|
padding: 0,
|
|
|
|
width: width,
|
|
|
|
pre: {
|
|
|
|
whiteSpace: 'break-spaces'
|
|
|
|
},
|
2023-06-05 19:27:25 +08:00
|
|
|
}}>
|
2023-06-14 12:28:03 +08:00
|
|
|
<MessageContext key={`message-context-${index}`} contexts={contexts} />
|
2023-06-28 17:09:27 +08:00
|
|
|
<CodeBlock key={`message-codeblock-${index}`} messageType={messageType} messageText={messageText} />
|
2023-06-14 12:28:03 +08:00
|
|
|
<MessageBlink key={`message-blink-${index}`} messageType={messageType} lastMessage={index === messages.length - 1} />
|
|
|
|
</Container >
|
|
|
|
{index !== messages.length - 1 && <Divider my={3} key={`message-divider-${index}`} />}
|
|
|
|
</Stack >;
|
|
|
|
});
|
2023-06-05 19:27:25 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
export default MessageContainer;
|