Merge pull request #1969 from Yidadaa/app

feat: ready to release desktop app
This commit is contained in:
Yifei Zhang 2023-06-15 02:53:42 +08:00 committed by GitHub
commit af3a273a56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 132 additions and 16 deletions

91
.github/workflows/app.yml vendored Normal file
View File

@ -0,0 +1,91 @@
name: Release App
on:
workflow_dispatch:
release:
types: [published]
jobs:
create-release:
permissions:
contents: write
runs-on: ubuntu-20.04
outputs:
release_id: ${{ steps.create-release.outputs.result }}
steps:
- uses: actions/checkout@v3
- name: setup node
uses: actions/setup-node@v3
with:
node-version: 16
- name: get version
run: echo "PACKAGE_VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_ENV
- name: create release
id: create-release
uses: actions/github-script@v6
with:
script: |
const { data } = await github.rest.repos.createRelease({
owner: context.repo.owner,
repo: context.repo.repo,
tag_name: `app-v${process.env.PACKAGE_VERSION}`,
name: `Desktop App v${process.env.PACKAGE_VERSION}`,
body: 'Take a look at the assets to download and install this app.',
draft: true,
prerelease: false
})
return data.id
build-tauri:
needs: create-release
permissions:
contents: write
strategy:
fail-fast: false
matrix:
platform: [macos-latest, ubuntu-20.04, windows-latest]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v3
- name: setup node
uses: actions/setup-node@v3
with:
node-version: 16
- name: install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: install dependencies (ubuntu only)
if: matrix.platform == 'ubuntu-20.04'
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
- name: install frontend dependencies
run: yarn install # change this to npm or pnpm depending on which one you use
- uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
releaseId: ${{ needs.create-release.outputs.release_id }}
publish-release:
permissions:
contents: write
runs-on: ubuntu-20.04
needs: [create-release, build-tauri]
steps:
- name: publish release
id: publish-release
uses: actions/github-script@v6
env:
release_id: ${{ needs.create-release.outputs.release_id }}
with:
script: |
github.rest.repos.updateRelease({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: process.env.release_id,
draft: false,
prerelease: false
})

View File

@ -35,6 +35,6 @@ jobs:
- name: Sync check - name: Sync check
if: failure() if: failure()
run: | run: |
echo "::error::由于权限不足,导致同步失败(这是预期的行为),请前往仓库首页手动执行[Sync fork]。" echo "[Error] 由于上游仓库的 workflow 文件变更,导致 GitHub 自动暂停了本次自动更新,你需要手动 Sync Fork 一次详细教程请查看https://github.com/Yidadaa/ChatGPT-Next-Web/blob/main/README_CN.md#%E6%89%93%E5%BC%80%E8%87%AA%E5%8A%A8%E6%9B%B4%E6%96%B0"
echo "::error::Due to insufficient permissions, synchronization failed (as expected). Please go to the repository homepage and manually perform [Sync fork]." echo "[Error] Due to a change in the workflow file of the upstream repository, GitHub has automatically suspended the scheduled automatic update. You need to manually sync your fork. Please refer to the detailed tutorial for instructions: https://github.com/Yidadaa/ChatGPT-Next-Web#enable-automatic-updates"
exit 1 exit 1

View File

