Spaces:
Running
Running
File size: 4,814 Bytes
a2b6d64 3a8bfcd a2b6d64 3a8bfcd d7e7825 3a8bfcd 077ebc4 a2b6d64 3a8bfcd a2b6d64 3a8bfcd d7e7825 3a8bfcd a2b6d64 3a8bfcd a2b6d64 3a8bfcd d7e7825 a2b6d64 d7e7825 3a8bfcd a2b6d64 d7e7825 3a8bfcd d7e7825 a2b6d64 3a8bfcd d7e7825 a2b6d64 d7e7825 a2b6d64 3a8bfcd d7e7825 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
import base64
from io import BytesIO
import torch
from fastapi import FastAPI, Query
from PIL import Image
from qwen_vl_utils import process_vision_info
from transformers import AutoProcessor, Qwen2_5_VLForConditionalGeneration, Qwen2VLForConditionalGeneration
app = FastAPI()
checkpoint = "Qwen/Qwen2-VL-7B-Instruct"
min_pixels = 256 * 28 * 28
max_pixels = 1280 * 28 * 28
processor = AutoProcessor.from_pretrained(
checkpoint, min_pixels=min_pixels, max_pixels=max_pixels
)
model = Qwen2VLForConditionalGeneration.from_pretrained(
checkpoint,
torch_dtype=torch.bfloat16,
device_map="auto",
# attn_implementation="flash_attention_2",
)
@app.get("/")
def read_root():
return {"message": "API is live. Use the /predict endpoint."}
def encode_image(image_path, max_size=(800, 800), quality=85):
"""
Converts an image from a local file path to a Base64-encoded string with optimized size.
Args:
image_path (str): The path to the image file.
max_size (tuple): The maximum width and height of the resized image.
quality (int): The compression quality (1-100, higher means better quality but bigger size).
Returns:
str: Base64-encoded representation of the optimized image.
"""
try:
with Image.open(image_path) as img:
# Convert to RGB (avoid issues with PNG transparency)
img = img.convert("RGB")
# Resize while maintaining aspect ratio
img.thumbnail(max_size, Image.LANCZOS)
# Save to buffer with compression
buffer = BytesIO()
img.save(
buffer, format="JPEG", quality=quality
) # Save as JPEG to reduce size
return base64.b64encode(buffer.getvalue()).decode("utf-8")
except Exception as e:
print(f"❌ Error encoding image {image_path}: {e}")
return None
@app.get("/predict")
def describe_image_with_qwen2_vl(image_url: str = Query(...), prompt: str = Query(...)):
"""
Generates a description for an image using the Qwen-2-VL model.
Args:
image_url (str): The URL of the image to describe.
prompt (str): The text prompt to guide the model's response.
Returns:
str: The generated description of the image.
"""
image = encode_image(image_url)
# Create the input message structure
messages = [
{
"role": "user",
"content": [
{"type": "image", "image": f"data:image;base64,{image}"},
{"type": "text", "text": prompt},
],
}
]
# Prepare inputs for the model
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("cuda:0")
# Generate the output
generated_ids = model.generate(**inputs, max_new_tokens=2056)
generated_ids_trimmed = [
out_ids[len(in_ids) :]
for in_ids, out_ids in zip(inputs.input_ids, generated_ids)
]
output_text = processor.batch_decode(
generated_ids_trimmed,
skip_special_tokens=True,
clean_up_tokenization_spaces=False,
)
return {"response": output_text[0] if output_text else "No description generated."}
# @app.get("/predict")
# def predict(image_url: str = Query(...), prompt: str = Query(...)):
# image = encode_image(image_url)
# messages = [
# {
# "role": "system",
# "content": "You are a helpful assistant with vision abilities.",
# },
# {
# "role": "user",
# "content": [
# {"type": "image", "image": f"data:image;base64,{image}"},
# {"type": "text", "text": 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)
# with torch.no_grad():
# generated_ids = model.generate(**inputs, max_new_tokens=128)
# generated_ids_trimmed = [
# out_ids[len(in_ids) :]
# for in_ids, out_ids in zip(inputs.input_ids, generated_ids)
# ]
# output_texts = processor.batch_decode(
# generated_ids_trimmed,
# skip_special_tokens=True,
# clean_up_tokenization_spaces=False,
# )
# return {"response": output_texts[0]}
|