from typing import List, Union from sglang.srt.layers.rotary_embedding import MRotaryEmbedding from sglang.srt.managers.schedule_batch import MultimodalProcessorOutput from sglang.srt.models.glm4v import Glm4vForConditionalGeneration from sglang.srt.models.glm4v_moe import Glm4vMoeForConditionalGeneration from sglang.srt.multimodal.processors.base_processor import ( BaseMultimodalProcessor as SGLangBaseProcessor, ) from sglang.srt.multimodal.processors.base_processor import ( MultimodalSpecialTokens, ) try: from sglang.srt.models.glm_ocr import GlmOcrForConditionalGeneration except ImportError: GlmOcrForConditionalGeneration = None class Glm4vImageProcessor(SGLangBaseProcessor): models = [ m for m in [ Glm4vForConditionalGeneration, Glm4vMoeForConditionalGeneration, GlmOcrForConditionalGeneration, ] if m is not None ] def __init__(self, hf_config, server_args, _processor, *args, **kwargs): super().__init__(hf_config, server_args, _processor, *args, **kwargs) # GLM-V specific tokens self.IMAGE_TOKEN = "<|image|>" self.VIDEO_TOKEN = "<|video|>" self.IMAGE_START_TOKEN = "<|begin_of_image|>" self.IMAGE_END_TOKEN = "<|end_of_image|>" self.VIDEO_START_TOKEN = "<|begin_of_video|>" self.VIDEO_END_TOKEN = "<|end_of_video|>" # Token IDs self.IM_TOKEN_ID = hf_config.image_token_id self.VIDEO_TOKEN_ID = hf_config.video_token_id self.IMAGE_START_TOKEN_ID = hf_config.image_start_token_id self.IMAGE_END_TOKEN_ID = hf_config.image_end_token_id self.VIDEO_START_TOKEN_ID = hf_config.video_start_token_id self.VIDEO_END_TOKEN_ID = hf_config.video_end_token_id # Vision config self.IMAGE_FACTOR = 28 self.MIN_PIXELS = 112 * 112 self.MAX_PIXELS = 30000 * 28 * 28 * 2 self.mm_tokens = MultimodalSpecialTokens( image_token=self.IMAGE_TOKEN, image_token_id=self.IM_TOKEN_ID, video_token=self.VIDEO_TOKEN, # Note: For GLM4v videos, it uses the video token before tokenization but uses image token after tokenization video_token_id=self.IM_TOKEN_ID, ).build(_processor) def compute_mrope_positions(self, input_ids, mm_items): image_grid_thw = None video_grid_thw = None for item in mm_items: if "image_grid_thw" in item.model_specific_data: image_grid_thw = item.model_specific_data["image_grid_thw"] if "video_grid_thw" in item.model_specific_data: video_grid_thw = item.model_specific_data["video_grid_thw"] import torch input_ids_tensor = torch.tensor(input_ids, dtype=torch.long).unsqueeze(0) attention_mask = torch.ones_like(input_ids_tensor) mrope_positions, mrope_position_delta = MRotaryEmbedding.get_rope_index_glm4v( input_ids=input_ids_tensor, hf_config=self.hf_config, image_grid_thw=image_grid_thw, video_grid_thw=video_grid_thw, attention_mask=attention_mask, ) return mrope_positions.squeeze(1), mrope_position_delta async def process_mm_data_async( self, image_data: List[Union[str, bytes]], input_text, request_obj, *args, **kwargs, ): base_output = await self.load_mm_data( prompt=input_text, image_data=image_data, video_data=request_obj.video_data, multimodal_tokens=self.mm_tokens, ) if base_output.videos: base_output.videos = request_obj.video_data mm_items, input_ids, ret = self.process_and_combine_mm_data( base_output, self.mm_tokens ) input_ids = input_ids.flatten() mrope_positions, mrope_position_delta = MRotaryEmbedding.get_rope_index_glm4v( input_ids=input_ids.unsqueeze(0), hf_config=self.hf_config, image_grid_thw=getattr(ret, "image_grid_thw", None), video_grid_thw=getattr(ret, "video_grid_thw", None), attention_mask=getattr(ret, "attention_mask", None), ) mrope_positions = mrope_positions.squeeze(1) return MultimodalProcessorOutput( input_ids=input_ids.tolist(), mm_items=mm_items, im_token_id=self.mm_tokens.image_token_id, video_token_id=self.mm_tokens.video_token_id, mrope_positions=mrope_positions, mrope_position_delta=mrope_position_delta, )