Spaces:
Running
Running
# app.py | |
import os | |
import random | |
import requests | |
import streamlit as st | |
from io import BytesIO | |
from PIL import Image | |
from smolagents import CodeAgent, DuckDuckGoSearchTool, HfApiModel, Tool | |
from huggingface_hub import login | |
import warnings | |
warnings.filterwarnings("ignore") | |
# Set page configuration | |
st.set_page_config( | |
page_title="SmolaAgents Tools", | |
page_icon="π€", | |
layout="wide", | |
initial_sidebar_state="expanded" | |
) | |
# Function to initialize the API with user-provided token | |
def initialize_api(token=None): | |
if token: | |
login(token) | |
try: | |
# Initialize the model | |
return HfApiModel(model_id="meta-llama/Llama-3.3-70B-Instruct") | |
except Exception as e: | |
st.error(f"Error initializing model: {str(e)}") | |
return None | |
else: | |
st.warning("Please enter your Hugging Face API token to use this app.") | |
return None | |
# Define all your tools | |
class RandomComicFetcher(Tool): | |
name = "fetch_random_comic_image" | |
description = "Fetches the image of a random XKCD comic" | |
inputs = {} | |
output_type = "string" | |
def __init__(self): | |
super().__init__() | |
self.xkcd_base_url = "https://xkcd.com/" | |
self.xkcd_latest_url = f"{self.xkcd_base_url}info.0.json" | |
def forward(self): | |
try: | |
# Fetch the latest comic info to get max comic number | |
latest_resp = requests.get(self.xkcd_latest_url) | |
latest_resp.raise_for_status() | |
latest_data = latest_resp.json() | |
max_comic_id = latest_data["num"] | |
# Pick a random comic ID between 1 and latest | |
selected_id = random.randint(1, max_comic_id) | |
comic_info_url = f"{self.xkcd_base_url}{selected_id}/info.0.json" | |
# Fetch comic metadata | |
comic_resp = requests.get(comic_info_url) | |
comic_resp.raise_for_status() | |
comic_data = comic_resp.json() | |
comic_img_url = comic_data["img"] | |
comic_title = comic_data["title"] | |
comic_alt = comic_data["alt"] | |
# Download and return the comic image | |
image_resp = requests.get(comic_img_url) | |
image_resp.raise_for_status() | |
img = Image.open(BytesIO(image_resp.content)) | |
return img, comic_title, comic_alt, comic_img_url | |
except requests.exceptions.RequestException as err: | |
st.error(f"Could not fetch comic: {err}") | |
return None, "Error fetching comic", "Error details", "" | |
class PrimeCheckTool(Tool): | |
name = "prime_check" | |
description = "Checks if a given number is a prime number." | |
inputs = { | |
"number": { | |
"type": "integer", | |
"description": "The number to check for primality.", | |
} | |
} | |
output_type = "boolean" | |
def forward(self, number: int) -> bool: | |
if number < 2: | |
return False | |
for i in range(2, int(number**0.5) + 1): | |
if number % i == 0: | |
return False | |
return True | |
# Initialize tools | |
search_tool = DuckDuckGoSearchTool() | |
random_comic = RandomComicFetcher() | |
prime_check_tool = PrimeCheckTool() | |
# Streamlit App | |
st.title("SmolaAgents Tools") | |
st.markdown("Select a tool from the sidebar and interact with AI-powered assistants") | |
# Initialize session state for token | |
if "hf_token" not in st.session_state: | |
st.session_state.hf_token = "" | |
st.session_state.model = None | |
# Sidebar for tool selection and token input | |
with st.sidebar: | |
st.title("Configuration") | |
# Check for token in environment first | |
env_token = os.environ.get("HF_TOKEN") | |
if env_token and not st.session_state.hf_token: | |
st.session_state.hf_token = env_token | |
st.success("HF_TOKEN found in environment variables") | |
# Token input | |
token_input = st.text_input( | |
"Enter your Hugging Face API Token:", | |
value=st.session_state.hf_token, | |
type="password", | |
help="Get your token from huggingface.co/settings/tokens" | |
) | |
if token_input != st.session_state.hf_token: | |
st.session_state.hf_token = token_input | |
# Reset model when token changes | |
st.session_state.model = None | |
# Button to initialize/test the token | |
if st.button("Initialize API"): | |
with st.spinner("Testing your token..."): | |
model = initialize_api(st.session_state.hf_token) | |
if model: | |
st.session_state.model = model | |
st.success("β API initialized successfully!") | |
else: | |
st.error("β Failed to initialize the API with the provided token.") | |
st.divider() | |
st.title("Tool Selection") | |
tool_choice = st.radio( | |
"Choose a tool:", | |
["Search Tool", "XKCD Comic Fetcher", "Prime Number Checker"] | |
) | |
st.divider() | |
st.markdown("### About") | |
st.markdown(""" | |
This app demonstrates the capabilities of SmolaAgents, allowing you to: | |
- Search the web with an AI assistant | |
- Fetch random XKCD comics with AI commentary | |
- Check if numbers are prime with creative explanations | |
""") | |
# Check if the model is initialized | |
if not st.session_state.model and st.session_state.hf_token: | |
with st.spinner("Initializing model..."): | |
st.session_state.model = initialize_api(st.session_state.hf_token) | |
if st.session_state.model: | |
st.success("Model initialized successfully!") | |
# Main content area - only show if token is provided | |
if st.session_state.hf_token and st.session_state.model: | |
# Main content area | |
if tool_choice == "Search Tool": | |
st.header("AI Web Search") | |
st.markdown("Ask any question and the AI will search the web for answers") | |
query = st.text_input("Enter your search query:", placeholder="What are the latest advancements in renewable energy?") | |
if st.button("Search"): | |
if query: | |
with st.spinner("Searching and processing..."): | |
agent = CodeAgent(tools=[search_tool], model=st.session_state.model) | |
response = agent.run(query) | |
st.success("Search complete!") | |
st.markdown("### Results") | |
st.markdown(response) | |
else: | |
st.warning("Please enter a search query") | |
elif tool_choice == "XKCD Comic Fetcher": | |
st.header("XKCD Comic Explorer") | |
st.markdown("Fetch a random XKCD comic and get AI commentary") | |
if "comic_fetched" not in st.session_state: | |
st.session_state.comic_fetched = False | |
st.session_state.comic_img = None | |
st.session_state.comic_title = "" | |
st.session_state.comic_alt = "" | |
st.session_state.comic_url = "" | |
col1, col2 = st.columns([1, 2]) | |
with col1: | |
if st.button("Fetch Random Comic"): | |
with st.spinner("Fetching a random comic..."): | |
img, title, alt, url = random_comic.forward() | |
if img: | |
st.session_state.comic_fetched = True | |
st.session_state.comic_img = img | |
st.session_state.comic_title = title | |
st.session_state.comic_alt = alt | |
st.session_state.comic_url = url | |
st.experimental_rerun() | |
if st.session_state.comic_fetched: | |
with col1: | |
st.image(st.session_state.comic_img, caption=st.session_state.comic_title) | |
st.caption(f"Alt text: {st.session_state.comic_alt}") | |
st.markdown(f"[View on XKCD]({st.session_state.comic_url})") | |
with col2: | |
st.subheader("Ask AI about this comic") | |
query = st.text_input("What would you like to know about this comic?", | |
placeholder="Explain this comic in a funny way") | |
if st.button("Ask AI"): | |
with st.spinner("Generating response..."): | |
agent = CodeAgent(tools=[random_comic], model=st.session_state.model) | |
response = agent.run(query if query else "Tell me about this XKCD comic.") | |
st.markdown("### AI Response") | |
st.markdown(response) | |
elif tool_choice == "Prime Number Checker": | |
st.header("Prime Number Checker") | |
st.markdown("Check if a number is prime and get a creative explanation") | |
number = st.number_input("Enter a number to check:", min_value=1, step=1, value=23) | |
explanation_style = st.selectbox( | |
"Choose explanation style:", | |
["Poetic", "Nursery Rhyme", "Scientific", "Humorous", "Historical"] | |
) | |
if st.button("Check Prime"): | |
with st.spinner("Checking and generating response..."): | |
is_prime = prime_check_tool.forward(int(number)) | |
# Format query based on selected style | |
query = f"Check if the number {number} is a prime number and explain it in a {explanation_style.lower()} style." | |
agent = CodeAgent(tools=[prime_check_tool], model=st.session_state.model) | |
response = agent.run(query) | |
# Display result with some styling | |
prime_status = "β PRIME" if is_prime else "β NOT PRIME" | |
st.markdown(f"### Result: {prime_status}") | |
st.markdown("### AI Explanation") | |
st.markdown(response) | |
# Optional: Show a mathematical representation | |
if st.checkbox("Show mathematical details"): | |
if is_prime: | |
st.markdown(f"{number} has no factors other than 1 and itself.") | |
else: | |
# Find the factors | |
factors = [i for i in range(1, number + 1) if number % i == 0] | |
st.markdown(f"Factors of {number}: {', '.join(map(str, factors))}") | |
else: | |
# Token not provided | |
st.info("π Please enter your Hugging Face API token in the sidebar to get started.") | |
# Show more information to help users understand what they need | |
st.markdown(""" | |
### How to Get a Hugging Face Token | |
1. Go to [huggingface.co](https://huggingface.co/) and create an account if you don't have one | |
2. Visit your [settings page](https://huggingface.co/settings/tokens) | |
3. Create a new token with read access | |
4. Copy the token and paste it in the sidebar | |
Your token will be used to access the language models needed for this application. | |
### Why is a token required? | |
This app uses Hugging Face's API to access powerful language models like Llama 3. Your API token | |
grants access to these models, which do the heavy lifting of understanding and responding to your queries. | |
""") | |
# Add footer | |
st.sidebar.divider() | |
st.sidebar.markdown("Made with β€οΈ using SmolaAgents") |