简体中文 English 繁體中文 日本語 Русский
本文为静态镜像,内容以交互版为准 在交互式文档中心打开 →

雲湖平台特性文件

YunhuAdapter 是基於雲湖協議建構的適配器,整合了所有雲湖功能模組,提供統一的事件處理和訊息操作介面。


文件資訊

基本資訊

v5 範式更新(4.4.0)

本適配器已完成 v5 範式對齊(增量升級,API 相容):

平台擴展動作(call / Api 方法)

from ErisPulse import sdk
yunhu = sdk.adapter.get("yunhu")

# Api 方法(官方服務端API)
await yunhu.Api.edit_message(msg_id, recv_id, "group", "text", {"text": "新內容"})
await yunhu.Api.batch_send(["userId1", "userId2"], "text", {"text": "公告"})
await yunhu.Api.get_message_list(group_id, "group", before=10)
await yunhu.Api.set_user_board(chat_id, "group", "看板內容", expire_time=3600)
await yunhu.Api.dismiss_global_board()
await yunhu.Api.gag_group_member(group_id, user_id, 600)      # 禁言600秒,0=解除
await yunhu.Api.remove_group_member(group_id, user_id)
await yunhu.Api.set_group_msg_type_limit(group_id, "text,image")
await yunhu.Api.create_group_tag(group_id, "VIP", color="#FF5733")
await yunhu.Api.add_user_tag(group_id, user_id, "VIP")

# 按鈕點擊回調(標準欄位)
from ErisPulse.Core.Event import notice

@notice.on_notice()
async def handle_button(event):
    if event.get("platform") == "yunhu" and event.get("button_data"):
        data = event["button_data"]     # 跨平台統一取值
        interaction_id = event["interaction_id"]

完整標準說明見 跨平台互動元件標準。


支援的訊息發送類型

所有發送方法均透過串接語法實現,例如:

from ErisPulse.Core import adapter
yunhu = adapter.get("yunhu")

await yunhu.Send.To("user", user_id).Text("Hello World!")

支援的發送類型包括:

群組管理方法

所有群組管理方法需要透過串接語法指定群組,例如:

from ErisPulse.Core import adapter
yunhu = adapter.get("yunhu")

await yunhu.Send.To("group", group_id).Kick(user_id)

訊息查詢方法

獲取指定會話(使用者/群)的歷史訊息列表,需要透過串接語法指定目標,例如:

from ErisPulse.Core import adapter
yunhu = adapter.get("yunhu")

result = await yunhu.Send.To("group", group_id).GetMessages(before=10)

Board 作用域由 To() 自動推斷:

# 本地看板(60 秒後相對過期)
await yunhu.Send.To("group", group_id).Expire(60).Board("公告", content_type="markdown")

# 群成員看板(僅指定成員可見)
await yunhu.Send.To("group", group_id).ForMember(user_id).Board("僅你可見")

# 絕對時間戳過期
await yunhu.Send.To("group", group_id).ExpireAt(1785208268).Board("指定時間過期")

# 全域看板
await yunhu.Send.Board("全域公告")

# 清空本地看板(內容為空 → 自動撤銷)
await yunhu.Send.To("group", group_id).Board("")

按鈕參數說明

buttons 參數是一個嵌套列表,表示按鈕的佈局和功能。每個按鈕物件包含以下欄位:

欄位 類型 是否必填 說明
text string 是 按鈕上的文字
actionType int 是 動作類型:
1: 跳轉 URL
2: 複製
3: 點擊回報
url string 否 當 actionType=1 時使用,表示跳轉的目標 URL
value string 否 當 actionType=2 時,該值會複製到剪貼板
當 actionType=3 時,該值會發送給訂閱端

範例:

buttons = [
    [
        {"text": "複製", "actionType": 2, "value": "xxxx"},
        {"text": "點擊跳轉", "actionType": 1, "url": "http://www.baidu.com"},
        {"text": "回報事件", "actionType": 3, "value": "xxxxx"}
    ]
]
await yunhu.Send.To("user", user_id).Buttons(buttons).Text("帶按鈕的訊息")

