# 配套文章：05-multimodal-and-realtime.md
# 本轮新增示例未执行；环境和运行方式见上级 GUIDE.md。

import argparse
import torch
from PIL import Image, ImageOps
from transformers import AutoProcessor, AutoModelForVision2Seq

parser = argparse.ArgumentParser(description="读取本地图片并进行图文问答")
parser.add_argument("image_path", help="待观察的本地图片路径，例如 cup.jpg")
args = parser.parse_args()

# EXIF 中可能记录拍摄方向；先矫正方向，再转为模型使用的 RGB。
# 使用文件实际像素，不把路径字符串当作图片内容发送给模型。
with Image.open(args.image_path) as source:
    picture = ImageOps.exif_transpose(source).convert("RGB")

model_id = "HuggingFaceTB/SmolVLM-256M-Instruct"
processor = AutoProcessor.from_pretrained(model_id)
model = AutoModelForVision2Seq.from_pretrained(
    model_id, torch_dtype=torch.float32, _attn_implementation="eager"
).eval()
messages = [{"role": "user", "content": [
    {"type": "image"},
    {"type": "text", "text": "Describe visible damage, if any. Do not infer its cause."},
]}]
# 图像占位与 images 中的图片一一对应，预处理由配套 Processor 完成。
prompt = processor.apply_chat_template(messages, add_generation_prompt=True)
inputs = processor(text=prompt, images=[picture], return_tensors="pt")
for name, value in inputs.items():
    # 观察文本 ID、像素等张量形状，不假设视觉表示等于文本 Token 数。
    if hasattr(value, "shape"):
        print(name, tuple(value.shape))

with torch.inference_mode():
    output = model.generate(**inputs, max_new_tokens=96, do_sample=False)
# 对此类因果生成模型，返回序列带有输入前缀；只解码新生成部分。
new_ids = output[:, inputs["input_ids"].shape[1]:]
print(processor.batch_decode(new_ids, skip_special_tokens=True)[0])
