Strona główna / Artykuły / Bez ograniczeń agenci automatyzacji przeglądarki z Node.js

Bez ograniczeń agenci automatyzacji przeglądarki z Node.js

Stwórz agenta sterującego przeglądarką z wyraźnymi granicami narzędzi, mechanizmami bezpieczeństwa oraz możliwością rejestracji działań.

4302 słów

To przewodnictwo odbudowuje funkcjonalną ścieżkę postępowania dotyczącą: jak stworzyć nieograniczonego agenta AI do automatyzacji przeglądarki przy użyciu Node.js, Playwright, Bright Data i Gemini. Skupiamy się na umowach, sprawdzeniach oraz kodzie, który można bez problemu dodać do repozytorium, nie musząc zgadywać intencji. Aby uzyskać ogólny obraz, zdefiniuj wprowadzenia, osobę odpowiedzialną za daną czynność oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić tę czynność od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Traktuj tę fazę jako umowę pomiędzy wprowadzeniami a zweryfikowanymi wynikami. Nadaj nazwy plikom, zdefiniuj sprawdzenia sukcesu i odrzucaj ciche, częściowe ukończenie zadania.

Wprowadzenie

W części wprowadzającej należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy rejestrować czasy wykonywania i koszty obok wyników funkcjonalnych. Wczesna widoczność zapobiega nieoczekiwanym rachunkom, gdy ścieżka przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Schematy narzędzi muszą być ściśle określone. Szersze pola tekstowe umożliwiają iniekcje i sprawiają, że audyty są kosztowne.

await page.goto(url)
await page.click(selector)
await page.type(selector, text)

To, co budujemy

Dla tego, co budujemy, należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Konfigurację należy przechowywać poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić, nie musząc czytać całej struktury aplikacji. Schematy narzędzi należy ściśle określić. Szerokie pola tekstowe umożliwiają iniekcje i sprawiają, że audyty stają się kosztowne.

Wymagania wstępne

Jako warunek wstępny należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy udokumentować zarówno prawidłowy przebieg procesu, jak i ścieżkę naprawczą. Próby ponownych działań, kontrole ludzkie oraz obsługa wiadomości błędnych stanowią część produktu, a nie elementy dodawane później. Schematy narzędzi muszą być ściśle określone. Szersze pola tekstowe sprzyjają infekcjom i utrudniają audyty. Jako warunek wstępny należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Traktuj tę fazę jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nazwij poszczególne elementy, zdefiniuj kryteria sukcesu i odrzuć ciche, częściowe ukończenie zadania.

Budowa projektu Sikki

Dla projektu Building Sikki należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany etap oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany etap na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy rejestrować czasy wykonywania i koszty obok wyników funkcjonalnych. Wczesna widoczność zapobiega nieoczekiwanym rachunkom, gdy proces przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Konieczny jest punkt kontrolny po drogich wywołaniach modeli, aby ponowna próba nie generowała dodatkowych opłat za tę samą pracę.

Etap 1: Stworzenie projektu

Dla kroku 1: Przed zmianą kodu utwórz projekt, określ dane wejściowe, osobę odpowiedzialną za ten krok oraz kryteria zakończenia. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Konfigurację należy przechowywać poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Utwórz punkt kontrolny po kosztownych wywołaniach modelu, aby ponowna próba nie generowała dodatkowych opłat za tę samą pracę.

mkdir sikki-agent
cd sikki-agent
npm init -y
npm pkg set type=module
npm install playwright

npm install @google/genai
npm install dotenv
npm install chalk
npm install ora
sikki-agent
 index.js
 .env
 screenshots/
 reports/
 package.json

Krok 2: Pobranie klucza API Gemini

