Deploy a Free AI Chat Assistant
Build and deploy an AI chatbot on Hugging Face Spaces at zero cost.
Introduction
30 Second Summary
You have probably chatted with AI assistants like ChatGPT or Gemini. But have you ever wondered what it takes to build and host one yourself?
In this project, you will build your own AI chat assistant and deploy it to a live public URL using Hugging Face Spaces. Everything happens in your web browser. No downloads, no installation, and no terminal commands needed.
What You'll Build
A browser-based AI chat assistant powered by the Qwen2.5-0.5B-Instruct open-source language model, running entirely on free CPU hardware with a clean Gradio interface.
By the end of this project, you'll have:
- A live AI chatbot deployed on Hugging Face Spaces that anyone can access via a public URL.
- Hands-on experience navigating the Hugging Face ecosystem, reading model cards, and choosing a model for a project.
- A chatbot with multiple assistant modes (Chat, Explain, Quiz, Summarize) that demonstrates simple prompt routing.
- Secret Mission: Switch the model to a smaller alternative and compare performance.
Are there any prerequisites?
No prior AI or machine learning experience is required. You just need a web browser and a free Hugging Face account (which you will create during the project). This works identically on Windows, Mac, Linux, or Chromebook.
Explore Hugging Face and Create Your Space
Before writing any code, you need a place to host your AI chatbot. Hugging Face is a platform where thousands of AI models, datasets, and apps live. It also provides free cloud hosting for apps through a feature called Spaces.
In this step, you will explore the Hugging Face ecosystem to understand what is available, create a free account, and set up your own Space where the chatbot will live.
In this step, get ready to:
- Explore the Hugging Face Tasks page and read a model card.
- Create a free Hugging Face account.
- Create a new Space and commit your first file.
Explore Hugging Face Tasks before we build
Hugging Face organizes AI capabilities into tasks. Browsing the Tasks page helps you understand the landscape before picking a model for your project.
- Open your web browser and go to huggingface.co/tasks.
- Notice the major categories listed on the page: Multimodal, Natural Language Processing, Computer Vision, Audio, Tabular, and Reinforcement Learning.
- Click into Text Generation (or go directly to huggingface.co/tasks/text-generation).
- On the Text Generation page, notice the use cases (Instruction Models, Code Generation, Stories Generation), model variants, and example code.
Why text generation?
Your chatbot works by generating text one token at a time in response to a user's message. That makes Text Generation the relevant AI task for this project.
Now you will find and read the model card for the specific model this project uses.
- Go to huggingface.co and type Qwen/Qwen2.5-0.5B-Instruct in the search bar at the top of the page.
- Click on the Qwen/Qwen2.5-0.5B-Instruct result to open its model card.
- Read through the model card page. Notice the model name, the Files section, the usage code snippets, and the Apache-2.0 license.
What is a model card?
A model card is like a profile page for an AI model. It tells you what the model does, who created it, how to use it, what license it has, and what limitations it may have.
You are not just using an AI model in this project. You are learning how to explore the Hugging Face model ecosystem, choose a model, and deploy it into a real app.
Create a free Hugging Face account
You need an account to create a Space and host your chatbot.
- Go to huggingface.co and click Sign Up in the top right corner.
- Fill in your email, pick a username and password, then click Create Account.
- Check your email inbox for a verification message from Hugging Face.
- Click the verification link in the email to activate your account.
Already have an account?
If you already have a Hugging Face account, click Log In instead and skip ahead to the next substep.
Create a new Space and your first file
A Space is a mini cloud environment where your app will run. Hugging Face Spaces gives you free CPU hardware to host Gradio apps without installing anything on your own computer.
- Click your profile icon in the top right corner of the Hugging Face website.
- Select New Space from the dropdown menu.
- In the Space name field, type my-ai-assistant.
- Under SDK, select Gradio.
- Under Template, select Blank.
- Set Hardware to CPU Basic (Free).
- Set Visibility to Public.
- Click Create Space.
What is the CPU Basic tier?
The CPU Basic (Free) tier gives you 2 vCPUs and 16 GB of RAM at no cost. That is more than enough to run a small language model like Qwen2.5-0.5B-Instruct.
Your Space is now created and waiting for files. Next, you will add the first file that tells the Space which Python packages to install.
- Click the Files tab at the top of your Space page.
- Click Contribute, then select Create a new file.
- In the filename field at the top of the editor, type requirements.txt.
- Paste the following code into the editor area:
transformers>=5.0.0
torch>=2.0.0
gradio>=4.0.0
What does this file do?
The requirements.txt file tells Hugging Face Spaces which Python packages to install before running your app. Each line names a package and a minimum version.
- transformers is the Hugging Face Transformers library for loading AI models.
- torch is PyTorch, the deep learning framework the model runs on.
- gradio is the UI framework that creates the chat interface.
- Scroll down to the bottom of the page where it says Commit new file.
- Leave the default commit message or type a short description like Add requirements.
- Click Commit new file to main.
You should now see requirements.txt listed in your Space's Files tab.
Don't see the file listed?
Make sure you clicked Commit new file to main at the bottom of the editor. If you navigated away before committing, the file was not saved.
Also confirm you are on the Files tab (not the App tab). The App tab shows the running application, which is not ready yet.
Still stuck? Help me find my committed file in my Hugging Face Space.
✔️ Awesome, I've got everything!
Great. Double check you have saved and committed the file before moving on.
ⓧ I'd like to double check the full code
Here is the complete requirements.txt file for comparison:
transformers>=5.0.0
torch>=2.0.0
gradio>=4.0.0
Your Space is ready and waiting for the main application file. Next up, you will write the chatbot code that loads the AI model and responds to messages.
Build the Basic AI Chat App
Your Space is set up and your dependencies are declared in requirements.txt. Now it is time to write the actual chatbot application.
In this step, you will create the main Python file that loads an open-source language model and wires it to a chat interface. By the end, your Space will have a complete (single-mode) AI assistant ready to respond to messages.
In this step, get ready to:
- Create app.py in your Space using the web editor.
- Load the Qwen2.5-0.5B-Instruct model with CPU-safe settings.
- Wire the model to a Gradio chat interface.
Create app.py in your Space
The app.py file is the main application file that Hugging Face Spaces looks for when it builds your project. It will load the Qwen/Qwen2.5-0.5B-Instruct model and tokenizer using the same imports you saw on the model card: AutoModelForCausalLM and AutoTokenizer from the Hugging Face Transformers library.
- In your Space, click the Files tab.
- Click Contribute, then select Create a new file.
- Type app.py as the filename.
Understand the response function and CPU-safe settings
Before you paste the code, here is what it does at a high level.
What does this code do?
The model loading section uses torch.float32 instead of BF16 because not all CPUs support BF16 natively. Float32 is universally safe on CPU hardware.
The respond function calls convert_history(history) to safely normalize the chat history into a consistent list of message dictionaries. It then formats messages using apply_chat_template (the same pattern from the model card) and generates responses with conservative settings: max_new_tokens=120, temperature=0.7, top_p=0.9, and do_sample=True. These keep generation fast on free CPU hardware.
Model loading and generation are wrapped in try/except blocks so the app shows a friendly error message instead of crashing.
💡 Why torch.float32 instead of BF16?
The Qwen2.5-0.5B-Instruct model card stores weights in BF16 format. However, the free CPU Basic tier on Hugging Face Spaces may not support BF16 natively. Explicitly setting dtype=torch.float32 ensures the model loads safely on any CPU.
The free tier provides 16 GB of RAM, and the model in float32 uses approximately 2 GB. This fits comfortably.
Paste the complete chatbot code
- Paste the following code into the app.py editor:
import gradio as gr
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
# --- Model Setup ---
# We use Qwen2.5-0.5B-Instruct: a small but capable instruction-tuned model
model_name = "Qwen/Qwen2.5-0.5B-Instruct"
print(f"Loading model: {model_name}")
print("This may take a minute on CPU...")
try:
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
model_name,
dtype=torch.float32
)
model.eval()
print("Model loaded successfully!")
except Exception as e:
print(f"Error loading model: {e}")
model = None
tokenizer = None
# --- System Prompt ---
SYSTEM_PROMPT = (
"You are a friendly and helpful AI assistant. "
"Keep your responses concise, clear, and helpful. "
"If you are unsure about something, say so honestly."
)
# --- History Conversion Helper ---
# Gradio chat history can arrive as dictionaries (new format) or lists/tuples
# (older format) depending on the Gradio version. This helper handles both.
def convert_history(history):
"""Convert chat history into a clean list of message dictionaries."""
messages = []
for msg in history:
if isinstance(msg, dict):
# New format: {"role": "user", "content": "..."}
role = msg.get("role", "")
content = msg.get("content", "")
if role in ("user", "assistant") and content:
messages.append({"role": role, "content": str(content)})
elif isinstance(msg, (list, tuple)) and len(msg) >= 2:
# Older format: ["user message", "assistant response"]
if msg[0]:
messages.append({"role": "user", "content": str(msg[0])})
if msg[1]:
messages.append({"role": "assistant", "content": str(msg[1])})
return messages
# --- Response Function ---
def respond(message, history):
if model is None or tokenizer is None:
return "Sorry, the model failed to load. Please check the Space logs."
messages = [{"role": "system", "content": SYSTEM_PROMPT}]
# Convert history to a consistent format before building messages
messages.extend(convert_history(history))
messages.append({"role": "user", "content": message})
try:
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
model_inputs = tokenizer([text], return_tensors="pt")
with torch.no_grad():
generated_ids = model.generate(
**model_inputs,
max_new_tokens=120,
temperature=0.7,
top_p=0.9,
do_sample=True,
)
generated_ids = generated_ids[0][model_inputs["input_ids"].shape[1]:]
response = tokenizer.decode(generated_ids, skip_special_tokens=True)
return response.strip()
except Exception as e:
return f"Sorry, I encountered an error: {str(e)}"
# --- Gradio Interface ---
demo = gr.ChatInterface(
fn=respond,
title="AI Study Assistant",
description=(
"A free AI assistant powered by a small open-source model. "
"Responses may take 10-30 seconds on free CPU hardware."
),
examples=[
["What is machine learning?"],
["Explain how the internet works"],
["What is the capital of France?"],
],
)
if __name__ == "__main__":
demo.launch()
What is happening in each section?
- Model Setup loads the Qwen2.5-0.5B-Instruct model and tokenizer into memory using float32.
- System Prompt defines the personality of your assistant. It tells the model to be friendly, concise, and honest.
- History Conversion Helper is a convert_history() function that normalizes chat history into a consistent dictionary format. Gradio can send history as dictionaries or as list/tuple pairs depending on the version, so this helper handles both safely.
- Response Function takes the user message, converts the chat history using convert_history(), formats everything into the model's expected template, generates a response, and returns it.
- Gradio Interface creates the chat UI with a title, description, and clickable example prompts.
- Scroll down and click Commit new file to main (or Commit changes) to save app.py to your Space.
After committing, your Space will start building automatically. You do not need to deploy it yourself.
Why does the Space rebuild on commit?
Hugging Face Spaces are backed by a Git repository. Every time you commit a file, the platform detects the change and triggers a fresh build. It installs your requirements.txt packages, downloads the model, and starts your app.
🙋♀️ Don't see a Commit button?
Make sure you are on the Hub repo page (huggingface.co/spaces/...) and not on the running app page (*.hf.space). The repo page is where file editing and commit controls live.
If you still cannot see the button, confirm you are logged in by checking the profile icon in the top right corner.
Help me commit my app.py file to my Hugging Face Space.
✔️ Awesome, I've got everything!
Great. Double check you have saved and committed your app.py file.
ⓧ I'd like to double check the full code
Here is the complete app.py you should have committed to your Space:
import gradio as gr
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
# --- Model Setup ---
# We use Qwen2.5-0.5B-Instruct: a small but capable instruction-tuned model
model_name = "Qwen/Qwen2.5-0.5B-Instruct"
print(f"Loading model: {model_name}")
print("This may take a minute on CPU...")
try:
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
model_name,
dtype=torch.float32
)
model.eval()
print("Model loaded successfully!")
except Exception as e:
print(f"Error loading model: {e}")
model = None
tokenizer = None
# --- System Prompt ---
SYSTEM_PROMPT = (
"You are a friendly and helpful AI assistant. "
"Keep your responses concise, clear, and helpful. "
"If you are unsure about something, say so honestly."
)
# --- History Conversion Helper ---
# Gradio chat history can arrive as dictionaries (new format) or lists/tuples
# (older format) depending on the Gradio version. This helper handles both.
def convert_history(history):
"""Convert chat history into a clean list of message dictionaries."""
messages = []
for msg in history:
if isinstance(msg, dict):
# New format: {"role": "user", "content": "..."}
role = msg.get("role", "")
content = msg.get("content", "")
if role in ("user", "assistant") and content:
messages.append({"role": role, "content": str(content)})
elif isinstance(msg, (list, tuple)) and len(msg) >= 2:
# Older format: ["user message", "assistant response"]
if msg[0]:
messages.append({"role": "user", "content": str(msg[0])})
if msg[1]:
messages.append({"role": "assistant", "content": str(msg[1])})
return messages
# --- Response Function ---
def respond(message, history):
if model is None or tokenizer is None:
return "Sorry, the model failed to load. Please check the Space logs."
messages = [{"role": "system", "content": SYSTEM_PROMPT}]
# Convert history to a consistent format before building messages
messages.extend(convert_history(history))
messages.append({"role": "user", "content": message})
try:
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
model_inputs = tokenizer([text], return_tensors="pt")
with torch.no_grad():
generated_ids = model.generate(
**model_inputs,
max_new_tokens=120,
temperature=0.7,
top_p=0.9,
do_sample=True,
)
generated_ids = generated_ids[0][model_inputs["input_ids"].shape[1]:]
response = tokenizer.decode(generated_ids, skip_special_tokens=True)
return response.strip()
except Exception as e:
return f"Sorry, I encountered an error: {str(e)}"
# --- Gradio Interface ---
demo = gr.ChatInterface(
fn=respond,
title="AI Study Assistant",
description=(
"A free AI assistant powered by a small open-source model. "
"Responses may take 10-30 seconds on free CPU hardware."
),
examples=[
["What is machine learning?"],
["Explain how the internet works"],
["What is the capital of France?"],
],
)
if __name__ == "__main__":
demo.launch()
Try out your live chat interface
Your Space started building the moment you committed app.py. Once the build finishes, your AI assistant is live and ready to chat.
- Click the App tab at the top of your Space page.
- Wait for the status badge to change from Building to Running. This can take 2-5 minutes while the model downloads.
- Once the chat interface appears, type a message in the text box at the bottom (for example, What is machine learning?) and press Enter.
- Wait 10-30 seconds for the model to generate a response.
What should I see?
You should see a chat interface with the title AI Study Assistant at the top, a short description about free CPU hardware, and three clickable example prompts below.
At the bottom is a text input box where you type your messages. After you send a message, the model's reply appears in a chat bubble above.
🙋♀️ Still see Building or an error?
The first build takes longer because it downloads the model (around 1 GB). Give it up to 5 minutes before troubleshooting.
If you see a Runtime error, click the Logs tab to check for typos in your code. The most common issue is a missing import or an indentation error in app.py.
Still stuck? Help me debug my Hugging Face Space that is not loading.
Your basic chatbot code is committed. Next up, you will upgrade this single-mode assistant into a multi-mode chatbot with different personalities for different tasks.
Add Multi-Mode Prompt Routing
Your chatbot works, but it only has one personality. Every message gets the same general-purpose system prompt, no matter what the user needs.
In this step, you will add prompt routing. Instead of a single instruction set, the chatbot will offer four modes that each shape how the model responds. The user picks a mode from a dropdown, and the model adapts its behavior instantly.
In this step, get ready to:
- Define four system prompts for different assistant modes.
- Update the response function to accept a mode parameter.
- Add a dropdown component to the Gradio interface.
Open app.py in the web editor
The Hugging Face Spaces web editor lets you modify files directly in your browser. You will replace the entire contents of app.py with an upgraded version that includes multi-mode routing.
- In your Space, click the Files tab at the top of the page.
- Click on app.py to open the file viewer.
- Click the pencil icon (Edit) to enter edit mode.
- Select all the existing code and delete it. You will paste the full replacement next.
Paste the multi-mode version
The upgraded code replaces the single SYSTEM_PROMPT string with a dictionary called SYSTEM_PROMPTS. Each key in the dictionary corresponds to a mode the user can select.
The respond function now takes a third parameter (mode) and looks up the matching system prompt before sending messages to the model. A gr.Dropdown component wired as an additional_input lets users switch modes directly in the chat interface.
- Paste the following complete code into the now-empty editor:
import gradio as gr
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
# --- Model Setup ---
model_name = "Qwen/Qwen2.5-0.5B-Instruct"
print(f"Loading model: {model_name}")
print("This may take a minute on CPU...")
try:
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
model_name,
dtype=torch.float32
)
model.eval()
print("Model loaded successfully!")
except Exception as e:
print(f"Error loading model: {e}")
model = None
tokenizer = None
# --- System Prompts for Each Mode ---
SYSTEM_PROMPTS = {
"Chat": (
"You are a friendly and helpful AI assistant. "
"Keep your responses concise, clear, and helpful. "
"If you are unsure about something, say so honestly."
),
"Explain Like I'm New": (
"You are a patient teacher explaining concepts to a complete beginner. "
"Use simple language, short sentences, and everyday analogies. "
"Avoid jargon. Break complex ideas into small pieces."
),
"Quiz Me": (
"You are a quiz master. When the user gives you a topic, "
"generate one multiple-choice question with 4 options (A, B, C, D) "
"and indicate the correct answer at the end. Keep it educational and fun."
),
"Summarize": (
"You are a summarization assistant. "
"When the user gives you text, summarize it in 2-3 short sentences. "
"Focus on the key points only."
),
}
# --- History Conversion Helper ---
# Gradio chat history can arrive as dictionaries (new format) or lists/tuples
# (older format) depending on the Gradio version. This helper handles both.
def convert_history(history):
"""Convert chat history into a clean list of message dictionaries."""
messages = []
for msg in history:
if isinstance(msg, dict):
# New format: {"role": "user", "content": "..."}
role = msg.get("role", "")
content = msg.get("content", "")
if role in ("user", "assistant") and content:
messages.append({"role": role, "content": str(content)})
elif isinstance(msg, (list, tuple)) and len(msg) >= 2:
# Older format: ["user message", "assistant response"]
if msg[0]:
messages.append({"role": "user", "content": str(msg[0])})
if msg[1]:
messages.append({"role": "assistant", "content": str(msg[1])})
return messages
# --- Response Function ---
def respond(message, history, mode):
if model is None or tokenizer is None:
return "Sorry, the model failed to load. Please check the Space logs."
system_prompt = SYSTEM_PROMPTS.get(mode, SYSTEM_PROMPTS["Chat"])
messages = [{"role": "system", "content": system_prompt}]
# Convert history to a consistent format before building messages
messages.extend(convert_history(history))
messages.append({"role": "user", "content": message})
try:
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
model_inputs = tokenizer([text], return_tensors="pt")
with torch.no_grad():
generated_ids = model.generate(
**model_inputs,
max_new_tokens=120,
temperature=0.7,
top_p=0.9,
do_sample=True,
)
generated_ids = generated_ids[0][model_inputs["input_ids"].shape[1]:]
response = tokenizer.decode(generated_ids, skip_special_tokens=True)
return response.strip()
except Exception as e:
return f"Sorry, I encountered an error: {str(e)}"
# --- Gradio Interface ---
mode_dropdown = gr.Dropdown(
choices=["Chat", "Explain Like I'm New", "Quiz Me", "Summarize"],
value="Chat",
label="Assistant Mode",
)
demo = gr.ChatInterface(
fn=respond,
additional_inputs=[mode_dropdown],
title="AI Study Assistant",
description=(
"A free AI assistant powered by a small open-source model. "
"Pick a mode and start chatting! Responses may take 10-30 seconds on free CPU hardware."
),
examples=[
["What is machine learning?"],
["Explain how the internet works"],
["Quiz me on world geography"],
["Summarize: The mitochondria is the powerhouse of the cell. It produces ATP through cellular respiration, converting glucose and oxygen into energy that the cell can use."],
],
)
if __name__ == "__main__":
demo.launch()
What changed from the basic version?
- SYSTEM_PROMPTS is now a dictionary with four keys. Each key maps to a different set of instructions that shape the model's behavior.
- convert_history(history) is a helper function that safely handles both dictionary-style and list/tuple-style chat history formats. This prevents crashes when different Gradio versions send history in different shapes.
- respond(message, history, mode) accepts a third argument. Gradio passes the dropdown value automatically as this third parameter.
- SYSTEM_PROMPTS.get(mode, SYSTEM_PROMPTS["Chat"]) selects the right prompt. If no match is found, it falls back to the Chat prompt as a safety default.
- gr.Dropdown creates the mode selector. The additional_inputs parameter on gr.ChatInterface wires the dropdown into the response function.
- The examples list now includes prompts tailored to each mode so users can try the chatbot immediately.
- Scroll down to the bottom of the editor and click Commit changes to main.
- After committing, you should see app.py updated in your Files list. The Space will start rebuilding automatically in the background.
Don't see the Edit button?
Make sure you are on the Hub repo page (huggingface.co/spaces/your-username/my-ai-assistant), not the running app page (which ends in .hf.space). The edit controls only appear on the repo page.
If the button is still missing, confirm you are logged in with the account that owns the Space.
Why can't I see the edit controls in my Space?
💡 Why use prompt routing instead of separate apps?
Prompt routing keeps a single model loaded in memory while changing its behavior through different system prompts. This is more efficient than deploying four separate Spaces because the model only downloads and loads once.
The dropdown costs nothing extra. The model itself is unchanged. The only difference between modes is the instruction text prepended to each conversation.
✔️ Awesome, I've got everything!
Great. Double check you clicked Commit changes to main and that app.py shows the updated content in your Files tab.
ⓧ I'd like to double check the full code
Here is the complete app.py your Space should contain at this point:
import gradio as gr
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
# --- Model Setup ---
model_name = "Qwen/Qwen2.5-0.5B-Instruct"
print(f"Loading model: {model_name}")
print("This may take a minute on CPU...")
try:
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
model_name,
dtype=torch.float32
)
model.eval()
print("Model loaded successfully!")
except Exception as e:
print(f"Error loading model: {e}")
model = None
tokenizer = None
# --- System Prompts for Each Mode ---
SYSTEM_PROMPTS = {
"Chat": (
"You are a friendly and helpful AI assistant. "
"Keep your responses concise, clear, and helpful. "
"If you are unsure about something, say so honestly."
),
"Explain Like I'm New": (
"You are a patient teacher explaining concepts to a complete beginner. "
"Use simple language, short sentences, and everyday analogies. "
"Avoid jargon. Break complex ideas into small pieces."
),
"Quiz Me": (
"You are a quiz master. When the user gives you a topic, "
"generate one multiple-choice question with 4 options (A, B, C, D) "
"and indicate the correct answer at the end. Keep it educational and fun."
),
"Summarize": (
"You are a summarization assistant. "
"When the user gives you text, summarize it in 2-3 short sentences. "
"Focus on the key points only."
),
}
# --- History Conversion Helper ---
# Gradio chat history can arrive as dictionaries (new format) or lists/tuples
# (older format) depending on the Gradio version. This helper handles both.
def convert_history(history):
"""Convert chat history into a clean list of message dictionaries."""
messages = []
for msg in history:
if isinstance(msg, dict):
# New format: {"role": "user", "content": "..."}
role = msg.get("role", "")
content = msg.get("content", "")
if role in ("user", "assistant") and content:
messages.append({"role": role, "content": str(content)})
elif isinstance(msg, (list, tuple)) and len(msg) >= 2:
# Older format: ["user message", "assistant response"]
if msg[0]:
messages.append({"role": "user", "content": str(msg[0])})
if msg[1]:
messages.append({"role": "assistant", "content": str(msg[1])})
return messages
# --- Response Function ---
def respond(message, history, mode):
if model is None or tokenizer is None:
return "Sorry, the model failed to load. Please check the Space logs."
system_prompt = SYSTEM_PROMPTS.get(mode, SYSTEM_PROMPTS["Chat"])
messages = [{"role": "system", "content": system_prompt}]
# Convert history to a consistent format before building messages
messages.extend(convert_history(history))
messages.append({"role": "user", "content": message})
try:
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
model_inputs = tokenizer([text], return_tensors="pt")
with torch.no_grad():
generated_ids = model.generate(
**model_inputs,
max_new_tokens=120,
temperature=0.7,
top_p=0.9,
do_sample=True,
)
generated_ids = generated_ids[0][model_inputs["input_ids"].shape[1]:]
response = tokenizer.decode(generated_ids, skip_special_tokens=True)
return response.strip()
except Exception as e:
return f"Sorry, I encountered an error: {str(e)}"
# --- Gradio Interface ---
mode_dropdown = gr.Dropdown(
choices=["Chat", "Explain Like I'm New", "Quiz Me", "Summarize"],
value="Chat",
label="Assistant Mode",
)
demo = gr.ChatInterface(
fn=respond,
additional_inputs=[mode_dropdown],
title="AI Study Assistant",
description=(
"A free AI assistant powered by a small open-source model. "
"Pick a mode and start chatting! Responses may take 10-30 seconds on free CPU hardware."
),
examples=[
["What is machine learning?"],
["Explain how the internet works"],
["Quiz me on world geography"],
["Summarize: The mitochondria is the powerhouse of the cell. It produces ATP through cellular respiration, converting glucose and oxygen into energy that the cell can use."],
],
)
if __name__ == "__main__":
demo.launch()
Your multi-mode chatbot code is committed and your Space is rebuilding. Next up, you will deploy the Space, test all four modes live, and share your public chatbot URL with the world.
Deploy and Test Your Live Chatbot
Your chatbot code is ready with all four assistant modes wired up. Now it is time to make it live on the internet so anyone with a browser can use it.
Hugging Face Spaces automatically created a README.md file when you set up your Space, but it only has basic placeholder metadata. You need to update it with the correct SDK version and app entry point so the platform knows exactly how to build and serve your chatbot.
In this step, get ready to:
- Update the README.md configuration file that tells Hugging Face how to build your Space.
- Monitor the build logs and confirm your Space reaches "Running" status.
- Test all four chatbot modes on the live public URL.
Update the README.md configuration
Your Space already has a README.md file with YAML frontmatter, but it uses generic defaults. You need to replace the contents with the correct Gradio SDK version pin and app entry point for your chatbot.
- In your Space, click the Files tab.
- Click README.md to open the file.
- Click the pencil icon (edit button) in the top-right corner of the file viewer.
- Select all the existing content and replace it with the following configuration:
---
title: AI Study Assistant
emoji: 🤖
colorFrom: blue
colorTo: purple
sdk: gradio
sdk_version: 5.29.0
app_file: app.py
pinned: false
---
What does this configuration do?
- sdk: gradio tells Hugging Face to install Gradio and serve your app using the Gradio runtime.
- sdk_version: 5.29.0 pins the Gradio version so your app builds consistently.
- app_file: app.py points Hugging Face to your main application file.
- title, emoji, colorFrom, and colorTo control how your Space appears in the Hugging Face directory.
- Click Commit changes to main to save your updated README.md.
Your Space now has all three files configured correctly. The build restarts automatically as soon as this commit lands.
✔️ Awesome, I've got everything!
Great. Double check you see all three files listed in your Files tab: requirements.txt, app.py, and README.md.
ⓧ I'd like to double check the full code
Here is the complete README.md file for comparison:
---
title: AI Study Assistant
emoji: 🤖
colorFrom: blue
colorTo: purple
sdk: gradio
sdk_version: 5.29.0
app_file: app.py
pinned: false
---
Monitor the build and wait for "Running" status
Once all three files are committed, Hugging Face Spaces kicks off an automatic build. The build installs your Python packages, downloads the Qwen2.5-0.5B-Instruct model weights, and launches your Gradio app.
- Click the Logs tab in the top menu bar of your Space.
- Watch the build output. You will see package installation progress, then model file downloads, then a message indicating the app is running.
- Wait 2-5 minutes for the first build to complete. The model download is the longest part.
Why does the first build take so long?
The Qwen2.5-0.5B-Instruct model is approximately 988 MB of weights in BF16 format. Hugging Face downloads these files once and caches them for future restarts.
Subsequent restarts (for example, after the Space sleeps from 48 hours of inactivity) only need to reload the cached model into memory, which is much faster.
🙋♀️ Build stuck or failed?
- If you see a build error mentioning a missing package, click the Files tab and open requirements.txt. Check that the package names are spelled exactly as shown: transformers, torch, gradio.
- If the build shows "no app" or cannot find the entry point, confirm that README.md contains app_file: app.py and that your file is named exactly app.py (lowercase, no spaces).
- If the build seems stuck for more than 10 minutes, try clicking Factory reboot in the Settings tab to restart the build from scratch.
Still stuck? Help me debug my Hugging Face Space build error
Test your live chatbot
Once the status badge at the top of your Space changes to Running, your chatbot is live and publicly accessible.
- Click the App tab to see your chatbot interface.
- Try the default Chat mode by clicking one of the example prompts below the input box.
- Wait 10-30 seconds for the response. Free CPU hardware processes tokens sequentially, so responses are not instant.
- Open the Assistant Mode dropdown and switch to Explain Like I'm New. Ask it to explain a concept and notice the simpler language.
- Switch to Quiz Me and type a topic like "world geography". Confirm you get a multiple-choice question.
- Switch to Summarize and paste in a paragraph of text. Confirm you get a short summary back.
- Copy the URL from your browser address bar. This is your chatbot's public URL that anyone can visit.
What if the Space is sleeping?
Free CPU Spaces go to sleep after 48 hours of no visits. The first visit after sleep triggers a restart that takes 30-60 seconds while the model reloads into memory. After that initial wake-up, responses flow normally.
🙋♀️ Not getting responses?
- If you see "Sorry, the model failed to load", switch to the Logs tab and look for error messages during model loading. The most common cause is a temporary download failure. Click Factory reboot in Settings to retry.
- If the chatbot loads but responses are cut off mid-sentence, this is normal for a small model with max_new_tokens=150. The model has a limited generation budget to keep responses fast on CPU.
My chatbot is not responding correctly, help me troubleshoot
🙋♀️ Seeing AttributeError: 'list' object has no attribute 'get'?
This error means Gradio sent chat history as old-style list/tuple pairs (like ["user message", "assistant response"]), but your code tried to call .get() on each item as if it were a dictionary.
The fix is the convert_history() helper function in your app.py. It checks whether each history item is a dictionary or a list/tuple, and converts both formats into a clean list of {"role": "...", "content": "..."} messages. If you see this error, make sure your respond function calls convert_history(history) before building the messages list.
Help me fix an AttributeError in my Gradio chatbot's history handling
Your chatbot is live at a public URL that works on any device. You can turn it into something that feels like a native app on your phone.
Add your chatbot to your phone's home screen
Save your Space URL as a home screen shortcut and it looks and launches just like a real app.
- iPhone (Safari): Open your chatbot URL in Safari, tap the Share button (square with an arrow), then tap Add to Home Screen.
- Android (Chrome): Open your chatbot URL in Chrome, tap the three-dot menu in the top right, then tap Add to Home screen.
You now have a one-tap shortcut to your personal AI assistant whenever you need it.
Secret mission
Switch to SmolLM2 for Faster Responses
Your chatbot works great with Qwen2.5-0.5B-Instruct, but what if you could make it respond faster? The SmolLM2-360M-Instruct model is smaller (362M parameters vs 494M) and may generate responses more quickly on free CPU hardware. Your mission: swap the model, redeploy, and compare the results.
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely on Hugging Face Spaces using free CPU hardware, so there are no ongoing costs. Your Space will automatically sleep after 48 hours of inactivity.
Decide whether to keep your Space running, pause it to come back later, or delete it entirely.
Resources you used:
- Hugging Face Space my-ai-assistant (includes app.py, requirements.txt, and README.md).
Keep everything running
No action needed. Choose this if you want your chatbot to stay live and accessible via its public URL.
- Your Space runs on free CPU hardware, so there is no charge.
- The Space will automatically sleep after 48 hours of no visits. The next visitor triggers a restart that takes 30-60 seconds.
- You can return to your Space at any time by visiting huggingface.co, clicking your profile icon, and selecting your Space from the list.
Pause - I'll come back to this later
Pause your Space so it stops executing immediately, without deleting any files. You can restart it at any time.
- Open your my-ai-assistant Space on huggingface.co.
- Click the Settings tab at the top of the Space page.
- Look for Pause Space and click it.
- Your Space will stop running but all files remain intact. To restart later, return to Settings and click Resume.
Delete - I don't want to use this again
Remove your Space and all its files permanently. This cannot be undone.
- Open your my-ai-assistant Space on huggingface.co.
- Click the Settings tab at the top of the Space page.
- Scroll all the way to the bottom of the Settings page.
- Click Delete this Space.
- Confirm by clicking I understand, delete this Space.
- Your Space, including app.py, requirements.txt, and README.md, is now permanently removed.
That's a Wrap!
That's a Wrap!
Nice work! You just built and deployed a fully functional AI chat assistant powered by an open-source language model, running on free cloud hardware for anyone to access.
You've learned how to:
- Navigate the Hugging Face ecosystem, read model cards, and choose the right model for a project.
- Build a complete AI chatbot with multi-mode prompt routing using Python, Gradio, and Hugging Face Transformers.
- Deploy a live, publicly accessible AI application to Hugging Face Spaces at zero cost, running a real language model on free CPU hardware.
- Secret Mission: Swapped to a different model (SmolLM2-360M-Instruct) and compared performance against the original.
Ready to quiz yourself?