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]
ko_fi: freechatgpt
ko_fi: betterchatgpt

View file

@ -99,10 +99,10 @@ Better ChatGPT 已经包含了大量的功能。您可以使用以下功能:
如果您想支持我们的团队,请考虑通过以下方法之一赞助我们。每一份贡献,无论多小,都有助于我们维护和改善我们的服务。
| 付款方式 | 链接 |
| -------------- | -------------------------------------------------------------------------------------- |
| -------------- | ---------------------------------------------------------------------------------------- |
| 支付宝 (Ayaka) | <img src="https://ayaka14732.github.io/sponsor/alipay.jpg" 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

@ -106,8 +106,8 @@ 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.
| 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 /> |
| Wechat (Ayaka) | <img src="https://ayaka14732.github.io/sponsor/wechat.png" width=150 /> |

View file

@ -10,11 +10,11 @@
<meta name="twitter:image" content="https://bettergpt.chat/preview.jpg" />
<meta
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
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:card" content="summary_large_image" />

View file

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

View file

@ -78,7 +78,7 @@ const AboutMenu = () => {
<p>{t('support.paragraph3', { ns: 'about' })}</p>
<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
src='/kofi.svg'
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 RefreshIcon from '@icon/RefreshIcon';
import DownChevronArrow from '@icon/DownChevronArrow';
import CopyIcon from '@icon/CopyIcon';
import useSubmit from '@hooks/useSubmit';
import { ChatInterface } from '@type/chat';
import PopupModal from '@components/PopupModal';
import TokenCount from '@components/TokenCount';
import CommandPrompt from './CommandPrompt';
import CodeBlock from './CodeBlock';
import { codeLanguageSubset } from '@constants/chat';
@ -126,6 +128,10 @@ const ContentView = React.memo(
handleSubmit();
};
const handleCopy = () => {
navigator.clipboard.writeText(content);
};
return (
<>
<div className='markdown prose w-full break-words dark:prose-invert dark share-gpt-message'>
@ -157,7 +163,9 @@ const ContentView = React.memo(
<div className='flex justify-end gap-2 w-full mt-2'>
{isDelete || (
<>
{role === 'assistant' && messageIndex === lastMessageIndex && (
{!useStore.getState().generating &&
role === 'assistant' &&
messageIndex === lastMessageIndex && (
<RefreshButton onClick={handleRefresh} />
)}
{messageIndex !== 0 && <UpButton onClick={handleMoveUp} />}
@ -165,6 +173,7 @@ const ContentView = React.memo(
<DownButton onClick={handleMoveDown} />
)}
<CopyButton onClick={handleCopy} />
<EditButton setIsEdit={setIsEdit} />
<DeleteButton setIsDelete={setIsDelete} />
</>
@ -277,6 +286,7 @@ const UpButton = ({
/>
);
};
const RefreshButton = ({
onClick,
}: {
@ -284,6 +294,28 @@ const RefreshButton = ({
}) => {
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 = ({
content,
setIsEdit,
@ -481,6 +513,7 @@ const EditViewButtons = React.memo(
</button>
)}
</div>
{sticky && <TokenCount />}
<CommandPrompt _setContent={_setContent} />
</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%;
}
.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 {
@apply inline-block;
}

View file

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