{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "2eec5cc39a59"
      },
      "outputs": [],
      "source": [
        "# Copyright 2024 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": "7c5e37584117"
      },
      "source": [
        "# Using Gemini Function Calling to Get Real-Time Company News and Insights\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/function-calling/use_case_company_news_and_insights.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/vertex-ai/colab/import/https:%2F%2Fraw.githubusercontent.com%2FGoogleCloudPlatform%2Fgenerative-ai%2Fmain%2Fgemini%2Ffunction-calling%2Fuse_case_company_news_and_insights.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/vertex-ai/workbench/deploy-notebook?download_url=https://raw.githubusercontent.com/GoogleCloudPlatform/generative-ai/main/gemini/function-calling/use_case_company_news_and_insights.ipynb\">\n",
        "      <img src=\"https://lh3.googleusercontent.com/UiNooY4LUgW_oTvpsNhPpQzsstV5W8F7rYgxgGBD85cWJoLmrOzhVs_ksK_vgx40SHs7jCqkTkCk=e14-rj-sc0xffffff-h130-w32\" alt=\"Vertex AI 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/function-calling/use_case_company_news_and_insights.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",
        "<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/function-calling/use_case_company_news_and_insights.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/function-calling/use_case_company_news_and_insights.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/function-calling/use_case_company_news_and_insights.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/function-calling/use_case_company_news_and_insights.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/function-calling/use_case_company_news_and_insights.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>            "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3d8f91830324"
      },
      "source": [
        "| Authors |\n",
        "| --- |\n",
        "| [Ishana Shinde](https://github.com/ishana7) |\n",
        "| [Kristopher Overholt](https://github.com/koverholt) |\n",
        "| [Ariyo Oluwasanmi](https://github.com/Sanmilee) |"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7102b39c47f0"
      },
      "source": [
        "## Function Calling in Gemini\n",
        "\n",
        "Gemini is a family of generative AI models developed by Google DeepMind that is designed for multimodal use cases. [Function Calling in Gemini](https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/function-calling) lets developers create a description of a function in their code, then pass that description to a language model in a request. The response from the model includes the name of a function that matches the description and the arguments to call it with.\n",
        "\n",
        "## Overview\n",
        "\n",
        "Meet Jane. She's a busy investor who's always on the lookout for the latest market trends and financial news. She needs information quickly and accurately, but sifting through endless articles and reports is time-consuming.\n",
        "\n",
        "Jane discovers [Function Calling](https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/function-calling), which is a powerful tool that uses the Gemini model to predict function calls to external systems and synthesizes information in natural language. Now Jane can get instant insights on companies and breaking news, all within her familiar coding environment. She can even build a web app on top of these APIs and functions so that her coworkers can benefit from this approach without writing any code!"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "be7720612149"
      },
      "source": [
        "![Standard Gemini Response](https://storage.googleapis.com/github-repo/generative-ai/gemini/function-calling/company_news_and_insights/standard-gemini-response.png)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "25543ba572f7"
      },
      "source": [
        "![Gemini with Function Calling](https://storage.googleapis.com/github-repo/generative-ai/gemini/function-calling/company_news_and_insights/gemini-function-calling-response.png)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "308fb67d0e91"
      },
      "source": [
        "Here's how Jane plans to interact with Gemini Function Calling to help her learn about stock prices, company profiles, and news about topics and trends that she's researching:\n",
        "\n",
        "### Financial Analysis\n",
        "\n",
        "- Jane wants to know about Google's current financial standing. She prompts Gemini to \"Give me a company overview of Google.\"\n",
        "- Behind the scenes, the application sends a request to an external API and retrieves comprehensive information about Google.\n",
        "- Gemini processes this data and presents Jane with a concise summary, highlighting key metrics and financial ratios.\n",
        "- Jane could also request a stock price with a simple prompt like \"Give me the current stock price for GOOG.\"\n",
        "    \n",
        "### News Insights\n",
        "\n",
        "- Jane wants to stay informed about the latest developments in AI. She prompts Gemini with \"What is the latest news on AI?\"\n",
        "- The application sends a request to a news API and collects relevant news articles from reliable sources.\n",
        "- Gemini analyzes the news and responds to Jane with a curated summary of the top headlines and key takeaways.\n",
        "\n",
        "This notebook demonstrates how Jane uses Function Calling in Gemini to interact with financial and news APIs to help her learn information about companies."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0f07a65d6572"
      },
      "source": [
        "### Benefits of Function Calling\n",
        "\n",
        "- **Native framework**: Function Calling is a native framework in Gemini, so there's no need to enable additional APIs or install extra packages.\n",
        "- **Time savings**: No need to write custom code to call, parse, and synthesize information from multiple APIs.\n",
        "- **Simplified interaction with generative AI models**: Gemini handles the complex task of understanding the user's intent, predicting function calls, extracting relevant function parameters, and generating natural language summaries.\n",
        "- **Versatility**: Easily extend capabilities by adding more function calls for different APIs and tailoring it to your needs.\n",
        "\n",
        "## Objectives\n",
        "\n",
        "In this tutorial, you will learn how to use the Vertex AI SDK for Python to work with financial and news APIs using the Gemini model and Function Calling.\n",
        "\n",
        "You will complete the following tasks:\n",
        "\n",
        "- Install the Vertex AI SDK for Python\n",
        "- Define functions to get company news, financial information, stock prices, and sentiment of company news\n",
        "- Initialize a chat session with the Gemini API\n",
        "- Write a helper function to handle function calls, API calls, and responses to the Gemini model\n",
        "- Ask questions about different aspects of companies and topics"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fcd6fe2a7b6d"
      },
      "source": [
        "## Getting Started\n",
        "\n",
        "### Install Vertex AI SDK and other required packages"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {
        "id": "cc681958b8f7"
      },
      "outputs": [],
      "source": [
        "%pip install --upgrade --quiet google-cloud-aiplatform requests"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8ed31279f009"
      },
      "source": [
        "### Restart runtime\n",
        "\n",
        "To use the newly installed packages in this Jupyter runtime, you must restart the runtime. You can do this by running the cell below, which restarts the current kernel.\n",
        "\n",
        "The restart might take a minute or longer. After it's restarted, continue to the next step."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {
        "id": "567212ff53a6"
      },
      "outputs": [],
      "source": [
        "import IPython\n",
        "\n",
        "app = IPython.Application.instance()\n",
        "app.kernel.do_shutdown(True)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "972161a99004"
      },
      "source": [
        "<div class=\"alert alert-block alert-warning\">\n",
        "<b>⚠️ The kernel is going to restart. Please wait until it is finished before continuing to the next step. ⚠️</b>\n",
        "</div>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "4460fec7ce2e"
      },
      "source": [
        "### Authenticate your notebook environment (Colab only)\n",
        "\n",
        "If you are running this notebook on Google Colab, run the cell below to authenticate your environment."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {
        "id": "59c887aafd02"
      },
      "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": "56e1e9ca7ddc"
      },
      "source": [
        "### Set Google Cloud project information and initialize Vertex AI SDK\n",
        "\n",
        "To get started using Vertex AI, you must have an existing Google Cloud project and [enable the Vertex AI API](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com).\n",
        "\n",
        "Learn more about [setting up a project and a development environment](https://cloud.google.com/vertex-ai/docs/start/cloud-environment)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "41c34a683156"
      },
      "outputs": [],
      "source": [
        "PROJECT_ID = \"[your-project-id]\"  # @param {type:\"string\"}\n",
        "LOCATION = \"us-central1\"  # @param {type:\"string\"}\n",
        "\n",
        "import vertexai\n",
        "\n",
        "vertexai.init(project=PROJECT_ID, location=LOCATION)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "26bcfc24e720"
      },
      "source": [
        "### Import libraries"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "metadata": {
        "id": "6d249cfcaf52"
      },
      "outputs": [],
      "source": [
        "from IPython.display import Markdown, display\n",
        "import requests\n",
        "from vertexai.generative_models import (\n",
        "    FunctionDeclaration,\n",
        "    GenerationConfig,\n",
        "    GenerationResponse,\n",
        "    GenerativeModel,\n",
        "    Part,\n",
        "    Tool,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "a8a3a9ff0f3d"
      },
      "source": [
        "## Building an assistant to answer financial and news questions about companies\n",
        "\n",
        "With the initial setup complete, you're ready to build your application that uses the Gemini model, functions as tools, and API calls to explore financial and news information related to various companies and industries.\n",
        "\n",
        "Before we go through the following code examples, it's helpful to understand a conceptual model of the development journey that you're about to go on with Gemini Function Calling. The following diagram shows key steps that you'll follow along the way:"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1f968100a531"
      },
      "source": [
        "![Function Calling Steps](https://storage.googleapis.com/github-repo/generative-ai/gemini/function-calling/company_news_and_insights/function-calling-steps.png)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "bf4ba70381cd"
      },
      "source": [
        "### Define functions and parameter descriptions\n",
        "\n",
        "Define function declarations that will be used as tools for Gemini by specifying the function details as a dictionary in accordance with the [OpenAPI JSON schema](https://spec.openapis.org/oas/v3.0.3#schemawr).\n",
        "\n",
        "You'll define four tools to fetch various company and financial information, including stock prices, company overviews, news for a given company, and news sentiment for a given topic:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "metadata": {
        "id": "82979452ed3f"
      },
      "outputs": [],
      "source": [
        "get_stock_price = FunctionDeclaration(\n",
        "    name=\"get_stock_price\",\n",
        "    description=\"Fetch the current stock price of a given company\",\n",
        "    parameters={\n",
        "        \"type\": \"object\",\n",
        "        \"properties\": {\n",
        "            \"ticker\": {\n",
        "                \"type\": \"string\",\n",
        "                \"description\": \"Stock ticker symbol for a company\",\n",
        "            }\n",
        "        },\n",
        "    },\n",
        ")\n",
        "\n",
        "get_company_overview = FunctionDeclaration(\n",
        "    name=\"get_company_overview\",\n",
        "    description=\"Get company details and other financial data\",\n",
        "    parameters={\n",
        "        \"type\": \"object\",\n",
        "        \"properties\": {\n",
        "            \"ticker\": {\n",
        "                \"type\": \"string\",\n",
        "                \"description\": \"Stock ticker symbol for a company\",\n",
        "            }\n",
        "        },\n",
        "    },\n",
        ")\n",
        "\n",
        "get_company_news = FunctionDeclaration(\n",
        "    name=\"get_company_news\",\n",
        "    description=\"Get the latest news headlines for a given company.\",\n",
        "    parameters={\n",
        "        \"type\": \"object\",\n",
        "        \"properties\": {\n",
        "            \"tickers\": {\n",
        "                \"type\": \"string\",\n",
        "                \"description\": \"Stock ticker symbol for a company\",\n",
        "            }\n",
        "        },\n",
        "    },\n",
        ")\n",
        "\n",
        "get_news_with_sentiment = FunctionDeclaration(\n",
        "    name=\"get_news_with_sentiment\",\n",
        "    description=\"Gets live and historical market news and sentiment data\",\n",
        "    parameters={\n",
        "        \"type\": \"object\",\n",
        "        \"properties\": {\n",
        "            \"news_topic\": {\n",
        "                \"type\": \"string\",\n",
        "                \"description\": \"\"\"News topic to learn about. Supported topics\n",
        "                               include blockchain, earnings, ipo,\n",
        "                               mergers_and_acquisitions, financial_markets,\n",
        "                               economy_fiscal, economy_monetary, economy_macro,\n",
        "                               energy_transportation, finance, life_sciences,\n",
        "                               manufacturing, real_estate, retail_wholesale,\n",
        "                               and technology\"\"\",\n",
        "            },\n",
        "        },\n",
        "    },\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "43373d59999e"
      },
      "source": [
        "### Wrap function declarations in a tool\n",
        "\n",
        "Now, you can define a tool that will allow Gemini to select from the set of functions we've defined:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "metadata": {
        "id": "8f75dcb05e2f"
      },
      "outputs": [],
      "source": [
        "company_insights_tool = Tool(\n",
        "    function_declarations=[\n",
        "        get_stock_price,\n",
        "        get_company_overview,\n",
        "        get_company_news,\n",
        "        get_news_with_sentiment,\n",
        "    ],\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7d4cc72d8e6c"
      },
      "source": [
        "### Company and financial information API\n",
        "\n",
        "Alpha Vantage provides real-time and historical financial market data through a set of data APIs. In this tutorial, you'll use the Alpha Vantage API to get stock prices, company information, and news about different industries.\n",
        "\n",
        "You can register for a free developer API key at [Alpha Vantage](https://www.alphavantage.co/). Once you have an API key, paste it into the cell below:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "metadata": {
        "id": "643a1ff45db9"
      },
      "outputs": [],
      "source": [
        "# API key for company and financial information\n",
        "# API_KEY = \"PASTE_YOUR_API_KEY_HERE\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1e32e0694d45"
      },
      "source": [
        "You'll use this API key throughout the rest of this notebook to make API requests and get information about various companies and industries."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "706839cf3dba"
      },
      "source": [
        "### Define Python functions and a function handler"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "4ef2ec1e97eb"
      },
      "source": [
        "Define Python functions that you'll invoke to fetch data from an external API:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "metadata": {
        "id": "81b9950967e1"
      },
      "outputs": [],
      "source": [
        "def get_stock_price_from_api(content):\n",
        "    url = f\"https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol={content['ticker']}&apikey={API_KEY}\"\n",
        "    api_request = requests.get(url)\n",
        "    return api_request.text\n",
        "\n",
        "\n",
        "def get_company_overview_from_api(content):\n",
        "    url = f\"https://www.alphavantage.co/query?function=OVERVIEW&symbol={content['ticker']}&apikey={API_KEY}\"\n",
        "    api_response = requests.get(url)\n",
        "    return api_response.text\n",
        "\n",
        "\n",
        "def get_company_news_from_api(content):\n",
        "    url = f\"https://www.alphavantage.co/query?function=NEWS_SENTIMENT&tickers={content['tickers']}&limit=20&sort=RELEVANCE&apikey={API_KEY}\"\n",
        "    api_response = requests.get(url)\n",
        "    return api_response.text\n",
        "\n",
        "\n",
        "def get_news_with_sentiment_from_api(content):\n",
        "    url = f\"https://www.alphavantage.co/query?function=NEWS_SENTIMENT&topics={content['news_topic']}&limit=20&sort=RELEVANCE&apikey={API_KEY}\"\n",
        "    api_request = requests.get(url)\n",
        "    return api_request.text"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "a9f9c6b3fb4a"
      },
      "source": [
        "Define a function handler that maps function call names (from your function declarations) to actual Python functions that call APIs:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "metadata": {
        "id": "900d2529a6ac"
      },
      "outputs": [],
      "source": [
        "function_handler = {\n",
        "    \"get_stock_price\": get_stock_price_from_api,\n",
        "    \"get_company_overview\": get_company_overview_from_api,\n",
        "    \"get_company_news\": get_company_news_from_api,\n",
        "    \"get_news_with_sentiment\": get_news_with_sentiment_from_api,\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "87eb49d4fe0f"
      },
      "source": [
        "### Initialize model\n",
        "\n",
        "Initialize the Gemini model with the desired model parameters and `Tool` that we defined earlier:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "11cb17ef1096"
      },
      "outputs": [],
      "source": [
        "gemini_model = GenerativeModel(\n",
        "    \"gemini-2.0-flash\",\n",
        "    generation_config=GenerationConfig(temperature=0),\n",
        "    tools=[company_insights_tool],\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7cdfddffe83b"
      },
      "source": [
        "### Initialize chat session"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "metadata": {
        "id": "5be6ada7bb71"
      },
      "outputs": [],
      "source": [
        "chat = gemini_model.start_chat()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "711af0ca6d5a"
      },
      "source": [
        "### Define a helper function to send chat messages and handle function calls & responses\n",
        "\n",
        "Before you start chatting with the Gemini model and making function calls, recall that Gemini Function Calling predicts a function call from a set of functions then returns structured information about which function to call and which parameters to use.\n",
        "\n",
        "The following diagram shows the data flow and step-by-step process that occurs with Gemini Function Calling for a given conversation turn (i.e., a single input prompt from the user and output summary to the user):"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7f5389c4a114"
      },
      "source": [
        "![Function Calling Architecture](https://storage.googleapis.com/github-repo/generative-ai/gemini/function-calling/company_news_and_insights/function-call-architecture.png)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2a4746fd4894"
      },
      "source": [
        "Helper function to extract one or more function calls from a Gemini Function Call response\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "metadata": {
        "id": "576ec03b8027"
      },
      "outputs": [],
      "source": [
        "def extract_function_calls(response: GenerationResponse) -> list[dict]:\n",
        "    function_calls: list[dict] = []\n",
        "    if response.candidates[0].function_calls:\n",
        "        for function_call in response.candidates[0].function_calls:\n",
        "            function_call_dict: dict[str, dict[str, Any]] = {function_call.name: {}}\n",
        "            for key, value in function_call.args.items():\n",
        "                function_call_dict[function_call.name][key] = value\n",
        "            function_calls.append(function_call_dict)\n",
        "    return function_calls"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0e00b8dd9c4b"
      },
      "source": [
        "Rather than having to manually inspect the predicted function names and function parameters and then repeatedly invoking API calls, the following helper function automates the process of handling API calls and responses to and from the Gemini model:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "metadata": {
        "id": "d9130fa4193a"
      },
      "outputs": [],
      "source": [
        "def send_chat_message(prompt):\n",
        "    prompt += \"\"\"Give a concise, high-level summary. Only use information that you learn from the API responses.\"\"\"\n",
        "    display(Markdown(\"#### Prompt\"))\n",
        "    print(prompt, \"\\n\")\n",
        "\n",
        "    # Send a chat message to the Gemini API\n",
        "    response = chat.send_message(prompt)\n",
        "\n",
        "    # Handle cases with multiple chained function calls\n",
        "    function_calling_in_process = True\n",
        "\n",
        "    while function_calling_in_process:\n",
        "        try:\n",
        "            # Check for a function call or a natural language response\n",
        "            # If natural language response, the except is triggered\n",
        "            response_call_name = (\n",
        "                response.candidates[0].content.parts[0].function_call.name\n",
        "            )\n",
        "\n",
        "            # Extract function names and parameters\n",
        "            function_calls = extract_function_calls(response)\n",
        "            display(Markdown(\"#### Function Extraction\"))\n",
        "            print(function_calls, \"\\n\")\n",
        "\n",
        "            # Loop over all function calls' API trigger to capture all responses\n",
        "            api_responses = []  # Initialize as a list of lists\n",
        "            for function_call in function_calls:\n",
        "                for function_name, function_args in function_call.items():\n",
        "                    # Determine which external API call to make\n",
        "                    if function_name in function_handler.keys():\n",
        "                        # Extract the function call parameters\n",
        "                        params = {key: value for key, value in function_args.items()}\n",
        "\n",
        "                        # Invoke a function that calls an external API\n",
        "                        # Stay within the input token limit\n",
        "                        function_api_response = function_handler[function_name](params)[\n",
        "                            :20000\n",
        "                        ]\n",
        "\n",
        "                        # Append the function name and response as a pair to the list\n",
        "                        api_responses.append([function_name, function_api_response])\n",
        "                        display(Markdown(\"#### API response\"))\n",
        "                        print(function_api_response[:500], \"...\", \"\\n\")\n",
        "\n",
        "            # Loop over multiple function calls to extract all API response contents\n",
        "            processed_methods = set()  # Set to track processed methods\n",
        "            parts = []  # Prepare parts to send\n",
        "\n",
        "            for funct_name in function_calls:\n",
        "                # Iterate through the keys:\n",
        "                for key in funct_name.keys():\n",
        "                    # Check if we've already processed this method\n",
        "                    if key in processed_methods:\n",
        "                        # Skip if method is already processed\n",
        "                        continue\n",
        "                    # Add the method to the processed set\n",
        "                    processed_methods.add(key)\n",
        "\n",
        "                    # Find all matching responses for the current function name in the list\n",
        "                    matching_responses = [\n",
        "                        response[1] for response in api_responses if response[0] == key\n",
        "                    ]\n",
        "\n",
        "                    # Check if there are multiple responses\n",
        "                    if (\n",
        "                        isinstance(matching_responses, list)\n",
        "                        and len(matching_responses) > 0\n",
        "                    ):\n",
        "                        for content in matching_responses:  # Iterate over the list\n",
        "                            parts.append(\n",
        "                                Part.from_function_response(\n",
        "                                    name=key, response={\"content\": content}\n",
        "                                )\n",
        "                            )\n",
        "\n",
        "            # Send all API response back to Gemini to generate natural summary or another function call\n",
        "            # If this does not have the '.function_call.name' method, the 'except' is triggered\n",
        "            response = chat.send_message(parts)\n",
        "            display(Markdown(\"***\"))\n",
        "\n",
        "        except AttributeError:\n",
        "            function_calling_in_process = False\n",
        "\n",
        "    # Show the final natural language summary\n",
        "    display(Markdown(\"#### Natural language response\"))\n",
        "    display(Markdown(response.text.replace(\"$\", \"\\\\$\")))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "5ea534893263"
      },
      "source": [
        "In the above helper function, the `while` loop handles cases in which the Gemini model predicts two or more chained Function Calls. The code within the `if` statement handles the invocation of function calls and API requests and responses. And the line of code in the `else` statement stops the Function Calling logic in the event that Gemini generates a natural language summary.\n",
        "\n",
        "### Ask questions about various companies and topics\n",
        "\n",
        "Now that you've defined your functions, initialized the Gemini model, and started a chat session, you're ready to ask questions!\n",
        "\n",
        "### Sample prompt related to stock price\n",
        "\n",
        "Start with a simple prompt that asks about a stock price:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "metadata": {
        "id": "daf9c088624e"
      },
      "outputs": [],
      "source": [
        "send_chat_message(\"What is the current stock price for Google?\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0fc0ec32b4fe"
      },
      "source": [
        "#### How it works\n",
        "\n",
        "Nice work! The output includes a concise summary of the real-time stock price for Alphabet, Inc.\n",
        "\n",
        "Let's walk through the step-by-step end process that your application code went through, from the input prompt to the output summary:\n",
        "\n",
        "1. Gemini used information within your prompt and predicted the `get_stock_price()` function along with the ticker symbol `GOOG`.\n",
        "1. Your helper function then invoked an API call to retrieve the latest stock ticker information about Alphabet Inc.\n",
        "1. Once you returned the API response to Gemini, it used this information to generate a natural language summary with the stock price of Alphabet Inc.\n",
        "\n",
        "### Sample prompt related to company information"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "metadata": {
        "id": "04f4c36f5bb5"
      },
      "outputs": [],
      "source": [
        "send_chat_message(\n",
        "    \"Give me a company overview of Google. Give a concise, high-level summary. Only use information that you learn from the API responses.\"\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "12b76d95eb48"
      },
      "source": [
        "#### How it works\n",
        "\n",
        "For this prompt, Gemini predicted the `get_company_overview()` function along with the ticker symbol `GOOG`. The logic within your helper function handled the API call, and the natural language response generated by Gemini includes information about financial metrics, a company description, and stock details.\n",
        "\n",
        "### Sample prompt for information about multiple companies\n",
        "\n",
        "Now, see what happens what you ask about two different companies:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "metadata": {
        "id": "c377e4b2d33b"
      },
      "outputs": [],
      "source": [
        "send_chat_message(\n",
        "    \"Give me a company overview of Walmart and The Home Depot. Give a concise, high-level summary. Only use information that you learn from the API responses.\"\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6989344d0365"
      },
      "source": [
        "#### How it works\n",
        "\n",
        "Great! This time, Gemini predicted the use of two subsequent function calls to `get_company_overview()`, one for each ticker symbol. The logic within your helper function handled the chained function calls, and the natural language response generated by Gemini includes information about both companies.\n",
        "\n",
        "### Sample prompt related to company news\n",
        "\n",
        "Ask a question about the latest news related to a particular company:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 18,
      "metadata": {
        "id": "50edfeabd1c4"
      },
      "outputs": [],
      "source": [
        "send_chat_message(\"What's the latest news about Google?\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8ed746e33ba0"
      },
      "source": [
        "#### How it works\n",
        "\n",
        "For this prompt, Gemini predicted the `get_company_news()` function. The logic within your helper function handled the API call, and the natural language response generated by Gemini includes the latest news related to Google.\n",
        "\n",
        "### Sample prompt related to industry news\n",
        "\n",
        "Now, try sending a prompt about news for a particular industry:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "metadata": {
        "id": "f912100fcddc"
      },
      "outputs": [],
      "source": [
        "send_chat_message(\"Has there been any exciting news related to real estate recently?\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "a94de4cd2309"
      },
      "source": [
        "#### How it works\n",
        "\n",
        "This time, Gemini predicted the `get_news_with_sentiment()` function along with the function parameter `real_estate` as defined in your `FunctionDeclaration`. The logic within your helper function handled the API call, and the natural language response generated by Gemini includes the latest news and sentiment in the real estate industry.\n",
        "\n",
        "### Summary\n",
        "\n",
        "This tutorial highlights how Gemini Function Calling helps bridge the gap between raw data and actionable insights. This functionality empowers users to ask questions in natural language, our application code makes API calls to retrieve the latest relevant information, then the Gemini model summarizes the results from one or more API calls.\n",
        "\n",
        "We're excited to see how you'll use Gemini Function calling to build generative AI applications that can help users make informed decisions, whether they are investors like Jane, or anyone who's looking to combine the power of generative AI models with reliable and up-to-date information from external data sources.\n",
        "\n",
        "Feel free to try sending additional prompts, editing the function declarations, or even adding your own. Happy Function Calling!"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "name": "use_case_company_news_and_insights.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
