commit
0a60a87c9f
@ -1,3 +1,4 @@
|
||||
{
|
||||
"extends": "next/core-web-vitals"
|
||||
"extends": "next/core-web-vitals",
|
||||
"plugins": ["prettier"]
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
name: Upstream Sync
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 */12 * * *' # every 12 hours
|
||||
workflow_dispatch: # on button click
|
||||
|
||||
jobs:
|
||||
sync_latest_from_upstream:
|
||||
name: Sync latest commits from upstream repo
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
# Step 1: run a standard checkout action, provided by github
|
||||
- name: Checkout target repo
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Step 2: run the sync action
|
||||
- name: Sync upstream changes
|
||||
id: sync
|
||||
uses: aormsby/Fork-Sync-With-Upstream-action@v3.4
|
||||
with:
|
||||
upstream_sync_repo: Yidadaa/ChatGPT-Next-Web
|
||||
upstream_sync_branch: main
|
||||
target_sync_branch: main
|
||||
target_repo_token: ${{ secrets.GITHUB_TOKEN }} # automatically generated, no need to set
|
||||
|
||||
# Set test_mode true to run tests instead of the true action!!
|
||||
test_mode: false
|
@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
npx lint-staged
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"./app/**/*.{js,ts,jsx,tsx,json,html,css,md}": [
|
||||
"eslint --fix",
|
||||
"prettier --write"
|
||||
]
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
module.exports = {
|
||||
printWidth: 80,
|
||||
tabWidth: 2,
|
||||
useTabs: false,
|
||||
semi: true,
|
||||
singleQuote: false,
|
||||
trailingComma: 'all',
|
||||
bracketSpacing: true,
|
||||
arrowParens: 'always',
|
||||
};
|
@ -1 +0,0 @@
|
||||
config.ts
|
@ -1,29 +0,0 @@
|
||||
import { OpenAIApi, Configuration } from "openai";
|
||||
import { ChatRequest } from "./typing";
|
||||
|
||||
export async function POST(req: Request) {
|
||||
try {
|
||||
let apiKey = process.env.OPENAI_API_KEY;
|
||||
|
||||
const userApiKey = req.headers.get("token");
|
||||
if (userApiKey) {
|
||||
apiKey = userApiKey;
|
||||
}
|
||||
|
||||
const openai = new OpenAIApi(
|
||||
new Configuration({
|
||||
apiKey,
|
||||
})
|
||||
);
|
||||
|
||||
const requestBody = (await req.json()) as ChatRequest;
|
||||
const completion = await openai!.createChatCompletion({
|
||||
...requestBody,
|
||||
});
|
||||
|
||||
return new Response(JSON.stringify(completion.data));
|
||||
} catch (e) {
|
||||
console.error("[Chat] ", e);
|
||||
return new Response(JSON.stringify(e));
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
import { NextRequest } from "next/server";
|
||||
|
||||
const OPENAI_URL = "api.openai.com";
|
||||
const DEFAULT_PROTOCOL = "https";
|
||||
const PROTOCOL = process.env.PROTOCOL ?? DEFAULT_PROTOCOL;
|
||||
const BASE_URL = process.env.BASE_URL ?? OPENAI_URL;
|
||||
|
||||
export async function requestOpenai(req: NextRequest) {
|
||||
const apiKey = req.headers.get("token");
|
||||
const openaiPath = req.headers.get("path");
|
||||
|
||||
console.log("[Proxy] ", openaiPath);
|
||||
|
||||
return fetch(`${PROTOCOL}://${BASE_URL}/${openaiPath}`, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
},
|
||||
method: req.method,
|
||||
body: req.body,
|
||||
});
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { requestOpenai } from "../common";
|
||||
|
||||
async function makeRequest(req: NextRequest) {
|
||||
try {
|
||||
const api = await requestOpenai(req);
|
||||
const res = new NextResponse(api.body);
|
||||
res.headers.set("Content-Type", "application/json");
|
||||
return res;
|
||||
} catch (e) {
|
||||
console.error("[OpenAI] ", req.body, e);
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: true,
|
||||
msg: JSON.stringify(e),
|
||||
},
|
||||
{
|
||||
status: 500,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
return makeRequest(req);
|
||||
}
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
return makeRequest(req);
|
||||
}
|
After Width: | Height: | Size: 1.6 KiB |
@ -0,0 +1,156 @@
|
||||
import { SubmitKey } from "../store/app";
|
||||
import type { LocaleType } from "./index";
|
||||
|
||||
const es: LocaleType = {
|
||||
WIP: "En construcción...",
|
||||
Error: {
|
||||
Unauthorized:
|
||||
"Acceso no autorizado, por favor ingrese el código de acceso en la página de configuración.",
|
||||
},
|
||||
ChatItem: {
|
||||
ChatItemCount: (count: number) => `${count} mensajes`,
|
||||
},
|
||||
Chat: {
|
||||
SubTitle: (count: number) => `${count} mensajes con ChatGPT`,
|
||||
Actions: {
|
||||
ChatList: "Ir a la lista de chats",
|
||||
CompressedHistory: "Historial de memoria comprimido",
|
||||
Export: "Exportar todos los mensajes como Markdown",
|
||||
Copy: "Copiar",
|
||||
Stop: "Detener",
|
||||
Retry: "Reintentar",
|
||||
},
|
||||
Rename: "Renombrar chat",
|
||||
Typing: "Escribiendo...",
|
||||
Input: (submitKey: string) => {
|
||||
var inputHints = `Escribe algo y presiona ${submitKey} para enviar`;
|
||||
if (submitKey === String(SubmitKey.Enter)) {
|
||||
inputHints += ", presiona Shift + Enter para nueva línea";
|
||||
}
|
||||
return inputHints;
|
||||
},
|
||||
Send: "Enviar",
|
||||
},
|
||||
Export: {
|
||||
Title: "Todos los mensajes",
|
||||
Copy: "Copiar todo",
|
||||
Download: "Descargar",
|
||||
},
|
||||
Memory: {
|
||||
Title: "Historial de memoria",
|
||||
EmptyContent: "Aún no hay nada.",
|
||||
Copy: "Copiar todo",
|
||||
},
|
||||
Home: {
|
||||
NewChat: "Nuevo chat",
|
||||
DeleteChat: "¿Confirmar eliminación de la conversación seleccionada?",
|
||||
},
|
||||
Settings: {
|
||||
Title: "Configuración",
|
||||
SubTitle: "Todas las configuraciones",
|
||||
Actions: {
|
||||
ClearAll: "Borrar todos los datos",
|
||||
ResetAll: "Restablecer todas las configuraciones",
|
||||
Close: "Cerrar",
|
||||
},
|
||||
Lang: {
|
||||
Name: "Language",
|
||||
Options: {
|
||||
cn: "简体中文",
|
||||
en: "Inglés",
|
||||
tw: "繁體中文",
|
||||
es: "Español",
|
||||
},
|
||||
},
|
||||
Avatar: "Avatar",
|
||||
FontSize: {
|
||||
Title: "Tamaño de fuente",
|
||||
SubTitle: "Ajustar el tamaño de fuente del contenido del chat",
|
||||
},
|
||||
Update: {
|
||||
Version: (x: string) => `Versión: ${x}`,
|
||||
IsLatest: "Última versión",
|
||||
CheckUpdate: "Buscar actualizaciones",
|
||||
IsChecking: "Buscando actualizaciones...",
|
||||
FoundUpdate: (x: string) => `Se encontró una nueva versión: ${x}`,
|
||||
GoToUpdate: "Actualizar",
|
||||
},
|
||||
SendKey: "Tecla de envío",
|
||||
Theme: "Tema",
|
||||
TightBorder: "Borde ajustado",
|
||||
Prompt: {
|
||||
Disable: {
|
||||
Title: "Desactivar autocompletado",
|
||||
SubTitle: "Escribe / para activar el autocompletado",
|
||||
},
|
||||
List: "Lista de autocompletado",
|
||||
ListCount: (builtin: number, custom: number) =>
|
||||
`${builtin} incorporado, ${custom} definido por el usuario`,
|
||||
Edit: "Editar",
|
||||
},
|
||||
HistoryCount: {
|
||||
Title: "Cantidad de mensajes adjuntos",
|
||||
SubTitle: "Número de mensajes enviados adjuntos por solicitud",
|
||||
},
|
||||
CompressThreshold: {
|
||||
Title: "Umbral de compresión de historial",
|
||||
SubTitle:
|
||||
"Se comprimirán los mensajes si la longitud de los mensajes no comprimidos supera el valor",
|
||||
},
|
||||
Token: {
|
||||
Title: "Clave de API",
|
||||
SubTitle: "Utiliza tu clave para ignorar el límite de código de acceso",
|
||||
Placeholder: "Clave de la API de OpenAI",
|
||||
},
|
||||
Usage: {
|
||||
Title: "Saldo de la cuenta",
|
||||
SubTitle(granted: any, used: any) {
|
||||
return `Total $${granted}, Usado $${used}`;
|
||||
},
|
||||
IsChecking: "Comprobando...",
|
||||
Check: "Comprobar de nuevo",
|
||||
},
|
||||
AccessCode: {
|
||||
Title: "Código de acceso",
|
||||
SubTitle: "Control de acceso habilitado",
|
||||
Placeholder: "Necesita código de acceso",
|
||||
},
|
||||
Model: "Modelo",
|
||||
Temperature: {
|
||||
Title: "Temperatura",
|
||||
SubTitle: "Un valor mayor genera una salida más aleatoria",
|
||||
},
|
||||
MaxTokens: {
|
||||
Title: "Máximo de tokens",
|
||||
SubTitle: "Longitud máxima de tokens de entrada y tokens generados",
|
||||
},
|
||||
PresencePenlty: {
|
||||
Title: "Penalización de presencia",
|
||||
SubTitle:
|
||||
"Un valor mayor aumenta la probabilidad de hablar sobre nuevos temas",
|
||||
},
|
||||
},
|
||||
Store: {
|
||||
DefaultTopic: "Nueva conversación",
|
||||
BotHello: "¡Hola! ¿Cómo puedo ayudarte hoy?",
|
||||
Error: "Algo salió mal, por favor intenta nuevamente más tarde.",
|
||||
Prompt: {
|
||||
History: (content: string) =>
|
||||
"Este es un resumen del historial del chat entre la IA y el usuario como recapitulación: " +
|
||||
content,
|
||||
Topic:
|
||||
"Por favor, genera un título de cuatro a cinco palabras que resuma nuestra conversación sin ningún inicio, puntuación, comillas, puntos, símbolos o texto adicional. Elimina las comillas que lo envuelven.",
|
||||
Summarize:
|
||||
"Resuma nuestra discusión brevemente en 50 caracteres o menos para usarlo como un recordatorio para futuros contextos.",
|
||||
},
|
||||
ConfirmClearAll:
|
||||
"¿Confirmar para borrar todos los datos de chat y configuración?",
|
||||
},
|
||||
Copy: {
|
||||
Success: "Copiado al portapapeles",
|
||||
Failed:
|
||||
"La copia falló, por favor concede permiso para acceder al portapapeles",
|
||||
},
|
||||
};
|
||||
|
||||
export default es;
|
@ -1,53 +1,60 @@
|
||||
import CN from './cn'
|
||||
import EN from './en'
|
||||
import CN from "./cn";
|
||||
import EN from "./en";
|
||||
import TW from "./tw";
|
||||
import ES from "./es";
|
||||
|
||||
export type { LocaleType } from './cn'
|
||||
export type { LocaleType } from "./cn";
|
||||
|
||||
type Lang = 'en' | 'cn'
|
||||
export const AllLangs = ["en", "cn", "tw", "es"] as const;
|
||||
type Lang = (typeof AllLangs)[number];
|
||||
|
||||
const LANG_KEY = 'lang'
|
||||
const LANG_KEY = "lang";
|
||||
|
||||
function getItem(key: string) {
|
||||
try {
|
||||
return localStorage.getItem(key)
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
try {
|
||||
return localStorage.getItem(key);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function setItem(key: string, value: string) {
|
||||
try {
|
||||
localStorage.setItem(key, value)
|
||||
} catch { }
|
||||
try {
|
||||
localStorage.setItem(key, value);
|
||||
} catch {}
|
||||
}
|
||||
|
||||
function getLanguage() {
|
||||
try {
|
||||
return navigator.language.toLowerCase()
|
||||
} catch {
|
||||
return 'cn'
|
||||
}
|
||||
try {
|
||||
return navigator.language.toLowerCase();
|
||||
} catch {
|
||||
return "cn";
|
||||
}
|
||||
}
|
||||
|
||||
export function getLang(): Lang {
|
||||
const savedLang = getItem(LANG_KEY)
|
||||
|
||||
if (['en', 'cn'].includes(savedLang ?? '')) {
|
||||
return savedLang as Lang
|
||||
}
|
||||
|
||||
const lang = getLanguage()
|
||||
|
||||
if (lang.includes('zh') || lang.includes('cn')) {
|
||||
return 'cn'
|
||||
} else {
|
||||
return 'en'
|
||||
}
|
||||
const savedLang = getItem(LANG_KEY);
|
||||
|
||||
if (AllLangs.includes((savedLang ?? "") as Lang)) {
|
||||
return savedLang as Lang;
|
||||
}
|
||||
|
||||
const lang = getLanguage();
|
||||
|
||||
if (lang.includes("zh") || lang.includes("cn")) {
|
||||
return "cn";
|
||||
} else if (lang.includes("tw")) {
|
||||
return "tw";
|
||||
} else if (lang.includes("es")) {
|
||||
return "es";
|
||||
} else {
|
||||
return "en";
|
||||
}
|
||||
}
|
||||
|
||||
export function changeLang(lang: Lang) {
|
||||
setItem(LANG_KEY, lang)
|
||||
location.reload()
|
||||
setItem(LANG_KEY, lang);
|
||||
location.reload();
|
||||
}
|
||||
|
||||
export default { en: EN, cn: CN }[getLang()]
|
||||
export default { en: EN, cn: CN, tw: TW, es: ES }[getLang()];
|
||||
|
@ -0,0 +1,117 @@
|
||||
import { create } from "zustand";
|
||||
import { persist } from "zustand/middleware";
|
||||
import Fuse from "fuse.js";
|
||||
|
||||
export interface Prompt {
|
||||
id?: number;
|
||||
title: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
export interface PromptStore {
|
||||
latestId: number;
|
||||
prompts: Map<number, Prompt>;
|
||||
|
||||
add: (prompt: Prompt) => number;
|
||||
remove: (id: number) => void;
|
||||
search: (text: string) => Prompt[];
|
||||
}
|
||||
|
||||
export const PROMPT_KEY = "prompt-store";
|
||||
|
||||
export const SearchService = {
|
||||
ready: false,
|
||||
engine: new Fuse<Prompt>([], { keys: ["title"] }),
|
||||
count: {
|
||||
builtin: 0,
|
||||
},
|
||||
|
||||
init(prompts: Prompt[]) {
|
||||
if (this.ready) {
|
||||
return;
|
||||
}
|
||||
this.engine.setCollection(prompts);
|
||||
this.ready = true;
|
||||
},
|
||||
|
||||
remove(id: number) {
|
||||
this.engine.remove((doc) => doc.id === id);
|
||||
},
|
||||
|
||||
add(prompt: Prompt) {
|
||||
this.engine.add(prompt);
|
||||
},
|
||||
|
||||
search(text: string) {
|
||||
const results = this.engine.search(text);
|
||||
return results.map((v) => v.item);
|
||||
},
|
||||
};
|
||||
|
||||
export const usePromptStore = create<PromptStore>()(
|
||||
persist(
|
||||
(set, get) => ({
|
||||
latestId: 0,
|
||||
prompts: new Map(),
|
||||
|
||||
add(prompt) {
|
||||
const prompts = get().prompts;
|
||||
prompt.id = get().latestId + 1;
|
||||
prompts.set(prompt.id, prompt);
|
||||
|
||||
set(() => ({
|
||||
latestId: prompt.id!,
|
||||
prompts: prompts,
|
||||
}));
|
||||
|
||||
return prompt.id!;
|
||||
},
|
||||
|
||||
remove(id) {
|
||||
const prompts = get().prompts;
|
||||
prompts.delete(id);
|
||||
SearchService.remove(id);
|
||||
|
||||
set(() => ({
|
||||
prompts,
|
||||
}));
|
||||
},
|
||||
|
||||
search(text) {
|
||||
return SearchService.search(text) as Prompt[];
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: PROMPT_KEY,
|
||||
version: 1,
|
||||
onRehydrateStorage(state) {
|
||||
const PROMPT_URL = "./prompts.json";
|
||||
|
||||
type PromptList = Array<[string, string]>;
|
||||
|
||||
fetch(PROMPT_URL)
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
const builtinPrompts = [res.en, res.cn]
|
||||
.map((promptList: PromptList) => {
|
||||
return promptList.map(
|
||||
([title, content]) =>
|
||||
({
|
||||
title,
|
||||
content,
|
||||
} as Prompt),
|
||||
);
|
||||
})
|
||||
.concat([...(state?.prompts?.values() ?? [])]);
|
||||
|
||||
const allPromptsForSearch = builtinPrompts.reduce(
|
||||
(pre, cur) => pre.concat(cur),
|
||||
[],
|
||||
);
|
||||
SearchService.count.builtin = res.en.length + res.cn.length;
|
||||
SearchService.init(allPromptsForSearch);
|
||||
});
|
||||
},
|
||||
},
|
||||
),
|
||||
);
|
@ -0,0 +1,4 @@
|
||||
User-agent: *
|
||||
Disallow: /
|
||||
User-agent: vitals.vercel-insights.com
|
||||
Allow: /
|
@ -1,24 +1,13 @@
|
||||
const CHATGPT_NEXT_WEB_CACHE = "chatgpt-next-web-cache";
|
||||
|
||||
self.addEventListener('activate', function (event) {
|
||||
console.log('ServiceWorker activated.');
|
||||
self.addEventListener("activate", function (event) {
|
||||
console.log("ServiceWorker activated.");
|
||||
});
|
||||
|
||||
self.addEventListener('install', function (event) {
|
||||
self.addEventListener("install", function (event) {
|
||||
event.waitUntil(
|
||||
caches.open(CHATGPT_NEXT_WEB_CACHE)
|
||||
.then(function (cache) {
|
||||
return cache.addAll([
|
||||
]);
|
||||
})
|
||||
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);
|
||||
})
|
||||
);
|
||||
});
|
@ -0,0 +1,53 @@
|
||||
import fetch from "node-fetch";
|
||||
import fs from "fs/promises";
|
||||
|
||||
const RAW_CN_URL =
|
||||
"https://raw.githubusercontent.com/PlexPt/awesome-chatgpt-prompts-zh/main/prompts-zh.json";
|
||||
const CN_URL =
|
||||
"https://cdn.jsdelivr.net/gh/PlexPt/awesome-chatgpt-prompts-zh@main/prompts-zh.json";
|
||||
const RAW_EN_URL =
|
||||
"https://raw.githubusercontent.com/f/awesome-chatgpt-prompts/main/prompts.csv";
|
||||
const EN_URL =
|
||||
"https://cdn.jsdelivr.net/gh/f/awesome-chatgpt-prompts@main/prompts.csv";
|
||||
const FILE = "./public/prompts.json";
|
||||
|
||||
async function fetchCN() {
|
||||
console.log("[Fetch] fetching cn prompts...");
|
||||
try {
|
||||
const raw = await (await fetch(CN_URL)).json();
|
||||
return raw.map((v) => [v.act, v.prompt]);
|
||||
} catch (error) {
|
||||
console.error("[Fetch] failed to fetch cn prompts", error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchEN() {
|
||||
console.log("[Fetch] fetching en prompts...");
|
||||
try {
|
||||
const raw = await (await fetch(EN_URL)).text();
|
||||
return raw
|
||||
.split("\n")
|
||||
.slice(1)
|
||||
.map((v) => v.split('","').map((v) => v.replace('"', "")));
|
||||
} catch (error) {
|
||||
console.error("[Fetch] failed to fetch cn prompts", error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
Promise.all([fetchCN(), fetchEN()])
|
||||
.then(([cn, en]) => {
|
||||
fs.writeFile(FILE, JSON.stringify({ cn, en }));
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error("[Fetch] failed to fetch prompts");
|
||||
fs.writeFile(FILE, JSON.stringify({ cn: [], en: [] }));
|
||||
})
|
||||
.finally(() => {
|
||||
console.log("[Fetch] saved to " + FILE);
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
@ -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
|
Loading…
Reference in new issue