Compare commits

...

45 Commits

Author SHA1 Message Date
lloydzhou
540f93ad25 remove DEFAULT_API_HOST 2024-09-25 20:46:01 +08:00
lloydzhou
cc33b7b6bf using tauriFetch fro fetchEventSource 2024-09-25 20:29:20 +08:00
lloydzhou
7f857284bb update 2024-09-25 20:03:18 +08:00
lloydzhou
9bd1635064 using @tauri-apps/plugin-http replace @tauri-apps/api/http 2024-09-25 19:49:57 +08:00
lloydzhou
4c9fe56f33 using @tauri-apps/plugin-http replace @tauri-apps/api/http 2024-09-25 19:49:11 +08:00
lloydzhou
29296d42d7 using this version from github fixed data_directory for webkitgtk 2024-09-25 15:30:02 +08:00
lloydzhou
d306491e88 update 2024-09-25 13:16:37 +08:00
lloydzhou
a7d8abbc4d Merge remote-tracking branch 'origin/feat-tauir-v2' into feat-tauir-v2 2024-09-25 00:15:46 +08:00
lloydzhou
4c6a593ae3 hotfix for get version in action 2024-09-25 00:13:36 +08:00
Lloyd Zhou
9ba1b39cf5 Merge pull request #5518 from WtecHtec/main
support tauri-v2
2024-09-24 23:39:10 +08:00
river
454c247de6 chore: remove specta 2024-09-24 21:22:13 +08:00
river
cb6576ec04 feat: simple cargo 2024-09-24 21:19:45 +08:00
river
2758ea5ddd Merge branch 'main' of github.com:WtecHtec/ChatGPT-Next-Web into wtec-main 2024-09-24 21:03:15 +08:00
river
a2e9e78457 chore: update config 2024-09-24 21:03:10 +08:00
sr7
b720ba4c30 删除多余 2024-09-24 20:48:41 +08:00
sr7
7151c0134a 删除多余 2024-09-24 20:36:11 +08:00
sr7
97099849b7 删除多余 2024-09-24 20:29:49 +08:00
river
1fa58c60d9 chore: update config 2024-09-24 20:29:43 +08:00
river
5aaa190a7d chore: remove package-lock 2024-09-24 20:17:46 +08:00
sr7
b9e6dce193 support tauri-v2 2024-09-24 18:52:38 +08:00
sr7
7b1667f204 support tauri-v2 2024-09-24 18:40:24 +08:00
sr7
87c5b72ea2 support tauri-v2 2024-09-24 18:38:12 +08:00
Dogtiti
649c5be64e Merge pull request #5508 from ConnectAI-E/feature-buildin-plugin
add buildin plugin
2024-09-24 17:28:48 +08:00
Dogtiti
fc0042a799 Merge pull request #5515 from DDMeaqua/config-artifacts
Config artifacts
2024-09-24 17:27:33 +08:00
DDMeaqua
269d064e0a fix: #5450 2024-09-24 15:21:27 +08:00
DDMeaqua
6c8143b7de feat: 全局设置是否启用artifacts 2024-09-24 15:15:08 +08:00
lloydzhou
f9f99639db update 2024-09-24 12:59:21 +08:00
Dogtiti
46fc2a5012 Merge pull request #5498 from DDMeaqua/fix-plugin-css
Fix plugin css
2024-09-24 10:23:06 +08:00
lloydzhou
90e7b5aecf try using openai api key for dalle-3 plugin 2024-09-23 20:20:20 +08:00
lloydzhou
ed20fd2962 1. add buildin plugin; 2. remove usingProxy 2024-09-23 20:00:07 +08:00
Lloyd Zhou
4c3fd55a75 Merge pull request #5495 from ConnectAI-E/Fix-code-duplication
Fix code duplication
2024-09-23 16:06:59 +08:00
lyf
d95d509046 fex 2024-09-23 15:43:36 +08:00
DDMeaqua
4a60512ae7 chore: css 2024-09-23 14:18:32 +08:00
DDMeaqua
0e210cf8de fix: #5486 plugin样式优化 2024-09-23 14:13:09 +08:00
lyf
35aa2c7270 Fix code duplication 2024-09-23 11:34:20 +08:00
Lloyd Zhou
23f2b6213c Merge pull request #5489 from ConnectAI-E/feature-fix-openai-function-call
Feature fix openai function call
2024-09-22 19:08:35 +08:00
lloydzhou
3a969054e3 hotfix openai function call tool_calls no index 2024-09-22 18:59:49 +08:00
lloydzhou
4d1f9e49d4 hotfix openai function call tool_calls no index 2024-09-22 18:53:51 +08:00
Dogtiti
2474d5b6d2 Merge pull request #5304 from dustookk/main
fix no max_tokens in payload when the vision model name does not cont…
2024-09-19 20:34:23 +08:00
Dogtiti
c75d9e3de4 Merge pull request #5463 from yudshj/main
修正了typo,WHITE_WEBDEV_ENDPOINTS -> WHITE_WEBDAV_ENDPOINTS
2024-09-19 14:26:48 +08:00
Yudong
df222ded12 修正了typo, WebDev -> WebDav 2024-09-19 14:15:31 +08:00
Yudong
212d15fdd0 修正了typo,WHITE_WEBDEV_ENDPOINTS -> WHITE_WEBDAV_ENDPOINTS 2024-09-19 11:20:18 +08:00
Dogtiti
b5ba05dd83 Merge pull request #5462 from JuliusMoehring/main
fix: Avoid fetching prompts.json serverside
2024-09-19 09:50:21 +08:00
JuliusMoehring
accb526cd6 Avoid fetching prompts.json serverside 2024-09-18 18:07:10 +02:00
yihang3
56eb9d1430 fix no max_tokens in payload when the vision model name does not contain 'vision'. 2024-08-21 15:22:31 +08:00
42 changed files with 5048 additions and 4761 deletions

View File

@@ -66,4 +66,4 @@ ANTHROPIC_API_VERSION=
ANTHROPIC_URL= ANTHROPIC_URL=
### (optional) ### (optional)
WHITE_WEBDEV_ENDPOINTS= WHITE_WEBDAV_ENDPOINTS=

View File

@@ -20,7 +20,7 @@ jobs:
with: with:
node-version: 18 node-version: 18
- name: get version - name: get version
run: echo "PACKAGE_VERSION=$(node -p "require('./src-tauri/tauri.conf.json').package.version")" >> $GITHUB_ENV run: echo "PACKAGE_VERSION=$(node -p "require('./src-tauri/tauri.conf.json').version")" >> $GITHUB_ENV
- name: create release - name: create release
id: create-release id: create-release
uses: actions/github-script@v6 uses: actions/github-script@v6
@@ -69,7 +69,7 @@ jobs:
if: matrix.config.os == 'ubuntu-latest' if: matrix.config.os == 'ubuntu-latest'
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf sudo apt-get install -y libgtk-3-dev libsoup-3.0-dev libjavascriptcoregtk-4.1 libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
- name: install frontend dependencies - name: install frontend dependencies
run: yarn install # change this to npm or pnpm depending on which one you use run: yarn install # change this to npm or pnpm depending on which one you use
- uses: tauri-apps/tauri-action@v0 - uses: tauri-apps/tauri-action@v0

1
.gitignore vendored
View File

@@ -46,3 +46,4 @@ dev
*.key.pub *.key.pub
masks.json masks.json
package-lock.json

