9
File size: 14,661 Bytes
833a2f1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import os  # 导入操作系统模块
import gradio as gr  # 导入Gradio库用于创建Web界面
import requests  # 导入请求库用于API调用
import inspect  # 导入检查模块用于函数检查
import pandas as pd  # 导入pandas用于数据处理

from smolagents import CodeAgent, DuckDuckGoSearchTool, OpenAIServerModel, WikipediaSearchTool  # 从smolagents导入所需组件

# (Keep Constants as is)  # 保持常量不变
# --- Constants ---  # 常量部分
DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space" 
deepseek_api_key = os.environ.get("DEEPSEEK_API_KEY")  # 从环境变量中获取 DeepSeek API Key
deepseek_api_base_url = "https://api.deepseek.com"
# --- Basic Agent Definition ---  
# ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------  
class BasicAgent: 
    def __init__(self):  
        # model = OpenAIServerModel(model_id="gpt-4o") 
        if not deepseek_api_key:
            raise ValueError("DeepSeek API Key not found in environment variables.") 
        model = OpenAIServerModel(
            model_id="deepseek-chat", 
            api_base=deepseek_api_base_url,
            api_headers={"Authorization": f"Bearer {deepseek_api_key}", "Content-Type": "application/json"}
        )
        search_tool = DuckDuckGoSearchTool()  
        wiki_search = WikipediaSearchTool()  

        self.agent = CodeAgent(  # 初始化代码代理
            model = model,  # 设置模型
            tools=[  # 设置可用工具列表
                search_tool,  # 搜索工具
                wiki_search  # 维基百科工具
            ]
        )

    def __call__(self, question: str) -> str:  # 定义调用方法,使对象可直接调用
        return self.agent.run(question) # type: ignore  # 运行代理并返回结果

