s1144662 commited on
Commit
de2bc79
·
verified ·
1 Parent(s): c6c4a33

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +135 -81
app.py CHANGED
@@ -4,102 +4,132 @@ import requests
4
  import pandas as pd
5
  import time
6
  from typing import Optional
7
- from smolagents import CodeAgent, OpenAIServerModel, tool
8
 
9
- # --- 搜尋工具 (修正安裝指令 + 省流量版) ---
10
  try:
11
  from duckduckgo_search import DDGS
12
  except ImportError:
13
  import os
14
- # 修正:使用正確的套件名稱進行安裝
15
- os.system('pip install duckduckgo-search')
16
  from duckduckgo_search import DDGS
17
 
18
- @tool
19
- def web_search(query: str) -> str:
20
- """
21
- Lite search with strict token limits for Groq free tier.
22
- Args:
23
- query: The search query string.
24
- """
25
- print(f"🕵️ [Debug] Searching: {query}")
26
  try:
27
- # 強制冷靜 1 秒保護新 Key
28
- time.sleep(1.0)
29
-
30
  with DDGS() as ddgs:
31
- # 使用 lite 模式,只抓 1 筆
32
- results = list(ddgs.text(query, max_results=1, backend="lite"))
33
 
34
  if not results:
35
- return "No results. Guess answer."
36
 
37
- # 關鍵保命符:截斷內容!
38
- # 只回傳前 400 字,避免瞬間 Token 爆量導致卡死
39
- first = results[0]
40
- summary = f"Title: {first.get('title','')}\nInfo: {first.get('body','')}"
41
- return summary[:400]
42
 
 
 
43
  except Exception as e:
44
- print(f" Error: {e}")
45
- return "Search error. Guess answer."
46
-
47
- # -----------------------------------------------------------
48
-
49
- DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
50
 
51
  class GroqAgent:
 
52
  def __init__(self):
53
  self.api_key = os.getenv("GROQ_API_KEY")
54
  if not self.api_key:
 
55
  self.agent = None
56
  return
57
-
58
- # 使用 Llama 3.3 70B
59
- model = OpenAIServerModel(
60
- model_id="llama-3.3-70b-versatile",
61
- api_base="https://api.groq.com/openai/v1",
62
- api_key=self.api_key
63
- )
64
 
65
- self.agent = CodeAgent(
66
- tools=[web_search],
67
- model=model,
68
- max_steps=2,
69
- verbosity_level=1
70
- )
71
 
72
  def __call__(self, question: str) -> str:
73
  if self.agent is None:
74
  return "Error: GROQ_API_KEY not configured."
75
 
76
  try:
77
- # 強制冷靜 2 秒,避免觸發 RPM 限制
78
- time.sleep(2.0)
 
 
 
 
 
 
 
 
 
 
 
79
 
80
- prompt = f"""
81
- Task: Answer concisely.
82
- 1. Search ONCE.
83
- 2. If search fails, GUESS.
84
- 3. Keep answer under 20 words.
85
 
86
- Question: {question}
 
87
  """
88
- return str(self.agent.run(prompt))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  except Exception as e:
90
  return f"Error: {str(e)[:100]}"
91
 
 
92
  def run_and_submit_all(profile: Optional[gr.OAuthProfile] = None):
 
 
93
  if profile is None:
94
- return "⚠️ Please login first!", None
95
 
96
  username = profile.username
97
  space_id = os.getenv("SPACE_ID", "s1144662")
98
  api_url = DEFAULT_API_URL
99
 
100
  try:
101
- agent_wrapper = GroqAgent()
102
- if agent_wrapper.agent is None:
103
  return "❌ Error: GROQ_API_KEY not found!", None
104
  except Exception as e:
105
  return f"❌ Init failed: {str(e)}", None
@@ -107,48 +137,72 @@ def run_and_submit_all(profile: Optional[gr.OAuthProfile] = None):
107
  try:
108
  print("Fetching questions...")
109
  response = requests.get(f"{api_url}/questions", timeout=30)
110
- questions = response.json()
111
  except Exception as e:
112
- return f"❌ Fetch failed: {str(e)}", None
113
 
114
- answers = []
115
- logs = []
116
 
117
- total = len(questions)
118
- for idx, item in enumerate(questions, 1):
119
- q = item.get("question")
120
- tid = item.get("task_id")
121
-
122
- print(f"🚀 [{idx}/{total}] Task: {tid}")
123
 
