Since I could not find any example that would be easy to understand and build upon i created this little script that shows the work flow
# -*- coding: utf-8 -*-
import google.generativeai as genai
genai.configure(api_key=' key')
import os
import json
# Define color codes for terminal output
# Define color codes for terminal output
reset = "\033[0m"
black = "\033[30m"
red = "\033[31m"
green = "\033[32m"
yellow = "\033[33m"
blue = "\033[34m"
magenta = "\033[35m"
cyan = "\033[36m"
white = "\033[37m"
bright_black = "\033[90m"
bright_red = "\033[91m"
bright_green = "\033[92m"
bright_yellow = "\033[93m"
bright_blue = "\033[94m"
bright_magenta = "\033[95m"
bright_cyan = "\033[96m"
bright_white = "\033[97m"
messages = []
def multiply(a: float, b: float):
"""Returns the product of two numbers."""
return a * b
# Example usage
multiply_description = {
'function_declarations': [
{
'name': 'multiply',
'description': 'Returns the product of two numbers.',
'parameters': {
'type_': 'OBJECT',
'properties': {
'a': {'type_': 'NUMBER'},
'b': {'type_': 'NUMBER'}
},
'required': ['a', 'b']
}
}
]
}
def save_to_file(content: str = None, file_name: str = 'NoName', file_path: str = None):
print(f"{blue}Entering: save_to_file(...)")
"""Saves content to a file and returns detailed execution result.
Args:
content (str): The content to save.
file_name (str, optional): The name of the file. Defaults to 'NoName'.
file_path (str, optional): The path to save the file. Defaults to the current working directory if not provided.
Returns:
dict: A dictionary containing the status, message, and file path if successful.
"""
if content is None:
content = ""
if file_path is None:
full_path = os.path.join(os.getcwd(), file_name)
else:
full_path = os.path.join(file_path, file_name)
try:
with open(full_path, 'w', encoding='utf-8') as f:
f.write(content)
success_message = f"File saved successfully at: {full_path}"
print(f"{green}{success_message}")
print(f"{blue}Exiting: save_to_file(...)")
return {"status": "success", "message": success_message, "file_path": full_path}
except Exception as e:
error_message = f"Failed to save file: {str(e)}"
print(f"{red}{error_message}")
print(f"{blue}Exiting: save_to_file(...)")
return {"status": "failure", "message": error_message}
save_to_file_description = {
'function_declarations': [
{
'name': 'save_to_file',
'description': 'Saves content to a file.',
'parameters': {
'type_': 'OBJECT',
'properties': {
'content': {'type_': 'STRING'},
'file_name': {'type_': 'STRING', 'description': 'The name of the file. Defaults to "NoName".'},
'file_path': {'type_': 'STRING',
'description': 'The path to save the file. Defaults to the current working directory if not provided.'}
},
'required': []
}
}
]
}
function_mapping = {
'multiply': multiply,
'save_to_file': save_to_file
}
model = genai.GenerativeModel(
system_instruction="You are a helpful assistant. Never use emojis. You can save files using functions!",
model_name='gemini-1.5-pro-latest',
safety_settings={'HARASSMENT': 'block_none'},
tools=[multiply_description, save_to_file_description]
)
def interpreter(response):
print(f"{bright_yellow}----------------INTERPRETER START----------------------")
"""
Interprets the model's response, extracts function details,
and executes the appropriate function with the provided arguments.
"""
Multiple_ResultsOfFunctions_From_interpreter = []
if response.candidates:
for part in response.candidates[0].content.parts:
if hasattr(part, 'function_call'):
function_call = part.function_call
function_name = function_call.name
function_args = function_call.args
function_to_call = function_mapping.get(function_name)
print(f"FUNCTION CALL: {function_name}({function_args}) ")
try:
results = function_to_call(**function_args)
except TypeError as e:
results = f"TypeError: {e}"
except Exception as e:
results = f"Exception: {e}"
print(f"{bright_blue}Function Call Exit: {function_name}")
function_name_arguments = f"{function_name}({function_args})"
modified_results = f"Result of Called function {function_name_arguments}: {results}"
Multiple_ResultsOfFunctions_From_interpreter.append(modified_results)
print(f"{bright_yellow}----------------INTERPRETER END------------------------")
print()
return Multiple_ResultsOfFunctions_From_interpreter
chat1 = model.start_chat(history=[])
while True:
user_input = input(f"{bright_green}user input (type 'exit' to quit): {reset}")
if user_input.lower() == 'exit':
break
try:
response = chat1.send_message(user_input)
print(f"{bright_magenta}Model Response: {response}")
try:
results = interpreter(response)
print(f"{bright_cyan}Results of Interpreter and Called Functions: {results}")
except Exception as e:
print(f"{bright_red}Error with interpreter: {e}")
except Exception as e:
print(f"{bright_red}An error occurred: {e}")
print(f"{bright_yellow}Exiting the program.")
- Define the New Function:
-
Create a Python function with a descriptive name and parameters.
-
Include a docstring that clearly explains what the function does.
- Create a Description for the Function (Function Description Variable):
-
Create a separate variable with the function name appended with “_description” (e.g., multiply_description).
-
Define a dictionary within this variable that includes the following:
-
function_declarations: A list containing a dictionary representing the function’s details:
-
name: The name of the function.
-
description: A textual description of the function.
-
parameters: A dictionary defining the parameters:
-
type_: The data type of the parameter (e.g., “NUMBER”, “STRING”, “OBJECT”).
-
properties: (For object types) A dictionary defining the properties of the object.
-
required: A list of required parameters (if any).
-
-
-
- Add the Function to the Function Mapping (Function Mapping Dictionary):
-
Update the function_mapping dictionary, which maps function names to their corresponding implementations.
-
Add a new entry with the function name as the key and the function itself as the value.
- Update the Model with the New Function Description (LLM’s Tools):
-
Pass the function description variable (e.g., multiply_description) to the tools parameter when creating the genai.GenerativeModel instance.
-
The LLM will now be aware of the new function and its capabilities.
- Ensure the Function Provides Execution Results:
-
The function should return a meaningful result that can be used in subsequent interactions.
-
The interpreter handles function execution and returns the result to the LLM, making it available for further processing or inclusion in the next prompt.
Example:
def multiply(a: float, b: float):
"""Returns the product of two numbers."""
return a * b
multiply_description = {
'function_declarations': [
{
'name': 'multiply',
'description': 'Returns the product of two numbers.',
'parameters': {
'type_': 'OBJECT',
'properties': {
'a': {'type_': 'NUMBER'},
'b': {'type_': 'NUMBER'}
},
'required': ['a', 'b']
}
}
]
}
function_mapping = {
'multiply': multiply,
# ... other functions
}
model = genai.GenerativeModel(
# ... other parameters
tools=[multiply_description, # ... other function descriptions]
)
if you have ideas about better workflow dont hesitate to speak!