Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -1290,7 +1290,124 @@ async def type_text(request: dict, token: str = Depends(verify_token)):
|
|
| 1290 |
except:
|
| 1291 |
raise HTTPException(status_code=500, detail=str(e))
|
| 1292 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1293 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1294 |
# ============================================================
|
| 1295 |
# SEARCH SITE
|
| 1296 |
# ============================================================
|
|
|
|
| 1290 |
except:
|
| 1291 |
raise HTTPException(status_code=500, detail=str(e))
|
| 1292 |
|
| 1293 |
+
# ===================== CLICK ELEMENT =====================
|
| 1294 |
+
@app.post("/click-element")
|
| 1295 |
+
async def click_element(request: dict, token: str = Depends(verify_token)):
|
| 1296 |
+
"""Click at specific coordinates on the page"""
|
| 1297 |
+
try:
|
| 1298 |
+
session_id = request.get("session_id")
|
| 1299 |
+
x = request.get("x", 0)
|
| 1300 |
+
y = request.get("y", 0)
|
| 1301 |
+
img_width = request.get("img_width", 1920)
|
| 1302 |
+
img_height = request.get("img_height", 1080)
|
| 1303 |
|
| 1304 |
+
session = session_manager.get_session(session_id)
|
| 1305 |
+
if not session:
|
| 1306 |
+
raise HTTPException(status_code=404, detail="Sessao nao encontrada")
|
| 1307 |
+
|
| 1308 |
+
driver = session["driver"]
|
| 1309 |
+
|
| 1310 |
+
# Recuperar janela ativa
|
| 1311 |
+
try:
|
| 1312 |
+
handles = driver.window_handles
|
| 1313 |
+
if handles:
|
| 1314 |
+
driver.switch_to.window(handles[-1])
|
| 1315 |
+
except Exception:
|
| 1316 |
+
pass
|
| 1317 |
+
|
| 1318 |
+
# Obter tamanho real da viewport do Selenium
|
| 1319 |
+
viewport_width = driver.execute_script("return window.innerWidth;")
|
| 1320 |
+
viewport_height = driver.execute_script("return window.innerHeight;")
|
| 1321 |
+
|
| 1322 |
+
# Escalar coordenadas da imagem de preview para a viewport real
|
| 1323 |
+
actual_x = int(x * viewport_width / img_width) if img_width > 0 else int(x)
|
| 1324 |
+
actual_y = int(y * viewport_height / img_height) if img_height > 0 else int(y)
|
| 1325 |
+
|
| 1326 |
+
# Garantir limites
|
| 1327 |
+
actual_x = max(0, min(actual_x, viewport_width - 1))
|
| 1328 |
+
actual_y = max(0, min(actual_y, viewport_height - 1))
|
| 1329 |
+
|
| 1330 |
+
logger.info(f"Click: preview({x},{y}) img({img_width}x{img_height}) -> real({actual_x},{actual_y}) viewport({viewport_width}x{viewport_height})")
|
| 1331 |
+
|
| 1332 |
+
# Detectar elemento antes do clique
|
| 1333 |
+
element_info = driver.execute_script(f"""
|
| 1334 |
+
var elem = document.elementFromPoint({actual_x}, {actual_y});
|
| 1335 |
+
if (elem) {{
|
| 1336 |
+
return {{
|
| 1337 |
+
tagName: elem.tagName || '',
|
| 1338 |
+
id: elem.id || '',
|
| 1339 |
+
text: (elem.textContent || '').substring(0, 100).trim(),
|
| 1340 |
+
type: elem.type || '',
|
| 1341 |
+
href: elem.href || '',
|
| 1342 |
+
className: (elem.className || '').substring(0, 100)
|
| 1343 |
+
}};
|
| 1344 |
+
}}
|
| 1345 |
+
return null;
|
| 1346 |
+
""")
|
| 1347 |
+
|
| 1348 |
+
# Clicar via JavaScript (mais confiavel que ActionChains)
|
| 1349 |
+
driver.execute_script(f"""
|
| 1350 |
+
var elem = document.elementFromPoint({actual_x}, {actual_y});
|
| 1351 |
+
if (elem) {{
|
| 1352 |
+
elem.scrollIntoView({{block: 'nearest'}});
|
| 1353 |
+
elem.click();
|
| 1354 |
+
}} else {{
|
| 1355 |
+
var evt = new MouseEvent('click', {{
|
| 1356 |
+
bubbles: true,
|
| 1357 |
+
cancelable: true,
|
| 1358 |
+
clientX: {actual_x},
|
| 1359 |
+
clientY: {actual_y},
|
| 1360 |
+
view: window
|
| 1361 |
+
}});
|
| 1362 |
+
document.elementFromPoint({actual_x}, {actual_y})?.dispatchEvent(evt);
|
| 1363 |
+
}}
|
| 1364 |
+
""")
|
| 1365 |
+
|
| 1366 |
+
import time
|
| 1367 |
+
time.sleep(2)
|
| 1368 |
+
|
| 1369 |
+
# Recuperar janela caso tenha mudado
|
| 1370 |
+
try:
|
| 1371 |
+
handles = driver.window_handles
|
| 1372 |
+
if handles:
|
| 1373 |
+
driver.switch_to.window(handles[-1])
|
| 1374 |
+
except Exception:
|
| 1375 |
+
pass
|
| 1376 |
+
|
| 1377 |
+
# Screenshot
|
| 1378 |
+
screenshot = None
|
| 1379 |
+
try:
|
| 1380 |
+
screenshot = driver.get_screenshot_as_base64()
|
| 1381 |
+
except Exception:
|
| 1382 |
+
pass
|
| 1383 |
+
|
| 1384 |
+
current_url = ""
|
| 1385 |
+
title = ""
|
| 1386 |
+
try:
|
| 1387 |
+
current_url = driver.current_url
|
| 1388 |
+
title = driver.title
|
| 1389 |
+
except Exception:
|
| 1390 |
+
pass
|
| 1391 |
+
|
| 1392 |
+
session["last_url"] = current_url
|
| 1393 |
+
session["last_activity"] = time.time()
|
| 1394 |
+
|
| 1395 |
+
return {
|
| 1396 |
+
"success": True,
|
| 1397 |
+
"message": f"Clique em ({actual_x}, {actual_y})",
|
| 1398 |
+
"clicked": element_info,
|
| 1399 |
+
"element": f"{element_info.get('tagName', '')}: {element_info.get('text', '')}" if element_info else "Nenhum elemento",
|
| 1400 |
+
"url": current_url,
|
| 1401 |
+
"current_url": current_url,
|
| 1402 |
+
"title": title,
|
| 1403 |
+
"screenshot": screenshot
|
| 1404 |
+
}
|
| 1405 |
+
|
| 1406 |
+
except HTTPException:
|
| 1407 |
+
raise
|
| 1408 |
+
except Exception as e:
|
| 1409 |
+
logger.error(f"Erro no clique: {e}")
|
| 1410 |
+
return {"success": False, "message": str(e), "screenshot": None}
|
| 1411 |
# ============================================================
|
| 1412 |
# SEARCH SITE
|
| 1413 |
# ============================================================
|