async def cache(self, example_id: int | None = None) -> None:
        """
        Caches examples so that their predictions can be shown immediately.
        Parameters:
            example_id: The id of the example to process (zero-indexed). If None, all examples are cached.
        """
        if self.root_block is None:
            raise Error("Cannot cache examples if not in a Blocks context.")
        if Path(self.cached_file).exists() and example_id is None:
            print(
                f"Using cache from '{utils.abspath(self.cached_folder)}' directory. If method or examples have changed since last caching, delete this folder to clear cache.\n"
            )
        else:
            print(f"Caching examples at: '{utils.abspath(self.cached_folder)}'")
            self.cache_logger.setup(self.outputs, self.cached_folder)
            generated_values = []
            if inspect.isgeneratorfunction(self.fn):

                def get_final_item(*args):  # type: ignore
                    x = None
                    generated_values.clear()
                    for x in self.fn(*args):  # noqa: B007  # type: ignore
                        generated_values.append(x)
                    return x

                fn = get_final_item
            elif inspect.isasyncgenfunction(self.fn):

                async def get_final_item(*args):
                    x = None
                    generated_values.clear()
                    async for x in self.fn(*args):  # noqa: B007  # type: ignore
                        generated_values.append(x)
                    return x

                fn = get_final_item
            else:
                fn = self.fn

            # create a fake dependency to process the examples and get the predictions
            from gradio.events import EventListenerMethod

            _, fn_index = self.root_block.default_config.set_event_trigger(
                [EventListenerMethod(Context.root_block, "load")],
                fn=fn,
                inputs=self.inputs,
                outputs=self.outputs,
                preprocess=self.preprocess and not self._api_mode,
                postprocess=self.postprocess and not self._api_mode,
                batch=self.batch,
            )

            if self.outputs is None:
                raise ValueError("self.outputs is missing")
            for i, example in enumerate(self.non_none_examples):
                if example_id is not None and i != example_id:
                    continue
                processed_input = self._get_processed_example(example)
                for index, keep in enumerate(self.input_has_examples):
                    if not keep:
                        processed_input.insert(index, None)
                if self.batch:
                    processed_input = [[value] for value in processed_input]
                with utils.MatplotlibBackendMananger():
                    prediction = await self.root_block.process_api(
                        block_fn=self.root_block.default_config.fns[fn_index],
                        inputs=processed_input,
                        request=None,
                    )
                output = prediction["data"]
                if generated_values:
                    output = await merge_generated_values_into_output(
                        self.outputs, generated_values, output
                    )
                if self.batch:
                    output = [value[0] for value in output]
                self.cache_logger.flag(output)
            # Remove the "fake_event" to prevent bugs in loading interfaces from spaces
            self.root_block.default_config.fns.pop(fn_index)

        Caches examples so that their predictions can be shown immediately.
        Parameters:
            example_id: The id of the example to process (zero-indexed). If None, all examples are cached.
        
gradio/helpers.py