zero_gpumodel / app.py
malek391's picture
Upload 3 files
3e110e0 verified
Raw
History Blame Contribute Delete
3.53 kB
"""Hugging Face Space — fine-tuned Flutter coder (ZeroGPU, free tier).
Deploy: create a new Gradio Space, upload this folder, set hardware to ZeroGPU.
Set HF Space URL in the Flutter IDE Settings (HUGGINGFACE_SPACE_URL).
"""
import os
import gradio as gr
import spaces
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
MODEL_ID = os.environ.get("HF_MODEL_ID", "malek391/my-custom-flutter-coder")
HF_TOKEN = os.environ.get("HF_TOKEN") or os.environ.get("HUGGINGFACE_ACCESS_TOKEN")
MAX_NEW_TOKENS = int(os.environ.get("MAX_NEW_TOKENS", "2048"))
_tokenizer = None
_model = None
def load_model():
"""Load on first GPU request — ZeroGPU has no CUDA at container startup."""
global _tokenizer, _model
if _model is not None:
return _tokenizer, _model
_tokenizer = AutoTokenizer.from_pretrained(
MODEL_ID,
token=HF_TOKEN,
trust_remote_code=True,
)
quant_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_quant_type="nf4",
)
_model = AutoModelForCausalLM.from_pretrained(
MODEL_ID,
token=HF_TOKEN,
trust_remote_code=True,
quantization_config=quant_config,
device_map="cuda",
)
return _tokenizer, _model
def gpu_duration(system_prompt: str, user_prompt: str, temperature: float, *args, **kwargs) -> int:
"""Keep declared duration under ZeroGPU free-tier per-call cap (~180s effective)."""
prompt_len = len(system_prompt or "") + len(user_prompt or "")
# Shorter prompts → lower reservation (better queue priority, less quota blocked)
return min(90, 60 + prompt_len // 800)
@spaces.GPU(duration=gpu_duration)
def chat(system_prompt: str, user_prompt: str, temperature: float) -> str:
"""OpenAI-style chat via system + user strings (Gradio API name: chat)."""
tokenizer, model = load_model()
messages = []
if system_prompt and system_prompt.strip():
messages.append({"role": "system", "content": system_prompt.strip()})
messages.append({"role": "user", "content": user_prompt.strip()})
if hasattr(tokenizer, "apply_chat_template"):
prompt = tokenizer.apply_chat_template(
messages, tokenize=False, add_generation_prompt=True
)
else:
prompt = f"{system_prompt}\n\n{user_prompt}"
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
temp = max(0.05, min(float(temperature), 1.0))
with torch.no_grad():
output = model.generate(
**inputs,
max_new_tokens=MAX_NEW_TOKENS,
temperature=temp,
do_sample=temp > 0.05,
pad_token_id=tokenizer.eos_token_id,
)
generated = output[0][inputs.input_ids.shape[1] :]
return tokenizer.decode(generated, skip_special_tokens=True)
demo = gr.Interface(
fn=chat,
inputs=[
gr.Textbox(label="System prompt", lines=4, placeholder="System instructions…"),
gr.Textbox(label="User prompt", lines=12, placeholder="User message…"),
gr.Slider(0.05, 1.0, value=0.25, step=0.05, label="Temperature"),
],
outputs=gr.Textbox(label="Model response", lines=20),
title="My Custom Flutter Coder",
description=(
f"Fine-tuned Qwen2.5-Coder served from `{MODEL_ID}` on ZeroGPU (4-bit). "
"First request may take ~1 min while the model loads."
),
api_name="chat",
)
if __name__ == "__main__":
demo.launch()