""" Chatterbox — HF Space chat app that writes code as downloadable files and previews HTML live, similar to Claude's "artifacts". Why the old version broke: - `mistralai/Mistral-7B-Instruct-v0.1` was dropped from HF's free serverless inference tier. - `client.text_generation(...)` with a hand-built `[INST]...[/INST]` prompt is the old (pre chat-template) way of calling models. `InferenceClient.chat_completion()` is the current, stable API and works across providers HF routes to (`provider="auto"`). Requirements (requirements.txt): gradio>=4.44 huggingface_hub>=0.26 """ import os import re import tempfile import zipfile from pathlib import Path import gradio as gr from huggingface_hub import InferenceClient # --------------------------------------------------------------------------- # Config # --------------------------------------------------------------------------- # Reads a token from the Space's secrets if you add one (needed for higher # rate limits / gated models). Works without it too, just more rate-limited. HF_TOKEN = os.environ.get("HF_TOKEN") or os.environ.get("HUGGINGFACE_TOKEN") # Models known to work through HF's free/routed serverless chat-completion # as of 2026. If one of these goes away, just remove it from the list — # HF periodically retires models from the free tier. MODEL_CHOICES = [ "meta-llama/Llama-3.1-8B-Instruct", "Qwen/Qwen2.5-Coder-32B-Instruct", "mistralai/Mistral-7B-Instruct-v0.3", "HuggingFaceH4/zephyr-7b-beta", ] DEFAULT_SYSTEM_PROMPT = ( "You are an expert software engineer, similar to Claude's coding " "assistant. When the user asks you to build or write something, answer " "with a short explanation and then one or more fenced code blocks.\n\n" "Every code block MUST start with a language tag, and its very first " "line must be a comment giving a filename, like this:\n\n" "```html\n\n...\n```\n" "```python\n# filename: app.py\nprint('hi')\n```\n\n" "Always write complete, self-contained, runnable files (inline CSS/JS " "for HTML pages). Never truncate code for brevity." ) CODE_BLOCK_RE = re.compile(r"```([a-zA-Z0-9_+-]*)\n(.*?)```", re.DOTALL) FILENAME_RE = re.compile(r"^\s*(?:#|//|