File size: 5,067 Bytes
a3fbafa
5f941ed
 
 
 
48de6a0
5f941ed
 
 
a3fbafa
5f941ed
a3fbafa
5f941ed
 
dbf465b
 
 
 
a3fbafa
 
 
5f941ed
a3fbafa
5f941ed
 
a3fbafa
5f941ed
a3fbafa
5f941ed
19c50da
 
a3fbafa
 
 
5f941ed
a3fbafa
5f941ed
a3fbafa
 
48de6a0
19c50da
a3fbafa
 
19c50da
5f941ed
a3fbafa
 
 
5f941ed
a3fbafa
5f941ed
19c50da
 
a3fbafa
5f941ed
a3fbafa
 
 
 
 
 
 
 
 
5f941ed
a3fbafa
5f941ed
a3fbafa
5f941ed
19c50da
 
a3fbafa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19c50da
 
a3fbafa
 
19c50da
a3fbafa
 
 
 
 
 
 
5f941ed
a3fbafa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5f941ed
 
a3fbafa
 
5f941ed
a3fbafa
 
 
 
19c50da
a3fbafa
 
5f941ed
 
a3fbafa
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
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()