{
  "format": "mosael-workflow",
  "version": 1,
  "workflow_revision": 1,
  "name": "商品 → 数字人出镜带货口播",
  "description": "在「带货口播短视频」的基础上,开场钩子和收尾号召换成资产库里的一位人物出镜说出来(用它的脸和嗓子),中间每一拍仍是带商品的画面,口播用同一个嗓子念、对齐每一拍的开头,每拍铺上屏幕短句,导出竖屏成片(带「AI 生成」标识)。运行前在「挑一位主播」上选好人物;人物要先在资产库里有正面图和音色;真人要有授权声明,克隆音色也要声明是谁的。视频模型可用时中间各拍动起来(和「带货口播短视频」同一个做法,开场和收尾本来就是主播出镜的视频):每拍多一次付费视频生成,拍数约为目标时长减去开场和收尾、再除以开始节点的 beat_seconds(每拍几秒)。这一份带着「把这一拍动起来」:开始节点的 beat_seconds 是每一拍几秒,挑的视频模型要出得了这个时长。没有视频模型的话,导入后在画布上打开逐拍的那个循环,删掉「把这一拍动起来」「归档这一拍的视频」「这一拍的视频不出声」三个节点,再把「出这一拍的画面」的结果连到「按这一拍的时长铺上去」的素材那一格 —— 每一拍就按 beat_seconds 铺一张静图。也可以在应用的模板库里直接添加:没有视频模型时建出来的就是静图版。",
  "graph_hash": "395999208839704ecb18f17f298cd427e3b1b7668d79ac4bc81f885aca228917",
  "graph": {
    "meta": {
      "template_id": "product_pitch_presenter",
      "template_version": 7,
      "source": "official"
    },
    "nodes": [
      {
        "id": "start",
        "type": "start",
        "name": "填商品与卖点",
        "position": {
          "x": 40,
          "y": 260
        },
        "config": {
          "params": {
            "product_name": "",
            "selling_points": "",
            "audience": "刷竖屏短视频的年轻观众",
            "target_duration_seconds": 30,
            "beat_seconds": 5,
            "width": 1080,
            "height": 1920,
            "fps": 30
          },
          "required_params": [
            "product_name",
            "selling_points"
          ]
        }
      },
      {
        "id": "product_photo",
        "type": "asset",
        "name": "选择商品图",
        "position": {
          "x": 330,
          "y": 260
        },
        "config": {
          "asset_id": ""
        }
      },
      {
        "id": "pitch_script",
        "type": "llm",
        "name": "写分拍口播脚本",
        "position": {
          "x": 650,
          "y": 120
        },
        "config": {
          "profile_id": "",
          "model": "",
          "preset": "creative",
          "system": "你是带货短视频的编导。用户给你一件商品和几条卖点，你要写一条约 {{start.target_duration_seconds}} 秒、\n能直接拍的口播脚本，按\"拍\"拆开。\n\n硬性要求：\n- 前三秒必须给出观看理由，不要从\"大家好\"开始。\n- 每一拍正好 {{start.beat_seconds}} 秒（视频模型一段就出这么长），每一拍的 narration 念出来不能超过它：中文按每秒约 4 个字估，宁短勿长。\n- visual_prompt 用英文写这一拍的第一帧画面（这一拍的视频从它开始动），**商品必须出现在画面里**；不要写机位参数，不要在画面里\n  生成文字、logo 或水印；也不要把画面写成「手机屏幕里的画面」、不要加设备边框或 App 界面 ——\n  成片本来就在手机上看。\n- motion_prompt 用英文写这 {{start.beat_seconds}} 秒里画面怎么动：镜头缓慢推近、平移或环绕，光线在商品表面\n  流动，场景里轻微的动作；动作要小、在这几秒内完成，商品始终完整、清楚、不变形、不换样子。\n- 卖点只能来自用户给的那几条，不要编造功效、成分、资质或数据。\n- caption 是屏幕上的短句，不是把 narration 原样抄一遍。\n- 最多 12 拍：每一拍都要出一张画面、再出一段视频，是两次付费生成。\n\n只输出符合 JSON Schema 的对象。\n\n这一条由一位主播**出镜**说开场钩子(hook_line)和结尾号召(call_to_action):这两句是对着镜头说的话,\n口语、自然,各自念出来不超过 8 秒;它们**也算在成片时长里**。中间的每一拍是商品画面,narration 是画外音。",
          "prompt": "商品名称：{{start.product_name}}\n卖点（只能用这些）：\n{{start.selling_points}}\n目标观众：{{start.audience}}\n成片目标时长：{{start.target_duration_seconds}} 秒\n\n请写出分拍脚本。拍数 × 每拍 {{start.beat_seconds}} 秒，加上开场钩子和结尾号召念出来的时长（中文每秒约 4 个字），要接近目标时长。",
          "response_format": "json_schema",
          "json_schema_name": "product_pitch_script",
          "json_schema": {
            "type": "object",
            "properties": {
              "hook_line": {
                "type": "string",
                "description": "主播出镜说的开场钩子,中文,念出来不超过 8 秒"
              },
              "beats": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "narration": {
                      "type": "string",
                      "description": "这一拍要念的口播原文,中文;念出来不超过一拍的时长"
                    },
                    "visual_prompt": {
                      "type": "string",
                      "description": "这一拍的第一帧画面,英文;商品必须在画面里"
                    },
                    "motion_prompt": {
                      "type": "string",
                      "description": "这一拍的画面怎么动,英文:镜头的缓慢运动、光线在商品上的变化、轻微的动作"
                    },
                    "caption": {
                      "type": "string",
                      "description": "屏幕上的短句,不超过 14 字"
                    }
                  },
                  "required": [
                    "narration",
                    "visual_prompt",
                    "motion_prompt",
                    "caption"
                  ],
                  "additionalProperties": false
                },
                "minItems": 2,
                "maxItems": 12
              },
              "call_to_action": {
                "type": "string",
                "description": "主播出镜说的结尾行动号召,中文,念出来不超过 8 秒"
              }
            },
            "required": [
              "hook_line",
              "beats",
              "call_to_action"
            ],
            "additionalProperties": false
          },
          "json_schema_strict": "true",
          "temperature": 0.6,
          "max_tokens": 6000
        }
      },
      {
        "id": "fit_beats",
        "type": "fit_narration",
        "name": "量一遍每拍的口播念不念得完",
        "position": {
          "x": 970,
          "y": 120
        },
        "config": {
          "items": "{{pitch_script.json.beats}}",
          "text_field": "narration",
          "seconds": "{{start.beat_seconds}}",
          "max_total_seconds": "{{start.target_duration_seconds}}",
          "reserved_text": "{{pitch_script.json.hook_line}}\n{{pitch_script.json.call_to_action}}",
          "profile_id": "",
          "model": ""
        }
      },
      {
        "id": "pitch_project",
        "type": "project_sequence_create",
        "name": "建立竖屏成片时间线",
        "position": {
          "x": 650,
          "y": 420
        },
        "config": {
          "name": "{{start.product_name}} · 带货短片",
          "width": "{{start.width}}",
          "height": "{{start.height}}",
          "fps": "{{start.fps}}"
        }
      },
      {
        "id": "presenter",
        "type": "entity_get",
        "name": "挑一位主播(资产库里的人物)",
        "position": {
          "x": 330,
          "y": 520
        },
        "config": {
          "entity_id": "",
          "kind": "character"
        }
      },
      {
        "id": "has_hook",
        "type": "condition",
        "name": "开场有话要说吗",
        "position": {
          "x": 650,
          "y": 520
        },
        "config": {
          "left": "{{pitch_script.json.hook_line}}",
          "op": "not_empty"
        }
      },
      {
        "id": "hook_talk",
        "type": "entity_speak",
        "name": "主播出镜说开场",
        "position": {
          "x": 650,
          "y": 620
        },
        "config": {
          "entity_id": "",
          "text": "{{pitch_script.json.hook_line}}",
          "model": ""
        },
        "inputs": [
          "entity_id"
        ]
      },
      {
        "id": "hook_place",
        "type": "timeline_append",
        "name": "开场放在最前面",
        "position": {
          "x": 970,
          "y": 620
        },
        "config": {
          "sequence_id": "",
          "asset_id": "",
          "track_id": ""
        },
        "inputs": [
          "sequence_id",
          "asset_id",
          "track_id"
        ]
      },
      {
        "id": "has_cta",
        "type": "condition",
        "name": "收尾有话要说吗",
        "position": {
          "x": 650,
          "y": 720
        },
        "config": {
          "left": "{{pitch_script.json.call_to_action}}",
          "op": "not_empty"
        }
      },
      {
        "id": "cta_talk",
        "type": "entity_speak",
        "name": "主播出镜说收尾",
        "position": {
          "x": 650,
          "y": 800
        },
        "config": {
          "entity_id": "",
          "text": "{{pitch_script.json.call_to_action}}",
          "model": ""
        },
        "inputs": [
          "entity_id"
        ]
      },
      {
        "id": "presenter_has_voice",
        "type": "condition",
        "name": "主播有音色吗",
        "position": {
          "x": 330,
          "y": 700
        },
        "config": {
          "left": "",
          "op": "not_empty"
        },
        "inputs": [
          "left"
        ]
      },
      {
        "id": "presenter_has_face",
        "type": "condition",
        "name": "主播有图吗",
        "position": {
          "x": 330,
          "y": 860
        },
        "config": {
          "left": "",
          "op": "not_empty"
        },
        "inputs": [
          "left"
        ]
      },
      {
        "id": "presenter_voice_notice",
        "type": "notify",
        "name": "主播还没有音色",
        "position": {
          "x": 40,
          "y": 860
        },
        "config": {
          "title": "带货短片没有开始:主播还没有音色",
          "body": "「{{presenter.name}}」还没有配音色。在资产库里给它配一把(克隆音色要声明是谁的),再运行一次。还没花任何钱。"
        }
      },
      {
        "id": "presenter_face_notice",
        "type": "notify",
        "name": "主播还没有图",
        "position": {
          "x": 40,
          "y": 1020
        },
        "config": {
          "title": "带货短片没有开始:主播还没有图",
          "body": "「{{presenter.name}}」还没有一张正面图。在资产库里给它加一张(或先画一张),再运行一次。还没花任何钱。"
        }
      },
      {
        "id": "cta_spoken",
        "type": "condition",
        "name": "收尾那段出来了吗",
        "position": {
          "x": 970,
          "y": 800
        },
        "config": {
          "left": "",
          "op": "not_empty"
        },
        "inputs": [
          "left"
        ]
      },
      {
        "id": "cta_place",
        "type": "timeline_append",
        "name": "收尾接在最后",
        "position": {
          "x": 1290,
          "y": 800
        },
        "config": {
          "sequence_id": "",
          "asset_id": "",
          "track_id": ""
        },
        "inputs": [
          "sequence_id",
          "asset_id",
          "track_id"
        ]
      },
      {
        "id": "hook_captions",
        "type": "generate_subtitles",
        "name": "开场那句上字幕",
        "position": {
          "x": 1610,
          "y": 620
        },
        "config": {
          "sequence_id": "",
          "segments": "",
          "clip_id": "",
          "allow_empty": "yes"
        },
        "inputs": [
          "sequence_id",
          "segments",
          "clip_id"
        ]
      },
      {
        "id": "cta_captions",
        "type": "generate_subtitles",
        "name": "收尾那句上字幕",
        "position": {
          "x": 1610,
          "y": 800
        },
        "config": {
          "sequence_id": "",
          "segments": "",
          "clip_id": "",
          "allow_empty": "yes"
        },
        "inputs": [
          "sequence_id",
          "segments",
          "clip_id"
        ]
      },
      {
        "id": "shoot_beats",
        "type": "loop_foreach",
        "name": "逐拍出画面、动起来、配画外音并上时间线",
        "position": {
          "x": 970,
          "y": 260
        },
        "config": {
          "items": "",
          "inputs": {
            "product_asset_id": "{{product_photo.asset_id}}",
            "product_name": "{{start.product_name}}",
            "project_id": "{{pitch_project.project_id}}",
            "sequence_id": "{{pitch_project.sequence_id}}",
            "video_track_id": "{{pitch_project.video_track_id}}",
            "audio_track_id": "{{pitch_project.audio_track_id}}",
            "beat_seconds": "{{start.beat_seconds}}",
            "aspect_ratio": "9:16",
            "resolution": "720p",
            "voice_engine": "{{presenter.voice_engine}}",
            "voice_id": "{{presenter.voice_id}}"
          },
          "body": {
            "nodes": [
              {
                "id": "beat_frame",
                "type": "ai_generate",
                "name": "出这一拍的画面",
                "position": {
                  "x": 80,
                  "y": 140
                },
                "config": {
                  "provider": "",
                  "provider_profile_id": "",
                  "model": "",
                  "kind": "image",
                  "prompt": "{{loop.item.visual_prompt}} The product in the reference image must be reproduced EXACTLY: identical cut, silhouette, colour, fabric texture, weave, print scale and placement, stitching, buttons, trims and any logo or label. Do not redesign, restyle, recolour, resize the print, add or remove details. Only the wearer, pose, setting and lighting may change. Vertical 9:16 portrait-orientation photograph, full-bleed: the scene fills the frame edge to edge. Photorealistic, no text, no logo overlay, no watermark.",
                  "negative_prompt": "different garment, altered pattern, changed colour, distorted print, redesigned collar or sleeves, extra logos, text, watermark, deformed hands, extra limbs, phone, smartphone, device frame, screen bezel, mockup, app interface",
                  "parameters": {},
                  "source_assets": [
                    "{{input.product_asset_id}}:reference_image"
                  ]
                }
              },
              {
                "id": "file_frame",
                "type": "asset_update",
                "name": "归档这一拍的画面",
                "position": {
                  "x": 400,
                  "y": 0
                },
                "config": {
                  "asset_ids": "",
                  "name": "{{input.product_name}} · {{loop.item.caption}}",
                  "project_id": "{{input.project_id}}"
                },
                "inputs": [
                  "asset_ids"
                ]
              },
              {
                "id": "beat_clip",
                "type": "ai_generate",
                "name": "把这一拍动起来",
                "position": {
                  "x": 400,
                  "y": 140
                },
                "config": {
                  "provider": "",
                  "provider_profile_id": "",
                  "model": "",
                  "kind": "video",
                  "prompt": "{{loop.item.motion_prompt}} The product in the reference image must be reproduced EXACTLY: identical cut, silhouette, colour, fabric texture, weave, print scale and placement, stitching, buttons, trims and any logo or label. Do not redesign, restyle, recolour, resize the print, add or remove details. Only the wearer, pose, setting and lighting may change. Subtle, natural motion only; the product stays whole, undistorted and readable throughout. No text, no logo overlay, no watermark.",
                  "negative_prompt": "different garment, altered pattern, changed colour, distorted print, redesigned collar or sleeves, extra logos, text, watermark, deformed hands, extra limbs, phone, smartphone, device frame, screen bezel, mockup, app interface",
                  "parameters": {
                    "duration_seconds": "{{input.beat_seconds}}",
                    "aspect_ratio": "{{input.aspect_ratio}}",
                    "resolution": "{{input.resolution}}",
                    "generate_audio": false
                  },
                  "source_assets": [
                    "{{beat_frame.asset_id}}:first_frame"
                  ]
                }
              },
              {
                "id": "file_clip",
                "type": "asset_update",
                "name": "归档这一拍的视频",
                "position": {
                  "x": 720,
                  "y": 0
                },
                "config": {
                  "asset_ids": "",
                  "name": "{{input.product_name}} · {{loop.item.caption}} · 视频",
                  "project_id": "{{input.project_id}}"
                },
                "inputs": [
                  "asset_ids"
                ]
              },
              {
                "id": "mute_clip",
                "type": "edit_timeline",
                "name": "这一拍的视频不出声",
                "position": {
                  "x": 1040,
                  "y": 140
                },
                "config": {
                  "sequence_id": "{{input.sequence_id}}",
                  "operations": "[{\"kind\": \"set_clip_gain\", \"clip_id\": \"{{beat_on_timeline.clip_id}}\", \"muted\": true}]"
                }
              },
              {
                "id": "beat_on_timeline",
                "type": "timeline_append",
                "name": "按这一拍的时长铺上去",
                "position": {
                  "x": 720,
                  "y": 140
                },
                "config": {
                  "sequence_id": "{{input.sequence_id}}",
                  "asset_id": "",
                  "track_id": "{{input.video_track_id}}",
                  "start": 0,
                  "end": "{{input.beat_seconds}}"
                },
                "inputs": [
                  "asset_id"
                ]
              },
              {
                "id": "has_narration",
                "type": "condition",
                "name": "这一拍有画外音吗",
                "position": {
                  "x": 80,
                  "y": 320
                },
                "config": {
                  "left": "{{loop.item.narration}}",
                  "op": "not_empty"
                }
              },
              {
                "id": "beat_voice",
                "type": "synthesize_speech",
                "name": "念这一拍的画外音",
                "position": {
                  "x": 400,
                  "y": 320
                },
                "config": {
                  "text": "{{loop.item.narration}}",
                  "engine": "{{input.voice_engine}}",
                  "voice": "{{input.voice_id}}"
                }
              },
              {
                "id": "beat_voice_place",
                "type": "timeline_append",
                "name": "画外音对齐这一拍开头",
                "position": {
                  "x": 1040,
                  "y": 320
                },
                "config": {
                  "sequence_id": "{{input.sequence_id}}",
                  "asset_id": "",
                  "track_id": "{{input.audio_track_id}}",
                  "at": "",
                  "max_duration": "",
                  "trim_overflow": "yes"
                },
                "inputs": [
                  "asset_id",
                  "at",
                  "max_duration"
                ]
              },
              {
                "id": "voice_overflow",
                "type": "condition",
                "name": "画外音裁掉了尾巴吗",
                "position": {
                  "x": 1360,
                  "y": 320
                },
                "config": {
                  "left": "",
                  "op": "gt",
                  "right": "0"
                },
                "inputs": [
                  "left"
                ]
              },
              {
                "id": "overflow_notice",
                "type": "notify",
                "name": "说一声画外音被裁了",
                "position": {
                  "x": 1680,
                  "y": 320
                },
                "config": {
                  "title": "带货短片:有一拍的画外音念不完",
                  "body": "「{{loop.item.caption}}」那一拍的画外音加速到 1.5 倍仍比画面长 {{beat_voice_place.trimmed}} 秒,超出的部分已裁掉。想保住整句,把这一拍的口播改短或把开始节点的 beat_seconds(每拍几秒)改长(视频模型要出得了那个时长)再运行一次。"
                }
              }
            ],
            "edges": [
              {
                "id": "file_then_clip",
                "source": "file_frame",
                "target": "beat_clip"
              },
              {
                "id": "clip_file",
                "source": "beat_clip",
                "target": "file_clip"
              },
              {
                "id": "clip_place",
                "source": "beat_clip",
                "target": "beat_on_timeline"
              },
              {
                "id": "place_mute",
                "source": "beat_on_timeline",
                "target": "mute_clip"
              },
              {
                "id": "frame_file",
                "source": "beat_frame",
                "target": "file_frame"
              },
              {
                "id": "place_voice",
                "source": "beat_on_timeline",
                "target": "beat_voice_place"
              },
              {
                "id": "voice_voice_place",
                "source": "beat_voice",
                "target": "beat_voice_place"
              },
              {
                "id": "narration_voice",
                "source": "has_narration",
                "target": "beat_voice",
                "source_handle": "true"
              },
              {
                "id": "narration_voice_place",
                "source": "has_narration",
                "target": "beat_voice_place",
                "source_handle": "true"
              },
              {
                "id": "voice_overflow_check",
                "source": "beat_voice_place",
                "target": "voice_overflow"
              },
              {
                "id": "overflow_notify",
                "source": "voice_overflow",
                "target": "overflow_notice",
                "source_handle": "true"
              },
              {
                "id": "d-beat_frame-asset_id-file_frame-asset_ids",
                "source": "beat_frame",
                "target": "file_frame",
                "kind": "data",
                "source_output": "asset_id",
                "target_input": "asset_ids"
              },
              {
                "id": "d-beat_clip-asset_id-file_clip-asset_ids",
                "source": "beat_clip",
                "target": "file_clip",
                "kind": "data",
                "source_output": "asset_id",
                "target_input": "asset_ids"
              },
              {
                "id": "d-beat_clip-asset_id-beat_on_timeline-asset_id",
                "source": "beat_clip",
                "target": "beat_on_timeline",
                "kind": "data",
                "source_output": "asset_id",
                "target_input": "asset_id"
              },
              {
                "id": "d-beat_voice-asset_id-beat_voice_place-asset_id",
                "source": "beat_voice",
                "target": "beat_voice_place",
                "kind": "data",
                "source_output": "asset_id",
                "target_input": "asset_id"
              },
              {
                "id": "d-beat_on_timeline-timeline_start-beat_voice_place-at",
                "source": "beat_on_timeline",
                "target": "beat_voice_place",
                "kind": "data",
                "source_output": "timeline_start",
                "target_input": "at"
              },
              {
                "id": "d-beat_on_timeline-duration-beat_voice_place-max_duration",
                "source": "beat_on_timeline",
                "target": "beat_voice_place",
                "kind": "data",
                "source_output": "duration",
                "target_input": "max_duration"
              },
              {
                "id": "d-beat_voice_place-trimmed-voice_overflow-left",
                "source": "beat_voice_place",
                "target": "voice_overflow",
                "kind": "data",
                "source_output": "trimmed",
                "target_input": "left"
              }
            ]
          },
          "concurrency": 1,
          "output": ""
        },
        "inputs": [
          "items"
        ]
      },
      {
        "id": "beat_captions",
        "type": "generate_subtitles",
        "name": "按每一拍的落点铺屏幕短句",
        "position": {
          "x": 1290,
          "y": 260
        },
        "config": {
          "sequence_id": "",
          "segments": "",
          "start_field": "beat_on_timeline.timeline_start",
          "end_field": "beat_on_timeline.timeline_end",
          "text_field": "loop.item.caption"
        },
        "inputs": [
          "sequence_id",
          "segments"
        ]
      },
      {
        "id": "export_short",
        "type": "export_sequence",
        "name": "导出成片",
        "position": {
          "x": 1610,
          "y": 260
        },
        "config": {
          "sequence_id": ""
        },
        "inputs": [
          "sequence_id"
        ]
      },
      {
        "id": "done_notice",
        "type": "notify",
        "name": "成片完成通知",
        "position": {
          "x": 1930,
          "y": 260
        },
        "config": {
          "title": "带货短片已导出",
          "body": "{{start.product_name}} 的口播短片已完成,共 {{shoot_beats.count}} 拍。\n{{fit_beats.note}}"
        }
      },
      {
        "id": "output",
        "type": "output",
        "name": "交付成片与脚本",
        "position": {
          "x": 2250,
          "y": 260
        },
        "config": {
          "values": {
            "final_asset_id": "{{export_short.asset_id}}",
            "script": "{{pitch_script.json}}",
            "beat_count": "{{shoot_beats.count}}",
            "caption_count": "{{beat_captions.count}}",
            "sequence_id": "{{pitch_project.sequence_id}}",
            "hook_asset_id": "{{hook_talk.asset_id}}",
            "cta_asset_id": "{{cta_talk.asset_id}}"
          }
        }
      }
    ],
    "edges": [
      {
        "id": "start_photo",
        "source": "start",
        "target": "product_photo"
      },
      {
        "id": "start_presenter",
        "source": "start",
        "target": "presenter"
      },
      {
        "id": "presenter_voice_check",
        "source": "presenter",
        "target": "presenter_has_voice"
      },
      {
        "id": "presenter_voice_ok",
        "source": "presenter_has_voice",
        "target": "presenter_has_face",
        "source_handle": "true"
      },
      {
        "id": "presenter_voice_missing",
        "source": "presenter_has_voice",
        "target": "presenter_voice_notice",
        "source_handle": "false"
      },
      {
        "id": "presenter_face_missing",
        "source": "presenter_has_face",
        "target": "presenter_face_notice",
        "source_handle": "false"
      },
      {
        "id": "presenter_script",
        "source": "presenter_has_face",
        "target": "pitch_script",
        "source_handle": "true"
      },
      {
        "id": "script_project",
        "source": "pitch_script",
        "target": "pitch_project"
      },
      {
        "id": "presenter_hook",
        "source": "presenter",
        "target": "hook_talk"
      },
      {
        "id": "script_has_hook",
        "source": "pitch_script",
        "target": "has_hook"
      },
      {
        "id": "hook_said",
        "source": "has_hook",
        "target": "hook_talk",
        "source_handle": "true"
      },
      {
        "id": "presenter_cta",
        "source": "presenter",
        "target": "cta_talk"
      },
      {
        "id": "script_has_cta",
        "source": "pitch_script",
        "target": "has_cta"
      },
      {
        "id": "cta_said",
        "source": "has_cta",
        "target": "cta_talk",
        "source_handle": "true"
      },
      {
        "id": "hook_place_edge",
        "source": "hook_talk",
        "target": "hook_place"
      },
      {
        "id": "project_hook",
        "source": "pitch_project",
        "target": "hook_place"
      },
      {
        "id": "hook_place_gate",
        "source": "has_hook",
        "target": "hook_place",
        "source_handle": "true"
      },
      {
        "id": "hook_then_beats",
        "source": "hook_place",
        "target": "shoot_beats"
      },
      {
        "id": "script_fit",
        "source": "pitch_script",
        "target": "fit_beats"
      },
      {
        "id": "fit_shoot",
        "source": "fit_beats",
        "target": "shoot_beats"
      },
      {
        "id": "beats_then_cta",
        "source": "shoot_beats",
        "target": "cta_spoken"
      },
      {
        "id": "cta_place_edge",
        "source": "cta_talk",
        "target": "cta_place"
      },
      {
        "id": "cta_place_gate",
        "source": "cta_spoken",
        "target": "cta_place",
        "source_handle": "true"
      },
      {
        "id": "cta_then_captions",
        "source": "cta_place",
        "target": "beat_captions"
      },
      {
        "id": "shoot_captions",
        "source": "shoot_beats",
        "target": "beat_captions"
      },
      {
        "id": "beats_then_hook_captions",
        "source": "beat_captions",
        "target": "hook_captions"
      },
      {
        "id": "hook_then_cta_captions",
        "source": "hook_captions",
        "target": "cta_captions"
      },
      {
        "id": "captions_export",
        "source": "cta_captions",
        "target": "export_short"
      },
      {
        "id": "export_notice",
        "source": "export_short",
        "target": "done_notice"
      },
      {
        "id": "notice_output",
        "source": "done_notice",
        "target": "output"
      },
      {
        "id": "d-presenter-entity_id-hook_talk-entity_id",
        "source": "presenter",
        "target": "hook_talk",
        "kind": "data",
        "source_output": "entity_id",
        "target_input": "entity_id"
      },
      {
        "id": "d-pitch_project-sequence_id-hook_place-sequence_id",
        "source": "pitch_project",
        "target": "hook_place",
        "kind": "data",
        "source_output": "sequence_id",
        "target_input": "sequence_id"
      },
      {
        "id": "d-hook_talk-asset_id-hook_place-asset_id",
        "source": "hook_talk",
        "target": "hook_place",
        "kind": "data",
        "source_output": "asset_id",
        "target_input": "asset_id"
      },
      {
        "id": "d-pitch_project-video_track_id-hook_place-track_id",
        "source": "pitch_project",
        "target": "hook_place",
        "kind": "data",
        "source_output": "video_track_id",
        "target_input": "track_id"
      },
      {
        "id": "d-presenter-entity_id-cta_talk-entity_id",
        "source": "presenter",
        "target": "cta_talk",
        "kind": "data",
        "source_output": "entity_id",
        "target_input": "entity_id"
      },
      {
        "id": "d-presenter-voice_id-presenter_has_voice-left",
        "source": "presenter",
        "target": "presenter_has_voice",
        "kind": "data",
        "source_output": "voice_id",
        "target_input": "left"
      },
      {
        "id": "d-presenter-asset_ids-presenter_has_face-left",
        "source": "presenter",
        "target": "presenter_has_face",
        "kind": "data",
        "source_output": "asset_ids",
        "target_input": "left"
      },
      {
        "id": "d-cta_talk-asset_id-cta_spoken-left",
        "source": "cta_talk",
        "target": "cta_spoken",
        "kind": "data",
        "source_output": "asset_id",
        "target_input": "left"
      },
      {
        "id": "d-pitch_project-sequence_id-cta_place-sequence_id",
        "source": "pitch_project",
        "target": "cta_place",
        "kind": "data",
        "source_output": "sequence_id",
        "target_input": "sequence_id"
      },
      {
        "id": "d-cta_talk-asset_id-cta_place-asset_id",
        "source": "cta_talk",
        "target": "cta_place",
        "kind": "data",
        "source_output": "asset_id",
        "target_input": "asset_id"
      },
      {
        "id": "d-pitch_project-video_track_id-cta_place-track_id",
        "source": "pitch_project",
        "target": "cta_place",
        "kind": "data",
        "source_output": "video_track_id",
        "target_input": "track_id"
      },
      {
        "id": "d-pitch_project-sequence_id-hook_captions-sequence_id",
        "source": "pitch_project",
        "target": "hook_captions",
        "kind": "data",
        "source_output": "sequence_id",
        "target_input": "sequence_id"
      },
      {
        "id": "d-hook_talk-cues-hook_captions-segments",
        "source": "hook_talk",
        "target": "hook_captions",
        "kind": "data",
        "source_output": "cues",
        "target_input": "segments"
      },
      {
        "id": "d-hook_place-clip_id-hook_captions-clip_id",
        "source": "hook_place",
        "target": "hook_captions",
        "kind": "data",
        "source_output": "clip_id",
        "target_input": "clip_id"
      },
      {
        "id": "d-pitch_project-sequence_id-cta_captions-sequence_id",
        "source": "pitch_project",
        "target": "cta_captions",
        "kind": "data",
        "source_output": "sequence_id",
        "target_input": "sequence_id"
      },
      {
        "id": "d-cta_talk-cues-cta_captions-segments",
        "source": "cta_talk",
        "target": "cta_captions",
        "kind": "data",
        "source_output": "cues",
        "target_input": "segments"
      },
      {
        "id": "d-cta_place-clip_id-cta_captions-clip_id",
        "source": "cta_place",
        "target": "cta_captions",
        "kind": "data",
        "source_output": "clip_id",
        "target_input": "clip_id"
      },
      {
        "id": "d-fit_beats-items-shoot_beats-items",
        "source": "fit_beats",
        "target": "shoot_beats",
        "kind": "data",
        "source_output": "items",
        "target_input": "items"
      },
      {
        "id": "d-pitch_project-sequence_id-beat_captions-sequence_id",
        "source": "pitch_project",
        "target": "beat_captions",
        "kind": "data",
        "source_output": "sequence_id",
        "target_input": "sequence_id"
      },
      {
        "id": "d-shoot_beats-results-beat_captions-segments",
        "source": "shoot_beats",
        "target": "beat_captions",
        "kind": "data",
        "source_output": "results",
        "target_input": "segments"
      },
      {
        "id": "d-pitch_project-sequence_id-export_short-sequence_id",
        "source": "pitch_project",
        "target": "export_short",
        "kind": "data",
        "source_output": "sequence_id",
        "target_input": "sequence_id"
      }
    ]
  }
}