124
- ans = agent_wrapper(q)
125
 
126
- answers.append({"task_id": tid, "submitted_answer": ans})
127
- logs.append({"Task": tid, "Answer": str(ans)[:100]})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
 
129
  try:
130
- print("Submitting...")
131
- res = requests.post(f"{api_url}/submit", json={
132
  "username": username,
133
  "agent_code": f"https://huggingface.co/spaces/{space_id}/tree/main",
134
- "answers": answers
135
- }, timeout=60)
136
 
137
- data = res.json()
 
 
 
 
 
138
  score = data.get('score', 0)
139
- return f"🎉 Score: {score}%", pd.DataFrame(logs)
140
 
 
 
 
141
  except Exception as e:
142
- return f"Submit error: {str(e)}", pd.DataFrame(logs)
143
 
144
- with gr.Blocks(title="Final Agent (New Key + Token Safe)") as demo:
145
- gr.Markdown("# 🚀 Final Agent (New Key)")
 
146
  with gr.Row():
147
- gr.LoginButton()
148
- btn = gr.Button("Run Evaluation", variant="primary")
149
- out = gr.Textbox(label="Status")
150
- tab = gr.DataFrame(label="Logs")
151
- btn.click(run_and_submit_all, outputs=[out, tab])
 
 
152
 
153
  if __name__ == "__main__":
154
  demo.launch()
 
4
  import pandas as pd
5
  import time
6
  from typing import Optional
 
7
 
8
+ # 引入搜尋工具
9
  try:
10
  from duckduckgo_search import DDGS
11
  except ImportError:
12
  import os
13
+ os.system('pip install duckduckgo-search>=6.0.0')
 
14
  from duckduckgo_search import DDGS
15
 
16
+ DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
17
+ GROQ_API_URL = "https://api.groq.com/openai/v1/chat/completions"
18
+
19
+ def perform_search(query: str) -> str:
20
+ """手動執行搜尋並回傳摘要"""
21
+ print(f"🕵️ Searching for: {query}")
 
 
22
  try:
23
+ # 為了避免被封鎖加一點延遲
24
+ time.sleep(1)
 
25
  with DDGS() as ddgs:
26
+ # 使用 lite 模式比較快且穩
27
+ results = list(ddgs.text(query, max_results=3, backend="lite"))
28
 
29
  if not results:
30
+ return "No search results found."
31
 
32
+ # 整理結果
33
+ context = []
34
+ for r in results:
35
+ context.append(f"- {r.get('body', '')}")
 
36
 
37
+ # 限制長度以免爆 Token
38
+ return "\n".join(context)[:1000]
39
  except Exception as e:
40
+ print(f"Search Error: {e}")
41
+ return "Search failed."
 
 
 
 
42
 
43
  class GroqAgent:
44
+ """使用 Groq API + 手動搜尋的 Agent"""
45
  def __init__(self):
46
  self.api_key = os.getenv("GROQ_API_KEY")
47
  if not self.api_key:
48
+ print("✗ GROQ_API_KEY not found")
49
  self.agent = None
50
  return
 
 
 
 
 
 
 
51
 
52
+ self.agent = True
53
+ print("✓ Groq agent initialized")
 
 
 
 
54
 
55
  def __call__(self, question: str) -> str:
56
  if self.agent is None:
57
  return "Error: GROQ_API_KEY not configured."
58
 
59
  try:
60
+ # 1. 先進行搜尋 (這是拿分的關鍵!)
61
+ # 我們直接搜整個問題,或者你可以寫邏輯去提取關鍵字
62
+ search_context = perform_search(question)
63
+
64
+ # 2. 組合新的 Prompt
65
+ system_prompt = """
66
+ You are a helpful AI assistant.
67
+ You will be provided with Context from a web search.
68
+ Use the Context to answer the User's Question accurately.
69
+ If the answer is in the Context, use it.
70
+ If the Context is empty or irrelevant, use your internal knowledge.
71
+ Keep answers concise.
72
+ """
73
 
74
+ user_content = f"""
75
+ Context:
76
+ {search_context}
 
 
77
 
78
+ Question:
79
+ {question}
80
  """
