Phase-Technologies commited on
Commit
73b86b3
·
verified ·
1 Parent(s): 00491ad

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +127 -0
app.py ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gc
3
+ import torch
4
+ import gradio as ui
5
+ from transformers import pipeline, TextIteratorStreamer
6
+ from threading import Thread
7
+
8
+ # 1. Initialize Pipeline
9
+ MODEL_ID = "Xerv-AI/tarn"
10
+
11
+ print("Loading tarn architecture into memory...")
12
+
13
+ # FIX: Replaced 'torch_dtype' with 'dtype' to clear the transformers deprecation warning.
14
+ pipe = pipeline(
15
+ "image-text-to-text",
16
+ model=MODEL_ID,
17
+ model_kwargs={
18
+ "dtype": torch.float16,
19
+ "device_map": "auto"
20
+ }
21
+ )
22
+ print("tarn is fully initialized.")
23
+
24
+ # 2. Define the Inference Logic
25
+ def process_chat(message, history):
26
+ """
27
+ Handles incoming messages (both images and text), formats them into
28
+ the proper Qwen 3.5 VL structure, and yields streamed tokens.
29
+ """
30
+ # Force clean any leftover GPU allocation trash before processing
31
+ gc.collect()
32
+ torch.cuda.empty_cache()
33
+
34
+ # Reconstruct history into Hugging Face chat template format
35
+ formatted_messages = []
36
+
37
+ # Process previous conversation turns
38
+ for user_turn, assistant_turn in history:
39
+ if user_turn:
40
+ # Check if user input in history was a file/image dict or text
41
+ if isinstance(user_turn, dict) or (isinstance(user_turn, tuple) and len(user_turn) == 1):
42
+ img_path = user_turn[0] if isinstance(user_turn, tuple) else user_turn.get("path")
43
+ formatted_messages.append({"role": "user", "content": [{"type": "image", "url": img_path}]})
44
+ else:
45
+ formatted_messages.append({"role": "user", "content": [{"type": "text", "text": str(user_turn)}]})
46
+ if assistant_turn:
47
+ formatted_messages.append({"role": "assistant", "content": [{"type": "text", "text": str(assistant_turn)}]})
48
+
49
+ # Append current incoming turn
50
+ current_content = []
51
+
52
+ # Check if the user uploaded an image along with text
53
+ if message["files"]:
54
+ for file_info in message["files"]:
55
+ # Gradio 4+ passes files as dicts or named objects
56
+ file_path = file_info if isinstance(file_info, str) else file_info.get("path")
57
+ current_content.append({"type": "image", "url": file_path})
58
+
59
+ if message["text"]:
60
+ current_content.append({"type": "text", "text": message["text"]})
61
+
62
+ # Guard clause if user sent nothing
63
+ if not current_content:
64
+ yield ""
65
+ return
66
+
67
+ formatted_messages.append({"role": "user", "content": current_content})
68
+
69
+ # Initialize a non-blocking compilation streamer
70
+ streamer = TextIteratorStreamer(pipe.tokenizer, skip_prompt=True, skip_special_tokens=True)
71
+
72
+ # Inject VRAM patch configurations directly into generator parameters
73
+ generate_kwargs = {
74
+ "text": formatted_messages,
75
+ "max_new_tokens": 1024,
76
+ "min_pixels": 256 * 28 * 28,
77
+ "max_pixels": 512 * 28 * 28,
78
+ "generate_kwargs": {"streamer": streamer}
79
+ }
80
+
81
+ # Execute text generation on a separate background thread to keep UI interactive
82
+ thread = Thread(target=pipe, kwargs=generate_kwargs)
83
+ thread.start()
84
+
85
+ # Yield generated tokens back to UI as they arrive
86
+ partial_text = ""
87
+ for new_token in streamer:
88
+ partial_text += new_token
89
+ yield partial_text
90
+
91
+ # 3. Build Web Layout using Custom Calm Styling Themes
92
+ custom_theme = ui.themes.Soft(
93
+ primary_hue="orange", # Brings in that subtle "tangy" vibe softly
94
+ neutral_hue="slate", # Keeps the interface looking professional and clean
95
+ font=[ui.themes.GoogleFont("Source Sans Pro"), "Arial", "sans-serif"]
96
+ )
97
+
98
+ # FIX: Removed `theme=custom_theme` from Blocks (moved to launch).
99
+ with ui.Blocks(title="tarn Demo Space") as demo:
100
+ ui.Markdown(
101
+ """
102
+ # 🌌 tarn Multimodal Reasoner
103
+ ### Fine-tuned for deep visual context analysis and structured step-by-step logic.
104
+ *Built and maintained by **Xerv-AI**.*
105
+ """
106
+ )
107
+
108
+ # Core multi-turn Gradio Chatbot interface
109
+ chatbot_interface = ui.ChatInterface(
110
+ fn=process_chat,
111
+ chatbot=ui.Chatbot(
112
+ height=550,
113
+ placeholder="📸 Upload an image or ask a structural reasoning question...",
114
+ # FIX: Removed `show_copy_button=True` as it is removed in newer Gradio versions.
115
+ avatar_images=(None, "https://huggingface.co/front/assets/huggingface/logos/huggingface-logo-dark.svg")
116
+ ),
117
+ multimodal=True, # Explicitly turns on the combined image upload + text input array
118
+ textbox=ui.MultimodalTextbox(
119
+ placeholder="Type your question here... (Click the paperclip icon to pin an image)",
120
+ file_types=["image"],
121
+ scale=7
122
+ )
123
+ )
124
+
125
+ if __name__ == "__main__":
126
+ # FIX: Passed the theme to the launch method to satisfy Gradio 6.0 requirements.
127
+ demo.queue().launch(theme=custom_theme)