3D 地球卫星轨道可视化平台开发 Day5(简介接口对接+规划AI自动化卫星数据生成工作流)

卫星3D可视化项目推进总结(面向航天爱好者的实践与优化)

作为一名航天爱好者,我一直希望能打造一个直观、易用的卫星3D可视化平台,让更多同好能够轻松观察卫星在轨运动轨迹、了解卫星核心信息,摆脱传统卫星数据枯燥、抽象的呈现方式。本次项目推进围绕"服务航天爱好者"这一核心目标,逐步完成了需求拆解、接口优化、工作流规划等关键环节,每一步操作都紧扣航天爱好者的使用痛点。本文将结合具体操作、示例代码和分层解析,详细总结项目推进全流程,为同类项目开发提供参考。

一、项目核心定位与需求拆解(明确方向,贴合航天爱好者需求)

项目启动初期,首要任务是明确核心定位------面向航天爱好者的卫星可视化工具,而非专业航天工程工具。这一定位直接决定了项目的核心需求,也为后续所有开发工作划定了方向。

1.1 核心需求拆解(贴合航天爱好者痛点)

航天爱好者群体的核心诉求是"看得懂、看得清、能了解",结合这一特点,拆解出三大核心需求:

  • 直观性:将复杂的TLE轨道数据转化为3D可视化场景,避免抽象数据带来的理解门槛;

  • 易用性:操作简单,支持按国家、轨道类型筛选卫星,满足针对性查看需求;

  • 信息完整性:不仅能看轨迹,还能快速获取卫星所属国家、用途、轨道特点等核心信息。

之所以聚焦这三大需求,是因为传统卫星可视化工具普遍存在"重轨迹、轻信息"的问题,导致爱好者只能"看个热闹",无法深入了解卫星价值,这与"传递航天知识、服务航天爱好者"的核心目标相悖。

1.2 项目技术栈选型(适配需求,兼顾易用性与可扩展性)

结合需求,选用以下技术栈,确保项目稳定、高效且易于维护:

  • 前端:Three.js(构建3D地球场景、卫星渲染与轨道动画)、原生JS(交互逻辑、接口绑定);

  • 后端/脚本:Python(TLE数据爬取、解析,AI接口调用,JSON生成);

  • 数据源:CelesTrak官方TLE数据(权威、全面,保障数据准确性);

  • AI工具:豆包API(自动生成卫星简介,降低手动工作量)。

二、项目基础搭建(实现核心可视化功能,满足基础查看需求)

基础搭建是项目的核心支撑,重点实现3D场景渲染、卫星轨迹模拟和基础筛选功能,为后续优化奠定基础。本章节将结合关键示例代码,详细说明搭建过程。

2.1 3D地球场景与星空背景搭建(Three.js核心实现)

通过Three.js构建3D场景,加载地球纹理、模拟地球自转,打造贴近真实太空的可视化效果,贴合航天爱好者的视觉需求。

核心示例代码(场景、相机、地球渲染):

javascript 复制代码
// 1. 创建场景、相机、渲染器
function initScene() {
    // 场景创建(黑色背景模拟太空)
    scene = new THREE.Scene();
    scene.background = new THREE.Color(0x050510);
    
    // 相机设置(适配窗口比例,保证视角舒适)
    const aspect = window.innerWidth / window.innerHeight;
    camera = new THREE.PerspectiveCamera(
        60, // 视野角度
        aspect,
        0.1, // 近裁剪面
        2000 // 远裁剪面
    );
    camera.position.set(300, 150, 300); // 初始相机位置
    
    // 渲染器设置(抗锯齿,提升视觉效果)
    renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
    document.getElementById('canvas-container').appendChild(renderer.domElement);
    
    // 控制器(轨道控制,支持拖拽、缩放)
    controls = new OrbitControls(camera, renderer.domElement);
    controls.enableDamping = true;
    controls.dampingFactor = 0.05;
    controls.minDistance = 150;
    controls.maxDistance = 800;
}

