| from typing import Any, Dict, Optional, Union |
| from pathlib import Path |
| import json |
| import torch |
| from transformers import AutoProcessor, AutoModelForMultimodalLM |
|
|
| from director.device import pick_device |
| from director.script_utils import ( |
| build_script_messages, |
| ) |
|
|
|
|
| def substring_from_first_to_last_brace(s: str) -> str | None: |
| start = s.find("{") |
| end = s.rfind("}") |
|
|
| if start == -1 or end == -1 or start > end: |
| return None |
|
|
| return s[start : end + 1] |
|
|
|
|
| def run_model( |
| rejection_text: Optional[str] = None, |
| image: Optional[Union[str, Path, Any]] = None, |
| runtime_seconds: int = 60, |
| scene_count: int = 8, |
| ) -> Optional[Union[Dict[str, Any], str]]: |
| |
|
|
| MODEL_ID = "google/gemma-4-E2B-it" |
|
|
| device, float_type = pick_device() |
|
|
| processor = AutoProcessor.from_pretrained(MODEL_ID) |
|
|
| model = AutoModelForMultimodalLM.from_pretrained( |
| MODEL_ID, |
| dtype=float_type, |
| ).to(device) |
|
|
| model.eval() |
|
|
| if not rejection_text and image is None: |
| rejection_text = ( |
| "The user received a vague rejection message with no useful explanation." |
| ) |
|
|
| script_messages = build_script_messages( |
| rejection_text=rejection_text, |
| image=image, |
| runtime_seconds=runtime_seconds, |
| scene_count=scene_count, |
| ) |
|
|
| try: |
|
|
| kwargs = dict( |
| add_generation_prompt=True, |
| tokenize=True, |
| return_dict=True, |
| return_tensors="pt", |
| ) |
|
|
| inputs = processor.apply_chat_template( |
| script_messages, |
| enable_thinking=False, |
| **kwargs, |
| ).to(model.device) |
|
|
| with torch.inference_mode(): |
| outputs = model.generate( |
| **inputs, |
| max_new_tokens=2600, |
| do_sample=True, |
| temperature=1.0, |
| top_p=0.95, |
| top_k=64, |
| ) |
| input_len = inputs["input_ids"].shape[-1] |
| response = processor.decode(outputs[0][input_len:], skip_special_tokens=False) |
| content = substring_from_first_to_last_brace( |
| processor.parse_response(response).get("content") |
| ) |
| return json.loads(content) |
|
|
| except Exception as e: |
| print(f"LLM script generation failed: {e}") |
| return None |
|
|