Files
tamakyi c5c2ffae68 TripSense 行知 · 周边出行顾问:首版
零依赖 Node 服务,三步流程(选出发地 → 分析候选 → 生成方案 + 路线图 + 住宿参考)。

- 候选发现:高德 place/text 类型词跨城检索 + 内置景区/城市/小众库 + Photon 兜底
- 区县级「排除同城」判定(adname),过滤发生在轮转取样之前
- 路线图画的是 AI 方案里实际安排的每个地点,按正文顺序编号 + 虚线动线 + 真实高德底图
- 住宿:RollingGo 只读 CLI 取实时报价,无价格源时如实标注不编造
- 服务端内存缓存(指纹 + TTL + LRU),数据源层与 HTTP 层分别缓存
- 上下文瘦身:逐日天气只给 rank1,紧凑 JSON,实测约 1335 token
2026-11-05 20:25:03 +08:00

153 lines
11 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'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 };