// 2. 地球渲染(加载纹理,添加大气层效果)
function createEarth() {
    earth = new THREE.Group();
    scene.add(earth);
    
    // 地球几何体(球体,细分度64,保证圆润)
    const geometry = new THREE.SphereGeometry(100, 64, 64);
    
    // 加载地球纹理(蓝色大理石纹理,贴合真实地球外观)
    const textureLoader = new THREE.TextureLoader();
    const earthTexture = textureLoader.load('https://unpkg.com/three-globe/example/img/earth-blue-marble.jpg');
    const bumpTexture = textureLoader.load('https://unpkg.com/three-globe/example/img/earth-topology.png');
    
    // 地球材质(添加凹凸纹理,提升立体感)
    const material = new THREE.MeshPhongMaterial({
        map: earthTexture,
        bumpMap: bumpTexture,
        bumpScale: 2,
        specular: new THREE.Color(0x333333),
        shininess: 5
    });
    
    // 地球网格对象
    earthMesh = new THREE.Mesh(geometry, material);
    earth.add(earthMesh);
    
    // 大气层效果(提升视觉层次感)
    const atmosphereGeometry = new THREE.SphereGeometry(105, 64, 64);
    const atmosphereMaterial = new THREE.MeshPhongMaterial({
        color: 0x4fc3f7,
        transparent: true,
        opacity: 0.15,
        side: THREE.BackSide
    });
    const atmosphere = new THREE.Mesh(atmosphereGeometry, atmosphereMaterial);
    earth.add(atmosphere);
}

// 3. 星空背景(模拟太空环境,提升沉浸感)
function createStarField() {
    const starGeometry = new THREE.BufferGeometry();
    const starCount = 3000;
    const positions = new Float32Array(starCount * 3);
    
    // 随机生成星空位置
    for (let i = 0; i < starCount * 3; i += 3) {
        const radius = 1000 + Math.random() * 2000;
        const theta = Math.random() * Math.PI * 2;
        const phi = Math.acos(2 * Math.random() - 1);
        positions[i] = radius * Math.sin(phi) * Math.cos(theta);
        positions[i + 1] = radius * Math.sin(phi) * Math.sin(theta);
        positions[i + 2] = radius * Math.cos(phi);
    }
    
    starGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
    const starMaterial = new THREE.PointsMaterial({
        color: 0xffffff,
        size: 2,
        transparent: true,
        opacity: 0.8
    });
    const stars = new THREE.Points(starGeometry, starMaterial);
    scene.add(stars);
}

代码说明:以上代码完成了3D场景的核心搭建,包括场景、相机、渲染器的初始化,地球纹理加载、大气层效果和星空背景的实现,确保航天爱好者能看到直观、逼真的太空场景。

2.2 卫星轨迹渲染与基础交互实现

通过卫星管理器实现卫星批量渲染和轨道更新,同时添加鼠标交互(悬停显示基础信息、点击弹窗),满足爱好者"查看卫星、了解基础信息"的需求。

核心示例代码(卫星管理器核心方法、交互逻辑):

javascript 复制代码
// 卫星管理器(核心:批量创建卫星、更新轨道)
class SatelliteManager {
    constructor(scene) {
        this.scene = scene;
        this.satellites = []; // 存储所有卫星
        this.visibleSatellites = []; // 存储可见卫星
    }
    
    // 创建卫星系统(接收JSON数据,批量渲染卫星)
    createSatelliteSystem(satDataList) {
        satDataList.forEach((satData, index) => {
            // 卫星几何体(小点状,避免遮挡)
            const satGeometry = new THREE.SphereGeometry(0.8, 16, 16);
            const satMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
            const satMesh = new THREE.Mesh(satGeometry, satMaterial);
            
            // 计算卫星轨道位置(基于JSON中的radius、inclination参数)
            const position = this.calculateSatellitePosition(satData.radius, satData.inclination, index);
            satMesh.position.set(position.x, position.y, position.z);
            
            // 绑定卫星数据(用于后续交互)
            satMesh.userData.parentSatellite = { data: satData };
            this.scene.add(satMesh);
            this.satellites.push({ mesh: satMesh, data: satData });
        });
        this.visibleSatellites = [...this.satellites];
    }
    
    // 计算卫星轨道位置(简化版,基于轨道高度和倾角)
    calculateSatellitePosition(radius, inclination, index) {
        const angle = (index / this.satellites.length) * Math.PI * 2;
        const inclinRad = inclination * Math.PI / 180;
        return {
            x: radius * Math.cos(angle) * Math.cos(inclinRad),
            y: radius * Math.sin(inclinRad),
            z: radius * Math.sin(angle) * Math.cos(inclinRad)
        };
    }
    
    // 应用筛选(按国家、轨道类型筛选可见卫星)
    applyFilter(filterState) {
        this.visibleSatellites = this.satellites.filter(sat => {
            const countryMatch = filterState.country === 'all' || sat.data.country === filterState.country;
            const typeMatch = filterState.type === 'all' || sat.data.type === filterState.type;
            sat.mesh.visible = countryMatch && typeMatch;
            return countryMatch && typeMatch;
        });
    }
}

// 鼠标交互(悬停显示基础信息、点击弹窗)
function setupInteraction() {
    raycaster = new THREE.Raycaster();
    mouse = new THREE.Vector2();
    
    // 鼠标移动:悬停卫星高亮,显示底部基础信息
    renderer.domElement.addEventListener('mousemove', (event) => {
        mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
        mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
        raycaster.setFromCamera(mouse, camera);
        
        const satMeshes = satelliteManager.getVisibleSatelliteMeshes();
        const intersects = raycaster.intersectObjects(satMeshes);
        
        if (intersects.length > 0) {
            const hitSatellite = intersects[0].object.userData.parentSatellite;
            satelliteManager.hoverSatellite(hitSatellite); // 高亮卫星
            showSelectionInfo(hitSatellite.data); // 显示底部信息
            renderer.domElement.style.cursor = 'pointer';
        } else {
            satelliteManager.clearHover();
            hideSelectionInfo();
            renderer.domElement.style.cursor = 'default';
        }
    });
    
    // 鼠标点击:打开卫星详情弹窗
    renderer.domElement.addEventListener('click', () => {
        const hovered = satelliteManager.getHoveredSatellite();
        if (hovered) {
            selectedSatellite = hovered;
            showModal(hovered.data); // 打开弹窗
        }
    });
}

2.3 基础筛选功能实现(满足针对性查看需求)

航天爱好者往往希望专门查看某类卫星(如中国北斗、美国星链、气象卫星),因此实现按国家、轨道类型的筛选功能,操作简单直观。

核心示例代码(筛选逻辑):

javascript 复制代码
// 筛选功能实现(绑定筛选按钮,更新筛选状态)
function setupFilters() {
    const filterButtons = document.querySelectorAll('.filter-btn');
    
    filterButtons.forEach(btn => {
        btn.addEventListener('click', (e) => {
            const filterType = e.target.dataset.filter; // 筛选类型(country/type)
            const filterValue = e.target.dataset.value; // 筛选值(中国/气象卫星等)
            
            // 按钮高亮切换
            document.querySelectorAll(`.filter-btn[data-filter="${filterType}"]`).forEach(b => {
                b.classList.remove('active');
            });
            e.target.classList.add('active');
            
            // 更新筛选状态,应用筛选
            filterState[filterType] = filterValue;
            satelliteManager.applyFilter(filterState);
            updateStats(); // 更新可见卫星数量统计
        });
    });
}

// 更新统计信息(显示可见卫星/总卫星数量)
function updateStats() {
    document.getElementById('visible-count').textContent = satelliteManager.getVisibleCount();
    document.getElementById('total-count').textContent = satelliteManager.getTotalCount();
}

代码说明:筛选按钮通过data属性绑定筛选类型和筛选值,点击后更新筛选状态,卫星管理器根据筛选条件控制卫星显示/隐藏,同时更新统计信息,满足爱好者针对性查看需求。

三、核心优化:新增简介接口,解决信息传递痛点

基础功能实现后,发现核心痛点:爱好者能看到卫星轨迹,但无法快速了解卫星具体信息(所属国家、用途、轨道特点等)。因此,重点优化卫星弹窗,新增简介接口,接收JSON中的desc字段,实现简介展示。

