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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +127 -150
app.py CHANGED
@@ -3,6 +3,8 @@ import gradio as gr
3
  import requests
4
  import pandas as pd
5
  import time
 
 
6
  from typing import Optional
7
 
8
  # 引入搜尋工具
@@ -17,192 +19,167 @@ 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
136
 
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()
 
3
  import requests
4
  import pandas as pd
5
  import time
6
+ import re
7
+ import random
8
  from typing import Optional
9
 
10
  # 引入搜尋工具
 
19
  GROQ_API_URL = "https://api.groq.com/openai/v1/chat/completions"
20
 
21
  def perform_search(query: str) -> str:
22
+ """搜尋工具:只抓重點,有隨機延遲"""
23
+ print(f"🕵️ Searching: {query[:50]}...")
24
  try:
25
+ time.sleep(random.uniform(1.0, 2.0)) # 隨機延遲
 
26
  with DDGS() as ddgs:
27
+ results = list(ddgs.text(query, max_results=2, backend="lite"))
 
28
 
29
  if not results:
30
+ return ""
31
 
32
+ context = [f"- {r.get('body', '')}" for r in results]
33
+ return "\n".join(context)[:800]
 
 
 
 
 
34
  except Exception as e:
35
  print(f"Search Error: {e}")
36
+ return ""
37
 
38
+ class GroqClient:
 
39
  def __init__(self):
40
  self.api_key = os.getenv("GROQ_API_KEY")
41
+
42
+ def query(self, messages, model, max_retries=3):
43
+ """發送請求給 Groq,包含自動重試機制"""
44
  if not self.api_key:
45
+ return "Error: No API Key"
46
+
47
+ headers = {
48
+ "Authorization": f"Bearer {self.api_key}",
49
+ "Content-Type": "application/json"
50
+ }
51
 
52
+ payload = {
53
+ "model": model,
54
+ "messages": messages,
55
+ "temperature": 0.1,
56
+ "max_tokens": 500
57
+ }
58
+
59
+ for attempt in range(max_retries):
60
+ try:
61
+ response = requests.post(GROQ_API_URL, headers=headers, json=payload, timeout=30)
62
+
63
+ # 如果成功
64
+ if response.status_code == 200:
65
+ return response.json()['choices'][0]['message']['content']
66
+
67
+ # 如果遇到 429 (太快了),休息久一點再試
68
+ if response.status_code == 429:
69
+ wait_time = (attempt + 1) * 10 # 第一次等10秒,第二次等20秒...
70
+ print(f"⚠️ Rate limit (429). Waiting {wait_time}s...")
71
+ time.sleep(wait_time)
72
+ continue
73
+
74
+ return f"API Error {response.status_code}"
75
+
76
+ except Exception as e:
77
+ print(f"Connection Error: {e}")
78
+ time.sleep(5)
79
+
80
+ return "Failed after retries."
81
+
82
+ def solve_question(question, client):
83
+ """分析題目類型並選擇策略"""
84
 
85
+ # 1. 檢查是否有圖片網址 (Vision 任務)
86
+ # 常見格式:https://... .png 或 .jpg
87
+ img_match = re.search(r'(https?://[^\s]+\.(?:jpg|jpeg|png|webp))', question)
88
+
89
+ if img_match:
90
+ image_url = img_match.group(1)
91
+ print(f"👁️ Vision Task Detected! URL: {image_url}")
92
 
93
+ # 使用 Groq 的視覺模型
94
+ messages = [
95
+ {
96
+ "role": "user",
97
+ "content": [
98
+ {"type": "text", "text": f"Answer this question directly: {question}"},
99
+ {"type": "image_url", "image_url": {"url": image_url}}
100
+ ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  }
102
+ ]
103
+ # 使用具備視覺能力的模型
104
+ return client.query(messages, model="llama-3.2-11b-vision-preview")
105
+
106
+ else:
107
+ # 2. 一般文字/搜尋任務
108
+ # 先搜尋
109
+ context = perform_search(question)
110
+
111
+ # 組合 Prompt
112
+ system_msg = "You are a helpful AI. Answer concisely using the provided context."
113
+ if context:
114
+ user_msg = f"Context: {context}\n\nQuestion: {question}"
115
+ else:
116
+ user_msg = question
117
 
118
+ messages = [
119
+ {"role": "system", "content": system_msg},
120
+ {"role": "user", "content": user_msg}
121
+ ]
122
+
123
+ # 使用最強的文字模型
124
+ return client.query(messages, model="llama-3.3-70b-versatile")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
 
126
  def run_and_submit_all(profile: Optional[gr.OAuthProfile] = None):
 
 
127
  if profile is None:
128
+ return "⚠️ Please login first!", None
129
 
130
+ client = GroqClient()
131
+ if not client.api_key:
132
+ return "❌ Error: GROQ_API_KEY not found!", None
 
 
 
 
 
 
 
133
 
134
  try:
135
  print("Fetching questions...")
136
+ questions = requests.get(f"{DEFAULT_API_URL}/questions", timeout=30).json()
 
137
  except Exception as e:
138
+ return f"❌ Fetch failed: {str(e)}", None
139
 
140
+ answers = []
141
+ logs = []
 
 
142
 
143
+ total = len(questions)
144
+ for idx, item in enumerate(questions, 1):
145
+ q = item.get("question")
146
+ tid = item.get("task_id")
147
 
148
+ print(f"🚀 [{idx}/{total}] Processing: {tid}...")
149
 
150
+ # 核心:解題
151
+ ans = solve_question(q, client)
152
+
153
+ answers.append({"task_id": tid, "submitted_answer": ans})
154
+ logs.append({"Task": tid, "Type": "Image" if "http" in q and ".jpg" in q else "Text", "Answer": str(ans)[:100]})
155
+
156
+ # !!! 關鍵保命符 !!!
157
+ # 每題解完強制休息 5 秒,防止 429 錯誤
158
+ time.sleep(5)
 
 
 
 
 
 
 
 
159
 
160
  try:
161
+ print("Submitting...")
162
+ res = requests.post(f"{DEFAULT_API_URL}/submit", json={
163
+ "username": profile.username,
164
+ "agent_code": "https://huggingface.co/spaces/test/test", # 這裡隨意填
165
+ "answers": answers
166
+ }, timeout=60)
167
 
168
+ data = res.json()
 
 
 
 
 
169
  score = data.get('score', 0)
170
+ return f"🎉 Final Score: {score}%", pd.DataFrame(logs)
171
 
 
 
 
172
  except Exception as e:
173
+ return f"Submit error: {str(e)}", pd.DataFrame(logs)
174
 
175
+ with gr.Blocks(title="Final Agent (Vision + Anti-429)") as demo:
176
+ gr.Markdown("# 🚀 Final Agent (Slow & Steady)")
 
177
  with gr.Row():
178
+ gr.LoginButton()
179
+ btn = gr.Button("Run Evaluation", variant="primary")
180
+ out = gr.Textbox(label="Status")
181
+ tab = gr.DataFrame(label="Logs")
182
+ btn.click(run_and_submit_all, outputs=[out, tab])
 
 
183
 
184
  if __name__ == "__main__":
185
  demo.launch()