File size: 6,536 Bytes
be3cb04 583face be3cb04 583face be3cb04 583face be3cb04 583face be3cb04 583face be3cb04 583face be3cb04 583face be3cb04 583face be3cb04 583face be3cb04 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
"""
Stealth Browser Agent - Persistent Session with Visible Browser
================================================================
Uses browser-use with headless=False for VNC visibility.
Maintains a persistent browser session for efficiency.
"""
import os
import logging
from typing import Dict, Any, Optional
from dotenv import load_dotenv
load_dotenv()
# Set OPENAI_API_KEY for browser_use compatibility
if os.getenv("OPENROUTER_API_KEY") and not os.getenv("OPENAI_API_KEY"):
os.environ["OPENAI_API_KEY"] = os.getenv("OPENROUTER_API_KEY")
from langchain_openai import ChatOpenAI
from browser_use import Agent, Controller, Browser
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
controller = Controller()
class BrowserSession:
"""Persistent browser session for efficiency."""
def __init__(self, browser: Browser):
self.browser = browser
self.is_active = True
@classmethod
async def create(cls) -> "BrowserSession":
"""Create a new persistent browser session."""
logger.info(f"π₯οΈ Creating browser on display {os.environ.get('DISPLAY', ':99')}")
browser = Browser(headless=False)
return cls(browser)
async def close(self):
"""Close the browser session."""
if self.browser:
try:
await self.browser.close()
except:
pass
self.is_active = False
async def validate_order(order_data: Dict[str, Any], session: Optional[BrowserSession] = None) -> Dict[str, Any]:
"""Validates order with VISIBLE browser - watch via Cloudflare tunnel!"""
logger.info(f"π Starting validation - WATCH VIA CLOUDFLARE TUNNEL!")
logs = []
def log(msg):
logger.info(msg)
logs.append(msg)
email = order_data.get('email', '')
phone = order_data.get('phone', '')
zip_code = order_data.get('zip', '')
city = order_data.get('city', '')
state = order_data.get('state', '')
task_id = order_data.get('task_id', 'unknown')
log(f"π§ Email: {email}")
log(f"π Phone: {phone}")
log(f"π Geo: {zip_code}, {city}, {state}")
log(f"πΊ Display: {os.environ.get('DISPLAY', 'NOT SET')} - VISIBLE MODE!")
task = f"""
You are a Validation Expert. Perform these 3 steps:
STEP 1: EMAIL VALIDATION (Browser)
- Go to 'https://email-checker.net/'
- Input '{email}' and check result.
- Extract: 'Valid', 'Invalid', or 'Risky'.
STEP 2: PHONE VALIDATION (Browser)
- Use a phone validator tool.
- Input '{phone}' and check status.
STEP 3: GEO VALIDATION (Internal Knowledge ONLY)
- Does Zip '{zip_code}' belong to City '{city}' in State '{state}'?
- Return 'Match' or 'Mismatch'.
OUTPUT JSON:
{{
"email_status": "Valid/Invalid/Risky",
"phone_status": "Valid/Invalid",
"geo_match": true/false,
"summary": "explanation"
}}
"""
api_key = os.getenv("OPENROUTER_API_KEY")
base_url = "https://openrouter.ai/api/v1"
if not api_key:
return {"task_id": task_id, "decision": "UNKNOWN", "error": "No API key", "logs": logs}
llm_primary = ChatOpenAI(
model="nvidia/nemotron-nano-12b-v2-vl:free",
api_key=api_key,
base_url=base_url,
temperature=0.1,
default_headers={"HTTP-Referer": "https://altyzen.com", "X-Title": "Altyzen Stealth Worker"}
)
llm_fallback = ChatOpenAI(
model="google/gemini-2.0-flash-exp:free",
api_key=api_key,
base_url=base_url,
temperature=0.1,
default_headers={"HTTP-Referer": "https://altyzen.com", "X-Title": "Altyzen Stealth Worker"}
)
# Use persistent session or create new browser
browser = session.browser if session and session.is_active else Browser(headless=False)
owns_browser = session is None or not session.is_active
result = None
try:
log("π€ Attempt 1: Using Nvidia Nemotron...")
agent = Agent(task=task, llm=llm_primary, browser=browser, controller=controller, use_vision=True, validate_output=False)
history = await agent.run()
result = history.final_result()
log("β
Nvidia Nemotron completed!")
except Exception as e:
log(f"β οΈ Primary failed: {str(e)[:100]}")
log("π Switching to Gemini fallback...")
try:
agent = Agent(task=task, llm=llm_fallback, browser=browser, controller=controller, use_vision=True, validate_output=False)
history = await agent.run()
result = history.final_result()
log("β
Gemini completed!")
except Exception as fallback_err:
log(f"β Fallback also failed: {str(fallback_err)[:100]}")
result = None
# Only close if we created the browser
if owns_browser:
try:
await browser.close()
log("π Browser closed")
except:
pass
parsed = _parse_result(result, order_data)
parsed["logs"] = logs
parsed["task_id"] = task_id
return parsed
def _parse_result(result, order_data):
import json
if result is None:
return {"decision": "UNKNOWN", "email_valid": False, "phone_valid": False, "geo_valid": False, "reasoning": "All models failed"}
parsed = {}
if isinstance(result, str):
try:
if "{" in result:
json_start = result.find("{")
json_end = result.rfind("}") + 1
parsed = json.loads(result[json_start:json_end])
except:
parsed = {"raw": result}
elif isinstance(result, dict):
parsed = result
email_valid = "valid" in str(parsed.get("email_status", "")).lower() and "invalid" not in str(parsed.get("email_status", "")).lower()
phone_valid = "valid" in str(parsed.get("phone_status", "")).lower() and "invalid" not in str(parsed.get("phone_status", "")).lower()
geo_valid = parsed.get("geo_match", False) if isinstance(parsed.get("geo_match"), bool) else str(parsed.get("geo_match", "")).lower() == "true"
decision = "APPROVED" if email_valid and phone_valid and geo_valid else "BLOCKED"
return {
"order_id": order_data.get("order_id", "UNKNOWN"),
"decision": decision,
"email_valid": email_valid,
"phone_valid": phone_valid,
"geo_valid": geo_valid,
"reasoning": parsed.get("summary", "Validation completed"),
"raw_result": parsed
}
|