@ -1,5 +1,11 @@
import { useDebouncedCallback } from "use-debounce"; import { useDebouncedCallback } from "use-debounce";
import React, { useState, useRef, useEffect, useLayoutEffect } from "react"; import React, {
useState,
useRef,
useEffect,
useLayoutEffect,
useMemo,
} from "react";
import SendWhiteIcon from "../icons/send-white.svg"; import SendWhiteIcon from "../icons/send-white.svg";
import BrainIcon from "../icons/brain.svg"; import BrainIcon from "../icons/brain.svg";
@ -61,6 +67,7 @@ import { useMaskStore } from "../store/mask";
import { useCommand } from "../command"; import { useCommand } from "../command";
import { prettyObject } from "../utils/format"; import { prettyObject } from "../utils/format";
import { ExportMessageModal } from "./exporter"; import { ExportMessageModal } from "./exporter";
import { getClientConfig } from "../config/client";
const Markdown = dynamic(async () => (await import("./markdown")).Markdown, { const Markdown = dynamic(async () => (await import("./markdown")).Markdown, {
loading: () => <LoadingIcon />, loading: () => <LoadingIcon />,
@ -704,9 +711,13 @@ export function Chat() {
} }
}; };
const clientConfig = useMemo(() => getClientConfig(), []);
const location = useLocation(); const location = useLocation();
const isChat = location.pathname === Path.Chat; const isChat = location.pathname === Path.Chat;
const autoFocus = !isMobileScreen || isChat; // only focus in chat page const autoFocus = !isMobileScreen || isChat; // only focus in chat page
const showMaxIcon = !isMobileScreen && !clientConfig?.isApp;
useCommand({ useCommand({
fill: setUserInput, fill: setUserInput,
@ -755,7 +766,7 @@ export function Chat() {
}} }}
/> />
</div> </div>
{!isMobileScreen && ( {showMaxIcon && (
<div className="window-action-button"> <div className="window-action-button">
<IconButton <IconButton
icon={config.tightBorder ? <MinIcon /> : <MaxIcon />} icon={config.tightBorder ? <MinIcon /> : <MaxIcon />}

View File

@ -94,9 +94,14 @@ const useHasHydrated = () => {
const loadAsyncGoogleFont = () => { const loadAsyncGoogleFont = () => {
const linkEl = document.createElement("link"); const linkEl = document.createElement("link");
const proxyFontUrl = "/google-fonts";
const remoteFontUrl = "https://fonts.googleapis.com";
const googleFontUrl =
getClientConfig()?.buildMode === "export" ? remoteFontUrl : proxyFontUrl;
linkEl.rel = "stylesheet"; linkEl.rel = "stylesheet";
linkEl.href = linkEl.href =
"/google-fonts/css2?family=Noto+Sans+SC:wght@300;400;700;900&display=swap"; googleFontUrl +
"/css2?family=Noto+Sans+SC:wght@300;400;700;900&display=swap";
document.head.appendChild(linkEl); document.head.appendChild(linkEl);
}; };

View File

@ -286,6 +286,9 @@ export function Settings() {
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, []); }, []);
const clientConfig = useMemo(() => getClientConfig(), []);
const showAccessCode = enabledAccessControl && !clientConfig?.isApp;
return ( return (
<ErrorBoundary> <ErrorBoundary>
<div className="window-header"> <div className="window-header">
@ -485,7 +488,7 @@ export function Settings() {
</List> </List>
<List> <List>
{enabledAccessControl ? ( {showAccessCode ? (
<ListItem <ListItem
title={Locale.Settings.AccessCode.Title} title={Locale.Settings.AccessCode.Title}
subTitle={Locale.Settings.AccessCode.SubTitle} subTitle={Locale.Settings.AccessCode.SubTitle}

View File

@ -21,6 +21,7 @@ export const getBuildConfig = () => {
return { return {
commitId: COMMIT_ID, commitId: COMMIT_ID,
buildMode: process.env.BUILD_MODE ?? "standalone", buildMode: process.env.BUILD_MODE ?? "standalone",
isApp: !!process.env.BUILD_APP,
}; };
}; };

View File

@ -11,6 +11,7 @@ declare global {
HIDE_USER_API_KEY?: string; // disable user's api key input HIDE_USER_API_KEY?: string; // disable user's api key input
DISABLE_GPT4?: string; // allow user to use gpt-4 or not DISABLE_GPT4?: string; // allow user to use gpt-4 or not
BUILD_MODE?: "standalone" | "export"; BUILD_MODE?: "standalone" | "export";
BUILD_APP?: string; // is building desktop app
} }
} }
} }

View File

@ -60,7 +60,7 @@ export const useAccessStore = create<AccessControlStore>()(
); );
}, },
fetch() { fetch() {
if (fetchState > 0) return; if (fetchState > 0 || getClientConfig()?.buildMode === "export") return;
fetchState = 1; fetchState = 1;
fetch("/api/config", { fetch("/api/config", {
method: "post", method: "post",

View File

@ -1,6 +1,7 @@
import { create } from "zustand"; import { create } from "zustand";
import { persist } from "zustand/middleware"; import { persist } from "zustand/middleware";
import { StoreKey } from "../constant"; import { StoreKey } from "../constant";
import { getBuildConfig } from "../config/build";
export enum SubmitKey { export enum SubmitKey {
Enter = "Enter", Enter = "Enter",
@ -21,7 +22,7 @@ export const DEFAULT_CONFIG = {
avatar: "1f603", avatar: "1f603",
fontSize: 14, fontSize: 14,
theme: Theme.Auto as Theme, theme: Theme.Auto as Theme,
tightBorder: false, tightBorder: !getBuildConfig().isApp,
sendPreviewBubble: true, sendPreviewBubble: true,
sidebarWidth: 300, sidebarWidth: 300,

View File

@ -7,7 +7,10 @@
"build": "next build", "build": "next build",
"start": "next start", "start": "next start",
"lint": "next lint", "lint": "next lint",
"export": "BUILD_MODE=export yarn build", "export": "cross-env BUILD_MODE=export BUILD_APP=1 yarn build",
"export:dev": "cross-env BUILD_MODE=export BUILD_APP=1 yarn dev",
"app:dev": "yarn tauri dev",
"app:build": "yarn tauri 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"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -1,14 +1,14 @@
{ {
"$schema": "../node_modules/@tauri-apps/cli/schema.json", "$schema": "../node_modules/@tauri-apps/cli/schema.json",
"build": { "build": {
"beforeBuildCommand": "yarn build", "beforeBuildCommand": "yarn export",
"beforeDevCommand": "yarn dev", "beforeDevCommand": "yarn export:dev",
"devPath": "http://localhost:3000", "devPath": "http://localhost:3000",
"distDir": "../out" "distDir": "../out"
}, },
"package": { "package": {
"productName": "chatgpt-next-web", "productName": "chatgpt-next-web",
"version": "2.8" "version": "2.8.1"
}, },
"tauri": { "tauri": {
"allowlist": { "allowlist": {
@ -29,8 +29,8 @@
"icons/icon.icns", "icons/icon.icns",
"icons/icon.ico" "icons/icon.ico"
], ],
"identifier": "com.yida.chatgpt.nextweb", "identifier": "com.yida.chatgpt.next.web",
"longDescription": "", "longDescription": "ChatGPT Next Web is a cross-platform ChatGPT client, including Web/Win/Linux/OSX/PWA.",
"macOS": { "macOS": {
"entitlements": null, "entitlements": null,
"exceptionDomain": "", "exceptionDomain": "",
@ -39,7 +39,7 @@
"signingIdentity": null "signingIdentity": null
}, },
"resources": [], "resources": [],
"shortDescription": "", "shortDescription": "ChatGPT Next Web App",
"targets": "all", "targets": "all",
"windows": { "windows": {
"certificateThumbprint": null, "certificateThumbprint": null,
@ -59,7 +59,7 @@
"height": 600, "height": 600,
"resizable": true, "resizable": true,
"title": "tauri-next", "title": "tauri-next",
"width": 800 "width": 960
} }
] ]
} }