You can use media sets in Python transforms for PDF text extraction, optical character recognition (OCR), image tiling, metadata parsing, and more. The following sections explain how to set up media sets in your Python repository and how to read to and write from media sets with Python transforms.
To use decorators specific to media sets, you first need to import the transforms-media
library into your repository. You can do this by navigating to the Libraries file drawer on the left side of the Code Repositories interface. Search for transforms-media
, then install the library.
transforms-media
in your code repository.You must use the @transform
decorator when working with media sets. Media set inputs and outputs can be passed in using transforms.mediasets.MediaSetInput
and transforms.mediasets.MediaSetOutput
specifications. During a build, these specifications are resolved into transforms.mediasets.MediaSetInputParam
and transforms.mediasets.MediaSetOutputParam
objects, respectively. These MediaSetInputParam
and MediaSetOutputParam
objects provide access to the media set within the compute function. Any number of media set inputs or outputs can be used in combination with any other valid transform inputs and outputs (such as tabular datasets). For example:
Copied!1 2 3 4 5 6 7 8
from transforms.api import transform from transforms.mediasets import MediaSetInput, MediaSetOutput @transform( images=MediaSetInput('/examples/images'), output_images=MediaSetOutput('/examples/output_images') ) def translate_images(images, output_images): ...
You can access individual media items either by the file path or RID:
Copied!1 2 3 4 5 6 7 8 9 10
from transforms.api import transform from transforms.mediasets import MediaSetInput, MediaSetOutput @transform( images=MediaSetInput('/examples/images'), output_images=MediaSetOutput('/examples/output_images') ) def translate_images(images, output_images): image1 = images.get_media_item_by_path("image1") image2 = images.get_media_item("ri.mio.main.media-item.123") ...
However, you will likely want to transform all the items in your media set. To do this, you must first pull the items into a dataframe using a listing method. In the example below, we list all items in the input media set and write the resulting dataframe to a tabular output:
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13
from transforms.api import transform, Output from transforms.mediasets import MediaSetInput @transform( images=MediaSetInput('/examples/images'), listing_output=Output('/examples/listed_images') ) def translate_images(ctx, images, listing_output): media_items_listing = images.list_media_items_by_path_with_media_reference(ctx) # You can perform regular PySpark transformations on media_items_listing column_typeclasses = {'mediaReference': [{'kind': 'reference', 'name': 'media_reference'}]} listing_output.write_dataframe(media_items_listing, column_typeclasses=column_typeclasses)
If multiple items in the media set are at a particular path, only the most recent will be included in the listing. The listing will have the following schema:
+--------------------------+-----------+-------------------+
| mediaItemRid | path | mediaReference |
+--------------------------+-----------+-------------------+
| ri.mio.main.media-item.1 | item1.jpg | {{reference1}} |
| ri.mio.main.media-item.2 | item2.jpg | {{reference2}} |
| ri.mio.main.media-item.3 | item3.jpg | {{reference3}} |
+--------------------------+-----------+-------------------+
Note that the above example only shows the top three rows of the listing.
By setting the typeclass of the mediaReference
column, we allow the column to be read as a media reference.
Calls to get_media_item()
, get_media_item_by_path()
, and so on return a Python file-like stream object. All options accepted by io.open()
↗ are also supported. Note that items are read as streams, meaning that random access is not supported.
You can also return metadata about individual media items without downloading the full item. The metadata will include information such as the dimensions for images, length for audio, and more. For a full reference of available metadata, see the appendix below. The example below adds a column to the media item listing with the metadata for each image.
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
from transforms.api import transform, Output from transforms.mediasets import MediaSetInput from pyspark.sql import functions as F from pyspark.sql.types import StringType from conjure_python_client import ConjureEncoder @transform( images=MediaSetInput('/examples/images'), listing_output_with_metadata=Output('/examples/listed_images_with_metadata') ) def translate_images(ctx, images, listing_output_with_metadata): def get_metadata(media_item_rid): metadata = images.get_media_item_metadata(media_item_rid) return ConjureEncoder().default(metadata) metadata_udf = F.udf(get_metadata, StringType()) media_items_listing = images.list_media_items_by_path_with_media_reference(ctx) listing_with_metadata = media_items_listing.withColumn('metadata', metadata_udf(F.col('mediaItemRid'))) column_typeclasses = {'mediaReference': [{'kind': 'reference', 'name': 'media_reference'}]} listing_output_with_metadata.write_dataframe(listing_with_metadata, column_typeclasses=column_typeclasses)
Media sets support a certain number of built-in transformations out of the box. See the appendix below for the API and list of supported transformations. Calls to these transformations will also return a Python file-like stream object. To use these built-in transformations, call the appropriate method on the media set input. For example:
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
@transform( images=MediaSetInput('/examples/images'), image_text_output=Output('/examples/listed_images_with_text') ) def translate_images(ctx, images, image_text_output): def get_ocr_on_image(media_item_rid): return images.transform_image_to_text_ocr_output_text(media_item_rid).read().decode('utf-8') ocr_on_image_udf = F.udf(get_ocr_on_image, StringType()) media_items_listing = images.list_media_items_by_path_with_media_reference(ctx) listing_with_ocr = media_items_listing.withColumn('text', ocr_on_image_udf(F.col('mediaItemRid'))) column_typeclasses = {'mediaReference': [{'kind': 'reference', 'name': 'media_reference'}]} image_text_output.write_dataframe(listing_with_ocr, column_typeclasses=column_typeclasses)
Media sets can be used as outputs to transformations by using the MediaSetOutput
specification.
Unlike regular datasets, media sets must already exist before being used as an output. You can do this through the Foundry filesystem interface by navigating to the folder where you want the media set to exist, selecting + New, then choosing Media set. You will then be guided through the creation of an empty media set that you can write into later from your Python transform.
To upload an item, call the put_media_item()
endpoint on the output media set. This endpoint accepts any file-like object and a path which will be used to identify the item in the output media set. The following is a basic example:
Copied!1 2 3 4 5 6 7 8 9
from transforms.api import transform from transforms.mediasets import MediaSetInput, MediaSetOutput @transform( images=MediaSetInput('/examples/images'), output_images=MediaSetOutput('/examples/output_images') ) def upload_images(images, output_images): with images.get_media_item_by_path("image1.jpg") as input_image: output_images.put_media_item(input_image, "copied_image1.jpg")
When copying items from one media set to another, you can use the fast_copy_media_item()
method on the output. This is a faster and more efficient option than downloading and re-uploading the media item:
Copied!1 2 3 4 5 6 7
@transform( images=MediaSetInput('/examples/images'), output_images=MediaSetOutput('/examples/output_images') ) def upload_images(images, output_images): origin_media_item_rid = images.get_media_item_rid_by_path("image1.jpg") output_images.fast_copy_media_item(images, origin_media_item_rid, "fast_copied_image1.jpg")
Items can be uploaded to media sets in user-defined functions (UDFs) for higher parallelism. In the example below, we transform the PDFs in the input media set into JPEGs using the built-in PDF to JPEG transformation and upload those JPEGs to a new output media set. We then write out a tabular dataset containing the media references of those uploaded JPEGs:
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
from transforms.api import transform, Output from transforms.mediasets import MediaSetInput, MediaSetOutput from pyspark.sql import functions as F from pyspark.sql.types import StringType @transform( pdfs=MediaSetInput('/examples/PDFs'), output_images=MediaSetOutput('/examples/JPEGs'), output_references=Output('/examples/JPEG listing') ) def upload_images(ctx, pdfs, output_images, output_references): def upload_jpg(media_item_rid, path): with pdfs.transform_document_to_jpg(media_item_rid, 0) as jpeg: response = output_images.put_media_item(jpeg, path) return response.media_item_rid upload_udf = F.udf(upload_jpg, StringType()) listed_pdfs = pdfs.list_media_items_by_path(ctx) media_reference_template = output_images.media_reference_template() uploaded_jpegs = listed_pdfs\ .withColumn('uploaded_media_item_rid', upload_udf(F.col('mediaItemRid'), F.col('path')))\ .select('path', 'uploaded_media_item_rid')\ .withColumn("mediaReference", F.format_string(media_reference_template, 'uploaded_media_item_rid')) column_typeclasses = {'mediaReference': [{'kind': 'reference', 'name': 'media_reference'}]} output_references.write_dataframe(uploaded_jpegs, column_typeclasses=column_typeclasses)
The Python media set SDK has built-in tooling to upload the files from a conventional dataset in the Palantir filesystem (known as the Catalog) into a media set. For example:
Copied!1 2 3 4 5 6 7 8
from transforms.api import transform, Input from transforms.mediasets import MediaSetOutput @transform( pdfs_dataset=Input('/examples/PDFs'), pdfs_media_set=MediaSetOutput('/examples/PDFs mediaset') ) def upload_to_media_set(pdfs_dataset, pdfs_media_set): pdfs_media_set.put_dataset_files(pdfs_dataset, ignore_items_not_matching_schema=False)
This transform will upload all items from the dataset into the media set. If any items do not match the schema of the media set (for example, if there is a JPEG in the dataset), then the build will fail. By setting ignore_items_not_matching_schema=True
any such mismatches will instead be ignored.
Files can alternatively be uploaded one by one. For example:
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14
from transforms.api import transform, Input, Output, incremental from transforms.mediasets import MediaSetInput, MediaSetOutput import os @transform( output_mediaset=MediaSetOutput("/path/mediaset_output", should_snapshot=False), input_dataset=Input("/path/dataset_of_raw_files"), ) def compute(input_dataset, output_mediaset): all_files = list(input_dataset.filesystem().ls()) for current_file in all_files: with input_dataset.filesystem().open(current_file.path, 'rb') as f: filename = os.path.basename(current_file.path) output_mediaset.put_media_item(f, filename)
Transform an individual page of a PDF document into a JPEG and return it.
Operates on: PDF documents
Returns: JPEG image
Parameters:
media_item_rid
: The RID of the media item to be transformed.page_number
: The zero-indexed page number.Example:
Copied!1
input_pdfs.transform_document_to_jpg("ri.mio.main.media-item.1", 0)
Transform an individual page of a PDF document into a PNG and return it.
Operates on: PDF documents
Returns: PNG image
Parameters:
media_item_rid
: The RID of the media item to be transformed.page_number
: The zero-indexed page number.Example:
Copied!1
input_pdfs.transform_document_to_png("ri.mio.main.media-item.1", 0)
OCR PDF into text output by page.
Operates on: PDF documents
Returns: Unstructured text in utf-8 encoding
Parameters:
media_item_rid
: The RID of the media item to be transformed.page_number
: The zero-indexed page number.ENG
.Example:
Copied!1 2
raw_output = input_pdfs.transform_document_to_text_ocr_output_text("ri.mio.main.media-item.1", 0) doc_text_ocr = raw_output.read().decode("utf-8")
OCR PDF into hOCR XML by page. Learn more about hOCR ↗.
Operates on: PDF documents
Returns: hOCR xml in utf-8 encoding
Parameters:
media_item_rid
: The RID of the media item to be transformed.page_number
: The zero-indexed page number.ENG
.Example:
Copied!1
input_pdfs.transform_document_to_text_ocr_output_hocr("ri.mio.main.media-item.1", 0)
Extract field from the PDF and return it. This is a parsing method that does not require image processing unlike with OCR.
Operates on: PDF documents
Returns: Unstructured text in UTF-8 encoding
Parameters:
media_item_rid
: The RID of the media item to be transformed.page_number
: The zero-indexed page number.Example:
Copied!1 2
raw_output = input_pdfs.transform_document_to_text_raw("ri.mio.main.media-item.1", 0) doc_text_extraction = raw_output.read().decode("utf-8")
Extract all form fields from the whole PDF and return it.
Operates on: PDF documents
Returns: JSON
Parameters:
media_item_rid
: The RID of the media item to be transformed.Example:
Copied!1
input_pdfs.transform_document_to_text_extract_field("ri.mio.main.media-item.1")
Extract field from the PDF and return it.
Operates on: PDF documents
Returns: JSON
Parameters:
media_item_rid
: The RID of the media item to be transformed.Example:
Copied!1
input_pdfs.transform_document_to_text_extract_table_of_contents("ri.mio.main.media-item.1")
OCR image into hOCR XML. Learn more about hOCR ↗.
Operates on: Image
Returns: JSON
Parameters:
media_item_rid
: The RID of the media item to be transformed.Example:
Copied!1
input_pdfs.transform_image_to_text_ocr_output_hocr("ri.mio.main.media-item.1")
OCR image into text.
Operates on: Image
Returns: Unstructured text in utf-8 encoding
Parameters:
media_item_rid
: The RID of the media item to be transformed.Example:
Copied!1
input_images.transform_image_to_text_ocr_output_text("ri.mio.main.media-item.1")
Transcribe audio file with speech into text.
Operates on: Audio
Returns: Unstructured plain text file with transcription
Parameters:
media_item_rid
: The RID of the media item to be transformed.Examples:
Copied!1 2
input_audio_files.transcribe("ri.mio.main.media-item.1") input_audio_files.transcribe("ri.mio.main.media-item.1", TranscriptionLanguage.ARABIC)