Spaces:
Sleeping
Sleeping
| """ | |
| Gradio demo for the SLM-264M recipe generator fine-tune (ZeroGPU). | |
| """ | |
| import os | |
| import spaces | |
| import torch | |
| import gradio as gr | |
| from tokenizers import Tokenizer | |
| from huggingface_hub import hf_hub_download | |
| MODEL_REPO = os.environ.get("MODEL_REPO", "uday210/slm-recipe-264m") # <-- EDIT to your recipe repo | |
| CKPT_FILENAME = os.environ.get("CKPT_FILENAME", "slm-recipe-final.pt") # <-- EDIT to real filename | |
| TOKENIZER_FILENAME = os.environ.get("TOKENIZER_FILENAME", "tokenizer.json") | |
| PROMPT_TEMPLATE = "Make a recipe using: {ingredients}\n" | |
| BLOCK_SIZE = 2048 | |
| EOT_TOKEN = "<|endoftext|>" | |
| from model import GPT # noqa: E402 (your import-safe model.py) | |
| _token = os.environ.get("HF_TOKEN") | |
| ckpt_path = hf_hub_download(MODEL_REPO, CKPT_FILENAME, token=_token) | |
| tok_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), TOKENIZER_FILENAME) | |
| ckpt = torch.load(ckpt_path, map_location="cpu", weights_only=False) | |
| model = GPT(ckpt["config"]) | |
| model.load_state_dict(ckpt["model"]) | |
| model.eval() | |
| tok = Tokenizer.from_file(tok_path) | |
| EOT_ID = tok.token_to_id(EOT_TOKEN) | |
| _moved = False | |
| def generate(prompt: str, max_new_tokens: int = 400, temperature: float = 0.8, top_k: int = 50): | |
| global _moved | |
| if not _moved: | |
| model.to("cuda") | |
| _moved = True | |
| ids = tok.encode(prompt).ids | |
| x = torch.tensor(ids, dtype=torch.long, device="cuda")[None] | |
| start = len(ids) | |
| for _ in range(max_new_tokens): | |
| logits, _ = model(x[:, -BLOCK_SIZE:]) | |
| logits = logits[:, -1, :] | |
| if temperature and temperature > 0: | |
| logits = logits / temperature | |
| if top_k: | |
| v, _ = torch.topk(logits, min(top_k, logits.size(-1))) | |
| logits[logits < v[:, [-1]]] = -float("inf") | |
| probs = torch.softmax(logits, dim=-1) | |
| nxt = torch.multinomial(probs, num_samples=1) | |
| else: | |
| nxt = logits.argmax(dim=-1, keepdim=True) | |
| x = torch.cat([x, nxt], dim=1) | |
| if EOT_ID is not None and nxt.item() == EOT_ID: | |
| break | |
| yield tok.decode(x[0, start:].tolist()) | |
| yield tok.decode(x[0, start:].tolist()) | |
| def make_recipe(ingredients, max_new_tokens, temperature): | |
| ingredients = (ingredients or "").strip() | |
| if not ingredients: | |
| yield "Enter a few ingredients first (e.g. chicken, rice, lemon)." | |
| return | |
| prompt = PROMPT_TEMPLATE.format(ingredients=ingredients) | |
| for partial in generate(prompt, int(max_new_tokens), float(temperature)): | |
| yield partial | |
| with gr.Blocks(title="SLM-264M Recipe Generator", theme=gr.themes.Soft()) as demo: | |
| gr.Markdown( | |
| "# 🍳 SLM-264M Recipe Generator\n" | |
| "A 264M small language model, trained from scratch and fine-tuned to turn a list " | |
| "of ingredients into a recipe.\n\n" | |
| "*Note: format is reliable; it can occasionally repeat an ingredient or drift on " | |
| "long recipes — it's a 264M model.*" | |
| ) | |
| with gr.Row(): | |
| with gr.Column(): | |
| ingredients = gr.Textbox( | |
| label="Ingredients", value="chicken, rice, lemon", lines=3, | |
| placeholder="e.g. chicken, rice, lemon", | |
| ) | |
| with gr.Accordion("Advanced", open=False): | |
| max_tok = gr.Slider(100, 800, value=400, step=50, label="Max new tokens") | |
| temp = gr.Slider( | |
| 0.0, 1.2, value=0.8, step=0.1, | |
| label="Temperature (higher = more varied; ~0.8 is a good default)", | |
| ) | |
| go = gr.Button("Generate recipe", variant="primary") | |
| gr.Examples( | |
| examples=[ | |
| ["chicken, rice, lemon"], | |
| ["flour, sugar, butter, eggs, chocolate"], | |
| ["tomato, basil, garlic, pasta"], | |
| ], | |
| inputs=[ingredients], | |
| ) | |
| with gr.Column(): | |
| out = gr.Textbox(label="Recipe", lines=18, show_copy_button=True) | |
| go.click(make_recipe, [ingredients, max_tok, temp], out) | |
| ingredients.submit(make_recipe, [ingredients, max_tok, temp], out) | |
| if __name__ == "__main__": | |
| demo.launch() |