前言
带大家今天拆解下最近非常火爆的解读书籍爆款短视频,单个视频最高20多万的点赞,该博主通过两个角色对话的方式解读一本书的短视频形式,仅仅只用了18个作品获得了19.5万粉丝,45.9万点赞。
先看下使用扣子Coze工作流一键生成“假如书籍会说话”复刻后的视频效果。
看完效果后我带大家再来拆解下具体的实现原理。
拆解
开始节点有三个输入参数【书名、作者、文字水印】给到豆包1.5-Pro-深度思考模型输出对话内容。
生成对话文案提示词:
# 角色
你是一个擅长生成书籍对话口播字幕文案的助手,能够根据给定的书籍名称和作者,创作视频对话口播字幕文案。对话角色设定为主持人和拟人化的书籍,采用跨时代的形式展开对话。
## 技能
### 技能1: 生成对话文案
1. 当用户提供《具体书籍名称》及作者等信息后,深度解读书籍内容。
2. 将书籍拟人化,如“富爸爸老师,请问......”,“富爸爸老师,为什么......”,其中后续问题要紧密结合讲解书籍里的核心痛点,吸引观众兴趣。
3. 生成至少1000字以上对话文案,提出至少10个以上问题,每个问题都要围绕这本书的痛点以及读者可能想了解或感兴趣的点展开。解答问题时,需结合现实生活中的实际情况或案例以及书籍知识点进行说明。
4. 文案中不能仅有提问和回答情节,要加入对话情节。当说到重点或真相时,提问的人要说出惊讶的话,使整个视频看起来更像真实的对话或采访。
5. 文案内容需包含每个问题对应的对话、解释、现如今是什么情况、之后该怎么做等部分。对于较长的台词,要用标点符号合理拆分为短句, 且每个短句不能超过10个字。
6. 回复内容说明:role_name=角色名称,固定2个,主持人和书籍名称, order=台词出场顺序,也是台词 唯一编号,line=角色台词,口播字幕文案
7.如果用户输入了{{text}},请直接对文案进行台词编号
- **回复示例**:
```json
{
"role_list": [
{
"role_name": "[主持人]"
},
{
"role_name": "[书籍]"
}
],
"text_list":[
{
"order": 1,
"line": "[台词]",
"role_name":"主持人"
},
{
"order": 2,
"line": "[台词]",
"role_name":"书籍"
},
{
"order": 3,
"line": "[台词]",
"role_name":"主持人"
},
{
"order": 4,
"line": "[台词]",
"role_name":"书籍2"
},
{
"order": 5,
"line": "[台词]",
"role_name":"主持人"
},
{
"order": 6,
"line": "[台词]",
"role_name":"书籍"
}
]
}
## 限制
- 只围绕用户提供的书籍相关内容生成对话文案,拒绝回答与书籍无关的话题。
- 文案需满足用户提出的格式和要求,不能偏离框架设定,尤其要注意将过长台词用标点符号拆分为短句。
- 采用长短句形式进行提问和回答, 用逗号将长句进行分隔。
生成的内容:
{
"role_list": [
{
"role_name": "主持人"
},
{
"role_name": "《富爸爸与穷爸爸》"
}
],
"text_list": [
{
"role_name": "主持人",
"line": "富爸爸老师,您好!今天想请教,为什么您总强调‘穷爸爸’和‘富爸爸’的思维差异是关键?",
"order": 1
},
{
"role_name": "《富爸爸与穷爸爸》",
"line": "因为思维决定行为,行为决定结果。穷爸爸说‘我买不起’,富爸爸问‘怎么买得起’。一个是终点思维,一个是探索思维。",
"order": 2
},
{
"role_name": "主持人",
"line": "这确实很不同!那现实中,这种思维差异具体体现在哪里?",
"order": 3
},
{
"role_name": "《富爸爸与穷爸爸》",
"line": "比如买房。很多人觉得‘有房就是资产’,却忽略贷款压力。若房子消耗现金流,它其实是负债。富爸爸会算租金能否覆盖月供,能覆盖的才是资产。",
"order": 4
},
{
"role_name": "主持人",
"line": "啊!原来我一直搞错了资产定义?",
"order": 5
},
{
"role_name": "《富爸爸与穷爸爸》",
"line": "对!书中核心就是:资产是能把钱放进你口袋的东西,负债是把钱从你口袋拿走的。车、自住房若需持续支出,都是负债。",
"order": 6
},
{
"role_name": "主持人",
"line": "那普通人总说‘努力工作就能变富’,这想法错在哪?",
"order": 7
},
{
"role_name": "《富爸爸与穷爸爸》",
"line": "错在为钱工作,而非让钱为你工作。穷爸爸拼命升职加薪,却被税收、通胀稀释财富。富爸爸用工资买资产,让资产生钱。",
"order": 8
},
{
"role_name": "主持人",
"line": "那年轻人刚工作,该怎么开始积累资产?",
"order": 9
},
{
"role_name": "《富爸爸与穷爸爸》",
"line": "先学财商知识,再从小资产起步。比如买指数基金、出租小公寓,甚至用副业收入投资。关键是让第一笔钱‘活’起来。",
"order": 10
},
{
"role_name": "主持人",
"line": "现在很多人月光,甚至负债消费,这该怎么破?",
"order": 11
},
{
"role_name": "《富爸爸与穷爸爸》",
"line": "停止‘收入增加—消费升级’的陷阱。先支付自己,把10%收入存起来买资产,再用剩下的钱支付账单。习惯了就不会觉得难。",
"order": 12
},
{
"role_name": "主持人",
"line": "学校为什么不教这些财商知识?我们只能自己学吗?",
"order": 13
},
{
"role_name": "《富爸爸与穷爸爸》",
"line": "传统教育培养‘雇员’,不是‘投资者’。但时代变了,打工人也可能被裁员。所以必须主动学,否则永远在‘老鼠赛跑’里转圈。",
"order": 14
},
{
"role_name": "主持人",
"line": "那‘财富自由’到底是什么状态?普通人能实现吗?",
"order": 15
},
{
"role_name": "《富爸爸与穷爸爸》",
"line": "当被动收入超过总支出,你就自由了。比如租金、股息、版权收入。普通人只要坚持买资产,5-10年就能看到变化。",
"order": 16
},
{
"role_name": "主持人",
"line": "有人说‘负债是毒药’,但您书里提到‘聪明负债’,这怎么理解?",
"order": 17
},
{
"role_name": "《富爸爸与穷爸爸》",
"line": "关键看负债用途。用信用卡消费是坏负债,用低息贷款买能生钱的资产是好负债。比如贷款买商铺收租,租金覆盖利息还有剩。",
"order": 18
},
{
"role_name": "主持人",
"line": "最后想问问,现在年轻人最该避开的理财误区是什么?",
"order": 19
},
{
"role_name": "《富爸爸与穷爸爸》",
"line": "别等‘有钱了再理财’。现在就开始,哪怕每月存300元买基金。拖延才是最大的敌人,时间复利比本金更重要。",
"order": 20
}
]
}
当拿到对话内容之后下一步就是同时去做 5 件事情:
第一件事情:提取开场文案并生成音频,然后获取每个音频的时间,最后合并成进行数据组装,最后得到两个数组,一个是音频数组一个是对应时间的数组。
在这里用到了两个核心插件:(后续会反复使用)
一个是扣子官方的语音合成:输入文字生成音频文件
https://www.coze.cn/store/plugin/7426654728890777650
另一个是速推AIGC的视频合成_剪映小助手
https://www.coze.cn/store/plugin/7457837529027493922
第二件事情:使用画板组件生成一个视频背景图,图片右下角写入了开始节点的文字水印参数。
第三件事情:从对话内容中提取对话中的核心关键词,后续要做核心文字的字幕特殊处理。
第四件事情:启动了三个循环节点生成对话音频内容与获取每段音频的时间,在循环体中判断不同的角色生成不同的音频信息。
接下来拿到所有的数据进行整合与配置
整合数据相关代码:
async functionmain({ params }: Args): Promise<Output> {
const { bg_image_url, audio_list1, duration_list1, role_list, text_list,audio_list2, duration_list2,audio_list3, duration_list3,keywords,
start_audio_list,start_duration_list } = params;
const audio_list = [...audio_list1, ...audio_list2, ...audio_list3];
const duration_list = [...duration_list1, ...duration_list2, ...duration_list3];
let audioStartTime = 0;
let maxDuration = 0;
let initialStartTime = 0;
const initialAudioData = [];
for(let i=0; i< start_audio_list.length;i++){
const duration = start_duration_list[i];
initialAudioData.push({
audio_url: start_audio_list[i],
duration,
volume: 2,
start: audioStartTime,
end: audioStartTime + duration
});
audioStartTime += duration;
maxDuration = audioStartTime;
initialStartTime += duration;
}
const start_text_timelines1 = [];
start_text_timelines1.push(
{
start: 0,
end: start_duration_list[0]
}
);
//https://p9-bot-workflow-sign.byteimg.com/tos-cn-i-mdko3gqilj/373c3e491f214adfa3934a507e1c92e4.MP3~tplv-mdko3gqilj-image.image?rk3s=81d4c505&x-expires=1777426600&x-signature=Bp8XLZFWPpP1SiIQRKkVxluOl%2BU%3D&x-wf-file_name=%E5%92%9A%E9%9F%B3%E6%95%88.MP3
const start_audio_text1 =[];
start_audio_text1.push({
audio_url: "https://p6-bot-sign.byteimg.com/tos-cn-i-v4nquku3lp/0562121f72f943f2802c7e8dc49e0e7b.MP3~tplv-v4nquku3lp-image.image?rk3s=68e6b6b5&x-expires=1749305401&x-signature=ZiBfMBfiHBWUnk6iqQPFe%2FFdfDM%3D",
duration: 548571,
volume: 2,
start: 0,
end: 548571
});
const start_text_timelines2 = [];
start_text_timelines2.push(
{
start: start_duration_list[0],
end: start_duration_list[0]+start_duration_list[1]
}
);
const start_audio_text2 =[];
start_audio_text2.push({
audio_url: "https://p9-bot-workflow-sign.byteimg.com/tos-cn-i-mdko3gqilj/2ae7ccd877ea4c79b4fcbcfe38170b54.MP3~tplv-mdko3gqilj-image.image?rk3s=81d4c505&x-expires=1777425687&x-signature=m4S898PliWoqTBPavUmbcGKWozY%3D&x-wf-file_name=%E5%AD%97%E5%B9%95%E5%87%BA%E5%9C%BA.MP3",
duration: 862040,
volume: 2,
start: start_duration_list[0],
end: start_duration_list[0] + 862040
});
const start_text_timelines3 = [];
start_text_timelines3.push(
{
start: start_duration_list[0]+start_duration_list[1],
end: start_duration_list[0]+start_duration_list[1]+start_duration_list[2]
}
);
// 处理音频数据
const audioData = [];
for(let i = 0; i < audio_list.length && i < duration_list.length; i++) {
const duration = duration_list[i];
audioData.push({
audio_url: audio_list[i],
duration,
volume: 2,
start: audioStartTime,
end: audioStartTime + duration
});
audioStartTime += duration;
maxDuration = audioStartTime;
}
// 书籍拟人化图片
var role1_img_url = "https://p9-bot-workflow-sign.byteimg.com/tos-cn-i-mdko3gqilj/7153ce955e1b4d51ab2e3972846fb13e.png~tplv-mdko3gqilj-image.image?rk3s=81d4c505&x-expires=1777338929&x-signature=LLDTeL38s5rfHt7%2BG1%2FvGFrwa%2FQ%3D&x-wf-file_name=CodeL.png";
var role2_img_url = "https://s.coze.cn/t/MRdXPFzGLOw/";
const result = generateVideoTimeline(
{
role_list: role_list,
text_list: text_list,
audio_list: audio_list,
duration_list: duration_list
},
role1_img_url,
role2_img_url,
keywords,
initialStartTime
);
// 处理背景图片
const bgImageData = [
{
image_url: bg_image_url,
width: 1920,
height: 1080,
start: 0,
end: maxDuration + 1000000
}
];
// 构建输出对象
const ret = {
"role": result.role,
"bgImageData": JSON.stringify(bgImageData),
"audioData": JSON.stringify(audioData),
"initialAudioData": JSON.stringify(initialAudioData),
"roleImage1": JSON.stringify(result.role[0].images),
"roleImage2": JSON.stringify(result.role[1].images),
"caption_text1": {
"text1": result.role[0].texts,
"timelines1": result.role[0].timelines
},
"caption_text2": {
"text2": result.role[1].texts,
"timelines2": result.role[1].timelines
},
"captions1": JSON.stringify(result.role[0].captions),
"captions2": JSON.stringify(result.role[1].captions),
"start_timelines1": start_text_timelines1,
"start_timelines2": start_text_timelines2,
"start_timelines3": start_text_timelines3,
"start_audio_text1": JSON.stringify(start_audio_text1),
"start_audio_text2": JSON.stringify(start_audio_text2)
};
return ret;
}
functiongenerateVideoTimeline(data, imageUrl1, imageUrl2, keywords = [], initialStartTime = 0) {
const { role_list, text_list, duration_list } = data;
// 按order排序台词
const sortedTexts = [...text_list].sort((a, b) => a.order - b.order);
// 初始化时间轴起点
let currentEnd = initialStartTime; // 使用传入的初始时间
const roleMap = new Map();
// 换行处理函数
const splitLongLines = (line) => {
const maxLength = 10;
if(line.length <= maxLength) return line;
return line.replace(new RegExp(`(.{${maxLength}})`, "g"), "$1n").replace(/n$/, "");
};
for(const text of sortedTexts) {
// 获取当前台词的持续时间
const duration = duration_list[text.order - 1];
const start = currentEnd; // 起始时间基于当前累计值
const end = start + duration;
currentEnd = end;
// 标准化角色名称匹配(处理方括号)
const matchedRole = role_list.find(role =>
role.role_name.replace(/[[]]/g, "") === text.role_name
);
if(!matchedRole) continue;
const roleKey = matchedRole.role_name;
// 初始化角色数据结构
if(!roleMap.has(roleKey)) {
roleMap.set(roleKey, {
role_name: roleKey,
texts: [],
timelines: [],
images: [],
captions: []
});
}
const roleData = roleMap.get(roleKey);
// 处理台词文本(换行分割)
const processedLine = splitLongLines(text.line);
roleData.texts.push(processedLine);
roleData.timelines.push({ start, end });
// 生成 captions 对象
const matchedKeywords = keywords.filter(keyword => processedLine.includes(keyword));
const uniqueKeywords = [...new Set(matchedKeywords)];
const caption = {
start, // 使用调整后的时间
end, // 使用调整后的时间
text: processedLine,
in_animation: "羽化向右擦开"
};
if(uniqueKeywords.length > 0) {
caption.keyword = uniqueKeywords.join('|');
caption.keyword_color = "#fe8a80";
caption.keyword_font_size = 10;
caption.font_size = 10;
}
roleData.captions.push(caption);
// 添加图片配置
const imageUrl = role_list.indexOf(matchedRole) === 0 ? imageUrl1 : imageUrl2;
const lastImage = roleData.images[roleData.images.length - 1];
if(lastImage && lastImage.end === start) { // 时间衔接判断依然有效
lastImage.end = end;
} else {
roleData.images.push({
image_url: imageUrl,
in_animation: "轻微放大",
width: 300,
height: 300,
start, // 使用调整后的时间
end // 使用调整后的时间
});
}
}
return { role: Array.from(roleMap.values()) };
}
然后将信息进行视频合成处理:从创建草稿(create_draft)- 添加背景图(create_draft)- 添加音频(add_audios)- 添加关键帧(add_keyframes)-批量添加字幕(caption_infos)-保存草稿(保存草稿)。
这里面一共使用了两个插件:
视频合成剪映小助手、剪映小助手数据生成器
当获取到最后的草稿地址(draft_url),粘贴到剪映小助手(客户端)创建草稿。
然后大家剪映可以看到最近的草稿,打开进入剪辑页面即可进行二次编辑,确定内容后右上角【导出】视频即可。
推荐站内搜索:最好用的开发软件、免费开源系统、渗透测试工具云盘下载、最新渗透测试资料、最新黑客工具下载……
还没有评论,来说两句吧...