详细技术介绍与功能架构
AstroDaily-cn 🌌 | 每日星图
基于 NASA APOD、AI 多语言翻译与阿里云边缘计算的现代沉浸式天文观测应用
📖 项目简介
AstroDaily-cn(每日星图) 是一个设计精致、性能优异的深空天文观测 Web 应用。每天自动抓取 NASA APOD(Astronomy Picture of the Day,每日天文一图),利用前沿大语言模型(Groq / Gemini / 混元)自动生成 8 种语言的通俗天文科普解析,并通过阿里云边缘安全加速(ESA Pages + Edge Routine + 边缘 KV)与 OSS 对象存储实现低延迟、高可靠的全球快速分发。
无论是作为日常天文爱好者探索宇宙的窗口,还是作为个人桌面/手机壁纸来源,每日星图都能带来极致的沉浸体验。
✨ 核心功能
🌌 观测与探索
- 🖼️ NASA 天文图片与高清画质:每日自动同步 APOD 原版数据,提供标清缩略展示与高清原图预览/下载。
- 🎥 动态视频媒体支持:无缝支持 NASA 发布的科普视频(YouTube 嵌入播放、MP4 边缘代理与原生下载)。
- 🎲 随机漫游 (Cosmic Odyssey):一键跨越时空,随机跃迁至历史上的某一个星空奇迹。
- 📅 天文日历导航:按日期自由穿梭,具备可用日期高亮指示与一键直达“今日最新”功能。
- ⏱️ 智能时区校准:自动计算 NASA 美东发布时间与用户本地时区的时差转换,确保日期显示精准无误。
🎨 沉浸与交互
- 🎬 全屏幻灯片 (Slideshow):支持沉浸式自动放映模式,可调节播放方向、暂停/播放与播放间隔。
- 📱 壁纸设备实时模拟:提供 Desktop 桌面、Tablet 平板、Mobile 手机三种视口的实时壁纸适配效果预览。
- 💌 星空分享卡片生成:内置 Canvas 引擎,动态渲染排版典雅的高清分享图,支持一键复制到剪贴板或下载 PNG。
- ❤️ 航行日志与本地收藏:本地持久化保存喜爱的观测记录,支持 JSON 格式日志导出备份与随时导入恢复。
- 🌓 明暗双主题:深度调校的深空深色模式与典雅浅色模式,一键无缝切换。
- ⌨️ 快捷键支持:
←/→:切换前一日 / 后一日观测空格键:开启 / 暂停全屏幻灯片放映Esc:退出全屏沉浸模式与弹窗
🛡️ 可用性与边缘容灾
- ⚡ 全球边缘极速访问:通过阿里云 ESA 边缘计算,元数据由最近的边缘节点读取,静态资源毫秒级响应。
- 🛡️ 双层降级容灾自愈:请求日期未缓存时自动回退就近可用历史记录;完全冷启动或网络故障时呈现交互式太空引导页,绝不白屏。
- 🌐 无感跨域代理:边缘函数拦截 OSS 默认下载头,强制转换为
inline内联展示,解决国内直接访问 OSS 的排版与防盗链难题。
🏗️ 系统架构
本项目采用存算分离与边缘加速的现代 Serverless 架构设计:
┌────────────────────────────────────────────────────────────────────────┐
│ 用户浏览器 │
│ React 19 SPA (Vite + Tailwind CSS 4 + Lucide Icons + Motion) │
│ ↓ 请求 /api/apod/metadata, /api/image-proxy │
├────────────────────────────────────────────────────────────────────────┤
│ 阿里云 ESA (边缘安全加速) │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ ESA Pages (静态资源托管) + Edge Routine 边缘函数 (src/entry.js) │ │
│ │ ├─ /api/apod/metadata → 读取 ESA KV 边缘键值缓存 │ │
│ │ ├─ /api/image-proxy → 代理/重定向至 OSS,覆写 Content-Disp │ │
│ │ └─ /api/video-proxy → 代理视频流与附件下载 │ │
│ └───────────────┬───────────────────────────────┬────────────────┘ │
│ │ │ │
│ ┌─────▼─────┐ ┌─────▼─────┐ │
│ │ ESA KV │ │ 阿里云 │ │
│ │ 元数据存储 │ │ OSS 存储桶 │ │
│ │(180天 TTL)│ │(180天生命) │ │
│ └───────────┘ └───────────┘ │
├────────────────────────────────────────────────────────────────────────┤
│ 阿里云 ECS 虚拟主机 (Crontab) │
│ Python 同步流水线 (sync_nasa_to_aliyun.py) │
│ 1. 定时拉取 NASA APOD API 原始数据 │
│ 2. 调用 Groq AI (llama-3.3-70b) 高速并发翻译 7 国语言 │
│ 3. 下载图片/视频并直传阿里云 OSS │
│ 4. 组装元数据与 OSS URL 写入 ESA KV,自动剪裁保持 180 天目录索引 │
└────────────────────────────────────────────────────────────────────────┘
技术栈一览
| 模块 | 技术选型 | 说明 |
|---|---|---|
| 前端视图 | React 19 + TypeScript + Motion | 现代响应式 UI 与优雅微交互动效 |
| 前端样式 | Tailwind CSS 4 + Lucide React | 极简、现代的深空美学与丰富图标集 |
| 构建体系 | Vite 6 + esbuild | 极速冷启动与热重载,生产代码极度精简 |
| 边缘计算 | 阿里云 DCDN ESA Edge Routine | ES 模块标准边缘函数,负责 API 路由与 OSS 代理 |
| 元数据存储 | 阿里云 ESA KV | 全球分布式边缘键值,单键 ~11KB,配置 180 天相对 TTL |
| 媒体存储 | 阿里云 OSS (对象存储) | 公共读 Bucket,承载高清大图与视频,配置 180 天生命周期规则 |
| AI 翻译引擎 | Groq (llama-3.3-70b-versatile) | 极速推理,平均 1~2 秒完成全语言高质量专业天文学翻译 |
| 备选 AI | 腾讯混元 (hy-mt2-pro) / Gemini 2.0 | 提供混元脚本变体与本地开发 Gemini 支持 |
| 本地服务 | Node.js + Express + tsx | 本地开发集成环境,内置 NASA API 直接调用与文件缓存 |
📂 项目结构说明
AstroDaily-cn/
├── src/ # 前端源码
│ ├── App.tsx # 应用核心逻辑(状态管理、媒体渲染、幻灯片、快捷键等)
│ ├── main.tsx # React DOM 挂载入口
│ ├── types.ts # TypeScript 类型定义与多语言 UI 静态词典
│ ├── index.css # 全局样式与 Tailwind 指令
│ ├── entry.js # 阿里云 ESA Edge Routine 边缘 API 入口
│ └── components/ # 核心功能组件
│ ├── Header.tsx # 顶部操作栏(多语言切换、深浅主题、收藏夹入口、免责声明)
│ ├── CalendarPopover.tsx # 交互式日历弹窗(支持可用日期高亮与快速年月翻转)
│ ├── StarfieldLoader.tsx # 优雅的星空十字准星加载动效与进度条
│ ├── WallpaperPreview.tsx # 多端设备壁纸模拟预览(桌面/平板/手机)
│ ├── ShareCardModal.tsx # Canvas 动态生成与导出高清星空分享卡片
│ ├── FavoritesManager.tsx # 本地收藏夹管理器(支持 JSON 导出/导入)
│ └── DisclaimerModal.tsx # 多语言免责声明与 NASA 版权说明对话框
│
├── api/
│ └── index.ts # 本地开发与备选 Node.js Express 后端路由
│
├── server.ts # 本地集成开发服务器(Vite HMR 中间件 + Express)
│
├── sync_nasa_to_aliyun.py # 【核心】阿里云云端定时同步脚本(NASA → Groq → OSS + ESA KV)
├── sync_nasa_to_aliyun_hy-mt2-pro.py # 阿里云同步脚本变体(采用腾讯混元模型)
├── fetch_nasa_apod_groq.py # 本地离线抓取工具(仅拉取并使用 Groq 翻译到本地 nasa_data)
├── fetch_nasa_apod_hy-mt2-pro.py # 本地离线抓取工具(腾讯混元变体)
├── upload_to_aliyun.py # 本地数据补录工具(将本地 nasa_data 目录批量推送到 OSS/KV)
├── upload_to_kv_patched.py # 历史补丁工具(Cloudflare 迁移遗留参考)
│
├── nasa_data/ # 本地抓取/缓存的 APOD 数据集(按 YYYY-MM-DD 归档)
├── assets/ # 静态资源与媒体
│
├── Aliyun_Deployment_Guide.md # 阿里云保姆级部署指南(OSS/KV/RAM/ECS 全流程)
├── DEVNOTES.md # 开发与架构踩坑笔记(SPA 回退/OSS 代理/CORS)
├── esa.jsonc # 阿里云 ESA Pages 部署配置文件
├── vercel.json # Vercel 备选部署配置文件
├── vite.config.ts # Vite 6 构建配置
├── tsconfig.json # TypeScript 编译配置
├── package.json # NPM 项目依赖与构建指令
└── .env.example # 环境变量配置模板
🚀 快速开始
1. 环境准备
- Node.js:18.0.0 或更高版本
- npm:9.0.0 或更高版本
- Python(可选,仅运行同步脚本需要):3.8+ 及对应依赖
2. 安装项目依赖
# 克隆仓库
git clone https://github.com/misterye/AstroDaily-cn.git
cd AstroDaily-cn
# 安装前端依赖
npm install
3. 配置本地环境变量
复制模板并按需填写:
cp .env.example .env
.env 配置文件说明:
# NASA API 密钥(可选,不填默认使用官方 DEMO_KEY,限额 30~50次/小时)
NASA_API_KEY="YOUR_NASA_API_KEY"
# Google Gemini API 密钥(本地开发模式下若需要实时 AI 翻译则配置)
GEMINI_API_KEY="YOUR_GEMINI_API_KEY"
💡 提示:即使不配置任何 API Key,本地开发服务器依然能够启动并正常工作(系统会自动启用容灾演示数据集与 DEMO_KEY)。
4. 启动本地开发服务
npm run dev
启动后在浏览器打开 http://localhost:3000 即可开始体验!
🛠️ NPM 指令一览
| 指令 | 说明 | 适用场景 |
|---|---|---|
npm run dev |
启动开发服务器(Vite 实时热重载 + 本地 Express 代理) | 本地功能开发与调试 |
npm run build |
完整构建前端(dist/)和后端服务端(dist/server.cjs) |
生产全栈部署 / Docker |
npm run build:pages |
仅构建前端静态资源至 dist/ 目录 |
阿里云 ESA Pages 部署(推荐) |
npm run start |
运行生产编译后的 Node.js 服务 | 本地测试生产包 |
npm run clean |
清除 dist 构建产物和临时生成物 |
构建缓存清理 |
npm run lint |
执行 TypeScript 静态类型检查(tsc --noEmit) |
CI/CD 与提交前检查 |
🌐 部署指南
方案 A:阿里云 ESA Pages + OSS(推荐生产环境 ⭐)
本项目生产环境完全运行在阿里云基础设施上,具有国内访问延迟低、全球多节点 CDN 加速和免运维等优势。
- 前端与 API:通过 ESA Pages 部署前端静态包,API 请求交由
src/entry.js边缘函数处理。 - 存储:ESA KV 承载元数据(180 天 TTL),OSS 承载大图与视频(配置 180 天生命周期)。
- 同步:ECS 定时任务执行 Python 脚本拉取并同步。
👉 点击查阅:阿里云保姆级部署指南 (Aliyun_Deployment_Guide.md)(包含创建 Bucket、跨域 CORS 配置、RAM 授权、ESA KV 创建、Crontab 配置的详尽步骤)。
esa.jsonc 配置文件:
{
"name": "astrodaily-cn",
"entry": "./src/entry.js", // 边缘函数入口
"buildCommand": "npm run build:pages", // 静态构建指令
"assets": {
"directory": "./dist",
"notFoundStrategy": "singlePageApplication" // SPA 路由回退
}
}
方案 B:Vercel(备用方案)
项目包含 vercel.json,可一键部署至 Vercel:
npm i -g vercel
vercel
在 Vercel 仪表盘中配置环境变量:
NASA_API_KEYGEMINI_API_KEY
方案 C:Docker 容器化部署
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
ENV NODE_ENV=production
EXPOSE 3000
CMD ["npm", "start"]
docker build -t astrodaily-cn .
docker run -d -p 3000:3000 \
-e NASA_API_KEY="your_key" \
-e GEMINI_API_KEY="your_key" \
--name astrodaily astrodaily-cn
🔌 API 接口规范
前端与边缘函数(src/entry.js)及本地后端(api/index.ts)完全解耦,支持以下标准化 RESTful 端点:
1. 获取 APOD 元数据
GET /api/apod/metadata(或重定向入口 GET /api/apod)
-
请求参数:
date(string,可选):目标日期,格式YYYY-MM-DD。缺省时自动返回最新已发布的记录。
-
成功响应示例 (200 OK):
{ "date": "2026-07-05", "title": "M27: The Dumbbell Nebula", "explanation": "The first hint of what will become of our Sun was discovered...", "url": "https://astrodaily-assets.oss-cn-shanghai.aliyuncs.com/media/2026-07-05/image_standard.jpg", "hdurl": "https://astrodaily-assets.oss-cn-shanghai.aliyuncs.com/media/2026-07-05/image_hd.jpg", "media_type": "image", "copyright": "Francesco Antonucci", "translations": { "zh-CN": { "title": "M27:哑铃星云", "explanation": "..." }, "zh-TW": { "title": "M27:啞鈴星雲", "explanation": "..." }, "ja": { "title": "M27:亜鈴状星雲", "explanation": "..." }, "ko": { "title": "...", "explanation": "..." }, "de": { "title": "...", "explanation": "..." }, "fr": { "title": "...", "explanation": "..." }, "es": { "title": "...", "explanation": "..." }, "en": { "title": "M27: The Dumbbell Nebula", "explanation": "..." } }, "from_cache": true, "available_dates": ["2026-07-05", "2026-07-04", "..."] }
2. 边缘图片代理与下载
GET /api/image-proxy
- 功能:由边缘函数反向代理阿里云 OSS 图片。解决直接请求 OSS 默认域名时强制下载的问题,并处理前端 Canvas 跨域绘制。
- 请求参数:
date(string,必须):YYYY-MM-DDtype(string,必须):standard(标清)或hd(高清原图)download(boolean,可选):为true时响应头附加Content-Disposition: attachment; filename="NASA-APOD-...",触发浏览器原生另存为。
3. 视频代理与下载
GET /api/video-proxy
- 功能:针对
media_type === "video"的 APOD 内容,提供 MP4 视频媒体流代理或重定向至原始视频载荷。 - 请求参数:
date(string,必须):YYYY-MM-DDtype(string,可选):standard或hd,默认standarddownload(boolean,可选):为true时强制附带视频文件下载响应头。
4. 边缘图片预热(Prewarm)
GET /api/apod/prepare-image
- 功能:用于前端客户端提前向边缘节点发起预加载与缓存命中探测。
🔄 数据同步流水线 (Python)
数据同步通过运行在阿里云 ECS 上的 Python 脚本全自动执行。
1. Python 环境与依赖
pip install requests yt-dlp oss2 alibabacloud_esa20240910 alibabacloud_tea_openapi
⚠️ 注意:
yt-dlp是解析与下载 NASA 官方每日视频必须的依赖组件;oss2与alibabacloud_esa20240910为阿里云官方 SDK。
2. 同步脚本命令与参数
主线脚本为 sync_nasa_to_aliyun.py:
# 1. 抓取并同步今天的数据(美东时间当前自然日)
python sync_nasa_to_aliyun.py
# 2. 同步指定历史日期的天文数据
python sync_nasa_to_aliyun.py --date 2026-07-05
# 3. 批量同步最近 N 天的数据(回溯近半个月)
python sync_nasa_to_aliyun.py --days 15
# 4. 强制覆盖已同步记录(忽略 aliyun_synced 标记重新拉取并更新)
python sync_nasa_to_aliyun.py --date 2026-07-05 --force
3. 配置 Crontab 定时自动运行
NASA 通常在美东时间午夜 00:00~01:00(即北京时间当天 13:00~14:00)更新当日天文一图。建议在 ECS 上设置每日 14:00 自动拉取最近 3 天数据:
crontab -e
添加以下定时任务:
# 每日北京时间 14:00 自动执行同步,输出追加记录至日志
0 14 * * * cd /data/AstroDaily-cn && /usr/bin/python3 sync_nasa_to_aliyun.py --days 3 >> /data/AstroDaily-cn/apod_data_handle_log.txt 2>&1
4. 辅助维护脚本说明
upload_to_aliyun.py:如果本地磁盘的nasa_data/目录已有此前抓取好的历史数据,可运行该脚本一次性全部批量推送到 OSS 和 ESA KV。fetch_nasa_apod_groq.py:仅在本地抓取 APOD 数据并通过 Groq 翻译保存到本地,适合单机测试或完全离线使用场景。sync_nasa_to_aliyun_hy-mt2-pro.py:采用腾讯混元 AI 大模型作为翻译引擎的变体脚本。
🌍 多语言支持矩阵
每日星图从 UI 界面交互到每日科普内容,全面适配以下 8 种语言:
| 语言代码 | 语言名称 | 地区 | 翻译模型 | 时区对应 |
|---|---|---|---|---|
zh-CN |
简体中文 | 中国大陆 | Groq / 混元 | Asia/Shanghai |
zh-TW |
繁體中文 | 港澳台地区 | Groq / 混元 | Asia/Taipei |
en |
English | 美国/全球 | 原始 NASA 文案 | America/New_York |
ja |
日本語 | 日本 | Groq / 混元 | Asia/Tokyo |
ko |
한국어 | 韩国 | Groq / 混元 | Asia/Seoul |
de |
Deutsch | 德国/欧洲 | Groq / 混元 | Europe/Berlin |
fr |
Français | 法国/欧洲 | Groq / 混元 | Europe/Paris |
es |
Español | 西班牙/拉美 | Groq / 混元 | Europe/Madrid |
🔧 常见故障排查 (Troubleshooting)
1. 点击下载按钮时,下载的是一个几百字节的 HTML 文件?
- 根因:使用了
<a download>标签触发下载。在静态单页应用(SPA)托管环境下,浏览器发出的属于导航请求(Navigation Request),被 ESA Pages 的notFoundStrategy: "singlePageApplication"策略拦截并重定向返回了index.html。 - 解决方式:项目中已全面改造为
fetch()请求子资源 +URL.createObjectURL(blob)方案触发原生下载。详见 开发踩坑笔记 (DEVNOTES.md)。
2. 在前端使用 Canvas 生成分享图时提示跨域错误(Tainted Canvas)?
- 根因:OSS Bucket 未开放跨域访问,或跨域规则未暴露
Content-Length、ETag等头。 - 解决方式:登录阿里云 OSS 控制台 -> 数据安全 -> 跨域设置 (CORS),允许
*或前端域名,并确保 Method 勾选了GET和OPTIONS。
3. 直接通过 OSS 链接打开图片却自动弹出了浏览器下载窗口?
- 根因:阿里云 OSS 默认域名强制绑定了
Content-Disposition: attachment。 - 解决方式:前端所有媒体渲染均通过 ESA Edge Routine 边缘路由
/api/image-proxy,边缘函数已将响应头覆写为Content-Disposition: inline。
4. AI 翻译失败或超时?
- 翻译流程具备完全的非阻塞与容错机制。若 Groq/Gemini 接口限流或超时,系统将自动回退展示 NASA 英文原文,不影响元数据与媒体资产的正常入库。
📄 软件协议
本项目基于 MIT License 开源发布。
🙏 致谢与灵感
- NASA APOD (Astronomy Picture of the Day) — 感谢 NASA 及其贡献天文学家每日带来的无与伦比的宇宙视野。
- Groq — 极速的 LPU 推理架构,赋予项目闪电般的多语言本地化翻译能力。
- Alibaba Cloud 阿里云 — 提供高速稳定的 ESA 边缘安全加速与 OSS 基础设施。
- Lucide Icons — 典雅轻量的现代矢量图标。
探索浩瀚星空,记录宇宙心跳 · Made with ❤️ for Stargazers Everywhere
