Merge branch 'main' of github.com:ztjhz/ChatGPTFreeApp

This commit is contained in:
Ayaka Mikazuki 2023-03-25 22:23:15 +09:30
commit 01b6fc7479
11 changed files with 124 additions and 18 deletions

2
.github/FUNDING.yml vendored
View file

@ -1,2 +1,2 @@
github: [ztjhz] github: [ztjhz]
ko_fi: freechatgpt ko_fi: betterchatgpt

View file

@ -98,11 +98,11 @@ Better ChatGPT 已经包含了大量的功能。您可以使用以下功能:
如果您想支持我们的团队,请考虑通过以下方法之一赞助我们。每一份贡献,无论多小,都有助于我们维护和改善我们的服务。 如果您想支持我们的团队,请考虑通过以下方法之一赞助我们。每一份贡献,无论多小,都有助于我们维护和改善我们的服务。
| 付款方式 | 链接 | | 付款方式 | 链接 |
| -------------- | -------------------------------------------------------------------------------------- | | -------------- | ---------------------------------------------------------------------------------------- |
| 支付宝 (Ayaka) | <img src="https://ayaka14732.github.io/sponsor/alipay.jpg" width=150 /> | | 支付宝 (Ayaka) | <img src="https://ayaka14732.github.io/sponsor/alipay.jpg" width=150 /> |
| 微信 (Ayaka) | <img src="https://ayaka14732.github.io/sponsor/wechat.png" width=150 /> | | 微信 (Ayaka) | <img src="https://ayaka14732.github.io/sponsor/wechat.png" width=150 /> |
| KoFi | [![support](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/freechatgpt) | | KoFi | [![support](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/betterchatgpt) |
感谢您成为我们社区的一员,我们期待着在未来为您提供更好的服务。 感谢您成为我们社区的一员,我们期待着在未来为您提供更好的服务。

View file

@ -105,11 +105,11 @@ If you have enjoyed using our app, we kindly ask you to give this project a ⭐
If you would like to support the team, consider sponsoring us through one of the methods below. Every contribution, no matter how small, helps us to maintain and improve our service. If you would like to support the team, consider sponsoring us through one of the methods below. Every contribution, no matter how small, helps us to maintain and improve our service.
| Payment Method | Link | | Payment Method | Link |
| -------------- | -------------------------------------------------------------------------------------- | | -------------- | ---------------------------------------------------------------------------------------- |
| KoFi | [![support](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/freechatgpt) | | KoFi | [![support](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/betterchatgpt) |
| Alipay (Ayaka) | <img src="https://ayaka14732.github.io/sponsor/alipay.jpg" width=150 /> | | Alipay (Ayaka) | <img src="https://ayaka14732.github.io/sponsor/alipay.jpg" width=150 /> |
| Wechat (Ayaka) | <img src="https://ayaka14732.github.io/sponsor/wechat.png" width=150 /> | | Wechat (Ayaka) | <img src="https://ayaka14732.github.io/sponsor/wechat.png" width=150 /> |
Thank you for being a part of our community, and we look forward to serving you better in the future. Thank you for being a part of our community, and we look forward to serving you better in the future.

View file

@ -10,11 +10,11 @@
<meta name="twitter:image" content="https://bettergpt.chat/preview.jpg" /> <meta name="twitter:image" content="https://bettergpt.chat/preview.jpg" />
<meta <meta
name="description" name="description"
content="Access unrestricted ChatGPT from anywhere in the world, completely free of charge!" content="Play and chat smarter with BetterChatGPT - an amazing open-source web app with a better UI for exploring OpenAI's ChatGPT API! "
/> />
<meta <meta
name="twitter:description" name="twitter:description"
content="Access unrestricted ChatGPT from anywhere in the world, completely free of charge!" content="Play and chat smarter with BetterChatGPT - an amazing open-source web app with a better UI for exploring OpenAI's ChatGPT API! "
/> />
<meta name="twitter:title" content="Better ChatGPT" /> <meta name="twitter:title" content="Better ChatGPT" />
<meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:card" content="summary_large_image" />

View file

@ -1,5 +1,5 @@
{ {
"name": "chatgpt-free-app", "name": "better-chatgpt",
"private": true, "private": true,
"version": "0.0.0", "version": "0.0.0",
"type": "module", "type": "module",

View file

@ -78,7 +78,7 @@ const AboutMenu = () => {
<p>{t('support.paragraph3', { ns: 'about' })}</p> <p>{t('support.paragraph3', { ns: 'about' })}</p>
<div className='flex flex-col items-center gap-4 my-4'> <div className='flex flex-col items-center gap-4 my-4'>
<a href='https://ko-fi.com/freechatgpt' target='_blank'> <a href='https://ko-fi.com/betterchatgpt' target='_blank'>
<img <img
src='/kofi.svg' src='/kofi.svg'
alt='Support us through the Ko-fi platform.' alt='Support us through the Ko-fi platform.'

View file

@ -19,12 +19,14 @@ import TickIcon from '@icon/TickIcon';
import CrossIcon from '@icon/CrossIcon'; import CrossIcon from '@icon/CrossIcon';
import RefreshIcon from '@icon/RefreshIcon'; import RefreshIcon from '@icon/RefreshIcon';
import DownChevronArrow from '@icon/DownChevronArrow'; import DownChevronArrow from '@icon/DownChevronArrow';
import CopyIcon from '@icon/CopyIcon';
import useSubmit from '@hooks/useSubmit'; import useSubmit from '@hooks/useSubmit';
import { ChatInterface } from '@type/chat'; import { ChatInterface } from '@type/chat';
import PopupModal from '@components/PopupModal'; import PopupModal from '@components/PopupModal';
import TokenCount from '@components/TokenCount';
import CommandPrompt from './CommandPrompt'; import CommandPrompt from './CommandPrompt';
import CodeBlock from './CodeBlock'; import CodeBlock from './CodeBlock';
import { codeLanguageSubset } from '@constants/chat'; import { codeLanguageSubset } from '@constants/chat';
@ -126,6 +128,10 @@ const ContentView = React.memo(
handleSubmit(); handleSubmit();
}; };
const handleCopy = () => {
navigator.clipboard.writeText(content);
};
return ( return (
<> <>
<div className='markdown prose w-full break-words dark:prose-invert dark share-gpt-message'> <div className='markdown prose w-full break-words dark:prose-invert dark share-gpt-message'>
@ -157,14 +163,17 @@ const ContentView = React.memo(
<div className='flex justify-end gap-2 w-full mt-2'> <div className='flex justify-end gap-2 w-full mt-2'>
{isDelete || ( {isDelete || (
<> <>
{role === 'assistant' && messageIndex === lastMessageIndex && ( {!useStore.getState().generating &&
<RefreshButton onClick={handleRefresh} /> role === 'assistant' &&
)} messageIndex === lastMessageIndex && (
<RefreshButton onClick={handleRefresh} />
)}
{messageIndex !== 0 && <UpButton onClick={handleMoveUp} />} {messageIndex !== 0 && <UpButton onClick={handleMoveUp} />}
{messageIndex !== lastMessageIndex && ( {messageIndex !== lastMessageIndex && (
<DownButton onClick={handleMoveDown} /> <DownButton onClick={handleMoveDown} />
)} )}
<CopyButton onClick={handleCopy} />
<EditButton setIsEdit={setIsEdit} /> <EditButton setIsEdit={setIsEdit} />
<DeleteButton setIsDelete={setIsDelete} /> <DeleteButton setIsDelete={setIsDelete} />
</> </>
@ -277,6 +286,7 @@ const UpButton = ({
/> />
); );
}; };
const RefreshButton = ({ const RefreshButton = ({
onClick, onClick,
}: { }: {
@ -284,6 +294,28 @@ const RefreshButton = ({
}) => { }) => {
return <MessageButton icon={<RefreshIcon />} onClick={onClick} />; return <MessageButton icon={<RefreshIcon />} onClick={onClick} />;
}; };
const CopyButton = ({
onClick,
}: {
onClick: React.MouseEventHandler<HTMLButtonElement>;
}) => {
const [isCopied, setIsCopied] = useState<boolean>(false);
return (
<MessageButton
icon={isCopied ? <TickIcon /> : <CopyIcon />}
onClick={(e) => {
onClick(e);
setIsCopied(true);
window.setTimeout(() => {
setIsCopied(false);
}, 3000);
}}
/>
);
};
const EditView = ({ const EditView = ({
content, content,
setIsEdit, setIsEdit,
@ -481,6 +513,7 @@ const EditViewButtons = React.memo(
</button> </button>
)} )}
</div> </div>
{sticky && <TokenCount />}
<CommandPrompt _setContent={_setContent} /> <CommandPrompt _setContent={_setContent} />
</div> </div>
); );

View file

@ -0,0 +1,29 @@
import React, { useEffect, useState } from 'react';
import useStore from '@store/store';
import { shallow } from 'zustand/shallow';
import { countMessagesToken } from '@utils/messageUtils';
const TokenCount = React.memo(() => {
const [tokenCount, setTokenCount] = useState<number>(0);
const generating = useStore((state) => state.generating);
const messages = useStore(
(state) =>
state.chats ? state.chats[state.currentChatIndex].messages : [],
shallow
);
useEffect(() => {
if (!generating) setTokenCount(countMessagesToken(messages));
}, [messages, generating]);
return (
<div className='absolute top-[-16px] right-0'>
<div className='text-xs italic text-gray-900 dark:text-gray-300'>
Tokens: {tokenCount}
</div>
</div>
);
});
export default TokenCount;

View file

@ -0,0 +1 @@
export { default } from './TokenCount';

View file

@ -27,6 +27,42 @@
height: 100%; height: 100%;
} }
.markdown table {
--tw-border-spacing-x: 0px;
--tw-border-spacing-y: 0px;
border-collapse: separate;
border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y);
width: 100%;
}
.markdown th {
background-color: rgba(236, 236, 241, 0.2);
border-bottom-width: 1px;
border-left-width: 1px;
border-top-width: 1px;
padding: 0.25rem 0.75rem;
}
.markdown th:first-child {
border-top-left-radius: 0.375rem;
}
.markdown th:last-child {
border-right-width: 1px;
border-top-right-radius: 0.375rem;
}
.markdown td {
border-bottom-width: 1px;
border-left-width: 1px;
padding: 0.25rem 0.75rem;
}
.markdown td:last-child {
border-right-width: 1px;
}
.markdown tbody tr:last-child td:first-child {
border-bottom-left-radius: 0.375rem;
}
.markdown tbody tr:last-child td:last-child {
border-bottom-right-radius: 0.375rem;
}
img { img {
@apply inline-block; @apply inline-block;
} }

View file

@ -17,3 +17,10 @@ export const limitMessageTokens = (
return limitedMessages; return limitedMessages;
}; };
export const countMessagesToken = (messages: MessageInterface[]) => {
return messages.reduce(
(tokenCount, message) => (tokenCount += countTokens(message.content)),
0
);
};