from typing import Final from litellm.types.llms.openai import CreateFileRequest from litellm.types.utils import ExtractedFileData # MIME types a .jsonl batch upload is plausibly labeled with. Clients are # inconsistent (text/plain, application/json, octet-stream, ndjson, ...), so a # batch file must not silently bypass the streaming path just because of its # declared type. ``purpose == "batch"`` is the authoritative signal; non-JSONL # content still fails loudly when the rows are parsed. _BATCH_JSONL_CONTENT_TYPES: Final = frozenset( { "application/jsonl", "application/json", "application/octet-stream", "application/x-ndjson", "application/x-jsonlines", "text/plain", } ) class FilesAPIUtils: """ Utils for files API interface on litellm """ @staticmethod def is_batch_jsonl_file(create_file_data: CreateFileRequest, extracted_file_data: ExtractedFileData) -> bool: """ Check if the file is a batch jsonl file """ return ( create_file_data.get("purpose") == "batch" and FilesAPIUtils.valid_content_type(extracted_file_data.get("content_type")) and extracted_file_data.get("content") is not None ) @staticmethod def is_batch_jsonl_request(create_file_data: CreateFileRequest, content_type: str | None) -> bool: """ Batch-jsonl check from metadata only, so the body can stay a streamable Path/handle instead of being read into memory. """ return ( create_file_data.get("purpose") == "batch" and FilesAPIUtils.valid_content_type(content_type) and create_file_data.get("file") is not None ) @staticmethod def valid_content_type(content_type: str | None) -> bool: """ Whether the upload's MIME type is one a batch JSONL file is plausibly sent as (see ``_BATCH_JSONL_CONTENT_TYPES``). """ return content_type in _BATCH_JSONL_CONTENT_TYPES