8787 # ORT GenAI (see onnxruntime-genai/src/models/model_type.h LLM list).
8888 "hunyuan_v1_dense" : "decoder" ,
8989 "deepseek_v4" : "decoder" ,
90- # Qwen VL models all use the same GenAI pipeline as qwen2_5_vl
90+ # Qwen VL model families have separate ORT GenAI model types.
9191 "qwen2_vl" : "qwen2_5_vl" ,
92- "qwen3_vl" : "qwen2_5_vl " ,
93- "qwen3_vl_text" : "qwen2_5_vl " ,
92+ "qwen3_vl" : "qwen3_vl " ,
93+ "qwen3_vl_text" : "qwen3_vl " ,
9494 "qwen3_5" : "qwen2_5_vl" ,
9595 "qwen3_5_vl" : "qwen2_5_vl" ,
9696}
@@ -880,6 +880,16 @@ def _write_genai_config(
880880 if sms is not None :
881881 vision_kwargs ["spatial_merge_size" ] = sms
882882 vision_kwargs ["config_filename" ] = "processor_config.json"
883+ if model_type in {"qwen3_vl" , "qwen3_vl_text" }:
884+ patch_size = getattr (vision_cfg , "patch_size" , None )
885+ window_size = getattr (vision_cfg , "window_size" , None )
886+ if patch_size is not None :
887+ vision_kwargs ["patch_size" ] = patch_size
888+ if window_size is not None :
889+ vision_kwargs ["window_size" ] = window_size
890+ vision_kwargs ["tokens_per_second" ] = float (
891+ getattr (config , "tokens_per_second" , 2.0 )
892+ )
883893
884894 if vision_input_mapping is not None :
885895 vision_kwargs ["input_names" ] = vision_input_mapping
@@ -889,6 +899,12 @@ def _write_genai_config(
889899 embedding_output_mapping = _introspect_outputs (pkg , "embedding" )
890900 if embedding_output_mapping is not None :
891901 vision_kwargs ["embedding_output_names" ] = embedding_output_mapping
902+ vision_start_token_id = getattr (config , "vision_start_token_id" , None )
903+ video_token_id = getattr (config , "video_token_id" , None )
904+ if vision_start_token_id is not None :
905+ vision_kwargs ["vision_start_token_id" ] = vision_start_token_id
906+ if video_token_id is not None :
907+ vision_kwargs ["video_token_id" ] = video_token_id
892908
893909 generator .with_vision (image_token_id = image_token_id , ** vision_kwargs )
894910
@@ -946,8 +962,8 @@ def write_ort_genai_config(
946962 pkg: Already-built :class:`~mobius._model_package.ModelPackage` with
947963 weights applied and ``config`` set.
948964 directory: Output directory (created if needed).
949- hf_model_id: HuggingFace model ID. When provided, used to fetch token
950- IDs (``bos``/``eos``/``pad``) and download tokenizer files.
965+ hf_model_id: HuggingFace model ID or local model directory. When provided,
966+ used to fetch token IDs (``bos``/``eos``/``pad``) and copy tokenizer files.
951967 When ``None``, token IDs are read from ``pkg.config`` fields
952968 (``bos_token_id``, ``eos_token_id``, ``pad_token_id``) populated
953969 by :meth:`~mobius._configs.ArchitectureConfig.from_transformers`,
@@ -1112,11 +1128,15 @@ def write_ort_genai_config(
11121128 f .write ("\n " )
11131129 result ["mtp_config" ] = mtp_path
11141130
1115- # Copy tokenizer files — HF Hub takes precedence; local dir is the fallback
1116- # for --config mode where no HF model ID is available .
1131+ # Copy tokenizer files. A local hf_model_id is a local model directory, not a
1132+ # Hub repo id; copy directly instead of calling hf_hub_download .
11171133 if hf_model_id is not None :
1118- logger .info ("Copying tokenizer files from %s" , hf_model_id )
1119- tokenizer_files = _copy_tokenizer_files (hf_model_id , directory )
1134+ if os .path .isdir (hf_model_id ):
1135+ logger .info ("Copying tokenizer files from local model directory %s" , hf_model_id )
1136+ tokenizer_files = _copy_tokenizer_files_from_local (hf_model_id , directory )
1137+ else :
1138+ logger .info ("Copying tokenizer files from %s" , hf_model_id )
1139+ tokenizer_files = _copy_tokenizer_files (hf_model_id , directory )
11201140 for tf in tokenizer_files :
11211141 result [tf ] = os .path .join (directory , tf )
11221142 elif local_config_dir is not None :
0 commit comments