让照片里的角色开口说话
本示例使用 Grok Imagine 将角色图片制作成会说话的视频。你将看到如何在一个视频提示词中引用多张图片和多种声音,让两个角色在同一段视频中对话。
提供一张角色图片,例如绘画、吉祥物或宠物照片,选择一种内置声音,再写一句台词。Grok Imagine 会生成一段短视频,让角色用指定声音说出这句话。加入第二个角色后,它会在同一段视频中用自己的声音回应。示例中的网页应用会在你编写时展示请求,并在视频完成后播放。
你将学到什么
在同一视频提示词中引用多张图片和多种声音,使用
<IMAGE_0>、<IMAGE_1>、<AUDIO_0>,<AUDIO_1>标签为每个角色指定预设声音,将其
voice_id填入reference_audios使用
client.voice.list()列出声音,并通过client.voice.speak()试听,再决定是否付费生成视频查询视频任务,使用
client.videos.get()显示当前进度通过服务器发送事件(SSE)将进度从 Node 服务器流式传送到网页
运行示例
需要 Node.js 22.13 或更高版本。将 API 密钥放入 .env(位于仓库根目录),或导出环境变量 XAI_API_KEY。
cd examples/photo-to-talking-character/typescript
npm install
npm run web打开 http://localhost:3000,点击 Try the dog and the cat,或添加自己的图片,选择声音并写一句台词。然后点击 Make it talk。这个页面就像一个小型动画工作室。左侧每个角色都有图片、台词,以及能用所选声音朗读台词的播放按钮。舞台上的角色旁会用气泡显示台词;舞台下方展示即将发出的请求,每个标签旁边都标出对应的图片或声音。渲染期间,舞台会显示进度,完成后播放视频。点击 Add a character who answers 可添加第二个角色。点击 Stop 仅停止等待。API 不支持取消已启动的视频任务,因此仍会完成渲染并计费。
如需在终端中生成视频,请为每个角色传入图片、声音和台词。使用 voices 可列出声音:
npm start -- ./your-drawing.png eve "Hello! Somebody finally drew me a mouth."
npm start -- ./dog.png rex "Want to play?" ./cat.png luna "No."
npm start -- voices不传参数时使用示例图片:一幅小狗的画 sample-dog.jpg 使用 Rex 的声音发言,一幅小猫的画 sample-cat.jpg 则用 Luna 的声音回答。两张图片均使用 grok-imagine-image-2.0 绘制。网页和终端两种版本均将视频保存到 output/<the first line>/scene.mp4,生成视频所用的提示词保存在旁边的 scene.json。
每次运行生成一段 5 至 15 秒的视频,时长取决于台词长度。运行约需一分钟,几乎都用在渲染上。我们测试时,示例生成 10 秒视频的费用为 $1.42;一句台词生成的 5 秒视频为 $0.71,相当于每秒约 14 美分。试听一段声音不足一美分。完成后,网页和终端都会显示视频费用。
工作原理
共享代码位于 src/scene.ts:
writePrompt()为整个场景编写一个提示词。每个标签都按列表位置引用输入:<IMAGE_0>指向第一张图片,图片列表为reference_images,<AUDIO_0>指向第一个声音,声音列表为reference_audios。因此,第一个角色来自<IMAGE_0>,声音来自<AUDIO_0>,第二个角色来自<IMAGE_1>,声音来自<AUDIO_1>。提示词用引号标出每句台词,按顺序列出,并要求不添加其他对白或音乐。makeScene()启动视频生成,调用的是client.videos.generate()。reference_images接收的图片类型为Blob,SDK 会将图片作为数据 URL 发送;reference_audios为每个角色接收一个{ voice_id },最多支持三个角色。sceneLength()根据台词的词数确定时长,因为每秒都会计费。参考图生视频最高支持 720p。waitForVideo()查询视频状态,所用方法为client.videos.get(),每三秒一次,并报告返回的progress百分比。client.videos.wait()可以代为轮询,但不报告进度。视频 URL 是临时的,因此makeScene()会立即下载视频。listVoices()列出可选声音,使用的是client.voice.list(),previewVoice()则选取其中一种声音朗读台词,调用的是client.voice.speak()。
关于视频中的声音,需要注意:
只有内置声音对所有用户开放。可信合作伙伴可申请使用自己的录音,办法是将录音作为
url填入reference_audios。client.voice.list()返回 28 种声音,但视频模型不支持其中的aurora和liora,因此listVoices()会将这两种声音排除。使用不支持的声音会收到 400 错误,错误信息会列出支持的声音。试听通过文本转语音朗读台词。在视频中,角色用所选声音演绎台词,节奏由视频中的表演决定。
src/server.ts 是一个小型 node:http 服务器。EventSource 只能发送 GET 请求,因此页面先将每张图片上传到 /api/pictures,再打开 /api/scene,传入图片 ID、声音和台词。服务器运行 makeScene(),将进度以 SSE 发送到网页,并以字节范围提供保存的视频,方便浏览器跳播。/api/voices 列出声音,而 /api/preview 会用所选声音说一句台词。服务器会保存每个试听片段,重播不再计费。/api/prompt 返回 writePrompt() 根据当前台词编写的提示词,供页面在发送前展示请求。每个 API 调用均接收一个 AbortSignal,当页面关闭请求时触发。点击 Stop 也会关闭请求。
public/index.html 使用原生 HTML 和 JavaScript 展示这些事件并播放视频。src/index.ts 则在终端中完成相同的工作。