mirror of
https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
synced 2025-10-09 19:46:37 +08:00
Merge remote-tracking branch 'upstream/main' into dev
This commit is contained in:
commit
9a271d7815
13
README.md
13
README.md
@ -7,7 +7,7 @@ One-Click to deploy well-designed ChatGPT web UI on Vercel.
|
||||
|
||||
一键免费部署你的私人 ChatGPT 网页应用。
|
||||
|
||||
[演示 Demo](https://chat-gpt-next-web.vercel.app/) / [反馈 Issues](https://github.com/Yidadaa/ChatGPT-Next-Web/issues) / [Join Discord](https://discord.gg/zrhvHCr79N) / [QQ 群](https://user-images.githubusercontent.com/16968934/228190818-7dd00845-e9b9-4363-97e5-44c507ac76da.jpeg) / [打赏开发者](https://user-images.githubusercontent.com/16968934/227772541-5bcd52d8-61b7-488c-a203-0330d8006e2b.jpg)
|
||||
[演示 Demo](https://chat-gpt-next-web.vercel.app/) / [反馈 Issues](https://github.com/Yidadaa/ChatGPT-Next-Web/issues) / [Join Discord](https://discord.gg/zrhvHCr79N) / [QQ 群](https://user-images.githubusercontent.com/16968934/228190818-7dd00845-e9b9-4363-97e5-44c507ac76da.jpeg) / [打赏开发者](https://user-images.githubusercontent.com/16968934/227772541-5bcd52d8-61b7-488c-a203-0330d8006e2b.jpg) / [Buy Me a Coffee](https://www.buymeacoffee.com/yidadaa)
|
||||
|
||||
[](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FYidadaa%2FChatGPT-Next-Web&env=OPENAI_API_KEY&env=CODE&project-name=chatgpt-next-web&repository-name=ChatGPT-Next-Web)
|
||||
|
||||
@ -71,9 +71,7 @@ One-Click to deploy well-designed ChatGPT web UI on Vercel.
|
||||
3. Enjoy :)
|
||||
|
||||
## FAQ
|
||||
> [简体中文 > 常见问题](./docs/faq-cn.md)
|
||||
|
||||
We are sorry that there is currently no English version of the FAQ. English users can use translation tools to access the document. We look forward to receiving your PR for an English version of the documentation.
|
||||
[简体中文 > 常见问题](./docs/faq-cn.md) | [English > FAQ](./docs/faq.en.md)
|
||||
|
||||
## Keep Updated
|
||||
> [简体中文 > 如何保持代码更新](./README_CN.md#保持更新)
|
||||
@ -171,6 +169,8 @@ bash <(curl -s https://raw.githubusercontent.com/Yidadaa/ChatGPT-Next-Web/main/s
|
||||
|
||||

|
||||
|
||||
## Donation
|
||||
[Buy Me a Coffee](https://www.buymeacoffee.com/yidadaa)
|
||||
|
||||
## Special Thanks
|
||||
### Sponsor
|
||||
@ -179,6 +179,11 @@ bash <(curl -s https://raw.githubusercontent.com/Yidadaa/ChatGPT-Next-Web/main/s
|
||||
[@ClarenceDan](https://github.com/ClarenceDan)
|
||||
[@zhangjia](https://github.com/zhangjia)
|
||||
[@hoochanlon](https://github.com/hoochanlon)
|
||||
[@relativequantum](https://github.com/relativequantum)
|
||||
[@desenmeng](https://github.com/desenmeng)
|
||||
[@webees](https://github.com/webees)
|
||||
[@chazzhou](https://github.com/chazzhou)
|
||||
[@hauy](https://github.com/hauy)
|
||||
|
||||
### Contributor
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
user-select: none;
|
||||
outline: none;
|
||||
border: none;
|
||||
color: rgb(51, 51, 51);
|
||||
color: var(--black);
|
||||
|
||||
&[disabled] {
|
||||
cursor: not-allowed;
|
||||
|
@ -59,6 +59,7 @@ export function ChatList() {
|
||||
state.removeSession,
|
||||
state.moveSession,
|
||||
]);
|
||||
const chatStore = useChatStore();
|
||||
|
||||
const onDragEnd: OnDragEndResponder = (result) => {
|
||||
const { destination, source } = result;
|
||||
@ -95,10 +96,7 @@ export function ChatList() {
|
||||
index={i}
|
||||
selected={i === selectedIndex}
|
||||
onClick={() => selectSession(i)}
|
||||
onDelete={() =>
|
||||
(!isMobileScreen() || confirm(Locale.Home.DeleteChat)) &&
|
||||
removeSession(i)
|
||||
}
|
||||
onDelete={chatStore.deleteSession}
|
||||
/>
|
||||
))}
|
||||
{provided.placeholder}
|
||||
|
@ -4,7 +4,7 @@ import { memo, useState, useRef, useEffect, useLayoutEffect } from "react";
|
||||
import SendWhiteIcon from "../icons/send-white.svg";
|
||||
import BrainIcon from "../icons/brain.svg";
|
||||
import ExportIcon from "../icons/export.svg";
|
||||
import MenuIcon from "../icons/menu.svg";
|
||||
import ReturnIcon from "../icons/return.svg";
|
||||
import CopyIcon from "../icons/copy.svg";
|
||||
import DownloadIcon from "../icons/download.svg";
|
||||
import LoadingIcon from "../icons/three-dots.svg";
|
||||
@ -343,6 +343,7 @@ export function Chat(props: {
|
||||
|
||||
const inputRef = useRef<HTMLTextAreaElement>(null);
|
||||
const [userInput, setUserInput] = useState("");
|
||||
const [beforeInput, setBeforeInput] = useState("");
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const { submitKey, shouldSubmit } = useSubmitHandler();
|
||||
const { scrollRef, setAutoScroll } = useScrollToBottom();
|
||||
@ -404,8 +405,10 @@ export function Chat(props: {
|
||||
|
||||
// submit user input
|
||||
const onUserSubmit = () => {
|
||||
if (userInput.length <= 0) return;
|
||||
setIsLoading(true);
|
||||
chatStore.onUserInput(userInput).then(() => setIsLoading(false));
|
||||
setBeforeInput(userInput);
|
||||
setUserInput("");
|
||||
setPromptHints([]);
|
||||
if (!isMobileScreen()) inputRef.current?.focus();
|
||||
@ -419,8 +422,13 @@ export function Chat(props: {
|
||||
|
||||
// check if should send message
|
||||
const onInputKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
|
||||
// if ArrowUp and no userInput
|
||||
if (e.key === "ArrowUp" && userInput.length <= 0) {
|
||||
setUserInput(beforeInput);
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
if (shouldSubmit(e)) {
|
||||
setAutoScroll(true);
|
||||
onUserSubmit();
|
||||
e.preventDefault();
|
||||
}
|
||||
@ -507,13 +515,10 @@ export function Chat(props: {
|
||||
return (
|
||||
<div className={styles.chat} key={session.id}>
|
||||
<div className={styles["window-header"]}>
|
||||
<div
|
||||
className={styles["window-header-title"]}
|
||||
onClick={props?.showSideBar}
|
||||
>
|
||||
<div className={styles["window-header-title"]}>
|
||||
<div
|
||||
className={`${styles["window-header-main-title"]} ${styles["chat-body-title"]}`}
|
||||
onClick={() => {
|
||||
onClickCapture={() => {
|
||||
const newTopic = prompt(Locale.Chat.Rename, session.topic);
|
||||
if (newTopic && newTopic !== session.topic) {
|
||||
chatStore.updateCurrentSession(
|
||||
@ -531,7 +536,7 @@ export function Chat(props: {
|
||||
<div className={styles["window-actions"]}>
|
||||
<div className={styles["window-action-button"] + " " + styles.mobile}>
|
||||
<IconButton
|
||||
icon={<MenuIcon />}
|
||||
icon={<ReturnIcon />}
|
||||
bordered
|
||||
title={Locale.Chat.Actions.ChatList}
|
||||
onClick={props?.showSideBar}
|
||||
@ -667,7 +672,7 @@ export function Chat(props: {
|
||||
onInput={(e) => onInput(e.currentTarget.value)}
|
||||
value={userInput}
|
||||
onKeyDown={onInputKeyDown}
|
||||
onFocus={() => setAutoScroll(isMobileScreen())}
|
||||
onFocus={() => setAutoScroll(true)}
|
||||
onBlur={() => {
|
||||
setAutoScroll(false);
|
||||
setTimeout(() => setPromptHints([]), 500);
|
||||
@ -679,7 +684,6 @@ export function Chat(props: {
|
||||
text={Locale.Chat.Send}
|
||||
className={styles["chat-input-send"]}
|
||||
noDark
|
||||
disabled={!userInput}
|
||||
onClick={onUserSubmit}
|
||||
/>
|
||||
</div>
|
||||
|
@ -157,6 +157,7 @@
|
||||
right: -20px;
|
||||
transition: all ease 0.3s;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.chat-item:hover > .chat-item-delete {
|
||||
|
@ -93,6 +93,7 @@ function _Home() {
|
||||
state.removeSession,
|
||||
],
|
||||
);
|
||||
const chatStore = useChatStore();
|
||||
const loading = !useHasHydrated();
|
||||
const [showSideBar, setShowSideBar] = useState(true);
|
||||
|
||||
@ -140,11 +141,7 @@ function _Home() {
|
||||
<div className={styles["sidebar-action"] + " " + styles.mobile}>
|
||||
<IconButton
|
||||
icon={<CloseIcon />}
|
||||
onClick={() => {
|
||||
if (confirm(Locale.Home.DeleteChat)) {
|
||||
removeSession(currentIndex);
|
||||
}
|
||||
}}
|
||||
onClick={chatStore.deleteSession}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles["sidebar-action"]}>
|
||||
|
@ -128,6 +128,19 @@ export function Settings(props: { closeSettings: () => void }) {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const keydownEvent = (e: KeyboardEvent) => {
|
||||
if (e.key === "Escape") {
|
||||
props.closeSettings();
|
||||
}
|
||||
};
|
||||
document.addEventListener("keydown", keydownEvent);
|
||||
return () => {
|
||||
document.removeEventListener("keydown", keydownEvent);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<div className={styles["window-header"]}>
|
||||
|
@ -135,9 +135,25 @@
|
||||
box-shadow: var(--card-shadow);
|
||||
border: var(--border-in-light);
|
||||
color: var(--black);
|
||||
padding: 10px 30px;
|
||||
padding: 10px 20px;
|
||||
border-radius: 50px;
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.toast-action {
|
||||
padding-left: 20px;
|
||||
color: var(--primary);
|
||||
opacity: 0.8;
|
||||
border: 0;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -160,4 +176,4 @@
|
||||
max-height: 50vh;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -110,17 +110,37 @@ export function showModal(props: ModalProps) {
|
||||
root.render(<Modal {...props} onClose={closeModal}></Modal>);
|
||||
}
|
||||
|
||||
export type ToastProps = { content: string };
|
||||
export type ToastProps = {
|
||||
content: string;
|
||||
action?: {
|
||||
text: string;
|
||||
onClick: () => void;
|
||||
};
|
||||
};
|
||||
|
||||
export function Toast(props: ToastProps) {
|
||||
return (
|
||||
<div className={styles["toast-container"]}>
|
||||
<div className={styles["toast-content"]}>{props.content}</div>
|
||||
<div className={styles["toast-content"]}>
|
||||
<span>{props.content}</span>
|
||||
{props.action && (
|
||||
<button
|
||||
onClick={props.action.onClick}
|
||||
className={styles["toast-action"]}
|
||||
>
|
||||
{props.action.text}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function showToast(content: string, delay = 3000) {
|
||||
export function showToast(
|
||||
content: string,
|
||||
action?: ToastProps["action"],
|
||||
delay = 3000,
|
||||
) {
|
||||
const div = document.createElement("div");
|
||||
div.className = styles.show;
|
||||
document.body.appendChild(div);
|
||||
@ -139,7 +159,7 @@ export function showToast(content: string, delay = 3000) {
|
||||
close();
|
||||
}, delay);
|
||||
|
||||
root.render(<Toast content={content} />);
|
||||
root.render(<Toast content={content} action={action} />);
|
||||
}
|
||||
|
||||
export type InputProps = React.HTMLProps<HTMLTextAreaElement> & {
|
||||
|
21
app/icons/return.svg
Normal file
21
app/icons/return.svg
Normal file
@ -0,0 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16"
|
||||
height="16" viewBox="0 0 16 16" fill="none">
|
||||
<defs>
|
||||
<rect id="path_0" x="0" y="0" width="16" height="16" />
|
||||
</defs>
|
||||
<g opacity="1" transform="translate(0 0) rotate(0 8 8)">
|
||||
<mask id="bg-mask-0" fill="white">
|
||||
<use xlink:href="#path_0"></use>
|
||||
</mask>
|
||||
<g mask="url(#bg-mask-0)">
|
||||
<path id="路径 1"
|
||||
style="stroke:#333333; stroke-width:1.3333333333333333; stroke-opacity:1; stroke-dasharray:0 0"
|
||||
transform="translate(2 2.6666666666666665) rotate(0 1.1666333333333334 2.1666666666666665)"
|
||||
d="M2.33,0L0,2L2.33,4.33 " />
|
||||
<path id="路径 2"
|
||||
style="stroke:#333333; stroke-width:1.3333333333333333; stroke-opacity:1; stroke-dasharray:0 0"
|
||||
transform="translate(2 4.666666666666666) rotate(0 6.000006859869576 4.333333333333333)"
|
||||
d="M0,0L7.66,0C9.96,0 11.91,1.87 12,4.17C12.09,6.59 10.09,8.67 7.66,8.67L2,8.67 " />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1013 B |
@ -47,6 +47,8 @@ const cn = {
|
||||
Home: {
|
||||
NewChat: "新的聊天",
|
||||
DeleteChat: "确认删除选中的对话?",
|
||||
DeleteToast: "已删除会话",
|
||||
Revert: "撤销",
|
||||
},
|
||||
Settings: {
|
||||
Title: "设置",
|
||||
|
@ -50,6 +50,8 @@ const en: LocaleType = {
|
||||
Home: {
|
||||
NewChat: "New Chat",
|
||||
DeleteChat: "Confirm to delete the selected conversation?",
|
||||
DeleteToast: "Chat Deleted",
|
||||
Revert: "Revert",
|
||||
},
|
||||
Settings: {
|
||||
Title: "Settings",
|
||||
|
@ -50,6 +50,8 @@ const es: LocaleType = {
|
||||
Home: {
|
||||
NewChat: "Nuevo chat",
|
||||
DeleteChat: "¿Confirmar eliminación de la conversación seleccionada?",
|
||||
DeleteToast: "Chat Deleted",
|
||||
Revert: "Revert",
|
||||
},
|
||||
Settings: {
|
||||
Title: "Configuración",
|
||||
|
@ -50,6 +50,8 @@ const it: LocaleType = {
|
||||
Home: {
|
||||
NewChat: "Nuova Chat",
|
||||
DeleteChat: "Confermare la cancellazione della conversazione selezionata?",
|
||||
DeleteToast: "Chat Deleted",
|
||||
Revert: "Revert",
|
||||
},
|
||||
Settings: {
|
||||
Title: "Impostazioni",
|
||||
|
@ -48,6 +48,8 @@ const tw: LocaleType = {
|
||||
Home: {
|
||||
NewChat: "新的對話",
|
||||
DeleteChat: "確定要刪除選取的對話嗎?",
|
||||
DeleteToast: "已刪除對話",
|
||||
Revert: "撤銷",
|
||||
},
|
||||
Settings: {
|
||||
Title: "設定",
|
||||
|
@ -7,9 +7,10 @@ import {
|
||||
requestChatStream,
|
||||
requestWithPrompt,
|
||||
} from "../requests";
|
||||
import { trimTopic } from "../utils";
|
||||
import { isMobileScreen, trimTopic } from "../utils";
|
||||
|
||||
import Locale from "../locales";
|
||||
import { showToast } from "../components/ui-lib";
|
||||
|
||||
export type Message = ChatCompletionResponseMessage & {
|
||||
date: string;
|
||||
@ -204,6 +205,7 @@ interface ChatStore {
|
||||
moveSession: (from: number, to: number) => void;
|
||||
selectSession: (index: number) => void;
|
||||
newSession: () => void;
|
||||
deleteSession: () => void;
|
||||
currentSession: () => ChatSession;
|
||||
onNewMessage: (message: Message) => void;
|
||||
onUserInput: (content: string) => Promise<void>;
|
||||
@ -324,6 +326,26 @@ export const useChatStore = create<ChatStore>()(
|
||||
}));
|
||||
},
|
||||
|
||||
deleteSession() {
|
||||
const deletedSession = get().currentSession();
|
||||
const index = get().currentSessionIndex;
|
||||
const isLastSession = get().sessions.length === 1;
|
||||
if (!isMobileScreen() || confirm(Locale.Home.DeleteChat)) {
|
||||
get().removeSession(index);
|
||||
}
|
||||
showToast(Locale.Home.DeleteToast, {
|
||||
text: Locale.Home.Revert,
|
||||
onClick() {
|
||||
set((state) => ({
|
||||
sessions: state.sessions
|
||||
.slice(0, index)
|
||||
.concat([deletedSession])
|
||||
.concat(state.sessions.slice(index + Number(isLastSession))),
|
||||
}));
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
currentSession() {
|
||||
let index = get().currentSessionIndex;
|
||||
const sessions = get().sessions;
|
||||
|
19
app/utils.ts
19
app/utils.ts
@ -7,21 +7,20 @@ export function trimTopic(topic: string) {
|
||||
}
|
||||
|
||||
export async function copyToClipboard(text: string) {
|
||||
if (navigator.clipboard) {
|
||||
navigator.clipboard.writeText(text).catch(err => {
|
||||
console.error('Failed to copy: ', err);
|
||||
});
|
||||
} else {
|
||||
const textArea = document.createElement('textarea');
|
||||
try {
|
||||
await navigator.clipboard.writeText(text);
|
||||
showToast(Locale.Copy.Success);
|
||||
} catch (error) {
|
||||
const textArea = document.createElement("textarea");
|
||||
textArea.value = text;
|
||||
document.body.appendChild(textArea);
|
||||
textArea.focus();
|
||||
textArea.select();
|
||||
try {
|
||||
document.execCommand('copy');
|
||||
console.log('Text copied to clipboard');
|
||||
} catch (err) {
|
||||
console.error('Failed to copy: ', err);
|
||||
document.execCommand("copy");
|
||||
showToast(Locale.Copy.Success);
|
||||
} catch (error) {
|
||||
showToast(Locale.Copy.Failed);
|
||||
}
|
||||
document.body.removeChild(textArea);
|
||||
}
|
||||
|
@ -126,3 +126,13 @@ OpenAI只接受指定地区的信用卡(中国信用卡无法使用)。一
|
||||
|
||||
## 如何使用 Azure OpenAI 接口
|
||||
请参考:[#371](https://github.com/Yidadaa/ChatGPT-Next-Web/issues/371)
|
||||
|
||||
## 为什么我的 Token 消耗得这么快?
|
||||
> 相关讨论:[#518](https://github.com/Yidadaa/ChatGPT-Next-Web/issues/518)
|
||||
- 如果你有 GPT 4 的权限,并且日常在使用 GPT 4 api,那么由于 GPT 4 价格是 GPT 3.5 的 15 倍左右,你的账单金额会急速膨胀;
|
||||
- 如果你在使用 GPT 3.5,并且使用频率并不高,仍然发现自己的账单金额在飞快增加,那么请马上按照以下步骤排查:
|
||||
- 去 openai 官网查看你的 api key 消费记录,如果你的 token 每小时都有消费,并且每次都消耗了上万 token,那你的 key 一定是泄露了,请立即删除重新生成。**不要在乱七八糟的网站上查余额。**
|
||||
- 如果你的密码设置很短,比如 5 位以内的字母,那么爆破成本是非常低的,建议你搜索一下 docker 的日志记录,确认是否有人大量尝试了密码组合,关键字:got access code
|
||||
- 通过上述两个方法就可以定位到你的 token 被快速消耗的原因:
|
||||
- 如果 openai 消费记录异常,但是 docker 日志没有问题,那么说明是 api key 泄露;
|
||||
- 如果 docker 日志发现大量 got access code 爆破记录,那么就是密码被爆破了。
|
||||
|
136
docs/faq.en.md
Normal file
136
docs/faq.en.md
Normal file
@ -0,0 +1,136 @@
|
||||
# Frequently Asked Questions
|
||||
|
||||
## How to get help quickly?
|
||||
1. Ask ChatGPT / Bing / Baidu / Google, etc.
|
||||
2. Ask online friends. Please provide background information and a detailed description of the problem. High-quality questions are more likely to get useful answers.
|
||||
|
||||
# Deployment Related Questions
|
||||
|
||||
## Why does the Docker deployment version always prompt for updates
|
||||
The Docker version is equivalent to the stable version, and the latest Docker is always consistent with the latest release version. Currently, our release frequency is once every one to two days, so the Docker version will always be one to two days behind the latest commit, which is expected.
|
||||
|
||||
## How to deploy on Vercel
|
||||
1. Register a Github account and fork this project.
|
||||
2. Register Vercel (mobile phone verification required, Chinese number can be used), and connect your Github account.
|
||||
3. Create a new project on Vercel, select the project you forked on Github, fill in the required environment variables, and start deploying. After deployment, you can access your project through the domain provided by Vercel. (Requires proxy in mainland China)
|
||||
* If you need to access it directly in China: At your DNS provider, add a CNAME record for the domain name, pointing to cname.vercel-dns.com. Then set up your domain access on Vercel.
|
||||
|
||||
## How to modify Vercel environment variables
|
||||
- Enter the Vercel console page;
|
||||
- Select your chatgpt-next-web project;
|
||||
- Click on the Settings option at the top of the page;
|
||||
- Find the Environment Variables option in the sidebar;
|
||||
- Modify the corresponding values as needed.
|
||||
|
||||
## What is the environment variable CODE? Is it necessary to set it?
|
||||
This is your custom access password, you can choose:
|
||||
1. Do not set it, delete the environment variable. Be cautious: anyone can access your project at this time.
|
||||
2. When deploying the project, set the environment variable CODE (supports multiple passwords, separated by commas). After setting the access password, users need to enter the access password in the settings page to use it. See [related instructions](https://github.com/Yidadaa/ChatGPT-Next-Web#access-password)
|
||||
|
||||
## Why doesn't the version I deployed have streaming response
|
||||
> Related discussion: [#386](https://github.com/Yidadaa/ChatGPT-Next-Web/issues/386)
|
||||
|
||||
If you use nginx reverse proxy, you need to add the following code to the configuration file:
|
||||
```
|
||||
# No caching, support streaming output
|
||||
proxy_cache off; # Turn off caching
|
||||
proxy_buffering off; # Turn off proxy buffering
|
||||
chunked_transfer_encoding on; # Turn on chunked transfer encoding
|
||||
tcp_nopush on; # Turn on TCP NOPUSH option, disable Nagle algorithm
|
||||
tcp_nodelay on; # Turn on TCP NODELAY option, disable delay ACK algorithm
|
||||
keepalive_timeout 300; # Set keep-alive timeout to 65 seconds
|
||||
```
|
||||
|
||||
If you are deploying on netlify, this issue is still waiting to be resolved, please be patient.
|
||||
|
||||
## I've deployed, but it's not accessible
|
||||
Please check and troubleshoot the following issues:
|
||||
- Is the service started?
|
||||
- Is the port correctly mapped?
|
||||
- Is the firewall port open?
|
||||
- Is the route to the server okay?
|
||||
- Is the domain name resolved correctly?
|
||||
|
||||
# Usage Related Questions
|
||||
|
||||
## Why does it always prompt "An error occurred, please try again later"
|
||||
There could be many reasons, please check the following in order:
|
||||
- First, check if your code version is the latest version, update to the latest version and try again;
|
||||
- Check if the api key is set correctly, the environment variable name must be uppercase with underscores;
|
||||
- Check if the api key is available;
|
||||
- If you still cannot determine the problem after going through the above steps, please submit a new issue in the issue area and attach the runtime log of vercel or the log of docker runtime.
|
||||
|
||||
## Why does ChatGPT's reply get garbled
|
||||
In the settings page - model settings, there is an item called `temperature`. If this value is greater than 1, it may cause garbled replies. Adjust it back to within 1.
|
||||
|
||||
## It prompts "Now it's unauthorized, please enter the access password on the settings page" when using?
|
||||
The project has set an access password through the environment variable CODE. When using it for the first time, you need to go to settings and enter the access code to use.
|
||||
|
||||
## It prompts "You exceeded your current quota, ..." when using?
|
||||
The API KEY is problematic. Insufficient balance.
|
||||
|
||||
## What is a proxy and how to use it?
|
||||
Due to IP restrictions of OpenAI, China and some other countries/regions cannot directly connect to OpenAI API and need to go through a proxy. You can use a proxy server (forward proxy) or a pre-configured OpenAI API reverse proxy.
|
||||
- Forward proxy example: VPN ladder. In the case of docker deployment, set the environment variable HTTP_PROXY to your proxy address (http://address:port).
|
||||
- Reverse proxy example: You can use someone else's proxy address or set it up for free through Cloudflare. Set the project environment variable BASE_URL to your proxy address.
|
||||
|
||||
## Can I deploy it on a server in China?
|
||||
It is possible but there are issues to be addressed:
|
||||
- Proxy is required to connect to websites such as Github and OpenAI;
|
||||
- Domain name resolution requires filing for servers in China;
|
||||
- Chinese policy restricts proxy access to foreign websites/ChatGPT-related applications, which may be blocked.
|
||||
|
||||
# Network Service Related Questions
|
||||
## What is Cloudflare?
|
||||
Cloudflare (CF) is a network service provider offering CDN, domain management, static page hosting, edge computing function deployment, and more. Common use cases: purchase and/or host your domain (resolution, dynamic domain, etc.), apply CDN to your server (can hide IP to avoid being blocked), deploy websites (CF Pages). CF offers most services for free.
|
||||
|
||||
## What is Vercel?
|
||||
Vercel is a global cloud platform designed to help developers build and deploy modern web applications more quickly. This project and many web applications can be deployed on Vercel with a single click for free. No need to understand code, Linux, have a server, pay, or set up an OpenAI API proxy. The downside is that you need to bind a domain name to access it without restrictions in China.
|
||||
|
||||
## How to obtain a domain name?
|
||||
1. Register with a domain provider, such as Namesilo (supports Alipay) or Cloudflare for international providers, and Wanwang for domestic providers in China.
|
||||
2. Free domain name providers: eu.org (second-level domain), etc.
|
||||
3. Ask friends for a free second-level domain.
|
||||
|
||||
## How to obtain a server
|
||||
- Examples of international server providers: Amazon Web Services, Google Cloud, Vultr, Bandwagon, Hostdare, etc.
|
||||
International server considerations: Server lines affect access speed in China; CN2 GIA and CN2 lines are recommended. If the server has difficulty accessing in China (serious packet loss, etc.), you can try using a CDN (from providers like Cloudflare).
|
||||
- Domestic server providers: Alibaba Cloud, Tencent, etc.
|
||||
Domestic server considerations: Domain name resolution requires filing; domestic server bandwidth is relatively expensive; accessing foreign websites (Github, OpenAI, etc.) requires a proxy.
|
||||
|
||||
# OpenAI-related Questions
|
||||
## How to register an OpenAI account?
|
||||
Go to chat.openai.com to register. You will need:
|
||||
- A good VPN (OpenAI only allows native IP addresses of supported regions)
|
||||
- A supported email (e.g., Gmail or a company/school email, not Outlook or QQ email)
|
||||
- A way to receive SMS verification (e.g., SMS-activate website)
|
||||
|
||||
## How to activate OpenAI API? How to check API balance?
|
||||
Official website (requires VPN): https://platform.openai.com/account/usage
|
||||
Some users have set up a proxy to check the balance without a VPN; ask online friends for access. Please verify the source is reliable to avoid API Key leakage.
|
||||
|
||||
## Why doesn't my new OpenAI account have an API balance?
|
||||
(Updated April 6th) Newly registered accounts usually display API balance within 24 hours. New accounts are currently given a $5 balance.
|
||||
|
||||
## How to recharge OpenAI API?
|
||||
OpenAI only accepts credit cards from designated regions (Chinese credit cards cannot be used). If the credit cards from your region is not supported, some options include:
|
||||
1. Depay virtual credit card
|
||||
2. Apply for a foreign credit card
|
||||
3. Find someone online to top up
|
||||
|
||||
## How to access the GPT-4 API?
|
||||
(Updated April 6th) Access to the GPT-4 API requires a separate application. Go to the following address and enter your information to join the waitlist (prepare your OpenAI organization ID): https://openai.com/waitlist/gpt-4-api
|
||||
Wait for email updates afterwards.
|
||||
|
||||
## How to use the Azure OpenAI interface
|
||||
Please refer to: [#371](https://github.com/Yidadaa/ChatGPT-Next-Web/issues/371)
|
||||
|
||||
## Why is my Token consumed so fast?
|
||||
> Related discussion: [#518](https://github.com/Yidadaa/ChatGPT-Next-Web/issues/518)
|
||||
- If you have GPT-4 access and use GPT-4 API regularly, your bill will increase rapidly since GPT-4 pricing is about 15 times higher than GPT-3.5;
|
||||
- If you are using GPT-3.5 and not using it frequently, but still find your bill increasing fast, please troubleshoot immediately using these steps:
|
||||
- Check your API key consumption record on the OpenAI website; if your token is consumed every hour and each time consumes tens of thousands of tokens, your key must have been leaked. Please delete it and regenerate it immediately. **Do not check your balance on random websites.**
|
||||
- If your password is short, such as 5 characters or fewer, the cost of brute-forcing is very low. It is recommended to search docker logs to confirm whether someone has tried a large number of password combinations. Keyword: got access code
|
||||
- By following these two methods, you can locate the reason for your token's rapid consumption:
|
||||
- If the OpenAI consumption record is abnormal but the Docker log has no issues, it means your API key has been leaked;
|
||||
- If the Docker log shows a large number of got access code brute-force attempts, your password has been cracked.
|
Loading…
Reference in New Issue
Block a user