Dla kroku 2: Pobranie klucza API Gemini – przed zmianą kodu należy zdefiniować dane wejściowe, osobę odpowiedzialną za ten krok oraz kryteria zakończenia. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy udokumentować zarówno prawidłowy przebieg działania, jak i ścieżkę naprawczą. Próby ponownego wykonania, kontrola przez człowieka oraz obsługa wiadomości błędnych stanowią część produktu, a nie elementy dodawane później. Ustaw punkt kontrolny po kosztownych wywołaniach modelu, aby ponowna próba nie powodowała ponownego naliczenia za tę samą pracę. Dla kroku 2: Pobranie klucza API Gemini – przed zmianą kodu należy zdefiniować dane wejściowe, osobę odpowiedzialną za ten krok oraz kryteria zakończenia. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Traktuj tę fazę jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nazwij poszczególne elementy, zdefiniuj kryteria sukcesu i odrzucaj ciche, częściowe ukończenie zadań.

GEMINI_API_KEY = your_gemini_api_key
BRIGHT_WS_ENDPOINT = //i will show you later

Krok 3: Konfiguracja infrastruktury przeglądarki Bright Data Cloud

W ramach kroku 3: Konfiguracja infrastruktury przeglądarki Bright Data Cloud należy zdefiniować dane wejściowe, osobę odpowiedzialną za ten krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić ten krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu systemu. Należy rejestrować czas trwania i koszty obok wyników funkcjonalnych. Wczesna widoczność zapobiega niespodziewanym rachunkom, gdy przechodzi się z środowiska demonstracyjnego do współdzielonych środowisk. Należy oddzielić planowanie od wykonywania zadań za pomocą narzędzi – planista proponuje rozwiązania, wykonawca je wdraża, a sprawdzający porównuje wyniki z założonym celem.

BRIGHT_WS_ENDPOINT = "your_endpoint"
chromium.launch()
chromium.connectOverCDP()

Krok 4: Połączenie Playwright z Bright Data

Dla kroku 4: Połączenie Playwright z Bright Data wymaga zdefiniowania danych wejściowych, osoby odpowiedzialnej za ten krok oraz kryteriów zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Konfigurację należy przechowywać poza kodem aplikacji. Pliki środowiskowe, magazyny haseł oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności przeglądania całej struktury. Należy oddzielić planowanie od wykonywania zadań za pomocą narzędzi. Planer proponuje rozwiązania; wykonawca je wdraża; sprawdzacz porównuje wyniki z założonym celem.

import { chromium }
from "playwright";

const BRIGHT_WS_ENDPOINT = "your_endpoint"

const browser =
await chromium.connectOverCDP(BRIGHT_WS_ENDPOINT
);

const page =
await browser.newPage();
await page.goto(
"https://cnn.com"
);

console.log(
await page.title()
);

Głębsze zapoznanie z SIKKI Agent przed implementacją

Aby lepiej poznać SIKKI Agent przed wdrożeniem, należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy udokumentować zarówno prawidłowy przebieg działania, jak i ścieżkę naprawczą. Próby ponownych działań, kontrola przez ludzi oraz obsługa wiadomości błędnych stanowią część produktu, a nie elementy dodawane później. Trzeba oddzielić planowanie od wykonywania zadań za pomocą narzędzi. Planista proponuje rozwiązania; wykonawca je wdraża; sprawdzający porównuje wyniki z założonym celem. Aby lepiej poznać SIKKI Agent przed wdrożeniem, należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Traktuj tę fazę jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nazwij poszczególne elementy, zdefiniuj kryteria sukcesu i odrzucaj ciche, częściowe rozwiązania.

zakończenie.

SIKKI to nie narzędzie do scrapingu

W przypadku SIKKI to nie narzędzie do scrapingu należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Zapisuj czas trwania i koszty obok wyników funkcjonalnych. Wczesna widoczność zapobiega niespodziewanym rachunkom, gdy ścieżka przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Schematy narzędzi muszą być ściśle określone. Szerokie pola tekstowe umożliwiają wstrzykiwanie danych i sprawiają, że audyty są kosztowne.

