{
 "schema_version": "1.0",
 "nodes": [
  {
   "id": "person",
   "type": "input/image",
   "label": "Person",
   "parameters": {
    "image": "__MODEL__",
    "required": true
   }
  },
  {
   "id": "brief",
   "type": "input/text",
   "label": "Brief",
   "parameters": {
    "text": "",
    "multiline": true,
    "required": true
   }
  },
  {
   "id": "role",
   "type": "input/text",
   "label": "Role",
   "parameters": {
    "text": "",
    "required": true
   }
  },
  {
   "id": "attempt_number",
   "type": "input/number",
   "label": "Attempt number",
   "parameters": {
    "required": true
   }
  },
  {
   "id": "previous_feedback",
   "type": "input/text",
   "label": "Previous feedback",
   "parameters": {
    "text": "",
    "multiline": true,
    "required": false
   }
  },
  {
   "id": "prompt",
   "type": "text/expression",
   "label": "Prompt",
   "parameters": {
    "expression": "{{ brief }} Keep the woman of the reference photo exactly as she is: her face, her skin, her dark shoulder-length hair, her build. Photorealistic, natural light."
   }
  },
  {
   "id": "make",
   "type": "ai/image_transform",
   "label": "Campaign picture",
   "parameters": {
    "aspect_ratio": "4:5"
   }
  },
  {
   "id": "find",
   "type": "ai/locate_subject",
   "label": "Find her",
   "parameters": {
    "margin": 0.04
   }
  },
  {
   "id": "face",
   "type": "image/face_detect",
   "label": "Her face",
   "parameters": {
    "framing": "head",
    "aspect": "1:1"
   }
  },
  {
   "id": "cut",
   "type": "image/crop",
   "label": "Cut her face",
   "parameters": {
    "x": 0,
    "y": 0,
    "width": 8192,
    "height": 8192,
    "on_out_of_bounds": "clip"
   }
  },
  {
   "id": "ref_face",
   "type": "image/face_detect",
   "label": "Reference face",
   "parameters": {
    "framing": "head",
    "aspect": "1:1"
   }
  },
  {
   "id": "ref_cut",
   "type": "image/crop",
   "label": "Cut the reference face",
   "parameters": {
    "x": 0,
    "y": 0,
    "width": 8192,
    "height": 8192,
    "on_out_of_bounds": "clip"
   }
  },
  {
   "id": "rate",
   "type": "ai/image_analysis",
   "label": "Rate her face",
   "parameters": {
    "prompt": "Picture 1 is a face from a generated photograph; Picture 2 is the reference face of the same character, who must look the same in every picture. Rate, from 0 to 10, how well Picture 1 keeps each of these of Picture 2 (10 = identical, 0 = clearly different), ignoring expression, angle, light and image quality:\n- features: the shape of the face, the eyes, eyebrows, nose, lips and jaw;\n- skin: freckles, moles, wrinkles and marks — none added, none missing;\n- hair: colour, length and style.\nAnswer with one JSON object only: {\"features\": n, \"skin\": n, \"hair\": n, \"differences\": \"what differs, in a few words, or none\"}.",
    "response_format": "json_object",
    "temperature": 0,
    "max_tokens": 1024
   }
  },
  {
   "id": "ok",
   "type": "utility/calculate",
   "label": "Accepted (1 or 0)",
   "parameters": {
    "expression": "if(found, min(if(rating.features >= 6, 1, 0), if(rating.skin >= 5, 1, 0), if(rating.hair >= 3, 1, 0)), 0)"
   }
  },
  {
   "id": "accepted",
   "type": "utility/predicate",
   "label": "Accepted?",
   "parameters": {
    "operation": "equals",
    "compare_number": 1
   }
  },
  {
   "id": "grade",
   "type": "utility/calculate",
   "label": "Score",
   "parameters": {
    "expression": "if(found, round((rating.features + rating.skin + rating.hair) / 30, 3), 0)"
   }
  },
  {
   "id": "why",
   "type": "text/expression",
   "label": "Correction",
   "parameters": {
    "expression": "{{ if !found }}The woman of the reference photo is not in the picture: she must be {{ role }}.{{ else if rating.differences == \"none\" }}She matches the reference.{{ else }}Keep her face, her skin and her hair exactly as in the reference photo. What differed: {{ rating.differences }}{{ end }}"
   }
  },
  {
   "id": "o_cand",
   "type": "output/image",
   "label": "candidate",
   "parameters": {
    "output_name": "candidate"
   }
  },
  {
   "id": "o_acc",
   "type": "output/json",
   "label": "accepted",
   "parameters": {
    "output_name": "accepted"
   }
  },
  {
   "id": "o_score",
   "type": "output/json",
   "label": "score",
   "parameters": {
    "output_name": "score"
   }
  },
  {
   "id": "o_fb",
   "type": "output/text",
   "label": "feedback",
   "parameters": {
    "output_name": "feedback"
   }
  }
 ],
 "connections": [
  {
   "from_node": "brief",
   "from_output": "text",
   "to_node": "prompt",
   "to_input": "brief"
  },
  {
   "from_node": "person",
   "from_output": "image",
   "to_node": "make",
   "to_input": "images"
  },
  {
   "from_node": "prompt",
   "from_output": "text",
   "to_node": "make",
   "to_input": "prompt"
  },
  {
   "from_node": "previous_feedback",
   "from_output": "text",
   "to_node": "make",
   "to_input": "instructions"
  },
  {
   "from_node": "make",
   "from_output": "result",
   "to_node": "find",
   "to_input": "image"
  },
  {
   "from_node": "person",
   "from_output": "image",
   "to_node": "find",
   "to_input": "references"
  },
  {
   "from_node": "role",
   "from_output": "text",
   "to_node": "find",
   "to_input": "description"
  },
  {
   "from_node": "find",
   "from_output": "crop",
   "to_node": "face",
   "to_input": "image"
  },
  {
   "from_node": "find",
   "from_output": "crop",
   "to_node": "cut",
   "to_input": "image"
  },
  {
   "from_node": "face",
   "from_output": "crop_region",
   "to_node": "cut",
   "to_input": "region"
  },
  {
   "from_node": "person",
   "from_output": "image",
   "to_node": "ref_face",
   "to_input": "image"
  },
  {
   "from_node": "person",
   "from_output": "image",
   "to_node": "ref_cut",
   "to_input": "image"
  },
  {
   "from_node": "ref_face",
   "from_output": "crop_region",
   "to_node": "ref_cut",
   "to_input": "region"
  },
  {
   "from_node": "cut",
   "from_output": "result",
   "to_node": "rate",
   "to_input": "images"
  },
  {
   "from_node": "ref_cut",
   "from_output": "result",
   "to_node": "rate",
   "to_input": "images"
  },
  {
   "from_node": "rate",
   "from_output": "json",
   "to_node": "ok",
   "to_input": "rating"
  },
  {
   "from_node": "find",
   "from_output": "found",
   "to_node": "ok",
   "to_input": "found"
  },
  {
   "from_node": "ok",
   "from_output": "result",
   "to_node": "accepted",
   "to_input": "a"
  },
  {
   "from_node": "rate",
   "from_output": "json",
   "to_node": "grade",
   "to_input": "rating"
  },
  {
   "from_node": "find",
   "from_output": "found",
   "to_node": "grade",
   "to_input": "found"
  },
  {
   "from_node": "rate",
   "from_output": "json",
   "to_node": "why",
   "to_input": "rating"
  },
  {
   "from_node": "find",
   "from_output": "found",
   "to_node": "why",
   "to_input": "found"
  },
  {
   "from_node": "role",
   "from_output": "text",
   "to_node": "why",
   "to_input": "role"
  },
  {
   "from_node": "make",
   "from_output": "result",
   "to_node": "o_cand",
   "to_input": "image"
  },
  {
   "from_node": "accepted",
   "from_output": "result",
   "to_node": "o_acc",
   "to_input": "json"
  },
  {
   "from_node": "grade",
   "from_output": "result",
   "to_node": "o_score",
   "to_input": "json"
  },
  {
   "from_node": "why",
   "from_output": "text",
   "to_node": "o_fb",
   "to_input": "text"
  }
 ],
 "layout": {
  "nodes": {
   "person": {
    "x": 80,
    "y": 80
   },
   "brief": {
    "x": 80,
    "y": 280
   },
   "role": {
    "x": 80,
    "y": 480
   },
   "attempt_number": {
    "x": 80,
    "y": 680
   },
   "previous_feedback": {
    "x": 80,
    "y": 880
   },
   "prompt": {
    "x": 420,
    "y": 80
   },
   "make": {
    "x": 760,
    "y": 80
   },
   "find": {
    "x": 1100,
    "y": 80
   },
   "face": {
    "x": 1440,
    "y": 80
   },
   "cut": {
    "x": 1780,
    "y": 80
   },
   "ref_face": {
    "x": 420,
    "y": 280
   },
   "ref_cut": {
    "x": 760,
    "y": 280
   },
   "rate": {
    "x": 2120,
    "y": 80
   },
   "ok": {
    "x": 2460,
    "y": 80
   },
   "accepted": {
    "x": 2800,
    "y": 80
   },
   "grade": {
    "x": 2460,
    "y": 280
   },
   "why": {
    "x": 2460,
    "y": 480
   },
   "o_cand": {
    "x": 1100,
    "y": 280
   },
   "o_acc": {
    "x": 3140,
    "y": 80
   },
   "o_score": {
    "x": 2800,
    "y": 280
   },
   "o_fb": {
    "x": 2800,
    "y": 480
   }
  }
 }
}
