import os import json import socket import requests import gradio as gr from huggingface_hub import login from smolagents import CodeAgent, InferenceClientModel, DuckDuckGoSearchTool, VisitWebpageTool # Auth hf_token = os.getenv("HF_TOKEN") if hf_token: login(token=hf_token) print("HF login OK") else: print("No HF_TOKEN set") # Model MODEL_ID = "Qwen/Qwen2.5-7B-Instruct" def build_agent(enable_tools: bool): model = InferenceClientModel(model_id=MODEL_ID, token=hf_token) tools = [DuckDuckGoSearchTool(), VisitWebpageTool()] if enable_tools else [] return CodeAgent(tools=tools, model=model, max_steps=8) # Perfume data and logic CATALOG = [ {"name": "Dior Sauvage EDT", "notes": ["bergamot", "ambroxan", "pepper"], "season": ["spring", "summer"], "style": "fresh", "price": 95, "gender": "masculine"}, {"name": "Chanel Bleu de Chanel EDP", "notes": ["citrus", "incense", "cedar"], "season": ["all"], "style": "fresh-woody", "price": 120, "gender": "masculine"}, {"name": "Creed Aventus", "notes": ["pineapple", "birch", "musk"], "season": ["spring", "summer", "fall"], "style": "fruity-woody", "price": 365, "gender": "masculine"}, {"name": "Maison Francis Kurkdjian Baccarat Rouge 540", "notes": ["saffron", "ambergris", "cedar"], "season": ["fall", "winter"], "style": "ambery", "price": 325, "gender": "unisex"}, {"name": "Le Labo Santal 33", "notes": ["sandalwood", "leather", "violet"], "season": ["fall", "winter", "spring"], "style": "woody", "price": 220, "gender": "unisex"}, {"name": "Tom Ford Black Orchid", "notes": ["truffle", "patchouli", "chocolate"], "season": ["fall", "winter", "night"], "style": "gourmand", "price": 160, "gender": "unisex"}, {"name": "Byredo Gypsy Water", "notes": ["juniper", "lemon", "vanilla"], "season": ["spring", "summer"], "style": "fresh-woody", "price": 205, "gender": "unisex"}, {"name": "Chanel Chance Eau Tendre", "notes": ["grapefruit", "jasmine", "musk"], "season": ["spring", "summer"], "style": "fresh-floral", "price": 120, "gender": "feminine"}, {"name": "YSL Libre EDP", "notes": ["lavender", "orange blossom", "vanilla"], "season": ["fall", "winter"], "style": "floral-amber", "price": 130, "gender": "feminine"}, {"name": "Jo Malone Wood Sage & Sea Salt", "notes": ["sage", "ambrette", "sea salt"], "season": ["summer", "spring"], "style": "fresh-aromatic", "price": 165, "gender": "unisex"}, ] def shortlist_catalog(preferred_notes, season, budget, gender_pref): notes = [n.strip().lower() for n in preferred_notes.split(",") if n.strip()] if preferred_notes else [] season = (season or "all").lower() gender_pref = (gender_pref or "unisex").lower() max_price = float(budget) if budget else 9999.0 def score(item): s = 0 if season in item["season"] or "all" in item["season"]: s += 1 if gender_pref in ["any", "unisex"] or gender_pref == item["gender"]: s += 1 s += sum(1 for n in notes if n in item["notes"]) if item["price"] <= max_price: s += 1 return s ranked = sorted(CATALOG, key=score, reverse=True) top = [p for p in ranked if score(p) > 0][:5] return top or ranked[:3] def recommend_perfumes(preferred_notes, season, occasion, budget, gender_pref, use_web_tools): agent = build_agent(enable_tools=use_web_tools) shortlist = shortlist_catalog(preferred_notes, season, budget, gender_pref) prompt = ( "Recommend three perfumes, ranked 1 to 3.\n" f"Preferred notes: {preferred_notes or 'not specified'}\n" f"Season: {season or 'any'}\n" f"Occasion: {occasion or 'any'}\n" f"Budget cap (USD): {budget or 'no cap'}\n" f"Gender preference: {gender_pref or 'any'}\n\n" "Candidates you can consider:\n" f"{json.dumps(shortlist, indent=2)}\n\n" "Return a short list with brand and perfume name, brief notes and vibe, why it fits, and approx price or where to sample. Keep it under 120 words." ) try: return str(agent.run(prompt)) except Exception as e: lines = [f"{i+1}. {p['name']} — ${p['price']} • {', '.join(p['notes'])}" for i, p in enumerate(shortlist[:3])] return "Local shortlist:\n" + "\n".join(lines) + f"\nError: {e}" # GAIA test GAIA_BASE = "https://agents-course-unit4-scoring.hf.space" def fetch_random_question(): r = requests.get(f"{GAIA_BASE}/random-question", timeout=15) r.raise_for_status() return r.json() def _check_match(agent_answer, expected_answer): a = str(agent_answer).strip().lower() e = str(expected_answer).strip().lower() if a == e: return "Exact match" if e and e in a: return "Partial match" return "No match" def run_agent_on_gaia(): try: q = fetch_random_question() except Exception as e: return f"Error fetching GAIA question: {e}" question_text = q.get("question") or "" expected_answer = q.get("final_answer") or "" try: agent = build_agent(enable_tools=True) agent_answer = str(agent.run(question_text)) except Exception as e: agent_answer = f"Error running agent: {e}" return ( "### Question\n" f"{question_text}\n\n" "### Agent answer\n" f"{agent_answer}\n\n" "### Expected answer\n" f"{expected_answer}\n\n" "### Match\n" f"{_check_match(agent_answer, expected_answer)}" ) # Diagnostics def net_diagnostics(): results = {} hosts = { "gaia": "agents-course-unit4-scoring.hf.space", "huggingface": "huggingface.co", "google": "www.google.com", } for name, host in hosts.items(): try: ip = socket.gethostbyname(host) results[f"dns_{name}"] = f"OK {host} -> {ip}" except Exception as e: results[f"dns_{name}"] = f"FAIL {host} -> {e}" urls = { "gaia_random_question": f"{GAIA_BASE}/random-question", "hf_home": "https://huggingface.co", } for key, url in urls.items(): try: r = requests.get(url, timeout=10) results[f"http_{key}"] = f"{r.status_code} {len(r.content)} bytes" except Exception as e: results[f"http_{key}"] = f"FAIL {e}" return "```\n" + json.dumps(results, indent=2) + "\n```" # UI with gr.Blocks(title="Perfume Recommender and GAIA Test") as demo: with gr.Tab("Perfume"): with gr.Row(): with gr.Column(): notes = gr.Textbox(label="Preferred notes (comma separated)") season = gr.Dropdown(label="Season", choices=["any","spring","summer","fall","winter","night"], value="any") occasion = gr.Dropdown(label="Occasion", choices=["any","work","date","party","gym","formal"], value="any") budget = gr.Textbox(label="Budget cap in USD") gender = gr.Dropdown(label="Gender preference", choices=["any","masculine","feminine","unisex"], value="any") use_tools = gr.Checkbox(label="Use web tools", value=False) go = gr.Button("Recommend") with gr.Column(): rec_out = gr.Markdown() go.click(recommend_perfumes, [notes, season, occasion, budget, gender, use_tools], [rec_out], show_progress="full") with gr.Tab("GAIA"): gaia_btn = gr.Button("Get random question and answer") gaia_out = gr.Markdown() gaia_btn.click(run_agent_on_gaia, None, [gaia_out], show_progress="full") with gr.Tab("Diagnostics"): diag_btn = gr.Button("Network diagnostics") diag_out = gr.Markdown() diag_btn.click(net_diagnostics, None, [diag_out], show_progress="minimal") demo.queue().launch()