ProductPriceAcer Nitro V$899ASUS TUF$949MSI Thin$979

Architektura stojąca za SIKKI

Aby zrozumieć architekturę stojącą za SIKKI, należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Konfigurację należy przechowywać poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności przeglądania całej struktury. Schematy narzędzi należy ściśle określić. Szersze pola tekstowe sprzyjają iniekcjom i utrudniają audyty.

SIKKI

Strategic Intelligence Commerce Kernel

┌──────────────────────────────┐
│ Browser Layer                │
│ Playwright + Bright Data     │
└──────────────────────────────┘
                │
                ▼
┌──────────────────────────────┐
│ Extraction Layer             │
│ Product                      │
│ Price                        │
│ Rating                       │
│ Seller                       │
│ Availability                 │
└──────────────────────────────┘
                │
                ▼
┌──────────────────────────────┐
│ AI Layer                     │
│ Gemini                       │
└──────────────────────────────┘
                │
                ▼
┌──────────────────────────────┐
│ Analysis Layer               │
│ Cheapest Products            │
│ Market Average               │
│ Competitor Comparison        │
│ Trend Analysis               │
└──────────────────────────────┘
                │
                ▼
        Markdown / CSV
        Dashboard Export

Budowa warstwy ekstrakcji

Aby zbudować warstwę ekstrakcji, należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy udokumentować zarówno prawidłowy przebieg działania, jak i ścieżkę naprawczą. Próby ponownych działań, kontrole ludzkie oraz obsługa wiadomości błędnych stanowią część produktu, a nie elementy dodawane później. Schematy narzędzi muszą być ściśle określone. Szersze pola tekstowe sprzyjają iniekcjom i sprawiają, że audyty są kosztowne. Aby zbudować warstwę ekstrakcji, należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Traktuj tę fazę jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nazwij poszczególne elementy, zdefiniuj kryteria sukcesu i odrzucaj ciche, częściowe ukończenie zadań.

const products = await page.evaluate(() => {const items = [];
    document.querySelectorAll('[data-component-type="s-search-result"]')
      .forEach(card => {
        const title =
          card.querySelector('h2 span')?.innerText;
        const price =
          card.querySelector('.a-price .a-offscreen')
          ?.innerText;
        const rating =
          card.querySelector('.a-icon-alt')
          ?.innerText;
        const link =
          card.querySelector('h2 a')
          ?.href;
        if(title && price){
            items.push({
                title,
                price,
                rating,
                link
            });
        }
    });
    return items;
});
console.log(products);
[
 {
   title: "Acer Nitro V Gaming Laptop",
   price: "$899",
   rating: "4.5 out of 5 stars",
   link: "https://..."
 },

{
   title: "ASUS TUF Gaming A15",
   price: "$949",
   rating: "4.4 out of 5 stars",
   link: "https://..."
 }
]

Dodawanie „mózgu” do SIKKI

Aby stworzyć SIKKI z funkcją rozumowania, należy określić dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy rejestrować czas trwania i koszty obok wyników funkcjonalnych. Wczesna widoczność zapobiega nieoczekiwanym rachunkom, gdy ścieżka przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Konieczny jest punkt kontrolny po drogich wywołaniach modelu, aby ponowna próba nie generowała dodatkowych opłat za tę samą pracę.

const prompt = `You are an ecommerce analyst.
Analyze the following products.
${JSON.stringify(products)}
Return:
1. Cheapest product
2. Average price
3. Best rated product
4. Summary of the market
5. Recommendation
`;

Budowa ostatecznego agenta SIKKI

Aby stworzyć ostatecznego agenta SIKKI, należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Konfigurację należy przechowywać poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Utwórz punkt kontrolny po kosztownych wywołaniach modelu, aby ponowna próba nie generowała dodatkowych opłat za tę samą pracę.

Krok 1: Stworzenie pliku agenta

