Detecția automată a spam-ului în Wordpress Detecția automată a spam-ului în Wordpress

Detecția automată a spam-ului în WordPress

Toată lumea s-a confruntat cu problema spam-ului din comentariile de pe website-uri, dar am putea automatiza detectarea acestuia?

1. Preambul

În acest articol vom aborda următoarea situație:

  • clientul posedă un website care nu a fost monitorizat de multă vreme;
  • există peste 25000 de comentarii la articolele din website;
  • unele din comentarii sunt reale, iar altele sunt de tip spam;
  • se dorește păstrarea doar acelor comentarii care sunt reale.

Desigur, ați putea spune că problema s-ar fi rezolvat prin instalarea unor sisteme de detecție automată a boților, precum ReCaptcha. Însă acestea sunt faptele, acum avem o gramadă de comentarii care ar trebui verificate individual.

Metodele de rezolvare a problemei prezentate în articol sunt doar cu titlul de exemplu, având un scop educativ. Nu sunt cele mai eficiente și optime, dar prezintă o utilizare practică a inteligenței artificiale în procese automatizate.

2. Algoritmi de detectare a spamului în text

La o primă vedere cele 25000 de comentarii sunt destul de amestecate, au surse diferite și au puține puncte comune: nu putem să le corelăm după adrese de email sau nume utilizatori.

Însă website-ul clientului conține articole cu teme despre România așadar în primul rând ne vom aștepta ca textul comentariului să fie în limba română și în al doilea rând să nu conțînă linkuri câtre alte website-uri.

Pentru simplificare putem stabili în acest caz particular că un comentariu este spam dacă îndeplinește oricare din cele 2 reguli:

  • conține linkuri;
  • este formulat în limba engleză sau rusă;

Este extrem de simplu pentru a identifica programatic dacă conținutul comentariului include url-uri, dar cum putem determina limba în care este formulat textul?

3. Automatizare detecție spam cu N8N și inteligența artificială

Pentru a detecta limba și sensul comentariului am putea utiliza un limbaj LLM (inteligența artificială) căruia să îi transmitem cum să facă interpretarea textului și cum să formuleze răspunsul într-un mod pe care îl putem folosi.

Va trebui să programăm un webhook care să primească textul la intrare și să genereze un răspuns la ieșire de tip true/false în funcție de clasificarea pe care o face.

N8N este un sistem de automatizare care este perfect de utilizat pentru exemplul nostru.

Schema gândită de noi este:

Avem următoarele noduri:

  • nodul de webhook care generează un endpoint pe care îl putem apela cu textul comentariului;
  • un nod de tip MarkUp care elimină toate tag-urile HTML din conținutul textului;
  • un nod de tip edit fields care setează textul de intrare în variabila user_text;
  • un nod LLM care folosește un model LLM prin serverul Ollama și are setat un model specific de răspuns;
  • din nou un nod edit fields care extrage răspunsul LLM-ului din format json și il setează în variabila response;
  • în final un nod de răspuns al webhookului.

După cum observați este necesar să precizăm ce model LLM folosim. Putem alege un API public și modele furnizate de Mistral, Meta, Anthropic, OpenAI etc sau modele instalate pe dispozitivele noastre care rulează pe un server Ollama.

Am ținut cont câ în acest caz conținutul care va fi procesat de AI este destul de mare, dar viteza de procesare nu este esențială. De asemenea am preferat ca datele să rămână local pentru a păstra confidențialitatea elementelor din mesajele reale. Din aceste motive vom folosi Ollama. Pentru stabilirea modelului avem foarte multe opțiuni (de exempu Llama, Phi 3.5 , Hermes 3 etc), dar pentru acest articol am ales Qwen2.5-14B – un model extraordinar de capabil și care rulează eficient și suficient de rapid.

Așa cum am spus, e necesar să instruim modelul legat de interpretarea textului:

Pentru aceasta am setat următorul prompt:

Classify the user text as spam or nor spam. Reply with true if it is spam and false if it is not spam.

Rules:
A text is spam if any of the rullles is true:
- text is in english or russian language
- text contains urls or links

Exemples:
Spam text:
"AD List 24 provides local classified ads for events, jobs, rentals, real estate, buy and sell, adults and dating. Angy Alonzo Elbertina" beacause is in english
"Fu all the little black babies who were never given a chance to grow up and become a contributing human being to the human race. Kaitlyn Torrin Emmie" because is in english
"http://mewkid.net/when-is-xuxlya2/ – Amoxicillin 500mg Capsules Amoxicillin 500 Mg ppg.fkta.thesolomoneffect.com.xgl.ur http://mewkid.net/when-is-xuxlya2/" becaue it contains urls (http word)

Not spam:
"Un articol foarte dragut" - because is not in english and it does not contains urls
"Felicitari pentru claritatea ideilor" - because is not in english and it does not contains urls

User text:
{{ $json.user_text }}

Variabila $json.user_text conține textul introdus de utilizator, iar singurele reguli setate sunt cele care identifică limba textului și dacă acesta conține linkuri.