注意:

  • 只有使用者點擊了按鈕回報事件的按鈕才會收到推送,複製和跳轉URL均無法收到推送。

鏈式修飾方法(可組合使用)

鏈式修飾方法回傳 self,支援鏈式呼叫,必須在最終發送方法前呼叫:

鏈式呼叫範例

# 基礎發送
await yunhu.Send.To("user", user_id).Text("Hello")

# 回覆訊息
await yunhu.Send.To("group", group_id).Reply(msg_id).Text("回覆訊息")

# 回覆 + 按鈕
await yunhu.Send.To("group", group_id).Reply(msg_id).Buttons(buttons).Text("帶回覆和按鈕的訊息")

群組管理範例

from ErisPulse.Core import adapter
yunhu = adapter.get("yunhu")

# 移除群成員
await yunhu.Send.To("group", group_id).Kick(user_id)

# 使用者禁言(10分鐘)
await yunhu.Send.To("group", group_id).Ban(user_id, duration=600)

# 解除禁言
await yunhu.Send.To("group", group_id).Ban(user_id, duration=0)

# 永久禁言
await yunhu.Send.To("group", group_id).Ban(user_id, duration=-1)

# 建立群標籤
await yunhu.Send.To("group", group_id).CreateTag("VIP使用者", color="#FF5733", desc="VIP會員")

# 修改群標籤
await yunhu.Send.To("group", group_id).EditTag("VIP使用者", new_tag="SVIP使用者", color="#33C4FF")

# 刪除群標籤
await yunhu.Send.To("group", group_id).DeleteTag("VIP使用者")

# 獲取群標籤列表
result = await yunhu.Send.To("group", group_id).GetTagList()

# 給使用者添加標籤
await yunhu.Send.To("group", group_id).AddUserTag(user_id, "VIP使用者")

# 移除使用者標籤
await yunhu.Send.To("group", group_id).RemoveUserTag(user_id, "VIP使用者")

# 設定訊息類型限制
await yunhu.Send.To("group", group_id).SetMsgTypeLimit("text,image,video")

# 取消訊息類型限制
await yunhu.Send.To("group", group_id).SetMsgTypeLimit("")

訊息查詢範例

from ErisPulse.Core import adapter
yunhu = adapter.get("yunhu")

# 獲取群最近10條訊息(共回傳10條)
result = await yunhu.Send.To("group", group_id).GetMessages(before=10)

# 獲取群中指定訊息ID前10條(共回傳11條)
result = await yunhu.Send.To("group", group_id).GetMessages(message_id="msg_xxx", before=10)

# 獲取群中指定訊息ID前后各10條(共回傳21條)
result = await yunhu.Send.To("group", group_id).GetMessages(message_id="msg_xxx", before=10, after=10)

# 獲取使用者會話歷史訊息
result = await yunhu.Send.To("user", user_id).GetMessages(message_id="msg_xxx", before=10)

OneBot12訊息支援

適配器支援發送 OneBot12 格式的訊息,便於跨平台訊息相容:

# 發送 OneBot12 格式訊息
ob12_msg = [{"type": "text", "data": {"text": "Hello"}}]
await yunhu.Send.To("user", user_id).Raw_ob12(ob12_msg)

# 配合鏈式修飾
ob12_msg = [{"type": "text", "data": {"text": "回覆訊息"}}]
await yunhu.Send.To("group", group_id).Reply(msg_id).Raw_ob12(ob12_msg)

標準 API 動作(ApiDSL)

Note

本特性需要 ErisPulse 2.7.0+ 且 YunhuAdapter **4.3.0+**。

除了 Send 鏈式發送,適配器還提供 Api 內部類,揭露 OneBot12 標準 API 動作與雲湖平台擴展動作。所有方法回傳標準回應格式。

from ErisPulse.Core import adapter
yunhu = adapter.get("yunhu")

# 信息查詢(透過公開 Web API,無需鑑權)
result = await yunhu.Api.get_self_info()              # 機器人自身資訊
result = await yunhu.Api.get_user_info("7058262")     # 任意使用者資訊
result = await yunhu.Api.get_group_info("635409929")  # 群資訊

