WME PLN Core - AI Handler

Módulo de comunicación con la API de IA para WME Place Normalizer. No funciona por sí solo.

Stan na 08-09-2025. Zobacz najnowsza wersja.

Ten skrypt nie powinien być instalowany bezpośrednio. Jest to biblioteka dla innych skyptów do włączenia dyrektywą meta // @require https://update.greatest.deepsurf.us/scripts/548746/1656813/WME%20PLN%20Core%20-%20AI%20Handler.js

// ==UserScript==
// @name         WME PLN Core - AI Handler
// @namespace    https://greatest.deepsurf.us/en/users/mincho77
// @version      9.0.0
// @description  Módulo de comunicación con la API de IA para WME Place Normalizer. No funciona por sí solo.
// @author       mincho77
// @license      MIT
// @grant        GM_xmlhttpRequest
// @connect      wme-normalizer-ai.cotalvaro.workers.dev
// ==/UserScript==

async function getAiSuggestions(placeName, wazeCategories, placeNameToCompare = '') {
    const WORKER_URL = 'https://wme-normalizer-ai.cotalvaro.workers.dev/';
    return new Promise((resolve) => {
        makeRequest({ // Asume que 'makeRequest' estará disponible en el scope principal
            method: "POST",
            url: WORKER_URL,
            headers: { "Content-Type": "application/json" },
            data: JSON.stringify({
                placeName: placeName,
                wazeCategories: wazeCategories,
                placeNameToCompare: placeNameToCompare
            }),
            timeout: 20000,
            onload: function (response) {
                if (response.status >= 200 && response.status < 300) {
                    try { const suggestions = JSON.parse(response.responseText); resolve(suggestions); }
                    catch (e) { resolve({ error: "La respuesta de la IA no es un JSON válido." }); }
                } else {
                     try { const errorResponse = JSON.parse(response.responseText); resolve(errorResponse); }
                     catch(e) { resolve({ error: `Error HTTP ${response.status} del servidor.` }); }
                }
            },
            onerror: function () { resolve({ error: "Error de red al contactar el Worker." }); },
            ontimeout: function () { resolve({ error: "Timeout al contactar el Worker." }); }
        });
    });
}

function plnGetSuggestedNameForPlaceId(placeId){
    try{
        const tr = document.querySelector(`tr[data-place-id="${placeId}"]`);
        if (!tr) return null;
        const tas = tr.querySelectorAll('textarea');
        const suggested = (tas.length > 1 ? tas[1].value : '').trim();
        if (suggested) return suggested;
        const current = (tas.length ? tas[0].value : '').trim();
        return current || null;
    }catch(_){ return null; }
}

function plnAdjustAiPayloadIfNeeded(options){
    try{
        const url = (options && options.url) || '';
        if (!/wme-normalizer-ai\.cotalvaro\.workers\.dev/i.test(url)) return options;
        if (!('data' in options) || options.data == null) return options;

        let data = options.data;
        const isString = typeof data === 'string';
        let payload = null;
        if (isString){
            try { payload = JSON.parse(data); } catch(_){ return options; }
        } else if (typeof data === 'object') {
            payload = data;
        } else {
            return options;
        }

        const adjustEntry = (entry)=>{
            if (!entry || typeof entry !== 'object') return entry;
            const pid = entry.placeId || entry.place_id || entry.id || entry.venueId || entry.venue_id;
            const suggested = pid ? plnGetSuggestedNameForPlaceId(pid) : null;
            if (suggested){
                if ('name' in entry) entry.name = suggested;
                else if ('text' in entry) entry.text = suggested;
                else if ('placeName' in entry) entry.placeName = suggested;
                else if ('query' in entry) entry.query = suggested;
                else if ('prompt' in entry) entry.prompt = `Normaliza este nombre de lugar: ${suggested}`;
            }
            return entry;
        };

        if (Array.isArray(payload)){
            payload = payload.map(adjustEntry);
        } else if (payload && typeof payload === 'object'){
            if (Array.isArray(payload.places)){
                payload.places = payload.places.map(adjustEntry);
            } else {
                adjustEntry(payload);
            }
        }

        const newData = isString ? JSON.stringify(payload) : payload;
        const cloned = { ...options, data: newData };
        if (isString){
            cloned.headers = { ...(options.headers||{}), 'Content-Type': 'application/json' };
        }
        return cloned;
    }catch(_){ return options; }
}