Skip to content

fix: 兼容 richText 消息中不带 type 字段的文本节点解析 - #8

Open
ecator wants to merge 1 commit into
DingTalk-Real-AI:mainfrom
ecator:fix/richtext_typemiss
Open

ecator wants to merge 1 commit into
DingTalk-Real-AI:mainfrom
ecator:fix/richtext_typemiss

Conversation

@ecator

@ecator ecator commented Oct 18, 2026

Copy link
Copy Markdown

问题描述

当用户在钉钉客户端发送带有附件(如图片+文字说明)的消息时,钉钉回调下发的消息类型为 msgtype: "richText"。根据钉钉回调协议及真实消息样本:

  1. 顶层 text 字段仅在 msgtype == "text" 时存在,richText 消息的正文与附件均位于 content.richText 数组中。
  2. content.richText 数组中的图片/文件等附件节点带有 "type": "picture" / "type": "file",但普通文本节点仅包含 {"text": "..."},不携带 {"type": "text"}字段:
{
  "msgtype": "richText",
  "content": {
    "richText": [
      {
        "pictureDownloadCode": "EJiwxxxxx",
        "downloadCode": "mIoxxxxx",
        "type": "picture"
      },
      {
        "text": "\n"
      },
      {
        "text": "请解释下"
      }
    ]
  }
}

此前 convert_rich_text 仅在 item.get("type", "") == "text" 时提取文本,导致真实 richText 消息中的文本段落被全部忽略,最终归一化后的 IncomingMessage.text 为空字符串 ""。

修改内容

  • src/dingtalk_channel_sdk/normalize/converters/richtext.py:
    • 将文本节点的类型判断放宽为 item_type in ("", "text")(item_type = item.get("type") or ""),同时兼容钉钉真实回调中缺省 type字段的文本段与显式指定 "type": "text" 的场景。
    • 对 content.get("richText") 增加 isinstance(..., list) 防御性校验。
    • 单元测试:
      • tests/test_normalize_converters.py:新增 test_convert_rich_text_without_type_field,覆盖无 type 文本段与图片/文件混排解析。
      • tests/test_message.py:新增 test_normalize_richtext_with_attachment_without_text_type,覆盖群聊 @ 剥离及单聊真实样本的 IncomingMessage归一化验证。

测试验证

  • 运行 pytest 全量单测(140 passed)全部通过。

一些钉钉原始消息样本
Details

单纯图片

没有文字说明

{
    "senderPlatform": "Win",
    "conversationId": "cidXxxxxx=",
    "chatbotCorpId": "dingxxxxxx",
    "chatbotUserId": "$:LWCP_v1:$xXxxxx",
    "openThreadId": "cidXxxxxx=",
    "msgId": "msgXxxx",
    "senderNick": "Xxxxx",
    "isAdmin": true,
    "senderStaffId": "0000000000-1234334534",
    "sessionWebhookExpiredTime": 1792293932778,
    "createAt": 1792288532437,
    "content": {
        "pictureDownloadCode": "EJixxxxx",
        "downloadCode": "mIoxxxxxxx"
    },
    "senderCorpId": "dingxxxxxx",
    "conversationType": "1",
    "senderId": "$:LWCP_v1:$Xxxxxx",
    "sessionWebhook": "https://oapi.dingtalk.com/robot/sendBySession?session=xxxxfsdfsdfsdfsdfessxxxxxx",
    "robotCode": "dingjgxxxxxxxxxxxxxxx",
    "msgtype": "picture"
}

纯文本消息

{
    "senderPlatform": "Win",
    "conversationId": "cidXxxxxx=",
    "chatbotCorpId": "dingxxxxxx",
    "chatbotUserId": "$:LWCP_v1:$xXxxxx",
    "openThreadId": "cidXxxxxx=",
    "msgId": "msgXxxx",
    "senderNick": "Xxxxx",
    "isAdmin": true,
    "senderStaffId": "0000000000-1234334534",
    "sessionWebhookExpiredTime": 1792293989877,
    "createAt": 1792288589651,
    "senderCorpId": "dingxxxxxx",
    "conversationType": "1",
    "senderId": "$:LWCP_v1:$Xxxxxx",
    "sessionWebhook": "https://oapi.dingtalk.com/robot/sendBySession?session=xxxxfsdfsdfsdfsdfessxxxxxx",
    "text": {
        "content": "你好"
    },
    "robotCode": "dingjgxxxxxxxxxxxxxxx",
    "msgtype": "text"
}

图片加文字说明

{
    "senderPlatform": "Win",
    "conversationId": "cidXxxxxx=",
    "chatbotCorpId": "dingxxxxxx",
    "chatbotUserId": "$:LWCP_v1:$xXxxxx",
    "openThreadId": "cidXxxxxx=",
    "msgId": "msgsXxxxxxx",
    "senderNick": "Xxxxx",
    "isAdmin": true,
    "senderStaffId": "0000000000-1234334534",
    "sessionWebhookExpiredTime": 1792294060566,
    "createAt": 1792288660182,
    "content": {
        "richText": [
            {
                "pictureDownloadCode": "EJiwxxxxx",
                "downloadCode": "mIoxxxxx",
                "type": "picture"
            },
            {
                "text": "\n"
            },
            {
                "text": "请解释下"
            }
        ]
    },
    "senderCorpId": "dingxxxxxx",
    "conversationType": "1",
    "senderId": "$:LWCP_v1:$Xxxxxx",
    "sessionWebhook": "https://oapi.dingtalk.com/robot/sendBySession?session=xxxxfsdfsdfsdfsdfessxxxxxx",
    "robotCode": "dingjgxxxxxxxxxxxxxxx",
    "msgtype": "richText"
}

单纯文件

{
    "senderPlatform": "Win",
    "conversationId": "cidXxxxxx=",
    "chatbotCorpId": "dingxxxxxx",
    "chatbotUserId": "$:LWCP_v1:$xXxxxx",
    "openThreadId": "cidXxxxxx=",
    "msgId": "msgsxxxxx",
    "senderNick": "Xxxxx",
    "isAdmin": true,
    "senderStaffId": "0000000000-1234334534",
    "sessionWebhookExpiredTime": 1792294174165,
    "createAt": 1792288773932,
    "content": {
        "spaceId": "1111111111111",
        "fileName": "xxxxx.mp3",
        "downloadCode": "j7mg+lxxxxxxx",
        "fileId": "222222222222"
    },
    "senderCorpId": "dingxxxxxx",
    "conversationType": "1",
    "senderId": "$:LWCP_v1:$Xxxxxx",
    "sessionWebhook": "https://oapi.dingtalk.com/robot/sendBySession?session=xxxxfsdfsdfsdfsdfessxxxxxx",
    "robotCode": "dingjgxxxxxxxxxxxxxxx",
    "msgtype": "file"
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant