Full Code of 53AI/53AIHub for AI

main 6e2b683e02b3 cached
1265 files
25.2 MB
6.7M tokens
12493 symbols
1 requests
Copy disabled (too large) Download .txt
Showing preview only (26,647K chars total). Download the full file to get everything.
Repository: 53AI/53AIHub
Branch: main
Commit: 6e2b683e02b3
Files: 1265
Total size: 25.2 MB

Directory structure:
gitextract_88ren__n/

├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── README_CN.md
├── README_JA.md
├── api/
│   ├── .gitattributes
│   ├── .gitignore
│   ├── Dockerfile
│   ├── Makefile
│   ├── README.md
│   ├── bin/
│   │   ├── restart.sh
│   │   └── version.txt
│   ├── build.sh
│   ├── common/
│   │   ├── cache.go
│   │   ├── ctxkey/
│   │   │   └── key.go
│   │   ├── email.go
│   │   ├── init.go
│   │   ├── lock.go
│   │   ├── logger/
│   │   │   └── logger.go
│   │   ├── permission.go
│   │   ├── redis.go
│   │   ├── session/
│   │   │   └── key.go
│   │   ├── storage/
│   │   │   ├── storage.go
│   │   │   └── storage_test.go
│   │   ├── utils/
│   │   │   ├── ai53/
│   │   │   │   └── api.go
│   │   │   ├── appbuilder/
│   │   │   │   └── api.go
│   │   │   ├── coze/
│   │   │   │   └── api.go
│   │   │   ├── env/
│   │   │   │   └── env.go
│   │   │   ├── helper/
│   │   │   │   ├── helper.go
│   │   │   │   ├── key.go
│   │   │   │   └── sso_sign.go
│   │   │   ├── huawei_cloud/
│   │   │   │   ├── model.go
│   │   │   │   └── signature.go
│   │   │   ├── ip.go
│   │   │   ├── jwt/
│   │   │   │   └── jwt.go
│   │   │   ├── random.go
│   │   │   ├── snowflake.go
│   │   │   ├── system/
│   │   │   │   ├── machine.go
│   │   │   │   └── version.go
│   │   │   └── wxbizjsonmsgcrypt/
│   │   │       └── wxbizjsonmsgcrypt.go
│   │   └── validate.go
│   ├── config/
│   │   ├── config.go
│   │   ├── database.go
│   │   ├── encryption.go
│   │   └── storage.go
│   ├── controller/
│   │   ├── agent.go
│   │   ├── ai53.go
│   │   ├── ai_link.go
│   │   ├── appbuilder.go
│   │   ├── auth_sso.go
│   │   ├── channel-test.go
│   │   ├── channel.go
│   │   ├── conversation.go
│   │   ├── coze.go
│   │   ├── department.go
│   │   ├── dify.go
│   │   ├── email.go
│   │   ├── enterprise.go
│   │   ├── enterprise_config.go
│   │   ├── group.go
│   │   ├── maxkb.go
│   │   ├── message.go
│   │   ├── model.go
│   │   ├── navigation.go
│   │   ├── navigation_icons.go
│   │   ├── order.go
│   │   ├── pay.go
│   │   ├── pay_setting.go
│   │   ├── prompt.go
│   │   ├── provider.go
│   │   ├── provider_callback.go
│   │   ├── relay.go
│   │   ├── rerank.go
│   │   ├── response_handler.go
│   │   ├── setting.go
│   │   ├── share.go
│   │   ├── status.go
│   │   ├── subscription.go
│   │   ├── sync_organization.go
│   │   ├── system_log.go
│   │   ├── tencent.go
│   │   ├── upload.go
│   │   └── user.go
│   ├── docker/
│   │   └── docker-compose.yml
│   ├── docs/
│   │   └── .gitignore
│   ├── go.mod
│   ├── go.sum
│   ├── main.go
│   ├── middleware/
│   │   ├── auth.go
│   │   ├── cors.go
│   │   ├── distributor.go
│   │   ├── logger.go
│   │   └── relay_auth.go
│   ├── model/
│   │   ├── agent.go
│   │   ├── ai_link.go
│   │   ├── base.go
│   │   ├── cache.go
│   │   ├── channel.go
│   │   ├── channel_file_mapping.go
│   │   ├── conversation.go
│   │   ├── department.go
│   │   ├── dingtalk_corp.go
│   │   ├── dingtalk_suite.go
│   │   ├── enterprise.go
│   │   ├── enterprise_config.go
│   │   ├── enterprise_sync.go
│   │   ├── group.go
│   │   ├── like.go
│   │   ├── main.go
│   │   ├── member_binding.go
│   │   ├── member_department_relation.go
│   │   ├── message.go
│   │   ├── navigation.go
│   │   ├── navigation_content.go
│   │   ├── order.go
│   │   ├── pay_setting.go
│   │   ├── prompt.go
│   │   ├── provider.go
│   │   ├── resource_permission.go
│   │   ├── response.go
│   │   ├── setting.go
│   │   ├── share_record.go
│   │   ├── subscription.go
│   │   ├── system_log.go
│   │   ├── upload_file.go
│   │   ├── user.go
│   │   ├── verification_code.go
│   │   ├── wecom_corp.go
│   │   └── wecom_suite.go
│   ├── router/
│   │   ├── api.go
│   │   ├── main.go
│   │   ├── static.go
│   │   └── web.go
│   ├── service/
│   │   ├── adaptor.go
│   │   ├── ai53_provider.go
│   │   ├── appbuilder_provider.go
│   │   ├── channel_service.go
│   │   ├── coze_provider.go
│   │   ├── enterprise_config_service.go
│   │   ├── hub_adaptor/
│   │   │   ├── 53AI/
│   │   │   │   ├── adaptor.go
│   │   │   │   ├── constants.go
│   │   │   │   ├── main.go
│   │   │   │   ├── model.go
│   │   │   │   └── workflow.go
│   │   │   ├── appbuilder/
│   │   │   │   ├── adaptor.go
│   │   │   │   ├── constants.go
│   │   │   │   ├── main.go
│   │   │   │   └── model.go
│   │   │   ├── bailian/
│   │   │   │   ├── adaptor.go
│   │   │   │   ├── constants.go
│   │   │   │   ├── main.go
│   │   │   │   ├── model.go
│   │   │   │   ├── rerank.go
│   │   │   │   └── rerank_model.go
│   │   │   ├── coze/
│   │   │   │   ├── adaptor.go
│   │   │   │   ├── constant/
│   │   │   │   │   ├── contenttype/
│   │   │   │   │   │   └── define.go
│   │   │   │   │   ├── event/
│   │   │   │   │   │   └── define.go
│   │   │   │   │   └── messagetype/
│   │   │   │   │       └── define.go
│   │   │   │   ├── constants.go
│   │   │   │   ├── helper.go
│   │   │   │   ├── main.go
│   │   │   │   ├── model.go
│   │   │   │   └── workflow.go
│   │   │   ├── custom/
│   │   │   │   ├── common.go
│   │   │   │   ├── config.go
│   │   │   │   └── workflow.go
│   │   │   ├── dify/
│   │   │   │   ├── adaptor.go
│   │   │   │   ├── constants.go
│   │   │   │   ├── info.go
│   │   │   │   ├── main.go
│   │   │   │   ├── model.go
│   │   │   │   └── workflow.go
│   │   │   ├── fastgpt/
│   │   │   │   └── workflow.go
│   │   │   ├── n8n/
│   │   │   │   ├── README.md
│   │   │   │   ├── adaptor.go
│   │   │   │   ├── constants.go
│   │   │   │   ├── main.go
│   │   │   │   ├── model.go
│   │   │   │   └── workflow.go
│   │   │   ├── openai/
│   │   │   │   ├── adaptor.go
│   │   │   │   ├── compatible.go
│   │   │   │   ├── constants.go
│   │   │   │   ├── helper.go
│   │   │   │   ├── image.go
│   │   │   │   ├── main.go
│   │   │   │   ├── model.go
│   │   │   │   ├── token.go
│   │   │   │   └── util.go
│   │   │   ├── tencent/
│   │   │   │   ├── adaptor.go
│   │   │   │   ├── constants.go
│   │   │   │   ├── helper.go
│   │   │   │   ├── main.go
│   │   │   │   ├── model.go
│   │   │   │   └── sdk/
│   │   │   │       ├── client.go
│   │   │   │       ├── errors.go
│   │   │   │       └── models.go
│   │   │   ├── volcengine/
│   │   │   │   └── main.go
│   │   │   └── yuanqi/
│   │   │       ├── adaptor.go
│   │   │       ├── constants.go
│   │   │       ├── main.go
│   │   │       └── model.go
│   │   ├── organizational_service.go
│   │   ├── payment/
│   │   │   ├── alipay.go
│   │   │   ├── manual.go
│   │   │   ├── payment.go
│   │   │   ├── paypal.go
│   │   │   └── wechatpay.go
│   │   ├── rerank_service.go
│   │   ├── resource_permission_service.go
│   │   ├── user_service.go
│   │   └── version_feature.go
│   ├── static/
│   │   └── libs/
│   │       └── js/
│   │           ├── UEditor/
│   │           │   ├── dialogs/
│   │           │   │   ├── anchor/
│   │           │   │   │   └── anchor.html
│   │           │   │   ├── attachment/
│   │           │   │   │   ├── attachment.css
│   │           │   │   │   ├── attachment.html
│   │           │   │   │   └── attachment.js
│   │           │   │   ├── background/
│   │           │   │   │   ├── background.css
│   │           │   │   │   ├── background.html
│   │           │   │   │   └── background.js
│   │           │   │   ├── charts/
│   │           │   │   │   ├── chart.config.js
│   │           │   │   │   ├── charts.css
│   │           │   │   │   ├── charts.html
│   │           │   │   │   └── charts.js
│   │           │   │   ├── emotion/
│   │           │   │   │   ├── emotion.css
│   │           │   │   │   ├── emotion.html
│   │           │   │   │   └── emotion.js
│   │           │   │   ├── gmap/
│   │           │   │   │   └── gmap.html
│   │           │   │   ├── help/
│   │           │   │   │   ├── help.css
│   │           │   │   │   ├── help.html
│   │           │   │   │   └── help.js
│   │           │   │   ├── image/
│   │           │   │   │   ├── image.css
│   │           │   │   │   ├── image.html
│   │           │   │   │   └── image.js
│   │           │   │   ├── insertframe/
│   │           │   │   │   └── insertframe.html
│   │           │   │   ├── internal.js
│   │           │   │   ├── link/
│   │           │   │   │   └── link.html
│   │           │   │   ├── map/
│   │           │   │   │   ├── map.html
│   │           │   │   │   └── show.html
│   │           │   │   ├── music/
│   │           │   │   │   ├── music.css
│   │           │   │   │   ├── music.html
│   │           │   │   │   └── music.js
│   │           │   │   ├── preview/
│   │           │   │   │   └── preview.html
│   │           │   │   ├── scrawl/
│   │           │   │   │   ├── scrawl.css
│   │           │   │   │   ├── scrawl.html
│   │           │   │   │   └── scrawl.js
│   │           │   │   ├── searchreplace/
│   │           │   │   │   ├── searchreplace.html
│   │           │   │   │   └── searchreplace.js
│   │           │   │   ├── snapscreen/
│   │           │   │   │   └── snapscreen.html
│   │           │   │   ├── spechars/
│   │           │   │   │   ├── spechars.html
│   │           │   │   │   └── spechars.js
│   │           │   │   ├── table/
│   │           │   │   │   ├── edittable.css
│   │           │   │   │   ├── edittable.html
│   │           │   │   │   ├── edittable.js
│   │           │   │   │   ├── edittd.html
│   │           │   │   │   └── edittip.html
│   │           │   │   ├── template/
│   │           │   │   │   ├── config.js
│   │           │   │   │   ├── template.css
│   │           │   │   │   ├── template.html
│   │           │   │   │   └── template.js
│   │           │   │   ├── video/
│   │           │   │   │   ├── video.css
│   │           │   │   │   ├── video.html
│   │           │   │   │   └── video.js
│   │           │   │   ├── webapp/
│   │           │   │   │   └── webapp.html
│   │           │   │   └── wordimage/
│   │           │   │       ├── fClipboard_ueditor.swf
│   │           │   │       ├── imageUploader.swf
│   │           │   │       ├── tangram.js
│   │           │   │       ├── wordimage.html
│   │           │   │       └── wordimage.js
│   │           │   ├── index.html
│   │           │   ├── lang/
│   │           │   │   ├── en/
│   │           │   │   │   └── en.js
│   │           │   │   └── zh-cn/
│   │           │   │       └── zh-cn.js
│   │           │   ├── themes/
│   │           │   │   ├── default/
│   │           │   │   │   ├── css/
│   │           │   │   │   │   └── ueditor.css
│   │           │   │   │   └── dialogbase.css
│   │           │   │   └── iframe.css
│   │           │   ├── third-party/
│   │           │   │   ├── SyntaxHighlighter/
│   │           │   │   │   ├── shCore.js
│   │           │   │   │   └── shCoreDefault.css
│   │           │   │   ├── codemirror/
│   │           │   │   │   ├── codemirror.css
│   │           │   │   │   └── codemirror.js
│   │           │   │   ├── highcharts/
│   │           │   │   │   ├── adapters/
│   │           │   │   │   │   ├── mootools-adapter.js
│   │           │   │   │   │   ├── mootools-adapter.src.js
│   │           │   │   │   │   ├── prototype-adapter.js
│   │           │   │   │   │   ├── prototype-adapter.src.js
│   │           │   │   │   │   ├── standalone-framework.js
│   │           │   │   │   │   └── standalone-framework.src.js
│   │           │   │   │   ├── highcharts-more.js
│   │           │   │   │   ├── highcharts-more.src.js
│   │           │   │   │   ├── highcharts.js
│   │           │   │   │   ├── highcharts.src.js
│   │           │   │   │   ├── modules/
│   │           │   │   │   │   ├── annotations.js
│   │           │   │   │   │   ├── annotations.src.js
│   │           │   │   │   │   ├── canvas-tools.js
│   │           │   │   │   │   ├── canvas-tools.src.js
│   │           │   │   │   │   ├── data.js
│   │           │   │   │   │   ├── data.src.js
│   │           │   │   │   │   ├── drilldown.js
│   │           │   │   │   │   ├── drilldown.src.js
│   │           │   │   │   │   ├── exporting.js
│   │           │   │   │   │   ├── exporting.src.js
│   │           │   │   │   │   ├── funnel.js
│   │           │   │   │   │   ├── funnel.src.js
│   │           │   │   │   │   ├── heatmap.js
│   │           │   │   │   │   ├── heatmap.src.js
│   │           │   │   │   │   ├── map.js
│   │           │   │   │   │   ├── map.src.js
│   │           │   │   │   │   ├── no-data-to-display.js
│   │           │   │   │   │   └── no-data-to-display.src.js
│   │           │   │   │   └── themes/
│   │           │   │   │       ├── dark-blue.js
│   │           │   │   │       ├── dark-green.js
│   │           │   │   │       ├── gray.js
│   │           │   │   │       ├── grid.js
│   │           │   │   │       └── skies.js
│   │           │   │   ├── jquery-1.10.2.js
│   │           │   │   ├── video-js/
│   │           │   │   │   ├── video-js.css
│   │           │   │   │   ├── video-js.swf
│   │           │   │   │   ├── video.dev.js
│   │           │   │   │   └── video.js
│   │           │   │   ├── webuploader/
│   │           │   │   │   ├── Uploader.swf
│   │           │   │   │   ├── webuploader.css
│   │           │   │   │   ├── webuploader.custom.js
│   │           │   │   │   ├── webuploader.flashonly.js
│   │           │   │   │   ├── webuploader.html5only.js
│   │           │   │   │   ├── webuploader.min.bak.js
│   │           │   │   │   └── webuploader.withoutimage.js
│   │           │   │   └── zeroclipboard/
│   │           │   │       ├── ZeroClipboard.js
│   │           │   │       └── ZeroClipboard.swf
│   │           │   ├── ueditor.all.min.bak.js
│   │           │   ├── ueditor.config.js
│   │           │   └── ueditor.parse.js
│   │           └── vditor/
│   │               └── dist/
│   │                   ├── content-theme/
│   │                   │   ├── ant-design.css
│   │                   │   ├── dark.css
│   │                   │   ├── light.css
│   │                   │   └── wechat.css
│   │                   ├── css/
│   │                   │   └── content-theme/
│   │                   │       ├── ant-design.css
│   │                   │       ├── dark.css
│   │                   │       ├── light.css
│   │                   │       └── wechat.css
│   │                   ├── index.css
│   │                   ├── index.d.ts
│   │                   ├── index.js
│   │                   ├── js/
│   │                   │   ├── graphviz/
│   │                   │   │   ├── full.render.js
│   │                   │   │   └── viz.js
│   │                   │   ├── highlight.js/
│   │                   │   │   ├── LICENSE
│   │                   │   │   └── third-languages.js
│   │                   │   ├── i18n/
│   │                   │   │   ├── en_US.js
│   │                   │   │   ├── fr_FR.js
│   │                   │   │   ├── ja_JP.js
│   │                   │   │   ├── ko_KR.js
│   │                   │   │   ├── pt_BR.js
│   │                   │   │   ├── ru_RU.js
│   │                   │   │   ├── sv_SE.js
│   │                   │   │   ├── zh_CN.js
│   │                   │   │   └── zh_TW.js
│   │                   │   ├── icons/
│   │                   │   │   ├── ant.js
│   │                   │   │   └── material.js
│   │                   │   ├── markmap/
│   │                   │   │   └── prism.css
│   │                   │   └── mathjax/
│   │                   │       ├── LICENSE
│   │                   │       ├── a11y/
│   │                   │       │   ├── assistive-mml.js
│   │                   │       │   ├── complexity.js
│   │                   │       │   ├── explorer.js
│   │                   │       │   └── semantic-enrich.js
│   │                   │       ├── input/
│   │                   │       │   ├── asciimath.js
│   │                   │       │   ├── mml/
│   │                   │       │   │   └── entities.js
│   │                   │       │   ├── mml.js
│   │                   │       │   ├── tex/
│   │                   │       │   │   └── extensions/
│   │                   │       │   │       ├── action.js
│   │                   │       │   │       ├── all-packages.js
│   │                   │       │   │       ├── ams.js
│   │                   │       │   │       ├── amscd.js
│   │                   │       │   │       ├── autoload.js
│   │                   │       │   │       ├── bbox.js
│   │                   │       │   │       ├── boldsymbol.js
│   │                   │       │   │       ├── braket.js
│   │                   │       │   │       ├── bussproofs.js
│   │                   │       │   │       ├── cancel.js
│   │                   │       │   │       ├── color.js
│   │                   │       │   │       ├── colorV2.js
│   │                   │       │   │       ├── configMacros.js
│   │                   │       │   │       ├── enclose.js
│   │                   │       │   │       ├── extpfeil.js
│   │                   │       │   │       ├── html.js
│   │                   │       │   │       ├── mhchem.js
│   │                   │       │   │       ├── newcommand.js
│   │                   │       │   │       ├── noerrors.js
│   │                   │       │   │       ├── noundefined.js
│   │                   │       │   │       ├── physics.js
│   │                   │       │   │       ├── require.js
│   │                   │       │   │       ├── tagFormat.js
│   │                   │       │   │       ├── textmacros.js
│   │                   │       │   │       ├── unicode.js
│   │                   │       │   │       └── verb.js
│   │                   │       │   ├── tex-base.js
│   │                   │       │   ├── tex-full.js
│   │                   │       │   └── tex.js
│   │                   │       ├── output/
│   │                   │       │   ├── chtml/
│   │                   │       │   │   └── fonts/
│   │                   │       │   │       └── tex.js
│   │                   │       │   ├── chtml.js
│   │                   │       │   ├── svg/
│   │                   │       │   │   └── fonts/
│   │                   │       │   │       └── tex.js
│   │                   │       │   └── svg.js
│   │                   │       ├── sre/
│   │                   │       │   ├── mathmaps/
│   │                   │       │   │   ├── de.js
│   │                   │       │   │   ├── en.js
│   │                   │       │   │   ├── es.js
│   │                   │       │   │   ├── fr.js
│   │                   │       │   │   ├── mathmaps_ie.js
│   │                   │       │   │   └── nemeth.js
│   │                   │       │   ├── sre-node.js
│   │                   │       │   └── sre_browser.js
│   │                   │       ├── tex-mml-chtml.js
│   │                   │       └── tex-svg-full.js
│   │                   ├── method.d.ts
│   │                   ├── method.js
│   │                   ├── ts/
│   │                   │   ├── constants.d.ts
│   │                   │   ├── devtools/
│   │                   │   │   └── index.d.ts
│   │                   │   ├── export/
│   │                   │   │   └── index.d.ts
│   │                   │   ├── hint/
│   │                   │   │   └── index.d.ts
│   │                   │   ├── ir/
│   │                   │   │   ├── expandMarker.d.ts
│   │                   │   │   ├── highlightToolbarIR.d.ts
│   │                   │   │   ├── index.d.ts
│   │                   │   │   ├── input.d.ts
│   │                   │   │   ├── process.d.ts
│   │                   │   │   └── processKeydown.d.ts
│   │                   │   ├── markdown/
│   │                   │   │   ├── SMILESRender.d.ts
│   │                   │   │   ├── abcRender.d.ts
│   │                   │   │   ├── adapterRender.d.ts
│   │                   │   │   ├── anchorRender.d.ts
│   │                   │   │   ├── chartRender.d.ts
│   │                   │   │   ├── codeRender.d.ts
│   │                   │   │   ├── flowchartRender.d.ts
│   │                   │   │   ├── getHTML.d.ts
│   │                   │   │   ├── getMarkdown.d.ts
│   │                   │   │   ├── graphvizRender.d.ts
│   │                   │   │   ├── highlightRender.d.ts
│   │                   │   │   ├── lazyLoadImageRender.d.ts
│   │                   │   │   ├── markmapRender.d.ts
│   │                   │   │   ├── mathRender.d.ts
│   │                   │   │   ├── mediaRender.d.ts
│   │                   │   │   ├── mermaidRender.d.ts
│   │                   │   │   ├── mindmapRender.d.ts
│   │                   │   │   ├── outlineRender.d.ts
│   │                   │   │   ├── plantumlRender.d.ts
│   │                   │   │   ├── previewRender.d.ts
│   │                   │   │   ├── setLute.d.ts
│   │                   │   │   └── speechRender.d.ts
│   │                   │   ├── outline/
│   │                   │   │   └── index.d.ts
│   │                   │   ├── preview/
│   │                   │   │   ├── image.d.ts
│   │                   │   │   └── index.d.ts
│   │                   │   ├── resize/
│   │                   │   │   └── index.d.ts
│   │                   │   ├── sv/
│   │                   │   │   ├── combineFootnote.d.ts
│   │                   │   │   ├── index.d.ts
│   │                   │   │   ├── inputEvent.d.ts
│   │                   │   │   ├── process.d.ts
│   │                   │   │   └── processKeydown.d.ts
│   │                   │   ├── tip/
│   │                   │   │   └── index.d.ts
│   │                   │   ├── toolbar/
│   │                   │   │   ├── Both.d.ts
│   │                   │   │   ├── Br.d.ts
│   │                   │   │   ├── CodeTheme.d.ts
│   │                   │   │   ├── ContentTheme.d.ts
│   │                   │   │   ├── Copy.d.ts
│   │                   │   │   ├── Counter.d.ts
│   │                   │   │   ├── Custom.d.ts
│   │                   │   │   ├── Devtools.d.ts
│   │                   │   │   ├── Divider.d.ts
│   │                   │   │   ├── EditMode.d.ts
│   │                   │   │   ├── Emoji.d.ts
│   │                   │   │   ├── Export.d.ts
│   │                   │   │   ├── Fullscreen.d.ts
│   │                   │   │   ├── Headings.d.ts
│   │                   │   │   ├── Help.d.ts
│   │                   │   │   ├── Indent.d.ts
│   │                   │   │   ├── Info.d.ts
│   │                   │   │   ├── InsertAfter.d.ts
│   │                   │   │   ├── InsertBefore.d.ts
│   │                   │   │   ├── InsertCode.d.ts
│   │                   │   │   ├── MenuItem.d.ts
│   │                   │   │   ├── Outdent.d.ts
│   │                   │   │   ├── Outline.d.ts
│   │                   │   │   ├── Preview.d.ts
│   │                   │   │   ├── Record.d.ts
│   │                   │   │   ├── Redo.d.ts
│   │                   │   │   ├── Undo.d.ts
│   │                   │   │   ├── Upload.d.ts
│   │                   │   │   ├── index.d.ts
│   │                   │   │   └── setToolbar.d.ts
│   │                   │   ├── ui/
│   │                   │   │   ├── initUI.d.ts
│   │                   │   │   ├── setCodeTheme.d.ts
│   │                   │   │   ├── setContentTheme.d.ts
│   │                   │   │   ├── setPreviewMode.d.ts
│   │                   │   │   └── setTheme.d.ts
│   │                   │   ├── undo/
│   │                   │   │   └── index.d.ts
│   │                   │   ├── util/
│   │                   │   │   ├── Options.d.ts
│   │                   │   │   ├── RecordMedia.d.ts
│   │                   │   │   ├── addScript.d.ts
│   │                   │   │   ├── addStyle.d.ts
│   │                   │   │   ├── code160to32.d.ts
│   │                   │   │   ├── compatibility.d.ts
│   │                   │   │   ├── editorCommonEvent.d.ts
│   │                   │   │   ├── fixBrowserBehavior.d.ts
│   │                   │   │   ├── function.d.ts
│   │                   │   │   ├── getSelectText.d.ts
│   │                   │   │   ├── hasClosest.d.ts
│   │                   │   │   ├── hasClosestByHeadings.d.ts
│   │                   │   │   ├── highlightToolbar.d.ts
│   │                   │   │   ├── hotKey.d.ts
│   │                   │   │   ├── log.d.ts
│   │                   │   │   ├── merge.d.ts
│   │                   │   │   ├── processCode.d.ts
│   │                   │   │   ├── selection.d.ts
│   │                   │   │   └── toc.d.ts
│   │                   │   └── wysiwyg/
│   │                   │       ├── afterRenderEvent.d.ts
│   │                   │       ├── highlightToolbarWYSIWYG.d.ts
│   │                   │       ├── index.d.ts
│   │                   │       ├── inlineTag.d.ts
│   │                   │       ├── input.d.ts
│   │                   │       ├── processKeydown.d.ts
│   │                   │       ├── renderDomByMd.d.ts
│   │                   │       ├── setHeading.d.ts
│   │                   │       ├── showCode.d.ts
│   │                   │       └── toolbarEvent.d.ts
│   │                   └── types/
│   │                       └── index.d.ts
│   └── tasks/
│       ├── channel_update_key.go
│       ├── main.go
│       └── order_tasks.go
├── docker/
│   └── docker-compose.yml
└── web/
    ├── README.md
    ├── console/
    │   ├── .editorconfig
    │   ├── .eslintignore
    │   ├── .eslintrc.cjs
    │   ├── .gitattributes
    │   ├── .gitignore
    │   ├── .husky/
    │   │   ├── commit-msg
    │   │   └── pre-commit
    │   ├── .npmrc
    │   ├── .prettierignore
    │   ├── .prettierrc.js
    │   ├── LINT_SETUP.md
    │   ├── README.md
    │   ├── auto-imports.d.ts
    │   ├── commitlint.config.js
    │   ├── components.d.ts
    │   ├── index.html
    │   ├── lint-staged.config.js
    │   ├── package.json
    │   ├── postcss.config.js
    │   ├── public/
    │   │   ├── UEditor/
    │   │   │   ├── dialogs/
    │   │   │   │   ├── anchor/
    │   │   │   │   │   └── anchor.html
    │   │   │   │   ├── attachment/
    │   │   │   │   │   ├── attachment.css
    │   │   │   │   │   ├── attachment.html
    │   │   │   │   │   └── attachment.js
    │   │   │   │   ├── background/
    │   │   │   │   │   ├── background.css
    │   │   │   │   │   ├── background.html
    │   │   │   │   │   └── background.js
    │   │   │   │   ├── charts/
    │   │   │   │   │   ├── chart.config.js
    │   │   │   │   │   ├── charts.css
    │   │   │   │   │   ├── charts.html
    │   │   │   │   │   └── charts.js
    │   │   │   │   ├── emotion/
    │   │   │   │   │   ├── emotion.css
    │   │   │   │   │   ├── emotion.html
    │   │   │   │   │   └── emotion.js
    │   │   │   │   ├── gmap/
    │   │   │   │   │   └── gmap.html
    │   │   │   │   ├── help/
    │   │   │   │   │   ├── help.css
    │   │   │   │   │   ├── help.html
    │   │   │   │   │   └── help.js
    │   │   │   │   ├── image/
    │   │   │   │   │   ├── image.css
    │   │   │   │   │   ├── image.html
    │   │   │   │   │   └── image.js
    │   │   │   │   ├── insertframe/
    │   │   │   │   │   └── insertframe.html
    │   │   │   │   ├── internal.js
    │   │   │   │   ├── link/
    │   │   │   │   │   └── link.html
    │   │   │   │   ├── map/
    │   │   │   │   │   ├── map.html
    │   │   │   │   │   └── show.html
    │   │   │   │   ├── music/
    │   │   │   │   │   ├── music.css
    │   │   │   │   │   ├── music.html
    │   │   │   │   │   └── music.js
    │   │   │   │   ├── preview/
    │   │   │   │   │   └── preview.html
    │   │   │   │   ├── scrawl/
    │   │   │   │   │   ├── scrawl.css
    │   │   │   │   │   ├── scrawl.html
    │   │   │   │   │   └── scrawl.js
    │   │   │   │   ├── searchreplace/
    │   │   │   │   │   ├── searchreplace.html
    │   │   │   │   │   └── searchreplace.js
    │   │   │   │   ├── snapscreen/
    │   │   │   │   │   └── snapscreen.html
    │   │   │   │   ├── spechars/
    │   │   │   │   │   ├── spechars.html
    │   │   │   │   │   └── spechars.js
    │   │   │   │   ├── table/
    │   │   │   │   │   ├── edittable.css
    │   │   │   │   │   ├── edittable.html
    │   │   │   │   │   ├── edittable.js
    │   │   │   │   │   ├── edittd.html
    │   │   │   │   │   └── edittip.html
    │   │   │   │   ├── template/
    │   │   │   │   │   ├── config.js
    │   │   │   │   │   ├── template.css
    │   │   │   │   │   ├── template.html
    │   │   │   │   │   └── template.js
    │   │   │   │   ├── video/
    │   │   │   │   │   ├── video.css
    │   │   │   │   │   ├── video.html
    │   │   │   │   │   └── video.js
    │   │   │   │   ├── webapp/
    │   │   │   │   │   └── webapp.html
    │   │   │   │   └── wordimage/
    │   │   │   │       ├── tangram.js
    │   │   │   │       ├── wordimage.html
    │   │   │   │       └── wordimage.js
    │   │   │   ├── index.html
    │   │   │   ├── lang/
    │   │   │   │   ├── en/
    │   │   │   │   │   └── en.js
    │   │   │   │   └── zh-cn/
    │   │   │   │       └── zh-cn.js
    │   │   │   ├── themes/
    │   │   │   │   ├── default/
    │   │   │   │   │   ├── css/
    │   │   │   │   │   │   └── ueditor.css
    │   │   │   │   │   └── dialogbase.css
    │   │   │   │   └── iframe.css
    │   │   │   ├── third-party/
    │   │   │   │   ├── SyntaxHighlighter/
    │   │   │   │   │   ├── shCore.js
    │   │   │   │   │   └── shCoreDefault.css
    │   │   │   │   ├── codemirror/
    │   │   │   │   │   ├── codemirror.css
    │   │   │   │   │   └── codemirror.js
    │   │   │   │   ├── highcharts/
    │   │   │   │   │   ├── adapters/
    │   │   │   │   │   │   ├── mootools-adapter.js
    │   │   │   │   │   │   ├── mootools-adapter.src.js
    │   │   │   │   │   │   ├── prototype-adapter.js
    │   │   │   │   │   │   ├── prototype-adapter.src.js
    │   │   │   │   │   │   ├── standalone-framework.js
    │   │   │   │   │   │   └── standalone-framework.src.js
    │   │   │   │   │   ├── highcharts-more.js
    │   │   │   │   │   ├── highcharts-more.src.js
    │   │   │   │   │   ├── highcharts.js
    │   │   │   │   │   ├── highcharts.src.js
    │   │   │   │   │   ├── modules/
    │   │   │   │   │   │   ├── annotations.js
    │   │   │   │   │   │   ├── annotations.src.js
    │   │   │   │   │   │   ├── canvas-tools.js
    │   │   │   │   │   │   ├── canvas-tools.src.js
    │   │   │   │   │   │   ├── data.js
    │   │   │   │   │   │   ├── data.src.js
    │   │   │   │   │   │   ├── drilldown.js
    │   │   │   │   │   │   ├── drilldown.src.js
    │   │   │   │   │   │   ├── exporting.js
    │   │   │   │   │   │   ├── exporting.src.js
    │   │   │   │   │   │   ├── funnel.js
    │   │   │   │   │   │   ├── funnel.src.js
    │   │   │   │   │   │   ├── heatmap.js
    │   │   │   │   │   │   ├── heatmap.src.js
    │   │   │   │   │   │   ├── map.js
    │   │   │   │   │   │   ├── map.src.js
    │   │   │   │   │   │   ├── no-data-to-display.js
    │   │   │   │   │   │   └── no-data-to-display.src.js
    │   │   │   │   │   └── themes/
    │   │   │   │   │       ├── dark-blue.js
    │   │   │   │   │       ├── dark-green.js
    │   │   │   │   │       ├── gray.js
    │   │   │   │   │       ├── grid.js
    │   │   │   │   │       └── skies.js
    │   │   │   │   ├── jquery-1.10.2.js
    │   │   │   │   ├── video-js/
    │   │   │   │   │   ├── video-js.css
    │   │   │   │   │   ├── video.dev.js
    │   │   │   │   │   └── video.js
    │   │   │   │   ├── webuploader/
    │   │   │   │   │   ├── webuploader.css
    │   │   │   │   │   ├── webuploader.custom.js
    │   │   │   │   │   ├── webuploader.flashonly.js
    │   │   │   │   │   ├── webuploader.html5only.js
    │   │   │   │   │   ├── webuploader.min.bak.js
    │   │   │   │   │   └── webuploader.withoutimage.js
    │   │   │   │   └── zeroclipboard/
    │   │   │   │       └── ZeroClipboard.js
    │   │   │   ├── ueditor.all.min.bak.js
    │   │   │   ├── ueditor.config.js
    │   │   │   └── ueditor.parse.js
    │   │   ├── km-login/
    │   │   │   └── index.html
    │   │   ├── manifest.json
    │   │   ├── oauth_login.html
    │   │   └── saas-login/
    │   │       └── index.html
    │   ├── src/
    │   │   ├── App.vue
    │   │   ├── api/
    │   │   │   ├── code.ts
    │   │   │   ├── config.ts
    │   │   │   ├── errorHandler.ts
    │   │   │   ├── index.ts
    │   │   │   ├── modules/
    │   │   │   │   ├── agent.ts
    │   │   │   │   ├── agents/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── transform.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── ai-link.ts
    │   │   │   │   ├── auth.ts
    │   │   │   │   ├── banner/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── transform.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── channel/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── transform.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── channel.ts
    │   │   │   │   ├── chunk-setting.ts
    │   │   │   │   ├── common.ts
    │   │   │   │   ├── conversation.ts
    │   │   │   │   ├── department.ts
    │   │   │   │   ├── dingtalk.ts
    │   │   │   │   ├── domain/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── transform.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── enterprise.ts
    │   │   │   │   ├── group.ts
    │   │   │   │   ├── libraries/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── transform.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── message.ts
    │   │   │   │   ├── navigation/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── transform.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── order.ts
    │   │   │   │   ├── payment/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── transform.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── permissions.ts
    │   │   │   │   ├── platform-settings/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── transform.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── prompt.ts
    │   │   │   │   ├── provider.ts
    │   │   │   │   ├── providers/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── transform.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── saas.ts
    │   │   │   │   ├── setting.ts
    │   │   │   │   ├── spaces/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── transform.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── subscription.ts
    │   │   │   │   ├── system-log/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── transform.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── template-style.ts
    │   │   │   │   ├── upload.ts
    │   │   │   │   ├── user.ts
    │   │   │   │   └── wecom.ts
    │   │   │   ├── readme.md
    │   │   │   ├── signature.ts
    │   │   │   └── types.ts
    │   │   ├── apis/
    │   │   │   ├── index.ts
    │   │   │   ├── modules/
    │   │   │   │   ├── conversation.ts
    │   │   │   │   ├── enterprise.ts
    │   │   │   │   ├── group.ts
    │   │   │   │   ├── qyy.ts
    │   │   │   │   ├── setting.ts
    │   │   │   │   └── user.ts
    │   │   │   └── readme.md
    │   │   ├── components/
    │   │   │   ├── AgentPicker/
    │   │   │   │   └── index.vue
    │   │   │   ├── CropperDialog/
    │   │   │   │   └── index.vue
    │   │   │   ├── DeptMemberPicker/
    │   │   │   │   └── index.vue
    │   │   │   ├── DialogueRecord/
    │   │   │   │   ├── drawer.vue
    │   │   │   │   └── index.vue
    │   │   │   ├── EntityDisplay/
    │   │   │   │   ├── README.md
    │   │   │   │   ├── index.vue
    │   │   │   │   └── types.ts
    │   │   │   ├── Filter/
    │   │   │   │   ├── date-range.vue
    │   │   │   │   ├── select.vue
    │   │   │   │   └── user.vue
    │   │   │   ├── Fullscreen/
    │   │   │   │   └── index.vue
    │   │   │   ├── GroupDialog/
    │   │   │   │   └── index.vue
    │   │   │   ├── GroupSelect/
    │   │   │   │   └── index.vue
    │   │   │   ├── GroupTabs/
    │   │   │   │   └── index.vue
    │   │   │   ├── Header/
    │   │   │   │   └── index.vue
    │   │   │   ├── LanguageDropdown/
    │   │   │   │   └── LanguageDropdown.vue
    │   │   │   ├── Layout/
    │   │   │   │   └── index.vue
    │   │   │   ├── Markdown/
    │   │   │   │   └── editor.vue
    │   │   │   ├── Model/
    │   │   │   │   ├── dialog.vue
    │   │   │   │   ├── index.ts
    │   │   │   │   ├── select.vue
    │   │   │   │   └── view.vue
    │   │   │   ├── OpenData/
    │   │   │   │   └── index.vue
    │   │   │   ├── Pagination/
    │   │   │   │   ├── index.vue
    │   │   │   │   └── simple.vue
    │   │   │   ├── Permission/
    │   │   │   │   ├── constant.ts
    │   │   │   │   ├── data.ts
    │   │   │   │   ├── member-selector.vue
    │   │   │   │   └── selector.vue
    │   │   │   ├── Prompt/
    │   │   │   │   ├── README.md
    │   │   │   │   ├── generate.vue
    │   │   │   │   ├── input.vue
    │   │   │   │   ├── optimize.vue
    │   │   │   │   └── test/
    │   │   │   │       ├── component.vue
    │   │   │   │       └── index.ts
    │   │   │   ├── ResourcePicker/
    │   │   │   │   └── index.vue
    │   │   │   ├── Scroller/
    │   │   │   │   └── index.vue
    │   │   │   ├── Search/
    │   │   │   │   └── index.vue
    │   │   │   ├── SelectPlus/
    │   │   │   │   └── index.vue
    │   │   │   ├── ServiceDialog/
    │   │   │   │   └── index.vue
    │   │   │   ├── Sortable/
    │   │   │   │   └── index.vue
    │   │   │   ├── SvgIcon/
    │   │   │   │   └── index.vue
    │   │   │   ├── TablePlus/
    │   │   │   │   ├── create-slots.ts
    │   │   │   │   └── index.vue
    │   │   │   ├── TipConfirm/
    │   │   │   │   ├── index.vue
    │   │   │   │   └── setup.ts
    │   │   │   ├── UEditor/
    │   │   │   │   └── index.vue
    │   │   │   ├── Upload/
    │   │   │   │   ├── certificate.vue
    │   │   │   │   ├── image.vue
    │   │   │   │   └── index.vue
    │   │   │   ├── UserLoginDialog/
    │   │   │   │   ├── index.vue
    │   │   │   │   └── setup.ts
    │   │   │   └── VerificationCodeInput/
    │   │   │       └── index.vue
    │   │   ├── constants/
    │   │   │   ├── .gitkeep
    │   │   │   ├── agent.ts
    │   │   │   ├── banner.ts
    │   │   │   ├── chunk.ts
    │   │   │   ├── domain.ts
    │   │   │   ├── enterprise.ts
    │   │   │   ├── group.ts
    │   │   │   ├── navigation.ts
    │   │   │   ├── order.ts
    │   │   │   ├── payment.ts
    │   │   │   ├── platform/
    │   │   │   │   ├── agent.ts
    │   │   │   │   ├── channel.ts
    │   │   │   │   ├── config.ts
    │   │   │   │   ├── index.ts
    │   │   │   │   ├── model.ts
    │   │   │   │   └── provider.ts
    │   │   │   ├── sync.ts
    │   │   │   ├── system-log.ts
    │   │   │   └── user.ts
    │   │   ├── directive/
    │   │   │   ├── copy.ts
    │   │   │   ├── debounce.ts
    │   │   │   ├── index.ts
    │   │   │   ├── overflow-tooltip.ts
    │   │   │   ├── readme.md
    │   │   │   ├── router.ts
    │   │   │   ├── tooltip.ts
    │   │   │   ├── truncate.ts
    │   │   │   └── version.ts
    │   │   ├── global/
    │   │   │   ├── filters.ts
    │   │   │   ├── index.ts
    │   │   │   ├── methods.ts
    │   │   │   └── readme.md
    │   │   ├── hooks/
    │   │   │   ├── useBasicLayout.ts
    │   │   │   ├── useEntityInfo.ts
    │   │   │   ├── useEnv.ts
    │   │   │   ├── useMobile.ts
    │   │   │   ├── useScroll.ts
    │   │   │   ├── useSso.ts
    │   │   │   ├── useTooltip.ts
    │   │   │   └── useVmodel.ts
    │   │   ├── icons/
    │   │   │   ├── 403.vue
    │   │   │   └── 500.vue
    │   │   ├── layout/
    │   │   │   ├── Child.vue
    │   │   │   ├── Layout.vue
    │   │   │   └── Sider.vue
    │   │   ├── locales/
    │   │   │   ├── en-v2.json
    │   │   │   ├── en.json
    │   │   │   ├── index.ts
    │   │   │   ├── ja.json
    │   │   │   ├── zh-cn.json
    │   │   │   └── zh-tw.json
    │   │   ├── main.ts
    │   │   ├── plugins/
    │   │   │   ├── assets.ts
    │   │   │   └── index.ts
    │   │   ├── router/
    │   │   │   └── index.ts
    │   │   ├── stores/
    │   │   │   ├── index.ts
    │   │   │   └── modules/
    │   │   │       ├── channel.ts
    │   │   │       ├── conversation.ts
    │   │   │       ├── domain.ts
    │   │   │       ├── enterprise.ts
    │   │   │       ├── group.ts
    │   │   │       ├── setting.ts
    │   │   │       └── user.ts
    │   │   ├── styles/
    │   │   │   ├── element/
    │   │   │   │   ├── _variables.scss
    │   │   │   │   ├── override.scss
    │   │   │   │   └── vars.scss
    │   │   │   ├── global.scss
    │   │   │   └── lib/
    │   │   │       └── tailwind.css
    │   │   ├── types/
    │   │   │   ├── agent.d.ts
    │   │   │   ├── ai-link.d.ts
    │   │   │   ├── category.d.ts
    │   │   │   ├── channel.d.ts
    │   │   │   ├── domain.d.ts
    │   │   │   ├── enterprise.d.ts
    │   │   │   ├── entity.ts
    │   │   │   ├── env.d.ts
    │   │   │   ├── global.d.ts
    │   │   │   ├── payment.d.ts
    │   │   │   ├── platform.d.ts
    │   │   │   ├── settings.d.ts
    │   │   │   ├── subscription.d.ts
    │   │   │   └── vue-template.d.ts
    │   │   ├── utils/
    │   │   │   ├── cache.ts
    │   │   │   ├── config.ts
    │   │   │   ├── copy.ts
    │   │   │   ├── event-bus.ts
    │   │   │   ├── filter.ts
    │   │   │   ├── form-rule.ts
    │   │   │   ├── form-rule.v2.ts
    │   │   │   ├── form-validator.ts
    │   │   │   ├── functions/
    │   │   │   │   ├── debounce.ts
    │   │   │   │   └── index.ts
    │   │   │   ├── index.ts
    │   │   │   ├── is/
    │   │   │   │   └── index.ts
    │   │   │   ├── loadLib.ts
    │   │   │   ├── md5.ts
    │   │   │   ├── moment.ts
    │   │   │   ├── request/
    │   │   │   │   ├── axios.ts
    │   │   │   │   ├── blob.ts
    │   │   │   │   ├── code.ts
    │   │   │   │   ├── helper.ts
    │   │   │   │   ├── index.ts
    │   │   │   │   └── signature.ts
    │   │   │   ├── timer-manager.ts
    │   │   │   ├── url.ts
    │   │   │   ├── version.ts
    │   │   │   └── wecom.ts
    │   │   └── views/
    │   │       ├── agent/
    │   │       │   ├── create/
    │   │       │   │   ├── components/
    │   │       │   │   │   ├── agent-info.vue
    │   │       │   │   │   ├── agent-type.vue
    │   │       │   │   │   ├── base-config.vue
    │   │       │   │   │   ├── expand-config.vue
    │   │       │   │   │   ├── field-input-setting.vue
    │   │       │   │   │   ├── field-input.vue
    │   │       │   │   │   ├── limit-config.vue
    │   │       │   │   │   ├── relate-agents-dialog.vue
    │   │       │   │   │   ├── relate-agents-setting.vue
    │   │       │   │   │   ├── relate-agents.vue
    │   │       │   │   │   └── use-scope.vue
    │   │       │   │   ├── drawer.vue
    │   │       │   │   ├── guide.vue
    │   │       │   │   ├── index.vue
    │   │       │   │   ├── platform/
    │   │       │   │   │   ├── 53ai-agent.vue
    │   │       │   │   │   ├── app-builder-agent.vue
    │   │       │   │   │   ├── bailian.vue
    │   │       │   │   │   ├── coze-cn.vue
    │   │       │   │   │   ├── coze-osv.vue
    │   │       │   │   │   ├── dify-agent.vue
    │   │       │   │   │   ├── fastgpt-agent.vue
    │   │       │   │   │   ├── index.vue
    │   │       │   │   │   ├── maxkb-agent.vue
    │   │       │   │   │   ├── n8n.vue
    │   │       │   │   │   ├── prompt.vue
    │   │       │   │   │   ├── tencent.vue
    │   │       │   │   │   ├── volcengine.vue
    │   │       │   │   │   └── yuanqi.vue
    │   │       │   │   ├── response/
    │   │       │   │   │   ├── chat.vue
    │   │       │   │   │   └── completion.vue
    │   │       │   │   └── store.ts
    │   │       │   └── index.vue
    │   │       ├── banner/
    │   │       │   └── index.vue
    │   │       ├── chunk/
    │   │       │   └── index.vue
    │   │       ├── domain/
    │   │       │   ├── components/
    │   │       │   │   ├── exclusive-setting-dialog.vue
    │   │       │   │   └── independent-setting-dialog.vue
    │   │       │   └── index.vue
    │   │       ├── exception/
    │   │       │   ├── 404/
    │   │       │   │   └── index.vue
    │   │       │   ├── 500/
    │   │       │   │   └── index.vue
    │   │       │   └── mobile-tip/
    │   │       │       └── index.vue
    │   │       ├── index.vue
    │   │       ├── info/
    │   │       │   └── index.vue
    │   │       ├── login/
    │   │       │   ├── components/
    │   │       │   │   ├── apply-form.vue
    │   │       │   │   ├── create-enterprise-form.vue
    │   │       │   │   ├── enterprise-list.vue
    │   │       │   │   ├── forget-form.vue
    │   │       │   │   ├── login-form.vue
    │   │       │   │   ├── register-form.vue
    │   │       │   │   └── wechat.vue
    │   │       │   └── index.vue
    │   │       ├── model/
    │   │       │   └── index.vue
    │   │       ├── navigation/
    │   │       │   ├── components/
    │   │       │   │   ├── nav-create-dialog.vue
    │   │       │   │   ├── nav-create-drawer.vue
    │   │       │   │   ├── pc-navigation-pane.vue
    │   │       │   │   └── seo-setting-dialog.vue
    │   │       │   ├── index.vue
    │   │       │   └── web-setting.vue
    │   │       ├── order/
    │   │       │   ├── components/
    │   │       │   │   └── order-add-dialog.vue
    │   │       │   └── index.vue
    │   │       ├── parse/
    │   │       │   └── index.vue
    │   │       ├── payment/
    │   │       │   ├── components/
    │   │       │   │   ├── alipay-setting-dialog.vue
    │   │       │   │   ├── manual-setting-dialog.vue
    │   │       │   │   ├── payment-card.vue
    │   │       │   │   └── wechat-setting-dialog.vue
    │   │       │   └── index.vue
    │   │       ├── platform/
    │   │       │   ├── components/
    │   │       │   │   ├── agent-list-drawer.vue
    │   │       │   │   ├── auth-list-drawer.vue
    │   │       │   │   ├── model-group.vue
    │   │       │   │   ├── model-save-dialog.vue
    │   │       │   │   ├── model-select-dialog.vue
    │   │       │   │   ├── model-setting-dialog.vue
    │   │       │   │   ├── provider-authorize-dialog.vue
    │   │       │   │   └── provider-card.vue
    │   │       │   ├── componentsv2/
    │   │       │   │   ├── model-group.vue
    │   │       │   │   ├── model-save-dialog.vue
    │   │       │   │   └── model-select-dialog.vue
    │   │       │   ├── index.vue
    │   │       │   ├── km.vue
    │   │       │   └── view/
    │   │       │       ├── file-editor.vue
    │   │       │       ├── file-parser.vue
    │   │       │       ├── model.vue
    │   │       │       └── web-search.vue
    │   │       ├── prompt/
    │   │       │   ├── components/
    │   │       │   │   ├── create-drawer.vue
    │   │       │   │   ├── form.vue
    │   │       │   │   └── links-dialog.vue
    │   │       │   ├── create/
    │   │       │   │   ├── guide.vue
    │   │       │   │   ├── index.vue
    │   │       │   │   └── store.ts
    │   │       │   └── index.vue
    │   │       ├── search/
    │   │       │   └── index.vue
    │   │       ├── smtp/
    │   │       │   ├── components/
    │   │       │   │   └── email-form.vue
    │   │       │   └── index.vue
    │   │       ├── space/
    │   │       │   ├── components/
    │   │       │   │   ├── info-save-dialog.vue
    │   │       │   │   └── knowledge-list-drawer.vue
    │   │       │   └── index.vue
    │   │       ├── sso/
    │   │       │   ├── components/
    │   │       │   │   ├── access-dialog.vue
    │   │       │   │   └── api-access-dialog.vue
    │   │       │   └── index.vue
    │   │       ├── statistics/
    │   │       │   └── index.vue
    │   │       ├── subscription/
    │   │       │   ├── index.vue
    │   │       │   └── utils.ts
    │   │       ├── svg/
    │   │       │   └── index.vue
    │   │       ├── system-log/
    │   │       │   └── index.vue
    │   │       ├── template-style/
    │   │       │   └── index.vue
    │   │       ├── toolbox/
    │   │       │   ├── components/
    │   │       │   │   ├── add-account.vue
    │   │       │   │   ├── create-dialog.vue
    │   │       │   │   ├── create-drawer.vue
    │   │       │   │   ├── store-dialog.vue
    │   │       │   │   ├── store-view.vue
    │   │       │   │   └── use-group.vue
    │   │       │   └── index.vue
    │   │       ├── user/
    │   │       │   ├── admin/
    │   │       │   │   └── index.vue
    │   │       │   ├── components/
    │   │       │   │   ├── department-add-dialog.vue
    │   │       │   │   ├── department-tree-select.vue
    │   │       │   │   ├── department-tree.vue
    │   │       │   │   ├── group-add-dialog.vue
    │   │       │   │   ├── user-add-dialog.vue
    │   │       │   │   ├── user-internal-add-dialog.vue
    │   │       │   │   ├── user-internal-edit-drawer.vue
    │   │       │   │   ├── user-internal-status.vue
    │   │       │   │   └── user-select-dialog.vue
    │   │       │   ├── dialogue-record/
    │   │       │   │   └── index.vue
    │   │       │   ├── internal/
    │   │       │   │   ├── account.vue
    │   │       │   │   ├── group.vue
    │   │       │   │   ├── index.vue
    │   │       │   │   ├── member.vue
    │   │       │   │   └── organization.vue
    │   │       │   └── register/
    │   │       │       └── index.vue
    │   │       └── viewer/
    │   │           └── index.vue
    │   ├── stylelint.config.js
    │   ├── tailwind.config.js
    │   ├── tsconfig.json
    │   ├── vite-plugins/
    │   │   └── conditional-compilation.ts
    │   └── vite.config.ts
    └── front/
        ├── .editorconfig
        ├── .eslintignore
        ├── .eslintrc.cjs
        ├── .gitattributes
        ├── .gitignore
        ├── .husky/
        │   ├── commit-msg
        │   └── pre-commit
        ├── .npmrc
        ├── .prettierignore
        ├── .prettierrc.js
        ├── LINT_SETUP.md
        ├── README.md
        ├── build/
        │   ├── entitlements.mac.plist
        │   └── icon.icns
        ├── commitlint.config.js
        ├── dev-app-update.yml
        ├── electron-builder.yml
        ├── electron.vite.config.ts
        ├── lint-staged.config.js
        ├── native/
        │   ├── binding.gyp
        │   ├── mouse_select_status_mac.mm
        │   └── mouse_select_status_win.cpp
        ├── package.json
        ├── postcss.config.js
        ├── src/
        │   ├── main/
        │   │   ├── enums/
        │   │   │   └── SystemTypeEnum.ts
        │   │   ├── helper/
        │   │   │   └── web.ts
        │   │   ├── host.ts
        │   │   ├── index.ts
        │   │   ├── service/
        │   │   │   ├── AutoUpdater.ts
        │   │   │   ├── Bookmarks.ts
        │   │   │   ├── Container.ts
        │   │   │   ├── FileSystem.ts
        │   │   │   ├── GlobalShortcutEvent.ts
        │   │   │   ├── Main.ts
        │   │   │   ├── MouseEventsHandler.ts
        │   │   │   └── Pages.ts
        │   │   ├── utils/
        │   │   │   ├── index.ts
        │   │   │   └── validate.ts
        │   │   └── window/
        │   │       ├── FastChat.ts
        │   │       ├── HoverMenu.ts
        │   │       └── Main.ts
        │   ├── preload/
        │   │   ├── fastChat.ts
        │   │   ├── hoverMenu.ts
        │   │   └── index.ts
        │   └── renderer/
        │       ├── index.html
        │       ├── main/
        │       │   ├── App.vue
        │       │   ├── api/
        │       │   │   ├── code.ts
        │       │   │   ├── config.ts
        │       │   │   ├── errorHandler.ts
        │       │   │   ├── host.ts
        │       │   │   ├── index.ts
        │       │   │   ├── modules/
        │       │   │   │   ├── agent.ts
        │       │   │   │   ├── chat.ts
        │       │   │   │   ├── common.ts
        │       │   │   │   ├── conversation.ts
        │       │   │   │   ├── enterprise.ts
        │       │   │   │   ├── group.ts
        │       │   │   │   ├── links.ts
        │       │   │   │   ├── navigation.ts
        │       │   │   │   ├── order.ts
        │       │   │   │   ├── payment.ts
        │       │   │   │   ├── prompt.ts
        │       │   │   │   ├── setting.ts
        │       │   │   │   ├── share/
        │       │   │   │   │   ├── index.ts
        │       │   │   │   │   ├── transform.ts
        │       │   │   │   │   └── types.ts
        │       │   │   │   ├── subscription.ts
        │       │   │   │   ├── system.ts
        │       │   │   │   ├── upload.ts
        │       │   │   │   └── user.ts
        │       │   │   ├── signature.ts
        │       │   │   └── types.ts
        │       │   ├── assets/
        │       │   │   └── styles/
        │       │   │       ├── animate.css
        │       │   │       ├── custom.css
        │       │   │       ├── element-plus.css
        │       │   │       ├── global.css
        │       │   │       └── tailwind.css
        │       │   ├── components/
        │       │   │   ├── AuthTagGroup/
        │       │   │   │   └── index.vue
        │       │   │   ├── CropperDialog/
        │       │   │   │   └── index.vue
        │       │   │   ├── ExpireModal/
        │       │   │   │   └── index.vue
        │       │   │   ├── FileUpload/
        │       │   │   │   └── index.vue
        │       │   │   ├── Filter/
        │       │   │   │   └── date-range.vue
        │       │   │   ├── Fullscreen/
        │       │   │   │   └── index.vue
        │       │   │   ├── LazyComponent/
        │       │   │   │   └── index.vue
        │       │   │   ├── Lead/
        │       │   │   │   └── index.vue
        │       │   │   ├── LoginModal/
        │       │   │   │   ├── email.vue
        │       │   │   │   ├── forgetPassword.vue
        │       │   │   │   ├── index.vue
        │       │   │   │   ├── register.vue
        │       │   │   │   ├── resetPassword.vue
        │       │   │   │   ├── wechat.vue
        │       │   │   │   └── wecom.vue
        │       │   │   ├── MarkMap/
        │       │   │   │   ├── index.ts
        │       │   │   │   ├── index.vue
        │       │   │   │   └── vis.vue
        │       │   │   ├── Markdown/
        │       │   │   │   ├── editor.vue
        │       │   │   │   ├── helper.ts
        │       │   │   │   └── preview.vue
        │       │   │   ├── Pagination/
        │       │   │   │   └── index.vue
        │       │   │   ├── Prompt/
        │       │   │   │   └── input.vue
        │       │   │   ├── RelatedScene/
        │       │   │   │   └── index.vue
        │       │   │   ├── Search/
        │       │   │   │   └── index.vue
        │       │   │   ├── Slider/
        │       │   │   │   └── index.vue
        │       │   │   ├── Sortable/
        │       │   │   │   └── index.vue
        │       │   │   ├── SvgIcon.vue
        │       │   │   ├── TablePlus/
        │       │   │   │   ├── create-slots.ts
        │       │   │   │   └── index.vue
        │       │   │   ├── Upgrade/
        │       │   │   │   ├── index.vue
        │       │   │   │   └── payment-qrcode.vue
        │       │   │   ├── Upload/
        │       │   │   │   ├── image.vue
        │       │   │   │   └── index.vue
        │       │   │   ├── VersionModal/
        │       │   │   │   └── index.vue
        │       │   │   └── modals/
        │       │   │       └── .editorconfig
        │       │   ├── constants/
        │       │   │   ├── currency.ts
        │       │   │   ├── events.ts
        │       │   │   ├── navigation.ts
        │       │   │   ├── payment.ts
        │       │   │   ├── storage.ts
        │       │   │   └── website.ts
        │       │   ├── directive/
        │       │   │   ├── README.md
        │       │   │   ├── copy.ts
        │       │   │   ├── debounce.ts
        │       │   │   ├── index.ts
        │       │   │   ├── permission.ts
        │       │   │   ├── tooltip.ts
        │       │   │   └── trim.ts
        │       │   ├── global/
        │       │   │   └── index.ts
        │       │   ├── hooks/
        │       │   │   ├── README.md
        │       │   │   ├── useBasicLayout.ts
        │       │   │   ├── useEmail.ts
        │       │   │   ├── useEnv.ts
        │       │   │   ├── useMobile.ts
        │       │   │   ├── useScroll.ts
        │       │   │   └── useVmodel.ts
        │       │   ├── layout/
        │       │   │   ├── header.vue
        │       │   │   ├── index.vue
        │       │   │   ├── m-footer.vue
        │       │   │   └── sider.vue
        │       │   ├── locales/
        │       │   │   ├── en.ts
        │       │   │   ├── index.ts
        │       │   │   ├── jp.ts
        │       │   │   ├── zh-cn.ts
        │       │   │   └── zh-tw.ts
        │       │   ├── main.ts
        │       │   ├── plugins/
        │       │   │   └── index.ts
        │       │   ├── router/
        │       │   │   └── index.ts
        │       │   ├── stores/
        │       │   │   ├── index.ts
        │       │   │   └── modules/
        │       │   │       ├── agent.ts
        │       │   │       ├── browser-setting.ts
        │       │   │       ├── conversation.ts
        │       │   │       ├── enterprise.ts
        │       │   │       ├── global.ts
        │       │   │       ├── links.ts
        │       │   │       ├── navigation.ts
        │       │   │       ├── prompt.ts
        │       │   │       └── user.ts
        │       │   ├── typings/
        │       │   │   ├── Browser.d.ts
        │       │   │   ├── agent.d.ts
        │       │   │   ├── category.d.ts
        │       │   │   ├── conversation.d.ts
        │       │   │   ├── enterprise.d.ts
        │       │   │   ├── global.d.ts
        │       │   │   ├── link.d.ts
        │       │   │   ├── navigation.d.ts
        │       │   │   ├── order.d.ts
        │       │   │   ├── prompt.ts
        │       │   │   ├── subscription.d.ts
        │       │   │   └── user.d.ts
        │       │   ├── utils/
        │       │   │   ├── cache.ts
        │       │   │   ├── copy.ts
        │       │   │   ├── event-bus.ts
        │       │   │   ├── file.ts
        │       │   │   ├── filter.ts
        │       │   │   ├── form-rules.ts
        │       │   │   ├── functions/
        │       │   │   │   ├── debounce.ts
        │       │   │   │   └── index.ts
        │       │   │   ├── index.ts
        │       │   │   ├── loadLib.ts
        │       │   │   ├── md5.ts
        │       │   │   ├── moment.ts
        │       │   │   ├── permission.ts
        │       │   │   ├── router.ts
        │       │   │   ├── scroll.ts
        │       │   │   ├── storage.ts
        │       │   │   └── url.ts
        │       │   └── views/
        │       │       ├── agent/
        │       │       │   ├── components/
        │       │       │   │   └── list.vue
        │       │       │   └── index.vue
        │       │       ├── chat/
        │       │       │   ├── chat/
        │       │       │   │   ├── components/
        │       │       │   │   │   ├── agent-tooltip.vue
        │       │       │   │   │   └── history.vue
        │       │       │   │   └── index.vue
        │       │       │   ├── completion/
        │       │       │   │   └── index.vue
        │       │       │   ├── helper.vue
        │       │       │   ├── index.vue
        │       │       │   └── store.ts
        │       │       ├── custom/
        │       │       │   └── index.vue
        │       │       ├── desktop/
        │       │       │   ├── components/
        │       │       │   │   ├── BookMarks.vue
        │       │       │   │   ├── Browser.vue
        │       │       │   │   ├── Error.vue
        │       │       │   │   ├── GNBTabs.vue
        │       │       │   │   ├── MultiBrowser.vue
        │       │       │   │   └── Reader/
        │       │       │   │       ├── html.vue
        │       │       │   │       ├── index.vue
        │       │       │   │       ├── markdown.vue
        │       │       │   │       └── summarize.vue
        │       │       │   ├── index.vue
        │       │       │   ├── stores/
        │       │       │   │   ├── tabs.ts
        │       │       │   │   └── user.ts
        │       │       │   └── tools/
        │       │       │       ├── index.vue
        │       │       │       └── toolbox.vue
        │       │       ├── discover/
        │       │       │   └── index.vue
        │       │       ├── index/
        │       │       │   ├── agent/
        │       │       │   │   ├── chat.vue
        │       │       │   │   └── index.vue
        │       │       │   ├── index.vue
        │       │       │   ├── layout.vue
        │       │       │   ├── prompt/
        │       │       │   │   ├── detail.vue
        │       │       │   │   └── index.vue
        │       │       │   ├── redirect.vue
        │       │       │   └── toolkit.vue
        │       │       ├── order/
        │       │       │   └── index.vue
        │       │       ├── profile/
        │       │       │   ├── about.vue
        │       │       │   ├── changeMobile.vue
        │       │       │   ├── common.vue
        │       │       │   ├── glider.vue
        │       │       │   ├── index.vue
        │       │       │   ├── password.vue
        │       │       │   ├── toolbar.vue
        │       │       │   └── userinfo.vue
        │       │       ├── prompt/
        │       │       │   ├── detail/
        │       │       │   │   └── index.vue
        │       │       │   ├── index.vue
        │       │       │   └── view.vue
        │       │       ├── share/
        │       │       │   └── chat.vue
        │       │       ├── svglist/
        │       │       │   └── index.vue
        │       │       └── toolkit/
        │       │           ├── components/
        │       │           │   ├── account-dialog.vue
        │       │           │   ├── group-list.vue
        │       │           │   └── list.vue
        │       │           └── index.vue
        │       └── public/
        │           └── oauth_login.html
        ├── stylelint.config.js
        ├── tailwind.config.js
        ├── tsconfig.json
        ├── tsconfig.node.json
        ├── tsconfig.web.json
        ├── vite.common.ts
        └── vite.config.ts

================================================
FILE CONTENTS
================================================

================================================
FILE: CONTRIBUTING.md
================================================
# 贡献指南

感谢您考虑为53AI Hub项目做出贡献!以下是一些指导方针,帮助您参与到项目中来。

## 行为准则

请尊重所有项目参与者,保持专业和友好的交流环境。

## 如何贡献

### 报告问题

如果您发现了bug或有新功能建议,请通过以下步骤提交问题:

1. 检查是否已存在相同或类似的问题
2. 使用清晰的标题和详细描述创建新问题
3. 包含重现步骤、预期行为和实际行为
4. 如可能,添加截图或错误日志

### 提交代码

1. Fork项目仓库
2. 创建您的特性分支 (`git checkout -b feature/amazing-feature`)
3. 提交您的更改 (`git commit -m '添加一些功能'`)
4. 推送到分支 (`git push origin feature/amazing-feature`)
5. 创建一个Pull Request

### 代码风格

- 遵循项目现有的代码风格和约定
- 使用ESLint和Prettier保持代码格式一致
- 为新功能编写测试
- 保持代码简洁可读

## 开发设置

请参考README.md中的项目设置部分,了解如何设置开发环境。

## Pull Request流程

1. 确保您的PR描述清晰地说明了更改内容和原因
2. 可能需要进行代码审查和修改
3. 一旦获得批准,您的PR将被合并

## 许可证

通过贡献代码,您同意您的贡献将在项目的[许可和贡献者协议](./LICENSE)下发布。




================================================
FILE: LICENSE
================================================
## 53AI 开源许可证  
**53AI Open Source License**  

53AI Hub 基于 Apache License 2.0 的开源协议,并附加以下条件:  
53AI Hub is licensed under the Apache License 2.0, with the following additional conditions:  

小微企业与创业团队**可将 53AI Hub 源码用于商业用途**。  
Small and micro enterprises, as well as startup teams, are permitted to use the 53AI Hub source code for commercial purposes.  

若满足以下任一条件,须从 53AI 获得商业许可:  
However, if any of the following conditions apply, a commercial license must be obtained from 53AI:  

- **中大型企业使用**:员工数 300 人以上或年营收 6,000 万以上属于中大型企业。  
- **Medium and large enterprises**: Companies with **300 or more employees** or **annual revenue exceeding 60 million RMB** are considered medium or large enterprises.  

- **移除 Logo 与版权**:不得删除或修改 53AI 的 Logo 及版权信息。  
- **Removal of logo and copyright**: The 53AI logo and copyright information **must not be removed or altered**.  

- **多租户 SaaS 服务**:不得使用 53AI Hub 的源代码运营多租户环境。  
- **Multi-tenant SaaS services**: The source code of 53AI Hub **must not be used to operate multi-tenant environments**.  

作为贡献者,需同意:  
As a contributor, you agree to:  

- 产品方可根据需要调整开源协议,使其更严格或更宽松。  
- Allow the product team to adjust the open-source license as needed, making it either stricter or more permissive.  

- 贡献的代码可用于商业用途,包括但不限于云服务运营。  
- Permit the contributed code to be used for commercial purposes, including but not limited to cloud service operations.  

除上述特定条件外,其他所有权利和限制遵循 Apache License 2.0。  
Except for the specific conditions mentioned above, all other rights and restrictions shall follow the Apache License 2.0.  

关于 Apache License 2.0 的详细信息,请访问 [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)。  
For detailed information about the Apache License 2.0, please visit [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0).


================================================
FILE: README.md
================================================
<div align="center">
  <a href="https://www.53ai.com/products/53AIHub"><img alt="Product Introduction Page" src="https://oss.ibos.cn/53ai/common/53AIHub_banner.png"></a>
</div>

<div align="center">
<a href="./README.md"><img alt="README in English" src="https://img.shields.io/badge/English-d9d9d9"></a>
<a href="./README_CN.md"><img alt="Simplified Chinese README" src="https://img.shields.io/badge/简体中文-d9d9d9"></a>
<a href="./README_JA.md"><img alt="Japanese README" src="https://img.shields.io/badge/日本語-d9d9d9"></a>
</div>

<div>
<a href="https://hub.53ai.com">Cloud Service</a> ·
<a href="https://docs.53ai.com/%E5%85%A5%E9%97%A8/%E6%9C%AC%E5%9C%B0%E9%83%A8%E7%BD%B2">Local Deployment</a> ·
<a href="https://docs.53ai.com/">Documentation</a> ·
<a href="https://aihub.53ai.com">Demo Site</a>
</div>

**53AI Hub** is an **open-source AI portal**, which enables you to quickly build a operational-level AI portal to launch and operate AI agents, prompts, and AI tools. It supports seamless integration with development platforms like **Coze, Dify, FastGPT, RAGFlow, and 53AI Studio**, and cloud platforms such as **Aliyun , Tencent Cloud , and Baidu Cloud**, helping developers and enterprises build production-grade AI portals without complex integrations. Even users with no technical background can participate easily, significantly lowering the barrier to AI inplementation.

Key features are as follows:

**1. Platform Integration**:
Supports integration with mainstream agent development platforms, cloud services, and large language model platforms. Users can choose from site templates and styles, and customize the interface as needed.

**2. Application Management**:
Provides full lifecycle management for AI agents, prompts, and AI tools, including publishing, grouping, sorting, and user permission configuration.

**3. User Operations**:
Supports the operation of both registered users and internal users, with the ability to manage and view login and usage records.

**4. Independent Deployment**:
Supports one-click deployment on both cloud and local environments, and binding to a custom domain name.

## Product Comparison

| Feature            | 53AI Hub                | NextChat    | lobehub     | Cherry Studio |
| ------------------ | ----------------------- | ----------- | ----------- | ------------- |
| Custom Interface   | Multiple styles         | Fixed style | Fixed style | Fixed style   |
| Access Permissions | Enterprise-grade        | None        | None        | None          |
| Agent Integration  | ✅                      | ❌          | ❌          | ❌            |
| LLM Integration    | ✅                      | ✅          | ✅          | ✅            |
| Registered Users   | ✅                      | ✅          | ✅          | ✅            |
| Internal Users     | ✅                      | ❌          | ❌          | ❌            |
| SSO Support        | WeCom, DingTalk, Feishu | ❌          | ❌          | ❌            |
| Local Deployment   | ✅                      | ✅          | ✅          | ✅            |

## Usage

* **Cloud Service**
  Visit [53AI Hub Cloud Service](https://hub.53ai.com) to apply. The cloud service includes Free, Standard, and Enterprise editions. The Enterprise version offers all features, and the Free version supports 10 agents and 100 registered users.
* **Community Open Source Edition**
  Refer to our [Getting Started Guide](https://docs.53ai.com/%E5%85%A5%E9%97%A8/%E6%AC%A2%E8%BF%8E%E4%BD%BF%E7%94%A8) for quick local deployment and our [Documentation](https://docs.53ai.com) for in-depth usage.
* **Enterprise Customized Edition**
  We offer enterprise custom versions with features like integration with WeCom, DingTalk, and Feishu org structures. For custom needs, contact us via [email](mailto:hub@53ai.com?subject=[GitHub]Customization).

## Installing the Community Edition

### System Requirements

Minimum configuration for installing 53AI Hub:

* CPU ≥ 1 Core
* RAM ≥ 2 GiB

### Quick Installation

The simplest way to install 53AI Hub Community Edition is to run our docker/docker-compose.yaml file. Before running the installation command, ensure that https://docs.docker.com/get-docker/ and https://docs.docker.com/compose/install/ are installed on your machine. :

1. Clone the repository
```bash
git clone https://github.com/53ai/53aihub.git
cd 53aihub
```
2. Run the following command
```bash
cd docker
docker compose up -d
```

Then visit [`http://localhost:3000`](http://localhost:3000) to access the administration panel and begin setup.

### Custom Configuration

Refer to the comments in `.env.example`, copy and rename it to `.env`, and edit the values. You may also modify `docker-compose.yaml` for things like image versions, port mappings, or volume mounts. After changes, rerun `docker-compose up -d`. You can find the full list of available environment variables here.

## Star History

[![Star History Chart](https://api.star-history.com/svg?repos=53AI/53AIhub&type=Date)](https://star-history.com/#53AI/53AIhub&Date)


## Contributing

> We're seeking contributors to help translate 53AI Hub into more languages. Interested? Get in touch!

We welcome your contributions—whether code, ideas, or issues. Feel free to share 53AI Hub at events, in talks, or on social media.

* [GitHub Discussion](https://github.com/53ai/53aihub/discussions): Share your apps and ideas with the community.
* [GitHub Issues](https://github.com/53ai/53aihub/issues): Report bugs or problems.



## Compliance Certifications

53AI has obtained the following certifications:

* **ISO/IEC 27001:2022 – Information Security Management Systems**
* **ISO 9001:2015 – Quality Management Systems**

## License

This repository is licensed under the [53AI Open Source License](https://docs.53ai.com/%E5%85%A5%E9%97%A8/%E5%BC%80%E6%BA%90%E8%AE%B8%E5%8F%AF%E5%8D%8F%E8%AE%AE), which is based on Apache 2.0 with additional restrictions.

## Follow Us

Star 53AI Hub on GitHub to get notified about updates and new releases.



================================================
FILE: README_CN.md
================================================
<div align="center">
  <a href="https://www.53ai.com/products/53AIHub"><img alt="产品介绍页" src="https://oss.ibos.cn/53ai/common/53AIHub_banner.png"></a>
</div>

<div align="center">
<a href="./README.md"><img alt="README in English" src="https://img.shields.io/badge/English-d9d9d9"></a>
<a href="./README_CN.md"><img alt="简体中文版自述文件" src="https://img.shields.io/badge/简体中文-d9d9d9"></a>
<a href="./README_JA.md"><img alt="日本語のREADME" src="https://img.shields.io/badge/日本語-d9d9d9"></a>

</div>
<div>
<a href="https://hub.53ai.com">云服务</a> ·
<a href="https://docs.53ai.com/%E5%85%A5%E9%97%A8/%E6%9C%AC%E5%9C%B0%E9%83%A8%E7%BD%B2">本地部署</a> ·
<a href="https://docs.53ai.com/">产品文档</a> ·
<a href="https://aihub.53ai.com">演示站</a>

</div>

**53AI Hub** 是一款**开源的AI门户**。它可以让你快速搭建一个运营级的AI门户,实现对智能体、提示词与AI工具的发布与运营。它支持无缝对接**字节扣子、腾讯元器、Dify、FastGPT、RAGFlow、53AI Studio**等智能体开发平台,以及**阿里百炼、腾讯云智能体开发平台、火山方舟、百度千帆 AppBuild**等云计算平台,让开发者和企业能够快速搭建生产运营级的 AI 门户,无需复杂的技术整合流程。即使是没有技术背景的人员,也能轻松参与智能体发布和运营,极大降低了 AI 应用落地的门槛。

以下是核心功能列表: </br> </br>

**1. 平台接入**:
主流的智能体开发平台、云计算平台、大模型平台的接入,可选择站点模板及风格,并进行自定义界面。

**2. 应用管理**:
支持智能体、提示词、AI工具的发布、管理、分组、排序、使用权限等设置。

**3.  用户运营**:
支持注册用户、内部用户两类用户的运营,可以管理和查看用户登录、使用记录,

**4. 独立部署**:
可在云平台及本地一键安装部署,支持绑定独立域名。

## 产品对比

<table style="width:100%;">
  <tr>
    <th align="center">功能</th>
    <th align="center">53AI Hub</th>
    <th align="center">NextChat</th>
    <th align="center">lobehub</th>
    <th align="center">Cherry Studio</th>
  </tr>
  <tr>
    <td align="center">自定义界面</td>
    <td align="center">多风格及样式</td>
    <td align="center">固定风格</td>
    <td align="center">固定风格</td>
    <td align="center">固定风格</td>
  </tr>
  <tr>
    <td align="center">使用权限</td>
    <td align="center">企业级权限</td>
    <td align="center">无</td>
    <td align="center">无</td>
    <td align="center">无</td>
  </tr>
  <tr>
    <td align="center">智能体接入</td>
    <td align="center">✅</td>
    <td align="center">❌</td>
    <td align="center">❌</td>
    <td align="center">❌</td>
  </tr>
  <tr>
    <td align="center">大模型接入</td>
    <td align="center">✅</td>
    <td align="center">✅</td>
    <td align="center">✅</td>
    <td align="center">✅</td>
  </tr>
  <tr>
    <td align="center">注册用户</td>
    <td align="center">✅</td>
    <td align="center">✅</td>
    <td align="center">✅</td>
    <td align="center">✅</td>
  </tr>
  <tr>
    <td align="center">内部用户</td>
    <td align="center">✅</td>
    <td align="center">❌</td>
    <td align="center">❌</td>
    <td align="center">❌</td>
  </tr>
  <tr>
    <td align="center">单点登录</td>
    <td align="center">企微、钉钉、飞书</td>
    <td align="center">❌</td>
    <td align="center">❌</td>
    <td align="center">❌</td>
  </tr>
  <tr>
    <td align="center">本地部署</td>
    <td align="center">✅</td>
    <td align="center">✅</td>
    <td align="center">✅</td>
    <td align="center">✅</td>
  </tr>
</table>

## 使用方式

* **在线云服务 </br>**
  我们提供[ 53AI Hub 云服务](https://hub.53ai.com),用户可以在线申请开通。云服务包含免费版、标准版和企业版,企业版提供了53AI Hub的全部功能,在免费版本中支持接入10个智能体及100个注册用户。
* **社区开源版</br>**
  通过[入门指南](https://docs.53ai.com/%E5%85%A5%E9%97%A8/%E6%AC%A2%E8%BF%8E%E4%BD%BF%E7%94%A8)快速进行本地部署,阅读[产品文档](https://docs.53ai.com)进行更深入的了解。
* **企业定制版</br>**
  我们提供可以企业定制版,具有包括不限于打通企微、钉钉、飞书组织架构等企业级产品特性,如果你需要个性化定制,也可以通过[电子邮件](mailto\:hub@53ai.com?subject=\[GitHub]个性定制)讨论你的个性化需求。 </br>

## 安装社区版

### 系统要求

53AI Hub 的最低安装配置:

* CPU >= 1 Core
* RAM >= 2 GiB

### 快速安装

安装 53AI Hub 社区版最简单方法是运行我们的 [docker-compose.yml](docker/docker-compose.yaml) 文件。在运行安装命令之前,请确保您的机器上安装了 [Docker](https://docs.docker.com/get-docker/) 和 [Docker Compose](https://docs.docker.com/compose/install/):

1. 克隆仓库:
```bash
git clone https://github.com/53ai/53aihub.git
cd 53aihub
```
2. 运行安装命令:
```bash
cd docker
docker compose up -d
```

运行后,可以在浏览器上访问 [`http://localhost:3000`](http://localhost:3000) 进入 53AI Hub 并开始初始化配置操作,默认账号通常是`admin@53ai.com` 密码`admin888`。

### 自定义配置

如果您需要自定义配置,请参考 `.env.example`文件中的注释,复制一个改名为 `.env`并更新文件中对应的值。
此外,您可能需要根据您的具体部署环境和需求对 `docker-compose.yaml`文件本身进行调整,例如更改镜像版本、端口映射或卷挂载。完成任何更改后,请重新运行 `docker-compose up -d`。您可以在此处找到可用环境变量的完整列表。

## Star History

[![Star History Chart](https://api.star-history.com/svg?repos=53AI/53AIhub&type=Date)](https://star-history.com/#53AI/53AIhub&Date)

## 参与项目

> 我们在寻找贡献者来帮助将 53AI Hub 翻译成英文之外的其他语言,如果您有兴趣参与,请通联系我们。

我们欢迎您为 53AI Hub做出贡献,包括不限于:提交代码、提交问题、你的新想法。我们也欢迎您在不同的活动、会议和社交媒体上分享 53AI Hub。

* [Github Discussion](https://github.com/53ai/53aihub/discussions)👉:分享您的应用程序并与社区交流。
* [GitHub Issues](https://github.com/53ai/53aihub/issues)👉:使用 53AI Hub 时遇到的错误和问题。

## 合规认证

53AI 已获取以下认证:

* **ISO/IEC 27001:2022  Information security management systems**
* **ISO 9001:2015 Quality management systems**

## 开源协议

本仓库遵循 [53AI Open Source License](https://docs.53ai.com/%E5%85%A5%E9%97%A8/%E5%BC%80%E6%BA%90%E8%AE%B8%E5%8F%AF%E5%8D%8F%E8%AE%AE) 开源协议,该许可证本质上是 Apache 2.0,但有一些额外的限制。

## 关注我们

在 GitHub 上给 53AI Hub Star,我们更新产品你将第一时间收到新版本更新的通知。

## 商务合作

联系人:杨先生

📮:hub@53ai.com

📱:18688881185 (非客服电话)

![.jpg](http://kmdev.53ai.com/api/preview/e884dbfe4ab8161ee268011111b900c3.jpg)

> 使用问题咨询,可以在官网首页底部加入用户交流群,也可邮件 hub@53ai.com
>
> 如果您需要更多开发和运营指导,可以联系购买商业版本及交付服务




================================================
FILE: README_JA.md
================================================
<div align="center">
  <a href="https://www.53ai.com/products/53AIHub"><img alt="製品紹介ページ" src="https://oss.ibos.cn/53ai/common/53AIHub_banner.png"></a>
</div>

<div align="center">
<a href="./README.md"><img alt="README(英語)" src="https://img.shields.io/badge/English-d9d9d9"></a>
<a href="./README_CN.md"><img alt="簡体字中国語README" src="https://img.shields.io/badge/简体中文-d9d9d9"></a>
<a href="./README_JA.md"><img alt="日本語README" src="https://img.shields.io/badge/日本語-d9d9d9"></a>
</div>

<div>
<a href="https://hub.53ai.com">クラウドサービス</a> ·
<a href="https://docs.53ai.com/%E5%85%A5%E9%97%A8/%E6%9C%AC%E5%9C%B0%E9%83%A8%E7%BD%B2">ローカル導入</a> ·
<a href="https://docs.53ai.com/">製品ドキュメント</a> ·
<a href="https://aihub.53ai.com">デモサイト</a>
</div>

**53AI Hub** は、**オープンソースのAIポータル**です。AIエージェント、プロンプト、AIツールの公開・運用を迅速に構築できます。**ByteDance Coze、Tencent Yuanqi、Dify、FastGPT、RAGFlow、53AI Studio**などの開発プラットフォーム、**Aliyun ModelScope、Tencent Cloud、Volcano Ark、Baidu Qianfan AppBuild**などのクラウドプラットフォームとシームレスに連携できます。技術的な統合作業を必要とせず、非技術者でもAIエージェントの運用に参加できるため、AI活用のハードルを大幅に下げることができます。

主な機能:

**1. プラットフォーム連携**:
主流のエージェント開発・クラウド・大規模言語モデル(LLM)との接続。サイトテンプレートやスタイルを選択し、UIをカスタマイズ可能。

**2. アプリケーション管理**:
AIエージェント、プロンプト、ツールの公開、管理、分類、順序、アクセス権限などを設定。

**3. ユーザー管理**:
登録ユーザーと内部ユーザーのログインや利用履歴を確認・管理。

**4. 独立導入**:
クラウドまたはローカル環境にワンクリックで導入可能。独自ドメインも設定可能。

## 製品比較

| 機能             | 53AI Hub                | NextChat     | lobehub      | Cherry Studio |
| ---------------- | ----------------------- | ------------ | ------------ | ------------- |
| UIカスタマイズ   | 多様なスタイル          | 固定スタイル | 固定スタイル | 固定スタイル  |
| アクセス制御     | 企業レベル              | なし         | なし         | なし          |
| エージェント統合 | ✅                      | ❌           | ❌           | ❌            |
| LLM統合          | ✅                      | ✅           | ✅           | ✅            |
| 登録ユーザー     | ✅                      | ✅           | ✅           | ✅            |
| 内部ユーザー     | ✅                      | ❌           | ❌           | ❌            |
| SSO対応          | WeCom、DingTalk、Feishu | ❌           | ❌           | ❌            |
| ローカル導入     | ✅                      | ✅           | ✅           | ✅            |

## 利用方法

* **クラウドサービス**
  [53AI Hubクラウドサービス](https://hub.53ai.com)から申請可能。無料版、標準版、企業版を提供。無料版では10個のAIエージェントと100人のユーザーが利用可能。
* **オープンソース版**
  [入門ガイド](https://docs.53ai.com/%E5%85%A5%E9%97%A8/%E6%AC%A2%E8%BF%8E%E4%BD%BF%E7%94%A8)を参照し、ローカルに迅速導入可能。[製品ドキュメント](https://docs.53ai.com)で詳細を確認。
* **企業向けカスタム版**
  WeCom、DingTalk、Feishuとの組織連携など企業向け機能に対応。カスタマイズのご希望は[メール](mailto:hub@53ai.com?subject=[GitHub]カスタマイズ要望)にてご相談ください。

## コミュニティ版の導入

### システム要件

最小構成:

* CPU:1コア以上
* メモリ:2GiB以上

### クイックインストール

[docker-compose.yml](docker/docker-compose.yaml) を使用すると簡単にインストールできます。事前に [Docker](https://docs.docker.com/get-docker/) と [Docker Compose](https://docs.docker.com/compose/install/) をインストールしてください。:

1. `git clone` でリポジトリをクローン
```bash
git clone https://github.com/53ai/53aihub.git
cd 53aihub
```
2. Docker Composeを実行
```bash
cd docker
docker compose up -d
```

ブラウザで [`http://localhost:3000`](http://localhost:3000) にアクセスし、管理画面で初期設定を行います。

### カスタム設定

`.env.example` を `.env` にコピーし、コメントを参考に必要な値を設定。`docker-compose.yaml`の内容も環境に応じて調整可能です。

## Star History

[![Star History Chart](https://api.star-history.com/svg?repos=53AI/53AIhub&type=Date)](https://star-history.com/#53AI/53AIhub&Date)


## コミュニティへの参加

> 他言語翻訳の貢献者も募集中です。興味のある方はご連絡ください。

コード、アイデア、フィードバックの提供など、あらゆる形での貢献を歓迎します。

* [GitHub Discussion](https://github.com/53ai/53aihub/discussions):アプリの共有や交流
* [GitHub Issues](https://github.com/53ai/53aihub/issues):バグ報告・提案

## 認証取得

53AIは以下の国際認証を取得済み:

* **ISO/IEC 27001:2022 – 情報セキュリティマネジメントシステム**
* **ISO 9001:2015 – 品質マネジメントシステム**

## ライセンス

このリポジトリは [53AI オープンソースライセンス](https://docs.53ai.com/%E5%85%A5%E9%97%A8/%E5%BC%80%E6%BA%90%E8%AE%B8%E5%8F%AF%E5%8D%8F%E8%AE%AE) の下で提供されており、Apache 2.0をベースに追加制限が加えられています。

## フォローしよう

GitHubで53AI Hubにスターを付けると、最新のアップデート通知を受け取ることができます。



================================================
FILE: api/.gitattributes
================================================
saas/** merge=ours

================================================
FILE: api/.gitignore
================================================
.idea
.vscode
upload
*.exe
*.db
build
*.db-journal
logs
data
/web/node_modules
cmd.md
.env
temp
.DS_Store
__debug_bin*
static/uploads/*
static/console/*
static/front/*
bin/.env
bin/*hub
docs/*
saas/
build-restart-develop.sh
send-build-msg.sh
.envkm
.envhub
53AIHub
AI_TASK.txt
.tasks/*
.env*

================================================
FILE: api/Dockerfile
================================================
FROM golang:1.24.1 as builder

# 设置工作目录
WORKDIR /app

# 设置GOPROXY为中国大陆代理
ENV GOPROXY=https://goproxy.cn,direct

# 安装构建依赖(使用阿里云Debian镜像源)
RUN echo "deb https://mirrors.aliyun.com/debian/ bookworm main contrib non-free\n\
deb https://mirrors.aliyun.com/debian/ bookworm-updates main contrib non-free\n\
deb https://mirrors.aliyun.com/debian-security bookworm-security main" > /etc/apt/sources.list && \
    apt-get update -o Acquire::Retries=3 -o Acquire::http::Timeout=10 && \
    apt-get install -y --no-install-recommends gcc libc6-dev && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

# 复制go.mod和go.sum文件
COPY go.mod go.sum ./

# 下载依赖
RUN go mod download

# 复制源代码
COPY . .

# 构建应用 (修正CGO设置)
RUN CGO_ENABLED=1 go build -a -o /app/53AIHub -ldflags '-X "github.com/53AI/53AIHub/config.VersionTime=$(date +%Y%m%d%H%M%S)" -extldflags "-static"' ./main.go

# 使用精简的Alpine镜像作为运行时
FROM alpine:3.18

# 安装SQLite运行时依赖和C库
RUN apk --no-cache add ca-certificates sqlite libc6-compat

# 从构建阶段复制可执行文件
COPY --from=builder /app/53AIHub /app/

# 暴露端口
EXPOSE 3000

# 设置启动命令
CMD ["/app/53AIHub"]

================================================
FILE: api/Makefile
================================================
# Go parameters
GOBIN = go
GOFMT = gofmt
GOLINT = golangci-lint
GOTEST = go test
GOBUILD = go build
GOCLEAN = go clean

# Binary name
BINARY_NAME = 53aihub
BINARY_UNIX = $(BINARY_NAME)_unix

# Output directory
BIN_DIR = bin

# Build flags
BUILD_FLAGS = -v

.PHONY: all build clean test lint fmt

all: clean fmt lint test build

build:
	$(GOBUILD) $(BUILD_FLAGS) -o $(BIN_DIR)/$(BINARY_NAME) ./main.go

sbuild:
	$(GOBUILD) $(BUILD_FLAGS) -o $(BIN_DIR)/$(BINARY_NAME) -v -ldflags="-X 'github.com/53AI/53AIHub/config.VersionTime=$(shell date +%Y%m%d%H%M%S)' -linkmode external -extldflags '-static'" ./main.go

test:
	$(GOTEST) -v ./...

clean:
	$(GOCLEAN)
	rm -f $(BIN_DIR)/*

lint:
	$(GOLINT) run

fmt:
	$(GOFMT) -w .

# Cross compilation
build-linux:
	CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(GOBUILD) $(BUILD_FLAGS) -o $(BIN_DIR)/$(BINARY_UNIX) -v ./...

# Static build with no glibc dependency
swagger-init:
	swag init -g router/main.go --output docs/

static-build: swagger-init
	CGO_ENABLED=0 $(GOBUILD) -trimpath $(BUILD_FLAGS) -o $(BIN_DIR)/$(BINARY_NAME) -a -ldflags '-X "github.com/53AI/53AIHub/config.VersionTime=$(shell date +%Y%m%d%H%M%S)" -extldflags "-static"' ./main.go

# 交叉编译 Windows 版本 (启用 CGO 支持 go-sqlite3)
WIN_OS := windows
WIN_BITS := 64
WIN_DATE := $(shell date +%Y%m%d%H%M)
WIN_OUTPUT := $(BIN_DIR)/$(BINARY_NAME)_$(WIN_OS)_$(WIN_BITS)_$(WIN_DATE).exe

LINUX_OS := linux
LINUX_BITS := 64
LINUX_DATE := $(shell date +%Y%m%d%H%M)
LINUX_OUTPUT := $(BIN_DIR)/$(BINARY_NAME)_$(LINUX_OS)_$(LINUX_BITS)_$(LINUX_DATE)

static-build-with-info: swagger-init
	GOMAXPROCS=1 CGO_ENABLED=0 $(GOBUILD) -trimpath $(BUILD_FLAGS) -o $(LINUX_OUTPUT) -a -ldflags '-X "github.com/53AI/53AIHub/config.VersionTime=$(LINUX_DATE)" -extldflags "-static"' ./main.go

build-windows-cgo:
	@echo "开始交叉编译 Windows 可执行文件 (启用 CGO)..."
	@if ! command -v x86_64-w64-mingw32-gcc > /dev/null; then \
		echo "请先安装 MinGW 交叉编译工具链: sudo apt-get install -y gcc-mingw-w64"; \
		exit 1; \
	fi
	CGO_ENABLED=1 GOOS=windows GOARCH=amd64 CC=x86_64-w64-mingw32-gcc CGO_LDFLAGS="-static -static-libgcc" $(GOBUILD) -trimpath $(BUILD_FLAGS) -o $(WIN_OUTPUT) -ldflags '-X "github.com/53AI/53AIHub/config.VersionTime=$(WIN_DATE)" -s -w' ./main.go
	@echo "Windows 可执行文件已生成: $(WIN_OUTPUT)"

# 静态编译 Windows 版本 (完全静态链接,启用 CGO)
build-windows-static-cgo:
	@echo "开始静态编译 Windows 可执行文件 (启用 CGO)..."
	@if ! command -v x86_64-w64-mingw32-gcc > /dev/null; then \
		echo "请先安装 MinGW 交叉编译工具链: sudo apt-get install -y gcc-mingw-w64"; \
		exit 1; \
	fi
	CGO_ENABLED=1 GOOS=windows GOARCH=amd64 CC=x86_64-w64-mingw32-gcc CGO_LDFLAGS="-static -static-libgcc -static-libstdc++" $(GOBUILD) -trimpath  $(BUILD_FLAGS) -o $(WIN_OUTPUT) -ldflags '-X "github.com/53AI/53AIHub/config.VersionTime=$(WIN_DATE)" -s -w -H=windowsgui' ./main.go
	@echo "Windows 静态可执行文件已生成: $(WIN_OUTPUT)"

================================================
FILE: api/README.md
================================================
# 53AIHub 后端接口

53AIHub 是一个强大的 AI 代理管理平台,支持多种 AI 模型的接入和管理。本指南将帮助您快速上手并开始使用 53AIHub。

## 目录

- [53AIHub 后端接口](#53aihub-后端接口)
  - [目录](#目录)
  - [环境要求](#环境要求)
  - [快速开始](#快速开始)
    - [使用 Docker Compose 启动](#使用-docker-compose-启动)
    - [使用 Go 源码编译启动](#使用-go-源码编译启动)
    - [源代码编译启动](#源代码编译启动)
    - [使用预编译文件启动](#使用预编译文件启动)
  - [配置说明](#配置说明)
  - [常见问题排查](#常见问题排查)
    - [1. 服务无法启动](#1-服务无法启动)
    - [2. 数据库问题](#2-数据库问题)
    - [3. 微信支付配置](#3-微信支付配置)
    - [4. Token 编码器初始化失败](#4-token-编码器初始化失败)

## 环境要求

- Docker 和 Docker Compose (如使用容器化部署)
- Go 1.24+ (如从源码编译)

## 快速开始

1. 克隆仓库到本地

```bash
git clone https://github.com/53AI/53AIHub.git
cd 53AIHub
```

### 使用 Docker Compose 启动


2. 进入 docker 目录并启动服务

```bash
cd docker
docker compose up -d
```

这将启动 53AIHub 应用 (端口 3000 可在docker-compose.yml中修改)。

服务将在 `http://localhost:3000` 上运行。

### 使用 Go 源码编译启动

1. 确保你本地有 Go 语言环境和构建工具,以及node和npm环境
2. 先进入web目录构建前端的网页前台与管理后台(**非常重要**)
3. 再进入本目录,执行构建
```bash
make build-windows-cgo
```
4. 构建完成后,可执行文件将生成在 `bin` 目录下。
5. 运行可执行文件

### 源代码编译启动

1. 安装依赖并编译

```bash
go mod tidy
go build -o bin/53aihub main.go
```

3. 启动 53AIHub 服务

```bash
./bin/53aihub
```

服务将在默认端口上运行(通常是 3000,可通过.evn文件的 PORT 环境变量修改)。

### 使用预编译文件启动

1. 从 GitHub Releases 页面下载预编译文件

访问 [GitHub Releases](https://github.com/53AI/53AIHub/releases) 下载适合您操作系统的预编译文件。

2. 启动 53AIHub

- Linux/MacOS:
  
  ```bash
  chmod +x 53AIHub_linux
  ./53AIHub_linux
  ```
- Windows:
  双击 `53AIHub_install.exe` 文件安装运行启动

服务将在默认端口上`3000`运行。

## 配置说明

53AIHub 默认不需要任何配置即可启动,它使用以下默认配置:

- 数据库:SQLite(默认,无需配置)
- 端口:默认为 3000(可通过.env的 PORT 环境变量修改)

如果需要特定功能,可以配置以下环境变量:

- `SQL_DSN`: 数据库连接字符串,默认使用 SQLite
- `PORT`: 服务监听端口,默认为 3000
- `LOG_LEVEL`: 日志级别,可选值为 DEBUG、INFO(默认)
- `API_HOST`: API 主机地址,如需支持微信支付,必须配置此项

## 常见问题排查

### 1. 服务无法启动

- 检查端口是否被占用
- 查看日志文件中的错误信息

```bash
cat logs/53aihub.log
```

### 2. 数据库问题

默认情况下,53AIHub 使用 SQLite 数据库,无需额外配置。如果您配置了 MySQL 数据库但连接失败:

- 确认 MySQL 服务是否正常运行
- 检查数据库连接参数是否正确
- 确认数据库用户是否有足够的权限

### 3. 支付配置

如需支持微信支付功能、支付宝支付功能,必须配置 `API_HOST` 环境变量:

```bash
export API_HOST="http://your-domain.com"
```

或在启动时指定:

```bash
API_HOST="http://your-domain.com" ./53aihub
```

### 4. Token 编码器初始化失败

错误信息示例:

```
panic: runtime error: invalid memory address or nil pointer dereference
```

可能原因:

- billingratio.ModelRatio 为 nil
- logger 未正确初始化

解决方法:

- 确保在使用 logger 前已正确初始化

请注意:静态编译需要安装一些额外的依赖项(例如 GCC、G++、Git、Make),请查看 Makefile 中的静态编译命令,以获得更多信息。如果您的环境缺少这些依赖项,可能会导致静态编译失败。

错误信息示例2:

```
CGO_ENABLED=0 go build -trimpath -v -o bin/53aihub -a -ldflags '-X "github.com/53AI/53AIHub/config.VersionTime=20250817222030" -extldflags "-static"' ./main.go
main.go:18:29: pattern all:static/console: no matching files found
make: *** [Makefile:48: static-build] Error 1

可能原因:

- 没有先编绎前端

//go:embed all:static/front all:static/console static/images all:static/libs
上面这句的意思是打包前端资源,注意要先将前端打包成出来,分别放在static/front和static/console里
不熟悉go的请注意它就是这种注释语法
如果您遇到其他问题,请提交 GitHub Issue 获取支持。

```

```



================================================
FILE: api/bin/restart.sh
================================================
#!/bin/bash

# 1. 找到 53aihub 运行的 pid 
PID=$(ps aux | grep '[5]3aihub' | awk '{print $2}')

# 2. 优雅 kill 掉
if [ -n "$PID" ]; then
    echo "找到 53aihub 进程 PID: $PID,正在停止..."
    kill -15 $PID
    sleep 2 # 等待进程结束
else
    echo "未找到正在运行的 53aihub 进程"
fi

# 3. 后台运行 53aihub 并且输出日志到当前目录位置
echo "启动 53aihub..."
nohup ./53aihub > ./53aihub.log 2>&1 &

echo "53aihub 已启动,日志输出到 ./53aihub.log"


================================================
FILE: api/bin/version.txt
================================================
v0.1.0

================================================
FILE: api/build.sh
================================================
#!/bin/bash
make static-build

================================================
FILE: api/common/cache.go
================================================
package common


================================================
FILE: api/common/ctxkey/key.go
================================================
package ctxkey

const (
	Config            = "config"
	Id                = "id"
	Username          = "username"
	Role              = "role"
	Status            = "status"
	Channel           = "channel"
	ChannelId         = "channel_id"
	SpecificChannelId = "specific_channel_id"
	RequestModel      = "request_model"
	ConvertedRequest  = "converted_request"
	OriginalModel     = "original_model"
	Group             = "group"
	ModelMapping      = "model_mapping"
	ChannelName       = "channel_name"
	TokenId           = "token_id"
	TokenName         = "token_name"
	BaseURL           = "base_url"
	AvailableModels   = "available_models"
	KeyRequestBody    = "key_request_body"
	SystemPrompt      = "system_prompt"
)


================================================
FILE: api/common/email.go
================================================
package common

import (
	"crypto/rand"
	"crypto/tls"
	"errors"
	"fmt"
	"net/smtp"
	"regexp"
	"strings"
	"time"

	"github.com/53AI/53AIHub/model"
	"github.com/jordan-wright/email"
	"gorm.io/gorm"
)

// ValidateEmailFormat 验证基础邮箱格式(通用版)
func ValidateEmailFormat(email string) bool {
	pattern := `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$` // 通用邮箱格式验证(如user@domain.com)
	return regexp.MustCompile(pattern).MatchString(email)
}

// sendQQMailWithTLS 使用手动TLS连接发送QQ邮件
func sendQQMailWithTLS(e *email.Email, auth smtp.Auth, host string, port int) error {
	// 创建 TLS 配置
	tlsconfig := &tls.Config{
		InsecureSkipVerify: false,
		ServerName:         host,
	}

	// 连接到 SMTP 服务器
	addr := fmt.Sprintf("%s:%d", host, port)
	conn, err := tls.Dial("tcp", addr, tlsconfig)
	if err != nil {
		return fmt.Errorf("TLS connection failed: %v", err)
	}
	defer conn.Close()

	// 创建 SMTP 客户端
	client, err := smtp.NewClient(conn, host)
	if err != nil {
		return fmt.Errorf("SMTP client creation failed: %v", err)
	}
	defer client.Quit()

	// 认证
	if err = client.Auth(auth); err != nil {
		return fmt.Errorf("authentication failed: %v", err)
	}

	// 设置发件人和收件人
	if err = client.Mail(e.From); err != nil {
		return fmt.Errorf("sender setup failed: %v", err)
	}

	for _, recipient := range e.To {
		if err = client.Rcpt(recipient); err != nil {
			return fmt.Errorf("recipient setup failed: %v", err)
		}
	}

	// 写入邮件内容
	wc, err := client.Data()
	if err != nil {
		return fmt.Errorf("data writer creation failed: %v", err)
	}
	defer wc.Close()

	// 构建邮件内容
	var msg strings.Builder
	// 添加From
	msg.WriteString(fmt.Sprintf("From: %s\r\n", e.From))
	// 添加To
	msg.WriteString(fmt.Sprintf("To: %s\r\n", strings.Join(e.To, ", ")))
	// 添加Subject
	msg.WriteString(fmt.Sprintf("Subject: %s\r\n", e.Subject))

	// 添加其他头部信息
	for key, values := range e.Headers {
		for _, value := range values {
			msg.WriteString(fmt.Sprintf("%s: %s\r\n", key, value))
		}
	}

	// 添加空行分隔头部和正文
	msg.WriteString("\r\n")

	// 添加正文
	if len(e.HTML) > 0 {
		msg.Write(e.HTML)
	} else if len(e.Text) > 0 {
		msg.Write(e.Text)
	}

	// 发送邮件内容
	_, err = wc.Write([]byte(msg.String()))
	if err != nil {
		return fmt.Errorf("message sending failed: %v", err)
	}

	return nil
}

// SendEmail 使用jordan-wright/email库通过通用SMTP服务发送邮件
func SendEmail(e *email.Email, auth smtp.Auth, isSsl bool, host string, port int) error {
	addr := fmt.Sprintf("%s:%d", host, port)

	fmt.Printf("Sending email to %v via %s, SSL: %v, Port: %d\n", e.To, addr, isSsl, port)

	// 针对QQ邮箱等特殊处理
	isQQMail := strings.Contains(host, "qq.com")

	// 对于QQ邮箱且使用465端口,使用特殊处理方式
	if isQQMail && port == 465 {
		fmt.Printf("Using special handling for QQ mail on port 465\n")
		return sendQQMailWithTLS(e, auth, host, port)
	}

	if isSsl {
		tlsConfig := &tls.Config{
			InsecureSkipVerify: false,
			ServerName:         host,
		}

		if err := e.SendWithTLS(addr, auth, tlsConfig); err != nil {
			return fmt.Errorf("failed to send email via %s:%d: %w", host, port, err)
		}
	} else {
		if err := e.Send(addr, auth); err != nil {
			return fmt.Errorf("failed to send email via %s:%d: %w", host, port, err)
		}
	}
	return nil
}

// VerifyEmailCode 验证邮箱验证码有效性
func VerifyEmailCode(email, code string) (bool, error) {
	if email == "" || code == "" {
		return false, errors.New("missing email or code parameter")
	}

	now := time.Now().UTC().UnixMilli()
	var storedCode string
	// 优先从Redis获取验证码
	storedCode, err := RedisGet("email_verification:" + email)
	if err != nil || storedCode == "" {
		// Redis不存在时查询数据库
		var vc model.VerificationCode
		err = model.DB.Where("target = ? AND type = 'email' AND code = ? AND expires_at > ?", email, code, now).First(&vc).Error
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return false, errors.New("verification code expired or invalid")
			}
			return false, fmt.Errorf("database query error: %w", err)
		}
		storedCode = code
	}

	if storedCode != code {
		return false, errors.New(model.InvalidVerificationCode)
	}

	_ = RedisDel("email_verification:" + email)
	return true, nil
}

func GenerateRandomCode(length int) (string, error) {
	bytes := make([]byte, length)
	if _, err := rand.Read(bytes); err != nil {
		return "", err
	}
	for i := 0; i < length; i++ {
		bytes[i] = byte(48 + int(bytes[i])%10) // 0-9
	}
	return string(bytes), nil
}


================================================
FILE: api/common/init.go
================================================
package common

import (
	"flag"
	"fmt"
	"os"

	"github.com/53AI/53AIHub/config"
)

var (
	Port         = flag.Int("1port", 3000, "the listening port")
	PrintVersion = flag.Bool("1version", false, "print version and exit")
	PrintHelp    = flag.Bool("1help", false, "print help and exit")
	LogDir       = flag.String("1log-dir", "./logs", "specify the log directory")
)

func printHelp() {
	// TODO: print help
	fmt.Println("53AIHub Api " + config.Version + " - Fast, simple, and efficient AI WebSite.")
	fmt.Println("Copyright (C) 2025 Liuzimu. All rights reserved.")
	fmt.Println("GitHub: xxx")
	fmt.Println("Usage: 53AIHub [--port <port>] [--log-dir <log directory>] [--version] [--help]")
}

func Init() {
	flag.Parse()

	if *PrintHelp {
		printHelp()
		os.Exit(0) // 仅在 --help 参数存在时退出
	}

	if *PrintVersion {
		fmt.Println(config.Version)
		os.Exit(0) // 仅在 --version 参数存在时退出
	}

	// Initialize the logger
	InitRedisClient()
	InitLocker()
}


================================================
FILE: api/common/lock.go
================================================
package common

import (
	"context"
	"sync"
	"time"

	"github.com/53AI/53AIHub/common/logger"
	"github.com/go-redis/redis/v8"
)

var LOCKER Locker

func InitLocker() {
	if RedisEnabled {
		LOCKER = NewRedisLock(RDB)
	} else {
		LOCKER = NewLocalLock()
	}
}

type Locker interface {
	// TryLock 尝试获取锁
	// name: 锁名称
	// ttl: 锁的存活时间
	// 返回是否获取成功
	TryLock(name string, ttl time.Duration) bool

	// Unlock 释放锁
	Unlock(name string)
}

func NewLocalLock() *LocalLock {
	return &LocalLock{}
}

type LocalLock struct {
	locks sync.Map // key: lockName, value: *lockEntry
}

type lockEntry struct {
	mu        sync.Mutex
	expiresAt time.Time
}

// TryLock 尝试获取锁,如果成功返回true,否则返回false
// name: 锁名称
// ttl: 锁的存活时间
func (ll *LocalLock) TryLock(name string, ttl time.Duration) bool {
	now := time.Now()
	entry, loaded := ll.locks.LoadOrStore(name, &lockEntry{
		expiresAt: now.Add(ttl),
	})

	le := entry.(*lockEntry)
	le.mu.Lock()
	logger.SysLogf("lock: %s", name)

	// 检查锁是否已过期
	if now.After(le.expiresAt) {
		le.expiresAt = now.Add(ttl)
		le.mu.Unlock()
		return true
	}

	if loaded {
		le.mu.Unlock()
		return false
	}

	// 新创建的锁,启动定时器自动释放
	time.AfterFunc(ttl, func() {
		le.mu.Lock()
		defer le.mu.Unlock()
		ll.locks.Delete(name)
		logger.SysLogf("lock %s expired, unlock", name)
	})

	le.mu.Unlock()
	return true
}

// Unlock 手动释放锁
func (ll *LocalLock) Unlock(name string) {
	if entry, ok := ll.locks.Load(name); ok {
		le := entry.(*lockEntry)
		le.mu.Lock()
		defer le.mu.Unlock()
		ll.locks.Delete(name)
	}
}

type RedisLock struct {
	client redis.Cmdable
}

func NewRedisLock(client redis.Cmdable) *RedisLock {
	return &RedisLock{client: client}
}

func (rl *RedisLock) TryLock(name string, ttl time.Duration) bool {
	ctx := context.Background()
	// 使用SET NX EX实现原子操作
	result, err := rl.client.SetNX(ctx, "lock:"+name, "1", ttl).Result()
	return err == nil && result
}

func (rl *RedisLock) Unlock(name string) {
	ctx := context.Background()
	rl.client.Del(ctx, "lock:"+name)
}


================================================
FILE: api/common/logger/logger.go
================================================
package logger

import (
	"context"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/53AI/53AIHub/common/utils/helper"
	"github.com/53AI/53AIHub/config"
	"github.com/gin-gonic/gin"
)

type loggerLevel string

const (
	loggerDEBUG loggerLevel = "DEBUG"
	loggerINFO  loggerLevel = "INFO"
	loggerWARN  loggerLevel = "WARN"
	loggerERROR loggerLevel = "ERROR"
	loggerFATAL loggerLevel = "FATAL"
	loggerNONE  loggerLevel = "NONE"
)

var (
	setupLogOnce sync.Once
	// Current log level, initialized from environment variable
	currentLogLevel loggerLevel = loggerINFO
)

// Initialize the logger system with environment variables
func init() {
	// Get log level from environment variable, default to INFO if not set
	envLogLevel := os.Getenv("LOG_LEVEL")
	if envLogLevel != "" {
		switch strings.ToUpper(envLogLevel) {
		case string(loggerDEBUG):
			currentLogLevel = loggerDEBUG
		case string(loggerINFO):
			currentLogLevel = loggerINFO
		case string(loggerWARN):
			currentLogLevel = loggerWARN
		case string(loggerERROR):
			currentLogLevel = loggerERROR
		case string(loggerFATAL):
			currentLogLevel = loggerFATAL
		case string(loggerNONE):
			currentLogLevel = loggerNONE
		default:
			// If invalid level is provided, default to INFO
			currentLogLevel = loggerINFO
		}
	}
}

// SetLogLevel allows programmatically setting the log level
func SetLogLevel(level string) {
	switch strings.ToUpper(level) {
	case string(loggerDEBUG):
		currentLogLevel = loggerDEBUG
	case string(loggerINFO):
		currentLogLevel = loggerINFO
	case string(loggerWARN):
		currentLogLevel = loggerWARN
	case string(loggerERROR):
		currentLogLevel = loggerERROR
	case string(loggerFATAL):
		currentLogLevel = loggerFATAL
	case string(loggerNONE):
		currentLogLevel = loggerNONE
	default:
		// If invalid level is provided, default to INFO
		currentLogLevel = loggerINFO
	}
}

// GetLogLevel returns the current log level
func GetLogLevel() string {
	return string(currentLogLevel)
}

// shouldLog determines if a log message should be output based on its level
func shouldLog(level loggerLevel) bool {
	if currentLogLevel == loggerNONE {
		return false
	}

	switch currentLogLevel {
	case loggerDEBUG:
		return true
	case loggerINFO:
		return level != loggerDEBUG
	case loggerWARN:
		return level != loggerDEBUG && level != loggerINFO
	case loggerERROR:
		return level == loggerERROR || level == loggerFATAL
	case loggerFATAL:
		return level == loggerFATAL
	default:
		return true
	}
}

func SetupLogger() {
	setupLogOnce.Do(func() {
		if config.LogDir != "" {
			var logPath string
			if config.OnlyOneLogFile {
				logPath = filepath.Join(config.LogDir, "53AIHub.log")
			} else {
				logPath = filepath.Join(config.LogDir, fmt.Sprintf("53AIHub-%s.log", time.Now().Format("20060102")))
			}
			fd, err := os.OpenFile(logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
			if err != nil {
				log.Fatal("failed to open log file")
			}
			gin.DefaultWriter = io.MultiWriter(os.Stdout, fd)
			gin.DefaultErrorWriter = io.MultiWriter(os.Stderr, fd)
		}
	})
}

func SysLog(s string) {
	logHelper(nil, loggerINFO, s)
}

func SysLogf(format string, a ...any) {
	logHelper(nil, loggerINFO, fmt.Sprintf(format, a...))
}

func SysWarn(s string) {
	logHelper(nil, loggerWARN, s)
}

func SysWarnf(format string, a ...any) {
	logHelper(nil, loggerWARN, fmt.Sprintf(format, a...))
}

func SysError(s string) {
	logHelper(nil, loggerERROR, s)
}

func SysErrorf(format string, a ...any) {
	logHelper(nil, loggerERROR, fmt.Sprintf(format, a...))
}

func Debug(ctx context.Context, msg string) {
	logHelper(ctx, loggerDEBUG, msg)
}

func Info(ctx context.Context, msg string) {
	logHelper(ctx, loggerINFO, msg)
}

func Warn(ctx context.Context, msg string) {
	logHelper(ctx, loggerWARN, msg)
}

func Error(ctx context.Context, msg string) {
	logHelper(ctx, loggerERROR, msg)
}

func Debugf(ctx context.Context, format string, a ...any) {
	logHelper(ctx, loggerDEBUG, fmt.Sprintf(format, a...))
}

func Infof(ctx context.Context, format string, a ...any) {
	logHelper(ctx, loggerINFO, fmt.Sprintf(format, a...))
}

func Warnf(ctx context.Context, format string, a ...any) {
	logHelper(ctx, loggerWARN, fmt.Sprintf(format, a...))
}

func Errorf(ctx context.Context, format string, a ...any) {
	logHelper(ctx, loggerERROR, fmt.Sprintf(format, a...))
}

func FatalLog(s string) {
	logHelper(nil, loggerFATAL, s)
}

func FatalLogf(format string, a ...any) {
	logHelper(nil, loggerFATAL, fmt.Sprintf(format, a...))
}

func logHelper(ctx context.Context, level loggerLevel, msg string) {
	// Check if this log level should be output
	if !shouldLog(level) {
		return
	}

	writer := gin.DefaultErrorWriter
	if level == loggerINFO {
		writer = gin.DefaultWriter
	}
	var requestId string
	if ctx != nil {
		rawRequestId := helper.GetRequestID(ctx)
		if rawRequestId != "" {
			requestId = fmt.Sprintf(" | %s", rawRequestId)
		}
	}
	lineInfo, funcName := getLineInfo()
	now := time.Now()
	_, _ = fmt.Fprintf(writer, "[%s] %v%s%s %s%s \n", level, now.Format("2006/01/02 - 15:04:05"), requestId, lineInfo, funcName, msg)
	SetupLogger()
	if level == loggerFATAL {
		os.Exit(1)
	}
}

func getLineInfo() (string, string) {
	funcName := "[unknown] "
	pc, file, line, ok := runtime.Caller(3)
	if ok {
		if fn := runtime.FuncForPC(pc); fn != nil {
			parts := strings.Split(fn.Name(), ".")
			funcName = "[" + parts[len(parts)-1] + "] "
		}
	} else {
		file = "unknown"
		line = 0
	}
	parts := strings.Split(file, "one-api/")
	if len(parts) > 1 {
		file = parts[1]
	}
	return fmt.Sprintf(" | %s:%d", file, line), funcName
}


================================================
FILE: api/common/permission.go
================================================
package common

import (
	"github.com/53AI/53AIHub/model"
	"github.com/gin-gonic/gin"
)

func IsAdmin(c *gin.Context) bool {
	role, success := c.Get("SESSION_USER_ROLE")
	if success && role != nil {
		return role.(int64) >= model.RoleAdminUser
	}
	return false
}


================================================
FILE: api/common/redis.go
================================================
package common

import (
	"context"
	"errors"
	"strconv"
	"time"

	"github.com/53AI/53AIHub/common/logger"
	"github.com/53AI/53AIHub/config"
	"github.com/go-redis/redis/v8"
)

var RDB redis.Cmdable
var RedisEnabled = true
var ErrRedisNotEnabled = errors.New("redis is not enabled")

// InitRedisClient
func InitRedisClient() error {
	if config.REDIS_CONN == "" {
		RedisEnabled = false
		logger.SysLog("REDIS_CONN not set, Redis is not enabled")
		return nil
	}

	logger.SysLog("Redis is enabled")
	opt, err := redis.ParseURL(config.REDIS_CONN)
	if err != nil {
		logger.FatalLog("Redis connection error: " + err.Error())
	}
	RDB = redis.NewClient(opt)

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	_, err = RDB.Ping(ctx).Result()
	if err != nil {
		logger.FatalLog("Redis test failed: " + err.Error())
	}
	return err
}

// checkRedisEnabled checks if Redis is enabled and logs a warning if not
// Returns true if Redis is enabled, false otherwise
func checkRedisEnabled() bool {
	if !RedisEnabled {
		logger.SysWarn("Redis operation attempted but Redis is not enabled")
		return false
	}
	return true
}

func IsRedisEnabled() bool {
	return RedisEnabled
}

func RedisSet(key string, value string, expiration time.Duration) error {
	if !checkRedisEnabled() {
		return ErrRedisNotEnabled
	}
	ctx := context.Background()
	return RDB.Set(ctx, key, value, expiration).Err()
}

func RedisGet(key string) (string, error) {
	if !checkRedisEnabled() {
		return "", ErrRedisNotEnabled
	}
	ctx := context.Background()
	return RDB.Get(ctx, key).Result()
}

func RedisDel(key string) error {
	if !checkRedisEnabled() {
		return ErrRedisNotEnabled
	}
	ctx := context.Background()
	return RDB.Del(ctx, key).Err()
}

func RedisDecrease(key string, value int64) error {
	if !checkRedisEnabled() {
		return ErrRedisNotEnabled
	}
	ctx := context.Background()
	return RDB.DecrBy(ctx, key, value).Err()
}

// RedisZAdd adds a member to a sorted set
// key: the key of the sorted set
// score: the score used for ordering
// member: the member to be added
// Returns the number of new members added and any error that occurred
func RedisZAdd(key string, score int64, member string) (int64, error) {
	if !checkRedisEnabled() {
		return 0, ErrRedisNotEnabled
	}
	ctx := context.Background()
	z := redis.Z{
		Score:  float64(score),
		Member: member,
	}
	return RDB.ZAdd(ctx, key, &z).Result()
}

// RedisZRangeByScore gets elements within a score range from a sorted set
// key: the key of the sorted set
// min: minimum score
// max: maximum score
// Returns all members in the specified range and any error that occurred
func RedisZRangeByScore(key string, min, max int64) ([]string, error) {
	if !checkRedisEnabled() {
		return nil, ErrRedisNotEnabled
	}
	ctx := context.Background()
	opt := &redis.ZRangeBy{
		Min: strconv.FormatInt(min, 10),
		Max: strconv.FormatInt(max, 10),
	}
	return RDB.ZRangeByScore(ctx, key, opt).Result()
}

// RedisZRem removes a member from a sorted set
// key: the key of the sorted set
// member: the member to be removed
// Returns the number of members removed and any error that occurred
func RedisZRem(key string, member string) (int64, error) {
	if !checkRedisEnabled() {
		return 0, ErrRedisNotEnabled
	}
	ctx := context.Background()
	return RDB.ZRem(ctx, key, member).Result()
}

// RedisZRemRangeByScore removes all elements within a score range from a sorted set
// key: the key of the sorted set
// min: minimum score
// max: maximum score
// Returns the number of members removed and any error that occurred
func RedisZRemRangeByScore(key string, min, max int64) (int64, error) {
	if !checkRedisEnabled() {
		return 0, ErrRedisNotEnabled
	}
	ctx := context.Background()
	return RDB.ZRemRangeByScore(ctx, key, strconv.FormatInt(min, 10), strconv.FormatInt(max, 10)).Result()
}

// RedisZCount counts the number of elements within a score range in a sorted set
// key: the key of the sorted set
// min: minimum score
// max: maximum score
// Returns the count of members in the specified range and any error that occurred
func RedisZCount(key string, min, max int64) (int64, error) {
	if !checkRedisEnabled() {
		return 0, ErrRedisNotEnabled
	}
	ctx := context.Background()
	return RDB.ZCount(ctx, key, strconv.FormatInt(min, 10), strconv.FormatInt(max, 10)).Result()
}

// RedisExists checks if a key exists
// key: the key to check
// Returns the number of existing keys and any error that occurred
func RedisExists(key string) (int64, error) {
	if !checkRedisEnabled() {
		return 0, ErrRedisNotEnabled
	}
	ctx := context.Background()
	return RDB.Exists(ctx, key).Result()
}

// RedisExpire sets an expiration time for a key
// key: the key to set expiration for
// expiration: the expiration duration
// Returns whether the expiration was set successfully and any error that occurred
func RedisExpire(key string, expiration time.Duration) (bool, error) {
	if !checkRedisEnabled() {
		return false, ErrRedisNotEnabled
	}
	ctx := context.Background()
	return RDB.Expire(ctx, key, expiration).Result()
}


================================================
FILE: api/common/session/key.go
================================================
package session

const (
	SESSION_USER_ID          = "SESSION_USER_ID"
	SESSION_USER_NICKNAME    = "SESSION_USER_NICKNAME"
	SESSION_USER_ROLE        = "SESSION_USER_ROLE"
	SESSION_USER_GROUP_ID    = "SESSION_USER_GROUP_ID"
	ENV_EID                  = "ENV_EID"
	SESSION_AGENT_MODEL      = "SESSION_AGENT_MODEL"
	SESSION_AGENT_ID         = "SESSION_AGENT_ID"
	SESSION_AGENT            = "SESSION_AGENT"
	SESSION_CONVERSATION_ID  = "SESSION_CONVERSATION_ID"
	SESSION_CONVERSATION     = "SESSION_CONVERSATION"
	SESSION_SAAS_USER        = "SESSION_SAAS_USER"
	SESSION_REQUEST_PROTOCOL = "SESSION_REQUEST_PROTOCOL"
	SESSION_REQUEST_DOMAIN   = "SESSION_REQUEST_DOMAIN"
	SESSION_ENV_VERSION      = "SESSION_ENV_VERSION"
)


================================================
FILE: api/common/storage/storage.go
================================================
package storage

import (
	"bytes"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"io"
	"mime/multipart"
	"os"
	"path"
	"path/filepath"
	"sync"

	"github.com/53AI/53AIHub/config"
	"github.com/aliyun/aliyun-oss-go-sdk/oss"
)

var StorageInstance Storage = NewStorage()

type Storage interface {
	Save(file []byte, fileName string) error
	Exists(fileName string) bool
	Delete(fileName string) error
	Load(fileName string) ([]byte, error)
	GetBasePath() string
}

type LocalStorage struct {
	BasePath string
	mu       sync.RWMutex
}

type AliyunOSSStorage struct {
	client          *oss.Client
	bucket          *oss.Bucket
	Endpoint        string
	AccessKeyID     string
	AccessKeySecret string
	BucketName      string
	BasePath        string
}

func NewStorage() Storage {
	switch config.StorageType {
	case "aliyun_oss":
		client, err := oss.New(config.AliyunOssEndpoint, config.AliyunOssAccessKeyID, config.AliyunOssAccessKeySecret)
		if err != nil {
			panic(fmt.Errorf("failed to create oss client: %w", err))
		}
		bucket, err := client.Bucket(config.AliyunOssBucketName)
		if err != nil {
			panic(fmt.Errorf("failed to get oss bucket: %w", err))
		}
		return &AliyunOSSStorage{
			client:          client,
			bucket:          bucket,
			Endpoint:        config.AliyunOssEndpoint,
			AccessKeyID:     config.AliyunOssAccessKeyID,
			AccessKeySecret: config.AliyunOssAccessKeySecret,
			BucketName:      config.AliyunOssBucketName,
			BasePath:        config.StorageBasePath,
		}
	default:
		return &LocalStorage{BasePath: config.StorageBasePath}
	}
}

func (l *LocalStorage) Save(file []byte, fileName string) error {
	l.mu.Lock()
	defer l.mu.Unlock()

	if err := os.MkdirAll(path.Dir(fileName), 0755); err != nil {
		return fmt.Errorf("create dir error: %w", err)
	}

	if err := os.WriteFile(fileName, file, 0666); err != nil {
		return fmt.Errorf("write file error: %w", err)
	}

	return nil
}

func (l *LocalStorage) Exists(fileName string) bool {
	l.mu.RLock()
	defer l.mu.RUnlock()
	_, err := os.Stat(fileName)
	return !os.IsNotExist(err)
}

func (l *LocalStorage) Delete(fileName string) error {
	l.mu.Lock()
	defer l.mu.Unlock()
	err := os.Remove(fileName)
	if err != nil {
		return fmt.Errorf("remove file error: %w", err)
	}
	return nil
}

func (l *LocalStorage) Load(fileName string) ([]byte, error) {
	l.mu.RLock()
	defer l.mu.RUnlock()
	data, err := os.ReadFile(fileName)
	if err != nil {
		return nil, fmt.Errorf("read file error: %w", err)
	}
	return data, nil
}

func GetFileHash(file multipart.File) (string, error) {
	hash := sha256.New()
	if _, err := io.Copy(hash, file); err != nil {
		return "", err
	}

	if seeker, ok := file.(io.Seeker); ok {
		if _, err := seeker.Seek(0, io.SeekStart); err != nil {
			return "", fmt.Errorf("file seek error: %w", err)
		}
	}

	hashInBytes := hash.Sum(nil)
	return hex.EncodeToString(hashInBytes), nil
}

func (l *LocalStorage) GetBasePath() string {
	return l.BasePath
}

func (a *AliyunOSSStorage) Save(file []byte, fileName string) error {
	objectName := filepath.ToSlash(fileName)
	reader := bytes.NewReader(file)

	err := a.bucket.PutObject(objectName, reader)
	if err != nil {
		return fmt.Errorf("oss upload error: %w", err)
	}
	return nil
}

func (a *AliyunOSSStorage) Load(fileName string) ([]byte, error) {
	objectName := filepath.ToSlash(fileName)
	reader, err := a.bucket.GetObject(objectName)
	if err != nil {
		return nil, fmt.Errorf("oss file download error: %w", err)
	}
	defer reader.Close()
	return io.ReadAll(reader)
}

func (a *AliyunOSSStorage) Exists(fileName string) bool {
	objectName := filepath.ToSlash(fileName)
	exist, err := a.bucket.IsObjectExist(objectName)
	return err == nil && exist
}

func (a *AliyunOSSStorage) Delete(fileName string) error {
	objectName := filepath.ToSlash(fileName)
	if err := a.bucket.DeleteObject(objectName); err != nil {
		return fmt.Errorf("oss file delete error: %w", err)
	}
	return nil
}

func (a *AliyunOSSStorage) GetBasePath() string {
	return a.BasePath
}


================================================
FILE: api/common/storage/storage_test.go
================================================
package storage

import (
	"os"
	"path/filepath"
	"testing"
)

func TestSaveFile(t *testing.T) {
	// 创建 LocalStorage 实例
	tempDir := "../../static/uploads"
	localStorage := &LocalStorage{
		BasePath: "../../static/uploads",
	}

	fileContent := []byte("测试文件内容")
	fileName := "test.txt"
	err := localStorage.Save(fileContent, fileName)
	if err != nil {
		t.Errorf("保存文件失败: %v", err)
	}

	filePath := filepath.Join(tempDir, fileName)
	_, err = os.Stat(filePath)
	if err != nil {
		t.Errorf("文件不存在: %v", err)
	}

	localStorage.BasePath = "/invalid/path"
	err = localStorage.Save(fileContent, fileName)
	if err == nil {
		t.Errorf("创建目录失败时应返回错误")
	}
}


================================================
FILE: api/common/utils/ai53/api.go
================================================
package ai53

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strconv"
	"strings"
)

type AI53Api struct {
	BaseUrl   string
	AuthToken string
}

type AppResponse struct {
	BotID              string   `json:"bot_id"`
	Name               string   `json:"name"`
	Nickname           string   `json:"nickname"`
	Description        *string  `json:"description"`
	Logo               string   `json:"logo"`
	OpeningStatement   string   `json:"opening_statement"`
	SuggestedQuestions []string `json:"suggested_questions"`
	UpdatedAt          int64    `json:"updated_at"`
}

func (a *AI53Api) GetBaseURL() string {
	url := a.BaseUrl
	url = strings.TrimSuffix(url, "/")
	url = strings.TrimSuffix(url, "/v3")
	return url
}

func (a *AI53Api) GetApps(offset, limit int) ([]AppResponse, error) {
	url := a.GetBaseURL() + "/v3/apps"
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}

	q := req.URL.Query()
	q.Add("offset", strconv.Itoa(offset))
	q.Add("limit", strconv.Itoa(limit))
	req.URL.RawQuery = q.Encode()

	req.Header.Set("Authorization", "Bearer "+a.AuthToken)
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode >= 400 {
		return nil, fmt.Errorf("API request failed with status %d", resp.StatusCode)
	}

	body, _ := io.ReadAll(resp.Body)
	// logger.SysLogf("AI53 GetApps response: %s", string(body))

	var result []AppResponse
	if err := json.Unmarshal(body, &result); err != nil {
		return nil, err
	}

	return result, nil
}

func (a *AI53Api) GetWorkflows(offset, limit int) ([]AppResponse, error) {
	url := a.GetBaseURL() + "/v3/workflows"
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}

	q := req.URL.Query()
	q.Add("offset", strconv.Itoa(offset))
	q.Add("limit", strconv.Itoa(limit))
	req.URL.RawQuery = q.Encode()

	req.Header.Set("Authorization", "Bearer "+a.AuthToken)
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode >= 400 {
		return nil, fmt.Errorf("API request failed with status %d", resp.StatusCode)
	}

	body, _ := io.ReadAll(resp.Body)
	// logger.SysLogf("AI53 GetWorkflows response: %s", string(body))

	var result []AppResponse
	if err := json.Unmarshal(body, &result); err != nil {
		return nil, err
	}

	return result, nil
}

// cleanBotId 清理 botId,去掉可能的前缀
func (a *AI53Api) cleanBotId(botId string) string {
	// 去掉 "bot-" 前缀
	if strings.HasPrefix(botId, "bot-") {
		return strings.TrimPrefix(botId, "bot-")
	}

	// 去掉 "workflow-" 前缀
	if strings.HasPrefix(botId, "workflow-") {
		return strings.TrimPrefix(botId, "workflow-")
	}

	// 直接返回原始 botId
	return botId
}

// GetAppParameters 获取 53AI 应用参数配置
func (a *AI53Api) GetAppParameters(botId string) (interface{}, error) {
	// 清理 botId (去掉可能的前缀)
	cleanBotId := a.cleanBotId(botId)

	// 构建 URL (使用 53AI 的 v3 端点)
	url := a.GetBaseURL() + "/v3/parameters"

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Authorization", "Bearer "+a.AuthToken)
	req.Header.Set("Bot-Id", cleanBotId)
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode >= 400 {
		return nil, fmt.Errorf("API request failed with status %d", resp.StatusCode)
	}

	body, _ := io.ReadAll(resp.Body)

	var result interface{}
	if err := json.Unmarshal(body, &result); err != nil {
		return nil, err
	}

	return result, nil
}


================================================
FILE: api/common/utils/appbuilder/api.go
================================================
package appbuilder

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strings"

	"github.com/53AI/53AIHub/common/logger"
)

type AppBuilderApi struct {
	BaseUrl   string
	AuthToken string
}

// AppInfo represents application information
// @Description Application information structure
type AppInfo struct {
	// ID is the unique identifier of the application
	// @Example "app_1234567890"
	ID string `json:"id"`

	// Name is the display name of the application
	// @Example "My Awesome App"
	Name string `json:"name"`

	// Description provides details about the application
	// @Example "This is a sample application for demonstration purposes"
	Description string `json:"description"`

	// AppType indicates the type of the application
	// @Example "chatbot"
	AppType string `json:"appType"`

	// IsPublished shows whether the application is published
	// @Example true
	IsPublished bool `json:"isPublished"`

	// UpdateTime is the last update timestamp in Unix time format
	// @Example 1672531200
	UpdateTime int64 `json:"updateTime"`
}

type DescribeAppsResponse struct {
	RequestId   string    `json:"requestId"`
	Data        []AppInfo `json:"data"`
	Marker      string    `json:"marker"`
	IsTruncated bool      `json:"isTruncated"`
	NextMarker  string    `json:"nextMarker"`
	MaxKeys     int       `json:"maxKeys"`
}

func (a *AppBuilderApi) DescribeApps(marker string, maxKeys int) (*DescribeAppsResponse, error) {
	url := a.BaseUrl + "/v2/app?Action=DescribeApps"
	var payload interface{}
	if marker == "" {
		payload = map[string]interface{}{
			"maxKeys": maxKeys,
		}
	} else {
		payload = map[string]interface{}{
			"marker":  marker,
			"maxKeys": maxKeys,
		}
	}

	headers := map[string]string{
		"Content-Type":  "application/json",
		"Authorization": "Bearer " + a.AuthToken,
	}

	resp, err := a.doRequest("POST", url, payload, headers)
	if err != nil {
		return nil, err
	}

	payloadBytes, _ := json.Marshal(payload)
	logger.SysLogf("AppBuilder DescribeApps request: URL: %s, Payload: %s", url, string(payloadBytes))
	logger.SysLogf("AppBuilder DescribeApps response: Body: %s", string(resp))
	var result DescribeAppsResponse
	err = json.Unmarshal(resp, &result)
	if err != nil {
		return nil, err
	}

	return &result, nil
}

type ConversationResponse struct {
	RequestId      string `json:"request_id"`
	ConversationId string `json:"conversation_id"`
}

type ErrorResponse struct {
	RequestId string `json:"request_id"`
	Code      string `json:"code"`
	Message   string `json:"message"`
}

func (a *AppBuilderApi) CreateConversation(appId string) (*ConversationResponse, error) {
	url := a.BaseUrl + "/v2/app/conversation"
	payload := map[string]interface{}{
		"app_id": appId,
	}

	headers := map[string]string{
		"Content-Type":  "application/json",
		"Authorization": "Bearer " + a.AuthToken,
	}

	resp, err := a.doRequest("POST", url, payload, headers)
	if err != nil {
		return nil, err
	}

	payloadBytes, _ := json.Marshal(payload)
	logger.SysLogf("AppBuilder CreateConversation request: URL: %s, Payload: %s", url, string(payloadBytes))
	logger.SysLogf("AppBuilder CreateConversation response: Body: %s", string(resp))

	if strings.Contains(string(resp), "code") {
		var errorResp ErrorResponse
		err = json.Unmarshal(resp, &errorResp)
		if err != nil {
			return nil, err
		}
		return nil, fmt.Errorf("API error: %s (%s)", errorResp.Message, errorResp.Code)
	}

	var result ConversationResponse
	err = json.Unmarshal(resp, &result)
	if err != nil {
		return nil, err
	}

	return &result, nil
}

func (a *AppBuilderApi) doRequest(method, url string, payload interface{}, headers map[string]string) ([]byte, error) {
	payloadBytes, err := json.Marshal(payload)
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest(method, url, bytes.NewBuffer(payloadBytes))
	if err != nil {
		return nil, err
	}

	for key, value := range headers {
		req.Header.Set(key, value)
	}

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode >= 400 {
		return nil, fmt.Errorf("request failed with status %d: %s", resp.StatusCode, string(body))
	}

	return body, nil
}


================================================
FILE: api/common/utils/coze/api.go
================================================
package coze

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"

	"github.com/53AI/53AIHub/model"
)

type CozeApi struct {
	BaseUrl string
}

const (
	CozeCnUrl  = "https://api.coze.cn"
	CozeComUrl = "https://api.coze.com"
)

type CozeApiTokenResponse struct {
	AccessToken  string `json:"access_token"`
	RefreshToken string `json:"refresh_token"`
	ExpiresIn    int64  `json:"expires_in"`
}

func (c *CozeApi) doRequest(method, url string, payload interface{}, headers map[string]string) ([]byte, error) {
	payloadBytes, err := json.Marshal(payload)
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest(method, url, bytes.NewBuffer(payloadBytes))
	if err != nil {
		return nil, err
	}

	for key, value := range headers {
		req.Header.Set(key, value)
	}

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode >= 400 {
		return nil, fmt.Errorf("request failed with status %d: %s", resp.StatusCode, string(body))
	}

	return body, nil
}

func (c *CozeApi) GetOAuthToken(clientID, clientSecret, code, redirectURI string) (*CozeApiTokenResponse, error) {
	url := c.BaseUrl + "/api/permission/oauth2/token"
	payload := map[string]string{
		"grant_type":   "authorization_code",
		"code":         code,
		"client_id":    clientID,
		"redirect_uri": redirectURI,
	}

	headers := map[string]string{
		"Content-Type":  "application/json",
		"Authorization": "Bearer " + clientSecret,
	}

	resp, err := c.doRequest("POST", url, payload, headers)
	if err != nil {
		return nil, err
	}

	var result CozeApiTokenResponse
	err = json.Unmarshal(resp, &result)
	if err != nil {
		return nil, err
	}

	if result.AccessToken == "" || result.RefreshToken == "" || result.ExpiresIn == 0 {
		return nil, fmt.Errorf("invalid token response: %s", string(resp))
	}
	return &result, nil
}

func (c *CozeApi) RefreshOAuthToken(clientID, clientSecret, refreshToken string) (*CozeApiTokenResponse, error) {
	url := c.BaseUrl + "/api/permission/oauth2/token"
	payload := map[string]string{
		"grant_type":    "refresh_token",
		"refresh_token": refreshToken,
		"client_id":     clientID,
	}

	headers := map[string]string{
		"Content-Type":  "application/json",
		"Authorization": "Bearer " + clientSecret,
	}

	resp, err := c.doRequest("POST", url, payload, headers)
	if err != nil {
		return nil, err
	}

	var result CozeApiTokenResponse
	err = json.Unmarshal(resp, &result)
	if err != nil {
		return nil, err
	}

	if result.AccessToken == "" || result.RefreshToken == "" || result.ExpiresIn == 0 {
		return nil, fmt.Errorf("invalid token response: %s", string(resp))
	}
	return &result, nil
}

type Workspace struct {
	ID            string `json:"id"`
	Name          string `json:"name"`
	IconURL       string `json:"icon_url"`
	RoleType      string `json:"role_type"`
	WorkspaceType string `json:"workspace_type"`
}

type WorkspacesResponse struct {
	TotalCount int         `json:"total_count"`
	Workspaces []Workspace `json:"workspaces"`
}

type Bot struct {
	BotID       string `json:"bot_id"`
	BotName     string `json:"bot_name"`
	Description string `json:"description"`
	IconURL     string `json:"icon_url"`
	PublishTime string `json:"publish_time"`
}

type PublishedBotsResponse struct {
	SpaceBots []Bot `json:"space_bots"`
	Total     int   `json:"total"`
}

// IsTokenExpired checks if token is expired (with 5 minutes buffer time)
func IsTokenExpired(provider *model.Provider) bool {
	return time.Now().Unix()+300 >= provider.CreatedTime+provider.ExpiresIn
}

// RefreshTokenIfNeeded refreshes token if it's about to expire
func (c *CozeApi) RefreshTokenIfNeeded(provider *model.Provider) error {
	if !IsTokenExpired(provider) {
		return nil
	}

	var config model.CozeConfig
	if err := json.Unmarshal([]byte(provider.Configs), &config); err != nil {
		return fmt.Errorf("failed to parse provider config: %w", err)
	}

	resp, err := c.RefreshOAuthToken(config.ClientID, config.ClientSecret, provider.RefreshToken)
	if err != nil {
		// If refresh token expired, mark provider as unauthorized
		if strings.Contains(err.Error(), "invalid_grant") || strings.Contains(err.Error(), "invalid_refresh_token") {
			provider.IsAuthorized = false
			if updateErr := model.UpdateProvider(provider); updateErr != nil {
				return fmt.Errorf("failed to update provider authorization status: %w", updateErr)
			}
			return fmt.Errorf("refresh token expired, reauthorization required: %w", err)
		}
		return fmt.Errorf("failed to refresh token: %w", err)
	}

	provider.AccessToken = resp.AccessToken
	provider.RefreshToken = resp.RefreshToken
	provider.ExpiresIn = resp.ExpiresIn
	provider.CreatedTime = time.Now().Unix()

	return model.UpdateProvider(provider)
}

// GetWorkspaces retrieves list of workspaces
func (c *CozeApi) GetWorkspaces(provider *model.Provider, pageNum int, pageSize int) (*WorkspacesResponse, error) {
	if err := c.RefreshTokenIfNeeded(provider); err != nil {
		return nil, err
	}

	url := c.BaseUrl + "/v1/workspaces"
	query := fmt.Sprintf("?page_num=%d&page_size=%d", pageNum, pageSize)
	url = url + query

	// Log request details
	fmt.Printf("GetWorkspaces: Provider ID %d, URL: %s\n", provider.ProviderID, url)
	fmt.Printf("GetWorkspaces: AccessToken: %s...\n", provider.AccessToken[:min(len(provider.AccessToken), 20)])

	headers := map[string]string{
		"Content-Type":  "application/json",
		"Authorization": "Bearer " + provider.AccessToken,
	}

	resp, err := c.doRequest("GET", url, nil, headers)
	if err != nil {
		fmt.Printf("GetWorkspaces: Request failed for provider %d: %v\n", provider.ProviderID, err)
		return nil, err
	}

	fmt.Printf("GetWorkspaces: Raw response for provider %d: %s\n", provider.ProviderID, string(resp))

	var result struct {
		Data WorkspacesResponse `json:"data"`
		Code int                `json:"code"`
		Msg  string             `json:"msg"`
	}
	if err := json.Unmarshal(resp, &result); err != nil {
		return nil, err
	}

	if result.Code != 0 {
		return nil, fmt.Errorf("request failed with code %d: %s", result.Code, result.Msg)
	}

	fmt.Printf("GetWorkspaces: Found %d workspaces for provider %d\n", len(result.Data.Workspaces), provider.ProviderID)
	return &result.Data, nil
}

// GetPublishedBots retrieves list of published bots
func (c *CozeApi) GetPublishedBots(provider *model.Provider, spaceID string, pageIndex int, pageSize int) (*PublishedBotsResponse, error) {
	if err := c.RefreshTokenIfNeeded(provider); err != nil {
		return nil, err
	}

	url := c.BaseUrl + "/v1/space/published_bots_list"
	query := fmt.Sprintf("?space_id=%s&page_size=%d&page_index=%d", spaceID, pageSize, pageIndex)
	url = url + query

	headers := map[string]string{
		"Content-Type":  "application/json",
		"Authorization": "Bearer " + provider.AccessToken,
	}

	resp, err := c.doRequest("GET", url, nil, headers)
	if err != nil {
		return nil, err
	}

	var result struct {
		Data PublishedBotsResponse `json:"data"`
		Code int                   `json:"code"`
		Msg  string                `json:"msg"`
	}
	if err := json.Unmarshal(resp, &result); err != nil {
		return nil, err
	}

	if result.Code != 0 {
		return nil, fmt.Errorf("request failed with code %d: %s", result.Code, result.Msg)
	}

	return &result.Data, nil
}


================================================
FILE: api/common/utils/env/env.go
================================================
package env

import (
	"os"
	"strconv"

	_ "github.com/joho/godotenv/autoload"
)

func Int(env string, defaultValue int) int {
	if env == "" || os.Getenv(env) == "" {
		return defaultValue
	}
	num, err := strconv.Atoi(os.Getenv(env))
	if err != nil {
		return defaultValue
	}
	return num
}

func Int64(env string, defaultValue int64) int64 {
	if env == "" || os.Getenv(env) == "" {
		return defaultValue
	}
	num, err := strconv.ParseInt(os.Getenv(env), 10, 64)
	if err != nil {
		return defaultValue
	}
	return num
}

func Float64(env string, defaultValue float64) float64 {
	if env == "" || os.Getenv(env) == "" {
		return defaultValue
	}
	num, err := strconv.ParseFloat(os.Getenv(env), 64)
	if err != nil {
		return defaultValue
	}
	return num
}

func String(env string, defaultValue string) string {
	if env == "" || os.Getenv(env) == "" {
		return defaultValue
	}
	return os.Getenv(env)
}

func Bool(env string, defaultValue bool) bool {
	if env == "" || os.Getenv(env) == "" {
		return defaultValue
	}
	return os.Getenv(env) == "true"
}


================================================
FILE: api/common/utils/helper/helper.go
================================================
package helper

import (
	"context"
	"crypto/md5"
	"fmt"
	"math/rand"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"
)

func GetRequestID(ctx context.Context) string {
	rawRequestId := ctx.Value(RequestIdKey)
	if rawRequestId == nil {
		return ""
	}
	return rawRequestId.(string)
}

const Chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

func RandomString(n int) string {
	rand.Seed(time.Now().UnixNano())
	key := make([]byte, n)
	for i := 0; i < n; i++ {
		key[i] = Chars[rand.Intn(len(Chars))]
	}
	return string(key)
}

func PasswordHash(password string, salt string) (string, error) {
	// md5(password+salt)
	combined := password + salt
	hash := md5.Sum([]byte(combined))
	return fmt.Sprintf("%x", hash), nil
}

var sizeKB = 1024
var sizeMB = sizeKB * 1024
var sizeGB = sizeMB * 1024

func Bytes2Size(num int64) string {
	numStr := ""
	unit := "B"
	if num/int64(sizeGB) > 1 {
		numStr = fmt.Sprintf("%.2f", float64(num)/float64(sizeGB))
		unit = "GB"
	} else if num/int64(sizeMB) > 1 {
		numStr = fmt.Sprintf("%d", int(float64(num)/float64(sizeMB)))
		unit = "MB"
	} else if num/int64(sizeKB) > 1 {
		numStr = fmt.Sprintf("%d", int(float64(num)/float64(sizeKB)))
		unit = "KB"
	} else {
		numStr = fmt.Sprintf("%d", num)
	}
	return numStr + " " + unit
}

func ParseSize(sizeStr string) (int64, error) {
	sizeStr = strings.TrimSpace(sizeStr)
	unitIndex := strings.IndexAny(sizeStr, "kKmMgG")
	if unitIndex == -1 {
		return strconv.ParseInt(sizeStr, 10, 64)
	}

	numStr := sizeStr[:unitIndex]
	num, err := strconv.ParseInt(numStr, 10, 64)
	if err != nil {
		return 0, err
	}

	unit := strings.ToUpper(sizeStr[unitIndex:])
	switch unit {
	case "K", "KB":
		return num * 1024, nil
	case "M", "MB":
		return num * 1024 * 1024, nil
	case "G", "GB":
		return num * 1024 * 1024 * 1024, nil
	default:
		return 0, nil
	}
}

func CalcElapsedTime(start time.Time) int64 {
	return time.Now().Sub(start).Milliseconds()
}

// IsValidPhone validates if the input is a valid phone number
// Supports international phone numbers in various formats
func IsValidPhone(phone string) bool {
	phone = regexp.MustCompile(`[\s\-\(\)]`).ReplaceAllString(phone, "")

	if phone == "" {
		return false
	}

	if strings.HasPrefix(phone, "+") {
		numPart := phone[1:]
		if regexp.MustCompile(`^\d{7,15}$`).MatchString(numPart) {
			return true
		}
	}

	if regexp.MustCompile(`^1[3-9]\d{9}$`).MatchString(phone) {
		return true
	}

	if regexp.MustCompile(`^\d{7,15}$`).MatchString(phone) {
		return true
	}

	return false
}

// IsValidEmail validates if the input is a valid email address
func IsValidEmail(email string) bool {
	// Simple email format validation
	match, _ := regexp.MatchString(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`, email)
	return match
}

func HasIntersection(a, b []int64) bool {
	if len(a) > len(b) {
		a, b = b, a
	}
	set := make(map[int64]struct{}, len(a))
	for _, v := range a {
		set[v] = struct{}{}
	}
	for _, v := range b {
		if _, ok := set[v]; ok {
			return true
		}
	}
	return false
}

func GetHost(u string) (string, error) {
	parsed, err := url.Parse(u)
	if err != nil {
		return "", err
	}

	host := parsed.Scheme + "://" + parsed.Host
	return host, nil
}

func StrInArray(str string, arr []string) bool {
	for _, v := range arr {
		if v == str {
			return true
		}
	}
	return false
}


================================================
FILE: api/common/utils/helper/key.go
================================================
package helper

const (
	RequestIdKey = "X-Request-Id"
)


================================================
FILE: api/common/utils/helper/sso_sign.go
================================================
package helper

import (
	"crypto/md5"
	"fmt"
)

// BuildSSORawString 构造原始签名串:timestamp={10位}&username={规范化用户名}{secret}
func BuildSSORawString(timestamp string, normalizedUsername string, secret string) string {
	return fmt.Sprintf("timestamp=%s&username=%s%s", timestamp, normalizedUsername, secret)
}

// CalcSSOSignLowerHex 计算 MD5 并返回小写十六进制字符串(UTF-8)
func CalcSSOSignLowerHex(raw string) string {
	sum := md5.Sum([]byte(raw))
	return fmt.Sprintf("%x", sum)
}


================================================
FILE: api/common/utils/huawei_cloud/model.go
================================================
package huawei_cloud

type HuaweicloudBaseResponse struct {
	ResultCode string `json:"resultCode"`
	ResultMsg  string `json:"resultMsg"`
}

type HuaweicloudCallbackRequest struct {
	Activity string `json:"activity"`
	TestFlag string `json:"testFlag"`
}

type HuaweicloudCallbackQuery struct {
	Signature string `form:"signature"`
	Timestamp int64  `form:"timestamp"`
	Nonce     string `form:"nonce"`
}

const (
	SUCCESS = "000000"
)

const (
	SUCCESS_MSG = "success"
)

type CreateInstanceResponse struct {
	HuaweicloudBaseResponse
	InstanceId string `json:"instanceId"`
}

func GetSuccess() HuaweicloudBaseResponse {
	return HuaweicloudBaseResponse{
		ResultCode: SUCCESS,
		ResultMsg:  SUCCESS_MSG,
	}
}

type HuaweiCloudBody struct {
	Activity    string `json:"activity"`
	BusinessId  string `json:"businessId"`
	OrderId     string `json:"orderId"`
	OrderLineId string `json:"orderLineId"`
	InstanceId  string `json:"instanceId"` // 查询实例信息时使用
	TestFlag    string `json:"testFlag"`

	// 更新实例相关字段
	Scene      string `json:"scene"`      // 场景:TRIAL_TO_FORMAL, RENEWAL, UNSUBSCRIBE_RENEWAL_PERIOD
	ProductId  string `json:"productId"`  // 产品标识
	ExpireTime string `json:"expireTime"` // 过期时间 yyyyMMddHHmmss

	// 更新实例状态相关字段
	Status string `json:"status"` // 状态:FROZEN, UNFROZEN

	// 升级实例相关字段
	NewProductId string `json:"newProductId"` // 新产品标识
}

// 查询实例信息响应结构
type QueryInstanceResponse struct {
	HuaweicloudBaseResponse
	Info []InstanceInfo `json:"info"`
}

type InstanceInfo struct {
	InstanceId string  `json:"instanceId"`
	AppInfo    AppInfo `json:"appInfo"`
}

type AppInfo struct {
	FrontEndUrl string `json:"frontEndUrl"` // 前台地址
	AdminUrl    string `json:"adminUrl"`    // 管理地址
	UserName    string `json:"userName"`    // 管理员账号
	Password    string `json:"password"`    // 管理员密码
	Memo        string `json:"memo"`        // 备注
}


================================================
FILE: api/common/utils/huawei_cloud/signature.go
================================================
package huawei_cloud

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"errors"
	"fmt"
	"math"
	"strconv"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

type IMessageResp struct {
	ResultCode string
	ResultMsg  string
}

const (
	TIMESTAMP = "timestamp"
	NONCE     = "nonce"
	SIGNATURE = "signature"
	TIME_DIFF = 60 * time.Second
)

func VerifySignature(c *gin.Context, accessKey string) error {
	// 从请求中获取时间戳
	timestamp := c.Query("timestamp")
	if timestamp == "" {
		return errors.New("缺少时间戳")
	}

	// 获取请求体
	body, err := c.GetRawData()
	if err != nil {
		return errors.New("获取请求体失败")
	}

	// 验证时间
	if !validateReqTime(timestamp) {
		return errors.New("时间戳无效")
	}

	// 获取随机字符串
	nonce := c.Query("nonce")
	if nonce == "" {
		return errors.New("缺少随机字符串")
	}

	// 获取签名
	signature := c.Query("signature")
	if signature == "" {
		return errors.New("缺少签名")
	}

	// 生成签名并验证
	generatedSig := generateSignature(accessKey, body, timestamp, nonce)
	if !strings.EqualFold(signature, generatedSig) {
		return errors.New("签名验证失败")
	}

	return nil
}

func generateSignature(accessKey string, body []byte, timestamp string, nonce string) string {
	// 计算请求体HMAC-SHA256哈希
	bodyHash := hmacSHA256(body, accessKey)

	// 构建规范请求字符串
	canonicalRequest := fmt.Sprintf("%s%s%s%s",
		accessKey, nonce, timestamp, strings.ToLower(hex.EncodeToString(bodyHash)))

	// 计算最终签名
	signature := hmacSHA256([]byte(canonicalRequest), accessKey)
	return strings.ToLower(hex.EncodeToString(signature))
}

// 辅助函数:计算HMAC-SHA256
func hmacSHA256(data []byte, key string) []byte {
	h := hmac.New(sha256.New, []byte(key))
	h.Write(data)
	return h.Sum(nil)
}

func validateReqTime(timestamp string) bool {
	reqTime, err := strconv.ParseInt(timestamp, 10, 64)
	if err != nil {
		return false
	}

	// 华为云时间戳是毫秒级,转换为秒
	reqTime = reqTime / 1000
	currentTime := time.Now().Unix()

	// 允许60秒的时间差
	return math.Abs(float64(currentTime-reqTime)) <= 60
}


================================================
FILE: api/common/utils/ip.go
================================================
package utils

import (
	"strings"

	"github.com/gin-gonic/gin"
)

// GetClientIP 获取请求客户端真实IP
// 优先级:X-Real-Ip > X-Forwarded-For > RemoteAddr
func GetClientIP(c *gin.Context) string {
	// 尝试从X-Real-Ip获取
	ip := c.GetHeader("X-Real-Ip")
	if ip != "" {
		return ip
	}

	// 尝试从X-Forwarded-For获取(取第一个IP)
	xForwardedFor := c.GetHeader("X-Forwarded-For")
	if xForwardedFor != "" {
		ips := strings.Split(xForwardedFor, ",")
		if len(ips) > 0 {
			ip = strings.TrimSpace(ips[0])
			if ip != "" {
				return ip
			}
		}
	}

	// 尝试从X-Client-Ip获取(兼容部分代理)
	ip = c.GetHeader("X-Client-Ip")
	if ip != "" {
		return ip
	}

	// 最后使用RemoteAddr(可能包含端口,需要解析)
	remoteAddr := c.Request.RemoteAddr
	if idx := strings.LastIndex(remoteAddr, ":"); idx > 0 {
		return remoteAddr[:idx]
	}
	return remoteAddr
}


================================================
FILE: api/common/utils/jwt/jwt.go
================================================
package jwt

import (
	"time"

	"github.com/53AI/53AIHub/common/utils/env"
	"github.com/golang-jwt/jwt/v5"
)

var secretKey = []byte(env.String("JWT_SECRET", "secret"))

func UserGenerateJWT(userID int64, eid int64) (string, error) {
	claims := jwt.MapClaims{
		"user_id": userID,
		"eid":     eid,
		"exp":     time.Now().Add(168 * time.Hour).Unix(),
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString(secretKey)
}

func UserParseJWT(tokenString string) (int64, int64, error) {
	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		return secretKey, nil
	})

	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		// 判断是否存在 eid,如果不存在则是 saas 用户 token,这里登录无效
		if _, ok := claims["eid"]; !ok {
			// 返回无效 token 错误
			return 0, 0, jwt.ErrTokenInvalidClaims
		}
		return int64(claims["user_id"].(float64)),
			int64(claims["eid"].(float64)), nil
	}
	return 0, 0, err
}


================================================
FILE: api/common/utils/random.go
================================================
package utils

import (
	"math/rand"
	"time"
)

var randomGenerator *rand.Rand

func init() {
	source := rand.NewSource(time.Now().UnixNano())
	randomGenerator = rand.New(source)
}

func GetRandomInt64(n int64) int64 {
	if n <= 0 {
		return 0
	}
	return randomGenerator.Int63n(n)
}


================================================
FILE: api/common/utils/snowflake.go
================================================
package utils

import (
	"strconv"
	"sync"
	"time"
)

// Snowflake ID generator
type Snowflake struct {
	mutex      sync.Mutex
	timestamp  int64
	workerId   int64
	sequence   int64
	startEpoch int64
}

// NewSnowflake creates a new Snowflake ID generator
func NewSnowflake(workerId int64) *Snowflake {
	// Use 2023-01-01 00:00:00 as start epoch
	startEpoch := int64(1672531200000)
	return &Snowflake{
		timestamp:  0,
		workerId:   workerId & 0x3FF, // 10-bit worker ID
		sequence:   0,
		startEpoch: startEpoch,
	}
}

// NextId generates the next ID
func (s *Snowflake) NextId() int64 {
	s.mutex.Lock()
	defer s.mutex.Unlock()

	currentTimestamp := time.Now().UnixNano() / 1e6 // Timestamp in milliseconds

	// If current time is less than last timestamp, system clock has moved backwards
	if currentTimestamp < s.timestamp {
		// Simple handling: use the last timestamp
		currentTimestamp = s.timestamp
	}

	// If generating ID in same millisecond, increment sequence
	if currentTimestamp == s.timestamp {
		s.sequence = (s.sequence + 1) & 0xFFF // 12-bit sequence
		// Sequence overflow in same millisecond
		if s.sequence == 0 {
			// Block until next millisecond
			currentTimestamp = s.waitNextMillis(currentTimestamp)
		}
	} else {
		// Reset sequence for different timestamp
		s.sequence = 0
	}

	// Update last timestamp
	s.timestamp = currentTimestamp

	// Combine timestamp, worker ID and sequence to generate 64-bit ID
	// timestamp bits | worker ID bits | sequence bits
	return ((currentTimestamp - s.startEpoch) << 22) | (s.workerId << 12) | s.sequence
}

// waitNextMillis blocks until next millisecond
func (s *Snowflake) waitNextMillis(lastTimestamp int64) int64 {
	timestamp := time.Now().UnixNano() / 1e6
	for timestamp <= lastTimestamp {
		timestamp = time.Now().UnixNano() / 1e6
	}
	return timestamp
}

// Global Snowflake generator instance
var defaultSnowflake = NewSnowflake(1) // Using worker ID = 1

// GenerateOrderId generates a unique order ID that complies with WeChat Pay requirements
// Must be 6-32 characters, can only contain numbers, letters and specific symbols
func GenerateOrderId() string {
	// Generate base ID using Snowflake algorithm
	snowflakeId := defaultSnowflake.NextId()

	// Convert to base36 string (contains numbers and letters)
	// Base36: 0-9 and a-z
	baseId := strconv.FormatInt(snowflakeId, 36)

	// Add prefix for better identification
	prefix := "AH"

	// Combine order ID
	orderId := prefix + baseId

	// Ensure length is between 6-32
	if len(orderId) < 6 {
		// Add timestamp if too short
		orderId = orderId + time.Now().Format("150405")
	} else if len(orderId) > 32 {
		// Truncate if too long
		orderId = orderId[:32]
	}

	return orderId
}


================================================
FILE: api/common/utils/system/machine.go
================================================
package system

import (
	"bufio"
	"crypto/md5"
	"fmt"
	"net"
	"os"
	"runtime"
	"strings"

	"github.com/53AI/53AIHub/common/logger"
)

const (
	EnvFilePath = ".env"
)

// MachineInfo 机器信息结构
type MachineInfo struct {
	MachineCode string `json:"machine_code"`
	OS          string `json:"os"`
	Arch        string `json:"arch"`
	Hostname    string `json:"hostname"`
	Version     string `json:"version"`
}

// GenerateMachineCode 生成唯一机器码
func GenerateMachineCode() (string, error) {
	// 获取系统信息
	hostname, _ := os.Hostname()

	// 获取网络接口MAC地址
	interfaces, err := net.Interfaces()
	if err != nil {
		logger.SysLogf("Failed to get network interfaces: %v", err)
		return "", err
	}

	var macAddresses []string
	for _, iface := range interfaces {
		// 跳过回环接口和虚拟接口
		if iface.Flags&net.FlagLoopback != 0 || iface.Flags&net.FlagUp == 0 {
			continue
		}

		mac := iface.HardwareAddr.String()
		if mac != "" && mac != "00:00:00:00:00:00" {
			macAddresses = append(macAddresses, mac)
		}
	}

	// 构建唯一标识字符串
	identifier := fmt.Sprintf("%s-%s-%s-%s",
		hostname,
		runtime.GOOS,
		runtime.GOARCH,
		strings.Join(macAddresses, "-"))

	// 生成MD5哈希作为机器码
	hash := md5.New()
	hash.Write([]byte(identifier))
	machineCode := fmt.Sprintf("%x", hash.Sum(nil))

	logger.SysLogf("Generated machine code: %s", machineCode)
	return machineCode, nil
}

// GetMachineInfo 获取完整的机器信息
func GetMachineInfo() (*MachineInfo, error) {
	// 从环境变量或生成新的机器码
	machineCode, err := GetOrGenerateMachineCode()
	if err != nil {
		return nil, err
	}

	hostname, _ := os.Hostname()
	version := GetVersion()

	return &MachineInfo{
		MachineCode: machineCode,
		OS:          runtime.GOOS,
		Arch:        runtime.GOARCH,
		Hostname:    hostname,
		Version:     version,
	}, nil
}

// GetOrGenerateMachineCode 获取或生成机器码
func GetOrGenerateMachineCode() (string, error) {
	// 先尝试从环境变量中获取
	existingCode := os.Getenv("MACHINE_CODE")
	if existingCode != "" {
		logger.SysLogf("Using existing machine code from environment: %s", existingCode)
		return existingCode, nil
	}

	// 尝试从.env文件中读取
	envMap, err := readEnvFile()
	if err != nil {
		logger.SysLogf("Failed to read .env file: %v", err)
	} else {
		if code, exists := envMap["MACHINE_CODE"]; exists && code != "" {
			logger.SysLogf("Using existing machine code from .env file: %s", code)
			return code, nil
		}
	}

	// 生成新的机器码
	machineCode, err := GenerateMachineCode()
	if err != nil {
		return "", err
	}

	// 保存到.env文件
	if err := saveMachineCodeToEnv(machineCode); err != nil {
		logger.SysLogf("Failed to save machine code to .env file: %v", err)
		// 不返回错误,因为机器码已经生成成功
	}

	return machineCode, nil
}

// GetVersion 获取版本信息
func GetVersion() string {
	// 尝试从版本文件读取
	if content, err := os.ReadFile("bin/version.txt"); err == nil {
		version := strings.TrimSpace(string(content))
		if version != "" {
			return version
		}
	}

	// 尝试从环境变量读取
	if version := os.Getenv("VERSION"); version != "" {
		return version
	}

	// 默认版本
	return "1.0.0"
}

// readEnvFile 读取.env文件
func readEnvFile() (map[string]string, error) {
	file, err := os.Open(EnvFilePath)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	envMap := make(map[string]string)
	scanner := bufio.NewScanner(file)

	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if line == "" || strings.HasPrefix(line, "#") {
			continue
		}

		parts := strings.SplitN(line, "=", 2)
		if len(parts) == 2 {
			key := strings.TrimSpace(parts[0])
			value := strings.TrimSpace(parts[1])
			// 移除可能的引号
			value = strings.Trim(value, "\"'")
			envMap[key] = value
		}
	}

	return envMap, scanner.Err()
}

// writeEnvFile 写入.env文件
func writeEnvFile(envMap map[string]string) error {
	file, err := os.Create(EnvFilePath)
	if err != nil {
		return err
	}
	defer file.Close()

	writer := bufio.NewWriter(file)
	defer writer.Flush()

	for key, value := range envMap {
		_, err := writer.WriteString(fmt.Sprintf("%s=\"%s\"\n", key, value))
		if err != nil {
			return err
		}
	}

	return nil
}

// saveMachineCodeToEnv 保存机器码到.env文件
func saveMachineCodeToEnv(machineCode string) error {
	envMap, err := readEnvFile()
	if err != nil {
		// 如果文件不存在,创建新的映射
		envMap = make(map[string]string)
	}

	// 检查是否已存在
	if existingCode, exists := envMap["MACHINE_CODE"]; exists && existingCode != "" {
		logger.SysLogf("MACHINE_CODE already exists in .env file: %s, skipping update", existingCode)
		return nil
	}

	// 添加机器码
	envMap["MACHINE_CODE"] = machineCode

	// 写回文件
	if err := writeEnvFile(envMap); err != nil {
		return fmt.Errorf("failed to write .env file: %v", err)
	}

	logger.SysLogf("Successfully saved MACHINE_CODE=%s to %s", machineCode, EnvFilePath)
	return nil
}

// AppendToEnvFile 追加内容到.env文件(如果不存在的话)
func AppendToEnvFile(key, value string) error {
	envMap, err := readEnvFile()
	if err != nil {
		envMap = make(map[string]string)
	}

	// 检查是否已存在
	if existingValue, exists := envMap[key]; exists && existingValue != "" {
		logger.SysLogf("%s already exists in .env file: %s, skipping update", key, existingValue)
		return nil
	}

	// 添加新值
	envMap[key] = value

	// 写回文件
	if err := writeEnvFile(envMap); err != nil {
		return fmt.Errorf("failed to write .env file: %v", err)
	}

	logger.SysLogf("Successfully saved %s=%s to %s", key, value, EnvFilePath)
	return nil
}


================================================
FILE: api/common/utils/system/version.go
================================================
package system

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"time"

	"github.com/53AI/53AIHub/common/logger"
)

const (
	// VersionCheckURL 版本检查URL
	VersionCheckURL = "https://update.53ai.net/checkversion/53aihub/"
)

// VersionCheckResponse 版本检查响应
type VersionCheckResponse struct {
	CurrentVersion string `json:"current_version"`
	LatestVersion  string `json:"latest_version"`
	HasUpdate      bool   `json:"has_update"`
	UpdateURL      string `json:"update_url"`
	ReleaseNotes   string `json:"release_notes"`
	WebsiteId      string `json:"websiteid"`
	ServerURL      string `json:"serverurl"`
	Action         string `json:"action"`
}

// CheckVersion 检查版本更新
func CheckVersion() (*VersionCheckResponse, error) {
	logger.SysLog("Checking for version updates...")

	// 获取机器信息
	machineInfo, err := GetMachineInfo()
	if err != nil {
		logger.SysLogf("Failed to get machine info: %v", err)
		return nil, fmt.Errorf("获取机器信息失败: %v", err)
	}

	// 准备请求数据
	requestData := map[string]interface{}{
		"machine_code": machineInfo.MachineCode,
		"version":      machineInfo.Version,
		"os":           machineInfo.OS,
		"arch":         machineInfo.Arch,
		"hostname":     machineInfo.Hostname,
		"timestamp":    time.Now().Unix(),
		"action":       "install",
	}

	// 序列化请求数据
	jsonData, err := json.Marshal(requestData)
	if err != nil {
		logger.SysLogf("Failed to marshal request data: %v", err)
		return nil, fmt.Errorf("序列化请求数据失败: %v", err)
	}

	// 创建 HTTP 客户端
	client := &http.Client{
		Timeout: 10 * time.Second,
	}

	// 发送 POST 请求
	resp, err := client.Post(VersionCheckURL, "application/json", bytes.NewBuffer(jsonData))
	if err != nil {
		logger.SysLogf("Failed to check version: %v", err)
		return nil, fmt.Errorf("无法连接到版本检查服务器: %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body)
		logger.SysLogf("Version check failed with status %d: %s", resp.StatusCode, string(body))
		return nil, fmt.Errorf("版本检查失败,状态码: %d", resp.StatusCode)
	}

	var versionResp VersionCheckResponse
	if err := json.NewDecoder(resp.Body).Decode(&versionResp); err != nil {
		logger.SysLogf("Failed to parse version response: %v", err)
		return nil, fmt.Errorf("解析版本响应失败: %v", err)
	}

	logger.SysLogf("Version check completed. Current: %s, Latest: %s, HasUpdate: %v",
		versionResp.CurrentVersion, versionResp.LatestVersion, versionResp.HasUpdate)

	return &versionResp, nil
}

// CheckVersionAsync 异步检查版本更新
func CheckVersionAndReturn() (*VersionCheckResponse, string, error) {
	if resp, err := CheckVersion(); err != nil {
		logger.SysLogf("Async version check failed: %v", err)
		return resp, "", err
	} else {
		logger.SysLog("Async version check completed.")
		if resp.HasUpdate {
			logger.SysLogf("New version: %s, URL: %s", resp.LatestVersion, resp.UpdateURL)
		}
		if resp.ReleaseNotes != "" {
			logger.SysLogf("Release Notes:\n%s", resp.ReleaseNotes)
		}
		if resp.Action == "install" {
			logger.SysLog("开始执行站点配置流程...")

			// 1. 检查 .env 文件中是否已有 WEBSITE_ID
			existingID, exists, err := checkWebsiteIdExists()
			if err != nil {
				logger.SysErrorf("检查 WEBSITE_ID 失败: %v", err)
			}
			if exists {
				logger.SysLogf("检测到已配置的 WEBSITE_ID: %s,跳过创建流程", existingID)
			} else {
				addWebsiteIdToEnv(resp.WebsiteId)
				// 生成统计脚本
				statisticScript := fmt.Sprintf(`<script src="%s/script.js" data-website-id="%s"></script>`, resp.ServerURL, resp.WebsiteId)
				logger.SysLogf("Successfully generated and saved statistic script")
				return resp, statisticScript, nil
			}

		}
		return resp, "", nil
	}
}

// checkWebsiteIdExists 检查 .env 文件中是否已有 WEBSITE_ID
func checkWebsiteIdExists() (string, bool, error) {
	envMap, err := readEnvFile()
	if err != nil {
		return "", false, err
	}
	id, exists := envMap["WEBSITE_ID"]
	return id, exists && id != "", nil
}

// addWebsiteIdToEnv 添加 WEBSITE_ID 到 .env 文件
func addWebsiteIdToEnv(websiteId string) error {
	envMap, err := readEnvFile()
	if err != nil {
		return fmt.Errorf("读取 .env 文件失败: %v", err)
	}

	// 检查是否已存在
	if existingID, exists := envMap["WEBSITE_ID"]; exists && existingID != "" {
		logger.SysLogf("WEBSITE_ID 已存在: %s,跳过添加", existingID)
		return nil
	}

	// 添加新的 WEBSITE_ID
	envMap["WEBSITE_ID"] = websiteId

	// 写回文件
	if err := writeEnvFile(envMap); err != nil {
		return fmt.Errorf("写入 .env 文件失败: %v", err)
	}

	logger.SysLogf("成功将 WEBSITE_ID=%s 添加到 %s", websiteId, EnvFilePath)
	return nil
}


================================================
FILE: api/common/utils/wxbizjsonmsgcrypt/wxbizjsonmsgcrypt.go
================================================
package wxbizmsgcrypt

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/sha1"
	"encoding/base64"
	"encoding/binary"
	"encoding/xml"
	"fmt"
	"math/rand"
	"sort"
	"strings"
)

const letterBytes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

const (
	ValidateSignatureError int = -40001
	ParseXmlError          int = -40002
	ComputeSignatureError  int = -40003
	IllegalAesKey          int = -40004
	ValidateCorpidError    int = -40005
	EncryptAESError        int = -40006
	DecryptAESError        int = -40007
	IllegalBuffer          int = -40008
	EncodeBase64Error      int = -40009
	DecodeBase64Error      int = -40010
	GenXmlError            int = -40010
	ParseJsonError         int = -40012
	GenJsonError           int = -40013
	IllegalProtocolType    int = -40014
)

type ProtocolType int

const (
	XmlType ProtocolType = 1
)

type CryptError struct {
	ErrCode int
	ErrMsg  string
}

func NewCryptError(err_code int, err_msg string) *CryptError {
	return &CryptError{ErrCode: err_code, ErrMsg: err_msg}
}

type WXBizMsg4Recv struct {
	Tousername string `xml:"ToUserName"`
	Encrypt    string `xml:"Encrypt"`
	Agentid    string `xml:"AgentID"`
}

type CDATA struct {
	Value string `xml:",cdata"`
}

type WXBizMsg4Send struct {
	XMLName   xml.Name `xml:"xml"`
	Encrypt   CDATA    `xml:"Encrypt"`
	Signature CDATA    `xml:"MsgSignature"`
	Timestamp string   `xml:"TimeStamp"`
	Nonce     CDATA    `xml:"Nonce"`
}

func NewWXBizMsg4Send(encrypt, signature, timestamp, nonce string) *WXBizMsg4Send {
	return &WXBizMsg4Send{Encrypt: CDATA{Value: encrypt}, Signature: CDATA{Value: signature}, Timestamp: timestamp, Nonce: CDATA{Value: nonce}}
}

type ProtocolProcessor interface {
	parse(src_data []byte) (*WXBizMsg4Recv, *CryptError)
	serialize(msg_send *WXBizMsg4Send) ([]byte, *CryptError)
}

type WXBizMsgCrypt struct {
	token              string
	encoding_aeskey    string
	receiver_id        string
	protocol_processor ProtocolProcessor
}

type XmlProcessor struct {
}

func (self *XmlProcessor) parse(src_data []byte) (*WXBizMsg4Recv, *CryptError) {
	var msg4_recv WXBizMsg4Recv
	err := xml.Unmarshal(src_data, &msg4_recv)
	if nil != err {
		return nil, NewCryptError(ParseXmlError, "xml to msg fail")
	}
	return &msg4_recv, nil
}

func (self *XmlProcessor) serialize(msg4_send *WXBizMsg4Send) ([]byte, *CryptError) {
	xml_msg, err := xml.Marshal(msg4_send)
	if nil != err {
		return nil, NewCryptError(GenXmlError, err.Error())
	}
	return xml_msg, nil
}

func NewWXBizMsgCrypt(token, encoding_aeskey, receiver_id string, protocol_type ProtocolType) *WXBizMsgCrypt {
	var protocol_processor ProtocolProcessor
	if protocol_type != XmlType {
		panic("unsupport protocal")
	} else {
		protocol_processor = new(XmlProcessor)
	}

	return &WXBizMsgCrypt{token: token, encoding_aeskey: (encoding_aeskey + "="), receiver_id: receiver_id, protocol_processor: protocol_processor}
}

func (self *WXBizMsgCrypt) randString(n int) string {
	b := make([]byte, n)
	for i := range b {
		b[i] = letterBytes[rand.Int63()%int64(len(letterBytes))]
	}
	return string(b)
}

func (self *WXBizMsgCrypt) pKCS7Padding(plaintext string, block_size int) []byte {
	padding := block_size - (len(plaintext) % block_size)
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	var buffer bytes.Buffer
	buffer.WriteString(plaintext)
	buffer.Write(padtext)
	return buffer.Bytes()
}

func (self *WXBizMsgCrypt) pKCS7Unpadding(plaintext []byte, block_size int) ([]byte, *CryptError) {
	plaintext_len := len(plaintext)
	if nil == plaintext || plaintext_len == 0 {
		return nil, NewCryptError(DecryptAESError, "pKCS7Unpadding error nil or zero")
	}
	if plaintext_len%block_size != 0 {
		return nil, NewCryptError(DecryptAESError, "pKCS7Unpadding text not a multiple of the block size")
	}
	padding_len := int(plaintext[plaintext_len-1])
	return plaintext[:plaintext_len-padding_len], nil
}

func (self *WXBizMsgCrypt) cbcEncrypter(plaintext string) ([]byte, *CryptError) {
	aeskey, err := base64.StdEncoding.DecodeString(self.encoding_aeskey)
	if nil != err {
		return nil, NewCryptError(DecodeBase64Error, err.Error())
	}
	const block_size = 32
	pad_msg := self.pKCS7Padding(plaintext, block_size)

	block, err := aes.NewCipher(aeskey)
	if err != nil {
		return nil, NewCryptError(EncryptAESError, err.Error())
	}

	ciphertext := make([]byte, len(pad_msg))
	iv := aeskey[:aes.BlockSize]

	mode := cipher.NewCBCEncrypter(block, iv)

	mode.CryptBlocks(ciphertext, pad_msg)
	base64_msg := make([]byte, base64.StdEncoding.EncodedLen(len(ciphertext)))
	base64.StdEncoding.Encode(base64_msg, ciphertext)

	return base64_msg, nil
}

func (self *WXBizMsgCrypt) cbcDecrypter(base64_encrypt_msg string) ([]byte, *CryptError) {
	aeskey, err := base64.StdEncoding.DecodeString(self.encoding_aeskey)
	if nil != err {
		return nil, NewCryptError(DecodeBase64Error, err.Error())
	}

	encrypt_msg, err := base64.StdEncoding.DecodeString(base64_encrypt_msg)
	if nil != err {
		return nil, NewCryptError(DecodeBase64Error, err.Error())
	}

	block, err := aes.NewCipher(aeskey)
	if err != nil {
		return nil, NewCryptError(DecryptAESError, err.Error())
	}

	if len(encrypt_msg) < aes.BlockSize {
		return nil, NewCryptError(DecryptAESError, "encrypt_msg size is not valid")
	}

	iv := aeskey[:aes.BlockSize]

	if len(encrypt_msg)%aes.BlockSize != 0 {
		return nil, NewCryptError(DecryptAESError, "encrypt_msg not a multiple of the block size")
	}

	mode := cipher.NewCBCDecrypter(block, iv)

	mode.CryptBlocks(encrypt_msg, encrypt_msg)

	return encrypt_msg, nil
}

func (self *WXBizMsgCrypt) calSignature(timestamp, nonce, data string) string {
	sort_arr := []string{self.token, timestamp, nonce, data}
	sort.Strings(sort_arr)
	var buffer bytes.Buffer
	for _, value := range sort_arr {
		buffer.WriteString(value)
	}

	sha := sha1.New()
	sha.Write(buffer.Bytes())
	signature := fmt.Sprintf("%x", sha.Sum(nil))
	return string(signature)
}

func (self *WXBizMsgCrypt) ParsePlainText(plaintext []byte) ([]byte, uint32, []byte, []byte, *CryptError) {
	const block_size = 32
	plaintext, err := self.pKCS7Unpadding(plaintext, block_size)
	if nil != err {
		return nil, 0, nil, nil, err
	}

	text_len := uint32(len(plaintext))
	if text_len < 20 {
		return nil, 0, nil, nil, NewCryptError(IllegalBuffer, "plain is to small 1")
	}
	random := plaintext[:16]
	msg_len := binary.BigEndian.Uint32(plaintext[16:20])
	if text_len < (20 + msg_len) {
		return nil, 0, nil, nil, NewCryptError(IllegalBuffer, "plain is to small 2")
	}

	msg := plaintext[20 : 20+msg_len]
	receiver_id := plaintext[20+msg_len:]

	return random, msg_len, msg, receiver_id, nil
}

func (self *WXBizMsgCrypt) VerifyURL(msg_signature, timestamp, nonce, echostr string) ([]byte, *CryptError) {
	signature := self.calSignature(timestamp, nonce, echostr)

	if strings.Compare(signature, msg_signature) != 0 {
		return nil, NewCryptError(ValidateSignatureError, "signature not equal")
	}

	plaintext, err := self.cbcDecrypter(echostr)
	if nil != err {
		return nil, err
	}

	_, _, msg, receiver_id, err := self.ParsePlainText(plaintext)
	if nil != err {
		return nil, err
	}

	if len(self.receiver_id) > 0 && strings.Compare(string(receiver_id), self.receiver_id) != 0 {
		fmt.Println(string(receiver_id), self.receiver_id, len(receiver_id), len(self.receiver_id))
		return nil, NewCryptError(ValidateCorpidError, "receiver_id is not equil")
	}

	return msg, nil
}

func (self *WXBizMsgCrypt) EncryptMsg(reply_msg, timestamp, nonce string) ([]byte, *CryptError) {
	rand_str := self.randString(16)
	var buffer bytes.Buffer
	buffer.WriteString(rand_str)

	msg_len_buf := make([]byte, 4)
	binary.BigEndian.PutUint32(msg_len_buf, uint32(len(reply_msg)))
	buffer.Write(msg_len_buf)
	buffer.WriteString(reply_msg)
	buffer.WriteString(self.receiver_id)

	tmp_ciphertext, err := self.cbcEncrypter(buffer.String())
	if nil != err {
		return nil, err
	}
	ciphertext := string(tmp_ciphertext)

	signature := self.calSignature(timestamp, nonce, ciphertext)

	msg4_send := NewWXBizMsg4Send(ciphertext, signature, timestamp, nonce)
	return self.protocol_processor.serialize(msg4_send)
}

func (self *WXBizMsgCrypt) DecryptMsg(msg_signature, timestamp, nonce string, post_data []byte) ([]byte, *CryptError) {
	msg4_recv, crypt_err := self.protocol_processor.parse(post_data)
	if nil != crypt_err {
		return nil, crypt_err
	}

	signature := self.calSignature(timestamp, nonce, msg4_recv.Encrypt)

	if strings.Compare(signature, msg_signature) != 0 {
		return nil, NewCryptError(ValidateSignatureError, "signature not equal")
	}

	plaintext, crypt_err := self.cbcDecrypter(msg4_recv.Encrypt)
	if nil != crypt_err {
		return nil, crypt_err
	}

	_, _, msg, receiver_id, crypt_err := self.ParsePlainText(plaintext)
	if nil != crypt_err {
		return nil, crypt_err
	}

	if len(self.receiver_id) > 0 && strings.Compare(string(receiver_id), self.receiver_id) != 0 {
		return nil, NewCryptError(ValidateCorpidError, "receiver_id is not equil")
	}

	return msg, nil
}


================================================
FILE: api/common/validate.go
================================================
package common

import "github.com/go-playground/validator/v10"

var Validate *validator.Validate

func init() {
	Validate = validator.New()
}


================================================
FILE: api/config/config.go
================================================
package config

import (
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/53AI/53AIHub/common/session"
	"github.com/53AI/53AIHub/common/utils/env"
	"github.com/53AI/53AIHub/common/utils/helper"
	"github.com/gin-gonic/gin"
)

var Version = env.String("HUB_VERSION", "v0.1.0")

// build time make file
// go build -ldflags "-X 'config.VersionTime=$(date +%Y%m%d%H%M)'"
var VersionTime string
var Server = env.String("HUB_SERVER", "")
var LogDir = env.String("LOG_DIR", "")
var DebugEnabled = env.Bool("DEBUG", false)
var OnlyOneLogFile = env.Bool("ONLY_ONE_LOG_FILE", false)
var StartTime = time.Now().Format("2006-01-02 15:04:05")
var IS_SAAS = env.Bool("IS_SAAS", false)
var ApiHost = env.String("API_HOST", "")
var MigrateDBEnabled = env.Bool("MIGRATE_DB_ENABLED", true)

var REDIS_CONN = env.String("REDIS_CONN", "")
var MAX_UPLOAD_FILE_SIZE_STRING = env.String("MAX_UPLOAD_FILE_SIZE", "30MB")
var MAX_UPLOAD_FILE_SIZE, _ = helper.ParseSize(MAX_UPLOAD_FILE_SIZE_STRING)

var CHANNEL_RETRY_TIMES = env.Int64("CHANNEL_RETRY_TIMES", 3)
var EnforceIncludeUsage = env.Bool("ENFORCE_INCLUDE_USAGE", false)

var PreConsumedQuota int64 = 500
var WECOM_SUITE_ID = env.String("WECOM_SUITE_ID", "")
var IS_TEST_WECOM_SUITE = env.Bool("IS_TEST_WECOM_SUITE", false)
var HUAWEI_CLOUD_ACCESS_KEY = env.String("HUAWEI_CLOUD_ACCESS_KEY", "")
var DINGTALK_SUITE_ID = env.String("DINGTALK_SUITE_ID", "")

func GetApiHost() string {
	if !strings.HasSuffix(ApiHost, "/") {
		return ApiHost + "/"
	}
	return ApiHost
}

func GetEID(c *gin.Context) int64 {
	eid, success := c.Get(session.ENV_EID)
	if success && eid != nil {
		return eid.(int64)
	} else {
		return env.Int64("EID", 1)
	}
}

func GetUserId(c *gin.Context) int64 {
	user_id, success := c.Get(session.SESSION_USER_ID)
	if success && user_id != nil {
		return user_id.(int64)
	}
	return 0
}

func GetUserNickname(c *gin.Context) string {
	nickanme, success := c.Get(session.SESSION_USER_NICKNAME)
	if success && nickanme != nil {
		return nickanme.(string)
	}
	return ""
}

// GetUserGroup returns the group id of the user
func GetUserGroupID(c *gin.Context) int64 {
	group_id, success := c.Get(session.SESSION_USER_GROUP_ID)
	if success && group_id != nil {
		return group_id.(int64)
	}
	return 0
}

// GetProtocol returns the request protocol from session
func GetProtocol(c *gin.Context) string {
	protocol, success := c.Get(session.SESSION_REQUEST_PROTOCOL)
	if success && protocol != nil {
		return protocol.(string)
	}
	return "http"
}

// GetDomain returns the request domain from session
func GetDomain(c *gin.Context) string {
	domain, success := c.Get(session.SESSION_REQUEST_DOMAIN)
	if success && domain != nil {
		return domain.(string)
	}
	return ""
}

func GetServer(c *gin.Context) string {
	return Server
}

func Getwd() string {
	workDir, err := os.Getwd()
	if err != nil {
		return ""
	}
	return workDir
}

func GetBinScriptPath(shName string) string {
	workDir := Getwd()
	base := filepath.Base(workDir)
	if base == "bin" {
		return filepath.Join(workDir, shName)
	} else {
		return filepath.Join(workDir, "bin", shName)
	}
}

func GetWecomSuiteID() string {
	return WECOM_SUITE_ID
}

func GetDingtalkSuiteID() string {
	return DINGTALK_SUITE_ID
}

func GetUserRole(c *gin.Context) int64 {
	role, success := c.Get(session.SESSION_USER_ROLE)
	if success && role != nil {
		return role.(int64)
	}
	return 0 // 默认返回 0,表示无权限或未登录
}


================================================
FILE: api/config/database.go
================================================
package config

import "github.com/53AI/53AIHub/common/utils/env"

var UsingSQLite = false
var UsingPostgreSQL = false
var UsingMySQL = false
var DebugSQLEnabled = env.Bool("DEBUG_SQL", false)

var SQLitePath = "53ai-hub.db"
var SQLiteBusyTimeout = env.Int("SQLITE_BUSY_TIMEOUT", 3000)


================================================
FILE: api/config/encryption.go
================================================
package config

import (
	"os"
)

// GetEncryptionKey returns the encryption key for sensitive data
func GetEncryptionKey() string {
	// In production, this should be a secure key stored in environment variables
	// or a secure key management system
	key := os.Getenv("53AIHub_ENCRYPTION_KEY")
	if key == "" {
		// Fallback to a default key (not recommended for production)
		key = "default-encryption-key-32-bytes-long"
	}
	return key
}


================================================
FILE: api/config/storage.go
================================================
package config

import "github.com/53AI/53AIHub/common/utils/env"

var StorageType = env.String("STORAGE", "local")
var StorageBasePath = env.String("BASE_PATH", "static/uploads")
var AliyunOssAccessKeyID = env.String("ALIYUN_OSS_ACCESS_KEY_ID", "")
var AliyunOssAccessKeySecret = env.String("ALIYUN_OSS_ACCESS_KEY_SECRET", "")
var AliyunOssEndpoint = env.String("ALIYUN_OSS_ENDPOINT", "")
var AliyunOssBucketName = env.String("ALIYUN_OSS_BUCKET_NAME", "")


================================================
FILE: api/controller/agent.go
================================================
package controller

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"strconv"
	"strings"

	"github.com/53AI/53AIHub/common"
	"github.com/53AI/53AIHub/common/utils"
	"github.com/53AI/53AIHub/config"
	"github.com/53AI/53AIHub/model"
	"github.com/53AI/53AIHub/service"
	"github.com/gin-gonic/gin"
)

type AgentListRequest struct {
	Keyword      string `json:"keyword" form:"keyword" example:"Json"`
	GroupId      int64  `json:"group_id" form:"group_id" example:"0"`
	Offset       int    `json:"offset" form:"offset" example:"0"`
	Limit        int    `json:"limit" form:"limit" example:"10"`
	ChannelTypes string `json:"channel_types" form:"channel_types" example:"0,1,2"`
	AgentTypes   string `json:"agent_types" form:"agent_types" example:"0,1,2"`
}

type AgentsResponse struct {
	Count  int64          `json:"count"`
	Agents []*model.Agent `json:"agents"`
}

type AgentRequest struct {
	Name                 string  `json:"name" example:"OpenAI-ChatGPT"`
	Logo                 string  `json:"logo" example:"http://URL_ADDRESS.com/logo.png"`
	Sort                 int     `json:"sort" example:"0"`
	Description          string  `json:"description" example:"A ChatGPT based agent for general conversation"`
	Configs              string  `json:"configs" example:"{\"model\":\"gpt-3.5-turbo\",\"temperature\":0.7}"`
	Prompt               string  `json:"prompt" example:"You are a helpful AI assistant"`
	ChannelType          int     `json:"channel_type"`
	Model                string  `json:"model" example:"gpt-3.5-turbo"`
	GroupId              int64   `json:"group_id" example:"0"`
	UseCases             string  `json:"use_cases" example:"[]"`
	Tools                string  `json:"tools"  example:"[]"`
	CustomConfig         string  `json:"custom_config" example:"{}"`
	UserGroupIds         []int64 `json:"user_group_ids"`
	Enable               bool    `json:"enable" example:"true"`
	SubscriptionGroupIds []int64 `json:"subscription_group_ids"` // 订阅分组IDs
	Settings             string  `json:"settings" example:"{}"`
	AgentType            int     `json:"agent_type" example:"0"` // Agent type (0=App, 1=Workflow), default is 0
}

type UpdateAgentEnableRequest struct {
	Enable *bool `json:"enable" example:"true" binding:"required"` // Enable status (true=enabled, false=disabled)
}

// @Summary Create a new agent
// @Description Create agent with configurable parameters. agent_type: 0=App (default), 1=Workflow
// @Tags Agent
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param Agent body AgentRequest true "Agent Data"
// @Success 200 {object} model.CommonResponse{data=model.Agent} "Success"
// @Router /api/agents [post]
func CreateAgent(c *gin.Context) {
	var agentReq AgentRequest
	if err := c.ShouldBindJSON(&agentReq); err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(nil))
		return
	}
	// Check if user is admin
	if !common.IsAdmin(c) {
		c.JSON(http.StatusForbidden, model.AuthFailed.ToResponse(nil))
		return
	}

	agentReq.Model = model.ProcessModelNames(agentReq.Model, agentReq.ChannelType)
	if agentReq.Model == "" {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(errors.New("model is required")))
		return
	}

	params := map[string]interface{}{
		"from": "agent",
	}
	_, err := service.IsFeatureAvailable(c, "agent", params)
	if err != nil {
		c.JSON(http.StatusForbidden, model.FeatureNotAvailableError.ToResponse(err))
		return
	}

	// Start transaction
	tx := model.DB.Begin()
	if tx.Error != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
		return
	}

	agent := model.Agent{
		Eid:          config.GetEID(c),
		Name:         agentReq.Name,
		Logo:         agentReq.Logo,
		ChannelType:  agentReq.ChannelType,
		Sort:         agentReq.Sort,
		Description:  agentReq.Description,
		Model:        agentReq.Model,
		Prompt:       agentReq.Prompt,
		Configs:      agentReq.Configs,
		Tools:        agentReq.Tools,
		CustomConfig: agentReq.CustomConfig,
		GroupID:      agentReq.GroupId,
		UseCases:     agentReq.UseCases,
		CreatedBy:    config.GetUserId(c),
		Enable:       agentReq.Enable,
		Settings:     agentReq.Settings,
		AgentType:    agentReq.AgentType, // 添加 AgentType 字段,默认为 0
	}

	if err := tx.Create(&agent).Error; err != nil {
		tx.Rollback()
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
		return
	}

	allGroupIds := make([]int64, 0)

	if len(agentReq.SubscriptionGroupIds) > 0 {
		allGroupIds = append(allGroupIds, agentReq.SubscriptionGroupIds...)
	}

	if len(agentReq.UserGroupIds) > 0 {
		allGroupIds = append(allGroupIds, agentReq.UserGroupIds...)
	}

	// Add permissions for user groups
	if len(allGroupIds) > 0 {
		for _, groupID := range allGroupIds {
			permission := model.ResourcePermission{
				GroupID:      groupID,
				ResourceID:   agent.AgentID,
				ResourceType: model.ResourceTypeAgent,
				Permission:   model.PermissionRead,
			}
			if err := tx.Create(&permission).Error; err != nil {
				tx.Rollback()
				c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
				return
			}
		}
	}

	// Commit transaction
	if err := tx.Commit().Error; err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
		return
	}

	// Parse CustomConfig to get agent_type
	var customConfig map[string]interface{}
	if err := json.Unmarshal([]byte(agentReq.CustomConfig), &customConfig); err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToErrorResponse(err))
		return
	}

	agentType, ok := customConfig["agent_type"].(string)
	if !ok {
		agentType = "unknown"
	}

	log := model.SystemLog{
		Eid:      agent.Eid,
		UserID:   agent.CreatedBy,
		Nickname: config.GetUserNickname(c),
		Module:   model.SystemLogModuleAgent,
		Action:   model.SystemLogActionCreate,
		Content:  fmt.Sprintf("新建智能体【】名称:【%s】;类型:%s", agent.Name, model.GetChannelDescription(agentType)),
		IP:       utils.GetClientIP(c),
	}
	model.CreateSystemLog(&log)

	c.JSON(http.StatusOK, model.Success.ToResponse(agent))
}

// @Summary Get agent details
// @Description Get agent by AgentID
// @Tags Agent
// @Produce json
// @Security BearerAuth
// @Param agent_id path int true "Agent ID"
// @Success 200 {object} model.CommonResponse{data=model.Agent} "Success"
// @Router /api/agents/{agent_id} [get]
func GetAgent(c *gin.Context) {
	agent_id, err := strconv.ParseInt(c.Param("agent_id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(nil))
		return
	}
	eid := config.GetEID(c)
	agent, err := model.GetAgentByID(eid, agent_id)
	if err != nil {
		c.JSON(http.StatusNotFound, model.NotFound.ToResponse(nil))
		return
	}

	// Check if user is admin or has permission to access this agent
	if !common.IsAdmin(c) {
		hasPermission, err := model.CheckPermission(config.GetUserGroupID(c), agent_id, model.ResourceTypeAgent, model.PermissionRead)
		if err != nil || !hasPermission {
			c.JSON(http.StatusForbidden, model.AuthFailed.ToResponse(nil))
			return
		}
	}

	if err := agent.LoadUserGroupIds(); err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
		return
	}
	c.JSON(http.StatusOK, model.Success.ToResponse(agent))
}

// @Summary Update agent
// @Description Update existing agent details. agent_type: 0=App (default), 1=Workflow
// @Tags Agent
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param agent_id path int true "Agent ID"
// @Param agent body AgentRequest true "Agent data" example:{"name":"OpenAI-ChatGPT","description":"ChatGPT","configs":"{\"model\":\"gpt-3.5-turbo\",\"temperature\":0.7}","prompt":"你好","model":"gpt-3.5-turbo","group_id":0,"use_cases":"[]","tools":"[]","user_group_ids":[1,2,3],"agent_type":0}
// @Success 200 {object} model.CommonResponse{data=model.Agent} "Success"
// @Router /api/agents/{agent_id} [put]
func UpdateAgent(c *gin.Context) {
	agent_id, err := strconv.ParseInt(c.Param("agent_id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(nil))
		return
	}
	eid := config.GetEID(c)
	agent, err := model.GetAgentByID(eid, agent_id)
	if err != nil {
		c.JSON(http.StatusNotFound, model.NotFound.ToResponse(nil))
		return
	}

	// Check if user is admin
	if !common.IsAdmin(c) {
		c.JSON(http.StatusForbidden, model.AuthFailed.ToResponse(nil))
		return
	}

	var agentReq AgentRequest
	if err := c.ShouldBindJSON(&agentReq); err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(nil))
		return
	}

	agentReq.Model = model.ProcessModelNames(agentReq.Model, agentReq.ChannelType)
	if agentReq.Model == "" {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(errors.New("model is required")))
		return
	}

	// Start transaction
	tx := model.DB.Begin()
	if tx.Error != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
		return
	}

	oldAgent := *agent

	// Update agent fields
	agent.Name = agentReq.Name
	agent.Description = agentReq.Description
	agent.Model = agentReq.Model
	agent.Prompt = agentReq.Prompt
	agent.Configs = agentReq.Configs
	agent.Tools = agentReq.Tools
	agent.GroupID = agentReq.GroupId
	agent.UseCases = agentReq.UseCases
	agent.ChannelType = agentReq.ChannelType
	agent.Sort = agentReq.Sort
	agent.Logo = agentReq.Logo
	agent.CustomConfig = agentReq.CustomConfig
	agent.Enable = agentReq.Enable
	agent.Settings = agentReq.Settings
	agent.AgentType = agentReq.AgentType // 添加 AgentType 字段更新

	if err := tx.Save(agent).Error; err != nil {
		tx.Rollback()
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
		return
	}

	// 获取企业信息
	enterprise, err := model.GetEnterpriseByID(eid)
	if err != nil {
		tx.Rollback()
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	// 确定分组ID
	var allGroupIds []int64
	groupIDSet := make(map[int64]bool)

	switch enterprise.Type {
	case model.EnterpriseTypeIndustry:
		// 取所有分组ID
		if len(agentReq.SubscriptionGroupIds) > 0 {
			for _, id := range agentReq.SubscriptionGroupIds {
				groupIDSet[id] = true
			}
		}
		if len(agentReq.UserGroupIds) > 0 {
			for _, id := range agentReq.UserGroupIds {
				groupIDSet[id] = true
			}
		}
	case model.EnterpriseTypeIndependent:
		// 只取订阅分组ID
		if len(agentReq.SubscriptionGroupIds) > 0 {
			for _, id := range agentReq.SubscriptionGroupIds {
				groupIDSet[id] = true
			}
		}
	case model.EnterpriseTypeEnterprise:
		// 只取用户分组ID
		if len(agentReq.UserGroupIds) > 0 {
			for _, id := range agentReq.UserGroupIds {
				groupIDSet[id] = true
			}
		}
	}

	// 转换为切片
	allGroupIds = make([]int64, 0, len(groupIDSet))
	for id := range groupIDSet {
		allGroupIds = append(allGroupIds, id)
	}

	// 使用通用方法更新资源权限(带过滤)
	if err := service.UpdateAgentResourcePermissions(c, tx, agent.AgentID, agentReq.SubscriptionGroupIds, agentReq.UserGroupIds, enterprise); err != nil {
		tx.Rollback()
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
		return
	}

	// Commit transaction
	if err := tx.Commit().Error; err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
		return
	}

	// Prepare for logging
	fieldMap := map[string]string{
		"Name":        "名称",
		"Description": "描述",
	}
	model.LogEntityChange(
		fmt.Sprintf("智能体【%s】", oldAgent.Name),
		model.SystemLogActionUpdate,
		eid,
		config.GetUserId(c),
		config.GetUserNickname(c),
		model.SystemLogModuleAgent,
		oldAgent,
		agent,
		utils.GetClientIP(c),
		fieldMap,
	)

	if err := agent.LoadUserGroupIds(); err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
		return
	}
	c.JSON(http.StatusOK, model.Success.ToResponse(agent))
}

// @Summary Delete agent
// @Description Delete agent by ID
// @Tags Agent
// @Produce json
// @Security BearerAuth
// @Param agent_id path int true "Agent ID"
// @Success 200 {object} model.CommonResponse "Success"
// @Router /api/agents/{agent_id} [delete]
func DeleteAgent(c *gin.Context) {
	agent_id, err := strconv.ParseInt(c.Param("agent_id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(nil))
		return
	}

	eid := config.GetEID(c)
	agent, err := model.GetAgentByID(eid, agent_id)
	if err != nil {
		c.JSON(http.StatusNotFound, model.NotFound.ToResponse(nil))
		return
	}

	// Check if user is admin
	if !common.IsAdmin(c) {
		c.JSON(http.StatusForbidden, model.AuthFailed.ToResponse(nil))
		return
	}

	// Start transaction
	tx := model.DB.Begin()
	if tx.Error != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
		return
	}

	// Delete agent
	if err := tx.Delete(agent).Error; err != nil {
		tx.Rollback()
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
		return
	}

	// Delete associated permissions
	if err := tx.Where("resource_id = ? AND resource_type = ?", agent_id, model.ResourceTypeAgent).Delete(&model.ResourcePermission{}).Error; err != nil {
		tx.Rollback()
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
		return
	}

	// Commit transaction
	if err := tx.Commit().Error; err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
		return
	}

	log := model.SystemLog{
		Eid:      agent.Eid,
		UserID:   agent.CreatedBy,
		Nickname: config.GetUserNickname(c),
		Module:   model.SystemLogModuleAgent,
		Action:   model.SystemLogActionDelete,
		Content:  fmt.Sprintf("删除智能体【%s】", agent.Name),
		IP:       utils.GetClientIP(c),
	}
	model.CreateSystemLog(&log)

	c.JSON(http.StatusOK, model.Success.ToResponse(nil))
}

// @Summary Get agents list
// @Description Retrieve paginated list of agents
// @Tags Agent
// @Produce json
// @Security BearerAuth
// @Param keyword query string false "Keyword"
// @Param group_id query int false "Group ID"
// @Param offset query int false "Offset"
// @Param limit query int false "Limit" default(10)
// @Param channel_types query string false "Channel types , split by comma"
// @Param agent_types query string false "Agent types , split by comma"
// @Success 200 {object} model.CommonResponse{data=AgentsResponse} "Success"
// @Router /api/agents [get]
func GetAgents(c *gin.Context) {
	var agentListRequest AgentListRequest
	if err := c.ShouldBindQuery(&agentListRequest); err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(err))
		return
	}

	// Set default limit to 10 if not specified
	if agentListRequest.Limit == 0 {
		agentListRequest.Limit = 10
	}

	// If user is not admin, get only agents they have permission to access
	var total int64
	var agents []*model.Agent
	var err error
	channelTypes := splitChannelTypesString(agentListRequest.ChannelTypes)
	agentTypes := splitAgentTypesString(agentListRequest.AgentTypes)
	if common.IsAdmin(c) {
		total, agents, err = model.GetAgentListWithIDs(
			config.GetEID(c), agentListRequest.Keyword, agentListRequest.GroupId,
			nil, channelTypes, agentTypes, agentListRequest.Offset, agentListRequest.Limit)
	} else {
		// Get list of agent IDs the user has permission to access
		permittedAgentIDs, getErr := model.GetResourcesByGroupAndType(config.GetUserGroupID(c), model.ResourceTypeAgent)
		if getErr != nil {
			c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
			return
		}

		total, agents, err = model.GetAgentListWithIDs(
			config.GetEID(c), agentListRequest.Keyword, agentListRequest.GroupId,
			permittedAgentIDs, channelTypes, agentTypes,
			agentListRequest.Offset, agentListRequest.Limit)
	}

	if err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
		return
	}

	for _, agent := range agents {
		if err := agent.LoadUserGroupIds(); err != nil {
			c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
			return
		}
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(AgentsResponse{
		Count:  total,
		Agents: agents,
	}))
}

// @Summary Get agents by group
// @Description Retrieve paginated list of agents by specified group
// @Tags Agent
// @Produce json
// @Security BearerAuth
// @Param keyword    query string false "Search keyword"
// @Param group_id   query int    false  "Target group ID"
// @Param offset     query int    false "Pagination offset" default(0)
// @Param limit      query int    false "Pagination limit"  default(10)
// @Param channel_types query string false "Channel types , split by comma"
// @Param agent_types query string false "Agent types , split by comma"
// @Success 200 {object} model.CommonResponse{data=AgentsResponse} "Success response with agent list"
// @Router /api/agents/group [get]
func GetAgentsByGroup(c *gin.Context) {
	var agentListRequest AgentListRequest
	if err := c.ShouldBindQuery(&agentListRequest); err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(err))
		return
	}

	// Set default limit to 10 if not specified
	if agentListRequest.Limit == 0 {
		agentListRequest.Limit = 10
	}

	channelTypes := splitChannelTypesString(agentListRequest.ChannelTypes)
	agentTypes := splitAgentTypesString(agentListRequest.AgentTypes)
	var total, agents, err = model.GetAgentListWithIDs(
		config.GetEID(c), agentListRequest.Keyword, agentListRequest.GroupId,
		nil, channelTypes, agentTypes, agentListRequest.Offset, agentListRequest.Limit)

	if err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
		return
	}

	for _, agent := range agents {
		if err := agent.LoadUserGroupIds(); err != nil {
			c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
			return
		}
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(AgentsResponse{
		Count:  total,
		Agents: agents,
	}))
}

// @Summary Get available agents
// @Description Retrieve paginated list of available agents
// @Tags Agent
// @Produce json
// @Param offset query int false "Pagination offset" default(0)
// @Param limit query int false "Pagination limit" default(10)
// @Param agent_types query string false "Agent types , split by comma"
// @Success 200 {object} model.CommonResponse{data=AgentsResponse} "Success response with available agent list"
// @Router /api/agents/available [get]
func GetAvailableAgents(c *gin.Context) {
	var agentListRequest AgentListRequest
	if err := c.ShouldBindQuery(&agentListRequest); err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(err))
		return
	}

	if agentListRequest.Limit == 0 {
		agentListRequest.Limit = 10
	}

	agentTypes := splitAgentTypesString(agentListRequest.AgentTypes)
	var total, agents, err = model.GetAvailableAgentList(
		config.GetEID(c),
		agentTypes,
		agentListRequest.Offset,
		agentListRequest.Limit,
	)

	if err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
		return
	}

	for _, agent := range agents {
		if err = agent.LoadUserGroupIds(); err != nil {
			c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
			return
		}
		if err = agent.LoadConversationCount(); err != nil {
			c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
			return
		}
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(AgentsResponse{
		Count:  total,
		Agents: agents,
	}))
}

// Get Current Agents
// @Summary Get current agent list
// @Description Get agents list under the first agent-type group of current enterprise (no pagination required)
// @Tags Agent
// @Produce json
// @Security BearerAuth
// @Success 200 {object} model.CommonResponse{data=AgentsResponse} "Success response containing agent list"
// @Router /api/agents/current [get]
func GetCurrentAgents(c *gin.Context) {
	eid := config.GetEID(c)

	authHeader := c.GetHeader("Authorization")
	authHeader = strings.Replace(authHeader, "Bearer ", "", 1)

	var theGroup *model.Group
	var err error

	if authHeader == "" {
		group, err := model.GetFirstGroupByEid(eid, model.USER_GROUP_TYPE)
		if err != nil {
			c.JSON(http.StatusNotFound, model.DBError.ToResponse(err))
			return
		}
		theGroup = &group
	} else {
		user := model.ValidateAccessToken(authHeader)
		if user == nil {
			c.JSON(http.StatusUnauthorized, model.UnauthorizedError.ToResponse(nil))
			return
		}

		if user.GroupId > 0 {
			theGroup, err = model.GetGroupByID(user.GroupId)
			if err != nil {
				c.JSON(http.StatusNotFound, model.DBError.ToResponse(err))
				return
			}
		}
	}

	group, err := model.GetGroupWithAgents(theGroup.GroupId, true)
	if err != nil {
		c.JSON(http.StatusNotFound, model.DBError.ToResponse(err))
		return
	}

	for i := range group.Agents {
		var count int64
		model.DB.Model(&model.Conversation{}).
			Where("eid = ? AND agent_id = ?", eid, group.Agents[i].AgentID).
			Count(&count)

		group.Agents[i].ConversationCount = count
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(AgentsResponse{
		Count:  int64(len(group.Agents)),
		Agents: group.Agents,
	}))
}

// @Summary Update agent status
// @Description Update agent enable/disable status
// @Tags Agent
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param agent_id path int true "Agent ID"
// @Param request body UpdateAgentEnableRequest true "Enable status"
// @Success 200 {object} model.CommonResponse "Success"
// @Router /api/agents/{agent_id}/status [patch]
func UpdateAgentStatus(c *gin.Context) {
	agentID, err := strconv.ParseInt(c.Param("agent_id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(nil))
		return
	}

	var updateAgentEnableReq UpdateAgentEnableRequest
	if err = c.ShouldBindJSON(&updateAgentEnableReq); err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(nil))
		return
	}

	eid := config.GetEID(c)
	_, err = model.GetAgentByID(eid, agentID)
	if err != nil {
		c.JSON(http.StatusNotFound, model.NotFound.ToResponse(nil))
		return
	}

	err = model.UpdateAgentStatus(eid, agentID, updateAgentEnableReq.Enable)
	if err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
		return
	}

	agent, err := model.GetAgentByID(eid, agentID)
	if err != nil {
		c.JSON(http.StatusNotFound, model.NotFound.ToResponse(nil))
		return
	}
	statusText := "启用"
	if !agent.Enable {
		statusText = "禁用"
	}

	log := model.SystemLog{
		Eid:      eid,
		UserID:   config.GetUserId(c),
		Nickname: config.GetUserNickname(c),
		Module:   model.SystemLogModuleAgent,
		Action:   model.SystemLogActionToggle,
		Content:  fmt.Sprintf("%s智能体【%s】", statusText, agent.Name),
		IP:       utils.GetClientIP(c),
	}
	model.CreateSystemLog(&log)

	c.JSON(http.StatusOK, model.Success.ToResponse(nil))
}

func splitChannelTypesString(channelTypesStr string) []int {
	var channelTypes []int
	if channelTypesStr != "" {
		strSlice := strings.Split(channelTypesStr, ",")
		for _, s := range strSlice {
			if i, err := strconv.Atoi(strings.TrimSpace(s)); err == nil {
				channelTypes = append(channelTypes, i)
			}
		}
	}
	return channelTypes
}

func splitAgentTypesString(agentTypesStr string) []int {
	var agentTypes []int
	if agentTypesStr != "" {
		strSlice := strings.Split(agentTypesStr, ",")
		for _, s := range strSlice {
			if i, err := strconv.Atoi(strings.TrimSpace(s)); err == nil {
				agentTypes = append(agentTypes, i)
			}
		}
	}
	return agentTypes
}

// GetInternalUserAgents retrieves available agents for a specific internal user
// @Summary Get available agents for a specific internal user
// @Description Get all available agents for a specific internal user (including agents from user's groups and department groups, with duplicates removed)
// @Tags Agent
// @Produce json
// @Security BearerAuth
// @Success 200 {object} model.CommonResponse{data=AgentsResponse} "Success response containing agent list"
// @Router /api/agents/internal_users [get]
func GetInternalUserAgents(c *gin.Context) {
	eid := config.GetEID(c)

	userID := config.GetUserId(c)
	user, err := model.GetUserByID(userID)
	if err != nil {
		c.JSON(http.StatusNotFound, model.DBError.ToResponse(err))
		return
	}

	if user.Eid != eid || user.Type != model.UserTypeInternal {
		c.JSON(http.StatusForbidden, model.AuthFailed.ToResponse("User is not an internal member of the current enterprise"))
		return
	}

	var groupIDs []int64
	groupIDs, err = model.GetGroupsByUserID(userID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	var dids []int64
	dids, err = model.GetMemberDidsByBID(eid, userID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	var departmentGroupIDs []int64
	if len(dids) == 0 {
		dids = []int64{0}
	}

	for _, did := range dids {
		deptGroupIDs, err := model.GetGroupsByDepartmentID(did)
		if err != nil {
			c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
			return
		}
		departmentGroupIDs = append(departmentGroupIDs, deptGroupIDs...)
	}

	if len(departmentGroupIDs) > 0 {
		groupIDMap := make(map[int64]bool)
		for _, id := range groupIDs {
			groupIDMap[id] = true
		}

		for _, id := range departmentGroupIDs {
			if !groupIDMap[id] {
				groupIDs = append(groupIDs, id)
				groupIDMap[id] = true
			}
		}
	}

	if len(groupIDs) == 0 {
		c.JSON(http.StatusOK, model.Success.ToResponse(AgentsResponse{
			Count:  0,
			Agents: []*model.Agent{},
		}))
		return
	}

	var allAgents []*model.Agent
	agentMap := make(map[int64]*model.Agent)

	for _, groupID := range groupIDs {
		group, err := model.GetGroupWithAgents(groupID, true)
		if err != nil {
			continue
		}

		for i := range group.Agents {
			if group.Agents[i].Enable {
				agentMap[group.Agents[i].AgentID] = group.Agents[i]
			}
		}
	}

	for _, agent := range agentMap {
		var count int64
		model.DB.Model(&model.Conversation{}).
			Where("eid = ? AND agent_id = ?", eid, agent.AgentID).
			Count(&count)

		agent.ConversationCount = count
		allAgents = append(allAgents, agent)
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(AgentsResponse{
		Count:  int64(len(allAgents)),
		Agents: allAgents,
	}))
}


================================================
FILE: api/controller/ai53.go
================================================
package controller

import (
	"net/http"
	"strconv"
	"strings"

	"github.com/53AI/53AIHub/common/logger"
	"github.com/53AI/53AIHub/common/utils/ai53"
	"github.com/53AI/53AIHub/config"
	"github.com/53AI/53AIHub/model"
	"github.com/53AI/53AIHub/service"
	"github.com/gin-gonic/gin"
)

// Get53AIAllBots Get all 53AI bots
// @Summary Get all 53AI bots list
// @Description Get all bots list from 53AI platform
// @Tags 53AI
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param provider_id query int false "Provider ID (optional, for backward compatibility)"
// @Success 200 {object} model.CommonResponse{data=[]ai53.AppResponse}
// @Router /api/53ai/bots [get]
func Get53AIAllBots(c *gin.Context) {
	eid := config.GetEID(c)
	providerID, _ := strconv.ParseInt(c.DefaultQuery("provider_id", "0"), 10, 64)
	provider, err := model.GetProviderByEidAndProviderTypeWithOptionalID(eid, int64(model.ProviderType53AI), providerID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, model.ProviderNoFoundError.ToResponse(err))
		return
	}

	ser := service.AI53Service{
		Provider: &provider,
	}

	bots, err := ser.GetAllBots()
	if err != nil {
		logger.SysLogf("Get53AIAllBots: %s", err.Error())
		c.JSON(http.StatusInternalServerError, model.ProviderNoFoundError.ToResponse(err))
		return
	}

	Update53AIChannel(provider, bots)
	c.JSON(http.StatusOK, model.Success.ToResponse(bots))
}

// Get53AIAllWorkflows Get all 53AI workflows
// @Summary Get all 53AI workflows list
// @Description Get all workflows list from 53AI platform
// @Tags 53AI
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param provider_id query int false "Provider ID (optional, for backward compatibility)"
// @Success 200 {object} model.CommonResponse{data=[]ai53.AppResponse}
// @Router /api/53ai/workflows [get]
func Get53AIAllWorkflows(c *gin.Context) {
	eid := config.GetEID(c)
	providerID, _ := strconv.ParseInt(c.DefaultQuery("provider_id", "0"), 10, 64)
	provider, err := model.GetProviderByEidAndProviderTypeWithOptionalID(eid, int64(model.ProviderType53AI), providerID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, model.ProviderNoFoundError.ToResponse(err))
		return
	}

	ser := service.AI53Service{
		Provider: &provider,
	}

	workflows, err := ser.GetAllWorkflows()
	if err != nil {
		logger.SysLogf("Get53AIAllWorkflows: %s", err.Error())
		c.JSON(http.StatusInternalServerError, model.ProviderNoFoundError.ToResponse(err))
		return
	}

	Update53AIWorkflowChannel(provider, workflows)
	c.JSON(http.StatusOK, model.Success.ToResponse(workflows))
}

func Update53AIChannel(provider model.Provider, apps []ai53.AppResponse) error {
	var botIds []string
	for _, bot := range apps {
		botIds = append(botIds, "bot-"+bot.BotID)
	}
	// todo Call interface user ID all use the same
	configStr := `{"region":"","sk":"","ak":"","user_id":"53AIHub","vertex_ai_project_id":"","vertex_ai_adc":""}`
	// Create or update channel record
	baseURL := provider.GetBaseURLByProviderType()
	channel := &model.Channel{
		Eid:        provider.Eid,
		Name:       provider.Name,
		Key:        provider.AccessToken,
		Type:       model.ChannelApi53AI,
		ProviderID: provider.ProviderID,
		BaseURL:    &baseURL,
		Status:     model.ChannelStatusEnabled,
		Config:     configStr,
	}

	existingChannel, err := model.GetFirstChannelByEidAndProviderId(channel.Eid, channel.ProviderID)
	if err != nil {
		// Create new record with initial botIds
		channel.Models = strings.Join(botIds, ",")
		return model.CreateChannel(channel)
	} else {
		// Update existing record with incremental botIds
		channel.ChannelID = existingChannel.ChannelID
		channel.CreatedTime = existingChannel.CreatedTime
		
		// Get existing botIds
		existingBotIds := strings.Split(existingChannel.Models, ",")
		botIdMap := make(map[string]bool)
		for _, id := range existingBotIds {
			if id != "" {
				botIdMap[id] = true
			}
		}
		
		// Add new botIds
		for _, id := range botIds {
			botIdMap[id] = true
		}
		
		// Convert map back to slice
		var updatedBotIds []string
		for id := range botIdMap {
			updatedBotIds = append(updatedBotIds, id)
		}
		
		channel.Models = strings.Join(updatedBotIds, ",")
		return model.UpdateChannel(channel)
	}
}

func Update53AIWorkflowChannel(provider model.Provider, apps []ai53.AppResponse) error {
	var workflowIds []string
	for _, workflow := range apps {
		workflowIds = append(workflowIds, "workflow-"+workflow.BotID)
	}
	// todo Call interface user ID all use the same
	configStr := `{"region":"","sk":"","ak":"","user_id":"53AIHub","vertex_ai_project_id":"","vertex_ai_adc":""}`
	// Create or update channel record
	baseURL := provider.GetBaseURLByProviderType()
	channel := &model.Channel{
		Eid:        provider.Eid,
		Name:       provider.Name,
		Key:        provider.AccessToken,
		Type:       model.ChannelApi53AI,
		ProviderID: provider.ProviderID,
		BaseURL:    &baseURL,
		Status:     model.ChannelStatusEnabled,
		Config:     configStr,
	}

	existingChannel, err := model.GetFirstChannelByEidAndProviderId(channel.Eid, channel.ProviderID)
	if err != nil {
		// Create new record with initial workflowIds
		channel.Models = strings.Join(workflowIds, ",")
		return model.CreateChannel(channel)
	} else {
		// Update existing record with incremental workflowIds
		channel.ChannelID = existingChannel.ChannelID
		channel.CreatedTime = existingChannel.CreatedTime
		
		// Get existing workflowIds
		existingWorkflowIds := strings.Split(existingChannel.Models, ",")
		workflowIdMap := make(map[string]bool)
		for _, id := range existingWorkflowIds {
			if id != "" {
				workflowIdMap[id] = true
			}
		}
		
		// Add new workflowIds
		for _, id := range workflowIds {
			workflowIdMap[id] = true
		}
		
		// Convert map back to slice
		var updatedWorkflowIds []string
		for id := range workflowIdMap {
			updatedWorkflowIds = append(updatedWorkflowIds, id)
		}
		
		channel.Models = strings.Join(updatedWorkflowIds, ",")
		return model.UpdateChannel(channel)
	}
}

// Get53AIAppParameters 获取 53AI 应用参数配置
// @Summary 获取 53AI 应用参数配置
// @Description 根据 botId 获取 53AI 应用的参数配置信息,支持带前缀或不带前缀的 botId
// @Tags 53AI
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param botId path string true "机器人ID (支持 bot-xxx, workflow-xxx 或直接 xxx 格式)"
// @Param provider_id query int false "Provider ID (optional, for backward compatibility)"
// @Success 200 {object} model.CommonResponse{data=interface{}}
// @Router /api/53ai/parameters/{botId} [get]
func Get53AIAppParameters(c *gin.Context) {
	// 1. 获取并处理 botId 参数
	botId := c.Param("botId")
	if botId == "" {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse("botId 不能为空"))
		return
	}

	logger.SysLogf("🔍 获取53AI应用参数 - Bot ID: %s", botId)

	// 2. 获取 EID (遵循 53AI 渠道模式)
	eid := config.GetEID(c)

	// 3. 获取 53AI Provider (遵循 53AI 渠道模式)
	providerID, _ := strconv.ParseInt(c.DefaultQuery("provider_id", "0"), 10, 64)
	provider, err := model.GetProviderByEidAndProviderTypeWithOptionalID(eid, int64(model.ProviderType53AI), providerID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, model.ProviderNoFoundError.ToResponse(err))
		return
	}

	// 4. 创建 AI53Service 实例 (遵循 53AI 渠道模式)
	ser := service.AI53Service{
		Provider: &provider,
	}

	// 5. 调用服务方法获取应用参数
	appParams, err := ser.GetAppParameters(botId)
	if err != nil {
		logger.SysLogf("Get53AIAppParameters: %s", err.Error())
		c.JSON(http.StatusInternalServerError, model.SystemError.ToResponse(err))
		return
	}

	logger.SysLogf("✅ 53AI应用参数获取成功 - Bot ID: %s", botId)
	// 6. 返回结果
	c.JSON(http.StatusOK, model.Success.ToResponse(appParams))
}


================================================
FILE: api/controller/ai_link.go
================================================
package controller

import (
	"net/http"
	"strconv"

	"github.com/53AI/53AIHub/config"
	"github.com/53AI/53AIHub/model"
	"github.com/53AI/53AIHub/service"
	"github.com/gin-gonic/gin"
)

type AILinkRequest struct {
	GroupID       int64  `json:"group_id" example:"1"`
	Name          string `json:"name" example:"ai_link_name"`
	Logo          string `json:"logo" example:"logo_url"`
	URL           string `json:"url" example:"ai_link_url"`
	Description   string `json:"description" example:"ai_link_description"`
	Sort          int64  `json:"sort" example:"0"`
	SharedAccount string `json:"shared_account" example:"[{'account':'admin', 'password':'<PASSWORD>', 'remark':''}]"`
	// 使用范围
	SubscriptionGroupIds []int64 `json:"subscription_group_ids"`
	UserGroupIds         []int64 `json:"user_group_ids"`
}

// @Summary Create AI Link
// @Description Create new AI link entry
// @Tags AI Link
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param link body AILinkRequest true "AI Link data"
// @Success 200 {object} model.CommonResponse
// @Router /api/ai_links [post]
func CreateAILink(c *gin.Context) {
	var req AILinkRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(err))
		return
	}

	link := model.AILink{
		Eid:           config.GetEID(c),
		GroupID:       req.GroupID,
		Name:          req.Name,
		Logo:          req.Logo,
		URL:           req.URL,
		Description:   req.Description,
		Sort:          req.Sort,
		CreatedBy:     config.GetUserId(c),
		SharedAccount: req.SharedAccount,
	}

	if err := model.CreateAILink(&link); err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	// 添加分组关联
	allGroupIds := make([]int64, 0)

	// 添加订阅分组
	if len(req.SubscriptionGroupIds) > 0 {
		allGroupIds = append(allGroupIds, req.SubscriptionGroupIds...)
	}

	// 添加用户分组
	if len(req.UserGroupIds) > 0 {
		allGroupIds = append(allGroupIds, req.UserGroupIds...)
	}

	// 创建资源权限
	if len(allGroupIds) > 0 {
		tx := model.DB.Begin()
		if tx.Error != nil {
			c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
			return
		}

		defer func() {
			if r := recover(); r != nil {
				tx.Rollback()
			}
		}()

		// 使用通用方法更新资源权限
		if err := service.UpdateResourcePermissions(c, tx, link.ID, model.ResourceTypeAILink, allGroupIds); err != nil {
			tx.Rollback()
			c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
			return
		}

		// 提交事务
		if err := tx.Commit().Error; err != nil {
			c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
			return
		}
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(link))
}

// @Summary Get AI Link
// @Description Get AI link by ID
// @Tags AI Link
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "Link ID"
// @Success 200 {object} model.CommonResponse{data=model.AILink}
// @Router /api/ai_links/{id} [get]
func GetAILink(c *gin.Context) {
	id, _ := strconv.Atoi(c.Param("id"))
	link, err := model.GetAILinkByID(int64(id))

	if err != nil || link.Eid != config.GetEID(c) {
		c.JSON(http.StatusNotFound, model.NotFound.ToResponse(nil))
		return
	}
	err = link.LoadUserGroupIds()
	if err != nil {
		link.UserGroupIds = []int64{}
	}
	link.LoadHasSharedAccount()

	c.JSON(http.StatusOK, model.Success.ToResponse(link))
}

// @Summary Update AI Link
// @Description Update existing AI link
// @Tags AI Link
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "Link ID"
// @Param link body AILinkRequest true "Update data"
// @Success 200 {object} model.CommonResponse
// @Router /api/ai_links/{id} [put]
func UpdateAILink(c *gin.Context) {
	id, _ := strconv.Atoi(c.Param("id"))
	link, err := model.GetAILinkByID(int64(id))

	if err != nil || link.Eid != config.GetEID(c) {
		c.JSON(http.StatusNotFound, model.NotFound.ToResponse(nil))
		return
	}

	var req AILinkRequest
	if c.ShouldBindJSON(&req) != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(nil))
		return
	}

	link.GroupID = req.GroupID
	link.Name = req.Name
	link.Logo = req.Logo
	link.URL = req.URL
	link.Description = req.Description
	link.Sort = req.Sort
	link.SharedAccount = req.SharedAccount

	if err := model.UpdateAILink(link); err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	// 更新分组关联
	allGroupIds := make([]int64, 0)

	// 添加订阅分组
	if len(req.SubscriptionGroupIds) > 0 {
		allGroupIds = append(allGroupIds, req.SubscriptionGroupIds...)
	}

	// 添加用户分组
	if len(req.UserGroupIds) > 0 {
		allGroupIds = append(allGroupIds, req.UserGroupIds...)
	}

	tx := model.DB.Begin()
	if tx.Error != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
		return
	}

	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	// 使用通用方法更新资源权限
	if err := service.UpdateResourcePermissions(c, tx, link.ID, model.ResourceTypeAILink, allGroupIds); err != nil {
		tx.Rollback()
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
		return
	}

	// 提交事务
	if err := tx.Commit().Error; err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
		return
	}
	err = link.LoadUserGroupIds()
	if err != nil {
		link.UserGroupIds = []int64{}
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(link))
}

// @Summary Delete AI Link
// @Description Delete AI link by ID
// @Tags AI Link
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "Link ID"
// @Success 200 {object} model.CommonResponse
// @Router /api/ai_links/{id} [delete]
func DeleteAILink(c *gin.Context) {
	id, _ := strconv.Atoi(c.Param("id"))
	link, err := model.GetAILinkByID(int64(id))

	if err != nil || link.Eid != config.GetEID(c) {
		c.JSON(http.StatusNotFound, model.NotFound.ToResponse(nil))
		return
	}

	// 开始事务
	tx := model.DB.Begin()
	if tx.Error != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(tx.Error))
		return
	}

	// 删除AI链接
	if err := tx.Delete(link).Error; err != nil {
		tx.Rollback()
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
		return
	}

	// 使用通用方法删除资源权限
	if err := service.UpdateResourcePermissions(c, tx, int64(id), model.ResourceTypeAILink, []int64{}); err != nil {
		tx.Rollback()
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(nil))
		return
	}

	// 提交事务
	if err := tx.Commit().Error; err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(nil))
}

// @Summary Get AI Links
// @Description Get AI links by group ID
// @Tags AI Link
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param group_id query int false "Empty for all groups or group ID"
// @Param keyword query string false "Search by name"
// @Success 200 {object} model.CommonResponse{data=[]model.AILink}
// @Router /api/ai_links [get]
func GetAILinks(c *gin.Context) {
	groupID, _ := strconv.ParseInt(c.Query("group_id"), 10, 64)
	keyword := c.Query("keyword")
	var links []model.AILink
	var err error

	if groupID != 0 {
		if keyword != "" {
			links, err = model.GetAILinksByEidAndGroupIdWithKeyword(config.GetEID(c), groupID, keyword)
		} else {
			links, err = model.GetAILinksByEidAndGroupId(config.GetEID(c), groupID)
		}
	} else {
		if keyword != "" {
			links, err = model.GetAILinksGroupedBySortWithKeyword(config.GetEID(c), keyword)
		} else {
			links, err = model.GetAILinksGroupedBySort(config.GetEID(c))
		}
	}

	if err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(links))
}

// @Summary Get current site AI links
// @Description Get all AI links for current site
// @Tags AI Link
// @Accept json
// @Produce json
// @Security BearerAuth
// @Success 200 {object} model.CommonResponse{data=[]model.AILink}
// @Router /api/ai_links/current [get]
func GetCurrentSiteAILinks(c *gin.Context) {
	eid := config.GetEID(c)
	links, err := model.GetAILinksGroupedBySort(eid)

	if err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(links))
}

// @Summary 获取默认AI链接数据
// @Description 获取预定义的AI工具分组及对应链接列表(如AI搜索、智能对话等分组)
// @Tags AI Link
// @Accept json
// @Produce json
// @Success 200 {object} model.CommonResponse{data=[]model.GroupInfo} "成功返回默认AI链接数据"
// @Router /api/ai_links/default [get]
func GetDefaultAILinks(c *gin.Context) {
	links := model.GetDefaultGroupData()

	c.JSON(http.StatusOK, model.Success.ToResponse(links))
}

type SortItem struct {
	ID      int64 `json:"id" example:"1"`
	Sort    int64 `json:"sort" example:"5"`
	GroupID int64 `json:"group_id" example:"1"`
}

type BatchSortRequest struct {
	Items []SortItem `json:"items"`
}

// @Summary Batch Sort AI Links
// @Description Batch update sort order of AI links
// @Tags AI Link
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param data body BatchSortRequest true "Batch sort data"
// @Success 200 {object} model.CommonResponse
// @Router /api/ai_links/batch/sort [post]
func BatchSortAILinks(c *gin.Context) {
	var req BatchSortRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(err))
		return
	}

	eid := config.GetEID(c)
	tx := model.DB.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	for _, item := range req.Items {
		link, err := model.GetAILinkByID(item.ID)
		if err != nil || link.Eid != eid {
			tx.Rollback()
			c.JSON(http.StatusNotFound, model.NotFound.ToResponse(nil))
			return
		}

		link.Sort = item.Sort
		link.GroupID = item.GroupID
		if err := tx.Model(&link).Updates(link).Error; err != nil {
			tx.Rollback()
			c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
			return
		}
	}

	if err := tx.Commit().Error; err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(nil))
}


================================================
FILE: api/controller/appbuilder.go
================================================
package controller

import (
	"net/http"
	"strconv"
	"strings"

	"github.com/53AI/53AIHub/common/logger"
	"github.com/53AI/53AIHub/common/utils/appbuilder"
	"github.com/53AI/53AIHub/config"
	"github.com/53AI/53AIHub/model"
	"github.com/53AI/53AIHub/service"
	"github.com/gin-gonic/gin"
)

// GetAppBuilderAllBots Get all AppBuilder bots
// @Summary Get all AppBuilder bots list
// @Description Get all bots list from AppBuilder
// @Tags AppBuilder
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param provider_id query int false "Provider ID (optional, for backward compatibility)"
// @Success 200 {object} model.CommonResponse{data=[]appbuilder.AppInfo}
// @Router /api/appbuilder/bots [get]
func GetAppBuilderAllBots(c *gin.Context) {
	eid := config.GetEID(c)
	providerID, _ := strconv.ParseInt(c.DefaultQuery("provider_id", "0"), 10, 64)
	provider, err := model.GetProviderByEidAndProviderTypeWithOptionalID(eid, int64(model.ProviderTypeAppBuilder), providerID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, model.ProviderNoFoundError.ToResponse(err))
		return
	}

	ser := service.AppBuilderService{
		Provider: &provider,
	}

	apps, err := ser.GetAllDescribeApps()
	if err != nil {
		logger.SysLogf("GetAppBuilderAllBots: %s", err.Error())
		if len(apps) == 0 {
			c.JSON(http.StatusInternalServerError, model.ProviderNoFoundError.ToResponse(err))
			return
		}
	}
	// update or channel
	UpdateAppBuilderChannel(provider, apps)
	c.JSON(http.StatusOK, model.Success.ToResponse(apps))
}

func UpdateAppBuilderChannel(provider model.Provider, apps []appbuilder.AppInfo) error {
	var botIds []string
	for _, bot := range apps {
		if !bot.IsPublished {
			continue
		}
		botIds = append(botIds, "bot-"+bot.ID)
	}
	// todo Call interface user ID all use the same
	configStr := `{"region":"","sk":"","ak":"","user_id":"53AIHub","vertex_ai_project_id":"","vertex_ai_adc":""}`
	// Create or update channel record
	baseURL := provider.GetBaseURLByProviderType()
	channel := &model.Channel{
		Eid:        provider.Eid,
		Name:       provider.Name,
		Key:        provider.AccessToken,
		Type:       model.ChannelApiAppBuilder,
		ProviderID: provider.ProviderID,
		BaseURL:    &baseURL, // Fix: assign address of baseURL since Channel.BaseURL is *string
		Models:     strings.Join(botIds, ","),
		Status:     model.ChannelStatusEnabled,
		Config:     configStr,
	}

	existingChannel, err := model.GetFirstChannelByEidAndProviderId(channel.Eid, channel.ProviderID)
	if err != nil {
		// Create new record
		return model.CreateChannel(channel) // Fix: return error instead of assigning i
	} else {
		// Update existing record
		channel.ChannelID = existingChannel.ChannelID
		channel.CreatedTime = existingChannel.CreatedTime
		return model.UpdateChannel(channel)
	}
}


================================================
FILE: api/controller/auth_sso.go
================================================
package controller

import (
	"encoding/json"
	"net/http"
	"strconv"
	"time"
	"unicode"

	"github.com/53AI/53AIHub/common/utils/helper"
	"github.com/53AI/53AIHub/config"
	"github.com/53AI/53AIHub/model"
	"github.com/53AI/53AIHub/service"
	"github.com/gin-gonic/gin"
)

// SSO 配置结构,存储于 enterprise-configs type="auth_sso" 的 JSON 内容
type SSOConfig struct {
	Enable         bool   `json:"enable"`
	EncryptEnabled bool   `json:"encrypt_enabled"`
	Secret         string `json:"secret"`
}

// SSO 登录请求体
type SSOLoginRequest struct {
	Username  string `json:"username" binding:"required"`
	Timestamp string `json:"timestamp"` // 10位秒
	Sign      string `json:"sign"`      // 加密启用时必须传
}

// SaasLoginResponse 复用现有返回体格式
type SaasLoginResponse struct {
	AccessToken string `json:"access_token"`
	UserID      int64  `json:"user_id"`
}

// @Summary API SSO Login
// @Description 站点API单点登录。时间戳为10位秒,窗口10分钟。eid无需传,使用站点环境。
// @Tags Auth
// @Accept json
// @Produce json
// @Param request body SSOLoginRequest true "SSO请求体"
// @Success 200 {object} model.CommonResponse{data=SaasLoginResponse} "成功,返回access_token与user_id"
// @Failure 401 {object} model.CommonResponse "未授权(超时或签名错误)"
// @Failure 403 {object} model.CommonResponse "拒绝(SSO关闭)"
// @Failure 404 {object} model.CommonResponse "用户不存在"
// @Router /api/auth/sso_login [post]
func ApiSSOSSOLogin(c *gin.Context) {
	eid := config.GetEID(c)

	// 加载 SSO 配置
	cfg := loadSSOConfig(eid)

	// 开关关闭:403
	if !cfg.Enable {
		c.JSON(http.StatusForbidden, model.ForbiddenError.ToNewErrorResponse("拒绝登录"))
		return
	}

	// 绑定请求参数
	var req SSOLoginRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusForbidden, model.ParamError.ToResponse(err))
		return
	}

	// 签名校验(加密启用时)
	if cfg.EncryptEnabled {
		// 校验时间戳:必须10位数字
		if !isValid10DigitTimestamp(req.Timestamp) {
			c.JSON(http.StatusUnauthorized, model.UnauthorizedError.ToNewErrorResponse("sso timeout"))
			return
		}
		ts, _ := strconv.ParseInt(req.Timestamp, 10, 64)
		now := time.Now().Unix()
		// 且600秒内有效
		if now-ts > 600 {
			c.JSON(http.StatusUnauthorized, model.UnauthorizedError.ToNewErrorResponse("sso timeout"))
			return
		}

		if cfg.Secret == "" {
			c.JSON(http.StatusUnauthorized, model.UnauthorizedError.ToNewErrorResponse("invalid sign"))
			return
		}
		raw := helper.BuildSSORawString(req.Timestamp, req.Username, cfg.Secret)
		expected := helper.CalcSSOSignLowerHex(raw)
		if expected != req.Sign {
			c.JSON(http.StatusUnauthorized, model.UnauthorizedError.ToNewErrorResponse("invalid sign"))
			return
		}
	}

	isEmail := helper.IsValidEmail(req.Username)
	// 根据账号查找用户(邮箱或手机)
	var user model.User
	if isEmail {
		u, err := model.GetUserByEmail(eid, req.Username)
		if err != nil {
			c.JSON(http.StatusNotFound, model.NotFound.ToNewErrorResponse("user not found"))
			return
		}
		user = u
	} else {
		u, err := model.GetUserByMobile(eid, req.Username)
		if err != nil {
			c.JSON(http.StatusNotFound, model.NotFound.ToNewErrorResponse("user not found"))
			return
		}
		user = u
	}

	// 刷新令牌并返回
	if err := user.RefreshAccessToken(); err != nil {
		c.JSON(http.StatusInternalServerError, model.SystemError.ToResponse(err))
		return
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(SaasLoginResponse{
		AccessToken: user.AccessToken,
		UserID:      user.UserID,
	}))
}

func loadSSOConfig(eid int64) *SSOConfig {
	// 从 enterprise-configs 读取 type="auth_sso"
	conf, err := service.GetEnterpriseConfigByType(eid, model.EnterpriseConfigTypeSSO)
	if err != nil || conf.Content == "" {
		// 不存在则视为关闭
		return &SSOConfig{Enable: false, EncryptEnabled: true, Secret: ""}
	}
	var cfg SSOConfig
	_ = json.Unmarshal([]byte(conf.Content), &cfg)
	cfg.Enable = conf.Enabled
	return &cfg
}

func isValid10DigitTimestamp(ts string) bool {
	if len(ts) != 10 {
		return false
	}
	for _, r := range ts {
		if !unicode.IsDigit(r) {
			return false
		}
	}
	return true
}


================================================
FILE: api/controller/channel-test.go
================================================
package controller

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"
	"net/url"
	"strconv"
	"strings"
	"time"

	"github.com/53AI/53AIHub/common/ctxkey"
	"github.com/53AI/53AIHub/common/logger"
	"github.com/53AI/53AIHub/middleware"
	"github.com/53AI/53AIHub/model"
	"github.com/53AI/53AIHub/service"
	"github.com/53AI/53AIHub/service/hub_adaptor/custom"
	"github.com/gin-gonic/gin"
	"github.com/songquanpeng/one-api/relay/adaptor/openai"
	"github.com/songquanpeng/one-api/relay/meta"
	relaymodel "github.com/songquanpeng/one-api/relay/model"
	"github.com/songquanpeng/one-api/relay/relaymode"
)

type ChannelTestResponse struct {
	Success bool    `json:"success"`
	Message string  `json:"message"`
	Time    float64 `json:"time"`
}

// TestChannel Test channel availability
// @Summary Test channel connectivity
// @Description Verify channel configuration by invoking actual API endpoints
// @Tags Channel
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param channel_id path int true "Channel ID"
// @Param model query string false "Model name"
// @Success 200 {object} model.CommonResponse{data=ChannelTestResponse}
// @Router /api/channels/test/{channel_id} [get]
func TestChannel(c *gin.Context) {
	ctx := c.Request.Context()
	channel_id, err := strconv.Atoi(c.Param("channel_id"))
	if err != nil {
		c.JSON(http.StatusOK, model.ParamError.ToResponse(err))
		return
	}
	channel, err := model.GetChannelByID(int64(channel_id))
	if err != nil {
		c.JSON(http.StatusOK, model.ParamError.ToResponse(err))
		return
	}
	modelName := c.Query("model")
	testRequest := buildTestRequest(modelName)
	tik := time.Now()
	responseMessage, err, _ := testChannel(ctx, channel, testRequest)
	tok := time.Now()
	milliseconds := tok.Sub(tik).Milliseconds()
	if err != nil {
		milliseconds = 0
	}
	go channel.UpdateResponseTime(milliseconds)
	consumedTime := float64(milliseconds) / 1000.0
	if err != nil {
		c.JSON(http.StatusOK, model.ParamError.ToResponse(err))
		return
	}
	c.JSON(http.StatusOK, model.Success.ToResponse(ChannelTestResponse{
		Success: true,
		Message: responseMessage,
		Time:    consumedTime,
	}))
}

func testChannel(ctx context.Context, channel *model.Channel, request *relaymodel.GeneralOpenAIRequest) (responseMessage string, err error, openaiErr *relaymodel.Error) {
	//startTime := time.Now()
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)
	c.Request = &http.Request{
		Method: "POST",
		URL:    &url.URL{Path: "/v1/chat/completions"},
		Body:   nil,
		Header: make(http.Header),
	}
	c.Request.Header.Set("Authorization", "Bearer "+channel.Key)
	c.Request.Header.Set("Content-Type", "application/json")
	c.Set(ctxkey.Channel, channel.Type)
	c.Set(ctxkey.BaseURL, channel.GetBaseURL())
	cfg, _ := channel.LoadConfig()
	c.Set(ctxkey.Config, cfg)
	middleware.SetupContextForSelectedChannel(c, channel, "")
	meta := meta.GetByContext(c)
	apiType := model.GetApiType(channel.Type)
	meta.APIType = apiType
	// apiType := channeltype.ToAPIType(channel.Type)
	adaptor := service.GetAdaptor(meta.APIType)
	err = service.SetCustomConfig(&adaptor, &custom.CustomConfig{
		ConversationId: "",
		UserId:         "53AIHub",
	})
	if err != nil {
		return "", err, nil
	}
	// adaptor := relay.GetAdaptor(apiType)
	if adaptor == nil {
		return "", fmt.Errorf("invalid api type: %d, adaptor is nil", apiType), nil
	}
	adaptor.Init(meta)
	modelName := request.Model
	modelMap := channel.GetModelMapping()
	if modelName == "" || !strings.Contains(channel.Models, modelName) {
		modelNames := strings.Split(channel.Models, ",")
		if len(modelNames) > 0 {
			modelName = modelNames[0]
		}
	}
	if modelMap != nil && modelMap[modelName] != "" {
		modelName = modelMap[modelName]
	}
	meta.OriginModelName, meta.ActualModelName = request.Model, modelName
	request.Model = modelName
	convertedRequest, err := adaptor.ConvertRequest(c, relaymode.ChatCompletions, request)
	if err != nil {
		return "", err, nil
	}
	jsonData, err := json.Marshal(convertedRequest)
	if err != nil {
		return "", err, nil
	}
	defer func() {
		//logContent := fmt.Sprintf("渠道 %s 测试成功,响应:%s", channel.Name, responseMessage)
		if err != nil || openaiErr != nil {
			// errorMessage := ""
			// if err != nil {
			// 	errorMessage = err.Error()
			// } else {
			// 	errorMessage = openaiErr.Message
			// }
			//logContent = fmt.Sprintf("渠道 %s 测试失败,错误:%s", channel.Name, errorMessage)
		}
		// go model.RecordTestLog(ctx, &model.Log{
		// 	ChannelId:   channel.Id,
		// 	ModelName:   modelName,
		// 	Content:     logContent,
		// 	ElapsedTime: helper.CalcElapsedTime(startTime),
		// })
	}()
	logger.SysLog(string(jsonData))
	requestBody := bytes.NewBuffer(jsonData)
	c.Request.Body = io.NopCloser(requestBody)
	resp, err := adaptor.DoRequest(c, meta, requestBody)
	if err != nil {
		return "", err, nil
	}
	if resp != nil && resp.StatusCode != http.StatusOK {
		// err := controller.RelayErrorHandler(resp)
		// err := errors.New("http status code: " + strconv.Itoa(resp.StatusCode))
		// errorMessage := err.Error.Message
		// if errorMessage != "" {
		// 	errorMessage = ", error message: " + errorMessage
		// }
		return "", fmt.Errorf("http status code: %d%s", resp.StatusCode, ""), nil
	}
	usage, respErr := adaptor.DoResponse(c, resp, meta)
	if respErr != nil {
		return "", fmt.Errorf("%s", respErr.Error.Message), &respErr.Error
	}
	if usage == nil {
		return "", errors.New("usage is nil"), nil
	}
	rawResponse := w.Body.String()
	_, responseMessage, err = parseTestResponse(rawResponse)
	if err != nil {
		logger.SysError(fmt.Sprintf("failed to parse error: %s, \nresponse: %s", err.Error(), rawResponse))
		return "", err, nil
	}
	result := w.Result()
	// print result.Body
	respBody, err := io.ReadAll(result.Body)
	if err != nil {
		return "", err, nil
	}
	logger.SysLog(fmt.Sprintf("testing channel #%d, response: \n%s", channel.ChannelID, string(respBody)))
	return responseMessage, nil, nil
}

func parseTestResponse(resp string) (*openai.TextResponse, string, error) {
	var response openai.TextResponse
	err := json.Unmarshal([]byte(resp), &response)
	if err != nil {
		return nil, "", err
	}
	if len(response.Choices) == 0 {
		return nil, "", errors.New("response has no choices")
	}
	stringContent, ok := response.Choices[0].Content.(string)
	if !ok {
		return nil, "", errors.New("response content is not string")
	}
	return &response, stringContent, nil
}

func buildTestRequest(model string) *relaymodel.GeneralOpenAIRequest {
	if model == "" {
		model = "gpt-3.5-turbo"
	}
	testRequest := &relaymodel.GeneralOpenAIRequest{
		Model: model,
	}
	testMessage := relaymodel.Message{
		Role:    "user",
		Content: "Output only your specific model name with no additional text.",
	}
	testRequest.Messages = append(testRequest.Messages, testMessage)
	return testRequest
}


================================================
FILE: api/controller/channel.go
================================================
package controller

import (
	"fmt"
	"net/http"
	"strconv"
	"strings"

	"github.com/53AI/53AIHub/config"
	"github.com/53AI/53AIHub/model"
	"github.com/gin-gonic/gin"
)

// autoAssignCozeStudioProvider automatically assigns a ProviderID for CozeStudio channels
// when ProviderID is 0 in the request
// In multi-provider environments, this should be explicitly specified by the client
func autoAssignCozeStudioProvider(channel *model.Channel) error {
	// Check if this is a CozeStudio channel and ProviderID is 0
	if channel.Type == model.ChannelApiTypeCozeStudio && channel.ProviderID == 0 {
		// Get all CozeStudio providers for this enterprise
		providers, err := model.GetProvidersByEidAndProviderType(channel.Eid, model.ProviderTypeCozeStudio)
		if err != nil {
			return err
		}
		if len(providers) == 0 {
			return fmt.Errorf("no CozeStudio provider found for enterprise %d", channel.Eid)
		}

		// If there's only one provider, auto-assign it
		if len(providers) == 1 {
			channel.ProviderID = providers[0].ProviderID
		} else {
			// Multiple providers found - this is ambiguous in multi-provider environment
			// Return error to force explicit provider selection
			return fmt.Errorf("multiple CozeStudio providers found (%d), please specify provider_id explicitly", len(providers))
		}
	}
	return nil
}

type ChannelRequest struct {
	Type         int     `json:"type" example:"1"`
	ModelType    *int    `json:"model_type" example:"1"`
	Key          string  `json:"key" example:"channel_key"`
	Name         string  `json:"name" example:"channel_name"`
	Models       string  `json:"models" example:"gpt-3.5-turbo"`
	Config       string  `json:"config" example:"{\"region\":\"us-east-1\"}"`
	ModelMapping *string `json:"model_mapping"`
	Weight       *uint   `json:"weight"`
	Priority     *int64  `json:"priority"`
	BaseURL      *string `json:"base_url"`
	Other        *string `json:"other"`
	ProviderID   *int64  `json:"provider_id" example:"181"`
}

// @Summary Create channel
// @Description Create new channel configuration
// @Tags Channel
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param channel body ChannelRequest true "Channel data"
// @Success 200 {object} model.CommonResponse
// @Router /api/channels [post]
func CreateChannel(c *gin.Context) {
	var req ChannelRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(err))
		return
	}

	channel := model.Channel{
		Eid:          config.GetEID(c),
		Type:         req.Type,
		ModelType:    1,
		Key:          req.Key,
		Name:         req.Name,
		Models:       req.Models,
		Config:       req.Config,
		ModelMapping: req.ModelMapping,
		Weight:       req.Weight,
		Priority:     req.Priority,
		BaseURL:      req.BaseURL,
		Other:        req.Other,
		ProviderID:   0, // Default to 0 if not provided
	}

	// Set ProviderID if provided in request
	if req.ProviderID != nil {
		channel.ProviderID = *req.ProviderID
	}
	// Set ModelType: default 1; if provided and valid (1,2,3), use it
	if req.ModelType != nil {
		if model.IsValidModelType(*req.ModelType) {
			channel.ModelType = *req.ModelType
		}
	}

	channel.Models = model.ProcessModelNames(req.Models, channel.Type)
	if channel.Models == "" {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(strings.NewReader("models is required")))
		return
	}

	// Auto assign ProviderID for CozeStudio channels if needed
	if err := autoAssignCozeStudioProvider(&channel); err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	if err := model.CreateChannel(&channel); err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(channel))
}

// @Summary Get channel
// @Description Get channel configuration by ID
// @Tags Channel
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param channel_id path int true "Channel ID"
// @Success 200 {object} model.CommonResponse
// @Router /api/channels/{channel_id} [get]
func GetChannel(c *gin.Context) {
	id, _ := strconv.ParseInt(c.Param("channel_id"), 10, 64)
	channel, err := model.GetChannelByID(id)

	if err != nil || channel.Eid != config.GetEID(c) {
		c.JSON(http.StatusNotFound, model.NotFound.ToResponse(nil))
		return
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(channel))
}

// @Summary Update channel
// @Description Update existing channel configuration
// @Tags Channel
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param channel_id path int true "Channel ID"
// @Param channel body ChannelRequest true "Update data"
// @Success 200 {object} model.CommonResponse
// @Router /api/channels/{channel_id} [put]
func UpdateChannel(c *gin.Context) {
	id, _ := strconv.ParseInt(c.Param("channel_id"), 10, 64)
	channel, err := model.GetChannelByID(id)

	if err != nil || channel.Eid != config.GetEID(c) {
		c.JSON(http.StatusNotFound, model.NotFound.ToResponse(nil))
		return
	}

	var req ChannelRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(err))
		return
	}

	channel.Models = model.ProcessModelNames(req.Models, channel.Type)

	if channel.Models == "" {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(strings.NewReader("models is required")))
		return
	}

	channel.Type = req.Type
	channel.Key = req.Key
	channel.Name = req.Name

	channel.Config = req.Config
	channel.ModelMapping = req.ModelMapping
	channel.Weight = req.Weight
	channel.Priority = req.Priority
	channel.BaseURL = req.BaseURL
	channel.Other = req.Other

	// Update ProviderID if provided in request
	if req.ProviderID != nil {
		channel.ProviderID = *req.ProviderID
	}
	// Update ModelType if provided and valid (1,2,3)
	if req.ModelType != nil {
		if model.IsValidModelType(*req.ModelType) {
			channel.ModelType = *req.ModelType
		}
	}

	// Auto assign ProviderID for CozeStudio channels if needed
	if err := autoAssignCozeStudioProvider(channel); err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	if err := model.UpdateChannel(channel); err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(channel))
}

// @Summary Delete channel
// @Description Delete channel by ID
// @Tags Channel
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param channel_id path int true "Channel ID"
// @Success 200 {object} model.CommonResponse
// @Router /api/channels/{channel_id} [delete]
func DeleteChannel(c *gin.Context) {
	id, _ := strconv.ParseInt(c.Param("channel_id"), 10, 64)
	channel, err := model.GetChannelByID(id)

	if err == nil && channel.Eid == config.GetEID(c) {
		err = model.DeleteChannelByID(id)
	}

	if err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(nil))
}

// @Summary Get all channels
// @Description Get all channels for current enterprise
// @Tags Channel
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param provider_id query int false "Provider ID, 0 means platform-added keys, non-zero means get channels from other platforms" example:"0"
// @Param channel_types query string false "Channel type filters" example:"1,1001,1002"
// @Param model_type query string false "Model type filters: 1=LLM,2=Embedding,3=Rerank; comma-separated supported; 0 or empty means no filter" example:"1,3"
// @Success 200 {object} model.CommonResponse
// @Router /api/channels [get]
func GetChannels(c *gin.Context) {
	providerId, _ := strconv.ParseInt(c.Query("provider_id"), 10, 64)
	channelTypesStr := c.Query("channel_types")
	var channelTypes []int
	if channelTypesStr != "" {
		for _, s := range strings.Split(channelTypesStr, ",") {
			if t, err := strconv.Atoi(strings.TrimSpace(s)); err == nil {
				channelTypes = append(channelTypes, t)
			}
		}
	}

	modelTypesStr := c.Query("model_type")
	var modelTypes []int
	if modelTypesStr != "" {
		for _, s := range strings.Split(modelTypesStr, ",") {
			if t, err := strconv.Atoi(strings.TrimSpace(s)); err == nil {
				// Only accept defined model types; 0 or invalid values mean no filter
				if model.IsValidModelType(t) {
					modelTypes = append(modelTypes, t)
				}
			}
		}
	}

	channels, err := model.GetChannelsByEidAndParams(config.GetEID(c), providerId, channelTypes, modelTypes)
	if err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(channels))
}


================================================
FILE: api/controller/conversation.go
================================================
package controller

import (
	"net/http"
	"strconv"

	"github.com/53AI/53AIHub/config"
	"github.com/53AI/53AIHub/model"
	"github.com/gin-gonic/gin"
)

type ConversationRequest struct {
	Title   string `json:"title"`
	AgentID int64  `json:"agent_id" binding:"required"`
}

type ConversationUpdateRequest struct {
	Title string `json:"title"`
}

type ConversationResponse struct {
	Count         int64                 `json:"count"`
	Conversations []*model.Conversation `json:"conversations"`
}

type ConversationListRequest struct {
	Keyword string `json:"keyword" form:"keyword"`
	Offset  int    `json:"offset" form:"offset" example:"0"`
	Limit   int    `json:"limit" form:"limit" example:"10"`
}

// @Summary Create conversation
// @Description Create a new conversation
// @Tags Conversation
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param conversation body ConversationRequest true "Conversation data"
// @Success 200 {object} model.CommonResponse{data=model.Conversation} "Success"
// @Router /api/conversations [post]
func CreateConversation(c *gin.Context) {
	var req ConversationRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(nil))
		return
	}

	eid := config.GetEID(c)
	agent, err := model.GetAgentByID(eid, req.AgentID)
	if err != nil {
		c.JSON(http.StatusNotFound, model.NotFound.ToResponse(nil))
		return
	}

	conversation := &model.Conversation{
		Eid:     eid,
		UserID:  config.GetUserId(c),
		AgentID: req.AgentID,
		Title:   req.Title,
		Status:  model.ConversationStatusActive,
		Model:   agent.Model,
	}

	if err := model.CreateConversation(conversation); err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	conversation.LoadAgent()
	c.JSON(http.StatusOK, model.Success.ToResponse(conversation))
}

// @Summary Get conversation details
// @Description Get conversation details by ID
// @Tags Conversation
// @Produce json
// @Security BearerAuth
// @Param conversation_id path int true "Conversation ID"
// @Success 200 {object} model.CommonResponse{data=model.Conversation} "Success"
// @Router /api/conversations/{conversation_id} [get]
func GetConversation(c *gin.Context) {
	conversationID, err := strconv.ParseInt(c.Param("conversation_id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(nil))
		return
	}

	conversation, err := model.GetConversationByID(config.GetEID(c), config.GetUserId(c), conversationID)
	if err != nil {
		c.JSON(http.StatusNotFound, model.NotFound.ToResponse(nil))
		return
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(conversation))
}

// @Summary Get user conversations
// @Description Get conversation list for current user
// @Tags Conversation
// @Produce json
// @Security BearerAuth
// @Param keyword query string false "Search keyword"
// @Param offset query int false "Offset" default(0)
// @Param limit query int false "Limit" default(10)
// @Success 200 {object} model.CommonResponse{data=ConversationResponse} "Success"
// @Router /api/conversations [get]
func GetConversations(c *gin.Context) {
	var req ConversationListRequest
	if err := c.ShouldBindQuery(&req); err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(err))
		return
	}

	conversations, err := model.GetConversationsByUserID(config.GetEID(c), config.GetUserId(c))
	if err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(&ConversationResponse{
		Count:         int64(len(conversations)),
		Conversations: conversations,
	}))
}

// @Summary Update conversation
// @Description Update conversation information
// @Tags Conversation
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param conversation_id path int true "Conversation ID"
// @Param conversation body ConversationUpdateRequest true "Conversation data"
// @Success 200 {object} model.CommonResponse{data=model.Conversation} "Success"
// @Router /api/conversations/{conversation_id} [put]
func UpdateConversation(c *gin.Context) {
	conversationID, err := strconv.ParseInt(c.Param("conversation_id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(nil))
		return
	}

	var req ConversationUpdateRequest
	if err = c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(err))
		return
	}

	conversation, err := model.GetConversationByID(config.GetEID(c), config.GetUserId(c), conversationID)
	if err != nil {
		c.JSON(http.StatusNotFound, model.NotFound.ToResponse(nil))
		return
	}

	conversation.Title = req.Title

	if err := model.UpdateConversation(conversation); err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(conversation))
}

type UserConversationListRequest struct {
	ConversationListRequest
	CreatedAtStart int64 `form:"created_at_start"`
	CreatedAtEnd   int64 `form:"created_at_end"`
	AgentID        int64 `form:"agent_id"`
}

// @Summary Get user conversations
// @Description Get paginated conversation list for specified user with time range filter
// @Tags Conversation
// @Produce json
// @Security BearerAuth
// @Param user_id path int true "Target user ID"
// @Param keyword query string false "Search keyword"
// @Param created_at_start query int64 false "Start time (millisecond timestamp)"
// @Param created_at_end query int64 false "End time (millisecond timestamp)"
// @Param offset query int false "Offset" default(0)
// @Param limit query int false "Limit" default(10)
// @Success 200 {object} model.CommonResponse{data=ConversationSummaryResponse} "Success"
// @Router /api/users/{user_id}/conversations [get]
func GetUserConversations(c *gin.Context) {
	userID, err := strconv.ParseInt(c.Param("user_id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(nil))
		return
	}

	user, err := model.GetUserByID(userID)
	if err != nil {
		c.JSON(http.StatusNotFound, model.NotFound.ToResponse(nil))
		return
	}
	var req UserConversationListRequest
	if err = c.ShouldBindQuery(&req); err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(err))
		return
	}

	conversations, total, err := model.GetUserConversationsWithFilter(
		config.GetEID(c),
		userID,
		req.Keyword,
		req.CreatedAtStart,
		req.CreatedAtEnd,
		req.Offset,
		req.Limit,
	)
	if err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	var summaries []*ConversationSummary = make([]*ConversationSummary, 0)
	for _, conv := range conversations {
		messageCount, msgErr := model.GetMessageCountByConversationID(conv.ConversationID)
		if msgErr != nil {
			messageCount = 0
		}
		firstMessage, firstMsgErr := model.GetFirstMessageByConversationID(conv.ConversationID)
		if firstMsgErr != nil {
			firstMessage = ""
		}
		summaries = append(summaries, &ConversationSummary{
			ID:           conv.ConversationID,
			Title:        conv.Title,
			CreatedAt:    conv.CreatedTime,
			Summary:      firstMessage,
			MessageCount: messageCount,
			User:         UserInfo{user.UserID, user.Username},
		})
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(&ConversationSummaryResponse{
		Count: total,
		Items: summaries,
	}))
}

type UserInfo struct {
	UserID   int64  `json:"user_id"`
	Username string `json:"username"`
}

// ConversationSummary 定义返回的会话摘要结构
type ConversationSummary struct {
	ID           int64    `json:"id"`
	Title        string   `json:"title"`
	CreatedAt    int64    `json:"created_at"`
	Summary      string   `json:"summary"`
	MessageCount int      `json:"message_count"`
	User         UserInfo `json:"user" omitempty:"true"`
}

// ConversationSummaryResponse 分页返回结构
type ConversationSummaryResponse struct {
	Count int64                  `json:"count"`
	Items []*ConversationSummary `json:"items"`
}

// @Summary Get agent conversations
// @Description Get paginated conversation list for specified agent with time range filter
// @Tags Conversation
// @Produce json
// @Security BearerAuth
// @Param agent_id path int true "Target agent ID"
// @Param keyword query string false "Search keyword"
// @Param created_at_start query int64 false "Start time (millisecond timestamp)"
// @Param created_at_end query int64 false "End time (millisecond timestamp)"
// @Param offset query int false "Offset" default(0)
// @Param limit query int false "Limit" default(10)
// @Success 200 {object} model.CommonResponse{data=ConversationSummaryResponse} "Success"
// @Router /api/agents/{agent_id}/conversations [get]
func GetAgentConversations(c *gin.Context) {
	agentID, err := strconv.ParseInt(c.Param("agent_id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(nil))
		return
	}

	var req UserConversationListRequest
	if err = c.ShouldBindQuery(&req); err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(err))
		return
	}

	conversations, total, err := model.GetAgentConversationsWithFilter(
		config.GetEID(c),
		agentID,
		req.Keyword,
		req.CreatedAtStart,
		req.CreatedAtEnd,
		req.Offset,
		req.Limit,
	)
	if err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	var summaries []*ConversationSummary = make([]*ConversationSummary, 0)
	for _, conv := range conversations {
		messageCount, msgErr := model.GetMessageCountByConversationID(conv.ConversationID)
		if msgErr != nil {
			messageCount = 0
		}
		firstMessage, firstMsgErr := model.GetFirstMessageByConversationID(conv.ConversationID)
		if firstMsgErr != nil {
			firstMessage = ""
		}
		conv.LoadUser()
		summaries = append(summaries, &ConversationSummary{
			ID:           conv.ConversationID,
			Title:        conv.Title,
			CreatedAt:    conv.CreatedTime,
			Summary:      firstMessage,
			MessageCount: messageCount,
			User:         UserInfo{conv.User.UserID, conv.User.Username},
		})
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(&ConversationSummaryResponse{
		Count: total,
		Items: summaries,
	}))
}

// @Summary Delete conversation
// @Description Delete specified conversation
// @Tags Conversation
// @Produce json
// @Security BearerAuth
// @Param conversation_id path int true "Conversation ID"
// @Success 200 {object} model.CommonResponse "Success"
// @Router /api/conversations/{conversation_id} [delete]
func DeleteConversation(c *gin.Context) {
	conversationID, err := strconv.ParseInt(c.Param("conversation_id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(nil))
		return
	}

	if err := model.DeleteConversation(config.GetEID(c), conversationID); err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(nil))
}


================================================
FILE: api/controller/coze.go
================================================
package controller

import (
	"net/http"
	"strconv"

	"github.com/53AI/53AIHub/common/logger"
	"github.com/53AI/53AIHub/config"
	"github.com/53AI/53AIHub/model"
	"github.com/53AI/53AIHub/service"
	"github.com/gin-gonic/gin"
)

// GetCozeAllWorkspaces Get all Coze workspaces
// @Summary Get all Coze workspaces
// @Description Get all Coze workspaces list under current enterprise
// @Tags Coze
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param provider_id query int false "Provider ID (optional, for backward compatibility)"
// @Success 200 {object} model.CommonResponse{data=[]coze.Workspace}
// @Router /api/coze/workspaces [get]
func GetCozeAllWorkspaces(c *gin.Context) {
	eid := config.GetEID(c)
	providerID, _ := strconv.ParseInt(c.DefaultQuery("provider_id", "0"), 10, 64)
	provider, err := model.GetProviderByEidAndProviderTypeWithOptionalID(eid, int64(model.ProviderTypeCozeCn), providerID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, model.ProviderNoFoundError.ToResponse(err))
		return
	}
	ser := service.CozeService{
		Provider: provider,
	}
	workspaces, err := ser.GetAllWorkspace()
	if err != nil {
		c.JSON(http.StatusInternalServerError, model.ProviderNoFoundError.ToResponse(err))
		return
	}
	c.JSON(http.StatusOK, model.Success.ToResponse(workspaces))
}

// GetCozeAllBots Get all bots in specified workspace
// @Summary Get workspace bots list
// @Description Get all bots list under specified Coze workspace
// @Tags Coze
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param workspace_id path string true "Workspace ID"
// @Param provider_id query int false "Provider ID (optional, for backward compatibility)"
// @Success 200 {object} model.CommonResponse{data=[]coze.Bot}
// @Router /api/coze/workspaces/{workspace_id}/bots [get]
func GetCozeAllBots(c *gin.Context) {
	workspaceID := c.Param("workspace_id")
	if workspaceID == "" {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(nil))
		return
	}

	eid := config.GetEID(c)
	providerID, _ := strconv.ParseInt(c.DefaultQuery("provider_id", "0"), 10, 64)
	provider, err := model.GetProviderByEidAndProviderTypeWithOptionalID(eid, int64(model.ProviderTypeCozeCn), providerID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, model.ProviderNoFoundError.ToResponse(err))
		return
	}

	ser := service.CozeService{
		Provider: provider,
	}

	bots, err := ser.GetAllBot(workspaceID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, model.ProviderNoFoundError.ToResponse(err))
		return
	}

	// 缓存所有bot图标(使用新的基于UploadFile的方式)
	logger.SysLogf("开始缓存 %d 个bot图标", len(bots))
	for i := range bots {
		if bots[i].IconURL != "" {
			logger.SysLogf("开始缓存bot图标,bot_id: %s, icon_url: %s", bots[i].BotID, bots[i].IconURL)
			cachedIconURL, err := ser.CacheBotIconWithUploadFile(bots[i].BotID, bots[i].IconURL, eid)
			if err != nil {
				// 如果缓存失败,记录日志但继续执行
				logger.SysLogf("缓存bot图标失败,bot_id: %s, error: %v", bots[i].BotID, err)
				// 不中断整个流程
				continue
			}
			// 使用缓存的图标URL
			logger.SysLogf("成功缓存bot图标,bot_id: %s, cached_url: %s", bots[i].BotID, cachedIconURL)
			bots[i].IconURL = cachedIconURL
		}
	}
	//重新合并请求

	var botIds []string
	for _, bot := range bots {
		botIds = append(botIds, bot.BotID)
	}

	ser.UpdateCozeChannel(botIds, &provider)

	c.JSON(http.StatusOK, model.Success.ToResponse(bots))
}


================================================
FILE: api/controller/department.go
================================================
package controller

import (
	"net/http"
	"strconv"

	"github.com/53AI/53AIHub/config"
	"github.com/53AI/53AIHub/model"
	"github.com/gin-gonic/gin"
)

// DepartmentRequest represents the request body for department operations
type DepartmentRequest struct {
	PDID int64  `json:"pdid"`
	Name string `json:"name" binding:"required"`
	Sort int    `json:"sort"`
}

type UpdateDepartmentRequest struct {
	Name string `json:"name" binding:"required"`
	Sort int    `json:"sort"`
}

// DepartmentResponse represents the response for department list
type DepartmentResponse struct {
	Departments []*model.Department `json:"departments"`
	Total       int                 `json:"total"`
}

// DepartmentTreeResponse represents the response for department tree
type DepartmentTreeResponse struct {
	Tree []*model.DepartmentNode `json:"tree"`
}

type BindRequest struct {
	Bid    int64 `json:"bid"`
	From   int   `json:"from"`
	UserID int64 `json:"user_id"`
}
type UnBindRequest struct {
	From   int   `json:"from"`
	UserID int64 `json:"user_id"`
}

// CreateDepartment creates a new department
// @Summary Create a new department
// @Description Create a new department in the organization
// @Tags Department
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body DepartmentRequest true "Department information"
// @Success 200 {object} model.CommonResponse{data=model.Department} "Success"
// @Failure 400 {object} model.CommonResponse "Bad request"
// @Failure 500 {object} model.CommonResponse "Internal server error"
// @Router /api/departments [post]
func CreateDepartment(c *gin.Context) {
	var req DepartmentRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(err))
		return
	}

	// Create department object
	dept := &model.Department{
		PDID: req.PDID,
		EID:  config.GetEID(c),
		Name: req.Name,
		Sort: req.Sort,
		From: model.DepartmentFromBackend,
	}

	// Create department in database
	if err := model.CreateDepartment(dept); err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(dept))
}

// GetDepartment retrieves a department by ID
// @Summary Get department by ID
// @Description Get department details by ID
// @Tags Department
// @Produce json
// @Security BearerAuth
// @Param did path int true "Department ID"
// @Success 200 {object} model.CommonResponse{data=model.Department} "Success"
// @Failure 404 {object} model.CommonResponse "Department not found"
// @Failure 500 {object} model.CommonResponse "Internal server error"
// @Router /api/departments/{did} [get]
func GetDepartment(c *gin.Context) {
	didStr := c.Param("did")
	did, err := strconv.ParseInt(didStr, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(err))
		return
	}

	dept, err := model.GetDepartmentByID(config.GetEID(c), did)
	if err != nil {
		c.JSON(http.StatusNotFound, model.NotFound.ToResponse(err))
		return
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(dept))
}

// UpdateDepartment updates an existing department
// @Summary Update department
// @Description Update an existing department
// @Tags Department
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param did path int true "Department ID"
// @Param request body UpdateDepartmentRequest true "Department information"
// @Success 200 {object} model.CommonResponse{data=model.Department} "Success"
// @Failure 400 {object} model.CommonResponse "Bad request"
// @Failure 404 {object} model.CommonResponse "Department not found"
// @Failure 500 {object} model.CommonResponse "Internal server error"
// @Router /api/departments/{did} [put]
func UpdateDepartment(c *gin.Context) {
	didStr := c.Param("did")
	did, err := strconv.ParseInt(didStr, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(err))
		return
	}

	var req UpdateDepartmentRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(err))
		return
	}

	// Get existing department
	dept, err := model.GetDepartmentByID(config.GetEID(c), did)
	if err != nil {
		c.JSON(http.StatusNotFound, model.NotFound.ToResponse(err))
		return
	}

	// Update department fields
	dept.Name = req.Name
	dept.Sort = req.Sort

	// Update department in database
	if err := model.UpdateDepartment(dept); err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(dept))
}

// DeleteDepartment deletes a department
// @Summary Delete department
// @Description Delete a department and optionally its children
// @Tags Department
// @Produce json
// @Security BearerAuth
// @Param did path int true "Department ID"
// @Param delete_children query bool false "Delete children" default(false)
// @Success 200 {object} model.CommonResponse "Success"
// @Failure 400 {object} model.CommonResponse "Bad request"
// @Failure 404 {object} model.CommonResponse "Department not found"
// @Failure 500 {object} model.CommonResponse "Internal server error"
// @Router /api/departments/{did} [delete]
func DeleteDepartment(c *gin.Context) {
	didStr := c.Param("did")
	did, err := strconv.ParseInt(didStr, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(err))
		return
	}

	deleteChildrenStr := c.DefaultQuery("delete_children", "false")
	deleteChildren := deleteChildrenStr == "true"

	if err := model.DeleteDepartment(config.GetEID(c), did, deleteChildren); err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(nil))
}

// GetDepartments retrieves all departments
// @Summary Get all departments
// @Description Get all departments for the current enterprise
// @Tags Department
// @Produce json
// @Security BearerAuth
// @Param keyword query string false "Search keyword"
// @Param limit query int false "Limit results" default(100)
// @Success 200 {object} model.CommonResponse{data=DepartmentResponse} "Success"
// @Failure 500 {object} model.CommonResponse "Internal server error"
// @Router /api/departments [get]
func GetDepartments(c *gin.Context) {
	keyword := c.Query("keyword")
	limitStr := c.DefaultQuery("limit", "100")
	limit, _ := strconv.Atoi(limitStr)

	departments, err := model.SearchDepartments(config.GetEID(c), keyword, limit)
	if err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(DepartmentResponse{
		Departments: departments,
		Total:       len(departments),
	}))
}

// GetChildDepartments retrieves child departments
// @Summary Get child departments
// @Description Get all child departments for a specific department
// @Tags Department
// @Produce json
// @Security BearerAuth
// @Param pdid path int true "Parent Department ID"
// @Success 200 {object} model.CommonResponse{data=DepartmentResponse} "Success"
// @Failure 400 {object} model.CommonResponse "Bad request"
// @Failure 500 {object} model.CommonResponse "Internal server error"
// @Router /api/departments/children/{pdid} [get]
func GetChildDepartments(c *gin.Context) {
	pdidStr := c.Param("pdid")
	pdid, err := strconv.ParseInt(pdidStr, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(err))
		return
	}

	departments, err := model.GetChildDepartments(config.GetEID(c), pdid)
	if err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(DepartmentResponse{
		Departments: departments,
		Total:       len(departments),
	}))
}

// GetDepartmentTree retrieves the department hierarchy
// @Summary Get department tree
// @Description Get hierarchical structure of departments
// @Tags Department
// @Produce json
// @Security BearerAuth
// @Param from query int false "Filter by source (0: backend [default], 1: wecom,2:dingtalk)" default(0)
// @Success 200 {object} model.CommonResponse{data=DepartmentTreeResponse} "Success"
// @Failure 500 {object} model.CommonResponse "Internal server error"
// @Router /api/departments/tree [get]
func GetDepartmentTree(c *gin.Context) {
	fromStr := c.Query("from")
	from, err := strconv.Atoi(fromStr)
	if err != nil {
		from = model.DepartmentFromBackend
	}
	tree, err := model.GetDepartmentTree(config.GetEID(c), from)
	if err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(DepartmentTreeResponse{
		Tree: tree,
	}))
}

// @Summary Bind member to department
// @Description Bind a member to specific department with given role
// @Tags Department
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body BindRequest true "Binding request parameters"
// @Success 200 {object} model.CommonResponse "Success"
// @Router /api/departments/bind-member [post]
func DepartmentBindMember(c *gin.Context) {
	eid := config.GetEID(c)
	// Replace query params with body params
	var req BindRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(err))
		return
	}

	// Now use req.Bid, req.From, req.UserID instead of the query params
	bid := req.Bid
	from := req.From
	userID := req.UserID

	var user *model.User
	err := model.DB.Where("eid = ? AND user_id = ?", eid, userID).First(&user).Error
	if err != nil {
		c.JSON(http.StatusBadRequest, model.NotFound.ToResponse(err))
		return
	}

	var memberBinding *model.MemberBinding
	memberBinding, _ = model.GetMemberBindingByMidAndFrom(user.UserID, from)

	if memberBinding != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse("user already bound"))
		return
	}

	err = model.DB.Where("eid =? AND id =? AND `from` =? AND mid = 0", eid, bid, from).First(&memberBinding).Error
	if err != nil || memberBinding == nil {
		c.JSON(http.StatusBadRequest, model.NotFound.ToResponse(err))
		return
	}

	memberBinding.MID = user.UserID
	memberBinding.Status = model.MemberBindingStatusActive

	err = model.UpdateMemberBinding(memberBinding)
	if err != nil {
		c.JSON(http.StatusInternalServerError, model.DBError.ToResponse(err))
		return
	}

	c.JSON(http.StatusOK, model.Success.ToResponse(nil))
}

// @Summary Unbind member from department
// @Description Remove a member's binding from department
// @Tags Department
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body UnBindRequest true "Unbinding request parameters"
// @Success 200 {object} model.CommonResponse "Success"
// @Router /api/departments/bind-member [delete]
func DepartmentUnbindMember(c *gin.Context) {
	eid := config.GetEID(c)
	var req UnBindRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(err))
		return
	}
	var user *model.User
	err := model.DB.Where("eid = ? AND user_id = ?", eid, req.UserID).First(&user).Error
	if err != nil {
		c.JSON(http.StatusBadRequest, model.NotFound.ToResponse(err))
		return
	}

	memberBinding, err := model.GetMemberBindingByMidAndFrom(user.UserID, req.From)
	if err != nil || memberBinding == nil {
		c.JSON(http.StatusBadRequest, model.NotFound.ToResponse("user bind not bound"))
		return
	}

	memberBinding.MID = 0
	memberBinding.Status = model.MemberBindingStatusInactive
	err = model.UpdateMemberBinding(memberBinding)

	c.JSON(http.StatusOK, model.Success.ToResponse(nil))
}


================================================
FILE: api/controller/dify.go
================================================
package control
Download .txt
gitextract_88ren__n/

├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── README_CN.md
├── README_JA.md
├── api/
│   ├── .gitattributes
│   ├── .gitignore
│   ├── Dockerfile
│   ├── Makefile
│   ├── README.md
│   ├── bin/
│   │   ├── restart.sh
│   │   └── version.txt
│   ├── build.sh
│   ├── common/
│   │   ├── cache.go
│   │   ├── ctxkey/
│   │   │   └── key.go
│   │   ├── email.go
│   │   ├── init.go
│   │   ├── lock.go
│   │   ├── logger/
│   │   │   └── logger.go
│   │   ├── permission.go
│   │   ├── redis.go
│   │   ├── session/
│   │   │   └── key.go
│   │   ├── storage/
│   │   │   ├── storage.go
│   │   │   └── storage_test.go
│   │   ├── utils/
│   │   │   ├── ai53/
│   │   │   │   └── api.go
│   │   │   ├── appbuilder/
│   │   │   │   └── api.go
│   │   │   ├── coze/
│   │   │   │   └── api.go
│   │   │   ├── env/
│   │   │   │   └── env.go
│   │   │   ├── helper/
│   │   │   │   ├── helper.go
│   │   │   │   ├── key.go
│   │   │   │   └── sso_sign.go
│   │   │   ├── huawei_cloud/
│   │   │   │   ├── model.go
│   │   │   │   └── signature.go
│   │   │   ├── ip.go
│   │   │   ├── jwt/
│   │   │   │   └── jwt.go
│   │   │   ├── random.go
│   │   │   ├── snowflake.go
│   │   │   ├── system/
│   │   │   │   ├── machine.go
│   │   │   │   └── version.go
│   │   │   └── wxbizjsonmsgcrypt/
│   │   │       └── wxbizjsonmsgcrypt.go
│   │   └── validate.go
│   ├── config/
│   │   ├── config.go
│   │   ├── database.go
│   │   ├── encryption.go
│   │   └── storage.go
│   ├── controller/
│   │   ├── agent.go
│   │   ├── ai53.go
│   │   ├── ai_link.go
│   │   ├── appbuilder.go
│   │   ├── auth_sso.go
│   │   ├── channel-test.go
│   │   ├── channel.go
│   │   ├── conversation.go
│   │   ├── coze.go
│   │   ├── department.go
│   │   ├── dify.go
│   │   ├── email.go
│   │   ├── enterprise.go
│   │   ├── enterprise_config.go
│   │   ├── group.go
│   │   ├── maxkb.go
│   │   ├── message.go
│   │   ├── model.go
│   │   ├── navigation.go
│   │   ├── navigation_icons.go
│   │   ├── order.go
│   │   ├── pay.go
│   │   ├── pay_setting.go
│   │   ├── prompt.go
│   │   ├── provider.go
│   │   ├── provider_callback.go
│   │   ├── relay.go
│   │   ├── rerank.go
│   │   ├── response_handler.go
│   │   ├── setting.go
│   │   ├── share.go
│   │   ├── status.go
│   │   ├── subscription.go
│   │   ├── sync_organization.go
│   │   ├── system_log.go
│   │   ├── tencent.go
│   │   ├── upload.go
│   │   └── user.go
│   ├── docker/
│   │   └── docker-compose.yml
│   ├── docs/
│   │   └── .gitignore
│   ├── go.mod
│   ├── go.sum
│   ├── main.go
│   ├── middleware/
│   │   ├── auth.go
│   │   ├── cors.go
│   │   ├── distributor.go
│   │   ├── logger.go
│   │   └── relay_auth.go
│   ├── model/
│   │   ├── agent.go
│   │   ├── ai_link.go
│   │   ├── base.go
│   │   ├── cache.go
│   │   ├── channel.go
│   │   ├── channel_file_mapping.go
│   │   ├── conversation.go
│   │   ├── department.go
│   │   ├── dingtalk_corp.go
│   │   ├── dingtalk_suite.go
│   │   ├── enterprise.go
│   │   ├── enterprise_config.go
│   │   ├── enterprise_sync.go
│   │   ├── group.go
│   │   ├── like.go
│   │   ├── main.go
│   │   ├── member_binding.go
│   │   ├── member_department_relation.go
│   │   ├── message.go
│   │   ├── navigation.go
│   │   ├── navigation_content.go
│   │   ├── order.go
│   │   ├── pay_setting.go
│   │   ├── prompt.go
│   │   ├── provider.go
│   │   ├── resource_permission.go
│   │   ├── response.go
│   │   ├── setting.go
│   │   ├── share_record.go
│   │   ├── subscription.go
│   │   ├── system_log.go
│   │   ├── upload_file.go
│   │   ├── user.go
│   │   ├── verification_code.go
│   │   ├── wecom_corp.go
│   │   └── wecom_suite.go
│   ├── router/
│   │   ├── api.go
│   │   ├── main.go
│   │   ├── static.go
│   │   └── web.go
│   ├── service/
│   │   ├── adaptor.go
│   │   ├── ai53_provider.go
│   │   ├── appbuilder_provider.go
│   │   ├── channel_service.go
│   │   ├── coze_provider.go
│   │   ├── enterprise_config_service.go
│   │   ├── hub_adaptor/
│   │   │   ├── 53AI/
│   │   │   │   ├── adaptor.go
│   │   │   │   ├── constants.go
│   │   │   │   ├── main.go
│   │   │   │   ├── model.go
│   │   │   │   └── workflow.go
│   │   │   ├── appbuilder/
│   │   │   │   ├── adaptor.go
│   │   │   │   ├── constants.go
│   │   │   │   ├── main.go
│   │   │   │   └── model.go
│   │   │   ├── bailian/
│   │   │   │   ├── adaptor.go
│   │   │   │   ├── constants.go
│   │   │   │   ├── main.go
│   │   │   │   ├── model.go
│   │   │   │   ├── rerank.go
│   │   │   │   └── rerank_model.go
│   │   │   ├── coze/
│   │   │   │   ├── adaptor.go
│   │   │   │   ├── constant/
│   │   │   │   │   ├── contenttype/
│   │   │   │   │   │   └── define.go
│   │   │   │   │   ├── event/
│   │   │   │   │   │   └── define.go
│   │   │   │   │   └── messagetype/
│   │   │   │   │       └── define.go
│   │   │   │   ├── constants.go
│   │   │   │   ├── helper.go
│   │   │   │   ├── main.go
│   │   │   │   ├── model.go
│   │   │   │   └── workflow.go
│   │   │   ├── custom/
│   │   │   │   ├── common.go
│   │   │   │   ├── config.go
│   │   │   │   └── workflow.go
│   │   │   ├── dify/
│   │   │   │   ├── adaptor.go
│   │   │   │   ├── constants.go
│   │   │   │   ├── info.go
│   │   │   │   ├── main.go
│   │   │   │   ├── model.go
│   │   │   │   └── workflow.go
│   │   │   ├── fastgpt/
│   │   │   │   └── workflow.go
│   │   │   ├── n8n/
│   │   │   │   ├── README.md
│   │   │   │   ├── adaptor.go
│   │   │   │   ├── constants.go
│   │   │   │   ├── main.go
│   │   │   │   ├── model.go
│   │   │   │   └── workflow.go
│   │   │   ├── openai/
│   │   │   │   ├── adaptor.go
│   │   │   │   ├── compatible.go
│   │   │   │   ├── constants.go
│   │   │   │   ├── helper.go
│   │   │   │   ├── image.go
│   │   │   │   ├── main.go
│   │   │   │   ├── model.go
│   │   │   │   ├── token.go
│   │   │   │   └── util.go
│   │   │   ├── tencent/
│   │   │   │   ├── adaptor.go
│   │   │   │   ├── constants.go
│   │   │   │   ├── helper.go
│   │   │   │   ├── main.go
│   │   │   │   ├── model.go
│   │   │   │   └── sdk/
│   │   │   │       ├── client.go
│   │   │   │       ├── errors.go
│   │   │   │       └── models.go
│   │   │   ├── volcengine/
│   │   │   │   └── main.go
│   │   │   └── yuanqi/
│   │   │       ├── adaptor.go
│   │   │       ├── constants.go
│   │   │       ├── main.go
│   │   │       └── model.go
│   │   ├── organizational_service.go
│   │   ├── payment/
│   │   │   ├── alipay.go
│   │   │   ├── manual.go
│   │   │   ├── payment.go
│   │   │   ├── paypal.go
│   │   │   └── wechatpay.go
│   │   ├── rerank_service.go
│   │   ├── resource_permission_service.go
│   │   ├── user_service.go
│   │   └── version_feature.go
│   ├── static/
│   │   └── libs/
│   │       └── js/
│   │           ├── UEditor/
│   │           │   ├── dialogs/
│   │           │   │   ├── anchor/
│   │           │   │   │   └── anchor.html
│   │           │   │   ├── attachment/
│   │           │   │   │   ├── attachment.css
│   │           │   │   │   ├── attachment.html
│   │           │   │   │   └── attachment.js
│   │           │   │   ├── background/
│   │           │   │   │   ├── background.css
│   │           │   │   │   ├── background.html
│   │           │   │   │   └── background.js
│   │           │   │   ├── charts/
│   │           │   │   │   ├── chart.config.js
│   │           │   │   │   ├── charts.css
│   │           │   │   │   ├── charts.html
│   │           │   │   │   └── charts.js
│   │           │   │   ├── emotion/
│   │           │   │   │   ├── emotion.css
│   │           │   │   │   ├── emotion.html
│   │           │   │   │   └── emotion.js
│   │           │   │   ├── gmap/
│   │           │   │   │   └── gmap.html
│   │           │   │   ├── help/
│   │           │   │   │   ├── help.css
│   │           │   │   │   ├── help.html
│   │           │   │   │   └── help.js
│   │           │   │   ├── image/
│   │           │   │   │   ├── image.css
│   │           │   │   │   ├── image.html
│   │           │   │   │   └── image.js
│   │           │   │   ├── insertframe/
│   │           │   │   │   └── insertframe.html
│   │           │   │   ├── internal.js
│   │           │   │   ├── link/
│   │           │   │   │   └── link.html
│   │           │   │   ├── map/
│   │           │   │   │   ├── map.html
│   │           │   │   │   └── show.html
│   │           │   │   ├── music/
│   │           │   │   │   ├── music.css
│   │           │   │   │   ├── music.html
│   │           │   │   │   └── music.js
│   │           │   │   ├── preview/
│   │           │   │   │   └── preview.html
│   │           │   │   ├── scrawl/
│   │           │   │   │   ├── scrawl.css
│   │           │   │   │   ├── scrawl.html
│   │           │   │   │   └── scrawl.js
│   │           │   │   ├── searchreplace/
│   │           │   │   │   ├── searchreplace.html
│   │           │   │   │   └── searchreplace.js
│   │           │   │   ├── snapscreen/
│   │           │   │   │   └── snapscreen.html
│   │           │   │   ├── spechars/
│   │           │   │   │   ├── spechars.html
│   │           │   │   │   └── spechars.js
│   │           │   │   ├── table/
│   │           │   │   │   ├── edittable.css
│   │           │   │   │   ├── edittable.html
│   │           │   │   │   ├── edittable.js
│   │           │   │   │   ├── edittd.html
│   │           │   │   │   └── edittip.html
│   │           │   │   ├── template/
│   │           │   │   │   ├── config.js
│   │           │   │   │   ├── template.css
│   │           │   │   │   ├── template.html
│   │           │   │   │   └── template.js
│   │           │   │   ├── video/
│   │           │   │   │   ├── video.css
│   │           │   │   │   ├── video.html
│   │           │   │   │   └── video.js
│   │           │   │   ├── webapp/
│   │           │   │   │   └── webapp.html
│   │           │   │   └── wordimage/
│   │           │   │       ├── fClipboard_ueditor.swf
│   │           │   │       ├── imageUploader.swf
│   │           │   │       ├── tangram.js
│   │           │   │       ├── wordimage.html
│   │           │   │       └── wordimage.js
│   │           │   ├── index.html
│   │           │   ├── lang/
│   │           │   │   ├── en/
│   │           │   │   │   └── en.js
│   │           │   │   └── zh-cn/
│   │           │   │       └── zh-cn.js
│   │           │   ├── themes/
│   │           │   │   ├── default/
│   │           │   │   │   ├── css/
│   │           │   │   │   │   └── ueditor.css
│   │           │   │   │   └── dialogbase.css
│   │           │   │   └── iframe.css
│   │           │   ├── third-party/
│   │           │   │   ├── SyntaxHighlighter/
│   │           │   │   │   ├── shCore.js
│   │           │   │   │   └── shCoreDefault.css
│   │           │   │   ├── codemirror/
│   │           │   │   │   ├── codemirror.css
│   │           │   │   │   └── codemirror.js
│   │           │   │   ├── highcharts/
│   │           │   │   │   ├── adapters/
│   │           │   │   │   │   ├── mootools-adapter.js
│   │           │   │   │   │   ├── mootools-adapter.src.js
│   │           │   │   │   │   ├── prototype-adapter.js
│   │           │   │   │   │   ├── prototype-adapter.src.js
│   │           │   │   │   │   ├── standalone-framework.js
│   │           │   │   │   │   └── standalone-framework.src.js
│   │           │   │   │   ├── highcharts-more.js
│   │           │   │   │   ├── highcharts-more.src.js
│   │           │   │   │   ├── highcharts.js
│   │           │   │   │   ├── highcharts.src.js
│   │           │   │   │   ├── modules/
│   │           │   │   │   │   ├── annotations.js
│   │           │   │   │   │   ├── annotations.src.js
│   │           │   │   │   │   ├── canvas-tools.js
│   │           │   │   │   │   ├── canvas-tools.src.js
│   │           │   │   │   │   ├── data.js
│   │           │   │   │   │   ├── data.src.js
│   │           │   │   │   │   ├── drilldown.js
│   │           │   │   │   │   ├── drilldown.src.js
│   │           │   │   │   │   ├── exporting.js
│   │           │   │   │   │   ├── exporting.src.js
│   │           │   │   │   │   ├── funnel.js
│   │           │   │   │   │   ├── funnel.src.js
│   │           │   │   │   │   ├── heatmap.js
│   │           │   │   │   │   ├── heatmap.src.js
│   │           │   │   │   │   ├── map.js
│   │           │   │   │   │   ├── map.src.js
│   │           │   │   │   │   ├── no-data-to-display.js
│   │           │   │   │   │   └── no-data-to-display.src.js
│   │           │   │   │   └── themes/
│   │           │   │   │       ├── dark-blue.js
│   │           │   │   │       ├── dark-green.js
│   │           │   │   │       ├── gray.js
│   │           │   │   │       ├── grid.js
│   │           │   │   │       └── skies.js
│   │           │   │   ├── jquery-1.10.2.js
│   │           │   │   ├── video-js/
│   │           │   │   │   ├── video-js.css
│   │           │   │   │   ├── video-js.swf
│   │           │   │   │   ├── video.dev.js
│   │           │   │   │   └── video.js
│   │           │   │   ├── webuploader/
│   │           │   │   │   ├── Uploader.swf
│   │           │   │   │   ├── webuploader.css
│   │           │   │   │   ├── webuploader.custom.js
│   │           │   │   │   ├── webuploader.flashonly.js
│   │           │   │   │   ├── webuploader.html5only.js
│   │           │   │   │   ├── webuploader.min.bak.js
│   │           │   │   │   └── webuploader.withoutimage.js
│   │           │   │   └── zeroclipboard/
│   │           │   │       ├── ZeroClipboard.js
│   │           │   │       └── ZeroClipboard.swf
│   │           │   ├── ueditor.all.min.bak.js
│   │           │   ├── ueditor.config.js
│   │           │   └── ueditor.parse.js
│   │           └── vditor/
│   │               └── dist/
│   │                   ├── content-theme/
│   │                   │   ├── ant-design.css
│   │                   │   ├── dark.css
│   │                   │   ├── light.css
│   │                   │   └── wechat.css
│   │                   ├── css/
│   │                   │   └── content-theme/
│   │                   │       ├── ant-design.css
│   │                   │       ├── dark.css
│   │                   │       ├── light.css
│   │                   │       └── wechat.css
│   │                   ├── index.css
│   │                   ├── index.d.ts
│   │                   ├── index.js
│   │                   ├── js/
│   │                   │   ├── graphviz/
│   │                   │   │   ├── full.render.js
│   │                   │   │   └── viz.js
│   │                   │   ├── highlight.js/
│   │                   │   │   ├── LICENSE
│   │                   │   │   └── third-languages.js
│   │                   │   ├── i18n/
│   │                   │   │   ├── en_US.js
│   │                   │   │   ├── fr_FR.js
│   │                   │   │   ├── ja_JP.js
│   │                   │   │   ├── ko_KR.js
│   │                   │   │   ├── pt_BR.js
│   │                   │   │   ├── ru_RU.js
│   │                   │   │   ├── sv_SE.js
│   │                   │   │   ├── zh_CN.js
│   │                   │   │   └── zh_TW.js
│   │                   │   ├── icons/
│   │                   │   │   ├── ant.js
│   │                   │   │   └── material.js
│   │                   │   ├── markmap/
│   │                   │   │   └── prism.css
│   │                   │   └── mathjax/
│   │                   │       ├── LICENSE
│   │                   │       ├── a11y/
│   │                   │       │   ├── assistive-mml.js
│   │                   │       │   ├── complexity.js
│   │                   │       │   ├── explorer.js
│   │                   │       │   └── semantic-enrich.js
│   │                   │       ├── input/
│   │                   │       │   ├── asciimath.js
│   │                   │       │   ├── mml/
│   │                   │       │   │   └── entities.js
│   │                   │       │   ├── mml.js
│   │                   │       │   ├── tex/
│   │                   │       │   │   └── extensions/
│   │                   │       │   │       ├── action.js
│   │                   │       │   │       ├── all-packages.js
│   │                   │       │   │       ├── ams.js
│   │                   │       │   │       ├── amscd.js
│   │                   │       │   │       ├── autoload.js
│   │                   │       │   │       ├── bbox.js
│   │                   │       │   │       ├── boldsymbol.js
│   │                   │       │   │       ├── braket.js
│   │                   │       │   │       ├── bussproofs.js
│   │                   │       │   │       ├── cancel.js
│   │                   │       │   │       ├── color.js
│   │                   │       │   │       ├── colorV2.js
│   │                   │       │   │       ├── configMacros.js
│   │                   │       │   │       ├── enclose.js
│   │                   │       │   │       ├── extpfeil.js
│   │                   │       │   │       ├── html.js
│   │                   │       │   │       ├── mhchem.js
│   │                   │       │   │       ├── newcommand.js
│   │                   │       │   │       ├── noerrors.js
│   │                   │       │   │       ├── noundefined.js
│   │                   │       │   │       ├── physics.js
│   │                   │       │   │       ├── require.js
│   │                   │       │   │       ├── tagFormat.js
│   │                   │       │   │       ├── textmacros.js
│   │                   │       │   │       ├── unicode.js
│   │                   │       │   │       └── verb.js
│   │                   │       │   ├── tex-base.js
│   │                   │       │   ├── tex-full.js
│   │                   │       │   └── tex.js
│   │                   │       ├── output/
│   │                   │       │   ├── chtml/
│   │                   │       │   │   └── fonts/
│   │                   │       │   │       └── tex.js
│   │                   │       │   ├── chtml.js
│   │                   │       │   ├── svg/
│   │                   │       │   │   └── fonts/
│   │                   │       │   │       └── tex.js
│   │                   │       │   └── svg.js
│   │                   │       ├── sre/
│   │                   │       │   ├── mathmaps/
│   │                   │       │   │   ├── de.js
│   │                   │       │   │   ├── en.js
│   │                   │       │   │   ├── es.js
│   │                   │       │   │   ├── fr.js
│   │                   │       │   │   ├── mathmaps_ie.js
│   │                   │       │   │   └── nemeth.js
│   │                   │       │   ├── sre-node.js
│   │                   │       │   └── sre_browser.js
│   │                   │       ├── tex-mml-chtml.js
│   │                   │       └── tex-svg-full.js
│   │                   ├── method.d.ts
│   │                   ├── method.js
│   │                   ├── ts/
│   │                   │   ├── constants.d.ts
│   │                   │   ├── devtools/
│   │                   │   │   └── index.d.ts
│   │                   │   ├── export/
│   │                   │   │   └── index.d.ts
│   │                   │   ├── hint/
│   │                   │   │   └── index.d.ts
│   │                   │   ├── ir/
│   │                   │   │   ├── expandMarker.d.ts
│   │                   │   │   ├── highlightToolbarIR.d.ts
│   │                   │   │   ├── index.d.ts
│   │                   │   │   ├── input.d.ts
│   │                   │   │   ├── process.d.ts
│   │                   │   │   └── processKeydown.d.ts
│   │                   │   ├── markdown/
│   │                   │   │   ├── SMILESRender.d.ts
│   │                   │   │   ├── abcRender.d.ts
│   │                   │   │   ├── adapterRender.d.ts
│   │                   │   │   ├── anchorRender.d.ts
│   │                   │   │   ├── chartRender.d.ts
│   │                   │   │   ├── codeRender.d.ts
│   │                   │   │   ├── flowchartRender.d.ts
│   │                   │   │   ├── getHTML.d.ts
│   │                   │   │   ├── getMarkdown.d.ts
│   │                   │   │   ├── graphvizRender.d.ts
│   │                   │   │   ├── highlightRender.d.ts
│   │                   │   │   ├── lazyLoadImageRender.d.ts
│   │                   │   │   ├── markmapRender.d.ts
│   │                   │   │   ├── mathRender.d.ts
│   │                   │   │   ├── mediaRender.d.ts
│   │                   │   │   ├── mermaidRender.d.ts
│   │                   │   │   ├── mindmapRender.d.ts
│   │                   │   │   ├── outlineRender.d.ts
│   │                   │   │   ├── plantumlRender.d.ts
│   │                   │   │   ├── previewRender.d.ts
│   │                   │   │   ├── setLute.d.ts
│   │                   │   │   └── speechRender.d.ts
│   │                   │   ├── outline/
│   │                   │   │   └── index.d.ts
│   │                   │   ├── preview/
│   │                   │   │   ├── image.d.ts
│   │                   │   │   └── index.d.ts
│   │                   │   ├── resize/
│   │                   │   │   └── index.d.ts
│   │                   │   ├── sv/
│   │                   │   │   ├── combineFootnote.d.ts
│   │                   │   │   ├── index.d.ts
│   │                   │   │   ├── inputEvent.d.ts
│   │                   │   │   ├── process.d.ts
│   │                   │   │   └── processKeydown.d.ts
│   │                   │   ├── tip/
│   │                   │   │   └── index.d.ts
│   │                   │   ├── toolbar/
│   │                   │   │   ├── Both.d.ts
│   │                   │   │   ├── Br.d.ts
│   │                   │   │   ├── CodeTheme.d.ts
│   │                   │   │   ├── ContentTheme.d.ts
│   │                   │   │   ├── Copy.d.ts
│   │                   │   │   ├── Counter.d.ts
│   │                   │   │   ├── Custom.d.ts
│   │                   │   │   ├── Devtools.d.ts
│   │                   │   │   ├── Divider.d.ts
│   │                   │   │   ├── EditMode.d.ts
│   │                   │   │   ├── Emoji.d.ts
│   │                   │   │   ├── Export.d.ts
│   │                   │   │   ├── Fullscreen.d.ts
│   │                   │   │   ├── Headings.d.ts
│   │                   │   │   ├── Help.d.ts
│   │                   │   │   ├── Indent.d.ts
│   │                   │   │   ├── Info.d.ts
│   │                   │   │   ├── InsertAfter.d.ts
│   │                   │   │   ├── InsertBefore.d.ts
│   │                   │   │   ├── InsertCode.d.ts
│   │                   │   │   ├── MenuItem.d.ts
│   │                   │   │   ├── Outdent.d.ts
│   │                   │   │   ├── Outline.d.ts
│   │                   │   │   ├── Preview.d.ts
│   │                   │   │   ├── Record.d.ts
│   │                   │   │   ├── Redo.d.ts
│   │                   │   │   ├── Undo.d.ts
│   │                   │   │   ├── Upload.d.ts
│   │                   │   │   ├── index.d.ts
│   │                   │   │   └── setToolbar.d.ts
│   │                   │   ├── ui/
│   │                   │   │   ├── initUI.d.ts
│   │                   │   │   ├── setCodeTheme.d.ts
│   │                   │   │   ├── setContentTheme.d.ts
│   │                   │   │   ├── setPreviewMode.d.ts
│   │                   │   │   └── setTheme.d.ts
│   │                   │   ├── undo/
│   │                   │   │   └── index.d.ts
│   │                   │   ├── util/
│   │                   │   │   ├── Options.d.ts
│   │                   │   │   ├── RecordMedia.d.ts
│   │                   │   │   ├── addScript.d.ts
│   │                   │   │   ├── addStyle.d.ts
│   │                   │   │   ├── code160to32.d.ts
│   │                   │   │   ├── compatibility.d.ts
│   │                   │   │   ├── editorCommonEvent.d.ts
│   │                   │   │   ├── fixBrowserBehavior.d.ts
│   │                   │   │   ├── function.d.ts
│   │                   │   │   ├── getSelectText.d.ts
│   │                   │   │   ├── hasClosest.d.ts
│   │                   │   │   ├── hasClosestByHeadings.d.ts
│   │                   │   │   ├── highlightToolbar.d.ts
│   │                   │   │   ├── hotKey.d.ts
│   │                   │   │   ├── log.d.ts
│   │                   │   │   ├── merge.d.ts
│   │                   │   │   ├── processCode.d.ts
│   │                   │   │   ├── selection.d.ts
│   │                   │   │   └── toc.d.ts
│   │                   │   └── wysiwyg/
│   │                   │       ├── afterRenderEvent.d.ts
│   │                   │       ├── highlightToolbarWYSIWYG.d.ts
│   │                   │       ├── index.d.ts
│   │                   │       ├── inlineTag.d.ts
│   │                   │       ├── input.d.ts
│   │                   │       ├── processKeydown.d.ts
│   │                   │       ├── renderDomByMd.d.ts
│   │                   │       ├── setHeading.d.ts
│   │                   │       ├── showCode.d.ts
│   │                   │       └── toolbarEvent.d.ts
│   │                   └── types/
│   │                       └── index.d.ts
│   └── tasks/
│       ├── channel_update_key.go
│       ├── main.go
│       └── order_tasks.go
├── docker/
│   └── docker-compose.yml
└── web/
    ├── README.md
    ├── console/
    │   ├── .editorconfig
    │   ├── .eslintignore
    │   ├── .eslintrc.cjs
    │   ├── .gitattributes
    │   ├── .gitignore
    │   ├── .husky/
    │   │   ├── commit-msg
    │   │   └── pre-commit
    │   ├── .npmrc
    │   ├── .prettierignore
    │   ├── .prettierrc.js
    │   ├── LINT_SETUP.md
    │   ├── README.md
    │   ├── auto-imports.d.ts
    │   ├── commitlint.config.js
    │   ├── components.d.ts
    │   ├── index.html
    │   ├── lint-staged.config.js
    │   ├── package.json
    │   ├── postcss.config.js
    │   ├── public/
    │   │   ├── UEditor/
    │   │   │   ├── dialogs/
    │   │   │   │   ├── anchor/
    │   │   │   │   │   └── anchor.html
    │   │   │   │   ├── attachment/
    │   │   │   │   │   ├── attachment.css
    │   │   │   │   │   ├── attachment.html
    │   │   │   │   │   └── attachment.js
    │   │   │   │   ├── background/
    │   │   │   │   │   ├── background.css
    │   │   │   │   │   ├── background.html
    │   │   │   │   │   └── background.js
    │   │   │   │   ├── charts/
    │   │   │   │   │   ├── chart.config.js
    │   │   │   │   │   ├── charts.css
    │   │   │   │   │   ├── charts.html
    │   │   │   │   │   └── charts.js
    │   │   │   │   ├── emotion/
    │   │   │   │   │   ├── emotion.css
    │   │   │   │   │   ├── emotion.html
    │   │   │   │   │   └── emotion.js
    │   │   │   │   ├── gmap/
    │   │   │   │   │   └── gmap.html
    │   │   │   │   ├── help/
    │   │   │   │   │   ├── help.css
    │   │   │   │   │   ├── help.html
    │   │   │   │   │   └── help.js
    │   │   │   │   ├── image/
    │   │   │   │   │   ├── image.css
    │   │   │   │   │   ├── image.html
    │   │   │   │   │   └── image.js
    │   │   │   │   ├── insertframe/
    │   │   │   │   │   └── insertframe.html
    │   │   │   │   ├── internal.js
    │   │   │   │   ├── link/
    │   │   │   │   │   └── link.html
    │   │   │   │   ├── map/
    │   │   │   │   │   ├── map.html
    │   │   │   │   │   └── show.html
    │   │   │   │   ├── music/
    │   │   │   │   │   ├── music.css
    │   │   │   │   │   ├── music.html
    │   │   │   │   │   └── music.js
    │   │   │   │   ├── preview/
    │   │   │   │   │   └── preview.html
    │   │   │   │   ├── scrawl/
    │   │   │   │   │   ├── scrawl.css
    │   │   │   │   │   ├── scrawl.html
    │   │   │   │   │   └── scrawl.js
    │   │   │   │   ├── searchreplace/
    │   │   │   │   │   ├── searchreplace.html
    │   │   │   │   │   └── searchreplace.js
    │   │   │   │   ├── snapscreen/
    │   │   │   │   │   └── snapscreen.html
    │   │   │   │   ├── spechars/
    │   │   │   │   │   ├── spechars.html
    │   │   │   │   │   └── spechars.js
    │   │   │   │   ├── table/
    │   │   │   │   │   ├── edittable.css
    │   │   │   │   │   ├── edittable.html
    │   │   │   │   │   ├── edittable.js
    │   │   │   │   │   ├── edittd.html
    │   │   │   │   │   └── edittip.html
    │   │   │   │   ├── template/
    │   │   │   │   │   ├── config.js
    │   │   │   │   │   ├── template.css
    │   │   │   │   │   ├── template.html
    │   │   │   │   │   └── template.js
    │   │   │   │   ├── video/
    │   │   │   │   │   ├── video.css
    │   │   │   │   │   ├── video.html
    │   │   │   │   │   └── video.js
    │   │   │   │   ├── webapp/
    │   │   │   │   │   └── webapp.html
    │   │   │   │   └── wordimage/
    │   │   │   │       ├── tangram.js
    │   │   │   │       ├── wordimage.html
    │   │   │   │       └── wordimage.js
    │   │   │   ├── index.html
    │   │   │   ├── lang/
    │   │   │   │   ├── en/
    │   │   │   │   │   └── en.js
    │   │   │   │   └── zh-cn/
    │   │   │   │       └── zh-cn.js
    │   │   │   ├── themes/
    │   │   │   │   ├── default/
    │   │   │   │   │   ├── css/
    │   │   │   │   │   │   └── ueditor.css
    │   │   │   │   │   └── dialogbase.css
    │   │   │   │   └── iframe.css
    │   │   │   ├── third-party/
    │   │   │   │   ├── SyntaxHighlighter/
    │   │   │   │   │   ├── shCore.js
    │   │   │   │   │   └── shCoreDefault.css
    │   │   │   │   ├── codemirror/
    │   │   │   │   │   ├── codemirror.css
    │   │   │   │   │   └── codemirror.js
    │   │   │   │   ├── highcharts/
    │   │   │   │   │   ├── adapters/
    │   │   │   │   │   │   ├── mootools-adapter.js
    │   │   │   │   │   │   ├── mootools-adapter.src.js
    │   │   │   │   │   │   ├── prototype-adapter.js
    │   │   │   │   │   │   ├── prototype-adapter.src.js
    │   │   │   │   │   │   ├── standalone-framework.js
    │   │   │   │   │   │   └── standalone-framework.src.js
    │   │   │   │   │   ├── highcharts-more.js
    │   │   │   │   │   ├── highcharts-more.src.js
    │   │   │   │   │   ├── highcharts.js
    │   │   │   │   │   ├── highcharts.src.js
    │   │   │   │   │   ├── modules/
    │   │   │   │   │   │   ├── annotations.js
    │   │   │   │   │   │   ├── annotations.src.js
    │   │   │   │   │   │   ├── canvas-tools.js
    │   │   │   │   │   │   ├── canvas-tools.src.js
    │   │   │   │   │   │   ├── data.js
    │   │   │   │   │   │   ├── data.src.js
    │   │   │   │   │   │   ├── drilldown.js
    │   │   │   │   │   │   ├── drilldown.src.js
    │   │   │   │   │   │   ├── exporting.js
    │   │   │   │   │   │   ├── exporting.src.js
    │   │   │   │   │   │   ├── funnel.js
    │   │   │   │   │   │   ├── funnel.src.js
    │   │   │   │   │   │   ├── heatmap.js
    │   │   │   │   │   │   ├── heatmap.src.js
    │   │   │   │   │   │   ├── map.js
    │   │   │   │   │   │   ├── map.src.js
    │   │   │   │   │   │   ├── no-data-to-display.js
    │   │   │   │   │   │   └── no-data-to-display.src.js
    │   │   │   │   │   └── themes/
    │   │   │   │   │       ├── dark-blue.js
    │   │   │   │   │       ├── dark-green.js
    │   │   │   │   │       ├── gray.js
    │   │   │   │   │       ├── grid.js
    │   │   │   │   │       └── skies.js
    │   │   │   │   ├── jquery-1.10.2.js
    │   │   │   │   ├── video-js/
    │   │   │   │   │   ├── video-js.css
    │   │   │   │   │   ├── video.dev.js
    │   │   │   │   │   └── video.js
    │   │   │   │   ├── webuploader/
    │   │   │   │   │   ├── webuploader.css
    │   │   │   │   │   ├── webuploader.custom.js
    │   │   │   │   │   ├── webuploader.flashonly.js
    │   │   │   │   │   ├── webuploader.html5only.js
    │   │   │   │   │   ├── webuploader.min.bak.js
    │   │   │   │   │   └── webuploader.withoutimage.js
    │   │   │   │   └── zeroclipboard/
    │   │   │   │       └── ZeroClipboard.js
    │   │   │   ├── ueditor.all.min.bak.js
    │   │   │   ├── ueditor.config.js
    │   │   │   └── ueditor.parse.js
    │   │   ├── km-login/
    │   │   │   └── index.html
    │   │   ├── manifest.json
    │   │   ├── oauth_login.html
    │   │   └── saas-login/
    │   │       └── index.html
    │   ├── src/
    │   │   ├── App.vue
    │   │   ├── api/
    │   │   │   ├── code.ts
    │   │   │   ├── config.ts
    │   │   │   ├── errorHandler.ts
    │   │   │   ├── index.ts
    │   │   │   ├── modules/
    │   │   │   │   ├── agent.ts
    │   │   │   │   ├── agents/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── transform.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── ai-link.ts
    │   │   │   │   ├── auth.ts
    │   │   │   │   ├── banner/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── transform.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── channel/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── transform.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── channel.ts
    │   │   │   │   ├── chunk-setting.ts
    │   │   │   │   ├── common.ts
    │   │   │   │   ├── conversation.ts
    │   │   │   │   ├── department.ts
    │   │   │   │   ├── dingtalk.ts
    │   │   │   │   ├── domain/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── transform.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── enterprise.ts
    │   │   │   │   ├── group.ts
    │   │   │   │   ├── libraries/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── transform.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── message.ts
    │   │   │   │   ├── navigation/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── transform.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── order.ts
    │   │   │   │   ├── payment/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── transform.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── permissions.ts
    │   │   │   │   ├── platform-settings/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── transform.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── prompt.ts
    │   │   │   │   ├── provider.ts
    │   │   │   │   ├── providers/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── transform.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── saas.ts
    │   │   │   │   ├── setting.ts
    │   │   │   │   ├── spaces/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── transform.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── subscription.ts
    │   │   │   │   ├── system-log/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── transform.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── template-style.ts
    │   │   │   │   ├── upload.ts
    │   │   │   │   ├── user.ts
    │   │   │   │   └── wecom.ts
    │   │   │   ├── readme.md
    │   │   │   ├── signature.ts
    │   │   │   └── types.ts
    │   │   ├── apis/
    │   │   │   ├── index.ts
    │   │   │   ├── modules/
    │   │   │   │   ├── conversation.ts
    │   │   │   │   ├── enterprise.ts
    │   │   │   │   ├── group.ts
    │   │   │   │   ├── qyy.ts
    │   │   │   │   ├── setting.ts
    │   │   │   │   └── user.ts
    │   │   │   └── readme.md
    │   │   ├── components/
    │   │   │   ├── AgentPicker/
    │   │   │   │   └── index.vue
    │   │   │   ├── CropperDialog/
    │   │   │   │   └── index.vue
    │   │   │   ├── DeptMemberPicker/
    │   │   │   │   └── index.vue
    │   │   │   ├── DialogueRecord/
    │   │   │   │   ├── drawer.vue
    │   │   │   │   └── index.vue
    │   │   │   ├── EntityDisplay/
    │   │   │   │   ├── README.md
    │   │   │   │   ├── index.vue
    │   │   │   │   └── types.ts
    │   │   │   ├── Filter/
    │   │   │   │   ├── date-range.vue
    │   │   │   │   ├── select.vue
    │   │   │   │   └── user.vue
    │   │   │   ├── Fullscreen/
    │   │   │   │   └── index.vue
    │   │   │   ├── GroupDialog/
    │   │   │   │   └── index.vue
    │   │   │   ├── GroupSelect/
    │   │   │   │   └── index.vue
    │   │   │   ├── GroupTabs/
    │   │   │   │   └── index.vue
    │   │   │   ├── Header/
    │   │   │   │   └── index.vue
    │   │   │   ├── LanguageDropdown/
    │   │   │   │   └── LanguageDropdown.vue
    │   │   │   ├── Layout/
    │   │   │   │   └── index.vue
    │   │   │   ├── Markdown/
    │   │   │   │   └── editor.vue
    │   │   │   ├── Model/
    │   │   │   │   ├── dialog.vue
    │   │   │   │   ├── index.ts
    │   │   │   │   ├── select.vue
    │   │   │   │   └── view.vue
    │   │   │   ├── OpenData/
    │   │   │   │   └── index.vue
    │   │   │   ├── Pagination/
    │   │   │   │   ├── index.vue
    │   │   │   │   └── simple.vue
    │   │   │   ├── Permission/
    │   │   │   │   ├── constant.ts
    │   │   │   │   ├── data.ts
    │   │   │   │   ├── member-selector.vue
    │   │   │   │   └── selector.vue
    │   │   │   ├── Prompt/
    │   │   │   │   ├── README.md
    │   │   │   │   ├── generate.vue
    │   │   │   │   ├── input.vue
    │   │   │   │   ├── optimize.vue
    │   │   │   │   └── test/
    │   │   │   │       ├── component.vue
    │   │   │   │       └── index.ts
    │   │   │   ├── ResourcePicker/
    │   │   │   │   └── index.vue
    │   │   │   ├── Scroller/
    │   │   │   │   └── index.vue
    │   │   │   ├── Search/
    │   │   │   │   └── index.vue
    │   │   │   ├── SelectPlus/
    │   │   │   │   └── index.vue
    │   │   │   ├── ServiceDialog/
    │   │   │   │   └── index.vue
    │   │   │   ├── Sortable/
    │   │   │   │   └── index.vue
    │   │   │   ├── SvgIcon/
    │   │   │   │   └── index.vue
    │   │   │   ├── TablePlus/
    │   │   │   │   ├── create-slots.ts
    │   │   │   │   └── index.vue
    │   │   │   ├── TipConfirm/
    │   │   │   │   ├── index.vue
    │   │   │   │   └── setup.ts
    │   │   │   ├── UEditor/
    │   │   │   │   └── index.vue
    │   │   │   ├── Upload/
    │   │   │   │   ├── certificate.vue
    │   │   │   │   ├── image.vue
    │   │   │   │   └── index.vue
    │   │   │   ├── UserLoginDialog/
    │   │   │   │   ├── index.vue
    │   │   │   │   └── setup.ts
    │   │   │   └── VerificationCodeInput/
    │   │   │       └── index.vue
    │   │   ├── constants/
    │   │   │   ├── .gitkeep
    │   │   │   ├── agent.ts
    │   │   │   ├── banner.ts
    │   │   │   ├── chunk.ts
    │   │   │   ├── domain.ts
    │   │   │   ├── enterprise.ts
    │   │   │   ├── group.ts
    │   │   │   ├── navigation.ts
    │   │   │   ├── order.ts
    │   │   │   ├── payment.ts
    │   │   │   ├── platform/
    │   │   │   │   ├── agent.ts
    │   │   │   │   ├── channel.ts
    │   │   │   │   ├── config.ts
    │   │   │   │   ├── index.ts
    │   │   │   │   ├── model.ts
    │   │   │   │   └── provider.ts
    │   │   │   ├── sync.ts
    │   │   │   ├── system-log.ts
    │   │   │   └── user.ts
    │   │   ├── directive/
    │   │   │   ├── copy.ts
    │   │   │   ├── debounce.ts
    │   │   │   ├── index.ts
    │   │   │   ├── overflow-tooltip.ts
    │   │   │   ├── readme.md
    │   │   │   ├── router.ts
    │   │   │   ├── tooltip.ts
    │   │   │   ├── truncate.ts
    │   │   │   └── version.ts
    │   │   ├── global/
    │   │   │   ├── filters.ts
    │   │   │   ├── index.ts
    │   │   │   ├── methods.ts
    │   │   │   └── readme.md
    │   │   ├── hooks/
    │   │   │   ├── useBasicLayout.ts
    │   │   │   ├── useEntityInfo.ts
    │   │   │   ├── useEnv.ts
    │   │   │   ├── useMobile.ts
    │   │   │   ├── useScroll.ts
    │   │   │   ├── useSso.ts
    │   │   │   ├── useTooltip.ts
    │   │   │   └── useVmodel.ts
    │   │   ├── icons/
    │   │   │   ├── 403.vue
    │   │   │   └── 500.vue
    │   │   ├── layout/
    │   │   │   ├── Child.vue
    │   │   │   ├── Layout.vue
    │   │   │   └── Sider.vue
    │   │   ├── locales/
    │   │   │   ├── en-v2.json
    │   │   │   ├── en.json
    │   │   │   ├── index.ts
    │   │   │   ├── ja.json
    │   │   │   ├── zh-cn.json
    │   │   │   └── zh-tw.json
    │   │   ├── main.ts
    │   │   ├── plugins/
    │   │   │   ├── assets.ts
    │   │   │   └── index.ts
    │   │   ├── router/
    │   │   │   └── index.ts
    │   │   ├── stores/
    │   │   │   ├── index.ts
    │   │   │   └── modules/
    │   │   │       ├── channel.ts
    │   │   │       ├── conversation.ts
    │   │   │       ├── domain.ts
    │   │   │       ├── enterprise.ts
    │   │   │       ├── group.ts
    │   │   │       ├── setting.ts
    │   │   │       └── user.ts
    │   │   ├── styles/
    │   │   │   ├── element/
    │   │   │   │   ├── _variables.scss
    │   │   │   │   ├── override.scss
    │   │   │   │   └── vars.scss
    │   │   │   ├── global.scss
    │   │   │   └── lib/
    │   │   │       └── tailwind.css
    │   │   ├── types/
    │   │   │   ├── agent.d.ts
    │   │   │   ├── ai-link.d.ts
    │   │   │   ├── category.d.ts
    │   │   │   ├── channel.d.ts
    │   │   │   ├── domain.d.ts
    │   │   │   ├── enterprise.d.ts
    │   │   │   ├── entity.ts
    │   │   │   ├── env.d.ts
    │   │   │   ├── global.d.ts
    │   │   │   ├── payment.d.ts
    │   │   │   ├── platform.d.ts
    │   │   │   ├── settings.d.ts
    │   │   │   ├── subscription.d.ts
    │   │   │   └── vue-template.d.ts
    │   │   ├── utils/
    │   │   │   ├── cache.ts
    │   │   │   ├── config.ts
    │   │   │   ├── copy.ts
    │   │   │   ├── event-bus.ts
    │   │   │   ├── filter.ts
    │   │   │   ├── form-rule.ts
    │   │   │   ├── form-rule.v2.ts
    │   │   │   ├── form-validator.ts
    │   │   │   ├── functions/
    │   │   │   │   ├── debounce.ts
    │   │   │   │   └── index.ts
    │   │   │   ├── index.ts
    │   │   │   ├── is/
    │   │   │   │   └── index.ts
    │   │   │   ├── loadLib.ts
    │   │   │   ├── md5.ts
    │   │   │   ├── moment.ts
    │   │   │   ├── request/
    │   │   │   │   ├── axios.ts
    │   │   │   │   ├── blob.ts
    │   │   │   │   ├── code.ts
    │   │   │   │   ├── helper.ts
    │   │   │   │   ├── index.ts
    │   │   │   │   └── signature.ts
    │   │   │   ├── timer-manager.ts
    │   │   │   ├── url.ts
    │   │   │   ├── version.ts
    │   │   │   └── wecom.ts
    │   │   └── views/
    │   │       ├── agent/
    │   │       │   ├── create/
    │   │       │   │   ├── components/
    │   │       │   │   │   ├── agent-info.vue
    │   │       │   │   │   ├── agent-type.vue
    │   │       │   │   │   ├── base-config.vue
    │   │       │   │   │   ├── expand-config.vue
    │   │       │   │   │   ├── field-input-setting.vue
    │   │       │   │   │   ├── field-input.vue
    │   │       │   │   │   ├── limit-config.vue
    │   │       │   │   │   ├── relate-agents-dialog.vue
    │   │       │   │   │   ├── relate-agents-setting.vue
    │   │       │   │   │   ├── relate-agents.vue
    │   │       │   │   │   └── use-scope.vue
    │   │       │   │   ├── drawer.vue
    │   │       │   │   ├── guide.vue
    │   │       │   │   ├── index.vue
    │   │       │   │   ├── platform/
    │   │       │   │   │   ├── 53ai-agent.vue
    │   │       │   │   │   ├── app-builder-agent.vue
    │   │       │   │   │   ├── bailian.vue
    │   │       │   │   │   ├── coze-cn.vue
    │   │       │   │   │   ├── coze-osv.vue
    │   │       │   │   │   ├── dify-agent.vue
    │   │       │   │   │   ├── fastgpt-agent.vue
    │   │       │   │   │   ├── index.vue
    │   │       │   │   │   ├── maxkb-agent.vue
    │   │       │   │   │   ├── n8n.vue
    │   │       │   │   │   ├── prompt.vue
    │   │       │   │   │   ├── tencent.vue
    │   │       │   │   │   ├── volcengine.vue
    │   │       │   │   │   └── yuanqi.vue
    │   │       │   │   ├── response/
    │   │       │   │   │   ├── chat.vue
    │   │       │   │   │   └── completion.vue
    │   │       │   │   └── store.ts
    │   │       │   └── index.vue
    │   │       ├── banner/
    │   │       │   └── index.vue
    │   │       ├── chunk/
    │   │       │   └── index.vue
    │   │       ├── domain/
    │   │       │   ├── components/
    │   │       │   │   ├── exclusive-setting-dialog.vue
    │   │       │   │   └── independent-setting-dialog.vue
    │   │       │   └── index.vue
    │   │       ├── exception/
    │   │       │   ├── 404/
    │   │       │   │   └── index.vue
    │   │       │   ├── 500/
    │   │       │   │   └── index.vue
    │   │       │   └── mobile-tip/
    │   │       │       └── index.vue
    │   │       ├── index.vue
    │   │       ├── info/
    │   │       │   └── index.vue
    │   │       ├── login/
    │   │       │   ├── components/
    │   │       │   │   ├── apply-form.vue
    │   │       │   │   ├── create-enterprise-form.vue
    │   │       │   │   ├── enterprise-list.vue
    │   │       │   │   ├── forget-form.vue
    │   │       │   │   ├── login-form.vue
    │   │       │   │   ├── register-form.vue
    │   │       │   │   └── wechat.vue
    │   │       │   └── index.vue
    │   │       ├── model/
    │   │       │   └── index.vue
    │   │       ├── navigation/
    │   │       │   ├── components/
    │   │       │   │   ├── nav-create-dialog.vue
    │   │       │   │   ├── nav-create-drawer.vue
    │   │       │   │   ├── pc-navigation-pane.vue
    │   │       │   │   └── seo-setting-dialog.vue
    │   │       │   ├── index.vue
    │   │       │   └── web-setting.vue
    │   │       ├── order/
    │   │       │   ├── components/
    │   │       │   │   └── order-add-dialog.vue
    │   │       │   └── index.vue
    │   │       ├── parse/
    │   │       │   └── index.vue
    │   │       ├── payment/
    │   │       │   ├── components/
    │   │       │   │   ├── alipay-setting-dialog.vue
    │   │       │   │   ├── manual-setting-dialog.vue
    │   │       │   │   ├── payment-card.vue
    │   │       │   │   └── wechat-setting-dialog.vue
    │   │       │   └── index.vue
    │   │       ├── platform/
    │   │       │   ├── components/
    │   │       │   │   ├── agent-list-drawer.vue
    │   │       │   │   ├── auth-list-drawer.vue
    │   │       │   │   ├── model-group.vue
    │   │       │   │   ├── model-save-dialog.vue
    │   │       │   │   ├── model-select-dialog.vue
    │   │       │   │   ├── model-setting-dialog.vue
    │   │       │   │   ├── provider-authorize-dialog.vue
    │   │       │   │   └── provider-card.vue
    │   │       │   ├── componentsv2/
    │   │       │   │   ├── model-group.vue
    │   │       │   │   ├── model-save-dialog.vue
    │   │       │   │   └── model-select-dialog.vue
    │   │       │   ├── index.vue
    │   │       │   ├── km.vue
    │   │       │   └── view/
    │   │       │       ├── file-editor.vue
    │   │       │       ├── file-parser.vue
    │   │       │       ├── model.vue
    │   │       │       └── web-search.vue
    │   │       ├── prompt/
    │   │       │   ├── components/
    │   │       │   │   ├── create-drawer.vue
    │   │       │   │   ├── form.vue
    │   │       │   │   └── links-dialog.vue
    │   │       │   ├── create/
    │   │       │   │   ├── guide.vue
    │   │       │   │   ├── index.vue
    │   │       │   │   └── store.ts
    │   │       │   └── index.vue
    │   │       ├── search/
    │   │       │   └── index.vue
    │   │       ├── smtp/
    │   │       │   ├── components/
    │   │       │   │   └── email-form.vue
    │   │       │   └── index.vue
    │   │       ├── space/
    │   │       │   ├── components/
    │   │       │   │   ├── info-save-dialog.vue
    │   │       │   │   └── knowledge-list-drawer.vue
    │   │       │   └── index.vue
    │   │       ├── sso/
    │   │       │   ├── components/
    │   │       │   │   ├── access-dialog.vue
    │   │       │   │   └── api-access-dialog.vue
    │   │       │   └── index.vue
    │   │       ├── statistics/
    │   │       │   └── index.vue
    │   │       ├── subscription/
    │   │       │   ├── index.vue
    │   │       │   └── utils.ts
    │   │       ├── svg/
    │   │       │   └── index.vue
    │   │       ├── system-log/
    │   │       │   └── index.vue
    │   │       ├── template-style/
    │   │       │   └── index.vue
    │   │       ├── toolbox/
    │   │       │   ├── components/
    │   │       │   │   ├── add-account.vue
    │   │       │   │   ├── create-dialog.vue
    │   │       │   │   ├── create-drawer.vue
    │   │       │   │   ├── store-dialog.vue
    │   │       │   │   ├── store-view.vue
    │   │       │   │   └── use-group.vue
    │   │       │   └── index.vue
    │   │       ├── user/
    │   │       │   ├── admin/
    │   │       │   │   └── index.vue
    │   │       │   ├── components/
    │   │       │   │   ├── department-add-dialog.vue
    │   │       │   │   ├── department-tree-select.vue
    │   │       │   │   ├── department-tree.vue
    │   │       │   │   ├── group-add-dialog.vue
    │   │       │   │   ├── user-add-dialog.vue
    │   │       │   │   ├── user-internal-add-dialog.vue
    │   │       │   │   ├── user-internal-edit-drawer.vue
    │   │       │   │   ├── user-internal-status.vue
    │   │       │   │   └── user-select-dialog.vue
    │   │       │   ├── dialogue-record/
    │   │       │   │   └── index.vue
    │   │       │   ├── internal/
    │   │       │   │   ├── account.vue
    │   │       │   │   ├── group.vue
    │   │       │   │   ├── index.vue
    │   │       │   │   ├── member.vue
    │   │       │   │   └── organization.vue
    │   │       │   └── register/
    │   │       │       └── index.vue
    │   │       └── viewer/
    │   │           └── index.vue
    │   ├── stylelint.config.js
    │   ├── tailwind.config.js
    │   ├── tsconfig.json
    │   ├── vite-plugins/
    │   │   └── conditional-compilation.ts
    │   └── vite.config.ts
    └── front/
        ├── .editorconfig
        ├── .eslintignore
        ├── .eslintrc.cjs
        ├── .gitattributes
        ├── .gitignore
        ├── .husky/
        │   ├── commit-msg
        │   └── pre-commit
        ├── .npmrc
        ├── .prettierignore
        ├── .prettierrc.js
        ├── LINT_SETUP.md
        ├── README.md
        ├── build/
        │   ├── entitlements.mac.plist
        │   └── icon.icns
        ├── commitlint.config.js
        ├── dev-app-update.yml
        ├── electron-builder.yml
        ├── electron.vite.config.ts
        ├── lint-staged.config.js
        ├── native/
        │   ├── binding.gyp
        │   ├── mouse_select_status_mac.mm
        │   └── mouse_select_status_win.cpp
        ├── package.json
        ├── postcss.config.js
        ├── src/
        │   ├── main/
        │   │   ├── enums/
        │   │   │   └── SystemTypeEnum.ts
        │   │   ├── helper/
        │   │   │   └── web.ts
        │   │   ├── host.ts
        │   │   ├── index.ts
        │   │   ├── service/
        │   │   │   ├── AutoUpdater.ts
        │   │   │   ├── Bookmarks.ts
        │   │   │   ├── Container.ts
        │   │   │   ├── FileSystem.ts
        │   │   │   ├── GlobalShortcutEvent.ts
        │   │   │   ├── Main.ts
        │   │   │   ├── MouseEventsHandler.ts
        │   │   │   └── Pages.ts
        │   │   ├── utils/
        │   │   │   ├── index.ts
        │   │   │   └── validate.ts
        │   │   └── window/
        │   │       ├── FastChat.ts
        │   │       ├── HoverMenu.ts
        │   │       └── Main.ts
        │   ├── preload/
        │   │   ├── fastChat.ts
        │   │   ├── hoverMenu.ts
        │   │   └── index.ts
        │   └── renderer/
        │       ├── index.html
        │       ├── main/
        │       │   ├── App.vue
        │       │   ├── api/
        │       │   │   ├── code.ts
        │       │   │   ├── config.ts
        │       │   │   ├── errorHandler.ts
        │       │   │   ├── host.ts
        │       │   │   ├── index.ts
        │       │   │   ├── modules/
        │       │   │   │   ├── agent.ts
        │       │   │   │   ├── chat.ts
        │       │   │   │   ├── common.ts
        │       │   │   │   ├── conversation.ts
        │       │   │   │   ├── enterprise.ts
        │       │   │   │   ├── group.ts
        │       │   │   │   ├── links.ts
        │       │   │   │   ├── navigation.ts
        │       │   │   │   ├── order.ts
        │       │   │   │   ├── payment.ts
        │       │   │   │   ├── prompt.ts
        │       │   │   │   ├── setting.ts
        │       │   │   │   ├── share/
        │       │   │   │   │   ├── index.ts
        │       │   │   │   │   ├── transform.ts
        │       │   │   │   │   └── types.ts
        │       │   │   │   ├── subscription.ts
        │       │   │   │   ├── system.ts
        │       │   │   │   ├── upload.ts
        │       │   │   │   └── user.ts
        │       │   │   ├── signature.ts
        │       │   │   └── types.ts
        │       │   ├── assets/
        │       │   │   └── styles/
        │       │   │       ├── animate.css
        │       │   │       ├── custom.css
        │       │   │       ├── element-plus.css
        │       │   │       ├── global.css
        │       │   │       └── tailwind.css
        │       │   ├── components/
        │       │   │   ├── AuthTagGroup/
        │       │   │   │   └── index.vue
        │       │   │   ├── CropperDialog/
        │       │   │   │   └── index.vue
        │       │   │   ├── ExpireModal/
        │       │   │   │   └── index.vue
        │       │   │   ├── FileUpload/
        │       │   │   │   └── index.vue
        │       │   │   ├── Filter/
        │       │   │   │   └── date-range.vue
        │       │   │   ├── Fullscreen/
        │       │   │   │   └── index.vue
        │       │   │   ├── LazyComponent/
        │       │   │   │   └── index.vue
        │       │   │   ├── Lead/
        │       │   │   │   └── index.vue
        │       │   │   ├── LoginModal/
        │       │   │   │   ├── email.vue
        │       │   │   │   ├── forgetPassword.vue
        │       │   │   │   ├── index.vue
        │       │   │   │   ├── register.vue
        │       │   │   │   ├── resetPassword.vue
        │       │   │   │   ├── wechat.vue
        │       │   │   │   └── wecom.vue
        │       │   │   ├── MarkMap/
        │       │   │   │   ├── index.ts
        │       │   │   │   ├── index.vue
        │       │   │   │   └── vis.vue
        │       │   │   ├── Markdown/
        │       │   │   │   ├── editor.vue
        │       │   │   │   ├── helper.ts
        │       │   │   │   └── preview.vue
        │       │   │   ├── Pagination/
        │       │   │   │   └── index.vue
        │       │   │   ├── Prompt/
        │       │   │   │   └── input.vue
        │       │   │   ├── RelatedScene/
        │       │   │   │   └── index.vue
        │       │   │   ├── Search/
        │       │   │   │   └── index.vue
        │       │   │   ├── Slider/
        │       │   │   │   └── index.vue
        │       │   │   ├── Sortable/
        │       │   │   │   └── index.vue
        │       │   │   ├── SvgIcon.vue
        │       │   │   ├── TablePlus/
        │       │   │   │   ├── create-slots.ts
        │       │   │   │   └── index.vue
        │       │   │   ├── Upgrade/
        │       │   │   │   ├── index.vue
        │       │   │   │   └── payment-qrcode.vue
        │       │   │   ├── Upload/
        │       │   │   │   ├── image.vue
        │       │   │   │   └── index.vue
        │       │   │   ├── VersionModal/
        │       │   │   │   └── index.vue
        │       │   │   └── modals/
        │       │   │       └── .editorconfig
        │       │   ├── constants/
        │       │   │   ├── currency.ts
        │       │   │   ├── events.ts
        │       │   │   ├── navigation.ts
        │       │   │   ├── payment.ts
        │       │   │   ├── storage.ts
        │       │   │   └── website.ts
        │       │   ├── directive/
        │       │   │   ├── README.md
        │       │   │   ├── copy.ts
        │       │   │   ├── debounce.ts
        │       │   │   ├── index.ts
        │       │   │   ├── permission.ts
        │       │   │   ├── tooltip.ts
        │       │   │   └── trim.ts
        │       │   ├── global/
        │       │   │   └── index.ts
        │       │   ├── hooks/
        │       │   │   ├── README.md
        │       │   │   ├── useBasicLayout.ts
        │       │   │   ├── useEmail.ts
        │       │   │   ├── useEnv.ts
        │       │   │   ├── useMobile.ts
        │       │   │   ├── useScroll.ts
        │       │   │   └── useVmodel.ts
        │       │   ├── layout/
        │       │   │   ├── header.vue
        │       │   │   ├── index.vue
        │       │   │   ├── m-footer.vue
        │       │   │   └── sider.vue
        │       │   ├── locales/
        │       │   │   ├── en.ts
        │       │   │   ├── index.ts
        │       │   │   ├── jp.ts
        │       │   │   ├── zh-cn.ts
        │       │   │   └── zh-tw.ts
        │       │   ├── main.ts
        │       │   ├── plugins/
        │       │   │   └── index.ts
        │       │   ├── router/
        │       │   │   └── index.ts
        │       │   ├── stores/
        │       │   │   ├── index.ts
        │       │   │   └── modules/
        │       │   │       ├── agent.ts
        │       │   │       ├── browser-setting.ts
        │       │   │       ├── conversation.ts
        │       │   │       ├── enterprise.ts
        │       │   │       ├── global.ts
        │       │   │       ├── links.ts
        │       │   │       ├── navigation.ts
        │       │   │       ├── prompt.ts
        │       │   │       └── user.ts
        │       │   ├── typings/
        │       │   │   ├── Browser.d.ts
        │       │   │   ├── agent.d.ts
        │       │   │   ├── category.d.ts
        │       │   │   ├── conversation.d.ts
        │       │   │   ├── enterprise.d.ts
        │       │   │   ├── global.d.ts
        │       │   │   ├── link.d.ts
        │       │   │   ├── navigation.d.ts
        │       │   │   ├── order.d.ts
        │       │   │   ├── prompt.ts
        │       │   │   ├── subscription.d.ts
        │       │   │   └── user.d.ts
        │       │   ├── utils/
        │       │   │   ├── cache.ts
        │       │   │   ├── copy.ts
        │       │   │   ├── event-bus.ts
        │       │   │   ├── file.ts
        │       │   │   ├── filter.ts
        │       │   │   ├── form-rules.ts
        │       │   │   ├── functions/
        │       │   │   │   ├── debounce.ts
        │       │   │   │   └── index.ts
        │       │   │   ├── index.ts
        │       │   │   ├── loadLib.ts
        │       │   │   ├── md5.ts
        │       │   │   ├── moment.ts
        │       │   │   ├── permission.ts
        │       │   │   ├── router.ts
        │       │   │   ├── scroll.ts
        │       │   │   ├── storage.ts
        │       │   │   └── url.ts
        │       │   └── views/
        │       │       ├── agent/
        │       │       │   ├── components/
        │       │       │   │   └── list.vue
        │       │       │   └── index.vue
        │       │       ├── chat/
        │       │       │   ├── chat/
        │       │       │   │   ├── components/
        │       │       │   │   │   ├── agent-tooltip.vue
        │       │       │   │   │   └── history.vue
        │       │       │   │   └── index.vue
        │       │       │   ├── completion/
        │       │       │   │   └── index.vue
        │       │       │   ├── helper.vue
        │       │       │   ├── index.vue
        │       │       │   └── store.ts
        │       │       ├── custom/
        │       │       │   └── index.vue
        │       │       ├── desktop/
        │       │       │   ├── components/
        │       │       │   │   ├── BookMarks.vue
        │       │       │   │   ├── Browser.vue
        │       │       │   │   ├── Error.vue
        │       │       │   │   ├── GNBTabs.vue
        │       │       │   │   ├── MultiBrowser.vue
        │       │       │   │   └── Reader/
        │       │       │   │       ├── html.vue
        │       │       │   │       ├── index.vue
        │       │       │   │       ├── markdown.vue
        │       │       │   │       └── summarize.vue
        │       │       │   ├── index.vue
        │       │       │   ├── stores/
        │       │       │   │   ├── tabs.ts
        │       │       │   │   └── user.ts
        │       │       │   └── tools/
        │       │       │       ├── index.vue
        │       │       │       └── toolbox.vue
        │       │       ├── discover/
        │       │       │   └── index.vue
        │       │       ├── index/
        │       │       │   ├── agent/
        │       │       │   │   ├── chat.vue
        │       │       │   │   └── index.vue
        │       │       │   ├── index.vue
        │       │       │   ├── layout.vue
        │       │       │   ├── prompt/
        │       │       │   │   ├── detail.vue
        │       │       │   │   └── index.vue
        │       │       │   ├── redirect.vue
        │       │       │   └── toolkit.vue
        │       │       ├── order/
        │       │       │   └── index.vue
        │       │       ├── profile/
        │       │       │   ├── about.vue
        │       │       │   ├── changeMobile.vue
        │       │       │   ├── common.vue
        │       │       │   ├── glider.vue
        │       │       │   ├── index.vue
        │       │       │   ├── password.vue
        │       │       │   ├── toolbar.vue
        │       │       │   └── userinfo.vue
        │       │       ├── prompt/
        │       │       │   ├── detail/
        │       │       │   │   └── index.vue
        │       │       │   ├── index.vue
        │       │       │   └── view.vue
        │       │       ├── share/
        │       │       │   └── chat.vue
        │       │       ├── svglist/
        │       │       │   └── index.vue
        │       │       └── toolkit/
        │       │           ├── components/
        │       │           │   ├── account-dialog.vue
        │       │           │   ├── group-list.vue
        │       │           │   └── list.vue
        │       │           └── index.vue
        │       └── public/
        │           └── oauth_login.html
        ├── stylelint.config.js
        ├── tailwind.config.js
        ├── tsconfig.json
        ├── tsconfig.node.json
        ├── tsconfig.web.json
        ├── vite.common.ts
        └── vite.config.ts
Download .txt
Showing preview only (2,128K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (12493 symbols across 590 files)

FILE: api/common/ctxkey/key.go
  constant Config (line 4) | Config            = "config"
  constant Id (line 5) | Id                = "id"
  constant Username (line 6) | Username          = "username"
  constant Role (line 7) | Role              = "role"
  constant Status (line 8) | Status            = "status"
  constant Channel (line 9) | Channel           = "channel"
  constant ChannelId (line 10) | ChannelId         = "channel_id"
  constant SpecificChannelId (line 11) | SpecificChannelId = "specific_channel_id"
  constant RequestModel (line 12) | RequestModel      = "request_model"
  constant ConvertedRequest (line 13) | ConvertedRequest  = "converted_request"
  constant OriginalModel (line 14) | OriginalModel     = "original_model"
  constant Group (line 15) | Group             = "group"
  constant ModelMapping (line 16) | ModelMapping      = "model_mapping"
  constant ChannelName (line 17) | ChannelName       = "channel_name"
  constant TokenId (line 18) | TokenId           = "token_id"
  constant TokenName (line 19) | TokenName         = "token_name"
  constant BaseURL (line 20) | BaseURL           = "base_url"
  constant AvailableModels (line 21) | AvailableModels   = "available_models"
  constant KeyRequestBody (line 22) | KeyRequestBody    = "key_request_body"
  constant SystemPrompt (line 23) | SystemPrompt      = "system_prompt"

FILE: api/common/email.go
  function ValidateEmailFormat (line 19) | func ValidateEmailFormat(email string) bool {
  function sendQQMailWithTLS (line 25) | func sendQQMailWithTLS(e *email.Email, auth smtp.Auth, host string, port...
  function SendEmail (line 106) | func SendEmail(e *email.Email, auth smtp.Auth, isSsl bool, host string, ...
  function VerifyEmailCode (line 138) | func VerifyEmailCode(email, code string) (bool, error) {
  function GenerateRandomCode (line 168) | func GenerateRandomCode(length int) (string, error) {

FILE: api/common/init.go
  function printHelp (line 18) | func printHelp() {
  function Init (line 26) | func Init() {

FILE: api/common/lock.go
  function InitLocker (line 14) | func InitLocker() {
  type Locker (line 22) | type Locker interface
  function NewLocalLock (line 33) | func NewLocalLock() *LocalLock {
  type LocalLock (line 37) | type LocalLock struct
    method TryLock (line 49) | func (ll *LocalLock) TryLock(name string, ttl time.Duration) bool {
    method Unlock (line 84) | func (ll *LocalLock) Unlock(name string) {
  type lockEntry (line 41) | type lockEntry struct
  type RedisLock (line 93) | type RedisLock struct
    method TryLock (line 101) | func (rl *RedisLock) TryLock(name string, ttl time.Duration) bool {
    method Unlock (line 108) | func (rl *RedisLock) Unlock(name string) {
  function NewRedisLock (line 97) | func NewRedisLock(client redis.Cmdable) *RedisLock {

FILE: api/common/logger/logger.go
  type loggerLevel (line 20) | type loggerLevel
  constant loggerDEBUG (line 23) | loggerDEBUG loggerLevel = "DEBUG"
  constant loggerINFO (line 24) | loggerINFO  loggerLevel = "INFO"
  constant loggerWARN (line 25) | loggerWARN  loggerLevel = "WARN"
  constant loggerERROR (line 26) | loggerERROR loggerLevel = "ERROR"
  constant loggerFATAL (line 27) | loggerFATAL loggerLevel = "FATAL"
  constant loggerNONE (line 28) | loggerNONE  loggerLevel = "NONE"
  function init (line 38) | func init() {
  function SetLogLevel (line 63) | func SetLogLevel(level string) {
  function GetLogLevel (line 84) | func GetLogLevel() string {
  function shouldLog (line 89) | func shouldLog(level loggerLevel) bool {
  function SetupLogger (line 110) | func SetupLogger() {
  function SysLog (line 129) | func SysLog(s string) {
  function SysLogf (line 133) | func SysLogf(format string, a ...any) {
  function SysWarn (line 137) | func SysWarn(s string) {
  function SysWarnf (line 141) | func SysWarnf(format string, a ...any) {
  function SysError (line 145) | func SysError(s string) {
  function SysErrorf (line 149) | func SysErrorf(format string, a ...any) {
  function Debug (line 153) | func Debug(ctx context.Context, msg string) {
  function Info (line 157) | func Info(ctx context.Context, msg string) {
  function Warn (line 161) | func Warn(ctx context.Context, msg string) {
  function Error (line 165) | func Error(ctx context.Context, msg string) {
  function Debugf (line 169) | func Debugf(ctx context.Context, format string, a ...any) {
  function Infof (line 173) | func Infof(ctx context.Context, format string, a ...any) {
  function Warnf (line 177) | func Warnf(ctx context.Context, format string, a ...any) {
  function Errorf (line 181) | func Errorf(ctx context.Context, format string, a ...any) {
  function FatalLog (line 185) | func FatalLog(s string) {
  function FatalLogf (line 189) | func FatalLogf(format string, a ...any) {
  function logHelper (line 193) | func logHelper(ctx context.Context, level loggerLevel, msg string) {
  function getLineInfo (line 219) | func getLineInfo() (string, string) {

FILE: api/common/permission.go
  function IsAdmin (line 8) | func IsAdmin(c *gin.Context) bool {

FILE: api/common/redis.go
  function InitRedisClient (line 19) | func InitRedisClient() error {
  function checkRedisEnabled (line 45) | func checkRedisEnabled() bool {
  function IsRedisEnabled (line 53) | func IsRedisEnabled() bool {
  function RedisSet (line 57) | func RedisSet(key string, value string, expiration time.Duration) error {
  function RedisGet (line 65) | func RedisGet(key string) (string, error) {
  function RedisDel (line 73) | func RedisDel(key string) error {
  function RedisDecrease (line 81) | func RedisDecrease(key string, value int64) error {
  function RedisZAdd (line 94) | func RedisZAdd(key string, score int64, member string) (int64, error) {
  function RedisZRangeByScore (line 111) | func RedisZRangeByScore(key string, min, max int64) ([]string, error) {
  function RedisZRem (line 127) | func RedisZRem(key string, member string) (int64, error) {
  function RedisZRemRangeByScore (line 140) | func RedisZRemRangeByScore(key string, min, max int64) (int64, error) {
  function RedisZCount (line 153) | func RedisZCount(key string, min, max int64) (int64, error) {
  function RedisExists (line 164) | func RedisExists(key string) (int64, error) {
  function RedisExpire (line 176) | func RedisExpire(key string, expiration time.Duration) (bool, error) {

FILE: api/common/session/key.go
  constant SESSION_USER_ID (line 4) | SESSION_USER_ID          = "SESSION_USER_ID"
  constant SESSION_USER_NICKNAME (line 5) | SESSION_USER_NICKNAME    = "SESSION_USER_NICKNAME"
  constant SESSION_USER_ROLE (line 6) | SESSION_USER_ROLE        = "SESSION_USER_ROLE"
  constant SESSION_USER_GROUP_ID (line 7) | SESSION_USER_GROUP_ID    = "SESSION_USER_GROUP_ID"
  constant ENV_EID (line 8) | ENV_EID                  = "ENV_EID"
  constant SESSION_AGENT_MODEL (line 9) | SESSION_AGENT_MODEL      = "SESSION_AGENT_MODEL"
  constant SESSION_AGENT_ID (line 10) | SESSION_AGENT_ID         = "SESSION_AGENT_ID"
  constant SESSION_AGENT (line 11) | SESSION_AGENT            = "SESSION_AGENT"
  constant SESSION_CONVERSATION_ID (line 12) | SESSION_CONVERSATION_ID  = "SESSION_CONVERSATION_ID"
  constant SESSION_CONVERSATION (line 13) | SESSION_CONVERSATION     = "SESSION_CONVERSATION"
  constant SESSION_SAAS_USER (line 14) | SESSION_SAAS_USER        = "SESSION_SAAS_USER"
  constant SESSION_REQUEST_PROTOCOL (line 15) | SESSION_REQUEST_PROTOCOL = "SESSION_REQUEST_PROTOCOL"
  constant SESSION_REQUEST_DOMAIN (line 16) | SESSION_REQUEST_DOMAIN   = "SESSION_REQUEST_DOMAIN"
  constant SESSION_ENV_VERSION (line 17) | SESSION_ENV_VERSION      = "SESSION_ENV_VERSION"

FILE: api/common/storage/storage.go
  type Storage (line 21) | type Storage interface
  type LocalStorage (line 29) | type LocalStorage struct
    method Save (line 69) | func (l *LocalStorage) Save(file []byte, fileName string) error {
    method Exists (line 84) | func (l *LocalStorage) Exists(fileName string) bool {
    method Delete (line 91) | func (l *LocalStorage) Delete(fileName string) error {
    method Load (line 101) | func (l *LocalStorage) Load(fileName string) ([]byte, error) {
    method GetBasePath (line 127) | func (l *LocalStorage) GetBasePath() string {
  type AliyunOSSStorage (line 34) | type AliyunOSSStorage struct
    method Save (line 131) | func (a *AliyunOSSStorage) Save(file []byte, fileName string) error {
    method Load (line 142) | func (a *AliyunOSSStorage) Load(fileName string) ([]byte, error) {
    method Exists (line 152) | func (a *AliyunOSSStorage) Exists(fileName string) bool {
    method Delete (line 158) | func (a *AliyunOSSStorage) Delete(fileName string) error {
    method GetBasePath (line 166) | func (a *AliyunOSSStorage) GetBasePath() string {
  function NewStorage (line 44) | func NewStorage() Storage {
  function GetFileHash (line 111) | func GetFileHash(file multipart.File) (string, error) {

FILE: api/common/storage/storage_test.go
  function TestSaveFile (line 9) | func TestSaveFile(t *testing.T) {

FILE: api/common/utils/ai53/api.go
  type AI53Api (line 12) | type AI53Api struct
    method GetBaseURL (line 28) | func (a *AI53Api) GetBaseURL() string {
    method GetApps (line 35) | func (a *AI53Api) GetApps(offset, limit int) ([]AppResponse, error) {
    method GetWorkflows (line 72) | func (a *AI53Api) GetWorkflows(offset, limit int) ([]AppResponse, erro...
    method cleanBotId (line 110) | func (a *AI53Api) cleanBotId(botId string) string {
    method GetAppParameters (line 126) | func (a *AI53Api) GetAppParameters(botId string) (interface{}, error) {
  type AppResponse (line 17) | type AppResponse struct

FILE: api/common/utils/appbuilder/api.go
  type AppBuilderApi (line 14) | type AppBuilderApi struct
    method DescribeApps (line 56) | func (a *AppBuilderApi) DescribeApps(marker string, maxKeys int) (*Des...
    method CreateConversation (line 103) | func (a *AppBuilderApi) CreateConversation(appId string) (*Conversatio...
    method doRequest (line 141) | func (a *AppBuilderApi) doRequest(method, url string, payload interfac...
  type AppInfo (line 21) | type AppInfo struct
  type DescribeAppsResponse (line 47) | type DescribeAppsResponse struct
  type ConversationResponse (line 92) | type ConversationResponse struct
  type ErrorResponse (line 97) | type ErrorResponse struct

FILE: api/common/utils/coze/api.go
  type CozeApi (line 15) | type CozeApi struct
    method doRequest (line 30) | func (c *CozeApi) doRequest(method, url string, payload interface{}, h...
    method GetOAuthToken (line 64) | func (c *CozeApi) GetOAuthToken(clientID, clientSecret, code, redirect...
    method RefreshOAuthToken (line 95) | func (c *CozeApi) RefreshOAuthToken(clientID, clientSecret, refreshTok...
    method RefreshTokenIfNeeded (line 157) | func (c *CozeApi) RefreshTokenIfNeeded(provider *model.Provider) error {
    method GetWorkspaces (line 189) | func (c *CozeApi) GetWorkspaces(provider *model.Provider, pageNum int,...
    method GetPublishedBots (line 233) | func (c *CozeApi) GetPublishedBots(provider *model.Provider, spaceID s...
  constant CozeCnUrl (line 20) | CozeCnUrl  = "https://api.coze.cn"
  constant CozeComUrl (line 21) | CozeComUrl = "https://api.coze.com"
  type CozeApiTokenResponse (line 24) | type CozeApiTokenResponse struct
  type Workspace (line 125) | type Workspace struct
  type WorkspacesResponse (line 133) | type WorkspacesResponse struct
  type Bot (line 138) | type Bot struct
  type PublishedBotsResponse (line 146) | type PublishedBotsResponse struct
  function IsTokenExpired (line 152) | func IsTokenExpired(provider *model.Provider) bool {

FILE: api/common/utils/env/env.go
  function Int (line 10) | func Int(env string, defaultValue int) int {
  function Int64 (line 21) | func Int64(env string, defaultValue int64) int64 {
  function Float64 (line 32) | func Float64(env string, defaultValue float64) float64 {
  function String (line 43) | func String(env string, defaultValue string) string {
  function Bool (line 50) | func Bool(env string, defaultValue bool) bool {

FILE: api/common/utils/helper/helper.go
  function GetRequestID (line 15) | func GetRequestID(ctx context.Context) string {
  constant Chars (line 23) | Chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
  function RandomString (line 25) | func RandomString(n int) string {
  function PasswordHash (line 34) | func PasswordHash(password string, salt string) (string, error) {
  function Bytes2Size (line 45) | func Bytes2Size(num int64) string {
  function ParseSize (line 63) | func ParseSize(sizeStr string) (int64, error) {
  function CalcElapsedTime (line 89) | func CalcElapsedTime(start time.Time) int64 {
  function IsValidPhone (line 95) | func IsValidPhone(phone string) bool {
  function IsValidEmail (line 121) | func IsValidEmail(email string) bool {
  function HasIntersection (line 127) | func HasIntersection(a, b []int64) bool {
  function GetHost (line 143) | func GetHost(u string) (string, error) {
  function StrInArray (line 153) | func StrInArray(str string, arr []string) bool {

FILE: api/common/utils/helper/key.go
  constant RequestIdKey (line 4) | RequestIdKey = "X-Request-Id"

FILE: api/common/utils/helper/sso_sign.go
  function BuildSSORawString (line 9) | func BuildSSORawString(timestamp string, normalizedUsername string, secr...
  function CalcSSOSignLowerHex (line 14) | func CalcSSOSignLowerHex(raw string) string {

FILE: api/common/utils/huawei_cloud/model.go
  type HuaweicloudBaseResponse (line 3) | type HuaweicloudBaseResponse struct
  type HuaweicloudCallbackRequest (line 8) | type HuaweicloudCallbackRequest struct
  type HuaweicloudCallbackQuery (line 13) | type HuaweicloudCallbackQuery struct
  constant SUCCESS (line 20) | SUCCESS = "000000"
  constant SUCCESS_MSG (line 24) | SUCCESS_MSG = "success"
  type CreateInstanceResponse (line 27) | type CreateInstanceResponse struct
  function GetSuccess (line 32) | func GetSuccess() HuaweicloudBaseResponse {
  type HuaweiCloudBody (line 39) | type HuaweiCloudBody struct
  type QueryInstanceResponse (line 60) | type QueryInstanceResponse struct
  type InstanceInfo (line 65) | type InstanceInfo struct
  type AppInfo (line 70) | type AppInfo struct

FILE: api/common/utils/huawei_cloud/signature.go
  type IMessageResp (line 17) | type IMessageResp struct
  constant TIMESTAMP (line 23) | TIMESTAMP = "timestamp"
  constant NONCE (line 24) | NONCE     = "nonce"
  constant SIGNATURE (line 25) | SIGNATURE = "signature"
  constant TIME_DIFF (line 26) | TIME_DIFF = 60 * time.Second
  function VerifySignature (line 29) | func VerifySignature(c *gin.Context, accessKey string) error {
  function generateSignature (line 68) | func generateSignature(accessKey string, body []byte, timestamp string, ...
  function hmacSHA256 (line 82) | func hmacSHA256(data []byte, key string) []byte {
  function validateReqTime (line 88) | func validateReqTime(timestamp string) bool {

FILE: api/common/utils/ip.go
  function GetClientIP (line 11) | func GetClientIP(c *gin.Context) string {

FILE: api/common/utils/jwt/jwt.go
  function UserGenerateJWT (line 12) | func UserGenerateJWT(userID int64, eid int64) (string, error) {
  function UserParseJWT (line 23) | func UserParseJWT(tokenString string) (int64, int64, error) {

FILE: api/common/utils/random.go
  function init (line 10) | func init() {
  function GetRandomInt64 (line 15) | func GetRandomInt64(n int64) int64 {

FILE: api/common/utils/snowflake.go
  type Snowflake (line 10) | type Snowflake struct
    method NextId (line 31) | func (s *Snowflake) NextId() int64 {
    method waitNextMillis (line 65) | func (s *Snowflake) waitNextMillis(lastTimestamp int64) int64 {
  function NewSnowflake (line 19) | func NewSnowflake(workerId int64) *Snowflake {
  function GenerateOrderId (line 78) | func GenerateOrderId() string {

FILE: api/common/utils/system/machine.go
  constant EnvFilePath (line 16) | EnvFilePath = ".env"
  type MachineInfo (line 20) | type MachineInfo struct
  function GenerateMachineCode (line 29) | func GenerateMachineCode() (string, error) {
  function GetMachineInfo (line 70) | func GetMachineInfo() (*MachineInfo, error) {
  function GetOrGenerateMachineCode (line 90) | func GetOrGenerateMachineCode() (string, error) {
  function GetVersion (line 125) | func GetVersion() string {
  function readEnvFile (line 144) | func readEnvFile() (map[string]string, error) {
  function writeEnvFile (line 174) | func writeEnvFile(envMap map[string]string) error {
  function saveMachineCodeToEnv (line 195) | func saveMachineCodeToEnv(machineCode string) error {
  function AppendToEnvFile (line 221) | func AppendToEnvFile(key, value string) error {

FILE: api/common/utils/system/version.go
  constant VersionCheckURL (line 16) | VersionCheckURL = "https://update.53ai.net/checkversion/53aihub/"
  type VersionCheckResponse (line 20) | type VersionCheckResponse struct
  function CheckVersion (line 32) | func CheckVersion() (*VersionCheckResponse, error) {
  function CheckVersionAndReturn (line 92) | func CheckVersionAndReturn() (*VersionCheckResponse, string, error) {
  function checkWebsiteIdExists (line 128) | func checkWebsiteIdExists() (string, bool, error) {
  function addWebsiteIdToEnv (line 138) | func addWebsiteIdToEnv(websiteId string) error {

FILE: api/common/utils/wxbizjsonmsgcrypt/wxbizjsonmsgcrypt.go
  constant letterBytes (line 17) | letterBytes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTU...
  constant ValidateSignatureError (line 20) | ValidateSignatureError int = -40001
  constant ParseXmlError (line 21) | ParseXmlError          int = -40002
  constant ComputeSignatureError (line 22) | ComputeSignatureError  int = -40003
  constant IllegalAesKey (line 23) | IllegalAesKey          int = -40004
  constant ValidateCorpidError (line 24) | ValidateCorpidError    int = -40005
  constant EncryptAESError (line 25) | EncryptAESError        int = -40006
  constant DecryptAESError (line 26) | DecryptAESError        int = -40007
  constant IllegalBuffer (line 27) | IllegalBuffer          int = -40008
  constant EncodeBase64Error (line 28) | EncodeBase64Error      int = -40009
  constant DecodeBase64Error (line 29) | DecodeBase64Error      int = -40010
  constant GenXmlError (line 30) | GenXmlError            int = -40010
  constant ParseJsonError (line 31) | ParseJsonError         int = -40012
  constant GenJsonError (line 32) | GenJsonError           int = -40013
  constant IllegalProtocolType (line 33) | IllegalProtocolType    int = -40014
  type ProtocolType (line 36) | type ProtocolType
  constant XmlType (line 39) | XmlType ProtocolType = 1
  type CryptError (line 42) | type CryptError struct
  function NewCryptError (line 47) | func NewCryptError(err_code int, err_msg string) *CryptError {
  type WXBizMsg4Recv (line 51) | type WXBizMsg4Recv struct
  type CDATA (line 57) | type CDATA struct
  type WXBizMsg4Send (line 61) | type WXBizMsg4Send struct
  function NewWXBizMsg4Send (line 69) | func NewWXBizMsg4Send(encrypt, signature, timestamp, nonce string) *WXBi...
  type ProtocolProcessor (line 73) | type ProtocolProcessor interface
  type WXBizMsgCrypt (line 78) | type WXBizMsgCrypt struct
    method randString (line 116) | func (self *WXBizMsgCrypt) randString(n int) string {
    method pKCS7Padding (line 124) | func (self *WXBizMsgCrypt) pKCS7Padding(plaintext string, block_size i...
    method pKCS7Unpadding (line 133) | func (self *WXBizMsgCrypt) pKCS7Unpadding(plaintext []byte, block_size...
    method cbcEncrypter (line 145) | func (self *WXBizMsgCrypt) cbcEncrypter(plaintext string) ([]byte, *Cr...
    method cbcDecrypter (line 170) | func (self *WXBizMsgCrypt) cbcDecrypter(base64_encrypt_msg string) ([]...
    method calSignature (line 203) | func (self *WXBizMsgCrypt) calSignature(timestamp, nonce, data string)...
    method ParsePlainText (line 217) | func (self *WXBizMsgCrypt) ParsePlainText(plaintext []byte) ([]byte, u...
    method VerifyURL (line 240) | func (self *WXBizMsgCrypt) VerifyURL(msg_signature, timestamp, nonce, ...
    method EncryptMsg (line 265) | func (self *WXBizMsgCrypt) EncryptMsg(reply_msg, timestamp, nonce stri...
    method DecryptMsg (line 288) | func (self *WXBizMsgCrypt) DecryptMsg(msg_signature, timestamp, nonce ...
  type XmlProcessor (line 85) | type XmlProcessor struct
    method parse (line 88) | func (self *XmlProcessor) parse(src_data []byte) (*WXBizMsg4Recv, *Cry...
    method serialize (line 97) | func (self *XmlProcessor) serialize(msg4_send *WXBizMsg4Send) ([]byte,...
  function NewWXBizMsgCrypt (line 105) | func NewWXBizMsgCrypt(token, encoding_aeskey, receiver_id string, protoc...

FILE: api/common/validate.go
  function init (line 7) | func init() {

FILE: api/config/config.go
  function GetApiHost (line 42) | func GetApiHost() string {
  function GetEID (line 49) | func GetEID(c *gin.Context) int64 {
  function GetUserId (line 58) | func GetUserId(c *gin.Context) int64 {
  function GetUserNickname (line 66) | func GetUserNickname(c *gin.Context) string {
  function GetUserGroupID (line 75) | func GetUserGroupID(c *gin.Context) int64 {
  function GetProtocol (line 84) | func GetProtocol(c *gin.Context) string {
  function GetDomain (line 93) | func GetDomain(c *gin.Context) string {
  function GetServer (line 101) | func GetServer(c *gin.Context) string {
  function Getwd (line 105) | func Getwd() string {
  function GetBinScriptPath (line 113) | func GetBinScriptPath(shName string) string {
  function GetWecomSuiteID (line 123) | func GetWecomSuiteID() string {
  function GetDingtalkSuiteID (line 127) | func GetDingtalkSuiteID() string {
  function GetUserRole (line 131) | func GetUserRole(c *gin.Context) int64 {

FILE: api/config/encryption.go
  function GetEncryptionKey (line 8) | func GetEncryptionKey() string {

FILE: api/controller/agent.go
  type AgentListRequest (line 19) | type AgentListRequest struct
  type AgentsResponse (line 28) | type AgentsResponse struct
  type AgentRequest (line 33) | type AgentRequest struct
  type UpdateAgentEnableRequest (line 53) | type UpdateAgentEnableRequest struct
  function CreateAgent (line 66) | func CreateAgent(c *gin.Context) {
  function GetAgent (line 193) | func GetAgent(c *gin.Context) {
  function UpdateAgent (line 232) | func UpdateAgent(c *gin.Context) {
  function DeleteAgent (line 388) | func DeleteAgent(c *gin.Context) {
  function GetAgents (line 462) | func GetAgents(c *gin.Context) {
  function GetAgentsByGroup (line 529) | func GetAgentsByGroup(c *gin.Context) {
  function GetAvailableAgents (line 574) | func GetAvailableAgents(c *gin.Context) {
  function GetCurrentAgents (line 623) | func GetCurrentAgents(c *gin.Context) {
  function UpdateAgentStatus (line 686) | func UpdateAgentStatus(c *gin.Context) {
  function splitChannelTypesString (line 736) | func splitChannelTypesString(channelTypesStr string) []int {
  function splitAgentTypesString (line 749) | func splitAgentTypesString(agentTypesStr string) []int {
  function GetInternalUserAgents (line 770) | func GetInternalUserAgents(c *gin.Context) {

FILE: api/controller/ai53.go
  function Get53AIAllBots (line 26) | func Get53AIAllBots(c *gin.Context) {
  function Get53AIAllWorkflows (line 60) | func Get53AIAllWorkflows(c *gin.Context) {
  function Update53AIChannel (line 84) | func Update53AIChannel(provider model.Provider, apps []ai53.AppResponse)...
  function Update53AIWorkflowChannel (line 139) | func Update53AIWorkflowChannel(provider model.Provider, apps []ai53.AppR...
  function Get53AIAppParameters (line 205) | func Get53AIAppParameters(c *gin.Context) {

FILE: api/controller/ai_link.go
  type AILinkRequest (line 13) | type AILinkRequest struct
  function CreateAILink (line 35) | func CreateAILink(c *gin.Context) {
  function GetAILink (line 112) | func GetAILink(c *gin.Context) {
  function UpdateAILink (line 139) | func UpdateAILink(c *gin.Context) {
  function DeleteAILink (line 221) | func DeleteAILink(c *gin.Context) {
  function GetAILinks (line 270) | func GetAILinks(c *gin.Context) {
  function GetCurrentSiteAILinks (line 306) | func GetCurrentSiteAILinks(c *gin.Context) {
  function GetDefaultAILinks (line 325) | func GetDefaultAILinks(c *gin.Context) {
  type SortItem (line 331) | type SortItem struct
  type BatchSortRequest (line 337) | type BatchSortRequest struct
  function BatchSortAILinks (line 350) | func BatchSortAILinks(c *gin.Context) {

FILE: api/controller/appbuilder.go
  function GetAppBuilderAllBots (line 26) | func GetAppBuilderAllBots(c *gin.Context) {
  function UpdateAppBuilderChannel (line 52) | func UpdateAppBuilderChannel(provider model.Provider, apps []appbuilder....

FILE: api/controller/auth_sso.go
  type SSOConfig (line 18) | type SSOConfig struct
  type SSOLoginRequest (line 25) | type SSOLoginRequest struct
  type SaasLoginResponse (line 32) | type SaasLoginResponse struct
  function ApiSSOSSOLogin (line 48) | func ApiSSOSSOLogin(c *gin.Context) {
  function loadSSOConfig (line 125) | func loadSSOConfig(eid int64) *SSOConfig {
  function isValid10DigitTimestamp (line 138) | func isValid10DigitTimestamp(ts string) bool {

FILE: api/controller/channel-test.go
  type ChannelTestResponse (line 30) | type ChannelTestResponse struct
  function TestChannel (line 47) | func TestChannel(c *gin.Context) {
  function testChannel (line 81) | func testChannel(ctx context.Context, channel *model.Channel, request *r...
  function parseTestResponse (line 193) | func parseTestResponse(resp string) (*openai.TextResponse, string, error) {
  function buildTestRequest (line 209) | func buildTestRequest(model string) *relaymodel.GeneralOpenAIRequest {

FILE: api/controller/channel.go
  function autoAssignCozeStudioProvider (line 17) | func autoAssignCozeStudioProvider(channel *model.Channel) error {
  type ChannelRequest (line 41) | type ChannelRequest struct
  function CreateChannel (line 65) | func CreateChannel(c *gin.Context) {
  function GetChannel (line 128) | func GetChannel(c *gin.Context) {
  function UpdateChannel (line 150) | func UpdateChannel(c *gin.Context) {
  function DeleteChannel (line 217) | func DeleteChannel(c *gin.Context) {
  function GetChannels (line 244) | func GetChannels(c *gin.Context) {

FILE: api/controller/conversation.go
  type ConversationRequest (line 12) | type ConversationRequest struct
  type ConversationUpdateRequest (line 17) | type ConversationUpdateRequest struct
  type ConversationResponse (line 21) | type ConversationResponse struct
  type ConversationListRequest (line 26) | type ConversationListRequest struct
  function CreateConversation (line 41) | func CreateConversation(c *gin.Context) {
  function GetConversation (line 81) | func GetConversation(c *gin.Context) {
  function GetConversations (line 107) | func GetConversations(c *gin.Context) {
  function UpdateConversation (line 136) | func UpdateConversation(c *gin.Context) {
  type UserConversationListRequest (line 165) | type UserConversationListRequest struct
  function GetUserConversations (line 185) | func GetUserConversations(c *gin.Context) {
  type UserInfo (line 243) | type UserInfo struct
  type ConversationSummary (line 249) | type ConversationSummary struct
  type ConversationSummaryResponse (line 259) | type ConversationSummaryResponse struct
  function GetAgentConversations (line 277) | func GetAgentConversations(c *gin.Context) {
  function DeleteConversation (line 339) | func DeleteConversation(c *gin.Context) {

FILE: api/controller/coze.go
  function GetCozeAllWorkspaces (line 24) | func GetCozeAllWorkspaces(c *gin.Context) {
  function GetCozeAllBots (line 54) | func GetCozeAllBots(c *gin.Context) {

FILE: api/controller/department.go
  type DepartmentRequest (line 13) | type DepartmentRequest struct
  type UpdateDepartmentRequest (line 19) | type UpdateDepartmentRequest struct
  type DepartmentResponse (line 25) | type DepartmentResponse struct
  type DepartmentTreeResponse (line 31) | type DepartmentTreeResponse struct
  type BindRequest (line 35) | type BindRequest struct
  type UnBindRequest (line 40) | type UnBindRequest struct
  function CreateDepartment (line 57) | func CreateDepartment(c *gin.Context) {
  function GetDepartment (line 93) | func GetDepartment(c *gin.Context) {
  function UpdateDepartment (line 124) | func UpdateDepartment(c *gin.Context) {
  function DeleteDepartment (line 171) | func DeleteDepartment(c *gin.Context) {
  function GetDepartments (line 201) | func GetDepartments(c *gin.Context) {
  function GetChildDepartments (line 229) | func GetChildDepartments(c *gin.Context) {
  function GetDepartmentTree (line 259) | func GetDepartmentTree(c *gin.Context) {
  function DepartmentBindMember (line 285) | func DepartmentBindMember(c *gin.Context) {
  function DepartmentUnbindMember (line 341) | func DepartmentUnbindMember(c *gin.Context) {

FILE: api/controller/dify.go
  function GetDifyAppInfo (line 24) | func GetDifyAppInfo(c *gin.Context) {
  function GetDifyAppParameters (line 82) | func GetDifyAppParameters(c *gin.Context) {

FILE: api/controller/email.go
  constant verificationCodeLength (line 21) | verificationCodeLength = 6
  constant duration (line 22) | duration               = 15
  constant codeExpiration (line 23) | codeExpiration         = duration * time.Minute
  type SendVerificationEmailRequest (line 26) | type SendVerificationEmailRequest struct
  function SendVerificationEmail (line 40) | func SendVerificationEmail(c *gin.Context) {
  type SendTestEmailRequest (line 107) | type SendTestEmailRequest struct
  function SendTestEmail (line 128) | func SendTestEmail(c *gin.Context) {
  type UpdateUserEmailRequest (line 163) | type UpdateUserEmailRequest struct
  function UpdateUserEmail (line 182) | func UpdateUserEmail(c *gin.Context) {

FILE: api/controller/enterprise.go
  type EnterpriseResponse (line 16) | type EnterpriseResponse struct
  function GetEnterprise (line 32) | func GetEnterprise(c *gin.Context) {
  function CreateEnterprise (line 58) | func CreateEnterprise(c *gin.Context) {
  type UpdateEnterpriseRequest (line 76) | type UpdateEnterpriseRequest struct
  function UpdateEnterprise (line 99) | func UpdateEnterprise(c *gin.Context) {
  function DeleteEnterprise (line 228) | func DeleteEnterprise(c *gin.Context) {
  function UpdateEnterpriseAttribute (line 259) | func UpdateEnterpriseAttribute(c *gin.Context) {
  function GetCurrentEnterprise (line 295) | func GetCurrentEnterprise(c *gin.Context) {
  type GetIsSaasResponse (line 321) | type GetIsSaasResponse struct
  function GetIsSaas (line 334) | func GetIsSaas(c *gin.Context) {
  type HomePageResponse (line 340) | type HomePageResponse struct
  function GetHomePage (line 355) | func GetHomePage(c *gin.Context) {
  function GetEnterpriseBanner (line 403) | func GetEnterpriseBanner(c *gin.Context) {
  type UpdateEnterpriseBannerRequest (line 421) | type UpdateEnterpriseBannerRequest struct
  function UpdateEnterpriseBanner (line 434) | func UpdateEnterpriseBanner(c *gin.Context) {
  type UpdateEnterpriseTemplateTypeRequest (line 468) | type UpdateEnterpriseTemplateTypeRequest struct
  function UpdateEnterpriseTemplateType (line 481) | func UpdateEnterpriseTemplateType(c *gin.Context) {
  function GetEnterpriseTemplateType (line 534) | func GetEnterpriseTemplateType(c *gin.Context) {

FILE: api/controller/enterprise_config.go
  type ConfigTypeStatus (line 15) | type ConfigTypeStatus struct
  function GetEnterpriseConfigTypes (line 30) | func GetEnterpriseConfigTypes(c *gin.Context) {
  function GetEnterpriseConfig (line 60) | func GetEnterpriseConfig(c *gin.Context) {
  function IsEnterpriseConfigEnabled (line 94) | func IsEnterpriseConfigEnabled(c *gin.Context) {
  type SaveEnterpriseConfigRequest (line 111) | type SaveEnterpriseConfigRequest struct
  function SaveEnterpriseConfig (line 128) | func SaveEnterpriseConfig(c *gin.Context) {
  function ToggleEnterpriseConfig (line 157) | func ToggleEnterpriseConfig(c *gin.Context) {

FILE: api/controller/group.go
  type BaseGroupRequest (line 14) | type BaseGroupRequest struct
  type GroupRequest (line 19) | type GroupRequest struct
  type BatchSubmitGroupRequestItem (line 24) | type BatchSubmitGroupRequestItem struct
  type BatchSubmitGroupsRequest (line 29) | type BatchSubmitGroupsRequest struct
  function CreateGroup (line 43) | func CreateGroup(c *gin.Context) {
  function GetGroup (line 79) | func GetGroup(c *gin.Context) {
  function UpdateGroup (line 105) | func UpdateGroup(c *gin.Context) {
  function DeleteGroup (line 150) | func DeleteGroup(c *gin.Context) {
  function GetGroups (line 185) | func GetGroups(c *gin.Context) {
  function GetCurrentGroups (line 209) | func GetCurrentGroups(c *gin.Context) {
  function BatchSubmitGroups (line 239) | func BatchSubmitGroups(c *gin.Context) {
  type AddAgentsToGroupRequest (line 283) | type AddAgentsToGroupRequest struct
  type AddResourcesToGroupRequest (line 288) | type AddResourcesToGroupRequest struct
  function AddAgentsToGroup (line 303) | func AddAgentsToGroup(c *gin.Context) {
  function AddResourcesToGroup (line 387) | func AddResourcesToGroup(c *gin.Context) {
  type RemoveAgentsFromGroupRequest (line 474) | type RemoveAgentsFromGroupRequest struct
  type RemoveResourcesFromGroupRequest (line 479) | type RemoveResourcesFromGroupRequest struct
  function RemoveAgentsFromGroup (line 494) | func RemoveAgentsFromGroup(c *gin.Context) {
  function RemoveResourcesFromGroup (line 563) | func RemoveResourcesFromGroup(c *gin.Context) {
  type GroupAgentListRequest (line 635) | type GroupAgentListRequest struct
  type GroupAgentListResponse (line 642) | type GroupAgentListResponse struct
  function GetGroupAgents (line 659) | func GetGroupAgents(c *gin.Context) {
  function GetGroupResources (line 764) | func GetGroupResources(c *gin.Context) {
  type GroupResourceListRequest (line 857) | type GroupResourceListRequest struct
  type GroupResourceListResponse (line 865) | type GroupResourceListResponse struct
  type BatchAddUsersToGroupRequest (line 871) | type BatchAddUsersToGroupRequest struct
  function BatchAddUsersToGroup (line 886) | func BatchAddUsersToGroup(c *gin.Context) {
  type GroupUsersRequest (line 1033) | type GroupUsersRequest struct
  type GroupUsersResponse (line 1041) | type GroupUsersResponse struct
  function GetGroupUsers (line 1060) | func GetGroupUsers(c *gin.Context) {
  type RemoveUsersFromGroupRequest (line 1226) | type RemoveUsersFromGroupRequest struct
  function RemoveUsersFromGroup (line 1240) | func RemoveUsersFromGroup(c *gin.Context) {
  function handleAgentResources (line 1292) | func handleAgentResources(c *gin.Context, agentIDs []int64, keyword stri...
  function handleAILinkResources (line 1323) | func handleAILinkResources(c *gin.Context, aiLinkIDs []int64, keyword st...
  function handlePromptResources (line 1354) | func handlePromptResources(c *gin.Context, promptIDs []int64, keyword st...

FILE: api/controller/maxkb.go
  type MaxKBProfileResponse (line 19) | type MaxKBProfileResponse struct
  type MaxKBProfileData (line 25) | type MaxKBProfileData struct
  function GetMaxKBApplicationProfile (line 57) | func GetMaxKBApplicationProfile(c *gin.Context) {
  function extractBaseURL (line 130) | func extractBaseURL(fullURL string) (string, error) {
  function makeMaxKBRequest (line 147) | func makeMaxKBRequest(url, applicationToken string) ([]byte, error) {
  function findMaxKBChannelByBotID (line 188) | func findMaxKBChannelByBotID(eid int64, botID string) (*model.Channel, e...
  function containsBotID (line 210) | func containsBotID(models, botID string) bool {

FILE: api/controller/message.go
  type MessagesResponse (line 13) | type MessagesResponse struct
  type EnhancedMessage (line 19) | type EnhancedMessage struct
  type MessageListRequest (line 26) | type MessageListRequest struct
  function convertToEnhancedMessages (line 34) | func convertToEnhancedMessages(messages []*model.Message) []*EnhancedMes...
  function GetMessagesByUserAndAgent (line 87) | func GetMessagesByUserAndAgent(c *gin.Context) {
  function GetUserMessages (line 129) | func GetUserMessages(c *gin.Context) {
  function GetMessagesByConversation (line 186) | func GetMessagesByConversation(c *gin.Context) {

FILE: api/controller/model.go
  type OpenAIModelPermission (line 14) | type OpenAIModelPermission struct
  type OpenAIModels (line 29) | type OpenAIModels struct
  type OpenAIModelsResponse (line 39) | type OpenAIModelsResponse struct
  function init (line 47) | func init() {
  function ListAllModels (line 158) | func ListAllModels(c *gin.Context) {

FILE: api/controller/navigation.go
  function GetNavigations (line 22) | func GetNavigations(c *gin.Context) {
  type NavigationRequest (line 48) | type NavigationRequest struct
  function CreateNavigation (line 66) | func CreateNavigation(c *gin.Context) {
  function GetNavigation (line 123) | func GetNavigation(c *gin.Context) {
  function UpdateNavigation (line 153) | func UpdateNavigation(c *gin.Context) {
  function DeleteNavigation (line 214) | func DeleteNavigation(c *gin.Context) {
  type UpdateNavigationStatusRequest (line 266) | type UpdateNavigationStatusRequest struct
  function UpdateNavigationStatus (line 280) | func UpdateNavigationStatus(c *gin.Context) {
  type NavigationSortItem (line 319) | type NavigationSortItem struct
  function SortNavigations (line 334) | func SortNavigations(c *gin.Context) {
  function handleNotFound (line 358) | func handleNotFound(c *gin.Context, nav *model.Navigation, err error) bo...
  function InitSystemNavigation (line 374) | func InitSystemNavigation(c *gin.Context) {
  type CreateNavigationContentRequest (line 424) | type CreateNavigationContentRequest struct
  function CreateNavigationContent (line 438) | func CreateNavigationContent(c *gin.Context) {
  function GetNavigationContent (line 505) | func GetNavigationContent(c *gin.Context) {

FILE: api/controller/navigation_icons.go
  type NavigationIcon (line 11) | type NavigationIcon struct
  function GetNavigationIcons (line 24) | func GetNavigationIcons(c *gin.Context) {

FILE: api/controller/order.go
  type Response (line 16) | type Response struct
  type ErrorResponse (line 22) | type ErrorResponse struct
  function CloseOrder (line 37) | func CloseOrder(c *gin.Context) {
  type OrderListRequest (line 96) | type OrderListRequest struct
  type OrderListResponse (line 109) | type OrderListResponse struct
  function GetOrders (line 134) | func GetOrders(c *gin.Context) {
  function GetOrder (line 211) | func GetOrder(c *gin.Context) {
  function GetUserOrders (line 239) | func GetUserOrders(c *gin.Context) {
  type UpdateOrderStatusRequest (line 254) | type UpdateOrderStatusRequest struct
  function UpdateOrderStatus (line 269) | func UpdateOrderStatus(c *gin.Context) {
  function DeleteOrder (line 334) | func DeleteOrder(c *gin.Context) {
  function ConfirmManualPayment (line 375) | func ConfirmManualPayment(c *gin.Context) {
  type UpdateManualTransferOrderRequest (line 455) | type UpdateManualTransferOrderRequest struct
  function UpdateManualTransferOrder (line 477) | func UpdateManualTransferOrder(c *gin.Context) {
  function QueryTradeOrder (line 521) | func QueryTradeOrder(c *gin.Context) {
  function RefunTradeOrder (line 557) | func RefunTradeOrder(c *gin.Context) {

FILE: api/controller/pay.go
  type WechatNotifyResponse (line 26) | type WechatNotifyResponse struct
  type CreateOrderRequest (line 32) | type CreateOrderRequest struct
  type OrderResponse (line 47) | type OrderResponse struct
  type PayOrderRequest (line 53) | type PayOrderRequest struct
  type PayOrderResponse (line 60) | type PayOrderResponse struct
  function CreateOrder (line 77) | func CreateOrder(c *gin.Context) {
  function getOrder (line 145) | func getOrder(c *gin.Context, eid int64, req CreateOrderRequest, paySett...
  function getCachedOrder (line 197) | func getCachedOrder(orderId string) (*model.Order, bool) {
  function removeCachedOrder (line 213) | func removeCachedOrder(orderId string) {
  function createOrUpdateOrderFromCache (line 218) | func createOrUpdateOrderFromCache(eid int64, orderId string, status int,...
  function createOrUpdateOrderFromCacheWithTime (line 278) | func createOrUpdateOrderFromCacheWithTime(eid int64, orderId string, sta...
  function AlipayNotify (line 359) | func AlipayNotify(c *gin.Context) {
  function WechatPayNotify (line 459) | func WechatPayNotify(c *gin.Context) {
  function QueryOrderStatus (line 672) | func QueryOrderStatus(c *gin.Context) {
  type OrderStatusResponse (line 808) | type OrderStatusResponse struct
  function getTradeStateDesc (line 815) | func getTradeStateDesc(tradeState string) string {
  function queryWechatOrderStatusWithOriginal (line 845) | func queryWechatOrderStatusWithOriginal(eid int64, orderId string) (int,...
  function queryAlipayOrderStatusWithOriginal (line 901) | func queryAlipayOrderStatusWithOriginal(eid int64, order *model.Order) (...
  type PayTypeStatus (line 955) | type PayTypeStatus struct
  function GetAvailablePayTypes (line 969) | func GetAvailablePayTypes(c *gin.Context) {

FILE: api/controller/pay_setting.go
  type PaySettingRequest (line 17) | type PaySettingRequest struct
  type PaySettingsResponse (line 29) | type PaySettingsResponse struct
  function CreatePaySetting (line 46) | func CreatePaySetting(c *gin.Context) {
  function UpdatePaySetting (line 127) | func UpdatePaySetting(c *gin.Context) {
  function DeletePaySetting (line 188) | func DeletePaySetting(c *gin.Context) {
  function GetPaySetting (line 219) | func GetPaySetting(c *gin.Context) {
  function GetPaySettings (line 244) | func GetPaySettings(c *gin.Context) {
  function GetPaySettingByType (line 266) | func GetPaySettingByType(c *gin.Context) {
  type PayConfigRequest (line 290) | type PayConfigRequest struct
  type PayStatusRequest (line 296) | type PayStatusRequest struct
  function UpdatePayConfig (line 311) | func UpdatePayConfig(c *gin.Context) {
  function UpdatePayStatus (line 382) | func UpdatePayStatus(c *gin.Context) {
  function isValidPayType (line 434) | func isValidPayType(payType int) bool {
  function processWechatConfig (line 439) | func processWechatConfig(payConfig string) (string, error) {

FILE: api/controller/prompt.go
  type PromptListRequest (line 19) | type PromptListRequest struct
  type PromptsResponse (line 27) | type PromptsResponse struct
  type PromptRequest (line 33) | type PromptRequest struct
  function GetPrompts (line 58) | func GetPrompts(c *gin.Context) {
  function CreatePrompt (line 143) | func CreatePrompt(c *gin.Context) {
  function GetPrompt (line 262) | func GetPrompt(c *gin.Context) {
  function UpdatePrompt (line 330) | func UpdatePrompt(c *gin.Context) {
  function DeletePrompt (line 449) | func DeletePrompt(c *gin.Context) {
  function UpdatePromptLike (line 514) | func UpdatePromptLike(c *gin.Context) {
  type UpdatePromptStatusRequest (line 608) | type UpdatePromptStatusRequest struct
  function UpdatePromptStatus (line 623) | func UpdatePromptStatus(c *gin.Context) {
  function GetPromptGroups (line 669) | func GetPromptGroups(c *gin.Context) {
  function getPromptListWithIDs (line 713) | func getPromptListWithIDs(eid int64, keyword string, groupIDStr string, ...

FILE: api/controller/provider.go
  type ProviderRequest (line 15) | type ProviderRequest struct
  function validateCozeConfig (line 23) | func validateCozeConfig(providerType int64, configStr string) error {
  function checkSaveAccessToken (line 39) | func checkSaveAccessToken(ProviderType int64, req ProviderRequest) (bool...
  function CreateProvider (line 64) | func CreateProvider(c *gin.Context) {
  function DeleteProvider (line 111) | func DeleteProvider(c *gin.Context) {
  function GetProviders (line 161) | func GetProviders(c *gin.Context) {
  function UpdateProvider (line 184) | func UpdateProvider(c *gin.Context) {

FILE: api/controller/provider_callback.go
  type CozeCallbackRequest (line 17) | type CozeCallbackRequest struct
  function CozeCallBack (line 34) | func CozeCallBack(c *gin.Context) {

FILE: api/controller/relay.go
  type Message (line 47) | type Message struct
  type ChatRequest (line 52) | type ChatRequest struct
  type WorkflowRunRequest (line 64) | type WorkflowRunRequest struct
  function WorkflowRun (line 80) | func WorkflowRun(c *gin.Context) {
  function GetSessionAgent (line 162) | func GetSessionAgent(c *gin.Context) (agent *model.Agent, err error) {
  function extractWorkflowID (line 175) | func extractWorkflowID(modelName, customConfig string) string {
  function GetSessionConversation (line 203) | func GetSessionConversation(c *gin.Context) (conversation *model.Convers...
  function Relay (line 224) | func Relay(c *gin.Context) {
  function handleChatRequest (line 254) | func handleChatRequest(c *gin.Context, body []byte, agent *model.Agent, ...
  function processChatRequest (line 265) | func processChatRequest(c *gin.Context, chatRequest *ChatRequest, agent ...
  function relayHelper (line 353) | func relayHelper(c *gin.Context, relayMode int) *relay_model.ErrorWithSt...
  function processChannelRelayError (line 372) | func processChannelRelayError(ctx context.Context, userId int, channelId...
  function getAndValidateTextRequest (line 381) | func getAndValidateTextRequest(c *gin.Context, relayMode int) (*relay_mo...
  function getMappedModelName (line 400) | func getMappedModelName(modelName string, mapping map[string]string) (st...
  function setSystemPrompt (line 411) | func setSystemPrompt(ctx context.Context, request *relay_model.GeneralOp...
  function createInitialMessage (line 432) | func createInitialMessage(c *gin.Context, agent *model.Agent, user_id in...
  function sendSaveMessageEvent (line 470) | func sendSaveMessageEvent(c *gin.Context, requestId, modelName string, m...
  function getPromptTokens (line 503) | func getPromptTokens(textRequest *relay_model.GeneralOpenAIRequest, rela...
  function getRequestBody (line 515) | func getRequestBody(c *gin.Context, meta *meta.Meta, textRequest *relay_...
  function RelayTextHelper (line 563) | func RelayTextHelper(c *gin.Context) *relay_model.ErrorWithStatusCode {
  function isErrorHappened (line 705) | func isErrorHappened(meta *meta.Meta, resp *http.Response) bool {
  function addAgentPrompt (line 737) | func addAgentPrompt(ctx context.Context, textRequest *relay_model.Genera...
  function postConsumeQuota (line 764) | func postConsumeQuota(c *gin.Context, agent *model.Agent, user_id int64,...
  function preConsumeQuota (line 855) | func preConsumeQuota(ctx context.Context, textRequest *relay_model.Gener...
  function getPreConsumedQuota (line 860) | func getPreConsumedQuota(textRequest *relay_model.GeneralOpenAIRequest, ...
  function failUpdateMessage (line 869) | func failUpdateMessage(c *gin.Context, agent *model.Agent, messageID int...
  function executeWorkflow (line 899) | func executeWorkflow(c *gin.Context, workflowRequest *WorkflowRunRequest...
  function executeWorkflowDirect (line 952) | func executeWorkflowDirect(c *gin.Context, workflowRequest *WorkflowRunR...
  function handleWorkflowError (line 979) | func handleWorkflowError(resp *http.Response, workflowType string) error {
  function executeCozeWorkflow (line 1029) | func executeCozeWorkflow(c *gin.Context, workflowRequest *WorkflowRunReq...
  function executeDifyWorkflow (line 1122) | func executeDifyWorkflow(c *gin.Context, workflowRequest *WorkflowRunReq...
  function executeFastGPTWorkflow (line 1208) | func executeFastGPTWorkflow(c *gin.Context, workflowRequest *WorkflowRun...
  function executeAI53Workflow (line 1293) | func executeAI53Workflow(c *gin.Context, workflowRequest *WorkflowRunReq...
  function saveWorkflowMessage (line 1378) | func saveWorkflowMessage(c *gin.Context, workflowRequest *WorkflowRunReq...
  function updateConversationLastMessage (line 1481) | func updateConversationLastMessage(eid, conversationId, userId int64, qu...
  function calculateWorkflowTokens (line 1508) | func calculateWorkflowTokens(workflowRequest *WorkflowRunRequest, respon...
  function executeN8nWorkflow (line 1548) | func executeN8nWorkflow(c *gin.Context, workflowRequest *WorkflowRunRequ...
  function getWorkflowChannelType (line 1639) | func getWorkflowChannelType(response *custom.WorkflowResponseData) int {
  function GetByContext (line 1651) | func GetByContext(c *gin.Context) *relay_meta.Meta {

FILE: api/controller/rerank.go
  type RerankRequest (line 26) | type RerankRequest struct
  type RerankResponse (line 35) | type RerankResponse struct
  type RerankResult (line 43) | type RerankResult struct
  type RerankDocument (line 51) | type RerankDocument struct
  type RerankUsage (line 56) | type RerankUsage struct
  function Rerank (line 72) | func Rerank(c *gin.Context) {
  function validateRerankRequest (line 232) | func validateRerankRequest(req *RerankRequest) error {
  function getChannelTypeByModel (line 255) | func getChannelTypeByModel(modelName string) int {
  function executeRerankRequest (line 270) | func executeRerankRequest(c *gin.Context, req *RerankRequest, channel *m...
  function executeAliRerankRequest (line 297) | func executeAliRerankRequest(c *gin.Context, req *RerankRequest, meta *m...
  function convertBailianRerankResponse (line 347) | func convertBailianRerankResponse(bailianResp map[string]interface{}, re...
  function calculateRerankUsage (line 406) | func calculateRerankUsage(req *RerankRequest, resultCount int) *relay_mo...
  function recordRerankUsage (line 431) | func recordRerankUsage(ctx context.Context, userId, eid int64, req *Rera...
  function maskAPIKey (line 492) | func maskAPIKey(apiKey string) string {
  function truncateString (line 500) | func truncateString(s string, maxLen int) string {

FILE: api/controller/response_handler.go
  function GetResponseContent (line 15) | func GetResponseContent(c *gin.Context, isStream bool, resp *http.Respon...
  type StreamResponseCollector (line 80) | type StreamResponseCollector struct
    method Collect (line 92) | func (c *StreamResponseCollector) Collect(chunk []byte) {
    method GetContent (line 127) | func (c *StreamResponseCollector) GetContent() (string, string) {
  function NewStreamResponseCollector (line 85) | func NewStreamResponseCollector() *StreamResponseCollector {
  type StreamResponseInterceptor (line 132) | type StreamResponseInterceptor struct
    method Write (line 138) | func (w *StreamResponseInterceptor) Write(b []byte) (int, error) {
    method WriteHeader (line 146) | func (w *StreamResponseInterceptor) WriteHeader(statusCode int) {
    method Flush (line 151) | func (w *StreamResponseInterceptor) Flush() {
  function SetupStreamInterceptor (line 158) | func SetupStreamInterceptor(c *gin.Context) *StreamResponseCollector {

FILE: api/controller/setting.go
  type SettingRequest (line 13) | type SettingRequest struct
  type UpdateDefaultLinksRequest (line 18) | type UpdateDefaultLinksRequest struct
  type LinkItem (line 22) | type LinkItem struct
  function CreateSetting (line 36) | func CreateSetting(c *gin.Context) {
  function GetSetting (line 65) | func GetSetting(c *gin.Context) {
  function UpdateSetting (line 87) | func UpdateSetting(c *gin.Context) {
  function DeleteSetting (line 122) | func DeleteSetting(c *gin.Context) {
  function GetSettings (line 146) | func GetSettings(c *gin.Context) {
  function GetSettingsByGroup (line 164) | func GetSettingsByGroup(c *gin.Context) {
  function GetSettingByKey (line 183) | func GetSettingByKey(c *gin.Context) {
  function BatchUpdateDefaultPromptLinks (line 212) | func BatchUpdateDefaultPromptLinks(c *gin.Context) {
  function GetDefaultPromptLinks (line 284) | func GetDefaultPromptLinks(c *gin.Context) {

FILE: api/controller/share.go
  type CreateShareRequest (line 12) | type CreateShareRequest struct
  type CreateShareResponse (line 18) | type CreateShareResponse struct
  function CreateShare (line 34) | func CreateShare(c *gin.Context) {
  type GetShareResponse (line 90) | type GetShareResponse struct
  function GetShare (line 120) | func GetShare(c *gin.Context) {

FILE: api/controller/status.go
  type HealthData (line 11) | type HealthData struct
  function HealthCheck (line 23) | func HealthCheck(c *gin.Context) {
  type CodeInfo (line 30) | type CodeInfo struct
  function GetAllResponseCodes (line 42) | func GetAllResponseCodes(c *gin.Context) {

FILE: api/controller/subscription.go
  type BatchSubscriptionRelation (line 17) | type BatchSubscriptionRelation struct
  type BatchSubscriptionItem (line 42) | type BatchSubscriptionItem struct
  type BatchSubscriptionRequest (line 74) | type BatchSubscriptionRequest struct
  type GetSubscriptionSettingsRequest (line 80) | type GetSubscriptionSettingsRequest struct
  type SubscriptionSettingsResponse (line 86) | type SubscriptionSettingsResponse struct
  function BatchSubscriptionOperation (line 100) | func BatchSubscriptionOperation(c *gin.Context) {
  function GetSubscriptionList (line 346) | func GetSubscriptionList(c *gin.Context) {

FILE: api/controller/sync_organization.go
  function SyncOrganization (line 23) | func SyncOrganization(c *gin.Context) {
  function GetSyncProgress (line 40) | func GetSyncProgress(c *gin.Context) {
  function GetAllSyncProgress (line 54) | func GetAllSyncProgress(c *gin.Context) {
  function GetSyncProgressByFrom (line 70) | func GetSyncProgressByFrom(c *gin.Context) {

FILE: api/controller/system_log.go
  function GetModules (line 20) | func GetModules(c *gin.Context) {
  function GetActions (line 34) | func GetActions(c *gin.Context) {
  type CreateLogRequest (line 40) | type CreateLogRequest struct
  type GetSystemLogsRequest (line 46) | type GetSystemLogsRequest struct
  type SystemLogsResponse (line 56) | type SystemLogsResponse struct
  function GetSystemLogs (line 78) | func GetSystemLogs(c *gin.Context) {
  function CreateSystemLogs (line 116) | func CreateSystemLogs(c *gin.Context) {

FILE: api/controller/tencent.go
  function GetTencentAllApps (line 29) | func GetTencentAllApps(c *gin.Context) {
  function GetTencentAppDetail (line 95) | func GetTencentAppDetail(c *gin.Context) {
  function UpdateTencentChannel (line 141) | func UpdateTencentChannel(client *tencent_sdk.Client, provider model.Pro...
  function parseTencentCredentials (line 193) | func parseTencentCredentials(configs string) (secretId, secretKey, regio...
  function initTencentClient (line 228) | func initTencentClient(secretId, secretKey, region string) (*tencent_sdk...

FILE: api/controller/upload.go
  function Upload (line 26) | func Upload(c *gin.Context) {
  function PreviewFile (line 122) | func PreviewFile(c *gin.Context) {

FILE: api/controller/user.go
  type LoginRequest (line 24) | type LoginRequest struct
  type LoginResponse (line 29) | type LoginResponse struct
  type PasswordRegisterUserRequest (line 34) | type PasswordRegisterUserRequest struct
  type EnterpriseAddUserRequest (line 41) | type EnterpriseAddUserRequest struct
  type EnterpriseUserGetRequest (line 52) | type EnterpriseUserGetRequest struct
  type EnterpriseUsersResponse (line 63) | type EnterpriseUsersResponse struct
  function Login (line 77) | func Login(c *gin.Context) {
  type SmsLoginRequest (line 141) | type SmsLoginRequest struct
  type SmsLoginResponse (line 146) | type SmsLoginResponse struct
  function SmsLogin (line 160) | func SmsLogin(c *gin.Context) {
  function PasswordRegister (line 215) | func PasswordRegister(c *gin.Context) {
  function EnterpriseAddUser (line 322) | func EnterpriseAddUser(c *gin.Context) {
  function EnterpriseUsers (line 374) | func EnterpriseUsers(c *gin.Context) {
  function DeleteEnterpriseUser (line 463) | func DeleteEnterpriseUser(c *gin.Context) {
  function UpdateEnterpriseUser (line 517) | func UpdateEnterpriseUser(c *gin.Context) {
  type GetCurrentUserResponse (line 575) | type GetCurrentUserResponse struct
  function GetCurrentUser (line 588) | func GetCurrentUser(c *gin.Context) {
  type UpdatePasswordRequest (line 616) | type UpdatePasswordRequest struct
  function UpdateUserPassword (line 630) | func UpdateUserPassword(c *gin.Context) {
  type UpdateCurrentUserRequest (line 659) | type UpdateCurrentUserRequest struct
  function UpdateCurrentUser (line 673) | func UpdateCurrentUser(c *gin.Context) {
  type CheckAccountRequest (line 709) | type CheckAccountRequest struct
  type CheckAccountResponse (line 714) | type CheckAccountResponse struct
  function CheckAccountExists (line 729) | func CheckAccountExists(c *gin.Context) {
  type BatchSetAdminRequest (line 756) | type BatchSetAdminRequest struct
  type BatchSetAdminResponse (line 761) | type BatchSetAdminResponse struct
  function SetUserAsAdmin (line 780) | func SetUserAsAdmin(c *gin.Context) {
  function UnsetUserAsAdmin (line 874) | func UnsetUserAsAdmin(c *gin.Context) {
  type BatchAddInternalUserRequest (line 963) | type BatchAddInternalUserRequest struct
  type InternalUserInfo (line 968) | type InternalUserInfo struct
  type BatchInternalUserInfo (line 977) | type BatchInternalUserInfo struct
  type BatchAddInternalUserResponse (line 985) | type BatchAddInternalUserResponse struct
  function BatchAddInternalUsers (line 1003) | func BatchAddInternalUsers(c *gin.Context) {
  type RegisterUserToInternalRequest (line 1063) | type RegisterUserToInternalRequest struct
  function RegisterUserToInternal (line 1080) | func RegisterUserToInternal(c *gin.Context) {
  type InternalUserRequest (line 1121) | type InternalUserRequest struct
  type InternalUserResponse (line 1132) | type InternalUserResponse struct
  function GetInternalUsers (line 1156) | func GetInternalUsers(c *gin.Context) {
  function UpdateUserStatus (line 1217) | func UpdateUserStatus(c *gin.Context) {
  type UpdateUserStatusRequest (line 1278) | type UpdateUserStatusRequest struct
  type UpdateInternalUserRequest (line 1283) | type UpdateInternalUserRequest struct
  function UpdateInternalUser (line 1302) | func UpdateInternalUser(c *gin.Context) {
  type ResetPasswordRequest (line 1492) | type ResetPasswordRequest struct
  function Logout (line 1509) | func Logout(c *gin.Context) {
  function ResetPassword (line 1570) | func ResetPassword(c *gin.Context) {
  type UpdateUserMobileRequest (line 1668) | type UpdateUserMobileRequest struct
  function UpdateUserMobile (line 1688) | func UpdateUserMobile(c *gin.Context) {
  function GetOrganizationUserList (line 1768) | func GetOrganizationUserList(c *gin.Context) {
  function SetUserToDefaultSubscription (line 1816) | func SetUserToDefaultSubscription(c *gin.Context) {
  function IsInit (line 1902) | func IsInit(c *gin.Context) {

FILE: api/main.go
  function main (line 21) | func main() {

FILE: api/middleware/auth.go
  function UserTokenAuth (line 14) | func UserTokenAuth(role int64) func(c *gin.Context) {
  function HandleTokenAuth (line 47) | func HandleTokenAuth(token string, role int64) (user *model.User, err er...

FILE: api/middleware/cors.go
  function CORS (line 8) | func CORS() gin.HandlerFunc {

FILE: api/middleware/distributor.go
  type ModelRequest (line 12) | type ModelRequest struct
  function SetupContextForSelectedChannel (line 16) | func SetupContextForSelectedChannel(c *gin.Context, channel *model.Chann...

FILE: api/middleware/logger.go
  function Logger (line 11) | func Logger() gin.HandlerFunc {

FILE: api/middleware/relay_auth.go
  function RelayTokenAuth (line 21) | func RelayTokenAuth() func(c *gin.Context) {

FILE: api/model/agent.go
  type Agent (line 9) | type Agent struct
    method Create (line 38) | func (agent *Agent) Create() error {
    method Update (line 57) | func (agent *Agent) Update() error {
    method Delete (line 62) | func (agent *Agent) Delete() error {
    method GetUserGroupIds (line 123) | func (a *Agent) GetUserGroupIds() ([]int64, error) {
    method LoadUserGroupIds (line 144) | func (a *Agent) LoadUserGroupIds() error {
    method LoadConversationCount (line 153) | func (a *Agent) LoadConversationCount() error {
    method GetProviderID (line 175) | func (a *Agent) GetProviderID() int64 {
  constant AgentTypeApp (line 34) | AgentTypeApp      = 0
  constant AgentTypeWorkflow (line 35) | AgentTypeWorkflow = 1
  function GetAgentByID (line 67) | func GetAgentByID(eid int64, agentID int64) (*Agent, error) {
  function GetAgentListWithIDs (line 76) | func GetAgentListWithIDs(eid int64, keyword string, group_id int64, perm...
  function GetAvailableAgentList (line 108) | func GetAvailableAgentList(eid int64, agent_types []int, offset int, lim...
  function UpdateAgentStatus (line 163) | func UpdateAgentStatus(eid, agentID int64, enable *bool) error {
  function GetAgentCountByEID (line 169) | func GetAgentCountByEID(eid int64) (int64, error) {

FILE: api/model/ai_link.go
  type AILink (line 8) | type AILink struct
    method CheckGroup (line 25) | func (aiLink *AILink) CheckGroup() error {
    method LoadUserGroupIds (line 67) | func (aiLink *AILink) LoadUserGroupIds() error {
    method LoadHasSharedAccount (line 178) | func (aiLink *AILink) LoadHasSharedAccount() {
  function CreateAILink (line 36) | func CreateAILink(aiLink *AILink) error {
  function DeleteAILinkByID (line 44) | func DeleteAILinkByID(id int64) error {
  function UpdateAILink (line 48) | func UpdateAILink(aiLink *AILink) error {
  function GetAILinkByID (line 58) | func GetAILinkByID(id int64) (*AILink, error) {
  function GetAILinksByEidAndGroupId (line 78) | func GetAILinksByEidAndGroupId(eid int64, groupID int64) ([]AILink, erro...
  function GetAILinksGroupedBySort (line 96) | func GetAILinksGroupedBySort(eid int64) ([]AILink, error) {
  function GetAILinksByEidAndGroupIdWithKeyword (line 128) | func GetAILinksByEidAndGroupIdWithKeyword(eid int64, groupID int64, keyw...
  function GetAILinksGroupedBySortWithKeyword (line 146) | func GetAILinksGroupedBySortWithKeyword(eid int64, keyword string) ([]AI...

FILE: api/model/base.go
  type BaseModel (line 9) | type BaseModel struct
    method BeforeCreate (line 14) | func (m *BaseModel) BeforeCreate(tx *gorm.DB) (err error) {
    method BeforeUpdate (line 23) | func (m *BaseModel) BeforeUpdate(tx *gorm.DB) (err error) {

FILE: api/model/cache.go
  constant LockOrganizationKeyPre (line 4) | LockOrganizationKeyPre = "lock_enterprise_organization_sync"

FILE: api/model/channel.go
  constant ChannelStatusUnknown (line 16) | ChannelStatusUnknown          = 0
  constant ChannelStatusEnabled (line 17) | ChannelStatusEnabled          = 1
  constant ChannelStatusManuallyDisabled (line 18) | ChannelStatusManuallyDisabled = 2
  constant ChannelStatusAutoDisabled (line 19) | ChannelStatusAutoDisabled     = 3
  constant ChannelApiDify (line 23) | ChannelApiDify       = 1001
  constant ChannelApi53AI (line 24) | ChannelApi53AI       = 1002
  constant ChannelApiBailian (line 25) | ChannelApiBailian    = 1003
  constant ChannelApiVolcengine (line 26) | ChannelApiVolcengine = 1004
  constant ChannelApiAppBuilder (line 27) | ChannelApiAppBuilder = 1005
  constant ChannelApiYuanqi (line 28) | ChannelApiYuanqi     = 1006
  constant ChannelApiTypeFastGpt (line 30) | ChannelApiTypeFastGpt    = 1007
  constant ChannelApiTypeMaxKB (line 31) | ChannelApiTypeMaxKB      = 1008
  constant ChannelApiTypeN8n (line 32) | ChannelApiTypeN8n        = 1009
  constant ChannelApiTypeCozeStudio (line 33) | ChannelApiTypeCozeStudio = 1010
  constant ChannelApiTypeTencent (line 35) | ChannelApiTypeTencent = 1011
  constant ModelTypeLLM (line 40) | ModelTypeLLM       = 1
  constant ModelTypeEmbedding (line 41) | ModelTypeEmbedding = 2
  constant ModelTypeRerank (line 42) | ModelTypeRerank    = 3
  function IsValidModelType (line 46) | func IsValidModelType(t int) bool {
  type ChannelDescription (line 55) | type ChannelDescription struct
  function GetChannelDescription (line 80) | func GetChannelDescription(key string) string {
  function GetAllChannelDescriptions (line 88) | func GetAllChannelDescriptions() []ChannelDescription {
  type Channel (line 96) | type Channel struct
    method GetBaseURL (line 179) | func (channel *Channel) GetBaseURL() string {
    method LoadConfig (line 186) | func (channel *Channel) LoadConfig() (oneapi_model.ChannelConfig, erro...
    method GetModelMapping (line 198) | func (channel *Channel) GetModelMapping() map[string]string {
    method UpdateResponseTime (line 211) | func (channel *Channel) UpdateResponseTime(responseTime int64) {
    method GetAddModelString (line 332) | func (channel *Channel) GetAddModelString(model string) string {
  function CreateChannel (line 120) | func CreateChannel(channel *Channel) error {
  function GetChannelByID (line 124) | func GetChannelByID(id int64) (*Channel, error) {
  function UpdateChannel (line 130) | func UpdateChannel(channel *Channel) error {
  function DeleteChannelByID (line 134) | func DeleteChannelByID(id int64) error {
  function GetChannelsByEid (line 138) | func GetChannelsByEid(eid int64) ([]Channel, error) {
  function GetChannelsByEidAndParams (line 147) | func GetChannelsByEidAndParams(eid int64, providerId int64, channelTypes...
  function GetFirstChannelByEidAndProviderId (line 173) | func GetFirstChannelByEidAndProviderId(eid int64, providerId int64) (*Ch...
  function GetRandomChannel (line 221) | func GetRandomChannel(eid int64, channelType int, modelName string) (*Ch...
  function GetApiType (line 260) | func GetApiType(channelType int) int {
  function GetFirstChannelByEidAndProviderType (line 274) | func GetFirstChannelByEidAndProviderType(eid int64, providerType int64, ...
  function GetFirstAvailableChannelByEidAndProviderType (line 286) | func GetFirstAvailableChannelByEidAndProviderType(eid int64, providerTyp...
  function StandardizationBotId (line 303) | func StandardizationBotId(botId string) string {
  function StandardizationBotIdByChannelType (line 310) | func StandardizationBotIdByChannelType(botId string, channelType int) st...
  function ProcessModelNames (line 318) | func ProcessModelNames(models string, channelType int) string {

FILE: api/model/channel_file_mapping.go
  type ChannelFileMapping (line 10) | type ChannelFileMapping struct
  type ObjectStringContent (line 22) | type ObjectStringContent struct
    method GetUploadFile (line 48) | func (obj *ObjectStringContent) GetUploadFile() *UploadFile {
  type ContentPart (line 27) | type ContentPart struct
  function GetChannelFileMapping (line 32) | func GetChannelFileMapping(eid int64, channelId int64, fileId int64) *Ch...
  function CreateChannelFileMapping (line 40) | func CreateChannelFileMapping(channelFileMapping *ChannelFileMapping) er...
  function UpdateChannelFileMapping (line 44) | func UpdateChannelFileMapping(channelFileMapping *ChannelFileMapping) er...

FILE: api/model/conversation.go
  type Conversation (line 3) | type Conversation struct
    method LoadAgent (line 112) | func (c *Conversation) LoadAgent() error {
    method LoadUser (line 121) | func (c *Conversation) LoadUser() error {
  constant ConversationStatusActive (line 23) | ConversationStatusActive   = 1
  constant ConversationStatusArchived (line 24) | ConversationStatusArchived = 2
  constant ConversationStatusDeleted (line 25) | ConversationStatusDeleted  = 0
  function CreateConversation (line 29) | func CreateConversation(conversation *Conversation) error {
  function GetConversationByID (line 34) | func GetConversationByID(eid int64, user_id int64, conversation_id int64...
  function AdminGetConversationByID (line 44) | func AdminGetConversationByID(eid int64, conversation_id int64) (*Conver...
  function GetConversationsByUserID (line 54) | func GetConversationsByUserID(eid int64, userID int64) ([]*Conversation,...
  function GetUserConversationsWithFilter (line 67) | func GetUserConversationsWithFilter(eid, userID int64, keyword string, c...
  function GetMessageCountByConversationID (line 95) | func GetMessageCountByConversationID(conversationID int64) (int, error) {
  function GetFirstMessageByConversationID (line 104) | func GetFirstMessageByConversationID(conversationID int64) (string, erro...
  function GetConversationsByAgentID (line 131) | func GetConversationsByAgentID(eid int64, agentID int64) ([]*Conversatio...
  function GetAgentConversationsWithFilter (line 141) | func GetAgentConversationsWithFilter(eid, agentID int64, keyword string,...
  function UpdateConversation (line 169) | func UpdateConversation(conversation *Conversation) error {
  function DeleteConversation (line 174) | func DeleteConversation(eid int64, conversation_id int64) error {
  function GetConversationByIdAndUserId (line 178) | func GetConversationByIdAndUserId(eid int64, conversation_id int64, user...

FILE: api/model/department.go
  constant DepartmentFromBackend (line 13) | DepartmentFromBackend   = 0
  constant DepartmentFromWecom (line 14) | DepartmentFromWecom     = 1
  constant DepartmentFromDingtalk (line 15) | DepartmentFromDingtalk  = 2
  constant DepartmentStatusNormal (line 20) | DepartmentStatusNormal   = 0
  constant DepartmentStatusDisabled (line 21) | DepartmentStatusDisabled = 1
  constant DepartmentStatusDeleted (line 22) | DepartmentStatusDeleted  = 2
  constant DepartmentSortDefault (line 27) | DepartmentSortDefault = 0
  constant DepartmentSortTop (line 28) | DepartmentSortTop     = -1
  type Department (line 32) | type Department struct
    method TableName (line 45) | func (Department) TableName() string {
  function InitDepartmentTable (line 50) | func InitDepartmentTable() error {
  function CreateDepartment (line 78) | func CreateDepartment(dept *Department) error {
  function validateDepartment (line 123) | func validateDepartment(dept *Department) error {
  function GetDepartmentByID (line 137) | func GetDepartmentByID(eid int64, did int64) (*Department, error) {
  function GetDepartmentsByEID (line 150) | func GetDepartmentsByEID(eid int64, from int) ([]*Department, error) {
  function GetChildDepartments (line 160) | func GetChildDepartments(eid int64, pdid int64) ([]*Department, error) {
  function BatchGetDepartmentsByIDs (line 170) | func BatchGetDepartmentsByIDs(eid int64, dids []int64) ([]*Department, e...
  function UpdateDepartment (line 184) | func UpdateDepartment(dept *Department) error {
  function handleParentChange (line 218) | func handleParentChange(dept *Department, existingDept *Department) error {
  function isChildDepartment (line 252) | func isChildDepartment(path string, did int64) bool {
  function updateChildDepartmentPaths (line 261) | func updateChildDepartmentPaths(eid int64, did int64, oldPath string, ne...
  function updateSingleChildPath (line 312) | func updateSingleChildPath(childPath, oldPath, newPath string, did int64...
  function DeleteDepartment (line 331) | func DeleteDepartment(eid int64, did int64, deleteChildren bool) error {
  function BatchDeleteDepartments (line 393) | func BatchDeleteDepartments(eid int64, dids []int64) error {
  function SearchDepartments (line 418) | func SearchDepartments(eid int64, keyword string, limit int) ([]*Departm...
  function GetDepartmentTree (line 440) | func GetDepartmentTree(eid int64, from int) ([]*DepartmentNode, error) {
  type DepartmentNode (line 484) | type DepartmentNode struct
  function buildDepartmentTree (line 490) | func buildDepartmentTree(node *DepartmentNode, allDepts []*Department, d...
  function sortDepartmentNodes (line 507) | func sortDepartmentNodes(nodes []*DepartmentNode) {

FILE: api/model/dingtalk_corp.go
  type DingtalkCorp (line 10) | type DingtalkCorp struct
    method GetAuthUserInfo (line 86) | func (d *DingtalkCorp) GetAuthUserInfo() *DingtalkAuthUserInfo {
    method Update (line 94) | func (d *DingtalkCorp) Update() error {
    method Delete (line 98) | func (d *DingtalkCorp) Delete() error {
    method GetAuthCorpInfo (line 102) | func (d *DingtalkCorp) GetAuthCorpInfo() *DingtalkAuthCorpInfo {
  type DingtalkAuthCorpInfo (line 31) | type DingtalkAuthCorpInfo struct
  type DingtalkAuthUserInfo (line 40) | type DingtalkAuthUserInfo struct
  type AuthInfo (line 44) | type AuthInfo struct
  function GetDingtalkCorp (line 55) | func GetDingtalkCorp(suiteId string, corpId string) (*DingtalkCorp, erro...
  function CreateDingtalkCorp (line 70) | func CreateDingtalkCorp(corp *DingtalkCorp) error {
  function UpdateDingtalkCorp (line 78) | func UpdateDingtalkCorp(corp *DingtalkCorp) error {

FILE: api/model/dingtalk_suite.go
  type DingtalkSuite (line 7) | type DingtalkSuite struct
    method Create (line 31) | func (suite *DingtalkSuite) Create() error {
    method Update (line 45) | func (suite *DingtalkSuite) Update() error {
    method Delete (line 53) | func (suite *DingtalkSuite) Delete() error {
  function GetDingtalkSuite (line 22) | func GetDingtalkSuite(suiteID string) (*DingtalkSuite, error) {
  function GetDingtalkSuitesByCorpID (line 61) | func GetDingtalkSuitesByCorpID(corpID string) ([]*DingtalkSuite, error) {

FILE: api/model/enterprise.go
  type Enterprise (line 13) | type Enterprise struct
    method Update (line 107) | func (enterprise *Enterprise) Update() error {
    method Delete (line 115) | func (enterprise *Enterprise) Delete() error {
    method PartialUpdateEnterprise (line 119) | func (enterprise *Enterprise) PartialUpdateEnterprise(updateData map[s...
    method LoadWecomCorpInfo (line 518) | func (e *Enterprise) LoadWecomCorpInfo(suiteID string, loadType int) e...
    method LoadDingtalkCorpInfo (line 539) | func (e *Enterprise) LoadDingtalkCorpInfo(suiteID string, loadType int...
  type WecomInstallInfo (line 37) | type WecomInstallInfo struct
  type DingtalkInstallInfo (line 42) | type DingtalkInstallInfo struct
  constant EnterpriseStatusNormal (line 48) | EnterpriseStatusNormal       = 1
  constant EnterpriseStatusDisabled (line 49) | EnterpriseStatusDisabled     = 2
  constant EnterpriseStatusNotActivated (line 50) | EnterpriseStatusNotActivated = 0
  constant EnterpriseTypeIndependent (line 52) | EnterpriseTypeIndependent = "independent"
  constant EnterpriseTypeEnterprise (line 53) | EnterpriseTypeEnterprise  = "enterprise"
  constant EnterpriseTypeIndustry (line 54) | EnterpriseTypeIndustry    = "industry"
  type EnterpriseTypeDescription (line 57) | type EnterpriseTypeDescription struct
  function GetEnterpriseTypeDescription (line 68) | func GetEnterpriseTypeDescription(key string) string {
  function GetAllEnterpriseTypeDescriptions (line 75) | func GetAllEnterpriseTypeDescriptions() []EnterpriseTypeDescription {
  function GetEnterpriseModel (line 83) | func GetEnterpriseModel(id int64) (*Enterprise, error) {
  function GetEnterpriseByID (line 94) | func GetEnterpriseByID(eid int64) (*Enterprise, error) {
  function CreateEnterpriseModel (line 103) | func CreateEnterpriseModel(enterprise *Enterprise) error {
  function GetEnterpriseName (line 155) | func GetEnterpriseName(eid int64) (string, error) {
  function InitializeSystem (line 172) | func InitializeSystem() error {
  function initAILinkData (line 443) | func initAILinkData(tx *gorm.DB, eid int64) error {
  function GetEnterpriseByWecomCorpID (line 506) | func GetEnterpriseByWecomCorpID(wecomCorpID string) (*Enterprise, error) {
  function GetEnterpriseByDingtalkCorpID (line 561) | func GetEnterpriseByDingtalkCorpID(dingtalkCorpID string) (*Enterprise, ...

FILE: api/model/enterprise_config.go
  type EnterpriseConfig (line 7) | type EnterpriseConfig struct
  constant EnterpriseConfigTypeSMTP (line 19) | EnterpriseConfigTypeSMTP   = "smtp"
  constant EnterpriseConfigTypeMobile (line 20) | EnterpriseConfigTypeMobile = "mobile"
  constant EnterpriseConfigTypeSSO (line 21) | EnterpriseConfigTypeSSO    = "auth_sso"
  function GetEnterpriseConfigDefaultContent (line 31) | func GetEnterpriseConfigDefaultContent(configType string) (string, error) {

FILE: api/model/enterprise_sync.go
  function FindEnterpriseUserByAccount (line 11) | func FindEnterpriseUserByAccount(account string) (*User, error) {
  function SetRelatedID (line 37) | func SetRelatedID(enterpriseUserID int64, platformUserID int64) error {
  function SetRelatedIDByEidAccount (line 46) | func SetRelatedIDByEidAccount(eid int64, account string, platformUserID ...

FILE: api/model/group.go
  type Group (line 4) | type Group struct
  constant USER_FREE_GROUP_NAME (line 17) | USER_FREE_GROUP_NAME = "免费版"
  function GetGroupWithAgents (line 21) | func GetGroupWithAgents(groupId int64, enable bool) (*Group, error) {
  function GetGroupsWithAgents (line 49) | func GetGroupsWithAgents(eid int64, groupType int64, offset, limit int) ...
  constant USER_GROUP_TYPE (line 95) | USER_GROUP_TYPE          = 1
  constant AI_LINKS_TYPE (line 96) | AI_LINKS_TYPE            = 2
  constant AGENT_TYPE (line 97) | AGENT_TYPE               = 3
  constant INTERNAL_USER_GROUP_TYPE (line 98) | INTERNAL_USER_GROUP_TYPE = 4
  constant SYSTEM_PROMPT_TYPE (line 99) | SYSTEM_PROMPT_TYPE       = 5
  constant PERSONAL_PROMPT_TYPE (line 100) | PERSONAL_PROMPT_TYPE     = 6
  function CreateGroup (line 103) | func CreateGroup(group *Group) error {
  function DeleteGroupByID (line 107) | func DeleteGroupByID(groupID int64) error {
  function UpdateGroup (line 111) | func UpdateGroup(group *Group) error {
  function GetGroupByID (line 117) | func GetGroupByID(groupID int64) (*Group, error) {
  function BatchSubmitGroups (line 128) | func BatchSubmitGroups(groupType int64, eid int64, groups []Group) error {
  function GetGroupsByEid (line 168) | func GetGroupsByEid(eid int64, groupType int64) ([]Group, error) {
  function GetFirstGroupByEid (line 190) | func GetFirstGroupByEid(eid int64, groupType int64) (Group, error) {
  function ExistsGroupByIDAndType (line 198) | func ExistsGroupByIDAndType(Eid int64, groupId int64, groupType int64) (...
  type AILinkInfo (line 208) | type AILinkInfo struct
  type GroupInfo (line 217) | type GroupInfo struct
  function GetDefaultGroupData (line 225) | func GetDefaultGroupData() []GroupInfo {
  function GetUserFreeGroup (line 282) | func GetUserFreeGroup(eid int64) (*Group, error) {

FILE: api/model/like.go
  type Like (line 10) | type Like struct
    method TableName (line 31) | func (Like) TableName() string {
    method Validate (line 36) | func (l *Like) Validate() error {
    method Create (line 50) | func (l *Like) Create() error {
    method UpdateStatus (line 69) | func (l *Like) UpdateStatus(newStatus int) error {
    method Delete (line 81) | func (l *Like) Delete() error {
    method HardDelete (line 86) | func (l *Like) HardDelete() error {
    method Exists (line 91) | func (l *Like) Exists() (bool, error) {
    method ToggleLike (line 135) | func (l *Like) ToggleLike() error {
  constant LikeStatusActive (line 21) | LikeStatusActive = 1
  constant LikeStatusCancel (line 22) | LikeStatusCancel = 0
  constant LikeTypePrompt (line 27) | LikeTypePrompt = "prompt"
  function GetLikeByID (line 100) | func GetLikeByID(likeID int64) (*Like, error) {
  function GetUserLikes (line 113) | func GetUserLikes(userID int64, likeType string) ([]Like, error) {
  function CountLikesByObject (line 126) | func CountLikesByObject(objectType string, objectID int64) (int64, error) {
  function GetLikeByUserObject (line 159) | func GetLikeByUserObject(userID int64, objectType string, objectID int64...

FILE: api/model/main.go
  function InitDB (line 20) | func InitDB() {
  function GetDbConn (line 44) | func GetDbConn() (*gorm.DB, error) {
  function openSQLite (line 59) | func openSQLite() (*gorm.DB, error) {
  function openMySQL (line 68) | func openMySQL(dsn string) (*gorm.DB, error) {
  function setDBConns (line 76) | func setDBConns(db *gorm.DB) *sql.DB {
  function migrateDB (line 93) | func migrateDB() error {

FILE: api/model/member_binding.go
  constant MemberBindingSourceNone (line 13) | MemberBindingSourceNone   = 0
  constant MemberBindingSourceWeChat (line 14) | MemberBindingSourceWeChat = 1
  constant MemberBindingStatusInactive (line 19) | MemberBindingStatusInactive = 0
  constant MemberBindingStatusActive (line 20) | MemberBindingStatusActive   = 1
  constant MemberBindingStatusDisabled (line 21) | MemberBindingStatusDisabled = 2
  constant MemberBindingStatusExpired (line 22) | MemberBindingStatusExpired  = 3
  type MemberBinding (line 26) | type MemberBinding struct
    method TableName (line 38) | func (MemberBinding) TableName() string {
  function InitMemberBindingTable (line 43) | func InitMemberBindingTable() error {
  function CreateMemberBinding (line 59) | func CreateMemberBinding(binding *MemberBinding) error {
  function validateMemberBinding (line 70) | func validateMemberBinding(binding *MemberBinding) error {
  function GetMemberBindingByID (line 87) | func GetMemberBindingByID(id int64) (*MemberBinding, error) {
  function GetMemberBindingByMID (line 100) | func GetMemberBindingByMID(mid int64) ([]*MemberBinding, error) {
  function GetMemberBindingByMidAndFrom (line 109) | func GetMemberBindingByMidAndFrom(mid int64, from int) (*MemberBinding, ...
  function GetMemberBindingByDepartmentFromBackend (line 121) | func GetMemberBindingByDepartmentFromBackend(mid int64, tx *gorm.DB) (*M...
  function GetMemberBindingByBindValue (line 152) | func GetMemberBindingByBindValue(eid int64, bindValue string, from int) ...
  function GetMemberBindings (line 165) | func GetMemberBindings(eid int64, from int, status int, offset, limit in...
  function UpdateMemberBinding (line 198) | func UpdateMemberBinding(binding *MemberBinding) error {
  function DeleteMemberBinding (line 222) | func DeleteMemberBinding(id int64) error {
  function BatchDeleteMemberBindings (line 235) | func BatchDeleteMemberBindings(ids []int64) error {
  function DeleteMemberBindingsByMID (line 245) | func DeleteMemberBindingsByMID(mid int64) error {
  function ActivateMemberBinding (line 251) | func ActivateMemberBinding(id int64) error {
  function DeactivateMemberBinding (line 260) | func DeactivateMemberBinding(id int64) error {
  function CountMemberBindings (line 269) | func CountMemberBindings(eid int64, from int) (int64, error) {
  function GetMemberBindingsBySource (line 282) | func GetMemberBindingsBySource(eid int64, from int) ([]*MemberBinding, e...

FILE: api/model/member_department_relation.go
  constant MemberDepartmentRelationFromBackend (line 12) | MemberDepartmentRelationFromBackend = 0
  constant MemberDepartmentRelationFromWeChat (line 13) | MemberDepartmentRelationFromWeChat  = 1
  type MemberDepartmentRelation (line 17) | type MemberDepartmentRelation struct
    method TableName (line 27) | func (MemberDepartmentRelation) TableName() string {
  function CreateMemberDepartmentRelation (line 32) | func CreateMemberDepartmentRelation(relation *MemberDepartmentRelation) ...
  function validateMemberDepartmentRelation (line 42) | func validateMemberDepartmentRelation(relation *MemberDepartmentRelation...
  function GetMemberDepartmentRelationByID (line 59) | func GetMemberDepartmentRelationByID(id int64) (*MemberDepartmentRelatio...
  function GetMemberDepartmentRelationsByEID (line 72) | func GetMemberDepartmentRelationsByEID(eid int64) ([]*MemberDepartmentRe...
  function GetMemberDepartmentRelationsByDID (line 82) | func GetMemberDepartmentRelationsByDID(eid int64, did int64) ([]*MemberD...
  function GetMemberDepartmentRelationsByBID (line 92) | func GetMemberDepartmentRelationsByBID(eid int64, bid int64) ([]*MemberD...
  function GetMemberDidsByBID (line 101) | func GetMemberDidsByBID(eid int64, bid int64) ([]int64, error) {
  function UpdateMemberDepartmentRelation (line 117) | func UpdateMemberDepartmentRelation(relation *MemberDepartmentRelation) ...
  function DeleteMemberDepartmentRelation (line 140) | func DeleteMemberDepartmentRelation(id int64) error {
  function DeleteMemberDepartmentRelationsByDID (line 153) | func DeleteMemberDepartmentRelationsByDID(eid int64, did int64) error {
  function DeleteMemberDepartmentRelationsByBID (line 159) | func DeleteMemberDepartmentRelationsByBID(eid int64, bid int64) error {
  function BatchCreateMemberDepartmentRelations (line 165) | func BatchCreateMemberDepartmentRelations(relations []*MemberDepartmentR...
  function GetUsersByDepartmentIDs (line 199) | func GetUsersByDepartmentIDs(eid int64, dids []int64) ([]int64, error) {

FILE: api/model/message.go
  type Message (line 5) | type Message struct
    method GetMessageType (line 37) | func (m *Message) GetMessageType() MessageType {
    method ParseChatMessage (line 53) | func (m *Message) ParseChatMessage() ([]map[string]interface{}, error) {
    method ParseWorkflowParameters (line 62) | func (m *Message) ParseWorkflowParameters() (map[string]interface{}, e...
    method ParseWorkflowOutput (line 71) | func (m *Message) ParseWorkflowOutput() (map[string]interface{}, error) {
  type MessageType (line 29) | type MessageType
  constant MessageTypeChat (line 32) | MessageTypeChat     MessageType = "chat"
  constant MessageTypeWorkflow (line 33) | MessageTypeWorkflow MessageType = "workflow"
  function CreateMessage (line 80) | func CreateMessage(message *Message) error {
  function GetMessageByID (line 85) | func GetMessageByID(eid int64, id int64) (*Message, error) {
  function GetMessagesByUserID (line 95) | func GetMessagesByUserID(eid int64, userID int64) ([]*Message, error) {
  function GetMessagesByAgentID (line 105) | func GetMessagesByAgentID(eid int64, agentID int64) ([]*Message, error) {
  function GetMessagesByUserAndAgent (line 115) | func GetMessagesByUserAndAgent(eid int64, userID int64, agentID int64, k...
  function UpdateMessage (line 145) | func UpdateMessage(message *Message) error {
  function DeleteMessage (line 150) | func DeleteMessage(eid int64, id int64) error {
  function DeleteMessagesByUserID (line 155) | func DeleteMessagesByUserID(eid int64, userID int64) error {
  function DeleteMessagesByAgentID (line 160) | func DeleteMessagesByAgentID(eid int64, agentID int64) error {
  function GetMessagesByConversationID (line 165) | func GetMessagesByConversationID(eid int64, conversationID int64, keywor...
  function GetMessagesByConversationIDWithDirection (line 192) | func GetMessagesByConversationIDWithDirection(eid int64, conversationID ...

FILE: api/model/navigation.go
  type Navigation (line 5) | type Navigation struct
    method Create (line 28) | func (nav *Navigation) Create() error {
    method Update (line 49) | func (nav *Navigation) Update() error {
    method Delete (line 53) | func (nav *Navigation) Delete() error {
    method LoadContent (line 67) | func (nav *Navigation) LoadContent() error {
  constant NavigationTypeSystemBuiltIn (line 20) | NavigationTypeSystemBuiltIn = 1
  constant NavigationTypeExternalLink (line 21) | NavigationTypeExternalLink  = 2
  constant NavigationTypeCustomPage (line 22) | NavigationTypeCustomPage    = 3
  constant NavigationStatusEnabled (line 24) | NavigationStatusEnabled  = 1
  constant NavigationStatusDisabled (line 25) | NavigationStatusDisabled = 2
  function GetNavigationByID (line 57) | func GetNavigationByID(eid int64, navigationID int64) (*Navigation, erro...
  function UpdateNavigation (line 77) | func UpdateNavigation(id int, updates map[string]interface{}) error {
  function DeleteNavigation (line 81) | func DeleteNavigation(id int) error {
  function UpdateNavigationStatus (line 85) | func UpdateNavigationStatus(id int, status int) error {
  function BatchUpdateNavigationSort (line 89) | func BatchUpdateNavigationSort(sortList []struct {
  function GetNavigationsByEid (line 110) | func GetNavigationsByEid(eid int64) ([]*Navigation, error) {

FILE: api/model/navigation_content.go
  type NavigationContent (line 8) | type NavigationContent struct
    method TableName (line 15) | func (NavigationContent) TableName() string {
    method Create (line 19) | func (nc *NavigationContent) Create() error {
    method Update (line 34) | func (nc *NavigationContent) Update() error {
    method Delete (line 41) | func (nc *NavigationContent) Delete() error {
  function GetContentByID (line 45) | func GetContentByID(contentID int64, navigationID int64) (*NavigationCon...
  function GetNavigationContentByID (line 54) | func GetNavigationContentByID(navID int64) (*NavigationContent, error) {
  function DeleteNavigationContentByNavID (line 62) | func DeleteNavigationContentByNavID(navID int64) error {

FILE: api/model/order.go
  constant OrderStatusConfirming (line 10) | OrderStatusConfirming = 1
  constant OrderStatusPending (line 11) | OrderStatusPending    = 2
  constant OrderStatusPaid (line 12) | OrderStatusPaid       = 3
  constant OrderStatusExpired (line 13) | OrderStatusExpired    = 4
  constant OrderStatusClosed (line 14) | OrderStatusClosed     = 5
  constant ServiceTypeSubscription (line 19) | ServiceTypeSubscription = 1
  constant TradeTypeJSAPI (line 24) | TradeTypeJSAPI    = "JSAPI"
  constant TradeTypeNative (line 25) | TradeTypeNative   = "NATIVE"
  constant TradeTypeApp (line 26) | TradeTypeApp      = "APP"
  constant TradeTypeMicroPay (line 27) | TradeTypeMicroPay = "MICROPAY"
  constant TradeTypeMWeb (line 28) | TradeTypeMWeb     = "MWEB"
  constant TradeTypeFacePay (line 29) | TradeTypeFacePay  = "FACEPAY"
  constant TradeStateSuccess (line 34) | TradeStateSuccess    = "SUCCESS"
  constant TradeStateRefund (line 35) | TradeStateRefund     = "REFUND"
  constant TradeStateNotPay (line 36) | TradeStateNotPay     = "NOTPAY"
  constant TradeStateClosed (line 37) | TradeStateClosed     = "CLOSED"
  constant TradeStateRevoked (line 38) | TradeStateRevoked    = "REVOKED"
  constant TradeStateUserPaying (line 39) | TradeStateUserPaying = "USERPAYING"
  constant TradeStatePayError (line 40) | TradeStatePayError   = "PAYERROR"
  constant TradeStateWaitBuyerPay (line 43) | TradeStateWaitBuyerPay = "WAIT_BUYER_PAY"
  constant TradeStateTradeClosed (line 44) | TradeStateTradeClosed  = "TRADE_CLOSED"
  constant TradeStateTradeSuccess (line 45) | TradeStateTradeSuccess = "TRADE_SUCCESS"
  constant TradeStateTradeFinish (line 46) | TradeStateTradeFinish  = "TRADE_FINISHED"
  type Order (line 50) | type Order struct
    method CalculateNewExpiredTime (line 72) | func (o *Order) CalculateNewExpiredTime(user *User) (int64, error) {
    method TableName (line 200) | func (o *Order) TableName() string {
    method Create (line 205) | func (o *Order) Create() error {
    method Update (line 210) | func (o *Order) Update() error {
    method Delete (line 215) | func (o *Order) Delete() error {
  function GetOrderByID (line 108) | func GetOrderByID(eid int64, id int64) (*Order, error) {
  function GetOrderByOrderId (line 115) | func GetOrderByOrderId(eid int64, orderId string) (*Order, error) {
  function UpdateOrderStatus (line 122) | func UpdateOrderStatus(eid int64, orderId string, status int) error {
  function UpdateOrderPaid (line 130) | func UpdateOrderPaid(eid int64, orderId string, transactionId string) er...
  function UpdateOrderPaidWithTime (line 135) | func UpdateOrderPaidWithTime(eid int64, orderId string, transactionId st...
  function GetOrders (line 220) | func GetOrders(eid, userID int64, status, page, pageSize int) ([]*Order,...
  function GetUserOrders (line 249) | func GetUserOrders(eid int64, userID int64) ([]*Order, error) {
  function GetPendingOrders (line 256) | func GetPendingOrders() ([]*Order, error) {
  function GetExpiredOrders (line 263) | func GetExpiredOrders() ([]*Order, error) {
  function GetOrdersByStatus (line 270) | func GetOrdersByStatus(eid int64, status int) ([]*Order, error) {
  function CountOrdersByStatus (line 277) | func CountOrdersByStatus(eid int64, status int) (int64, error) {
  function GetOrderStatistics (line 284) | func GetOrderStatistics(eid int64) (map[string]interface{}, error) {
  function GetRecentOrders (line 326) | func GetRecentOrders(eid int64, limit int) ([]*Order, error) {
  function GetOrdersWithFilters (line 333) | func GetOrdersWithFilters(eid int64, userID int64, status, payType int, ...
  function UpdateExpiredOrders (line 387) | func UpdateExpiredOrders() (int64, error) {
  function GetExpiredPendingOrders (line 397) | func GetExpiredPendingOrders(expireTime time.Time) ([]Order, error) {

FILE: api/model/pay_setting.go
  constant PayTypeWechat (line 7) | PayTypeWechat = 1
  constant PayTypeManual (line 8) | PayTypeManual = 2
  constant PayTypePaypal (line 9) | PayTypePaypal = 3
  constant PayTypeAlipay (line 10) | PayTypeAlipay = 4
  constant PayStatusDisabled (line 15) | PayStatusDisabled = false
  constant PayStatusEnabled (line 16) | PayStatusEnabled  = true
  type PaySetting (line 20) | type PaySetting struct
    method TableName (line 55) | func (PaySetting) TableName() string {
    method Create (line 60) | func (ps *PaySetting) Create() error {
    method Update (line 65) | func (ps *PaySetting) Update() error {
    method Delete (line 70) | func (ps *PaySetting) Delete() error {
  type WechatPayConfig (line 31) | type WechatPayConfig struct
  type AlipayConfig (line 46) | type AlipayConfig struct
  function GetPaySettingByID (line 75) | func GetPaySettingByID(eid int64, id int64) (*PaySetting, error) {
  function GetPaySettingsByEid (line 85) | func GetPaySettingsByEid(eid int64) ([]*PaySetting, error) {
  function GetPaySettingByType (line 95) | func GetPaySettingByType(eid int64, payType int) (*PaySetting, error) {
  function GetPayTypeText (line 104) | func GetPayTypeText(payType int) (string, error) {

FILE: api/model/prompt.go
  type Prompt (line 10) | type Prompt struct
    method TableName (line 40) | func (Prompt) TableName() string {
    method Create (line 45) | func (p *Prompt) Create() error {
    method Update (line 66) | func (p *Prompt) Update() error {
    method Delete (line 81) | func (p *Prompt) Delete() error {
    method HardDelete (line 90) | func (p *Prompt) HardDelete() error {
    method IncrementViews (line 169) | func (p *Prompt) IncrementViews() error {
    method UpdateSort (line 178) | func (p *Prompt) UpdateSort(sort int) error {
    method UpdateCustomConfig (line 187) | func (p *Prompt) UpdateCustomConfig(config string) error {
    method LoadPromptGroups (line 195) | func (p *Prompt) LoadPromptGroups() error {
    method LoadIsLiked (line 210) | func (p *Prompt) LoadIsLiked(UserId int64) error {
  constant PromptTypeSystem (line 31) | PromptTypeSystem   = 1
  constant PromptTypePersonal (line 32) | PromptTypePersonal = 2
  constant PromptStatusDisable (line 34) | PromptStatusDisable = 0
  constant PromptStatusNormal (line 35) | PromptStatusNormal  = 1
  constant PromptStatusDelete (line 36) | PromptStatusDelete  = 2
  function GetPromptByID (line 96) | func GetPromptByID(promptID int) (*Prompt, error) {
  function GetPromptsByEid (line 107) | func GetPromptsByEid(eid int) ([]*Prompt, error) {
  function GetPromptList (line 117) | func GetPromptList(eid int64, keyword string, groupIDStr string, status,...

FILE: api/model/provider.go
  type Provider (line 7) | type Provider struct
    method GetBaseURLByProviderType (line 37) | func (provider *Provider) GetBaseURLByProviderType() string {
  type CozeConfig (line 22) | type CozeConfig struct
  constant ProviderTypeCozeCn (line 28) | ProviderTypeCozeCn     = 1
  constant ProviderTypeCozeCom (line 29) | ProviderTypeCozeCom    = 2
  constant ProviderTypeAppBuilder (line 30) | ProviderTypeAppBuilder = 3
  constant ProviderType53AI (line 31) | ProviderType53AI       = 4
  constant ProviderTypeCozeStudio (line 32) | ProviderTypeCozeStudio = 5
  constant ProviderTypeTencent (line 33) | ProviderTypeTencent    = 6
  function CreateProvider (line 59) | func CreateProvider(provider *Provider) error {
  function DeleteProviderByID (line 63) | func DeleteProviderByID(id, eid int64) error {
  function UpdateProvider (line 67) | func UpdateProvider(provider *Provider) error {
  function GetProviderByID (line 72) | func GetProviderByID(id, eid int64) (*Provider, error) {
  function GetProvidersByEidAndProviderType (line 78) | func GetProvidersByEidAndProviderType(eid int64, providerType int64) ([]...
  function GetProvidersByEidWithFilters (line 89) | func GetProvidersByEidWithFilters(eid int64, providerType int64, name st...
  function GetFirstProviderByEidAndProviderType (line 105) | func GetFirstProviderByEidAndProviderType(eid int64, providerType int64)...
  function GetProvidersByTypeAndAuthStatus (line 110) | func GetProvidersByTypeAndAuthStatus(providerType int64, authStatus bool...
  function GetProviderByEidAndProviderTypeWithOptionalID (line 119) | func GetProviderByEidAndProviderTypeWithOptionalID(eid int64, providerTy...

FILE: api/model/resource_permission.go
  constant ResourceTypeAgent (line 5) | ResourceTypeAgent      = "agent"
  constant ResourceTypeUser (line 6) | ResourceTypeUser       = "user"
  constant ResourceTypeDepartment (line 7) | ResourceTypeDepartment = "department"
  constant ResourceTypePrompt (line 8) | ResourceTypePrompt     = "prompt"
  constant ResourceTypeAILink (line 9) | ResourceTypeAILink     = "ai_link"
  constant PermissionRead (line 14) | PermissionRead  = "read"
  constant PermissionWrite (line 15) | PermissionWrite = "write"
  type ResourcePermission (line 19) | type ResourcePermission struct
    method TableName (line 31) | func (ResourcePermission) TableName() string {
    method Create (line 36) | func (rule *ResourcePermission) Create() error {
    method Update (line 41) | func (rule *ResourcePermission) Update() error {
    method Delete (line 46) | func (rule *ResourcePermission) Delete() error {
  function GetResourcePermissionByID (line 51) | func GetResourcePermissionByID(id int64) (*ResourcePermission, error) {
  function GetResourcePermissionsByGroupID (line 61) | func GetResourcePermissionsByGroupID(groupID int64) ([]*ResourcePermissi...
  function CheckPermission (line 71) | func CheckPermission(groupID int64, resourceID int64, resourceType strin...
  function GetResourcesByGroupAndType (line 86) | func GetResourcesByGroupAndType(groupID int64, resourceType string) ([]i...
  function DeleteResourcePermissionsByResource (line 100) | func DeleteResourcePermissionsByResource(resourceID int64, resourceType ...
  function GetGroupsByUserID (line 104) | func GetGroupsByUserID(userID int64) ([]int64, error) {
  function GetGroupsByUserIDAndType (line 117) | func GetGroupsByUserIDAndType(userID int64, groupType int64) ([]int64, e...
  function GetGroupsByDepartmentID (line 133) | func GetGroupsByDepartmentID(departmentID int64) ([]int64, error) {
  function GetGroupIDsByDepartmentIDs (line 146) | func GetGroupIDsByDepartmentIDs(dids []int64) ([]int64, error) {

FILE: api/model/response.go
  type CommonResponse (line 10) | type CommonResponse struct
  type OpenAIErrorResponse (line 31) | type OpenAIErrorResponse struct
  type ResponseCode (line 40) | type ResponseCode
    method Message (line 101) | func (c ResponseCode) Message() string {
    method ToResponse (line 108) | func (c ResponseCode) ToResponse(data interface{}) CommonResponse {
    method ToErrorResponse (line 119) | func (c ResponseCode) ToErrorResponse(err error) CommonResponse {
    method ToNewErrorResponse (line 127) | func (c ResponseCode) ToNewErrorResponse(message string) CommonResponse {
    method ToOpenAIErrorRespone (line 136) | func (c ResponseCode) ToOpenAIErrorRespone(data interface{}) OpenAIErr...
  constant Success (line 45) | Success                      ResponseCode = iota
  constant ParamError (line 46) | ParamError
  constant DBError (line 47) | DBError
  constant NetworkError (line 48) | NetworkError
  constant SystemError (line 49) | SystemError
  constant AuthFailed (line 50) | AuthFailed
  constant NotFound (line 51) | NotFound
  constant UnauthorizedError (line 52) | UnauthorizedError
  constant FileError (line 53) | FileError
  constant ForbiddenError (line 54) | ForbiddenError
  constant AgentAuthError (line 55) | AgentAuthError
  constant TokenExpiredError (line 56) | TokenExpiredError
  constant ChatError (line 57) | ChatError
  constant ProviderNoFoundError (line 58) | ProviderNoFoundError
  constant OperateTooFast (line 59) | OperateTooFast
  constant FeatureNotAvailableError (line 60) | FeatureNotAvailableError
  constant RecordAlreadyExists (line 61) | RecordAlreadyExists
  constant InvalidVerificationCodeError (line 62) | InvalidVerificationCodeError
  constant InvalidEnterpriseID (line 91) | InvalidEnterpriseID     = "invalid enterprise id"
  constant InvalidVerificationCode (line 92) | InvalidVerificationCode = "invalid or expired verification code"
  constant InvalidMobileOrEmail (line 93) | InvalidMobileOrEmail    = "invalid mobile number or email format"
  constant InvalidMobileFormat (line 94) | InvalidMobileFormat     = "invalid mobile number format"
  constant PasswordNotMatch (line 95) | PasswordNotMatch        = "password not match"
  constant OrderNotFound (line 96) | OrderNotFound           = "order not found"
  constant FeatureNotAvailable (line 97) | FeatureNotAvailable     = "feature not available"
  constant FeatureOverLimit (line 98) | FeatureOverLimit        = "feature over limit"

FILE: api/model/setting.go
  type Setting (line 10) | type Setting struct
  type SettingKey (line 18) | type SettingKey
  constant ThirdPartyStatisticHeader (line 21) | ThirdPartyStatisticHeader SettingKey = "third_party_statistic_header"
  constant ThirdPartyStatisticCss (line 22) | ThirdPartyStatisticCss    SettingKey = "third_party_statistic_css"
  constant DefaultPromptLinks (line 26) | DefaultPromptLinks string = "default_prompt_links"
  type SettingGroup (line 29) | type SettingGroup
  function GetSettingGroupByName (line 40) | func GetSettingGroupByName(group_name string) (SettingGroup, bool) {
  function CreateSetting (line 45) | func CreateSetting(setting *Setting) error {
  function DeleteSettingByID (line 49) | func DeleteSettingByID(id int64) error {
  function UpdateSetting (line 53) | func UpdateSetting(setting *Setting) error {
  function GetSettingByID (line 59) | func GetSettingByID(id int64) (*Setting, error) {
  function GetSettingsByEid (line 68) | func GetSettingsByEid(eid int64) ([]Setting, error) {
  function GetSettingsBySettingsGroup (line 76) | func GetSettingsBySettingsGroup(eid int64, group_name string) ([]Setting...
  function GetSettingByEidAndKey (line 92) | func GetSettingByEidAndKey(eid int64, key string) (*Setting, error) {
  function GetDefaultPromptLinks (line 105) | func GetDefaultPromptLinks(eid int64) ([]AILinkInfo, error) {

FILE: api/model/share_record.go
  type ShareRecord (line 15) | type ShareRecord struct
    method TableName (line 30) | func (ShareRecord) TableName() string {
  function NormalizeMessageIDs (line 35) | func NormalizeMessageIDs(ids []int64) (string, []int64) {
  function HashNormalizedKey (line 57) | func HashNormalizedKey(key string) string {
  function ParseMessageIDsToIDs (line 63) | func ParseMessageIDsToIDs(key string) ([]int64, error) {
  function ValidateMessagesBelongToConversation (line 81) | func ValidateMessagesBelongToConversation(eid, conversationID int64, ids...
  function CreateShareRecord (line 99) | func CreateShareRecord(eid, conversationID int64, messageIDsNormalized s...
  function GetShareRecordByShareID (line 136) | func GetShareRecordByShareID(shareID string) (*ShareRecord, error) {
  function ListMessageIDsByConversation (line 146) | func ListMessageIDsByConversation(eid, conversationID int64) ([]int64, e...
  function GetMessagesByIDsOrderedAsc (line 166) | func GetMessagesByIDsOrderedAsc(eid int64, ids []int64) ([]*Message, err...

FILE: api/model/subscription.go
  constant CurrencyCNY (line 4) | CurrencyCNY = "CNY"
  constant CurrencyUSD (line 5) | CurrencyUSD = "USD"
  constant TimeUnitYear (line 7) | TimeUnitYear    = "year"
  constant TimeUnitMonth (line 8) | TimeUnitMonth   = "month"
  constant TimeUnitWeek (line 9) | TimeUnitWeek    = "week"
  constant TimeUnitDay (line 10) | TimeUnitDay     = "day"
  constant TimeUnitQuarter (line 11) | TimeUnitQuarter = "quarter"
  constant SubscriptionTypeFee (line 13) | SubscriptionTypeFee    = 1
  constant SubscriptionTypePoints (line 14) | SubscriptionTypePoints = 2
  type SubscriptionSetting (line 20) | type SubscriptionSetting struct
    method LoadRelations (line 44) | func (s *SubscriptionSetting) LoadRelations() error {
    method TableName (line 78) | func (SubscriptionSetting) TableName() string {
  type SubscriptionRelation (line 51) | type SubscriptionRelation struct
    method TableName (line 82) | func (SubscriptionRelation) TableName() string {
  function CreateSubscriptionSetting (line 87) | func CreateSubscriptionSetting(setting *SubscriptionSetting) error {
  function UpdateSubscriptionSetting (line 92) | func UpdateSubscriptionSetting(setting *SubscriptionSetting) error {
  function DeleteSubscriptionSetting (line 100) | func DeleteSubscriptionSetting(settingId int64) error {
  function GetSubscriptionSettingById (line 106) | func GetSubscriptionSettingById(settingId int64) (*SubscriptionSetting, ...
  function GetAllSubscriptionSettings (line 113) | func GetAllSubscriptionSettings(offset, limit int) ([]SubscriptionSettin...
  function CreateSubscriptionRelation (line 133) | func CreateSubscriptionRelation(relation *SubscriptionRelation) error {
  function UpdateSubscriptionRelation (line 138) | func UpdateSubscriptionRelation(relation *SubscriptionRelation) error {
  function DeleteSubscriptionRelation (line 148) | func DeleteSubscriptionRelation(relationId int64) error {
  function DeleteSubscriptionRelationsBySettingId (line 154) | func DeleteSubscriptionRelationsBySettingId(settingId int64) error {
  function GetSubscriptionRelationsBySettingId (line 160) | func GetSubscriptionRelationsBySettingId(settingId int64) ([]Subscriptio...
  type SubscriptionSettingWithAgents (line 167) | type SubscriptionSettingWithAgents struct
  function GetSubscriptionSettingsWithAgents (line 173) | func GetSubscriptionSettingsWithAgents(eid int64, offset, limit int) ([]...
  function GetDefaultSubscription (line 204) | func GetDefaultSubscription(eid int64) (*SubscriptionSetting, error) {

FILE: api/model/system_log.go
  type SystemLog (line 12) | type SystemLog struct
    method TableName (line 74) | func (SystemLog) TableName() string {
  constant SystemLogModuleSystem (line 26) | SystemLogModuleSystem       uint8 = 1
  constant SystemLogModuleAgent (line 27) | SystemLogModuleAgent        uint8 = 2
  constant SystemLogModulePrompt (line 28) | SystemLogModulePrompt       uint8 = 3
  constant SystemLogModuleAITool (line 29) | SystemLogModuleAITool       uint8 = 4
  constant SystemLogModuleOrder (line 30) | SystemLogModuleOrder        uint8 = 5
  constant SystemLogModuleRegistered (line 31) | SystemLogModuleRegistered   uint8 = 6
  constant SystemLogModuleInternalUser (line 32) | SystemLogModuleInternalUser uint8 = 7
  constant SystemLogModuleSubscription (line 33) | SystemLogModuleSubscription uint8 = 8
  constant SystemLogModuleAdmin (line 34) | SystemLogModuleAdmin        uint8 = 9
  constant SystemLogModuleTemplate (line 35) | SystemLogModuleTemplate     uint8 = 10
  constant SystemLogModuleBanner (line 36) | SystemLogModuleBanner       uint8 = 11
  constant SystemLogModuleNavigation (line 37) | SystemLogModuleNavigation   uint8 = 12
  constant SystemLogModuleSiteInfo (line 38) | SystemLogModuleSiteInfo     uint8 = 13
  constant SystemLogModulePlatform (line 39) | SystemLogModulePlatform     uint8 = 14
  constant SystemLogModulePayment (line 40) | SystemLogModulePayment      uint8 = 15
  constant SystemLogModuleDomain (line 41) | SystemLogModuleDomain       uint8 = 16
  constant SystemLogModuleStatistics (line 42) | SystemLogModuleStatistics   uint8 = 17
  function GetModuleByGroupType (line 46) | func GetModuleByGroupType(groupType int64) uint8 {
  constant SystemLogActionCreate (line 66) | SystemLogActionCreate   uint8 = 1
  constant SystemLogActionUpdate (line 67) | SystemLogActionUpdate   uint8 = 2
  constant SystemLogActionDelete (line 68) | SystemLogActionDelete   uint8 = 3
  constant SystemLogActionToggle (line 69) | SystemLogActionToggle   uint8 = 4
  constant SystemLogActionLoginOut (line 70) | SystemLogActionLoginOut uint8 = 5
  function GetSystemLogsByConditions (line 79) | func GetSystemLogsByConditions(eid, module, action, userID, startTime, e...
  function CreateSystemLog (line 112) | func CreateSystemLog(log *SystemLog) {
  function LogEntityChange (line 125) | func LogEntityChange(entityType string, action uint8, eid, userId int64,...
  function generateChangeContent (line 146) | func generateChangeContent(entityType string, action uint8, oldEntity, n...
  function compareEntities (line 167) | func compareEntities(oldEntity, newEntity interface{}, fieldMap map[stri...
  type ModuleItem (line 232) | type ModuleItem struct
  function GetAllModules (line 259) | func GetAllModules() []ModuleItem {
  function GetModuleText (line 268) | func GetModuleText(value uint8) string {
  type ActionItem (line 273) | type ActionItem struct
  function GetAllActions (line 289) | func GetAllActions() []ActionItem {
  function GetActionText (line 298) | func GetActionText(value uint8) string {

FILE: api/model/upload_file.go
  type UploadFile (line 13) | type UploadFile struct
    method Save (line 34) | func (uploadFile *UploadFile) Save() error {
    method GetChannelFileMapping (line 83) | func (uploadFile *UploadFile) GetChannelFileMapping(channelId int, mod...
    method GetPreviewFullUrl (line 92) | func (uploadFile *UploadFile) GetPreviewFullUrl() string {
  function GetFileKey (line 27) | func GetFileKey(fileName string, Eid int64, UserId int64) string {
  function GetPreviewKey (line 55) | func GetPreviewKey(hashStr string, extension string) (string, error) {
  function GetUploadFileByEidAndPreviewKey (line 62) | func GetUploadFileByEidAndPreviewKey(Eid int64, PreviewKey string) (uplo...
  function GetNoAuthUploadFileByEidAndPreviewKey (line 70) | func GetNoAuthUploadFileByEidAndPreviewKey(PreviewKey string) (uploadFil...
  function GetUploadFileByID (line 78) | func GetUploadFileByID(id int64) (uploadFile *UploadFile, err error) {

FILE: api/model/user.go
  type User (line 15) | type User struct
    method Create (line 57) | func (user *User) Create() error {
    method Update (line 112) | func (user *User) Update(updatePassword bool) error {
    method Delete (line 139) | func (user *User) Delete() error {
    method LoginValidate (line 153) | func (user *User) LoginValidate(eid int64, username string, password s...
    method RefreshAccessToken (line 184) | func (user *User) RefreshAccessToken() error {
    method UpdateStatusToJoin (line 201) | func (user *User) UpdateStatusToJoin() error {
    method VerifyPassword (line 325) | func (user *User) VerifyPassword(password string) error {
    method LoadDepartments (line 442) | func (u *User) LoadDepartments(from int) error {
    method LoadMemberBindings (line 456) | func (u *User) LoadMemberBindings(from int) error {
    method LoadUserInfo (line 469) | func (u *User) LoadUserInfo(from int) {
    method GetUserGroupIds (line 475) | func (u *User) GetUserGroupIds() ([]int64, error) {
    method LoadGroupIds (line 503) | func (u *User) LoadGroupIds() error {
    method InvalidateAccessToken (line 571) | func (user *User) InvalidateAccessToken() error {
  constant RoleGuestUser (line 43) | RoleGuestUser   = 0
  constant RoleCommonUser (line 44) | RoleCommonUser  = 1
  constant RoleAdminUser (line 45) | RoleAdminUser   = 10
  constant RoleCreatorUser (line 46) | RoleCreatorUser = 10000
  constant RoleRootUser (line 47) | RoleRootUser    = 100000
  constant UserStatusNotJoined (line 49) | UserStatusNotJoined = 0
  constant UserStatusJoined (line 50) | UserStatusJoined    = 1
  constant UserStatusDisabled (line 51) | UserStatusDisabled  = 2
  constant UserTypeRegistered (line 53) | UserTypeRegistered = 1
  constant UserTypeInternal (line 54) | UserTypeInternal   = 2
  function GetUserByID (line 144) | func GetUserByID(userID int64) (*User, error) {
  function GetUserByUserName (line 175) | func GetUserByUserName(eid int64, username string) (*User, error) {
  function ValidateAccessToken (line 210) | func ValidateAccessToken(token string) (user *User) {
  function GetUserList (line 221) | func GetUserList(eid int64, keyword string, group_id int64, offset int, ...
  function DeleteUser (line 239) | func DeleteUser(eid int64, user_id int64) error {
  function UpdateUserPassword (line 285) | func UpdateUserPassword(eid int64, userID int64, newPassword string) err...
  function UpdateAllUsersPasswordByRelatedID (line 300) | func UpdateAllUsersPasswordByRelatedID(relatedId int64, newSalt string, ...
  function GetUserByEmail (line 313) | func GetUserByEmail(eid int64, email string) (User, error) {
  function GetUserByMobile (line 319) | func GetUserByMobile(eid int64, mobile string) (User, error) {
  function GetUserByRelatedId (line 337) | func GetUserByRelatedId(eid int64, relatedId int64) (*User, error) {
  function GetFirstUserByRelatedId (line 346) | func GetFirstUserByRelatedId(relatedId int64) (*User, error) {
  function GetUserListWithRoles (line 356) | func GetUserListWithRoles(eid int64, keyword string, groupId int64, role...
  function IsUserExistsByAccount (line 413) | func IsUserExistsByAccount(eid int64, account string) (bool, error) {
  function GetLoginUser (line 515) | func GetLoginUser(c *gin.Context) (*User, error) {
  function GetUserByOpenId (line 529) | func GetUserByOpenId(openId string, eid int64) (*User, error) {
  function GetUserByUnionId (line 537) | func GetUserByUnionId(unionId string, eid int64) (*User, error) {
  function GetFirstUserByUnionId (line 545) | func GetFirstUserByUnionId(unionId string) (*User, error) {
  function IsOpenIdExists (line 554) | func IsOpenIdExists(openId string) (bool, error) {
  function GetUserCountByEIDAndType (line 562) | func GetUserCountByEIDAndType(eid int64, theType int) (int64, error) {
  function IsAdmin (line 578) | func IsAdmin(role int64) bool {

FILE: api/model/verification_code.go
  type VerificationCode (line 5) | type VerificationCode struct
    method TableName (line 21) | func (VerificationCode) TableName() string {
  constant VerificationCodeTypePhone (line 16) | VerificationCodeTypePhone = "phone"
  constant VerificationCodeTypeEmail (line 17) | VerificationCodeTypeEmail = "email"

FILE: api/model/wecom_corp.go
  type WecomCorp (line 10) | type WecomCorp struct
    method GetWecomAuthUserInfo (line 106) | func (w *WecomCorp) GetWecomAuthUserInfo() *AuthUserInfo {
    method Delete (line 114) | func (w *WecomCorp) Delete() error {
    method GetAgents (line 118) | func (w *WecomCorp) GetAgents() []AgentItem {
    method GetAgentID (line 126) | func (w *WecomCorp) GetAgentID() int {
    method GetAuthCorpInfo (line 134) | func (w *WecomCorp) GetAuthCorpInfo() *AuthCorpInfo {
  type AuthCorpInfo (line 41) | type AuthCorpInfo struct
  type AuthUserInfo (line 49) | type AuthUserInfo struct
  type AgentItem (line 56) | type AgentItem struct
  type Privilege (line 65) | type Privilege struct
  function GetWecomCorp (line 75) | func GetWecomCorp(suiteID string, corpID string) (*WecomCorp, error) {
  function CreateWecomCorp (line 90) | func CreateWecomCorp(corp *WecomCorp) error {
  function UpdateWecomCorp (line 98) | func UpdateWecomCorp(corp *WecomCorp) error {

FILE: api/model/wecom_suite.go
  type WecomSuite (line 7) | type WecomSuite struct
    method Create (line 39) | func (suite *WecomSuite) Create() error {
    method Update (line 53) | func (suite *WecomSuite) Update() error {
    method Delete (line 61) | func (suite *WecomSuite) Delete() error {
  function GetWecomSuite (line 30) | func GetWecomSuite(suiteID string) (*WecomSuite, error) {
  function GetWecomSuitesByCorpID (line 69) | func GetWecomSuitesByCorpID(corpID string) ([]*WecomSuite, error) {

FILE: api/router/api.go
  function SetApiRouter (line 10) | func SetApiRouter(router *gin.Engine) {

FILE: api/router/main.go
  function SetRouter (line 25) | func SetRouter(router *gin.Engine, buildFS embed.FS) {
  function setStaticImagesRouter (line 38) | func setStaticImagesRouter(router *gin.Engine, buildFS embed.FS) {
  function setStaticLibsRouter (line 43) | func setStaticLibsRouter(router *gin.Engine, buildFS embed.FS) {

FILE: api/router/static.go
  constant pathAPI (line 14) | pathAPI     = "/api/"
  constant pathStatic (line 15) | pathStatic  = "/static/"
  constant pathConsole (line 16) | pathConsole = "/console"
  constant pathAssets (line 17) | pathAssets  = "/assets/"
  constant pathImages (line 18) | pathImages  = "/images/"
  constant contentTypeHTML (line 21) | contentTypeHTML = "text/html; charset=utf-8"
  function serveHTMLFile (line 24) | func serveHTMLFile(c *gin.Context, fsys fs.FS, filename string, logMsg s...
  function serveStaticFile (line 40) | func serveStaticFile(c *gin.Context, fsys fs.FS, filepath string, logMsg...
  function tryServeFile (line 70) | func tryServeFile(c *gin.Context, fsys fs.FS, filePath string, logMsg st...
  function SetStaticRouter (line 88) | func SetStaticRouter(router *gin.Engine, buildFS embed.FS) error {

FILE: api/router/web.go
  function SetWebRouter (line 12) | func SetWebRouter(router *gin.Engine, buildFS embed.FS) {

FILE: api/service/adaptor.go
  function GetAdaptor (line 40) | func GetAdaptor(apiType int) adaptor.Adaptor {
  function SetCustomConfig (line 107) | func SetCustomConfig(a *adaptor.Adaptor, customConfig *custom.CustomConf...
  function GetCustomConfig (line 145) | func GetCustomConfig(a *adaptor.Adaptor) *custom.CustomConfig {

FILE: api/service/ai53_provider.go
  type AI53Service (line 8) | type AI53Service struct
    method GetApiSdk (line 12) | func (a *AI53Service) GetApiSdk() *ai53.AI53Api {
    method GetAllBots (line 20) | func (a *AI53Service) GetAllBots() ([]ai53.AppResponse, error) {
    method GetAllWorkflows (line 43) | func (a *AI53Service) GetAllWorkflows() ([]ai53.AppResponse, error) {
    method GetAppParameters (line 66) | func (a *AI53Service) GetAppParameters(botId string) (interface{}, err...

FILE: api/service/appbuilder_provider.go
  type AppBuilderService (line 10) | type AppBuilderService struct
    method GetApiSdk (line 14) | func (a *AppBuilderService) GetApiSdk() *appbuilder.AppBuilderApi {
    method GetAllDescribeApps (line 25) | func (a *AppBuilderService) GetAllDescribeApps() ([]appbuilder.AppInfo...

FILE: api/service/channel_service.go
  function GetChannelWithTokenRefresh (line 14) | func GetChannelWithTokenRefresh(ctx context.Context, eid int64, channelT...

FILE: api/service/coze_provider.go
  type CozeService (line 22) | type CozeService struct
    method GetCozeApiSdk (line 26) | func (ser *CozeService) GetCozeApiSdk() (*coze.CozeApi, error) {
    method HandlerAccessTokenByCode (line 48) | func (ser *CozeService) HandlerAccessTokenByCode(coze string, callback...
    method HandlerAccessTokenByRefreshToken (line 85) | func (ser *CozeService) HandlerAccessTokenByRefreshToken() error {
    method CheckAndRefreshToken (line 128) | func (ser *CozeService) CheckAndRefreshToken() (ok bool, err error) {
    method GetAllWorkspace (line 145) | func (ser *CozeService) GetAllWorkspace() ([]*coze.Workspace, error) {
    method GetAllBot (line 194) | func (ser *CozeService) GetAllBot(workspaceId string) ([]*coze.Bot, er...
    method CacheBotIconWithUploadFile (line 260) | func (ser *CozeService) CacheBotIconWithUploadFile(botID string, iconU...
    method findUploadFileByHash (line 335) | func (ser *CozeService) findUploadFileByHash(hash string) *db_model.Up...
    method downloadIcon (line 348) | func (ser *CozeService) downloadIcon(iconURL string) ([]byte, error) {
    method UpdateCozeChannel (line 401) | func (ser *CozeService) UpdateCozeChannel(botIds []string, provider *m...

FILE: api/service/enterprise_config_service.go
  type ConfigContent (line 14) | type ConfigContent struct
  type SmtpConfig (line 20) | type SmtpConfig struct
    method UnmarshalJSON (line 30) | func (s *SmtpConfig) UnmarshalJSON(data []byte) error {
  function getStringValue (line 82) | func getStringValue(value interface{}) string {
  function getBoolValue (line 100) | func getBoolValue(value interface{}) bool {
  function GetEnterpriseConfigs (line 119) | func GetEnterpriseConfigs(eid int64) ([]model.EnterpriseConfig, error) {
  function GetEnterpriseConfigByType (line 142) | func GetEnterpriseConfigByType(eid int64, configType string) (*model.Ent...
  function SaveEnterpriseConfig (line 163) | func SaveEnterpriseConfig(eid int64, configType string, content string, ...
  function IsEnterpriseConfigEnabled (line 193) | func IsEnterpriseConfigEnabled(eid int64, configType string) (bool, erro...
  function ToggleEnterpriseConfig (line 207) | func ToggleEnterpriseConfig(eid int64, configType string) (bool, error) {
  function GetSmtpConfig (line 228) | func GetSmtpConfig(eid int64) (smtp.Auth, string, string, int, bool, err...
  function GetSmtpConfigFromEnv (line 263) | func GetSmtpConfigFromEnv() (smtp.Auth, string, string, int, bool, error) {

FILE: api/service/hub_adaptor/53AI/adaptor.go
  type Adaptor (line 25) | type Adaptor struct
    method Init (line 30) | func (a *Adaptor) Init(meta *meta.Meta) {
    method GetRequestURL (line 40) | func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
    method SetupRequestHeader (line 45) | func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Request...
    method ConvertRequest (line 53) | func (a *Adaptor) ConvertRequest(c *gin.Context, relayMode int, reques...
    method DoRequest (line 147) | func (a *Adaptor) DoRequest(c *gin.Context, meta *meta.Meta, requestBo...
    method ConvertImageRequest (line 151) | func (a *Adaptor) ConvertImageRequest(request *model.ImageRequest) (an...
    method DoResponse (line 158) | func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, meta...
    method GetModelList (line 232) | func (a *Adaptor) GetModelList() []string {
    method GetChannelName (line 236) | func (a *Adaptor) GetChannelName() string {
  function GetBaseURL (line 34) | func GetBaseURL(baseUrl string) string {
  function ConvertRequest (line 61) | func ConvertRequest(textRequest model.GeneralOpenAIRequest, meta *meta.M...
  function Handler (line 177) | func Handler(c *gin.Context, resp *http.Response, promptTokens int, mode...
  function ResponseAi53OpenAI (line 210) | func ResponseAi53OpenAI(ai53Response *BlockResponse) *openai.TextResponse {
  function AI53UploadFile (line 240) | func AI53UploadFile(meta *meta.Meta, uploadFile *db_model.UploadFile, fi...
  function Get53AIFileType (line 367) | func Get53AIFileType(mimeType string, extension string) string {

FILE: api/service/hub_adaptor/53AI/main.go
  function StreamHandler (line 18) | func StreamHandler(c *gin.Context, resp *http.Response) (*model.ErrorWit...
  function StreamResponseai53OpenAI (line 75) | func StreamResponseai53OpenAI(ai53Response *StreamResponse) (*openai.Cha...
  function BlockingResponseai53OpenAI (line 115) | func BlockingResponseai53OpenAI(ai53Response *BlockResponse) (*openai.Ch...
  function stopReasonAi53OpenAI (line 129) | func stopReasonAi53OpenAI(reason *string) string {
  constant TransferMethodRemoteUrl (line 146) | TransferMethodRemoteUrl = "remote_url"
  constant TransferMethodLocalFile (line 147) | TransferMethodLocalFile = "local_file"
  type File (line 150) | type File struct
  constant ResponseModeStream (line 158) | ResponseModeStream = "streaming"
  constant ResponseModeBlock (line 159) | ResponseModeBlock  = "blocking"
  type Request (line 162) | type Request struct

FILE: api/service/hub_adaptor/53AI/model.go
  type StreamResponse (line 3) | type StreamResponse struct
  type Response (line 15) | type Response struct
  type Message (line 23) | type Message struct
  type BlockResponse (line 30) | type BlockResponse struct
  type AppendContent (line 41) | type AppendContent struct
  type Metadata (line 46) | type Metadata struct
  type Usage (line 50) | type Usage struct
  type UploadResponse (line 65) | type UploadResponse struct

FILE: api/service/hub_adaptor/53AI/workflow.go
  type readCloser (line 23) | type readCloser struct
    method Close (line 27) | func (rc *readCloser) Close() error {
  type AI53WorkflowAdaptor (line 32) | type AI53WorkflowAdaptor struct
    method Init (line 58) | func (a *AI53WorkflowAdaptor) Init(meta *meta.Meta) {
    method GetRequestURL (line 63) | func (a *AI53WorkflowAdaptor) GetRequestURL(meta *meta.Meta) (string, ...
    method SetupRequestHeader (line 75) | func (a *AI53WorkflowAdaptor) SetupRequestHeader(c *gin.Context, req *...
    method extractBotId (line 87) | func (a *AI53WorkflowAdaptor) extractBotId(modelName string) string {
    method ConvertRequest (line 96) | func (a *AI53WorkflowAdaptor) ConvertRequest(c *gin.Context, relayMode...
    method processFile (line 165) | func (a *AI53WorkflowAdaptor) processFile(uploadFile *db_model.UploadF...
    method processWorkflowParameters (line 200) | func (a *AI53WorkflowAdaptor) processWorkflowParameters(parameters map...
    method processParameterValue (line 222) | func (a *AI53WorkflowAdaptor) processParameterValue(value interface{})...
    method processFileIDString (line 258) | func (a *AI53WorkflowAdaptor) processFileIDString(value string) (inter...
    method getUserID (line 313) | func (a *AI53WorkflowAdaptor) getUserID(request *model.GeneralOpenAIRe...
    method DoRequest (line 321) | func (a *AI53WorkflowAdaptor) DoRequest(c *gin.Context, meta *meta.Met...
    method DoResponse (line 392) | func (a *AI53WorkflowAdaptor) DoResponse(c *gin.Context, resp *http.Re...
    method ConvertWorkflowToAI53Request (line 477) | func (a *AI53WorkflowAdaptor) ConvertWorkflowToAI53Request(parameters ...
    method ProcessAI53WorkflowResponse (line 522) | func (a *AI53WorkflowAdaptor) ProcessAI53WorkflowResponse(resp *http.R...
    method maskAPIKey (line 650) | func (a *AI53WorkflowAdaptor) maskAPIKey(apiKey string) string {
  type AI53WorkflowRequest (line 38) | type AI53WorkflowRequest struct
  type AI53WorkflowEvent (line 45) | type AI53WorkflowEvent struct
  type AI53WorkflowResponse (line 52) | type AI53WorkflowResponse struct

FILE: api/service/hub_adaptor/appbuilder/adaptor.go
  type Adaptor (line 25) | type Adaptor struct
    method Init (line 30) | func (a *Adaptor) Init(meta *meta.Meta) {
    method GetRequestURL (line 34) | func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
    method SetupRequestHeader (line 42) | func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Request...
    method ConvertRequest (line 49) | func (a *Adaptor) ConvertRequest(c *gin.Context, relayMode int, reques...
    method DoRequest (line 128) | func (a *Adaptor) DoRequest(c *gin.Context, meta *meta.Meta, requestBo...
    method ConvertImageRequest (line 132) | func (a *Adaptor) ConvertImageRequest(request *model.ImageRequest) (an...
    method DoResponse (line 139) | func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, meta...
    method GetModelList (line 158) | func (a *Adaptor) GetModelList() []string {
    method GetChannelName (line 162) | func (a *Adaptor) GetChannelName() string {
    method GetConversationId (line 166) | func (a *Adaptor) GetConversationId() (string, error) {
  function ConvertRequest (line 58) | func ConvertRequest(botID string, meta *meta.Meta, textRequest model.Gen...
  function AppBuilderUploadFile (line 180) | func AppBuilderUploadFile(meta *meta.Meta, uploadFile *db_model.UploadFi...

FILE: api/service/hub_adaptor/appbuilder/main.go
  function StreamHandler (line 20) | func StreamHandler(c *gin.Context, resp *http.Response) (*model.ErrorWit...
  function Handler (line 76) | func Handler(c *gin.Context, resp *http.Response, promptTokens int, mode...
  function StreamResponseToOpenAI (line 109) | func StreamResponseToOpenAI(appBuilderResponse *Response) (*openai.ChatC...
  function stopReasonAppBuilderOpenAI (line 129) | func stopReasonAppBuilderOpenAI(reason *string) string {
  function ResponseToOpenAI (line 145) | func ResponseToOpenAI(response *Response) *openai.TextResponse {

FILE: api/service/hub_adaptor/appbuilder/model.go
  type Request (line 3) | type Request struct
  type ToolChoice (line 16) | type ToolChoice struct
  type Function (line 21) | type Function struct
  type Tool (line 26) | type Tool struct
  type ToolOutput (line 31) | type ToolOutput struct
  type Action (line 36) | type Action struct
  type InterruptEvent (line 41) | type InterruptEvent struct
  type Response (line 47) | type Response struct
  type Content (line 58) | type Content struct
  type ToolCall (line 72) | type ToolCall struct
  type Usage (line 80) | type Usage struct

FILE: api/service/hub_adaptor/bailian/adaptor.go
  type Adaptor (line 22) | type Adaptor struct
    method Init (line 27) | func (a *Adaptor) Init(meta *meta.Meta) {
    method GetRequestURL (line 30) | func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
    method SetupRequestHeader (line 39) | func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Request...
    method ConvertRequest (line 67) | func (a *Adaptor) ConvertRequest(c *gin.Context, relayMode int, reques...
    method IsRerankRequest (line 100) | func (a *Adaptor) IsRerankRequest(c *gin.Context, request *model.Gener...
    method DoRequest (line 172) | func (a *Adaptor) DoRequest(c *gin.Context, meta *meta.Meta, requestBo...
    method ConvertImageRequest (line 176) | func (a *Adaptor) ConvertImageRequest(request *model.ImageRequest) (an...
    method DoResponse (line 183) | func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, meta...
    method GetModelList (line 202) | func (a *Adaptor) GetModelList() []string {
    method GetChannelName (line 206) | func (a *Adaptor) GetChannelName() string {
  function ConvertRequest (line 114) | func ConvertRequest(textRequest model.GeneralOpenAIRequest, meta *meta.M...

FILE: api/service/hub_adaptor/bailian/main.go
  function StreamHandler (line 20) | func StreamHandler(c *gin.Context, resp *http.Response) (*model.ErrorWit...
  function Handler (line 99) | func Handler(c *gin.Context, resp *http.Response, promptTokens int, mode...
  function StreamResponseToOpenAI (line 132) | func StreamResponseToOpenAI(bailianResponse *Response) (*openai.ChatComp...
  function stopReasonAppBuilderOpenAI (line 152) | func stopReasonAppBuilderOpenAI(reason *string) string {
  function ResponseToOpenAI (line 168) | func ResponseToOpenAI(response *Response) *openai.TextResponse {

FILE: api/service/hub_adaptor/bailian/model.go
  type Request (line 3) | type Request struct
  type Input (line 8) | type Input struct
  type Parameters (line 15) | type Parameters struct
  type Response (line 19) | type Response struct
  type Output (line 25) | type Output struct
  type Usage (line 31) | type Usage struct
  type Models (line 35) | type Models
  type ErrorResponse (line 41) | type ErrorResponse struct

FILE: api/service/hub_adaptor/bailian/rerank.go
  type RerankRequest (line 16) | type RerankRequest struct
  method ConvertToRerankRequest (line 25) | func (a *Adaptor) ConvertToRerankRequest(request *RerankRequest) (*Baili...
  method GetRerankURL (line 54) | func (a *Adaptor) GetRerankURL() string {
  method DoRerankRequest (line 63) | func (a *Adaptor) DoRerankRequest(c *gin.Context, request *BailianRerank...
  method ProcessRerankResponse (line 90) | func (a *Adaptor) ProcessRerankResponse(resp *http.Response) (*OpenAIRer...
  method HandleRerankRequest (line 137) | func (a *Adaptor) HandleRerankRequest(c *gin.Context, request *RerankReq...
  function ParseRerankRequest (line 170) | func ParseRerankRequest(c *gin.Context) (*RerankRequest, error) {
  method IsRerankModel (line 189) | func (a *Adaptor) IsRerankModel(modelName string) bool {

FILE: api/service/hub_adaptor/bailian/rerank_model.go
  type BailianRerankRequest (line 4) | type BailianRerankRequest struct
  type BailianRerankInput (line 10) | type BailianRerankInput struct
  type BailianRerankParameters (line 15) | type BailianRerankParameters struct
  type BailianRerankResponse (line 21) | type BailianRerankResponse struct
  type BailianRerankOutput (line 27) | type BailianRerankOutput struct
  type BailianRerankResult (line 31) | type BailianRerankResult struct
  type BailianRerankDocument (line 37) | type BailianRerankDocument struct
  type RerankUsage (line 41) | type RerankUsage struct
  type OpenAIRerankResponse (line 46) | type OpenAIRerankResponse struct
  type OpenAIRerankResult (line 53) | type OpenAIRerankResult struct
  type OpenAIRerankDocument (line 60) | type OpenAIRerankDocument struct
  type OpenAIRerankUsage (line 64) | type OpenAIRerankUsage struct

FILE: api/service/hub_adaptor/coze/adaptor.go
  type Adaptor (line 17) | type Adaptor struct
    method Init (line 22) | func (a *Adaptor) Init(meta *meta.Meta) {
    method GetRequestURL (line 26) | func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
    method SetupRequestHeader (line 50) | func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Request...
    method ConvertRequest (line 56) | func (a *Adaptor) ConvertRequest(c *gin.Context, relayMode int, reques...
    method ConvertImageRequest (line 76) | func (a *Adaptor) ConvertImageRequest(request *model.ImageRequest) (an...
    method DoRequest (line 83) | func (a *Adaptor) DoRequest(c *gin.Context, meta *meta.Meta, requestBo...
    method DoResponse (line 87) | func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, meta...
    method GetModelList (line 107) | func (a *Adaptor) GetModelList() []string {
    method GetChannelName (line 111) | func (a *Adaptor) GetChannelName() string {

FILE: api/service/hub_adaptor/coze/constant/contenttype/define.go
  constant Text (line 4) | Text = "text"

FILE: api/service/hub_adaptor/coze/constant/event/define.go
  constant Message (line 4) | Message = "message"
  constant Done (line 5) | Done    = "done"
  constant Error (line 6) | Error   = "error"

FILE: api/service/hub_adaptor/coze/constant/messagetype/define.go
  constant Answer (line 4) | Answer   = "answer"
  constant FollowUp (line 5) | FollowUp = "follow_up"

FILE: api/service/hub_adaptor/coze/helper.go
  function event2StopReason (line 5) | func event2StopReason(e *string) string {

FILE: api/service/hub_adaptor/coze/main.go
  function stopReasonCoze2OpenAI (line 30) | func stopReasonCoze2OpenAI(reason *string) string {
  function ConvertRequest (line 46) | func ConvertRequest(textRequest model.GeneralOpenAIRequest, meta *meta.M...
  function StreamResponseCoze2OpenAI (line 141) | func StreamResponseCoze2OpenAI(cozeResponse *StreamResponseV3) (*openai....
  function ResponseCoze2OpenAI (line 159) | func ResponseCoze2OpenAI(cozeResponse *Response) (*openai.TextResponse, ...
  function StreamHandler (line 186) | func StreamHandler(c *gin.Context, resp *http.Response) (*model.ErrorWit...
  function Handler (line 267) | func Handler(c *gin.Context, resp *http.Response, promptTokens int, mode...
  function CozeUploadFile (line 307) | func CozeUploadFile(meta *meta.Meta, uploadFile *db_model.UploadFile, fi...

FILE: api/service/hub_adaptor/coze/model.go
  type Message (line 3) | type Message struct
  constant TypeQuestion (line 11) | TypeQuestion     = "question"
  constant TypeAnswer (line 12) | TypeAnswer       = "answer"
  constant TypeFunctionCall (line 13) | TypeFunctionCall = "function_call"
  constant TypeToolResponse (line 14) | TypeToolResponse = "tool_response"
  constant ContentTypeText (line 18) | ContentTypeText         = "text"
  constant ContentTypeObjectString (line 19) | ContentTypeObjectString = "object_string"
  type AdditionalMessage (line 22) | type AdditionalMessage struct
  type ErrorInformation (line 29) | type ErrorInformation struct
  type Request (line 34) | type Request struct
  type Response (line 41) | type Response struct
  type StreamResponse (line 48) | type StreamResponse struct
  type StreamResponseV3 (line 57) | type StreamResponseV3 struct
  type WorkflowRequest (line 70) | type WorkflowRequest struct
  type WorkflowResponse (line 75) | type WorkflowResponse struct
  type WorkflowExecutionData (line 84) | type WorkflowExecutionData struct
  type WorkflowError (line 91) | type WorkflowError struct
  constant WorkflowStatusSuccess (line 97) | WorkflowStatusSuccess = "success"
  constant WorkflowStatusFailed (line 98) | WorkflowStatusFailed  = "failed"
  constant WorkflowStatusRunning (line 99) | WorkflowStatusRunning = "running"

FILE: api/service/hub_adaptor/coze/workflow.go
  type WorkflowAdaptor (line 22) | type WorkflowAdaptor struct
    method Init (line 27) | func (a *WorkflowAdaptor) Init(meta *meta.Meta) {
    method GetRequestURL (line 31) | func (a *WorkflowAdaptor) GetRequestURL(meta *meta.Meta) (string, erro...
    method SetupRequestHeader (line 39) | func (a *WorkflowAdaptor) SetupRequestHeader(c *gin.Context, req *http...
    method ConvertRequest (line 45) | func (a *WorkflowAdaptor) ConvertRequest(c *gin.Context, relayMode int...
    method ConvertWorkflowRequest (line 101) | func (a *WorkflowAdaptor) ConvertWorkflowRequest(workflowID string, pa...
    method processWorkflowParameters (line 119) | func (a *WorkflowAdaptor) processWorkflowParameters(parameters map[str...
    method processParameterValue (line 142) | func (a *WorkflowAdaptor) processParameterValue(value interface{}) (in...
    method processFileIDString (line 178) | func (a *WorkflowAdaptor) processFileIDString(value string) (interface...
    method ConvertImageRequest (line 261) | func (a *WorkflowAdaptor) ConvertImageRequest(request *model.ImageRequ...
    method DoRequest (line 265) | func (a *WorkflowAdaptor) DoRequest(c *gin.Context, meta *meta.Meta, r...
    method DoResponse (line 269) | func (a *WorkflowAdaptor) DoResponse(c *gin.Context, resp *http.Respon...
    method GetModelList (line 334) | func (a *WorkflowAdaptor) GetModelList() []string {
    method GetChannelName (line 338) | func (a *WorkflowAdaptor) GetChannelName() string {
    method convertToOpenAIResponse (line 355) | func (a *WorkflowAdaptor) convertToOpenAIResponse(workflowResp *Workfl...
    method ConvertToWorkflowResponseData (line 440) | func (a *WorkflowAdaptor) ConvertToWorkflowResponseData(responseBody [...
    method parseWorkflowOutputData (line 470) | func (a *WorkflowAdaptor) parseWorkflowOutputData(rawData interface{})...
  function extractWorkflowIDFromModel (line 343) | func extractWorkflowIDFromModel(modelName string) string {
  function extractUnifiedOutput (line 419) | func extractUnifiedOutput(outputData map[string]interface{}) string {

FILE: api/service/hub_adaptor/custom/common.go
  function SetupCommonRequestHeader (line 21) | func SetupCommonRequestHeader(c *gin.Context, req *http.Request, meta *m...
  function DoRequestHelper (line 29) | func DoRequestHelper(a adaptor.Adaptor, c *gin.Context, meta *meta.Meta,...
  function DoRequest (line 89) | func DoRequest(c *gin.Context, req *http.Request) (*http.Response, error) {
  function GetBaseURL (line 102) | func GetBaseURL(baseUrl string) (string, error) {

FILE: api/service/hub_adaptor/custom/config.go
  type CustomConfig (line 3) | type CustomConfig struct
  type WorkflowParam (line 12) | type WorkflowParam struct

FILE: api/service/hub_adaptor/custom/workflow.go
  type WorkflowResponseData (line 4) | type WorkflowResponseData struct
  type WorkflowAdaptorResponse (line 13) | type WorkflowAdaptorResponse interface

FILE: api/service/hub_adaptor/dify/adaptor.go
  type Adaptor (line 25) | type Adaptor struct
    method Init (line 30) | func (a *Adaptor) Init(meta *meta.Meta) {
    method GetRequestURL (line 34) | func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
    method SetupRequestHeader (line 42) | func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Request...
    method ConvertRequest (line 48) | func (a *Adaptor) ConvertRequest(c *gin.Context, relayMode int, reques...
    method DoRequest (line 142) | func (a *Adaptor) DoRequest(c *gin.Context, meta *meta.Meta, requestBo...
    method ConvertImageRequest (line 146) | func (a *Adaptor) ConvertImageRequest(request *model.ImageRequest) (an...
    method DoResponse (line 153) | func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, meta...
    method GetModelList (line 227) | func (a *Adaptor) GetModelList() []string {
    method GetChannelName (line 231) | func (a *Adaptor) GetChannelName() string {
  function ConvertRequest (line 56) | func ConvertRequest(textRequest model.GeneralOpenAIRequest, meta *meta.M...
  function Handler (line 172) | func Handler(c *gin.Context, resp *http.Response, promptTokens int, mode...
  function ResponseDify2OpenAI (line 205) | func ResponseDify2OpenAI(difyResponse *BlockResponse) *openai.TextRespon...
  function DIFYUploadFile (line 235) | func DIFYUploadFile(meta *meta.Meta, uploadFile *db_model.UploadFile, fi...

FILE: api/service/hub_adaptor/dify/info.go
  type DifyInfoAdaptor (line 15) | type DifyInfoAdaptor struct
    method GetAppInfo (line 87) | func (a *DifyInfoAdaptor) GetAppInfo(meta *meta.Meta) (*AppInfoRespons...
    method GetAppParameters (line 138) | func (a *DifyInfoAdaptor) GetAppParameters(meta *meta.Meta) (*AppParam...
    method buildInfoURL (line 189) | func (a *DifyInfoAdaptor) buildInfoURL(baseURL string) (string, error) {
    method buildParametersURL (line 199) | func (a *DifyInfoAdaptor) buildParametersURL(baseURL string) (string, ...
  type AppInfoResponse (line 18) | type AppInfoResponse struct
  type AppParametersResponse (line 27) | type AppParametersResponse struct
  type UserInputFormItem (line 34) | type UserInputFormItem struct
  type TextInputConfig (line 41) | type TextInputConfig struct
  type ParagraphConfig (line 49) | type ParagraphConfig struct
  type SelectConfig (line 57) | type SelectConfig struct
  type FileUploadConfig (line 66) | type FileUploadConfig struct
  type ImageUploadConfig (line 71) | type ImageUploadConfig struct
  type SystemParametersConfig (line 79) | type SystemParametersConfig struct
  function maskAPIKey (line 209) | func maskAPIKey(apiKey string) string {

FILE: api/service/hub_adaptor/dify/main.go
  function StreamHandler (line 18) | func StreamHandler(c *gin.Context, resp *http.Response) (*model.ErrorWit...
  function StreamResponseDifyOpenAI (line 75) | func StreamResponseDifyOpenAI(difyResponse *StreamResponse) (*openai.Cha...
  function BlockingResponseDifyOpenAI (line 95) | func BlockingResponseDifyOpenAI(difyResponse *BlockResponse) (*openai.Ch...
  function stopReasonDifyOpenAI (line 109) | func stopReasonDifyOpenAI(reason *string) string {
  type File (line 125) | type File struct
  constant ResponseModeStream (line 133) | ResponseModeStream = "streaming"
  constant ResponseModeBlock (line 134) | ResponseModeBlock  = "blocking"
  type Request (line 137) | type Request struct

FILE: api/service/hub_adaptor/dify/model.go
  type StreamResponse (line 3) | type StreamResponse struct
  type Response (line 13) | type Response struct
  type Message (line 21) | type Message struct
  type BlockResponse (line 28) | type BlockResponse struct
  type Metadata (line 39) | type Metadata struct
  type Usage (line 43) | type Usage struct
  type DIFYUploadResponse (line 58) | type DIFYUploadResponse struct

FILE: api/service/hub_adaptor/dify/workflow.go
  type DifyWorkflowAdaptor (line 23) | type DifyWorkflowAdaptor struct
    method Init (line 57) | func (a *DifyWorkflowAdaptor) Init(meta *meta.Meta) {
    method GetRequestURL (line 61) | func (a *DifyWorkflowAdaptor) GetRequestURL(meta *meta.Meta) (string, ...
    method SetupRequestHeader (line 73) | func (a *DifyWorkflowAdaptor) SetupRequestHeader(c *gin.Context, req *...
    method ConvertWorkflowRequest (line 80) | func (a *DifyWorkflowAdaptor) ConvertWorkflowRequest(workflowID string...
    method processWorkflowParameters (line 102) | func (a *DifyWorkflowAdaptor) processWorkflowParameters(parameters map...
    method processParameterValue (line 124) | func (a *DifyWorkflowAdaptor) processParameterValue(value interface{})...
    method processFileIDString (line 160) | func (a *DifyWorkflowAdaptor) processFileIDString(value string) (inter...
    method getDifyFileType (line 240) | func (a *DifyWorkflowAdaptor) getDifyFileType(mimeType, extension stri...
    method getUserID (line 286) | func (a *DifyWorkflowAdaptor) getUserID() string {
    method DoRequest (line 294) | func (a *DifyWorkflowAdaptor) DoRequest(c *gin.Context, meta *meta.Met...
    method ProcessStreamingResponse (line 350) | func (a *DifyWorkflowAdaptor) ProcessStreamingResponse(resp *http.Resp...
    method ConvertImageRequest (line 479) | func (a *DifyWorkflowAdaptor) ConvertImageRequest(request *model.Image...
  type DifyWorkflowRequest (line 29) | type DifyWorkflowRequest struct
  type DifyFileInput (line 36) | type DifyFileInput struct
  type DifyWorkflowEvent (line 43) | type DifyWorkflowEvent struct
  type DifyWorkflowResponse (line 51) | type DifyWorkflowResponse struct
  function DifyUploadFile (line 474) | func DifyUploadFile(meta *meta.Meta, uploadFile *db_model.UploadFile, fi...

FILE: api/service/hub_adaptor/fastgpt/workflow.go
  type FastGPTWorkflowAdaptor (line 21) | type FastGPTWorkflowAdaptor struct
    method Init (line 50) | func (a *FastGPTWorkflowAdaptor) Init(meta *meta.Meta) {
    method GetRequestURL (line 56) | func (a *FastGPTWorkflowAdaptor) GetRequestURL(meta *meta.Meta) (strin...
    method ConvertWorkflowToWorkflowRequest (line 87) | func (a *FastGPTWorkflowAdaptor) ConvertWorkflowToWorkflowRequest(para...
    method processFileParameters (line 105) | func (a *FastGPTWorkflowAdaptor) processFileParameters(parameters map[...
    method processFileParameter (line 130) | func (a *FastGPTWorkflowAdaptor) processFileParameter(fileParam string...
    method DoRequest (line 196) | func (a *FastGPTWorkflowAdaptor) DoRequest(c *gin.Context, meta *meta....
    method ProcessWorkflowResponse (line 251) | func (a *FastGPTWorkflowAdaptor) ProcessWorkflowResponse(resp *http.Re...
    method extractWorkflowOutput (line 286) | func (a *FastGPTWorkflowAdaptor) extractWorkflowOutput(responseData []...
    method ExtractWorkflowOutputForTest (line 314) | func (a *FastGPTWorkflowAdaptor) ExtractWorkflowOutputForTest(response...
  type FastGPTWorkflowRequest (line 28) | type FastGPTWorkflowRequest struct
  type FastGPTWorkflowResponse (line 35) | type FastGPTWorkflowResponse struct
  type ModuleResponse (line 40) | type ModuleResponse struct
  function standardizeBaseURL (line 62) | func standardizeBaseURL(baseURL string) string {
  function isImageFile (line 185) | func isImageFile(extension string) bool {
  function maskAPIKey (line 319) | func maskAPIKey(apiKey string) string {

FILE: api/service/hub_adaptor/n8n/adaptor.go
  type Adaptor (line 14) | type Adaptor struct
    method Init (line 19) | func (a *Adaptor) Init(meta *meta.Meta) {
    method GetRequestURL (line 23) | func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
    method SetupRequestHeader (line 32) | func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Request...
    method ConvertRequest (line 41) | func (a *Adaptor) ConvertRequest(c *gin.Context, relayMode int, reques...
    method ConvertImageRequest (line 46) | func (a *Adaptor) ConvertImageRequest(request *model.ImageRequest) (an...
    method DoRequest (line 50) | func (a *Adaptor) DoRequest(c *gin.Context, meta *meta.Meta, requestBo...
    method DoResponse (line 54) | func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, meta...
    method GetModelList (line 65) | func (a *Adaptor) GetModelList() []string {
    method GetChannelName (line 69) | func (a *Adaptor) GetChannelName() string {

FILE: api/service/hub_adaptor/n8n/main.go
  function ProcessN8nWorkflowResponse (line 21) | func ProcessN8nWorkflowResponse(c *gin.Context, resp *http.Response, met...
  function StreamHandler (line 35) | func StreamHandler(c *gin.Context, resp *http.Response) (*model.ErrorWit...
  function Handler (line 75) | func Handler(c *gin.Context, resp *http.Response, promptTokens int, mode...
  function ResponseN8nToOpenAI (line 109) | func ResponseN8nToOpenAI(workflowResponse *custom.WorkflowResponseData, ...
  function ValidateN8nWorkflowID (line 155) | func ValidateN8nWorkflowID(workflowID string) bool {

FILE: api/service/hub_adaptor/n8n/model.go
  type N8nWorkflowRequest (line 4) | type N8nWorkflowRequest
  type N8nWorkflowResponse (line 7) | type N8nWorkflowResponse
  type N8nWorkflowItem (line 10) | type N8nWorkflowItem struct
  type N8nErrorResponse (line 18) | type N8nErrorResponse struct

FILE: api/service/hub_adaptor/n8n/workflow.go
  type N8nWorkflowAdaptor (line 21) | type N8nWorkflowAdaptor struct
    method Init (line 26) | func (a *N8nWorkflowAdaptor) Init(meta *meta.Meta) {
    method GetRequestURL (line 30) | func (a *N8nWorkflowAdaptor) GetRequestURL(meta *meta.Meta) (string, e...
    method SetupRequestHeader (line 69) | func (a *N8nWorkflowAdaptor) SetupRequestHeader(c *gin.Context, req *h...
    method ConvertWorkflowRequest (line 81) | func (a *N8nWorkflowAdaptor) ConvertWorkflowRequest(workflowID string,...
    method processWorkflowParameters (line 99) | func (a *N8nWorkflowAdaptor) processWorkflowParameters(parameters map[...
    method processParameterValue (line 121) | func (a *N8nWorkflowAdaptor) processParameterValue(value interface{}) ...
    method processFileIDString (line 157) | func (a *N8nWorkflowAdaptor) processFileIDString(value string) (interf...
    method DoRequest (line 213) | func (a *N8nWorkflowAdaptor) DoRequest(c *gin.Context, meta *meta.Meta...
    method ProcessResponse (line 272) | func (a *N8nWorkflowAdaptor) ProcessResponse(resp *http.Response) (*cu...
    method convertN8nResponseToOutputData (line 311) | func (a *N8nWorkflowAdaptor) convertN8nResponseToOutputData(n8nRespons...
  function extractWorkflowID (line 347) | func extractWorkflowID(modelName string) string {
  function maskAPIKey (line 358) | func maskAPIKey(apiKey string) string {

FILE: api/service/hub_adaptor/openai/adaptor.go
  type Adaptor (line 28) | type Adaptor struct
    method Init (line 33) | func (a *Adaptor) Init(meta *meta.Meta) {
    method GetRequestURL (line 37) | func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
    method SetupRequestHeader (line 75) | func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Request...
    method ConvertRequest (line 89) | func (a *Adaptor) ConvertRequest(c *gin.Context, relayMode int, reques...
    method ConvertImageRequest (line 105) | func (a *Adaptor) ConvertImageRequest(request *model.ImageRequest) (an...
    method DoRequest (line 112) | func (a *Adaptor) DoRequest(c *gin.Context, meta *meta.Meta, requestBo...
    method DoResponse (line 116) | func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, meta...
    method GetModelList (line 138) | func (a *Adaptor) GetModelList() []string {
    method GetChannelName (line 143) | func (a *Adaptor) GetChannelName() string {
    method HandlerUploadFileMessages (line 148) | func (a *Adaptor) HandlerUploadFileMessages(request *model.GeneralOpen...
  function GetFileFastGptTypeString (line 237) | func GetFileFastGptTypeString(extension string) string {

FILE: api/service/hub_adaptor/openai/compatible.go
  function GetCompatibleChannelMeta (line 39) | func GetCompatibleChannelMeta(channelType int) (string, []string) {

FILE: api/service/hub_adaptor/openai/helper.go
  function ResponseText2Usage (line 11) | func ResponseText2Usage(responseText string, modelName string, promptTok...
  function GetFullRequestURL (line 19) | func GetFullRequestURL(baseURL string, requestURL string, channelType in...

FILE: api/service/hub_adaptor/openai/image.go
  function ImageHandler (line 12) | func ImageHandler(c *gin.Context, resp *http.Response) (*model.ErrorWith...

FILE: api/service/hub_adaptor/openai/main.go
  constant dataPrefix (line 22) | dataPrefix       = "data: "
  constant done (line 23) | done             = "[DONE]"
  constant dataPrefixLength (line 24) | dataPrefixLength = len(dataPrefix)
  function StreamHandler (line 27) | func StreamHandler(c *gin.Context, resp *http.Response, relayMode int) (...
  function Handler (line 109) | func Handler(c *gin.Context, resp *http.Response, promptTokens int, mode...

FILE: api/service/hub_adaptor/openai/model.go
  type TextContent (line 5) | type TextContent struct
  type ImageContent (line 10) | type ImageContent struct
  type ChatRequest (line 15) | type ChatRequest struct
  type TextRequest (line 21) | type TextRequest struct
  type ImageRequest (line 30) | type ImageRequest struct
  type WhisperJSONResponse (line 41) | type WhisperJSONResponse struct
  type WhisperVerboseJSONResponse (line 45) | type WhisperVerboseJSONResponse struct
  type Segment (line 53) | type Segment struct
  type TextToSpeechRequest (line 66) | type TextToSpeechRequest struct
  type UsageOrResponseText (line 74) | type UsageOrResponseText struct
  type SlimTextResponse (line 79) | type SlimTextResponse struct
  type TextResponseChoice (line 85) | type TextResponseChoice struct
  type TextResponse (line 91) | type TextResponse struct
  type EmbeddingResponseItem (line 100) | type EmbeddingResponseItem struct
  type EmbeddingResponse (line 106) | type EmbeddingResponse struct
  type ImageData (line 113) | type ImageData struct
  type ImageResponse (line 119) | type ImageResponse struct
  type ChatCompletionsStreamResponseChoice (line 125) | type ChatCompletionsStreamResponseChoice struct
  type ChatCompletionsStreamResponse (line 131) | type ChatCompletionsStreamResponse struct
  type CompletionsStreamResponse (line 140) | type CompletionsStreamResponse struct
  type FastGptFileContent (line 147) | type FastGptFileContent struct

FILE: api/service/hub_adaptor/openai/token.go
  function InitTokenEncoders (line 22) | func InitTokenEncoders() {
  function getTokenEncoder (line 52) | func getTokenEncoder(model string) *tiktoken.Tiktoken {
  function getTokenNum (line 69) | func getTokenNum(tokenEncoder *tiktoken.Tiktoken, text string) int {
  function CountTokenMessages (line 76) | func CountTokenMessages(messages []model.Message, model string) int {
  constant lowDetailCost (line 137) | lowDetailCost         = 85
  constant highDetailCostPerTile (line 138) | highDetailCostPerTile = 170
  constant additionalCost (line 139) | additionalCost        = 85
  constant gpt4oMiniLowDetailCost (line 141) | gpt4oMiniLowDetailCost  = 2833
  constant gpt4oMiniHighDetailCost (line 142) | gpt4oMiniHighDetailCost = 5667
  constant gpt4oMiniAdditionalCost (line 143) | gpt4oMiniAdditionalCost = 2833
  function countImageTokens (line 148) | func countImageTokens(url string, detail string, model string) (_ int, e...
  function CountTokenInput (line 214) | func CountTokenInput(input any, model string) int {
  function CountTokenText (line 228) | func CountTokenText(text string, model string) int {
  function CountToken (line 233) | func CountToken(text string) int {

FILE: api/service/hub_adaptor/openai/util.go
  function ErrorWrapper (line 11) | func ErrorWrapper(err error, code string, statusCode int) *model.ErrorWi...

FILE: api/service/hub_adaptor/tencent/adaptor.go
  type Adaptor (line 14) | type Adaptor struct
    method Init (line 19) | func (a *Adaptor) Init(meta *meta.Meta) {
    method GetRequestURL (line 23) | func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
    method SetupRequestHeader (line 32) | func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Request...
    method ConvertRequest (line 39) | func (a *Adaptor) ConvertRequest(c *gin.Context, relayMode int, reques...
    method ConvertImageRequest (line 51) | func (a *Adaptor) ConvertImageRequest(request *model.ImageRequest) (an...
    method DoRequest (line 56) | func (a *Adaptor) DoRequest(c *gin.Context, meta *meta.Meta, requestBo...
    method DoResponse (line 60) | func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, meta...
    method GetModelList (line 83) | func (a *Adaptor) GetModelList() []string {
    method GetChannelName (line 87) | func (a *Adaptor) GetChannelName() string {

FILE: api/service/hub_adaptor/tencent/constants.go
  constant TencentBaseURL (line 16) | TencentBaseURL = "https://wss.lke.cloud.tencent.com"

FILE: api/service/hub_adaptor/tencent/helper.go
  function ConvertRequest (line 16) | func ConvertRequest(request model.GeneralOpenAIRequest, conversationID i...
  function generateUUID (line 59) | func generateUUID() string {
  function ConvertResponse (line 71) | func ConvertResponse(tencentResp *TencentResponse, modelName string) *op...
  function ConvertStreamResponse (line 98) | func ConvertStreamResponse(data string, modelName string, previousConten...
  function IsStreamEnd (line 199) | func IsStreamEnd(event string) bool {

FILE: api/service/hub_adaptor/tencent/main.go
  function Handler (line 19) | func Handler(c *gin.Context, resp *http.Response) (*model.ErrorWithStatu...
  function StreamHandler (line 40) | func StreamHandler(c *gin.Context, meta *meta.Meta, resp *http.Response)...

FILE: api/service/hub_adaptor/tencent/model.go
  type TencentRequest (line 4) | type TencentRequest struct
  type VisitorLabel (line 23) | type VisitorLabel struct
  type FileInfo (line 28) | type FileInfo struct
  type TencentResponse (line 37) | type TencentResponse struct
  type TencentResponsePayload (line 43) | type TencentResponsePayload struct
  type TencentKnowledge (line 65) | type TencentKnowledge struct
  type TencentQuoteInfo (line 72) | type TencentQuoteInfo struct
  type TencentStreamResponse (line 78) | type TencentStreamResponse struct
  type TencentErrorResponse (line 84) | type TencentErrorResponse struct
  type TencentErrorInfo (line 89) | type TencentErrorInfo struct

FILE: api/service/hub_adaptor/tencent/sdk/client.go
  constant APIVersion (line 26) | APIVersion = "2023-11-30"
  type Client (line 28) | type Client struct
    method CheckAttributeLabelExist (line 68) | func (c *Client) CheckAttributeLabelExist(request *CheckAttributeLabel...
    method CheckAttributeLabelExistWithContext (line 74) | func (c *Client) CheckAttributeLabelExistWithContext(ctx context.Conte...
    method CheckAttributeLabelRefer (line 111) | func (c *Client) CheckAttributeLabelRefer(request *CheckAttributeLabel...
    method CheckAttributeLabelReferWithContext (line 117) | func (c *Client) CheckAttributeLabelReferWithContext(ctx context.Conte...
    method CreateApp (line 154) | func (c *Client) CreateApp(request *CreateAppRequest) (response *Creat...
    method CreateAppWithContext (line 160) | func (c *Client) CreateAppWithContext(ctx context.Context, request *Cr...
    method CreateAttributeLabel (line 201) | func (c *Client) CreateAttributeLabel(request *CreateAttributeLabelReq...
    method CreateAttributeLabelWithContext (line 211) | func (c *Client) CreateAttributeLabelWithContext(ctx context.Context, ...
    method CreateDocCate (line 252) | func (c *Client) CreateDocCate(request *CreateDocCateRequest) (respons...
    method CreateDocCateWithContext (line 262) | func (c *Client) CreateDocCateWithContext(ctx context.Context, request...
    method CreateQA (line 303) | func (c *Client) CreateQA(request *CreateQARequest) (response *CreateQ...
    method CreateQAWithContext (line 313) | func (c *Client) CreateQAWithContext(ctx context.Context, request *Cre...
    method CreateQACate (line 354) | func (c *Client) CreateQACate(request *CreateQACateRequest) (response ...
    method CreateQACateWithContext (line 364) | func (c *Client) CreateQACateWithContext(ctx context.Context, request ...
    method CreateRejectedQuestion (line 405) | func (c *Client) CreateRejectedQuestion(request *CreateRejectedQuestio...
    method CreateRejectedQuestionWithContext (line 415) | func (c *Client) CreateRejectedQuestionWithContext(ctx context.Context...
    method CreateRelease (line 456) | func (c *Client) CreateRelease(request *CreateReleaseRequest) (respons...
    method CreateReleaseWithContext (line 466) | func (c *Client) CreateReleaseWithContext(ctx context.Context, request...
    method CreateSharedKnowledge (line 507) | func (c *Client) CreateSharedKnowledge(request *CreateSharedKnowledgeR...
    method CreateSharedKnowledgeWithContext (line 517) | func (c *Client) CreateSharedKnowledgeWithContext(ctx context.Context,...
    method CreateVar (line 559) | func (c *Client) CreateVar(request *CreateVarRequest) (response *Creat...
    method CreateVarWithContext (line 570) | func (c *Client) CreateVarWithContext(ctx context.Context, request *Cr...
    method CreateWorkflowRun (line 614) | func (c *Client) CreateWorkflowRun(request *CreateWorkflowRunRequest) ...
    method CreateWorkflowRunWithContext (line 627) | func (c *Client) CreateWorkflowRunWithContext(ctx context.Context, req...
    method DeleteAgent (line 668) | func (c *Client) DeleteAgent(request *DeleteAgentRequest) (response *D...
    method DeleteAgentWithContext (line 678) | func (c *Client) DeleteAgentWithContext(ctx context.Context, request *...
    method DeleteApp (line 719) | func (c *Client) DeleteApp(request *DeleteAppRequest) (response *Delet...
    method DeleteAppWithContext (line 729) | func (c *Client) DeleteAppWithContext(ctx context.Context, request *De...
    method DeleteAttributeLabel (line 770) | func (c *Client) DeleteAttributeLabel(request *DeleteAttributeLabelReq...
    method DeleteAttributeLabelWithContext (line 780) | func (c *Client) DeleteAttributeLabelWithContext(ctx context.Context, ...
    method DeleteDoc (line 821) | func (c *Client) DeleteDoc(request *DeleteDocRequest) (response *Delet...
    method DeleteDocWithContext (line 831) | func (c *Client) DeleteDocWithContext(ctx context.Context, request *De...
    method DeleteDocCate (line 872) | func (c *Client) DeleteDocCate(request *DeleteDocCateRequest) (respons...
    method DeleteDocCateWithContext (line 882) | func (c *Client) DeleteDocCateWithContext(ctx context.Context, request...
    method DeleteQA (line 923) | func (c *Client) DeleteQA(request *DeleteQARequest) (response *DeleteQ...
    method DeleteQAWithContext (line 933) | func (c *Client) DeleteQAWithContext(ctx context.Context, request *Del...
    method DeleteQACate (line 974) | func (c *Client) DeleteQACate(request *DeleteQACateRequest) (response ...
    method DeleteQACateWithContext (line 984) | func (c *Client) DeleteQACateWithContext(ctx context.Context, request ...
    method DeleteRejectedQuestion (line 1025) | func (c *Client) DeleteRejectedQuestion(request *DeleteRejectedQuestio...
    method DeleteRejectedQuestionWithContext (line 1035) | func (c *Client) DeleteRejectedQuestionWithContext(ctx context.Context...
    method DeleteSharedKnowledge (line 1076) | func (c *Client) DeleteSharedKnowledge(request *DeleteSharedKnowledgeR...
    method DeleteSharedKnowledgeWithContext (line 1086) | func (c *Client) DeleteSharedKnowledgeWithContext(ctx context.Context,...
    method DeleteVar (line 1127) | func (c *Client) DeleteVar(request *DeleteVarRequest) (response *Delet...
    method DeleteVarWithContext (line 1137) | func (c *Client) DeleteVarWithContext(ctx context.Context, request *De...
    method DescribeApp (line 1178) | func (c *Client) DescribeApp(request *DescribeAppRequest) (response *D...
    method DescribeAppWithContext (line 1188) | func (c *Client) DescribeAppWithContext(ctx context.Context, request *...
    method DescribeAppAgentList (line 1229) | func (c *Client) DescribeAppAgentList(request *DescribeAppAgentListReq...
    method DescribeAppAgentListWithContext (line 1239) | func (c *Client) DescribeAppAgentListWithContext(ctx context.Context, ...
    method DescribeAttributeLabel (line 1280) | func (c *Client) DescribeAttributeLabel(request *DescribeAttributeLabe...
    method DescribeAttributeLabelWithContext (line 1290) | func (c *Client) DescribeAttributeLabelWithContext(ctx context.Context...
    method DescribeCallStatsGraph (line 1331) | func (c *Client) DescribeCallStatsGraph(request *DescribeCallStatsGrap...
    method DescribeCallStatsGraphWithContext (line 1341) | func (c *Client) DescribeCallStatsGraphWithContext(ctx context.Context...
    method DescribeConcurrencyUsage (line 1382) | func (c *Client) DescribeConcurrencyUsage(request *DescribeConcurrency...
    method DescribeConcurrencyUsageWithContext (line 1392) | func (c *Client) DescribeConcurrencyUsageWithContext(ctx context.Conte...
    method DescribeConcurrencyUsageGraph (line 1433) | func (c *Client) DescribeConcurrencyUsageGraph(request *DescribeConcur...
    method DescribeConcurrencyUsageGraphWithContext (line 1443) | func (c *Client) DescribeConcurrencyUsageGraphWithContext(ctx context....
    method DescribeDoc (line 1484) | func (c *Client) DescribeDoc(request *DescribeDocRequest) (response *D...
    method DescribeDocWithContext (line 1494) | func (c *Client) DescribeDocWithContext(ctx context.Context, request *...
    method DescribeKnowledgeUsage (line 1535) | func (c *Client) DescribeKnowledgeUsage(request *DescribeKnowledgeUsag...
    method DescribeKnowledgeUsageWithContext (line 1545) | func (c *Client) DescribeKnowledgeUsageWithContext(ctx context.Context...
    method DescribeKnowledgeUsagePieGraph (line 1586) | func (c *Client) DescribeKnowledgeUsagePieGraph(request *DescribeKnowl...
    method DescribeKnowledgeUsagePieGraphWithContext (line 1596) | func (c *Client) DescribeKnowledgeUsagePieGraphWithContext(ctx context...
    method DescribeNodeRun (line 1638) | func (c *Client) DescribeNodeRun(request *DescribeNodeRunRequest) (res...
    method DescribeNodeRunWithContext (line 1649) | func (c *Client) DescribeNodeRunWithContext(ctx context.Context, reque...
    method DescribeQA (line 1691) | func (c *Client) DescribeQA(request *DescribeQARequest) (response *Des...
    method DescribeQAWithContext (line 1702) | func (c *Client) DescribeQAWithContext(ctx context.Context, request *D...
    method DescribeRefer (line 1744) | func (c *Client) DescribeRefer(request *DescribeReferRequest) (respons...
    method DescribeReferWithContext (line 1755) | func (c *Client) DescribeReferWithContext(ctx context.Context, request...
    method DescribeRelease (line 1797) | func (c *Client) DescribeRelease(request *DescribeReleaseRequest) (res...
    method DescribeReleaseWithContext (line 1808) | func (c *Client) DescribeReleaseWithContext(ctx context.Context, reque...
    method DescribeReleaseInfo (line 1850) | func (c *Client) DescribeReleaseInfo(request *DescribeReleaseInfoReque...
    method DescribeReleaseInfoWithContext (line 1861) | func (c *Client) DescribeReleaseInfoWithContext(ctx context.Context, r...
    method DescribeRobotBizIDByAppKey (line 1902) | func (c *Client) DescribeRobotBizIDByAppKey(request *DescribeRobotBizI...
    method DescribeRobotBizIDByAppKeyWithContext (line 1912) | func (c *Client) DescribeRobotBizIDByAppKeyWithContext(ctx context.Con...
    method DescribeSearchStatsGraph (line 1953) | func (c *Client) DescribeSearchStatsGraph(request *DescribeSearchStats...
    method DescribeSearchStatsGraphWithContext (line 1963) | func (c *Client) DescribeSearchStatsGraphWithContext(ctx context.Conte...
    method DescribeSegments (line 2004) | func (c *Client) DescribeSegments(request *DescribeSegmentsRequest) (r...
    method DescribeSegmentsWithContext (line 2014) | func (c *Client) DescribeSegmentsWithContext(ctx context.Context, requ...
    method DescribeSharedKnowledge (line 2055) | func (c *Client) DescribeSharedKnowledge(request *DescribeSharedKnowle...
    method DescribeSharedKnowledgeWithContext (line 2065) | func (c *Client) DescribeSharedKnowledgeWithContext(ctx context.Contex...
    method DescribeStorageCredential (line 2106) | func (c *Client) DescribeStorageCredential(request *DescribeStorageCre...
    method DescribeStorageCredentialWithContext (line 2116) | func (c *Client) DescribeStorageCredentialWithContext(ctx context.Cont...
    method DescribeTokenUsage (line 2157) | func (c *Client) DescribeTokenUsage(request *DescribeTokenUsageRequest...
    method DescribeTokenUsageWithContext (line 2167) | func (c *Client) DescribeTokenUsageWithContext(ctx context.Context, re...
    method DescribeTokenUsageGraph (line 2208) | func (c *Client) DescribeTokenUsageGraph(request *DescribeTokenUsageGr...
    method DescribeTokenUsageGraphWithContext (line 2218) | func (c *Client) DescribeTokenUsageGraphWithContext(ctx context.Contex...
    method DescribeUnsatisfiedReplyContext (line 2260) | func (c *Client) DescribeUnsatisfiedReplyContext(request *DescribeUnsa...
    method DescribeUnsatisfiedReplyContextWithContext (line 2271) | func (c *Client) DescribeUnsatisfiedReplyContextWithContext(ctx contex...
    method DescribeWorkflowRun (line 2313) | func (c *Client) DescribeWorkflowRun(request *DescribeWorkflowRunReque...
    method DescribeWorkflowRunWithContext (line 2324) | func (c *Client) DescribeWorkflowRunWithContext(ctx context.Context, r...
    method ExportAttributeLabel (line 2366) | func (c *Client) ExportAttributeLabel(request *ExportAttributeLabelReq...
    method ExportAttributeLabelWithContext (line 2377) | func (c *Client) ExportAttributeLabelWithContext(ctx context.Context, ...
    method ExportQAList (line 2419) | func (c *Client) ExportQAList(request *ExportQAListRequest) (response ...
    method ExportQAListWithContext (line 2430) | func (c *Client) ExportQAListWithContext(ctx context.Context, request ...
    method ExportUnsatisfiedReply (line 2472) | func (c *Client) ExportUnsatisfiedReply(request *ExportUnsatisfiedRepl...
    method ExportUnsatisfiedReplyWithContext (line 2483) | func (c *Client) ExportUnsatisfiedReplyWithContext(ctx context.Context...
    method GenerateQA (line 2524) | func (c *Client) GenerateQA(request *GenerateQARequest) (response *Gen...
    method GenerateQAWithContext (line 2534) | func (c *Client) GenerateQAWithContext(ctx context.Context, request *G...
    method GetAnswerTypeDataCount (line 2576) | func (c *Client) GetAnswerTypeDataCount(request *GetAnswerTypeDataCoun...
    method GetAnswerTypeDataCountWithContext (line 2587) | func (c *Client) GetAnswerTypeDataCountWithContext(ctx context.Context...
    method GetAppKnowledgeCount (line 2628) | func (c *Client) GetAppKnowledgeCount(request *GetAppKnowledgeCountReq...
    method GetAppKnowledgeCountWithContext (line 2638) | func (c *Client) GetAppKnowledgeCountWithContext(ctx context.Context, ...
    method GetAppSecret (line 2679) | func (c *Client) GetAppSecret(request *GetAppSecretRequest) (response ...
    method GetAppSecretWithContext (line 2689) | func (c *Client) GetAppSecretWithContext(ctx context.Context, request ...
    method GetDocPreview (line 2730) | func (c *Client) GetDocPreview(request *GetDocPreviewRequest) (respons...
    method GetDocPreviewWithContext (line 2740) | func (c *Client) GetDocPreviewWithContext(ctx context.Context, request...
    method GetLikeDataCount (line 2782) | func (c *Client) GetLikeDataCount(request *GetLikeDataCountRequest) (r...
    method GetLikeDataCountWithContext (line 2793) | func (c *Client) GetLikeDataCountWithContext(ctx context.Context, requ...
    method GetMsgRecord (line 2837) | func (c *Client) GetMsgRecord(request *GetMsgRecordRequest) (response ...
    method GetMsgRecordWithContext (line 2850) | func (c *Client) GetMsgRecordWithContext(ctx context.Context, request ...
    method GetTaskStatus (line 2892) | func (c *Client) GetTaskStatus(request *GetTaskStatusRequest) (respons...
    method GetTaskStatusWithContext (line 2903) | func (c *Client) GetTaskStatusWithContext(ctx context.Context, request...
    method GetVarList (line 2945) | func (c *Client) GetVarList(request *GetVarListRequest) (response *Get...
    method GetVarListWithContext (line 2956) | func (c *Client) GetVarListWithContext(ctx context.Context, request *G...
    method GetWsToken (line 2997) | func (c *Client) GetWsToken(request *GetWsTokenRequest) (response *Get...
    method GetWsTokenWithContext (line 3007) | func (c *Client) GetWsTokenWithContext(ctx context.Context, request *G...
    method GroupDoc (line 3048) | func (c *Client) GroupDoc(request *GroupDocRequest) (response *GroupDo...
    method GroupDocWithContext (line 3058) | func (c *Client) GroupDocWithContext(ctx context.Context, request *Gro...
    method GroupQA (line 3099) | func (c *Client) GroupQA(request *GroupQARequest) (response *GroupQARe...
    method GroupQAWithContext (line 3109) | func (c *Client) GroupQAWithContext(ctx context.Context, request *Grou...
    method IgnoreUnsatisfiedReply (line 3150) | func (c *Client) IgnoreUnsatisfiedReply(request *IgnoreUnsatisfiedRepl...
    method IgnoreUnsatisfiedReplyWithContext (line 3160) | func (c *Client) IgnoreUnsatisfiedReplyWithContext(ctx context.Context...
    method IsTransferIntent (line 3201) | func (c *Client) IsTransferIntent(request *IsTransferIntentRequest) (r...
    method IsTransferIntentWithContext (line 3211) | func (c *Client) IsTransferIntentWithContext(ctx context.Context, requ...
    method ListApp (line 3252) | func (c *Client) ListApp(request *ListAppRequest) (response *ListAppRe...
    method ListAppWithContext (line 3262) | func (c *Client) ListAppWithContext(ctx context.Context, request *List...
    method ListAppKnowledgeDetail (line 3303) | func (c *Client) ListAppKnowledgeDetail(request *ListAppKnowledgeDetai...
    method ListAppKnowledgeDetailWithContext (line 3313) | func (c *Client) ListAppKnowledgeDetailWithContext(ctx context.Context...
    method ListAttributeLabel (line 3354) | func (c *Client) ListAttributeLabel(request *ListAttributeLabelRequest...
    method ListAttributeLabelWithContext (line 3364) | func (c *Client) ListAttributeLabelWithContext(ctx context.Context, re...
    method ListChannel (line 3405) | func (c *Client) ListChannel(request *ListChannelRequest) (response *L...
    method ListChannelWithContext (line 3415) | func (c *Client) ListChannelWithContext(ctx context.Context, request *...
    method ListDoc (line 3456) | func (c *Client) ListDoc(request *ListDocRequest) (response *ListDocRe...
    method ListDocWithContext (line 3466) | func (c *Client) ListDocWithContext(ctx context.Context, request *List...
    method ListDocCate (line 3507) | func (c *Client) ListDocCate(request *ListDocCateRequest) (response *L...
    method ListDocCateWithContext (line 3517) | func (c *Client) ListDocCateWithContext(ctx context.Context, request *...
    method ListModel (line 3558) | func (c *Client) ListModel(request *ListModelRequest) (response *ListM...
    method ListModelWithContext (line 3568) | func (c *Client) ListModelWithContext(ctx context.Context, request *Li...
    method ListQA (line 3609) | func (c *Client) ListQA(request *ListQARequest) (response *ListQARespo...
    method ListQAWithContext (line 3619) | func (c *Client) ListQAWithContext(ctx context.Context, request *ListQ...
    method ListQACate (line 3660) | func (c *Client) ListQACate(request *ListQACateRequest) (response *Lis...
    method ListQACateWithContext (line 3670) | func (c *Client) ListQACateWithContext(ctx context.Context, request *L...
    method ListReferShareKnowledge (line 3711) | func (c *Client) ListReferShareKnowledge(request *ListReferShareKnowle...
    method ListReferShareKnowledgeWithContext (line 3721) | func (c *Client) ListReferShareKnowledgeWithContext(ctx context.Contex...
    method ListRejectedQuestion (line 3762) | func (c *Client) ListRejectedQuestion(request *ListRejectedQuestionReq...
    method ListRejectedQuestionWithContext (line 3772) | func (c *Client) ListRejectedQuestionWithContext(ctx context.Context, ...
    method ListRejectedQuestionPreview (line 3813) | func (c *Client) ListRejectedQuestionPreview(request *ListRejectedQues...
    method ListRejectedQuestionPreviewWithContext (line 3823) | func (c *Client) ListRejectedQuestionPreviewWithContext(ctx context.Co...
    method ListRelease (line 3864) | func (c *Client) ListRelease(request *ListReleaseRequest) (response *L...
    method ListReleaseWithContext (line 3874) | func (c *Client) ListReleaseWithContext(ctx context.Context, request *...
    method ListReleaseConfigPreview (line 3915) | func (c *Client) ListReleaseConfigPreview(request *ListReleaseConfigPr...
    method ListReleaseConfigPreviewWithContext (line 3925) | func (c *Client) ListReleaseConfigPreviewWithContext(ctx context.Conte...
    method ListReleaseDocPreview (line 3966) | func (c *Client) ListReleaseDocPreview(request *ListReleaseDocPreviewR...
    method ListReleaseDocPreviewWithContext (line 3976) | func (c *Client) ListReleaseDocPreviewWithContext(ctx context.Context,...
    method ListReleaseQAPreview (line 4017) | func (c *Client) ListReleaseQAPreview(request *ListReleaseQAPreviewReq...
    method ListReleaseQAPreviewWithContext (line 4027) | func (c *Client) ListReleaseQAPreviewWithContext(ctx context.Context, ...
    method ListSelectDoc (line 4068) | func (c *Client) ListSelectDoc(request *ListSelectDocRequest) (respons...
    method ListSelectDocWithContext (line 4078) | func (c *Client) ListSelectDocWithContext(ctx context.Context, request...
    method ListSharedKnowledge (line 4119) | func (c *Client) ListSharedKnowledge(request *ListSharedKnowledgeReque...
    method ListSharedKnowledgeWithContext (line 4129) | func (c *Client) ListSharedKnowledgeWithContext(ctx context.Context, r...
    method ListUnsatisfiedReply (line 4171) | func (c *Client) ListUnsatisfiedReply(request *ListUnsatisfiedReplyReq...
    method ListUnsatisfiedReplyWithContext (line 4182) | func (c *Client) ListUnsatisfiedReplyWithContext(ctx context.Context, ...
    method ListUsageCallDetail (line 4224) | func (c *Client) ListUsageCallDetail(request *ListUsageCallDetailReque...
    method ListUsageCallDetailWithContext (line 4235) | func (c *Client) ListUsageCallDetailWithContext(ctx context.Context, r...
    method ListWorkflowRuns (line 4277) | func (c *Client) ListWorkflowRuns(request *ListWorkflowRunsRequest) (r...
    method ListWorkflowRunsWithContext (line 4288) | func (c *Client) ListWorkflowRunsWithContext(ctx context.Context, requ...
    method ModifyApp (line 4330) | func (c *Client) ModifyApp(request *ModifyAppRequest) (response *Modif...
    method ModifyAppWithContext (line 4341) | func (c *Client) ModifyAppWithContext(ctx context.Context, request *Mo...
    method ModifyAttributeLabel (line 4383) | func (c *Client) ModifyAttributeLabel(request *ModifyAttributeLabelReq...
    method ModifyAttributeLabelWithContext (line 4394) | func (c *Client) ModifyAttributeLabelWithContext(ctx context.Context, ...
    method ModifyDoc (line 4436) | func (c *Client) ModifyDoc(request *ModifyDocRequest) (response *Modif...
    method ModifyDocWithContext (line 4447) | func (c *Client) ModifyDocWithContext(ctx context.Context, request *Mo...
    method ModifyDocAttrRange (line 4488) | func (c *Client) ModifyDocAttrRange(request *ModifyDocAttrRangeRequest...
    method ModifyDocAttrRangeWithContext (line 4498) | func (c *Client) ModifyDocAttrRangeWithContext(ctx context.Context, re...
    method ModifyDocCate (line 4539) | func (c *Client) ModifyDocCate(request *ModifyDocCateRequest) (respons...
    method ModifyDocCateWithContext (line 4549) | func (c *Client) ModifyDocCateWithContext(ctx context.Context, request...
    method ModifyQA (line 4590) | func (c *Client) ModifyQA(request *ModifyQARequest) (response *ModifyQ...
    method ModifyQAWithContext (line 4600) | func (c *Client) ModifyQAWithContext(ctx context.Context, request *Mod...
    method ModifyQAAttrRange (line 4641) | func (c *Client) ModifyQAAttrRange(request *ModifyQAAttrRangeRequest) ...
    method ModifyQAAttrRangeWithContext (line 4651) | func (c *Client) ModifyQAAttrRangeWithContext(ctx context.Context, req...
    method ModifyQACate (line 4692) | func (c *Client) ModifyQACate(request *ModifyQACateRequest) (response ...
    method ModifyQACateWithContext (line 4702) | func (c *Client) ModifyQACateWithContext(ctx context.Context, request ...
    method ModifyRejectedQuestion (line 4743) | func (c *Client) ModifyRejectedQuestion(request *ModifyRejectedQuestio...
    method ModifyRejectedQuestionWithContext (line 4753) | func (c *Client) ModifyRejectedQuestionWithContext(ctx context.Context...
    method RateMsgRecord (line 4794) | func (c *Client) RateMsgRecord(request *RateMsgRecordRequest) (respons...
    method RateMsgRecordWithContext (line 4804) | func (c *Client) RateMsgRecordWithContext(ctx context.Context, request...
    method ReferShareKnowledge (line 4845) | func (c *Client) ReferShareKnowledge(request *ReferShareKnowledgeReque...
    method ReferShareKnowledgeWithContext (line 4855) | func (c *Client) ReferShareKnowledgeWithContext(ctx context.Context, r...
    method RenameDoc (line 4896) | func (c *Client) RenameDoc(request *RenameDocRequest) (response *Renam...
    method RenameDocWithContext (line 4906) | func (c *Client) RenameDocWithContext(ctx context.Context, request *Re...
    method RetryDocAudit (line 4947) | func (c *Client) RetryDocAudit(request *RetryDocAuditRequest) (respons...
    method RetryDocAuditWithContext (line 4957) | func (c *Client) RetryDocAuditWithContext(ctx context.Context, request...
    method RetryDocParse (line 4998) | func (c *Client) RetryDocParse(request *RetryDocParseRequest) (respons...
    method RetryDocParseWithContext (line 5008) | func (c *Client) RetryDocParseWithContext(ctx context.Context, request...
    method RetryRelease (line 5049) | func (c *Client) RetryRelease(request *RetryReleaseRequest) (response ...
    method RetryReleaseWithContext (line 5059) | func (c *Client) RetryReleaseWithContext(ctx context.Context, request ...
    method SaveDoc (line 5110) | func (c *Client) SaveDoc(request *SaveDocRequest) (response *SaveDocRe...
    method SaveDocWithContext (line 5130) | func (c *Client) SaveDocWithContext(ctx context.Context, request *Save...
    method StopDocParse (line 5171) | func (c *Client) StopDocParse(request *StopDocParseRequest) (response ...
    method StopDocParseWithContext (line 5181) | func (c *Client) StopDocParseWithContext(ctx context.Context, request ...
    method StopWorkflowRun (line 5223) | func (c *Client) StopWorkflowRun(request *StopWorkflowRunRequest) (res...
    method StopWorkflowRunWithContext (line 5234) | func (c *Client) StopWorkflowRunWithContext(ctx context.Context, reque...
    method UpdateSharedKnowledge (line 5276) | func (c *Client) UpdateSharedKnowledge(request *UpdateSharedKnowledgeR...
    method UpdateSharedKnowledgeWithContext (line 5287) | func (c *Client) UpdateSharedKnowledgeWithContext(ctx context.Context,...
    method UpdateVar (line 5329) | func (c *Client) UpdateVar(request *UpdateVarRequest) (response *Updat...
    method UpdateVarWithContext (line 5340) | func (c *Client) UpdateVarWithContext(ctx context.Context, request *Up...
    method UploadAttributeLabel (line 5382) | func (c *Client) UploadAttributeLabel(request *UploadAttributeLabelReq...
    method UploadAttributeLabelWithContext (line 5393) | func (c *Client) UploadAttributeLabelWithContext(ctx context.Context, ...
    method VerifyQA (line 5435) | func (c *Client) VerifyQA(request *VerifyQARequest) (response *VerifyQ...
    method VerifyQAWithContext (line 5446) | func (c *Client) VerifyQAWithContext(ctx context.Context, request *Ver...
  function NewClientWithSecretId (line 33) | func NewClientWithSecretId(secretId, secretKey, region string) (client *...
  function NewClient (line 40) | func NewClient(credential common.CredentialIface, region string, clientP...
  function NewCheckAttributeLabelExistRequest (line 48) | func NewCheckAttributeLabelExistRequest() (request *CheckAttributeLabelE...
  function NewCheckAttributeLabelExistResponse (line 58) | func NewCheckAttributeLabelExistResponse() (response *CheckAttributeLabe...
  function NewCheckAttributeLabelReferRequest (line 91) | func NewCheckAttributeLabelReferRequest() (request *CheckAttributeLabelR...
  function NewCheckAttributeLabelReferResponse (line 101) | func NewCheckAttributeLabelReferResponse() (response *CheckAttributeLabe...
  function NewCreateAppRequest (line 134) | func NewCreateAppRequest() (request *CreateAppRequest) {
  function NewCreateAppResponse (line 144) | func NewCreateAppResponse() (response *CreateAppResponse) {
  function NewCreateAttributeLabelRequest (line 177) | func NewCreateAttributeLabelRequest() (request *CreateAttributeLabelRequ...
  function NewCreateAttributeLabelResponse (line 187) | func NewCreateAttributeLabelResponse() (response *CreateAttributeLabelRe...
  function NewCreateDocCateRequest (line 228) | func NewCreateDocCateRequest() (request *CreateDocCateRequest) {
  function NewCreateDocCateResponse (line 238) | func NewCreateDocCateResponse() (response *CreateDocCateResponse) {
  function NewCreateQARequest (line 279) | func NewCreateQARequest() (request *CreateQARequest) {
  function NewCreateQAResponse (line 289) | func NewCreateQAResponse() (response *CreateQAResponse) {
  function NewCreateQACateRequest (line 330) | func NewCreateQACateRequest() (request *CreateQACateRequest) {
  function NewCreateQACateResponse (line 340) | func NewCreateQACateResponse() (response *CreateQACateResponse) {
  function NewCreateRejectedQuestionRequest (line 381) | func NewCreateRejectedQuestionRequest() (request *CreateRejectedQuestion...
  function NewCreateRejectedQuestionResponse (line 391) | func NewCreateRejectedQuestionResponse() (response *CreateRejectedQuesti...
  function NewCreateReleaseRequest (line 432) | func NewCreateReleaseRequest() (request *CreateReleaseRequest) {
  function NewCreateReleaseResponse (line 442) | func NewCreateReleaseResponse() (response *CreateReleaseResponse) {
  function NewCreateSharedKnowledgeRequest (line 483) | func NewCreateSharedKnowledgeRequest() (request *CreateSharedKnowledgeRe...
  function NewCreateSharedKnowledgeResponse (line 493) | func NewCreateSharedKnowledgeResponse() (response *CreateSharedKnowledge...
  function NewCreateVarRequest (line 534) | func NewCreateVarRequest() (request *CreateVarRequest) {
  function NewCreateVarResponse (line 544) | func NewCreateVarResponse() (response *CreateVarResponse) {
  function NewCreateWorkflowRunRequest (line 587) | func NewCreateWorkflowRunRequest() (request *CreateWorkflowRunRequest) {
  function NewCreateWorkflowRunResponse (line 597) | func NewCreateWorkflowRunResponse() (response *CreateWorkflowRunResponse) {
  function NewDeleteAgentRequest (line 644) | func NewDeleteAgentRequest() (request *DeleteAgentRequest) {
  function NewDeleteAgentResponse (line 654) | func NewDeleteAgentResponse() (response *DeleteAgentResponse) {
  function NewDeleteAppRequest (line 695) | func NewDeleteAppRequest() (request *DeleteAppRequest) {
  function NewDeleteAppResponse (line 705) | func NewDeleteAppResponse() (response *DeleteAppResponse) {
  function NewDeleteAttributeLabelRequest (line 746) | func NewDeleteAttributeLabelRequest() (request *DeleteAttributeLabelRequ...
  function NewDeleteAttributeLabelResponse (line 756) | func NewDeleteAttributeLabelResponse() (response *DeleteAttributeLabelRe...
  function NewDeleteDocRequest (line 797) | func NewDeleteDocRequest() (request *DeleteDocRequest) {
  function NewDeleteDocResponse (line 807) | func NewDeleteDocResponse() (response *DeleteDocResponse) {
  function NewDeleteDocCateRequest (line 848) | func NewDeleteDocCateRequest() (request *DeleteDocCateRequest) {
  function NewDeleteDocCateResponse (line 858) | func NewDeleteDocCateResponse() (response *DeleteDocCateResponse) {
  function NewDeleteQARequest (line 899) | func NewDeleteQARequest() (request *DeleteQARequest) {
  function NewDeleteQAResponse (line 909) | func NewDeleteQAResponse() (response *DeleteQAResponse) {
  function NewDeleteQACateRequest (line 950) | func NewDeleteQACateRequest() (request *DeleteQACateRequest) {
  function NewDeleteQACateResponse (line 960) | func NewDeleteQACateResponse() (response *DeleteQACateResponse) {
  function NewDeleteRejectedQuestionRequest (line 1001) | func NewDeleteRejectedQuestionRequest() (request *DeleteRejectedQuestion...
  function NewDeleteRejectedQuestionResponse (line 1011) | func NewDeleteRejectedQuestionResponse() (response *DeleteRejectedQuesti...
  function NewDeleteSharedKnowledgeRequest (line 1052) | func NewDeleteSharedKnowledgeRequest() (request *DeleteSharedKnowledgeRe...
  function NewDeleteSharedKnowledgeResponse (line 1062) | func NewDeleteSharedKnowledgeResponse() (response *DeleteSharedKnowledge...
  function NewDeleteVarRequest (line 1103) | func NewDeleteVarRequest() (request *DeleteVarRequest) {
  function NewDeleteVarResponse (line 1113) | func NewDeleteVarResponse() (response *DeleteVarResponse) {
  function NewDescribeAppRequest (line 1154) | func NewDescribeAppRequest() (request *DescribeAppRequest) {
  function NewDescribeAppResponse (line 1164) | func NewDescribeAppResponse() (response *DescribeAppResponse) {
  function NewDescribeAppAgentListRequest (line 1205) | func NewDescribeAppAgentListRequest() (request *DescribeAppAgentListRequ...
  function NewDescribeAppAgentListResponse (line 1215) | func NewDescribeAppAgentListResponse() (response *DescribeAppAgentListRe...
  function NewDescribeAttributeLabelRequest (line 1256) | func NewDescribeAttributeLabelRequest() (request *DescribeAttributeLabel...
  function NewDescribeAttributeLabelResponse (line 1266) | func NewDescribeAttributeLabelResponse() (response *DescribeAttributeLab...
  function NewDescribeCallStatsGraphRequest (line 1307) | func NewDescribeCallStatsGraphRequest() (request *DescribeCallStatsGraph...
  function NewDescribeCallStatsGraphResponse (line 1317) | func NewDescribeCallStatsGraphResponse() (response *DescribeCallStatsGra...
  function NewDescribeConcurrencyUsageRequest (line 1358) | func NewDescribeConcurrencyUsageRequest() (request *DescribeConcurrencyU...
  function NewDescribeConcurrencyUsageResponse (line 1368) | func NewDescribeConcurrencyUsageResponse() (response *DescribeConcurrenc...
  function NewDescribeConcurrencyUsageGraphRequest (line 1409) | func NewDescribeConcurrencyUsageGraphRequest() (request *DescribeConcurr...
  function NewDescribeConcurrencyUsageGraphResponse (line 1419) | func NewDescribeConcurrencyUsageGraphResponse() (response *DescribeConcu...
  function NewDescribeDocRequest (line 1460) | func NewDescribeDocRequest() (request *DescribeDocRequest) {
  function NewDescribeDocResponse (line 1470) | func NewDescribeDocResponse() (response *DescribeDocResponse) {
  function NewDescribeKnowledgeUsageRequest (line 1511) | func NewDescribeKnowledgeUsageRequest() (request *DescribeKnowledgeUsage...
  function NewDescribeKnowledgeUsageResponse (line 1521) | func NewDescribeKnowledgeUsageResponse() (response *DescribeKnowledgeUsa...
  function NewDescribeKnowledgeUsagePieGraphRequest (line 1562) | func NewDescribeKnowledgeUsagePieGraphRequest() (request *DescribeKnowle...
  function NewDescribeKnowledgeUsagePieGraphResponse (line 1572) | func NewDescribeKnowledgeUsagePieGraphResponse() (response *DescribeKnow...
  function NewDescribeNodeRunRequest (line 1613) | func NewDescribeNodeRunRequest() (request *DescribeNodeRunRequest) {
  function NewDescribeNodeRunResponse (line 1623) | func NewDescribeNodeRunResponse() (response *DescribeNodeRunResponse) {
  function NewDescribeQARequest (line 1666) | func NewDescribeQARequest() (request *DescribeQARequest) {
  function NewDescribeQAResponse (line 1676) | func NewDescribeQAResponse() (response *DescribeQAResponse) {
  function NewDescribeReferRequest (line 1719) | func NewDescribeReferRequest() (request *DescribeReferRequest) {
  function NewDescribeReferResponse (line 1729) | func NewDescribeReferResponse() (response *DescribeReferResponse) {
  function NewDescribeReleaseRequest (line 1772) | func NewDescribeReleaseRequest() (request *DescribeReleaseRequest) {
  function NewDescribeReleaseResponse (line 1782) | func NewDescribeReleaseResponse() (response *DescribeReleaseResponse) {
  function NewDescribeReleaseInfoRequest (line 1825) | func NewDescribeReleaseInfoRequest() (request *DescribeReleaseInfoReques...
  function NewDescribeReleaseInfoResponse (line 1835) | func NewDescribeReleaseInfoResponse() (response *DescribeReleaseInfoResp...
  function NewDescribeRobotBizIDByAppKeyRequest (line 1878) | func NewDescribeRobotBizIDByAppKeyRequest() (request *DescribeRobotBizID...
  function NewDescribeRobotBizIDByAppKeyResponse (line 1888) | func NewDescribeRobotBizIDByAppKeyResponse() (response *DescribeRobotBiz...
  function NewDescribeSearchStatsGraphRequest (line 1929) | func NewDescribeSearchStatsGraphRequest() (request *DescribeSearchStatsG...
  function NewDescribeSearchStatsGraphResponse (line 1939) | func NewDescribeSearchStatsGraphResponse() (response *DescribeSearchStat...
  function NewDescribeSegmentsRequest (line 1980) | func NewDescribeSegmentsRequest() (request *DescribeSegmentsRequest) {
  function NewDescribeSegmentsResponse (line 1990) | func NewDescribeSegmentsResponse() (response *DescribeSegmentsResponse) {
  function NewDescribeSharedKnowledgeRequest (line 2031) | func NewDescribeSharedKnowledgeRequest() (request *DescribeSharedKnowled...
  function NewDescribeSharedKnowledgeResponse (line 2041) | func NewDescribeSharedKnowledgeResponse() (response *DescribeSharedKnowl...
  function NewDescribeStorageCredentialRequest (line 2082) | func NewDescribeStorageCredentialRequest() (request *DescribeStorageCred...
  function NewDescribeStorageCredentialResponse (line 2092) | func NewDescribeStorageCredentialResponse() (response *DescribeStorageCr...
  function NewDescribeTokenUsageRequest (line 2133) | func NewDescribeTokenUsageRequest() (request *DescribeTokenUsageRequest) {
  function NewDescribeTokenUsageResponse (line 2143) | func NewDescribeTokenUsageResponse() (response *DescribeTokenUsageRespon...
  function NewDescribeTokenUsageGraphRequest (line 2184) | func NewDescribeTokenUsageGraphRequest() (request *DescribeTokenUsageGra...
  function NewDescribeTokenUsageGraphResponse (line 2194) | func NewDescribeTokenUsageGraphResponse() (response *DescribeTokenUsageG...
  function NewDescribeUnsatisfiedReplyContextRequest (line 2235) | func NewDescribeUnsatisfiedReplyContextRequest() (request *DescribeUnsat...
  function NewDescribeUnsatisfiedReplyContextResponse (line 2245) | func NewDescribeUnsatisfiedReplyContextResponse() (response *DescribeUns...
  function NewDescribeWorkflowRunRequest (line 2288) | func NewDescribeWorkflowRunRequest() (request *DescribeWorkflowRunReques...
  function NewDescribeWorkflowRunResponse (line 2298) | func NewDescribeWorkflowRunResponse() (response *DescribeWorkflowRunResp...
  function NewExportAttributeLabelRequest (line 2341) | func NewExportAttributeLabelRequest() (request *ExportAttributeLabelRequ...
  function NewExportAttributeLabelResponse (line 2351) | func NewExportAttributeLabelResponse() (response *ExportAttributeLabelRe...
  function NewExportQAListRequest (line 2394) | func NewExportQAListRequest() (request *ExportQAListRequest) {
  function NewExportQAListResponse (line 2404) | func NewExportQAListResponse() (response *ExportQAListResponse) {
  function NewExportUnsatisfiedReplyRequest (line 2447) | func NewExportUnsatisfiedReplyRequest() (request *ExportUnsatisfiedReply...
  function NewExportUnsatisfiedReplyResponse (line 2457) | func NewExportUnsatisfiedReplyResponse() (response *ExportUnsatisfiedRep...
  function NewGenerateQARequest (line 2500) | func NewGenerateQARequest() (request *GenerateQARequest) {
  function NewGenerateQAResponse (line 2510) | func NewGenerateQAResponse() (response *GenerateQAResponse) {
  function NewGetAnswerTypeDataCountRequest (line 2551) | func NewGetAnswerTypeDataCountRequest() (request *GetAnswerTypeDataCount...
  function NewGetAnswerTypeDataCountResponse (line 2561) | func NewGetAnswerTypeDataCountResponse() (response *GetAnswerTypeDataCou...
  function NewGetAppKnowledgeCountRequest (line 2604) | func NewGetAppKnowledgeCountRequest() (request *GetAppKnowledgeCountRequ...
  function NewGetAppKnowledgeCountResponse (line 2614) | func NewGetAppKnowledgeCountResponse() (response *GetAppKnowledgeCountRe...
  function NewGetAppSecretRequest (line 2655) | func NewGetAppSecretRequest() (request *GetAppSecretRequest) {
  function NewGetAppSecretResponse (line 2665) | func NewGetAppSecretResponse() (response *GetAppSecretResponse) {
  function NewGetDocPreviewRequest (line 2706) | func NewGetDocPreviewRequest() (request *GetDocPreviewRequest) {
  function NewGetDocPreviewResponse (line 2716) | func NewGetDocPreviewResponse() (response *GetDocPreviewResponse) {
  function NewGetLikeDataCountRequest (line 2757) | func NewGetLikeDataCountRequest() (request *GetLikeDataCountRequest) {
  function NewGetLikeDataCountResponse (line 2767) | func NewGetLikeDataCountResponse() (response *GetLikeDataCountResponse) {
  function NewGetMsgRecordRequest (line 2810) | func NewGetMsgRecordRequest() (request *GetMsgRecordRequest) {
  function NewGetMsgRecordResponse (line 2820) | func NewGetMsgRecordResponse() (response *GetMsgRecordResponse) {
  function NewGetTaskStatusRequest (line 2867) | func NewGetTaskStatusRequest() (request *GetTaskStatusRequest) {
  function NewGetTaskStatusResponse (line 2877) | func NewGetTaskStatusResponse() (response *GetTaskStatusResponse) {
  function NewGetVarListRequest (line 2920) | func NewGetVarListRequest() (request *GetVarListRequest) {
  function NewGetVarListResponse (line 2930) | func NewGetVarListResponse() (response *GetVarListResponse) {
  function NewGetWsTokenRequest (line 2973) | func NewGetWsTokenRequest() (request *GetWsTokenRequest) {
  function NewGetWsTokenResponse (line 2983) | func NewGetWsTokenResponse() (response *GetWsTokenResponse) {
  function NewGroupDocRequest (line 3024) | func NewGroupDocRequest() (request *GroupDocRequest) {
  function NewGroupDocResponse (line 3034) | func NewGroupDocResponse() (response *GroupDocResponse) {
  function NewGroupQARequest (line 3075) | func NewGroupQARequest() (request *GroupQARequest) {
  function NewGroupQAResponse (line 3085) | func NewGroupQAResponse() (response *GroupQAResponse) {
  function NewIgnoreUnsatisfiedReplyRequest (line 3126) | func NewIgnoreUnsatisfiedReplyRequest() (request *IgnoreUnsatisfiedReply...
  function NewIgnoreUnsatisfiedReplyResponse (line 3136) | func NewIgnoreUnsatisfiedReplyResponse() (response *IgnoreUnsatisfiedRep...
  function NewIsTransferIntentRequest (line 3177) | func NewIsTransferIntentRequest() (request *IsTransferIntentRequest) {
  function NewIsTransferIntentResponse (line 3187) | func NewIsTransferIntentResponse() (response *IsTransferIntentResponse) {
  function NewListAppRequest (line 3228) | func NewListAppRequest() (request *ListAppRequest) {
  function NewListAppResponse (line 3238) | func NewListAppResponse() (response *ListAppResponse) {
  function NewListAppKnowledgeDetailRequest (line 3279) | func NewListAppKnowledgeDetailRequest() (request *ListAppKnowledgeDetail...
  function NewListAppKnowledgeDetailResponse (line 3289) | func NewListAppKnowledgeDetailResponse() (response *ListAppKnowledgeDeta...
  function NewListAttributeLabelRequest (line 3330) | func NewListAttributeLabelRequest() (request *ListAttributeLabelRequest) {
  function NewListAttributeLabelResponse (line 3340) | func NewListAttributeLabelResponse() (response *ListAttributeLabelRespon...
  function NewListChannelRequest (line 3381) | func NewListChannelRequest() (request *ListChannelRequest) {
  function NewListChannelResponse (line 3391) | func NewListChannel
Copy disabled (too large) Download .json
Condensed preview — 1265 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (28,015K chars).
[
  {
    "path": "CONTRIBUTING.md",
    "chars": 661,
    "preview": "# 贡献指南\n\n感谢您考虑为53AI Hub项目做出贡献!以下是一些指导方针,帮助您参与到项目中来。\n\n## 行为准则\n\n请尊重所有项目参与者,保持专业和友好的交流环境。\n\n## 如何贡献\n\n### 报告问题\n\n如果您发现了bug或有新功能"
  },
  {
    "path": "LICENSE",
    "chars": 1846,
    "preview": "## 53AI 开源许可证  \n**53AI Open Source License**  \n\n53AI Hub 基于 Apache License 2.0 的开源协议,并附加以下条件:  \n53AI Hub is licensed und"
  },
  {
    "path": "README.md",
    "chars": 5997,
    "preview": "<div align=\"center\">\n  <a href=\"https://www.53ai.com/products/53AIHub\"><img alt=\"Product Introduction Page\" src=\"https:/"
  },
  {
    "path": "README_CN.md",
    "chars": 5086,
    "preview": "<div align=\"center\">\n  <a href=\"https://www.53ai.com/products/53AIHub\"><img alt=\"产品介绍页\" src=\"https://oss.ibos.cn/53ai/co"
  },
  {
    "path": "README_JA.md",
    "chars": 3912,
    "preview": "<div align=\"center\">\n  <a href=\"https://www.53ai.com/products/53AIHub\"><img alt=\"製品紹介ページ\" src=\"https://oss.ibos.cn/53ai/"
  },
  {
    "path": "api/.gitattributes",
    "chars": 18,
    "preview": "saas/** merge=ours"
  },
  {
    "path": "api/.gitignore",
    "chars": 291,
    "preview": ".idea\n.vscode\nupload\n*.exe\n*.db\nbuild\n*.db-journal\nlogs\ndata\n/web/node_modules\ncmd.md\n.env\ntemp\n.DS_Store\n__debug_bin*\ns"
  },
  {
    "path": "api/Dockerfile",
    "chars": 1086,
    "preview": "FROM golang:1.24.1 as builder\n\n# 设置工作目录\nWORKDIR /app\n\n# 设置GOPROXY为中国大陆代理\nENV GOPROXY=https://goproxy.cn,direct\n\n# 安装构建依赖"
  },
  {
    "path": "api/Makefile",
    "chars": 2824,
    "preview": "# Go parameters\nGOBIN = go\nGOFMT = gofmt\nGOLINT = golangci-lint\nGOTEST = go test\nGOBUILD = go build\nGOCLEAN = go clean\n\n"
  },
  {
    "path": "api/README.md",
    "chars": 2934,
    "preview": "# 53AIHub 后端接口\n\n53AIHub 是一个强大的 AI 代理管理平台,支持多种 AI 模型的接入和管理。本指南将帮助您快速上手并开始使用 53AIHub。\n\n## 目录\n\n- [53AIHub 后端接口](#53aihub-后端"
  },
  {
    "path": "api/bin/restart.sh",
    "chars": 383,
    "preview": "#!/bin/bash\n\n# 1. 找到 53aihub 运行的 pid \nPID=$(ps aux | grep '[5]3aihub' | awk '{print $2}')\n\n# 2. 优雅 kill 掉\nif [ -n \"$PID\""
  },
  {
    "path": "api/bin/version.txt",
    "chars": 6,
    "preview": "v0.1.0"
  },
  {
    "path": "api/build.sh",
    "chars": 29,
    "preview": "#!/bin/bash\nmake static-build"
  },
  {
    "path": "api/common/cache.go",
    "chars": 15,
    "preview": "package common\n"
  },
  {
    "path": "api/common/ctxkey/key.go",
    "chars": 713,
    "preview": "package ctxkey\n\nconst (\n\tConfig            = \"config\"\n\tId                = \"id\"\n\tUsername          = \"username\"\n\tRole   "
  },
  {
    "path": "api/common/email.go",
    "chars": 4304,
    "preview": "package common\n\nimport (\n\t\"crypto/rand\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/smtp\"\n\t\"regexp\"\n\t\"strings\"\n\t\"time\"\n\n\t\"githu"
  },
  {
    "path": "api/common/init.go",
    "chars": 945,
    "preview": "package common\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/53AI/53AIHub/config\"\n)\n\nvar (\n\tPort         = flag.Int(\"1por"
  },
  {
    "path": "api/common/lock.go",
    "chars": 1974,
    "preview": "package common\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/53AI/53AIHub/common/logger\"\n\t\"github.com/go-redis/redi"
  },
  {
    "path": "api/common/logger/logger.go",
    "chars": 5607,
    "preview": "package logger\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\""
  },
  {
    "path": "api/common/permission.go",
    "chars": 263,
    "preview": "package common\n\nimport (\n\t\"github.com/53AI/53AIHub/model\"\n\t\"github.com/gin-gonic/gin\"\n)\n\nfunc IsAdmin(c *gin.Context) bo"
  },
  {
    "path": "api/common/redis.go",
    "chars": 5070,
    "preview": "package common\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/53AI/53AIHub/common/logger\"\n\t\"github.com/"
  },
  {
    "path": "api/common/session/key.go",
    "chars": 715,
    "preview": "package session\n\nconst (\n\tSESSION_USER_ID          = \"SESSION_USER_ID\"\n\tSESSION_USER_NICKNAME    = \"SESSION_USER_NICKNAM"
  },
  {
    "path": "api/common/storage/storage.go",
    "chars": 3979,
    "preview": "package storage\n\nimport (\n\t\"bytes\"\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"io\"\n\t\"mime/multipart\"\n\t\"os\"\n\t\"path\"\n\t\"path/"
  },
  {
    "path": "api/common/storage/storage_test.go",
    "chars": 646,
    "preview": "package storage\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n)\n\nfunc TestSaveFile(t *testing.T) {\n\t// 创建 LocalStorage 实例\n"
  },
  {
    "path": "api/common/utils/ai53/api.go",
    "chars": 3698,
    "preview": "package ai53\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n)\n\ntype AI53Api struct {\n\tBaseUrl"
  },
  {
    "path": "api/common/utils/appbuilder/api.go",
    "chars": 4256,
    "preview": "package appbuilder\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AIHub/co"
  },
  {
    "path": "api/common/utils/coze/api.go",
    "chars": 7341,
    "preview": "package coze\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/53AI/53AIHub/"
  },
  {
    "path": "api/common/utils/env/env.go",
    "chars": 1042,
    "preview": "package env\n\nimport (\n\t\"os\"\n\t\"strconv\"\n\n\t_ \"github.com/joho/godotenv/autoload\"\n)\n\nfunc Int(env string, defaultValue int)"
  },
  {
    "path": "api/common/utils/helper/helper.go",
    "chars": 3331,
    "preview": "package helper\n\nimport (\n\t\"context\"\n\t\"crypto/md5\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"net/url\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\""
  },
  {
    "path": "api/common/utils/helper/key.go",
    "chars": 57,
    "preview": "package helper\n\nconst (\n\tRequestIdKey = \"X-Request-Id\"\n)\n"
  },
  {
    "path": "api/common/utils/helper/sso_sign.go",
    "chars": 462,
    "preview": "package helper\n\nimport (\n\t\"crypto/md5\"\n\t\"fmt\"\n)\n\n// BuildSSORawString 构造原始签名串:timestamp={10位}&username={规范化用户名}{secret}\n"
  },
  {
    "path": "api/common/utils/huawei_cloud/model.go",
    "chars": 1833,
    "preview": "package huawei_cloud\n\ntype HuaweicloudBaseResponse struct {\n\tResultCode string `json:\"resultCode\"`\n\tResultMsg  string `j"
  },
  {
    "path": "api/common/utils/huawei_cloud/signature.go",
    "chars": 1914,
    "preview": "package huawei_cloud\n\nimport (\n\t\"crypto/hmac\"\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"strconv\"\n\t\"str"
  },
  {
    "path": "api/common/utils/ip.go",
    "chars": 783,
    "preview": "package utils\n\nimport (\n\t\"strings\"\n\n\t\"github.com/gin-gonic/gin\"\n)\n\n// GetClientIP 获取请求客户端真实IP\n// 优先级:X-Real-Ip > X-Forwa"
  },
  {
    "path": "api/common/utils/jwt/jwt.go",
    "chars": 953,
    "preview": "package jwt\n\nimport (\n\t\"time\"\n\n\t\"github.com/53AI/53AIHub/common/utils/env\"\n\t\"github.com/golang-jwt/jwt/v5\"\n)\n\nvar secret"
  },
  {
    "path": "api/common/utils/random.go",
    "chars": 282,
    "preview": "package utils\n\nimport (\n\t\"math/rand\"\n\t\"time\"\n)\n\nvar randomGenerator *rand.Rand\n\nfunc init() {\n\tsource := rand.NewSource("
  },
  {
    "path": "api/common/utils/snowflake.go",
    "chars": 2703,
    "preview": "package utils\n\nimport (\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n)\n\n// Snowflake ID generator\ntype Snowflake struct {\n\tmutex      sync"
  },
  {
    "path": "api/common/utils/system/machine.go",
    "chars": 5227,
    "preview": "package system\n\nimport (\n\t\"bufio\"\n\t\"crypto/md5\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"runtime\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AIHub/com"
  },
  {
    "path": "api/common/utils/system/version.go",
    "chars": 4405,
    "preview": "package system\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/53AI/53AIHub/common/lo"
  },
  {
    "path": "api/common/utils/wxbizjsonmsgcrypt/wxbizjsonmsgcrypt.go",
    "chars": 8972,
    "preview": "package wxbizmsgcrypt\n\nimport (\n\t\"bytes\"\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/sha1\"\n\t\"encoding/base64\"\n\t\"encoding/bin"
  },
  {
    "path": "api/common/validate.go",
    "chars": 143,
    "preview": "package common\n\nimport \"github.com/go-playground/validator/v10\"\n\nvar Validate *validator.Validate\n\nfunc init() {\n\tValida"
  },
  {
    "path": "api/config/config.go",
    "chars": 3395,
    "preview": "package config\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/53AI/53AIHub/common/session\"\n\t\"github.c"
  },
  {
    "path": "api/config/database.go",
    "chars": 286,
    "preview": "package config\n\nimport \"github.com/53AI/53AIHub/common/utils/env\"\n\nvar UsingSQLite = false\nvar UsingPostgreSQL = false\nv"
  },
  {
    "path": "api/config/encryption.go",
    "chars": 438,
    "preview": "package config\n\nimport (\n\t\"os\"\n)\n\n// GetEncryptionKey returns the encryption key for sensitive data\nfunc GetEncryptionKe"
  },
  {
    "path": "api/config/storage.go",
    "chars": 457,
    "preview": "package config\n\nimport \"github.com/53AI/53AIHub/common/utils/env\"\n\nvar StorageType = env.String(\"STORAGE\", \"local\")\nvar "
  },
  {
    "path": "api/controller/agent.go",
    "chars": 25775,
    "preview": "package controller\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AI"
  },
  {
    "path": "api/controller/ai53.go",
    "chars": 7569,
    "preview": "package controller\n\nimport (\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AIHub/common/logger\"\n\t\"github.com/53"
  },
  {
    "path": "api/controller/ai_link.go",
    "chars": 10101,
    "preview": "package controller\n\nimport (\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/53AI/53AIHub/config\"\n\t\"github.com/53AI/53AIHub/model\"\n"
  },
  {
    "path": "api/controller/appbuilder.go",
    "chars": 2784,
    "preview": "package controller\n\nimport (\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AIHub/common/logger\"\n\t\"github.com/53"
  },
  {
    "path": "api/controller/auth_sso.go",
    "chars": 3880,
    "preview": "package controller\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"time\"\n\t\"unicode\"\n\n\t\"github.com/53AI/53AIHub/commo"
  },
  {
    "path": "api/controller/channel-test.go",
    "chars": 6832,
    "preview": "package controller\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest"
  },
  {
    "path": "api/controller/channel.go",
    "chars": 8630,
    "preview": "package controller\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AIHub/config\"\n\t\"github.com/53"
  },
  {
    "path": "api/controller/conversation.go",
    "chars": 10890,
    "preview": "package controller\n\nimport (\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/53AI/53AIHub/config\"\n\t\"github.com/53AI/53AIHub/model\"\n"
  },
  {
    "path": "api/controller/coze.go",
    "chars": 3341,
    "preview": "package controller\n\nimport (\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/53AI/53AIHub/common/logger\"\n\t\"github.com/53AI/53AIHub/"
  },
  {
    "path": "api/controller/department.go",
    "chars": 11568,
    "preview": "package controller\n\nimport (\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/53AI/53AIHub/config\"\n\t\"github.com/53AI/53AIHub/model\"\n"
  },
  {
    "path": "api/controller/dify.go",
    "chars": 3511,
    "preview": "package controller\n\nimport (\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/53AI/53AIHub/model\"\n\t\"github.com/53AI/53AIHub/service/"
  },
  {
    "path": "api/controller/email.go",
    "chars": 6874,
    "preview": "package controller\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/smtp\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/53AI/53AIHub/comm"
  },
  {
    "path": "api/controller/enterprise.go",
    "chars": 16511,
    "preview": "package controller\n\nimport (\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/53AI/53AIHub/common/utils\"\n\t\"github.com/53AI/53AIHub/c"
  },
  {
    "path": "api/controller/enterprise_config.go",
    "chars": 5039,
    "preview": "package controller\n\nimport (\n\t\"errors\"\n\t\"net/http\"\n\n\t\"github.com/53AI/53AIHub/config\"\n\t\"github.com/53AI/53AIHub/model\"\n\t"
  },
  {
    "path": "api/controller/group.go",
    "chars": 41760,
    "preview": "package controller\n\nimport (\n\t\"net/http\"\n\t\"strconv\"\n\t\"errors\"\n\n\t\"github.com/53AI/53AIHub/common/utils\"\n\t\"github.com/53AI"
  },
  {
    "path": "api/controller/maxkb.go",
    "chars": 7042,
    "preview": "package controller\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AIHub/"
  },
  {
    "path": "api/controller/message.go",
    "chars": 7727,
    "preview": "package controller\n\nimport (\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/53AI/53AIHub/common\"\n\t\"github.com/53AI/53AIHub/config\""
  },
  {
    "path": "api/controller/model.go",
    "chars": 4750,
    "preview": "package controller\n\nimport (\n\t\"github.com/53AI/53AIHub/model\"\n\t\"github.com/53AI/53AIHub/service\"\n\t\"github.com/gin-gonic/"
  },
  {
    "path": "api/controller/navigation.go",
    "chars": 13377,
    "preview": "package controller\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/53AI/53AIHub/common/utils\"\n\t\""
  },
  {
    "path": "api/controller/navigation_icons.go",
    "chars": 2123,
    "preview": "package controller\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/53AI/53AIHub/model\"\n\t\"github.com/gin-gonic/gin\"\n)\n\n// NavigationI"
  },
  {
    "path": "api/controller/order.go",
    "chars": 17685,
    "preview": "package controller\n\nimport (\n\t\"net/http\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/53AI/53AIHub/config\"\n\t\"github.com/53AI/53AIHub"
  },
  {
    "path": "api/controller/pay.go",
    "chars": 33793,
    "preview": "package controller\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com"
  },
  {
    "path": "api/controller/pay_setting.go",
    "chars": 14639,
    "preview": "package controller\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/53AI/53AIHub/common/utils\"\n\t\"g"
  },
  {
    "path": "api/controller/prompt.go",
    "chars": 23772,
    "preview": "package controller\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AIHub/com"
  },
  {
    "path": "api/controller/provider.go",
    "chars": 7262,
    "preview": "package controller\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/53AI/53AIHub/config\""
  },
  {
    "path": "api/controller/provider_callback.go",
    "chars": 5395,
    "preview": "package controller\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AIHub/common/logger"
  },
  {
    "path": "api/controller/relay.go",
    "chars": 53752,
    "preview": "package controller\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"net/http\"\n\t\"strings\"\n"
  },
  {
    "path": "api/controller/rerank.go",
    "chars": 15953,
    "preview": "package controller\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"math\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/53A"
  },
  {
    "path": "api/controller/response_handler.go",
    "chars": 4398,
    "preview": "package controller\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AIHub/common/lo"
  },
  {
    "path": "api/controller/setting.go",
    "chars": 7881,
    "preview": "package controller\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/53AI/53AIHub/config\"\n\t\"github.com/53A"
  },
  {
    "path": "api/controller/share.go",
    "chars": 5592,
    "preview": "package controller\n\nimport (\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AIHub/config\"\n\t\"github.com/53AI/53AIHub/model\"\n"
  },
  {
    "path": "api/controller/status.go",
    "chars": 1370,
    "preview": "package controller\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/53AI/53AIHub/config\"\n\t\"github.com/53AI/53AIHub/model\"\n\t\"github.co"
  },
  {
    "path": "api/controller/subscription.go",
    "chars": 12873,
    "preview": "package controller\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AIHub/common/utils\"\n\t\"github.com/53AI/53"
  },
  {
    "path": "api/controller/sync_organization.go",
    "chars": 2776,
    "preview": "package controller\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/53AI/53AIHub/model\"\n\t\"github.com/gin-gonic/gin\"\n)\n\n// SyncOrganiz"
  },
  {
    "path": "api/controller/system_log.go",
    "chars": 4020,
    "preview": "package controller\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/53AI/53AIHub/common/utils\"\n\t\"github.com/53AI/53AIHub/config\"\n\t\"gi"
  },
  {
    "path": "api/controller/tencent.go",
    "chars": 7412,
    "preview": "package controller\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AIHub/common"
  },
  {
    "path": "api/controller/upload.go",
    "chars": 4050,
    "preview": "package controller\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"path\"\n\n\t\"github.com/53AI/53AIHub/common/sto"
  },
  {
    "path": "api/controller/user.go",
    "chars": 56806,
    "preview": "package controller\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/5"
  },
  {
    "path": "api/docker/docker-compose.yml",
    "chars": 814,
    "preview": "version: '3.8'\n\nservices:\n  53aihub:\n    build:\n      context: ..\n      dockerfile: Dockerfile\n    env_file: .env\n    po"
  },
  {
    "path": "api/docs/.gitignore",
    "chars": 49,
    "preview": "# 忽略文件夹内所有文件\n*\n# 但不忽略 .gitignore 文件本身\n!.gitignore"
  },
  {
    "path": "api/go.mod",
    "chars": 6208,
    "preview": "module github.com/53AI/53AIHub\n\ngo 1.24.1\n\nrequire (\n\tgithub.com/alibabacloud-go/darabonba-openapi/v2 v2.1.13\n\tgithub.co"
  },
  {
    "path": "api/go.sum",
    "chars": 49349,
    "preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go/auth v0.6.1 h1:T0"
  },
  {
    "path": "api/main.go",
    "chars": 1854,
    "preview": "package main\n\nimport (\n\t\"embed\"\n\t\"os\"\n\n\t\"github.com/53AI/53AIHub/common\"\n\t\"github.com/53AI/53AIHub/common/logger\"\n\t\"gith"
  },
  {
    "path": "api/middleware/auth.go",
    "chars": 2009,
    "preview": "package middleware\n\nimport (\n\t\"errors\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AIHub/common/session\"\n\t\"github.com/53"
  },
  {
    "path": "api/middleware/cors.go",
    "chars": 364,
    "preview": "package middleware\n\nimport (\n\t\"github.com/gin-contrib/cors\"\n\t\"github.com/gin-gonic/gin\"\n)\n\nfunc CORS() gin.HandlerFunc {"
  },
  {
    "path": "api/middleware/distributor.go",
    "chars": 1998,
    "preview": "package middleware\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/53AI/53AIHub/common/ctxkey\"\n\t\"github.com/53AI/53AIHub/model\"\n\t\"github."
  },
  {
    "path": "api/middleware/logger.go",
    "chars": 688,
    "preview": "package middleware\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/53AI/53AIHub/common/session\"\n\t\"github.com/gin-gonic/gin\"\n)\n\nfu"
  },
  {
    "path": "api/middleware/relay_auth.go",
    "chars": 4060,
    "preview": "package middleware\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/5"
  },
  {
    "path": "api/model/agent.go",
    "chars": 5290,
    "preview": "package model\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"strconv\"\n)\n\ntype Agent struct {\n\tAgentID           int64   `json:\"a"
  },
  {
    "path": "api/model/ai_link.go",
    "chars": 5964,
    "preview": "package model\n\nimport (\n\t\"errors\"\n\t\"log\"\n)\n\ntype AILink struct {\n\tID          int64  `json:\"id\" gorm:\"primaryKey;autoInc"
  },
  {
    "path": "api/model/base.go",
    "chars": 488,
    "preview": "package model\n\nimport (\n\t\"time\"\n\n\t\"gorm.io/gorm\"\n)\n\ntype BaseModel struct {\n\tCreatedTime int64 `json:\"created_time\" gorm"
  },
  {
    "path": "api/model/cache.go",
    "chars": 87,
    "preview": "package model\n\nconst (\n\tLockOrganizationKeyPre = \"lock_enterprise_organization_sync\"\n)\n"
  },
  {
    "path": "api/model/channel.go",
    "chars": 10081,
    "preview": "package model\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AIHub/common/logger\"\n\t\"github.com/53AI/5"
  },
  {
    "path": "api/model/channel_file_mapping.go",
    "chars": 1807,
    "preview": "package model\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AIHub/common/logger\"\n)\n\ntype ChannelFileMapping struc"
  },
  {
    "path": "api/model/conversation.go",
    "chars": 6716,
    "preview": "package model\n\ntype Conversation struct {\n\tConversationID                    int64  `json:\"conversation_id\" gorm:\"column"
  },
  {
    "path": "api/model/department.go",
    "chars": 13675,
    "preview": "package model\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"gorm.io/gorm\"\n)\n\n// Department source constants\nconst (\n\tDepartme"
  },
  {
    "path": "api/model/dingtalk_corp.go",
    "chars": 3486,
    "preview": "package model\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\n\t\"gorm.io/gorm\"\n)\n\ntype DingtalkCorp struct {\n\tCorpId          strin"
  },
  {
    "path": "api/model/dingtalk_suite.go",
    "chars": 2043,
    "preview": "package model\n\nimport (\n\t\"errors\"\n)\n\ntype DingtalkSuite struct {\n\tSuiteID                 string `json:\"suite_id\" gorm:\""
  },
  {
    "path": "api/model/enterprise.go",
    "chars": 20617,
    "preview": "package model\n\nimport (\n\t\"errors\"\n\t\"time\"\n\n\t\"github.com/53AI/53AIHub/common/logger\"\n\t\"github.com/53AI/53AIHub/common/uti"
  },
  {
    "path": "api/model/enterprise_config.go",
    "chars": 1452,
    "preview": "package model\n\nimport (\n\t\"fmt\"\n)\n\ntype EnterpriseConfig struct {\n\tID      int64  `gorm:\"primaryKey;autoIncrement\" json:\""
  },
  {
    "path": "api/model/enterprise_sync.go",
    "chars": 1775,
    "preview": "package model\n\nimport (\n\t\"errors\"\n\n\t\"github.com/53AI/53AIHub/common/utils/helper\"\n)\n\n// FindEnterpriseUserByAccount 在所有企"
  },
  {
    "path": "api/model/group.go",
    "chars": 14073,
    "preview": "package model\n\n// Group represents a group entity with optional agent associations\ntype Group struct {\n\tGroupId   int64 "
  },
  {
    "path": "api/model/like.go",
    "chars": 3662,
    "preview": "package model\n\nimport (\n\t\"errors\"\n\n\t\"gorm.io/gorm\"\n)\n\n// Like 点赞记录表\ntype Like struct {\n\tLikeID   int64  `json:\"like_id\" "
  },
  {
    "path": "api/model/main.go",
    "chars": 3721,
    "preview": "package model\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/53AI/53AIHub/common/logger\"\n\t\"github.com/53AI"
  },
  {
    "path": "api/model/member_binding.go",
    "chars": 8150,
    "preview": "package model\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"gorm.io/gorm\"\n)\n\n// Member binding source constants\nconst (\n\tMemberB"
  },
  {
    "path": "api/model/member_department_relation.go",
    "chars": 6688,
    "preview": "package model\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"gorm.io/gorm\"\n)\n\n// MemberDepartmentRelation source constants\nconst (\n\tMembe"
  },
  {
    "path": "api/model/message.go",
    "chars": 7052,
    "preview": "package model\n\nimport \"encoding/json\"\n\ntype Message struct {\n\tID                int64  `json:\"id\" gorm:\"column:id;primar"
  },
  {
    "path": "api/model/navigation.go",
    "chars": 3206,
    "preview": "package model\n\nimport \"errors\"\n\ntype Navigation struct {\n\tNavigationID int64              `json:\"navigation_id\" gorm:\"pr"
  },
  {
    "path": "api/model/navigation_content.go",
    "chars": 1663,
    "preview": "package model\n\nimport (\n\t\"errors\"\n\t\"time\"\n)\n\ntype NavigationContent struct {\n\tContentID    int64  `json:\"content_id\" gor"
  },
  {
    "path": "api/model/order.go",
    "chars": 13509,
    "preview": "package model\n\nimport (\n\t\"errors\"\n\t\"time\"\n)\n\n// Order status constants\nconst (\n\tOrderStatusConfirming = 1 // Manual paym"
  },
  {
    "path": "api/model/pay_setting.go",
    "chars": 4157,
    "preview": "package model\n\nimport \"errors\"\n\n// Payment type constants\nconst (\n\tPayTypeWechat = 1 // WeChat Pay\n\tPayTypeManual = 2 //"
  },
  {
    "path": "api/model/prompt.go",
    "chars": 5681,
    "preview": "package model\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// Prompt 提示词表\ntype Prompt struct {\n\tPromptID     int64      "
  },
  {
    "path": "api/model/provider.go",
    "chars": 5013,
    "preview": "package model\n\nimport (\n\t\"github.com/53AI/53AIHub/common/logger\"\n)\n\ntype Provider struct {\n\tProviderID   int64   `json:\""
  },
  {
    "path": "api/model/resource_permission.go",
    "chars": 4980,
    "preview": "package model\n\n// ResourceType defines constants for resource types\nconst (\n\tResourceTypeAgent      = \"agent\"      // Ag"
  },
  {
    "path": "api/model/response.go",
    "chars": 5917,
    "preview": "package model\n\nimport \"errors\"\n\n// CommonResponse represents the standard API response format\n// @Description Standard A"
  },
  {
    "path": "api/model/setting.go",
    "chars": 3914,
    "preview": "package model\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\n\t\"gorm.io/gorm\"\n)\n\ntype Setting struct {\n\tSettingID int64  `json:\"se"
  },
  {
    "path": "api/model/share_record.go",
    "chars": 5374,
    "preview": "package model\n\nimport (\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/google/uuid\"\n"
  },
  {
    "path": "api/model/subscription.go",
    "chars": 7652,
    "preview": "package model\n\nconst (\n\tCurrencyCNY = \"CNY\"\n\tCurrencyUSD = \"USD\"\n\n\tTimeUnitYear    = \"year\"\n\tTimeUnitMonth   = \"month\"\n\t"
  },
  {
    "path": "api/model/system_log.go",
    "chars": 8777,
    "preview": "package model\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\t\"time\"\n)\n\n// SystemLog 系统日志模型\n// @Description 对应数据库system_logs表,记录"
  },
  {
    "path": "api/model/upload_file.go",
    "chars": 3325,
    "preview": "package model\n\nimport (\n\t\"crypto/md5\"\n\t\"fmt\"\n\t\"path\"\n\t\"strconv\"\n\n\t\"github.com/53AI/53AIHub/common/storage\"\n\t\"github.com/"
  },
  {
    "path": "api/model/user.go",
    "chars": 16342,
    "preview": "package model\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/53AI/53AIHub/common/utils/helper\"\n\t"
  },
  {
    "path": "api/model/verification_code.go",
    "chars": 911,
    "preview": "package model\n\n// VerificationCode 验证码数据表\n// @Description 存储手机号/邮箱验证码及发送次数等信息\ntype VerificationCode struct {\n\tID        "
  },
  {
    "path": "api/model/wecom_corp.go",
    "chars": 4586,
    "preview": "package model\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\n\t\"gorm.io/gorm\"\n)\n\ntype WecomCorp struct {\n\tCorpID                st"
  },
  {
    "path": "api/model/wecom_suite.go",
    "chars": 2625,
    "preview": "package model\n\nimport (\n\t\"errors\"\n)\n\ntype WecomSuite struct {\n\tSuiteID                 string `json:\"suite_id\" gorm:\"pri"
  },
  {
    "path": "api/router/api.go",
    "chars": 18547,
    "preview": "package router\n\nimport (\n\t\"github.com/53AI/53AIHub/controller\"\n\t\"github.com/53AI/53AIHub/middleware\"\n\t\"github.com/53AI/5"
  },
  {
    "path": "api/router/main.go",
    "chars": 1329,
    "preview": "package router\n\nimport (\n\t\"embed\"\n\t\"io/fs\"\n\t\"net/http\"\n\t\"os\"\n\n\t\"github.com/53AI/53AIHub/controller\"\n\t_ \"github.com/53AI/"
  },
  {
    "path": "api/router/static.go",
    "chars": 5571,
    "preview": "package router\n\nimport (\n\t\"embed\"\n\t\"io/fs\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AIHub/common/logger\"\n\t\"github.com"
  },
  {
    "path": "api/router/web.go",
    "chars": 790,
    "preview": "package router\n\nimport (\n\t\"embed\"\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n\n\t\"github.com/gin-gonic/gin\"\n)\n\nfunc SetWebRouter(router *gin"
  },
  {
    "path": "api/service/adaptor.go",
    "chars": 5270,
    "preview": "package service\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/53AI/53AIHub/model\"\n\tadaptor53AI \"github.com/53AI/53AIH"
  },
  {
    "path": "api/service/ai53_provider.go",
    "chars": 1286,
    "preview": "package service\n\nimport (\n\t\"github.com/53AI/53AIHub/common/utils/ai53\"\n\t\"github.com/53AI/53AIHub/model\"\n)\n\ntype AI53Serv"
  },
  {
    "path": "api/service/appbuilder_provider.go",
    "chars": 1239,
    "preview": "package service\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/53AI/53AIHub/common/utils/appbuilder\"\n\t\"github.com/53AI/53AIHub/model\"\n)\n"
  },
  {
    "path": "api/service/channel_service.go",
    "chars": 2030,
    "preview": "package service\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/53AI/53AIHub/common/logger\"\n\t\"github.com/53AI/53AIHub/config\"\n"
  },
  {
    "path": "api/service/coze_provider.go",
    "chars": 13661,
    "preview": "package service\n\nimport (\n\t\"crypto/md5\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"path\"\n\t\"strings\"\n\t\"time\"\n\n"
  },
  {
    "path": "api/service/enterprise_config_service.go",
    "chars": 6436,
    "preview": "package service\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"net/smtp\"\n\t\"strconv\"\n\n\t\"github.com/53AI/53AIHub/common/utils/env\""
  },
  {
    "path": "api/service/hub_adaptor/53AI/adaptor.go",
    "chars": 12447,
    "preview": "package adaptor53AI\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"mime/multipart\"\n\t\"net/http\"\n\t\"net/textp"
  },
  {
    "path": "api/service/hub_adaptor/53AI/constants.go",
    "chars": 48,
    "preview": "package adaptor53AI\n\nvar ModelList = []string{}\n"
  },
  {
    "path": "api/service/hub_adaptor/53AI/main.go",
    "chars": 4816,
    "preview": "package adaptor53AI\n\nimport (\n\t\"bufio\"\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AIHub/common/logger\""
  },
  {
    "path": "api/service/hub_adaptor/53AI/model.go",
    "chars": 2483,
    "preview": "package adaptor53AI\n\ntype StreamResponse struct {\n\tEvent          string          `json:\"event\"`\n\tConversationID string "
  },
  {
    "path": "api/service/hub_adaptor/53AI/workflow.go",
    "chars": 17633,
    "preview": "package adaptor53AI\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings"
  },
  {
    "path": "api/service/hub_adaptor/appbuilder/adaptor.go",
    "chars": 7254,
    "preview": "package appbuilder\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"mime/multipart\"\n\t\"net/http\"\n\t\"strings\"\n\n"
  },
  {
    "path": "api/service/hub_adaptor/appbuilder/constants.go",
    "chars": 47,
    "preview": "package appbuilder\n\nvar ModelList = []string{}\n"
  },
  {
    "path": "api/service/hub_adaptor/appbuilder/main.go",
    "chars": 4861,
    "preview": "package appbuilder\n\nimport (\n\t\"bufio\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AIHub/co"
  },
  {
    "path": "api/service/hub_adaptor/appbuilder/model.go",
    "chars": 2630,
    "preview": "package appbuilder\n\ntype Request struct {\n\tAppID          string       `json:\"app_id\"`\n\tEndUserID      string       `jso"
  },
  {
    "path": "api/service/hub_adaptor/bailian/adaptor.go",
    "chars": 5466,
    "preview": "package bailian\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.c"
  },
  {
    "path": "api/service/hub_adaptor/bailian/constants.go",
    "chars": 63,
    "preview": "package bailian\n\nvar ModelList = []string{\n\t\"gte-rerank-v2\",\n}\n"
  },
  {
    "path": "api/service/hub_adaptor/bailian/main.go",
    "chars": 5192,
    "preview": "package bailian\n\nimport (\n\t\"bufio\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AIHub/co"
  },
  {
    "path": "api/service/hub_adaptor/bailian/model.go",
    "chars": 1022,
    "preview": "package bailian\n\ntype Request struct {\n\tInput      Input      `json:\"input\"`\n\tParameters Parameters `json:\"parameters\"`\n"
  },
  {
    "path": "api/service/hub_adaptor/bailian/rerank.go",
    "chars": 5173,
    "preview": "package bailian\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AIHub/commo"
  },
  {
    "path": "api/service/hub_adaptor/bailian/rerank_model.go",
    "chars": 1813,
    "preview": "package bailian\n\n// Rerank 请求结构 - 百炼格式\ntype BailianRerankRequest struct {\n\tModel      string                  `json:\"mod"
  },
  {
    "path": "api/service/hub_adaptor/coze/adaptor.go",
    "chars": 2997,
    "preview": "package coze\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AIHub/service/hub_adaptor/cust"
  },
  {
    "path": "api/service/hub_adaptor/coze/constant/contenttype/define.go",
    "chars": 46,
    "preview": "package contenttype\n\nconst (\n\tText = \"text\"\n)\n"
  },
  {
    "path": "api/service/hub_adaptor/coze/constant/event/define.go",
    "chars": 83,
    "preview": "package event\n\nconst (\n\tMessage = \"message\"\n\tDone    = \"done\"\n\tError   = \"error\"\n)\n"
  },
  {
    "path": "api/service/hub_adaptor/coze/constant/messagetype/define.go",
    "chars": 76,
    "preview": "package messagetype\n\nconst (\n\tAnswer   = \"answer\"\n\tFollowUp = \"follow_up\"\n)\n"
  },
  {
    "path": "api/service/hub_adaptor/coze/constants.go",
    "chars": 41,
    "preview": "package coze\n\nvar ModelList = []string{}\n"
  },
  {
    "path": "api/service/hub_adaptor/coze/helper.go",
    "chars": 202,
    "preview": "package coze\n\nimport \"github.com/songquanpeng/one-api/relay/adaptor/coze/constant/event\"\n\nfunc event2StopReason(e *strin"
  },
  {
    "path": "api/service/hub_adaptor/coze/main.go",
    "chars": 10617,
    "preview": "package coze\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"mime/multipart\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"githu"
  },
  {
    "path": "api/service/hub_adaptor/coze/model.go",
    "chars": 2983,
    "preview": "package coze\n\ntype Message struct {\n\tRole        string `json:\"role\"`\n\tType        string `json:\"type\"`\n\tContent     str"
  },
  {
    "path": "api/service/hub_adaptor/coze/workflow.go",
    "chars": 14653,
    "preview": "package coze\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\n\tdb_model \"github.com/"
  },
  {
    "path": "api/service/hub_adaptor/custom/common.go",
    "chars": 2773,
    "preview": "package custom\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AI"
  },
  {
    "path": "api/service/hub_adaptor/custom/config.go",
    "chars": 695,
    "preview": "package custom\n\ntype CustomConfig struct {\n\tUserId                     string                   `json:\"user_id,omitempty"
  },
  {
    "path": "api/service/hub_adaptor/custom/workflow.go",
    "chars": 597,
    "preview": "package custom\n\n// WorkflowResponseData 工作流标准响应数据结构\ntype WorkflowResponseData struct {\n\tWorkflowOutputData map[string]in"
  },
  {
    "path": "api/service/hub_adaptor/dify/adaptor.go",
    "chars": 9164,
    "preview": "package dify\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"mime/multipart\"\n\t\"net/http\"\n\t\"net/textproto\"\n\t"
  },
  {
    "path": "api/service/hub_adaptor/dify/constants.go",
    "chars": 41,
    "preview": "package dify\n\nvar ModelList = []string{}\n"
  },
  {
    "path": "api/service/hub_adaptor/dify/info.go",
    "chars": 5965,
    "preview": "package dify\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/songquanpeng/one-api/common/lo"
  },
  {
    "path": "api/service/hub_adaptor/dify/main.go",
    "chars": 3988,
    "preview": "package dify\n\nimport (\n\t\"bufio\"\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AIHub/common/logger\"\n\t\"gith"
  },
  {
    "path": "api/service/hub_adaptor/dify/model.go",
    "chars": 2177,
    "preview": "package dify\n\ntype StreamResponse struct {\n\tEvent          string `json:\"event\"`\n\tConversationID string `json:\"conversat"
  },
  {
    "path": "api/service/hub_adaptor/dify/workflow.go",
    "chars": 12975,
    "preview": "package dify\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\n\tdb_"
  },
  {
    "path": "api/service/hub_adaptor/fastgpt/workflow.go",
    "chars": 9403,
    "preview": "package fastgpt\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/53AI/53"
  },
  {
    "path": "api/service/hub_adaptor/n8n/README.md",
    "chars": 4044,
    "preview": "# n8n 工作流适配器\n\nn8n 是一个强大的工作流自动化平台,本适配器实现了与 n8n webhook 的完整集成,支持文件上传和复杂参数传递。\n\n## 功能特性\n\n### ✅ 核心功能\n- **渠道类型**: ChannelApiTy"
  },
  {
    "path": "api/service/hub_adaptor/n8n/adaptor.go",
    "chars": 1891,
    "preview": "package n8n\n\nimport (\n\t\"errors\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/53AI/53AIHub/service/hub_adaptor/custom\"\n\t\"github.com/gi"
  },
  {
    "path": "api/service/hub_adaptor/n8n/constants.go",
    "chars": 40,
    "preview": "package n8n\n\nvar ModelList = []string{}\n"
  },
  {
    "path": "api/service/hub_adaptor/n8n/main.go",
    "chars": 4518,
    "preview": "package n8n\n\nimport (\n\t\"bufio\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AIHub/common/logger\"\n"
  },
  {
    "path": "api/service/hub_adaptor/n8n/model.go",
    "chars": 582,
    "preview": "package n8n\n\n// N8nWorkflowRequest n8n 工作流请求结构\ntype N8nWorkflowRequest map[string]interface{}\n\n// N8nWorkflowResponse n8"
  },
  {
    "path": "api/service/hub_adaptor/n8n/workflow.go",
    "chars": 10102,
    "preview": "package n8n\n\nimport (\n\t\"bytes\"\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"git"
  },
  {
    "path": "api/service/hub_adaptor/openai/adaptor.go",
    "chars": 8237,
    "preview": "package openai\n\nimport (\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com"
  },
  {
    "path": "api/service/hub_adaptor/openai/compatible.go",
    "chars": 2355,
    "preview": "package openai\n\nimport (\n\t\"github.com/songquanpeng/one-api/relay/adaptor/ai360\"\n\t\"github.com/songquanpeng/one-api/relay/"
  },
  {
    "path": "api/service/hub_adaptor/openai/constants.go",
    "chars": 1061,
    "preview": "package openai\n\nvar ModelList = []string{\n\t\"gpt-3.5-turbo\", \"gpt-3.5-turbo-0301\", \"gpt-3.5-turbo-0613\", \"gpt-3.5-turbo-1"
  },
  {
    "path": "api/service/hub_adaptor/openai/helper.go",
    "chars": 966,
    "preview": "package openai\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/songquanpeng/one-api/relay/channeltype\"\n\t\"github.com/songquanpe"
  },
  {
    "path": "api/service/hub_adaptor/openai/image.go",
    "chars": 1225,
    "preview": "package openai\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"github.com/gin-gonic/gin\"\n\t\"github.com/songquanpeng/one-api/relay/m"
  },
  {
    "path": "api/service/hub_adaptor/openai/main.go",
    "chars": 5226,
    "preview": "package openai\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/songquanpeng/one-"
  },
  {
    "path": "api/service/hub_adaptor/openai/model.go",
    "chars": 4609,
    "preview": "package openai\n\nimport \"github.com/songquanpeng/one-api/relay/model\"\n\ntype TextContent struct {\n\tType string `json:\"type"
  },
  {
    "path": "api/service/hub_adaptor/openai/token.go",
    "chars": 7755,
    "preview": "package openai\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"strings\"\n\n\t\"github.com/pkoukk/tiktoken-go\"\n\n\t\"github.com/songquanpen"
  },
  {
    "path": "api/service/hub_adaptor/openai/util.go",
    "chars": 475,
    "preview": "package openai\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/songquanpeng/one-api/common/logger\"\n\t\"github.com/songquanpeng/o"
  },
  {
    "path": "api/service/hub_adaptor/tencent/adaptor.go",
    "chars": 2411,
    "preview": "package tencent\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/53AI/53AIHub/service/hub_adaptor/custom\"\n\t\"github.com/g"
  },
  {
    "path": "api/service/hub_adaptor/tencent/constants.go",
    "chars": 300,
    "preview": "package tencent\n\nvar ModelList = []string{\n\t\"tencent-bot\",\n\t\"hunyuan\",\n\t\"hunyuan-13B\",\n\t\"hunyuan-turbo\",\n\t\"hunyuan-stand"
  },
  {
    "path": "api/service/hub_adaptor/tencent/helper.go",
    "chars": 4972,
    "preview": "package tencent\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/53AI/53AIHub/common/logg"
  },
  {
    "path": "api/service/hub_adaptor/tencent/main.go",
    "chars": 3308,
    "preview": "package tencent\n\nimport (\n\t\"bufio\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AIHub/common/logg"
  },
  {
    "path": "api/service/hub_adaptor/tencent/model.go",
    "chars": 3334,
    "preview": "package tencent\n\n// TencentRequest 腾讯云请求结构体\ntype TencentRequest struct {\n\tRequestID         string            `json:\"req"
  },
  {
    "path": "api/service/hub_adaptor/tencent/sdk/client.go",
    "chars": 138808,
    "preview": "// Copyright (c) 2017-2025 Tencent. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Lice"
  },
  {
    "path": "api/service/hub_adaptor/tencent/sdk/errors.go",
    "chars": 810,
    "preview": "// Copyright (c) 2017-2025 Tencent. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Lice"
  },
  {
    "path": "api/service/hub_adaptor/tencent/sdk/models.go",
    "chars": 389479,
    "preview": "// Copyright (c) 2017-2025 Tencent. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Lice"
  },
  {
    "path": "api/service/hub_adaptor/volcengine/main.go",
    "chars": 391,
    "preview": "package volcengine\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/songquanpeng/one-api/relay/meta\"\n\t\"github.com/songquanpeng/one-api/rel"
  },
  {
    "path": "api/service/hub_adaptor/yuanqi/adaptor.go",
    "chars": 5233,
    "preview": "package yuanqi\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AIHub/commo"
  },
  {
    "path": "api/service/hub_adaptor/yuanqi/constants.go",
    "chars": 43,
    "preview": "package yuanqi\n\nvar ModelList = []string{}\n"
  },
  {
    "path": "api/service/hub_adaptor/yuanqi/main.go",
    "chars": 4491,
    "preview": "package yuanqi\n\nimport (\n\t\"bufio\"\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/53AI/53AIHub/common/logger"
  }
]

// ... and 1065 more files (download for full content)

About this extraction

This page contains the full source code of the 53AI/53AIHub GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 1265 files (25.2 MB), approximately 6.7M tokens, and a symbol index with 12493 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!