Spaces:
Sleeping
Sleeping
File size: 7,646 Bytes
21219d5 3fd1c1a 7936364 3fd1c1a aa2e87f 3fd1c1a 21219d5 d5bebb0 7936364 3fd1c1a 21219d5 3fd1c1a 21219d5 3fd1c1a 21219d5 3fd1c1a 21219d5 7936364 9bc5cc9 3fd1c1a 21219d5 7936364 21219d5 3fd1c1a 21219d5 3fd1c1a 21219d5 3fd1c1a 21219d5 22fe62c 21219d5 9bc5cc9 21219d5 3fd1c1a 21219d5 9bc5cc9 21219d5 9bc5cc9 22fe62c 9bc5cc9 21219d5 9bc5cc9 3fd1c1a 7936364 21219d5 22fe62c 21219d5 3fd1c1a d5bebb0 3fd1c1a aa2e87f 3fd1c1a aa2e87f 3fd1c1a 21219d5 7936364 9bc5cc9 7936364 3fd1c1a 7936364 21219d5 3fd1c1a aa2e87f 3fd1c1a aa2e87f 3fd1c1a aa2e87f 3fd1c1a |
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 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# app.py
import gradio as gr
import torch
from PIL import Image
from transformers import AutoModelForImageTextToText, AutoProcessor
from gradio.events import SelectData
import warnings
import os
import requests
warnings.filterwarnings("ignore", category=UserWarning, message="Overriding torch_dtype=None")
# --- 1. Tải Model và Processor ---
MODEL_ID = "sunbv56/qwen2.5-vl-vqa-vibook"
print(f"🚀 Đang tải model '{MODEL_ID}' và processor...")
try:
dtype = torch.bfloat16 if torch.cuda.is_available() and torch.cuda.is_bf16_supported() else torch.float16
model = AutoModelForImageTextToText.from_pretrained(MODEL_ID, torch_dtype=dtype, device_map="auto", trust_remote_code=True)
processor = AutoProcessor.from_pretrained(MODEL_ID, trust_remote_code=True, use_fast=True)
model.eval()
print(f"✅ Model và processor đã được tải thành công!")
except Exception as e:
print(f"❌ Lỗi khi tải model/processor: {e}")
exit()
# --- 2. Hàm Inference Cốt lõi ---
def process_vqa(image: Image.Image, question: str):
if image.mode != "RGB":
image = image.convert("RGB")
messages = [{"role": "user", "content": [{"type": "image"}, {"type": "text", "text": question}]}]
prompt_text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
model_inputs = processor(text=[prompt_text], images=[image], return_tensors="pt").to(model.device)
generated_ids = model.generate(
**model_inputs,
max_new_tokens=128,
do_sample=False,
temperature=1.0,
eos_token_id=processor.tokenizer.eos_token_id,
pad_token_id=processor.tokenizer.pad_token_id
)
generated_ids = generated_ids[:, model_inputs['input_ids'].shape[1]:]
response = processor.tokenizer.decode(generated_ids[0], skip_special_tokens=True).strip()
return response
# --- 3. Logic Chatbot ---
# ### THAY ĐỔI MỚI 1: Định nghĩa HTML và CSS cho hiệu ứng động ###
# HTML cho hiệu ứng "đang gõ"
THINKING_HTML = """
<div class="typing-indicator">
<span></span>
<span></span>
<span></span>
</div>
"""
# CSS để tạo hiệu ứng
CUSTOM_CSS = """
@keyframes blink {
0% { opacity: .2; }
20% { opacity: 1; }
100% { opacity: .2; }
}
.typing-indicator {
display: flex;
align-items: center;
justify-content: flex-start; /* Căn trái */
padding: 8px 0; /* Thêm chút khoảng đệm */
}
.typing-indicator span {
height: 10px;
width: 10px;
margin: 0 2px;
background-color: #9E9E9E; /* Màu xám */
border-radius: 50%;
animation: blink 1.4s infinite both;
}
.typing-indicator span:nth-child(2) {
animation-delay: .2s;
}
.typing-indicator span:nth-child(3) {
animation-delay: .4s;
}
"""
# Hàm dành cho việc người dùng tự nhập câu hỏi
def manual_chat_responder(user_question: str, chat_history: list, uploaded_image: Image.Image):
if uploaded_image is None:
gr.Warning("Vui lòng tải ảnh lên trước để đặt câu hỏi về nó.")
return "", chat_history
if not user_question or not user_question.strip():
gr.Warning("Vui lòng nhập một câu hỏi.")
return "", chat_history
chat_history.append({"role": "user", "content": user_question})
# ### THAY ĐỔI MỚI 2: Sử dụng HTML động thay cho text tĩnh ###
chat_history.append({"role": "assistant", "content": THINKING_HTML})
yield "", chat_history
bot_response = process_vqa(uploaded_image, user_question)
chat_history[-1]["content"] = bot_response
yield "", chat_history
# Hàm dành riêng cho việc xử lý khi nhấn vào ví dụ
def run_example(evt: SelectData):
selected_example = example_list[evt.index]
image_path, question = selected_example
gr.Info(f"Đang chạy ví dụ: \"{question}\"")
image = Image.open(image_path).convert("RGB")
# ### THAY ĐỔI MỚI 3: Sử dụng HTML động thay cho text tĩnh ###
chat_history = [
{"role": "user", "content": question},
{"role": "assistant", "content": THINKING_HTML}
]
yield image, question, chat_history
bot_response = process_vqa(image, question)
chat_history[-1]["content"] = bot_response
yield image, question, chat_history
def clear_chat():
return []
# --- 4. Định nghĩa Giao diện Người dùng Gradio ---
# ### THAY ĐỔI MỚI 4: Thêm CSS vào Blocks ###
with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"), title="Vibook VQA Chatbot", css=CUSTOM_CSS) as demo:
gr.Markdown("# 🤖 Vibook VQA Chatbot")
example_list = [
["./assets/book_example_1.jpg", "Đâu là tên đúng của cuốn sách này?"],
["./assets/book_example_1.jpg", "Ai là người đã viết cuốn sách này?"],
["./assets/book_example_2.jpg", "tác giả và tên của cuốn sách là gì?"],
]
with gr.Row(equal_height=False):
with gr.Column(scale=1, min_width=350):
gr.Markdown("### Bảng điều khiển")
image_input = gr.Image(type="pil", label="Tải ảnh lên", sources=["upload", "clipboard", "webcam"])
gr.Markdown("---")
gr.Markdown("### Ví dụ (Nhấn để chạy)")
example_dataset = gr.Dataset(components=[gr.Image(visible=False), gr.Textbox(visible=False)], samples=example_list, label="Ví dụ", type="index")
with gr.Column(scale=2):
chatbot = gr.Chatbot(label="Cuộc trò chuyện", height=600, avatar_images=(None, "https://huggingface.co/datasets/huggingface/brand-assets/resolve/main/hf-logo.png"), type="messages", value=[])
question_input = gr.Textbox(label="Hoặc nhập câu hỏi về ảnh đã tải lên", placeholder="Nhập câu hỏi và nhấn Enter...", container=False, scale=7)
# --- 5. Xử lý Sự kiện ---
question_input.submit(fn=manual_chat_responder, inputs=[question_input, chatbot, image_input], outputs=[question_input, chatbot])
example_dataset.select(fn=run_example, inputs=None, outputs=[image_input, question_input, chatbot], show_progress="full")
image_input.upload(fn=clear_chat, inputs=None, outputs=[chatbot])
image_input.clear(fn=clear_chat, inputs=None, outputs=[chatbot])
# --- Phần cuối ---
if __name__ == "__main__":
ASSETS_DIR = "assets"
if not os.path.exists(ASSETS_DIR):
os.makedirs(ASSETS_DIR)
print("Đã tạo thư mục 'assets' cho các hình ảnh ví dụ.")
EXAMPLE_FILES = {
"book_example_1.jpg": "https://cdn0.fahasa.com/media/catalog/product/d/i/dieu-ky-dieu-cua-tiem-tap-hoa-namiya---tai-ban-2020.jpg",
"book_example_2.jpg": "https://cdn0.fahasa.com/media/catalog/product/d/r/dr.-stone_bia_tap-26.jpg"
}
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"}
for filename, url in EXAMPLE_FILES.items():
filepath = os.path.join(ASSETS_DIR, filename)
if not os.path.exists(filepath):
print(f"Đang tải xuống hình ảnh ví dụ: {filename}...")
try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
with open(filepath, 'wb') as f:
f.write(response.content)
print("...Đã xong.")
except requests.exceptions.RequestException as e:
print(f" Lỗi khi tải {filename}: {e}")
demo.launch(debug=True) |