def calculate_num_tokens(
    messages: List[Dict[str, Union[str, Dict[str, str], List[Dict[str, str]]]]],
    model: str = GPT_3_5_TURBO_0613_MODEL,
) -> int:
    """Returns the number of tokens used by a list of messages."""
    try:
        encoding = tiktoken.encoding_for_model(model)
    except KeyError:
        encoding = tiktoken.get_encoding("cl100k_base")
    num_tokens = 0

    # Handle model-specific tokens per message and name
    model_tokens: Optional[Tuple[int, int]] = MODEL_TOKENS.get(model, None)
    if model_tokens is None:
        fallback_result = None
        if model in MODEL_FALLBACKS:
            actual_model = MODEL_FALLBACKS[model]
            fallback_result = calculate_num_tokens(messages, model=actual_model)
        if fallback_result is not None:
            return fallback_result
        error = (
            f"Calculating the number of tokens for model {model} is not yet supported. "
            "See https://github.com/openai/openai-python/blob/main/chatml.md "
            "for information on how messages are converted to tokens."
        )
        raise NotImplementedError(error)

    tokens_per_message, tokens_per_name = model_tokens

    for message in messages:
        num_tokens += tokens_per_message
        for key, value in message.items():
            if key == "function_call":
                num_tokens += (
                    1
                    + len(encoding.encode(value["name"]))
                    + len(encoding.encode(value["arguments"]))
                )
            else:
                num_tokens += encode_and_count_tokens(value, encoding)
            if key == "name":
                num_tokens += tokens_per_name

    num_tokens += 3  # every reply is primed with <|im_start|>assistant<|im_sep|>

    return num_tokens
Returns the number of tokens used by a list of messages.
app/openai_ops.py