1.前言
HiDream-E1-Full 是全球首款 对话式交互编辑模型,专注于解决传统图像生成工具中难以精准控制输出细节的痛点。其核心功能包括:
- 自然语言指令编辑:用户可通过自然语言对话(如“调整机械臂的金属光泽”“增加星空粒子效果”)对 HiDream-I1 生成的图像进行实时修改,无需手动调整参数,极大降低创作门槛。
- 多维度编辑能力:支持对图像风格、局部细节(如光影、材质)、构图元素(如添加或移除对象)等进行动态调整,形成“生成-反馈-优化”的闭环流程。
- 与 HiDream-I1 的协同性:作为 HiDream-I1 的配套工具,E1-Full 能够直接解析生成模型的中间结果,提升编辑效率与一致性。
一张图给大家展示一下效果
前期也给大家介绍过google Gemini 2.0 Flash Exp 文字一键生图改图工作流,本次给大家介绍的是一块开源的一键生图模型。
目前这个开源的模型已经在gitee平台上上架了,我也算是第一时间体验了这块模型。体验地址
目前gitee平台每天送100次模型体验,感兴趣小伙伴可以去平台注册和使用。下面我们重点看下dify平台整合这个模型的工作流是什么样子的
上面是整体工作流的截图。我们给大家看一下效果。
话不多说下面介绍一下这个工作流是如何制作的。
2.工作流的制作
这个工作流用到一个叫做图片转base64的第三方组件,我们需要在插件市场上把它安装。
关于这个组件的安装,这里就不做详细展开。这个组件安装后有地方需要设置否则会报错,关于这个组件的设置和注意事项。大家可以到文章末尾会介绍。
安装完成后我们就可以看到图片转base64这个插件了。
接下来我们把工作流制作需要的重点几个给大家介绍一下。
这个工作流由以下几个部分组成:1 开始节点、2条件分支、3图片转base64 、4代码执行、5 自定义HiDream E1图像生成_forbase64工具、6 代码执行 2、7 直接回复、8 变量赋值、9自定义HiDream E1图像生成_forimageurl 等组成。
开始
这个开始节点有2个参数,第一个参数是提示词prompt,第二个参数用户上传的图片
条件分支
这个地方主要是控制第一次和后面几次做区分的。 主要的判断依据就是picture_url 是否为空。picture_url 是一个会话变量。
条件分支配置如下截图
判断不为空就走上面的,为空就走下面,第一次就会走下面的流程。
会话变量
下面流程中用到了条件分支,这个条件分支的判断是生成图片的URL连接是否存在作为判断依据,所以我们这里增加一个会话变量。
这个会话变量只有在chatflow才会有的。顾名思义chat聊天才产生多伦对话。
我们需要添加一个picture_url 会话变量,主要是存储后面文生图产生的图片URL链接使用。
图片转Base64
这个就用到我们前面安装的第三方组件。
这个组件有好几个功能,我们这里用到了图片转base64,它的参数这里就一个文件。
代码出来
上面的组件返回的值 不是一个标准base64值,所以我们这里用代码处理一下
import json
def main(json_input_string: str) -> dict:
result_value = None
error_message = None
try:
text_field_value=json_input_string
if not text_field_value:
error_message = "错误:JSON 数据中未找到 'text' 字段。"
elif not isinstance(text_field_value, str):
error_message = "错误:'text' 字段的值不是字符串类型。"
elif "base64," not in text_field_value:
error_message = "错误:'text' 字段的值不包含 'base64,' 标记,格式不符合预期。"
else:
parts = text_field_value.split("base64,", 1)
# 确保 "base64," 后面确实有内容
if len(parts) > 1 and parts[1]:
result_value = parts[1]
else:
error_message = "错误:'text' 字段在 'base64,' 标记后没有数据。"
except json.JSONDecodeError:
error_message = "错误:无法解析输入的 JSON 字符串。"
except Exception as e:
error_message = f"处理过程中发生未知错误: {str(e)}"
# 确保始终返回包含 "result" 和 "error" 键的字典
# Dify 平台可能会专门查找 "result" 键。
# 如果发生错误,"result" 的值为 None,错误信息记录在 "error" 键中。
return {"result": result_value, "error": error_message}
自定义HiDream E1图像生成
这里我们需要先编写一个服务端代码,代码的部分主要是参考gitee api 接口然后我们使用fastapi实现接口的转发,程序部署在服务器上面。由于这个工作流涉及知识点较多,这里就不把详细代码展开细说。我们贴一下核心代码(关于详细代码我会上传到我开源项目里面,文章末尾会有项目合集,大家可以去上面找源码)
部分代码片段
@router.post("/difyforgitee/generate-HiDream-E1/")
async def generate_hidream_e1(request: HiDreamE1Request): # 修改函数签名以接收新的 Pydantic 模型
# --- 代理配置示例 ---
# 如果您的服务器需要通过代理访问外部网络,请取消注释以下行并配置您的代理服务器地址
# proxies = {
# "http://": "http://your_proxy_username:your_proxy_password@your_proxy_address:port",
# "https://": "https://your_proxy_username:your_proxy_password@your_proxy_address:port",
# }
# http_client_with_proxy = httpx.Client(proxies=proxies)
# --- ---
client = OpenAI(
base_url="https://ai.gitee.com/v1",
api_key=api_key, # 使用从配置文件读取的api_key
timeout=300.0, # <-- 修改: 设置请求超时时间为300秒
max_retries=0 # <-- 新增: 禁用重试
# http_client=http_client_with_proxy # <-- 新增: 如果使用代理,取消注释此行
)
logger.info(f"Received request with prompt: {request.prompt}, imageurl: {request.imageurl}, has_image_base64: {request.image_base64 is not None}")
base64_encoded_content_to_process: Optional[str] = None
if request.imageurl:
logger.info(f"Attempting to process image from URL: {request.imageurl}")
try:
async with httpx.AsyncClient(timeout=30.0) as http_client: # 使用 httpx 进行异步 GET 请求
response = await http_client.get(request.imageurl)
response.raise_for_status() # 如果状态码是 4xx 或 5xx,则引发 HTTPStatusError
image_bytes_from_url = response.content
base64_encoded_content_to_process = base64.b64encode(image_bytes_from_url).decode('utf-8')
logger.info(f"Successfully downloaded and base64 encoded image from URL: {request.imageurl}")
except httpx.HTTPStatusError as e:
logger.error(f"HTTP error downloading image from {request.imageurl}: {e.response.status_code} - {e.response.text}")
raise HTTPException(status_code=e.response.status_code, detail=f"下载图片URL '{request.imageurl}' 时出错: {e.response.status_code} - {e.response.text}")
except httpx.RequestError as e: # 处理网络错误、DNS 失败等
logger.error(f"Request error downloading image from {request.imageurl}: {str(e)}")
raise HTTPException(status_code=503, detail=f"连接图片URL '{request.imageurl}' 时出错: {str(e)}") # 503 Service Unavailable
except Exception as e: # 捕获其他意外错误
logger.error(f"Unexpected error processing image URL {request.imageurl}: {str(e)}")
raise HTTPException(status_code=500, detail=f"处理图片URL '{request.imageurl}' 时发生意外错误: {str(e)}")
elif request.image_base64:
logger.info("Using provided image_base64 from request body.")
base64_encoded_content_to_process = request.image_base64
if not base64_encoded_content_to_process:
logger.warning("No image data provided in request (neither imageurl nor image_base64).")
raise HTTPException(
status_code=400,
detail="未提供图像数据。请提供 'imageurl' 或 'image_base64'。"
)
logger.info(f"Proceeding with image processing. Base64 content length (approx): {len(base64_encoded_content_to_process) if base64_encoded_content_to_process else 0}")
try:
# 从请求体中获取 prompt (这部分逻辑不变)
prompt_text = request.prompt
# 将Base64字符串解码为字节
# 使用 base64_encoded_content_to_process 替代原来的 request.image_base64
try:
image_bytes = base64.b64decode(base64_encoded_content_to_process.encode('utf-8'))
except Exception as e:
logger.error(f"解码提供的Base64图片数据时出错: {str(e)}") # 增加此处的日志记录
raise HTTPException(status_code=400, detail=f"无法解码提供的Base64图片数据: {str(e)}")
logger.info(f"Base64图片数据已成功解码。 Image byte length: {len(image_bytes)}")
response = client.images.edit(
model="HiDream-E1-Full",
image=image_bytes, # 直接传递解码后的图片字节
prompt=prompt_text, # 使用从请求体中获取的 prompt
response_format="b64_json",
extra_body={
"steps": 28,
"instruction_following_strength": 5,
"image_preservation_strength": 3,
"refinement_strength": 0.3,
"seed": -1,
}
)
logger.info(f"Received response from Gitee API: {response}")
if not response.data or not response.data[0].b64_json:
raise HTTPException(status_code=500, detail="从Gitee API响应中获取base64数据失败。格式不符合预期。")
result_b64 = response.data[0].b64_json
filename, output_path_local = base64_to_image(result_b64, output_path)
logger.info(f"Image saved to {output_path_local}")
etag = upload_cos(region, secret_id, secret_key, bucket, filename, output_path)
logger.info(f"Image uploaded to COS with etag: {etag}")
if not etag:
raise HTTPException(status_code=500, detail="上传图片到COS失败。")
return {
"filename": filename,
"output_path": output_path_local, # 保持字段名一致性或明确区分
"etag": etag
}
except APIConnectionError as e: # <-- 新增: 更具体地捕获连接错误
logger.error(f"Gitee API Connection Error: {e}")
error_message = (
f"无法连接到 Gitee API (请求URL: {e.request.url if hasattr(e, 'request') and e.request else 'N/A'}): {str(e)}. "
"这通常是由于服务器的网络配置问题(例如防火墙、DNS解析、代理服务器设置)或目标服务暂时不可达。 "
"请检查服务器的网络连通性,并确认是否需要为应用程序配置代理服务器。"
)
raise HTTPException(status_code=503, detail=f"Gitee API 连接错误: {error_message}") # 503 Service Unavailable
except APIError as e:
logger.error(f"Gitee API Error: {e}")
error_detail = str(e)
if hasattr(e, 'message') and e.message:
error_detail = e.message
elif hasattr(e, 'response') and e.response is not None:
try:
# 尝试解析JSON响应体中的错误信息
error_content = e.response.json()
error_detail = error_content.get("error", {}).get("message", str(e.response.content))
except json.JSONDecodeError: # 如果响应不是有效的JSON
error_detail = e.response.text # 使用原始文本响应
except Exception: # 其他解析错误
error_detail = str(e.response.content) # Fallback to raw content as string
# Gitee API 可能会在 status_code 为 4xx/5xx 时返回非 JSON 错误,例如纯文本或 HTML
# 因此,直接使用 e.response.text 可能更稳妥,如果 JSON 解析失败
status_code_to_return = e.status_code if hasattr(e, 'status_code') and e.status_code else 500
raise HTTPException(status_code=status_code_to_return, detail=f"Gitee API 错误: {error_detail}")
except HTTPException as e:
logger.error(f"HTTPException: {e}")
raise e
except Exception as e:
logger.error(f"Unexpected error: {e}")
# 对于其他未预料到的错误,记录日志并返回通用错误信息
# import traceback; traceback.print_exc(); # 可选:在服务器端打印详细堆栈信息
raise HTTPException(status_code=500, detail=f"发生意外错误: {type(e).__name__} - {str(e)}")
这个服务端代码发布后我们需要写2个curl 命令来实现 测试,后面把这个curl命令转换成openapi 3.1.0 版本的json schema,我们一般测试可以先测试代码,也可以使用postman来实现测试
下面讲一下这个curl 命令如何转成openapi 3.1.0 版本的json schema。关于这块知识大家可以看我早起的文章
有的小伙伴看我上面的文章可能觉的还是有点麻烦,我这边也做了一个小工具帮助大家来生成json schema。
curl命令
这里我们有2段curl 命令代码如下
curl --location --request POST 'http://14.103.204.132:8080/difyforgitee/generate-HiDream-E1/' \
--header 'Content-Type: application/json' \
--data-raw '{"prompt": " 请将图片转成吉卜力风格", "image_base64": "/9j/4AAQSkZJRgAB...}'
curl --location --request POST 'http://14.103.204.132:8080/difyforgitee/generate-HiDream-E1/' \
--header 'Content-Type: application/json' \
--data-raw '{"prompt": " 请将图片转成吉卜力风格", "imageurl": "http://example.com/your_image.jpg"}'
使用工作流创建json schema
我们可以使用这个项目difyhs.duckcloud.fun/chat/71yzWK… 命令复制到工作流里面
工作流就会返回我们要的openapi 3.1.0 版本的json schema
上面json schema 代码我们就可以到dify 自定义工具中创建。
制作自定义工具
把生成的代码在自定义工具添加。
点击创建自定义工具,把上面的JSON 代码复制到shema里面
自定义接口可以增加一个鉴权,增加安全性。
以上设置完成后我们,我们点击保存完成自定工具创建
自定义工具在dify使用
我们回到dify工作流界面中。添加节点-工具-HiDream E1 图像生成_forbase64
这个自定义工具有2个参数,第一个是 prompt 第二是前面base64工具转化后的base64值
代码运行
这个代码运行和我之前文生的代码类似,主要功能就是通过服务端代码生成的图片上传到我的腾讯COS图床上,返回我要的图片的URL地址我这边用代码解析返回的URL .
代码如下
def main(arg1: str) -> str:
import json
data = json.loads(arg1)
filename=data['filename']
url=data['etag']
markdown_result = f""
return {"result": markdown_result,"url": url}
输入参数 arg1
返回参数 result,url
直接回复
这个直接回复就比较简单了,把上面代码执行的信息返回
变量赋值
这个地方主要的目的是为了通过全局变量保存会话产生的图片的url 方便后面第二轮,第三轮对话时候用到上一次对话的图片地址。
这个地方只是赋值就可以了,这个地方需要结合前面的会话变量设置一起用。简单来说就是前面配置好,这个地方来使用。
好了,上面第一轮对话的工作流就已经初步制作完成了。接下来我们将第二个分支
这个分支和上面的东西几乎是一样的,差异就是自定义工具。
自定义HiDream E1图像生成(图片url)
我们在上面条件分支if语句中拉一个自定义HiDream E1图像生成_forimageurl,这个自定义工具和上面步骤6一行的。
它有2个参数,第一个参数是 prompt,这里我们接受系统提示词。
另外一个imageurl 这个地方我们就从上面变量赋值获取picture_url
后面的流程和前面的都一样,这里我们就不做详细展开了。
通过以上我们就完成了工作流的制作。
3.工作流的分享和使用
接下来我们就可以把工作流分享出去了。
体验地址difyhs.duckcloud.fun/chat/GIcuzi… 备用地址(http://14.103.204.132/chat/GIcuziInjH61FLUx)
相关资料和文档可以看我开源的项目 github.com/wwwzhouhui/…
4.问题记录
前面我们提到工作流在使用到图片转base64的第三方组件 安装访问遇到的问题
如果默认安装小伙伴大概率会遇到这个问题。
出现上述错误如何解决?
需要修改2个地方。
1.env 文件中查找FILES_URL
默认的FILES_URL是空的,我们需要修改使用 http://:5001 或 http://api:5001,在此情况下,确保外部可以访问端口 5001
2.docker-compose.yaml 对应的FILES_URL修改
此外dify-api容器镜像端口开放出来(默认情况是不开放的),增加如下代码
ports:
- '5001:5001'
我们也可以从docker容器看到端口开放情况(默认是不开启的)
另外我们在运行调用自定义接口 可能会返回超时,主要原因是请求接口的重试机制和超时导致的额,这里大家多试一试。
5.总结
今天主要带大家了解并实现了基于 HiDream - E1 - Full 模型在 Dify 平台的图像编辑工作流方案。详细介绍了在 Dify 平台整合此模型的工作流制作过程。该工作流由开始节点、条件分支、图片转 base64、代码执行、自定义 HiDream E1 图像生成工具等多个部分组成。在制作过程中,涉及第三方组件的安装与设置、服务端代码的编写、curl 命令转成 OpenAPI 3.1.0 版本的 json schema、自定义工具的创建与使用等多个关键步骤,还针对流程中使用的会话变量、代码处理等细节进行了说明。总体来说,这个方案相对较为全面地整合了图像编辑和生成的功能,为用户提供了一种便捷、高效的图像创作方式。感兴趣的小伙伴可以按照本文步骤去尝试。今天的分享就到这里结束了,我们下一篇文章见。