app.py 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. """
  2. Entry point for the unified LF-MRI GUI.
  3. Run from the repo root (MRI-testing/):
  4. python lf_mri_gui/app.py
  5. Or with optional pre-loads:
  6. python lf_mri_gui/app.py path/to/sequence.seq \\
  7. --hw-config lf_mri_gui/cfg/hw_config.json \\
  8. --output-dir /tmp/mri_output
  9. """
  10. from __future__ import annotations
  11. import os
  12. import sys
  13. # -- sys.path setup ------------------------------------------------------------
  14. # _here = apps/gui/ -> enables: from src.xxx import ...
  15. # _repo_root = repo root/ -> enables: local project imports
  16. # _lf_scanner_root = libs/lf-scanner/ -> enables: import pypulseq
  17. _here = os.path.dirname(os.path.abspath(__file__))
  18. _repo_root = os.path.dirname(os.path.dirname(_here))
  19. _lf_scanner_root = os.path.join(_repo_root, "libs", "lf-scanner")
  20. for _p in (_here, _repo_root, _lf_scanner_root):
  21. if _p not in sys.path:
  22. sys.path.insert(0, _p)
  23. import argparse
  24. from PySide6.QtWidgets import QApplication
  25. from src.app_window import LFMRIWindow
  26. def main() -> None:
  27. parser = argparse.ArgumentParser(
  28. description="LF-MRI System - unified scanner GUI"
  29. )
  30. parser.add_argument(
  31. "seq_file", nargs="?", default=None,
  32. help="Optional .seq file to pre-load in the Sequence tab",
  33. )
  34. parser.add_argument(
  35. "--hw-config", default=None,
  36. help="Optional hardware config JSON to load on startup",
  37. )
  38. parser.add_argument(
  39. "--output-dir", default=None,
  40. help="Optional output directory for exports",
  41. )
  42. args = parser.parse_args()
  43. app = QApplication(sys.argv)
  44. app.setApplicationName("LF-MRI System")
  45. app.setOrganizationName("LF-MRI")
  46. hw_config = os.path.abspath(args.hw_config) if args.hw_config and os.path.isfile(args.hw_config) else None
  47. output_dir = os.path.abspath(args.output_dir) if args.output_dir else None
  48. seq_file = os.path.abspath(args.seq_file) if args.seq_file and os.path.isfile(args.seq_file) else None
  49. # Load service URLs and mode from bundled config (fallback to defaults)
  50. _cfg_path = os.path.join(_here, "cfg", "server_config.json")
  51. orchestrator_url = "http://localhost:1717"
  52. seq_interp_url = "http://localhost:7475"
  53. spectroscopy_url = "http://localhost:8002"
  54. hw_mode = "plug"
  55. try:
  56. import json as _json
  57. with open(_cfg_path, encoding="utf-8") as _f:
  58. _cfg = _json.load(_f)
  59. orchestrator_url = _cfg.get("orchestrator_url", orchestrator_url)
  60. seq_interp_url = _cfg.get("seq_interp_url", seq_interp_url)
  61. spectroscopy_url = _cfg.get("spectroscopy_url", spectroscopy_url)
  62. hw_mode = _cfg.get("mode", hw_mode)
  63. except Exception:
  64. pass
  65. win = LFMRIWindow(
  66. hw_config_path=hw_config,
  67. output_dir=output_dir,
  68. seq_file=seq_file,
  69. orchestrator_url=orchestrator_url,
  70. seq_interp_url=seq_interp_url,
  71. spectroscopy_url=spectroscopy_url,
  72. hw_mode=hw_mode,
  73. )
  74. # Start in a maximized windowed state so the app fills the usable screen
  75. # area while preserving the native title bar and taskbar.
  76. win.showMaximized()
  77. sys.exit(app.exec())
  78. if __name__ == "__main__":
  79. main()