Dla kroku 1: Stwórz plik agenta, zdefiniuj dane wejściowe, osobę odpowiedzialną za ten krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić ten krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Zdokumentuj zarówno prawidłowy przebieg działania, jak i ścieżkę naprawczą. Próby ponownego wykonania, kontrola przez ludzi oraz obsługa wiadomości błędnych stanowią część produktu, a nie elementy dodawane później. Utwórz punkt kontrolny po kosztownych wywołaniach modelu, aby ponowna próba nie generowała dodatkowych opłat za tę samą pracę. Dla kroku 1: Stwórz plik agenta, zdefiniuj dane wejściowe, osobę odpowiedzialną za ten krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić ten krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Traktuj ten etap jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nadaj nazwy poszczególnym elementom, zdefiniuj kryteria sukcesu i odrzucaj ciche, częściowe ukończenie zadań.

import "dotenv/config"; //to use environment variables from .env file
import fs from "fs"; //to read and write files

import { chromium } from "playwright";
import { GoogleGenAI } from "@google/genai";


//api keys and endpoints from environment variables
const BRIGHT_WS_ENDPOINT = process.env.BRIGHT_WS_ENDPOINT;
const GEMINI_API_KEY = process.env.GEMINI_API_KEY;
//initialize the GoogleGenAI client with the Gemini API key

const ai = new GoogleGenAI({
  apiKey: GEMINI_API_KEY,
});

//the prompt to send to the Gemini API
const prompt = "Write a short introduction to the Gemini API.";

const response = await ai.models.generateContent({
  model: "gemini-2.5-flash",
  contents: prompt,
});

console.log(response.text);

Krok 2: Konfiguracja Playwright do połączenia z WebSocketiem Bright Data

W ramach kroku 2: Konfiguracja Playwright do połączenia z WebSocketiem Bright Data, przed zmianą kodu należy określić dane wejściowe, osobę odpowiedzialną za ten krok oraz kryteria zakończenia. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy rejestrować czasy wykonywania i koszty obok wyników funkcjonalnych. Wczesna widoczność zapobiega nieoczekiwanym rachunkom, gdy ścieżka przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Należy oddzielić planowanie od wykonywania narzędzia – planista proponuje, wykonawca wprowadza zmiany, a weryfikator sprawdza wyniki pod kątem celu.

//setup Playwright to connect to Bright Data's WebSocket endpoint and navigate to Amazon search results for "gaming laptop"
async function main(){
  const browser = await chromium.connectOverCDP(BRIGHT_WS_ENDPOINT);
  const page = await browser.newPage();

  const query = "gaming laptop";
  const searchUrl = `https://www.amazon.com/s?k=${encodeURIComponent(query)}`;

  console.log("Navigating Bright Data Playwright to:", searchUrl);
  await page.goto(searchUrl, { waitUntil: "domcontentloaded" });

  const title = await page.title();
  console.log("Amazon search page title:", title);
  console.log("Bright Data navigation complete for query:", query);

  await browser.close();
}

main();

Krok 3: Wydobycie informacji o produkcie

Dla kroku 3: Wyodrębnianie informacji o produkcie, należy zdefiniować dane wejściowe, osobę odpowiedzialną za ten krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Konfigurację należy przechowywać poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Należy oddzielić planowanie od wykonywania zadań za pomocą narzędzi. Planista proponuje rozwiązania; wykonawca je wdraża; sprawdzający porównuje wyniki z założonym celem.

// Playwright to connect to Bright Data's WebSocket endpoint and navigate to Amazon search results for "gaming laptop"
async function main(){
  const browser = await chromium.connectOverCDP(BRIGHT_WS_ENDPOINT);
  const page = await browser.newPage();

  const query = "gaming laptop";
  const searchUrl = `https://www.amazon.com/s?k=${encodeURIComponent(query)}`;

  console.log("Navigating Bright Data Playwright to:", searchUrl);
  await page.goto(searchUrl, { waitUntil: "domcontentloaded" });

  const products = await page.evaluate(() => {
    const data = [];
    document
      .querySelectorAll('[data-component-type="s-search-result"]')
      .forEach((card) => {
        const title = card.querySelector("h2 span")?.innerText;
        const price = card.querySelector(".a-price .a-offscreen")?.innerText;
        const rating = card.querySelector(".a-icon-alt")?.innerText;
        if (title && price) {
          data.push({
            title,
            price,
            rating,
          });
        }
      });
    return data;
  });

  console.log("Step 3: Extract Product Information");
  console.log(products);

  const title = await page.title();
  console.log("Amazon search page title:", title);
  console.log("Bright Data navigation complete for query:", query);

  await browser.close();
}

main();

Krok 4: Poproszenie Gemini o analizę rynku

Dla kroku 4: Poproś Gemini o analizę rynku – zdefiniuj dane wejściowe, osobę odpowiedzialną za ten krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Zdokumentuj zarówno prawidłowy przebieg działania, jak i ścieżkę naprawczą. Próby ponownych działań, kontrola przez ludzi oraz obsługa wiadomości błędowych stanowią część produktu, a nie elementy dodawane później. Rozdziel planowanie od wykonywania zadań za pomocą narzędzi. Planista proponuje; wykonawca wprowadza zmiany; weryfikator sprawdza wyniki pod kątem osiągnięcia celu. Dla kroku 4: Poproś Gemini o analizę rynku – zdefiniuj dane wejściowe, osobę odpowiedzialną za ten krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Traktuj tę fazę jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nadaj nazwy poszczególnym elementom, zdefiniuj kryteria sukcesu i odrzucaj ciche, częściowe ukończenie zadań.

const prompt = `You are an ecommerce analyst.
Analyze these products:
${JSON.stringify(products)}
Return:
1. Cheapest Product
2. Average Market Price
3. Best Rated Product
4. Competitor Comparison
5. Final Recommendation
`;
const result = await model.generateContent(prompt);
const analysis =
result.response.text();
### 3. Best Rated Product
There are three products tied for the highest rating of **5.0 out of 5 stars**:
1.  **HP OMEN 16" Gaming Laptop Computer** (Intel Ultra 9 285H, NVIDIA GeForce RTX 5070 8GB, 16GB DDR5, 1TB PCIe SSD, 144Hz IPS WUXGA Display) at **$1,745.99**
2.  **HP OMEN 16 Slim RTX 5070 Gaming Laptop** (Intel Ultra 9 285H, NVIDIA RTX 5070, 32GB DDR5, 1TB SSD, 16" FHD+ Anti-Glare) at **$1,929.00**
3.  **ASUS ROG Strix G16 Gaming Laptop** (Intel Core i7 14650HX, NVIDIA RTX 5060, 32 GB DDR5 RAM, 1 TB SSD, 16" FHD+ LED Display, & Gaming Accessories) at **$1,999.99**

**Analysis:** It's noteworthy that two HP OMEN laptops achieved perfect ratings, both featuring high-end Ultra 9 CPUs and RTX 5070 GPUs.
This suggests strong customer satisfaction with HP's premium gaming line.
The ASUS ROG Strix G16 also achieved a 5.0 rating,
despite having a slightly lower-tier GPU (RTX 5060) than the
HP OMENs in this bracket, possibly due to the included
"Gaming Accessories" and overall perceived value.
The Alienware product has no rating, so it cannot be considered here.

Krok 5: Eksport raportu rynkowego Sikki

W ramach kroku 5: Eksport raportu rynkowego Sikki należy zdefiniować dane wejściowe, osobę odpowiedzialną za ten krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić ten krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu systemu. Należy rejestrować czasy wykonywania i koszty obok wyników funkcjonalnych. Wczesna widoczność zapobiega niespodziewanym rachunkom, gdy proces przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Schematy narzędzi muszą być ściśle określone – szerokie pola tekstowe sprzyjają infekcjom i zwiększają koszty audytów.

const report = `
# SIKKI Market Report
## Search Query
${query}

## Products
${JSON.stringify(products, null, 2)}

## Gemini Analysis
${analysis}

Generated: ${new Date().toISOString()}
`;

fs.writeFileSync(reportPath, report, "utf8");
import "dotenv/config"; // use environment variables from .env file
import fs from "fs";

import { chromium } from "playwright";
import { GoogleGenAI } from "@google/genai";

const BRIGHT_WS_ENDPOINT = process.env.BRIGHT_WS_ENDPOINT;
const GEMINI_API_KEY = process.env.GEMINI_API_KEY;

if (!BRIGHT_WS_ENDPOINT) {
  throw new Error("Missing BRIGHT_WS_ENDPOINT environment variable.");
}

if (!GEMINI_API_KEY) {
  throw new Error("Missing GEMINI_API_KEY environment variable.");
}

const ai = new GoogleGenAI({
  apiKey: GEMINI_API_KEY,
});

async function retryWithBackoff(fn, maxRetries = 5, initialDelayMs = 2000) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await fn();
    } catch (error) {
      const errorMsg = error?.message || error?.status || JSON.stringify(error);
      if (attempt === maxRetries) {
        console.error(`Final attempt failed. Error: ${errorMsg}`);
        throw error;
      }
      const delayMs = initialDelayMs * Math.pow(2, attempt - 1);
      console.log(`Attempt ${attempt} failed: ${errorMsg}`);
      console.log(`Retrying in ${delayMs}ms... (${attempt}/${maxRetries})`);
      await new Promise((resolve) => setTimeout(resolve, delayMs));
    }
  }
}

