feat: add wechat tip
This commit is contained in:
parent
822e5c74c5
commit
88e0963aec
44
src/views/components/WechatTip/index.tsx
Normal file
44
src/views/components/WechatTip/index.tsx
Normal file
@ -0,0 +1,44 @@
|
||||
import React, { useEffect } from "react";
|
||||
import axios from "axios";
|
||||
import messageUtil from "@/util/MessageUtil";
|
||||
|
||||
const key =
|
||||
"DC.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdfaWQiOjgxODg1ODM1MDgyLCJqdGkiOjcyNjk5NTE1NzkyOTU5ODgzNjB9.s1P6Br4Cw3xki_76bqJ-HRr229Q0WjMQrQ3z7hXTPtk";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
export default function WechatTip() {
|
||||
const getSettings = () => {
|
||||
messageUtil.sendMessage({
|
||||
command: "getSetting",
|
||||
key1: "DevChat",
|
||||
key2: "API_ENDPOINT",
|
||||
});
|
||||
};
|
||||
useEffect(() => {
|
||||
getSettings();
|
||||
messageUtil.registerHandler("getSetting", (message: { value: string }) => {
|
||||
console.log("value API_ENDPOINT: ", message);
|
||||
});
|
||||
|
||||
axios
|
||||
.get("https://apptest.devchat.ai/api/v1/users/profile", {
|
||||
headers: { Authorization: `Bearer ${key}` },
|
||||
})
|
||||
.then((res) => {
|
||||
console.log("res: ", res);
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
padding: "10px 15px",
|
||||
backgroundColor: "var(--vscode-input-background)",
|
||||
position: "absolute",
|
||||
}}
|
||||
>
|
||||
Your remaining credit is ¥1.5. Sign in to{" "}
|
||||
<a href="https://test.devchat.ai">devchat.ai </a>to earn additional ¥8.
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,202 +1,269 @@
|
||||
import * as React from 'react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { ActionIcon, Alert, Anchor, Box, Button, Center, Chip, Container, Flex, Group, Radio, Stack, px } from '@mantine/core';
|
||||
import { ScrollArea } from '@mantine/core';
|
||||
import { useResizeObserver, useTimeout, useViewportSize } from '@mantine/hooks';
|
||||
import messageUtil from '@/util/MessageUtil';
|
||||
import * as React from "react";
|
||||
import { useEffect, useRef } from "react";
|
||||
import {
|
||||
ActionIcon,
|
||||
Alert,
|
||||
Anchor,
|
||||
Box,
|
||||
Button,
|
||||
Center,
|
||||
Chip,
|
||||
Container,
|
||||
Flex,
|
||||
Group,
|
||||
Radio,
|
||||
Stack,
|
||||
px,
|
||||
} from "@mantine/core";
|
||||
import { ScrollArea } from "@mantine/core";
|
||||
import { useResizeObserver, useTimeout, useViewportSize } from "@mantine/hooks";
|
||||
import messageUtil from "@/util/MessageUtil";
|
||||
import CurrentMessage from "@/views/components/CurrentMessage";
|
||||
import StopButton from '@/views/components/StopButton';
|
||||
import RegenerationButton from '@/views/components/RegenerationButton';
|
||||
import StopButton from "@/views/components/StopButton";
|
||||
import RegenerationButton from "@/views/components/RegenerationButton";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { useMst } from "@/views/stores/RootStore";
|
||||
import { Message } from "@/views/stores/ChatStore";
|
||||
|
||||
|
||||
import InputMessage from '@/views/components/InputMessage';
|
||||
import MessageList from '@/views/components/MessageList';
|
||||
import { IconCircleArrowDownFilled, IconExternalLink } from '@tabler/icons-react';
|
||||
|
||||
import InputMessage from "@/views/components/InputMessage";
|
||||
import MessageList from "@/views/components/MessageList";
|
||||
import WechatTip from "@/views/components/WechatTip";
|
||||
import {
|
||||
IconCircleArrowDownFilled,
|
||||
IconExternalLink,
|
||||
} from "@tabler/icons-react";
|
||||
|
||||
const chatPanel = observer(() => {
|
||||
const { input, chat } = useMst();
|
||||
const { input, chat } = useMst();
|
||||
|
||||
const [chatContainerRef, chatContainerRect] = useResizeObserver();
|
||||
const scrollViewport = useRef<HTMLDivElement>(null);
|
||||
const { height, width } = useViewportSize();
|
||||
const [chatContainerRef, chatContainerRect] = useResizeObserver();
|
||||
const scrollViewport = useRef<HTMLDivElement>(null);
|
||||
const { height, width } = useViewportSize();
|
||||
|
||||
const chatPanelWidth = chatContainerRect.width;
|
||||
const chatPanelWidth = chatContainerRect.width;
|
||||
|
||||
const scrollToBottom = () =>
|
||||
scrollViewport?.current?.scrollTo({ top: scrollViewport.current.scrollHeight, behavior: 'smooth' });
|
||||
const scrollToBottom = () =>
|
||||
scrollViewport?.current?.scrollTo({
|
||||
top: scrollViewport.current.scrollHeight,
|
||||
behavior: "smooth",
|
||||
});
|
||||
|
||||
const getSettings = () => {
|
||||
messageUtil.sendMessage({
|
||||
command: "getSetting",
|
||||
key1: "DevChat",
|
||||
key2: "OpenAI.model"
|
||||
});
|
||||
};
|
||||
const getSettings = () => {
|
||||
messageUtil.sendMessage({
|
||||
command: "getSetting",
|
||||
key1: "DevChat",
|
||||
key2: "OpenAI.model",
|
||||
});
|
||||
};
|
||||
|
||||
const getFeatureToggles = () => {
|
||||
messageUtil.sendMessage({
|
||||
command: "featureToggles"
|
||||
});
|
||||
};
|
||||
const getFeatureToggles = () => {
|
||||
messageUtil.sendMessage({
|
||||
command: "featureToggles",
|
||||
});
|
||||
};
|
||||
|
||||
const timer = useTimeout(() => {
|
||||
if (chat.isBottom) {
|
||||
scrollToBottom();
|
||||
}
|
||||
}, 1000);
|
||||
const timer = useTimeout(() => {
|
||||
if (chat.isBottom) {
|
||||
scrollToBottom();
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
const chipStyle = {
|
||||
color: 'var(--vscode-checkbox-foreground)',
|
||||
fontSize: 'var(--vscode-editor-font-size)',
|
||||
backgroundColor: 'var(--vscode-checkbox-background)',
|
||||
borderColor: 'var(--vscode-checkbox-border)',
|
||||
'&[data-checked]': {
|
||||
borderColor: 'var(--vscode-checkbox-selectBorder)',
|
||||
}
|
||||
};
|
||||
|
||||
const onScrollPositionChange = ({ x, y }) => {
|
||||
const sh = scrollViewport.current?.scrollHeight || 0;
|
||||
const vh = scrollViewport.current?.clientHeight || 0;
|
||||
const gap = sh - vh - y;
|
||||
const isBottom = sh < vh ? true : gap < 100;
|
||||
const isTop = y === 0;
|
||||
// console.log(`sh:${sh},vh:${vh},x:${x},y:${y},gap:${gap}`);
|
||||
if (isBottom) {
|
||||
chat.onMessagesBottom();
|
||||
} else if (isTop) {
|
||||
chat.onMessagesTop()
|
||||
if (!chat.isLastPage) {
|
||||
//TODO: Data loading flickers and has poor performance, so I temporarily disabled the loading logic.
|
||||
// dispatch(fetchHistoryMessages({ pageIndex: pageIndex + 1 }));
|
||||
}
|
||||
} else {
|
||||
chat.onMessagesMiddle();
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getSettings();
|
||||
getFeatureToggles();
|
||||
chat.fetchHistoryMessages({ pageIndex: 0 }).then();
|
||||
messageUtil.registerHandler('receiveMessagePartial', (message: { text: string; }) => {
|
||||
chat.startResponsing(message.text);
|
||||
timer.start();
|
||||
});
|
||||
messageUtil.registerHandler('receiveMessage', (message: { text: string; isError: boolean, hash }) => {
|
||||
chat.stopGenerating(true, message.hash, message.text);
|
||||
if (message.isError) {
|
||||
chat.happendError(message.text);
|
||||
}
|
||||
});
|
||||
messageUtil.registerHandler('systemMessage', (message: { text: string }) => {
|
||||
const messageItem = Message.create({ type: 'system', message: message.text });
|
||||
chat.newMessage(messageItem);
|
||||
// start generating
|
||||
chat.startSystemMessage();
|
||||
// Clear the input field
|
||||
input.setValue('');
|
||||
input.clearContexts();
|
||||
});
|
||||
messageUtil.registerHandler('getSetting', (message: { value: string }) => {
|
||||
chat.changeChatModel(message.value);
|
||||
});
|
||||
messageUtil.registerHandler('featureToggles', (message: { features: object }) => {
|
||||
// chat.changeChatModel(message.value);
|
||||
chat.updateFeatures(message.features);
|
||||
});
|
||||
const chipStyle = {
|
||||
color: "var(--vscode-checkbox-foreground)",
|
||||
fontSize: "var(--vscode-editor-font-size)",
|
||||
backgroundColor: "var(--vscode-checkbox-background)",
|
||||
borderColor: "var(--vscode-checkbox-border)",
|
||||
"&[data-checked]": {
|
||||
borderColor: "var(--vscode-checkbox-selectBorder)",
|
||||
},
|
||||
};
|
||||
|
||||
const onScrollPositionChange = ({ x, y }) => {
|
||||
const sh = scrollViewport.current?.scrollHeight || 0;
|
||||
const vh = scrollViewport.current?.clientHeight || 0;
|
||||
const gap = sh - vh - y;
|
||||
const isBottom = sh < vh ? true : gap < 100;
|
||||
const isTop = y === 0;
|
||||
// console.log(`sh:${sh},vh:${vh},x:${x},y:${y},gap:${gap}`);
|
||||
if (isBottom) {
|
||||
chat.onMessagesBottom();
|
||||
} else if (isTop) {
|
||||
chat.onMessagesTop();
|
||||
if (!chat.isLastPage) {
|
||||
//TODO: Data loading flickers and has poor performance, so I temporarily disabled the loading logic.
|
||||
// dispatch(fetchHistoryMessages({ pageIndex: pageIndex + 1 }));
|
||||
}
|
||||
} else {
|
||||
chat.onMessagesMiddle();
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getSettings();
|
||||
getFeatureToggles();
|
||||
chat.fetchHistoryMessages({ pageIndex: 0 }).then();
|
||||
messageUtil.registerHandler(
|
||||
"receiveMessagePartial",
|
||||
(message: { text: string }) => {
|
||||
chat.startResponsing(message.text);
|
||||
timer.start();
|
||||
return () => {
|
||||
timer.clear();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
scrollToBottom();
|
||||
}, [chat.scrollBottom]);
|
||||
|
||||
return (
|
||||
<Box
|
||||
ref={chatContainerRef}
|
||||
miw={300}
|
||||
sx={{
|
||||
height: '100%',
|
||||
margin: 0,
|
||||
padding: '10px 10px 5px 10px',
|
||||
background: 'var(--vscode-sideBar-background)',
|
||||
color: 'var(--vscode-editor-foreground)'
|
||||
}}>
|
||||
|
||||
{!chat.isBottom && <ActionIcon
|
||||
onClick={() => { scrollToBottom() }}
|
||||
title='Bottom'
|
||||
variant='transparent' sx={{ position: "absolute", bottom: 80, right: 20, zIndex: 1 }}>
|
||||
<IconCircleArrowDownFilled size="1.125rem" />
|
||||
</ActionIcon>}
|
||||
<ScrollArea
|
||||
sx={{
|
||||
height: chat.generating ? height - px('9rem') : height - px('6rem'),
|
||||
padding: 0,
|
||||
margin: 0,
|
||||
}}
|
||||
onScrollPositionChange={onScrollPositionChange}
|
||||
viewportRef={scrollViewport}>
|
||||
<MessageList chatPanelWidth={chatPanelWidth} />
|
||||
<CurrentMessage />
|
||||
{chat.errorMessage &&
|
||||
<Box mb={20} >
|
||||
<Alert styles={{ message: { fontSize: 'var(--vscode-editor-font-size)' } }} w={chatContainerRect.width} color="gray" variant="filled">
|
||||
{chat.errorMessage}
|
||||
</Alert>
|
||||
{
|
||||
chat.errorMessage.search('Insufficient balance') > -1 &&
|
||||
<Button size='xs' component="a" href={chat.rechargeSite} mt={5} variant="outline" leftIcon={<IconExternalLink size="0.9rem" />}>
|
||||
Open official website to recharge.
|
||||
</Button>
|
||||
}
|
||||
</Box>
|
||||
}
|
||||
</ScrollArea>
|
||||
<Stack
|
||||
spacing={0}
|
||||
sx={{ position: 'absolute', bottom: 10, width: chatPanelWidth }}>
|
||||
{chat.generating &&
|
||||
<Center mb={5}>
|
||||
<StopButton />
|
||||
</Center>
|
||||
}
|
||||
{chat.errorMessage &&
|
||||
<Center mb={5}>
|
||||
<RegenerationButton />
|
||||
</Center>
|
||||
}
|
||||
<InputMessage chatPanelWidth={chatPanelWidth} />
|
||||
<Chip.Group multiple={false}
|
||||
value={chat.chatModel}
|
||||
onChange={(value) => {
|
||||
chat.changeChatModel(value);
|
||||
messageUtil.sendMessage({
|
||||
command: 'updateSetting',
|
||||
key1: "DevChat",
|
||||
key2: "OpenAI.model",
|
||||
value: value
|
||||
});
|
||||
}} >
|
||||
<Group position="left" spacing={5} mt={5}>
|
||||
<Chip size="xs" styles={{ label: chipStyle }} value="gpt-3.5-turbo">GPT-3.5</Chip>
|
||||
<Chip size="xs" styles={{ label: chipStyle }} value="gpt-3.5-turbo-16k">GPT-3.5-16K</Chip>
|
||||
<Chip size="xs" styles={{ label: chipStyle }} value="gpt-4">GPT-4</Chip>
|
||||
</Group>
|
||||
</Chip.Group>
|
||||
</Stack>
|
||||
</Box>
|
||||
}
|
||||
);
|
||||
messageUtil.registerHandler(
|
||||
"receiveMessage",
|
||||
(message: { text: string; isError: boolean; hash }) => {
|
||||
chat.stopGenerating(true, message.hash, message.text);
|
||||
if (message.isError) {
|
||||
chat.happendError(message.text);
|
||||
}
|
||||
}
|
||||
);
|
||||
messageUtil.registerHandler(
|
||||
"systemMessage",
|
||||
(message: { text: string }) => {
|
||||
const messageItem = Message.create({
|
||||
type: "system",
|
||||
message: message.text,
|
||||
});
|
||||
chat.newMessage(messageItem);
|
||||
// start generating
|
||||
chat.startSystemMessage();
|
||||
// Clear the input field
|
||||
input.setValue("");
|
||||
input.clearContexts();
|
||||
}
|
||||
);
|
||||
messageUtil.registerHandler("getSetting", (message: { value: string }) => {
|
||||
chat.changeChatModel(message.value);
|
||||
});
|
||||
messageUtil.registerHandler(
|
||||
"featureToggles",
|
||||
(message: { features: object }) => {
|
||||
// chat.changeChatModel(message.value);
|
||||
chat.updateFeatures(message.features);
|
||||
}
|
||||
);
|
||||
|
||||
timer.start();
|
||||
return () => {
|
||||
timer.clear();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
scrollToBottom();
|
||||
}, [chat.scrollBottom]);
|
||||
|
||||
return (
|
||||
<Box
|
||||
ref={chatContainerRef}
|
||||
miw={300}
|
||||
sx={{
|
||||
height: "100%",
|
||||
margin: 0,
|
||||
padding: "10px 10px 5px 10px",
|
||||
background: "var(--vscode-sideBar-background)",
|
||||
color: "var(--vscode-editor-foreground)",
|
||||
}}
|
||||
>
|
||||
<WechatTip />
|
||||
{!chat.isBottom && (
|
||||
<ActionIcon
|
||||
onClick={() => {
|
||||
scrollToBottom();
|
||||
}}
|
||||
title="Bottom"
|
||||
variant="transparent"
|
||||
sx={{ position: "absolute", bottom: 80, right: 20, zIndex: 1 }}
|
||||
>
|
||||
<IconCircleArrowDownFilled size="1.125rem" />
|
||||
</ActionIcon>
|
||||
)}
|
||||
<ScrollArea
|
||||
sx={{
|
||||
height: chat.generating ? height - px("9rem") : height - px("6rem"),
|
||||
padding: 0,
|
||||
margin: 0,
|
||||
}}
|
||||
onScrollPositionChange={onScrollPositionChange}
|
||||
viewportRef={scrollViewport}
|
||||
>
|
||||
<MessageList chatPanelWidth={chatPanelWidth} />
|
||||
<CurrentMessage />
|
||||
{chat.errorMessage && (
|
||||
<Box mb={20}>
|
||||
<Alert
|
||||
styles={{
|
||||
message: { fontSize: "var(--vscode-editor-font-size)" },
|
||||
}}
|
||||
w={chatContainerRect.width}
|
||||
color="gray"
|
||||
variant="filled"
|
||||
>
|
||||
{chat.errorMessage}
|
||||
</Alert>
|
||||
{chat.errorMessage.search("Insufficient balance") > -1 && (
|
||||
<Button
|
||||
size="xs"
|
||||
component="a"
|
||||
href={chat.rechargeSite}
|
||||
mt={5}
|
||||
variant="outline"
|
||||
leftIcon={<IconExternalLink size="0.9rem" />}
|
||||
>
|
||||
Open official website to recharge.
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
</ScrollArea>
|
||||
<Stack
|
||||
spacing={0}
|
||||
sx={{ position: "absolute", bottom: 10, width: chatPanelWidth }}
|
||||
>
|
||||
{chat.generating && (
|
||||
<Center mb={5}>
|
||||
<StopButton />
|
||||
</Center>
|
||||
)}
|
||||
{chat.errorMessage && (
|
||||
<Center mb={5}>
|
||||
<RegenerationButton />
|
||||
</Center>
|
||||
)}
|
||||
<InputMessage chatPanelWidth={chatPanelWidth} />
|
||||
<Chip.Group
|
||||
multiple={false}
|
||||
value={chat.chatModel}
|
||||
onChange={(value) => {
|
||||
chat.changeChatModel(value);
|
||||
messageUtil.sendMessage({
|
||||
command: "updateSetting",
|
||||
key1: "DevChat",
|
||||
key2: "OpenAI.model",
|
||||
value: value,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Group position="left" spacing={5} mt={5}>
|
||||
<Chip size="xs" styles={{ label: chipStyle }} value="gpt-4">
|
||||
GPT-4
|
||||
</Chip>
|
||||
<Chip size="xs" styles={{ label: chipStyle }} value="gpt-3.5-turbo">
|
||||
GPT-3.5
|
||||
</Chip>
|
||||
<Chip
|
||||
size="xs"
|
||||
styles={{ label: chipStyle }}
|
||||
value="gpt-3.5-turbo-16k"
|
||||
>
|
||||
GPT-3.5-16K
|
||||
</Chip>
|
||||
</Group>
|
||||
</Chip.Group>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
});
|
||||
|
||||
export default chatPanel;
|
||||
export default chatPanel;
|
||||
|
Loading…
x
Reference in New Issue
Block a user