基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
  • 知识卡片碎片时间过考点
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
    • AI 热点每日 AI 资讯与动向
AI 工作台
简历
旧版
AIHT
内容
精选全部 AI 动态热点榜AI 日报收藏
分类
模型行业编程产品技术观点开源
更多
Agent 接入
返回首页开发者导航
AIHT
精选 / 资讯详情
8.0
热点
AI SCORE
技术实践2026-11-05 18:01

AI 视频服务如何约束生成与处理退款

dev.to · AI#视频生成#提示词#计费
Editor brief · 编辑速览

作者将视频生成限制为双人、单场景和固定时长,通过场景模板与结构化提示减少输出失控。文章还讨论付费生成中的积分账本及失败退款,代码为简化示例。

文章思维导图
Knowledge map
拖拽缩放
AI deep read

AI 深度解读

把两张人物照片做成一段带原创歌词和节拍的说唱视频,难点不只是让模型出片。作者做的 AI Rap Generators,把产品限制为 15 秒、9:16、两名成年表演者,再用结构化提示词控制画面,用积分账本处理扣费和失败退款。

这篇最值得程序员借鉴的,是怎样把一次有随机性的模型调用,包装成用户敢付钱的服务。不过,提示词效果主要来自作者经验,支付代码也只是简化示意,离完整生产方案还有距离。

AI 说唱视频生成工具的产品展示

为什么先限制玩法,再谈模型能力

通用视频工具把大量选择交给用户:怎么写提示词、镜头怎么动、音乐怎么配、跨镜头如何保持人脸一致。对独立开发者来说,每多一个自由度,就多一批需要处理的失败组合。

作者因此固定了「两个人、一个舞台、一段说唱」。用户的主要操作只有上传肖像和选择场景,例如吐槽对决、生日、宠物二重唱、屋顶,也可以补充名字或内部笑话。其他决定尽量交给场景模板。15 秒、9:16 MP4 的输出,也对应 TikTok、Reels、Shorts 的分享形式。

缩小输入范围,才有机会反复调好同一类输出。

模型选用 Seedance 2.0。按作者的描述,它能联合生成音视频,节拍、人声和表演在同一次生成中完成;参考图片则提供脸部、服装和发型等身份信息。这样可以减少后期拼接声音与口型的工作,但不等于口型和相似度有保证。

作者所用供应商的文档支持最长 15 秒,并允许单次请求组合文本和多张参考图。他也明确提醒,不同供应商的限制和参数可能不同。原文没有给出具体接入 API,不能据此直接写出调用代码。

提示词拆成五块,改动才有落点

作者最初为每个场景写一整段描述,结果不稳定,出问题也很难定位。后来改成五个区块:[Scene] 管身份与构图,[Music] 管音乐,[Timeline] 管动作节奏,[Lyrics] 管演唱内容,[Constraints] 管禁止事项。

下面这段屋顶模板,展示了如何把抽象的「来一段酷一点的说唱」拆成具体要求:

[Scene]
Use reference image 1 for the single rapper's identity, outfit, hair,
and proportions. On the rooftop terrace, keep the performer centered in
a locked-off knee-up vertical 9:16 shot. Preserve the city skyline,
string lights, palms, lounge furniture, and reflective stone floor;
no other people enter.

[Music]
Confident melodic rap, 110 BPM: hard kick, snare, rolling hats, deep sub
bass, piano-and-bell hook, airy pads. One clear vocal rides a constant
radio-loud beat.

[Timeline]
0-3s: bounce on beat and point at camera. 3-6s: broad arm sweeps.
6-9s: lean in with a smile and head bob. 9-12s: step side to side,
hands wide. 12-15s: keep the energy high and freeze on the final hit.

[Lyrics, in English, perform exactly these]
1. ...
(six lines)

[Constraints]
Accurate lip-sync, one rapper only, no subtitles or text, no cuts, no
camera move, no extra people. Keep the performer in the lower three
quarters, knee-up, with hands below the top quarter.

要留意 Use reference image 1 这一行:它指定了身份来源。不过,这份示例写的是单人表演,与产品强调的双人形式并不一致,原文没有解释,不能直接当成双人模板使用。

这些区块各有作用。固定机位和膝盖以上构图,可以减少镜头变化;110 BPM、明确的乐器和单一清晰人声,让音乐要求更具体;15 秒拆成五个 3 秒动作段,既提供变化,也安排了最后一拍定格的收尾。

歌词则主动压短:六行,每行约 7 到 10 个音节。作者认为长句容易让口型漂移,要求逐字演唱也有助于减少模型改写。但示例只保留了歌词占位,没有提供实际歌词供复现。

约束区块按失败现象逐条补充,比如禁止字幕、切镜、额外人物和镜头移动。原文提到要列出问题与规则的对应关系,却没有展示完整清单。

这里可靠的工程思路是把变量拆开,方便一次只改一项。至于成功率提高多少,作者没有给出样本量或对照数据。

一次生成,要按一笔交易来处理