def run_and_submit_all( profile: gr.OAuthProfile | None):  # 运行并提交所有回答的函数
    """
    Fetches all questions, runs the BasicAgent on them, submits all answers,
    and displays the results.
    """ 
    # --- Determine HF Space Runtime URL and Repo URL ---  
    space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code  # 获取SPACE_ID用于发送代码链接

    if profile:  # 如果用户已登录
        username= f"{profile.username}"  # 获取用户名
        print(f"User logged in: {username}")  # 打印已登录的用户名
    else:  # 如果用户未登录
        print("User not logged in.")  # 打印用户未登录
        return "Please Login to Hugging Face with the button.", None  # 返回请求登录的消息

    api_url = DEFAULT_API_URL  # 设置API URL
    questions_url = f"{api_url}/questions"  # 构建获取问题的URL
    submit_url = f"{api_url}/submit"  # 构建提交答案的URL

    # 1. Instantiate Agent ( modify this part to create your agent)  # 1. 实例化代理(修改此部分来创建你的代理)
    try:  # 尝试
        agent = BasicAgent()  # 创建基本代理实例
    except Exception as e:  # 捕获异常
        print(f"Error instantiating agent: {e}")  # 打印代理实例化错误
        return f"Error initializing agent: {e}", None  # 返回初始化错误信息
    # In the case of an app running as a hugging Face space, this link points toward your codebase ( usefull for others so please keep it public)  # 当应用程序作为Hugging Face空间运行时,此链接指向你的代码库(对其他人有用,请保持公开)
    agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"  # 构建代码库URL
    print(agent_code)  # 打印代码库URL

    # 2. Fetch Questions  # 2. 获取问题
    print(f"Fetching questions from: {questions_url}")  # 打印正在从哪个URL获取问题
    try:  # 尝试
        response = requests.get(questions_url, timeout=15)  # 发送GET请求获取问题,超时设置为15秒
        response.raise_for_status()  # 检查HTTP错误
        questions_data = response.json()  # 解析JSON响应
        if not questions_data:  # 如果问题列表为空
             print("Fetched questions list is empty.")  # 打印问题列表为空
             return "Fetched questions list is empty or invalid format.", None  # 返回问题列表为空或格式无效的消息
        print(f"Fetched {len(questions_data)} questions.")  # 打印获取到的问题数量
    except requests.exceptions.RequestException as e:  # 捕获请求异常
        print(f"Error fetching questions: {e}")  # 打印获取问题错误
        return f"Error fetching questions: {e}", None  # 返回获取问题错误
    except requests.exceptions.JSONDecodeError as e:  # 捕获JSON解码错误
         print(f"Error decoding JSON response from questions endpoint: {e}")  # 打印JSON解码错误
         print(f"Response text: {response.text[:500]}")  # 打印响应文本(前500个字符)
         return f"Error decoding server response for questions: {e}", None  # 返回服务器响应解码错误
    except Exception as e:  # 捕获其他异常
        print(f"An unexpected error occurred fetching questions: {e}")  # 打印获取问题时发生意外错误
        return f"An unexpected error occurred fetching questions: {e}", None  # 返回获取问题时发生意外错误

    # 3. Run your Agent  # 3. 运行你的代理
    results_log = []  # 初始化结果日志列表
    answers_payload = []  # 初始化答案载荷列表
    print(f"Running agent on {len(questions_data)} questions...")  # 打印正在多少个问题上运行代理
    for item in questions_data:  # 遍历每个问题数据项
        task_id = item.get("task_id")  # 获取任务ID
        question_text = item.get("question")  # 获取问题文本
        if not task_id or question_text is None:  # 如果任务ID或问题文本缺失
            print(f"Skipping item with missing task_id or question: {item}")  # 打印跳过缺少任务ID或问题的项
            continue  # 继续下一个循环
        try:  # 尝试
            submitted_answer = agent(question_text)  # 使用代理回答问题
            answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})  # 将答案添加到载荷中
            results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})  # 将结果添加到日志中
        except Exception as e:  # 捕获异常
             print(f"Error running agent on task {task_id}: {e}")  # 打印在任务上运行代理时出错
             results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})  # 将错误添加到结果日志中

    if not answers_payload:  # 如果答案载荷为空
        print("Agent did not produce any answers to submit.")  # 打印代理没有产生任何答案可提交
        return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)  # 返回代理没有产生任何答案可提交

    # 4. Prepare Submission  # 4. 准备提交
    submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}  # 准备提交数据
    status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."  # 构建状态更新消息
    print(status_update)  # 打印状态更新

    # 5. Submit  # 5. 提交
    print(f"Submitting {len(answers_payload)} answers to: {submit_url}")  # 打印正在将多少个答案提交到哪个URL
    try:  # 尝试
        response = requests.post(submit_url, json=submission_data, timeout=60)  # 发送POST请求提交数据,超时设置为60秒
        response.raise_for_status()  # 检查HTTP错误
        result_data = response.json()  # 解析JSON响应
        final_status = (  # 构建最终状态消息
            f"Submission Successful!\n"  # 提交成功
            f"User: {result_data.get('username')}\n"  # 用户名
            f"Overall Score: {result_data.get('score', 'N/A')}% "  # 总分
            f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"  # 正确数/总尝试数
            f"Message: {result_data.get('message', 'No message received.')}"  # 消息
        )
        print("Submission successful.")  # 打印提交成功
        results_df = pd.DataFrame(results_log)  # 创建结果数据框
        return final_status, results_df  # 返回最终状态和结果数据框
    except requests.exceptions.HTTPError as e:  # 捕获HTTP错误
        error_detail = f"Server responded with status {e.response.status_code}."  # 服务器响应状态
        try:  # 尝试
            error_json = e.response.json()  # 解析错误响应的JSON
            error_detail += f" Detail: {error_json.get('detail', e.response.text)}"  # 添加错误详情
        except requests.exceptions.JSONDecodeError:  # 捕获JSON解码错误
            error_detail += f" Response: {e.response.text[:500]}"  # 添加原始响应文本
        status_message = f"Submission Failed: {error_detail}"  # 构建提交失败消息
        print(status_message)  # 打印状态消息
        results_df = pd.DataFrame(results_log)  # 创建结果数据框
        return status_message, results_df  # 返回状态消息和结果数据框
    except requests.exceptions.Timeout:  # 捕获超时异常
        status_message = "Submission Failed: The request timed out."  # 构建请求超时消息
        print(status_message)  # 打印状态消息
        results_df = pd.DataFrame(results_log)  # 创建结果数据框
        return status_message, results_df  # 返回状态消息和结果数据框
    except requests.exceptions.RequestException as e:  # 捕获请求异常
        status_message = f"Submission Failed: Network error - {e}"  # 构建网络错误消息
        print(status_message)  # 打印状态消息
        results_df = pd.DataFrame(results_log)  # 创建结果数据框
        return status_message, results_df  # 返回状态消息和结果数据框
    except Exception as e:  # 捕获其他异常
        status_message = f"An unexpected error occurred during submission: {e}"  # 构建意外错误消息
        print(status_message)  # 打印状态消息
        results_df = pd.DataFrame(results_log)  # 创建结果数据框
        return status_message, results_df  # 返回状态消息和结果数据框

