import os import random import uuid import json import time from threading import Thread from typing import Iterable import gradio as gr import spaces import torch import numpy as np from PIL import Image import cv2 from transformers import ( Qwen3VLForConditionalGeneration, AutoProcessor, TextIteratorStreamer, ) from transformers.image_utils import load_image from gradio.themes import Soft from gradio.themes.utils import colors, fonts, sizes colors.orange_red = colors.Color( name="orange_red", c50="#FFF0E5", c100="#FFE0CC", c200="#FFC299", c300="#FFA366", c400="#FF8533", c500="#FF4500", c600="#E63E00", c700="#CC3700", c800="#B33000", c900="#992900", c950="#802200", ) class OrangeRedTheme(Soft): def __init__( self, *, primary_hue: colors.Color | str = colors.gray, secondary_hue: colors.Color | str = colors.orange_red, neutral_hue: colors.Color | str = colors.slate, text_size: sizes.Size | str = sizes.text_lg, font: fonts.Font | str | Iterable[fonts.Font | str] = ( fonts.GoogleFont("Outfit"), "Arial", "sans-serif", ), font_mono: fonts.Font | str | Iterable[fonts.Font | str] = ( fonts.GoogleFont("IBM Plex Mono"), "ui-monospace", "monospace", ), ): super().__init__( primary_hue=primary_hue, secondary_hue=secondary_hue, neutral_hue=neutral_hue, text_size=text_size, font=font, font_mono=font_mono, ) super().set( background_fill_primary="*primary_50", background_fill_primary_dark="*primary_900", body_background_fill="linear-gradient(135deg, *primary_200, *primary_100)", body_background_fill_dark="linear-gradient(135deg, *primary_900, *primary_800)", button_primary_text_color="white", button_primary_text_color_hover="white", button_primary_background_fill="linear-gradient(90deg, *secondary_500, *secondary_600)", button_primary_background_fill_hover="linear-gradient(90deg, *secondary_600, *secondary_700)", button_primary_background_fill_dark="linear-gradient(90deg, *secondary_600, *secondary_700)", button_primary_background_fill_hover_dark="linear-gradient(90deg, *secondary_500, *secondary_600)", button_secondary_text_color="black", button_secondary_text_color_hover="white", button_secondary_background_fill="linear-gradient(90deg, *primary_300, *primary_300)", button_secondary_background_fill_hover="linear-gradient(90deg, *primary_400, *primary_400)", button_secondary_background_fill_dark="linear-gradient(90deg, *primary_500, *primary_600)", button_secondary_background_fill_hover_dark="linear-gradient(90deg, *primary_500, *primary_500)", slider_color="*secondary_500", slider_color_dark="*secondary_600", block_title_text_weight="600", block_border_width="3px", block_shadow="*shadow_drop_lg", button_primary_shadow="*shadow_drop_lg", button_large_padding="11px", color_accent_soft="*primary_100", block_label_background_fill="*primary_200", ) orange_red_theme = OrangeRedTheme() css = """ #main-title h1 { font-size: 2.3em !important; } #output-title h2 { font-size: 2.2em !important; } /* Wider sidebar */ .sidebar { min-width: 420px !important; max-width: 480px !important; } """ MAX_MAX_NEW_TOKENS = 4096 DEFAULT_MAX_NEW_TOKENS = 1024 MAX_INPUT_TOKEN_LENGTH = int(os.getenv("MAX_INPUT_TOKEN_LENGTH", "4096")) device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") print("CUDA_VISIBLE_DEVICES=", os.environ.get("CUDA_VISIBLE_DEVICES")) print("torch.__version__ =", torch.__version__) print("torch.version.cuda =", torch.version.cuda) print("cuda available:", torch.cuda.is_available()) print("cuda device count:", torch.cuda.device_count()) if torch.cuda.is_available(): print("current device:", torch.cuda.current_device()) print("device name:", torch.cuda.get_device_name(torch.cuda.current_device())) print("Using device:", device) MODEL_ID_V = "prithivMLmods/Qwen3-VL-8B-Instruct-Unredacted-MAX" processor_v = AutoProcessor.from_pretrained(MODEL_ID_V, trust_remote_code=True) model_v = Qwen3VLForConditionalGeneration.from_pretrained( MODEL_ID_V, attn_implementation="kernels-community/flash-attn3", trust_remote_code=True, torch_dtype=torch.float16, ).to(device).eval() def calc_timeout_duration( text: str, image: Image.Image, max_new_tokens: int, temperature: float, top_p: float, top_k: int, repetition_penalty: float, gpu_timeout: int, ): """Calculate GPU timeout duration based on the last argument.""" try: return int(gpu_timeout) except Exception: return 60 @spaces.GPU(duration=calc_timeout_duration) def generate_image( text: str, image: Image.Image, max_new_tokens: int, temperature: float, top_p: float, top_k: int, repetition_penalty: float, gpu_timeout: int, ): """ Generates responses using the Qwen3-VL-4B-Instruct-Unredacted-MAX model for image input. Unredacted: Ask Anything with Near-Zero Refusal Rates. """ processor = processor_v model = model_v if image is None: yield "Please upload an image.", "Please upload an image." return messages = [ { "role": "user", "content": [ {"type": "image"}, {"type": "text", "text": text}, ], } ] prompt_full = processor.apply_chat_template( messages, tokenize=False, add_generation_prompt=True ) inputs = processor( text=[prompt_full], images=[image], return_tensors="pt", padding=True ).to(device) streamer = TextIteratorStreamer( processor, skip_prompt=True, skip_special_tokens=True ) generation_kwargs = { **inputs, "streamer": streamer, "max_new_tokens": max_new_tokens, "do_sample": True, "temperature": temperature, "top_p": top_p, "top_k": top_k, "repetition_penalty": repetition_penalty, } thread = Thread(target=model.generate, kwargs=generation_kwargs) thread.start() buffer = "" for new_text in streamer: buffer += new_text buffer = buffer.replace("<|im_end|>", "") time.sleep(0.01) yield buffer, buffer with gr.Blocks(fill_height=True) as demo: with gr.Sidebar(width=450): gr.Markdown("# **Qwen3VL-MAX**", elem_id="main-title") image_upload = gr.Image(type="pil", label="Upload Image", height=300) image_query = gr.Textbox( label="Query Input", placeholder="Ask me anything!" ) image_submit = gr.Button("Submit", variant="primary") gpu_duration_dropdown = gr.Dropdown( choices=["60", "90", "120", "180", "240"], value="60", label="ZeroGPU Duration (seconds)", ) gpu_duration_state = gr.Number(value=60, visible=False) with gr.Accordion("Advanced options", open=False): max_new_tokens = gr.Slider( label="Max new tokens", minimum=1, maximum=MAX_MAX_NEW_TOKENS, step=1, value=DEFAULT_MAX_NEW_TOKENS, ) temperature = gr.Slider( label="Temperature", minimum=0.1, maximum=4.0, step=0.1, value=0.7, ) top_p = gr.Slider( label="Top-p (nucleus sampling)", minimum=0.05, maximum=1.0, step=0.05, value=0.9, ) top_k = gr.Slider( label="Top-k", minimum=1, maximum=1000, step=1, value=50 ) repetition_penalty = gr.Slider( label="Repetition penalty", minimum=1.0, maximum=2.0, step=0.05, value=1.1, ) gr.Markdown("## Output", elem_id="output-title") output = gr.Textbox(label="Raw Output Stream", interactive=True, lines=22) with gr.Accordion("(Result.md)", open=False): markdown_output = gr.Markdown(label="(Result.Md)") gpu_duration_dropdown.change( fn=lambda val: int(val), inputs=gpu_duration_dropdown, outputs=[gpu_duration_state], api_visibility="private", ) image_submit.click( fn=generate_image, inputs=[ image_query, image_upload, max_new_tokens, temperature, top_p, top_k, repetition_penalty, gpu_duration_state, ], outputs=[output, markdown_output], ) if __name__ == "__main__": demo.queue(max_size=50).launch( css=css, theme=orange_red_theme, mcp_server=True, ssr_mode=False, show_error=True, )