| |
| """ |
| NSE Stock Dashboard (NSEDashboard) Application Entry Point. |
| |
| This module serves as the primary executable entry point for the NSE Stock |
| Dashboard Flask application. It parses command-line arguments to configure |
| the server settings (base directory, host interface, port, and debug mode), |
| initializes the Flask application with all required services, and starts |
| the Flask WSGI server with multithreading enabled. |
| |
| Features: |
| - Configurable base data directory via command line or environment variables. |
| - Integrated background task processing framework. |
| - Multi-threaded Flask server configuration to maintain frontend responsiveness. |
| |
| Usage: |
| python nsedash_app.py [--base-dir BASE_DIR] [--host HOST] [--port PORT] [--debug] |
| |
| Options: |
| --base-dir DIR Specify the directory containing the processed stock data files. |
| If not provided, the current working directory or the value of the |
| $NSEDASH_BASE_DIR environment variable is used. |
| --host HOST Host interface to bind the web server to (default: 127.0.0.1). |
| --port PORT Port to listen on (default: 5000). |
| --debug Run the Flask application in debug mode. |
| """ |
|
|
| import argparse |
| import os |
| import signal |
| import sys |
| import time |
|
|
| |
| |
| |
|
|
| |
| ENABLE_HF = '-hf' in sys.argv or '--hf' in sys.argv |
|
|
| |
| ENABLE_NOADMIN = '-noadmin' in sys.argv or '--noadmin' in sys.argv |
|
|
| if ENABLE_HF: |
| os.environ["HF_MODE"] = "1" |
| print("[*] HF mode (-hf): Enabled — binding 0.0.0.0:7860, HF dataset sync active.") |
|
|
| if ENABLE_NOADMIN: |
| os.environ["ADMIN_MODE"] = "0" |
| print("[*] No-admin (-noadmin): Enabled — admin tools disabled.") |
|
|
| |
| if "SPACE_ID" in os.environ or ENABLE_HF: |
| os.environ["CUDA_VISIBLE_DEVICES"] = "-1" |
| os.environ["HF_MODE"] = "1" |
|
|
| from nsedash.web import create_app |
|
|
|
|
| def get_gpu_info() -> str: |
| gpu_info = "CPU Only (No GPU detected)" |
| try: |
| import torch |
| if torch.cuda.is_available(): |
| gpu_info = f"CUDA Active - {torch.cuda.get_device_name(0)}" |
| except ImportError: |
| pass |
| |
| try: |
| if gpu_info == "CPU Only (No GPU detected)": |
| import tensorflow as tf |
| gpus = tf.config.list_physical_devices('GPU') |
| if gpus: |
| gpu_info = f"TensorFlow Active - {len(gpus)} GPU(s)" |
| except ImportError: |
| pass |
| return gpu_info |
|
|
|
|
| def print_console_splash(host, port): |
| display_host = "localhost" if host in ("127.0.0.1", "0.0.0.0") else host |
| gpu_info = get_gpu_info() |
| is_hf = os.environ.get("HF_MODE") == "1" or "SPACE_ID" in os.environ |
| admin_enabled = os.environ.get("ADMIN_MODE", "1") == "1" |
|
|
| banner = r""" |
| ====================================================================== |
| _ _ ____ _____ ____ _ ____ _ _ ____ ___ _ ____ ____ |
| | \ | / ___|| ____| _ \ / \ / ___|| | | | _ \ / _ \ / \ | _ \| _ \ |
| | \| \___ \| _| | | | / _ \\___ \| |_| | |_) | | | / _ \| |_) | | | | |
| | |\ |___) | |___| |_| / ___ \___) | _ | _ <| |_| / ___ \ _ <| |_| | |
| |_| \_|____/|_____|____/_/ \_\____/|_| |_|_| \_\\___/_/ \_\_| \_\____/ |
| ====================================================================== |
| """ |
| print(banner) |
| print(f" * NSE Stock Dashboard (Flask v5.0)") |
| print(f" * Running on: http://{display_host}:{port}/") |
| print(f" * GPU in use: {gpu_info}") |
| print(f" * HF Mode: {'Enabled (HF dataset sync active)' if is_hf else 'Disabled (local mode)'}") |
| print(f" * Admin Mode: {'Enabled' if admin_enabled else 'Disabled (-noadmin)'}") |
| print(f" * Auth: userid + password + TOTP (mlbench pattern)") |
| print(f" * Press Ctrl+C in console to exit gracefully.") |
| print("======================================================================\n") |
|
|
|
|
| _shutdown_in_progress = False |
|
|
| def register_shutdown_handler(app): |
| def handle_sigint(signum, frame): |
| global _shutdown_in_progress |
| if _shutdown_in_progress: |
| return |
| _shutdown_in_progress = True |
| |
| print("\n[Shutdown] Gracefully shutting down nsedash backend...") |
| |
| |
| try: |
| service = app.extensions["nsedash"]["service"] |
| service.is_exiting = True |
| except Exception: |
| pass |
| |
| |
| time.sleep(1.5) |
| |
| |
| try: |
| scheduler = app.extensions["nsedash"]["scheduler"] |
| scheduler.stop() |
| except Exception: |
| pass |
| |
| try: |
| scripts = app.extensions["nsedash"]["scripts"] |
| for run in list(scripts._runs.values()): |
| if run.process and run.process.poll() is None: |
| run.process.terminate() |
| try: |
| run.process.wait(timeout=1.0) |
| except Exception: |
| run.process.kill() |
| except Exception: |
| pass |
| |
| try: |
| runtime = app.extensions["nsedash"]["runtime"] |
| runtime.shutdown() |
| except Exception: |
| pass |
| |
| print("[Shutdown] Backend shutdown complete. Exiting process.") |
| sys.exit(0) |
| |
| signal.signal(signal.SIGINT, handle_sigint) |
|
|
|
|
| def main(): |
| parser = argparse.ArgumentParser( |
| description="NSE Stock Dashboard (Flask)", |
| formatter_class=argparse.RawDescriptionHelpFormatter, |
| epilog=""" |
| CLI switches (mlbench pattern, checked before argparse): |
| -hf Force HuggingFace mode: 0.0.0.0:7860, HF dataset sync |
| -noadmin Disable admin tools (script runner, data utilities) |
| """, |
| ) |
| parser.add_argument("--base-dir", default=None, |
| help="Base data directory (default: CWD or $NSEDASH_BASE_DIR)") |
|
|
| is_hf = ENABLE_HF or ("SPACE_ID" in os.environ) |
| default_host = "0.0.0.0" if is_hf else "127.0.0.1" |
| default_port = 7860 if is_hf else 5000 |
|
|
| parser.add_argument("--host", default=default_host) |
| parser.add_argument("--port", type=int, default=default_port) |
| parser.add_argument("--debug", action="store_true") |
| parser.add_argument("--hf", action="store_true", help="Force HF mode (same as -hf switch)") |
| parser.add_argument("--noadmin", action="store_true", help="Disable admin tools (same as -noadmin switch)") |
| args = parser.parse_args() |
|
|
| |
| if args.hf: |
| os.environ["HF_MODE"] = "1" |
| if args.noadmin: |
| os.environ["ADMIN_MODE"] = "0" |
|
|
| app = create_app(args.base_dir) |
|
|
| |
| register_shutdown_handler(app) |
| print_console_splash(args.host, args.port) |
|
|
| |
| |
| app.run(host=args.host, port=args.port, debug=args.debug, threaded=True) |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|