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
    }