# 檔案操作
result = await yunhu.Api.upload_file(type="path", name="a.png", path="./a.png")
result = await yunhu.Api.get_file("https://chat-file.jwznb.com/xxx")

# 撤回訊息(需額外提供 chat_id + chat_type)
await yunhu.Api.delete_message("msg_id", chat_id="123", chat_type="group")

# 多帳號:指定 Bot 帳號
info = await yunhu.Api.Using("bot1").get_self_info()

支援的標準動作

方法 說明 資料來源
get_self_info() 機器人自身資訊 公開 Web API(bot-info)
get_user_info(user_id) 使用者資訊(任意使用者可查) 公開 Web API(user/homepage)
get_group_info(group_id) 群資訊 公開 Web API(group-info)
upload_file(*, type, name, ...) 上傳檔案(自動判定 image/video/file) Bot 開放 API
get_file(file_id) 獲取檔案(file_id 即 URL) —
delete_message(message_id, *, chat_id, chat_type) 撤回訊息 Bot 開放 API(/bot/recall)

注意:get_self_info / get_user_info / get_group_info 透過非官方公開 Web API(chat-web-go.jwzhd.com)實現,這些介面無需鑑權但非官方文件、可能隨平台更新變動;失敗時回傳標準錯誤回應。

不支援的標準動作

以下標準動作雲湖無對應 API,呼叫時回傳 retcode=10002(不支援的操作):

平台擴展動作

透過 Api.call("yunhu.xxx", **params) 呼叫雲湖特有動作(參數採用 OB12 風格命名,適配器自動翻譯為雲湖欄位):

擴展動作 說明 等價 Send 方法
yunhu.recall 撤回訊息(msg_id, chat_id, chat_type) Send.To(...).Recall(msg_id)
yunhu.kick 移除群成員(group_id, user_id) Send.To("group", g).Kick(uid)
yunhu.ban 禁言(group_id, user_id, duration) Send.To("group", g).Ban(uid, duration)
yunhu.unban 解除禁言(group_id, user_id) Send.To("group", g).Ban(uid, duration=0)
yunhu.tag.create/edit/delete/list 群標籤 CRUD(group_id, ...) Send.To("group", g).CreateTag(...) 等
yunhu.tag.relate / yunhu.tag.relate_cancel 給使用者添加/移除標籤 Send.To("group", g).AddUserTag(...) 等
yunhu.set_member_title / yunhu.unset_member_title 成員頭銜語義別名(標籤≈頭銜,內部映射到 tag.relate) —
yunhu.msg_type_limit 群訊息類型限制(group_id, type) Send.To("group", g).SetMsgTypeLimit(...)
yunhu.get_messages 獲取歷史訊息(chat_id, chat_type, message_id?, before?, after?) Send.To(...).GetMessages(...)
yunhu.bot_info 公開 bot-info 查詢(bot_id) —
yunhu.user_homepage 公開使用者主頁查詢(user_id) —
# 平台擴展示例
await yunhu.Api.call("yunhu.kick", group_id="123", user_id="456")
await yunhu.Api.call("yunhu.set_member_title", group_id="123", user_id="456", title="VIP")
result = await yunhu.Api.call("yunhu.get_messages", chat_id="123", chat_type="group", before=10)

標籤與頭銜:雲湖的"標籤"語義等同 OneBot12 群成員 title。yunhu.set_member_title 是 yunhu.tag.relate 的原生語義別名,二者內部映射到同一端點。群訊息事件中發送者角色由 senderUserLevel 映射到標準 role 欄位(owner/admin/member)。

發送方法回傳值

所有發送方法均回傳一個 Task 物件,可以直接 await 獲取發送結果。回傳結果遵循 ErisPulse 适配器标准化回傳規範:

{
    "status": "ok",           // 執行狀態
    "retcode": 0,             // 回傳碼
    "data": {...},            // 回應資料
    "self": {...},            // 自身資訊(包含 bot_id)
    "message_id": "123456",   // 訊息ID
    "message": "",            // 錯誤資訊
    "yunhu_raw": {...}        // 原始回應資料
}