În mod particular am fost interesați ca răspunsul să nu conțină explicații, ci doar informația true/false, așadar am instruit modelul LLM să răspundă în format json.

Qwen2.5 este foarte capabil să facă aceste procesări, ba chiar mult mai mult, iar într-un articol următor îl vom folosi pentru interpretarea textului, extragerea informațiilor și generarea unui răspuns automat.

4. Integrarea N8N și AI în WordPress

Așadar acum avem la îndemână un tool care ne poate spune dacă un text este de tip spam sau nu, mai trebuie doar să îl punem în practică și să îl aplicâm pe cele 25 000 de comentarii din website-ul nostru.

Putem parcurge mesajele în diferite moduri, printr-un script direct în WordPress, un plugin sau (metoda aleasă de noi pentru acest articol) printr-un API prin WP Rest API.

Așadar, am făcut un script care parcurge toate ID-urile comentariilor, dacă comentariul există îl va trimite la webhookul N8N, iar dacă acesta ne răspunde că mesajul este de tip spam atunci vom șterge mesajul (tot prin API).

Codul folosit este următorul:

<?php

// WordPress site URL
$site_url = 'https://www.XXXXXXXXXXXXX.com';

// WordPress REST API endpoint for comments
$comments_endpoint = '/wp-json/wp/v2/comments';

// Basic Auth credentials
$username = 'XXXXXXXXXXXXXXXX';
$password = 'XXXXXXXXXXXXXXXXXXXXXXXXXXX';
$basic_auth = base64_encode("$username:$password");

for ($id = 0; $id <= 23554; $id++) {
    $url = $site_url . $comments_endpoint . '/' . $id ;
    $curl = curl_init();
    curl_setopt_array($curl, array(
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => "POST",
        CURLOPT_ENCODING => "",
        CURLOPT_MAXREDIRS => 10,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
        CURLOPT_CUSTOMREQUEST => "GET",
        CURLOPT_HTTPHEADER => array(
            "authorization: Basic " . $basic_auth,
            "cache-control: no-cache"
        )
    ));

    $response = curl_exec($curl); 
    $err = curl_error($curl);

    $http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    if ($http_code == 200) {
        $comments_response = json_decode($response, true); 
        $comentariu = $comments_response['content']['rendered'];
        curl_close($curl);

        // se trimite comentariul la endpointul N8N pentru a vedea daca este tip spam sau nu
        $n8n_url = 'https://n8n.ai-XXXXXXXXXXXXX';
        $n8n_curl = curl_init();
        curl_setopt_array($n8n_curl, array(
            CURLOPT_URL => $n8n_url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CUSTOMREQUEST => "POST",
            CURLOPT_POSTFIELDS => json_encode(array('comentariu' => $comentariu)),
            CURLOPT_HTTPHEADER => array(
                "Content-Type: application/json",
                "cache-control: no-cache"
            ),
        ));
$n8n_response = curl_exec($n8n_curl);
        curl_close($n8n_curl);
        
        $validare = json_decode($n8n_response, true); 
        if ($validare['response'] == true) {
            $url = $site_url . $comments_endpoint . '/23554' ;
            $curl_del = curl_init();
                curl_setopt_array($curl_del, array(
                    CURLOPT_URL => $url,
                    CURLOPT_RETURNTRANSFER => true,
                    CURLOPT_CUSTOMREQUEST => "POST",
                    CURLOPT_ENCODING => "",
                    CURLOPT_MAXREDIRS => 10,
                    CURLOPT_TIMEOUT => 30,
                    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
                    CURLOPT_CUSTOMREQUEST => "DELETE",
                    CURLOPT_HTTPHEADER => array(
                        "authorization: Basic " . $basic_auth,
                        "cache-control: no-cache"
                    )
                ));
            $response_del = curl_exec($curl_del);    
        }
    } 
}
?>

Câteva explicații:

  • folosim WP REST API pentru a extrage comentariile pe rând de la url-ul de tip ttps://www.XXXXXXXXXXXXX.com/p-json/wp/v2/comments/ID;
  • trimitem comentariul la endpointul N6N pentru a face validarea lui;
  • verificăm răspunsul N8N, iar dacă acesta este true (adică s-a detectat spam) atunci comentariul este șters.

Un exemplu pentru analiza spam este în imaginea următoare:

Qwen2.5: 14B a avut o precizie de 100% pe cele 25 000 de mesaje pe care a rulat exemplul nostru.

4. Concluzii

Inteligența artificială poate automatiza extrem de multe sarcini care privesc procesarea informațiilor dinamice, precum un text al unui utilizator.

Așa cum în articolul de azi am detectat doar dacă limba textului este sau nu româna, tot așa putem interpreta mesajul transmis și intenția utilizatorului (de exemplu un review negativ sau pozitiv, cererea unei informații suplimentare sau o ofertă) și putem pe baza acestor interpretări să generăm răspunsuri automate care nu mai necesită intervenția umană.

Beneficiile sunt evidente: resursele umane blocate în aceste procese repetitive și plictisitoare poate fi folosite în altă parte, iar utilizatorii vor avea un feedback mult mai rapid la comentariile lor.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *