第 4 课 AI 画图:一句话让豆包画图,再一句句接着改 | 大模型多模态专题

返回专题

做完你会得到什么

一个「AI 画图」App:写一句「一只戴宇航员头盔的橘猫,站在月球上,水彩风格」,十几秒后出图;再写「把背景换成晚霞」,它在这张图上接着改。每一版都留着,可以退回上一版;满意了下载保存、分享出去。

AI 画图界面预览

图为执行最终 .aia 里的真实积木生成的布局预览,不是真机截图;AI 的回答与照片、生成的图片都是示意。

难度 用时 前置 用到的模型
★★ 40 分钟 第 1 课、会用列表 豆包 Seedream 生图模型(doubao-seedream-4-0-250828)

下载本课 .aia(AiPainter.aia)

准备

准备什么 说明
火山方舟 API Key 到 火山方舟控制台 创建 API Key
开通生图模型 火山方舟里的模型要先开通再调用:控制台「开通管理」里找到 Seedream,点开通。没开通会报 ModelNotOpen
豆包组件的属性 生图只看 ImageModelName(默认 doubao-seedream-4-0-250828)、ImageSize、ImageWatermark,不用填 ModelName(那是对话和识图用的)

文生图与图生图

  文生图 图生图
方法 GenerateImage(描述) GenerateImageFromUrl(描述, 参考图地址)
参考图 无 一个图片网址(本课用上一版的地址;第 5 课教你把本地照片变成地址)
结果 GotImage(imageUrl):一个临时图片地址 同左

imageUrl 可以直接设给图像组件的「图片」属性显示。它是临时链接,过一段时间会失效,要长期保留就下载到手机上。

界面组件

组件 命名 关键属性 / 作用
文本输入框 文本输入框_描述 允许多行,高 90
下拉框 下拉框_尺寸 元素字串:方形 2K,竖版 9:16,横版 16:9
图像 图像_作品 高 300,缩放图片以适应
文本输入框 文本输入框_修改 提示:接着改,比如:把背景换成晚霞
按钮 按钮_画图、按钮_修改、按钮_上一版、按钮_保存、按钮_分享  
Doubao(拓展) Doubao1 默认属性即可
Web 客户端 Web客户端1 保存响应信息 勾上(下载成文件)
信息分享器 信息分享器1  
计时器 计时器1 给文件名取时间戳;启用计时 设为假

API Key 卡片与第 1 课相同(标签名 doubaoKey)。

分步搭

第 1 步:文生图,尺寸用下拉框选

ImageSize 可以填 1K/2K/4K,也可以填具体像素。竖版、横版用 Seedream 推荐的 2K 像素尺寸。

global 版本 = []
global 序号 = 0
global 正在画 = false
global 已保存 = ""

function 尺寸值(选项) {
  return choose(选项 == "竖版 9:16", "1440x2560", choose(选项 == "横版 16:9", "2560x1440", "2K"))
}

when 按钮_画图.Click() {
  var 描述 = trim(文本输入框_描述.Text)
  if Doubao1.APIKey == "" {
    底部提示条1.Show("先在上面填好 API Key 并点保存")
  } else if 描述 == "" {
    底部提示条1.Show("先写下想画什么")
  } else {
    Doubao1.ImageSize = 尺寸值(下拉框_尺寸.Selection)
    开始画("正在画……")
    Doubao1.GenerateImage(描述)
  }
}

描述怎么写出好图:主体 + 动作 + 场景 + 风格 + 光线,越具体越好。「一只猫」不如「一只戴宇航员头盔的橘猫,站在月球表面,背后是蓝色的地球,水彩风格,柔和的侧光」。描述不要超过 300 个汉字。

第 2 步:每一版都记下来

用一个列表 版本 存下每次得到的图片地址,序号 指向正在看的那一版。新图来了就追加到列表末尾,并切到最新一版。

when Doubao1.GotImage(imageUrl) {
  正在画 = false
  listadd(版本, imageUrl)
  序号 = length(版本)
  显示当前()
}

procedure 显示当前() {
  图像_作品.Picture = 版本[序号]
  已保存 = ""
  标签_状态.Text = join("第 ", 序号, " / ", length(版本), " 版。图片链接有时效,满意的记得下载保存。")
  刷新按钮()
}

procedure 开始画(状态) {
  正在画 = true
  标签_状态.Text = 状态
  刷新按钮()
}

中途验证:写一句描述点「开始画」,十几秒后图片出现,状态行「第 1 / 1 版」。

第 3 步:图生图,在当前这一版上接着改

修改时把正在看的那一版的地址当参考图传进去。描述只写「要改什么」就行:「把背景换成晚霞」「加一面小红旗」「改成黑白漫画风」。

when 按钮_修改.Click() {
  var 修改 = trim(文本输入框_修改.Text)
  if 序号 == 0 {
    底部提示条1.Show("先画出第一张")
  } else if 修改 == "" {
    底部提示条1.Show("写下想怎么改,比如:把背景换成晚霞")
  } else {
    文本输入框_修改.Text = ""
    开始画(join("正在改:", 修改))
    Doubao1.GenerateImageFromUrl(修改, 版本[序号])
  }
}

