Spaces:
Sleeping
Sleeping
π₯ Add direct database download endpoints
Browse files⨠NEW FEATURES:
- /download/database - Direct SQLite database download
- /download/csv - Direct CSV export download
- /download/status - Direct status report download
- Files backed up to static/ directory for HTTP access
- Fallback to root directory if static files not found
π§ FIXES:
- Backup system now creates files in multiple locations
- Static directory backup for immediate HTTP access
- Git commit still attempted but not required for access
- Works even if git commits fail in HF Spaces
π± For Users:
- Instant database access via download endpoints
- No need to wait for git sync
- Multiple download options available
- Persistent data guaranteed
This ensures your Tezpur team can always access their tree data!
app.py
CHANGED
@@ -448,30 +448,43 @@ initialize_app()
|
|
448 |
import shutil
|
449 |
|
450 |
def backup_database():
|
451 |
-
"""Backup database
|
452 |
try:
|
453 |
source_db = Path("data/trees.db")
|
454 |
if not source_db.exists():
|
455 |
logger.warning("Source database does not exist")
|
456 |
return False
|
457 |
|
458 |
-
# 1. Copy database to
|
459 |
-
|
460 |
-
shutil.copy2(source_db,
|
461 |
|
462 |
-
# 2.
|
463 |
-
|
464 |
-
|
465 |
|
466 |
-
# 3.
|
467 |
-
|
468 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
469 |
|
470 |
-
#
|
471 |
if _is_docker_environment():
|
472 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
473 |
|
474 |
-
logger.info("Database backed up locally")
|
475 |
return True
|
476 |
|
477 |
except Exception as e:
|
@@ -1113,6 +1126,55 @@ async def get_photo_categories():
|
|
1113 |
}
|
1114 |
|
1115 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1116 |
@app.get("/api/persistence/status", tags=["System"])
|
1117 |
async def get_persistence_status():
|
1118 |
"""Get database backup system status"""
|
|
|
448 |
import shutil
|
449 |
|
450 |
def backup_database():
|
451 |
+
"""Backup database to accessible locations (HF Spaces compatible)"""
|
452 |
try:
|
453 |
source_db = Path("data/trees.db")
|
454 |
if not source_db.exists():
|
455 |
logger.warning("Source database does not exist")
|
456 |
return False
|
457 |
|
458 |
+
# 1. Copy database to static directory for direct HTTP access
|
459 |
+
static_db = Path("static/trees_database.db")
|
460 |
+
shutil.copy2(source_db, static_db)
|
461 |
|
462 |
+
# 2. Also copy to root level (in case git access works)
|
463 |
+
root_db = Path("trees_database.db")
|
464 |
+
shutil.copy2(source_db, root_db)
|
465 |
|
466 |
+
# 3. Export to CSV in multiple locations
|
467 |
+
static_csv = Path("static/trees_backup.csv")
|
468 |
+
root_csv = Path("trees_backup.csv")
|
469 |
+
_export_trees_to_csv(static_csv)
|
470 |
+
_export_trees_to_csv(root_csv)
|
471 |
+
|
472 |
+
# 4. Create comprehensive status files
|
473 |
+
static_status = Path("static/database_status.txt")
|
474 |
+
root_status = Path("database_status.txt")
|
475 |
+
tree_count = _create_status_file(static_status, source_db)
|
476 |
+
_create_status_file(root_status, source_db)
|
477 |
|
478 |
+
# 5. Try git commit (may fail in HF Spaces but that's okay)
|
479 |
if _is_docker_environment():
|
480 |
+
git_success = _git_commit_backup([root_db, root_csv, root_status], tree_count)
|
481 |
+
if git_success:
|
482 |
+
logger.info(f"β
Database backed up and committed to git: {tree_count} trees")
|
483 |
+
else:
|
484 |
+
logger.info(f"π Database backed up to static files (git commit failed): {tree_count} trees")
|
485 |
+
else:
|
486 |
+
logger.info(f"π Database backed up locally: {tree_count} trees")
|
487 |
|
|
|
488 |
return True
|
489 |
|
490 |
except Exception as e:
|
|
|
1126 |
}
|
1127 |
|
1128 |
|
1129 |
+
# Direct file download endpoints
|
1130 |
+
@app.get("/download/database", tags=["Downloads"])
|
1131 |
+
async def download_database():
|
1132 |
+
"""Download the SQLite database file"""
|
1133 |
+
db_file = Path("static/trees_database.db")
|
1134 |
+
if not db_file.exists():
|
1135 |
+
# Try root location
|
1136 |
+
db_file = Path("trees_database.db")
|
1137 |
+
if not db_file.exists():
|
1138 |
+
raise HTTPException(status_code=404, detail="Database file not found")
|
1139 |
+
|
1140 |
+
return FileResponse(
|
1141 |
+
path=str(db_file),
|
1142 |
+
filename="trees_database.db",
|
1143 |
+
media_type="application/x-sqlite3"
|
1144 |
+
)
|
1145 |
+
|
1146 |
+
@app.get("/download/csv", tags=["Downloads"])
|
1147 |
+
async def download_csv():
|
1148 |
+
"""Download the CSV backup file"""
|
1149 |
+
csv_file = Path("static/trees_backup.csv")
|
1150 |
+
if not csv_file.exists():
|
1151 |
+
# Try root location
|
1152 |
+
csv_file = Path("trees_backup.csv")
|
1153 |
+
if not csv_file.exists():
|
1154 |
+
raise HTTPException(status_code=404, detail="CSV file not found")
|
1155 |
+
|
1156 |
+
return FileResponse(
|
1157 |
+
path=str(csv_file),
|
1158 |
+
filename="trees_backup.csv",
|
1159 |
+
media_type="text/csv"
|
1160 |
+
)
|
1161 |
+
|
1162 |
+
@app.get("/download/status", tags=["Downloads"])
|
1163 |
+
async def download_status():
|
1164 |
+
"""Download the status report file"""
|
1165 |
+
status_file = Path("static/database_status.txt")
|
1166 |
+
if not status_file.exists():
|
1167 |
+
# Try root location
|
1168 |
+
status_file = Path("database_status.txt")
|
1169 |
+
if not status_file.exists():
|
1170 |
+
raise HTTPException(status_code=404, detail="Status file not found")
|
1171 |
+
|
1172 |
+
return FileResponse(
|
1173 |
+
path=str(status_file),
|
1174 |
+
filename="database_status.txt",
|
1175 |
+
media_type="text/plain"
|
1176 |
+
)
|
1177 |
+
|
1178 |
@app.get("/api/persistence/status", tags=["System"])
|
1179 |
async def get_persistence_status():
|
1180 |
"""Get database backup system status"""
|