Files
crm-ai/bridge/src/faq-fetcher.js
T

82 lines
2.4 KiB
JavaScript

'use strict';
const fs = require('fs');
const path = require('path');
function stripHtml(value) {
return String(value || '')
.replace(/<br\s*\/?>/gi, '\n')
.replace(/<[^>]+>/g, ' ')
.replace(/&nbsp;/g, ' ')
.replace(/&amp;/g, '&')
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/&quot;/g, '"')
.replace(/\s+/g, ' ')
.trim();
}
function extractFaqFromLdJson(html, max = 50) {
const re = /<script[^>]*type=["']application\/ld\+json["'][^>]*>([\s\S]*?)<\/script>/gi;
let m;
while ((m = re.exec(String(html)))) {
try {
const data = JSON.parse(m[1].trim());
const candidates = Array.isArray(data) ? data : [data];
for (const item of candidates) {
const main = item && (item.mainEntity || (item['@type'] === 'FAQPage' && item.mainEntity));
if (!Array.isArray(main)) continue;
const out = main
.filter((q) => q && q.name && q.acceptedAnswer && q.acceptedAnswer.text)
.map((q) => ({ q: stripHtml(q.name), a: stripHtml(q.acceptedAnswer.text) }))
.filter((q) => q.q && q.a)
.slice(0, max);
if (out.length) return out;
}
} catch {
// 非 JSON-LD 块忽略
}
}
return [];
}
function loadFaqConfig(file) {
try {
return JSON.parse(fs.readFileSync(file, 'utf8'));
} catch {
return { enabled: false, pages: [] };
}
}
function createFaqFetcher(config = {}) {
const pages = config.pages || [];
const timeoutMs = config.timeoutMs || 15000;
const max = config.maxFaqsPerPage || 50;
async function fetchPage(url) {
const res = await fetch(url, {
headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36', Accept: 'text/html,application/xhtml+xml' },
signal: AbortSignal.timeout(timeoutMs),
});
if (!res.ok) throw new Error(`fetch ${url} failed: HTTP ${res.status}`);
return extractFaqFromLdJson(await res.text(), max);
}
async function fetchAll() {
const out = [];
for (const page of pages) {
try {
const questions = await fetchPage(page.url);
out.push({ ...page, questions });
} catch (err) {
out.push({ ...page, questions: [], error: err.message });
}
}
return out;
}
return { fetchPage, fetchAll, pages };
}
module.exports = { createFaqFetcher, loadFaqConfig, extractFaqFromLdJson, stripHtml };