diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..72e9aa4 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,7 @@ +Dockerfile +.dockerignore +node_modules +npm-debug.log +README.md +.next +.git \ No newline at end of file diff --git a/.drone.yml b/.drone.yml index 329d87b..6773fc0 100644 --- a/.drone.yml +++ b/.drone.yml @@ -7,36 +7,15 @@ platform: os: linux arch: amd64 -volumes: - - name: debian-dist - host: - path: /home/debian/dist - steps: - name: build - image: node:23-alpine - commands: - - npm ci - - npm run build - - - name: package - image: node:23-alpine - environment: - ZHIPU_API_KEY: - from_secret: zhipu_api_key - commands: - - apk add zip - - mkdir -p .next/standalone/.next - - cp -r public .next/standalone - - cp -r .next/static .next/standalone/.next - - cd .next/standalone - - echo "$ZHIPU_API_KEY" > zhipu_api_key.txt - - rm -f /dist/learn-languages.zip - - zip -r /dist/learn-languages.zip . - volumes: - - name: debian-dist - path: /dist - + image: plugins/docker + settings: + repo: learn-languages + tags: + - latest + dry_run: true + - name: deploy image: appleboy/drone-ssh settings: @@ -48,24 +27,8 @@ steps: from_secret: ssh_password port: 22 script: - - cd ~/ - - rm -rf learn-languages - - mkdir learn-languages - - unzip -d learn-languages dist/learn-languages.zip - - cd learn-languages - - npm i - - | - if pm2 list | grep -q learn-languages; then - echo "进程 learn-languages 已在pm2中运行,正在重启..." - ZHIPU_API_KEY=`cat zhipu_api_key.txt` PORT=3030 pm2 restart "learn-languages" - else - echo "进程 learn-languages 未在pm2中运行,正在启动..." - ZHIPU_API_KEY=`cat zhipu_api_key.txt` PORT=3030 pm2 start "./server.js" --name "learn-languages" - fi - - pm2 save - - cd ~/ - - rm -rf dist - - mkdir dist + - cd ~/docker/learn-languages + - docker-compose restart || docker-compose up -d debug: true trigger: diff --git a/.gitignore b/.gitignore index 7da0df6..597a03d 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,5 @@ yarn-error.log* next-env.d.ts .env + +build.sh \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..5e980d4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,66 @@ +# syntax=docker.io/docker/dockerfile:1 + +FROM node:23-alpine AS base + +# Install dependencies only when needed +FROM base AS deps +# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. +RUN apk add --no-cache libc6-compat +WORKDIR /app + +# Install dependencies based on the preferred package manager +COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./ +RUN \ + if [ -f yarn.lock ]; then yarn --frozen-lockfile; \ + elif [ -f package-lock.json ]; then npm ci; \ + elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \ + else echo "Lockfile not found." && exit 1; \ + fi + + +# Rebuild the source code only when needed +FROM base AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +# Next.js collects completely anonymous telemetry data about general usage. +# Learn more here: https://nextjs.org/telemetry +# Uncomment the following line in case you want to disable telemetry during the build. +ENV NEXT_TELEMETRY_DISABLED=1 + +RUN \ + if [ -f yarn.lock ]; then yarn run build; \ + elif [ -f package-lock.json ]; then npm run build; \ + elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \ + else echo "Lockfile not found." && exit 1; \ + fi + +# Production image, copy all the files and run next +FROM base AS runner +WORKDIR /app + +ENV NODE_ENV=production +# Uncomment the following line in case you want to disable telemetry during runtime. +ENV NEXT_TELEMETRY_DISABLED=1 + +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +COPY --from=builder /app/public ./public + +# Automatically leverage output traces to reduce image size +# https://nextjs.org/docs/advanced-features/output-file-tracing +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +USER nextjs + +EXPOSE 3000 + +ENV PORT=3000 + +# server.js is created by next build from the standalone output +# https://nextjs.org/docs/pages/api-reference/config/next-config-js/output +ENV HOSTNAME="0.0.0.0" +CMD ["node", "server.js"] diff --git a/package-lock.json b/package-lock.json index 85eef9a..0aa08a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3685,7 +3685,6 @@ "version": "7.2.3", "resolved": "https://mirrors.cloud.tencent.com/npm/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", "license": "ISC", "optional": true, "peer": true, @@ -4710,14 +4709,15 @@ } }, "node_modules/@unimodules/react-native-adapter": { - "version": "6.3.9", - "resolved": "https://mirrors.cloud.tencent.com/npm/@unimodules/react-native-adapter/-/react-native-adapter-6.3.9.tgz", - "integrity": "sha512-i9/9Si4AQ8awls+YGAKkByFbeAsOPgUNeLoYeh2SQ3ddjxJ5ZJDtq/I74clDnpDcn8zS9pYlcDJ9fgVJa39Glw==", + "version": "6.5.0", + "resolved": "https://mirrors.cloud.tencent.com/npm/@unimodules/react-native-adapter/-/react-native-adapter-6.5.0.tgz", + "integrity": "sha512-F2J6gVw9a57DTVTQQunp64fqD4HVBkltOpUz1L5lEccNbQlZEA7SjnqKJzXakI7uPhhN76/n+SGb7ihzHw2swQ==", + "deprecated": "replaced by the 'expo' package, learn more: https://blog.expo.dev/whats-new-in-expo-modules-infrastructure-7a7cdda81ebc", "license": "MIT", "optional": true, "dependencies": { - "expo-modules-autolinking": "^0.0.3", - "invariant": "^2.2.4" + "expo-modules-autolinking": "^0.3.2", + "expo-modules-core": "~0.4.0" } }, "node_modules/@unrs/resolver-binding-android-arm-eabi": { @@ -5188,7 +5188,7 @@ "node_modules/any-promise": { "version": "1.3.0", "resolved": "https://mirrors.cloud.tencent.com/npm/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", "license": "MIT", "optional": true, "peer": true @@ -5396,7 +5396,7 @@ "node_modules/asap": { "version": "2.0.6", "resolved": "https://mirrors.cloud.tencent.com/npm/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", "license": "MIT", "optional": true, "peer": true @@ -5765,7 +5765,7 @@ "node_modules/base-64": { "version": "0.1.0", "resolved": "https://mirrors.cloud.tencent.com/npm/base-64/-/base-64-0.1.0.tgz", - "integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==" + "integrity": "sha1-eAqZyE59YAJgNhURxId2E78k9rs=" }, "node_modules/base64-js": { "version": "1.5.1", @@ -5789,9 +5789,9 @@ "optional": true }, "node_modules/baseline-browser-mapping": { - "version": "2.8.22", - "resolved": "https://mirrors.cloud.tencent.com/npm/baseline-browser-mapping/-/baseline-browser-mapping-2.8.22.tgz", - "integrity": "sha512-/tk9kky/d8T8CTXIQYASLyhAxR5VwL3zct1oAoVTaOUHwrmsGnfbRwNdEq+vOl2BN8i3PcDdP0o4Q+jjKQoFbQ==", + "version": "2.8.23", + "resolved": "https://mirrors.cloud.tencent.com/npm/baseline-browser-mapping/-/baseline-browser-mapping-2.8.23.tgz", + "integrity": "sha512-616V5YX4bepJFzNyOfce5Fa8fDJMfoxzOIzDCZwaGL8MKVpFrXqfNUoIpRn9YMI5pXf/VKgzjB4htFMsFKKdiQ==", "license": "Apache-2.0", "optional": true, "peer": true, @@ -6093,17 +6093,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chownr": { - "version": "3.0.0", - "resolved": "https://mirrors.cloud.tencent.com/npm/chownr/-/chownr-3.0.0.tgz", - "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", - "license": "BlueOak-1.0.0", - "optional": true, - "peer": true, - "engines": { - "node": ">=18" - } - }, "node_modules/chrome-launcher": { "version": "0.15.2", "resolved": "https://mirrors.cloud.tencent.com/npm/chrome-launcher/-/chrome-launcher-0.15.2.tgz", @@ -6374,7 +6363,7 @@ "node_modules/compression/node_modules/ms": { "version": "2.0.0", "resolved": "https://mirrors.cloud.tencent.com/npm/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT", "optional": true, "peer": true @@ -6393,7 +6382,7 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://mirrors.cloud.tencent.com/npm/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "devOptional": true, "license": "MIT" }, @@ -6428,7 +6417,7 @@ "node_modules/connect/node_modules/ms": { "version": "2.0.0", "resolved": "https://mirrors.cloud.tencent.com/npm/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT", "optional": true, "peer": true @@ -6803,7 +6792,7 @@ "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://mirrors.cloud.tencent.com/npm/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", "license": "MIT", "optional": true, "peer": true @@ -6826,7 +6815,7 @@ "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://mirrors.cloud.tencent.com/npm/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", "license": "MIT", "optional": true, "peer": true, @@ -7057,7 +7046,7 @@ "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://mirrors.cloud.tencent.com/npm/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", "license": "MIT", "optional": true, "peer": true @@ -7518,7 +7507,7 @@ "node_modules/etag": { "version": "1.8.1", "resolved": "https://mirrors.cloud.tencent.com/npm/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", "license": "MIT", "optional": true, "peer": true, @@ -7546,9 +7535,9 @@ "peer": true }, "node_modules/expo-modules-autolinking": { - "version": "0.0.3", - "resolved": "https://mirrors.cloud.tencent.com/npm/expo-modules-autolinking/-/expo-modules-autolinking-0.0.3.tgz", - "integrity": "sha512-azkCRYj/DxbK4udDuDxA9beYzQTwpJ5a9QA0bBgha2jHtWdFGF4ZZWSY+zNA5mtU3KqzYt8jWHfoqgSvKyu1Aw==", + "version": "0.3.4", + "resolved": "https://mirrors.cloud.tencent.com/npm/expo-modules-autolinking/-/expo-modules-autolinking-0.3.4.tgz", + "integrity": "sha512-Mu3CIMqEAI8aNM18U/l+7CCi+afU8dERrKjDDEx/Hu7XX3v3FcnnP+NuWDLY/e9/ETzwTJaqoRoBuzhawsuLWw==", "license": "MIT", "optional": true, "dependencies": { @@ -7738,7 +7727,7 @@ "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", "resolved": "https://mirrors.cloud.tencent.com/npm/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT", "optional": true, "peer": true @@ -7881,7 +7870,7 @@ "node_modules/fresh": { "version": "0.5.2", "resolved": "https://mirrors.cloud.tencent.com/npm/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "license": "MIT", "optional": true, "peer": true, @@ -7908,7 +7897,7 @@ "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://mirrors.cloud.tencent.com/npm/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "license": "ISC", "optional": true, "peer": true @@ -9270,7 +9259,6 @@ "version": "7.2.3", "resolved": "https://mirrors.cloud.tencent.com/npm/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", "license": "ISC", "optional": true, "peer": true, @@ -9768,7 +9756,7 @@ "node_modules/isomorphic-webcrypto/node_modules/react-native-securerandom": { "version": "0.1.1", "resolved": "https://mirrors.cloud.tencent.com/npm/react-native-securerandom/-/react-native-securerandom-0.1.1.tgz", - "integrity": "sha1-8TBiOkEsM4sK+t7bwgTFy7i/IHA=", + "integrity": "sha512-CozcCx0lpBLevxiXEb86kwLRalBCHNjiGPlw3P7Fi27U6ZLdfjOCNRHD1LtBKcvPvI3TvkBXB3GOtLvqaYJLGw==", "license": "MIT", "optional": true, "dependencies": { @@ -9824,7 +9812,6 @@ "version": "7.2.3", "resolved": "https://mirrors.cloud.tencent.com/npm/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", "license": "ISC", "optional": true, "peer": true, @@ -10468,7 +10455,7 @@ "node_modules/lighthouse-logger/node_modules/ms": { "version": "2.0.0", "resolved": "https://mirrors.cloud.tencent.com/npm/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT", "optional": true, "peer": true @@ -10776,7 +10763,7 @@ "node_modules/lodash.throttle": { "version": "4.1.1", "resolved": "https://mirrors.cloud.tencent.com/npm/lodash.throttle/-/lodash.throttle-4.1.1.tgz", - "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", + "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=", "license": "MIT", "optional": true, "peer": true @@ -11716,7 +11703,7 @@ "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://mirrors.cloud.tencent.com/npm/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "devOptional": true, "license": "MIT", "engines": { @@ -11864,7 +11851,7 @@ "node_modules/once": { "version": "1.4.0", "resolved": "https://mirrors.cloud.tencent.com/npm/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "license": "ISC", "optional": true, "peer": true, @@ -11875,7 +11862,7 @@ "node_modules/onetime": { "version": "2.0.1", "resolved": "https://mirrors.cloud.tencent.com/npm/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", "license": "MIT", "optional": true, "peer": true, @@ -12171,7 +12158,7 @@ "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://mirrors.cloud.tencent.com/npm/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "license": "MIT", "optional": true, "peer": true, @@ -12477,7 +12464,7 @@ "node_modules/qrcode-terminal": { "version": "0.11.0", "resolved": "https://mirrors.cloud.tencent.com/npm/qrcode-terminal/-/qrcode-terminal-0.11.0.tgz", - "integrity": "sha1-/8bCii/Av7RwUrR+I/T0RqX7254=", + "integrity": "sha512-Uu7ii+FQy4Qf82G4xu7ShHhjhGahEpCWc3x8UavY3CTcWV+ufmmCtwkr7ZKsX42jdL0kr1B5FKUeqJvAn51jzQ==", "optional": true, "peer": true, "bin": { @@ -12547,7 +12534,7 @@ "node_modules/rc/node_modules/strip-json-comments": { "version": "2.0.1", "resolved": "https://mirrors.cloud.tencent.com/npm/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "license": "MIT", "optional": true, "peer": true, @@ -12747,7 +12734,7 @@ "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://mirrors.cloud.tencent.com/npm/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "license": "MIT", "optional": true, "peer": true, @@ -12869,7 +12856,7 @@ "node_modules/restore-cursor": { "version": "2.0.0", "resolved": "https://mirrors.cloud.tencent.com/npm/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", "license": "MIT", "optional": true, "peer": true, @@ -12921,7 +12908,6 @@ "version": "7.2.3", "resolved": "https://mirrors.cloud.tencent.com/npm/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", "license": "ISC", "optional": true, "peer": true, @@ -13108,7 +13094,7 @@ "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", "resolved": "https://mirrors.cloud.tencent.com/npm/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT", "optional": true, "peer": true @@ -13152,7 +13138,7 @@ "node_modules/serialize-error": { "version": "2.1.0", "resolved": "https://mirrors.cloud.tencent.com/npm/serialize-error/-/serialize-error-2.1.0.tgz", - "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==", + "integrity": "sha1-ULZ51WNc34Rme9yOWa9OW4HV9go=", "license": "MIT", "optional": true, "peer": true, @@ -13191,7 +13177,7 @@ "node_modules/serve-static/node_modules/debug/node_modules/ms": { "version": "2.0.0", "resolved": "https://mirrors.cloud.tencent.com/npm/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT", "optional": true, "peer": true @@ -13250,7 +13236,7 @@ "node_modules/serve-static/node_modules/send/node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://mirrors.cloud.tencent.com/npm/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", "license": "MIT", "optional": true, "peer": true, @@ -13542,7 +13528,7 @@ "node_modules/source-map": { "version": "0.5.7", "resolved": "https://mirrors.cloud.tencent.com/npm/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "license": "BSD-3-Clause", "optional": true, "peer": true, @@ -13585,7 +13571,7 @@ "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://mirrors.cloud.tencent.com/npm/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "license": "BSD-3-Clause", "optional": true, "peer": true @@ -13678,7 +13664,7 @@ "node_modules/stream-buffers": { "version": "2.2.0", "resolved": "https://mirrors.cloud.tencent.com/npm/stream-buffers/-/stream-buffers-2.2.0.tgz", - "integrity": "sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==", + "integrity": "sha1-kdX1Ew0c75bc+n9yaUUYh0HQnuQ=", "license": "Unlicense", "optional": true, "peer": true, @@ -13914,7 +13900,7 @@ "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://mirrors.cloud.tencent.com/npm/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, "license": "MIT", "engines": { @@ -14080,6 +14066,17 @@ "node": ">=18" } }, + "node_modules/tar/node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://mirrors.cloud.tencent.com/npm/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "license": "BlueOak-1.0.0", + "optional": true, + "peer": true, + "engines": { + "node": ">=18" + } + }, "node_modules/tar/node_modules/yallist": { "version": "5.0.0", "resolved": "https://mirrors.cloud.tencent.com/npm/yallist/-/yallist-5.0.0.tgz", @@ -14168,7 +14165,6 @@ "version": "7.2.3", "resolved": "https://mirrors.cloud.tencent.com/npm/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", "license": "ISC", "optional": true, "peer": true, @@ -14687,7 +14683,7 @@ "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://mirrors.cloud.tencent.com/npm/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "license": "MIT", "optional": true, "peer": true, @@ -14752,7 +14748,7 @@ "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://mirrors.cloud.tencent.com/npm/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "license": "MIT", "optional": true, "peer": true, @@ -14782,7 +14778,7 @@ "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://mirrors.cloud.tencent.com/npm/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", "license": "BSD-2-Clause" }, "node_modules/whatwg-fetch": { @@ -14796,7 +14792,7 @@ "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://mirrors.cloud.tencent.com/npm/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "license": "MIT", "dependencies": { "tr46": "~0.0.3", diff --git a/messages/en-US/alphabet.json b/public/messages/en-US/alphabet.json similarity index 100% rename from messages/en-US/alphabet.json rename to public/messages/en-US/alphabet.json diff --git a/messages/en-US/home.json b/public/messages/en-US/home.json similarity index 100% rename from messages/en-US/home.json rename to public/messages/en-US/home.json diff --git a/messages/en-US/memorize/choose.json b/public/messages/en-US/memorize/choose.json similarity index 100% rename from messages/en-US/memorize/choose.json rename to public/messages/en-US/memorize/choose.json diff --git a/messages/en-US/memorize/edit.json b/public/messages/en-US/memorize/edit.json similarity index 100% rename from messages/en-US/memorize/edit.json rename to public/messages/en-US/memorize/edit.json diff --git a/messages/en-US/memorize/main.json b/public/messages/en-US/memorize/main.json similarity index 100% rename from messages/en-US/memorize/main.json rename to public/messages/en-US/memorize/main.json diff --git a/messages/en-US/memorize/start.json b/public/messages/en-US/memorize/start.json similarity index 100% rename from messages/en-US/memorize/start.json rename to public/messages/en-US/memorize/start.json diff --git a/messages/en-US/navbar.json b/public/messages/en-US/navbar.json similarity index 100% rename from messages/en-US/navbar.json rename to public/messages/en-US/navbar.json diff --git a/messages/en-US/srt-player.json b/public/messages/en-US/srt-player.json similarity index 100% rename from messages/en-US/srt-player.json rename to public/messages/en-US/srt-player.json diff --git a/messages/en-US/text-speaker.json b/public/messages/en-US/text-speaker.json similarity index 100% rename from messages/en-US/text-speaker.json rename to public/messages/en-US/text-speaker.json diff --git a/messages/en-US/translator.json b/public/messages/en-US/translator.json similarity index 100% rename from messages/en-US/translator.json rename to public/messages/en-US/translator.json diff --git a/messages/zh-CN/alphabet.json b/public/messages/zh-CN/alphabet.json similarity index 100% rename from messages/zh-CN/alphabet.json rename to public/messages/zh-CN/alphabet.json diff --git a/messages/zh-CN/home.json b/public/messages/zh-CN/home.json similarity index 100% rename from messages/zh-CN/home.json rename to public/messages/zh-CN/home.json diff --git a/messages/zh-CN/memorize/choose.json b/public/messages/zh-CN/memorize/choose.json similarity index 100% rename from messages/zh-CN/memorize/choose.json rename to public/messages/zh-CN/memorize/choose.json diff --git a/messages/zh-CN/memorize/edit.json b/public/messages/zh-CN/memorize/edit.json similarity index 100% rename from messages/zh-CN/memorize/edit.json rename to public/messages/zh-CN/memorize/edit.json diff --git a/messages/zh-CN/memorize/main.json b/public/messages/zh-CN/memorize/main.json similarity index 100% rename from messages/zh-CN/memorize/main.json rename to public/messages/zh-CN/memorize/main.json diff --git a/messages/zh-CN/memorize/start.json b/public/messages/zh-CN/memorize/start.json similarity index 100% rename from messages/zh-CN/memorize/start.json rename to public/messages/zh-CN/memorize/start.json diff --git a/messages/zh-CN/navbar.json b/public/messages/zh-CN/navbar.json similarity index 100% rename from messages/zh-CN/navbar.json rename to public/messages/zh-CN/navbar.json diff --git a/messages/zh-CN/srt-player.json b/public/messages/zh-CN/srt-player.json similarity index 100% rename from messages/zh-CN/srt-player.json rename to public/messages/zh-CN/srt-player.json diff --git a/messages/zh-CN/text-speaker.json b/public/messages/zh-CN/text-speaker.json similarity index 100% rename from messages/zh-CN/text-speaker.json rename to public/messages/zh-CN/text-speaker.json diff --git a/messages/zh-CN/translator.json b/public/messages/zh-CN/translator.json similarity index 100% rename from messages/zh-CN/translator.json rename to public/messages/zh-CN/translator.json diff --git a/src/app/api/textinfo/route.ts b/src/app/api/textinfo/route.ts deleted file mode 100644 index fab0bb4..0000000 --- a/src/app/api/textinfo/route.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { callZhipuAPI } from "@/utils"; -import { NextRequest, NextResponse } from "next/server"; - -async function getTextinfo(text: string) { - console.log(`get textinfo of ${text}`); - const messages = [ - { - role: "user", - content: ` -请推断以下文本的语言、locale,生成宽式国际音标(IPA),以JSON格式返回 -[${text}] -结果如: -{ - "text": "你好。", - "lang": "mandarin", - "ipa": "[ni˨˩˦ xɑʊ˨˩˦]", - "locale": "zh-CN" -} -注意: -直接返回json文本, -ipa一定要加[], -lang的值是小写字母的英文的语言名称, -locale如果可能有多个,选取最可能的一个,其中使用符号"-" -`, - }, - ]; - try { - const response = await callZhipuAPI(messages); - let to_parse = response.choices[0].message.content.trim() as string; - if (to_parse.startsWith("`")) - to_parse = to_parse.slice(7, to_parse.length - 3); - if (to_parse.length === 0) throw Error("ai啥也每说"); - return JSON.parse(to_parse); - } catch (error) { - console.error(error); - return null; - } -} - -export async function GET(request: NextRequest) { - try { - const searchParams = request.nextUrl.searchParams; - const text = searchParams.get("text"); - - if (!text) { - return NextResponse.json( - { error: "查询参数错误", message: "text参数是必需的" }, - { status: 400 }, - ); - } - - const textInfo = await getTextinfo(text); - if (!textInfo) { - return NextResponse.json( - { error: "服务暂时不可用", message: "LLM API 请求失败" }, - { status: 503 }, - ); - } - return NextResponse.json(textInfo, { status: 200 }); - } catch (error) { - console.error("API 错误:", error); - return NextResponse.json( - { error: "服务器内部错误", message: "请稍后重试" }, - { status: 500 }, - ); - } -} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index cf04445..ed5ee0d 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,5 +1,4 @@ import type { Metadata } from "next"; -import { Geist, Geist_Mono } from "next/font/google"; import "./globals.css"; import type { Viewport } from "next"; import { NextIntlClientProvider } from "next-intl"; @@ -9,16 +8,6 @@ export const viewport: Viewport = { initialScale: 1.0, }; -const geistSans = Geist({ - variable: "--font-geist-sans", - subsets: ["latin"], -}); - -const geistMono = Geist_Mono({ - variable: "--font-geist-mono", - subsets: ["latin"], -}); - export const metadata: Metadata = { title: "Learn Languages", description: "A Website to Learn Languages", @@ -32,7 +21,7 @@ export default async function RootLayout({ return (