code: def retry_with_exponential_backoff(
      initial_delay: float = 1,
      hour_budget: float = 0.3,
      jitter: bool = False,
      exponential_base: int = 2,
      wait_errors: tuple = (
          openai.APITimeoutError,
          openai.APIConnectionError,
          PendingFT,
      ),
      status_errors: tuple = (
          openai.APIStatusError,
          openai.APIResponseValidationError,
      ),
  ):
      """
      Wrapper to enable optional arguments. It means this decorator always needs to be called with parenthesis:
  
      > @retry_with_exponential_backoff()  # optional argument override here
      > def f(): [...]
  
      """  # noqa
  
      @profiler.profile()
      def _retry_with_exponential_backoff(func):
          """
          Exponential backoff to retry requests on a rate-limited API call, as recommended by OpenAI.
          Loops the call until a successful response or max_retries is hit or an exception is raised.
  
          Slight changes in the implementation, but originally from:
          https://github.com/openai/openai-cookbook/blob/main/examples/How_to_handle_rate_limits.ipynb
          """  # noqa
  
          def wrapper(*args, **kwargs):
              num_retries = 0
              delay = initial_delay
  
              if isinstance(hour_budget, float) or isinstance(
                  hour_budget, int
              ):
                  try:
                      max_retries = round(
                          (
                              math.log(
                                  (hour_budget * 3600) / initial_delay
                              )
                          )
                          / math.log(exponential_base)
                      )
                  except ValueError:
                      max_retries = 10
              else:
                  max_retries = 10
              max_retries = max(1, max_retries)
  
              while True:
                  try:
                      return func(*args, **kwargs)
  
                  except status_errors as e:
                      raise Exception(
                          f'Error status {e.status_code} raised by OpenAI API: {e.body.get("message", "Please refer to `https://platform.openai.com/docs/guides/error-codes` for more information.")}'  # noqa
                      )  # noqa
  
                  except wait_errors:
                      num_retries += 1
                      if num_retries > max_retries:
                          raise Exception(
                              f"Maximum number of retries ({max_retries}) exceeded."
                          )
                      # Increment the delay and wait
                      delay *= exponential_base * (
                          1 + jitter * random.random()
                      )
                      time.sleep(delay)
  
                  except openai.OpenAIError as e:
                      raise Exception(
                          f"General {str(e)} error raised by OpenAI. Please refer to `https://platform.openai.com/docs/guides/error-codes` for more information."  # noqa
                      )
  
                  except Exception as e:
                      raise e
  
          return wrapper
  
      return _retry_with_exponential_backoff
  
file_path: mindsdb/mindsdb/integrations/handlers/openai_handler/helpers.py
imports: import os
  from typing import List
  import random
  import time
  import math
  import openai
  from openai import OpenAI
  import tiktoken
  import mindsdb.utilities.profiler
  from mindsdb.integrations.handlers.openai_handler.constants import OPENAI_API_BASE
label_desc: Use image node_id 1 for calling a global function with example usage: retry_with_exponential_backoff(initial_delay, hour_budget, jitter, exponential_base, wait_errors, status_errors) and returns: _retry_with_exponential_backoff, wrapper, func