特有事件類型

需要 platform=="yunhu" 檢測再使用本平台特性

核心差異點

  1. 特有事件類型:
    • 表單(如表單指令):yunhu_form
    • 表情包/貼紙訊息段:yunhu_expression
    • 按鈕點擊:yunhu_button_click
    • A2UI按鈕點擊:yunhu_a2ui_button
    • 機器人設定:yunhu_bot_setting
    • 快捷選單:yunhu_shortcut_menu
  2. 標準欄位擴展(4.3.0+):
    • 訊息事件新增標準 role 欄位(由雲湖 senderUserLevel 映射為 owner/admin/member)
    • 新增 user_avatar 欄位(發送者頭像 URL)
  3. 擴展欄位:
    • 所有特有欄位均以yunhu_前綴標識
    • 保留原始資料在yunhu_raw欄位
    • 私聊中self.user_id表示機器人ID

特殊欄位範例

# 表單命令
{
  "type": "message",
  "detail_type": "private",
  "yunhu_command": {
    "name": "表單指令名",
    "id": "指令ID",
    "form": {
      "字段ID1": {
        "id": "字段ID1",
        "type": "input/textarea/select/radio/checkbox/switch",
        "label": "字段標籤",
        "value": "字段值"
      }
    }
  }
}

# 按鈕事件
{
  "type": "notice",
  "detail_type": "yunhu_button_click",
  "user_id": "點擊按鈕的使用者ID",
  "user_nickname": "使用者暱稱",
  "message_id": "訊息ID",
  "yunhu_button": {
    "id": "按鈕ID(可能為空)",
    "value": "按鈕值"
  }
}

# A2UI按鈕事件
{
  "type": "notice",
  "detail_type": "yunhu_a2ui_button",
  "user_id": "操作使用者ID",
  "user_nickname": "使用者暱稱",
  "message_id": "訊息ID",
  "yunhu_a2ui": {
    "recv_id": "接收者ID",
    "recv_type": "接收者類型",
    "action_name": "操作名稱",
    "source_component_id": "來源元件ID",
    "form_context": {},
    "interaction_json": "互動資料JSON字串"
  }
}

### 按鈕點擊事件處理範例

```python
from ErisPulse.Core.Event import notice

@notice.on_notice()
async def handle_yunhu_notice(event):
    """處理雲湖通知事件

    使用通用的 on_notice() 裝飾器來處理所有通知事件,
    然後透過 detail_type 區分不同類型的通知
    event.reply() 會自動透過雲湖平台回覆
    """
    # 檢查是否是按鈕點擊事件
    if event.get("detail_type") == "yunhu_button_click":
        user_id = event.get_user_id()
        user_nickname = event.get_user_nickname()
        button_value = event.get("yunhu_button", {}).get("value", "")

        print(f"使用者 {user_nickname}({user_id}) 點擊了按鈕: {button_value}")

        # 使用 event.reply() 自動回覆(會根據平台自動選擇正確的發送方式)
        if button_value == "confirm":
            await event.reply("你點擊了確認按鈕!")
        elif button_value == "cancel":
            await event.reply("操作已取消")
        else:
            await event.reply(f"收到你的選擇: {button_value}")

    # 處理快捷選單事件
    elif event.get("detail_type") == "yunhu_shortcut_menu":
        menu_id = event.get("yunhu_menu", {}).get("id", "")
        await event.reply(f"觸發了快捷選單: {menu_id}")

    # 處理機器人設定變更
    elif event.get("detail_type") == "yunhu_bot_setting":
        settings = event.get("yunhu_setting", {})
        await event.reply(f"設定已更新: {settings}")

    # 處理A2UI按鈕事件
    elif event.get("detail_type") == "yunhu_a2ui_button":
        a2ui = event.get("yunhu_a2ui", {})
        action_name = a2ui.get("action_name", "")
        form_context = a2ui.get("form_context", {})
        await event.reply(f"A2UI操作: {action_name}, 表單資料: {form_context}")

使用串接呼叫發送帶按鈕訊息

from ErisPulse import sdk

yunhu = sdk.adapter.get("yunhu")

buttons = [
    [
        {"text": "確認", "actionType": 3, "value": "confirm"},
        {"text": "取消", "actionType": 3, "value": "cancel"},
        {"text": "檢視詳情", "actionType": 1, "url": "http://example.com/detail"}
    ]
]

# 發送帶按鈕的訊息到群組
await yunhu.Send.To("group", "123456").Buttons(buttons).Text("請確認以下操作")

# 發送帶按鈕的訊息到使用者私聊
await yunhu.Send.To("user", "789").Buttons(buttons).Text("請選擇你的偏好設定")

發送A2UI訊息

from ErisPulse import sdk

yunhu = sdk.adapter.get("yunhu")

# 發送A2UI訊息
await yunhu.Send.To("user", user_id).A2UI("A2UI互動卡片內容")

機器人設定

{ "type": "notice", "detail_type": "yunhu_bot_setting", "group_id": "群組ID(可能為空)", "user_nickname": "使用者暱稱", "yunhu_setting": { "設定項ID": { "id": "設定項ID", "type": "input/radio/checkbox/select/switch", "value": "設定值" } } }

快捷選單

{ "type": "notice", "detail_type": "yunhu_shortcut_menu", "user_id": "觸發選單的使用者ID", "user_nickname": "使用者暱稱", "group_id": "群組ID(如果是群聊)", "yunhu_menu": { "id": "選單ID", "type": "選單類型(整數)", "action": "選單動作(整數)" } }


## Event Mixin 擴展方法

適配器註冊了以下平台專有方法,僅在 `platform == "yunhu"` 時可用:

| 方法 | 回傳類型 | 說明 |
|------|----------|------|
| `get_raw_event()` | `dict` | 獲取雲湖原始事件資料(`yunhu_raw`) |
| `get_sender_level()` | `str` | 發送者雲湖原生等級(owner/administrator/member/unknown) |
| `get_sender_role()` | `str` | 發送者 OneBot12 標準 role(owner/admin/member) |
| `get_sender_title()` | `str` | 發送者頭銜(標準 `title` 欄位存取器,預留) |
| `get_sender_avatar()` | `str` | 發送者頭像 URL |
| `get_command()` | `dict` | 指令資料(僅指令訊息事件,`yunhu_command`) |
| `get_button_value()` | `str` | 按鈕點擊事件的 value(`yunhu_button.value`) |
| `get_a2ui_action()` | `str` | A2UI 按鈕事件的 actionName |
| `get_a2ui_form_context()` | `dict` | A2UI 按鈕事件的表單上下文 |
| `get_menu_id()` | `str` | 快捷選單事件 ID(`yunhu_menu.id`) |
| `get_setting()` | `dict` | 機器人設定事件的設定資料(`yunhu_setting`) |
| `is_command_message()` | `bool` | 是否為指令訊息 |
| `is_button_click()` | `bool` | 是否為按鈕點擊事件 |
| `is_a2ui_button()` | `bool` | 是否為 A2UI 按鈕事件 |

```python
from ErisPulse.Core.Event import notice

@notice.on_notice()
async def handle_yunhu_notice(event):
    if event.get("platform") != "yunhu":
        return

    if event.is_button_click():
        value = event.get_button_value()
        await event.reply(f"你點擊了按鈕: {value}")

    if event.get("detail_type") == "yunhu_shortcut_menu":
        menu_id = event.get_menu_id()

擴展欄位說明

表情包/貼紙訊息段 (yunhu_expression)

當使用者發送表情包或貼紙時,訊息段類型為 yunhu_expression:

{
  "type": "yunhu_expression",
  "data": {
    "sticker_id": "35154",
    "sticker_pack_id": "1670",
    "expression_id": "0",
    "image_name": "sticker/fabb9077f2ba302402ea871cab3686ad7a3fc52c.gif",
    "width": 500,
    "height": 500
  }
}
欄位 類型 說明
sticker_id string 貼紙唯一標識
sticker_pack_id string 貼紙包ID
expression_id string 表情ID
image_name string 表情圖片檔名
width int 圖片寬度(可選)
height int 圖片高度(可選)