View File

@@ -340,7 +340,7 @@ For ByteDance: use `modelName@bytedance=deploymentName` to customize model name
Change default model Change default model
### `WHITE_WEBDEV_ENDPOINTS` (optional) ### `WHITE_WEBDAV_ENDPOINTS` (optional)
You can use this option if you want to increase the number of webdav service addresses you are allowed to access, as required by the format You can use this option if you want to increase the number of webdav service addresses you are allowed to access, as required by the format
- Each address must be a complete endpoint - Each address must be a complete endpoint

View File

@@ -202,7 +202,7 @@ ByteDance Api Url.
如果你想禁用从链接解析预制设置,将此环境变量设置为 1 即可。 如果你想禁用从链接解析预制设置,将此环境变量设置为 1 即可。
### `WHITE_WEBDEV_ENDPOINTS` (可选) ### `WHITE_WEBDAV_ENDPOINTS` (可选)
如果你想增加允许访问的webdav服务地址可以使用该选项格式要求 如果你想增加允许访问的webdav服务地址可以使用该选项格式要求
- 每一个地址必须是一个完整的 endpoint - 每一个地址必须是一个完整的 endpoint

View File

@@ -193,7 +193,7 @@ ByteDance API の URL。
リンクからのプリセット設定解析を無効にしたい場合は、この環境変数を 1 に設定します。 リンクからのプリセット設定解析を無効にしたい場合は、この環境変数を 1 に設定します。
### `WHITE_WEBDEV_ENDPOINTS` (オプション) ### `WHITE_WEBDAV_ENDPOINTS` (オプション)
アクセス許可を与える WebDAV サービスのアドレスを追加したい場合、このオプションを使用します。フォーマット要件: アクセス許可を与える WebDAV サービスのアドレスを追加したい場合、このオプションを使用します。フォーマット要件:
- 各アドレスは完全なエンドポイントでなければなりません。 - 各アドレスは完全なエンドポイントでなければなりません。

View File