async function main() {
  let browser;
  try {
    browser = await chromium.connectOverCDP(BRIGHT_WS_ENDPOINT);
    const page = await browser.newPage();

    const query = "gaming laptop";
    const searchUrl = `https://www.amazon.com/s?k=${encodeURIComponent(query)}`;

    console.log("Connecting Playwright to Bright Data...");
    console.log("Navigating to:", searchUrl);

    await page.goto(searchUrl, { waitUntil: "domcontentloaded" });

    const products = await page.evaluate(() => {
      const data = [];
      document
        .querySelectorAll('[data-component-type="s-search-result"]')
        .forEach((card) => {
          const title = card.querySelector("h2 span")?.innerText;
          const price = card.querySelector(".a-price .a-offscreen")?.innerText;
          const rating = card.querySelector(".a-icon-alt")?.innerText;
          if (title && price) {
            data.push({
              title,
              price,
              rating,
            });
          }
        });
      return data;
    });

    console.log(`Extracted ${products.length} products.`);

    const analysisPrompt = `You are an ecommerce analyst.
Analyze these products:
${JSON.stringify(products)}
Return:
1. Cheapest Product
2. Average Market Price
3. Best Rated Product
4. Competitor Comparison
5. Final Recommendation
`;

    console.log("Sending products to Gemini for analysis (with retry logic)...");
    const analysisResult = await retryWithBackoff(async () => {
      return await ai.models.generateContent({
        model: "gemini-2.5-flash",
        contents: analysisPrompt,
      });
    }, 5, 2000);

    const analysis = analysisResult.text || "No analysis text returned.";

    const report = `# SIKKI Market Report

## Search Query
${query}

## Products
${JSON.stringify(products, null, 2)}

## Gemini Analysis
${analysis}

Generated: ${new Date().toISOString()}
`;

    fs.writeFileSync("sikki-report.md", report, "utf8");

    console.log("Step 5: Export the Results");
    console.log("Report generated: sikki-report.md");
    console.log("Final analysis saved. Open sikki-report.md to review the result.");

    await browser.close();
  } catch (error) {
    console.error("Error:", error.message || error);
    if (browser) {
      await browser.close().catch(() => {});
    }
    process.exit(1);
  }
}

