Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -62,15 +62,18 @@ MOCK_ANSWERS = {
|
|
| 62 |
# --- Task Handlers ---
|
| 63 |
def handle_grocery_list(question: str) -> str:
|
| 64 |
logger.info("Handling grocery list task")
|
| 65 |
-
|
|
|
|
| 66 |
if not match:
|
| 67 |
logger.error("Failed to extract grocery list")
|
| 68 |
return "Error: Invalid input"
|
| 69 |
items = match.group(1).strip()
|
|
|
|
| 70 |
botanical_fruits = [
|
| 71 |
"bell pepper", "zucchini", "corn", "plums", "cucumber", "tomato",
|
| 72 |
"eggplant", "pumpkin", "squash", "avocado", "olive"
|
| 73 |
]
|
|
|
|
| 74 |
vegetables = [
|
| 75 |
item.strip().lower() for item in items.split(',')
|
| 76 |
if item.strip().lower() not in botanical_fruits and any(
|
|
@@ -82,27 +85,33 @@ def handle_grocery_list(question: str) -> str:
|
|
| 82 |
]
|
| 83 |
vegetables = sorted(vegetables)
|
| 84 |
result = ','.join(vegetables) if vegetables else "None"
|
| 85 |
-
logger.info(f"
|
| 86 |
-
#
|
| 87 |
rate_limiter.acquire()
|
| 88 |
@backoff.on_exception(backoff.expo, Exception, max_tries=3)
|
| 89 |
def groq_format():
|
| 90 |
client = Groq(api_key=GROQ_API_KEY)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
response = client.chat.completions.create(
|
| 92 |
model="llama-3.3-70b-versatile",
|
| 93 |
-
messages=[{
|
| 94 |
-
"role": "user",
|
| 95 |
-
"content": f"Return the input as a comma-separated list with no spaces, no extra characters, and exact item names: {result}"
|
| 96 |
-
}],
|
| 97 |
temperature=0
|
| 98 |
)
|
| 99 |
formatted = response.choices[0].message.content.strip()
|
| 100 |
-
debug_log.append({"task_id": "8e867cd7-cff9-4e6c-867a-ff5ddc2550be", "groq_response": formatted})
|
| 101 |
# Validate response
|
| 102 |
-
if len(formatted) > 100 or any(c in formatted for c in '|;'):
|
| 103 |
logger.error(f"Invalid Groq response: {formatted}")
|
| 104 |
return result
|
| 105 |
-
|
|
|
|
|
|
|
|
|
|
| 106 |
return formatted
|
| 107 |
try:
|
| 108 |
return groq_format()
|
|
@@ -118,25 +127,37 @@ def handle_sales(file_path: str) -> str:
|
|
| 118 |
try:
|
| 119 |
df = pd.read_excel(file_path)
|
| 120 |
logger.info(f"Excel columns: {list(df.columns)}")
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
|
|
|
|
|
|
|
|
|
| 124 |
return "Error: Missing 'category' or 'sales' columns"
|
| 125 |
-
food_sales = df[df[
|
| 126 |
result = f"{food_sales:.2f}"
|
| 127 |
logger.info(f"Sales result: {result}")
|
| 128 |
rate_limiter.acquire()
|
| 129 |
@backoff.on_exception(backoff.expo, Exception, max_tries=3)
|
| 130 |
def groq_format():
|
| 131 |
client = Groq(api_key=GROQ_API_KEY)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
response = client.chat.completions.create(
|
| 133 |
model="llama-3.3-70b-versatile",
|
| 134 |
-
messages=[{"role": "user", "content":
|
| 135 |
temperature=0
|
| 136 |
)
|
| 137 |
formatted = response.choices[0].message.content.strip()
|
| 138 |
-
debug_log.append({"task_id": "7bd855d8-463d-4ed5-93ca-5fe35145f733", "groq_response": formatted})
|
| 139 |
-
|
|
|
|
|
|
|
|
|
|
| 140 |
return formatted
|
| 141 |
try:
|
| 142 |
return groq_format()
|
|
@@ -156,14 +177,23 @@ def handle_web(task_id: str, question: str) -> str:
|
|
| 156 |
@backoff.on_exception(backoff.expo, Exception, max_tries=3)
|
| 157 |
def groq_validate():
|
| 158 |
client = Groq(api_key=GROQ_API_KEY)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 159 |
response = client.chat.completions.create(
|
| 160 |
model="llama-3.3-70b-versatile",
|
| 161 |
-
messages=[{"role": "user", "content":
|
| 162 |
temperature=0
|
| 163 |
)
|
| 164 |
formatted = response.choices[0].message.content.strip()
|
| 165 |
-
debug_log.append({"task_id": task_id, "groq_response": formatted})
|
| 166 |
-
|
|
|
|
|
|
|
|
|
|
| 167 |
return formatted
|
| 168 |
try:
|
| 169 |
return groq_validate()
|
|
@@ -183,6 +213,7 @@ TASK_HANDLERS = {
|
|
| 183 |
}
|
| 184 |
|
| 185 |
# --- File Download ---
|
|
|
|
| 186 |
def download_file_if_any(base_api_url: str, task_id: str) -> Optional[str]:
|
| 187 |
if task_id != "7bd855d8-463d-4ed5-93ca-5fe35145f733":
|
| 188 |
logger.info(f"No file needed for task_id: {task_id}")
|
|
@@ -196,7 +227,7 @@ def download_file_if_any(base_api_url: str, task_id: str) -> Optional[str]:
|
|
| 196 |
return None
|
| 197 |
resp.raise_for_status()
|
| 198 |
cdisp = resp.headers.get("content-disposition", "")
|
| 199 |
-
filename = task_id
|
| 200 |
if "filename=" in cdisp:
|
| 201 |
m = re.search(r'filename="([^"]+)"', cdisp)
|
| 202 |
if m:
|
|
@@ -214,12 +245,12 @@ def download_file_if_any(base_api_url: str, task_id: str) -> Optional[str]:
|
|
| 214 |
|
| 215 |
# --- Answer Formatter ---
|
| 216 |
def format_answer(answer: str, task_id: str) -> str:
|
| 217 |
-
space_preserved_tasks = ["3cef3a44-215e-4aed-8e3b-b1e3f08063b7", "99c9cc74-fdc8-46c6-8f8d-3ce2d3bfeea3"]
|
| 218 |
answer = answer.strip()
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
|
|
|
|
| 223 |
logger.info(f"Formatted answer for task_id {task_id}: {answer}")
|
| 224 |
return answer
|
| 225 |
|
|
@@ -263,20 +294,25 @@ class GroqAgent:
|
|
| 263 |
rate_limiter.acquire()
|
| 264 |
@backoff.on_exception(backoff.expo, Exception, max_tries=3)
|
| 265 |
def groq_fallback():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 266 |
response = self.client.chat.completions.create(
|
| 267 |
model="llama-3.3-70b-versatile",
|
| 268 |
-
messages=[{"role": "user", "content":
|
| 269 |
temperature=0
|
| 270 |
)
|
| 271 |
result = response.choices[0].message.content.strip()
|
| 272 |
-
debug_log.append({"task_id": task_id, "groq_response": result})
|
| 273 |
-
logger.info(f"Groq
|
| 274 |
return result
|
| 275 |
try:
|
| 276 |
result = groq_fallback()
|
| 277 |
return format_answer(result, task_id)
|
| 278 |
except Exception as e:
|
| 279 |
-
logger.error(f"Groq error for
|
| 280 |
return format_answer(MOCK_ANSWERS.get(task_id, "Error"), task_id)
|
| 281 |
file_path = download_file_if_any(DEFAULT_API_URL, task_id)
|
| 282 |
try:
|
|
|
|
| 62 |
# --- Task Handlers ---
|
| 63 |
def handle_grocery_list(question: str) -> str:
|
| 64 |
logger.info("Handling grocery list task")
|
| 65 |
+
# Extract items
|
| 66 |
+
match = re.search(r'list\s*[:\s]*([^.]+)', question, re.IGNORECASE)
|
| 67 |
if not match:
|
| 68 |
logger.error("Failed to extract grocery list")
|
| 69 |
return "Error: Invalid input"
|
| 70 |
items = match.group(1).strip()
|
| 71 |
+
# Define botanical fruits
|
| 72 |
botanical_fruits = [
|
| 73 |
"bell pepper", "zucchini", "corn", "plums", "cucumber", "tomato",
|
| 74 |
"eggplant", "pumpkin", "squash", "avocado", "olive"
|
| 75 |
]
|
| 76 |
+
# Filter vegetables
|
| 77 |
vegetables = [
|
| 78 |
item.strip().lower() for item in items.split(',')
|
| 79 |
if item.strip().lower() not in botanical_fruits and any(
|
|
|
|
| 85 |
]
|
| 86 |
vegetables = sorted(vegetables)
|
| 87 |
result = ','.join(vegetables) if vegetables else "None"
|
| 88 |
+
logger.info(f"Raw grocery list result: {result}")
|
| 89 |
+
# Use Groq for formatting
|
| 90 |
rate_limiter.acquire()
|
| 91 |
@backoff.on_exception(backoff.expo, Exception, max_tries=3)
|
| 92 |
def groq_format():
|
| 93 |
client = Groq(api_key=GROQ_API_KEY)
|
| 94 |
+
prompt = f"""
|
| 95 |
+
Format the following list as a comma-separated string with no spaces, no extra characters, and exact item names in alphabetical order:
|
| 96 |
+
Input: {result}
|
| 97 |
+
Example: broccoli,carrot,lettuce
|
| 98 |
+
Output: {result}
|
| 99 |
+
"""
|
| 100 |
response = client.chat.completions.create(
|
| 101 |
model="llama-3.3-70b-versatile",
|
| 102 |
+
messages=[{"role": "user", "content": prompt}],
|
|
|
|
|
|
|
|
|
|
| 103 |
temperature=0
|
| 104 |
)
|
| 105 |
formatted = response.choices[0].message.content.strip()
|
| 106 |
+
debug_log.append({"task_id": "8e867cd7-cff9-4e6c-867a-ff5ddc2550be", "groq_prompt": prompt, "groq_response": formatted})
|
| 107 |
# Validate response
|
| 108 |
+
if len(formatted) > 100 or any(c in formatted for c in ':|;'):
|
| 109 |
logger.error(f"Invalid Groq response: {formatted}")
|
| 110 |
return result
|
| 111 |
+
if not re.match(r'^[a-z,]+$', formatted):
|
| 112 |
+
logger.error(f"Groq response format incorrect: {formatted}")
|
| 113 |
+
return result
|
| 114 |
+
logger.info(f"Groq formatted result: {formatted}")
|
| 115 |
return formatted
|
| 116 |
try:
|
| 117 |
return groq_format()
|
|
|
|
| 127 |
try:
|
| 128 |
df = pd.read_excel(file_path)
|
| 129 |
logger.info(f"Excel columns: {list(df.columns)}")
|
| 130 |
+
# Case-insensitive column search
|
| 131 |
+
df.columns = [col.lower().strip() for col in df.columns]
|
| 132 |
+
category_col = next((col for col in df.columns if 'category' in col), None)
|
| 133 |
+
sales_col = next((col for col in df.columns if 'sales' in col), None)
|
| 134 |
+
if not category_col or not sales_col:
|
| 135 |
+
logger.error(f"Columns missing: category={category_col}, sales={sales_col}")
|
| 136 |
return "Error: Missing 'category' or 'sales' columns"
|
| 137 |
+
food_sales = df[df[category_col].str.lower() == 'food'][sales_col].sum()
|
| 138 |
result = f"{food_sales:.2f}"
|
| 139 |
logger.info(f"Sales result: {result}")
|
| 140 |
rate_limiter.acquire()
|
| 141 |
@backoff.on_exception(backoff.expo, Exception, max_tries=3)
|
| 142 |
def groq_format():
|
| 143 |
client = Groq(api_key=GROQ_API_KEY)
|
| 144 |
+
prompt = f"""
|
| 145 |
+
Format the number as a string with two decimal places, no extra characters:
|
| 146 |
+
Input: {result}
|
| 147 |
+
Example: 1234.56
|
| 148 |
+
Output: {result}
|
| 149 |
+
"""
|
| 150 |
response = client.chat.completions.create(
|
| 151 |
model="llama-3.3-70b-versatile",
|
| 152 |
+
messages=[{"role": "user", "content": prompt}],
|
| 153 |
temperature=0
|
| 154 |
)
|
| 155 |
formatted = response.choices[0].message.content.strip()
|
| 156 |
+
debug_log.append({"task_id": "7bd855d8-463d-4ed5-93ca-5fe35145f733", "groq_prompt": prompt, "groq_response": formatted})
|
| 157 |
+
if not re.match(r'^\d+\.\d{2}$', formatted):
|
| 158 |
+
logger.error(f"Invalid Groq sales format: {formatted}")
|
| 159 |
+
return result
|
| 160 |
+
logger.info(f"Groq formatted sales: {formatted}")
|
| 161 |
return formatted
|
| 162 |
try:
|
| 163 |
return groq_format()
|
|
|
|
| 177 |
@backoff.on_exception(backoff.expo, Exception, max_tries=3)
|
| 178 |
def groq_validate():
|
| 179 |
client = Groq(api_key=GROQ_API_KEY)
|
| 180 |
+
prompt = f"""
|
| 181 |
+
Return the input exactly as provided, no extra characters, no spaces:
|
| 182 |
+
Input: {result}
|
| 183 |
+
Example: Input: John,Doe Output: John,Doe
|
| 184 |
+
Output: {result}
|
| 185 |
+
"""
|
| 186 |
response = client.chat.completions.create(
|
| 187 |
model="llama-3.3-70b-versatile",
|
| 188 |
+
messages=[{"role": "user", "content": prompt}],
|
| 189 |
temperature=0
|
| 190 |
)
|
| 191 |
formatted = response.choices[0].message.content.strip()
|
| 192 |
+
debug_log.append({"task_id": task_id, "groq_prompt": prompt, "groq_response": formatted})
|
| 193 |
+
if formatted != result:
|
| 194 |
+
logger.error(f"Groq altered web task output: {formatted}")
|
| 195 |
+
return result
|
| 196 |
+
logger.info(f"Groq validated web task {task_id}: {formatted}")
|
| 197 |
return formatted
|
| 198 |
try:
|
| 199 |
return groq_validate()
|
|
|
|
| 213 |
}
|
| 214 |
|
| 215 |
# --- File Download ---
|
| 216 |
+
@backoff.on_exception(backoff.expo, RequestException, max_tries=3)
|
| 217 |
def download_file_if_any(base_api_url: str, task_id: str) -> Optional[str]:
|
| 218 |
if task_id != "7bd855d8-463d-4ed5-93ca-5fe35145f733":
|
| 219 |
logger.info(f"No file needed for task_id: {task_id}")
|
|
|
|
| 227 |
return None
|
| 228 |
resp.raise_for_status()
|
| 229 |
cdisp = resp.headers.get("content-disposition", "")
|
| 230 |
+
filename = task_id + ".xlsx"
|
| 231 |
if "filename=" in cdisp:
|
| 232 |
m = re.search(r'filename="([^"]+)"', cdisp)
|
| 233 |
if m:
|
|
|
|
| 245 |
|
| 246 |
# --- Answer Formatter ---
|
| 247 |
def format_answer(answer: str, task_id: str) -> str:
|
|
|
|
| 248 |
answer = answer.strip()
|
| 249 |
+
# Strict formatting: remove spaces, non-alphanumeric except commas/periods
|
| 250 |
+
answer = re.sub(r'\s+', '', answer)
|
| 251 |
+
answer = re.sub(r'[^a-zA-Z0-9,.]', '', answer)
|
| 252 |
+
# Ensure no trailing commas or periods
|
| 253 |
+
answer = answer.rstrip(',.')
|
| 254 |
logger.info(f"Formatted answer for task_id {task_id}: {answer}")
|
| 255 |
return answer
|
| 256 |
|
|
|
|
| 294 |
rate_limiter.acquire()
|
| 295 |
@backoff.on_exception(backoff.expo, Exception, max_tries=3)
|
| 296 |
def groq_fallback():
|
| 297 |
+
prompt = f"""
|
| 298 |
+
Answer in a single value or comma-separated list, no spaces, no extra characters:
|
| 299 |
+
Question: {question[:500]}
|
| 300 |
+
Example: apple,banana or 123.45
|
| 301 |
+
"""
|
| 302 |
response = self.client.chat.completions.create(
|
| 303 |
model="llama-3.3-70b-versatile",
|
| 304 |
+
messages=[{"role": "user", "content": prompt}],
|
| 305 |
temperature=0
|
| 306 |
)
|
| 307 |
result = response.choices[0].message.content.strip()
|
| 308 |
+
debug_log.append({"task_id": task_id, "groq_prompt": prompt, "groq_response": result})
|
| 309 |
+
logger.info(f"Groq fallback result for {task_id}: {result}")
|
| 310 |
return result
|
| 311 |
try:
|
| 312 |
result = groq_fallback()
|
| 313 |
return format_answer(result, task_id)
|
| 314 |
except Exception as e:
|
| 315 |
+
logger.error(f"Groq fallback error for task_id {task_id}: {e}")
|
| 316 |
return format_answer(MOCK_ANSWERS.get(task_id, "Error"), task_id)
|
| 317 |
file_path = download_file_if_any(DEFAULT_API_URL, task_id)
|
| 318 |
try:
|