Spaces:
Sleeping
Sleeping
File size: 4,973 Bytes
73b86b3 c376ada 73b86b3 c376ada 73b86b3 | 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 | import os
import gc
import torch
import gradio as ui
import spaces # ADDED: Hugging Face Spaces SDK for ZeroGPU support
from transformers import pipeline, TextIteratorStreamer
from threading import Thread
# 1. Initialize Pipeline
MODEL_ID = "Xerv-AI/tarn"
print("Loading tarn architecture into memory...")
# FIX: Replaced 'torch_dtype' with 'dtype' to clear the transformers deprecation warning.
pipe = pipeline(
"image-text-to-text",
model=MODEL_ID,
model_kwargs={
"dtype": torch.float16,
"device_map": "auto"
}
)
print("tarn is fully initialized.")
# 2. Define the Inference Logic
@spaces.GPU # ADDED: Required by HF Spaces to allocate ZeroGPU dynamically
def process_chat(message, history):
"""
Handles incoming messages (both images and text), formats them into
the proper Qwen 3.5 VL structure, and yields streamed tokens.
"""
# Force clean any leftover GPU allocation trash before processing
gc.collect()
torch.cuda.empty_cache()
# Reconstruct history into Hugging Face chat template format
formatted_messages = []
# Process previous conversation turns
for user_turn, assistant_turn in history:
if user_turn:
# Check if user input in history was a file/image dict or text
if isinstance(user_turn, dict) or (isinstance(user_turn, tuple) and len(user_turn) == 1):
img_path = user_turn[0] if isinstance(user_turn, tuple) else user_turn.get("path")
formatted_messages.append({"role": "user", "content": [{"type": "image", "url": img_path}]})
else:
formatted_messages.append({"role": "user", "content": [{"type": "text", "text": str(user_turn)}]})
if assistant_turn:
formatted_messages.append({"role": "assistant", "content": [{"type": "text", "text": str(assistant_turn)}]})
# Append current incoming turn
current_content = []
# Check if the user uploaded an image along with text
if message["files"]:
for file_info in message["files"]:
# Gradio 4+ passes files as dicts or named objects
file_path = file_info if isinstance(file_info, str) else file_info.get("path")
current_content.append({"type": "image", "url": file_path})
if message["text"]:
current_content.append({"type": "text", "text": message["text"]})
# Guard clause if user sent nothing
if not current_content:
yield ""
return
formatted_messages.append({"role": "user", "content": current_content})
# Initialize a non-blocking compilation streamer
streamer = TextIteratorStreamer(pipe.tokenizer, skip_prompt=True, skip_special_tokens=True)
# Inject VRAM patch configurations directly into generator parameters
generate_kwargs = {
"text": formatted_messages,
"max_new_tokens": 1024,
"min_pixels": 256 * 28 * 28,
"max_pixels": 512 * 28 * 28,
"generate_kwargs": {"streamer": streamer}
}
# Execute text generation on a separate background thread to keep UI interactive
thread = Thread(target=pipe, kwargs=generate_kwargs)
thread.start()
# Yield generated tokens back to UI as they arrive
partial_text = ""
for new_token in streamer:
partial_text += new_token
yield partial_text
# 3. Build Web Layout using Custom Calm Styling Themes
custom_theme = ui.themes.Soft(
primary_hue="orange", # Brings in that subtle "tangy" vibe softly
neutral_hue="slate", # Keeps the interface looking professional and clean
font=[ui.themes.GoogleFont("Source Sans Pro"), "Arial", "sans-serif"]
)
# FIX: Removed `theme=custom_theme` from Blocks (moved to launch).
with ui.Blocks(title="tarn Demo Space") as demo:
ui.Markdown(
"""
# 🌌 tarn Multimodal Reasoner
### Fine-tuned for deep visual context analysis and structured step-by-step logic.
*Built and maintained by **Xerv-AI**.*
"""
)
# Core multi-turn Gradio Chatbot interface
chatbot_interface = ui.ChatInterface(
fn=process_chat,
chatbot=ui.Chatbot(
height=550,
placeholder="📸 Upload an image or ask a structural reasoning question...",
# FIX: Removed `show_copy_button=True` as it is removed in newer Gradio versions.
avatar_images=(None, "https://huggingface.co/front/assets/huggingface/logos/huggingface-logo-dark.svg")
),
multimodal=True, # Explicitly turns on the combined image upload + text input array
textbox=ui.MultimodalTextbox(
placeholder="Type your question here... (Click the paperclip icon to pin an image)",
file_types=["image"],
scale=7
)
)
if __name__ == "__main__":
# FIX: Passed the theme to the launch method to satisfy Gradio 6.0 requirements.
demo.queue().launch(theme=custom_theme)
|