DEV Community

Harshit Kedia
Harshit Kedia

Posted on

Function calling with Google Gemini chat AI

Function calling enables developers to incorporte custom functions or APIs with a generative AI chat application

The AI model decides if any of the functions and APIs is useful for answering the user query, and the AI model responds with the functions and their arguments to be used
The functions need to be well described with the arguments, their argument data types and the returning values
In this tutorial we will explore parallel function calling with Python, using Google Gemini AI, with external APIs providing city's population and country's currency used, for answering user questions
import requests
import json
import google.generativeai as genai
Enter fullscreen mode Exit fullscreen mode

Add your API key and select the model

genai.configure(api_key="YOUR API KEY")
model = genai.GenerativeModel("gemini-1.5-flash")
response = model.generate_content("What is the date today?")
print(response.text)
Enter fullscreen mode Exit fullscreen mode
Today is October 26, 2023.
Enter fullscreen mode Exit fullscreen mode

Define function to be used in function calling

#### Ensure to specify the datatype of arguments used in the function,
#### otherwise it will give error in function calling

def set_light_values(brightness: int, color_temp: str):
    """Set the brightness and color temperature of a room light. (mock API).

    Args:
        brightness: Light level from 0 to 100. Zero is off and 100 is full brightness
        color_temp: Color temperature of the light fixture, which can be `daylight`, `cool` or `warm`.

    Returns:
        A dictionary containing the set brightness and color temperature.
    """
    return {
        "brightness": brightness,
        "colorTemperature": color_temp
    }

Enter fullscreen mode Exit fullscreen mode
set_light_values(brightness=30,color_temp="daylight")
Enter fullscreen mode Exit fullscreen mode
{'brightness': 30, 'colorTemperature': 'daylight'}
Enter fullscreen mode Exit fullscreen mode

Select the model and specify the tool to be used in function calling

model = genai.GenerativeModel(model_name='gemini-1.5-flash',
                              tools=[set_light_values])

Enter fullscreen mode Exit fullscreen mode

The response generated from the input will contain the suggested functions and arguments the chat model suggests

chat = model.start_chat()
response = chat.send_message('Dim the lights so the room feels cozy and warm.')

Enter fullscreen mode Exit fullscreen mode
response
Enter fullscreen mode Exit fullscreen mode
response:
GenerateContentResponse(
    done=True,
    iterator=None,
    result=protos.GenerateContentResponse({
      "candidates": [
        {
          "content": {
            "parts": [
              {
                "function_call": {
                  "name": "set_light_values",
                  "args": {
                    "brightness": 30.0,
                    "color_temp": "warm"
                  }
                }
              }
            ],
            "role": "model"
          },
          "finish_reason": "STOP",
          "avg_logprobs": -0.0008751733228564262
        }
      ],
      "usage_metadata": {
        "prompt_token_count": 150,
        "candidates_token_count": 10,
        "total_token_count": 160
      }
    }),
)
Enter fullscreen mode Exit fullscreen mode

Evaluate the functions with the arguments the chat model suggests and store the functions with their corresponding values returned, as a JSON object

def function_used_and_their_outputs(functions,response):
  for part in response.parts:
      #### in every iteration, fn is assigned a function used by AI during the function call
      if fn := part.function_call:
          #### args gets assigned a string value like "brightness=30.0, color_temp='warm'",
          #### repr() is used to add quotes to the keys like 'warm',
          #### repr() is used so string value keys are treated as string, not variable
          args = ", ".join(f"{key}={repr(val)}" for key, val in fn.args.items())
          print("arguments are: ", args)
          #### Function is being generated using f strings
          function_to_be_called = f"{fn.name}({args})"
          print("function being called using eval, with arguments: ", function_to_be_called)
          output=eval(function_to_be_called)
          functions[fn.name]=output
Enter fullscreen mode Exit fullscreen mode
house_functions={}
function_used_and_their_outputs(house_functions,response)
house_functions
Enter fullscreen mode Exit fullscreen mode
arguments are:  brightness=30.0, color_temp='warm'
function being called using eval, with arguments:  set_light_values(brightness=30.0, color_temp='warm')





{'set_light_values': {'brightness': 30.0, 'colorTemperature': 'warm'}}
Enter fullscreen mode Exit fullscreen mode

Provide the JSON object back to the generative chat function to get AI generated response processing the outputs of the functions

def response_based_on_used_functions(functions):
  response_parts = [
      genai.protos.Part(function_response=genai.protos.FunctionResponse(name=fn, response={"result": val}))
      for fn, val in functions.items()
  ]

  response = chat.send_message(response_parts)
  print(response.text)

response_based_on_used_functions(house_functions)
Enter fullscreen mode Exit fullscreen mode
OK. I've dimmed the lights to 30% brightness and set the color temperature to warm.  Is there anything else?
Enter fullscreen mode Exit fullscreen mode

