{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ikIep-HBcvvC"
      },
      "outputs": [],
      "source": [
        "# Copyright 2026 Google LLC\n",
        "#\n",
        "# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "#     https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Qw6ttkOtrQ_D"
      },
      "source": [
        "# Gemini 3.1 Flash Image (Nano Banana 2 🍌) Generation\n",
        "\n",
        "<table align=\"left\">\n",
        "  <td style=\"text-align: center\">\n",
        "    <a href=\"https://colab.research.google.com/github/GoogleCloudPlatform/generative-ai/blob/main/gemini/getting-started/intro_gemini_3_1_flash_image_gen.ipynb\">\n",
        "      <img width=\"32px\" src=\"https://www.gstatic.com/pantheon/images/bigquery/welcome_page/colab-logo.svg\" alt=\"Google Colaboratory logo\"><br> Open in Colab\n",
        "    </a>\n",
        "  </td>\n",
        "  <td style=\"text-align: center\">\n",
        "    <a href=\"https://console.cloud.google.com/agent-platform/colab/import/https:%2F%2Fraw.githubusercontent.com%2FGoogleCloudPlatform%2Fgenerative-ai%2Fmain%2Fgemini%2Fgetting-started%2Fintro_gemini_3_1_flash_image_gen.ipynb\">\n",
        "      <img width=\"32px\" src=\"https://lh3.googleusercontent.com/JmcxdQi-qOpctIvWKgPtrzZdJJK-J3sWE1RsfjZNwshCFgE_9fULcNpuXYTilIR2hjwN\" alt=\"Google Cloud Colab Enterprise logo\"><br> Open in Colab Enterprise\n",
        "    </a>\n",
        "  </td>\n",
        "  <td style=\"text-align: center\">\n",
        "    <a href=\"https://console.cloud.google.com/agent-platform/workbench/instances?download_url=https://raw.githubusercontent.com/GoogleCloudPlatform/generative-ai/main/gemini/getting-started/intro_gemini_3_1_flash_image_gen.ipynb\">\n",
        "      <img width=\"32px\" src=\"https://storage.googleapis.com/github-repo/workbench-icon.svg\" alt=\"Workbench logo\"><br> Open in Workbench\n",
        "    </a>\n",
        "  </td>\n",
        "  <td style=\"text-align: center\">\n",
        "    <a href=\"https://github.com/GoogleCloudPlatform/generative-ai/blob/main/gemini/getting-started/intro_gemini_3_1_flash_image_gen.ipynb\">\n",
        "      <img width=\"32px\" src=\"https://raw.githubusercontent.com/primer/octicons/refs/heads/main/icons/mark-github-24.svg\" alt=\"GitHub logo\"><br> View on GitHub\n",
        "    </a>\n",
        "  </td>\n",
        "</table>\n",
        "\n",
        "<div style=\"clear: both;\"></div>\n",
        "\n",
        "<p>\n",
        "<b>Share to:</b>\n",
        "\n",
        "<a href=\"https://www.linkedin.com/sharing/share-offsite/?url=https%3A//github.com/GoogleCloudPlatform/generative-ai/blob/main/gemini/getting-started/intro_gemini_3_1_flash_image_gen.ipynb\" target=\"_blank\">\n",
        "  <img width=\"20px\" src=\"https://upload.wikimedia.org/wikipedia/commons/8/81/LinkedIn_icon.svg\" alt=\"LinkedIn logo\">\n",
        "</a>\n",
        "\n",
        "<a href=\"https://bsky.app/intent/compose?text=https%3A//github.com/GoogleCloudPlatform/generative-ai/blob/main/gemini/getting-started/intro_gemini_3_1_flash_image_gen.ipynb\" target=\"_blank\">\n",
        "  <img width=\"20px\" src=\"https://upload.wikimedia.org/wikipedia/commons/7/7a/Bluesky_Logo.svg\" alt=\"Bluesky logo\">\n",
        "</a>\n",
        "\n",
        "<a href=\"https://twitter.com/intent/tweet?url=https%3A//github.com/GoogleCloudPlatform/generative-ai/blob/main/gemini/getting-started/intro_gemini_3_1_flash_image_gen.ipynb\" target=\"_blank\">\n",
        "  <img width=\"20px\" src=\"https://upload.wikimedia.org/wikipedia/commons/5/5a/X_icon_2.svg\" alt=\"X logo\">\n",
        "</a>\n",
        "\n",
        "<a href=\"https://reddit.com/submit?url=https%3A//github.com/GoogleCloudPlatform/generative-ai/blob/main/gemini/getting-started/intro_gemini_3_1_flash_image_gen.ipynb\" target=\"_blank\">\n",
        "  <img width=\"20px\" src=\"https://redditinc.com/hubfs/Reddit%20Inc/Brand/Reddit_Logo.png\" alt=\"Reddit logo\">\n",
        "</a>\n",
        "\n",
        "<a href=\"https://www.facebook.com/sharer/sharer.php?u=https%3A//github.com/GoogleCloudPlatform/generative-ai/blob/main/gemini/getting-started/intro_gemini_3_1_flash_image_gen.ipynb\" target=\"_blank\">\n",
        "  <img width=\"20px\" src=\"https://upload.wikimedia.org/wikipedia/commons/5/51/Facebook_f_logo_%282019%29.svg\" alt=\"Facebook logo\">\n",
        "</a>\n",
        "</p>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "uDN8B4CBdMNs"
      },
      "source": [
        "| Author |\n",
        "| --- |\n",
        "| [Katie Nguyen](https://github.com/katiemn) |"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "b0e4d036833c"
      },
      "source": [
        "## Overview\n",
        "This notebook will show you how to use the Gemini 3.1 Flash Image (Nano Banana 2) image model. This model is a powerful, generalist multimodal model that offers state-of-the-art image generation and conversational image editing capabilities. It's also able to show its work, allowing you to set the thinking level and see the 'thought process' behind the generated output.\n",
        "\n",
        "In this tutorial, you'll learn how to use gemini-3.1-flash-image on Agent Platform using the Google Gen AI SDK to try out the following scenarios:\n",
        "\n",
        "- Image generation:\n",
        "  - Text-to-image generation\n",
        "  - Model thoughts\n",
        "  - Prominent people filter\n",
        "  - Grounding with web and image search\n",
        "  - Image sizing\n",
        "  - Video-to-image generation\n",
        "- Image editing:\n",
        "  - Localization\n",
        "  - Multi-turn image editing (chat)\n",
        "  - Editing with reference images"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Mfk6YY3G5kqp"
      },
      "source": [
        "## Get started"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "uJqUEH_mg6kb"
      },
      "source": [
        "### Install Google Gen AI SDK for Python\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "-VBT2jIXLD7h"
      },
      "outputs": [],
      "source": [
        "%pip install --upgrade --quiet google-genai"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "eLIrxLFihSoE"
      },
      "source": [
        "### Authenticate your notebook environment (Colab only)\n",
        "\n",
        "If you are running this notebook on Google Colab, run the following cell to authenticate your environment."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {
        "id": "hP-_lnBZhUjZ"
      },
      "outputs": [],
      "source": [
        "import sys\n",
        "\n",
        "if \"google.colab\" in sys.modules:\n",
        "    from google.colab import auth\n",
        "\n",
        "    auth.authenticate_user()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "oukaeL9Thgy4"
      },
      "source": [
        "### Import libraries"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {
        "id": "227VoQtmhjRa"
      },
      "outputs": [],
      "source": [
        "import warnings\n",
        "\n",
        "from IPython.display import Image, Markdown, display, Video\n",
        "from google import genai\n",
        "from google.genai import types\n",
        "\n",
        "warnings.filterwarnings(\"ignore\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "VdO2n52RhwBG"
      },
      "source": [
        "### Set Google Cloud project information\n",
        "\n",
        "To get started using Agent Platform, you must have an existing Google Cloud project and [enable the Agent Platform API](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com).\n",
        "\n",
        "Learn more about [setting up a project](https://docs.cloud.google.com/resource-manager/docs/creating-managing-projects) and a [development environment](https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "metadata": {
        "id": "lpI4Mo0phyq8"
      },
      "outputs": [],
      "source": [
        "import os\n",
        "\n",
        "# fmt: off\n",
        "PROJECT_ID = \"[your-project-id]\"  # @param {type: \"string\", placeholder: \"[your-project-id]\", isTemplate: true}\n",
        "# fmt: on\n",
        "if not PROJECT_ID or PROJECT_ID == \"[your-project-id]\":\n",
        "    PROJECT_ID = str(os.environ.get(\"GOOGLE_CLOUD_PROJECT\"))\n",
        "\n",
        "LOCATION = \"global\"\n",
        "\n",
        "client = genai.Client(enterprise=True, project=PROJECT_ID, location=LOCATION)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "QOov6dpG99rY"
      },
      "source": [
        "### Load the model"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "metadata": {
        "id": "27Fikag0xSaB"
      },
      "outputs": [],
      "source": [
        "MODEL_ID = \"gemini-3.1-flash-image\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "xuHBu3aRiYYv"
      },
      "source": [
        "## Image generation"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "M2i8O36nTHI1"
      },
      "source": [
        "### Text-to-image\n",
        "\n",
        "In the cell below, you'll call the `generate_content` method and modify the following arguments:\n",
        "\n",
        "  - `prompt`: A text-only user message describing the image to be generated.\n",
        "  - `config`: A config for specifying content settings.\n",
        "    - `response_modalities`: To generate an image, you must include `IMAGE` in the `response_modalities` list. To get both text and images, specify `IMAGE` and `TEXT`.\n",
        "    - `ImageConfig`: Set the `aspect_ratio`. Valid ratios are: 1:1, 3:2, 2:3, 3:4, 4:3, 1:4, 4:1, 4:5, 5:4, 1:8, 8:1, 9:16, 16:9, 21:9\n",
        "    - `ThinkingConfig`: Set the `thinking_level` to `HIGH` or `MINIMAL`, and if you'd like to view the model thoughts, set `include_thoughts` to `True`.\n",
        "      - `HIGH`: Allows the model to use more tokens for thinking and is suitable for complex prompts requiring deep reasoning.\n",
        "      - `MINIMAL`: Constrains the model to use as few tokens as possible for thinking and is best used for low-complexity tasks.\n",
        "\n",
        "\n",
        "All generated images include a [SynthID watermark](https://deepmind.google/technologies/synthid/)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "NZsZMcA-iPSj"
      },
      "outputs": [],
      "source": [
        "prompt = \"\"\"\n",
        "A high-contrast, grainy black and white street photography shot. A woman in dark sunglasses is captured in mid-stride with elegant motion blur. Overlaid on the image are large, white, pillowy bubble lines that curve around her to trace her silhouette. A word is added to the top of the image in the same white, bubble font: STYLE.\n",
        "\"\"\"\n",
        "aspect_ratio = \"3:2\"\n",
        "\n",
        "response = client.models.generate_content(\n",
        "    model=MODEL_ID,\n",
        "    contents=prompt,\n",
        "    config=types.GenerateContentConfig(\n",
        "        response_modalities=[\"IMAGE\", \"TEXT\"],\n",
        "        image_config=types.ImageConfig(\n",
        "            aspect_ratio=aspect_ratio,\n",
        "            output_mime_type=\"image/png\",\n",
        "        ),\n",
        "        thinking_config=types.ThinkingConfig(\n",
        "            include_thoughts=True, thinking_level=types.ThinkingLevel.HIGH\n",
        "        ),\n",
        "    ),\n",
        ")\n",
        "\n",
        "# Check for errors if an image is not generated\n",
        "if response.candidates[0].finish_reason != types.FinishReason.STOP:\n",
        "    reason = response.candidates[0].finish_reason\n",
        "    raise ValueError(f\"Prompt Content Error: {reason}\")\n",
        "\n",
        "for part in response.candidates[0].content.parts:\n",
        "    if part.thought:\n",
        "        continue  # Skip displaying thoughts\n",
        "    if part.inline_data:\n",
        "        display(Image(data=part.inline_data.data, width=500))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mbpegA7YhkxI"
      },
      "source": [
        "### See the thoughts\n",
        "\n",
        "Since this is a thinking model, you can check the thoughts that led to the image being produced."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "KzKLlFCYhzov"
      },
      "outputs": [],
      "source": [
        "for part in response.parts:\n",
        "    if part.thought:\n",
        "        if part.text:\n",
        "            display(Markdown(part.text))\n",
        "        elif part.inline_data:\n",
        "            display(Image(data=part.inline_data.data, width=500))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "xS1G2QWV7A3e"
      },
      "source": [
        "### Prominent people\n",
        "\n",
        "You can block the model from generating photorealistic images of prominent people by setting `prominent_people` to `types.ProminentPeople.BLOCK_PROMINENT_PEOPLE`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "uFJQcgbJ7Dry"
      },
      "outputs": [],
      "source": [
        "prompt = \"Generate an image of Beyonce\"\n",
        "\n",
        "response = client.models.generate_content(\n",
        "    model=MODEL_ID,\n",
        "    contents=prompt,\n",
        "    config=types.GenerateContentConfig(\n",
        "        response_modalities=[\"IMAGE\", \"TEXT\"],\n",
        "        image_config=types.ImageConfig(\n",
        "            aspect_ratio=\"1:1\",\n",
        "            prominent_people=types.ProminentPeople.BLOCK_PROMINENT_PEOPLE,\n",
        "        ),\n",
        "    ),\n",
        ")\n",
        "\n",
        "# Check for errors if an image is not generated\n",
        "if response.candidates[0].finish_reason != types.FinishReason.STOP:\n",
        "    print(response.candidates[0].finish_reason, response.candidates[0].finish_message)\n",
        "else:\n",
        "    for part in response.candidates[0].content.parts:\n",
        "        if part.thought:\n",
        "            continue\n",
        "        if part.inline_data:\n",
        "            display(Image(data=part.inline_data.data, width=500))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ys_8nuIENJP9"
      },
      "source": [
        "### Grounding with web search results\n",
        "\n",
        "With this model, you can also generate responses that are grounded in the results of a Google Search.\n",
        "\n",
        "To display the grounding data, use the helper function in the following cell."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "metadata": {
        "id": "_H9eISeEJNZQ"
      },
      "outputs": [],
      "source": [
        "def print_search_grounding_data(response: types.GenerateContentResponse) -> None:\n",
        "    \"\"\"Prints response with grounding citations in Markdown format.\"\"\"\n",
        "    grounding_metadata = response.candidates[0].grounding_metadata\n",
        "    lines = []\n",
        "\n",
        "    if response.text:\n",
        "        ENCODING = \"utf-8\"\n",
        "        text_bytes = response.text.encode(ENCODING)\n",
        "        last_byte_index = 0\n",
        "\n",
        "        if grounding_metadata.grounding_supports:\n",
        "            for support in grounding_metadata.grounding_supports:\n",
        "                lines.append(\n",
        "                    text_bytes[last_byte_index : support.segment.end_index].decode(\n",
        "                        ENCODING\n",
        "                    )\n",
        "                )\n",
        "                footnotes = \"\".join(\n",
        "                    [f\"[{i + 1}]\" for i in support.grounding_chunk_indices]\n",
        "                )\n",
        "                lines.append(f\" {footnotes}\")\n",
        "                last_byte_index = support.segment.end_index\n",
        "\n",
        "        if last_byte_index < len(text_bytes):\n",
        "            lines.append(text_bytes[last_byte_index:].decode(ENCODING))\n",
        "\n",
        "    lines.append(\"\\n\\n----\\n## Grounding Sources\\n\")\n",
        "\n",
        "    if grounding_metadata.grounding_chunks:\n",
        "        lines.append(\"### Grounding Chunks\\n\")\n",
        "        for i, chunk in enumerate(grounding_metadata.grounding_chunks, start=1):\n",
        "            context = chunk.web or chunk.retrieved_context or chunk.maps\n",
        "            image = chunk.image\n",
        "\n",
        "            if not context and not image:\n",
        "                continue\n",
        "\n",
        "            if image:\n",
        "                title = image.title or \"Image Source\"\n",
        "                uri = image.source_uri or \"#\"\n",
        "                image_uri = image.image_uri\n",
        "                domain = image.domain\n",
        "\n",
        "                lines.append(f\"{i}. [{title}]({uri})\\n\")\n",
        "                if domain:\n",
        "                    lines.append(f\"    - Domain: `{domain}`\\n\")\n",
        "                if image_uri:\n",
        "                    lines.append(f\"    <img src='{image_uri}' width='250'>\\n\\n\")\n",
        "\n",
        "            elif context:\n",
        "                uri = context.uri\n",
        "                title = context.title or \"Source\"\n",
        "                if uri:\n",
        "                    uri = uri.replace(\" \", \"%20\")\n",
        "                    if uri.startswith(\"gs://\"):\n",
        "                        uri = uri.replace(\"gs://\", \"https://storage.googleapis.com/\", 1)\n",
        "\n",
        "                lines.append(f\"{i}. [{title}]({uri})\\n\")\n",
        "                if hasattr(context, \"text\") and context.text:\n",
        "                    lines.append(f\"{context.text}\\n\\n\")\n",
        "\n",
        "    web_queries = grounding_metadata.web_search_queries or []\n",
        "    image_queries = getattr(grounding_metadata, \"image_search_queries\", []) or []\n",
        "\n",
        "    all_queries = list(web_queries) + list(image_queries)\n",
        "\n",
        "    if all_queries:\n",
        "        lines.append(f\"\\n**Web Search Queries:** {all_queries}\\n\")\n",
        "\n",
        "        if grounding_metadata.search_entry_point:\n",
        "            lines.append(\n",
        "                f\"\\n**Search Entry Point:**\\n{grounding_metadata.search_entry_point.rendered_content}\\n\"\n",
        "            )\n",
        "    elif grounding_metadata.retrieval_queries:\n",
        "        lines.append(\n",
        "            f\"\\n**Retrieval Queries:** {grounding_metadata.retrieval_queries}\\n\"\n",
        "        )\n",
        "\n",
        "    display(Markdown(\"\".join(lines)))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "QIRVJT5SJWVZ"
      },
      "source": [
        "Next, you'll create a Google Search tool and include it in the `tools` parameter of the following request to perform a web search."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "yWHgXTHldU_N"
      },
      "outputs": [],
      "source": [
        "prompt = \"\"\"\n",
        "A cinematic, wide-angle illustration of the NFL team's stadium that won the 2026 Super Bowl. Digital art style with high-detail architecture.\n",
        "\"\"\"\n",
        "google_search = types.Tool(\n",
        "    google_search=types.GoogleSearch(\n",
        "        search_types=types.SearchTypes(web_search=types.WebSearch())\n",
        "    )\n",
        ")\n",
        "response = client.models.generate_content(\n",
        "    model=MODEL_ID,\n",
        "    contents=prompt,\n",
        "    config=types.GenerateContentConfig(\n",
        "        response_modalities=[\"TEXT\", \"IMAGE\"],\n",
        "        image_config=types.ImageConfig(\n",
        "            aspect_ratio=\"21:9\",\n",
        "        ),\n",
        "        thinking_config=types.ThinkingConfig(\n",
        "            include_thoughts=True, thinking_level=types.ThinkingLevel.HIGH\n",
        "        ),\n",
        "        tools=[google_search],\n",
        "    ),\n",
        ")\n",
        "\n",
        "for part in response.candidates[0].content.parts:\n",
        "    if part.text:\n",
        "        display(Markdown(part.text))\n",
        "    if part.inline_data:\n",
        "        display(Image(data=part.inline_data.data, width=500))\n",
        "\n",
        "print_search_grounding_data(response)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "y7akNXJC5pTA"
      },
      "source": [
        "Below, you'll do the same thing, except with an image search."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "4C0d3W4L5q6W"
      },
      "outputs": [],
      "source": [
        "prompt = \"Generate a watercolor image of the Lansdowne Bridge\"\n",
        "google_search = types.Tool(\n",
        "    google_search=types.GoogleSearch(\n",
        "        search_types=types.SearchTypes(\n",
        "            image_search=types.ImageSearch(),\n",
        "        )\n",
        "    )\n",
        ")\n",
        "\n",
        "response = client.models.generate_content(\n",
        "    model=MODEL_ID,\n",
        "    contents=prompt,\n",
        "    config=types.GenerateContentConfig(\n",
        "        response_modalities=[\"TEXT\", \"IMAGE\"],\n",
        "        image_config=types.ImageConfig(\n",
        "            aspect_ratio=\"16:9\",\n",
        "        ),\n",
        "        thinking_config=types.ThinkingConfig(\n",
        "            include_thoughts=True, thinking_level=types.ThinkingLevel.HIGH\n",
        "        ),\n",
        "        tools=[google_search],\n",
        "    ),\n",
        ")\n",
        "\n",
        "for part in response.candidates[0].content.parts:\n",
        "    if part.text:\n",
        "        display(Markdown(part.text))\n",
        "    if part.inline_data:\n",
        "        display(Image(data=part.inline_data.data, width=500))\n",
        "\n",
        "\n",
        "print_search_grounding_data(response)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hgO4Xqv9NRph"
      },
      "source": [
        "### Image sizes\n",
        "\n",
        "You can have Nano Banana 2 generate images with an `image_size` of `512`, `1K`, `2K`, or `4K`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "m6cGJoDDinY3"
      },
      "outputs": [],
      "source": [
        "prompt = \"\"\"\n",
        "Macro photography of a vibrant teal and lime green chameleon perched on a mossy branch.\n",
        "\"\"\"\n",
        "\n",
        "response = client.models.generate_content(\n",
        "    model=MODEL_ID,\n",
        "    contents=prompt,\n",
        "    config=types.GenerateContentConfig(\n",
        "        response_modalities=[\"TEXT\", \"IMAGE\"],\n",
        "        image_config=types.ImageConfig(\n",
        "            aspect_ratio=\"1:1\",\n",
        "            image_size=\"4K\",\n",
        "        ),\n",
        "    ),\n",
        ")\n",
        "\n",
        "for part in response.candidates[0].content.parts:\n",
        "    if part.thought:\n",
        "        continue\n",
        "    if part.inline_data:\n",
        "        display(Image(data=part.inline_data.data, width=500))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HFR2LKZHNmtZ"
      },
      "source": [
        "### Video-to-image"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "EH0Q_PalPIcv"
      },
      "source": [
        "Nano Banana 2 is also able to generate images from a video. The model is able to observe the frames and generate new images based on the visual content.\n",
        "\n",
        "Start by downloading and displaying a video below."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "dXJICih8PdXZ"
      },
      "outputs": [],
      "source": [
        "!wget https://storage.googleapis.com/cloud-samples-data/generative-ai/video/animals.mp4\n",
        "\n",
        "video_file = \"animals.mp4\"\n",
        "display(Video(video_file, embed=True, width=600))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "O-rAlzxvOXHv"
      },
      "outputs": [],
      "source": [
        "with open(video_file, \"rb\") as f:\n",
        "    video = f.read()\n",
        "\n",
        "response = client.models.generate_content(\n",
        "    model=MODEL_ID,\n",
        "    contents=[\n",
        "      types.Part.from_bytes(\n",
        "          data=video,\n",
        "          mime_type=\"video/mp4\"\n",
        "      ),\n",
        "      \"Generate an illustration of every animal featured in this video\",\n",
        "    ],\n",
        "    config=types.GenerateContentConfig(\n",
        "        response_modalities=[\"TEXT\", \"IMAGE\"],\n",
        "    ),\n",
        ")\n",
        "\n",
        "\n",
        "for part in response.candidates[0].content.parts:\n",
        "    if part.text:\n",
        "        display(Markdown(part.text))\n",
        "    if part.inline_data:\n",
        "        display(Image(data=part.inline_data.data, width=500))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "yAoLWBu4RUGP"
      },
      "source": [
        "You can also generate images from YouTube videos and videos in Cloud Storage. Simply provide the `file_uri` and `mime_type` in the request."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "oBVD4GdbRsIh"
      },
      "outputs": [],
      "source": [
        "youtube_link = \"https://www.youtube.com/watch?v=rjoMZyxncUI\"\n",
        "\n",
        "response = client.models.generate_content(\n",
        "    model=MODEL_ID,\n",
        "    contents=[\n",
        "      types.Part.from_uri(\n",
        "          file_uri=youtube_link,\n",
        "          mime_type=\"video/mp4\"\n",
        "      ),\n",
        "      \"Generate an infographic of the topics covered in this video\",\n",
        "    ],\n",
        "    config=types.GenerateContentConfig(\n",
        "        response_modalities=[\"TEXT\", \"IMAGE\"],\n",
        "    ),\n",
        ")\n",
        "\n",
        "\n",
        "for part in response.candidates[0].content.parts:\n",
        "    if part.text:\n",
        "        display(Markdown(part.text))\n",
        "    if part.inline_data:\n",
        "        display(Image(data=part.inline_data.data, width=500))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "5nlhVQCuT6DS"
      },
      "source": [
        "## Image editing\n",
        "\n",
        "You can also edit images with this model; simply pass the original image as part of the prompt."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "qG0_O2yU9d99"
      },
      "source": [
        "### Localization\n",
        "\n",
        "You can also translate the text in images through image editing. Start by downloading the image and displaying it below."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "nVOW78Qt9keo"
      },
      "outputs": [],
      "source": [
        "!wget https://storage.googleapis.com/cloud-samples-data/generative-ai/image/city-street.png\n",
        "\n",
        "starting_image = \"city-street.png\"\n",
        "display(Image(filename=starting_image, width=500))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "V48CSOv995Z9"
      },
      "outputs": [],
      "source": [
        "with open(starting_image, \"rb\") as f:\n",
        "    image = f.read()\n",
        "\n",
        "response = client.models.generate_content(\n",
        "    model=MODEL_ID,\n",
        "    contents=[\n",
        "        types.Part.from_bytes(\n",
        "            data=image,\n",
        "            mime_type=\"image/png\",\n",
        "        ),\n",
        "        \"Change the text in this infographic from English to Japanese.\",\n",
        "    ],\n",
        "    config=types.GenerateContentConfig(\n",
        "        response_modalities=[\"TEXT\", \"IMAGE\"],\n",
        "    ),\n",
        ")\n",
        "\n",
        "for part in response.candidates[0].content.parts:\n",
        "    if part.text:\n",
        "        display(Markdown(part.text))\n",
        "    if part.inline_data:\n",
        "        display(Image(data=part.inline_data.data, width=500))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0sIquv-1lAzn"
      },
      "source": [
        "### Multi-turn image editing (chat)\n",
        "\n",
        "In this next section, you'll generate a starting image and iteratively alter certain aspects of the image by chatting with the model."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "NRMWpFgKY3Xx"
      },
      "outputs": [],
      "source": [
        "chat = client.chats.create(\n",
        "    model=MODEL_ID,\n",
        "    config=types.GenerateContentConfig(response_modalities=[\"TEXT\", \"IMAGE\"]),\n",
        ")\n",
        "\n",
        "message = \"A minimalist overhead shot of two dense florist buckets on a smooth grey pavement. One contains a bouquet of pink baby's breath, and the other contains a cluster of pale blush poppies.\"\n",
        "response = chat.send_message(message)\n",
        "\n",
        "for part in response.candidates[0].content.parts:\n",
        "    if part.thought:\n",
        "        continue\n",
        "    if part.inline_data:\n",
        "        display(Image(data=part.inline_data.data, width=500))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PR6T_rSBJwM1"
      },
      "source": [
        "Now, you'll send a new message in the existing chat to update the previously generated image."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "bMp_cFHplh-Z"
      },
      "outputs": [],
      "source": [
        "message = \"Change the poppies to white dahlias and add a third bucket of pink hydrangeas in the top right corner.\"\n",
        "response = chat.send_message(message)\n",
        "\n",
        "for part in response.candidates[0].content.parts:\n",
        "    if part.thought:\n",
        "        continue\n",
        "    if part.inline_data:\n",
        "        display(Image(data=part.inline_data.data, width=500))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hQ_uiJOY5Sy9"
      },
      "source": [
        "### Multiple reference images\n",
        "\n",
        "With Nano Banana 2, you can include up to 14 reference images in a request to generate a new image that preserves the content of the original images.\n",
        "\n",
        "Run the following cell to visualize the starting images stored in Cloud Storage."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "cUsResOwmBuS"
      },
      "outputs": [],
      "source": [
        "from io import BytesIO\n",
        "\n",
        "import matplotlib.pyplot as plt\n",
        "import requests\n",
        "from PIL import Image as PIL_Image\n",
        "\n",
        "image_urls = [\n",
        "    \"https://storage.googleapis.com/cloud-samples-data/generative-ai/image/woman.jpeg\",\n",
        "    \"https://storage.googleapis.com/cloud-samples-data/generative-ai/image/black-boots.jpg\",\n",
        "    \"https://storage.googleapis.com/cloud-samples-data/generative-ai/image/black-bag.jpg\",\n",
        "    \"https://storage.googleapis.com/cloud-samples-data/generative-ai/image/shirt.jpg\",\n",
        "    \"https://storage.googleapis.com/cloud-samples-data/generative-ai/image/jacket.jpg\",\n",
        "    \"https://storage.googleapis.com/cloud-samples-data/generative-ai/image/white-pants.jpg\",\n",
        "]\n",
        "\n",
        "fig, axes = plt.subplots(2, 3, figsize=(12, 8))\n",
        "for i, ax in enumerate(axes.flatten()):\n",
        "    ax.imshow(PIL_Image.open(BytesIO(requests.get(image_urls[i]).content)))\n",
        "    ax.axis(\"off\")\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ErSjXfZ2qg7F"
      },
      "source": [
        "The process for sending the request is similar to previous image editing calls. The main difference is that you will provide multiple `Part.from_uri` instances, one for each reference image."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "_93g7aAeoyNP"
      },
      "outputs": [],
      "source": [
        "response = client.models.generate_content(\n",
        "    model=MODEL_ID,\n",
        "    contents=[\n",
        "        types.Part.from_uri(\n",
        "            file_uri=\"gs://cloud-samples-data/generative-ai/image/woman.jpeg\",\n",
        "            mime_type=\"image/jpeg\",\n",
        "        ),\n",
        "        types.Part.from_uri(\n",
        "            file_uri=\"gs://cloud-samples-data/generative-ai/image/black-boots.jpg\",\n",
        "            mime_type=\"image/png\",\n",
        "        ),\n",
        "        types.Part.from_uri(\n",
        "            file_uri=\"gs://cloud-samples-data/generative-ai/image/black-bag.jpg\",\n",
        "            mime_type=\"image/png\",\n",
        "        ),\n",
        "        types.Part.from_uri(\n",
        "            file_uri=\"gs://cloud-samples-data/generative-ai/image/shirt.jpg\",\n",
        "            mime_type=\"image/png\",\n",
        "        ),\n",
        "        types.Part.from_uri(\n",
        "            file_uri=\"gs://cloud-samples-data/generative-ai/image/jacket.jpg\",\n",
        "            mime_type=\"image/jpeg\",\n",
        "        ),\n",
        "        types.Part.from_uri(\n",
        "            file_uri=\"gs://cloud-samples-data/generative-ai/image/white-pants.jpg\",\n",
        "            mime_type=\"image/png\",\n",
        "        ),\n",
        "        \"Generate an image of a woman wearing white pants, a navy blue shirt, a cropped trench coat, and black boots. She's carrying a black bag. The outline of the woman is cropped against a piece of cardstock with a giant paperclip attached at the top.\",\n",
        "    ],\n",
        "    config=types.GenerateContentConfig(\n",
        "        response_modalities=[\"TEXT\", \"IMAGE\"],\n",
        "        image_config=types.ImageConfig(\n",
        "            aspect_ratio=\"4:3\",\n",
        "        ),\n",
        "    ),\n",
        ")\n",
        "\n",
        "for part in response.candidates[0].content.parts:\n",
        "    if part.text:\n",
        "        display(Markdown(part.text))\n",
        "    if part.inline_data:\n",
        "        display(Image(data=part.inline_data.data, width=500))"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "name": "intro_gemini_3_1_flash_image_gen.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
