支持Markdown包裹的base64图片直发
1. 为Dify聊天插件新增Markdown图片语法解析,支持从  中提取内联图片。 2. 兼容JSON里text/answer/result/content字段承载Markdown图片的返回格式。 3. 避免绘图模型返回Markdown图片时被误判为普通文本而继续走md2image。
This commit is contained in:
@@ -561,7 +561,8 @@ class DifyPlugin(MessagePluginInterface):
|
|||||||
支持的输入形态:
|
支持的输入形态:
|
||||||
1. `data:image/png;base64,...` 这类 data URL;
|
1. `data:image/png;base64,...` 这类 data URL;
|
||||||
2. 纯 base64 图片字符串;
|
2. 纯 base64 图片字符串;
|
||||||
3. JSON 字符串里常见的 `b64_json` / `image_base64` / `base64` / `data` 字段。
|
3. Markdown 图片语法中的 data URL,例如 ``;
|
||||||
|
4. JSON 字符串里常见的 `b64_json` / `image_base64` / `base64` / `data` 字段。
|
||||||
"""
|
"""
|
||||||
normalized_text = str(response_text or "").strip()
|
normalized_text = str(response_text or "").strip()
|
||||||
if not normalized_text:
|
if not normalized_text:
|
||||||
@@ -572,6 +573,15 @@ class DifyPlugin(MessagePluginInterface):
|
|||||||
if image_bytes and str(mime_type or "").startswith("image/"):
|
if image_bytes and str(mime_type or "").startswith("image/"):
|
||||||
return image_bytes
|
return image_bytes
|
||||||
|
|
||||||
|
# 再处理 Markdown 包裹的 data URL。
|
||||||
|
# 当前绘图模型常见返回形态就是:
|
||||||
|
# 如果不先拆出来,后续会把整段 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,兼容工作流把 base64 包在结构化字段里的情况。
|
||||||
# 这里优先挑常见图片字段,避免把普通 JSON 文本误判成图片。
|
# 这里优先挑常见图片字段,避免把普通 JSON 文本误判成图片。
|
||||||
json_candidate = self._extract_base64_from_json_text(normalized_text)
|
json_candidate = self._extract_base64_from_json_text(normalized_text)
|
||||||
@@ -595,6 +605,27 @@ class DifyPlugin(MessagePluginInterface):
|
|||||||
value = parsed.get(key)
|
value = parsed.get(key)
|
||||||
if isinstance(value, str) and value.strip():
|
if isinstance(value, str) and value.strip():
|
||||||
return 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 ""
|
||||||
|
|
||||||
|
# 匹配形如 
|
||||||
|
match = re.search(r"!\[[^\]]*\]\((data:image/[^)]+)\)", normalized, flags=re.IGNORECASE | re.DOTALL)
|
||||||
|
if match:
|
||||||
|
return match.group(1).strip()
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
def _decode_base64_image_bytes(self, candidate: str) -> bytes:
|
def _decode_base64_image_bytes(self, candidate: str) -> bytes:
|
||||||
|
|||||||
Reference in New Issue
Block a user