feat: add cheerio nps scraping and nws weather alerts

This commit is contained in:
deepkoluguri 2026-06-02 22:41:01 -04:00
parent f7b311802f
commit 0d88c2d5cb
3 changed files with 33 additions and 10 deletions

View File

@ -5,6 +5,7 @@
"main": "server.js",
"scripts": { "start": "node server.js" },
"dependencies": {
"cheerio": "^1.0.0-rc.12",
"express": "^4.18.2",
"node-cron": "^3.0.3"
}

View File

@ -4,6 +4,7 @@ const fs = require('fs');
const http = require('http');
const https = require('https');
const path = require('path');
const cheerio = require('cheerio');
const app = express();
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;
const url = `https://www.nps.gov/${parkCode}/planyourvisit/conditions.htm`;
try {
const data = await fetchJson(`https://developer.nps.gov/api/v1/alerts?parkCode=${parkCode}&api_key=DEMO_KEY`);
if (data.data && data.data.length > 0) {
return data.data.map(a => `⚠️ ${a.title}`).slice(0, 3).join('\n');
const html = await fetchText(url);
const $ = cheerio.load(html);
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) {
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 ──────────────────────────────────────────────────────
async function generateAndSendBriefing(trip, dayPlan) {
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 insight = await getAiInsight(dayPlan.activities, dayPlan.location || 'Smoky Mountains', trip);
const message = `*🏕️ ${trip.name} - ${dayPlan.date} Briefing*\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` +
`*🍴 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` +
`*🤖 AI Insight:*\n${insight}`;

View File

@ -3,8 +3,7 @@
"briefingTime": "07:00",
"sendToGroup": true,
"groupUrls": [
"https://chat.whatsapp.com/YOUR_GROUP_INVITE_LINK_1",
"https://chat.whatsapp.com/YOUR_GROUP_INVITE_LINK_2"
"https://chat.whatsapp.com/FXO0SCLA8DpJwClNNWdhhx"
],
"npsParkCode": "grsm",
"days": [