Spaces:
Sleeping
Sleeping
File size: 6,150 Bytes
c48778f 10e9b7d c48778f 10e9b7d 3c4371f c48778f 527d5e0 712c104 17dcb7d c48778f 10e9b7d 3db6293 d1a4341 c48778f e80aab9 3c4371f c48778f 7e4a06b e80aab9 31243f4 c48778f 3c4371f 527d5e0 712c104 527d5e0 712c104 527d5e0 712c104 c48778f eccf8e4 c48778f 7d65c66 c48778f 712c104 c48778f d1a4341 c48778f d1a4341 c48778f 712c104 c48778f 712c104 c48778f e80aab9 c48778f 527d5e0 c48778f e80aab9 c48778f 7d65c66 c48778f e80aab9 c48778f 0ee0419 c48778f e80aab9 7e4a06b c48778f 31243f4 c48778f e80aab9 3c4371f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | """
app.py: Hugging Face Agents Course, Unit 4 final assignment (faster version).
Changes from the template:
- questions run in parallel (WORKERS at a time); the rate limiter in agent.py keeps
the total number of model calls inside the free tier
- each question has a time cap, so one stuck question can't hold up the whole run
- answers are cached in answers_cache.json: if a run stops halfway, the next run
only answers what's missing
- a placeholder @spaces.GPU function, needed only when the Space runs on ZeroGPU
"""
import os
import json
import time
import concurrent.futures as cf
import gradio as gr
import pandas as pd
import requests
import agent as agent_module
from agent import BasicAgent, check_model
try: # ZeroGPU checks for one @spaces.GPU function at startup
import spaces
@spaces.GPU
def gpu_placeholder():
return None
except ImportError: # CPU Spaces don't have (or need) the spaces package
pass
DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
WORKERS = 2 # questions answered at the same time (the agent's rate limiter paces Groq anyway)
RUN_TIME_CAP = 3600 # seconds for the whole run; unfinished questions are submitted as "unknown"
CACHE_FILE = "answers_cache.json"
def load_cache():
try:
with open(CACHE_FILE) as f:
return json.load(f)
except (OSError, ValueError):
return {}
def save_cache(cache):
with open(CACHE_FILE, "w") as f:
json.dump(cache, f, indent=2)
def run_and_submit_all(profile: gr.OAuthProfile | None, use_cache: bool):
if not profile:
return "Please log in to Hugging Face with the button above.", None
username = profile.username
space_id = os.getenv("SPACE_ID")
agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
api_url = DEFAULT_API_URL
try:
agent = BasicAgent()
except Exception as e:
return f"Error creating the agent: {e}", None
# 0. check the API key and quota with one tiny call before spending time on 20 questions
problem = check_model()
if problem:
return ("Test call to the model failed, so nothing was run or submitted.\n"
f"{problem[:800]}\n\n"
"Usual causes: Groq's daily free limit used up (wait until tomorrow), a wrong or missing "
"GROQ_API_KEY secret, or a model name that changed (edit MODEL_ID in agent.py)."), None
# 1. fetch questions
try:
r = requests.get(f"{api_url}/questions", timeout=20)
r.raise_for_status()
questions = r.json()
except Exception as e:
return f"Error fetching questions: {e}", None
if not questions:
return "The question list is empty.", None
# 2. answer them in parallel, reusing cached answers
cache = load_cache() if use_cache else {}
todo = [q for q in questions if q.get("task_id") and q["task_id"] not in cache]
print(f"{len(questions)} questions, {len(questions) - len(todo)} from cache, {len(todo)} to answer")
done = 0
start = time.time()
pool = cf.ThreadPoolExecutor(max_workers=WORKERS)
futures = {pool.submit(agent, q["question"], q["task_id"]): q for q in todo}
try:
for fut in cf.as_completed(futures, timeout=RUN_TIME_CAP):
q = futures[fut]
try:
answer = fut.result()
except Exception as e:
print(f"[{q['task_id']}] error: {e}")
answer = "unknown"
if answer and answer != "unknown": # only real answers are cached
cache[q["task_id"]] = answer
save_cache(cache)
done += 1
print(f"[{done}/{len(todo)}] {time.time() - start:.0f}s {answer!r}")
except cf.TimeoutError:
print("Time cap reached; unfinished questions are submitted as 'unknown'.")
pool.shutdown(wait=False, cancel_futures=True)
# 3. build the payload and the results table
answers_payload, log = [], []
for q in questions:
answer = cache.get(q["task_id"], "unknown")
answers_payload.append({"task_id": q["task_id"], "submitted_answer": answer})
log.append({"Task ID": q["task_id"], "Question": q["question"], "Submitted Answer": answer,
"Error": agent.last_error.get(q["task_id"], "")})
results_df = pd.DataFrame(log)
# 4. submit
submission = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
try:
r = requests.post(f"{api_url}/submit", json=submission, timeout=60)
r.raise_for_status()
d = r.json()
status = (
f"Model: {agent_module.MODEL_ID}\n"
f"Submission successful in {time.time() - start:.0f}s\n"
f"User: {d.get('username')}\n"
f"Score: {d.get('score', 'N/A')}% "
f"({d.get('correct_count', '?')}/{d.get('total_attempted', '?')} correct)\n"
f"Message: {d.get('message', '')}"
)
except requests.exceptions.HTTPError as e:
status = f"Submission failed: {e.response.status_code} {e.response.text[:500]}"
except Exception as e:
status = f"Submission failed: {e}"
return status, results_df
with gr.Blocks() as demo:
gr.Markdown("# Agents Course: Unit 4 final assignment")
gr.Markdown(
"1. Log in with your Hugging Face account.\n"
"2. Click **Run Evaluation & Submit All Answers**. Questions run in parallel; "
"with the cache on, a second run only answers the questions that are still missing."
)
gr.LoginButton()
use_cache = gr.Checkbox(value=True, label="Reuse answers from the previous run")
run_button = gr.Button("Run Evaluation & Submit All Answers")
status_output = gr.Textbox(label="Run status / submission result", lines=6, interactive=False)
results_table = gr.DataFrame(label="Questions and agent answers", wrap=True)
run_button.click(fn=run_and_submit_all, inputs=[use_cache], outputs=[status_output, results_table])
if __name__ == "__main__":
demo.launch(debug=True, share=False) |