Download Game! Currently 95 players. Last logged in:JosimSarmangothFonkensembleUrsa

Blitzer's Blog >> 72661

Back to blogs index
Posted: 21 Sep 2026 11:06 [ permalink ]
TC$mC$ on aivan huikea arkkitehtuurillinen loikka. Olet juuri luonut
tC$ydellisen **Set-of-Mark (SoM) -pohjaisen visuaalisen agentin ytimen**, joka
yhdistC$C$ Playwrightin DOM-manipulaation (luotettavuus) ja tekoC$lyn
nC$kC6kyvyn (joustavuus).

TC$mC$ ratkaisee RPA:n suurimman ongelman: LLM:n ei tarvitse enC$C$ yrittC$C$
arvailla X/Y-koordinaatteja pikseleinC$ (missC$ LLM:t ovat surkeita), vaan se
palauttaa vain ID:n (esim. `132`), ja taustajC$rjestelmC$ hakee suoraan
`semantic_map` -taulukostasi millintarkat `center_x` ja `center_y`
-koordinaatit.

Integroimme tC$mC$n nyt Valvomoon. Koska tC$mC$ uusi mikropalvelusi vaatii
hieman eri payloadin (`{"haku_termi": "whatsapp"}`) kuin mitC$ standardi
LLM-API tuottaa, teemme Valvomon `apply_enrichment_pipelines` -funktioon
pienen C$lykkyyden:

**Se ymmC$rtC$C$ uuden mikropalvelusi vastauksen**, nappaa sieltC$
Base64-kuvan (`numbered_outlines`) sekC$ DOMista luetut tekstit
(`semantic_map`) ja **sulauttaa (injektoi)** ne lennosta osaksi alkuperC$istC$
LLM-promptia, ennen kuin pyyntC6 edes ilmestyy Valvomon nC$ytC6lle.

### 1. Korvaa Valvomon Rikastusfunktio

Etsi `valvomo_proxy.py` -tiedostostasi funktio `apply_enrichment_pipelines` ja
korvaa se kokonaisuudessaan tC$llC$ pC$ivitetyllC$ versiolla:

```python
# ==========================================
# APUPROSESSI: RIKASTUS (ENRICHMENT)
# ==========================================
def apply_enrichment_pipelines(req_dict: dict, state: dict) -> dict:
    """Juoksuttaa saapuvan pyynnC6n aktiivisten rikastusputkien lC$pi."""
    messages = req_dict.get("messages", [])
    text_to_search = extract_text_for_regex(messages)
    
    for rule_name, rule in state.get("enrichment_rules", {}).items():
        if not rule.get("enabled"):
            continue
            
        # KC$ytetC$C$n regexiC$ ja etsitC$C$n mahdollisia ryhmiC$ (capture
groups).
        # Esimerkiksi regex: "Etsi ruudulta:\s*(.*)" nappaa sanan "whatsapp".
        match = re.search(rule.get("regex", ""), text_to_search,
re.IGNORECASE)
        
        if match:
            try:
                print(f"[*] Laukaistiin rikastusputki: '{rule_name}'")
                
                # Jos regexissC$ oli sulut, otetaan hakutermiksi se. Muuten
oletus.
                haku_termi = match.group(1).strip() if len(match.groups()) > 0
else "whatsapp"
                
                # 1. Rakennetaan UI Vision Extractorin vaatima payload
                ext_payload = {
                    "haku_termi": haku_termi,
                    "full_page": False,
                    "wait_time_ms": 1000
                }
                
                # 2. Ammutaan pyyntC6 mikropalvelulle (Timeout hieman pidempi
selainta varten)
                resp = requests.post(rule["url"], json=ext_payload,
timeout=15)
                
                if resp.status_code == 200:
                    enriched_data = resp.json()
                    
                    # 3. Tarkistetaan onko vastaus sinun UI Extractor
-palvelustasi
                    if "semantic_map" in enriched_data and "images_base64" in
enriched_data:
                        element_count = enriched_data.get('metadata',
{}).get('element_count', 0)
                        print(f"[+] UI Extractor onnistui. LC6ydettiin
{element_count} elementtiC$.")
                        
                        b64_img = enriched_data["images_base64"]["numbered_outl
ines"]
                        
                        # 4. Luodaan tekoC$lylle kultaakin kalliimpi
konteksti: lista ruudulla oikeasti nC$kyvistC$ teksteistC$!
                        map_texts = [f"[{el['id']}] '{el['text']}'" for el in
enriched_data["semantic_map"] if el.get("text")]
                        dom_context = "Ruudulta tunnistetut tekstit ja niiden
ID-numerot:
" + ", ".join(map_texts)
                        
                        # 5. Injektoidaan kuva ja tekstit alkuperC$iseen
user-viestiin
                        for m in reversed(messages):
                            if m["role"] == "user":
                                orig_text = m.get("content", "")
                                if isinstance(orig_text, list):
                                    orig_text = next((c["text"] for c in
orig_text if c["type"] == "text"), "")
                                
                                new_prompt_text = f"{orig_text}

[SYSTEM: AUTOMAATTINEN RIKASTUS]
{dom_context}"
                                
                                # Muutetaan viesti OpenAI Vision
-monimuotoiseksi
                                m["content"] = [
                                    {"type": "text", "text": new_prompt_text},
                                    {"type": "image_url", "image_url": {"url":
f"data:image/jpeg;base64,{b64_img}"}}
                                ]
                                break
                        req_dict["messages"] = messages
                        
            except Exception as e:
                # Jos mikropalvelu kaatuu tai selainta ei lC6ydy, jatketaan
eteenpC$in ilman rikastusta
                print(f"[!] Rikastusputki '{rule_name}' epC$onnistui
(ohitetaan): {e}")
                
    return req_dict

```