@@ -6,7 +6,7 @@ const config = getServerSideConfig();
const mergedAllowedWebDavEndpoints = [ const mergedAllowedWebDavEndpoints = [
...internalAllowedWebDavEndpoints, ...internalAllowedWebDavEndpoints,
...config.allowedWebDevEndpoints, ...config.allowedWebDavEndpoints,
].filter((domain) => Boolean(domain.trim())); ].filter((domain) => Boolean(domain.trim()));
const normalizeUrl = (url: string) => { const normalizeUrl = (url: string) => {

View File

@@ -22,7 +22,7 @@ import {
} from "@fortaine/fetch-event-source"; } from "@fortaine/fetch-event-source";
import { prettyObject } from "@/app/utils/format"; import { prettyObject } from "@/app/utils/format";
import { getClientConfig } from "@/app/config/client"; import { getClientConfig } from "@/app/config/client";
import { getMessageTextContent } from "@/app/utils"; import { getMessageTextContent, fetch } from "@/app/utils";
export interface OpenAIListModelResponse { export interface OpenAIListModelResponse {
object: string; object: string;
@@ -178,6 +178,7 @@ export class QwenApi implements LLMApi {
controller.signal.onabort = finish; controller.signal.onabort = finish;
fetchEventSource(chatPath, { fetchEventSource(chatPath, {
fetch: fetch as any,
...chatPayload, ...chatPayload,
async onopen(res) { async onopen(res) {
clearTimeout(requestTimeoutId); clearTimeout(requestTimeoutId);

View File

@@ -7,8 +7,6 @@ import {
usePluginStore, usePluginStore,
ChatMessageTool, ChatMessageTool,
} from "@/app/store"; } from "@/app/store";
import { getClientConfig } from "@/app/config/client";
import { DEFAULT_API_HOST } from "@/app/constant";
import { getMessageTextContent, isVisionModel } from "@/app/utils"; import { getMessageTextContent, isVisionModel } from "@/app/utils";
import { preProcessImageContent, stream } from "@/app/utils/chat"; import { preProcessImageContent, stream } from "@/app/utils/chat";
import { cloudflareAIGatewayUrl } from "@/app/utils/cloudflare"; import { cloudflareAIGatewayUrl } from "@/app/utils/cloudflare";
@@ -386,11 +384,7 @@ export class ClaudeApi implements LLMApi {
// if endpoint is empty, use default endpoint // if endpoint is empty, use default endpoint
if (baseUrl.trim().length === 0) { if (baseUrl.trim().length === 0) {
const isApp = !!getClientConfig()?.isApp; baseUrl = ApiPath.Anthropic;
baseUrl = isApp
? DEFAULT_API_HOST + "/api/proxy/anthropic"
: ApiPath.Anthropic;
} }
if (!baseUrl.startsWith("http") && !baseUrl.startsWith("/api")) { if (!baseUrl.startsWith("http") && !baseUrl.startsWith("/api")) {

View File

@@ -23,7 +23,7 @@ import {
} from "@fortaine/fetch-event-source"; } from "@fortaine/fetch-event-source";
import { prettyObject } from "@/app/utils/format"; import { prettyObject } from "@/app/utils/format";
import { getClientConfig } from "@/app/config/client"; import { getClientConfig } from "@/app/config/client";
import { getMessageTextContent } from "@/app/utils"; import { getMessageTextContent, fetch } from "@/app/utils";
export interface OpenAIListModelResponse { export interface OpenAIListModelResponse {
object: string; object: string;
@@ -197,6 +197,7 @@ export class ErnieApi implements LLMApi {
controller.signal.onabort = finish; controller.signal.onabort = finish;
fetchEventSource(chatPath, { fetchEventSource(chatPath, {
fetch: fetch as any,
...chatPayload, ...chatPayload,
async onopen(res) { async onopen(res) {
clearTimeout(requestTimeoutId); clearTimeout(requestTimeoutId);

View File

@@ -22,7 +22,7 @@ import {
} from "@fortaine/fetch-event-source"; } from "@fortaine/fetch-event-source";
import { prettyObject } from "@/app/utils/format"; import { prettyObject } from "@/app/utils/format";
import { getClientConfig } from "@/app/config/client"; import { getClientConfig } from "@/app/config/client";
import { getMessageTextContent } from "@/app/utils"; import { getMessageTextContent, fetch } from "@/app/utils";
export interface OpenAIListModelResponse { export interface OpenAIListModelResponse {
object: string; object: string;
@@ -165,6 +165,7 @@ export class DoubaoApi implements LLMApi {
controller.signal.onabort = finish; controller.signal.onabort = finish;
fetchEventSource(chatPath, { fetchEventSource(chatPath, {
fetch: fetch as any,
...chatPayload, ...chatPayload,
async onopen(res) { async onopen(res) {
clearTimeout(requestTimeoutId); clearTimeout(requestTimeoutId);

View File

@@ -8,8 +8,6 @@ import {
SpeechOptions, SpeechOptions,
} from "../api"; } from "../api";
import { useAccessStore, useAppConfig, useChatStore } from "@/app/store"; import { useAccessStore, useAppConfig, useChatStore } from "@/app/store";
import { getClientConfig } from "@/app/config/client";
import { DEFAULT_API_HOST } from "@/app/constant";
import Locale from "../../locales"; import Locale from "../../locales";
import { import {
EventStreamContentType, EventStreamContentType,
@@ -20,6 +18,7 @@ import {
getMessageTextContent, getMessageTextContent,
getMessageImages, getMessageImages,
isVisionModel, isVisionModel,
fetch,
} from "@/app/utils"; } from "@/app/utils";
import { preProcessImageContent } from "@/app/utils/chat"; import { preProcessImageContent } from "@/app/utils/chat";
@@ -32,9 +31,8 @@ export class GeminiProApi implements LLMApi {
baseUrl = accessStore.googleUrl; baseUrl = accessStore.googleUrl;
} }
const isApp = !!getClientConfig()?.isApp;
if (baseUrl.length === 0) { if (baseUrl.length === 0) {
baseUrl = isApp ? DEFAULT_API_HOST + `/api/proxy/google` : ApiPath.Google; baseUrl = ApiPath.Google;
} }
if (baseUrl.endsWith("/")) { if (baseUrl.endsWith("/")) {
baseUrl = baseUrl.slice(0, baseUrl.length - 1); baseUrl = baseUrl.slice(0, baseUrl.length - 1);
@@ -217,6 +215,7 @@ export class GeminiProApi implements LLMApi {
controller.signal.onabort = finish; controller.signal.onabort = finish;
fetchEventSource(chatPath, { fetchEventSource(chatPath, {
fetch: fetch as any,
...chatPayload, ...chatPayload,
async onopen(res) { async onopen(res) {
clearTimeout(requestTimeoutId); clearTimeout(requestTimeoutId);

View File

@@ -1,10 +1,5 @@
"use client"; "use client";
import { import { ApiPath, Iflytek, REQUEST_TIMEOUT_MS } from "@/app/constant";
ApiPath,
DEFAULT_API_HOST,
Iflytek,
REQUEST_TIMEOUT_MS,
} from "@/app/constant";
import { useAccessStore, useAppConfig, useChatStore } from "@/app/store"; import { useAccessStore, useAppConfig, useChatStore } from "@/app/store";
import { import {
@@ -20,8 +15,7 @@ import {
fetchEventSource, fetchEventSource,
} from "@fortaine/fetch-event-source"; } from "@fortaine/fetch-event-source";
import { prettyObject } from "@/app/utils/format"; import { prettyObject } from "@/app/utils/format";
import { getClientConfig } from "@/app/config/client"; import { getMessageTextContent, fetch } from "@/app/utils";
import { getMessageTextContent } from "@/app/utils";
import { RequestPayload } from "./openai"; import { RequestPayload } from "./openai";
@@ -38,9 +32,7 @@ export class SparkApi implements LLMApi {
} }
if (baseUrl.length === 0) { if (baseUrl.length === 0) {
const isApp = !!getClientConfig()?.isApp; baseUrl = ApiPath.Iflytek;
const apiPath = ApiPath.Iflytek;
baseUrl = isApp ? DEFAULT_API_HOST + "/proxy" + apiPath : apiPath;
} }
if (baseUrl.endsWith("/")) { if (baseUrl.endsWith("/")) {
@@ -149,6 +141,7 @@ export class SparkApi implements LLMApi {
controller.signal.onabort = finish; controller.signal.onabort = finish;
fetchEventSource(chatPath, { fetchEventSource(chatPath, {
fetch: fetch as any,
...chatPayload, ...chatPayload,
async onopen(res) { async onopen(res) {
clearTimeout(requestTimeoutId); clearTimeout(requestTimeoutId);

View File

@@ -1,11 +1,6 @@
"use client"; "use client";
// azure and openai, using same models. so using same LLMApi. // azure and openai, using same models. so using same LLMApi.
import { import { ApiPath, Moonshot, REQUEST_TIMEOUT_MS } from "@/app/constant";
ApiPath,
DEFAULT_API_HOST,
Moonshot,
REQUEST_TIMEOUT_MS,
} from "@/app/constant";
import { import {
useAccessStore, useAccessStore,
useAppConfig, useAppConfig,
@@ -21,7 +16,6 @@ import {
LLMModel, LLMModel,
SpeechOptions, SpeechOptions,
} from "../api"; } from "../api";
import { getClientConfig } from "@/app/config/client";
import { getMessageTextContent } from "@/app/utils"; import { getMessageTextContent } from "@/app/utils";
import { RequestPayload } from "./openai"; import { RequestPayload } from "./openai";
@@ -38,9 +32,8 @@ export class MoonshotApi implements LLMApi {
} }
if (baseUrl.length === 0) { if (baseUrl.length === 0) {
const isApp = !!getClientConfig()?.isApp;
const apiPath = ApiPath.Moonshot; const apiPath = ApiPath.Moonshot;
baseUrl = isApp ? DEFAULT_API_HOST + "/proxy" + apiPath : apiPath; baseUrl = apiPath;
} }
if (baseUrl.endsWith("/")) { if (baseUrl.endsWith("/")) {

View File

@@ -2,7 +2,6 @@
// azure and openai, using same models. so using same LLMApi. // azure and openai, using same models. so using same LLMApi.
import { import {
ApiPath, ApiPath,
DEFAULT_API_HOST,
DEFAULT_MODELS, DEFAULT_MODELS,
OpenaiPath, OpenaiPath,
Azure, Azure,
@@ -36,7 +35,6 @@ import {
SpeechOptions, SpeechOptions,
} from "../api"; } from "../api";
import Locale from "../../locales"; import Locale from "../../locales";
import { getClientConfig } from "@/app/config/client";
import { import {
getMessageTextContent, getMessageTextContent,
isVisionModel, isVisionModel,
@@ -96,9 +94,7 @@ export class ChatGPTApi implements LLMApi {
} }
if (baseUrl.length === 0) { if (baseUrl.length === 0) {
const isApp = !!getClientConfig()?.isApp; baseUrl = isAzure ? ApiPath.Azure : ApiPath.OpenAI;
const apiPath = isAzure ? ApiPath.Azure : ApiPath.OpenAI;
baseUrl = isApp ? DEFAULT_API_HOST + "/proxy" + apiPath : apiPath;
} }
if (baseUrl.endsWith("/")) { if (baseUrl.endsWith("/")) {
@@ -277,6 +273,7 @@ export class ChatGPTApi implements LLMApi {
); );
} }
if (shouldStream) { if (shouldStream) {
let index = -1;
const [tools, funcs] = usePluginStore const [tools, funcs] = usePluginStore
.getState() .getState()
.getAsTools( .getAsTools(
@@ -302,10 +299,10 @@ export class ChatGPTApi implements LLMApi {
}>; }>;
const tool_calls = choices[0]?.delta?.tool_calls; const tool_calls = choices[0]?.delta?.tool_calls;
if (tool_calls?.length > 0) { if (tool_calls?.length > 0) {
const index = tool_calls[0]?.index;
const id = tool_calls[0]?.id; const id = tool_calls[0]?.id;
const args = tool_calls[0]?.function?.arguments; const args = tool_calls[0]?.function?.arguments;
if (id) { if (id) {
index += 1;
runTools.push({ runTools.push({
id, id,
type: tool_calls[0]?.type, type: tool_calls[0]?.type,
@@ -327,6 +324,8 @@ export class ChatGPTApi implements LLMApi {
toolCallMessage: any, toolCallMessage: any,
toolCallResult: any[], toolCallResult: any[],
) => { ) => {
// reset index value
index = -1;
// @ts-ignore // @ts-ignore
requestPayload?.messages?.splice( requestPayload?.messages?.splice(
// @ts-ignore // @ts-ignore

View File

@@ -1,5 +1,5 @@
"use client"; "use client";
import { ApiPath, DEFAULT_API_HOST, REQUEST_TIMEOUT_MS } from "@/app/constant"; import { ApiPath, REQUEST_TIMEOUT_MS } from "@/app/constant";
import { useAccessStore, useAppConfig, useChatStore } from "@/app/store"; import { useAccessStore, useAppConfig, useChatStore } from "@/app/store";
import { import {
@@ -16,8 +16,7 @@ import {
fetchEventSource, fetchEventSource,
} from "@fortaine/fetch-event-source"; } from "@fortaine/fetch-event-source";
import { prettyObject } from "@/app/utils/format"; import { prettyObject } from "@/app/utils/format";
import { getClientConfig } from "@/app/config/client"; import { getMessageTextContent, isVisionModel, fetch } from "@/app/utils";
import { getMessageTextContent, isVisionModel } from "@/app/utils";
import mapKeys from "lodash-es/mapKeys"; import mapKeys from "lodash-es/mapKeys";
import mapValues from "lodash-es/mapValues"; import mapValues from "lodash-es/mapValues";
import isArray from "lodash-es/isArray"; import isArray from "lodash-es/isArray";
@@ -69,10 +68,7 @@ export class HunyuanApi implements LLMApi {
} }
if (baseUrl.length === 0) { if (baseUrl.length === 0) {
const isApp = !!getClientConfig()?.isApp; baseUrl = ApiPath.Tencent;
baseUrl = isApp
? DEFAULT_API_HOST + "/api/proxy/tencent"
: ApiPath.Tencent;
} }
if (baseUrl.endsWith("/")) { if (baseUrl.endsWith("/")) {
@@ -179,6 +175,7 @@ export class HunyuanApi implements LLMApi {
controller.signal.onabort = finish; controller.signal.onabort = finish;
fetchEventSource(chatPath, { fetchEventSource(chatPath, {
fetch: fetch as any,
...chatPayload, ...chatPayload,
async onopen(res) { async onopen(res) {
clearTimeout(requestTimeoutId); clearTimeout(requestTimeoutId);

View File

@@ -21,6 +21,7 @@ import {
} from "./artifacts"; } from "./artifacts";
import { useChatStore } from "../store"; import { useChatStore } from "../store";
import { IconButton } from "./button"; import { IconButton } from "./button";
import { useAppConfig } from "../store/config";
export function Mermaid(props: { code: string }) { export function Mermaid(props: { code: string }) {
const ref = useRef<HTMLDivElement>(null); const ref = useRef<HTMLDivElement>(null);
@@ -92,7 +93,9 @@ export function PreCode(props: { children: any }) {
} }
}, 600); }, 600);
const enableArtifacts = session.mask?.enableArtifacts !== false; const config = useAppConfig();
const enableArtifacts =
session.mask?.enableArtifacts !== false && config.enableArtifacts;
//Wrap the paragraph for plain-text //Wrap the paragraph for plain-text
useEffect(() => { useEffect(() => {
@@ -128,8 +131,9 @@ export function PreCode(props: { children: any }) {
className="copy-code-button" className="copy-code-button"
onClick={() => { onClick={() => {
if (ref.current) { if (ref.current) {
const code = ref.current.innerText; copyToClipboard(
copyToClipboard(code); ref.current.querySelector("code")?.innerText ?? "",
);
} }
}} }}
></span> ></span>

View File

@@ -166,21 +166,23 @@ export function MaskConfig(props: {
></input> ></input>
</ListItem> </ListItem>
<ListItem {globalConfig.enableArtifacts && (
title={Locale.Mask.Config.Artifacts.Title} <ListItem
subTitle={Locale.Mask.Config.Artifacts.SubTitle} title={Locale.Mask.Config.Artifacts.Title}
> subTitle={Locale.Mask.Config.Artifacts.SubTitle}
<input >
aria-label={Locale.Mask.Config.Artifacts.Title} <input
type="checkbox" aria-label={Locale.Mask.Config.Artifacts.Title}
checked={props.mask.enableArtifacts !== false} type="checkbox"
onChange={(e) => { checked={props.mask.enableArtifacts !== false}
props.updateMask((mask) => { onChange={(e) => {
mask.enableArtifacts = e.currentTarget.checked; props.updateMask((mask) => {
}); mask.enableArtifacts = e.currentTarget.checked;
}} });
></input> }}
</ListItem> ></input>
</ListItem>
)}
{!props.shouldSyncFromGlobal ? ( {!props.shouldSyncFromGlobal ? (
<ListItem <ListItem

View File

@@ -10,7 +10,29 @@
max-height: 240px; max-height: 240px;
overflow-y: auto; overflow-y: auto;
white-space: pre-wrap; white-space: pre-wrap;
min-width: 300px; min-width: 280px;
} }
} }
.plugin-schema {
display: flex;
justify-content: flex-end;
flex-direction: row;
input {
margin-right: 20px;
@media screen and (max-width: 600px) {
margin-right: 0px;
}
}
@media screen and (max-width: 600px) {
flex-direction: column;
gap: 5px;
button {
padding: 10px;
}
}
}

View File

@@ -12,7 +12,6 @@ import EditIcon from "../icons/edit.svg";
import AddIcon from "../icons/add.svg"; import AddIcon from "../icons/add.svg";
import CloseIcon from "../icons/close.svg"; import CloseIcon from "../icons/close.svg";
import DeleteIcon from "../icons/delete.svg"; import DeleteIcon from "../icons/delete.svg";
import EyeIcon from "../icons/eye.svg";
import ConfirmIcon from "../icons/confirm.svg"; import ConfirmIcon from "../icons/confirm.svg";
import ReloadIcon from "../icons/reload.svg"; import ReloadIcon from "../icons/reload.svg";
import GithubIcon from "../icons/github.svg"; import GithubIcon from "../icons/github.svg";
@@ -29,7 +28,6 @@ import {
import Locale from "../locales"; import Locale from "../locales";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { useState } from "react"; import { useState } from "react";
import { getClientConfig } from "../config/client";
export function PluginPage() { export function PluginPage() {
const navigate = useNavigate(); const navigate = useNavigate();
@@ -209,19 +207,11 @@ export function PluginPage() {
</div> </div>
</div> </div>
<div className={styles["mask-actions"]}> <div className={styles["mask-actions"]}>
{m.builtin ? ( <IconButton
<IconButton icon={<EditIcon />}
icon={<EyeIcon />} text={Locale.Plugin.Item.Edit}
text={Locale.Plugin.Item.View} onClick={() => setEditingPluginId(m.id)}
onClick={() => setEditingPluginId(m.id)} />
/>
) : (
<IconButton
icon={<EditIcon />}
text={Locale.Plugin.Item.Edit}
onClick={() => setEditingPluginId(m.id)}
/>
)}
{!m.builtin && ( {!m.builtin && (
<IconButton <IconButton
icon={<DeleteIcon />} icon={<DeleteIcon />}
@@ -325,30 +315,13 @@ export function PluginPage() {
></PasswordInput> ></PasswordInput>
</ListItem> </ListItem>
)} )}
{!getClientConfig()?.isApp && (
<ListItem
title={Locale.Plugin.Auth.Proxy}
subTitle={Locale.Plugin.Auth.ProxyDescription}
>
<input
type="checkbox"
checked={editingPlugin?.usingProxy}
style={{ minWidth: 16 }}
onChange={(e) => {
pluginStore.updatePlugin(editingPlugin.id, (plugin) => {
plugin.usingProxy = e.currentTarget.checked;
});
}}
></input>
</ListItem>
)}
</List> </List>
<List> <List>
<ListItem title={Locale.Plugin.EditModal.Content}> <ListItem title={Locale.Plugin.EditModal.Content}>
<div style={{ display: "flex", justifyContent: "flex-end" }}> <div className={pluginStyles["plugin-schema"]}>
<input <input
type="text" type="text"
style={{ minWidth: 200, marginRight: 20 }} style={{ minWidth: 200 }}
onInput={(e) => setLoadUrl(e.currentTarget.value)} onInput={(e) => setLoadUrl(e.currentTarget.value)}
></input> ></input>
<IconButton <IconButton

View File

@@ -1465,6 +1465,23 @@ export function Settings() {
} }
></input> ></input>
</ListItem> </ListItem>
<ListItem
title={Locale.Mask.Config.Artifacts.Title}
subTitle={Locale.Mask.Config.Artifacts.SubTitle}
>
<input
aria-label={Locale.Mask.Config.Artifacts.Title}
type="checkbox"
checked={config.enableArtifacts}
onChange={(e) =>
updateConfig(
(config) =>
(config.enableArtifacts = e.currentTarget.checked),
)
}
></input>
</ListItem>
</List> </List>
<SyncItems /> <SyncItems />

View File

@@ -10,7 +10,7 @@ export const getBuildConfig = () => {
const buildMode = process.env.BUILD_MODE ?? "standalone"; const buildMode = process.env.BUILD_MODE ?? "standalone";
const isApp = !!process.env.BUILD_APP; const isApp = !!process.env.BUILD_APP;
const version = "v" + tauriConfig.package.version; const version = "v" + tauriConfig.version;
const commitInfo = (() => { const commitInfo = (() => {
try { try {

View File

@@ -154,8 +154,8 @@ export const getServerSideConfig = () => {
// `[Server Config] using ${randomIndex + 1} of ${apiKeys.length} api key`, // `[Server Config] using ${randomIndex + 1} of ${apiKeys.length} api key`,
// ); // );
const allowedWebDevEndpoints = ( const allowedWebDavEndpoints = (
process.env.WHITE_WEBDEV_ENDPOINTS ?? "" process.env.WHITE_WEBDAV_ENDPOINTS ?? ""
).split(","); ).split(",");
return { return {
@@ -229,6 +229,6 @@ export const getServerSideConfig = () => {
disableFastLink: !!process.env.DISABLE_FAST_LINK, disableFastLink: !!process.env.DISABLE_FAST_LINK,
customModels, customModels,
defaultModel, defaultModel,
allowedWebDevEndpoints, allowedWebDavEndpoints,
}; };
}; };

View File

@@ -11,7 +11,6 @@ export const RUNTIME_CONFIG_DOM = "danger-runtime-config";
export const STABILITY_BASE_URL = "https://api.stability.ai"; export const STABILITY_BASE_URL = "https://api.stability.ai";
export const DEFAULT_API_HOST = "https://api.nextchat.dev";
export const OPENAI_BASE_URL = "https://api.openai.com"; export const OPENAI_BASE_URL = "https://api.openai.com";
export const ANTHROPIC_BASE_URL = "https://api.anthropic.com"; export const ANTHROPIC_BASE_URL = "https://api.anthropic.com";

View File

@@ -1,6 +1,5 @@
import { import {
ApiPath, ApiPath,
DEFAULT_API_HOST,
GoogleSafetySettingsThreshold, GoogleSafetySettingsThreshold,
ServiceProvider, ServiceProvider,
StoreKey, StoreKey,
@@ -15,46 +14,6 @@ let fetchState = 0; // 0 not fetch, 1 fetching, 2 done
const isApp = getClientConfig()?.buildMode === "export"; const isApp = getClientConfig()?.buildMode === "export";
const DEFAULT_OPENAI_URL = isApp
? DEFAULT_API_HOST + "/api/proxy/openai"
: ApiPath.OpenAI;
const DEFAULT_GOOGLE_URL = isApp
? DEFAULT_API_HOST + "/api/proxy/google"
: ApiPath.Google;
const DEFAULT_ANTHROPIC_URL = isApp
? DEFAULT_API_HOST + "/api/proxy/anthropic"
: ApiPath.Anthropic;
const DEFAULT_BAIDU_URL = isApp
? DEFAULT_API_HOST + "/api/proxy/baidu"
: ApiPath.Baidu;
const DEFAULT_BYTEDANCE_URL = isApp
? DEFAULT_API_HOST + "/api/proxy/bytedance"
: ApiPath.ByteDance;
const DEFAULT_ALIBABA_URL = isApp
? DEFAULT_API_HOST + "/api/proxy/alibaba"
: ApiPath.Alibaba;
const DEFAULT_TENCENT_URL = isApp
? DEFAULT_API_HOST + "/api/proxy/tencent"
: ApiPath.Tencent;
const DEFAULT_MOONSHOT_URL = isApp
? DEFAULT_API_HOST + "/api/proxy/moonshot"
: ApiPath.Moonshot;
const DEFAULT_STABILITY_URL = isApp
? DEFAULT_API_HOST + "/api/proxy/stability"
: ApiPath.Stability;
const DEFAULT_IFLYTEK_URL = isApp
? DEFAULT_API_HOST + "/api/proxy/iflytek"
: ApiPath.Iflytek;
const DEFAULT_ACCESS_STATE = { const DEFAULT_ACCESS_STATE = {
accessCode: "", accessCode: "",
useCustomConfig: false, useCustomConfig: false,
@@ -62,7 +21,7 @@ const DEFAULT_ACCESS_STATE = {
provider: ServiceProvider.OpenAI, provider: ServiceProvider.OpenAI,
// openai // openai
openaiUrl: DEFAULT_OPENAI_URL, openaiUrl: ApiPath.OpenAI as string,
openaiApiKey: "", openaiApiKey: "",
// azure // azure
@@ -71,44 +30,44 @@ const DEFAULT_ACCESS_STATE = {
azureApiVersion: "2023-08-01-preview", azureApiVersion: "2023-08-01-preview",
// google ai studio // google ai studio
googleUrl: DEFAULT_GOOGLE_URL, googleUrl: ApiPath.Google as string,
googleApiKey: "", googleApiKey: "",
googleApiVersion: "v1", googleApiVersion: "v1",
googleSafetySettings: GoogleSafetySettingsThreshold.BLOCK_ONLY_HIGH, googleSafetySettings: GoogleSafetySettingsThreshold.BLOCK_ONLY_HIGH,
// anthropic // anthropic
anthropicUrl: DEFAULT_ANTHROPIC_URL, anthropicUrl: ApiPath.Anthropic as string,
anthropicApiKey: "", anthropicApiKey: "",
anthropicApiVersion: "2023-06-01", anthropicApiVersion: "2023-06-01",
// baidu // baidu
baiduUrl: DEFAULT_BAIDU_URL, baiduUrl: ApiPath.Baidu as string,
baiduApiKey: "", baiduApiKey: "",
baiduSecretKey: "", baiduSecretKey: "",
// bytedance // bytedance
bytedanceUrl: DEFAULT_BYTEDANCE_URL, bytedanceUrl: ApiPath.ByteDance as string,
bytedanceApiKey: "", bytedanceApiKey: "",
// alibaba // alibaba
alibabaUrl: DEFAULT_ALIBABA_URL, alibabaUrl: ApiPath.Alibaba as string,
alibabaApiKey: "", alibabaApiKey: "",
// moonshot // moonshot
moonshotUrl: DEFAULT_MOONSHOT_URL, moonshotUrl: ApiPath.Moonshot as string,
moonshotApiKey: "", moonshotApiKey: "",
//stability //stability
stabilityUrl: DEFAULT_STABILITY_URL, stabilityUrl: ApiPath.Stability as string,
stabilityApiKey: "", stabilityApiKey: "",
// tencent // tencent
tencentUrl: DEFAULT_TENCENT_URL, tencentUrl: ApiPath.Tencent as string,
tencentSecretKey: "", tencentSecretKey: "",
tencentSecretId: "", tencentSecretId: "",
// iflytek // iflytek
iflytekUrl: DEFAULT_IFLYTEK_URL, iflytekUrl: ApiPath.Iflytek as string,
iflytekApiKey: "", iflytekApiKey: "",
iflytekApiSecret: "", iflytekApiSecret: "",

View File

@@ -50,6 +50,8 @@ export const DEFAULT_CONFIG = {
enableAutoGenerateTitle: true, enableAutoGenerateTitle: true,
sidebarWidth: DEFAULT_SIDEBAR_WIDTH, sidebarWidth: DEFAULT_SIDEBAR_WIDTH,
enableArtifacts: true, // show artifacts config
disablePromptHint: false, disablePromptHint: false,
dontShowMaskSplashScreen: false, // dont show splash screen when create chat dontShowMaskSplashScreen: false, // dont show splash screen when create chat

View File

@@ -2,8 +2,12 @@ import OpenAPIClientAxios from "openapi-client-axios";
import { StoreKey } from "../constant"; import { StoreKey } from "../constant";
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import { createPersistStore } from "../utils/store"; import { createPersistStore } from "../utils/store";
import { getClientConfig } from "../config/client";
import yaml from "js-yaml"; import yaml from "js-yaml";
import { adapter } from "../utils"; import { adapter } from "../utils";
import { useAccessStore } from "./access";
const isApp = getClientConfig()?.isApp;
export type Plugin = { export type Plugin = {
id: string; id: string;
@@ -16,7 +20,6 @@ export type Plugin = {
authLocation?: string; authLocation?: string;
authHeader?: string; authHeader?: string;
authToken?: string; authToken?: string;
usingProxy?: boolean;
}; };
export type FunctionToolItem = { export type FunctionToolItem = {
@@ -46,18 +49,25 @@ export const FunctionToolService = {
plugin?.authType == "basic" plugin?.authType == "basic"
? `Basic ${plugin?.authToken}` ? `Basic ${plugin?.authToken}`
: plugin?.authType == "bearer" : plugin?.authType == "bearer"
? ` Bearer ${plugin?.authToken}` ? `Bearer ${plugin?.authToken}`
: plugin?.authToken; : plugin?.authToken;
const authLocation = plugin?.authLocation || "header"; const authLocation = plugin?.authLocation || "header";
const definition = yaml.load(plugin.content) as any; const definition = yaml.load(plugin.content) as any;
const serverURL = definition?.servers?.[0]?.url; const serverURL = definition?.servers?.[0]?.url;
const baseURL = !!plugin?.usingProxy ? "/api/proxy" : serverURL; const baseURL = !isApp ? "/api/proxy" : serverURL;
const headers: Record<string, string | undefined> = { const headers: Record<string, string | undefined> = {
"X-Base-URL": !!plugin?.usingProxy ? serverURL : undefined, "X-Base-URL": !isApp ? serverURL : undefined,
}; };
if (authLocation == "header") { if (authLocation == "header") {
headers[headerName] = tokenValue; headers[headerName] = tokenValue;
} }
// try using openaiApiKey for Dalle3 Plugin.
if (!tokenValue && plugin.id === "dalle3") {
const openaiApiKey = useAccessStore.getState().openaiApiKey;
if (openaiApiKey) {
headers[headerName] = `Bearer ${openaiApiKey}`;
}
}
const api = new OpenAPIClientAxios({ const api = new OpenAPIClientAxios({
definition: yaml.load(plugin.content) as any, definition: yaml.load(plugin.content) as any,
axiosConfigDefaults: { axiosConfigDefaults: {
@@ -165,7 +175,7 @@ export const usePluginStore = createPersistStore(
(set, get) => ({ (set, get) => ({
create(plugin?: Partial<Plugin>) { create(plugin?: Partial<Plugin>) {
const plugins = get().plugins; const plugins = get().plugins;
const id = nanoid(); const id = plugin?.id || nanoid();
plugins[id] = { plugins[id] = {
...createEmptyPlugin(), ...createEmptyPlugin(),
...plugin, ...plugin,
@@ -220,5 +230,42 @@ export const usePluginStore = createPersistStore(
{ {
name: StoreKey.Plugin, name: StoreKey.Plugin,
version: 1, version: 1,
onRehydrateStorage(state) {
// Skip store rehydration on server side
if (typeof window === "undefined") {
return;
}
fetch("./plugins.json")
.then((res) => res.json())
.then((res) => {
Promise.all(
res.map((item: any) =>
// skip get schema
state.get(item.id)
? item
: fetch(item.schema)
.then((res) => res.text())
.then((content) => ({
...item,
content,
}))
.catch((e) => item),
),
).then((builtinPlugins: any) => {
builtinPlugins
.filter((item: any) => item?.content)
.forEach((item: any) => {
const plugin = state.create(item);
state.updatePlugin(plugin.id, (plugin) => {
const tool = FunctionToolService.add(plugin, true);
plugin.title = tool.api.definition.info.title;
plugin.version = tool.api.definition.info.version;
plugin.builtin = true;
});
});
});
});
},
}, },
); );

View File

@@ -1,7 +1,7 @@
import Fuse from "fuse.js"; import Fuse from "fuse.js";
import { getLang } from "../locales";
import { StoreKey } from "../constant";
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import { StoreKey } from "../constant";
import { getLang } from "../locales";
import { createPersistStore } from "../utils/store"; import { createPersistStore } from "../utils/store";
export interface Prompt { export interface Prompt {
@@ -147,6 +147,11 @@ export const usePromptStore = createPersistStore(
}, },
onRehydrateStorage(state) { onRehydrateStorage(state) {
// Skip store rehydration on server side
if (typeof window === "undefined") {
return;
}
const PROMPT_URL = "./prompts.json"; const PROMPT_URL = "./prompts.json";
type PromptList = Array<[string, string]>; type PromptList = Array<[string, string]>;

View File

@@ -12,7 +12,6 @@ import { downloadAs, readFromFile } from "../utils";
import { showToast } from "../components/ui-lib"; import { showToast } from "../components/ui-lib";
import Locale from "../locales"; import Locale from "../locales";
import { createSyncClient, ProviderType } from "../utils/cloud"; import { createSyncClient, ProviderType } from "../utils/cloud";
import { corsPath } from "../utils/cors";
export interface WebDavConfig { export interface WebDavConfig {
server: string; server: string;
@@ -26,7 +25,7 @@ export type SyncStore = GetStoreState<typeof useSyncStore>;
const DEFAULT_SYNC_STATE = { const DEFAULT_SYNC_STATE = {
provider: ProviderType.WebDAV, provider: ProviderType.WebDAV,
useProxy: true, useProxy: true,
proxyUrl: corsPath(ApiPath.Cors), proxyUrl: ApiPath.Cors as string,
webdav: { webdav: {
endpoint: "", endpoint: "",

View File

@@ -2,8 +2,8 @@ import { useEffect, useState } from "react";
import { showToast } from "./components/ui-lib"; import { showToast } from "./components/ui-lib";
import Locale from "./locales"; import Locale from "./locales";
import { RequestMessage } from "./client/api"; import { RequestMessage } from "./client/api";
import { ServiceProvider, REQUEST_TIMEOUT_MS } from "./constant"; import { ServiceProvider } from "./constant";
import { fetch as tauriFetch, ResponseType } from "@tauri-apps/api/http"; import { fetch as tauriFetch } from "@tauri-apps/plugin-http";
export function trimTopic(topic: string) { export function trimTopic(topic: string) {
// Fix an issue where double quotes still show in the Indonesian language // Fix an issue where double quotes still show in the Indonesian language
@@ -292,19 +292,7 @@ export function fetch(
options?: Record<string, unknown>, options?: Record<string, unknown>,
): Promise<any> { ): Promise<any> {
if (window.__TAURI__) { if (window.__TAURI__) {
const payload = options?.body || options?.data; return tauriFetch(url, options);
return tauriFetch(url, {
...options,
body:
payload &&
({
type: "Text",
payload,
} as any),
timeout: ((options?.timeout as number) || REQUEST_TIMEOUT_MS) / 1000,
responseType:
options?.responseType == "text" ? ResponseType.Text : ResponseType.JSON,
} as any);
} }
return window.fetch(url, options); return window.fetch(url, options);
} }
@@ -315,7 +303,12 @@ export function adapter(config: Record<string, unknown>) {
const fetchUrl = params const fetchUrl = params
? `${path}?${new URLSearchParams(params as any).toString()}` ? `${path}?${new URLSearchParams(params as any).toString()}`
: path; : path;
return fetch(fetchUrl as string, { ...rest, responseType: "text" }); if (window.__TAURI__) {
return tauriFetch(fetchUrl as string, rest)
.then((res) => res.text())
.then((data: any) => ({ data }));
}
return window.fetch(fetchUrl as string, rest);
} }
export function safeLocalStorage(): { export function safeLocalStorage(): {

View File

@@ -10,6 +10,7 @@ import {
fetchEventSource, fetchEventSource,
} from "@fortaine/fetch-event-source"; } from "@fortaine/fetch-event-source";
import { prettyObject } from "./format"; import { prettyObject } from "./format";
import { fetch } from "@/app/utils";
export function compressImage(file: Blob, maxSize: number): Promise<string> { export function compressImage(file: Blob, maxSize: number): Promise<string> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@@ -287,6 +288,7 @@ export function stream(
REQUEST_TIMEOUT_MS, REQUEST_TIMEOUT_MS,
); );
fetchEventSource(chatPath, { fetchEventSource(chatPath, {
fetch: fetch as any, // using tauriFetch or window.fetch
...chatPayload, ...chatPayload,
async onopen(res) { async onopen(res) {
clearTimeout(requestTimeoutId); clearTimeout(requestTimeoutId);

View File

@@ -1,19 +0,0 @@
import { getClientConfig } from "../config/client";
import { DEFAULT_API_HOST } from "../constant";
export function corsPath(path: string) {
const baseUrl = getClientConfig()?.isApp ? `${DEFAULT_API_HOST}` : "";
if (baseUrl === "" && path === "") {
return "";
}
if (!path.startsWith("/")) {
path = "/" + path;
}
if (!path.endsWith("/")) {
path += "/";
}
return `${baseUrl}${path}`;
}

View File

@@ -13,6 +13,9 @@
"export:dev": "concurrently -r \"yarn mask:watch\" \"cross-env BUILD_MODE=export BUILD_APP=1 next dev\"", "export:dev": "concurrently -r \"yarn mask:watch\" \"cross-env BUILD_MODE=export BUILD_APP=1 next dev\"",
"app:dev": "concurrently -r \"yarn mask:watch\" \"yarn tauri dev\"", "app:dev": "concurrently -r \"yarn mask:watch\" \"yarn tauri dev\"",
"app:build": "yarn mask && yarn tauri build", "app:build": "yarn mask && yarn tauri build",
"ios:init": "yarn tauri ios init",
"ios:dev": "concurrently -r \"yarn mask:watch\" \"yarn tauri ios dev\"",
"ios:build": "yarn mask && yarn tauri ios build",
"prompts": "node ./scripts/fetch-prompts.mjs", "prompts": "node ./scripts/fetch-prompts.mjs",
"prepare": "husky install", "prepare": "husky install",
"proxy-dev": "sh ./scripts/init-proxy.sh && proxychains -f ./scripts/proxychains.conf yarn dev" "proxy-dev": "sh ./scripts/init-proxy.sh && proxychains -f ./scripts/proxychains.conf yarn dev"
@@ -22,6 +25,7 @@
"@hello-pangea/dnd": "^16.5.0", "@hello-pangea/dnd": "^16.5.0",
"@next/third-parties": "^14.1.0", "@next/third-parties": "^14.1.0",
"@svgr/webpack": "^6.5.1", "@svgr/webpack": "^6.5.1",
"@tauri-apps/plugin-http": "^2.0.0-rc.2",
"@vercel/analytics": "^0.1.11", "@vercel/analytics": "^0.1.11",
"@vercel/speed-insights": "^1.0.2", "@vercel/speed-insights": "^1.0.2",
"axios": "^1.7.5", "axios": "^1.7.5",
@@ -31,8 +35,8 @@
"html-to-image": "^1.11.11", "html-to-image": "^1.11.11",
"idb-keyval": "^6.2.1", "idb-keyval": "^6.2.1",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"mermaid": "^10.6.1",
"markdown-to-txt": "^2.0.1", "markdown-to-txt": "^2.0.1",
"mermaid": "^10.6.1",
"nanoid": "^5.0.3", "nanoid": "^5.0.3",
"next": "^14.1.1", "next": "^14.1.1",
"node-fetch": "^3.3.1", "node-fetch": "^3.3.1",
@@ -52,8 +56,7 @@
"zustand": "^4.3.8" "zustand": "^4.3.8"
}, },
"devDependencies": { "devDependencies": {
"@tauri-apps/api": "^1.6.0", "@tauri-apps/cli": "^2.0.0-rc.0",
"@tauri-apps/cli": "1.5.11",
"@types/js-yaml": "4.0.9", "@types/js-yaml": "4.0.9",
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
"@types/node": "^20.11.30", "@types/node": "^20.11.30",
@@ -80,4 +83,4 @@
"lint-staged/yaml": "^2.2.2" "lint-staged/yaml": "^2.2.2"
}, },
"packageManager": "yarn@1.22.19" "packageManager": "yarn@1.22.19"
} }

17
public/plugins.json Normal file
View File

@@ -0,0 +1,17 @@
[
{
"id": "dalle3",
"name": "Dalle3",
"schema": "https://ghp.ci/https://raw.githubusercontent.com/ChatGPTNextWeb/NextChat-Awesome-Plugins/main/plugins/dalle/openapi.json"
},
{
"id": "arxivsearch",
"name": "ArxivSearch",
"schema": "https://ghp.ci/https://raw.githubusercontent.com/ChatGPTNextWeb/NextChat-Awesome-Plugins/main/plugins/arxivsearch/openapi.json"
},
{
"id": "duckduckgolite",
"name": "DuckDuckGoLiteSearch",
"schema": "https://ghp.ci/https://raw.githubusercontent.com/ChatGPTNextWeb/NextChat-Awesome-Plugins/main/plugins/duckduckgolite/openapi.json"
}
]

View File

@@ -1,3 +1,4 @@
# Generated by Cargo # Generated by Cargo
# will have compiled files and executables # will have compiled files and executables
/target/ /target/
/gen/

3839
src-tauri/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -2,44 +2,47 @@
name = "nextchat" name = "nextchat"
version = "0.1.0" version = "0.1.0"
description = "A cross platform app for LLM ChatBot." description = "A cross platform app for LLM ChatBot."
authors = ["Yidadaa"] authors = ["GPTsMotion Tech LLC"]
license = "mit" license = "mit"
repository = "" repository = "https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web"
default-run = "nextchat" default-run = "nextchat"
edition = "2021" edition = "2021"
rust-version = "1.60" rust-version = "1.71"
[lib]
name = "nextchat"
crate-type = ["staticlib", "cdylib", "rlib"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[build-dependencies] [build-dependencies]
tauri-build = { version = "1.5.1", features = [] } tauri-build = { version = "2.0.0-rc", features = [] }
[dependencies] [dependencies]
serde_json = "1.0" serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
tauri = { version = "1.5.4", features = [ "http-all", log = "0.4"
"notification-all", tauri = { version = "2.0.0-rc.15", features = [] }
"fs-all", tauri-plugin-log = "2.0.0-rc"
"clipboard-all", tauri-plugin-http = "2.0.0-rc.5"
"dialog-all",
"shell-open", [replace]
"updater", # using this version from github fixed data_directory for webkitgtk
"window-close", "wry:0.43.1" = { git = "https://github.com/lloydzhou/wry", branch="webkitgtk-data_manager-directory" }
"window-hide",
"window-maximize", # Optimize for smaller binary size
"window-minimize", [profile.release]
"window-set-icon", panic = "abort" # Strip expensive panic clean-up logic
"window-set-ignore-cursor-events", codegen-units = 1 # Compile crates one after another so the compiler can optimize better
"window-set-resizable", lto = true # Enables link to optimizations
"window-show", opt-level = "s" # Optimize for binary size
"window-start-dragging", strip = true # Remove debug symbols
"window-unmaximize",
"window-unminimize",
] }
tauri-plugin-window-state = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" }
[features] [features]
# this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled. # 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. # 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!! # DO NOT REMOVE!!
custom-protocol = ["tauri/custom-protocol"] custom-protocol = ["tauri/custom-protocol"]

View File

@@ -0,0 +1,22 @@
{
"identifier": "main",
"description": "permissions for desktop app",
"local": true,
"windows": ["main"],
"permissions": [
"core:default",
"core:window:allow-start-dragging",
"core:window:allow-maximize",
{
"identifier": "http:default",
"allow": [
{
"url": "https://*"
},
{
"url": "http://*"
}
]
}
]
}

17
src-tauri/src/lib.rs Normal file
View File

@@ -0,0 +1,17 @@
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_http::init())
.setup(|app| {
if cfg!(debug_assertions) {
app.handle().plugin(
tauri_plugin_log::Builder::default()
.level(log::LevelFilter::Info)
.build(),
)?;
}
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

View File

@@ -1,9 +1,4 @@
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
fn main() { fn main() {
tauri::Builder::default() nextchat::run()
.plugin(tauri_plugin_window_state::Builder::default().build()) }
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

View File

@@ -1,110 +1,18 @@
{ {
"$schema": "../node_modules/@tauri-apps/cli/schema.json", "$schema": "../node_modules/@tauri-apps/cli/schema.json",
"productName": "NextChat",
"mainBinaryName": "next-chat",
"identifier": "com.yida.chatgpt.next.web",
"version": "2.15.4",
"build": { "build": {
"beforeBuildCommand": "yarn export", "beforeBuildCommand": "yarn export",
"beforeDevCommand": "yarn export:dev", "beforeDevCommand": "yarn export:dev",
"devPath": "http://localhost:3000", "devUrl": "http://localhost:3000",
"distDir": "../out", "frontendDist": "../out"
"withGlobalTauri": true
}, },
"package": { "plugins": {},
"productName": "NextChat", "app": {
"version": "2.15.2" "withGlobalTauri": true,
},
"tauri": {
"allowlist": {
"all": false,
"shell": {
"all": false,
"open": true
},
"dialog": {
"all": true,
"ask": true,
"confirm": true,
"message": true,
"open": true,
"save": true
},
"clipboard": {
"all": true,
"writeText": true,
"readText": true
},
"window": {
"all": false,
"close": true,
"hide": true,
"maximize": true,
"minimize": true,
"setIcon": true,
"setIgnoreCursorEvents": true,
"setResizable": true,
"show": true,
"startDragging": true,
"unmaximize": true,
"unminimize": true
},
"fs": {
"all": true
},
"notification": {
"all": true
},
"http": {
"all": true,
"request": true,
"scope": ["https://*", "http://*"]
}
},
"bundle": {
"active": true,
"category": "DeveloperTool",
"copyright": "2023, Zhang Yifei All Rights Reserved.",
"deb": {
"depends": []
},
"externalBin": [],
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
],
"identifier": "com.yida.chatgpt.next.web",
"longDescription": "NextChat is a cross-platform ChatGPT client, including Web/Win/Linux/OSX/PWA.",
"macOS": {
"entitlements": null,
"exceptionDomain": "",
"frameworks": [],
"providerShortName": null,
"signingIdentity": null
},
"resources": [],
"shortDescription": "NextChat App",
"targets": "all",
"windows": {
"certificateThumbprint": null,
"digestAlgorithm": "sha256",
"timestampUrl": ""
}
},
"security": {
"csp": null,
"dangerousUseHttpScheme": true
},
"updater": {
"active": true,
"endpoints": [
"https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web/releases/latest/download/latest.json"
],
"dialog": false,
"windows": {
"installMode": "passive"
},
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IERFNDE4MENFM0Y1RTZBOTQKUldTVWFsNC96b0JCM3RqM2NmMnlFTmxIaStRaEJrTHNOU2VqRVlIV1hwVURoWUdVdEc1eDcxVEYK"
},
"windows": [ "windows": [
{ {
"fullscreen": false, "fullscreen": false,
@@ -115,6 +23,27 @@
"hiddenTitle": true, "hiddenTitle": true,
"titleBarStyle": "Overlay" "titleBarStyle": "Overlay"
} }
],
"security": {
"csp": null
}
},
"bundle": {
"active": true,
"targets": "all",
"category": "Utility",
"copyright": "Copyright © 2024 GPTsMotion Tech LLC All Rights Reserved.",
"shortDescription": "NextChat App",
"longDescription": "Experience NextChat: Local-first, seamless, and designed for the ultimate chat experience",
"macOS": {
"signingIdentity": "-"
},
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
] ]
} }
} }

5313
yarn.lock

File diff suppressed because it is too large Load Diff