mirror of
https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
synced 2025-05-30 09:30:19 +09:00
Merge remote-tracking branch 'upstream/main'
This commit is contained in:
commit
b56d2e6b4f
15
.github/workflows/app.yml
vendored
15
.github/workflows/app.yml
vendored
@ -43,12 +43,9 @@ jobs:
|
||||
- os: ubuntu-latest
|
||||
arch: x86_64
|
||||
rust_target: x86_64-unknown-linux-gnu
|
||||
- os: macos-latest
|
||||
arch: x86_64
|
||||
rust_target: x86_64-apple-darwin
|
||||
- os: macos-latest
|
||||
arch: aarch64
|
||||
rust_target: aarch64-apple-darwin
|
||||
rust_target: x86_64-apple-darwin,aarch64-apple-darwin
|
||||
- os: windows-latest
|
||||
arch: x86_64
|
||||
rust_target: x86_64-pc-windows-msvc
|
||||
@ -60,13 +57,14 @@ jobs:
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
cache: 'yarn'
|
||||
- name: install Rust stable
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: ${{ matrix.config.rust_target }}
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
key: ${{ matrix.config.rust_target }}
|
||||
key: ${{ matrix.config.os }}
|
||||
- name: install dependencies (ubuntu only)
|
||||
if: matrix.config.os == 'ubuntu-latest'
|
||||
run: |
|
||||
@ -79,8 +77,15 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
with:
|
||||
releaseId: ${{ needs.create-release.outputs.release_id }}
|
||||
args: ${{ matrix.config.os == 'macos-latest' && '--target universal-apple-darwin' || '' }}
|
||||
|
||||
publish-release:
|
||||
permissions:
|
||||
|
1
.github/workflows/deploy_preview.yml
vendored
1
.github/workflows/deploy_preview.yml
vendored
@ -5,6 +5,7 @@ on:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
- reopened
|
||||
|
||||
env:
|
||||
VERCEL_TEAM: ${{ secrets.VERCEL_TEAM }}
|
||||
|
@ -171,7 +171,7 @@ export function getHeaders(ignoreHeaders?: boolean) {
|
||||
const accessStore = useAccessStore.getState();
|
||||
let headers: Record<string, string> = {};
|
||||
const modelConfig = useChatStore.getState().currentSession().mask.modelConfig;
|
||||
const isGoogle = modelConfig.model === "gemini-pro";
|
||||
const isGoogle = modelConfig.model.startsWith("gemini");
|
||||
if (!ignoreHeaders && !isGoogle) {
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
|
@ -13,15 +13,8 @@ import {
|
||||
LLMUsage,
|
||||
} from "../api";
|
||||
import { useAccessStore, useAppConfig, useChatStore } from "@/app/store";
|
||||
import {
|
||||
EventStreamContentType,
|
||||
fetchEventSource,
|
||||
} from "@fortaine/fetch-event-source";
|
||||
import { prettyObject } from "@/app/utils/format";
|
||||
import { getClientConfig } from "@/app/config/client";
|
||||
import Locale from "../../locales";
|
||||
import { getServerSideConfig } from "@/app/config/server";
|
||||
import de from "@/app/locales/de";
|
||||
import { DEFAULT_API_HOST } from "@/app/constant";
|
||||
export class GeminiProApi implements LLMApi {
|
||||
toolAgentChat(options: AgentChatOptions): Promise<void> {
|
||||
throw new Error("Method not implemented.");
|
||||
@ -36,7 +29,7 @@ export class GeminiProApi implements LLMApi {
|
||||
);
|
||||
}
|
||||
async chat(options: ChatOptions): Promise<void> {
|
||||
const apiClient = this;
|
||||
// const apiClient = this;
|
||||
const messages = options.messages.map((v) => ({
|
||||
role: v.role.replace("assistant", "model").replace("system", "user"),
|
||||
parts: [{ text: v.content }],
|
||||
@ -94,13 +87,27 @@ export class GeminiProApi implements LLMApi {
|
||||
],
|
||||
};
|
||||
|
||||
console.log("[Request] google payload: ", requestPayload);
|
||||
const accessStore = useAccessStore.getState();
|
||||
let baseUrl = accessStore.googleUrl;
|
||||
const isApp = !!getClientConfig()?.isApp;
|
||||
|
||||
const shouldStream = !!options.config.stream;
|
||||
let shouldStream = !!options.config.stream;
|
||||
const controller = new AbortController();
|
||||
options.onController?.(controller);
|
||||
try {
|
||||
const chatPath = this.path(Google.ChatPath);
|
||||
let chatPath = this.path(Google.ChatPath);
|
||||
|
||||
// let baseUrl = accessStore.googleUrl;
|
||||
|
||||
if (!baseUrl) {
|
||||
baseUrl = isApp
|
||||
? DEFAULT_API_HOST + "/api/proxy/google/" + Google.ChatPath
|
||||
: chatPath;
|
||||
}
|
||||
|
||||
if (isApp) {
|
||||
baseUrl += `?key=${accessStore.googleApiKey}`;
|
||||
}
|
||||
const chatPayload = {
|
||||
method: "POST",
|
||||
body: JSON.stringify(requestPayload),
|
||||
@ -116,10 +123,6 @@ export class GeminiProApi implements LLMApi {
|
||||
if (shouldStream) {
|
||||
let responseText = "";
|
||||
let remainText = "";
|
||||
let streamChatPath = chatPath.replace(
|
||||
"generateContent",
|
||||
"streamGenerateContent",
|
||||
);
|
||||
let finished = false;
|
||||
|
||||
let existingTexts: string[] = [];
|
||||
@ -149,7 +152,11 @@ export class GeminiProApi implements LLMApi {
|
||||
|
||||
// start animaion
|
||||
animateResponseText();
|
||||
fetch(streamChatPath, chatPayload)
|
||||
|
||||
fetch(
|
||||
baseUrl.replace("generateContent", "streamGenerateContent"),
|
||||
chatPayload,
|
||||
)
|
||||
.then((response) => {
|
||||
const reader = response?.body?.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
@ -200,11 +207,9 @@ export class GeminiProApi implements LLMApi {
|
||||
console.error("Error:", error);
|
||||
});
|
||||
} else {
|
||||
const res = await fetch(chatPath, chatPayload);
|
||||
const res = await fetch(baseUrl, chatPayload);
|
||||
clearTimeout(requestTimeoutId);
|
||||
|
||||
const resJson = await res.json();
|
||||
|
||||
if (resJson?.promptFeedback?.blockReason) {
|
||||
// being blocked
|
||||
options.onError?.(
|
||||
|
@ -1,3 +1,4 @@
|
||||
"use client";
|
||||
import {
|
||||
ApiPath,
|
||||
DEFAULT_API_HOST,
|
||||
@ -53,7 +54,9 @@ export class ChatGPTApi implements LLMApi {
|
||||
|
||||
if (baseUrl.length === 0) {
|
||||
const isApp = !!getClientConfig()?.isApp;
|
||||
baseUrl = isApp ? DEFAULT_API_HOST : ApiPath.OpenAI;
|
||||
baseUrl = isApp
|
||||
? DEFAULT_API_HOST + "/proxy" + ApiPath.OpenAI
|
||||
: ApiPath.OpenAI;
|
||||
}
|
||||
|
||||
if (baseUrl.endsWith("/")) {
|
||||
@ -68,6 +71,8 @@ export class ChatGPTApi implements LLMApi {
|
||||
return [baseUrl, model, path].join("/");
|
||||
}
|
||||
|
||||
console.log("[Proxy Endpoint] ", baseUrl, path);
|
||||
|
||||
return [baseUrl, path].join("/");
|
||||
}
|
||||
|
||||
|
@ -307,7 +307,7 @@ export function PreviewActions(props: {
|
||||
setShouldExport(false);
|
||||
|
||||
var api: ClientApi;
|
||||
if (config.modelConfig.model === "gemini-pro") {
|
||||
if (config.modelConfig.model.startsWith("gemini")) {
|
||||
api = new ClientApi(ModelProvider.GeminiPro);
|
||||
} else {
|
||||
api = new ClientApi(ModelProvider.GPT);
|
||||
|
@ -178,7 +178,7 @@ export function useLoadData() {
|
||||
const config = useAppConfig();
|
||||
|
||||
var api: ClientApi;
|
||||
if (config.modelConfig.model === "gemini-pro") {
|
||||
if (config.modelConfig.model.startsWith("gemini")) {
|
||||
api = new ClientApi(ModelProvider.GeminiPro);
|
||||
} else {
|
||||
api = new ClientApi(ModelProvider.GPT);
|
||||
|
@ -92,7 +92,7 @@ export function ModelConfigList(props: {
|
||||
></input>
|
||||
</ListItem>
|
||||
|
||||
{props.modelConfig.model === "gemini-pro" ? null : (
|
||||
{props.modelConfig.model.startsWith("gemini") ? null : (
|
||||
<>
|
||||
<ListItem
|
||||
title={Locale.Settings.PresencePenalty.Title}
|
||||
|
@ -8,8 +8,7 @@ export const FETCH_COMMIT_URL = `https://api.github.com/repos/${OWNER}/${REPO}/c
|
||||
export const FETCH_TAG_URL = `https://api.github.com/repos/${OWNER}/${REPO}/tags?per_page=1`;
|
||||
export const RUNTIME_CONFIG_DOM = "danger-runtime-config";
|
||||
|
||||
export const DEFAULT_CORS_HOST = "https://a.nextweb.fun";
|
||||
export const DEFAULT_API_HOST = `${DEFAULT_CORS_HOST}/api/proxy`;
|
||||
export const DEFAULT_API_HOST = "https://api.nextchat.dev";
|
||||
export const OPENAI_BASE_URL = "https://api.openai.com";
|
||||
export const GOOGLE_BASE_URL = "https://generativelanguage.googleapis.com";
|
||||
|
||||
|
@ -12,7 +12,9 @@ import { ensure } from "../utils/clone";
|
||||
let fetchState = 0; // 0 not fetch, 1 fetching, 2 done
|
||||
|
||||
const DEFAULT_OPENAI_URL =
|
||||
getClientConfig()?.buildMode === "export" ? DEFAULT_API_HOST : ApiPath.OpenAI;
|
||||
getClientConfig()?.buildMode === "export"
|
||||
? DEFAULT_API_HOST + "/api/proxy/openai"
|
||||
: ApiPath.OpenAI;
|
||||
|
||||
const DEFAULT_ACCESS_STATE = {
|
||||
accessCode: "",
|
||||
|
@ -100,14 +100,18 @@ function countMessages(msgs: ChatMessage[]) {
|
||||
}
|
||||
|
||||
function fillTemplateWith(input: string, modelConfig: ModelConfig) {
|
||||
const cutoff = KnowledgeCutOffDate[modelConfig.model] ?? KnowledgeCutOffDate.default;
|
||||
const cutoff =
|
||||
KnowledgeCutOffDate[modelConfig.model] ?? KnowledgeCutOffDate.default;
|
||||
// Find the model in the DEFAULT_MODELS array that matches the modelConfig.model
|
||||
const modelInfo = DEFAULT_MODELS.find(m => m.name === modelConfig.model);
|
||||
if (!modelInfo) {
|
||||
throw new Error(`Model ${modelConfig.model} not found in DEFAULT_MODELS array.`);
|
||||
const modelInfo = DEFAULT_MODELS.find((m) => m.name === modelConfig.model);
|
||||
|
||||
var serviceProvider = "OpenAI";
|
||||
if (modelInfo) {
|
||||
// TODO: auto detect the providerName from the modelConfig.model
|
||||
|
||||
// Directly use the providerName from the modelInfo
|
||||
serviceProvider = modelInfo.provider.providerName;
|
||||
}
|
||||
// Directly use the providerName from the modelInfo
|
||||
const serviceProvider = modelInfo.provider.providerName;
|
||||
|
||||
const vars = {
|
||||
ServiceProvider: serviceProvider,
|
||||
@ -127,7 +131,7 @@ function fillTemplateWith(input: string, modelConfig: ModelConfig) {
|
||||
}
|
||||
|
||||
Object.entries(vars).forEach(([name, value]) => {
|
||||
const regex = new RegExp(`{{${name}}}`, 'g');
|
||||
const regex = new RegExp(`{{${name}}}`, "g");
|
||||
output = output.replace(regex, value.toString()); // Ensure value is a string
|
||||
});
|
||||
|
||||
@ -404,7 +408,7 @@ export const useChatStore = createPersistStore(
|
||||
},
|
||||
});
|
||||
} else {
|
||||
if (modelConfig.model === "gemini-pro") {
|
||||
if (modelConfig.model.startsWith("gemini")) {
|
||||
api = new ClientApi(ModelProvider.GeminiPro);
|
||||
}
|
||||
// make request
|
||||
@ -587,7 +591,7 @@ export const useChatStore = createPersistStore(
|
||||
const modelConfig = session.mask.modelConfig;
|
||||
|
||||
var api: ClientApi;
|
||||
if (modelConfig.model === "gemini-pro") {
|
||||
if (modelConfig.model.startsWith("gemini")) {
|
||||
api = new ClientApi(ModelProvider.GeminiPro);
|
||||
} else {
|
||||
api = new ClientApi(ModelProvider.GPT);
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { getClientConfig } from "../config/client";
|
||||
import { ApiPath, DEFAULT_CORS_HOST } from "../constant";
|
||||
import { ApiPath, DEFAULT_API_HOST } from "../constant";
|
||||
|
||||
export function corsPath(path: string) {
|
||||
const baseUrl = getClientConfig()?.isApp ? `${DEFAULT_CORS_HOST}` : "";
|
||||
const baseUrl = getClientConfig()?.isApp ? `${DEFAULT_API_HOST}` : "";
|
||||
|
||||
if (!path.startsWith("/")) {
|
||||
path = "/" + path;
|
||||
|
@ -64,8 +64,17 @@ if (mode !== "export") {
|
||||
|
||||
nextConfig.rewrites = async () => {
|
||||
const ret = [
|
||||
// adjust for previous verison directly using "/api/proxy/" as proxy base route
|
||||
{
|
||||
source: "/api/proxy/:path*",
|
||||
source: "/api/proxy/v1/:path*",
|
||||
destination: "https://api.openai.com/v1/:path*",
|
||||
},
|
||||
{
|
||||
source: "/api/proxy/google/:path*",
|
||||
destination: "https://generativelanguage.googleapis.com/:path*",
|
||||
},
|
||||
{
|
||||
source: "/api/proxy/openai/:path*",
|
||||
destination: "https://api.openai.com/:path*",
|
||||
},
|
||||
{
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "chatgpt-next-web",
|
||||
"name": "nextchat",
|
||||
"private": false,
|
||||
"license": "mit",
|
||||
"scripts": {
|
||||
@ -80,4 +80,4 @@
|
||||
"resolutions": {
|
||||
"lint-staged/yaml": "^2.2.2"
|
||||
}
|
||||
}
|
||||
}
|
652
src-tauri/Cargo.lock
generated
652
src-tauri/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,27 +1,45 @@
|
||||
[package]
|
||||
name = "chatgpt-next-web"
|
||||
name = "nextchat"
|
||||
version = "0.1.0"
|
||||
description = "A cross platform app for LLM ChatBot."
|
||||
authors = ["Yidadaa"]
|
||||
license = "mit"
|
||||
repository = ""
|
||||
default-run = "chatgpt-next-web"
|
||||
default-run = "nextchat"
|
||||
edition = "2021"
|
||||
rust-version = "1.60"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "1.3.0", features = [] }
|
||||
tauri-build = { version = "1.5.1", features = [] }
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
tauri = { version = "1.3.0", features = ["notification-all", "fs-all", "clipboard-all", "dialog-all", "shell-open", "updater", "window-close", "window-hide", "window-maximize", "window-minimize", "window-set-icon", "window-set-ignore-cursor-events", "window-set-resizable", "window-show", "window-start-dragging", "window-unmaximize", "window-unminimize"] }
|
||||
tauri = { version = "1.5.4", features = [
|
||||
"notification-all",
|
||||
"fs-all",
|
||||
"clipboard-all",
|
||||
"dialog-all",
|
||||
"shell-open",
|
||||
"updater",
|
||||
"window-close",
|
||||
"window-hide",
|
||||
"window-maximize",
|
||||
"window-minimize",
|
||||
"window-set-icon",
|
||||
"window-set-ignore-cursor-events",
|
||||
"window-set-resizable",
|
||||
"window-show",
|
||||
"window-start-dragging",
|
||||
"window-unmaximize",
|
||||
"window-unminimize",
|
||||
] }
|
||||
tauri-plugin-window-state = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" }
|
||||
|
||||
[features]
|
||||
# this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled.
|
||||
# If you use cargo directly instead of tauri's cli you can use this feature flag to switch between tauri's `dev` and `build` modes.
|
||||
# DO NOT REMOVE!!
|
||||
custom-protocol = [ "tauri/custom-protocol" ]
|
||||
custom-protocol = ["tauri/custom-protocol"]
|
||||
|
@ -9,7 +9,7 @@
|
||||
},
|
||||
"package": {
|
||||
"productName": "NextChat",
|
||||
"version": "2.10.1"
|
||||
"version": "2.10.3"
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
@ -86,7 +86,8 @@
|
||||
}
|
||||
},
|
||||
"security": {
|
||||
"csp": null
|
||||
"csp": null,
|
||||
"dangerousUseHttpScheme": true
|
||||
},
|
||||
"updater": {
|
||||
"active": true,
|
||||
|
Loading…
Reference in New Issue
Block a user