when 按钮_上一版.Click() {
  if 序号 > 1 {
    序号 = 序号 - 1
    显示当前()
  }
}

退回到第 1 版再改,新结果会追加成第 3 版,第 2 版不会丢。

中途验证:改一次得到第 2 版;点「上一版」回到第 1 版;在第 1 版上再改,得到「第 3 / 3 版」。

第 4 步:按钮状态一处管

哪些按钮能点,取决于「是不是正在画」「有没有作品」「有没有上一版」「有没有下载好的文件」。把这些规则写在一个过程里,任何状态变化后调用它一次。

procedure 刷新按钮() {
  按钮_画图.Enabled = not 正在画
  按钮_修改.Enabled = not 正在画 and 序号 > 0
  按钮_上一版.Enabled = not 正在画 and 序号 > 1
  按钮_保存.Enabled = not 正在画 and 序号 > 0
  按钮_分享.Enabled = not 正在画 and 已保存 != ""
}

第 5 步:下载保存与分享

Web 客户端勾上「保存响应信息」后,Get() 不再返回文本,而是把内容存成文件,完成时触发获得文件,参数里有文件的完整路径。文件名带上毫秒时间戳,保存多张不会互相覆盖。

when 按钮_保存.Click() {
  if 序号 > 0 {
    Web客户端1.ResponseFileName = join("ai-painting-", 计时器1.SystemTime(), ".jpg")
    Web客户端1.Url = 版本[序号]
    标签_状态.Text = "正在下载……"
    Web客户端1.Get()
  }
}

when Web客户端1.GotFile(url, responseCode, responseType, fileName) {
  if responseCode == 200 {
    已保存 = fileName
    标签_状态.Text = join("已保存到 App 文件夹,可以点「分享」发到相册或聊天:", fileName)
  } else {
    标签_状态.Text = join("下载失败(", responseCode, "):图片链接可能已经过期,重新画一张吧。")
  }
  刷新按钮()
}

when 按钮_分享.Click() {
  信息分享器1.ShareFile(已保存)
}

文件存在 App 自己的文件夹里,相册里看不到。点「分享」弹出系统分享面板,选「保存到相册」或发给好友。

中途验证:点「下载保存」,状态行出现文件路径,「分享」变成可点;分享到微信能看到这张图。

第 6 步:出错处理

生图有两个特有的错误:模型没开通(ModelNotOpen),以及内容审核没通过(错误码里带 Sensitive,描述或生成的图被判定为不适合的内容)。

when Screen1.ErrorOccurred(component, functionName, errorNumber, message) {
  正在画 = false
  刷新按钮()
  标签_状态.Text = 错误说明(message)
}

function 错误说明(message) {
  return choose(containstext(message, "401"), "API Key 不对:检查是否抄全,或到火山方舟重新创建。", choose(containstext(message, "ModelNotOpen"), "生图模型还没开通:到火山方舟「开通管理」里开通 Seedream 后再试。", choose(containstext(message, "Sensitive"), "描述或图片被判定为不适合生成的内容,换个说法试试。", choose(containstext(message, "429"), "请求太频繁了,等几秒再试。", join("出错了:", message)))))
}

这一课的要点

  • 生图是异步的:调用后立刻返回,图片地址在 GotImage 里拿。
  • 图生图要的是网址:本课用上一版的地址,自然形成「一句句改」的效果。
  • 结果是临时链接:要保留就用 Web 客户端「保存响应信息」下载成文件。
  • 生图和对话用不同的模型属性:生图看 ImageModelName,对话识图看 ModelName,互不影响。
  • 一张图一般要十几秒到几十秒,生成期间一定要把按钮变灰,否则用户连点几次就是几张图的费用。

常见问题

现象 原因与处理
状态行「生图模型还没开通」 火山方舟控制台「开通管理」里开通 Seedream 后再试
状态行「被判定为不适合生成的内容」 描述里有敏感词,或生成的画面被审核拦下。换个说法,避免真实人名、暴力等内容
图片出来了,过几天再打开 App 显示不出来 链接过期了。满意的图当场「下载保存」
下载失败(403 / 404) 同上,链接已失效,重新生成
改了几次,图越改越不像原来的 图生图每次都会重新画,细节会漂移。一次只改一处,并在修改描述里强调「其余保持不变」
生成的图片上带水印 ImageWatermark 为真时会加水印,默认是假
竖版、横版没生效 检查 ImageSize 传的是不是 1440x2560 这种「宽x高」格式,中间是小写字母 x

平台说明

  • 安卓、鸿蒙都能运行。鸿蒙版豆包组件的生图默认模型与安卓一致。
  • 业务检查见验证记录:尺寸取值、在当前版本上改、退回后再改追加新版本、下载与分享、链接过期、三类出错等都逐条执行过。

下一课

第 5 课 照片变漫画:图生图要的是网址,可手机里的照片没有网址怎么办?下一课用「图片处理」把照片变成一个 Base64 图片地址,一键把自拍变成动漫、水彩、像素、黏土四种风格。

文档反馈