├── .editorconfig ├── .github └── workflows │ ├── deploy.yml │ └── font.yml ├── .gitignore ├── LICENSE ├── README.md ├── docs ├── .vitepress │ ├── config.js │ ├── nav │ │ ├── navbar.js │ │ └── sidebar.js │ └── theme │ │ ├── custom.css │ │ └── index.js ├── assets │ ├── 5a4a07cc67f556288d3df2e9029fc14.jpg │ ├── console │ │ ├── addBot.png │ │ ├── link.png │ │ ├── llOneBot.png │ │ ├── llOneBotConfig.png │ │ ├── mainBot.png │ │ ├── ntqq.png │ │ ├── online.png │ │ ├── plugin.png │ │ ├── plugin2.png │ │ ├── plugin3.png │ │ └── test.png │ ├── deploy │ │ └── running.png │ ├── design │ │ ├── account.svg │ │ ├── adapter.svg │ │ ├── centerProcessor.svg │ │ ├── handlerFactory.svg │ │ └── lifeCycle.svg │ └── examples │ │ ├── awesome1.png │ │ ├── hello.png │ │ ├── hello2.png │ │ ├── hello3.png │ │ ├── hello4.png │ │ ├── hello5.png │ │ ├── hello6.png │ │ └── hello7.png ├── components │ ├── bots.vue │ ├── chargeThanks.vue │ ├── download.vue │ ├── mirrorChyan.vue │ └── specialThanks.vue ├── develop │ ├── adapters │ │ ├── comwechat.md │ │ ├── gocq.md │ │ ├── index.md │ │ ├── kook.md │ │ ├── mah.md │ │ ├── onebot11.md │ │ ├── onebot12.md │ │ ├── qqChannel.md │ │ ├── qqGlobal.md │ │ └── qqGroup.md │ ├── advanced │ │ ├── blockingIO.md │ │ ├── chainBuilder.md │ │ ├── eventBus.md │ │ ├── index.md │ │ ├── lifeCycle.md │ │ ├── loadPlugins.md │ │ ├── logger.md │ │ ├── playwright.md │ │ ├── startupParameter.md │ │ └── timedTask.md │ ├── basic │ │ ├── api │ │ │ ├── index.md │ │ │ └── qqbot.md │ │ ├── chainBuild │ │ │ ├── ark.md │ │ │ ├── at.md │ │ │ ├── atAll.md │ │ │ ├── embed.md │ │ │ ├── extend.md │ │ │ ├── face.md │ │ │ ├── forward.md │ │ │ ├── html.md │ │ │ ├── image.md │ │ │ ├── markdown.md │ │ │ ├── mdTemplate.md │ │ │ ├── tag.md │ │ │ ├── text.md │ │ │ ├── textImage.md │ │ │ ├── video.md │ │ │ └── voice.md │ │ ├── continuityMessage.md │ │ ├── handleEvents.md │ │ ├── handleException.md │ │ ├── index.md │ │ ├── messageHandler.md │ │ ├── multipleAccounts.md │ │ ├── recallMessage.md │ │ ├── recvMessage.md │ │ ├── sendActiveMessage.md │ │ ├── sendMessage.md │ │ ├── statement.md │ │ └── testInstance.md │ ├── design.md │ ├── index.md │ ├── old │ │ └── httpSupport.md │ ├── plugin │ │ ├── addDoc.md │ │ ├── amiyaBotPluginInstance.md │ │ ├── build.md │ │ ├── create.md │ │ ├── debug.md │ │ ├── env.md │ │ ├── index.md │ │ ├── jsonSchema.md │ │ ├── life.md │ │ └── publish.md │ └── tools │ │ ├── databaseSupport.md │ │ ├── httpRequests.md │ │ └── httpSupport.md ├── download.md ├── footstone ├── guide │ ├── deploy │ │ ├── advanced │ │ │ ├── index.md │ │ │ └── mysql.md │ │ ├── console │ │ │ ├── configure.md │ │ │ ├── index.md │ │ │ └── plugin.md │ │ ├── faq │ │ │ ├── PluginProblem.md │ │ │ └── commonProblem.md │ │ ├── getStarted │ │ │ ├── code.md │ │ │ ├── docker.md │ │ │ ├── exe.md │ │ │ └── index.md │ │ ├── index.md │ │ ├── instances │ │ │ ├── cqhttp.md │ │ │ ├── kook.md │ │ │ ├── llonebot.md │ │ │ ├── mirai.md │ │ │ ├── napcatqq.md │ │ │ └── qqbot.md │ │ └── maintain │ │ │ └── upgrade.md │ └── index.md ├── index.md ├── public │ ├── E0BA9D78918921391A5BE261A96C6F04.jpg │ ├── F7AB3AFE554027987502E5E1AB65746E.jpg │ ├── bot │ │ └── 102068219.json │ ├── favicon.ico │ └── logo.svg └── sponsor.md ├── package.json └── scripts ├── HarmonyOS_Sans_SC.ttf ├── minfont.py └── uFont.py /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 4 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Delpoy 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | 10 | jobs: 11 | build: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | strategy: 16 | matrix: 17 | node-version: [ 16.x ] 18 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ 19 | 20 | steps: 21 | - name: Fetch sources 22 | uses: actions/checkout@v2 23 | 24 | - name: Use Node.js ${{ matrix.node-version }} 25 | uses: actions/setup-node@v2 26 | with: 27 | node-version: ${{ matrix.node-version }} 28 | 29 | - name: Build 30 | run: | 31 | npm install 32 | npm run docs:build 33 | 34 | - name: Update CNAME 35 | run: 36 | echo 'www.amiyabot.com' > docs/.vitepress/dist/CNAME 37 | 38 | - name: Deploy 39 | uses: crazy-max/ghaction-github-pages@v2.5.0 40 | env: 41 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 42 | with: 43 | target_branch: gh-pages 44 | build_dir: docs/.vitepress/dist 45 | -------------------------------------------------------------------------------- /.github/workflows/font.yml: -------------------------------------------------------------------------------- 1 | name: Font Optimization 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | 7 | jobs: 8 | Optimization: 9 | 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v2.4.2 14 | 15 | - name: Use Python 3.8 16 | uses: actions/setup-python@v4 17 | with: 18 | python-version: '3.8' 19 | 20 | - name: Font Optimization 21 | env: 22 | SECRETID: ${{ secrets.SECRETID }} 23 | SECRETKEY: ${{ secrets.SECRETKEY }} 24 | run: | 25 | pip install fontTools cos-python-sdk-v5 brotli 26 | python scripts/minfont.py 27 | python scripts/uFont.py 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .temp/ 3 | .cache/ 4 | 5 | dist/ 6 | cache/ 7 | node_modules/ 8 | 9 | .DS_Store 10 | 11 | yarn.lock 12 | package-lock.json 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 AmiyaBot 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AmiyaBot 文档 2 | 3 | ```bash 4 | npm install 5 | npm run docs:dev 6 | ``` 7 | 8 | ### 版权信息 9 | 10 |
11 | 12 | 本仓库内容版权信息如下: 13 |

14 | 代码部分使用 [MIT](/LICENSE) 授权。 15 |