# --- Build Gradio Interface using Blocks --- 
with gr.Blocks() as demo:  # 创建Gradio Blocks界面
    gr.Markdown("# Basic Agent Evaluation Runner")  # 添加标题
    gr.Markdown(  # 添加说明文本
        """
        Modified by niku....  # 由niku修改
        **Instructions:**  # 指示
        1.  Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...  # 请克隆此空间,然后修改代码以定义代理逻辑、工具和必要的包等
        2.  Log in to your Hugging Face account using the button below. This uses your HF username for submission.  # 使用下面的按钮登录您的Hugging Face账户。这将使用您的HF用户名进行提交
        3.  Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.  # 点击"运行评估并提交所有答案"以获取问题,运行您的代理,提交答案,并查看分数
        ---
        **Disclaimers:**  # 免责声明
        Once clicking on the "submit button, it can take quite some time ( this is the time for the agent to go through all the questions).  # 点击"提交"按钮后,可能需要相当长的时间(这是代理回答所有问题所需的时间)
        This space provides a basic setup and is intentionally sub-optimal to encourage you to develop your own, more robust solution. For instance for the delay process of the submit button, a solution could be to cache the answers and submit in a seperate action or even to answer the questions in async.  # 此空间提供了一个基本设置,故意设计成不是最优的,以鼓励您开发自己的更强大的解决方案。例如,对于提交按钮的延迟过程,一个解决方案可能是缓存答案并在单独的操作中提交,或者甚至异步回答问题
        """
    )

    gr.LoginButton()  # 添加登录按钮

    run_button = gr.Button("Run Evaluation & Submit All Answers")  # 添加运行评估按钮

    status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)  # 添加状态输出文本框
    # Removed max_rows=10 from DataFrame constructor  # 从DataFrame构造函数中移除了max_rows=10
    results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)  # 添加结果表格

    run_button.click(  # 设置按钮点击事件
        fn=run_and_submit_all,  # 点击时运行的函数
        outputs=[status_output, results_table]  # 输出组件
    )

if __name__ == "__main__":  # 如果这个脚本作为主程序运行
    print("\n" + "-"*30 + " App Starting " + "-"*30)  # 打印应用启动分隔线
    # Check for SPACE_HOST and SPACE_ID at startup for information  # 启动时检查SPACE_HOST和SPACE_ID信息
    space_host_startup = os.getenv("SPACE_HOST")  # 获取SPACE_HOST环境变量
    space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup  # 获取SPACE_ID环境变量

    if space_host_startup:  # 如果找到SPACE_HOST
        print(f"✅ SPACE_HOST found: {space_host_startup}")  # 打印找到SPACE_HOST
        print(f"   Runtime URL should be: https://{space_host_startup}.hf.space")  # 打印运行时URL
    else:  # 如果没找到SPACE_HOST
        print("ℹ️  SPACE_HOST environment variable not found (running locally?).")  # 打印SPACE_HOST环境变量未找到

    if space_id_startup: # Print repo URLs if SPACE_ID is found  # 如果找到SPACE_ID,打印代码库URL
        print(f"✅ SPACE_ID found: {space_id_startup}")  # 打印找到SPACE_ID
        print(f"   Repo URL: https://huggingface.co/spaces/{space_id_startup}")  # 打印代码库URL
        print(f"   Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")  # 打印代码库树URL
    else:  # 如果没找到SPACE_ID
        print("ℹ️  SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")  # 打印SPACE_ID环境变量未找到

    print("-"*(60 + len(" App Starting ")) + "\n")  # 打印结束分隔线

    print("Launching Gradio Interface for Basic Agent Evaluation...")  # 打印正在启动Gradio界面
    demo.launch(debug=True, share=False)  # 启动Gradio演示,启用调试模式,不共享