您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Módulo de comunicación con la API de IA para WME Place Normalizer. No funciona por sí solo.
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.greasyforks.org/scripts/548746/1657857/WME%20PLN%20Core%20-%20AI%20Handler.js
// ==UserScript== // @name WME PLN Core - AI Handler // @namespace https://greasyforks.org/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 // ==/UserScript== // Función para realizar solicitudes HTTP usando GM_xmlhttpRequest function makeRequest(options) { try { if (typeof window.plnUiNetRequest === 'function') { window.plnUiNetRequest(options); // UI/adapter ejecuta GM_xmlhttpRequest real } else { throw new Error('No request adapter (plnUiNetRequest) disponible.'); } } catch (e) { plnLog('error', 'AI core: no hay adaptador de red (plnUiNetRequest).', e); } }//makeRequest // Función para obtener sugerencias de nombres de lugares desde la API de IA async function getAiSuggestions(placeName, wazeCategories, placeNameToCompare = '', hooks = null) { const WORKER_URL = 'https://wme-normalizer-ai.cotalvaro.workers.dev/'; return new Promise((resolve) => { const req = buildAiRequestOptions(placeName, wazeCategories, placeNameToCompare, WORKER_URL, 20000); req.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.` }); } } }; req.onerror = function () { resolve({ error: "Error de red al contactar el Worker." }); }; req.ontimeout = function () { resolve({ error: "Timeout al contactar el Worker." }); }; const adjusted = plnAdjustAiPayloadIfNeeded(req, hooks); makeRequest(adjusted); }); }//getAiSuggestions // Helper pura: arma el objeto de request para el Worker de IA (sin efectos secundarios) function buildAiRequestOptions(placeName, wazeCategories, placeNameToCompare = '', workerUrl = 'https://wme-normalizer-ai.cotalvaro.workers.dev/', timeoutMs = 20000) { const safeName = String(placeName ?? ''); const safeCats = Array.isArray(wazeCategories) ? wazeCategories : []; const safeCompare = String(placeNameToCompare ?? ''); return { method: "POST", url: workerUrl, headers: { "Content-Type": "application/json" }, data: JSON.stringify({ placeName: safeName, wazeCategories: safeCats, placeNameToCompare: safeCompare }), timeout: timeoutMs }; } //Permite ajustar la carga útil de las solicitudes a la API de IA para incluir nombres sugeridos function plnAdjustAiPayloadIfNeeded(options, hooks = null) { 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 getSuggested = hooks && typeof hooks.getSuggestedNameByPlaceId === 'function' ? hooks.getSuggestedNameByPlaceId : null; 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 && getSuggested ? getSuggested(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; } }