diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index a7a29644d..8ac96f193 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -43,7 +43,7 @@ jobs: uses: docker/build-push-action@v4 with: context: . - platforms: linux/amd64 + platforms: linux/amd64,linux/arm64 push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} diff --git a/Dockerfile b/Dockerfile index 018396ef3..7ed7bc155 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,7 +17,6 @@ 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 @@ -46,7 +45,7 @@ CMD if [ -n "$PROXY_URL" ]; then \ host=$(echo $PROXY_URL | cut -d/ -f3 | cut -d: -f1); \ port=$(echo $PROXY_URL | cut -d: -f3); \ conf=/etc/proxychains.conf; \ - echo "strict_chain" >> $conf; \ + echo "strict_chain" > $conf; \ echo "proxy_dns" >> $conf; \ echo "remote_dns_subnet 224" >> $conf; \ echo "tcp_read_time_out 15000" >> $conf; \ diff --git a/app/api/access.ts b/app/api/access.ts deleted file mode 100644 index d3e4c9cf9..000000000 --- a/app/api/access.ts +++ /dev/null @@ -1,17 +0,0 @@ -import md5 from "spark-md5"; - -export function getAccessCodes(): Set { - const code = process.env.CODE; - - try { - const codes = (code?.split(",") ?? []) - .filter((v) => !!v) - .map((v) => md5.hash(v.trim())); - return new Set(codes); - } catch (e) { - return new Set(); - } -} - -export const ACCESS_CODES = getAccessCodes(); -export const IS_IN_DOCKER = process.env.DOCKER; diff --git a/app/api/chat-stream/route.ts b/app/api/chat-stream/route.ts index 526623ce1..41f135495 100644 --- a/app/api/chat-stream/route.ts +++ b/app/api/chat-stream/route.ts @@ -40,7 +40,7 @@ async function createStream(req: NextRequest) { const parser = createParser(onParse); for await (const chunk of res.body as any) { - parser.feed(decoder.decode(chunk)); + parser.feed(decoder.decode(chunk, { stream: true })); } }, }); diff --git a/app/api/config/route.ts b/app/api/config/route.ts new file mode 100644 index 000000000..e04e22a0c --- /dev/null +++ b/app/api/config/route.ts @@ -0,0 +1,21 @@ +import { NextRequest, NextResponse } from "next/server"; + +import { getServerSideConfig } from "../../config/server"; + +const serverConfig = getServerSideConfig(); + +// Danger! Don not write any secret value here! +// 警告!不要在这里写入任何敏感信息! +const DANGER_CONFIG = { + needCode: serverConfig.needCode, +}; + +declare global { + type DangerConfig = typeof DANGER_CONFIG; +} + +export async function POST(req: NextRequest) { + return NextResponse.json({ + needCode: serverConfig.needCode, + }); +} diff --git a/app/components/home.tsx b/app/components/home.tsx index 7e7af3d1b..5c8070267 100644 --- a/app/components/home.tsx +++ b/app/components/home.tsx @@ -2,13 +2,7 @@ require("../polyfill"); -import { - useState, - useEffect, - useRef, - useCallback, - MouseEventHandler, -} from "react"; +import { useState, useEffect, useRef } from "react"; import { IconButton } from "./button"; import styles from "./home.module.scss"; @@ -31,7 +25,6 @@ import { Chat } from "./chat"; import dynamic from "next/dynamic"; import { REPO_URL } from "../constant"; import { ErrorBoundary } from "./error"; -import { useDebounce } from "use-debounce"; import type { Prompt } from "../store/prompt"; diff --git a/app/components/settings.tsx b/app/components/settings.tsx index bbb28b46e..e418d4843 100644 --- a/app/components/settings.tsx +++ b/app/components/settings.tsx @@ -26,7 +26,7 @@ import { import { Avatar } from "./chat"; import Locale, { AllLangs, changeLang, getLang } from "../locales"; -import { getCurrentVersion, getEmojiUrl } from "../utils"; +import { getEmojiUrl } from "../utils"; import Link from "next/link"; import { UPDATE_URL } from "../constant"; import { SearchService, usePromptStore } from "../store/prompt"; @@ -88,13 +88,13 @@ export function Settings(props: { closeSettings: () => void }) { const updateStore = useUpdateStore(); const [checkingUpdate, setCheckingUpdate] = useState(false); - const currentId = getCurrentVersion(); - const remoteId = updateStore.remoteId; - const hasNewVersion = currentId !== remoteId; + const currentVersion = updateStore.version; + const remoteId = updateStore.remoteVersion; + const hasNewVersion = currentVersion !== remoteId; function checkUpdate(force = false) { setCheckingUpdate(true); - updateStore.getLatestCommitId(force).then(() => { + updateStore.getLatestVersion(force).then(() => { setCheckingUpdate(false); }); } @@ -224,7 +224,7 @@ export function Settings(props: { closeSettings: () => void }) { { + try { + const childProcess = require("child_process"); + return ( + childProcess + // .execSync("git describe --tags --abbrev=0") + .execSync("git rev-parse --short HEAD") + .toString() + .trim() + ); + } catch (e) { + console.error("[Build Config] No git or not from git repo."); + return "unknown"; + } +})(); + +export const getBuildConfig = () => { + if (typeof process === "undefined") { + throw Error( + "[Server Config] you are importing a nodejs-only module outside of nodejs", + ); + } + + return { + commitId: COMMIT_ID, + }; +}; diff --git a/app/config/server.ts b/app/config/server.ts new file mode 100644 index 000000000..798177e59 --- /dev/null +++ b/app/config/server.ts @@ -0,0 +1,42 @@ +import md5 from "spark-md5"; + +declare global { + namespace NodeJS { + interface ProcessEnv { + OPENAI_API_KEY?: string; + CODE?: string; + PROXY_URL?: string; + VERCEL?: string; + } + } +} + +const ACCESS_CODES = (function getAccessCodes(): Set { + const code = process.env.CODE; + + try { + const codes = (code?.split(",") ?? []) + .filter((v) => !!v) + .map((v) => md5.hash(v.trim())); + return new Set(codes); + } catch (e) { + return new Set(); + } +})(); + +export const getServerSideConfig = () => { + if (typeof process === "undefined") { + throw Error( + "[Server Config] you are importing a nodejs-only module outside of nodejs", + ); + } + + return { + apiKey: process.env.OPENAI_API_KEY, + code: process.env.CODE, + codes: ACCESS_CODES, + needCode: ACCESS_CODES.size > 0, + proxyUrl: process.env.PROXY_URL, + isVercel: !!process.env.VERCEL, + }; +}; diff --git a/app/constant.ts b/app/constant.ts index 8a519d44e..6f08ad756 100644 --- a/app/constant.ts +++ b/app/constant.ts @@ -5,3 +5,4 @@ export const ISSUE_URL = `https://github.com/${OWNER}/${REPO}/issues`; export const UPDATE_URL = `${REPO_URL}#keep-updated`; export const FETCH_COMMIT_URL = `https://api.github.com/repos/${OWNER}/${REPO}/commits?per_page=1`; export const FETCH_TAG_URL = `https://api.github.com/repos/${OWNER}/${REPO}/tags?per_page=1`; +export const RUNTIME_CONFIG_DOM = "danger-runtime-config"; diff --git a/app/layout.tsx b/app/layout.tsx index 49a6d644d..38748ef37 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -2,19 +2,9 @@ import "./styles/globals.scss"; import "./styles/markdown.scss"; import "./styles/highlight.scss"; -import process from "child_process"; -import { ACCESS_CODES, IS_IN_DOCKER } from "./api/access"; +import { getBuildConfig } from "./config/build"; -let COMMIT_ID: string | undefined; -try { - COMMIT_ID = process - // .execSync("git describe --tags --abbrev=0") - .execSync("git rev-parse --short HEAD") - .toString() - .trim(); -} catch (e) { - console.error("No git or not from git repo."); -} +const buildConfig = getBuildConfig(); export const metadata = { title: "ChatGPT Next Web", @@ -26,21 +16,6 @@ export const metadata = { themeColor: "#fafafa", }; -function Meta() { - const metas = { - version: COMMIT_ID ?? "unknown", - access: ACCESS_CODES.size > 0 || IS_IN_DOCKER ? "enabled" : "disabled", - }; - - return ( - <> - {Object.entries(metas).map(([k, v]) => ( - - ))} - - ); -} - export default function RootLayout({ children, }: { @@ -58,7 +33,7 @@ export default function RootLayout({ content="#151515" media="(prefers-color-scheme: dark)" /> - + diff --git a/app/locales/cn.ts b/app/locales/cn.ts index 9bd4b0a3f..d3df950b5 100644 --- a/app/locales/cn.ts +++ b/app/locales/cn.ts @@ -72,6 +72,7 @@ const cn = { tw: "繁體中文", es: "Español", it: "Italiano", + tr: "Türkçe", }, }, Avatar: "头像", diff --git a/app/locales/en.ts b/app/locales/en.ts index 731309034..6b63f21be 100644 --- a/app/locales/en.ts +++ b/app/locales/en.ts @@ -75,6 +75,7 @@ const en: LocaleType = { tw: "繁體中文", es: "Español", it: "Italiano", + tr: "Türkçe", }, }, Avatar: "Avatar", diff --git a/app/locales/es.ts b/app/locales/es.ts index 06277f6b5..eac504dd8 100644 --- a/app/locales/es.ts +++ b/app/locales/es.ts @@ -75,6 +75,7 @@ const es: LocaleType = { tw: "繁體中文", es: "Español", it: "Italiano", + tr: "Türkçe", }, }, Avatar: "Avatar", diff --git a/app/locales/index.ts b/app/locales/index.ts index 5c41eeb77..d7a1aefe5 100644 --- a/app/locales/index.ts +++ b/app/locales/index.ts @@ -3,10 +3,11 @@ import EN from "./en"; import TW from "./tw"; import ES from "./es"; import IT from "./it"; +import TR from "./tr"; export type { LocaleType } from "./cn"; -export const AllLangs = ["en", "cn", "tw", "es", "it"] as const; +export const AllLangs = ["en", "cn", "tw", "es", "it", "tr"] as const; type Lang = (typeof AllLangs)[number]; const LANG_KEY = "lang"; @@ -50,6 +51,8 @@ export function getLang(): Lang { return "es"; } else if (lang.includes("it")) { return "it"; + } else if (lang.includes("tr")) { + return "tr"; } else { return "en"; } @@ -60,4 +63,4 @@ export function changeLang(lang: Lang) { location.reload(); } -export default { en: EN, cn: CN, tw: TW, es: ES, it: IT }[getLang()]; +export default { en: EN, cn: CN, tw: TW, es: ES, it: IT, tr: TR }[getLang()]; diff --git a/app/locales/it.ts b/app/locales/it.ts index 70967d966..3c11e708d 100644 --- a/app/locales/it.ts +++ b/app/locales/it.ts @@ -75,6 +75,7 @@ const it: LocaleType = { tw: "繁體中文", es: "Español", it: "Italiano", + tr: "Türkçe", }, }, Avatar: "Avatar", diff --git a/app/locales/tr.ts b/app/locales/tr.ts new file mode 100644 index 000000000..ddb74ddd0 --- /dev/null +++ b/app/locales/tr.ts @@ -0,0 +1,180 @@ +import { SubmitKey } from "../store/app"; +import type { LocaleType } from "./index"; + +const tr: LocaleType = { + WIP: "Çalışma devam ediyor...", + Error: { + Unauthorized: + "Yetkisiz erişim, lütfen erişim kodunu ayarlar sayfasından giriniz.", + }, + ChatItem: { + ChatItemCount: (count: number) => `${count} mesaj`, + }, + Chat: { + SubTitle: (count: number) => `ChatGPT tarafından ${count} mesaj`, + Actions: { + ChatList: "Sohbet Listesine Git", + CompressedHistory: "Sıkıştırılmış Geçmiş Bellek Komutu", + Export: "Tüm Mesajları Markdown Olarak Dışa Aktar", + Copy: "Kopyala", + Stop: "Durdur", + Retry: "Tekrar Dene", + }, + Rename: "Sohbeti Yeniden Adlandır", + Typing: "Yazıyor…", + Input: (submitKey: string) => { + var inputHints = `Göndermek için ${submitKey}`; + if (submitKey === String(SubmitKey.Enter)) { + inputHints += ", kaydırmak için Shift + Enter"; + } + return inputHints + ", komutları aramak için / (eğik çizgi)"; + }, + Send: "Gönder", + }, + Export: { + Title: "Tüm Mesajlar", + Copy: "Tümünü Kopyala", + Download: "İndir", + MessageFromYou: "Sizin Mesajınız", + MessageFromChatGPT: "ChatGPT'nin Mesajı", + }, + Memory: { + Title: "Bellek Komutları", + EmptyContent: "Henüz değil.", + Send: "Belleği Gönder", + Copy: "Belleği Kopyala", + Reset: "Oturumu Sıfırla", + ResetConfirm: + "Sıfırlama, geçerli görüşme geçmişini ve geçmiş belleği siler. Sıfırlamak istediğinizden emin misiniz?", + }, + Home: { + NewChat: "Yeni Sohbet", + DeleteChat: "Seçili sohbeti silmeyi onaylıyor musunuz?", + DeleteToast: "Sohbet Silindi", + Revert: "Geri Al", + }, + Settings: { + Title: "Ayarlar", + SubTitle: "Tüm Ayarlar", + Actions: { + ClearAll: "Tüm Verileri Temizle", + ResetAll: "Tüm Ayarları Sıfırla", + Close: "Kapat", + ConfirmResetAll: { + Confirm: "Tüm ayarları sıfırlamak istediğinizden emin misiniz?", + }, + ConfirmClearAll: { + Confirm: "Tüm sohbeti sıfırlamak istediğinizden emin misiniz?", + }, + }, + Lang: { + Name: "Language", // ATTENTION: if you wanna add a new translation, please do not translate this value, leave it as `Language` + Options: { + cn: "简体中文", + en: "English", + tw: "繁體中文", + es: "Español", + it: "Italiano", + tr: "Türkçe", + }, + }, + Avatar: "Avatar", + FontSize: { + Title: "Yazı Boyutu", + SubTitle: "Sohbet içeriğinin yazı boyutunu ayarlayın", + }, + Update: { + Version: (x: string) => `Sürüm: ${x}`, + IsLatest: "En son sürüm", + CheckUpdate: "Güncellemeyi Kontrol Et", + IsChecking: "Güncelleme kontrol ediliyor...", + FoundUpdate: (x: string) => `Yeni sürüm bulundu: ${x}`, + GoToUpdate: "Güncelle", + }, + SendKey: "Gönder Tuşu", + Theme: "Tema", + TightBorder: "Tam Ekran", + SendPreviewBubble: "Mesaj Önizleme Balonu", + Prompt: { + Disable: { + Title: "Otomatik tamamlamayı devre dışı bırak", + SubTitle: "Otomatik tamamlamayı kullanmak için / (eğik çizgi) girin", + }, + List: "Komut Listesi", + ListCount: (builtin: number, custom: number) => + `${builtin} yerleşik, ${custom} kullanıcı tanımlı`, + Edit: "Düzenle", + }, + HistoryCount: { + Title: "Ekli Mesaj Sayısı", + SubTitle: "İstek başına ekli gönderilen mesaj sayısı", + }, + CompressThreshold: { + Title: "Geçmiş Sıkıştırma Eşiği", + SubTitle: + "Sıkıştırılmamış mesajların uzunluğu bu değeri aşarsa sıkıştırılır", + }, + Token: { + Title: "API Anahtarı", + SubTitle: "Erişim kodu sınırını yoksaymak için anahtarınızı kullanın", + Placeholder: "OpenAI API Anahtarı", + }, + Usage: { + Title: "Hesap Bakiyesi", + SubTitle(used: any, total: any) { + return `Bu ay kullanılan $${used}, abonelik $${total}`; + }, + IsChecking: "Kontrol ediliyor...", + Check: "Tekrar Kontrol Et", + NoAccess: "Bakiyeyi kontrol etmek için API anahtarını girin", + }, + AccessCode: { + Title: "Erişim Kodu", + SubTitle: "Erişim kontrolü etkinleştirme", + Placeholder: "Erişim Kodu Gerekiyor", + }, + Model: "Model", + Temperature: { + Title: "Gerçeklik", + SubTitle: + "Daha büyük bir değer girildiğinde gerçeklik oranı düşer ve daha rastgele çıktılar üretir", + }, + MaxTokens: { + Title: "Maksimum Belirteç", + SubTitle: + "Girdi belirteçlerinin ve oluşturulan belirteçlerin maksimum uzunluğu", + }, + PresencePenlty: { + Title: "Varlık Cezası", + SubTitle: + "Daha büyük bir değer, yeni konular hakkında konuşma olasılığını artırır", + }, + }, + Store: { + DefaultTopic: "Yeni Konuşma", + BotHello: "Merhaba! Size bugün nasıl yardımcı olabilirim?", + Error: "Bir şeyler yanlış gitti. Lütfen daha sonra tekrar deneyiniz.", + Prompt: { + History: (content: string) => + "Bu, yapay zeka ile kullanıcı arasındaki sohbet geçmişinin bir özetidir: " + + content, + Topic: + "Lütfen herhangi bir giriş, noktalama işareti, tırnak işareti, nokta, sembol veya ek metin olmadan konuşmamızı özetleyen dört ila beş kelimelik bir başlık oluşturun. Çevreleyen tırnak işaretlerini kaldırın.", + Summarize: + "Gelecekteki bağlam için bir bilgi istemi olarak kullanmak üzere tartışmamızı en fazla 200 kelimeyle özetleyin.", + }, + ConfirmClearAll: + "Tüm sohbet ve ayar verilerini temizlemeyi onaylıyor musunuz?", + }, + Copy: { + Success: "Panoya kopyalandı", + Failed: "Kopyalama başarısız oldu, lütfen panoya erişim izni verin", + }, + Context: { + Toast: (x: any) => `${x} bağlamsal bellek komutu`, + Edit: "Bağlamsal ve Bellek Komutları", + Add: "Yeni Ekle", + }, +}; + +export default tr; diff --git a/app/locales/tw.ts b/app/locales/tw.ts index 3861a671c..89924b726 100644 --- a/app/locales/tw.ts +++ b/app/locales/tw.ts @@ -73,6 +73,7 @@ const tw: LocaleType = { tw: "繁體中文", es: "Español", it: "Italiano", + tr: "Türkçe", }, }, Avatar: "大頭貼", diff --git a/app/page.tsx b/app/page.tsx index 1d1da2227..20b503174 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -2,11 +2,15 @@ import { Analytics } from "@vercel/analytics/react"; import { Home } from "./components/home"; -export default function App() { +import { getServerSideConfig } from "./config/server"; + +const serverConfig = getServerSideConfig(); + +export default async function App() { return ( <> - + {serverConfig?.isVercel && } ); } diff --git a/app/requests.ts b/app/requests.ts index d7d8e4184..4d24d4986 100644 --- a/app/requests.ts +++ b/app/requests.ts @@ -175,7 +175,7 @@ export async function requestChatStream( const resTimeoutId = setTimeout(() => finish(), TIME_OUT_MS); const content = await reader?.read(); clearTimeout(resTimeoutId); - const text = decoder.decode(content?.value); + const text = decoder.decode(content?.value, { stream: true }); responseText += text; const done = !content || content.done; diff --git a/app/store/access.ts b/app/store/access.ts index ac036d7df..aed131684 100644 --- a/app/store/access.ts +++ b/app/store/access.ts @@ -1,26 +1,33 @@ import { create } from "zustand"; import { persist } from "zustand/middleware"; -import { queryMeta } from "../utils"; export interface AccessControlStore { accessCode: string; token: string; + needCode: boolean; + updateToken: (_: string) => void; updateCode: (_: string) => void; enabledAccessControl: () => boolean; isAuthorized: () => boolean; + fetch: () => void; } export const ACCESS_KEY = "access-control"; +let fetchState = 0; // 0 not fetch, 1 fetching, 2 done + export const useAccessStore = create()( persist( (set, get) => ({ token: "", accessCode: "", + needCode: true, enabledAccessControl() { - return queryMeta("access") === "enabled"; + get().fetch(); + + return get().needCode; }, updateCode(code: string) { set((state) => ({ accessCode: code })); @@ -34,6 +41,25 @@ export const useAccessStore = create()( !!get().token || !!get().accessCode || !get().enabledAccessControl() ); }, + fetch() { + if (fetchState > 0) return; + fetchState = 1; + fetch("/api/config", { + method: "post", + body: null, + }) + .then((res) => res.json()) + .then((res: DangerConfig) => { + console.log("[Config] got config from server", res); + set(() => ({ ...res })); + }) + .catch(() => { + console.error("[Config] failed to fetch config"); + }) + .finally(() => { + fetchState = 2; + }); + }, }), { name: ACCESS_KEY, diff --git a/app/store/update.ts b/app/store/update.ts index 97fb343c3..efcdc8a7b 100644 --- a/app/store/update.ts +++ b/app/store/update.ts @@ -1,28 +1,46 @@ import { create } from "zustand"; import { persist } from "zustand/middleware"; import { FETCH_COMMIT_URL, FETCH_TAG_URL } from "../constant"; -import { getCurrentVersion } from "../utils"; export interface UpdateStore { lastUpdate: number; - remoteId: string; + remoteVersion: string; - getLatestCommitId: (force: boolean) => Promise; + version: string; + getLatestVersion: (force: boolean) => Promise; } export const UPDATE_KEY = "chat-update"; +function queryMeta(key: string, defaultValue?: string): string { + let ret: string; + if (document) { + const meta = document.head.querySelector( + `meta[name='${key}']`, + ) as HTMLMetaElement; + ret = meta?.content ?? ""; + } else { + ret = defaultValue ?? ""; + } + + return ret; +} + export const useUpdateStore = create()( persist( (set, get) => ({ lastUpdate: 0, - remoteId: "", + remoteVersion: "", + + version: "unknown", + + async getLatestVersion(force = false) { + set(() => ({ version: queryMeta("version") })); - async getLatestCommitId(force = false) { const overTenMins = Date.now() - get().lastUpdate > 10 * 60 * 1000; const shouldFetch = force || overTenMins; if (!shouldFetch) { - return getCurrentVersion(); + return get().version ?? "unknown"; } try { @@ -32,13 +50,13 @@ export const useUpdateStore = create()( const remoteId = (data[0].sha as string).substring(0, 7); set(() => ({ lastUpdate: Date.now(), - remoteId, + remoteVersion: remoteId, })); console.log("[Got Upstream] ", remoteId); return remoteId; } catch (error) { console.error("[Fetch Upstream Commit Id]", error); - return getCurrentVersion(); + return get().version ?? ""; } }, }), diff --git a/app/utils.ts b/app/utils.ts index 9a792fd52..5c2b06975 100644 --- a/app/utils.ts +++ b/app/utils.ts @@ -69,31 +69,6 @@ export function selectOrCopy(el: HTMLElement, content: string) { return true; } -export function queryMeta(key: string, defaultValue?: string): string { - let ret: string; - if (document) { - const meta = document.head.querySelector( - `meta[name='${key}']`, - ) as HTMLMetaElement; - ret = meta?.content ?? ""; - } else { - ret = defaultValue ?? ""; - } - - return ret; -} - -let currentId: string; -export function getCurrentVersion() { - if (currentId) { - return currentId; - } - - currentId = queryMeta("version"); - - return currentId; -} - export function getEmojiUrl(unified: string, style: EmojiStyle) { return `https://cdn.staticfile.org/emoji-datasource-apple/14.0.0/img/${style}/64/${unified}.png`; } diff --git a/middleware.ts b/middleware.ts index 9338a2c6b..c2e077706 100644 --- a/middleware.ts +++ b/middleware.ts @@ -1,21 +1,23 @@ import { NextRequest, NextResponse } from "next/server"; -import { ACCESS_CODES } from "./app/api/access"; +import { getServerSideConfig } from "./app/config/server"; import md5 from "spark-md5"; export const config = { matcher: ["/api/openai", "/api/chat-stream"], }; +const serverConfig = getServerSideConfig(); + export function middleware(req: NextRequest) { const accessCode = req.headers.get("access-code"); const token = req.headers.get("token"); const hashedCode = md5.hash(accessCode ?? "").trim(); - console.log("[Auth] allowed hashed codes: ", [...ACCESS_CODES]); + console.log("[Auth] allowed hashed codes: ", [...serverConfig.codes]); console.log("[Auth] got access code:", accessCode); console.log("[Auth] hashed access code:", hashedCode); - if (ACCESS_CODES.size > 0 && !ACCESS_CODES.has(hashedCode) && !token) { + if (serverConfig.needCode && !serverConfig.codes.has(hashedCode) && !token) { return NextResponse.json( { error: true, @@ -30,7 +32,7 @@ export function middleware(req: NextRequest) { // inject api key if (!token) { - const apiKey = process.env.OPENAI_API_KEY; + const apiKey = serverConfig.apiKey; if (apiKey) { console.log("[Auth] set system token"); req.headers.set("token", apiKey); diff --git a/next.config.js b/next.config.js index fc164db9c..f7d5ff086 100644 --- a/next.config.js +++ b/next.config.js @@ -8,14 +8,11 @@ const nextConfig = { config.module.rules.push({ test: /\.svg$/, use: ["@svgr/webpack"], - }); // 针对 SVG 的处理规则 + }); return config; - } + }, + output: "standalone", }; -if (process.env.DOCKER) { - nextConfig.output = 'standalone' -} - module.exports = nextConfig;