Full Code of coaidev/coai for AI

main 3048a493eedc cached
535 files
2.2 MB
600.3k tokens
2665 symbols
1 requests
Download .txt
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">

![chatnio](/app/public/logo.png)

# [🥳 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)

[![CoAI.Dev: #1 Repo Of The Day](https://trendshift.io/api/badge/repositories/6369)](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
>
> ![Pro Version Preview](./screenshot/coai-pro.png)
>
> - ✅ 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)
[![Deploy on Zeabur](https://zeabur.com/button.svg)](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)
[![Deploy on AlibabaCloud ComputeNest International Edition](https://service-info-public.oss-cn-hangzhou.aliyuncs.com/computenest-en.svg)](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">

![chatnio](/app/public/logo.png)

# [🥳 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)

[![CoAI.Dev: #1 Repo Of The Day](https://trendshift.io/api/badge/repositories/6369)](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 ビジネス版
>
> ![Pro Version Preview](./screenshot/coai-pro.png)
>
> - ✅ 美しい商用グレードの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 (ワンクリック)
[![Deploy on Zeabur](https://zeabur.com/button.svg)](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">

![chatnio](/app/public/logo.png)

# [🥳 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)

[![CoAI.Dev: #1 Repo Of The Day](https://trendshift.io/api/badge/repositories/6369)](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 商业版
> ![商业版预览](./screenshot/coai-pro.png)
>
> - ✅ 美观商业级 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 (一键部署)
[![Deploy on Zeabur](https://zeabur.com/button.svg)](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` 登录后台管理。

### 阿里云计算巢 (一键部署)
 [![Deploy on AlibabaCloud ComputeNest](https://service-info-public.oss-cn-hangzhou.aliyuncs.com/computenest.svg)](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
	// ```
	// ![image](...)

	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
Download .txt
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
Download .txt
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![chatnio](/app/public/logo.png)\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![chatnio](/app/public/logo.png)\n\n# [🥳 CoAI.Dev](https://coai.dev)\n\n#### 🚀 次世代AIGCワンストップビジネスソリューショ"
  },
  {
    "path": "README_zh-CN.md",
    "chars": 13405,
    "preview": "<div align=\"center\">\n\n![chatnio](/app/public/logo.png)\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.

Copied to clipboard!