Skip to content

功能限制与实现细节 ​

音频发送策略 ​

云湖的机器人接口不允许机器人直接发送音频文件(用户可以发送语音,但机器人不能)。早期适配器会把音频通过 ctx.ffmpeg 转成带纯色背景的视频再发送,但视频消息在聊天中会占据较大的上下高度,容易造成刷屏。

当前适配器会根据音频来源采用两种策略:

音频来源发送方式
公网可访问的 HTTP(S) 链接使用 A2UI 协议发送 AudioPlayer 播放器组件
内网、本机或云湖无法公网访问的链接下载并上传音频,再通过适配器配置的媒体代理地址交给 AudioPlayer 播放

公网音频链接 ​

当 <audio> 元素的 src 是公网可访问的 HTTP(S) 链接时,适配器会生成 A2UI 消息(contentType: 'a2ui'),云湖客户端可以直接渲染播放器,无需转换成视频。

ts
await session.send(h('audio', {
  src: 'https://example.com/audio.mp3',
  title: '示例音频',
}));

适配器会排除 localhost、127.0.0.1 以及内网 IPv4 地址;如果你的域名实际无法被云湖访问,请先将其替换为公网可访问的链接。

内网音频链接 ​

如果音频链接是内网地址、本机地址,或无法被云湖客户端直接访问,适配器会下载原始音频并上传,再通过媒体代理地址提供给客户端。最终仍然是 A2UI 消息,不会转换为视频消息。

为什么不直接使用文件上传接口得到的原始地址?

云湖 A2UI 播放器请求音频时可能受到富媒体资源请求头限制。适配器因此对非公网来源的音频使用媒体代理地址,避免播放器无法加载资源。

文件大小限制 ​

云湖对不同类型的文件有严格的上传大小限制:

  • 图片:最大 10MB
  • 视频:最大 20MB
  • 其他文件:最大 20MB

为了尽可能确保文件能成功发送,适配器会进行如下处理:

  • 超限视频:如果视频大小超过 20MB,适配器会尝试使用 ctx.ffmpeg 对其进行一次压缩。如果压缩后的大小符合限制,则会发送;否则,操作将失败。
  • 超限图片和文件:适配器无法处理超限的图片或其他文件,将直接抛出错误。

图片资源访问 ​

直接访问云湖的图片 URL 会因为缺少 Referer 请求头而导致 403 Forbidden 错误。

您必须在请求中添加 Referer: https://www.yhchat.com/ 头才能成功获取图片。

以下是一个使用 curl 访问图片的示例:

bash
curl --location 'https://chat-img.jwznb.com/a0068c6770fe2df08d1923287bb9cdbf.jpg' \
--header 'Referer: https://www.yhchat.com/'

额外接口的来源 ​

本适配器提供的一些非官方额外接口,其实现逻辑来源于对以下几个 Web 页面的网络请求分析:

  • https://www.yhchat.com/user/homepage/7756242
  • https://yhfx.jwznb.com/share?key=0FRmLHlPL47M&ts=1761497803
  • https://yhfx.jwznb.com/share?key=m7Z4l2bLBWt2&ts=1761497822

Webhook GET 请求处理 ​

在设置 Webhook 监听地址时,为了方便用户确认该路径可被公网访问,适配器对 GET 请求进行了额外处理。

当您通过浏览器访问 Webhook 路径时,会看到一个说明页面,用于验证连通性。

发送富文本消息 ​

本适配器支持通过 Koishi 的 h() 函数 发送 Markdown 和 HTML 格式的消息。

Markdown 消息 ​

使用 <yunhu:markdown> 元素来发送 Markdown 格式的内容。

ts
ctx
  .command('md测试')
  .action(async ({ session }) => {
    const markdownContent = '# 你好\n## 这是 Markdown!';
    await session.send(h('yunhu:markdown', markdownContent));
    await session.send(h('markdown', markdownContent));
});

HTML 消息 ​

使用 <html> 元素来发送 HTML 格式的内容。

ts
ctx
  .command('html测试')
  .action(async ({ session }) => {
    const htmlContent = '<h1>你好</h1><h2>这是 HTML!</h2>';
    await session.send(h('yunhu:html', htmlContent));
    await session.send(h('html', htmlContent));
  });

WARNING

注意!

常见问题:我复制了以上demo指令 html测试,为什么发出来的内容里有一个是图片呢?

这是因为你的koishi用插件实现了 component:html 服务。此服务一般由 puppeteer 插件提供。

此时你有两个解决方法:

  • 不使用h("html"),改为使用h("yunhu:html")
  • 不使用puppeteer的component:html 服务。如果你不希望使用此服务。可以使用 @shangxueink/puppeteer-without-canvas 插件。

指令前缀兼容性 ​

云湖平台的所有机器人指令都带有一个固定且不可修改的前缀 /。

为了确保在 Koishi 中定义的指令能够被正确触发,您必须将 / 添加到 Koishi 的指令前缀配置中。

可以在 Koishi 控制台的“全局设置”下的 prefix 配置项中完成。

集成侧边栏 ​

为了方便您在 Koishi 控制台中快速管理机器人,本适配器在侧边栏注册了一个云湖图标。

点击该图标,即可直接跳转到云湖的官方控制台,无需离开koishi控制台。