Download main.py from dn-scribe/attstore: direct link, hf CLI and curl.
- Browser
- Download file 3.94 kB
-
https://huggingface.co/spaces/dn-scribe/attstore/resolve/main/main.py
- Command line
-
hf download hf://spaces/dn-scribe/attstore/main.py
-
curl -L -o main.py https://huggingface.co/spaces/dn-scribe/attstore/resolve/main/main.py
3.94 kB
| import logging | |
| import os | |
| import threading | |
| import time | |
| from sqlalchemy import inspect | |
| from sqlalchemy.engine.url import make_url | |
| from app import app, db | |
| from config import PORT | |
| from werkzeug.serving import WSGIRequestHandler | |
| from logging_utils import cleanup_old_logs | |
| # --- Alembic migration runner --- | |
| from alembic import command | |
| from alembic.config import Config | |
| # On startup, run Alembic migrations to ensure DB schema is up to date. | |
| # To generate a migration after changing models: | |
| # 1. Run: alembic -c migrations/alembic.ini revision --autogenerate -m "Describe your change". To upstream: alembic -c migrations/alembic.ini upgrade head | |
| # 2. Review the migration file in migrations/versions/ | |
| # 3. (Optional) Edit for correctness | |
| # 4. Migrations will be applied automatically on next startup | |
| def run_migrations(): | |
| alembic_cfg = Config("migrations/alembic.ini") | |
| with app.app_context(): | |
| command.upgrade(alembic_cfg, "head") | |
| def ensure_sqlite_database(): | |
| """Bootstrap SQLite DB files before Alembic runs.""" | |
| db_uri = app.config.get("SQLALCHEMY_DATABASE_URI", "") | |
| if not db_uri.startswith("sqlite"): | |
| return | |
| url = make_url(db_uri) | |
| database = url.database | |
| if not database: | |
| return | |
| if os.path.isabs(database): | |
| db_path = database | |
| else: | |
| db_path = os.path.join(app.instance_path, database) | |
| os.makedirs(os.path.dirname(db_path), exist_ok=True) | |
| bootstrap_reason = None | |
| if not os.path.exists(db_path): | |
| bootstrap_reason = "file missing" | |
| else: | |
| with app.app_context(): | |
| inspector = inspect(db.engine) | |
| tables = inspector.get_table_names() | |
| if 'users' not in tables: | |
| bootstrap_reason = "schema missing" | |
| if not bootstrap_reason: | |
| logging.info(f"SQLite database already initialized at {db_path}") | |
| return | |
| logging.info(f"Bootstrapping SQLite database at {db_path} ({bootstrap_reason})") | |
| with app.app_context(): | |
| db.create_all() | |
| logging.info("SQLite database initialization complete") | |
| def schedule_log_cleanup(): | |
| """ | |
| Background thread that runs log cleanup daily. | |
| Cleans up logs older than LOG_RETENTION_DAYS (default: 10 days). | |
| """ | |
| def cleanup_thread(): | |
| while True: | |
| try: | |
| # Wait 24 hours between cleanups | |
| time.sleep(24 * 60 * 60) | |
| with app.app_context(): | |
| deleted = cleanup_old_logs() | |
| if deleted > 0: | |
| logging.info(f"Scheduled cleanup: removed {deleted} old log entries") | |
| except Exception as e: | |
| logging.error(f"Error in scheduled log cleanup: {e}") | |
| # Start cleanup thread as daemon so it exits when main thread exits | |
| thread = threading.Thread(target=cleanup_thread, daemon=True) | |
| thread.start() | |
| logging.info("Log cleanup scheduler started (runs daily)") | |
| # Filter out specific paths from Werkzeug logs | |
| class FilteredWSGIRequestHandler(WSGIRequestHandler): | |
| def log(self, type, message, *args): | |
| # Skip logging for Chrome DevTools discovery requests | |
| if '.well-known/appspecific/com.chrome.devtools.json' in message: | |
| return | |
| return super().log(type, message, *args) | |
| if __name__ == '__main__': | |
| from config import create_default_admin_user | |
| ensure_sqlite_database() | |
| run_migrations() # Always ensure DB schema is up to date before serving | |
| with app.app_context(): | |
| create_default_admin_user(app) | |
| # Run initial cleanup on startup | |
| cleanup_old_logs() | |
| # Start background log cleanup scheduler | |
| schedule_log_cleanup() | |
| # Use filtered request handler | |
| debug_mode = os.environ.get('FLASK_DEBUG', 'false').lower() in ('true', '1', 'yes') | |
| app.run(host='0.0.0.0', port=PORT, debug=debug_mode, request_handler=FilteredWSGIRequestHandler) | |