reconstruct.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. import io, os, json, zipfile, traceback
  2. from fastapi import APIRouter, BackgroundTasks, HTTPException
  3. from fastapi.responses import FileResponse, StreamingResponse
  4. import matplotlib.pyplot as plt
  5. from ..core import EXECUTOR
  6. from ..schemas import StartSessionRequest, SessionStatus
  7. from ..session import Session, SESSIONS
  8. from ..storage import FILES
  9. from ..utils import SavefigRedirect, collect_outputs
  10. from ..recon_app import ReconstructionApp, ReconstructionH5
  11. router = APIRouter()
  12. @router.post("/reconstruct", response_model=SessionStatus)
  13. def reconstruct(req: StartSessionRequest, background: BackgroundTasks):
  14. if req.file_raw_id not in FILES: raise HTTPException(400, "file_raw_id не найден")
  15. if req.file_json_id not in FILES: raise HTTPException(400, "file_json_id не найден")
  16. if req.file_order_id and req.file_order_id not in FILES: raise HTTPException(400, "file_order_id не найден")
  17. session = Session(
  18. FILES[req.file_raw_id],
  19. FILES[req.file_json_id],
  20. FILES.get(req.file_order_id) if req.file_order_id else None,
  21. req.sequence_name, req.digit, req.phase_shift
  22. )
  23. SESSIONS[session.session_id] = session
  24. def _run():
  25. savefig_orig = plt.savefig
  26. try:
  27. session.set(status="running", progress=0.1, message="init")
  28. with SavefigRedirect(session.work_dir):
  29. app_reco = ReconstructionApp(name=session.sequence_name, digit=session.digit, shift=session.phase_shift)
  30. session.set(progress=0.2, message="read + prepare")
  31. app_reco.start_reconstruction(
  32. path_raw_data=session.file_raw,
  33. path_np_data_json=session.file_json,
  34. path_order_json=session.file_order if session.file_order else session.file_json
  35. )
  36. session.set(progress=0.95, message="collect results")
  37. session.result_files = collect_outputs(session.work_dir)
  38. session.set(status="done", progress=1.0, message="done")
  39. except Exception:
  40. session.error_traceback = traceback.format_exc()
  41. session.set(status="error", message="error")
  42. finally:
  43. plt.savefig = savefig_orig
  44. with open(os.path.join(session.work_dir, "status.json"), "w", encoding="utf-8") as f:
  45. json.dump(session.to_status().model_dump(), f, ensure_ascii=False, indent=2)
  46. background.add_task(EXECUTOR.submit, _run)
  47. return session.to_status()
  48. @router.post("/h5/reconstruct", response_model=SessionStatus)
  49. def reconstructFromH5(req: StartSessionRequest, background: BackgroundTasks):
  50. if req.file_raw_id not in FILES: raise HTTPException(400, "file_raw_id не найден")
  51. if req.file_json_id not in FILES: raise HTTPException(400, "file_json_id не найден")
  52. if req.file_order_id and req.file_order_id not in FILES: raise HTTPException(400, "file_order_id не найден")
  53. session = Session(
  54. FILES[req.file_raw_id],
  55. FILES[req.file_json_id],
  56. FILES.get(req.file_order_id) if req.file_order_id else None,
  57. req.sequence_name, req.digit, req.phase_shift
  58. )
  59. SESSIONS[session.session_id] = session
  60. def _run():
  61. savefig_orig = plt.savefig
  62. try:
  63. session.set(status="running", progress=0.1, message="init")
  64. with SavefigRedirect(session.work_dir):
  65. app_reco = ReconstructionH5(name=session.sequence_name, digit=session.digit, shift=session.phase_shift)
  66. session.set(progress=0.2, message="read + prepare")
  67. app_reco.start_reconstruction(
  68. path_raw_data=session.file_raw,
  69. path_np_data_json=session.file_json,
  70. path_order_json=session.file_order if session.file_order else session.file_json
  71. )
  72. session.set(progress=0.95, message="collect results")
  73. session.result_files = collect_outputs(session.work_dir)
  74. session.set(status="done", progress=1.0, message="done")
  75. except Exception:
  76. session.error_traceback = traceback.format_exc()
  77. session.set(status="error", message="error")
  78. finally:
  79. plt.savefig = savefig_orig
  80. with open(os.path.join(session.work_dir, "status.json"), "w", encoding="utf-8") as f:
  81. json.dump(session.to_status().model_dump(), f, ensure_ascii=False, indent=2)
  82. background.add_task(EXECUTOR.submit, _run)
  83. return session.to_status()
  84. @router.get("/sessions/{session_id}", response_model=SessionStatus)
  85. def get_status(session_id: str):
  86. session = SESSIONS.get(session_id)
  87. if not session: raise HTTPException(404, "не найден")
  88. return session.to_status()
  89. @router.get("/sessions/{session_id}/files")
  90. def list_files(session_id: str):
  91. session = SESSIONS.get(session_id)
  92. if not session: raise HTTPException(404, "не найден")
  93. files = [os.path.basename(p) for p in session.result_files if os.path.isfile(p)]
  94. return {"files": files}
  95. @router.get("/sessions/{session_id}/files/{name}")
  96. def download_file(session_id: str, name: str):
  97. session = SESSIONS.get(session_id)
  98. if not session: raise HTTPException(404, "не найден")
  99. target = os.path.join(session.work_dir, name)
  100. if not os.path.isfile(target): raise HTTPException(404, "файл не найден")
  101. return FileResponse(target, filename=name)
  102. @router.get("/sessions/{session_id}/archive.zip")
  103. def download_zip(session_id: str):
  104. session = SESSIONS.get(session_id)
  105. if not session: raise HTTPException(404, "не найден")
  106. mem = io.BytesIO()
  107. with zipfile.ZipFile(mem, "w", zipfile.ZIP_DEFLATED) as zf:
  108. for p in session.result_files:
  109. if os.path.isfile(p):
  110. zf.write(p, arcname=os.path.basename(p))
  111. zf.writestr("status.json", json.dumps(session.to_status().model_dump(), ensure_ascii=False, indent=2))
  112. mem.seek(0)
  113. return StreamingResponse(mem, media_type="application/zip",
  114. headers={"Content-Disposition": f'attachment; filename=\"%s.zip\"' % session.session_id})
  115. @router.delete("/sessions/{session_id}")
  116. def delete_session(session_id: str):
  117. from shutil import rmtree
  118. session = SESSIONS.pop(session_id, None)
  119. if not session: raise HTTPException(404, "не найден")
  120. rmtree(session.work_dir, ignore_errors=True)
  121. return {"deleted": session_id}