main();

Krok 6: Nauczenie SIKKI gromadzenia dowodów

Dla kroku 6: Naucz SIKKI zbierania dowodów, zdefiniuj dane wejściowe, osobę odpowiedzialną za ten krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Konfigurację należy przechowywać poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Schematy narzędzi muszą być ściśle określone. Szerokie pola tekstowe umożliwiają iniekcje i sprawiają, że audyty stają się kosztowne.

const searchScreenshot = path.join(screenshotDir, "search-results.png");
await page.screenshot({ path: searchScreenshot, fullPage: true });
const summaryPath = path.join(screenshotDir, "top-product-summary.png");
await cards[0].screenshot({ path: summaryPath });

Krok 7: Zapisz każdą stronę produktu

Dla kroku 7: Zapisz każdą stronę produktu – przed zmianą kodu zdefiniuj dane wejściowe, osobę odpowiedzialną za ten krok oraz kryteria zakończenia. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Zdokumentuj zarówno prawidłowy przebieg działania, jak i ścieżkę naprawczą. Próby ponownych działań, kontrole ludzkie oraz obsługa wiadomości błędowych stanowią część produktu, a nie elementy dodawane później. Ściśle określ schematy narzędzi. Szerokie pola tekstowe sprzyjają iniekcjom i sprawiają, że audyty są kosztowne. Dla kroku 7: Zapisz każdą stronę produktu – przed zmianą kodu zdefiniuj dane wejściowe, osobę odpowiedzialną za ten krok oraz kryteria zakończenia. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Traktuj ten etap jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nadaj nazwy poszczególnym elementom, zdefiniuj kryteria sukcesu i odrzucaj ciche, częściowe ukończenie zadań.

const normalized = normalizeAmazonUrl(p.url, p.title);
await retryWithBackoff(async () =>
 await page.goto(normalized, { waitUntil: "domcontentloaded", timeout: 120000 }),
 3,
 1500
);
await page.waitForTimeout(800);
await page.screenshot({ path: outPath, fullPage: true });

Krok 8: Stwórz eksport w formacie CSV

Dla kroku 8: Tworzenie eksportu w formacie CSV – należy zdefiniować dane wejściowe, osobę odpowiedzialną za ten krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić ten krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy rejestrować czasy wykonywania i koszty obok wyników funkcjonalnych. Wczesna widoczność informacji zapobiega nieoczekiwanym rachunkom, gdy proces przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Należy ustawić punkt kontrolny po drogich wywołaniach modelu, aby ponowna próba nie generowała dodatkowych opłat za tę samą pracę.

const csvLines = ["TITLE,PRICE,RATING,URL"];
enriched.forEach((p) => {
 const safe = (s) => `"${String(s || "").replace(/"/g, '""')}"`;
 csvLines.push([safe(p.title), safe(p.price), safe(p.rating || ""), safe(p.url || "")].join(","));
});
fs.writeFileSync(csvPath, csvLines.join("\n"), "utf8");

Krok 9: Generowanie podsumowania na panelu sterowania

Dla kroku 9: Generowanie podsumowania na panelu sterowania – przed zmianą kodu należy zdefiniować dane wejściowe, osobę odpowiedzialną za ten krok oraz kryteria zakończenia. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Konfigurację należy przechowywać poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Ustal punkt kontrolny po kosztownych wywołaniach modelu, aby ponowna próba nie generowała dodatkowych opłat za tę samą pracę.

