mirror of
https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
synced 2025-10-09 03:26:38 +08:00
Merge branch 'main' of https://github.com/Yidadaa/ChatGPT-Next-Web into fetch-prompt
This commit is contained in:
commit
1a723ed090
@ -9,7 +9,7 @@ One-Click to deploy your own ChatGPT web UI.
|
|||||||
|
|
||||||
[演示 Demo](https://chat-gpt-next-web.vercel.app/) / [反馈 Issues](https://github.com/Yidadaa/ChatGPT-Next-Web/issues) / [加入 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) / [加入 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)
|
||||||
|
|
||||||
[](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FYidadaa%2FChatGPT-Next-Web&env=OPENAI_API_KEY&project-name=chatgpt-next-web&repository-name=ChatGPT-Next-Web)
|
[](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)
|
||||||
|
|
||||||
[](https://gitpod.io/#https://github.com/Yidadaa/ChatGPT-Next-Web)
|
[](https://gitpod.io/#https://github.com/Yidadaa/ChatGPT-Next-Web)
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ One-Click to deploy your own ChatGPT web UI.
|
|||||||
|
|
||||||
1. 准备好你的 [OpenAI API Key](https://platform.openai.com/account/api-keys);
|
1. 准备好你的 [OpenAI API Key](https://platform.openai.com/account/api-keys);
|
||||||
2. 点击右侧按钮开始部署:
|
2. 点击右侧按钮开始部署:
|
||||||
[](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FYidadaa%2FChatGPT-Next-Web&env=OPENAI_API_KEY&project-name=chatgpt-next-web&repository-name=ChatGPT-Next-Web),直接使用 Github 账号登陆即可,记得在环境变量页填入 API Key;
|
[](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),直接使用 Github 账号登陆即可,记得在环境变量页填入 API Key;
|
||||||
3. 部署完毕后,即可开始使用;
|
3. 部署完毕后,即可开始使用;
|
||||||
4. (可选)[绑定自定义域名](https://vercel.com/docs/concepts/projects/domains/add-a-domain):Vercel 分配的域名 DNS 在某些区域被污染了,绑定自定义域名即可直连。
|
4. (可选)[绑定自定义域名](https://vercel.com/docs/concepts/projects/domains/add-a-domain):Vercel 分配的域名 DNS 在某些区域被污染了,绑定自定义域名即可直连。
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ One-Click to deploy your own ChatGPT web UI.
|
|||||||
|
|
||||||
1. Get [OpenAI API Key](https://platform.openai.com/account/api-keys);
|
1. Get [OpenAI API Key](https://platform.openai.com/account/api-keys);
|
||||||
2. Click
|
2. Click
|
||||||
[](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FYidadaa%2FChatGPT-Next-Web&env=OPENAI_API_KEY&project-name=chatgpt-next-web&repository-name=ChatGPT-Next-Web);
|
[](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);
|
||||||
3. Enjoy :)
|
3. Enjoy :)
|
||||||
|
|
||||||
## 保持更新 Keep Updated
|
## 保持更新 Keep Updated
|
||||||
|
@ -292,6 +292,7 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
top: -26px;
|
top: -26px;
|
||||||
|
left: 100px;
|
||||||
transition: all ease 0.3s;
|
transition: all ease 0.3s;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
@ -302,6 +303,7 @@
|
|||||||
.chat-message-top-action {
|
.chat-message-top-action {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
color: var(--black);
|
color: var(--black);
|
||||||
|
white-space: nowrap;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
@ -408,7 +410,7 @@
|
|||||||
background-color: var(--white);
|
background-color: var(--white);
|
||||||
color: var(--black);
|
color: var(--black);
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
padding: 10px 14px;
|
padding: 10px 14px 50px;
|
||||||
resize: none;
|
resize: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,7 @@ function useSubmitHandler() {
|
|||||||
|
|
||||||
const shouldSubmit = (e: KeyboardEvent) => {
|
const shouldSubmit = (e: KeyboardEvent) => {
|
||||||
if (e.key !== "Enter") return false;
|
if (e.key !== "Enter") return false;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
(config.submitKey === SubmitKey.AltEnter && e.altKey) ||
|
(config.submitKey === SubmitKey.AltEnter && e.altKey) ||
|
||||||
(config.submitKey === SubmitKey.CtrlEnter && e.ctrlKey) ||
|
(config.submitKey === SubmitKey.CtrlEnter && e.ctrlKey) ||
|
||||||
@ -170,7 +170,7 @@ export function PromptHints(props: {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Chat(props: { showSideBar?: () => void }) {
|
export function Chat(props: { showSideBar?: () => void, sideBarShowing?: boolean }) {
|
||||||
type RenderMessage = Message & { preview?: boolean };
|
type RenderMessage = Message & { preview?: boolean };
|
||||||
|
|
||||||
const chatStore = useChatStore();
|
const chatStore = useChatStore();
|
||||||
@ -178,6 +178,7 @@ export function Chat(props: { showSideBar?: () => void }) {
|
|||||||
state.currentSession(),
|
state.currentSession(),
|
||||||
state.currentSessionIndex,
|
state.currentSessionIndex,
|
||||||
]);
|
]);
|
||||||
|
const fontSize = useChatStore((state) => state.config.fontSize);
|
||||||
|
|
||||||
const inputRef = useRef<HTMLTextAreaElement>(null);
|
const inputRef = useRef<HTMLTextAreaElement>(null);
|
||||||
const [userInput, setUserInput] = useState("");
|
const [userInput, setUserInput] = useState("");
|
||||||
@ -205,6 +206,11 @@ export function Chat(props: { showSideBar?: () => void }) {
|
|||||||
// only search prompts when user input is short
|
// only search prompts when user input is short
|
||||||
const SEARCH_TEXT_LIMIT = 30;
|
const SEARCH_TEXT_LIMIT = 30;
|
||||||
const onInput = (text: string) => {
|
const onInput = (text: string) => {
|
||||||
|
const textareaDom = inputRef.current
|
||||||
|
if (textareaDom) {
|
||||||
|
const paddingBottomNum: number = parseInt(window.getComputedStyle(textareaDom).paddingBottom, 10);
|
||||||
|
textareaDom.scrollTop = textareaDom.scrollHeight - textareaDom.offsetHeight + paddingBottomNum;
|
||||||
|
}
|
||||||
setUserInput(text);
|
setUserInput(text);
|
||||||
const n = text.trim().length;
|
const n = text.trim().length;
|
||||||
if (n === 0 || n > SEARCH_TEXT_LIMIT) {
|
if (n === 0 || n > SEARCH_TEXT_LIMIT) {
|
||||||
@ -374,7 +380,7 @@ export function Chat(props: { showSideBar?: () => void }) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className={styles["chat-message-item"]}>
|
<div className={styles["chat-message-item"]}>
|
||||||
{!isUser && (
|
{(!isUser && !(message.preview || message.content.length === 0)) && (
|
||||||
<div className={styles["chat-message-top-actions"]}>
|
<div className={styles["chat-message-top-actions"]}>
|
||||||
{message.streaming ? (
|
{message.streaming ? (
|
||||||
<div
|
<div
|
||||||
@ -406,6 +412,7 @@ export function Chat(props: { showSideBar?: () => void }) {
|
|||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
className="markdown-body"
|
className="markdown-body"
|
||||||
|
style={{ fontSize: `${fontSize}px` }}
|
||||||
onContextMenu={(e) => onRightClick(e, message)}
|
onContextMenu={(e) => onRightClick(e, message)}
|
||||||
>
|
>
|
||||||
<Markdown content={message.content} />
|
<Markdown content={message.content} />
|
||||||
@ -444,7 +451,7 @@ export function Chat(props: { showSideBar?: () => void }) {
|
|||||||
setAutoScroll(false);
|
setAutoScroll(false);
|
||||||
setTimeout(() => setPromptHints([]), 100);
|
setTimeout(() => setPromptHints([]), 100);
|
||||||
}}
|
}}
|
||||||
autoFocus
|
autoFocus={!props?.sideBarShowing}
|
||||||
/>
|
/>
|
||||||
<IconButton
|
<IconButton
|
||||||
icon={<SendWhiteIcon />}
|
icon={<SendWhiteIcon />}
|
||||||
@ -646,7 +653,7 @@ export function Home() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Chat key="chat" showSideBar={() => setShowSideBar(true)} />
|
<Chat key="chat" showSideBar={() => setShowSideBar(true)} sideBarShowing={showSideBar} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -226,6 +226,26 @@ export function Settings(props: { closeSettings: () => void }) {
|
|||||||
</select>
|
</select>
|
||||||
</SettingItem>
|
</SettingItem>
|
||||||
|
|
||||||
|
<SettingItem
|
||||||
|
title={Locale.Settings.FontSize.Title}
|
||||||
|
subTitle={Locale.Settings.FontSize.SubTitle}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="range"
|
||||||
|
title={`${config.fontSize ?? 14}px`}
|
||||||
|
value={config.fontSize}
|
||||||
|
min="12"
|
||||||
|
max="18"
|
||||||
|
step="1"
|
||||||
|
onChange={(e) =>
|
||||||
|
updateConfig(
|
||||||
|
(config) =>
|
||||||
|
(config.fontSize = Number.parseInt(e.currentTarget.value))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
></input>
|
||||||
|
</SettingItem>
|
||||||
|
|
||||||
<div className="no-mobile">
|
<div className="no-mobile">
|
||||||
<SettingItem title={Locale.Settings.TightBorder}>
|
<SettingItem title={Locale.Settings.TightBorder}>
|
||||||
<input
|
<input
|
||||||
@ -369,7 +389,7 @@ export function Settings(props: { closeSettings: () => void }) {
|
|||||||
type="range"
|
type="range"
|
||||||
value={config.modelConfig.temperature.toFixed(1)}
|
value={config.modelConfig.temperature.toFixed(1)}
|
||||||
min="0"
|
min="0"
|
||||||
max="1"
|
max="2"
|
||||||
step="0.1"
|
step="0.1"
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
updateConfig(
|
updateConfig(
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { SubmitKey } from "../store/app";
|
||||||
|
|
||||||
const cn = {
|
const cn = {
|
||||||
WIP: "该功能仍在开发中……",
|
WIP: "该功能仍在开发中……",
|
||||||
Error: {
|
Error: {
|
||||||
@ -17,7 +19,13 @@ const cn = {
|
|||||||
Retry: "重试",
|
Retry: "重试",
|
||||||
},
|
},
|
||||||
Typing: "正在输入…",
|
Typing: "正在输入…",
|
||||||
Input: (submitKey: string) => `输入消息,${submitKey} 发送`,
|
Input: (submitKey: string) => {
|
||||||
|
var inputHints = `输入消息,${submitKey} 发送`;
|
||||||
|
if (submitKey === String(SubmitKey.Enter)) {
|
||||||
|
inputHints += ",Shift + Enter 换行";
|
||||||
|
}
|
||||||
|
return inputHints;
|
||||||
|
},
|
||||||
Send: "发送",
|
Send: "发送",
|
||||||
},
|
},
|
||||||
Export: {
|
Export: {
|
||||||
@ -51,6 +59,10 @@ const cn = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Avatar: "头像",
|
Avatar: "头像",
|
||||||
|
FontSize: {
|
||||||
|
Title: "字体大小",
|
||||||
|
SubTitle: "聊天内容的字体大小",
|
||||||
|
},
|
||||||
Update: {
|
Update: {
|
||||||
Version: (x: string) => `当前版本:${x}`,
|
Version: (x: string) => `当前版本:${x}`,
|
||||||
IsLatest: "已是最新版本",
|
IsLatest: "已是最新版本",
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { SubmitKey } from "../store/app";
|
||||||
import type { LocaleType } from "./index";
|
import type { LocaleType } from "./index";
|
||||||
|
|
||||||
const en: LocaleType = {
|
const en: LocaleType = {
|
||||||
@ -20,8 +21,13 @@ const en: LocaleType = {
|
|||||||
Retry: "Retry",
|
Retry: "Retry",
|
||||||
},
|
},
|
||||||
Typing: "Typing…",
|
Typing: "Typing…",
|
||||||
Input: (submitKey: string) =>
|
Input: (submitKey: string) => {
|
||||||
`Type something and press ${submitKey} to send`,
|
var inputHints = `Type something and press ${submitKey} to send`;
|
||||||
|
if (submitKey === String(SubmitKey.Enter)) {
|
||||||
|
inputHints += ", press Shift + Enter to newline";
|
||||||
|
}
|
||||||
|
return inputHints;
|
||||||
|
},
|
||||||
Send: "Send",
|
Send: "Send",
|
||||||
},
|
},
|
||||||
Export: {
|
Export: {
|
||||||
@ -55,6 +61,10 @@ const en: LocaleType = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Avatar: "Avatar",
|
Avatar: "Avatar",
|
||||||
|
FontSize: {
|
||||||
|
Title: "Font Size",
|
||||||
|
SubTitle: "Adjust font size of chat content",
|
||||||
|
},
|
||||||
Update: {
|
Update: {
|
||||||
Version: (x: string) => `Version: ${x}`,
|
Version: (x: string) => `Version: ${x}`,
|
||||||
IsLatest: "Latest version",
|
IsLatest: "Latest version",
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { SubmitKey } from "../store/app";
|
||||||
import type { LocaleType } from "./index";
|
import type { LocaleType } from "./index";
|
||||||
|
|
||||||
const tw: LocaleType = {
|
const tw: LocaleType = {
|
||||||
@ -19,7 +20,13 @@ const tw: LocaleType = {
|
|||||||
Retry: "重試",
|
Retry: "重試",
|
||||||
},
|
},
|
||||||
Typing: "正在輸入…",
|
Typing: "正在輸入…",
|
||||||
Input: (submitKey: string) => `輸入訊息後,按下 ${submitKey} 鍵即可發送`,
|
Input: (submitKey: string) => {
|
||||||
|
var inputHints = `輸入訊息後,按下 ${submitKey} 鍵即可發送`;
|
||||||
|
if (submitKey === String(SubmitKey.Enter)) {
|
||||||
|
inputHints += ",Shift + Enter 鍵換行";
|
||||||
|
}
|
||||||
|
return inputHints;
|
||||||
|
},
|
||||||
Send: "發送",
|
Send: "發送",
|
||||||
},
|
},
|
||||||
Export: {
|
Export: {
|
||||||
@ -53,6 +60,10 @@ const tw: LocaleType = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Avatar: "大頭貼",
|
Avatar: "大頭貼",
|
||||||
|
FontSize: {
|
||||||
|
Title: "字型大小",
|
||||||
|
SubTitle: "聊天內容的字型大小",
|
||||||
|
},
|
||||||
Update: {
|
Update: {
|
||||||
Version: (x: string) => `當前版本:${x}`,
|
Version: (x: string) => `當前版本:${x}`,
|
||||||
IsLatest: "已是最新版本",
|
IsLatest: "已是最新版本",
|
||||||
|
@ -31,12 +31,12 @@ export enum Theme {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ChatConfig {
|
export interface ChatConfig {
|
||||||
maxToken?: number;
|
|
||||||
historyMessageCount: number; // -1 means all
|
historyMessageCount: number; // -1 means all
|
||||||
compressMessageLengthThreshold: number;
|
compressMessageLengthThreshold: number;
|
||||||
sendBotMessages: boolean; // send bot's message or not
|
sendBotMessages: boolean; // send bot's message or not
|
||||||
submitKey: SubmitKey;
|
submitKey: SubmitKey;
|
||||||
avatar: string;
|
avatar: string;
|
||||||
|
fontSize: number;
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
tightBorder: boolean;
|
tightBorder: boolean;
|
||||||
|
|
||||||
@ -123,6 +123,7 @@ const DEFAULT_CONFIG: ChatConfig = {
|
|||||||
sendBotMessages: true as boolean,
|
sendBotMessages: true as boolean,
|
||||||
submitKey: SubmitKey.CtrlEnter as SubmitKey,
|
submitKey: SubmitKey.CtrlEnter as SubmitKey,
|
||||||
avatar: "1f603",
|
avatar: "1f603",
|
||||||
|
fontSize: 14,
|
||||||
theme: Theme.Auto as Theme,
|
theme: Theme.Auto as Theme,
|
||||||
tightBorder: false,
|
tightBorder: false,
|
||||||
|
|
||||||
|
@ -1116,4 +1116,4 @@
|
|||||||
|
|
||||||
.markdown-body ::-webkit-calendar-picker-indicator {
|
.markdown-body ::-webkit-calendar-picker-indicator {
|
||||||
filter: invert(50%);
|
filter: invert(50%);
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user