app.py 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  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 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. try:
  55. import json as _json
  56. with open(_cfg_path, encoding="utf-8") as _f:
  57. _cfg = _json.load(_f)
  58. orchestrator_url = _cfg.get("orchestrator_url", orchestrator_url)
  59. seq_interp_url = _cfg.get("seq_interp_url", seq_interp_url)
  60. spectroscopy_url = _cfg.get("spectroscopy_url", spectroscopy_url)
  61. except Exception:
  62. pass
  63. win = LFMRIWindow(
  64. hw_config_path=hw_config,
  65. output_dir=output_dir,
  66. seq_file=seq_file,
  67. orchestrator_url=orchestrator_url,
  68. seq_interp_url=seq_interp_url,
  69. spectroscopy_url=spectroscopy_url,
  70. )
  71. # Start in a maximized windowed state so the app fills the usable screen
  72. # area while preserving the native title bar and taskbar.
  73. win.showMaximized()
  74. sys.exit(app.exec())
  75. if __name__ == "__main__":
  76. main()