code: def completion(
      model: str,
      messages: list,
      custom_prompt_dict: dict,
      model_response: ModelResponse,
      print_verbose: Callable,
      encoding,
      logging_obj,
      optional_params=None,
      litellm_params=None,
      logger_fn=None,
  ):
      exception_mapping_worked = False
      try:
          # pop aws_secret_access_key, aws_access_key_id, aws_region_name from kwargs, since completion calls fail with them
          aws_secret_access_key = optional_params.pop(
              "aws_secret_access_key", None
          )
          aws_access_key_id = optional_params.pop(
              "aws_access_key_id", None
          )
          aws_region_name = optional_params.pop("aws_region_name", None)
          aws_bedrock_runtime_endpoint = optional_params.pop(
              "aws_bedrock_runtime_endpoint", None
          )
  
          # use passed in BedrockRuntime.Client if provided, otherwise create a new one
          client = optional_params.pop("aws_bedrock_client", None)
  
          # only init client, if user did not pass one
          if client is None:
              client = init_bedrock_client(
                  aws_access_key_id=aws_access_key_id,
                  aws_secret_access_key=aws_secret_access_key,
                  aws_region_name=aws_region_name,
                  aws_bedrock_runtime_endpoint=aws_bedrock_runtime_endpoint,
              )
  
          model = model
          modelId = (
              optional_params.pop("model_id", None) or model
          )  # default to model if not passed
          provider = model.split(".")[0]
          prompt = convert_messages_to_prompt(
              model, messages, provider, custom_prompt_dict
          )
          inference_params = copy.deepcopy(optional_params)
          stream = inference_params.pop("stream", False)
          if provider == "anthropic":
              ## LOAD CONFIG
              config = litellm.AmazonAnthropicConfig.get_config()
              for k, v in config.items():
                  if (
                      k not in inference_params
                  ):  # completion(top_k=3) > anthropic_config(top_k=3) <- allows for dynamic variables to be passed in
                      inference_params[k] = v
              data = json.dumps({"prompt": prompt, **inference_params})
          elif provider == "ai21":
              ## LOAD CONFIG
              config = litellm.AmazonAI21Config.get_config()
              for k, v in config.items():
                  if (
                      k not in inference_params
                  ):  # completion(top_k=3) > anthropic_config(top_k=3) <- allows for dynamic variables to be passed in
                      inference_params[k] = v
  
              data = json.dumps({"prompt": prompt, **inference_params})
          elif provider == "cohere":
              ## LOAD CONFIG
              config = litellm.AmazonCohereConfig.get_config()
              for k, v in config.items():
                  if (
                      k not in inference_params
                  ):  # completion(top_k=3) > anthropic_config(top_k=3) <- allows for dynamic variables to be passed in
                      inference_params[k] = v
              if optional_params.get("stream", False) == True:
                  inference_params[
                      "stream"
                  ] = True  # cohere requires stream = True in inference params
              data = json.dumps({"prompt": prompt, **inference_params})
          elif provider == "meta":
              ## LOAD CONFIG
              config = litellm.AmazonLlamaConfig.get_config()
              for k, v in config.items():
                  if (
                      k not in inference_params
                  ):  # completion(top_k=3) > anthropic_config(top_k=3) <- allows for dynamic variables to be passed in
                      inference_params[k] = v
              data = json.dumps({"prompt": prompt, **inference_params})
          elif provider == "amazon":  # amazon titan
              ## LOAD CONFIG
              config = litellm.AmazonTitanConfig.get_config()
              for k, v in config.items():
                  if (
                      k not in inference_params
                  ):  # completion(top_k=3) > amazon_config(top_k=3) <- allows for dynamic variables to be passed in
                      inference_params[k] = v
  
              data = json.dumps(
                  {
                      "inputText": prompt,
                      "textGenerationConfig": inference_params,
                  }
              )
          else:
              data = json.dumps({})
  
          ## COMPLETION CALL
          accept = "application/json"
          contentType = "application/json"
          if stream == True:
              if provider == "ai21":
                  ## LOGGING
                  request_str = f"""
                  response = client.invoke_model(
                      body={data},
                      modelId={modelId},
                      accept=accept,
                      contentType=contentType
                  )
                  """
                  logging_obj.pre_call(
                      input=prompt,
                      api_key="",
                      additional_args={
                          "complete_input_dict": data,
                          "request_str": request_str,
                      },
                  )
  
                  response = client.invoke_model(
                      body=data,
                      modelId=modelId,
                      accept=accept,
                      contentType=contentType,
                  )
  
                  response = response.get("body").read()
                  return response
              else:
                  ## LOGGING
                  request_str = f"""
                  response = client.invoke_model_with_response_stream(
                      body={data},
                      modelId={modelId},
                      accept=accept,
                      contentType=contentType
                  )
                  """
                  logging_obj.pre_call(
                      input=prompt,
                      api_key="",
                      additional_args={
                          "complete_input_dict": data,
                          "request_str": request_str,
                      },
                  )
  
                  response = client.invoke_model_with_response_stream(
                      body=data,
                      modelId=modelId,
                      accept=accept,
                      contentType=contentType,
                  )
                  response = response.get("body")
                  return response
          try:
              ## LOGGING
              request_str = f"""
              response = client.invoke_model(
                  body={data},
                  modelId={modelId},
                  accept=accept,
                  contentType=contentType
              )
              """
              logging_obj.pre_call(
                  input=prompt,
                  api_key="",
                  additional_args={
                      "complete_input_dict": data,
                      "request_str": request_str,
                  },
              )
              response = client.invoke_model(
                  body=data,
                  modelId=modelId,
                  accept=accept,
                  contentType=contentType,
              )
          except client.exceptions.ValidationException as e:
              if "The provided model identifier is invalid" in str(e):
                  raise BedrockError(status_code=404, message=str(e))
              raise BedrockError(status_code=400, message=str(e))
          except Exception as e:
              raise BedrockError(status_code=500, message=str(e))
  
          response_body = json.loads(response.get("body").read())
  
          ## LOGGING
          logging_obj.post_call(
              input=prompt,
              api_key="",
              original_response=json.dumps(response_body),
              additional_args={"complete_input_dict": data},
          )
          print_verbose(f"raw model_response: {response}")
          ## RESPONSE OBJECT
          outputText = "default"
          if provider == "ai21":
              outputText = (
                  response_body.get("completions")[0]
                  .get("data")
                  .get("text")
              )
          elif provider == "anthropic":
              outputText = response_body["completion"]
              model_response["finish_reason"] = response_body[
                  "stop_reason"
              ]
          elif provider == "cohere":
              outputText = response_body["generations"][0]["text"]
          elif provider == "meta":
              outputText = response_body["generation"]
          else:  # amazon titan
              outputText = response_body.get("results")[0].get(
                  "outputText"
              )
  
          response_metadata = response.get("ResponseMetadata", {})
          if response_metadata.get("HTTPStatusCode", 500) >= 400:
              raise BedrockError(
                  message=outputText,
                  status_code=response_metadata.get(
                      "HTTPStatusCode", 500
                  ),
              )
          else:
              try:
                  if len(outputText) > 0:
                      model_response["choices"][0]["message"][
                          "content"
                      ] = outputText
              except:
                  raise BedrockError(
                      message=json.dumps(outputText),
                      status_code=response_metadata.get(
                          "HTTPStatusCode", 500
                      ),
                  )
  
          ## CALCULATING USAGE - baseten charges on time, not tokens - have some mapping of cost here.
          prompt_tokens = len(encoding.encode(prompt))
          completion_tokens = len(
              encoding.encode(
                  model_response["choices"][0]["message"].get(
                      "content", ""
                  )
              )
          )
  
          model_response["created"] = int(time.time())
          model_response["model"] = model
          usage = Usage(
              prompt_tokens=prompt_tokens,
              completion_tokens=completion_tokens,
              total_tokens=prompt_tokens + completion_tokens,
          )
          model_response.usage = usage
          return model_response
      except BedrockError as e:
          exception_mapping_worked = True
          raise e
      except Exception as e:
          if exception_mapping_worked:
              raise e
          else:
              import traceback
  
              raise BedrockError(
                  status_code=500, message=traceback.format_exc()
              )
  
imports: import json, copy, types
  import os
  from enum import Enum
  import time
  from typing import Callable, Optional, Any, Union
  import litellm
  from litellm.utils import ModelResponse, get_secret, Usage
  from .prompt_templates.factory import prompt_factory, custom_prompt
  import httpx
label_desc: Use image node_id 3 for calling a global function with example usage: completion(model, messages, custom_prompt_dict, model_response, print_verbose, encoding, logging_obj, optional_params, litellm_params, logger_fn) and returns: model_response, response, response