nsedash / nsedash_app.py
Sam-max1's picture
Deploy bare minimum codebase for nsedash
1203c07 verified
Raw
History Blame Contribute Delete
7.59 kB
#!/usr/bin/env python3
"""
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
# ---------------------------------------------------------------------------
# CLI SWITCHES (mlbench pattern — parsed before argparse for env var side-effects)
# ---------------------------------------------------------------------------
#: -hf Force HuggingFace mode: bind 0.0.0.0:7860, activate HF dataset sync
ENABLE_HF = '-hf' in sys.argv or '--hf' in sys.argv
#: -noadmin Disable admin-only tools (script runner, data utilities)
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.")
# Disable CUDA inside Hugging Face Spaces mode to save resources
if "SPACE_ID" in os.environ or ENABLE_HF:
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
os.environ["HF_MODE"] = "1" # Also set from SPACE_ID detection
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...")
# 1. Mark as exiting so UI status calls see it
try:
service = app.extensions["nsedash"]["service"]
service.is_exiting = True
except Exception:
pass
# 2. Wait a short moment for UI to poll/receive the exiting state
time.sleep(1.5)
# 3. Clean up backend components
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()
# argparse flags also set env vars (in case user passed --hf instead of -hf)
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 & show splash screen
register_shutdown_handler(app)
print_console_splash(args.host, args.port)
# threaded=True: request handlers stay responsive while background
# crews run on the dedicated asyncio thread.
app.run(host=args.host, port=args.port, debug=args.debug, threaded=True)
if __name__ == "__main__":
main()