#!/usr/bin/env python3 from __future__ import annotations import argparse import base64 import json import mimetypes import sys import urllib.error import urllib.request from pathlib import Path def build_data_url(image_path: Path) -> str: mime_type, _ = mimetypes.guess_type(image_path.name) if mime_type is None or not mime_type.startswith("image/"): mime_type = "image/jpeg" encoded = base64.b64encode(image_path.read_bytes()).decode("ascii") return f"data:{mime_type};base64,{encoded}" def main() -> int: parser = argparse.ArgumentParser(description="Send a local image to the vLLM OpenAI API.") parser.add_argument("image", type=Path, help="Path to a local image") parser.add_argument("prompt", nargs="?", default="Describe this image in detail.") parser.add_argument("--api-base", default="http://127.0.0.1:8000/v1") parser.add_argument("--model", default="internvl35-fp8") parser.add_argument("--max-tokens", type=int, default=256) args = parser.parse_args() if not args.image.is_file(): print(f"Image not found: {args.image}", file=sys.stderr) return 2 payload = { "model": args.model, "messages": [ { "role": "user", "content": [ {"type": "image_url", "image_url": {"url": build_data_url(args.image)}}, {"type": "text", "text": args.prompt}, ], } ], "temperature": 0.0, "max_tokens": args.max_tokens, } request = urllib.request.Request( f"{args.api_base.rstrip('/')}/chat/completions", data=json.dumps(payload).encode("utf-8"), headers={"Content-Type": "application/json"}, method="POST", ) try: with urllib.request.urlopen(request, timeout=300) as response: result = json.load(response) except urllib.error.HTTPError as exc: print(exc.read().decode("utf-8", errors="replace"), file=sys.stderr) return 1 except urllib.error.URLError as exc: print(f"Request failed: {exc}", file=sys.stderr) return 1 print(result["choices"][0]["message"]["content"]) return 0 if __name__ == "__main__": raise SystemExit(main())