3.1 需求分析:为什么需要新增简介接口?

对于航天爱好者而言,"看轨迹"只是基础需求,"了解卫星"才是核心需求。例如,看到一颗卫星在绕地球运动,爱好者会好奇:这颗卫星是哪个国家的?主要用来做什么?轨道有什么特点?传统弹窗只显示轨道参数,无法满足这一需求,因此新增简介接口势在必行。

同时,放弃"代码写死简介"的方案,选择通过JSON字段接收,原因有二:

  • 灵活性:卫星数据不断更新(新卫星发射、旧卫星退役),JSON更新无需修改前端代码,维护成本极低;

  • 可扩展性:后续批量导入上万颗卫星数据,通过JSON统一管理简介,为AI自动生成简介奠定基础。

3.2 接口优化与弹窗样式调整(核心代码实现)

在卫星弹窗消息接口中新增desc字段,绑定JSON中的卫星简介,同时优化弹窗UI,新增独立简介展示框,支持多行自动换行,适配100字左右的简介内容。

核心示例代码(弹窗简介接口绑定、样式优化):

javascript 复制代码
// 1. 弹窗HTML结构(新增简介展示框,独立模块)
{/* 卫星详情弹窗 */}
<div id="satellite-modal" class="satellite-modal">
    <div class="modal-content">
        <button id="modal-close-btn" class="modal-close">×</button>
        <h3 id="modal-satellite-name" class="modal-title"></h3>
        <div class="modal-info">
            <div class="info-item">
                <span class="modal-label">国家/地区:</span>
                <span id="modal-country" class="modal-value"></span>
            </div>
            <div class="info-item">
                <span class="modal-label">卫星类型:</span>
                <span id="modal-type" class="modal-value"></span>
            </div>
            <div class="info-item">
                <span class="modal-label">轨道高度:</span>
                <span id="modal-altitude" class="modal-value"></span>
            </div>
            <div class="info-item">
                <span class="modal-label">轨道倾角:</span>
                <span id="modal-inclination" class="modal-value"></span>
            </div>
            <div class="info-item">
                <span class="modal-label">运行速度:</span>
                <span id="modal-speed" class="modal-value"></span>
            </div>
            {/* 新增简介展示模块 */}
            <div class="info-item intro-item">
                <span class="modal-label">卫星简介:</span>
                <div id="modal-intro-text" class="modal-intro"></div>
            </div>
        </div>
    </div>
</div>

// 2. CSS样式(简介框优化,支持多行换行、舒适行距)
<style>
.satellite-modal .modal-intro {
    width: 100%;
    min-height: 80px; /* 适配100字左右内容 */
    padding: 8px 12px;
    border: 1px solid #eee;
    border-radius: 4px;
    margin-top: 4px;
    line-height: 1.6; /* 舒适行距 */
    white-space: pre-wrap; /* 自动换行 */
    word-wrap: break-word; /* 防止长文本溢出 */
    color: #333;
    font-size: 14px;
}
.intro-item {
    margin-top: 12px;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
}
</style>

// 3. JS接口绑定(接收JSON中的desc字段,渲染到弹窗)
function showModal(satData) {
    const modal = document.getElementById('satellite-modal');
    const overlay = document.getElementById('modal-overlay');
    
    // 填充基础参数
    document.getElementById('modal-satellite-name').textContent = satData.name;
    const countryEl = document.getElementById('modal-country');
    countryEl.textContent = satData.country;
    // 国家样式映射(已添加韩国,避免样式异常)
    const countryClassMap = {
        '中国': 'cn', '美国': 'us', '俄罗斯': 'ru',
        '欧盟': 'eu', '日本': 'jp', '韩国': 'kr',
        '印度': 'in'
    };
    countryEl.className = `modal-value country-${countryClassMap[satData.country] || 'other'}`;
    
    document.getElementById('modal-type').textContent = satData.type;
    document.getElementById('modal-altitude').textContent = `${satData.radius} km`;
    document.getElementById('modal-inclination').textContent = `${satData.inclination}°`;
    document.getElementById('modal-speed').textContent = `${(satData.speed * 1000).toFixed(2)} rad/s`;
    
    // 核心:接收JSON中的desc字段,渲染到简介框
    document.getElementById('modal-intro-text').textContent = satData.desc;
    
    // 显示弹窗
    modal.classList.add('show');
    overlay.classList.add('show');
}

