Gemma4-Gradio / app.py
AdrianLi33's picture
Create app.py
028cff0 verified
Raw
History Blame Contribute Delete
6.41 kB
#!pip install -U transformers gradio pillow
import torch
import gradio as gr
from transformers import AutoProcessor, AutoModelForImageTextToText
from PIL import Image
# โ”€โ”€ ่ผ‰ๅ…ฅๆจกๅž‹ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
MODEL_ID = "google/gemma-4-12B"
print(f"่ผ‰ๅ…ฅๆจกๅž‹๏ผš{MODEL_ID} ...")
processor = AutoProcessor.from_pretrained(MODEL_ID)
model = AutoModelForImageTextToText.from_pretrained(
MODEL_ID,
torch_dtype=torch.float16,
device_map="auto",
)
model.eval()
print("ๆจกๅž‹่ผ‰ๅ…ฅๅฎŒๆˆ๏ผ")
# โ”€โ”€ ๆŽจ่ซ–ๅ‡ฝๅผ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def build_messages(history: list[dict], user_text: str, image=None) -> list[dict]:
"""ๅฐ‡ Gradio ๆญทๅฒ่จ˜้Œ„่ฝ‰ๆ›ๆˆ HuggingFace messages ๆ ผๅผใ€‚"""
messages = []
# ๅŠ ๅ…ฅๆญทๅฒๅฐ่ฉฑ
for turn in history:
messages.append({"role": "user", "content": [{"type": "text", "text": turn["content"] if turn["role"] == "user" else ""}]})
messages.append({"role": "assistant", "content": [{"type": "text", "text": turn["content"] if turn["role"] == "assistant" else ""}]})
# ๅŠ ๅ…ฅๆœฌ่ผชไฝฟ็”จ่€…่จŠๆฏ
user_content = []
if image is not None:
user_content.append({"type": "image", "image": image})
user_content.append({"type": "text", "text": user_text})
messages.append({"role": "user", "content": user_content})
return messages
def chat(
user_message: str,
image,
history: list[dict],
max_new_tokens: int,
temperature: float,
top_p: float,
):
"""ไธปๅฐ่ฉฑๅ‡ฝๅผ๏ผŒๅ›žๅ‚ณๆ›ดๆ–ฐๅพŒ็š„ๆญทๅฒ่ˆ‡ๆธ…็ฉบ็š„่ผธๅ…ฅใ€‚"""
if not user_message.strip() and image is None:
return history, history, gr.update(value=""), gr.update(value=None)
# ๅปบๆง‹ messages
messages = build_messages(history, user_message, image)
# Processor ๅ‰่™•็†
pil_images = [image] if image is not None else None
inputs = processor.apply_chat_template(
messages,
add_generation_prompt=True,
tokenize=True,
return_tensors="pt",
return_dict=True,
images=pil_images,
).to(model.device, dtype=torch.float16)
# ็”Ÿๆˆๅ›ž่ฆ†
with torch.inference_mode():
output_ids = model.generate(
**inputs,
max_new_tokens=max_new_tokens,
do_sample=temperature > 0,
temperature=temperature if temperature > 0 else 1.0,
top_p=top_p,
)
# ๅชๅ–ๆ–ฐ็”Ÿๆˆ็š„้ƒจๅˆ†
input_len = inputs["input_ids"].shape[-1]
generated_ids = output_ids[:, input_len:]
response = processor.decode(generated_ids[0], skip_special_tokens=True).strip()
# ๆ›ดๆ–ฐๆญทๅฒ๏ผˆไฝฟ็”จ Gradio messages ๆ ผๅผ๏ผ‰
history = history + [
{"role": "user", "content": user_message},
{"role": "assistant", "content": response},
]
return history, history, gr.update(value=""), gr.update(value=None)
def clear_history():
return [], [], gr.update(value=""), gr.update(value=None)
# โ”€โ”€ Gradio UI โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
with gr.Blocks(
title="Gemma-4 Chat",
theme=gr.themes.Soft(primary_hue="emerald"),
css="""
#chatbot { height: 550px; }
.send-btn { background: #10b981 !important; color: white !important; }
footer { display: none !important; }
""",
) as demo:
# โ”€โ”€ ๆจ™้กŒ โ”€โ”€
gr.Markdown(
"""
# ๐Ÿค– Gemma-4 ๅคšๆจกๆ…‹ๅฐ่ฉฑๅŠฉ็†
ๆ”ฏๆด็ด”ๆ–‡ๅญ—ๅฐ่ฉฑ๏ผŒไบฆๅฏไธŠๅ‚ณๅœ–็‰‡้€ฒ่กŒๅœ–ๆ–‡ๅ•็ญ”ใ€‚
"""
)
# โ”€โ”€ ๅฐ่ฉฑ็‹€ๆ…‹ โ”€โ”€
state = gr.State([]) # ๅ„ฒๅญ˜ messages ๆญทๅฒ
with gr.Row():
# โ”€โ”€ ๅทฆๆฌ„๏ผš่Šๅคฉ่ฆ–็ช— โ”€โ”€
with gr.Column(scale=3):
chatbot = gr.Chatbot(
elem_id="chatbot",
label="ๅฐ่ฉฑ่ฆ–็ช—",
type="messages", # ไฝฟ็”จ dict ๆ ผๅผ
avatar_images=(None, "https://huggingface.co/datasets/huggingface/brand-assets/resolve/main/hf-logo.svg"),
)
with gr.Row():
user_input = gr.Textbox(
placeholder="่ผธๅ…ฅ่จŠๆฏ๏ผŒๆŒ‰ Enter ๆˆ–้ปžๆ“Š้€ๅ‡บโ€ฆ",
show_label=False,
lines=2,
scale=5,
)
send_btn = gr.Button("้€ๅ‡บ โ–ถ", elem_classes="send-btn", scale=1)
# โ”€โ”€ ๅณๆฌ„๏ผš่จญๅฎš่ˆ‡ๅœ–็‰‡ไธŠๅ‚ณ โ”€โ”€
with gr.Column(scale=1):
image_input = gr.Image(
label="ไธŠๅ‚ณๅœ–็‰‡๏ผˆ้ธๅกซ๏ผ‰",
type="pil",
height=220,
)
gr.Markdown("### โš™๏ธ ็”Ÿๆˆๅƒๆ•ธ")
max_new_tokens = gr.Slider(64, 2048, value=512, step=64, label="ๆœ€ๅคง็”Ÿๆˆ้•ทๅบฆ")
temperature = gr.Slider(0.0, 2.0, value=0.7, step=0.05, label="Temperature๏ผˆ0 = ็ขบๅฎšๆ€ง๏ผ‰")
top_p = gr.Slider(0.1, 1.0, value=0.9, step=0.05, label="Top-p")
clear_btn = gr.Button("๐Ÿ—‘๏ธ ๆธ…้™คๅฐ่ฉฑ", variant="secondary")
# โ”€โ”€ ไบ‹ไปถ็ถๅฎš โ”€โ”€
send_inputs = [user_input, image_input, state, max_new_tokens, temperature, top_p]
send_outputs = [chatbot, state, user_input, image_input]
send_btn.click(chat, inputs=send_inputs, outputs=send_outputs)
user_input.submit(chat, inputs=send_inputs, outputs=send_outputs)
clear_btn.click(clear_history, outputs=[chatbot, state, user_input, image_input])
# โ”€โ”€ ๅ•Ÿๅ‹• โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
if __name__ == "__main__":
demo.launch(
server_name="0.0.0.0", # ๅ…่จฑๅค–้ƒจ้€ฃ็ทš๏ผˆColab / ้ ็ซฏไผบๆœๅ™จ็”จ๏ผ‰
server_port=7860,
share=False, # ่จญ็‚บ True ๅฏ็”ข็”Ÿๅ…ฌ้–‹้€ฃ็ต๏ผˆColab ้œ€่ฆ๏ผ‰
inbrowser=True,
)