DEV Community

Cover image for Building a Self-Healing, Type-Safe Desktop RPA with Python and Computer Vision
Ruesch Manny
Ruesch Manny

Posted on Originally published at mannyverse767.gumroad.com

Building a Self-Healing, Type-Safe Desktop RPA with Python and Computer Vision

Desktop automation has a dirty secret: it’s terrifyingly brittle. If you’ve ever written a script that relies on static X/Y coordinates, you know the pain. A Windows update changes a button's padding by 5 pixels, a user moves a window, or UI scaling shifts—and suddenly your bot is blindly clicking empty space.

Enterprise RPA platforms (UiPath, Automation Anywhere) solve this, but they charge extortionate licensing fees just to access basic computer vision capabilities. You shouldn't have to pay massive corporate subscriptions for your script to "see" what's on the screen.

Today, we are going to build a resilient, local, type-safe automation engine that executes workflows based on visual state and OCR, completely free of corporate bloat.

1. The Bottleneck: Why commercial solutions are overpriced or fragile

When dealing with legacy desktop applications or Citrix environments where there is no DOM to inspect, developers usually resort to two terrible options:

  1. Blind Coordinate Clicking: pyautogui.click(x=100, y=200). This breaks the second a window is resized.
  2. Enterprise RPA: Heavily bloated, vendor-locked IDEs that cost thousands per seat and require a PhD in their proprietary visual languages.

The alternative? A lightweight, Python-based pipeline utilizing Computer Vision (OpenCV) and OCR (Tesseract/LLMs) to dynamically detect UI elements, combined with strict type-safe bindings (Pydantic) to ensure our workflows only execute when the application is in the exact expected state.

2. The Architecture: Visual State Detection

Instead of defining "where" an element is, we define "what" the screen should look like.

Our architecture consists of three layers:

  1. The Vision Engine: Continuously captures screen buffers and runs fast localized OCR to find anchor text (e.g., "Submit", "Invoice Number").
  2. The Type-Safe State Machine: Uses Pydantic to validate the parsed UI data. If the OCR reads a messy string, we run domain sanitization and pass it through a local LLM to map it strictly to our data model.
  3. The Orchestrator (n8n): Acts as the brain, triggering the Python RPA agent via local webhooks and routing the structured data to our CRM.

3. The Code & Logic: Type-Safe Detection and LLM Sanitization

Here is the core logic. First, we define our expected UI state using Pydantic. Then, we use a combination of OCR and a lightweight LLM prompt to sanitize the messy text read from the screen (e.g., extracting clean domains and email addresses from a messy desktop email client).

import cv2
import pytesseract
import pyautogui
from pydantic import BaseModel, Field, ValidationError
from typing import Optional
import openai

# 1. Type-Safe Definition of our expected UI State
class InvoiceUIState(BaseModel):
    is_loaded: bool
    invoice_number: Optional[str] = Field(None, description="Extracted Invoice ID")
    client_domain: Optional[str] = Field(None, description="Sanitized client domain")

# 2. Domain Sanitization & LLM Prompt Structuring
def sanitize_ocr_with_llm(raw_ocr_text: str) -> InvoiceUIState:
    """Uses a local or fast API LLM to extract structured data from messy OCR."""
    prompt = f"""
    You are a data extraction agent. Parse the following raw OCR text from a desktop application.
    Extract the invoice number and sanitize the client's email into a clean domain.
    If the UI hasn't fully loaded, set is_loaded to false.

    Raw OCR:
    {raw_ocr_text}
    """

    # Using OpenAI's structured outputs to guarantee our Pydantic model
    response = openai.ChatCompletion.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": prompt}],
        functions=[{"name": "extract_ui", "parameters": InvoiceUIState.schema()}],
        function_call={"name": "extract_ui"}
    )

    return InvoiceUIState.parse_raw(response.choices[0].message.function_call.arguments)

# 3. Execution Logic
def click_element_by_text(target_text: str):
    """Finds screen coordinates dynamically based on OCR, avoiding X/Y brittleness."""
    screenshot = pyautogui.screenshot()
    screenshot.save("buffer.png")

    img = cv2.imread("buffer.png")
    data = pytesseract.image_to_data(img, output_type=pytesseract.Output.DICT)

    for i in range(len(data['text'])):
        if target_text.lower() in data['text'][i].lower():
            x, y, w, h = data['left'][i], data['top'][i], data['width'][i], data['height'][i]
            # Self-healing click: always targets the center of the found text
            pyautogui.click(x + w/2, y + h/2)
            return True
    raise Exception(f"Element '{target_text}' not found in current UI state.")
Enter fullscreen mode Exit fullscreen mode

4. Deployment & Performance: Handling UI Rendering and Routing

When running this in production, desktop applications don't load instantly. We must implement Exponential Backoff to handle timeouts, rate limits, and rendering delays.

Instead of time.sleep(5) (which is an anti-pattern), wrap your vision checks in a polling loop:

import time

def wait_for_ui_state(target_text: str, timeout: int = 30):
    start_time = time.time()
    while time.time() - start_time < timeout:
        try:
            if click_element_by_text(target_text):
                print(f"UI State matched: {target_text}")
                return
        except Exception:
            time.sleep(1) # Wait 1 second before re-evaluating screen buffer
    raise TimeoutError("UI failed to render in time.")
Enter fullscreen mode Exit fullscreen mode

Integrating with n8n:
To integrate this local python engine with your broader marketing or CRM automation, wrap the Python script in a simple FastAPI server. You can then use an n8n HTTP Request node to trigger your local RPA agent securely, passing payloads back and forth between your desktop applications and your web-based CRMs.

5. Conclusion & Ready-to-use Workflow

Desktop automation doesn't require five-figure enterprise licenses. By combining open-source Computer Vision, LLM-based domain sanitization, and strict Python typing, you can build self-healing automation pipelines that survive UI changes.

You can absolutely take the code snippets above, integrate them with n8n, and build this pipeline yourself. However, if you want to skip the trial-and-error and get a production-ready system right now, I've packaged the complete engine.

VisionRPA: Type-Safe Desktop UI Automation & OCR Engine is available as a turnkey package with pre-built test fixtures, n8n JSON templates, and the complete Python source code.

Grab it here:

  • Instant Access on Whop: Link
  • Direct Download on Gumroad: Link (Use promo code EARLYBIRD for 20% off).

Stop letting hard-coded X/Y coordinates break your workflows. Build visually, execute locally.


🛠️ D'autres outils MR Studio qui pourraient vous intéresser :

Top comments (0)