main
py 61 lines 2.07 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 from transformers import BaseImageProcessor, BatchFeature, TensorType
4 from transformers.processing_utils import ProcessorMixin
5
6 from vllm.tokenizers.hf import HfTokenizer
7
8
9 class KimiK3Processor(ProcessorMixin):
10 """HF-style processor wrapper for the image-only Kimi-K3 model.
11
12 K3 exposes the standard ``image`` modality, so vLLM calls this processor
13 with ``images=[PIL, ...]``. The underlying checkpoint image processor
14 (``KimiK3VisionProcessor``) works on ``{"type": "image", "image": PIL}``
15 media dicts, so this wrapper adapts bare PIL images into that shape before
16 delegating to ``preprocess``.
17
18 Text is only tokenized here; the single ``<|kimi_image_placeholder|>``
19 token per image is expanded into the resolution-aware media block by the
20 model's ``_get_prompt_updates`` on the vLLM side.
21 """
22
23 attributes = ["image_processor", "tokenizer"]
24
25 def __init__(
26 self,
27 image_processor: BaseImageProcessor,
28 tokenizer: HfTokenizer,
29 ) -> None:
30 self.image_processor = image_processor
31 self.tokenizer = tokenizer
32
33 def __call__(
34 self,
35 text: str | list[str] | None = None,
36 images: object | list[object] | None = None,
37 return_tensors: str | TensorType | None = None,
38 **kwargs,
39 ) -> BatchFeature:
40 if images is not None:
41 if not isinstance(images, list):
42 images = [images]
43 medias = [{"type": "image", "image": image} for image in images]
44 mm_inputs = self.image_processor.preprocess(
45 medias,
46 return_tensors=return_tensors,
47 )
48 else:
49 mm_inputs = {}
50
51 if text is not None:
52 if not isinstance(text, list):
53 text = [text]
54 text_inputs = self.tokenizer(text)
55 else:
56 text_inputs = {}
57
58 return BatchFeature(
59 data={**text_inputs, **mm_inputs},
60 tensor_type=return_tensors,
61 )