File size: 7,704 Bytes
10e9b7d
79a6984
eccf8e4
c1074ea
b6cd9a2
 
3ab99c9
12850a5
 
0e1fcc9
b6cd9a2
023211e
 
 
 
 
 
12850a5
b6cd9a2
b02d70e
 
 
 
 
 
 
 
 
 
 
 
b6cd9a2
84944af
023211e
5ca79a2
023211e
5ca79a2
 
023211e
5ca79a2
49436c1
023211e
 
 
49436c1
023211e
0c05b5e
d27baf3
62ebd37
5ca79a2
62ebd37
5ca79a2
 
62ebd37
5ca79a2
d27baf3
023211e
 
 
d27baf3
62ebd37
1a70103
b6cd9a2
b02d70e
b6cd9a2
 
 
9e89eb7
023211e
81c9217
 
 
 
 
023211e
81c9217
 
 
 
 
 
 
 
 
 
 
fa3e9dc
81c9217
b02d70e
81c9217
b02d70e
 
 
9e89eb7
31243f4
 
1af702d
b6cd9a2
 
023211e
1af702d
67bae22
 
 
1af702d
b6cd9a2
023211e
b02d70e
 
 
 
 
 
 
 
023211e
 
 
67bae22
394713d
b6cd9a2
 
 
 
40795a7
fa3e9dc
9f04c9f
62c58dd
fa3e9dc
79a6984
fa3e9dc
79a6984
dbdcf6f
 
023211e
dbdcf6f
 
 
023211e
 
 
dbdcf6f
fa3e9dc
79a6984
 
023211e
fa3e9dc
79a6984
 
9f04c9f
b6cd9a2
b02d70e
b6cd9a2
 
3c4371f
b6cd9a2
 
 
0f7618e
b6cd9a2
 
 
0f7618e
 
b6cd9a2
 
 
0f7618e
 
 
b6cd9a2
 
0f7618e
5ca79a2
 
b6cd9a2
 
5ca79a2
 
b6cd9a2
0f7618e
b6cd9a2
 
 
31243f4
b6cd9a2
 
0f7618e
 
b6cd9a2
5ca79a2
 
 
b6cd9a2
 
 
81c9217
b6cd9a2
 
 
 
 
 
 
0f7618e
b6cd9a2
0f7618e
b6cd9a2
0f7618e
b6cd9a2
b02d70e
b6cd9a2
e80aab9
31243f4
0f7618e
b6cd9a2
 
 
0f7618e
7e4a06b
b668b47
 
 
0f7618e
b6cd9a2
e80aab9
 
81c9217
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
import os
import re
import requests
import pandas as pd
import yaml
import gradio as gr

from datetime import datetime
from typing import Optional

import pytz
import wikipedia

from smolagents import CodeAgent, HfApiModel, tool
from tools.final_answer    import FinalAnswerTool
from tools.web_search      import DuckDuckGoSearchTool
from tools.visit_webpage   import VisitWebpageTool

# -----------------------------------------------------------------------------
# 1) IMPORT YOUR NEW TOOLS
# -----------------------------------------------------------------------------
from tools.search_tools          import simple_search, archive_search
from tools.page_navigation_tools import (
    find_on_page_ctrl_f,
    find_next,
    page_down,
    page_up,
)

# -----------------------------------------------------------------------------
# 2) YOUR CUSTOM TOOLS (with proper docstrings for Args)
# -----------------------------------------------------------------------------
@tool
def get_current_time_in_timezone(timezone: str) -> str:
    """
    Fetches the current local time in a specified timezone.

    Args:
        timezone: A string representing a valid timezone (e.g., 'America/New_York').
    """
    try:
        tz = pytz.timezone(timezone)
        now = datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S")
        return f"The current local time in {timezone} is: {now}"
    except Exception as e:
        return f"Error fetching time for timezone '{timezone}': {e}"

@tool
def wiki(query: str) -> str:
    """
    Searches Wikipedia for a query and returns the page content (English).

    Args:
        query: The Wikipedia page title or search term.
    """
    try:
        wikipedia.set_lang("en")
        page = wikipedia.page(query, auto_suggest=False)
        return page.content
    except Exception as e:
        return f"Error fetching Wikipedia page for '{query}': {e}"

# -----------------------------------------------------------------------------
# 3) LOAD PROMPTS & RAG MAP
# -----------------------------------------------------------------------------
with open("prompts.yaml", "r") as f:
    prompt_templates = yaml.safe_load(f)

# top-level key in prompts.yaml must now be `rag_fallbacks:`
rag_fallbacks = prompt_templates.get("rag_fallbacks", {})