使用範例:

from ErisPulse.Core.Event import message

@message.on_message()
async def handle_message(event):
    if event.get_platform() == "yunhu":
        for segment in event.get("message", []):
            if segment.get("type") == "yunhu_expression":
                data = segment["data"]
                print(f"收到表情包: sticker_id={data['sticker_id']}, 包ID={data['sticker_pack_id']}")

多Bot配置

配置說明

雲湖適配器支援同時配置和運行多個雲湖機器人帳戶。

# config.toml
[Yunhu_Adapter.accounts.bot1]
token = "your_bot1_token"  # 機器人token(必填)
mode = "ws"  # 接收模式(可選,默认为"ws",可选值:"ws"、"webhook")
webhook_path = "/webhook/bot1"  # Webhook路径(可选,默认为"/webhook")
enabled = true  # 是否启用(可选,默认为true)

[Yunhu_Adapter.accounts.bot2]
token = "your_bot2_token"  # 第二個機器人的token
webhook_path = "/webhook/bot2"  # 獨立的webhook路径
enabled = true

配置項說明:

重要提示:

  1. 雲湖平台的機器人ID在執行時自動檢測,無需在配置中指定
  2. webhook 模式下每個bot都應該有獨立的webhook_path,以便接收各自的webhook事件
  3. 在雲湖平台配置webhook時,請為每個bot配置對應的URL,例如:
    • Bot1: https://your-domain.com/webhook/bot1
    • Bot2: https://your-domain.com/webhook/bot2

使用Send DSL指定Bot

可以透過Using()方法指定使用哪個bot發送訊息。該方法支援兩種參數:

from ErisPulse.Core import adapter
yunhu = adapter.get("yunhu")

# 使用帳戶名發送訊息
await yunhu.Send.Using("bot1").To("user", "user123").Text("Hello from bot1!")

# 使用 bot_id 發送訊息(自動匹配對應帳戶)
await yunhu.Send.Using("30535459").To("group", "group456").Text("Hello from bot!")

# 不指定時使用第一個啟用的bot
await yunhu.Send.To("user", "user123").Text("Hello from default bot!")

提示: 使用 bot_id 時,系統會自動查找配置中匹配的帳戶。這在處理事件回覆時特別有用,可以直接使用 event["self"]["user_id"] 來回覆同一帳戶。

事件中的Bot標識

接收到的事件會自動包含對應的bot_id資訊:

from ErisPulse.Core.Event import message

@message.on_message()
async def handle_message(event):
    if event["platform"] == "yunhu":
        # 獲取觸發事件的機器人ID
        bot_id = event["self"]["user_id"]
        print(f"訊息來自Bot: {bot_id}")
        
        # 使用相同bot回覆訊息
        yunhu = adapter.get("yunhu")
        await yunhu.Send.Using(bot_id).To(
            event["detail_type"],
            event["user_id"] if event["detail_type"] == "private" else event["group_id"]
        ).Text("回覆訊息")

日誌資訊

適配器會在日誌中自動包含 bot_id 資訊,便於除錯和追蹤:

[INFO] [yunhu] [bot:30535459] 收到來自使用者 user123 的私聊訊息
[INFO] [yunhu] [bot:12345678] 訊息發送成功,message_id: abc123

管理介面

# 獲取所有帳戶資訊
bots = yunhu.bots

# 檢查帳戶是否啟用
bot_status = {
    bot_name: bot_config.enabled
    for bot_name, bot_config in yunhu.bots.items()
}

# 動態啟用/禁用帳戶(需要重新啟動適配器)
yunhu.bots["bot1"].enabled = False

舊配置相容

舊版 [Yunhu_Adapter.bots.*] 配置(含 bot_id 字段)會自動遷移到 accounts 格式(bot_id 已改為執行時自動檢測,配置中的值會被忽略);建議儘快遷移到新格式。