Spaces:
Runtime error
Runtime error
| # Backup_Manager.py | |
| # | |
| # Imports: | |
| import os | |
| import shutil | |
| import sqlite3 | |
| from datetime import datetime | |
| import logging | |
| # | |
| # Local Imports: | |
| from App_Function_Libraries.DB.Character_Chat_DB import chat_DB_PATH | |
| from App_Function_Libraries.DB.RAG_QA_Chat_DB import get_rag_qa_db_path | |
| from App_Function_Libraries.Utils.Utils import get_project_relative_path | |
| # | |
| # End of Imports | |
| ####################################################################################################################### | |
| # | |
| # Functions: | |
| def init_backup_directory(backup_base_dir: str, db_name: str) -> str: | |
| """Initialize backup directory for a specific database.""" | |
| backup_dir = os.path.join(backup_base_dir, db_name) | |
| os.makedirs(backup_dir, exist_ok=True) | |
| return backup_dir | |
| def create_backup(db_path: str, backup_dir: str, db_name: str) -> str: | |
| """Create a full backup of the database.""" | |
| try: | |
| db_path = os.path.abspath(db_path) | |
| backup_dir = os.path.abspath(backup_dir) | |
| logging.info(f"Creating backup:") | |
| logging.info(f" DB Path: {db_path}") | |
| logging.info(f" Backup Dir: {backup_dir}") | |
| logging.info(f" DB Name: {db_name}") | |
| # Create subdirectory based on db_name | |
| specific_backup_dir = os.path.join(backup_dir, db_name) | |
| os.makedirs(specific_backup_dir, exist_ok=True) | |
| timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | |
| backup_file = os.path.join(specific_backup_dir, f"{db_name}_backup_{timestamp}.db") | |
| logging.info(f" Full backup path: {backup_file}") | |
| # Create a backup using SQLite's backup API | |
| with sqlite3.connect(db_path) as source, \ | |
| sqlite3.connect(backup_file) as target: | |
| source.backup(target) | |
| logging.info(f"Backup created successfully: {backup_file}") | |
| return f"Backup created: {backup_file}" | |
| except Exception as e: | |
| error_msg = f"Failed to create backup: {str(e)}" | |
| logging.error(error_msg) | |
| return error_msg | |
| def create_incremental_backup(db_path: str, backup_dir: str, db_name: str) -> str: | |
| """Create an incremental backup using VACUUM INTO.""" | |
| try: | |
| timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | |
| backup_file = os.path.join(backup_dir, | |
| f"{db_name}_incremental_{timestamp}.sqlib") | |
| with sqlite3.connect(db_path) as conn: | |
| conn.execute(f"VACUUM INTO '{backup_file}'") | |
| logging.info(f"Incremental backup created: {backup_file}") | |
| return f"Incremental backup created: {backup_file}" | |
| except Exception as e: | |
| error_msg = f"Failed to create incremental backup: {str(e)}" | |
| logging.error(error_msg) | |
| return error_msg | |
| def list_backups(backup_dir: str) -> str: | |
| """List all available backups.""" | |
| try: | |
| backups = [f for f in os.listdir(backup_dir) | |
| if f.endswith(('.db', '.sqlib'))] | |
| backups.sort(reverse=True) # Most recent first | |
| return "\n".join(backups) if backups else "No backups found" | |
| except Exception as e: | |
| error_msg = f"Failed to list backups: {str(e)}" | |
| logging.error(error_msg) | |
| return error_msg | |
| def restore_single_db_backup(db_path: str, backup_dir: str, db_name: str, backup_name: str) -> str: | |
| """Restore database from a backup file.""" | |
| try: | |
| logging.info(f"Restoring backup: {backup_name}") | |
| backup_path = os.path.join(backup_dir, backup_name) | |
| if not os.path.exists(backup_path): | |
| logging.error(f"Backup file not found: {backup_name}") | |
| return f"Backup file not found: {backup_name}" | |
| # Create a timestamp for the current db | |
| timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | |
| current_backup = os.path.join(backup_dir, | |
| f"{db_name}_pre_restore_{timestamp}.db") | |
| # Backup current database before restore | |
| logging.info(f"Creating backup of current database: {current_backup}") | |
| shutil.copy2(db_path, current_backup) | |
| # Restore the backup | |
| logging.info(f"Restoring database from {backup_name}") | |
| shutil.copy2(backup_path, db_path) | |
| logging.info(f"Database restored from {backup_name}") | |
| return f"Database restored from {backup_name}" | |
| except Exception as e: | |
| error_msg = f"Failed to restore backup: {str(e)}" | |
| logging.error(error_msg) | |
| return error_msg | |
| def setup_backup_config(): | |
| """Setup configuration for database backups.""" | |
| backup_base_dir = get_project_relative_path('tldw_DB_Backups') | |
| logging.info(f"Base backup directory: {os.path.abspath(backup_base_dir)}") | |
| # RAG Chat DB configuration | |
| rag_db_path = get_rag_qa_db_path() | |
| rag_backup_dir = os.path.join(backup_base_dir, 'rag_chat') | |
| os.makedirs(rag_backup_dir, exist_ok=True) | |
| logging.info(f"RAG backup directory: {os.path.abspath(rag_backup_dir)}") | |
| rag_db_config = { | |
| 'db_path': rag_db_path, | |
| 'backup_dir': rag_backup_dir, # Make sure we use the full path | |
| 'db_name': 'rag_qa' | |
| } | |
| # Character Chat DB configuration | |
| char_backup_dir = os.path.join(backup_base_dir, 'character_chat') | |
| os.makedirs(char_backup_dir, exist_ok=True) | |
| logging.info(f"Character backup directory: {os.path.abspath(char_backup_dir)}") | |
| char_db_config = { | |
| 'db_path': chat_DB_PATH, | |
| 'backup_dir': char_backup_dir, # Make sure we use the full path | |
| 'db_name': 'chatDB' | |
| } | |
| # Media DB configuration (based on your logs) | |
| media_backup_dir = os.path.join(backup_base_dir, 'media') | |
| os.makedirs(media_backup_dir, exist_ok=True) | |
| logging.info(f"Media backup directory: {os.path.abspath(media_backup_dir)}") | |
| media_db_config = { | |
| 'db_path': os.path.join(os.path.dirname(chat_DB_PATH), 'media_summary.db'), | |
| 'backup_dir': media_backup_dir, | |
| 'db_name': 'media' | |
| } | |
| return rag_db_config, char_db_config, media_db_config | |