| import torch |
| import spaces |
| from threading import Thread |
| from transformers import AutoProcessor, AutoModelForCausalLM, TextIteratorStreamer |
| from PIL import Image |
| from config import settings |
|
|
| MODEL_ID = settings.model |
| hf_token = settings.hf_token |
|
|
| print(f"Loading {MODEL_ID}...") |
| processor = AutoProcessor.from_pretrained(MODEL_ID, token=hf_token) |
| model = AutoModelForCausalLM.from_pretrained( |
| MODEL_ID, torch_dtype=torch.float16, token=hf_token |
| ) |
|
|
|
|
| @spaces.GPU |
| def generate_vision_pass(image_path: str, prompt: str) -> str: |
| """Run the multimodal vision pass locally on ZeroGPU.""" |
| model.to("cuda") |
| image = Image.open(image_path).convert("RGB") |
|
|
| messages = [ |
| { |
| "role": "user", |
| "content": [{"type": "image"}, {"type": "text", "text": prompt}], |
| } |
| ] |
|
|
| text = processor.apply_chat_template(messages, add_generation_prompt=True) |
| inputs = processor(text=text, images=image, return_tensors="pt").to("cuda") |
|
|
| with torch.no_grad(): |
| output = model.generate(**inputs, max_new_tokens=512) |
|
|
| generated_ids = output[0, inputs["input_ids"].shape[1] :] |
| return processor.decode(generated_ids, skip_special_tokens=True) |
|
|
|
|
| @spaces.GPU |
| def stream_text_generation(messages: list): |
| """Stream text generation locally on ZeroGPU.""" |
| model.to("cuda") |
|
|
| |
| |
| text = processor.apply_chat_template( |
| messages, add_generation_prompt=True, tokenize=False |
| ) |
|
|
| tokenizer = processor.tokenizer if hasattr(processor, "tokenizer") else processor |
| inputs = tokenizer(text, return_tensors="pt").to("cuda") |
|
|
| streamer = TextIteratorStreamer( |
| tokenizer, skip_prompt=True, skip_special_tokens=True |
| ) |
|
|
| generation_kwargs = dict(**inputs, streamer=streamer, max_new_tokens=512) |
|
|
| thread = Thread(target=model.generate, kwargs=generation_kwargs) |
| thread.start() |
|
|
| for text_chunk in streamer: |
| yield text_chunk |
|
|