├── .commitlintrc.json ├── .dockerignore ├── .editorconfig ├── .env ├── .eslintignore ├── .eslintrc.cjs ├── .gitattributes ├── .github └── workflows │ ├── desktop.yml │ └── docker-image.yml ├── .gitignore ├── .husky ├── commit-msg └── pre-commit ├── .npmrc ├── .vscode ├── extensions.json └── settings.json ├── CHANGELOG.md ├── CONTRIBUTING.en.md ├── CONTRIBUTING.md ├── Dockerfile ├── README.md ├── README_EN.md ├── README_FR.md ├── README_KR.md ├── README_RU.md ├── README_TR.md ├── README_VN.md ├── README_ZH.md ├── SPONSOR.md ├── api ├── proxy.js ├── session.js └── verify.js ├── changlog.md ├── docker-compose ├── docker-compose.yml ├── gpt-mj │ ├── deploy.sh │ ├── docker-compose.yml │ └── readme.md ├── gpts-mj-file │ ├── docker-compose.yml │ ├── nginx │ │ └── nginx.conf │ ├── readme.md │ ├── start.sh │ └── start_h.sh └── readme.md ├── docs ├── alipay.jpg ├── c1-2.8.0.png ├── c1-2.9.0.png ├── c1.png ├── c2-2.8.0.png ├── c2-2.9.0.png ├── c2.png ├── check_error.jpg ├── desk.jpg ├── docker.png ├── gptbase.jpg ├── gpts.jpg ├── gpts1.jpg ├── luma-video.jpg ├── mj1.jpg ├── mj2.jpg ├── mj2a1.jpg ├── mj2a2.jpg ├── mj2a3.jpg ├── mj3a2.jpg ├── mj4a1.png ├── mjs1.jpg ├── mjs2.jpg ├── mjs3.jpg ├── realtime-1.jpg ├── realtime-2.jpg ├── realtime.mp4 ├── suno-ds.jpg ├── suno.jpg ├── suno2.jpg ├── tts-whisper.png ├── tts.jpg └── wxpay.jpg ├── index.html ├── kubernetes ├── README.md ├── deploy.yaml └── ingress.yaml ├── license ├── package-lock.json ├── package.json ├── pnpm-lock.yaml ├── postcss.config.js ├── public ├── favicon-full.ico ├── favicon-full.svg ├── favicon.ico ├── favicon.svg ├── gpts.json ├── pwa-192x192.png └── pwa-512x512.png ├── service ├── .env.example ├── .eslintrc.json ├── .gitignore ├── .npmrc ├── .vscode │ ├── extensions.json │ └── settings.json ├── package.json ├── pnpm-lock.yaml ├── src │ ├── chatgpt │ │ ├── index.ts │ │ └── types.ts │ ├── index.ts │ ├── middleware │ │ ├── auth.ts │ │ └── limiter.ts │ ├── myfun.ts │ ├── types.ts │ └── utils │ │ ├── index.ts │ │ └── is.ts ├── tsconfig.json └── tsup.config.ts ├── src-tauri ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── build.rs ├── icons │ ├── 128x128.png │ ├── 128x128@2x.png │ ├── 256x256.png │ ├── 32x32.png │ ├── Square107x107Logo.png │ ├── Square142x142Logo.png │ ├── Square150x150Logo.png │ ├── Square284x284Logo.png │ ├── Square30x30Logo.png │ ├── Square310x310Logo.png │ ├── Square44x44Logo.png │ ├── Square71x71Logo.png │ ├── Square89x89Logo.png │ ├── StoreLogo.png │ ├── icon.icns │ ├── icon.ico │ └── icon.png ├── icons_bak │ ├── 128x128.png │ ├── 128x128@2x.png │ ├── 256x256.png │ ├── 32x32.png │ ├── Square107x107Logo.png │ ├── Square142x142Logo.png │ ├── Square150x150Logo.png │ ├── Square284x284Logo.png │ ├── Square30x30Logo.png │ ├── Square310x310Logo.png │ ├── Square44x44Logo.png │ ├── Square71x71Logo.png │ ├── Square89x89Logo.png │ ├── StoreLogo.png │ ├── icon.icns │ ├── icon.ico │ └── icon.png ├── src │ └── main.rs └── tauri.conf.json ├── src ├── App.vue ├── api │ ├── Recognition.ts │ ├── chat.ts │ ├── ideo.ts │ ├── index.ts │ ├── kling.ts │ ├── klingStore.ts │ ├── luma.ts │ ├── lumaStore.ts │ ├── mic.ts │ ├── mjapi.ts │ ├── mjsave.ts │ ├── mp4img.ts │ ├── openapi.ts │ ├── pika.ts │ ├── pikaStore.ts │ ├── pixverse.ts │ ├── pixverseStore.ts │ ├── realtime.ts │ ├── runway.ts │ ├── runwayStore.ts │ ├── runwayml.ts │ ├── runwaymlStore.ts │ ├── sse │ │ ├── fetch.ts │ │ ├── fetchsse.ts │ │ ├── stream-async-iterable.ts │ │ └── types.ts │ ├── suno.ts │ ├── sunoStore.ts │ ├── udio.ts │ ├── udioStore.ts │ ├── units.ts │ ├── viggle.ts │ └── viggleStore.ts ├── assets │ ├── avatar.jpg │ └── recommend.json ├── components │ ├── common │ │ ├── HoverButton │ │ │ ├── Button.vue │ │ │ └── index.vue │ │ ├── NaiveProvider │ │ │ └── index.vue │ │ ├── PromptStore │ │ │ └── index.vue │ │ ├── Setting │ │ │ ├── About.vue │ │ │ ├── Advanced.vue │ │ │ ├── General.vue │ │ │ └── index.vue │ │ ├── SvgIcon │ │ │ └── index.vue │ │ ├── UserAvatar │ │ │ └── index.vue │ │ └── index.ts │ └── custom │ │ ├── GithubSite.vue │ │ └── index.ts ├── hooks │ ├── useBasicLayout.ts │ ├── useIconRender.ts │ ├── useLanguage.ts │ └── useTheme.ts ├── icons │ ├── 403.vue │ ├── 404.svg │ └── 500.vue ├── lib │ └── wavtools │ │ ├── index.js │ │ └── lib │ │ ├── analysis │ │ ├── audio_analysis.js │ │ └── constants.js │ │ ├── wav_packer.js │ │ ├── wav_recorder.js │ │ ├── wav_stream_player.js │ │ └── worklets │ │ ├── audio_processor.js │ │ └── stream_processor.js ├── locales │ ├── en-US.ts │ ├── fr-FR.ts │ ├── index.ts │ ├── ko-KR.ts │ ├── ru-RU.ts │ ├── tr-TR.ts │ ├── vi-VN.ts │ ├── zh-CN.ts │ └── zh-TW.ts ├── main.ts ├── plugins │ ├── assets.ts │ ├── index.ts │ └── scrollbarStyle.ts ├── router │ ├── index.ts │ └── permission.ts ├── static │ └── mitf │ │ ├── assets │ │ ├── checkerboard.png │ │ ├── mj.js │ │ └── style.css │ │ └── index.html ├── store │ ├── helper.ts │ ├── homeStore.ts │ ├── index.ts │ └── modules │ │ ├── app │ │ ├── helper.ts │ │ └── index.ts │ │ ├── auth │ │ ├── helper.ts │ │ └── index.ts │ │ ├── chat │ │ ├── helper.ts │ │ └── index.ts │ │ ├── index.ts │ │ ├── prompt │ │ ├── helper.ts │ │ └── index.ts │ │ ├── settings │ │ ├── helper.ts │ │ └── index.ts │ │ └── user │ │ ├── helper.ts │ │ └── index.ts ├── styles │ ├── global.less │ └── lib │ │ ├── github-markdown.less │ │ ├── highlight.less │ │ └── tailwind.css ├── typings │ ├── chat.d.ts │ ├── env.d.ts │ └── global.d.ts ├── utils │ ├── copy.ts │ ├── functions │ │ ├── debounce.ts │ │ └── index.ts │ ├── is │ │ └── index.ts │ ├── request │ │ ├── axios.ts │ │ └── index.ts │ ├── storage │ │ └── index.ts │ └── wav_renderer.ts └── views │ ├── chat │ ├── components │ │ ├── Header │ │ │ └── index.vue │ │ ├── Message │ │ │ ├── Avatar.vue │ │ │ ├── Text.vue │ │ │ ├── index.vue │ │ │ └── style.less │ │ └── index.ts │ ├── hooks │ │ ├── useChat.ts │ │ ├── useScroll.ts │ │ └── useUsingContext.ts │ ├── index.vue │ └── layout │ │ ├── Layout.vue │ │ ├── Permission.vue │ │ ├── index.ts │ │ └── sider │ │ ├── Footer.vue │ │ ├── List.vue │ │ └── index.vue │ ├── exception │ ├── 404 │ │ └── index.vue │ └── 500 │ │ └── index.vue │ ├── kling │ ├── kgImage.vue │ ├── kgInput.vue │ ├── kgInputImage.vue │ ├── kgInputVideo.vue │ └── kgList.vue │ ├── luma │ ├── layout.vue │ ├── lumaInput.vue │ ├── pikaInput.vue │ ├── pikaList.vue │ ├── pixCamera.json │ ├── pixEffact.json │ ├── pixInput.vue │ ├── pixList.vue │ ├── runInput.vue │ ├── runmlInput.vue │ ├── runmlList.vue │ ├── runwayInput.vue │ ├── runwayList.vue │ ├── video.vue │ ├── voInput.vue │ └── voList.vue │ ├── mj │ ├── aiBlend.vue │ ├── aiCanvas.vue │ ├── aiDall.vue │ ├── aiDrawInput.vue │ ├── aiDrawInputItem.vue │ ├── aiFace.vue │ ├── aiFooter.vue │ ├── aiGallery.vue │ ├── aiGalleryItem.vue │ ├── aiGpt.vue │ ├── aiGptInput.vue │ ├── aiGpts.vue │ ├── aiGptsAdd.vue │ ├── aiGptsCom.vue │ ├── aiIdeoInput.vue │ ├── aiListText.vue │ ├── aiMic.vue │ ├── aiMobileMenu.vue │ ├── aiModel.vue │ ├── aiModelServer.vue │ ├── aiMsg.vue │ ├── aiOther.vue │ ├── aiSetAuth.vue │ ├── aiSetServer.vue │ ├── aiSider.vue │ ├── aiSiderInput.vue │ ├── aiTextSetting.vue │ ├── dallText.vue │ ├── draw.json │ ├── draw.vue │ ├── drawList.vue │ ├── index.ts │ ├── layout.vue │ ├── mjText.vue │ ├── mjTextAttr.vue │ ├── myTest.vue │ ├── ttsText.vue │ └── whisperText.vue │ ├── suno │ ├── layout.vue │ ├── mcInput.vue │ ├── mcList.vue │ ├── mcUploadMp3.vue │ ├── mcplayer.vue │ ├── music.vue │ ├── player.vue │ ├── playui.vue │ ├── udioInput.vue │ └── udioList.vue │ ├── viggle │ ├── dance.vue │ ├── dcInput.vue │ ├── dcList.vue │ └── dcTemple.vue │ └── wav │ ├── an_main.vue │ ├── css │ └── in-and-out.css │ ├── realtime.vue │ ├── realtimeLayout.vue │ ├── wav.vue │ └── wavSetting.vue ├── start.cmd ├── start.sh ├── tailwind.config.js ├── tauri_debug.sh ├── tsconfig.json ├── vercel.json ├── vite.config.ts └── yarn.lock /.commitlintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@commitlint/config-conventional"] 3 | } 4 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | */node_modules 3 | node_modules 4 | Dockerfile 5 | .* 6 | */.* 7 | !.env 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = tab 8 | indent_size = 2 9 | end_of_line = lf 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | # Glob API URL 2 | VITE_GLOB_API_URL=/api 3 | 4 | VITE_APP_API_BASE_URL=http://127.0.0.1:3002 5 | #VITE_APP_API_BASE_URL=http://192.168.31.186:3002 6 | #VITE_APP_API_BASE_URL=http://192.168.0.105:3002 7 | 8 | # Whether long replies are supported, which may result in higher API fees 9 | VITE_GLOB_OPEN_LONG_REPLY=false 10 | 11 | # When you want to use PWA 12 | VITE_GLOB_APP_PWA=false 13 | 14 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | docker-compose 2 | kubernetes 3 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['@antfu'], 4 | } 5 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | "*.vue" eol=lf 2 | "*.js" eol=lf 3 | "*.ts" eol=lf 4 | "*.jsx" eol=lf 5 | "*.tsx" eol=lf 6 | "*.cjs" eol=lf 7 | "*.cts" eol=lf 8 | "*.mjs" eol=lf 9 | "*.mts" eol=lf 10 | "*.json" eol=lf 11 | "*.html" eol=lf 12 | "*.css" eol=lf 13 | "*.less" eol=lf 14 | "*.scss" eol=lf 15 | "*.sass" eol=lf 16 | "*.styl" eol=lf 17 | "*.md" eol=lf 18 | -------------------------------------------------------------------------------- /.github/workflows/docker-image.yml: -------------------------------------------------------------------------------- 1 | name: Publish Docker image 2 | 3 | on: 4 | workflow_dispatch: 5 | release: 6 | types: [published] 7 | 8 | jobs: 9 | push_to_registry: 10 | name: Push Docker image to Docker Hub 11 | runs-on: ubuntu-latest 12 | steps: 13 | - 14 | name: Check out the repo 15 | uses: actions/checkout@v3 16 | - run: | 17 | echo 本次构建的版本为:${{ github.ref_name }} 18 | echo 账号:${{ secrets.DOCKER_USERNAME }} 19 | env 20 | - 21 | name: Log in to Docker Hub 22 | uses: docker/login-action@v2 23 | with: 24 | username: ${{ secrets.DOCKER_USERNAME }} 25 | password: ${{ secrets.DOCKER_PASSWORD }} 26 | 27 | - 28 | name: Extract metadata (tags, labels) for Docker 29 | id: meta 30 | uses: docker/metadata-action@v4 31 | with: 32 | images: ydlhero/chatgpt-web-midjourney-proxy 33 | tags: | 34 | type=raw,value=latest 35 | type=ref,event=tag 36 | 37 | - 38 | name: Set up QEMU 39 | uses: docker/setup-qemu-action@v2 40 | 41 | - 42 | name: Set up Docker Buildx 43 | uses: docker/setup-buildx-action@v2 44 | 45 | - 46 | name: Build and push Docker image 47 | uses: docker/build-push-action@v4 48 | with: 49 | context: . 50 | platforms: linux/amd64,linux/arm64 51 | push: true 52 | tags: ${{ steps.meta.outputs.tags }} 53 | labels: ${{ steps.meta.outputs.labels }} 54 | cache-from: ${{ inputs.use-cache == 'true' && 'type=gha' || 'type=local,src=/tmp' }} 55 | cache-to: ${{ inputs.use-cache == 'true' && 'type=gha, mode=max' || 'type=local,dest=/tmp' }} 56 | 57 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | .DS_Store 12 | dist 13 | dist-ssr 14 | coverage 15 | *.local 16 | 17 | /cypress/videos/ 18 | /cypress/screenshots/ 19 | 20 | # Editor directories and files 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/extensions.json 24 | .idea 25 | *.suo 26 | *.ntvs* 27 | *.njsproj 28 | *.sln 29 | *.sw? 30 | 31 | # Environment variables files 32 | /service/.env 33 | /service/uploads -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx --no -- commitlint --edit 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | strict-peer-dependencies=false 2 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["Vue.volar", "dbaeumer.vscode-eslint"] 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "prettier.enable": false, 3 | "editor.formatOnSave": false, 4 | "editor.codeActionsOnSave": { 5 | "source.fixAll.eslint": "explicit" 6 | }, 7 | "eslint.validate": [ 8 | "javascript", 9 | "javascriptreact", 10 | "typescript", 11 | "typescriptreact", 12 | "vue", 13 | "html", 14 | "json", 15 | "jsonc", 16 | "json5", 17 | "yaml", 18 | "yml", 19 | "markdown" 20 | ], 21 | "cSpell.words": [ 22 | "antfu", 23 | "axios", 24 | "bumpp", 25 | "chatgpt", 26 | "chenzhaoyu", 27 | "commitlint", 28 | "davinci", 29 | "dockerhub", 30 | "esno", 31 | "GPTAPI", 32 | "highlightjs", 33 | "hljs", 34 | "iconify", 35 | "katex", 36 | "katexmath", 37 | "linkify", 38 | "logprobs", 39 | "mdhljs", 40 | "mila", 41 | "nodata", 42 | "OPENAI", 43 | "pinia", 44 | "Popconfirm", 45 | "rushstack", 46 | "Sider", 47 | "tailwindcss", 48 | "traptitech", 49 | "tsup", 50 | "Typecheck", 51 | "unplugin", 52 | "VITE", 53 | "vueuse", 54 | "Zhao" 55 | ], 56 | "i18n-ally.enabledParsers": [ 57 | "ts" 58 | ], 59 | "i18n-ally.sortKeys": true, 60 | "i18n-ally.keepFulfilled": true, 61 | "i18n-ally.localesPaths": [ 62 | "src/locales" 63 | ], 64 | "i18n-ally.keystyle": "nested" 65 | } 66 | -------------------------------------------------------------------------------- /CONTRIBUTING.en.md: -------------------------------------------------------------------------------- 1 | # Contribution Guide 2 | Thank you for your valuable time. Your contributions will make this project better! Before submitting a contribution, please take some time to read the getting started guide below. 3 | 4 | ## Semantic Versioning 5 | This project follows semantic versioning. We release patch versions for important bug fixes, minor versions for new features or non-important changes, and major versions for significant and incompatible changes. 6 | 7 | Each major change will be recorded in the `changelog`. 8 | 9 | ## Submitting Pull Request 10 | 1. Fork [this repository](https://github.com/Chanzhaoyu/chatgpt-web) and create a branch from `main`. For new feature implementations, submit a pull request to the `feature` branch. For other changes, submit to the `main` branch. 11 | 2. Install the `pnpm` tool using `npm install pnpm -g`. 12 | 3. Install the `Eslint` plugin for `VSCode`, or enable `eslint` functionality for other editors such as `WebStorm`. 13 | 4. Execute `pnpm bootstrap` in the root directory. 14 | 5. Execute `pnpm install` in the `/service/` directory. 15 | 6. Make changes to the codebase. If applicable, ensure that appropriate testing has been done. 16 | 7. Execute `pnpm lint:fix` in the root directory to perform a code formatting check. 17 | 8. Execute `pnpm type-check` in the root directory to perform a type check. 18 | 9. Submit a git commit, following the [Commit Guidelines](#commit-guidelines). 19 | 10. Submit a `pull request`. If there is a corresponding `issue`, please link it using the [linking-a-pull-request-to-an-issue keyword](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword). 20 | 21 | ## Commit Guidelines 22 | 23 | Commit messages should follow the [conventional-changelog standard](https://www.conventionalcommits.org/en/v1.0.0/): 24 | 25 | ```bash 26 | [optional scope]: 27 | 28 | [optional body] 29 | 30 | [optional footer] 31 | ``` 32 | 33 | ### Commit Types 34 | 35 | The following is a list of commit types: 36 | 37 | - feat: New feature or functionality 38 | - fix: Bug fix 39 | - docs: Documentation update 40 | - style: Code style or component style update 41 | - refactor: Code refactoring, no new features or bug fixes introduced 42 | - perf: Performance optimization 43 | - test: Unit test 44 | - chore: Other commits that do not modify src or test files 45 | 46 | 47 | ## License 48 | 49 | [MIT](./license) -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # 贡献指南 2 | 感谢你的宝贵时间。你的贡献将使这个项目变得更好!在提交贡献之前,请务必花点时间阅读下面的入门指南。 3 | 4 | ## 语义化版本 5 | 该项目遵循语义化版本。我们对重要的漏洞修复发布修订号,对新特性或不重要的变更发布次版本号,对重大且不兼容的变更发布主版本号。 6 | 7 | 每个重大更改都将记录在 `changelog` 中。 8 | 9 | ## 提交 Pull Request 10 | 1. Fork [此仓库](https://github.com/Chanzhaoyu/chatgpt-web),从 `main` 创建分支。新功能实现请发 pull request 到 `feature` 分支。其他更改发到 `main` 分支。 11 | 2. 使用 `npm install pnpm -g` 安装 `pnpm` 工具。 12 | 3. `vscode` 安装了 `Eslint` 插件,其它编辑器如 `webStorm` 打开了 `eslint` 功能。 13 | 4. 根目录下执行 `pnpm bootstrap`。 14 | 5. `/service/` 目录下执行 `pnpm install`。 15 | 6. 对代码库进行更改。如果适用的话,请确保进行了相应的测试。 16 | 7. 请在根目录下执行 `pnpm lint:fix` 进行代码格式检查。 17 | 8. 请在根目录下执行 `pnpm type-check` 进行类型检查。 18 | 9. 提交 git commit, 请同时遵守 [Commit 规范](#commit-指南) 19 | 10. 提交 `pull request`, 如果有对应的 `issue`,请进行[关联](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword)。 20 | 21 | ## Commit 指南 22 | 23 | Commit messages 请遵循[conventional-changelog 标准](https://www.conventionalcommits.org/en/v1.0.0/): 24 | 25 | ```bash 26 | <类型>[可选 范围]: <描述> 27 | 28 | [可选 正文] 29 | 30 | [可选 脚注] 31 | ``` 32 | 33 | ### Commit 类型 34 | 35 | 以下是 commit 类型列表: 36 | 37 | - feat: 新特性或功能 38 | - fix: 缺陷修复 39 | - docs: 文档更新 40 | - style: 代码风格或者组件样式更新 41 | - refactor: 代码重构,不引入新功能和缺陷修复 42 | - perf: 性能优化 43 | - test: 单元测试 44 | - chore: 其他不修改 src 或测试文件的提交 45 | 46 | 47 | ## License 48 | 49 | [MIT](./license) 50 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # build front-end 2 | FROM node:lts-alpine AS frontend 3 | 4 | RUN npm install pnpm -g 5 | # 安装 Git 6 | RUN apk add --no-cache git 7 | 8 | WORKDIR /app 9 | 10 | COPY ./package.json /app 11 | 12 | COPY ./pnpm-lock.yaml /app 13 | 14 | #RUN git --version 15 | 16 | RUN pnpm install 17 | 18 | COPY . /app 19 | 20 | RUN pnpm run build 21 | 22 | # build backend 23 | FROM node:lts-alpine as backend 24 | 25 | RUN npm install pnpm -g 26 | 27 | WORKDIR /app 28 | 29 | COPY /service/package.json /app 30 | 31 | COPY /service/pnpm-lock.yaml /app 32 | 33 | RUN pnpm install 34 | 35 | COPY /service /app 36 | 37 | RUN pnpm build 38 | 39 | # service 40 | FROM node:lts-alpine 41 | 42 | RUN npm install pnpm -g 43 | 44 | WORKDIR /app 45 | 46 | COPY /service/package.json /app 47 | 48 | COPY /service/pnpm-lock.yaml /app 49 | 50 | RUN pnpm install --production && rm -rf /root/.npm /root/.pnpm-store /usr/local/share/.cache /tmp/* 51 | 52 | COPY /service /app 53 | 54 | COPY --from=frontend /app/dist /app/public 55 | 56 | COPY --from=backend /app/build /app/build 57 | 58 | EXPOSE 3002 59 | 60 | CMD ["pnpm", "run", "prod"] 61 | -------------------------------------------------------------------------------- /SPONSOR.md: -------------------------------------------------------------------------------- 1 | # Sponsor My Open Source Works 2 | 3 | 如果我的开源项目对你有帮助,请考虑通过以下任意一种方式赞助: 4 | 5 | ## 微信赞助 6 | ![微信](./docs/wxpay.jpg) 7 | ## 支付宝赞助 8 | ![支付宝](./docs/alipay.jpg) -------------------------------------------------------------------------------- /api/proxy.js: -------------------------------------------------------------------------------- 1 | const { 2 | createProxyMiddleware 3 | } = require('http-proxy-middleware') 4 | 5 | module.exports = (req, res) => { 6 | let target = '' 7 | let headers= {} 8 | // 代理目标地址 9 | if (req.url.startsWith('/mjapi')) { //这里使用/api可能会与vercel serverless 的 api 路径冲突,根据接口进行调整 10 | target = process.env.MJ_SERVER??'https://api.openai.com'; 11 | headers= { 12 | 'Mj-Api-Secret': process.env.MJ_API_SECRET // 添加自定义请求头 13 | } 14 | }else if(req.url.startsWith('/openapi')){ 15 | target = process.env.OPENAI_API_BASE_URL??'https://api.openai.com'; 16 | headers= { 17 | 'Authorization': 'Bearer ' +process.env.OPENAI_API_KEY // 添加自定义请求头 18 | } 19 | } 20 | // 创建代理对象并转发请求 21 | createProxyMiddleware({ 22 | target, 23 | changeOrigin: true, 24 | headers, 25 | pathRewrite: { 26 | // 通过路径重写,去除请求路径中的 `/api` 27 | '^/mjapi/': '/' 28 | ,'^/openapi/': '/' 29 | } 30 | })(req, res) 31 | } 32 | -------------------------------------------------------------------------------- /api/session.js: -------------------------------------------------------------------------------- 1 | module.exports = (req, res) => { 2 | console.log('session.js', req.body); 3 | try { 4 | let data = req.body.data; 5 | let obj ={ 6 | "status": "Success", 7 | "message": "", 8 | "data": { 9 | "isHideServer": false, 10 | "isUpload": false, 11 | "auth": process.env.AUTH_SECRET_KEY?true:false , 12 | "model": "ChatGPTAPI", 13 | "amodel": process.env.OPENAI_API_MODEL?? "gpt-3.5-turbo" 14 | ,isApiGallery: process.env.MJ_API_GALLERY ? true : false 15 | ,cmodels : process.env.CUSTOM_MODELS??'' 16 | ,baiduId : process.env.TJ_BAIDU_ID?? "" 17 | ,googleId: process.env.TJ_GOOGLE_ID?? "" 18 | , notify : process.env.SYS_NOTIFY?? "" 19 | ,disableGpt4 : process.env.DISABLE_GPT4?? "" 20 | ,isWsrv: process.env.MJ_IMG_WSRV?? "" 21 | ,uploadImgSize: process.env.UPLOAD_IMG_SIZE?? "1" 22 | ,gptUrl : process.env.GPT_URL?? "" 23 | ,theme : process.env.SYS_THEME?? "dark" 24 | ,isCloseMdPreview : process.env.CLOSE_MD_PREVIEW?true:false 25 | ,menuDisable: process.env.MENU_DISABLE??"" 26 | ,visionModel: process.env.VISION_MODEL??"" 27 | ,systemMessage: process.env.SYSTEM_MESSAGE??"" 28 | ,customVisionModel: process.env.CUSTOM_VISION_MODELS??"" 29 | 30 | } 31 | } 32 | res.writeHead(200).end( 33 | JSON.stringify( obj ) 34 | ); 35 | } catch (e) { 36 | console.error('session.js', e, req.body); 37 | } 38 | } -------------------------------------------------------------------------------- /api/verify.js: -------------------------------------------------------------------------------- 1 | module.exports = (req, res) => { 2 | let obj = { 3 | "status": "Fail", 4 | "message": "密钥无效 | Secret key is invalid", 5 | "data": null 6 | }; 7 | const auth_secret_keys = process.env.AUTH_SECRET_KEY? process.env.AUTH_SECRET_KEY.trim().split(',').filter(item => item !== ''):[]; 8 | if (req.body && req.body.token && auth_secret_keys.include(req.body.token)) obj = { 9 | status: 'Success', 10 | message: 'Verify successfully', 11 | data: null 12 | } 13 | res.setHeader('Content-type', 'application/json'); 14 | res.writeHead(200).end( 15 | JSON.stringify(obj) 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /docker-compose/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | gptweb: 5 | container_name: chatgpt-web-midjourney-proxy 6 | image: ydlhero/chatgpt-web-midjourney-proxy # 总是使用latest,更新时重新pull该tag镜像即可 7 | ports: 8 | - 6050:3002 9 | environment: 10 | TZ: Asia/Shanghai # 指定时区 11 | # 必选 12 | OPENAI_API_KEY: sk-xxxx 13 | # API接口地址,可选,设置 OPENAI_API_KEY 时可用 14 | OPENAI_API_BASE_URL: 15 | # API模型,可选,设置 OPENAI_API_KEY 时可用 16 | OPENAI_API_MODEL: 17 | # 访问权限密钥,可选 18 | AUTH_SECRET_KEY: 19 | # midjourney 服务器地址,可选 可用下面的 http://midjourney-proxy:8080 20 | MJ_SERVER: 21 | # midjourney API密钥,可选 22 | MJ_API_SECRET: 23 | #API_UPLOADER 是否可以上传 1 可以其他都不可以,可选 24 | API_UPLOADER: 25 | #HIDE_SERVER 隐藏服务端 1,可选 26 | HIDE_SERVER: 27 | #自定义模型 CUSTOM_MODELS=-gpt-3.5-turbo-0301,gpt-4.5 不显示 gpt-3.5-turbo-0301 新增加 gpt-4.5,可选 28 | CUSTOM_MODELS: 29 | #TJ_BAIDU_ID 百度统计ID,可选 30 | TJ_BAIDU_ID: 31 | #TJ_GOOGLE_ID 谷歌统计ID,可选 32 | TJ_GOOGLE_ID: 33 | #SYS_NOTIFY 系统通知 支持HTML ,可选 34 | SYS_NOTIFY: 35 | #FILE_SERVER 文件服务器,可选 可以用下面的 http://fileserver:3012 36 | FILE_SERVER: 37 | #DISABLE_GPT4=1 前端限制GPT4调用,可选 38 | DISABLE_GPT4: 39 | # cloudflare r2 存储 10 GB/月 免费 https://www.cloudflare.com/zh-cn/developer-platform/r2/ 40 | R2_DOMAIN: 41 | R2_BUCKET_NAME: 42 | R2_ACCOUNT_ID: 43 | R2_KEY_ID: 44 | R2_KEY_SECRET: 45 | ## UPLOAD_IMG_SIZE gpt-4-version 图片上传大小 单位是兆 注意别带单位 最好别超过10 46 | UPLOAD_IMG_SIZE: 1 47 | # GPT_URL=/gpts.json 自定义GPTs模型 48 | GPT_URL: 49 | # SYS_THEME 主题 theme light 或者 dark 50 | SYS_THEME: dark 51 | #关闭MD预览 CLOSE_MD_PREVIEW=1 52 | CLOSE_MD_PREVIEW: 53 | #爆破:验证次数 注意: vercel 不支持 nginx 请设置 proxy_set_header X-Forwarded-For $remote_addr; 54 | AUTH_SECRET_ERROR_COUNT: 3 55 | #爆破:验证停留时间 单位分钟 注意: vercel 不支持 56 | AUTH_SECRET_ERROR_TIME: 10 57 | 58 | -------------------------------------------------------------------------------- /docker-compose/gpt-mj/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | docker compose pull 4 | docker compose up -d --remove-orphans 5 | -------------------------------------------------------------------------------- /docker-compose/gpt-mj/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | gptweb: 4 | image: ydlhero/chatgpt-web-midjourney-proxy 5 | ports: 6 | - 6055:3002 7 | environment: 8 | TZ: Asia/Shanghai # 指定时区 9 | # 必选 10 | OPENAI_API_KEY: sk-xxxx 11 | # API接口地址,可选,设置 OPENAI_API_KEY 时可用 12 | OPENAI_API_BASE_URL: 13 | # midjourney 服务器地址,可选 14 | MJ_SERVER: http://midjourney-proxy:8080 15 | # midjourney API密钥,可选 16 | MJ_API_SECRET: mjpassword 17 | 18 | # midjourney服务 可选 19 | midjourney-proxy: 20 | image: novicezk/midjourney-proxy:2.5.5 21 | restart: always 22 | # ports: 23 | # - 6013:8080 #映射端口 24 | environment: 25 | TZ: Asia/Shanghai # 指定时区 26 | mj.discord.guild-id: xxxx 27 | mj.discord.channel-id: xxx 28 | mj.discord.user-token: tooken-xxx 29 | mj.api-secret: mjpassword 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /docker-compose/gpt-mj/readme.md: -------------------------------------------------------------------------------- 1 | ### 仅部署chatgpt和mj 2 | 3 | ```shell 4 | git clone https://github.com/Dooy/chatgpt-web-midjourney-proxy.git 5 | cd chatgpt-web-midjourney-proxy/docker-compose/gpt-mj 6 | #修改 docker-compose.yml 文件配置文件 7 | 8 | ./deploy.sh 9 | ``` 10 | 11 | -------------------------------------------------------------------------------- /docker-compose/gpts-mj-file/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | gptweb: 5 | container_name: chatgpt-web-midjourney-proxy 6 | image: ydlhero/chatgpt-web-midjourney-proxy # 总是使用latest,更新时重新pull该tag镜像即可 7 | ports: 8 | - 6050:3002 9 | environment: 10 | TZ: Asia/Shanghai # 指定时区 11 | # 必选 12 | OPENAI_API_KEY: sk-xxxx 13 | # API接口地址,可选,设置 OPENAI_API_KEY 时可用 14 | OPENAI_API_BASE_URL: 15 | # 访问权限密钥,可选 注意修改 16 | AUTH_SECRET_KEY: mygod 17 | # midjourney 服务器地址,可选 可用下面的 http://midjourney-proxy:8080 18 | MJ_SERVER: http://midjourney-proxy:8080 19 | # midjourney API密钥,可选 20 | MJ_API_SECRET: mygod 21 | #API_UPLOADER 是否可以上传 1 可以其他都不可以,可选 22 | API_UPLOADER: 1 23 | #FILE_SERVER 文件服务器,可选 可以用下面的 http://fileserver:3012 24 | FILE_SERVER: http://fileserver:3012 25 | #爆破:验证次数 注意: vercel 不支持 nginx 请设置 proxy_set_header X-Forwarded-For $remote_addr; 26 | AUTH_SECRET_ERROR_COUNT: 3 27 | #爆破:验证停留时间 单位分钟 注意: vercel 不支持 28 | AUTH_SECRET_ERROR_TIME: 10 29 | 30 | # midjourney服务 可选 31 | midjourney-proxy: 32 | image: novicezk/midjourney-proxy:2.5.5 33 | restart: always 34 | # ports: 35 | # - 6013:8080 #映射端口 36 | environment: 37 | TZ: Asia/Shanghai # 指定时区 38 | mj.discord.guild-id: xxx # xxx 如何获取 39 | mj.discord.channel-id: xxx 40 | mj.discord.user-token: xxx 41 | mj.api-secret: mygod # MJ_API_SECRET 42 | 43 | #文件服务 可选 44 | fileserver: 45 | image: ydlhero/file-server:latest 46 | restart: always 47 | environment: 48 | TZ: Asia/Shanghai # 指定时区 49 | #对外显示的域名 50 | SERVER_NAME: http://myip:3102 51 | ports: 52 | - "3102:3102" 53 | volumes: 54 | - /data/uploads:/app/uploads 55 | 56 | -------------------------------------------------------------------------------- /docker-compose/gpts-mj-file/nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name localhost; 4 | charset utf-8; 5 | error_page 500 502 503 504 /50x.html; 6 | 7 | # 防止爬虫抓取 8 | if ($http_user_agent ~* "360Spider|JikeSpider|Spider|spider|bot|Bot|2345Explorer|curl|wget|webZIP|qihoobot|Baiduspider|Googlebot|Googlebot-Mobile|Googlebot-Image|Mediapartners-Google|Adsbot-Google|Feedfetcher-Google|Yahoo! Slurp|Yahoo! Slurp China|YoudaoBot|Sosospider|Sogou spider|Sogou web spider|MSNBot|ia_archiver|Tomato Bot|NSPlayer|bingbot") 9 | { 10 | return 403; 11 | } 12 | 13 | location / { 14 | root /usr/share/nginx/html; 15 | try_files $uri /index.html; 16 | } 17 | 18 | location /api { 19 | proxy_set_header X-Real-IP $remote_addr; #转发用户IP 20 | proxy_pass http://app:3002; 21 | } 22 | 23 | proxy_set_header Host $host; 24 | proxy_set_header X-Real-IP $remote_addr; 25 | proxy_set_header REMOTE-HOST $remote_addr; 26 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 27 | } 28 | -------------------------------------------------------------------------------- /docker-compose/gpts-mj-file/readme.md: -------------------------------------------------------------------------------- 1 | ### docker-compose 部署教程 2 | 3 | ```shell 4 | git clone https://github.com/Dooy/chatgpt-web-midjourney-proxy.git 5 | cd chatgpt-web-midjourney-proxy/docker-compose/gpts-mj-file 6 | #修改 docker-compose.yml 文件配置问文件 7 | 8 | #如果执行有问题 请执行 start_h.sh 9 | start.sh 10 | ``` -------------------------------------------------------------------------------- /docker-compose/gpts-mj-file/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | # docker compose pull 4 | # docker compose up -d --remove-orphans 5 | docker-compose pull 6 | docker-compose up -d --remove-orphans -------------------------------------------------------------------------------- /docker-compose/gpts-mj-file/start_h.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | docker compose pull 4 | docker compose up -d --remove-orphans 5 | -------------------------------------------------------------------------------- /docker-compose/readme.md: -------------------------------------------------------------------------------- 1 | ### docker-compose 部署教程 2 | - 将打包好的前端文件放到 `nginx/html` 目录下 3 | - ```shell 4 | # 启动 5 | docker-compose up -d 6 | ``` 7 | - ```shell 8 | # 查看运行状态 9 | docker ps 10 | ``` 11 | - ```shell 12 | # 结束运行 13 | docker-compose down 14 | ``` 15 | -------------------------------------------------------------------------------- /docs/alipay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/alipay.jpg -------------------------------------------------------------------------------- /docs/c1-2.8.0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/c1-2.8.0.png -------------------------------------------------------------------------------- /docs/c1-2.9.0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/c1-2.9.0.png -------------------------------------------------------------------------------- /docs/c1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/c1.png -------------------------------------------------------------------------------- /docs/c2-2.8.0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/c2-2.8.0.png -------------------------------------------------------------------------------- /docs/c2-2.9.0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/c2-2.9.0.png -------------------------------------------------------------------------------- /docs/c2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/c2.png -------------------------------------------------------------------------------- /docs/check_error.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/check_error.jpg -------------------------------------------------------------------------------- /docs/desk.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/desk.jpg -------------------------------------------------------------------------------- /docs/docker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/docker.png -------------------------------------------------------------------------------- /docs/gptbase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/gptbase.jpg -------------------------------------------------------------------------------- /docs/gpts.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/gpts.jpg -------------------------------------------------------------------------------- /docs/gpts1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/gpts1.jpg -------------------------------------------------------------------------------- /docs/luma-video.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/luma-video.jpg -------------------------------------------------------------------------------- /docs/mj1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/mj1.jpg -------------------------------------------------------------------------------- /docs/mj2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/mj2.jpg -------------------------------------------------------------------------------- /docs/mj2a1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/mj2a1.jpg -------------------------------------------------------------------------------- /docs/mj2a2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/mj2a2.jpg -------------------------------------------------------------------------------- /docs/mj2a3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/mj2a3.jpg -------------------------------------------------------------------------------- /docs/mj3a2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/mj3a2.jpg -------------------------------------------------------------------------------- /docs/mj4a1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/mj4a1.png -------------------------------------------------------------------------------- /docs/mjs1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/mjs1.jpg -------------------------------------------------------------------------------- /docs/mjs2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/mjs2.jpg -------------------------------------------------------------------------------- /docs/mjs3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/mjs3.jpg -------------------------------------------------------------------------------- /docs/realtime-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/realtime-1.jpg -------------------------------------------------------------------------------- /docs/realtime-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/realtime-2.jpg -------------------------------------------------------------------------------- /docs/realtime.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/realtime.mp4 -------------------------------------------------------------------------------- /docs/suno-ds.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/suno-ds.jpg -------------------------------------------------------------------------------- /docs/suno.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/suno.jpg -------------------------------------------------------------------------------- /docs/suno2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/suno2.jpg -------------------------------------------------------------------------------- /docs/tts-whisper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/tts-whisper.png -------------------------------------------------------------------------------- /docs/tts.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/tts.jpg -------------------------------------------------------------------------------- /docs/wxpay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/docs/wxpay.jpg -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | ChatGPT Web Midjourney Proxy 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /kubernetes/README.md: -------------------------------------------------------------------------------- 1 | ## 增加一个Kubernetes的部署方式 2 | ``` 3 | kubectl apply -f deploy.yaml 4 | ``` 5 | 6 | ### 如果需要Ingress域名接入 7 | ``` 8 | kubectl apply -f ingress.yaml 9 | ``` 10 | -------------------------------------------------------------------------------- /kubernetes/deploy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: chatgpt-web 5 | labels: 6 | app: chatgpt-web 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | app: chatgpt-web 12 | strategy: 13 | type: RollingUpdate 14 | template: 15 | metadata: 16 | labels: 17 | app: chatgpt-web 18 | spec: 19 | containers: 20 | - image: chenzhaoyu94/chatgpt-web 21 | name: chatgpt-web 22 | imagePullPolicy: Always 23 | ports: 24 | - containerPort: 3002 25 | env: 26 | - name: OPENAI_API_KEY 27 | value: sk-xxx 28 | - name: OPENAI_API_BASE_URL 29 | value: 'https://api.openai.com' 30 | - name: OPENAI_API_MODEL 31 | value: gpt-3.5-turbo 32 | - name: API_REVERSE_PROXY 33 | value: https://ai.fakeopen.com/api/conversation 34 | - name: AUTH_SECRET_KEY 35 | value: '123456' 36 | - name: TIMEOUT_MS 37 | value: '60000' 38 | - name: SOCKS_PROXY_HOST 39 | value: '' 40 | - name: SOCKS_PROXY_PORT 41 | value: '' 42 | - name: HTTPS_PROXY 43 | value: '' 44 | resources: 45 | limits: 46 | cpu: 500m 47 | memory: 500Mi 48 | requests: 49 | cpu: 300m 50 | memory: 300Mi 51 | --- 52 | apiVersion: v1 53 | kind: Service 54 | metadata: 55 | labels: 56 | app: chatgpt-web 57 | name: chatgpt-web 58 | spec: 59 | ports: 60 | - name: chatgpt-web 61 | port: 3002 62 | protocol: TCP 63 | targetPort: 3002 64 | selector: 65 | app: chatgpt-web 66 | type: ClusterIP 67 | -------------------------------------------------------------------------------- /kubernetes/ingress.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | annotations: 5 | kubernetes.io/ingress.class: nginx 6 | nginx.ingress.kubernetes.io/proxy-connect-timeout: '5' 7 | name: chatgpt-web 8 | spec: 9 | rules: 10 | - host: chatgpt.example.com 11 | http: 12 | paths: 13 | - backend: 14 | service: 15 | name: chatgpt-web 16 | port: 17 | number: 3002 18 | path: / 19 | pathType: ImplementationSpecific 20 | tls: 21 | - secretName: chatgpt-web-tls 22 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Dooy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chatgpt-web-midjourney-proxy", 3 | "version": "2.24.6", 4 | "private": false, 5 | "description": "ChatGPT Web Midjourney Proxy", 6 | "author": "Dooy ", 7 | "keywords": [ 8 | "chatgpt-web", 9 | "chatgpt", 10 | "chatbot", 11 | "Midjourney", 12 | "Midjourney UI", 13 | "Midjourney Proxy", 14 | "gpts", 15 | "gpts ui", 16 | "vue" 17 | ], 18 | "scripts": { 19 | "dev": "vite", 20 | "build": "run-p build-only", 21 | "buildold": "run-p type-check build-only", 22 | "preview": "vite preview", 23 | "build-only": "vite build", 24 | "type-check": "vue-tsc --noEmit", 25 | "lint": "eslint .", 26 | "lint:fix": "eslint . --fix", 27 | "bootstrap": "pnpm install && pnpm run common:prepare", 28 | "common:cleanup": "rimraf node_modules && rimraf pnpm-lock.yaml", 29 | "common:prepare": "husky install" 30 | }, 31 | "dependencies": { 32 | "@ffmpeg/ffmpeg": "^0.12.10", 33 | "@ffmpeg/util": "^0.12.1", 34 | "@traptitech/markdown-it-katex": "^3.6.0", 35 | "@vueuse/core": "^9.13.0", 36 | "eventsource-parser": "^1.1.1", 37 | "form-data": "^4.0.0", 38 | "gpt-tokenizer": "^2.1.2", 39 | "highlight.js": "^11.7.0", 40 | "html2canvas": "^1.4.1", 41 | "js-audio-recorder": "^1.0.7", 42 | "katex": "^0.16.4", 43 | "localforage": "^1.10.0", 44 | "markdown-it": "^13.0.1", 45 | "naive-ui": "^2.34.3", 46 | "pinia": "^2.0.33", 47 | "vue": "^3.2.47", 48 | "vue-i18n": "^9.2.2", 49 | "vue-router": "^4.1.6", 50 | "vue-turnstile": "^1.0.8", 51 | "vue-waterfall-plugin-next": "^2.3.1" 52 | }, 53 | "devDependencies": { 54 | "@antfu/eslint-config": "^0.35.3", 55 | "@commitlint/cli": "^17.4.4", 56 | "@commitlint/config-conventional": "^17.4.4", 57 | "@iconify/vue": "^4.1.0", 58 | "@openai/realtime-api-beta": "github:dooy/openai-realtime-api-beta", 59 | "@openai/realtime-wavtools": "github:dooy/openai-realtime-wavtools", 60 | "@tauri-apps/cli": "^1.5.11", 61 | "@types/crypto-js": "^4.1.1", 62 | "@types/katex": "^0.16.0", 63 | "@types/markdown-it": "^12.2.3", 64 | "@types/markdown-it-link-attributes": "^3.0.1", 65 | "@types/node": "^18.14.6", 66 | "@vitejs/plugin-vue": "^4.0.0", 67 | "autoprefixer": "^10.4.13", 68 | "axios": "^1.3.4", 69 | "crypto-js": "^4.1.1", 70 | "eslint": "^8.35.0", 71 | "http-proxy-middleware": "^2.0.6", 72 | "husky": "^8.0.3", 73 | "less": "^4.1.3", 74 | "lint-staged": "^13.1.2", 75 | "markdown-it-link-attributes": "^4.0.1", 76 | "npm-run-all": "^4.1.5", 77 | "postcss": "^8.4.21", 78 | "rimraf": "^4.2.0", 79 | "tailwindcss": "^3.3.6", 80 | "typescript": "~4.9.5", 81 | "vite": "^4.2.0", 82 | "vite-plugin-pwa": "^0.14.4", 83 | "vite-plugin-static-copy": "^0.17.0", 84 | "vue-tsc": "^1.2.0" 85 | }, 86 | "lint-staged": { 87 | "*.{ts,tsx,vue}": [ 88 | "pnpm lint:fix" 89 | ] 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /public/favicon-full.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/public/favicon-full.ico -------------------------------------------------------------------------------- /public/favicon-full.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/public/favicon.ico -------------------------------------------------------------------------------- /public/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /public/gpts.json: -------------------------------------------------------------------------------- 1 | { 2 | "tag": [ 3 | "图像", 4 | "论文", 5 | "文件", 6 | "识别", 7 | "PDF", 8 | "新闻", 9 | "医生", 10 | "老师", 11 | "Logo" 12 | ], 13 | "gpts": [ 14 | { 15 | "gid": "gpt-4-all", 16 | "name": "gpt-4-all", 17 | "logo": "https://cos.aitutu.cc/gpts/gpt4all.jpg", 18 | "info": "集合官方GPT-4、联网,多模态(gpt-4v),绘图功能(dall-e3),限制不支持function等", 19 | "use_cnt": "8624", 20 | "bad": "0" 21 | }, 22 | { 23 | "gid": "gpt-4-gizmo-g-2fkFE8rbu", 24 | "name": "DALL·E", 25 | "logo": "https://files.oaiusercontent.com/file-SxYQO0Fq1ZkPagkFtg67DRVb?se=2123-10-12T23%3A57%3A32Z&sp=r&sv=2021-08-06&sr=b&rscc=max-age%3D31536000%2C%20immutable&rscd=attachment%3B%20filename%3Dagent_3.webp&sig=pLlQh8oUktqQzhM09SDDxn5aakqFuM2FAPptuA0mbqc%3D", 26 | "info": "让我将你的想象变成图像 – 基于 ChatGPT", 27 | "use_cnt": "3087", 28 | "bad": "1" 29 | } 30 | ] 31 | } -------------------------------------------------------------------------------- /public/pwa-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/public/pwa-192x192.png -------------------------------------------------------------------------------- /public/pwa-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/public/pwa-512x512.png -------------------------------------------------------------------------------- /service/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "ignorePatterns": ["build"], 4 | "extends": ["@antfu"] 5 | } 6 | -------------------------------------------------------------------------------- /service/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | .DS_Store 12 | dist 13 | dist-ssr 14 | coverage 15 | *.local 16 | 17 | /cypress/videos/ 18 | /cypress/screenshots/ 19 | 20 | # Editor directories and files 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/extensions.json 24 | .idea 25 | *.suo 26 | *.ntvs* 27 | *.njsproj 28 | *.sln 29 | *.sw? 30 | 31 | build 32 | -------------------------------------------------------------------------------- /service/.npmrc: -------------------------------------------------------------------------------- 1 | enable-pre-post-scripts=true 2 | -------------------------------------------------------------------------------- /service/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["dbaeumer.vscode-eslint"] 3 | } 4 | -------------------------------------------------------------------------------- /service/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "prettier.enable": false, 3 | "editor.formatOnSave": false, 4 | "editor.codeActionsOnSave": { 5 | "source.fixAll.eslint": true 6 | }, 7 | "eslint.validate": [ 8 | "javascript", 9 | "typescript", 10 | "json", 11 | "jsonc", 12 | "json5", 13 | "yaml" 14 | ], 15 | "cSpell.words": [ 16 | "antfu", 17 | "chatgpt", 18 | "esno", 19 | "GPTAPI", 20 | "OPENAI" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /service/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chatgpt-web-service", 3 | "version": "2.15.6", 4 | "private": false, 5 | "description": "ChatGPT Web Midjourney Proxy", 6 | "author": "ChenZhaoYu ", 7 | "keywords": [ 8 | "chatgpt-web", 9 | "chatgpt", 10 | "chatbot", 11 | "express" 12 | ], 13 | "engines": { 14 | "node": "^16 || ^18 || ^19" 15 | }, 16 | "scripts": { 17 | "start": "esno ./src/index.ts", 18 | "dev": "esno watch ./src/index.ts", 19 | "prod": "node ./build/index.mjs", 20 | "build": "pnpm clean && tsup", 21 | "clean": "rimraf build", 22 | "lint": "eslint .", 23 | "lint:fix": "eslint . --fix", 24 | "common:cleanup": "rimraf node_modules && rimraf pnpm-lock.yaml" 25 | }, 26 | "dependencies": { 27 | "aws-sdk": "^2.1535.0", 28 | "axios": "^1.3.4", 29 | "body-parser": "^1.20.2", 30 | "chatgpt": "^5.1.2", 31 | "dotenv": "^16.0.3", 32 | "esno": "^0.16.3", 33 | "express": "^4.18.2", 34 | "express-http-proxy": "^2.0.0", 35 | "express-rate-limit": "^6.7.0", 36 | "form-data": "^4.0.0", 37 | "http-proxy-middleware": "^2.0.6", 38 | "https-proxy-agent": "^5.0.1", 39 | "isomorphic-fetch": "^3.0.0", 40 | "md5": "^2.3.0", 41 | "multer": "1.4.5-lts.1", 42 | "node-fetch": "^3.3.0", 43 | "socks-proxy-agent": "^7.0.0", 44 | "uuid": "^9.0.1" 45 | }, 46 | "devDependencies": { 47 | "@antfu/eslint-config": "^0.35.3", 48 | "@types/express": "^4.17.17", 49 | "@types/node": "^18.14.6", 50 | "eslint": "^8.35.0", 51 | "rimraf": "^4.3.0", 52 | "tsup": "^6.6.3", 53 | "typescript": "^4.9.5" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /service/src/chatgpt/types.ts: -------------------------------------------------------------------------------- 1 | import type { ChatMessage } from 'chatgpt' 2 | import type fetch from 'node-fetch' 3 | 4 | export interface RequestOptions { 5 | message: string 6 | lastContext?: { conversationId?: string; parentMessageId?: string } 7 | process?: (chat: ChatMessage) => void 8 | systemMessage?: string 9 | temperature?: number 10 | top_p?: number 11 | } 12 | 13 | export interface SetProxyOptions { 14 | fetch?: typeof fetch 15 | } 16 | 17 | export interface UsageResponse { 18 | total_usage: number 19 | } 20 | -------------------------------------------------------------------------------- /service/src/middleware/limiter.ts: -------------------------------------------------------------------------------- 1 | import { rateLimit } from 'express-rate-limit' 2 | import { isNotEmptyString } from '../utils/is' 3 | 4 | const MAX_REQUEST_PER_HOUR = process.env.MAX_REQUEST_PER_HOUR 5 | 6 | const maxCount = (isNotEmptyString(MAX_REQUEST_PER_HOUR) && !isNaN(Number(MAX_REQUEST_PER_HOUR))) 7 | ? parseInt(MAX_REQUEST_PER_HOUR) 8 | : 0 // 0 means unlimited 9 | 10 | const limiter = rateLimit({ 11 | windowMs: 60 * 60 * 1000, // Maximum number of accesses within an hour 12 | max: maxCount, 13 | statusCode: 200, // 200 means success,but the message is 'Too many request from this IP in 1 hour' 14 | message: async (req, res) => { 15 | res.send({ status: 'Fail', message: 'Too many request from this IP in 1 hour', data: null }) 16 | }, 17 | }) 18 | 19 | export { limiter } 20 | -------------------------------------------------------------------------------- /service/src/types.ts: -------------------------------------------------------------------------------- 1 | import type { FetchFn } from 'chatgpt' 2 | 3 | export interface RequestProps { 4 | prompt: string 5 | options?: ChatContext 6 | systemMessage: string 7 | temperature?: number 8 | top_p?: number 9 | } 10 | 11 | export interface ChatContext { 12 | conversationId?: string 13 | parentMessageId?: string 14 | } 15 | 16 | export interface ChatGPTUnofficialProxyAPIOptions { 17 | accessToken: string 18 | apiReverseProxyUrl?: string 19 | model?: string 20 | debug?: boolean 21 | headers?: Record 22 | fetch?: FetchFn 23 | } 24 | 25 | export interface ModelConfig { 26 | apiModel?: ApiModel 27 | reverseProxy?: string 28 | timeoutMs?: number 29 | socksProxy?: string 30 | httpsProxy?: string 31 | usage?: string 32 | } 33 | 34 | export type ApiModel = 'ChatGPTAPI' | 'ChatGPTUnofficialProxyAPI' | undefined 35 | -------------------------------------------------------------------------------- /service/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | interface SendResponseOptions { 2 | type: 'Success' | 'Fail' 3 | message?: string 4 | data?: T 5 | } 6 | 7 | export function sendResponse(options: SendResponseOptions) { 8 | if (options.type === 'Success') { 9 | return Promise.resolve({ 10 | message: options.message ?? null, 11 | data: options.data ?? null, 12 | status: options.type, 13 | }) 14 | } 15 | 16 | // eslint-disable-next-line prefer-promise-reject-errors 17 | return Promise.reject({ 18 | message: options.message ?? 'Failed', 19 | data: options.data ?? null, 20 | status: options.type, 21 | }) 22 | } 23 | -------------------------------------------------------------------------------- /service/src/utils/is.ts: -------------------------------------------------------------------------------- 1 | export function isNumber(value: T | unknown): value is number { 2 | return Object.prototype.toString.call(value) === '[object Number]' 3 | } 4 | 5 | export function isString(value: T | unknown): value is string { 6 | return Object.prototype.toString.call(value) === '[object String]' 7 | } 8 | 9 | export function isNotEmptyString(value: any): boolean { 10 | return typeof value === 'string' && value.length > 0 11 | } 12 | 13 | export function isBoolean(value: T | unknown): value is boolean { 14 | return Object.prototype.toString.call(value) === '[object Boolean]' 15 | } 16 | 17 | export function isFunction any | void | never>(value: T | unknown): value is T { 18 | return Object.prototype.toString.call(value) === '[object Function]' 19 | } 20 | 21 | export const formattedDate=()=>{ 22 | const currentDate = new Date(); 23 | const year = currentDate.getFullYear(); 24 | const month = (currentDate.getMonth() + 1).toString().padStart(2, '0'); 25 | const day = currentDate.getDate().toString().padStart(2, '0'); 26 | return `${year}${month}${day}`; 27 | 28 | } -------------------------------------------------------------------------------- /service/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "lib": [ 5 | "esnext" 6 | ], 7 | "allowJs": true, 8 | "skipLibCheck": true, 9 | "strict": false, 10 | "forceConsistentCasingInFileNames": true, 11 | "esModuleInterop": true, 12 | "module": "esnext", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "baseUrl": ".", 17 | "outDir": "build", 18 | "noEmit": true 19 | }, 20 | "exclude": [ 21 | "node_modules", 22 | "build" 23 | ], 24 | "include": [ 25 | "**/*.ts" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /service/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup' 2 | 3 | export default defineConfig({ 4 | entry: ['src/index.ts'], 5 | outDir: 'build', 6 | target: 'es2020', 7 | format: ['esm'], 8 | splitting: false, 9 | sourcemap: true, 10 | minify: false, 11 | shims: true, 12 | dts: false, 13 | }) 14 | -------------------------------------------------------------------------------- /src-tauri/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | -------------------------------------------------------------------------------- /src-tauri/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "app" 3 | version = "0.1.0" 4 | description = "A Tauri App" 5 | authors = ["you"] 6 | license = "" 7 | repository = "" 8 | default-run = "app" 9 | edition = "2021" 10 | rust-version = "1.60" 11 | 12 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 13 | 14 | [build-dependencies] 15 | tauri-build = { version = "1.5.1", features = [] } 16 | 17 | [dependencies] 18 | serde_json = "1.0" 19 | serde = { version = "1.0", features = ["derive"] } 20 | tauri = { version = "1.6.1", features = [ "updater", "window-minimize", "window-show", "shell-open", "window-close", "fs-all", "window-start-dragging", "window-maximize", "window-set-resizable", "notification-all", "window-unminimize", "clipboard-all", "window-hide", "dialog-all", "window-set-ignore-cursor-events", "window-unmaximize", "window-set-icon"] } 21 | 22 | [features] 23 | # this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled. 24 | # 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. 25 | # DO NOT REMOVE!! 26 | custom-protocol = [ "tauri/custom-protocol" ] 27 | -------------------------------------------------------------------------------- /src-tauri/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | tauri_build::build() 3 | } 4 | -------------------------------------------------------------------------------- /src-tauri/icons/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons/128x128.png -------------------------------------------------------------------------------- /src-tauri/icons/128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons/128x128@2x.png -------------------------------------------------------------------------------- /src-tauri/icons/256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons/256x256.png -------------------------------------------------------------------------------- /src-tauri/icons/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons/32x32.png -------------------------------------------------------------------------------- /src-tauri/icons/Square107x107Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons/Square107x107Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square142x142Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons/Square142x142Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square150x150Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons/Square150x150Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square284x284Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons/Square284x284Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square30x30Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons/Square30x30Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square310x310Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons/Square310x310Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square44x44Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons/Square44x44Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square71x71Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons/Square71x71Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/Square89x89Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons/Square89x89Logo.png -------------------------------------------------------------------------------- /src-tauri/icons/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons/StoreLogo.png -------------------------------------------------------------------------------- /src-tauri/icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons/icon.icns -------------------------------------------------------------------------------- /src-tauri/icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons/icon.ico -------------------------------------------------------------------------------- /src-tauri/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons/icon.png -------------------------------------------------------------------------------- /src-tauri/icons_bak/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons_bak/128x128.png -------------------------------------------------------------------------------- /src-tauri/icons_bak/128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons_bak/128x128@2x.png -------------------------------------------------------------------------------- /src-tauri/icons_bak/256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons_bak/256x256.png -------------------------------------------------------------------------------- /src-tauri/icons_bak/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons_bak/32x32.png -------------------------------------------------------------------------------- /src-tauri/icons_bak/Square107x107Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons_bak/Square107x107Logo.png -------------------------------------------------------------------------------- /src-tauri/icons_bak/Square142x142Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons_bak/Square142x142Logo.png -------------------------------------------------------------------------------- /src-tauri/icons_bak/Square150x150Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons_bak/Square150x150Logo.png -------------------------------------------------------------------------------- /src-tauri/icons_bak/Square284x284Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons_bak/Square284x284Logo.png -------------------------------------------------------------------------------- /src-tauri/icons_bak/Square30x30Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons_bak/Square30x30Logo.png -------------------------------------------------------------------------------- /src-tauri/icons_bak/Square310x310Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons_bak/Square310x310Logo.png -------------------------------------------------------------------------------- /src-tauri/icons_bak/Square44x44Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons_bak/Square44x44Logo.png -------------------------------------------------------------------------------- /src-tauri/icons_bak/Square71x71Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons_bak/Square71x71Logo.png -------------------------------------------------------------------------------- /src-tauri/icons_bak/Square89x89Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons_bak/Square89x89Logo.png -------------------------------------------------------------------------------- /src-tauri/icons_bak/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons_bak/StoreLogo.png -------------------------------------------------------------------------------- /src-tauri/icons_bak/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons_bak/icon.icns -------------------------------------------------------------------------------- /src-tauri/icons_bak/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons_bak/icon.ico -------------------------------------------------------------------------------- /src-tauri/icons_bak/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src-tauri/icons_bak/icon.png -------------------------------------------------------------------------------- /src-tauri/src/main.rs: -------------------------------------------------------------------------------- 1 | // Prevents additional console window on Windows in release, DO NOT REMOVE!! 2 | #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] 3 | 4 | fn main() { 5 | tauri::Builder::default() 6 | .run(tauri::generate_context!()) 7 | .expect("error while running tauri application"); 8 | } 9 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 25 | -------------------------------------------------------------------------------- /src/api/chat.ts: -------------------------------------------------------------------------------- 1 | //import { reactive } from 'vue' 2 | 3 | import { gptConfigStore, gptConfigType } from "@/store"; 4 | import { ss } from '@/utils/storage' 5 | import { mlog } from "./mjapi"; 6 | import { debounce } from "@/utils/functions/debounce"; 7 | 8 | //let time_limit= 0 9 | 10 | export class chatSetting{ 11 | private uuid: number; 12 | private localKey='chat-setting'; 13 | private time_limit=0; 14 | private mObj:gptConfigType[]=[]; 15 | 16 | //private gptConfig: gptConfigType 17 | // 构造函数 18 | constructor(uuid: number) { 19 | this.uuid = uuid; 20 | //this.gptConfig = gptConfigStore.myData; 21 | //this.init(); 22 | } 23 | 24 | public setUuid(uuid: number){ 25 | this.uuid = uuid; 26 | return this 27 | } 28 | public getGptConfig():gptConfigType { 29 | mlog("toMyuid16","getGptConfig", this.uuid ) 30 | const index = this.findIndex(); 31 | if( index<=-1) return gptConfigStore.myData; 32 | const arr = this.getObjs(); 33 | const rz= arr[index]; 34 | //gptConfigStore.setMyData( rz ); 35 | gptConfigStore.myData.model= rz.model; 36 | return rz; 37 | } 38 | public getObjsDebounce=debounce( this.getObjs ,600); 39 | //卡死 可疑点 40 | public getObjs():gptConfigType[]{ 41 | const now= Math.floor(Date.now() / 1) 42 | const dt= now- this.time_limit; 43 | mlog("toMyuid15","getObjs", this.uuid , dt) 44 | if(dt<500 ){ //防止卡死 45 | return this.mObj ; 46 | } 47 | this.time_limit=now ; 48 | 49 | const obj = ss.get( this.localKey ) as undefined| gptConfigType[]; 50 | 51 | this.mObj= obj? obj:[] 52 | return this.mObj; 53 | } 54 | public findIndex(){ 55 | mlog("toMyuid8","findIndex") 56 | return this.getObjs().findIndex(v=>v.uuid && v.uuid==this.uuid ) 57 | } 58 | public save( obj : Partial){ 59 | mlog("toMyuid8","save") 60 | let sobj ={ ...gptConfigStore.myData , ...obj }; 61 | sobj.uuid= this.uuid; 62 | const index = this.findIndex(); 63 | let arr = this.getObjs(); 64 | if( index>-1 )arr[index]= sobj; 65 | else arr.push( sobj ); 66 | ss.set(this.localKey, arr ); 67 | return this ; 68 | } 69 | 70 | 71 | } -------------------------------------------------------------------------------- /src/api/index.ts: -------------------------------------------------------------------------------- 1 | import type { AxiosProgressEvent, GenericAbortSignal } from 'axios' 2 | import { post } from '@/utils/request' 3 | import { homeStore, useAuthStore, useSettingStore } from '@/store' 4 | 5 | 6 | export function fetchChatAPI( 7 | prompt: string, 8 | options?: { conversationId?: string; parentMessageId?: string }, 9 | signal?: GenericAbortSignal, 10 | ) { 11 | return post({ 12 | url: '/chat', 13 | data: { prompt, options }, 14 | signal, 15 | }) 16 | } 17 | 18 | export function fetchChatConfig() { 19 | return post({ 20 | url: '/config', 21 | }) 22 | } 23 | 24 | export function fetchChatAPIProcess( 25 | params: { 26 | prompt: string 27 | options?: { conversationId?: string; parentMessageId?: string } 28 | signal?: GenericAbortSignal 29 | onDownloadProgress?: (progressEvent: AxiosProgressEvent) => void }, 30 | ) { 31 | const settingStore = useSettingStore() 32 | const authStore = useAuthStore() 33 | 34 | let data: Record = { 35 | prompt: params.prompt, 36 | options: params.options, 37 | } 38 | 39 | if (authStore.isChatGPTAPI) { 40 | data = { 41 | ...data, 42 | systemMessage: settingStore.systemMessage, 43 | temperature: settingStore.temperature, 44 | top_p: settingStore.top_p, 45 | } 46 | } 47 | 48 | return post({ 49 | url: '/chat-process', 50 | data, 51 | signal: params.signal, 52 | onDownloadProgress: params.onDownloadProgress, 53 | }) 54 | } 55 | 56 | export function fetchSession() { 57 | if (homeStore.myData.isClient) 58 | return {"status":"Success","message":"","data":{"isHideServer":false,"isUpload":false,"auth":false,"model":"ChatGPTAPI","amodel":"gpt-4","isApiGallery":false,"cmodels":"","baiduId":"9d5fa7fc2f5fd585aa8fd3010d19be1e","googleId":"","notify":"","disableGpt4":"","isWsrv":"","uploadImgSize":"1","gptUrl":"","theme":"dark","isCloseMdPreview":false}} 59 | 60 | return post({ 61 | url: '/session', 62 | }) 63 | } 64 | 65 | export function fetchVerify(token: string) { 66 | return post({ 67 | url: '/verify', 68 | data: { token }, 69 | }) 70 | } 71 | 72 | export * from "./mjapi" 73 | export * from "./mjsave" 74 | export * from "./openapi" 75 | export * from "./units" 76 | export * from "./mic" 77 | export * from "./chat" 78 | export * from "./sse/fetchsse" 79 | export * from "./Recognition" 80 | export * from "./luma" 81 | export * from "./ideo" 82 | export * from "./realtime" 83 | 84 | -------------------------------------------------------------------------------- /src/api/klingStore.ts: -------------------------------------------------------------------------------- 1 | import { ss } from "@/utils/storage"; 2 | 3 | 4 | export interface KlingTask { 5 | cat?: string //类别 6 | prompt?: string //提示词 7 | last_feed?: number //最后更新时间 8 | code: number; 9 | message: string; 10 | request_id: string; 11 | data: { 12 | task_id: string; 13 | task_status: string; 14 | task_status_msg: string; 15 | created_at: number; 16 | updated_at: number; 17 | task_result?: { 18 | images: Array<{ 19 | index: number; 20 | url: string; 21 | }> | null; 22 | videos: Array<{ 23 | id: string; 24 | url: string; 25 | duration: string; 26 | }> | null; 27 | }; 28 | }; 29 | } 30 | 31 | export class klingStore{ 32 | //private id: string; 33 | private localKey='kling-store'; 34 | public save(obj:KlingTask ){ 35 | if(!obj.data.task_id ) throw "taskID must"; 36 | let arr= this.getObjs(); 37 | let i= arr.findIndex( v=>v.data.task_id==obj.data.task_id ); 38 | if(i>-1) arr[i]= obj; 39 | else arr.push(obj); 40 | ss.set(this.localKey, arr ); 41 | return this; 42 | } 43 | public findIndex(id:string){ 44 | return this.getObjs().findIndex( v=>v.data.task_id == id ) 45 | } 46 | 47 | public getObjs():KlingTask[]{ 48 | const obj = ss.get( this.localKey ) as undefined| KlingTask[]; 49 | if(!obj) return []; 50 | return obj; 51 | } 52 | public getOneById(id:string):KlingTask|null{ 53 | const i= this.findIndex(id) 54 | if(i<0) return null; 55 | let arr= this.getObjs(); 56 | return arr[i] 57 | } 58 | public delete( id:string ){ 59 | //if(!obj.data.task_id ) throw "id must"; 60 | let arr= this.getObjs(); 61 | let i= arr.findIndex( v=>v.data.task_id==id ); 62 | if(i<0) return false 63 | arr.splice(i, 1); 64 | ss.set(this.localKey, arr ); 65 | return true; 66 | } 67 | } -------------------------------------------------------------------------------- /src/api/lumaStore.ts: -------------------------------------------------------------------------------- 1 | import { ss } from '@/utils/storage' 2 | 3 | type LumaVideo = { 4 | url: string; 5 | width: number; 6 | height: number; 7 | thumbnail: string | null; 8 | download_url?: string; 9 | }; 10 | 11 | 12 | export type LumaMedia = { 13 | id: string; 14 | prompt: string; 15 | state: string; 16 | created_at?: string; 17 | video?: LumaVideo; 18 | liked?: boolean | null; 19 | estimate_wait_seconds?: number | null; 20 | last_feed?:number 21 | }; 22 | export class lumaStore{ 23 | //private id: string; 24 | private localKey='luma-store'; 25 | public save(obj:LumaMedia ){ 26 | if(!obj.id ) throw "id must"; 27 | let arr= this.getObjs(); 28 | let i= arr.findIndex( v=>v.id==obj.id ); 29 | if(i>-1) arr[i]= obj; 30 | else arr.push(obj); 31 | ss.set(this.localKey, arr ); 32 | return this; 33 | } 34 | public findIndex(id:string){ 35 | return this.getObjs().findIndex( v=>v.id== id ) 36 | } 37 | 38 | public getObjs():LumaMedia[]{ 39 | const obj = ss.get( this.localKey ) as undefined| LumaMedia[]; 40 | if(!obj) return []; 41 | return obj; 42 | } 43 | public delete( obj:LumaMedia ){ 44 | if(!obj.id ) throw "id must"; 45 | let arr= this.getObjs(); 46 | let i= arr.findIndex( v=>v.id==obj.id ); 47 | if(i<0) return false 48 | arr.splice(i, 1); 49 | ss.set(this.localKey, arr ); 50 | return true; 51 | } 52 | } 53 | 54 | export type LumaHk={ 55 | id: string 56 | isHK:boolean 57 | } 58 | 59 | export class lumaHkStore{ 60 | //private id: string; 61 | private localKey='luma-HK'; 62 | public save(obj:LumaHk ){ 63 | if(!obj.id ) throw "id must"; 64 | let arr= this.getObjs(); 65 | let i= arr.findIndex( v=>v.id==obj.id ); 66 | if(i>-1) arr[i]= obj; 67 | else arr.push(obj); 68 | ss.set(this.localKey, arr ); 69 | return this; 70 | } 71 | public findIndex(id:string){ 72 | return this.getObjs().findIndex( v=>v.id== id ) 73 | } 74 | 75 | public getObjs():LumaHk[]{ 76 | const obj = ss.get( this.localKey ) as undefined| LumaHk[]; 77 | if(!obj) return []; 78 | return obj; 79 | } 80 | public getOneById(id:string):LumaHk|null{ 81 | const i= this.findIndex(id) 82 | if(i<0) return null; 83 | let arr= this.getObjs(); 84 | return arr[i] 85 | } 86 | } -------------------------------------------------------------------------------- /src/api/mic.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | export const tts=(index:Number)=>{ 4 | 5 | } 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/api/mp4img.ts: -------------------------------------------------------------------------------- 1 | import { FFmpeg } from '@ffmpeg/ffmpeg' 2 | import type { LogEvent } from '@ffmpeg/ffmpeg/dist/esm/types' 3 | import { fetchFile, toBlobURL } from '@ffmpeg/util' 4 | import { mlog } from './mjapi' 5 | const baseURL = 'https://unpkg.com/@ffmpeg/core-mt@0.12.6/dist/esm' 6 | 7 | export async function myTestTranscode( vidoUrl:string) { 8 | mlog('vidoUrl>> ', vidoUrl ) 9 | const ffmpeg = new FFmpeg() 10 | //await ffmpeg.load(); 11 | 12 | //message.value = 'Loading ffmpeg-core.js' 13 | ffmpeg.on('log', ({ message: msg }: LogEvent) => { 14 | //message.value = msg 15 | mlog('FFmpeg', msg) 16 | }) 17 | mlog('FFmpegs url23 ' ) 18 | try{ 19 | await ffmpeg.load({ 20 | coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'), 21 | wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'), 22 | workerURL: await toBlobURL(`${baseURL}/ffmpeg-core.worker.js`, 'text/javascript') 23 | }) 24 | }catch(e){ 25 | mlog('FFmpegs url3 er ', e ) 26 | } 27 | 28 | //await ffmpeg.load(); 29 | mlog('FFmpegs url3 ' ) 30 | //message.value = 'Start transcoding' 31 | await ffmpeg.writeFile('input.mp4', await fetchFile(vidoUrl)) 32 | //await ffmpeg.exec(['-i', 'test.avi', 'test.mp4']) 33 | await ffmpeg.exec(['-sseof', '-3', '-i', 'input.mp4', '-update', '1', '-q:v', '1', 'last_frame.jpg']) 34 | //message.value = 'Complete transcoding' 35 | const data = await ffmpeg.readFile( 'last_frame.jpg') 36 | //const url = URL.createObjectURL(new Blob([data.buffer], { type: 'image/jpeg' })); 37 | const url = URL.createObjectURL(new Blob([(data as Uint8Array).buffer], { type: 'image/jpeg' } )) 38 | mlog('FFmpeg url ', url ) 39 | // 创建一个临时的元素 40 | const a = document.createElement('a'); 41 | a.href = url; 42 | a.download ='last_frame.jpg'; // 设置下载文件的名称 43 | 44 | // 将 元素添加到 DOM,然后触发点击事件以启动下载 45 | document.body.appendChild(a); 46 | a.click(); 47 | 48 | // 触发下载后,从 DOM 中移除 元素,并释放 URL 对象 49 | document.body.removeChild(a); 50 | URL.revokeObjectURL(url); 51 | 52 | } -------------------------------------------------------------------------------- /src/api/pikaStore.ts: -------------------------------------------------------------------------------- 1 | import { ss } from "@/utils/storage"; 2 | interface Video { 3 | id: string; 4 | status: string; 5 | seed: number; 6 | resultUrl: string; 7 | sharingUrl: string; 8 | videoPoster: string; 9 | imageThumb: string; 10 | duration: number; 11 | error: string; 12 | progress: number; 13 | } 14 | 15 | // 定义主结构体接口 16 | export interface PikaTask { 17 | id: string; 18 | promptText: string; 19 | videos: Video[]; 20 | last_feed?:number; 21 | } 22 | 23 | export class pikaStore{ 24 | //private id: string; 25 | private localKey='pika-store'; 26 | public save(obj:PikaTask ){ 27 | if(!obj.id ) throw "taskID must"; 28 | let arr= this.getObjs(); 29 | let i= arr.findIndex( v=>v.id==obj.id ); 30 | if(i>-1) arr[i]= obj; 31 | else arr.push(obj); 32 | ss.set(this.localKey, arr ); 33 | return this; 34 | } 35 | public findIndex(id:string){ 36 | return this.getObjs().findIndex( v=>v.id== id ) 37 | } 38 | 39 | public getObjs():PikaTask[]{ 40 | const obj = ss.get( this.localKey ) as undefined| PikaTask[]; 41 | if(!obj) return []; 42 | return obj; 43 | } 44 | public getOneById(id:string):PikaTask|null{ 45 | const i= this.findIndex(id) 46 | if(i<0) return null; 47 | let arr= this.getObjs(); 48 | return arr[i] 49 | } 50 | public delete( obj:PikaTask ){ 51 | if(!obj.id ) throw "id must"; 52 | let arr= this.getObjs(); 53 | let i= arr.findIndex( v=>v.id==obj.id ); 54 | if(i<0) return false 55 | arr.splice(i, 1); 56 | ss.set(this.localKey, arr ); 57 | return true; 58 | } 59 | } -------------------------------------------------------------------------------- /src/api/pixverseStore.ts: -------------------------------------------------------------------------------- 1 | import { ss } from "@/utils/storage"; 2 | 3 | export interface pixverseRep{ 4 | video_status: number; 5 | created_at: string; 6 | first_frame: string; 7 | prompt: string; 8 | model: string; 9 | negative_prompt: string; 10 | quality: string; 11 | motion_mode: string; 12 | video_duration: number; 13 | last_frame: string; 14 | extended?: number; 15 | url: string; 16 | } 17 | export interface pixverseTask { 18 | video_id: number; 19 | last_feed?: number //最后更新时间 20 | data?:pixverseRep 21 | } 22 | 23 | 24 | 25 | 26 | export class pixverseStore{ 27 | //private id: string; 28 | private localKey='pixverse-store'; 29 | public save(obj:pixverseTask ){ 30 | if(!obj.video_id) throw "video_id must"; 31 | let arr= this.getObjs(); 32 | let i= arr.findIndex( v=>v.video_id==obj.video_id); 33 | if(i>-1) arr[i]= obj; 34 | else arr.push(obj); 35 | ss.set(this.localKey, arr ); 36 | return this; 37 | } 38 | public findIndex(id:number){ 39 | return this.getObjs().findIndex( v=>v.video_id == id ) 40 | } 41 | 42 | public getObjs():pixverseTask[]{ 43 | const obj = ss.get( this.localKey ) as undefined| pixverseTask[]; 44 | if(!obj) return []; 45 | return obj; 46 | } 47 | public getOneById(id:number):pixverseTask|null{ 48 | const i= this.findIndex(id) 49 | if(i<0) return null; 50 | let arr= this.getObjs(); 51 | return arr[i] 52 | } 53 | public delete( id:number ){ 54 | //if(!obj.data.task_id ) throw "id must"; 55 | let arr= this.getObjs(); 56 | let i= arr.findIndex( v=>v.video_id==id ); 57 | if(i<0) return false 58 | arr.splice(i, 1); 59 | ss.set(this.localKey, arr ); 60 | return true; 61 | } 62 | } -------------------------------------------------------------------------------- /src/api/realtime.ts: -------------------------------------------------------------------------------- 1 | export const instructions = `System settings: 2 | Tool use: enabled. 3 | 4 | Instructions: 5 | - You are an artificial intelligence agent responsible for helping test realtime voice capabilities 6 | - Please make sure to respond with a helpful voice via audio 7 | - Be kind, helpful, and curteous 8 | - It is okay to ask the user questions 9 | - Use tools and functions you have available liberally, it is part of the training apparatus 10 | - Be open to exploration and conversation 11 | - Remember: this is just for fun and testing! 12 | 13 | Personality: 14 | - Be upbeat and genuine 15 | - Try speaking quickly as if excited 16 | `; 17 | export interface RealtimeEvent { 18 | time: string; 19 | source: 'client' | 'server'; 20 | count?: number; 21 | event: { [key: string]: any }; 22 | } -------------------------------------------------------------------------------- /src/api/runwaymlStore.ts: -------------------------------------------------------------------------------- 1 | import { ss } from "@/utils/storage"; 2 | 3 | export interface RunwayMlTask { 4 | id: string; 5 | status: string; 6 | createdAt: string; 7 | output?: string[]; 8 | last_feed?:number; 9 | failure?: string 10 | failureCode?: string 11 | model:string 12 | promptText:string 13 | } 14 | 15 | 16 | 17 | export class RunwayMlStore{ 18 | //private id: string; 19 | private localKey='runwayml-store'; 20 | public save(obj:RunwayMlTask ){ 21 | if(!obj.id ) throw "taskID must"; 22 | let arr= this.getObjs(); 23 | let i= arr.findIndex( v=>v.id==obj.id ); 24 | if(i>-1) arr[i]= obj; 25 | else arr.push(obj); 26 | ss.set(this.localKey, arr ); 27 | return this; 28 | } 29 | public findIndex(id:string){ 30 | return this.getObjs().findIndex( v=>v.id== id ) 31 | } 32 | 33 | public getObjs():RunwayMlTask[]{ 34 | const obj = ss.get( this.localKey ) as undefined| RunwayMlTask[]; 35 | if(!obj) return []; 36 | return obj; 37 | } 38 | public getOneById(id:string):RunwayMlTask|null{ 39 | const i= this.findIndex(id) 40 | if(i<0) return null; 41 | let arr= this.getObjs(); 42 | return arr[i] 43 | } 44 | public delete( obj:RunwayMlTask ){ 45 | if(!obj.id ) throw "id must"; 46 | let arr= this.getObjs(); 47 | let i= arr.findIndex( v=>v.id==obj.id ); 48 | if(i<0) return false 49 | arr.splice(i, 1); 50 | ss.set(this.localKey, arr ); 51 | return true; 52 | } 53 | } -------------------------------------------------------------------------------- /src/api/sse/fetch.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | const fetch = globalThis.fetch 4 | 5 | export { fetch } 6 | -------------------------------------------------------------------------------- /src/api/sse/stream-async-iterable.ts: -------------------------------------------------------------------------------- 1 | export async function* streamAsyncIterable(stream: ReadableStream) { 2 | const reader = stream.getReader() 3 | try { 4 | while (true) { 5 | const { done, value } = await reader.read() 6 | if (done) { 7 | return 8 | } 9 | yield value 10 | } 11 | } finally { 12 | reader.releaseLock() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/api/sunoStore.ts: -------------------------------------------------------------------------------- 1 | import { ss } from '@/utils/storage' 2 | 3 | export type SunoMedia = { 4 | id: string; 5 | video_url: string; 6 | audio_url: string; 7 | image_url: string; 8 | image_large_url: string; 9 | is_video_pending: boolean; 10 | major_model_version: string; 11 | model_name: string; 12 | metadata: { 13 | tags?: string; 14 | prompt: string; 15 | gpt_description_prompt?: string ; 16 | audio_prompt_id?: string ; 17 | history?: string ; 18 | concat_history?: string ; 19 | type: string; 20 | duration: number; 21 | refund_credits: boolean; 22 | stream: boolean; 23 | error_type?: string ; 24 | error_message?: string ; 25 | }; 26 | is_liked: boolean; 27 | user_id: string; 28 | display_name: string; 29 | handle: string; 30 | is_handle_updated: boolean; 31 | is_trashed: boolean; 32 | reaction?: any; // You might want to define a proper type for this 33 | created_at: string; 34 | status: string; 35 | title: string; 36 | play_count: number; 37 | upvote_count: number; 38 | is_public: boolean; 39 | }; 40 | export class sunoStore{ 41 | //private id: string; 42 | private localKey='suno-store'; 43 | public save(obj:SunoMedia ){ 44 | if(!obj.id ) throw "id must"; 45 | let arr= this.getObjs(); 46 | let i= arr.findIndex( v=>v.id==obj.id ); 47 | if(i>-1) arr[i]= obj; 48 | else arr.push(obj); 49 | ss.set(this.localKey, arr ); 50 | return this; 51 | } 52 | public findIndex(id:string){ 53 | return this.getObjs().findIndex( v=>v.id== id ) 54 | } 55 | 56 | public getObjs():SunoMedia[]{ 57 | const obj = ss.get( this.localKey ) as undefined| SunoMedia[]; 58 | if(!obj) return []; 59 | return obj; 60 | } 61 | public delete( obj:SunoMedia ){ 62 | if(!obj.id ) throw "id must"; 63 | let arr= this.getObjs(); 64 | let i= arr.findIndex( v=>v.id==obj.id ); 65 | if(i<0) return false 66 | arr.splice(i, 1); 67 | ss.set(this.localKey, arr ); 68 | return true; 69 | } 70 | } -------------------------------------------------------------------------------- /src/api/udioStore.ts: -------------------------------------------------------------------------------- 1 | import { ss } from "@/utils/storage"; 2 | import { mlog } from "./mjapi"; 3 | 4 | 5 | export interface udioTask { 6 | // id: string; 7 | // generationId: string; 8 | // tags?: string[]; 9 | // title: string; 10 | // artist: string; 11 | // lyrics?: string; 12 | // //prompt: string; 13 | // //disliked: boolean; 14 | // duration: number; 15 | // finished: boolean; 16 | // songPath: string; 17 | // //userTags: string[]; 18 | // createdAt: string; 19 | // // errorCode: string | null; 20 | // // errorType: string | null; 21 | // imagePath: string; 22 | // //videoPath: string | null; 23 | // // attribution: string; 24 | // // description: string; 25 | // //publishable: boolean; 26 | // errorDetail?: string; 27 | // artistImage: string; 28 | 29 | id: string; 30 | tags?: string[]; 31 | title: string; 32 | //artist: string; 33 | lyrics: string; 34 | prompt: string; 35 | //disliked: boolean; 36 | duration: number; 37 | finished: boolean; 38 | song_path: string; 39 | //user_tags: string[]; 40 | created_at: string; // ISO 8601 format 41 | // error_code: string | null; 42 | // error_type: string | null; 43 | image_path: string; 44 | // video_path?: string ; 45 | attribution: string; 46 | description: string; 47 | publishable: boolean; 48 | artist_image: string; 49 | error_detail?: string ; 50 | generation_id: string; 51 | audio_conditioning_type?:string 52 | 53 | last_feed?: number //最后更新时间 54 | status?:string 55 | taskId?:string 56 | failReason?:string 57 | } 58 | 59 | export class udioStore{ 60 | //private id: string; 61 | private localKey='udio-store'; 62 | public save(obj:udioTask ){ 63 | if(!obj.id ) throw "taskID must"; 64 | let arr= this.getObjs(); 65 | let i= arr.findIndex( v=>v.id==obj.id ); 66 | if(i>-1) arr[i]= obj; 67 | else arr.push(obj); 68 | ss.set(this.localKey, arr ); 69 | return this; 70 | } 71 | public findIndex(id:string){ 72 | return this.getObjs().findIndex( v=>v.id == id ) 73 | } 74 | 75 | public getObjs():udioTask[]{ 76 | const obj = ss.get( this.localKey ) as undefined| udioTask[]; 77 | if(!obj) return []; 78 | return obj; 79 | } 80 | public getOneById(id:string):udioTask|null{ 81 | const i= this.findIndex(id) 82 | if(i<0) return null; 83 | let arr= this.getObjs(); 84 | return arr[i] 85 | } 86 | public delete( id:string ){ 87 | let arr= this.getObjs(); 88 | 89 | let i= arr.findIndex( v=>v.id==id ); 90 | //mlog('ddd',i , arr) 91 | if(i<0) return false 92 | arr.splice(i, 1); 93 | ss.set(this.localKey, arr ); 94 | return true; 95 | } 96 | } -------------------------------------------------------------------------------- /src/api/units.ts: -------------------------------------------------------------------------------- 1 | import { homeStore } from "@/store" 2 | 3 | export const checkDisableGpt4=( model:string )=>{ 4 | if(!homeStore.myData.session.disableGpt4 || homeStore.myData.session.disableGpt4!='1') return false; 5 | const rz = model.indexOf('gpt-4')>-1 ; 6 | if(rz){ 7 | homeStore.setMyData({isLoader:false,act:'stopLoading'}); 8 | } 9 | return rz ; 10 | 11 | } 12 | 13 | export const isApikeyError=( text:string )=>{ 14 | text= text.toLocaleLowerCase(); 15 | if( 16 | text.indexOf('error') && ( 17 | text.indexOf('无效的令牌')>-1 //one-api 错误 18 | || text.indexOf('incorrect api key')>-1 //原生 19 | || text.indexOf('key error')>-1 20 | )) return true ; 21 | return false; 22 | } 23 | export const isAuthSessionError = ( text:string )=>{ 24 | text= text.toLocaleLowerCase(); 25 | if(text.indexOf('token_check')>-1 ) return true ; 26 | return false; 27 | } -------------------------------------------------------------------------------- /src/api/viggleStore.ts: -------------------------------------------------------------------------------- 1 | import { ss } from "@/utils/storage"; 2 | 3 | export interface ViggleTask { 4 | taskID: string; 5 | name: string; 6 | status: number; 7 | videoDuration: number; 8 | bgMode: number; 9 | modelInfoID: number; 10 | optimize: boolean; 11 | watermark: number; 12 | freeCredits: number; 13 | planCredits: number; 14 | purchasedCredits: number; 15 | mqType: number; 16 | result: string; 17 | resultCover: string; 18 | createdAt: string; 19 | last_feed:number; 20 | } 21 | 22 | export class viggleStore{ 23 | //private id: string; 24 | private localKey='viggle-store'; 25 | public save(obj:ViggleTask ){ 26 | if(!obj.taskID ) throw "taskID must"; 27 | let arr= this.getObjs(); 28 | let i= arr.findIndex( v=>v.taskID==obj.taskID ); 29 | if(i>-1) arr[i]= obj; 30 | else arr.push(obj); 31 | ss.set(this.localKey, arr ); 32 | return this; 33 | } 34 | public findIndex(id:string){ 35 | return this.getObjs().findIndex( v=>v.taskID== id ) 36 | } 37 | 38 | public getObjs():ViggleTask[]{ 39 | const obj = ss.get( this.localKey ) as undefined| ViggleTask[]; 40 | if(!obj) return []; 41 | return obj; 42 | } 43 | public getOneById(id:string):ViggleTask|null{ 44 | const i= this.findIndex(id) 45 | if(i<0) return null; 46 | let arr= this.getObjs(); 47 | return arr[i] 48 | } 49 | 50 | public delete( obj:ViggleTask ){ 51 | if(!obj.taskID ) throw "id must"; 52 | let arr= this.getObjs(); 53 | let i= arr.findIndex( v=>v.taskID==obj.taskID ); 54 | if(i<0) return false 55 | arr.splice(i, 1); 56 | ss.set(this.localKey, arr ); 57 | return true; 58 | } 59 | 60 | } -------------------------------------------------------------------------------- /src/assets/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src/assets/avatar.jpg -------------------------------------------------------------------------------- /src/assets/recommend.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "key": "awesome-chatgpt-prompts-zh", 4 | "desc": "ChatGPT 中文调教指南", 5 | "downloadUrl": "https://raw.githubusercontent.com/PlexPt/awesome-chatgpt-prompts-zh/main/prompts-zh.json", 6 | "url": "https://github.com/PlexPt/awesome-chatgpt-prompts-zh" 7 | }, 8 | { 9 | "key": "awesome-chatgpt-prompts-zh-TW", 10 | "desc": "ChatGPT 中文調教指南 (透過 OpenAI / OpenCC 協助,從簡體中文轉換為繁體中文的版本)", 11 | "downloadUrl": "https://raw.githubusercontent.com/PlexPt/awesome-chatgpt-prompts-zh/main/prompts-zh-TW.json", 12 | "url": "https://github.com/PlexPt/awesome-chatgpt-prompts-zh" 13 | } 14 | ] 15 | -------------------------------------------------------------------------------- /src/components/common/HoverButton/Button.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 21 | -------------------------------------------------------------------------------- /src/components/common/HoverButton/index.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 47 | -------------------------------------------------------------------------------- /src/components/common/NaiveProvider/index.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 44 | -------------------------------------------------------------------------------- /src/components/common/Setting/Advanced.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 71 | -------------------------------------------------------------------------------- /src/components/common/Setting/index.vue: -------------------------------------------------------------------------------- 1 | 39 | 40 | 85 | -------------------------------------------------------------------------------- /src/components/common/SvgIcon/index.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 22 | -------------------------------------------------------------------------------- /src/components/common/UserAvatar/index.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 41 | -------------------------------------------------------------------------------- /src/components/common/index.ts: -------------------------------------------------------------------------------- 1 | import HoverButton from './HoverButton/index.vue' 2 | import NaiveProvider from './NaiveProvider/index.vue' 3 | import SvgIcon from './SvgIcon/index.vue' 4 | import UserAvatar from './UserAvatar/index.vue' 5 | import Setting from './Setting/index.vue' 6 | import PromptStore from './PromptStore/index.vue' 7 | 8 | export { HoverButton, NaiveProvider, SvgIcon, UserAvatar, Setting, PromptStore } 9 | -------------------------------------------------------------------------------- /src/components/custom/GithubSite.vue: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /src/components/custom/index.ts: -------------------------------------------------------------------------------- 1 | import GithubSite from './GithubSite.vue' 2 | 3 | export { GithubSite } 4 | -------------------------------------------------------------------------------- /src/hooks/useBasicLayout.ts: -------------------------------------------------------------------------------- 1 | import { breakpointsTailwind, useBreakpoints } from '@vueuse/core' 2 | 3 | export function useBasicLayout() { 4 | const breakpoints = useBreakpoints(breakpointsTailwind) 5 | const isMobile = breakpoints.smaller('sm') 6 | 7 | return { isMobile } 8 | } 9 | -------------------------------------------------------------------------------- /src/hooks/useIconRender.ts: -------------------------------------------------------------------------------- 1 | import { h } from 'vue' 2 | import { SvgIcon } from '@/components/common' 3 | 4 | export const useIconRender = () => { 5 | interface IconConfig { 6 | icon?: string 7 | color?: string 8 | fontSize?: number 9 | } 10 | 11 | interface IconStyle { 12 | color?: string 13 | fontSize?: string 14 | } 15 | 16 | const iconRender = (config: IconConfig) => { 17 | const { color, fontSize, icon } = config 18 | 19 | const style: IconStyle = {} 20 | 21 | if (color) 22 | style.color = color 23 | 24 | if (fontSize) 25 | style.fontSize = `${fontSize}px` 26 | 27 | if (!icon) 28 | window.console.warn('iconRender: icon is required') 29 | 30 | return () => h(SvgIcon, { icon, style }) 31 | } 32 | 33 | return { 34 | iconRender, 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/hooks/useLanguage.ts: -------------------------------------------------------------------------------- 1 | import { computed } from 'vue' 2 | import { enUS, koKR, zhCN, zhTW } from 'naive-ui' 3 | import { useAppStore } from '@/store' 4 | import { setLocale } from '@/locales' 5 | 6 | export function useLanguage() { 7 | const appStore = useAppStore() 8 | 9 | const language = computed(() => { 10 | switch (appStore.language) { 11 | case 'en-US': 12 | setLocale('en-US') 13 | return enUS 14 | case 'ru-RU': 15 | setLocale('ru-RU') 16 | return enUS 17 | case 'ko-KR': 18 | setLocale('ko-KR') 19 | return koKR 20 | case 'zh-CN': 21 | setLocale('zh-CN') 22 | return zhCN 23 | case 'zh-TW': 24 | setLocale('zh-TW') 25 | return zhTW 26 | case 'vi-VN': 27 | setLocale('vi-VN') 28 | return zhTW 29 | case 'fr-FR': 30 | setLocale('fr-FR') 31 | return enUS 32 | case 'tr-TR': 33 | setLocale('tr-TR') 34 | return enUS 35 | default: 36 | setLocale('zh-CN') 37 | return zhCN 38 | } 39 | }) 40 | 41 | return { language } 42 | } 43 | -------------------------------------------------------------------------------- /src/hooks/useTheme.ts: -------------------------------------------------------------------------------- 1 | import type { GlobalThemeOverrides } from 'naive-ui' 2 | import { computed, watch } from 'vue' 3 | import { darkTheme, useOsTheme } from 'naive-ui' 4 | import { useAppStore } from '@/store' 5 | 6 | export function useTheme() { 7 | const appStore = useAppStore() 8 | 9 | const OsTheme = useOsTheme() 10 | 11 | const isDark = computed(() => { 12 | if (appStore.theme === 'auto') 13 | return OsTheme.value === 'dark' 14 | else 15 | return appStore.theme === 'dark' 16 | }) 17 | 18 | const theme = computed(() => { 19 | return isDark.value ? darkTheme : undefined 20 | }) 21 | 22 | const themeOverrides = computed(() => { 23 | if (isDark.value) { 24 | return { 25 | common: {}, 26 | } 27 | } 28 | return {} 29 | }) 30 | 31 | watch( 32 | () => isDark.value, 33 | (dark) => { 34 | if (dark) 35 | document.documentElement.classList.add('dark') 36 | else 37 | document.documentElement.classList.remove('dark') 38 | }, 39 | { immediate: true }, 40 | ) 41 | 42 | return { theme, themeOverrides } 43 | } 44 | -------------------------------------------------------------------------------- /src/lib/wavtools/index.js: -------------------------------------------------------------------------------- 1 | import { WavPacker } from './lib/wav_packer.js'; 2 | import { AudioAnalysis } from './lib/analysis/audio_analysis.js'; 3 | import { WavStreamPlayer } from './lib/wav_stream_player.js'; 4 | import { WavRecorder } from './lib/wav_recorder.js'; 5 | 6 | export { AudioAnalysis, WavPacker, WavStreamPlayer, WavRecorder }; 7 | -------------------------------------------------------------------------------- /src/lib/wavtools/lib/analysis/constants.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Constants for help with visualization 3 | * Helps map frequency ranges from Fast Fourier Transform 4 | * to human-interpretable ranges, notably music ranges and 5 | * human vocal ranges. 6 | */ 7 | 8 | // Eighth octave frequencies 9 | const octave8Frequencies = [ 10 | 4186.01, 4434.92, 4698.63, 4978.03, 5274.04, 5587.65, 5919.91, 6271.93, 11 | 6644.88, 7040.0, 7458.62, 7902.13, 12 | ]; 13 | 14 | // Labels for each of the above frequencies 15 | const octave8FrequencyLabels = [ 16 | 'C', 17 | 'C#', 18 | 'D', 19 | 'D#', 20 | 'E', 21 | 'F', 22 | 'F#', 23 | 'G', 24 | 'G#', 25 | 'A', 26 | 'A#', 27 | 'B', 28 | ]; 29 | 30 | /** 31 | * All note frequencies from 1st to 8th octave 32 | * in format "A#8" (A#, 8th octave) 33 | */ 34 | export const noteFrequencies = []; 35 | export const noteFrequencyLabels = []; 36 | for (let i = 1; i <= 8; i++) { 37 | for (let f = 0; f < octave8Frequencies.length; f++) { 38 | const freq = octave8Frequencies[f]; 39 | noteFrequencies.push(freq / Math.pow(2, 8 - i)); 40 | noteFrequencyLabels.push(octave8FrequencyLabels[f] + i); 41 | } 42 | } 43 | 44 | /** 45 | * Subset of the note frequencies between 32 and 2000 Hz 46 | * 6 octave range: C1 to B6 47 | */ 48 | const voiceFrequencyRange = [32.0, 2000.0]; 49 | export const voiceFrequencies = noteFrequencies.filter((_, i) => { 50 | return ( 51 | noteFrequencies[i] > voiceFrequencyRange[0] && 52 | noteFrequencies[i] < voiceFrequencyRange[1] 53 | ); 54 | }); 55 | export const voiceFrequencyLabels = noteFrequencyLabels.filter((_, i) => { 56 | return ( 57 | noteFrequencies[i] > voiceFrequencyRange[0] && 58 | noteFrequencies[i] < voiceFrequencyRange[1] 59 | ); 60 | }); 61 | -------------------------------------------------------------------------------- /src/locales/index.ts: -------------------------------------------------------------------------------- 1 | import type { App } from 'vue' 2 | import { createI18n } from 'vue-i18n' 3 | import enUS from './en-US' 4 | import koKR from './ko-KR' 5 | import zhCN from './zh-CN' 6 | import zhTW from './zh-TW' 7 | import ruRU from './ru-RU' 8 | import viVn from './vi-VN' 9 | import frFr from './fr-FR' 10 | import trTr from './tr-TR' 11 | import { useAppStoreWithOut } from '@/store/modules/app' 12 | import type { Language } from '@/store/modules/app/helper' 13 | 14 | const appStore = useAppStoreWithOut() 15 | 16 | const defaultLocale = appStore.language || 'zh-CN' 17 | 18 | const i18n = createI18n({ 19 | locale: defaultLocale, 20 | fallbackLocale: 'en-US', 21 | allowComposition: true, 22 | messages: { 23 | 'en-US': enUS, 24 | 'ko-KR': koKR, 25 | 'zh-CN': zhCN, 26 | 'zh-TW': zhTW, 27 | 'ru-RU': ruRU, 28 | 'vi-VN': viVn, 29 | 'fr-FR': frFr, 30 | 'tr-TR': trTr, 31 | }, 32 | }) 33 | 34 | export const t = i18n.global.t 35 | 36 | export function setLocale(locale: Language) { 37 | i18n.global.locale = locale 38 | } 39 | 40 | export function setupI18n(app: App) { 41 | app.use(i18n) 42 | } 43 | 44 | export default i18n 45 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | import { setupI18n } from './locales' 4 | import { setupAssets, setupScrollbarStyle } from './plugins' 5 | import { setupStore } from './store' 6 | import { setupRouter } from './router' 7 | 8 | async function bootstrap() { 9 | const app = createApp(App) 10 | setupAssets() 11 | 12 | setupScrollbarStyle() 13 | 14 | setupStore(app) 15 | 16 | setupI18n(app) 17 | 18 | await setupRouter(app) 19 | 20 | app.mount('#app') 21 | } 22 | 23 | bootstrap() 24 | -------------------------------------------------------------------------------- /src/plugins/assets.ts: -------------------------------------------------------------------------------- 1 | import 'katex/dist/katex.min.css' 2 | import '@/styles/lib/tailwind.css' 3 | import '@/styles/lib/highlight.less' 4 | import '@/styles/lib/github-markdown.less' 5 | import '@/styles/global.less' 6 | 7 | /** Tailwind's Preflight Style Override */ 8 | function naiveStyleOverride() { 9 | const meta = document.createElement('meta') 10 | meta.name = 'naive-ui-style' 11 | document.head.appendChild(meta) 12 | } 13 | 14 | function setupAssets() { 15 | naiveStyleOverride() 16 | } 17 | 18 | export default setupAssets 19 | -------------------------------------------------------------------------------- /src/plugins/index.ts: -------------------------------------------------------------------------------- 1 | import setupAssets from './assets' 2 | import setupScrollbarStyle from './scrollbarStyle' 3 | 4 | export { setupAssets, setupScrollbarStyle } 5 | -------------------------------------------------------------------------------- /src/plugins/scrollbarStyle.ts: -------------------------------------------------------------------------------- 1 | import { darkTheme, lightTheme } from 'naive-ui' 2 | 3 | const setupScrollbarStyle = () => { 4 | const style = document.createElement('style') 5 | const styleContent = ` 6 | ::-webkit-scrollbar { 7 | background-color: transparent; 8 | width: ${lightTheme.Scrollbar.common?.scrollbarWidth}; 9 | } 10 | ::-webkit-scrollbar-thumb { 11 | background-color: ${lightTheme.Scrollbar.common?.scrollbarColor}; 12 | border-radius: ${lightTheme.Scrollbar.common?.scrollbarBorderRadius}; 13 | } 14 | html.dark ::-webkit-scrollbar { 15 | background-color: transparent; 16 | width: ${darkTheme.Scrollbar.common?.scrollbarWidth}; 17 | } 18 | html.dark ::-webkit-scrollbar-thumb { 19 | background-color: ${darkTheme.Scrollbar.common?.scrollbarColor}; 20 | border-radius: ${darkTheme.Scrollbar.common?.scrollbarBorderRadius}; 21 | } 22 | ` 23 | 24 | style.innerHTML = styleContent 25 | document.head.appendChild(style) 26 | } 27 | 28 | export default setupScrollbarStyle 29 | -------------------------------------------------------------------------------- /src/router/permission.ts: -------------------------------------------------------------------------------- 1 | import type { Router } from 'vue-router' 2 | import { useAuthStoreWithout } from '@/store/modules/auth' 3 | 4 | export function setupPageGuard(router: Router) { 5 | router.beforeEach(async (to, from, next) => { 6 | const authStore = useAuthStoreWithout() 7 | if (!authStore.session) { 8 | try { 9 | const data = await authStore.getSession() 10 | if (String(data.auth) === 'false' && authStore.token) 11 | authStore.removeToken() 12 | if (to.path === '/500') 13 | next({ name: 'Root' }) 14 | else 15 | next() 16 | } 17 | catch (error) { 18 | if (to.path !== '/500') 19 | next({ name: '500' }) 20 | else 21 | next() 22 | } 23 | } 24 | else { 25 | next() 26 | } 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /src/static/mitf/assets/checkerboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/c3c4b2717f59fdc7e74f3a616929f8b4ca50bd04/src/static/mitf/assets/checkerboard.png -------------------------------------------------------------------------------- /src/store/helper.ts: -------------------------------------------------------------------------------- 1 | import { createPinia } from 'pinia' 2 | 3 | export const store = createPinia() 4 | -------------------------------------------------------------------------------- /src/store/index.ts: -------------------------------------------------------------------------------- 1 | import type { App } from 'vue' 2 | import { store } from './helper' 3 | 4 | export function setupStore(app: App) { 5 | app.use(store) 6 | } 7 | 8 | export * from './modules' 9 | export * from "./homeStore" 10 | -------------------------------------------------------------------------------- /src/store/modules/app/helper.ts: -------------------------------------------------------------------------------- 1 | import { homeStore } from '@/store/homeStore' 2 | import { ss } from '@/utils/storage' 3 | 4 | const LOCAL_NAME = 'appSetting' 5 | 6 | export type Theme = 'light' | 'dark' | 'auto' 7 | 8 | export type Language = 'zh-CN' | 'zh-TW' | 'en-US' | 'ko-KR' | 'ru-RU' | 'vi-VN' | 'fr-FR' | 'tr-TR' 9 | 10 | export interface AppState { 11 | siderCollapsed: boolean 12 | theme: Theme 13 | language: Language 14 | } 15 | 16 | export function defaultSetting(): AppState { 17 | const userLang = navigator.language || navigator.userLanguage; 18 | let content:Language= 'en-US'; 19 | if (userLang.startsWith('zh-HK') || userLang.startsWith('zh-TW')) { 20 | content = 'zh-TW'; // 繁体中文 21 | } else if (userLang.startsWith('zh')) { 22 | content = 'zh-CN'; // 简体中文 23 | } else if (userLang.startsWith('fr')) { 24 | content = 'fr-FR'; // 法语 25 | } else if (userLang.startsWith('ko')) { 26 | content = 'ko-KR'; // 韩语 27 | } else if (userLang.startsWith('ru')) { 28 | content = 'ru-RU'; // 俄文 29 | } else if (userLang.startsWith('vi')) { 30 | content = 'vi-VN'; // 越南语 31 | } else if (userLang.startsWith('tr')) { 32 | content = 'tr-TR'; // 土耳其语 33 | } else { 34 | content = 'en-US'; // 英语 35 | } 36 | return { siderCollapsed: false, theme: homeStore.myData.session.theme=='light'?'light': 'auto', language: content } 37 | } 38 | 39 | export function getLocalSetting(): AppState { 40 | const localSetting: AppState | undefined = ss.get(LOCAL_NAME) 41 | return { ...defaultSetting(), ...localSetting } 42 | } 43 | 44 | export function setLocalSetting(setting: AppState): void { 45 | ss.set(LOCAL_NAME, setting) 46 | } 47 | -------------------------------------------------------------------------------- /src/store/modules/app/index.ts: -------------------------------------------------------------------------------- 1 | import { defineStore } from 'pinia' 2 | import type { AppState, Language, Theme } from './helper' 3 | import { getLocalSetting, setLocalSetting } from './helper' 4 | import { store } from '@/store/helper' 5 | 6 | export const useAppStore = defineStore('app-store', { 7 | state: (): AppState => getLocalSetting(), 8 | actions: { 9 | setSiderCollapsed(collapsed: boolean) { 10 | this.siderCollapsed = collapsed 11 | this.recordState() 12 | }, 13 | 14 | setTheme(theme: Theme) { 15 | this.theme = theme 16 | this.recordState() 17 | }, 18 | 19 | setLanguage(language: Language) { 20 | if (this.language !== language) { 21 | this.language = language 22 | this.recordState() 23 | } 24 | }, 25 | 26 | recordState() { 27 | setLocalSetting(this.$state) 28 | }, 29 | }, 30 | }) 31 | 32 | export function useAppStoreWithOut() { 33 | return useAppStore(store) 34 | } 35 | -------------------------------------------------------------------------------- /src/store/modules/auth/helper.ts: -------------------------------------------------------------------------------- 1 | import { ss } from '@/utils/storage' 2 | 3 | const LOCAL_NAME = 'SECRET_TOKEN' 4 | 5 | export function getToken() { 6 | return ss.get(LOCAL_NAME) 7 | } 8 | 9 | export function setToken(token: string) { 10 | return ss.set(LOCAL_NAME, token) 11 | } 12 | 13 | export function removeToken() { 14 | return ss.remove(LOCAL_NAME) 15 | } 16 | -------------------------------------------------------------------------------- /src/store/modules/auth/index.ts: -------------------------------------------------------------------------------- 1 | import { defineStore } from 'pinia' 2 | import { getToken, removeToken, setToken } from './helper' 3 | import { store } from '@/store/helper' 4 | import { fetchSession } from '@/api' 5 | import { gptConfigStore, homeStore } from '@/store/homeStore' 6 | import { useAppStore } from '@/store' 7 | const appStore = useAppStore() 8 | interface SessionResponse { 9 | theme?: string 10 | auth: boolean 11 | model: 'ChatGPTAPI' | 'ChatGPTUnofficialProxyAPI' 12 | } 13 | 14 | export interface AuthState { 15 | token: string | undefined 16 | session: SessionResponse | null 17 | } 18 | 19 | export const useAuthStore = defineStore('auth-store', { 20 | state: (): AuthState => ({ 21 | token: getToken(), 22 | session: null, 23 | }), 24 | 25 | getters: { 26 | isChatGPTAPI(state): boolean { 27 | return state.session?.model === 'ChatGPTAPI' 28 | }, 29 | }, 30 | 31 | actions: { 32 | async getSession() { 33 | try { 34 | const { data } = await fetchSession() 35 | this.session = { ...data } 36 | 37 | homeStore.setMyData({session: data }); 38 | if(appStore.$state.theme=='auto' ){ 39 | appStore.setTheme( data.theme && data.theme=='light' ?'light':'dark') 40 | } 41 | 42 | let str = localStorage.getItem('gptConfigStore'); 43 | if( ! str ) setTimeout( ()=> gptConfigStore.setInit() , 500); 44 | return Promise.resolve(data) 45 | } 46 | catch (error) { 47 | return Promise.reject(error) 48 | } 49 | }, 50 | 51 | setToken(token: string) { 52 | this.token = token 53 | setToken(token) 54 | }, 55 | 56 | removeToken() { 57 | this.token = undefined 58 | removeToken() 59 | }, 60 | }, 61 | }) 62 | 63 | export function useAuthStoreWithout() { 64 | return useAuthStore(store) 65 | } 66 | -------------------------------------------------------------------------------- /src/store/modules/chat/helper.ts: -------------------------------------------------------------------------------- 1 | import { ss } from '@/utils/storage' 2 | 3 | const LOCAL_NAME = 'chatStorage' 4 | 5 | export function defaultState(): Chat.ChatState { 6 | const uuid = 1002 7 | return { 8 | active: uuid, 9 | usingContext: true, 10 | history: [{ uuid, title: 'New Chat', isEdit: false }], 11 | chat: [{ uuid, data: [] }], 12 | } 13 | } 14 | 15 | export function getLocalState(): Chat.ChatState { 16 | const localState = ss.get(LOCAL_NAME) 17 | return { ...defaultState(), ...localState } 18 | } 19 | 20 | export function setLocalState(state: Chat.ChatState) { 21 | ss.set(LOCAL_NAME, state) 22 | } 23 | -------------------------------------------------------------------------------- /src/store/modules/index.ts: -------------------------------------------------------------------------------- 1 | export * from './app' 2 | export * from './chat' 3 | export * from './user' 4 | export * from './prompt' 5 | export * from './settings' 6 | export * from './auth' 7 | -------------------------------------------------------------------------------- /src/store/modules/prompt/helper.ts: -------------------------------------------------------------------------------- 1 | import { ss } from '@/utils/storage' 2 | 3 | const LOCAL_NAME = 'promptStore' 4 | 5 | export type PromptList = [] 6 | 7 | export interface PromptStore { 8 | promptList: PromptList 9 | } 10 | 11 | export function getLocalPromptList(): PromptStore { 12 | const promptStore: PromptStore | undefined = ss.get(LOCAL_NAME) 13 | return promptStore ?? { promptList: [] } 14 | } 15 | 16 | export function setLocalPromptList(promptStore: PromptStore): void { 17 | ss.set(LOCAL_NAME, promptStore) 18 | } 19 | -------------------------------------------------------------------------------- /src/store/modules/prompt/index.ts: -------------------------------------------------------------------------------- 1 | import { defineStore } from 'pinia' 2 | import type { PromptStore } from './helper' 3 | import { getLocalPromptList, setLocalPromptList } from './helper' 4 | 5 | export const usePromptStore = defineStore('prompt-store', { 6 | state: (): PromptStore => getLocalPromptList(), 7 | 8 | actions: { 9 | updatePromptList(promptList: []) { 10 | this.$patch({ promptList }) 11 | setLocalPromptList({ promptList }) 12 | }, 13 | getPromptList() { 14 | return this.$state 15 | }, 16 | }, 17 | }) 18 | -------------------------------------------------------------------------------- /src/store/modules/settings/helper.ts: -------------------------------------------------------------------------------- 1 | import { ss } from '@/utils/storage' 2 | 3 | const LOCAL_NAME = 'settingsStorage' 4 | 5 | export interface SettingsState { 6 | systemMessage: string 7 | temperature: number 8 | top_p: number 9 | } 10 | 11 | export function defaultSetting(): SettingsState { 12 | return { 13 | systemMessage: 'You are ChatGPT, a large language model trained by OpenAI. Follow the user\'s instructions carefully. Respond using markdown.', 14 | temperature: 0.8, 15 | top_p: 1, 16 | } 17 | } 18 | 19 | export function getLocalState(): SettingsState { 20 | const localSetting: SettingsState | undefined = ss.get(LOCAL_NAME) 21 | return { ...defaultSetting(), ...localSetting } 22 | } 23 | 24 | export function setLocalState(setting: SettingsState): void { 25 | ss.set(LOCAL_NAME, setting) 26 | } 27 | 28 | export function removeLocalState() { 29 | ss.remove(LOCAL_NAME) 30 | } 31 | -------------------------------------------------------------------------------- /src/store/modules/settings/index.ts: -------------------------------------------------------------------------------- 1 | import { defineStore } from 'pinia' 2 | import type { SettingsState } from './helper' 3 | import { defaultSetting, getLocalState, removeLocalState, setLocalState } from './helper' 4 | 5 | export const useSettingStore = defineStore('setting-store', { 6 | state: (): SettingsState => getLocalState(), 7 | actions: { 8 | updateSetting(settings: Partial) { 9 | this.$state = { ...this.$state, ...settings } 10 | this.recordState() 11 | }, 12 | 13 | resetSetting() { 14 | this.$state = defaultSetting() 15 | removeLocalState() 16 | }, 17 | 18 | recordState() { 19 | setLocalState(this.$state) 20 | }, 21 | }, 22 | }) 23 | -------------------------------------------------------------------------------- /src/store/modules/user/helper.ts: -------------------------------------------------------------------------------- 1 | import { ss } from '@/utils/storage' 2 | import { t } from '@/locales' 3 | import { homeStore } from "@/store"; 4 | const LOCAL_NAME = 'userStorage' 5 | const backgroundImage = homeStore.myData.session.backgroundImage ?? "https://t.alcy.cc/fj/" 6 | 7 | export interface UserInfo { 8 | avatar: string 9 | name: string 10 | backgroundImage: string 11 | description: string 12 | } 13 | 14 | export interface UserState { 15 | userInfo: UserInfo 16 | } 17 | 18 | export function defaultSetting(): UserState { 19 | return { 20 | userInfo: { 21 | avatar: 'https://raw.githubusercontent.com/Dooy/chatgpt-web-midjourney-proxy/main/src/assets/avatar.jpg', 22 | name: t('mjset.sysname'),//'AI绘图', 23 | description: 'Star on GitHub', 24 | }, 25 | } 26 | } 27 | 28 | export function getLocalState(): UserState { 29 | const localSetting: UserState | undefined = ss.get(LOCAL_NAME) 30 | return { ...defaultSetting(), ...localSetting } 31 | } 32 | 33 | export function setLocalState(setting: UserState): void { 34 | ss.set(LOCAL_NAME, setting) 35 | } 36 | -------------------------------------------------------------------------------- /src/store/modules/user/index.ts: -------------------------------------------------------------------------------- 1 | import { defineStore } from 'pinia' 2 | import type { UserInfo, UserState } from './helper' 3 | import { defaultSetting, getLocalState, setLocalState } from './helper' 4 | 5 | export const useUserStore = defineStore('user-store', { 6 | state: (): UserState => getLocalState(), 7 | actions: { 8 | updateUserInfo(userInfo: Partial) { 9 | this.userInfo = { ...this.userInfo, ...userInfo } 10 | this.recordState() 11 | }, 12 | 13 | resetUserInfo() { 14 | this.userInfo = { ...defaultSetting().userInfo } 15 | this.recordState() 16 | }, 17 | 18 | recordState() { 19 | setLocalState(this.$state) 20 | }, 21 | }, 22 | }) 23 | -------------------------------------------------------------------------------- /src/styles/global.less: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #app { 4 | height: 100%; 5 | } 6 | 7 | body { 8 | padding-bottom: constant(safe-area-inset-bottom); 9 | padding-bottom: env(safe-area-inset-bottom); 10 | } 11 | 12 | .active{ 13 | color: #4b9e5f!important; 14 | } 15 | -------------------------------------------------------------------------------- /src/styles/lib/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /src/typings/chat.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace Chat { 2 | 3 | interface Chat { 4 | dateTime: string 5 | text: string 6 | inversion?: boolean 7 | error?: boolean 8 | loading?: boolean 9 | conversationOptions?: ConversationRequest | null 10 | requestOptions: { prompt: string; options?: ConversationRequest | null } 11 | model?:string //模型 12 | mjID?:string //MJ的ID 13 | opt?:{ 14 | progress?:string,seed?:number, imageUrl?:string 15 | , status?:string, images?:string[] 16 | ,promptEn?:string,buttons?:any[] 17 | ,action?:string 18 | ,duration?:number 19 | ,lkey?:string 20 | } // 21 | uuid?:number 22 | index?:number 23 | myid?:string //唯一随机 24 | logo?:string 25 | 26 | //progress?:string 27 | } 28 | 29 | interface History { 30 | title: string 31 | isEdit: boolean 32 | uuid: number 33 | } 34 | 35 | interface ChatState { 36 | active: number | null 37 | usingContext: boolean; 38 | history: History[] 39 | chat: { uuid: number; data: Chat[] }[] 40 | } 41 | 42 | interface ConversationRequest { 43 | conversationId?: string 44 | parentMessageId?: string 45 | } 46 | 47 | interface ConversationResponse { 48 | conversationId: string 49 | detail: { 50 | choices: { finish_reason: string; index: number; logprobs: any; text: string }[] 51 | created: number 52 | id: string 53 | model: string 54 | object: string 55 | usage: { completion_tokens: number; prompt_tokens: number; total_tokens: number } 56 | } 57 | id: string 58 | parentMessageId: string 59 | role: string 60 | text: string 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/typings/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | interface ImportMetaEnv { 4 | readonly VITE_GLOB_API_URL: string; 5 | readonly VITE_APP_API_BASE_URL: string; 6 | readonly VITE_GLOB_OPEN_LONG_REPLY: string; 7 | readonly VITE_GLOB_APP_PWA: string; 8 | } 9 | -------------------------------------------------------------------------------- /src/typings/global.d.ts: -------------------------------------------------------------------------------- 1 | interface Window { 2 | $loadingBar?: import('naive-ui').LoadingBarProviderInst; 3 | $dialog?: import('naive-ui').DialogProviderInst; 4 | $message?: import('naive-ui').MessageProviderInst; 5 | $notification?: import('naive-ui').NotificationProviderInst; 6 | } 7 | -------------------------------------------------------------------------------- /src/utils/copy.ts: -------------------------------------------------------------------------------- 1 | export function copyToClip(text: string) { 2 | return new Promise((resolve, reject) => { 3 | try { 4 | const input: HTMLTextAreaElement = document.createElement('textarea') 5 | input.setAttribute('readonly', 'readonly') 6 | input.value = text 7 | document.body.appendChild(input) 8 | input.select() 9 | if (document.execCommand('copy')) 10 | document.execCommand('copy') 11 | document.body.removeChild(input) 12 | resolve(text) 13 | } 14 | catch (error) { 15 | reject(error) 16 | } 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /src/utils/functions/debounce.ts: -------------------------------------------------------------------------------- 1 | type CallbackFunc = (...args: T) => void 2 | 3 | export function debounce( 4 | func: CallbackFunc, 5 | wait: number, 6 | ): (...args: T) => void { 7 | let timeoutId: ReturnType | undefined 8 | 9 | return (...args: T) => { 10 | const later = () => { 11 | clearTimeout(timeoutId) 12 | func(...args) 13 | } 14 | 15 | clearTimeout(timeoutId) 16 | timeoutId = setTimeout(later, wait) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/utils/functions/index.ts: -------------------------------------------------------------------------------- 1 | export function getCurrentDate() { 2 | const date = new Date() 3 | const day = date.getDate() 4 | const month = date.getMonth() + 1 5 | const year = date.getFullYear() 6 | return `${year}-${month}-${day}` 7 | } 8 | -------------------------------------------------------------------------------- /src/utils/is/index.ts: -------------------------------------------------------------------------------- 1 | export function isNumber(value: T | unknown): value is number { 2 | return Object.prototype.toString.call(value) === '[object Number]' 3 | } 4 | 5 | export function isString(value: T | unknown): value is string { 6 | return Object.prototype.toString.call(value) === '[object String]' 7 | } 8 | 9 | export function isBoolean(value: T | unknown): value is boolean { 10 | return Object.prototype.toString.call(value) === '[object Boolean]' 11 | } 12 | 13 | export function isNull(value: T | unknown): value is null { 14 | return Object.prototype.toString.call(value) === '[object Null]' 15 | } 16 | 17 | export function isUndefined(value: T | unknown): value is undefined { 18 | return Object.prototype.toString.call(value) === '[object Undefined]' 19 | } 20 | 21 | export function isObject(value: T | unknown): value is object { 22 | return Object.prototype.toString.call(value) === '[object Object]' 23 | } 24 | 25 | export function isArray(value: T | unknown): value is T { 26 | return Object.prototype.toString.call(value) === '[object Array]' 27 | } 28 | 29 | export function isFunction any | void | never>(value: T | unknown): value is T { 30 | return Object.prototype.toString.call(value) === '[object Function]' 31 | } 32 | 33 | export function isDate(value: T | unknown): value is T { 34 | return Object.prototype.toString.call(value) === '[object Date]' 35 | } 36 | 37 | export function isRegExp(value: T | unknown): value is T { 38 | return Object.prototype.toString.call(value) === '[object RegExp]' 39 | } 40 | 41 | export function isPromise>(value: T | unknown): value is T { 42 | return Object.prototype.toString.call(value) === '[object Promise]' 43 | } 44 | 45 | export function isSet>(value: T | unknown): value is T { 46 | return Object.prototype.toString.call(value) === '[object Set]' 47 | } 48 | 49 | export function isMap>(value: T | unknown): value is T { 50 | return Object.prototype.toString.call(value) === '[object Map]' 51 | } 52 | 53 | export function isFile(value: T | unknown): value is T { 54 | return Object.prototype.toString.call(value) === '[object File]' 55 | } 56 | -------------------------------------------------------------------------------- /src/utils/request/axios.ts: -------------------------------------------------------------------------------- 1 | import axios, { type AxiosResponse } from 'axios' 2 | import { useAuthStore } from '@/store' 3 | 4 | const service = axios.create({ 5 | baseURL: import.meta.env.VITE_GLOB_API_URL, 6 | }) 7 | 8 | service.interceptors.request.use( 9 | (config) => { 10 | const token = useAuthStore().token 11 | if (token) 12 | config.headers.Authorization = `Bearer ${token}` 13 | return config 14 | }, 15 | (error) => { 16 | return Promise.reject(error.response) 17 | }, 18 | ) 19 | 20 | service.interceptors.response.use( 21 | (response: AxiosResponse): AxiosResponse => { 22 | if (response.status === 200) 23 | return response 24 | 25 | throw new Error(response.status.toString()) 26 | }, 27 | (error) => { 28 | return Promise.reject(error) 29 | }, 30 | ) 31 | 32 | export default service 33 | -------------------------------------------------------------------------------- /src/utils/request/index.ts: -------------------------------------------------------------------------------- 1 | import type { AxiosProgressEvent, AxiosResponse, GenericAbortSignal } from 'axios' 2 | import request from './axios' 3 | import { useAuthStore } from '@/store' 4 | 5 | export interface HttpOption { 6 | url: string 7 | data?: any 8 | method?: string 9 | headers?: any 10 | onDownloadProgress?: (progressEvent: AxiosProgressEvent) => void 11 | signal?: GenericAbortSignal 12 | beforeRequest?: () => void 13 | afterRequest?: () => void 14 | } 15 | 16 | export interface Response { 17 | data: T 18 | message: string | null 19 | status: string 20 | } 21 | 22 | function http( 23 | { url, data, method, headers, onDownloadProgress, signal, beforeRequest, afterRequest }: HttpOption, 24 | ) { 25 | const successHandler = (res: AxiosResponse>) => { 26 | const authStore = useAuthStore() 27 | 28 | if (res.data.status === 'Success' || typeof res.data === 'string') 29 | return res.data 30 | 31 | if (res.data.status === 'Unauthorized') { 32 | authStore.removeToken() 33 | window.location.reload() 34 | } 35 | 36 | return Promise.reject(res.data) 37 | } 38 | 39 | const failHandler = (error: Response) => { 40 | afterRequest?.() 41 | throw new Error(error?.message || 'Error') 42 | } 43 | 44 | beforeRequest?.() 45 | 46 | method = method || 'GET' 47 | 48 | const params = Object.assign(typeof data === 'function' ? data() : data ?? {}, {}) 49 | 50 | return method === 'GET' 51 | ? request.get(url, { params, signal, onDownloadProgress }).then(successHandler, failHandler) 52 | : request.post(url, params, { headers, signal, onDownloadProgress }).then(successHandler, failHandler) 53 | } 54 | 55 | export function get( 56 | { url, data, method = 'GET', onDownloadProgress, signal, beforeRequest, afterRequest }: HttpOption, 57 | ): Promise> { 58 | return http({ 59 | url, 60 | method, 61 | data, 62 | onDownloadProgress, 63 | signal, 64 | beforeRequest, 65 | afterRequest, 66 | }) 67 | } 68 | 69 | export function post( 70 | { url, data, method = 'POST', headers, onDownloadProgress, signal, beforeRequest, afterRequest }: HttpOption, 71 | ): Promise> { 72 | return http({ 73 | url, 74 | method, 75 | data, 76 | headers, 77 | onDownloadProgress, 78 | signal, 79 | beforeRequest, 80 | afterRequest, 81 | }) 82 | } 83 | 84 | export default post 85 | -------------------------------------------------------------------------------- /src/utils/storage/index.ts: -------------------------------------------------------------------------------- 1 | interface StorageData { 2 | data: T 3 | expire: number | null 4 | } 5 | 6 | export function createLocalStorage(options?: { expire?: number | null }) { 7 | const DEFAULT_CACHE_TIME = 60 * 60 * 24 * 7 8 | 9 | const { expire } = Object.assign({ expire: DEFAULT_CACHE_TIME }, options) 10 | 11 | function set(key: string, data: T) { 12 | const storageData: StorageData = { 13 | data, 14 | expire: expire !== null ? new Date().getTime() + expire * 1000 : null, 15 | } 16 | 17 | const json = JSON.stringify(storageData) 18 | window.localStorage.setItem(key, json) 19 | } 20 | 21 | function get(key: string) { 22 | const json = window.localStorage.getItem(key) 23 | if (json) { 24 | let storageData: StorageData | null = null 25 | 26 | try { 27 | storageData = JSON.parse(json) 28 | } 29 | catch { 30 | // Prevent failure 31 | } 32 | 33 | if (storageData) { 34 | const { data, expire } = storageData 35 | if (expire === null || expire >= Date.now()) 36 | return data 37 | } 38 | 39 | remove(key) 40 | return null 41 | } 42 | } 43 | 44 | function remove(key: string) { 45 | window.localStorage.removeItem(key) 46 | } 47 | 48 | function clear() { 49 | window.localStorage.clear() 50 | } 51 | 52 | return { set, get, remove, clear } 53 | } 54 | 55 | export const ls = createLocalStorage() 56 | 57 | export const ss = createLocalStorage({ expire: null }) 58 | -------------------------------------------------------------------------------- /src/views/chat/components/Message/Avatar.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 32 | -------------------------------------------------------------------------------- /src/views/chat/components/index.ts: -------------------------------------------------------------------------------- 1 | import Message from './Message/index.vue' 2 | 3 | export { Message } 4 | -------------------------------------------------------------------------------- /src/views/chat/hooks/useChat.ts: -------------------------------------------------------------------------------- 1 | import { useChatStore } from '@/store' 2 | 3 | export function useChat() { 4 | const chatStore = useChatStore() 5 | 6 | const getChatByUuidAndIndex = (uuid: number, index: number) => { 7 | return chatStore.getChatByUuidAndIndex(uuid, index) 8 | } 9 | 10 | const addChat = (uuid: number, chat: Chat.Chat) => { 11 | chatStore.addChatByUuid(uuid, chat) 12 | } 13 | 14 | const updateChat = (uuid: number, index: number, chat: Chat.Chat) => { 15 | chatStore.updateChatByUuid(uuid, index, chat) 16 | } 17 | 18 | const updateChatSome = (uuid: number, index: number, chat: Partial) => { 19 | chatStore.updateChatSomeByUuid(uuid, index, chat) 20 | } 21 | 22 | return { 23 | addChat, 24 | updateChat, 25 | updateChatSome, 26 | getChatByUuidAndIndex, 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/views/chat/hooks/useScroll.ts: -------------------------------------------------------------------------------- 1 | import type { Ref } from 'vue' 2 | import { nextTick, ref } from 'vue' 3 | 4 | type ScrollElement = HTMLDivElement | null 5 | 6 | interface ScrollReturn { 7 | scrollRef: Ref 8 | scrollToBottom: () => Promise 9 | scrollToTop: () => Promise 10 | scrollToBottomIfAtBottom: () => Promise 11 | } 12 | 13 | export function useScroll(): ScrollReturn { 14 | const scrollRef = ref(null) 15 | 16 | const scrollToBottom = async () => { 17 | await nextTick() 18 | if (scrollRef.value) 19 | scrollRef.value.scrollTop = scrollRef.value.scrollHeight 20 | } 21 | 22 | const scrollToTop = async () => { 23 | await nextTick() 24 | if (scrollRef.value) 25 | scrollRef.value.scrollTop = 0 26 | } 27 | 28 | const scrollToBottomIfAtBottom = async () => { 29 | await nextTick() 30 | if (scrollRef.value) { 31 | const threshold = 100 // 阈值,表示滚动条到底部的距离阈值 32 | const distanceToBottom = scrollRef.value.scrollHeight - scrollRef.value.scrollTop - scrollRef.value.clientHeight 33 | if (distanceToBottom <= threshold) 34 | scrollRef.value.scrollTop = scrollRef.value.scrollHeight 35 | } 36 | } 37 | 38 | return { 39 | scrollRef, 40 | scrollToBottom, 41 | scrollToTop, 42 | scrollToBottomIfAtBottom, 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/views/chat/hooks/useUsingContext.ts: -------------------------------------------------------------------------------- 1 | import { computed } from 'vue' 2 | import { useMessage } from 'naive-ui' 3 | import { t } from '@/locales' 4 | import { useChatStore } from '@/store' 5 | 6 | export function useUsingContext() { 7 | const ms = useMessage() 8 | const chatStore = useChatStore() 9 | const usingContext = computed(() => chatStore.usingContext) 10 | 11 | function toggleUsingContext() { 12 | chatStore.setUsingContext(!usingContext.value) 13 | if (usingContext.value) 14 | ms.success(t('chat.turnOnContext')) 15 | else 16 | ms.warning(t('chat.turnOffContext')) 17 | } 18 | 19 | return { 20 | usingContext, 21 | toggleUsingContext, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/views/chat/layout/Layout.vue: -------------------------------------------------------------------------------- 1 | 64 | 65 | 84 | 85 | 90 | -------------------------------------------------------------------------------- /src/views/chat/layout/Permission.vue: -------------------------------------------------------------------------------- 1 | 53 | 54 | 81 | -------------------------------------------------------------------------------- /src/views/chat/layout/index.ts: -------------------------------------------------------------------------------- 1 | import ChatLayout from './Layout.vue' 2 | 3 | export { ChatLayout } 4 | -------------------------------------------------------------------------------- /src/views/chat/layout/sider/Footer.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 25 | -------------------------------------------------------------------------------- /src/views/exception/404/index.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 32 | -------------------------------------------------------------------------------- /src/views/exception/500/index.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 33 | -------------------------------------------------------------------------------- /src/views/kling/kgImage.vue: -------------------------------------------------------------------------------- 1 | 44 | 45 | -------------------------------------------------------------------------------- /src/views/kling/kgInput.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/views/luma/layout.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | 60 | 65 | -------------------------------------------------------------------------------- /src/views/luma/pixCamera.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": { 3 | "horizontal_left": "水平向左", 4 | "horizontal_right": "水平向右", 5 | "vertical_up": "垂直向上", 6 | "vertical_down": "垂直向下", 7 | "crane_up": "上升镜头", 8 | "hitchcock": "希区柯克变焦", 9 | "zoom_in": "放大", 10 | "zoom_out": "缩小", 11 | "quickly_zoom_in": "快速推进", 12 | "quickly_zoom_out": "快速拉远", 13 | "smooth_zoom_in": "平滑推进", 14 | "super_dolly_out": "超级拉远", 15 | "left_follow": "左侧跟拍", 16 | "right_follow": "右侧跟拍", 17 | "pan_left": "左侧环弧", 18 | "pan_right": "右侧环弧", 19 | "fix_bg": "固定镜头", 20 | "camera_rotation": "镜头旋转", 21 | "robo_arm": "机械臂运动", 22 | "whip_pan": "快速摇镜" 23 | }, 24 | "image": { 25 | "horizontal_left": "https://media.pixverse.ai/asset/template/web_horizontalleft_250429.gif", 26 | "horizontal_right": "https://media.pixverse.ai/asset/template/web_horizontalright_250429.gif", 27 | "vertical_up": "https://media.pixverse.ai/asset/template/web_verticalup_250429.gif", 28 | "vertical_down": "https://media.pixverse.ai/asset/template/web_verticaldown _250429.gif", 29 | "crane_up": "https://media.pixverse.ai/asset/template/web_craneup_250428.gif", 30 | "hitchcock": "https://media.pixverse.ai/asset/template/Dolly Zoom.gif", 31 | "zoom_in": "https://media.pixverse.ai/asset/template/web_zoomin_250429.gif", 32 | "zoom_out": "https://media.pixverse.ai/asset/template/web_zoomout_250429.gif", 33 | "quickly_zoom_in": "https://media.pixverse.ai/asset/template/web_quicklyzoomin_250428.gif", 34 | "quickly_zoom_out": "https://media.pixverse.ai/asset/template/web_quicklyzoomout_250428.gif", 35 | "smooth_zoom_in": "https://media.pixverse.ai/asset/template/web_smoothzoomin_250428.gif", 36 | "super_dolly_out": "https://media.pixverse.ai/asset/template/web_superdollyout_250428.gif", 37 | "left_follow": "https://media.pixverse.ai/asset/template/Left Tracking Shot.gif", 38 | "right_follow": "https://media.pixverse.ai/asset/template/Right Tracking Shot.gif", 39 | "pan_left": "https://media.pixverse.ai/asset/template/Left Arc Shot.gif", 40 | "pan_right": "https://media.pixverse.ai/asset/template/Right Arc Shot.gif", 41 | "fix_bg": "https://media.pixverse.ai/asset/template/Fixed Shot.gif", 42 | "camera_rotation": "https://media.pixverse.ai/asset/template/web_camerarotation_250428.gif", 43 | "robo_arm": "https://media.pixverse.ai/asset/template/web_roboarm_250428.gif", 44 | "whip_pan": "https://media.pixverse.ai/asset/template/web_whippan_250428.gif" 45 | } 46 | } -------------------------------------------------------------------------------- /src/views/luma/runInput.vue: -------------------------------------------------------------------------------- 1 | 26 | -------------------------------------------------------------------------------- /src/views/luma/video.vue: -------------------------------------------------------------------------------- 1 | 12 | -------------------------------------------------------------------------------- /src/views/luma/voInput.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 60 | 61 | -------------------------------------------------------------------------------- /src/views/mj/aiCanvas.vue: -------------------------------------------------------------------------------- 1 | 43 | -------------------------------------------------------------------------------- /src/views/mj/aiFace.vue: -------------------------------------------------------------------------------- 1 | 32 | -------------------------------------------------------------------------------- /src/views/mj/aiFooter.vue: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /src/views/mj/aiGallery.vue: -------------------------------------------------------------------------------- 1 | 52 | 53 | -------------------------------------------------------------------------------- /src/views/mj/aiGpts.vue: -------------------------------------------------------------------------------- 1 | 22 | 45 | -------------------------------------------------------------------------------- /src/views/mj/aiGptsAdd.vue: -------------------------------------------------------------------------------- 1 | 43 | -------------------------------------------------------------------------------- /src/views/mj/aiListText.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /src/views/mj/aiMsg.vue: -------------------------------------------------------------------------------- 1 | 4 | 36 | 37 | 40 | -------------------------------------------------------------------------------- /src/views/mj/aiOther.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | -------------------------------------------------------------------------------- /src/views/mj/aiSetAuth.vue: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /src/views/mj/aiSiderInput.vue: -------------------------------------------------------------------------------- 1 | 33 | -------------------------------------------------------------------------------- /src/views/mj/aiTextSetting.vue: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /src/views/mj/dallText.vue: -------------------------------------------------------------------------------- 1 | 56 | -------------------------------------------------------------------------------- /src/views/mj/draw.vue: -------------------------------------------------------------------------------- 1 | 26 | -------------------------------------------------------------------------------- /src/views/mj/index.ts: -------------------------------------------------------------------------------- 1 | import aiSider from "./aiSider.vue" 2 | import aiGpts from "./aiGpts.vue" 3 | import aiGallery from "./aiGallery.vue" 4 | import aiFooter from "./aiFooter.vue" 5 | 6 | export {aiSider,aiGpts,aiGallery,aiFooter } -------------------------------------------------------------------------------- /src/views/mj/layout.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 58 | 63 | -------------------------------------------------------------------------------- /src/views/mj/mjTextAttr.vue: -------------------------------------------------------------------------------- 1 | 45 | 46 | -------------------------------------------------------------------------------- /src/views/mj/ttsText.vue: -------------------------------------------------------------------------------- 1 | 67 | -------------------------------------------------------------------------------- /src/views/suno/layout.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 59 | 64 | -------------------------------------------------------------------------------- /src/views/suno/mcUploadMp3.vue: -------------------------------------------------------------------------------- 1 | 61 | -------------------------------------------------------------------------------- /src/views/suno/mcplayer.vue: -------------------------------------------------------------------------------- 1 | 32 | -------------------------------------------------------------------------------- /src/views/suno/music.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | -------------------------------------------------------------------------------- /src/views/suno/player.vue: -------------------------------------------------------------------------------- 1 | 79 | -------------------------------------------------------------------------------- /src/views/suno/playui.vue: -------------------------------------------------------------------------------- 1 | 39 | 47 | -------------------------------------------------------------------------------- /src/views/viggle/dance.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/views/wav/an_main.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/views/wav/realtimeLayout.vue: -------------------------------------------------------------------------------- 1 | 15 | -------------------------------------------------------------------------------- /start.cmd: -------------------------------------------------------------------------------- 1 | cd ./service 2 | start pnpm start > service.log & 3 | echo "Start service complete!" 4 | 5 | 6 | cd .. 7 | echo "" > front.log 8 | start pnpm dev > front.log & 9 | echo "Start front complete!" 10 | -------------------------------------------------------------------------------- /start.sh: -------------------------------------------------------------------------------- 1 | 2 | cd ./service 3 | nohup pnpm start > service.log & 4 | echo "Start service complete!" 5 | 6 | 7 | cd .. 8 | echo "" > front.log 9 | nohup pnpm dev > front.log & 10 | echo "Start front complete!" 11 | tail -f front.log 12 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | darkMode: 'class', 4 | content: [ 5 | './index.html', 6 | './src/**/*.{vue,js,ts,jsx,tsx}', 7 | ], 8 | theme: { 9 | extend: { 10 | animation: { 11 | blink: 'blink 1.2s infinite steps(1, start)', 12 | }, 13 | keyframes: { 14 | blink: { 15 | '0%, 100%': { 'background-color': 'currentColor' }, 16 | '50%': { 'background-color': 'transparent' }, 17 | }, 18 | }, 19 | }, 20 | }, 21 | plugins: [], 22 | } 23 | -------------------------------------------------------------------------------- /tauri_debug.sh: -------------------------------------------------------------------------------- 1 | pnpm tauri dev -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "module": "ESNext", 5 | "target": "ESNext", 6 | "lib": ["DOM", "ESNext"], 7 | "strict": true, 8 | "esModuleInterop": true, 9 | "allowSyntheticDefaultImports": true, 10 | "jsx": "preserve", 11 | "moduleResolution": "node", 12 | "resolveJsonModule": true, 13 | "noUnusedLocals": true, 14 | "strictNullChecks": true, 15 | "forceConsistentCasingInFileNames": true, 16 | "skipLibCheck": true, 17 | "paths": { 18 | "@/*": ["./src/*"] 19 | }, 20 | "types": ["vite/client", "node", "naive-ui/volar"] 21 | }, 22 | "exclude": ["node_modules", "dist", "service"] 23 | } 24 | -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "rewrites": [ 3 | { 4 | "source": "/openapi/(.*)", 5 | "destination": "/api/proxy" 6 | }, 7 | { 8 | "source": "/mjapi/(.*)", 9 | "destination": "/api/proxy" 10 | } 11 | ] 12 | } --------------------------------------------------------------------------------