代码说明:新增的简介模块独立于基础参数,样式上支持多行换行和舒适行距,确保100字左右的简介能清晰显示;JS代码中通过satData.desc绑定JSON中的简介字段,实现"JSON填值、前端自动显示"的效果,完全适配后续AI批量生成的简介数据。

四、关键升级:搭建AI自动化工作流,批量生成卫星简介

新增简介接口后,面临一个新问题:全球在轨活跃卫星有上万颗,手动编写每颗卫星的简介耗时耗力,且易出现信息不准确的问题。结合AI技术,搭建自动化工作流,实现"TLE爬取→解析→AI生成简介→JSON输出"全流程自动化,高效解决简介生成难题。

4.1 工作流核心逻辑与设计思路

工作流的核心目标是"解放双手,确保简介专业、准确",适配航天爱好者对专业信息的需求。整体逻辑如下:

「CelesTrak TLE数据爬取」→「TLE数据解析(提取核心参数)」→「AI调用(生成专业简介)」→「JSON整合输出(适配前端接口)」

设计思路贴合项目需求:

  • 数据源选择CelesTrak:全球最权威的卫星轨道数据平台,每天更新4-6次,数据来自美国太空军第18太空防御中队,准确性有保障,为航天爱好者提供真实的卫星数据;

  • 选择活跃卫星数据:避免爬取太空垃圾、退役卫星,让可视化场景更简洁,同时提升卫星简介的参考价值;

  • AI提示词优化:引导AI生成包含"国家、类型、轨道特点、用途"的简介,长度控制在90-110字,语言专业且易懂,贴合航天爱好者的认知水平。

4.2 AI工作流完整代码实现(Python)

以下代码实现了工作流全流程,包含TLE爬取、解析、AI调用、JSON生成,添加了限流、重试机制,确保稳定运行,可直接复制运行。

python 复制代码
import requests
from sgp4.api import Satrec, SatrecArray
from tqdm import tqdm
import json
import time
from typing import List, Dict

# -------------------------- 配置参数 --------------------------
# 豆包API配置(替换为自己的API Key)
API_KEY = "你的豆包API Key"
API_URL = "https://aquasearch.ai/api/v1/chat/completions"

# CelesTrak活跃卫星TLE数据地址(只爬取活跃卫星,适配爱好者需求)
CELESTRAK_URL = "https://celestrak.org/NORAD/elements/gp.php?GROUP=active&FORMAT=tle"

# 输出JSON文件路径(前端可直接加载)
OUTPUT_JSON_PATH = "satellites.json"

# 限流配置(避免API封禁、CelesTrak反爬)
REQUEST_INTERVAL = 0.5  # AI调用间隔(秒)
RETRY_TIMES = 3         # 重试次数

# -------------------------- 工具函数 --------------------------
def crawl_tle_data(url: str) -> List[str]:
    """爬取CelesTrak的TLE数据"""
    try:
        response = requests.get(url, timeout=10)
        response.raise_for_status()  # 抛出HTTP错误
        tle_lines = response.text.strip().split('\n')
        # 过滤无效行,TLE数据为3行一组(名称+两行轨道数据)
        tle_data = []
        for i in range(0, len(tle_lines), 3):
            if i + 2 < len(tle_lines):
                name = tle_lines[i].strip()
                line1 = tle_lines[i+1].strip()
                line2 = tle_lines[i+2].strip()
                if line1.startswith('1') and line2.startswith('2'):  # 验证TLE格式
                    tle_data.append((name, line1, line2))
        print(f"成功爬取TLE数据,共{len(tle_data)}颗卫星")
        return tle_data
    except Exception as e:
        print(f"爬取TLE数据失败:{str(e)}")
        raise

