"""Fast-dVLM command-line chatbot with speculative block-causal decoding.""" import argparse import torch from transformers import AutoModelForCausalLM, AutoTokenizer, AutoProcessor from qwen_vl_utils import process_vision_info def build_messages(image, prompt): content = [] if image: content.append({"type": "image", "image": image}) content.append({"type": "text", "text": prompt}) return [{"role": "user", "content": content}] def run_inference(model, processor, image, prompt, args): messages = build_messages(image, prompt) text = processor.apply_chat_template( messages, tokenize=False, add_generation_prompt=True, ) image_inputs, video_inputs = process_vision_info(messages) inputs = processor( text=[text], images=image_inputs, videos=video_inputs, padding=True, return_tensors="pt", ).to(model.device) mask_id = processor.tokenizer.encode(args.mask_token)[0] gen_kwargs = { "input_ids": inputs.input_ids, "tokenizer": processor.tokenizer, "block_size": args.block_size, "max_tokens": args.max_tokens, "mask_id": mask_id, } if hasattr(inputs, "pixel_values"): gen_kwargs["pixel_values"] = inputs.pixel_values if hasattr(inputs, "image_grid_thw"): gen_kwargs["image_grid_thw"] = inputs.image_grid_thw generated_ids = model.generate(**gen_kwargs) generated_ids_trimmed = [ out[len(inp):] for inp, out in zip(inputs.input_ids, generated_ids) ] return processor.batch_decode( generated_ids_trimmed, skip_special_tokens=True, )[0] def main(): parser = argparse.ArgumentParser(description="Fast-dVLM chatbot") parser.add_argument( "--model-name", default="Efficient-Large-Model/Fast_dVLM_3B", help="HuggingFace model id or local path.", ) parser.add_argument( "--image", default=None, help="Image URL or local path. Leave empty for text-only.", ) parser.add_argument( "--prompt", default=None, help="Text prompt. If omitted, enters interactive mode.", ) parser.add_argument("--block-size", type=int, default=32) parser.add_argument("--max-tokens", type=int, default=512) parser.add_argument("--mask-token", default="||") parser.add_argument("--device", default="cuda") args = parser.parse_args() print("Loading model...") model = AutoModelForCausalLM.from_pretrained( args.model_name, torch_dtype=torch.bfloat16, device_map="auto", trust_remote_code=True, ) tokenizer = AutoTokenizer.from_pretrained(args.model_name) processor = AutoProcessor.from_pretrained(args.model_name, use_fast=False) processor.tokenizer = tokenizer if args.prompt: image = args.image or "https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen-VL/assets/demo.jpeg" output = run_inference(model, processor, image, args.prompt, args) print(f"\n{output}") else: print("Interactive mode. Type 'exit' to quit, 'clear' to reset.") while True: prompt = input("\nYou: ").strip() if prompt.lower() == "exit": break if prompt.lower() == "clear": print("History cleared.") continue if not prompt: continue image = args.image output = run_inference(model, processor, image, prompt, args) print(f"\nAssistant: {output}") if __name__ == "__main__": main()