Defining functions to get population and currency of input city and country respectively

def get_population(city: str):
  """Gets population of a city and year of count.

  Args:
    city: The name of the city.

  Returns:
    JSON object encapsulating the population of the city and year of count if function executed successfully, else, an error message.
  """
  url = "https://countriesnow.space/api/v0.1/countries/population/cities"

  payload = {"city": city}
  headers = {}

  response = requests.request("POST", url, headers=headers, data=payload)
  json_data=json.loads(response.text)

  if json_data['error']:
    return json_data['msg']
  else:
    return {'population':json_data['data']['populationCounts'][0]['value'],'year of counting':json_data['data']['populationCounts'][0]['year']}
Enter fullscreen mode Exit fullscreen mode
get_population('amsterdam')
Enter fullscreen mode Exit fullscreen mode
{'population': '779808', 'year of counting': '2011'}
Enter fullscreen mode Exit fullscreen mode
def get_currency(country_code: str):
  """Gets information about the currency used in the country

  Args:
      country_code (str): The alphabetical country code of the country, eg.: if referring to Nigeria, then argument passed will be its alphabetical country code NG

  Returns:
    JSON object encapsulating the currency used in the country if function executed successfully, else, an error message is returned.
  """
  url = "https://countriesnow.space/api/v0.1/countries/currency"

  payload = {"iso2":country_code}
  headers = {}

  response = requests.request("POST", url, headers=headers, data=payload)

  json_data=json.loads(response.text)

  if json_data['error']:
    return json_data['msg']
  else:
    return json_data['data']['currency']
Enter fullscreen mode Exit fullscreen mode
get_currency('pk')
Enter fullscreen mode Exit fullscreen mode
'PKR'
Enter fullscreen mode Exit fullscreen mode
demography_functions=[get_population, get_currency]
model = genai.GenerativeModel(model_name="gemini-1.5-flash", tools=demography_functions)

Enter fullscreen mode Exit fullscreen mode
chat = model.start_chat()
Enter fullscreen mode Exit fullscreen mode

In the following example, notice that both, the population and currency functions are being called by the AI chat when population and currency are being asked by user, also notice that the AI is using its own knowledge to identify the country in which the city asked by the user is located, to send the corresponding country code as the argument to the currency function

response = chat.send_message('Tell about the population and currency used in delhi')
demography_functions_used={}
function_used_and_their_outputs(demography_functions_used,response)
demography_functions_used
Enter fullscreen mode Exit fullscreen mode
arguments are:  city='Delhi'
function being called using eval, with arguments:  get_population(city='Delhi')
arguments are:  country_code='IN'
function being called using eval, with arguments:  get_currency(country_code='IN')





{'get_population': {'population': '9879172', 'year of counting': '2001'},
 'get_currency': 'INR'}
Enter fullscreen mode Exit fullscreen mode
response_based_on_used_functions(demography_functions_used)
Enter fullscreen mode Exit fullscreen mode
The population of Delhi was 9,879,172 in 2001. The currency used in India, where Delhi is located, is the Indian Rupee (INR).
Enter fullscreen mode Exit fullscreen mode

In the following 2 examples, notice that only the population function is being called by the AI chat when only population is asked by user

response = chat.send_message('Tell about the population of Tokyo')
demography_functions_used={}
function_used_and_their_outputs(demography_functions_used,response)
response_based_on_used_functions(demography_functions_used)
Enter fullscreen mode Exit fullscreen mode
arguments are:  city='Tokyo'
function being called using eval, with arguments:  get_population(city='Tokyo')
The population of Tokyo was 8,945,695 in 2010.
Enter fullscreen mode Exit fullscreen mode
Due to some reason, the API isn't able to fetch the population of New York, which the AI chat achnowledges
response = chat.send_message('Tell about the population of new york')
demography_functions_used={}
function_used_and_their_outputs(demography_functions_used,response)
response_based_on_used_functions(demography_functions_used)
Enter fullscreen mode Exit fullscreen mode
arguments are:  city='New York'
function being called using eval, with arguments:  get_population(city='New York')
I'm sorry, I couldn't find information about the population of New York.
Enter fullscreen mode Exit fullscreen mode

In the following examples, notice that only the currency function is being called by the AI chat when only currency is asked by user

response = chat.send_message('Tell about the currency of london')
demography_functions_used={}
function_used_and_their_outputs(demography_functions_used,response)
response_based_on_used_functions(demography_functions_used)
Enter fullscreen mode Exit fullscreen mode
arguments are:  country_code='GB'
function being called using eval, with arguments:  get_currency(country_code='GB')
The currency used in London, United Kingdom is the British Pound (GBP).
Enter fullscreen mode Exit fullscreen mode

– I am Harshit from India. I am exploring generative AI, data science and machine learning. To collaborate, let's connect on linkedin and twitter 😊

Top comments (0)