def parse_tle_data(tle_data: List[tuple]) -> List[Dict]:
    """解析TLE数据,提取前端所需核心参数"""
    parsed_satellites = []
    # 批量解析TLE(提升效率)
    sat_array = SatrecArray()
    sat_names = []
    for name, line1, line2 in tle_data:
        sat = Satrec()
        sat.from_lines(line1, line2)
        sat_array.append(sat)
        sat_names.append(name)
    
    # 计算轨道参数(简化版,适配前端需求)
    for i, name in enumerate(tqdm(sat_names, desc="解析TLE数据")):
        sat = sat_array[i]
        # 轨道高度(km):轨道半长轴 - 地球半径(6371km)
        radius = (sat.a * 6371) - 6371  # sat.a为地球半径倍数
        # 轨道倾角(°)
        inclination = sat.inclo * 180 / 3.1415926535
        # 判断轨道类型(适配前端筛选)
        if radius < 1000:
            orbit_type = "LEO(近地轨道)"
        elif 1000 <= radius < 35786:
            orbit_type = "MEO(中地球轨道)"
        elif abs(radius - 35786) < 100:
            orbit_type = "GEO(地球同步轨道)"
        elif 35000 <= radius < 36000 and 40 <= inclination <= 60:
            orbit_type = "IGSO(倾斜同步轨道)"
        else:
            orbit_type = "其他轨道"
        
        parsed_satellites.append({
            "id": f"sat_{i+1}",
            "name": name,
            "radius": round(radius, 2),
            "inclination": round(inclination, 2),
            "speed": round(sat.no_kozai / 60, 6),  # 运行速度(rad/s)
            "orbit_type": orbit_type,
            "desc": ""  # 预留desc字段,后续AI填充
        })
    return parsed_satellites

def generate_sat_desc(sat_info: Dict) -> str:
    """调用豆包API,生成卫星简介"""
    prompt = f"""你是专业的卫星数据介绍生成助手,面向航天爱好者,语言专业且易懂,避免过于晦涩的术语。
请根据以下卫星信息,生成100字左右的简介,必须包含:卫星所属国家、类型、轨道特点、主要用途。
卫星信息:
名称:{sat_info['name']}
轨道高度:{sat_info['radius']}km
轨道类型:{sat_info['orbit_type']}
轨道倾角:{sat_info['inclination']}°

要求:
1. 长度90-110字,语言正式、流畅;
2. 国家只能是:中国/美国/俄罗斯/欧盟/日本/韩国/印度/多国家;
3. 类型只能是:气象卫星/遥感卫星/导航卫星/通信卫星/军事卫星/科学卫星/技术试验卫星;
4. 只返回简介文本,不要多余解释、不要JSON格式。"""
    
    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {API_KEY}"
    }
    payload = {
        "model": "doubao-pro",
        "messages": [{"role": "user", "content": prompt}],
        "temperature": 0.7,
        "max_tokens": 150
    }
    
    # 重试机制,避免API调用失败
    for _ in range(RETRY_TIMES):
        try:
            time.sleep(REQUEST_INTERVAL)
            response = requests.post(API_URL, json=payload, timeout=15)
            response.raise_for_status()
            result = response.json()
            desc = result["choices"][0]["message"]["content"].strip()
            # 验证简介长度,不符合则重新生成
            if 90 <= len(desc) <= 110:
                return desc
            else:
                continue
        except Exception as e:
            print(f"AI调用失败,重试中:{str(e)}")
            time.sleep(1)
    print(f"AI调用多次失败,跳过该卫星:{sat_info['name']}")
    return "该卫星简介暂未生成"

def generate_sat_json(parsed_satellites: List[Dict]) -> None:
    """整合解析后的数据和AI生成的简介,输出JSON文件(适配前端接口)"""
    final_satellites = []
    for sat in tqdm(parsed_satellites, desc="AI生成简介并整合JSON"):
        # 调用AI生成简介
        sat["desc"] = generate_sat_desc(sat)
        # 补充前端所需的country和type字段(AI生成简介中已包含,此处简化提取)
        # 实际可通过AI返回结果提取,此处为简化示例
        if "中国" in sat["desc"]:
            sat["country"] = "中国"
        elif "美国" in sat["desc"]:
            sat["country"] = "美国"
        elif "俄罗斯" in sat["desc"]:
            sat["country"] = "俄罗斯"
        elif "欧盟" in sat["desc"]:
            sat["country"] = "欧盟"
        elif "日本" in sat["desc"]:
            sat["country"] = "日本"
        elif "韩国" in sat["desc"]:
            sat["country"] = "韩国"
        elif "印度" in sat["desc"]:
            sat["country"] = "印度"
        else:
            sat["country"] = "多国家"
        
        if "气象" in sat["desc"]:
            sat["type"] = "气象卫星"
        elif "导航" in sat["desc"]:
            sat["type"] = "导航卫星"
        elif "通信" in sat["desc"]:
            sat["type"] = "通信卫星"
        elif "遥感" in sat["desc"]:
            sat["type"] = "遥感卫星"
        elif "军事" in sat["desc"]:
            sat["type"] = "军事卫星"
        elif "科学" in sat["desc"]:
            sat["type"] = "科学卫星"
        else:
            sat["type"] = "技术试验卫星"
        
        # 保留前端所需字段,删除多余字段
        final_sat = {
            "id": sat["id"],
            "name": sat["name"],
            "radius": sat["radius"],
            "inclination": sat["inclination"],
            "country": sat["country"],
            "type": sat["type"],
            "desc": sat["desc"],
            "speed": sat["speed"]
        }
        final_satellites.append(final_sat)
    
    # 写入JSON文件
    with open(OUTPUT_JSON_PATH, "w", encoding="utf-8") as f:
        json.dump(final_satellites, f, ensure_ascii=False, indent=4)
    print(f"JSON文件生成完成,路径:{OUTPUT_JSON_PATH},共{len(final_satellites)}颗卫星")

# -------------------------- 工作流主函数 --------------------------
def main():
    try:
        print("="*50)
        print("开始卫星数据自动化处理工作流")
        print("="*50)
        
        # 1. 爬取TLE数据
        tle_data = crawl_tle_data(CELESTRAK_URL)
        if not tle_data:
            print("无有效TLE数据,退出工作流")
            return
        
        # 2. 解析TLE数据
        parsed_satellites = parse_tle_data(tle_data)
        
        # 3. AI生成简介并整合JSON
        generate_sat_json(parsed_satellites)
        
        print("="*50)
        print("工作流执行完成,JSON文件可直接用于前端加载")
        print("="*50)
    except Exception as e:
        print(f"工作流执行失败:{str(e)}")

if __name__ == "__main__":
    main()

4.3 工作流关键说明(适配航天爱好者需求)

  • 限流与重试机制:避免爬取CelesTrak时被反爬,同时防止AI API被限流,确保工作流稳定运行;

  • 轨道类型判断:通过轨道高度和倾角,自动区分LEO、GEO、MEO、IGSO四种常见轨道类型,与前端筛选功能对应,方便爱好者按轨道类型查看;

  • AI简介优化:提示词明确要求简介包含国家、类型、轨道特点、用途,语言专业且易懂,贴合航天爱好者的认知水平,避免过于晦涩的专业术语;

  • JSON格式适配:输出的JSON字段与前端接口完全兼容,无需前端修改代码,放入指定目录即可自动加载,实现"一键对接"。

五、项目推进总结与后续规划

本次项目推进围绕"服务航天爱好者"这一核心目标,完成了从基础搭建到核心优化、关键升级的全流程,每一步操作都贴合爱好者的使用痛点,同时通过示例代码确保项目可落地、可复用。

5.1 项目推进总结(已完成工作)

  1. 基础搭建:完成3D地球场景、星空背景、卫星轨迹渲染,实现鼠标交互和基础筛选功能,满足爱好者"直观查看卫星轨迹"的需求;

  2. 核心优化:新增简介接口,绑定JSON中的desc字段,优化弹窗样式,解决"信息传递不足"的痛点,让爱好者能快速了解卫星核心信息;

  3. 关键升级:搭建AI自动化工作流,实现TLE数据爬取、解析、AI简介生成、JSON输出全流程自动化,高效解决上万颗卫星简介的生成难题;

  4. 细节优化:添加韩国国家样式映射,确保筛选和弹窗样式正常;优化AI提示词,确保简介专业、易懂;加入限流、重试机制,提升工作流稳定性。

通过本次推进,项目已实现核心功能:3D可视化展示、卫星筛选、弹窗简介展示,完全满足航天爱好者的基础需求,同时具备可扩展性,为后续优化奠定了基础。

5.2 存在的不足

  • AI工作流效率:批量处理上万颗卫星数据时耗时较长,后续可优化并发处理逻辑,提升效率;

  • 简介个性化:目前AI生成的简介模板化程度较高,后续可结合卫星具体用途,生成更具针对性的简介;

  • 前端交互体验:可增加卫星轨迹高亮、鼠标悬停详细提示、轨迹历史回放等功能,进一步提升爱好者的使用体验。

5.3 后续规划(持续优化,贴合航天爱好者需求)

  • 优化AI工作流:引入并发处理,提升批量数据处理效率;优化AI提示词,结合更多航天知识库,提升简介准确性和个性化;

  • 丰富前端功能:增加卫星轨迹历史回放、轨迹高亮、卫星分类标签等功能,满足爱好者的深度查看需求;

  • 数据更新机制:添加JSON数据自动更新功能,定期爬取CelesTrak最新数据,确保卫星信息的时效性;

  • 用户体验优化:优化弹窗样式,增加简介排版美化;适配移动端,让爱好者随时随地查看卫星轨迹和信息。

六、总结

本次卫星3D可视化项目推进,核心是"以航天爱好者需求为导向",将复杂的卫星数据转化为直观、易用的可视化工具,同时通过AI技术解决批量简介生成的难题,让爱好者既能"看轨迹",也能"懂卫星"。

整个项目推进过程中,我不仅提升了前端开发、Python爬虫和AI接口调用能力,更深刻理解了"以用户需求为核心"的开发理念------对于面向航天爱好者的项目,专业、直观、易用是关键,既要保证数据的准确性和专业性,又要避免过于复杂的操作,让不同层次的航天爱好者都能轻松使用。

后续,我将继续深耕航天可视化领域,结合AI技术和航天知识,不断优化项目,希望能为航天爱好者提供更全面、更直观、更易用的卫星观察工具,也希望通过这个项目,让更多人关注航天、热爱航天,感受太空探索的无限魅力。

关注我,后续持续更新 AI 工作流实操落地、前端交互优化细节,带你从零打造可直接上线的卫星 3D 可视化平台,解锁航天可视化更多玩法~

相关推荐
毛骗导演2 小时前
Claude Code Agent 实现原理深度剖析
前端·架构
木卫二号Coding2 小时前
第八十四篇-V100-32G+Easyclaw+Ollama+Qwopus3.5-27B-V3
人工智能
xiaoxiang96092 小时前
TDD测试驱动开发:从理论到实战的完整指南(含AI增强工作流)
人工智能·驱动开发·tdd
星晨雪海2 小时前
若依框架原有页面功能进行了点位管理模块完整改造(3)
开发语言·前端·javascript
小张同学8242 小时前
Python 封神技巧:1 行代码搞定 90% 日常数据处理,效率直接拉满
开发语言·人工智能·python
源码之家2 小时前
计算机毕业设计:Python棉花产业数据可视化与预测系统 Django框架 ARIMA算法 数据分析 可视化 爬虫 大数据 大模型(建议收藏)✅
人工智能·python·算法·信息可视化·数据挖掘·django·课程设计
chatexcel2 小时前
北大ChatExcel团队推出AI办公桌宠“仓鼠元元”:桌面宠物开始做效率助手了
人工智能·宠物
数字供应链安全产品选型2 小时前
从影子AI到合规溯源:悬镜安全灵境AIDR如何覆盖智能体安全全生命周期?
人工智能
梵得儿SHI2 小时前
(第一篇)Spring AI 架构设计与优化:从单实例到万级 QPS 分布式服务的演进之路
人工智能·分布式架构·spring ai·万级 qps·ai 服务高并发·模型 / 向量 / 业务·qps分布式服务