@tool
def rag_fallback(question: str) -> str:
    """
    Returns a pre‐cached answer if the question matches any RAG key.

    Args:
        question: The user’s question.
    """
    q_low = question.lower()
    for key, val in rag_fallbacks.items():
        tokens = re.findall(r"\w+", key.lower())
        tokens = [t for t in tokens if len(t) > 2]
        if tokens and all(tok in q_low for tok in tokens):
            return val
    return ""

# -----------------------------------------------------------------------------
# 4) INSTANTIATE TOOLS & AGENT
# -----------------------------------------------------------------------------
final_answer   = FinalAnswerTool()
web_search     = DuckDuckGoSearchTool()
visit_webpage  = VisitWebpageTool()

class BasicAgent:
    def __init__(self):
        model = HfApiModel(
            model_id="Qwen/Qwen2.5-Coder-32B-Instruct",
            max_tokens=2096,
            temperature=0.2,       # more conservative
        )
        self.agent = CodeAgent(
            model=model,
            tools=[
                final_answer,
                web_search,
                visit_webpage,
                # our new tools:
                simple_search,
                archive_search,
                find_on_page_ctrl_f,
                find_next,
                page_down,
                page_up,
                # legacy tools:
                wiki,
                get_current_time_in_timezone,
                rag_fallback,
            ],
            max_steps=10,          # allow enough steps to chain browse → navigate
            verbosity_level=1,
            name="Son_of_Anton",
            description="Your friendly AI agent to help you with any task",
            prompt_templates=prompt_templates,
        )
        self.rag_fallbacks = rag_fallbacks

    def __call__(self, question: str) -> str:
        try:
            raw_ans = self.agent.run(question)
        except Exception:
            raw_ans = ""

        ans_str = str(raw_ans).strip().lower()
        # manual fallback if nothing useful came out
        if (
            not ans_str
            or ans_str.startswith("i'm sorry")
            or "unanswered" in ans_str
            or "none"       in ans_str
            or "error"      in ans_str
        ):
            for key, val in self.rag_fallbacks.items():
                tokens = re.findall(r"\w+", key.lower())
                tokens = [t for t in tokens if len(t) > 2]
                if tokens and all(tok in question.lower() for tok in tokens):
                    return val

        return raw_ans

# -----------------------------------------------------------------------------
# 5) EVALUATION LOGIC (unchanged)
# -----------------------------------------------------------------------------
DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"

def run_and_submit_all(profile: Optional[gr.OAuthProfile]):
    if profile is None:
        return "Please log in with Hugging Face to submit.", None

    space_id      = os.getenv("SPACE_ID")
    questions_url = f"{DEFAULT_API_URL}/questions"
    submit_url    = f"{DEFAULT_API_URL}/submit"

    try:
        r = requests.get(questions_url, timeout=15)
        r.raise_for_status()
        questions = r.json()
    except Exception as e:
        return f"Error fetching questions: {e}", None

    if not questions:
        return "No questions returned.", None

    agent   = BasicAgent()
    logs    = []
    answers = []
    for item in questions:
        tid = item.get("task_id")
        q   = item.get("question")
        if not tid or not q:
            continue
        ans = agent(q)
        logs.append({"Task ID": tid, "Question": q, "Answer": ans})
        answers.append({"task_id": tid, "submitted_answer": ans})

    if not answers:
        return "Agent produced no answers.", pd.DataFrame(logs)

    try:
        payload = {
            "username":   profile.username,
            "agent_code": f"https://huggingface.co/spaces/{space_id}/tree/main",
            "answers":    answers,
        }
        r2 = requests.post(submit_url, json=payload, timeout=60)
        r2.raise_for_status()
        res    = r2.json()
        status = (
            f"✔ Submission Successful!\n"
            f"User: {res.get('username')}\n"
            f"Score: {res.get('score')}% "
            f"({res.get('correct_count')}/"
            f"{res.get('total_attempted')})\n"
            f"{res.get('message','')}"
        )
        return status, pd.DataFrame(logs)
    except Exception as e:
        return f"Submission Failed: {e}", pd.DataFrame(logs)

# -----------------------------------------------------------------------------
# 6) GRADIO EVALUATION UI (unchanged)
# -----------------------------------------------------------------------------
with gr.Blocks() as demo:
    gr.Markdown("# Basic Agent Evaluation Runner")
    gr.Markdown("""
    **Instructions**  
    1. Log in with your Hugging Face account.  
    2. Click “Run Evaluation & Submit All Answers” below.
    """)
    gr.LoginButton()
    btn   = gr.Button("Run Evaluation & Submit All Answers")
    out_s = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
    out_df= gr.DataFrame(label="Questions and Agent Answers", wrap=True)

    btn.click(run_and_submit_all, [], [out_s, out_df])

if __name__ == "__main__":
    demo.launch(debug=True, share=False)