├── web
├── next
├── web@0.1.0
├── .env.example
├── src
│ ├── app
│ │ ├── favicon.ico
│ │ ├── home
│ │ │ ├── page.tsx
│ │ │ ├── knowledge
│ │ │ │ ├── components
│ │ │ │ │ ├── kb-form
│ │ │ │ │ │ └── ChooseEntity.ts
│ │ │ │ │ ├── kb-card
│ │ │ │ │ │ └── KBCardVO.ts
│ │ │ │ │ ├── external-kb-card
│ │ │ │ │ │ └── ExternalKBCardVO.ts
│ │ │ │ │ └── kb-retrieve
│ │ │ │ │ │ └── ExternalKBRetrieve.tsx
│ │ │ │ └── knowledgeBase.module.css
│ │ │ ├── models
│ │ │ │ ├── component
│ │ │ │ │ ├── ChooseRequesterEntity.ts
│ │ │ │ │ ├── ICreateEmbeddingField.ts
│ │ │ │ │ ├── ICreateLLMField.ts
│ │ │ │ │ ├── embedding-card
│ │ │ │ │ │ └── EmbeddingCardVO.ts
│ │ │ │ │ └── llm-card
│ │ │ │ │ │ └── LLMCardVO.ts
│ │ │ │ └── LLMConfig.module.css
│ │ │ ├── bots
│ │ │ │ ├── components
│ │ │ │ │ ├── bot-form
│ │ │ │ │ │ └── ChooseEntity.ts
│ │ │ │ │ └── bot-card
│ │ │ │ │ │ └── BotCardVO.ts
│ │ │ │ └── botConfig.module.css
│ │ │ ├── pipelines
│ │ │ │ ├── components
│ │ │ │ │ ├── pipeline-form
│ │ │ │ │ │ └── pipelineFormStyle.module.css
│ │ │ │ │ ├── pipeline-card
│ │ │ │ │ │ └── PipelineCardVO.ts
│ │ │ │ │ └── debug-dialog
│ │ │ │ │ │ └── AtBadge.tsx
│ │ │ │ └── pipelineConfig.module.css
│ │ │ ├── plugins
│ │ │ │ ├── plugins.module.css
│ │ │ │ ├── mcp-server
│ │ │ │ │ └── MCPCardVO.ts
│ │ │ │ └── components
│ │ │ │ │ └── plugin-market
│ │ │ │ │ └── plugin-market-card
│ │ │ │ │ └── PluginMarketCardVO.ts
│ │ │ └── components
│ │ │ │ └── home-titlebar
│ │ │ │ └── HomeTittleBar.module.css
│ │ ├── assets
│ │ │ └── langbot-logo.webp
│ │ ├── infra
│ │ │ ├── http
│ │ │ │ ├── requestParam
│ │ │ │ │ └── bots
│ │ │ │ │ │ ├── GetBotLogsRequest.ts
│ │ │ │ │ │ └── GetBotLogsResponse.ts
│ │ │ │ └── HttpClient.ts
│ │ │ ├── entities
│ │ │ │ ├── common.ts
│ │ │ │ └── pipeline
│ │ │ │ │ └── index.ts
│ │ │ └── basic-component
│ │ │ │ └── create-card-component
│ │ │ │ ├── CreateCardComponent.tsx
│ │ │ │ └── createCartComponent.module.css
│ │ ├── page.tsx
│ │ ├── login
│ │ │ └── layout.tsx
│ │ ├── register
│ │ │ └── layout.tsx
│ │ ├── reset-password
│ │ │ └── layout.tsx
│ │ └── layout.tsx
│ ├── lib
│ │ └── utils.ts
│ ├── i18next.d.ts
│ ├── components
│ │ ├── ui
│ │ │ ├── skeleton.tsx
│ │ │ ├── sonner.tsx
│ │ │ ├── label.tsx
│ │ │ ├── theme-toggle.tsx
│ │ │ ├── separator.tsx
│ │ │ ├── textarea.tsx
│ │ │ └── input.tsx
│ │ └── providers
│ │ │ └── theme-provider.tsx
│ ├── hooks
│ │ └── use-mobile.ts
│ └── i18n
│ │ └── index.ts
├── postcss.config.mjs
├── public
│ ├── vercel.svg
│ ├── window.svg
│ ├── file.svg
│ └── globe.svg
├── .lintstagedrc.json
├── README.md
├── next.config.ts
├── .prettierrc.mjs
├── components.json
├── eslint.config.mjs
├── .gitignore
└── tsconfig.json
├── CLAUDE.md
├── tests
├── __init__.py
└── unit_tests
│ ├── __init__.py
│ ├── pipeline
│ ├── __init__.py
│ └── test_simple.py
│ ├── storage
│ └── __init__.py
│ ├── config
│ └── __init__.py
│ └── plugin
│ └── __init__.py
├── res
├── announcement.json
├── announcement_saved.json
├── logo.png
├── social.png
├── instance_id.json
└── scripts
│ └── publish_announcement.py
├── src
└── langbot
│ ├── pkg
│ ├── __init__.py
│ ├── api
│ │ ├── __init__.py
│ │ └── http
│ │ │ ├── __init__.py
│ │ │ ├── controller
│ │ │ ├── __init__.py
│ │ │ └── groups
│ │ │ │ ├── __init__.py
│ │ │ │ ├── platform
│ │ │ │ └── __init__.py
│ │ │ │ ├── provider
│ │ │ │ └── __init__.py
│ │ │ │ ├── knowledge
│ │ │ │ └── __init__.py
│ │ │ │ ├── pipelines
│ │ │ │ └── __init__.py
│ │ │ │ ├── resources
│ │ │ │ └── __init__.py
│ │ │ │ ├── stats.py
│ │ │ │ └── logs.py
│ │ │ └── service
│ │ │ └── __init__.py
│ ├── core
│ │ ├── __init__.py
│ │ ├── notes
│ │ │ ├── __init__.py
│ │ │ ├── n001_classic_msgs.py
│ │ │ ├── n003_print_version.py
│ │ │ └── n002_selection_mode_on_windows.py
│ │ ├── bootutils
│ │ │ ├── __init__.py
│ │ │ ├── config.py
│ │ │ └── files.py
│ │ ├── migrations
│ │ │ ├── __init__.py
│ │ │ ├── m037_mcp_config.py
│ │ │ ├── m012_runner_config.py
│ │ │ ├── m011_command_prefix_config.py
│ │ │ ├── m006_vision_config.py
│ │ │ ├── m009_msg_truncator_cfg.py
│ │ │ ├── m007_qcg_center_url.py
│ │ │ ├── m014_force_delay_config.py
│ │ │ ├── m010_ollama_requester_config.py
│ │ │ ├── m022_lmstudio_config.py
│ │ │ ├── m001_sensitive_word_migration.py
│ │ │ ├── m018_xai_config.py
│ │ │ ├── m016_dify_service_api.py
│ │ │ ├── m019_zhipuai_config.py
│ │ │ ├── m033_dify_thinking_config.py
│ │ │ ├── m023_siliconflow_config.py
│ │ │ ├── m032_volcark_config.py
│ │ │ ├── m028_aliyun_requester_config.py
│ │ │ ├── m035_wxoa_mode.py
│ │ │ ├── m008_ad_fixwin_config_migrate.py
│ │ │ ├── m013_http_api_config.py
│ │ │ ├── m015_gitee_ai_config.py
│ │ │ ├── m024_discord_config.py
│ │ │ ├── m038_tg_dingtalk_markdown.py
│ │ │ ├── m036_wxoa_loading_message.py
│ │ │ ├── m029_dashscope_app_api_config.py
│ │ │ ├── m026_qqofficial_config.py
│ │ │ ├── m031_dingtalk_config.py
│ │ │ ├── m040_ppio_config.py
│ │ │ ├── m017_dify_api_timeout_params.py
│ │ │ ├── m020_wecom_config.py
│ │ │ ├── m021_lark_config.py
│ │ │ ├── m034_gewechat_file_url_config.py
│ │ │ ├── m004_moonshot_cfg_completion.py
│ │ │ ├── m005_deepseek_cfg_completion.py
│ │ │ ├── m027_wx_official_account_config.py
│ │ │ ├── m030_lark_config_cmpl.py
│ │ │ ├── m003_anthropic_requester_cfg_completion.py
│ │ │ └── m039_modelscope_cfg_completion.py
│ │ ├── stages
│ │ │ ├── __init__.py
│ │ │ └── genkeys.py
│ │ ├── entities.py
│ │ ├── stage.py
│ │ ├── migration.py
│ │ └── note.py
│ ├── utils
│ │ ├── __init__.py
│ │ ├── constants.py
│ │ ├── platform.py
│ │ └── pkgmgr.py
│ ├── command
│ │ ├── __init__.py
│ │ └── operators
│ │ │ ├── __init__.py
│ │ │ └── prompt.py
│ ├── config
│ │ ├── __init__.py
│ │ ├── impls
│ │ │ └── __init__.py
│ │ └── model.py
│ ├── discover
│ │ └── __init__.py
│ ├── entity
│ │ ├── __init__.py
│ │ ├── errors
│ │ │ ├── __init__.py
│ │ │ ├── platform.py
│ │ │ └── provider.py
│ │ └── persistence
│ │ │ ├── __init__.py
│ │ │ ├── base.py
│ │ │ ├── vector.py
│ │ │ ├── metadata.py
│ │ │ ├── user.py
│ │ │ ├── apikey.py
│ │ │ ├── mcp.py
│ │ │ ├── bstorage.py
│ │ │ ├── webhook.py
│ │ │ ├── plugin.py
│ │ │ └── bot.py
│ ├── pipeline
│ │ ├── __init__.py
│ │ ├── bansess
│ │ │ └── __init__.py
│ │ ├── cntfilter
│ │ │ ├── __init__.py
│ │ │ └── filters
│ │ │ │ └── __init__.py
│ │ ├── longtext
│ │ │ ├── __init__.py
│ │ │ └── strategies
│ │ │ │ └── __init__.py
│ │ ├── msgtrun
│ │ │ ├── __init__.py
│ │ │ └── truncators
│ │ │ │ ├── __init__.py
│ │ │ │ └── round.py
│ │ ├── preproc
│ │ │ └── __init__.py
│ │ ├── process
│ │ │ ├── __init__.py
│ │ │ ├── handlers
│ │ │ │ └── __init__.py
│ │ │ └── handler.py
│ │ ├── ratelimit
│ │ │ ├── __init__.py
│ │ │ └── algos
│ │ │ │ └── __init__.py
│ │ ├── respback
│ │ │ └── __init__.py
│ │ ├── resprule
│ │ │ ├── __init__.py
│ │ │ ├── rules
│ │ │ │ ├── __init__.py
│ │ │ │ ├── random.py
│ │ │ │ └── regexp.py
│ │ │ └── entities.py
│ │ ├── wrapper
│ │ │ └── __init__.py
│ │ └── entities.py
│ ├── platform
│ │ ├── __init__.py
│ │ └── sources
│ │ │ ├── __init__.py
│ │ │ ├── kook.png
│ │ │ ├── line.png
│ │ │ ├── onebot.png
│ │ │ ├── slack.png
│ │ │ ├── wecom.png
│ │ │ ├── wechatpad.png
│ │ │ ├── wecombot.png
│ │ │ ├── legacy
│ │ │ ├── nakuru.png
│ │ │ ├── gewechat.png
│ │ │ ├── qqbotpy.yaml
│ │ │ └── nakuru.yaml
│ │ │ ├── officialaccount.png
│ │ │ ├── websocket.yaml
│ │ │ ├── kook.yaml
│ │ │ ├── telegram.svg
│ │ │ ├── slack.yaml
│ │ │ ├── discord.yaml
│ │ │ ├── qqofficial.yaml
│ │ │ ├── wecomcs.yaml
│ │ │ ├── telegram.yaml
│ │ │ ├── wecombot.yaml
│ │ │ ├── dingtalk.svg
│ │ │ ├── lark.svg
│ │ │ └── line.yaml
│ ├── storage
│ │ ├── __init__.py
│ │ ├── providers
│ │ │ └── __init__.py
│ │ ├── mgr.py
│ │ └── provider.py
│ ├── vector
│ │ ├── __init__.py
│ │ └── vdbs
│ │ │ └── __init__.py
│ ├── persistence
│ │ ├── __init__.py
│ │ ├── databases
│ │ │ ├── __init__.py
│ │ │ ├── sqlite.py
│ │ │ └── postgresql.py
│ │ ├── migrations
│ │ │ ├── __init__.py
│ │ │ ├── dbm008_plugin_config.py
│ │ │ └── dbm009_pipeline_extension_preferences.py
│ │ ├── migration.py
│ │ └── database.py
│ ├── provider
│ │ ├── tools
│ │ │ ├── __init__.py
│ │ │ └── loaders
│ │ │ │ └── __init__.py
│ │ ├── modelmgr
│ │ │ ├── __init__.py
│ │ │ ├── requesters
│ │ │ │ ├── __init__.py
│ │ │ │ ├── 302ai.png
│ │ │ │ ├── bailian.png
│ │ │ │ ├── newapi.png
│ │ │ │ ├── qhaigc.png
│ │ │ │ ├── compshare.png
│ │ │ │ ├── jiekouai.png
│ │ │ │ ├── lmstudio.webp
│ │ │ │ ├── moonshot.png
│ │ │ │ ├── xai.svg
│ │ │ │ ├── giteeaichatcmpl.py
│ │ │ │ ├── xaichatcmpl.py
│ │ │ │ ├── anthropic.svg
│ │ │ │ ├── 302aichatcmpl.py
│ │ │ │ ├── newapichatcmpl.py
│ │ │ │ ├── qhaigcchatcmpl.py
│ │ │ │ ├── lmstudiochatcmpl.py
│ │ │ │ ├── tokenponychatcmpl.py
│ │ │ │ ├── zhipuaichatcmpl.py
│ │ │ │ ├── compsharechatcmpl.py
│ │ │ │ ├── siliconflowchatcmpl.py
│ │ │ │ ├── volcarkchatcmpl.py
│ │ │ │ ├── openrouterchatcmpl.py
│ │ │ │ ├── gemini.svg
│ │ │ │ ├── seekdb.svg
│ │ │ │ ├── xaichatcmpl.yaml
│ │ │ │ ├── anthropicmsgs.yaml
│ │ │ │ ├── ollamachat.yaml
│ │ │ │ ├── 302aichatcmpl.yaml
│ │ │ │ ├── chatcmpl.yaml
│ │ │ │ ├── compsharechatcmpl.yaml
│ │ │ │ ├── deepseekchatcmpl.yaml
│ │ │ │ ├── moonshotchatcmpl.yaml
│ │ │ │ ├── newapichatcmpl.yaml
│ │ │ │ ├── seekdbembed.yaml
│ │ │ │ ├── zhipuaichatcmpl.yaml
│ │ │ │ ├── volcarkchatcmpl.yaml
│ │ │ │ ├── bailianchatcmpl.yaml
│ │ │ │ ├── giteeaichatcmpl.yaml
│ │ │ │ ├── tokenpony.yaml
│ │ │ │ ├── lmstudiochatcmpl.yaml
│ │ │ │ ├── geminichatcmpl.yaml
│ │ │ │ ├── openrouterchatcmpl.yaml
│ │ │ │ ├── siliconflowchatcmpl.yaml
│ │ │ │ ├── modelscope.svg
│ │ │ │ ├── ppiochatcmpl.yaml
│ │ │ │ ├── qhaigcchatcmpl.yaml
│ │ │ │ ├── jiekouaichatcmpl.yaml
│ │ │ │ ├── modelscopechatcmpl.yaml
│ │ │ │ ├── shengsuanyun.yaml
│ │ │ │ ├── shengsuanyun.py
│ │ │ │ └── ppio.svg
│ │ │ ├── errors.py
│ │ │ ├── requester.yaml
│ │ │ ├── entities.py
│ │ │ └── token.py
│ │ ├── runners
│ │ │ └── __init__.py
│ │ ├── session
│ │ │ └── __init__.py
│ │ ├── __init__.py
│ │ └── runner.py
│ ├── rag
│ │ └── knowledge
│ │ │ └── services
│ │ │ ├── __init__.py
│ │ │ └── base_service.py
│ └── plugin
│ │ └── __init__.py
│ ├── templates
│ ├── __init__.py
│ ├── legacy
│ │ ├── command.json
│ │ ├── system.json
│ │ └── pipeline.json
│ └── components.yaml
│ ├── libs
│ ├── slack_api
│ │ └── __init__.py
│ ├── wecom_api
│ │ ├── __init__.py
│ │ └── ierror.py
│ ├── dingtalk_api
│ │ ├── __init__.py
│ │ └── EchoHandler.py
│ ├── coze_server_api
│ │ └── __init__.py
│ ├── dify_service_api
│ │ ├── v1
│ │ │ ├── __init__.py
│ │ │ ├── errors.py
│ │ │ └── client_test.py
│ │ ├── README.md
│ │ └── __init__.py
│ ├── qq_official_api
│ │ └── __init__.py
│ ├── wechatpad_api
│ │ ├── api
│ │ │ ├── __init__.py
│ │ │ ├── friend.py
│ │ │ ├── chatroom.py
│ │ │ └── user.py
│ │ ├── util
│ │ │ ├── __init__.py
│ │ │ └── terminal_printer.py
│ │ ├── __init__.py
│ │ └── README.md
│ ├── official_account_api
│ │ └── __init__.py
│ ├── wecom_customer_service_api
│ │ └── __init__.py
│ ├── README.md
│ └── wecom_ai_bot_api
│ │ └── ierror.py
│ └── __init__.py
├── main.py
├── codecov.yml
├── .dockerignore
├── Dockerfile
├── .github
├── ISSUE_TEMPLATE
│ ├── feature-request.yml
│ ├── submit-plugin.yml
│ ├── feature-request_en.yml
│ ├── submit-plugin_en.yml
│ └── bug-report.yml
├── dependabot.yml
└── workflows
│ └── build-dev-image.yaml
├── .pre-commit-config.yaml
├── run_tests.sh
├── pytest.ini
├── CONTRIBUTING.md
├── .gitignore
├── .mcp.json
└── docker
└── docker-compose.yaml
/web/next:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/web@0.1.0:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/CLAUDE.md:
--------------------------------------------------------------------------------
1 | AGENTS.md
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/res/announcement.json:
--------------------------------------------------------------------------------
1 | []
2 |
--------------------------------------------------------------------------------
/src/langbot/pkg/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/unit_tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/res/announcement_saved.json:
--------------------------------------------------------------------------------
1 | []
--------------------------------------------------------------------------------
/src/langbot/pkg/api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/utils/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/templates/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/libs/slack_api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/libs/wecom_api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/api/http/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/command/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/config/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/notes/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/discover/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/entity/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/pipeline/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/platform/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/storage/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/vector/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/unit_tests/pipeline/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/unit_tests/storage/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/libs/dingtalk_api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/config/impls/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/bootutils/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/stages/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/entity/errors/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/persistence/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/tools/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/libs/coze_server_api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/libs/dify_service_api/v1/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/libs/qq_official_api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/libs/wechatpad_api/api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/libs/wechatpad_api/util/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/api/http/controller/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/api/http/service/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/command/operators/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/entity/persistence/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/pipeline/bansess/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/pipeline/cntfilter/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/pipeline/longtext/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/pipeline/msgtrun/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/pipeline/preproc/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/pipeline/process/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/pipeline/ratelimit/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/pipeline/respback/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/pipeline/resprule/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/pipeline/wrapper/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/platform/sources/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/runners/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/session/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/storage/providers/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/libs/official_account_api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/persistence/databases/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/persistence/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/pipeline/process/handlers/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/pipeline/ratelimit/algos/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/pipeline/resprule/rules/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/tools/loaders/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/rag/knowledge/services/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/libs/wecom_customer_service_api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/api/http/controller/groups/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/pipeline/cntfilter/filters/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/pipeline/longtext/strategies/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/pipeline/msgtrun/truncators/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/api/http/controller/groups/platform/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/api/http/controller/groups/provider/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/unit_tests/config/__init__.py:
--------------------------------------------------------------------------------
1 | # Config unit tests
2 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | import langbot.__main__
2 |
3 | langbot.__main__.main()
4 |
--------------------------------------------------------------------------------
/src/langbot/pkg/api/http/controller/groups/knowledge/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/api/http/controller/groups/pipelines/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/api/http/controller/groups/resources/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/__init__.py:
--------------------------------------------------------------------------------
1 | """OpenAI 接口处理及会话管理相关"""
2 |
--------------------------------------------------------------------------------
/web/.env.example:
--------------------------------------------------------------------------------
1 | NEXT_PUBLIC_API_BASE_URL=http://localhost:5300
2 |
--------------------------------------------------------------------------------
/tests/unit_tests/plugin/__init__.py:
--------------------------------------------------------------------------------
1 | # Plugin connector unit tests
2 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | coverage:
2 | status:
3 | project: off
4 | patch: off
--------------------------------------------------------------------------------
/res/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langbot-app/LangBot/HEAD/res/logo.png
--------------------------------------------------------------------------------
/res/social.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langbot-app/LangBot/HEAD/res/social.png
--------------------------------------------------------------------------------
/src/langbot/pkg/plugin/__init__.py:
--------------------------------------------------------------------------------
1 | """插件支持包
2 |
3 | 包含插件基类、插件宿主以及部分API接口
4 | """
5 |
--------------------------------------------------------------------------------
/src/langbot/libs/wechatpad_api/__init__.py:
--------------------------------------------------------------------------------
1 | from .client import WeChatPadClient as WeChatPadClient
2 |
--------------------------------------------------------------------------------
/web/src/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langbot-app/LangBot/HEAD/web/src/app/favicon.ico
--------------------------------------------------------------------------------
/web/src/app/home/page.tsx:
--------------------------------------------------------------------------------
1 | export default function Home() {
2 | return
;
3 | }
4 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | .github
2 | .venv
3 | .vscode
4 | .data
5 | .temp
6 | web/.next
7 | web/node_modules
8 | web/.env
9 |
--------------------------------------------------------------------------------
/src/langbot/libs/dify_service_api/README.md:
--------------------------------------------------------------------------------
1 | # Dify Service API Python SDK
2 |
3 | 这个 SDK 尚不完全支持 Dify Service API 的所有功能。
4 |
--------------------------------------------------------------------------------
/web/src/app/assets/langbot-logo.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langbot-app/LangBot/HEAD/web/src/app/assets/langbot-logo.webp
--------------------------------------------------------------------------------
/src/langbot/__init__.py:
--------------------------------------------------------------------------------
1 | """LangBot - Easy-to-use global IM bot platform designed for LLM era"""
2 |
3 | __version__ = '4.6.5'
4 |
--------------------------------------------------------------------------------
/src/langbot/libs/README.md:
--------------------------------------------------------------------------------
1 | # LangBot/libs
2 |
3 | LangBot 项目下的 libs 目录下的所有代码均遵循本目录下的许可证约束。
4 | 您在使用、修改、分发本目录下的代码时,需要遵守其中包含的条款。
5 |
--------------------------------------------------------------------------------
/src/langbot/pkg/platform/sources/kook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langbot-app/LangBot/HEAD/src/langbot/pkg/platform/sources/kook.png
--------------------------------------------------------------------------------
/src/langbot/pkg/platform/sources/line.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langbot-app/LangBot/HEAD/src/langbot/pkg/platform/sources/line.png
--------------------------------------------------------------------------------
/src/langbot/pkg/entity/persistence/base.py:
--------------------------------------------------------------------------------
1 | import sqlalchemy.orm
2 |
3 |
4 | class Base(sqlalchemy.orm.DeclarativeBase):
5 | pass
6 |
--------------------------------------------------------------------------------
/src/langbot/pkg/platform/sources/onebot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langbot-app/LangBot/HEAD/src/langbot/pkg/platform/sources/onebot.png
--------------------------------------------------------------------------------
/src/langbot/pkg/platform/sources/slack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langbot-app/LangBot/HEAD/src/langbot/pkg/platform/sources/slack.png
--------------------------------------------------------------------------------
/src/langbot/pkg/platform/sources/wecom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langbot-app/LangBot/HEAD/src/langbot/pkg/platform/sources/wecom.png
--------------------------------------------------------------------------------
/web/postcss.config.mjs:
--------------------------------------------------------------------------------
1 | const config = {
2 | plugins: {
3 | '@tailwindcss/postcss': {},
4 | },
5 | };
6 | export default config;
7 |
--------------------------------------------------------------------------------
/src/langbot/pkg/platform/sources/wechatpad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langbot-app/LangBot/HEAD/src/langbot/pkg/platform/sources/wechatpad.png
--------------------------------------------------------------------------------
/src/langbot/pkg/platform/sources/wecombot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langbot-app/LangBot/HEAD/src/langbot/pkg/platform/sources/wecombot.png
--------------------------------------------------------------------------------
/src/langbot/templates/legacy/command.json:
--------------------------------------------------------------------------------
1 | {
2 | "privilege": {},
3 | "command-prefix": [
4 | "!",
5 | "!"
6 | ]
7 | }
--------------------------------------------------------------------------------
/web/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/platform/sources/legacy/nakuru.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langbot-app/LangBot/HEAD/src/langbot/pkg/platform/sources/legacy/nakuru.png
--------------------------------------------------------------------------------
/web/src/app/home/knowledge/components/kb-form/ChooseEntity.ts:
--------------------------------------------------------------------------------
1 | export interface IEmbeddingModelEntity {
2 | label: string;
3 | value: string;
4 | }
5 |
--------------------------------------------------------------------------------
/src/langbot/libs/dify_service_api/__init__.py:
--------------------------------------------------------------------------------
1 | from .v1 import client as client
2 | from .v1 import errors as errors
3 |
4 | __all__ = ['client', 'errors']
5 |
--------------------------------------------------------------------------------
/src/langbot/pkg/platform/sources/legacy/gewechat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langbot-app/LangBot/HEAD/src/langbot/pkg/platform/sources/legacy/gewechat.png
--------------------------------------------------------------------------------
/src/langbot/pkg/platform/sources/officialaccount.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langbot-app/LangBot/HEAD/src/langbot/pkg/platform/sources/officialaccount.png
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/302ai.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langbot-app/LangBot/HEAD/src/langbot/pkg/provider/modelmgr/requesters/302ai.png
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/bailian.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langbot-app/LangBot/HEAD/src/langbot/pkg/provider/modelmgr/requesters/bailian.png
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/newapi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langbot-app/LangBot/HEAD/src/langbot/pkg/provider/modelmgr/requesters/newapi.png
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/qhaigc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langbot-app/LangBot/HEAD/src/langbot/pkg/provider/modelmgr/requesters/qhaigc.png
--------------------------------------------------------------------------------
/web/.lintstagedrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "*.{js,jsx,ts,tsx}": ["next lint --fix --file", "next lint --file"],
3 | "**/*": ["bash -c 'cd \"$(pwd)\" && next build"]
4 | }
5 |
--------------------------------------------------------------------------------
/web/README.md:
--------------------------------------------------------------------------------
1 | # Debug LangBot Frontend
2 |
3 | Please refer to the [Development Guide](https://docs.langbot.app/en/develop/dev-config.html) for more information.
4 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/compshare.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langbot-app/LangBot/HEAD/src/langbot/pkg/provider/modelmgr/requesters/compshare.png
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/jiekouai.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langbot-app/LangBot/HEAD/src/langbot/pkg/provider/modelmgr/requesters/jiekouai.png
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/lmstudio.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langbot-app/LangBot/HEAD/src/langbot/pkg/provider/modelmgr/requesters/lmstudio.webp
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/moonshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langbot-app/LangBot/HEAD/src/langbot/pkg/provider/modelmgr/requesters/moonshot.png
--------------------------------------------------------------------------------
/res/instance_id.json:
--------------------------------------------------------------------------------
1 | {"host_id": "host_9b4a220d-3bb6-42fc-aec3-41188ce0a41c", "instance_id": "instance_61d8f262-b98a-4165-8e77-85fb6262529e", "instance_create_ts": 1736824678}
--------------------------------------------------------------------------------
/web/src/app/infra/http/requestParam/bots/GetBotLogsRequest.ts:
--------------------------------------------------------------------------------
1 | export interface GetBotLogsRequest {
2 | from_index: number; // 从某索引开始往前找,-1代表结尾,也就是拉取最新的
3 | max_count: number; // 最大拉取数量
4 | }
5 |
--------------------------------------------------------------------------------
/web/next.config.ts:
--------------------------------------------------------------------------------
1 | import type { NextConfig } from 'next';
2 |
3 | const nextConfig: NextConfig = {
4 | /* config options here */
5 | output: 'export',
6 | };
7 |
8 | export default nextConfig;
9 |
--------------------------------------------------------------------------------
/web/src/lib/utils.ts:
--------------------------------------------------------------------------------
1 | import { clsx, type ClassValue } from 'clsx';
2 | import { twMerge } from 'tailwind-merge';
3 |
4 | export function cn(...inputs: ClassValue[]) {
5 | return twMerge(clsx(inputs));
6 | }
7 |
--------------------------------------------------------------------------------
/web/src/app/home/models/component/ChooseRequesterEntity.ts:
--------------------------------------------------------------------------------
1 | export interface IChooseRequesterEntity {
2 | label: string;
3 | value: string;
4 | provider_category?: string;
5 | description?: string;
6 | }
7 |
--------------------------------------------------------------------------------
/src/langbot/libs/wechatpad_api/api/friend.py:
--------------------------------------------------------------------------------
1 | class FriendApi:
2 | """联系人API类,处理所有与联系人相关的操作"""
3 |
4 | def __init__(self, base_url: str, token: str):
5 | self.base_url = base_url
6 | self.token = token
7 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/errors.py:
--------------------------------------------------------------------------------
1 | class RequesterError(Exception):
2 | """Base class for all Requester errors."""
3 |
4 | def __init__(self, message: str):
5 | super().__init__('模型请求失败: ' + message)
6 |
--------------------------------------------------------------------------------
/web/src/app/home/models/component/ICreateEmbeddingField.ts:
--------------------------------------------------------------------------------
1 | export interface ICreateEmbeddingField {
2 | name: string;
3 | model_provider: string;
4 | url: string;
5 | api_key: string;
6 | extra_args?: string[];
7 | }
8 |
--------------------------------------------------------------------------------
/src/langbot/libs/dify_service_api/v1/errors.py:
--------------------------------------------------------------------------------
1 | class DifyAPIError(Exception):
2 | """Dify API 请求失败"""
3 |
4 | def __init__(self, message: str):
5 | self.message = message
6 | super().__init__(self.message)
7 |
--------------------------------------------------------------------------------
/web/src/app/home/models/component/ICreateLLMField.ts:
--------------------------------------------------------------------------------
1 | export interface ICreateLLMField {
2 | name: string;
3 | model_provider: string;
4 | url: string;
5 | api_key: string;
6 | abilities: string[];
7 | extra_args: string[];
8 | }
9 |
--------------------------------------------------------------------------------
/web/src/app/home/bots/components/bot-form/ChooseEntity.ts:
--------------------------------------------------------------------------------
1 | export interface IChooseAdapterEntity {
2 | label: string;
3 | value: string;
4 | }
5 |
6 | export interface IPipelineEntity {
7 | label: string;
8 | value: string;
9 | }
10 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/entities.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import enum
4 |
5 |
6 | class LifecycleControlScope(enum.Enum):
7 | APPLICATION = 'application'
8 | PLATFORM = 'platform'
9 | PLUGIN = 'plugin'
10 | PROVIDER = 'provider'
11 |
--------------------------------------------------------------------------------
/web/src/i18next.d.ts:
--------------------------------------------------------------------------------
1 | import 'react-i18next';
2 |
3 | declare module 'react-i18next' {
4 | interface CustomTypeOptions {
5 | defaultNS: 'translation';
6 | resources: {
7 | translation: typeof import('./i18n/locales/zh-Hans').default;
8 | };
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/langbot/pkg/pipeline/resprule/entities.py:
--------------------------------------------------------------------------------
1 | import pydantic
2 |
3 | import langbot_plugin.api.entities.builtin.platform.message as platform_message
4 |
5 |
6 | class RuleJudgeResult(pydantic.BaseModel):
7 | matching: bool = False
8 |
9 | replacement: platform_message.MessageChain = None
10 |
--------------------------------------------------------------------------------
/src/langbot/pkg/utils/constants.py:
--------------------------------------------------------------------------------
1 | import langbot
2 |
3 | semantic_version = f'v{langbot.__version__}'
4 |
5 | required_database_version = 13
6 | """Tag the version of the database schema, used to check if the database needs to be migrated"""
7 |
8 | debug_mode = False
9 |
10 | edition = 'community'
11 |
--------------------------------------------------------------------------------
/web/src/app/home/bots/botConfig.module.css:
--------------------------------------------------------------------------------
1 | .botListContainer {
2 | width: 100%;
3 | padding-left: 0.8rem;
4 | padding-right: 0.8rem;
5 | display: grid;
6 | grid-template-columns: repeat(auto-fill, minmax(24rem, 1fr));
7 | gap: 2rem;
8 | justify-items: stretch;
9 | align-items: start;
10 | }
11 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/bootutils/config.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 |
4 | from ...config import manager as config_mgr
5 |
6 |
7 | load_python_module_config = config_mgr.load_python_module_config
8 | load_json_config = config_mgr.load_json_config
9 | load_yaml_config = config_mgr.load_yaml_config
10 |
--------------------------------------------------------------------------------
/src/langbot/pkg/entity/errors/platform.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 |
4 | class AdapterNotFoundError(Exception):
5 | def __init__(self, adapter_name: str):
6 | self.adapter_name = adapter_name
7 |
8 | def __str__(self):
9 | return f'Adapter {self.adapter_name} not found'
10 |
--------------------------------------------------------------------------------
/src/langbot/pkg/vector/vdbs/__init__.py:
--------------------------------------------------------------------------------
1 | """Vector database implementations for LangBot."""
2 |
3 | from .chroma import ChromaVectorDatabase
4 | from .qdrant import QdrantVectorDatabase
5 | from .seekdb import SeekDBVectorDatabase
6 |
7 | __all__ = ['ChromaVectorDatabase', 'QdrantVectorDatabase', 'SeekDBVectorDatabase']
8 |
--------------------------------------------------------------------------------
/web/src/app/page.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useRouter } from 'next/navigation';
4 | import { useEffect } from 'react';
5 |
6 | export default function Home() {
7 | const router = useRouter();
8 | useEffect(() => {
9 | router.push('/login');
10 | }, []);
11 | return ;
12 | }
13 |
--------------------------------------------------------------------------------
/src/langbot/pkg/entity/errors/provider.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 |
4 | class RequesterNotFoundError(Exception):
5 | def __init__(self, requester_name: str):
6 | self.requester_name = requester_name
7 |
8 | def __str__(self):
9 | return f'Requester {self.requester_name} not found'
10 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requester.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ComponentTemplate
3 | metadata:
4 | name: LLMAPIRequester
5 | label:
6 | en_US: LLM API Requester
7 | zh_Hans: LLM API 请求器
8 | spec:
9 | type:
10 | - python
11 | execution:
12 | python:
13 | path: ./requester.py
14 | attr: LLMAPIRequester
--------------------------------------------------------------------------------
/web/src/app/home/pipelines/components/pipeline-form/pipelineFormStyle.module.css:
--------------------------------------------------------------------------------
1 | .formItemSubtitle {
2 | font-size: 18px;
3 | font-weight: bold;
4 | margin-bottom: 10px;
5 | }
6 |
7 | .changeFormButtonGroupContainer {
8 | width: 320px;
9 | display: flex;
10 | flex-direction: row;
11 | justify-content: space-between;
12 | }
13 |
--------------------------------------------------------------------------------
/web/src/app/infra/http/requestParam/bots/GetBotLogsResponse.ts:
--------------------------------------------------------------------------------
1 | export interface GetBotLogsResponse {
2 | logs: BotLog[];
3 | total_count: number;
4 | }
5 |
6 | export interface BotLog {
7 | images: [];
8 | level: string;
9 | message_session_id: string;
10 | seq_id: number;
11 | text: string;
12 | timestamp: number;
13 | }
14 |
--------------------------------------------------------------------------------
/web/src/app/login/layout.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import React from 'react';
4 |
5 | export default function LoginLayout({
6 | children,
7 | }: Readonly<{
8 | children: React.ReactNode;
9 | }>) {
10 | return (
11 |
12 | {children}
13 |
14 | );
15 | }
16 |
--------------------------------------------------------------------------------
/web/src/components/ui/skeleton.tsx:
--------------------------------------------------------------------------------
1 | import { cn } from '@/lib/utils';
2 |
3 | function Skeleton({ className, ...props }: React.ComponentProps<'div'>) {
4 | return (
5 |
10 | );
11 | }
12 |
13 | export { Skeleton };
14 |
--------------------------------------------------------------------------------
/web/src/app/register/layout.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import React from 'react';
4 |
5 | export default function RegisterLayout({
6 | children,
7 | }: Readonly<{
8 | children: React.ReactNode;
9 | }>) {
10 | return (
11 |
12 | {children}
13 |
14 | );
15 | }
16 |
--------------------------------------------------------------------------------
/web/src/app/reset-password/layout.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import React from 'react';
4 |
5 | export default function ResetPasswordLayout({
6 | children,
7 | }: Readonly<{
8 | children: React.ReactNode;
9 | }>) {
10 | return (
11 |
12 | {children}
13 |
14 | );
15 | }
16 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/xai.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/public/window.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/public/file.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/src/app/home/pipelines/pipelineConfig.module.css:
--------------------------------------------------------------------------------
1 | .configPageContainer {
2 | width: 100%;
3 | height: 100%;
4 | }
5 |
6 | .pipelineListContainer {
7 | width: 100%;
8 | padding-left: 0.8rem;
9 | padding-right: 0.8rem;
10 | display: grid;
11 | grid-template-columns: repeat(auto-fill, minmax(24rem, 1fr));
12 | gap: 2rem;
13 | justify-items: stretch;
14 | align-items: start;
15 | }
16 |
--------------------------------------------------------------------------------
/src/langbot/templates/components.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Blueprint
3 | metadata:
4 | name: builtin-components
5 | label:
6 | en_US: Builtin Components
7 | zh_Hans: 内置组件
8 | spec:
9 | components:
10 | MessagePlatformAdapter:
11 | fromDirs:
12 | - path: pkg/platform/sources/
13 | LLMAPIRequester:
14 | fromDirs:
15 | - path: pkg/provider/modelmgr/requesters/
16 |
--------------------------------------------------------------------------------
/src/langbot/pkg/rag/knowledge/services/base_service.py:
--------------------------------------------------------------------------------
1 | # 封装异步操作
2 | import asyncio
3 |
4 |
5 | class BaseService:
6 | def __init__(self):
7 | pass
8 |
9 | async def _run_sync(self, func, *args, **kwargs):
10 | """
11 | 在单独的线程中运行同步函数。
12 | 如果第一个参数是 session,则在 to_thread 中获取新的 session。
13 | """
14 |
15 | return await asyncio.to_thread(func, *args, **kwargs)
16 |
--------------------------------------------------------------------------------
/web/src/app/home/knowledge/knowledgeBase.module.css:
--------------------------------------------------------------------------------
1 | .configPageContainer {
2 | width: 100%;
3 | height: 100%;
4 | }
5 |
6 | .knowledgeListContainer {
7 | width: 100%;
8 | margin-top: 2rem;
9 | padding-left: 0.8rem;
10 | padding-right: 0.8rem;
11 | display: grid;
12 | grid-template-columns: repeat(auto-fill, minmax(24rem, 1fr));
13 | gap: 2rem;
14 | justify-items: stretch;
15 | align-items: start;
16 | }
17 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/giteeaichatcmpl.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 |
4 | import typing
5 |
6 | from . import ppiochatcmpl
7 |
8 |
9 | class GiteeAIChatCompletions(ppiochatcmpl.PPIOChatCompletions):
10 | """Gitee AI ChatCompletions API 请求器"""
11 |
12 | default_config: dict[str, typing.Any] = {
13 | 'base_url': 'https://ai.gitee.com/v1',
14 | 'timeout': 120,
15 | }
16 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/xaichatcmpl.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import typing
4 | import openai
5 |
6 | from . import chatcmpl
7 |
8 |
9 | class XaiChatCompletions(chatcmpl.OpenAIChatCompletions):
10 | """xAI ChatCompletion API 请求器"""
11 |
12 | client: openai.AsyncClient
13 |
14 | default_config: dict[str, typing.Any] = {
15 | 'base_url': 'https://api.x.ai/v1',
16 | 'timeout': 120,
17 | }
18 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/anthropic.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/302aichatcmpl.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import typing
4 | import openai
5 |
6 | from . import chatcmpl
7 |
8 |
9 | class AI302ChatCompletions(chatcmpl.OpenAIChatCompletions):
10 | """302.AI ChatCompletion API 请求器"""
11 |
12 | client: openai.AsyncClient
13 |
14 | default_config: dict[str, typing.Any] = {
15 | 'base_url': 'https://api.302.ai/v1',
16 | 'timeout': 120,
17 | }
18 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:22-alpine AS node
2 |
3 | WORKDIR /app
4 |
5 | COPY web ./web
6 |
7 | RUN cd web && npm install && npm run build
8 |
9 | FROM python:3.12.7-slim
10 |
11 | WORKDIR /app
12 |
13 | COPY . .
14 |
15 | COPY --from=node /app/web/out ./web/out
16 |
17 | RUN apt update \
18 | && apt install gcc -y \
19 | && python -m pip install --no-cache-dir uv \
20 | && uv sync \
21 | && touch /.dockerenv
22 |
23 | CMD [ "uv", "run", "--no-sync", "main.py" ]
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/newapichatcmpl.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import typing
4 | import openai
5 |
6 | from . import chatcmpl
7 |
8 |
9 | class NewAPIChatCompletions(chatcmpl.OpenAIChatCompletions):
10 | """New API ChatCompletion API 请求器"""
11 |
12 | client: openai.AsyncClient
13 |
14 | default_config: dict[str, typing.Any] = {
15 | 'base_url': 'http://localhost:3000/v1',
16 | 'timeout': 120,
17 | }
18 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/qhaigcchatcmpl.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import openai
4 | import typing
5 |
6 | from . import chatcmpl
7 |
8 |
9 | class QHAIGCChatCompletions(chatcmpl.OpenAIChatCompletions):
10 | """启航 AI ChatCompletion API 请求器"""
11 |
12 | client: openai.AsyncClient
13 |
14 | default_config: dict[str, typing.Any] = {
15 | 'base_url': 'https://api.qhaigc.com/v1',
16 | 'timeout': 120,
17 | }
18 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/lmstudiochatcmpl.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import typing
4 | import openai
5 |
6 | from . import chatcmpl
7 |
8 |
9 | class LmStudioChatCompletions(chatcmpl.OpenAIChatCompletions):
10 | """LMStudio ChatCompletion API 请求器"""
11 |
12 | client: openai.AsyncClient
13 |
14 | default_config: dict[str, typing.Any] = {
15 | 'base_url': 'http://127.0.0.1:1234/v1',
16 | 'timeout': 120,
17 | }
18 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/tokenponychatcmpl.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import typing
4 | import openai
5 |
6 | from . import chatcmpl
7 |
8 |
9 | class TokenPonyChatCompletions(chatcmpl.OpenAIChatCompletions):
10 | """TokenPony ChatCompletion API 请求器"""
11 |
12 | client: openai.AsyncClient
13 |
14 | default_config: dict[str, typing.Any] = {
15 | 'base_url': 'https://api.tokenpony.cn/v1',
16 | 'timeout': 120,
17 | }
18 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/zhipuaichatcmpl.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import typing
4 | import openai
5 |
6 | from . import chatcmpl
7 |
8 |
9 | class ZhipuAIChatCompletions(chatcmpl.OpenAIChatCompletions):
10 | """智谱AI ChatCompletion API 请求器"""
11 |
12 | client: openai.AsyncClient
13 |
14 | default_config: dict[str, typing.Any] = {
15 | 'base_url': 'https://open.bigmodel.cn/api/paas/v4',
16 | 'timeout': 120,
17 | }
18 |
--------------------------------------------------------------------------------
/src/langbot/libs/dify_service_api/v1/client_test.py:
--------------------------------------------------------------------------------
1 | from . import client
2 |
3 | import asyncio
4 |
5 | import os
6 |
7 |
8 | class TestDifyClient:
9 | async def test_chat_messages(self):
10 | cln = client.DifyClient(api_key=os.getenv('DIFY_API_KEY'))
11 |
12 | resp = await cln.chat_messages(inputs={}, query='Who are you?', user_id='test')
13 | print(resp)
14 |
15 |
16 | if __name__ == '__main__':
17 | asyncio.run(TestDifyClient().test_chat_messages())
18 |
--------------------------------------------------------------------------------
/src/langbot/pkg/platform/sources/websocket.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: MessagePlatformAdapter
3 | metadata:
4 | name: websocket
5 | label:
6 | en_US: "WebSocket Chat"
7 | zh_Hans: "WebSocket 聊天"
8 | description:
9 | en_US: "WebSocket adapter for bidirectional real-time communication"
10 | zh_Hans: "用于双向实时通信的 WebSocket 适配器"
11 | icon: ""
12 | spec:
13 | config: []
14 | execution:
15 | python:
16 | path: "websocket_adapter.py"
17 | attr: "WebSocketAdapter"
18 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/compsharechatcmpl.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import typing
4 | import openai
5 |
6 | from . import chatcmpl
7 |
8 |
9 | class CompShareChatCompletions(chatcmpl.OpenAIChatCompletions):
10 | """CompShare ChatCompletion API 请求器"""
11 |
12 | client: openai.AsyncClient
13 |
14 | default_config: dict[str, typing.Any] = {
15 | 'base_url': 'https://api.modelverse.cn/v1',
16 | 'timeout': 120,
17 | }
18 |
--------------------------------------------------------------------------------
/web/.prettierrc.mjs:
--------------------------------------------------------------------------------
1 | /**
2 | * @see https://prettier.io/docs/configuration
3 | * @type {import("prettier").Config}
4 | */
5 | const config = {
6 | // 单行长度
7 | printWidth: 80,
8 | // 缩进
9 | tabWidth: 2,
10 | // 使用空格代替tab缩进
11 | useTabs: false,
12 | // 句末使用分号
13 | semi: true,
14 | // 使用单引号
15 | singleQuote: true,
16 | // 大括号前后空格
17 | bracketSpacing: true,
18 | attributeVerticalAlignment: 'auto',
19 | trailingComma: 'all',
20 | };
21 |
22 | export default config;
23 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/notes/n001_classic_msgs.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import typing
4 |
5 | from .. import note
6 |
7 |
8 | @note.note_class('ClassicNotes', 1)
9 | class ClassicNotes(note.LaunchNote):
10 | """Classic launch information"""
11 |
12 | async def need_show(self) -> bool:
13 | return True
14 |
15 | async def yield_note(self) -> typing.AsyncGenerator[typing.Tuple[str, int], None]:
16 | yield await self.ap.ver_mgr.show_version_update()
17 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/siliconflowchatcmpl.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import typing
4 | import openai
5 |
6 | from . import chatcmpl
7 |
8 |
9 | class SiliconFlowChatCompletions(chatcmpl.OpenAIChatCompletions):
10 | """SiliconFlow ChatCompletion API 请求器"""
11 |
12 | client: openai.AsyncClient
13 |
14 | default_config: dict[str, typing.Any] = {
15 | 'base_url': 'https://api.siliconflow.cn/v1',
16 | 'timeout': 120,
17 | }
18 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/volcarkchatcmpl.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import typing
4 | import openai
5 |
6 | from . import chatcmpl
7 |
8 |
9 | class VolcArkChatCompletions(chatcmpl.OpenAIChatCompletions):
10 | """火山方舟大模型平台 ChatCompletion API 请求器"""
11 |
12 | client: openai.AsyncClient
13 |
14 | default_config: dict[str, typing.Any] = {
15 | 'base_url': 'https://ark.cn-beijing.volces.com/api/v3',
16 | 'timeout': 120,
17 | }
18 |
--------------------------------------------------------------------------------
/web/src/app/home/models/LLMConfig.module.css:
--------------------------------------------------------------------------------
1 | .modelListContainer {
2 | width: 100%;
3 | padding-left: 0.8rem;
4 | padding-right: 0.8rem;
5 | display: grid;
6 | grid-template-columns: repeat(auto-fill, minmax(24rem, 1fr));
7 | gap: 2rem;
8 | justify-items: stretch;
9 | align-items: start;
10 | }
11 |
12 | .emptyContainer {
13 | width: 100%;
14 | height: 100%;
15 | display: flex;
16 | flex-direction: column;
17 | align-items: center;
18 | justify-content: center;
19 | }
20 |
--------------------------------------------------------------------------------
/src/langbot/libs/wechatpad_api/api/chatroom.py:
--------------------------------------------------------------------------------
1 | from langbot.libs.wechatpad_api.util.http_util import post_json
2 |
3 |
4 | class ChatRoomApi:
5 | def __init__(self, base_url, token):
6 | self.base_url = base_url
7 | self.token = token
8 |
9 | def get_chatroom_member_detail(self, chatroom_name):
10 | params = {'ChatRoomName': chatroom_name}
11 | url = self.base_url + '/group/GetChatroomMemberDetail'
12 | return post_json(url, token=self.token, data=params)
13 |
--------------------------------------------------------------------------------
/web/src/app/home/plugins/plugins.module.css:
--------------------------------------------------------------------------------
1 | .pageContainer {
2 | width: 100%;
3 | }
4 |
5 | .marketComponentBody {
6 | width: 100%;
7 | height: calc(100% - 60px);
8 | }
9 |
10 | .pluginListContainer {
11 | width: 100%;
12 | padding-left: 0.8rem;
13 | padding-right: 0.8rem;
14 | padding-top: 2rem;
15 | padding-bottom: 2rem;
16 | display: grid;
17 | grid-template-columns: repeat(auto-fill, minmax(30rem, 1fr));
18 | gap: 2rem;
19 | justify-items: stretch;
20 | align-items: start;
21 | }
22 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/openrouterchatcmpl.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import typing
4 | import openai
5 |
6 | from . import modelscopechatcmpl
7 |
8 |
9 | class OpenRouterChatCompletions(modelscopechatcmpl.ModelScopeChatCompletions):
10 | """OpenRouter ChatCompletion API 请求器"""
11 |
12 | client: openai.AsyncClient
13 |
14 | default_config: dict[str, typing.Any] = {
15 | 'base_url': 'https://openrouter.ai/api/v1',
16 | 'timeout': 120,
17 | }
18 |
--------------------------------------------------------------------------------
/src/langbot/pkg/utils/platform.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 |
4 |
5 | def get_platform() -> str:
6 | """获取当前平台"""
7 | # 检查是不是在 docker 里
8 |
9 | DOCKER_ENV = os.environ.get('DOCKER_ENV', 'false')
10 |
11 | if os.path.exists('/.dockerenv') or DOCKER_ENV == 'true':
12 | return 'docker'
13 |
14 | return sys.platform
15 |
16 |
17 | standalone_runtime = False
18 |
19 |
20 | def use_websocket_to_connect_plugin_runtime() -> bool:
21 | """是否使用 websocket 连接插件运行时"""
22 | return standalone_runtime
23 |
--------------------------------------------------------------------------------
/web/components.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://ui.shadcn.com/schema.json",
3 | "style": "new-york",
4 | "rsc": true,
5 | "tsx": true,
6 | "tailwind": {
7 | "config": "",
8 | "css": "src/app/global.css",
9 | "baseColor": "zinc",
10 | "cssVariables": true,
11 | "prefix": ""
12 | },
13 | "aliases": {
14 | "components": "@/components",
15 | "utils": "@/lib/utils",
16 | "ui": "@/components/ui",
17 | "lib": "@/lib",
18 | "hooks": "@/hooks"
19 | },
20 | "iconLibrary": "lucide"
21 | }
22 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.yml:
--------------------------------------------------------------------------------
1 | name: 需求建议
2 | title: "[Feature]: "
3 | labels: []
4 | description: "【供中文用户】新功能或现有功能优化请使用这个模板;不符合类别的issue将被直接关闭"
5 | body:
6 | - type: dropdown
7 | attributes:
8 | label: 这是一个?
9 | description: 新功能建议还是现有功能优化
10 | options:
11 | - 新功能
12 | - 现有功能优化
13 | validations:
14 | required: true
15 | - type: textarea
16 | attributes:
17 | label: 详细描述
18 | description: 详细描述,越详细越好
19 | validations:
20 | required: true
21 |
22 |
--------------------------------------------------------------------------------
/web/src/app/infra/http/HttpClient.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @deprecated 此文件仅用于向后兼容。请使用新的 client:
3 | * - import { backendClient } from '@/app/infra/http'
4 | * - import { getCloudServiceClient } from '@/app/infra/http'
5 | */
6 |
7 | // 重新导出新的客户端实现,保持向后兼容
8 | export {
9 | backendClient as httpClient,
10 | systemInfo,
11 | type ResponseData,
12 | type RequestConfig,
13 | } from './index';
14 |
15 | // 为了兼容性,重新导出 BackendClient 作为 HttpClient
16 | import { BackendClient } from './BackendClient';
17 | export const HttpClient = BackendClient;
18 |
--------------------------------------------------------------------------------
/src/langbot/pkg/entity/persistence/vector.py:
--------------------------------------------------------------------------------
1 | from sqlalchemy import Column, Integer, ForeignKey, LargeBinary
2 | from sqlalchemy.orm import declarative_base, relationship
3 |
4 | Base = declarative_base()
5 |
6 |
7 | class Vector(Base):
8 | __tablename__ = 'vectors'
9 | id = Column(Integer, primary_key=True, index=True)
10 | chunk_id = Column(Integer, ForeignKey('chunks.id'), unique=True)
11 | embedding = Column(LargeBinary) # Store embeddings as binary
12 |
13 | chunk = relationship('Chunk', back_populates='vector')
14 |
--------------------------------------------------------------------------------
/web/src/components/providers/theme-provider.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { ThemeProvider as NextThemesProvider } from 'next-themes';
4 | import { type ThemeProviderProps } from 'next-themes';
5 |
6 | export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
7 | return (
8 |
15 | {children}
16 |
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/notes/n003_print_version.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import typing
4 | import logging
5 |
6 | from .. import note
7 |
8 |
9 | @note.note_class('PrintVersion', 3)
10 | class PrintVersion(note.LaunchNote):
11 | """Print Version Information"""
12 |
13 | async def need_show(self) -> bool:
14 | return True
15 |
16 | async def yield_note(self) -> typing.AsyncGenerator[typing.Tuple[str, int], None]:
17 | yield f'Current Version: {self.ap.ver_mgr.get_current_version()}', logging.INFO
18 |
--------------------------------------------------------------------------------
/src/langbot/pkg/entity/persistence/metadata.py:
--------------------------------------------------------------------------------
1 | import sqlalchemy
2 |
3 | from .base import Base
4 | from ...utils import constants
5 |
6 |
7 | initial_metadata = [
8 | {
9 | 'key': 'database_version',
10 | 'value': str(constants.required_database_version),
11 | },
12 | ]
13 |
14 |
15 | class Metadata(Base):
16 | """Database metadata"""
17 |
18 | __tablename__ = 'metadata'
19 |
20 | key = sqlalchemy.Column(sqlalchemy.String(255), primary_key=True)
21 | value = sqlalchemy.Column(sqlalchemy.String(255))
22 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m037_mcp_config.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('mcp-config', 37)
7 | class MCPConfigMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 | return 'mcp' not in self.ap.provider_cfg.data
13 |
14 | async def run(self):
15 | """执行迁移"""
16 | self.ap.provider_cfg.data['mcp'] = {'servers': []}
17 |
18 | await self.ap.provider_cfg.dump_config()
19 |
--------------------------------------------------------------------------------
/web/src/app/infra/entities/common.ts:
--------------------------------------------------------------------------------
1 | export interface I18nObject {
2 | en_US: string;
3 | zh_Hans: string;
4 | zh_Hant?: string;
5 | ja_JP?: string;
6 | }
7 |
8 | export interface ComponentManifest {
9 | apiVersion: string;
10 | kind: string;
11 | metadata: {
12 | name: string;
13 | label: I18nObject;
14 | description?: I18nObject;
15 | icon?: string;
16 | repository?: string;
17 | version?: string;
18 | author?: string;
19 | };
20 | spec: Record; // eslint-disable-line @typescript-eslint/no-explicit-any
21 | }
22 |
--------------------------------------------------------------------------------
/src/langbot/libs/wechatpad_api/README.md:
--------------------------------------------------------------------------------
1 | # wechatpad-python
2 |
3 |
4 | ## 此项目时准备对接wechatpadpro 的pythonsdk
5 |
6 | ## 未完工接口
7 |
8 | * 关于好友的接口
9 | * 关于群管理的接口
10 | * 关于下载的接口
11 | * 关于用户的部分接口
12 | * 关于消息的部分接口
13 | * 关于支付的
14 | * 关于朋友圈的
15 | * 关于标签的
16 | * 关于收藏的
17 |
18 | * 暂时只写了一部分接口
19 |
20 |
21 | ## 已完工接口
22 |
23 | 1. 获取普通token
24 | 2. 登录二维码(只是返回数据,暂时还未打印二维码)
25 | 3. 获取登录状态
26 | 4. 唤醒登录
27 | 5. 退出登录
28 | 6. 获取用户信息
29 | 7. 获取用户二维码
30 | 8. 上传用户头像
31 | 9. 获取设备信息
32 | 10. 发送文本消息
33 | 11. 发送图片消息
34 | 12. 发送语音消息
35 | 13. 发送app消息
36 | 14. 发送emoji消息
37 | 15. 发送名片消息
38 | 16. 撤回消息
39 |
--------------------------------------------------------------------------------
/src/langbot/pkg/platform/sources/kook.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: MessagePlatformAdapter
3 | metadata:
4 | name: kook
5 | label:
6 | en_US: KOOK
7 | zh_Hans: KOOK
8 | description:
9 | en_US: KOOK Adapter (formerly KaiHeiLa)
10 | zh_Hans: KOOK 适配器(原开黑啦),支持频道消息和私聊消息
11 | icon: kook.png
12 | spec:
13 | config:
14 | - name: token
15 | label:
16 | en_US: Bot Token
17 | zh_Hans: 机器人令牌
18 | type: string
19 | required: true
20 | default: ""
21 | execution:
22 | python:
23 | path: ./kook.py
24 | attr: KookAdapter
25 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m012_runner_config.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('runner-config', 12)
7 | class RunnerConfigMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 | return 'runner' not in self.ap.provider_cfg.data
13 |
14 | async def run(self):
15 | """执行迁移"""
16 |
17 | self.ap.provider_cfg.data['runner'] = 'local-agent'
18 |
19 | await self.ap.provider_cfg.dump_config()
20 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/submit-plugin.yml:
--------------------------------------------------------------------------------
1 | name: 提交新插件
2 | title: "[Plugin]: 请求登记新插件"
3 | labels: ["独立插件"]
4 | description: "【供中文用户】本模板供且仅供提交新插件使用"
5 | body:
6 | - type: input
7 | attributes:
8 | label: 插件名称
9 | description: 填写插件的名称
10 | validations:
11 | required: true
12 | - type: textarea
13 | attributes:
14 | label: 插件代码库地址
15 | description: 仅支持 Github
16 | validations:
17 | required: true
18 | - type: textarea
19 | attributes:
20 | label: 插件简介
21 | description: 插件的简介
22 | validations:
23 | required: true
24 |
25 |
--------------------------------------------------------------------------------
/web/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import { dirname } from 'path';
2 | import { fileURLToPath } from 'url';
3 | import { FlatCompat } from '@eslint/eslintrc';
4 | import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
5 |
6 | const __filename = fileURLToPath(import.meta.url);
7 | const __dirname = dirname(__filename);
8 |
9 | const compat = new FlatCompat({
10 | baseDirectory: __dirname,
11 | });
12 |
13 | const eslintConfig = [
14 | ...compat.extends('next/core-web-vitals', 'next/typescript'),
15 | eslintPluginPrettierRecommended,
16 | ];
17 |
18 | export default eslintConfig;
19 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "pip" # See documentation for possible values
9 | directory: "/" # Location of package manifests
10 | schedule:
11 | interval: "weekly"
12 | allow:
13 | - dependency-name: "openai"
14 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/gemini.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m011_command_prefix_config.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('command-prefix-config', 11)
7 | class CommandPrefixConfigMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 | return 'command-prefix' not in self.ap.command_cfg.data
13 |
14 | async def run(self):
15 | """执行迁移"""
16 |
17 | self.ap.command_cfg.data['command-prefix'] = ['!', '!']
18 |
19 | await self.ap.command_cfg.dump_config()
20 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/entities.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import typing
4 |
5 | import pydantic
6 |
7 | from . import requester
8 | from . import token
9 |
10 |
11 | class LLMModelInfo(pydantic.BaseModel):
12 | """模型"""
13 |
14 | name: str
15 |
16 | model_name: typing.Optional[str] = None
17 |
18 | token_mgr: token.TokenManager
19 |
20 | requester: requester.ProviderAPIRequester
21 |
22 | tool_call_supported: typing.Optional[bool] = False
23 |
24 | vision_supported: typing.Optional[bool] = False
25 |
26 | class Config:
27 | arbitrary_types_allowed = True
28 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/seekdb.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/src/langbot/pkg/persistence/databases/sqlite.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import sqlalchemy.ext.asyncio as sqlalchemy_asyncio
4 |
5 | from .. import database
6 |
7 |
8 | @database.manager_class('sqlite')
9 | class SQLiteDatabaseManager(database.BaseDatabaseManager):
10 | """SQLite database manager"""
11 |
12 | async def initialize(self) -> None:
13 | db_file_path = self.ap.instance_config.data.get('database', {}).get('sqlite', {}).get('path', 'data/langbot.db')
14 | engine_url = f'sqlite+aiosqlite:///{db_file_path}'
15 | self.engine = sqlalchemy_asyncio.create_async_engine(engine_url)
16 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m006_vision_config.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('vision-config', 6)
7 | class VisionConfigMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 | return 'enable-vision' not in self.ap.provider_cfg.data
13 |
14 | async def run(self):
15 | """执行迁移"""
16 | if 'enable-vision' not in self.ap.provider_cfg.data:
17 | self.ap.provider_cfg.data['enable-vision'] = False
18 |
19 | await self.ap.provider_cfg.dump_config()
20 |
--------------------------------------------------------------------------------
/web/src/app/infra/entities/pipeline/index.ts:
--------------------------------------------------------------------------------
1 | import { I18nObject } from '@/app/infra/entities/common';
2 | import { IDynamicFormItemSchema } from '@/app/infra/entities/form/dynamic';
3 |
4 | export interface PipelineFormEntity {
5 | basic: object;
6 | ai: object;
7 | trigger: object;
8 | safety: object;
9 | output: object;
10 | }
11 |
12 | export interface PipelineConfigTab {
13 | name: string;
14 | label: I18nObject;
15 | stages: PipelineConfigStage[];
16 | }
17 |
18 | export interface PipelineConfigStage {
19 | name: string;
20 | label: I18nObject;
21 | description?: I18nObject;
22 | config: IDynamicFormItemSchema[];
23 | }
24 |
--------------------------------------------------------------------------------
/src/langbot/pkg/platform/sources/telegram.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/token.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import typing
4 |
5 |
6 | class TokenManager:
7 | """鉴权 Token 管理器"""
8 |
9 | name: str
10 |
11 | tokens: list[str]
12 |
13 | using_token_index: typing.Optional[int] = 0
14 |
15 | def __init__(self, name: str, tokens: list[str]):
16 | self.name = name
17 | self.tokens = tokens
18 | self.using_token_index = 0
19 |
20 | def get_token(self) -> str:
21 | return self.tokens[self.using_token_index]
22 |
23 | def next_token(self):
24 | self.using_token_index = (self.using_token_index + 1) % len(self.tokens)
25 |
--------------------------------------------------------------------------------
/web/src/app/home/models/component/embedding-card/EmbeddingCardVO.ts:
--------------------------------------------------------------------------------
1 | export interface IEmbeddingCardVO {
2 | id: string;
3 | iconURL: string;
4 | name: string;
5 | providerLabel: string;
6 | baseURL: string;
7 | }
8 |
9 | export class EmbeddingCardVO implements IEmbeddingCardVO {
10 | id: string;
11 | iconURL: string;
12 | providerLabel: string;
13 | name: string;
14 | baseURL: string;
15 |
16 | constructor(props: IEmbeddingCardVO) {
17 | this.id = props.id;
18 | this.iconURL = props.iconURL;
19 | this.providerLabel = props.providerLabel;
20 | this.name = props.name;
21 | this.baseURL = props.baseURL;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/web/src/hooks/use-mobile.ts:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | const MOBILE_BREAKPOINT = 768;
4 |
5 | export function useIsMobile() {
6 | const [isMobile, setIsMobile] = React.useState(
7 | undefined,
8 | );
9 |
10 | React.useEffect(() => {
11 | const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
12 | const onChange = () => {
13 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
14 | };
15 | mql.addEventListener('change', onChange);
16 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
17 | return () => mql.removeEventListener('change', onChange);
18 | }, []);
19 |
20 | return !!isMobile;
21 | }
22 |
--------------------------------------------------------------------------------
/src/langbot/pkg/entity/persistence/user.py:
--------------------------------------------------------------------------------
1 | import sqlalchemy
2 |
3 | from .base import Base
4 |
5 |
6 | class User(Base):
7 | __tablename__ = 'users'
8 |
9 | id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
10 | user = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
11 | password = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
12 | created_at = sqlalchemy.Column(sqlalchemy.DateTime, nullable=False, server_default=sqlalchemy.func.now())
13 | updated_at = sqlalchemy.Column(
14 | sqlalchemy.DateTime,
15 | nullable=False,
16 | server_default=sqlalchemy.func.now(),
17 | onupdate=sqlalchemy.func.now(),
18 | )
19 |
--------------------------------------------------------------------------------
/web/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.*
7 | .yarn/*
8 | !.yarn/patches
9 | !.yarn/plugins
10 | !.yarn/releases
11 | !.yarn/versions
12 |
13 | # testing
14 | /coverage
15 |
16 | # next.js
17 | /.next/
18 | /out/
19 |
20 | # production
21 | /build
22 |
23 | # misc
24 | .DS_Store
25 | *.pem
26 |
27 | # debug
28 | npm-debug.log*
29 | yarn-debug.log*
30 | yarn-error.log*
31 | .pnpm-debug.log*
32 |
33 | # env files (can opt-in for committing if needed)
34 | .env*
35 | !.env.example
36 |
37 | # vercel
38 | .vercel
39 |
40 | # typescript
41 | *.tsbuildinfo
42 | next-env.d.ts
43 |
--------------------------------------------------------------------------------
/web/src/app/infra/basic-component/create-card-component/CreateCardComponent.tsx:
--------------------------------------------------------------------------------
1 | import styles from './createCartComponent.module.css';
2 |
3 | export default function CreateCardComponent({
4 | height,
5 | plusSize,
6 | onClick,
7 | width = '100%',
8 | }: {
9 | height: string;
10 | plusSize: string;
11 | onClick: () => void;
12 | width?: string;
13 | }) {
14 | return (
15 |
24 | +
25 |
26 | );
27 | }
28 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m009_msg_truncator_cfg.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('msg-truncator-cfg-migration', 9)
7 | class MsgTruncatorConfigMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 | return 'msg-truncate' not in self.ap.pipeline_cfg.data
13 |
14 | async def run(self):
15 | """执行迁移"""
16 |
17 | self.ap.pipeline_cfg.data['msg-truncate'] = {
18 | 'method': 'round',
19 | 'round': {'max-round': 10},
20 | }
21 |
22 | await self.ap.pipeline_cfg.dump_config()
23 |
--------------------------------------------------------------------------------
/web/src/app/home/pipelines/components/pipeline-card/PipelineCardVO.ts:
--------------------------------------------------------------------------------
1 | export interface IPipelineCardVO {
2 | id: string;
3 | name: string;
4 | description: string;
5 | lastUpdatedTimeAgo: string;
6 | isDefault: boolean;
7 | }
8 |
9 | export class PipelineCardVO implements IPipelineCardVO {
10 | id: string;
11 | description: string;
12 | name: string;
13 | lastUpdatedTimeAgo: string;
14 | isDefault: boolean;
15 |
16 | constructor(props: IPipelineCardVO) {
17 | this.id = props.id;
18 | this.name = props.name;
19 | this.description = props.description;
20 | this.lastUpdatedTimeAgo = props.lastUpdatedTimeAgo;
21 | this.isDefault = props.isDefault;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m007_qcg_center_url.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('qcg-center-url-config', 7)
7 | class QCGCenterURLConfigMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 | return 'qcg-center-url' not in self.ap.system_cfg.data
13 |
14 | async def run(self):
15 | """执行迁移"""
16 |
17 | if 'qcg-center-url' not in self.ap.system_cfg.data:
18 | self.ap.system_cfg.data['qcg-center-url'] = 'https://api.qchatgpt.rockchin.top/api/v2'
19 |
20 | await self.ap.system_cfg.dump_config()
21 |
--------------------------------------------------------------------------------
/web/src/components/ui/sonner.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useTheme } from 'next-themes';
4 | import { Toaster as Sonner, ToasterProps } from 'sonner';
5 |
6 | const Toaster = ({ ...props }: ToasterProps) => {
7 | const { theme = 'system' } = useTheme();
8 |
9 | return (
10 |
22 | );
23 | };
24 |
25 | export { Toaster };
26 |
--------------------------------------------------------------------------------
/web/src/app/home/models/component/llm-card/LLMCardVO.ts:
--------------------------------------------------------------------------------
1 | export interface ILLMCardVO {
2 | id: string;
3 | iconURL: string;
4 | name: string;
5 | providerLabel: string;
6 | baseURL: string;
7 | abilities: string[];
8 | }
9 |
10 | export class LLMCardVO implements ILLMCardVO {
11 | id: string;
12 | iconURL: string;
13 | providerLabel: string;
14 | name: string;
15 | baseURL: string;
16 | abilities: string[];
17 |
18 | constructor(props: ILLMCardVO) {
19 | this.id = props.id;
20 | this.iconURL = props.iconURL;
21 | this.providerLabel = props.providerLabel;
22 | this.name = props.name;
23 | this.baseURL = props.baseURL;
24 | this.abilities = props.abilities;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/web/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2017",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "noEmit": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "resolveJsonModule": true,
13 | "isolatedModules": true,
14 | "jsx": "preserve",
15 | "incremental": true,
16 | "plugins": [
17 | {
18 | "name": "next"
19 | }
20 | ],
21 | "paths": {
22 | "@/*": ["./src/*"]
23 | }
24 | },
25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
26 | "exclude": ["node_modules"]
27 | }
28 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/xaichatcmpl.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: LLMAPIRequester
3 | metadata:
4 | name: xai-chat-completions
5 | label:
6 | en_US: xAI
7 | zh_Hans: xAI
8 | icon: xai.svg
9 | spec:
10 | config:
11 | - name: base_url
12 | label:
13 | en_US: Base URL
14 | zh_Hans: 基础 URL
15 | type: string
16 | required: true
17 | default: https://api.x.ai/v1
18 | - name: timeout
19 | label:
20 | en_US: Timeout
21 | zh_Hans: 超时时间
22 | type: integer
23 | required: true
24 | default: 120
25 | support_type:
26 | - llm
27 | provider_category: manufacturer
28 | execution:
29 | python:
30 | path: ./xaichatcmpl.py
31 | attr: XaiChatCompletions
32 |
--------------------------------------------------------------------------------
/src/langbot/pkg/platform/sources/slack.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: MessagePlatformAdapter
3 | metadata:
4 | name: slack
5 | label:
6 | en_US: Slack
7 | zh_Hans: Slack
8 | description:
9 | en_US: Slack Adapter
10 | zh_Hans: Slack 适配器,请查看文档了解使用方式
11 | icon: slack.png
12 | spec:
13 | config:
14 | - name: bot_token
15 | label:
16 | en_US: Bot Token
17 | zh_Hans: 机器人令牌
18 | type: string
19 | required: true
20 | default: ""
21 | - name: signing_secret
22 | label:
23 | en_US: signing_secret
24 | zh_Hans: 密钥
25 | type: string
26 | required: true
27 | default: ""
28 | execution:
29 | python:
30 | path: ./slack.py
31 | attr: SlackAdapter
--------------------------------------------------------------------------------
/web/src/components/ui/label.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import * as React from 'react';
4 | import * as LabelPrimitive from '@radix-ui/react-label';
5 |
6 | import { cn } from '@/lib/utils';
7 |
8 | function Label({
9 | className,
10 | ...props
11 | }: React.ComponentProps) {
12 | return (
13 |
21 | );
22 | }
23 |
24 | export { Label };
25 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request_en.yml:
--------------------------------------------------------------------------------
1 | name: Feature request
2 | title: "[Feature]: "
3 | labels: []
4 | description: "New features or existing feature improvements should use this template; issues that do not match will be closed directly"
5 | body:
6 | - type: dropdown
7 | attributes:
8 | label: This is a?
9 | description: New feature request or existing feature improvement
10 | options:
11 | - New feature
12 | - Existing feature improvement
13 | validations:
14 | required: true
15 | - type: textarea
16 | attributes:
17 | label: Detailed description
18 | description: Detailed description, the more detailed the better
19 | validations:
20 | required: true
21 |
22 |
--------------------------------------------------------------------------------
/src/langbot/pkg/platform/sources/discord.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: MessagePlatformAdapter
3 | metadata:
4 | name: discord
5 | label:
6 | en_US: Discord
7 | zh_Hans: Discord
8 | description:
9 | en_US: Discord Adapter
10 | zh_Hans: Discord 适配器,请查看文档了解使用方式
11 | icon: discord.svg
12 | spec:
13 | config:
14 | - name: client_id
15 | label:
16 | en_US: Client ID
17 | zh_Hans: 客户端ID
18 | type: string
19 | required: true
20 | default: ""
21 | - name: token
22 | label:
23 | en_US: Token
24 | zh_Hans: 令牌
25 | type: string
26 | required: true
27 | default: ""
28 | execution:
29 | python:
30 | path: ./discord.py
31 | attr: DiscordAdapter
32 |
--------------------------------------------------------------------------------
/src/langbot/pkg/persistence/migrations/dbm008_plugin_config.py:
--------------------------------------------------------------------------------
1 | from .. import migration
2 |
3 |
4 | @migration.migration_class(8)
5 | class DBMigratePluginConfig(migration.DBMigration):
6 | """插件配置"""
7 |
8 | async def upgrade(self):
9 | """升级"""
10 |
11 | if 'plugin' not in self.ap.instance_config.data:
12 | self.ap.instance_config.data['plugin'] = {
13 | 'runtime_ws_url': 'ws://langbot_plugin_runtime:5400/control/ws',
14 | 'enable_marketplace': True,
15 | 'cloud_service_url': 'https://space.langbot.app',
16 | }
17 |
18 | await self.ap.instance_config.dump_config()
19 |
20 | async def downgrade(self):
21 | """降级"""
22 | pass
23 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m014_force_delay_config.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('force-delay-config', 14)
7 | class ForceDelayConfigMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 | return isinstance(self.ap.platform_cfg.data['force-delay'], list)
13 |
14 | async def run(self):
15 | """执行迁移"""
16 |
17 | self.ap.platform_cfg.data['force-delay'] = {
18 | 'min': self.ap.platform_cfg.data['force-delay'][0],
19 | 'max': self.ap.platform_cfg.data['force-delay'][1],
20 | }
21 |
22 | await self.ap.platform_cfg.dump_config()
23 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m010_ollama_requester_config.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('ollama-requester-config', 10)
7 | class MsgTruncatorConfigMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 | return 'ollama-chat' not in self.ap.provider_cfg.data['requester']
13 |
14 | async def run(self):
15 | """执行迁移"""
16 |
17 | self.ap.provider_cfg.data['requester']['ollama-chat'] = {
18 | 'base-url': 'http://127.0.0.1:11434',
19 | 'args': {},
20 | 'timeout': 600,
21 | }
22 |
23 | await self.ap.provider_cfg.dump_config()
24 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/anthropicmsgs.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: LLMAPIRequester
3 | metadata:
4 | name: anthropic-messages
5 | label:
6 | en_US: Anthropic
7 | zh_Hans: Anthropic
8 | icon: anthropic.svg
9 | spec:
10 | config:
11 | - name: base_url
12 | label:
13 | en_US: Base URL
14 | zh_Hans: 基础 URL
15 | type: string
16 | required: true
17 | default: https://api.anthropic.com
18 | - name: timeout
19 | label:
20 | en_US: Timeout
21 | zh_Hans: 超时时间
22 | type: integer
23 | required: true
24 | default: 120
25 | support_type:
26 | - llm
27 | provider_category: manufacturer
28 | execution:
29 | python:
30 | path: ./anthropicmsgs.py
31 | attr: AnthropicMessages
32 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/ollamachat.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: LLMAPIRequester
3 | metadata:
4 | name: ollama-chat
5 | label:
6 | en_US: Ollama
7 | zh_Hans: Ollama
8 | icon: ollama.svg
9 | spec:
10 | config:
11 | - name: base_url
12 | label:
13 | en_US: Base URL
14 | zh_Hans: 基础 URL
15 | type: string
16 | required: true
17 | default: http://127.0.0.1:11434
18 | - name: timeout
19 | label:
20 | en_US: Timeout
21 | zh_Hans: 超时时间
22 | type: integer
23 | required: true
24 | default: 120
25 | support_type:
26 | - llm
27 | - text-embedding
28 | provider_category: self-hosted
29 | execution:
30 | python:
31 | path: ./ollamachat.py
32 | attr: OllamaChatCompletions
33 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m022_lmstudio_config.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('lmstudio-config', 22)
7 | class LmStudioConfigMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 |
13 | return 'lmstudio-chat-completions' not in self.ap.provider_cfg.data['requester']
14 |
15 | async def run(self):
16 | """执行迁移"""
17 | self.ap.provider_cfg.data['requester']['lmstudio-chat-completions'] = {
18 | 'base-url': 'http://127.0.0.1:1234/v1',
19 | 'args': {},
20 | 'timeout': 120,
21 | }
22 |
23 | await self.ap.provider_cfg.dump_config()
24 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/302aichatcmpl.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: LLMAPIRequester
3 | metadata:
4 | name: 302-ai-chat-completions
5 | label:
6 | en_US: 302.AI
7 | zh_Hans: 302.AI
8 | icon: 302ai.png
9 | spec:
10 | config:
11 | - name: base_url
12 | label:
13 | en_US: Base URL
14 | zh_Hans: 基础 URL
15 | type: string
16 | required: true
17 | default: https://api.302.ai/v1
18 | - name: timeout
19 | label:
20 | en_US: Timeout
21 | zh_Hans: 超时时间
22 | type: integer
23 | required: true
24 | default: 120
25 | support_type:
26 | - llm
27 | - text-embedding
28 | provider_category: maas
29 | execution:
30 | python:
31 | path: ./302aichatcmpl.py
32 | attr: AI302ChatCompletions
33 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/submit-plugin_en.yml:
--------------------------------------------------------------------------------
1 | name: Submit a new plugin
2 | title: "[Plugin]: Request to register a new plugin"
3 | labels: ["Independent Plugin"]
4 | description: "This template is only for submitting new plugins"
5 | body:
6 | - type: input
7 | attributes:
8 | label: Plugin name
9 | description: Fill in the name of the plugin
10 | validations:
11 | required: true
12 | - type: textarea
13 | attributes:
14 | label: Plugin code repository address
15 | description: Only support Github
16 | validations:
17 | required: true
18 | - type: textarea
19 | attributes:
20 | label: Plugin description
21 | description: The description of the plugin
22 | validations:
23 | required: true
24 |
25 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/chatcmpl.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: LLMAPIRequester
3 | metadata:
4 | name: openai-chat-completions
5 | label:
6 | en_US: OpenAI
7 | zh_Hans: OpenAI
8 | icon: openai.svg
9 | spec:
10 | config:
11 | - name: base_url
12 | label:
13 | en_US: Base URL
14 | zh_Hans: 基础 URL
15 | type: string
16 | required: true
17 | default: https://api.openai.com/v1
18 | - name: timeout
19 | label:
20 | en_US: Timeout
21 | zh_Hans: 超时时间
22 | type: integer
23 | required: true
24 | default: 120
25 | support_type:
26 | - llm
27 | - text-embedding
28 | provider_category: manufacturer
29 | execution:
30 | python:
31 | path: ./chatcmpl.py
32 | attr: OpenAIChatCompletions
33 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/compsharechatcmpl.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: LLMAPIRequester
3 | metadata:
4 | name: compshare-chat-completions
5 | label:
6 | en_US: CompShare
7 | zh_Hans: 优云智算
8 | icon: compshare.png
9 | spec:
10 | config:
11 | - name: base_url
12 | label:
13 | en_US: Base URL
14 | zh_Hans: 基础 URL
15 | type: string
16 | required: true
17 | default: https://api.modelverse.cn/v1
18 | - name: timeout
19 | label:
20 | en_US: Timeout
21 | zh_Hans: 超时时间
22 | type: integer
23 | required: true
24 | default: 120
25 | support_type:
26 | - llm
27 | provider_category: maas
28 | execution:
29 | python:
30 | path: ./compsharechatcmpl.py
31 | attr: CompShareChatCompletions
32 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/deepseekchatcmpl.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: LLMAPIRequester
3 | metadata:
4 | name: deepseek-chat-completions
5 | label:
6 | en_US: DeepSeek
7 | zh_Hans: DeepSeek
8 | icon: deepseek.svg
9 | spec:
10 | config:
11 | - name: base_url
12 | label:
13 | en_US: Base URL
14 | zh_Hans: 基础 URL
15 | type: string
16 | required: true
17 | default: https://api.deepseek.com
18 | - name: timeout
19 | label:
20 | en_US: Timeout
21 | zh_Hans: 超时时间
22 | type: integer
23 | required: true
24 | default: 120
25 | support_type:
26 | - llm
27 | provider_category: manufacturer
28 | execution:
29 | python:
30 | path: ./deepseekchatcmpl.py
31 | attr: DeepseekChatCompletions
32 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/moonshotchatcmpl.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: LLMAPIRequester
3 | metadata:
4 | name: moonshot-chat-completions
5 | label:
6 | en_US: Moonshot
7 | zh_Hans: 月之暗面
8 | icon: moonshot.png
9 | spec:
10 | config:
11 | - name: base_url
12 | label:
13 | en_US: Base URL
14 | zh_Hans: 基础 URL
15 | type: string
16 | required: true
17 | default: https://api.moonshot.ai/v1
18 | - name: timeout
19 | label:
20 | en_US: Timeout
21 | zh_Hans: 超时时间
22 | type: integer
23 | required: true
24 | default: 120
25 | support_type:
26 | - llm
27 | provider_category: manufacturer
28 | execution:
29 | python:
30 | path: ./moonshotchatcmpl.py
31 | attr: MoonshotChatCompletions
32 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/newapichatcmpl.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: LLMAPIRequester
3 | metadata:
4 | name: new-api-chat-completions
5 | label:
6 | en_US: New API
7 | zh_Hans: New API
8 | icon: newapi.png
9 | spec:
10 | config:
11 | - name: base_url
12 | label:
13 | en_US: Base URL
14 | zh_Hans: 基础 URL
15 | type: string
16 | required: true
17 | default: http://localhost:3000/v1
18 | - name: timeout
19 | label:
20 | en_US: Timeout
21 | zh_Hans: 超时时间
22 | type: integer
23 | required: true
24 | default: 120
25 | support_type:
26 | - llm
27 | - text-embedding
28 | provider_category: maas
29 | execution:
30 | python:
31 | path: ./newapichatcmpl.py
32 | attr: NewAPIChatCompletions
33 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/seekdbembed.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: LLMAPIRequester
3 | metadata:
4 | name: seekdb-embedding
5 | label:
6 | en_US: SeekDB Embedding
7 | zh_Hans: SeekDB 嵌入
8 | description:
9 | en_US: SeekDB Python library built-in embedding model (all-MiniLM-L6-v2), it will take time to download the model file for the first time
10 | zh_Hans: 使用来自 SeekDB Python 库的内置嵌入模型 (all-MiniLM-L6-v2),首次使用时将会花费时间自动下载模型文件
11 | ja_JP: SeekDB Python ライブラリの組み込み埋め込みモデル (all-MiniLM-L6-v2) を使用します。初回使用時にモデルファイルのダウンロードに時間がかかります。
12 | icon: seekdb.svg
13 | spec:
14 | config: []
15 | support_type:
16 | - text-embedding
17 | provider_category: builtin
18 | execution:
19 | python:
20 | path: ./seekdbembed.py
21 | attr: SeekDBEmbedding
22 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/zhipuaichatcmpl.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: LLMAPIRequester
3 | metadata:
4 | name: zhipuai-chat-completions
5 | label:
6 | en_US: ZhipuAI
7 | zh_Hans: 智谱 AI
8 | icon: zhipuai.svg
9 | spec:
10 | config:
11 | - name: base_url
12 | label:
13 | en_US: Base URL
14 | zh_Hans: 基础 URL
15 | type: string
16 | required: true
17 | default: https://open.bigmodel.cn/api/paas/v4
18 | - name: timeout
19 | label:
20 | en_US: Timeout
21 | zh_Hans: 超时时间
22 | type: integer
23 | required: true
24 | default: 120
25 | support_type:
26 | - llm
27 | provider_category: manufacturer
28 | execution:
29 | python:
30 | path: ./zhipuaichatcmpl.py
31 | attr: ZhipuAIChatCompletions
32 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/volcarkchatcmpl.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: LLMAPIRequester
3 | metadata:
4 | name: volcark-chat-completions
5 | label:
6 | en_US: Volc Engine Ark
7 | zh_Hans: 火山方舟
8 | icon: volcark.svg
9 | spec:
10 | config:
11 | - name: base_url
12 | label:
13 | en_US: Base URL
14 | zh_Hans: 基础 URL
15 | type: string
16 | required: true
17 | default: https://ark.cn-beijing.volces.com/api/v3
18 | - name: timeout
19 | label:
20 | en_US: Timeout
21 | zh_Hans: 超时时间
22 | type: integer
23 | required: true
24 | default: 120
25 | support_type:
26 | - llm
27 | provider_category: maas
28 | execution:
29 | python:
30 | path: ./volcarkchatcmpl.py
31 | attr: VolcArkChatCompletions
32 |
--------------------------------------------------------------------------------
/src/langbot/libs/wechatpad_api/util/terminal_printer.py:
--------------------------------------------------------------------------------
1 | import qrcode
2 |
3 |
4 | def print_green(text):
5 | print(f'\033[32m{text}\033[0m')
6 |
7 |
8 | def print_yellow(text):
9 | print(f'\033[33m{text}\033[0m')
10 |
11 |
12 | def print_red(text):
13 | print(f'\033[31m{text}\033[0m')
14 |
15 |
16 | def make_and_print_qr(url):
17 | """生成并打印二维码
18 |
19 | Args:
20 | url: 需要生成二维码的URL字符串
21 |
22 | Returns:
23 | None
24 |
25 | 功能:
26 | 1. 在终端打印二维码的ASCII图形
27 | 2. 同时提供在线二维码生成链接作为备选
28 | """
29 | print_green('请扫描下方二维码登录')
30 | qr = qrcode.QRCode()
31 | qr.add_data(url)
32 | qr.make()
33 | qr.print_ascii(invert=True)
34 | print_green(f'也可以访问下方链接获取二维码:\nhttps://api.qrserver.com/v1/create-qr-code/?data={url}')
35 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/bailianchatcmpl.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: LLMAPIRequester
3 | metadata:
4 | name: bailian-chat-completions
5 | label:
6 | en_US: Aliyun Bailian
7 | zh_Hans: 阿里云百炼
8 | icon: bailian.png
9 | spec:
10 | config:
11 | - name: base_url
12 | label:
13 | en_US: Base URL
14 | zh_Hans: 基础 URL
15 | type: string
16 | required: true
17 | default: https://dashscope.aliyuncs.com/compatible-mode/v1
18 | - name: timeout
19 | label:
20 | en_US: Timeout
21 | zh_Hans: 超时时间
22 | type: integer
23 | required: true
24 | default: 120
25 | support_type:
26 | - llm
27 | provider_category: maas
28 | execution:
29 | python:
30 | path: ./bailianchatcmpl.py
31 | attr: BailianChatCompletions
32 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/giteeaichatcmpl.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: LLMAPIRequester
3 | metadata:
4 | name: gitee-ai-chat-completions
5 | label:
6 | en_US: Gitee AI
7 | zh_Hans: Gitee AI
8 | icon: giteeai.svg
9 | spec:
10 | config:
11 | - name: base_url
12 | label:
13 | en_US: Base URL
14 | zh_Hans: 基础 URL
15 | type: string
16 | required: true
17 | default: https://ai.gitee.com/v1
18 | - name: timeout
19 | label:
20 | en_US: Timeout
21 | zh_Hans: 超时时间
22 | type: integer
23 | required: true
24 | default: 120
25 | support_type:
26 | - llm
27 | - text-embedding
28 | provider_category: maas
29 | execution:
30 | python:
31 | path: ./giteeaichatcmpl.py
32 | attr: GiteeAIChatCompletions
33 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/tokenpony.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: LLMAPIRequester
3 | metadata:
4 | name: tokenpony-chat-completions
5 | label:
6 | en_US: TokenPony
7 | zh_Hans: 小马算力
8 | icon: tokenpony.svg
9 | spec:
10 | config:
11 | - name: base_url
12 | label:
13 | en_US: Base URL
14 | zh_Hans: 基础 URL
15 | type: string
16 | required: true
17 | default: https://api.tokenpony.cn/v1
18 | - name: timeout
19 | label:
20 | en_US: Timeout
21 | zh_Hans: 超时时间
22 | type: integer
23 | required: true
24 | default: 120
25 | support_type:
26 | - llm
27 | - text-embedding
28 | provider_category: maas
29 | execution:
30 | python:
31 | path: ./tokenponychatcmpl.py
32 | attr: TokenPonyChatCompletions
33 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m001_sensitive_word_migration.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import os
4 |
5 | from .. import migration
6 |
7 |
8 | @migration.migration_class('sensitive-word-migration', 1)
9 | class SensitiveWordMigration(migration.Migration):
10 | """敏感词迁移"""
11 |
12 | async def need_migrate(self) -> bool:
13 | """判断当前环境是否需要运行此迁移"""
14 | return os.path.exists('data/config/sensitive-words.json') and not os.path.exists(
15 | 'data/metadata/sensitive-words.json'
16 | )
17 |
18 | async def run(self):
19 | """执行迁移"""
20 | # 移动文件
21 | os.rename('data/config/sensitive-words.json', 'data/metadata/sensitive-words.json')
22 |
23 | # 重新加载配置
24 | await self.ap.sensitive_meta.load_config()
25 |
--------------------------------------------------------------------------------
/src/langbot/templates/legacy/system.json:
--------------------------------------------------------------------------------
1 | {
2 | "admin-sessions": [],
3 | "network-proxies": {
4 | "http": null,
5 | "https": null
6 | },
7 | "report-usage": true,
8 | "logging-level": "info",
9 | "session-concurrency": {
10 | "default": 1
11 | },
12 | "pipeline-concurrency": 20,
13 | "qcg-center-url": "https://api.qchatgpt.rockchin.top/api/v2",
14 | "help-message": "LangBot - 😎高稳定性、🧩支持插件、🌏实时联网的 ChatGPT QQ 机器人🤖\n链接:https://q.rkcn.top",
15 | "http-api": {
16 | "enable": true,
17 | "host": "0.0.0.0",
18 | "port": 5300,
19 | "jwt-expire": 604800
20 | },
21 | "persistence": {
22 | "sqlite": {
23 | "path": "data/langbot.db"
24 | },
25 | "use": "sqlite"
26 | }
27 | }
--------------------------------------------------------------------------------
/web/src/components/ui/theme-toggle.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import * as React from 'react';
4 | import { Moon, Sun } from 'lucide-react';
5 | import { useTheme } from 'next-themes';
6 |
7 | import { Button } from '@/components/ui/button';
8 |
9 | export function ThemeToggle() {
10 | const { theme, setTheme } = useTheme();
11 |
12 | return (
13 |
22 | );
23 | }
24 |
--------------------------------------------------------------------------------
/web/src/app/home/knowledge/components/kb-card/KBCardVO.ts:
--------------------------------------------------------------------------------
1 | export interface IKnowledgeBaseVO {
2 | id: string;
3 | name: string;
4 | description: string;
5 | embeddingModelUUID: string;
6 | top_k: number;
7 | lastUpdatedTimeAgo: string;
8 | }
9 |
10 | export class KnowledgeBaseVO implements IKnowledgeBaseVO {
11 | id: string;
12 | name: string;
13 | description: string;
14 | embeddingModelUUID: string;
15 | top_k: number;
16 | lastUpdatedTimeAgo: string;
17 |
18 | constructor(props: IKnowledgeBaseVO) {
19 | this.id = props.id;
20 | this.name = props.name;
21 | this.description = props.description;
22 | this.embeddingModelUUID = props.embeddingModelUUID;
23 | this.top_k = props.top_k;
24 | this.lastUpdatedTimeAgo = props.lastUpdatedTimeAgo;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/langbot/pkg/pipeline/resprule/rules/random.py:
--------------------------------------------------------------------------------
1 | import random
2 |
3 |
4 | from .. import rule as rule_model
5 | from .. import entities
6 | import langbot_plugin.api.entities.builtin.platform.message as platform_message
7 | import langbot_plugin.api.entities.builtin.pipeline.query as pipeline_query
8 |
9 |
10 | @rule_model.rule_class('random')
11 | class RandomRespRule(rule_model.GroupRespondRule):
12 | async def match(
13 | self,
14 | message_text: str,
15 | message_chain: platform_message.MessageChain,
16 | rule_dict: dict,
17 | query: pipeline_query.Query,
18 | ) -> entities.RuleJudgeResult:
19 | random_rate = rule_dict['random']
20 |
21 | return entities.RuleJudgeResult(matching=random.random() < random_rate, replacement=message_chain)
22 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/lmstudiochatcmpl.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: LLMAPIRequester
3 | metadata:
4 | name: lmstudio-chat-completions
5 | label:
6 | en_US: LM Studio
7 | zh_Hans: LM Studio
8 | icon: lmstudio.webp
9 | spec:
10 | config:
11 | - name: base_url
12 | label:
13 | en_US: Base URL
14 | zh_Hans: 基础 URL
15 | type: string
16 | required: true
17 | default: http://127.0.0.1:1234/v1
18 | - name: timeout
19 | label:
20 | en_US: Timeout
21 | zh_Hans: 超时时间
22 | type: integer
23 | required: true
24 | default: 120
25 | support_type:
26 | - llm
27 | - text-embedding
28 | provider_category: self-hosted
29 | execution:
30 | python:
31 | path: ./lmstudiochatcmpl.py
32 | attr: LmStudioChatCompletions
33 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m018_xai_config.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('xai-config', 18)
7 | class XaiConfigMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 | return 'xai-chat-completions' not in self.ap.provider_cfg.data['requester']
13 |
14 | async def run(self):
15 | """执行迁移"""
16 | self.ap.provider_cfg.data['requester']['xai-chat-completions'] = {
17 | 'base-url': 'https://api.x.ai/v1',
18 | 'args': {},
19 | 'timeout': 120,
20 | }
21 | self.ap.provider_cfg.data['keys']['xai'] = ['xai-1234567890']
22 |
23 | await self.ap.provider_cfg.dump_config()
24 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/geminichatcmpl.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: LLMAPIRequester
3 | metadata:
4 | name: gemini-chat-completions
5 | label:
6 | en_US: Google Gemini
7 | zh_Hans: Google Gemini
8 | icon: gemini.svg
9 | spec:
10 | config:
11 | - name: base_url
12 | label:
13 | en_US: Base URL
14 | zh_Hans: 基础 URL
15 | type: string
16 | required: true
17 | default: https://generativelanguage.googleapis.com/v1beta/openai
18 | - name: timeout
19 | label:
20 | en_US: Timeout
21 | zh_Hans: 超时时间
22 | type: integer
23 | required: true
24 | default: 120
25 | support_type:
26 | - llm
27 | provider_category: manufacturer
28 | execution:
29 | python:
30 | path: ./geminichatcmpl.py
31 | attr: GeminiChatCompletions
32 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/openrouterchatcmpl.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: LLMAPIRequester
3 | metadata:
4 | name: openrouter-chat-completions
5 | label:
6 | en_US: OpenRouter
7 | zh_Hans: OpenRouter
8 | icon: openrouter.svg
9 | spec:
10 | config:
11 | - name: base_url
12 | label:
13 | en_US: Base URL
14 | zh_Hans: 基础 URL
15 | type: string
16 | required: true
17 | default: https://openrouter.ai/api/v1
18 | - name: timeout
19 | label:
20 | en_US: Timeout
21 | zh_Hans: 超时时间
22 | type: integer
23 | required: true
24 | default: 120
25 | support_type:
26 | - llm
27 | - text-embedding
28 | provider_category: maas
29 | execution:
30 | python:
31 | path: ./openrouterchatcmpl.py
32 | attr: OpenRouterChatCompletions
33 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/siliconflowchatcmpl.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: LLMAPIRequester
3 | metadata:
4 | name: siliconflow-chat-completions
5 | label:
6 | en_US: SiliconFlow
7 | zh_Hans: 硅基流动
8 | icon: siliconflow.svg
9 | spec:
10 | config:
11 | - name: base_url
12 | label:
13 | en_US: Base URL
14 | zh_Hans: 基础 URL
15 | type: string
16 | required: true
17 | default: https://api.siliconflow.cn/v1
18 | - name: timeout
19 | label:
20 | en_US: Timeout
21 | zh_Hans: 超时时间
22 | type: integer
23 | required: true
24 | default: 120
25 | support_type:
26 | - llm
27 | - text-embedding
28 | provider_category: maas
29 | execution:
30 | python:
31 | path: ./siliconflowchatcmpl.py
32 | attr: SiliconFlowChatCompletions
33 |
--------------------------------------------------------------------------------
/web/src/app/infra/basic-component/create-card-component/createCartComponent.module.css:
--------------------------------------------------------------------------------
1 | .cardContainer {
2 | background-color: #fff;
3 | border-radius: 9px;
4 | box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.1);
5 | display: flex;
6 | flex-direction: column;
7 | align-items: center;
8 | justify-content: space-evenly;
9 | cursor: pointer;
10 | transition: all 0.2s ease;
11 | }
12 |
13 | :global(.dark) .cardContainer {
14 | background-color: #1f1f22;
15 | box-shadow: 0;
16 | }
17 |
18 | .cardContainer:hover {
19 | box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.05);
20 | }
21 |
22 | :global(.dark) .cardContainer:hover {
23 | box-shadow: 0;
24 | }
25 |
26 | .createCardContainer {
27 | font-size: 90px;
28 | color: #acacac;
29 | }
30 |
31 | :global(.dark) .createCardContainer {
32 | color: #666666;
33 | }
34 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 | - repo: https://github.com/astral-sh/ruff-pre-commit
3 | # Ruff version.
4 | rev: v0.11.7
5 | hooks:
6 | # Run the linter of backend.
7 | - id: ruff
8 | args: [--fix]
9 | # Run the formatter of backend.
10 | - id: ruff-format
11 |
12 | - repo: https://github.com/pre-commit/mirrors-prettier
13 | rev: v3.1.0
14 | hooks:
15 | - id: prettier
16 | types_or: [javascript, jsx, ts, tsx, css, scss]
17 | additional_dependencies:
18 | - prettier@3.1.0
19 |
20 | - repo: local
21 | hooks:
22 | - id: lint-staged
23 | name: lint-staged
24 | entry: cd web && pnpm lint-staged
25 | language: system
26 | types: [javascript, jsx, ts, tsx]
27 | pass_filenames: false
28 |
--------------------------------------------------------------------------------
/run_tests.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Script to run all unit tests
4 | # This script helps avoid circular import issues by setting up the environment properly
5 |
6 | set -e
7 |
8 | echo "Setting up test environment..."
9 |
10 | # Activate virtual environment if it exists
11 | if [ -d ".venv" ]; then
12 | source .venv/bin/activate
13 | fi
14 |
15 | # Check if pytest is installed
16 | if ! command -v pytest &> /dev/null; then
17 | echo "Installing test dependencies..."
18 | pip install pytest pytest-asyncio pytest-cov
19 | fi
20 |
21 | echo "Running all unit tests..."
22 |
23 | # Run tests with coverage
24 | pytest tests/unit_tests/ -v --tb=short \
25 | --cov=langbot \
26 | --cov-report=xml \
27 | "$@"
28 |
29 | echo ""
30 | echo "Test run complete!"
31 | echo "Coverage report saved to coverage.xml"
32 |
--------------------------------------------------------------------------------
/src/langbot/pkg/persistence/migrations/dbm009_pipeline_extension_preferences.py:
--------------------------------------------------------------------------------
1 | import sqlalchemy
2 | from .. import migration
3 |
4 |
5 | @migration.migration_class(9)
6 | class DBMigratePipelineExtensionPreferences(migration.DBMigration):
7 | """Pipeline extension preferences"""
8 |
9 | async def upgrade(self):
10 | """Upgrade"""
11 |
12 | sql_text = sqlalchemy.text(
13 | "ALTER TABLE legacy_pipelines ADD COLUMN extensions_preferences JSON NOT NULL DEFAULT '{}'"
14 | )
15 | await self.ap.persistence_mgr.execute_async(sql_text)
16 |
17 | async def downgrade(self):
18 | """Downgrade"""
19 | sql_text = sqlalchemy.text('ALTER TABLE legacy_pipelines DROP COLUMN extensions_preferences')
20 | await self.ap.persistence_mgr.execute_async(sql_text)
21 |
--------------------------------------------------------------------------------
/src/langbot/pkg/config/model.py:
--------------------------------------------------------------------------------
1 | import abc
2 |
3 |
4 | class ConfigFile(metaclass=abc.ABCMeta):
5 | """Config file abstract class"""
6 |
7 | config_file_name: str = None
8 | """Config file name"""
9 |
10 | template_file_name: str = None
11 | """Template file name"""
12 |
13 | template_data: dict = None
14 | """Template data"""
15 |
16 | @abc.abstractmethod
17 | def exists(self) -> bool:
18 | pass
19 |
20 | @abc.abstractmethod
21 | async def create(self):
22 | pass
23 |
24 | @abc.abstractmethod
25 | async def load(self, completion: bool = True) -> dict:
26 | pass
27 |
28 | @abc.abstractmethod
29 | async def save(self, data: dict):
30 | pass
31 |
32 | @abc.abstractmethod
33 | def save_sync(self, data: dict):
34 | pass
35 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m016_dify_service_api.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('dify-service-api-config', 16)
7 | class DifyServiceAPICfgMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 | return 'dify-service-api' not in self.ap.provider_cfg.data
13 |
14 | async def run(self):
15 | """执行迁移"""
16 | self.ap.provider_cfg.data['dify-service-api'] = {
17 | 'base-url': 'https://api.dify.ai/v1',
18 | 'app-type': 'chat',
19 | 'chat': {'api-key': 'app-1234567890'},
20 | 'workflow': {'api-key': 'app-1234567890', 'output-key': 'summary'},
21 | }
22 |
23 | await self.ap.provider_cfg.dump_config()
24 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m019_zhipuai_config.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('zhipuai-config', 19)
7 | class ZhipuaiConfigMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 | return 'zhipuai-chat-completions' not in self.ap.provider_cfg.data['requester']
13 |
14 | async def run(self):
15 | """执行迁移"""
16 | self.ap.provider_cfg.data['requester']['zhipuai-chat-completions'] = {
17 | 'base-url': 'https://open.bigmodel.cn/api/paas/v4',
18 | 'args': {},
19 | 'timeout': 120,
20 | }
21 | self.ap.provider_cfg.data['keys']['zhipuai'] = ['xxxxxxx']
22 |
23 | await self.ap.provider_cfg.dump_config()
24 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/modelscope.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/src/components/ui/separator.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import * as React from 'react';
4 | import * as SeparatorPrimitive from '@radix-ui/react-separator';
5 |
6 | import { cn } from '@/lib/utils';
7 |
8 | function Separator({
9 | className,
10 | orientation = 'horizontal',
11 | decorative = true,
12 | ...props
13 | }: React.ComponentProps) {
14 | return (
15 |
25 | );
26 | }
27 |
28 | export { Separator };
29 |
--------------------------------------------------------------------------------
/pytest.ini:
--------------------------------------------------------------------------------
1 | [pytest]
2 | # Test discovery patterns
3 | python_files = test_*.py
4 | python_classes = Test*
5 | python_functions = test_*
6 |
7 | # Test paths
8 | testpaths = tests
9 |
10 | # Asyncio configuration
11 | asyncio_mode = auto
12 |
13 | # Output options
14 | addopts =
15 | -v
16 | --strict-markers
17 | --tb=short
18 | --disable-warnings
19 |
20 | # Markers
21 | markers =
22 | asyncio: mark test as async
23 | unit: mark test as unit test
24 | integration: mark test as integration test
25 | slow: mark test as slow running
26 |
27 | # Coverage options (when using pytest-cov)
28 | [coverage:run]
29 | source = langbot
30 | omit =
31 | */tests/*
32 | */test_*.py
33 | */__pycache__/*
34 | */site-packages/*
35 |
36 | [coverage:report]
37 | precision = 2
38 | show_missing = True
39 | skip_covered = False
40 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m033_dify_thinking_config.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('dify-thinking-config', 33)
7 | class DifyThinkingConfigMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 |
13 | if 'options' not in self.ap.provider_cfg.data['dify-service-api']:
14 | return True
15 |
16 | if 'convert-thinking-tips' not in self.ap.provider_cfg.data['dify-service-api']['options']:
17 | return True
18 |
19 | return False
20 |
21 | async def run(self):
22 | """执行迁移"""
23 | self.ap.provider_cfg.data['dify-service-api']['options'] = {'convert-thinking-tips': 'plain'}
24 | await self.ap.provider_cfg.dump_config()
25 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/stage.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import abc
4 | import typing
5 |
6 | from . import app
7 |
8 |
9 | preregistered_stages: dict[str, typing.Type[BootingStage]] = {}
10 | """Pre-registered request processing stages. All request processing stage classes are registered in this dictionary during initialization.
11 |
12 | Currently not supported for extension
13 | """
14 |
15 |
16 | def stage_class(name: str):
17 | def decorator(cls: typing.Type[BootingStage]) -> typing.Type[BootingStage]:
18 | preregistered_stages[name] = cls
19 | return cls
20 |
21 | return decorator
22 |
23 |
24 | class BootingStage(abc.ABC):
25 | """Booting stage"""
26 |
27 | name: str = None
28 |
29 | @abc.abstractmethod
30 | async def run(self, ap: app.Application):
31 | """Run"""
32 | pass
33 |
--------------------------------------------------------------------------------
/web/src/components/ui/textarea.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | import { cn } from '@/lib/utils';
4 |
5 | function Textarea({ className, ...props }: React.ComponentProps<'textarea'>) {
6 | return (
7 |
15 | );
16 | }
17 |
18 | export { Textarea };
19 |
--------------------------------------------------------------------------------
/src/langbot/pkg/api/http/controller/groups/stats.py:
--------------------------------------------------------------------------------
1 | from .. import group
2 |
3 |
4 | @group.group_class('stats', '/api/v1/stats')
5 | class StatsRouterGroup(group.RouterGroup):
6 | async def initialize(self) -> None:
7 | @self.route('/basic', methods=['GET'], auth_type=group.AuthType.USER_TOKEN)
8 | async def _() -> str:
9 | conv_count = 0
10 | for session in self.ap.sess_mgr.session_list:
11 | conv_count += len(session.conversations if session.conversations is not None else [])
12 |
13 | return self.success(
14 | data={
15 | 'active_session_count': len(self.ap.sess_mgr.session_list),
16 | 'conversation_count': conv_count,
17 | 'query_count': self.ap.query_pool.query_id_counter,
18 | }
19 | )
20 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m023_siliconflow_config.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('siliconflow-config', 23)
7 | class SiliconFlowConfigMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 |
13 | return 'siliconflow-chat-completions' not in self.ap.provider_cfg.data['requester']
14 |
15 | async def run(self):
16 | """执行迁移"""
17 | self.ap.provider_cfg.data['keys']['siliconflow'] = ['xxxxxxx']
18 |
19 | self.ap.provider_cfg.data['requester']['siliconflow-chat-completions'] = {
20 | 'base-url': 'https://api.siliconflow.cn/v1',
21 | 'args': {},
22 | 'timeout': 120,
23 | }
24 |
25 | await self.ap.provider_cfg.dump_config()
26 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## 参与项目
2 |
3 | 欢迎为此项目贡献代码或其他支持,以使您的点子或众人期待的功能成为现实,助力社区成长。
4 |
5 | ### 贡献形式
6 |
7 | - 提交PR,解决issues中提到的bug或期待的功能
8 | - 提交PR,实现您设想的功能(请先提出issue与项目维护者沟通)
9 | - 为本项目在其他社交平台撰写文章、制作视频等
10 | - 为本项目的衍生项目作出贡献,或开发插件增加功能
11 |
12 | ### 沟通语言规范
13 |
14 | - 在 PR 和 Commit Message 中请使用全英文
15 | - 对于中文用户,issue 中可以使用中文
16 |
17 |
18 |
19 | ## Guidelines
20 |
21 | ### Contribution
22 |
23 | - Submit PRs to solve bugs or features in the issues
24 | - Submit PRs to implement your ideas (Please create an issue first and communicate with the project maintainer)
25 | - Write articles or make videos about this project on other social platforms
26 | - Contribute to the development of derivative projects, or develop plugins to add features
27 |
28 | ### Spoken Language
29 |
30 | - Use English in PRs and Commit Messages
31 | - For English users, you can use English in issues
32 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m032_volcark_config.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('volcark-requester-config', 32)
7 | class VolcArkRequesterConfigMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 |
13 | return 'volcark-chat-completions' not in self.ap.provider_cfg.data['requester']
14 |
15 | async def run(self):
16 | """执行迁移"""
17 | self.ap.provider_cfg.data['keys']['volcark'] = ['xxxxxxxx']
18 |
19 | self.ap.provider_cfg.data['requester']['volcark-chat-completions'] = {
20 | 'base-url': 'https://ark.cn-beijing.volces.com/api/v3',
21 | 'args': {},
22 | 'timeout': 120,
23 | }
24 |
25 | await self.ap.provider_cfg.dump_config()
26 |
--------------------------------------------------------------------------------
/src/langbot/libs/wecom_api/ierror.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | #########################################################################
4 | # Author: jonyqin
5 | # Created Time: Thu 11 Sep 2014 01:53:58 PM CST
6 | # File Name: ierror.py
7 | # Description:定义错误码含义
8 | #########################################################################
9 | WXBizMsgCrypt_OK = 0
10 | WXBizMsgCrypt_ValidateSignature_Error = -40001
11 | WXBizMsgCrypt_ParseXml_Error = -40002
12 | WXBizMsgCrypt_ComputeSignature_Error = -40003
13 | WXBizMsgCrypt_IllegalAesKey = -40004
14 | WXBizMsgCrypt_ValidateCorpid_Error = -40005
15 | WXBizMsgCrypt_EncryptAES_Error = -40006
16 | WXBizMsgCrypt_DecryptAES_Error = -40007
17 | WXBizMsgCrypt_IllegalBuffer = -40008
18 | WXBizMsgCrypt_EncodeBase64_Error = -40009
19 | WXBizMsgCrypt_DecodeBase64_Error = -40010
20 | WXBizMsgCrypt_GenReturnXml_Error = -40011
21 |
--------------------------------------------------------------------------------
/src/langbot/pkg/entity/persistence/apikey.py:
--------------------------------------------------------------------------------
1 | import sqlalchemy
2 |
3 | from .base import Base
4 |
5 |
6 | class ApiKey(Base):
7 | """API Key for external service authentication"""
8 |
9 | __tablename__ = 'api_keys'
10 |
11 | id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True, autoincrement=True)
12 | name = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
13 | key = sqlalchemy.Column(sqlalchemy.String(255), nullable=False, unique=True)
14 | description = sqlalchemy.Column(sqlalchemy.String(512), nullable=True, default='')
15 | created_at = sqlalchemy.Column(sqlalchemy.DateTime, nullable=False, server_default=sqlalchemy.func.now())
16 | updated_at = sqlalchemy.Column(
17 | sqlalchemy.DateTime,
18 | nullable=False,
19 | server_default=sqlalchemy.func.now(),
20 | onupdate=sqlalchemy.func.now(),
21 | )
22 |
--------------------------------------------------------------------------------
/res/scripts/publish_announcement.py:
--------------------------------------------------------------------------------
1 | # 输出工作路径
2 | import os
3 | import time
4 | import json
5 |
6 | print('工作路径: ' + os.getcwd())
7 | announcement = input('请输入公告内容: ')
8 |
9 | # 读取现有的公告文件 res/announcement.json
10 | with open('res/announcement.json', 'r', encoding='utf-8') as f:
11 | announcement_json = json.load(f)
12 |
13 | # 将公告内容写入公告文件
14 |
15 | # 当前自然时间
16 | now = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
17 |
18 | # 获取最后一个公告的id
19 | last_id = announcement_json[-1]['id'] if len(announcement_json) > 0 else -1
20 |
21 | announcement = {
22 | 'id': last_id + 1,
23 | 'time': now,
24 | 'timestamp': int(time.time()),
25 | 'content': announcement,
26 | }
27 |
28 | announcement_json.append(announcement)
29 |
30 | # 将公告写入公告文件
31 | with open('res/announcement.json', 'w', encoding='utf-8') as f:
32 | json.dump(announcement_json, f, indent=4, ensure_ascii=False)
33 |
--------------------------------------------------------------------------------
/web/src/app/layout.tsx:
--------------------------------------------------------------------------------
1 | import './global.css';
2 | import 'react-photo-view/dist/react-photo-view.css';
3 | import type { Metadata } from 'next';
4 | import { Toaster } from '@/components/ui/sonner';
5 | import I18nProvider from '@/i18n/I18nProvider';
6 | import { ThemeProvider } from '@/components/providers/theme-provider';
7 |
8 | export const metadata: Metadata = {
9 | title: 'LangBot',
10 | description: 'LangBot 是大模型原生即时通信机器人平台',
11 | };
12 |
13 | export default function RootLayout({
14 | children,
15 | }: Readonly<{
16 | children: React.ReactNode;
17 | }>) {
18 | return (
19 |
20 |
21 |
22 |
23 | {children}
24 |
25 |
26 |
27 |
28 |
29 | );
30 | }
31 |
--------------------------------------------------------------------------------
/src/langbot/libs/wecom_ai_bot_api/ierror.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | #########################################################################
4 | # Author: jonyqin
5 | # Created Time: Thu 11 Sep 2014 01:53:58 PM CST
6 | # File Name: ierror.py
7 | # Description:定义错误码含义
8 | #########################################################################
9 | WXBizMsgCrypt_OK = 0
10 | WXBizMsgCrypt_ValidateSignature_Error = -40001
11 | WXBizMsgCrypt_ParseXml_Error = -40002
12 | WXBizMsgCrypt_ComputeSignature_Error = -40003
13 | WXBizMsgCrypt_IllegalAesKey = -40004
14 | WXBizMsgCrypt_ValidateCorpid_Error = -40005
15 | WXBizMsgCrypt_EncryptAES_Error = -40006
16 | WXBizMsgCrypt_DecryptAES_Error = -40007
17 | WXBizMsgCrypt_IllegalBuffer = -40008
18 | WXBizMsgCrypt_EncodeBase64_Error = -40009
19 | WXBizMsgCrypt_DecodeBase64_Error = -40010
20 | WXBizMsgCrypt_GenReturnXml_Error = -40011
21 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m028_aliyun_requester_config.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('bailian-requester-config', 28)
7 | class BailianRequesterConfigMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 |
13 | return 'bailian-chat-completions' not in self.ap.provider_cfg.data['requester']
14 |
15 | async def run(self):
16 | """执行迁移"""
17 | self.ap.provider_cfg.data['keys']['bailian'] = ['sk-xxxxxxx']
18 |
19 | self.ap.provider_cfg.data['requester']['bailian-chat-completions'] = {
20 | 'base-url': 'https://dashscope.aliyuncs.com/compatible-mode/v1',
21 | 'args': {},
22 | 'timeout': 120,
23 | }
24 |
25 | await self.ap.provider_cfg.dump_config()
26 |
--------------------------------------------------------------------------------
/src/langbot/pkg/entity/persistence/mcp.py:
--------------------------------------------------------------------------------
1 | import sqlalchemy
2 |
3 | from .base import Base
4 |
5 |
6 | class MCPServer(Base):
7 | __tablename__ = 'mcp_servers'
8 |
9 | uuid = sqlalchemy.Column(sqlalchemy.String(255), primary_key=True, unique=True)
10 | name = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
11 | enable = sqlalchemy.Column(sqlalchemy.Boolean, nullable=False, default=False)
12 | mode = sqlalchemy.Column(sqlalchemy.String(255), nullable=False) # stdio, sse
13 | extra_args = sqlalchemy.Column(sqlalchemy.JSON, nullable=False, default={})
14 | created_at = sqlalchemy.Column(sqlalchemy.DateTime, nullable=False, server_default=sqlalchemy.func.now())
15 | updated_at = sqlalchemy.Column(
16 | sqlalchemy.DateTime,
17 | nullable=False,
18 | server_default=sqlalchemy.func.now(),
19 | onupdate=sqlalchemy.func.now(),
20 | )
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /config.py
2 | .idea/
3 | __pycache__/
4 | database.db
5 | langbot.log
6 | /banlist.py
7 | /plugins/
8 | !/plugins/__init__.py
9 | /revcfg.py
10 | prompts/
11 | logs/
12 | sensitive.json
13 | temp/
14 | current_tag
15 | scenario/
16 | !scenario/default-template.json
17 | override.json
18 | cookies.json
19 | data/labels/announcement_saved.json
20 | cmdpriv.json
21 | tips.py
22 | venv*
23 | bin/
24 | .vscode
25 | /test_*
26 | venv/
27 | hugchat.json
28 | qcapi
29 | claude.json
30 | bard.json
31 | /*yaml
32 | !.pre-commit-config.yaml
33 | !components.yaml
34 | !/docker-compose.yaml
35 | data/labels/instance_id.json
36 | .DS_Store
37 | /data
38 | botpy.log*
39 | /poc
40 | /libs/wecom_api/test.py
41 | /venv
42 | test.py
43 | /web_ui
44 | .venv/
45 | uv.lock
46 | /test
47 | plugins.bak
48 | coverage.xml
49 | .coverage
50 | src/langbot/web/
51 |
52 | # Build artifacts
53 | /dist
54 | /build
55 | *.egg-info
56 |
--------------------------------------------------------------------------------
/web/src/app/home/components/home-titlebar/HomeTittleBar.module.css:
--------------------------------------------------------------------------------
1 | .titleBarContainer {
2 | width: 100%;
3 | padding-top: 1rem;
4 | height: 4rem;
5 | opacity: 1;
6 | font-size: 20px;
7 | display: flex;
8 | flex-direction: column;
9 | align-items: flex-start;
10 | justify-content: center;
11 | }
12 |
13 | .titleText {
14 | margin-left: 3.2rem;
15 | font-size: 1.4rem;
16 | font-weight: 500;
17 | color: #585858;
18 | }
19 |
20 | :global(.dark) .titleText {
21 | color: #e0e0e0;
22 | }
23 |
24 | .subtitleText {
25 | margin-left: 3.2rem;
26 | font-size: 0.8rem;
27 | color: #808080;
28 | display: flex;
29 | align-items: center;
30 | }
31 |
32 | :global(.dark) .subtitleText {
33 | color: #b0b0b0;
34 | }
35 |
36 | .helpLink {
37 | margin-left: 0.2rem;
38 | font-size: 0.8rem;
39 | color: #8b8b8b;
40 | }
41 |
42 | :global(.dark) .helpLink {
43 | color: #a0a0a0;
44 | }
45 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m035_wxoa_mode.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('wxoa-mode', 35)
7 | class WxoaModeMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 |
13 | for adapter in self.ap.platform_cfg.data['platform-adapters']:
14 | if adapter['adapter'] == 'officialaccount':
15 | if 'Mode' not in adapter:
16 | return True
17 | return False
18 |
19 | async def run(self):
20 | """执行迁移"""
21 | for adapter in self.ap.platform_cfg.data['platform-adapters']:
22 | if adapter['adapter'] == 'officialaccount':
23 | if 'Mode' not in adapter:
24 | adapter['Mode'] = 'drop'
25 |
26 | await self.ap.platform_cfg.dump_config()
27 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/ppiochatcmpl.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: LLMAPIRequester
3 | metadata:
4 | name: ppio-chat-completions
5 | label:
6 | en_US: ppio
7 | zh_Hans: 派欧云
8 | icon: ppio.svg
9 | spec:
10 | config:
11 | - name: base_url
12 | label:
13 | en_US: Base URL
14 | zh_Hans: 基础 URL
15 | type: string
16 | required: true
17 | default: https://api.ppinfra.com/v3/openai
18 | - name: args
19 | label:
20 | en_US: Args
21 | zh_Hans: 附加参数
22 | type: object
23 | required: true
24 | default: {}
25 | - name: timeout
26 | label:
27 | en_US: Timeout
28 | zh_Hans: 超时时间
29 | type: int
30 | required: true
31 | default: 120
32 | support_type:
33 | - llm
34 | - text-embedding
35 | provider_category: maas
36 | execution:
37 | python:
38 | path: ./ppiochatcmpl.py
39 | attr: PPIOChatCompletions
40 |
--------------------------------------------------------------------------------
/src/langbot/pkg/entity/persistence/bstorage.py:
--------------------------------------------------------------------------------
1 | import sqlalchemy
2 |
3 | from .base import Base
4 |
5 |
6 | class BinaryStorage(Base):
7 | """Current for plugin use only"""
8 |
9 | __tablename__ = 'binary_storages'
10 |
11 | unique_key = sqlalchemy.Column(sqlalchemy.String(255), primary_key=True)
12 | key = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
13 | owner_type = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
14 | owner = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
15 | value = sqlalchemy.Column(sqlalchemy.LargeBinary, nullable=False)
16 | created_at = sqlalchemy.Column(sqlalchemy.DateTime, nullable=False, server_default=sqlalchemy.func.now())
17 | updated_at = sqlalchemy.Column(
18 | sqlalchemy.DateTime,
19 | nullable=False,
20 | server_default=sqlalchemy.func.now(),
21 | onupdate=sqlalchemy.func.now(),
22 | )
23 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/qhaigcchatcmpl.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: LLMAPIRequester
3 | metadata:
4 | name: qhaigc-chat-completions
5 | label:
6 | en_US: QH AI
7 | zh_Hans: 启航 AI
8 | icon: qhaigc.png
9 | spec:
10 | config:
11 | - name: base_url
12 | label:
13 | en_US: Base URL
14 | zh_Hans: 基础 URL
15 | type: string
16 | required: true
17 | default: https://api.qhaigc.net/v1
18 | - name: args
19 | label:
20 | en_US: Args
21 | zh_Hans: 附加参数
22 | type: object
23 | required: true
24 | default: {}
25 | - name: timeout
26 | label:
27 | en_US: Timeout
28 | zh_Hans: 超时时间
29 | type: int
30 | required: true
31 | default: 120
32 | support_type:
33 | - llm
34 | - text-embedding
35 | provider_category: maas
36 | execution:
37 | python:
38 | path: ./qhaigcchatcmpl.py
39 | attr: QHAIGCChatCompletions
40 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m008_ad_fixwin_config_migrate.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('ad-fixwin-cfg-migration', 8)
7 | class AdFixwinConfigMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 | return isinstance(self.ap.pipeline_cfg.data['rate-limit']['fixwin']['default'], int)
13 |
14 | async def run(self):
15 | """执行迁移"""
16 |
17 | for session_name in self.ap.pipeline_cfg.data['rate-limit']['fixwin']:
18 | temp_dict = {
19 | 'window-size': 60,
20 | 'limit': self.ap.pipeline_cfg.data['rate-limit']['fixwin'][session_name],
21 | }
22 |
23 | self.ap.pipeline_cfg.data['rate-limit']['fixwin'][session_name] = temp_dict
24 |
25 | await self.ap.pipeline_cfg.dump_config()
26 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m013_http_api_config.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('http-api-config', 13)
7 | class HttpApiConfigMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 | return 'http-api' not in self.ap.system_cfg.data or 'persistence' not in self.ap.system_cfg.data
13 |
14 | async def run(self):
15 | """执行迁移"""
16 |
17 | self.ap.system_cfg.data['http-api'] = {
18 | 'enable': True,
19 | 'host': '0.0.0.0',
20 | 'port': 5300,
21 | 'jwt-expire': 604800,
22 | }
23 |
24 | self.ap.system_cfg.data['persistence'] = {
25 | 'sqlite': {'path': 'data/persistence.db'},
26 | 'use': 'sqlite',
27 | }
28 |
29 | await self.ap.system_cfg.dump_config()
30 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/stages/genkeys.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import secrets
4 |
5 | from .. import stage, app
6 |
7 |
8 | @stage.stage_class('GenKeysStage')
9 | class GenKeysStage(stage.BootingStage):
10 | """Generate keys stage"""
11 |
12 | async def run(self, ap: app.Application):
13 | """Generate keys"""
14 |
15 | if not ap.instance_config.data['system']['jwt']['secret']:
16 | ap.instance_config.data['system']['jwt']['secret'] = secrets.token_hex(16)
17 | await ap.instance_config.dump_config()
18 |
19 | if 'recovery_key' not in ap.instance_config.data['system']:
20 | ap.instance_config.data['system']['recovery_key'] = ''
21 |
22 | if not ap.instance_config.data['system']['recovery_key']:
23 | ap.instance_config.data['system']['recovery_key'] = secrets.token_hex(3).upper()
24 | await ap.instance_config.dump_config()
25 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/jiekouaichatcmpl.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: LLMAPIRequester
3 | metadata:
4 | name: jiekouai-chat-completions
5 | label:
6 | en_US: JieKou AI
7 | zh_Hans: 接口 AI
8 | icon: jiekouai.png
9 | spec:
10 | config:
11 | - name: base_url
12 | label:
13 | en_US: Base URL
14 | zh_Hans: 基础 URL
15 | type: string
16 | required: true
17 | default: https://api.jiekou.ai/openai
18 | - name: args
19 | label:
20 | en_US: Args
21 | zh_Hans: 附加参数
22 | type: object
23 | required: true
24 | default: {}
25 | - name: timeout
26 | label:
27 | en_US: Timeout
28 | zh_Hans: 超时时间
29 | type: int
30 | required: true
31 | default: 120
32 | support_type:
33 | - llm
34 | - text-embedding
35 | provider_category: maas
36 | execution:
37 | python:
38 | path: ./jiekouaichatcmpl.py
39 | attr: JieKouAIChatCompletions
40 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/modelscopechatcmpl.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: LLMAPIRequester
3 | metadata:
4 | name: modelscope-chat-completions
5 | label:
6 | en_US: ModelScope
7 | zh_Hans: 魔搭社区
8 | icon: modelscope.svg
9 | spec:
10 | config:
11 | - name: base_url
12 | label:
13 | en_US: Base URL
14 | zh_Hans: 基础 URL
15 | type: string
16 | required: true
17 | default: https://api-inference.modelscope.cn/v1
18 | - name: args
19 | label:
20 | en_US: Args
21 | zh_Hans: 附加参数
22 | type: object
23 | required: true
24 | default: {}
25 | - name: timeout
26 | label:
27 | en_US: Timeout
28 | zh_Hans: 超时时间
29 | type: int
30 | required: true
31 | default: 120
32 | support_type:
33 | - llm
34 | provider_category: maas
35 | execution:
36 | python:
37 | path: ./modelscopechatcmpl.py
38 | attr: ModelScopeChatCompletions
39 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m015_gitee_ai_config.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('gitee-ai-config', 15)
7 | class GiteeAIConfigMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 | return (
13 | 'gitee-ai-chat-completions' not in self.ap.provider_cfg.data['requester']
14 | or 'gitee-ai' not in self.ap.provider_cfg.data['keys']
15 | )
16 |
17 | async def run(self):
18 | """执行迁移"""
19 | self.ap.provider_cfg.data['requester']['gitee-ai-chat-completions'] = {
20 | 'base-url': 'https://ai.gitee.com/v1',
21 | 'args': {},
22 | 'timeout': 120,
23 | }
24 |
25 | self.ap.provider_cfg.data['keys']['gitee-ai'] = ['XXXXX']
26 |
27 | await self.ap.provider_cfg.dump_config()
28 |
--------------------------------------------------------------------------------
/src/langbot/pkg/platform/sources/qqofficial.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: MessagePlatformAdapter
3 | metadata:
4 | name: qqofficial
5 | label:
6 | en_US: QQ Official API
7 | zh_Hans: QQ 官方 API
8 | description:
9 | en_US: QQ Official API (Webhook)
10 | zh_Hans: QQ 官方 API (Webhook),请查看文档了解使用方式
11 | icon: qqofficial.svg
12 | spec:
13 | config:
14 | - name: appid
15 | label:
16 | en_US: App ID
17 | zh_Hans: 应用ID
18 | type: string
19 | required: true
20 | default: ""
21 | - name: secret
22 | label:
23 | en_US: Secret
24 | zh_Hans: 密钥
25 | type: string
26 | required: true
27 | default: ""
28 | - name: token
29 | label:
30 | en_US: Token
31 | zh_Hans: 令牌
32 | type: string
33 | required: true
34 | default: ""
35 | execution:
36 | python:
37 | path: ./qqofficial.py
38 | attr: QQOfficialAdapter
39 |
--------------------------------------------------------------------------------
/src/langbot/pkg/utils/pkgmgr.py:
--------------------------------------------------------------------------------
1 | from pip._internal import main as pipmain
2 |
3 |
4 | def install(package):
5 | pipmain(['install', package])
6 |
7 |
8 | def install_upgrade(package):
9 | pipmain(
10 | [
11 | 'install',
12 | '--upgrade',
13 | package,
14 | '-i',
15 | 'https://pypi.tuna.tsinghua.edu.cn/simple',
16 | '--trusted-host',
17 | 'pypi.tuna.tsinghua.edu.cn',
18 | ]
19 | )
20 |
21 |
22 | def run_pip(params: list):
23 | pipmain(params)
24 |
25 |
26 | def install_requirements(file, extra_params: list = []):
27 | pipmain(
28 | [
29 | 'install',
30 | '-r',
31 | file,
32 | '-i',
33 | 'https://pypi.tuna.tsinghua.edu.cn/simple',
34 | '--trusted-host',
35 | 'pypi.tuna.tsinghua.edu.cn',
36 | ]
37 | + extra_params
38 | )
39 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/shengsuanyun.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: LLMAPIRequester
3 | metadata:
4 | name: shengsuanyun-chat-completions
5 | label:
6 | en_US: ShengSuanYun
7 | zh_Hans: 胜算云
8 | icon: shengsuanyun.svg
9 | spec:
10 | config:
11 | - name: base_url
12 | label:
13 | en_US: Base URL
14 | zh_Hans: 基础 URL
15 | type: string
16 | required: true
17 | default: https://router.shengsuanyun.com/api/v1
18 | - name: args
19 | label:
20 | en_US: Args
21 | zh_Hans: 附加参数
22 | type: object
23 | required: true
24 | default: {}
25 | - name: timeout
26 | label:
27 | en_US: Timeout
28 | zh_Hans: 超时时间
29 | type: int
30 | required: true
31 | default: 120
32 | support_type:
33 | - llm
34 | - text-embedding
35 | provider_category: maas
36 | execution:
37 | python:
38 | path: ./shengsuanyun.py
39 | attr: ShengSuanYunChatCompletions
40 |
--------------------------------------------------------------------------------
/.mcp.json:
--------------------------------------------------------------------------------
1 | {
2 | "mcpServers": {
3 | "shadcn": {
4 | "command": "npx",
5 | "args": [
6 | "shadcn@latest",
7 | "mcp"
8 | ]
9 | },
10 | "sequential-thinking": {
11 | "type": "stdio",
12 | "command": "npx",
13 | "args": ["-y", "@modelcontextprotocol/server-sequential-thinking"],
14 | "env": {}
15 | },
16 | "github": {
17 | "type": "stdio",
18 | "command": "npx",
19 | "args": ["-y", "@modelcontextprotocol/server-github"],
20 | "env": {
21 | "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_PERSONAL_ACCESS_TOKEN}"
22 | }
23 | },
24 | "fetch": {
25 | "type": "stdio",
26 | "command": "uvx",
27 | "args": ["mcp-server-fetch"],
28 | "env": {}
29 | },
30 | "playwright": {
31 | "type": "stdio",
32 | "command": "npx",
33 | "args": ["-y", "@playwright/mcp@latest"],
34 | "env": {}
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/web/src/app/home/plugins/mcp-server/MCPCardVO.ts:
--------------------------------------------------------------------------------
1 | import { MCPServer, MCPSessionStatus } from '@/app/infra/entities/api';
2 |
3 | export class MCPCardVO {
4 | name: string;
5 | mode: 'stdio' | 'sse';
6 | enable: boolean;
7 | status: MCPSessionStatus;
8 | tools: number;
9 | error?: string;
10 |
11 | constructor(data: MCPServer) {
12 | this.name = data.name;
13 | this.mode = data.mode;
14 | this.enable = data.enable;
15 |
16 | // Determine status from runtime_info
17 | if (!data.runtime_info) {
18 | this.status = MCPSessionStatus.ERROR;
19 | this.tools = 0;
20 | } else if (data.runtime_info.status === MCPSessionStatus.CONNECTED) {
21 | this.status = data.runtime_info.status;
22 | this.tools = data.runtime_info.tool_count || 0;
23 | } else {
24 | this.status = data.runtime_info.status;
25 | this.tools = 0;
26 | this.error = data.runtime_info.error_message;
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/langbot/pkg/entity/persistence/webhook.py:
--------------------------------------------------------------------------------
1 | import sqlalchemy
2 |
3 | from .base import Base
4 |
5 |
6 | class Webhook(Base):
7 | """Webhook for pushing bot events to external systems"""
8 |
9 | __tablename__ = 'webhooks'
10 |
11 | id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True, autoincrement=True)
12 | name = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
13 | url = sqlalchemy.Column(sqlalchemy.String(1024), nullable=False)
14 | description = sqlalchemy.Column(sqlalchemy.String(512), nullable=True, default='')
15 | enabled = sqlalchemy.Column(sqlalchemy.Boolean, nullable=False, default=True)
16 | created_at = sqlalchemy.Column(sqlalchemy.DateTime, nullable=False, server_default=sqlalchemy.func.now())
17 | updated_at = sqlalchemy.Column(
18 | sqlalchemy.DateTime,
19 | nullable=False,
20 | server_default=sqlalchemy.func.now(),
21 | onupdate=sqlalchemy.func.now(),
22 | )
23 |
--------------------------------------------------------------------------------
/web/src/app/home/pipelines/components/debug-dialog/AtBadge.tsx:
--------------------------------------------------------------------------------
1 | import { Badge } from '@/components/ui/badge';
2 | import { X } from 'lucide-react';
3 |
4 | interface AtBadgeProps {
5 | targetName: string;
6 | readonly?: boolean;
7 | onRemove?: () => void;
8 | }
9 |
10 | export default function AtBadge({
11 | targetName,
12 | readonly = false,
13 | onRemove,
14 | }: AtBadgeProps) {
15 | return (
16 |
20 | @{targetName}
21 | {!readonly && onRemove && (
22 |
28 | )}
29 |
30 | );
31 | }
32 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/bootutils/files.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import os
4 | import shutil
5 |
6 |
7 | required_files = {
8 | 'data/config.yaml': 'templates/config.yaml',
9 | }
10 |
11 | required_paths = [
12 | 'temp',
13 | 'data',
14 | 'data/metadata',
15 | 'data/logs',
16 | 'data/labels',
17 | ]
18 |
19 |
20 | async def generate_files() -> list[str]:
21 | global required_files, required_paths
22 |
23 | from ...utils import paths as path_utils
24 |
25 | for required_paths in required_paths:
26 | if not os.path.exists(required_paths):
27 | os.mkdir(required_paths)
28 |
29 | generated_files = []
30 | for file in required_files:
31 | if not os.path.exists(file):
32 | template_path = path_utils.get_resource_path(required_files[file])
33 | shutil.copyfile(template_path, file)
34 | generated_files.append(file)
35 |
36 | return generated_files
37 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m024_discord_config.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('discord-config', 24)
7 | class DiscordConfigMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 |
13 | # for adapter in self.ap.platform_cfg.data['platform-adapters']:
14 | # if adapter['adapter'] == 'discord':
15 | # return False
16 |
17 | # return True
18 | return False
19 |
20 | async def run(self):
21 | """执行迁移"""
22 | self.ap.platform_cfg.data['platform-adapters'].append(
23 | {
24 | 'adapter': 'discord',
25 | 'enable': False,
26 | 'client_id': '1234567890',
27 | 'token': 'XXXXXXXXXX',
28 | }
29 | )
30 |
31 | await self.ap.platform_cfg.dump_config()
32 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/notes/n002_selection_mode_on_windows.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import typing
4 | import os
5 | import logging
6 |
7 | from .. import note
8 |
9 |
10 | @note.note_class('SelectionModeOnWindows', 2)
11 | class SelectionModeOnWindows(note.LaunchNote):
12 | """Selection mode prompt information on Windows"""
13 |
14 | async def need_show(self) -> bool:
15 | return os.name == 'nt'
16 |
17 | async def yield_note(self) -> typing.AsyncGenerator[typing.Tuple[str, int], None]:
18 | yield (
19 | """您正在使用 Windows 系统,若窗口左上角显示处于”选择“模式,程序将被暂停运行,此时请右键窗口中空白区域退出选择模式。""",
20 | logging.INFO,
21 | )
22 |
23 | yield (
24 | """You are using Windows system, if the top left corner of the window displays "Selection" mode, the program will be paused running, please right-click on the blank area in the window to exit the selection mode.""",
25 | logging.INFO,
26 | )
27 |
--------------------------------------------------------------------------------
/src/langbot/pkg/persistence/databases/postgresql.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import sqlalchemy.ext.asyncio as sqlalchemy_asyncio
4 |
5 | from .. import database
6 |
7 |
8 | @database.manager_class('postgresql')
9 | class PostgreSQLDatabaseManager(database.BaseDatabaseManager):
10 | """PostgreSQL database manager"""
11 |
12 | async def initialize(self) -> None:
13 | postgresql_config = self.ap.instance_config.data.get('database', {}).get('postgresql', {})
14 |
15 | host = postgresql_config.get('host', '127.0.0.1')
16 | port = postgresql_config.get('port', 5432)
17 | user = postgresql_config.get('user', 'postgres')
18 | password = postgresql_config.get('password', 'postgres')
19 | database = postgresql_config.get('database', 'postgres')
20 | engine_url = f'postgresql+asyncpg://{user}:{password}@{host}:{port}/{database}'
21 | self.engine = sqlalchemy_asyncio.create_async_engine(engine_url)
22 |
--------------------------------------------------------------------------------
/src/langbot/pkg/persistence/migration.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import typing
4 | import abc
5 |
6 | from ..core import app
7 |
8 |
9 | preregistered_db_migrations: list[typing.Type[DBMigration]] = []
10 |
11 |
12 | def migration_class(number: int):
13 | """Migration class decorator"""
14 |
15 | def wrapper(cls: typing.Type[DBMigration]) -> typing.Type[DBMigration]:
16 | cls.number = number
17 | preregistered_db_migrations.append(cls)
18 | return cls
19 |
20 | return wrapper
21 |
22 |
23 | class DBMigration(abc.ABC):
24 | """Database migration"""
25 |
26 | number: int
27 | """Migration number"""
28 |
29 | def __init__(self, ap: app.Application):
30 | self.ap = ap
31 |
32 | @abc.abstractmethod
33 | async def upgrade(self):
34 | """Upgrade"""
35 | pass
36 |
37 | @abc.abstractmethod
38 | async def downgrade(self):
39 | """Downgrade"""
40 | pass
41 |
--------------------------------------------------------------------------------
/src/langbot/pkg/platform/sources/legacy/qqbotpy.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: MessagePlatformAdapter
3 | metadata:
4 | name: qq-botpy
5 | label:
6 | en_US: QQBotPy
7 | zh_Hans: QQBotPy
8 | description:
9 | en_US: QQ Official API (WebSocket)
10 | zh_Hans: QQ 官方 API (WebSocket),请查看文档了解使用方式
11 | icon: qqbotpy.svg
12 | spec:
13 | config:
14 | - name: appid
15 | label:
16 | en_US: App ID
17 | zh_Hans: 应用ID
18 | type: string
19 | required: true
20 | default: ""
21 | - name: secret
22 | label:
23 | en_US: Secret
24 | zh_Hans: 密钥
25 | type: string
26 | required: true
27 | default: ""
28 | - name: intents
29 | label:
30 | en_US: Intents
31 | zh_Hans: 权限
32 | type: array
33 | required: true
34 | default: []
35 | items:
36 | type: string
37 | execution:
38 | python:
39 | path: ./qqbotpy.py
40 | attr: OfficialAdapter
41 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m038_tg_dingtalk_markdown.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('tg-dingtalk-markdown', 38)
7 | class TgDingtalkMarkdownMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 |
13 | for adapter in self.ap.platform_cfg.data['platform-adapters']:
14 | if adapter['adapter'] in ['dingtalk', 'telegram']:
15 | if 'markdown_card' not in adapter:
16 | return True
17 | return False
18 |
19 | async def run(self):
20 | """执行迁移"""
21 | for adapter in self.ap.platform_cfg.data['platform-adapters']:
22 | if adapter['adapter'] in ['dingtalk', 'telegram']:
23 | if 'markdown_card' not in adapter:
24 | adapter['markdown_card'] = False
25 | await self.ap.platform_cfg.dump_config()
26 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m036_wxoa_loading_message.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('wxoa-loading-message', 36)
7 | class WxoaLoadingMessageMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 |
13 | for adapter in self.ap.platform_cfg.data['platform-adapters']:
14 | if adapter['adapter'] == 'officialaccount':
15 | if 'LoadingMessage' not in adapter:
16 | return True
17 | return False
18 |
19 | async def run(self):
20 | """执行迁移"""
21 | for adapter in self.ap.platform_cfg.data['platform-adapters']:
22 | if adapter['adapter'] == 'officialaccount':
23 | if 'LoadingMessage' not in adapter:
24 | adapter['LoadingMessage'] = 'AI正在思考中,请发送任意内容获取回复。'
25 |
26 | await self.ap.platform_cfg.dump_config()
27 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m029_dashscope_app_api_config.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('dashscope-app-api-config', 29)
7 | class DashscopeAppAPICfgMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 | return 'dashscope-app-api' not in self.ap.provider_cfg.data
13 |
14 | async def run(self):
15 | """执行迁移"""
16 | self.ap.provider_cfg.data['dashscope-app-api'] = {
17 | 'app-type': 'agent',
18 | 'api-key': 'sk-1234567890',
19 | 'agent': {'app-id': 'Your_app_id', 'references_quote': '参考资料来自:'},
20 | 'workflow': {
21 | 'app-id': 'Your_app_id',
22 | 'references_quote': '参考资料来自:',
23 | 'biz_params': {'city': '北京', 'date': '2023-08-10'},
24 | },
25 | }
26 |
27 | await self.ap.provider_cfg.dump_config()
28 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/shengsuanyun.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import openai
4 | import typing
5 |
6 | from . import chatcmpl
7 | import openai.types.chat.chat_completion as chat_completion
8 |
9 |
10 | class ShengSuanYunChatCompletions(chatcmpl.OpenAIChatCompletions):
11 | """胜算云(ModelSpot.AI) ChatCompletion API 请求器"""
12 |
13 | client: openai.AsyncClient
14 |
15 | default_config: dict[str, typing.Any] = {
16 | 'base_url': 'https://router.shengsuanyun.com/api/v1',
17 | 'timeout': 120,
18 | }
19 |
20 | async def _req(
21 | self,
22 | args: dict,
23 | extra_body: dict = {},
24 | ) -> chat_completion.ChatCompletion:
25 | return await self.client.chat.completions.create(
26 | **args,
27 | extra_body=extra_body,
28 | extra_headers={
29 | 'HTTP-Referer': 'https://langbot.app',
30 | 'X-Title': 'LangBot',
31 | },
32 | )
33 |
--------------------------------------------------------------------------------
/src/langbot/pkg/storage/mgr.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 |
4 | from ..core import app
5 | from . import provider
6 | from .providers import localstorage, s3storage
7 |
8 |
9 | class StorageMgr:
10 | """Storage manager"""
11 |
12 | ap: app.Application
13 |
14 | storage_provider: provider.StorageProvider
15 |
16 | def __init__(self, ap: app.Application):
17 | self.ap = ap
18 |
19 | async def initialize(self):
20 | storage_config = self.ap.instance_config.data.get('storage', {})
21 | storage_type = storage_config.get('use', 'local')
22 |
23 | if storage_type == 's3':
24 | self.storage_provider = s3storage.S3StorageProvider(self.ap)
25 | self.ap.logger.info('Initialized S3 storage backend.')
26 | else:
27 | self.storage_provider = localstorage.LocalStorageProvider(self.ap)
28 | self.ap.logger.info('Initialized local storage backend.')
29 |
30 | await self.storage_provider.initialize()
31 |
--------------------------------------------------------------------------------
/src/langbot/pkg/pipeline/process/handler.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import abc
4 |
5 | from ...core import app
6 | from .. import entities
7 | import langbot_plugin.api.entities.builtin.pipeline.query as pipeline_query
8 |
9 |
10 | class MessageHandler(metaclass=abc.ABCMeta):
11 | ap: app.Application
12 |
13 | def __init__(self, ap: app.Application):
14 | self.ap = ap
15 |
16 | async def initialize(self):
17 | pass
18 |
19 | @abc.abstractmethod
20 | async def handle(
21 | self,
22 | query: pipeline_query.Query,
23 | ) -> entities.StageProcessResult:
24 | raise NotImplementedError
25 |
26 | def cut_str(self, s: str) -> str:
27 | """
28 | Take the first line of the string, up to 20 characters, if there are multiple lines, or more than 20 characters, add an ellipsis
29 | """
30 | s0 = s.split('\n')[0]
31 | if len(s0) > 20 or '\n' in s:
32 | s0 = s0[:20] + '...'
33 | return s0
34 |
--------------------------------------------------------------------------------
/web/public/globe.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/src/app/home/bots/components/bot-card/BotCardVO.ts:
--------------------------------------------------------------------------------
1 | export interface IBotCardVO {
2 | id: string;
3 | iconURL: string;
4 | name: string;
5 | description: string;
6 | adapter: string;
7 | adapterLabel: string;
8 | adapterConfig: object;
9 | usePipelineName: string;
10 | enable: boolean;
11 | }
12 |
13 | export class BotCardVO implements IBotCardVO {
14 | id: string;
15 | iconURL: string;
16 | name: string;
17 | description: string;
18 | adapter: string;
19 | adapterLabel: string;
20 | adapterConfig: object;
21 | usePipelineName: string;
22 | enable: boolean;
23 |
24 | constructor(props: IBotCardVO) {
25 | this.id = props.id;
26 | this.iconURL = props.iconURL;
27 | this.name = props.name;
28 | this.description = props.description;
29 | this.adapter = props.adapter;
30 | this.adapterConfig = props.adapterConfig;
31 | this.adapterLabel = props.adapterLabel;
32 | this.usePipelineName = props.usePipelineName;
33 | this.enable = props.enable;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/langbot/pkg/api/http/controller/groups/logs.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 |
4 | import quart
5 |
6 | from .. import group
7 |
8 |
9 | @group.group_class('logs', '/api/v1/logs')
10 | class LogsRouterGroup(group.RouterGroup):
11 | async def initialize(self) -> None:
12 | @self.route('', methods=['GET'], auth_type=group.AuthType.USER_TOKEN)
13 | async def _() -> str:
14 | start_page_number = int(quart.request.args.get('start_page_number', 0))
15 | start_offset = int(quart.request.args.get('start_offset', 0))
16 |
17 | logs_str, end_page_number, end_offset = self.ap.log_cache.get_log_by_pointer(
18 | start_page_number=start_page_number, start_offset=start_offset
19 | )
20 |
21 | return self.success(
22 | data={
23 | 'logs': logs_str,
24 | 'end_page_number': end_page_number,
25 | 'end_offset': end_offset,
26 | }
27 | )
28 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m026_qqofficial_config.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('qqofficial-config', 26)
7 | class QQOfficialConfigMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 |
13 | # for adapter in self.ap.platform_cfg.data['platform-adapters']:
14 | # if adapter['adapter'] == 'qqofficial':
15 | # return False
16 |
17 | # return True
18 | return False
19 |
20 | async def run(self):
21 | """执行迁移"""
22 | self.ap.platform_cfg.data['platform-adapters'].append(
23 | {
24 | 'adapter': 'qqofficial',
25 | 'enable': False,
26 | 'appid': '',
27 | 'secret': '',
28 | 'port': 2284,
29 | 'token': '',
30 | }
31 | )
32 |
33 | await self.ap.platform_cfg.dump_config()
34 |
--------------------------------------------------------------------------------
/src/langbot/pkg/command/operators/prompt.py:
--------------------------------------------------------------------------------
1 | # from __future__ import annotations
2 |
3 | # import typing
4 |
5 | # from .. import operator
6 | # from langbot_plugin.api.entities.builtin.command import context as command_context, errors as command_errors
7 |
8 |
9 | # @operator.operator_class(name='prompt', help='查看当前对话的前文', usage='!prompt')
10 | # class PromptOperator(operator.CommandOperator):
11 | # async def execute(
12 | # self, context: command_context.ExecuteContext
13 | # ) -> typing.AsyncGenerator[command_context.CommandReturn, None]:
14 | # """执行"""
15 | # if context.session.using_conversation is None:
16 | # yield command_context.CommandReturn(error=command_errors.CommandOperationError('当前没有对话'))
17 | # else:
18 | # reply_str = '当前对话所有内容:\n\n'
19 |
20 | # for msg in context.session.using_conversation.messages:
21 | # reply_str += f'{msg.role}: {msg.content}\n'
22 |
23 | # yield command_context.CommandReturn(text=reply_str)
24 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m031_dingtalk_config.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('dingtalk-config', 31)
7 | class DingTalkConfigMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 |
13 | # for adapter in self.ap.platform_cfg.data['platform-adapters']:
14 | # if adapter['adapter'] == 'dingtalk':
15 | # return False
16 |
17 | # return True
18 | return False
19 |
20 | async def run(self):
21 | """执行迁移"""
22 | self.ap.platform_cfg.data['platform-adapters'].append(
23 | {
24 | 'adapter': 'dingtalk',
25 | 'enable': False,
26 | 'client_id': '',
27 | 'client_secret': '',
28 | 'robot_code': '',
29 | 'robot_name': '',
30 | }
31 | )
32 |
33 | await self.ap.platform_cfg.dump_config()
34 |
--------------------------------------------------------------------------------
/src/langbot/pkg/storage/provider.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import abc
4 |
5 | from ..core import app
6 |
7 |
8 | class StorageProvider(abc.ABC):
9 | ap: app.Application
10 |
11 | def __init__(self, ap: app.Application):
12 | self.ap = ap
13 |
14 | async def initialize(self):
15 | pass
16 |
17 | @abc.abstractmethod
18 | async def save(
19 | self,
20 | key: str,
21 | value: bytes,
22 | ):
23 | pass
24 |
25 | @abc.abstractmethod
26 | async def load(
27 | self,
28 | key: str,
29 | ) -> bytes:
30 | pass
31 |
32 | @abc.abstractmethod
33 | async def exists(
34 | self,
35 | key: str,
36 | ) -> bool:
37 | pass
38 |
39 | @abc.abstractmethod
40 | async def delete(
41 | self,
42 | key: str,
43 | ):
44 | pass
45 |
46 | @abc.abstractmethod
47 | async def delete_dir_recursive(
48 | self,
49 | dir_path: str,
50 | ):
51 | pass
52 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/runner.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import abc
4 | import typing
5 |
6 | from ..core import app
7 |
8 |
9 | preregistered_runners: list[typing.Type[RequestRunner]] = []
10 |
11 |
12 | def runner_class(name: str):
13 | """注册一个请求运行器"""
14 |
15 | def decorator(cls: typing.Type[RequestRunner]) -> typing.Type[RequestRunner]:
16 | cls.name = name
17 | preregistered_runners.append(cls)
18 | return cls
19 |
20 | return decorator
21 |
22 |
23 | class RequestRunner(abc.ABC):
24 | """请求运行器"""
25 |
26 | name: str = None
27 |
28 | ap: app.Application
29 |
30 | pipeline_config: dict
31 |
32 | def __init__(self, ap: app.Application, pipeline_config: dict):
33 | self.ap = ap
34 | self.pipeline_config = pipeline_config
35 |
36 | @abc.abstractmethod
37 | async def run(
38 | self, query: core_entities.Query
39 | ) -> typing.AsyncGenerator[llm_entities.Message | llm_entities.MessageChunk, None]:
40 | """运行请求"""
41 | pass
42 |
--------------------------------------------------------------------------------
/.github/workflows/build-dev-image.yaml:
--------------------------------------------------------------------------------
1 | name: Build Dev Image
2 |
3 | on:
4 | push:
5 | workflow_dispatch:
6 |
7 | jobs:
8 | build-dev-image:
9 | runs-on: ubuntu-latest
10 | # 如果是tag则跳过
11 | if: ${{ !startsWith(github.ref, 'refs/tags/') }}
12 | steps:
13 | - name: Checkout
14 | uses: actions/checkout@v2
15 | with:
16 | persist-credentials: false
17 |
18 | - name: Generate Tag
19 | id: generate_tag
20 | run: |
21 | # 获取分支名称,把/替换为-
22 | echo ${{ github.ref }} | sed 's/refs\/heads\///g' | sed 's/\//-/g'
23 | echo ::set-output name=tag::$(echo ${{ github.ref }} | sed 's/refs\/heads\///g' | sed 's/\//-/g')
24 | - name: Login to Registry
25 | run: docker login --username=${{ secrets.DOCKER_USERNAME }} --password ${{ secrets.DOCKER_PASSWORD }}
26 | - name: Build Docker Image
27 | run: |
28 | docker buildx create --name mybuilder --use
29 | docker build -t rockchin/langbot:${{ steps.generate_tag.outputs.tag }} . --push
30 |
--------------------------------------------------------------------------------
/src/langbot/pkg/pipeline/entities.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import enum
4 | import typing
5 |
6 | import pydantic
7 |
8 | import langbot_plugin.api.entities.builtin.pipeline.query as pipeline_query
9 | import langbot_plugin.api.entities.builtin.platform.message as platform_message
10 |
11 |
12 | class ResultType(enum.Enum):
13 | CONTINUE = enum.auto()
14 | """继续流水线"""
15 |
16 | INTERRUPT = enum.auto()
17 | """中断流水线"""
18 |
19 |
20 | class StageProcessResult(pydantic.BaseModel):
21 | result_type: ResultType
22 |
23 | new_query: pipeline_query.Query
24 |
25 | user_notice: typing.Optional[
26 | typing.Union[
27 | str,
28 | list[platform_message.MessageComponent],
29 | platform_message.MessageChain,
30 | None,
31 | ]
32 | ] = []
33 | """只要设置了就会发送给用户"""
34 |
35 | console_notice: typing.Optional[str] = ''
36 | """只要设置了就会输出到控制台"""
37 |
38 | debug_notice: typing.Optional[str] = ''
39 |
40 | error_notice: typing.Optional[str] = ''
41 |
--------------------------------------------------------------------------------
/src/langbot/pkg/pipeline/msgtrun/truncators/round.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import truncator
4 | import langbot_plugin.api.entities.builtin.pipeline.query as pipeline_query
5 |
6 |
7 | @truncator.truncator_class('round')
8 | class RoundTruncator(truncator.Truncator):
9 | """Truncate the conversation message chain to adapt to the LLM message length limit."""
10 |
11 | async def truncate(self, query: pipeline_query.Query) -> pipeline_query.Query:
12 | """截断"""
13 | max_round = query.pipeline_config['ai']['local-agent']['max-round']
14 |
15 | temp_messages = []
16 |
17 | current_round = 0
18 |
19 | # Traverse from back to front
20 | for msg in query.messages[::-1]:
21 | if current_round < max_round:
22 | temp_messages.append(msg)
23 | if msg.role == 'user':
24 | current_round += 1
25 | else:
26 | break
27 |
28 | query.messages = temp_messages[::-1]
29 |
30 | return query
31 |
--------------------------------------------------------------------------------
/src/langbot/pkg/pipeline/resprule/rules/regexp.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 |
4 | from .. import rule as rule_model
5 | from .. import entities
6 | import langbot_plugin.api.entities.builtin.platform.message as platform_message
7 | import langbot_plugin.api.entities.builtin.pipeline.query as pipeline_query
8 |
9 |
10 | @rule_model.rule_class('regexp')
11 | class RegExpRule(rule_model.GroupRespondRule):
12 | async def match(
13 | self,
14 | message_text: str,
15 | message_chain: platform_message.MessageChain,
16 | rule_dict: dict,
17 | query: pipeline_query.Query,
18 | ) -> entities.RuleJudgeResult:
19 | regexps = rule_dict['regexp']
20 |
21 | for regexp in regexps:
22 | match = re.match(regexp, message_text)
23 |
24 | if match:
25 | return entities.RuleJudgeResult(
26 | matching=True,
27 | replacement=message_chain,
28 | )
29 |
30 | return entities.RuleJudgeResult(matching=False, replacement=message_chain)
31 |
--------------------------------------------------------------------------------
/docker/docker-compose.yaml:
--------------------------------------------------------------------------------
1 | # Docker Compose configuration for LangBot
2 | # For Kubernetes deployment, see kubernetes.yaml and README_K8S.md
3 | version: "3"
4 |
5 | services:
6 |
7 | langbot_plugin_runtime:
8 | image: rockchin/langbot:latest
9 | container_name: langbot_plugin_runtime
10 | volumes:
11 | - ./data/plugins:/app/data/plugins
12 | ports:
13 | - 5401:5401
14 | restart: on-failure
15 | environment:
16 | - TZ=Asia/Shanghai
17 | command: ["uv", "run", "-m", "langbot_plugin.cli.__init__", "rt"]
18 | networks:
19 | - langbot_network
20 |
21 | langbot:
22 | image: rockchin/langbot:latest
23 | container_name: langbot
24 | volumes:
25 | - ./data:/app/data
26 | restart: on-failure
27 | environment:
28 | - TZ=Asia/Shanghai
29 | ports:
30 | - 5300:5300 # For web ui and webhook callback
31 | - 2280-2285:2280-2285 # For platform reverse connection
32 | networks:
33 | - langbot_network
34 |
35 | networks:
36 | langbot_network:
37 | driver: bridge
38 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.yml:
--------------------------------------------------------------------------------
1 | name: 漏洞反馈
2 | description: 【供中文用户】报错或漏洞请使用这个模板创建,不使用此模板创建的异常、漏洞相关issue将被直接关闭。由于自己操作不当/不甚了解所用技术栈引起的网络连接问题恕无法解决,请勿提 issue。容器间网络连接问题,参考文档 https://docs.langbot.app/zh/workshop/network-details.html
3 | title: "[Bug]: "
4 | labels: ["bug?"]
5 | body:
6 | - type: input
7 | attributes:
8 | label: 运行环境
9 | description: LangBot 版本、操作系统、系统架构、**Python版本**、**主机地理位置**
10 | placeholder: 例如:v3.3.0、CentOS x64 Python 3.10.3、Docker
11 | validations:
12 | required: true
13 | - type: textarea
14 | attributes:
15 | label: 异常情况
16 | description: 完整描述异常情况,什么时候发生的、发生了什么。**请附带日志信息。**
17 | validations:
18 | required: true
19 | - type: textarea
20 | attributes:
21 | label: 复现步骤
22 | description: 提供越多信息,我们会越快解决问题,建议多提供配置截图;**如果你不认真填写(只一两句话概括),我们会很生气并且立即关闭 issue 或两年后才回复你**
23 | validations:
24 | required: false
25 | - type: textarea
26 | attributes:
27 | label: 启用的插件
28 | description: 有些情况可能和插件功能有关,建议提供插件启用情况。
29 | validations:
30 | required: false
31 |
--------------------------------------------------------------------------------
/src/langbot/pkg/persistence/database.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import abc
4 |
5 | import sqlalchemy.ext.asyncio as sqlalchemy_asyncio
6 |
7 | from ..core import app
8 |
9 |
10 | preregistered_managers: list[type[BaseDatabaseManager]] = []
11 |
12 |
13 | def manager_class(name: str) -> None:
14 | """Register a database manager class"""
15 |
16 | def decorator(cls: type[BaseDatabaseManager]) -> type[BaseDatabaseManager]:
17 | cls.name = name
18 | preregistered_managers.append(cls)
19 | return cls
20 |
21 | return decorator
22 |
23 |
24 | class BaseDatabaseManager(abc.ABC):
25 | """Base database manager class"""
26 |
27 | name: str
28 |
29 | ap: app.Application
30 |
31 | engine: sqlalchemy_asyncio.AsyncEngine
32 |
33 | def __init__(self, ap: app.Application) -> None:
34 | self.ap = ap
35 |
36 | @abc.abstractmethod
37 | async def initialize(self) -> None:
38 | pass
39 |
40 | def get_engine(self) -> sqlalchemy_asyncio.AsyncEngine:
41 | return self.engine
42 |
--------------------------------------------------------------------------------
/src/langbot/pkg/platform/sources/wecomcs.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: MessagePlatformAdapter
3 | metadata:
4 | name: wecomcs
5 | label:
6 | en_US: WeComCustomerService
7 | zh_Hans: 企业微信客服
8 | description:
9 | en_US: WeComCSAdapter
10 | zh_Hans: 企业微信客服适配器
11 | icon: wecom.png
12 | spec:
13 | config:
14 | - name: corpid
15 | label:
16 | en_US: Corpid
17 | zh_Hans: 企业ID
18 | type: string
19 | required: true
20 | default: ""
21 | - name: secret
22 | label:
23 | en_US: Secret
24 | zh_Hans: 密钥
25 | type: string
26 | required: true
27 | default: ""
28 | - name: token
29 | label:
30 | en_US: Token
31 | zh_Hans: 令牌
32 | type: string
33 | required: true
34 | default: ""
35 | - name: EncodingAESKey
36 | label:
37 | en_US: EncodingAESKey
38 | zh_Hans: 消息加解密密钥
39 | type: string
40 | required: true
41 | default: ""
42 | execution:
43 | python:
44 | path: ./wecomcs.py
45 | attr: WecomCSAdapter
--------------------------------------------------------------------------------
/web/src/components/ui/input.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | import { cn } from '@/lib/utils';
4 |
5 | function Input({ className, type, ...props }: React.ComponentProps<'input'>) {
6 | return (
7 |
18 | );
19 | }
20 |
21 | export { Input };
22 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m040_ppio_config.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('ppio-config', 40)
7 | class PPIOConfigMigration(migration.Migration):
8 | """PPIO配置迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 | return (
13 | 'ppio-chat-completions' not in self.ap.provider_cfg.data['requester']
14 | or 'ppio' not in self.ap.provider_cfg.data['keys']
15 | )
16 |
17 | async def run(self):
18 | """执行迁移"""
19 | if 'ppio-chat-completions' not in self.ap.provider_cfg.data['requester']:
20 | self.ap.provider_cfg.data['requester']['ppio-chat-completions'] = {
21 | 'base-url': 'https://api.ppinfra.com/v3/openai',
22 | 'args': {},
23 | 'timeout': 120,
24 | }
25 |
26 | if 'ppio' not in self.ap.provider_cfg.data['keys']:
27 | self.ap.provider_cfg.data['keys']['ppio'] = []
28 |
29 | await self.ap.provider_cfg.dump_config()
30 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m017_dify_api_timeout_params.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('dify-api-timeout-params', 17)
7 | class DifyAPITimeoutParamsMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 | return (
13 | 'timeout' not in self.ap.provider_cfg.data['dify-service-api']['chat']
14 | or 'timeout' not in self.ap.provider_cfg.data['dify-service-api']['workflow']
15 | or 'agent' not in self.ap.provider_cfg.data['dify-service-api']
16 | )
17 |
18 | async def run(self):
19 | """执行迁移"""
20 | self.ap.provider_cfg.data['dify-service-api']['chat']['timeout'] = 120
21 | self.ap.provider_cfg.data['dify-service-api']['workflow']['timeout'] = 120
22 | self.ap.provider_cfg.data['dify-service-api']['agent'] = {
23 | 'api-key': 'app-1234567890',
24 | 'timeout': 120,
25 | }
26 |
27 | await self.ap.provider_cfg.dump_config()
28 |
--------------------------------------------------------------------------------
/src/langbot/pkg/provider/modelmgr/requesters/ppio.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/langbot/pkg/platform/sources/legacy/nakuru.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: MessagePlatformAdapter
3 | metadata:
4 | name: nakuru
5 | label:
6 | en_US: Nakuru
7 | zh_Hans: Nakuru
8 | description:
9 | en_US: Nakuru Adapter
10 | zh_Hans: Nakuru 适配器(go-cqhttp),请查看文档了解使用方式
11 | icon: nakuru.png
12 | spec:
13 | config:
14 | - name: host
15 | label:
16 | en_US: Host
17 | zh_Hans: 主机
18 | type: string
19 | required: true
20 | default: "127.0.0.1"
21 | - name: http_port
22 | label:
23 | en_US: HTTP Port
24 | zh_Hans: HTTP端口
25 | type: integer
26 | required: true
27 | default: 5700
28 | - name: ws_port
29 | label:
30 | en_US: WebSocket Port
31 | zh_Hans: WebSocket端口
32 | type: integer
33 | required: true
34 | default: 8080
35 | - name: token
36 | label:
37 | en_US: Token
38 | zh_Hans: 令牌
39 | type: string
40 | required: true
41 | default: ""
42 | execution:
43 | python:
44 | path: ./nakuru.py
45 | attr: NakuruAdapter
46 |
--------------------------------------------------------------------------------
/src/langbot/pkg/platform/sources/telegram.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: MessagePlatformAdapter
3 | metadata:
4 | name: telegram
5 | label:
6 | en_US: Telegram
7 | zh_Hans: 电报
8 | description:
9 | en_US: Telegram Adapter
10 | zh_Hans: 电报适配器,请查看文档了解使用方式
11 | icon: telegram.svg
12 | spec:
13 | config:
14 | - name: token
15 | label:
16 | en_US: Token
17 | zh_Hans: 令牌
18 | type: string
19 | required: true
20 | default: ""
21 | - name: markdown_card
22 | label:
23 | en_US: Markdown Card
24 | zh_Hans: 是否使用 Markdown 卡片
25 | type: boolean
26 | required: false
27 | default: true
28 | - name: enable-stream-reply
29 | label:
30 | en_US: Enable Stream Reply Mode
31 | zh_Hans: 启用电报流式回复模式
32 | description:
33 | en_US: If enabled, the bot will use the stream of telegram reply mode
34 | zh_Hans: 如果启用,将使用电报流式方式来回复内容
35 | type: boolean
36 | required: true
37 | default: false
38 | execution:
39 | python:
40 | path: ./telegram.py
41 | attr: TelegramAdapter
42 |
--------------------------------------------------------------------------------
/src/langbot/pkg/platform/sources/wecombot.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: MessagePlatformAdapter
3 | metadata:
4 | name: wecombot
5 | label:
6 | en_US: WeComBot
7 | zh_Hans: 企业微信智能机器人
8 | description:
9 | en_US: WeComBot Adapter
10 | zh_Hans: 企业微信智能机器人适配器,请查看文档了解使用方式
11 | icon: wecombot.png
12 | spec:
13 | config:
14 | - name: Corpid
15 | label:
16 | en_US: Corpid
17 | zh_Hans: 企业ID
18 | type: string
19 | required: true
20 | default: ""
21 | - name: Token
22 | label:
23 | en_US: Token
24 | zh_Hans: 令牌 (Token)
25 | type: string
26 | required: true
27 | default: ""
28 | - name: EncodingAESKey
29 | label:
30 | en_US: EncodingAESKey
31 | zh_Hans: 消息加解密密钥 (EncodingAESKey)
32 | type: string
33 | required: true
34 | default: ""
35 | - name: BotId
36 | label:
37 | en_US: BotId
38 | zh_Hans: 机器人ID
39 | type: string
40 | required: false
41 | default: ""
42 | execution:
43 | python:
44 | path: ./wecombot.py
45 | attr: WecomBotAdapter
--------------------------------------------------------------------------------
/src/langbot/templates/legacy/pipeline.json:
--------------------------------------------------------------------------------
1 | {
2 | "access-control":{
3 | "mode": "blacklist",
4 | "blacklist": [],
5 | "whitelist": []
6 | },
7 | "respond-rules": {
8 | "default": {
9 | "at": true,
10 | "prefix": [
11 | "/ai", "!ai", "!ai", "ai"
12 | ],
13 | "regexp": [],
14 | "random": 0.0
15 | }
16 | },
17 | "income-msg-check": true,
18 | "ignore-rules": {
19 | "prefix": [],
20 | "regexp": []
21 | },
22 | "check-sensitive-words": true,
23 | "baidu-cloud-examine": {
24 | "enable": false,
25 | "api-key": "",
26 | "api-secret": ""
27 | },
28 | "rate-limit": {
29 | "strategy": "drop",
30 | "algo": "fixwin",
31 | "fixwin": {
32 | "default": {
33 | "window-size": 60,
34 | "limit": 60
35 | }
36 | }
37 | },
38 | "msg-truncate": {
39 | "method": "round",
40 | "round": {
41 | "max-round": 10
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migration.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import abc
4 | import typing
5 |
6 | from . import app
7 |
8 |
9 | preregistered_migrations: list[typing.Type[Migration]] = []
10 | """Currently not supported for extension"""
11 |
12 |
13 | def migration_class(name: str, number: int):
14 | """Register a migration"""
15 |
16 | def decorator(cls: typing.Type[Migration]) -> typing.Type[Migration]:
17 | cls.name = name
18 | cls.number = number
19 | preregistered_migrations.append(cls)
20 | return cls
21 |
22 | return decorator
23 |
24 |
25 | class Migration(abc.ABC):
26 | """A version migration"""
27 |
28 | name: str
29 |
30 | number: int
31 |
32 | ap: app.Application
33 |
34 | def __init__(self, ap: app.Application):
35 | self.ap = ap
36 |
37 | @abc.abstractmethod
38 | async def need_migrate(self) -> bool:
39 | """Determine if the current environment needs to run this migration"""
40 | pass
41 |
42 | @abc.abstractmethod
43 | async def run(self):
44 | """Run migration"""
45 | pass
46 |
--------------------------------------------------------------------------------
/src/langbot/pkg/platform/sources/dingtalk.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/web/src/app/home/knowledge/components/external-kb-card/ExternalKBCardVO.ts:
--------------------------------------------------------------------------------
1 | export class ExternalKBCardVO {
2 | id: string;
3 | name: string;
4 | description: string;
5 | retrieverName: string;
6 | retrieverConfig: Record;
7 | lastUpdatedTimeAgo: string;
8 | pluginAuthor: string;
9 | pluginName: string;
10 |
11 | constructor({
12 | id,
13 | name,
14 | description,
15 | retrieverName,
16 | retrieverConfig,
17 | lastUpdatedTimeAgo,
18 | pluginAuthor,
19 | pluginName,
20 | }: {
21 | id: string;
22 | name: string;
23 | description: string;
24 | retrieverName: string;
25 | retrieverConfig: Record;
26 | lastUpdatedTimeAgo: string;
27 | pluginAuthor: string;
28 | pluginName: string;
29 | }) {
30 | this.id = id;
31 | this.name = name;
32 | this.description = description;
33 | this.retrieverName = retrieverName;
34 | this.retrieverConfig = retrieverConfig;
35 | this.lastUpdatedTimeAgo = lastUpdatedTimeAgo;
36 | this.pluginAuthor = pluginAuthor;
37 | this.pluginName = pluginName;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m020_wecom_config.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('wecom-config', 20)
7 | class WecomConfigMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 |
13 | # for adapter in self.ap.platform_cfg.data['platform-adapters']:
14 | # if adapter['adapter'] == 'wecom':
15 | # return False
16 |
17 | # return True
18 | return False
19 |
20 | async def run(self):
21 | """执行迁移"""
22 | self.ap.platform_cfg.data['platform-adapters'].append(
23 | {
24 | 'adapter': 'wecom',
25 | 'enable': False,
26 | 'host': '0.0.0.0',
27 | 'port': 2290,
28 | 'corpid': '',
29 | 'secret': '',
30 | 'token': '',
31 | 'EncodingAESKey': '',
32 | 'contacts_secret': '',
33 | }
34 | )
35 |
36 | await self.ap.platform_cfg.dump_config()
37 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m021_lark_config.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('lark-config', 21)
7 | class LarkConfigMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 |
13 | # for adapter in self.ap.platform_cfg.data['platform-adapters']:
14 | # if adapter['adapter'] == 'lark':
15 | # return False
16 |
17 | # return True
18 | return False
19 |
20 | async def run(self):
21 | """执行迁移"""
22 | self.ap.platform_cfg.data['platform-adapters'].append(
23 | {
24 | 'adapter': 'lark',
25 | 'enable': False,
26 | 'app_id': 'cli_abcdefgh',
27 | 'app_secret': 'XXXXXXXXXX',
28 | 'bot_name': 'LangBot',
29 | 'enable-webhook': False,
30 | 'port': 2285,
31 | 'encrypt-key': 'xxxxxxxxx',
32 | }
33 | )
34 |
35 | await self.ap.platform_cfg.dump_config()
36 |
--------------------------------------------------------------------------------
/src/langbot/pkg/entity/persistence/plugin.py:
--------------------------------------------------------------------------------
1 | import sqlalchemy
2 |
3 | from .base import Base
4 |
5 |
6 | class PluginSetting(Base):
7 | """Plugin setting"""
8 |
9 | __tablename__ = 'plugin_settings'
10 |
11 | plugin_author = sqlalchemy.Column(sqlalchemy.String(255), primary_key=True)
12 | plugin_name = sqlalchemy.Column(sqlalchemy.String(255), primary_key=True)
13 | enabled = sqlalchemy.Column(sqlalchemy.Boolean, nullable=False, default=True)
14 | priority = sqlalchemy.Column(sqlalchemy.Integer, nullable=False, default=0)
15 | config = sqlalchemy.Column(sqlalchemy.JSON, nullable=False, default=dict)
16 | install_source = sqlalchemy.Column(sqlalchemy.String(255), nullable=False, default='github')
17 | install_info = sqlalchemy.Column(sqlalchemy.JSON, nullable=False, default=dict)
18 | created_at = sqlalchemy.Column(sqlalchemy.DateTime, nullable=False, server_default=sqlalchemy.func.now())
19 | updated_at = sqlalchemy.Column(
20 | sqlalchemy.DateTime,
21 | nullable=False,
22 | server_default=sqlalchemy.func.now(),
23 | onupdate=sqlalchemy.func.now(),
24 | )
25 |
--------------------------------------------------------------------------------
/src/langbot/libs/dingtalk_api/EchoHandler.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | import dingtalk_stream # type: ignore
3 | from dingtalk_stream import AckMessage
4 |
5 |
6 | class EchoTextHandler(dingtalk_stream.ChatbotHandler):
7 | def __init__(self, client):
8 | super().__init__() # Call parent class initializer to set up logger
9 | self.msg_id = ''
10 | self.incoming_message = None
11 | self.client = client # 用于更新 DingTalkClient 中的 incoming_message
12 |
13 | """处理钉钉消息"""
14 |
15 | async def process(self, callback: dingtalk_stream.CallbackMessage):
16 | incoming_message = dingtalk_stream.ChatbotMessage.from_dict(callback.data)
17 | if incoming_message.message_id != self.msg_id:
18 | self.msg_id = incoming_message.message_id
19 |
20 | await self.client.update_incoming_message(incoming_message)
21 |
22 | return AckMessage.STATUS_OK, 'OK'
23 |
24 | async def get_incoming_message(self):
25 | """异步等待消息的到来"""
26 | while self.incoming_message is None:
27 | await asyncio.sleep(0.1) # 异步等待,避免阻塞
28 |
29 | return self.incoming_message
30 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m034_gewechat_file_url_config.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from urllib.parse import urlparse
4 |
5 | from .. import migration
6 |
7 |
8 | @migration.migration_class('gewechat-file-url-config', 34)
9 | class GewechatFileUrlConfigMigration(migration.Migration):
10 | """迁移"""
11 |
12 | async def need_migrate(self) -> bool:
13 | """判断当前环境是否需要运行此迁移"""
14 |
15 | for adapter in self.ap.platform_cfg.data['platform-adapters']:
16 | if adapter['adapter'] == 'gewechat':
17 | if 'gewechat_file_url' not in adapter:
18 | return True
19 | return False
20 |
21 | async def run(self):
22 | """执行迁移"""
23 | for adapter in self.ap.platform_cfg.data['platform-adapters']:
24 | if adapter['adapter'] == 'gewechat':
25 | if 'gewechat_file_url' not in adapter:
26 | parsed_url = urlparse(adapter['gewechat_url'])
27 | adapter['gewechat_file_url'] = f'{parsed_url.scheme}://{parsed_url.hostname}:2532'
28 |
29 | await self.ap.platform_cfg.dump_config()
30 |
--------------------------------------------------------------------------------
/src/langbot/pkg/entity/persistence/bot.py:
--------------------------------------------------------------------------------
1 | import sqlalchemy
2 |
3 | from .base import Base
4 |
5 |
6 | class Bot(Base):
7 | """Bot"""
8 |
9 | __tablename__ = 'bots'
10 |
11 | uuid = sqlalchemy.Column(sqlalchemy.String(255), primary_key=True, unique=True)
12 | name = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
13 | description = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
14 | adapter = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
15 | adapter_config = sqlalchemy.Column(sqlalchemy.JSON, nullable=False)
16 | enable = sqlalchemy.Column(sqlalchemy.Boolean, nullable=False, default=False)
17 | use_pipeline_name = sqlalchemy.Column(sqlalchemy.String(255), nullable=True)
18 | use_pipeline_uuid = sqlalchemy.Column(sqlalchemy.String(255), nullable=True)
19 | created_at = sqlalchemy.Column(sqlalchemy.DateTime, nullable=False, server_default=sqlalchemy.func.now())
20 | updated_at = sqlalchemy.Column(
21 | sqlalchemy.DateTime,
22 | nullable=False,
23 | server_default=sqlalchemy.func.now(),
24 | onupdate=sqlalchemy.func.now(),
25 | )
26 |
--------------------------------------------------------------------------------
/web/src/app/home/knowledge/components/kb-retrieve/ExternalKBRetrieve.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import React from 'react';
4 | import { httpClient } from '@/app/infra/http/HttpClient';
5 | import { RetrieveResult } from '@/app/infra/entities/api';
6 | import KBRetrieveGeneric from './KBRetrieveGeneric';
7 |
8 | interface ExternalKBRetrieveProps {
9 | kbId: string;
10 | }
11 |
12 | /**
13 | * External knowledge base retrieve component
14 | * Uses the generic retrieve component with external KB API
15 | */
16 | export default function ExternalKBRetrieve({ kbId }: ExternalKBRetrieveProps) {
17 | const getResultTitle = (result: RetrieveResult): string => {
18 | // For external KB, try to get document_name or use a generic title
19 | return (
20 | (result.metadata.document_name as string) ||
21 | (result.metadata.source as string) ||
22 | result.id
23 | );
24 | };
25 |
26 | return (
27 |
34 | );
35 | }
36 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m004_moonshot_cfg_completion.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('moonshot-config-completion', 4)
7 | class MoonshotConfigCompletionMigration(migration.Migration):
8 | """OpenAI配置迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 | return (
13 | 'moonshot-chat-completions' not in self.ap.provider_cfg.data['requester']
14 | or 'moonshot' not in self.ap.provider_cfg.data['keys']
15 | )
16 |
17 | async def run(self):
18 | """执行迁移"""
19 | if 'moonshot-chat-completions' not in self.ap.provider_cfg.data['requester']:
20 | self.ap.provider_cfg.data['requester']['moonshot-chat-completions'] = {
21 | 'base-url': 'https://api.moonshot.cn/v1',
22 | 'args': {},
23 | 'timeout': 120,
24 | }
25 |
26 | if 'moonshot' not in self.ap.provider_cfg.data['keys']:
27 | self.ap.provider_cfg.data['keys']['moonshot'] = []
28 |
29 | await self.ap.provider_cfg.dump_config()
30 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m005_deepseek_cfg_completion.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('deepseek-config-completion', 5)
7 | class DeepseekConfigCompletionMigration(migration.Migration):
8 | """OpenAI配置迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 | return (
13 | 'deepseek-chat-completions' not in self.ap.provider_cfg.data['requester']
14 | or 'deepseek' not in self.ap.provider_cfg.data['keys']
15 | )
16 |
17 | async def run(self):
18 | """执行迁移"""
19 | if 'deepseek-chat-completions' not in self.ap.provider_cfg.data['requester']:
20 | self.ap.provider_cfg.data['requester']['deepseek-chat-completions'] = {
21 | 'base-url': 'https://api.deepseek.com',
22 | 'args': {},
23 | 'timeout': 120,
24 | }
25 |
26 | if 'deepseek' not in self.ap.provider_cfg.data['keys']:
27 | self.ap.provider_cfg.data['keys']['deepseek'] = []
28 |
29 | await self.ap.provider_cfg.dump_config()
30 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m027_wx_official_account_config.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('wx-official-account-config', 27)
7 | class WXOfficialAccountConfigMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 |
13 | # for adapter in self.ap.platform_cfg.data['platform-adapters']:
14 | # if adapter['adapter'] == 'officialaccount':
15 | # return False
16 |
17 | # return True
18 | return False
19 |
20 | async def run(self):
21 | """执行迁移"""
22 | self.ap.platform_cfg.data['platform-adapters'].append(
23 | {
24 | 'adapter': 'officialaccount',
25 | 'enable': False,
26 | 'token': '',
27 | 'EncodingAESKey': '',
28 | 'AppID': '',
29 | 'AppSecret': '',
30 | 'host': '0.0.0.0',
31 | 'port': 2287,
32 | }
33 | )
34 |
35 | await self.ap.platform_cfg.dump_config()
36 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/note.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import abc
4 | import typing
5 |
6 | from . import app
7 |
8 | preregistered_notes: list[typing.Type[LaunchNote]] = []
9 |
10 |
11 | def note_class(name: str, number: int):
12 | """Register a launch information"""
13 |
14 | def decorator(cls: typing.Type[LaunchNote]) -> typing.Type[LaunchNote]:
15 | cls.name = name
16 | cls.number = number
17 | preregistered_notes.append(cls)
18 | return cls
19 |
20 | return decorator
21 |
22 |
23 | class LaunchNote(abc.ABC):
24 | """Launch information"""
25 |
26 | name: str
27 |
28 | number: int
29 |
30 | ap: app.Application
31 |
32 | def __init__(self, ap: app.Application):
33 | self.ap = ap
34 |
35 | @abc.abstractmethod
36 | async def need_show(self) -> bool:
37 | """Determine if the current environment needs to display this launch information"""
38 | pass
39 |
40 | @abc.abstractmethod
41 | async def yield_note(self) -> typing.AsyncGenerator[typing.Tuple[str, int], None]:
42 | """Generate launch information"""
43 | pass
44 |
--------------------------------------------------------------------------------
/tests/unit_tests/pipeline/test_simple.py:
--------------------------------------------------------------------------------
1 | """
2 | Simple standalone tests to verify test infrastructure
3 | These tests don't import the actual pipeline code to avoid circular import issues
4 | """
5 |
6 | import pytest
7 | from unittest.mock import Mock, AsyncMock
8 |
9 |
10 | def test_pytest_works():
11 | """Verify pytest is working"""
12 | assert True
13 |
14 |
15 | @pytest.mark.asyncio
16 | async def test_async_works():
17 | """Verify async tests work"""
18 | mock = AsyncMock(return_value=42)
19 | result = await mock()
20 | assert result == 42
21 |
22 |
23 | def test_mocks_work():
24 | """Verify mocking works"""
25 | mock = Mock()
26 | mock.return_value = 'test'
27 | assert mock() == 'test'
28 |
29 |
30 | def test_fixtures_work(mock_app):
31 | """Verify fixtures are loaded"""
32 | assert mock_app is not None
33 | assert mock_app.logger is not None
34 | assert mock_app.sess_mgr is not None
35 |
36 |
37 | def test_sample_query(sample_query):
38 | """Verify sample query fixture works"""
39 | assert sample_query.query_id == 'test-query-id'
40 | assert sample_query.launcher_id == 12345
41 |
--------------------------------------------------------------------------------
/web/src/i18n/index.ts:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import i18n from 'i18next';
4 | import { initReactI18next } from 'react-i18next';
5 | import LanguageDetector from 'i18next-browser-languagedetector';
6 |
7 | import enUS from './locales/en-US';
8 | import zhHans from './locales/zh-Hans';
9 | import zhHant from './locales/zh-Hant';
10 | import jaJP from './locales/ja-JP';
11 |
12 | i18n
13 | .use(LanguageDetector)
14 | .use(initReactI18next)
15 | .init({
16 | resources: {
17 | 'en-US': {
18 | translation: enUS,
19 | },
20 | 'zh-Hans': {
21 | translation: zhHans,
22 | },
23 | 'zh-Hant': {
24 | translation: zhHant,
25 | },
26 | 'ja-JP': {
27 | translation: jaJP,
28 | },
29 | },
30 | fallbackLng: 'zh-Hans',
31 | debug: process.env.NODE_ENV === 'development',
32 | interpolation: {
33 | escapeValue: false, // React already escapes values
34 | },
35 | detection: {
36 | order: ['localStorage', 'navigator'],
37 | lookupLocalStorage: 'langbot_language',
38 | caches: ['localStorage'],
39 | },
40 | });
41 |
42 | export default i18n;
43 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m030_lark_config_cmpl.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('lark-config-cmpl', 30)
7 | class LarkConfigCmplMigration(migration.Migration):
8 | """迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 |
13 | for adapter in self.ap.platform_cfg.data['platform-adapters']:
14 | if adapter['adapter'] == 'lark':
15 | if 'enable-webhook' not in adapter:
16 | return True
17 |
18 | return False
19 |
20 | async def run(self):
21 | """执行迁移"""
22 | for adapter in self.ap.platform_cfg.data['platform-adapters']:
23 | if adapter['adapter'] == 'lark':
24 | if 'enable-webhook' not in adapter:
25 | adapter['enable-webhook'] = False
26 | if 'port' not in adapter:
27 | adapter['port'] = 2285
28 | if 'encrypt-key' not in adapter:
29 | adapter['encrypt-key'] = 'xxxxxxxxx'
30 |
31 | await self.ap.platform_cfg.dump_config()
32 |
--------------------------------------------------------------------------------
/src/langbot/pkg/platform/sources/lark.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/langbot/pkg/platform/sources/line.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: MessagePlatformAdapter
3 | metadata:
4 | name: LINE
5 | label:
6 | en_US: LINE
7 | zh_Hans: LINE
8 | description:
9 | en_US: LINE Adapter
10 | zh_Hans: LINE适配器,请查看文档了解使用方式
11 | ja_JP: LINEアダプター、ドキュメントを参照してください
12 | zh_Hant: LINE適配器,請查看文檔了解使用方式
13 | icon: line.png
14 | spec:
15 | config:
16 | - name: channel_access_token
17 | label:
18 | en_US: Channel access token
19 | zh_Hans: 频道访问令牌
20 | ja_JP: チャンネルアクセストークン
21 | zh_Hant: 頻道訪問令牌
22 | type: string
23 | required: true
24 | default: ""
25 | - name: channel_secret
26 | label:
27 | en_US: Channel secret
28 | zh_Hans: 消息密钥
29 | ja_JP: チャンネルシークレット
30 | zh_Hant: 消息密钥
31 | description:
32 | en_US: Only valid when webhook mode is enabled, please fill in the encrypt key
33 | zh_Hans: 请填写加密密钥
34 | ja_JP: Webhookモードが有効な場合にのみ、暗号化キーを入力してください
35 | zh_Hant: 請填寫加密密钥
36 | type: string
37 | required: true
38 | default: ""
39 | execution:
40 | python:
41 | path: ./line.py
42 | attr: LINEAdapter
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m003_anthropic_requester_cfg_completion.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('anthropic-requester-config-completion', 3)
7 | class AnthropicRequesterConfigCompletionMigration(migration.Migration):
8 | """OpenAI配置迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 | return (
13 | 'anthropic-messages' not in self.ap.provider_cfg.data['requester']
14 | or 'anthropic' not in self.ap.provider_cfg.data['keys']
15 | )
16 |
17 | async def run(self):
18 | """执行迁移"""
19 | if 'anthropic-messages' not in self.ap.provider_cfg.data['requester']:
20 | self.ap.provider_cfg.data['requester']['anthropic-messages'] = {
21 | 'base-url': 'https://api.anthropic.com',
22 | 'args': {'max_tokens': 1024},
23 | 'timeout': 120,
24 | }
25 |
26 | if 'anthropic' not in self.ap.provider_cfg.data['keys']:
27 | self.ap.provider_cfg.data['keys']['anthropic'] = []
28 |
29 | await self.ap.provider_cfg.dump_config()
30 |
--------------------------------------------------------------------------------
/src/langbot/pkg/core/migrations/m039_modelscope_cfg_completion.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from .. import migration
4 |
5 |
6 | @migration.migration_class('modelscope-config-completion', 39)
7 | class ModelScopeConfigCompletionMigration(migration.Migration):
8 | """ModelScope配置迁移"""
9 |
10 | async def need_migrate(self) -> bool:
11 | """判断当前环境是否需要运行此迁移"""
12 | return (
13 | 'modelscope-chat-completions' not in self.ap.provider_cfg.data['requester']
14 | or 'modelscope' not in self.ap.provider_cfg.data['keys']
15 | )
16 |
17 | async def run(self):
18 | """执行迁移"""
19 | if 'modelscope-chat-completions' not in self.ap.provider_cfg.data['requester']:
20 | self.ap.provider_cfg.data['requester']['modelscope-chat-completions'] = {
21 | 'base-url': 'https://api-inference.modelscope.cn/v1',
22 | 'args': {},
23 | 'timeout': 120,
24 | }
25 |
26 | if 'modelscope' not in self.ap.provider_cfg.data['keys']:
27 | self.ap.provider_cfg.data['keys']['modelscope'] = []
28 |
29 | await self.ap.provider_cfg.dump_config()
30 |
--------------------------------------------------------------------------------
/src/langbot/libs/wechatpad_api/api/user.py:
--------------------------------------------------------------------------------
1 | from langbot.libs.wechatpad_api.util.http_util import post_json, async_request, get_json
2 |
3 |
4 | class UserApi:
5 | def __init__(self, base_url, token):
6 | self.base_url = base_url
7 | self.token = token
8 |
9 | def get_profile(self):
10 | """获取个人资料"""
11 | url = f'{self.base_url}/user/GetProfile'
12 |
13 | return get_json(base_url=url, token=self.token)
14 |
15 | def get_qr_code(self, recover: bool = True, style: int = 8):
16 | """获取自己的二维码"""
17 | param = {'Recover': recover, 'Style': style}
18 | url = f'{self.base_url}/user/GetMyQRCode'
19 | return post_json(base_url=url, token=self.token, data=param)
20 |
21 | def get_safety_info(self):
22 | """获取设备记录"""
23 | url = f'{self.base_url}/equipment/GetSafetyInfo'
24 | return post_json(base_url=url, token=self.token)
25 |
26 | async def update_head_img(self, head_img_base64):
27 | """修改头像"""
28 | param = {'Base64': head_img_base64}
29 | url = f'{self.base_url}/user/UploadHeadImage'
30 | return await async_request(base_url=url, token_key=self.token, json=param)
31 |
--------------------------------------------------------------------------------
/web/src/app/home/plugins/components/plugin-market/plugin-market-card/PluginMarketCardVO.ts:
--------------------------------------------------------------------------------
1 | export interface IPluginMarketCardVO {
2 | pluginId: string;
3 | author: string;
4 | pluginName: string;
5 | label: string;
6 | description: string;
7 | installCount: number;
8 | iconURL: string;
9 | githubURL: string;
10 | version: string;
11 | components?: Record;
12 | }
13 |
14 | export class PluginMarketCardVO implements IPluginMarketCardVO {
15 | pluginId: string;
16 | description: string;
17 | label: string;
18 | author: string;
19 | pluginName: string;
20 | iconURL: string;
21 | githubURL: string;
22 | installCount: number;
23 | version: string;
24 | components?: Record;
25 |
26 | constructor(prop: IPluginMarketCardVO) {
27 | this.description = prop.description;
28 | this.label = prop.label;
29 | this.author = prop.author;
30 | this.pluginName = prop.pluginName;
31 | this.iconURL = prop.iconURL;
32 | this.githubURL = prop.githubURL;
33 | this.installCount = prop.installCount;
34 | this.pluginId = prop.pluginId;
35 | this.version = prop.version;
36 | this.components = prop.components;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------