mirror of
https://github.com/Yidadaa/ChatGPT-Next-Web.git
synced 2025-09-05 23:30:31 +08:00
Compare commits
49 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
7f3cbaa064 | ||
|
eb72c83b7e | ||
|
e93ea0fa97 | ||
|
3b6f93afdf | ||
|
4597a2286a | ||
|
780968979d | ||
|
adc0db4c74 | ||
|
f0dd95a2a3 | ||
|
6155a190ac | ||
|
493aa8c591 | ||
|
6c82f804ae | ||
|
a2807c9815 | ||
|
d822f333c2 | ||
|
8f498075b9 | ||
|
c4bf6a6383 | ||
|
939402b2d9 | ||
|
684a3c41ef | ||
|
306f0850e9 | ||
|
55f37248f7 | ||
|
c93a46a02f | ||
|
77a3fdea5f | ||
|
cc1a1d4f3c | ||
|
0463b350d8 | ||
|
8f87a68f72 | ||
|
60f27fdfbb | ||
|
d17706636b | ||
|
9570691d5b | ||
|
efe4fcc188 | ||
|
efaf6590ef | ||
|
fb06fb8c38 | ||
|
f188841188 | ||
|
5593c067c4 | ||
|
689b7bab26 | ||
|
a81e7394f0 | ||
|
492fed6802 | ||
|
bdf17fafff | ||
|
58baa23199 | ||
|
dd80c4563d | ||
|
785372ad73 | ||
|
d8e4808316 | ||
|
6446692db0 | ||
|
cd73c3a7cb | ||
|
d0eee767fa | ||
|
e880df6db9 | ||
|
96c4f5bbd9 | ||
|
2645540721 | ||
|
b1f27aaf93 | ||
|
fb2d281aac | ||
|
8d0d08725d |
1
.eslintignore
Normal file
1
.eslintignore
Normal file
@@ -0,0 +1 @@
|
|||||||
|
public/serviceWorker.js
|
33
.github/workflows/docker.yml
vendored
Normal file
33
.github/workflows/docker.yml
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
name: Publish Docker image
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
push_to_registry:
|
||||||
|
name: Push Docker image to Docker Hub
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check out the repo
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Log in to Docker Hub
|
||||||
|
uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Extract metadata (tags, labels) for Docker
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
|
||||||
|
with:
|
||||||
|
images: yidadaa/chatgpt-next-web
|
||||||
|
|
||||||
|
- name: Build and push Docker image
|
||||||
|
uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
44
Dockerfile
Normal file
44
Dockerfile
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
FROM node:18-alpine AS base
|
||||||
|
|
||||||
|
FROM base AS deps
|
||||||
|
|
||||||
|
RUN apk add --no-cache libc6-compat
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package.json yarn.lock* package-lock.json* ./
|
||||||
|
|
||||||
|
RUN \
|
||||||
|
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
|
||||||
|
elif [ -f package-lock.json ]; then npm ci; \
|
||||||
|
else echo "Lockfile not found." && exit 1; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
FROM base AS builder
|
||||||
|
|
||||||
|
RUN apk update && apk add --no-cache git
|
||||||
|
|
||||||
|
ENV OPENAI_API_KEY=""
|
||||||
|
ENV CODE=""
|
||||||
|
ARG DOCKER=true
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN yarn build
|
||||||
|
|
||||||
|
FROM base AS runner
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
ENV OPENAI_API_KEY=""
|
||||||
|
ENV CODE=""
|
||||||
|
|
||||||
|
COPY --from=builder /app/public ./public
|
||||||
|
COPY --from=builder /app/.next/standalone ./
|
||||||
|
COPY --from=builder /app/.next/static ./.next/static
|
||||||
|
COPY --from=builder /app/.next/server ./.next/server
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
CMD ["node","server.js"]
|
39
README.md
39
README.md
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
One-Click to deploy your own ChatGPT web UI.
|
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) / [微信群](https://user-images.githubusercontent.com/16968934/227772522-b3ba3713-9206-4c8d-a81f-22300b7c313a.jpg) / [打赏开发者](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&project-name=chatgpt-next-web&repository-name=ChatGPT-Next-Web)
|
||||||
|
|
||||||
@@ -109,31 +109,24 @@ OPENAI_API_KEY=<your api key here>
|
|||||||
```
|
```
|
||||||
|
|
||||||
### 本地开发 Local Development
|
### 本地开发 Local Development
|
||||||
|
|
||||||
> 如果你是中国大陆用户,不建议在本地进行开发,除非你能够独立解决 OpenAI API 本地代理问题。
|
> 如果你是中国大陆用户,不建议在本地进行开发,除非你能够独立解决 OpenAI API 本地代理问题。
|
||||||
|
|
||||||
1. 安装 nodejs 和 yarn,具体细节请询问 ChatGPT;
|
1. 安装 nodejs 和 yarn,具体细节请询问 ChatGPT;
|
||||||
2. 执行 `yarn install && yarn dev` 即可。
|
2. 执行 `yarn install && yarn dev` 即可。
|
||||||
|
|
||||||
### 本地部署 Local Deployment
|
### 本地部署 Local Deployment
|
||||||
请直接询问 ChatGPT,使用下列 Prompt:
|
```shell
|
||||||
```
|
bash <(curl -s https://raw.githubusercontent.com/Yidadaa/ChatGPT-Next-Web/main/scripts/setup.sh)
|
||||||
如何使用 pm2 和 yarn 部署 nextjs 项目到 ubuntu 服务器上,项目编译命令为 yarn build,启动命令为 yarn start,启动时需要设置环境变量为 OPENAI_API_KEY,端口为 3000,使用 ngnix 做反向代理
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Please ask ChatGPT with prompt:
|
|
||||||
```
|
|
||||||
how to deploy nextjs project with pm2 and yarn on my ubuntu server, the build command is `yarn build`, the start command is `yarn start`, the project must start with env var named `OPENAI_API_KEY`, the port is 3000, use ngnix
|
|
||||||
```
|
|
||||||
|
|
||||||
### Docker Deployment
|
### 容器部署 Docker Deployment
|
||||||
请直接询问 ChatGPT,使用下列 Prompt:
|
|
||||||
```
|
|
||||||
如何使用 docker 部署 nextjs 项目到 ubuntu 服务器上,项目编译命令为 yarn build,启动命令为 yarn start,启动时需要设置环境变量为 OPENAI_API_KEY,端口为 3000,使用 ngnix 做反向代理
|
|
||||||
```
|
|
||||||
|
|
||||||
Please ask ChatGPT with prompt:
|
```shell
|
||||||
```
|
docker pull yidadaa/chatgpt-next-web
|
||||||
how to deploy nextjs project with docker on my ubuntu server, the build command is `yarn build`, the start command is `yarn start`, the project must start with env var named `OPENAI_API_KEY`, the port is 3000, use ngnix
|
|
||||||
|
docker run -d -p 3000:3000 -e OPENAI_API_KEY="" -e CODE="" yidadaa/chatgpt-next-web
|
||||||
```
|
```
|
||||||
|
|
||||||
## 截图 Screenshots
|
## 截图 Screenshots
|
||||||
@@ -143,17 +136,29 @@ how to deploy nextjs project with docker on my ubuntu server, the build command
|
|||||||

|

|
||||||
|
|
||||||
## 说明 Attention
|
## 说明 Attention
|
||||||
|
|
||||||
本项目的演示地址所用的 OpenAI 账户的免费额度将于 2023-04-01 过期,届时将无法通过演示地址在线体验。
|
本项目的演示地址所用的 OpenAI 账户的免费额度将于 2023-04-01 过期,届时将无法通过演示地址在线体验。
|
||||||
|
|
||||||
如果你想贡献出自己的 API Key,可以通过作者主页的邮箱发送给作者,并标注过期时间。
|
如果你想贡献出自己的 API Key,可以通过作者主页的邮箱发送给作者,并标注过期时间。
|
||||||
|
|
||||||
The free trial of the OpenAI account used by the demo will expire on April 1, 2023, and the demo will not be available at that time.
|
The free trial of the OpenAI account used by the demo will expire on April 1, 2023, and the demo will not be available at that time.
|
||||||
|
|
||||||
If you would like to contribute your API key, you can email it to the author and indicate the expiration date of the API key.
|
If you would like to contribute your API key, you can email it to the author and indicate the expiration date of the API key.
|
||||||
|
|
||||||
## 鸣谢 Special Thanks
|
## 鸣谢 Special Thanks
|
||||||
|
|
||||||
### 捐赠者 Sponsor
|
### 捐赠者 Sponsor
|
||||||
|
|
||||||
[@mushan0x0](https://github.com/mushan0x0)
|
[@mushan0x0](https://github.com/mushan0x0)
|
||||||
|
[@ClarenceDan](https://github.com/ClarenceDan)
|
||||||
|
[@zhangjia](https://github.com/zhangjia)
|
||||||
|
|
||||||
|
### 贡献者 Contributor
|
||||||
|
|
||||||
|
[@AprilNEA](https://github.com/AprilNEA)
|
||||||
|
[@iSource](https://github.com/iSource)
|
||||||
|
[@iFwu](https://github.com/iFwu)
|
||||||
|
[@xiaotianxt](https://github.com/xiaotianxt)
|
||||||
|
|
||||||
## LICENSE
|
## LICENSE
|
||||||
|
|
||||||
|
@@ -14,3 +14,4 @@ export function getAccessCodes(): Set<string> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const ACCESS_CODES = getAccessCodes();
|
export const ACCESS_CODES = getAccessCodes();
|
||||||
|
export const IS_IN_DOCKER = process.env.DOCKER;
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
import type { ChatRequest } from "../chat/typing";
|
|
||||||
import { createParser } from "eventsource-parser";
|
import { createParser } from "eventsource-parser";
|
||||||
import { NextRequest } from "next/server";
|
import { NextRequest } from "next/server";
|
||||||
|
|
||||||
|
@@ -131,10 +131,12 @@ function useSubmitHandler() {
|
|||||||
(config.submitKey === SubmitKey.AltEnter && e.altKey) ||
|
(config.submitKey === SubmitKey.AltEnter && e.altKey) ||
|
||||||
(config.submitKey === SubmitKey.CtrlEnter && e.ctrlKey) ||
|
(config.submitKey === SubmitKey.CtrlEnter && e.ctrlKey) ||
|
||||||
(config.submitKey === SubmitKey.ShiftEnter && e.shiftKey) ||
|
(config.submitKey === SubmitKey.ShiftEnter && e.shiftKey) ||
|
||||||
|
(config.submitKey === SubmitKey.MetaEnter && e.metaKey) ||
|
||||||
(config.submitKey === SubmitKey.Enter &&
|
(config.submitKey === SubmitKey.Enter &&
|
||||||
!e.altKey &&
|
!e.altKey &&
|
||||||
!e.ctrlKey &&
|
!e.ctrlKey &&
|
||||||
!e.shiftKey)
|
!e.shiftKey &&
|
||||||
|
!e.metaKey)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -163,6 +165,7 @@ export function Chat(props: { showSideBar?: () => void }) {
|
|||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
onUserInput(userInput).then(() => setIsLoading(false));
|
onUserInput(userInput).then(() => setIsLoading(false));
|
||||||
setUserInput("");
|
setUserInput("");
|
||||||
|
inputRef.current?.focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
// stop response
|
// stop response
|
||||||
@@ -203,6 +206,7 @@ export function Chat(props: { showSideBar?: () => void }) {
|
|||||||
|
|
||||||
// for auto-scroll
|
// for auto-scroll
|
||||||
const latestMessageRef = useRef<HTMLDivElement>(null);
|
const latestMessageRef = useRef<HTMLDivElement>(null);
|
||||||
|
const inputRef = useRef<HTMLTextAreaElement>(null);
|
||||||
|
|
||||||
// wont scroll while hovering messages
|
// wont scroll while hovering messages
|
||||||
const [autoScroll, setAutoScroll] = useState(false);
|
const [autoScroll, setAutoScroll] = useState(false);
|
||||||
@@ -371,6 +375,7 @@ export function Chat(props: { showSideBar?: () => void }) {
|
|||||||
<div className={styles["chat-input-panel"]}>
|
<div className={styles["chat-input-panel"]}>
|
||||||
<div className={styles["chat-input-panel-inner"]}>
|
<div className={styles["chat-input-panel-inner"]}>
|
||||||
<textarea
|
<textarea
|
||||||
|
ref={inputRef}
|
||||||
className={styles["chat-input"]}
|
className={styles["chat-input"]}
|
||||||
placeholder={Locale.Chat.Input(submitKey)}
|
placeholder={Locale.Chat.Input(submitKey)}
|
||||||
rows={3}
|
rows={3}
|
||||||
@@ -399,11 +404,16 @@ function useSwitchTheme() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.body.classList.remove("light");
|
document.body.classList.remove("light");
|
||||||
document.body.classList.remove("dark");
|
document.body.classList.remove("dark");
|
||||||
|
|
||||||
if (config.theme === "dark") {
|
if (config.theme === "dark") {
|
||||||
document.body.classList.add("dark");
|
document.body.classList.add("dark");
|
||||||
} else if (config.theme === "light") {
|
} else if (config.theme === "light") {
|
||||||
document.body.classList.add("light");
|
document.body.classList.add("light");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const themeColor = getComputedStyle(document.body).getPropertyValue("--theme-color").trim();
|
||||||
|
const metaDescription = document.querySelector('meta[name="theme-color"]');
|
||||||
|
metaDescription?.setAttribute('content', themeColor);
|
||||||
}, [config.theme]);
|
}, [config.theme]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,6 +475,16 @@ function showMemoryPrompt(session: ChatSession) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const useHasHydrated = () => {
|
||||||
|
const [hasHydrated, setHasHydrated] = useState<boolean>(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setHasHydrated(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return hasHydrated;
|
||||||
|
};
|
||||||
|
|
||||||
export function Home() {
|
export function Home() {
|
||||||
const [createNewSession, currentIndex, removeSession] = useChatStore(
|
const [createNewSession, currentIndex, removeSession] = useChatStore(
|
||||||
(state) => [
|
(state) => [
|
||||||
@@ -473,7 +493,7 @@ export function Home() {
|
|||||||
state.removeSession,
|
state.removeSession,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
const loading = !useChatStore?.persist?.hasHydrated();
|
const loading = !useHasHydrated();
|
||||||
const [showSideBar, setShowSideBar] = useState(true);
|
const [showSideBar, setShowSideBar] = useState(true);
|
||||||
|
|
||||||
// setting
|
// setting
|
||||||
@@ -546,7 +566,10 @@ export function Home() {
|
|||||||
<IconButton
|
<IconButton
|
||||||
icon={<AddIcon />}
|
icon={<AddIcon />}
|
||||||
text={Locale.Home.NewChat}
|
text={Locale.Home.NewChat}
|
||||||
onClick={createNewSession}
|
onClick={()=>{
|
||||||
|
createNewSession();
|
||||||
|
setShowSideBar(false);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -354,7 +354,7 @@ export function Settings(props: { closeSettings: () => void }) {
|
|||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
min={100}
|
min={100}
|
||||||
max={4000}
|
max={4096}
|
||||||
value={config.modelConfig.max_tokens}
|
value={config.modelConfig.max_tokens}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
updateConfig(
|
updateConfig(
|
||||||
|
@@ -3,22 +3,32 @@ import "./styles/globals.scss";
|
|||||||
import "./styles/markdown.scss";
|
import "./styles/markdown.scss";
|
||||||
import "./styles/prism.scss";
|
import "./styles/prism.scss";
|
||||||
import process from "child_process";
|
import process from "child_process";
|
||||||
import { ACCESS_CODES } from "./api/access";
|
import { ACCESS_CODES, IS_IN_DOCKER } from "./api/access";
|
||||||
|
|
||||||
const COMMIT_ID = process
|
let COMMIT_ID: string | undefined;
|
||||||
.execSync("git rev-parse --short HEAD")
|
try {
|
||||||
.toString()
|
COMMIT_ID = process
|
||||||
.trim();
|
.execSync("git rev-parse --short HEAD")
|
||||||
|
.toString()
|
||||||
|
.trim();
|
||||||
|
} catch (e) {
|
||||||
|
console.error("No git or not from git repo.")
|
||||||
|
}
|
||||||
|
|
||||||
export const metadata = {
|
export const metadata = {
|
||||||
title: "ChatGPT Next Web",
|
title: "ChatGPT Next Web",
|
||||||
description: "Your personal ChatGPT Chat Bot.",
|
description: "Your personal ChatGPT Chat Bot.",
|
||||||
|
appleWebApp: {
|
||||||
|
title: "ChatGPT Next Web",
|
||||||
|
statusBarStyle: "black-translucent",
|
||||||
|
},
|
||||||
|
themeColor: "#fafafa"
|
||||||
};
|
};
|
||||||
|
|
||||||
function Meta() {
|
function Meta() {
|
||||||
const metas = {
|
const metas = {
|
||||||
version: COMMIT_ID,
|
version: COMMIT_ID ?? "unknown",
|
||||||
access: ACCESS_CODES.size > 0 ? "enabled" : "disabled",
|
access: (ACCESS_CODES.size > 0 || IS_IN_DOCKER) ? "enabled" : "disabled",
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -50,6 +60,7 @@ export default function RootLayout({
|
|||||||
href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;700;900&display=swap"
|
href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;700;900&display=swap"
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
></link>
|
></link>
|
||||||
|
<script src="/serviceWorkerRegister.js" defer></script>
|
||||||
</head>
|
</head>
|
||||||
<body>{children}</body>
|
<body>{children}</body>
|
||||||
</html>
|
</html>
|
||||||
|
@@ -21,6 +21,7 @@ export enum SubmitKey {
|
|||||||
CtrlEnter = "Ctrl + Enter",
|
CtrlEnter = "Ctrl + Enter",
|
||||||
ShiftEnter = "Shift + Enter",
|
ShiftEnter = "Shift + Enter",
|
||||||
AltEnter = "Alt + Enter",
|
AltEnter = "Alt + Enter",
|
||||||
|
MetaEnter = "Meta + Enter",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Theme {
|
export enum Theme {
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
--second: rgb(231, 248, 255);
|
--second: rgb(231, 248, 255);
|
||||||
--hover-color: #f3f3f3;
|
--hover-color: #f3f3f3;
|
||||||
--bar-color: rgba(0, 0, 0, 0.1);
|
--bar-color: rgba(0, 0, 0, 0.1);
|
||||||
|
--theme-color: var(--gray);
|
||||||
|
|
||||||
/* shadow */
|
/* shadow */
|
||||||
--shadow: 50px 50px 100px 10px rgb(0, 0, 0, 0.1);
|
--shadow: 50px 50px 100px 10px rgb(0, 0, 0, 0.1);
|
||||||
@@ -28,6 +29,8 @@
|
|||||||
--bar-color: rgba(255, 255, 255, 0.1);
|
--bar-color: rgba(255, 255, 255, 0.1);
|
||||||
|
|
||||||
--border-in-light: 1px solid rgba(255, 255, 255, 0.192);
|
--border-in-light: 1px solid rgba(255, 255, 255, 0.192);
|
||||||
|
|
||||||
|
--theme-color: var(--gray);
|
||||||
}
|
}
|
||||||
|
|
||||||
.light {
|
.light {
|
||||||
@@ -84,7 +87,11 @@ body {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
font-family: "Noto Sans SC", "SF Pro SC", "SF Pro Text", "SF Pro Icons",
|
font-family: "Noto Sans SC", "SF Pro SC", "SF Pro Text", "SF Pro Icons",
|
||||||
"PingFang SC", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
|
"PingFang SC", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
|
||||||
|
|
||||||
|
@media only screen and (max-width: 600px) {
|
||||||
|
background-color: var(--second);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
|
@@ -839,21 +839,20 @@
|
|||||||
|
|
||||||
.markdown-body .highlight pre,
|
.markdown-body .highlight pre,
|
||||||
.markdown-body pre {
|
.markdown-body pre {
|
||||||
padding: 16px;
|
padding: 16px 16px 8px 16px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
font-size: 85%;
|
font-size: 85%;
|
||||||
line-height: 1.45;
|
line-height: 1.45;
|
||||||
background-color: var(--color-canvas-subtle);
|
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-body pre code,
|
.markdown-body pre code,
|
||||||
.markdown-body pre tt {
|
.markdown-body pre tt {
|
||||||
display: inline;
|
display: inline-block;
|
||||||
max-width: auto;
|
max-width: 100%;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
overflow: visible;
|
overflow-x: scroll;
|
||||||
line-height: inherit;
|
line-height: inherit;
|
||||||
word-wrap: normal;
|
word-wrap: normal;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
@@ -1,4 +1,9 @@
|
|||||||
.markdown-body {
|
.markdown-body {
|
||||||
|
pre {
|
||||||
|
background: #282a36;
|
||||||
|
color: #f8f8f2;
|
||||||
|
}
|
||||||
|
|
||||||
code[class*="language-"],
|
code[class*="language-"],
|
||||||
pre[class*="language-"] {
|
pre[class*="language-"] {
|
||||||
color: #f8f8f2;
|
color: #f8f8f2;
|
||||||
@@ -117,13 +122,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@mixin light {
|
@mixin light {
|
||||||
.markdown-body pre[class*="language-"] {
|
.markdown-body pre {
|
||||||
filter: invert(1) hue-rotate(50deg) brightness(1.3);
|
filter: invert(1) hue-rotate(90deg) brightness(1.3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin dark {
|
@mixin dark {
|
||||||
.markdown-body pre[class*="language-"] {
|
.markdown-body pre {
|
||||||
filter: none;
|
filter: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -14,4 +14,8 @@ const nextConfig = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (process.env.DOCKER) {
|
||||||
|
nextConfig.output = 'standalone'
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = nextConfig;
|
module.exports = nextConfig;
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
"name": "chatgpt-next-web",
|
"name": "chatgpt-next-web",
|
||||||
"version": "1.1",
|
"version": "1.1",
|
||||||
"private": false,
|
"private": false,
|
||||||
|
"license": "Anti 996",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
|
4
public/robots.txt
Normal file
4
public/robots.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
User-agent: *
|
||||||
|
Disallow: /
|
||||||
|
User-agent: vitals.vercel-insights.com
|
||||||
|
Allow: /
|
24
public/serviceWorker.js
Normal file
24
public/serviceWorker.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
const CHATGPT_NEXT_WEB_CACHE = "chatgpt-next-web-cache";
|
||||||
|
|
||||||
|
self.addEventListener('activate', function (event) {
|
||||||
|
console.log('ServiceWorker activated.');
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener('install', function (event) {
|
||||||
|
event.waitUntil(
|
||||||
|
caches.open(CHATGPT_NEXT_WEB_CACHE)
|
||||||
|
.then(function (cache) {
|
||||||
|
return cache.addAll([
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener('fetch', function (event) {
|
||||||
|
event.respondWith(
|
||||||
|
caches.match(event.request)
|
||||||
|
.then(function (response) {
|
||||||
|
return response || fetch(event.request);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
9
public/serviceWorkerRegister.js
Normal file
9
public/serviceWorkerRegister.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
if ('serviceWorker' in navigator) {
|
||||||
|
window.addEventListener('load', function () {
|
||||||
|
navigator.serviceWorker.register('/serviceWorker.js').then(function (registration) {
|
||||||
|
console.log('ServiceWorker registration successful with scope: ', registration.scope);
|
||||||
|
}, function (err) {
|
||||||
|
console.error('ServiceWorker registration failed: ', err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
@@ -1 +1,21 @@
|
|||||||
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
|
{
|
||||||
|
"name": "ChatGPT Next Web",
|
||||||
|
"short_name": "ChatGPT",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "/android-chrome-192x192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/android-chrome-512x512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"start_url": "/",
|
||||||
|
"theme_color": "#ffffff",
|
||||||
|
"background_color": "#ffffff",
|
||||||
|
"display": "standalone"
|
||||||
|
}
|
||||||
|
|
64
scripts/setup.sh
Normal file
64
scripts/setup.sh
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Check if running on a supported system
|
||||||
|
case "$(uname -s)" in
|
||||||
|
Linux)
|
||||||
|
if [[ -f "/etc/lsb-release" ]]; then
|
||||||
|
. /etc/lsb-release
|
||||||
|
if [[ "$DISTRIB_ID" != "Ubuntu" ]]; then
|
||||||
|
echo "This script only works on Ubuntu, not $DISTRIB_ID."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [[ ! "$(cat /etc/*-release | grep '^ID=')" =~ ^(ID=\"ubuntu\")|(ID=\"centos\")|(ID=\"arch\")$ ]]; then
|
||||||
|
echo "Unsupported Linux distribution."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
Darwin)
|
||||||
|
echo "Running on MacOS."
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unsupported operating system."
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Check if needed dependencies are installed and install if necessary
|
||||||
|
if ! command -v node >/dev/null || ! command -v git >/dev/null || ! command -v yarn >/dev/null; then
|
||||||
|
case "$(uname -s)" in
|
||||||
|
Linux)
|
||||||
|
if [[ "$(cat /etc/*-release | grep '^ID=')" = "ID=\"ubuntu\"" ]]; then
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get -y install nodejs git yarn
|
||||||
|
elif [[ "$(cat /etc/*-release | grep '^ID=')" = "ID=\"centos\"" ]]; then
|
||||||
|
sudo yum -y install epel-release
|
||||||
|
sudo yum -y install nodejs git yarn
|
||||||
|
elif [[ "$(cat /etc/*-release | grep '^ID=')" = "ID=\"arch\"" ]]; then
|
||||||
|
sudo pacman -Syu -y
|
||||||
|
sudo pacman -S -y nodejs git yarn
|
||||||
|
else
|
||||||
|
echo "Unsupported Linux distribution"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
Darwin)
|
||||||
|
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
|
||||||
|
brew install node git yarn
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Clone the repository and install dependencies
|
||||||
|
git clone https://github.com/Yidadaa/ChatGPT-Next-Web
|
||||||
|
cd ChatGPT-Next-Web
|
||||||
|
yarn install
|
||||||
|
|
||||||
|
# Prompt user for environment variables
|
||||||
|
read -p "Enter OPENAI_API_KEY: " OPENAI_API_KEY
|
||||||
|
read -p "Enter CODE: " CODE
|
||||||
|
read -p "Enter PORT: " PORT
|
||||||
|
|
||||||
|
# Build and run the project using the environment variables
|
||||||
|
OPENAI_API_KEY=$OPENAI_API_KEY CODE=$CODE PORT=$PORT yarn build && OPENAI_API_KEY=$OPENAI_API_KEY CODE=$CODE PORT=$PORT yarn start
|
Reference in New Issue
Block a user