TripSense 行知 · 周边出行顾问:首版

零依赖 Node 服务,三步流程(选出发地 → 分析候选 → 生成方案 + 路线图 + 住宿参考)。

- 候选发现:高德 place/text 类型词跨城检索 + 内置景区/城市/小众库 + Photon 兜底
- 区县级「排除同城」判定(adname),过滤发生在轮转取样之前
- 路线图画的是 AI 方案里实际安排的每个地点,按正文顺序编号 + 虚线动线 + 真实高德底图
- 住宿:RollingGo 只读 CLI 取实时报价,无价格源时如实标注不编造
- 服务端内存缓存(指纹 + TTL + LRU),数据源层与 HTTP 层分别缓存
- 上下文瘦身:逐日天气只给 rank1,紧凑 JSON,实测约 1335 token
This commit is contained in:
2026-11-05 20:25:03 +08:00
commit c5c2ffae68
53 changed files with 8586 additions and 0 deletions
+152
View File
@@ -0,0 +1,152 @@
'use strict';
const { EXTRA_SCENIC, CN_CITIES } = require('./places-cn');
const { NICHE_SPOTS } = require('./places-niche');
// ------------------------------------------------------- WMO 天气现象编码表
// code -> { label, icon, severity } severity: 0晴好 1一般 2小雨/雾 3中雨以上 4雪 5雷暴
const WMO = {
0: { label: '晴', icon: '☀️', severity: 0 },
1: { label: '晴间多云', icon: '🌤️', severity: 0 },
2: { label: '多云', icon: '⛅', severity: 1 },
3: { label: '阴', icon: '☁️', severity: 1 },
45: { label: '有雾', icon: '🌫️', severity: 2 },
48: { label: '冻雾', icon: '🌫️', severity: 2 },
51: { label: '轻微毛毛雨', icon: '🌦️', severity: 2 },
53: { label: '毛毛雨', icon: '🌦️', severity: 2 },
55: { label: '较强毛毛雨', icon: '🌧️', severity: 3 },
56: { label: '冻毛毛雨', icon: '🌧️', severity: 4 },
57: { label: '强冻毛毛雨', icon: '🌧️', severity: 4 },
61: { label: '小雨', icon: '🌦️', severity: 2 },
63: { label: '中雨', icon: '🌧️', severity: 3 },
65: { label: '大雨', icon: '🌧️', severity: 3 },
66: { label: '冻雨', icon: '🌧️', severity: 4 },
67: { label: '强冻雨', icon: '🌧️', severity: 4 },
71: { label: '小雪', icon: '🌨️', severity: 4 },
73: { label: '中雪', icon: '🌨️', severity: 4 },
75: { label: '大雪', icon: '❄️', severity: 4 },
77: { label: '米雪', icon: '🌨️', severity: 4 },
80: { label: '阵雨', icon: '🌦️', severity: 2 },
81: { label: '较强阵雨', icon: '🌧️', severity: 3 },
82: { label: '强阵雨', icon: '⛈️', severity: 4 },
85: { label: '阵雪', icon: '🌨️', severity: 4 },
86: { label: '强阵雪', icon: '❄️', severity: 4 },
95: { label: '雷阵雨', icon: '⛈️', severity: 5 },
96: { label: '雷暴伴冰雹', icon: '⛈️', severity: 5 },
99: { label: '强雷暴伴冰雹', icon: '⛈️', severity: 5 },
};
function wmo(code) {
return WMO[Number(code)] || { label: '未知', icon: '🌡️', severity: 1 };
}
// --------------------------------------------- Photon 类别 -> 目的地类型/标签
// 每一项对应一次 include=osm.<key>.<value> 查询(不需要 q)
const CATEGORIES = [
{ include: 'osm.tourism.attraction', kind: '景点', tags: ['人文历史', '拍照', '观光'] },
{ include: 'osm.tourism.museum', kind: '博物馆', tags: ['人文历史', '亲子', '室内避雨'] },
{ include: 'osm.tourism.gallery', kind: '展馆', tags: ['人文历史', '拍照', '室内避雨'] },
{ include: 'osm.tourism.viewpoint', kind: '观景地', tags: ['自然风光', '拍照', '徒步登山'] },
{ include: 'osm.tourism.theme_park', kind: '主题乐园', tags: ['亲子', '主题乐园'] },
{ include: 'osm.tourism.zoo', kind: '动物园', tags: ['亲子', '自然风光'] },
{ include: 'osm.leisure.park', kind: '公园', tags: ['自然风光', '休闲', '亲子'] },
{ include: 'osm.leisure.garden', kind: '园林', tags: ['人文历史', '休闲', '拍照'] },
{ include: 'osm.leisure.nature_reserve', kind: '自然保护地', tags: ['自然风光', '徒步登山'] },
{ include: 'osm.natural.peak', kind: '山峰', tags: ['自然风光', '徒步登山', '拍照'] },
{ include: 'osm.natural.beach', kind: '海滨', tags: ['亲水海滨', '自然风光', '拍照'] },
{ include: 'osm.historic.castle', kind: '古迹', tags: ['人文历史', '古镇', '拍照'] },
{ include: 'osm.amenity.place_of_worship', kind: '寺观', tags: ['人文历史', '静心', '拍照'] },
{ include: 'osm.boundary.national_park', kind: '风景区', tags: ['自然风光', '徒步登山', '拍照'] },
];
const INTERESTS = [
'自然风光', '人文历史', '亲子', '拍照', '美食',
'徒步登山', '室内避雨', '亲水海滨', '古镇', '主题乐园', '休闲', '小众秘境',
];
// 明显不是「目的地」的设施名,检索结果里剔除
const JUNK_NAME = /(停车场|厕所|卫生间|售票|游客中心|管理处|管理中心|出入口|入口|出口|公交站|地铁站|加油站|派出所|医院|学校|办公|宿舍|仓库|变电站|公厕|ATM|自动售货|候车|服务区|收费站|bridge|Bridge)/;
// OSM 里常见的无辨识度地名(土堆、观景台、未命名山峰等),不适合作为推荐目的地
const POOR_NAME = /^(土堆|土丘|山丘|小土包|无名|未命名|无名称|观景台|瞭望台|望台|平台|山顶|山峰|山头|碑|石碑|界碑|标记|标记点|点|路口|桥|桥头|河|沟|渠|村|庄|地|块|遗址|旧址|某处|unknown|unnamed|viewpoint|peak|summit|mountain)$/i;
// 「名字像景点、实际不是独立出行目的地」的点位。
// OSM 里这类条目辨识度很高(有名字、有范围),会把真正值得去的地方挤下去,
// 例如燕京八景中的几处只是小公园或一块碑,外国使馆旧址多为办公建筑。
// 仅用于实时检索来源(OSM / 高德),不影响内置景区与内置小众地点库。
const LOW_VALUE_NAME = /(金台夕照|蓟门烟树|卢沟晓月|太液秋风|琼岛春阴|玉泉趵突|西山晴雪|居庸叠翠|使馆旧址|使馆$|墓和祠|纪念碑$|纪念塔$|界桩$|上马石$|下马石$)/;
// ------------------------------------------ 兜底数据:国内知名目的地(经纬度)
// 用途:① Photon 不可用时保证仍有结果;② 始终补入若干知名目的地,提升清单可读性。
// 字段:名称, 纬度, 经度, 类型, 标签
const CURATED_BASE = [
['故宫博物院', 39.9163, 116.3972, '人文历史', '人文历史,拍照,室内避雨'],
['天坛公园', 39.8822, 116.4066, '公园', '人文历史,拍照,休闲'],
['颐和园', 39.9999, 116.2755, '园林', '人文历史,拍照,休闲'],
['八达岭长城', 40.3564, 116.0169, '古迹', '人文历史,徒步登山,拍照'],
['慕田峪长城', 40.4319, 116.5695, '古迹', '人文历史,徒步登山,拍照'],
['香山公园', 39.9960, 116.1896, '自然风光', '自然风光,徒步登山,拍照'],
['北京环球度假区', 39.8508, 116.6767, '主题乐园', '亲子,主题乐园'],
['798艺术区', 39.9828, 116.4905, '展馆', '人文历史,拍照,室内避雨'],
['中国国家博物馆', 39.9037, 116.4018, '博物馆', '人文历史,亲子,室内避雨'],
['古北水镇', 40.6883, 117.2764, '古镇', '古镇,人文历史,拍照'],
['十渡风景区', 39.6472, 115.5883, '风景区', '自然风光,亲水海滨,徒步登山'],
['五大道', 39.1167, 117.2000, '人文历史', '人文历史,拍照,休闲'],
['盘山', 40.0889, 117.2500, '山峰', '自然风光,徒步登山,拍照'],
['承德避暑山庄', 40.9975, 117.9364, '园林', '人文历史,休闲,拍照'],
['北戴河海滨', 39.8167, 119.4833, '海滨', '亲水海滨,自然风光,休闲'],
['山海关', 40.0089, 119.7536, '古迹', '人文历史,拍照'],
['白洋淀', 38.8500, 115.9833, '风景区', '自然风光,亲水海滨,休闲'],
['野三坡', 39.6833, 115.4333, '风景区', '自然风光,徒步登山'],
['正定古城', 38.1458, 114.5750, '古镇', '古镇,人文历史,拍照'],
['平遥古城', 37.2011, 112.1761, '古镇', '古镇,人文历史,拍照'],
['云冈石窟', 40.1106, 113.1222, '古迹', '人文历史,拍照'],
['五台山', 38.9833, 113.5833, '山峰', '自然风光,徒步登山,人文历史'],
['泰山', 36.2558, 117.1008, '山峰', '自然风光,徒步登山,拍照'],
['趵突泉', 36.6608, 117.0142, '公园', '自然风光,休闲,拍照'],
['曲阜三孔', 35.5917, 116.9886, '古迹', '人文历史,拍照'],
['青岛栈桥', 36.0597, 120.3128, '海滨', '亲水海滨,拍照,休闲'],
['崂山', 36.1500, 120.6333, '山峰', '自然风光,徒步登山,亲水海滨'],
['龙门石窟', 34.5589, 112.4714, '古迹', '人文历史,拍照'],
['少林寺', 34.5086, 113.0031, '寺观', '人文历史,拍照'],
['清明上河园', 34.8000, 114.3500, '主题乐园', '人文历史,亲子,主题乐园'],
['秦始皇兵马俑', 34.3853, 109.2785, '古迹', '人文历史,亲子,室内避雨'],
['华山', 34.4833, 110.0833, '山峰', '自然风光,徒步登山,拍照'],
['中山陵', 32.0617, 118.8486, '古迹', '人文历史,休闲'],
['拙政园', 31.4900, 120.6294, '园林', '人文历史,拍照,休闲'],
['周庄古镇', 31.1236, 120.8500, '古镇', '古镇,人文历史,拍照'],
['鼋头渚', 31.5333, 120.2333, '风景区', '自然风光,亲水海滨,拍照'],
['上海外滩', 31.2400, 121.4900, '人文历史', '人文历史,拍照,休闲'],
['上海迪士尼', 31.1434, 121.6570, '主题乐园', '亲子,主题乐园'],
['杭州西湖', 30.2424, 120.1481, '风景区', '自然风光,拍照,休闲'],
['乌镇', 30.7461, 120.4889, '古镇', '古镇,人文历史,拍照'],
['千岛湖', 29.6000, 118.9833, '风景区', '自然风光,亲水海滨,休闲'],
['普陀山', 30.0000, 122.3833, '寺观', '人文历史,亲水海滨,自然风光'],
['黄山', 30.1333, 118.1667, '山峰', '自然风光,徒步登山,拍照'],
['宏村', 29.9000, 117.9833, '古镇', '古镇,人文历史,拍照'],
['鼓浪屿', 24.4489, 118.0672, '海滨', '亲水海滨,人文历史,拍照'],
['武夷山', 27.7167, 117.9833, '山峰', '自然风光,徒步登山,亲水海滨'],
['黄鹤楼', 30.5450, 114.3030, '古迹', '人文历史,拍照'],
['武当山', 32.4000, 111.0000, '山峰', '自然风光,徒步登山,人文历史'],
['张家界国家森林公园', 29.3167, 110.4833, '风景区', '自然风光,徒步登山,拍照'],
['九寨沟', 33.2500, 103.9167, '风景区', '自然风光,拍照,亲水海滨'],
['都江堰', 31.0000, 103.6167, '古迹', '人文历史,自然风光'],
['青城山', 30.9000, 103.5667, '山峰', '自然风光,徒步登山,人文历史'],
['洪崖洞', 29.5630, 106.5830, '人文历史', '人文历史,拍照,美食'],
['白云山', 23.1833, 113.3000, '山峰', '自然风光,徒步登山,休闲'],
['丹霞山', 25.0333, 113.7500, '风景区', '自然风光,徒步登山,拍照'],
['阳朔漓江', 24.7833, 110.4833, '风景区', '自然风光,亲水海滨,拍照'],
['大理古城', 25.6911, 100.1600, '古镇', '古镇,人文历史,休闲'],
['洱海', 25.7500, 100.1833, '风景区', '自然风光,亲水海滨,拍照'],
['丽江古城', 26.8667, 100.2333, '古镇', '古镇,人文历史,拍照'],
['黄果树瀑布', 25.9833, 105.6667, '风景区', '自然风光,亲水海滨,拍照'],
['亚龙湾', 18.2167, 109.6500, '海滨', '亲水海滨,自然风光,休闲'],
['沈阳故宫', 41.7997, 123.4539, '古迹', '人文历史,拍照'],
['长白山天池', 42.0000, 128.0667, '山峰', '自然风光,徒步登山,拍照'],
['青海湖', 36.8833, 100.1833, '风景区', '自然风光,亲水海滨,拍照'],
['莫高窟', 40.0417, 94.8000, '古迹', '人文历史,室内避雨,拍照'],
['布达拉宫', 29.6578, 91.1175, '古迹', '人文历史,拍照'],
];
const CURATED = [...CURATED_BASE, ...EXTRA_SCENIC];
module.exports = { WMO, wmo, CATEGORIES, INTERESTS, JUNK_NAME, POOR_NAME, LOW_VALUE_NAME, CURATED, CN_CITIES, NICHE_SPOTS };