视频调用会消耗真实成本,所以作者定了三条规则:先占用积分再调用模型;每次余额变化都写入只追加的账本;任务最终失败时最多退款一次。

产品每条视频消耗 10 积分,积分包从 $6.99 起,没有订阅,失败渲染自动退款。原文未说明起步积分包包含多少积分,因此无法据此计算单条视频的实际售价。

数据层分成 credit_ledger 和 credit_balance。前者记录 delta、job_id、idem_key 等信息,kind 限定为 purchase、hold、refund,且 idem_key 必须唯一;后者用 CHECK (balance >= 0) 防止负余额。

创建任务和占用积分放在同一个事务中。扣费通过带 balance >= $2 条件的 UPDATE 完成,并用 RETURNING balance 判断是否成功,避免先查余额再扣费之间的并发空隙。余额不足时抛出 INSUFFICIENT_CREDITS,占用记录使用 hold:job:${job.rows[0].id}。

退款路径则同时限制任务状态和账本写入:

const upd = await tx.query(
  `UPDATE jobs SET status = 'failed', error_code = $2, finished_at = now()
   WHERE id = $1 AND status NOT IN ('succeeded','failed')
   RETURNING user_id, cost_credits`,
  [jobId, errorCode]
);
if (upd.rowCount === 0) return; // 已经处于终态

const ins = await tx.query(
  `INSERT INTO credit_ledger (user_id, delta, kind, job_id, idem_key)
   VALUES ($1, $2, 'refund', $3, $4)
   ON CONFLICT (idem_key) DO NOTHING RETURNING id`,
  [upd.rows[0].user_id, upd.rows[0].cost_credits, jobId, `refund:job:${jobId}`]
);

if (ins.rowCount === 1) {
  await tx.query(
    `UPDATE credit_balance SET balance = balance + $2 WHERE user_id = $1`,
    [upd.rows[0].user_id, upd.rows[0].cost_credits]
  );
}

要注意 if (ins.rowCount === 1):只有确实新增了退款流水,才增加余额。重复回调、worker 重启和人工重试再次进入这条路径时,就不会反复退钱。这个保证依赖整段操作处于同一事务中。

重试沿用原任务和原占用,不能重新收费。

作者把超时、上游 5xx、限流归为可退避重试的问题;输入被拒绝、内容审核失败则不重试。只有进入最终失败状态才退款,并通过每晚比较余额与账本流水之和进行对账。

我的判断

这套做法适合借鉴:产品边界减少变化,提示词区块帮助定位问题,账本让收费行为可追溯。尤其是条件扣费与退款幂等,比应用层先查余额、靠回调只执行一次更经得起重复请求。

但原文的 hold 实际上直接扣减可用余额,账本也没有成功结算类型。它展示的是「先扣、失败再返还」的简化方案。示例没有完整覆盖提交生成请求后进程崩溃、供应商已接单但本地超时、成功回调与失败处理竞争等情况,也没有展示创建任务接口如何防止客户端重复提交。

提示词部分则属于经验之谈。没有对照实验,就不能确认五个标签本身带来了多少提升,也无法判断它与更短模板相比的成本收益。

另一个可取之处是把肖像规则写进产品:仅接受本人或已同意参与的成年人,不接受未成年人和公众人物,禁止色情、仇恨、欺骗及骚扰内容,输出标注 AI 生成。照片在七天后删除,通过存储生命周期规则和数据库标记落实。原文没有说明身份、年龄和同意如何验证,规则声明与执行机制之间仍有空白。

能拿来做什么

  • 做 AI 生成页面时,先固定输出时长、比例和少量场景,把能力边界放到用户提交之前。这里的限制包括 15 秒、不支持自定义歌曲上传、仅面向两名成年人,以及肖像相似度会变化。
  • 维护视频提示词时,可以按身份、音乐、时间线、歌词、约束拆分模板,记录具体失败现象,再逐项修改,避免一次改完整段后无法归因。
  • 在 Node 服务中接入付费生成时,把任务创建、条件扣费和账本写入放进同一事务;退款同时检查任务终态和唯一流水,并让重试复用原任务。
  • 承诺照片七天删除时,把存储生命周期配置和数据库状态处理一起纳入实现与检查,确保页面承诺有系统机制承接。
Original source

本文由 AI 通读原文后重新编写,观点部分为站内判断,细节以原文为准,来源 dev.to · AI,原文版权归原作者所有。

阅读原文
上一篇
Agent 权限控制为何必须记录会话历史
下一篇
用 Git 状态摘要减少编程智能体重复读库

资讯速览

dev.to · AI · 2026-11-05 18:01

AI 评分 8.0 / 10

相关标签

#视频生成#提示词#计费

继续阅读

  • PR Agent:可自行部署的 AI 代码审查助手
  • Agent 权限控制为何必须记录会话历史
  • 用 Git 状态摘要减少编程智能体重复读库
  • 提示词实验:五个智能体未胜过单体
  • 让编程智能体先估算规模再动手