const priced = enriched.filter((p) => !isNaN(p.priceValue));
const cheapestObj = priced.length ? priced.reduce((a, b) => (a.priceValue <= b.priceValue ? a : b)) : null;
const avgPriceVal = priced.length ? (priced.reduce((s, p) => s + p.priceValue, 0) / priced.length).toFixed(2) : “N/A”;
const bestRatedObj = enriched.slice().sort((a, b) => {
 const ra = parseFloat((a.rating || “”).split(“ “)[0]) || 0;
 const rb = parseFloat((b.rating || “”).split(“ “)[0]) || 0;
 return rb — ra;
})[0] || null;
const dashboard = [];
dashboard.push(“==================================”);
dashboard.push(“SIKKI MARKET DASHBOARD”);
dashboard.push(“==================================”);
dashboard.push(`Query: ${query}`);
dashboard.push(`Products Extracted: ${enriched.length}`);
dashboard.push(`Cheapest Product: ${cheapestObj ? `${cheapestObj.title} | ${cheapestObj.price}` : “N/A”}`);
dashboard.push(`Average Price: ${avgPriceVal === “N/A” ? “N/A” : `${avgPriceVal}`}`);
dashboard.push(`Best Rated: ${bestRatedObj ? `${bestRatedObj.title} | ${bestRatedObj.rating || “N/A”}` : “N/A”}`);
dashboard.push(“\nTop 5 Products:”);
enriched.slice(0, 5).forEach((p, i) => {
 dashboard.push(`${i + 1}. ${p.title} | ${p.price} | ${p.rating || “N/A”} | ${p.url || “N/A”}`);
});
fs.writeFileSync(dashboardPath, dashboard.join(“\n”), “utf8”);

Dalej co robić

Dla kroku „Gdzie iść dalej” należy zdefiniować dane wejściowe, osobę odpowiedzialną za ten krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy udokumentować zarówno prawidłowy przebieg działania, jak i ścieżkę naprawczą. Próby ponownego wykonania, kontrola przez ludzi oraz obsługa wiadomości błędnych stanowią część produktu, a nie elementy dodawane później. Ustawiaj punkty kontrolne po kosztownych wywołaniach modeli, aby ponowne próby nie powodowały ponownego naliczania tych samych zadań. Dla kroku „Gdzie iść dalej” należy zdefiniować dane wejściowe, osobę odpowiedzialną za ten krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Traktuj ten etap jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nazwij poszczególne elementy, zdefiniuj kryteria sukcesu i odrzucaj ciche, częściowe ukończenie zadań.

Wniosek

Na zakończenie należy określić dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy rejestrować czasy wykonywania i koszty obok wyników funkcjonalnych. Wczesna widoczność zapobiega niespodziewanym rachunkom, gdy proces przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Należy oddzielić planowanie od wykonywania zadań za pomocą narzędzi – planista proponuje rozwiązania, wykonawca je wdraża, a sprawdzający porównuje wyniki z założonym celem.

Lista kontrolna operacyjna

W ramach listy kontrolnej operacyjnej należy określić dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu.

Należy preferować małe, łatwe do przetestowania jednostki nad rozbudowanymi skryptami. Gdy dany krok zawodzi, powinien wskazywać na konkretną przyczynę, a nie na skomplikowany łańcuch operacji.

Punkt kontrolny po drogich wywołaniach modeli, aby ponowna próba nie generowała dodatkowych opłat za tę samą pracę.

Zrozum granice pętli zdarzeń: co blokuje wątek, a co czeka na jądro.

Napisz krótki przewodnik: jak rotować klucze, jak opróżniać kolejkę, jak cofnąć ostatnią zmianę.

Zachowaj konfigurację poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności przeglądania całej struktury.

Zanim zaktualizujesz stack, zamroź wersje, utwórz „złoty zapis” dla kluczowych ścieżek oraz potwierdź kroki cofania. Środowiska współdzielone wymagają ograniczeń szybkości, weryfikacji użytkowników oraz wyraźnego właściciela odpowiedzialnego za rotację tajnych danych. Wolisz nudną niezawodność od pomysłowych, jednorazowych demonstracji.

Literatura pokrewna