From 0d88c2d5cb010b1dd7ea3d474cc11a79224b2750 Mon Sep 17 00:00:00 2001 From: deepkoluguri Date: Tue, 2 Jun 2026 22:41:01 -0400 Subject: [PATCH] feat: add cheerio nps scraping and nws weather alerts --- trip-service/package.json | 1 + trip-service/server.js | 39 ++++++++++++++++++++++++------- trip-service/smoky-mountains.json | 3 +-- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/trip-service/package.json b/trip-service/package.json index acf8647..0a0aeb0 100644 --- a/trip-service/package.json +++ b/trip-service/package.json @@ -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" } diff --git a/trip-service/server.js b/trip-service/server.js index 1cff2b6..28699db 100644 --- a/trip-service/server.js +++ b/trip-service/server.js @@ -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}`; diff --git a/trip-service/smoky-mountains.json b/trip-service/smoky-mountains.json index 356042e..425c427 100644 --- a/trip-service/smoky-mountains.json +++ b/trip-service/smoky-mountains.json @@ -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": [