diff --git a/bayer/epdb_hooks.py b/bayer/epdb_hooks.py index a1a237f5..a5279572 100644 --- a/bayer/epdb_hooks.py +++ b/bayer/epdb_hooks.py @@ -13,6 +13,14 @@ register_template( "modals.collections.compound", "modals/collections/new_pes_modal.html", ) +register_template( + "epdb.actions.objects.pathway.add", + "actions/objects/pathway_add_pes.html", +) +register_template( + "epdb.modals.objects.pathway.add", + "modals/objects/add_pathway_pes_node_modal.html" +) # PES Viz register_template( diff --git a/bayer/templates/actions/objects/pathway_add_pes.html b/bayer/templates/actions/objects/pathway_add_pes.html new file mode 100644 index 00000000..41490fb1 --- /dev/null +++ b/bayer/templates/actions/objects/pathway_add_pes.html @@ -0,0 +1,8 @@ +
  • + + Add PES +
  • \ No newline at end of file diff --git a/bb4g/__init__.py b/bb4g/__init__.py new file mode 100644 index 00000000..1a26effb --- /dev/null +++ b/bb4g/__init__.py @@ -0,0 +1,161 @@ +import json +import math +from datetime import datetime +from typing import List + +import requests +from django.conf import settings as s + +from bridge.contracts import Classifier # noqa: I001 +from bridge.dto import ( + BuildResult, + EnviPyDTO, + EvaluationResult, + RunResult, + TransformationProductPrediction, +) # noqa: I001 + + +# Once stable these will be exposed by enviPy-plugins lib +class BB4G(Classifier): + Config = None + + def __init__(self, config=None): + super().__init__(config) + self.url = f"{s.BB4G_URL}" + + self.token = self.acquire_token() + self.header = { + "Authorization": f"Bearer {self.token}", + "Content-Type": "application/json", + } + self.proxies = { + "http": s.HTTP_PROXY, + "https": s.HTTPS_PROXY, + } + + def acquire_token(self): + BB4G_TENANT_ID = s.BB4G_TENANT_ID + BB4G_CLIENT_ID = s.BB4G_CLIENT_ID + BB4G_CLIENT_SECRET = s.BB4G_CLIENT_SECRET + BB4G_SCOPE = s.BB4G_SCOPE + + BB4G_TOKEN_URL = f"https://login.microsoftonline.com/{BB4G_TENANT_ID}/oauth2/v2.0/token" + + payload = { + "client_id": BB4G_CLIENT_ID, + "client_secret": BB4G_CLIENT_SECRET, + "scope": BB4G_SCOPE, + "grant_type": "client_credentials" + } + + # No Proxy required, URL is whitelisted + res = requests.post(BB4G_TOKEN_URL, data=payload) + + res.raise_for_status() + + return res.json()["access_token"] + + def start(self): + header = { + "Authorization": f"Bearer {self.token}", + "Content-Type": "application/json", + } + + started = False + retries = 0 + while not started and retries < 5: + res = requests.post(f"{self.url}/start", headers=header, data={}, proxies=self.proxies) + + if res.status_code == 200: + started = True + elif res.status_code in [500, 502]: + retries += 1 + import time + time.sleep(5) + else: + raise ValueError(f"Unexpected status code: {res.status_code}") + + @classmethod + def requires_rule_packages(cls) -> bool: + return False + + @classmethod + def requires_data_packages(cls) -> bool: + return False + + @classmethod + def identifier(cls) -> str: + return "bb4g" + + @classmethod + def name(cls) -> str: + return "BB4G Template Free Model" + + @classmethod + def display(cls) -> str: + return "BB4G Template Free Model" + + def build(self, eP: EnviPyDTO, *args, **kwargs) -> BuildResult | None: + return + + def run(self, eP: EnviPyDTO, *args, **kwargs) -> RunResult: + + # Ensure Service is running + self.start() + + smiles = [c.smiles for c in eP.get_compounds()] + preds = self._post(smiles) + + results = [] + + for substrate in preds.keys(): + results.append( + TransformationProductPrediction( + substrate=substrate, + products=preds[substrate], + ) + ) + + return RunResult( + producer=eP.get_context().url, + description=f"Generated at {datetime.now()}", + result=results, + ) + + def evaluate(self, eP: EnviPyDTO, *args, **kwargs) -> EvaluationResult: + pass + + def build_and_evaluate(self, eP: EnviPyDTO, *args, **kwargs) -> EvaluationResult: + pass + + def _post(self, smiles: List[str]) -> dict[str, dict[str, float]]: + header = { + "Authorization": f"Bearer {self.token}", + "Content-Type": "application/json", + } + + result = {} + + for smi in smiles: + data = { + "smiles": smi, + "sampling_alg": "exact", + "cutoff": -5, + } + + resp = requests.post(f"{self.url}/compute", headers=header, data=json.dumps(data), proxies=self.proxies) + + resp.raise_for_status() + + for substrate, predictions in resp.json().items(): + preds = {} + + for pred in predictions: + prod = pred["prediction"] + prob = math.exp(pred["log_likelihood"]) + preds[prod] = prob + + result[substrate] = preds + + return result diff --git a/templates/actions/objects/pathway.html b/templates/actions/objects/pathway.html index 7ead1c57..85e4164b 100644 --- a/templates/actions/objects/pathway.html +++ b/templates/actions/objects/pathway.html @@ -9,14 +9,6 @@ Add Compound -
  • - - Add PES -