81
+
82
+ # 3. 呼叫 Groq
83
+ headers = {
84
+ "Authorization": f"Bearer {self.api_key}",
85
+ "Content-Type": "application/json"
86
+ }
87
+
88
+ payload = {
89
+ "model": "llama-3.3-70b-versatile", # 70B 比較聰明
90
+ "messages": [
91
+ {"role": "system", "content": system_prompt},
92
+ {"role": "user", "content": user_content}
93
+ ],
94
+ "temperature": 0.1, # 降低隨機性
95
+ "max_tokens": 300,
96
+ }
97
+
98
+ # 強制冷靜一下避免 Rate Limit
99
+ time.sleep(1)
100
+
101
+ response = requests.post(
102
+ GROQ_API_URL,
103
+ headers=headers,
104
+ json=payload,
105
+ timeout=30
106
+ )
107
+
108
+ if response.status_code != 200:
109
+ return f"API Error {response.status_code}"
110
+
111
+ result = response.json()
112
+ answer = result['choices'][0]['message']['content'].strip()
113
+
114
+ return answer
115
+
116
  except Exception as e:
117
  return f"Error: {str(e)[:100]}"
118
 
119
+
120
  def run_and_submit_all(profile: Optional[gr.OAuthProfile] = None):
121
+ """主要評估和提交函數"""
122
+
123
  if profile is None:
124
+ return "⚠️ Please click 'Login with Hugging Face' button first!", None
125
 
126
  username = profile.username
127
  space_id = os.getenv("SPACE_ID", "s1144662")
128
  api_url = DEFAULT_API_URL
129
 
130
  try:
131
+ agent = GroqAgent()
132
+ if agent.agent is None:
133
  return "❌ Error: GROQ_API_KEY not found!", None
134
  except Exception as e:
135
  return f"❌ Init failed: {str(e)}", None
 
137
  try:
138
  print("Fetching questions...")
139
  response = requests.get(f"{api_url}/questions", timeout=30)
140
+ questions_data = response.json()
141
  except Exception as e:
142
+ return f"❌ Failed to fetch questions: {str(e)}", None
143
 
144
+ answers_payload = []
145
+ results_log = []
146
 
147
+ total = len(questions_data)
148
+
149
+ for idx, item in enumerate(questions_data, 1):
150
+ task_id = item.get("task_id")
151
+ question_text = item.get("question")
 
152
 
153
+ print(f"[{idx}/{total}] Processing: {task_id}...")
154
 
155
+ try:
156
+ answer = agent(question_text)
157
+
158
+ answers_payload.append({
159
+ "task_id": task_id,
160
+ "submitted_answer": answer
161
+ })
162
+
163
+ results_log.append({
164
+ "Task ID": task_id,
165
+ "Question": question_text[:50],
166
+ "Answer": answer[:100]
167
+ })
168
+
169
+ except Exception as e:
170
+ answers_payload.append({"task_id": task_id, "submitted_answer": "Error"})
171
+ results_log.append({"Task ID": task_id, "Question": "Error", "Answer": str(e)})
172
 
173
  try:
174
+ print("Submitting answers...")
175
+ submission_data = {
176
  "username": username,
177
  "agent_code": f"https://huggingface.co/spaces/{space_id}/tree/main",
178
+ "answers": answers_payload
179
+ }
180
 
181
+ response = requests.post(
182
+ f"{api_url}/submit",
183
+ json=submission_data,
184
+ timeout=120
185
+ )
186
+ data = response.json()
187
  score = data.get('score', 0)
 
188
 
189
+ status_msg = f"🎉 Score: {score}%" if score >= 30 else f"Score: {score}% (Need 30%)"
190
+ return status_msg, pd.DataFrame(results_log)
191
+
192
  except Exception as e:
193
+ return f" Submission failed: {str(e)}", pd.DataFrame(results_log)
194
 
195
+ # Gradio 介面
196
+ with gr.Blocks(title="Unit 4 Final Assignment (Manual RAG)", theme=gr.themes.Soft()) as demo:
197
+ gr.Markdown("# 🚀 Final Agent (Manual Search)")
198
  with gr.Row():
199
+ gr.LoginButton(scale=1)
200
+ run_btn = gr.Button("Run Evaluation", scale=3, variant="primary")
201
+
202
+ status = gr.Textbox(label="Status", lines=2)
203
+ details = gr.DataFrame(label="Results")
204
+
205
+ run_btn.click(fn=run_and_submit_all, inputs=[], outputs=[status, details])
206
 
207
  if __name__ == "__main__":
208
  demo.launch()