{
 "schema_version": "1.0",
 "nodes": [
  {
   "id": "reviews",
   "type": "input/data",
   "label": "Reviews of the month",
   "parameters": {
    "dataConfig": {
     "assetPath": "__REVIEWS_CSV__",
     "format": "auto",
     "headerRow": 1,
     "locale": "en-US",
     "formulaPolicy": "cached_value",
     "emptyBehavior": "fail",
     "maxRows": 1000
    }
   }
  },
  {
   "id": "osteria",
   "type": "input/text",
   "label": "Restaurant name",
   "parameters": {
    "text": "Osteria Le Tre Lune",
    "required": true
   }
  },
  {
   "id": "month",
   "type": "input/text",
   "label": "Period",
   "parameters": {
    "text": "September 2026",
    "required": true
   }
  },
  {
   "id": "reviews_page",
   "type": "input/text",
   "label": "Link to all reviews",
   "parameters": {
    "text": "https://www.example.com/osteria-le-tre-lune/reviews",
    "required": true
   }
  },
  {
   "id": "each",
   "type": "enumerate/data_rows",
   "label": "Each review",
   "parameters": {
    "rowMapping": {
     "columns": [
      {
       "sourceColumn": "review_id",
       "outputPort": "review_id",
       "outputType": "text",
       "selected": true,
       "label": "review_id",
       "conversion": "strict"
      },
      {
       "sourceColumn": "source",
       "outputPort": "source",
       "outputType": "text",
       "selected": true,
       "label": "source",
       "conversion": "strict"
      },
      {
       "sourceColumn": "rating",
       "outputPort": "rating",
       "outputType": "number",
       "selected": true,
       "label": "rating",
       "conversion": "strict"
      },
      {
       "sourceColumn": "author",
       "outputPort": "author",
       "outputType": "text",
       "selected": true,
       "label": "author",
       "conversion": "strict"
      },
      {
       "sourceColumn": "text",
       "outputPort": "text",
       "outputType": "text",
       "selected": true,
       "label": "text",
       "conversion": "strict"
      }
     ]
    }
   }
  },
  {
   "id": "brief",
   "type": "text/template",
   "label": "The review as a brief",
   "parameters": {
    "template": "Review by [author] on [source], [rating] stars:\n[text]",
    "placeholders": [
     {
      "name": "author",
      "inputPort": "author"
     },
     {
      "name": "source",
      "inputPort": "source"
     },
     {
      "name": "rating",
      "inputPort": "rating"
     },
     {
      "name": "text",
      "inputPort": "text"
     }
    ]
   }
  },
  {
   "id": "rating_text",
   "type": "text/format",
   "label": "Stars as text",
   "parameters": {
    "format": "auto"
   }
  },
  {
   "id": "read",
   "type": "ai/text_generation",
   "label": "Read the review",
   "parameters": {
    "system_prompt": "You read the guest reviews of Osteria Le Tre Lune, a family-run trattoria in Lucca, Tuscany, for its owner, Marta. Reviews come in any language. Answer with one JSON object and nothing else, with these keys:\n- language: the two-letter code of the language of the review\n- complaints: an object with the keys food, service, waiting, prices and atmosphere, each 1 if the guest complains about it and 0 if not. Waiting covers slow service and long gaps between courses; atmosphere covers noise, heat and comfort; service covers staff, bookings, bills and payments.\n- urgent: true only when the owner must act personally today: a guest's health, money charged wrongly, or a guest who asks to be contacted; otherwise false\n- summary: one sentence in English, at most 140 characters, of what the guest says\n- reply: the public reply of the osteria, in the language of the review, at most 600 characters. Thank the guest by first name and address them formally where the language has a polite form (Lei, Sie, vous, usted); answer the points they make, specifically; never promise refunds, discounts or free meals, and never invent facts. When urgent is true, apologise and ask the guest to write to ciao@letrelune.example so Marta can call them. Sign 'Marta, Osteria Le Tre Lune'.",
    "response_format": "json_object",
    "max_tokens": 2000
   }
  },
  {
   "id": "check",
   "type": "utility/json_schema_validate",
   "label": "Check the reading",
   "parameters": {
    "schema_source": "inline",
    "schema_definition": {
     "$schema": "https://json-schema.org/draft/2020-12/schema",
     "title": "One review, read",
     "type": "object",
     "additionalProperties": false,
     "required": [
      "language",
      "complaints",
      "urgent",
      "summary",
      "reply"
     ],
     "properties": {
      "language": {
       "type": "string",
       "pattern": "^[a-z]{2}$"
      },
      "complaints": {
       "type": "object",
       "additionalProperties": false,
       "required": [
        "food",
        "service",
        "waiting",
        "prices",
        "atmosphere"
       ],
       "properties": {
        "food": {
         "enum": [
          0,
          1
         ]
        },
        "service": {
         "enum": [
          0,
          1
         ]
        },
        "waiting": {
         "enum": [
          0,
          1
         ]
        },
        "prices": {
         "enum": [
          0,
          1
         ]
        },
        "atmosphere": {
         "enum": [
          0,
          1
         ]
        }
       }
      },
      "urgent": {
       "type": "boolean"
      },
      "summary": {
       "type": "string",
       "minLength": 10,
       "maxLength": 140
      },
      "reply": {
       "type": "string",
       "minLength": 40,
       "maxLength": 600
      }
     }
    },
    "mode": "fail"
   }
  },
  {
   "id": "language",
   "type": "utility/extract",
   "label": "Language",
   "parameters": {
    "path": "language",
    "expected_type": "text",
    "on_missing": "fail"
   }
  },
  {
   "id": "complaints",
   "type": "utility/extract",
   "label": "Complaints",
   "parameters": {
    "path": "complaints",
    "expected_type": "json",
    "on_missing": "fail"
   }
  },
  {
   "id": "urgent",
   "type": "utility/extract",
   "label": "Urgent",
   "parameters": {
    "path": "urgent",
    "expected_type": "boolean",
    "on_missing": "fail"
   }
  },
  {
   "id": "summary",
   "type": "utility/extract",
   "label": "Summary",
   "parameters": {
    "path": "summary",
    "expected_type": "text",
    "on_missing": "fail"
   }
  },
  {
   "id": "reply",
   "type": "utility/extract",
   "label": "Reply",
   "parameters": {
    "path": "reply",
    "expected_type": "text",
    "on_missing": "fail"
   }
  },
  {
   "id": "happy",
   "type": "utility/calculate",
   "label": "Happy (4–5 stars)",
   "parameters": {
    "expression": "if(rating >= 4, 1, 0)"
   }
  },
  {
   "id": "middle",
   "type": "utility/calculate",
   "label": "In between (3 stars)",
   "parameters": {
    "expression": "if(rating == 3, 1, 0)"
   }
  },
  {
   "id": "unhappy",
   "type": "utility/calculate",
   "label": "Unhappy (1–2 stars)",
   "parameters": {
    "expression": "if(rating <= 2, 1, 0)"
   }
  },
  {
   "id": "urgent_n",
   "type": "utility/calculate",
   "label": "Urgent as a number",
   "parameters": {
    "expression": "if(urgent, 1, 0)"
   }
  },
  {
   "id": "urgent_mark",
   "type": "text/format",
   "label": "Urgent as a mark",
   "parameters": {
    "format": "auto",
    "true_text": "URGENT",
    "false_text": "—"
   }
  },
  {
   "id": "month_json",
   "type": "aggregate/json",
   "label": "The month, review by review",
   "parameters": {
    "emptyBehavior": "fail",
    "jsonAggregateConfig": {
     "prettyPrint": true,
     "outputName": "reviews",
     "columns": [
      {
       "name": "review_id",
       "inputPort": "review_id",
       "type": "text"
      },
      {
       "name": "author",
       "inputPort": "author",
       "type": "text"
      },
      {
       "name": "source",
       "inputPort": "source",
       "type": "text"
      },
      {
       "name": "rating",
       "inputPort": "rating",
       "type": "number"
      },
      {
       "name": "text",
       "inputPort": "text",
       "type": "text"
      },
      {
       "name": "language",
       "inputPort": "language",
       "type": "text"
      },
      {
       "name": "summary",
       "inputPort": "summary",
       "type": "text"
      },
      {
       "name": "complaints",
       "inputPort": "complaints",
       "type": "json"
      },
      {
       "name": "happy",
       "inputPort": "happy",
       "type": "number"
      },
      {
       "name": "middle",
       "inputPort": "middle",
       "type": "number"
      },
      {
       "name": "unhappy",
       "inputPort": "unhappy",
       "type": "number"
      },
      {
       "name": "urgent",
       "inputPort": "urgent",
       "type": "number"
      }
     ]
    }
   }
  },
  {
   "id": "replies",
   "type": "aggregate/csv",
   "label": "Replies to send",
   "parameters": {
    "csvAggregateConfig": {
     "delimiter": ",",
     "quoteValues": true,
     "includeHeader": true,
     "encoding": "utf-8",
     "outputName": "replies",
     "columns": [
      {
       "name": "Review",
       "inputPort": "review_id",
       "type": "text"
      },
      {
       "name": "Guest",
       "inputPort": "author",
       "type": "text"
      },
      {
       "name": "Source",
       "inputPort": "source",
       "type": "text"
      },
      {
       "name": "Stars",
       "inputPort": "rating",
       "type": "number"
      },
      {
       "name": "Language",
       "inputPort": "language",
       "type": "text"
      },
      {
       "name": "Urgent",
       "inputPort": "urgent",
       "type": "text"
      },
      {
       "name": "Reply",
       "inputPort": "reply",
       "type": "text"
      }
     ]
    }
   }
  },
  {
   "id": "n_reviews",
   "type": "utility/calculate",
   "label": "Reviews",
   "parameters": {
    "expression": "count(month[*].rating)"
   }
  },
  {
   "id": "t_n_reviews",
   "type": "text/format",
   "label": "Reviews as text",
   "parameters": {
    "format": "number",
    "locale": "en-GB"
   }
  },
  {
   "id": "average",
   "type": "utility/calculate",
   "label": "Average stars",
   "parameters": {
    "expression": "avg(month[*].rating)",
    "decimals": 1
   }
  },
  {
   "id": "t_average",
   "type": "text/format",
   "label": "Average stars as text",
   "parameters": {
    "format": "number",
    "locale": "en-GB",
    "decimals": 1
   }
  },
  {
   "id": "n_happy",
   "type": "utility/calculate",
   "label": "Happy guests",
   "parameters": {
    "expression": "sum(month[*].happy)"
   }
  },
  {
   "id": "t_n_happy",
   "type": "text/format",
   "label": "Happy guests as text",
   "parameters": {
    "format": "number",
    "locale": "en-GB"
   }
  },
  {
   "id": "n_middle",
   "type": "utility/calculate",
   "label": "In between",
   "parameters": {
    "expression": "sum(month[*].middle)"
   }
  },
  {
   "id": "t_n_middle",
   "type": "text/format",
   "label": "In between as text",
   "parameters": {
    "format": "number",
    "locale": "en-GB"
   }
  },
  {
   "id": "n_unhappy",
   "type": "utility/calculate",
   "label": "Unhappy guests",
   "parameters": {
    "expression": "sum(month[*].unhappy)"
   }
  },
  {
   "id": "t_n_unhappy",
   "type": "text/format",
   "label": "Unhappy guests as text",
   "parameters": {
    "format": "number",
    "locale": "en-GB"
   }
  },
  {
   "id": "n_urgent",
   "type": "utility/calculate",
   "label": "Urgent",
   "parameters": {
    "expression": "sum(month[*].urgent)"
   }
  },
  {
   "id": "t_n_urgent",
   "type": "text/format",
   "label": "Urgent as text",
   "parameters": {
    "format": "number",
    "locale": "en-GB"
   }
  },
  {
   "id": "c_food",
   "type": "utility/calculate",
   "label": "Complaints: food",
   "parameters": {
    "expression": "sum(month[*].complaints.food)"
   }
  },
  {
   "id": "t_c_food",
   "type": "text/format",
   "label": "Complaints: food as text",
   "parameters": {
    "format": "number",
    "locale": "en-GB"
   }
  },
  {
   "id": "c_service",
   "type": "utility/calculate",
   "label": "Complaints: service",
   "parameters": {
    "expression": "sum(month[*].complaints.service)"
   }
  },
  {
   "id": "t_c_service",
   "type": "text/format",
   "label": "Complaints: service as text",
   "parameters": {
    "format": "number",
    "locale": "en-GB"
   }
  },
  {
   "id": "c_waiting",
   "type": "utility/calculate",
   "label": "Complaints: waiting",
   "parameters": {
    "expression": "sum(month[*].complaints.waiting)"
   }
  },
  {
   "id": "t_c_waiting",
   "type": "text/format",
   "label": "Complaints: waiting as text",
   "parameters": {
    "format": "number",
    "locale": "en-GB"
   }
  },
  {
   "id": "c_prices",
   "type": "utility/calculate",
   "label": "Complaints: prices",
   "parameters": {
    "expression": "sum(month[*].complaints.prices)"
   }
  },
  {
   "id": "t_c_prices",
   "type": "text/format",
   "label": "Complaints: prices as text",
   "parameters": {
    "format": "number",
    "locale": "en-GB"
   }
  },
  {
   "id": "c_atmosphere",
   "type": "utility/calculate",
   "label": "Complaints: atmosphere",
   "parameters": {
    "expression": "sum(month[*].complaints.atmosphere)"
   }
  },
  {
   "id": "t_c_atmosphere",
   "type": "text/format",
   "label": "Complaints: atmosphere as text",
   "parameters": {
    "format": "number",
    "locale": "en-GB"
   }
  },
  {
   "id": "byline",
   "type": "text/template",
   "label": "Byline",
   "parameters": {
    "template": "[n] reviews · [month] · average [avg] out of 5 · [u] urgent",
    "placeholders": [
     {
      "name": "n",
      "inputPort": "n"
     },
     {
      "name": "month",
      "inputPort": "month"
     },
     {
      "name": "avg",
      "inputPort": "avg"
     },
     {
      "name": "u",
      "inputPort": "u"
     }
    ]
   }
  },
  {
   "id": "step_1",
   "type": "text/template",
   "label": "Step 1",
   "parameters": {
    "template": "[n] happy guests · 4–5 stars",
    "placeholders": [
     {
      "name": "n",
      "inputPort": "n"
     }
    ]
   }
  },
  {
   "id": "step_2",
   "type": "text/template",
   "label": "Step 2",
   "parameters": {
    "template": "[n] in between · 3 stars",
    "placeholders": [
     {
      "name": "n",
      "inputPort": "n"
     }
    ]
   }
  },
  {
   "id": "step_3",
   "type": "text/template",
   "label": "Step 3",
   "parameters": {
    "template": "[n] unhappy · 1–2 stars",
    "placeholders": [
     {
      "name": "n",
      "inputPort": "n"
     }
    ]
   }
  },
  {
   "id": "theme_counts",
   "type": "text/template",
   "label": "Complaints by theme",
   "parameters": {
    "template": "Reviews with a complaint, by theme\nFood: [food]\nService: [service]\nWaiting: [waiting]\nPrices: [prices]\nAtmosphere: [atmosphere]",
    "placeholders": [
     {
      "name": "food",
      "inputPort": "food"
     },
     {
      "name": "service",
      "inputPort": "service"
     },
     {
      "name": "waiting",
      "inputPort": "waiting"
     },
     {
      "name": "prices",
      "inputPort": "prices"
     },
     {
      "name": "atmosphere",
      "inputPort": "atmosphere"
     }
    ]
   }
  },
  {
   "id": "month_text",
   "type": "text/format",
   "label": "The month as text",
   "parameters": {
    "format": "json",
    "json_style": "compact"
   }
  },
  {
   "id": "report_brief",
   "type": "text/template",
   "label": "Brief for the report",
   "parameters": {
    "template": "Complaints by theme this month (counted, not to be repeated as figures):\n[themes]\n\nThe reviews, as JSON (review_id, author, source, rating, text, language, summary, complaints, urgent):\n[reviews]",
    "placeholders": [
     {
      "name": "themes",
      "inputPort": "themes"
     },
     {
      "name": "reviews",
      "inputPort": "reviews"
     }
    ]
   }
  },
  {
   "id": "write",
   "type": "ai/text_generation",
   "label": "Write the page",
   "parameters": {
    "system_prompt": "You write the one-page monthly review report of Osteria Le Tre Lune, a family-run trattoria in Lucca, for its owner and staff. You receive every review of the month and how many complain about each theme.\n\nRules:\n- Write in English, clear and concrete, as a good manager would; no hype, no exclamation marks.\n- Never write how many guests or reviews say something, neither in figures nor in words ('one', 'three', 'half'): the page prints the figures, counted by the system. Write 'some guests' or 'many guests' instead.\n- Use only what the reviews say; never invent facts, names or events.\n- Keep strictly within the character limits below: they are the space on the printed page.\n\nReturn one JSON object and nothing else:\n- \"big_idea\": 40 to 130 characters: the month in one sentence, what guests love and what costs the osteria its stars.\n- \"key_ideas\": 4 or 5 objects, the most important first, each with \"tag\" (at most 16 characters: the theme), \"title\" (at most 40 characters) and \"text\" (60 to 118 characters) saying what guests say about it.\n- \"actions\": exactly 3 objects with \"text\" (20 to 80 characters): what the team should do this week, the most urgent first; a guest whose health or money is at stake comes before anything else.\n- \"quote_original\": one sentence copied exactly, character for character, from the text of one review that captures why guests come, in its original language, at most 120 characters.\n- \"quote_translation\": its English translation, at most 120 characters.\n- \"quote_source\": the guest's name, the source and the stars, such as 'Hans M. · Google · 5 stars'.\n- \"illustration_prompt\": in English, at most 600 characters, for an image model: a square editorial illustration of a Tuscan trattoria table at dusk, with a dish the reviews praise, flat shapes with soft grain, a limited palette of deep navy, terracotta, sand and warm cream, plenty of calm space, full bleed to every edge with no border or frame, no people, no text, no letters, no logos.",
    "response_format": "json_object",
    "max_tokens": 4000
   }
  },
  {
   "id": "page_check",
   "type": "utility/json_schema_validate",
   "label": "The words fit the page",
   "parameters": {
    "schema_source": "inline",
    "schema_definition": {
     "$schema": "https://json-schema.org/draft/2020-12/schema",
     "title": "The words of the report page",
     "type": "object",
     "additionalProperties": false,
     "required": [
      "big_idea",
      "key_ideas",
      "actions",
      "quote_original",
      "quote_translation",
      "quote_source",
      "illustration_prompt"
     ],
     "properties": {
      "big_idea": {
       "type": "string",
       "minLength": 40,
       "maxLength": 150,
       "pattern": "^[^0-9]*$"
      },
      "key_ideas": {
       "type": "array",
       "minItems": 4,
       "maxItems": 5,
       "items": {
        "type": "object",
        "additionalProperties": false,
        "required": [
         "tag",
         "title",
         "text"
        ],
        "properties": {
         "tag": {
          "type": "string",
          "minLength": 3,
          "maxLength": 18,
          "pattern": "^[^0-9]*$"
         },
         "title": {
          "type": "string",
          "minLength": 10,
          "maxLength": 44,
          "pattern": "^[^0-9]*$"
         },
         "text": {
          "type": "string",
          "minLength": 50,
          "maxLength": 130,
          "pattern": "^[^0-9]*$"
         }
        }
       }
      },
      "actions": {
       "type": "array",
       "minItems": 3,
       "maxItems": 3,
       "items": {
        "type": "object",
        "additionalProperties": false,
        "required": [
         "text"
        ],
        "properties": {
         "text": {
          "type": "string",
          "minLength": 20,
          "maxLength": 90,
          "pattern": "^[^0-9]*$"
         }
        }
       }
      },
      "quote_original": {
       "type": "string",
       "minLength": 10,
       "maxLength": 130
      },
      "quote_translation": {
       "type": "string",
       "minLength": 10,
       "maxLength": 130
      },
      "quote_source": {
       "type": "string",
       "minLength": 5,
       "maxLength": 60
      },
      "illustration_prompt": {
       "type": "string",
       "minLength": 80,
       "maxLength": 600
      }
     }
    },
    "mode": "fail"
   }
  },
  {
   "id": "quote",
   "type": "utility/extract",
   "label": "The quotation",
   "parameters": {
    "path": "quote_original",
    "expected_type": "text",
    "on_missing": "fail"
   }
  },
  {
   "id": "quote_found",
   "type": "text/replace",
   "label": "Is the quotation in the reviews?",
   "parameters": {
    "case_sensitive": true
   }
  },
  {
   "id": "quote_ok",
   "type": "utility/predicate",
   "label": "Quotation found at least once",
   "parameters": {
    "operation": "greater_or_equal",
    "compare_number": 1
   }
  },
  {
   "id": "page_words",
   "type": "utility/filter",
   "label": "Only a verified page goes to print",
   "parameters": {
    "invert": false
   }
  },
  {
   "id": "illustration_prompt",
   "type": "utility/extract",
   "label": "Illustration prompt",
   "parameters": {
    "path": "illustration_prompt",
    "expected_type": "text",
    "on_missing": "fail"
   }
  },
  {
   "id": "illustration",
   "type": "ai/text_to_image",
   "label": "Paint the illustration",
   "parameters": {
    "aspect_ratio": "1_1",
    "variants": 1
   }
  },
  {
   "id": "render",
   "type": "design/template_render",
   "label": "Render the report",
   "parameters": {
    "template_id": "__TEMPLATE_ID__",
    "template_revision": "__TEMPLATE_REVISION__",
    "output": "both",
    "page_selection": "all",
    "missing_policy": "fail_required",
    "overflow_policy": "template",
    "max_repeat": 6
   }
  },
  {
   "id": "o_pdf",
   "type": "output/pdf",
   "label": "Report PDF",
   "parameters": {
    "output_name": "report_pdf"
   }
  },
  {
   "id": "o_img",
   "type": "output/image",
   "label": "Report image",
   "parameters": {
    "output_name": "report_image"
   }
  },
  {
   "id": "o_replies",
   "type": "output/csv",
   "label": "Replies",
   "parameters": {
    "output_name": "replies"
   }
  },
  {
   "id": "o_month",
   "type": "output/json",
   "label": "The month, review by review",
   "parameters": {
    "output_name": "reviews"
   }
  },
  {
   "id": "o_themes",
   "type": "output/text",
   "label": "Complaints by theme",
   "parameters": {
    "output_name": "complaints_by_theme"
   }
  },
  {
   "id": "o_quote",
   "type": "output/json",
   "label": "Quotation found",
   "parameters": {
    "output_name": "quotation_found"
   }
  },
  {
   "id": "o_layout",
   "type": "output/json",
   "label": "Layout report",
   "parameters": {
    "output_name": "layout_report"
   }
  }
 ],
 "connections": [
  {
   "from_node": "reviews",
   "from_output": "dataset",
   "to_node": "each",
   "to_input": "dataset"
  },
  {
   "from_node": "each",
   "from_output": "author",
   "to_node": "brief",
   "to_input": "author"
  },
  {
   "from_node": "each",
   "from_output": "source",
   "to_node": "brief",
   "to_input": "source"
  },
  {
   "from_node": "each",
   "from_output": "text",
   "to_node": "brief",
   "to_input": "text"
  },
  {
   "from_node": "each",
   "from_output": "rating",
   "to_node": "rating_text",
   "to_input": "value"
  },
  {
   "from_node": "rating_text",
   "from_output": "text",
   "to_node": "brief",
   "to_input": "rating"
  },
  {
   "from_node": "brief",
   "from_output": "result",
   "to_node": "read",
   "to_input": "prompt"
  },
  {
   "from_node": "read",
   "from_output": "json",
   "to_node": "check",
   "to_input": "document"
  },
  {
   "from_node": "check",
   "from_output": "normalized_json",
   "to_node": "language",
   "to_input": "json"
  },
  {
   "from_node": "check",
   "from_output": "normalized_json",
   "to_node": "complaints",
   "to_input": "json"
  },
  {
   "from_node": "check",
   "from_output": "normalized_json",
   "to_node": "urgent",
   "to_input": "json"
  },
  {
   "from_node": "check",
   "from_output": "normalized_json",
   "to_node": "summary",
   "to_input": "json"
  },
  {
   "from_node": "check",
   "from_output": "normalized_json",
   "to_node": "reply",
   "to_input": "json"
  },
  {
   "from_node": "each",
   "from_output": "rating",
   "to_node": "happy",
   "to_input": "rating"
  },
  {
   "from_node": "each",
   "from_output": "rating",
   "to_node": "middle",
   "to_input": "rating"
  },
  {
   "from_node": "each",
   "from_output": "rating",
   "to_node": "unhappy",
   "to_input": "rating"
  },
  {
   "from_node": "urgent",
   "from_output": "value",
   "to_node": "urgent_n",
   "to_input": "urgent"
  },
  {
   "from_node": "urgent",
   "from_output": "value",
   "to_node": "urgent_mark",
   "to_input": "value"
  },
  {
   "from_node": "each",
   "from_output": "review_id",
   "to_node": "month_json",
   "to_input": "review_id"
  },
  {
   "from_node": "each",
   "from_output": "author",
   "to_node": "month_json",
   "to_input": "author"
  },
  {
   "from_node": "each",
   "from_output": "source",
   "to_node": "month_json",
   "to_input": "source"
  },
  {
   "from_node": "each",
   "from_output": "rating",
   "to_node": "month_json",
   "to_input": "rating"
  },
  {
   "from_node": "each",
   "from_output": "text",
   "to_node": "month_json",
   "to_input": "text"
  },
  {
   "from_node": "language",
   "from_output": "value",
   "to_node": "month_json",
   "to_input": "language"
  },
  {
   "from_node": "summary",
   "from_output": "value",
   "to_node": "month_json",
   "to_input": "summary"
  },
  {
   "from_node": "complaints",
   "from_output": "value",
   "to_node": "month_json",
   "to_input": "complaints"
  },
  {
   "from_node": "happy",
   "from_output": "result",
   "to_node": "month_json",
   "to_input": "happy"
  },
  {
   "from_node": "middle",
   "from_output": "result",
   "to_node": "month_json",
   "to_input": "middle"
  },
  {
   "from_node": "unhappy",
   "from_output": "result",
   "to_node": "month_json",
   "to_input": "unhappy"
  },
  {
   "from_node": "urgent_n",
   "from_output": "result",
   "to_node": "month_json",
   "to_input": "urgent"
  },
  {
   "from_node": "each",
   "from_output": "review_id",
   "to_node": "replies",
   "to_input": "review_id"
  },
  {
   "from_node": "each",
   "from_output": "author",
   "to_node": "replies",
   "to_input": "author"
  },
  {
   "from_node": "each",
   "from_output": "source",
   "to_node": "replies",
   "to_input": "source"
  },
  {
   "from_node": "each",
   "from_output": "rating",
   "to_node": "replies",
   "to_input": "rating"
  },
  {
   "from_node": "language",
   "from_output": "value",
   "to_node": "replies",
   "to_input": "language"
  },
  {
   "from_node": "urgent_mark",
   "from_output": "text",
   "to_node": "replies",
   "to_input": "urgent"
  },
  {
   "from_node": "reply",
   "from_output": "value",
   "to_node": "replies",
   "to_input": "reply"
  },
  {
   "from_node": "month_json",
   "from_output": "result",
   "to_node": "n_reviews",
   "to_input": "month"
  },
  {
   "from_node": "n_reviews",
   "from_output": "result",
   "to_node": "t_n_reviews",
   "to_input": "value"
  },
  {
   "from_node": "month_json",
   "from_output": "result",
   "to_node": "average",
   "to_input": "month"
  },
  {
   "from_node": "average",
   "from_output": "result",
   "to_node": "t_average",
   "to_input": "value"
  },
  {
   "from_node": "month_json",
   "from_output": "result",
   "to_node": "n_happy",
   "to_input": "month"
  },
  {
   "from_node": "n_happy",
   "from_output": "result",
   "to_node": "t_n_happy",
   "to_input": "value"
  },
  {
   "from_node": "month_json",
   "from_output": "result",
   "to_node": "n_middle",
   "to_input": "month"
  },
  {
   "from_node": "n_middle",
   "from_output": "result",
   "to_node": "t_n_middle",
   "to_input": "value"
  },
  {
   "from_node": "month_json",
   "from_output": "result",
   "to_node": "n_unhappy",
   "to_input": "month"
  },
  {
   "from_node": "n_unhappy",
   "from_output": "result",
   "to_node": "t_n_unhappy",
   "to_input": "value"
  },
  {
   "from_node": "month_json",
   "from_output": "result",
   "to_node": "n_urgent",
   "to_input": "month"
  },
  {
   "from_node": "n_urgent",
   "from_output": "result",
   "to_node": "t_n_urgent",
   "to_input": "value"
  },
  {
   "from_node": "month_json",
   "from_output": "result",
   "to_node": "c_food",
   "to_input": "month"
  },
  {
   "from_node": "c_food",
   "from_output": "result",
   "to_node": "t_c_food",
   "to_input": "value"
  },
  {
   "from_node": "month_json",
   "from_output": "result",
   "to_node": "c_service",
   "to_input": "month"
  },
  {
   "from_node": "c_service",
   "from_output": "result",
   "to_node": "t_c_service",
   "to_input": "value"
  },
  {
   "from_node": "month_json",
   "from_output": "result",
   "to_node": "c_waiting",
   "to_input": "month"
  },
  {
   "from_node": "c_waiting",
   "from_output": "result",
   "to_node": "t_c_waiting",
   "to_input": "value"
  },
  {
   "from_node": "month_json",
   "from_output": "result",
   "to_node": "c_prices",
   "to_input": "month"
  },
  {
   "from_node": "c_prices",
   "from_output": "result",
   "to_node": "t_c_prices",
   "to_input": "value"
  },
  {
   "from_node": "month_json",
   "from_output": "result",
   "to_node": "c_atmosphere",
   "to_input": "month"
  },
  {
   "from_node": "c_atmosphere",
   "from_output": "result",
   "to_node": "t_c_atmosphere",
   "to_input": "value"
  },
  {
   "from_node": "t_n_reviews",
   "from_output": "text",
   "to_node": "byline",
   "to_input": "n"
  },
  {
   "from_node": "month",
   "from_output": "text",
   "to_node": "byline",
   "to_input": "month"
  },
  {
   "from_node": "t_average",
   "from_output": "text",
   "to_node": "byline",
   "to_input": "avg"
  },
  {
   "from_node": "t_n_urgent",
   "from_output": "text",
   "to_node": "byline",
   "to_input": "u"
  },
  {
   "from_node": "t_n_happy",
   "from_output": "text",
   "to_node": "step_1",
   "to_input": "n"
  },
  {
   "from_node": "t_n_middle",
   "from_output": "text",
   "to_node": "step_2",
   "to_input": "n"
  },
  {
   "from_node": "t_n_unhappy",
   "from_output": "text",
   "to_node": "step_3",
   "to_input": "n"
  },
  {
   "from_node": "t_c_food",
   "from_output": "text",
   "to_node": "theme_counts",
   "to_input": "food"
  },
  {
   "from_node": "t_c_service",
   "from_output": "text",
   "to_node": "theme_counts",
   "to_input": "service"
  },
  {
   "from_node": "t_c_waiting",
   "from_output": "text",
   "to_node": "theme_counts",
   "to_input": "waiting"
  },
  {
   "from_node": "t_c_prices",
   "from_output": "text",
   "to_node": "theme_counts",
   "to_input": "prices"
  },
  {
   "from_node": "t_c_atmosphere",
   "from_output": "text",
   "to_node": "theme_counts",
   "to_input": "atmosphere"
  },
  {
   "from_node": "month_json",
   "from_output": "result",
   "to_node": "month_text",
   "to_input": "value"
  },
  {
   "from_node": "theme_counts",
   "from_output": "result",
   "to_node": "report_brief",
   "to_input": "themes"
  },
  {
   "from_node": "month_text",
   "from_output": "text",
   "to_node": "report_brief",
   "to_input": "reviews"
  },
  {
   "from_node": "report_brief",
   "from_output": "result",
   "to_node": "write",
   "to_input": "prompt"
  },
  {
   "from_node": "write",
   "from_output": "json",
   "to_node": "page_check",
   "to_input": "document"
  },
  {
   "from_node": "page_check",
   "from_output": "normalized_json",
   "to_node": "quote",
   "to_input": "json"
  },
  {
   "from_node": "month_text",
   "from_output": "text",
   "to_node": "quote_found",
   "to_input": "text"
  },
  {
   "from_node": "quote",
   "from_output": "value",
   "to_node": "quote_found",
   "to_input": "find"
  },
  {
   "from_node": "quote",
   "from_output": "value",
   "to_node": "quote_found",
   "to_input": "replace"
  },
  {
   "from_node": "quote_found",
   "from_output": "count",
   "to_node": "quote_ok",
   "to_input": "a"
  },
  {
   "from_node": "quote_ok",
   "from_output": "result",
   "to_node": "page_words",
   "to_input": "condition"
  },
  {
   "from_node": "page_check",
   "from_output": "normalized_json",
   "to_node": "page_words",
   "to_input": "value"
  },
  {
   "from_node": "page_words",
   "from_output": "value",
   "to_node": "illustration_prompt",
   "to_input": "json"
  },
  {
   "from_node": "illustration_prompt",
   "from_output": "value",
   "to_node": "illustration",
   "to_input": "prompt"
  },
  {
   "from_node": "page_words",
   "from_output": "value",
   "to_node": "render",
   "to_input": "data_0"
  },
  {
   "from_node": "osteria",
   "from_output": "text",
   "to_node": "render",
   "to_input": "title"
  },
  {
   "from_node": "byline",
   "from_output": "result",
   "to_node": "render",
   "to_input": "byline"
  },
  {
   "from_node": "step_1",
   "from_output": "result",
   "to_node": "render",
   "to_input": "step_1"
  },
  {
   "from_node": "step_2",
   "from_output": "result",
   "to_node": "render",
   "to_input": "step_2"
  },
  {
   "from_node": "step_3",
   "from_output": "result",
   "to_node": "render",
   "to_input": "step_3"
  },
  {
   "from_node": "reviews_page",
   "from_output": "text",
   "to_node": "render",
   "to_input": "source_url"
  },
  {
   "from_node": "illustration",
   "from_output": "result",
   "to_node": "render",
   "to_input": "illustration"
  },
  {
   "from_node": "render",
   "from_output": "pdf",
   "to_node": "o_pdf",
   "to_input": "pdf"
  },
  {
   "from_node": "render",
   "from_output": "image",
   "to_node": "o_img",
   "to_input": "image"
  },
  {
   "from_node": "replies",
   "from_output": "result",
   "to_node": "o_replies",
   "to_input": "csv"
  },
  {
   "from_node": "month_json",
   "from_output": "result",
   "to_node": "o_month",
   "to_input": "json"
  },
  {
   "from_node": "theme_counts",
   "from_output": "result",
   "to_node": "o_themes",
   "to_input": "text"
  },
  {
   "from_node": "quote_found",
   "from_output": "count",
   "to_node": "o_quote",
   "to_input": "json"
  },
  {
   "from_node": "render",
   "from_output": "layout_report",
   "to_node": "o_layout",
   "to_input": "json"
  }
 ]
}