第6篇:COZE 爆品剖析【原来历史故事还能这样玩?一键生成沉浸式剧情,小白秒变故事大师!】工作流全面解析

目录

原来历史故事还能这样玩?一键生成沉浸式剧情,小白秒变故事大师!

1.  前言

2.  Coze工作流设计思路

2.1  整体架构规划​

2.2  完整的工作流程

3.  Coze工作流具体实现

3.1  开始节点:

3.2  准备文案:

3.3  生成主角首图:

3.4  生成主题词:

3.5  生成分镜提示词:

3.6  批处理-生成分镜画面

3.7  代码-整合素材

3.8 创建草稿并加入素材

3.9  结束节点:

3.10  利用剪映小助手下载草稿到本地

3.11  代码

3.12  复盘智能体工作流流程

4.  资料领取

5.  结语


原来历史故事还能这样玩?一键生成沉浸式剧情,小白秒变故事大师!

1.  前言

       想穿越千年,亲身体验金戈铁马的战场厮杀,或是见证才子佳人的爱恨情仇吗?无需苦读万卷史书,也不必绞尽脑汁构思情节,现在,只需简单几步,就能一键生成扣人心弦的沉浸式历史故事!无论是你心中预设的历史主题,还是突然迸发的灵感文案,本教程都能帮你将其转化为生动鲜活的故事。从秦朝的咸阳街头到大唐的长安夜市,带你轻松解锁历史故事创作新姿势,让文字成为连接古今的时光隧道!​

2.  Coze工作流设计思路

2.1  整体架构规划​

      我们设计的工作流主要包含五个核心环节:文案准备、生成分镜、绘制分镜、整合素材、创建草稿。从用户输入故事主题开始,工作流将自动按照预设步骤运行,最终输出草稿链接。

2.2  完整的工作流程

3.  Coze工作流具体实现

3.1  开始节点:

      作为工作流的起始点,其主要作用是接收用户输入的故事主题,工作流同时也接受用户自定义情节。

3.2  准备文案:

       该组节点首先通过一个选择器判断用户是否输入的自定义文案,如果未输入文案,则通过大模型节点生成一段文案,最后通过变量聚合节点获得最终的文案。​

3.3  生成主角首图:

        通过大模型节点和图像生成节点绘制出主角形象放在视频的开始位置。    

3.4  生成主题词:

        通过大模型节点提炼出一个出题词放在视频的开始位置。    

3.5  生成分镜提示词:

        通过大模型节点将文案拆解成若干个分镜画面提示词。

3.6  批处理-生成分镜画面

        通过批处理节点将分镜描述逐一生成对应的图像。

3.7  代码-整合素材

        通过代码节点将前面的素材整理成符合剪映小助手的数据格式。

3.8 创建草稿并加入素材

        通过剪映小助手创建剪映草稿并将素材逐一加入到草稿中。

3.9  结束节点:

       工作流的最终节点,用于返回草稿路径。

3.10  利用剪映小助手下载草稿到本地

        将结束节点的输出变量粘贴进剪映小助手,将草稿下载到本地,然后就可以通过剪映编辑发布了。

3.11  代码

整合素材

async function main({ params }: Args): Promise<Output> {
    const { image_list, audio_list, duration_list, scenes } = params;
    // 处理音频数据
    const audioData = [];
    let audioStartTime = 0;
    const aideoTimelines = [];
    let maxDuration = 0;

    const imageData = [];
    
    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,
            start: audioStartTime,
            end: audioStartTime + duration
        });
        aideoTimelines.push({
            start: audioStartTime,
            end: audioStartTime + duration
        });

        if((i-1)%2==0){
            imageData.push({
                image_url: image_list[i],
                start: audioStartTime,
                end: audioStartTime + duration,
                width: 1440,
                height: 1080,
                in_animation: "轻微放大",
                in_animation_duration: 100000
            });
        } else{
            imageData.push({
                image_url: image_list[i],
                start: audioStartTime,
                end: audioStartTime + duration,
                width: 1440,
                height: 1080
            });
        }
       
        
        audioStartTime += duration;
        maxDuration = audioStartTime;
    }

    const roleImgData = [];
    roleImgData.push({
        image_url: params.role_img_url,
        start: 0,
        end: duration_list[0],
        width: 1440,
        height: 1080
    });


    const captions = scenes.map(item => item.cap);
    const subtitleDurations = duration_list;
    
    const { textTimelines, processedSubtitles } = processSubtitles(
        captions,
        subtitleDurations
    );


    // 开场2个字
    const title = params.title;  // 标题
    const title_list = [];
    title_list.push(title);
    const title_timelimes = [
        {
            start: 0,
            end: duration_list[0]
        }
    ];
    
    // 开场音效 
    var kc_audio_url = "音频地址";
    // 背景音乐 
    var bg_audio_url ="音频地址";

    const bg_audio_data = [];
    bg_audio_data.push({
        audio_url: bg_audio_url,
        duraion: maxDuration,
        start: 0,
        end: maxDuration
    });

    const kc_audio_data = [];
    kc_audio_data.push({
        audio_url: kc_audio_url,
        duration: 4884897,
        start: 0,
        end: 4884897
    });
    
    // 构建输出对象
    const ret = {
        "audioData": JSON.stringify(audioData),
        "bgAudioData": JSON.stringify(bg_audio_data),
        "kcAudioData": JSON.stringify(kc_audio_data),
        "imageData": JSON.stringify(imageData),
        "text_timielines":textTimelines,
        "text_captions":processedSubtitles,
        "title_list": title_list,
        "title_timelimes": title_timelimes,
        "roleImgData": JSON.stringify(roleImgData)
    };

    return ret;
}



const SUB_CONFIG = {
    MAX_LINE_LENGTH: 25,
    SPLIT_PRIORITY: ['。','!','?',',',',',':',':','、',';',';',' '], // 补充句子结束符
    TIME_PRECISION: 3
};

function splitLongPhrase(text, maxLen) {
    if (text.length <= maxLen) return [text];
    
    // 严格在maxLen范围内查找分隔符
    for (const delimiter of SUB_CONFIG.SPLIT_PRIORITY) {
        const pos = text.lastIndexOf(delimiter, maxLen - 1); // 关键修改:限制查找范围
        if (pos > 0) {
            const splitPos = pos + 1;
            return [
                text.substring(0, splitPos).trim(),
                ...splitLongPhrase(text.substring(splitPos).trim(), maxLen)
            ];
        }
    }

    // 汉字边界检查防止越界
    const startPos = Math.min(maxLen, text.length) - 1;
    for (let i = startPos; i > 0; i--) {
        if (/[\p{Unified_Ideograph}]/u.test(text[i])) {
            return [
                text.substring(0, i + 1).trim(),
                ...splitLongPhrase(text.substring(i + 1).trim(), maxLen)
            ];
        }
    }

    // 强制分割时保证不超过maxLen
    const splitPos = Math.min(maxLen, text.length);
    return [
        text.substring(0, splitPos).trim(),
        ...splitLongPhrase(text.substring(splitPos).trim(), maxLen)
    ];
}

const processSubtitles = (
    captions,
    subtitleDurations,
    startTimeμs = 0 // 新增参数:起始时间(单位微秒,默认0)
  ) => {
    const cleanRegex = /[\u3000\u3002-\u303F\uff00-\uffef\u2000-\u206F!"#$%&'()*+\-./<=>?@\\^_`{|}~]/g;
    
    let processedSubtitles = [];
    let processedSubtitleDurations = [];
    
    captions.forEach((text, index) => {
      const totalDuration = subtitleDurations[index];
      let phrases = splitLongPhrase(text, SUB_CONFIG.MAX_LINE_LENGTH);
      
      phrases = phrases.map(p => p.replace(cleanRegex, '').trim())
                     .filter(p => p.length > 0);
  
      if (phrases.length === 0) {
        processedSubtitles.push('[无内容]');
        processedSubtitleDurations.push(totalDuration);
        return;
      }
  
      const totalChars = phrases.reduce((sum, p) => sum + p.length, 0);
      let accumulatedμs = 0;
      
      phrases.forEach((phrase, i) => {
        const ratio = phrase.length / totalChars;
        let durationμs = i === phrases.length - 1 
          ? totalDuration - accumulatedμs
          : Math.round(totalDuration * ratio);
  
        processedSubtitles.push(phrase);
        processedSubtitleDurations.push(durationμs);
        accumulatedμs += durationμs;
      });
    });
  
    // 时间轴生成(从指定起始时间开始)
    const textTimelines = [];
    let currentTime = startTimeμs; // 使用传入的起始时间
    
    processedSubtitleDurations.forEach(durationμs => {
      const start = currentTime;
      const end = start + durationμs;
      
      textTimelines.push({
        start: start, // 直接使用整数
        end: end
      });
      
      currentTime = end; // 自动累计到下一段
    });
  
    return { textTimelines, processedSubtitles };
  };

3.12  复盘智能体工作流流程

4.  资料领取

         在使用大模型时若感觉体验不佳,很可能是提示词撰写方式有待优化。为此,我们整理了丰富的提示词模板与 Coze系列操作教程,涉及的代码和提示词、完整工作流程已同步至 Coze 空间,感兴趣的朋友可以私信微信详细了解~

5.  结语

        掌握了 “一键生成沉浸式历史故事” 的工作流,你就拥有了打开历史宝库的神奇钥匙。快去输入你的奇思妙想,让历史在你的笔下焕发新生!如果你在创作过程中有了独特的发现,或是生成了超惊艳的故事,欢迎分享给大家。期待你用这份技能,创作出更多引人入胜的历史篇章,与他人一同穿梭在精彩的历史长卷中!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值