feat: add cheerio nps scraping and nws weather alerts
This commit is contained in:
parent
f7b311802f
commit
0d88c2d5cb
|
|
@ -5,6 +5,7 @@
|
||||||
"main": "server.js",
|
"main": "server.js",
|
||||||
"scripts": { "start": "node server.js" },
|
"scripts": { "start": "node server.js" },
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"cheerio": "^1.0.0-rc.12",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"node-cron": "^3.0.3"
|
"node-cron": "^3.0.3"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ const fs = require('fs');
|
||||||
const http = require('http');
|
const http = require('http');
|
||||||
const https = require('https');
|
const https = require('https');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const cheerio = require('cheerio');
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
app.use(express.json({ limit: '1mb' }));
|
app.use(express.json({ limit: '1mb' }));
|
||||||
|
|
@ -62,16 +63,36 @@ async function getWeather(location) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getNpsAlerts(parkCode) {
|
async function scrapeNpsConditions(parkCode) {
|
||||||
if (!parkCode) return null;
|
if (!parkCode) return null;
|
||||||
|
const url = `https://www.nps.gov/${parkCode}/planyourvisit/conditions.htm`;
|
||||||
try {
|
try {
|
||||||
const data = await fetchJson(`https://developer.nps.gov/api/v1/alerts?parkCode=${parkCode}&api_key=DEMO_KEY`);
|
const html = await fetchText(url);
|
||||||
if (data.data && data.data.length > 0) {
|
const $ = cheerio.load(html);
|
||||||
return data.data.map(a => `⚠️ ${a.title}`).slice(0, 3).join('\n');
|
const alerts = [];
|
||||||
|
$('.Alert-title').each((i, el) => {
|
||||||
|
alerts.push(`⚠️ ${$(el).text().trim()}`);
|
||||||
|
});
|
||||||
|
if (alerts.length > 0) {
|
||||||
|
return alerts.slice(0, 5).join('\n');
|
||||||
}
|
}
|
||||||
return 'No active NPS alerts.';
|
return 'No active NPS conditions listed.';
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return 'NPS alerts unavailable';
|
console.error('[TripService] NPS scrape error:', e.message);
|
||||||
|
return 'NPS conditions unavailable';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getWeatherAlerts(stateCode) {
|
||||||
|
try {
|
||||||
|
const data = await fetchJson(`https://api.weather.gov/alerts/active?area=${stateCode}`);
|
||||||
|
if (data.features && data.features.length > 0) {
|
||||||
|
return data.features.map(f => `🌩️ ${f.properties.event || f.properties.headline}`).slice(0, 3).join('\n');
|
||||||
|
}
|
||||||
|
return 'No active weather alerts.';
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[TripService] Weather alerts error:', e.message);
|
||||||
|
return 'Weather alerts unavailable';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -289,15 +310,17 @@ function sendWhatsApp(to, message) {
|
||||||
// ── Briefing Generation ──────────────────────────────────────────────────────
|
// ── Briefing Generation ──────────────────────────────────────────────────────
|
||||||
async function generateAndSendBriefing(trip, dayPlan) {
|
async function generateAndSendBriefing(trip, dayPlan) {
|
||||||
const weather = await getWeather(dayPlan.location || 'Pigeon Forge, TN');
|
const weather = await getWeather(dayPlan.location || 'Pigeon Forge, TN');
|
||||||
const nps = await getNpsAlerts(trip.npsParkCode);
|
const weatherAlerts = await getWeatherAlerts('TN');
|
||||||
|
const nps = await scrapeNpsConditions(trip.npsParkCode);
|
||||||
const traffic = await getTdotTraffic();
|
const traffic = await getTdotTraffic();
|
||||||
const insight = await getAiInsight(dayPlan.activities, dayPlan.location || 'Smoky Mountains', trip);
|
const insight = await getAiInsight(dayPlan.activities, dayPlan.location || 'Smoky Mountains', trip);
|
||||||
|
|
||||||
const message = `*🏕️ ${trip.name} - ${dayPlan.date} Briefing*\n\n` +
|
const message = `*🏕️ ${trip.name} - ${dayPlan.date} Briefing*\n\n` +
|
||||||
`*🌤️ Weather (${dayPlan.location || 'Pigeon Forge'}):* ${weather}\n\n` +
|
`*🌤️ Weather (${dayPlan.location || 'Pigeon Forge'}):* ${weather}\n\n` +
|
||||||
|
`*🌩️ Weather Alerts (TN):*\n${weatherAlerts}\n\n` +
|
||||||
`*📋 Today's Plan:*\n${dayPlan.activities}\n\n` +
|
`*📋 Today's Plan:*\n${dayPlan.activities}\n\n` +
|
||||||
`*🍴 Meals:*\n${dayPlan.meals}\n\n` +
|
`*🍴 Meals:*\n${dayPlan.meals}\n\n` +
|
||||||
(nps ? `*🌲 Park Alerts:*\n${nps}\n\n` : '') +
|
(nps ? `*🌲 Park Conditions:*\n${nps}\n\n` : '') +
|
||||||
`*🚗 Traffic Info:*\n${traffic}\n\n` +
|
`*🚗 Traffic Info:*\n${traffic}\n\n` +
|
||||||
`*🤖 AI Insight:*\n${insight}`;
|
`*🤖 AI Insight:*\n${insight}`;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,7 @@
|
||||||
"briefingTime": "07:00",
|
"briefingTime": "07:00",
|
||||||
"sendToGroup": true,
|
"sendToGroup": true,
|
||||||
"groupUrls": [
|
"groupUrls": [
|
||||||
"https://chat.whatsapp.com/YOUR_GROUP_INVITE_LINK_1",
|
"https://chat.whatsapp.com/FXO0SCLA8DpJwClNNWdhhx"
|
||||||
"https://chat.whatsapp.com/YOUR_GROUP_INVITE_LINK_2"
|
|
||||||
],
|
],
|
||||||
"npsParkCode": "grsm",
|
"npsParkCode": "grsm",
|
||||||
"days": [
|
"days": [
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue