作者:鸥弋、筱姜

2023年下半年,ComfyUI 以其快速、流畅的图像生成能力,结合多样的自定义节点,迅速在创作者中流行起来。ComfyUI 的亮点就是能够批量化生成图像,一键加载大量工作流,让用户可以轻松实现人像生成、背景替换、风格迁移和图像动画化等功能。越来越多的企业及个人开发者希望借助 ComfyUI 能力进行 AI 绘画领域创业或者业务上新,获得高流量及商业价值,但使用原生的 ComfyUI 仍然存在一些问题:

1.显卡资源昂贵且难以购买:GPU 卡池管理技术门槛高:高性能的 GPU 资源不仅价格昂贵,而且往往难以大规模采购。此外,GPU 卡池的有效管理和维护需要复杂的技术支持,也带来了额外的挑战。
2.难以应对高并发:原生的 ComfyUI 出图需要排队,并发处理能力有限。在面对高并发场景时,尤其是并发请求具有大的波动性时,资源配置难以精确预测,从而可能导致系统错误和业务中断。
3.门槛高,难以对外透出:ComfyUI 拥有一定的门槛,对于普通的创作者而言几乎无法使用,需要对其进行二次包装才能让更多用户享受到 AI 的便捷。

为了帮助用户高效率、低成本应对企业级复杂场景,以下介绍 ComfyUI API Serverless 版解决方案,通过使用该方案,用户可以充分利用 ComfyUI + Serverless 技术优势快速开发上线 AI 绘画应用,期待为广大开发者 AI 绘画创业及变现提供思路。
相关文章: AI 绘画平台难开发,难变现?试试 Stable Diffusion API Serverless 版解决方案

阿里云X优酷联名发起的「Creat@AI江湖创作大赛」使用本文章中的解决方案,基于函数计算FC 一键部署 AI 绘图平台,1分钟实现 “破次元壁合照”、5分钟实现 Stable Diffusion、ComfyUI 部署,生成以“少年江湖“为主题的画作赢万元奖金。
活动链接: https://developer.aliyun.com/plan/create/snbm
零门槛AI 绘图:教你为客户定制 ComfyUI Serverless API 应用_serverless

方案优势

在以往的活动中,我们也面临了很多非技术相关的用户期望享受 AI 的魅力。结合实际需要我们给出了 Serverless 化的 ComfyUI 实践案例,解决了上述问题。

  • 部署简单:提供基础 ComfyUI 镜像,不需要修改时一键即可拉起出图,需要修改时也只需要修改 ComfyUI 镜像地址即可
  • 弹性 GPU:函数计算提供了 GPU 弹性的能力,根据实际请求控制实例个数,有突发流量时自动弹新实例承接请求,完全不需要增加额外的关注
  • 按量付费:函数计算的按量实例为毫秒级粒度的计费策略,用多久就收多少钱,确保每分钱都花在刀刃上
  • ComfyUI Serverless 化改造:对原本不适应 Serverless 弹性能力的 ComfyUI 改造,使其可以支持异步、并发、弹性等各种 Serverless 能力
  • 前后端联动:活动开源了一个支持自定义参数,并且并发出图的前端页面,可直接提供给客户使用

应用场景

ComfyUI 提供了非常高的自由度和灵活性,支持定制化工作流,并且可以重复使用,批量出图,特别适用于需要创意图像生成场景:

  • 艺术创作与设计: 艺术家和设计师可以利用 ComfyUI 生成独特的艺术作品,包括概念艺术、插画、海报设计等。通过 ComfyUI,他们可以根据自己的创意想法生成初步的图像草稿,然后再进一步细化和完善。
  • 内容制作与营销: 在社交媒体、广告和营销领域,ComfyUI 可用于快速生成符合品牌风格的视觉素材,用于社交媒体内容、广告横幅、海报等
  • 游戏开发: 游戏开发者可能利用 ComfyUI 自动生成游戏内的景观或建筑物的纹理,减少手工制作这些元素所需的时间和成本。
  • 视觉特效与影视后期: 电影和电视行业的视觉特效团队可以使用 ComfyUI 来辅助创建逼真的背景、特殊效果或修复旧影片中的画面缺陷。

通过 API 接口调用 ComfyUI 解决方案

常规的 ComfyUI 出图的流程大致如下

  • 调用 /prompt 接口,发起出图任务
  • 通过 WebSocket 获取出图进度

由于在 Serverless 场景下,无请求的时候实例会被冻结,因此 WebSocket 请求是必须要存在的,且需要保持连接到出图完成。

在并发请求数比较大的情况下,我们往往期望可以利用 Serverless 的弹性,动态创建多个函数实例处理出图任务。但由于 ComfyUI 本身是“有状态”的,难以确保出图的请求和获取状态的请求固定打到同一个实例上,这可能会导致接口的调用不符合预期。

为了让 ComfyUI 更加适配 Serverless 模式,需要针对 ComfyUI 进行一定的改造。
参考  fc-comfyui/src/images/agent 的代码,在 ComfyUI 镜像里内置 agent 程序,负责转换 ComfyUI 请求并且拉起 ComfyUI。
零门槛AI 绘图:教你为客户定制 ComfyUI Serverless API 应用_serverless_02

注意!
我们提供的代码仅用于运营活动使用,作为 Serverless 方式调用的实践参考。
功能未经过严格测试,请根据实际的业务需要开发或调整相关的代码,并构建 ComfyUI 镜像。

目前提供的 Agent 能力介绍

开启 Agent 能力,需要增加环境变量

  • USE_AGENT1

当通过 Agent 的 API 调用时,建议您调整单实例并发度为 1 ~ 5,确保并发请求尽量使用单独的实例,提高出图效率

数据类型

出图 Prompt

与 ComfyUI 在 Dev Mode 导出的文件一致

  1. type TPromptNode struct {
  2. Inputs map[string]any `json:"inputs"`
  3. ClassType string `json:"class_type"`
  4. Meta map[string]any `json:"_meta"`
  5. }
  6. type TPrompt map[string]TPromptNode
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

LoadImage 节点的参数做了特殊处理,如果内容为 base64 或 http 地址,会自动将对应的文件上传,并转换为 ComfyUI 可识别的形式

进度
  1. // key 为 node id 的 map 对象
  2. type TProgress map[string]TProgressNode
  3. type TProgressNode struct {
  4. Max int `json:"max"` // 进度的最大值
  5. Value int `json:"value"` // 当前进度
  6. Start int64 `json:"start"` // 开始时间
  7. LastUpdated int64 `json:"last_updated"` // 最后一次更新时间
  8. Images []TProgressNodeImage `json:"images"` // 当前节点输出的图片信息(路径)
  9. Results []string `json:"results,omitempty"` // 当前节点输出的图片 base64
  10. }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

接口

出图请求(HTTP 同步)

路径:/api/run
Body:json 格式的 prompt 数据
返回值:最后一次的进度(包含图片信息)

当需要异步请求时,需要增加 X-Fc-Invocation-Typetask-id,前者告知 FC 异步形式调用,后者用于记录当前任务的唯一 id,方便后续获取状态

  1. curl http://xxxxx/api/run -v \
  2. -H 'X-Fc-Invocation-Type: Async' \
  3. -H "task-id: abcdefg" \
  4. -XPOST \
  5. -d '{
  6. "3": {
  7. "inputs": {
  8. "seed": 1586995582004891,
  9. "steps": 17,
  10. "cfg": 6,
  11. "sampler_name": "dpm_2",
  12. "scheduler": "karras",
  13. "denoise": 1,
  14. "model": [
  15. "33",
  16. 0
  17. ],
  18. "positive": [
  19. "31",
  20. 0
  21. ],
  22. "negative": [
  23. "32",
  24. 0
  25. ],
  26. "latent_image": [
  27. "5",
  28. 0
  29. ]
  30. },
  31. "class_type": "KSampler",
  32. "_meta": {
  33. "title": "KSampler"
  34. }
  35. },
  36. "4": {
  37. "inputs": {
  38. "ckpt_name": "majicMIX realistic_v7.safetensors"
  39. },
  40. "class_type": "CheckpointLoaderSimple",
  41. "_meta": {
  42. "title": "Load Checkpoint"
  43. }
  44. },
  45. "5": {
  46. "inputs": {
  47. "width": 1024,
  48. "height": 784,
  49. "batch_size": 1
  50. },
  51. "class_type": "EmptyLatentImage",
  52. "_meta": {
  53. "title": "Empty Latent Image"
  54. }
  55. },
  56. "6": {
  57. "inputs": {
  58. "text": "2 human\nhi quality,detailed",
  59. "clip": [
  60. "4",
  61. 1
  62. ]
  63. },
  64. "class_type": "CLIPTextEncode",
  65. "_meta": {
  66. "title": "CLIP Text Encode (Prompt)"
  67. }
  68. },
  69. "8": {
  70. "inputs": {
  71. "samples": [
  72. "3",
  73. 0
  74. ],
  75. "vae": [
  76. "4",
  77. 2
  78. ]
  79. },
  80. "class_type": "VAEDecode",
  81. "_meta": {
  82. "title": "VAE Decode"
  83. }
  84. },
  85. "9": {
  86. "inputs": {
  87. "filename_prefix": "ComfyUI",
  88. "images": [
  89. "8",
  90. 0
  91. ]
  92. },
  93. "class_type": "SaveImage",
  94. "_meta": {
  95. "title": "Save Image"
  96. }
  97. },
  98. "10": {
  99. "inputs": {
  100. "image": "https://serverless-tool-images.oss-cn-hangzhou.aliyuncs.com/aigc/json/couple/default.png",
  101. "upload": "image"
  102. },
  103. "class_type": "LoadImage",
  104. "_meta": {
  105. "title": "Load Image"
  106. }
  107. },
  108. "11": {
  109. "inputs": {
  110. "image": "https://serverless-tool-images.oss-cn-hangzhou.aliyuncs.com/aigc/json/couple/百里东君.png",
  111. "upload": "image"
  112. },
  113. "class_type": "LoadImage",
  114. "_meta": {
  115. "title": "Load Image",
  116. "edit": []
  117. }
  118. },
  119. "12": {
  120. "inputs": {
  121. "image": "https://serverless-tool-images.oss-cn-hangzhou.aliyuncs.com/aigc/json/couple/background.png",
  122. "upload": "image"
  123. },
  124. "class_type": "LoadImage",
  125. "_meta": {
  126. "title": "Load Image"
  127. }
  128. },
  129. "13": {
  130. "inputs": {
  131. "image": "https://serverless-tool-images.oss-cn-hangzhou.aliyuncs.com/aigc/json/couple/mask.png",
  132. "upload": "image"
  133. },
  134. "class_type": "LoadImage",
  135. "_meta": {
  136. "title": "Load Image"
  137. }
  138. },
  139. "15": {
  140. "inputs": {
  141. "threshold_r": 0.15,
  142. "threshold_g": 0.15,
  143. "threshold_b": 0.15,
  144. "remove_isolated_pixels": 0,
  145. "fill_holes": false,
  146. "image": [
  147. "13",
  148. 0
  149. ]
  150. },
  151. "class_type": "MaskFromRGBCMYBW+",
  152. "_meta": {
  153. "title": "声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
    推荐阅读
    相关标签