This commit is contained in:
GH Action - Upstream Sync 2023-05-05 00:54:47 +00:00
commit 96c0a5c911
12 changed files with 64 additions and 16 deletions

View File

@ -8,7 +8,7 @@ WORKDIR /app
COPY package.json yarn.lock ./ COPY package.json yarn.lock ./
RUN yarn config set registry 'https://registry.npm.taobao.org' RUN yarn config set registry 'https://registry.npmmirror.com/'
RUN yarn install RUN yarn install
FROM base AS builder FROM base AS builder

View File

@ -9,9 +9,9 @@ One-Click to deploy well-designed ChatGPT web UI on Vercel.
一键免费部署你的私人 ChatGPT 网页应用。 一键免费部署你的私人 ChatGPT 网页应用。
[Demo](https://chat-gpt-next-web.vercel.app/) / [Issues](https://github.com/Yidadaa/ChatGPT-Next-Web/issues) / [Join Discord](https://discord.gg/zrhvHCr79N) / [Buy Me a Coffee](https://www.buymeacoffee.com/yidadaa) [Demo](https://chatgpt.nextweb.fun/) / [Issues](https://github.com/Yidadaa/ChatGPT-Next-Web/issues) / [Join Discord](https://discord.gg/zrhvHCr79N) / [Buy Me a Coffee](https://www.buymeacoffee.com/yidadaa)
[演示](https://chat-gpt-next-web.vercel.app/) / [反馈](https://github.com/Yidadaa/ChatGPT-Next-Web/issues) / [QQ 群](https://user-images.githubusercontent.com/16968934/234462588-e8eff256-f5ca-46ef-8f5f-d7db6d28735a.jpg) / [打赏开发者](https://user-images.githubusercontent.com/16968934/227772541-5bcd52d8-61b7-488c-a203-0330d8006e2b.jpg) [演示](https://chatgpt.nextweb.fun/) / [反馈](https://github.com/Yidadaa/ChatGPT-Next-Web/issues) / [QQ 群](https://user-images.githubusercontent.com/16968934/234462588-e8eff256-f5ca-46ef-8f5f-d7db6d28735a.jpg) / [打赏开发者](https://user-images.githubusercontent.com/16968934/227772541-5bcd52d8-61b7-488c-a203-0330d8006e2b.jpg)
[![Deploy with Vercel](https://vercel.com/button)](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) [![Deploy with Vercel](https://vercel.com/button)](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)

View File

@ -1,6 +1,7 @@
import { NextRequest } from "next/server"; import { NextRequest } from "next/server";
import { getServerSideConfig } from "../config/server"; import { getServerSideConfig } from "../config/server";
import md5 from "spark-md5"; import md5 from "spark-md5";
import { ACCESS_CODE_PREFIX } from "../constant";
const serverConfig = getServerSideConfig(); const serverConfig = getServerSideConfig();
@ -17,10 +18,10 @@ function getIP(req: NextRequest) {
function parseApiKey(bearToken: string) { function parseApiKey(bearToken: string) {
const token = bearToken.trim().replaceAll("Bearer ", "").trim(); const token = bearToken.trim().replaceAll("Bearer ", "").trim();
const isOpenAiKey = token.startsWith("sk-"); const isOpenAiKey = !token.startsWith(ACCESS_CODE_PREFIX);
return { return {
accessCode: isOpenAiKey ? "" : token, accessCode: isOpenAiKey ? "" : token.slice(ACCESS_CODE_PREFIX.length),
apiKey: isOpenAiKey ? token : "", apiKey: isOpenAiKey ? token : "",
}; };
} }

View File

@ -15,8 +15,11 @@ declare global {
type DangerConfig = typeof DANGER_CONFIG; type DangerConfig = typeof DANGER_CONFIG;
} }
export async function POST() { async function handle() {
return NextResponse.json(DANGER_CONFIG); return NextResponse.json(DANGER_CONFIG);
} }
export const GET = handle;
export const POST = handle;
export const runtime = "edge"; export const runtime = "edge";

View File

@ -480,7 +480,7 @@ export function Chat() {
// submit user input // submit user input
const onUserSubmit = () => { const onUserSubmit = () => {
if (userInput.length <= 0) return; if (userInput.trim() === "") return;
setIsLoading(true); setIsLoading(true);
chatStore.onUserInput(userInput).then(() => setIsLoading(false)); chatStore.onUserInput(userInput).then(() => setIsLoading(false));
setBeforeInput(userInput); setBeforeInput(userInput);

View File

@ -21,7 +21,7 @@ import { useNavigate } from "react-router-dom";
import chatStyle from "./chat.module.scss"; import chatStyle from "./chat.module.scss";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { downloadAs } from "../utils"; import { downloadAs, readFromFile } from "../utils";
import { Updater } from "../api/openai/typing"; import { Updater } from "../api/openai/typing";
import { ModelConfigList } from "./model-config"; import { ModelConfigList } from "./model-config";
import { FileName, Path } from "../constant"; import { FileName, Path } from "../constant";
@ -222,6 +222,21 @@ export function MaskPage() {
downloadAs(JSON.stringify(masks), FileName.Masks); downloadAs(JSON.stringify(masks), FileName.Masks);
}; };
const importFromFile = () => {
readFromFile().then((content) => {
try {
const importMasks = JSON.parse(content);
if (Array.isArray(importMasks)) {
for (const mask of importMasks) {
if (mask.name) {
maskStore.create(mask);
}
}
}
} catch {}
});
};
return ( return (
<ErrorBoundary> <ErrorBoundary>
<div className={styles["mask-page"]}> <div className={styles["mask-page"]}>
@ -247,7 +262,7 @@ export function MaskPage() {
<IconButton <IconButton
icon={<UploadIcon />} icon={<UploadIcon />}
bordered bordered
onClick={() => showToast(Locale.WIP)} onClick={() => importFromFile()}
/> />
</div> </div>
<div className="window-action-button"> <div className="window-action-button">
@ -371,7 +386,10 @@ export function MaskPage() {
key="export" key="export"
bordered bordered
onClick={() => onClick={() =>
downloadAs(JSON.stringify(editingMask), "mask.json") downloadAs(
JSON.stringify(editingMask),
`${editingMask.name}.json`,
)
} }
/>, />,
<IconButton <IconButton

View File

@ -36,3 +36,5 @@ export enum StoreKey {
export const MAX_SIDEBAR_WIDTH = 500; export const MAX_SIDEBAR_WIDTH = 500;
export const MIN_SIDEBAR_WIDTH = 230; export const MIN_SIDEBAR_WIDTH = 230;
export const NARROW_SIDEBAR_WIDTH = 100; export const NARROW_SIDEBAR_WIDTH = 100;
export const ACCESS_CODE_PREFIX = "ak-";

View File

@ -8,6 +8,7 @@ import {
useChatStore, useChatStore,
} from "./store"; } from "./store";
import { showToast } from "./components/ui-lib"; import { showToast } from "./components/ui-lib";
import { ACCESS_CODE_PREFIX } from "./constant";
const TIME_OUT_MS = 60000; const TIME_OUT_MS = 60000;
@ -44,9 +45,7 @@ const makeRequestParam = (
function getHeaders() { function getHeaders() {
const accessStore = useAccessStore.getState(); const accessStore = useAccessStore.getState();
const headers = { let headers: Record<string, string> = {};
Authorization: "",
};
const makeBearer = (token: string) => `Bearer ${token.trim()}`; const makeBearer = (token: string) => `Bearer ${token.trim()}`;
const validString = (x: string) => x && x.length > 0; const validString = (x: string) => x && x.length > 0;
@ -58,7 +57,9 @@ function getHeaders() {
accessStore.enabledAccessControl() && accessStore.enabledAccessControl() &&
validString(accessStore.accessCode) validString(accessStore.accessCode)
) { ) {
headers.Authorization = makeBearer(accessStore.accessCode); headers.Authorization = makeBearer(
ACCESS_CODE_PREFIX + accessStore.accessCode,
);
} }
return headers; return headers;

View File

@ -57,6 +57,7 @@ export const useMaskStore = create<MaskStore>()(
...createEmptyMask(), ...createEmptyMask(),
...mask, ...mask,
id, id,
builtin: false,
}; };
set(() => ({ masks })); set(() => ({ masks }));

View File

@ -42,6 +42,26 @@ export function downloadAs(text: string, filename: string) {
document.body.removeChild(element); document.body.removeChild(element);
} }
export function readFromFile() {
return new Promise<string>((res, rej) => {
const fileInput = document.createElement("input");
fileInput.type = "file";
fileInput.accept = "application/json";
fileInput.onchange = (event: any) => {
const file = event.target.files[0];
const fileReader = new FileReader();
fileReader.onload = (e: any) => {
res(e.target.result);
};
fileReader.onerror = (e) => rej(e);
fileReader.readAsText(file);
};
fileInput.click();
});
}
export function isIOS() { export function isIOS() {
const userAgent = navigator.userAgent.toLowerCase(); const userAgent = navigator.userAgent.toLowerCase();
return /iphone|ipad|ipod/.test(userAgent); return /iphone|ipad|ipod/.test(userAgent);

View File

@ -16,7 +16,9 @@ const nextConfig = {
}); });
} }
return ret; return {
afterFiles: ret,
};
}, },
webpack(config) { webpack(config) {
config.module.rules.push({ config.module.rules.push({

View File

@ -40,7 +40,7 @@ async function fetchEN() {
return raw return raw
.split("\n") .split("\n")
.slice(1) .slice(1)
.map((v) => v.split('","').map((v) => v.replace('"', ""))); .map((v) => v.split('","').map((v) => v.replace(/^"|"$/g, '').replaceAll('""','"')));
} catch (error) { } catch (error) {
console.error("[Fetch] failed to fetch en prompts", error); console.error("[Fetch] failed to fetch en prompts", error);
return []; return [];