Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -8,19 +8,14 @@ import subprocess
|
|
| 8 |
import sys
|
| 9 |
|
| 10 |
DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
|
| 11 |
-
|
| 12 |
-
# Track API calls for rate limiting
|
| 13 |
_last_call_time = 0
|
| 14 |
|
| 15 |
def rate_limited_groq(api_key, prompt, system="", max_tokens=128):
|
| 16 |
-
"""Call Groq with rate limiting — max 25 req/min to stay safe."""
|
| 17 |
global _last_call_time
|
| 18 |
-
# Ensure at least 2.5 seconds between calls (= 24/min, safely under 30 limit)
|
| 19 |
elapsed = time.time() - _last_call_time
|
| 20 |
if elapsed < 2.5:
|
| 21 |
time.sleep(2.5 - elapsed)
|
| 22 |
_last_call_time = time.time()
|
| 23 |
-
|
| 24 |
url = "https://api.groq.com/openai/v1/chat/completions"
|
| 25 |
headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
|
| 26 |
msgs = []
|
|
@@ -38,12 +33,16 @@ def rate_limited_groq(api_key, prompt, system="", max_tokens=128):
|
|
| 38 |
raise Exception(f"Groq {resp.status_code}: {resp.text[:200]}")
|
| 39 |
return resp.json()["choices"][0]["message"]["content"].strip()
|
| 40 |
|
| 41 |
-
def download_task_file(task_id):
|
|
|
|
| 42 |
url = f"{DEFAULT_API_URL}/files/{task_id}"
|
|
|
|
|
|
|
|
|
|
| 43 |
try:
|
| 44 |
-
resp = requests.get(url, timeout=30)
|
| 45 |
-
print(f" File
|
| 46 |
-
f"content
|
| 47 |
if resp.status_code != 200 or len(resp.content) == 0:
|
| 48 |
return None, None
|
| 49 |
cd = resp.headers.get("content-disposition", "")
|
|
@@ -57,12 +56,13 @@ def download_task_file(task_id):
|
|
| 57 |
elif "excel" in ct or "spreadsheet" in ct: ext = ".xlsx"
|
| 58 |
elif "csv" in ct: ext = ".csv"
|
| 59 |
elif "image" in ct: ext = ".png"
|
|
|
|
| 60 |
else: ext = ".bin"
|
| 61 |
fname += ext
|
| 62 |
tmp = tempfile.NamedTemporaryFile(delete=False, suffix=ext, prefix="gaia_")
|
| 63 |
tmp.write(resp.content)
|
| 64 |
tmp.close()
|
| 65 |
-
print(f" Saved: {fname}
|
| 66 |
return tmp.name, fname
|
| 67 |
except Exception as e:
|
| 68 |
print(f" Download error: {e}")
|
|
@@ -136,11 +136,12 @@ Reply with ONLY the final answer. No explanation. No prefix. No "The answer is".
|
|
| 136 |
Give the bare answer: a name, number, word, or short phrase only."""
|
| 137 |
|
| 138 |
class BasicAgent:
|
| 139 |
-
def __init__(self):
|
| 140 |
self.key = os.getenv("GROQ_API_KEY", "")
|
| 141 |
if not self.key:
|
| 142 |
raise RuntimeError("GROQ_API_KEY not set!")
|
| 143 |
-
|
|
|
|
| 144 |
|
| 145 |
def ask(self, prompt, max_tokens=128):
|
| 146 |
return clean_answer(rate_limited_groq(self.key, prompt, SYSTEM, max_tokens))
|
|
@@ -156,10 +157,9 @@ class BasicAgent:
|
|
| 156 |
file_ctx = ""
|
| 157 |
is_py = False
|
| 158 |
|
| 159 |
-
# Download file
|
| 160 |
if task_id:
|
| 161 |
-
|
| 162 |
-
lp, fn = download_task_file(task_id)
|
| 163 |
if lp and fn:
|
| 164 |
ext = os.path.splitext(fn)[-1].lower()
|
| 165 |
if ext == ".py":
|
|
@@ -175,8 +175,6 @@ class BasicAgent:
|
|
| 175 |
else:
|
| 176 |
contents = read_file_contents(lp, fn)
|
| 177 |
file_ctx = f"\n[File: {fn}]\n{contents[:4000]}\n"
|
| 178 |
-
else:
|
| 179 |
-
print(f" No file found for this task.")
|
| 180 |
|
| 181 |
# Web search
|
| 182 |
search_ctx = ""
|
|
@@ -189,7 +187,7 @@ class BasicAgent:
|
|
| 189 |
q = question.lower()
|
| 190 |
fmt = ""
|
| 191 |
if "studio album" in q:
|
| 192 |
-
fmt = "\nCount only SOLO studio albums (
|
| 193 |
elif "first name" in q:
|
| 194 |
fmt = "\nFirst name only."
|
| 195 |
elif "surname" in q or "last name" in q:
|
|
@@ -199,21 +197,19 @@ class BasicAgent:
|
|
| 199 |
elif "how many" in q:
|
| 200 |
fmt = "\nSingle integer only."
|
| 201 |
elif "ioc" in q or ("country" in q and "olympic" in q):
|
| 202 |
-
fmt = "\nIOC country code only (3 letters
|
| 203 |
elif "excel" in q or ("sale" in q and "food" in q):
|
| 204 |
-
fmt = "\
|
| 205 |
elif "chess" in q:
|
| 206 |
-
fmt = "\nChess move in algebraic notation only."
|
| 207 |
elif "pitcher" in q and "number" in q:
|
| 208 |
-
fmt = "\nTwo last names, comma-separated
|
| 209 |
elif "wikipedia" in q and "nominat" in q:
|
| 210 |
fmt = "\nWikipedia username only."
|
| 211 |
elif "grocery" in q or ("shopping" in q and "list" in q):
|
| 212 |
fmt = "\nComma-separated list, alphabetical order."
|
| 213 |
elif "youtube" in q or "video" in q:
|
| 214 |
-
fmt = "\nExact short answer
|
| 215 |
-
elif "grant" in q or "award number" in q:
|
| 216 |
-
fmt = "\nExact identifier only."
|
| 217 |
|
| 218 |
prompt = (
|
| 219 |
f"Question: {question}"
|
|
@@ -240,9 +236,14 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
|
|
| 240 |
space_id = os.getenv("SPACE_ID")
|
| 241 |
if not profile:
|
| 242 |
return "Please Login to Hugging Face.", None
|
|
|
|
| 243 |
username = profile.username
|
|
|
|
|
|
|
|
|
|
|
|
|
| 244 |
try:
|
| 245 |
-
agent = BasicAgent()
|
| 246 |
except RuntimeError as e:
|
| 247 |
return f"❌ {e}", None
|
| 248 |
|
|
@@ -263,10 +264,10 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
|
|
| 263 |
continue
|
| 264 |
print(f"\n[{i+1}/{len(questions_data)}]")
|
| 265 |
try:
|
| 266 |
-
# Pass task_id directly — no injection needed
|
| 267 |
ans = agent(question_text, task_id=task_id)
|
| 268 |
except Exception as e:
|
| 269 |
ans = ""
|
|
|
|
| 270 |
answers_payload.append({"task_id": task_id, "submitted_answer": ans})
|
| 271 |
results_log.append({
|
| 272 |
"Task ID": task_id,
|
|
|
|
| 8 |
import sys
|
| 9 |
|
| 10 |
DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
|
|
|
|
|
|
|
| 11 |
_last_call_time = 0
|
| 12 |
|
| 13 |
def rate_limited_groq(api_key, prompt, system="", max_tokens=128):
|
|
|
|
| 14 |
global _last_call_time
|
|
|
|
| 15 |
elapsed = time.time() - _last_call_time
|
| 16 |
if elapsed < 2.5:
|
| 17 |
time.sleep(2.5 - elapsed)
|
| 18 |
_last_call_time = time.time()
|
|
|
|
| 19 |
url = "https://api.groq.com/openai/v1/chat/completions"
|
| 20 |
headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
|
| 21 |
msgs = []
|
|
|
|
| 33 |
raise Exception(f"Groq {resp.status_code}: {resp.text[:200]}")
|
| 34 |
return resp.json()["choices"][0]["message"]["content"].strip()
|
| 35 |
|
| 36 |
+
def download_task_file(task_id, hf_token=None):
|
| 37 |
+
"""Download with HF OAuth token for authentication."""
|
| 38 |
url = f"{DEFAULT_API_URL}/files/{task_id}"
|
| 39 |
+
headers = {}
|
| 40 |
+
if hf_token:
|
| 41 |
+
headers["Authorization"] = f"Bearer {hf_token}"
|
| 42 |
try:
|
| 43 |
+
resp = requests.get(url, headers=headers, timeout=30)
|
| 44 |
+
print(f" File [{task_id[:8]}]: HTTP {resp.status_code}, "
|
| 45 |
+
f"size={len(resp.content)}, ct={resp.headers.get('content-type','?')[:40]}")
|
| 46 |
if resp.status_code != 200 or len(resp.content) == 0:
|
| 47 |
return None, None
|
| 48 |
cd = resp.headers.get("content-disposition", "")
|
|
|
|
| 56 |
elif "excel" in ct or "spreadsheet" in ct: ext = ".xlsx"
|
| 57 |
elif "csv" in ct: ext = ".csv"
|
| 58 |
elif "image" in ct: ext = ".png"
|
| 59 |
+
elif "text" in ct: ext = ".txt"
|
| 60 |
else: ext = ".bin"
|
| 61 |
fname += ext
|
| 62 |
tmp = tempfile.NamedTemporaryFile(delete=False, suffix=ext, prefix="gaia_")
|
| 63 |
tmp.write(resp.content)
|
| 64 |
tmp.close()
|
| 65 |
+
print(f" Saved: {fname} ({len(resp.content)} bytes)")
|
| 66 |
return tmp.name, fname
|
| 67 |
except Exception as e:
|
| 68 |
print(f" Download error: {e}")
|
|
|
|
| 136 |
Give the bare answer: a name, number, word, or short phrase only."""
|
| 137 |
|
| 138 |
class BasicAgent:
|
| 139 |
+
def __init__(self, hf_token=None):
|
| 140 |
self.key = os.getenv("GROQ_API_KEY", "")
|
| 141 |
if not self.key:
|
| 142 |
raise RuntimeError("GROQ_API_KEY not set!")
|
| 143 |
+
self.hf_token = hf_token
|
| 144 |
+
print(f"Agent ready. Groq key: {self.key[:8]}... | HF token: {'YES' if hf_token else 'NO'}")
|
| 145 |
|
| 146 |
def ask(self, prompt, max_tokens=128):
|
| 147 |
return clean_answer(rate_limited_groq(self.key, prompt, SYSTEM, max_tokens))
|
|
|
|
| 157 |
file_ctx = ""
|
| 158 |
is_py = False
|
| 159 |
|
| 160 |
+
# Download file with HF token
|
| 161 |
if task_id:
|
| 162 |
+
lp, fn = download_task_file(task_id, self.hf_token)
|
|
|
|
| 163 |
if lp and fn:
|
| 164 |
ext = os.path.splitext(fn)[-1].lower()
|
| 165 |
if ext == ".py":
|
|
|
|
| 175 |
else:
|
| 176 |
contents = read_file_contents(lp, fn)
|
| 177 |
file_ctx = f"\n[File: {fn}]\n{contents[:4000]}\n"
|
|
|
|
|
|
|
| 178 |
|
| 179 |
# Web search
|
| 180 |
search_ctx = ""
|
|
|
|
| 187 |
q = question.lower()
|
| 188 |
fmt = ""
|
| 189 |
if "studio album" in q:
|
| 190 |
+
fmt = "\nCount only SOLO studio albums (not live, compilation, or collaborative). Single integer."
|
| 191 |
elif "first name" in q:
|
| 192 |
fmt = "\nFirst name only."
|
| 193 |
elif "surname" in q or "last name" in q:
|
|
|
|
| 197 |
elif "how many" in q:
|
| 198 |
fmt = "\nSingle integer only."
|
| 199 |
elif "ioc" in q or ("country" in q and "olympic" in q):
|
| 200 |
+
fmt = "\nIOC country code only (3 letters). If tied, alphabetically first country."
|
| 201 |
elif "excel" in q or ("sale" in q and "food" in q):
|
| 202 |
+
fmt = "\nNumber with exactly two decimal places. No $ sign, no commas (e.g. 89.50)."
|
| 203 |
elif "chess" in q:
|
| 204 |
+
fmt = "\nChess move in algebraic notation only (e.g. Qd8, e5)."
|
| 205 |
elif "pitcher" in q and "number" in q:
|
| 206 |
+
fmt = "\nTwo last names, comma-separated. Pitcher with lower jersey number first."
|
| 207 |
elif "wikipedia" in q and "nominat" in q:
|
| 208 |
fmt = "\nWikipedia username only."
|
| 209 |
elif "grocery" in q or ("shopping" in q and "list" in q):
|
| 210 |
fmt = "\nComma-separated list, alphabetical order."
|
| 211 |
elif "youtube" in q or "video" in q:
|
| 212 |
+
fmt = "\nExact short answer — quote, number, or brief phrase only."
|
|
|
|
|
|
|
| 213 |
|
| 214 |
prompt = (
|
| 215 |
f"Question: {question}"
|
|
|
|
| 236 |
space_id = os.getenv("SPACE_ID")
|
| 237 |
if not profile:
|
| 238 |
return "Please Login to Hugging Face.", None
|
| 239 |
+
|
| 240 |
username = profile.username
|
| 241 |
+
# Get the HF OAuth token from the login profile
|
| 242 |
+
hf_token = getattr(profile, "token", None)
|
| 243 |
+
print(f"User: {username}, HF token present: {bool(hf_token)}")
|
| 244 |
+
|
| 245 |
try:
|
| 246 |
+
agent = BasicAgent(hf_token=hf_token)
|
| 247 |
except RuntimeError as e:
|
| 248 |
return f"❌ {e}", None
|
| 249 |
|
|
|
|
| 264 |
continue
|
| 265 |
print(f"\n[{i+1}/{len(questions_data)}]")
|
| 266 |
try:
|
|
|
|
| 267 |
ans = agent(question_text, task_id=task_id)
|
| 268 |
except Exception as e:
|
| 269 |
ans = ""
|
| 270 |
+
print(f" Error: {e}")
|
| 271 |
answers_payload.append({"task_id": task_id, "submitted_answer": ans})
|
| 272 |
results_log.append({
|
| 273 |
"Task ID": task_id,
|