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 CN from "./cn";
|
||||||
import EN from './en'
|
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) {
|
function getItem(key: string) {
|
||||||
try {
|
try {
|
||||||
return localStorage.getItem(key)
|
return localStorage.getItem(key);
|
||||||
} catch {
|
} catch {
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setItem(key: string, value: string) {
|
function setItem(key: string, value: string) {
|
||||||
try {
|
try {
|
||||||
localStorage.setItem(key, value)
|
localStorage.setItem(key, value);
|
||||||
} catch { }
|
} catch {}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLanguage() {
|
function getLanguage() {
|
||||||
try {
|
try {
|
||||||
return navigator.language.toLowerCase()
|
return navigator.language.toLowerCase();
|
||||||
} catch {
|
} catch {
|
||||||
return 'cn'
|
return "cn";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getLang(): Lang {
|
export function getLang(): Lang {
|
||||||
const savedLang = getItem(LANG_KEY)
|
const savedLang = getItem(LANG_KEY);
|
||||||
|
|
||||||
if (['en', 'cn'].includes(savedLang ?? '')) {
|
if (AllLangs.includes((savedLang ?? "") as Lang)) {
|
||||||
return savedLang as Lang
|
return savedLang as Lang;
|
||||||
}
|
}
|
||||||
|
|
||||||
const lang = getLanguage()
|
const lang = getLanguage();
|
||||||
|
|
||||||
if (lang.includes('zh') || lang.includes('cn')) {
|
if (lang.includes("zh") || lang.includes("cn")) {
|
||||||
return 'cn'
|
return "cn";
|
||||||
|
} else if (lang.includes("tw")) {
|
||||||
|
return "tw";
|
||||||
|
} else if (lang.includes("es")) {
|
||||||
|
return "es";
|
||||||
} else {
|
} else {
|
||||||
return 'en'
|
return "en";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function changeLang(lang: Lang) {
|
export function changeLang(lang: Lang) {
|
||||||
setItem(LANG_KEY, lang)
|
setItem(LANG_KEY, lang);
|
||||||
location.reload()
|
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";
|
const CHATGPT_NEXT_WEB_CACHE = "chatgpt-next-web-cache";
|
||||||
|
|
||||||
self.addEventListener('activate', function (event) {
|
self.addEventListener("activate", function (event) {
|
||||||
console.log('ServiceWorker activated.');
|
console.log("ServiceWorker activated.");
|
||||||
});
|
});
|
||||||
|
|
||||||
self.addEventListener('install', function (event) {
|
self.addEventListener("install", function (event) {
|
||||||
event.waitUntil(
|
event.waitUntil(
|
||||||
caches.open(CHATGPT_NEXT_WEB_CACHE)
|
caches.open(CHATGPT_NEXT_WEB_CACHE).then(function (cache) {
|
||||||
.then(function (cache) {
|
return cache.addAll([]);
|
||||||
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