├── server ├── resource │ ├── jwt │ │ └── .gitkeep │ └── SF Slapstick Comic Bold Oblique.ttf ├── .runtime │ ├── logs │ │ └── .gitkeep │ └── cache │ │ └── tiktoken │ │ └── .gitkeep ├── config │ ├── ai.php │ └── openai.php ├── Module │ ├── Config │ │ ├── Contract │ │ │ └── IEnum.php │ │ ├── Annotation │ │ │ ├── PublicEnum.php │ │ │ ├── ConfigModel.php │ │ │ └── AdminPublicEnum.php │ │ ├── Command │ │ │ └── ConfigCommand.php │ │ └── Facade │ │ │ └── Config.php │ ├── Chat │ │ ├── Prompt │ │ │ ├── Contract │ │ │ │ └── IPromptCrawler.php │ │ │ ├── Enum │ │ │ │ └── PromptType.php │ │ │ ├── Annotation │ │ │ │ └── PromptCrawler.php │ │ │ ├── Command │ │ │ │ └── PromptCommand.php │ │ │ └── Cron │ │ │ │ ├── PromptCrawlerCron.php │ │ │ │ └── CleanTempRecordCron.php │ │ ├── Model │ │ │ ├── PromptCrawlerOrigin.php │ │ │ ├── Admin │ │ │ │ ├── ChatMessage.php │ │ │ │ ├── PromptCategory.php │ │ │ │ └── ChatSession.php │ │ │ └── ChatMessage.php │ │ ├── Enum │ │ │ ├── QAStatus.php │ │ │ └── SessionType.php │ │ ├── Service │ │ │ └── PromptCrawlerOriginService.php │ │ └── ApiController │ │ │ └── PromptCategoryController.php │ ├── Payment │ │ ├── Model │ │ │ └── PaymentChannel.php │ │ ├── Enum │ │ │ ├── PaymentBusinessType.php │ │ │ ├── OrderType.php │ │ │ └── SecondaryPaymentChannel.php │ │ ├── Annotation │ │ │ ├── PaymentChannel.php │ │ │ └── SubPaymentChannel.php │ │ └── ApiController │ │ │ └── PaymentController.php │ ├── VCode │ │ ├── Struct │ │ │ ├── VCodeTokenStore.php │ │ │ └── VCode.php │ │ ├── ApiController │ │ │ └── VCodeController.php │ │ └── Model │ │ │ └── Redis │ │ │ └── VCodeConfig.php │ ├── Member │ │ ├── Annotation │ │ │ └── LoginRequired.php │ │ ├── Model │ │ │ └── Admin │ │ │ │ └── Member.php │ │ ├── Enum │ │ │ └── MemberStatus.php │ │ ├── Struct │ │ │ ├── EmailForgotTokenStore.php │ │ │ └── EmailRegisterTokenStore.php │ │ └── Aop │ │ │ └── LoginRequiredInject.php │ ├── Card │ │ ├── Model │ │ │ ├── MemberCardRefundOrder.php │ │ │ ├── Admin │ │ │ │ ├── CardDetailAdmin.php │ │ │ │ ├── CardExAdmin.php │ │ │ │ ├── MemberCardOrderAdmin.php │ │ │ │ └── CardAdmin.php │ │ │ ├── CardType.php │ │ │ └── CardEx.php │ │ ├── Listener │ │ │ └── OnPayListener.php │ │ └── Enum │ │ │ └── OperationType.php │ ├── Admin │ │ ├── Annotation │ │ │ └── AdminLoginRequired.php │ │ ├── Enum │ │ │ ├── AdminMemberStatus.php │ │ │ └── OperationLogStatus.php │ │ ├── Util │ │ │ └── OperationLog.php │ │ ├── Aop │ │ │ └── AdminLoginRequiredInject.php │ │ └── Cron │ │ │ └── CleanOperationLogCron.php │ ├── Embedding │ │ ├── FileHandler │ │ │ ├── IFileHandler.php │ │ │ └── DocxFileHandler.php │ │ ├── Model │ │ │ ├── Admin │ │ │ │ ├── EmbeddingFileAdmin.php │ │ │ │ ├── EmbeddingFileInListAdmin.php │ │ │ │ ├── EmbeddingSectionInListAdmin.php │ │ │ │ ├── EmbeddingSectionAdmin.php │ │ │ │ ├── EmbeddingQaAdmin.php │ │ │ │ └── EmbeddingProjectAdmin.php │ │ │ ├── DTO │ │ │ │ ├── EmbeddingFileInList.php │ │ │ │ ├── EmbeddingSectionInList.php │ │ │ │ └── PublicEmbeddingProject.php │ │ │ ├── EmbeddingPublicProject.php │ │ │ └── EmbeddingSectionSearched.php │ │ ├── Enum │ │ │ ├── EmbeddingQAStatus.php │ │ │ ├── EmbeddingStatus.php │ │ │ ├── ContentFileTypes.php │ │ │ ├── PublicProjectStatus.php │ │ │ └── CompressFileTypes.php │ │ └── ApiController │ │ │ └── ConfigController.php │ ├── OpenAI │ │ ├── Client │ │ │ ├── Contract │ │ │ │ └── IClient.php │ │ │ ├── Annotation │ │ │ │ └── OpenAIClient.php │ │ │ ├── LikeOpenAI │ │ │ │ └── Client.php │ │ │ └── OpenAIClient.php │ │ ├── Util │ │ │ └── OpenAIUtil.php │ │ └── ApiController │ │ │ └── Admin │ │ │ └── OpenAIController.php │ └── Business │ │ └── Enum │ │ └── BusinessType.php ├── .gitignore ├── bin │ ├── generate-facade │ └── generate-model ├── Exception │ ├── BaseException.php │ ├── NoScoreException.php │ ├── AdminMemberNoLoginException.php │ ├── NotFoundException.php │ ├── MemberNoLoginException.php │ ├── MemberBandedException.php │ ├── MemberStatusAnomalyException.php │ └── ErrorException.php ├── init.php ├── Util │ ├── SecureFieldUtil.php │ ├── MaskUtil.php │ ├── IPUtil.php │ ├── RateLimit.php │ ├── RequestUtil.php │ ├── QueryHelper.php │ └── Generator.php ├── phpstan.neon ├── .env.tpl └── ApiServer │ └── HttpController │ └── HandShakeController.php ├── web ├── .npmrc ├── .eslintignore ├── .commitlintrc.json ├── .eslintrc.cjs ├── public │ ├── favicon.ico │ ├── pwa-192x192.png │ └── pwa-512x512.png ├── src │ ├── assets │ │ ├── logo.png │ │ ├── avatar.jpg │ │ ├── pay-alipay.png │ │ ├── pay-wechat.png │ │ └── recommend.json │ ├── styles │ │ ├── lib │ │ │ └── tailwind.css │ │ └── global.less │ ├── views │ │ ├── chat │ │ │ ├── layout │ │ │ │ ├── index.ts │ │ │ │ └── Layout.vue │ │ │ ├── components │ │ │ │ └── index.ts │ │ │ └── hooks │ │ │ │ ├── useUsingContext.ts │ │ │ │ └── useChat.ts │ │ ├── common │ │ │ └── layout │ │ │ │ └── index.ts │ │ ├── embedding │ │ │ ├── layout │ │ │ │ └── index.ts │ │ │ ├── components │ │ │ │ └── index.ts │ │ │ └── index.vue │ │ ├── layout │ │ │ └── components │ │ │ │ ├── index.ts │ │ │ │ └── MemberAvatar │ │ │ │ └── index.vue │ │ ├── auth │ │ │ └── components │ │ │ │ └── index.ts │ │ └── card │ │ │ └── components │ │ │ └── index.ts │ ├── components │ │ ├── custom │ │ │ ├── index.ts │ │ │ └── GithubSite.vue │ │ └── common │ │ │ ├── Time │ │ │ └── index.vue │ │ │ ├── HoverButton │ │ │ └── Button.vue │ │ │ ├── index.ts │ │ │ └── SvgIcon │ │ │ └── index.vue │ ├── api │ │ ├── vcode.ts │ │ ├── payment.ts │ │ ├── invitation.ts │ │ └── config.ts │ ├── plugins │ │ ├── index.ts │ │ └── assets.ts │ ├── store │ │ ├── modules │ │ │ ├── index.ts │ │ │ ├── auth │ │ │ │ └── helper.ts │ │ │ ├── embedding │ │ │ │ └── helper.ts │ │ │ ├── prompt │ │ │ │ └── helper.ts │ │ │ ├── settings │ │ │ │ ├── index.ts │ │ │ │ └── helper.ts │ │ │ ├── chat │ │ │ │ └── helper.ts │ │ │ └── app │ │ │ │ └── helper.ts │ │ └── index.ts │ ├── typings │ │ ├── naive-ui.d.ts │ │ ├── global.d.ts │ │ ├── env.d.ts │ │ └── card.d.ts │ ├── router │ │ └── permission.ts │ ├── hooks │ │ ├── useBasicLayout.ts │ │ └── useIconRender.ts │ ├── utils │ │ ├── functions │ │ │ └── debounce.ts │ │ └── copy.ts │ ├── App.vue │ └── main.ts ├── .vscode │ └── extensions.json ├── .dockerignore ├── postcss.config.js ├── .editorconfig ├── .gitattributes ├── .env.tpl ├── .gitignore ├── tailwind.config.js └── tsconfig.json ├── admin ├── src │ ├── service │ │ ├── index.ts │ │ ├── api │ │ │ ├── vcode.ts │ │ │ ├── openai.ts │ │ │ ├── index.ts │ │ │ ├── config.ts │ │ │ ├── auth.ts │ │ │ ├── payment.ts │ │ │ └── email.ts │ │ └── request │ │ │ └── index.ts │ ├── locales │ │ ├── index.ts │ │ └── locale.ts │ ├── utils │ │ ├── form │ │ │ └── index.ts │ │ ├── components │ │ │ ├── index.ts │ │ │ └── pagination.ts │ │ ├── storage │ │ │ ├── index.ts │ │ │ └── session.ts │ │ ├── service │ │ │ ├── index.ts │ │ │ └── msg.ts │ │ ├── common │ │ │ ├── index.ts │ │ │ ├── pattern.ts │ │ │ └── number.ts │ │ ├── index.ts │ │ ├── router │ │ │ ├── regexp.ts │ │ │ ├── index.ts │ │ │ ├── helpers.ts │ │ │ ├── module.ts │ │ │ └── cache.ts │ │ └── auth │ │ │ └── index.ts │ ├── router │ │ ├── helpers │ │ │ └── index.ts │ │ ├── modules │ │ │ ├── index.ts │ │ │ ├── member.ts │ │ │ ├── payment.ts │ │ │ ├── dashboard.ts │ │ │ ├── chat.ts │ │ │ └── prompt.ts │ │ └── guard │ │ │ └── index.ts │ ├── store │ │ ├── modules │ │ │ ├── common │ │ │ │ ├── index.ts │ │ │ │ └── enum.ts │ │ │ ├── prompt │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ ├── auth │ │ │ │ └── helpers.ts │ │ │ └── setup-store │ │ │ │ └── index.ts │ │ ├── subscribe │ │ │ ├── index.ts │ │ │ └── app.ts │ │ ├── index.ts │ │ └── plugins │ │ │ └── index.ts │ ├── hooks │ │ ├── index.ts │ │ ├── business │ │ │ └── index.ts │ │ └── common │ │ │ ├── index.ts │ │ │ ├── use-loading.ts │ │ │ ├── use-loading-empty.ts │ │ │ ├── use-context.ts │ │ │ ├── use-boolean.ts │ │ │ └── use-reload.ts │ ├── settings │ │ ├── index.ts │ │ └── color.ts │ ├── plugins │ │ ├── index.ts │ │ └── assets.ts │ ├── config │ │ ├── index.ts │ │ ├── map-sdk.ts │ │ └── regexp.ts │ ├── constants │ │ ├── index.ts │ │ ├── _shared.ts │ │ ├── business.ts │ │ └── common.ts │ ├── styles │ │ ├── scss │ │ │ ├── global.scss │ │ │ └── scrollbar.scss │ │ └── css │ │ │ └── global.css │ ├── assets │ │ ├── fonts │ │ │ ├── aguazyuan-bold.ttf │ │ │ ├── aguazyuan-light.ttf │ │ │ └── aguazyuan-regular.ttf │ │ └── svg-icon │ │ │ ├── activity.svg │ │ │ ├── copy.svg │ │ │ ├── chrome.svg │ │ │ ├── heart.svg │ │ │ ├── at-sign.svg │ │ │ ├── wind.svg │ │ │ ├── cast.svg │ │ │ ├── custom-icon.svg │ │ │ ├── logo.svg │ │ │ └── logo-fill.svg │ ├── layouts │ │ ├── common │ │ │ ├── global-search │ │ │ │ ├── components │ │ │ │ │ ├── index.ts │ │ │ │ │ └── search-footer.vue │ │ │ │ └── index.vue │ │ │ ├── global-tab │ │ │ │ └── components │ │ │ │ │ ├── tab-detail │ │ │ │ │ └── components │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── index.ts │ │ │ ├── global-sider │ │ │ │ ├── components │ │ │ │ │ ├── vertical-sider │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── index.vue │ │ │ │ │ ├── index.ts │ │ │ │ │ └── vertical-mix-sider │ │ │ │ │ │ └── components │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── mix-menu-collapse.vue │ │ │ │ └── index.vue │ │ │ ├── setting-drawer │ │ │ │ └── components │ │ │ │ │ ├── layout-mode │ │ │ │ │ └── components │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── theme-color-select │ │ │ │ │ └── components │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── color-checkbox.vue │ │ │ │ │ ├── setting-menu │ │ │ │ │ └── index.vue │ │ │ │ │ ├── index.ts │ │ │ │ │ └── drawer-button │ │ │ │ │ └── index.vue │ │ │ ├── global-footer │ │ │ │ └── index.vue │ │ │ ├── index.ts │ │ │ ├── global-header │ │ │ │ └── components │ │ │ │ │ ├── setting-button.vue │ │ │ │ │ ├── theme-mode.vue │ │ │ │ │ ├── menu-collapse.vue │ │ │ │ │ ├── github-site.vue │ │ │ │ │ ├── full-screen.vue │ │ │ │ │ └── index.ts │ │ │ └── global-logo │ │ │ │ └── index.vue │ │ ├── index.ts │ │ └── blank-layout │ │ │ └── index.vue │ ├── typings │ │ ├── vcode.d.ts │ │ ├── naive-ui.d.ts │ │ ├── email.d.ts │ │ ├── router.d.ts │ │ ├── openai.d.ts │ │ ├── package.d.ts │ │ ├── expose.d.ts │ │ ├── config.d.ts │ │ ├── admin-operation-log.d.ts │ │ ├── admin-member.d.ts │ │ ├── storage.d.ts │ │ ├── business.d.ts │ │ ├── member.d.ts │ │ ├── global.d.ts │ │ └── payment.d.ts │ ├── views │ │ ├── _builtin │ │ │ ├── 403 │ │ │ │ └── index.vue │ │ │ ├── 404 │ │ │ │ └── index.vue │ │ │ ├── 500 │ │ │ │ └── index.vue │ │ │ ├── login │ │ │ │ └── components │ │ │ │ │ ├── pwd-login │ │ │ │ │ └── components │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── other-login.vue │ │ │ │ │ ├── index.ts │ │ │ │ │ └── login-bg │ │ │ │ │ └── components │ │ │ │ │ └── index.ts │ │ │ └── not-found │ │ │ │ └── index.vue │ │ ├── dashboard │ │ │ └── analysis │ │ │ │ ├── components │ │ │ │ ├── data-card │ │ │ │ │ └── components │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── gradient-bg.vue │ │ │ │ └── index.ts │ │ │ │ └── index.vue │ │ ├── exception │ │ │ ├── 403 │ │ │ │ └── index.vue │ │ │ ├── 404 │ │ │ │ └── index.vue │ │ │ └── 500 │ │ │ │ └── index.vue │ │ └── about │ │ │ ├── components │ │ │ ├── index.ts │ │ │ ├── project-introduction.vue │ │ │ ├── pro-dependency.vue │ │ │ └── dev-dependency.vue │ │ │ └── index.vue │ ├── composables │ │ ├── index.ts │ │ └── system.ts │ ├── components │ │ ├── custom │ │ │ ├── github-link.vue │ │ │ ├── web-site-link.vue │ │ │ └── image-verify.vue │ │ └── common │ │ │ ├── system-logo.vue │ │ │ ├── dark-mode-container.vue │ │ │ └── exception-base.vue │ ├── directives │ │ ├── index.ts │ │ ├── network.ts │ │ ├── permission.ts │ │ └── login.ts │ ├── App.vue │ └── main.ts ├── .eslintignore ├── .env.development ├── .npmrc ├── build │ ├── config │ │ ├── index.ts │ │ ├── define.ts │ │ └── proxy.ts │ ├── index.ts │ ├── plugins │ │ ├── visualizer.ts │ │ ├── compress.ts │ │ └── pwa.ts │ └── utils │ │ └── index.ts ├── public │ ├── logo.png │ └── favicon.svg ├── postcss.config.js ├── .env.production ├── .github │ ├── PULL_REQUEST_TEMPLATE.md │ └── workflows │ │ ├── release.yml │ │ └── linter.yml ├── .editorconfig ├── .env-config.ts ├── .gitattributes ├── Makefile ├── index.html ├── scripts │ └── logo.ts ├── docker │ ├── Dockerfile │ └── .dockerignore ├── .vscode │ ├── launch.json │ └── extensions.json ├── tailwind.config.js ├── .env.tpl ├── .gitignore └── tsconfig.json ├── res ├── 1.jpg ├── 2.jpg ├── 3.jpg ├── 4.jpg ├── logo.png ├── pay.png └── wechat.png └── .github └── swoole.dockerfile /server/resource/jwt/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/.runtime/logs/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/.runtime/cache/tiktoken/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/.npmrc: -------------------------------------------------------------------------------- 1 | strict-peer-dependencies=false 2 | -------------------------------------------------------------------------------- /admin/src/service/index.ts: -------------------------------------------------------------------------------- 1 | export * from './api'; 2 | -------------------------------------------------------------------------------- /web/.eslintignore: -------------------------------------------------------------------------------- 1 | docker-compose 2 | kubernetes 3 | -------------------------------------------------------------------------------- /admin/src/locales/index.ts: -------------------------------------------------------------------------------- 1 | export * from './i18n'; 2 | -------------------------------------------------------------------------------- /admin/src/utils/form/index.ts: -------------------------------------------------------------------------------- 1 | export * from './rule'; 2 | -------------------------------------------------------------------------------- /admin/src/router/helpers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './scroll'; 2 | -------------------------------------------------------------------------------- /admin/.eslintignore: -------------------------------------------------------------------------------- 1 | !.env-config.ts 2 | router-page.d.ts 3 | 4 | -------------------------------------------------------------------------------- /admin/src/store/modules/common/index.ts: -------------------------------------------------------------------------------- 1 | export * from './enum'; 2 | -------------------------------------------------------------------------------- /res/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imiphp/imi-ai/HEAD/res/1.jpg -------------------------------------------------------------------------------- /res/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imiphp/imi-ai/HEAD/res/2.jpg -------------------------------------------------------------------------------- /res/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imiphp/imi-ai/HEAD/res/3.jpg -------------------------------------------------------------------------------- /res/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imiphp/imi-ai/HEAD/res/4.jpg -------------------------------------------------------------------------------- /admin/.env.development: -------------------------------------------------------------------------------- 1 | VITE_HTTP_PROXY=N 2 | VITE_SOYBEAN_ROUTE_PLUGIN=Y -------------------------------------------------------------------------------- /admin/src/utils/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './pagination'; 2 | -------------------------------------------------------------------------------- /res/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imiphp/imi-ai/HEAD/res/logo.png -------------------------------------------------------------------------------- /res/pay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imiphp/imi-ai/HEAD/res/pay.png -------------------------------------------------------------------------------- /res/wechat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imiphp/imi-ai/HEAD/res/wechat.png -------------------------------------------------------------------------------- /admin/.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmmirror.com/ 2 | shamefully-hoist=true 3 | -------------------------------------------------------------------------------- /admin/build/config/index.ts: -------------------------------------------------------------------------------- 1 | export * from './define'; 2 | export * from './proxy'; 3 | -------------------------------------------------------------------------------- /admin/src/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './common'; 2 | export * from './business'; 3 | -------------------------------------------------------------------------------- /admin/src/settings/index.ts: -------------------------------------------------------------------------------- 1 | export * from './theme'; 2 | export * from './color'; 3 | -------------------------------------------------------------------------------- /web/.commitlintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@commitlint/config-conventional"] 3 | } 4 | -------------------------------------------------------------------------------- /admin/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imiphp/imi-ai/HEAD/admin/public/logo.png -------------------------------------------------------------------------------- /admin/src/utils/storage/index.ts: -------------------------------------------------------------------------------- 1 | export * from './local'; 2 | export * from './session'; 3 | -------------------------------------------------------------------------------- /web/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['@antfu'], 4 | } 5 | -------------------------------------------------------------------------------- /web/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imiphp/imi-ai/HEAD/web/public/favicon.ico -------------------------------------------------------------------------------- /web/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imiphp/imi-ai/HEAD/web/src/assets/logo.png -------------------------------------------------------------------------------- /admin/src/plugins/index.ts: -------------------------------------------------------------------------------- 1 | import setupAssets from './assets'; 2 | 3 | export { setupAssets }; 4 | -------------------------------------------------------------------------------- /web/public/pwa-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imiphp/imi-ai/HEAD/web/public/pwa-192x192.png -------------------------------------------------------------------------------- /web/public/pwa-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imiphp/imi-ai/HEAD/web/public/pwa-512x512.png -------------------------------------------------------------------------------- /web/src/assets/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imiphp/imi-ai/HEAD/web/src/assets/avatar.jpg -------------------------------------------------------------------------------- /web/src/styles/lib/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /web/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["Vue.volar", "dbaeumer.vscode-eslint"] 3 | } 4 | -------------------------------------------------------------------------------- /web/src/assets/pay-alipay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imiphp/imi-ai/HEAD/web/src/assets/pay-alipay.png -------------------------------------------------------------------------------- /web/src/assets/pay-wechat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imiphp/imi-ai/HEAD/web/src/assets/pay-wechat.png -------------------------------------------------------------------------------- /web/src/views/chat/layout/index.ts: -------------------------------------------------------------------------------- 1 | import ChatLayout from './Layout.vue' 2 | 3 | export { ChatLayout } 4 | -------------------------------------------------------------------------------- /admin/build/index.ts: -------------------------------------------------------------------------------- 1 | export * from './plugins'; 2 | export * from './config'; 3 | export * from './utils'; 4 | -------------------------------------------------------------------------------- /web/src/components/custom/index.ts: -------------------------------------------------------------------------------- 1 | import GithubSite from './GithubSite.vue' 2 | 3 | export { GithubSite } 4 | -------------------------------------------------------------------------------- /web/src/views/chat/components/index.ts: -------------------------------------------------------------------------------- 1 | import Message from './Message/index.vue' 2 | 3 | export { Message } 4 | -------------------------------------------------------------------------------- /web/src/views/common/layout/index.ts: -------------------------------------------------------------------------------- 1 | import CommonLayout from './Layout.vue' 2 | 3 | export { CommonLayout } 4 | -------------------------------------------------------------------------------- /admin/src/config/index.ts: -------------------------------------------------------------------------------- 1 | export * from './service'; 2 | export * from './regexp'; 3 | export * from './map-sdk'; 4 | -------------------------------------------------------------------------------- /web/.dockerignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | */node_modules 3 | node_modules 4 | Dockerfile 5 | .* 6 | */.* 7 | !.env 8 | -------------------------------------------------------------------------------- /admin/src/constants/index.ts: -------------------------------------------------------------------------------- 1 | export * from './common'; 2 | export * from './system'; 3 | export * from './business'; 4 | -------------------------------------------------------------------------------- /web/src/views/embedding/layout/index.ts: -------------------------------------------------------------------------------- 1 | import EmbeddingLayout from './Layout.vue' 2 | 3 | export { EmbeddingLayout } 4 | -------------------------------------------------------------------------------- /admin/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {} 5 | } 6 | }; 7 | -------------------------------------------------------------------------------- /admin/src/styles/scss/global.scss: -------------------------------------------------------------------------------- 1 | @import "./scrollbar.scss"; 2 | 3 | .spin > .n-spin-content { 4 | height: 100%; 5 | } 6 | -------------------------------------------------------------------------------- /admin/src/utils/service/index.ts: -------------------------------------------------------------------------------- 1 | export * from './transform'; 2 | export * from './error'; 3 | export * from './handler'; 4 | -------------------------------------------------------------------------------- /web/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /admin/src/assets/fonts/aguazyuan-bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imiphp/imi-ai/HEAD/admin/src/assets/fonts/aguazyuan-bold.ttf -------------------------------------------------------------------------------- /admin/src/assets/fonts/aguazyuan-light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imiphp/imi-ai/HEAD/admin/src/assets/fonts/aguazyuan-light.ttf -------------------------------------------------------------------------------- /admin/src/assets/fonts/aguazyuan-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imiphp/imi-ai/HEAD/admin/src/assets/fonts/aguazyuan-regular.ttf -------------------------------------------------------------------------------- /admin/src/layouts/common/global-search/components/index.ts: -------------------------------------------------------------------------------- 1 | import SearchModal from './search-modal.vue'; 2 | 3 | export { SearchModal }; 4 | -------------------------------------------------------------------------------- /admin/src/typings/vcode.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace VCode { 2 | interface VCodeResponse { 3 | image: string; 4 | token: string; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /admin/src/views/_builtin/login/components/pwd-login/components/index.ts: -------------------------------------------------------------------------------- 1 | import OtherLogin from './other-login.vue'; 2 | 3 | export { OtherLogin }; 4 | -------------------------------------------------------------------------------- /server/resource/SF Slapstick Comic Bold Oblique.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imiphp/imi-ai/HEAD/server/resource/SF Slapstick Comic Bold Oblique.ttf -------------------------------------------------------------------------------- /admin/src/views/dashboard/analysis/components/data-card/components/index.ts: -------------------------------------------------------------------------------- 1 | import GradientBg from './gradient-bg.vue'; 2 | 3 | export { GradientBg }; 4 | -------------------------------------------------------------------------------- /web/src/api/vcode.ts: -------------------------------------------------------------------------------- 1 | import { get } from '@/utils/request' 2 | 3 | export function vcode() { 4 | return get({ 5 | url: '/vcode/get', 6 | }) 7 | } 8 | -------------------------------------------------------------------------------- /admin/src/layouts/common/global-tab/components/tab-detail/components/index.ts: -------------------------------------------------------------------------------- 1 | import ContextMenu from './context-menu.vue'; 2 | 3 | export { ContextMenu }; 4 | -------------------------------------------------------------------------------- /admin/src/typings/naive-ui.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace NaiveUI { 2 | type ThemeColor = 'default' | 'error' | 'primary' | 'info' | 'success' | 'warning'; 3 | } 4 | -------------------------------------------------------------------------------- /admin/.env.production: -------------------------------------------------------------------------------- 1 | VITE_VISUALIZER=N 2 | 3 | VITE_COMPRESS=N 4 | 5 | # gzip | brotliCompress | deflate | deflateRaw 6 | VITE_COMPRESS_TYPE=gzip 7 | 8 | VITE_PWA=N 9 | -------------------------------------------------------------------------------- /admin/src/layouts/common/global-sider/components/vertical-sider/components/index.ts: -------------------------------------------------------------------------------- 1 | import VerticalMenu from './vertical-menu.vue'; 2 | 3 | export { VerticalMenu }; 4 | -------------------------------------------------------------------------------- /web/src/plugins/index.ts: -------------------------------------------------------------------------------- 1 | import setupAssets from './assets' 2 | import setupScrollbarStyle from './scrollbarStyle' 3 | 4 | export { setupAssets, setupScrollbarStyle } 5 | -------------------------------------------------------------------------------- /admin/src/typings/email.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace Email { 2 | type EmailBlackListResponse = { 3 | list: string[]; 4 | total: number; 5 | } & Api.BaseResponse; 6 | } 7 | -------------------------------------------------------------------------------- /admin/src/typings/router.d.ts: -------------------------------------------------------------------------------- 1 | import 'vue-router'; 2 | 3 | declare module 'vue-router' { 4 | interface RouteMeta extends AuthRoute.RouteMeta {} 5 | } 6 | -------------------------------------------------------------------------------- /admin/.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Pull Request 详情 2 | 3 | 请根据实际使用情况修改以下信息。 4 | 5 | ## 版本信息 6 | 7 | ## 解决了哪些问题 8 | 9 | ## 是否关闭了某个 Issue 10 | 11 | Closes # 12 | -------------------------------------------------------------------------------- /admin/src/utils/common/index.ts: -------------------------------------------------------------------------------- 1 | export * from './typeof'; 2 | export * from './color'; 3 | export * from './number'; 4 | export * from './pattern'; 5 | export * from './time'; 6 | -------------------------------------------------------------------------------- /admin/src/views/_builtin/403/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /admin/src/views/_builtin/404/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /admin/src/views/_builtin/500/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /admin/src/views/exception/403/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /admin/src/views/exception/404/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /admin/src/views/exception/500/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /server/config/ai.php: -------------------------------------------------------------------------------- 1 | env('AI_ID_SALT', 'imi-ai'), 9 | ]; 10 | -------------------------------------------------------------------------------- /admin/src/hooks/business/index.ts: -------------------------------------------------------------------------------- 1 | import useCountDown from './use-count-down'; 2 | import useImageVerify from './use-image-verify'; 3 | 4 | export { useCountDown, useImageVerify }; 5 | -------------------------------------------------------------------------------- /admin/src/views/_builtin/login/components/index.ts: -------------------------------------------------------------------------------- 1 | import LoginBg from './login-bg/index.vue'; 2 | import PwdLogin from './pwd-login/index.vue'; 3 | 4 | export { LoginBg, PwdLogin }; 5 | -------------------------------------------------------------------------------- /admin/src/views/_builtin/not-found/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /web/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 | -------------------------------------------------------------------------------- /admin/build/plugins/visualizer.ts: -------------------------------------------------------------------------------- 1 | import { visualizer } from 'rollup-plugin-visualizer'; 2 | 3 | export default visualizer({ 4 | gzipSize: true, 5 | brotliSize: true, 6 | open: true 7 | }); 8 | -------------------------------------------------------------------------------- /web/src/typings/naive-ui.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'naive-ui/es/tabs/src/TabPane' { 2 | export interface TabPaneSlots { 3 | tab?: () => VNode[] 4 | default?: () => VNode[] 5 | } 6 | } -------------------------------------------------------------------------------- /admin/src/layouts/index.ts: -------------------------------------------------------------------------------- 1 | const BasicLayout = () => import('./basic-layout/index.vue'); 2 | const BlankLayout = () => import('./blank-layout/index.vue'); 3 | 4 | export { BasicLayout, BlankLayout }; 5 | -------------------------------------------------------------------------------- /admin/src/service/api/vcode.ts: -------------------------------------------------------------------------------- 1 | import { request } from '../request'; 2 | 3 | /** 4 | * 获取验证码 5 | */ 6 | export function fetchVcode() { 7 | return request.get('/vcode/get'); 8 | } 9 | -------------------------------------------------------------------------------- /admin/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './common'; 2 | export * from './storage'; 3 | export * from './service'; 4 | export * from './router'; 5 | export * from './form'; 6 | export * from './components'; 7 | -------------------------------------------------------------------------------- /admin/src/layouts/common/global-tab/components/index.ts: -------------------------------------------------------------------------------- 1 | import TabDetail from './tab-detail/index.vue'; 2 | import ReloadButton from './reload-button/index.vue'; 3 | 4 | export { TabDetail, ReloadButton }; 5 | -------------------------------------------------------------------------------- /admin/src/views/_builtin/login/components/login-bg/components/index.ts: -------------------------------------------------------------------------------- 1 | import CornerTop from './corner-top.vue'; 2 | import CornerBottom from './corner-bottom.vue'; 3 | 4 | export { CornerTop, CornerBottom }; 5 | -------------------------------------------------------------------------------- /web/src/router/permission.ts: -------------------------------------------------------------------------------- 1 | import type { Router } from 'vue-router' 2 | 3 | export function setupPageGuard(router: Router) { 4 | router.beforeEach(async (to, from, next) => { 5 | next() 6 | }) 7 | } 8 | -------------------------------------------------------------------------------- /admin/src/service/api/openai.ts: -------------------------------------------------------------------------------- 1 | import { request } from '../request'; 2 | 3 | export const fetchOpenAIClientList = async () => { 4 | return request.get('/admin/openai/clientList'); 5 | }; 6 | -------------------------------------------------------------------------------- /web/src/api/payment.ts: -------------------------------------------------------------------------------- 1 | import { get } from '@/utils/request' 2 | 3 | export async function result(tradeNo: string) { 4 | return await get({ 5 | url: '/payment/result', 6 | data: { tradeNo }, 7 | }) 8 | } 9 | -------------------------------------------------------------------------------- /admin/src/store/modules/prompt/index.ts: -------------------------------------------------------------------------------- 1 | export const promptCategorySelectOptions = (models: Prompt.PromptCategory[]) => { 2 | return models.map(model => ({ 3 | label: model.title, 4 | value: model.id 5 | })); 6 | }; 7 | -------------------------------------------------------------------------------- /admin/build/config/define.ts: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs'; 2 | 3 | /** 项目构建时间 */ 4 | const PROJECT_BUILD_TIME = JSON.stringify(dayjs().format('YYYY-MM-DD HH:mm:ss')); 5 | 6 | export const viteDefine = { 7 | PROJECT_BUILD_TIME 8 | }; 9 | -------------------------------------------------------------------------------- /admin/src/layouts/common/global-sider/components/index.ts: -------------------------------------------------------------------------------- 1 | import VerticalSider from './vertical-sider/index.vue'; 2 | import VerticalMixSider from './vertical-mix-sider/index.vue'; 3 | 4 | export { VerticalSider, VerticalMixSider }; 5 | -------------------------------------------------------------------------------- /admin/src/layouts/common/setting-drawer/components/layout-mode/components/index.ts: -------------------------------------------------------------------------------- 1 | import LayoutCheckbox from './layout-checkbox.vue'; 2 | import LayoutCard from './layout-card.vue'; 3 | 4 | export { LayoutCheckbox, LayoutCard }; 5 | -------------------------------------------------------------------------------- /admin/src/layouts/common/setting-drawer/components/theme-color-select/components/index.ts: -------------------------------------------------------------------------------- 1 | import ColorCheckbox from './color-checkbox.vue'; 2 | import ColorModal from './color-modal.vue'; 3 | 4 | export { ColorCheckbox, ColorModal }; 5 | -------------------------------------------------------------------------------- /admin/src/composables/index.ts: -------------------------------------------------------------------------------- 1 | export * from './system'; 2 | export * from './router'; 3 | export * from './layout'; 4 | export * from './events'; 5 | export * from './echarts'; 6 | export * from './icon'; 7 | export * from './websocket'; 8 | -------------------------------------------------------------------------------- /admin/src/constants/_shared.ts: -------------------------------------------------------------------------------- 1 | export function transformObjectToOption(obj: T) { 2 | return Object.entries(obj).map(([value, label]) => ({ 3 | value, 4 | label 5 | })) as Common.OptionWithKey[]; 6 | } 7 | -------------------------------------------------------------------------------- /admin/src/router/modules/index.ts: -------------------------------------------------------------------------------- 1 | import { handleModuleRoutes } from '@/utils'; 2 | 3 | const modules = import.meta.glob('./**/*.ts', { eager: true }) as AuthRoute.RouteModule; 4 | 5 | export const routes = handleModuleRoutes(modules); 6 | -------------------------------------------------------------------------------- /server/Module/Config/Contract/IEnum.php: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin/src/store/subscribe/index.ts: -------------------------------------------------------------------------------- 1 | import subscribeAppStore from './app'; 2 | import subscribeThemeStore from './theme'; 3 | 4 | /** 订阅状态 */ 5 | export function subscribeStore() { 6 | subscribeAppStore(); 7 | subscribeThemeStore(); 8 | } 9 | -------------------------------------------------------------------------------- /web/src/views/layout/components/index.ts: -------------------------------------------------------------------------------- 1 | import Header from './Header/index.vue' 2 | import MemberAvatar from './MemberAvatar/index.vue' 3 | import Invitation from './Invitation/index.vue' 4 | 5 | export { Header, MemberAvatar, Invitation } 6 | -------------------------------------------------------------------------------- /web/src/views/auth/components/index.ts: -------------------------------------------------------------------------------- 1 | import EmailRegister from './register/emailRegister.vue' 2 | import Login from './login/login.vue' 3 | import EmailForgot from './forgot/emailForgot.vue' 4 | 5 | export { EmailRegister, Login, EmailForgot } 6 | -------------------------------------------------------------------------------- /admin/src/utils/router/regexp.ts: -------------------------------------------------------------------------------- 1 | /** 获取登录页面模块的动态路由的正则 */ 2 | export function getLoginModuleRegExp() { 3 | const modules: UnionKey.LoginModule[] = ['pwd-login', 'code-login', 'register', 'reset-pwd', 'bind-wechat']; 4 | return modules.join('|'); 5 | } 6 | -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | *.lock 2 | /.idea 3 | composer.lock 4 | /ide-helper 5 | .runtime 6 | *.log 7 | *.pid 8 | *.cache 9 | /.vscode 10 | /release 11 | /bin/swoole-cli 12 | /build 13 | /test.php.test 14 | /vendor 15 | /.env 16 | resource/jwt/*.pem 17 | -------------------------------------------------------------------------------- /admin/src/views/dashboard/analysis/components/index.ts: -------------------------------------------------------------------------------- 1 | import TopChart from './top-chart/index.vue'; 2 | import DataCard from './data-card/index.vue'; 3 | import BottomPart from './bottom-part/index.vue'; 4 | 5 | export { TopChart, DataCard, BottomPart }; 6 | -------------------------------------------------------------------------------- /web/src/store/index.ts: -------------------------------------------------------------------------------- 1 | import type { App } from 'vue' 2 | import { createPinia } from 'pinia' 3 | 4 | export const store = createPinia() 5 | 6 | export function setupStore(app: App) { 7 | app.use(store) 8 | } 9 | 10 | export * from './modules' 11 | -------------------------------------------------------------------------------- /admin/.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 | -------------------------------------------------------------------------------- /admin/build/plugins/compress.ts: -------------------------------------------------------------------------------- 1 | import ViteCompression from 'vite-plugin-compression'; 2 | 3 | export default (viteEnv: ImportMetaEnv) => { 4 | const { VITE_COMPRESS_TYPE = 'gzip' } = viteEnv; 5 | return ViteCompression({ algorithm: VITE_COMPRESS_TYPE }); 6 | }; 7 | -------------------------------------------------------------------------------- /web/.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 | -------------------------------------------------------------------------------- /web/src/components/custom/GithubSite.vue: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /admin/src/utils/router/index.ts: -------------------------------------------------------------------------------- 1 | export * from './module'; 2 | export * from './helpers'; 3 | export * from './cache'; 4 | export * from './auth'; 5 | export * from './menu'; 6 | export * from './breadcrumb'; 7 | export * from './regexp'; 8 | export * from './transform'; 9 | -------------------------------------------------------------------------------- /admin/src/typings/openai.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace OpenAI { 2 | interface Client { 3 | title: string; 4 | class: string; 5 | } 6 | 7 | type ClientListResponse = { 8 | list: Client[]; 9 | } & Api.BaseResponse & 10 | Api.PaginationResponse; 11 | } 12 | -------------------------------------------------------------------------------- /server/bin/generate-facade: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 生成门面类 3 | 4 | __DIR__=$(cd `dirname $0`; pwd)/../ 5 | 6 | $__DIR__/vendor/bin/imi-swoole generate/facade "app\Module\Config\Facade\Config" "\app\Module\Config\Service\ConfigService" && \ 7 | 8 | $__DIR__/vendor/bin/php-cs-fixer fix 9 | -------------------------------------------------------------------------------- /admin/src/typings/package.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | declare namespace BMap { 5 | class Map extends BMapGL.Map {} 6 | class Point extends BMapGL.Point {} 7 | } 8 | 9 | declare const TMap: any; 10 | -------------------------------------------------------------------------------- /web/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 | -------------------------------------------------------------------------------- /admin/src/layouts/blank-layout/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /admin/src/locales/locale.ts: -------------------------------------------------------------------------------- 1 | import zhCN from './lang/zh-CN'; 2 | import en from './lang/en'; 3 | import kmKH from './lang/km-KH'; 4 | 5 | const locales: Record = { 6 | 'zh-CN': zhCN, 7 | en, 8 | 'km-KH': kmKH 9 | }; 10 | 11 | export default locales; 12 | -------------------------------------------------------------------------------- /admin/src/store/modules/index.ts: -------------------------------------------------------------------------------- 1 | export * from './app'; 2 | export * from './theme'; 3 | export * from './auth'; 4 | export * from './tab'; 5 | export * from './route'; 6 | export * from './setup-store'; 7 | export * from './common'; 8 | export * from './config'; 9 | export * from './prompt'; 10 | -------------------------------------------------------------------------------- /admin/src/typings/expose.d.ts: -------------------------------------------------------------------------------- 1 | /** vue 的defineExpose导出的类型 */ 2 | declare namespace Expose { 3 | interface BetterScroll { 4 | instance: import('@better-scroll/core').BScrollInstance; 5 | } 6 | 7 | interface ImageVerify { 8 | /** 获取图片验证码 */ 9 | getImgCode(): void; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /admin/src/assets/svg-icon/copy.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin/src/layouts/common/global-sider/components/vertical-mix-sider/components/index.ts: -------------------------------------------------------------------------------- 1 | import MixMenuDetail from './mix-menu-detail.vue'; 2 | import MixMenuDrawer from './mix-menu-drawer.vue'; 3 | import MixMenuCollapse from './mix-menu-collapse.vue'; 4 | 5 | export { MixMenuDetail, MixMenuDrawer, MixMenuCollapse }; 6 | -------------------------------------------------------------------------------- /server/Exception/BaseException.php: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin/src/utils/common/pattern.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 策略模式 3 | * @param actions 每一种可能执行的操作 4 | */ 5 | export function exeStrategyActions(actions: Common.StrategyAction[]) { 6 | actions.some(item => { 7 | const [flag, action] = item; 8 | if (flag) { 9 | action(); 10 | } 11 | return flag; 12 | }); 13 | } 14 | -------------------------------------------------------------------------------- /server/Module/Chat/Prompt/Contract/IPromptCrawler.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | public function crawl(): \Iterator; 13 | } 14 | -------------------------------------------------------------------------------- /server/init.php: -------------------------------------------------------------------------------- 1 | 2 | interface Props { 3 | time: number 4 | } 5 | 6 | const props = withDefaults(defineProps(), { 7 | time: 0, 8 | }) 9 | 10 | 11 | 14 | -------------------------------------------------------------------------------- /web/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 | $router: import('vue-router').Router; 7 | } 8 | -------------------------------------------------------------------------------- /admin/src/assets/svg-icon/heart.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin/src/hooks/common/index.ts: -------------------------------------------------------------------------------- 1 | import useContext from './use-context'; 2 | import useBoolean from './use-boolean'; 3 | import useLoading from './use-loading'; 4 | import useLoadingEmpty from './use-loading-empty'; 5 | import useReload from './use-reload'; 6 | 7 | export { useContext, useBoolean, useLoading, useLoadingEmpty, useReload }; 8 | -------------------------------------------------------------------------------- /server/config/openai.php: -------------------------------------------------------------------------------- 1 | env('OPENAI_HTTP', [ 10 | 'timeout' => 60, 11 | 'verify' => false, // 验证证书,设为 false 解决 swoole-cli 和部分环境验证失败。对安全敏感用户可以设为 true 12 | ]), 13 | ]; 14 | -------------------------------------------------------------------------------- /admin/src/hooks/common/use-loading.ts: -------------------------------------------------------------------------------- 1 | import useBoolean from './use-boolean'; 2 | 3 | export default function useLoading(initValue = false) { 4 | const { bool: loading, setTrue: startLoading, setFalse: endLoading } = useBoolean(initValue); 5 | 6 | return { 7 | loading, 8 | startLoading, 9 | endLoading 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /admin/src/views/about/components/index.ts: -------------------------------------------------------------------------------- 1 | import ProjectIntroduction from './project-introduction.vue'; 2 | import ProjectInfo from './project-info.vue'; 3 | import ProDependency from './pro-dependency.vue'; 4 | import DevDependency from './dev-dependency.vue'; 5 | 6 | export { ProjectIntroduction, ProjectInfo, ProDependency, DevDependency }; 7 | -------------------------------------------------------------------------------- /admin/src/assets/svg-icon/at-sign.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /web/src/views/card/components/index.ts: -------------------------------------------------------------------------------- 1 | import CardList from './list.vue' 2 | import CardActivation from './activation.vue' 3 | import MemberCardDetails from './memberCardDetails.vue' 4 | import CardDetails from './cardDetails.vue' 5 | import BuyCard from './buyCard.vue' 6 | 7 | export { CardList, CardActivation, MemberCardDetails, CardDetails, BuyCard } 8 | -------------------------------------------------------------------------------- /web/src/views/embedding/components/index.ts: -------------------------------------------------------------------------------- 1 | import ProjectList from './projectList.vue' 2 | import Upload from './upload.vue' 3 | import Setting from './Setting/index.vue' 4 | import PublicProjectList from './publicProjectList.vue' 5 | import General from './Setting/General.vue' 6 | 7 | export { PublicProjectList, ProjectList, Upload, Setting, General } 8 | -------------------------------------------------------------------------------- /admin/src/assets/svg-icon/wind.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin/src/views/dashboard/analysis/index.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /server/Util/SecureFieldUtil.php: -------------------------------------------------------------------------------- 1 | vcode; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /admin/src/assets/svg-icon/cast.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin/src/service/request/index.ts: -------------------------------------------------------------------------------- 1 | import { getServiceEnvConfig } from '~/.env-config'; 2 | import { createRequest } from './request'; 3 | 4 | const { url, proxyPattern } = getServiceEnvConfig(import.meta.env); 5 | 6 | const isHttpProxy = import.meta.env.VITE_HTTP_PROXY === 'Y'; 7 | 8 | export const request = createRequest({ baseURL: isHttpProxy ? proxyPattern : url }); 9 | -------------------------------------------------------------------------------- /server/Util/MaskUtil.php: -------------------------------------------------------------------------------- 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 | readonly VITE_BUY_CARD_TEXT: string; 9 | readonly VITE_APP_TITLE: string; 10 | readonly VITE_APP_SUB_TITLE: string; 11 | } 12 | -------------------------------------------------------------------------------- /admin/src/components/custom/github-link.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 17 | 18 | -------------------------------------------------------------------------------- /admin/src/constants/business.ts: -------------------------------------------------------------------------------- 1 | import { $t } from '@/locales'; 2 | 3 | export const loginModuleLabels: Record = { 4 | 'pwd-login': $t('page.login.pwdLogin.title'), 5 | 'code-login': $t('page.login.codeLogin.title'), 6 | register: $t('page.login.register.title'), 7 | 'reset-pwd': $t('page.login.resetPwd.title'), 8 | 'bind-wechat': $t('page.login.bindWeChat.title') 9 | }; 10 | -------------------------------------------------------------------------------- /admin/src/views/about/index.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /server/Module/Card/Model/Admin/CardExAdmin.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /admin/src/plugins/assets.ts: -------------------------------------------------------------------------------- 1 | import 'uno.css'; 2 | import '@soybeanjs/vue-materials/dist/style.css'; 3 | import 'swiper/css'; 4 | import 'swiper/css/navigation'; 5 | import 'swiper/css/pagination'; 6 | import 'virtual:svg-icons-register'; 7 | import '../styles/css/global.css'; 8 | 9 | /** import static assets: css, js , font and so on. - [引入静态资源,css、js和字体文件等] */ 10 | export default function setupAssets() { 11 | // 12 | } 13 | -------------------------------------------------------------------------------- /admin/src/typings/config.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace Config { 2 | interface Model { 3 | title: string; 4 | model: string; 5 | enable: boolean; 6 | paying: boolean; 7 | inputTokenMultiple: string | number; 8 | outputTokenMultiple: string | number; 9 | maxTokens: number; 10 | tips: string; 11 | additionalTokensPerMessage: number; 12 | additionalTokensAfterMessages: number; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /admin/src/store/index.ts: -------------------------------------------------------------------------------- 1 | import type { App } from 'vue'; 2 | import { createPinia } from 'pinia'; 3 | import { resetSetupStore } from './plugins'; 4 | 5 | /** setup vue store plugin: pinia. - [安装vue状态管理插件:pinia] */ 6 | export function setupStore(app: App) { 7 | const store = createPinia(); 8 | store.use(resetSetupStore); 9 | 10 | app.use(store); 11 | } 12 | 13 | export * from './modules'; 14 | export * from './subscribe'; 15 | -------------------------------------------------------------------------------- /server/Module/Embedding/FileHandler/IFileHandler.php: -------------------------------------------------------------------------------- 1 | 2 |
3 | {{ label }} 4 | 5 |
6 | 7 | 8 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /admin/Makefile: -------------------------------------------------------------------------------- 1 | ImageTag ?=v0.9.6 2 | SoybeanAdminImg ?= soybeanjs/soybean-admin:$(ImageTag) 3 | 4 | VERSION=$(shell git rev-parse --short HEAD) 5 | 6 | soybean-admin: soybean-admin-build soybean-admin-push 7 | 8 | soybean-admin-build: 9 | docker build --build-arg version=$(VERSION) -t ${SoybeanAdminImg} -f docker/Dockerfile . 10 | 11 | soybean-admin-push: 12 | docker push ${SoybeanAdminImg} 13 | 14 | # run tauri app: 15 | run: 16 | pnpm tauri dev 17 | -------------------------------------------------------------------------------- /admin/src/layouts/common/global-footer/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /server/Module/Chat/Model/Admin/ChatMessage.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | %VITE_APP_NAME% 9 | 10 | 11 |
12 |
13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /admin/src/hooks/common/use-loading-empty.ts: -------------------------------------------------------------------------------- 1 | import useBoolean from './use-boolean'; 2 | 3 | export default function useLoadingEmpty(initLoading = false, initEmpty = false) { 4 | const { bool: loading, setTrue: startLoading, setFalse: endLoading } = useBoolean(initLoading); 5 | const { bool: empty, setBool: setEmpty } = useBoolean(initEmpty); 6 | 7 | return { 8 | loading, 9 | startLoading, 10 | endLoading, 11 | empty, 12 | setEmpty 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /.github/swoole.dockerfile: -------------------------------------------------------------------------------- 1 | ARG SWOOLE_DOCKER_VERSION 2 | 3 | FROM phpswoole/swoole:${SWOOLE_DOCKER_VERSION} 4 | 5 | RUN set -eux \ 6 | && apt-get update && apt-get -y install libzip-dev zlib1g-dev libjpeg-dev libpng-dev libwebp-dev libjpeg62-turbo-dev libpng-dev libxpm-dev libfreetype6-dev \ 7 | && docker-php-ext-configure gd \ 8 | --with-webp \ 9 | --with-jpeg \ 10 | --with-xpm \ 11 | --with-freetype \ 12 | && docker-php-ext-install -j$(nproc) bcmath zip gd 13 | -------------------------------------------------------------------------------- /server/Module/Member/Enum/MemberStatus.php: -------------------------------------------------------------------------------- 1 | 2 |

3 | {{ label }} 4 | 5 | {{ link }} 6 | 7 |

8 | 9 | 10 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /admin/src/typings/admin-operation-log.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace AdminOperationLog { 2 | interface Log { 3 | id: number; 4 | memberId: number; 5 | object: string; 6 | objectText: string; 7 | status: number; 8 | statusText: string; 9 | message: string; 10 | ip: string; 11 | time: number; 12 | memberInfo: Member.MemberInfo; 13 | } 14 | 15 | type LogListResponse = { 16 | list: Log[]; 17 | } & Api.BaseResponse & 18 | Api.PaginationResponse; 19 | } 20 | -------------------------------------------------------------------------------- /server/Module/Chat/Enum/QAStatus.php: -------------------------------------------------------------------------------- 1 | 2 | interface Emit { 3 | (e: 'click'): void 4 | } 5 | 6 | const emit = defineEmits() 7 | 8 | function handleClick() { 9 | emit('click') 10 | } 11 | 12 | 13 | 21 | -------------------------------------------------------------------------------- /server/Module/Admin/Enum/AdminMemberStatus.php: -------------------------------------------------------------------------------- 1 | = (...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 | -------------------------------------------------------------------------------- /admin/docker/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | .npmrc 5 | .cache 6 | 7 | tests/server/static 8 | tests/server/static/upload 9 | 10 | .local 11 | # local env files 12 | .env.local 13 | .env.*.local 14 | .eslintcache 15 | 16 | # Log files 17 | npm-debug.log* 18 | yarn-debug.log* 19 | yarn-error.log* 20 | pnpm-debug.log* 21 | 22 | # Editor directories and files 23 | .idea 24 | # .vscode 25 | *.suo 26 | *.ntvs* 27 | *.njsproj 28 | *.sln 29 | *.sw? 30 | yarn.lock 31 | pnpm-lock.yaml 32 | /vite-profile.cpuprofile 33 | -------------------------------------------------------------------------------- /admin/src/utils/auth/index.ts: -------------------------------------------------------------------------------- 1 | import sha512 from 'crypto-js/sha512'; 2 | 3 | export function formatByte(size: number, decimals = 2) { 4 | // 符合人类阅读习惯的数字大小单位 5 | const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; 6 | if (size === 0) return '0 B'; 7 | const index = Math.floor(Math.log(size) / Math.log(1024)); 8 | return `${(size / 1024 ** index).toFixed(decimals)} ${units[index]}`; 9 | } 10 | 11 | export function hashPassword(password: string): string { 12 | return sha512(password).toString(); 13 | } 14 | -------------------------------------------------------------------------------- /server/Module/Embedding/Model/Admin/EmbeddingSectionAdmin.php: -------------------------------------------------------------------------------- 1 | /**"], 16 | "runtimeArgs": ["--loader", "tsx"], 17 | "program": "${relativeFile}" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /admin/src/layouts/common/setting-drawer/components/index.ts: -------------------------------------------------------------------------------- 1 | import DrawerButton from './drawer-button/index.vue'; 2 | import DarkMode from './dark-mode/index.vue'; 3 | import LayoutMode from './layout-mode/index.vue'; 4 | import ThemeColorSelect from './theme-color-select/index.vue'; 5 | import PageFunc from './page-func/index.vue'; 6 | import PageView from './page-view/index.vue'; 7 | import ThemeConfig from './theme-config/index.vue'; 8 | 9 | export { DrawerButton, DarkMode, LayoutMode, ThemeColorSelect, PageFunc, PageView, ThemeConfig }; 10 | -------------------------------------------------------------------------------- /web/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 | -------------------------------------------------------------------------------- /admin/src/settings/color.ts: -------------------------------------------------------------------------------- 1 | import colorJson from './color.json'; 2 | 3 | interface TraditionColorDetail { 4 | label: string; 5 | color: string; 6 | } 7 | interface TraditionColor { 8 | label: string; 9 | data: TraditionColorDetail[]; 10 | } 11 | 12 | /** 中国传统颜色 */ 13 | export const traditionColors = colorJson as TraditionColor[]; 14 | 15 | export function isInTraditionColors(color: string) { 16 | return traditionColors.some(item => { 17 | const flag = item.data.some(v => v.color === color); 18 | return flag; 19 | }); 20 | } 21 | -------------------------------------------------------------------------------- /admin/src/views/about/components/project-introduction.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /admin/src/hooks/common/use-context.ts: -------------------------------------------------------------------------------- 1 | import { inject, provide } from 'vue'; 2 | import type { InjectionKey } from 'vue'; 3 | 4 | /** 创建共享上下文状态 */ 5 | export default function useContext(contextName = 'context') { 6 | const injectKey: InjectionKey = Symbol(contextName); 7 | 8 | function useProvide(context: T) { 9 | provide(injectKey, context); 10 | return context; 11 | } 12 | 13 | function useInject() { 14 | return inject(injectKey) as T; 15 | } 16 | 17 | return { 18 | useProvide, 19 | useInject 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /admin/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | darkMode: 'class', 4 | content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'], 5 | theme: { 6 | extend: { 7 | animation: { 8 | blink: 'blink 1.2s infinite steps(1, start)' 9 | }, 10 | keyframes: { 11 | blink: { 12 | '0%, 100%': { 'background-color': 'currentColor' }, 13 | '50%': { 'background-color': 'transparent' } 14 | } 15 | } 16 | } 17 | }, 18 | plugins: [] 19 | }; 20 | -------------------------------------------------------------------------------- /server/Module/Embedding/Model/DTO/EmbeddingFileInList.php: -------------------------------------------------------------------------------- 1 | 2 | import { computed, useAttrs } from 'vue' 3 | import { Icon } from '@iconify/vue' 4 | 5 | interface Props { 6 | icon?: string 7 | } 8 | 9 | defineProps() 10 | 11 | const attrs = useAttrs() 12 | 13 | const bindAttrs = computed<{ class: string; style: string }>(() => ({ 14 | class: (attrs.class as string) || '', 15 | style: (attrs.style as string) || '', 16 | })) 17 | 18 | 19 | 22 | -------------------------------------------------------------------------------- /admin/src/components/common/dark-mode-container.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /server/Module/Config/Annotation/PublicEnum.php: -------------------------------------------------------------------------------- 1 | ('/admin/config/save', { 9 | data 10 | }); 11 | } 12 | 13 | export async function adminEnumValues(name?: string | string[]) { 14 | if (typeof name === 'object') name = name.join(','); 15 | return request.get('/admin/enum/values', { 16 | params: { 17 | name 18 | } 19 | }); 20 | } 21 | -------------------------------------------------------------------------------- /admin/src/styles/scss/scrollbar.scss: -------------------------------------------------------------------------------- 1 | @mixin scrollbar($size: 8px, $color: #d9d9d9) { 2 | scrollbar-width: thin; 3 | scrollbar-color: $color transparent; 4 | 5 | &::-webkit-scrollbar-thumb { 6 | background-color: $color; 7 | border-radius: $size; 8 | } 9 | &::-webkit-scrollbar-thumb:hover { 10 | background-color: $color; 11 | border-radius: $size; 12 | } 13 | &::-webkit-scrollbar { 14 | width: $size; 15 | height: $size; 16 | } 17 | &::-webkit-scrollbar-track-piece { 18 | background-color: rgba(0, 0, 0, 0); 19 | border-radius: 0; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /admin/src/utils/router/helpers.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 获取所有固定路由的名称集合 3 | * @param routes - 固定路由 4 | */ 5 | export function getConstantRouteNames(routes: AuthRoute.Route[]) { 6 | return routes.map(route => getConstantRouteName(route)).flat(1); 7 | } 8 | 9 | /** 10 | * 获取所有固定路由的名称集合 11 | * @param route - 固定路由 12 | */ 13 | function getConstantRouteName(route: AuthRoute.Route) { 14 | const names = [route.name]; 15 | if (route.children?.length) { 16 | names.push(...route.children!.map(item => getConstantRouteName(item)).flat(1)); 17 | } 18 | return names; 19 | } 20 | -------------------------------------------------------------------------------- /admin/src/views/_builtin/login/components/pwd-login/components/other-login.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /server/Module/Card/Model/Admin/MemberCardOrderAdmin.php: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin/src/router/modules/member.ts: -------------------------------------------------------------------------------- 1 | const member: AuthRoute.Route = { 2 | name: 'member', 3 | path: '/member', 4 | component: 'basic', 5 | children: [ 6 | { 7 | name: 'member_list', 8 | path: '/member/list', 9 | component: 'self', 10 | meta: { 11 | title: '用户管理', 12 | requiresAuth: true, 13 | icon: 'ic:round-manage-accounts' 14 | } 15 | } 16 | ], 17 | meta: { 18 | title: '用户管理', 19 | icon: 'carbon:cloud-service-management', 20 | order: 1 21 | } 22 | }; 23 | 24 | export default member; 25 | -------------------------------------------------------------------------------- /admin/src/service/api/auth.ts: -------------------------------------------------------------------------------- 1 | import { request } from '../request'; 2 | 3 | /** 4 | * 登录 5 | * @param account - 用户名 6 | * @param password - 密码 7 | */ 8 | export function fetchLogin(account: string, password: string, vcode: string, vcodeToken: string) { 9 | return request.post('/admin/auth/login', { account, password, vcode, vcodeToken }); 10 | } 11 | 12 | export function changePassword(oldPassword: string, newPassword: string) { 13 | return request.post('/admin/auth/changePassword', { oldPassword, newPassword }); 14 | } 15 | -------------------------------------------------------------------------------- /server/Module/Config/Annotation/AdminPublicEnum.php: -------------------------------------------------------------------------------- 1 | { 17 | return request.get('/admin/paymentOrder/list', { 18 | params: data 19 | }); 20 | }; 21 | -------------------------------------------------------------------------------- /admin/src/styles/css/global.css: -------------------------------------------------------------------------------- 1 | @import "./transition.css"; 2 | @import "./reset.css"; 3 | 4 | html, 5 | body, 6 | #app { 7 | height: 100%; 8 | } 9 | 10 | @media screen and (max-width: 1280px) { 11 | .n-card>.n-card-header{ 12 | --n-padding-left: 0.618em; 13 | --n-padding-right: 0.618em; 14 | --n-padding-top: 0.618em; 15 | --n-padding-bottom: 0.618em; 16 | } 17 | .n-card>.n-card__content, 18 | .n-card>.n-card__footer { 19 | --n-padding-left: 0.618em; 20 | --n-padding-right: 0.618em; 21 | --n-padding-top: 0; 22 | --n-padding-bottom: 0.618em; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /server/Module/Config/Command/ConfigCommand.php: -------------------------------------------------------------------------------- 1 | init(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /admin/src/router/modules/payment.ts: -------------------------------------------------------------------------------- 1 | const payment: AuthRoute.Route = { 2 | name: 'payment', 3 | path: '/payment', 4 | component: 'basic', 5 | children: [ 6 | { 7 | name: 'payment_order', 8 | path: '/payment/order', 9 | component: 'self', 10 | meta: { 11 | title: '支付订单', 12 | requiresAuth: true, 13 | icon: 'ic:round-manage-accounts' 14 | } 15 | } 16 | ], 17 | meta: { 18 | title: '支付管理', 19 | icon: 'carbon:cloud-service-management', 20 | order: 1 21 | } 22 | }; 23 | 24 | export default payment; 25 | -------------------------------------------------------------------------------- /server/Module/Embedding/Enum/EmbeddingQAStatus.php: -------------------------------------------------------------------------------- 1 | 2 | import { NAvatar } from 'naive-ui' 3 | import { computed } from 'vue' 4 | import { useUserStore } from '@/store' 5 | import defaultAvatar from '@/assets/avatar.jpg' 6 | 7 | const userStore = useUserStore() 8 | 9 | const userInfo = computed(() => userStore.userInfo) 10 | 11 | 12 | 21 | -------------------------------------------------------------------------------- /web/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 | -------------------------------------------------------------------------------- /server/Module/OpenAI/Client/Annotation/OpenAIClient.php: -------------------------------------------------------------------------------- 1 | '购买卡包', 23 | }; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /admin/src/layouts/common/global-sider/components/vertical-mix-sider/components/mix-menu-collapse.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /server/Module/VCode/Struct/VCode.php: -------------------------------------------------------------------------------- 1 | image; 16 | } 17 | 18 | public function getVcode(): string 19 | { 20 | return $this->vcode; 21 | } 22 | 23 | public function getToken(): string 24 | { 25 | return $this->token; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /admin/src/typings/admin-member.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace Admin { 2 | interface AdminMember { 3 | /** 用户id */ 4 | id: number; 5 | /** 用户名 */ 6 | account: string; 7 | /** 昵称 */ 8 | nickname: string; 9 | /** 10 | * 用户状态 11 | * - 1: 启用 12 | * - 2: 禁用 13 | */ 14 | status: number; 15 | statusText: string; 16 | createTime: number; 17 | lastLoginTime: number; 18 | lastLoginIp: string; 19 | } 20 | 21 | type AdminMemberListResponse = { 22 | list: AdminMember[]; 23 | } & Api.BaseResponse & 24 | Api.PaginationResponse; 25 | } 26 | -------------------------------------------------------------------------------- /server/Exception/NotFoundException.php: -------------------------------------------------------------------------------- 1 | { 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 | -------------------------------------------------------------------------------- /server/Exception/MemberNoLoginException.php: -------------------------------------------------------------------------------- 1 | = { 12 | [envConfig.proxyPattern]: { 13 | target: envConfig.url, 14 | changeOrigin: true, 15 | rewrite: path => path.replace(new RegExp(`^${envConfig.proxyPattern}`), '') 16 | } 17 | }; 18 | 19 | return proxy; 20 | } 21 | -------------------------------------------------------------------------------- /admin/.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 | dist.zip 15 | coverage 16 | *.local 17 | stats.html 18 | 19 | /cypress/videos/ 20 | /cypress/screenshots/ 21 | 22 | # Editor directories and files 23 | .vscode/* 24 | !.vscode/extensions.json 25 | !.vscode/launch.json 26 | !.vscode/settings.json 27 | .idea 28 | *.suo 29 | *.ntvs* 30 | *.njsproj 31 | *.sln 32 | *.sw? 33 | 34 | /src/typings/components.d.ts 35 | package-lock.json 36 | yarn.lock 37 | pnpm-lock.yaml 38 | /.env 39 | -------------------------------------------------------------------------------- /admin/src/layouts/common/global-header/components/setting-button.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /admin/src/store/plugins/index.ts: -------------------------------------------------------------------------------- 1 | import type { PiniaPluginContext } from 'pinia'; 2 | import { cloneDeep } from 'lodash-es'; 3 | 4 | /** 5 | * setup语法的重置状态插件 6 | * @param context 7 | * @description 请将用setup语法的状态id写入到setupSyntaxIds 8 | */ 9 | export function resetSetupStore(context: PiniaPluginContext) { 10 | const setupSyntaxIds = ['setup-store']; 11 | 12 | if (setupSyntaxIds.includes(context.store.$id)) { 13 | const { $state } = context.store; 14 | 15 | const defaultStore = cloneDeep($state); 16 | 17 | context.store.$reset = () => { 18 | context.store.$patch(defaultStore); 19 | }; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /server/Exception/MemberStatusAnomalyException.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | 12 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /server/Module/Chat/Prompt/Annotation/PromptCrawler.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /server/Module/Config/Facade/Config.php: -------------------------------------------------------------------------------- 1 | getConfigClasses() 15 | */ 16 | class Config extends BaseFacade 17 | { 18 | } 19 | -------------------------------------------------------------------------------- /web/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 | -------------------------------------------------------------------------------- /admin/src/hooks/common/use-reload.ts: -------------------------------------------------------------------------------- 1 | import { nextTick } from 'vue'; 2 | import useBoolean from './use-boolean'; 3 | 4 | /** 重载 */ 5 | export default function useReload() { 6 | // 重载的标志 7 | const { bool: reloadFlag, setTrue, setFalse } = useBoolean(true); 8 | 9 | /** 10 | * 触发重载 11 | * @param duration - 延迟时间(ms) 12 | */ 13 | async function handleReload(duration = 0) { 14 | setFalse(); 15 | await nextTick(); 16 | 17 | if (duration > 0) { 18 | setTimeout(() => { 19 | setTrue(); 20 | }, duration); 21 | } 22 | } 23 | 24 | return { 25 | reloadFlag, 26 | handleReload 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /admin/src/constants/common.ts: -------------------------------------------------------------------------------- 1 | export const dataTypeLabels: { [K in TypeUtil.DataTypeStringKey]: TypeUtil.DataTypeString } = { 2 | string: '[object String]', 3 | number: '[object Number]', 4 | boolean: '[object Boolean]', 5 | null: '[object Null]', 6 | undefined: '[object Undefined]', 7 | symbol: '[object Symbol]', 8 | bigInt: '[object BigInt]', 9 | object: '[object Object]', 10 | function: '[object Function]', 11 | array: '[object Array]', 12 | date: '[object Date]', 13 | regExp: '[object RegExp]', 14 | promise: '[object Promise]', 15 | set: '[object Set]', 16 | map: '[object Map]', 17 | file: '[object File]' 18 | }; 19 | -------------------------------------------------------------------------------- /admin/src/layouts/common/global-header/components/github-site.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /server/Module/Chat/Prompt/Command/PromptCommand.php: -------------------------------------------------------------------------------- 1 | crawl(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /server/Module/Embedding/Enum/EmbeddingStatus.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{ item.version }} 6 | 7 | 8 | 9 | 10 | 11 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /server/Module/Admin/Util/OperationLog.php: -------------------------------------------------------------------------------- 1 | log($memberId, $object, $status, $message, $ip, $time); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /server/Module/Embedding/Enum/ContentFileTypes.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{ item.version }} 6 | 7 | 8 | 9 | 10 | 11 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /admin/src/store/modules/auth/helpers.ts: -------------------------------------------------------------------------------- 1 | import { localStg } from '@/utils'; 2 | 3 | /** 获取token */ 4 | export function getToken() { 5 | return localStg.get('token') || ''; 6 | } 7 | 8 | /** 获取用户信息 */ 9 | export function getUserInfo() { 10 | const emptyInfo: Auth.UserInfo = { 11 | id: '', 12 | account: '', 13 | nickname: '', 14 | userRole: 'user' 15 | }; 16 | const userInfo: Auth.UserInfo = localStg.get('userInfo') || emptyInfo; 17 | 18 | return userInfo; 19 | } 20 | 21 | /** 去除用户相关缓存 */ 22 | export function clearAuthStorage() { 23 | localStg.remove('token'); 24 | localStg.remove('refreshToken'); 25 | localStg.remove('userInfo'); 26 | } 27 | -------------------------------------------------------------------------------- /server/Module/Chat/Service/PromptCrawlerOriginService.php: -------------------------------------------------------------------------------- 1 | $class]); 14 | } 15 | 16 | public function create(string $class): PromptCrawlerOrigin 17 | { 18 | $origin = PromptCrawlerOrigin::newInstance(); 19 | $origin->class = $class; 20 | $origin->insert(); 21 | 22 | return $origin; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /admin/src/store/modules/setup-store/index.ts: -------------------------------------------------------------------------------- 1 | import { reactive } from 'vue'; 2 | import { defineStore } from 'pinia'; 3 | import { useBoolean } from '@/hooks'; 4 | 5 | export const useSetupStore = defineStore('setup-store', () => { 6 | const { bool: visible, setTrue: show, setFalse: hide } = useBoolean(); 7 | 8 | interface Config { 9 | name: string; 10 | } 11 | 12 | const config = reactive({ name: 'config' }); 13 | 14 | /** 设置配置 */ 15 | function setConfig(conf: Partial) { 16 | Object.assign(config, conf); 17 | } 18 | 19 | return { 20 | visible, 21 | show, 22 | hide, 23 | config, 24 | setConfig 25 | }; 26 | }); 27 | -------------------------------------------------------------------------------- /server/Module/Payment/Enum/OrderType.php: -------------------------------------------------------------------------------- 1 | '支付', 28 | self::Refund => '退款', 29 | }; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /server/Module/Embedding/Enum/PublicProjectStatus.php: -------------------------------------------------------------------------------- 1 | getRandomApi($model, $checkAvaiable); 20 | 21 | return App::newInstance($api->client, $api); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /server/phpstan.neon: -------------------------------------------------------------------------------- 1 | parameters: 2 | level: 6 3 | 4 | phpVersion: 80100 5 | 6 | paths: 7 | - . 8 | 9 | excludePaths: 10 | - */vendor/* 11 | - */Grpc/* 12 | - */Metadata/* 13 | 14 | bootstrapFiles: 15 | - vendor/autoload.php 16 | 17 | treatPhpDocTypesAsCertain: false 18 | checkGenericClassInNonGenericObjectType: false 19 | checkMissingIterableValueType: false 20 | reportUnmatchedIgnoredErrors: false 21 | 22 | ignoreErrors: 23 | - '#expects class-string<\S+>, string given#' 24 | - '#Unable to resolve the template type T in call to method#' 25 | 26 | tmpDir: ".runtime/phpstan" 27 | -------------------------------------------------------------------------------- /admin/src/App.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /web/src/App.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 24 | -------------------------------------------------------------------------------- /admin/src/layouts/common/global-sider/index.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 17 | 18 | 23 | -------------------------------------------------------------------------------- /admin/src/router/modules/dashboard.ts: -------------------------------------------------------------------------------- 1 | const dashboard: AuthRoute.Route = { 2 | name: 'dashboard', 3 | path: '/dashboard', 4 | component: 'basic', 5 | children: [ 6 | { 7 | name: 'dashboard_analysis', 8 | path: '/dashboard/analysis', 9 | component: 'self', 10 | meta: { 11 | title: '分析页', 12 | requiresAuth: true, 13 | icon: 'icon-park-outline:analysis', 14 | i18nTitle: 'routes.dashboard.analysis' 15 | } 16 | } 17 | ], 18 | meta: { 19 | title: '仪表盘', 20 | icon: 'mdi:monitor-dashboard', 21 | order: 0, 22 | i18nTitle: 'routes.dashboard._value' 23 | } 24 | }; 25 | 26 | export default dashboard; 27 | -------------------------------------------------------------------------------- /admin/src/layouts/common/global-header/components/full-screen.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /server/Module/Card/Model/CardType.php: -------------------------------------------------------------------------------- 1 | (() => 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 | -------------------------------------------------------------------------------- /admin/src/service/api/email.ts: -------------------------------------------------------------------------------- 1 | import { request } from '../request'; 2 | 3 | export const fetchEmailBlackList = async (search = '', page = 1, limit = 15) => { 4 | return request.get('/admin/email/blackList/list', { 5 | params: { 6 | search, 7 | page, 8 | limit 9 | } 10 | }); 11 | }; 12 | 13 | export const addEmailBlackList = async (domains: string[]) => { 14 | return request.post('/admin/email/blackList/add', { 15 | domains 16 | }); 17 | }; 18 | 19 | export const removeEmailBlackList = async (domains: string[]) => { 20 | return request.post('/admin/email/blackList/remove', { 21 | domains 22 | }); 23 | }; 24 | -------------------------------------------------------------------------------- /web/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 | -------------------------------------------------------------------------------- /admin/src/store/modules/common/enum.ts: -------------------------------------------------------------------------------- 1 | import { adminEnumValues } from '~/src/service/api/config'; 2 | 3 | export const ENUM_ALL = { text: '全部', value: 0 }; 4 | 5 | export async function useAdminEnums(names: string[], withAll = false, allItem: any = ENUM_ALL) { 6 | const { data } = await adminEnumValues(names); 7 | const result: any = (data as any).data; 8 | if (withAll) { 9 | for (const key of Object.keys(result)) { 10 | parseEnumWithAll(result[key], allItem); 11 | } 12 | } 13 | return result; 14 | } 15 | 16 | export function parseEnumWithAll(enums: Array, allItem: any = ENUM_ALL) { 17 | const result = enums.map(item => item); 18 | result.unshift(allItem); 19 | return result; 20 | } 21 | -------------------------------------------------------------------------------- /web/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp, nextTick } from 'vue' 2 | import App from './App.vue' 3 | import { setupI18n } from './locales' 4 | import { setupAssets, setupScrollbarStyle } from './plugins' 5 | import { setupStore, useAppStoreWithOut, useUserStore } 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 | nextTick(() => { 21 | useUserStore().updateUserInfoFromApi() 22 | }) 23 | 24 | app.mount('#app') 25 | 26 | useAppStoreWithOut().parseAction() 27 | } 28 | 29 | bootstrap() 30 | -------------------------------------------------------------------------------- /server/Module/Chat/Prompt/Cron/PromptCrawlerCron.php: -------------------------------------------------------------------------------- 1 | crawl(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /admin/src/views/dashboard/analysis/components/data-card/components/gradient-bg.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /server/Module/Payment/Annotation/PaymentChannel.php: -------------------------------------------------------------------------------- 1 | 16) 21 | { 22 | throw new \InvalidArgumentException('PaymentChannel->name length must <= 16'); 23 | } 24 | parent::__construct(...\func_get_args()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /server/Util/IPUtil.php: -------------------------------------------------------------------------------- 1 | getHeaderLine('CF-Connecting-IP') ?: $request->getHeaderLine('x-real-ip') ?: $request->getHeaderLine('X-Forwarded-For') ?: $request->getClientAddress()->getAddress(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /server/Exception/ErrorException.php: -------------------------------------------------------------------------------- 1 | statusCode = $code; 25 | } 26 | 27 | /** 28 | * 获取状态码 29 | */ 30 | public function getStatusCode(): int 31 | { 32 | return $this->statusCode; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /server/Module/Chat/Model/ChatMessage.php: -------------------------------------------------------------------------------- 1 | { 12 | // 开始 loadingBar 13 | window.$loadingBar?.start(); 14 | // 页面跳转权限处理 15 | await createPermissionGuard(to, from, next); 16 | }); 17 | router.afterEach(to => { 18 | // 设置document title 19 | useTitle(to.meta.i18nTitle ? $t(to.meta.i18nTitle) : to.meta.title); 20 | // 结束 loadingBar 21 | window.$loadingBar?.finish(); 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /admin/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 | "isolatedModules": true, 13 | "resolveJsonModule": true, 14 | "noUnusedLocals": true, 15 | "strictNullChecks": true, 16 | "forceConsistentCasingInFileNames": true, 17 | "paths": { 18 | "~/*": ["./*"], 19 | "@/*": ["./src/*"] 20 | }, 21 | "types": ["vite/client", "node", "unplugin-icons/types/vue", "naive-ui/volar"] 22 | }, 23 | "exclude": ["node_modules", "dist"] 24 | } 25 | -------------------------------------------------------------------------------- /admin/public/favicon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /admin/src/typings/business.d.ts: -------------------------------------------------------------------------------- 1 | /** 用户相关模块 */ 2 | declare namespace Auth { 3 | /** 4 | * 用户角色类型(前端静态路由用角色类型进行路由权限的控制) 5 | * - super: 超级管理员(该权限具有所有路由数据) 6 | * - admin: 管理员 7 | * - user: 用户 8 | */ 9 | type RoleType = 'super' | 'admin' | 'user'; 10 | 11 | /** 用户信息 */ 12 | interface UserInfo { 13 | /** 用户id */ 14 | id: string; 15 | /** 用户名 */ 16 | account: string; 17 | /** 用户名 */ 18 | nickname: string; 19 | /** 用户角色类型 */ 20 | userRole: RoleType; 21 | } 22 | } 23 | 24 | declare namespace UserManagement { 25 | interface User extends ApiUserManagement.User {} 26 | 27 | /** 28 | * 用户状态 29 | * - 1: 启用 30 | * - 2: 禁用 31 | */ 32 | type UserStatusKey = NonNullable; 33 | } 34 | -------------------------------------------------------------------------------- /server/Module/Payment/Enum/SecondaryPaymentChannel.php: -------------------------------------------------------------------------------- 1 | '支付宝', 31 | self::Wechat => '微信', 32 | }; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /server/Module/Card/Model/Admin/CardAdmin.php: -------------------------------------------------------------------------------- 1 | '微秒', 18 | 'millisecond' => '毫秒', 19 | 'second' => '秒', 20 | 'minute' => '分钟', 21 | 'hour' => '小时', 22 | 'day' => '天', 23 | 'week' => '周', 24 | 'month' => '月', 25 | 'year' => '年', 26 | default => $unit, 27 | }; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /admin/.github/workflows/linter.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Lint Code 3 | 4 | permissions: 5 | contents: write 6 | 7 | on: 8 | pull_request: 9 | branches: [main] 10 | 11 | jobs: 12 | lint: 13 | name: Lint All Code 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Checkout Code 18 | uses: actions/checkout@v3 19 | with: 20 | fetch-depth: 0 21 | 22 | - name: Lint Code Base 23 | uses: github/super-linter@v4 24 | env: 25 | VALIDATE_ALL_CODEBASE: false 26 | DEFAULT_BRANCH: main 27 | # To change branch master or main 28 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 29 | FILTER_REGEX_EXCLUDE: (docs|.github) 30 | VALIDATE_MARKDOWN: false 31 | -------------------------------------------------------------------------------- /admin/src/assets/svg-icon/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /admin/src/assets/svg-icon/logo-fill.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /admin/src/layouts/common/global-logo/index.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /admin/src/typings/member.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace Member { 2 | interface Member { 3 | /** 用户id */ 4 | id: number; 5 | /** 用户id */ 6 | recordId: string; 7 | /** 邮箱 */ 8 | email: string; 9 | /** 昵称 */ 10 | nickname: string; 11 | password: string; 12 | /** 13 | * 用户状态 14 | * - 1: 启用 15 | * - 2: 禁用 16 | */ 17 | status: number; 18 | statusText: string; 19 | registerTime: number; 20 | registerIp: string; 21 | lastLoginTime: number; 22 | lastLoginIp: string; 23 | } 24 | 25 | type MemberListResponse = { 26 | list: Member[]; 27 | } & Api.BaseResponse & 28 | Api.PaginationResponse; 29 | 30 | interface MemberInfo { 31 | recordId: string; 32 | nickname: string; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /server/Module/Member/Struct/EmailForgotTokenStore.php: -------------------------------------------------------------------------------- 1 | email; 16 | } 17 | 18 | public function getPassword(): string 19 | { 20 | return $this->password; 21 | } 22 | 23 | public function getCode(): string 24 | { 25 | return $this->code; 26 | } 27 | 28 | public function getVerifyToken(): string 29 | { 30 | return $this->verifyToken; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /admin/src/layouts/common/global-header/components/index.ts: -------------------------------------------------------------------------------- 1 | import MenuCollapse from './menu-collapse.vue'; 2 | import GlobalBreadcrumb from './global-breadcrumb.vue'; 3 | import HeaderMenu from './header-menu.vue'; 4 | import GithubSite from './github-site.vue'; 5 | import FullScreen from './full-screen.vue'; 6 | import ThemeMode from './theme-mode.vue'; 7 | import UserAvatar from './user-avatar.vue'; 8 | import SystemMessage from './system-message.vue'; 9 | import SettingButton from './setting-button.vue'; 10 | import ToggleLang from './toggle-lang.vue'; 11 | 12 | export { 13 | MenuCollapse, 14 | GlobalBreadcrumb, 15 | HeaderMenu, 16 | GithubSite, 17 | FullScreen, 18 | ThemeMode, 19 | UserAvatar, 20 | SystemMessage, 21 | SettingButton, 22 | ToggleLang 23 | }; 24 | -------------------------------------------------------------------------------- /server/Module/Card/Model/CardEx.php: -------------------------------------------------------------------------------- 1 | CompressFileTypes::getValues(), 21 | 'contentFileTypes' => ContentFileTypes::getValues(), 22 | ]; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /server/.env.tpl: -------------------------------------------------------------------------------- 1 | # 生产环境禁用热更新 2 | @app.beans.hotUpdate.status=0 3 | # 生产环境禁用调试 4 | APP_DEBUG=false 5 | 6 | # 测试环境启动时,接收邮件通知的邮箱 7 | # DEBUG_STARTUP_EMAIL_ADDRESS= 8 | # 正式环境启动时,接收邮件通知的邮箱 9 | # RELEASE_STARTUP_EMAIL_ADDRESS= 10 | 11 | # 服务监听ip 12 | APP_HOST=0.0.0.0 13 | # 服务端口 14 | APP_PORT=12333 15 | # 服务 Worker 进程数量 16 | APP_WORKER_NUM=2 17 | 18 | # MySQL 配置 19 | APP_MYSQL_HOST=127.0.0.1 20 | APP_MYSQL_PORT=3306 21 | APP_MYSQL_USERNAME=root 22 | APP_MYSQL_PASSWORD=root 23 | APP_MYSQL_DATABASE=db_imi_ai 24 | 25 | # PostgreSQL 配置 26 | APP_PGSQL_HOST=127.0.0.1 27 | APP_PGSQL_PORT=5432 28 | APP_PGSQL_USERNAME=root 29 | APP_PGSQL_PASSWORD=root 30 | APP_PGSQL_DATABASE=db_imi_ai 31 | 32 | # Redis 配置 33 | APP_REDIS_HOST=127.0.0.1 34 | APP_REDIS_PORT=6379 35 | 36 | # id 加密盐,改成你自己的 37 | AI_ID_SALT=imi_ai 38 | -------------------------------------------------------------------------------- /server/Module/Business/Enum/BusinessType.php: -------------------------------------------------------------------------------- 1 | $this->promptCategoryService->list(), 24 | ]; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /server/Module/Embedding/Enum/CompressFileTypes.php: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /admin/src/router/modules/chat.ts: -------------------------------------------------------------------------------- 1 | const chat: AuthRoute.Route = { 2 | name: 'chat', 3 | path: '/chat', 4 | component: 'basic', 5 | children: [ 6 | { 7 | name: 'chat_list', 8 | path: '/chat/list', 9 | component: 'self', 10 | meta: { 11 | title: 'AI聊天管理', 12 | requiresAuth: true, 13 | icon: 'ic:round-manage-accounts' 14 | } 15 | }, 16 | { 17 | name: 'chat_message_list', 18 | path: '/chat/message/list', 19 | component: 'self', 20 | meta: { 21 | title: 'AI聊天消息列表', 22 | requiresAuth: true, 23 | hide: true 24 | } 25 | } 26 | ], 27 | meta: { 28 | title: 'AI聊天管理', 29 | icon: 'carbon:cloud-service-management', 30 | order: 1 31 | } 32 | }; 33 | 34 | export default chat; 35 | -------------------------------------------------------------------------------- /server/Module/Chat/Model/Admin/ChatSession.php: -------------------------------------------------------------------------------- 1 | memberInfo = null; 25 | $this->member->__setSecureField($secureField); 26 | 27 | return $this; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /admin/build/plugins/pwa.ts: -------------------------------------------------------------------------------- 1 | import { VitePWA } from 'vite-plugin-pwa'; 2 | 3 | export default function setupVitePwa() { 4 | return VitePWA({ 5 | registerType: 'autoUpdate', 6 | includeAssets: ['favicon.ico'], 7 | manifest: { 8 | name: 'imi AI 管理后台', 9 | short_name: 'imi AI 管理后台', 10 | theme_color: '#fff', 11 | icons: [ 12 | { 13 | src: '/logo.png', 14 | sizes: '192x192', 15 | type: 'image/png' 16 | }, 17 | { 18 | src: '/logo.png', 19 | sizes: '512x512', 20 | type: 'image/png' 21 | }, 22 | { 23 | src: '/logo.png', 24 | sizes: '512x512', 25 | type: 'image/png', 26 | purpose: 'any maskable' 27 | } 28 | ] 29 | } 30 | }); 31 | } 32 | -------------------------------------------------------------------------------- /admin/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 | 8 | interface ViewTransition { 9 | ready: Promise; 10 | } 11 | 12 | interface Document { 13 | startViewTransition?: (callback: () => Promise | void) => ViewTransition; 14 | } 15 | 16 | /** 通用类型 */ 17 | declare namespace Common { 18 | /** 19 | * 策略模式 20 | * [状态, 为true时执行的回调函数] 21 | */ 22 | type StrategyAction = [boolean, () => void]; 23 | 24 | /** 选项数据 */ 25 | type OptionWithKey = { value: K; label: string }; 26 | } 27 | 28 | /** 构建时间 */ 29 | declare const PROJECT_BUILD_TIME: string; 30 | -------------------------------------------------------------------------------- /admin/src/layouts/common/global-search/index.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /server/Module/Embedding/Model/EmbeddingPublicProject.php: -------------------------------------------------------------------------------- 1 | status); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /admin/src/utils/router/module.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 权限路由排序 3 | * @param routes - 权限路由 4 | */ 5 | export function sortRoutes(routes: AuthRoute.Route[]) { 6 | return routes 7 | .sort((next, pre) => Number(next.meta?.order) - Number(pre.meta?.order)) 8 | .map(i => { 9 | if (i.children) sortRoutes(i.children); 10 | return i; 11 | }); 12 | } 13 | 14 | /** 15 | * 处理全部导入的路由模块 16 | * @param modules - 路由模块 17 | */ 18 | export function handleModuleRoutes(modules: AuthRoute.RouteModule) { 19 | const routes: AuthRoute.Route[] = []; 20 | 21 | Object.keys(modules).forEach(key => { 22 | const item = modules[key].default; 23 | if (item) { 24 | routes.push(item); 25 | } else { 26 | window.console.error(`路由模块解析出错: key = ${key}`); 27 | } 28 | }); 29 | 30 | return sortRoutes(routes); 31 | } 32 | -------------------------------------------------------------------------------- /web/src/store/modules/chat/helper.ts: -------------------------------------------------------------------------------- 1 | import { QAStatus } from '.' 2 | import { ss } from '@/utils/storage' 3 | 4 | const LOCAL_NAME = 'chatStorage' 5 | 6 | export function defaultState(): Chat.ChatState { 7 | const id = '' 8 | return { 9 | active: null, 10 | usingContext: true, 11 | history: [{ id, title: 'New Chat', isEdit: false, createTime: 0, updateTime: 0, qaStatus: QAStatus.ASK, tokens: 0 }], 12 | chat: [{ id, data: [] }], 13 | page: 1, 14 | pageSize: 15, 15 | hasNextPage: true, 16 | } 17 | } 18 | 19 | export function getLocalState(): Chat.ChatState { 20 | // const localState = ss.get(LOCAL_NAME) 21 | // return { ...defaultState(), ...localState } 22 | return defaultState() 23 | } 24 | 25 | export function setLocalState(state: Chat.ChatState) { 26 | ss.set(LOCAL_NAME, state) 27 | } 28 | -------------------------------------------------------------------------------- /server/Module/VCode/ApiController/VCodeController.php: -------------------------------------------------------------------------------- 1 | vcodeService->generateVCode(); 23 | 24 | return [ 25 | 'image' => base64_encode($vcode->getImage()), 26 | 'token' => $vcode->getToken(), 27 | ]; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /web/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 | -------------------------------------------------------------------------------- /server/Module/Card/Listener/OnPayListener.php: -------------------------------------------------------------------------------- 1 | getData(); 22 | [ 23 | 'tmpOrder' => $record, 24 | 'payResult' => $result, 25 | ] = $data; 26 | $card = $this->cardService->payCallback($record, $result); 27 | $data['businessId'] = $card->id; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /admin/src/router/modules/prompt.ts: -------------------------------------------------------------------------------- 1 | const prompt: AuthRoute.Route = { 2 | name: 'prompt', 3 | path: '/prompt', 4 | component: 'basic', 5 | children: [ 6 | { 7 | name: 'prompt_category_list', 8 | path: '/prompt/category/list', 9 | component: 'self', 10 | meta: { 11 | title: '提示语分类管理', 12 | requiresAuth: true, 13 | icon: 'ic:round-manage-accounts' 14 | } 15 | }, 16 | { 17 | name: 'prompt_list', 18 | path: '/prompt/list', 19 | component: 'self', 20 | meta: { 21 | title: '提示语管理', 22 | requiresAuth: true, 23 | icon: 'ic:round-manage-accounts' 24 | } 25 | } 26 | ], 27 | meta: { 28 | title: '提示语管理', 29 | icon: 'carbon:cloud-service-management', 30 | order: 1 31 | } 32 | }; 33 | 34 | export default prompt; 35 | -------------------------------------------------------------------------------- /server/Util/RequestUtil.php: -------------------------------------------------------------------------------- 1 | true], text: '消费')] 15 | public const PAY = 1; 16 | 17 | #[EnumItem(__data: ['deduct' => false], text: '退款')] 18 | public const REFUND = 2; 19 | 20 | #[EnumItem(__data: ['deduct' => false], text: '系统赠送')] 21 | public const GIFT = 3; 22 | 23 | #[EnumItem(__data: ['deduct' => false], text: '激活卡')] 24 | public const ACTIVATION_CARD = 4; 25 | 26 | #[EnumItem(__data: ['deduct' => false], text: '冲抵基础账户')] 27 | public const OFFSET_BASE_CARD = 5; 28 | } 29 | -------------------------------------------------------------------------------- /web/src/views/chat/layout/Layout.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 30 | -------------------------------------------------------------------------------- /server/Util/QueryHelper.php: -------------------------------------------------------------------------------- 1 | $value) 22 | { 23 | $valueNames[] = $valueName = ':v' . $i; 24 | $bindValues[$valueName] = $value; 25 | } 26 | 27 | return $query->orderRaw(sprintf('field(' . $name . ', %s)', implode(',', $valueNames)))->bindValues($bindValues); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /server/Module/Embedding/Model/Admin/EmbeddingQaAdmin.php: -------------------------------------------------------------------------------- 1 | memberInfo = null; 29 | $this->member->__setSecureField($secureField); 30 | 31 | return $this; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /server/Module/OpenAI/ApiController/Admin/OpenAIController.php: -------------------------------------------------------------------------------- 1 | $this->service->getClients(), 28 | ]; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /server/Module/Payment/Annotation/SubPaymentChannel.php: -------------------------------------------------------------------------------- 1 | memberInfo = null; 29 | $this->member->__setSecureField($secureField); 30 | 31 | return $this; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /server/Util/Generator.php: -------------------------------------------------------------------------------- 1 | = { 14 | mounted(el: HTMLElement, binding) { 15 | if (binding.value === false) return; 16 | el.addEventListener('click', listenerHandler, { capture: true }); 17 | }, 18 | unmounted(el: HTMLElement, binding) { 19 | if (binding.value === false) return; 20 | el.removeEventListener('click', listenerHandler); 21 | } 22 | }; 23 | 24 | app.directive('network', networkDirective); 25 | } 26 | -------------------------------------------------------------------------------- /admin/src/utils/router/cache.ts: -------------------------------------------------------------------------------- 1 | import type { RouteRecordRaw } from 'vue-router'; 2 | 3 | /** 4 | * 获取缓存的路由对应组件的名称 5 | * @param routes - 转换后的vue路由 6 | */ 7 | export function getCacheRoutes(routes: RouteRecordRaw[]) { 8 | const cacheNames: string[] = []; 9 | routes.forEach(route => { 10 | // 只需要获取二级路由的缓存的组件名 11 | if (hasChildren(route)) { 12 | (route.children as RouteRecordRaw[]).forEach(item => { 13 | if (isKeepAlive(item)) { 14 | cacheNames.push(item.name as string); 15 | } 16 | }); 17 | } 18 | }); 19 | return cacheNames; 20 | } 21 | 22 | /** 23 | * 路由是否缓存 24 | * @param route 25 | */ 26 | function isKeepAlive(route: RouteRecordRaw) { 27 | return Boolean(route?.meta?.keepAlive); 28 | } 29 | /** 30 | * 是否有二级路由 31 | * @param route 32 | */ 33 | function hasChildren(route: RouteRecordRaw) { 34 | return Boolean(route.children && route.children.length); 35 | } 36 | -------------------------------------------------------------------------------- /server/ApiServer/HttpController/HandShakeController.php: -------------------------------------------------------------------------------- 1 | checkLogin(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /web/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 | .wrap { 13 | width: 1280px; 14 | margin: 0 auto; 15 | } 16 | 17 | .spin-loading { 18 | position: absolute; 19 | z-index: 9999; 20 | width: 100%; 21 | height: 100%; 22 | background-color: rgba(255, 255, 255, 0.618); 23 | } 24 | 25 | @media screen and (max-width: 1280px) { 26 | .wrap { 27 | width: 100%; 28 | padding: 0 6px; 29 | } 30 | 31 | .n-card>.n-card-header { 32 | --n-padding-left: 12px; 33 | --n-padding-right: 12px; 34 | --n-padding-top: 9px; 35 | --n-padding-bottom: 10px; 36 | } 37 | 38 | .n-card>.n-card__content, 39 | .n-card>.n-card__footer { 40 | --n-padding-left: 12px; 41 | --n-padding-right: 12px; 42 | --n-padding-top: 0; 43 | --n-padding-bottom: 12px; 44 | } 45 | } -------------------------------------------------------------------------------- /server/Module/Embedding/Model/DTO/PublicEmbeddingProject.php: -------------------------------------------------------------------------------- 1 | memberInfo = null; 29 | $this->member->__setSecureField($secureField); 30 | 31 | return $this; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /server/Module/Payment/ApiController/PaymentController.php: -------------------------------------------------------------------------------- 1 | $this->paymentResultCacheService->getResult($tradeNo), 30 | ]; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /admin/src/layouts/common/setting-drawer/components/theme-color-select/components/color-checkbox.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /admin/src/typings/payment.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace Payment { 2 | interface Order { 3 | id: number; 4 | typeTitle: string; 5 | businessTypeTitle: string; 6 | createTime: number; 7 | channelTitle: string; 8 | secondaryChannelTitle: string; 9 | tertiaryChannelTitle: string; 10 | type: number; 11 | channelId: number; 12 | secondaryChannelId: number; 13 | tertiaryChannelId: number; 14 | tradeNo: string; 15 | channelTradeNo: string; 16 | secondaryTradeNo: string; 17 | tertiaryTradeNo: string; 18 | businessType: number; 19 | businessId: number; 20 | memberId: number; 21 | amount: number; 22 | leftAmount: number; 23 | remark: string; 24 | payTime: number; 25 | notifyTime: number; 26 | memberInfo: Member.MemberInfo; 27 | } 28 | 29 | type OrderResponse = { 30 | list: Order[]; 31 | } & Api.BaseResponse & 32 | Api.PaginationResponse; 33 | } 34 | -------------------------------------------------------------------------------- /server/Module/Embedding/FileHandler/DocxFileHandler.php: -------------------------------------------------------------------------------- 1 | content) 18 | { 19 | $sourceFileName = $this->getFileName(); 20 | $outputFileName = $sourceFileName . '.md'; 21 | Pandoc::exec([ 22 | '-s' => $sourceFileName, 23 | '-o' => $outputFileName, 24 | '-t' => 'markdown-simple_tables-multiline_tables-grid_tables+pipe_tables', 25 | ]); 26 | 27 | return $this->content = file_get_contents($outputFileName); 28 | } 29 | 30 | return $this->content; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /server/Module/Member/Struct/EmailRegisterTokenStore.php: -------------------------------------------------------------------------------- 1 | email; 16 | } 17 | 18 | public function getPassword(): string 19 | { 20 | return $this->password; 21 | } 22 | 23 | public function getCode(): string 24 | { 25 | return $this->code; 26 | } 27 | 28 | public function getVerifyToken(): string 29 | { 30 | return $this->verifyToken; 31 | } 32 | 33 | public function getInvitationCode(): string 34 | { 35 | return $this->invitationCode; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /admin/src/components/common/exception-base.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /admin/src/composables/system.ts: -------------------------------------------------------------------------------- 1 | import UAParser from 'ua-parser-js'; 2 | import { useAuthStore } from '@/store'; 3 | import { isArray, isString } from '@/utils'; 4 | 5 | /** 获取设备信息 */ 6 | export function useDeviceInfo() { 7 | const parser = new UAParser(); 8 | const result = parser.getResult(); 9 | return result; 10 | } 11 | 12 | /** 权限判断 */ 13 | export function usePermission() { 14 | const auth = useAuthStore(); 15 | 16 | function hasPermission(permission: Auth.RoleType | Auth.RoleType[]) { 17 | const { userRole } = auth.userInfo; 18 | 19 | let has = userRole === 'super'; 20 | if (!has) { 21 | if (isArray(permission)) { 22 | has = (permission as Auth.RoleType[]).includes(userRole); 23 | } 24 | if (isString(permission)) { 25 | has = (permission as Auth.RoleType) === userRole; 26 | } 27 | } 28 | return has; 29 | } 30 | 31 | return { 32 | hasPermission 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /admin/src/directives/permission.ts: -------------------------------------------------------------------------------- 1 | import type { App, Directive } from 'vue'; 2 | import { usePermission } from '@/composables'; 3 | 4 | export default function setupPermissionDirective(app: App) { 5 | const { hasPermission } = usePermission(); 6 | 7 | function updateElVisible(el: HTMLElement, permission: Auth.RoleType | Auth.RoleType[]) { 8 | if (!permission) { 9 | throw new Error(`need roles: like v-permission="'admin'", v-permission="['admin', 'test]"`); 10 | } 11 | if (!hasPermission(permission)) { 12 | el.parentElement?.removeChild(el); 13 | } 14 | } 15 | 16 | const permissionDirective: Directive = { 17 | mounted(el, binding) { 18 | updateElVisible(el, binding.value); 19 | }, 20 | beforeUpdate(el, binding) { 21 | updateElVisible(el, binding.value); 22 | } 23 | }; 24 | 25 | app.directive('permission', permissionDirective); 26 | } 27 | -------------------------------------------------------------------------------- /admin/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue'; 2 | import App from './App.vue'; 3 | import AppLoading from './components/common/app-loading.vue'; 4 | import { setupDirectives } from './directives'; 5 | import { setupRouter } from './router'; 6 | import { setupAssets } from './plugins'; 7 | import { setupStore } from './store'; 8 | import { setupI18n } from './locales'; 9 | 10 | async function setupApp() { 11 | // import assets: js、css 12 | setupAssets(); 13 | 14 | // app loading 15 | const appLoading = createApp(AppLoading); 16 | 17 | appLoading.mount('#appLoading'); 18 | 19 | const app = createApp(App); 20 | 21 | // store plugin: pinia 22 | setupStore(app); 23 | 24 | // vue custom directives 25 | setupDirectives(app); 26 | 27 | // vue router 28 | await setupRouter(app); 29 | 30 | setupI18n(app); 31 | 32 | appLoading.unmount(); 33 | 34 | // mount app 35 | app.mount('#app'); 36 | } 37 | 38 | setupApp(); 39 | -------------------------------------------------------------------------------- /admin/src/utils/components/pagination.ts: -------------------------------------------------------------------------------- 1 | import { reactive } from 'vue'; 2 | import { useBasicLayout } from '~/src/composables'; 3 | 4 | export function defaultPaginationProps(loadData: CallableFunction, simple?: boolean) { 5 | const { isMobile } = useBasicLayout(); 6 | const pagination = reactive({ 7 | page: 1, 8 | pageSize: 10, 9 | showSizePicker: true, 10 | pageSizes: [10, 15, 20, 25, 30], 11 | pageCount: 1, 12 | itemCount: 0 as number | undefined, 13 | onChange: (page: number) => { 14 | pagination.page = page; 15 | loadData(); 16 | }, 17 | onUpdatePageSize: (pageSize: number) => { 18 | pagination.pageSize = pageSize; 19 | pagination.page = 1; 20 | loadData(); 21 | }, 22 | simple: simple ?? isMobile, 23 | prefix: () => { 24 | return undefined === pagination.itemCount ? '' : `共 ${pagination.itemCount} 条数据`; 25 | } 26 | }); 27 | return pagination; 28 | } 29 | -------------------------------------------------------------------------------- /server/Module/Admin/Aop/AdminLoginRequiredInject.php: -------------------------------------------------------------------------------- 1 | checkLogin(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /admin/src/layouts/common/global-sider/components/vertical-sider/index.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /admin/src/directives/login.ts: -------------------------------------------------------------------------------- 1 | import type { App, Directive } from 'vue'; 2 | import { useAuthStore } from '@/store'; 3 | import { useRouterPush } from '@/composables'; 4 | 5 | export default function setupLoginDirective(app: App) { 6 | const auth = useAuthStore(); 7 | const { toLogin } = useRouterPush(false); 8 | function listenerHandler(event: MouseEvent) { 9 | if (!auth.isLogin) { 10 | event.stopPropagation(); 11 | toLogin(); 12 | } 13 | } 14 | 15 | const loginDirective: Directive = { 16 | mounted(el: HTMLElement, binding) { 17 | if (binding.value === false) return; 18 | el.addEventListener('click', listenerHandler, { capture: true }); 19 | }, 20 | unmounted(el: HTMLElement, binding) { 21 | if (binding.value === false) return; 22 | el.removeEventListener('click', listenerHandler); 23 | } 24 | }; 25 | 26 | app.directive('login', loginDirective); 27 | } 28 | -------------------------------------------------------------------------------- /web/src/store/modules/app/helper.ts: -------------------------------------------------------------------------------- 1 | import { ss } from '@/utils/storage' 2 | 3 | const LOCAL_NAME = 'appSetting' 4 | 5 | export type Theme = 'light' | 'dark' | 'auto' 6 | 7 | export type Language = 'zh-CN' | 'zh-TW' | 'en-US' | 'ko-KR' | 'ru-RU' 8 | 9 | export interface AppState { 10 | siderCollapsed: boolean 11 | theme: Theme 12 | language: Language 13 | } 14 | 15 | export function defaultSetting(): AppState { 16 | return { siderCollapsed: false, theme: 'light', language: 'zh-CN' } 17 | } 18 | 19 | export function getLocalSetting(): AppState { 20 | const localSetting: AppState | undefined = ss.get(LOCAL_NAME) 21 | return { ...defaultSetting(), ...localSetting } 22 | } 23 | 24 | export function setLocalSetting(setting: AppState): void { 25 | ss.set(LOCAL_NAME, setting) 26 | } 27 | 28 | export interface Runtime { 29 | headerTitle: string 30 | } 31 | 32 | export function getLocalRuntime(): Runtime { 33 | return { headerTitle: '' } 34 | } 35 | -------------------------------------------------------------------------------- /server/Module/Chat/Prompt/Cron/CleanTempRecordCron.php: -------------------------------------------------------------------------------- 1 | getTempRecordTTL(); 27 | if ($ttl > 0) 28 | { 29 | $promptService = App::getBean(PromptService::class); 30 | $promptService->deleteTempRecords($ttl); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /server/Module/Embedding/Model/EmbeddingSectionSearched.php: -------------------------------------------------------------------------------- 1 | distance; 29 | } 30 | 31 | public function setDistance(float|string|null $distance): self 32 | { 33 | $this->distance = null === $distance ? null : (float) $distance; 34 | 35 | return $this; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /server/Module/OpenAI/Client/OpenAIClient.php: -------------------------------------------------------------------------------- 1 | getAnnotation(); 20 | $class = $point->getClass(); 21 | $this->clients[] = [ 22 | 'title' => $annotation->title, 23 | 'class' => $class, 24 | ]; 25 | } 26 | } 27 | 28 | public function getClients(): array 29 | { 30 | return $this->clients; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /server/Module/Admin/Cron/CleanOperationLogCron.php: -------------------------------------------------------------------------------- 1 | getOperationLogExpires(); 27 | if ($expires > 0) 28 | { 29 | $service = App::getBean(AdminOperationLogService::class); 30 | $service->clean($expires); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /admin/src/layouts/common/global-search/components/search-footer.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 22 | 23 | 31 | -------------------------------------------------------------------------------- /admin/src/store/subscribe/app.ts: -------------------------------------------------------------------------------- 1 | import { effectScope, onScopeDispose, watch } from 'vue'; 2 | import { useFullscreen } from '@vueuse/core'; 3 | import { useAppStore } from '../modules'; 4 | 5 | /** 订阅app store */ 6 | export default function subscribeAppStore() { 7 | const { isFullscreen, toggle } = useFullscreen(); 8 | 9 | const app = useAppStore(); 10 | 11 | const scope = effectScope(); 12 | 13 | function update() { 14 | if (app.contentFull && !isFullscreen.value) { 15 | toggle(); 16 | } 17 | if (!app.contentFull && isFullscreen.value) { 18 | toggle(); 19 | } 20 | } 21 | 22 | scope.run(() => { 23 | watch( 24 | () => app.contentFull, 25 | () => { 26 | update(); 27 | } 28 | ); 29 | 30 | watch(isFullscreen, newValue => { 31 | if (!newValue) { 32 | app.setContentFull(false); 33 | } 34 | }); 35 | }); 36 | 37 | onScopeDispose(() => { 38 | scope.stop(); 39 | }); 40 | } 41 | -------------------------------------------------------------------------------- /web/src/views/chat/hooks/useChat.ts: -------------------------------------------------------------------------------- 1 | import { useChatStore } from '@/store' 2 | 3 | export function useChat() { 4 | const chatStore = useChatStore() 5 | 6 | const getChatByUuidAndIndex = (id: string, index: number) => { 7 | return chatStore.getChatByUuidAndIndex(id, index) 8 | } 9 | 10 | const addChat = (id: string, chat: Chat.Chat) => { 11 | chatStore.addChatByUuid(id, chat) 12 | } 13 | 14 | const updateChat = (id: string, index: number, chat: Chat.Chat) => { 15 | chatStore.updateChatByUuid(id, index, chat) 16 | } 17 | 18 | const updateChatSome = (id: string, index: number, chat: Partial) => { 19 | chatStore.updateChatSomeByUuid(id, index, chat) 20 | } 21 | 22 | const deleteChatByUuid = (id: string, index: number) => { 23 | chatStore.deleteChatByUuid(id, index) 24 | } 25 | 26 | return { 27 | addChat, 28 | updateChat, 29 | updateChatSome, 30 | getChatByUuidAndIndex, 31 | deleteChatByUuid, 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /admin/src/components/custom/image-verify.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /admin/src/utils/service/msg.ts: -------------------------------------------------------------------------------- 1 | import { ERROR_MSG_DURATION, NO_ERROR_MSG_CODE } from '@/config'; 2 | 3 | /** 错误消息栈,防止同一错误同时出现 */ 4 | const errorMsgStack = new Map([]); 5 | 6 | function addErrorMsg(error: Service.RequestError) { 7 | errorMsgStack.set(error.code, error.msg); 8 | } 9 | function removeErrorMsg(error: Service.RequestError) { 10 | errorMsgStack.delete(error.code); 11 | } 12 | function hasErrorMsg(error: Service.RequestError) { 13 | return errorMsgStack.has(error.code); 14 | } 15 | 16 | /** 17 | * 显示错误信息 18 | * @param error 19 | */ 20 | export function showErrorMsg(error: Service.RequestError) { 21 | if (!error.msg || NO_ERROR_MSG_CODE.includes(error.code) || hasErrorMsg(error)) return; 22 | 23 | addErrorMsg(error); 24 | window.console.warn(error.code, error.msg); 25 | window.$message?.error(error.msg, { duration: ERROR_MSG_DURATION }); 26 | setTimeout(() => { 27 | removeErrorMsg(error); 28 | }, ERROR_MSG_DURATION); 29 | } 30 | -------------------------------------------------------------------------------- /server/Module/VCode/Model/Redis/VCodeConfig.php: -------------------------------------------------------------------------------- 1 | ttl; 34 | } 35 | 36 | public function setTTL(int $ttl): self 37 | { 38 | $this->ttl = $ttl; 39 | 40 | return $this; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /web/src/views/embedding/index.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 30 | -------------------------------------------------------------------------------- /admin/src/utils/common/number.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 根据数字获取对应的汉字 3 | * @param num - 数字(0-10) 4 | */ 5 | export function getHanByNumber(num: number) { 6 | const HAN_STR = '零一二三四五六七八九十'; 7 | return HAN_STR.charAt(num); 8 | } 9 | 10 | /** 11 | * 将总秒数转换成 分:秒 12 | * @param seconds - 秒 13 | */ 14 | export function transformToTimeCountDown(seconds: number) { 15 | const SECONDS_A_MINUTE = 60; 16 | function fillZero(num: number) { 17 | return num.toString().padStart(2, '0'); 18 | } 19 | const minuteNum = Math.floor(seconds / SECONDS_A_MINUTE); 20 | const minute = fillZero(minuteNum); 21 | const second = fillZero(seconds - minuteNum * SECONDS_A_MINUTE); 22 | return `${minute}: ${second}`; 23 | } 24 | 25 | /** 26 | * 获取指定整数范围内的随机整数 27 | * @param start - 开始范围 28 | * @param end - 结束范围 29 | */ 30 | export function getRandomInteger(end: number, start = 0) { 31 | const range = end - start; 32 | const random = Math.floor(Math.random() * range + start); 33 | return random; 34 | } 35 | -------------------------------------------------------------------------------- /admin/src/utils/storage/session.ts: -------------------------------------------------------------------------------- 1 | import { decrypt, encrypt } from '../crypto'; 2 | 3 | function createSessionStorage() { 4 | function set(key: K, value: T[K]) { 5 | const json = encrypt(value); 6 | sessionStorage.setItem(key as string, json); 7 | } 8 | function get(key: K) { 9 | const json = sessionStorage.getItem(key as string); 10 | let data: T[K] | null = null; 11 | if (json) { 12 | try { 13 | data = decrypt(json); 14 | } catch { 15 | // 防止解析失败 16 | } 17 | } 18 | return data; 19 | } 20 | function remove(key: keyof T) { 21 | window.sessionStorage.removeItem(key as string); 22 | } 23 | function clear() { 24 | window.sessionStorage.clear(); 25 | } 26 | 27 | return { 28 | set, 29 | get, 30 | remove, 31 | clear 32 | }; 33 | } 34 | 35 | export const sessionStg = createSessionStorage(); 36 | --------------------------------------------------------------------------------