diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index b7e0de26d..197e2f0db 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -43,10 +43,10 @@ jobs: uses: docker/build-push-action@v4 with: context: . - platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8 + platforms: linux/amd64 push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max - \ No newline at end of file + diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml new file mode 100644 index 000000000..9914a603a --- /dev/null +++ b/.github/workflows/sync.yml @@ -0,0 +1,16 @@ +# .github/workflows/sync.yml +name: Sync Fork + +on: + schedule: + - cron: "0 8 * * *" # 每天0点触发 +jobs: + repo-sync: + runs-on: ubuntu-latest + steps: + - uses: TG908/fork-sync@v1.1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} # 这个 token action 会默认配置, 这里只需这样写就行 + owner: Yidadaa # fork 上游项目 owner + head: main # fork 上游项目需要同步的分支 + base: main # 需要同步到本项目的目标分支 diff --git a/Dockerfile b/Dockerfile index f97618e70..6f7547b21 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,13 +6,9 @@ RUN apk add --no-cache libc6-compat WORKDIR /app -COPY package.json yarn.lock* package-lock.json* ./ +COPY package.json yarn.lock ./ -RUN \ - if [ -f yarn.lock ]; then yarn install --frozen-lockfile --network-timeout 100000; \ - elif [ -f package-lock.json ]; then npm ci; \ - else echo "Lockfile not found." && exit 1; \ - fi +RUN yarn install FROM base AS builder diff --git a/README.md b/README.md index 5952aa33a..cd5dcc7a4 100644 --- a/README.md +++ b/README.md @@ -191,4 +191,4 @@ docker run -d -p 3000:3000 -e OPENAI_API_KEY="" -e CODE="" yidadaa/chatgpt-next- ## LICENSE -- [Anti 996 License](https://github.com/kattgu7/Anti-996-License/blob/master/LICENSE_CN_EN) +[Anti 996 License](https://github.com/kattgu7/Anti-996-License/blob/master/LICENSE_CN_EN) diff --git a/app/components/home.module.scss b/app/components/home.module.scss index 87231feee..cef1662b5 100644 --- a/app/components/home.module.scss +++ b/app/components/home.module.scss @@ -26,13 +26,13 @@ @media only screen and (min-width: 600px) { .tight-container { --window-width: 100vw; - --window-height: 100vh; + --window-height: var(--full-height); --window-content-width: calc(100% - var(--sidebar-width)); @include container(); max-width: 100vw; - max-height: 100vh; + max-height: var(--full-height); border-radius: 0; } @@ -74,7 +74,7 @@ position: absolute; left: -100%; z-index: 999; - height: 100vh; + height: var(--full-height); transition: all ease 0.3s; box-shadow: none; } diff --git a/app/components/home.tsx b/app/components/home.tsx index cecd5c104..d7eb1b8af 100644 --- a/app/components/home.tsx +++ b/app/components/home.tsx @@ -24,7 +24,13 @@ import DownloadIcon from "../icons/download.svg"; import { Message, SubmitKey, useChatStore, ChatSession } from "../store"; import { showModal, showToast } from "./ui-lib"; -import { copyToClipboard, downloadAs, isIOS, selectOrCopy } from "../utils"; +import { + copyToClipboard, + downloadAs, + isIOS, + isMobileScreen, + selectOrCopy, +} from "../utils"; import Locale from "../locales"; import dynamic from "next/dynamic"; @@ -285,9 +291,7 @@ export function Chat(props: { // for auto-scroll const latestMessageRef = useRef(null); - - // wont scroll while hovering messages - const [autoScroll, setAutoScroll] = useState(false); + const [autoScroll, setAutoScroll] = useState(true); // preview messages const messages = (session.messages as RenderMessage[]) @@ -320,7 +324,17 @@ export function Chat(props: { useLayoutEffect(() => { setTimeout(() => { const dom = latestMessageRef.current; - if (dom && !isIOS() && autoScroll) { + const inputDom = inputRef.current; + + // only scroll when input overlaped message body + let shouldScroll = true; + if (dom && inputDom) { + const domRect = dom.getBoundingClientRect(); + const inputRect = inputDom.getBoundingClientRect(); + shouldScroll = domRect.top > inputRect.top; + } + + if (dom && autoScroll && shouldScroll) { dom.scrollIntoView({ block: "end", }); @@ -476,7 +490,7 @@ export function Chat(props: { onFocus={() => setAutoScroll(true)} onBlur={() => { setAutoScroll(false); - setTimeout(() => setPromptHints([]), 100); + setTimeout(() => setPromptHints([]), 500); }} autoFocus={!props?.sideBarShowing} /> @@ -618,7 +632,9 @@ export function Home() { return (
void }) { const updateStore = useUpdateStore(); const [checkingUpdate, setCheckingUpdate] = useState(false); - const currentId = getCurrentCommitId(); + const currentId = getCurrentVersion(); const remoteId = updateStore.remoteId; const hasNewVersion = currentId !== remoteId; @@ -267,19 +267,17 @@ export function Settings(props: { closeSettings: () => void }) { > -
- - - updateConfig( - (config) => (config.tightBorder = e.currentTarget.checked), - ) - } - > - -
+ + + updateConfig( + (config) => (config.tightBorder = e.currentTarget.checked), + ) + } + > + void }) { type="range" title={config.historyMessageCount.toString()} value={config.historyMessageCount} - min="2" + min="0" max="25" step="2" onChange={(e) => diff --git a/app/constant.ts b/app/constant.ts index 818ef1fbe..fff77607e 100644 --- a/app/constant.ts +++ b/app/constant.ts @@ -3,3 +3,4 @@ export const REPO = "ChatGPT-Next-Web"; export const REPO_URL = `https://github.com/${OWNER}/${REPO}`; export const UPDATE_URL = `${REPO_URL}#%E4%BF%9D%E6%8C%81%E6%9B%B4%E6%96%B0-keep-updated`; export const FETCH_COMMIT_URL = `https://api.github.com/repos/${OWNER}/${REPO}/commits?per_page=1`; +export const FETCH_TAG_URL = `https://api.github.com/repos/${OWNER}/${REPO}/tags?per_page=1`; diff --git a/app/layout.tsx b/app/layout.tsx index 3a4140460..32d3576c5 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -8,11 +8,12 @@ import { ACCESS_CODES, IS_IN_DOCKER } from "./api/access"; let COMMIT_ID: string | undefined; try { COMMIT_ID = process + // .execSync("git describe --tags --abbrev=0") .execSync("git rev-parse --short HEAD") .toString() .trim(); } catch (e) { - console.error("No git or not from git repo.") + console.error("No git or not from git repo."); } export const metadata = { @@ -22,13 +23,13 @@ export const metadata = { title: "ChatGPT Next Web", statusBarStyle: "black-translucent", }, - themeColor: "#fafafa" + themeColor: "#fafafa", }; function Meta() { const metas = { version: COMMIT_ID ?? "unknown", - access: (ACCESS_CODES.size > 0 || IS_IN_DOCKER) ? "enabled" : "disabled", + access: ACCESS_CODES.size > 0 || IS_IN_DOCKER ? "enabled" : "disabled", }; return ( diff --git a/app/store/app.ts b/app/store/app.ts index 118e9ed6c..6ab3229ac 100644 --- a/app/store/app.ts +++ b/app/store/app.ts @@ -89,7 +89,9 @@ export function isValidNumber(x: number, min: number, max: number) { return typeof x === "number" && x <= max && x >= min; } -export function filterConfig(config: ModelConfig): Partial { +export function filterConfig(oldConfig: ModelConfig): Partial { + const config = Object.assign({}, oldConfig); + const validator: { [k in keyof ModelConfig]: (x: ModelConfig[keyof ModelConfig]) => boolean; } = { @@ -103,7 +105,7 @@ export function filterConfig(config: ModelConfig): Partial { return isValidNumber(x as number, -2, 2); }, temperature(x) { - return isValidNumber(x as number, 0, 1); + return isValidNumber(x as number, 0, 2); }, }; diff --git a/app/store/update.ts b/app/store/update.ts index 118ea3cea..97fb343c3 100644 --- a/app/store/update.ts +++ b/app/store/update.ts @@ -1,7 +1,7 @@ import { create } from "zustand"; import { persist } from "zustand/middleware"; -import { FETCH_COMMIT_URL } from "../constant"; -import { getCurrentCommitId } from "../utils"; +import { FETCH_COMMIT_URL, FETCH_TAG_URL } from "../constant"; +import { getCurrentVersion } from "../utils"; export interface UpdateStore { lastUpdate: number; @@ -19,16 +19,17 @@ export const useUpdateStore = create()( remoteId: "", async getLatestCommitId(force = false) { - const overOneHour = Date.now() - get().lastUpdate > 3600 * 1000; - const shouldFetch = force || overOneHour; + const overTenMins = Date.now() - get().lastUpdate > 10 * 60 * 1000; + const shouldFetch = force || overTenMins; if (!shouldFetch) { - return getCurrentCommitId(); + return getCurrentVersion(); } try { + // const data = await (await fetch(FETCH_TAG_URL)).json(); + // const remoteId = data[0].name as string; const data = await (await fetch(FETCH_COMMIT_URL)).json(); - const sha = data[0].sha as string; - const remoteId = sha.substring(0, 7); + const remoteId = (data[0].sha as string).substring(0, 7); set(() => ({ lastUpdate: Date.now(), remoteId, @@ -37,13 +38,13 @@ export const useUpdateStore = create()( return remoteId; } catch (error) { console.error("[Fetch Upstream Commit Id]", error); - return getCurrentCommitId(); + return getCurrentVersion(); } }, }), { name: UPDATE_KEY, version: 1, - } - ) + }, + ), ); diff --git a/app/styles/globals.scss b/app/styles/globals.scss index b4b25b5cd..c514274ab 100644 --- a/app/styles/globals.scss +++ b/app/styles/globals.scss @@ -53,12 +53,13 @@ --sidebar-width: 300px; --window-content-width: calc(100% - var(--sidebar-width)); --message-max-width: 80%; + --full-height: 100vh; } @media only screen and (max-width: 600px) { :root { --window-width: 100vw; - --window-height: 100vh; + --window-height: var(--full-height); --sidebar-width: 100vw; --window-content-width: var(--window-width); --message-max-width: 100%; @@ -80,14 +81,14 @@ body { color: var(--black); margin: 0; padding: 0; - height: 100vh; + height: var(--full-height); width: 100vw; display: flex; justify-content: center; align-items: center; user-select: none; font-family: "Noto Sans SC", "SF Pro SC", "SF Pro Text", "SF Pro Icons", - "PingFang SC", "Helvetica Neue", "Helvetica", "Arial", sans-serif; + "PingFang SC", "Helvetica Neue", "Helvetica", "Arial", sans-serif; @media only screen and (max-width: 600px) { background-color: var(--second); @@ -119,6 +120,11 @@ select { cursor: pointer; background-color: var(--white); color: var(--black); + text-align: center; +} + +input { + text-align: center; } input[type="checkbox"] { @@ -196,7 +202,7 @@ div.math { position: fixed; top: 0; left: 0; - height: 100vh; + height: var(--full-height); width: 100vw; background-color: rgba($color: #000000, $alpha: 0.5); display: flex; diff --git a/app/styles/prism.scss b/app/styles/prism.scss index 0d011ce0e..65ee8b5fc 100644 --- a/app/styles/prism.scss +++ b/app/styles/prism.scss @@ -120,33 +120,3 @@ cursor: help; } } - -@mixin light { - .markdown-body pre { - filter: invert(1) hue-rotate(90deg) brightness(1.3); - } -} - -@mixin dark { - .markdown-body pre { - filter: none; - } -} - -:root { - @include light(); -} - -.light { - @include light(); -} - -.dark { - @include dark(); -} - -@media (prefers-color-scheme: dark) { - :root { - @include dark(); - } -} diff --git a/app/utils.ts b/app/utils.ts index b32332322..64120df4d 100644 --- a/app/utils.ts +++ b/app/utils.ts @@ -45,6 +45,10 @@ export function isIOS() { return /iphone|ipad|ipod/.test(userAgent); } +export function isMobileScreen() { + return window.innerWidth <= 600; +} + export function selectOrCopy(el: HTMLElement, content: string) { const currentSelection = window.getSelection(); @@ -72,7 +76,7 @@ export function queryMeta(key: string, defaultValue?: string): string { } let currentId: string; -export function getCurrentCommitId() { +export function getCurrentVersion() { if (currentId) { return currentId; } diff --git a/scripts/fetch-prompts.mjs b/scripts/fetch-prompts.mjs index daebfe7a6..3c4801443 100644 --- a/scripts/fetch-prompts.mjs +++ b/scripts/fetch-prompts.mjs @@ -1,10 +1,14 @@ import fetch from "node-fetch"; import fs from "fs/promises"; -const CN_URL = +const RAW_CN_URL = "https://raw.githubusercontent.com/PlexPt/awesome-chatgpt-prompts-zh/main/prompts-zh.json"; -const EN_URL = +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() {