From 6003aa7beb7703941f79dc93a261e56019e0ef88 Mon Sep 17 00:00:00 2001 From: liuwei Date: Tue, 28 Apr 2026 16:37:35 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81Markdown=E5=8C=85=E8=A3=B9?= =?UTF-8?q?=E7=9A=84base64=E5=9B=BE=E7=89=87=E7=9B=B4=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 为Dify聊天插件新增Markdown图片语法解析,支持从 ![image](data:image/...;base64,...) 中提取内联图片。 2. 兼容JSON里text/answer/result/content字段承载Markdown图片的返回格式。 3. 避免绘图模型返回Markdown图片时被误判为普通文本而继续走md2image。 --- plugins/dify/main.py | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/plugins/dify/main.py b/plugins/dify/main.py index dba55fb..a01ca55 100644 --- a/plugins/dify/main.py +++ b/plugins/dify/main.py @@ -561,7 +561,8 @@ class DifyPlugin(MessagePluginInterface): 支持的输入形态: 1. `data:image/png;base64,...` 这类 data URL; 2. 纯 base64 图片字符串; - 3. JSON 字符串里常见的 `b64_json` / `image_base64` / `base64` / `data` 字段。 + 3. Markdown 图片语法中的 data URL,例如 `![image](data:image/png;base64,...)`; + 4. JSON 字符串里常见的 `b64_json` / `image_base64` / `base64` / `data` 字段。 """ normalized_text = str(response_text or "").strip() if not normalized_text: @@ -572,6 +573,15 @@ class DifyPlugin(MessagePluginInterface): if image_bytes and str(mime_type or "").startswith("image/"): return image_bytes + # 再处理 Markdown 包裹的 data URL。 + # 当前绘图模型常见返回形态就是:![image_1](data:image/png;base64,...) + # 如果不先拆出来,后续会把整段 Markdown 当作普通文本,最终误走 md2image。 + markdown_data_url = self._extract_data_url_from_markdown(normalized_text) + if markdown_data_url: + image_bytes, mime_type = UnifiedLLMClient.decode_data_url(markdown_data_url) + if image_bytes and str(mime_type or "").startswith("image/"): + return image_bytes + # 再尝试把字符串解析为 JSON,兼容工作流把 base64 包在结构化字段里的情况。 # 这里优先挑常见图片字段,避免把普通 JSON 文本误判成图片。 json_candidate = self._extract_base64_from_json_text(normalized_text) @@ -595,6 +605,27 @@ class DifyPlugin(MessagePluginInterface): value = parsed.get(key) if isinstance(value, str) and value.strip(): return value.strip() + # 一些返回会把 markdown 图片包在 text 字段里,这里顺手兼容。 + if key == "data": + continue + for key in ("text", "answer", "result", "content"): + value = parsed.get(key) + if isinstance(value, str) and value.strip(): + markdown_data_url = self._extract_data_url_from_markdown(value.strip()) + if markdown_data_url: + return markdown_data_url + return "" + + def _extract_data_url_from_markdown(self, text: str) -> str: + """从 Markdown 图片语法中提取 data URL。""" + normalized = str(text or "").strip() + if not normalized: + return "" + + # 匹配形如 ![alt](data:image/png;base64,...) + match = re.search(r"!\[[^\]]*\]\((data:image/[^)]+)\)", normalized, flags=re.IGNORECASE | re.DOTALL) + if match: + return match.group(1).strip() return "" def _decode_base64_image_bytes(self, candidate: str) -> bytes: