Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -20,9 +20,13 @@ 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(
|
| 26 |
with DDGS() as ddgs:
|
| 27 |
results = list(ddgs.text(query, max_results=2, backend="lite"))
|
| 28 |
|
|
@@ -39,8 +43,8 @@ class GroqClient:
|
|
| 39 |
def __init__(self):
|
| 40 |
self.api_key = os.getenv("GROQ_API_KEY")
|
| 41 |
|
| 42 |
-
def query(self, messages, model, max_retries=
|
| 43 |
-
"""發送請求給 Groq,包含自動重試機制"""
|
| 44 |
if not self.api_key:
|
| 45 |
return "Error: No API Key"
|
| 46 |
|
|
@@ -49,11 +53,21 @@ class GroqClient:
|
|
| 49 |
"Content-Type": "application/json"
|
| 50 |
}
|
| 51 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
payload = {
|
| 53 |
"model": model,
|
| 54 |
-
"messages":
|
| 55 |
"temperature": 0.1,
|
| 56 |
-
"max_tokens":
|
| 57 |
}
|
| 58 |
|
| 59 |
for attempt in range(max_retries):
|
|
@@ -62,63 +76,59 @@ class GroqClient:
|
|
| 62 |
|
| 63 |
# 如果成功
|
| 64 |
if response.status_code == 200:
|
| 65 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
|
| 67 |
-
# 如果遇到 429 (太快了),休息久
|
| 68 |
if response.status_code == 429:
|
| 69 |
-
wait_time = (attempt + 1) *
|
| 70 |
-
print(f"⚠️ Rate limit (429). Waiting {wait_time}s...")
|
| 71 |
time.sleep(wait_time)
|
| 72 |
continue
|
| 73 |
|
| 74 |
-
|
|
|
|
| 75 |
|
| 76 |
except Exception as e:
|
| 77 |
print(f"Connection Error: {e}")
|
| 78 |
-
time.sleep(
|
| 79 |
|
| 80 |
-
return "
|
| 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
|
| 92 |
|
| 93 |
-
# 使用 Groq 的視覺模型
|
| 94 |
messages = [
|
| 95 |
{
|
| 96 |
"role": "user",
|
| 97 |
"content": [
|
| 98 |
-
{"type": "text", "text": f"
|
| 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
|
| 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")
|
|
@@ -150,18 +160,21 @@ def run_and_submit_all(profile: Optional[gr.OAuthProfile] = None):
|
|
| 150 |
# 核心:解題
|
| 151 |
ans = solve_question(q, client)
|
| 152 |
|
|
|
|
|
|
|
| 153 |
answers.append({"task_id": tid, "submitted_answer": ans})
|
| 154 |
-
logs.append({"Task": tid, "
|
| 155 |
|
| 156 |
-
# !!!
|
| 157 |
-
#
|
| 158 |
-
|
|
|
|
| 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 |
|
|
@@ -172,8 +185,8 @@ def run_and_submit_all(profile: Optional[gr.OAuthProfile] = None):
|
|
| 172 |
except Exception as e:
|
| 173 |
return f"Submit error: {str(e)}", pd.DataFrame(logs)
|
| 174 |
|
| 175 |
-
with gr.Blocks(title="Final Agent (
|
| 176 |
-
gr.Markdown("# 🚀 Final Agent (
|
| 177 |
with gr.Row():
|
| 178 |
gr.LoginButton()
|
| 179 |
btn = gr.Button("Run Evaluation", variant="primary")
|
|
|
|
| 20 |
|
| 21 |
def perform_search(query: str) -> str:
|
| 22 |
"""搜尋工具:只抓重點,並有隨機延遲"""
|
| 23 |
+
# 針對一些明顯的邏輯題,跳過搜尋以節省時間和 Token
|
| 24 |
+
if "reverse" in query.lower() or "tfel" in query.lower() or "python" in query.lower():
|
| 25 |
+
return ""
|
| 26 |
+
|
| 27 |
print(f"🕵️ Searching: {query[:50]}...")
|
| 28 |
try:
|
| 29 |
+
time.sleep(random.uniform(2.0, 4.0)) # 增加延遲
|
| 30 |
with DDGS() as ddgs:
|
| 31 |
results = list(ddgs.text(query, max_results=2, backend="lite"))
|
| 32 |
|
|
|
|
| 43 |
def __init__(self):
|
| 44 |
self.api_key = os.getenv("GROQ_API_KEY")
|
| 45 |
|
| 46 |
+
def query(self, messages, model, max_retries=5): # 增加重試次數到 5 次
|
| 47 |
+
"""發送請求給 Groq,包含超強自動重試機制"""
|
| 48 |
if not self.api_key:
|
| 49 |
return "Error: No API Key"
|
| 50 |
|
|
|
|
| 53 |
"Content-Type": "application/json"
|
| 54 |
}
|
| 55 |
|
| 56 |
+
# 針對這門課的特殊要求:強制簡潔
|
| 57 |
+
# 這是拿分的關鍵,避免模型講廢話
|
| 58 |
+
system_instruction = {
|
| 59 |
+
"role": "system",
|
| 60 |
+
"content": "You are taking a test. Provide ONLY the exact answer. No sentences, no punctuation, no explanations. Example: if the answer is 5, output '5'. If the answer is Paris, output 'Paris'."
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
# 確保 system instruction 在最前面
|
| 64 |
+
final_messages = [system_instruction] + messages
|
| 65 |
+
|
| 66 |
payload = {
|
| 67 |
"model": model,
|
| 68 |
+
"messages": final_messages,
|
| 69 |
"temperature": 0.1,
|
| 70 |
+
"max_tokens": 100 # 限制回答長度
|
| 71 |
}
|
| 72 |
|
| 73 |
for attempt in range(max_retries):
|
|
|
|
| 76 |
|
| 77 |
# 如果成功
|
| 78 |
if response.status_code == 200:
|
| 79 |
+
content = response.json()['choices'][0]['message']['content'].strip()
|
| 80 |
+
# 移除最後的句號 (常見錯誤)
|
| 81 |
+
if content.endswith('.'):
|
| 82 |
+
content = content[:-1]
|
| 83 |
+
return content
|
| 84 |
|
| 85 |
+
# 如果遇到 429 (太快了),休息很久再試
|
| 86 |
if response.status_code == 429:
|
| 87 |
+
wait_time = (attempt + 1) * 20 # 20s, 40s, 60s, 80s, 100s
|
| 88 |
+
print(f"⚠️ Rate limit (429). Waiting {wait_time}s... (Attempt {attempt+1}/{max_retries})")
|
| 89 |
time.sleep(wait_time)
|
| 90 |
continue
|
| 91 |
|
| 92 |
+
print(f"API Error {response.status_code}: {response.text[:100]}")
|
| 93 |
+
return f"Error"
|
| 94 |
|
| 95 |
except Exception as e:
|
| 96 |
print(f"Connection Error: {e}")
|
| 97 |
+
time.sleep(10)
|
| 98 |
|
| 99 |
+
return "Error"
|
| 100 |
|
| 101 |
def solve_question(question, client):
|
| 102 |
"""分析題目類型並選擇策略"""
|
| 103 |
|
| 104 |
# 1. 檢查是否有圖片網址 (Vision 任務)
|
|
|
|
| 105 |
img_match = re.search(r'(https?://[^\s]+\.(?:jpg|jpeg|png|webp))', question)
|
| 106 |
|
| 107 |
if img_match:
|
| 108 |
image_url = img_match.group(1)
|
| 109 |
+
print(f"👁️ Vision Task: {image_url}")
|
| 110 |
|
|
|
|
| 111 |
messages = [
|
| 112 |
{
|
| 113 |
"role": "user",
|
| 114 |
"content": [
|
| 115 |
+
{"type": "text", "text": f"What is the answer to this question? {question}"},
|
| 116 |
{"type": "image_url", "image_url": {"url": image_url}}
|
| 117 |
]
|
| 118 |
}
|
| 119 |
]
|
|
|
|
| 120 |
return client.query(messages, model="llama-3.2-11b-vision-preview")
|
| 121 |
|
| 122 |
else:
|
| 123 |
# 2. 一般文字/搜尋任務
|
|
|
|
| 124 |
context = perform_search(question)
|
| 125 |
|
|
|
|
|
|
|
| 126 |
if context:
|
| 127 |
+
user_msg = f"Context from search:\n{context}\n\nQuestion: {question}\nAnswer:"
|
| 128 |
else:
|
| 129 |
+
user_msg = f"Question: {question}\nAnswer:"
|
| 130 |
|
| 131 |
+
messages = [{"role": "user", "content": user_msg}]
|
|
|
|
|
|
|
|
|
|
| 132 |
|
| 133 |
# 使用最強的文字模型
|
| 134 |
return client.query(messages, model="llama-3.3-70b-versatile")
|
|
|
|
| 160 |
# 核心:解題
|
| 161 |
ans = solve_question(q, client)
|
| 162 |
|
| 163 |
+
print(f"✅ Answer: {ans}") # 在 Log 顯示答案確認
|
| 164 |
+
|
| 165 |
answers.append({"task_id": tid, "submitted_answer": ans})
|
| 166 |
+
logs.append({"Task": tid, "Answer": str(ans)[:100]})
|
| 167 |
|
| 168 |
+
# !!! 強制休息 10 秒 !!!
|
| 169 |
+
# 這是為了確保下一題不會立刻觸發 429
|
| 170 |
+
print("💤 Sleeping 10s to respect rate limits...")
|
| 171 |
+
time.sleep(10)
|
| 172 |
|
| 173 |
try:
|
| 174 |
print("Submitting...")
|
| 175 |
res = requests.post(f"{DEFAULT_API_URL}/submit", json={
|
| 176 |
"username": profile.username,
|
| 177 |
+
"agent_code": "https://huggingface.co/spaces/test/test",
|
| 178 |
"answers": answers
|
| 179 |
}, timeout=60)
|
| 180 |
|
|
|
|
| 185 |
except Exception as e:
|
| 186 |
return f"Submit error: {str(e)}", pd.DataFrame(logs)
|
| 187 |
|
| 188 |
+
with gr.Blocks(title="Final Agent (Anti-429 v2)") as demo:
|
| 189 |
+
gr.Markdown("# 🚀 Final Agent (Strict Format + Slow Mode)")
|
| 190 |
with gr.Row():
|
| 191 |
gr.LoginButton()
|
| 192 |
btn = gr.Button("Run Evaluation", variant="primary")
|