import os, json, time import gradio as gr import requests import pandas as pd import spaces from smolagents import CodeAgent, tool, LiteLLMModel @tool def web_search(query: str) -> str: """Search web. Args: query: query """ try: try: from duckduckgo_search import DDGS except ImportError: from ddgs import DDGS with DDGS(timeout=6) as ddgs: res = list(ddgs.text(query, max_results=2)) return "\n".join([f"{r['title']}: {r['body'][:100]}" for r in res[:2]]) if res else "No results" except Exception as e: return f"Search fail: {e}" DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space" PROGRESS_FILE = "/tmp/gaia_progress.json" class TinyAgent: def __init__(self): key = os.getenv("GROQ_API_KEY") if not key: raise ValueError("Add GROQ_API_KEY secret!") self.model = LiteLLMModel(model_id="groq/llama-3.1-8b-instant", api_key=key, temperature=0.1) self.agent = CodeAgent(tools=[web_search], model=self.model, add_base_tools=True, max_steps=3) def ask(self, q): try: r = self.agent.run(q + "\nFINAL ANSWER: short") s = str(r) if "FINAL ANSWER:" in s: s = s.split("FINAL ANSWER:")[-1] return s.split("\n")[0].strip().strip('"')[:150] except: return "0" # ONLY 20s REQUESTED - fits in 81s left (4 clicks = 80s total) @spaces.GPU(duration=20) def run_chunk(profile: gr.OAuthProfile | None): if not profile: return "Login first", None username = profile.username if not os.getenv("GROQ_API_KEY"): return "Add GROQ_API_KEY secret in Settings", None # Load progress if os.path.exists(PROGRESS_FILE): with open(PROGRESS_FILE, "r") as f: data = json.load(f) answers = data.get("answers", []) done_ids = set(a["task_id"] for a in answers) else: answers = [] done_ids = set() # Fetch all questions try: all_qs = requests.get(f"{DEFAULT_API_URL}/questions", timeout=10).json() except Exception as e: return f"Fetch error: {e}", None # Find 5 not done yet todo = [q for q in all_qs if q["task_id"] not in done_ids][:5] if not todo and len(answers) >= 20: # All done, submit try: r = requests.post(f"{DEFAULT_API_URL}/submit", json={ "username": username, "agent_code": f"https://huggingface.co/spaces/{os.getenv('SPACE_ID')}/tree/main", "answers": answers }, timeout=15).json() return f"✅ SUBMITTED! Score: {r.get('score')}% {r.get('correct_count')}/{r.get('total_attempted')} - {r.get('message')}", pd.DataFrame(answers) except Exception as e: return f"Submit failed: {e}", pd.DataFrame(answers) if not todo: return f"Already did {len(answers)}/20, click again to submit", pd.DataFrame(answers) agent = TinyAgent() start = time.time() for item in todo: tid = item["task_id"] qtxt = item["question"] # skip file questions to save time (return 0 fast) if item.get("file_name"): ans = "0" else: ans = agent.ask(qtxt) answers.append({"task_id": tid, "submitted_answer": ans}) print(f"{tid} -> {ans} | elapsed {time.time()-start:.1f}s") # Stop if near 18s to avoid killing if time.time() - start > 15: break # Save progress with open(PROGRESS_FILE, "w") as f: json.dump({"answers": answers}, f) remaining = 20 - len(answers) if remaining > 0: return f"Progress: {len(answers)}/20 done in {time.time()-start:.1f}s (used 20s of your 81s). Click RUN AGAIN to do next 5. Need {remaining} more. After 20/20, click once more to submit.", pd.DataFrame(answers) else: return f"All 20 done! Click RUN AGAIN to SUBMIT now.", pd.DataFrame(answers) @spaces.GPU(duration=20) def reset_progress(): if os.path.exists(PROGRESS_FILE): os.remove(PROGRESS_FILE) return "Progress reset", None with gr.Blocks() as demo: gr.Markdown("# 🆘 ZeroGPU 81s Left - Chunked 20s Version") gr.Markdown("**You have 81s quota left, old code needed 270s so it fails. This version only requests 20s per click and does 5 Qs at a time. 4 clicks = 80s total < 81s. For file questions it returns 0 to save time (you still pass 30% on text Qs).**\n\n**BETTER: Go to Settings -> Hardware -> CPU basic (free) -> Save. Then use previous app.py with no GPU decorator and you get infinite time, no quota.**") gr.LoginButton() with gr.Row(): btn = gr.Button("Run 5 Questions (20s)") reset = gr.Button("Reset Progress") out = gr.Textbox(label="Status", lines=5) table = gr.DataFrame(label="Answers") btn.click(fn=run_chunk, outputs=[out, table]) reset.click(fn=reset_progress, outputs=[out, table]) if __name__ == "__main__": demo.launch()