Source code for steamship.utils.context_length
import logging
from typing import List
import tiktoken
from steamship import Block, SteamshipError
from steamship.data.tags.tag_constants import RoleTag
[docs]
def token_length(block: Block, tiktoken_encoder: str = "p50k_base") -> int:
"""Calculate num tokens with tiktoken package."""
# create a GPT-3 encoder instance
enc = tiktoken.get_encoding(tiktoken_encoder)
# encode the text using the GPT-3 encoder
tokenized_text = enc.encode(block.text)
# calculate the number of tokens in the encoded text
return len(tokenized_text)
# TODO: abstract this into one of N possible strategies
[docs]
def filter_blocks_for_prompt_length(max_tokens: int, blocks: List[Block]) -> List[int]:
retained_blocks = []
total_length = 0
# Keep all system blocks
for block in blocks:
if block.chat_role == RoleTag.SYSTEM:
retained_blocks.append(block)
total_length += token_length(block)
# If system blocks are too long, throw error
if total_length > max_tokens:
raise SteamshipError(
f"Plugin attempted to filter input to fit into {max_tokens} tokens, but the total size of system blocks was {total_length}"
)
# Now work backwards and keep as many blocks as we can
num_system_blocks = len(retained_blocks)
for block in reversed(blocks):
if block.chat_role != RoleTag.SYSTEM and total_length < max_tokens:
block_length = token_length(block)
if block_length + total_length < max_tokens:
retained_blocks.append(block)
total_length += block_length
logging.info(f"Adding block {block.index_in_file} of token length {block_length}")
# If we didn't add any non-system blocks, throw error
if len(retained_blocks) == num_system_blocks:
raise SteamshipError(
f"Plugin attempted to filter input to fit into {max_tokens} tokens, but no non-System blocks remained."
)
block_indices = [block.index_in_file for block in blocks if block in retained_blocks]
logging.info(f"Filtered input. Total tokens {total_length} Block indices: {block_indices}")
return block_indices