16 | 文档(不包括多媒体内容,字体等)使用 [知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议(CC BY-NC-SA 4.0)](https://creativecommons.org/licenses/by-nc-sa/4.0/) 17 | 授权。 18 |

19 | 知识共享许可协议 20 |

21 | 所有内容的署名应当以 [本 Github Repo](https://github.com/AmiyaBot/Amiya-Bot-docs) 的相关文件提交记录为准。所有对文件内容具有有效修改(Pull request 被项目组合并入本 Repo)的贡献者对于其贡献部分具有署名权。 22 |

23 | 多媒体内容,字体等其他内容除另有说明外不作授权。 24 |

25 | 仓库中可能有一些内容项目开发组并非权利人,这些内容的相关权利由其权利人保留。 26 |

27 | 本仓库的 [字体压缩脚本](scripts/minfont.py) 28 | 来自 [GraiaCommunity/Docs](https://github.com/GraiaCommunity/Docs),使用 [MIT](https://github.com/GraiaCommunity/Docs/blob/vitepress/LICENSE) 29 | 授权。 30 |

31 | 注意:当您在行使项目开发组根据许可证/许可协议在此明确授权给您的权利之前,请先确保您是否已经/可以履行许可证/许可协议,或您的用途是否在许可证/许可协议允许的范围之内。具体的事项请参照相关超链接指向部分,这十分重要,若您不按照许可证/许可协议要求来使用本仓库内容,则您可能涉及侵权。侵权行为一经发现必将追究到底! 32 | -------------------------------------------------------------------------------- /docs/.vitepress/config.js: -------------------------------------------------------------------------------- 1 | import navbar from './nav/navbar' 2 | import sidebar from './nav/sidebar' 3 | 4 | export default { 5 | lang: 'zh-CN', 6 | title: 'AmiyaBot', 7 | description: 'AmiyaBot,Python 渐进式 QQ 频道机器人框架,可使用内置适配器对接 QQ 群、OneBot v11/12、KOOK 等机器人平台。', 8 | themeConfig: { 9 | nav: navbar, 10 | logo: '/logo.svg', 11 | sidebar: sidebar, 12 | editLink: { 13 | pattern: 'https://github.com/AmiyaBot/Amiya-Bot-docs/edit/master/docs/:path', 14 | text: '在 GitHub 上编辑此页/查看此页贡献者' 15 | }, 16 | socialLinks: [ 17 | { icon: 'github', link: 'https://github.com/AmiyaBot' } 18 | ], 19 | footer: { 20 | message: 'MIT & CC BY-NC-SA 4.0 Licensed. More Info Click Here.', 21 | copyright: 'Copyright © 2024-present vivien8261 粤ICP备2021107697号-1' 22 | }, 23 | search: { 24 | provider: 'local' 25 | } 26 | }, 27 | lastUpdated: true 28 | } 29 | -------------------------------------------------------------------------------- /docs/.vitepress/nav/navbar.js: -------------------------------------------------------------------------------- 1 | import sidebar, {adapters} from './sidebar' 2 | 3 | function getFirstNav(navItems) { 4 | return navItems.map(item => { 5 | return { 6 | text: item.text, 7 | link: item.items[0].link 8 | } 9 | }) 10 | } 11 | 12 | export default [ 13 | { 14 | text: '主页', 15 | link: '/' 16 | }, 17 | { 18 | text: '简介', 19 | items: [ 20 | {text: '项目介绍', link: '/guide/'}, 21 | {text: '设计', link: '/develop/design'} 22 | ] 23 | }, 24 | { 25 | text: '开发指南', 26 | items: [ 27 | {text: '基础', items: getFirstNav(sidebar['/develop/basic/'])}, 28 | {text: '进阶', items: getFirstNav(sidebar['/develop/advanced/'])}, 29 | {text: '插件', items: [{text: '插件开发', link: '/develop/plugin/'}]}, 30 | ...sidebar['/develop/tools/'], 31 | ] 32 | }, 33 | { 34 | text: '适配器', 35 | items: adapters 36 | }, 37 | { 38 | text: '兔兔机器人', 39 | items: [ 40 | { 41 | text: '部署', 42 | items: [ 43 | {text: '开始部署', link: '/guide/deploy/'}, 44 | {text: '常见问题', link: '/guide/deploy/faq/commonProblem'}, 45 | {text: '连接控制台', link: '/guide/deploy/console/index.md'}, 46 | {text: '如何更新', link: '/guide/deploy/maintain/upgrade.md'}, 47 | {text: '高级使用', link: '/guide/deploy/advanced/index.md'}, 48 | ] 49 | }, 50 | {text: '使用官方版 🎉', link: '/guide/deploy/#官方版兔兔'}, 51 | ] 52 | }, 53 | { 54 | text: '联系我们', 55 | items: [ 56 | { 57 | text: '赞助', 58 | link: '/sponsor' 59 | }, 60 | { 61 | text: '官方群', 62 | link: 'https://qm.qq.com/q/9ft0w6HQj0' 63 | }, 64 | { 65 | text: '官方频道', 66 | link: 'https://qun.qq.com/qqweb/qunpro/share?_wv=3&_wwv=128&appChannel=share&inviteCode=1W4sJux&appChannel=share&businessType=9&from=181074&biz=ka&shareSource=5' 67 | } 68 | ] 69 | }, 70 | { 71 | text: '下载', 72 | link: '/download' 73 | }, 74 | ] 75 | -------------------------------------------------------------------------------- /docs/.vitepress/nav/sidebar.js: -------------------------------------------------------------------------------- 1 | export const adapters = [ 2 | {text: 'QQ频道机器人', link: '/develop/adapters/qqChannel.md'}, 3 | {text: 'QQ群机器人', link: '/develop/adapters/qqGroup.md'}, 4 | {text: 'QQ全域机器人', link: '/develop/adapters/qqGlobal.md'}, 5 | {text: 'KOOK机器人', link: '/develop/adapters/kook.md'}, 6 | {text: 'Mirai-Api-Http', link: '/develop/adapters/mah.md'}, 7 | {text: 'Go-CQHttp', link: '/develop/adapters/gocq.md'}, 8 | {text: 'ComWeChatBot Client', link: '/develop/adapters/comwechat.md'}, 9 | {text: 'OneBot 11', link: '/develop/adapters/onebot11.md'}, 10 | {text: 'OneBot 12', link: '/develop/adapters/onebot12.md'}, 11 | 12 | ] 13 | 14 | export default { 15 | '/develop/basic/': [ 16 | { 17 | text: '创建实例', 18 | collapsible: true, 19 | items: [ 20 | {text: '开始使用', link: '/develop/basic/index.md'}, 21 | {text: '多账号', link: '/develop/basic/multipleAccounts.md'} 22 | ] 23 | }, 24 | { 25 | text: '接收&发送消息', 26 | collapsible: true, 27 | items: [ 28 | {text: '声明', link: '/develop/basic/statement.md'}, 29 | {text: '注册消息响应', link: '/develop/basic/messageHandler.md'}, 30 | {text: '接收消息', link: '/develop/basic/recvMessage.md'}, 31 | {text: '发送消息', link: '/develop/basic/sendMessage.md'}, 32 | {text: '发送主动消息', link: '/develop/basic/sendActiveMessage.md'}, 33 | {text: '创建连续对话', link: '/develop/basic/continuityMessage.md'}, 34 | {text: '撤回消息', link: '/develop/basic/recallMessage.md'} 35 | ] 36 | }, 37 | { 38 | text: '事件&异常', 39 | collapsible: true, 40 | items: [ 41 | {text: '事件监听', link: '/develop/basic/handleEvents.md'}, 42 | {text: '异常监听', link: '/develop/basic/handleException.md'} 43 | ] 44 | }, 45 | { 46 | text: '消息构建元素', 47 | collapsible: true, 48 | items: [ 49 | {text: 'At', link: '/develop/basic/chainBuild/at.md'}, 50 | {text: 'At 所有人', link: '/develop/basic/chainBuild/atAll.md'}, 51 | {text: '频道跳转超链接', link: '/develop/basic/chainBuild/tag.md'}, 52 | {text: '文字', link: '/develop/basic/chainBuild/text.md'}, 53 | {text: '表情', link: '/develop/basic/chainBuild/face.md'}, 54 | {text: '图片', link: '/develop/basic/chainBuild/image.md'}, 55 | {text: '语音', link: '/develop/basic/chainBuild/voice.md'}, 56 | {text: '视频', link: '/develop/basic/chainBuild/video.md'}, 57 | {text: '文字生成的图片', link: '/develop/basic/chainBuild/textImage.md'}, 58 | {text: 'HTML 生成的图片', link: '/develop/basic/chainBuild/html.md'}, 59 | {text: 'Markdown 生成的图片', link: '/develop/basic/chainBuild/markdown.md'}, 60 | {text: 'Markdown 模版', link: '/develop/basic/chainBuild/mdTemplate.md'}, 61 | {text: 'Embed 消息', link: '/develop/basic/chainBuild/embed.md'}, 62 | {text: 'Ark 模版', link: '/develop/basic/chainBuild/ark.md'}, 63 | {text: '原生模板 & CQ码', link: '/develop/basic/chainBuild/extend.md'}, 64 | {text: '合并转发消息', link: '/develop/basic/chainBuild/forward.md'} 65 | ] 66 | }, 67 | { 68 | text: 'API', 69 | collapsible: true, 70 | items: [ 71 | {text: '调用 API', link: '/develop/basic/api/qqbot.md'}, 72 | ] 73 | }, 74 | { 75 | text: '调试', 76 | collapsible: true, 77 | items: [ 78 | {text: '使用测试实例调试', link: '/develop/basic/testInstance.md'} 79 | ] 80 | } 81 | ], 82 | '/develop/basic/api/': [ 83 | { 84 | text: 'API', 85 | collapsible: true, 86 | items: [ 87 | {text: '使用说明', link: '/develop/basic/api/index.md'}, 88 | ] 89 | }, 90 | { 91 | text: '适配器', 92 | collapsible: true, 93 | items: [ 94 | {text: 'QQ 频道', link: '/develop/basic/api/qqbot.md'} 95 | ] 96 | } 97 | ], 98 | '/develop/adapters/': [ 99 | { 100 | text: '选择适配器', 101 | collapsible: true, 102 | items: [ 103 | {text: '说明', link: '/develop/adapters/index.md'}, 104 | ...adapters 105 | ] 106 | } 107 | ], 108 | '/develop/advanced/': [ 109 | { 110 | text: '进阶开发', 111 | collapsible: true, 112 | items: [ 113 | {text: '说明', link: '/develop/advanced/index.md'}, 114 | {text: '生命周期', link: '/develop/advanced/lifeCycle.md'}, 115 | {text: '定时任务', link: '/develop/advanced/timedTask.md'}, 116 | {text: '事件总线', link: '/develop/advanced/eventBus.md'}, 117 | {text: '日志模块', link: '/develop/advanced/logger.md'}, 118 | {text: '加载插件', link: '/develop/advanced/loadPlugins.md'}, 119 | {text: '介入媒体消息的构建过程', link: '/develop/advanced/chainBuilder.md'}, 120 | ] 121 | }, 122 | { 123 | text: '开发辅助', 124 | collapsible: true, 125 | items: [ 126 | {text: '处理 IO 阻塞的操作', link: '/develop/advanced/blockingIO.md'}, 127 | {text: '改变 Playwright 启动', link: '/develop/advanced/playwright.md'}, 128 | {text: '启动参数', link: '/develop/advanced/startupParameter.md'} 129 | ] 130 | }, 131 | ], 132 | '/develop/tools/': [ 133 | { 134 | text: '衍生工具', 135 | collapsible: true, 136 | items: [ 137 | {text: 'HTTP 请求', link: '/develop/tools/httpRequests.md'}, 138 | {text: 'HTTP 服务器', link: '/develop/tools/httpSupport.md'}, 139 | {text: '数据库', link: '/develop/tools/databaseSupport.md'} 140 | ] 141 | } 142 | ], 143 | '/develop/plugin/': [ 144 | { 145 | text: '准备', 146 | collapsible: true, 147 | items: [ 148 | {text: '插件开发说明', link: '/develop/plugin/index.md'}, 149 | {text: '环境准备', link: '/develop/plugin/env.md'}, 150 | ] 151 | }, 152 | { 153 | text: '开发', 154 | collapsible: true, 155 | items: [ 156 | {text: '创建&编写插件', link: '/develop/plugin/create.md'}, 157 | {text: 'AmiyaBotPluginInstance', link: '/develop/plugin/amiyaBotPluginInstance.md'}, 158 | {text: '插件生命周期', link: '/develop/plugin/life.md'}, 159 | {text: '添加插件文档', link: '/develop/plugin/addDoc.md'}, 160 | ] 161 | }, 162 | { 163 | text: '调试', 164 | collapsible: true, 165 | items: [ 166 | {text: '调试插件', link: '/develop/plugin/debug.md'}, 167 | ] 168 | }, 169 | { 170 | text: '发布', 171 | collapsible: true, 172 | items: [ 173 | {text: '打包插件', link: '/develop/plugin/build.md'}, 174 | {text: '发布到插件商店', link: '/develop/plugin/publish.md'}, 175 | ] 176 | }, 177 | { 178 | text: '其他', 179 | collapsible: true, 180 | items: [ 181 | {text: 'JsonSchema 解释', link: '/develop/plugin/jsonSchema.md'}, 182 | ] 183 | }, 184 | ], 185 | '/guide/deploy/': [ 186 | { 187 | text: '说明', 188 | collapsible: true, 189 | items: [ 190 | {text: '简要说明', link: '/guide/deploy/index.md'}, 191 | ] 192 | }, 193 | { 194 | text: '部署兔兔V6', 195 | collapsible: true, 196 | items: [ 197 | {text: '必看', link: '/guide/deploy/getStarted/index.md'}, 198 | {text: '可执行文件部署', link: '/guide/deploy/getStarted/exe.md'}, 199 | {text: 'Docker部署', link: '/guide/deploy/getStarted/docker.md'}, 200 | {text: '代码部署', link: '/guide/deploy/getStarted/code.md'}, 201 | ] 202 | }, 203 | { 204 | text: '使用控制台', 205 | collapsible: true, 206 | items: [ 207 | {text: '连接控制台', link: '/guide/deploy/console/index.md'}, 208 | {text: '配置实例', link: '/guide/deploy/console/configure.md'}, 209 | {text: '安装插件', link: '/guide/deploy/console/plugin.md'}, 210 | ] 211 | }, 212 | { 213 | text: '实例部署', 214 | collapsible: true, 215 | items: [ 216 | {text: '官方QQ群&频道机器人', link: '/guide/deploy/instances/qqbot.md'}, 217 | {text: 'KOOK机器人', link: '/guide/deploy/instances/kook.md'}, 218 | {text: 'LLOneBot QQ群机器人', link: '/guide/deploy/instances/llonebot.md'}, 219 | {text: 'NapCatQQ QQ群机器人', link: '/guide/deploy/instances/napcatqq.md'}, 220 | {text: 'CQ-Http QQ群机器人', link: '/guide/deploy/instances/cqhttp.md'}, 221 | {text: 'Mirai-api-http QQ群机器人', link: '/guide/deploy/instances/mirai.md'}, 222 | ] 223 | }, 224 | { 225 | text: '维护', 226 | collapsible: true, 227 | items: [ 228 | {text: '如何更新', link: '/guide/deploy/maintain/upgrade.md'}, 229 | ] 230 | }, 231 | { 232 | text: '高级使用', 233 | collapsible: true, 234 | items: [ 235 | {text: '说明', link: '/guide/deploy/advanced/index.md'}, 236 | {text: '使用 Mysql', link: '/guide/deploy/advanced/mysql.md'}, 237 | ] 238 | }, 239 | { 240 | text: 'F&Q', 241 | collapsible: true, 242 | items: [ 243 | {text: '常见问题', link: '/guide/deploy/faq/commonProblem.md'}, 244 | {text: '插件常见问题', link: '/guide/deploy/faq/PluginProblem.md'} 245 | ] 246 | } 247 | ] 248 | } 249 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/custom.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Harmony'; 3 | font-weight: normal; 4 | font-style: normal; 5 | src: url('https://cos.amiyabot.com/resource/Harmony_amiyabot.com.min.woff2') 6 | } 7 | 8 | :root { 9 | scroll-behavior: smooth; 10 | --vp-font-family-base: 'Inter var experimental', 'Inter var', -apple-system, 11 | BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 12 | 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 'Harmony', sans-serif; 13 | --vp-c-brand: #ba68c8; 14 | --vp-c-brand-dark: #b74ec9; 15 | --vp-c-brand-darker: #b74ec9; 16 | --vp-c-brand-light: #ce93d8; 17 | --vp-c-brand-lighter: #ce93d8; 18 | --vp-c-text-light-1: #213547; 19 | } 20 | 21 | .vp-doc table { 22 | font-size: 14px; 23 | } 24 | 25 | .vp-doc th, .vp-doc td { 26 | padding: 5px 10px; 27 | } 28 | 29 | .vp-doc blockquote { 30 | padding: 10px 16px; 31 | border-left: 3px solid #b74ec9; 32 | background: rgb(240 248 255 / 10%); 33 | } 34 | 35 | .vp-doc blockquote > p { 36 | color: #b74ec9; 37 | } 38 | 39 | code:not(div[class*='language-'] code) { 40 | font-family: var(--vp-font-family-base); 41 | } 42 | 43 | img { 44 | border-radius: 4px; 45 | } 46 | 47 | .beta-tag { 48 | color: #fff; 49 | background: #f44336; 50 | padding: 0 5px; 51 | font-size: 18px; 52 | border-radius: 4px; 53 | } 54 | 55 | i.red { 56 | font-style: normal; 57 | color: red; 58 | } 59 | 60 | .custom-block a { 61 | text-decoration: underline !important; 62 | } 63 | 64 | .VPLink.link.link > .text { 65 | line-height: 20px; 66 | } 67 | 68 | .main-container { 69 | width: 1152px; 70 | margin: auto; 71 | padding: 30px 20px 0; 72 | } 73 | 74 | @media screen and (max-width: 768px) { 75 | .main-container { 76 | width: calc(100% - 20px); 77 | } 78 | } 79 | 80 | /*.VPContent.is-home {*/ 81 | /* -webkit-filter: grayscale(100%);*/ 82 | /* -moz-filter: grayscale(100%);*/ 83 | /* -ms-filter: grayscale(100%);*/ 84 | /* -o-filter: grayscale(100%);*/ 85 | /* filter: grayscale(100%);*/ 86 | /* filter: progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);*/ 87 | /*}*/ 88 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/index.js: -------------------------------------------------------------------------------- 1 | import DefaultTheme from 'vitepress/theme' 2 | import './custom.css' 3 | 4 | export default DefaultTheme 5 | -------------------------------------------------------------------------------- /docs/assets/5a4a07cc67f556288d3df2e9029fc14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmiyaBot/Amiya-Bot-docs/03b94939d8726c62af678160cd806e5f65649077/docs/assets/5a4a07cc67f556288d3df2e9029fc14.jpg -------------------------------------------------------------------------------- /docs/assets/console/addBot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmiyaBot/Amiya-Bot-docs/03b94939d8726c62af678160cd806e5f65649077/docs/assets/console/addBot.png -------------------------------------------------------------------------------- /docs/assets/console/link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmiyaBot/Amiya-Bot-docs/03b94939d8726c62af678160cd806e5f65649077/docs/assets/console/link.png -------------------------------------------------------------------------------- /docs/assets/console/llOneBot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmiyaBot/Amiya-Bot-docs/03b94939d8726c62af678160cd806e5f65649077/docs/assets/console/llOneBot.png -------------------------------------------------------------------------------- /docs/assets/console/llOneBotConfig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmiyaBot/Amiya-Bot-docs/03b94939d8726c62af678160cd806e5f65649077/docs/assets/console/llOneBotConfig.png -------------------------------------------------------------------------------- /docs/assets/console/mainBot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmiyaBot/Amiya-Bot-docs/03b94939d8726c62af678160cd806e5f65649077/docs/assets/console/mainBot.png -------------------------------------------------------------------------------- /docs/assets/console/ntqq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmiyaBot/Amiya-Bot-docs/03b94939d8726c62af678160cd806e5f65649077/docs/assets/console/ntqq.png -------------------------------------------------------------------------------- /docs/assets/console/online.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmiyaBot/Amiya-Bot-docs/03b94939d8726c62af678160cd806e5f65649077/docs/assets/console/online.png -------------------------------------------------------------------------------- /docs/assets/console/plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmiyaBot/Amiya-Bot-docs/03b94939d8726c62af678160cd806e5f65649077/docs/assets/console/plugin.png -------------------------------------------------------------------------------- /docs/assets/console/plugin2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmiyaBot/Amiya-Bot-docs/03b94939d8726c62af678160cd806e5f65649077/docs/assets/console/plugin2.png -------------------------------------------------------------------------------- /docs/assets/console/plugin3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmiyaBot/Amiya-Bot-docs/03b94939d8726c62af678160cd806e5f65649077/docs/assets/console/plugin3.png -------------------------------------------------------------------------------- /docs/assets/console/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmiyaBot/Amiya-Bot-docs/03b94939d8726c62af678160cd806e5f65649077/docs/assets/console/test.png -------------------------------------------------------------------------------- /docs/assets/deploy/running.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmiyaBot/Amiya-Bot-docs/03b94939d8726c62af678160cd806e5f65649077/docs/assets/deploy/running.png -------------------------------------------------------------------------------- /docs/assets/design/adapter.svg: -------------------------------------------------------------------------------- 1 | TencentMirai-api-httpGo-cqhttpAdapterCenterProcessorAmiyaBot -------------------------------------------------------------------------------- /docs/assets/design/handlerFactory.svg: -------------------------------------------------------------------------------- 1 | AmiyaBot@bot.on_event@bot.on_message@bot.on_messageevent_handlersmessage_handlersexception_handlersCenterProcessorBotHandlerFactory -------------------------------------------------------------------------------- /docs/assets/examples/awesome1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmiyaBot/Amiya-Bot-docs/03b94939d8726c62af678160cd806e5f65649077/docs/assets/examples/awesome1.png -------------------------------------------------------------------------------- /docs/assets/examples/hello.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmiyaBot/Amiya-Bot-docs/03b94939d8726c62af678160cd806e5f65649077/docs/assets/examples/hello.png -------------------------------------------------------------------------------- /docs/assets/examples/hello2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmiyaBot/Amiya-Bot-docs/03b94939d8726c62af678160cd806e5f65649077/docs/assets/examples/hello2.png -------------------------------------------------------------------------------- /docs/assets/examples/hello3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmiyaBot/Amiya-Bot-docs/03b94939d8726c62af678160cd806e5f65649077/docs/assets/examples/hello3.png -------------------------------------------------------------------------------- /docs/assets/examples/hello4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmiyaBot/Amiya-Bot-docs/03b94939d8726c62af678160cd806e5f65649077/docs/assets/examples/hello4.png -------------------------------------------------------------------------------- /docs/assets/examples/hello5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmiyaBot/Amiya-Bot-docs/03b94939d8726c62af678160cd806e5f65649077/docs/assets/examples/hello5.png -------------------------------------------------------------------------------- /docs/assets/examples/hello6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmiyaBot/Amiya-Bot-docs/03b94939d8726c62af678160cd806e5f65649077/docs/assets/examples/hello6.png -------------------------------------------------------------------------------- /docs/assets/examples/hello7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmiyaBot/Amiya-Bot-docs/03b94939d8726c62af678160cd806e5f65649077/docs/assets/examples/hello7.png -------------------------------------------------------------------------------- /docs/components/bots.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 30 | 31 | 58 | -------------------------------------------------------------------------------- /docs/components/chargeThanks.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 52 | 53 | 101 | -------------------------------------------------------------------------------- /docs/components/download.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 34 | 35 | 40 | -------------------------------------------------------------------------------- /docs/components/mirrorChyan.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 27 | 28 | 62 | -------------------------------------------------------------------------------- /docs/components/specialThanks.vue: -------------------------------------------------------------------------------- 1 | 47 | 48 | 53 | 54 | 96 | -------------------------------------------------------------------------------- /docs/develop/adapters/comwechat.md: -------------------------------------------------------------------------------- 1 | # ComWeChatBot Client Beta 2 | 3 | [ComWeChatBot Client](https://justundertaker.github.io/ComWeChatBotClient/) 是 PC hook 微信的协议端。 4 | 5 | 需在服务配置开启 [正向 websocket](https://justundertaker.github.io/ComWeChatBotClient/guide/#websocekt-type)。 6 | 7 | ## 连接 ComWeChatBot 8 | 9 | | 参数名 | 类型 | 释义 | 默认值 | 10 | |-----------|-----|------------------|-----| 11 | | host | str | 服务的 ip 地址 | | 12 | | ws_port | int | 服务的 websocket 端口 | | 13 | | http_port | int | 服务的 http 端口 | | 14 | 15 | ```python 16 | from amiyabot.adapters.comwechat import com_wechat 17 | 18 | token = '******' # access-token 19 | 20 | adapter_service = com_wechat('127.0.0.1', 8080, 8060) 21 | 22 | bot = AmiyaBot(appid=appid, token=token, adapter=adapter_service) 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/develop/adapters/gocq.md: -------------------------------------------------------------------------------- 1 | # go-cqhttp 2 | 3 | [go-cqhttp](https://docs.go-cqhttp.org/) 以下简称 **gocq**。它是基于 Mirai 以及 MiraiGo 的 OneBot Golang 原生实现。 4 | 5 | ::: danger 注意
6 | go-cq 的配置中,`post-format` 需更改为 `array`。 7 | 8 | ```yaml 9 | # config.yml 10 | message: 11 | # 上报数据类型 12 | # 可选: string, array 13 | post-format: array 14 | ``` 15 | 16 | ::: 17 | 18 | ## 连接 gocq 19 | 20 | | 参数名 | 类型 | 释义 | 默认值 | 21 | |-----------|-----|-----------------------|-----| 22 | | host | str | gocq 服务的 ip 地址 | | 23 | | ws_port | int | gocq 服务的 websocket 端口 | | 24 | | http_port | int | gocq 服务的 http 端口 | | 25 | 26 | ```python 27 | from amiyabot.adapters.cqhttp import cq_http 28 | 29 | qq = '******' # 机器人的 QQ 号 30 | token = '******' # gocq 的 access-token 31 | 32 | adapter_service = cq_http('127.0.0.1', 8080, 5700) 33 | 34 | bot = AmiyaBot(appid=qq, token=token, adapter=adapter_service) 35 | ``` 36 | -------------------------------------------------------------------------------- /docs/develop/adapters/index.md: -------------------------------------------------------------------------------- 1 | # 适配器 2 | 3 | 更改默认适配器可以让你搭建其他平台的机器人,除了 `bot.instance.api` 4 | 有差异外,你几乎可以完全按照文档的开发方式进行。我们尽量为所有适配器的基本逻辑实现了相同的效果,使得在不同平台下 AmiyaBot 5 | 的开发差异变得极其之小。 6 | 7 | ## 适配器参数 adapter 8 | 9 | AmiyaBot 对象拥有一个适配器参数 adapter,接受一个 `BotAdapterProtocol` 的子类。默认值为 QQ 10 | 频道机器人的适配器 `QQGuildBotInstance`。 11 | 12 | ```python 13 | class AmiyaBot(BotHandlerFactory): 14 | def __init__(self, 15 | ... 16 | adapter: Type[BotAdapterProtocol] = QQGuildBotInstance): 17 | ... 18 | ``` 19 | 20 | 从左侧导航挑选合适的适配器,更改你的实例。 21 | -------------------------------------------------------------------------------- /docs/develop/adapters/kook.md: -------------------------------------------------------------------------------- 1 | # KOOK 机器人 2 | 3 | [KOOK](https://www.kookapp.cn/) 是一款免费无广告的语音沟通工具,并提供了强大的官方机器人支持。 4 | 5 | KOOK 适配器不需要 `appid`,只需要传入 [应用的 websocket token](https://developer.kookapp.cn/app/index) 参数即可。 6 | 7 | ```python 8 | from amiyabot import KOOKBotInstance 9 | 10 | ws_token = '******' # websocket Token 11 | 12 | bot = AmiyaBot(token=ws_token, adapter=KOOKBotInstance) 13 | ``` 14 | -------------------------------------------------------------------------------- /docs/develop/adapters/mah.md: -------------------------------------------------------------------------------- 1 | # mirai-api-http 2 | 3 | [mirai-api-http](https://docs.mirai.mamoe.net/mirai-api-http/) 以下简称 **mah**。是一个在全平台下运行,提供 QQ Android 4 | 协议支持的高效率机器人库。 5 | 6 | 如要使用此适配器,需要 mah 同时开启了 websocket 和 http 服务。AmiyaBot 将通过 mirai_api_http 方法实例化它的适配器。 7 | 8 | ## 连接 mah 9 | 10 | | 参数名 | 类型 | 释义 | 默认值 | 11 | |-----------|-----|----------------------|-----| 12 | | host | str | mah 服务的 ip 地址 | | 13 | | ws_port | int | mah 服务的 websocket 端口 | | 14 | | http_port | int | mah 服务的 http 端口 | | 15 | 16 | ```python 17 | from amiyabot.adapters.mirai import mirai_api_http 18 | 19 | qq = '******' # 机器人的 QQ 号 20 | auth_key = '******' # mah 的 verifyKey 21 | 22 | adapter_service = mirai_api_http('127.0.0.1', 8060, 8080) 23 | 24 | bot = AmiyaBot(appid=qq, token=auth_key, adapter=adapter_service) 25 | ``` 26 | -------------------------------------------------------------------------------- /docs/develop/adapters/onebot11.md: -------------------------------------------------------------------------------- 1 | # OneBot v11 Beta 2 | 3 | [OneBot 11](https://github.com/botuniverse/onebot-11) 以下简称 **ob11**。该标准是从原 CKYU 平台的 CQHTTP 4 | 插件接口修改而来的通用聊天机器人应用接口标准。
5 | 使用此适配器,可连接任何 OneBot 11 实现的机器人平台。 6 | 7 | ## 连接 onebot11 8 | 9 | | 参数名 | 类型 | 释义 | 默认值 | 10 | |-----------|-----|-----------------------|-----| 11 | | host | str | ob11 服务的 ip 地址 | | 12 | | ws_port | int | ob11 服务的 websocket 端口 | | 13 | | http_port | int | ob11 服务的 http 端口 | | 14 | 15 | ```python 16 | from amiyabot.adapters.onebot.v11 import onebot11 17 | 18 | appid = '******' # 机器人的账号(如需要) 19 | token = '******' # access-token 20 | 21 | adapter_service = onebot11('127.0.0.1', 8080, 8060) 22 | 23 | bot = AmiyaBot(appid=appid, token=token, adapter=adapter_service) 24 | ``` 25 | -------------------------------------------------------------------------------- /docs/develop/adapters/onebot12.md: -------------------------------------------------------------------------------- 1 | # OneBot v12 Beta 2 | 3 | [OneBot 12](https://onebot.dev/) 以下简称 **ob12** 4 | 。是一个聊天机器人应用接口标准,旨在统一不同聊天平台上的机器人应用开发接口,使开发者只需编写一次业务逻辑代码即可应用到多种机器人平台。
5 | 使用此适配器,可连接任何 OneBot 12 实现的机器人平台。 6 | 7 | ## 连接 onebot12 8 | 9 | | 参数名 | 类型 | 释义 | 默认值 | 10 | |-----------|-----|-----------------------|-----| 11 | | host | str | ob12 服务的 ip 地址 | | 12 | | ws_port | int | ob12 服务的 websocket 端口 | | 13 | | http_port | int | ob12 服务的 http 端口 | | 14 | 15 | ```python 16 | from amiyabot.adapters.onebot.v12 import onebot12 17 | 18 | appid = '******' # 机器人的账号(如需要) 19 | token = '******' # access-token 20 | 21 | adapter_service = onebot12('127.0.0.1', 8080, 8060) 22 | 23 | bot = AmiyaBot(appid=appid, token=token, adapter=adapter_service) 24 | ``` 25 | -------------------------------------------------------------------------------- /docs/develop/adapters/qqChannel.md: -------------------------------------------------------------------------------- 1 | # QQ 频道机器人 2 | 3 | 按照 [基础指南](/develop/basic/index.md) 创建的机器人即为 QQ 频道机器人,无需额外的适配器。 4 | 5 | ## 事件分片 6 | 7 | 考虑到开发者事件接收时可以实现负载均衡,QQ 8 | 提供了分片逻辑,事件通知会落在不同的分片上,可参考官方文档 [分片连接LoadBalance](https://bot.q.qq.com/wiki/develop/api-v2/dev-prepare/interface-framework/event-emit.html#%E5%88%86%E7%89%87%E8%BF%9E%E6%8E%A5loadbalance) 9 | 了解分片机制。 10 | 11 | 创建分片连接需要使用分片适配器 `qq_guild_shards` 12 | 13 | ```python 14 | from amiyabot.adapters.tencent.qqGuild import qq_guild_shards 15 | 16 | bot1 = AmiyaBot(appid='...', token='...', adapter=qq_guild_shards(0, 2)) 17 | bot2 = AmiyaBot(appid='...', token='...', adapter=qq_guild_shards(1, 2)) 18 | ``` 19 | 20 | ::: danger 注意
21 | 每个分片的启动应当**按顺序缓慢进行**,切勿同时启动,以免 gateway 返回的信息一致造成连接失败。 22 | 23 | ```python 24 | # 仅作示意,实际上每个分片应当是独立的服务。 25 | def start(): 26 | asyncio.create_task(bot1.start()) 27 | time.sleep(2) 28 | asyncio.create_task(bot2.start()) 29 | ``` 30 | 31 | ::: 32 | 33 | `qq_guild_shards` 参数 34 | 35 | | 参数名 | 类型 | 释义 | 默认值 | 36 | |-------------|-----|-------------|-----| 37 | | shard_index | int | 分片下标,从 0 开始 | | 38 | | shards | int | 分片总数 | | 39 | 40 | ## 沙箱环境 41 | 42 | 使用 `QQGuildSandboxBotInstance` 适配器将 API 调用更改为沙箱环境。沙箱环境只会收到测试频道的事件,且调用 openapi 仅能操作测试频道。 43 | 44 | ```python 45 | from amiyabot.adapters.tencent.qqGuild import QQGuildSandboxBotInstance 46 | 47 | bot = AmiyaBot(..., adapter=QQGuildSandboxBotInstance) 48 | ``` 49 | -------------------------------------------------------------------------------- /docs/develop/adapters/qqGlobal.md: -------------------------------------------------------------------------------- 1 | # QQ 全域机器人 Beta 2 | 3 | 全域机器人指同时支持群聊、消息记录和频道的机器人 4 | 5 | ## 创建全域适配器 6 | 7 | 全域适配器的参数和用法和[QQ 群机器人](/develop/adapters/qqGroup.html)一致,请参考文档。 8 | 9 | 创建后机器人能够同时接收到来自群聊、消息记录和频道的消息。 10 | 11 | ```python 12 | from amiyabot.adapters.tencent.qqGlobal import qq_global 13 | 14 | client_secret = '******' # 密钥 15 | 16 | bot = AmiyaBot(appid='******', token='******', adapter=qq_global(client_secret)) 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/develop/adapters/qqGroup.md: -------------------------------------------------------------------------------- 1 | # QQ 群机器人 Beta 2 | 3 | 在 [QQ 开放平台](https://bot.q.qq.com/wiki/#_2-%E4%BC%81%E4%B8%9A%E4%B8%BB%E4%BD%93%E5%85%A5%E9%A9%BB) 完成主体入驻,即可创建可在 4 | QQ 群聊里使用的 QQ 群机器人。 5 | 6 | ## 在公网下使用 7 | 8 | QQ 9 | 群聊适配器默认在本地启动资源服务让腾讯服务器能够访问媒体资源,需要在公网下使用。如果无法在公网下部署,请参考[自定义资源服务](#自定义资源服务)。 10 | 11 | ```python 12 | from amiyabot.adapters.tencent.qqGroup import qq_group 13 | 14 | client_secret = '******' # 密钥 15 | 16 | bot = AmiyaBot(appid='******', token='******', adapter=qq_group(client_secret)) 17 | ``` 18 | 19 | `qq_group` 参数 20 | 21 | | 参数名 | 类型 | 释义 | 默认值 | 22 | |-------------------------------|-----|-------------|------------------------------| 23 | | client_secret | str | 机器人密钥 | | 24 | | default_chain_builder | | 默认消息构建器 | None | 25 | | default_chain_builder_options | | 默认消息构建器参数 | QQGroupChainBuilderOptions() | 26 | | shard_index | int | 分片下标,从 0 开始 | 0 | 27 | | shards | int | 分片总数 | 1 | 28 | 29 | - 在机器人启动时,资源服务也会一同启动。 30 | - 默认的资源服务是端口单例的,实例化多个 QQ 群聊适配器 AmiyaBot 或使用 [多账号](/develop/basic/multipleAccounts.html) 31 | 时,同一个端口的资源服务会相互共享。 32 | 33 | ## 事件分片 34 | 35 | 考虑到开发者事件接收时可以实现负载均衡,QQ 36 | 提供了分片逻辑,事件通知会落在不同的分片上,可参考官方文档 [分片连接LoadBalance](https://bot.q.qq.com/wiki/develop/api-v2/dev-prepare/interface-framework/event-emit.html#%E5%88%86%E7%89%87%E8%BF%9E%E6%8E%A5loadbalance) 37 | 了解分片机制。 38 | 39 | ```python 40 | bot1 = AmiyaBot( 41 | appid='...', 42 | token='...', 43 | adapter=qq_group(client_secret='...', shard_index=0, shards=2), 44 | ) 45 | bot2 = AmiyaBot( 46 | appid='...', 47 | token='...', 48 | adapter=qq_group(client_secret='...', shard_index=1, shards=2), 49 | ) 50 | ``` 51 | 52 | ::: danger 注意
53 | 每个分片的启动应当**按顺序缓慢进行**,切勿同时启动,以免 gateway 返回的信息一致造成连接失败。 54 | 55 | ```python 56 | # 仅作示意,实际上每个分片应当是独立的服务。 57 | def start(): 58 | asyncio.create_task(bot1.start()) 59 | time.sleep(2) 60 | asyncio.create_task(bot2.start()) 61 | ``` 62 | 63 | ::: 64 | 65 | ### 修改资源服务配置 66 | 67 | 引入 `QQGroupChainBuilderOptions` 修改默认的资源服务配置。 68 | 69 | | 参数名 | 类型 | 释义 | 默认值 | 70 | |---------------------|------|--------------------------------------------------------|------------| 71 | | host | str | 资源服务监听地址 | 0.0.0.0 | 72 | | port | int | 资源服务监听端口 | 8086 | 73 | | resource_path | str | 临时文件存放目录 | ./resource | 74 | | http_server_options | dict | [HttpServer **kwargs](/develop/tools/httpSupport.html) | | 75 | 76 | ```python 77 | from amiyabot.adapters.tencent.qqGroup import qq_group 78 | from amiyabot.adapters.tencent.qqGroup.builder import QQGroupChainBuilderOptions 79 | 80 | bot = AmiyaBot( 81 | appid='******', 82 | token='******', 83 | adapter=qq_group( 84 | client_secret='******', 85 | default_chain_builder_options=QQGroupChainBuilderOptions( 86 | '0.0.0.0', 87 | 8086, 88 | './resource', 89 | ), 90 | ), 91 | ) 92 | ``` 93 | 94 | ## 自定义资源服务 95 | 96 | 非公网部署下的资源服务难题解决途径非常多,这里列举两个比较常见的解决办法。 97 | 98 | ### 使用内网穿透 99 | 100 | 使用一些内网穿透工具代理本地地址 http://127.0.0.1:8086(视配置而定)后,通常会得到一个新的地址。继承 `QQGroupChainBuilder` 101 | 并覆盖 **domain** 方法,即可使用内网穿透让腾讯服务器访问资源。 102 | 103 | 示例: 104 | 105 | > **http://3913rc56vl17.vicp.fun:40229/resource** 106 | 107 | 红色高亮部分即为内网穿透地址,`/resource` 为固定的路由值。 108 | 109 | ```python 110 | from amiyabot.adapters.tencent.qqGroup import qq_group, QQGroupChainBuilder, QQGroupChainBuilderOptions 111 | 112 | class PenetrationChainBuilder(QQGroupChainBuilder): 113 | @property 114 | def domain(self): 115 | return 'http://3913rc56vl17.vicp.fun:40229/resource' 116 | 117 | 118 | bot = AmiyaBot( 119 | ..., 120 | adapter=qq_group( 121 | ..., 122 | default_chain_builder=PenetrationChainBuilder( 123 | QQGroupChainBuilderOptions(), 124 | ), 125 | ), 126 | ) 127 | ``` 128 | 129 | ### 继承 ChainBuilder 并实现相关方法使用第三方托管服务。 130 | 131 | 多数情况下我们推荐使用第三方托管服务来搭建资源服务,如 [腾讯云COS](https://www.baidu.com/s?wd=%E8%85%BE%E8%AE%AF%E4%BA%91COS) 132 | 或 [阿里云OSS](https://www.baidu.com/s?wd=%E9%98%BF%E9%87%8C%E4%BA%91OSS) 等。通过自定义默认的 `ChainBuilder` 133 | ,来实现上传文件到托管服务以及返回生成的 url。 134 | 135 | 可参考 [进阶指南 - 介入媒体消息的构建过程](/develop/advanced/chainBuilder.md) 136 | 137 | ```python 138 | from typing import Union 139 | from graiax import silkcoder 140 | from amiyabot import ChainBuilder 141 | 142 | class ThirdPartyChainBuilder(ChainBuilder): 143 | @classmethod 144 | async def get_image(cls, image: Union[str, bytes]) -> Union[str, bytes]: 145 | # 上传图片到第三方托管服务 146 | ... 147 | return url # 返回访问资源的 URL 148 | 149 | @classmethod 150 | async def get_voice(cls, voice_file: str) -> str: 151 | # 上传语音文件到第三方托管服务,语音文件必须是 silk 格式 152 | voice: bytes = await silkcoder.async_encode(voice_file, ios_adaptive=True) 153 | ... 154 | return url # 返回访问资源的 URL 155 | 156 | @classmethod 157 | async def get_video(cls, video_file: str) -> str: 158 | # 上传视频文件到第三方托管服务 159 | ... 160 | return url # 返回访问资源的 URL 161 | 162 | 163 | bot = AmiyaBot( 164 | ..., 165 | adapter=qq_group( 166 | ..., 167 | default_chain_builder=ThirdPartyChainBuilder(), 168 | ), 169 | ) 170 | ``` 171 | -------------------------------------------------------------------------------- /docs/develop/advanced/blockingIO.md: -------------------------------------------------------------------------------- 1 | # 处理 IO 阻塞的操作 2 | 3 | AmiyaBot 为异步程序,一般情况下应该遵循异步编程来进行开发。但在使用一些标准或第三方库时,不能保证其方法是异步的,使用 IO 4 | 阻塞的方法容易造成线程阻塞,影响业务逻辑。 5 | 6 | ## run_in_thread_pool 7 | 8 | AmiyaBot `util` 库里提供的利用线程池将同步方法转变为异步方法执行的函数。 9 | 10 | | 参数名 | 类型 | 释义 | 默认值 | 11 | |------------|----------|----------|-----| 12 | | block_func | Callable | IO 阻塞的方法 | | 13 | | *args | | 原方法参数 | | 14 | | **kwargs | | 原方法字典参数 | | 15 | 16 | ```python 17 | from amiyabot.util import run_in_thread_pool 18 | 19 | # IO 阻塞的方法 20 | block_io_method(arg1, arg2, arg3='xxx') 21 | 22 | # 转变为异步执行 23 | await run_in_thread_pool(block_io_method, arg1, arg2, arg3='xxx') 24 | ``` 25 | -------------------------------------------------------------------------------- /docs/develop/advanced/chainBuilder.md: -------------------------------------------------------------------------------- 1 | # 介入 Chain 构建媒体消息时的操作 2 | 3 | Chain 对象在构建消息时,可使用辅助类介入媒体消息或浏览器的构建过程。 4 | 5 | ## 创建辅助类 6 | 7 | 继承 `ChainBuilder` 类并覆写其方法创建一个自定义的辅助类。在实例化 Chain 时,传入辅助类实例即可介入 Chain 的操作。 8 | 9 | ```python 10 | from typing import Union 11 | from amiyabot import Chain, ChainBuilder 12 | from playwright.async_api import Page 13 | 14 | class MyBuilder(ChainBuilder): 15 | @classmethod 16 | async def get_image(cls, image: Union[str, bytes]) -> Union[str, bytes]: 17 | ... 18 | return image 19 | 20 | @classmethod 21 | async def get_voice(cls, voice_file: str) -> str: 22 | ... 23 | return voice_file 24 | 25 | @classmethod 26 | async def get_video(cls, video_file: str) -> str: 27 | ... 28 | return video_file 29 | 30 | @classmethod 31 | async def on_page_rendered(cls, page: Page): 32 | ... 33 | 34 | 35 | # 在构造参数里使用辅助类 36 | chain = Chain(..., chain_builder=MyBuilder()) 37 | 38 | # 为属性赋值使用辅助类 39 | chain.builder = MyBuilder() 40 | ``` 41 | 42 | ## get_image 43 | 44 | 该函数会在 chain 构建图片消息时调用,每张图片调用一次。传入一个参数 `image` ,类型为 `str`(文件路径或 url) 或 45 | `bytes`(图片字节数据)。
46 | 如果函数有返回值(必须是以上两种类型),chain 会使用返回值构建图片消息。 47 | 48 | ## get_voice 49 | 50 | 该函数会在 chain 构建语音消息时调用,每个语音文件调用一次。传入文件路径 `voice_file`。
51 | 如果函数有返回值,chain 会使用返回值构建语音消息。 52 | 53 | ## get_video 54 | 55 | 该函数会在 chain 构建视频消息时调用,每个视频文件调用一次。传入文件路径 `video_file`。
56 | 如果函数有返回值,chain 会使用返回值构建视频消息。 57 | 58 | ## on_page_rendered 59 | 60 | 该函数会在 chain 构建浏览器渲染的图片并打开了页面时调用,提供了浏览器的 `Page` 对象,可在此对 `Page` 进行操作(如对页面进行 61 | JS 注入等)。 62 | 63 | ::: tip 提示 64 | 构建浏览器渲染的图片同样也会调用一次 `get_image` 函数。 65 | ::: 66 | 67 | **使用示例** 68 | 69 | ```python 70 | class BaiduSearch(ChainBuilder): 71 | @classmethod 72 | async def on_page_rendered(cls, page: Page): 73 | """ 74 | 可以在截图前先对页面进行操作,比如 ”百度一下“ 75 | """ 76 | await page.locator('#kw').fill('AmiyaBot') 77 | await page.locator('#su').click() 78 | await asyncio.sleep(2) 79 | 80 | 81 | @bot.on_message(keywords='hello') 82 | async def _(data: Message): 83 | chain = Chain(data, chain_builder=BaiduSearch()) 84 | 85 | return chain.html( 86 | 'https://www.baidu.com/', 87 | is_template=False, 88 | render_time=1000, 89 | ) 90 | ``` 91 | -------------------------------------------------------------------------------- /docs/develop/advanced/eventBus.md: -------------------------------------------------------------------------------- 1 | # 事件总线 2 | 3 | AmiyaBot 提供了简易的全局事件总线的方法 4 | 5 | ```python 6 | from amiyabot import event_bus 7 | ``` 8 | 9 | ## 发布事件 10 | 11 | **publish** 12 | 13 | | 参数名 | 类型 | 释义 | 默认值 | 14 | |------------|-----|------|------| 15 | | event_name | str | 事件名 | | 16 | | data | Any | 事件数据 | None | 17 | 18 | ```python 19 | event_bus.publish('myEvent', data=...) 20 | ``` 21 | 22 | ## 订阅事件 23 | 24 | **subscribe** 25 | 26 | | 参数名 | 类型 | 释义 | 默认值 | 27 | |------------|----------|----------|------| 28 | | event_name | str | 事件名 | | 29 | | method | Callable | 响应方法(可选) | None | 30 | 31 | ::: tip 提示
32 | 响应方法同时支持**异步**和**同步**函数 33 | ::: 34 | 35 | 通过装饰器订阅事件 36 | 37 | ```python 38 | @event_bus.subscribe('myEvent') 39 | async def event_handler(data): 40 | ... 41 | ``` 42 | 43 | 也可以通过传入响应函数订阅事件 44 | 45 | ```python 46 | async def event_handler(data): 47 | ... 48 | 49 | event_bus.subscribe('myEvent', event_handler) 50 | ``` 51 | 52 | ## 取消订阅 53 | 54 | 取消订阅需要传入**订阅时的响应方法对象**(且需要保证其内存地址是一致的) 55 | 56 | **unsubscribe** 57 | 58 | | 参数名 | 类型 | 释义 | 默认值 | 59 | |------------|----------|------|------| 60 | | event_name | str | 事件名 | | 61 | | method | Callable | 响应方法 | None | 62 | 63 | ```python 64 | event_bus.unsubscribe('myEvent', event_handler) 65 | ``` 66 | -------------------------------------------------------------------------------- /docs/develop/advanced/index.md: -------------------------------------------------------------------------------- 1 | # 进阶指南 2 | 3 | 本篇章将会深入讲解 AmiyaBot 的一些高级用法。包括如何控制日志、介入生命周期、创建定时任务、加载插件以及额外支持的数据库 ORM 和 4 | HTTP 服务等。这将有助于你构建一个复杂的,更有逻辑性的机器人。 5 | 6 | 和基础开发指南一样,在本章后续文档中,为了减少篇幅量,将不会再在代码示例中出现 AmiyaBot 类的实例化代码。统一以变量 `bot` 7 | 表示已经实例化的 AmiyaBot 类。 8 | -------------------------------------------------------------------------------- /docs/develop/advanced/lifeCycle.md: -------------------------------------------------------------------------------- 1 | # 生命周期 2 | 3 | AmiyaBot 接收的消息和事件,都会历经一个完整的生命周期。你可以介入这些周期来对业务进行进一步的调整。 4 | 5 | ## 消息生命周期 6 | 7 | 在接收消息到回复发送完毕,总共会经过至少五个周期,如下图所示,紫色的节点就是可以介入的周期。 8 | 9 | 如果消息响应里存在等待事件,那么周期将会延长,再次从消息接收开始,直至等待事件结束后继续向下执行。 10 | 11 | 12 | 13 | 通过 AmiyaBot 对象或 PluginInstance 对象注册周期钩子函数。 14 | 15 | > 所有钩子均可以同时存在多个,按加载顺序逐个调用。 16 | 17 | ### message_created 18 | 19 | 消息创建完毕阶段,可以在此阶段修改 Message 对象并返回。存在多个此钩子时,按加载顺序逐个调用,参数接受的 Message 20 | 对象受上一个函数的执行结果影响。 21 | 22 | 该钩子函数可返回三种结果: 23 | 24 | - **None**:对后续不产生影响 25 | - **Message**:修改 Message 对象,将影响后续所有周期进程的参数 26 | - **False**:布尔值仅可返回 False,将结束生命周期(包括此周期后续的钩子函数) 27 | 28 | ```python 29 | @bot.message_created 30 | async def _(data: Message, instance: BotAdapterProtocol): 31 | if ...: 32 | data.text = ... 33 | return data 34 | ``` 35 | 36 | ### message_before_waiter_set 37 | 38 | 当存在等待事件且消息分配器无返回或等待事件属于强制等待类型时,在进入等待事件前执行此钩子。 39 | 40 | ```python 41 | from amiyabot import Waiter 42 | 43 | @bot.message_before_waiter_set 44 | async def _(data: Message, waiter: Waiter, instance: BotAdapterProtocol): 45 | ... 46 | ``` 47 | 48 | ### message_before_handle 49 | 50 | 当消息分配器有返回,在执行消息响应器前执行此钩子。存在多个此钩子时,按加载顺序逐个调用。全部执行完成后当有其中一个返回 51 | False,则不往下继续执行并结束生命周期。 52 | 53 | ```python 54 | @bot.message_before_handle 55 | async def _(data: Message, factory_name: str, instance: BotAdapterProtocol): 56 | if ...: 57 | return False 58 | return True 59 | ``` 60 | 61 | ### message_before_send 62 | 63 | 当消息响应器执行完毕且存在返回时,在发送其返回前执行此钩子。可以在此阶段修改 Chain 对象并返回。存在多个此钩子时,按加载顺序逐个调用,参数接受的 64 | Chain 对象受上一个函数的执行结果影响。 65 | 66 | ```python 67 | @bot.message_before_send 68 | async def _(chain: Chain, factory_name: str, instance: BotAdapterProtocol): 69 | ... 70 | return chain 71 | ``` 72 | 73 | ### message_after_send 74 | 75 | 当消息响应器执行完毕且存在返回时,在发送其返回结束后执行此钩子。 76 | 77 | ```python 78 | @bot.message_after_send 79 | async def _(chain: Chain, factory_name: str, instance: BotAdapterProtocol): 80 | ... 81 | ``` 82 | 83 | ### message_after_handle 84 | 85 | 当消息响应器执行完毕(无论有没有返回)后执行此钩子。 86 | 87 | ```python 88 | @bot.message_after_handle 89 | async def _(chain: Optional[Chain], factory_name: str, instance: BotAdapterProtocol): 90 | ... 91 | ``` 92 | 93 | ## 事件生命周期 94 | 95 | 目前事件生命周期只有一个。 96 | 97 | ```python 98 | @bot.event_created 99 | async def _(event: EventType, instance: BotAdapterProtocol): 100 | ... 101 | ``` 102 | -------------------------------------------------------------------------------- /docs/develop/advanced/loadPlugins.md: -------------------------------------------------------------------------------- 1 | # 加载插件 2 | 3 | 本篇将会讲解 AmiyaBot 插件的工作原理以及插件导入和卸载的方法。 4 | 5 | ## 前言 6 | 7 | 插件设计的目的是因为 [兔兔-v6](https://github.com/AmiyaBot/Amiya-Bot) 8 | 通常会以可执行文件的形式发布,将一些功能模块分散为插件的形式,更有助于用户灵活的管理自己的机器人功能,以及对单独的功能进行热更新。 9 | 10 | AmiyaBot 的插件加载得益于 Python 作为脚本语言的一个优点:**动态执行代码**,配合标准库的 `importlib` 和 11 | `zipimport`,就能够很好的完成外部代码的导入与执行,理解这一原理,需要你熟悉 Python 12 | 的导入机制。而“动态执行代码”,如果你不是第一次接触脚本语言,想必你对其应有了一定的了解。 13 | 14 | ## 开发插件 15 | 16 | 开发插件可以参考主项目的 [插件开发](/develop/plugin/create) 形式,但本篇并不是作为主项目的引导文档。在主项目里,插件是一个 17 | zip 压缩包,在加载时解压并导入,完成代码的动态执行。 18 | 19 | 但在本框架的设计里,插件还能有另外几种导入方式。 20 | 21 | ## 导入插件实例 22 | 23 | 插件实例可以直接在你的程序里定义,这是正常的做法,事实上这对你的功能管理(如动态增加或软删除功能时)有很大帮助。 24 | 25 | ```python 26 | from amiyabot import AmiyaBot, PluginInstance 27 | 28 | plugin = PluginInstance( 29 | name='我的插件', 30 | version='1.0', 31 | plugin_id='my-plugin', 32 | description='我的第一个插件' 33 | ) 34 | 35 | @plugin.on_message(keywords='hello') 36 | async def _(data: Message): 37 | return Chain(data).text(f'hello, {data.nickname}') 38 | 39 | 40 | bot = AmiyaBot(...) # or MultipleAccounts 41 | bot.install_plugin(plugin) 42 | ``` 43 | 44 | 此时,该 AmiyaBot 实例便拥有了这个插件定义的所有消息响应、事件或定时任务等功能。 45 | 46 | ## 导入 Python 文件 47 | 48 | 这是写有插件注册代码的一个 Python 文件 `myPlugin.py` 49 | 50 | ```python 51 | from amiyabot import PluginInstance 52 | 53 | # bot 变量名是必须的,详见插件开发文档。 54 | bot = PluginInstance( 55 | name='我的插件', 56 | version='1.0', 57 | plugin_id='my-plugin', 58 | description='我的第一个插件' 59 | ) 60 | 61 | @bot.on_message(keywords='hello') 62 | async def _(data: Message): 63 | return Chain(data).text(f'hello, {data.nickname}') 64 | ``` 65 | 66 | 以 Python 文件导入这个插件 67 | 68 | ```python 69 | bot.install_plugin('myPlugin.py') # 相当于执行了代码:import myPlugin 70 | ``` 71 | 72 | 单文件插件是最简单的开发方式,这是在不考虑文件大小、静态资源或变量污染的前提下。 73 | 74 | ## 导入 Python Package 目录 75 | 76 | 如果一个插件的逻辑非常复杂,它可能会是以 Package 目录的形式存在。此时插件的目录应如下所示。 77 | 78 | ```text 79 | myPlugin 80 | ├── __init__.py 81 | ├── a.py 82 | ├── b.py 83 | │ ... 84 | ... 85 | ``` 86 | 87 | 以目录导入这个插件 88 | 89 | ```python 90 | bot.install_plugin('myPlugin') # 相当于执行了代码:import myPlugin 91 | ``` 92 | 93 | ## 导入 zip 压缩包 94 | 95 | 如果一些插件甚至带有静态资源,虽然 Package 目录同样能实现,但为了方便传播,它可能会是一个 zip 压缩文件。 96 | 97 | ```text 98 | myPlugin.zip 99 | ├── assetsFolder 100 | ├── config.yaml 101 | ├── __init__.py 102 | ├── a.py 103 | ├── b.py 104 | │ ... 105 | ... 106 | ``` 107 | 108 | 以 zip 导入这个插件 109 | 110 | ```python 111 | bot.install_plugin('myPlugin.zip') 112 | ``` 113 | 114 | 这里将会发生另一种情况,在 zip 导入时,并不是像上述两种方式一样相当于执行
`import myPlugin` 115 | 语句。而是通过标准库 `zipimport`,读取了此压缩包,并执行 `__init__.py`。 116 | 117 | 这有点抽象,你可以理解为使用了 python 命令执行了 `__init__.py` 118 | 119 | ```bash 120 | python __init__.py 121 | ``` 122 | 123 | 那么当 `__init__.py` 在相对导入其目录下的模块时,由于它属于顶级模块,插件将会 124 | 加载失败 125 | 并抛出如下异常。 126 | 127 | ```python 128 | from .main import bot 129 | ``` 130 | 131 | ```text 132 | plugin install error: Traceback (most recent call last): 133 | File "F:\Project\Amiya-Bot-core\amiyabot\log\manager.py", line 116, in sync_catch 134 | yield 135 | File "F:\Project\Amiya-Bot-core\amiyabot\handler\__init__.py", line 287, in install_plugin 136 | module = zipimport.zipimporter(plugin).load_module('__init__') 137 | File "", line 259, in load_module 138 | File "plugins\myPlugin.zip\__init__.py", line 1, in 139 | from .main import bot 140 | ImportError: attempted relative import with no known parent package 141 | ``` 142 | 143 | **install_plugin** 里提供了参数解决这一问题。先看看这个方法的参数列表。 144 | 145 | | 参数名 | 类型 | 释义 | 默认值 | 146 | |---------------------|---------------------|---------------------------------------|-------| 147 | | plugin | str, PluginInstance | 插件(文件、package 的路径或 PluginInstance 实例) | | 148 | | extract_plugin | bool | 是否解压插件 | False | 149 | | extract_plugin_dest | str | 插件解压后的目录名(默认为 zip 文件名) | | 150 | 151 | 解决上述问题,我们只需要添加参数 `extract_plugin=True`,将 zip 导入转换为 Package 目录导入。 152 | 153 | ```python 154 | bot.install_plugin('myPlugin.zip', extract_plugin=True) 155 | ``` 156 | 157 | ::: danger 注意
158 | 每次执行加载时都会解压一次全部文件,但如果路径已存在,将不会覆盖原文件。如果插件有一些原文件修改的更新,应注意这一特性。 159 | ::: 160 | 161 | ## 卸载插件 162 | 163 | 插件实例都有一个唯一 ID(属性 plugin_id),通过这个 ID 可以卸载指定的插件。 164 | 165 | **uninstall_plugin** 166 | 167 | | 参数名 | 类型 | 释义 | 默认值 | 168 | |-----------|------|------------|-------| 169 | | plugin_id | str | 插件 ID | | 170 | | remove | bool | 是否删除插件的原文件 | False | 171 | 172 | ```python 173 | bot.uninstall_plugin('my-plugin') 174 | ``` 175 | -------------------------------------------------------------------------------- /docs/develop/advanced/logger.md: -------------------------------------------------------------------------------- 1 | # 日志模块 2 | 3 | AmiyaBot 使用 logging 模块构建日志体系。 4 | 5 | ## 输出日志 6 | 7 | AmiyaBot 的日志同样拥有与 logging 相同的等级输出。输出的日志会储存在 `log` 文件夹下。 8 | 9 | ```python 10 | from amiyabot import log 11 | 12 | log.info(...) 13 | log.error(...) 14 | log.debug(...) 15 | log.warning(...) 16 | log.critical(...) 17 | ``` 18 | 19 | 日志的固有格式如下所示,分别为`时间`、`日志模块名`、`日志等级`和`日志内容`。DEBUG 模式下会显示日志的输出文件名和位置。 20 | 21 | ``` 22 | normal: 23 | 2022-11-02 18:22:40,425 [ Bot][ INFO] initialize completed. 24 | 25 | debug mode: 26 | 2022-11-02 18:22:40,425 [ Bot][ INFO][test.py:5] initialize completed. 27 | ``` 28 | 29 | ::: tip 提示
30 | 使用启动参数 `--debug` 开启 DEBUG 模式。 31 | ::: 32 | 33 | ## 输出异常日志 34 | 35 | `log.error()` 方法不仅可以传入字符串,也支持传入 Exception 的子类。传入 Exception 子类时,将会输出完整的异常追踪(Traceback)。 36 | 37 | ```python {5} 38 | try: 39 | a = 0 40 | a += '1' 41 | except Exception as e: 42 | log.error(e, desc='calc error:') 43 | ``` 44 | 45 | 将输出如下日志 46 | 47 | ``` 48 | 2022-11-02 18:44:22,155 [ Bot][ ERROR] calc error: Traceback (most recent call last): 49 | File "F:\Project\Amiya-Bot-core\logTest.py", line 5, in 50 | a += '1' 51 | TypeError: unsupported operand type(s) for +=: 'int' and 'str' 52 | ``` 53 | 54 | 如果你并不需要处理异常,仅仅希望异常不会终止你的程序,log 模块提供了上下文管理的方式,来捕获并输出在上下文中产出的异常。 55 | 56 | | 参数名 | 类型 | 释义 | 默认值 | 57 | |---------|-----------------------|--------------|------| 58 | | desc | str | 异常标题 | | 59 | | ignore | List[Type[Exception]] | 仅捕获但不输出的异常列表 | None | 60 | | handler | Callable | 捕获异常后执行的方法 | None | 61 | 62 | ```python 63 | async def err_handler(err: Exception): 64 | print(err) 65 | 66 | # 异步方式 67 | async with log.catch('calc error:', ignore=[TypeError, ...], handler=err_handler): 68 | a = 0 69 | a += '1' 70 | 71 | # 同步方式 72 | with log.sync_catch(...): 73 | a = 0 74 | a += '1' 75 | ``` 76 | 77 | ## 创建日志模块 78 | 79 | 你可以创建一个独立的日志模块以标记输出。 80 | 81 | ```python 82 | from amiyabot.log import LoggerManager 83 | 84 | logger = LoggerManager('MyLogger') 85 | logger.info('this is a log.') 86 | 87 | # 2022-11-02 18:32:05,053 [MyLogger][ INFO] this is a log. 88 | ``` 89 | 90 | **LoggerManager** 91 | 92 | | 参数名 | 类型 | 释义 | 默认值 | 93 | |---------------|-----|-------------|------------------------------------------------------| 94 | | name | str | logger 模块名称 | | 95 | | level | int | 日志等级 | logging.INFO | 96 | | formatter | str | 日志格式 | `%(asctime)s [%(name)8s][%(levelname)8s]%(message)s` | 97 | | save_path | str | 日志文件保存目录 | log | 98 | | save_filename | str | 日志文件名 | running | 99 | 100 | ## 自定义全局日志模块 101 | 102 | 如果你不喜欢默认的日志输出,你也可以全局修改日志模块。但必须注意的事,你自定义的模块,必须包含常规的几个等级输出方法。 103 | 104 | ```python 105 | from amiyabot.log import UserLogger 106 | 107 | 108 | class Mylogger: 109 | def info(self, text: str): ... 110 | 111 | def error(self, text: str): ... 112 | 113 | def debug(self, text: str): ... 114 | 115 | def warning(self, text: str): ... 116 | 117 | def critical(self, text: str): ... 118 | 119 | 120 | UserLogger.logger = Mylogger() # 将默认日志处理替换为自定义的类 121 | ``` 122 | -------------------------------------------------------------------------------- /docs/develop/advanced/playwright.md: -------------------------------------------------------------------------------- 1 | # 改变 Playwright 启动 2 | 3 | 改变默认的 Playwright 启动行为。 4 | 5 | ```python 6 | from playwright.async_api import Playwright, Browser 7 | from amiyabot import BrowserLaunchConfig 8 | 9 | 10 | class MyBrowserLauncher(BrowserLaunchConfig): 11 | def __init__(self): 12 | super().__init__() 13 | 14 | self.browser_type = 'firefox' # 修改浏览器属性 15 | 16 | # 或改写 launch_browser 方法 17 | async def launch_browser(self, playwright: Playwright) -> Browser: 18 | ... 19 | 20 | # 返回通过任意方式创建的 Browser 对象 21 | # return await playwright.webkit.launch() 22 | # return await playwright.chromium.launch() 23 | return await playwright.firefox.launch() 24 | 25 | 26 | bot = AmiyaBot() 27 | asyncio.run( 28 | bot.start(launch_browser=MyBrowserLauncher()) 29 | ) 30 | ``` 31 | -------------------------------------------------------------------------------- /docs/develop/advanced/startupParameter.md: -------------------------------------------------------------------------------- 1 | # 启动参数 2 | 3 | 使用启动参数修改一些内置变量 4 | 5 | | 参数 | 是否需要值 | 默认值 | 释义 | 6 | |--------------------------|-------|------|-------------------------| 7 | | --debug | 否 | | 以 DEBUG 模式启动程序 | 8 | | --browser-width | 是 | 1280 | 浏览器视窗默认宽度(px) | 9 | | --browser-height | 是 | 720 | 浏览器视窗默认高度(px) | 10 | | --browser-render-time | 是 | 200 | 浏览器默认渲染时间(ms) | 11 | | --text-max-length | 是 | 100 | Chain 对象转换文字图片的文字长度最大值 | 12 | | --browser-page-not-close | 否 | | 取消自动关闭 playwright 的网页窗口 | 13 | 14 | ## 在 兔兔-v6 下使用 15 | 16 | 代码部署 17 | 18 | ```bash 19 | python amiya.py --text-max-length 200 --browser-render-time 1000 20 | ``` 21 | 22 | 可执行文件部署 23 | 24 | ```bash 25 | AmiyaBot-v6.x.x-master.exe --debug --browser-page-not-close 26 | ``` 27 | -------------------------------------------------------------------------------- /docs/develop/advanced/timedTask.md: -------------------------------------------------------------------------------- 1 | # 定时任务 2 | 3 | AmiyaBot 提供了全局定时任务管理器,基于 [apscheduler](https://github.com/agronholm/apscheduler)。 4 | 5 | ::: warning ⚠️注意⚠️不兼容的更新
6 | 在版本 1.6.9 开始,不再支持全局定义定时任务,以及移除了 custom 参数,使用更泛用的 apscheduler trigger 控制任务执行时机。 7 | 8 | 此方法已不再支持,全局变量 tasks_control 已删除。 9 | 10 | ```python 11 | from amiyabot import AmiyaBot, tasks_control 12 | 13 | @tasks_control.timed_task(each=120) 14 | async def _(): 15 | ... 16 | ``` 17 | 18 | bot.timed_task 装饰器的 custom 参数已删除。 19 | 20 | | 参数名 | 类型 | 释义 | 默认值 | 21 | |------------|--------------|----------------|-------------| 22 | | each | int | 循环执行间隔时间,单位(秒) | | 23 | | ~~custom~~ | ~~Callable~~ | ~~自定义循环规则~~ | | 24 | | sub_tag | str | 子标签 | default_tag | 25 | 26 | ::: 27 | 28 | ## 简单使用 29 | 30 | ```python 31 | from amiyabot import AmiyaBot 32 | from amiyabot.factory import BotHandlerFactory 33 | 34 | bot = AmiyaBot(...) # 或 MultipleAccounts / PluginInstance 对象 35 | 36 | # 每 60 秒执行一次任务 37 | @bot.timed_task(each=60) 38 | async def _(instance: BotHandlerFactory): 39 | ... 40 | ``` 41 | 42 | ## 插件开发 43 | 44 | 如果你正在开发插件,并且你不希望在插件的卸载方法里手动取消定时任务,请务必通过 `PluginInstance.timed_task` 定义任务。 45 | 46 | 通过 `PluginInstance.timed_task` 定义的任务可以在插件被卸载时自动取消。 47 | 48 | ```python 49 | from amiyabot import PluginInstance 50 | from amiyabot.factory import BotHandlerFactory 51 | 52 | bot = PluginInstance(...) 53 | 54 | @bot.timed_task(each=60) 55 | async def _(instance: BotHandlerFactory): 56 | ... 57 | ``` 58 | 59 | 插件开发详情请查看 [插件开发文档](/develop/plugin/)。 60 | 61 | ## timed_task 装饰器 62 | 63 | | 参数名 | 类型 | 释义 | 默认值 | 64 | |----------------|------|---------------------------------------------------------------------------------------------------------------|-------------| 65 | | each | int | 循环执行间隔时间,单位(秒),如果使用其他触发方式,请使用 kwargs 形式的 scheduler.add_job 参数 | None | 66 | | sub_tag | str | 子标签 | default_tag | 67 | | run_when_added | bool | 添加时立即执行一次任务 | default_tag | 68 | | **kwargs | | [scheduler.add_job](https://github.com/agronholm/apscheduler/blob/3.x/apscheduler/schedulers/base.py#L384) 参数 | | 69 | 70 | ::: danger 注意
71 | 使用 kwargs 自定义定时任务时,不可使用参数 `func` 以及 `id`。 72 | ::: 73 | 74 | ### 自定义执行时机 75 | 76 | 使用 `scheduler.add_job` 参数定义任务,可以使任务的执行时机更加灵活。 77 | 78 | ```python 79 | from amiyabot import PluginInstance 80 | from amiyabot.factory import BotHandlerFactory 81 | from apscheduler.triggers.cron import CronTrigger 82 | 83 | bot = PluginInstance(...) 84 | 85 | # 每个小时中的 5 分 30 秒时执行 86 | @bot.timed_task(trigger='cron', minute=5, second=30) 87 | async def _(instance: BotHandlerFactory): 88 | ... 89 | 90 | # 每分钟的第 20 秒和 40 秒时执行 91 | @bot.timed_task(trigger=CronTrigger('20,40')) 92 | async def _(instance: BotHandlerFactory): 93 | ... 94 | ``` 95 | 96 | ## 取消定时任务 97 | 98 | 为需要取消的定时任务传入 sub_tag 参数,可以重复,重复的 sub_tag 会被整合为一组。 99 | 100 | ### bot.remove_timed_task() 101 | 102 | 按标签名取消定时任务 103 | 104 | | 参数名 | 类型 | 释义 | 默认值 | 105 | |---------|-----|----------------|-----| 106 | | sub_tag | str | 需要取消的定时任务的子标签名 | | 107 | 108 | 示例:执行一次后取消任务 109 | 110 | ```python 111 | from amiyabot import PluginInstance 112 | from amiyabot.factory import BotHandlerFactory 113 | 114 | bot = PluginInstance(...) 115 | 116 | @bot.timed_task(each=60, sub_tag='test') 117 | async def _(instance: BotHandlerFactory): 118 | ... 119 | bot.remove_timed_task('test') 120 | ``` 121 | -------------------------------------------------------------------------------- /docs/develop/basic/api/index.md: -------------------------------------------------------------------------------- 1 | # API 2 | 3 | API 是实现适配器部分基础逻辑的基础,你也可以调用 API 来进一步完成你的业务逻辑。 4 | 5 | `api` 属性位于 `AmiyaBot` 的 `instance` 属性下。 6 | 7 | ```python {3} 8 | bot = AmiyaBot(...) 9 | 10 | await bot.instance.api.get_me() 11 | ``` 12 | 13 | ::: danger 请注意
14 | 不用的适配器下,api 的方法不尽相同,在创作多平台机器人时,请注意可能产生的影响。 15 | ::: 16 | 17 | ## 引入 API 类以注解变量 18 | 19 | 我们强烈建议在使用不同的适配器时,引入相应的 API 类注解 api 属性。它们通常在适配器模块的 `api` 模块下。 20 | 21 | ```python 22 | from amiyabot.adapters.tencent.qqGuild.api import QQGuildAPI 23 | # from amiyabot.adapters.cqhttp.api import CQHttpAPI 24 | # from amiyabot.adapters.kook.api import KOOKAPI 25 | 26 | 27 | api: QQGuildAPI = bot.instance.api 28 | await api.get_me() 29 | ``` 30 | 31 | ## 共同的方法 32 | 33 | api 实际上是调用了不同平台提供的接口。在不同平台下,调用接口的鉴权规则也不一样。所有适配器的 api 34 | 都存在以下三个方法,参数也是一样的。方法内部实现了不同平台的鉴权规则,你只需要直接调用接口即可。 35 | 36 | ### get 37 | 38 | | 参数名 | 类型 | 释义 | 默认值 | 39 | |----------|-------------------|--------------------------------------------------------------------------------------|-----| 40 | | url | str | 接口 url | | 41 | | params | Union[dict, None] | get 参数 | | 42 | | **kwargs | | [request 参数](https://github.com/aio-libs/aiohttp/blob/master/aiohttp/client.py#L316) | | 43 | 44 | ### post 45 | 46 | | 参数名 | 类型 | 释义 | 默认值 | 47 | |--------------|-------------------|--------------------------------------------------------------------------------------|-----| 48 | | url | str | 接口 url | | 49 | | payload | Union[dict, None] | post 参数 | | 50 | | is_form_data | bool | 是否使用 form 表单提交(仅 QQ 频道拥有此参数) | | 51 | | **kwargs | | [request 参数](https://github.com/aio-libs/aiohttp/blob/master/aiohttp/client.py#L316) | | 52 | 53 | ### request 54 | 55 | 可以使用除 get、post 以外的一些 method 调用接口。 56 | 57 | | 参数名 | 类型 | 释义 | 默认值 | 58 | |----------|-------------------|--------------------------------------------------------------------------------------|-----| 59 | | url | str | 接口 url | | 60 | | method | str | 请求 method | | 61 | | payload | Union[dict, None] | 请求参数 | | 62 | | **kwargs | | [request 参数](https://github.com/aio-libs/aiohttp/blob/master/aiohttp/client.py#L316) | | 63 | 64 | ```python 65 | res = await bot.instance.api.post('/interface', {...}) 66 | ``` 67 | 68 | ::: tip 为什么没有 headers 参数
69 | 方法内部实现了不同平台的鉴权规则,控制了 headers 70 | 的内容,你不需要手动控制。如果你希望自己实现请求,请使用 👉 [进阶指南 - HTTP 请求](/develop/tools/httpRequests) 71 | ::: 72 | 73 | ## api 的返回 74 | 75 | 参考 [进阶指南 - HTTP 请求 - 返回值](/develop/tools/httpRequests.html#返回值) 76 | -------------------------------------------------------------------------------- /docs/develop/basic/chainBuild/ark.md: -------------------------------------------------------------------------------- 1 | # Ark 消息 2 | 3 | 发送 QQ 频道 ARK 4 | 模板消息,详情请查看[发送 ark 消息](https://bot.q.qq.com/wiki/develop/api/openapi/message/post_ark_messages.html)。 5 | 6 | ## Chain().ark() 7 | 8 | | 参数名 | 类型 | 释义 | 默认值 | 9 | |-------------|------------|-----------------|-----| 10 | | template_id | str | 模版 ID | | 11 | | kv | List[dict] | 模版 key-value 数据 | | 12 | 13 | ```python 14 | kv_data = [ 15 | {'key': '#PROMPT#', 'value': '通知提醒'}, 16 | {'key': '#METATITLE#', 'value': '标题'}, 17 | {'key': '#METASUBTITLE#', 'value': '子标题'}, 18 | {'key': '#METACOVER#', 'value': 'https://vfiles.gtimg.cn/vupload/20211029/bf0ed01635493790634.jpg'}, 19 | {'key': '#METAURL#', 'value': 'https://qq.com'}, 20 | ] 21 | 22 | Chain(data, at=False).ark(37, kv_data) 23 | ``` 24 | 25 | ![](https://mpqq.gtimg.cn/bot-wiki/online/assets/img/37.2955062b.png) 26 | -------------------------------------------------------------------------------- /docs/develop/basic/chainBuild/at.md: -------------------------------------------------------------------------------- 1 | # At 2 | 3 | 发送 `@XXX` 4 | 5 | ## Chain().at() 6 | 7 | ::: tip 提示
8 | 私信回复里无效 9 | ::: 10 | 11 | | 参数名 | 类型 | 释义 | 默认值 | 12 | |-------|----------|---------------------------|-------| 13 | | user | int, str | @ 的用户ID,默认为 Message 对象的用户 | | 14 | | enter | bool | 是否 @ 用户后换行 | False | 15 | 16 | ```python 17 | Chain(data).at(12345678).text('hello, world') 18 | ``` 19 | 20 | Chain 对象在实例化的时候,默认会在消息体头部添加 `@XXX`。 21 | -------------------------------------------------------------------------------- /docs/develop/basic/chainBuild/atAll.md: -------------------------------------------------------------------------------- 1 | # At 所有人 2 | 3 | 发送 `@所有人`,需要机器人拥有发送 `@所有人` 消息的权限 4 | 5 | ## Chain().at_all() 6 | 7 | ::: tip 提示
8 | 私信回复里无效 9 | ::: 10 | 11 | ```python 12 | Chain(data).at_all() 13 | ``` 14 | -------------------------------------------------------------------------------- /docs/develop/basic/chainBuild/embed.md: -------------------------------------------------------------------------------- 1 | # Embed 消息 2 | 3 | 发送 QQ 4 | 频道卡片消息,详情请查看 [embed 消息](https://bot.q.qq.com/wiki/develop/api/openapi/message/template/embed_message.html) 5 | 6 | ## Chain().embed() 7 | 8 | | 参数名 | 类型 | 释义 | 默认值 | 9 | |-----------|-----------|------------|-----| 10 | | title | str | 标题 | | 11 | | prompt | str | 消息弹窗内容 | | 12 | | thumbnail | str | 缩略图 url | | 13 | | fields | List[str] | embed 字段数据 | | 14 | 15 | ```python 16 | Chain(data, at=False).embed( 17 | '标题', 18 | '消息通知', 19 | 'xxxxxx', 20 | ['当前等级:黄金', '之前等级:白银', '😁继续努力'], 21 | ) 22 | ``` 23 | 24 | ![](https://mpqq.gtimg.cn/bot-wiki/online/assets/img/embed.18d8bc6d.jpg) 25 | -------------------------------------------------------------------------------- /docs/develop/basic/chainBuild/extend.md: -------------------------------------------------------------------------------- 1 | # 原生模板 2 | 3 | 使用原生消息模板扩展 Chain 对象 4 | 5 | ::: warning 温馨提示
6 | 消息扩展暂仅支持 `mirai-api-http` 和 `cq-http`。 7 | ::: 8 | 9 | 除了以上内置的消息类型外,`mirai-api-http` 和 `cq-http` 还提供了多种消息类型用于发送丰富的消息内容。 10 | 11 | - [mirai-api-http 消息类型](https://docs.mirai.mamoe.net/mirai-api-http/api/MessageType.html#%E6%B6%88%E6%81%AF%E7%B1%BB%E5%9E%8B) 12 | - [go-cqhttp 消息类型](https://docs.go-cqhttp.org/cqcode/#%E6%B6%88%E6%81%AF%E7%B1%BB%E5%9E%8B) 13 | 14 | ## Chain().extend() 15 | 16 | | 参数名 | 类型 | 释义 | 默认值 | 17 | |------|-----|------------|-----| 18 | | data | Any | 原始消息类型格式数据 | | 19 | 20 | ### 示例 21 | 22 | 使用 [mirai-api-http 消息类型 Dice](https://docs.mirai.mamoe.net/mirai-api-http/api/MessageType.html#dice) 发送一个点数 23 | 6 的骰子魔法表情 24 | 25 | ```python 26 | Chain(data).extend( 27 | { 28 | 'type': 'Dice', 29 | 'value': 6 30 | } 31 | ) 32 | ``` 33 | 34 | 使用 [go-cqhttp 消息类型 链接分享](https://docs.go-cqhttp.org/cqcode/#%E9%93%BE%E6%8E%A5%E5%88%86%E4%BA%AB) 发送一个百度首页链接分享 35 | 36 | ```python 37 | Chain(data).extend( 38 | { 39 | 'type': 'share', 40 | 'data': { 41 | 'url': 'https://www.baidu.com', 42 | 'title': '百度' 43 | } 44 | } 45 | ) 46 | ``` 47 | 48 | ## 发送 CQ 码 49 | 50 | 发送 CQ 码目前仅支持 `cq-http` 适配器。可通过适配器的 API 对象发送或扩展消息发送。 51 | 52 | ```python 53 | from amiyabot import CQCode, CQHttpBotInstance 54 | 55 | instance: CQHttpBotInstance = bot.instance 56 | 57 | 58 | @bot.on_message(keywords='hello') 59 | async def _(data: Message): 60 | # 通过 API 发送 61 | instance.api.send_cq_code(data.user_id, 62 | data.channel_id, 63 | f'hello, {data.nickname} [CQ:face,id=123]') 64 | 65 | # 通过扩展消息发送 66 | return Chain(data).extend( 67 | CQCode(f'hello, {data.nickname} [CQ:face,id=123]') 68 | ) 69 | ``` 70 | -------------------------------------------------------------------------------- /docs/develop/basic/chainBuild/face.md: -------------------------------------------------------------------------------- 1 | # emoji 表情 2 | 3 | 仅限 QQ 内置的小黄人表情 4 | 5 | ## Chain().face() 6 | 7 | | 参数名 | 类型 | 释义 | 默认值 | 8 | |---------|----------|------|-----| 9 | | face_id | int, str | 表情ID | | 10 | 11 | ```python 12 | Chain(data).face(175) 13 | ``` 14 | -------------------------------------------------------------------------------- /docs/develop/basic/chainBuild/forward.md: -------------------------------------------------------------------------------- 1 | # 合并转发消息 Beta 2 | 3 | 合并转发消息不是 Chain 对象的方法,需要使用适配器提供的工具类构建。 4 | 5 | ::: danger 注意
6 | QQ 频道机器人暂时不支持发送合并转发消息,目前仅支持 `mirai-api-http` 和 `cq-http`。 7 | ::: 8 | 9 | ```python 10 | from amiyabot.adapters.mirai import MiraiForwardMessage 11 | # from amiyabot.adapters.cqhttp import CQHTTPForwardMessage 12 | 13 | ... 14 | 15 | @bot.on_message(keywords='hello') 16 | async def _(data: Message): 17 | forward = MiraiForwardMessage(data) 18 | # forward = CQHTTPForwardMessage(data) 19 | 20 | chain = Chain().text(f'hello, {data.nickname}') 21 | 22 | await forward.add_message(chain, user_id=..., nickname='...') 23 | await forward.send() 24 | ``` 25 | 26 | ## 添加自定义消息 27 | 28 | **add_message** 29 | 30 | | 参数名 | 类型 | 释义 | 默认值 | 31 | |----------|-------------|---------------------------------------------------------------|-----| 32 | | chain | Chain, list | Chain 对象,可为[空 Chain](/develop/basic/sendMessage.html#空-chain) | | 33 | | user_id | int | 用户 ID | | 34 | | nickname | str | 用户昵称(可自定义) | | 35 | | time | int | 发送时间 | 0 | 36 | 37 | - `user_id` 为实际 QQ 用户的 QQ 号,可以是任意人,在合并消息内显示其头像。 38 | - `nickname` 为自定义的昵称。 39 | 40 | 如果 `chain` 参数传入了空 Chain,则 `user_id` 和 `nickname` 为必须参数。 41 | 42 | ```python 43 | await forward.add_message(Chain(data).text(...)) 44 | await forward.add_message(Chain().text(...), user_id=..., nickname='...') 45 | ``` 46 | 47 | ## 添加指定 ID 的消息 48 | 49 | **add_message_by_id** 50 | 51 | | 参数名 | 类型 | 释义 | 默认值 | 52 | |------------|-----|-------|-----| 53 | | message_id | int | 消息 ID | | 54 | 55 | ```python 56 | await forward.add_message_by_id(5128) 57 | ``` 58 | 59 | ## 添加嵌套的合并转发消息 60 | 61 | 为 `add_message` 的 `chain` 参数传入 ForwardMessage 类的 `node` 属性,即可完成合并消息嵌套。 62 | 63 | ```python {8,10} 64 | @bot.on_message(keywords='hello') 65 | async def _(data: Message): 66 | forward = MiraiForwardMessage(data) 67 | 68 | await forward.add_message(...) 69 | await forward.add_message(...) 70 | 71 | forward2 = MiraiForwardMessage(data) 72 | 73 | await forward2.add_message(forward.node, user_id=..., nickname='...') 74 | await forward2.send() 75 | ``` 76 | 77 | ## 发送 & 撤回 78 | 79 | ```python 80 | callback = await forward.send() # 发送 81 | if callback: 82 | await callback.recall() # 撤回 83 | ``` 84 | -------------------------------------------------------------------------------- /docs/develop/basic/chainBuild/html.md: -------------------------------------------------------------------------------- 1 | # HTML 生成的图片 2 | 3 | 发送一张使用 html 页面生成的图片,在同等工作量下,它通常比使用 PIL 合成的图片更加生动,技术难度也比 PIL 要低得多。 4 | 5 | ::: danger 操作系统支持
6 | 7 | HTML制图需要使用 playwright 模块,所以仅支持以下操作系统: 8 | 9 | - Windows 10、Windows Subsystem for Linux (WSL) 或 Windows Server 2012 及以上系统 10 | - MacOS 11 (Big Sur) 及以上系统 11 | - Linux 系统官方支持 Debian 11、Ubuntu 18.04 以及 Ubuntu 20.04 12 | 13 | ::: 14 | 15 | ## 安装 Chromium 16 | 17 | 命令行执行以下命令安装 Chromium 内核: 18 | 19 | ```bash 20 | # Windows or MacOS 21 | playwright install chromium 22 | # Linux 23 | playwright install --with-deps chromium 24 | ``` 25 | 26 | ## 启动时打开 Chromium 27 | 28 | 在 bot(包括[多账号实例](/develop/basic/multipleAccounts.html#创建一个多账号实例))启动的 start 29 | 方法内设置参数 `launch_browser=True` 30 | 31 | ```python 32 | bot.start(launch_browser=True) 33 | ``` 34 | 35 | 进阶使用:[改变默认的 Playwright 启动行为](/develop/advanced/playwright) 36 | 37 | ## Chain().html() 38 | 39 | | 参数名 | 类型 | 释义 | 默认值 | 40 | |-------------|------|--------------------------|------| 41 | | path | str | 模板文件路径或网站URL | | 42 | | data | Any | 传入模板文件的数据(数据可被 json 序列化) | | 43 | | width | int | 浏览器视窗宽度 | 1280 | 44 | | height | int | 浏览器视窗高度 | 720 | 45 | | is_template | bool | 是否为模板文件 | True | 46 | | render_time | int | 渲染时间(毫秒) | 200 | 47 | 48 | ```python 49 | Chain(data).html('template.html', {...}) 50 | ``` 51 | 52 | ## **创建html模板文件** 53 | 54 | 创建文件 hello.html 并定义全局的 init 方法。 55 | 56 | ```html 57 | 58 |
59 | 60 | 66 | ``` 67 | 68 | 将需要渲染的数据传入模板: 69 | 70 | ```python 71 | @bot.on_message(keywords='hello') 72 | async def _(data: Message): 73 | return Chain(data).html('hello.html', {'username': data.nickname}) 74 | ``` 75 | 76 | 示例在触发会话并开始发送消息时,Chain 对象将会调用 Chromium 无头浏览器,渲染 `hello.html` 并在页面内执行 JavaScript 77 | 语句 `init({'username': 'vivien8261'})`。
78 | 渲染结束后,无头浏览器截图生成图片,然后执行常规的图片发送方法。 79 | 80 | image 81 | 82 | _发挥你的想象,写出更美观的页面!_ 83 | 84 | ::: details 兔兔-v6 效果
85 | image 86 | ::: 87 | 88 | ## **通过网站URL制图** 89 | 90 | 支持直接使用网站URL生成图片。 91 | 92 | ::: danger 注意
93 | 在页面加载完毕后,默认预留200ms的渲染时间。如果页面有部分元素是异步渲染的,将有可能不显示在图片内。可通过参数 `render_time` 94 | 设置需要的时间。 95 | ::: 96 | 97 | 设置参数 `is_template=False` 98 | 99 | ```python 100 | @bot.on_message(keywords='hello') 101 | async def _(data: Message): 102 | return Chain(data).html('https://www.baidu.com/', 103 | is_template=False, 104 | render_time=1000) 105 | ``` 106 | 107 | 触发会话时,渲染 `https://www.baidu.com/` 页面,并在等待 `1000ms` 后截图发送图片。 108 | -------------------------------------------------------------------------------- /docs/develop/basic/chainBuild/image.md: -------------------------------------------------------------------------------- 1 | # 图片 2 | 3 | 发送一张图片 4 | 5 | ## Chain().image() 6 | 7 | | 参数名 | 类型 | 释义 | 默认值 | 8 | |--------|------------|-----------------|-----| 9 | | target | str, bytes | 图片文件路径或图片 bytes | | 10 | | url | str | 网络图片的URL | | 11 | 12 | ```python 13 | Chain(data).image(target) 14 | ``` 15 | 16 | 当传入的类型为字符串时,image 方法会认为值为本地图片的路径并尝试读取文件。也可以直接传入 bytes 类型。
17 | 如果是网络图片,可以使用 url 参数传入。 18 | 19 | ```python 20 | Chain(data).image(url=target) 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/develop/basic/chainBuild/markdown.md: -------------------------------------------------------------------------------- 1 | # Markdown 生成的图片 2 | 3 | 添加一张由 Markdown 文本渲染的图片,直接传入 md 格式的文本,使用 HTML 4 | 模式渲染。建议先阅读 [发送 html 生成的图片](/develop/basic/chainBuild/html.md) 了解如何启动 Chromium。 5 | 6 | ::: danger 注意
7 | 这并非 QQ 8 | 机器人官方提供的 [发送 markdown 消息](https://bot.q.qq.com/wiki/develop/api/openapi/message/post_markdown_messages.html) 9 | ,要发送官方的 Markdown 模版消息请查看 [Markdown 模版](/develop/basic/chainBuild/mdTemplate.md)。 10 | ::: 11 | 12 | ## Chain().markdown() 13 | 14 | | 参数名 | 类型 | 释义 | 默认值 | 15 | |-------------|------|-------------|-------| 16 | | content | str | markdown 文本 | | 17 | | render_time | int | 渲染时间(毫秒) | 200 | 18 | | is_dark | bool | 是否使用暗黑样式 | False | 19 | 20 | ```python 21 | Chain(data).markdown(text) 22 | ``` 23 | 24 | ::: warning 提示
25 | 文本量大时,渲染将会耗费较长时间,默认预留200ms的渲染时间。可通过参数 `render_time` 设置需要的时间。 26 | ::: 27 | 28 | ## 更换渲染 Markdown 的 HTML 文件 29 | 30 | 更改全局配置可以使用自己的 HTML 文件渲染 Markdown 31 | 32 | ```python 33 | from amiyabot.builtin.messageChain import ChainConfig 34 | 35 | ChainConfig.md_template = './myMarkdown.html' 36 | ChainConfig.md_template_dark = './myDarkMarkdown.html' 37 | ``` 38 | 39 | HTML 内需要实现以下方法获取到 Markdown 文本 40 | 41 | ```js 42 | window.init = (data) => { 43 | const markdownText = data['content'] 44 | } 45 | ``` 46 | -------------------------------------------------------------------------------- /docs/develop/basic/chainBuild/mdTemplate.md: -------------------------------------------------------------------------------- 1 | # Markdown 模版消息 2 | 3 | 发送 QQ 频道 Markdown 4 | 模板消息,详情请查看[发送 markdown 消息](https://bot.q.qq.com/wiki/develop/api/openapi/message/post_markdown_messages.html)。 5 | 6 | ## Chain().markdown_template() 7 | 8 | | 参数名 | 类型 | 释义 | 默认值 | 9 | |----------------------|----------------|-----------------|-----| 10 | | template_id | str | 模版 ID | | 11 | | params | List[dict] | 模版 key-value 数据 | | 12 | | keyboard | InlineKeyboard | 按钮消息(自定义) | | 13 | | keyboard_template_id | str | 按钮消息(模版) | | 14 | 15 | ```python 16 | params = [ 17 | {'key': 'para1', 'values': ['段落1']}, 18 | {'key': 'para2', 'values': ['段落2']}, 19 | {'key': 'desc', 'values': ['简介']}, 20 | ] 21 | 22 | Chain(data, at=False).markdown_template('101993071_1658748972', params) 23 | ``` 24 | 25 | ## 按钮消息 26 | 27 | [发送含有消息按钮组件的消息](https://bot.q.qq.com/wiki/develop/api/openapi/message/post_keyboard_messages.html) 28 | 29 | ### 使用按钮模版 30 | 31 | ```python {4} 32 | # 必须跟随 md 模版发送 33 | Chain(data, at=False).markdown_template( 34 | '101993071_1658748972', 35 | params, 36 | keyboard_template_id='102005657_1703561314', 37 | ) 38 | ``` 39 | 40 | ### 自定义按钮 41 | 42 | 自定义按钮通过内置的 InlineKeyboard 类构建。 43 | 44 | ```python 45 | from amiyabot import InlineKeyboard 46 | 47 | @bot.on_message(keywords='hello') 48 | async def _(data: Message): 49 | keyboard = InlineKeyboard(data.instance.appid) 50 | 51 | # 添加第一行按钮组 52 | row = keyboard.add_row() 53 | row.add_button('1', '按钮1') 54 | row.add_button('2', '按钮2') 55 | 56 | # 添加第二行按钮组 57 | row2 = keyboard.add_row() 58 | row2.add_button('3', '按钮3') 59 | row2.add_button('4', '更多功能...', action_type=0) 60 | 61 | # 必须跟随 md 模版发送 62 | chain = Chain(data, at=False).markdown_template( 63 | '102005657_1704356453', 64 | [{'key': 'content', 'values': ['Markdown 测试']}], 65 | keyboard=keyboard, 66 | ) 67 | 68 | # 通过主动消息发送 69 | await bot[data.instance.appid].send_message(chain, channel_id=data.channel_id) 70 | ``` 71 | -------------------------------------------------------------------------------- /docs/develop/basic/chainBuild/tag.md: -------------------------------------------------------------------------------- 1 | # 频道跳转超链接 2 | 3 | 发送频道跳转超链接 `#子频道`,点击可以跳转至子频道,仅支持当前频道内的子频道 4 | 5 | ::: danger 注意
6 | 仅支持 QQ 频道 7 | ::: 8 | 9 | ## Chain().tag() 10 | 11 | | 参数名 | 类型 | 释义 | 默认值 | 12 | |--------|-----|-------|-----| 13 | | target | int | 子频道ID | | 14 | 15 | ```python 16 | Chain(data).tag(12345678) 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/develop/basic/chainBuild/text.md: -------------------------------------------------------------------------------- 1 | # 文字 2 | 3 | 发送一段文字消息 4 | 5 | ## Chain().text() 6 | 7 | | 参数名 | 类型 | 释义 | 默认值 | 8 | |--------------|------|--------------|------| 9 | | text | str | 内容文本 | | 10 | | auto_convert | bool | 是否超出字数后转换为图片 | True | 11 | 12 | ```python 13 | Chain(data).text('hello, world') 14 | ``` 15 | 16 | 设置 `auto_convert=True` 可开启自动转换,当文字超过一定长度时(默认配置为 100),会自动将本段落转换为图片发送。 17 | 18 | ## 插入表情 19 | 20 | 在文本内使用 `[face:ID]` 模板也可以插入 QQ 表情。 21 | 22 | ```python 23 | Chain(data).text('hello, world[face:175]') 24 | ``` 25 | -------------------------------------------------------------------------------- /docs/develop/basic/chainBuild/textImage.md: -------------------------------------------------------------------------------- 1 | # 文字生成的图片 2 | 3 | 此方法可以将文字转换为图片发送,使用**调色模板**可以进行文字调色,亦可插入图片渲染。 4 | 5 | ## Chain().text_image() 6 | 7 | | 参数名 | 类型 | 释义 | 默认值 | 8 | |---------|-----------------|-------|---------| 9 | | text | str | 内容文本 | | 10 | | images | List[ImageElem] | 插入图片 | None | 11 | | width | int | 图片宽度 | None | 12 | | height | int | 图片高度 | None | 13 | | bgcolor | str | 图片背景色 | #F5F5F5 | 14 | 15 | ```python 16 | Chain(data).text_image('hello, world') 17 | ``` 18 | 19 | ### 调色模板 20 | 21 | 在文本内使用 22 | \[cl 23 | 文字内容@#颜色代码 24 | cle] 25 | 格式的模板,将指定文字内容改变颜色。 26 | 27 | ```python 28 | @bot.on_message(keywords='hello') 29 | async def _(data: Message): 30 | return Chain(data).text(f'hello [cl {data.nickname}@#ff0000 cle]') 31 | ``` 32 | 33 | image 34 | 35 | ::: danger text_image 无法插入表情
36 | 如果 `Chain.text` 的文本内使用了**调色模板**,将会强制转换为图片。同时 `[face:ID]` 模板也会失效。 37 | ::: 38 | 39 | ### 渲染图片 40 | 41 | 在 images 参数内传入一个包含 ImageElem 对象的列表,可在文字图片内渲染图片。
42 | 43 | **ImageElem** 44 | 45 | | 参数名 | 类型 | 释义 | 默认值 | 46 | |------|------------|---------------|-----| 47 | | path | str | 图片路径 | | 48 | | size | int | 图片大小 | | 49 | | pos | (int, int) | 图片渲染位置 (x, y) | | 50 | 51 | 简单尝试一下,发送一张 `hello, world` 的文字图片,并在里面插入一张图片。
52 | 需要注意的是,因为 `hello, world` 文字只有一行,所以需要指定一下**图片高度**。否则插入的图片可能会显示不全。
53 | 你可以一次插入很多张图片,所以任何时候,都请把握好你的**文字图片宽高**与插入的图片的**大小、坐标**之间的影响。 54 | 55 | ```python 56 | from amiyabot.builtin.lib.imageCreator import ImageElem 57 | 58 | 59 | @bot.on_message(keywords='hello') 60 | async def _(data: Message): 61 | image = ImageElem(path='face.png', size=80, pos=(0, 20)) 62 | 63 | return Chain(data).text_image('hello,world', images=[image], height=100) 64 | ``` 65 | 66 | 你可以收到如下的回复 67 | 68 | image 69 | 70 | ## 更换字体 71 | 72 | 可以使用自己的 ttf 字体文件更换字体 73 | 74 | ```python 75 | from amiyabot.builtin.lib.imageCreator import FontStyle 76 | 77 | FontStyle.file = './font.ttf' 78 | ``` 79 | -------------------------------------------------------------------------------- /docs/develop/basic/chainBuild/video.md: -------------------------------------------------------------------------------- 1 | # 视频 2 | 3 | 发送一段 **mp4** 格式的视频 4 | 5 | ::: danger 注意
6 | QQ 频道机器人暂时不支持发送视频,目前仅支持官方 QQ 群。 7 | ::: 8 | 9 | ## Chain().video() 10 | 11 | | 参数名 | 类型 | 释义 | 默认值 | 12 | |------|-----|--------|-----| 13 | | file | str | 视频文件路径 | | 14 | 15 | ```python 16 | Chain(data).video(file) 17 | ``` 18 | 19 | ```python 20 | @bot.on_message(keywords='hello') 21 | async def _(data: Message): 22 | return Chain(data).video('xxxxxx.mp4') 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/develop/basic/chainBuild/voice.md: -------------------------------------------------------------------------------- 1 | # 语音 2 | 3 | 发送一段 **wav** 格式的音频 4 | 5 | ::: danger 注意
6 | QQ 频道机器人暂时不支持发送语音,目前仅支持官方 QQ 群、 `mirai-api-http` 和 `cq-http`。 7 | ::: 8 | 9 | ## Chain().voice() 10 | 11 | | 参数名 | 类型 | 释义 | 默认值 | 12 | |-------|-----|-------------|-------| 13 | | file | str | 语音 wav 文件路径 | | 14 | | title | str | 语音标题 | voice | 15 | 16 | ```python 17 | Chain(data).voice(file) 18 | ``` 19 | 20 | ```python 21 | @bot.on_message(keywords='hello') 22 | async def _(data: Message): 23 | return Chain(data).voice('阿米娅_问候.wav') 24 | ``` 25 | -------------------------------------------------------------------------------- /docs/develop/basic/continuityMessage.md: -------------------------------------------------------------------------------- 1 | # 创建连续对话 2 | 3 | 在一些使用场景里,需要机器人与使用者产生连续的对话。比如询问使用者以获取信息等。 4 | 5 | Message 对象内置了连续对话支持。 6 | 7 | ## Message.wait() 8 | 9 | **参数列表** 10 | 11 | | 参数名 | 类型 | 释义 | 默认值 | 12 | |-------------|----------|-------------|-------| 13 | | reply | Chain | Chain 对象 | | 14 | | force | bool | 使用强制等待 | False | 15 | | max_time | int | 最长等待时间(秒数) | 30 | 16 | | data_filter | Callable | Message 过滤器 | | 17 | | level | int | 优先级 | 0 | 18 | 19 | 使用 wait 方法实现一个简单的连续对话 20 | 21 | ```python {4} 22 | @bot.on_message(keywords='hello') 23 | async def _(data: Message): 24 | 25 | reply = await data.wait(Chain(data).text('tell me your name please~')) 26 | 27 | if reply: 28 | return Chain(reply).text(f'hello,{reply.text}') 29 | ``` 30 | 31 | image 32 | 33 | ### force 强制等待 34 | 35 | 等待通常不会影响消息分配器运作,也就是说 **仅在不能触发任何其他功能** 36 | 的时候,消息才会返回到当前等待处。**(也包括本功能的初始触发方式,一般功能的优先级默认为 1,比等待事件的默认优先级高)** 37 | 38 | 如果你不希望如此,使用参数 `force=True`,可以忽略分配器让消息强制返回到等待处。 39 | 40 | ### data_filter 消息过滤器 41 | 42 | 如果在等待过程中,希望 wait 接收到符合期望的消息后再返回到等待处,可以使用 data_filter 参数过滤消息。 43 | 44 | ```python {8} 45 | async def my_data_filter(data: Message): 46 | if ...: 47 | return True # 返回 True 代表此则消息符合期望,将返回到等待处 48 | 49 | 50 | @bot.on_message(keywords='hello') 51 | async def _(data: Message): 52 | reply = await data.wait(Chain(data).text('tell me your name please~'), data_filter=my_data_filter) 53 | 54 | if reply: 55 | return Chain(reply).text(f'hello,{reply.text}') 56 | ``` 57 | 58 | ### 关于 wait 方法你需要知道的事 59 | 60 | - 若用户超过最长等待时间未回复,wait 会返回 `None`。 61 | - 62 | 63 | 同一个子频道内的同一个用户只能存在一个等待事件,当一个新的等待事件创建后,上一个未使用的等待事件会被注销并引发 `WaitEventCancel` 64 | 异常,进行中的业务将会被**终止**,这是符合预期的,通常这个异常会被全局异常捕捉器过滤。 65 | 66 | - 在等待时间内使用其他功能,等待也会被注销。 67 | 68 | ## Message.wait_channel() 69 | 70 | ::: danger 注意
71 | 该方法不可用于支持私信的功能里 72 | ::: 73 | 74 | **参数列表** 75 | 76 | | 参数名 | 类型 | 释义 | 默认值 | 77 | |-------------|----------|-------------|-------| 78 | | reply | Chain | Chain 对象 | | 79 | | force | bool | 使用强制等待 | False | 80 | | clean | bool | 是否清空消息列表 | True | 81 | | max_time | int | 最长等待时间(秒数) | 30 | 82 | | data_filter | Callable | Message 过滤器 | | 83 | | level | int | 优先级 | 0 | 84 | 85 | wait_channel 方法用于等待**子频道全体成员的回复**。 86 | 87 | 与 wait 方法不同的是,wait_channel 返回的不是 Message 对象,而是 `ChannelMessagesItem` 对象。内含等待事件的实例,和该次返回的消息。 88 | 89 | **ChannelMessagesItem** 90 | 91 | 属性 92 | 93 | | 属性 | 类型 | 释义 | 94 | |---------|------------------|-----------| 95 | | event | ChannelWaitEvent | 等待事件的实例 | 96 | | message | Message | Message对象 | 97 | 98 | 方法 99 | 100 | | 方法名 | 参数 | 释义 | 异步 | 101 | |-------------|----|--------|----| 102 | | close_event | | 关闭等待事件 | 否 | 103 | 104 | 下面来看一个简单的例子 105 | 106 | ```python {6,8,10,11} 107 | @bot.on_message(keywords='hello') 108 | async def _(data: Message): 109 | await data.send(Chain(data).text('hello everyone, tell me your name please~')) 110 | while True: 111 | await asyncio.sleep(0) 112 | event = await data.wait_channel() 113 | if event: 114 | reply = event.message 115 | 116 | if reply.text == 'stop': 117 | event.close_event() # 关闭等待事件 118 | break 119 | 120 | await data.send(Chain(reply).text(f'hello,{reply.text}')) 121 | ``` 122 | 123 | ### close_event() 124 | 125 | 关闭等待事件 126 | 127 | wait_channel 与 wait 的用法是**大致相同**的,但是 wait_channel 在接收到有效消息并返回后,不会像 wait 128 | 那样关闭事件,而是保持接收子频道的消息。在你的业务逻辑正常结束时,你**必须**使用 `close_event` 关闭它。 129 | 130 | ::: warning 请注意
131 | **请务必让你的业务逻辑有机会关闭等待事件**,否则等待事件没有被正常关闭时,它可能会**持续拦截子频道消息**直至超时自动关闭。 132 | ::: 133 | 134 | ### 不清除消息队列 135 | 136 | 如果你持续调用 wait_channel(如示例所示),但你不希望在处理业务时错过子频道内的消息,可以设置参数 `clean=False` 137 | 让事件不清除消息队列。让你可以按顺序获取到子频道内的消息。 138 | 139 | ```python 140 | await data.wait_channel(clean=False) 141 | ``` 142 | -------------------------------------------------------------------------------- /docs/develop/basic/handleEvents.md: -------------------------------------------------------------------------------- 1 | # 事件监听 2 | 3 | 监听频道发生的事件。
4 | 一般来说消息(`MESSAGE_CREATE`、`AT_MESSAGE_CREATE`以及`DIRECT_MESSAGE_CREATE`)也属于事件,但是在构建阶段,这些消息事件会被归类并产出 5 | Message 对象。剩下的事件类型,则会产出 6 | Event 对象。可以使用 on_event 装饰器去获取事件。 7 | 8 | ## 注册事件响应 9 | 10 | ```python 11 | from amiyabot import Event, BotAdapterProtocol 12 | 13 | ... 14 | 15 | @bot.on_event() 16 | async def _(event: Event, instance: BotAdapterProtocol): 17 | ... 18 | 19 | @bot.on_event('GUILD_CREATE') 20 | async def _(event: Event, instance: BotAdapterProtocol): 21 | ... 22 | 23 | @bot.on_event(['CHANNEL_CREATE', 'CHANNEL_UPDATE']) 24 | async def _(event: Event, instance: BotAdapterProtocol): 25 | ... 26 | ``` 27 | 28 | - `on_event` 接受一个**事件名或事件名列表**作为参数(无参数则监听全事件)。事件名可参阅对应适配器服务的官方文档。 29 | - 响应函数是一个协程,接受 Event 对象和 bot 实例两个参数。 30 | 31 | ### Event 对象 32 | 33 | | 属性 | 类型 | 释义 | 34 | |------------|------|------------------| 35 | | appid | str | 发生该事件的 Bot AppId | 36 | | event_name | str | 事件名 | 37 | | data | dict | 事件的内容字典 | 38 | 39 | ## 频道事件 40 | 41 | 频道事件 `Event.data` 的值为 websocket 消息体里的 `d` 字段内容。 42 | 43 | 如下为 [频道事件 - GUILD_CREATE](https://bot.q.qq.com/wiki/develop/api/gateway/guild.html#guild-create) 官方文档示例的 44 | websocket 消息体。 45 | 46 | ```json 47 | { 48 | "op": 0, 49 | "s": 6, 50 | "t": "GUILD_CREATE", 51 | "d": { 52 | "description": "频道介绍", 53 | "icon": "", 54 | "id": "200000000", 55 | "joined_at": "2021-10-21T11:20:18+08:00", 56 | "max_members": 300, 57 | "member_count": 17, 58 | "name": "频道名称", 59 | "op_user_id": "100000000", 60 | "owner_id": "100000000" 61 | } 62 | } 63 | ``` 64 | 65 | 在 on_event 里接收到时 66 | 67 | ```python 68 | @bot.on_event('GUILD_CREATE') 69 | async def _(event: Event, instance: BotAdapterProtocol): 70 | 71 | print(event.data['name']) // 频道名称 72 | print(event.data['description']) // 频道介绍 73 | ``` 74 | 75 | 频道的事件名和内容可以查看官方文档 [事件订阅](https://bot.q.qq.com/wiki/develop/api/gateway/intents.html) 76 | 77 | ## mirai-api-http 事件 78 | 79 | - [mirai-api-http 事件类型一览](https://docs.mirai.mamoe.net/mirai-api-http/api/EventType.html) 80 | 81 | mirai-api-http 戳一戳事件推送的消息。 82 | 83 | ```json 84 | { 85 | "type": "NudgeEvent", 86 | "fromId": 123456, 87 | "subject": { 88 | "id": 123456, 89 | "kind": "Group" 90 | }, 91 | "action": "戳了戳", 92 | "suffix": "的脸", 93 | "target": 123456 94 | } 95 | ``` 96 | 97 | 监听 type 的值 `NudgeEvent` 即可。 98 | 99 | ```python 100 | @bot.on_event('NudgeEvent') 101 | async def _(event: Event, instance: BotAdapterProtocol): 102 | ... 103 | ``` 104 | 105 | ## go-cqhttp 事件 106 | 107 | - [go-cqhttp 事件](https://docs.go-cqhttp.org/event/) 108 | 109 | 针对 go-cqhttp 事件的 [数据结构](https://docs.go-cqhttp.org/reference/data_struct.html#post-type),AmiyaBot 110 | 对其进行了分类,可以使用以下事件名精确获取。 111 | 112 | 如:戳一戳事件中 go-cqhttp 对其进行了三级分类。 113 | 114 | ```json 115 | { 116 | "post_type": "notice", 117 | "notice_type": "notify", 118 | "sub_type": "poke" 119 | } 120 | ``` 121 | 122 | 监听 `notice` 事件时,无法获得准确的事件。因为在 `notice_type` 的分类里,还包含了好友添加、消息撤回等一系列子事件。
123 | 当然,如果你需要监听这个大类的事件时,仍然可以监听这个事件名。 124 | 125 | ```python 126 | # 监听 post_type 为 notice 的事件 127 | @bot.on_event('notice') 128 | async def _(event: Event, instance: BotAdapterProtocol): 129 | ... 130 | 131 | # 监听 post_type 为 notice 且 notice_type 为 notify 的事件 132 | @bot.on_event('notice.notify') 133 | async def _(event: Event, instance: BotAdapterProtocol): 134 | ... 135 | ``` 136 | 137 | 通过事件名 `notice.notify.poke`,即可监听到准确的戳一戳事件。 138 | 139 | ```python 140 | @bot.on_event('notice.notify.poke') 141 | async def _(event: Event, instance: BotAdapterProtocol): 142 | ... 143 | ``` 144 | 145 | 其他类别的事件同理,通过事件数据中的 `post_type.xxxxx_type.sub_type` 定义事件监听名即可。 146 | -------------------------------------------------------------------------------- /docs/develop/basic/handleException.md: -------------------------------------------------------------------------------- 1 | # 异常监听 2 | 3 | AmiyaBot 内置了全局的用户层面异常捕获让程序不会轻易崩溃。如果你希望获取这些异常,可以通过注册异常处理器来获得它们。在执行消息响应或在消息响应筛选过程产生异常时,会执行这些注册的异常处理函数。 4 | 5 | 异常处理函数接受三个参数,分别是 **异常类型实例** `Exception`、**适配器实例** `BotAdapterProtocol`、**产生异常的数据** 6 | (`Message` 或 `Event`) 7 | 8 | ```python 9 | from amiyabot import BotAdapterProtocol 10 | 11 | @bot.on_exception() 12 | async def _(err: Exception, 13 | instance: BotAdapterProtocol, 14 | data: Union[Message, Event]): 15 | ... 16 | ``` 17 | 18 | ## 指定异常类型 19 | 20 | ```python 21 | @bot.on_exception(KeyError) 22 | async def _(err: Exception, 23 | instance: BotAdapterProtocol, 24 | data: Union[Message, Event]): 25 | ... 26 | ``` 27 | 28 | ## 指定多种异常类型 29 | 30 | ```python 31 | @bot.on_exception([OSError, IndexError]) 32 | async def _(err: Exception, 33 | instance: BotAdapterProtocol, 34 | data: Union[Message, Event]): 35 | ... 36 | ``` 37 | 38 | -------------------------------------------------------------------------------- /docs/develop/basic/index.md: -------------------------------------------------------------------------------- 1 | # 开始使用 2 | 3 | 在开始之前,我们希望你知道 AmiyaBot 是一款针对 QQ 频道机器人的框架。如果你想使用第三方机器人服务(如 mirai-api-http 或 4 | go-cqhttp),可通过更改实例的适配器使用。
5 | 接下来的文档将围绕 QQ 频道机器人展开。**如果需要 [更改适配器](/develop/adapters/) 请在安装依赖后阅读适配器文档**。 6 | 7 | 我们建议你先在 [QQ开放平台](https://bot.q.qq.com/wiki) 了解 QQ 频道机器人的运营规则,这非常重要,因为在本文档里,关于这部分的内容将会非常少。如果你并不了解 8 | QQ 9 | 频道机器人,后续的文档可能会对你造成疑惑。 10 | 11 | ## 安装依赖 12 | 13 | ![amiyabot](https://img.shields.io/pypi/v/amiyabot) 14 | 15 | ```bash 16 | pip install amiyabot 17 | ``` 18 | 19 | ## 创建你的第一个 Bot 20 | 21 | 1. 在 [QQ开放平台](https://q.qq.com/) 申请并创建你的 QQ 机器人。创建沙箱频道,并把你的机器人添加进频道里。(此处不作详细说明) 22 | 2. 使用机器人的 `appid` 和 `token` 创建一个 AmiyaBot 实例 23 | 24 | ```python 25 | import asyncio 26 | 27 | from amiyabot import AmiyaBot, Message, Chain 28 | 29 | bot = AmiyaBot(appid='******', token='******') 30 | 31 | 32 | @bot.on_message(keywords='hello') 33 | async def _(data: Message): 34 | return Chain(data).text(f'hello, {data.nickname}') 35 | 36 | 37 | asyncio.run(bot.start()) 38 | ``` 39 | 40 | 3. 运行代码,在频道里输入 `@机器人 hello`,你预期会看到如下输出。 41 | 42 | image 43 | 44 | 那么恭喜你,你的 QQ 机器人已经可以正常运作了。 45 | 46 | > _「这是个人迈出的一小步,但却是人类迈出的一大步。」—— 阿姆斯特朗_ 47 | 48 | ## 创建私域机器人 49 | 50 | 如果你在平台创建的是**私域机器人**,在 `AmiyaBot` 的参数里设置 `private=True` 51 | 来开启私域模式,私域机器人支持接收非 `@机器人` 的消息,你可以使机器人以更灵活的方式触发功能。 52 | 53 | ```python 54 | # 配置 private=True 让实例改为私域 55 | bot = AmiyaBot(appid='******', token='******', private=True) 56 | ``` 57 | 58 | ## 使用前缀触发词唤醒机器人 59 | 60 | ```python 61 | bot = AmiyaBot(...) 62 | 63 | # 添加前缀触发词 64 | bot.set_prefix_keywords(['amiya', 'amy']) 65 | ``` 66 | 67 | 此时机器人只能接收指定前缀的对话 68 | 69 | image 70 | 71 | ## 沙箱环境 72 | 73 | 使用 `QQGuildSandboxBotInstance` 适配器将 API 调用更改为沙箱环境。沙箱环境只会收到测试频道的事件,且调用 openapi 仅能操作测试频道。 74 | 75 | ```python 76 | from amiyabot.adapters.tencent.qqGuild import QQGuildSandboxBotInstance 77 | 78 | bot = AmiyaBot(..., adapter=QQGuildSandboxBotInstance) 79 | ``` 80 | -------------------------------------------------------------------------------- /docs/develop/basic/messageHandler.md: -------------------------------------------------------------------------------- 1 | # 注册消息响应器 2 | 3 | AmiyaBot 功能开发的关键模块一共有三个,分别是 `AmiyaBot`、`Message`和`Chain`。 4 | 5 | - `AmiyaBot` 为机器人实例,包含了消息和事件的注册器。 6 | - `Message` 为接收的消息主体,内含预解析的消息内容,以及一些相关操作函数。Message 对象在此仅用于参数类型注解,供编辑器智能提示使用,任何时候,你都不需要实例化 7 | Message 对象。 8 | - `Chain` 为机器人消息的创建工具。任何需要发送消息的时候,消息都必须由 Chain 类创建。核心会调用 Chain 类的 build 方法生成消息链。 9 | 10 | 首先需要知道的是,**如何注册消息响应**。 11 | 12 | ## on_message 装饰器 13 | 14 | ::: tip 何为机器人的功能?
15 | 消息响应我们会在后续的文档称之为**功能**,因为机器人的主要功能,一般就是通过响应用户的消息实现的。 16 | ::: 17 | 18 | 装饰器 `on_message` 作用于你的业务逻辑主体函数,以此注册消息响应来实现你的机器人功能。 19 | 20 | ```python 21 | # 当和机器人的对话中包含 'hello' 关键字时,将会触发该函数 22 | @bot.on_message(keywords='hello') 23 | async def _(data: Message): 24 | return Chain(data).text(f'hello, {data.nickname}') 25 | ``` 26 | 27 | #### 参数列表 28 | 29 | | 参数名 | 类型 | 释义 | 默认值 | 30 | |--------------|----------|--------------------------------|-------| 31 | | group_id | str | 功能组ID | | 32 | | keywords | | 触发关键字,支持多种类型,详见本章文档 | | 33 | | verify | Callable | 自定义校验方法,当该参数被赋值时,keywords 将会失效 | | 34 | | check_prefix | bool | 是否校验前缀或指定需要校验的前缀 | True | 35 | | allow_direct | bool | 是否支持通过私信使用该功能 | False | 36 | | direct_only | bool | 是否仅支持私信 | False | 37 | | level | int | 关键字校验成功后函数的候选默认等级 | 0 | 38 | 39 | ## 功能组 40 | 41 | 参数 `group_id` 可以为该功能设置功能组。功能组可以批量为功能设置参数。 42 | 43 | 实例化 **GroupConfig** 对象创建一个功能组,并将其设置到 bot 实例内。 44 | 45 | | 参数名 | 类型 | 释义 | 默认值 | 46 | |--------------|------|------------------|-------| 47 | | group_id | str | 功能组ID | | 48 | | check_prefix | bool | 是否校验前缀或指定需要校验的前缀 | True | 49 | | allow_direct | bool | 是否支持通过私信使用该功能 | False | 50 | | direct_only | bool | 是否仅支持私信 | False | 51 | 52 | ```python 53 | from amiyabot import GroupConfig 54 | 55 | fn_group = GroupConfig('test', check_prefix=False) 56 | bot.set_group_config(fn_group) # 注册功能组 57 | ``` 58 | 59 | 为消息响应设置 `group_id` 参数 60 | 61 | ```python 62 | # 传入功能组名称设置组别 63 | @bot.on_message(group_id='test', keywords='...') 64 | async def _(data: Message): 65 | ... 66 | 67 | 68 | # 传入功能组对象设置组别(效果相同) 69 | @bot.on_message(group_id=fn_group, keywords='...') 70 | async def _(data: Message): 71 | ... 72 | ``` 73 | 74 | ::: danger 注意
75 | 仅当 on_message 里没有设置该参数时,功能组的参数才会对其生效。否则优先使用 on_message 的参数。 76 | ::: 77 | 78 | ## 私域模式的前缀校验 79 | 80 | AmiyaBot 私域模式建议在对话中包含指定前缀才能进入消息分配器。设置前缀触发词后,在一些特殊的情况下,可以通过 `忽略前缀检查` 81 | 和 `校验完全匹配` 的方式绕过检查。 82 | 83 | ### 接收不包含前缀的消息 84 | 85 | 添加参数 `check_prefix=False` 可忽略前缀检查 86 | 87 | ```python 88 | @bot.on_message(keywords='hello', check_prefix=False) 89 | async def _(data: Message): 90 | return Chain(data).text(f'hello, {data.nickname}') 91 | ``` 92 | 93 | ### 接收指定前缀的消息 94 | 95 | `check_prefix` 参数改为字符串列表可以临时修改前缀检查为指定单词 96 | 97 | ```python 98 | @bot.on_message(keywords='hello', check_prefix=['amiya', '🐰']) 99 | async def _(data: Message): 100 | return Chain(data).text(f'hello, {data.nickname}') 101 | ``` 102 | 103 | ## 校验符合正则检查的句式 104 | 105 | 关键字传入 `re.compile` 对象,可以检查对话文本是否符合正则表达式。 106 | 107 | ```python 108 | import re 109 | ... 110 | 111 | @bot.on_message(keywords=re.compile(r'hello,\d+')) 112 | async def _(data: Message): 113 | return Chain(data).text(f'hello, {data.nickname}') 114 | ``` 115 | 116 | ## 校验完全匹配的句式 117 | 118 | 完全匹配的句式指对话的文本内容**全等于** keyword 关键字(不包括 @ 部分),使用工具类 `Equal` 即可达到效果。 119 | 120 | ```python 121 | from amiyabot import Equal 122 | ... 123 | 124 | @bot.on_message(keywords=Equal('hello, amiya')) 125 | async def _(data: Message): 126 | return Chain(data).text(f'hello, {data.nickname}') 127 | ``` 128 | 129 | ::: tip 提示
130 | 在私域机器人下且不需要 @ 唤起的场合,Equal 会无视前缀检查。 131 | ::: 132 | 133 | ## 组合多个和多种 keywords 134 | 135 | keywords 支持由 `字符串、正则、Equal` 构成的列表,组合中包含 `Equal` 时,`Equal` 依然会无视前缀检查。 136 | 137 | ```python 138 | @bot.on_message( 139 | keywords=[ 140 | 'hello', 141 | 'hey', 142 | Equal('hello, amiya'), 143 | re.compile(r'hello,(\d+)'), 144 | ] 145 | ) 146 | async def _(data: Message): 147 | return Chain(data).text(f'hello, {data.nickname}') 148 | ``` 149 | 150 | ## 功能优先级 151 | 152 | 当关键字校验存在冲突时,可以通过指定优先级供消息分配器选择。
153 | 分配器的工作原理,是在完成检查之后,将通过校验的候选函数列表按优先级倒序排序,然后选取第一个执行。
154 | 所有函数的默认优先级都为 `1`,如果不指定优先级,分配器会按照加载的先后顺序选择。 155 | 156 | ```python 157 | # 如果不指定优先级,当对话内容为 "helloworld" 时,第一个函数会首先通过校验并输出。 158 | # 因为在模块加载阶段,第一个函数更早注册完毕。 159 | 160 | @bot.on_message(keywords='hello', level=1) 161 | async def _(data: Message): 162 | return Chain(data).text(f'hello, {data.nickname}') 163 | 164 | 165 | @bot.on_message(keywords='helloworld', level=2) 166 | async def _(data: Message): 167 | return Chain(data).text('hello,world') 168 | ``` 169 | 170 | ::: tip 提示
171 | 优先级允许为 0 或**负数**。 172 | ::: 173 | 174 | ## 自定义检查 175 | 176 | 当关键字检查无法满足功能的触发方式时,就需要使用自定义检查。
177 | 自定义检查是一个协程函数,参数为 Message 对象,返回一个`布尔值(必选)`、`优先级(可选)` 和 `关键值(可选)`的元组。 178 | 179 | ```python 180 | async def my_verify(data: Message): 181 | if 'hello' in data.text: 182 | return True 183 | 184 | 185 | @bot.on_message(verify=my_verify) 186 | async def _(data: Message): 187 | return Chain(data).text(f'hello, {data.nickname}') 188 | ``` 189 | 190 | 当消息响应获得执行权,自定义检查结果(Verify)将储存在 Message.verify 中。 191 | 192 | **Verify 对象** 193 | 194 | | 属性 | 类型 | 释义 | 195 | |----------|------|-------| 196 | | result | bool | 检查结果 | 197 | | weight | int | 优先级 | 198 | | keypoint | Any | 关键值信息 | 199 | 200 | ### 动态输出优先级的值 201 | 202 | 返回元组第二个值,即可以指定动态优先级。 203 | 204 | ```python {3,5} 205 | async def my_verify(data: Message): 206 | if ...: 207 | return True, 2 208 | elif ...: 209 | return True, 1 210 | return False 211 | ``` 212 | 213 | ### 输出关键值 214 | 215 | 返回元组第三个值,可以向 Message 的检查结果里添加关键值信息。可以是任意类型。 216 | 217 | ```python {3,9} 218 | async def my_verify(data: Message): 219 | if ...: 220 | return True, 1, {'name': 'my name'} 221 | return False 222 | 223 | 224 | @bot.on_message(verify=my_verify) 225 | async def _(data: Message): 226 | info = data.verify.keypoint # {'name': 'my name'} 227 | ``` 228 | 229 | ## 使功能在私信里可用 230 | 231 | 设置参数 `allow_direct=True`,允许功能在私信里触发。
232 | 设置参数 `direct_only=True`,功能仅私信可触发。 233 | 234 | ```python 235 | @bot.on_message(keywords='hello', allow_direct=True) 236 | async def _(data: Message): 237 | return Chain(data).text(f'hello, {data.nickname}') 238 | 239 | 240 | # 仅私信可触发 241 | @bot.on_message(keywords='hi', direct_only=True) 242 | async def _(data: Message): 243 | return Chain(data).text(f'hey, {data.nickname}') 244 | ``` 245 | -------------------------------------------------------------------------------- /docs/develop/basic/multipleAccounts.md: -------------------------------------------------------------------------------- 1 | # 多账号 2 | 3 | AmiyaBot 支持同时启动多个账号,所有账号之间可以共享资源以及功能。 4 | 5 | ## 创建多个单独实例 6 | 7 | 你可以同时创建多个**互不相关**的实例,只需要实例化多个 `AmiyaBot`。多实例启动时,一些内置的资源对象不会重复创建多个,而是被它们共享,以节约内存。 8 | 9 | ```python 10 | import asyncio 11 | 12 | from amiyabot import AmiyaBot, Message, Chain 13 | 14 | bot1 = AmiyaBot(appid='******', token='******', private=True) 15 | bot2 = AmiyaBot(appid='******', token='******') 16 | 17 | 18 | @bot1.on_message(keywords='hello') 19 | async def _(data: Message): 20 | return Chain(data).text(f'hello, {data.nickname}') 21 | 22 | 23 | @bot2.on_message(keywords='hey') 24 | async def _(data: Message): 25 | return Chain(data).text(f'hey, {data.nickname}') 26 | 27 | 28 | asyncio.run( 29 | asyncio.wait([ 30 | bot1.start(), 31 | bot2.start() 32 | ]) 33 | ) 34 | ``` 35 | 36 | ## 创建一个多账号实例 37 | 38 | **MultipleAccounts** 39 | 40 | `MultipleAccounts` 可以创建一个多账号实例,参数是多个 **AmiyaBot 实例**。它拥有与 AmiyaBot 一样的所有方法,所以你可以像 41 | AmiyaBot 一样使用它来注册你的功能。
42 | 通过 MultipleAccounts 注册的功能,将被所有包含的 AmiyaBot 共享。而其中的 AmiyaBot 实例,仍能单独注册属于自己的私有功能。 43 | 44 | ```python {8} 45 | import asyncio 46 | 47 | from amiyabot import AmiyaBot, MultipleAccounts, Message, Chain 48 | 49 | bot1 = AmiyaBot(appid='******', token='******', private=True) 50 | bot2 = AmiyaBot(appid='******', token='******') 51 | 52 | bot = MultipleAccounts(bot1, bot2, AmiyaBot(appid='******', token='******'), ...) 53 | 54 | 55 | # 公共功能 56 | @bot.on_message(keywords='hello') 57 | async def _(data: Message): 58 | return Chain(data).text(f'hello, {data.nickname}') 59 | 60 | 61 | # bot1 的私有功能 62 | @bot1.on_message(keywords='hey') 63 | async def _(data: Message): 64 | return Chain(data).text(f'hey, my name is Amiyabot') 65 | 66 | 67 | asyncio.run(bot.start()) 68 | ``` 69 | 70 | ## 多账号热插拔 71 | 72 | 多账号支持动态创建和删除里面的实例,也允许先创建**空多账号实例**。随后往里面插入 AmiyaBot 对象。 73 | 74 | ### MultipleAccounts.append() 75 | 76 | 插入一个实例 77 | 78 | | 参数名 | 类型 | 释义 | 默认值 | 79 | |-----------------|----------|----------------|-------| 80 | | item | AmiyaBot | AmiyaBot 实例 | | 81 | | enable_chromium | bool | 启动时开启 chromium | False | 82 | | start_up | bool | 插入后立即启动 | True | 83 | 84 | 示例 85 | 86 | ```python 87 | # 创建一个空多账号 88 | bot = MultipleAccounts() 89 | # 插入并启动一个实例 90 | bot.append(AmiyaBot(appid='12345', ...)) 91 | # 删除实例,同时关闭实例的连接 92 | del bot['12345'] 93 | ``` 94 | -------------------------------------------------------------------------------- /docs/develop/basic/recallMessage.md: -------------------------------------------------------------------------------- 1 | # 撤回消息 2 | 3 | 撤回一条消息。 4 | 5 | ## 在 Message 对象中撤回 6 | 7 | 使用 Message 对象的 `recall` 方法,撤回当前消息。 8 | 9 | **Message.recall()** 10 | 11 | ```python {3} 12 | @bot.on_message(keywords='hello') 13 | async def _(data: Message): 14 | await data.recall() 15 | ``` 16 | 17 | 你可以在任何能获取到 Message 对象的地方使用 `recall` 方法。比如在连续对话或异常监听里。 18 | 19 | ```python {6} 20 | @bot.on_message(keywords='hello') 21 | async def _(data: Message): 22 | # 等待事件返回的也是 Message 对象 23 | reply = await data.wait(Chain(data).text('...')) 24 | if reply: 25 | await reply.recall() 26 | ``` 27 | 28 | ```python {6} 29 | @bot.on_exception() 30 | async def _(err: Exception, 31 | instance: BotAdapterProtocol, 32 | data: Union[Message, Event]): 33 | if type(data) is Message: 34 | await data.recall() 35 | ``` 36 | 37 | ## 手动撤回 38 | 39 | 使用适配器实例的 `recall_message` 方法 40 | 41 | **AmiyaBot.instance.recall_message()** 42 | 43 | | 参数名 | 类型 | 释义 | 默认值 | 44 | |------------|---------|------------------------------------|------| 45 | | message_id | str | 消息ID(通常可以在 Message.message_id 获取到) | | 46 | | data | Message | Message 对象 | None | 47 | 48 | ```python 49 | await bot.instance.recall_message(message_id='......', target_id='......') 50 | ``` 51 | 52 | ## 撤回 Bot 发送的消息 53 | 54 | 如果是通过在消息响应器里面返回 `Chain` 对象或等待函数 `Message.wait()` 发送的消息,**是无法撤回的**,但后者可以通过另外的方法达到撤回效果。 55 | 56 | | 发送消息的方法 | 是否可撤回 | 57 | |------------------------|--------| 58 | | Message.send() | ✅ 可以撤回 | 59 | | Message.wait() | ❌ 无法撤回 | 60 | | Message.wait_channel() | ❌ 无法撤回 | 61 | | return Chain() | ❌ 无法撤回 | 62 | 63 | ```python 64 | @bot.on_message(keywords='hello') 65 | async def _(data: Message): 66 | chain = Chain(data).text(f'hello, {data.nickname}') 67 | 68 | callback = await data.send(chain) # ✅ 可以撤回 69 | if callback: 70 | await callback.recall() # 使用回调对象撤回 71 | 72 | wait = await data.wait(chain) # ❌ 无法撤回 73 | event = await data.wait_channel(chain) # ❌ 无法撤回 74 | 75 | return chain # ❌ 无法撤回 76 | ``` 77 | 78 | **Message.send()** 方法返回一个 `MessageCallback` 79 | 对象或其组成的列表(语音或频道多图消息会产生分开发送的结果)。如果消息没有发送成功则返回 `None`。 80 | 81 | 调用 `MessageCallback.recall()` 即可撤回发送的消息。 82 | 83 | ```python {6} 84 | @bot.on_message(keywords='hello') 85 | async def _(data: Message): 86 | 87 | callback = await data.send(...) 88 | if callback: 89 | await callback.recall() 90 | # 或 91 | # for item in callback: 92 | # await item.recall() 93 | ``` 94 | 95 | ### 撤回等待的消息 96 | 97 | **Message.wait()** 没有返回执行 `send` 时获得的 `MessageCallback`,因此你无法在使用该方法发送消息的情况下撤回,但你可以配合 98 | `send` 达到这个效果。 99 | 100 | ```python {3,4} 101 | @bot.on_message(keywords='hello') 102 | async def _(data: Message): 103 | callback = await data.send(Chain(data).text('hello, what\'s your name?')) # 使用 send 方法代替 wait 发送消息 104 | wait = await data.wait() # 只等待,不发送消息 105 | 106 | if callback and not wait: 107 | await callback.recall() 108 | 109 | ... 110 | ``` 111 | 112 | ### 撤回合并转发的消息 113 | 114 | [撤回合并转发](/develop/basic/chainBuild/forward.html#发送-撤回) 115 | -------------------------------------------------------------------------------- /docs/develop/basic/recvMessage.md: -------------------------------------------------------------------------------- 1 | # 接收消息 2 | 3 | 在上一节 [注册消息响应](/develop/basic/messageHandler) 4 | 中讲述了如何注册一个接收指定消息的函数,当接收到消息时,函数被执行时,参数 `data: Message` 就是接收到的消息的内容。 5 | 6 | `Message` 对象是接收到消息之后预处理化的一个消息数据对象。内含这则消息相关的各项属性,以及针对这则消息的一些操作API。
7 | 该对象主要应用在功能函数和自定义检查中。建议在开发时引入 Message 对象并注解在对应地方。 8 | 9 | ```python {1} 10 | from amiyabot import Message 11 | 12 | 13 | async def my_verify(data: Message): 14 | ... 15 | 16 | 17 | @bot.on_message(verify=my_verify) 18 | async def _(data: Message): 19 | print('recv:', data.text) 20 | ... 21 | ``` 22 | 23 | ## Message 对象 24 | 25 | ::: warning 重要变动
26 | 从 `1.9.8` 起,如果配置了[前缀触发词](/develop/basic/#使用前缀触发词唤醒机器人),Message 27 | 对象内的消息文本系列字段将不再包含触发对话的前缀([Commit 99ada6b](https://github.com/AmiyaBot/Amiya-Bot-core/commit/99ada6b494d3115cee58eef2a119eea334bb8f23)), 28 | 前缀在对话文本中被移除后将赋值到 `text_prefix` 属性内。 29 | ::: 30 | 31 | ### 属性 32 | 33 | | 属性 | 类型 | 释义 | 34 | |---------------|-------------------------------------------------------|----------------------------| 35 | | instance | BotAdapterProtocol | bot 实例 | 36 | | message | dict | 原始消息字典 | 37 | | message_id | str | 消息 ID | 38 | | message_type | str | 消息类型(适用于群聊适配器) | 39 | | face | List[str] | 消息内表情 ID 列表 | 40 | | image | List[str] | 消息内图片 URL 列表 | 41 | | text | str | 消息文本(不包含触发词、中间件处理) | 42 | | text_digits | str | 消息文本(不包含触发词、中间件处理、中文转数字处理) | 43 | | text_unsigned | str | 消息文本(不包含触发词、去字符处理) | 44 | | text_original | str | 消息文本(原始文本) | 45 | | text_words | List[str] | 消息文本分词 | 46 | | text_prefix | str | 消息触发词 | 47 | | at_target | List[str] | 消息内 @ 的对象列表 | 48 | | is_at | bool | 是否 @ 机器人 | 49 | | is_admin | bool | 是否为子频道管理员 | 50 | | is_direct | bool | 是否是私信消息 | 51 | | user_id | str | 用户 ID | 52 | | guild_id | str | 频道 ID | 53 | | src_guild_id | str | 来源频道 ID,私信下有效 | 54 | | channel_id | str | 子频道 ID | 55 | | nickname | str | 用户昵称 | 56 | | avatar | str | 用户头像的 URL | 57 | | joined_at | ISO8601 timestamp | 用户加入频道的时间 | 58 | | verify | [Verify 对象](/develop/basic/messageHandler.html#自定义检查) | 自定义检查的结果 | 59 | | time | int | 消息时间 | 60 | 61 | ### 方法 62 | 63 | | 方法名 | 参数 | 释义 | 异步 | 64 | |--------------|----------------------------------------|---------|----| 65 | | send | reply | 发送一条消息 | 是 | 66 | | wait | reply,force,max_time,data_filter | 等待用户消息 | 是 | 67 | | wait_channel | reply,force,clean,max_time,data_filter | 等待子频道消息 | 是 | 68 | | recall | | 撤回消息 | 是 | 69 | 70 | 接下来,使用 Message 对象提供的属性完成业务逻辑,并[发送消息](/develop/basic/sendMessage)。 71 | -------------------------------------------------------------------------------- /docs/develop/basic/sendActiveMessage.md: -------------------------------------------------------------------------------- 1 | # 发送主动消息 2 | 3 | ::: danger 主动消息限制
4 | 主动消息需要频道设置允许机器人推送,发送消息也存在数量限制。
5 | 详见官方文档 [接入流程-语料配置-消息类型](https://bot.q.qq.com/wiki/#_9-%E5%8F%91%E5%B8%83%E8%AE%BE%E7%BD%AE) 6 | ::: 7 | 8 | ## AmiyaBot.send_message() 9 | 10 | send_message 是发送主动消息的方法,它的第一个参数 chain 需要传入一个 Chain 对象。可以通过实例化一个无 Message 的 Chain 得到。 11 | 12 | ```python 13 | message = Chain().text('hello') 14 | ``` 15 | 16 | | 参数名 | 类型 | 释义 | 默认值 | 17 | |---------------------|-------|----------|-----| 18 | | chain | Chain | Chain 对象 | | 19 | | user_id | str | 用户ID | | 20 | | channel_id | str | 子频道ID | | 21 | | direct_src_guild_id | str | 来源频道ID | | 22 | 23 | ## 发送一条主动子频道消息 24 | 25 | ```python 26 | bot = AmiyaBot(...) 27 | message = Chain().text('hello') 28 | 29 | await bot.send_message(message, channel_id='******') 30 | ``` 31 | 32 | ## 发送一条主动私信 Beta 33 | 34 | 传入参数 `user_id`(用户ID)和 `direct_src_guild_id`(来源频道ID),send_message 将会发送主动私信消息。 35 | 36 | ```python 37 | bot = AmiyaBot(...) 38 | message = Chain().text('hello') 39 | 40 | await bot.send_message(message, 41 | user_id='*******', 42 | direct_src_guild_id='*******') 43 | ``` 44 | 45 | ## 在多账号实例里使用 send_message 46 | 47 | ```python 48 | bot = MultipleAccounts( 49 | [ 50 | AmiyaBot(appid='111111', ...), 51 | AmiyaBot(appid='222222', ...), 52 | ] 53 | ) 54 | 55 | await bot['222222'].send_message(...) 56 | ``` 57 | 58 | ## 在事件响应里使用 send_message 59 | 60 | ::: tip 提示
61 | 事件响应的方法通常可以返回触发了该事件的实例。 62 | ::: 63 | 64 | ### 事件监听 65 | 66 | ```python 67 | @bot.on_event('MESSAGE_DELETE') 68 | async def _(event: Event, instance: BotAdapterProtocol): 69 | await instance.send_message(...) 70 | ``` 71 | 72 | ### 异常监听 73 | 74 | ```python 75 | @bot.on_exception() 76 | async def _(err: Exception, 77 | instance: BotAdapterProtocol, 78 | data: Union[Message, Event]): 79 | await instance.send_message(...) 80 | ``` 81 | -------------------------------------------------------------------------------- /docs/develop/basic/sendMessage.md: -------------------------------------------------------------------------------- 1 | # 发送消息 2 | 3 | 在消息响应器内返回 Chain 对象,或使用 Message 对象的 send 方法,均可发送消息。 4 | 5 | ```python {3,5} 6 | @bot.on_message(keywords='hello') 7 | async def _(data: Message): 8 | await data.send(Chain(data).text('hello')) 9 | 10 | return Chain(data).text(data.nickname) 11 | ``` 12 | 13 | image 14 | 15 | ## Chain 对象 16 | 17 | | 参数名 | 类型 | 释义 | 默认值 | 18 | |---------------|--------------|--------------|----------------| 19 | | data | Message | Message 对象 | None | 20 | | at | bool | 是否 @ 用户 | True | 21 | | reference | bool | 是否回复用户(引用消息) | False | 22 | | chain_builder | ChainBuilder | Chain 辅助构建实例 | ChainBuilder() | 23 | 24 | `Chain` 对象是构建你的消息体的工具类。任何需要发送消息的时候,消息都必须由 Chain 类创建。
25 | Chain 对象提供丰富的消息构建方式,可以让你发送多彩的文字图片,甚至是html模板。
26 | 27 | 这是最简单的一条文本消息: 28 | 29 | ```python 30 | Chain(data).text('hello, world') 31 | ``` 32 | 33 | 更多类型请查看左侧导航**消息构建元素**。 34 | 35 | ## 构建消息的方法 36 | 37 | ### 普通消息 38 | 39 | Chain 对象支持链式语法,用于构建复杂的消息结构。
40 | 只需要按顺序以链式使用上述方法,即可拼接出内容丰富的消息。Chain 在最终构建消息的时候,会优化图片与文字的组成,减少消息的请求数量。 41 | 42 | ```python 43 | Chain(data).text(...).image(...).text(...).html(...) 44 | ``` 45 | 46 | ### 合并转发消息 47 | 48 | 合并转发消息需要使用独立的工具类创建 49 | 50 | - [发送合并转发消息](/develop/basic/chainBuild/forward.md) 51 | 52 | ## 空 Chain 53 | 54 | 实例化 Chain 对象时,不传入 Message 对象构建的。本文称之为 **“空 Chain”**。空 Chain 一般用于预构建消息。 55 | 56 | ```python 57 | Chain().text(...).image(...) 58 | ``` 59 | 60 | ## 使用辅助类扩展构建 61 | 62 | Chain 63 | 对象在构建消息时,可使用辅助类介入媒体消息或浏览器的构建过程。请移步 [进阶指南 - 介入媒体消息的构建过程](/develop/advanced/chainBuilder.md) 64 | -------------------------------------------------------------------------------- /docs/develop/basic/statement.md: -------------------------------------------------------------------------------- 1 | # 声明 2 | 3 | 在本章后续文档中,为了减少篇幅量,将不会再在代码示例中出现 `AmiyaBot` 或 `MultipleAccounts` 4 | 类的实例化代码。统一以变量 `bot` 表示已经实例化的 `AmiyaBot` 或 `MultipleAccounts` 类。 5 | 6 | 你将会在诸多场景中看到 bot 变量的存在。 7 | 8 | ```python 9 | # 装饰器 10 | @bot.on_message(...) 11 | 12 | # 调用方法 13 | bot.some_func(...) 14 | 15 | ... 16 | ``` 17 | -------------------------------------------------------------------------------- /docs/develop/basic/testInstance.md: -------------------------------------------------------------------------------- 1 | # 使用测试实例调试 2 | 3 | 使用适配器 `test_instance` 并配置 host、port 参数即可启动一个测试实例。 4 | 5 | ```python 6 | import asyncio 7 | 8 | from amiyabot import AmiyaBot, Message, Chain 9 | from amiyabot.adapters.test import test_instance 10 | 11 | bot = AmiyaBot(appid='123456', 12 | token='', 13 | adapter=test_instance('127.0.0.1', 32001)) 14 | 15 | 16 | @bot.on_message(keywords='hello', check_prefix=False) 17 | async def _(data: Message): 18 | return Chain(data).text(f'hello, {data.nickname}') 19 | 20 | 21 | asyncio.run(bot.start()) 22 | ``` 23 | 24 | 运行实例,访问 https://console.amiyabot.com/#/test 并输入配置的地址和 appid 连接测试服务,即可模拟测试对话。 25 | 26 | ![test.png](../../assets/console/test.png) 27 | -------------------------------------------------------------------------------- /docs/develop/design.md: -------------------------------------------------------------------------------- 1 | # 设计 2 | 3 | AmiyaBot 是一款 QQ 机器人框架,基于异步I/O构建,并提供了装饰器模式(Decorator Pattern)以及插件化动态导入(Dynamic 4 | import)的编程方式。 5 | 内置多种适配器兼容不同的服务来源以及丰富的消息构建类型,旨在帮助你更高效地编写业务逻辑,实现你的创意。 6 | 7 | 框架结构可分为`业务模块`,`通讯模块`,`数据处理模块`,`存储模块`和`运转中心`五个组成部分。它们独立运作,并在彼此之间相互提供数据。 8 | 9 | ## 业务模块 10 | 11 | 业务模块由`插件(Plugin)`、`账号实例(AmiyaBot)`和`多账号实例(MultipleAccounts)` 12 | 组成。它们一般会被组织成层层嵌套的树状结构。账号实例和多账号实例是同质的,它们均可以被运转中心(CenterProcessor)直接访问,运转中心无法访问插件。 13 | 14 | 运转中心在访问这些对象时,顶级对象会组合所有子级对象的属性提供给运转中心。 15 | 16 | 17 | 18 | ### 插件设计 19 | 20 | 实现上述模式的思路来源于 Vue 的 [组件设计](https://cn.vuejs.org/guide/essentials/component-basics.html) 21 | ,所以在代码层面,插件与账号实例都属于“组件”,理论上账号实例之间也能互相嵌套。但在设计时加入了限制,防止这种关系的出现。 22 | 23 | ### 业务设计 24 | 25 | 业务模块通过各种装饰器来定义业务逻辑以及规则。这些装饰器都来源于它们继承的工厂对象(BotHandlerFactory),工厂对象是业务模块与运转中心的桥梁,业务函数会被工厂对象收集并封装,最终提供给运转中心调用。 26 | 27 | **账号实例图解** 28 | 29 | 30 | 31 | ## 通讯与数据处理模块 32 | 33 | 通讯模块主要形式为`适配器(Adapter)`,用于对接由机器人运营方提供的服务。 34 | 35 | ### 适配器 36 | 37 | 账号实例里面有一个重要参数:adapter,它指定了通讯模块的运行方式(选择适配器)以适配不同运营方的连接协议。 38 | 39 | 40 | 41 | 通讯模块负责解决对接收和发送的数据进行解包与封包,所以它与数据处理模块紧密相连。适配器必须为数据处理模块提供统一的接口,在与不同的运营方服务通讯过程中,运转中心获取到的源数据格式都必须是一致的。而接收到运转中心需要发出的数据时,适配器需要把数据封包为运营方协定的格式,完成发送。 42 | 43 | 账号实例也可以脱离运转中心的调控随时调用适配器与运营方服务通讯,完成一些特殊情况下的操作。 44 | 45 | ## 运转中心 46 | 47 | 运转中心包含**事件处理**,**消息处理**、**分配器**和**日志** 48 | 等各种将所有模块相连的处理单元,是业务层的主要调度模块。在接收到由适配器传入的消息后,运转中心会将消息归类并分发到不同的处理模块。 49 | 50 | ### 消息处理 51 | 52 | 分配到消息处理的数据,将会对数据和业务模块收集的消息响应器(on_message)进行匹配,并将匹配成功的消息响应器按优先级排序,选取最高优先级的执行。 53 | 54 | 消息响应器的执行结果会经由运转中心返回到适配器,进行封包后发送。 55 | 56 | 57 | 58 | 这个过程在运转中心内称为“生命周期”,工厂对象可以介入这些周期影响消息处理的分配与执行结果。 59 | 60 | ## 结语 61 | 62 | 存储模块以及运转中心的日志等模块,在本文将忽略不谈。这些模块依赖第三方库或 Python 的标准库,本框架仅对其做了适度的封装。 63 | -------------------------------------------------------------------------------- /docs/develop/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: false 3 | --- 4 | 5 | # 欢迎访问开发文档 6 | 7 | - [基础开发指南](/develop/basic/) 8 | - [进阶开发指南](/develop/advanced/) 9 | -------------------------------------------------------------------------------- /docs/develop/old/httpSupport.md: -------------------------------------------------------------------------------- 1 | # HTTP服务器支持 2 | 3 | AmiyaBot 内置了基于 [FastApi](https://fastapi.tiangolo.com/) 的HTTP服务构建工具。 4 | 5 | ## 创建服务 6 | 7 | ### HttpServer 类 8 | 9 | | 参数名 | 类型 | 释义 | 默认值 | 10 | |-----------------|------|-------------------------|--------------------------| 11 | | host | str | 服务监听地址 | | 12 | | port | int | 服务监听端口 | | 13 | | title | str | swagger 页面标题 | AmiyaBot | 14 | | description | str | swagger 页面注释 | https://www.amiyabot.com | 15 | | auth_key | str | 请求头密钥 | | 16 | | fastapi_options | dict | FastAPI **kwargs | | 17 | | uvicorn_options | dict | uvicorn.Config **kwargs | | 18 | 19 | ```python 20 | from amiyabot import HttpServer 21 | 22 | server = HttpServer(host='0.0.0.0', port=8088) 23 | 24 | 25 | @server.controller 26 | class Bot: 27 | @server.route(method='get') 28 | async def get_name(self): 29 | return 'AmiyaBot' 30 | 31 | @server.route(method='post') 32 | async def say_hello(self): 33 | return server.response(message='hello') 34 | 35 | 36 | asyncio.run(server.serve()) 37 | ``` 38 | 39 | 运行代码,访问 http://127.0.0.1:8088/docs 即可看到生成了如下两个接口。 40 | 41 | ``` 42 | /bot/getName 43 | /bot/sayHello 44 | ``` 45 | 46 | ## 自定义路由 47 | 48 | 接口的路由将默认使用**控制器类名**以及**方法名**组成,如果需要自定义路由,在方法装饰器 route 传入 router_path 参数即可。 49 | 50 | ```python 51 | @server.route(method='get', router_path='/custom/getBotName') 52 | async def get_name(self): 53 | ... 54 | ``` 55 | 56 | ## 请求头密钥 57 | 58 | 在创建 HttpServer 时传入 auth_key 参数,则在调用接口时,需要在请求头(Header)里添加 `authKey` 字段并匹配参数的值,才允许访问。 59 | 60 | ```python 61 | server = HttpServer(..., auth_key='my_auth_key') 62 | ``` 63 | 64 | ## FastApi 扩展 65 | 66 | AmiyaBot 仅对 FastApi 的路由注册做了简易的封装。如需要扩展其用法,可获取 app 67 | 实例后参考[官方文档](https://fastapi.tiangolo.com/)进一步使用。 68 | 69 | ```python 70 | server = HttpServer() 71 | app: FastAPI = server.app 72 | ``` 73 | -------------------------------------------------------------------------------- /docs/develop/plugin/addDoc.md: -------------------------------------------------------------------------------- 1 | # 添加插件文档 2 | 3 | 你应该添加一个文档并详细描述插件的使用方法 4 | 5 | ## 添加一个 markdown 文档 6 | 7 | ```text {6,7} 8 | Amiya-Bot 9 | ├── pluginsDev 10 | │ ├── myPlugin 11 | │ │ ├── __init__.py 12 | │ │ ├── main.py 13 | │ │ ├── README.md 14 | │ │ └── HOWTOUSE.md 15 | │ ... 16 | ... 17 | ``` 18 | 19 | demo 允许直接使用 markdown 文件路径作为文档,只需要把路径传入到 **PluginInstance** 对象的 `document` 参数。 20 | 21 | ## 添加使用指引文档 22 | 23 | 若使用了 [AmiyaBotPluginInstance](/develop/plugin/amiyaBotPluginInstance.html) 24 | 对象创建插件,可使用参数 `instruction`,其作用是当 bot 的用户在使用 “查看功能指引” 25 | 类的指令时,向其展示 `instruction` 的内容。`document` 更偏向于提供给 bot 26 | 的部署者查看的文档。在没有配置 `instruction` 时,“查看功能指引” 将返回 `document` 的内容。 27 | 28 | ```python 29 | import os 30 | 31 | from amiyabot import PluginInstance, AmiyaBotPluginInstance 32 | 33 | plugin_dir = os.path.dirname(__file__) 34 | 35 | bot = PluginInstance( 36 | document=f'{plugin_dir}/README.md' 37 | ) 38 | # 或 39 | bot = AmiyaBotPluginInstance( 40 | document=f'{plugin_dir}/README.md', 41 | instruction=f'{plugin_dir}/HOWTOUSE.md' 42 | ) 43 | ``` 44 | 45 | ## 直接在参数内编写 46 | 47 | ::: warning 提示
48 | 我们不推荐这种做法,除非你的插件文档只有少量文本。 49 | ::: 50 | 51 | ```python 52 | bot = PluginInstance( 53 | document=''' 54 | ... 55 | ''' 56 | ) 57 | ``` 58 | -------------------------------------------------------------------------------- /docs/develop/plugin/amiyaBotPluginInstance.md: -------------------------------------------------------------------------------- 1 | # AmiyaBotPluginInstance 2 | 3 | AmiyaBotPluginInstance 是 [兔兔-v6](/guide/deploy/) 项目中的对插件类 PluginInstance 的扩展实现。使用该类创建插件时,能够获得更多的能力。 4 | 5 | 在 demo 项目里导入 `AmiyaBotPluginInstance` 创建插件。 6 | 7 | ```python 8 | from core import AmiyaBotPluginInstance 9 | 10 | bot = AmiyaBotPluginInstance( 11 | name='我的插件', 12 | version='1.0', 13 | plugin_id='my-plugin', 14 | description='我的第一个插件', 15 | channel_config_default=..., 16 | channel_config_schema=..., 17 | global_config_default=..., 18 | global_config_schema=..., 19 | deprecated_config_delete_days=..., 20 | ) 21 | ``` 22 | 23 | AmiyaBotPluginInstance 继承了 PluginInstance,并且拥有以下新参数和方法 24 | 25 | ### 参数 26 | 27 | | 参数名 | 类型 | 释义 | 默认值 | 28 | |-------------------------------|-------------------|------------------------------------------------------------|------| 29 | | instruction | str | [使用指引文档](/develop/plugin/addDoc.html#添加使用指引文档) | None | 30 | | requirements | List[Requirement] | [插件依赖](/develop/plugin/amiyaBotPluginInstance.html#添加插件依赖) | None | 31 | | channel_config_default | str | 频道级别配置默认值 | None | 32 | | channel_config_schema | str | 频道级别配置表单的 JsonSchema | None | 33 | | global_config_default | str | 全局级别配置默认值 | None | 34 | | global_config_schema | str | 全局级别配置表单的 JsonSchema | None | 35 | | deprecated_config_delete_days | int | 旧配置项失效的天数 | 7 | 36 | 37 | - 默认值和 JsonSchema 传入的值均为字符串,可以是 JSON 字符串或 `json` 文件路径。(默认值允许使用 `yaml` 文件路径) 38 | - 在控制台中点击 `重置为默认` 时会使用默认值的 JSON 数据覆盖,创建新配置项时使用默认值的 JSON 数据填充。 39 | - 如果提供了 JsonSchema,将会使用 JsonSchema 创建表单界面,否则使用默认值的 JSON 数据。 40 | - 如果提供了 JsonSchema,必须同时提供默认值数据。 41 | 42 | ```python 43 | plugin_dir = os.path.dirname(__file__) 44 | 45 | bot = AmiyaBotPluginInstance( 46 | channel_config_default=f'{plugin_dir}/config.yaml', 47 | channel_config_schema=f'{plugin_dir}/jsonSchema.json' 48 | ) 49 | ``` 50 | 51 | ## 使用 JsonSchema 对接控制台 52 | 53 | 你可以通过**对接控制台**使用户能够使用控制台的界面管理你的插件。如下所示。 54 | 55 | ![](../../assets/console/plugin3.png) 56 | 57 | 请阅读 [介绍文档](/develop/plugin/jsonSchema) 了解如何编辑 jsonSchema.json 文件。 58 | 59 | ### get_config 60 | 61 | 读取一个指定名称的配置项,如果没有频道级别的配置则返回同名全局配置,如果也没有全局配置,返回 `None`。传入 `channel_id=None` 62 | 可以直接读取全局配置。 63 | 64 | | 参数名 | 类型 | 释义 | 默认值 | 65 | |-------------|-----|------|------| 66 | | config_name | str | 配置名称 | | 67 | | channel_id | str | 频道ID | None | 68 | 69 | ```python 70 | config_value = bot.get_config('name', channel_id='...') 71 | ``` 72 | 73 | ### set_config 74 | 75 | 写入配置,传入 `channel_id=None` 可以强制指定写入全局配置。 76 | 77 | | 参数名 | 类型 | 释义 | 默认值 | 78 | |--------------|-----|------------------------|------| 79 | | config_name | str | 配置名称 | | 80 | | config_value | Any | 配置值,仅支持可被 JSON 序列化的值类型 | | 81 | | channel_id | str | 频道ID | None | 82 | 83 | ```python 84 | bot.set_config('name', 'value', channel_id='...') 85 | ``` 86 | 87 | ### 说明 88 | 89 | 插件加载时会进行下面的校验,校验不通过则会报错: 90 | 91 | - 提供了 schema 则必须提供对应的 default,反之则不必。 92 | - 如果给出了 schema,则会用 schema 对提供的 default 进行校验。 93 | 94 | 当有下列需求的时候,建议考虑提供 schema 文件: 95 | 96 | - 您想要使用下拉列表框。schema 中指定 enum 元素时,界面会生成下拉列表框。 97 | - 您想要对用户的配置进行校验,如果不满足条件时输出提示。 98 | 99 | 提供 `channel_config_default` 时,界面可以新建频道配置。 100 | 101 | 插件初次安装初次加载时,会将 `global_config_default` 作为默认全局配置写入数据库。
102 | 该过程发生在构造函数,因此您如果需要对全局配置进行初始化操作,您需要在您的**插件实例**的构造函数,或者 install 函数中进行。 103 | 104 | ## 添加插件依赖 105 | 106 | 当插件需要在别的插件的基础上运行,可在 requirements 参数内传入 `Requirement` 类的列表,当插件安装时,会从插件市场服务尝试寻找对应的插件依赖并一同安装。 107 | 108 | **Requirement** 109 | 110 | | 参数名 | 类型 | 释义 | 默认值 | 111 | |-----------|------|---------|-------| 112 | | plugin_id | str | 插件ID | | 113 | | version | str | 版本号(可选) | None | 114 | | official | bool | 是否官方插件 | False | 115 | 116 | ```python 117 | from core import AmiyaBotPluginInstance, Requirement 118 | 119 | bot = AmiyaBotPluginInstance( 120 | requirements=[ 121 | Requirement('other-plugin'), 122 | Requirement('other-plugin2', '2.0'), 123 | ] 124 | ) 125 | ``` 126 | 127 | ::: tip 提示
128 | 插件添加依赖后,仅当全部依赖安装成功后,才会进行自身的安装。 129 | ::: 130 | -------------------------------------------------------------------------------- /docs/develop/plugin/build.md: -------------------------------------------------------------------------------- 1 | # 打包插件 2 | 3 | 插件推荐发布为 zip 压缩包 4 | 5 | ## 直接打包 6 | 7 | 将整个插件文件夹压缩为 zip 包即可。如果你的插件使用了第三方库,你可能需要将第三方库手动放进插件包内。 8 | 9 | ### 示例 10 | 11 | 如在插件内使用了库 `pypyodbc`,在本地 python 环境内找到 **pypyodbc.py**(有时候会是 package 文件夹),并拷贝进 zip 包内。 12 | 13 | ```python 14 | # main.py 15 | import pypyodbc 16 | 17 | ... 18 | ``` 19 | 20 | ```text {4} 21 | myPlugin.zip 22 | ├── __init__.py 23 | ├── main.py 24 | └── pypyodbc.py 25 | ``` 26 | 27 | 当 `main.py` 内的导入语句 `import pypyodbc` 被执行时,优先使用插件内的 pypyodbc 包。 28 | 29 | ::: warning 注意
30 | 若无法通过上述手段将第三方包添加进插件包,你的插件将可能不支持 31 | [可执行文件部署](/guide/deploy/getStarted/index.html#通过可执行文件部署) 32 | 。你可以在你的插件文档内注明,并让代码部署的用户使用 `pip install xxx` 安装第三方依赖。 33 | ::: 34 | 35 | ## 使用脚本打包 36 | 37 | 如果你是在 demo 下开发的插件,运行脚本 run_build.py 即可自动打包。 38 | 39 | ```bash 40 | python run_build.py --type plugins 41 | ``` 42 | 43 | ::: warning 注意
44 | 脚本打包尚处于试验阶段,你仍然需要手动添加第三方包进插件 45 | ::: 46 | -------------------------------------------------------------------------------- /docs/develop/plugin/create.md: -------------------------------------------------------------------------------- 1 | # 创建插件 2 | 3 | 在 pluginsDev 目录内,创建一个 Python package 形式的模块。为了防止加载插件时的**全局环境变量污染**。你的业务逻辑必须在另一个入口文件内进行。 4 | 5 | 创建入口文件 `main.py` 6 | 7 | ```text {3,4,5} 8 | Amiya-Bot 9 | ├── pluginsDev 10 | │ ├── myPlugin 11 | │ │ ├── __init__.py 12 | │ │ └── main.py 13 | │ ... 14 | ... 15 | ``` 16 | 17 | ## 编写插件程序 18 | 19 | 在 `main.py` 内编写插件的注册程序 20 | 21 | ```python 22 | from amiyabot import PluginInstance 23 | 24 | bot = PluginInstance( 25 | name='我的插件', 26 | version='1.0', 27 | plugin_id='my-plugin', 28 | description='我的第一个插件' 29 | ) 30 | ``` 31 | 32 | `PluginInstance` 对象继承了工厂类 `BotHandlerFactory`,这意味着你完全可以按照 [开发指南](/develop/basic/messageHandler) 33 | 去编写你的插件功能。 34 | 35 | ```python 36 | @bot.on_message(keywords='hello') 37 | async def _(data: Message): 38 | return Chain(data).text(f'hello, {data.nickname}') 39 | 40 | @bot.on_event('GUILD_CREATE') 41 | async def _(event: Event, instance: BotAdapterProtocol): 42 | ... 43 | ``` 44 | 45 | 这些消息响应器都会在插件被加载时注册到主体程序中。 46 | 47 | ## 插件内静态资源的使用 48 | 49 | 如果你的插件包含静态资源,在读取它们时,应该以插件的绝对目录读取。 50 | 51 | ```text {6} 52 | Amiya-Bot 53 | ├── pluginsDev 54 | │ ├── myPlugin 55 | │ │ ├── __init__.py 56 | │ │ ├── main.py 57 | │ │ └── file.txt 58 | │ ... 59 | ... 60 | ``` 61 | 62 | ```python 63 | # main.py 64 | import os 65 | 66 | plugin_dir = os.path.dirname(__file__) 67 | file = open(f'{plugin_dir}/file.txt') 68 | ``` 69 | 70 | ## 导出插件的实例 71 | 72 | 在 `__init__.py` 内导出插件的入口,命名为 bot。这个命名是固定的,即使 main 内部的 73 | PluginInstance 实例变量名不为 bot,在导出时都必须使用 `as bot` 重命名。 74 | 75 | ```python 76 | from .main import bot 77 | ``` 78 | 79 | ::: danger 注意
80 | 请不要在 `__init__.py` 81 | 内编写多余的代码,我们希望这个文件有且只有上面的一行。插件在加载时,会临时添加插件目录为系统路径,这会使主模块的一些全局一等对象污染主体程序,导致不可预测的后果。 82 | ::: 83 | -------------------------------------------------------------------------------- /docs/develop/plugin/debug.md: -------------------------------------------------------------------------------- 1 | # 调试插件 2 | 3 | 调试插件的方法有很多种,一般来说,你可以直接打包插件然后放到主项目中加载并使用来观察效果,显然这不够效率。AmiyaBot 4 | 提供了 [测试实例](/develop/basic/testInstance),在主项目中,有现成的示例脚本。 5 | 6 | ## 在测试脚本中调试 7 | 8 | 在 兔兔-v6 根目录下的 **run_test.py** 内,修改如下位置的代码。 9 | 10 | ```python 11 | # 显式导入插件开发目录,可以在编辑器 DEBUG 调试。 12 | from pluginsDev.src.user import bot as plugin 13 | 14 | 15 | async def install_plugin(): 16 | # 导入插件 17 | bot.install_plugin(plugin) 18 | # 直接导入插件 zip 包 19 | # bot.install_plugin('plugins/amiyabot-arknights-operator-1.5.zip', extract_plugin=True) 20 | ``` 21 | 22 | 运行 `python run_test.py`,访问测试网址并使用。详见 [测试实例](/develop/basic/testInstance) 23 | -------------------------------------------------------------------------------- /docs/develop/plugin/env.md: -------------------------------------------------------------------------------- 1 | # 准备开发环境 2 | 3 | 插件并不强制要求在 demo 的项目下开发,如果插件**不需要使用 demo 的内置模块**,那么你可以在自己任意的目录内开发而不需要克隆 4 | demo 项目以及插件仓库的代码。 5 | 6 | 以下说明默认在 demo 项目内。 7 | 8 | ## 克隆仓库 9 | 10 | 克隆 兔兔-v6 11 | 12 | ```bash 13 | git clone https://github.com/AmiyaBot/Amiya-Bot.git 14 | ``` 15 | 16 | 在 demo 项目内克隆插件开发仓库 17 | 18 | ```bash 19 | cd Amiya-Bot 20 | git clone https://github.com/AmiyaBot/Amiya-Bot-plugins.git pluginsDev 21 | ``` 22 | 23 | 此时的目录结构应为 24 | 25 | ``` 26 | Amiya-Bot 27 | ├── pluginsDev 28 | │ │ 29 | │ ... 30 | ... 31 | ``` 32 | 33 | 建议安装 兔兔-v6 的依赖,如果**不需要使用 demo 的内置模块**或是你在自己的目录内开发插件。那么只需要安装 amiyabot 即可。 34 | 35 | ```bash 36 | pip install amiyabot 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/develop/plugin/index.md: -------------------------------------------------------------------------------- 1 | # 简要说明 2 | 3 | 本文档将讲述如何为 [兔兔-v6](/guide/deploy/) 开发插件。 4 | -------------------------------------------------------------------------------- /docs/develop/plugin/jsonSchema.md: -------------------------------------------------------------------------------- 1 | # JsonSchema 解释 2 | 3 | 本篇介绍如何使用 [draft-07](http://json-schema.org) 版本的 JsonSchema 4 | 规范编辑 [插件对接控制台的配置文件](/develop/plugin/amiyaBotPluginInstance)。 5 | 6 | ```json 7 | { 8 | "$schema": "http://json-schema.org/draft-07/schema#", 9 | "type": "object", 10 | "required": [], 11 | "properties": {} 12 | } 13 | ``` 14 | 15 | - `required`:必填字段(暂未支持前端校验,敬请期待...) 16 | - `properties`:字段配置 17 | 18 | ## 基本配置 19 | 20 | 字段定义在 **properties** 对象里: 21 | 22 | - ``:**配置名称**,是使用 [get_config](/develop/plugin/amiyaBotPluginInstance.html#get-config) 方法时的参数 23 | - `.type`:类型 24 | - `.title`(可选):表单标题,不配置则使用 **config_name** 25 | - `.description`(可选):表单tips,鼠标移动到页面的问号图标时显示的内容 26 | - `.default`(可选):默认值,需按照类型填写。 27 | 28 | 示例 29 | 30 | ```json 31 | { 32 | "properties": { 33 | "imagesCachePath": { 34 | "title": "图片缓存目录", 35 | "description": "图片缓存的目录路径,可以为绝对路径", 36 | "type": "string", 37 | "default": "./imagesCache" 38 | } 39 | } 40 | } 41 | ``` 42 | 43 | ## 文本输入框 44 | 45 | 默认值 `default` 的类型为字符串 46 | 47 | ```json 48 | { 49 | "properties": { 50 | "": { 51 | "type": "string", 52 | "default": "text" 53 | } 54 | } 55 | } 56 | ``` 57 | 58 | ## 数字输入框 59 | 60 | 默认值 `default` 的类型为数字 61 | 62 | - `minimum`(可选): 可输入的**最小值** 63 | - `maximum`(可选): 可输入的**最大值** 64 | 65 | 当 type 为 integer 时,只能输入整数,为 number 时可以输入浮点数。 66 | 67 | ```json 68 | { 69 | "properties": { 70 | "": { 71 | "type": "integer", 72 | "minimum": -10, 73 | "maximum": 20, 74 | "default": 0 75 | }, 76 | "": { 77 | "type": "number", 78 | "default": 0.5 79 | } 80 | } 81 | } 82 | ``` 83 | 84 | ## 切换按钮 85 | 86 | 默认值 `default` 的类型为布尔型 87 | 88 | ```json 89 | { 90 | "properties": { 91 | "": { 92 | "type": "boolean", 93 | "default": false 94 | } 95 | } 96 | } 97 | ``` 98 | 99 | ## 下拉选择框 100 | 101 | 下拉选择框不需要 `type` 字段,默认值 `default` 的类型为内容的值类型 102 | 103 | ```json 104 | { 105 | "properties": { 106 | "": { 107 | "enum": [ 108 | "option1", 109 | "option2", 110 | "option3" 111 | ], 112 | "default": "option2" 113 | } 114 | } 115 | } 116 | ``` 117 | 118 | ## 日期时间选择器 119 | 120 | 当 `type` 配置为 `string` 时,若配置了对应的 `format` 字段,可更改为日期时间选择器。
121 | 默认值 `default` 的类型为**字符串或数值** 122 | 123 | ```json 124 | { 125 | "properties": { 126 | "": { 127 | "type": "string", 128 | "format": "datetime" 129 | } 130 | } 131 | } 132 | ``` 133 | 134 | ### format 选项 135 | 136 | 配置相应的 format 以使用不同种类的选择器 137 | 138 | - **date**:日期 `YYYY-MM-DD` 139 | - **time**:时间 `HH:mm:ss` 140 | - **datetime**:日期时间 `YYYY-MM-DD HH:mm:ss` 141 | - **date-range**:日期范围 `[ YYYY-MM-DD, YYYY-MM-DD ]` 142 | - **time-range**:时间范围 `[ HH:mm:ss, HH:mm:ss ]` 143 | - **datetime-range**:日期时间范围 `[ YYYY-MM-DD HH:mm:ss, YYYY-MM-DD HH:mm:ss ]` 144 | 145 | 当使用范围选择器时,数据为数组类型,代表范围,如 146 | 147 | ```json 148 | [ 149 | "2023-05-20 08:00:00", 150 | "2023-05-21 16:00:00" 151 | ] 152 | ``` 153 | 154 | ## 动态输入-值数组 155 | 156 | 如果你需要 `get_config` 方法返回 `[value1, value2, value3, ...]` 形式的值数值,可以使用动态输入值数组。
157 | 默认值 `default` 的类型为数组 158 | 159 | - `type` 配置为 `array` 160 | - `items` 为数组配置 161 | - `type`:值类型,仅支持 `string`、`integer`、`number` 以及 [object](#动态输入-对象数组) 162 | 163 | ```json 164 | { 165 | "properties": { 166 | "": { 167 | "type": "array", 168 | "items": { 169 | "type": "string" 170 | } 171 | } 172 | } 173 | } 174 | ``` 175 | 176 | ## 动态输入-对象数组 177 | 178 | 如果你需要 `get_config` 方法返回 `[{...}, {...}, {...}, ...]` 形式的值数值,可以使用动态输入对象(字典)数组。
179 | 默认值 `default` 的类型为数组 180 | 181 | - `type` 配置为 `array` 182 | - `items` 为数组配置 183 | - `type` 配置为 `object` 184 | - `properties` 根据上文 [基本配置](#基本配置) 185 | 添加 [文本输入框](#文本输入框)、[数字输入框](#数字输入框)、[切换按钮](#切换按钮)、[下拉选择框](#下拉选择框) 186 | 或 [日期&时间选择器](#日期时间选择器) 187 | 188 | ```json 189 | { 190 | "properties": { 191 | "": { 192 | "type": "array", 193 | "items": { 194 | "type": "object", 195 | "properties": {} 196 | } 197 | } 198 | } 199 | } 200 | ``` 201 | 202 | ## 子级对象 203 | 204 | 有时候有些复杂配置不能用只有一级的对象(字典)存放,使用子级对象组建多层的对象(字典)。 205 | 206 | - `type` 配置为 `object` 207 | - `properties` 根据上文 [基本配置](#基本配置) 添加**任意输入类型**或将 `type` 配置为 `object` 继续作为新的子级对象 208 | 209 | ```json 210 | { 211 | "properties": { 212 | "": { 213 | "type": "object", 214 | "properties": {} 215 | } 216 | } 217 | } 218 | ``` 219 | 220 | ### 示例 221 | 222 | ```json 223 | { 224 | "properties": { 225 | "user": { 226 | "type": "object", 227 | "properties": { 228 | "name": { 229 | "type": "string" 230 | }, 231 | "age": { 232 | "type": "integer" 233 | }, 234 | "attrs": { 235 | "type": "object", 236 | "properties": { 237 | "atk": { 238 | "type": "number" 239 | }, 240 | "def": { 241 | "type": "number" 242 | } 243 | } 244 | } 245 | } 246 | } 247 | } 248 | } 249 | ``` 250 | 251 | 以上配置调用 `bot.get_config()` 方法将返回以下内容 252 | 253 | ```json 254 | { 255 | "user": { 256 | "name": ..., 257 | "age": ..., 258 | "attrs": { 259 | "atk": ..., 260 | "def": ... 261 | } 262 | } 263 | } 264 | ``` 265 | -------------------------------------------------------------------------------- /docs/develop/plugin/life.md: -------------------------------------------------------------------------------- 1 | # 插件生命周期 2 | 3 | 你可以在插件被安装或卸载时执行一些操作,只需要继承 PluginInstance 并覆盖其方法。 4 | 5 | ```python 6 | from amiyabot import PluginInstance 7 | 8 | 9 | class MyPlugin(PluginInstance): 10 | def install(self): 11 | # 插件被安装时执行的操作 12 | ... 13 | 14 | def uninstall(self): 15 | # 插件被卸载时执行的操作 16 | ... 17 | 18 | 19 | bot = MyPlugin( 20 | name='我的插件', 21 | version='1.0', 22 | plugin_id='my-plugin', 23 | description='我的第一个插件' 24 | ) 25 | ``` 26 | -------------------------------------------------------------------------------- /docs/develop/plugin/publish.md: -------------------------------------------------------------------------------- 1 | # 发布到插件商店 2 | 3 | 访问 [控制台-插件商店](https://console.amiyabot.com/#/shop),点击【上传创意插件】完成流程即可发布到商店。 4 | 5 | ## 插件密钥 6 | 7 | 上传插件时需要输入一个**密钥**,在你更新或下架你的插件时,需要输入这个密钥校验。请牢记你的密钥。 8 | -------------------------------------------------------------------------------- /docs/develop/tools/databaseSupport.md: -------------------------------------------------------------------------------- 1 | # 数据库支持 2 | 3 | AmiyaBot 提供了 Sqlite 和 MySQL 数据库的 ORM 4 | 支持。基于 [peewee](https://github.com/coleifer/peewee) 5 | ,封装了部分表结构管理以及查询转换。日常使用的查询操作详见 [peewee文档](http://docs.peewee-orm.com/) 6 | 7 | ::: warning 温馨提示
8 | AmiyaBot 仅能提供有限的数据库支持,**推荐你使用自己的更优的数据库解决方案**。 9 | ::: 10 | 11 | ## Sqlite 12 | 13 | 对于轻量级机器人应用,Sqlite 足以应对大部分的日常操作,`connect_database` 方法默认创建 Sqlite 数据库。 14 | 15 | ```python 16 | from amiyabot.database import * # 引入数据库模块 17 | 18 | db = connect_database('database_name') # 创建或连接一个 Sqlite 数据库文件 19 | 20 | 21 | # 创建数据库基础模型,继承 ModelClass 获得 AmiyaBot 的扩展查询方法 22 | class BotBaseModel(ModelClass): 23 | class Meta: 24 | database = db 25 | 26 | 27 | # 创建表模型,使用 table 装饰器进行表结构管理,将会自动创建或更新表结构 28 | @table 29 | class TableName(BotBaseModel): 30 | field1 = CharField() 31 | field2 = IntegerField(null=True) 32 | 33 | 34 | TableName.select() # ORM 操作详见 peewee 文档 35 | ``` 36 | 37 | ## MySQL 38 | 39 | `connect_database` 参数设置 `mysql=True` 以及 `config` 即可更改为 MySQL 数据库。 40 | 41 | **可自动创建数据库。** 42 | 43 | ```python 44 | from amiyabot.database import * 45 | 46 | db = connect_database('database_name', is_mysql=True, config=MysqlConfig( 47 | host='127.0.0.1', 48 | port=3306, 49 | user='root', 50 | password='' 51 | )) 52 | ``` 53 | 54 | ## 表结构管理 55 | 56 | 在 table 装饰的表模型内增加或删除字段,启动程序时会自动修改到数据库表结构中。**暂不支持更新字段类型。** 57 | 58 | ```python 59 | @table 60 | class TableName(BotBaseModel): 61 | field1 = CharField() 62 | field2 = IntegerField(null=True) 63 | field3 = TextField(null=True) 64 | ... 65 | ``` 66 | 67 | ## 扩展查询 68 | 69 | 内置了部分扩展查询,方便日常使用。 70 | 71 | ### batch_insert 72 | 73 | 批量插入 74 | 75 | | 参数名 | 类型 | 释义 | 默认值 | 76 | |------------|-------------|--------|-----| 77 | | rows | List\[dict] | 数据列表 | | 78 | | chunk_size | int | 分片插入大小 | 200 | 79 | 80 | ```python 81 | data = [ 82 | {...}, 83 | {...}, 84 | {...}, ... 85 | ] 86 | 87 | TableName.batch_insert(data) 88 | ``` 89 | 90 | ### insert_or_update 91 | 92 | 插入或更新(适配Sqlite和MySQL) 93 | 94 | | 参数名 | 类型 | 释义 | 默认值 | 95 | |-----------------|------|--------------------|------| 96 | | insert | dict | 如果是插入的数据 | | 97 | | update | dict | 如果是更新的数据 | None | 98 | | conflict_target | list | 构成约束的列(仅Sqlite需要) | None | 99 | | preserve | list | 一个列的列表,其值应从原始插入中保留 | None | 100 | 101 | ## 查询转换工具 102 | 103 | ### convert_model 104 | 105 | 将查询结果转换为字典 106 | 107 | | 参数名 | 类型 | 释义 | 默认值 | 108 | |--------------|--------|-------------|-----| 109 | | model | | peewee 查询结果 | | 110 | | select_model | Select | peewee 查询对象 | | 111 | 112 | ```python 113 | data = convert_model(TableName.get_or_none()) 114 | ``` 115 | 116 | ### query_to_list 117 | 118 | 将查询结果转换为字典列表 119 | 120 | | 参数名 | 类型 | 释义 | 默认值 | 121 | |--------------|--------|-------------|-----| 122 | | query | list | peewee 查询结果 | | 123 | | select_model | Select | peewee 查询对象 | | 124 | 125 | ```python 126 | data = query_to_list(TableName.select()) 127 | ``` 128 | 129 | ### select_for_paginate 130 | 131 | 分页查询工具 132 | 133 | | 参数名 | 类型 | 释义 | 默认值 | 134 | |-----------|-------------|-------------|-----| 135 | | model | ModelSelect | peewee 查询对象 | | 136 | | page | int | 当前页 | | 137 | | page_size | int | 页行数 | | 138 | 139 | ```python 140 | data = select_for_paginate(TableName.select(), 1, 10) 141 | 142 | data['list'] # 查询结果 143 | data['total'] # 总条数 144 | ``` 145 | -------------------------------------------------------------------------------- /docs/develop/tools/httpRequests.md: -------------------------------------------------------------------------------- 1 | # 发送 HTTP 请求 2 | 3 | AmiyaBot 内置了异步的 HTTP 请求工具,基于 [aiohttp](https://github.com/aio-libs/aiohttp)。 4 | 5 | ::: danger 不推荐使用 requests 库
6 | requests 是著名的 python http 请求工具库。但其请求方法均为**同步**的。AmiyaBot 为异步程序,使用同步请求将会阻塞主线程运行。 7 | 8 | 如果是**无法干预的**同步请求行为,可以使用内置的线程池方法更变为异步。详见 [处理阻塞操作](/develop/advanced/blockingIO)。 9 | ::: 10 | 11 | 直接引入 `http_requests` 实例和 `download_async` 方法即可使用。 12 | 13 | ```python 14 | from amiyabot.network.httpRequests import http_requests 15 | from amiyabot.network.download import download_async 16 | 17 | await http_requests.get() 18 | await http_requests.post() 19 | await http_requests.post_form() 20 | await http_requests.post_upload() 21 | await http_requests.request() 22 | await download_async() 23 | ``` 24 | 25 | ## 返回值 26 | 27 | `http_requests` 的请求均返回**字符串**的请求结果(如果请求失败会返回空字符串),但有些不一样。这个 “字符串” 可以使用一些额外的属性。 28 | 29 | ### json 30 | 31 | 调用这个属性会尝试返回 json 格式化的 `responseText` 内容。 32 | 33 | ```python 34 | res = await http_requests.post('/interface', {...}) 35 | if res: 36 | data = res.json['data'] 37 | ``` 38 | 39 | ### response 40 | 41 | 调用这个属性可以返回请求结果(`aiohttp.ClientResponse` 的实例),可以获取请求的状态码和其他信息。 42 | 43 | ```python 44 | res = await http_requests.post('/interface', {...}) 45 | 46 | status = res.response.status 47 | ``` 48 | 49 | ### error 50 | 51 | 如果请求失败,可以调用这个属性获取异常(`Exception` 的实例)。 52 | 53 | ```python 54 | res = await http_requests.post('/interface', {...}) 55 | 56 | error = res.error 57 | ``` 58 | 59 | ## GET 请求 60 | 61 | ```python 62 | res: str = await http_requests.get() 63 | ``` 64 | 65 | | 参数名 | 类型 | 释义 | 默认值 | 66 | |-----------|-----|--------------------------------------------------------------------------------------|-----| 67 | | interface | str | 请求地址 | | 68 | | **kwargs | | [request 参数](https://github.com/aio-libs/aiohttp/blob/master/aiohttp/client.py#L316) | | 69 | 70 | ## POST 请求 71 | 72 | post 方法默认在请求头内添加 `'Content-Type': 'application/json'`,请求体**仅接受字典或列表类型数据**。 73 | 74 | ```python 75 | res: str = await http_requests.post() 76 | ``` 77 | 78 | | 参数名 | 类型 | 释义 | 默认值 | 79 | |-----------|------------|--------------------------------------------------------------------------------------|-----| 80 | | interface | str | 请求地址 | | 81 | | payload | dict, list | 请求体 | | 82 | | headers | dict | 追加的请求头 | | 83 | | **kwargs | | [request 参数](https://github.com/aio-libs/aiohttp/blob/master/aiohttp/client.py#L316) | | 84 | 85 | ## FORM 表单请求 86 | 87 | post_form 方法类似 post 方法。唯一不同的是请求体仅接受**字典类型**,发送请求时会被构建为 form data 表单数据。 88 | 89 | ```python 90 | res: str = await http_requests.post_form() 91 | ``` 92 | 93 | | 参数名 | 类型 | 释义 | 默认值 | 94 | |-----------|------|--------------------------------------------------------------------------------------|-----| 95 | | interface | str | 请求地址 | | 96 | | payload | dict | 请求体 | | 97 | | headers | dict | 追加的请求头 | | 98 | | **kwargs | | [request 参数](https://github.com/aio-libs/aiohttp/blob/master/aiohttp/client.py#L316) | | 99 | 100 | ## 文件上传 101 | 102 | 文件上传 post_upload 方法以 form 表单的方式提交文件。 103 | 104 | ```python 105 | res: str = await http_requests.post_upload() 106 | ``` 107 | 108 | | 参数名 | 类型 | 释义 | 默认值 | 109 | |------------|-------|--------------------------------------------------------------------------------------|------| 110 | | interface | str | 请求地址 | | 111 | | file | bytes | 文件 bytes | | 112 | | filename | str | 文件名 | file | 113 | | file_field | str | 表单数据中存放文件的字段名 | file | 114 | | payload | dict | 请求体 | | 115 | | headers | dict | 追加的请求头 | | 116 | | **kwargs | | [request 参数](https://github.com/aio-libs/aiohttp/blob/master/aiohttp/client.py#L316) | | 117 | 118 | ## 自定义请求 119 | 120 | 如果需要发送更多类型的请求,如 `PUT`、`PATCH`、`DELETE` 等,或需要自定义更多的请求场景,可使用 request 方法。 121 | 122 | ```python 123 | res: str = await http_requests.request() 124 | ``` 125 | 126 | | 参数名 | 类型 | 释义 | 默认值 | 127 | |--------------|------|--------------------------------------------------------------------------------------|------| 128 | | url | str | 请求地址 | | 129 | | method | dict | 请求方法 | post | 130 | | request_name | dict | 请求过程的 LOG 标识 | | 131 | | **kwargs | | [request 参数](https://github.com/aio-libs/aiohttp/blob/master/aiohttp/client.py#L316) | | 132 | 133 | ## 下载文件 134 | 135 | download_async 是提供的异步下载文件的方法。默认返回 bytes 类型的数据。 136 | 137 | ```python 138 | file: bytes = await download_async() 139 | ``` 140 | 141 | | 参数名 | 类型 | 释义 | 默认值 | 142 | |-----------|------|--------------------------------------------------------------------------------------|-------| 143 | | url | str | 请求地址 | | 144 | | headers | dict | 追加的请求头 | | 145 | | stringify | bool | 是否返回字符串结果 | False | 146 | | **kwargs | | [request 参数](https://github.com/aio-libs/aiohttp/blob/master/aiohttp/client.py#L316) | | 147 | 148 | ### 同步下载 149 | 150 | 如某些场景需要使用同步下载,可使用同模块中的 download_sync 方法。 151 | 152 | ```python 153 | from amiyabot.network.download import download_sync 154 | 155 | file: bytes = download_sync() 156 | ``` 157 | 158 | | 参数名 | 类型 | 释义 | 默认值 | 159 | |-----------|------|-----------------------------------------------------------------------------|-------| 160 | | url | str | 请求地址 | | 161 | | headers | dict | 追加的请求头 | | 162 | | stringify | bool | 是否返回字符串结果 | False | 163 | | progress | bool | 是否显示进度条 | False | 164 | | **kwargs | | [request 参数](https://github.com/psf/requests/blob/main/requests/api.py#L14) | | 165 | -------------------------------------------------------------------------------- /docs/develop/tools/httpSupport.md: -------------------------------------------------------------------------------- 1 | # Amiya HTTP 服务 2 | 3 | ![PyPI](https://img.shields.io/pypi/v/amiyahttp) 4 | 5 | 对 [FastAPI](https://fastapi.tiangolo.com/) 进行二次封装的简易 HTTP Web 服务 SDK 6 | 7 | ::: tip 温馨提示
8 | **2.0.5 版本起,amiyabot 不再内置 HTTP 服务组件。** 9 | 10 | 如果你正在使用 [amiyabot-2.0.4](https://pypi.org/project/amiyabot/2.0.4/) 11 | 及以前的版本,并希望使用原来内置的 HTTP 服务,请阅读 [旧版文档](/develop/old/httpSupport)。 12 | ::: 13 | 14 | ## 安装 15 | 16 | ```bash 17 | pip install amiyahttp 18 | ``` 19 | 20 | ## 简单实现 21 | 22 | POST 请求参数定义详见 FastAPI 文档。 23 | 24 | ```python 25 | import asyncio 26 | from pydantic import BaseModel 27 | from amiyahttp import HttpServer 28 | 29 | 30 | # 定义 POST 请求参数 31 | class UserModel(BaseModel): 32 | username: str 33 | nickname: str 34 | 35 | 36 | server = HttpServer(host='0.0.0.0', port=8088) 37 | 38 | 39 | @server.controller 40 | class Bot: 41 | @server.route(method='get') 42 | async def get_name(self): 43 | return 'AmiyaBot' 44 | 45 | @server.route(method='post') 46 | async def say_hello(self, params: UserModel): 47 | return server.response(message=f'hello, {params.nickname}') 48 | 49 | 50 | asyncio.run(server.serve()) 51 | ``` 52 | 53 | ### 自定义路由 54 | 55 | 接口的路由将默认使用**控制器类名**以及**方法名**组成,如果需要自定义路由,在方法装饰器 route 传入 router_path 参数即可。 56 | 57 | ```python 58 | @server.route(method='get', router_path='/custom/getBotName') 59 | async def get_name(self): 60 | ... 61 | ``` 62 | 63 | ## 加载插件 64 | 65 | HttpServer 类允许使用 use_plugin 方法加载插件 66 | 67 | ```python 68 | from amiyahttp.serverBase import ServerPlugin, ServerConfig 69 | 70 | class MyPlugin(ServerPlugin): 71 | def install(self, app: FastAPI, config: ServerConfig): ... 72 | 73 | plugin = MyPlugin() 74 | 75 | server = HttpServer(host='0.0.0.0', port=8088) 76 | server.use_plugin(plugin) 77 | ``` 78 | 79 | ## 基于请求头鉴权 80 | 81 | 导入 AuthKey 插件并实例化后加载进服务。调用接口时,需要在请求头里添加 `Authorization` 字段和值,才允许访问。 82 | 83 | 为了避免一些静态资源或无需鉴权的接口被拦截,可在 `allow_path` 参数里传入对应 url。 84 | 85 | ```python 86 | import asyncio 87 | from amiyahttp import HttpServer 88 | from amiyahttp.auth.authKey import AuthKey 89 | 90 | auth_key = AuthKey( 91 | auth_key='my_auth_key', 92 | headers_key='Authorization', 93 | allow_path=[ 94 | '/static', 95 | '/assets', 96 | ], 97 | ) 98 | 99 | server = HttpServer(host='0.0.0.0', port=8088) 100 | server.use_plugin(auth_key) 101 | ``` 102 | 103 | ## OAuth2 鉴权 104 | 105 | 导入 OAuth2 插件继承到一个新的类,并实现 `get_user_password` 方法,即可实现 OAuth2 鉴权。 106 | 107 | 在接口的方法参数里添加 `username: str = oauth2.authorized_user()`,表示该接口需要进行鉴权调用。 108 | 109 | ```python {23} 110 | from amiyahttp import HttpServer 111 | from amiyahttp.auth.oauth2 import OAuth2 112 | 113 | class OAuth2Plugin(OAuth2): 114 | # 返回用户加密之后的密码 115 | async def get_user_password(self, username: str) -> str: 116 | return '' 117 | 118 | 119 | oauth2 = OAuth2Plugin() 120 | 121 | server = HttpServer(host='0.0.0.0', port=8088) 122 | server.use_plugin(oauth2) 123 | 124 | 125 | @server.controller 126 | class Bot: 127 | @server.route(method='get') 128 | async def get_name(self): 129 | return 'AmiyaBot' 130 | 131 | @server.route(method='post') 132 | async def create_user(self, params: UserModel, username: str = oauth2.authorized_user()): 133 | # 创建密码 134 | pwd = oauth2.create_password('123456') 135 | ``` 136 | 137 | ## FastAPI 和 Uvicorn 扩展配置 138 | 139 | 通过使用 `ServerConfig` 类自定义 FastAPI 和 Uvicorn 的启动参数。只需在 `fastapi_options` 或 `uvicorn_options` 140 | 字典中定义相应的实例化参数即可(这些参数相当于传递给 FastAPI 或 Uvicorn 的 **kwargs)。 141 | 142 | ```python 143 | from amiyahttp import HttpServer, ServerConfig 144 | 145 | server = HttpServer( 146 | host='0.0.0.0', 147 | port=8088, 148 | config=ServerConfig( 149 | fastapi_options={...}, 150 | uvicorn_options={...}, 151 | ), 152 | ) 153 | ``` 154 | 155 | ### 获取 FastApi 实例 156 | 157 | 如需要扩展 FastApi 的用法,可获取实例后参考[官方文档](https://fastapi.tiangolo.com/)进一步使用。 158 | 159 | ```python 160 | server = HttpServer() 161 | app: FastAPI = server.app 162 | ``` 163 | -------------------------------------------------------------------------------- /docs/download.md: -------------------------------------------------------------------------------- 1 | --- 2 | aside: false 3 | --- 4 | 5 | 8 | 9 | # 下载 10 | 11 | [![amiyabot](https://img.shields.io/pypi/v/amiyabot)](https://pypi.org/project/amiyabot/#files) 12 | 13 | ```bash 14 | pip install amiyabot 15 | ``` 16 | 17 | ## 兔兔-v6 18 | 19 | | 操作系统 | 下载 | 备注 | 20 | |---------|------------------------------|------------------------------------------| 21 | | Windows | | 仅支持 Windows 10、Windows Server 2016 及以上系统 | 22 | -------------------------------------------------------------------------------- /docs/footstone: -------------------------------------------------------------------------------- 1 | *************************** 2 | 不要删除这个文件!!! 3 | DON'T DELETE THIS FILE!!! 4 | 正如文件名“基石”,这个文件包含了一些最基本的字符,以确保在字体压缩时压缩后的产物可以显示这些基本字符。 5 | 如果删除它,当网站拥有评论功能时,将会出现严重问题! 6 | 就算没有评论功能,留着它也没坏处么。 7 | 你还可以自己添加一些内容,如果你的站点要用到没有写在 Markdown 里的字的话。 8 | 本文件使用 WTFPL 授权,但恳请您保留这段说明及作者:Initial_heart。 9 | *************************** 10 | 11 | The quick brown fox jumps over the lazy dog. 12 | THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG. 13 | Innovation in China 中国智造,慧及全球 0123456789 14 | `~!@#$%^&*()-_=+,.<>/?;:'"[{]}\| 15 | ,。《》、?;:‘“”’【{】}、|·~!@#¥%……&*()-——=+© 16 | 一地在要工 上是中国同 和的有人我 主产不为这 民了发以经 17 | 本站大量使用了在 CC0 协议下授权的作品,衷心感谢这些作品的作者并向他们致以崇高的敬意。 18 | 时 分 秒 钟 点 19 | 凌晨 午夜 清晨 早上 上午 中午 下午 晚上 深夜 -------------------------------------------------------------------------------- /docs/guide/deploy/advanced/index.md: -------------------------------------------------------------------------------- 1 | # 说明 2 | 3 | 本部分文档可能只是对控制台暂未支持的部分的一种补充,文档中的内容可能不会一直维护,也不会一直有效,在不久的将来可能都会在控制台中实现。届时对应的文档也会从这里删去。当然,这并不是绝对的,部分功能可能无法或者不会在控制台中实现,那么控制台将可能会有指向这些文档的链接。目录名称“高级使用”仅是用来区分可以在控制台内直接实现的操作的,并无其他含义。 4 | 5 | 请理解:由于本部分的特殊性,我们可能不会高频率的维护这些文档以至于它们可能无法与最新的版本相匹配,甚至可能随时删除或停止维护这些文档。您使用过期文档导致生产事故等的情况我们不负任何责任,也不对其造成的影响负责。 6 | 7 | 如果您已阅读并理解,同意以上部分,则请您浏览左侧的目录跳转至您需要的部分开始阅读。 8 | -------------------------------------------------------------------------------- /docs/guide/deploy/advanced/mysql.md: -------------------------------------------------------------------------------- 1 | # 使用 Mysql 2 | 3 | 在 `config\database.yaml` 中可以配置使用的数据库,如需更改数据库类型为 `Mysql`,请按下面的配置说明进行配置: 4 | 5 | ```yaml 6 | mode: 'mysql' 7 | config: 8 | host: '数据库地址' 9 | port: 数据库端口 10 | user: '登录用户名' 11 | password: '数据库密码' 12 | ``` 13 | -------------------------------------------------------------------------------- /docs/guide/deploy/console/configure.md: -------------------------------------------------------------------------------- 1 | # 配置实例 2 | 3 | “实例”指的是机器人的账户,兔兔支持登录多个机器人账号同时使用,多个账号之间共享数据。 4 | 5 | > 简单来说就是“兔兔”是一个灵魂👻,你需要给她找一个合适的“身体”,才能和你在现实中对话。一个灵魂多个身体也不是什么奇怪的事对吧……(?) 6 | 7 | ## 部署实例 8 | 9 |

给兔兔找一个“身体”,重头戏,也是最难的部分来了!!!

10 | 11 | 选择你希望部署的实例: 12 | 13 | - [官方QQ群&频道机器人](/guide/deploy/instances/qqbot.md)(限制多,QQ官方推荐) 14 | - [KOOK机器人](/guide/deploy/instances/kook.md) 15 | - [LLOneBot QQ群机器人](/guide/deploy/instances/llonebot.md)(推荐) 16 | - [NapCatQQ QQ群机器人](/guide/deploy/instances/napcatqq.md)(推荐) 17 | - [~~CQ-Http QQ群机器人~~](/guide/deploy/instances/cqhttp.md)(不推荐) 18 | - [~~Mirai-api-http QQ群机器人~~](/guide/deploy/instances/mirai.md)(不推荐) 19 | 20 | ## 添加实例 21 | 22 | 在左侧导航选择“实例管理”,并点击“添加实例” 23 | 24 | ![](../../../assets/console/addBot.png) 25 | 26 | ## 运行实例 27 | 28 | 点击“保存并启动”运行实例,当实例状态为在线时,即启动成功。 29 | 30 | image 31 | 32 | ::: tip 温馨提示
33 | 实例的连接需要时间,通常只需要几秒钟不到。如果显示**离线**可以等待几秒再刷新页面。 34 | ::: 35 | 36 | ## 配置可控实例 37 | 38 | 配置时打开选项 `可控实例`,并填写一个群号。可接收到该实例的一些相关通知。 39 | 40 | image 41 | 42 | -------------------------------------------------------------------------------- /docs/guide/deploy/console/index.md: -------------------------------------------------------------------------------- 1 | # 连接控制台 2 | 3 | 兔兔在启动后会开启一个 HTTP 服务,默认端口为 8088。提供给 [控制台](https://console.amiyabot.com) 4 | 调用。你可以根据需要在启动前修改配置`config/server.yaml`。 5 | 6 | ```yaml 7 | host: 127.0.0.1 8 | port: 8088 9 | authKey: 10 | ``` 11 | 12 | authKey 为连接控制台时的密钥,默认不需要。 13 | 14 | ::: danger **危险**
15 | **当您试图将控制台暴露至公网时,请务必设定 authKey!**
16 | **如果不这么做,您的服务将可能面临极大的安全风险!因此造成的一切后果与项目组无关,由您自行承担!** 17 | ::: 18 | 19 | ::: warning **注意**
20 | **不推荐您使用纯数字,或是简单的数字、字母组合等弱口令作为 authKey(如 `123456`, `000000`, `abcdef` 等)。**
21 | **如果您坚持这么做,您的服务将可能面临较大的安全风险!因此造成的一切后果与项目组无关,由您自行承担!**
22 | **特别的,当您尝试使用纯数字的 authKey 时,由于 YAML 规范定义其为整数类型,您的 authKey 将可能因类型错误无法识别。如果您坚持使用纯数字的 authKey,请使用单引号 `''` 或双引号 `""` 将 authKey 括起。** 23 | ::: 24 | 25 | ## 连接 26 | 27 | 浏览器打开控制台 https://console.amiyabot.com,在主界面填入你的服务地址。
28 | 默认为 http://127.0.0.1:8088 29 | 30 | ![](../../../assets/console/link.png) 31 | 32 | 点击“测试并连接”,成功进入后即可开始配置。 33 | 34 | ## 公网/局域网访问 35 | 36 | host 配置为 `0.0.0.0` 即可让服务通过本机 IP 访问 37 | 38 | ```yaml 39 | host: 0.0.0.0 40 | ``` 41 | 42 | ::: danger **危险**
43 | **当您试图从公网连接至控制台时,请务必通过反向代理加密连接!**
44 | **如果不这么做,您的服务将面临极大的安全风险!因此造成的一切后果与项目组无关,由您自行承担!** 45 | ::: 46 | 47 | 我们的团队成员 Initial-heart 48 | 为你提供了 [一篇通过 Nginx 反向代理加密连接的博客](https://www.initbili.top/2022/84452dac2fe6/),你可以根据这篇博客对你的连接进行加密。 49 | -------------------------------------------------------------------------------- /docs/guide/deploy/console/plugin.md: -------------------------------------------------------------------------------- 1 | # 安装插件 2 | 3 | 选择安装你需要的功能插件 4 | 5 | ## 在插件商店安装插件 6 | 7 | 插件商店可以实时查看有新版本的插件,需要时可通过商店更新。 8 | 9 | ![](../../../assets/console/plugin.png) 10 | 11 | ## 通过插件包自动安装 12 | 13 | 插件通常是一个zip压缩包或是 Python Package 的形式,你可以将它放在 plugins 目录下,启动时可以自动安装。 14 | 15 | ## 管理插件 16 | 17 | 安装好的插件可以在**插件管理**查看,现在,你已经可以使用它们了。 18 | 19 | ![](../../../assets/console/plugin2.png) 20 | 21 | 部分插件可能存在需要配置的信息,可在插件配置选项卡查看并编辑(需插件支持)。 22 | 23 | ![](../../../assets/console/plugin3.png) 24 | 25 |

🎉 恭喜你,到这里你已经部署完成了!快去体验兔兔吧!🎉

26 | -------------------------------------------------------------------------------- /docs/guide/deploy/faq/PluginProblem.md: -------------------------------------------------------------------------------- 1 | # 插件常见问题 2 | 3 | 本章收录了用户在使用官方插件时向我们提问较多的问题。 4 | 5 | ## 公招图片识别没法用 6 | 7 | ::: danger 请注意
8 | 公招图片识别功能需要申请并配置相应的百度智能云 API 9 | ::: 10 | 11 | 请根据插件文档配置相关信息。 12 | 13 | > 我不知道如何申请百度云 api 14 | 15 | + 请自行百度或联系百度智能云的支持服务。 16 | 17 | ## 如何给兔兔添加表情 18 | 19 | + 对应的文件位置在 `plugins/amiyabot-user*/face` 下,直接将图片文件扔到文件夹内即可。 20 | 21 | ## 代码部署后部分插件无法正常产生图片 22 | 23 | + 在安装完依赖后 需要额外安装playwright的chromium及其依赖 24 | + 对于windows: 25 | ```shell 26 | playwright install chromium 27 | ``` 28 | + 对于linux: 29 | ```shell 30 | playwright install --with-deps chromium 31 | ``` 32 | 33 | ::: danger 注意
34 | 若使用的操作系统不在 [官方支持列表](/guide/deploy/getStarted/index.html) 中,您可能无法正确执行该操作,也无法获得官方的任何支持。 35 | ::: 36 | 37 | ## 有时候公招图/专精材料图显示不完整 38 | 39 | 偶现该情况是正常现象,这与设备性能等因素有关,通常再请求一次即可正常返回图片。 40 | 41 | ## 抽卡时出现了(按游戏卡池发布顺序来说)不可能出现的新干员 42 | 43 | 请理解为卡池在现在复刻了。复刻的卡池中显然会出现任何非限定或特殊干员。 44 | 45 | ## 抽卡时出现了黑色的人物条/出现了限定/赠送/肉鸽干员 46 | 47 | + 可以前往控制台中的干员设置设定干员的限定属性(黑色的条一般是各个预备干员) 48 | 49 | > 可是我的各个限定干员都已经被设置为不可抽取了 50 | 51 | + 有时你可能更新了卡池却没有更新干员数据也会导致这个问题 52 | + 此时重启兔兔本体或点击按钮【应用干员设置】即可更新干员数据 53 | -------------------------------------------------------------------------------- /docs/guide/deploy/faq/commonProblem.md: -------------------------------------------------------------------------------- 1 | # 常见问题 2 | 3 | 本章收录了用户在部署/使用过程中向我们提问较多的问题。 4 | 5 | 作者:[晓月君](https://github.com/XiaoYue-Kun)
6 | 修饰:[Chino酱](https://github.com/vivien8261) 7 | 8 | ## 我看不懂什么是克隆仓库/代码部署的指令会报错 9 | 10 | + 你是否在考虑使用可执行文件部署而不是代码部署? 11 | + 请注意文档中提供的“使用可执行文件部署”与“使用代码部署”任选其一进行即可,执行完即可进入下一步骤,而不是两者都要进行。 12 | 13 | ## 使用可执行文件部署时,兔兔的窗口闪现了一下/出现了一小段时间又消失了(闪退) 14 | 15 | ### git 未正确配置 16 | 17 | 请使用组合键 `win+R` 输入 `cmd` 后回车,在跳出来的黑色框框中输入 `git` 后回车,如果显示 18 | 19 | ``` 20 | 'git'不是内部或外部命令,也不是可运行的程序或批处理文件。 21 | ``` 22 | 23 | 通常情况下,这是 git 未正确安装导致的,可能是由于**你没有认真看文档**根本没有安装 git 24 | 所导致。请根据文档[安装 git](/guide/deploy/getStarted/index.html#安装-git) 25 | 26 | 安装完成后,再次重复上述操作,此时应该会显示如下的文本,这就证明你配置好了 git,可以再次尝试打开可执行文件了。 27 | 28 | ``` 29 | usage: git [-v | --version] [-h | --help] [-C ] [-c =] 30 | [--exec-path[=]] [--html-path] [--man-path] [--info-path] 31 | [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare] 32 | [--git-dir=] [--work-tree=] [--namespace=] 33 | [--super-prefix=] [--config-env==] 34 | [] 35 | 36 | These are common Git commands used in various situations: 37 | 38 | start a working area (see also: git help tutorial) 39 | clone Clone a repository into a new directory 40 | init Create an empty Git repository or reinitialize an existing one 41 | 42 | work on the current change (see also: git help everyday) 43 | add Add file contents to the index 44 | mv Move or rename a file, a directory, or a symlink 45 | restore Restore working tree files 46 | rm Remove files from the working tree and from the index 47 | 48 | ... 49 | ``` 50 | 51 | > 我很确定我已经安装了git,但是我在黑框内输入git后还是会显示“不是内部或外部命令” 52 | 53 | 这个现象大概率是因为设备的环境变量没有配置好导致的,请参考 [此文章](https://blog.csdn.net/ZSQ717/article/details/123095769) 54 | 尝试将 git 的路径添加入环境变量中再次尝试开头的操作。 55 | 56 | ### 资源包没能完成下载 57 | 58 | > 我在窗口最上方看到了一些进度条,可是没能跑完就闪退了 59 | 60 | + 请检查你的网络连接或是否开启了代理软件。 61 | + 若你有意或无意地导致了 `resource/gamedata` 文件夹内的内容产生了变动,可能导致无法更新。直接删除整个 `resource/gamedata` 62 | 文件夹重新启动程序即可 63 | 64 | ## 启动时弹窗提示“无法定位程序输入点...” 65 | 66 | + 你是否在使用 win7 或较老的 WindowsServer 版本? 67 | + 就结论而言 win7 或较老的 WindowsServer 版本无法运行兔兔 68 | 原因是 node 版本不兼容 69 | 推荐升级 win10(若情况允许)或者使用云服务器部署/更换云服务器镜像 70 | 71 | ## 无法进入控制台 72 | 73 | > 我尝试进入控制台时出现了 `ERR_NETWORK 服务器异常` 74 | 75 | + 检查浏览器顶端的地址栏 76 | 通常,地址栏中协议(也就是网址最开头的http/https)应该使用http 77 | 如果你的网址以https开头,请改为http后再重新尝试访问 78 | 79 | + 部分内核的浏览器可能会拦截公网对私网不安全的访问请求 80 | + 打开 tab 页面 `chrome://flags/#block-insecure-private-network-requests` 81 | + 将 `Block insecure private network requests` 设置为 `Disabled`, 然后重启 82 | ![zukVk6.png](https://s1.ax1x.com/2022/11/18/zukVk6.png) 83 | + 若你访问控制台的设备与运行兔兔的设备不是同一台设备 84 | 你需要修改兔兔本体的一些设置 85 | + 前往兔兔的`config/server.yaml` 86 | + 将`host`的值修改为`0.0.0.0` 87 | + 重新启动兔兔 88 | 89 | > 我不知道服务地址应该填什么 90 | 91 | + 如果你访问控制台的设备与部署兔兔的设备为同一台的话,通常你应该填写的就是`http://127.0.0.1:8088`,而服务密钥留空 92 | + 如果你访问控制台的设备与部署兔兔的设备不是同一台,但是在同一个局域网内(通常指在同一个家里) 93 | + 参照[文档](/guide/deploy/console/index.html#公网-局域网访问)将 `host` 修改为 `0.0.0.0` 94 | + 参考[此文章](https://jingyan.baidu.com/article/ad310e80fd60c65949f49e9f.html)查询你部署兔兔的设备的局域网ip(通常是以 95 | 192 开头的一串数字) 96 | + 控制台中应填写 `http://[你查询到的ip]:8088` 97 | + 而服务密钥留空 98 | + 如果你将兔兔部署在云服务器上,在另一台设备上访问控制台,那么事情将会变得有些棘手,首先你需要参照上面的指示将 `host` 99 | 修改为 `0.0.0.0`,其次你需要给云服务器运营商的防火墙设置一个入站规则(关于如何做到这一点,请自行百度),通常端口是 100 | 8088,协议为tcp,并且操作系统内也需要设置入站规则(也请自行百度) 101 | + 提示:通过公网访问,可能有设备被攻击的风险,请自行配置服务密钥(在 `config/server.yaml` 中修改 `authKey` 102 | 的值并填入控制台的服务密钥中)。更进一步,推荐使用Nginx反代服务提供更高的安全性,请参考[文档](/guide/deploy/console/index.html#公网-局域网访问) 103 | 104 | ## 控制台中实例无法连接 105 | 106 | 由于作者仅涉足过mirai,本处仅将提供mirai相关问题的解决思路,不过部分解决思路也可用在gocq中 107 | 108 | 我们先来对配置单的具体内容进行一些解释 109 | 110 | + APP ID:mirai登陆的qq号,也就是你bot的qq号 111 | + TOKEN:对mirai来说,为`mirai/config/net.mamoe.mirai-api-http/settings.yml`中`verifyKey`的值 112 | + 适配器类型:通常你**应该**选择`CQ-Http`或是`Mirai-api-http`**而不是**`QQ-Bot` 113 | + 可控实例:是否将一些运行信息发送至特定群组 114 | (若是勾选了,控制台群组id应为你希望运行信息出现在的群聊的群聊号中) 115 | + Host地址:如提示所示,如果是同一台设备的话 填写127.0.0.1 116 | + HTTP端口:`mirai/config/net.mamoe.mirai-api-http/settings.yml`中`http`下`port`的值 117 | + WS端口:`mirai/config/net.mamoe.mirai-api-http/settings.yml`中`ws`下`port`的值 118 | (如果你参考的是初心佬的文章,那这两项应该分别为`8080`和`8060`) 119 | 120 | 以下是兔兔的窗口中可能出现的报错信息以及相应处理方法 121 | 122 | ### 指定bot不存在 123 | 124 | 请检查mirai是否正确登陆了bot的qq 125 | 126 | ### Auth Key错误 127 | 128 | rt,检查mirai本体配置中authKey的值与控制台填写的是否一致 129 | 130 | ### Cannot connect to mirai-api-http websocket server 131 | 132 | + 检查mirai是否启动 133 | + 检查mirai-api-http中host地址与两个端口填写是否有误 134 | + 常见错误为**看错**并填写错端口(如8080与8060看混 或者修改了mah的配置却未更改控制台实例配置单) 135 | 136 | ### Got code 401 137 | 138 | 适配器类型**应该是**`Mirai-api-http`或者`CQ-Http`**而不是**`QQ-Bot` 139 | 140 | ### 无效参数 141 | 142 | 实例配置单中的qq号是否填写错误了 143 | 144 | ## mcl无法正常启动 145 | 146 | **温馨提示:对mcl一切配置文件的更改都应该在mcl不在运行的情况下进行** 147 | 148 | ### 系统找不到指定的路径 149 | 150 | + mcl处于的路径中不能有任何中文字符(包括汉字与中文标点) 151 | + 请将mcl-installer转移至一个没有中文字符的路径下重新安装 152 | 153 | > 我很确定我的路径中没有中文字符 154 | 155 | + 你是否人为移动了(有意或无意)mcl所处文件夹或者其子文件夹? 156 | + 对小白来说,如果你想移动mirai,最好的方法其实是将mcl-installer移动到别处重新安装 157 | 并将原来的config以及plugins文件夹移动到新安装的mirai中**覆盖** 158 | 159 | ### 当前qq版本太低 160 | 161 | + 升级mcl本体 162 | + 将协议换为IPAD 163 | 前往`config/Console/AutoLogin.yml` 164 | 将`protocol`更改为`IPAD` 165 | + 删除`bots`文件夹下所有内容 166 | 167 | ### 登录存在安全风险 168 | 169 | + 这个东西吧...挺玄学的,通常是云服务器上部署的mirai才会有这个问题,要通过这个验证,通常需要手机与电脑在同一网络环境下,而如果你使用了云服务器,那么除了使用一些玄学手段(指过两天再试就好了)或者科学手段(这玩意儿可不兴展开来讲啊 170 | 哥)外别无他法。 171 | 172 | ### 苹果手机无法安装滑块助手 173 | 174 | + 在[初心佬的文章](https://www.initbili.top/2022/8d92a2feb3e2/)最下方有手动获取ticket的教程 175 | + 注意,此时你不需要再点击`Open with TxCaptchaHelper`按钮了,而是直接将教程中获取到的ticket填入ticket栏中即可 176 | 177 | ### A JNI error has occured. 178 | 179 | + 通常这是由于java版本太低导致的 180 | + 两个解决方案 181 | 1. 可以手动安装一个java的jdk(建议版本为17或18 安装方法请自行百度) 182 | 2. 使用mcl installer重新安装mcl 在安装时会询问是否安装java jdk 选择安装即可 183 | 184 | ### 有大段看不懂/完全没有中文信息的红色报错 185 | 186 | + 通常,这类报错的关键信息都在红色文本的最下方或者最上方 187 | + 如果最下方没有中文的提示,那么请前往红色文本的最上方查找关键信息 188 | 189 | #### Address already in use 190 | 191 | + 你是否启动了两个mcl? 192 | 如果是的话,请关闭一个,并保证同时只有一个mcl在运行 193 | + mah中所填写的的端口与某个外部应用冲突,可以修改`config/net.mamoe.mirai-api-http/setting.yml` 194 | 中两个端口的值解决,值理论上可以是1024~65535中的任何一个数字 195 | 196 | ::: danger 注意
197 | 若是在此处修改了端口值,你应该在控制台中填写实例配置单时相对应地修改端口值 198 | ::: 199 | 200 | ## 代码部署启动时/使用特定命令时会报错 201 | 202 | 既然你是代码部署的,一些常见的细节我将会省略不解释,希望你能看懂 203 | 204 | + 请更新代码 & 依赖 & 插件 205 | ```shell 206 | git pull 207 | pip install --upgrade amiyabot 208 | ``` 209 | 210 | ## 可执行文件部署启动时会报错 211 | 212 | + 你是否更新了插件? 213 | ~~我通常称这种行为叫旧瓶装新酒~~ 214 | + 请检查[项目官网](https://www.amiyabot.com/guide/deploy/getStarted.html)是否有更新的版本 215 | + 如果是的话,请更新兔兔版本后再试 216 | 217 | ## 部署过程看起来一切都很正常,但兔兔就是不理人 218 | 219 | + 检查是否有安装插件,v6的插件化使得默认部署完的兔兔是没有插件的 220 | 也就无法对常见的互动进行回应 221 | 222 | > 我已经安装好插件了 223 | 224 | + 查看mirai窗口,检查是否有消息推送的提示,如果没有,则是mirai启动/配置有问题,导致mirai这一步就收不到消息,请检查mirai的启动情况与配置文件,并配合前文的排错食用 225 | + 查看兔兔窗口 是否有消息推送 226 | ~~通常 有的话还不回应就见鬼了~~ 227 | + 检查报错,是否未正确连接到mirai 228 | 229 | ::: danger 划重点
230 | windows的cmd存在 单击窗体内黑色部分进入快速选择 这么一个机制 231 | 标志是窗口标题最前面出现了`选择`二字 232 | 而进入了快速选择 应用本体的运行将会被冻结 产生应用卡住不动的表象 233 | 这种情况下 只要敲击回车就可以推出快速选择 234 | 这一点对mirai和兔兔两者都适用 235 | ::: 236 | 237 | ## 更新兔兔/迁移兔兔时,如何保留原来的数据 238 | 239 | + 将旧兔兔的 database 整个覆盖至新兔兔的根目录下即可 240 | + 对于可执行文件部署,也可以选择用新的可执行文件覆盖旧的可执行文件,便可以不用迁移数据库文件,但请注意,有时这会导致插件与本体版本不一致的问题,通常使用上一个方案,并重新安装插件即可解决 241 | -------------------------------------------------------------------------------- /docs/guide/deploy/getStarted/code.md: -------------------------------------------------------------------------------- 1 | # 通过代码部署 2 | 3 | 请根据操作系统按顺序执行以下命令。 4 | 5 | ::: warning 注意
6 | 推荐使用 Python 3.8 ~ 3.9 运行本项目代码,并参照可执行文件的系统支持选择部署的操作系统。 7 | ::: 8 | 9 | 1. [克隆仓库](https://github.com/AmiyaBot/Amiya-Bot) 10 | 11 | ```bash 12 | git clone --depth 1 https://github.com/AmiyaBot/Amiya-Bot.git 13 | cd Amiya-Bot 14 | ``` 15 | 16 | 2. 使用 [virtualenv](https://virtualenv.pypa.io/en/latest/) 创建虚拟环境(非必须,或根据个人习惯选择虚拟环境) 17 | 18 | ```bash 19 | # Windows 20 | python -m venv venv 21 | call venv/Scripts/activate.bat 22 | ``` 23 | 24 | ```bash 25 | # Linux or MacOS 26 | python -m venv venv 27 | source venv/bin/activate 28 | ``` 29 | 30 | 3. 安装依赖 31 | 32 | ```bash 33 | pip install -r requirements.txt 34 | ``` 35 | 36 | 4. 安装浏览器内核 37 | 38 | 默认为 Chromium 39 | 40 | ```bash 41 | # Windows or MacOS 42 | playwright install chromium 43 | # Linux 44 | playwright install --with-deps chromium 45 | ``` 46 | 47 | 部分系统由于版本过低(如 Windows Server 2012),可能不支持 chromium 内核。推荐修改为火狐(firefox)内核启动。 48 | 49 | ```bash 50 | # Windows or MacOS 51 | playwright install firefox 52 | # Linux 53 | playwright install --with-deps firefox 54 | ``` 55 | 56 | ::: details 使用火狐内核需要修改入口程序 `amiya.py`,点击查看代码 57 | 58 | ```python {3,6-11,20} 59 | import ... 60 | 61 | from amiyabot import BrowserLaunchConfig # 导入浏览器启动配置类 62 | 63 | 64 | # 创建新启动类 65 | class Launcher(BrowserLaunchConfig): 66 | def __init__(self): 67 | super().__init__() 68 | 69 | self.browser_type = 'firefox' # 设定浏览器属性 70 | 71 | 72 | def run_amiya(*tasks: Coroutine): 73 | ... 74 | 75 | 76 | if __name__ == '__main__': 77 | run_amiya( 78 | bot.start(launch_browser=Launcher()), # 更改为使用新启动类启动浏览器 79 | app.serve(), 80 | load_plugins() 81 | ) 82 | ``` 83 | 84 | ::: 85 | 86 | 5. 运行代码 87 | 88 | ```bash 89 | python amiya.py 90 | ``` 91 | 92 | 日志显示同可执行文件部署,成功后可以进入下一节。 93 | -------------------------------------------------------------------------------- /docs/guide/deploy/getStarted/docker.md: -------------------------------------------------------------------------------- 1 | # Linux Docker 部署 2 | 3 | 进入控制台,执行以下命令一键安装 4 | 5 | ```bash 6 | bash <(curl -fsSL https://raw.githubusercontent.com/AmiyaBot/Amiya-Bot/V6-master/dockersh/install.sh) 7 | ``` 8 | 9 | ## 一键部署脚本 10 | 11 | [点击下载](https://github.com/AmiyaBot/Amiya-Bot/blob/V6-master/dockersh/install.sh) 12 | 13 | 建议提前安装好 Docker 并配置镜像 14 | -------------------------------------------------------------------------------- /docs/guide/deploy/getStarted/exe.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | # Windows 可执行文件部署 6 | 7 | 1. 点击下载一键包 ,仅支持 Windows 10、Windows Server 2016 及以上系统。 8 | 2. 解压,运行 ,如下图成功运行后可以进入[下一节](/guide/deploy/console/)。 9 | 10 | ![img.png](../../../assets/deploy/running.png) 11 | -------------------------------------------------------------------------------- /docs/guide/deploy/getStarted/index.md: -------------------------------------------------------------------------------- 1 | # 开始部署 2 | 3 | ::: danger 操作系统支持
4 | 5 | - Windows 10、Windows Subsystem for Linux (WSL) 或 Windows Server 2012 及以上系统 6 | - MacOS 11 (Big Sur) 及以上系统 7 | - Linux 系统官方支持 Debian 11、Ubuntu 18.04 及更新版本 8 | 9 | ::: 10 | 11 | ## 安装 Git 12 | 13 | 部分插件依赖本地的 Git 服务,必须安装 Git 以确保正常使用。请自行到 [GIT官网](http://gitforwindows.org/) 下载合适自己系统的版本。 14 | 15 | ## 部署 16 | 17 | 根据你的设备系统或习惯,你可以选择以下其中一种部署方式: 18 | 19 | 1. [可执行文件部署](/guide/deploy/getStarted/exe.md)(仅限 Windows) 20 | 2. [Docker部署](/guide/deploy/getStarted/docker.md) 21 | 3. [代码部署](/guide/deploy/getStarted/code.md) 22 | 23 | Windows 系统推荐使用**可执行文件部署**,可执行文件部署是一键部署的模式,部署难度低。
24 | Linux 系统推荐使用 **Docker 部署**,Docker 部署可以解决不同 Linux 发行版的系统依赖问题,支持一键升级,推荐云服务器使用该种方式部署。 25 | 26 | ::: danger 注意
27 | 理论上,Windows 亦可使用 Docker 部署,但并不推荐您使用该方式。请注意,我们不会就特定于在 Windows 上使用 Docker 28 | 部署相关的任何问题提供支持。 29 | ::: 30 | -------------------------------------------------------------------------------- /docs/guide/deploy/index.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | # 简要说明 6 | 7 | [兔兔-v6](https://github.com/AmiyaBot/Amiya-Bot)是游戏《明日方舟》主题的机器人,为本框架的主体项目。 8 | 9 | 如果你是为了开发一个完全由自己定制的机器人,请阅读[开发指南](/develop/basic/)而不是本文档。 10 | 11 | 当然,你也可以从 兔兔-v6 的基础上进行定制。但之中的一部分代码服务于其本身的《明日方舟》功能系列插件,以及控制台项目 12 | [Amiya-Bot-console2](https://github.com/AmiyaBot/Amiya-Bot-console2),如果你不需要这些代码,也许你难以将它们抽离。请谨慎选择此方式。 13 | 14 | 那么,如何部署属于自己的 兔兔-v6(以下简称“兔兔”),请阅读接下来的文档。 15 | 16 | ## 官方版兔兔 17 | 18 | 你也可以直接使用官方版的兔兔啦!🎉🎉🎉 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/guide/deploy/instances/cqhttp.md: -------------------------------------------------------------------------------- 1 | # CQ-Http QQ群机器人 2 | 3 | `APP ID` 为登录在 go-cqhttp 的 **QQ 号**。
4 | `TOKEN` 填写配置的 access-token,没有配置则不需要填写。
5 | `CQ-Http 配置` 请准确填写你部署 go-cqhttp 时的信息。 6 | 7 | 需要配置 go-cqhttp 目录下的文件 `config.yml` 里数据类型为 array,修改完后重启 go-cqhttp 生效。 8 | 9 | ```yaml {4} 10 | message: 11 | # 上报数据类型 12 | # 可选: string,array 13 | post-format: array 14 | ``` 15 | 16 | access-token 可在 go-cqhttp 目录下的文件 `config.yml` 找到 17 | 18 | ```yaml {4} 19 | # 默认中间件锚点 20 | default-middlewares: &default 21 | # 访问密钥, 强烈推荐在公网的服务器设置 22 | access-token: '*******' 23 | # 事件过滤器文件目录 24 | filter: '' 25 | # API限速设置 26 | # 该设置为全局生效 27 | # 原 cqhttp 虽然启用了 rate_limit 后缀, 但是基本没插件适配 28 | # 目前该限速设置为令牌桶算法, 请参考: 29 | # https://baike.baidu.com/item/%E4%BB%A4%E7%89%8C%E6%A1%B6%E7%AE%97%E6%B3%95/6597000?fr=aladdin 30 | rate-limit: 31 | enabled: false # 是否启用限速 32 | frequency: 1 # 令牌回复频率, 单位秒 33 | bucket: 1 # 令牌桶大小 34 | ``` 35 | -------------------------------------------------------------------------------- /docs/guide/deploy/instances/kook.md: -------------------------------------------------------------------------------- 1 | # KOOK机器人 2 | 3 | 在 [KOOK 开发者平台](https://developer.kookapp.cn/app/index) 查看并在实例配置填写你创建的机器人应用的 `Token` 即可。KOOK 4 | 机器人不需要 appid,但你仍然需要在配置里随便填写一个 appid,推荐使用 KOOK 5 | 应用的 `Client Id`。 6 | -------------------------------------------------------------------------------- /docs/guide/deploy/instances/llonebot.md: -------------------------------------------------------------------------------- 1 | # LLOneBot QQ群机器人 2 | 3 | 当前环境下,推荐使用 LLOneBot 部署QQ机器人。
4 | 首先你需要下载并安装 [NTQQ](https://im.qq.com/pcqq/index.shtml)。注意,不是普通的 Window QQ,而是 **NTQQ**。 5 | 安装后,打开 QQ 的菜单并点击关于,在底部看到 `基于QQNT技术架构` 证明你安装对了。 6 | 7 | image 8 | 9 | 接下来,跟随 [llonebot的教程](https://llonebot.github.io/zh-CN/guide/getting-started),安装 LiteLoaderQQNT 和 LLOneBot。 10 | 11 | 全部安装完成后,打开 QQ 的设置菜单,可以看到 LLOneBot 就证明你安装成功了。 12 | 13 | image 14 | 15 | 接下来,按照下图所示(看不清楚可以右键图片在新标签中打开),填写 LLOneBot 配置项,和配置 AmiayBot 实例。
16 | 其中新消息上报格式要选择消息段。 17 | 18 | ![AmiyaBot-LLOneBot](https://github.com/user-attachments/assets/5ead21c1-4e25-45ac-b51a-d60c37a37763) 19 | -------------------------------------------------------------------------------- /docs/guide/deploy/instances/mirai.md: -------------------------------------------------------------------------------- 1 | # Mirai-api-http QQ群机器人 2 | 3 | `APP ID` 为登录在 mirai-api-http 的 **QQ 号**。
4 | `TOKEN` 为 mirai-api-http 的 **AuthKey**。
5 | `Mirai-api-http 配置` 请准确填写你部署 mah 时的信息。 6 | 7 | AuthKey 可在 mirai-console 目录下的文件 `config/net.mamoe.mirai-api-http/setting.yml` 找到 8 | 9 | ```yaml {6} 10 | adapters: 11 | - http 12 | - ws 13 | debug: false 14 | enableVerify: true 15 | verifyKey: ******* # 此处即是 AuthKey 16 | singleMode: false 17 | cacheSize: 4096 18 | adapterSettings: 19 | http: 20 | host: 0.0.0.0 21 | port: 8080 22 | cors: [ * ] 23 | ws: 24 | host: 0.0.0.0 25 | port: 8060 26 | reservedSyncId: -1 27 | ``` 28 | -------------------------------------------------------------------------------- /docs/guide/deploy/instances/napcatqq.md: -------------------------------------------------------------------------------- 1 | # NapCatQQ QQ群机器人 2 | 3 | ## 初略流程 4 | 5 | 1. 遵照其详细教程启动 NapCat 本体。 6 | 2. 进入 WebUI,启动需要的 HTTP/WS 服务端。 7 | 3. 配置 AmiyaBot 连接 NapCat。 8 | 9 | ## 启动方式 10 | 11 | NapCat 有着众多启动方式,每种方式各有优点: 12 | 13 | - **Shell 版本**:具有低内存、服务器部署简单的特点。 14 | - **Framework 版本**:具有方便人机交互、便于窥屏的特点。 15 | 16 | ## 安装 17 | 18 | 略,详见 [NapCatQQ 官方文档](https://napneko.github.io/guide/install) 19 | 20 | ## 配置 21 | 22 | ### 通过 WebUI 配置 23 | 24 | 默认地址为 `0.0.0.0`,即监听所有地址。当配置了不可用的地址时将禁用 WebUI。 25 | 26 | 默认端口为 `6099`,当端口被设置为 `0` 时将禁用 WebUI。 27 | 28 | 启动后可在启动日志中看到形如 `[WebUi] WebUi Local Panel Url: http://127.0.0.1:6099/webui?token=xxxx` 的token信息。 29 | 30 | 也可打开 `webui.json` 文件,在其中找到token。 31 | 32 | ```webui.json 33 | { 34 | "host": "0.0.0.0", // WebUI 监听地址 35 | "port": 6099, // WebUI 端口 36 | "token": "xxxx", //登录密钥,默认是自动生成的随机登录密码 37 | "loginRate": 3, //每分钟登录次数限制 38 | } 39 | ``` 40 | 41 | 访问 `http://ip:port/webui/`,然后进行以下操作: 42 | 1. 进入 QQ 登录,点击 `QRCode` 进行二维码登录。 43 | 2. 登录成功后,进入网络配置添加以下配置。 44 | 1. HTTP 配置如下图 45 | ![AmiyaBot-NapCatQQ-HTTP](https://github.com/user-attachments/assets/aae0f255-8348-4ddb-a338-1d466f2b0ba5) 46 | 2. websocket 配置如下图 47 | ![AmiyaBot-NapCatQQ-WS](https://github.com/user-attachments/assets/96369055-f87a-4079-90df-fb380d3356fb) 48 | 3. 配置完成后,点击确认即可。 49 | -------------------------------------------------------------------------------- /docs/guide/deploy/instances/qqbot.md: -------------------------------------------------------------------------------- 1 | # QQ群 & QQ频道机器人(官方) 2 | 3 | 在 [QQ 开放平台](https://q.qq.com/#/) 查看并在实例配置填写你注册的机器人信息,表单字段就是对应内容。 4 | 5 | ::: danger 请注意
6 | 群机器人在不修改任何配置的情况下,**无法在个人电脑(非公网)上部署**,也就是只支持在**云服务器**上部署 7 | ,如果您一定要在个人电脑上部署,目前提供了 [内网穿透](https://www.baidu.com/s?wd=内网穿透) 8 | 和 [腾讯云COS](https://www.baidu.com/s?wd=腾讯云COS) 的方式解决。 9 | ::: 10 | 11 | ## 内网穿透 12 | 13 | 实例配置资源服务地址为 `127.0.0.1`。端口随意,默认为 `8086`。使用内网穿透工具代理 http://127.0.0.1:8086 后,修改配置文件 14 | `config/penetration.yaml` 的 ports 参数,新增一行配置,字段为实例配置里的资源服务端口,值为内网穿透地址,重启兔兔生效。 15 | 16 | ```yaml 17 | ports: 18 | 8086: http://3913rc56vl17.vicp.fun:40229 19 | ``` 20 | 21 | ## 腾讯云COS 22 | 23 | 无需理会资源服务配置,修改配置文件 `config/cos.yaml` 如下(懂的都懂,不懂的建议折腾内网穿透),重启兔兔生效。 24 | 25 | ```yaml 26 | activate: true 27 | domain: https://amiyabot-xxxxxxxxx.cos.ap-guangzhou.myqcloud.com 28 | folder: /temp/group 29 | secret_id: AKIDwiHcxxxxxxxxxxCpGfqDZp2U 30 | secret_key: Uky7BB8zxxxxxxxxigQzVt64oLgnn 31 | ``` 32 | -------------------------------------------------------------------------------- /docs/guide/deploy/maintain/upgrade.md: -------------------------------------------------------------------------------- 1 | # 如何更新 2 | 3 | ## 游戏资源更新 4 | 5 | 每次启动时会检查资源仓库并更新新资源。
6 | 当游戏有更新的当日,可以通过重启程序来获得更新。 7 | 8 | ::: tip 提示
9 | 资源的解包需要一定时间,无法获取更新时可稍后再试。 10 | ::: 11 | 12 | ## 程序更新 13 | 14 | 从 V6 15 | 开始程序将不再自动更新,也不会推送更新消息。请关注 [官方频道](https://qun.qq.com/qqweb/qunpro/share?_wv=3&_wwv=128&appChannel=share&inviteCode=1W4sJux&appChannel=share&businessType=9&from=181074&biz=ka&shareSource=5) 16 | 获取最新的通知。 17 | 18 | 当有更新时可到 [下载页面](/download) 下载更新包。
19 | 通常情况下,你只需要解压更新包的 exe 程序到你**原来的目录**下并启动新的程序就可以了。 20 | 21 | ## 插件更新 22 | 23 | 插件同样也不会自动更新。请关注插件商店和频道的公告。 24 | -------------------------------------------------------------------------------- /docs/guide/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | aside: false 3 | --- 4 | 5 | # AmiyaBot 简介 6 | 7 | ## 介绍 8 | 9 | AmiyaBot 是异步 Python QQ 机器人框架。基于 QQ [官方API](https://bot.q.qq.com/wiki/develop/api-v2/) 10 | 。内置了丰富的消息构建方法和适配器,让你轻松实现你的创意。 11 | 12 | ### 她的过去... 13 | 14 | AmiyaBot 诞生于2019年,是一个[《明日方舟》](https://ak.hypergryph.com/index)民间 QQ 机器人,至本框架发布时已迭代了 5 15 | 个里程碑版本。一直以来,AmiyaBot 都秉着 **“为所有人带来快乐”** 的初衷,跌跌撞撞到现在,依旧坚持开源、免费为用户提供服务。 16 | 17 | 2022年5月13日重大变故后,AmiyaBot 决定迁移至 QQ 频道成为正式的机器人。原群聊机器人(Amiya2号)终止服务。
18 | 2022年6月11日,剥离出其核心部分成为框架,也就是本文档所指的 [AmiyaBot](/)。
19 | 2022年9月14日,[V6 版本](/guide/deploy/) 的用户自部署群聊机器人发布,由用户延续原群聊机器人(Amiya2号)的初衷。
20 | 2024年6月18日,官方[全域机器人](/guide/deploy/#官方版兔兔)正式发布。 21 | 22 | ### 现在 23 | 24 | AmiyaBot 依旧坚持初心,将快乐带给所有人。加入我们的 25 | [官方群](https://qm.qq.com/q/9ft0w6HQj0)、 26 | [官方频道](https://qun.qq.com/qqweb/qunpro/share?_wv=3&_wwv=128&appChannel=share&inviteCode=1W4sJux&appChannel=share&businessType=9&from=181074&biz=ka&shareSource=5) 27 | 或 28 | [开始使用](/guide/deploy/)。 29 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | 4 | hero: 5 | name: AmiyaBot 6 | text: Progressive Python QQ Bot Framework 7 | tagline: 渐进式 QQ 机器人框架,可使用内置适配器对接官方 QQ 群、OneBot v11/12、KOOK 等机器人平台。 8 | image: 9 | src: /logo.svg 10 | alt: AmiyaBot 11 | actions: 12 | - theme: brand 13 | text: 开始使用 14 | link: /develop/basic/ 15 | - theme: alt 16 | text: 添加兔兔机器人到你的群聊 17 | link: /guide/deploy/#官方版兔兔 18 | - theme: alt 19 | text: 部署兔兔机器人 20 | link: /guide/deploy/ 21 | 22 | features: 23 | - icon: 🚀 24 | title: 简洁高效 25 | details: 采用异步 I/O,摆脱官方 API 繁杂的操作,以更加简洁和可读性更高的代码让你专注于你的业务逻辑。 26 | - icon: 🎭 27 | title: 多账号 & 热插拔 28 | details: 支持同时创建多个机器人实例,为所有实例注册共享的消息处理方法,以及在多账号实例内动态增删机器人。 29 | - icon: 🧩 30 | title: 适配器 & 插件支持 31 | details: 通过适配器来更改机器人的服务来源,提供更大的灵活性和可扩展性。支持插件开发方案,将业务和主程序分离,使机器人更加生态化和可定制化。 32 | - icon: 🎉 33 | title: 丰富的消息类型 34 | details: 内置的 PIL 图像合成模块以及 HTML 转换器,支持合成文字图片或通过渲染 WEB 和 Markdown 合成图片,轻松实现你的绝佳创意。 35 | 36 | --- 37 | 38 | 42 | 43 |
44 | 45 | 46 |
47 | -------------------------------------------------------------------------------- /docs/public/E0BA9D78918921391A5BE261A96C6F04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmiyaBot/Amiya-Bot-docs/03b94939d8726c62af678160cd806e5f65649077/docs/public/E0BA9D78918921391A5BE261A96C6F04.jpg -------------------------------------------------------------------------------- /docs/public/F7AB3AFE554027987502E5E1AB65746E.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmiyaBot/Amiya-Bot-docs/03b94939d8726c62af678160cd806e5f65649077/docs/public/F7AB3AFE554027987502E5E1AB65746E.jpg -------------------------------------------------------------------------------- /docs/public/bot/102068219.json: -------------------------------------------------------------------------------- 1 | {"bot_appid":102068219} -------------------------------------------------------------------------------- /docs/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmiyaBot/Amiya-Bot-docs/03b94939d8726c62af678160cd806e5f65649077/docs/public/favicon.ico -------------------------------------------------------------------------------- /docs/public/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/sponsor.md: -------------------------------------------------------------------------------- 1 | --- 2 | aside: false 3 | --- 4 | 5 | 10 | 11 | 12 | 13 | # 感谢有你 14 | 15 | AmiyaBot 一路走来离不开大家的默默支持,如果你喜欢并支持我们,可以为我们打赏一瓶快乐水。我相信快乐是可以互相传递的,你的快乐水带给我们快乐的同时,想必 16 | AmiyaBot 也给你带去了快乐吧。 17 | 18 | 但同时我们希望你量力而为,你对 AmiyaBot 19 | 的认可就已经是最大的支持了。如果可以的话,恳请你在 [Github](https://github.com/AmiyaBot/Amiya-Bot) 为 AmiyaBot 点上一颗小小的️ 20 | ⭐ star。 21 | 22 | ## 特别鸣谢 23 | 24 | 感谢各位对 AmiyaBot 社区做出的贡献,是大家共同塑造了 AmiyaBot 社区的繁荣。期待未来我们能携手创造更多可能!🌹 25 | 26 | 27 | 28 | ## 充电鸣谢 29 | 30 | 你们的鼎力支持让我们感到创作 AmiyaBot 项目是值得的。感谢有你,让 AmiyaBot 秉承初衷。❤️ 31 | 32 | 33 | 34 | 打赏请前往[爱发电主页](https://afdian.com/a/amiyabot)。 35 | 36 | 37 | 40 | 41 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "amiya-bot-docs", 3 | "version": "1.0.0", 4 | "description": "pypi project amiyabot's docs", 5 | "main": "index.js", 6 | "scripts": { 7 | "docs:dev": "vitepress dev docs --host --port 8080", 8 | "docs:build": "vitepress build docs", 9 | "docs:serve": "vitepress serve docs" 10 | }, 11 | "author": "vivien8261", 12 | "license": "MIT", 13 | "devDependencies": { 14 | "vitepress": "1.0.0-beta.2", 15 | "vue": "^3.2.39" 16 | }, 17 | "dependencies": { 18 | "axios": "^0.27.2" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /scripts/HarmonyOS_Sans_SC.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmiyaBot/Amiya-Bot-docs/03b94939d8726c62af678160cd806e5f65649077/scripts/HarmonyOS_Sans_SC.ttf -------------------------------------------------------------------------------- /scripts/minfont.py: -------------------------------------------------------------------------------- 1 | # GraiaCommunity (https://github.com/GraiaCommunity/Docs) b678d2f1f517b19717e5084326c519d05b64af77 2 | # Use of this file is authorized by MIT License. 3 | # Different from the original version. 4 | # The file has been modified for specific requirements. 5 | # 6 | # 依照 MIT License 使用本文件。 7 | # 与原始版本不一致。 8 | # 为满足特定需求,该文件进行了一些修改。 9 | 10 | import os 11 | import platform 12 | from os.path import basename, exists, join 13 | 14 | from fontTools import subset 15 | from fontTools.ttLib import TTFont 16 | 17 | origin_path = join('docs') 18 | ignore_dirs = ['dist', 'public', '.DS_Store', 'assets'] 19 | out_path = join('fonts') 20 | font = join('scripts', 'HarmonyOS_Sans_SC.ttf') 21 | 22 | content = '' 23 | 24 | 25 | def read(path): 26 | global content 27 | for root, dirs, files in os.walk(path): 28 | if basename(root) in ignore_dirs: 29 | dirs[:] = [] # 忽略当前目录下的子目录 30 | continue 31 | for f in files: 32 | print(f'正在读取 {join(root, f)}') 33 | with open(join(root, f), 'r', encoding='utf8') as file: 34 | while True: 35 | if char := file.read(1): 36 | content += f'{char}\n' 37 | else: 38 | break 39 | 40 | 41 | print('读取文件中...') 42 | read(origin_path) 43 | 44 | print(f'正在处理 {font}') 45 | if not exists(out_path): 46 | os.mkdir(out_path) 47 | f = TTFont(font) 48 | 49 | subsetter = subset.Subsetter() 50 | 51 | subsetter.populate(text=content) 52 | subsetter.subset(f) 53 | f.flavor = 'woff2' 54 | f.save(join(out_path, 'Harmony.min.woff2')) 55 | -------------------------------------------------------------------------------- /scripts/uFont.py: -------------------------------------------------------------------------------- 1 | from qcloud_cos import CosConfig 2 | from qcloud_cos import CosS3Client 3 | 4 | import os 5 | import sys 6 | import logging 7 | 8 | logging.basicConfig(level=logging.INFO, stream=sys.stdout) 9 | 10 | secret_id = os.environ.get('SECRETID') 11 | secret_key = os.environ.get('SECRETKEY') 12 | region = 'ap-guangzhou' 13 | token = None 14 | scheme = 'https' 15 | 16 | config = CosConfig(Region=region, SecretId=secret_id, SecretKey=secret_key, Token=token, Scheme=scheme) 17 | client = CosS3Client(config) 18 | 19 | with open('fonts/Harmony.min.woff2', 'rb') as fp: 20 | response = client.put_object( 21 | Bucket='amiyabot-1302462817', 22 | Body=fp, 23 | Key='resource/Harmony_amiyabot.com.min.woff2', 24 | StorageClass='STANDARD', 25 | EnableMD5=False 26 | ) 27 | print(response['ETag']) 28 | --------------------------------------------------------------------------------