diff --git a/src/murfey/server/api/instrument.py b/src/murfey/server/api/instrument.py index 9606a0f6b..7f5f34dcb 100644 --- a/src/murfey/server/api/instrument.py +++ b/src/murfey/server/api/instrument.py @@ -19,8 +19,15 @@ from smartem_backend.keycloak_client import KeycloakClient, load_keycloak_config from smartem_common.schemas import AcquisitionData, MicroscopeData + from murfey.util.config import get_security_config + keycloak_client = KeycloakClient( - load_keycloak_config(Path(os.getenv("SMARTEM_KEYCLOAK_CONFIGURATION") or "")) + load_keycloak_config( + Path( + os.getenv("SMARTEM_KEYCLOAK_CONFIGURATION") + or get_security_config().smartem_keycloak_config + ) + ) ) SMARTEM_ACTIVE = True except ImportError: diff --git a/src/murfey/server/api/session_control.py b/src/murfey/server/api/session_control.py index c789b1901..256a93634 100644 --- a/src/murfey/server/api/session_control.py +++ b/src/murfey/server/api/session_control.py @@ -9,16 +9,24 @@ from fastapi.responses import FileResponse from ispyb.sqlalchemy import AutoProcProgram as ISPyBAutoProcProgram from pydantic import BaseModel -from sqlalchemy import func +from sqlalchemy import desc, func from sqlmodel import select try: + from smartem_agent.fs_parser import EpuParser from smartem_backend.api_client import SmartEMAPIClient from smartem_backend.keycloak_client import KeycloakClient, load_keycloak_config - from smartem_common.schemas import AtlasData + from smartem_common.schemas import AtlasTileGridSquarePositionData + + from murfey.util.config import get_security_config keycloak_client = KeycloakClient( - load_keycloak_config(Path(os.getenv("SMARTEM_KEYCLOAK_CONFIGURATION") or "")) + load_keycloak_config( + Path( + os.getenv("SMARTEM_KEYCLOAK_CONFIGURATION") + or get_security_config().smartem_keycloak_config + ) + ) ) SMARTEM_ACTIVE = True except ImportError: @@ -390,12 +398,23 @@ def register_atlas( keycloak_client=keycloak_client, ) grid_uuid = None + atlas_path = None if atlas_registration_data.tag: dcg = db.exec( select(DataCollectionGroup) .where(DataCollectionGroup.session_id == session_id) .where(DataCollectionGroup.tag == atlas_registration_data.tag) ).one_or_none() + if dcg is None: + sample = int( + atlas_registration_data.tag.split("Sample")[1].split("/")[0] + ) + dcg = db.exec( + select(DataCollectionGroup) + .where(DataCollectionGroup.session_id == session_id) + .where(DataCollectionGroup.sample == sample) + .order_by(desc(DataCollectionGroup.id)) + ).first() grid_uuid = dcg.smartem_grid_uuid else: possible_grids = smartem_client.get_acquisition_grids( @@ -404,8 +423,9 @@ def register_atlas( for grid in possible_grids: if grid.name == atlas_registration_data.name.replace("_atlas", ""): grid_uuid = grid.uuid + atlas_path = Path(grid.atlas_dir).parent break - if grid_uuid is not None: + if grid_uuid is not None and atlas_path is not None: existing_atlas = smartem_client.get_grid_atlas(grid_uuid) if ( existing_atlas.name == atlas_registration_data.name @@ -414,16 +434,29 @@ def register_atlas( ): # there is a question here of whether the grid should be registered if specified return - atlas_data = AtlasData( - id=atlas_registration_data.name, - acquisition_date=datetime.now(), - storage_folder=atlas_registration_data.storage_folder, - name=atlas_registration_data.name, - tiles=[], - gridsquare_positions=None, - grid_uuid=grid_uuid, + parser = EpuParser() + atlas_data = parser.parse_atlas_manifest( + str(atlas_path / "Atlas.dm"), grid_uuid ) + atlas_data.acquisition_date = atlas_data.acquisition_date.replace( + tzinfo=None + ) # timezone information is not consistently provided so drop it smartem_client.create_grid_atlas(atlas_data) + registered_squares = smartem_client.get_grid_gridsquares(grid_uuid) + gs_uuid_map = {gs.gridsquare_id: gs.uuid for gs in registered_squares} + for atlastile in atlas_data.tiles: + pos_data_for_tile = [] + for gsid, gs_tile_pos in atlastile.gridsquare_positions.items(): + for pos in gs_tile_pos: + pos_data_for_tile.append( + AtlasTileGridSquarePositionData( + gridsquare_uuid=gs_uuid_map[gsid], + tile_uuid=atlastile.uuid, + position=pos.position, + size=pos.size, + ) + ) + smartem_client.link_atlas_tile_and_gridsquares(pos_data_for_tile) if atlas_registration_data.register_grid: smartem_client.grid_registered(grid_uuid) else: diff --git a/src/murfey/server/api/workflow.py b/src/murfey/server/api/workflow.py index 195897d3e..4d82f6ec7 100644 --- a/src/murfey/server/api/workflow.py +++ b/src/murfey/server/api/workflow.py @@ -30,8 +30,15 @@ MicrographManifest as SmartEMMicrographManifest, ) + from murfey.util.config import get_security_config + keycloak_client = KeycloakClient( - load_keycloak_config(Path(os.getenv("SMARTEM_KEYCLOAK_CONFIGURATION") or "")) + load_keycloak_config( + Path( + os.getenv("SMARTEM_KEYCLOAK_CONFIGURATION") + or get_security_config().smartem_keycloak_config + ) + ) ) SMARTEM_ACTIVE = True except ImportError: diff --git a/src/murfey/util/config.py b/src/murfey/util/config.py index fcf7ca243..e392eb0e8 100644 --- a/src/murfey/util/config.py +++ b/src/murfey/util/config.py @@ -261,6 +261,9 @@ class Security(BaseModel): session_token_timeout: Optional[int] = None allow_origins: list[str] = ["*"] + # SmartEM keycloak config file + smartem_keycloak_config: str = "" + # RabbitMQ settings rabbitmq_credentials: Path feedback_queue: str = "murfey_feedback" diff --git a/src/murfey/workflows/spa/ctf_estimation.py b/src/murfey/workflows/spa/ctf_estimation.py index 5f88abd77..799cc0612 100644 --- a/src/murfey/workflows/spa/ctf_estimation.py +++ b/src/murfey/workflows/spa/ctf_estimation.py @@ -15,12 +15,25 @@ try: from smartem_backend.api_client import SmartEMAPIClient from smartem_backend.keycloak_client import KeycloakClient, load_keycloak_config - from smartem_backend.model.http_request import MicrographUpdateRequest - from smartem_backend.model.http_response import MicrographResponse + from smartem_backend.model.http_request import ( + CtfEstimationRegisteredRequest, + MicrographUpdateRequest, + ) + from smartem_backend.model.http_response import ( + MicrographResponse, + ProcessingFeedbackPublishResponse, + ) from smartem_common.entity_status import MicrographStatus + from murfey.util.config import get_security_config + keycloak_client = KeycloakClient( - load_keycloak_config(Path(os.getenv("SMARTEM_KEYCLOAK_CONFIGURATION") or "")) + load_keycloak_config( + Path( + os.getenv("SMARTEM_KEYCLOAK_CONFIGURATION") + or get_security_config().smartem_keycloak_config + ) + ) ) SMARTEM_ACTIVE = True except ImportError: @@ -55,6 +68,15 @@ def ctf_estimated(message: dict, murfey_db: Session) -> dict[str, bool]: update, MicrographResponse, ) + registered_request = CtfEstimationRegisteredRequest( + quality=True, metric_name="ctfmaxresolution" + ) # True is a placeholder until we figure out the best way to calculate this + smartem_client._request( + "post", + f"micrographs/{movie.smartem_uuid}/ctf_estimation/registered", + registered_request, + ProcessingFeedbackPublishResponse, + ) except Exception: logger.warning( "Failed to emit CTF estimation complete event to smartem", diff --git a/src/murfey/workflows/spa/flush_spa_preprocess.py b/src/murfey/workflows/spa/flush_spa_preprocess.py index 39d3547dc..6541d537c 100644 --- a/src/murfey/workflows/spa/flush_spa_preprocess.py +++ b/src/murfey/workflows/spa/flush_spa_preprocess.py @@ -17,8 +17,15 @@ GridSquareMetadata as SmartEMGridSquareMetadata, ) + from murfey.util.config import get_security_config + keycloak_client = KeycloakClient( - load_keycloak_config(Path(os.getenv("SMARTEM_KEYCLOAK_CONFIGURATION") or "")) + load_keycloak_config( + Path( + os.getenv("SMARTEM_KEYCLOAK_CONFIGURATION") + or get_security_config().smartem_keycloak_config + ) + ) ) SMARTEM_ACTIVE = True except ImportError: diff --git a/src/murfey/workflows/spa/motion_correction.py b/src/murfey/workflows/spa/motion_correction.py index 8aa5c6a2d..218da437b 100644 --- a/src/murfey/workflows/spa/motion_correction.py +++ b/src/murfey/workflows/spa/motion_correction.py @@ -15,12 +15,25 @@ try: from smartem_backend.api_client import SmartEMAPIClient from smartem_backend.keycloak_client import KeycloakClient, load_keycloak_config - from smartem_backend.model.http_request import MicrographUpdateRequest - from smartem_backend.model.http_response import MicrographResponse + from smartem_backend.model.http_request import ( + MicrographUpdateRequest, + MotionCorrectionRegisteredRequest, + ) + from smartem_backend.model.http_response import ( + MicrographResponse, + ProcessingFeedbackPublishResponse, + ) from smartem_common.entity_status import MicrographStatus + from murfey.util.config import get_security_config + keycloak_client = KeycloakClient( - load_keycloak_config(Path(os.getenv("SMARTEM_KEYCLOAK_CONFIGURATION") or "")) + load_keycloak_config( + Path( + os.getenv("SMARTEM_KEYCLOAK_CONFIGURATION") + or get_security_config().smartem_keycloak_config + ) + ) ) SMARTEM_ACTIVE = True except ImportError: @@ -57,6 +70,15 @@ def motion_corrected(message: dict, murfey_db: Session) -> dict[str, bool]: update, MicrographResponse, ) + registered_request = MotionCorrectionRegisteredRequest( + quality=True, metric_name="motioncorrection" + ) # True is a placeholder until we figure out the best way to calculate this + smartem_client._request( + "post", + f"micrographs/{movie.smartem_uuid}/motion_correction/registered", + registered_request, + ProcessingFeedbackPublishResponse, + ) except Exception: logger.warning( "Failed to emit motion correction complete event to smartem", diff --git a/src/murfey/workflows/spa/picking.py b/src/murfey/workflows/spa/picking.py index ec229fc30..500738de7 100644 --- a/src/murfey/workflows/spa/picking.py +++ b/src/murfey/workflows/spa/picking.py @@ -38,8 +38,15 @@ from smartem_backend.model.http_response import MicrographResponse from smartem_common.entity_status import MicrographStatus + from murfey.util.config import get_security_config + keycloak_client = KeycloakClient( - load_keycloak_config(Path(os.getenv("SMARTEM_KEYCLOAK_CONFIGURATION") or "")) + load_keycloak_config( + Path( + os.getenv("SMARTEM_KEYCLOAK_CONFIGURATION") + or get_security_config().smartem_keycloak_config + ) + ) ) SMARTEM_ACTIVE = True except ImportError: