{
 "schema_version": "1.0",
 "nodes": [
  {
   "id": "briefing",
   "type": "input/video",
   "label": "The briefing",
   "parameters": {
    "required": true
   }
  },
  {
   "id": "brief",
   "type": "input/json_value",
   "label": "The editor's brief",
   "parameters": { "value": {"publication": "Orbit Weekly, a science magazine's website (fictional)", "audience": "curious general readers, no specialist knowledge", "who_speaks": "NASA's Administrator, then three NASA astronauts, interviewed one at a time", "source": "NASA, Artemis Media Resource — Interview Soundbites, 2019 (public domain)"},
    "required": true
   }
  },
  {
   "id": "speech",
   "type": "video/extract_audio",
   "label": "The speech",
   "parameters": {
    "profile": "speech",
    "format": "wav"
   }
  },
  {
   "id": "transcribe",
   "type": "ai/speech_to_text",
   "label": "Transcribe, in one pass",
   "parameters": {
    "task": "transcribe",
    "language": "en",
    "granularity": "segment",
    "diarization": true,
    "caption_format": "none"
   },
   "model": {
    "model": "elevenlabs-scribe-v2"
   }
  },
  {
   "id": "transcript",
   "type": "text/format",
   "label": "The transcript as text",
   "parameters": {
    "format": "json"
   }
  },
  {
   "id": "each_line",
   "type": "enumerate/json",
   "label": "Each line of speech",
   "parameters": {
    "jsonConfig": {
     "arrayPath": "cues",
     "properties": [
      {
       "sourcePath": "text",
       "outputPort": "text",
       "outputType": "text",
       "selected": true,
       "label": "text"
      }
     ]
    },
    "emptyBehavior": "fail"
   }
  },
  {
   "id": "said",
   "type": "aggregate/concat_text",
   "label": "What was said, as one text",
   "parameters": {
    "separator": " "
   }
  },
  {
   "id": "publication",
   "type": "utility/extract",
   "label": "Publication",
   "parameters": {
    "path": "publication",
    "expected_type": "text",
    "on_missing": "fail"
   }
  },
  {
   "id": "audience",
   "type": "utility/extract",
   "label": "Audience",
   "parameters": {
    "path": "audience",
    "expected_type": "text",
    "on_missing": "fail"
   }
  },
  {
   "id": "who_speaks",
   "type": "utility/extract",
   "label": "Who speaks",
   "parameters": {
    "path": "who_speaks",
    "expected_type": "text",
    "on_missing": "fail"
   }
  },
  {
   "id": "source",
   "type": "utility/extract",
   "label": "Source",
   "parameters": {
    "path": "source",
    "expected_type": "text",
    "on_missing": "fail"
   }
  },
  {
   "id": "for_writer",
   "type": "text/template",
   "label": "Brief for the writer",
   "parameters": {
    "template": "Publication: [publication]\nReaders: [audience]\nWho speaks: [who]\n\nThe transcript, one cue per line of speech, with a speaker label per voice:\n[transcript]",
    "placeholders": [
     {
      "name": "publication",
      "inputPort": "publication"
     },
     {
      "name": "audience",
      "inputPort": "audience"
     },
     {
      "name": "who",
      "inputPort": "who"
     },
     {
      "name": "transcript",
      "inputPort": "transcript"
     }
    ]
   }
  },
  {
   "id": "write",
   "type": "ai/text_generation",
   "label": "Write the package",
   "parameters": {
    "response_format": "json_object",
    "max_tokens": 8000,
    "system_prompt": "You are the editor of a science magazine's website. From the transcript of a recorded briefing you write a news story and the material that goes with it. Use only what the speakers say; never add facts, figures, names or dates that are not in the transcript. Do not name the speakers: say what they are, as the brief says, and only when the transcript makes it clear; otherwise write 'one of the astronauts' or 'a speaker'.\nReturn one JSON object with exactly these keys:\n- headline: 40 to 90 characters\n- standfirst: one sentence under the headline, 120 to 220 characters\n- body: the story in five or six paragraphs separated by a blank line, 280 to 420 words, in your words: no quotation marks in it\n- quotes: exactly three objects, the best lines of the briefing, each with: quote — one complete sentence copied word for word from the transcript, with its punctuation, without quotation marks, 60 to 220 characters; speaker — who says it, as above; about — what it is about, three to six words in lower case, such as 'the Moon as a step to Mars'\n- social: an object with the keys en, it and es, each with linkedin (300 to 600 characters, two short paragraphs) and x (at most 260 characters), written natively in English, Italian and Spanish; no quotation marks and no hashtags\n- audio_script: a summary to be read aloud, 90 to 120 words, in plain spoken English, with no headings and no lists\n- image_idea: one English sentence describing a picture for the story: the Moon, a spacecraft, a landscape — no people, no faces, no text, no logos"
   },
   "model": {
    "model": "gpt-5.6-luna",
    "params": {
     "reasoning_effort": "low"
    }
   }
  },
  {
   "id": "check",
   "type": "utility/json_schema_validate",
   "label": "The package is complete",
   "parameters": {
    "schema_source": "inline",
    "mode": "fail",
    "schema_definition": {
     "$schema": "https://json-schema.org/draft/2020-12/schema",
     "title": "An editorial package",
     "type": "object",
     "required": [
      "headline",
      "standfirst",
      "body",
      "quotes",
      "social",
      "audio_script",
      "image_idea"
     ],
     "properties": {
      "headline": {
       "type": "string",
       "minLength": 30,
       "maxLength": 100
      },
      "standfirst": {
       "type": "string",
       "minLength": 100,
       "maxLength": 240
      },
      "body": {
       "type": "string",
       "minLength": 1500,
       "maxLength": 3200,
       "pattern": "^[^\"“”]*$"
      },
      "quotes": {
       "type": "array",
       "minItems": 3,
       "maxItems": 3,
       "items": {
        "type": "object",
        "required": [
         "quote",
         "speaker",
         "about"
        ],
        "properties": {
         "quote": {
          "type": "string",
          "minLength": 20,
          "maxLength": 240
         },
         "speaker": {
          "type": "string",
          "minLength": 3,
          "maxLength": 60
         },
         "about": {
          "type": "string",
          "minLength": 5,
          "maxLength": 60
         }
        }
       }
      },
      "social": {
       "type": "object",
       "required": [
        "en",
        "it",
        "es"
       ],
       "properties": {
        "en": {
         "type": "object",
         "required": [
          "linkedin",
          "x"
         ],
         "properties": {
          "linkedin": {
           "type": "string",
           "minLength": 250,
           "maxLength": 700,
           "pattern": "^[^\"“”]*$"
          },
          "x": {
           "type": "string",
           "minLength": 60,
           "maxLength": 280,
           "pattern": "^[^\"“”]*$"
          }
         }
        },
        "it": {
         "type": "object",
         "required": [
          "linkedin",
          "x"
         ],
         "properties": {
          "linkedin": {
           "type": "string",
           "minLength": 250,
           "maxLength": 700,
           "pattern": "^[^\"“”]*$"
          },
          "x": {
           "type": "string",
           "minLength": 60,
           "maxLength": 280,
           "pattern": "^[^\"“”]*$"
          }
         }
        },
        "es": {
         "type": "object",
         "required": [
          "linkedin",
          "x"
         ],
         "properties": {
          "linkedin": {
           "type": "string",
           "minLength": 250,
           "maxLength": 700,
           "pattern": "^[^\"“”]*$"
          },
          "x": {
           "type": "string",
           "minLength": 60,
           "maxLength": 280,
           "pattern": "^[^\"“”]*$"
          }
         }
        }
       }
      },
      "audio_script": {
       "type": "string",
       "minLength": 450,
       "maxLength": 900
      },
      "image_idea": {
       "type": "string",
       "minLength": 40,
       "maxLength": 400
      }
     }
    }
   }
  },
  {
   "id": "x_headline",
   "type": "utility/extract",
   "label": "Headline",
   "parameters": {
    "path": "headline",
    "expected_type": "text",
    "on_missing": "fail"
   }
  },
  {
   "id": "x_standfirst",
   "type": "utility/extract",
   "label": "Standfirst",
   "parameters": {
    "path": "standfirst",
    "expected_type": "text",
    "on_missing": "fail"
   }
  },
  {
   "id": "x_body",
   "type": "utility/extract",
   "label": "Body",
   "parameters": {
    "path": "body",
    "expected_type": "text",
    "on_missing": "fail"
   }
  },
  {
   "id": "x_social",
   "type": "utility/extract",
   "label": "Social",
   "parameters": {
    "path": "social",
    "expected_type": "json",
    "on_missing": "fail"
   }
  },
  {
   "id": "x_audio_script",
   "type": "utility/extract",
   "label": "Audio script",
   "parameters": {
    "path": "audio_script",
    "expected_type": "text",
    "on_missing": "fail"
   }
  },
  {
   "id": "x_image_idea",
   "type": "utility/extract",
   "label": "Image idea",
   "parameters": {
    "path": "image_idea",
    "expected_type": "text",
    "on_missing": "fail"
   }
  },
  {
   "id": "x_quotes",
   "type": "utility/extract",
   "label": "Quotes",
   "parameters": {
    "path": "quotes",
    "expected_type": "json",
    "on_missing": "fail"
   }
  },
  {
   "id": "each_quote",
   "type": "enumerate/json",
   "label": "Each quotation",
   "parameters": {
    "jsonConfig": {
     "arrayPath": "(root)",
     "properties": [
      {
       "sourcePath": "quote",
       "outputPort": "quote",
       "outputType": "text",
       "selected": true,
       "label": "quote"
      },
      {
       "sourcePath": "speaker",
       "outputPort": "speaker",
       "outputType": "text",
       "selected": true,
       "label": "speaker"
      },
      {
       "sourcePath": "about",
       "outputPort": "about",
       "outputType": "text",
       "selected": true,
       "label": "about"
      }
     ]
    },
    "emptyBehavior": "fail"
   }
  },
  {
   "id": "find",
   "type": "text/replace",
   "label": "Find it in the transcript",
   "parameters": {
    "replace_with": ""
   }
  },
  {
   "id": "found",
   "type": "utility/predicate",
   "label": "Found word for word",
   "parameters": {
    "operation": "greater_or_equal",
    "compare_number": 1
   }
  },
  {
   "id": "as_markdown",
   "type": "text/template",
   "label": "The quotation, set",
   "parameters": {
    "template": "> “[quote]”\n>\n> — [speaker], on [about]",
    "placeholders": [
     {
      "name": "quote",
      "inputPort": "quote"
     },
     {
      "name": "speaker",
      "inputPort": "speaker"
     },
     {
      "name": "about",
      "inputPort": "about"
     }
    ]
   }
  },
  {
   "id": "verified",
   "type": "utility/filter",
   "label": "Only a quotation that was said",
   "parameters": {
    "invert": false
   }
  },
  {
   "id": "not_said",
   "type": "utility/filter",
   "label": "A quotation not in the transcript",
   "parameters": {
    "invert": true
   }
  },
  {
   "id": "quotes_block",
   "type": "aggregate/concat_text",
   "label": "The quotations that were said",
   "parameters": {
    "separator": "\n\n"
   }
  },
  {
   "id": "quotes_report",
   "type": "aggregate/json",
   "label": "Quotations checked",
   "parameters": {
    "emptyBehavior": "empty",
    "jsonAggregateConfig": {
     "prettyPrint": true,
     "outputName": "quotations",
     "columns": [
      {
       "name": "quote",
       "inputPort": "quote",
       "type": "text"
      },
      {
       "name": "speaker",
       "inputPort": "speaker",
       "type": "text"
      },
      {
       "name": "times_found",
       "inputPort": "times_found",
       "type": "number"
      }
     ]
    }
   }
  },
  {
   "id": "not_said_list",
   "type": "aggregate/json",
   "label": "Quotations left out",
   "parameters": {
    "emptyBehavior": "empty",
    "jsonAggregateConfig": {
     "prettyPrint": true,
     "outputName": "quotations-left-out",
     "columns": [
      {
       "name": "quote",
       "inputPort": "quote",
       "type": "text",
       "whenAbsent": "skip_row"
      }
     ]
    }
   }
  },
  {
   "id": "article",
   "type": "text/template",
   "label": "The story, in Markdown",
   "parameters": {
    "template": "# [headline]\n\n*[standfirst]*\n\n[body]\n\n## In their words\n\n[quotes]\n\n---\n\n*Source: [source]. Every quotation was found word for word in the transcript.*",
    "placeholders": [
     {
      "name": "headline",
      "inputPort": "headline"
     },
     {
      "name": "standfirst",
      "inputPort": "standfirst"
     },
     {
      "name": "body",
      "inputPort": "body"
     },
     {
      "name": "quotes",
      "inputPort": "quotes"
     },
     {
      "name": "source",
      "inputPort": "source"
     }
    ]
   }
  },
  {
   "id": "picture_prompt",
   "type": "text/template",
   "label": "Direction for the picture",
   "parameters": {
    "template": "[idea] Editorial illustration for a science magazine, wide format, painterly and luminous, deep blues and warm sunlight; no people, no text, no logos.",
    "placeholders": [
     {
      "name": "idea",
      "inputPort": "idea"
     }
    ]
   }
  },
  {
   "id": "picture",
   "type": "ai/text_to_image",
   "label": "Paint the header",
   "parameters": {
    "aspect_ratio": "16_9"
   }
  },
  {
   "id": "voice",
   "type": "ai/text_to_speech",
   "label": "Read the summary aloud",
   "parameters": {},
   "model": {
    "model": "elevenlabs-turbo-v2.5",
    "params": {
     "voice": "Rachel",
     "stability": 0.55,
     "apply_text_normalization": "auto",
     "timestamps": false
    }
   }
  },
  {
   "id": "o_article",
   "type": "output/text",
   "label": "The story",
   "parameters": {
    "output_name": "story_markdown"
   }
  },
  {
   "id": "o_picture",
   "type": "output/image",
   "label": "Header picture",
   "parameters": {
    "output_name": "header_picture"
   }
  },
  {
   "id": "o_voice",
   "type": "output/audio",
   "label": "Audio summary",
   "parameters": {
    "output_name": "audio_summary"
   }
  },
  {
   "id": "o_script",
   "type": "output/text",
   "label": "Audio script",
   "parameters": {
    "output_name": "audio_script"
   }
  },
  {
   "id": "o_social",
   "type": "output/json",
   "label": "Social posts",
   "parameters": {
    "output_name": "social_posts"
   }
  },
  {
   "id": "o_quotes",
   "type": "output/json",
   "label": "Quotations checked",
   "parameters": {
    "output_name": "quotations_checked"
   }
  },
  {
   "id": "o_left_out",
   "type": "output/json",
   "label": "Quotations left out",
   "parameters": {
    "output_name": "quotations_left_out"
   }
  },
  {
   "id": "o_transcript",
   "type": "output/json",
   "label": "Transcript",
   "parameters": {
    "output_name": "transcript"
   }
  }
 ],
 "connections": [
  {
   "from_node": "briefing",
   "from_output": "video",
   "to_node": "speech",
   "to_input": "video"
  },
  {
   "from_node": "speech",
   "from_output": "audio",
   "to_node": "transcribe",
   "to_input": "audio"
  },
  {
   "from_node": "transcribe",
   "from_output": "caption_track",
   "to_node": "transcript",
   "to_input": "value"
  },
  {
   "from_node": "transcribe",
   "from_output": "caption_track",
   "to_node": "each_line",
   "to_input": "json"
  },
  {
   "from_node": "each_line",
   "from_output": "text",
   "to_node": "said",
   "to_input": "texts"
  },
  {
   "from_node": "brief",
   "from_output": "json",
   "to_node": "publication",
   "to_input": "json"
  },
  {
   "from_node": "brief",
   "from_output": "json",
   "to_node": "audience",
   "to_input": "json"
  },
  {
   "from_node": "brief",
   "from_output": "json",
   "to_node": "who_speaks",
   "to_input": "json"
  },
  {
   "from_node": "brief",
   "from_output": "json",
   "to_node": "source",
   "to_input": "json"
  },
  {
   "from_node": "publication",
   "from_output": "value",
   "to_node": "for_writer",
   "to_input": "publication"
  },
  {
   "from_node": "audience",
   "from_output": "value",
   "to_node": "for_writer",
   "to_input": "audience"
  },
  {
   "from_node": "who_speaks",
   "from_output": "value",
   "to_node": "for_writer",
   "to_input": "who"
  },
  {
   "from_node": "transcript",
   "from_output": "text",
   "to_node": "for_writer",
   "to_input": "transcript"
  },
  {
   "from_node": "for_writer",
   "from_output": "result",
   "to_node": "write",
   "to_input": "prompt"
  },
  {
   "from_node": "write",
   "from_output": "json",
   "to_node": "check",
   "to_input": "document"
  },
  {
   "from_node": "check",
   "from_output": "normalized_json",
   "to_node": "x_headline",
   "to_input": "json"
  },
  {
   "from_node": "check",
   "from_output": "normalized_json",
   "to_node": "x_standfirst",
   "to_input": "json"
  },
  {
   "from_node": "check",
   "from_output": "normalized_json",
   "to_node": "x_body",
   "to_input": "json"
  },
  {
   "from_node": "check",
   "from_output": "normalized_json",
   "to_node": "x_social",
   "to_input": "json"
  },
  {
   "from_node": "check",
   "from_output": "normalized_json",
   "to_node": "x_audio_script",
   "to_input": "json"
  },
  {
   "from_node": "check",
   "from_output": "normalized_json",
   "to_node": "x_image_idea",
   "to_input": "json"
  },
  {
   "from_node": "check",
   "from_output": "normalized_json",
   "to_node": "x_quotes",
   "to_input": "json"
  },
  {
   "from_node": "x_quotes",
   "from_output": "value",
   "to_node": "each_quote",
   "to_input": "json"
  },
  {
   "from_node": "said",
   "from_output": "result",
   "to_node": "find",
   "to_input": "text"
  },
  {
   "from_node": "each_quote",
   "from_output": "quote",
   "to_node": "find",
   "to_input": "find"
  },
  {
   "from_node": "find",
   "from_output": "count",
   "to_node": "found",
   "to_input": "a"
  },
  {
   "from_node": "each_quote",
   "from_output": "quote",
   "to_node": "as_markdown",
   "to_input": "quote"
  },
  {
   "from_node": "each_quote",
   "from_output": "speaker",
   "to_node": "as_markdown",
   "to_input": "speaker"
  },
  {
   "from_node": "each_quote",
   "from_output": "about",
   "to_node": "as_markdown",
   "to_input": "about"
  },
  {
   "from_node": "found",
   "from_output": "result",
   "to_node": "verified",
   "to_input": "condition"
  },
  {
   "from_node": "as_markdown",
   "from_output": "result",
   "to_node": "verified",
   "to_input": "value"
  },
  {
   "from_node": "found",
   "from_output": "result",
   "to_node": "not_said",
   "to_input": "condition"
  },
  {
   "from_node": "each_quote",
   "from_output": "quote",
   "to_node": "not_said",
   "to_input": "value"
  },
  {
   "from_node": "verified",
   "from_output": "value",
   "to_node": "quotes_block",
   "to_input": "texts"
  },
  {
   "from_node": "each_quote",
   "from_output": "quote",
   "to_node": "quotes_report",
   "to_input": "quote"
  },
  {
   "from_node": "each_quote",
   "from_output": "speaker",
   "to_node": "quotes_report",
   "to_input": "speaker"
  },
  {
   "from_node": "find",
   "from_output": "count",
   "to_node": "quotes_report",
   "to_input": "times_found"
  },
  {
   "from_node": "not_said",
   "from_output": "value",
   "to_node": "not_said_list",
   "to_input": "quote"
  },
  {
   "from_node": "x_headline",
   "from_output": "value",
   "to_node": "article",
   "to_input": "headline"
  },
  {
   "from_node": "x_standfirst",
   "from_output": "value",
   "to_node": "article",
   "to_input": "standfirst"
  },
  {
   "from_node": "x_body",
   "from_output": "value",
   "to_node": "article",
   "to_input": "body"
  },
  {
   "from_node": "quotes_block",
   "from_output": "result",
   "to_node": "article",
   "to_input": "quotes"
  },
  {
   "from_node": "source",
   "from_output": "value",
   "to_node": "article",
   "to_input": "source"
  },
  {
   "from_node": "x_image_idea",
   "from_output": "value",
   "to_node": "picture_prompt",
   "to_input": "idea"
  },
  {
   "from_node": "picture_prompt",
   "from_output": "result",
   "to_node": "picture",
   "to_input": "prompt"
  },
  {
   "from_node": "x_audio_script",
   "from_output": "value",
   "to_node": "voice",
   "to_input": "text"
  },
  {
   "from_node": "article",
   "from_output": "result",
   "to_node": "o_article",
   "to_input": "text"
  },
  {
   "from_node": "picture",
   "from_output": "result",
   "to_node": "o_picture",
   "to_input": "image"
  },
  {
   "from_node": "voice",
   "from_output": "audio",
   "to_node": "o_voice",
   "to_input": "audio"
  },
  {
   "from_node": "x_audio_script",
   "from_output": "value",
   "to_node": "o_script",
   "to_input": "text"
  },
  {
   "from_node": "x_social",
   "from_output": "value",
   "to_node": "o_social",
   "to_input": "json"
  },
  {
   "from_node": "quotes_report",
   "from_output": "result",
   "to_node": "o_quotes",
   "to_input": "json"
  },
  {
   "from_node": "not_said_list",
   "from_output": "result",
   "to_node": "o_left_out",
   "to_input": "json"
  },
  {
   "from_node": "transcribe",
   "from_output": "caption_track",
   "to_node": "o_transcript",
   "to_input": "json"
  }
 ]
}