diff --git a/quickstarts/Error_handling.ipynb b/quickstarts/Error_handling.ipynb new file mode 100644 index 00000000..03413db5 --- /dev/null +++ b/quickstarts/Error_handling.ipynb @@ -0,0 +1,312 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "8968a502d25e" + }, + "source": [ + "##### Copyright 2024 Google LLC." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "a73f56372655" + }, + "outputs": [], + "source": [ + "# @title 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": "35219116d3b3" + }, + "source": [ + "# Gemini API: Error handling" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "571fb2e6d4ba" + }, + "source": [ + "\n", + " \n", + "
\n", + " Run in Google Colab\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "b58341384860" + }, + "source": [ + "This Colab notebook demonstrates strategies for handling common errors you might encounter when working with the Gemini API:\n", + "\n", + "* **Transient Errors:** Temporary failures due to network issues, server overload, etc.\n", + "* **Rate Limits:** Restrictions on the number of requests you can make within a certain timeframe.\n", + "* **Timeouts:** When an API call takes too long to complete.\n", + "\n", + "You have two main approaches to explore:\n", + "\n", + "1. **Automatic retries:** A simple way to retry requests when they fail due to transient errors.\n", + "2. **Manual backoff and retry:** A more customizable approach that provides finer control over retry behavior.\n", + "\n", + "\n", + "**Gemini Rate Limits**\n", + "\n", + "The default rate limits for different Gemini models are outlined in the [Gemini API model documentation](https://ai.google.dev/gemini-api/docs/models/gemini#model-variations). If your application requires a higher quota, consider [requesting a rate limit increase](https://ai.google.dev/gemini-api/docs/quota)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "b2bb83e651f4" + }, + "outputs": [], + "source": [ + "!pip install -U google-generativeai" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "34bf10124280" + }, + "outputs": [], + "source": [ + "import google.generativeai as genai" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "cf16b627705c" + }, + "source": [ + "### Setup your API key\n", + "\n", + "To run the following cells, store your API key in a Colab Secret named `GOOGLE_API_KEY`. If you don't have an API key or need help creating a Colab Secret, see the [Authentication](https://github.com/google-gemini/cookbook/blob/main/quickstarts/Authentication.ipynb) guide." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "34e7b42a93e3" + }, + "outputs": [], + "source": [ + "from google.colab import userdata\n", + "\n", + "GOOGLE_API_KEY = userdata.get(\"GOOGLE_API_KEY\")\n", + "genai.configure(api_key=GOOGLE_API_KEY)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "89d975abf7a2" + }, + "source": [ + "### Automatic retries\n", + "\n", + "The Gemini API's client library offers built-in retry mechanisms for handling transient errors. You can enable this feature by using the `request_options` argument with API calls like `generate_content`, `generate_answer`, `embed_content`, and `generate_content_async`.\n", + "\n", + "**Advantages:**\n", + "\n", + "* **Simplicity:** Requires minimal code changes for significant reliability gains.\n", + "* **Robust:** Effectively addresses most transient errors without additional logic.\n", + "\n", + "**Customize retry behavior:**\n", + "\n", + "Use these settings in [`retry`](https://googleapis.dev/python/google-api-core/latest/retry.html) to customize retry behavior:\n", + "\n", + "* `predicate`: (callable) Determines if an exception is retryable. Default: [`if_transient_error`](https://github.com/googleapis/python-api-core/blob/main/google/api_core/retry/retry_base.py#L75C4-L75C13)\n", + "* `initial`: (float) Initial delay in seconds before the first retry. Default: `1.0`\n", + "* `maximum`: (float) Maximum delay in seconds between retries. Default: `60.0`\n", + "* `multiplier`: (float) Factor by which the delay increases after each retry. Default: `2.0`\n", + "* `timeout`: (float) Total retry duration in seconds. Default: `120.0`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "09d14986b9cf" + }, + "outputs": [], + "source": [ + "from google.api_core import retry\n", + "\n", + "model = genai.GenerativeModel(\"gemini-1.5-flash-latest\")\n", + "prompt = \"Write a story about a magic backpack.\"\n", + "\n", + "model.generate_content(\n", + " prompt, request_options={\"retry\": retry.Retry(predicate=retry.if_transient_error)}\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "1abafce2315c" + }, + "source": [ + "### Manually increase timeout when responses take time\n", + "\n", + "If you encounter `ReadTimeout` or `DeadlineExceeded` errors, meaning an API call exceeds the default timeout (600 seconds), you can manually adjust it by defining `timeout` in the `request_options` argument." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "5bdc7450fcd8" + }, + "outputs": [], + "source": [ + "model = genai.GenerativeModel(\"gemini-1.5-flash-latest\")\n", + "prompt = \"Write a story about a magic backpack.\"\n", + "\n", + "model.generate_content(\n", + " prompt, request_options={\"timeout\": 900}\n", + ") # Increase timeout to 15 minutes" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "c27ccc71fa27" + }, + "source": [ + "**Caution:** While increasing timeouts can be helpful, be mindful of setting them too high, as this can delay error detection and potentially waste resources." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "69dd9fd7f359" + }, + "source": [ + "### Manually implement backoff and retry with error handling\n", + "\n", + "For finer control over retry behavior and error handling, you can use the [`retry`](https://googleapis.dev/python/google-api-core/latest/retry.html) library (or similar libraries like [`backoff`](https://pypi.org/project/backoff/) and [`tenacity`](https://tenacity.readthedocs.io/en/latest/)). This gives you precise control over retry strategies and allows you to handle specific types of errors differently." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "c134fc5aaecc" + }, + "outputs": [], + "source": [ + "from google.api_core import retry, exceptions\n", + "\n", + "model = genai.GenerativeModel(\"gemini-1.5-flash-latest\")\n", + "\n", + "\n", + "@retry.Retry(\n", + " predicate=retry.if_transient_error,\n", + " initial=2.0,\n", + " maximum=64.0,\n", + " multiplier=2.0,\n", + " timeout=600,\n", + ")\n", + "def generate_with_retry(model, prompt):\n", + " response = model.generate_content(prompt)\n", + " return response\n", + "\n", + "\n", + "prompt = \"Write a one-liner advertisement for magic backpack.\"\n", + "\n", + "generate_with_retry(model=model, prompt=prompt)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "85fc3d0bae17" + }, + "source": [ + "### Test the error handling with retry mechanism\n", + "\n", + "To validate that your error handling and retry mechanism work as intended, define a `generate_content` function that deliberately raises a `ServiceUnavailable` error on the first call. This setup will help you ensure that the retry decorator successfully handles the transient error and retries the operation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "981415e25158" + }, + "outputs": [], + "source": [ + "from google.api_core import retry, exceptions\n", + "\n", + "\n", + "@retry.Retry(\n", + " predicate=retry.if_transient_error,\n", + " initial=2.0,\n", + " maximum=64.0,\n", + " multiplier=2.0,\n", + " timeout=600,\n", + ")\n", + "def generate_content_first_fail(model, prompt):\n", + " if not hasattr(generate_content_first_fail, \"call_counter\"):\n", + " generate_content_first_fail.call_counter = 0\n", + "\n", + " generate_content_first_fail.call_counter += 1\n", + "\n", + " try:\n", + " if generate_content_first_fail.call_counter == 1:\n", + " raise exceptions.ServiceUnavailable(\"Service Unavailable\")\n", + "\n", + " response = model.generate_content(prompt)\n", + " return response.text\n", + " except exceptions.ServiceUnavailable as e:\n", + " print(f\"Error: {e}\")\n", + " raise\n", + "\n", + "\n", + "model = genai.GenerativeModel(\"gemini-1.5-flash-latest\")\n", + "prompt = \"Write a one-liner advertisement for magic backpack.\"\n", + "\n", + "generate_content_first_fail(model=model, prompt=prompt)" + ] + } + ], + "metadata": { + "colab": { + "name": "Error_handling.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +}