diff --git a/.DS_Store b/.DS_Store index d87b7eb..178d40c 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/SCHEDULED_JOBS_CODE_REVIEW.md b/SCHEDULED_JOBS_CODE_REVIEW.md deleted file mode 100644 index ff56774..0000000 --- a/SCHEDULED_JOBS_CODE_REVIEW.md +++ /dev/null @@ -1,148 +0,0 @@ -# Scheduled Jobs System - Code Review Summary - -## Overview -This document summarizes the code review and cleanup performed on the scheduled jobs system. - -## Changes Made - -### 1. Backend - Removed Debug Logs with Emojis - -#### `app/jobs/predefined.py` -- Removed emoji icons from log messages (🌍, 📋, 🔄, ✅, ❌, 🎉, ⚠️) -- Changed `logger.info` to `logger.debug` for detailed operation logs -- Kept `logger.info` only for high-level operation summaries -- Kept `logger.error` and `logger.warning` for error conditions - -**Before:** -```python -logger.info(f"🌍 Starting solar system position sync: days={days}") -logger.info(f"🔄 Fetching positions for {body.name}") -logger.info(f"✅ Saved {count} positions for {body.name}") -``` - -**After:** -```python -logger.info(f"Starting solar system position sync: days={days}") -logger.debug(f"Fetching positions for {body.name}") -logger.debug(f"Saved {count} positions for {body.name}") -``` - -#### `app/jobs/registry.py` -- Changed task registration log from `logger.info` to `logger.debug` -- Changed task execution logs from `logger.info` to `logger.debug` -- Removed emoji icons (📋, 🚀, ✅) - -#### `app/services/scheduler_service.py` -- Removed emoji icons from all log messages (⏰, ❌, ✅) -- Kept important lifecycle logs as `logger.info` (start, stop, job scheduling) -- Changed detailed execution logs to `logger.debug` - -### 2. Backend - Removed Unused Imports - -#### `app/api/scheduled_job.py` -- Removed unused imports: `update`, `delete` from sqlalchemy - -**Before:** -```python -from sqlalchemy import select, update, delete -``` - -**After:** -```python -from sqlalchemy import select -``` - -### 3. Frontend - Removed Debug Console Logs - -#### `pages/admin/ScheduledJobs.tsx` -- Removed `console.log` statements from `loadAvailableTasks()` -- Removed `console.error` statements from `loadAvailableTasks()` -- Removed `console.log` statements from `handleEdit()` -- Removed `console.error` from error handling (kept only toast messages) - -**Removed:** -```typescript -console.log('Loaded available tasks:', result); -console.error('Failed to load available tasks:', error); -console.log('Editing record:', record); -console.log('Available tasks:', availableTasks); -console.error(error); -``` - -## Code Quality Improvements - -### 1. Consistent Logging Levels -- **ERROR**: For failures that prevent operations -- **WARNING**: For non-critical issues (e.g., "No bodies found") -- **INFO**: For high-level operation summaries -- **DEBUG**: For detailed operation traces - -### 2. Clean User-Facing Messages -- All user-facing error messages use toast notifications -- No console output in production frontend code -- Backend logs are professional and parseable - -### 3. Transaction Safety -- Using SQLAlchemy savepoints (`begin_nested()`) for isolated error handling -- Proper rollback and commit patterns -- Error messages include full traceback for debugging - -## Testing Results - -### Import Test -✓ All backend imports successful -✓ Task registry properly initialized -✓ 2 tasks registered: - - sync_solar_system_positions - - sync_celestial_events - -### Task Schema Test -✓ Task parameters properly defined: - - body_ids (array, optional, default=None) - - days (integer, optional, default=7) - - source (string, optional, default=nasa_horizons_cron) - -### Integration Test -✓ Position constraint fixed (nasa_horizons_cron added to CHECK constraint) -✓ Manual job execution successful -✓ 26 celestial bodies synced with 52 positions -✓ Task record properly created and updated -✓ No failures during execution - -## Remaining Console Logs (Other Admin Pages) - -The following console logs exist in other admin pages but were left unchanged as they're outside the scope of this scheduled jobs feature: - -- `SystemSettings.tsx`: 1 console.error -- `Users.tsx`: 2 console.error -- `Dashboard.tsx`: 1 console.error -- `StaticData.tsx`: 1 console.error -- `CelestialBodies.tsx`: 2 (1 error, 1 for JSON parsing) -- `NASADownload.tsx`: 3 (2 debug logs, 1 error) - -## Files Modified - -### Backend -1. `/backend/app/jobs/predefined.py` - Removed emoji logs, adjusted log levels -2. `/backend/app/jobs/registry.py` - Changed to debug logging -3. `/backend/app/services/scheduler_service.py` - Removed emojis, adjusted log levels -4. `/backend/app/api/scheduled_job.py` - Removed unused imports - -### Frontend -1. `/frontend/src/pages/admin/ScheduledJobs.tsx` - Removed all console logs - -### Database -1. `/backend/scripts/fix_position_source_constraint.py` - Fixed CHECK constraint - -## Summary - -All scheduled jobs related code has been reviewed and cleaned: -- ✅ No emoji icons in production logs -- ✅ Appropriate logging levels (ERROR/WARNING/INFO/DEBUG) -- ✅ No console.log/console.error in frontend -- ✅ No unused imports -- ✅ All imports and registrations working -- ✅ Database constraints fixed -- ✅ Integration tests passing - -The code is now production-ready with clean, professional logging suitable for monitoring and debugging. diff --git a/STAR_SYSTEM_MIGRATION_PROGRESS.md b/STAR_SYSTEM_MIGRATION_PROGRESS.md deleted file mode 100644 index 09f8d33..0000000 --- a/STAR_SYSTEM_MIGRATION_PROGRESS.md +++ /dev/null @@ -1,182 +0,0 @@ -# 恒星系统架构改造 - 进度报告 - -## ✅ 已完成工作 - -### 1. 数据库架构改造 -- ✅ 创建 `star_systems` 表 -- ✅ 添加太阳系初始记录(id=1) -- ✅ 扩展 `celestial_bodies` 表(添加 `system_id` 字段) -- ✅ 更新所有太阳系天体 `system_id = 1`(30个天体) - -### 2. ORM 模型 -- ✅ 创建 `StarSystem` ORM 模型 -- ✅ 更新 `CelestialBody` ORM 模型(添加 system_id 关系) -- ✅ 在 `__init__.py` 中注册 StarSystem - -### 3. 数据迁移 -- ✅ 编写完整的数据迁移脚本(`scripts/migrate_interstellar_data.py`) -- ✅ 实现自动中文名翻译功能 -- ✅ 实现行星数据去重逻辑 -- ✅ 成功迁移 578 个系外恒星系统 -- ✅ 成功迁移 898 颗系外行星(去重后) - -### 4. 后端服务层 -- ✅ 创建 `StarSystemService`(`app/services/star_system_service.py`) - - 支持 CRUD 操作 - - 支持搜索和分页 - - 支持获取恒星系及其所有天体 - - 支持统计功能 - -- ✅ 创建 Pydantic 模型(`app/models/star_system.py`) - - StarSystemBase - - StarSystemCreate - - StarSystemUpdate - - StarSystemResponse - - StarSystemWithBodies - - StarSystemStatistics - -### 5. 迁移数据统计 -``` -恒星系统总数: 579 -- 太阳系: 1 -- 系外恒星系: 578 - -天体总数: 928 -- 太阳系天体: 30(含太阳、行星、矮行星、卫星、探测器、彗星) -- 系外行星: 898(已去重) - -数据质量: -- 去重前行星记录: ~3000+ -- 去重后行星记录: 898 -- 去重率: ~70% -``` - ---- - -## 🚧 剩余工作 - -### 1. 后端 API 开发 -- [ ] 创建 StarSystem API 路由 - - GET /api/star-systems(获取所有恒星系统) - - GET /api/star-systems/{id}(获取单个恒星系统) - - GET /api/star-systems/{id}/bodies(获取恒星系及其天体) - - POST /api/admin/star-systems(创建恒星系统) - - PUT /api/admin/star-systems/{id}(更新恒星系统) - - DELETE /api/admin/star-systems/{id}(删除恒星系统) - - GET /api/star-systems/statistics(获取统计信息) - -- [ ] 更新 CelestialBody API - - 添加 `system_id` 查询参数 - - 添加 `include_no_system` 参数(用于包含探测器等) - -### 2. 后台管理界面(Admin Frontend) -- [ ] 创建恒星系统管理页面(`/admin/star-systems`) - - 列表展示(支持搜索、分页) - - 新增恒星系统 - - 编辑恒星系统 - - 删除恒星系统(不可删除太阳系) - - 查看恒星系详情(含所有行星) - -- [ ] 改造天体管理页面(`/admin/celestial-bodies`) - - **关键改动**:先选择恒星系,再列出该恒星系的天体 - - 添加恒星系选择器(下拉框) - - 根据选中的恒星系过滤天体列表 - - 新增天体时自动设置 `system_id` - - 支持在恒星系之间移动天体 - -### 3. 前端界面更新 -- [ ] 更新 GalaxyScene 组件 - - 使用新的 `/api/star-systems` API - - 移除前端行星去重代码 - - 优化恒星点击事件(使用后端返回的完整数据) - -- [ ] 更新 App.tsx 查询逻辑 - - Solar 视图:查询 `system_id=1` 的天体 - - Galaxy 视图:查询所有恒星系统 - -### 4. 菜单配置 -- [ ] 在后台管理菜单中添加"恒星系统管理"入口 - ---- - -## 📊 数据模型关系图 - -``` -star_systems (579条记录) -├── id=1: Solar System (太阳系) -│ └── celestial_bodies (30条) -│ ├── Sun (star) -│ ├── Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune (planet) -│ ├── Pluto, Ceres, Haumea, Makemake, Eris (dwarf_planet) -│ ├── Moon, Io, Europa, Ganymede, Callisto (satellite) -│ ├── Voyager 1, Voyager 2, Parker Solar Probe... (probe) -│ └── Halley, NEOWISE, C/2020 F3 (comet) -│ -├── id=2: Proxima Cen System (比邻星系统) -│ └── celestial_bodies (2条) -│ ├── Proxima Cen b (比邻星 b) -│ └── Proxima Cen d (比邻星 d) -│ -├── id=3: TRAPPIST-1 System -│ └── celestial_bodies (7条) -│ └── TRAPPIST-1 b/c/d/e/f/g/h -│ -└── ... (575 more systems) -``` - ---- - -## 🎯 下一步行动 - -**立即可做:** -1. 完成 StarSystem API 路由 -2. 测试 API 端点 -3. 开发后台管理界面 - -**预计工作量:** -- 后端 API:1-2小时 -- 后台界面:3-4小时 -- 前端更新:1-2小时 -- 测试验证:1小时 - -**总计:6-9小时** - ---- - -## 🔧 技术要点 - -### 中文名翻译规则 -```python -# 恒星名翻译示例 -Proxima Cen → 比邻星 -Kepler-442 → 开普勒-442 -TRAPPIST-1 → TRAPPIST-1 -HD 40307 → HD 40307 - -# 行星名翻译示例 -Proxima Cen b → 比邻星 b -Kepler-442 b → 开普勒-442 b -``` - -### 去重逻辑 -- 按行星名称(name)去重 -- 保留字段最完整的记录(非NULL字段最多的) -- 平均每个恒星系从5.2条记录减少到1.6条(效率提升70%) - -### 查询优化 -```sql --- Solar 视图 -SELECT * FROM celestial_bodies WHERE system_id = 1; - --- Galaxy 视图 -SELECT * FROM star_systems WHERE id > 1; - --- 恒星系详情 -SELECT * FROM celestial_bodies WHERE system_id = ?; -``` - ---- - -**文档版本**: v1.0 -**更新时间**: 2025-12-05 19:10 -**状态**: 数据迁移完成,API开发进行中 diff --git a/add_missing_radii.py b/add_missing_radii.py deleted file mode 100644 index 47cea08..0000000 --- a/add_missing_radii.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python3 -"""Add missing real_radius data for solar system bodies""" -import asyncio -import sys -import os - -sys.path.append(os.path.join(os.getcwd(), "backend")) - -from app.database import AsyncSessionLocal -from app.services.db_service import celestial_body_service - -# Real radii from NASA data (in km) -MISSING_RADII = { - '10': 696000, # Sun - '999': 1188, # Pluto - '2000001': 476, # Ceres - '136199': 1163, # Eris - '136108': 816, # Haumea - '136472': 715, # Makemake -} - -async def add_missing_radii(): - """Add real_radius to bodies that are missing it""" - async with AsyncSessionLocal() as session: - print("=" * 70) - print("Adding missing real_radius data") - print("=" * 70) - - for body_id, radius in MISSING_RADII.items(): - body = await celestial_body_service.get_body_by_id(body_id, session) - - if not body: - print(f"❌ Body {body_id} not found") - continue - - # Get existing extra_data or create new dict - extra_data = body.extra_data.copy() if body.extra_data else {} - - # Add real_radius - extra_data['real_radius'] = radius - - # Update body - updated = await celestial_body_service.update_body( - body_id, - {'extra_data': extra_data}, - session - ) - - if updated: - print(f"✅ {body.name:<20} (ID: {body_id:<10}): Added real_radius = {radius:>8} km") - else: - print(f"❌ {body.name:<20} (ID: {body_id:<10}): Update failed") - - await session.commit() - - print("\n" + "=" * 70) - print("✅ All missing real_radius data added successfully!") - print("=" * 70) - -if __name__ == "__main__": - asyncio.run(add_missing_radii()) diff --git a/analyze_problem.py b/analyze_problem.py deleted file mode 100644 index fa5b853..0000000 --- a/analyze_problem.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python3 -"""Analyze the size calculation problem""" -import json - -print("=" * 80) -print("SIZE CALCULATION ANALYSIS") -print("=" * 80) - -configs = { - "planet": {"ratio": 0.00008}, - "dwarf_planet": {"ratio": 0.00015}, -} - -bodies = { - 'Jupiter': {'type': 'planet', 'radius': 69911}, - 'Saturn': {'type': 'planet', 'radius': 58232}, - 'Earth': {'type': 'planet', 'radius': 6371}, - 'Ceres': {'type': 'dwarf_planet', 'radius': 476}, - 'Pluto': {'type': 'dwarf_planet', 'radius': 1188}, -} - -print("\n1. CALCULATED DISPLAY SIZES:") -print("-" * 80) -for name, body in bodies.items(): - ratio = configs[body['type']]['ratio'] - size = body['radius'] * ratio - print(f"{name:<15}: {body['radius']:>6} km * {ratio:.6f} = {size:.4f}") - -print("\n2. SIZE RATIOS (relative to Earth):") -print("-" * 80) -earth_size = bodies['Earth']['radius'] * configs['planet']['ratio'] -for name, body in bodies.items(): - ratio = configs[body['type']]['ratio'] - size = body['radius'] * ratio - relative = size / earth_size - print(f"{name:<15}: {size:.4f} / {earth_size:.4f} = {relative:.2f}x Earth") - -print("\n" + "=" * 80) -print("⚠️ PROBLEM IDENTIFIED:") -print("=" * 80) -print("Planet ratio: 0.00008") -print("Dwarf planet ratio: 0.00015 (1.875x larger!)") -print() -print("This means dwarf planets are artificially ENLARGED by 1.875x") -print("relative to regular planets!") -print() -print("IMPACT:") -print(" • Small dwarf planets (Ceres) appear TOO LARGE") -print(" • Large planets (Jupiter, Saturn) appear correctly sized") -print(" • But the ratio between them is WRONG") -print() -print("SOLUTION:") -print(" → Use the SAME ratio for all body types") -print(" → Recommended: ratio = 0.00008 for all types") -print("=" * 80) - -# Show what sizes would be with unified ratio -print("\n3. SIZES WITH UNIFIED RATIO (0.00008):") -print("-" * 80) -unified_ratio = 0.00008 -for name, body in bodies.items(): - size = body['radius'] * unified_ratio - relative = size / earth_size - print(f"{name:<15}: {body['radius']:>6} km * {unified_ratio:.6f} = {size:.4f} ({relative:.2f}x Earth)") diff --git a/check_all_positions.py b/check_all_positions.py deleted file mode 100644 index f3af1f2..0000000 --- a/check_all_positions.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python3 -"""Check all positions for Earth""" -import asyncio -import sys -import os - -sys.path.append(os.path.join(os.getcwd(), "backend")) - -from app.database import AsyncSessionLocal -from app.services.db_service import position_service - -async def check_all_positions(): - """Check all position data for Earth""" - async with AsyncSessionLocal() as session: - # Get all positions (no time filter) - positions = await position_service.get_positions( - body_id="399", - start_time=None, - end_time=None, - session=session - ) - - print(f"Total positions for Earth: {len(positions)}") - - if positions: - print(f"\nFirst position: {positions[0].time}") - print(f"Last position: {positions[-1].time}") - print("\nSample of last 5 positions:") - for pos in positions[-5:]: - print(f" {pos.time}: ({pos.x:.6f}, {pos.y:.6f}, {pos.z:.6f})") - else: - print("\n❌ No positions at all!") - print("You need to download position data first.") - -if __name__ == "__main__": - asyncio.run(check_all_positions()) diff --git a/check_all_radii.py b/check_all_radii.py deleted file mode 100644 index 8961a10..0000000 --- a/check_all_radii.py +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env python3 -"""Check real_radius for all planets""" -import asyncio -import sys -import os - -sys.path.append(os.path.join(os.getcwd(), "backend")) - -from app.database import AsyncSessionLocal -from sqlalchemy import select -from app.models.db.celestial_body import CelestialBody - -async def check_radii(): - async with AsyncSessionLocal() as session: - # Get all planets and dwarf planets - stmt = select(CelestialBody).where( - CelestialBody.type.in_(['planet', 'dwarf_planet', 'star']) - ).order_by(CelestialBody.name) - - result = await session.execute(stmt) - bodies = result.scalars().all() - - print("Body Name | Type | Real Radius (km)") - print("-" * 60) - - for body in bodies: - radius = body.extra_data.get('real_radius') if body.extra_data else None - print(f"{body.name:20s} | {body.type:13s} | {radius if radius else 'N/A'}") - - # Calculate ratios relative to Earth - earth_radius = 6371 - print("\n" + "=" * 60) - print("Size ratios relative to Earth (6371 km):") - print("=" * 60) - - for body in bodies: - if body.extra_data and body.extra_data.get('real_radius'): - radius = body.extra_data['real_radius'] - ratio = radius / earth_radius - print(f"{body.name:20s}: {radius:8.0f} km = {ratio:6.2f}x Earth") - -if __name__ == "__main__": - asyncio.run(check_radii()) diff --git a/check_api.py b/check_api.py deleted file mode 100644 index e3ee455..0000000 --- a/check_api.py +++ /dev/null @@ -1,29 +0,0 @@ - -import requests -import sys - -def check_api(): - url = "http://localhost:8000/api/celestial/positions" - try: - response = requests.get(url, timeout=5) - response.raise_for_status() - data = response.json() - - bodies = data.get("bodies", []) - print(f"API returned {len(bodies)} bodies.") - - targets = [b for b in bodies if b.get("name") in ["Earth", "Jupiter"]] - for t in targets: - print(f"Body: {t.get('name')}") - print(f" Keys: {list(t.keys())}") - print(f" Extra Data: {t.get('extra_data')}") - if t.get('extra_data'): - print(f" Real Radius: {t.get('extra_data', {}).get('real_radius')}") - else: - print(" Real Radius: MISSING") - - except Exception as e: - print(f"Error checking API: {e}") - -if __name__ == "__main__": - check_api() diff --git a/check_configs.py b/check_configs.py deleted file mode 100644 index 3925baf..0000000 --- a/check_configs.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env python3 -"""Check celestial_type_configs system setting""" -import asyncio -import sys -import os -import json - -sys.path.append(os.path.join(os.getcwd(), "backend")) - -from app.database import AsyncSessionLocal -from app.services.system_settings_service import system_settings_service - -async def check_configs(): - async with AsyncSessionLocal() as session: - # Get celestial_type_configs - configs = await system_settings_service.get_setting_value('celestial_type_configs', session) - - if configs: - print("=" * 70) - print("CELESTIAL TYPE CONFIGS") - print("=" * 70) - print(json.dumps(configs, indent=2)) - print("\n" + "=" * 70) - print("CALCULATED SIZES (assuming Earth radius = 6371 km)") - print("=" * 70) - - # Test calculation for different body types - test_bodies = { - 'Sun': {'type': 'star', 'real_radius': 696000}, - 'Jupiter': {'type': 'planet', 'real_radius': 69911}, - 'Saturn': {'type': 'planet', 'real_radius': 58232}, - 'Earth': {'type': 'planet', 'real_radius': 6371}, - 'Mars': {'type': 'planet', 'real_radius': 3389}, - 'Ceres': {'type': 'dwarf_planet', 'real_radius': 476}, - 'Pluto': {'type': 'dwarf_planet', 'real_radius': 1188}, - } - - for name, body in test_bodies.items(): - body_type = body['type'] - real_radius = body['real_radius'] - - if body_type in configs and 'ratio' in configs[body_type]: - ratio = configs[body_type]['ratio'] - calculated_size = real_radius * ratio - print(f"{name:<15} ({body_type:<13}): {real_radius:>7} km * {ratio:.6f} = {calculated_size:.4f}") - else: - print(f"{name:<15} ({body_type:<13}): No ratio config found") - - else: - print("❌ celestial_type_configs not found in system settings") - -if __name__ == "__main__": - asyncio.run(check_configs()) diff --git a/check_missing_radii.py b/check_missing_radii.py deleted file mode 100644 index 11b1c3b..0000000 --- a/check_missing_radii.py +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env python3 -"""Check which solar system bodies are missing real_radius""" -import asyncio -import sys -import os - -sys.path.append(os.path.join(os.getcwd(), "backend")) - -from app.database import AsyncSessionLocal -from sqlalchemy import select -from app.models.db.celestial_body import CelestialBody - -async def check_missing_radii(): - async with AsyncSessionLocal() as session: - # Solar System body IDs - solar_ids = ['10', '199', '299', '399', '499', '599', '699', '799', '899', '999', - '2000001', '136199', '136108', '136472'] - - stmt = select(CelestialBody).where(CelestialBody.id.in_(solar_ids)) - result = await session.execute(stmt) - bodies = result.scalars().all() - - print("=" * 70) - print("SOLAR SYSTEM BODIES - Missing real_radius Check") - print("=" * 70) - - has_radius = [] - missing_radius = [] - - for body in bodies: - radius = body.extra_data.get('real_radius') if body.extra_data else None - if radius: - has_radius.append((body.name, body.type, radius)) - else: - missing_radius.append((body.name, body.type)) - - print(f"\n✅ Bodies WITH real_radius ({len(has_radius)}):") - print("-" * 70) - for name, btype, radius in sorted(has_radius, key=lambda x: x[2], reverse=True): - print(f" {name:<20} ({btype:<15}): {radius:>8.0f} km") - - print(f"\n❌ Bodies MISSING real_radius ({len(missing_radius)}):") - print("-" * 70) - for name, btype in sorted(missing_radius): - print(f" {name:<20} ({btype})") - - if missing_radius: - print("\n⚠️ WARNING: Bodies without real_radius will use TYPE_SIZES fallback!") - print(" This causes INCONSISTENT scaling!") - -if __name__ == "__main__": - asyncio.run(check_missing_radii()) diff --git a/check_positions.py b/check_positions.py deleted file mode 100644 index 1230ff3..0000000 --- a/check_positions.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python3 -"""Check if positions exist in database for Earth""" -import asyncio -import sys -import os -from datetime import datetime, timedelta - -sys.path.append(os.path.join(os.getcwd(), "backend")) - -from app.database import AsyncSessionLocal -from app.services.db_service import position_service - -async def check_positions(): - """Check if we have position data for Earth""" - async with AsyncSessionLocal() as session: - now = datetime.utcnow() - recent_window = now - timedelta(hours=24) - - positions = await position_service.get_positions( - body_id="399", - start_time=recent_window, - end_time=now, - session=session - ) - - print(f"Checking positions for Earth (ID: 399)") - print(f"Time range: {recent_window} to {now}") - print(f"Found {len(positions)} positions") - - if positions: - latest = positions[-1] - print(f"\nLatest position:") - print(f" Time: {latest.time}") - print(f" X: {latest.x}, Y: {latest.y}, Z: {latest.z}") - else: - print("\n❌ No recent positions found for Earth!") - print("This explains why the API is failing.") - -if __name__ == "__main__": - asyncio.run(check_positions()) diff --git a/check_solar_radii.py b/check_solar_radii.py deleted file mode 100644 index 23f8a0e..0000000 --- a/check_solar_radii.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env python3 -"""Check real_radius for solar system planets only""" -import asyncio -import sys -import os - -sys.path.append(os.path.join(os.getcwd(), "backend")) - -from app.database import AsyncSessionLocal -from sqlalchemy import select -from app.models.db.celestial_body import CelestialBody - -async def check_solar_system(): - async with AsyncSessionLocal() as session: - # Solar System body IDs - solar_ids = ['10', '199', '299', '399', '499', '599', '699', '799', '899', '999', - '2000001', '136199', '136108', '136472'] - - stmt = select(CelestialBody).where(CelestialBody.id.in_(solar_ids)) - result = await session.execute(stmt) - bodies = result.scalars().all() - - print("=" * 70) - print("SOLAR SYSTEM CELESTIAL BODIES - Real Radius Check") - print("=" * 70) - print(f"{'Name':<20} {'Type':<15} {'Real Radius (km)':>15}") - print("-" * 70) - - for body in bodies: - radius = body.extra_data.get('real_radius') if body.extra_data else None - print(f"{body.name:<20} {body.type:<15} {radius if radius else 'N/A':>15}") - - # Calculate ratios relative to Earth - earth_radius = 6371 - print("\n" + "=" * 70) - print("SIZE RATIOS (relative to Earth = 1.0x)") - print("=" * 70) - - for body in sorted(bodies, key=lambda b: b.extra_data.get('real_radius', 0) if b.extra_data else 0, reverse=True): - if body.extra_data and body.extra_data.get('real_radius'): - radius = body.extra_data['real_radius'] - ratio = radius / earth_radius - print(f"{body.name:<20}: {radius:>8.0f} km = {ratio:>6.2f}x Earth") - -if __name__ == "__main__": - asyncio.run(check_solar_system()) diff --git a/clear_all_caches.py b/clear_all_caches.py deleted file mode 100644 index 046b96e..0000000 --- a/clear_all_caches.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python3 -"""Clear all caches to force fresh data""" -import asyncio -import sys -import os - -sys.path.append(os.path.join(os.getcwd(), "backend")) - -from app.services.redis_cache import redis_cache -from app.services.cache import cache_service - -async def clear_caches(): - """Clear all caches""" - print("Clearing memory cache...") - cache_service.clear() - print("✓ Memory cache cleared") - - print("\nClearing Redis cache...") - try: - await redis_cache.clear_all() - print("✓ Redis cache cleared") - except Exception as e: - print(f"✗ Redis cache clear failed: {e}") - - print("\nAll caches cleared! Fresh data will be loaded on next request.") - -if __name__ == "__main__": - asyncio.run(clear_caches()) diff --git a/clear_cache.py b/clear_cache.py deleted file mode 100644 index 89d0e14..0000000 --- a/clear_cache.py +++ /dev/null @@ -1,15 +0,0 @@ -import requests - -def clear_cache(): - url = "http://localhost:8000/api/system/cache/clear" - try: - response = requests.post(url, timeout=5) - print(f"Status: {response.status_code}") - print(f"Body: {response.text}") - response.raise_for_status() - print(f"Cache cleared: {response.json()}") - except Exception as e: - print(f"Error clearing cache: {e}") - -if __name__ == "__main__": - clear_cache() \ No newline at end of file diff --git a/complete_analysis.py b/complete_analysis.py deleted file mode 100644 index 675b8d5..0000000 --- a/complete_analysis.py +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/env python3 -"""Show the complete picture of the sizing problem""" - -print("=" * 90) -print("COMPLETE SIZE CALCULATION ANALYSIS") -print("=" * 90) - -# Real radii (km) -real_radii = { - 'Sun': 696000, - 'Jupiter': 69911, - 'Saturn': 58232, - 'Earth': 6371, - 'Ceres': 476, - 'Pluto': 1188, -} - -# Current config -planet_ratio = 0.00008 -dwarf_ratio = 0.00015 -star_ratio = 0.0000015 - -# Current TYPE_SIZES fallback -type_sizes = { - 'planet': 0.6, - 'dwarf_planet': 0.18, - 'star': 0.4, -} - -print("\n📊 CURRENT SITUATION:") -print("-" * 90) -print(f"{'Body':<15} {'Has real_radius?':<20} {'Calculation':<40} {'Size':<10}") -print("-" * 90) - -# Planets with real_radius -for name in ['Jupiter', 'Saturn', 'Earth']: - radius = real_radii[name] - size = radius * planet_ratio - calc = f"{radius} * {planet_ratio} = {size:.4f}" - print(f"{name:<15} {'YES (✓)':<20} {calc:<40} {size:<10.4f}") - -# Dwarf planets WITHOUT real_radius (using fallback) -for name in ['Ceres', 'Pluto']: - radius = real_radii[name] - fallback_size = type_sizes['dwarf_planet'] - correct_size = radius * planet_ratio # What it SHOULD be - calc = f"FALLBACK: {fallback_size:.2f} (should be {correct_size:.4f})" - ratio = fallback_size / correct_size - print(f"{name:<15} {'NO (✗) MISSING!':<20} {calc:<40} {fallback_size:<10.2f} ({ratio:.1f}x too large!)") - -# Sun WITHOUT real_radius -name = 'Sun' -radius = real_radii[name] -fallback_size = type_sizes['star'] -correct_size = radius * star_ratio -calc = f"FALLBACK: {fallback_size:.2f} (should be {correct_size:.4f})" -ratio = fallback_size / correct_size -print(f"{name:<15} {'NO (✗) MISSING!':<20} {calc:<40} {fallback_size:<10.2f}") - -print("\n" + "=" * 90) -print("⚠️ PROBLEMS:") -print("=" * 90) -print("1. Dwarf planets (Ceres, Pluto, etc.) use FIXED fallback size 0.18") -print(" → Ceres (476 km) should be 0.0381 but shows as 0.18 (4.7x too large!)") -print(" → Pluto (1188 km) should be 0.0950 but shows as 0.18 (1.9x too large!)") -print() -print("2. Different ratios for different types causes MORE confusion:") -print(f" → planet ratio: {planet_ratio}") -print(f" → dwarf_planet ratio: {dwarf_ratio} (1.875x larger!)") -print() -print("3. Sun has no real_radius, uses fixed size 0.4") -print() - -print("=" * 90) -print("✅ SOLUTION:") -print("=" * 90) -print("1. Add missing real_radius data for:") -print(" • Sun: 696000 km") -print(" • Ceres: 476 km") -print(" • Pluto: 1188 km") -print(" • Eris: 1163 km") -print(" • Haumea: 816 km") -print(" • Makemake: 715 km") -print() -print("2. Use UNIFIED ratio for all types:") -print(" • Recommended: 0.00008 for ALL types (star, planet, dwarf_planet, etc.)") -print(" • This ensures consistent scaling based on real physical size") -print() -print("3. If planets appear too large visually, adjust the GLOBAL ratio:") -print(" • Reduce ratio to 0.00005 or 0.00004 for ALL types") -print(" • This keeps relative sizes correct while fitting better on screen") -print("=" * 90) diff --git a/direct_update_config.py b/direct_update_config.py deleted file mode 100644 index 1169bec..0000000 --- a/direct_update_config.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env python3 -"""Direct update celestial_type_configs using SQL""" -import asyncio -import sys -import os -import json - -sys.path.append(os.path.join(os.getcwd(), "backend")) - -from app.database import AsyncSessionLocal -from sqlalchemy import select, update -from app.models.db.system_settings import SystemSettings - -# Unified ratio for all types -UNIFIED_RATIO = 0.00008 - -async def direct_update(): - """Direct SQL update of celestial_type_configs""" - async with AsyncSessionLocal() as session: - # Get the setting record - stmt = select(SystemSettings).where(SystemSettings.key == 'celestial_type_configs') - result = await session.execute(stmt) - setting = result.scalar_one_or_none() - - if not setting: - print("❌ Setting 'celestial_type_configs' not found!") - return - - # Parse the JSON value - current_value = json.loads(setting.value) if isinstance(setting.value, str) else setting.value - - print("BEFORE UPDATE:") - print(json.dumps(current_value, indent=2)) - - # Update all ratios - updated_config = {} - for body_type, config in current_value.items(): - updated_config[body_type] = { - 'ratio': UNIFIED_RATIO, - 'default': config.get('default', 0.5) - } - - # Update the raw_value (stored as JSON string) - setting.raw_value = json.dumps(updated_config) - - await session.commit() - - print("\nAFTER UPDATE:") - print(json.dumps(updated_config, indent=2)) - print(f"\n✅ Successfully updated all ratios to {UNIFIED_RATIO}") - -if __name__ == "__main__": - asyncio.run(direct_update()) diff --git a/final_verification.py b/final_verification.py deleted file mode 100644 index 9a2cafd..0000000 --- a/final_verification.py +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env python3 -"""Verify final sizes after updates - SIMPLIFIED""" -import asyncio -import sys -import os - -sys.path.append(os.path.join(os.getcwd(), "backend")) - -from app.database import AsyncSessionLocal -from sqlalchemy import select -from app.models.db.celestial_body import CelestialBody -from app.services.system_settings_service import system_settings_service - -async def verify_final(): - async with AsyncSessionLocal() as session: - # Get updated config - configs = await system_settings_service.get_setting_value('celestial_type_configs', session) - - # Solar System body IDs - solar_ids = ['10', '199', '299', '399', '499', '599', '699', '799', '899', '999', - '2000001', '136199', '136108', '136472'] - - stmt = select(CelestialBody).where(CelestialBody.id.in_(solar_ids)) - result = await session.execute(stmt) - bodies = result.scalars().all() - - print("=" * 95) - print("FINAL VERIFICATION - Solar System Celestial Body Display Sizes") - print("=" * 95) - print(f"{'Name':<15} {'Type':<15} {'Real Radius':>12} {'× Ratio':>12} {'= Display':>12} {'Relative':<12}") - print("-" * 95) - - earth_display = None - data = [] - - for body in bodies: - if body.extra_data and body.extra_data.get('real_radius'): - real_radius = body.extra_data['real_radius'] - ratio = configs[body.type]['ratio'] - display_size = real_radius * ratio - - data.append({ - 'name': body.name, - 'type': body.type, - 'real_radius': real_radius, - 'ratio': ratio, - 'display': display_size - }) - - if body.name == 'Earth': - earth_display = display_size - - # Sort by display size - data.sort(key=lambda x: x['display'], reverse=True) - - for d in data: - rel = f"{d['display'] / earth_display:.2f}x Earth" if earth_display else "N/A" - print(f"{d['name']:<15} {d['type']:<15} {d['real_radius']:>9,.0f} km {d['ratio']:.6f} {d['display']:>10.4f} {rel:<12}") - - print("\n" + "=" * 95) - print("🎉 SUCCESS! All sizes are now physically accurate and consistent!") - print("=" * 95) - print(f"\nUnified Ratio: {configs['planet']['ratio']}") - print(f"Formula: Display Size = Real Radius (km) × {configs['planet']['ratio']}") - print("\nKey Size Relationships (all relative to Earth):") - - size_dict = {d['name']: d['display'] for d in data} - print(f" • Sun = {size_dict['Sun'] / earth_display:>6.2f}x (physically correct)") - print(f" • Jupiter = {size_dict['Jupiter'] / earth_display:>6.2f}x (should be ~11x) ✓") - print(f" • Saturn = {size_dict['Saturn'] / earth_display:>6.2f}x (should be ~9x) ✓") - print(f" • Earth = {size_dict['Earth'] / earth_display:>6.2f}x (baseline)") - print(f" • Pluto = {size_dict['Pluto'] / earth_display:>6.2f}x (should be ~0.19x) ✓") - print(f" • Ceres = {size_dict['Ceres'] / earth_display:>6.2f}x (should be ~0.07x) ✓") - -if __name__ == "__main__": - asyncio.run(verify_final()) diff --git a/test_api_response.py b/test_api_response.py deleted file mode 100644 index bdb6eaa..0000000 --- a/test_api_response.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python3 -"""Test script to verify extra_data in API response""" -import asyncio -import sys -import os -import json - -# Add backend to path -sys.path.append(os.path.join(os.getcwd(), "backend")) - -from app.database import AsyncSessionLocal -from app.services.db_service import celestial_body_service - -async def test_api_data(): - """Simulate API response building""" - async with AsyncSessionLocal() as session: - # Get Earth - body = await celestial_body_service.get_body_by_id("399", session) - - if not body: - print("Earth not found in database") - return - - # Build response dict like API does - body_dict = { - "id": body.id, - "name": body.name, - "name_zh": body.name_zh, - "type": body.type, - "description": body.description, - "is_active": body.is_active, - "extra_data": body.extra_data, - "positions": [] - } - - print("=== Database Body Object ===") - print(f"Body ID: {body.id}") - print(f"Body Name: {body.name}") - print(f"Body Type: {body.type}") - print(f"Extra Data Type: {type(body.extra_data)}") - print(f"Extra Data: {body.extra_data}") - - print("\n=== API Response Dict ===") - print(json.dumps(body_dict, indent=2, default=str)) - -if __name__ == "__main__": - asyncio.run(test_api_data()) diff --git a/test_full_api.py b/test_full_api.py deleted file mode 100644 index 2efc9e1..0000000 --- a/test_full_api.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env python3 -"""Direct API test - simulate the exact API call""" -import asyncio -import sys -import os -from datetime import datetime - -sys.path.append(os.path.join(os.getcwd(), "backend")) - -from app.database import AsyncSessionLocal -from app.services.db_service import celestial_body_service, position_service - -async def simulate_api_call(): - """Simulate /celestial/positions endpoint""" - async with AsyncSessionLocal() as db: - # Get all bodies from database - all_bodies = await celestial_body_service.get_all_bodies(db) - - # Filter to only Solar System bodies - all_bodies = [b for b in all_bodies if b.system_id == 1] - - # Filter to Earth only - all_bodies = [b for b in all_bodies if b.id == "399"] - - bodies_data = [] - now = datetime.utcnow() - - for body in all_bodies: - # Get most recent position - recent_positions = await position_service.get_positions( - body_id=body.id, - start_time=now, - end_time=now, - session=db - ) - - if recent_positions and len(recent_positions) > 0: - latest_pos = recent_positions[-1] - body_dict = { - "id": body.id, - "name": body.name, - "name_zh": body.name_zh, - "type": body.type, - "description": body.description, - "is_active": body.is_active, - "extra_data": body.extra_data, # THIS IS THE KEY LINE - "positions": [{ - "time": latest_pos.time.isoformat(), - "x": latest_pos.x, - "y": latest_pos.y, - "z": latest_pos.z, - }] - } - bodies_data.append(body_dict) - - print("=== Simulated API Response for Earth ===") - print(f"ID: {body_dict['id']}") - print(f"Name: {body_dict['name']}") - print(f"Type: {body_dict['type']}") - print(f"Extra Data: {body_dict['extra_data']}") - print(f"Extra Data Type: {type(body_dict['extra_data'])}") - if body_dict['extra_data']: - print(f"Real Radius: {body_dict['extra_data'].get('real_radius')}") - -if __name__ == "__main__": - asyncio.run(simulate_api_call()) diff --git a/update_unified_ratio.py b/update_unified_ratio.py deleted file mode 100644 index 83fae8a..0000000 --- a/update_unified_ratio.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python3 -"""Update celestial_type_configs to use unified ratio""" -import asyncio -import sys -import os -import json - -sys.path.append(os.path.join(os.getcwd(), "backend")) - -from app.database import AsyncSessionLocal -from app.services.system_settings_service import system_settings_service - -# Unified ratio for all types -# This ensures consistent scaling based on real physical size -UNIFIED_RATIO = 0.00008 - -async def update_unified_ratio(): - """Update all type ratios to use unified value""" - async with AsyncSessionLocal() as session: - # Get current config - current_config = await system_settings_service.get_setting_value('celestial_type_configs', session) - - print("=" * 70) - print("CURRENT celestial_type_configs:") - print("=" * 70) - print(json.dumps(current_config, indent=2)) - - # Update all ratios to unified value - updated_config = {} - for body_type, config in current_config.items(): - updated_config[body_type] = { - 'ratio': UNIFIED_RATIO, - 'default': config.get('default', 0.5) # Keep existing defaults - } - - print("\n" + "=" * 70) - print(f"UPDATED celestial_type_configs (unified ratio = {UNIFIED_RATIO}):") - print("=" * 70) - print(json.dumps(updated_config, indent=2)) - - # Save updated config - await system_settings_service.update_setting( - 'celestial_type_configs', - updated_config, - session - ) - - await session.commit() - - print("\n" + "=" * 70) - print("✅ All type ratios unified successfully!") - print("=" * 70) - print("\nNOW ALL BODIES WILL USE:") - print(f" Display Size = real_radius (km) × {UNIFIED_RATIO}") - print("\nThis ensures:") - print(" • Consistent scaling across all body types") - print(" • Jupiter is correctly 10.97x larger than Earth") - print(" • Ceres is correctly 0.07x the size of Earth") - print(" • Pluto is correctly 0.19x the size of Earth") - -if __name__ == "__main__": - asyncio.run(update_unified_ratio()) diff --git a/verify_final_sizes.py b/verify_final_sizes.py deleted file mode 100644 index 0227751..0000000 --- a/verify_final_sizes.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env python3 -"""Verify final sizes after updates""" -import asyncio -import sys -import os - -sys.path.append(os.path.join(os.getcwd(), "backend")) - -from app.database import AsyncSessionLocal -from sqlalchemy import select -from app.models.db.celestial_body import CelestialBody -from app.services.system_settings_service import system_settings_service - -async def verify_final_sizes(): - async with AsyncSessionLocal() as session: - # Get updated config - configs = await system_settings_service.get_setting_value('celestial_type_configs', session) - - # Solar System body IDs - solar_ids = ['10', '199', '299', '399', '499', '599', '699', '799', '899', '999', - '2000001', '136199', '136108', '136472'] - - stmt = select(CelestialBody).where(CelestialBody.id.in_(solar_ids)) - result = await session.execute(stmt) - bodies = result.scalars().all() - - print("=" * 85) - print("FINAL VERIFICATION - All Celestial Body Sizes") - print("=" * 85) - print(f"{'Name':<20} {'Type':<15} {'Real Radius':<15} {'Ratio':<12} {'Display Size':<12} {'vs Earth'}") - print("-" * 85) - - earth_size = None - sizes = [] - - for body in sorted(bodies, key=lambda b: b.extra_data.get('real_radius', 0) if b.extra_data else 0, reverse=True): - if body.extra_data and body.extra_data.get('real_radius'): - real_radius = body.extra_data['real_radius'] - ratio = configs[body.type]['ratio'] - display_size = real_radius * ratio - - sizes.append((body.name, body.type, real_radius, ratio, display_size)) - - if body.name == 'Earth': - earth_size = display_size - - # Print with Earth comparison - for name, btype, real_radius, ratio, display_size in sizes: - vs_earth = f"{display_size / earth_size:.2f}x" if earth_size else "N/A" - print(f"{name:<20} {btype:<15} {real_radius:>8.0f} km {ratio:.6f} {display_size:>10.4f} {vs_earth:>7}") - - print("\n" + "=" * 85) - print("✅ VERIFICATION COMPLETE") - print("=" * 85) - print("All bodies now use:") - print(f" • Unified ratio: {configs['planet']['ratio']}") - print(f" • Display Size = real_radius × {configs['planet']['ratio']}") - print("\nSize relationships:") - print(f" • Jupiter = {sizes[0][4] / earth_size:.2f}x Earth (should be ~11x)") - print(f" • Saturn = {sizes[1][4] / earth_size:.2f}x Earth (should be ~9x)") - print(f" • Pluto = {[s for s in sizes if s[0] == 'Pluto'][0][4] / earth_size:.2f}x Earth (should be ~0.19x)") - print(f" • Ceres = {[s for s in sizes if s[0] == 'Ceres'][0][4] / earth_size:.2f}x Earth (should be ~0.07x)") - print("\n🎉 All sizes are now consistent and physically accurate!") - -if __name__ == "__main__": - asyncio.run(verify_final_sizes())