Showing preview only (2,389K chars total). Download the full file or copy to clipboard to get everything.
Repository: coaidev/coai
Branch: main
Commit: 3048a493eedc
Files: 535
Total size: 2.2 MB
Directory structure:
gitextract__4v8y3mp/
├── .dockerignore
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ ├── channel_update.md
│ │ ├── config.yml
│ │ └── feature_request.md
│ └── workflows/
│ ├── app.yaml
│ ├── build.yaml
│ ├── docker-cd.yaml
│ ├── docker-ci.yaml
│ └── issue-translator.yaml
├── .gitignore
├── Dockerfile
├── LICENSE
├── README.md
├── README_ja-JP.md
├── README_zh-CN.md
├── adapter/
│ ├── adapter.go
│ ├── azure/
│ │ ├── chat.go
│ │ ├── image.go
│ │ ├── processor.go
│ │ ├── struct.go
│ │ └── types.go
│ ├── baichuan/
│ │ ├── chat.go
│ │ ├── processor.go
│ │ ├── struct.go
│ │ └── types.go
│ ├── bing/
│ │ ├── chat.go
│ │ ├── struct.go
│ │ └── types.go
│ ├── claude/
│ │ ├── chat.go
│ │ ├── struct.go
│ │ └── types.go
│ ├── common/
│ │ ├── interface.go
│ │ └── types.go
│ ├── coze/
│ │ ├── chat.go
│ │ ├── processor.go
│ │ └── struct.go
│ ├── dashscope/
│ │ ├── chat.go
│ │ ├── struct.go
│ │ └── types.go
│ ├── deepseek/
│ │ ├── chat.go
│ │ └── struct.go
│ ├── dify/
│ │ ├── chat.go
│ │ ├── processor.go
│ │ └── struct.go
│ ├── hunyuan/
│ │ ├── chat.go
│ │ ├── sdk.go
│ │ └── struct.go
│ ├── midjourney/
│ │ ├── api.go
│ │ ├── chat.go
│ │ ├── expose.go
│ │ ├── handler.go
│ │ ├── storage.go
│ │ ├── struct.go
│ │ └── types.go
│ ├── openai/
│ │ ├── chat.go
│ │ ├── image.go
│ │ ├── processor.go
│ │ ├── struct.go
│ │ ├── types.go
│ │ └── videos.go
│ ├── palm2/
│ │ ├── chat.go
│ │ ├── formatter.go
│ │ ├── image.go
│ │ ├── struct.go
│ │ └── types.go
│ ├── request.go
│ ├── router.go
│ ├── skylark/
│ │ ├── chat.go
│ │ ├── formatter.go
│ │ └── struct.go
│ ├── slack/
│ │ ├── chat.go
│ │ └── struct.go
│ ├── sparkdesk/
│ │ ├── chat.go
│ │ ├── struct.go
│ │ └── types.go
│ ├── zhinao/
│ │ ├── chat.go
│ │ ├── processor.go
│ │ ├── struct.go
│ │ └── types.go
│ └── zhipuai/
│ ├── chat.go
│ ├── processor.go
│ ├── struct.go
│ └── types.go
├── addition/
│ ├── article/
│ │ ├── api.go
│ │ ├── data/
│ │ │ └── .gitkeep
│ │ ├── generate.go
│ │ ├── template.docx
│ │ └── utils.go
│ ├── card/
│ │ ├── .gitignore
│ │ ├── card.go
│ │ ├── card.php
│ │ ├── error.php
│ │ └── utils.php
│ ├── generation/
│ │ ├── api.go
│ │ ├── build.go
│ │ ├── data/
│ │ │ └── .gitkeep
│ │ ├── generate.go
│ │ └── prompt.go
│ ├── router.go
│ └── web/
│ ├── call.go
│ └── search.go
├── admin/
│ ├── analysis/
│ │ ├── analysis.go
│ │ ├── format.go
│ │ ├── reflect.go
│ │ ├── statistic.go
│ │ └── types.go
│ ├── controller.go
│ ├── format.go
│ ├── instance.go
│ ├── invitation.go
│ ├── logger.go
│ ├── market.go
│ ├── redeem.go
│ ├── router.go
│ ├── statistic.go
│ ├── types.go
│ └── user.go
├── app/
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── .prettierrc.json
│ ├── components.json
│ ├── index.html
│ ├── package.json
│ ├── postcss.config.js
│ ├── public/
│ │ ├── manifest.json
│ │ ├── robots.txt
│ │ ├── service.js
│ │ ├── site.webmanifest
│ │ └── workbox.js
│ ├── qodana.yaml
│ ├── src/
│ │ ├── App.tsx
│ │ ├── admin/
│ │ │ ├── api/
│ │ │ │ ├── channel.ts
│ │ │ │ ├── charge.ts
│ │ │ │ ├── chart.ts
│ │ │ │ ├── info.ts
│ │ │ │ ├── logger.ts
│ │ │ │ ├── market.ts
│ │ │ │ ├── plan.ts
│ │ │ │ └── system.ts
│ │ │ ├── channel.ts
│ │ │ ├── charge.ts
│ │ │ ├── colors.ts
│ │ │ ├── datasets/
│ │ │ │ └── charge.ts
│ │ │ ├── hook.tsx
│ │ │ ├── market.ts
│ │ │ └── types.ts
│ │ ├── api/
│ │ │ ├── addition.ts
│ │ │ ├── auth.ts
│ │ │ ├── broadcast.ts
│ │ │ ├── common.ts
│ │ │ ├── connection.ts
│ │ │ ├── file.ts
│ │ │ ├── generation.ts
│ │ │ ├── history.ts
│ │ │ ├── mask.ts
│ │ │ ├── plugin.ts
│ │ │ ├── quota.ts
│ │ │ ├── record.ts
│ │ │ ├── redeem.ts
│ │ │ ├── sharing.ts
│ │ │ ├── types.tsx
│ │ │ └── v1.ts
│ │ ├── assets/
│ │ │ ├── admin/
│ │ │ │ ├── all.less
│ │ │ │ ├── broadcast.less
│ │ │ │ ├── channel.less
│ │ │ │ ├── charge.less
│ │ │ │ ├── dashboard.less
│ │ │ │ ├── logger.less
│ │ │ │ ├── management.less
│ │ │ │ ├── market.less
│ │ │ │ ├── menu.less
│ │ │ │ ├── subscription.less
│ │ │ │ └── system.less
│ │ │ ├── common/
│ │ │ │ ├── 404.less
│ │ │ │ ├── editor.less
│ │ │ │ ├── file.less
│ │ │ │ ├── loader.less
│ │ │ │ └── plugin.less
│ │ │ ├── fonts/
│ │ │ │ ├── all.less
│ │ │ │ ├── common.less
│ │ │ │ └── katex.less
│ │ │ ├── globals.less
│ │ │ ├── main.less
│ │ │ ├── markdown/
│ │ │ │ ├── all.less
│ │ │ │ ├── highlight.less
│ │ │ │ ├── style.less
│ │ │ │ └── theme.less
│ │ │ ├── pages/
│ │ │ │ ├── api.less
│ │ │ │ ├── article.less
│ │ │ │ ├── auth.less
│ │ │ │ ├── chat.less
│ │ │ │ ├── generation.less
│ │ │ │ ├── home.less
│ │ │ │ ├── navbar.less
│ │ │ │ ├── notify.less
│ │ │ │ ├── package.less
│ │ │ │ ├── preset.less
│ │ │ │ ├── quota.less
│ │ │ │ ├── record.less
│ │ │ │ ├── settings.less
│ │ │ │ ├── share-manager.less
│ │ │ │ ├── sharing.less
│ │ │ │ └── subscription.less
│ │ │ └── ui.less
│ │ ├── components/
│ │ │ ├── Avatar.tsx
│ │ │ ├── EditorProvider.tsx
│ │ │ ├── Emoji.tsx
│ │ │ ├── ErrorBoundary.tsx
│ │ │ ├── FileProvider.tsx
│ │ │ ├── FileViewer.tsx
│ │ │ ├── I18nProvider.tsx
│ │ │ ├── Loader.tsx
│ │ │ ├── MCPResultDebug.tsx
│ │ │ ├── MCPResultPanel.tsx
│ │ │ ├── Markdown.tsx
│ │ │ ├── Message.tsx
│ │ │ ├── ModelAvatar.tsx
│ │ │ ├── OperationAction.tsx
│ │ │ ├── Paragraph.tsx
│ │ │ ├── PopupDialog.tsx
│ │ │ ├── ProjectLink.tsx
│ │ │ ├── ReloadService.tsx
│ │ │ ├── Require.tsx
│ │ │ ├── SelectGroup.tsx
│ │ │ ├── ThemeProvider.tsx
│ │ │ ├── ThinkContent.tsx
│ │ │ ├── TickButton.tsx
│ │ │ ├── Tips.tsx
│ │ │ ├── TrendBadge.tsx
│ │ │ ├── VoiceProvider.tsx
│ │ │ ├── WarningButton.tsx
│ │ │ ├── admin/
│ │ │ │ ├── ChannelSettings.tsx
│ │ │ │ ├── ChargeWidget.tsx
│ │ │ │ ├── ChartBox.tsx
│ │ │ │ ├── InfoBox.tsx
│ │ │ │ ├── InvitationTable.tsx
│ │ │ │ ├── MenuBar.tsx
│ │ │ │ ├── RedeemTable.tsx
│ │ │ │ ├── UserTable.tsx
│ │ │ │ ├── assemblies/
│ │ │ │ │ ├── BillingChart.tsx
│ │ │ │ │ ├── BroadcastTable.tsx
│ │ │ │ │ ├── ChannelEditor.tsx
│ │ │ │ │ ├── ChannelTable.tsx
│ │ │ │ │ ├── ErrorChart.tsx
│ │ │ │ │ ├── ModelChart.tsx
│ │ │ │ │ ├── ModelUsageChart.tsx
│ │ │ │ │ ├── RequestChart.tsx
│ │ │ │ │ └── UserTypeChart.tsx
│ │ │ │ └── common/
│ │ │ │ └── StateBadge.tsx
│ │ │ ├── app/
│ │ │ │ ├── Announcement.tsx
│ │ │ │ ├── AppProvider.tsx
│ │ │ │ ├── Contact.tsx
│ │ │ │ ├── MenuBar.tsx
│ │ │ │ └── NavBar.tsx
│ │ │ ├── home/
│ │ │ │ ├── ChatInterface.tsx
│ │ │ │ ├── ChatSpace.tsx
│ │ │ │ ├── ChatWrapper.tsx
│ │ │ │ ├── ConversationItem.tsx
│ │ │ │ ├── MaskEditor.tsx
│ │ │ │ ├── ModelArea.tsx
│ │ │ │ ├── SideBar.tsx
│ │ │ │ ├── assemblies/
│ │ │ │ │ ├── ActionButton.tsx
│ │ │ │ │ ├── ChatAction.tsx
│ │ │ │ │ ├── ChatInput.tsx
│ │ │ │ │ └── ScrollAction.tsx
│ │ │ │ └── subscription/
│ │ │ │ ├── SubscriptionUsage.tsx
│ │ │ │ └── UpgradePlan.tsx
│ │ │ ├── markdown/
│ │ │ │ ├── Code.tsx
│ │ │ │ ├── Image.tsx
│ │ │ │ ├── Label.tsx
│ │ │ │ ├── Link.tsx
│ │ │ │ ├── Reference.tsx
│ │ │ │ ├── Video.tsx
│ │ │ │ └── VirtualMessage.tsx
│ │ │ ├── plugins/
│ │ │ │ ├── file.tsx
│ │ │ │ ├── mermaid.tsx
│ │ │ │ └── progress.tsx
│ │ │ ├── ui/
│ │ │ │ ├── accordion.tsx
│ │ │ │ ├── alert-dialog.tsx
│ │ │ │ ├── alert.tsx
│ │ │ │ ├── badge.tsx
│ │ │ │ ├── button.tsx
│ │ │ │ ├── calendar.tsx
│ │ │ │ ├── card.tsx
│ │ │ │ ├── checkbox.tsx
│ │ │ │ ├── clickable.tsx
│ │ │ │ ├── combo-box.tsx
│ │ │ │ ├── command.tsx
│ │ │ │ ├── context-menu.tsx
│ │ │ │ ├── date-picker.tsx
│ │ │ │ ├── dialog.tsx
│ │ │ │ ├── drawer.tsx
│ │ │ │ ├── dropdown-menu.tsx
│ │ │ │ ├── icons/
│ │ │ │ │ ├── Github.tsx
│ │ │ │ │ └── Send.tsx
│ │ │ │ ├── input.tsx
│ │ │ │ ├── label.tsx
│ │ │ │ ├── lib/
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── multi-combobox.tsx
│ │ │ │ ├── number-input.tsx
│ │ │ │ ├── pagination.tsx
│ │ │ │ ├── popover.tsx
│ │ │ │ ├── progress.tsx
│ │ │ │ ├── radio-box.tsx
│ │ │ │ ├── radio-group.tsx
│ │ │ │ ├── scroll-area.tsx
│ │ │ │ ├── select.tsx
│ │ │ │ ├── separator.tsx
│ │ │ │ ├── sheet.tsx
│ │ │ │ ├── skeleton.tsx
│ │ │ │ ├── slider.tsx
│ │ │ │ ├── sonner.tsx
│ │ │ │ ├── step.tsx
│ │ │ │ ├── switch.tsx
│ │ │ │ ├── table.tsx
│ │ │ │ ├── tabs.tsx
│ │ │ │ ├── textarea.tsx
│ │ │ │ ├── toast.tsx
│ │ │ │ ├── toaster.tsx
│ │ │ │ ├── toggle-group.tsx
│ │ │ │ ├── toggle.tsx
│ │ │ │ ├── tooltip.tsx
│ │ │ │ └── use-toast.ts
│ │ │ └── utils/
│ │ │ └── Icon.tsx
│ │ ├── conf/
│ │ │ ├── api.ts
│ │ │ ├── bootstrap.ts
│ │ │ ├── deeptrain.tsx
│ │ │ ├── env.ts
│ │ │ ├── model.ts
│ │ │ ├── storage.ts
│ │ │ ├── subscription.tsx
│ │ │ └── version.json
│ │ ├── dialogs/
│ │ │ ├── SettingsDialog.tsx
│ │ │ └── index.tsx
│ │ ├── events/
│ │ │ ├── blob.ts
│ │ │ ├── info.ts
│ │ │ ├── model.ts
│ │ │ ├── spinner.ts
│ │ │ ├── struct.ts
│ │ │ └── theme.ts
│ │ ├── i18n.ts
│ │ ├── main.tsx
│ │ ├── masks/
│ │ │ ├── prompts.ts
│ │ │ └── types.ts
│ │ ├── payment/
│ │ │ ├── icons.tsx
│ │ │ ├── request.ts
│ │ │ └── utils.ts
│ │ ├── plugin/
│ │ │ └── types.ts
│ │ ├── resources/
│ │ │ └── i18n/
│ │ │ ├── cn.json
│ │ │ ├── en.json
│ │ │ ├── ja.json
│ │ │ ├── ru.json
│ │ │ └── tw.json
│ │ ├── router.tsx
│ │ ├── routes/
│ │ │ ├── Account.tsx
│ │ │ ├── Admin.tsx
│ │ │ ├── Article.tsx
│ │ │ ├── Auth.tsx
│ │ │ ├── Forgot.tsx
│ │ │ ├── Generation.tsx
│ │ │ ├── Home.tsx
│ │ │ ├── Index.tsx
│ │ │ ├── Model.tsx
│ │ │ ├── NotFound.tsx
│ │ │ ├── Register.tsx
│ │ │ ├── Sharing.tsx
│ │ │ ├── Wallet.tsx
│ │ │ ├── admin/
│ │ │ │ ├── Broadcast.tsx
│ │ │ │ ├── Channel.tsx
│ │ │ │ ├── Charge.tsx
│ │ │ │ ├── DashBoard.tsx
│ │ │ │ ├── License.tsx
│ │ │ │ ├── Logger.tsx
│ │ │ │ ├── Market.tsx
│ │ │ │ ├── Notification.tsx
│ │ │ │ ├── Subscription.tsx
│ │ │ │ ├── System.tsx
│ │ │ │ ├── Users.tsx
│ │ │ │ └── common/
│ │ │ │ └── CommonAdminPage.tsx
│ │ │ └── wallet/
│ │ │ ├── AmountItem.tsx
│ │ │ └── WalletQuotaBox.tsx
│ │ ├── spinner.tsx
│ │ ├── store/
│ │ │ ├── api.ts
│ │ │ ├── auth.ts
│ │ │ ├── avatar.ts
│ │ │ ├── chat.ts
│ │ │ ├── globals.ts
│ │ │ ├── index.ts
│ │ │ ├── info.ts
│ │ │ ├── menu.ts
│ │ │ ├── package.ts
│ │ │ ├── quota.ts
│ │ │ ├── record.ts
│ │ │ ├── settings.ts
│ │ │ ├── sharing.ts
│ │ │ ├── subscription.ts
│ │ │ └── utils.ts
│ │ ├── translator/
│ │ │ ├── adapter.ts
│ │ │ ├── index.ts
│ │ │ ├── io.ts
│ │ │ └── translator.ts
│ │ ├── types/
│ │ │ ├── performance.d.ts
│ │ │ ├── service.d.ts
│ │ │ └── ui.d.ts
│ │ ├── utils/
│ │ │ ├── analytics.ts
│ │ │ ├── app.ts
│ │ │ ├── base.ts
│ │ │ ├── date.ts
│ │ │ ├── desktop.ts
│ │ │ ├── dev.ts
│ │ │ ├── device.ts
│ │ │ ├── dom.ts
│ │ │ ├── form.ts
│ │ │ ├── groups.ts
│ │ │ ├── hook.ts
│ │ │ ├── loader.tsx
│ │ │ ├── memory.ts
│ │ │ ├── path.ts
│ │ │ └── processor.ts
│ │ └── vite-env.d.ts
│ ├── src-tauri/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── build.rs
│ │ ├── icons/
│ │ │ └── icon.icns
│ │ ├── src/
│ │ │ └── main.rs
│ │ └── tauri.conf.json
│ ├── tailwind.config.js
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
├── auth/
│ ├── analysis.go
│ ├── apikey.go
│ ├── auth.go
│ ├── call.go
│ ├── cert.go
│ ├── controller.go
│ ├── invitation.go
│ ├── package.go
│ ├── payment.go
│ ├── quota.go
│ ├── redeem.go
│ ├── router.go
│ ├── rule.go
│ ├── struct.go
│ ├── subscription.go
│ ├── usage.go
│ └── validators.go
├── channel/
│ ├── channel.go
│ ├── charge.go
│ ├── controller.go
│ ├── manager.go
│ ├── plan.go
│ ├── router.go
│ ├── sequence.go
│ ├── system.go
│ ├── ticker.go
│ ├── types.go
│ └── worker.go
├── cli/
│ ├── admin.go
│ ├── exec.go
│ ├── help.go
│ ├── invite.go
│ ├── parser.go
│ └── token.go
├── config.example.yaml
├── connection/
│ ├── cache.go
│ ├── database.go
│ ├── db_migration.go
│ └── worker.go
├── docker-compose.stable.yaml
├── docker-compose.watch.yaml
├── docker-compose.yaml
├── globals/
│ ├── constant.go
│ ├── interface.go
│ ├── logger.go
│ ├── method.go
│ ├── params.go
│ ├── sql.go
│ ├── tools.go
│ ├── types.go
│ ├── usage.go
│ └── variables.go
├── go.mod
├── go.sum
├── main.go
├── manager/
│ ├── broadcast/
│ │ ├── controller.go
│ │ ├── manage.go
│ │ ├── router.go
│ │ ├── types.go
│ │ └── view.go
│ ├── chat.go
│ ├── chat_completions.go
│ ├── completions.go
│ ├── connection.go
│ ├── conversation/
│ │ ├── api.go
│ │ ├── conversation.go
│ │ ├── mask.go
│ │ ├── router.go
│ │ ├── shared.go
│ │ └── storage.go
│ ├── images.go
│ ├── manager.go
│ ├── relay.go
│ ├── router.go
│ ├── types.go
│ ├── usage.go
│ └── videos.go
├── middleware/
│ ├── auth.go
│ ├── builtins.go
│ ├── cors.go
│ ├── middleware.go
│ └── throttle.go
├── migration/
│ ├── 3.6.sql
│ └── 3.8.sql
├── nginx.conf
├── utils/
│ ├── base.go
│ ├── bootstrap.go
│ ├── buffer.go
│ ├── cache.go
│ ├── char.go
│ ├── compress.go
│ ├── config.go
│ ├── ctx.go
│ ├── encrypt.go
│ ├── fs.go
│ ├── image.go
│ ├── net.go
│ ├── scanner.go
│ ├── smtp.go
│ ├── sse.go
│ ├── templates/
│ │ └── code.html
│ ├── tokenizer.go
│ └── websocket.go
└── zeabur.yaml
================================================
FILE CONTENTS
================================================
================================================
FILE: .dockerignore
================================================
app/node_modules
app/src-tauri
app/.idea
app/.vscode
app/dist
app/dev-dist
app/dist-ssr
app/target
app/tauri.conf.json
app/tauri.js
screenshot
.vscode
.idea
config.yaml
config.dev.yaml
# current in ~/storage
addition/generation/data/*
!addition/generation/data/.gitkeep
addition/article/data/*
!addition/article/data/.gitkeep
sdk
logs
chat
chat.exe
# for reverse engine
reverse
access.json
access/*.json
db
cache
config
README.md
.gitignore
screenshot
LICENSE
.github
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: 报告问题 | Bug Report
about: 使用简练详细的语言描述你遇到的问题 | Describe the issue you encountered in detail
title: ''
labels: bug
assignees: ''
---
[//]: # (方框内删除已有的空格,填 x 号)
+ [ ] 我已确认目前没有类似 issue
+ [ ] 我已确认我已升级到最新版本
+ [ ] 我已完整浏览项目 README 和项目文档并未找到解决方案
+ [ ] 我理解并愿意跟进此 issue,协助测试和提供反馈
+ [ ] 我将以礼貌和尊重的态度提问,不得使用不文明用语 (包括在此发布评论的所有人同样适用, 不遵守的人将被 block)
+ [ ] 我理解并认可上述内容,并理解项目维护者精力有限,**不遵循规则的 issue 可能会被无视或直接关闭**
**问题描述**
**复现步骤**
**预期结果**
**日志信息**
**相关截图 (如果有)**
================================================
FILE: .github/ISSUE_TEMPLATE/channel_update.md
================================================
---
name: 渠道更新 | Channel Update
about: 新大模型供应商格式增加、更新请求 | Request to add or update a new llm provider format
title: ''
labels: feature
assignees: ''
---
[//]: # (方框内删除已有的空格,填 x 号)
+ [ ] 我已确认目前没有类似 issue
+ [ ] 我已确认我已升级到最新版本
+ [ ] 我已完整浏览项目 README 和项目文档并未找到解决方案
+ [ ] 我理解并愿意跟进此 issue,协助测试和提供反馈
+ [ ] 我将以礼貌和尊重的态度提问,不得使用不文明用语 (包括在此发布评论的所有人同样适用, 不遵守的人将被 block)
+ [ ] 如果为新供应商格式,我已确认此供应商有一定的用户群体和知名度,借此以广告和推广类的名义的中转站点请求将被直接关闭
+ [ ] 我理解并认可上述内容,并理解项目维护者精力有限,**不遵循规则的 issue 可能会被无视或直接关闭**
**供应商名称**
**描述**
**供应商网址 / 截图 / 样例 (如果愿意提供)**
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
- name: Discord
url: https://discord.gg/rpzNSmqaF2
about: Join Discord Community
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: 功能请求 | Feature Request
about: 使用简练详细的语言描述希望加入的新功能 | Describe the feature you would like to request
title: ''
labels: feature
assignees: ''
---
[//]: # (方框内删除已有的空格,填 x 号)
+ [ ] 我已确认目前没有类似 issue
+ [ ] 我已确认我已升级到最新版本
+ [ ] 我已完整浏览项目 README 和项目文档并未找到解决方案
+ [ ] 我理解并愿意跟进此 issue,协助测试和提供反馈
+ [ ] 我将以礼貌和尊重的态度提问,不得使用不文明用语 (包括在此发布评论的所有人同样适用, 不遵守的人将被 block)
+ [ ] 我理解并认可上述内容,并理解项目维护者精力有限,**不遵循规则的 issue 可能会被无视或直接关闭**
**功能描述**
**相关截图 (如果有)**
================================================
FILE: .github/workflows/app.yaml
================================================
name: Release App
on:
workflow_dispatch:
release:
types: [published]
jobs:
create-release:
permissions:
contents: write
runs-on: ubuntu-latest
outputs:
release_id: ${{ steps.create-release.outputs.result }}
steps:
- uses: actions/checkout@v3
- name: setup node
uses: actions/setup-node@v3
with:
node-version: 16
- name: get version
run: |
cd app
echo "PACKAGE_VERSION=$(node -p "require('./src-tauri/tauri.conf.json').package.version")" >> $GITHUB_ENV
- name: create release
id: create-release
uses: actions/github-script@v6
with:
script: |
const { data } = await github.rest.repos.getLatestRelease({
owner: context.repo.owner,
repo: context.repo.repo,
})
return data.id
build-tauri:
needs: create-release
permissions:
contents: write
strategy:
fail-fast: false
matrix:
config:
- os: ubuntu-latest
arch: x86_64
rust_target: x86_64-unknown-linux-gnu
- os: macos-latest
arch: x86_64
rust_target: x86_64-apple-darwin
- os: macos-latest
arch: aarch64
rust_target: aarch64-apple-darwin
- os: windows-latest
arch: x86_64
rust_target: x86_64-pc-windows-msvc
runs-on: ${{ matrix.config.os }}
steps:
- uses: actions/checkout@v3
- name: setup node
uses: actions/setup-node@v3
with:
node-version: 16
- name: install Rust stable
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.config.rust_target }}
- uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.config.rust_target }}
- name: install dependencies (ubuntu only)
if: matrix.config.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
- name: install frontend dependencies
run: |
cd app
npm install -g pnpm
pnpm install
- uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
with:
releaseId: ${{ needs.create-release.outputs.release_id }}
projectPath: ./app
publish-release:
permissions:
contents: write
runs-on: ubuntu-latest
needs: [create-release, build-tauri]
steps:
- name: publish release
id: publish-release
uses: actions/github-script@v6
env:
release_id: ${{ needs.create-release.outputs.release_id }}
with:
script: |
github.rest.repos.updateRelease({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: process.env.release_id,
draft: false,
prerelease: false
})
================================================
FILE: .github/workflows/build.yaml
================================================
name: Build Test
on:
push:
branches:
- '*'
pull_request:
branches:
- '*'
jobs:
release:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [ 18.x ]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Use Golang
uses: actions/setup-go@v4
with:
go-version: '1.20'
- name: Build Backend
run: |
go build .
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: Build Frontend
run: |
cd app
npm install -g pnpm
pnpm install
pnpm build
- name: Upload a Build Artifact
uses: actions/upload-artifact@v4.0.0
with:
name: Build result
path: app/dist
================================================
FILE: .github/workflows/docker-cd.yaml
================================================
name: Docker CD
on:
release:
types: [created]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Build and push Docker images
uses: docker/build-push-action@v2
with:
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: programzmh/chatnio:stable
================================================
FILE: .github/workflows/docker-ci.yaml
================================================
name: Docker Image CI
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
with:
platforms: "arm64,amd64"
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Get version
run: echo "VERSION=$(node -p "require('./app/src/conf/version.json').version")" >> $GITHUB_ENV
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Build and push Docker images
uses: docker/build-push-action@v3
with:
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: |
programzmh/chatnio:latest
programzmh/chatnio:${{ env.VERSION }}
cache-from: |
type=registry,ref=programzmh/chatnio:buildcache
type=gha
cache-to: |
type=registry,ref=programzmh/chatnio:buildcache,mode=max
type=gha,mode=max
================================================
FILE: .github/workflows/issue-translator.yaml
================================================
name: Issue Translator
on:
issue_comment:
types: [created]
issues:
types: [opened]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: usthe/issues-translate-action@v2.7
with:
IS_MODIFY_TITLE: false
CUSTOM_BOT_NOTE: Bot detected the issue body's language is not English, translate it automatically.
================================================
FILE: .gitignore
================================================
app/node_modules
.vscode
.idea
config.yaml
config.dev.yaml
storage
addition/generation/data/*
!addition/generation/data/.gitkeep
addition/article/data/*
!addition/article/data/.gitkeep
sdk
logs
chat
*.exe
chat.exe
# for reverse engine
reverse
access.json
access/*.json
db
redis
config
presets
key/*
!key/.gitkeep
# for https://github.com/di-sukharev/opencommit
.env
================================================
FILE: Dockerfile
================================================
# Author: ProgramZmh
# License: Apache-2.0
# Description: Dockerfile for chatnio
FROM --platform=$TARGETPLATFORM golang:1.20-alpine AS backend
WORKDIR /backend
COPY . .
# Set go proxy to https://goproxy.cn (open for vps in China Mainland)
# RUN go env -w GOPROXY=https://goproxy.cn,direct
ARG TARGETARCH
ARG TARGETOS
ENV GOOS=$TARGETOS GOARCH=$TARGETARCH GO111MODULE=on CGO_ENABLED=1
# Install build dependencies
RUN apk update && \
apk add --no-cache \
gcc \
musl-dev \
g++ \
make \
linux-headers
# Build backend
RUN go build -o chat -a -ldflags="-extldflags=-static" .
FROM node:18 AS frontend
WORKDIR /app
COPY ./app .
RUN npm install -g pnpm && \
pnpm install && \
pnpm run build && \
rm -rf node_modules src
FROM alpine
# Install dependencies
RUN apk upgrade --no-cache && \
apk add --no-cache wget ca-certificates tzdata && \
update-ca-certificates 2>/dev/null || true
# Set timezone
RUN echo "Asia/Shanghai" > /etc/timezone && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
WORKDIR /
# Copy dist
COPY --from=backend /backend/chat /chat
COPY --from=backend /backend/config.example.yaml /config.example.yaml
COPY --from=backend /backend/utils/templates /utils/templates
COPY --from=backend /backend/addition/article/template.docx /addition/article/template.docx
COPY --from=frontend /app/dist /app/dist
# Volumes
VOLUME ["/config", "/logs", "/storage"]
# Expose port
EXPOSE 8094
# Run application
CMD ["./chat"]
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
<div align="center">

# [🥳 CoAI.Dev](https://coai.dev)
#### 🚀 Next Generation AIGC One-Stop Business Solution
#### *"CoAI.Dev > [Next Web](https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web) + [One API](https://github.com/songquanpeng/one-api)"*
English · [简体中文](./README_zh-CN.md) · [日本語](./README_ja-JP.md) · [Docs](https://coai.dev) · [Discord](https://discord.gg/rpzNSmqaF2) · [Deployment Guide](https://coai.dev/docs/deploy)
[](https://trendshift.io/repositories/6369)
<img alt="CoAI.Dev Preview" src="./screenshot/coai.png" width="100%" style="border-radius: 8px">
</div>
## 📝 Features
1. 🤖️ **Rich Model Support**: Multi-model service provider support (OpenAI / Anthropic / Gemini / Midjourney and more than ten compatible formats & private LLM support)
2. 🤯 **Beautiful UI Design**: UI compatible with PC / Pad / Mobile, following [Shadcn UI](https://ui.shadcn.com) & [Tremor Charts](https://blocks.tremor.so) design standards, rich and beautiful interface design and backend dashboard
3. 🎃 **Complete Markdown Support**: Support for **LaTeX formulas** / **Mermaid mind maps** / table rendering / code highlighting / chart drawing / progress bars and other advanced Markdown syntax support
4. 👀 **Multi-theme Support**: Support for multiple theme switching, including **Light Mode** for light themes and **Dark Mode** for dark themes. 👉 [Custom Color Scheme](https://github.com/coaidev/coai/blob/main/app/src/assets/globals.less)
5. 📚 **Internationalization Support**: Support for internationalization, multi-language switching 🇨🇳 🇺🇸 🇯🇵 🇷🇺 👉 Welcome to contribute translations [Pull Request](https://github.com/coaidev/coai/pulls)
6. 🎨 **Text-to-Image Support**: Support for multiple text-to-image models: **OpenAI DALL-E**✅ & **Midjourney** (support for **U/V/R** operations)✅ & Stable Diffusion✅ etc.
7. 📡 **Powerful Conversation Sync**: **Zero-cost cross-device conversation sync support for users**, support for **conversation sharing** (link sharing & save as image & share management), **no need for WebDav / WebRTC and other dependencies and complex learning costs**
8. 🎈 **Model Market & Preset System**: Support for customizable model market in the backend, providing model introductions, tags, and other parameters. Site owners can customize model introductions according to the situation. Also supports a preset system, including **custom presets** and **cloud synchronization** functions.
9. 📖 **Rich File Parsing**: **Out-of-the-box**, supports file parsing for **all models** (PDF / Docx / Pptx / Excel / image formats parsing), **supports more cloud image storage solutions** (S3 / R2 / MinIO etc.), **supports OCR image recognition** 👉 See project [CoAI.Dev Blob Service](https://github.com/coaidev/blob-service) for details (supports Vercel / Docker one-click deployment)
10. 🌏 **Full Model Internet Search**: Based on the [SearXNG](https://github.com/searxng/searxng) open-source engine, supports rich search engines such as Google / Bing / DuckDuckGo / Yahoo / Wikipedia / Arxiv / Qwant, supports safe search mode, content truncation, image proxy, test search availability, and other functions.
11. 💕 **Progressive Web App (PWA)**: Supports PWA applications & desktop support (desktop based on [Tauri](https://github.com/tauri-apps/tauri))
12. 🤩 **Comprehensive Backend Management**: Supports beautiful and rich dashboard, announcement & notification management, user management, subscription management, gift code & redemption code management, price setting, subscription setting, custom model market, custom site name & logo, SMTP email settings, and other functions
13. 🤑 **Multiple Billing Methods**: Supports 💴 **Subscription** and 💴 **Elastic Billing** two billing methods. Elastic billing supports per-request billing / token billing / no billing / anonymous calls and **minimum request points** detection and other powerful features
14. 🎉 **Innovative Model Caching**: Supports enabling model caching: i.e., under the same request parameter hash, if it has been requested before, it will directly return the cached result (hitting the cache will not be billed), reducing the number of requests. You can customize whether to cache models, cache time, multiple cache result numbers, and other advanced cache settings
15. 🥪 **Additional Features** (Support Discontinued): 🍎 **AI Project Generator Function** / 📂 **Batch Article Generation Function** / 🥪 **AI Card Function** (Deprecated)
16. 😎 **Excellent Channel Management**: Self-written excellent channel algorithm, supports ⚡ **multi-channel management**, supports 🥳**priority** setting for channel call order, supports 🥳**weight** setting for load balancing probability distribution of channels at the same priority, supports 🥳**user grouping**, 🥳**automatic retry on failure**, 🥳**model redirection**, 🥳**built-in upstream hiding**, 🥳**channel status management** and other powerful **enterprise-level functions**
17. ⭐ **OpenAI API Distribution & Proxy System**: Supports calling various large models in **OpenAI API** standard format, integrates powerful channel management functions, only needs to deploy one site to achieve simultaneous development of B/C-end business💖
18. 👌 **Quick Upstream Synchronization**: Channel settings, model market, price settings, and other settings can quickly synchronize with upstream sites, modify your site configuration based on this, quickly build your site, save time and effort, one-click synchronization, quick launch
19. 👋 **SEO Optimization**: Supports SEO optimization, supports custom site name, site logo, and other SEO optimization settings to make search engines crawl faster, making your site stand out👋
20. 🎫 **Multiple Redemption Code Systems**: Supports multiple redemption code systems, supports gift codes and redemption codes, supports batch generation, gift codes are suitable for promotional distribution, redemption codes are suitable for card sales, for gift codes of one type, a user can only redeem one code, which to some extent reduces the situation of one user redeeming multiple times in promotions😀
21. 🥰 **Business-Friendly License**: Adopts the **Apache-2.0** open-source license, friendly for commercial secondary development & distribution (please also comply with the provisions of the Apache-2.0 license, do not use for illegal purposes)
> ### ✨ CoAI.Dev Business
>
> 
>
> - ✅ Beautiful commercial-grade UI, elegant frontend interface and backend management
> - ✅ Supports TTS & STT, plugin marketplace, RAG knowledge base and other rich features and modules
> - ✅ More payment providers, more billing models and advanced order management
> - ✅ Supports more authentication methods, including SMS login, OAuth login, etc.
> - ✅ Supports model monitoring, channel health detection, fault alarm automatic channel switching
> - ✅ Supports multi-tenant API Key distribution system, enterprise-level token permission management and visitor restrictions
> - ✅ Supports security auditing, logging, model rate limiting, API Gateway and other advanced features
> - ✅ Supports promotion rewards, professional data statistics, user profile analysis and other business analysis capabilities
> - ✅ Supports Discord/Telegram/Feishu and other bot integration capabilities (extension modules)
> - ...
>
> [👉 Learn More](https://www.coai.dev/docs/contact)
## 🔨 Supported Models
1. OpenAI & Azure OpenAI *(✅ Vision ✅ Function Calling)*
2. Anthropic Claude *(✅ Vision ✅ Function Calling)*
3. Google Gemini & PaLM2 *(✅ Vision)*
4. Midjourney *(✅ Mode Toggling ✅ U/V/R Actions)*
5. iFlytek SparkDesk *(✅ Vision ✅ Function Calling)*
6. Zhipu AI ChatGLM *(✅ Vision)*
7. Alibaba Tongyi Qwen
8. Tencent Hunyuan
9. Baichuan AI
10. Moonshot AI (👉 OpenAI)
11. DeepSeek AI (👉 OpenAI)
12. ByteDance Skylark *(✅ Function Calling)*
13. Groq Cloud AI
14. OpenRouter (👉 OpenAI)
15. 360 GPT
16. LocalAI / Ollama (👉 OpenAI)
## 👻 OpenAI Compatible API Proxy
- [x] Chat Completions _(/v1/chat/completions)_
- [x] Image Generation _(/v1/images)_
- [x] Model List _(/v1/models)_
- [x] Dashboard Billing _(/v1/billing)_
## 📦 Deployment
> [!TIP]
> **After successful deployment, the admin account is `root`, with the default password `chatnio123456`**
### ✨ Zeabur (One-Click)
[](https://zeabur.com/templates/M86XJI)
> Zeabur provides a certain free quota, you can use non-paid regions for one-click deployment, and also supports plan subscriptions and elastic billing for flexible expansion.
> 1. Click `Deploy` to deploy, and enter the domain name you wish to bind, wait for the deployment to complete.
> 2. After deployment is complete, please visit your domain name and log in to the backend management using the username `root` and password `chatnio123456`. Please follow the prompts to change the password in the chatnio backend in a timely manner.
### 🐳 BTPanel (One-Click)
1. Install Baota Panel by visiting [BTPanel](https://www.bt.cn/new/download.html) and install using the stable version script.
2. Log in to the panel and click **Docker** on the left to enter Docker management.
3. If prompted that Docker / Docker Compose is not installed, you can install according to the guide above.
4. After installation is complete, enter **App Store**, search for `CoAI` and click **Install**.
5. Configure basic application information such as your domain name, port, etc., and click **Confirm** (default configuration can be used).
6. First-time installation may take 1-2 minutes to complete database initialization. If you encounter issues, please check the panel running logs for troubleshooting.
7. Visit your configured domain or server `http://[ip]:[port]`, log in to the backend management using username `root` and password `chatnio123456`.
### AlibabaCloud ComputeNest (One-Click)
[](https://computenest.console.aliyun.com/service/instance/create/ap-southeast-1?type=user&ServiceName=CoAI%20%20Community%20Edition)
1. Access the CoAI service on [ComputeNest International Edition](https://computenest.console.aliyun.com/service/instance/create/ap-southeast-1?type=user&ServiceName=CoAI%20%20Community%20Edition). If you are in China, please visit [ComputeNest](https://computenest.console.aliyun.com/service/instance/create/default?type=user&ServiceName=CoAI社区版), and fill in the deployment parameters as prompted.
2. Select the payment type, fill in the instance parameters and network parameters, and click **Next: Confirm Order**.
3. After confirming the deployment parameters and checking the estimated price, click Create Now and wait for the service instance to be deployed.
4. Click **Service Instance** on the left. After the service instance is deployed, click the instance ID to enter the details interface.
5. Click the address in **Use Now** on the details interface to enter the CoAI interface. The default username is `root` and the password is `chatnio123456` to log in to the backend management.
6. For more operation details and payment information, see:[Service Details](https://computenest.console.aliyun.com/service/detail/ap-southeast-1/service-27e11d3a5c9b40628505/1?type=user&isRecommend=true).
### ⚡ Docker Compose Installation (Recommended)
> [!NOTE]
> After successful execution, the host machine mapping address is `http://localhost:8000`
```shell
git clone --depth=1 --branch=main --single-branch https://github.com/coaidev/coai.git
cd chatnio
docker-compose up -d # Run the service
# To use the stable version, use docker-compose -f docker-compose.stable.yaml up -d instead
# To use Watchtower for automatic updates, use docker-compose -f docker-compose.watch.yaml up -d instead
```
Version update (_If Watchtower automatic updates are enabled, manual updates are not necessary_):
```shell
docker-compose down
docker-compose pull
docker-compose up -d
```
> - MySQL database mount directory: ~/**db**
> - Redis database mount directory: ~/**redis**
> - Configuration file mount directory: ~/**config**
### ⚡ Docker Installation (Lightweight runtime, commonly used for external _MYSQL/RDS_ services)
> [!NOTE]
> After successful execution, the host machine address is `http://localhost:8094`.
>
> To use the stable version, use `programzmh/chatnio:stable` instead of `programzmh/chatnio:latest`
```shell
docker run -d --name chatnio \
--network host \
-v ~/config:/config \
-v ~/logs:/logs \
-v ~/storage:/storage \
-e MYSQL_HOST=localhost \
-e MYSQL_PORT=3306 \
-e MYSQL_DB=chatnio \
-e MYSQL_USER=root \
-e MYSQL_PASSWORD=chatnio123456 \
-e REDIS_HOST=localhost \
-e REDIS_PORT=6379 \
-e SECRET=secret \
-e SERVE_STATIC=true \
programzmh/chatnio:latest
```
> - *--network host* means using the host machine's network, allowing the Docker container to use the host's network. You can modify this as needed.
> - SECRET: JWT secret key, generate a random string and modify accordingly
> - SERVE_STATIC: Whether to enable static file serving (normally this doesn't need to be changed, see FAQ below for details)
> - *-v ~/config:/config* mounts the configuration file, *-v ~/logs:/logs* mounts the host machine directory for log files, *-v ~/storage:/storage* mounts the directory for additional feature generated files
> - MySQL and Redis services need to be configured. Please refer to the information above to modify the environment variables accordingly
Version update (_After enabling Watchtower, manual updates are not necessary. After execution, follow the steps above to run again_):
```shell
docker stop chatnio
docker rm chatnio
docker pull programzmh/chatnio:latest
```
### ⚒ Compile and Install
> [!NOTE]
> After successful deployment, the default port is **8094**, and the access address is `http://localhost:8094`
>
> Config settings (~/config/**config.yaml**) can be overridden using environment variables. For example, the `MYSQL_HOST` environment variable can override the `mysql.host` configuration item
```shell
git clone https://github.com/coaidev/coai.git
cd chatnio
cd app
npm install -g pnpm
pnpm install
pnpm build
cd ..
go build -o chatnio
# e.g. using nohup (you can also use systemd or other service manager)
nohup ./chatnio > output.log & # using nohup to run in background
```
## 📦 Tech Stack
- 🥗 Frontend: React + Redux + Radix UI + Tailwind CSS
- 🍎 Backend: Golang + Gin + Redis + MySQL
- 🍒 Application Technology: PWA + WebSocket
## 🤯 Why Create This Project & Project Advantages
- We found that most AIGC commercial sites on the market are frontend-oriented lightweight deployment projects with beautiful UI interface designs, such as the commercial version of [Next Chat](https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web). Due to its personal privatization-oriented design, there are some limitations in secondary commercial development, presenting some issues, such as:
1. **Difficult conversation synchronization**, for example, requiring services like WebDav, high user learning costs, and difficulties in real-time cross-device synchronization.
2. **Insufficient billing**, for example, only supporting elastic billing or only subscription-based, unable to meet the needs of different users.
3. **Inconvenient file parsing**, for example, only supporting uploading images to an image hosting service first, then returning to the site to input the URL direct link in the input box, without built-in file parsing functionality.
4. **No support for conversation URL sharing**, for example, only supporting conversation screenshot sharing, unable to support conversation URL sharing (or only supporting tools like ShareGPT, which cannot promote the site).
5. **Insufficient channel management**, for example, the backend only supports OpenAI format channels, making it difficult to be compatible with other format channels. And only one channel can be filled in, unable to support multi-channel management.
6. **No API call support**, for example, only supporting user interface calls, unable to support API proxying and management.
- Another type is API distribution-oriented sites with powerful distribution systems, such as projects based on [One API](https://github.com/songquanpeng/one-api).
Although these projects support powerful API proxying and management, they lack interface design and some C-end features, such as:
1. **Insufficient user interface**, for example, only supporting API calls, without built-in user interface chat. User interface chat requires manually copying the key and going to other sites to use, which has a high learning cost for ordinary users.
2. **No subscription system**, for example, only supporting elastic billing, lacking billing design for C-end users, unable to meet different user needs, and not user-friendly in terms of cost perception for users without a foundation.
3. **Insufficient C-end features**, for example, only supporting API calls, not supporting conversation synchronization, conversation sharing, file parsing, and other functions.
4. **Insufficient load balancing**, the open-source version does not support the **weight** parameter, unable to achieve balanced load distribution probability for channels at the same priority ([New API](https://github.com/Calcium-Ion/new-api) also solves this pain point, with a more beautiful UI).
Therefore, we hope to combine the advantages of these two types of projects to create a project that has both a powerful API distribution system and a rich user interface design,
thus meeting the needs of C-end users while developing B-end business, improving user experience, reducing user learning costs, and increasing user stickiness.
Thus, **CoAI.Dev** was born. We hope to create a project that has both a powerful API distribution system and a rich user interface design, becoming the next-generation open-source AIGC project's one-stop commercial solution.
## ❤ Donations
If you find this project helpful, you can give it a Star to show your support!
================================================
FILE: README_ja-JP.md
================================================
<div align="center">

# [🥳 CoAI.Dev](https://coai.dev)
#### 🚀 次世代AIGCワンストップビジネスソリューション
#### *"CoAI.Dev > [Next Web](https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web) + [One API](https://github.com/songquanpeng/one-api)"*
English · [简体中文](./README_zh-CN.md) · [日本語](./README_ja-JP.md) · [ドキュメント](https://coai.dev) · [Discord](https://discord.gg/rpzNSmqaF2) · [デプロイガイド](https://coai.dev/docs/deploy)
[](https://trendshift.io/repositories/6369)
<img alt="CoAI.Dev Preview" src="./screenshot/coai.png" width="100%" style="border-radius: 8px">
</div>
## 📝 機能
1. 🤖️ **豊富なモデルサポート**: 複数のモデルサービスプロバイダーのサポート (OpenAI / Anthropic / Gemini / Midjourney など十数種類の互換フォーマット & プライベートLLMサポート)
2. 🤯 **美しいUIデザイン**: PC / Pad / モバイルに対応したUI、[Shadcn UI](https://ui.shadcn.com) & [Tremor Charts](https://blocks.tremor.so) のデザイン基準に従った豊富で美しいインターフェースデザインとバックエンドダッシュボード
3. 🎃 **完全なMarkdownサポート**: **LaTeX数式** / **Mermaidマインドマップ** / テーブルレンダリング / コードハイライト / チャート描画 / プログレスバーなどの高度なMarkdown構文サポート
4. 👀 **マルチテーマサポート**: 複数のテーマ切り替えをサポート、ライトテーマの**ライトモード**とダークテーマの**ダークモード**を含む。 👉 [カスタムカラースキーム](https://github.com/coaidev/coai/blob/main/app/src/assets/globals.less)
5. 📚 **国際化サポート**: 国際化をサポートし、複数の言語切り替えをサポート 🇨🇳 🇺🇸 🇯🇵 🇷🇺 👉 翻訳の貢献を歓迎します [Pull Request](https://github.com/coaidev/coai/pulls)
6. 🎨 **テキストから画像へのサポート**: 複数のテキストから画像へのモデルをサポート: **OpenAI DALL-E**✅ & **Midjourney** ( **U/V/R** 操作をサポート)✅ & Stable Diffusion✅ など
7. 📡 **強力な会話同期**: **ユーザーのゼロコストクロスデバイス会話同期サポート**、**会話共有** (リンク共有 & 画像として保存 & 共有管理) をサポート、**WebDav / WebRTCなどの依存関係や複雑な学習コストは不要**
8. 🎈 **モデル市場 & プリセットシステム**: バックエンドでカスタマイズ可能なモデル市場をサポートし、モデルの紹介、タグなどのパラメータを提供。サイトオーナーは状況に応じてモデルの紹介をカスタマイズできます。また、**カスタムプリセット**と**クラウド同期**機能を含むプリセットシステムもサポート。
9. 📖 **豊富なファイル解析**: **すぐに使える**、**すべてのモデル**のファイル解析をサポート (PDF / Docx / Pptx / Excel / 画像形式の解析)、**より多くのクラウド画像ストレージソリューション** (S3 / R2 / MinIO など) をサポート、**OCR画像認識**をサポート 👉 詳細はプロジェクト [CoAI.Dev Blob Service](https://github.com/coaidev/blob-service) を参照 (Vercel / Dockerのワンクリックデプロイをサポート)
10. 🌏 **全モデルインターネット検索**: [SearXNG](https://github.com/searxng/searxng) オープンソースエンジンに基づき、Google / Bing / DuckDuckGo / Yahoo / Wikipedia / Arxiv / Qwant などの豊富な検索エンジン検索をサポート、安全検索モード、コンテンツ切り捨て、画像プロキシ、検索可用性テストなどの機能をサポート。
11. 💕 **プログレッシブウェブアプリ (PWA)**: PWAアプリケーションをサポートし、デスクトップサポート (デスクトップは [Tauri](https://github.com/tauri-apps/tauri) に基づく)
12. 🤩 **包括的なバックエンド管理**: 美しく豊富なダッシュボード、公告 & 通知管理、ユーザー管理、サブスクリプション管理、ギフトコード & 交換コード管理、価格設定、サブスクリプション設定、カスタムモデル市場、カスタムサイト名 & ロゴ、SMTPメール設定などの機能をサポート
13. 🤑 **複数の課金方法**: 💴 **サブスクリプション** と 💴 **エラスティック課金** の2つの課金方法をサポート。エラスティック課金は、リクエストごとの課金 / トークン課金 / 無課金 / 匿名通話をサポートし、**最小リクエストポイント** 検出などの強力な機能をサポート
14. 🎉 **革新的なモデルキャッシュ**: モデルキャッシュの有効化をサポート: 同じリクエストパラメータハッシュの下で、以前にリクエストされた場合、キャッシュ結果を直接返します (キャッシュヒットは課金されません)、リクエスト回数を減らします。キャッシュするモデル、キャッシュ時間、複数のキャッシュ結果数などの高度なキャッシュ設定をカスタマイズできます
15. 🥪 **追加機能** (サポート終了): 🍎 **AIプロジェクトジェネレーター機能** / 📂 **バッチ記事生成機能** / 🥪 **AIカード機能** (廃止)
16. 😎 **優れたチャネル管理**: 自作の優れたチャネルアルゴリズム、⚡ **マルチチャネル管理** をサポート、チャネル呼び出し順序の設定をサポート、同じ優先度のチャネルの負荷分散確率の設定をサポート、**ユーザーグループ化**、**失敗時の自動再試行**、**モデルリダイレクト**、**組み込みの上流非表示**、**チャネル状態管理** などの強力な**企業レベルの機能**をサポート
17. ⭐ **OpenAI API分散 & プロキシシステム**: **OpenAI API** 標準フォーマットでさまざまな大規模モデルを呼び出すことをサポートし、強力なチャネル管理機能を統合。1つのサイトをデプロイするだけで、B/Cエンドビジネスの同時開発を実現💖
18. 👌 **迅速な上流同期**: チャネル設定、モデル市場、価格設定などの設定を迅速に上流サイトと同期し、これに基づいてサイト設定を変更し、迅速にサイトを構築し、時間と労力を節約し、ワンクリック同期、迅速なオンライン化を実現
19. 👋 **SEO最適化**: SEO最適化をサポートし、カスタムサイト名、サイトロゴなどのSEO最適化設定をサポートし、検索エンジンがより速くクロールできるようにし、サイトを際立たせます👋
20. 🎫 **複数の交換コードシステム**: 複数の交換コードシステムをサポートし、ギフトコードと交換コードをサポートし、バッチ生成をサポート。ギフトコードはプロモーション配布に適しており、交換コードはカード販売に適しています。ギフトコードの1つのタイプの複数のコードは、1人のユーザーが1つのコードしか交換できないため、プロモーション中に1人のユーザーが複数回交換する状況をある程度減らします😀
21. 🥰 **ビジネスフレンドリーなライセンス**: **Apache-2.0** オープンソースライセンスを採用し、商用の二次開発 & 配布にフレンドリー (Apache-2.0ライセンスの規定を遵守し、違法な目的で使用しないでください)
> ### ✨ CoAI.Dev ビジネス版
>
> 
>
> - ✅ 美しい商用グレードのUI、エレガントなフロントエンドインターフェースとバックエンド管理
> - ✅ TTS & STT、プラグインマーケットプレイス、RAGナレッジベースなどの豊富な機能とモジュールをサポート
> - ✅ より多くの支払いプロバイダー、より多くの課金モデルと高度な注文管理をサポート
> - ✅ SMSログイン、OAuthログインなど、より多くの認証方法をサポート
> - ✅ モデル監視、チャネルの健康状態検出、障害アラーム自動チャネル切り替えをサポート
> - ✅ マルチテナントAPIキー配布システム、企業レベルのトークン権限管理と訪問者制限をサポート
> - ✅ セキュリティ監査、ログ記録、モデルレート制限、APIゲートウェイなどの高度な機能をサポート
> - ✅ プロモーション報酬、プロフェッショナルなデータ統計、ユーザープロファイル分析などのビジネス分析能力をサポート
> - ✅ Discord/Telegram/Feishuなどのボット統合機能をサポート (拡張モジュール)
> - ...
>
> [👉 詳細はこちら](https://www.coai.dev/docs/contact)
## 🔨 サポートされているモデル
1. OpenAI & Azure OpenAI *(✅ Vision ✅ Function Calling)*
2. Anthropic Claude *(✅ Vision ✅ Function Calling)*
3. Google Gemini & PaLM2 *(✅ Vision)*
4. Midjourney *(✅ Mode Toggling ✅ U/V/R Actions)*
5. iFlytek SparkDesk *(✅ Vision ✅ Function Calling)*
6. Zhipu AI ChatGLM *(✅ Vision)*
7. Alibaba Tongyi Qwen
8. Tencent Hunyuan
9. Baichuan AI
10. Moonshot AI (👉 OpenAI)
11. DeepSeek AI (👉 OpenAI)
12. ByteDance Skylark *(✅ Function Calling)*
13. Groq Cloud AI
14. OpenRouter (👉 OpenAI)
15. 360 GPT
16. LocalAI / Ollama (👉 OpenAI)
## 👻 OpenAI互換APIプロキシ
- [x] Chat Completions _(/v1/chat/completions)_
- [x] Image Generation _(/v1/images)_
- [x] Model List _(/v1/models)_
- [x] Dashboard Billing _(/v1/billing)_
## 📦 デプロイ
> [!TIP]
> **デプロイが成功した後、管理者アカウントは `root` で、デフォルトのパスワードは `chatnio123456` です**
### ✨ Zeabur (ワンクリック)
[](https://zeabur.com/templates/M86XJI)
> Zeaburは一定の無料クォータを提供しており、非有料地域でのワンクリックデプロイをサポートし、プランサブスクリプションとエラスティック課金による柔軟な拡張もサポートしています。
> 1. `Deploy` をクリックしてデプロイし、バインドしたいドメイン名を入力し、デプロイが完了するのを待ちます。
> 2. デプロイが完了したら、ドメイン名にアクセスし、ユーザー名 `root` とパスワード `chatnio123456` を使用してバックエンド管理にログインします。チャットニオのバックエンドでパスワードを変更するように指示に従ってください。
### ⚡ Docker Composeインストール (推奨)
> [!NOTE]
> 実行が成功した後、ホストマシンのマッピングアドレスは `http://localhost:8000` です
```shell
git clone --depth=1 --branch=main --single-branch https://github.com/coaidev/coai.git
cd chatnio
docker-compose up -d # サービスを実行
# 安定版を使用するには、docker-compose -f docker-compose.stable.yaml up -d を使用してください
# Watchtowerを使用して自動更新するには、docker-compose -f docker-compose.watch.yaml up -d を使用してください
```
バージョン更新 (_Watchtower自動更新が有効な場合、手動更新は不要です_):
```shell
docker-compose down
docker-compose pull
docker-compose up -d
```
> - MySQLデータベースマウントディレクトリ: ~/**db**
> - Redisデータベースマウントディレクトリ: ~/**redis**
> - 設定ファイルマウントディレクトリ: ~/**config**
### ⚡ Dockerインストール (軽量ランタイム、外部 _MYSQL/RDS_ サービスでよく使用されます)
> [!NOTE]
> 実行が成功した後、ホストマシンのアドレスは `http://localhost:8094` です。
>
> 安定版を使用するには、`programzmh/chatnio:stable` を `programzmh/chatnio:latest` の代わりに使用してください
```shell
docker run -d --name chatnio \
--network host \
-v ~/config:/config \
-v ~/logs:/logs \
-v ~/storage:/storage \
-e MYSQL_HOST=localhost \
-e MYSQL_PORT=3306 \
-e MYSQL_DB=chatnio \
-e MYSQL_USER=root \
-e MYSQL_PASSWORD=chatnio123456 \
-e REDIS_HOST=localhost \
-e REDIS_PORT=6379 \
-e SECRET=secret \
-e SERVE_STATIC=true \
programzmh/chatnio:latest
```
> - *--network host* はホストマシンのネットワークを使用することを意味し、Dockerコンテナがホストのネットワークを使用できるようにします。必要に応じて変更できます。
> - SECRET: JWTシークレットキー、ランダムな文字列を生成して適宜変更
> - SERVE_STATIC: 静的ファイルの提供を有効にするかどうか (通常、これを変更する必要はありません。詳細はFAQを参照)
> - *-v ~/config:/config* は設定ファイルをマウントし、*-v ~/logs:/logs* はログファイルのホストマシンディレクトリをマウントし、*-v ~/storage:/storage* は追加機能の生成ファイルのディレクトリをマウント
> - MySQLとRedisサービスを設定する必要があります。上記の情報を参照して環境変数を適宜変更してください
バージョン更新 (_Watchtowerを有効にした後、手動更新は不要です。実行後、上記の手順に従って再度実行してください_):
```shell
docker stop chatnio
docker rm chatnio
docker pull programzmh/chatnio:latest
```
### ⚒ コンパイルとインストール
> [!NOTE]
> デプロイが成功した後、デフォルトのポートは **8094** で、アクセスアドレスは `http://localhost:8094` です
>
> 設定項目 (~/config/**config.yaml**) は環境変数を使用して上書きできます。例えば、`MYSQL_HOST` 環境変数は `mysql.host` 設定項目を上書きできます
```shell
git clone https://github.com/coaidev/coai.git
cd chatnio
cd app
npm install -g pnpm
pnpm install
pnpm build
cd ..
go build -o chatnio
# 例: nohupを使用 (systemdや他のサービスマネージャーも使用できます)
nohup ./chatnio > output.log & # バックグラウンドで実行するためにnohupを使用
```
## 📦 技術スタック
- 🥗 フロントエンド: React + Redux + Radix UI + Tailwind CSS
- 🍎 バックエンド: Golang + Gin + Redis + MySQL
- 🍒 アプリケーション技術: PWA + WebSocket
## 🤯 なぜこのプロジェクトを作成したのか & プロジェクトの利点
- 市場にあるほとんどのAIGC商用サイトは、[Next Chat](https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web) の商用版のように、美しいUIインターフェースデザインを持つフロントエンド指向の軽量デプロイプロジェクトです。個人のプライベート化指向の設計のため、二次商用開発にはいくつかの制限があり、いくつかの問題が発生します。例えば:
1. **会話の同期が難しい**: 例えば、WebDavなどのサービスが必要で、ユーザーの学習コストが高く、クロスデバイスのリアルタイム同期が困難です。
2. **課金が不十分**: 例えば、エラスティック課金のみをサポートするか、サブスクリプションのみをサポートし、異なるユーザーのニーズを満たすことができません。
3. **ファイル解析が不便**: 例えば、最初に画像ホスティングサービスに画像をアップロードし、サイトに戻って入力ボックスにURL直リンクを入力する必要があり、組み込みのファイル解析機能がありません。
4. **会話URL共有のサポートがない**: 例えば、会話のスクリーンショット共有のみをサポートし、会話URL共有をサポートしません (またはShareGPTなどのツールのみをサポートし、サイトのプロモーションには役立ちません)。
5. **チャネル管理が不十分**: 例えば、バックエンドはOpenAIフォーマットのチャネルのみをサポートし、他のフォーマットのチャネルとの互換性が難しいです。そして、1つのチャネルしか入力できず、マルチチャネル管理をサポートしません。
6. **API呼び出しのサポートがない**: 例えば、ユーザーインターフェース呼び出しのみをサポートし、APIプロキシと管理をサポートしません。
- もう1つのタイプは、[One API](https://github.com/songquanpeng/one-api) に基づくプロジェクトのように、強力な分散システムを持つAPI分散指向のサイトです。
これらのプロジェクトは強力なAPIプロキシと管理をサポートしていますが、インターフェースデザインといくつかのCエンド機能が不足しています。例えば:
1. **ユーザーインターフェースが不十分**: 例えば、API呼び出しのみをサポートし、組み込みのユーザーインターフェースチャットがありません。ユーザーインターフェースチャットは、手動でキーをコピーして他のサイトに行って使用する必要があり、普通のユーザーにとって学習コストが高いです。
2. **サブスクリプションシステムがない**: 例えば、エラスティック課金のみをサポートし、Cエンドユーザーの課金設計が不足しており、異なるユーザーのニーズを満たすことができず、基礎のないユーザーにとってコスト感知がフレンドリーではありません。
3. **Cエンド機能が不十分**: 例えば、API呼び出しのみをサポートし、会話同期、会話共有、ファイル解析などの機能をサポートしません。
4. **負荷分散が不十分**: オープンソース版は**重み**パラメータをサポートしておらず、同じ優先度のチャネルの負荷分散確率を実現できません ([New API](https://github.com/Calcium-Ion/new-api) もこの痛点を解決し、UIもより美しいです)。
したがって、これら2つのタイプのプロジェクトの利点を組み合わせて、強力なAPI分散システムと豊富なユーザーインターフェースデザインを持つプロジェクトを作成し、
Cエンドユーザーのニーズを満たしながらBエンドビジネスを開発し、ユーザーエクスペリエンスを向上させ、ユーザーの学習コストを削減し、ユーザーの粘着性を高めることを目指しています。
そのため、**CoAI.Dev** が誕生しました。強力なAPI分散システムと豊富なユーザーインターフェースデザインを持つプロジェクトを作成し、次世代のオープンソースAIGCプロジェクトのワンストップ商用ソリューションになることを目指しています。
## ❤ 寄付
このプロジェクトが役立つと思われる場合は、Starをクリックしてサポートを示すことができます!
================================================
FILE: README_zh-CN.md
================================================
<div align="center">

# [🥳 CoAI.Dev](https://coai.dev)
#### 🚀 下一代 AIGC 一站式商业解决方案
#### *“ CoAI.Dev > [Next Web](https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web) + [One API](https://github.com/songquanpeng/one-api) ”*
[English](./README.md) · 简体中文 · [文档](https://coai.dev) · [Discord](https://discord.gg/rpzNSmqaF2) · [部署文档](https://coai.dev/docs/deploy)
[](https://trendshift.io/repositories/6369)
<img alt="CoAI.Dev Preview" src="./screenshot/coai.png" width="100%" style="border-radius: 8px">
</div>
## 📝 功能
1. 🤖️ **丰富模型支持**: 多模型服务商支持 (OpenAI / Anthropic / Gemini / Midjourney 等十余种格式兼容 & 私有化 LLM 支持)
2. 🤯 **美观 UI 设计**: UI 兼容 PC / Pad / 移动三端,遵循 [Shadcn UI](https://ui.shadcn.com) & [Tremor Charts](https://blocks.tremor.so) 设计规范,丰富美观的界面设计和后台仪表盘
3. 🎃 **完整 Markdown 支持**: 支持 **LaTeX 公式** / **Mermaid 思维导图** / 表格渲染 / 代码高亮 / 图表绘制 / 进度条等进阶 Markdown 语法支持
4. 👀 **多主题支持**: 支持多种主题切换,包含亮色主题的**明亮模式**和暗色主题的**深色模式**。 👉 [自定义配色](https://github.com/coaidev/coai/blob/main/app/src/assets/globals.less)
5. 📚 **国际化支持**: 支持国际化,支持多语言切换 🇨🇳 🇺🇸 🇯🇵 🇷🇺 👉 欢迎贡献翻译 [Pull Request](https://github.com/coaidev/coai/pulls)
6. 🎨 **文生图支持**: 支持多种文生图模型: **OpenAI DALL-E**✅ & **Midjourney** (支持 **U/V/R** 操作)✅ & Stable Diffusion✅ 等
7. 📡 **强大对话同步**: **用户 0 成本对话跨端同步支持**,支持**对话分享** (支持链接分享 & 保存为图片 & 分享管理), **无需 WebDav / WebRTC 等依赖和复杂学习成本**
8. 🎈 **模型市场 & 预设系统**: 支持后台可自定义的模型市场, 可提供模型介绍、标签等参数, 站长可根据情况自定义模型简介。同时支持预设系统,包含 **自定义预设** 和 **云端同步** 功能。
9. 📖 **丰富文件解析**: **开箱即用**, 支持**所有模型**的文件解析 (PDF / Docx / Pptx / Excel / 图片等格式解析), **支持更多云端图片存储方案** (S3 / R2 / MinIO 等), **支持 OCR 图片识别** 👉 详情参见项目 [CoAI.Dev Blob Service](https://github.com/coaidev/blob-service) (支持 Vercel / Docker 一键部署)
10. 🌏 **全模型联网搜索**: 基于 [SearXNG](https://github.com/searxng/searxng) 开源引擎, 支持 Google / Bing / DuckDuckGo / Yahoo / WikiPedia / Arxiv / Qwant 等丰富搜索引擎搜索, 支持安全搜索模式, 内容截断, 图片代理, 测试搜索可用性等功能。
11. 💕 **渐进式 Web 应用 (PWA)**: 支持 PWA 应用 & 支持桌面端 (桌面端基于 [Tauri](https://github.com/tauri-apps/tauri))
12. 🤩 **齐全后台管理**: 支持美观丰富的仪表盘, 公告 & 通知管理, 用户管理, 订阅管理, 礼品码 & 兑换码管理, 价格设定, 订阅设定, 自定义模型市场, 自定义站点名称 & Logo, SMTP 发件设置等功能
13. 🤑 **多种计费方式**: 支持 💴 **订阅制** 和 💴 **弹性计费** 两种计费方式, 弹性计费支持 次数计费 / Token 计费 / 不计费 / 可匿名调用 和 **最小请求点数** 检测等强大功能
14. 🎉 **创新模型缓存**: 支持开启模型缓存:即同一个请求入参 Hash 下, 如果之前已请求过, 将直接返回缓存结果 (击中缓存将不计费), 减少请求次数。可自行自定义是否缓存的模型、缓存时间、多种缓存结果数等高级缓存设置
15. 🥪 **附加功能** (停止支持): 🍎 **AI 项目生成器功能** / 📂 **批量文章生成功能** / 🥪 **AI 卡片功能** (已废弃)
16. 😎 **优秀渠道管理**: 自写优秀渠道算法, 支持⚡ **多渠道管理**, 支持🥳**优先级**设置渠道的调用顺序, 支持🥳**权重**设置同一优先级下的渠道均衡负载分配概率, 支持🥳**用户分组**, 🥳**失败自动重试**, 🥳**模型重定向**, 🥳**内置上游隐藏**, 🥳**渠道状态管理**等强大**企业级功能**
17. ⭐ **OpenAI API 分发 & 中转系统**: 支持以 **OpenAI API** 标准格式调用各种大模型, 集成强大的渠道管理功能, 仅需部署一个站点即可实现同时发展 B/C 端业务💖
18. 👌 **快速同步上游**: 渠道设置、模型市场、价格设定等设置都可快速同步上游站点,以此基础修改自己的站点配置,快速搭建自己的站点,省时省力,一键同步,快速上线
19. 👋 **SEO 优化**: 支持 SEO 优化,支持自定义站点名称、站点 Logo 等 SEO 优化设设置使搜索引擎更快的爬取,你的站点与众不同👋
20. 🎫 **多种兑换码体系**: 支持多种兑换码体系,支持礼品码和兑换码,支持批量生成,礼品码适合宣传分发,兑换码适合发卡销售,礼品码一个类型的多个码一个用户仅能兑换一个码,在宣传中一定程度上减少一个用户兑换多次的情况😀
21. 🥰 **商用友好协议**: 采用 **Apache-2.0** 开源协议, 商用二开 & 分发友好 (也请遵守 Apache-2.0 协议的规定, 请勿用于违法用途)
> ### ✨ CoAI.Dev 商业版
> 
>
> - ✅ 美观商业级 UI, 漂亮的前端界面与后台管理
> - ✅ 支持 TTS & STT, 插件市场, RAG 知识库等丰富功能与模块
> - ✅ 更多支付供应商, 更多计费模式和高级订单管理
> - ✅ 支持更多鉴权方式,包括短信登录、OAuth 登录等
> - ✅ 支持模型监控,渠道健康检测,故障告警自动渠道切换
> - ✅ 支持多租户 API Key 分发系统, 企业级令牌权限管理与访问者限制
> - ✅ 支持安全审核, 日志记录, 模型限速, API Gateway 等高级功能
> - ✅ 支持推广奖励,专业数据统计,用户画像分析等商业分析能力
> - ✅ 支持Discord/Telegram/飞书等机器人对接集成能力 (扩展模块)
> - ...
>
> [👉 了解更多](https://www.coai.dev/docs/contact)
## 🔨 支持模型
1. OpenAI & Azure OpenAI *(✅ Vision ✅ Function Calling)*
2. Anthropic Claude *(✅ Vision ✅ Function Calling)*
3. Google Gemini & PaLM2 *(✅ Vision)*
4. Midjourney *(✅ Mode Toggling ✅ U/V/R Actions)*
5. 讯飞星火 SparkDesk *(✅ Vision ✅ Function Calling)*
6. 智谱清言 ChatGLM *(✅ Vision)*
7. 通义千问 Tongyi Qwen
8. 腾讯混元 Tencent Hunyuan
9. 百川大模型 Baichuan AI
10. 月之暗面 Moonshot AI (👉 OpenAI)
11. 深度求索 DeepSeek AI (👉 OpenAI)
12. 字节云雀 ByteDance Skylark *(✅ Function Calling)*
13. Groq Cloud AI
14. OpenRouter (👉 OpenAI)
15. 360 GPT
16. LocalAI / Ollama (👉 OpenAI)
## 👻 中转 OpenAI 兼容 API
- [x] Chat Completions _(/v1/chat/completions)_
- [x] Image Generation _(/v1/images)_
- [x] Model List _(/v1/models)_
- [x] Dashboard Billing _(/v1/billing)_
## 📦 部署方式
> [!TIP]
> **部署成功后, 管理员账号为 `root`, 密码默认为 `chatnio123456`**
### ✨ Zeabur (一键部署)
[](https://zeabur.com/templates/M86XJI)
> Zeabur 提供一定的免费额度, 可以使用非付费区域进行一键部署,同时也支持计划订阅和弹性计费等方式弹性扩展。
> 1. 点击 `Deploy` 进行部署, 并输入你希望绑定的域名,等待部署完成。
> 2. 部署完成后, 请访问你的域名, 并使用用户名 `root` 密码 `chatnio123456` 登录后台管理,请按照提示在 chatnio 后台及时修改密码。
### 🐳 宝塔面板 (一键部署)
1. 安装宝塔面板,前往 [宝塔面板官网](https://www.bt.cn/new/download.html) 进行安装,选择正式版脚本安装。
2. 登录面板,点击左侧 **Docker** 进入 Docker 管理。
3. 如提示未安装 Docker / Docker Compose, 可根据上方引导安装。
4. 安装完成后,进入 **应用商城**,搜索 `CoAI` 并点击 **安装**。
5. 配置应用基本信息,如您的域名,端口等配置,并点击 **确认** (可使用默认配置)。
6. 首次安装可能需要等待 1-2 分钟完成数据库初始化。如遇到问题,请查看面板运行日志进行排查。
7. 访问您配置的域名或服务器 `http://[ip]:[port]`,使用用户名 `root` 和密码 `chatnio123456` 登录后台管理。
### 阿里云计算巢 (一键部署)
[](https://computenest.console.aliyun.com/service/instance/create/default?type=user&ServiceName=CoAI社区版)
1. 访问计算巢CoAI[部署链接](https://computenest.console.aliyun.com/service/instance/create/cn-hangzhou?type=user&ServiceName=CoAI社区版),按提示填写部署参数
2. 选择付费类型,填写实例参数与网络参数,点击 **确认订单**
3. 确认部署参数并查看预估价格后,点击立即创建,等待服务实例部署完成
4. 点击左侧 **服务实例** 等待服务实例部署完成后,点击实例ID进入到详情界面
5. 点击详情界面**立即使用**中的链接,可进入CoAI社区版界面。默认用户名为`root`,密码`为chatnio123456` 登录后台管理。
6. 更多操作详情与付费信息,参见:[服务详情](https://computenest.console.aliyun.com/service/detail/cn-hangzhou/service-bfbf676bd89d434691fc/1?type=user&isRecommend=true)
### ⚡ Docker Compose 安装 (推荐)
> [!NOTE]
> 运行成功后, 宿主机映射地址为 `http://localhost:8000`
```shell
git clone --depth=1 --branch=main --single-branch https://github.com/coaidev/coai.git
cd chatnio
docker-compose up -d # 运行服务
# 如需使用 stable 版本, 请使用 docker-compose -f docker-compose.stable.yaml up -d 替代
# 如需使用 watchtower 自动更新, 请使用 docker-compose -f docker-compose.watch.yaml up -d 替代
```
版本更新(_开启 Watchtower 自动更新的情况下, 无需手动更新_):
```shell
docker-compose down
docker-compose pull
docker-compose up -d
```
> - MySQL 数据库挂载目录项目 ~/**db**
> - Redis 数据库挂载目录项目 ~/**redis**
> - 配置文件挂载目录项目 ~/**config**
### ⚡ Docker 安装 (轻量运行时, 常用于外置 _MYSQL/RDS_ 服务)
> [!NOTE]
> 运行成功后, 宿主机地址为 `http://localhost:8094`。
>
> 如需使用 stable 版本, 请使用 `programzmh/chatnio:stable` 替代 `programzmh/chatnio:latest`
```shell
docker run -d --name chatnio \
--network host \
-v ~/config:/config \
-v ~/logs:/logs \
-v ~/storage:/storage \
-e MYSQL_HOST=localhost \
-e MYSQL_PORT=3306 \
-e MYSQL_DB=chatnio \
-e MYSQL_USER=root \
-e MYSQL_PASSWORD=chatnio123456 \
-e REDIS_HOST=localhost \
-e REDIS_PORT=6379 \
-e SECRET=secret \
-e SERVE_STATIC=true \
programzmh/chatnio:latest
```
> - *--network host* 指使用宿主机网络, 使 Docker 容器使用宿主机的网络, 可自行修改
> - SECRET: JWT 密钥, 自行生成随机字符串修改
> - SERVE_STATIC: 是否启用静态文件服务 (正常情况下不需要更改此项, 详见下方常见问题解答)
> - *-v ~/config:/config* 挂载配置文件, *-v ~/logs:/logs* 挂载日志文件的宿主机目录, *-v ~/storage:/storage* 挂载附加功能的生成文件
> - 需配置 MySQL 和 Redis 服务, 请自行参考上方信息修改环境变量
版本更新 (_开启 Watchtower 后无需手动更新, 执行后按照上述步骤重新运行即可_):
```shell
docker stop chatnio
docker rm chatnio
docker pull programzmh/chatnio:latest
```
### ⚒ 编译安装
> [!NOTE]
> 部署成功后, 默认端口为 **8094**, 访问地址为 `http://localhost:8094`
>
> Config 配置项 (~/config/**config.yaml**) 可以使用环境变量进行覆盖, 如 `MYSQL_HOST` 环境变量可覆盖 `mysql.host` 配置项
```shell
git clone https://github.com/coaidev/coai.git
cd chatnio
cd app
npm install -g pnpm
pnpm install
pnpm build
cd ..
go build -o chatnio
# e.g. using nohup (you can also use systemd or other service manager)
nohup ./chatnio > output.log & # using nohup to run in background
```
## ❓ 常见问题 Q&A
1. **为什么我部署后的站点可以访问页面, 可以登录注册, 但是无法使用聊天 (一直在转圈)?**
- 聊天等此类功能通过 websocket 进行通信, 请确保你的服务支持 websocket。 (Tip: 中转通过 Http 实现, 无需 websocket 支持)
- 如果你使用了 Nginx, Apache 等反向代理, 请确保已配置 websocket 支持。
- 如果使用了端口映射, 端口转发, CDN, API Gateway 等服务, 请确保你的服务支持并开启 websocket。
2. **我配置的 Midjourney Proxy 格式的渠道一直转圈或报错 `please provide available notify url`**
- 若为转圈,请确保你的 Midjourney Proxy 服务已正常运行, 并且已配置正确的上游地址。
- **Midjourney 要填渠道类型要用 Midjourney 而不是 OpenAI (不知道为什么很多人填成了 OpenAI 类型格式然后过来反馈为什么empty response, mj-chat 类除外)**
- 排查完这些问题后, 请查看你的系统设置中的**后端域名**是否已经配置并配置正确。如果不配置, 将导致 Midjourney Proxy 服务无法正常回调。
3. **此项目有什么外部依赖?**
- MySQL: 存储用户信息, 对话记录, 管理员信息等持久化数据。
- Redis: 存储用户快速鉴权信息, IP 速率限制, 订阅配额, 邮箱验证码等数据。
- 环境未配置好的情况下, 会导致服务无法正常运行, 请确保你的 MySQL 和 Redis 服务已正常运行 (Docker 部署, 编译部署需自行搭建外部服务)。
4. **我的机器为 ARM 架构, 该项目支持 ARM 架构吗?**
- 支持。CoAI.Dev 项目使用 BuildX 构建多架构镜像, 你可以直接使用 docker-compose 或 docker 运行, 无需额外配置。
- 如果你使用编译安装, 直接在 ARM 机器上编译即可, 无需欸外配置。如果你使用 x86 机器编译, 请使用 `GOARCH=arm64 go build -o chatnio` 进行交叉编译并上传至 ARM 机器上运行。
5. **如何修改 Root 默认密码?**
- 请点击右上角头像或侧边栏底部用户框进入后台管理, 点击系统设置下常规设置操作栏的 修改 Root 密码 进行修改。或者选择在 用户管理 中选定 root 用户进行修改密码操作。
6. **系统设置中的后端域名是什么?**
- 后端域名是指后端 API 服务的地址, 默认为你访问站点后加 `/api` 的地址, 如 `https://example.com/api` 。
- 如果设置为非 *SERVE_STATIC* 模式, 开启前后端分离部署, 请将后端域名设置为你的后端 API 服务地址, 如 `https://api.example.com`。
- 后端域名此处用于 Midjourney Proxy 服务的后端回调地址, 如无需使用 Midjourney Proxy 服务, 请忽略此设置。
7. **如何配置支付方式?**
- CoAI.Dev 开源版支持发卡模式, 设置系统设置中的购买链接为你的发卡地址即可。卡密可通过用户管理中兑换码管理中批量生成。
8. **礼品码和兑换码有什么区别?**
- 礼品码一种类型只能一个用户只能绑定一次, 而非 aff code, 发福利等方式可使用礼品码, 可在头像下拉菜单中的礼品码中兑换。
- 兑换码一种类型可以多个用户绑定, 可作为正常购买和发卡使用, 可在用户管理中的兑换码管理中批量生成, 在头像下拉菜单的点数(菜单第一个)内输入兑换码进行兑换。
- 一个例子:比如我发了一个类型为 *新年快乐* 的福利, 此时推荐使用礼品码, 假设发放 100 个 66 点数, 如果为兑换码, 手快的一个用户就批量把所有兑换码的 6600 点数都用完了, 而礼品码则可以保证每个用户只能使用一次 (获得 66 点数)。
- 而搭建发卡的时, 如果用礼品码, 因为一个类型只能兑换一次, 购买多个礼品码会导致兑换失败, 而兑换码则可以在此场景下使用。
9. **该项目支持 Vercel 部署吗?**
- CoAI.Dev 本身并不支持 Vercel 部署, 但是你可以使用前后端分离模式, Vercel 部署前端部分, 后端部分使用 Docker 部署或编译部署。
10. **前后端分离部署模式是什么?**
- 正常情况下, 前后端在同一服务内, 后端地址为 `/api`。前后端分离部署指前端和后端分别部署在不同的服务上, 前端服务为静态文件服务, 后端服务为 API 服务。
- 举个例子, 前端使用 Nginx (或 Vercel 等) 部署, 部署的域名为 `https://www.chatnio.net`。
- 后端使用 Docker 部署, 部署的域名为 `https://api.chatnio.net`。
- 此种部署方式需自行打包前端, 配置环境变量 `VITE_BACKEND_ENDPOINT` 为你的后端地址, 如 `https://api.chatnio.net`。
- 配置后端环境变量的 `SERVE_STATIC=false` 使后端服务不提供静态文件服务。
11. **弹性计费和订阅详解**
- 弹性计费, 即 `点数`, 其图标类似于**云**, 模型计费通用方式, 为了防止虚假汇率, 写死 10 点数 = 1 元, 汇率可以在计费规则中的 **应用内置模板** 中自定义汇率。
- 订阅, 即订阅计划, 为固定价格计费方式按次配额, 订阅计费扣取点数 (举例: 如果站点的用户想订阅 32 元的计划, 则需要保证点数大于等于 320 点数)
- 订阅是 Item 的组合, 每个 Item 都可设置涵盖的模型, 订阅配额 (-1 为无限使用), 名称, ID (用于区分不同的 Item), 图标等。可在后台的订阅管理中进行操作, 是否开启订阅, 订阅价格等, 修改每个订阅等级的 Item, 以及支持直接导入其他订阅等级的 Item。
- 订阅支持分层并写死为三个等级。 等级分别为: _普通用户 (0)_, _基础版订阅 (1)_, _标准版订阅 (2)_, _专业版订阅 (3)_, 订阅等级即为用户分组, 可在渠道管理中进行高级设置, 选择勾选可使用此模型的用户分组。
- 订阅配额设置, 可在订阅管理中进行操作, 是否支持中转 API (默认关闭)
12. **可请求最小点数检测 `user quota is not enough` 详解**
- 为防止站点用户滥用站点模型, 当请求点数低于最小请求点数时将返回点数不足的错误信息, 大于等于最小请求点数时将正常请求。
- 模型的最小可请求点数规则:
- 不计费模型无限制
- 次数计费模型最小点数为该模型的 1 次请求点数 (e.g. 若一个模型的单次请求点数为 0.1 点数, 则最小请求点数为 0.1 点数)
- Token 弹性计费模型为 1K 输入 Tokens 价格 + 1K 输出 Tokens 价格 (e.g. 若一个模型的 1K 输入 Tokens 价格为 0.05 点数, 1K 输出 Tokens 价格 0.1 点数, 则最小请求点数为 0.15 点数)
13. **为何我的 GPT-4-All 等逆向模型无法使用上传文件中的图片?**
- 上传模型图片为 Base64 格式, 如果逆向不支持 Base64 格式, 请使用 URL 直链而非上传文件做法。
14. **如何开始域名严格跨域检测?**
- 正常情况下,后端对所有域名开放跨域。如果非特殊需求,无需开启严格跨域检测。
- 如果需要开启严格跨域检测,可以在后端环境变量中 并配置 `ALLOW_ORIGINS`, 如 `ALLOW_ORIGINS=chatnio.net,chatnio.app` (不需要加协议前缀, www 解析无需手动添加, 后端将自动识别并允许跨域), 这样就会支持严格跨域检测 (如 *http://www.chatnio.app*, *https://chatnio.net* 等将会被允许, 其他域名将会被拒绝)。
- 即使在开启严格跨域检测的情况下, /v1 接口会被仍然允许所有域的跨域请求, 以保证中转 API 的正常使用。
15. **模型映射功能是如何使用的?**
- 渠道内的模型映射格式为 `[from]>[to]`, 多个映射之间换行, **from** 为请求的模型, **to** 为真实向上游发送的模型并且需要上游真实支持
- 如: 我有一个逆向渠道, 填写 `gpt-4-all>gpt-4`, 则我的用户请求 **gpt-4-all** 模型到该渠道时, 后端则会模型映射至 **gpt-4** 向该渠道请求 **gpt-4**, 此时该渠道支持 2 个模型, **gpt-4** 和 **gpt-4-all** (本质上都为 **gpt-4**)
- 如果我不想让我的这个逆向渠道影响到 **gpt-4** 的渠道组, 可以加前缀 `!gpt-4-all>gpt-4`, 该渠道 **gpt-4** 则会被忽略, 此时该渠道将只支持 1 个模型, **gpt-4-all** (但本质上为 **gpt-4**)
## 📦 技术栈
- 🥗 前端: React + Redux + Radix UI + Tailwind CSS
- 🍎 后端: Golang + Gin + Redis + MySQL
- 🍒 应用技术: PWA + WebSocket
## 🤯 为什么写此项目 & 项目优势
我们发现,市面上的 AIGC 商业站点,大多数都是偏向于前端轻量部署的项目,有精美的 UI 界面设计,
比如 [Next Chat](https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web) 的二开商业版本,
由于其偏向个人私有化的设计,在二开商业化时有一定的局限性,呈现出一些问题,比如:
- **对话同步难**, 比如需要 WebDav 等服务,用户学习成本高,跨端实时同步困难。
- **计费不够完善**, 比如只支持弹性计费或只支持订阅制,无法满足不同用户的需求。
- **文件解析不便捷**, 比如只支持先在图床上传图片,返回站点后再在输入框中输入 URL 直链,无内置文件解析功能。
- **不支持对话 URL 分享**, 比如只支持对话截图分享,无法支持对话 URL 分享 (或仅支持 ShareGPT 等工具,无法对站点起到推广作用)。
- **渠道管理不够强大**, 比如后台仅支持 OpenAI 格式渠道,兼容其他格式渠道困难。且只能填入一个渠道,无法支持多渠道管理。
- **不支持 API 调用**, 比如只支持用户界面调用,无法支持 API 中转和管理。
另一种是偏向于 API 分发的站点,有强大的分发系统,比如基于 [One API](https://github.com/songquanpeng/one-api) 等项目,
这类项目虽然支持强大的 API 中转和管理,但是缺少界面设计,且缺少一些 C 端功能,比如:
- **用户界面不够丰富**, 比如只支持 API 调用,不内置用户界面聊天。用户界面聊天需要自行复制密钥并前往其他站点才能使用,这对于普通用户来说,学习成本较高。
- **没有订阅制**, 比如只支持弹性计费,缺少对 C 端用户的计费设计,无法满足用户的不同需求,对于无基础的用户来说,成本感知不够友好。
- **C 端功能不够丰富**, 比如只支持 API 调用,不支持对话同步,不支持对话分享,不支持文件解析等功能。
- **均衡负载不够强大**, 开源版不支持**权重**参数, 无法实现同优先级的渠道均衡负载分配概率 ([New API](https://github.com/Calcium-Ion/new-api) 也解决了此痛点, UI 也更美观)。
因此,我们希望能够将这两种项目的优势结合起来,做出一个既有强大的 API 分发系统,又有丰富的用户界面设计的项目,
这样既能满足 C 端用户的需求,又能发展 B 端业务,提高用户体验,降低用户学习成本,提高用户粘性。
于是,**CoAI.Dev** 应运而生,我们希望能够做出一个既有强大的 API 分发系统,又有丰富的用户界面设计的项目,成为下一代开源 AIGC 项目的商业一站式解决方案。
## ❤ 捐助
如果您觉得这个项目对您有所帮助, 您可以点个 Star 支持一下!
================================================
FILE: adapter/adapter.go
================================================
package adapter
import (
"chat/adapter/azure"
"chat/adapter/baichuan"
"chat/adapter/bing"
"chat/adapter/claude"
adaptercommon "chat/adapter/common"
"chat/adapter/coze"
"chat/adapter/dashscope"
"chat/adapter/deepseek"
"chat/adapter/dify"
"chat/adapter/hunyuan"
"chat/adapter/midjourney"
"chat/adapter/openai"
"chat/adapter/palm2"
"chat/adapter/skylark"
"chat/adapter/slack"
"chat/adapter/sparkdesk"
"chat/adapter/zhinao"
"chat/adapter/zhipuai"
"chat/globals"
"fmt"
)
var channelFactories = map[string]adaptercommon.FactoryCreator{
globals.OpenAIChannelType: openai.NewChatInstanceFromConfig,
globals.AzureOpenAIChannelType: azure.NewChatInstanceFromConfig,
globals.ClaudeChannelType: claude.NewChatInstanceFromConfig,
globals.SlackChannelType: slack.NewChatInstanceFromConfig,
globals.BingChannelType: bing.NewChatInstanceFromConfig,
globals.PalmChannelType: palm2.NewChatInstanceFromConfig,
globals.SparkdeskChannelType: sparkdesk.NewChatInstanceFromConfig,
globals.ChatGLMChannelType: zhipuai.NewChatInstanceFromConfig,
globals.QwenChannelType: dashscope.NewChatInstanceFromConfig,
globals.HunyuanChannelType: hunyuan.NewChatInstanceFromConfig,
globals.BaichuanChannelType: baichuan.NewChatInstanceFromConfig,
globals.SkylarkChannelType: skylark.NewChatInstanceFromConfig,
globals.ZhinaoChannelType: zhinao.NewChatInstanceFromConfig,
globals.MidjourneyChannelType: midjourney.NewChatInstanceFromConfig,
globals.DeepseekChannelType: deepseek.NewChatInstanceFromConfig,
globals.DifyChannelType: dify.NewChatInstanceFromConfig,
globals.CozeChannelType: coze.NewChatInstanceFromConfig,
globals.MoonshotChannelType: openai.NewChatInstanceFromConfig, // openai format
globals.GroqChannelType: openai.NewChatInstanceFromConfig, // openai format
}
func createChatRequest(conf globals.ChannelConfig, props *adaptercommon.ChatProps, hook globals.Hook) error {
props.Model = conf.GetModelReflect(props.OriginalModel)
props.Proxy = conf.GetProxy()
factoryType := conf.GetType()
if factory, ok := channelFactories[factoryType]; ok {
return factory(conf).CreateStreamChatRequest(props, hook)
}
return fmt.Errorf("unknown channel type %s (channel #%d)", conf.GetType(), conf.GetId())
}
func createVideoRequest(conf globals.ChannelConfig, props *adaptercommon.VideoProps, hook globals.Hook) error {
props.Model = conf.GetModelReflect(props.OriginalModel)
props.Proxy = conf.GetProxy()
factoryType := conf.GetType()
if creator, ok := channelFactories[factoryType]; ok {
inst := creator(conf)
if v, ok := inst.(adaptercommon.VideoFactory); ok {
return v.CreateVideoRequest(props, hook)
}
return fmt.Errorf("video request not supported by channel type %s (channel #%d)", conf.GetType(), conf.GetId())
}
return fmt.Errorf("unknown channel type %s (channel #%d)", conf.GetType(), conf.GetId())
}
================================================
FILE: adapter/azure/chat.go
================================================
package azure
import (
adaptercommon "chat/adapter/common"
"chat/globals"
"chat/utils"
"errors"
"fmt"
"strings"
)
func (c *ChatInstance) GetChatEndpoint(props *adaptercommon.ChatProps) string {
model := strings.ReplaceAll(props.Model, ".", "")
if props.Model == globals.GPT3TurboInstruct {
return fmt.Sprintf("%s/openai/deployments/%s/completions?api-version=%s", c.GetResource(), model, c.GetEndpoint())
}
return fmt.Sprintf("%s/openai/deployments/%s/chat/completions?api-version=%s", c.GetResource(), model, c.GetEndpoint())
}
func (c *ChatInstance) GetCompletionPrompt(messages []globals.Message) string {
result := ""
for _, message := range messages {
result += fmt.Sprintf("%s: %s\n", message.Role, message.Content)
}
return result
}
func (c *ChatInstance) GetLatestPrompt(props *adaptercommon.ChatProps) string {
if len(props.Message) == 0 {
return ""
}
return props.Message[len(props.Message)-1].Content
}
func (c *ChatInstance) GetChatBody(props *adaptercommon.ChatProps, stream bool) interface{} {
if props.Model == globals.GPT3TurboInstruct {
// for completions
return CompletionRequest{
Prompt: c.GetCompletionPrompt(props.Message),
MaxToken: props.MaxTokens,
Stream: stream,
}
}
return ChatRequest{
Messages: formatMessages(props),
MaxToken: props.MaxTokens,
Stream: stream,
PresencePenalty: props.PresencePenalty,
FrequencyPenalty: props.FrequencyPenalty,
Temperature: props.Temperature,
TopP: props.TopP,
Tools: props.Tools,
ToolChoice: props.ToolChoice,
}
}
// CreateChatRequest is the native http request body for openai
func (c *ChatInstance) CreateChatRequest(props *adaptercommon.ChatProps) (string, error) {
if globals.IsOpenAIDalleModel(props.Model) {
return c.CreateImage(props)
}
res, err := utils.Post(
c.GetChatEndpoint(props),
c.GetHeader(),
c.GetChatBody(props, false),
props.Proxy,
)
if err != nil || res == nil {
return "", fmt.Errorf("openai error: %s", err.Error())
}
data := utils.MapToStruct[ChatResponse](res)
if data == nil {
return "", fmt.Errorf("openai error: cannot parse response")
} else if data.Error.Message != "" {
return "", fmt.Errorf("openai error: %s", data.Error.Message)
}
return data.Choices[0].Message.Content, nil
}
// CreateStreamChatRequest is the stream response body for openai
func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.ChatProps, callback globals.Hook) error {
if globals.IsOpenAIDalleModel(props.Model) {
if url, err := c.CreateImage(props); err != nil {
return err
} else {
return callback(&globals.Chunk{Content: url})
}
}
isCompletionType := props.Model == globals.GPT3TurboInstruct
ticks := 0
err := utils.EventScanner(&utils.EventScannerProps{
Method: "POST",
Uri: c.GetChatEndpoint(props),
Headers: c.GetHeader(),
Body: c.GetChatBody(props, true),
Callback: func(data string) error {
ticks += 1
partial, err := c.ProcessLine(data, isCompletionType)
if err != nil {
return err
}
return callback(partial)
},
}, props.Proxy)
if err != nil {
if form := processChatErrorResponse(err.Body); form != nil {
msg := fmt.Sprintf("%s (type: %s)", form.Error.Message, form.Error.Type)
return errors.New(msg)
}
return err.Error
}
if ticks == 0 {
return errors.New("no response")
}
return nil
}
================================================
FILE: adapter/azure/image.go
================================================
package azure
import (
adaptercommon "chat/adapter/common"
"chat/globals"
"chat/utils"
"fmt"
"strings"
)
type ImageProps struct {
Model string
Prompt string
Size ImageSize
Proxy globals.ProxyConfig
}
func (c *ChatInstance) GetImageEndpoint(model string) string {
model = strings.ReplaceAll(model, ".", "")
return fmt.Sprintf("%s/openai/deployments/%s/images/generations?api-version=%s", c.GetResource(), model, c.GetEndpoint())
}
// CreateImageRequest will create a dalle image from prompt, return url of image, base64 data and error
func (c *ChatInstance) CreateImageRequest(props ImageProps) (string, string, error) {
res, err := utils.Post(
c.GetImageEndpoint(props.Model),
c.GetHeader(), ImageRequest{
Prompt: props.Prompt,
Size: utils.Multi[ImageSize](
props.Model == globals.Dalle3 || props.Model == globals.GPTImage1,
ImageSize1024,
ImageSize512,
),
N: 1,
}, props.Proxy)
if err != nil || res == nil {
return "", "", fmt.Errorf("openai error: %s", err.Error())
}
data := utils.MapToStruct[ImageResponse](res)
if data == nil {
return "", "", fmt.Errorf("openai error: cannot parse response")
} else if data.Error.Message != "" {
return "", "", fmt.Errorf("openai error: %s", data.Error.Message)
}
// for gpt-image-1, return base64 data if available
if props.Model == globals.GPTImage1 && data.Data[0].B64Json != "" {
return "", data.Data[0].B64Json, nil
}
return data.Data[0].Url, "", nil
}
// CreateImage will create a dalle image from prompt, return markdown of image
func (c *ChatInstance) CreateImage(props *adaptercommon.ChatProps) (string, error) {
url, b64Json, err := c.CreateImageRequest(ImageProps{
Model: props.Model,
Prompt: c.GetLatestPrompt(props),
Proxy: props.Proxy,
})
if err != nil {
if strings.Contains(err.Error(), "safety") {
return err.Error(), nil
}
return "", err
}
if b64Json != "" {
return utils.GetBase64ImageMarkdown(b64Json), nil
}
return utils.GetImageMarkdown(url), nil
}
================================================
FILE: adapter/azure/processor.go
================================================
package azure
import (
adaptercommon "chat/adapter/common"
"chat/globals"
"chat/utils"
"errors"
"fmt"
"regexp"
)
func formatMessages(props *adaptercommon.ChatProps) interface{} {
if globals.IsVisionModel(props.Model) {
return utils.Each[globals.Message, Message](props.Message, func(message globals.Message) Message {
if message.Role == globals.User {
raw, urls := utils.ExtractImages(message.Content, true)
images := utils.EachNotNil[string, MessageContent](urls, func(url string) *MessageContent {
obj, err := utils.NewImage(url)
if err != nil {
globals.Info(fmt.Sprintf("cannot process image: %s (source: %s)", err.Error(), utils.Extract(url, 24, "...")))
return nil
}
props.Buffer.AddImage(obj)
return &MessageContent{
Type: "image_url",
ImageUrl: &ImageUrl{
Url: url,
},
}
})
return Message{
Role: message.Role,
Content: utils.Prepend(images, MessageContent{
Type: "text",
Text: &raw,
}),
Name: message.Name,
FunctionCall: message.FunctionCall,
ToolCalls: message.ToolCalls,
ToolCallId: message.ToolCallId,
}
}
return Message{
Role: message.Role,
Content: MessageContents{
MessageContent{
Type: "text",
Text: &message.Content,
},
},
Name: message.Name,
FunctionCall: message.FunctionCall,
ToolCalls: message.ToolCalls,
ToolCallId: message.ToolCallId,
}
})
}
return props.Message
}
func processChatResponse(data string) *ChatStreamResponse {
return utils.UnmarshalForm[ChatStreamResponse](data)
}
func processCompletionResponse(data string) *CompletionResponse {
return utils.UnmarshalForm[CompletionResponse](data)
}
func processChatErrorResponse(data string) *ChatStreamErrorResponse {
return utils.UnmarshalForm[ChatStreamErrorResponse](data)
}
func getChoices(form *ChatStreamResponse) *globals.Chunk {
if len(form.Choices) == 0 {
return &globals.Chunk{Content: ""}
}
choice := form.Choices[0].Delta
return &globals.Chunk{
Content: choice.Content,
ToolCall: choice.ToolCalls,
FunctionCall: choice.FunctionCall,
}
}
func getCompletionChoices(form *CompletionResponse) string {
if len(form.Choices) == 0 {
return ""
}
return form.Choices[0].Text
}
func getRobustnessResult(chunk string) string {
exp := `\"content\":\"(.*?)\"`
compile, err := regexp.Compile(exp)
if err != nil {
return ""
}
matches := compile.FindStringSubmatch(chunk)
if len(matches) > 1 {
return utils.ProcessRobustnessChar(matches[1])
} else {
return ""
}
}
func (c *ChatInstance) ProcessLine(data string, isCompletionType bool) (*globals.Chunk, error) {
if isCompletionType {
// openai legacy support
if completion := processCompletionResponse(data); completion != nil {
return &globals.Chunk{
Content: getCompletionChoices(completion),
}, nil
}
globals.Warn(fmt.Sprintf("openai error: cannot parse completion response: %s", data))
return &globals.Chunk{Content: ""}, errors.New("parser error: cannot parse completion response")
}
if form := processChatResponse(data); form != nil {
return getChoices(form), nil
}
if form := processChatErrorResponse(data); form != nil {
return &globals.Chunk{Content: ""}, errors.New(fmt.Sprintf("openai error: %s (type: %s)", form.Error.Message, form.Error.Type))
}
globals.Warn(fmt.Sprintf("openai error: cannot parse chat completion response: %s", data))
return &globals.Chunk{Content: ""}, errors.New("parser error: cannot parse chat completion response")
}
================================================
FILE: adapter/azure/struct.go
================================================
package azure
import (
factory "chat/adapter/common"
"chat/globals"
)
type ChatInstance struct {
Endpoint string
ApiKey string
Resource string
}
func (c *ChatInstance) GetEndpoint() string {
return c.Endpoint
}
func (c *ChatInstance) GetApiKey() string {
return c.ApiKey
}
func (c *ChatInstance) GetResource() string {
return c.Resource
}
func (c *ChatInstance) GetHeader() map[string]string {
return map[string]string{
"Content-Type": "application/json",
"api-key": c.GetApiKey(),
}
}
func NewChatInstance(endpoint, apiKey string, resource string) *ChatInstance {
return &ChatInstance{
Endpoint: endpoint,
ApiKey: apiKey,
Resource: resource,
}
}
func NewChatInstanceFromConfig(conf globals.ChannelConfig) factory.Factory {
param := conf.SplitRandomSecret(2)
return NewChatInstance(
conf.GetEndpoint(),
param[0],
param[1],
)
}
================================================
FILE: adapter/azure/types.go
================================================
package azure
import "chat/globals"
type ImageUrl struct {
Url string `json:"url"`
Detail *string `json:"detail,omitempty"`
}
type MessageContent struct {
Type string `json:"type"`
Text *string `json:"text,omitempty"`
ImageUrl *ImageUrl `json:"image_url,omitempty"`
}
type MessageContents []MessageContent
type Message struct {
Role string `json:"role"`
Content MessageContents `json:"content"`
Name *string `json:"name,omitempty"`
FunctionCall *globals.FunctionCall `json:"function_call,omitempty"` // only `function` role
ToolCallId *string `json:"tool_call_id,omitempty"` // only `tool` role
ToolCalls *globals.ToolCalls `json:"tool_calls,omitempty"` // only `assistant` role
}
// ChatRequest is the request body for openai
type ChatRequest struct {
Model string `json:"model"`
Messages interface{} `json:"messages"`
MaxToken *int `json:"max_tokens,omitempty"`
MaxCompletionTokens *int `json:"max_completion_tokens,omitempty"`
Stream bool `json:"stream"`
PresencePenalty *float32 `json:"presence_penalty,omitempty"`
FrequencyPenalty *float32 `json:"frequency_penalty,omitempty"`
Temperature *float32 `json:"temperature,omitempty"`
TopP *float32 `json:"top_p,omitempty"`
Tools *globals.FunctionTools `json:"tools,omitempty"`
ToolChoice *interface{} `json:"tool_choice,omitempty"` // string or object
}
// CompletionRequest is the request body for openai completion
type CompletionRequest struct {
Model string `json:"model"`
Prompt string `json:"prompt"`
MaxToken *int `json:"max_tokens,omitempty"`
Stream bool `json:"stream"`
}
// ChatResponse is the native http request body for openai
type ChatResponse struct {
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
Model string `json:"model"`
Choices []struct {
Index int `json:"index"`
Message globals.Message `json:"message"`
FinishReason string `json:"finish_reason"`
} `json:"choices"`
Error struct {
Message string `json:"message"`
} `json:"error"`
}
// ChatStreamResponse is the stream response body for openai
type ChatStreamResponse struct {
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
Model string `json:"model"`
Choices []struct {
Delta globals.Message `json:"delta"`
Index int `json:"index"`
FinishReason string `json:"finish_reason"`
} `json:"choices"`
}
// CompletionResponse is the native http request body / stream response body for openai completion
type CompletionResponse struct {
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
Model string `json:"model"`
Choices []struct {
Text string `json:"text"`
Index int `json:"index"`
} `json:"choices"`
}
type ChatStreamErrorResponse struct {
Error struct {
Message string `json:"message"`
Type string `json:"type"`
} `json:"error"`
}
type ImageSize string
// ImageRequest is the request body for openai dalle image generation
type ImageRequest struct {
Model string `json:"model"`
Prompt string `json:"prompt"`
Size ImageSize `json:"size"`
N int `json:"n"`
}
type ImageResponse struct {
Data []struct {
Url string `json:"url,omitempty"`
B64Json string `json:"b64_json,omitempty"`
} `json:"data"`
Error struct {
Message string `json:"message"`
} `json:"error"`
Usage *struct {
InputTokens int `json:"input_tokens"`
InputTokensDetails struct {
ImageTokens int `json:"image_tokens"`
TextTokens int `json:"text_tokens"`
} `json:"input_tokens_details"`
OutputTokens int `json:"output_tokens"`
TotalTokens int `json:"total_tokens"`
} `json:"usage,omitempty"`
}
var (
ImageSize256 ImageSize = "256x256"
ImageSize512 ImageSize = "512x512"
ImageSize1024 ImageSize = "1024x1024"
)
================================================
FILE: adapter/baichuan/chat.go
================================================
package baichuan
import (
adaptercommon "chat/adapter/common"
"chat/globals"
"chat/utils"
"errors"
"fmt"
)
func (c *ChatInstance) GetChatEndpoint() string {
return fmt.Sprintf("%s/v1/chat/completions", c.GetEndpoint())
}
func (c *ChatInstance) GetModel(model string) string {
switch model {
case globals.Baichuan53B:
return "Baichuan2"
default:
return model
}
}
func (c *ChatInstance) GetMessages(messages []globals.Message) []globals.Message {
for _, message := range messages {
if message.Role == globals.System || message.Role == globals.Tool {
message.Role = globals.User
}
}
return messages
}
func (c *ChatInstance) GetChatBody(props *adaptercommon.ChatProps, stream bool) ChatRequest {
return ChatRequest{
Model: c.GetModel(props.Model),
Messages: c.GetMessages(props.Message),
Stream: stream,
TopP: props.TopP,
TopK: props.TopK,
Temperature: props.Temperature,
}
}
// CreateChatRequest is the native http request body for baichuan
func (c *ChatInstance) CreateChatRequest(props *adaptercommon.ChatProps) (string, error) {
res, err := utils.Post(
c.GetChatEndpoint(),
c.GetHeader(),
c.GetChatBody(props, false),
props.Proxy,
)
if err != nil || res == nil {
return "", fmt.Errorf("baichuan error: %s", err.Error())
}
data := utils.MapToStruct[ChatResponse](res)
if data == nil {
return "", fmt.Errorf("baichuan error: cannot parse response")
} else if data.Error.Message != "" {
return "", fmt.Errorf("baichuan error: %s", data.Error.Message)
}
return data.Choices[0].Message.Content, nil
}
// CreateStreamChatRequest is the stream response body for baichuan
func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.ChatProps, callback globals.Hook) error {
err := utils.EventScanner(&utils.EventScannerProps{
Method: "POST",
Uri: c.GetChatEndpoint(),
Headers: c.GetHeader(),
Body: c.GetChatBody(props, true),
Callback: func(data string) error {
partial, err := c.ProcessLine(data)
if err != nil {
return err
}
return callback(partial)
},
}, props.Proxy)
if err != nil {
if form := processChatErrorResponse(err.Body); form != nil {
msg := fmt.Sprintf("%s (type: %s)", form.Error.Message, form.Error.Type)
return errors.New(msg)
}
return err.Error
}
return nil
}
================================================
FILE: adapter/baichuan/processor.go
================================================
package baichuan
import (
"chat/globals"
"chat/utils"
"errors"
"fmt"
)
func processChatResponse(data string) *ChatStreamResponse {
return utils.UnmarshalForm[ChatStreamResponse](data)
}
func processChatErrorResponse(data string) *ChatStreamErrorResponse {
return utils.UnmarshalForm[ChatStreamErrorResponse](data)
}
func getChoices(form *ChatStreamResponse) *globals.Chunk {
if len(form.Choices) == 0 {
return &globals.Chunk{Content: ""}
}
choice := form.Choices[0].Delta
return &globals.Chunk{
Content: choice.Content,
}
}
func (c *ChatInstance) ProcessLine(data string) (*globals.Chunk, error) {
if form := processChatResponse(data); form != nil {
return getChoices(form), nil
}
if form := processChatErrorResponse(data); form != nil {
return &globals.Chunk{Content: ""}, errors.New(fmt.Sprintf("baichuan error: %s (type: %s)", form.Error.Message, form.Error.Type))
}
globals.Warn(fmt.Sprintf("baichuan error: cannot parse chat completion response: %s", data))
return &globals.Chunk{Content: ""}, errors.New("parser error: cannot parse chat completion response")
}
================================================
FILE: adapter/baichuan/struct.go
================================================
package baichuan
import (
factory "chat/adapter/common"
"chat/globals"
"fmt"
)
type ChatInstance struct {
Endpoint string
ApiKey string
}
func (c *ChatInstance) GetEndpoint() string {
return c.Endpoint
}
func (c *ChatInstance) GetApiKey() string {
return c.ApiKey
}
func (c *ChatInstance) GetHeader() map[string]string {
return map[string]string{
"Content-Type": "application/json",
"Authorization": fmt.Sprintf("Bearer %s", c.GetApiKey()),
}
}
func NewChatInstance(endpoint, apiKey string) *ChatInstance {
return &ChatInstance{
Endpoint: endpoint,
ApiKey: apiKey,
}
}
func NewChatInstanceFromConfig(conf globals.ChannelConfig) factory.Factory {
return NewChatInstance(
conf.GetEndpoint(),
conf.GetRandomSecret(),
)
}
================================================
FILE: adapter/baichuan/types.go
================================================
package baichuan
import "chat/globals"
// Baichuan AI API is similar to OpenAI API
type ChatRequest struct {
Model string `json:"model"`
Messages []globals.Message `json:"messages"`
Stream bool `json:"stream"`
TopP *float32 `json:"top_p,omitempty"`
TopK *int `json:"top_k,omitempty"`
Temperature *float32 `json:"temperature,omitempty"`
WithSearchEnhance *bool `json:"with_search_enhance,omitempty"`
}
// ChatResponse is the native http request body for baichuan
type ChatResponse struct {
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
Model string `json:"model"`
Choices []struct {
Message struct {
Content string `json:"content"`
}
} `json:"choices"`
Error struct {
Message string `json:"message"`
} `json:"error"`
}
// ChatStreamResponse is the stream response body for baichuan
type ChatStreamResponse struct {
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
Model string `json:"model"`
Choices []struct {
Delta struct {
Content string `json:"content"`
}
Index int `json:"index"`
} `json:"choices"`
}
type ChatStreamErrorResponse struct {
Error struct {
Message string `json:"message"`
Type string `json:"type"`
} `json:"error"`
}
================================================
FILE: adapter/bing/chat.go
================================================
package bing
import (
adaptercommon "chat/adapter/common"
"chat/globals"
"chat/utils"
"fmt"
"strings"
)
func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.ChatProps, hook globals.Hook) error {
var conn *utils.WebSocket
if conn = utils.NewWebsocketClient(c.GetEndpoint()); conn == nil {
return fmt.Errorf("bing error: websocket connection failed")
}
defer conn.DeferClose()
model := strings.TrimPrefix(props.Model, "bing-")
prompt := props.Message[len(props.Message)-1].Content
if err := conn.SendJSON(&ChatRequest{
Prompt: prompt,
Hash: c.Secret,
Model: model,
}); err != nil {
return err
}
for {
form, err := utils.ReadForm[ChatResponse](conn)
if err != nil {
if strings.Contains(err.Error(), "websocket: close 1000") {
return nil
}
globals.Debug(fmt.Sprintf("bing error: %s", err.Error()))
return nil
}
if err := hook(&globals.Chunk{
Content: form.Response,
}); err != nil {
return err
}
}
}
================================================
FILE: adapter/bing/struct.go
================================================
package bing
import (
factory "chat/adapter/common"
"chat/globals"
"fmt"
)
type ChatInstance struct {
Endpoint string
Secret string
}
func (c *ChatInstance) GetEndpoint() string {
return fmt.Sprintf("%s/chat", c.Endpoint)
}
func NewChatInstance(endpoint, secret string) *ChatInstance {
return &ChatInstance{
Endpoint: endpoint,
Secret: secret,
}
}
func NewChatInstanceFromConfig(conf globals.ChannelConfig) factory.Factory {
return NewChatInstance(
conf.GetEndpoint(),
conf.GetRandomSecret(),
)
}
================================================
FILE: adapter/bing/types.go
================================================
package bing
// see https://github.com/Deeptrain-Community/chatnio-bing-service
type ChatRequest struct {
Prompt string `json:"prompt"`
Hash string `json:"hash"`
Model string `json:"model"`
}
type ChatResponse struct {
Response string `json:"response"`
}
================================================
FILE: adapter/claude/chat.go
================================================
package claude
import (
adaptercommon "chat/adapter/common"
"chat/globals"
"chat/utils"
"errors"
"fmt"
)
const defaultTokens = 2500
func (c *ChatInstance) GetChatEndpoint() string {
return fmt.Sprintf("%s/v1/messages", c.GetEndpoint())
}
func (c *ChatInstance) GetChatHeaders() map[string]string {
return map[string]string{
"content-type": "application/json",
"anthropic-version": "2023-06-01",
"x-api-key": c.GetApiKey(),
}
}
// ConvertCompletionMessage converts the completion message to anthropic complete format (deprecated)
func (c *ChatInstance) ConvertCompletionMessage(message []globals.Message) string {
mapper := map[string]string{
globals.System: "Assistant",
globals.User: "Human",
globals.Assistant: "Assistant",
}
var result string
for i, item := range message {
if item.Role == globals.Tool {
continue
}
if i == 0 && item.Role == globals.Assistant {
// skip first assistant message
continue
}
result += fmt.Sprintf("\n\n%s: %s", mapper[item.Role], item.Content)
}
return fmt.Sprintf("%s\n\nAssistant:", result)
}
func (c *ChatInstance) GetTokens(props *adaptercommon.ChatProps) int {
if props.MaxTokens == nil || *props.MaxTokens <= 0 {
return defaultTokens
}
return *props.MaxTokens
}
func (c *ChatInstance) ConvertMessages(props *adaptercommon.ChatProps) []globals.Message {
// anthropic api: top message must be user message, only `user` and `assistant` role messages are allowd
start := false
result := make([]globals.Message, 0)
for _, message := range props.Message {
if message.Role == globals.System {
continue
}
// if is first message, set it to user message
if !start {
start = true
result = append(result, globals.Message{
Role: globals.User,
Content: message.Content,
})
continue
}
// anthropic api does not allow multi-same role messages
if len(result) > 0 && result[len(result)-1].Role == message.Role {
result[len(result)-1].Content += "\n" + message.Content
continue
}
result = append(result, message)
}
return result
}
func (c *ChatInstance) GetMessages(props *adaptercommon.ChatProps) []Message {
converted := c.ConvertMessages(props)
return utils.Each(converted, func(message globals.Message) Message {
if !globals.IsVisionModel(props.Model) || message.Role != globals.User {
return Message{
Role: message.Role,
Content: message.Content,
}
}
content, urls := utils.ExtractImages(message.Content, true)
images := utils.EachNotNil(urls, func(url string) *MessageContent {
obj, err := utils.NewImage(url)
props.Buffer.AddImage(obj)
if err != nil {
globals.Info(fmt.Sprintf("cannot process image: %s (source: %s)", err.Error(), utils.Extract(url, 24, "...")))
}
i := utils.NewImageContent(url)
return &MessageContent{
Type: "image",
Source: &MessageImage{
Type: "base64",
MediaType: i.GetType(),
Data: i.ToRawBase64(),
},
}
})
return Message{
Role: message.Role,
Content: utils.Prepend(images, MessageContent{
Type: "text",
Text: &content,
}),
}
})
}
func (c *ChatInstance) GetSystemPrompt(props *adaptercommon.ChatProps) (prompt string) {
for _, message := range props.Message {
if message.Role == globals.System {
prompt += message.Content
}
}
return
}
func (c *ChatInstance) GetChatBody(props *adaptercommon.ChatProps, stream bool) *ChatBody {
messages := c.GetMessages(props)
return &ChatBody{
Messages: messages,
MaxTokens: c.GetTokens(props),
Model: props.Model,
System: c.GetSystemPrompt(props),
Stream: stream,
Temperature: props.Temperature,
TopP: props.TopP,
TopK: props.TopK,
}
}
func (c *ChatInstance) ProcessLine(data string) (*globals.Chunk, error) {
if form := processChatResponse(data); form != nil {
return &globals.Chunk{
Content: form.Delta.Text,
}, nil
}
if form := processChatErrorResponse(data); form != nil {
return &globals.Chunk{Content: ""}, fmt.Errorf("anthropic error: %s (type: %s)", form.Error.Message, form.Error.Type)
}
return &globals.Chunk{Content: ""}, nil
}
func processChatErrorResponse(data string) *ChatErrorResponse {
if form := utils.UnmarshalForm[ChatErrorResponse](data); form != nil {
return form
}
return nil
}
func processChatResponse(data string) *ChatStreamResponse {
if form := utils.UnmarshalForm[ChatStreamResponse](data); form != nil {
return form
}
return nil
}
// CreateStreamChatRequest is the stream request for anthropic claude
func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.ChatProps, hook globals.Hook) error {
err := utils.EventScanner(&utils.EventScannerProps{
Method: "POST",
Uri: c.GetChatEndpoint(),
Headers: c.GetChatHeaders(),
Body: c.GetChatBody(props, true),
Callback: func(data string) error {
partial, err := c.ProcessLine(data)
if err != nil {
return err
}
return hook(partial)
},
},
props.Proxy,
)
if err != nil {
if form := processChatErrorResponse(err.Body); form != nil {
if form.Error.Type == "" && form.Error.Message == "" {
return errors.New(utils.ToMarkdownCode("json", err.Body))
}
return errors.New(fmt.Sprintf("%s (type: %s)", form.Error.Message, form.Error.Type))
}
return fmt.Errorf("%s\n%s", err.Error, errors.New(utils.ToMarkdownCode("json", err.Body)))
}
return nil
}
================================================
FILE: adapter/claude/struct.go
================================================
package claude
import (
factory "chat/adapter/common"
"chat/globals"
)
type ChatInstance struct {
Endpoint string
ApiKey string
}
func NewChatInstance(endpoint, apiKey string) *ChatInstance {
return &ChatInstance{
Endpoint: endpoint,
ApiKey: apiKey,
}
}
func NewChatInstanceFromConfig(conf globals.ChannelConfig) factory.Factory {
return NewChatInstance(
conf.GetEndpoint(),
conf.GetRandomSecret(),
)
}
func (c *ChatInstance) GetEndpoint() string {
return c.Endpoint
}
func (c *ChatInstance) GetApiKey() string {
return c.ApiKey
}
================================================
FILE: adapter/claude/types.go
================================================
package claude
// ChatBody is the request body for anthropic claude
type Message struct {
Role string `json:"role"`
Content interface{} `json:"content"`
}
type MessageImage struct {
Type string `json:"type"`
MediaType interface{} `json:"media_type"`
Data interface{} `json:"data"`
}
type MessageContent struct {
Type string `json:"type"`
Text *string `json:"text,omitempty"`
Source *MessageImage `json:"source,omitempty"`
}
type ChatBody struct {
Messages []Message `json:"messages"`
MaxTokens int `json:"max_tokens"`
Model string `json:"model"`
System string `json:"system"`
Stream bool `json:"stream"`
Temperature *float32 `json:"temperature,omitempty"`
TopP *float32 `json:"top_p,omitempty"`
TopK *int `json:"top_k,omitempty"`
}
type ChatStreamResponse struct {
Type string `json:"type"`
Index int `json:"index"`
Delta struct {
Type string `json:"type"`
Text string `json:"text"`
} `json:"delta"`
}
type ChatErrorResponse struct {
Error struct {
Type string `json:"type" binding:"required"`
Message string `json:"message"`
} `json:"error"`
}
================================================
FILE: adapter/common/interface.go
================================================
package adaptercommon
import (
"chat/globals"
)
type Factory interface {
CreateStreamChatRequest(props *ChatProps, hook globals.Hook) error
}
type VideoFactory interface {
CreateVideoRequest(props *VideoProps, hook globals.Hook) error
}
type FactoryCreator func(globals.ChannelConfig) Factory
================================================
FILE: adapter/common/types.go
================================================
package adaptercommon
import (
"chat/globals"
"chat/utils"
)
type RequestProps struct {
MaxRetries *int `json:"-"`
Current int `json:"-"`
Group string `json:"-"`
Proxy globals.ProxyConfig `json:"-"`
}
type VideoProps struct {
RequestProps
Model string `json:"model,omitempty"`
OriginalModel string `json:"-"`
Prompt string `json:"prompt"`
Seconds *string `json:"seconds,omitempty"`
Size *string `json:"size,omitempty"`
InputReference *string `json:"input_reference,omitempty"`
User string `json:"-"`
}
type ChatProps struct {
RequestProps
Model string `json:"model,omitempty"`
OriginalModel string `json:"-"`
Message []globals.Message `json:"messages,omitempty"`
MaxTokens *int `json:"max_tokens,omitempty"`
PresencePenalty *float32 `json:"presence_penalty,omitempty"`
FrequencyPenalty *float32 `json:"frequency_penalty,omitempty"`
RepetitionPenalty *float32 `json:"repetition_penalty,omitempty"`
Temperature *float32 `json:"temperature,omitempty"`
TopP *float32 `json:"top_p,omitempty"`
TopK *int `json:"top_k,omitempty"`
Tools *globals.FunctionTools `json:"tools,omitempty"`
ToolChoice *interface{} `json:"tool_choice,omitempty"`
Buffer *utils.Buffer `json:"-"`
}
func (c *ChatProps) SetupBuffer(buf *utils.Buffer) {
buf.SetPrompts(c)
c.Buffer = buf
}
func CreateChatProps(props *ChatProps, buffer *utils.Buffer) *ChatProps {
props.SetupBuffer(buffer)
return props
}
func CreateVideoProps(props *VideoProps) *VideoProps {
return props
}
================================================
FILE: adapter/coze/chat.go
================================================
package coze
import (
adaptercommon "chat/adapter/common"
"chat/globals"
"chat/utils"
"encoding/json"
"errors"
"fmt"
"strings"
"sync"
"time"
)
type ChatInstance struct {
Endpoint string
ApiKey string
AutoSaveHistory bool
responseComplete bool
}
func (c *ChatInstance) GetEndpoint() string {
return c.Endpoint
}
func (c *ChatInstance) GetApiKey() string {
return c.ApiKey
}
func (c *ChatInstance) GetHeader() map[string]string {
return map[string]string{
"Content-Type": "application/json",
"Authorization": fmt.Sprintf("Bearer %s", c.GetApiKey()),
}
}
func NewChatInstance(endpoint, apiKey string) *ChatInstance {
return &ChatInstance{
Endpoint: endpoint,
ApiKey: apiKey,
AutoSaveHistory: false,
}
}
func NewChatInstanceFromConfig(conf globals.ChannelConfig) adaptercommon.Factory {
return NewChatInstance(
conf.GetEndpoint(),
conf.GetRandomSecret(),
)
}
func (c *ChatInstance) GetChatEndpoint() string {
return fmt.Sprintf("%s/v3/chat", c.GetEndpoint())
}
func (c *ChatInstance) GetChatBody(props *adaptercommon.ChatProps, stream bool) interface{} {
additionalMessages := []EnterMessage{}
for _, msg := range props.Message {
enterMsg := EnterMessage{
Role: msg.Role,
Content: msg.Content,
ContentType: "text",
}
if msg.Role == "user" {
enterMsg.Type = "question"
} else if msg.Role == "assistant" {
enterMsg.Type = "answer"
}
additionalMessages = append(additionalMessages, enterMsg)
}
// `user_id` is required in coze
timestamp := time.Now().UnixNano()
userID := fmt.Sprintf("user_%d", timestamp)
return ChatRequest{
BotID: props.Model,
UserID: userID,
AdditionalMessages: additionalMessages,
Stream: stream,
AutoSaveHistory: c.AutoSaveHistory,
}
}
func (c *ChatInstance) ProcessLine(data string) (string, error) {
if c.responseComplete {
return "", nil
}
if data == "" {
return "", nil
}
chunk, complete, err := processStreamResponse(data)
if err != nil {
return "", err
}
if complete {
c.responseComplete = true
}
return chunk.Content, nil
}
func (c *ChatInstance) CreateChatRequest(props *adaptercommon.ChatProps) (string, error) {
// TODO: use standard non-stream request
c.AutoSaveHistory = true
res, err := utils.Post(
c.GetChatEndpoint(),
c.GetHeader(),
c.GetChatBody(props, false),
props.Proxy,
)
if err != nil || res == nil {
return "", fmt.Errorf("coze error: %s", err.Error())
}
responseBody := utils.Marshal(res)
response := processChatResponse(responseBody)
if response == nil {
return "", fmt.Errorf("coze error: cannot parse response")
}
if response.Code != 0 {
return "", fmt.Errorf("coze error: %s (code: %d)", response.Msg, response.Code)
}
var responseContent string
var responseMutex sync.Mutex
err = c.CreateStreamChatRequest(props, func(chunk *globals.Chunk) error {
responseMutex.Lock()
defer responseMutex.Unlock()
responseContent += chunk.Content
return nil
})
if err != nil {
return "", err
}
if responseContent == "" {
return "", fmt.Errorf("coze error: empty response from API")
}
return responseContent, nil
}
func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.ChatProps, callback globals.Hook) error {
c.responseComplete = false
c.AutoSaveHistory = false
err := utils.EventScanner(&utils.EventScannerProps{
Method: "POST",
Uri: c.GetChatEndpoint(),
Headers: c.GetHeader(),
Body: c.GetChatBody(props, true),
FullSSE: true,
Callback: func(data string) error {
partial, err := c.ProcessLine(data)
if err != nil {
return err
}
if partial != "" {
err = callback(&globals.Chunk{Content: partial})
if err != nil {
return err
}
}
return nil
},
}, props.Proxy)
c.responseComplete = true
if err != nil {
if strings.Contains(err.Body, "\"code\":") {
errorResp := processChatErrorResponse(err.Body)
if errorResp != nil && errorResp.Data.Code != 0 {
return errors.New(fmt.Sprintf("coze error: %s (code: %d)", errorResp.Data.Msg, errorResp.Data.Code))
}
var genericResp map[string]interface{}
if jsonErr := json.Unmarshal([]byte(err.Body), &genericResp); jsonErr == nil {
errMsg, _ := json.Marshal(genericResp)
return errors.New(fmt.Sprintf("coze error: %s", string(errMsg)))
}
}
if err.Error != nil {
return err.Error
}
return errors.New(fmt.Sprintf("coze error: unexpected error in stream request"))
}
return nil
}
================================================
FILE: adapter/coze/processor.go
================================================
package coze
import (
"chat/globals"
"chat/utils"
"errors"
"fmt"
"strconv"
"strings"
)
func processChatResponse(data string) *ChatResponse {
if form := utils.UnmarshalForm[ChatResponse](data); form != nil {
return form
}
return nil
}
func processChatStreamResponse(data string) *ChatStreamResponse {
if form := utils.UnmarshalForm[ChatStreamResponse](data); form != nil {
return form
}
return nil
}
func processChatStreamData(data string) *ChatStreamData {
if form := utils.UnmarshalForm[ChatStreamData](data); form != nil {
return form
}
return nil
}
func processChatErrorResponse(data string) *ChatStreamErrorResponse {
if form := utils.UnmarshalForm[ChatStreamErrorResponse](data); form != nil {
return form
}
return nil
}
func processSSEData(data string) (event string, eventData string, err error) {
if data == "" {
return "", "", nil
}
sseLines := strings.Split(data, "\n")
for _, line := range sseLines {
line = strings.TrimSpace(line)
if strings.HasPrefix(line, "event:") {
event = strings.TrimSpace(strings.TrimPrefix(line, "event:"))
} else if strings.HasPrefix(line, "data:") {
eventData = strings.TrimSpace(strings.TrimPrefix(line, "data:"))
}
}
if eventData == "" {
return "", "", nil
}
if strings.HasPrefix(eventData, "\"") && strings.HasSuffix(eventData, "\"") && len(eventData) > 2 {
unquoted, err := strconv.Unquote(eventData)
if err == nil {
eventData = unquoted
}
}
return event, eventData, nil
}
func processEventContent(event string, eventData string) (content string, complete bool, err error) {
switch event {
case "conversation.message.delta":
content, _ := parseEventContent(event, eventData)
if content != "" {
return content, false, nil
}
streamData := processChatStreamData(eventData)
if streamData != nil && streamData.Type == "answer" && streamData.Role == "assistant" && streamData.Content != "" {
return streamData.Content, false, nil
}
case "conversation.message.completed":
return "", false, nil
case "conversation.chat.completed":
return "", true, nil
case "conversation.chat.failed":
streamData := processChatStreamData(eventData)
if streamData != nil {
if streamData.Code != 0 && streamData.Msg != "" {
return "", false, errors.New(fmt.Sprintf("coze error: %s (code: %d)", streamData.Msg, streamData.Code))
}
}
return "", false, errors.New("coze error: conversation failed")
case "done":
return "", true, nil
}
errorResp := processChatErrorResponse(eventData)
if errorResp != nil && errorResp.Data.Code != 0 {
return "", false, errors.New(fmt.Sprintf("coze error: %s (code: %d)", errorResp.Data.Msg, errorResp.Data.Code))
}
streamData := processChatStreamData(eventData)
if streamData != nil {
if streamData.Code != 0 && streamData.Msg != "" {
return "", false, errors.New(fmt.Sprintf("coze error: %s (code: %d)", streamData.Msg, streamData.Code))
}
if streamData.LastError.Code != 0 && streamData.LastError.Msg != "" {
return "", false, errors.New(fmt.Sprintf("coze error: %s (code: %d)", streamData.LastError.Msg, streamData.LastError.Code))
}
}
return "", false, nil
}
func parseEventContent(eventType string, eventData string) (string, error) {
if eventType == "conversation.message.delta" {
streamResp := processChatStreamResponse(fmt.Sprintf(`{"event":"%s","data":%s}`, eventType, eventData))
if streamResp != nil {
streamData := processChatStreamData(streamResp.Data)
if streamData != nil && streamData.Type == "answer" && streamData.Role == "assistant" && streamData.Content != "" {
return streamData.Content, nil
}
}
}
return "", nil
}
func processStreamResponse(data string) (*globals.Chunk, bool, error) {
event, eventData, err := processSSEData(data)
if err != nil {
return nil, false, err
}
if event == "" || eventData == "" {
return &globals.Chunk{Content: ""}, false, nil
}
content, complete, err := processEventContent(event, eventData)
if err != nil {
return nil, false, err
}
return &globals.Chunk{
Content: content,
}, complete, nil
}
================================================
FILE: adapter/coze/struct.go
================================================
package coze
type ChatRequest struct {
BotID string `json:"bot_id"`
UserID string `json:"user_id"`
AdditionalMessages []EnterMessage `json:"additional_messages,omitempty"`
Stream bool `json:"stream"`
CustomVariables map[string]string `json:"custom_variables,omitempty"`
AutoSaveHistory bool `json:"auto_save_history"`
MetaData map[string]string `json:"meta_data,omitempty"`
ExtraParams map[string]string `json:"extra_params,omitempty"`
ShortcutCommand *ShortcutCommand `json:"shortcut_command,omitempty"`
}
type EnterMessage struct {
Role string `json:"role"`
Type string `json:"type,omitempty"`
Content string `json:"content,omitempty"`
ContentType string `json:"content_type,omitempty"`
MetaData map[string]string `json:"meta_data,omitempty"`
}
type ShortcutCommand struct {
// TODO: support for adding this on demand
}
type ObjectString struct {
Type string `json:"type"`
Text string `json:"text,omitempty"`
FileID string `json:"file_id,omitempty"`
FileURL string `json:"file_url,omitempty"`
}
type ChatResponse struct {
Data struct {
ID string `json:"id"`
ConversationID string `json:"conversation_id"`
BotID string `json:"bot_id"`
CreatedAt int64 `json:"created_at"`
CompletedAt int64 `json:"completed_at"`
LastError interface{} `json:"last_error"`
MetaData map[string]string `json:"meta_data"`
Status string `json:"status"`
Usage *Usage `json:"usage"`
} `json:"data"`
Code int `json:"code"`
Msg string `json:"msg"`
}
type Usage struct {
TokenCount int `json:"token_count"`
OutputTokens int `json:"output_tokens"`
InputTokens int `json:"input_tokens"`
}
type ChatStreamResponse struct {
Event string `json:"event"`
Data string `json:"data"`
}
type ChatStreamData struct {
ID string `json:"id,omitempty"`
Role string `json:"role,omitempty"`
Type string `json:"type,omitempty"`
Content string `json:"content,omitempty"`
ContentType string `json:"content_type,omitempty"`
ChatID string `json:"chat_id,omitempty"`
ConversationID string `json:"conversation_id,omitempty"`
BotID string `json:"bot_id,omitempty"`
SectionID string `json:"section_id,omitempty"`
CreatedAt int64 `json:"created_at,omitempty"`
CompletedAt int64 `json:"completed_at,omitempty"`
UpdatedAt int64 `json:"updated_at,omitempty"`
Status string `json:"status,omitempty"`
LastError struct {
Code int `json:"code"`
Msg string `json:"msg"`
} `json:"last_error,omitempty"`
Code int `json:"code"`
Msg string `json:"msg"`
Usage *Usage `json:"usage,omitempty"`
MetaData map[string]string `json:"meta_data,omitempty"`
FromModule interface{} `json:"from_module,omitempty"`
FromUnit interface{} `json:"from_unit,omitempty"`
}
type ChatStreamErrorResponse struct {
Event string `json:"event"`
Data struct {
Code int `json:"code"`
Msg string `json:"msg"`
} `json:"data"`
}
================================================
FILE: adapter/dashscope/chat.go
================================================
package dashscope
import (
adaptercommon "chat/adapter/common"
"chat/globals"
"chat/utils"
"fmt"
"strings"
)
const defaultMaxTokens = 1500
func (c *ChatInstance) GetHeader() map[string]string {
return map[string]string{
"Content-Type": "application/json",
"Authorization": fmt.Sprintf("Bearer %s", c.GetApiKey()),
"X-DashScope-SSE": "enable",
}
}
func (c *ChatInstance) FormatMessages(message []globals.Message) []Message {
var messages []Message
var start bool
for _, v := range message {
if v.Role == globals.Tool {
continue
}
if !start {
start = true
// dashscope first message should be [`user`, `system`] role, convert other roles to `user`
if v.Role != globals.User && v.Role != globals.System {
v.Role = globals.User
}
}
messages = append(messages, Message{
Role: v.Role,
Content: v.Content,
})
}
return messages
}
func (c *ChatInstance) GetMaxTokens(props *adaptercommon.ChatProps) int {
// dashscope has a restriction of 1500 tokens in completion
if props.MaxTokens == nil || *props.MaxTokens <= 0 || *props.MaxTokens > 1500 {
return defaultMaxTokens
}
return *props.MaxTokens
}
func (c *ChatInstance) GetTopP(props *adaptercommon.ChatProps) *float32 {
// range of top_p should be (0.0, 1.0)
if props.TopP == nil {
return nil
}
if *props.TopP <= 0.0 {
return utils.ToPtr[float32](0.1)
} else if *props.TopP >= 1.0 {
return utils.ToPtr[float32](0.9)
}
return props.TopP
}
func (c *ChatInstance) GetRepeatPenalty(props *adaptercommon.ChatProps) *float32 {
// range of repetition_penalty should greater than 0.0
if props.RepetitionPenalty == nil {
return nil
}
if *props.RepetitionPenalty <= 0.0 {
return utils.ToPtr[float32](0.1)
}
return props.RepetitionPenalty
}
func (c *ChatInstance) GetChatBody(props *adaptercommon.ChatProps) ChatRequest {
return ChatRequest{
Model: strings.TrimSuffix(props.Model, "-net"),
Input: ChatInput{
Messages: c.FormatMessages(props.Message),
},
Parameters: ChatParam{
MaxTokens: c.GetMaxTokens(props),
Temperature: props.Temperature,
TopP: c.GetTopP(props),
TopK: props.TopK,
RepetitionPenalty: c.GetRepeatPenalty(props),
EnableSearch: utils.ToPtr(strings.HasSuffix(props.Model, "-net")),
IncrementalOutput: true,
},
}
}
func (c *ChatInstance) GetChatEndpoint() string {
return fmt.Sprintf("%s/api/v1/services/aigc/text-generation/generation", c.Endpoint)
}
func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.ChatProps, callback globals.Hook) error {
return utils.EventSource(
"POST",
c.GetChatEndpoint(),
c.GetHeader(),
c.GetChatBody(props),
func(data string) error {
// example:
// id:1
// event:result
// :HTTP_STATUS/200
// data:{"output":{"finish_reason":"null","text":"hi"},"usage":{"total_tokens":15,"input_tokens":14,"output_tokens":1},"request_id":"08da1369-e009-9f8f-8363-54b966f80daf"}
data = strings.TrimSpace(data)
if !strings.HasPrefix(data, "data:") {
return nil
}
slice := strings.TrimSpace(strings.TrimPrefix(data, "data:"))
if form := utils.UnmarshalForm[ChatResponse](slice); form != nil {
if form.Output.Text == "" && form.Message != "" {
return fmt.Errorf("dashscope error: %s", form.Message)
}
if err := callback(&globals.Chunk{Content: form.Output.Text}); err != nil {
return err
}
return nil
}
globals.Debug(fmt.Sprintf("dashscope error: cannot unmarshal data %s", slice))
return nil
},
props.Proxy,
)
}
================================================
FILE: adapter/dashscope/struct.go
================================================
package dashscope
import (
factory "chat/adapter/common"
"chat/globals"
)
type ChatInstance struct {
Endpoint string
ApiKey string
}
func (c *ChatInstance) GetApiKey() string {
return c.ApiKey
}
func (c *ChatInstance) GetEndpoint() string {
return c.Endpoint
}
func NewChatInstance(endpoint string, apiKey string) *ChatInstance {
return &ChatInstance{
Endpoint: endpoint,
ApiKey: apiKey,
}
}
func NewChatInstanceFromConfig(conf globals.ChannelConfig) factory.Factory {
return NewChatInstance(
conf.GetEndpoint(),
conf.GetRandomSecret(),
)
}
================================================
FILE: adapter/dashscope/types.go
================================================
package dashscope
// ChatRequest is the request body for dashscope
type ChatRequest struct {
Model string `json:"model"`
Input ChatInput `json:"input"`
Parameters ChatParam `json:"parameters"`
}
type Message struct {
Role string `json:"role"`
Content string `json:"content"`
}
type ChatInput struct {
Messages []Message `json:"messages"`
}
type ChatParam struct {
IncrementalOutput bool `json:"incremental_output"`
EnableSearch *bool `json:"enable_search,omitempty"`
MaxTokens int `json:"max_tokens"`
Temperature *float32 `json:"temperature,omitempty"`
TopP *float32 `json:"top_p,omitempty"`
TopK *int `json:"top_k,omitempty"`
RepetitionPenalty *float32 `json:"repetition_penalty,omitempty"`
}
// ChatResponse is the response body for dashscope
type ChatResponse struct {
Output struct {
FinishReason string `json:"finish_reason"`
Text string `json:"text"`
} `json:"output"`
RequestId string `json:"request_id"`
Usage struct {
InputTokens int `json:"input_tokens"`
OutputTokens int `json:"output_tokens"`
} `json:"usage"`
Message string `json:"message"`
}
================================================
FILE: adapter/deepseek/chat.go
================================================
package deepseek
import (
adaptercommon "chat/adapter/common"
"chat/globals"
"chat/utils"
"errors"
"fmt"
)
type ChatInstance struct {
Endpoint string
ApiKey string
isFirstReasoning bool
isReasonOver bool
}
func (c *ChatInstance) GetEndpoint() string {
return c.Endpoint
}
func (c *ChatInstance) GetApiKey() string {
return c.ApiKey
}
func (c *ChatInstance) GetHeader() map[string]string {
return map[string]string{
"Content-Type": "application/json",
"Authorization": fmt.Sprintf("Bearer %s", c.GetApiKey()),
}
}
func NewChatInstance(endpoint, apiKey string) *ChatInstance {
return &ChatInstance{
Endpoint: endpoint,
ApiKey: apiKey,
isFirstReasoning: true,
}
}
func NewChatInstanceFromConfig(conf globals.ChannelConfig) adaptercommon.Factory {
return NewChatInstance(
conf.GetEndpoint(),
conf.GetRandomSecret(),
)
}
func (c *ChatInstance) GetChatEndpoint() string {
return fmt.Sprintf("%s/chat/completions", c.GetEndpoint())
}
func (c *ChatInstance) GetChatBody(props *adaptercommon.ChatProps, stream bool) interface{} {
messages := props.Message
// because of deepseek first message must be user role
// convert assistant message to user message
if len(messages) > 0 && messages[0].Role == globals.Assistant {
messages = make([]globals.Message, len(props.Message))
copy(messages, props.Message)
messages[0].Role = globals.User
}
return ChatRequest{
Model: props.Model,
Messages: messages,
MaxTokens: props.MaxTokens,
Stream: stream,
Temperature: props.Temperature,
TopP: props.TopP,
PresencePenalty: props.PresencePenalty,
FrequencyPenalty: props.FrequencyPenalty,
}
}
func processChatResponse(data string) *ChatResponse {
if form := utils.UnmarshalForm[ChatResponse](data); form != nil {
return form
}
return nil
}
func processChatStreamResponse(data string) *ChatStreamResponse {
if form := utils.UnmarshalForm[ChatStreamResponse](data); form != nil {
return form
}
return nil
}
func processChatErrorResponse(data string) *ChatStreamErrorResponse {
if form := utils.UnmarshalForm[ChatStreamErrorResponse](data); form != nil {
return form
}
return nil
}
func (c *ChatInstance) ProcessLine(data string) (string, error) {
if form := processChatStreamResponse(data); form != nil {
if len(form.Choices) == 0 {
return "", nil
}
delta := form.Choices[0].Delta
if c.isFirstReasoning == false && !c.isReasonOver && delta.ReasoningContent == nil {
c.isReasonOver = true
if delta.Content != "" {
return fmt.Sprintf("\n</think>\n\n%s", delta.Content), nil
}
return "\n</think>\n\n", nil
}
if delta.ReasoningContent != nil {
content := *delta.ReasoningContent
if c.isFirstReasoning {
c.isFirstReasoning = false
return fmt.Sprintf("<think>\n%s", content), nil
}
return content, nil
}
return delta.Content, nil
}
if form := processChatErrorResponse(data); form != nil {
if form.Error.Message != "" {
return "", errors.New(fmt.Sprintf("deepseek error: %s", form.Error.Message))
}
}
return "", nil
}
func (c *ChatInstance) CreateChatRequest(props *adaptercommon.ChatProps) (string, error) {
res, err := utils.Post(
c.GetChatEndpoint(),
c.GetHeader(),
c.GetChatBody(props, false),
props.Proxy,
)
if err != nil || res == nil {
return "", fmt.Errorf("deepseek error: %s", err.Error())
}
data := utils.MapToStruct[ChatResponse](res)
if data == nil {
return "", fmt.Errorf("deepseek error: cannot parse response")
}
if len(data.Choices) == 0 {
return "", fmt.Errorf("deepseek error: no choices")
}
message := data.Choices[0].Message
content := message.Content
if message.ReasoningContent != nil {
content = fmt.Sprintf("<think>\n%s\n</think>\n\n%s", *message.ReasoningContent, content)
}
return content, nil
}
func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.ChatProps, callback globals.Hook) error {
c.isFirstReasoning = true
c.isReasonOver = false
err := utils.EventScanner(&utils.EventScannerProps{
Method: "POST",
Uri: c.GetChatEndpoint(),
Headers: c.GetHeader(),
Body: c.GetChatBody(props, true),
Callback: func(data string) error {
partial, err := c.ProcessLine(data)
if err != nil {
return err
}
return callback(&globals.Chunk{Content: partial})
},
}, props.Proxy)
if err != nil {
if form := processChatErrorResponse(err.Body); form != nil {
if form.Error.Type == "" && form.Error.Message == "" {
return errors.New(utils.ToMarkdownCode("json", err.Body))
}
return errors.New(fmt.Sprintf("deepseek error: %s (type: %s)", form.Error.Message, form.Error.Type))
}
return err.Error
}
return nil
}
================================================
FILE: adapter/deepseek/struct.go
================================================
package deepseek
import (
"chat/globals"
)
// DeepSeek API is similar to OpenAI API with additional reasoning content
type ChatRequest struct {
Model string `json:"model"`
Messages []globals.Message `json:"messages"`
MaxTokens *int `json:"max_tokens,omitempty"`
Stream bool `json:"stream"`
Temperature *float32 `json:"temperature,omitempty"`
TopP *float32 `json:"top_p,omitempty"`
PresencePenalty *float32 `json:"presence_penalty,omitempty"`
FrequencyPenalty *float32 `json:"frequency_penalty,omitempty"`
}
// ChatResponse is the native http request body for deepseek
type ChatResponse struct {
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
Model string `json:"model"`
Choices []struct {
Index int `json:"index"`
Message globals.Message `json:"message"`
FinishReason string `json:"finish_reason"`
} `json:"choices"`
Usage struct {
PromptTokens int `json:"prompt_tokens"`
CompletionTokens int `json:"completion_tokens"`
TotalTokens int `json:"total_tokens"`
} `json:"usage"`
}
// ChatStreamResponse is the stream response body for deepseek
type ChatStreamResponse struct {
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
Model string `json:"model"`
Choices []struct {
Delta globals.Message `json:"delta"`
Index int `json:"index"`
FinishReason string `json:"finish_reason"`
} `json:"choices"`
}
type ChatStreamErrorResponse struct {
Error struct {
Message string `json:"message"`
Type string `json:"type"`
} `json:"error"`
}
================================================
FILE: adapter/dify/chat.go
================================================
package dify
import (
adaptercommon "chat/adapter/common"
"chat/globals"
"chat/utils"
"encoding/json"
"errors"
"fmt"
"strings"
"time"
)
type ChatInstance struct {
Endpoint string
ApiKey string
responseComplete bool
}
func (c *ChatInstance) GetEndpoint() string {
return c.Endpoint
}
func (c *ChatInstance) GetApiKey() string {
return c.ApiKey
}
func (c *ChatInstance) GetHeader() map[string]string {
return map[string]string{
"Content-Type": "application/json",
"Authorization": fmt.Sprintf("Bearer %s", c.GetApiKey()),
}
}
func NewChatInstance(endpoint, apiKey string) *ChatInstance {
return &ChatInstance{
Endpoint: endpoint,
ApiKey: apiKey,
}
}
func NewChatInstanceFromConfig(conf globals.ChannelConfig) adaptercommon.Factory {
return NewChatInstance(
conf.GetEndpoint(),
conf.GetRandomSecret(),
)
}
func (c *ChatInstance) GetChatEndpoint() string {
return fmt.Sprintf("%s/chat-messages", c.GetEndpoint())
}
func (c *ChatInstance) GetChatBody(props *adaptercommon.ChatProps, stream bool) interface{} {
timestamp := time.Now().UnixNano()
userID := fmt.Sprintf("user_%d", timestamp)
query := ""
for _, msg := range props.Message {
if msg.Role == "user" {
query = msg.Content
break
}
}
return ChatRequest{
Inputs: map[string]interface{}{},
Query: query,
ResponseMode: "streaming",
User: userID,
AutoGenerateName: true,
}
}
func (c *ChatInstance) ProcessLine(data string) (string, error) {
if c.responseComplete {
return "", nil
}
if data == "" {
return "", nil
}
chunk, complete, err := processStreamResponse(data)
if err != nil {
return "", err
}
if complete {
c.responseComplete = true
}
return chunk.Content, nil
}
func (c *ChatInstance) CreateChatRequest(props *adaptercommon.ChatProps) (string, error) {
res, err := utils.Post(
c.GetChatEndpoint(),
c.GetHeader(),
c.GetChatBody(props, false),
props.Proxy,
)
if err != nil || res == nil {
return "", fmt.Errorf("dify error: %s", err.Error())
}
responseBody := utils.Marshal(res)
response := processChatResponse(responseBody)
if response == nil {
return "", fmt.Errorf("dify error: cannot parse response")
}
return response.Answer, nil
}
func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.ChatProps, callback globals.Hook) error {
c.responseComplete = false
err := utils.EventScanner(&utils.EventScannerProps{
Method: "POST",
Uri: c.GetChatEndpoint(),
Headers: c.GetHeader(),
Body: c.GetChatBody(props, true),
Callback: func(data string) error {
partial, err := c.ProcessLine(data)
if err != nil {
return err
}
if partial != "" {
err = callback(&globals.Chunk{Content: partial})
if err != nil {
return err
}
}
return nil
},
}, props.Proxy)
c.responseComplete = true
if err != nil {
if strings.Contains(err.Body, "\"code\":") {
errorResp := processChatErrorResponse(err.Body)
if errorResp != nil {
return errors.New(fmt.Sprintf("dify error: %s (code: %s)", errorResp.Message, errorResp.Code))
}
var genericResp map[string]interface{}
if jsonErr := json.Unmarshal([]byte(err.Body), &genericResp); jsonErr == nil {
errMsg, _ := json.Marshal(genericResp)
return errors.New(fmt.Sprintf("dify error: %s", string(errMsg)))
}
}
if err.Error != nil {
return err.Error
}
return errors.New(fmt.Sprintf("dify error: unexpected error in stream request"))
}
return nil
}
================================================
FILE: adapter/dify/processor.go
================================================
package dify
import (
"chat/globals"
"chat/utils"
"errors"
"fmt"
)
func processChatResponse(data string) *ChatResponse {
if form := utils.UnmarshalForm[ChatResponse](data); form != nil {
return form
}
return nil
}
func processChatStreamResponse(data string) *ChatStreamResponse {
if form := utils.UnmarshalForm[ChatStreamResponse](data); form != nil {
return form
}
return nil
}
func processChatErrorResponse(data string) *ChatStreamErrorResponse {
if form := utils.UnmarshalForm[ChatStreamErrorResponse](data); form != nil {
return form
}
return nil
}
func processStreamResponse(data string) (*globals.Chunk, bool, error) {
if data == "" {
return &globals.Chunk{Content: ""}, false, nil
}
streamData := processChatStreamResponse(data)
if streamData == nil {
return &globals.Chunk{Content: ""}, false, nil
}
switch streamData.Event {
case "message":
if streamData.Answer != "" {
return &globals.Chunk{
Content: streamData.Answer,
}, false, nil
}
case "message_end":
return &globals.Chunk{
Content: "",
}, true, nil
case "error":
if streamData.Code != "" && streamData.Message != "" {
return nil, false, errors.New(fmt.Sprintf("dify error: %s (code: %s)", streamData.Message, streamData.Code))
}
return nil, false, errors.New("dify error: conversation failed")
case "workflow_started", "node_started", "node_finished", "workflow_finished", "iteration_started", "iteration_next", "iteration_finished", "iteration_completed", "parallel_branch_started", "parallel_branch_finished", "ping":
return &globals.Chunk{Content: ""}, false, nil
}
errorResp := processChatErrorResponse(data)
if errorResp != nil {
return nil, false, errors.New(fmt.Sprintf("dify error: %s (code: %s)", errorResp.Message, errorResp.Code))
}
return &globals.Chunk{Content: ""}, false, nil
}
================================================
FILE: adapter/dify/struct.go
================================================
package dify
type ChatRequest struct {
Inputs map[string]interface{} `json:"inputs"`
Query string `json:"query"`
ResponseMode string `json:"response_mode"`
ConversationID string `json:"conversation_id,omitempty"`
User string `json:"user"`
Files []File `json:"files,omitempty"`
AutoGenerateName bool `json:"auto_generate_name,omitempty"`
}
type File struct {
Type string `json:"type"`
TransferMethod string `json:"transfer_method"`
URL string `json:"url,omitempty"`
UploadFileID string `json:"upload_file_id,omitempty"`
}
type ChatResponse struct {
MessageID string `json:"message_id"`
ConversationID string `json:"conversation_id"`
Mode string `json:"mode"`
Answer string `json:"answer"`
Metadata map[string]interface{} `json:"metadata"`
Usage Usage `json:"usage"`
RetrieverResources []RetrieverResource `json:"retriever_resources"`
CreatedAt int64 `json:"created_at"`
}
type Usage struct {
TokenCount int `json:"token_count"`
OutputTokens int `json:"output_tokens"`
InputTokens int `json:"input_tokens"`
}
type RetrieverResource struct {
SegmentID string `json:"segment_id"`
Content string `json:"content"`
Source string `json:"source"`
}
type ChatStreamResponse struct {
Event string `json:"event"`
TaskID string `json:"task_id"`
MessageID string `json:"message_id,omitempty"`
ConversationID string `json:"conversation_id,omitempty"`
Answer string `json:"answer,omitempty"`
CreatedAt int64 `json:"created_at,omitempty"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
Usage *Usage `json:"usage,omitempty"`
RetrieverResources []RetrieverResource `json:"retriever_resources,omitempty"`
Audio string `json:"audio,omitempty"`
Status int `json:"status,omitempty"`
Code string `json:"code,omitempty"`
Message string `json:"message,omitempty"`
}
type ChatStreamErrorResponse struct {
Event string `json:"event"`
TaskID string `json:"task_id"`
MessageID string `json:"message_id"`
Status int `json:"status"`
Code string `json:"code"`
Message string `json:"message"`
}
================================================
FILE: adapter/hunyuan/chat.go
================================================
package hunyuan
import (
adaptercommon "chat/adapter/common"
"chat/globals"
"context"
"fmt"
)
func (c *ChatInstance) FormatMessages(messages []globals.Message) []globals.Message {
var result []globals.Message
for _, message := range messages {
switch message.Role {
case globals.System:
result = append(result, globals.Message{Role: globals.User, Content: message.Content})
case globals.Assistant, globals.User:
bound := len(result) > 0 && result[len(result)-1].Role == message.Role
if bound {
result[len(result)-1].Content += message.Content
} else {
result = append(result, message)
}
case globals.Tool:
continue
default:
result = append(result, message)
}
}
return result
}
func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.ChatProps, callback globals.Hook) error {
credential := NewCredential(c.GetSecretId(), c.GetSecretKey())
client := NewInstance(c.GetAppId(), c.GetEndpoint(), credential)
channel, err := client.Chat(context.Background(), NewRequest(Stream, c.FormatMessages(props.Message), props.Temperature, props.TopP))
if err != nil {
return fmt.Errorf("tencent hunyuan error: %+v", err)
}
for chunk := range channel {
if chunk.Error.Code != 0 {
fmt.Printf("tencent hunyuan error: %+v\n", chunk.Error)
break
}
if len(chunk.Choices) == 0 {
continue
}
choice := chunk.Choices[0].Delta
if err := callback(&globals.Chunk{Content: choice.Content}); err != nil {
return err
}
}
return nil
}
================================================
FILE: adapter/hunyuan/sdk.go
================================================
package hunyuan
/*
* Copyright (c) 2017-2018 THL A29 Limited, a Tencent company. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import (
"bufio"
"bytes"
"chat/globals"
"context"
"crypto/hmac"
"crypto/sha1"
"encoding/base64"
"encoding/json"
"fmt"
"github.com/google/uuid"
"io"
"net/http"
"sort"
"strconv"
"strings"
"time"
)
const (
defaultProtocol = "https"
defaultHost = "hunyuan.cloud.tencent.com"
path = "/hyllm/v1/chat/completions?"
)
const (
Synchronize = iota
Stream
)
func getUrl(endpoint string) string {
return fmt.Sprintf("%s://%s%s", getProtocol(endpoint), getHost(endpoint), path)
}
func getProtocol(endpoint string) string {
seg := strings.Split(endpoint, "://")
if len(seg) > 0 && seg[0] != "" {
return seg[0]
}
return defaultProtocol
}
func getHost(endpoint string) string {
seg := strings.Split(endpoint, "://")
if len(seg) > 1 && seg[1] != "" {
return seg[1]
}
return defaultHost
}
func getFullPath(endpoint string) string {
return getHost(endpoint) + path
}
type ResponseChoices struct {
FinishReason string `json:"finish_reason,omitempty"`
Messages []globals.Message `json:"messages,omitempty"`
Delta globals.Message `json:"delta,omitempty"`
}
type ResponseUsage struct {
PromptTokens int64 `json:"prompt_tokens,omitempty"`
TotalTokens int64 `json:"total_tokens,omitempty"`
CompletionTokens int64 `json:"completion_tokens,omitempty"`
}
type ResponseError struct {
Message string `json:"message,omitempty"`
Code int `json:"code,omitempty"`
}
type StreamDelta struct {
Content string `json:"content"`
}
type ChatRequest struct {
AppID int64 `json:"app_id"`
SecretID string `json:"secret_id"`
Timestamp int `json:"timestamp"`
Expired int `json:"expired"`
QueryID string `json:"query_id"`
Temperature float64 `json:"temperature"`
TopP float64 `json:"top_p"`
Stream int `json:"stream"`
Messages []globals.Message `json:"messages"`
}
type ChatResponse struct {
Choices []ResponseChoices `json:"choices,omitempty"`
Created string `json:"created,omitempty"`
ID string `json:"id,omitempty"`
Usage ResponseUsage `json:"usage,omitempty"`
Error ResponseError `json:"error,omitempty"`
Note string `json:"note,omitempty"`
ReqID string `json:"req_id,omitempty"`
}
type Credential struct {
SecretID string
SecretKey string
}
func NewCredential(secretID, secretKey string) *Credential {
return &Credential{SecretID: secretID, SecretKey: secretKey}
}
type Client struct {
Credential *Credential
AppID int64
EndPoint string
}
func NewInstance(appId int64, endpoint string, credential *Credential) *Client {
return &Client{
Credential: credential,
AppID: appId,
EndPoint: endpoint,
}
}
func NewRequest(mod int, messages []globals.Message, temperature *float32, topP *float32) ChatRequest {
queryID := uuid.NewString()
return ChatRequest{
Timestamp: int(time.Now().Unix()),
Expired: int(time.Now().Unix()) + 24*60*60,
Temperature: 0,
TopP: 0.8,
Messages: messages,
QueryID: queryID,
Stream: mod,
}
}
func (t *Client) getHttpReq(ctx context.Context, req ChatRequest) (*http.Request, error) {
req.AppID = t.AppID
req.SecretID = t.Credential.SecretID
signatureUrl := t.buildURL(req)
signature := t.genSignature(signatureUrl)
body, err := json.Marshal(req)
if err != nil {
return nil, fmt.Errorf("json marshal err: %+v", err)
}
httpReq, err := http.NewRequestWithContext(ctx, "POST", getUrl(t.EndPoint), bytes.NewReader(body))
if err != nil {
return nil, fmt.Errorf("new http request err: %+v", err)
}
httpReq.Header.Set("Authorization", signature)
httpReq.Header.Set("Content-Type", "application/json")
if req.Stream == Stream {
httpReq.Header.Set("Cache-Control", "no-cache")
httpReq.Header.Set("Connection", "keep-alive")
httpReq.Header.Set("Accept", "text/event-Stream")
}
return httpReq, nil
}
func (t *Client) Chat(ctx context.Context, req ChatRequest) (<-chan ChatResponse, error) {
res := make(chan ChatResponse, 1)
httpReq, err := t.getHttpReq(ctx, req)
if err != nil {
return nil, fmt.Errorf("do general http request err: %+v", err)
}
httpResp, err := http.DefaultClient.Do(httpReq)
if err != nil {
return nil, fmt.Errorf("do chat request err: %+v", err)
}
if httpResp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("do chat request failed status code :%d", httpResp.StatusCode)
}
if req.Stream == Synchronize {
err = t.synchronize(httpResp, res)
return res, err
}
go t.stream(httpResp, res)
return res, nil
}
func (t *Client) synchronize(httpResp *http.Response, res chan ChatResponse) (err error) {
defer func() {
httpResp.Body.Close()
close(res)
}()
var chatResp ChatResponse
respBody, err := io.ReadAll(httpResp.Body)
if err != nil {
return fmt.Errorf("read response body err: %+v", err)
}
if err = json.Unmarshal(respBody, &chatResp); err != nil {
return fmt.Errorf("json unmarshal err: %+v", err)
}
res <- chatResp
return
}
func (t *Client) stream(httpResp *http.Response, res chan ChatResponse) {
defer func() {
httpResp.Body.Close()
close(res)
}()
reader := bufio.NewReader(httpResp.Body)
for {
raw, err := reader.ReadBytes('\n')
if err != nil {
if err == io.EOF {
return
}
res <- ChatResponse{Error: ResponseError{Message: fmt.Sprintf("tencent error: read stream data failed: %+v", err), Code: 500}}
return
}
data := strings.TrimSpace(string(raw))
if data == "" || !strings.HasPrefix(data, "data: ") {
continue
}
var chatResponse ChatResponse
if err := json.Unmarshal([]byte(data[6:]), &chatResponse); err != nil {
res <- ChatResponse{Error: ResponseError{Message: fmt.Sprintf("json unmarshal err: %+v", err), Code: 500}}
return
}
res <- chatResponse
if chatResponse.Choices[0].FinishReason == "stop" {
return
}
}
}
func (t *Client) genSignature(url string) string {
mac := hmac.New(sha1.New, []byte(t.Credential.SecretKey))
signURL := url
mac.Write([]byte(signURL))
sign := mac.Sum([]byte(nil))
return base64.StdEncoding.EncodeToString(sign)
}
func (t *Client) getMessages(messages []globals.Message) string {
var message string
for _, msg := range messages {
message += fmt.Sprintf(`{"role":"%s","content":"%s"},`, msg.Role, msg.Content)
}
message = strings.TrimSuffix(message, ",")
return message
}
func (t *Client) buildURL(req ChatRequest) string {
params := make([]string, 0)
params = append(params, "app_id="+strconv.FormatInt(req.AppID, 10))
params = append(params, "secret_id="+req.SecretID)
params = append(params, "timestamp="+strconv.Itoa(req.Timestamp))
params = append(params, "query_id="+req.QueryID)
params = append(params, "temperature="+strconv.FormatFloat(req.Temperature, 'f', -1, 64))
params = append(params, "top_p="+strconv.FormatFloat(req.TopP, 'f', -1, 64))
params = append(params, "stream="+strconv.Itoa(req.Stream))
params = append(params, "expired="+strconv.Itoa(req.Expired))
params = append(params, fmt.Sprintf("messages=[%s]", t.getMessages(req.Messages)))
sort.Sort(sort.StringSlice(params))
return getFullPath(t.EndPoint) + strings.Join(params, "&")
}
================================================
FILE: adapter/hunyuan/struct.go
================================================
package hunyuan
import (
factory "chat/adapter/common"
"chat/globals"
"chat/utils"
)
type ChatInstance struct {
Endpoint string
AppId int64
SecretId string
SecretKey string
}
func (c *ChatInstance) GetAppId() int64 {
return c.AppId
}
func (c *ChatInstance) GetEndpoint() string {
return c.Endpoint
}
func (c *ChatInstance) GetSecretId() string {
return c.SecretId
}
func (c *ChatInstance) GetSecretKey() string {
return c.SecretKey
}
func NewChatInstance(endpoint, appId, secretId, secretKey string) *ChatInstance {
return &ChatInstance{
Endpoint: endpoint,
AppId: utils.ParseInt64(appId),
SecretId: secretId,
SecretKey: secretKey,
}
}
func NewChatInstanceFromConfig(conf globals.ChannelConfig) factory.Factory {
params := conf.SplitRandomSecret(3)
return NewChatInstance(
conf.GetEndpoint(),
params[0], params[1], params[2],
)
}
================================================
FILE: adapter/midjourney/api.go
================================================
package midjourney
import (
"chat/globals"
"chat/utils"
"fmt"
)
func (c *ChatInstance) GetImagineEndpoint() string {
return fmt.Sprintf("%s/mj/submit/imagine", c.GetEndpoint())
}
func (c *ChatInstance) GetChangeEndpoint() string {
return fmt.Sprintf("%s/mj/submit/change", c.GetEndpoint())
}
func (c *ChatInstance) GetImagineRequest(prompt string) *ImagineRequest {
return &ImagineRequest{
NotifyHook: c.GetNotifyEndpoint(),
Prompt: prompt,
}
}
func (c *ChatInstance) GetChangeRequest(action string, task string, index *int) *ChangeRequest {
return &ChangeRequest{
NotifyHook: c.GetNotifyEndpoint(),
Action: action,
Index: index,
TaskId: task,
}
}
func (c *ChatInstance) CreateImagineRequest(proxy globals.ProxyConfig, prompt string) (*CommonResponse, error) {
content, err := utils.PostRaw(
c.GetImagineEndpoint(),
c.GetMidjourneyHeaders(),
c.GetImagineRequest(prompt),
proxy,
)
if err != nil {
return nil, err
}
if data, err := utils.UnmarshalString[CommonResponse](content); err == nil {
return &data, nil
} else {
return nil, utils.ToMarkdownError(err, content)
}
}
func (c *ChatInstance) CreateChangeRequest(proxy globals.ProxyConfig, action string, task string, index *int) (*CommonResponse, error) {
res, err := utils.Post(
c.GetChangeEndpoint(),
c.GetMidjourneyHeaders(),
c.GetChangeRequest(action, task, index),
proxy,
)
if err != nil {
return nil, err
}
return utils.MapToStruct[CommonResponse](res), nil
}
================================================
FILE: adapter/midjourney/chat.go
================================================
package midjourney
import (
adaptercommon "chat/adapter/common"
"chat/globals"
"chat/utils"
"fmt"
"strings"
)
const maxActions = 4
const (
ImagineAction = "IMAGINE"
UpscaleAction = "UPSCALE"
VariationAction = "VARIATION"
RerollAction = "REROLL"
)
const (
ImagineCommand = "/IMAGINE"
UpscaleCommand = "/UPSCALE"
VariationCommand = "/VARIATION"
RerollCommand = "/REROLL"
)
type ChatProps struct {
Messages []globals.Message
Model string
}
func getMode(model string) string {
switch model {
case globals.Midjourney: // relax
return RelaxMode
case globals.MidjourneyFast: // fast
return FastMode
case globals.MidjourneyTurbo: // turbo
return TurboMode
default:
return RelaxMode
}
}
func (c *ChatInstance) IsIgnoreMode() bool {
return strings.HasSuffix(c.Endpoint, "/mj-relax") ||
strings.HasSuffix(c.Endpoint, "/mj-fast") ||
strings.HasSuffix(c.Endpoint, "/mj-turbo")
}
func (c *ChatInstance) GetCleanPrompt(model string, prompt string) string {
if c.IsIgnoreMode() {
return prompt
}
arr := strings.Split(strings.TrimSpace(prompt), " ")
var res []string
for _, word := range arr {
if utils.Contains[string](word, RendererMode) {
continue
}
res = append(res, word)
}
res = append(res, getMode(model))
target := strings.Join(res, " ")
return target
}
func (c *ChatInstance) GetPrompt(props *adaptercommon.ChatProps) string {
if len(props.Message) == 0 {
return ""
}
content := props.Message[len(props.Message)-1].Content
return c.GetCleanPrompt(props.Model, content)
}
func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.ChatProps, callback globals.Hook) error {
// partial response like:
// ```progress
// 0
// ...
// 100
// ```
// 
if len(globals.NotifyUrl) == 0 {
return fmt.Errorf("format error: please provide available notify url")
}
action, prompt := c.ExtractPrompt(c.GetPrompt(props))
if len(prompt) == 0 {
return fmt.Errorf("format error: please provide available prompt")
}
var begin bool
form, err := c.CreateStreamTask(props, action, prompt, func(form *StorageForm, progress int) error {
if progress == -1 {
// ping event
return callback(&globals.Chunk{Content: ""})
}
if !begin {
begin = true
if err := callback(&globals.Chunk{Content: "```progress\n"}); err != nil {
return err
}
} else if progress == 100 && !begin {
if err := callback(&globals.Chunk{Content: "```progress\n"}); err != nil {
return err
}
}
if err := callback(&globals.Chunk{Content: fmt.Sprintf("%d\n", progress)}); err != nil {
return err
}
if progress == 100 {
if err := callback(&globals.Chunk{Content: "```\n"}); err != nil {
return err
}
}
return nil
})
if err != nil {
return fmt.Errorf("error from midjourney: %s", err.Error())
}
if err := callback(&globals.Chunk{Content: utils.GetImageMarkdown(form.Url)}); err != nil {
return err
}
return c.CallbackActions(props, form, callback)
}
func toVirtualMessage(message string, model string) string {
prompt := strings.Replace(message, " ", "-", -1)
return fmt.Sprintf("https://chatnio.virtual%s::%s", prompt, model)
}
func (c *ChatInstance) CallbackActions(props *adaptercommon.ChatProps, form *StorageForm, callback globals.Hook) error {
if form.Action == UpscaleAction {
return nil
}
actions := utils.Range(1, maxActions+1)
upscale := strings.Join(utils.Each(actions, func(index int) string {
return fmt.Sprintf("[U%d](%s)", index, toVirtualMessage(fmt.Sprintf("/UPSCALE %s %d", form.Task, index), props.OriginalModel))
}), " ")
variation := strings.Join(utils.Each(actions, func(index int) string {
return fmt.Sprintf("[V%d](%s)", index, toVirtualMessage(fmt.Sprintf("/VARIATION %s %d", form.Task, index), props.OriginalModel))
}), " ")
reroll := fmt.Sprintf("[REROLL](%s)", toVirtualMessage(fmt.Sprintf("/REROLL %s", form.Task), props.OriginalModel))
return callback(&globals.Chunk{
Content: fmt.Sprintf("\n\n%s\n\n%s\n\n%s\n", upscale, variation, reroll),
})
}
================================================
FILE: adapter/midjourney/expose.go
================================================
package midjourney
import (
"chat/globals"
"chat/utils"
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"strings"
)
var whiteList []string
func SaveWhiteList(raw string) {
arr := utils.Filter(strings.Split(raw, ","), func(s string) bool {
return len(strings.TrimSpace(s)) > 0
})
for _, ip := range arr {
if !utils.Contains(ip, whiteList) {
whiteList = append(whiteList, ip)
}
}
}
func InWhiteList(ip string) bool {
if len(whiteList) == 0 {
return true
}
return utils.Contains(ip, whiteList)
}
func NotifyAPI(c *gin.Context) {
if !InWhiteList(c.ClientIP()) {
globals.Info(fmt.Sprintf("[midjourney] notify api: banned request from %s", c.ClientIP()))
c.AbortWithStatus(http.StatusForbidden)
return
}
var form NotifyForm
if err := c.ShouldBindJSON(&form); err != nil {
c.AbortWithStatus(http.StatusBadRequest)
return
}
globals.Debug(fmt.Sprintf("[midjourney] notify api: get notify: %s (from: %s)", utils.Marshal(form), c.ClientIP()))
if !utils.Contains(form.Status, []string{InProgress, Success, Failure}) {
// ignore
return
}
reason, ok := form.FailReason.(string)
if !ok {
reason = "unknown"
}
err := setStorage(form.Id, StorageForm{
Task: form.Id,
Action: form.Action,
Url: form.ImageUrl,
FailReason: reason,
Progress: form.Progress,
Status: form.Status,
})
c.JSON(http.StatusOK, gin.H{
"status": err == nil,
})
}
================================================
FILE: adapter/midjourney/handler.go
================================================
package midjourney
import (
adaptercommon "chat/adapter/common"
"chat/globals"
"chat/utils"
"fmt"
"strings"
"time"
)
const maxTimeout = 30 * time.Minute // 30 min timeout
func getStatusCode(action string, response *CommonResponse) error {
code := response.Code
switch code {
case SuccessCode, QueueCode:
return nil
case ExistedCode:
if action != ImagineCommand {
return nil
}
return fmt.Errorf("task is existed, please try again later with another prompt")
case MaxQueueCode:
return fmt.Errorf("task queue is full, please try again later")
case NudeCode:
return fmt.Errorf("prompt violates the content policy of midjourney, the request is rejected")
default:
return fmt.Errorf(fmt.Sprintf("unknown error from midjourney (code: %d, description: %s)", code, response.Description))
}
}
func getProgress(value string) int {
progress := strings.TrimSuffix(value, "%")
return utils.ParseInt(progress)
}
func (c *ChatInstance) GetAction(command string) string {
return strings.TrimLeft(command, "/")
}
func (c *ChatInstance) ExtractPrompt(input string) (action string, prompt string) {
segment := utils.SafeSplit(input, " ", 2)
action = strings.TrimSpace(segment[0])
prompt = strings.TrimSpace(segment[1])
switch action {
case ImagineCommand, VariationCommand, UpscaleCommand, RerollCommand:
return
default:
return ImagineCommand, strings.TrimSpace(input)
}
}
func (c *ChatInstance) ExtractCommand(input string) (task string, index *int) {
segment := utils.SafeSplit(input, " ", 2)
task = strings.TrimSpace(segment[0])
if segment[1] != "" {
data := segment[1]
slice := strings.Split(segment[1], " ")
if len(slice) > 1 {
data = slice[0]
}
index = utils.ToPtr(utils.ParseInt(strings.TrimSpace(data)))
}
return
}
func (c *ChatInstance) CreateRequest(proxy globals.ProxyConfig, action string, prompt string) (*CommonResponse, error) {
switch action {
case ImagineCommand:
return c.CreateImagineRequest(proxy, prompt)
case VariationCommand, UpscaleCommand, RerollCommand:
task, index := c.ExtractCommand(prompt)
return c.CreateChangeRequest(proxy, c.GetAction(action), task, index)
default:
return nil, fmt.Errorf("unknown action: %s", action)
}
}
func (c *ChatInstance) CreateStreamTask(props *adaptercommon.ChatProps, action string, prompt string, hook func(form *StorageForm, progress int) error) (*StorageForm, error) {
res, err := c.CreateRequest(props.Proxy, action, prompt)
if err != nil {
return nil, err
}
if err := getStatusCode(action, res); err != nil {
return nil, err
}
task := res.Result
progress := -1
ticker := time.NewTicker(50 * time.Millisecond)
defer ticker.Stop()
for {
select {
case <-ticker.C:
form := getNotifyStorage(task)
if form == nil {
// hook for ping (in order to catch the stop signal)
if err := hook(nil, -1); err != nil {
return nil, err
}
continue
}
switch form.Status {
case Success:
if err := hook(form, 100); err != nil {
return nil, err
}
return form, nil
case Failure:
return nil, fmt.Errorf("task failed: %s", form.FailReason)
case InProgress:
current := getProgress(form.Progress)
if progress != current {
if err := hook(form, current); err != nil {
return nil, err
}
progress = current
}
default:
// ping
if err := hook(form, -1); err != nil {
return nil, err
}
}
case <-time.After(maxTimeout):
return nil, fmt.Errorf("task timeout")
}
}
}
================================================
FILE: adapter/midjourney/storage.go
================================================
package midjourney
import (
"chat/connection"
"chat/utils"
"fmt"
)
func getTaskName(task string) string {
return fmt.Sprintf("nio:mj-task:%s", task)
}
func setStorage(task string, form StorageForm) error {
return utils.SetJson(connection.Cache, getTaskName(task), form, 60*60)
}
func getNotifyStorage(task string) *StorageForm {
return utils.GetCacheStore[StorageForm](connection.Cache, getTaskName(task))
}
================================================
FILE: adapter/midjourney/struct.go
================================================
package midjourney
import (
factory "chat/adapter/common"
"chat/globals"
"fmt"
)
var midjourneyEmptySecret = "null"
type ChatInstance struct {
Endpoint string
ApiSecret string
}
func (c *ChatInstance) GetApiSecret() string {
return c.ApiSecret
}
func (c *ChatInstance) GetEndpoint() string {
return c.Endpoint
}
func (c *ChatInstance) GetMidjourneyHeaders() map[string]string {
secret := c.GetApiSecret()
if secret == "" || secret == midjourneyEmptySecret {
return map[string]string{
"Content-Type": "application/json",
}
}
return map[string]string{
"Content-Type": "application/json",
"mj-api-secret": secret,
}
}
func (c *ChatInstance) GetNotifyEndpoint() string {
return fmt.Sprintf("%s/mj/notify", globals.NotifyUrl)
}
func NewChatInstance(endpoint, apiSecret, whiteList string) *ChatInstance {
SaveWhiteList(whiteList)
return &ChatInstance{
Endpoint: endpoint,
ApiSecret: apiSecret,
}
}
func NewChatInstanceFromConfig(conf globals.ChannelConfig) factory.Factory {
params := conf.SplitRandomSecret(2)
return NewChatInstance(
conf.GetEndpoint(),
params[0], params[1],
)
}
================================================
FILE: adapter/midjourney/types.go
================================================
package midjourney
const (
SuccessCode = 1
ExistedCode = 21
QueueCode = 22
MaxQueueCode = 23
NudeCode = 24
)
const (
NotStartStatus = "NOT_START"
Submitted = "SUBMITTED"
InProgress = "IN_PROGRESS"
Failure = "FAILURE"
Success = "SUCCESS"
)
const (
TurboMode = "--turbo"
FastMode = "--fast"
RelaxMode = "--relax"
)
var RendererMode = []string{TurboMode, FastMode, RelaxMode}
type CommonHeader struct {
ContentType string `json:"Content-Type"`
MjApiSecret string `json:"mj-api-secret,omitempty"`
}
type CommonResponse struct {
Code int `json:"code"`
Description string `json:"description"`
Result string `json:"result"`
}
type ImagineRequest struct {
NotifyHook string `json:"notifyHook"`
Prompt string `json:"prompt"`
}
type ChangeRequest struct {
NotifyHook string `json:"notifyHook"`
Action string `json:"action"`
Index *int `json:"index,omitempty"`
TaskId string `json:"taskId"`
}
type NotifyForm struct {
Id string `json:"id"`
Action string `json:"action"`
Status string `json:"status"`
Prompt string `json:"prompt"`
PromptEn string `json:"promptEn"`
Description string `json:"description"`
SubmitTime int64 `json:"submitTime"`
StartTime int64 `json:"startTime"`
FinishTime int64 `json:"finishTime"`
Progress string `json:"progress"`
ImageUrl string `json:"imageUrl"`
FailReason interface{} `json:"failReason"`
}
type StorageForm struct {
Task string `json:"task"`
Action string `json:"action"`
Url string `json:"url"`
FailReason string `json:"failReason"`
Progress string `json:"progress"`
Status string `json:"status"`
}
================================================
FILE: adapter/openai/chat.go
================================================
package openai
import (
adaptercommon "chat/adapter/common"
"chat/globals"
"chat/utils"
"errors"
"fmt"
"regexp"
"strings"
)
func (c *ChatInstance) GetChatEndpoint(props *adaptercommon.ChatProps) string {
if props.Model == globals.GPT3TurboInstruct {
return fmt.Sprintf("%s/v1/completions", c.GetEndpoint())
}
return fmt.Sprintf("%s/v1/chat/completions", c.GetEndpoint())
}
func (c *ChatInstance) GetCompletionPrompt(messages []globals.Message) string {
result := ""
for _, message := range messages {
result += fmt.Sprintf("%s: %s\n", message.Role, message.Content)
}
return result
}
func (c *ChatInstance) GetLatestPrompt(props *adaptercommon.ChatProps) string {
if len(props.Message) == 0 {
return ""
}
return props.Message[len(props.Message)-1].Content
}
func (c *ChatInstance) GetChatBody(props *adaptercommon.ChatProps, stream bool) interface{} {
if props.Model == globals.GPT3TurboInstruct {
// for completions
return CompletionRequest{
Model: props.Model,
Prompt: c.GetCompletionPrompt(props.Message),
MaxToken: props.MaxTokens,
Stream: stream,
}
}
messages := formatMessages(props)
// o1, o3, gpt-5 compatibility
isNewModel := len(props.Model) >= 2 && (props.Model[:2] == "o1" || props.Model[:2] == "o3") || strings.HasPrefix(props.Model, "gpt-5")
var temperature *float32
if isNewModel {
temp := float32(1.0)
temperature = &temp
} else {
temperature = props.Temperature
}
request := ChatRequest{
Model: props.Model,
Messages: messages,
Stream: stream,
PresencePenalty: props.PresencePenalty,
FrequencyPenalty: props.FrequencyPenalty,
Temperature: temperature,
TopP: props.TopP,
Tools: props.Tools,
ToolChoice: props.ToolChoice,
}
if isNewModel {
request.MaxCompletionTokens = props.MaxTokens
} else {
request.MaxToken = props.MaxTokens
}
return request
}
// CreateChatRequest is the native http request body for openai
func (c *ChatInstance) CreateChatRequest(props *adaptercommon.ChatProps) (string, error) {
if globals.IsOpenAIDalleModel(props.Model) {
return c.CreateImage(props)
}
res, err := utils.Post(
c.GetChatEndpoint(props),
c.GetHeader(),
c.GetChatBody(props, false),
props.Proxy,
)
if err != nil || res == nil {
return "", fmt.Errorf("openai error: %s", err.Error())
}
data := utils.MapToStruct[ChatResponse](res)
if data == nil {
return "", fmt.Errorf("openai error: cannot parse response")
} else if data.Error.Message != "" {
return "", fmt.Errorf("openai error: %s", data.Error.Message)
}
return data.Choices[0].Message.Content, nil
}
func hideRequestId(message string) string {
// xxx (request id: 2024020311120561344953f0xfh0TX)
exp := regexp.MustCompile(`\(request id: [a-zA-Z0-9]+\)`)
return exp.ReplaceAllString(message, "")
}
// CreateStreamChatRequest is the stream response body for openai
func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.ChatProps, callback globals.Hook) error {
if globals.IsOpenAIDalleModel(props.Model) {
if url, err := c.CreateImage(props); err != nil {
return err
} else {
return callback(&globals.Chunk{
Content: url,
})
}
}
isCompletionType := props.Model == globals.GPT3TurboInstruct
ticks := 0
err := utils.EventScanner(&utils.EventScannerProps{
Method: "POST",
Uri: c.GetChatEndpoint(props),
Headers: c.GetHeader(),
Body: c.GetChatBody(props, true),
Callback: func(data string) error {
ticks += 1
partial, err := c.ProcessLine(data, isCompletionType)
if err != nil {
return err
}
return callback(partial)
},
}, props.Proxy)
if err != nil {
if form := processChatErrorResponse(err.Body); form != nil {
if form.Error.Type == "" && form.Error.Message == "" {
return errors.New(utils.ToMarkdownCode("json", err.Body))
}
msg := fmt.Sprintf("%s (type: %s)", form.Error.Message, form.Error.Type)
return errors.New(hideRequestId(msg))
}
return err.Error
}
if ticks == 0 {
return errors.New("no response")
}
return nil
}
================================================
FILE: adapter/openai/image.go
================================================
package openai
import (
adaptercommon "chat/adapter/common"
"chat/globals"
"chat/utils"
"fmt"
"strings"
)
type ImageProps struct {
Model string
Prompt string
Size ImageSize
Proxy globals.ProxyConfig
}
func (c *ChatInstance) GetImageEndpoint() string {
return fmt.Sprintf("%s/v1/images/generations", c.GetEndpoint())
}
// CreateImageRequest will create a dalle image from prompt, return url of image, base64 data and error
func (c *ChatInstance) CreateImageRequest(props ImageProps) (string, string, error) {
res, err := utils.Post(
c.GetImageEndpoint(),
c.GetHeader(), ImageRequest{
Model: props.Model,
Prompt: props.Prompt,
Size: utils.Multi[ImageSize](
props.Model == globals.Dalle3 || props.Model == globals.GPTImage1,
ImageSize1024,
ImageSize512,
),
N: 1,
}, props.Proxy)
if err != nil || res == nil {
return "", "", fmt.Errorf(err.Error())
}
data := utils.MapToStruct[ImageResponse](res)
if data == nil {
return "", "", fmt.Errorf("openai error: cannot parse response")
} else if data.Error.Message != "" {
return "", "", fmt.Errorf(data.Error.Message)
}
// for gpt-image-1, return base64 data if available
if props.Model == globals.GPTImage1 && data.Data[0].B64Json != "" {
return "", data.Data[0].B64Json, nil
}
return data.Data[0].Url, "", nil
}
// CreateImage will create a dalle image from prompt, return markdown of image
func (c *ChatInstance) CreateImage(props *adaptercommon.ChatProps) (string, error) {
url, b64Json, err := c.CreateImageRequest(ImageProps{
Model: props.Model,
Prompt: c.GetLatestPrompt(props),
Proxy: props.Proxy,
})
if err != nil {
if strings.Contains(err.Error(), "safety") {
return err.Error(), nil
}
return "", err
}
if b64Json != "" {
return utils.GetBase64ImageMarkdown(b64Json), nil
}
storedUrl := utils.StoreImage(url)
return utils.GetImageMarkdown(storedUrl), nil
}
================================================
FILE: adapter/openai/processor.go
================================================
package openai
import (
adaptercommon "chat/adapter/common"
"chat/globals"
"chat/utils"
"errors"
"fmt"
"regexp"
)
func formatMessages(props *adaptercommon.ChatProps) interface{} {
if globals.IsVisionModel(props.Model) {
return utils.Each[globals.Message, Message](props.Message, func(message globals.Message) Message {
if message.Role == globals.User {
content, urls := utils.ExtractImages(message.Content, true)
images := utils.EachNotNil[string, MessageContent](urls, func(url string) *MessageContent {
obj, err := utils.NewImage(url)
props.Buffer.AddImage(obj)
if err != nil {
globals.Info(fmt.Sprintf("cannot process image: %s (source: %s)", err.Error(), utils.Extract(url, 24, "...")))
}
return &MessageContent{
Type: "image_url",
ImageUrl: &ImageUrl{
Url: url,
},
}
})
return Message{
Role: message.Role,
Content: utils.Prepend(images, MessageContent{
Type: "text",
Text: &content,
}),
Name: message.Name,
FunctionCall: message.FunctionCall,
ToolCalls: message.ToolCalls,
ToolCallId: message.ToolCallId,
}
}
return Message{
Role: message.Role,
Content: MessageContents{
MessageContent{
Type: "text",
Text: &message.Content,
},
},
Name: message.Name,
FunctionCall: message.FunctionCall,
ToolCalls: message.ToolCalls,
ToolCallId: message.ToolCallId,
}
})
}
return props.Message
}
func processChatResponse(data string) *ChatStreamResponse {
return utils.UnmarshalForm[ChatStreamResponse](data)
}
func processCompletionResponse(data string) *CompletionResponse {
return utils.UnmarshalForm[CompletionResponse](data)
}
func processChatErrorResponse(data string) *ChatStreamErrorResponse {
return utils.UnmarshalForm[ChatStreamErrorResponse](data)
}
func getChoices(form *ChatStreamResponse) *globals.Chunk {
if len(form.Choices) == 0 {
return &globals.Chunk{Content: ""}
}
choice := form.Choices[0].Delta
return &globals.Chunk{
Content: choice.Content,
ToolCall: choice.ToolCalls,
FunctionCall: choice.FunctionCall,
}
}
func getCompletionChoices(form *CompletionResponse) string {
if len(form.Choices) == 0 {
return ""
}
return form.Choices[0].Text
}
func getRobustnessResult(chunk string) string {
exp := `\"content\":\"(.*?)\"`
compile, err := regexp.Compile(exp)
if err != nil {
return ""
}
matches := compile.FindStringSubmatch(chunk)
if len(matches) > 1 {
return utils.ProcessRobustnessChar(matches[1])
} else {
return ""
}
}
func (c *ChatInstance) ProcessLine(data string, isCompletionType bool) (*globals.Chunk, error) {
if isCompletionType {
// openai legacy support
if completion := processCompletionResponse(data); completion != nil {
return &globals.Chunk{
Content: getCompletionChoices(completion),
}, nil
}
globals.Warn(fmt.Sprintf("openai error: cannot parse completion response: %s", data))
return &globals.Chunk{Content: ""}, errors.New("parser error: cannot parse completion response")
}
if form := processChatResponse(data); form != nil {
return getChoices(form), nil
}
if form := processChatErrorResponse(data); form != nil {
return &globals.Chunk{Content: ""}, errors.New(fmt.Sprintf("openai error: %s (type: %s)", form.Error.Message, form.Error.Type))
}
globals.Warn(fmt.Sprintf("openai error: cannot parse chat completion response: %s", data))
return &globals.Chunk{Content: ""}, errors.New("parser error: cannot parse chat completion response")
}
================================================
FILE: adapter/openai/struct.go
================================================
package openai
import (
factory "chat/adapter/common"
"chat/globals"
"fmt"
)
type ChatInstance struct {
Endpoint string
ApiKey string
}
func (c *ChatInstance) GetEndpoint() string {
return c.Endpoint
}
func (c *ChatInstance) GetApiKey() string {
return c.ApiKey
}
func (c *ChatInstance) GetHeader() map[string]string {
return map[string]string{
"Content-Type": "application/json",
"Authorization": fmt.Sprintf("Bearer %s", c.GetApiKey()),
}
}
func NewChatInstance(endpoint, apiKey string) *ChatInstance {
return &ChatInstance{
Endpoint: endpoint,
ApiKey: apiKey,
}
}
func NewChatInstanceFromConfig(conf globals.ChannelConfig) factory.Factory {
return NewChatInstance(
conf.GetEndpoint(),
conf.GetRandomSecret(),
)
}
================================================
FILE: adapter/openai/types.go
================================================
package openai
import "chat/globals"
type ImageUrl struct {
Url string `json:"url"`
Detail *string `json:"detail,omitempty"`
}
type MessageContent struct {
Type string `json:"type"`
Text *string `json:"text,omitempty"`
ImageUrl *ImageUrl `json:"image_url,omitempty"`
}
type MessageContents []MessageContent
type Message struct {
Role string `json:"role"`
Content MessageContents `json:"content"`
Name *string `json:"name,omitempty"`
FunctionCall *globals.FunctionCall `json:"function_call,omitempty"` // only `function` role
ToolCallId *string `json:"tool_call_id,omitempty"` // only `tool` role
ToolCalls *globals.ToolCalls `json:"tool_calls,omitempty"` // only `assistant` role
ReasoningContent *string `json:"reasoning,omitempty"` // only for claude reasoning models
}
// ChatRequest is the request body for openai
type ChatRequest struct {
Model string `json:"model"`
Messages interface{} `json:"messages"`
MaxToken *int `json:"max_tokens,omitempty"`
MaxCompletionTokens *int `json:"max_completion_tokens,omitempty"`
Stream bool `json:"stream"`
PresencePenalty *float32 `json:"presence_penalty,omitempty"`
FrequencyPenalty *float32 `json:"frequency_penalty,omitempty"`
Temperature *float32 `json:"temperature,omitempty"`
TopP *float32 `json:"top_p,omitempty"`
Tools *globals.FunctionTools `json:"tools,omitempty"`
ToolChoice *interface{} `json:"tool_choice,omitempty"` // string or object
}
// CompletionRequest is the request body for openai completion
type CompletionRequest struct {
Model string `json:"model"`
Prompt string `json:"prompt"`
MaxToken *int `json:"max_tokens,omitempty"`
Stream bool `json:"stream"`
}
// ChatResponse is the native http request body for openai
type ChatResponse struct {
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
Model string `json:"model"`
Choices []struct {
Index int `json:"index"`
Message globals.Message `json:"message"`
FinishReason string `json:"finish_reason"`
} `json:"choices"`
Error struct {
Message string `json:"message"`
} `json:"error"`
}
// ChatStreamResponse is the stream response body for openai
type ChatStreamResponse struct {
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
Model string `json:"model"`
Choices []struct {
Delta globals.Message `json:"delta"`
Index int `json:"index"`
FinishReason string `json:"finish_reason"`
} `json:"choices"`
}
// CompletionResponse is the native http request body / stream response body for openai completion
type CompletionResponse struct {
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
Model string `json:"model"`
Choices []struct {
Text string `json:"text"`
Index int `json:"index"`
} `json:"choices"`
}
type ChatStreamErrorResponse struct {
Error struct {
Message string `json:"message"`
Type string `json:"type"`
} `json:"error"`
}
type ImageSize string
// ImageRequest is the request body for openai dalle image generation
type ImageRequest struct {
Model string `json:"model"`
Prompt string `json:"prompt"`
Size ImageSize `json:"size"`
N int `json:"n"`
}
type ImageResponse struct {
Data []struct {
Url string `json:"url,omitempty"`
B64Json string `json:"b64_json,omitempty"`
} `json:"data"`
Error struct {
Message string `json:"message"`
} `json:"error"`
}
var (
ImageSize256 ImageSize = "256x256"
ImageSize512 ImageSize = "512x512"
ImageSize1024 ImageSize = "1024x1024"
)
================================================
FILE: adapter/openai/videos.go
================================================
package openai
import (
adaptercommon "chat/adapter/common"
"chat/globals"
"chat/utils"
"fmt"
"time"
)
type VideoRequest struct {
Prompt string `json:"prompt"`
Model string `json:"model,omitempty"`
Seconds *string `json:"seconds,omitempty"`
Size *string `json:"size,omitempty"`
InputReference *string `json:"input_reference,omitempty"`
}
type VideoJob struct {
CompletedAt *int64 `json:"completed_at,omitempty"`
CreatedAt int64 `json:"created_at"`
ExpiresAt *int64 `json:"expires_at,omitempty"`
Id string `json:"id"`
Model string `json:"model"`
Object string `json:"object"`
Progress *int `json:"progress,omitempty"`
Prompt string `json:"prompt"`
RemixedFromVideoId *string `json:"remixed_from_video_id,omitempty"`
Seconds string `json:"seconds"`
Size string `json:"size"`
Status string `json:"status"`
Error *struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"error,omitempty"`
}
func (c *ChatInstance) getVideoCreateEndpoint() string {
return fmt.Sprintf("%s/v1/videos", c.GetEndpoint())
}
func (c *ChatInstance) getVideoQueryEndpoint(id string) string {
return fmt.Sprintf("%s/v1/videos/%s", c.GetEndpoint(), id)
}
func (c *ChatInstance) CreateVideoRequest(props *adaptercommon.VideoProps, hook globals.Hook) error {
body := VideoRequest{
Prompt: props.Prompt,
Model: props.Model,
Seconds: props.Seconds,
Size: props.Size,
InputReference: props.InputReference,
}
res, err := utils.Post(c.getVideoCreateEndpoint(), c.GetHeader(), body, props.Proxy)
if err != nil || res == nil {
if err != nil {
return fmt.Errorf("openai video error: %s", err.Error())
}
return fmt.Errorf("openai video error: empty response")
}
job := utils.MapToStruct[VideoJob](res)
if job == nil {
return fmt.Errorf("openai video error: cannot parse response")
}
if job.Error != nil && (job.Error.Message != "") {
return fmt.Errorf("openai video error: %s", job.Error.Message)
}
const maxTimeout = 30 * time.Minute
ticker := time.NewTicker(2 * time.Second)
defer ticker.Stop()
deadline := time.After(maxTimeout)
var begin bool
var lastProgress int = -1
for {
if job.Status == "completed" {
if begin {
if err := hook(&globals.Chunk{Content: "```\n"}); err != nil {
return err
}
}
return hook(&globals.Chunk{Content: utils.Marshal(job)})
}
if job.Status == "failed" {
if begin {
if err := hook(&globals.Chunk{Content: "```\n"}); err != nil {
return err
}
}
if job.Error != nil && job.Error.Message != "" {
return fmt.Errorf("openai video job failed: %s", job.Error.Message)
}
return fmt.Errorf("openai video job failed")
}
select {
case <-ticker.C:
if job.Id == "" {
return hook(&globals.Chunk{Content: utils.Marshal(job)})
}
data, gErr := utils.Get(c.getVideoQueryEndpoint(job.Id), c.GetHeader(), props.Proxy)
if gErr != nil || data == nil {
continue
}
if j := utils.MapToStruct[VideoJob](data); j != nil {
job = j
}
progress := 0
if job.Progress != nil {
progress = *job.Progress
}
if !begin {
begin = true
if err := hook(&globals.Chunk{Content: "```progress\n"}); err != nil {
return err
}
}
if progress != lastProgress {
if err := hook(&globals.Chunk{Content: fmt.Sprintf("%d\n", progress)}); err != nil {
return err
}
lastProgress = progress
}
case <-deadline:
if begin {
if err := hook(&globals.Chunk{Content: "```\n"}); err != nil {
return err
}
}
return fmt.Errorf("openai video job timeout")
}
}
}
================================================
FILE: adapter/palm2/chat.go
================================================
package palm2
import (
adaptercommon "chat/adapter/common"
"chat/globals"
"chat/utils"
"errors"
"fmt"
"strings"
)
var geminiMaxImages = 16
func (c *ChatInstance) GetChatEndpoint(model string, stream bool) string {
if model == globals.ChatBison001 {
return fmt.Sprintf("%s/v1beta2/models/%s:generateMessage?key=%s", c.Endpoint, model, c.ApiKey)
}
if stream {
return fmt.Sprintf("%s/v1beta/models/%s:streamGenerateContent?alt=sse&key=%s", c.Endpoint, model, c.ApiKey)
}
return fmt.Sprintf("%s/v1beta/models/%s:generateContent?key=%s", c.Endpoint, model, c.ApiKey)
}
func (c *ChatInstance) ConvertMessage(message []globals.Message) []PalmMessage {
var result []PalmMessage
for i, item := range message {
if len(item.Content) == 0 {
// palm model: message must include non empty content
continue
}
if item.Role == globals.Tool {
continue
}
if i > 0 && item.Role == result[len(result)-1].Author {
// palm model: messages must alternate between authors
result[len(result)-1].Content += " " + item.Content
continue
}
result = append(result, PalmMessage{
Author: item.Role,
Content: item.Content,
})
}
return result
}
func (c *ChatInstance) GetPalm2ChatBody(props *adaptercommon.ChatProps) *PalmChatBody {
return &PalmChatBody{
Prompt: PalmPrompt{
Messages: c.ConvertMessage(props.Message),
},
}
}
func (c *ChatInstance) GetGeminiChatBody(props *adaptercommon.ChatProps) *GeminiChatBody {
return &GeminiChatBody{
Contents: c.GetGeminiContents(props.Model, props.Message),
GenerationConfig: GeminiConfig{
Temperature: props.Temperature,
MaxOutputTokens: props.MaxTokens,
TopP: props.TopP,
TopK: props.TopK,
},
}
}
func (c *ChatInstance) GetPalm2ChatResponse(data interface{}) (string, error) {
if form := utils.MapToStruct[PalmChatResponse](data); form != nil {
if len(form.Candidates) == 0 {
return "", fmt.Errorf("palm2 error: the content violates content policy")
}
return form.Candidates[0].Content, nil
}
return "", fmt.Errorf("palm2 error: cannot parse response")
}
func (c *ChatInstance) GetGeminiChatResponse(data interface{}) (string, error) {
if form := utils.MapToStruct[GeminiChatResponse](data); form != nil {
if len(form.Candidates) != 0 && len(form.Candidates[0].Content.Parts) != 0 {
return form.Candidates[0].Content.Parts[0].Text, nil
}
}
if form := utils.MapToStruct[GeminiChatErrorResponse](data); form != nil {
return "", fmt.Errorf("gemini error: %s (code: %d, status: %s)", form.Error.Message, form.Error.Code, form.Error.Status)
}
return "", fmt.Errorf("gemini: cannot parse response")
}
func (c *ChatInstance) CreateChatRequest(props *adaptercommon.ChatProps) (string, error) {
uri := c.GetChatEndpoint(props.Model, false)
if props.Model == globals.ChatBison001 {
data, err := utils.Post(uri, map[string]string{
"Content-Type": "application/json",
}, c.GetPalm2ChatBody(props), props.Proxy)
if err != nil {
return "", fmt.Errorf("palm2 error: %s", err.Error())
}
return c.GetPalm2ChatResponse(data)
}
data, err := utils.Post(uri, map[string]string{
"Content-Type": "application/json",
}, c.GetGeminiChatBody(props), props.Proxy)
if err != nil {
return "", fmt.Errorf("gemini error: %s", err.Error())
}
return c.GetGeminiChatResponse(data)
}
// CreateStreamChatRequest is the stream request for palm2
func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.ChatProps, callback globals.Hook) error {
// Handle imagen models
if globals.IsGoogleImagenModel(props.Model) {
response, err := c.CreateImage(props)
if err != nil {
return err
}
return callback(&globals.Chunk{Content: response})
}
// Handle chat models
if props.Model == globals.ChatBison001 {
response, err := c.CreateChatRequest(props)
if err != nil {
return err
}
for _, item := range utils.SplitItem(response, " ") {
if err := callback(&globals.Chunk{Content: item}); err != nil {
return err
}
}
return nil
}
ticks := 0
scanErr := utils.EventScanner(&utils.EventScannerProps{
Method: "POST",
Uri: c.GetChatEndpoint(props.Model, true),
Headers: map[string]string{
"Content-Type": "application/json",
},
Body: c.GetGeminiChatBody(props),
Callback: func(data string) error {
ticks += 1
if form := utils.UnmarshalForm[GeminiStreamResponse](data); form != nil {
if len(form.Candidates) != 0 && len(form.Candidates[0].Content.Parts) != 0 {
return callback(&globals.Chunk{
Content: form.Candidates[0].Content.Parts[0].Text,
})
}
return nil
}
if form := utils.UnmarshalForm[GeminiChatErrorResponse](data); form != nil {
return fmt.Errorf("gemini error: %s (code: %d, status: %s)", form.Error.Message, form.Error.Code, form.Error.Status)
}
return nil
},
}, props.Proxy)
if scanErr != nil {
if scanErr.Error != nil && strings.Contains(scanErr.Error.Error(), "status code: 404") {
// downgrade to non-stream request
response, err := c.CreateChatRequest(props)
if err != nil {
return err
}
return callback(&globals.Chunk{Content: response})
}
if scanErr.Body != "" {
if form := utils.UnmarshalForm[GeminiChatErrorResponse](scanErr.Body); form != nil {
return fmt.Errorf("gemini error: %s (code: %d, status: %s)", form.Error.Message, form.Error.Code, form.Error.Status)
}
return fmt.Errorf("gemini error: %s", scanErr.Body)
}
return fmt.Errorf("gemini error: %v", scanErr.Error)
}
if ticks == 0 {
return errors.New("no response")
}
return nil
}
func (c *ChatInstance) GetLatestPrompt(props *adaptercommon.ChatProps) string {
if len(props.Message) == 0 {
return ""
}
return props.Message[len(props.Message)-1].Content
}
================================================
FILE: adapter/palm2/formatter.go
================================================
package palm2
import (
"chat/globals"
"chat/utils"
"strings"
)
func getGeminiRole(role string) string {
switch role {
case globals.User:
return GeminiUserType
case globals.Assistant, globals.Tool, globals.System:
return GeminiModelType
default:
return GeminiUserType
}
}
func getMimeType(content string) string {
segment := strings.Split(content, ".")
if len(segment) == 0 || len(segment) == 1 {
return "image/png"
}
suffix := strings.TrimSpace(strings.ToLower(segment[len(segment)-1]))
switch suffix {
case "png":
return "image/png"
case "jpg", "jpeg":
return "image/jpeg"
case "gif":
return "image/gif"
case "webp":
return "image/webp"
case "heif":
return "image/heif"
case "heic":
return "image/heic"
default:
return "image/png"
}
}
func getGeminiContent(parts []GeminiChatPart, content string, model string) []GeminiChatPart {
if model == globals.GeminiPro {
return append(parts, GeminiChatPart{
Text: &content,
})
}
raw, urls := utils.ExtractImages(content, true)
if len(urls) > geminiMaxImages {
urls = urls[:geminiMaxImages]
}
parts = append(parts, GeminiChatPart{
Text: &raw,
})
for _, url := range urls {
data, err := utils.ConvertToBase64(url)
if err != nil {
continue
}
parts = append(parts, GeminiChatPart{
InlineData: &GeminiInlineData{
MimeType: getMimeType(url),
Data: data,
},
})
}
return parts
}
func (c *ChatInstance) GetGeminiContents(model string, message []globals.Message) []GeminiContent {
// gemini role should be user-model
result := make([]GeminiContent, 0)
for _, item := range message {
role := getGeminiRole(item.Role)
if len(item.Content) == 0 {
// gemini model: message must include non empty content
continue
}
if len(result) == 0 && getGeminiRole(item.Role) == GeminiModelType {
// gemini model: first message must be user
result = append(result, GeminiContent{
Role: GeminiUserType,
Parts: getGeminiContent(make([]GeminiChatPart, 0), "", model),
})
}
if len(result) > 0 && role == result[len(result)-1].Role {
// gemini model: messages must alternate between authors
result[len(result)-1].Parts = getGeminiContent(result[len(result)-1].Parts, item.Content, model)
continue
}
result = append(result, GeminiContent{
Role: getGeminiRole(item.Role),
Parts: getGeminiContent(make([]GeminiChatPart, 0), item.Content, model),
})
}
return result
}
================================================
FILE: adapter/palm2/image.go
================================================
package palm2
import (
adaptercommon "chat/adapter/common"
"chat/globals"
"chat/utils"
"fmt"
"strings"
)
type ImageProps struct {
Model string
Prompt string
Proxy globals.ProxyConfig
}
func (c *ChatInstance) GetImageEndpoint(model string) string {
return fmt.Sprintf("%s/v1beta/models/%s:predict?key=%s", c.Endpoint, model, c.ApiKey)
}
// CreateImageRequest will create a gemini imagen from prompt, return base64 of image and error
func (c *ChatInstance) CreateImageRequest(props ImageProps) (string, error) {
res, err := utils.Post(
c.GetImageEndpoint(props.Model),
map[string]string{
"Content-Type": "application/json",
},
ImageRequest{
Instances: []ImageInstance{
{
Prompt: props.Prompt,
},
},
Parameters: ImageParameters{
SampleCount: 1,
AspectRatio: "1:1",
PersonGeneration: "allow_adult",
},
},
props.Proxy,
)
if err != nil || res == nil {
return "", fmt.Errorf("gemini error: %s", err.Error())
}
data := utils.MapToStruct[ImageResponse](res)
if data == nil {
return "", fmt.Errorf("gemini error: cannot parse response")
}
if len(data.Predictions) == 0 {
return "", fmt.Errorf("gemini error: no image generated")
}
return data.Predictions[0].BytesBase64Encoded, nil
}
// CreateImage will create a gemini imagen from prompt, return markdown of image
func (c *ChatInstance) CreateImage(props *adaptercommon.ChatProps) (string, error) {
if !globals.IsGoogleImagenModel(props.Model) {
return "", nil
}
base64Data, err := c.CreateImageRequest(ImageProps{
Model: props.Model,
Prompt: c.GetLatestPrompt(props),
Proxy: props.Proxy,
})
if err != nil {
if strings.Contains(err.Error(), "safety") {
return err.Error(), nil
}
return "", err
}
// Convert base64 to data URL format
dataUrl := fmt.Sprintf("data:image/png;base64,%s", base64Data)
url := utils.StoreImage(dataUrl)
return utils.GetImageMarkdown(url), nil
}
================================================
FILE: adapter/palm2/struct.go
================================================
package palm2
import (
factory "chat/adapter/common"
"chat/globals"
)
type ChatInstance struct {
Endpoint string
ApiKey string
}
func (c *ChatInstance) GetApiKey() string {
return c.ApiKey
}
func (c *ChatInstance) GetEndpoint() string {
return c.Endpoint
}
func NewChatInstance(endpoint string, apiKey string) *ChatInstance {
return &ChatInstance{
Endpoint: endpoint,
ApiKey: apiKey,
}
}
func NewChatInstanceFromConfig(conf globals.ChannelConfig) factory.Factory {
return NewChatInstance(
conf.GetEndpoint(),
conf.GetRandomSecret(),
)
}
================================================
FILE: adapter/palm2/types.go
================================================
package palm2
const (
GeminiUserType = "user"
GeminiModelType = "model"
)
type PalmMessage struct {
Author string `json:"author"`
Content string `json:"content"`
}
// PalmChatBody is the native http request body for palm2
type PalmChatBody struct {
Prompt PalmPrompt `json:"prompt"`
}
type PalmPrompt struct {
Messages []PalmMessage `json:"messages"`
}
// PalmChatResponse is the native http response body for palm2
type PalmChatResponse struct {
Candidates []PalmMessage `json:"candidates"`
}
// GeminiChatBody is the native http request body for gemini
type GeminiChatBody struct {
Contents []GeminiContent `json:"contents"`
GenerationConfig GeminiConfig `json:"generationConfig"`
}
type GeminiConfig struct {
Temperature *float32 `json:"temperature,omitempty"`
MaxOutputTokens *int `json:"maxOutputTokens,omitempty"`
TopP *float32 `json:"topP,omitempty"`
TopK *int `json:"topK,omitempty"`
}
type GeminiContent struct {
Role string `json:"role"`
Parts []GeminiChatPart `json:"parts"`
}
type GeminiChatPart struct {
Text *string `json:"text,omitempty"`
InlineData *GeminiInlineData `json:"inline_data,omitempty"`
}
type GeminiInlineData struct {
MimeType string `json:"mime_type"`
Data string `json:"data"`
}
type GeminiChatResponse struct {
Candidates []struct {
Content struct {
Parts []struct {
Text string `json:"text"`
} `json:"parts"`
Role string `json:"role"`
} `json:"content"`
} `json:"candidates"`
}
type GeminiChatErrorResponse struct {
Error struct {
Code int `json:"code"`
Message string `json:"message"`
Status string `json:"status"`
} `json:"error"`
}
type GeminiStreamResponse struct {
Candidates []struct {
Content struct {
Parts []struct {
Text string `json:"text"`
} `json:"parts"`
Role string `json:"role"`
} `json:"content"`
} `json:"candidates"`
}
// ImageRequest is the native http request body for imagen
type ImageRequest struct {
Instances []ImageInstance `json:"instances"`
Parameters ImageParameters `json:"parameters"`
}
type ImageInstance struct {
Prompt string `json:"prompt"`
}
type ImageParameters struct {
SampleCount int `json:"sampleCount,omitempty"`
AspectRatio string `json:"aspectRatio,omitempty"`
PersonGeneration string `json:"personGeneration,omitempty"`
}
// ImageResponse is the native http response body for imagen
type ImageResponse struct {
Predictions []ImagePrediction `json:"predictions"`
}
type ImagePrediction struct {
MimeType string `json:"mimeType"`
BytesBase64Encoded string `json:"bytesBase64Encoded"`
}
================================================
FILE: adapter/request.go
================================================
package adapter
import (
adaptercommon "chat/adapter/common"
"chat/globals"
"chat/utils"
"fmt"
"strings"
"time"
)
func IsAvailableError(err error) bool {
return err != nil && (err.Error() != "signal" && !strings.Contains(err.Error(), "signal"))
}
func IsSkipError(err error) bool {
return err == nil || (err.Error() == "signal" || strings.Contains(err.Error(), "signal"))
}
func isQPSOverLimit(model string, err error) bool {
if strings.Contains(model, "spark-desk") {
return strings.Contains(err.Error(), "AppIdQpsOverFlowError")
}
return false
}
func NewChatRequest(conf globals.ChannelConfig, props *adaptercommon.ChatProps, hook globals.Hook) error {
err := createChatRequest(conf, props, hook)
retries := conf.GetRetry()
props.Current++
if IsAvailableError(err) {
if isQPSOverLimit(props.OriginalModel, err) {
// sleep for 0.5s to avoid qps limit
globals.Info(fmt.Sprintf("qps limit for %s, sleep and retry (times: %d)", props.OriginalModel, props.Current))
time.Sleep(500 * time.Millisecond)
return NewChatRequest(conf, props, hook)
}
if props.Current < retries {
content := strings.Replace(err.Error(), "\n", "", -1)
globals.Warn(fmt.Sprintf("retrying chat request for %s (attempt %d/%d, error: %s)", props.OriginalModel, props.Current+1, retries, content))
return NewChatRequest(conf, props, hook)
}
}
return conf.ProcessError(err)
}
func NewVideoRequest(conf globals.ChannelConfig, props *adaptercommon.VideoProps, hook globals.Hook) error {
err := createVideoRequest(conf, props, hook)
retries := conf.GetRetry()
props.Current++
if IsAvailableError(err) {
if isQPSOverLimit(props.OriginalModel, err) {
// sleep for 0.5s to avoid qps limit
globals.Info(fmt.Sprintf("qps limit for %s, sleep and retry (times: %d)", props.OriginalModel, props.Current))
time.Sleep(500 * time.Millisecond)
return NewVideoRequest(conf, props, hook)
}
if props.Current < retries {
content := strings.Replace(err.Error(), "\n", "", -1)
globals.Info(fmt.Sprintf("retrying error request for %s (attempt %d/%d, error: %s)", props.OriginalModel, props.Current+1, retries, content))
return NewVideoRequest(conf, props, hook)
}
}
return conf.ProcessError(err)
}
func ClearMessages(model string, messages []globals.Message) []globals.Message {
if globals.IsVisionModel(model) {
return messages
}
return utils.Each[globals.Message](messages, func(message globals.Message) globals.Message {
if message.Role != globals.User {
return message
}
images := utils.ExtractBase64Images(message.Content)
for _, image := range images {
if len(image) <= 46 {
continue
}
message.Content = strings.Replace(message.Content, image, utils.Extract(image, 46, " ..."), -1)
}
return message
})
}
================================================
FILE: adapter/router.go
================================================
package adapter
import (
"chat/adapter/midjourney"
"github.com/gin-gonic/gin"
)
func Register(app *gin.RouterGroup) {
app.POST("/mj/notify", midjourney.NotifyAPI)
}
================================================
FILE: adapter/skylark/chat.go
================================================
package skylark
import (
adaptercommon "chat/adapter/common"
"chat/globals"
"chat/utils"
"context"
"fmt"
"io"
"github.com/volcengine/volcengine-go-sdk/service/arkruntime/model"
"github.com/volcengine/volcengine-go-sdk/volcengine"
)
const defaultMaxTokens int = 4096
func getMessages(messages []globals.Message) []*model.ChatCompletionMessage {
result := make([]*model.ChatCompletionMessage, 0)
for _, message := range messages {
if message.Role == globals.Tool {
message.Role = model.ChatMessageRoleTool
}
msg := &model.ChatCompletionMessage{
Role: message.Role,
Content: &model.ChatCompletionMessageContent{StringValue: volcengine.String(message.Content)},
FunctionCall: getFunctionCall(message.ToolCalls),
ReasoningContent: message.ReasoningContent,
}
hasPrevious := len(result) > 0
// a message should not followed by the same role message, merge them
if hasPrevious && result[len(result)-1].Role == message.Role {
prev := result[len(result)-1]
prev.Content.StringValue = volcengine.String(*prev.Content.StringValue + *msg.Content.StringValue)
if message.ToolCalls != nil {
prev.FunctionCall = msg.FunctionCall
}
continue
}
// `assistant` message should follow a user or function message, if not has previous message, change the role to `user`
if !hasPrevious && message.Role == model.ChatMessageRoleAssistant {
msg.Role = model.ChatMessageRoleUser
}
result = append(result, msg)
}
return result
}
func (c *ChatInstance) GetMaxTokens(token *int) int {
if token == nil || *token < 0 {
return defaultMaxTokens
}
return *token
}
func (c *ChatInstance) CreateRequest(props *adaptercommon.ChatProps) *model.ChatCompletionRequest {
return &model.ChatCompletionRequest{
Model: props.Model,
Messages: getMessages(props.Message),
Temperature: utils.GetPtrVal(props.Temperature, 0.),
TopP: utils.GetPtrVal(props.TopP, 0.),
// skylark v3 not support TopK
PresencePenalty: utils.GetPtrVal(props.PresencePenalty, 0.),
FrequencyPenalty: utils.GetPtrVal(props.FrequencyPenalty, 0.),
RepetitionPenalty: utils.GetPtrVal(props.RepetitionPenalty, 0.),
MaxTokens: c.GetMaxTokens(props.MaxTokens),
FunctionCall: getFunctions(props.Tools),
}
}
func getToolCalls(id string, choiceDelta model.ChatCompletionStreamChoiceDelta) *globals.ToolCalls {
calls := choiceDelta.FunctionCall
if calls == nil {
return nil
}
return &globals.ToolCalls{
globals.ToolCall{
Type: "function",
Id: fmt.Sprintf("%s-%s", calls.Name, id),
Function: globals.ToolCallFunction{
Name: calls.Name,
Arguments: calls.Arguments,
},
},
}
}
func getChoice(choice model.ChatCompletionStreamResponse) *globals.Chunk {
if len(choice.Choices) == 0 {
return &globals.Chunk{Content: ""}
}
message := choice.Choices[0].Delta
return &globals.Chunk{
Content: message.Content,
ToolCall: getToolCalls(choice.ID, message),
}
}
func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.ChatProps, callback globals.Hook) error {
req := c.CreateRequest(props)
c.isFirstReasoning = true
c.isReasonOver = false
if globals.DebugMode {
globals.Debug(fmt.Sprintf("[skylark] request: %v", utils.Marshal(req)))
}
stream, err := c.Instance.CreateChatCompletionStream(context.Background(), req)
if err != nil {
if globals.DebugMode {
globals.Debug(fmt.Sprintf("[skylark] stream error: %v", err))
}
return err
}
defer stream.Close()
for {
recv, err2 := stream.Recv()
if err2 == io.EOF {
return nil
}
if err2 != nil {
if globals.DebugMode {
globals.Debug(fmt.Sprintf("[skylark] receive error: %v", err2))
}
return err2
}
if globals.DebugMode {
globals.Debug(fmt.Sp
gitextract__4v8y3mp/ ├── .dockerignore ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ ├── channel_update.md │ │ ├── config.yml │ │ └── feature_request.md │ └── workflows/ │ ├── app.yaml │ ├── build.yaml │ ├── docker-cd.yaml │ ├── docker-ci.yaml │ └── issue-translator.yaml ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── README_ja-JP.md ├── README_zh-CN.md ├── adapter/ │ ├── adapter.go │ ├── azure/ │ │ ├── chat.go │ │ ├── image.go │ │ ├── processor.go │ │ ├── struct.go │ │ └── types.go │ ├── baichuan/ │ │ ├── chat.go │ │ ├── processor.go │ │ ├── struct.go │ │ └── types.go │ ├── bing/ │ │ ├── chat.go │ │ ├── struct.go │ │ └── types.go │ ├── claude/ │ │ ├── chat.go │ │ ├── struct.go │ │ └── types.go │ ├── common/ │ │ ├── interface.go │ │ └── types.go │ ├── coze/ │ │ ├── chat.go │ │ ├── processor.go │ │ └── struct.go │ ├── dashscope/ │ │ ├── chat.go │ │ ├── struct.go │ │ └── types.go │ ├── deepseek/ │ │ ├── chat.go │ │ └── struct.go │ ├── dify/ │ │ ├── chat.go │ │ ├── processor.go │ │ └── struct.go │ ├── hunyuan/ │ │ ├── chat.go │ │ ├── sdk.go │ │ └── struct.go │ ├── midjourney/ │ │ ├── api.go │ │ ├── chat.go │ │ ├── expose.go │ │ ├── handler.go │ │ ├── storage.go │ │ ├── struct.go │ │ └── types.go │ ├── openai/ │ │ ├── chat.go │ │ ├── image.go │ │ ├── processor.go │ │ ├── struct.go │ │ ├── types.go │ │ └── videos.go │ ├── palm2/ │ │ ├── chat.go │ │ ├── formatter.go │ │ ├── image.go │ │ ├── struct.go │ │ └── types.go │ ├── request.go │ ├── router.go │ ├── skylark/ │ │ ├── chat.go │ │ ├── formatter.go │ │ └── struct.go │ ├── slack/ │ │ ├── chat.go │ │ └── struct.go │ ├── sparkdesk/ │ │ ├── chat.go │ │ ├── struct.go │ │ └── types.go │ ├── zhinao/ │ │ ├── chat.go │ │ ├── processor.go │ │ ├── struct.go │ │ └── types.go │ └── zhipuai/ │ ├── chat.go │ ├── processor.go │ ├── struct.go │ └── types.go ├── addition/ │ ├── article/ │ │ ├── api.go │ │ ├── data/ │ │ │ └── .gitkeep │ │ ├── generate.go │ │ ├── template.docx │ │ └── utils.go │ ├── card/ │ │ ├── .gitignore │ │ ├── card.go │ │ ├── card.php │ │ ├── error.php │ │ └── utils.php │ ├── generation/ │ │ ├── api.go │ │ ├── build.go │ │ ├── data/ │ │ │ └── .gitkeep │ │ ├── generate.go │ │ └── prompt.go │ ├── router.go │ └── web/ │ ├── call.go │ └── search.go ├── admin/ │ ├── analysis/ │ │ ├── analysis.go │ │ ├── format.go │ │ ├── reflect.go │ │ ├── statistic.go │ │ └── types.go │ ├── controller.go │ ├── format.go │ ├── instance.go │ ├── invitation.go │ ├── logger.go │ ├── market.go │ ├── redeem.go │ ├── router.go │ ├── statistic.go │ ├── types.go │ └── user.go ├── app/ │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── .prettierrc.json │ ├── components.json │ ├── index.html │ ├── package.json │ ├── postcss.config.js │ ├── public/ │ │ ├── manifest.json │ │ ├── robots.txt │ │ ├── service.js │ │ ├── site.webmanifest │ │ └── workbox.js │ ├── qodana.yaml │ ├── src/ │ │ ├── App.tsx │ │ ├── admin/ │ │ │ ├── api/ │ │ │ │ ├── channel.ts │ │ │ │ ├── charge.ts │ │ │ │ ├── chart.ts │ │ │ │ ├── info.ts │ │ │ │ ├── logger.ts │ │ │ │ ├── market.ts │ │ │ │ ├── plan.ts │ │ │ │ └── system.ts │ │ │ ├── channel.ts │ │ │ ├── charge.ts │ │ │ ├── colors.ts │ │ │ ├── datasets/ │ │ │ │ └── charge.ts │ │ │ ├── hook.tsx │ │ │ ├── market.ts │ │ │ └── types.ts │ │ ├── api/ │ │ │ ├── addition.ts │ │ │ ├── auth.ts │ │ │ ├── broadcast.ts │ │ │ ├── common.ts │ │ │ ├── connection.ts │ │ │ ├── file.ts │ │ │ ├── generation.ts │ │ │ ├── history.ts │ │ │ ├── mask.ts │ │ │ ├── plugin.ts │ │ │ ├── quota.ts │ │ │ ├── record.ts │ │ │ ├── redeem.ts │ │ │ ├── sharing.ts │ │ │ ├── types.tsx │ │ │ └── v1.ts │ │ ├── assets/ │ │ │ ├── admin/ │ │ │ │ ├── all.less │ │ │ │ ├── broadcast.less │ │ │ │ ├── channel.less │ │ │ │ ├── charge.less │ │ │ │ ├── dashboard.less │ │ │ │ ├── logger.less │ │ │ │ ├── management.less │ │ │ │ ├── market.less │ │ │ │ ├── menu.less │ │ │ │ ├── subscription.less │ │ │ │ └── system.less │ │ │ ├── common/ │ │ │ │ ├── 404.less │ │ │ │ ├── editor.less │ │ │ │ ├── file.less │ │ │ │ ├── loader.less │ │ │ │ └── plugin.less │ │ │ ├── fonts/ │ │ │ │ ├── all.less │ │ │ │ ├── common.less │ │ │ │ └── katex.less │ │ │ ├── globals.less │ │ │ ├── main.less │ │ │ ├── markdown/ │ │ │ │ ├── all.less │ │ │ │ ├── highlight.less │ │ │ │ ├── style.less │ │ │ │ └── theme.less │ │ │ ├── pages/ │ │ │ │ ├── api.less │ │ │ │ ├── article.less │ │ │ │ ├── auth.less │ │ │ │ ├── chat.less │ │ │ │ ├── generation.less │ │ │ │ ├── home.less │ │ │ │ ├── navbar.less │ │ │ │ ├── notify.less │ │ │ │ ├── package.less │ │ │ │ ├── preset.less │ │ │ │ ├── quota.less │ │ │ │ ├── record.less │ │ │ │ ├── settings.less │ │ │ │ ├── share-manager.less │ │ │ │ ├── sharing.less │ │ │ │ └── subscription.less │ │ │ └── ui.less │ │ ├── components/ │ │ │ ├── Avatar.tsx │ │ │ ├── EditorProvider.tsx │ │ │ ├── Emoji.tsx │ │ │ ├── ErrorBoundary.tsx │ │ │ ├── FileProvider.tsx │ │ │ ├── FileViewer.tsx │ │ │ ├── I18nProvider.tsx │ │ │ ├── Loader.tsx │ │ │ ├── MCPResultDebug.tsx │ │ │ ├── MCPResultPanel.tsx │ │ │ ├── Markdown.tsx │ │ │ ├── Message.tsx │ │ │ ├── ModelAvatar.tsx │ │ │ ├── OperationAction.tsx │ │ │ ├── Paragraph.tsx │ │ │ ├── PopupDialog.tsx │ │ │ ├── ProjectLink.tsx │ │ │ ├── ReloadService.tsx │ │ │ ├── Require.tsx │ │ │ ├── SelectGroup.tsx │ │ │ ├── ThemeProvider.tsx │ │ │ ├── ThinkContent.tsx │ │ │ ├── TickButton.tsx │ │ │ ├── Tips.tsx │ │ │ ├── TrendBadge.tsx │ │ │ ├── VoiceProvider.tsx │ │ │ ├── WarningButton.tsx │ │ │ ├── admin/ │ │ │ │ ├── ChannelSettings.tsx │ │ │ │ ├── ChargeWidget.tsx │ │ │ │ ├── ChartBox.tsx │ │ │ │ ├── InfoBox.tsx │ │ │ │ ├── InvitationTable.tsx │ │ │ │ ├── MenuBar.tsx │ │ │ │ ├── RedeemTable.tsx │ │ │ │ ├── UserTable.tsx │ │ │ │ ├── assemblies/ │ │ │ │ │ ├── BillingChart.tsx │ │ │ │ │ ├── BroadcastTable.tsx │ │ │ │ │ ├── ChannelEditor.tsx │ │ │ │ │ ├── ChannelTable.tsx │ │ │ │ │ ├── ErrorChart.tsx │ │ │ │ │ ├── ModelChart.tsx │ │ │ │ │ ├── ModelUsageChart.tsx │ │ │ │ │ ├── RequestChart.tsx │ │ │ │ │ └── UserTypeChart.tsx │ │ │ │ └── common/ │ │ │ │ └── StateBadge.tsx │ │ │ ├── app/ │ │ │ │ ├── Announcement.tsx │ │ │ │ ├── AppProvider.tsx │ │ │ │ ├── Contact.tsx │ │ │ │ ├── MenuBar.tsx │ │ │ │ └── NavBar.tsx │ │ │ ├── home/ │ │ │ │ ├── ChatInterface.tsx │ │ │ │ ├── ChatSpace.tsx │ │ │ │ ├── ChatWrapper.tsx │ │ │ │ ├── ConversationItem.tsx │ │ │ │ ├── MaskEditor.tsx │ │ │ │ ├── ModelArea.tsx │ │ │ │ ├── SideBar.tsx │ │ │ │ ├── assemblies/ │ │ │ │ │ ├── ActionButton.tsx │ │ │ │ │ ├── ChatAction.tsx │ │ │ │ │ ├── ChatInput.tsx │ │ │ │ │ └── ScrollAction.tsx │ │ │ │ └── subscription/ │ │ │ │ ├── SubscriptionUsage.tsx │ │ │ │ └── UpgradePlan.tsx │ │ │ ├── markdown/ │ │ │ │ ├── Code.tsx │ │ │ │ ├── Image.tsx │ │ │ │ ├── Label.tsx │ │ │ │ ├── Link.tsx │ │ │ │ ├── Reference.tsx │ │ │ │ ├── Video.tsx │ │ │ │ └── VirtualMessage.tsx │ │ │ ├── plugins/ │ │ │ │ ├── file.tsx │ │ │ │ ├── mermaid.tsx │ │ │ │ └── progress.tsx │ │ │ ├── ui/ │ │ │ │ ├── accordion.tsx │ │ │ │ ├── alert-dialog.tsx │ │ │ │ ├── alert.tsx │ │ │ │ ├── badge.tsx │ │ │ │ ├── button.tsx │ │ │ │ ├── calendar.tsx │ │ │ │ ├── card.tsx │ │ │ │ ├── checkbox.tsx │ │ │ │ ├── clickable.tsx │ │ │ │ ├── combo-box.tsx │ │ │ │ ├── command.tsx │ │ │ │ ├── context-menu.tsx │ │ │ │ ├── date-picker.tsx │ │ │ │ ├── dialog.tsx │ │ │ │ ├── drawer.tsx │ │ │ │ ├── dropdown-menu.tsx │ │ │ │ ├── icons/ │ │ │ │ │ ├── Github.tsx │ │ │ │ │ └── Send.tsx │ │ │ │ ├── input.tsx │ │ │ │ ├── label.tsx │ │ │ │ ├── lib/ │ │ │ │ │ └── utils.ts │ │ │ │ ├── multi-combobox.tsx │ │ │ │ ├── number-input.tsx │ │ │ │ ├── pagination.tsx │ │ │ │ ├── popover.tsx │ │ │ │ ├── progress.tsx │ │ │ │ ├── radio-box.tsx │ │ │ │ ├── radio-group.tsx │ │ │ │ ├── scroll-area.tsx │ │ │ │ ├── select.tsx │ │ │ │ ├── separator.tsx │ │ │ │ ├── sheet.tsx │ │ │ │ ├── skeleton.tsx │ │ │ │ ├── slider.tsx │ │ │ │ ├── sonner.tsx │ │ │ │ ├── step.tsx │ │ │ │ ├── switch.tsx │ │ │ │ ├── table.tsx │ │ │ │ ├── tabs.tsx │ │ │ │ ├── textarea.tsx │ │ │ │ ├── toast.tsx │ │ │ │ ├── toaster.tsx │ │ │ │ ├── toggle-group.tsx │ │ │ │ ├── toggle.tsx │ │ │ │ ├── tooltip.tsx │ │ │ │ └── use-toast.ts │ │ │ └── utils/ │ │ │ └── Icon.tsx │ │ ├── conf/ │ │ │ ├── api.ts │ │ │ ├── bootstrap.ts │ │ │ ├── deeptrain.tsx │ │ │ ├── env.ts │ │ │ ├── model.ts │ │ │ ├── storage.ts │ │ │ ├── subscription.tsx │ │ │ └── version.json │ │ ├── dialogs/ │ │ │ ├── SettingsDialog.tsx │ │ │ └── index.tsx │ │ ├── events/ │ │ │ ├── blob.ts │ │ │ ├── info.ts │ │ │ ├── model.ts │ │ │ ├── spinner.ts │ │ │ ├── struct.ts │ │ │ └── theme.ts │ │ ├── i18n.ts │ │ ├── main.tsx │ │ ├── masks/ │ │ │ ├── prompts.ts │ │ │ └── types.ts │ │ ├── payment/ │ │ │ ├── icons.tsx │ │ │ ├── request.ts │ │ │ └── utils.ts │ │ ├── plugin/ │ │ │ └── types.ts │ │ ├── resources/ │ │ │ └── i18n/ │ │ │ ├── cn.json │ │ │ ├── en.json │ │ │ ├── ja.json │ │ │ ├── ru.json │ │ │ └── tw.json │ │ ├── router.tsx │ │ ├── routes/ │ │ │ ├── Account.tsx │ │ │ ├── Admin.tsx │ │ │ ├── Article.tsx │ │ │ ├── Auth.tsx │ │ │ ├── Forgot.tsx │ │ │ ├── Generation.tsx │ │ │ ├── Home.tsx │ │ │ ├── Index.tsx │ │ │ ├── Model.tsx │ │ │ ├── NotFound.tsx │ │ │ ├── Register.tsx │ │ │ ├── Sharing.tsx │ │ │ ├── Wallet.tsx │ │ │ ├── admin/ │ │ │ │ ├── Broadcast.tsx │ │ │ │ ├── Channel.tsx │ │ │ │ ├── Charge.tsx │ │ │ │ ├── DashBoard.tsx │ │ │ │ ├── License.tsx │ │ │ │ ├── Logger.tsx │ │ │ │ ├── Market.tsx │ │ │ │ ├── Notification.tsx │ │ │ │ ├── Subscription.tsx │ │ │ │ ├── System.tsx │ │ │ │ ├── Users.tsx │ │ │ │ └── common/ │ │ │ │ └── CommonAdminPage.tsx │ │ │ └── wallet/ │ │ │ ├── AmountItem.tsx │ │ │ └── WalletQuotaBox.tsx │ │ ├── spinner.tsx │ │ ├── store/ │ │ │ ├── api.ts │ │ │ ├── auth.ts │ │ │ ├── avatar.ts │ │ │ ├── chat.ts │ │ │ ├── globals.ts │ │ │ ├── index.ts │ │ │ ├── info.ts │ │ │ ├── menu.ts │ │ │ ├── package.ts │ │ │ ├── quota.ts │ │ │ ├── record.ts │ │ │ ├── settings.ts │ │ │ ├── sharing.ts │ │ │ ├── subscription.ts │ │ │ └── utils.ts │ │ ├── translator/ │ │ │ ├── adapter.ts │ │ │ ├── index.ts │ │ │ ├── io.ts │ │ │ └── translator.ts │ │ ├── types/ │ │ │ ├── performance.d.ts │ │ │ ├── service.d.ts │ │ │ └── ui.d.ts │ │ ├── utils/ │ │ │ ├── analytics.ts │ │ │ ├── app.ts │ │ │ ├── base.ts │ │ │ ├── date.ts │ │ │ ├── desktop.ts │ │ │ ├── dev.ts │ │ │ ├── device.ts │ │ │ ├── dom.ts │ │ │ ├── form.ts │ │ │ ├── groups.ts │ │ │ ├── hook.ts │ │ │ ├── loader.tsx │ │ │ ├── memory.ts │ │ │ ├── path.ts │ │ │ └── processor.ts │ │ └── vite-env.d.ts │ ├── src-tauri/ │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ ├── build.rs │ │ ├── icons/ │ │ │ └── icon.icns │ │ ├── src/ │ │ │ └── main.rs │ │ └── tauri.conf.json │ ├── tailwind.config.js │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── auth/ │ ├── analysis.go │ ├── apikey.go │ ├── auth.go │ ├── call.go │ ├── cert.go │ ├── controller.go │ ├── invitation.go │ ├── package.go │ ├── payment.go │ ├── quota.go │ ├── redeem.go │ ├── router.go │ ├── rule.go │ ├── struct.go │ ├── subscription.go │ ├── usage.go │ └── validators.go ├── channel/ │ ├── channel.go │ ├── charge.go │ ├── controller.go │ ├── manager.go │ ├── plan.go │ ├── router.go │ ├── sequence.go │ ├── system.go │ ├── ticker.go │ ├── types.go │ └── worker.go ├── cli/ │ ├── admin.go │ ├── exec.go │ ├── help.go │ ├── invite.go │ ├── parser.go │ └── token.go ├── config.example.yaml ├── connection/ │ ├── cache.go │ ├── database.go │ ├── db_migration.go │ └── worker.go ├── docker-compose.stable.yaml ├── docker-compose.watch.yaml ├── docker-compose.yaml ├── globals/ │ ├── constant.go │ ├── interface.go │ ├── logger.go │ ├── method.go │ ├── params.go │ ├── sql.go │ ├── tools.go │ ├── types.go │ ├── usage.go │ └── variables.go ├── go.mod ├── go.sum ├── main.go ├── manager/ │ ├── broadcast/ │ │ ├── controller.go │ │ ├── manage.go │ │ ├── router.go │ │ ├── types.go │ │ └── view.go │ ├── chat.go │ ├── chat_completions.go │ ├── completions.go │ ├── connection.go │ ├── conversation/ │ │ ├── api.go │ │ ├── conversation.go │ │ ├── mask.go │ │ ├── router.go │ │ ├── shared.go │ │ └── storage.go │ ├── images.go │ ├── manager.go │ ├── relay.go │ ├── router.go │ ├── types.go │ ├── usage.go │ └── videos.go ├── middleware/ │ ├── auth.go │ ├── builtins.go │ ├── cors.go │ ├── middleware.go │ └── throttle.go ├── migration/ │ ├── 3.6.sql │ └── 3.8.sql ├── nginx.conf ├── utils/ │ ├── base.go │ ├── bootstrap.go │ ├── buffer.go │ ├── cache.go │ ├── char.go │ ├── compress.go │ ├── config.go │ ├── ctx.go │ ├── encrypt.go │ ├── fs.go │ ├── image.go │ ├── net.go │ ├── scanner.go │ ├── smtp.go │ ├── sse.go │ ├── templates/ │ │ └── code.html │ ├── tokenizer.go │ └── websocket.go └── zeabur.yaml
Showing preview only (227K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (2665 symbols across 398 files)
FILE: adapter/adapter.go
function createChatRequest (line 49) | func createChatRequest(conf globals.ChannelConfig, props *adaptercommon....
function createVideoRequest (line 61) | func createVideoRequest(conf globals.ChannelConfig, props *adaptercommon...
FILE: adapter/azure/chat.go
method GetChatEndpoint (line 12) | func (c *ChatInstance) GetChatEndpoint(props *adaptercommon.ChatProps) s...
method GetCompletionPrompt (line 20) | func (c *ChatInstance) GetCompletionPrompt(messages []globals.Message) s...
method GetLatestPrompt (line 28) | func (c *ChatInstance) GetLatestPrompt(props *adaptercommon.ChatProps) s...
method GetChatBody (line 36) | func (c *ChatInstance) GetChatBody(props *adaptercommon.ChatProps, strea...
method CreateChatRequest (line 60) | func (c *ChatInstance) CreateChatRequest(props *adaptercommon.ChatProps)...
method CreateStreamChatRequest (line 86) | func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.Chat...
FILE: adapter/azure/image.go
type ImageProps (line 11) | type ImageProps struct
method GetImageEndpoint (line 18) | func (c *ChatInstance) GetImageEndpoint(model string) string {
method CreateImageRequest (line 24) | func (c *ChatInstance) CreateImageRequest(props ImageProps) (string, str...
method CreateImage (line 56) | func (c *ChatInstance) CreateImage(props *adaptercommon.ChatProps) (stri...
FILE: adapter/azure/processor.go
function formatMessages (line 12) | func formatMessages(props *adaptercommon.ChatProps) interface{} {
function processChatResponse (line 66) | func processChatResponse(data string) *ChatStreamResponse {
function processCompletionResponse (line 70) | func processCompletionResponse(data string) *CompletionResponse {
function processChatErrorResponse (line 74) | func processChatErrorResponse(data string) *ChatStreamErrorResponse {
function getChoices (line 78) | func getChoices(form *ChatStreamResponse) *globals.Chunk {
function getCompletionChoices (line 92) | func getCompletionChoices(form *CompletionResponse) string {
function getRobustnessResult (line 100) | func getRobustnessResult(chunk string) string {
method ProcessLine (line 115) | func (c *ChatInstance) ProcessLine(data string, isCompletionType bool) (...
FILE: adapter/azure/struct.go
type ChatInstance (line 8) | type ChatInstance struct
method GetEndpoint (line 14) | func (c *ChatInstance) GetEndpoint() string {
method GetApiKey (line 18) | func (c *ChatInstance) GetApiKey() string {
method GetResource (line 22) | func (c *ChatInstance) GetResource() string {
method GetHeader (line 26) | func (c *ChatInstance) GetHeader() map[string]string {
function NewChatInstance (line 33) | func NewChatInstance(endpoint, apiKey string, resource string) *ChatInst...
function NewChatInstanceFromConfig (line 41) | func NewChatInstanceFromConfig(conf globals.ChannelConfig) factory.Facto...
FILE: adapter/azure/types.go
type ImageUrl (line 5) | type ImageUrl struct
type MessageContent (line 10) | type MessageContent struct
type MessageContents (line 16) | type MessageContents
type Message (line 18) | type Message struct
type ChatRequest (line 28) | type ChatRequest struct
type CompletionRequest (line 43) | type CompletionRequest struct
type ChatResponse (line 51) | type ChatResponse struct
type ChatStreamResponse (line 67) | type ChatStreamResponse struct
type CompletionResponse (line 80) | type CompletionResponse struct
type ChatStreamErrorResponse (line 91) | type ChatStreamErrorResponse struct
type ImageSize (line 98) | type ImageSize
type ImageRequest (line 101) | type ImageRequest struct
type ImageResponse (line 108) | type ImageResponse struct
FILE: adapter/baichuan/chat.go
method GetChatEndpoint (line 11) | func (c *ChatInstance) GetChatEndpoint() string {
method GetModel (line 15) | func (c *ChatInstance) GetModel(model string) string {
method GetMessages (line 24) | func (c *ChatInstance) GetMessages(messages []globals.Message) []globals...
method GetChatBody (line 34) | func (c *ChatInstance) GetChatBody(props *adaptercommon.ChatProps, strea...
method CreateChatRequest (line 46) | func (c *ChatInstance) CreateChatRequest(props *adaptercommon.ChatProps)...
method CreateStreamChatRequest (line 68) | func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.Chat...
FILE: adapter/baichuan/processor.go
function processChatResponse (line 10) | func processChatResponse(data string) *ChatStreamResponse {
function processChatErrorResponse (line 14) | func processChatErrorResponse(data string) *ChatStreamErrorResponse {
function getChoices (line 18) | func getChoices(form *ChatStreamResponse) *globals.Chunk {
method ProcessLine (line 30) | func (c *ChatInstance) ProcessLine(data string) (*globals.Chunk, error) {
FILE: adapter/baichuan/struct.go
type ChatInstance (line 9) | type ChatInstance struct
method GetEndpoint (line 14) | func (c *ChatInstance) GetEndpoint() string {
method GetApiKey (line 18) | func (c *ChatInstance) GetApiKey() string {
method GetHeader (line 22) | func (c *ChatInstance) GetHeader() map[string]string {
function NewChatInstance (line 29) | func NewChatInstance(endpoint, apiKey string) *ChatInstance {
function NewChatInstanceFromConfig (line 36) | func NewChatInstanceFromConfig(conf globals.ChannelConfig) factory.Facto...
FILE: adapter/baichuan/types.go
type ChatRequest (line 7) | type ChatRequest struct
type ChatResponse (line 18) | type ChatResponse struct
type ChatStreamResponse (line 34) | type ChatStreamResponse struct
type ChatStreamErrorResponse (line 47) | type ChatStreamErrorResponse struct
FILE: adapter/bing/chat.go
method CreateStreamChatRequest (line 11) | func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.Chat...
FILE: adapter/bing/struct.go
type ChatInstance (line 9) | type ChatInstance struct
method GetEndpoint (line 14) | func (c *ChatInstance) GetEndpoint() string {
function NewChatInstance (line 18) | func NewChatInstance(endpoint, secret string) *ChatInstance {
function NewChatInstanceFromConfig (line 25) | func NewChatInstanceFromConfig(conf globals.ChannelConfig) factory.Facto...
FILE: adapter/bing/types.go
type ChatRequest (line 5) | type ChatRequest struct
type ChatResponse (line 11) | type ChatResponse struct
FILE: adapter/claude/chat.go
constant defaultTokens (line 11) | defaultTokens = 2500
method GetChatEndpoint (line 13) | func (c *ChatInstance) GetChatEndpoint() string {
method GetChatHeaders (line 17) | func (c *ChatInstance) GetChatHeaders() map[string]string {
method ConvertCompletionMessage (line 26) | func (c *ChatInstance) ConvertCompletionMessage(message []globals.Messag...
method GetTokens (line 48) | func (c *ChatInstance) GetTokens(props *adaptercommon.ChatProps) int {
method ConvertMessages (line 56) | func (c *ChatInstance) ConvertMessages(props *adaptercommon.ChatProps) [...
method GetMessages (line 89) | func (c *ChatInstance) GetMessages(props *adaptercommon.ChatProps) []Mes...
method GetSystemPrompt (line 128) | func (c *ChatInstance) GetSystemPrompt(props *adaptercommon.ChatProps) (...
method GetChatBody (line 137) | func (c *ChatInstance) GetChatBody(props *adaptercommon.ChatProps, strea...
method ProcessLine (line 151) | func (c *ChatInstance) ProcessLine(data string) (*globals.Chunk, error) {
function processChatErrorResponse (line 165) | func processChatErrorResponse(data string) *ChatErrorResponse {
function processChatResponse (line 172) | func processChatResponse(data string) *ChatStreamResponse {
method CreateStreamChatRequest (line 180) | func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.Chat...
FILE: adapter/claude/struct.go
type ChatInstance (line 8) | type ChatInstance struct
method GetEndpoint (line 27) | func (c *ChatInstance) GetEndpoint() string {
method GetApiKey (line 31) | func (c *ChatInstance) GetApiKey() string {
function NewChatInstance (line 13) | func NewChatInstance(endpoint, apiKey string) *ChatInstance {
function NewChatInstanceFromConfig (line 20) | func NewChatInstanceFromConfig(conf globals.ChannelConfig) factory.Facto...
FILE: adapter/claude/types.go
type Message (line 5) | type Message struct
type MessageImage (line 10) | type MessageImage struct
type MessageContent (line 16) | type MessageContent struct
type ChatBody (line 22) | type ChatBody struct
type ChatStreamResponse (line 33) | type ChatStreamResponse struct
type ChatErrorResponse (line 42) | type ChatErrorResponse struct
FILE: adapter/common/interface.go
type Factory (line 7) | type Factory interface
type VideoFactory (line 11) | type VideoFactory interface
type FactoryCreator (line 15) | type FactoryCreator
FILE: adapter/common/types.go
type RequestProps (line 8) | type RequestProps struct
type VideoProps (line 15) | type VideoProps struct
type ChatProps (line 29) | type ChatProps struct
method SetupBuffer (line 48) | func (c *ChatProps) SetupBuffer(buf *utils.Buffer) {
function CreateChatProps (line 53) | func CreateChatProps(props *ChatProps, buffer *utils.Buffer) *ChatProps {
function CreateVideoProps (line 58) | func CreateVideoProps(props *VideoProps) *VideoProps {
FILE: adapter/coze/chat.go
type ChatInstance (line 15) | type ChatInstance struct
method GetEndpoint (line 22) | func (c *ChatInstance) GetEndpoint() string {
method GetApiKey (line 26) | func (c *ChatInstance) GetApiKey() string {
method GetHeader (line 30) | func (c *ChatInstance) GetHeader() map[string]string {
method GetChatEndpoint (line 52) | func (c *ChatInstance) GetChatEndpoint() string {
method GetChatBody (line 56) | func (c *ChatInstance) GetChatBody(props *adaptercommon.ChatProps, str...
method ProcessLine (line 88) | func (c *ChatInstance) ProcessLine(data string) (string, error) {
method CreateChatRequest (line 109) | func (c *ChatInstance) CreateChatRequest(props *adaptercommon.ChatProp...
method CreateStreamChatRequest (line 155) | func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.Ch...
function NewChatInstance (line 37) | func NewChatInstance(endpoint, apiKey string) *ChatInstance {
function NewChatInstanceFromConfig (line 45) | func NewChatInstanceFromConfig(conf globals.ChannelConfig) adaptercommon...
FILE: adapter/coze/processor.go
function processChatResponse (line 12) | func processChatResponse(data string) *ChatResponse {
function processChatStreamResponse (line 19) | func processChatStreamResponse(data string) *ChatStreamResponse {
function processChatStreamData (line 26) | func processChatStreamData(data string) *ChatStreamData {
function processChatErrorResponse (line 33) | func processChatErrorResponse(data string) *ChatStreamErrorResponse {
function processSSEData (line 40) | func processSSEData(data string) (event string, eventData string, err er...
function processEventContent (line 69) | func processEventContent(event string, eventData string) (content string...
function parseEventContent (line 116) | func parseEventContent(eventType string, eventData string) (string, erro...
function processStreamResponse (line 129) | func processStreamResponse(data string) (*globals.Chunk, bool, error) {
FILE: adapter/coze/struct.go
type ChatRequest (line 3) | type ChatRequest struct
type EnterMessage (line 15) | type EnterMessage struct
type ShortcutCommand (line 23) | type ShortcutCommand struct
type ObjectString (line 27) | type ObjectString struct
type ChatResponse (line 34) | type ChatResponse struct
type Usage (line 50) | type Usage struct
type ChatStreamResponse (line 56) | type ChatStreamResponse struct
type ChatStreamData (line 61) | type ChatStreamData struct
type ChatStreamErrorResponse (line 92) | type ChatStreamErrorResponse struct
FILE: adapter/dashscope/chat.go
constant defaultMaxTokens (line 11) | defaultMaxTokens = 1500
method GetHeader (line 13) | func (c *ChatInstance) GetHeader() map[string]string {
method FormatMessages (line 21) | func (c *ChatInstance) FormatMessages(message []globals.Message) []Messa...
method GetMaxTokens (line 47) | func (c *ChatInstance) GetMaxTokens(props *adaptercommon.ChatProps) int {
method GetTopP (line 56) | func (c *ChatInstance) GetTopP(props *adaptercommon.ChatProps) *float32 {
method GetRepeatPenalty (line 71) | func (c *ChatInstance) GetRepeatPenalty(props *adaptercommon.ChatProps) ...
method GetChatBody (line 84) | func (c *ChatInstance) GetChatBody(props *adaptercommon.ChatProps) ChatR...
method GetChatEndpoint (line 102) | func (c *ChatInstance) GetChatEndpoint() string {
method CreateStreamChatRequest (line 106) | func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.Chat...
FILE: adapter/dashscope/struct.go
type ChatInstance (line 8) | type ChatInstance struct
method GetApiKey (line 13) | func (c *ChatInstance) GetApiKey() string {
method GetEndpoint (line 17) | func (c *ChatInstance) GetEndpoint() string {
function NewChatInstance (line 21) | func NewChatInstance(endpoint string, apiKey string) *ChatInstance {
function NewChatInstanceFromConfig (line 28) | func NewChatInstanceFromConfig(conf globals.ChannelConfig) factory.Facto...
FILE: adapter/dashscope/types.go
type ChatRequest (line 4) | type ChatRequest struct
type Message (line 10) | type Message struct
type ChatInput (line 15) | type ChatInput struct
type ChatParam (line 19) | type ChatParam struct
type ChatResponse (line 30) | type ChatResponse struct
FILE: adapter/deepseek/chat.go
type ChatInstance (line 11) | type ChatInstance struct
method GetEndpoint (line 18) | func (c *ChatInstance) GetEndpoint() string {
method GetApiKey (line 22) | func (c *ChatInstance) GetApiKey() string {
method GetHeader (line 26) | func (c *ChatInstance) GetHeader() map[string]string {
method GetChatEndpoint (line 48) | func (c *ChatInstance) GetChatEndpoint() string {
method GetChatBody (line 52) | func (c *ChatInstance) GetChatBody(props *adaptercommon.ChatProps, str...
method ProcessLine (line 95) | func (c *ChatInstance) ProcessLine(data string) (string, error) {
method CreateChatRequest (line 132) | func (c *ChatInstance) CreateChatRequest(props *adaptercommon.ChatProp...
method CreateStreamChatRequest (line 162) | func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.Ch...
function NewChatInstance (line 33) | func NewChatInstance(endpoint, apiKey string) *ChatInstance {
function NewChatInstanceFromConfig (line 41) | func NewChatInstanceFromConfig(conf globals.ChannelConfig) adaptercommon...
function processChatResponse (line 74) | func processChatResponse(data string) *ChatResponse {
function processChatStreamResponse (line 81) | func processChatStreamResponse(data string) *ChatStreamResponse {
function processChatErrorResponse (line 88) | func processChatErrorResponse(data string) *ChatStreamErrorResponse {
FILE: adapter/deepseek/struct.go
type ChatRequest (line 9) | type ChatRequest struct
type ChatResponse (line 21) | type ChatResponse struct
type ChatStreamResponse (line 39) | type ChatStreamResponse struct
type ChatStreamErrorResponse (line 51) | type ChatStreamErrorResponse struct
FILE: adapter/dify/chat.go
type ChatInstance (line 14) | type ChatInstance struct
method GetEndpoint (line 20) | func (c *ChatInstance) GetEndpoint() string {
method GetApiKey (line 24) | func (c *ChatInstance) GetApiKey() string {
method GetHeader (line 28) | func (c *ChatInstance) GetHeader() map[string]string {
method GetChatEndpoint (line 49) | func (c *ChatInstance) GetChatEndpoint() string {
method GetChatBody (line 53) | func (c *ChatInstance) GetChatBody(props *adaptercommon.ChatProps, str...
method ProcessLine (line 74) | func (c *ChatInstance) ProcessLine(data string) (string, error) {
method CreateChatRequest (line 95) | func (c *ChatInstance) CreateChatRequest(props *adaptercommon.ChatProp...
method CreateStreamChatRequest (line 116) | func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.Ch...
function NewChatInstance (line 35) | func NewChatInstance(endpoint, apiKey string) *ChatInstance {
function NewChatInstanceFromConfig (line 42) | func NewChatInstanceFromConfig(conf globals.ChannelConfig) adaptercommon...
FILE: adapter/dify/processor.go
function processChatResponse (line 10) | func processChatResponse(data string) *ChatResponse {
function processChatStreamResponse (line 17) | func processChatStreamResponse(data string) *ChatStreamResponse {
function processChatErrorResponse (line 24) | func processChatErrorResponse(data string) *ChatStreamErrorResponse {
function processStreamResponse (line 31) | func processStreamResponse(data string) (*globals.Chunk, bool, error) {
FILE: adapter/dify/struct.go
type ChatRequest (line 3) | type ChatRequest struct
type File (line 13) | type File struct
type ChatResponse (line 20) | type ChatResponse struct
type Usage (line 31) | type Usage struct
type RetrieverResource (line 37) | type RetrieverResource struct
type ChatStreamResponse (line 43) | type ChatStreamResponse struct
type ChatStreamErrorResponse (line 59) | type ChatStreamErrorResponse struct
FILE: adapter/hunyuan/chat.go
method FormatMessages (line 10) | func (c *ChatInstance) FormatMessages(messages []globals.Message) []glob...
method CreateStreamChatRequest (line 33) | func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.Chat...
FILE: adapter/hunyuan/sdk.go
constant defaultProtocol (line 39) | defaultProtocol = "https"
constant defaultHost (line 40) | defaultHost = "hunyuan.cloud.tencent.com"
constant path (line 41) | path = "/hyllm/v1/chat/completions?"
constant Synchronize (line 45) | Synchronize = iota
constant Stream (line 46) | Stream
function getUrl (line 49) | func getUrl(endpoint string) string {
function getProtocol (line 53) | func getProtocol(endpoint string) string {
function getHost (line 62) | func getHost(endpoint string) string {
function getFullPath (line 71) | func getFullPath(endpoint string) string {
type ResponseChoices (line 75) | type ResponseChoices struct
type ResponseUsage (line 81) | type ResponseUsage struct
type ResponseError (line 87) | type ResponseError struct
type StreamDelta (line 92) | type StreamDelta struct
type ChatRequest (line 96) | type ChatRequest struct
type ChatResponse (line 108) | type ChatResponse struct
type Credential (line 118) | type Credential struct
function NewCredential (line 123) | func NewCredential(secretID, secretKey string) *Credential {
type Client (line 127) | type Client struct
method getHttpReq (line 154) | func (t *Client) getHttpReq(ctx context.Context, req ChatRequest) (*ht...
method Chat (line 180) | func (t *Client) Chat(ctx context.Context, req ChatRequest) (<-chan Ch...
method synchronize (line 203) | func (t *Client) synchronize(httpResp *http.Response, res chan ChatRes...
method stream (line 221) | func (t *Client) stream(httpResp *http.Response, res chan ChatResponse) {
method genSignature (line 255) | func (t *Client) genSignature(url string) string {
method getMessages (line 263) | func (t *Client) getMessages(messages []globals.Message) string {
method buildURL (line 273) | func (t *Client) buildURL(req ChatRequest) string {
function NewInstance (line 133) | func NewInstance(appId int64, endpoint string, credential *Credential) *...
function NewRequest (line 141) | func NewRequest(mod int, messages []globals.Message, temperature *float3...
FILE: adapter/hunyuan/struct.go
type ChatInstance (line 9) | type ChatInstance struct
method GetAppId (line 16) | func (c *ChatInstance) GetAppId() int64 {
method GetEndpoint (line 20) | func (c *ChatInstance) GetEndpoint() string {
method GetSecretId (line 24) | func (c *ChatInstance) GetSecretId() string {
method GetSecretKey (line 28) | func (c *ChatInstance) GetSecretKey() string {
function NewChatInstance (line 32) | func NewChatInstance(endpoint, appId, secretId, secretKey string) *ChatI...
function NewChatInstanceFromConfig (line 41) | func NewChatInstanceFromConfig(conf globals.ChannelConfig) factory.Facto...
FILE: adapter/midjourney/api.go
method GetImagineEndpoint (line 9) | func (c *ChatInstance) GetImagineEndpoint() string {
method GetChangeEndpoint (line 13) | func (c *ChatInstance) GetChangeEndpoint() string {
method GetImagineRequest (line 17) | func (c *ChatInstance) GetImagineRequest(prompt string) *ImagineRequest {
method GetChangeRequest (line 24) | func (c *ChatInstance) GetChangeRequest(action string, task string, inde...
method CreateImagineRequest (line 33) | func (c *ChatInstance) CreateImagineRequest(proxy globals.ProxyConfig, p...
method CreateChangeRequest (line 52) | func (c *ChatInstance) CreateChangeRequest(proxy globals.ProxyConfig, ac...
FILE: adapter/midjourney/chat.go
constant maxActions (line 11) | maxActions = 4
constant ImagineAction (line 13) | ImagineAction = "IMAGINE"
constant UpscaleAction (line 14) | UpscaleAction = "UPSCALE"
constant VariationAction (line 15) | VariationAction = "VARIATION"
constant RerollAction (line 16) | RerollAction = "REROLL"
constant ImagineCommand (line 20) | ImagineCommand = "/IMAGINE"
constant UpscaleCommand (line 21) | UpscaleCommand = "/UPSCALE"
constant VariationCommand (line 22) | VariationCommand = "/VARIATION"
constant RerollCommand (line 23) | RerollCommand = "/REROLL"
type ChatProps (line 26) | type ChatProps struct
function getMode (line 31) | func getMode(model string) string {
method IsIgnoreMode (line 44) | func (c *ChatInstance) IsIgnoreMode() bool {
method GetCleanPrompt (line 50) | func (c *ChatInstance) GetCleanPrompt(model string, prompt string) string {
method GetPrompt (line 70) | func (c *ChatInstance) GetPrompt(props *adaptercommon.ChatProps) string {
method CreateStreamChatRequest (line 79) | func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.Chat...
function toVirtualMessage (line 139) | func toVirtualMessage(message string, model string) string {
method CallbackActions (line 144) | func (c *ChatInstance) CallbackActions(props *adaptercommon.ChatProps, f...
FILE: adapter/midjourney/expose.go
function SaveWhiteList (line 14) | func SaveWhiteList(raw string) {
function InWhiteList (line 26) | func InWhiteList(ip string) bool {
function NotifyAPI (line 33) | func NotifyAPI(c *gin.Context) {
FILE: adapter/midjourney/handler.go
constant maxTimeout (line 12) | maxTimeout = 30 * time.Minute
function getStatusCode (line 14) | func getStatusCode(action string, response *CommonResponse) error {
function getProgress (line 33) | func getProgress(value string) int {
method GetAction (line 38) | func (c *ChatInstance) GetAction(command string) string {
method ExtractPrompt (line 42) | func (c *ChatInstance) ExtractPrompt(input string) (action string, promp...
method ExtractCommand (line 56) | func (c *ChatInstance) ExtractCommand(input string) (task string, index ...
method CreateRequest (line 74) | func (c *ChatInstance) CreateRequest(proxy globals.ProxyConfig, action s...
method CreateStreamTask (line 87) | func (c *ChatInstance) CreateStreamTask(props *adaptercommon.ChatProps, ...
FILE: adapter/midjourney/storage.go
function getTaskName (line 9) | func getTaskName(task string) string {
function setStorage (line 13) | func setStorage(task string, form StorageForm) error {
function getNotifyStorage (line 17) | func getNotifyStorage(task string) *StorageForm {
FILE: adapter/midjourney/struct.go
type ChatInstance (line 11) | type ChatInstance struct
method GetApiSecret (line 16) | func (c *ChatInstance) GetApiSecret() string {
method GetEndpoint (line 20) | func (c *ChatInstance) GetEndpoint() string {
method GetMidjourneyHeaders (line 24) | func (c *ChatInstance) GetMidjourneyHeaders() map[string]string {
method GetNotifyEndpoint (line 38) | func (c *ChatInstance) GetNotifyEndpoint() string {
function NewChatInstance (line 42) | func NewChatInstance(endpoint, apiSecret, whiteList string) *ChatInstance {
function NewChatInstanceFromConfig (line 51) | func NewChatInstanceFromConfig(conf globals.ChannelConfig) factory.Facto...
FILE: adapter/midjourney/types.go
constant SuccessCode (line 4) | SuccessCode = 1
constant ExistedCode (line 5) | ExistedCode = 21
constant QueueCode (line 6) | QueueCode = 22
constant MaxQueueCode (line 7) | MaxQueueCode = 23
constant NudeCode (line 8) | NudeCode = 24
constant NotStartStatus (line 12) | NotStartStatus = "NOT_START"
constant Submitted (line 13) | Submitted = "SUBMITTED"
constant InProgress (line 14) | InProgress = "IN_PROGRESS"
constant Failure (line 15) | Failure = "FAILURE"
constant Success (line 16) | Success = "SUCCESS"
constant TurboMode (line 20) | TurboMode = "--turbo"
constant FastMode (line 21) | FastMode = "--fast"
constant RelaxMode (line 22) | RelaxMode = "--relax"
type CommonHeader (line 27) | type CommonHeader struct
type CommonResponse (line 32) | type CommonResponse struct
type ImagineRequest (line 38) | type ImagineRequest struct
type ChangeRequest (line 43) | type ChangeRequest struct
type NotifyForm (line 50) | type NotifyForm struct
type StorageForm (line 65) | type StorageForm struct
FILE: adapter/openai/chat.go
method GetChatEndpoint (line 13) | func (c *ChatInstance) GetChatEndpoint(props *adaptercommon.ChatProps) s...
method GetCompletionPrompt (line 20) | func (c *ChatInstance) GetCompletionPrompt(messages []globals.Message) s...
method GetLatestPrompt (line 28) | func (c *ChatInstance) GetLatestPrompt(props *adaptercommon.ChatProps) s...
method GetChatBody (line 36) | func (c *ChatInstance) GetChatBody(props *adaptercommon.ChatProps, strea...
method CreateChatRequest (line 81) | func (c *ChatInstance) CreateChatRequest(props *adaptercommon.ChatProps)...
function hideRequestId (line 106) | func hideRequestId(message string) string {
method CreateStreamChatRequest (line 114) | func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.Chat...
FILE: adapter/openai/image.go
type ImageProps (line 11) | type ImageProps struct
method GetImageEndpoint (line 18) | func (c *ChatInstance) GetImageEndpoint() string {
method CreateImageRequest (line 23) | func (c *ChatInstance) CreateImageRequest(props ImageProps) (string, str...
method CreateImage (line 56) | func (c *ChatInstance) CreateImage(props *adaptercommon.ChatProps) (stri...
FILE: adapter/openai/processor.go
function formatMessages (line 12) | func formatMessages(props *adaptercommon.ChatProps) interface{} {
function processChatResponse (line 64) | func processChatResponse(data string) *ChatStreamResponse {
function processCompletionResponse (line 68) | func processCompletionResponse(data string) *CompletionResponse {
function processChatErrorResponse (line 72) | func processChatErrorResponse(data string) *ChatStreamErrorResponse {
function getChoices (line 76) | func getChoices(form *ChatStreamResponse) *globals.Chunk {
function getCompletionChoices (line 90) | func getCompletionChoices(form *CompletionResponse) string {
function getRobustnessResult (line 98) | func getRobustnessResult(chunk string) string {
method ProcessLine (line 113) | func (c *ChatInstance) ProcessLine(data string, isCompletionType bool) (...
FILE: adapter/openai/struct.go
type ChatInstance (line 9) | type ChatInstance struct
method GetEndpoint (line 14) | func (c *ChatInstance) GetEndpoint() string {
method GetApiKey (line 18) | func (c *ChatInstance) GetApiKey() string {
method GetHeader (line 22) | func (c *ChatInstance) GetHeader() map[string]string {
function NewChatInstance (line 29) | func NewChatInstance(endpoint, apiKey string) *ChatInstance {
function NewChatInstanceFromConfig (line 36) | func NewChatInstanceFromConfig(conf globals.ChannelConfig) factory.Facto...
FILE: adapter/openai/types.go
type ImageUrl (line 5) | type ImageUrl struct
type MessageContent (line 10) | type MessageContent struct
type MessageContents (line 16) | type MessageContents
type Message (line 18) | type Message struct
type ChatRequest (line 29) | type ChatRequest struct
type CompletionRequest (line 44) | type CompletionRequest struct
type ChatResponse (line 52) | type ChatResponse struct
type ChatStreamResponse (line 68) | type ChatStreamResponse struct
type CompletionResponse (line 81) | type CompletionResponse struct
type ChatStreamErrorResponse (line 92) | type ChatStreamErrorResponse struct
type ImageSize (line 99) | type ImageSize
type ImageRequest (line 102) | type ImageRequest struct
type ImageResponse (line 109) | type ImageResponse struct
FILE: adapter/openai/videos.go
type VideoRequest (line 11) | type VideoRequest struct
type VideoJob (line 19) | type VideoJob struct
method getVideoCreateEndpoint (line 38) | func (c *ChatInstance) getVideoCreateEndpoint() string {
method getVideoQueryEndpoint (line 42) | func (c *ChatInstance) getVideoQueryEndpoint(id string) string {
method CreateVideoRequest (line 46) | func (c *ChatInstance) CreateVideoRequest(props *adaptercommon.VideoProp...
FILE: adapter/palm2/chat.go
method GetChatEndpoint (line 14) | func (c *ChatInstance) GetChatEndpoint(model string, stream bool) string {
method ConvertMessage (line 26) | func (c *ChatInstance) ConvertMessage(message []globals.Message) []PalmM...
method GetPalm2ChatBody (line 52) | func (c *ChatInstance) GetPalm2ChatBody(props *adaptercommon.ChatProps) ...
method GetGeminiChatBody (line 60) | func (c *ChatInstance) GetGeminiChatBody(props *adaptercommon.ChatProps)...
method GetPalm2ChatResponse (line 72) | func (c *ChatInstance) GetPalm2ChatResponse(data interface{}) (string, e...
method GetGeminiChatResponse (line 82) | func (c *ChatInstance) GetGeminiChatResponse(data interface{}) (string, ...
method CreateChatRequest (line 96) | func (c *ChatInstance) CreateChatRequest(props *adaptercommon.ChatProps)...
method CreateStreamChatRequest (line 122) | func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.Chat...
method GetLatestPrompt (line 201) | func (c *ChatInstance) GetLatestPrompt(props *adaptercommon.ChatProps) s...
FILE: adapter/palm2/formatter.go
function getGeminiRole (line 9) | func getGeminiRole(role string) string {
function getMimeType (line 20) | func getMimeType(content string) string {
function getGeminiContent (line 46) | func getGeminiContent(parts []GeminiChatPart, content string, model stri...
method GetGeminiContents (line 79) | func (c *ChatInstance) GetGeminiContents(model string, message []globals...
FILE: adapter/palm2/image.go
type ImageProps (line 11) | type ImageProps struct
method GetImageEndpoint (line 17) | func (c *ChatInstance) GetImageEndpoint(model string) string {
method CreateImageRequest (line 22) | func (c *ChatInstance) CreateImageRequest(props ImageProps) (string, err...
method CreateImage (line 60) | func (c *ChatInstance) CreateImage(props *adaptercommon.ChatProps) (stri...
FILE: adapter/palm2/struct.go
type ChatInstance (line 8) | type ChatInstance struct
method GetApiKey (line 13) | func (c *ChatInstance) GetApiKey() string {
method GetEndpoint (line 17) | func (c *ChatInstance) GetEndpoint() string {
function NewChatInstance (line 21) | func NewChatInstance(endpoint string, apiKey string) *ChatInstance {
function NewChatInstanceFromConfig (line 28) | func NewChatInstanceFromConfig(conf globals.ChannelConfig) factory.Facto...
FILE: adapter/palm2/types.go
constant GeminiUserType (line 4) | GeminiUserType = "user"
constant GeminiModelType (line 5) | GeminiModelType = "model"
type PalmMessage (line 8) | type PalmMessage struct
type PalmChatBody (line 14) | type PalmChatBody struct
type PalmPrompt (line 18) | type PalmPrompt struct
type PalmChatResponse (line 23) | type PalmChatResponse struct
type GeminiChatBody (line 28) | type GeminiChatBody struct
type GeminiConfig (line 33) | type GeminiConfig struct
type GeminiContent (line 40) | type GeminiContent struct
type GeminiChatPart (line 45) | type GeminiChatPart struct
type GeminiInlineData (line 50) | type GeminiInlineData struct
type GeminiChatResponse (line 55) | type GeminiChatResponse struct
type GeminiChatErrorResponse (line 66) | type GeminiChatErrorResponse struct
type GeminiStreamResponse (line 74) | type GeminiStreamResponse struct
type ImageRequest (line 86) | type ImageRequest struct
type ImageInstance (line 91) | type ImageInstance struct
type ImageParameters (line 95) | type ImageParameters struct
type ImageResponse (line 102) | type ImageResponse struct
type ImagePrediction (line 106) | type ImagePrediction struct
FILE: adapter/request.go
function IsAvailableError (line 12) | func IsAvailableError(err error) bool {
function IsSkipError (line 16) | func IsSkipError(err error) bool {
function isQPSOverLimit (line 20) | func isQPSOverLimit(model string, err error) bool {
function NewChatRequest (line 27) | func NewChatRequest(conf globals.ChannelConfig, props *adaptercommon.Cha...
function NewVideoRequest (line 52) | func NewVideoRequest(conf globals.ChannelConfig, props *adaptercommon.Vi...
function ClearMessages (line 77) | func ClearMessages(model string, messages []globals.Message) []globals.M...
FILE: adapter/router.go
function Register (line 8) | func Register(app *gin.RouterGroup) {
FILE: adapter/skylark/chat.go
constant defaultMaxTokens (line 15) | defaultMaxTokens int = 4096
function getMessages (line 17) | func getMessages(messages []globals.Message) []*model.ChatCompletionMess...
method GetMaxTokens (line 56) | func (c *ChatInstance) GetMaxTokens(token *int) int {
method CreateRequest (line 64) | func (c *ChatInstance) CreateRequest(props *adaptercommon.ChatProps) *mo...
function getToolCalls (line 79) | func getToolCalls(id string, choiceDelta model.ChatCompletionStreamChoic...
function getChoice (line 97) | func getChoice(choice model.ChatCompletionStreamResponse) *globals.Chunk {
method CreateStreamChatRequest (line 109) | func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.Chat...
FILE: adapter/skylark/formatter.go
function getFunctionCall (line 12) | func getFunctionCall(calls *globals.ToolCalls) *model.FunctionCall {
function getType (line 24) | func getType(p globals.ToolProperty) string {
function getDescription (line 33) | func getDescription(p globals.ToolProperty) string {
function getValue (line 42) | func getValue(p globals.ToolProperty) *structpb.Value {
function getFunctions (line 59) | func getFunctions(tools *globals.FunctionTools) []*api.Function {
FILE: adapter/skylark/struct.go
type ChatInstance (line 10) | type ChatInstance struct
function NewChatInstance (line 16) | func NewChatInstance(endpoint, apiKey string) *ChatInstance {
function NewChatInstanceFromConfig (line 26) | func NewChatInstanceFromConfig(conf globals.ChannelConfig) factory.Facto...
FILE: adapter/slack/chat.go
method CreateStreamChatRequest (line 9) | func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.Chat...
FILE: adapter/slack/struct.go
type ChatInstance (line 13) | type ChatInstance struct
method GetBotId (line 20) | func (c *ChatInstance) GetBotId() string {
method GetToken (line 24) | func (c *ChatInstance) GetToken() string {
method GetChannel (line 28) | func (c *ChatInstance) GetChannel() string {
method GetInstance (line 32) | func (c *ChatInstance) GetInstance() types.Chat {
method FormatMessage (line 58) | func (c *ChatInstance) FormatMessage(message []globals.Message) string {
method ProcessPartialResponse (line 70) | func (c *ChatInstance) ProcessPartialResponse(res chan types.PartialRe...
function NewChatInstance (line 36) | func NewChatInstance(botId, token, channel string) *ChatInstance {
function NewChatInstanceFromConfig (line 50) | func NewChatInstanceFromConfig(conf globals.ChannelConfig) factory.Facto...
FILE: adapter/sparkdesk/chat.go
function GetToken (line 16) | func GetToken(props *adaptercommon.ChatProps) *int {
function GetTopK (line 35) | func GetTopK(props *adaptercommon.ChatProps) *int {
method GetMessages (line 47) | func (c *ChatInstance) GetMessages(props *adaptercommon.ChatProps) []Mes...
method GetFunctionCalling (line 65) | func (c *ChatInstance) GetFunctionCalling(props *adaptercommon.ChatProps...
function getFunctionCall (line 82) | func getFunctionCall(call *FunctionCall) *globals.ToolCalls {
function getChoice (line 99) | func getChoice(form *ChatResponse) *globals.Chunk {
method CreateStreamChatRequest (line 117) | func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.Chat...
FILE: adapter/sparkdesk/struct.go
type ChatInstance (line 15) | type ChatInstance struct
method CreateUrl (line 67) | func (c *ChatInstance) CreateUrl(endpoint, host, date, auth string) st...
method Sign (line 75) | func (c *ChatInstance) Sign(data, key string) string {
method GenerateUrl (line 82) | func (c *ChatInstance) GenerateUrl(endpoint string) string {
function TransformAddr (line 22) | func TransformAddr(model string) string {
function TransformModel (line 37) | func TransformModel(model string) string {
function NewChatInstanceFromConfig (line 56) | func NewChatInstanceFromConfig(conf globals.ChannelConfig) factory.Facto...
FILE: adapter/sparkdesk/types.go
type ChatRequest (line 6) | type ChatRequest struct
type RequestHeader (line 12) | type RequestHeader struct
type RequestPayload (line 16) | type RequestPayload struct
type FunctionsPayload (line 21) | type FunctionsPayload struct
type Message (line 25) | type Message struct
type FunctionCall (line 31) | type FunctionCall struct
type MessagePayload (line 36) | type MessagePayload struct
type RequestParameter (line 40) | type RequestParameter struct
type ChatParameter (line 44) | type ChatParameter struct
type ChatResponse (line 52) | type ChatResponse struct
FILE: adapter/zhinao/chat.go
method GetChatEndpoint (line 11) | func (c *ChatInstance) GetChatEndpoint() string {
method GetModel (line 15) | func (c *ChatInstance) GetModel(model string) string {
method GetChatBody (line 24) | func (c *ChatInstance) GetChatBody(props *adaptercommon.ChatProps, strea...
method CreateChatRequest (line 49) | func (c *ChatInstance) CreateChatRequest(props *adaptercommon.ChatProps)...
method CreateStreamChatRequest (line 71) | func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.Chat...
FILE: adapter/zhinao/processor.go
function processFormat (line 11) | func processFormat(data string) string {
function processChatResponse (line 27) | func processChatResponse(data string) *ChatStreamResponse {
function processChatErrorResponse (line 46) | func processChatErrorResponse(data string) *ChatStreamErrorResponse {
function isDone (line 60) | func isDone(data string) bool {
function getChoices (line 67) | func getChoices(form *ChatStreamResponse) string {
method ProcessLine (line 75) | func (c *ChatInstance) ProcessLine(buf, data string) (string, error) {
FILE: adapter/zhinao/struct.go
type ChatInstance (line 9) | type ChatInstance struct
method GetEndpoint (line 14) | func (c *ChatInstance) GetEndpoint() string {
method GetApiKey (line 18) | func (c *ChatInstance) GetApiKey() string {
method GetHeader (line 22) | func (c *ChatInstance) GetHeader() map[string]string {
function NewChatInstance (line 29) | func NewChatInstance(endpoint, apiKey string) *ChatInstance {
function NewChatInstanceFromConfig (line 36) | func NewChatInstanceFromConfig(conf globals.ChannelConfig) factory.Facto...
FILE: adapter/zhinao/types.go
type ChatRequest (line 8) | type ChatRequest struct
type ChatResponse (line 20) | type ChatResponse struct
type ChatStreamResponse (line 36) | type ChatStreamResponse struct
type ChatStreamErrorResponse (line 51) | type ChatStreamErrorResponse struct
FILE: adapter/zhipuai/chat.go
method GetChatEndpoint (line 12) | func (c *ChatInstance) GetChatEndpoint() string {
method GetCompletionPrompt (line 16) | func (c *ChatInstance) GetCompletionPrompt(messages []globals.Message) s...
method GetLatestPrompt (line 24) | func (c *ChatInstance) GetLatestPrompt(props *adaptercommon.ChatProps) s...
method ConvertModel (line 32) | func (c *ChatInstance) ConvertModel(model string) string {
method GetChatBody (line 48) | func (c *ChatInstance) GetChatBody(props *adaptercommon.ChatProps, strea...
method CreateChatRequest (line 83) | func (c *ChatInstance) CreateChatRequest(props *adaptercommon.ChatProps)...
function hideRequestId (line 104) | func hideRequestId(message string) string {
method CreateStreamChatRequest (line 112) | func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.Chat...
FILE: adapter/zhipuai/processor.go
function formatMessages (line 13) | func formatMessages(props *adaptercommon.ChatProps) interface{} {
function processChatResponse (line 67) | func processChatResponse(data string) *ChatStreamResponse {
function processCompletionResponse (line 71) | func processCompletionResponse(data string) *CompletionResponse {
function processChatErrorResponse (line 75) | func processChatErrorResponse(data string) *ChatStreamErrorResponse {
function getChoices (line 79) | func getChoices(form *ChatStreamResponse) *globals.Chunk {
function getCompletionChoices (line 93) | func getCompletionChoices(form *CompletionResponse) string {
function getRobustnessResult (line 101) | func getRobustnessResult(chunk string) string {
method ProcessLine (line 116) | func (c *ChatInstance) ProcessLine(data string, isCompletionType bool) (...
FILE: adapter/zhipuai/struct.go
type ChatInstance (line 14) | type ChatInstance struct
method GetEndpoint (line 25) | func (c *ChatInstance) GetEndpoint() string {
method GetApiKey (line 29) | func (c *ChatInstance) GetApiKey() string {
method GetHeader (line 33) | func (c *ChatInstance) GetHeader() map[string]string {
method GetToken (line 40) | func (c *ChatInstance) GetToken() string {
type Payload (line 19) | type Payload struct
function NewChatInstance (line 63) | func NewChatInstance(endpoint, apiKey string) *ChatInstance {
function NewChatInstanceFromConfig (line 70) | func NewChatInstanceFromConfig(conf globals.ChannelConfig) factory.Facto...
FILE: adapter/zhipuai/types.go
constant GLM4 (line 6) | GLM4 = "glm-4"
constant GLM4Vision (line 7) | GLM4Vision = "glm-4v"
constant GLMTurbo (line 8) | GLMTurbo = "glm-3-turbo"
constant GLMPro (line 9) | GLMPro = "chatglm_pro"
constant GLMStd (line 10) | GLMStd = "chatglm_std"
constant GLMLite (line 11) | GLMLite = "chatglm_lite"
type ImageUrl (line 14) | type ImageUrl struct
type MessageContent (line 19) | type MessageContent struct
type MessageContents (line 25) | type MessageContents
type Message (line 27) | type Message struct
type ChatRequest (line 37) | type ChatRequest struct
type CompletionRequest (line 51) | type CompletionRequest struct
type ChatResponse (line 59) | type ChatResponse struct
type ChatStreamResponse (line 75) | type ChatStreamResponse struct
type CompletionResponse (line 88) | type CompletionResponse struct
type ChatStreamErrorResponse (line 99) | type ChatStreamErrorResponse struct
type ImageSize (line 107) | type ImageSize
type ImageRequest (line 110) | type ImageRequest struct
type ImageResponse (line 117) | type ImageResponse struct
FILE: addition/article/api.go
type WebsocketArticleForm (line 12) | type WebsocketArticleForm struct
type WebsocketArticleResponse (line 20) | type WebsocketArticleResponse struct
function ProjectTarDownloadAPI (line 25) | func ProjectTarDownloadAPI(c *gin.Context) {
function ProjectZipDownloadAPI (line 31) | func ProjectZipDownloadAPI(c *gin.Context) {
function GenerateAPI (line 37) | func GenerateAPI(c *gin.Context) {
FILE: addition/article/generate.go
type StreamProgressResponse (line 13) | type StreamProgressResponse struct
type Response (line 19) | type Response struct
function GenerateArticle (line 24) | func GenerateArticle(c *gin.Context, user *auth.User, model string, hash...
function ParseTitle (line 36) | func ParseTitle(titles string) []string {
function CreateGenerationWorker (line 47) | func CreateGenerationWorker(c *gin.Context, user *auth.User, model strin...
function CreateWorker (line 60) | func CreateWorker(c *gin.Context, user *auth.User, model string, prompt ...
FILE: addition/article/utils.go
function GenerateDocxFile (line 10) | func GenerateDocxFile(target, title, content string) error {
function CreateArticleFile (line 32) | func CreateArticleFile(hash, title, content string) string {
FILE: addition/card/card.go
type RequestForm (line 12) | type RequestForm struct
constant maxColumnPerLine (line 17) | maxColumnPerLine = 50
function ProcessMarkdownLine (line 19) | func ProcessMarkdownLine(source []byte) string {
function MarkdownConvert (line 43) | func MarkdownConvert(text string) string {
function HandlerAPI (line 52) | func HandlerAPI(c *gin.Context) {
FILE: addition/card/utils.php
function compress (line 5) | function compress($buffer): array|string|null
function fetch (line 12) | function fetch($message, $web): array|string|null
function get (line 28) | function get($param, $default = null)
FILE: addition/generation/api.go
type WebsocketGenerationForm (line 13) | type WebsocketGenerationForm struct
function ProjectTarDownloadAPI (line 19) | func ProjectTarDownloadAPI(c *gin.Context) {
function ProjectZipDownloadAPI (line 25) | func ProjectZipDownloadAPI(c *gin.Context) {
function GenerateAPI (line 31) | func GenerateAPI(c *gin.Context) {
FILE: addition/generation/build.go
function GetFolder (line 9) | func GetFolder(hash string) string {
function GetFolderByHash (line 13) | func GetFolderByHash(model string, prompt string) (string, string) {
function GenerateProject (line 18) | func GenerateProject(path string, instance ProjectResult) bool {
FILE: addition/generation/generate.go
function CreateGenerationWithCache (line 9) | func CreateGenerationWithCache(group, model, prompt string, hook func(bu...
FILE: addition/generation/prompt.go
type ProjectResult (line 12) | type ProjectResult struct
function CreateGeneration (line 16) | func CreateGeneration(group, model, prompt, path string, hook func(buffe...
function GenerateMessage (line 45) | func GenerateMessage(prompt string) []globals.Message {
FILE: addition/router.go
function Register (line 10) | func Register(app *gin.RouterGroup) {
FILE: addition/web/call.go
type Hook (line 11) | type Hook
function toWebSearchingMessage (line 13) | func toWebSearchingMessage(message []globals.Message) []globals.Message {
function ToChatSearched (line 25) | func ToChatSearched(instance *conversation.Conversation, restart bool) [...
function ToSearched (line 35) | func ToSearched(enable bool, message []globals.Message) []globals.Message {
FILE: addition/web/search.go
type SearXNGResponse (line 16) | type SearXNGResponse struct
function formatResponse (line 41) | func formatResponse(data *SearXNGResponse) string {
function createURLParams (line 54) | func createURLParams(query string) string {
function createSearXNGRequest (line 70) | func createSearXNGRequest(query string) (*SearXNGResponse, error) {
function GenerateSearchResult (line 80) | func GenerateSearchResult(q string) (string, error) {
function TestSearch (line 99) | func TestSearch(c *gin.Context) {
FILE: admin/analysis/analysis.go
type UserTypeForm (line 13) | type UserTypeForm struct
function getDates (line 22) | func getDates(t []time.Time) []string {
function getFormat (line 28) | func getFormat(t time.Time) string {
function getMinuteFormat (line 32) | func getMinuteFormat(t time.Time) string {
function GetSubscriptionUsers (line 36) | func GetSubscriptionUsers(db *sql.DB) int64 {
function GetBillingToday (line 48) | func GetBillingToday(cache *redis.Client) float32 {
function GetBillingYesterday (line 52) | func GetBillingYesterday(cache *redis.Client) float32 {
function GetBillingMonth (line 56) | func GetBillingMonth(cache *redis.Client) float32 {
function GetBillingLastMonth (line 60) | func GetBillingLastMonth(cache *redis.Client) float32 {
function GetTpmToday (line 64) | func GetTpmToday(cache *redis.Client, user string) int64 {
function GetRpmToday (line 70) | func GetRpmToday(cache *redis.Client, user string) int64 {
function GetModelData (line 76) | func GetModelData(cache *redis.Client) ModelChartForm {
function GetSortedModelData (line 97) | func GetSortedModelData(cache *redis.Client) ModelChartForm {
function GetRequestData (line 108) | func GetRequestData(cache *redis.Client) RequestChartForm {
function GetBillingData (line 119) | func GetBillingData(cache *redis.Client) BillingChartForm {
function GetErrorData (line 130) | func GetErrorData(cache *redis.Client) ErrorChartForm {
function GetUserTypeData (line 141) | func GetUserTypeData(db *sql.DB) (UserTypeForm, error) {
FILE: admin/analysis/format.go
function getMonth (line 8) | func getMonth() string {
function getLastMonth (line 13) | func getLastMonth() string {
function getDay (line 18) | func getDay() string {
function getLastDay (line 23) | func getLastDay() string {
function getDays (line 28) | func getDays(n int) []time.Time {
function getErrorFormat (line 38) | func getErrorFormat(t string) string {
function getBillingFormat (line 42) | func getBillingFormat(t string) string {
function getMonthBillingFormat (line 46) | func getMonthBillingFormat(t string) string {
function getRequestFormat (line 50) | func getRequestFormat(t string) string {
function getModelFormat (line 54) | func getModelFormat(t string, model string) string {
function getTpmFormat (line 58) | func getTpmFormat(t string, user string) string {
function getRpmFormat (line 62) | func getRpmFormat(t string, user string) string {
FILE: admin/analysis/statistic.go
function IncrErrorRequest (line 12) | func IncrErrorRequest(cache *redis.Client) {
function IncrBillingRequest (line 16) | func IncrBillingRequest(cache *redis.Client, amount int64, isAdmin bool) {
function IncrRequest (line 26) | func IncrRequest(cache *redis.Client) {
function IncrModelRequest (line 30) | func IncrModelRequest(cache *redis.Client, model string, tokens int64) {
function AnalyseRequest (line 34) | func AnalyseRequest(model string, user string, buffer *utils.Buffer, err...
function IncrTpm (line 57) | func IncrTpm(cache *redis.Client, user string, n int64) {
function IncrRpm (line 61) | func IncrRpm(cache *redis.Client, user string, n int64) {
FILE: admin/analysis/types.go
type ModelData (line 3) | type ModelData struct
type ModelChartForm (line 8) | type ModelChartForm struct
type RequestChartForm (line 13) | type RequestChartForm struct
type BillingChartForm (line 18) | type BillingChartForm struct
type ErrorChartForm (line 23) | type ErrorChartForm struct
FILE: admin/controller.go
type GenerateInvitationForm (line 14) | type GenerateInvitationForm struct
type DeleteInvitationForm (line 20) | type DeleteInvitationForm struct
type GenerateRedeemForm (line 24) | type GenerateRedeemForm struct
type PasswordMigrationForm (line 29) | type PasswordMigrationForm struct
type EmailMigrationForm (line 34) | type EmailMigrationForm struct
type SetAdminForm (line 39) | type SetAdminForm struct
type BanForm (line 44) | type BanForm struct
type QuotaOperationForm (line 49) | type QuotaOperationForm struct
type SubscriptionOperationForm (line 55) | type SubscriptionOperationForm struct
type SubscriptionLevelForm (line 60) | type SubscriptionLevelForm struct
type ReleaseUsageForm (line 65) | type ReleaseUsageForm struct
type UpdateRootPasswordForm (line 69) | type UpdateRootPasswordForm struct
function UpdateMarketAPI (line 73) | func UpdateMarketAPI(c *gin.Context) {
function InfoAPI (line 97) | func InfoAPI(c *gin.Context) {
function ModelAnalysisAPI (line 111) | func ModelAnalysisAPI(c *gin.Context) {
function RequestAnalysisAPI (line 116) | func RequestAnalysisAPI(c *gin.Context) {
function BillingAnalysisAPI (line 121) | func BillingAnalysisAPI(c *gin.Context) {
function ErrorAnalysisAPI (line 126) | func ErrorAnalysisAPI(c *gin.Context) {
function UserTypeAnalysisAPI (line 131) | func UserTypeAnalysisAPI(c *gin.Context) {
function RedeemListAPI (line 140) | func RedeemListAPI(c *gin.Context) {
function DeleteRedeemAPI (line 147) | func DeleteRedeemAPI(c *gin.Context) {
function InvitationPaginationAPI (line 166) | func InvitationPaginationAPI(c *gin.Context) {
function DeleteInvitationAPI (line 173) | func DeleteInvitationAPI(c *gin.Context) {
function GenerateInvitationAPI (line 191) | func GenerateInvitationAPI(c *gin.Context) {
function GenerateRedeemAPI (line 206) | func GenerateRedeemAPI(c *gin.Context) {
function UserPaginationAPI (line 221) | func UserPaginationAPI(c *gin.Context) {
function UpdatePasswordAPI (line 229) | func UpdatePasswordAPI(c *gin.Context) {
function UpdateEmailAPI (line 256) | func UpdateEmailAPI(c *gin.Context) {
function SetAdminAPI (line 282) | func SetAdminAPI(c *gin.Context) {
function BanAPI (line 308) | func BanAPI(c *gin.Context) {
function UserQuotaAPI (line 334) | func UserQuotaAPI(c *gin.Context) {
function UserSubscriptionAPI (line 360) | func UserSubscriptionAPI(c *gin.Context) {
function SubscriptionLevelAPI (line 394) | func SubscriptionLevelAPI(c *gin.Context) {
function ReleaseUsageAPI (line 420) | func ReleaseUsageAPI(c *gin.Context) {
function UpdateRootPasswordAPI (line 447) | func UpdateRootPasswordAPI(c *gin.Context) {
function ListLoggerAPI (line 473) | func ListLoggerAPI(c *gin.Context) {
function DownloadLoggerAPI (line 477) | func DownloadLoggerAPI(c *gin.Context) {
function DeleteLoggerAPI (line 482) | func DeleteLoggerAPI(c *gin.Context) {
function ConsoleLoggerAPI (line 497) | func ConsoleLoggerAPI(c *gin.Context) {
FILE: admin/format.go
function getMonth (line 8) | func getMonth() string {
function getDay (line 13) | func getDay() string {
function getDays (line 18) | func getDays(n int) []time.Time {
function getErrorFormat (line 28) | func getErrorFormat(t string) string {
function getBillingFormat (line 32) | func getBillingFormat(t string) string {
function getMonthBillingFormat (line 36) | func getMonthBillingFormat(t string) string {
function getRequestFormat (line 40) | func getRequestFormat(t string) string {
function getModelFormat (line 44) | func getModelFormat(t string, model string) string {
FILE: admin/instance.go
function InitInstance (line 5) | func InitInstance() {
FILE: admin/invitation.go
function GetInvitationPagination (line 13) | func GetInvitationPagination(db *sql.DB, page int64) PaginationForm {
function DeleteInvitationCode (line 63) | func DeleteInvitationCode(db *sql.DB, code string) error {
function NewInvitationCode (line 70) | func NewInvitationCode(db *sql.DB, code string, quota float32, t string)...
function GenerateInvitations (line 78) | func GenerateInvitations(db *sql.DB, num int, quota float32, t string) I...
FILE: admin/logger.go
type LogFile (line 11) | type LogFile struct
function ListLogs (line 16) | func ListLogs() []LogFile {
function getLogPath (line 25) | func getLogPath(path string) string {
function getBlobFile (line 29) | func getBlobFile(c *gin.Context, path string) {
function deleteLogFile (line 33) | func deleteLogFile(path string) error {
function getLatestLogs (line 37) | func getLatestLogs(n int) string {
FILE: admin/market.go
type ModelTag (line 11) | type ModelTag
type MarketModel (line 12) | type MarketModel struct
type MarketModelList (line 21) | type MarketModelList
type Market (line 23) | type Market struct
method GetModels (line 39) | func (m *Market) GetModels() MarketModelList {
method GetModel (line 43) | func (m *Market) GetModel(id string) *MarketModel {
method SaveConfig (line 52) | func (m *Market) SaveConfig() error {
method SetModels (line 56) | func (m *Market) SetModels(models MarketModelList) error {
function NewMarket (line 27) | func NewMarket() *Market {
FILE: admin/redeem.go
function GetRedeemData (line 12) | func GetRedeemData(db *sql.DB, page int64) PaginationForm {
function DeleteRedeemCode (line 60) | func DeleteRedeemCode(db *sql.DB, code string) error {
function GenerateRedeemCodes (line 68) | func GenerateRedeemCodes(db *sql.DB, num int, quota float32) RedeemGener...
function CreateRedeemCode (line 90) | func CreateRedeemCode(db *sql.DB, quota float32) (string, error) {
FILE: admin/router.go
function Register (line 10) | func Register(app *gin.RouterGroup) {
FILE: admin/statistic.go
function IncrErrorRequest (line 12) | func IncrErrorRequest(cache *redis.Client) {
function IncrBillingRequest (line 16) | func IncrBillingRequest(cache *redis.Client, amount int64) {
function IncrRequest (line 21) | func IncrRequest(cache *redis.Client) {
function IncrModelRequest (line 25) | func IncrModelRequest(cache *redis.Client, model string, tokens int64) {
function AnalyseRequest (line 29) | func AnalyseRequest(model string, buffer *utils.Buffer, err error) {
FILE: admin/types.go
type InfoForm (line 5) | type InfoForm struct
type ModelData (line 14) | type ModelData struct
type ModelChartForm (line 19) | type ModelChartForm struct
type RequestChartForm (line 24) | type RequestChartForm struct
type BillingChartForm (line 29) | type BillingChartForm struct
type ErrorChartForm (line 34) | type ErrorChartForm struct
type PaginationForm (line 39) | type PaginationForm struct
type InvitationData (line 46) | type InvitationData struct
type RedeemData (line 56) | type RedeemData struct
type InvitationGenerateResponse (line 64) | type InvitationGenerateResponse struct
type RedeemGenerateResponse (line 70) | type RedeemGenerateResponse struct
type UserData (line 76) | type UserData struct
FILE: admin/user.go
type AuthLike (line 18) | type AuthLike struct
method GetID (line 22) | func (a *AuthLike) GetID(_ *sql.DB) int64 {
method HitID (line 26) | func (a *AuthLike) HitID() int64 {
function getUsersForm (line 30) | func getUsersForm(db *sql.DB, page int64, search string) PaginationForm {
function clearUserCache (line 117) | func clearUserCache(cache *redis.Client) error {
function passwordMigration (line 128) | func passwordMigration(db *sql.DB, cache *redis.Client, id int64, passwo...
function emailMigration (line 152) | func emailMigration(db *sql.DB, id int64, email string) error {
function setAdmin (line 160) | func setAdmin(db *sql.DB, id int64, isAdmin bool) error {
function banUser (line 168) | func banUser(db *sql.DB, id int64, isBanned bool) error {
function quotaMigration (line 176) | func quotaMigration(db *sql.DB, id int64, quota float32, override bool) ...
function subscriptionMigration (line 197) | func subscriptionMigration(db *sql.DB, id int64, expired string) error {
function subscriptionLevelMigration (line 205) | func subscriptionLevelMigration(db *sql.DB, id int64, level int64) error {
function releaseUsage (line 218) | func releaseUsage(db *sql.DB, cache *redis.Client, id int64) error {
function UpdateRootPassword (line 240) | func UpdateRootPassword(db *sql.DB, cache *redis.Client, password string...
FILE: app/public/service.js
constant SERVICE_NAME (line 2) | const SERVICE_NAME = "coai";
FILE: app/src-tauri/build.rs
function main (line 1) | fn main() {
FILE: app/src-tauri/src/main.rs
function main (line 4) | fn main() {
FILE: app/src/App.tsx
function App (line 9) | function App() {
FILE: app/src/admin/api/channel.ts
type ChannelListResponse (line 6) | type ChannelListResponse = CommonResponse & {
type GetChannelResponse (line 10) | type GetChannelResponse = CommonResponse & {
function listChannel (line 14) | async function listChannel(): Promise<ChannelListResponse> {
function getChannel (line 23) | async function getChannel(id: number): Promise<GetChannelResponse> {
function createChannel (line 32) | async function createChannel(channel: Channel): Promise<CommonResponse> {
function updateChannel (line 41) | async function updateChannel(
function deleteChannel (line 53) | async function deleteChannel(id: number): Promise<CommonResponse> {
function activateChannel (line 62) | async function activateChannel(id: number): Promise<CommonResponse> {
function deactivateChannel (line 71) | async function deactivateChannel(id: number): Promise<CommonResponse> {
FILE: app/src/admin/api/charge.ts
type ChargeListResponse (line 6) | type ChargeListResponse = CommonResponse & {
type ChargeSyncRequest (line 10) | type ChargeSyncRequest = {
type ChargeFetchRequest (line 15) | type ChargeFetchRequest = {
type ChargeFetchResponse (line 20) | type ChargeFetchResponse = CommonResponse & {
function listCharge (line 24) | async function listCharge(): Promise<ChargeListResponse> {
function setCharge (line 33) | async function setCharge(charge: ChargeProps): Promise<CommonResponse> {
function deleteCharge (line 42) | async function deleteCharge(id: number): Promise<CommonResponse> {
function syncCharge (line 51) | async function syncCharge(
function fetchUpstreamCharge (line 62) | async function fetchUpstreamCharge(
FILE: app/src/admin/api/chart.ts
type UserFilterProps (line 26) | type UserFilterProps = {
function getAdminInfo (line 44) | async function getAdminInfo(): Promise<InfoResponse> {
function getModelChart (line 56) | async function getModelChart(): Promise<ModelChartResponse> {
function getRequestChart (line 71) | async function getRequestChart(): Promise<RequestChartResponse> {
function getBillingChart (line 81) | async function getBillingChart(): Promise<BillingChartResponse> {
function getErrorChart (line 91) | async function getErrorChart(): Promise<ErrorChartResponse> {
function getUserTypeChart (line 101) | async function getUserTypeChart(): Promise<UserTypeChartResponse> {
function getInvitationList (line 118) | async function getInvitationList(
function deleteInvitation (line 134) | async function deleteInvitation(code: string): Promise<CommonResponse> {
function generateInvitation (line 143) | async function generateInvitation(
function getRedeemList (line 160) | async function getRedeemList(page: number): Promise<RedeemResponse> {
function deleteRedeem (line 170) | async function deleteRedeem(code: string): Promise<CommonResponse> {
function generateRedeem (line 179) | async function generateRedeem(
function getUserList (line 194) | async function getUserList(
function updatePassword (line 218) | async function updatePassword(
function updateEmail (line 233) | async function updateEmail(
function quotaOperation (line 248) | async function quotaOperation(
function subscriptionOperation (line 265) | async function subscriptionOperation(
function banUserOperation (line 280) | async function banUserOperation(
function setAdminOperation (line 295) | async function setAdminOperation(
function subscriptionLevelOperation (line 310) | async function subscriptionLevelOperation(
function releaseUsageOperation (line 322) | async function releaseUsageOperation(
FILE: app/src/admin/api/info.ts
type SiteInfo (line 13) | type SiteInfo = {
function getSiteInfo (line 36) | async function getSiteInfo(): Promise<SiteInfo> {
function syncSiteInfo (line 70) | function syncSiteInfo() {
FILE: app/src/admin/api/logger.ts
type Logger (line 5) | type Logger = {
function listLoggers (line 10) | async function listLoggers(): Promise<Logger[]> {
function getLoggerConsole (line 20) | async function getLoggerConsole(n?: number): Promise<string> {
function downloadLogger (line 30) | async function downloadLogger(path: string): Promise<void> {
function deleteLogger (line 47) | async function deleteLogger(path: string): Promise<CommonResponse> {
FILE: app/src/admin/api/market.ts
function updateMarket (line 6) | async function updateMarket(data: Model[]): Promise<CommonResponse> {
FILE: app/src/admin/api/plan.ts
type PlanConfig (line 7) | type PlanConfig = {
function getPlanConfig (line 12) | async function getPlanConfig(): Promise<PlanConfig> {
function getExternalPlanConfig (line 28) | async function getExternalPlanConfig(
function setPlanConfig (line 35) | async function setPlanConfig(
FILE: app/src/admin/api/system.ts
type TestWebSearchResponse (line 6) | type TestWebSearchResponse = CommonResponse & {
type whiteList (line 10) | type whiteList = {
type GeneralState (line 16) | type GeneralState = {
type MailState (line 35) | type MailState = {
type SearchState (line 45) | type SearchState = {
type SecurityState (line 56) | type SecurityState = {
type PaymentState (line 73) | type PaymentState = {
type SiteState (line 113) | type SiteState = {
type CustomState (line 128) | type CustomState = {
type AutoTitleState (line 135) | type AutoTitleState = {
type CommonState (line 144) | type CommonState = {
type SystemProps (line 156) | type SystemProps = {
type SystemResponse (line 168) | type SystemResponse = CommonResponse & {
function getConfig (line 287) | async function getConfig(): Promise<SystemResponse> {
function setConfig (line 370) | async function setConfig(config: SystemProps): Promise<CommonResponse> {
type UploadResponse (line 379) | type UploadResponse = CommonResponse & {
function uploadFavicon (line 383) | async function uploadFavicon(file: File): Promise<UploadResponse> {
function uploadResource (line 399) | async function uploadResource(file: File): Promise<UploadResponse> {
function updateRootPassword (line 421) | async function updateRootPassword(
function testWebSearching (line 432) | async function testWebSearching(
type AuditTypes (line 445) | enum AuditTypes {
FILE: app/src/admin/channel.ts
type Channel (line 10) | type Channel = {
type proxyType (line 33) | enum proxyType {
type ChannelInfo (line 47) | type ChannelInfo = {
function getChannelInfo (line 331) | function getChannelInfo(type?: string): ChannelInfo {
function getChannelType (line 336) | function getChannelType(type?: string): string {
function getShortChannelType (line 341) | function getShortChannelType(type?: string): string {
FILE: app/src/admin/charge.ts
type ChargeType (line 7) | type ChargeType = (typeof chargeTypes)[number];
type ChargeBaseProps (line 9) | type ChargeBaseProps = {
type ChargeProps (line 16) | type ChargeProps = ChargeBaseProps & {
FILE: app/src/admin/colors.ts
function getUnknownModelColor (line 106) | function getUnknownModelColor(model: string): string {
function getModelColor (line 113) | function getModelColor(model: string): string {
FILE: app/src/admin/datasets/charge.ts
type Currency (line 8) | enum Currency {
type PricingItem (line 13) | type PricingItem = {
type PricingDataset (line 21) | type PricingDataset = PricingItem[];
FILE: app/src/admin/hook.tsx
type onStateChange (line 8) | type onStateChange<T> = (state: boolean, data?: T) => void;
FILE: app/src/admin/types.ts
type CommonResponse (line 1) | type CommonResponse = {
type InfoResponse (line 7) | type InfoResponse = {
type ModelChartResponse (line 16) | type ModelChartResponse = {
type RequestChartResponse (line 24) | type RequestChartResponse = {
type BillingChartResponse (line 29) | type BillingChartResponse = {
type ErrorChartResponse (line 34) | type ErrorChartResponse = {
type UserTypeChartResponse (line 39) | type UserTypeChartResponse = {
type InvitationData (line 48) | type InvitationData = {
type InvitationForm (line 58) | type InvitationForm = {
type InvitationResponse (line 63) | type InvitationResponse = {
type Redeem (line 70) | type Redeem = {
type RedeemForm (line 78) | type RedeemForm = {
type RedeemResponse (line 83) | type RedeemResponse = CommonResponse & {
type InvitationGenerateResponse (line 88) | type InvitationGenerateResponse = {
type RedeemGenerateResponse (line 94) | type RedeemGenerateResponse = {
type UserData (line 100) | type UserData = {
type UserForm (line 115) | type UserForm = {
type UserResponse (line 120) | type UserResponse = {
FILE: app/src/api/addition.ts
type QuotaResponse (line 4) | type QuotaResponse = {
type PackageResponse (line 9) | type PackageResponse = {
type SubscriptionResponse (line 15) | type SubscriptionResponse = {
type BuySubscriptionResponse (line 27) | type BuySubscriptionResponse = {
type ApiKeyResponse (line 32) | type ApiKeyResponse = {
type ResetApiKeyResponse (line 37) | type ResetApiKeyResponse = {
function buyQuota (line 43) | async function buyQuota(quota: number): Promise<QuotaResponse> {
function getPackage (line 53) | async function getPackage(): Promise<PackageResponse> {
function getSubscription (line 70) | async function getSubscription(): Promise<SubscriptionResponse> {
function buySubscription (line 95) | async function buySubscription(
function getKey (line 108) | async function getKey(): Promise<ApiKeyResponse> {
function regenerateKey (line 124) | async function regenerateKey(): Promise<ResetApiKeyResponse> {
FILE: app/src/api/auth.ts
type LoginForm (line 6) | type LoginForm = {
type DeepLoginForm (line 11) | type DeepLoginForm = {
type LoginResponse (line 15) | type LoginResponse = {
type StateResponse (line 21) | type StateResponse = {
type RegisterForm (line 27) | type RegisterForm = {
type RegisterResponse (line 35) | type RegisterResponse = {
type VerifyForm (line 41) | type VerifyForm = {
type VerifyResponse (line 45) | type VerifyResponse = {
type ResetForm (line 50) | type ResetForm = {
type ResetResponse (line 57) | type ResetResponse = {
type UserInfo (line 62) | type UserInfo = {
type UserInfoResponse (line 70) | type UserInfoResponse = {
function doLogin (line 76) | async function doLogin(
function doState (line 83) | async function doState(): Promise<StateResponse> {
function doRegister (line 88) | async function doRegister(
function doVerify (line 103) | async function doVerify(
function doReset (line 121) | async function doReset(data: ResetForm): Promise<ResetResponse> {
function sendCode (line 133) | async function sendCode(
function getUserInfo (line 161) | async function getUserInfo(): Promise<UserInfoResponse> {
FILE: app/src/api/broadcast.ts
type Broadcast (line 4) | type Broadcast = {
type BroadcastInfo (line 9) | type BroadcastInfo = Broadcast & {
type BroadcastListResponse (line 14) | type BroadcastListResponse = {
type CommonBroadcastResponse (line 18) | type CommonBroadcastResponse = {
function getRawBroadcast (line 23) | async function getRawBroadcast(): Promise<Broadcast> {
type BroadcastEvent (line 37) | type BroadcastEvent = {
function getBroadcast (line 42) | async function getBroadcast(): Promise<BroadcastEvent> {
function getBroadcastList (line 66) | async function getBroadcastList(): Promise<BroadcastInfo[]> {
function createBroadcast (line 77) | async function createBroadcast(
function removeBroadcast (line 96) | async function removeBroadcast(
function updateBroadcast (line 111) | async function updateBroadcast(
FILE: app/src/api/common.ts
type CommonResponse (line 3) | type CommonResponse = {
function withNotify (line 11) | function withNotify(
FILE: app/src/api/connection.ts
type StreamMessage (line 10) | type StreamMessage = {
type ChatProps (line 50) | type ChatProps = {
type StreamCallback (line 74) | type StreamCallback = (id: number, message: StreamMessage) => void;
class Connection (line 76) | class Connection {
method constructor (line 83) | public constructor(id: number, callback?: StreamCallback) {
method init (line 90) | public init(): void {
method reconnect (line 121) | public reconnect(): void {
method send (line 125) | public send(data: Record<string, string | boolean | number>): boolean {
method sendWithRetry (line 135) | public sendWithRetry(t: any, data: ChatProps, times?: number): void {
method sendEvent (line 169) | public sendEvent(t: any, event: string, data?: string, props?: ChatPro...
method sendStopEvent (line 178) | public sendStopEvent(t: any) {
method sendRestartEvent (line 182) | public sendRestartEvent(t: any, data?: ChatProps) {
method sendMaskEvent (line 186) | public sendMaskEvent(t: any, mask: Mask) {
method sendEditEvent (line 190) | public sendEditEvent(t: any, id: number, message: string) {
method sendRemoveEvent (line 194) | public sendRemoveEvent(t: any, id: number) {
method sendShareEvent (line 198) | public sendShareEvent(t: any, refer: string) {
method close (line 202) | public close(): void {
method setCallback (line 207) | public setCallback(callback?: StreamCallback): void {
method triggerCallback (line 211) | protected triggerCallback(message: StreamMessage): void {
method setId (line 215) | public setId(id: number): void {
method isReady (line 219) | public isReady(): boolean {
method isRunning (line 223) | public isRunning(): boolean {
class ConnectionStack (line 230) | class ConnectionStack {
method constructor (line 234) | public constructor(callback?: StreamCallback) {
method getConnection (line 239) | public getConnection(id: number): Connection | undefined {
method createConnection (line 243) | public createConnection(id: number): Connection {
method send (line 255) | public send(id: number, t: any, props: ChatProps) {
method hasConnection (line 263) | public hasConnection(id: number): boolean {
method setCallback (line 267) | public setCallback(callback?: StreamCallback): void {
method sendEvent (line 271) | public sendEvent(id: number, t: any, event: string, data?: string) {
method sendStopEvent (line 276) | public sendStopEvent(id: number, t: any) {
method sendRestartEvent (line 281) | public sendRestartEvent(id: number, t: any, data?: ChatProps) {
method sendMaskEvent (line 286) | public sendMaskEvent(id: number, t: any, mask: Mask) {
method sendEditEvent (line 291) | public sendEditEvent(id: number, t: any, messageId: number, message: s...
method sendRemoveEvent (line 296) | public sendRemoveEvent(id: number, t: any, messageId: number) {
method sendShareEvent (line 301) | public sendShareEvent(id: number, t: any, refer: string) {
method close (line 306) | public close(id: number): void {
method closeAll (line 311) | public closeAll(): void {
method reconnect (line 315) | public reconnect(id: number): void {
method reconnectAll (line 320) | public reconnectAll(): void {
method raiseConnection (line 324) | public raiseConnection(id: number): void {
method triggerCallback (line 331) | public triggerCallback(id: number, message: StreamMessage): void {
FILE: app/src/api/file.ts
type BlobParserResponse (line 4) | type BlobParserResponse = {
type FileObject (line 10) | type FileObject = {
type Model (line 16) | type Model = {
type FileArray (line 23) | type FileArray = FileObject[];
function fileToBase64 (line 25) | async function fileToBase64(file: File): Promise<string> {
function checkFileSuffix (line 34) | function checkFileSuffix(
function quickBlobParser (line 47) | async function quickBlobParser(
function blobParser (line 103) | async function blobParser(
FILE: app/src/api/generation.ts
type GenerationForm (line 6) | type GenerationForm = {
type GenerationSegmentResponse (line 12) | type GenerationSegmentResponse = {
type MessageEvent (line 21) | type MessageEvent = {
class GenerationManager (line 26) | class GenerationManager {
method constructor (line 35) | constructor() {
method setProcessingChangeHandler (line 41) | public setProcessingChangeHandler(
method setMessageHandler (line 47) | public setMessageHandler(handler: (message: MessageEvent) => void): vo...
method setErrorHandler (line 51) | public setErrorHandler(handler: (error: string) => void): void {
method setFinishedHandler (line 55) | public setFinishedHandler(handler: (hash: string) => void): void {
method isProcessing (line 59) | public isProcessing(): boolean {
method setProcessing (line 63) | protected setProcessing(processing: boolean): boolean {
method getConnection (line 73) | public getConnection(): WebSocket | null {
method handleMessage (line 77) | protected handleMessage(message: GenerationSegmentResponse): void {
method generate (line 96) | public generate(prompt: string, model: string) {
method generateWithBlock (line 115) | public generateWithBlock(prompt: string, model: string): boolean {
FILE: app/src/api/history.ts
function getConversationList (line 10) | async function getConversationList(): Promise<ConversationInstance[]> {
function updateConversationList (line 22) | async function updateConversationList(
function loadConversation (line 29) | async function loadConversation(
function deleteConversation (line 114) | async function deleteConversation(id: number): Promise<boolean> {
function renameConversation (line 124) | async function renameConversation(
function deleteAllConversations (line 137) | async function deleteAllConversations(): Promise<boolean> {
FILE: app/src/api/mask.ts
type ListMaskResponse (line 6) | type ListMaskResponse = CommonResponse & {
function listMasks (line 10) | async function listMasks(): Promise<ListMaskResponse> {
function saveMask (line 28) | async function saveMask(mask: CustomMask): Promise<CommonResponse> {
function deleteMask (line 40) | async function deleteMask(id: number): Promise<CommonResponse> {
FILE: app/src/api/plugin.ts
type ListPluginResponse (line 5) | type ListPluginResponse = CommonResponse & {
type TestPluginResponse (line 9) | type TestPluginResponse = CommonResponse & {
function listPlugins (line 19) | async function listPlugins(): Promise<ListPluginResponse> {
function savePlugin (line 37) | async function savePlugin(plugin: Partial<Plugin>): Promise<CommonRespon...
function deletePlugin (line 49) | async function deletePlugin(id: number): Promise<CommonResponse> {
function testPlugin (line 61) | async function testPlugin(serverUrl: string): Promise<TestPluginResponse> {
function formatToolCallResult (line 75) | function formatToolCallResult(result: string): string {
function parseMCPInput (line 105) | function parseMCPInput(input: string): {
FILE: app/src/api/quota.ts
function getQuota (line 3) | async function getQuota(): Promise<number> {
FILE: app/src/api/record.ts
type Record (line 4) | type Record = {
type RecordData (line 20) | type RecordData = {
type RecordStats (line 25) | type RecordStats = {
type RecordQuery (line 34) | type RecordQuery = {
type ListRecordsResponse (line 44) | type ListRecordsResponse = CommonResponse & {
type RecordStatsResponse (line 48) | type RecordStatsResponse = CommonResponse & {
type RecordType (line 52) | enum RecordType {
function listRecords (line 66) | async function listRecords(
function getRecordStats (line 85) | async function getRecordStats(): Promise<RecordStatsResponse> {
FILE: app/src/api/redeem.ts
type RedeemResponse (line 4) | type RedeemResponse = {
function useRedeem (line 10) | async function useRedeem(code: string): Promise<RedeemResponse> {
FILE: app/src/api/sharing.ts
type SharingForm (line 4) | type SharingForm = {
type SharingPreviewForm (line 10) | type SharingPreviewForm = {
type ViewData (line 17) | type ViewData = {
type ViewForm (line 25) | type ViewForm = {
type ListSharingResponse (line 31) | type ListSharingResponse = {
type DeleteSharingResponse (line 37) | type DeleteSharingResponse = {
function shareConversation (line 42) | async function shareConversation(
function viewConversation (line 54) | async function viewConversation(hash: string): Promise<ViewForm> {
function listSharing (line 67) | async function listSharing(): Promise<ListSharingResponse> {
function deleteSharing (line 79) | async function deleteSharing(
function getSharedLink (line 93) | function getSharedLink(hash: string): string {
FILE: app/src/api/types.tsx
type Role (line 10) | type Role = typeof UserRole | typeof AssistantRole | typeof SystemRole;
type Message (line 28) | type Message = {
type Model (line 74) | type Model = {
type Id (line 93) | type Id = number;
type ConversationInstance (line 95) | type ConversationInstance = {
type PlanItem (line 103) | type PlanItem = {
type Plan (line 111) | type Plan = {
type Plans (line 118) | type Plans = Plan[];
function newModel (line 120) | function newModel(id: string, name?: string, avatar?: string): Model {
FILE: app/src/api/v1.ts
type v1Options (line 6) | type v1Options = {
type v1Models (line 10) | type v1Models = {
type v1ModelItem (line 15) | type v1ModelItem =
type v1Resp (line 24) | type v1Resp<T> = {
type v1ApiKey (line 30) | type v1ApiKey = {
function getModelName (line 60) | function getModelName(id: string): string {
function getV1Path (line 81) | function getV1Path(path: string, options?: v1Options): string {
function getApiModels (line 88) | async function getApiModels(
function getApiPlans (line 121) | async function getApiPlans(options?: v1Options): Promise<Plan[]> {
function getApiMarket (line 132) | async function getApiMarket(options?: v1Options): Promise<Model[]> {
function getFilledApiMarket (line 142) | async function getFilledApiMarket(
function bindMarket (line 172) | async function bindMarket(options?: v1Options): Promise<Model[]> {
function getApiCharge (line 190) | async function getApiCharge(
function listApiKey (line 202) | async function listApiKey(
function updateApiKey (line 214) | async function updateApiKey(
function deleteApiKey (line 227) | async function deleteApiKey(
type ManifestJson (line 240) | type ManifestJson = {
function getManifestJson (line 252) | async function getManifestJson(): Promise<ManifestJson> {
FILE: app/src/components/Avatar.tsx
type AvatarProps (line 10) | interface AvatarProps extends ImgHTMLAttributes<HTMLElement> {
function checkGravatar (line 14) | async function checkGravatar(
function Avatar (line 39) | function Avatar({ username, ...props }: AvatarProps) {
FILE: app/src/components/EditorProvider.tsx
type RichEditorProps (line 21) | type RichEditorProps = {
function RichEditor (line 39) | function RichEditor({
function EditorProvider (line 199) | function EditorProvider(props: RichEditorProps) {
function JSONEditorProvider (line 229) | function JSONEditorProvider({ ...props }: RichEditorProps) {
FILE: app/src/components/Emoji.tsx
function getEmojiSource (line 3) | function getEmojiSource(emoji: string): string {
type EmojiProps (line 7) | type EmojiProps = {
function Emoji (line 12) | function Emoji({ emoji, className }: EmojiProps) {
FILE: app/src/components/ErrorBoundary.tsx
type ErrorBoundaryProps (line 9) | type ErrorBoundaryProps = { children: React.ReactNode } & WithTranslation;
class ErrorBoundary (line 11) | class ErrorBoundary extends React.Component<
method constructor (line 15) | constructor(props: ErrorBoundaryProps) {
method getDerivedStateFromError (line 20) | static getDerivedStateFromError(error: Error) {
method render (line 24) | render() {
FILE: app/src/components/FileProvider.tsx
type FileTask (line 47) | type FileTask = {
type FileTaskState (line 53) | type FileTaskState = {
function fileTaskReducer (line 57) | function fileTaskReducer(state: FileTaskState, action: any): FileTaskSta...
type FileProviderProps (line 80) | type FileProviderProps = {
function FileProvider (line 85) | function FileProvider({ files, dispatch }: FileProviderProps) {
type FileTaskItemProps (line 244) | type FileTaskItemProps = {
function FileTaskItem (line 248) | function FileTaskItem({ task }: FileTaskItemProps) {
type FileBadgeProps (line 259) | type FileBadgeProps = {
function getFileExtension (line 263) | function getFileExtension(name: string) {
function getFileIcon (line 267) | function getFileIcon(name: string) {
function FileIconObject (line 341) | function FileIconObject({ name }: FileBadgeProps) {
function FileBadge (line 351) | function FileBadge({ name }: FileBadgeProps) {
type FileListProps (line 416) | type FileListProps = {
function FileList (line 421) | function FileList({ value, removeFile }: FileListProps) {
type FileInputProps (line 486) | type FileInputProps = {
function FileInput (line 493) | function FileInput({ id, loading, className, handleEvent }: FileInputPro...
FILE: app/src/components/FileViewer.tsx
type FileViewerProps (line 15) | type FileViewerProps = {
type viewerType (line 22) | enum viewerType {
function FileViewer (line 27) | function FileViewer({ filename, content, children, asChild }: FileViewer...
FILE: app/src/components/I18nProvider.tsx
function I18nProvider (line 12) | function I18nProvider() {
FILE: app/src/components/Loader.tsx
type LoaderProps (line 3) | type LoaderProps = {
function Loader (line 8) | function Loader({ className, prompt }: LoaderProps) {
FILE: app/src/components/MCPResultDebug.tsx
type MCPResultDebugProps (line 6) | interface MCPResultDebugProps {
function MCPResultDebug (line 16) | function MCPResultDebug({ toolCall }: MCPResultDebugProps): JSX.Element {
FILE: app/src/components/MCPResultPanel.tsx
type ToolArgumentEditorProps (line 16) | interface ToolArgumentEditorProps {
function ToolArgumentEditor (line 22) | function ToolArgumentEditor({
type SingleToolCallPanelProps (line 104) | interface SingleToolCallPanelProps {
function SingleToolCallPanel (line 120) | function SingleToolCallPanel({
FILE: app/src/components/Markdown.tsx
type MarkdownProps (line 16) | type MarkdownProps = {
function MarkdownContent (line 24) | function MarkdownContent({
function Markdown (line 78) | function Markdown({
type CodeMarkdownProps (line 100) | type CodeMarkdownProps = MarkdownProps & {
function CodeMarkdown (line 105) | function CodeMarkdown({
FILE: app/src/components/Message.tsx
type MessageProps (line 40) | type MessageProps = {
function MessageSegment (line 54) | function MessageSegment(props: MessageProps) {
type MessageQuotaProps (line 80) | type MessageQuotaProps = {
function MessageQuota (line 84) | function MessageQuota({ message }: MessageQuotaProps) {
type MessageMenuProps (line 127) | type MessageMenuProps = {
function MessageMenu (line 139) | function MessageMenu({
function MessageContent (line 245) | function MessageContent({
FILE: app/src/components/ModelAvatar.tsx
type ModelAvatarProps (line 43) | type ModelAvatarProps = {
function getAvatarType (line 133) | function getAvatarType(id: string): string | undefined {
function ModelAvatar (line 138) | function ModelAvatar({ model, className, size }: ModelAvatarProps) {
type ChannelTypeAvatarProps (line 186) | type ChannelTypeAvatarProps = {
function ChannelTypeAvatar (line 192) | function ChannelTypeAvatar({
FILE: app/src/components/OperationAction.tsx
type ActionProps (line 16) | type ActionProps = ButtonProps & {
function OperationAction (line 31) | function OperationAction({
FILE: app/src/components/Paragraph.tsx
type ParagraphProps (line 13) | type ParagraphProps = {
function Paragraph (line 22) | function Paragraph({
function ParagraphItem (line 58) | function ParagraphItem({
type ParagraphDescriptionProps (line 74) | type ParagraphDescriptionProps = {
function ParagraphDescription (line 82) | function ParagraphDescription({
function ParagraphSpace (line 106) | function ParagraphSpace() {
function ParagraphFooter (line 110) | function ParagraphFooter({ children }: { children: React.ReactNode }) {
FILE: app/src/components/PopupDialog.tsx
type popupTypes (line 31) | enum popupTypes {
type ParamProps (line 41) | type ParamProps = {
type PopupDialogProps (line 46) | type PopupDialogProps = {
type PopupFieldProps (line 70) | type PopupFieldProps = PopupDialogProps & {
function PopupField (line 75) | function PopupField({
function fixedZero (line 153) | function fixedZero(val: number) {
function CalendarComp (line 157) | function CalendarComp(props: {
function PopupDialog (line 298) | function PopupDialog(props: PopupDialogProps) {
type PopupAlertDialogProps (line 370) | type PopupAlertDialogProps = {
function PopupAlertDialog (line 382) | function PopupAlertDialog({
FILE: app/src/components/ProjectLink.tsx
function ProjectLink (line 7) | function ProjectLink() {
FILE: app/src/components/ReloadService.tsx
function ReloadPrompt (line 7) | function ReloadPrompt() {
FILE: app/src/components/Require.tsx
function Required (line 6) | function Required() {
type LengthRangeRequiredProps (line 10) | type LengthRangeRequiredProps = {
function LengthRangeRequired (line 17) | function LengthRangeRequired({
type SameRequiredProps (line 41) | type SameRequiredProps = {
function SameRequired (line 47) | function SameRequired({
type EmailRequireProps (line 70) | type EmailRequireProps = {
function EmailRequire (line 75) | function EmailRequire({ content, hideOnEmpty }: EmailRequireProps) {
FILE: app/src/components/SelectGroup.tsx
type SingleSelectItemBadgeProps (line 14) | type SingleSelectItemBadgeProps = {
type SelectItemBadgeProps (line 22) | type SelectItemBadgeProps =
type SelectItemProps (line 26) | type SelectItemProps = {
type SelectGroupProps (line 34) | type SelectGroupProps = {
function SingleGroupSelectItemBadge (line 48) | function SingleGroupSelectItemBadge(props: SingleSelectItemBadgeProps) {
function GroupSelectItemBadge (line 90) | function GroupSelectItemBadge(props: { data: SelectItemBadgeProps }) {
function GroupSelectItem (line 98) | function GroupSelectItem(props: SelectItemProps) {
function SelectGroupDesktop (line 110) | function SelectGroupDesktop(props: SelectGroupProps) {
function SelectGroupMobile (line 184) | function SelectGroupMobile(props: SelectGroupProps) {
function SelectGroup (line 232) | function SelectGroup(props: SelectGroupProps) {
FILE: app/src/components/ThemeProvider.tsx
type Theme (line 10) | type Theme = "dark" | "light" | "system";
type ThemeProviderProps (line 12) | type ThemeProviderProps = {
type ThemeProviderState (line 17) | type ThemeProviderState = {
function activeTheme (line 23) | function activeTheme(theme: Theme) {
function getTheme (line 39) | function getTheme() {
function getNextTheme (line 44) | function getNextTheme(current: Theme): Theme {
function ThemeProvider (line 63) | function ThemeProvider({
function ThemeToggle (line 114) | function ThemeToggle({ className, size = "icon" }: { className?: string;...
FILE: app/src/components/ThinkContent.tsx
type ThinkContentProps (line 9) | interface ThinkContentProps {
function ThinkContent (line 14) | function ThinkContent({ content, isComplete = true }: ThinkContentProps) {
FILE: app/src/components/TickButton.tsx
type TickButtonProps (line 5) | interface TickButtonProps extends ButtonProps {
function TickButton (line 13) | function TickButton({
function useTicker (line 53) | function useTicker(
FILE: app/src/components/Tips.tsx
type TipsProps (line 17) | type TipsProps = {
function Tips (line 35) | function Tips({
FILE: app/src/components/TrendBadge.tsx
type TrendBadgeProps (line 4) | type TrendBadgeProps = {
FILE: app/src/components/VoiceProvider.tsx
function VoiceAction (line 6) | function VoiceAction() {
FILE: app/src/components/WarningButton.tsx
type WarningButtonProps (line 18) | type WarningButtonProps = ButtonProps & {
function WarningButton (line 26) | function WarningButton({
FILE: app/src/components/admin/ChannelSettings.tsx
function reducer (line 30) | function reducer(state: Channel, action: any): Channel {
function ChannelSettings (line 142) | function ChannelSettings() {
FILE: app/src/components/admin/ChargeWidget.tsx
function reducer (line 96) | function reducer(state: ChargeProps, action: any): ChargeProps {
function preflight (line 136) | function preflight(state: ChargeProps): ChargeProps {
type SyncDialogProps (line 160) | type SyncDialogProps = {
function SyncDialog (line 169) | function SyncDialog({
type ChargeActionProps (line 300) | type ChargeActionProps = {
function ChargeAction (line 306) | function ChargeAction({
type ChargeAlertProps (line 369) | type ChargeAlertProps = {
function ChargeAlert (line 374) | function ChargeAlert({ models, onClick }: ChargeAlertProps) {
type ChargeEditorProps (line 403) | type ChargeEditorProps = {
function ChargeEditor (line 411) | function ChargeEditor({
type ChargeTableProps (line 671) | type ChargeTableProps = {
function ChargeTable (line 677) | function ChargeTable({ data, dispatch, onRefresh }: ChargeTableProps) {
function ChargeWidget (line 762) | function ChargeWidget() {
FILE: app/src/components/admin/ChartBox.tsx
function ChartBox (line 24) | function ChartBox() {
FILE: app/src/components/admin/InfoBox.tsx
function InfoBox (line 16) | function InfoBox() {
FILE: app/src/components/admin/InvitationTable.tsx
function GenerateDialog (line 39) | function GenerateDialog({ update }: { update: () => void }) {
function InvitationTable (line 143) | function InvitationTable() {
FILE: app/src/components/admin/MenuBar.tsx
type MenuItemProps (line 26) | type MenuItemProps = {
function MenuItem (line 34) | function MenuItem({ title, icon, path, exit, pro }: MenuItemProps) {
function MenuBar (line 66) | function MenuBar() {
FILE: app/src/components/admin/RedeemTable.tsx
function GenerateDialog (line 39) | function GenerateDialog({ update }: { update: () => void }) {
function RedeemTable (line 147) | function RedeemTable() {
FILE: app/src/components/admin/UserTable.tsx
type OperationMenuProps (line 80) | type OperationMenuProps = {
type UserType (line 85) | enum UserType {
function doToast (line 99) | function doToast(t: any, resp: CommonResponse) {
function OperationMenu (line 112) | function OperationMenu({ user, onRefresh }: OperationMenuProps) {
function UserTable (line 368) | function UserTable() {
FILE: app/src/components/admin/assemblies/BillingChart.tsx
type BillingChartProps (line 7) | type BillingChartProps = {
function BillingChart (line 11) | function BillingChart({ labels, datasets }: BillingChartProps) {
FILE: app/src/components/admin/assemblies/BroadcastTable.tsx
type CreateBroadcastDialogProps (line 66) | type CreateBroadcastDialogProps = {
function CreateBroadcastDialog (line 70) | function CreateBroadcastDialog(props: CreateBroadcastDialogProps) {
type BroadcastItemProps (line 156) | type BroadcastItemProps = {
function BroadcastItem (line 161) | function BroadcastItem({ item, onRefresh }: BroadcastItemProps) {
function BroadcastTable (line 242) | function BroadcastTable() {
FILE: app/src/components/admin/assemblies/ChannelEditor.tsx
type CustomActionProps (line 66) | type CustomActionProps = {
function CustomAction (line 69) | function CustomAction({ onPost }: CustomActionProps) {
function validator (line 98) | function validator(state: Channel): boolean {
function handler (line 107) | function handler(data: Channel): Channel {
type ChannelEditorProps (line 145) | type ChannelEditorProps = {
function ChannelEditor (line 154) | function ChannelEditor({
FILE: app/src/components/admin/assemblies/ChannelTable.tsx
type ChannelTableProps (line 56) | type ChannelTableProps = {
type TypeBadgeProps (line 65) | type TypeBadgeProps = {
function TypeBadge (line 78) | function TypeBadge({ type, className, variant }: TypeBadgeProps) {
type SyncDialogProps (line 91) | type SyncDialogProps = {
function SyncDialog (line 97) | function SyncDialog({ dispatch, open, setOpen }: SyncDialogProps) {
function ChannelTable (line 182) | function ChannelTable({
FILE: app/src/components/admin/assemblies/ErrorChart.tsx
type ErrorChartProps (line 7) | type ErrorChartProps = {
function ErrorChart (line 11) | function ErrorChart({ labels, datasets }: ErrorChartProps) {
FILE: app/src/components/admin/assemblies/ModelChart.tsx
type ModelChartProps (line 10) | type ModelChartProps = {
function ModelChart (line 18) | function ModelChart({ labels, datasets }: ModelChartProps) {
FILE: app/src/components/admin/assemblies/ModelUsageChart.tsx
type ModelChartProps (line 10) | type ModelChartProps = {
type DataUsage (line 18) | type DataUsage = {
function ModelUsageChart (line 23) | function ModelUsageChart({ labels, datasets }: ModelChartProps) {
FILE: app/src/components/admin/assemblies/RequestChart.tsx
type RequestChartProps (line 7) | type RequestChartProps = {
function RequestChart (line 12) | function RequestChart({ labels, datasets }: RequestChartProps) {
FILE: app/src/components/admin/assemblies/UserTypeChart.tsx
type UserTypeChartProps (line 10) | type UserTypeChartProps = {
type UserType (line 14) | enum UserType {
type UserStatus (line 22) | type UserStatus = {
function UserTypeChart (line 27) | function UserTypeChart({ data }: UserTypeChartProps) {
FILE: app/src/components/admin/common/StateBadge.tsx
type StateBadgeProps (line 4) | type StateBadgeProps = {
function StateBadge (line 8) | function StateBadge({ state }: StateBadgeProps) {
FILE: app/src/components/app/Announcement.tsx
type AnnouncementProps (line 25) | type AnnouncementProps = {
function Announcement (line 32) | function Announcement({
type BroadcastListProps (line 138) | type BroadcastListProps = {
function BroadcastList (line 142) | function BroadcastList({ open, setOpen }: BroadcastListProps) {
FILE: app/src/components/app/AppProvider.tsx
function AppProvider (line 18) | function AppProvider({ children }: { children?: React.ReactNode }) {
FILE: app/src/components/app/Contact.tsx
function Contact (line 15) | function Contact() {
FILE: app/src/components/app/MenuBar.tsx
type MenuBarProps (line 29) | type MenuBarProps = {
type MenuBarItemProps (line 34) | type MenuBarItemProps = {
function MenuBar (line 52) | function MenuBar({ children, className }: MenuBarProps) {
FILE: app/src/components/app/NavBar.tsx
function NavMenu (line 28) | function NavMenu() {
function NavBar (line 47) | function NavBar() {
FILE: app/src/components/home/ChatInterface.tsx
type ChatInterfaceProps (line 13) | type ChatInterfaceProps = {
function ChatInterface (line 30) | function ChatInterface({ scrollable, setTarget }: ChatInterfaceProps) {
FILE: app/src/components/home/ChatSpace.tsx
function Footer (line 12) | function Footer() {
function ChatSpace (line 34) | function ChatSpace() {
FILE: app/src/components/home/ChatWrapper.tsx
type InterfaceProps (line 39) | type InterfaceProps = {
function Interface (line 44) | function Interface(props: InterfaceProps) {
function fileReducer (line 49) | function fileReducer(state: FileArray, action: Record<string, any>): Fil...
function ChatWrapper (line 62) | function ChatWrapper() {
FILE: app/src/components/home/ConversationItem.tsx
type ConversationItemProps (line 31) | type ConversationItemProps = {
function ConversationItem (line 39) | function ConversationItem({
FILE: app/src/components/home/MaskEditor.tsx
function maskEditorReducer (line 31) | function maskEditorReducer(state: CustomMask, action: any): CustomMask {
type RoleActionProps (line 102) | type RoleActionProps = {
function RoleAction (line 107) | function RoleAction({ role, onClick }: RoleActionProps) {
type MaskActionProps (line 129) | type MaskActionProps = {
function MaskAction (line 135) | function MaskAction({ children, disabled, onClick }: MaskActionProps) {
type CustomMaskDialogProps (line 146) | type CustomMaskDialogProps = {
function MaskEditor (line 153) | function MaskEditor({
FILE: app/src/components/home/ModelArea.tsx
function GetModel (line 69) | function GetModel(models: Model[], name: string): Model {
type ModelSelectorProps (line 73) | type ModelSelectorProps = {
function formatModel (line 77) | function formatModel(
function ModelFinder (line 117) | function ModelFinder(props: ModelSelectorProps) {
function ModelArea (line 193) | function ModelArea() {
FILE: app/src/components/home/SideBar.tsx
type Operation (line 47) | type Operation = {
type SidebarActionProps (line 52) | type SidebarActionProps = {
type ConversationListProps (line 58) | type ConversationListProps = {
function SidebarAction (line 64) | function SidebarAction({
function SidebarConversationList (line 195) | function SidebarConversationList({
function SideBar (line 398) | function SideBar() {
FILE: app/src/components/home/assemblies/ActionButton.tsx
type SendButtonProps (line 16) | type SendButtonProps = {
function ActionButton (line 21) | function ActionButton({ onClick, working }: SendButtonProps) {
type ActionCommandProps (line 64) | type ActionCommandProps = {
function ActionCommand (line 68) | function ActionCommand({ input }: ActionCommandProps) {
FILE: app/src/components/home/assemblies/ChatAction.tsx
type ChatActionProps (line 31) | type ChatActionProps = {
function WebAction (line 87) | function WebAction() {
function NewConversationAction (line 159) | function NewConversationAction() {
FILE: app/src/components/home/assemblies/ChatInput.tsx
type ChatInputProps (line 12) | type ChatInputProps = {
function ChatInput (line 20) | function ChatInput({
FILE: app/src/components/home/assemblies/ScrollAction.tsx
type ScrollActionProps (line 9) | type ScrollActionProps = {
function ScrollAction (line 15) | function ScrollAction(
FILE: app/src/components/home/subscription/SubscriptionUsage.tsx
type UsageProps (line 3) | type UsageProps = {
function SubscriptionUsage (line 11) | function SubscriptionUsage({ name, usage }: UsageProps) {
FILE: app/src/components/home/subscription/UpgradePlan.tsx
function countPrice (line 36) | function countPrice(data: Plans, base: number, month: number): number {
function countUpgradePrice (line 58) | function countUpgradePrice(
function getDiscountPercent (line 69) | function getDiscountPercent(data: Plans, base: number, month: number): n...
type UpgradeProps (line 89) | type UpgradeProps = {
function callBuyAction (line 95) | async function callBuyAction(
function callMigrateAction (line 134) | async function callMigrateAction(t: any, level: number): Promise<boolean> {
function Upgrade (line 148) | function Upgrade({ level, current, isYearly }: UpgradeProps) {
FILE: app/src/components/markdown/Code.tsx
type CodeProps (line 21) | type CodeProps = {
function Code (line 29) | function Code({
FILE: app/src/components/markdown/Image.tsx
type ImageState (line 18) | enum ImageState {
type ImageStateType (line 23) | type ImageStateType = (typeof ImageState)[keyof typeof ImageState];
function Image (line 25) | function Image({
FILE: app/src/components/markdown/Label.tsx
type QuotaExceededFormProps (line 20) | type QuotaExceededFormProps = {
function QuotaExceededForm (line 27) | function QuotaExceededForm({
type LabelProps (line 120) | type LabelProps = {
FILE: app/src/components/markdown/Link.tsx
function getSocialIcon (line 5) | function getSocialIcon(url: string) {
type LinkProps (line 24) | type LinkProps = {
FILE: app/src/components/markdown/Reference.tsx
type ReferenceProps (line 5) | interface ReferenceProps {
function Reference (line 10) | function Reference({ url, children }: ReferenceProps): JSX.Element {
FILE: app/src/components/markdown/Video.tsx
type VideoState (line 20) | enum VideoState {
type VideoStateType (line 25) | type VideoStateType = (typeof VideoState)[keyof typeof VideoState];
type VideoProps (line 27) | type VideoProps = React.VideoHTMLAttributes<HTMLVideoElement> & {
function Video (line 31) | function Video({
FILE: app/src/components/markdown/VirtualMessage.tsx
function getVirtualIcon (line 28) | function getVirtualIcon(command: string) {
function getVirualPrompt (line 46) | function getVirualPrompt(command: string) {
function GetI18nPrompt (line 80) | function GetI18nPrompt({ command }: { command: string }) {
type VirtualPromptProps (line 89) | type VirtualPromptProps = {
function VirtualPrompt (line 94) | function VirtualPrompt({ message, children }: VirtualPromptProps) {
type VirtualMessageProps (line 130) | type VirtualMessageProps = {
function parseMessage (line 135) | function parseMessage(message: string): { prompt: string; model: string } {
function VirtualMessage (line 145) | function VirtualMessage({ message, children }: VirtualMessageProps) {
FILE: app/src/components/plugins/file.tsx
type MarkdownFileProps (line 15) | type MarkdownFileProps = {
function MarkdownFile (line 20) | function MarkdownFile({ children, acceptDownload }: MarkdownFileProps) {
FILE: app/src/components/plugins/mermaid.tsx
type MermaidProps (line 19) | type MermaidProps = {
function Mermaid (line 23) | function Mermaid({ children }: MermaidProps) {
function MarkdownMermaid (line 86) | function MarkdownMermaid({ children }: { children: React.ReactNode }) {
FILE: app/src/components/plugins/progress.tsx
type MarkdownProgressbarProps (line 5) | type MarkdownProgressbarProps = {
function MarkdownProgressbar (line 9) | function MarkdownProgressbar({ children }: MarkdownProgressbarProps) {
FILE: app/src/components/ui/alert-dialog.tsx
type AlertDialogEmojiProps (line 82) | type AlertDialogEmojiProps = React.HTMLAttributes<HTMLDivElement> & {
FILE: app/src/components/ui/badge.tsx
type BadgeProps (line 29) | interface BadgeProps
type BadgeVariants (line 33) | type BadgeVariants = keyof ReturnType<typeof badgeVariants>;
function Badge (line 35) | function Badge({ className, variant, ...props }: BadgeProps) {
FILE: app/src/components/ui/button.tsx
type ButtonProps (line 52) | interface ButtonProps
type TemporaryButtonProps (line 168) | type TemporaryButtonProps = ButtonProps & {
type UploadFileButtonProps (line 190) | type UploadFileButtonProps = ButtonProps & {
FILE: app/src/components/ui/calendar.tsx
type CalendarProps (line 8) | type CalendarProps = React.ComponentProps<typeof DayPicker>;
function Calendar (line 10) | function Calendar({
FILE: app/src/components/ui/clickable.tsx
type ClickableProps (line 5) | interface ClickableProps
FILE: app/src/components/ui/combo-box.tsx
type ComboBoxProps (line 20) | type ComboBoxProps = {
function Combobox (line 35) | function Combobox({
FILE: app/src/components/ui/command.tsx
type CommandDialogProps (line 25) | interface CommandDialogProps extends DialogProps {}
FILE: app/src/components/ui/date-picker.tsx
type DatePickerProps (line 15) | type DatePickerProps = CalendarProps & {
function parseDate (line 21) | function parseDate(value?: string, init?: boolean): Date | undefined {
FILE: app/src/components/ui/dialog.tsx
type DialogContentProps (line 32) | type DialogContentProps = {
FILE: app/src/components/ui/icons/Github.tsx
function Github (line 3) | function Github(props: React.SVGProps<SVGSVGElement>) {
FILE: app/src/components/ui/icons/Send.tsx
function Send (line 3) | function Send(props: React.SVGProps<SVGSVGElement>) {
FILE: app/src/components/ui/input.tsx
type InputProps (line 7) | interface InputProps
FILE: app/src/components/ui/lib/utils.ts
function cn (line 4) | function cn(...inputs: ClassValue[]) {
FILE: app/src/components/ui/multi-combobox.tsx
type MultiComboBoxProps (line 20) | type MultiComboBoxProps = {
function MultiCombobox (line 39) | function MultiCombobox({
FILE: app/src/components/ui/number-input.tsx
type NumberInputProps (line 7) | interface NumberInputProps extends InputProps {
FILE: app/src/components/ui/pagination.tsx
type PaginationLinkProps (line 36) | type PaginationLinkProps = {
type PaginationActionProps (line 105) | type PaginationActionProps = React.ComponentProps<"div"> & {
FILE: app/src/components/ui/radio-box.tsx
type RadioBoxItemProps (line 7) | type RadioBoxItemProps = {
type RadioBoxProps (line 12) | type RadioBoxProps = {
FILE: app/src/components/ui/sheet.tsx
type SheetContentProps (line 50) | interface SheetContentProps
FILE: app/src/components/ui/skeleton.tsx
function Skeleton (line 4) | function Skeleton({
FILE: app/src/components/ui/slider.tsx
type SliderProps (line 6) | type SliderProps = {
FILE: app/src/components/ui/sonner.tsx
type ToasterProps (line 5) | type ToasterProps = React.ComponentProps<typeof Sonner>;
FILE: app/src/components/ui/step.tsx
type StepProps (line 5) | type StepProps = {
function Step (line 12) | function Step({ step, label, children, className, ...props }: StepProps) {
FILE: app/src/components/ui/table.tsx
type TableProps (line 16) | type TableProps = React.HTMLAttributes<HTMLTableElement> & {
type Visibility (line 126) | type Visibility = {
type VisibilityOptions (line 130) | type VisibilityOptions = {
type Column (line 134) | type Column = { key: string; name: string; value: boolean };
type ColumnsVisibilityBarProps (line 172) | type ColumnsVisibilityBarProps = {
FILE: app/src/components/ui/textarea.tsx
type TextareaProps (line 6) | interface TextareaProps
type FlexibleTextareaProps (line 26) | interface FlexibleTextareaProps extends TextareaProps {
FILE: app/src/components/ui/toast.tsx
type ToastProps (line 113) | type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>;
type ToastActionElement (line 115) | type ToastActionElement = React.ReactElement<typeof ToastAction>;
FILE: app/src/components/ui/toaster.tsx
function Toaster (line 11) | function Toaster() {
FILE: app/src/components/ui/use-toast.ts
constant TOAST_LIMIT (line 6) | const TOAST_LIMIT = 3;
constant TOAST_REMOVE_DELAY (line 7) | const TOAST_REMOVE_DELAY = 1000000;
type ToasterToast (line 9) | type ToasterToast = ToastProps & {
function genId (line 27) | function genId() {
type ActionType (line 32) | type ActionType = typeof actionTypes;
type Action (line 34) | type Action =
type State (line 52) | interface State {
function dispatch (line 152) | function dispatch(action: Action) {
type Toast (line 159) | type Toast = Omit<ToasterToast, "id">;
function toast (line 161) | function toast({ ...props }: Toast, timeout?: number) {
function useToast (line 194) | function useToast() {
FILE: app/src/components/utils/Icon.tsx
type Icon (line 3) | type Icon = {
function Icon (line 9) | function Icon({ icon, className, id, ...props }: Icon) {
FILE: app/src/conf/api.ts
type AxiosConfig (line 4) | type AxiosConfig = {
function setAxiosConfig (line 9) | function setAxiosConfig(config: AxiosConfig) {
FILE: app/src/conf/deeptrain.tsx
function goDeepLogin (line 10) | function goDeepLogin() {
function DeeptrainOnly (line 17) | function DeeptrainOnly({ children }: { children: React.ReactNode }) {
FILE: app/src/conf/env.ts
function getDev (line 32) | function getDev(): boolean {
function getRestApi (line 39) | function getRestApi(deploy: boolean): string {
function getWebsocketApi (line 46) | function getWebsocketApi(deploy: boolean): string {
function getTokenField (line 63) | function getTokenField(deploy: boolean): string {
function setAppName (line 70) | function setAppName(name: string): void {
function setAppLogo (line 81) | function setAppLogo(logo: string): void {
function setDocsUrl (line 92) | function setDocsUrl(url: string): void {
function setBlobEndpoint (line 101) | function setBlobEndpoint(endpoint: string): void {
function setBuyLink (line 110) | function setBuyLink(link: string): void {
FILE: app/src/conf/model.ts
function getModelFromId (line 3) | function getModelFromId(market: Model[], id: string): Model | undefined {
function isHighContextModel (line 7) | function isHighContextModel(market: Model[], id: string): boolean {
FILE: app/src/conf/storage.ts
function savePreferenceModels (line 4) | function savePreferenceModels(models: Model[]): void {
function getPreferenceModels (line 8) | function getPreferenceModels(): string[] {
function loadPreferenceModels (line 13) | function loadPreferenceModels(models: Model[]): Model[] {
function setOfflineModels (line 33) | function setOfflineModels(models: Model[]): void {
function parseOfflineModels (line 37) | function parseOfflineModels(models: string): Model[] {
function getOfflineModels (line 70) | function getOfflineModels(): Model[] {
function setOfflinePlans (line 75) | function setOfflinePlans(plans: Plan[]): void {
function parseOfflinePlans (line 79) | function parseOfflinePlans(plans: string): Plan[] {
function getOfflinePlans (line 89) | function getOfflinePlans(): Plan[] {
FILE: app/src/conf/subscription.tsx
function getPlan (line 9) | function getPlan(data: Plans, level: number): Plan {
function getPlanModels (line 14) | function getPlanModels(data: Plans, level: number): string[] {
function includingModelFromPlan (line 18) | function includingModelFromPlan(
function getPlanPrice (line 26) | function getPlanPrice(data: Plans, level: number): number {
function getPlanName (line 30) | function getPlanName(level: number): string {
FILE: app/src/dialogs/SettingsDialog.tsx
function SettingsDialog (line 46) | function SettingsDialog() {
FILE: app/src/dialogs/index.tsx
function DialogManager (line 4) | function DialogManager() {
FILE: app/src/events/spinner.ts
type SpinnerEvent (line 3) | type SpinnerEvent = {
FILE: app/src/events/struct.ts
type EventCommitterProps (line 1) | type EventCommitterProps = {
class EventCommitter (line 6) | class EventCommitter<T> {
method constructor (line 12) | constructor({ name, destroyedAfterTrigger = false }: EventCommitterPro...
method setTrigger (line 17) | protected setTrigger(trigger: (data: T) => void) {
method clearTrigger (line 21) | protected clearTrigger() {
method triggerEvent (line 25) | protected triggerEvent(data: T) {
method emit (line 32) | public emit(data: T) {
method bind (line 36) | public bind(trigger: (data: T) => void) {
method addEventListener (line 40) | public addEventListener(listener: (data: T) => void) {
method removeEventListener (line 44) | public removeEventListener(listener: (data: T) => void) {
method clearEventListener (line 48) | public clearEventListener() {
FILE: app/src/i18n.ts
function getLanguage (line 47) | function getLanguage(): string {
function setLanguage (line 60) | function setLanguage(i18n: any, lang: string): void {
FILE: app/src/masks/prompts.ts
constant MASKS (line 4) | let MASKS: Mask[] = [];
FILE: app/src/masks/types.ts
type MaskMessage (line 3) | type MaskMessage = {
type Mask (line 8) | type Mask = {
type CustomMask (line 18) | type CustomMask = Mask & {
FILE: app/src/payment/icons.tsx
type IconProps (line 7) | type IconProps = React.SVGProps<SVGSVGElement>;
function Alipay (line 9) | function Alipay(props: IconProps) {
function Wechat (line 22) | function Wechat(props: IconProps) {
function Paypal (line 35) | function Paypal(props: IconProps) {
function Afdian (line 48) | function Afdian(props: IconProps) {
function Stripe (line 65) | function Stripe(props: IconProps) {
function QQ (line 78) | function QQ(props: IconProps) {
function PaymentIcon (line 115) | function PaymentIcon({ type, ...props }: { type: string } & IconProps) {
function PaymentButton (line 120) | function PaymentButton({
FILE: app/src/payment/request.ts
type PaymentResponse (line 9) | type PaymentResponse = CommonResponse & {
type PaymentStatusResponse (line 16) | type PaymentStatusResponse = CommonResponse & {
type PaymentOrder (line 21) | type PaymentOrder = {
type PaymentListResponse (line 35) | type PaymentListResponse = CommonResponse & {
type RecheckOrderResponse (line 40) | type RecheckOrderResponse = CommonResponse & {
function createPaymentOrder (line 45) | async function createPaymentOrder(
function getPaymentOrderStatus (line 64) | async function getPaymentOrderStatus(
function usePaymentState (line 77) | function usePaymentState(order: string): boolean {
function getPaymentOrders (line 97) | async function getPaymentOrders(
function recheckOrderStatus (line 114) | async function recheckOrderStatus(
FILE: app/src/payment/utils.ts
function getDomain (line 3) | function getDomain() {
function getDeviceType (line 9) | function getDeviceType() {
FILE: app/src/plugin/types.ts
type PluginEditorState (line 1) | type PluginEditorState = {
type TestResult (line 9) | type TestResult = {
type PluginEditorAction (line 19) | type PluginEditorAction =
function pluginEditorReducer (line 35) | function pluginEditorReducer(
FILE: app/src/router.tsx
function AuthRequired (line 317) | function AuthRequired({ children }: { children: React.ReactNode }) {
function AuthForbidden (line 332) | function AuthForbidden({ children }: { children: React.ReactNode }) {
function AdminRequired (line 347) | function AdminRequired({ children }: { children: React.ReactNode }) {
function AppRouter (line 362) | function AppRouter() {
FILE: app/src/routes/Account.tsx
type AccountCardProps (line 68) | type AccountCardProps = {
function AccountCard (line 78) | function AccountCard({
type ShareContentProps (line 124) | type ShareContentProps = {
function ShareContent (line 128) | function ShareContent({ data }: ShareContentProps) {
function Account (line 193) | function Account() {
FILE: app/src/routes/Admin.tsx
function Admin (line 10) | function Admin() {
FILE: app/src/routes/Article.tsx
type ProgressProps (line 29) | type ProgressProps = {
function GenerateProgress (line 34) | function GenerateProgress({
function ArticleContent (line 73) | function ArticleContent() {
function Wrapper (line 211) | function Wrapper() {
function Article (line 229) | function Article() {
FILE: app/src/routes/Auth.tsx
function DeepAuth (line 24) | function DeepAuth() {
function Login (line 84) | function Login() {
function Auth (line 220) | function Auth() {
FILE: app/src/routes/Forgot.tsx
function Forgot (line 24) | function Forgot() {
FILE: app/src/routes/Generation.tsx
type WrapperProps (line 18) | type WrapperProps = {
function Wrapper (line 22) | function Wrapper({ onSend }: WrapperProps) {
function Generation (line 153) | function Generation() {
FILE: app/src/routes/Home.tsx
function Home (line 4) | function Home() {
FILE: app/src/routes/Index.tsx
type BarItemProps (line 33) | type BarItemProps = {
function isPrefix (line 39) | function isPrefix(current: string, path: string): boolean {
function BarItem (line 46) | function BarItem({ icon, path, name }: BarItemProps) {
function ToolBar (line 96) | function ToolBar() {
function Home (line 125) | function Home() {
FILE: app/src/routes/Model.tsx
type SearchBarProps (line 81) | type SearchBarProps = {
function getTags (line 92) | function getTags(model: Model): string[] {
function SearchBar (line 104) | function SearchBar({
type ModelProps (line 198) | type ModelProps = React.DetailedHTMLProps<
type PriceColumnProps (line 211) | type PriceColumnProps = ChargeBaseProps & {
function PriceColumn (line 217) | function PriceColumn({
function ModelItem (line 301) | function ModelItem({
type MarketPlaceProps (line 518) | type MarketPlaceProps = {
function MarketPlace (line 524) | function MarketPlace({ search, showPricing, show1mPricing }: MarketPlace...
function MarketHeader (line 576) | function MarketHeader() {
function MarketFooter (line 607) | function MarketFooter() {
function Model (line 630) | function Model() {
FILE: app/src/routes/NotFound.tsx
function NotFound (line 7) | function NotFound() {
FILE: app/src/routes/Register.tsx
type CompProps (line 23) | type CompProps = {
function Preflight (line 30) | function Preflight({ form, dispatch, setNext }: CompProps) {
function doFormat (line 122) | function doFormat(form: RegisterForm): RegisterForm {
function Verify (line 133) | function Verify({ form, dispatch, setNext }: CompProps) {
function Register (line 235) | function Register() {
FILE: app/src/routes/Sharing.tsx
type SharingFormProps (line 35) | type SharingFormProps = {
function SharingForm (line 40) | function SharingForm({ data }: SharingFormProps) {
function Sharing (line 224) | function Sharing() {
FILE: app/src/routes/Wallet.tsx
type PlanItemProps (line 46) | type PlanItemProps = {
function PlanItem (line 51) | function PlanItem({ level, isYearly }: PlanItemProps) {
function WalletPlanBox (line 255) | function WalletPlanBox() {
function Wallet (line 453) | function Wallet() {
FILE: app/src/routes/admin/Broadcast.tsx
function Broadcast (line 10) | function Broadcast() {
FILE: app/src/routes/admin/Channel.tsx
function Channel (line 10) | function Channel() {
FILE: app/src/routes/admin/Charge.tsx
function Charge (line 10) | function Charge() {
FILE: app/src/routes/admin/DashBoard.tsx
function DashBoard (line 4) | function DashBoard() {
FILE: app/src/routes/admin/License.tsx
type ModuleItemProps (line 16) | type ModuleItemProps = {
function ModuleItem (line 21) | function ModuleItem({ id, price, bought }: ModuleItemProps) {
function License (line 77) | function License() {
FILE: app/src/routes/admin/Logger.tsx
type LoggerItemProps (line 26) | type LoggerItemProps = Logger & {
function LoggerItem (line 29) | function LoggerItem({ path, size, onUpdate }: LoggerItemProps) {
function LoggerList (line 68) | function LoggerList() {
function LoggerConsole (line 86) | function LoggerConsole() {
function Logger (line 196) | function Logger() {
FILE: app/src/routes/admin/Market.tsx
type Model (line 65) | type Model = RawModel & {
type MarketForm (line 69) | type MarketForm = Model[];
function reducer (line 73) | function reducer(state: MarketForm, action: any): MarketForm {
type MarketTagsProps (line 340) | type MarketTagsProps = {
function MarketTags (line 346) | function MarketTags({ tag, idx, dispatch }: MarketTagsProps) {
type MarketImageProps (line 387) | type MarketImageProps = {
function CustomMarketImage (line 393) | function CustomMarketImage({ image, idx, dispatch }: MarketImageProps) {
type MarketItemProps (line 455) | type MarketItemProps = React.DetailedHTMLProps<
function MarketItem (line 468) | function MarketItem({
type MarketGroupProps (line 780) | type MarketGroupProps = {
function MarketGroup (line 787) | function MarketGroup({
type SyncDialogProps (line 817) | type SyncDialogProps = {
function SyncDialog (line 825) | function SyncDialog({
type MarketAlertProps (line 944) | type MarketAlertProps = {
function MarketAlert (line 951) | function MarketAlert({
function Market (line 996) | function Market() {
FILE: app/src/routes/admin/Notification.tsx
function Notification (line 2) | function Notification() {
FILE: app/src/routes/admin/Subscription.tsx
function reducer (line 59) | function reducer(state: PlanConfig, action: Record<string, any>): PlanCo...
type ImportActionProps (line 318) | type ImportActionProps = {
type ImportActionItem (line 324) | type ImportActionItem = {
function ImportAction (line 329) | function ImportAction({ plans, level, dispatch }: ImportActionProps) {
function PlanConfig (line 369) | function PlanConfig() {
function Subscription (line 789) | function Subscription() {
FILE: app/src/routes/admin/System.tsx
type CompProps (line 67) | type CompProps<T> = {
function RootDialog (line 74) | function RootDialog() {
function General (line 150) | function General({ data, dispatch, onChange }: CompProps<GeneralState>) {
function Mail (line 279) | function Mail({ data, dispatch, onChange }: CompProps<MailState>) {
function Site (line 519) | function Site({ data, dispatch, onChange }: CompProps<SiteState>) {
function Common (line 666) | function Common({ form, data, dispatch, onChange }: CompProps<CommonStat...
function Search (line 833) | function Search({ data, dispatch, onChange }: CompProps<SearchState>) {
function System (line 1042) | function System() {
FILE: app/src/routes/admin/Users.tsx
function Users (line 15) | function Users() {
FILE: app/src/routes/admin/common/CommonAdminPage.tsx
type CommonAdminPageProps (line 11) | type CommonAdminPageProps = {
function CommonAdminPage (line 17) | function CommonAdminPage({ title, children, pro }: CommonAdminPageProps) {
FILE: app/src/routes/wallet/AmountItem.tsx
type AmountComponentProps (line 10) | type AmountComponentProps = {
function QuotaItem (line 18) | function QuotaItem({ amount, active, other, onClick }: AmountComponentPr...
type QuotaWrapperProps (line 62) | type QuotaWrapperProps = {
function QuotaWrapper (line 70) | function QuotaWrapper({
FILE: app/src/routes/wallet/WalletQuotaBox.tsx
function WalletQuotaBox (line 22) | function WalletQuotaBox() {
type RedeemComponentProps (line 129) | type RedeemComponentProps = {
function RedeemComponent (line 134) | function RedeemComponent({ open, onOpenChanged }: RedeemComponentProps) {
FILE: app/src/spinner.tsx
function Spinner (line 11) | function Spinner() {
FILE: app/src/store/auth.ts
function validateToken (line 64) | function validateToken(
FILE: app/src/store/avatar.ts
type AvatarState (line 3) | interface AvatarState {
FILE: app/src/store/chat.ts
type ConversationSerialized (line 48) | type ConversationSerialized = {
type ConnectionEvent (line 53) | type ConnectionEvent = {
type initialStateType (line 60) | type initialStateType = {
function inModel (line 75) | function inModel(supportModels: Model[], model: string): boolean {
function getModel (line 82) | function getModel(
function getModelList (line 90) | function getModelList(
function useConversation (line 396) | function useConversation(): ConversationSerialized | undefined {
function useConversationActions (line 403) | function useConversationActions() {
function useMessageActions (line 471) | function useMessageActions() {
function listenMessageEvent (line 588) | function listenMessageEvent() {
function useMessages (line 611) | function useMessages(): Message[] {
function useWorking (line 623) | function useWorking(): boolean {
FILE: app/src/store/globals.ts
type GlobalState (line 7) | type GlobalState = {
FILE: app/src/store/index.ts
type RootState (line 34) | type RootState = ReturnType<typeof store.getState>;
type AppDispatch (line 35) | type AppDispatch = typeof store.dispatch;
function createCronJob (line 37) | function createCronJob(
function clearCronJob (line 47) | function clearCronJob(job: ReturnType<typeof setInterval>) {
function clearCronJobs (line 51) | function clearCronJobs(jobs: ReturnType<typeof setInterval>[]) {
FILE: app/src/store/info.ts
type Currency (line 15) | type Currency = {
FILE: app/src/store/record.ts
type RecordProps (line 5) | type RecordProps = {
FILE: app/src/store/utils.ts
function dispatchWrapper (line 4) | function dispatchWrapper(
function getSelector (line 13) | function getSelector(reducer: string, key: string) {
FILE: app/src/translator/adapter.ts
function getFormattedLanguage (line 16) | function getFormattedLanguage(lang: string): string {
type translationResponse (line 20) | type translationResponse = {
function translate (line 26) | async function translate(
function doTranslate (line 42) | function doTranslate(
FILE: app/src/translator/index.ts
function createTranslationPlugin (line 4) | function createTranslationPlugin(): Plugin {
FILE: app/src/translator/io.ts
function readJSON (line 4) | function readJSON(...paths: string[]): any {
function writeJSON (line 8) | function writeJSON(data: any, ...paths: string[]): void {
function getMigration (line 12) | function getMigration(
function getFields (line 40) | function getFields(data: any): number {
function getTranslation (line 55) | function getTranslation(data: Record<string, any>, path: string): any {
function setTranslation (line 65) | function setTranslation(
FILE: app/src/translator/translator.ts
function processTranslation (line 16) | async function processTranslation(
FILE: app/src/types/performance.d.ts
type PerformanceMemory (line 4) | interface PerformanceMemory {
type Performance (line 10) | interface Performance {
type Window (line 14) | interface Window {
FILE: app/src/types/service.d.ts
type BeforeInstallPromptEvent (line 17) | interface BeforeInstallPromptEvent extends Event {
FILE: app/src/types/ui.d.ts
type ToastProps (line 4) | interface ToastProps {
type ToastFunc (line 15) | type ToastFunc = (title: string, options?: ToastProps) => void;
type ToastPromise (line 16) | type ToastPromise = (promise: Promise<any>, options?: any) => void;
FILE: app/src/utils/analytics.ts
function initGoogleAnalytics (line 3) | function initGoogleAnalytics(trackingId: string | undefined): void {
FILE: app/src/utils/app.ts
function triggerInstallApp (line 12) | function triggerInstallApp() {
function getMemoryPerformance (line 34) | function getMemoryPerformance(): number {
function navigate (line 47) | function navigate(path: string): void {
function goAuth (line 54) | function goAuth(): void {
FILE: app/src/utils/base.ts
function insert (line 3) | function insert<T>(arr: T[], idx: number, value: T): T[] {
function insertStart (line 7) | function insertStart<T>(arr: T[], value: T): T[] {
function remove (line 11) | function remove<T>(arr: T[], idx: number): T[] {
function replace (line 15) | function replace<T>(arr: T[], idx: number, value: T): T[] {
function move (line 19) | function move<T>(arr: T[], from: number, to: number): T[] {
function asyncCaller (line 24) | function asyncCaller<T>(fn: (...args: any[]) => Promise<T>) {
function sum (line 32) | function sum(arr: number[]): number {
function average (line 36) | function average(arr: number[]): number {
function getUniqueList (line 40) | function getUniqueList<T>(arr: T[]): T[] {
function getNumber (line 44) | function getNumber(value: string, supportNegative = true): string {
function parseNumber (line 48) | function parseNumber(value: string): number {
function splitList (line 52) | function splitList(value: string, separators: string[]): string[] {
function getErrorMessage (line 60) | function getErrorMessage(error: any): string {
function isAsyncFunc (line 66) | function isAsyncFunc(fn: any): boolean {
function generateRandomChar (line 70) | function generateRandomChar(n: number): string {
function generateInt (line 78) | function generateInt(min: number, max: number): number {
function generateListNumber (line 82) | function generateListNumber(n: number): number {
function isUrl (line 86) | function isUrl(value: string): boolean {
function isEnter (line 99) | function isEnter<T extends HTMLElement>(
function withCtrl (line 105) | function withCtrl<T extends HTMLElement>(
function withShift (line 112) | function withShift<T extends HTMLElement>(
function resetJsArray (line 118) | function resetJsArray<T>(arr: T[], target: T[]): T[] {
function getSizeUnit (line 127) | function getSizeUnit(size: number): string {
function getHostName (line 134) | function getHostName(url: string): string {
function isB64Image (line 142) | function isB64Image(value: string): boolean {
function trimPrefix (line 146) | function trimPrefix(value: string, prefix: string): string {
function trimSuffix (line 150) | function trimSuffix(value: string, suffix: string): string {
function addPrefix (line 154) | function addPrefix(value: string, prefix: string): string {
function addSuffix (line 158) | function addSuffix(value: string, suffix: string): string {
function trimPrefixes (line 162) | function trimPrefixes(value: string, prefixes: string[]): string {
function trimSuffixes (line 169) | function trimSuffixes(value: string, suffixes: string[]): string {
function getFilenameFromURL (line 176) | function getFilenameFromURL(url: string | undefined): string {
function formatDecimal (line 182) | function formatDecimal(value: number): string {
FILE: app/src/utils/date.ts
function convertDate (line 1) | function convertDate(date: Date): string {
function convertDateTime (line 6) | function convertDateTime(date: Date): string {
FILE: app/src/utils/desktop.ts
function isTauri (line 1) | function isTauri(): boolean {
FILE: app/src/utils/dev.ts
function inWaiting (line 1) | function inWaiting(duration: number): Promise<void> {
FILE: app/src/utils/device.ts
function isMobile (line 10) | function isMobile(): boolean {
function isSafari (line 23) | function isSafari(): boolean {
function useMobile (line 32) | function useMobile(): boolean {
function openWindow (line 58) | function openWindow(url: string, target?: string): void {
function openPage (line 73) | function openPage(url: string): void {
function openForm (line 77) | function openForm(
FILE: app/src/utils/dom.ts
function _copyClipboard (line 6) | async function _copyClipboard(text: string) {
function copyClipboard (line 24) | async function copyClipboard(text: string) {
function useClipboard (line 40) | function useClipboard() {
function saveAsFile (line 70) | function saveAsFile(filename: string, content: string) {
function saveBlobAsFile (line 86) | function saveBlobAsFile(filename: string, blob: Blob) {
function saveImageAsFile (line 102) | function saveImageAsFile(filename: string, data_url: string) {
function getSelectionText (line 117) | function getSelectionText(): string {
function getSelectionTextInArea (line 134) | function getSelectionTextInArea(el: HTMLElement): string {
function useDraggableInput (line 154) | function useDraggableInput(
function testNumberInputEvent (line 185) | function testNumberInputEvent(e: any): boolean {
function replaceInputValue (line 209) | function replaceInputValue(
function useInputValue (line 225) | function useInputValue(id: string, value: string) {
function addEventListener (line 239) | function addEventListener(
function addEventListeners (line 260) | function addEventListeners(
function scrollDown (line 282) | function scrollDown(el: HTMLElement | null) {
function scrollUp (line 298) | function scrollUp(el: HTMLElement | null) {
function updateFavicon (line 314) | function updateFavicon(url?: string) {
function updateDocumentTitle (line 326) | function updateDocumentTitle(title?: string) {
function getQuerySelector (line 337) | function getQuerySelector(query: string): HTMLElement | null {
function isContainDom (line 349) | function isContainDom(
function convertImgToB64 (line 371) | function convertImgToB64(img: HTMLImageElement): string {
FILE: app/src/utils/form.ts
function setKey (line 1) | function setKey<T>(state: T, key: string, value: any): T {
function isEmailValid (line 36) | function isEmailValid(email: string) {
function isInRange (line 40) | function isInRange(value: number, min: number, max: number) {
function isTextInRange (line 44) | function isTextInRange(value: string, min: number, max: number) {
FILE: app/src/utils/groups.ts
function useGroup (line 22) | function useGroup(countAdminLevel?: boolean): string {
function hitGroup (line 43) | function hitGroup(group: string[]): boolean {
FILE: app/src/utils/hook.ts
function useEffectAsync (line 3) | function useEffectAsync<T>(effect: () => Promise<T>, deps?: any[]) {
function useAnimation (line 21) | function useAnimation(
function useTemporaryState (line 47) | function useTemporaryState(interval?: number): {
FILE: app/src/utils/loader.tsx
function lazyFactor (line 9) | function lazyFactor<T extends React.ComponentType<any>>(
FILE: app/src/utils/memory.ts
function setMemory (line 1) | function setMemory(key: string, value: string) {
function setBooleanMemory (line 6) | function setBooleanMemory(key: string, value: boolean) {
function setNumberMemory (line 10) | function setNumberMemory(key: string, value: number) {
function setArrayMemory (line 14) | function setArrayMemory(key: string, value: string[]) {
function getMemory (line 18) | function getMemory(key: string, defaultValue?: string): string {
function getBooleanMemory (line 22) | function getBooleanMemory(key: string, defaultValue: boolean): boolean {
function getNumberMemory (line 27) | function getNumberMemory(key: string, defaultValue: number): number {
function getArrayMemory (line 32) | function getArrayMemory(key: string): string[] {
function forgetMemory (line 37) | function forgetMemory(key: string) {
function clearMemory (line 41) | function clearMemory() {
function popMemory (line 45) | function popMemory(key: string): string {
FILE: app/src/utils/path.ts
function getQueryParams (line 1) | function getQueryParams() {
function getQueryParam (line 19) | function getQueryParam(key: string): string {
function replaceHistoryState (line 33) | function replaceHistoryState(
function pushHistoryState (line 48) | function pushHistoryState(
function getHistoryState (line 63) | function getHistoryState(): Record<string, string> {
function clearHistoryState (line 75) | function clearHistoryState() {
FILE: app/src/utils/processor.ts
function getFile (line 3) | function getFile(file: FileObject): string {
function formatMessage (line 10) | function formatMessage(files: FileArray, message: string): string {
function filterMessage (line 17) | function filterMessage(message: string): string {
function extractMessage (line 21) | function extractMessage(
function escapeRegExp (line 29) | function escapeRegExp(str: string): string {
function handleLine (line 40) | function handleLine(
function handleGenerationData (line 56) | function handleGenerationData(data: string): string {
function getReadableNumber (line 64) | function getReadableNumber(
FILE: auth/analysis.go
function getMonth (line 10) | func getMonth() string {
function getDay (line 15) | func getDay() string {
function getBillingFormat (line 20) | func getBillingFormat(t string) string {
function getMonthBillingFormat (line 24) | func getMonthBillingFormat(t string) string {
function incrBillingRequest (line 28) | func incrBillingRequest(cache *redis.Client, amount int64) {
FILE: auth/apikey.go
method CreateApiKey (line 11) | func (u *User) CreateApiKey(db *sql.DB) string {
method GetApiKey (line 20) | func (u *User) GetApiKey(db *sql.DB) string {
method ResetApiKey (line 28) | func (u *User) ResetApiKey(db *sql.DB) (string, error) {
FILE: auth/auth.go
function ParseToken (line 20) | func ParseToken(c *gin.Context, token string) *User {
function ParseApiKey (line 43) | func ParseApiKey(c *gin.Context, key string) *User {
function getCode (line 62) | func getCode(c *gin.Context, cache *redis.Client, email string) string {
function checkCode (line 70) | func checkCode(c *gin.Context, cache *redis.Client, email, code string) ...
function setCode (line 84) | func setCode(c *gin.Context, cache *redis.Client, email, code string) {
function generateCode (line 88) | func generateCode(c *gin.Context, cache *redis.Client, email string) str...
function Verify (line 94) | func Verify(c *gin.Context, email string, checkout bool) error {
function SignUp (line 107) | func SignUp(c *gin.Context, form RegisterForm) (string, error) {
function Login (line 164) | func Login(c *gin.Context, form LoginForm) (string, error) {
function DeepLogin (line 194) | func DeepLogin(c *gin.Context, token string) (string, error) {
function Reset (line 247) | func Reset(c *gin.Context, form ResetForm) error {
method UpdatePassword (line 285) | func (u *User) UpdatePassword(db *sql.DB, cache *redis.Client, password ...
method Validate (line 299) | func (u *User) Validate(c *gin.Context) bool {
method GenerateToken (line 326) | func (u *User) GenerateToken() (string, error) {
method GenerateTokenSafe (line 341) | func (u *User) GenerateTokenSafe(db *sql.DB) (string, error) {
FILE: auth/call.go
type ValidateUserResponse (line 9) | type ValidateUserResponse struct
function getDeeptrainApi (line 15) | func getDeeptrainApi(path string) string {
function useDeeptrain (line 19) | func useDeeptrain() bool {
function Validate (line 23) | func Validate(token string) *ValidateUserResponse {
FILE: auth/cert.go
type CertResponse (line 9) | type CertResponse struct
function Cert (line 15) | func Cert(username string) *CertResponse {
FILE: auth/controller.go
type RegisterForm (line 13) | type RegisterForm struct
type VerifyForm (line 20) | type VerifyForm struct
type LoginForm (line 25) | type LoginForm struct
type DeepLoginForm (line 30) | type DeepLoginForm struct
type ResetForm (line 34) | type ResetForm struct
type BuyForm (line 40) | type BuyForm struct
type SubscribeForm (line 44) | type SubscribeForm struct
function GetUser (line 49) | func GetUser(c *gin.Context) *User {
function GetUserByCtx (line 58) | func GetUserByCtx(c *gin.Context) *User {
function RequireAuth (line 73) | func RequireAuth(c *gin.Context) *User {
function RequireAdmin (line 83) | func RequireAdmin(c *gin.Context) *User {
function RequireSubscription (line 102) | func RequireSubscription(c *gin.Context) *User {
function RequireEnterprise (line 121) | func RequireEnterprise(c *gin.Context) *User {
function RegisterAPI (line 140) | func RegisterAPI(c *gin.Context) {
function LoginAPI (line 181) | func LoginAPI(c *gin.Context) {
function VerifyAPI (line 223) | func VerifyAPI(c *gin.Context) {
function ResetAPI (line 246) | func ResetAPI(c *gin.Context) {
function StateAPI (line 269) | func StateAPI(c *gin.Context) {
function UserInfoAPI (line 278) | func UserInfoAPI(c *gin.Context) {
function IndexAPI (line 298) | func IndexAPI(c *gin.Context) {
function KeyAPI (line 308) | func KeyAPI(c *gin.Context) {
function ResetKeyAPI (line 324) | func ResetKeyAPI(c *gin.Context) {
function PackageAPI (line 347) | func PackageAPI(c *gin.Context) {
function QuotaAPI (line 360) | func QuotaAPI(c *gin.Context) {
function SubscriptionAPI (line 373) | func SubscriptionAPI(c *gin.Context) {
function SubscribeAPI (line 409) | func SubscribeAPI(c *gin.Context) {
function BuyAPI (line 447) | func BuyAPI(c *gin.Context) {
function InviteAPI (line 485) | func InviteAPI(c *gin.Context) {
function RedeemAPI (line 518) | func RedeemAPI(c *gin.Context) {
FILE: auth/invitation.go
type Invitation (line 11) | type Invitation struct
method IsUsed (line 68) | func (i *Invitation) IsUsed() bool {
method Use (line 72) | func (i *Invitation) Use(db *sql.DB, userId int64) error {
method GetQuota (line 79) | func (i *Invitation) GetQuota() float32 {
method UseInvitation (line 83) | func (i *Invitation) UseInvitation(db *sql.DB, user User) error {
function GenerateInvitations (line 20) | func GenerateInvitations(db *sql.DB, num int, quota float32, t string) (...
function CreateInvitationCode (line 39) | func CreateInvitationCode(db *sql.DB, code string, quota float32, t stri...
function GetInvitation (line 47) | func GetInvitation(db *sql.DB, code string) (*Invitation, error) {
method UseInvitation (line 104) | func (u *User) UseInvitation(db *sql.DB, code string) (float32, error) {
FILE: auth/package.go
type GiftResponse (line 8) | type GiftResponse struct
method HasPackage (line 13) | func (u *User) HasPackage(db *sql.DB, _t string) bool {
method HasCertPackage (line 22) | func (u *User) HasCertPackage(db *sql.DB) bool {
method HasTeenagerPackage (line 26) | func (u *User) HasTeenagerPackage(db *sql.DB) bool {
function NewPackage (line 30) | func NewPackage(db *sql.DB, user *User, _t string) bool {
function NewCertPackage (line 46) | func NewCertPackage(db *sql.DB, user *User) bool {
function NewTeenagerPackage (line 55) | func NewTeenagerPackage(db *sql.DB, user *User) bool {
function RefreshPackage (line 64) | func RefreshPackage(db *sql.DB, user *User) *GiftResponse {
FILE: auth/payment.go
type BalanceResponse (line 12) | type BalanceResponse struct
type PaymentResponse (line 17) | type PaymentResponse struct
function GenerateOrder (line 22) | func GenerateOrder() string {
function GetBalance (line 26) | func GetBalance(username string) float32 {
function Pay (line 51) | func Pay(username string, amount float32) bool {
method Pay (line 77) | func (u *User) Pay(db *sql.DB, cache *redis.Client, amount float32) bool {
function BuyQuota (line 89) | func BuyQuota(db *sql.DB, cache *redis.Client, user *User, quota int) er...
FILE: auth/quota.go
method CreateInitialQuota (line 9) | func (u *User) CreateInitialQuota(db *sql.DB) bool {
method GetQuota (line 16) | func (u *User) GetQuota(db *sql.DB) float32 {
method GetUsedQuota (line 24) | func (u *User) GetUsedQuota(db *sql.DB) float32 {
method SetQuota (line 32) | func (u *User) SetQuota(db *sql.DB, quota float32) bool {
method SetUsedQuota (line 39) | func (u *User) SetUsedQuota(db *sql.DB, used float32) bool {
method IncreaseQuota (line 46) | func (u *User) IncreaseQuota(db *sql.DB, quota float32) bool {
method IncreaseUsedQuota (line 53) | func (u *User) IncreaseUsedQuota(db *sql.DB, used float32) bool {
method DecreaseQuota (line 60) | func (u *User) DecreaseQuota(db *sql.DB, quota float32) bool {
method UseQuota (line 67) | func (u *User) UseQuota(db *sql.DB, quota float32) bool {
method PayedQuota (line 77) | func (u *User) PayedQuota(db *sql.DB, quota float32) bool {
method PayedQuotaAsAmount (line 93) | func (u *User) PayedQuotaAsAmount(db *sql.DB, amount float32) bool {
FILE: auth/redeem.go
type Redeem (line 12) | type Redeem struct
method IsUsed (line 61) | func (r *Redeem) IsUsed() bool {
method Use (line 65) | func (r *Redeem) Use(db *sql.DB) error {
method GetQuota (line 72) | func (r *Redeem) GetQuota() float32 {
method UseRedeem (line 76) | func (r *Redeem) UseRedeem(db *sql.DB, user *User) error {
function GenerateRedeemCodes (line 19) | func GenerateRedeemCodes(db *sql.DB, num int, quota float32) ([]string, ...
function CreateRedeemCode (line 37) | func CreateRedeemCode(db *sql.DB, code string, quota float32) error {
function GetRedeemCode (line 44) | func GetRedeemCode(db *sql.DB, code string) (*Redeem, error) {
method UseRedeem (line 97) | func (u *User) UseRedeem(db *sql.DB, cache *redis.Client, code string) (...
FILE: auth/router.go
function Register (line 5) | func Register(app *gin.RouterGroup) {
FILE: auth/rule.go
constant ErrNotAuthenticated (line 15) | ErrNotAuthenticated = "not authenticated error (model: %s)"
constant ErrNotSetPrice (line 16) | ErrNotSetPrice = "the price of the model is not set (model: %s)"
constant ErrNotEnoughQuota (line 17) | ErrNotEnoughQuota = "user quota is not enough error (model: %s, minimu...
constant ErrEstimatedCost (line 18) | ErrEstimatedCost = "estimated cost exceeds user quota (model: %s, est...
function CanEnableModel (line 22) | func CanEnableModel(db *sql.DB, user *User, model string, messages []glo...
function CanEnableModelWithSubscription (line 58) | func CanEnableModelWithSubscription(db *sql.DB, cache *redis.Client, use...
FILE: auth/struct.go
type User (line 10) | type User struct
method IsBanned (line 62) | func (u *User) IsBanned(db *sql.DB) bool {
method IsAdmin (line 76) | func (u *User) IsAdmin(db *sql.DB) bool {
method GetID (line 90) | func (u *User) GetID(db *sql.DB) int64 {
method HitID (line 100) | func (u *User) HitID() int64 {
method GetEmail (line 104) | func (u *User) GetEmail(db *sql.DB) string {
method GetUserInfo (line 118) | func (u *User) GetUserInfo(db *sql.DB) (*UserInfo, error) {
type UserInfo (line 23) | type UserInfo struct
function GetUserById (line 31) | func GetUserById(db *sql.DB, id int64) *User {
function GetUserByName (line 39) | func GetUserByName(db *sql.DB, username string) *User {
function GetUserByEmail (line 47) | func GetUserByEmail(db *sql.DB, email string) *User {
function GetId (line 55) | func GetId(db *sql.DB, user *User) int64 {
function IsUserExist (line 153) | func IsUserExist(db *sql.DB, username string) bool {
function IsEmailExist (line 161) | func IsEmailExist(db *sql.DB, email string) bool {
function getMaxBindId (line 169) | func getMaxBindId(db *sql.DB) int64 {
function GetGroup (line 177) | func GetGroup(db *sql.DB, user *User) string {
function HitGroup (line 197) | func HitGroup(db *sql.DB, user *User, group string) bool {
function GetUsernameString (line 205) | func GetUsernameString(db *sql.DB, user *User) string {
function HitGroups (line 213) | func HitGroups(db *sql.DB, user *User, groups []string) bool {
FILE: auth/subscription.go
function disableSubscription (line 15) | func disableSubscription() bool {
method GetSubscription (line 19) | func (u *User) GetSubscription(db *sql.DB) (time.Time, int) {
method GetSubscriptionLevel (line 38) | func (u *User) GetSubscriptionLevel(db *sql.DB) int {
method GetPlan (line 46) | func (u *User) GetPlan(db *sql.DB) channel.Plan {
method GetSubscriptionExpiredAt (line 50) | func (u *User) GetSubscriptionExpiredAt(db *sql.DB) time.Time {
method GetSubscriptionTime (line 55) | func (u *User) GetSubscriptionTime(db *sql.DB) time.Time {
method IsSubscribe (line 60) | func (u *User) IsSubscribe(db *sql.DB) bool {
method IsEnterprise (line 65) | func (u *User) IsEnterprise(db *sql.DB) bool {
method GetSubscriptionExpiredDay (line 78) | func (u *User) GetSubscriptionExpiredDay(db *sql.DB) int {
method AddSubscription (line 83) | func (u *User) AddSubscription(db *sql.DB, month int, level int) bool {
method DowngradePlan (line 97) | func (u *User) DowngradePlan(db *sql.DB, target int) error {
method CountUpgradePrice (line 115) | func (u *User) CountUpgradePrice(db *sql.DB, target int) float32 {
method SetSubscriptionLevel (line 126) | func (u *User) SetSubscriptionLevel(db *sql.DB, level int) bool {
function CountSubscriptionPrize (line 131) | func CountSubscriptionPrize(level int, month int) float32 {
function BuySubscription (line 144) | func BuySubscription(db *sql.DB, cache *redis.Client, user *User, level ...
function HandleSubscriptionUsage (line 188) | func HandleSubscriptionUsage(db *sql.DB, cache *redis.Client, user *User...
function RevertSubscriptionUsage (line 196) | func RevertSubscriptionUsage(db *sql.DB, cache *redis.Client, user *User...
FILE: auth/usage.go
method GetSubscriptionUsage (line 12) | func (u *User) GetSubscriptionUsage(db *sql.DB, cache *redis.Client) cha...
method GetSubscriptionRefreshAt (line 17) | func (u *User) GetSubscriptionRefreshAt(db *sql.DB, cache *redis.Client)...
method GetSubscriptionRefreshDay (line 38) | func (u *User) GetSubscriptionRefreshDay(db *sql.DB, cache *redis.Client...
FILE: auth/validators.go
function isInRange (line 8) | func isInRange(content string, min, max int) bool {
function validateUsername (line 13) | func validateUsername(username string) bool {
function validateUsernameOrEmail (line 17) | func validateUsernameOrEmail(username string) bool {
function validatePassword (line 21) | func validatePassword(password string) bool {
function validateEmail (line 25) | func validateEmail(email string) bool {
function validateCode (line 34) | func validateCode(code string) bool {
FILE: channel/channel.go
method GetId (line 19) | func (c *Channel) GetId() int {
method GetName (line 23) | func (c *Channel) GetName() string {
method GetType (line 27) | func (c *Channel) GetType() string {
method GetPriority (line 31) | func (c *Channel) GetPriority() int {
method GetWeight (line 35) | func (c *Channel) GetWeight() int {
method GetModels (line 42) | func (c *Channel) GetModels() []string {
method GetRetry (line 46) | func (c *Channel) GetRetry() int {
method GetSecret (line 53) | func (c *Channel) GetSecret() string {
method GetCurrentSecret (line 57) | func (c *Channel) GetCurrentSecret() *string {
method GetRandomSecret (line 62) | func (c *Channel) GetRandomSecret() string {
method GetCurrentSecretValue (line 75) | func (c *Channel) GetCurrentSecretValue() string {
method SplitRandomSecret (line 83) | func (c *Channel) SplitRandomSecret(num int) []string {
method GetEndpoint (line 99) | func (c *Channel) GetEndpoint() string {
method GetDomain (line 103) | func (c *Channel) GetDomain() string {
method GetMapper (line 111) | func (c *Channel) GetMapper() string {
method Load (line 115) | func (c *Channel) Load() {
method GetReflect (line 156) | func (c *Channel) GetReflect() map[string]string {
method GetExcludeModels (line 160) | func (c *Channel) GetExcludeModels() []string {
method GetModelReflect (line 165) | func (c *Channel) GetModelReflect(model string) string {
method GetHitModels (line 174) | func (c *Channel) GetHitModels() []string {
method GetState (line 178) | func (c *Channel) GetState() bool {
method GetGroup (line 182) | func (c *Channel) GetGroup() []string {
method GetProxy (line 186) | func (c *Channel) GetProxy() globals.ProxyConfig {
method IsHitGroup (line 190) | func (c *Channel) IsHitGroup(group string) bool {
method IsHit (line 198) | func (c *Channel) IsHit(model string) bool {
method ProcessError (line 202) | func (c *Channel) ProcessError(err error) error {
FILE: channel/charge.go
function NewChargeManager (line 10) | func NewChargeManager() *ChargeManager {
method Load (line 26) | func (m *ChargeManager) Load() {
method GetModels (line 59) | func (m *ChargeManager) GetModels() map[string]*Charge {
method GetNonBillingModels (line 63) | func (m *ChargeManager) GetNonBillingModels() []string {
method IsBilling (line 67) | func (m *ChargeManager) IsBilling(model string) bool {
method GetCharge (line 71) | func (m *ChargeManager) GetCharge(model string) *Charge {
method SaveConfig (line 82) | func (m *ChargeManager) SaveConfig() error {
method GetMaxId (line 86) | func (m *ChargeManager) GetMaxId() int {
method AddRawRule (line 96) | func (m *ChargeManager) AddRawRule(charge *Charge) {
method AddRule (line 101) | func (m *ChargeManager) AddRule(charge Charge) error {
method UpdateRawRule (line 106) | func (m *ChargeManager) UpdateRawRule(charge *Charge) {
method UpdateRule (line 115) | func (m *ChargeManager) UpdateRule(charge Charge) error {
method SetRawRule (line 120) | func (m *ChargeManager) SetRawRule(charge *Charge) {
method SetRule (line 128) | func (m *ChargeManager) SetRule(charge Charge) error {
method DeleteRawRule (line 133) | func (m *ChargeManager) DeleteRawRule(id int) {
method DeleteRule (line 142) | func (m *ChargeManager) DeleteRule(id int) error {
method SyncRules (line 147) | func (m *ChargeManager) SyncRules(charge ChargeSequence, overwrite bool)...
method SyncRule (line 155) | func (m *ChargeManager) SyncRule(charge *Charge, overwrite bool) {
method SyncRuleWithOverwrite (line 163) | func (m *ChargeManager) SyncRuleWithOverwrite(charge *Charge) {
method SyncRuleWithoutOverwrite (line 190) | func (m *ChargeManager) SyncRuleWithoutOverwrite(charge *Charge) {
method ListRules (line 201) | func (m *ChargeManager) ListRules() ChargeSequence {
method Contains (line 205) | func (m *ChargeManager) Contains(model string) bool {
method GetRule (line 214) | func (m *ChargeManager) GetRule(id int) *Charge {
method GetRuleByModel (line 223) | func (m *ChargeManager) GetRuleByModel(model string) *Charge {
method IsUnsetType (line 232) | func (c *Charge) IsUnsetType() bool {
method GetType (line 236) | func (c *Charge) GetType() string {
method GetModels (line 243) | func (c *Charge) GetModels() []string {
method GetInput (line 247) | func (c *Charge) GetInput() float32 {
method GetOutput (line 254) | func (c *Charge) GetOutput() float32 {
method SupportAnonymous (line 261) | func (c *Charge) SupportAnonymous() bool {
method IsBilling (line 265) | func (c *Charge) IsBilling() bool {
method IsBillingType (line 269) | func (c *Charge) IsBillingType(t string) bool {
method GetLimit (line 273) | func (c *Charge) GetLimit() float32 {
method Contains (line 287) | func (c *Charge) Contains(model string) bool {
method New (line 291) | func (c *Charge) New(model string) *Charge {
FILE: channel/controller.go
type SyncChargeForm (line 10) | type SyncChargeForm struct
function GetInfo (line 15) | func GetInfo(c *gin.Context) {
function AttachmentService (line 19) | func AttachmentService(c *gin.Context) {
function DeleteChannel (line 25) | func DeleteChannel(c *gin.Context) {
function ActivateChannel (line 35) | func ActivateChannel(c *gin.Context) {
function DeactivateChannel (line 45) | func DeactivateChannel(c *gin.Context) {
function GetChannelList (line 55) | func GetChannelList(c *gin.Context) {
function GetChannel (line 62) | func GetChannel(c *gin.Context) {
function CreateChannel (line 72) | func CreateChannel(c *gin.Context) {
function UpdateChannel (line 89) | func UpdateChannel(c *gin.Context) {
function SetCharge (line 109) | func SetCharge(c *gin.Context) {
function GetChargeList (line 126) | func GetChargeList(c *gin.Context) {
function DeleteCharge (line 133) | func DeleteCharge(c *gin.Context) {
function SyncCharge (line 143) | func SyncCharge(c *gin.Context) {
function GetConfig (line 159) | func GetConfig(c *gin.Context) {
function UpdateConfig (line 166) | func UpdateConfig(c *gin.Context) {
function GetPlanConfig (line 183) | func GetPlanConfig(c *gin.Context) {
function UpdatePlanConfig (line 187) | func UpdatePlanConfig(c *gin.Context) {
FILE: channel/manager.go
function InitManager (line 17) | func InitManager() {
function NewChannelManager (line 24) | func NewChannelManager() *Manager {
method Load (line 42) | func (m *Manager) Load() {
method GetSequence (line 89) | func (m *Manager) GetSequence() Sequence {
method GetActiveSequence (line 93) | func (m *Manager) GetActiveSequence() Sequence {
method GetModels (line 104) | func (m *Manager) GetModels() []string {
method GetPreflightSequence (line 108) | func (m *Manager) GetPreflightSequence() map[string]Sequence {
method HitSequence (line 113) | func (m *Manager) HitSequence(model string) Sequence {
method HasChannel (line 118) | func (m *Manager) HasChannel(model string) bool {
method GetTicker (line 122) | func (m *Manager) GetTicker(model, group string) *Ticker {
method Len (line 130) | func (m *Manager) Len() int {
method GetMaxId (line 134) | func (m *Manager) GetMaxId() int {
method SaveConfig (line 144) | func (m *Manager) SaveConfig() error {
method CreateChannel (line 148) | func (m *Manager) CreateChannel(channel *Channel) error {
method UpdateChannel (line 154) | func (m *Manager) UpdateChannel(id int, channel *Channel) error {
method DeleteChannel (line 164) | func (m *Manager) DeleteChannel(id int) error {
method ActivateChannel (line 174) | func (m *Manager) ActivateChannel(id int) error {
method DeactivateChannel (line 184) | func (m *Manager) DeactivateChannel(id int) error {
FILE: channel/plan.go
type PlanManager (line 16) | type PlanManager struct
method SaveConfig (line 52) | func (c *PlanManager) SaveConfig() error {
method UpdateConfig (line 56) | func (c *PlanManager) UpdateConfig(data *PlanManager) error {
method GetPlan (line 62) | func (c *PlanManager) GetPlan(level int) Plan {
method GetPlans (line 71) | func (c *PlanManager) GetPlans() []Plan {
method GetRawPlans (line 79) | func (c *PlanManager) GetRawPlans() []Plan {
method IsEnabled (line 83) | func (c *PlanManager) IsEnabled() bool {
type Plan (line 21) | type Plan struct
method GetUsage (line 184) | func (p *Plan) GetUsage(user globals.AuthLike, db *sql.DB, cache *redi...
method IncreaseUsage (line 243) | func (p *Plan) IncreaseUsage(user globals.AuthLike, cache *redis.Clien...
method DecreaseUsage (line 253) | func (p *Plan) DecreaseUsage(user globals.AuthLike, cache *redis.Clien...
method ReleaseUsage (line 263) | func (p *Plan) ReleaseUsage(user globals.AuthLike, cache *redis.Client...
method ReleaseAll (line 273) | func (p *Plan) ReleaseAll(user globals.AuthLike, cache *redis.Client) ...
type PlanItem (line 27) | type PlanItem struct
method GetUsage (line 190) | func (p *PlanItem) GetUsage(user globals.AuthLike, db *sql.DB, cache *...
method ResetUsage (line 197) | func (p *PlanItem) ResetUsage(user globals.AuthLike, cache *redis.Clie...
method CreateUsage (line 205) | func (p *PlanItem) CreateUsage(user globals.AuthLike, cache *redis.Cli...
method GetUsageForm (line 212) | func (p *PlanItem) GetUsageForm(user globals.AuthLike, db *sql.DB, cac...
method IsInfinity (line 219) | func (p *PlanItem) IsInfinity() bool {
method IsExceeded (line 223) | func (p *PlanItem) IsExceeded(user globals.AuthLike, db *sql.DB, cache...
method Increase (line 227) | func (p *PlanItem) Increase(user globals.AuthLike, cache *redis.Client...
method Decrease (line 232) | func (p *PlanItem) Decrease(user globals.AuthLike, cache *redis.Client...
method Release (line 239) | func (p *PlanItem) Release(user globals.AuthLike, cache *redis.Client)...
type Usage (line 35) | type Usage struct
type UsageMap (line 39) | type UsageMap
function NewPlanManager (line 43) | func NewPlanManager() *PlanManager {
function getOffsetFormat (line 87) | func getOffsetFormat(offset time.Time, usage int64) string {
function GetSubscriptionUsage (line 91) | func GetSubscriptionUsage(cache *redis.Client, user globals.AuthLike, t ...
function IncreaseSubscriptionUsage (line 147) | func IncreaseSubscriptionUsage(cache *redis.Client, user globals.AuthLik...
function DecreaseSubscriptionUsage (line 161) | func DecreaseSubscriptionUsage(cache *redis.Client, user globals.AuthLik...
function ReleaseSubscriptionUsage (line 175) | func ReleaseSubscriptionUsage(cache *redis.Client, user globals.AuthLike...
function IsValidPlan (line 283) | func IsValidPlan(level int) bool {
FILE: channel/router.go
function Register (line 5) | func Register(app *gin.RouterGroup) {
FILE: channel/sequence.go
method Len (line 5) | func (s *Sequence) Len() int {
method Less (line 9) | func (s *Sequence) Less(i, j int) bool {
method Swap (line 13) | func (s *Sequence) Swap(i, j int) {
method GetChannelById (line 17) | func (s *Sequence) GetChannelById(id int) *Channel {
method Sort (line 26) | func (s *Sequence) Sort() {
FILE: channel/system.go
type ApiInfo (line 12) | type ApiInfo struct
type generalState (line 28) | type generalState struct
type siteState (line 38) | type siteState struct
type whiteList (line 50) | type whiteList struct
type mailState (line 56) | type mailState struct
type SearchState (line 66) | type SearchState struct
type commonState (line 75) | type commonState struct
type SystemConfig (line 85) | type SystemConfig struct
method Load (line 103) | func (c *SystemConfig) Load() {
method SaveConfig (line 132) | func (c *SystemConfig) SaveConfig() error {
method AsInfo (line 136) | func (c *SystemConfig) AsInfo() ApiInfo {
method UpdateConfig (line 154) | func (c *SystemConfig) UpdateConfig(data *SystemConfig) error {
method GetInitialQuota (line 167) | func (c *SystemConfig) GetInitialQuota() float64 {
method GetBackend (line 171) | func (c *SystemConfig) GetBackend() string {
method GetMail (line 175) | func (c *SystemConfig) GetMail() *utils.SmtpPoster {
method IsMailValid (line 186) | func (c *SystemConfig) IsMailValid() bool {
method GetMailSuffix (line 190) | func (c *SystemConfig) GetMailSuffix() []string {
method IsValidMailSuffix (line 198) | func (c *SystemConfig) IsValidMailSuffix(suffix string) bool {
method IsValidMail (line 206) | func (c *SystemConfig) IsValidMail(email string) error {
method SendVerifyMail (line 219) | func (c *SystemConfig) SendVerifyMail(email string, code string) error {
method GetSearchCropLength (line 234) | func (c *SystemConfig) GetSearchCropLength() int {
method GetSearchEngines (line 242) | func (c *SystemConfig) GetSearchEngines() string {
method GetImageProxy (line 246) | func (c *SystemConfig) GetImageProxy() string {
method GetAppName (line 255) | func (c *SystemConfig) GetAppName() string {
method GetAppLogo (line 264) | func (c *SystemConfig) GetAppLogo() string {
method GetCacheAcceptedModels (line 273) | func (c *SystemConfig) GetCacheAcceptedModels() []string {
method GetCacheAcceptedExpire (line 277) | func (c *SystemConfig) GetCacheAcceptedExpire() int64 {
method GetCacheAcceptedSize (line 286) | func (c *SystemConfig) GetCacheAcceptedSize() int64 {
method AcceptImageStore (line 294) | func (c *SystemConfig) AcceptImageStore() bool {
method SupportRelayPlan (line 303) | func (c *SystemConfig) SupportRelayPlan() bool {
function NewSystemConfig (line 93) | func NewSystemConfig() *SystemConfig {
FILE: channel/ticker.go
function NewTicker (line 5) | func NewTicker(seq Sequence, group string) *Ticker {
method GetChannelByPriority (line 20) | func (t *Ticker) GetChannelByPriority(priority int) *Channel {
method Next (line 65) | func (t *Ticker) Next() *Channel {
method SkipPriority (line 78) | func (t *Ticker) SkipPriority(priority int) {
method IsDone (line 90) | func (t *Ticker) IsDone() bool {
method IsEmpty (line 94) | func (t *Ticker) IsEmpty() bool {
FILE: channel/types.go
type Channel (line 7) | type Channel struct
type Sequence (line 27) | type Sequence
type Manager (line 29) | type Manager struct
type Ticker (line 35) | type Ticker struct
type Charge (line 40) | type Charge struct
type ChargeSequence (line 50) | type ChargeSequence
type ChargeManager (line 52) | type ChargeManager struct
FILE: channel/worker.go
function NewChatRequest (line 14) | func NewChatRequest(group string, props *adaptercommon.ChatProps, hook g...
function PreflightCache (line 41) | func PreflightCache(cache *redis.Client, model string, hash string, buff...
function StoreCache (line 75) | func StoreCache(cache *redis.Client, hash string, index int64, buffer *u...
function NewChatRequestWithCache (line 83) | func NewChatRequestWithCache(cache *redis.Client, buffer *utils.Buffer, ...
function NewVideoRequestWithCache (line 103) | func NewVideoRequestWithCache(_ *redis.Client, buffer *utils.Buffer, gro...
FILE: cli/admin.go
function UpdateRootCommand (line 9) | func UpdateRootCommand(args []string) {
FILE: cli/exec.go
function Run (line 3) | func Run() bool {
FILE: cli/help.go
function Help (line 13) | func Help() {
FILE: cli/invite.go
function CreateInvitationCommand (line 10) | func CreateInvitationCommand(args []string) {
FILE: cli/parser.go
function GetArgs (line 10) | func GetArgs() []string {
function GetArg (line 14) | func GetArg(args []string, idx int) string {
function GetArgInt (line 21) | func GetArgInt(args []string, idx int) int {
function GetArgFloat (line 29) | func GetArgFloat(args []string, idx int, bitSize int) float64 {
function GetArgFloat32 (line 37) | func GetArgFloat32(args []string, idx int) float32 {
function GetArgFloat64 (line 41) | func GetArgFloat64(args []string, idx int) float64 {
function GetArgBool (line 45) | func GetArgBool(args []string, idx int) bool {
function GetArgInt64 (line 53) | func GetArgInt64(args []string, idx int) int64 {
function GetArgString (line 61) | func GetArgString(args []string, idx int) string {
function outputError (line 65) | func outputError(err error) {
function outputInfo (line 69) | func outputInfo(t, msg string) {
FILE: cli/token.go
function CreateTokenCommand (line 10) | func CreateTokenCommand(args []string) {
FILE: connection/cache.go
function InitRedisSafe (line 13) | func InitRedisSafe() *redis.Client {
function ConnectRedis (line 21) | func ConnectRedis() *redis.Client {
FILE: connection/database.go
function InitMySQLSafe (line 18) | func InitMySQLSafe() *sql.DB {
function getConn (line 26) | func getConn() *sql.DB {
function ConnectDatabase (line 76) | func ConnectDatabase() *sql.DB {
function InitRootUser (line 103) | func InitRootUser(db *sql.DB) {
function CreateUserTable (line 126) | func CreateUserTable(db *sql.DB) {
function CreatePackageTable (line 146) | func CreatePackageTable(db *sql.DB) {
function CreateQuotaTable (line 162) | func CreateQuotaTable(db *sql.DB) {
function CreateConversationTable (line 179) | func CreateConversationTable(db *sql.DB) {
function CreateMaskTable (line 198) | func CreateMaskTable(db *sql.DB) {
function CreateSharingTable (line 217) | func CreateSharingTable(db *sql.DB) {
function CreateSubscriptionTable (line 235) | func CreateSubscriptionTable(db *sql.DB) {
function CreateApiKeyTable (line 254) | func CreateApiKeyTable(db *sql.DB) {
function CreateInvitationTable (line 269) | func CreateInvitationTable(db *sql.DB) {
function CreateRedeemTable (line 289) | func CreateRedeemTable(db *sql.DB) {
function CreateBroadcastTable (line 305) | func CreateBroadcastTable(db *sql.DB) {
FILE: connection/db_migration.go
function validSqlError (line 9) | func validSqlError(err error) bool {
function checkSqlError (line 22) | func checkSqlError(_ sql.Result, err error) error {
function execSql (line 30) | func execSql(db *sql.DB, sql string, args ...interface{}) error {
function doMigration (line 34) | func doMigration(db *sql.DB) error {
function doSqliteMigration (line 71) | func doSqliteMigration(db *sql.DB) error {
FILE: connection/worker.go
function MysqlWorker (line 11) | func MysqlWorker(db *sql.DB) {
function pingRedis (line 23) | func pingRedis(client *redis.Client) error {
function RedisWorker (line 30) | func RedisWorker(cache *redis.Client) {
FILE: globals/constant.go
constant System (line 4) | System = "system"
constant User (line 5) | User = "user"
constant Assistant (line 6) | Assistant = "assistant"
constant Tool (line 7) | Tool = "tool"
constant Function (line 8) | Function = "function"
constant OpenAIChannelType (line 12) | OpenAIChannelType = "openai"
constant AzureOpenAIChannelType (line 13) | AzureOpenAIChannelType = "azure"
constant ClaudeChannelType (line 14) | ClaudeChannelType = "claude"
constant SlackChannelType (line 15) | SlackChannelType = "slack"
constant SparkdeskChannelType (line 16) | SparkdeskChannelType = "sparkdesk"
constant ChatGLMChannelType (line 17) | ChatGLMChannelType = "chatglm"
constant HunyuanChannelType (line 18) | HunyuanChannelType = "hunyuan"
constant QwenChannelType (line 19) | QwenChannelType = "qwen"
constant ZhinaoChannelType (line 20) | ZhinaoChannelType = "zhinao"
constant BaichuanChannelType (line 21) | BaichuanChannelType = "baichuan"
constant SkylarkChannelType (line 22) | SkylarkChannelType = "skylark"
constant BingChannelType (line 23) | BingChannelType = "bing"
constant PalmChannelType (line 24) | PalmChannelType = "palm"
constant MidjourneyChannelType (line 25) | MidjourneyChannelType = "midjourney"
constant MoonshotChannelType (line 26) | MoonshotChannelType = "moonshot"
constant GroqChannelType (line 27) | GroqChannelType = "groq"
constant DeepseekChannelType (line 28) | DeepseekChannelType = "deepseek"
constant DifyChannelType (line 29) | DifyChannelType = "dify"
constant CozeChannelType (line 30) | CozeChannelType = "coze"
constant NonBilling (line 34) | NonBilling = "non-billing"
constant TimesBilling (line 35) | TimesBilling = "times-billing"
constant TokenBilling (line 36) | TokenBilling = "token-billing"
constant AnonymousType (line 40) | AnonymousType = "anonymous"
constant NormalType (line 41) | NormalType = "normal"
constant BasicType (line 42) | BasicType = "basic"
constant StandardType (line 43) | StandardType = "standard"
constant ProType (line 44) | ProType = "pro"
constant AdminType (line 45) | AdminType = "admin"
constant NoneProxyType (line 49) | NoneProxyType = iota
constant HttpProxyType (line 50) | HttpProxyType
constant HttpsProxyType (line 51) | HttpsProxyType
constant Socks5ProxyType (line 52) | Socks5ProxyType
constant WebTokenType (line 56) | WebTokenType = "web"
constant ApiTokenType (line 57) | ApiTokenType = "api"
constant SystemToken (line 58) | SystemToken = "system"
FILE: globals/interface.go
type ChannelConfig (line 5) | type ChannelConfig interface
type AuthLike (line 17) | type AuthLike interface
FILE: globals/logger.go
constant DefaultLoggerFile (line 12) | DefaultLoggerFile = "chatnio.log"
type AppLogger (line 16) | type AppLogger struct
method Format (line 20) | func (l *AppLogger) Format(entry *logrus.Entry) ([]byte, error) {
function init (line 35) | func init() {
function Output (line 51) | func Output(args ...interface{}) {
function Debug (line 55) | func Debug(args ...interface{}) {
function Info (line 59) | func Info(args ...interface{}) {
function Warn (line 63) | func Warn(args ...interface{}) {
function Error (line 67) | func Error(args ...interface{}) {
function Fatal (line 71) | func Fatal(args ...interface{}) {
function Panic (line 75) | func Panic(args ...interface{}) {
FILE: globals/method.go
method IsEmpty (line 3) | func (c *Chunk) IsEmpty() bool {
FILE: globals/sql.go
type batch (line 11) | type batch struct
function batchReplace (line 17) | func batchReplace(sql string, batch []batch) string {
function PreflightSql (line 29) | func PreflightSql(sql string) string {
function ExecDb (line 85) | func ExecDb(db *sql.DB, sql string, args ...interface{}) (sql.Result, er...
function PrepareDb (line 90) | func PrepareDb(db *sql.DB, sql string) (*sql.Stmt, error) {
function QueryDb (line 95) | func QueryDb(db *sql.DB, sql string, args ...interface{}) (*sql.Rows, er...
function QueryRowDb (line 100) | func QueryRowDb(db *sql.DB, sql string, args ...interface{}) *sql.Row {
FILE: globals/tools.go
type FunctionTools (line 3) | type FunctionTools
type ToolObject (line 4) | type ToolObject struct
type ToolFunction (line 9) | type ToolFunction struct
type ToolParameters (line 16) | type ToolParameters struct
type ToolProperties (line 22) | type ToolProperties
type JsonSchemaType (line 26) | type JsonSchemaType
type JSONSchemaDefinition (line 27) | type JSONSchemaDefinition
type ToolProperty (line 28) | type ToolProperty
type DetailToolProperty (line 29) | type DetailToolProperty struct
type ToolCallFunction (line 77) | type ToolCallFunction struct
type ToolCall (line 82) | type ToolCall struct
type ToolCalls (line 88) | type ToolCalls
type FunctionCall (line 90) | type FunctionCall struct
FILE: globals/types.go
type Hook (line 3) | type Hook
type Message (line 5) | type Message struct
type Chunk (line 15) | type Chunk struct
type ChatSegmentResponse (line 21) | type ChatSegmentResponse struct
type GenerationSegmentResponse (line 30) | type GenerationSegmentResponse struct
type ListModels (line 38) | type ListModels struct
type ListModelsItem (line 43) | type ListModelsItem struct
type ProxyConfig (line 50) | type ProxyConfig struct
FILE: globals/usage.go
function GetSubscriptionLimitFormat (line 7) | func GetSubscriptionLimitFormat(t string, id int64) string {
FILE: globals/variables.go
constant ChatMaxThread (line 11) | ChatMaxThread = 5
constant AnonymousMaxThread (line 12) | AnonymousMaxThread = 1
function OriginIsAllowed (line 37) | func OriginIsAllowed(uri string) bool {
function OriginIsOpen (line 59) | func OriginIsOpen(c *gin.Context) bool {
constant GPT3Turbo (line 64) | GPT3Turbo = "gpt-3.5-turbo"
constant GPT3TurboInstruct (line 65) | GPT3TurboInstruct = "gpt-3.5-turbo-instruct"
constant GPT3Turbo0613 (line 66) | GPT3Turbo0613 = "gpt-3.5-turbo-0613"
constant GPT3Turbo0301 (line 67) | GPT3Turbo0301 = "gpt-3.5-turbo-0301"
constant GPT3Turbo1106 (line 68) | GPT3Turbo1106 = "gpt-3.5-turbo-1106"
constant GPT3Turbo0125 (line 69) | GPT3Turbo0125 = "gpt-3.5-turbo-0125"
constant GPT3Turbo16k (line 70) | GPT3Turbo16k = "gpt-3.5-turbo-16k"
constant GPT3Turbo16k0613 (line 71) | GPT3Turbo16k0613 = "gpt-3.5-turbo-16k-0613"
constant GPT3Turbo16k0301 (line 72) | GPT3Turbo16k0301 = "gpt-3.5-turbo-16k-0301"
constant GPT4 (line 73) | GPT4 = "gpt-4"
constant GPT4All (line 74) | GPT4All = "gpt-4-all"
constant GPT4Vision (line 75) | GPT4Vision = "gpt-4-v"
constant GPT4Dalle (line 76) | GPT4Dalle = "gpt-4-dalle"
constant GPT40314 (line 77) | GPT40314 = "gpt-4-0314"
constant GPT40613 (line 78) | GPT40613 = "gpt-4-0613"
constant GPT41106Preview (line 79) | GPT41106Preview = "gpt-4-1106-preview"
constant GPT40125Preview (line 80) | GPT40125Preview = "gpt-4-0125-preview"
constant GPT4TurboPreview (line 81) | GPT4TurboPreview = "gpt-4-turbo-preview"
constant GPT4VisionPreview (line 82) | GPT4VisionPreview = "gpt-4-vision-preview"
constant GPT4Turbo (line 83) | GPT4Turbo = "gpt-4-turbo"
constant GPT4Turbo20240409 (line 84) | GPT4Turbo20240409 = "gpt-4-turbo-2024-04-09"
constant GPT41106VisionPreview (line 85) | GPT41106VisionPreview = "gpt-4-1106-vision-preview"
constant GPT432k (line 86) | GPT432k = "gpt-4-32k"
constant GPT432k0314 (line 87) | GPT432k0314 = "gpt-4-32k-0314"
constant GPT432k0613 (line 88) | GPT432k0613 = "gpt-4-32k-0613"
constant GPT4O (line 89) | GPT4O = "gpt-4o"
constant GPT4O20240513 (line 90) | GPT4O20240513 = "gpt-4o-2024-05-13"
constant GPTImage1 (line 91) | GPTImage1 = "gpt-image-1"
constant Sora2 (line 92) | Sora2 = "sora-2"
constant Dalle (line 93) | Dalle = "dalle"
constant Dalle2 (line 94) | Dalle2 = "dall-e-2"
constant Dalle3 (line 95) | Dalle3 = "dall-e-3"
constant Claude1 (line 96) | Claude1 = "claude-1"
constant Claude1100k (line 97) | Claude1100k = "claude-1.3"
constant Claude2 (line 98) | Claude2 = "claude-1-100k"
constant Claude2100k (line 99) | Claude2100k = "claude-2"
constant Claude2200k (line 100) | Claude2200k = "claude-2.1"
constant Claude3 (line 101) | Claude3 = "claude-3"
constant ClaudeSlack (line 102) | ClaudeSlack = "claude-slack"
constant SparkDeskLite (line 103) | SparkDeskLite = "spark-desk-lite"
constant SparkDeskPro (line 104) | SparkDeskPro = "spark-desk-pro"
constant SparkDeskPro128K (line 105) | SparkDeskPro128K = "spark-desk-pro-128k"
constant SparkDeskMax (line 106) | SparkDeskMax = "spark-desk-max"
constant SparkDeskMax32K (line 107) | SparkDeskMax32K = "spark-desk-max-32k"
constant SparkDeskV4Ultra (line 108) | SparkDeskV4Ultra = "spark-desk-4.0-ultra"
constant ChatBison001 (line 109) | ChatBison001 = "chat-bison-001"
constant GeminiPro (line 110) | GeminiPro = "gemini-pro"
constant GeminiProVision (line 111) | GeminiProVision = "gemini-pro-vision"
constant Gemini15ProLatest (line 112) | Gemini15ProLatest = "gemini-1.5-pro-latest"
constant Gemini15FlashLatest (line 113) | Gemini15FlashLatest = "gemini-1.5-flash-latest"
constant Gemini20ProExp (line 114) | Gemini20ProExp = "gemini-2.0-pro-exp-02-05"
constant Gemini20Flash (line 115) | Gemini20Flash = "gemini-2.0-flash"
constant Gemini20FlashExp (line 116) | Gemini20FlashExp = "gemini-2.0-flash-exp"
constant Gemini20Flash001 (line 117) | Gemini20Flash001 = "gemini-2.0-flash-001"
constant Gemini20FlashThinkingExp (line 118) | Gemini20FlashThinkingExp = "gemini-2.0-flash-thinking-exp-01-21"
constant Gemini20FlashLitePreview (line 119) | Gemini20FlashLitePreview = "gemini-2.0-flash-lite-preview-02-05"
constant Gemini20FlashThinkingExp1219 (line 120) | Gemini20FlashThinkingExp1219 = "gemini-2.0-flash-thinking-exp-1219"
constant GeminiExp1206 (line 121) | GeminiExp1206 = "gemini-exp-1206"
constant GoogleImagen002 (line 122) | GoogleImagen002 = "imagen-3.0-generate-002"
constant BingCreative (line 123) | BingCreative = "bing-creative"
constant BingBalanced (line 124) | BingBalanced = "bing-balanced"
constant BingPrecise (line 125) | BingPrecise = "bing-precise"
constant ZhiPuChatGLM4 (line 126) | ZhiPuChatGLM4 = "glm-4"
constant ZhiPuChatGLM4Vision (line 127) | ZhiPuChatGLM4Vision = "glm-4v"
constant ZhiPuChatGLM3Turbo (line 128) | ZhiPuChatGLM3Turbo = "glm-3-turbo"
constant ZhiPuChatGLMTurbo (line 129) | ZhiPuChatGLMTurbo = "zhipu-chatglm-turbo"
constant ZhiPuChatGLMPro (line 130) | ZhiPuChatGLMPro = "zhipu-chatglm-pro"
constant ZhiPuChatGLMStd (line 131) | ZhiPuChatGLMStd = "zhipu-chatglm-std"
constant ZhiPuChatGLMLite (line 132) | ZhiPuChatGLMLite = "zhipu-chatglm-lite"
constant QwenTurbo (line 133) | QwenTurbo = "qwen-turbo"
constant QwenPlus (line 134) | QwenPlus = "qwen-plus"
constant QwenTurboNet (line 135) | QwenTurboNet = "qwen-turbo-net"
constant QwenPlusNet (line 136) | QwenPlusNet = "qwen-plus-net"
constant Midjourney (line 137) | Midjourney = "midjourney"
constant MidjourneyFast (line 138) | MidjourneyFast = "midjourney-fast"
constant MidjourneyTurbo (line 139) | MidjourneyTurbo = "midjourney-turbo"
constant Hunyuan (line 140) | Hunyuan = "hunyuan"
constant GPT360V9 (line 141) | GPT360V9 = "360-gpt-v9"
constant Baichuan53B (line 142) | Baichuan53B = "baichuan-53b"
constant SkylarkLite (line 143) | SkylarkLite = "skylark-lite-public"
constant SkylarkPlus (line 144) | SkylarkPlus = "skylark-plus-public"
constant SkylarkPro (line 145) | SkylarkPro = "skylark-pro-public"
constant SkylarkChat (line 146) | SkylarkChat = "skylark-chat"
constant DeepseekV3 (line 147) | DeepseekV3 = "deepseek-chat"
constant DeepseekR1 (line 148) | DeepseekR1 = "deepseek-reasoner"
function in (line 174) | func in(value string, slice []string) bool {
function IsOpenAIDalleModel (line 183) | func IsOpenAIDalleModel(model string) bool {
function IsGoogleImagenModel (line 188) | func IsGoogleImagenModel(model string) bool {
function IsVisionModel (line 193) | func IsVisionModel(model string) bool {
function IsVideoModel (line 197) | func IsVideoModel(model string) bool {
FILE: main.go
function readCorsOrigins (line 21) | func readCorsOrigins() {
function registerApiRouter (line 37) | func registerApiRouter(engine *gin.Engine) {
function main (line 55) | func main() {
FILE: manager/broadcast/controller.go
function ViewBroadcastAPI (line 9) | func ViewBroadcastAPI(c *gin.Context) {
function CreateBroadcastAPI (line 13) | func CreateBroadcastAPI(c *gin.Context) {
function GetBroadcastListAPI (line 41) | func GetBroadcastListAPI(c *gin.Context) {
FILE: manager/broadcast/manage.go
function createBroadcast (line 11) | func createBroadcast(c *gin.Context, user *auth.User, content string) er...
function getBroadcastList (line 24) | func getBroadcastList(c *gin.Context) ([]Info, error) {
FILE: manager/broadcast/router.go
function Register (line 5) | func Register(app *gin.RouterGroup) {
FILE: manager/broadcast/types.go
type Broadcast (line 3) | type Broadcast struct
type Info (line 8) | type Info struct
type listResponse (line 15) | type listResponse struct
type createRequest (line 19) | type createRequest struct
type createResponse (line 23) | type createResponse struct
FILE: manager/broadcast/view.go
function getLatestBroadcast (line 11) | func getLatestBroadcast(c *gin.Context) *Broadcast {
FILE: manager/chat.go
constant defaultMessage (line 25) | defaultMessage = "empty response"
constant interruptMessage (line 26) | interruptMessage = "interrupted"
function CollectQuota (line 28) | func CollectQuota(c *gin.Context, user *auth.User, buffer *utils.Buffer,...
type partialChunk (line 45) | type partialChunk struct
function createStopSignal (line 52) | func createStopSignal(conn *Connection) chan bool {
function createChatTask (line 80) | func createChatTask(
function ChatHandler (line 250) | func ChatHandler(conn *Connection, user *auth.User, instance *conversati...
FILE: manager/chat_completions.go
constant ReasonStop (line 23) | ReasonStop = "stop"
constant ReasonToolCalls (line 24) | ReasonToolCalls = "tool_calls"
function supportRelayPlan (line 27) | func supportRelayPlan() bool {
function checkEnableState (line 31) | func checkEnableState(db *sql.DB, cache *redis.Client, user *auth.User, ...
function ChatRelayAPI (line 39) | func ChatRelayAPI(c *gin.Context) {
function getChatProps (line 96) | func getChatProps(form RelayForm, messages []globals.Message, buffer *ut...
function sendTranshipmentResponse (line 112) | func sendTranshipmentResponse(c *gin.Context, form RelayForm, messages [...
function getFinishReason (line 163) | func getFinishReason(buffer *utils.Buffer, end bool) interface{} {
function getRole (line 175) | func getRole(data *globals.Chunk) string {
function getStreamTranshipmentForm (line 187) | func getStreamTranshipmentForm(id string, created int64, form RelayForm,...
function sendStreamTranshipmentResponse (line 215) | func sendStreamTranshipmentResponse(c *gin.Context, form RelayForm, mess...
FILE: manager/completions.go
function NativeChatHandler (line 17) | func NativeChatHandler(c *gin.Context, user *auth.User, model string, me...
FILE: manager/connection.go
constant ChatType (line 14) | ChatType = "chat"
constant StopType (line 15) | StopType = "stop"
constant RestartType (line 16) | RestartType = "restart"
constant ShareType (line 17) | ShareType = "share"
constant MaskType (line 18) | MaskType = "mask"
constant EditType (line 19) | EditType = "edit"
constant RemoveType (line 20) | RemoveType = "remove"
type Stack (line 23) | type Stack
type Connection (line 25) | type Connection struct
method GetConn (line 41) | func (c *Connection) GetConn() *utils.WebSocket {
method GetCtx (line 45) | func (c *Connection) GetCtx() *gin.Context {
method GetStack (line 49) | func (c *Connection) GetStack() Stack {
method ReadWorker (line 53) | func (c *Connection) ReadWorker() {
method Write (line 74) | func (c *Connection) Write(data *conversation.FormMessage) {
method IsClosed (line 81) | func (c *Connection) IsClosed() bool {
method Stop (line 85) | func (c *Connection) Stop() {
method Read (line 89) | func (c *Connection) Read() *conversation.FormMessage {
method Peek (line 94) | func (c *Connection) Peek() *conversation.FormMessage {
method PeekWithType (line 104) | func (c *Connection) PeekWithType(t string) *conversation.FormMessage {
method PeekWithTypes (line 117) | func (c *Connection) PeekWithTypes(types ...string) *conversation.Form...
method PeekStop (line 132) | func (c *Connection) PeekStop() *conversation.FormMessage {
method Skip (line 136) | func (c *Connection) Skip() {
method GetDB (line 140) | func (c *Connection) GetDB() *sql.DB {
method GetCache (line 144) | func (c *Connection) GetCache() *redis.Client {
method Send (line 148) | func (c *Connection) Send(message globals.ChatSegmentResponse) {
method SendClient (line 152) | func (c *Connection) SendClient(message globals.ChatSegmentResponse) e...
method Process (line 156) | func (c *Connection) Process(handler func(*conversation.FormMessage) e...
method Handle (line 168) | func (c *Connection) Handle(handler func(*conversation.FormMessage) er...
method Lock (line 173) | func (c *Connection) Lock() bool {
method Release (line 192) | func (c *Connection) Release() {
function NewConnection (line 32) | func NewConnection(conn *utils.WebSocket, auth bool, hash string, buffer...
FILE: manager/conversation/api.go
type ShareForm (line 12) | type ShareForm struct
type RenameConversationForm (line 17) | type RenameConversationForm struct
type DeleteMaskForm (line 22) | type DeleteMaskForm struct
type LoadMaskResponse (line 26) | type LoadMaskResponse struct
type CommonMaskResponse (line 32) | type CommonMaskResponse struct
function ListAPI (line 37) | func ListAPI(c *gin.Context) {
function LoadAPI (line 56) | func LoadAPI(c *gin.Context) {
function DeleteAPI (line 90) | func DeleteAPI(c *gin.Context) {
function RenameAPI (line 124) | func RenameAPI(c *gin.Context) {
function CleanAPI (line 159) | func CleanAPI(c *gin.Context) {
function ShareAPI (line 184) | func ShareAPI(c *gin.Context) {
function ViewAPI (line 219) | func ViewAPI(c *gin.Context) {
function ListSharingAPI (line 246) | func ListSharingAPI(c *gin.Context) {
function DeleteSharingAPI (line 265) | func DeleteSharingAPI(c *gin.Context) {
function LoadMaskAPI (line 299) | func LoadMaskAPI(c *gin.Context) {
function DeleteMaskAPI (line 330) | func DeleteMaskAPI(c *gin.Context) {
function SaveMaskAPI (line 373) | func SaveMaskAPI(c *gin.Context) {
FILE: manager/conversation/conversation.go
constant defaultConversationName (line 12) | defaultConversationName = "new chat"
constant defaultConversationContext (line 13) | defaultConversationContext = 8
type Conversation (line 15) | type Conversation struct
method GetModel (line 101) | func (c *Conversation) GetModel() string {
method IsEnableWeb (line 108) | func (c *Conversation) IsEnableWeb() bool {
method GetContextLength (line 112) | func (c *Conversation) GetContextLength() int {
method SetModel (line 120) | func (c *Conversation) SetModel(model string) {
method SetEnableWeb (line 127) | func (c *Conversation) SetEnableWeb(enable bool) {
method GetTemperature (line 131) | func (c *Conversation) GetTemperature() *float32 {
method SetTemperature (line 135) | func (c *Conversation) SetTemperature(temperature *float32) {
method GetTopP (line 139) | func (c *Conversation) GetTopP() *float32 {
method SetTopP (line 143) | func (c *Conversation) SetTopP(topP *float32) {
method GetTopK (line 147) | func (c *Conversation) GetTopK() *int {
method SetTopK (line 151) | func (c *Conversation) SetTopK(topK *int) {
method GetPresencePenalty (line 155) | func (c *Conversation) GetPresencePenalty() *float32 {
method SetPresencePenalty (line 159) | func (c *Conversation) SetPresencePenalty(presencePenalty *float32) {
method GetFrequencyPenalty (line 163) | func (c *Conversation) GetFrequencyPenalty() *float32 {
method SetFrequencyPenalty (line 167) | func (c *Conversation) SetFrequencyPenalty(frequencyPenalty *float32) {
method GetRepetitionPenalty (line 171) | func (c *Conversation) GetRepetitionPenalty() *float32 {
method SetRepetitionPenalty (line 175) | func (c *Conversation) SetRepetitionPenalty(repetitionPenalty *float32) {
method GetMaxTokens (line 179) | func (c *Conversation) GetMaxTokens() *int {
method SetMaxTokens (line 183) | func (c *Conversation) SetMaxTokens(maxTokens *int) {
method SetContextLength (line 187) | func (c *Conversation) SetContextLength(context int, ignore bool) {
method GetName (line 197) | func (c *Conversation) GetName() string {
method SetName (line 201) | func (c *Conversation) SetName(db *sql.DB, name string) {
method GetId (line 206) | func (c *Conversation) GetId() int64 {
method GetUserID (line 210) | func (c *Conversation) GetUserID() int64 {
method SetId (line 214) | func (c *Conversation) SetId(id int64) {
method GetMessage (line 218) | func (c *Conversation) GetMessage() []globals.Message {
method GetMessageById (line 222) | func (c *Conversation) GetMessageById(id int) globals.Message {
method GetMessageLength (line 226) | func (c *Conversation) GetMessageLength() int {
method GetMessageSegment (line 230) | func (c *Conversation) GetMessageSegment(length int) []globals.Message {
method GetChatMessage (line 237) | func (c *Conversation) GetChatMessage(restart bool) []globals.Message {
method GetLastMessage (line 266) | func (c *Conversation) GetLastMessage() globals.Message {
method AddMessage (line 270) | func (c *Conversation) AddMessage(message globals.Message) {
method AddMessages (line 274) | func (c *Conversation) AddMessages(messages []globals.Message) {
method InsertMessage (line 278) | func (c *Conversation) InsertMessage(message globals.Message, index in...
method InsertMessages (line 282) | func (c *Conversation) InsertMessages(messages []globals.Message, inde...
method AddMessageFromUser (line 286) | func (c *Conversation) AddMessageFromUser(message string) {
method AddMessageFromAssistant (line 293) | func (c *Conversation) AddMessageFromAssistant(message string) {
method AddMessageFromSystem (line 300) | func (c *Conversation) AddMessageFromSystem(message string) {
method ApplyParam (line 319) | func (c *Conversation) ApplyParam(form *FormMessage) {
method AddMessageFromByte (line 333) | func (c *Conversation) AddMessageFromByte(data []byte) (string, error) {
method AddMessageFromForm (line 347) | func (c *Conversation) AddMessageFromForm(form *FormMessage) error {
method HandleMessage (line 358) | func (c *Conversation) HandleMessage(db *sql.DB, form *FormMessage) bo...
method HandleMessageFromByte (line 370) | func (c *Conversation) HandleMessageFromByte(db *sql.DB, data []byte) ...
method GetLatestMessage (line 383) | func (c *Conversation) GetLatestMessage() string {
method SaveResponse (line 387) | func (c *Conversation) SaveResponse(db *sql.DB, message string) {
method RemoveMessage (line 392) | func (c *Conversation) RemoveMessage(index int) globals.Message {
method RemoveLatestMessage (line 401) | func (c *Conversation) RemoveLatestMessage() globals.Message {
method RemoveLatestMessageWithRole (line 405) | func (c *Conversation) RemoveLatestMessageWithRole(role string) global...
method EditMessage (line 418) | func (c *Conversation) EditMessage(index int, message string) {
method DeleteMessage (line 425) | func (c *Conversation) DeleteMessage(index int) {
method GetTaskID (line 432) | func (c *Conversation) GetTaskID() string {
method SetTaskID (line 436) | func (c *Conversation) SetTaskID(taskID string) {
type FormMessage (line 36) | type FormMessage struct
function NewAnonymousConversation (line 54) | func NewAnonymousConversation() *Conversation {
function NewConversation (line 66) | func NewConversation(db *sql.DB, id int64) *Conversation {
function ExtractConversation (line 77) | func ExtractConversation(db *sql.DB, user *auth.User, id int64, ref stri...
function CopyMessage (line 262) | func CopyMessage(message []globals.Message) []globals.Message {
function GetMessage (line 307) | func GetMessage(data []byte) (string, error) {
FILE: manager/conversation/mask.go
type Mask (line 10) | type Mask struct
method Save (line 25) | func (m *Mask) Save(db *sql.DB, user *auth.User) error {
method Delete (line 43) | func (m *Mask) Delete(db *sql.DB, user *auth.User) error {
method LoadMask (line 18) | func (c *Conversation) LoadMask(data string) {
function LoadMask (line 48) | func LoadMask(db *sql.DB, user *auth.User) ([]Mask, error) {
FILE: manager/conversation/router.go
function Register (line 5) | func Register(app *gin.RouterGroup) {
FILE: manager/conversation/shared.go
type SharedPreviewForm (line 13) | type SharedPreviewForm struct
type SharedForm (line 20) | type SharedForm struct
type SharedHashForm (line 28) | type SharedHashForm struct
function GetRef (line 34) | func GetRef(refs []int) (result string) {
function ShareConversation (line 41) | func ShareConversation(db *sql.DB, user *auth.User, id int64, refs []int...
function GetSharedMessages (line 63) | func GetSharedMessages(db *sql.DB, userId int64, conversationId int64, r...
function ListSharedConversation (line 84) | func ListSharedConversation(db *sql.DB, user *auth.User) []SharedPreview...
function DeleteSharedConversation (line 118) | func DeleteSharedConversation(db *sql.DB, user *auth.User, hash string) ...
function GetSharedConversation (line 132) | func GetSharedConversation(db *sql.DB, hash string) (*SharedForm, error) {
function UseSharedConversation (line 158) | func UseSharedConversation(db *sql.DB, user *auth.User, hash string) *Co...
method LoadSharing (line 188) | func (c *Conversation) LoadSharing(db *sql.DB, hash string) {
FILE: manager/conversation/storage.go
method SaveConversation (line 11) | func (c *Conversation) SaveConversation(db *sql.DB) bool {
function GetConversationLengthByUserID (line 46) | func GetConversationLengthByUserID(db *sql.DB, userId int64) int64 {
function LoadConversation (line 55) | func LoadConversation(db *sql.DB, userId int64, conversationId int64) *C...
function LoadConversationList (line 92) | func LoadConversationList(db *sql.DB, userId int64) []Conversation {
method DeleteConversation (line 120) | func (c *Conversation) DeleteConversation(db *sql.DB) bool {
method RenameConversation (line 128) | func (c *Conversation) RenameConversation(db *sql.DB, name string) bool {
function DeleteAllConversations (line 136) | func DeleteAllConversations(db *sql.DB, user auth.User) error {
FILE: manager/images.go
function ImagesRelayAPI (line 18) | func ImagesRelayAPI(c *gin.Context) {
function getImageProps (line 66) | func getImageProps(form RelayImageForm, messages []globals.Message, buff...
function getImageDataFromBuffer (line 74) | func getImageDataFromBuffer(buffer *utils.Buffer) (string, string) {
function createRelayImageObject (line 90) | func createRelayImageObject(c *gin.Context, form RelayImageForm, prompt ...
FILE: manager/manager.go
type WebsocketAuthForm (line 13) | type WebsocketAuthForm struct
function ParseAuth (line 19) | func ParseAuth(c *gin.
Condensed preview — 535 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,491K chars).
[
{
"path": ".dockerignore",
"chars": 476,
"preview": "app/node_modules\napp/src-tauri\napp/.idea\napp/.vscode\napp/dist\napp/dev-dist\napp/dist-ssr\napp/target\napp/tauri.conf.json\na"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 459,
"preview": "---\nname: 报告问题 | Bug Report\nabout: 使用简练详细的语言描述你遇到的问题 | Describe the issue you encountered in detail\ntitle: ''\nlabels: bu"
},
{
"path": ".github/ISSUE_TEMPLATE/channel_update.md",
"chars": 527,
"preview": "---\nname: 渠道更新 | Channel Update\nabout: 新大模型供应商格式增加、更新请求 | Request to add or update a new llm provider format\ntitle: ''\nl"
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 135,
"preview": "blank_issues_enabled: false\ncontact_links:\n - name: Discord\n url: https://discord.gg/rpzNSmqaF2\n about: Join Disc"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 442,
"preview": "---\nname: 功能请求 | Feature Request\nabout: 使用简练详细的语言描述希望加入的新功能 | Describe the feature you would like to request\ntitle: ''\nl"
},
{
"path": ".github/workflows/app.yaml",
"chars": 3202,
"preview": "name: Release App\n\non:\n workflow_dispatch:\n release:\n types: [published]\n\njobs:\n create-release:\n permissions:\n"
},
{
"path": ".github/workflows/build.yaml",
"chars": 851,
"preview": "name: Build Test\non:\n push:\n branches:\n - '*'\n pull_request:\n branches:\n - '*'\njobs:\n release:\n ru"
},
{
"path": ".github/workflows/docker-cd.yaml",
"chars": 682,
"preview": "name: Docker CD\n\non:\n release:\n types: [created]\n\njobs:\n\n deploy:\n\n runs-on: ubuntu-latest\n\n steps:\n - u"
},
{
"path": ".github/workflows/docker-ci.yaml",
"chars": 1243,
"preview": "name: Docker Image CI\n\non:\n push:\n branches: [main]\n\njobs:\n build:\n runs-on: ubuntu-latest\n\n steps:\n - n"
},
{
"path": ".github/workflows/issue-translator.yaml",
"chars": 358,
"preview": "name: Issue Translator\non: \n issue_comment: \n types: [created]\n issues: \n types: [opened]\n\njobs:\n build:\n ru"
},
{
"path": ".gitignore",
"chars": 372,
"preview": "app/node_modules\n.vscode\n.idea\nconfig.yaml\nconfig.dev.yaml\nstorage\n\naddition/generation/data/*\n!addition/generation/data"
},
{
"path": "Dockerfile",
"chars": 1493,
"preview": "# Author: ProgramZmh\n# License: Apache-2.0\n# Description: Dockerfile for chatnio\n\nFROM --platform=$TARGETPLATFORM golang"
},
{
"path": "LICENSE",
"chars": 11357,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 18222,
"preview": "<div align=\"center\">\n\n\n\n# [🥳 CoAI.Dev](https://coai.dev)\n\n#### 🚀 Next Generation AIGC On"
},
{
"path": "README_ja-JP.md",
"chars": 9905,
"preview": "<div align=\"center\">\n\n\n\n# [🥳 CoAI.Dev](https://coai.dev)\n\n#### 🚀 次世代AIGCワンストップビジネスソリューショ"
},
{
"path": "README_zh-CN.md",
"chars": 13405,
"preview": "<div align=\"center\">\n\n\n\n# [🥳 CoAI.Dev](https://coai.dev)\n\n#### 🚀 下一代 AIGC 一站式商业解决方案\n####"
},
{
"path": "adapter/adapter.go",
"chars": 2930,
"preview": "package adapter\n\nimport (\n\t\"chat/adapter/azure\"\n\t\"chat/adapter/baichuan\"\n\t\"chat/adapter/bing\"\n\t\"chat/adapter/claude\"\n\tad"
},
{
"path": "adapter/azure/chat.go",
"chars": 3418,
"preview": "package azure\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n)"
},
{
"path": "adapter/azure/image.go",
"chars": 2009,
"preview": "package azure\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"fmt\"\n\t\"strings\"\n)\n\ntype Ima"
},
{
"path": "adapter/azure/processor.go",
"chars": 3606,
"preview": "package azure\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n)\n"
},
{
"path": "adapter/azure/struct.go",
"chars": 875,
"preview": "package azure\n\nimport (\n\tfactory \"chat/adapter/common\"\n\t\"chat/globals\"\n)\n\ntype ChatInstance struct {\n\tEndpoint string\n\tA"
},
{
"path": "adapter/azure/types.go",
"chars": 4208,
"preview": "package azure\n\nimport \"chat/globals\"\n\ntype ImageUrl struct {\n\tUrl string `json:\"url\"`\n\tDetail *string `json:\"detail,"
},
{
"path": "adapter/baichuan/chat.go",
"chars": 2332,
"preview": "package baichuan\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"errors\"\n\t\"fmt\"\n)\n\nfunc ("
},
{
"path": "adapter/baichuan/processor.go",
"chars": 1101,
"preview": "package baichuan\n\nimport (\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"errors\"\n\t\"fmt\"\n)\n\nfunc processChatResponse(data string) *Chat"
},
{
"path": "adapter/baichuan/struct.go",
"chars": 755,
"preview": "package baichuan\n\nimport (\n\tfactory \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"fmt\"\n)\n\ntype ChatInstance struct {\n\tEndpoint"
},
{
"path": "adapter/baichuan/types.go",
"chars": 1409,
"preview": "package baichuan\n\nimport \"chat/globals\"\n\n// Baichuan AI API is similar to OpenAI API\n\ntype ChatRequest struct {\n\tModel "
},
{
"path": "adapter/bing/chat.go",
"chars": 979,
"preview": "package bing\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"fmt\"\n\t\"strings\"\n)\n\nfunc (c *"
},
{
"path": "adapter/bing/struct.go",
"chars": 524,
"preview": "package bing\n\nimport (\n\tfactory \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"fmt\"\n)\n\ntype ChatInstance struct {\n\tEndpoint str"
},
{
"path": "adapter/bing/types.go",
"chars": 265,
"preview": "package bing\n\n// see https://github.com/Deeptrain-Community/chatnio-bing-service\n\ntype ChatRequest struct {\n\tPrompt stri"
},
{
"path": "adapter/claude/chat.go",
"chars": 5429,
"preview": "package claude\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"errors\"\n\t\"fmt\"\n)\n\nconst de"
},
{
"path": "adapter/claude/struct.go",
"chars": 559,
"preview": "package claude\n\nimport (\n\tfactory \"chat/adapter/common\"\n\t\"chat/globals\"\n)\n\ntype ChatInstance struct {\n\tEndpoint string\n\t"
},
{
"path": "adapter/claude/types.go",
"chars": 1188,
"preview": "package claude\n\n// ChatBody is the request body for anthropic claude\n\ntype Message struct {\n\tRole string `json:\""
},
{
"path": "adapter/common/interface.go",
"chars": 300,
"preview": "package adaptercommon\n\nimport (\n\t\"chat/globals\"\n)\n\ntype Factory interface {\n\tCreateStreamChatRequest(props *ChatProps, h"
},
{
"path": "adapter/common/types.go",
"chars": 1796,
"preview": "package adaptercommon\n\nimport (\n\t\"chat/globals\"\n\t\"chat/utils\"\n)\n\ntype RequestProps struct {\n\tMaxRetries *int "
},
{
"path": "adapter/coze/chat.go",
"chars": 4534,
"preview": "package coze\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"f"
},
{
"path": "adapter/coze/processor.go",
"chars": 4087,
"preview": "package coze\n\nimport (\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nfunc processChatResponse("
},
{
"path": "adapter/coze/struct.go",
"chars": 3244,
"preview": "package coze\n\ntype ChatRequest struct {\n\tBotID string `json:\"bot_id\"`\n\tUserID string"
},
{
"path": "adapter/dashscope/chat.go",
"chars": 3572,
"preview": "package dashscope\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"fmt\"\n\t\"strings\"\n)\n\ncons"
},
{
"path": "adapter/dashscope/struct.go",
"chars": 569,
"preview": "package dashscope\n\nimport (\n\tfactory \"chat/adapter/common\"\n\t\"chat/globals\"\n)\n\ntype ChatInstance struct {\n\tEndpoint strin"
},
{
"path": "adapter/dashscope/types.go",
"chars": 1178,
"preview": "package dashscope\n\n// ChatRequest is the request body for dashscope\ntype ChatRequest struct {\n\tModel string `jso"
},
{
"path": "adapter/deepseek/chat.go",
"chars": 4758,
"preview": "package deepseek\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"errors\"\n\t\"fmt\"\n)\n\ntype C"
},
{
"path": "adapter/deepseek/struct.go",
"chars": 1773,
"preview": "package deepseek\n\nimport (\n\t\"chat/globals\"\n)\n\n// DeepSeek API is similar to OpenAI API with additional reasoning content"
},
{
"path": "adapter/dify/chat.go",
"chars": 3520,
"preview": "package dify\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"f"
},
{
"path": "adapter/dify/processor.go",
"chars": 1840,
"preview": "package dify\n\nimport (\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"errors\"\n\t\"fmt\"\n)\n\nfunc processChatResponse(data string) *ChatResp"
},
{
"path": "adapter/dify/struct.go",
"chars": 2711,
"preview": "package dify\n\ntype ChatRequest struct {\n\tInputs map[string]interface{} `json:\"inputs\"`\n\tQuery strin"
},
{
"path": "adapter/hunyuan/chat.go",
"chars": 1508,
"preview": "package hunyuan\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"context\"\n\t\"fmt\"\n)\n\nfunc (c *ChatInstanc"
},
{
"path": "adapter/hunyuan/sdk.go",
"chars": 7910,
"preview": "package hunyuan\n\n/*\n * Copyright (c) 2017-2018 THL A29 Limited, a Tencent company. All Rights Reserved.\n *\n * Licensed u"
},
{
"path": "adapter/hunyuan/struct.go",
"chars": 878,
"preview": "package hunyuan\n\nimport (\n\tfactory \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n)\n\ntype ChatInstance struct {\n\tEn"
},
{
"path": "adapter/midjourney/api.go",
"chars": 1502,
"preview": "package midjourney\n\nimport (\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"fmt\"\n)\n\nfunc (c *ChatInstance) GetImagineEndpoint() string "
},
{
"path": "adapter/midjourney/chat.go",
"chars": 4042,
"preview": "package midjourney\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"fmt\"\n\t\"strings\"\n)\n\ncon"
},
{
"path": "adapter/midjourney/expose.go",
"chars": 1414,
"preview": "package midjourney\n\nimport (\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"fmt\"\n\t\"github.com/gin-gonic/gin\"\n\t\"net/http\"\n\t\"strings\"\n)\n\n"
},
{
"path": "adapter/midjourney/handler.go",
"chars": 3513,
"preview": "package midjourney\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time"
},
{
"path": "adapter/midjourney/storage.go",
"chars": 418,
"preview": "package midjourney\n\nimport (\n\t\"chat/connection\"\n\t\"chat/utils\"\n\t\"fmt\"\n)\n\nfunc getTaskName(task string) string {\n\treturn f"
},
{
"path": "adapter/midjourney/struct.go",
"chars": 1128,
"preview": "package midjourney\n\nimport (\n\tfactory \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"fmt\"\n)\n\nvar midjourneyEmptySecret = \"null\""
},
{
"path": "adapter/midjourney/types.go",
"chars": 1763,
"preview": "package midjourney\n\nconst (\n\tSuccessCode = 1\n\tExistedCode = 21\n\tQueueCode = 22\n\tMaxQueueCode = 23\n\tNudeCode = 2"
},
{
"path": "adapter/openai/chat.go",
"chars": 4095,
"preview": "package openai\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\t"
},
{
"path": "adapter/openai/image.go",
"chars": 1911,
"preview": "package openai\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"fmt\"\n\t\"strings\"\n)\n\ntype Im"
},
{
"path": "adapter/openai/processor.go",
"chars": 3597,
"preview": "package openai\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n)"
},
{
"path": "adapter/openai/struct.go",
"chars": 753,
"preview": "package openai\n\nimport (\n\tfactory \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"fmt\"\n)\n\ntype ChatInstance struct {\n\tEndpoint s"
},
{
"path": "adapter/openai/types.go",
"chars": 4022,
"preview": "package openai\n\nimport \"chat/globals\"\n\ntype ImageUrl struct {\n\tUrl string `json:\"url\"`\n\tDetail *string `json:\"detail"
},
{
"path": "adapter/openai/videos.go",
"chars": 3798,
"preview": "package openai\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"fmt\"\n\t\"time\"\n)\n\ntype Video"
},
{
"path": "adapter/palm2/chat.go",
"chars": 5766,
"preview": "package palm2\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n)"
},
{
"path": "adapter/palm2/formatter.go",
"chars": 2450,
"preview": "package palm2\n\nimport (\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"strings\"\n)\n\nfunc getGeminiRole(role string) string {\n\tswitch rol"
},
{
"path": "adapter/palm2/image.go",
"chars": 1942,
"preview": "package palm2\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"fmt\"\n\t\"strings\"\n)\n\ntype Ima"
},
{
"path": "adapter/palm2/struct.go",
"chars": 565,
"preview": "package palm2\n\nimport (\n\tfactory \"chat/adapter/common\"\n\t\"chat/globals\"\n)\n\ntype ChatInstance struct {\n\tEndpoint string\n\tA"
},
{
"path": "adapter/palm2/types.go",
"chars": 2663,
"preview": "package palm2\n\nconst (\n\tGeminiUserType = \"user\"\n\tGeminiModelType = \"model\"\n)\n\ntype PalmMessage struct {\n\tAuthor string"
},
{
"path": "adapter/request.go",
"chars": 2791,
"preview": "package adapter\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n)"
},
{
"path": "adapter/router.go",
"chars": 170,
"preview": "package adapter\n\nimport (\n\t\"chat/adapter/midjourney\"\n\t\"github.com/gin-gonic/gin\"\n)\n\nfunc Register(app *gin.RouterGroup) "
},
{
"path": "adapter/skylark/chat.go",
"chars": 4561,
"preview": "package skylark\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\n\t\""
},
{
"path": "adapter/skylark/formatter.go",
"chars": 1974,
"preview": "package skylark\n\nimport (\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"github.com/volcengine/volcengine-go-sdk/service/arkruntime/mod"
},
{
"path": "adapter/skylark/struct.go",
"chars": 736,
"preview": "package skylark\n\nimport (\n\tfactory \"chat/adapter/common\"\n\t\"chat/globals\"\n\n\t\"github.com/volcengine/volcengine-go-sdk/serv"
},
{
"path": "adapter/slack/chat.go",
"chars": 448,
"preview": "package slack\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"context\"\n)\n\nfunc (c *ChatInstance) Create"
},
{
"path": "adapter/slack/struct.go",
"chars": 1755,
"preview": "package slack\n\nimport (\n\tfactory \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"fmt\"\n\t\"github.com/bincooo/claude-api\"\n\t\"github."
},
{
"path": "adapter/sparkdesk/chat.go",
"chars": 3852,
"preview": "package sparkdesk\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"fmt\"\n\t\"strings\"\n)\n\nvar "
},
{
"path": "adapter/sparkdesk/struct.go",
"chars": 2325,
"preview": "package sparkdesk\n\nimport (\n\tfactory \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"crypto/hmac\"\n\t\"crypto/sha256\"\n\t\"encoding/ba"
},
{
"path": "adapter/sparkdesk/types.go",
"chars": 1835,
"preview": "package sparkdesk\n\nimport \"chat/globals\"\n\n// ChatRequest is the request body for sparkdesk\ntype ChatRequest struct {\n\tHe"
},
{
"path": "adapter/zhinao/chat.go",
"chars": 2578,
"preview": "package zhinao\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"fmt\"\n\t\"strings\"\n)\n\nfunc (c"
},
{
"path": "adapter/zhinao/processor.go",
"chars": 2180,
"preview": "package zhinao\n\nimport (\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n)\n\nfunc processFormat(data string) st"
},
{
"path": "adapter/zhinao/struct.go",
"chars": 753,
"preview": "package zhinao\n\nimport (\n\tfactory \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"fmt\"\n)\n\ntype ChatInstance struct {\n\tEndpoint s"
},
{
"path": "adapter/zhinao/types.go",
"chars": 1591,
"preview": "package zhinao\n\nimport \"chat/globals\"\n\n// 360 ZhiNao API is similar to OpenAI API\n\n// ChatRequest is the request body fo"
},
{
"path": "adapter/zhipuai/chat.go",
"chars": 3798,
"preview": "package zhipuai\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n"
},
{
"path": "adapter/zhipuai/processor.go",
"chars": 3724,
"preview": "package zhipuai\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n"
},
{
"path": "adapter/zhipuai/struct.go",
"chars": 1540,
"preview": "package zhipuai\n\nimport (\n\tfactory \"chat/adapter/common\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"gith"
},
{
"path": "adapter/zhipuai/types.go",
"chars": 4020,
"preview": "package zhipuai\n\nimport \"chat/globals\"\n\nconst (\n\tGLM4 = \"glm-4\"\n\tGLM4Vision = \"glm-4v\"\n\tGLMTurbo = \"glm-3-turbo\""
},
{
"path": "addition/article/api.go",
"chars": 1648,
"preview": "package article\n\nimport (\n\t\"chat/auth\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"fmt\"\n\t\"github.com/gin-gonic/gin\"\n\t\"strings\"\n)\n\nty"
},
{
"path": "addition/article/data/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "addition/article/generate.go",
"chars": 2304,
"preview": "package article\n\nimport (\n\t\"chat/auth\"\n\t\"chat/globals\"\n\t\"chat/manager\"\n\t\"chat/utils\"\n\t\"fmt\"\n\t\"github.com/gin-gonic/gin\"\n"
},
{
"path": "addition/article/utils.go",
"chars": 818,
"preview": "package article\n\nimport (\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"fmt\"\n\t\"github.com/lukasjarosch/go-docx\"\n)\n\nfunc GenerateDocxFi"
},
{
"path": "addition/card/.gitignore",
"chars": 14,
"preview": ".idea\n.vscode\n"
},
{
"path": "addition/card/card.go",
"chars": 1668,
"preview": "package card\n\nimport (\n\t\"chat/globals\"\n\t\"chat/manager\"\n\t\"github.com/gin-gonic/gin\"\n\t\"github.com/russross/blackfriday/v2\""
},
{
"path": "addition/card/card.php",
"chars": 5593,
"preview": "<?php\ninclude 'utils.php';\n\n$dark = get('theme', 'light') === 'dark';\n$message = get('message', 'hi');\n$web = get('web',"
},
{
"path": "addition/card/error.php",
"chars": 1552,
"preview": "<?php\ninclude_once 'utils.php';\n$dark = isset($_GET['theme']) && $_GET['theme'] === 'dark';\n\n$header = $dark ? \"#fff\" : "
},
{
"path": "addition/card/utils.php",
"chars": 929,
"preview": "<?php\nheader('Content-Type: image/svg+xml');\nheader('Cache-Control: no-cache');\n\nfunction compress($buffer): array|strin"
},
{
"path": "addition/generation/api.go",
"chars": 2340,
"preview": "package generation\n\nimport (\n\t\"chat/auth\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/gin-gonic/gin\"\n)"
},
{
"path": "addition/generation/build.go",
"chars": 741,
"preview": "package generation\n\nimport (\n\t\"chat/utils\"\n\t\"fmt\"\n\t\"time\"\n)\n\nfunc GetFolder(hash string) string {\n\treturn fmt.Sprintf(\"s"
},
{
"path": "addition/generation/data/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "addition/generation/generate.go",
"chars": 739,
"preview": "package generation\n\nimport (\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"fmt\"\n)\n\nfunc CreateGenerationWithCache(group, model, prompt"
},
{
"path": "addition/generation/prompt.go",
"chars": 4560,
"preview": "package generation\n\nimport (\n\tadaptercommon \"chat/adapter/common\"\n\t\"chat/admin\"\n\t\"chat/channel\"\n\t\"chat/globals\"\n\t\"chat/u"
},
{
"path": "addition/router.go",
"chars": 600,
"preview": "package addition\n\nimport (\n\t\"chat/addition/article\"\n\t\"chat/addition/card\"\n\t\"chat/addition/generation\"\n\t\"github.com/gin-g"
},
{
"path": "addition/web/call.go",
"chars": 1160,
"preview": "package web\n\nimport (\n\t\"chat/globals\"\n\t\"chat/manager/conversation\"\n\t\"chat/utils\"\n\t\"fmt\"\n\t\"time\"\n)\n\ntype Hook func(messag"
},
{
"path": "addition/web/search.go",
"chars": 3221,
"preview": "package web\n\nimport (\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"git"
},
{
"path": "admin/analysis/analysis.go",
"chars": 4915,
"preview": "package analysis\n\nimport (\n\t\"chat/channel\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"database/sql\"\n\t\"time\"\n\n\t\"github.com/go-redis/"
},
{
"path": "admin/analysis/format.go",
"chars": 1287,
"preview": "package analysis\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\nfunc getMonth() string {\n\tdate := time.Now()\n\treturn date.Format(\"2006-01\")"
},
{
"path": "admin/analysis/reflect.go",
"chars": 279,
"preview": "package analysis\n\nimport \"reflect\"\n\nvar _ = reflect.TypeOf(UserTypeForm{})\nvar _ = reflect.TypeOf(ModelData{})\nvar _ = r"
},
{
"path": "admin/analysis/statistic.go",
"chars": 1683,
"preview": "package analysis\n\nimport (\n\t\"chat/adapter\"\n\t\"chat/connection\"\n\t\"chat/utils\"\n\t\"time\"\n\n\t\"github.com/go-redis/redis/v8\"\n)\n\n"
},
{
"path": "admin/analysis/types.go",
"chars": 487,
"preview": "package analysis\n\ntype ModelData struct {\n\tModel string `json:\"model\"`\n\tData []int64 `json:\"data\"`\n}\n\ntype ModelChartF"
},
{
"path": "admin/controller.go",
"chars": 10192,
"preview": "package admin\n\nimport (\n\t\"chat/admin/analysis\"\n\t\"chat/utils\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gin"
},
{
"path": "admin/format.go",
"chars": 865,
"preview": "package admin\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\nfunc getMonth() string {\n\tdate := time.Now()\n\treturn date.Format(\"2006-01\")\n}\n"
},
{
"path": "admin/instance.go",
"chars": 97,
"preview": "package admin\n\nvar MarketInstance *Market\n\nfunc InitInstance() {\n\tMarketInstance = NewMarket()\n}\n"
},
{
"path": "admin/invitation.go",
"chars": 2661,
"preview": "package admin\n\nimport (\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"database/sql\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"strings\"\n)\n\nfunc GetInv"
},
{
"path": "admin/logger.go",
"chars": 862,
"preview": "package admin\n\nimport (\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"fmt\"\n\t\"github.com/gin-gonic/gin\"\n\t\"strings\"\n)\n\ntype LogFile stru"
},
{
"path": "admin/market.go",
"chars": 1411,
"preview": "package admin\n\nimport (\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"fmt\"\n\n\t\"github.com/spf13/viper\"\n)\n\ntype ModelTag []string\ntype M"
},
{
"path": "admin/redeem.go",
"chars": 2160,
"preview": "package admin\n\nimport (\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"math\"\n\t\"strings\"\n)\n\nfunc GetRedeemData(db"
},
{
"path": "admin/router.go",
"chars": 1612,
"preview": "package admin\n\nimport (\n\t\"chat/addition/web\"\n\t\"chat/channel\"\n\n\t\"github.com/gin-gonic/gin\"\n)\n\nfunc Register(app *gin.Rout"
},
{
"path": "admin/statistic.go",
"chars": 1013,
"preview": "package admin\n\nimport (\n\t\"chat/adapter\"\n\t\"chat/connection\"\n\t\"chat/utils\"\n\t\"time\"\n\n\t\"github.com/go-redis/redis/v8\"\n)\n\nfun"
},
{
"path": "admin/types.go",
"chars": 2314,
"preview": "package admin\n\nvar pagination int64 = 10\n\ntype InfoForm struct {\n\tBillingToday float32 `json:\"billing_today\"`\n\tBill"
},
{
"path": "admin/user.go",
"chars": 6350,
"preview": "package admin\n\nimport (\n\t\"chat/channel\"\n\t\"chat/globals\"\n\t\"chat/utils\"\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"math\"\n\t\"string"
},
{
"path": "app/.eslintrc.cjs",
"chars": 436,
"preview": "module.exports = {\n root: true,\n env: { browser: true, es2020: true },\n extends: [\n 'eslint:recommended',\n 'plu"
},
{
"path": "app/.gitignore",
"chars": 274,
"preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndis"
},
{
"path": "app/.prettierrc.json",
"chars": 3,
"preview": "{}\n"
},
{
"path": "app/components.json",
"chars": 341,
"preview": "{\n \"$schema\": \"https://ui.shadcn.com/schema.json\",\n \"style\": \"default\",\n \"rsc\": false,\n \"tsx\": true,\n \"tailwind\": {"
},
{
"path": "app/index.html",
"chars": 3097,
"preview": "<!doctype html>\n<html>\n <head>\n <meta charset=\"UTF-8\" />\n <link rel=\"icon\" href=\"/favicon.ico\" />\n <meta name="
},
{
"path": "app/package.json",
"chars": 3838,
"preview": "{\n \"name\": \"coai\",\n \"private\": false,\n \"version\": \"2.6.0\",\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vite\",\n "
},
{
"path": "app/postcss.config.js",
"chars": 80,
"preview": "export default {\n plugins: {\n tailwindcss: {},\n autoprefixer: {},\n },\n}\n"
},
{
"path": "app/public/manifest.json",
"chars": 63975,
"preview": "{\n \"_1c.7075dba8.js\": {\n \"file\": \"assets/1c.7075dba8.js\",\n \"imports\": [\n \"index.html\"\n ],\n \"isDynamicE"
},
{
"path": "app/public/robots.txt",
"chars": 41,
"preview": "User-Agent: *\nAllow: /\nDisallow: /admin/\n"
},
{
"path": "app/public/service.js",
"chars": 532,
"preview": "\nconst SERVICE_NAME = \"coai\";\n\nself.addEventListener('activate', function (event) {\n console.debug(\"[service] service w"
},
{
"path": "app/public/site.webmanifest",
"chars": 434,
"preview": "{\n \"name\": \"CoAI\",\n \"short_name\": \"CoAI\",\n \"icons\": [\n {\n \"src\": \"/service/android-chrome-192x192.p"
},
{
"path": "app/public/workbox.js",
"chars": 379,
"preview": "\nif ('serviceWorker' in navigator) {\n window.addEventListener('load', function () {\n navigator.serviceWorker.registe"
},
{
"path": "app/qodana.yaml",
"chars": 988,
"preview": "#-------------------------------------------------------------------------------#\n# Qodana analysis is con"
},
{
"path": "app/src/App.tsx",
"chars": 556,
"preview": "import { Provider } from \"react-redux\";\nimport store from \"./store/index.ts\";\nimport AppProvider from \"./components/app/"
},
{
"path": "app/src/admin/api/channel.ts",
"chars": 2315,
"preview": "import { Channel } from \"@/admin/channel.ts\";\nimport axios from \"axios\";\nimport { getErrorMessage } from \"@/utils/base.t"
},
{
"path": "app/src/admin/api/charge.ts",
"chars": 2039,
"preview": "import { CommonResponse } from \"@/api/common.ts\";\nimport { ChargeProps } from \"@/admin/charge.ts\";\nimport { getErrorMess"
},
{
"path": "app/src/admin/api/chart.ts",
"chars": 7839,
"preview": "import {\n BillingChartResponse,\n CommonResponse,\n ErrorChartResponse,\n InfoResponse,\n InvitationGenerateResponse,\n "
},
{
"path": "app/src/admin/api/info.ts",
"chars": 1820,
"preview": "import axios from \"axios\";\nimport {\n setAppLogo,\n setAppName,\n setBlobEndpoint,\n setBuyLink,\n setDocsUrl,\n} from \"@"
},
{
"path": "app/src/admin/api/logger.ts",
"chars": 1512,
"preview": "import axios from \"axios\";\nimport { CommonResponse } from \"@/api/common.ts\";\nimport { getErrorMessage } from \"@/utils/ba"
},
{
"path": "app/src/admin/api/market.ts",
"chars": 460,
"preview": "import { Model } from \"@/api/types.tsx\";\nimport { CommonResponse } from \"@/api/common.ts\";\nimport axios from \"axios\";\nim"
},
{
"path": "app/src/admin/api/plan.ts",
"chars": 1256,
"preview": "import { Plan } from \"@/api/types.tsx\";\nimport axios from \"axios\";\nimport { CommonResponse } from \"@/api/common.ts\";\nimp"
},
{
"path": "app/src/admin/api/system.ts",
"chars": 10310,
"preview": "import { CommonResponse } from \"@/api/common.ts\";\nimport { getErrorMessage } from \"@/utils/base.ts\";\nimport axios from \""
},
{
"path": "app/src/admin/channel.ts",
"chars": 9951,
"preview": "import { getUniqueList } from \"@/utils/base.ts\";\nimport {\n AnonymousType,\n BasicType,\n NormalType,\n ProType,\n Stand"
},
{
"path": "app/src/admin/charge.ts",
"chars": 496,
"preview": "export const tokenBilling = \"token-billing\";\nexport const timesBilling = \"times-billing\";\nexport const nonBilling = \"non"
},
{
"path": "app/src/admin/colors.ts",
"chars": 2232,
"preview": "export const modelColorMapper: Record<string, string> = {\n // OpenAI & Azure OpenAI\n \"gpt-3.5-turbo\": \"green-500\",\n \""
},
{
"path": "app/src/admin/datasets/charge.ts",
"chars": 6231,
"preview": "import {\n ChargeProps,\n ChargeType,\n timesBilling,\n tokenBilling,\n} from \"@/admin/charge.ts\";\n\nexport enum Currency "
},
{
"path": "app/src/admin/hook.tsx",
"chars": 1515,
"preview": "import { useMemo, useState } from \"react\";\nimport { getUniqueList } from \"@/utils/base.ts\";\nimport { defaultChannelModel"
},
{
"path": "app/src/admin/market.ts",
"chars": 700,
"preview": "export const marketEditableTags = [\n \"official\",\n \"multi-modal\",\n \"web\",\n \"high-quality\",\n \"high-price\",\n \"open-so"
},
{
"path": "app/src/admin/types.ts",
"chars": 2082,
"preview": "export type CommonResponse = {\n status: boolean;\n message: string;\n error?: string;\n};\n\nexport type InfoResponse = {\n"
},
{
"path": "app/src/api/addition.ts",
"chars": 2905,
"preview": "import axios from \"axios\";\nimport { getErrorMessage } from \"@/utils/base.ts\";\n\ntype QuotaResponse = {\n status: boolean;"
},
{
"path": "app/src/api/auth.ts",
"chars": 3416,
"preview": "import axios from \"axios\";\nimport { getErrorMessage } from \"@/utils/base.ts\";\nimport { isEmailValid } from \"@/utils/form"
},
{
"path": "app/src/api/broadcast.ts",
"chars": 2571,
"preview": "import axios from \"axios\";\nimport { getMemory, setMemory } from \"@/utils/memory.ts\";\n\nexport type Broadcast = {\n conten"
},
{
"path": "app/src/api/common.ts",
"chars": 575,
"preview": "import { toast } from \"sonner\";\n\nexport type CommonResponse = {\n status: boolean;\n error?: string;\n reason?: string;\n"
},
{
"path": "app/src/api/connection.ts",
"chars": 8172,
"preview": "import { tokenField, websocketEndpoint } from \"@/conf/bootstrap.ts\";\nimport { getMemory } from \"@/utils/memory.ts\";\nimpo"
},
{
"path": "app/src/api/file.ts",
"chars": 4219,
"preview": "import { blobEndpoint } from \"@/conf/env.ts\";\nimport { trimSuffixes } from \"@/utils/base.ts\";\n\nexport type BlobParserRes"
},
{
"path": "app/src/api/generation.ts",
"chars": 3054,
"preview": "import { tokenField, websocketEndpoint } from \"@/conf/bootstrap.ts\";\nimport { getMemory } from \"@/utils/memory.ts\";\n\nexp"
},
{
"path": "app/src/api/history.ts",
"chars": 4648,
"preview": "import axios from \"axios\";\nimport type { ConversationInstance } from \"./types.tsx\";\nimport { setHistory } from \"@/store/"
},
{
"path": "app/src/api/mask.ts",
"chars": 1120,
"preview": "import { CustomMask } from \"@/masks/types.ts\";\nimport axios from \"axios\";\nimport { CommonResponse } from \"@/api/common.t"
},
{
"path": "app/src/api/plugin.ts",
"chars": 3660,
"preview": "import axios from \"axios\";\nimport { CommonResponse } from \"@/api/common.ts\";\nimport { getErrorMessage } from \"@/utils/ba"
},
{
"path": "app/src/api/quota.ts",
"chars": 277,
"preview": "import axios from \"axios\";\n\nexport async function getQuota(): Promise<number> {\n try {\n const response = await axios"
},
{
"path": "app/src/api/record.ts",
"chars": 1944,
"preview": "import { CommonResponse } from \"@/api/common.ts\";\nimport axios from \"axios\";\n\nexport type Record = {\n username: string;"
},
{
"path": "app/src/api/redeem.ts",
"chars": 500,
"preview": "import axios from \"axios\";\nimport { getErrorMessage } from \"@/utils/base.ts\";\n\nexport type RedeemResponse = {\n status: "
},
{
"path": "app/src/api/sharing.ts",
"chars": 1983,
"preview": "import axios from \"axios\";\nimport { Message } from \"./types.tsx\";\n\nexport type SharingForm = {\n status: boolean;\n mess"
},
{
"path": "app/src/api/types.tsx",
"chars": 2704,
"preview": "import { ChargeBaseProps } from \"@/admin/charge.ts\";\nimport { useMemo } from \"react\";\nimport { BotIcon, ServerIcon, User"
},
{
"path": "app/src/api/v1.ts",
"chars": 6020,
"preview": "import axios from \"axios\";\nimport { Model, Plan } from \"@/api/types.tsx\";\nimport { ChargeProps, nonBilling } from \"@/adm"
},
{
"path": "app/src/assets/admin/all.less",
"chars": 1615,
"preview": "@import \"menu\";\n@import \"dashboard\";\n@import \"market\";\n@import \"management\";\n@import \"broadcast\";\n@import \"channel\";\n@im"
},
{
"path": "app/src/assets/admin/broadcast.less",
"chars": 323,
"preview": ".broadcast {\n width: 100%;\n height: max-content;\n padding: 2rem;\n display: flex;\n flex-direction: column;\n\n .broad"
},
{
"path": "app/src/assets/admin/channel.less",
"chars": 2411,
"preview": ".channel {\n width: 100%;\n height: max-content;\n padding: 2rem;\n display: flex;\n flex-direction: column;\n\n .channel"
},
{
"path": "app/src/assets/admin/charge.less",
"chars": 1196,
"preview": ".charge {\n width: 100%;\n height: max-content;\n padding: 2rem;\n display: flex;\n flex-direction: column;\n\n .charge-c"
},
{
"path": "app/src/assets/admin/dashboard.less",
"chars": 3042,
"preview": ".dashboard {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n padding: 0.5rem 0;\n\n & > * {\n "
},
{
"path": "app/src/assets/admin/logger.less",
"chars": 1896,
"preview": ".logger {\n width: 100%;\n height: max-content;\n padding: 2rem;\n display: flex;\n flex-direction: column;\n\n .logger-c"
},
{
"path": "app/src/assets/admin/management.less",
"chars": 1163,
"preview": ".user-interface {\n position: relative;\n display: flex;\n flex-direction: column;\n width: 100%;\n max-width: 100%;\n h"
},
{
"path": "app/src/assets/admin/market.less",
"chars": 4029,
"preview": ".market {\n width: 100%;\n height: max-content;\n padding: 2rem;\n display: flex;\n flex-direction: column;\n\n .market-c"
},
{
"path": "app/src/assets/admin/menu.less",
"chars": 1970,
"preview": ".admin-menu {\n display: flex;\n flex-shrink: 0;\n flex-direction: column;\n height: 100%;\n padding: 0.75rem;\n margin:"
},
{
"path": "app/src/assets/admin/subscription.less",
"chars": 2855,
"preview": ".admin-subscription {\n width: 100%;\n height: max-content;\n padding: 2rem;\n display: flex;\n flex-direction: column;\n"
},
{
"path": "app/src/assets/admin/system.less",
"chars": 189,
"preview": ".system {\n width: 100%;\n height: max-content;\n padding: 2rem;\n display: flex;\n flex-direction: column;\n\n .system-c"
},
{
"path": "app/src/assets/common/404.less",
"chars": 492,
"preview": ".error-page {\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n height: 100"
},
{
"path": "app/src/assets/common/editor.less",
"chars": 1808,
"preview": ".editor-action {\n position: absolute;\n top: 50%;\n right: 8px;\n transform: translateY(-50%);\n background: hsl(var(--"
},
{
"path": "app/src/assets/common/file.less",
"chars": 2126,
"preview": ".file-action {\n position: absolute;\n top: 50%;\n left: 8px;\n transform: translateY(-50%);\n background: hsl(var(--inp"
},
{
"path": "app/src/assets/common/loader.less",
"chars": 1516,
"preview": ".loader-wrapper {\n position: absolute;\n display: flex;\n flex-direction: column;\n align-items: center;\n vertical-ali"
},
{
"path": "app/src/assets/common/plugin.less",
"chars": 13419,
"preview": ".plugin-dialog {\n max-width: min(95vw, 1024px) !important;\n width: 100%;\n height: auto;\n max-height: 90vh;\n}\n\n.plugi"
},
{
"path": "app/src/assets/fonts/all.less",
"chars": 34,
"preview": "@import \"common\";\n@import \"katex\";"
},
{
"path": "app/src/assets/fonts/common.less",
"chars": 85,
"preview": "\n@import '@fontsource-variable/inter';\n@import '@fontsource-variable/jetbrains-mono';"
},
{
"path": "app/src/assets/fonts/katex.less",
"chars": 29461,
"preview": "/* stylelint-disable font-family-no-missing-generic-family-keyword */\n@font-face {\n font-family: 'KaTeX_AMS';\n src: ur"
},
{
"path": "app/src/assets/globals.less",
"chars": 3877,
"preview": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n@import 'normalize.css';\n\n@layer base {\n :root {\n --back"
},
{
"path": "app/src/assets/main.less",
"chars": 5637,
"preview": "@import \"ui\";\n@font-family: \"HarmonyOS Sans\",\"Inter Variable\",ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,\""
},
{
"path": "app/src/assets/markdown/all.less",
"chars": 2768,
"preview": "@import \"highlight.less\";\n@import \"style.less\";\n@import \"theme.less\";\n\n.file-instance {\n display: flex;\n flex-directio"
},
{
"path": "app/src/assets/markdown/highlight.less",
"chars": 1519,
"preview": "/*!\n Theme: GitHub\n Description: Light theme as seen on github.com\n Author: github.com\n Maintainer: @Hirse\n Updated"
},
{
"path": "app/src/assets/markdown/style.less",
"chars": 6134,
"preview": "/* This is a theme distributed by `starry-night`.\n * It’s based on what GitHub uses on their site.\n * See <https://githu"
},
{
"path": "app/src/assets/markdown/theme.less",
"chars": 25763,
"preview": ".markdown-body {\n color-scheme: light;\n --color-prettylights-syntax-comment: #6e7781;\n --color-prettylights-syntax-co"
},
{
"path": "app/src/assets/pages/api.less",
"chars": 377,
"preview": ".api-dialog {\n display: flex;\n flex-direction: column;\n align-items: center;\n width: 100%;\n height: max-content;\n "
},
{
"path": "app/src/assets/pages/article.less",
"chars": 805,
"preview": ".article-page {\n position: relative;\n display: flex;\n width: 100%;\n min-height: calc(100% - var(--navbar-height));\n "
},
{
"path": "app/src/assets/pages/auth.less",
"chars": 1403,
"preview": ".auth {\n width: 100%;\n height: 100%;\n overflow: hidden;\n}\n\n.auth-container {\n display: flex;\n flex-direction: colum"
},
{
"path": "app/src/assets/pages/chat.less",
"chars": 19853,
"preview": "@keyframes FlexInAnimationFromBottom {\n 0% {\n opacity: .2;\n margin-top: 20px;\n margin-bottom: 0;\n }\n 100% {\n"
},
{
"path": "app/src/assets/pages/generation.less",
"chars": 3584,
"preview": ".generation-page {\n position: relative;\n display: flex;\n width: 100%;\n height: calc(100% - var(--navbar-height));\n\n "
},
{
"path": "app/src/assets/pages/home.less",
"chars": 17791,
"preview": ".main {\n position: relative;\n display: inline-flex;\n flex-direction: row;\n width: 100%;\n height: calc(100% - var(--"
},
{
"path": "app/src/assets/pages/navbar.less",
"chars": 1175,
"preview": ".navbar {\n display: flex;\n flex-direction: row;\n align-content: center;\n vertical-align: center;\n user-select: none"
},
{
"path": "app/src/assets/pages/notify.less",
"chars": 122,
"preview": ".notify-container {\n width: 100%;\n height: 100%;\n overflow: hidden;\n background: hsla(var(--background-container));\n"
},
{
"path": "app/src/assets/pages/package.less",
"chars": 497,
"preview": ".package-wrapper {\n display: flex;\n flex-direction: column;\n\n .package {\n display: flex;\n flex-direction: colum"
},
{
"path": "app/src/assets/pages/preset.less",
"chars": 5209,
"preview": "\n\n.mask-container {\n height: max-content;\n overflow-x: hidden;\n overflow-y: auto;\n scrollbar-width: thin;\n padding:"
},
{
"path": "app/src/assets/pages/quota.less",
"chars": 3449,
"preview": ".buy-interface {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n flex-basis: auto;\n flex-shrink: 0;\n widt"
},
{
"path": "app/src/assets/pages/record.less",
"chars": 1007,
"preview": ".record-wrapper > * {\n max-width: 100%;\n}\n\n.record-area {\n display: block !important;\n}\n\n.stats-boxes {\n .stats-box {"
},
{
"path": "app/src/assets/pages/settings.less",
"chars": 1873,
"preview": ".settings-dialog {\n max-width: min(90vw, 660px) !important;\n}\n\n.settings-container {\n display: flex;\n flex-direction:"
}
]
// ... and 335 more files (download for full content)
About this extraction
This page contains the full source code of the coaidev/coai GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 535 files (2.2 MB), approximately 600.3k tokens, and a symbol index with 2665 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.