forked from enviPath/enviPy
Merge remote-tracking branch 'origin/develop' into feature/frontend_update
This commit is contained in:
@ -135,6 +135,7 @@ USE_TZ = True
|
|||||||
|
|
||||||
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||||
|
|
||||||
|
EMAIL_SUBJECT_PREFIX = "[enviPath] "
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
||||||
else:
|
else:
|
||||||
@ -144,6 +145,8 @@ else:
|
|||||||
EMAIL_HOST_USER = os.environ["EMAIL_HOST_USER"]
|
EMAIL_HOST_USER = os.environ["EMAIL_HOST_USER"]
|
||||||
EMAIL_HOST_PASSWORD = os.environ["EMAIL_HOST_PASSWORD"]
|
EMAIL_HOST_PASSWORD = os.environ["EMAIL_HOST_PASSWORD"]
|
||||||
EMAIL_PORT = 587
|
EMAIL_PORT = 587
|
||||||
|
DEFAULT_FROM_EMAIL = os.environ["DEFAULT_FROM_EMAIL"]
|
||||||
|
SERVER_EMAIL = os.environ["SERVER_EMAIL"]
|
||||||
|
|
||||||
AUTH_USER_MODEL = "epdb.User"
|
AUTH_USER_MODEL = "epdb.User"
|
||||||
ADMIN_APPROVAL_REQUIRED = os.environ.get("ADMIN_APPROVAL_REQUIRED", "False") == "True"
|
ADMIN_APPROVAL_REQUIRED = os.environ.get("ADMIN_APPROVAL_REQUIRED", "False") == "True"
|
||||||
|
|||||||
@ -7,6 +7,7 @@ from .models import (
|
|||||||
GroupPackagePermission,
|
GroupPackagePermission,
|
||||||
Package,
|
Package,
|
||||||
MLRelativeReasoning,
|
MLRelativeReasoning,
|
||||||
|
EnviFormer,
|
||||||
Compound,
|
Compound,
|
||||||
CompoundStructure,
|
CompoundStructure,
|
||||||
SimpleAmbitRule,
|
SimpleAmbitRule,
|
||||||
@ -50,6 +51,10 @@ class MLRelativeReasoningAdmin(EPAdmin):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class EnviFormerAdmin(EPAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class CompoundAdmin(EPAdmin):
|
class CompoundAdmin(EPAdmin):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -104,6 +109,7 @@ admin.site.register(Group, GroupAdmin)
|
|||||||
admin.site.register(GroupPackagePermission, GroupPackagePermissionAdmin)
|
admin.site.register(GroupPackagePermission, GroupPackagePermissionAdmin)
|
||||||
admin.site.register(Package, PackageAdmin)
|
admin.site.register(Package, PackageAdmin)
|
||||||
admin.site.register(MLRelativeReasoning, MLRelativeReasoningAdmin)
|
admin.site.register(MLRelativeReasoning, MLRelativeReasoningAdmin)
|
||||||
|
admin.site.register(EnviFormer, EnviFormerAdmin)
|
||||||
admin.site.register(Compound, CompoundAdmin)
|
admin.site.register(Compound, CompoundAdmin)
|
||||||
admin.site.register(CompoundStructure, CompoundStructureAdmin)
|
admin.site.register(CompoundStructure, CompoundStructureAdmin)
|
||||||
admin.site.register(SimpleAmbitRule, SimpleAmbitRuleAdmin)
|
admin.site.register(SimpleAmbitRule, SimpleAmbitRuleAdmin)
|
||||||
|
|||||||
@ -26,6 +26,7 @@ from epdb.models import (
|
|||||||
Compound,
|
Compound,
|
||||||
Reaction,
|
Reaction,
|
||||||
CompoundStructure,
|
CompoundStructure,
|
||||||
|
EnzymeLink,
|
||||||
)
|
)
|
||||||
from utilities.chem import FormatConverter
|
from utilities.chem import FormatConverter
|
||||||
from utilities.misc import PackageImporter, PackageExporter
|
from utilities.misc import PackageImporter, PackageExporter
|
||||||
@ -617,6 +618,8 @@ class PackageManager(object):
|
|||||||
parent_mapping = {}
|
parent_mapping = {}
|
||||||
# Mapping old scen_id to old_obj_id
|
# Mapping old scen_id to old_obj_id
|
||||||
scen_mapping = defaultdict(list)
|
scen_mapping = defaultdict(list)
|
||||||
|
# Enzymelink Mapping rule_id to enzymelink objects
|
||||||
|
enzyme_mapping = defaultdict(list)
|
||||||
|
|
||||||
# Store Scenarios
|
# Store Scenarios
|
||||||
for scenario in data["scenarios"]:
|
for scenario in data["scenarios"]:
|
||||||
@ -648,9 +651,7 @@ class PackageManager(object):
|
|||||||
# Broken eP Data
|
# Broken eP Data
|
||||||
if name == "initialmasssediment" and addinf_data == "missing data":
|
if name == "initialmasssediment" and addinf_data == "missing data":
|
||||||
continue
|
continue
|
||||||
|
if name == "columnheight" and addinf_data == "(2)-(2.5);(6)-(8)":
|
||||||
# TODO Enzymes arent ready yet
|
|
||||||
if name == "enzyme":
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -740,6 +741,9 @@ class PackageManager(object):
|
|||||||
for scen in rule["scenarios"]:
|
for scen in rule["scenarios"]:
|
||||||
scen_mapping[scen["id"]].append(r)
|
scen_mapping[scen["id"]].append(r)
|
||||||
|
|
||||||
|
for enzyme_link in rule.get("enzymeLinks", []):
|
||||||
|
enzyme_mapping[r.uuid].append(enzyme_link)
|
||||||
|
|
||||||
print("Par: ", len(par_rules))
|
print("Par: ", len(par_rules))
|
||||||
print("Seq: ", len(seq_rules))
|
print("Seq: ", len(seq_rules))
|
||||||
|
|
||||||
@ -757,6 +761,9 @@ class PackageManager(object):
|
|||||||
for scen in par_rule["scenarios"]:
|
for scen in par_rule["scenarios"]:
|
||||||
scen_mapping[scen["id"]].append(r)
|
scen_mapping[scen["id"]].append(r)
|
||||||
|
|
||||||
|
for enzyme_link in par_rule.get("enzymeLinks", []):
|
||||||
|
enzyme_mapping[r.uuid].append(enzyme_link)
|
||||||
|
|
||||||
for simple_rule in par_rule["simpleRules"]:
|
for simple_rule in par_rule["simpleRules"]:
|
||||||
if simple_rule["id"] in mapping:
|
if simple_rule["id"] in mapping:
|
||||||
r.simple_rules.add(SimpleRule.objects.get(uuid=mapping[simple_rule["id"]]))
|
r.simple_rules.add(SimpleRule.objects.get(uuid=mapping[simple_rule["id"]]))
|
||||||
@ -777,6 +784,9 @@ class PackageManager(object):
|
|||||||
for scen in seq_rule["scenarios"]:
|
for scen in seq_rule["scenarios"]:
|
||||||
scen_mapping[scen["id"]].append(r)
|
scen_mapping[scen["id"]].append(r)
|
||||||
|
|
||||||
|
for enzyme_link in seq_rule.get("enzymeLinks", []):
|
||||||
|
enzyme_mapping[r.uuid].append(enzyme_link)
|
||||||
|
|
||||||
for i, simple_rule in enumerate(seq_rule["simpleRules"]):
|
for i, simple_rule in enumerate(seq_rule["simpleRules"]):
|
||||||
sro = SequentialRuleOrdering()
|
sro = SequentialRuleOrdering()
|
||||||
sro.simple_rule = simple_rule
|
sro.simple_rule = simple_rule
|
||||||
@ -910,6 +920,39 @@ class PackageManager(object):
|
|||||||
|
|
||||||
print("Scenarios linked...")
|
print("Scenarios linked...")
|
||||||
|
|
||||||
|
# Import Enzyme Links
|
||||||
|
for rule_uuid, enzyme_links in enzyme_mapping.items():
|
||||||
|
r = Rule.objects.get(uuid=rule_uuid)
|
||||||
|
for enzyme in enzyme_links:
|
||||||
|
e = EnzymeLink()
|
||||||
|
e.uuid = UUID(enzyme["id"].split("/")[-1]) if keep_ids else uuid4()
|
||||||
|
e.rule = r
|
||||||
|
e.name = enzyme["name"]
|
||||||
|
e.ec_number = enzyme["ecNumber"]
|
||||||
|
e.classification_level = enzyme["classificationLevel"]
|
||||||
|
e.linking_method = enzyme["linkingMethod"]
|
||||||
|
e.save()
|
||||||
|
|
||||||
|
for reaction in enzyme["reactionLinkEvidence"]:
|
||||||
|
reaction = Reaction.objects.get(uuid=mapping[reaction["id"]])
|
||||||
|
e.reaction_evidence.add(reaction)
|
||||||
|
|
||||||
|
for edge in enzyme["edgeLinkEvidence"]:
|
||||||
|
edge = Edge.objects.get(uuid=mapping[edge["id"]])
|
||||||
|
e.reaction_evidence.add(edge)
|
||||||
|
|
||||||
|
for evidence in enzyme["linkEvidence"]:
|
||||||
|
matches = re.findall(r">(R[0-9]+)<", evidence["evidence"])
|
||||||
|
if not matches or len(matches) != 1:
|
||||||
|
logger.warning(f"Could not find reaction id in {evidence['evidence']}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
e.add_kegg_reaction_id(matches[0])
|
||||||
|
|
||||||
|
e.save()
|
||||||
|
|
||||||
|
print("Enzyme links imported...")
|
||||||
|
|
||||||
print("Import statistics:")
|
print("Import statistics:")
|
||||||
print("Package {} stored".format(pack.url))
|
print("Package {} stored".format(pack.url))
|
||||||
print("Imported {} compounds".format(Compound.objects.filter(package=pack).count()))
|
print("Imported {} compounds".format(Compound.objects.filter(package=pack).count()))
|
||||||
|
|||||||
@ -7,10 +7,11 @@ from epdb.models import MLRelativeReasoning, EnviFormer, Package
|
|||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
"""This command can be run with
|
"""This command can be run with
|
||||||
`python manage.py create_ml_models [model_names] -d [data_packages] OPTIONAL: -e [eval_packages]`
|
`python manage.py create_ml_models [model_names] -d [data_packages] FOR MLRR ONLY: -r [rule_packages]
|
||||||
For example, to train both EnviFormer and MLRelativeReasoning on BBD and SOIL and evaluate them on SLUDGE
|
OPTIONAL: -e [eval_packages] -t threshold`
|
||||||
the below command would be used:
|
For example, to train both EnviFormer and MLRelativeReasoning on BBD and SOIL and evaluate them on SLUDGE with a
|
||||||
`python manage.py create_ml_models enviformer mlrr -d bbd soil -e sludge
|
threshold of 0.6, the below command would be used:
|
||||||
|
`python manage.py create_ml_models enviformer mlrr -d bbd soil -e sludge -t 0.6
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
def add_arguments(self, parser):
|
||||||
@ -34,6 +35,13 @@ class Command(BaseCommand):
|
|||||||
help="Rule Packages mandatory for MLRR",
|
help="Rule Packages mandatory for MLRR",
|
||||||
default=[],
|
default=[],
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-t",
|
||||||
|
"--threshold",
|
||||||
|
type=float,
|
||||||
|
help="Model prediction threshold",
|
||||||
|
default=0.5,
|
||||||
|
)
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
@ -67,7 +75,11 @@ class Command(BaseCommand):
|
|||||||
return packages
|
return packages
|
||||||
|
|
||||||
# Iteratively create models in options["model_names"]
|
# Iteratively create models in options["model_names"]
|
||||||
print(f"Creating models: {options['model_names']}")
|
print(f"Creating models: {options['model_names']}\n"
|
||||||
|
f"Data packages: {options['data_packages']}\n"
|
||||||
|
f"Rule Packages (only for MLRR): {options['rule_packages']}\n"
|
||||||
|
f"Eval Packages: {options['eval_packages']}\n"
|
||||||
|
f"Threshold: {options['threshold']:.2f}")
|
||||||
data_packages = decode_packages(options["data_packages"])
|
data_packages = decode_packages(options["data_packages"])
|
||||||
eval_packages = decode_packages(options["eval_packages"])
|
eval_packages = decode_packages(options["eval_packages"])
|
||||||
rule_packages = decode_packages(options["rule_packages"])
|
rule_packages = decode_packages(options["rule_packages"])
|
||||||
@ -78,9 +90,10 @@ class Command(BaseCommand):
|
|||||||
pack,
|
pack,
|
||||||
data_packages=data_packages,
|
data_packages=data_packages,
|
||||||
eval_packages=eval_packages,
|
eval_packages=eval_packages,
|
||||||
threshold=0.5,
|
threshold=options['threshold'],
|
||||||
name="EnviFormer - T0.5",
|
name=f"EnviFormer - {', '.join(options['data_packages'])} - T{options['threshold']:.2f}",
|
||||||
description="EnviFormer transformer",
|
description=f"EnviFormer transformer trained on {options['data_packages']} "
|
||||||
|
f"evaluated on {options['eval_packages']}.",
|
||||||
)
|
)
|
||||||
elif model_name == "mlrr":
|
elif model_name == "mlrr":
|
||||||
model = MLRelativeReasoning.create(
|
model = MLRelativeReasoning.create(
|
||||||
@ -88,9 +101,10 @@ class Command(BaseCommand):
|
|||||||
rule_packages=rule_packages,
|
rule_packages=rule_packages,
|
||||||
data_packages=data_packages,
|
data_packages=data_packages,
|
||||||
eval_packages=eval_packages,
|
eval_packages=eval_packages,
|
||||||
threshold=0.5,
|
threshold=options['threshold'],
|
||||||
name="ECC - BBD - T0.5",
|
name=f"ECC - {', '.join(options['data_packages'])} - T{options['threshold']:.2f}",
|
||||||
description="ML Relative Reasoning",
|
description=f"ML Relative Reasoning trained on {options['data_packages']} with rules from "
|
||||||
|
f"{options['rule_packages']} and evaluated on {options['eval_packages']}.",
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Cannot create model of type {model_name}, unknown model type")
|
raise ValueError(f"Cannot create model of type {model_name}, unknown model type")
|
||||||
@ -100,6 +114,6 @@ class Command(BaseCommand):
|
|||||||
print(f"Training {model_name}")
|
print(f"Training {model_name}")
|
||||||
model.build_model()
|
model.build_model()
|
||||||
print(f"Evaluating {model_name}")
|
print(f"Evaluating {model_name}")
|
||||||
model.evaluate_model()
|
model.evaluate_model(False, eval_packages=eval_packages)
|
||||||
print(f"Saving {model_name}")
|
print(f"Saving {model_name}")
|
||||||
model.save()
|
model.save()
|
||||||
|
|||||||
59
epdb/management/commands/dump_enviformer.py
Normal file
59
epdb/management/commands/dump_enviformer.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import json
|
||||||
|
import os
|
||||||
|
import tarfile
|
||||||
|
from tempfile import TemporaryDirectory
|
||||||
|
|
||||||
|
from django.conf import settings as s
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
|
from epdb.models import EnviFormer
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument(
|
||||||
|
"model",
|
||||||
|
type=str,
|
||||||
|
help="Model UUID of the Model to Dump",
|
||||||
|
)
|
||||||
|
parser.add_argument("--output", type=str)
|
||||||
|
|
||||||
|
def package_dict_and_folder(self, dict_data, folder_path, output_path):
|
||||||
|
with TemporaryDirectory() as tmpdir:
|
||||||
|
dict_filename = os.path.join(tmpdir, "data.json")
|
||||||
|
|
||||||
|
with open(dict_filename, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(dict_data, f, indent=2)
|
||||||
|
|
||||||
|
with tarfile.open(output_path, "w:gz") as tar:
|
||||||
|
tar.add(dict_filename, arcname="data.json")
|
||||||
|
tar.add(folder_path, arcname=os.path.basename(folder_path))
|
||||||
|
|
||||||
|
os.remove(dict_filename)
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
output = options["output"]
|
||||||
|
|
||||||
|
if os.path.exists(output):
|
||||||
|
raise ValueError(f"Output file {output} already exists")
|
||||||
|
|
||||||
|
model = EnviFormer.objects.get(uuid=options["model"])
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"uuid": str(model.uuid),
|
||||||
|
"name": model.name,
|
||||||
|
"description": model.description,
|
||||||
|
"kv": model.kv,
|
||||||
|
"data_packages_uuids": [str(p.uuid) for p in model.data_packages.all()],
|
||||||
|
"eval_packages_uuids": [str(p.uuid) for p in model.data_packages.all()],
|
||||||
|
"threshold": model.threshold,
|
||||||
|
"eval_results": model.eval_results,
|
||||||
|
"multigen_eval": model.multigen_eval,
|
||||||
|
"model_status": model.model_status,
|
||||||
|
}
|
||||||
|
|
||||||
|
model_folder = os.path.join(s.MODEL_DIR, "enviformer", str(model.uuid))
|
||||||
|
|
||||||
|
self.package_dict_and_folder(data, model_folder, output)
|
||||||
81
epdb/management/commands/load_enviformer.py
Normal file
81
epdb/management/commands/load_enviformer.py
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import json
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import tarfile
|
||||||
|
from tempfile import TemporaryDirectory
|
||||||
|
|
||||||
|
from django.conf import settings as s
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
|
from epdb.models import EnviFormer, Package
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument(
|
||||||
|
"input",
|
||||||
|
type=str,
|
||||||
|
help=".tar.gz file containing the Model dump.",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"package",
|
||||||
|
type=str,
|
||||||
|
help="Package UUID where the Model should be loaded to.",
|
||||||
|
)
|
||||||
|
|
||||||
|
def read_dict_and_folder_from_archive(self, archive_path, extract_to="extracted_folder"):
|
||||||
|
with tarfile.open(archive_path, "r:gz") as tar:
|
||||||
|
tar.extractall(extract_to)
|
||||||
|
|
||||||
|
dict_path = os.path.join(extract_to, "data.json")
|
||||||
|
|
||||||
|
if not os.path.exists(dict_path):
|
||||||
|
raise FileNotFoundError("data.json not found in the archive.")
|
||||||
|
|
||||||
|
with open(dict_path, "r", encoding="utf-8") as f:
|
||||||
|
data_dict = json.load(f)
|
||||||
|
|
||||||
|
extracted_items = os.listdir(extract_to)
|
||||||
|
folders = [item for item in extracted_items if item != "data.json"]
|
||||||
|
folder_path = os.path.join(extract_to, folders[0]) if folders else None
|
||||||
|
|
||||||
|
return data_dict, folder_path
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
if not os.path.exists(options["input"]):
|
||||||
|
raise ValueError(f"Input file {options['input']} does not exist.")
|
||||||
|
|
||||||
|
target_package = Package.objects.get(uuid=options["package"])
|
||||||
|
|
||||||
|
with TemporaryDirectory() as tmpdir:
|
||||||
|
data, folder = self.read_dict_and_folder_from_archive(options["input"], tmpdir)
|
||||||
|
|
||||||
|
model = EnviFormer()
|
||||||
|
model.package = target_package
|
||||||
|
# model.uuid = data["uuid"]
|
||||||
|
model.name = data["name"]
|
||||||
|
model.description = data["description"]
|
||||||
|
model.kv = data["kv"]
|
||||||
|
model.threshold = float(data["threshold"])
|
||||||
|
model.eval_results = data["eval_results"]
|
||||||
|
model.multigen_eval = data["multigen_eval"]
|
||||||
|
model.model_status = data["model_status"]
|
||||||
|
model.save()
|
||||||
|
|
||||||
|
for p_uuid in data["data_packages_uuids"]:
|
||||||
|
p = Package.objects.get(uuid=p_uuid)
|
||||||
|
model.data_packages.add(p)
|
||||||
|
|
||||||
|
for p_uuid in data["eval_packages_uuids"]:
|
||||||
|
p = Package.objects.get(uuid=p_uuid)
|
||||||
|
model.eval_packages.add(p)
|
||||||
|
|
||||||
|
target_folder = os.path.join(s.MODEL_DIR, "enviformer", str(model.uuid))
|
||||||
|
|
||||||
|
shutil.copytree(folder, target_folder)
|
||||||
|
os.rename(
|
||||||
|
os.path.join(s.MODEL_DIR, "enviformer", str(model.uuid), f"{data['uuid']}.ckpt"),
|
||||||
|
os.path.join(s.MODEL_DIR, "enviformer", str(model.uuid), f"{model.uuid}.ckpt"),
|
||||||
|
)
|
||||||
@ -1,8 +1,10 @@
|
|||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
from django.db.models import F, Value
|
from django.db.models import F, Value, TextField, JSONField
|
||||||
from django.db.models.functions import Replace
|
from django.db.models.functions import Replace, Cast
|
||||||
|
|
||||||
|
from epdb.models import EnviPathModel
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
@ -41,6 +43,7 @@ class Command(BaseCommand):
|
|||||||
"RuleBasedRelativeReasoning",
|
"RuleBasedRelativeReasoning",
|
||||||
"EnviFormer",
|
"EnviFormer",
|
||||||
"ApplicabilityDomain",
|
"ApplicabilityDomain",
|
||||||
|
"EnzymeLink",
|
||||||
]
|
]
|
||||||
for model in MODELS:
|
for model in MODELS:
|
||||||
obj_cls = apps.get_model("epdb", model)
|
obj_cls = apps.get_model("epdb", model)
|
||||||
@ -48,3 +51,14 @@ class Command(BaseCommand):
|
|||||||
obj_cls.objects.update(
|
obj_cls.objects.update(
|
||||||
url=Replace(F("url"), Value(options["old"]), Value(options["new"]))
|
url=Replace(F("url"), Value(options["old"]), Value(options["new"]))
|
||||||
)
|
)
|
||||||
|
if issubclass(obj_cls, EnviPathModel):
|
||||||
|
obj_cls.objects.update(
|
||||||
|
kv=Cast(
|
||||||
|
Replace(
|
||||||
|
Cast(F("kv"), output_field=TextField()),
|
||||||
|
Value(options["old"]),
|
||||||
|
Value(options["new"]),
|
||||||
|
),
|
||||||
|
output_field=JSONField(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|||||||
38
epdb/management/commands/update_job_logs.py
Normal file
38
epdb/management/commands/update_job_logs.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
from datetime import date, timedelta
|
||||||
|
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
|
from epdb.models import JobLog
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument(
|
||||||
|
"--cleanup",
|
||||||
|
type=int,
|
||||||
|
default=None,
|
||||||
|
help="Remove all logs older than this number of days. Default is None, which does not remove any logs.",
|
||||||
|
)
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
if options["cleanup"] is not None:
|
||||||
|
cleanup_dt = date.today() - timedelta(days=options["cleanup"])
|
||||||
|
print(JobLog.objects.filter(created__lt=cleanup_dt).delete())
|
||||||
|
|
||||||
|
logs = JobLog.objects.filter(status="INITIAL")
|
||||||
|
print(f"Found {logs.count()} logs to update")
|
||||||
|
updated = 0
|
||||||
|
for log in logs:
|
||||||
|
res = log.check_for_update()
|
||||||
|
if res:
|
||||||
|
updated += 1
|
||||||
|
|
||||||
|
print(f"Updated {updated} logs")
|
||||||
|
|
||||||
|
from django.db.models import Count
|
||||||
|
|
||||||
|
qs = JobLog.objects.values("status").annotate(total=Count("status"))
|
||||||
|
for r in qs:
|
||||||
|
print(r["status"], r["total"])
|
||||||
64
epdb/migrations/0008_enzymelink.py
Normal file
64
epdb/migrations/0008_enzymelink.py
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
# Generated by Django 5.2.7 on 2025-10-10 06:58
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
import model_utils.fields
|
||||||
|
import uuid
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("epdb", "0007_alter_enviformer_options_enviformer_app_domain_and_more"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="EnzymeLink",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"created",
|
||||||
|
model_utils.fields.AutoCreatedField(
|
||||||
|
default=django.utils.timezone.now, editable=False, verbose_name="created"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"modified",
|
||||||
|
model_utils.fields.AutoLastModifiedField(
|
||||||
|
default=django.utils.timezone.now, editable=False, verbose_name="modified"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"uuid",
|
||||||
|
models.UUIDField(
|
||||||
|
default=uuid.uuid4, unique=True, verbose_name="UUID of this object"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("name", models.TextField(default="no name", verbose_name="Name")),
|
||||||
|
(
|
||||||
|
"description",
|
||||||
|
models.TextField(default="no description", verbose_name="Descriptions"),
|
||||||
|
),
|
||||||
|
("url", models.TextField(null=True, unique=True, verbose_name="URL")),
|
||||||
|
("kv", models.JSONField(blank=True, default=dict, null=True)),
|
||||||
|
("ec_number", models.TextField(verbose_name="EC Number")),
|
||||||
|
("classification_level", models.IntegerField(verbose_name="Classification Level")),
|
||||||
|
("linking_method", models.TextField(verbose_name="Linking Method")),
|
||||||
|
("edge_evidence", models.ManyToManyField(to="epdb.edge")),
|
||||||
|
("reaction_evidence", models.ManyToManyField(to="epdb.reaction")),
|
||||||
|
(
|
||||||
|
"rule",
|
||||||
|
models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="epdb.rule"),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"abstract": False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
66
epdb/migrations/0009_joblog.py
Normal file
66
epdb/migrations/0009_joblog.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
# Generated by Django 5.2.7 on 2025-10-27 09:39
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
import model_utils.fields
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("epdb", "0008_enzymelink"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="JobLog",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"created",
|
||||||
|
model_utils.fields.AutoCreatedField(
|
||||||
|
default=django.utils.timezone.now, editable=False, verbose_name="created"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"modified",
|
||||||
|
model_utils.fields.AutoLastModifiedField(
|
||||||
|
default=django.utils.timezone.now, editable=False, verbose_name="modified"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("task_id", models.UUIDField(unique=True)),
|
||||||
|
("job_name", models.TextField()),
|
||||||
|
(
|
||||||
|
"status",
|
||||||
|
models.CharField(
|
||||||
|
choices=[
|
||||||
|
("INITIAL", "Initial"),
|
||||||
|
("SUCCESS", "Success"),
|
||||||
|
("FAILURE", "Failure"),
|
||||||
|
("REVOKED", "Revoked"),
|
||||||
|
("IGNORED", "Ignored"),
|
||||||
|
],
|
||||||
|
default="INITIAL",
|
||||||
|
max_length=20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("done_at", models.DateTimeField(blank=True, default=None, null=True)),
|
||||||
|
("task_result", models.TextField(blank=True, default=None, null=True)),
|
||||||
|
(
|
||||||
|
"user",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"abstract": False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
166
epdb/models.py
166
epdb/models.py
@ -310,7 +310,7 @@ class ExternalDatabase(TimeStampedModel):
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"database": ExternalDatabase.objects.get(name="ChEBI"),
|
"database": ExternalDatabase.objects.get(name="ChEBI"),
|
||||||
"placeholder": "ChEBI ID without prefix e.g. 12345",
|
"placeholder": "ChEBI ID without prefix e.g. 10576",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"structure": [
|
"structure": [
|
||||||
@ -328,7 +328,7 @@ class ExternalDatabase(TimeStampedModel):
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"database": ExternalDatabase.objects.get(name="ChEBI"),
|
"database": ExternalDatabase.objects.get(name="ChEBI"),
|
||||||
"placeholder": "ChEBI ID without prefix e.g. 12345",
|
"placeholder": "ChEBI ID without prefix e.g. 10576",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"reaction": [
|
"reaction": [
|
||||||
@ -342,7 +342,7 @@ class ExternalDatabase(TimeStampedModel):
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"database": ExternalDatabase.objects.get(name="UniProt"),
|
"database": ExternalDatabase.objects.get(name="UniProt"),
|
||||||
"placeholder": "Query ID for UniPro e.g. rhea:12345",
|
"placeholder": "Query ID for UniProt e.g. rhea:12345",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
@ -477,7 +477,7 @@ class ChemicalIdentifierMixin(ExternalIdentifierMixin):
|
|||||||
return self.add_external_identifier("CAS", cas_number)
|
return self.add_external_identifier("CAS", cas_number)
|
||||||
|
|
||||||
def get_pubchem_identifiers(self):
|
def get_pubchem_identifiers(self):
|
||||||
return self.get_external_identifier("PubChem Compound") or self.get_external_identifier(
|
return self.get_external_identifier("PubChem Compound") | self.get_external_identifier(
|
||||||
"PubChem Substance"
|
"PubChem Substance"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -494,6 +494,20 @@ class ChemicalIdentifierMixin(ExternalIdentifierMixin):
|
|||||||
return self.get_external_identifier("CAS")
|
return self.get_external_identifier("CAS")
|
||||||
|
|
||||||
|
|
||||||
|
class KEGGIdentifierMixin(ExternalIdentifierMixin):
|
||||||
|
@property
|
||||||
|
def kegg_reaction_links(self):
|
||||||
|
return self.get_external_identifier("KEGG Reaction")
|
||||||
|
|
||||||
|
def add_kegg_reaction_id(self, kegg_id):
|
||||||
|
return self.add_external_identifier(
|
||||||
|
"KEGG Reaction", kegg_id, f"https://www.genome.jp/entry/{kegg_id}"
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
|
||||||
class ReactionIdentifierMixin(ExternalIdentifierMixin):
|
class ReactionIdentifierMixin(ExternalIdentifierMixin):
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
@ -1014,6 +1028,26 @@ class CompoundStructure(EnviPathModel, AliasMixin, ScenarioMixin, ChemicalIdenti
|
|||||||
return self.compound.default_structure == self
|
return self.compound.default_structure == self
|
||||||
|
|
||||||
|
|
||||||
|
class EnzymeLink(EnviPathModel, KEGGIdentifierMixin):
|
||||||
|
rule = models.ForeignKey("Rule", on_delete=models.CASCADE, db_index=True)
|
||||||
|
ec_number = models.TextField(blank=False, null=False, verbose_name="EC Number")
|
||||||
|
classification_level = models.IntegerField(
|
||||||
|
blank=False, null=False, verbose_name="Classification Level"
|
||||||
|
)
|
||||||
|
linking_method = models.TextField(blank=False, null=False, verbose_name="Linking Method")
|
||||||
|
|
||||||
|
reaction_evidence = models.ManyToManyField("epdb.Reaction")
|
||||||
|
edge_evidence = models.ManyToManyField("epdb.Edge")
|
||||||
|
|
||||||
|
external_identifiers = GenericRelation("ExternalIdentifier")
|
||||||
|
|
||||||
|
def _url(self):
|
||||||
|
return "{}/enzymelink/{}".format(self.rule.url, self.uuid)
|
||||||
|
|
||||||
|
def get_group(self) -> str:
|
||||||
|
return ".".join(self.ec_number.split(".")[:3]) + ".-"
|
||||||
|
|
||||||
|
|
||||||
class Rule(PolymorphicModel, EnviPathModel, AliasMixin, ScenarioMixin):
|
class Rule(PolymorphicModel, EnviPathModel, AliasMixin, ScenarioMixin):
|
||||||
package = models.ForeignKey(
|
package = models.ForeignKey(
|
||||||
"epdb.Package", verbose_name="Package", on_delete=models.CASCADE, db_index=True
|
"epdb.Package", verbose_name="Package", on_delete=models.CASCADE, db_index=True
|
||||||
@ -1095,6 +1129,18 @@ class Rule(PolymorphicModel, EnviPathModel, AliasMixin, ScenarioMixin):
|
|||||||
|
|
||||||
return new_rule
|
return new_rule
|
||||||
|
|
||||||
|
def enzymelinks(self):
|
||||||
|
return self.enzymelink_set.all()
|
||||||
|
|
||||||
|
def get_grouped_enzymelinks(self):
|
||||||
|
res = defaultdict(list)
|
||||||
|
|
||||||
|
for el in self.enzymelinks():
|
||||||
|
key = ".".join(el.ec_number.split(".")[:3]) + ".-"
|
||||||
|
res[key].append(el)
|
||||||
|
|
||||||
|
return dict(res)
|
||||||
|
|
||||||
|
|
||||||
class SimpleRule(Rule):
|
class SimpleRule(Rule):
|
||||||
pass
|
pass
|
||||||
@ -1437,6 +1483,16 @@ class Reaction(EnviPathModel, AliasMixin, ScenarioMixin, ReactionIdentifierMixin
|
|||||||
id__in=Edge.objects.filter(edge_label=self).values("pathway_id")
|
id__in=Edge.objects.filter(edge_label=self).values("pathway_id")
|
||||||
).order_by("name")
|
).order_by("name")
|
||||||
|
|
||||||
|
def get_related_enzymes(self):
|
||||||
|
res = []
|
||||||
|
edges = Edge.objects.filter(edge_label=self)
|
||||||
|
for e in edges:
|
||||||
|
for scen in e.scenarios.all():
|
||||||
|
for ai in scen.additional_information.keys():
|
||||||
|
if ai == "Enzyme":
|
||||||
|
res.extend(scen.additional_information[ai])
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
class Pathway(EnviPathModel, AliasMixin, ScenarioMixin):
|
class Pathway(EnviPathModel, AliasMixin, ScenarioMixin):
|
||||||
package = models.ForeignKey(
|
package = models.ForeignKey(
|
||||||
@ -2169,10 +2225,18 @@ class PackageBasedModel(EPModel):
|
|||||||
self.model_status = self.BUILT_NOT_EVALUATED
|
self.model_status = self.BUILT_NOT_EVALUATED
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def evaluate_model(self):
|
def evaluate_model(self, multigen: bool, eval_packages: List["Package"] = None):
|
||||||
if self.model_status != self.BUILT_NOT_EVALUATED:
|
if self.model_status != self.BUILT_NOT_EVALUATED:
|
||||||
raise ValueError(f"Can't evaluate a model in state {self.model_status}!")
|
raise ValueError(f"Can't evaluate a model in state {self.model_status}!")
|
||||||
|
|
||||||
|
if multigen:
|
||||||
|
self.multigen_eval = multigen
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
if eval_packages is not None:
|
||||||
|
for p in eval_packages:
|
||||||
|
self.eval_packages.add(p)
|
||||||
|
|
||||||
self.model_status = self.EVALUATING
|
self.model_status = self.EVALUATING
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
@ -2469,7 +2533,6 @@ class RuleBasedRelativeReasoning(PackageBasedModel):
|
|||||||
package: "Package",
|
package: "Package",
|
||||||
rule_packages: List["Package"],
|
rule_packages: List["Package"],
|
||||||
data_packages: List["Package"],
|
data_packages: List["Package"],
|
||||||
eval_packages: List["Package"],
|
|
||||||
threshold: float = 0.5,
|
threshold: float = 0.5,
|
||||||
min_count: int = 10,
|
min_count: int = 10,
|
||||||
max_count: int = 0,
|
max_count: int = 0,
|
||||||
@ -2518,10 +2581,6 @@ class RuleBasedRelativeReasoning(PackageBasedModel):
|
|||||||
for p in rule_packages:
|
for p in rule_packages:
|
||||||
rbrr.data_packages.add(p)
|
rbrr.data_packages.add(p)
|
||||||
|
|
||||||
if eval_packages:
|
|
||||||
for p in eval_packages:
|
|
||||||
rbrr.eval_packages.add(p)
|
|
||||||
|
|
||||||
rbrr.save()
|
rbrr.save()
|
||||||
|
|
||||||
return rbrr
|
return rbrr
|
||||||
@ -2576,7 +2635,6 @@ class MLRelativeReasoning(PackageBasedModel):
|
|||||||
package: "Package",
|
package: "Package",
|
||||||
rule_packages: List["Package"],
|
rule_packages: List["Package"],
|
||||||
data_packages: List["Package"],
|
data_packages: List["Package"],
|
||||||
eval_packages: List["Package"],
|
|
||||||
threshold: float = 0.5,
|
threshold: float = 0.5,
|
||||||
name: "str" = None,
|
name: "str" = None,
|
||||||
description: str = None,
|
description: str = None,
|
||||||
@ -2616,10 +2674,6 @@ class MLRelativeReasoning(PackageBasedModel):
|
|||||||
for p in rule_packages:
|
for p in rule_packages:
|
||||||
mlrr.data_packages.add(p)
|
mlrr.data_packages.add(p)
|
||||||
|
|
||||||
if eval_packages:
|
|
||||||
for p in eval_packages:
|
|
||||||
mlrr.eval_packages.add(p)
|
|
||||||
|
|
||||||
if build_app_domain:
|
if build_app_domain:
|
||||||
ad = ApplicabilityDomain.create(
|
ad = ApplicabilityDomain.create(
|
||||||
mlrr,
|
mlrr,
|
||||||
@ -2939,7 +2993,6 @@ class EnviFormer(PackageBasedModel):
|
|||||||
def create(
|
def create(
|
||||||
package: "Package",
|
package: "Package",
|
||||||
data_packages: List["Package"],
|
data_packages: List["Package"],
|
||||||
eval_packages: List["Package"],
|
|
||||||
threshold: float = 0.5,
|
threshold: float = 0.5,
|
||||||
name: "str" = None,
|
name: "str" = None,
|
||||||
description: str = None,
|
description: str = None,
|
||||||
@ -2972,10 +3025,6 @@ class EnviFormer(PackageBasedModel):
|
|||||||
for p in data_packages:
|
for p in data_packages:
|
||||||
mod.data_packages.add(p)
|
mod.data_packages.add(p)
|
||||||
|
|
||||||
if eval_packages:
|
|
||||||
for p in eval_packages:
|
|
||||||
mod.eval_packages.add(p)
|
|
||||||
|
|
||||||
# if build_app_domain:
|
# if build_app_domain:
|
||||||
# ad = ApplicabilityDomain.create(mod, app_domain_num_neighbours, app_domain_reliability_threshold,
|
# ad = ApplicabilityDomain.create(mod, app_domain_num_neighbours, app_domain_reliability_threshold,
|
||||||
# app_domain_local_compatibility_threshold)
|
# app_domain_local_compatibility_threshold)
|
||||||
@ -2989,7 +3038,8 @@ class EnviFormer(PackageBasedModel):
|
|||||||
from enviformer import load
|
from enviformer import load
|
||||||
|
|
||||||
ckpt = os.path.join(s.MODEL_DIR, "enviformer", str(self.uuid), f"{self.uuid}.ckpt")
|
ckpt = os.path.join(s.MODEL_DIR, "enviformer", str(self.uuid), f"{self.uuid}.ckpt")
|
||||||
return load(device=s.ENVIFORMER_DEVICE, ckpt_path=ckpt)
|
mod = load(device=s.ENVIFORMER_DEVICE, ckpt_path=ckpt)
|
||||||
|
return mod
|
||||||
|
|
||||||
def predict(self, smiles) -> List["PredictionResult"]:
|
def predict(self, smiles) -> List["PredictionResult"]:
|
||||||
return self.predict_batch([smiles])[0]
|
return self.predict_batch([smiles])[0]
|
||||||
@ -3003,8 +3053,12 @@ class EnviFormer(PackageBasedModel):
|
|||||||
for smiles in smiles_list
|
for smiles in smiles_list
|
||||||
]
|
]
|
||||||
logger.info(f"Submitting {canon_smiles} to {self.name}")
|
logger.info(f"Submitting {canon_smiles} to {self.name}")
|
||||||
|
start = datetime.now()
|
||||||
products_list = self.model.predict_batch(canon_smiles)
|
products_list = self.model.predict_batch(canon_smiles)
|
||||||
logger.info(f"Got results {products_list}")
|
end = datetime.now()
|
||||||
|
logger.info(
|
||||||
|
f"Prediction took {(end - start).total_seconds():.2f} seconds. Got results {products_list}"
|
||||||
|
)
|
||||||
|
|
||||||
results = []
|
results = []
|
||||||
for products in products_list:
|
for products in products_list:
|
||||||
@ -3031,6 +3085,7 @@ class EnviFormer(PackageBasedModel):
|
|||||||
|
|
||||||
start = datetime.now()
|
start = datetime.now()
|
||||||
# Standardise reactions for the training data, EnviFormer ignores stereochemistry currently
|
# Standardise reactions for the training data, EnviFormer ignores stereochemistry currently
|
||||||
|
co2 = {"C(=O)=O", "O=C=O"}
|
||||||
ds = []
|
ds = []
|
||||||
for reaction in self._get_reactions():
|
for reaction in self._get_reactions():
|
||||||
educts = ".".join(
|
educts = ".".join(
|
||||||
@ -3045,7 +3100,8 @@ class EnviFormer(PackageBasedModel):
|
|||||||
for smile in reaction.products.all()
|
for smile in reaction.products.all()
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
ds.append(f"{educts}>>{products}")
|
if products not in co2:
|
||||||
|
ds.append(f"{educts}>>{products}")
|
||||||
|
|
||||||
end = datetime.now()
|
end = datetime.now()
|
||||||
logger.debug(f"build_dataset took {(end - start).total_seconds()} seconds")
|
logger.debug(f"build_dataset took {(end - start).total_seconds()} seconds")
|
||||||
@ -3081,10 +3137,18 @@ class EnviFormer(PackageBasedModel):
|
|||||||
args = {"clz": "EnviFormer"}
|
args = {"clz": "EnviFormer"}
|
||||||
return args
|
return args
|
||||||
|
|
||||||
def evaluate_model(self):
|
def evaluate_model(self, multigen: bool, eval_packages: List["Package"] = None):
|
||||||
if self.model_status != self.BUILT_NOT_EVALUATED:
|
if self.model_status != self.BUILT_NOT_EVALUATED:
|
||||||
raise ValueError(f"Can't evaluate a model in state {self.model_status}!")
|
raise ValueError(f"Can't evaluate a model in state {self.model_status}!")
|
||||||
|
|
||||||
|
if multigen:
|
||||||
|
self.multigen_eval = multigen
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
if eval_packages is not None:
|
||||||
|
for p in eval_packages:
|
||||||
|
self.eval_packages.add(p)
|
||||||
|
|
||||||
self.model_status = self.EVALUATING
|
self.model_status = self.EVALUATING
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
@ -3241,7 +3305,7 @@ class EnviFormer(PackageBasedModel):
|
|||||||
|
|
||||||
ds = self.load_dataset()
|
ds = self.load_dataset()
|
||||||
n_splits = 20
|
n_splits = 20
|
||||||
shuff = ShuffleSplit(n_splits=n_splits, test_size=0.25, random_state=42)
|
shuff = ShuffleSplit(n_splits=n_splits, test_size=0.1, random_state=42)
|
||||||
|
|
||||||
# Single gen eval is done in one loop of train then evaluate rather than storing all n_splits trained models
|
# Single gen eval is done in one loop of train then evaluate rather than storing all n_splits trained models
|
||||||
# this helps reduce the memory footprint.
|
# this helps reduce the memory footprint.
|
||||||
@ -3309,7 +3373,7 @@ class EnviFormer(PackageBasedModel):
|
|||||||
# Compute splits of the collected pathway and evaluate. Like single gen we train and evaluate in each
|
# Compute splits of the collected pathway and evaluate. Like single gen we train and evaluate in each
|
||||||
# iteration instead of storing all trained models.
|
# iteration instead of storing all trained models.
|
||||||
for split_id, (train, test) in enumerate(
|
for split_id, (train, test) in enumerate(
|
||||||
ShuffleSplit(n_splits=n_splits, test_size=0.25, random_state=42).split(pathways)
|
ShuffleSplit(n_splits=n_splits, test_size=0.1, random_state=42).split(pathways)
|
||||||
):
|
):
|
||||||
train_pathways = [pathways[i] for i in train]
|
train_pathways = [pathways[i] for i in train]
|
||||||
test_pathways = [pathways[i] for i in test]
|
test_pathways = [pathways[i] for i in test]
|
||||||
@ -3608,3 +3672,53 @@ class Setting(EnviPathModel):
|
|||||||
self.public = True
|
self.public = True
|
||||||
self.global_default = True
|
self.global_default = True
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
|
|
||||||
|
class JobLogStatus(models.TextChoices):
|
||||||
|
INITIAL = "INITIAL", "Initial"
|
||||||
|
SUCCESS = "SUCCESS", "Success"
|
||||||
|
FAILURE = "FAILURE", "Failure"
|
||||||
|
REVOKED = "REVOKED", "Revoked"
|
||||||
|
IGNORED = "IGNORED", "Ignored"
|
||||||
|
|
||||||
|
|
||||||
|
class JobLog(TimeStampedModel):
|
||||||
|
user = models.ForeignKey("epdb.User", models.CASCADE)
|
||||||
|
task_id = models.UUIDField(unique=True)
|
||||||
|
job_name = models.TextField(null=False, blank=False)
|
||||||
|
status = models.CharField(
|
||||||
|
max_length=20,
|
||||||
|
choices=JobLogStatus.choices,
|
||||||
|
default=JobLogStatus.INITIAL,
|
||||||
|
)
|
||||||
|
|
||||||
|
done_at = models.DateTimeField(null=True, blank=True, default=None)
|
||||||
|
task_result = models.TextField(null=True, blank=True, default=None)
|
||||||
|
|
||||||
|
def check_for_update(self):
|
||||||
|
async_res = self.get_result()
|
||||||
|
new_status = async_res.state
|
||||||
|
|
||||||
|
TERMINAL_STATES = [
|
||||||
|
"SUCCESS",
|
||||||
|
"FAILURE",
|
||||||
|
"REVOKED",
|
||||||
|
"IGNORED",
|
||||||
|
]
|
||||||
|
|
||||||
|
if new_status != self.status and new_status in TERMINAL_STATES:
|
||||||
|
self.status = new_status
|
||||||
|
self.done_at = async_res.date_done
|
||||||
|
|
||||||
|
if new_status == "SUCCESS":
|
||||||
|
self.task_result = async_res.result
|
||||||
|
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_result(self):
|
||||||
|
from celery.result import AsyncResult
|
||||||
|
|
||||||
|
return AsyncResult(str(self.task_id))
|
||||||
|
|||||||
129
epdb/tasks.py
129
epdb/tasks.py
@ -1,12 +1,56 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import Optional
|
from datetime import datetime
|
||||||
|
from typing import Callable, Optional
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
from celery import shared_task
|
from celery import shared_task
|
||||||
from epdb.models import Pathway, Node, EPModel, Setting
|
from celery.utils.functional import LRUCache
|
||||||
from epdb.logic import SPathway
|
|
||||||
|
|
||||||
|
from epdb.logic import SPathway
|
||||||
|
from epdb.models import EPModel, JobLog, Node, Package, Pathway, Setting, User
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
ML_CACHE = LRUCache(3) # Cache the three most recent ML models to reduce load times.
|
||||||
|
|
||||||
|
|
||||||
|
def get_ml_model(model_pk: int):
|
||||||
|
if model_pk not in ML_CACHE:
|
||||||
|
ML_CACHE[model_pk] = EPModel.objects.get(id=model_pk)
|
||||||
|
return ML_CACHE[model_pk]
|
||||||
|
|
||||||
|
|
||||||
|
def dispatch_eager(user: "User", job: Callable, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
x = job(*args, **kwargs)
|
||||||
|
log = JobLog()
|
||||||
|
log.user = user
|
||||||
|
log.task_id = uuid4()
|
||||||
|
log.job_name = job.__name__
|
||||||
|
log.status = "SUCCESS"
|
||||||
|
log.done_at = datetime.now()
|
||||||
|
log.task_result = str(x) if x else None
|
||||||
|
log.save()
|
||||||
|
|
||||||
|
return x
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(e)
|
||||||
|
raise e
|
||||||
|
|
||||||
|
|
||||||
|
def dispatch(user: "User", job: Callable, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
x = job.delay(*args, **kwargs)
|
||||||
|
log = JobLog()
|
||||||
|
log.user = user
|
||||||
|
log.task_id = x.task_id
|
||||||
|
log.job_name = job.__name__
|
||||||
|
log.status = "INITIAL"
|
||||||
|
log.save()
|
||||||
|
|
||||||
|
return x.result
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(e)
|
||||||
|
raise e
|
||||||
|
|
||||||
|
|
||||||
@shared_task(queue="background")
|
@shared_task(queue="background")
|
||||||
@ -16,7 +60,7 @@ def mul(a, b):
|
|||||||
|
|
||||||
@shared_task(queue="predict")
|
@shared_task(queue="predict")
|
||||||
def predict_simple(model_pk: int, smiles: str):
|
def predict_simple(model_pk: int, smiles: str):
|
||||||
mod = EPModel.objects.get(id=model_pk)
|
mod = get_ml_model(model_pk)
|
||||||
res = mod.predict(smiles)
|
res = mod.predict(smiles)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@ -26,17 +70,55 @@ def send_registration_mail(user_pk: int):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@shared_task(queue="model")
|
@shared_task(bind=True, queue="model")
|
||||||
def build_model(model_pk: int):
|
def build_model(self, model_pk: int):
|
||||||
mod = EPModel.objects.get(id=model_pk)
|
mod = EPModel.objects.get(id=model_pk)
|
||||||
mod.build_dataset()
|
|
||||||
mod.build_model()
|
if JobLog.objects.filter(task_id=self.request.id).exists():
|
||||||
|
JobLog.objects.filter(task_id=self.request.id).update(status="RUNNING", task_result=mod.url)
|
||||||
|
|
||||||
|
try:
|
||||||
|
mod.build_dataset()
|
||||||
|
mod.build_model()
|
||||||
|
except Exception as e:
|
||||||
|
if JobLog.objects.filter(task_id=self.request.id).exists():
|
||||||
|
JobLog.objects.filter(task_id=self.request.id).update(
|
||||||
|
status="FAILED", task_result=mod.url
|
||||||
|
)
|
||||||
|
|
||||||
|
raise e
|
||||||
|
|
||||||
|
if JobLog.objects.filter(task_id=self.request.id).exists():
|
||||||
|
JobLog.objects.filter(task_id=self.request.id).update(status="SUCCESS", task_result=mod.url)
|
||||||
|
|
||||||
|
return mod.url
|
||||||
|
|
||||||
|
|
||||||
@shared_task(queue="model")
|
@shared_task(bind=True, queue="model")
|
||||||
def evaluate_model(model_pk: int):
|
def evaluate_model(self, model_pk: int, multigen: bool, package_pks: Optional[list] = None):
|
||||||
|
packages = None
|
||||||
|
|
||||||
|
if package_pks:
|
||||||
|
packages = Package.objects.filter(pk__in=package_pks)
|
||||||
|
|
||||||
mod = EPModel.objects.get(id=model_pk)
|
mod = EPModel.objects.get(id=model_pk)
|
||||||
mod.evaluate_model()
|
if JobLog.objects.filter(task_id=self.request.id).exists():
|
||||||
|
JobLog.objects.filter(task_id=self.request.id).update(status="RUNNING", task_result=mod.url)
|
||||||
|
|
||||||
|
try:
|
||||||
|
mod.evaluate_model(multigen, eval_packages=packages)
|
||||||
|
except Exception as e:
|
||||||
|
if JobLog.objects.filter(task_id=self.request.id).exists():
|
||||||
|
JobLog.objects.filter(task_id=self.request.id).update(
|
||||||
|
status="FAILED", task_result=mod.url
|
||||||
|
)
|
||||||
|
|
||||||
|
raise e
|
||||||
|
|
||||||
|
if JobLog.objects.filter(task_id=self.request.id).exists():
|
||||||
|
JobLog.objects.filter(task_id=self.request.id).update(status="SUCCESS", task_result=mod.url)
|
||||||
|
|
||||||
|
return mod.url
|
||||||
|
|
||||||
|
|
||||||
@shared_task(queue="model")
|
@shared_task(queue="model")
|
||||||
@ -45,16 +127,26 @@ def retrain(model_pk: int):
|
|||||||
mod.retrain()
|
mod.retrain()
|
||||||
|
|
||||||
|
|
||||||
@shared_task(queue="predict")
|
@shared_task(bind=True, queue="predict")
|
||||||
def predict(
|
def predict(
|
||||||
pw_pk: int, pred_setting_pk: int, limit: Optional[int] = None, node_pk: Optional[int] = None
|
self,
|
||||||
|
pw_pk: int,
|
||||||
|
pred_setting_pk: int,
|
||||||
|
limit: Optional[int] = None,
|
||||||
|
node_pk: Optional[int] = None,
|
||||||
) -> Pathway:
|
) -> Pathway:
|
||||||
pw = Pathway.objects.get(id=pw_pk)
|
pw = Pathway.objects.get(id=pw_pk)
|
||||||
setting = Setting.objects.get(id=pred_setting_pk)
|
setting = Setting.objects.get(id=pred_setting_pk)
|
||||||
|
# If the setting has a model add/restore it from the cache
|
||||||
|
if setting.model is not None:
|
||||||
|
setting.model = get_ml_model(setting.model.pk)
|
||||||
|
|
||||||
pw.kv.update(**{"status": "running"})
|
pw.kv.update(**{"status": "running"})
|
||||||
pw.save()
|
pw.save()
|
||||||
|
|
||||||
|
if JobLog.objects.filter(task_id=self.request.id).exists():
|
||||||
|
JobLog.objects.filter(task_id=self.request.id).update(status="RUNNING", task_result=pw.url)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# regular prediction
|
# regular prediction
|
||||||
if limit is not None:
|
if limit is not None:
|
||||||
@ -79,7 +171,18 @@ def predict(
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
pw.kv.update({"status": "failed"})
|
pw.kv.update({"status": "failed"})
|
||||||
pw.save()
|
pw.save()
|
||||||
|
|
||||||
|
if JobLog.objects.filter(task_id=self.request.id).exists():
|
||||||
|
JobLog.objects.filter(task_id=self.request.id).update(
|
||||||
|
status="FAILED", task_result=pw.url
|
||||||
|
)
|
||||||
|
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
pw.kv.update(**{"status": "completed"})
|
pw.kv.update(**{"status": "completed"})
|
||||||
pw.save()
|
pw.save()
|
||||||
|
|
||||||
|
if JobLog.objects.filter(task_id=self.request.id).exists():
|
||||||
|
JobLog.objects.filter(task_id=self.request.id).update(status="SUCCESS", task_result=pw.url)
|
||||||
|
|
||||||
|
return pw.url
|
||||||
|
|||||||
@ -1,8 +1,21 @@
|
|||||||
from django import template
|
from django import template
|
||||||
|
from pydantic import AnyHttpUrl, ValidationError
|
||||||
|
from pydantic.type_adapter import TypeAdapter
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
|
url_adapter = TypeAdapter(AnyHttpUrl)
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def classname(obj):
|
def classname(obj):
|
||||||
return obj.__class__.__name__
|
return obj.__class__.__name__
|
||||||
|
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def is_url(value):
|
||||||
|
try:
|
||||||
|
url_adapter.validate_python(value)
|
||||||
|
return True
|
||||||
|
except ValidationError:
|
||||||
|
return False
|
||||||
|
|||||||
51
epdb/urls.py
51
epdb/urls.py
@ -1,5 +1,5 @@
|
|||||||
from django.urls import path, re_path
|
|
||||||
from django.contrib.auth import views as auth_views
|
from django.contrib.auth import views as auth_views
|
||||||
|
from django.urls import path, re_path
|
||||||
|
|
||||||
from . import views as v
|
from . import views as v
|
||||||
|
|
||||||
@ -88,20 +88,36 @@ urlpatterns = [
|
|||||||
v.package_rule,
|
v.package_rule,
|
||||||
name="package rule detail",
|
name="package rule detail",
|
||||||
),
|
),
|
||||||
re_path(
|
# re_path(
|
||||||
rf"^package/(?P<package_uuid>{UUID})/simple-rdkit-rule/(?P<rule_uuid>{UUID})$",
|
# rf"^package/(?P<package_uuid>{UUID})/simple-rdkit-rule/(?P<rule_uuid>{UUID})$",
|
||||||
v.package_rule,
|
# v.package_rule,
|
||||||
name="package rule detail",
|
# name="package rule detail",
|
||||||
),
|
# ),
|
||||||
re_path(
|
re_path(
|
||||||
rf"^package/(?P<package_uuid>{UUID})/parallel-rule/(?P<rule_uuid>{UUID})$",
|
rf"^package/(?P<package_uuid>{UUID})/parallel-rule/(?P<rule_uuid>{UUID})$",
|
||||||
v.package_rule,
|
v.package_rule,
|
||||||
name="package rule detail",
|
name="package rule detail",
|
||||||
),
|
),
|
||||||
|
# re_path(
|
||||||
|
# rf"^package/(?P<package_uuid>{UUID})/sequential-rule/(?P<rule_uuid>{UUID})$",
|
||||||
|
# v.package_rule,
|
||||||
|
# name="package rule detail",
|
||||||
|
# ),
|
||||||
|
# EnzymeLinks
|
||||||
re_path(
|
re_path(
|
||||||
rf"^package/(?P<package_uuid>{UUID})/sequential-rule/(?P<rule_uuid>{UUID})$",
|
rf"^package/(?P<package_uuid>{UUID})/rule/(?P<rule_uuid>{UUID})/enzymelink/(?P<enzymelink_uuid>{UUID})$",
|
||||||
v.package_rule,
|
v.package_rule_enzymelink,
|
||||||
name="package rule detail",
|
name="package rule enzymelink detail",
|
||||||
|
),
|
||||||
|
re_path(
|
||||||
|
rf"^package/(?P<package_uuid>{UUID})/simple-ambit-rule/(?P<rule_uuid>{UUID})/enzymelink/(?P<enzymelink_uuid>{UUID})$",
|
||||||
|
v.package_rule_enzymelink,
|
||||||
|
name="package rule enzymelink detail",
|
||||||
|
),
|
||||||
|
re_path(
|
||||||
|
rf"^package/(?P<package_uuid>{UUID})/parallel-rule/(?P<rule_uuid>{UUID})/enzymelink/(?P<enzymelink_uuid>{UUID})$",
|
||||||
|
v.package_rule_enzymelink,
|
||||||
|
name="package rule enzymelink detail",
|
||||||
),
|
),
|
||||||
# Reaction
|
# Reaction
|
||||||
re_path(
|
re_path(
|
||||||
@ -174,15 +190,16 @@ urlpatterns = [
|
|||||||
re_path(r"^indigo/dearomatize$", v.dearomatize, name="indigo_dearomatize"),
|
re_path(r"^indigo/dearomatize$", v.dearomatize, name="indigo_dearomatize"),
|
||||||
re_path(r"^indigo/layout$", v.layout, name="indigo_layout"),
|
re_path(r"^indigo/layout$", v.layout, name="indigo_layout"),
|
||||||
re_path(r"^depict$", v.depict, name="depict"),
|
re_path(r"^depict$", v.depict, name="depict"),
|
||||||
|
re_path(r"^jobs", v.jobs, name="jobs"),
|
||||||
# OAuth Stuff
|
# OAuth Stuff
|
||||||
path("o/userinfo/", v.userinfo, name="oauth_userinfo"),
|
path("o/userinfo/", v.userinfo, name="oauth_userinfo"),
|
||||||
# Static Pages
|
# Static Pages
|
||||||
re_path(r"^terms$", v.terms_of_use, name="terms_of_use"),
|
re_path(r"^terms$", v.static_terms_of_use, name="terms_of_use"),
|
||||||
re_path(r"^privacy$", v.privacy_policy, name="privacy_policy"),
|
re_path(r"^privacy$", v.static_privacy_policy, name="privacy_policy"),
|
||||||
re_path(r"^cookie-policy$", v.cookie_policy, name="cookie_policy"),
|
re_path(r"^cookie-policy$", v.static_cookie_policy, name="cookie_policy"),
|
||||||
re_path(r"^about$", v.about_us, name="about_us"),
|
re_path(r"^about$", v.static_about_us, name="about_us"),
|
||||||
re_path(r"^contact$", v.contact_support, name="contact_support"),
|
re_path(r"^contact$", v.static_contact_support, name="contact_support"),
|
||||||
re_path(r"^jobs$", v.jobs, name="jobs"),
|
re_path(r"^jobs$", v.static_jobs, name="jobs"),
|
||||||
re_path(r"^cite$", v.cite, name="cite"),
|
re_path(r"^cite$", v.static_cite, name="cite"),
|
||||||
re_path(r"^legal$", v.legal, name="legal"),
|
re_path(r"^legal$", v.static_legal, name="legal"),
|
||||||
]
|
]
|
||||||
|
|||||||
268
epdb/views.py
268
epdb/views.py
@ -46,6 +46,8 @@ from .models import (
|
|||||||
Edge,
|
Edge,
|
||||||
ExternalDatabase,
|
ExternalDatabase,
|
||||||
ExternalIdentifier,
|
ExternalIdentifier,
|
||||||
|
EnzymeLink,
|
||||||
|
JobLog,
|
||||||
)
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -756,8 +758,8 @@ def package_models(request, package_uuid):
|
|||||||
context["unreviewed_objects"] = unreviewed_model_qs
|
context["unreviewed_objects"] = unreviewed_model_qs
|
||||||
|
|
||||||
context["model_types"] = {
|
context["model_types"] = {
|
||||||
"ML Relative Reasoning": "ml-relative-reasoning",
|
"ML Relative Reasoning": "mlrr",
|
||||||
"Rule Based Relative Reasoning": "rule-based-relative-reasoning",
|
"Rule Based Relative Reasoning": "rbrr",
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.FLAGS.get("ENVIFORMER", False):
|
if s.FLAGS.get("ENVIFORMER", False):
|
||||||
@ -777,69 +779,67 @@ def package_models(request, package_uuid):
|
|||||||
|
|
||||||
model_type = request.POST.get("model-type")
|
model_type = request.POST.get("model-type")
|
||||||
|
|
||||||
|
# Generic fields for ML and Rule Based
|
||||||
|
rule_packages = request.POST.getlist("model-rule-packages")
|
||||||
|
data_packages = request.POST.getlist("model-data-packages")
|
||||||
|
|
||||||
|
# Generic params
|
||||||
|
params = {
|
||||||
|
"package": current_package,
|
||||||
|
"name": name,
|
||||||
|
"description": description,
|
||||||
|
"data_packages": [
|
||||||
|
PackageManager.get_package_by_url(current_user, p) for p in data_packages
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
if model_type == "enviformer":
|
if model_type == "enviformer":
|
||||||
threshold = float(request.POST.get(f"{model_type}-threshold", 0.5))
|
threshold = float(request.POST.get("model-threshold", 0.5))
|
||||||
|
params["threshold"] = threshold
|
||||||
|
|
||||||
mod = EnviFormer.create(current_package, name, description, threshold)
|
mod = EnviFormer.create(**params)
|
||||||
|
elif model_type == "mlrr":
|
||||||
|
# ML Specific
|
||||||
|
threshold = float(request.POST.get("model-threshold", 0.5))
|
||||||
|
# TODO handle additional fingerprinter
|
||||||
|
# fingerprinter = request.POST.get("model-fingerprinter")
|
||||||
|
|
||||||
elif model_type == "ml-relative-reasoning" or model_type == "rule-based-relative-reasoning":
|
params["rule_packages"] = [
|
||||||
# Generic fields for ML and Rule Based
|
PackageManager.get_package_by_url(current_user, p) for p in rule_packages
|
||||||
rule_packages = request.POST.getlist("package-based-relative-reasoning-rule-packages")
|
]
|
||||||
data_packages = request.POST.getlist("package-based-relative-reasoning-data-packages")
|
|
||||||
eval_packages = request.POST.getlist(
|
|
||||||
"package-based-relative-reasoning-evaluation-packages", []
|
|
||||||
)
|
|
||||||
|
|
||||||
# Generic params
|
# App Domain related parameters
|
||||||
params = {
|
build_ad = request.POST.get("build-app-domain", False) == "on"
|
||||||
"package": current_package,
|
num_neighbors = request.POST.get("num-neighbors", 5)
|
||||||
"name": name,
|
reliability_threshold = request.POST.get("reliability-threshold", 0.5)
|
||||||
"description": description,
|
local_compatibility_threshold = request.POST.get("local-compatibility-threshold", 0.5)
|
||||||
"rule_packages": [
|
|
||||||
PackageManager.get_package_by_url(current_user, p) for p in rule_packages
|
|
||||||
],
|
|
||||||
"data_packages": [
|
|
||||||
PackageManager.get_package_by_url(current_user, p) for p in data_packages
|
|
||||||
],
|
|
||||||
"eval_packages": [
|
|
||||||
PackageManager.get_package_by_url(current_user, p) for p in eval_packages
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
if model_type == "ml-relative-reasoning":
|
params["threshold"] = threshold
|
||||||
# ML Specific
|
# params['fingerprinter'] = fingerprinter
|
||||||
threshold = float(request.POST.get(f"{model_type}-threshold", 0.5))
|
params["build_app_domain"] = build_ad
|
||||||
# TODO handle additional fingerprinter
|
params["app_domain_num_neighbours"] = num_neighbors
|
||||||
# fingerprinter = request.POST.get(f"{model_type}-fingerprinter")
|
params["app_domain_reliability_threshold"] = reliability_threshold
|
||||||
|
params["app_domain_local_compatibility_threshold"] = local_compatibility_threshold
|
||||||
|
|
||||||
# App Domain related parameters
|
mod = MLRelativeReasoning.create(**params)
|
||||||
build_ad = request.POST.get("build-app-domain", False) == "on"
|
elif model_type == "rbrr":
|
||||||
num_neighbors = request.POST.get("num-neighbors", 5)
|
params["rule_packages"] = [
|
||||||
reliability_threshold = request.POST.get("reliability-threshold", 0.5)
|
PackageManager.get_package_by_url(current_user, p) for p in rule_packages
|
||||||
local_compatibility_threshold = request.POST.get(
|
]
|
||||||
"local-compatibility-threshold", 0.5
|
|
||||||
)
|
|
||||||
|
|
||||||
params["threshold"] = threshold
|
mod = RuleBasedRelativeReasoning.create(**params)
|
||||||
# params['fingerprinter'] = fingerprinter
|
elif s.FLAGS.get("PLUGINS", False) and model_type in s.CLASSIFIER_PLUGINS.values():
|
||||||
params["build_app_domain"] = build_ad
|
pass
|
||||||
params["app_domain_num_neighbours"] = num_neighbors
|
|
||||||
params["app_domain_reliability_threshold"] = reliability_threshold
|
|
||||||
params["app_domain_local_compatibility_threshold"] = local_compatibility_threshold
|
|
||||||
|
|
||||||
mod = MLRelativeReasoning.create(**params)
|
|
||||||
else:
|
|
||||||
mod = RuleBasedRelativeReasoning.create(**params)
|
|
||||||
|
|
||||||
from .tasks import build_model
|
|
||||||
|
|
||||||
build_model.delay(mod.pk)
|
|
||||||
else:
|
else:
|
||||||
return error(
|
return error(
|
||||||
request, "Invalid model type.", f'Model type "{model_type}" is not supported."'
|
request, "Invalid model type.", f'Model type "{model_type}" is not supported."'
|
||||||
)
|
)
|
||||||
return redirect(mod.url)
|
|
||||||
|
|
||||||
|
from .tasks import dispatch, build_model
|
||||||
|
|
||||||
|
dispatch(current_user, build_model, mod.pk)
|
||||||
|
|
||||||
|
return redirect(mod.url)
|
||||||
else:
|
else:
|
||||||
return HttpResponseNotAllowed(["GET", "POST"])
|
return HttpResponseNotAllowed(["GET", "POST"])
|
||||||
|
|
||||||
@ -867,6 +867,10 @@ def package_model(request, package_uuid, model_uuid):
|
|||||||
return JsonResponse({"error": f'"{smiles}" is not a valid SMILES'}, status=400)
|
return JsonResponse({"error": f'"{smiles}" is not a valid SMILES'}, status=400)
|
||||||
|
|
||||||
if classify:
|
if classify:
|
||||||
|
from epdb.tasks import dispatch_eager, predict_simple
|
||||||
|
|
||||||
|
res = dispatch_eager(current_user, predict_simple, current_model.pk, stand_smiles)
|
||||||
|
|
||||||
pred_res = current_model.predict(stand_smiles)
|
pred_res = current_model.predict(stand_smiles)
|
||||||
res = []
|
res = []
|
||||||
|
|
||||||
@ -911,9 +915,25 @@ def package_model(request, package_uuid, model_uuid):
|
|||||||
current_model.delete()
|
current_model.delete()
|
||||||
return redirect(current_package.url + "/model")
|
return redirect(current_package.url + "/model")
|
||||||
elif hidden == "evaluate":
|
elif hidden == "evaluate":
|
||||||
from .tasks import evaluate_model
|
from .tasks import dispatch, evaluate_model
|
||||||
|
|
||||||
|
eval_type = request.POST.get("model-evaluation-type")
|
||||||
|
|
||||||
|
if eval_type not in ["sg", "mg"]:
|
||||||
|
return error(
|
||||||
|
request,
|
||||||
|
"Invalid evaluation type",
|
||||||
|
f'Evaluation type "{eval_type}" is not supported. Only "sg" and "mg" are supported.',
|
||||||
|
)
|
||||||
|
|
||||||
|
multigen = eval_type == "mg"
|
||||||
|
|
||||||
|
eval_packages = request.POST.getlist("model-evaluation-packages")
|
||||||
|
eval_package_ids = [
|
||||||
|
PackageManager.get_package_by_url(current_user, p).id for p in eval_packages
|
||||||
|
]
|
||||||
|
dispatch(current_user, evaluate_model, current_model.pk, multigen, eval_package_ids)
|
||||||
|
|
||||||
evaluate_model.delay(current_model.pk)
|
|
||||||
return redirect(current_model.url)
|
return redirect(current_model.url)
|
||||||
else:
|
else:
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
@ -1253,7 +1273,16 @@ def package_compound_structures(request, package_uuid, compound_uuid):
|
|||||||
structure_smiles = request.POST.get("structure-smiles")
|
structure_smiles = request.POST.get("structure-smiles")
|
||||||
structure_description = request.POST.get("structure-description")
|
structure_description = request.POST.get("structure-description")
|
||||||
|
|
||||||
cs = current_compound.add_structure(structure_smiles, structure_name, structure_description)
|
try:
|
||||||
|
cs = current_compound.add_structure(
|
||||||
|
structure_smiles, structure_name, structure_description
|
||||||
|
)
|
||||||
|
except ValueError:
|
||||||
|
return error(
|
||||||
|
request,
|
||||||
|
"Adding structure failed!",
|
||||||
|
"The structure could not be added as normalized structures don't match!",
|
||||||
|
)
|
||||||
|
|
||||||
return redirect(cs.url)
|
return redirect(cs.url)
|
||||||
|
|
||||||
@ -1456,12 +1485,20 @@ def package_rule(request, package_uuid, rule_uuid):
|
|||||||
logger.info(
|
logger.info(
|
||||||
f"Rule {current_rule.uuid} returned multiple product sets on {smiles}, picking the first one."
|
f"Rule {current_rule.uuid} returned multiple product sets on {smiles}, picking the first one."
|
||||||
)
|
)
|
||||||
|
# Some Rules are touching unrelated areas which might result in ~ indicating
|
||||||
smirks = f"{stand_smiles}>>{'.'.join(sorted(res[0]))}"
|
# any bond (-, =, #). For drawing we need a concrete bond. -> use single bond
|
||||||
|
product_smiles = [x.replace("~", "-") for x in res[0]]
|
||||||
|
smirks = f"{stand_smiles}>>{'.'.join(sorted(product_smiles))}"
|
||||||
# Usually the functional groups are a mapping of fg -> count
|
# Usually the functional groups are a mapping of fg -> count
|
||||||
# As we are doing it on the fly here fake a high count to ensure that its properly highlighted
|
# As we are doing it on the fly here fake a high count to ensure that its properly highlighted
|
||||||
educt_functional_groups = {x: 1000 for x in current_rule.reactants_smarts}
|
|
||||||
product_functional_groups = {x: 1000 for x in current_rule.products_smarts}
|
if isinstance(current_rule, SimpleAmbitRule):
|
||||||
|
educt_functional_groups = {current_rule.reactants_smarts: 1000}
|
||||||
|
product_functional_groups = {current_rule.products_smarts: 1000}
|
||||||
|
else:
|
||||||
|
educt_functional_groups = {x: 1000 for x in current_rule.reactants_smarts}
|
||||||
|
product_functional_groups = {x: 1000 for x in current_rule.products_smarts}
|
||||||
|
|
||||||
return HttpResponse(
|
return HttpResponse(
|
||||||
IndigoUtils.smirks_to_svg(
|
IndigoUtils.smirks_to_svg(
|
||||||
smirks,
|
smirks,
|
||||||
@ -1531,6 +1568,32 @@ def package_rule(request, package_uuid, rule_uuid):
|
|||||||
return HttpResponseNotAllowed(["GET", "POST"])
|
return HttpResponseNotAllowed(["GET", "POST"])
|
||||||
|
|
||||||
|
|
||||||
|
@package_permission_required()
|
||||||
|
def package_rule_enzymelink(request, package_uuid, rule_uuid, enzymelink_uuid):
|
||||||
|
current_user = _anonymous_or_real(request)
|
||||||
|
current_package = PackageManager.get_package_by_id(current_user, package_uuid)
|
||||||
|
current_rule = Rule.objects.get(package=current_package, uuid=rule_uuid)
|
||||||
|
current_enzymelink = EnzymeLink.objects.get(rule=current_rule, uuid=enzymelink_uuid)
|
||||||
|
|
||||||
|
if request.method == "GET":
|
||||||
|
context = get_base_context(request)
|
||||||
|
|
||||||
|
context["title"] = f"enviPath - {current_package.name} - {current_rule.name}"
|
||||||
|
|
||||||
|
context["meta"]["current_package"] = current_package
|
||||||
|
context["object_type"] = "enzyme"
|
||||||
|
context["breadcrumbs"] = breadcrumbs(
|
||||||
|
current_package, "rule", current_rule, "enzymelink", current_enzymelink
|
||||||
|
)
|
||||||
|
|
||||||
|
context["enzymelink"] = current_enzymelink
|
||||||
|
context["current_object"] = current_enzymelink
|
||||||
|
|
||||||
|
return render(request, "objects/enzymelink.html", context)
|
||||||
|
|
||||||
|
return HttpResponseNotAllowed(["GET"])
|
||||||
|
|
||||||
|
|
||||||
@package_permission_required()
|
@package_permission_required()
|
||||||
def package_reactions(request, package_uuid):
|
def package_reactions(request, package_uuid):
|
||||||
current_user = _anonymous_or_real(request)
|
current_user = _anonymous_or_real(request)
|
||||||
@ -1768,9 +1831,9 @@ def package_pathways(request, package_uuid):
|
|||||||
pw.setting = prediction_setting
|
pw.setting = prediction_setting
|
||||||
pw.save()
|
pw.save()
|
||||||
|
|
||||||
from .tasks import predict
|
from .tasks import dispatch, predict
|
||||||
|
|
||||||
predict.delay(pw.pk, prediction_setting.pk, limit=limit)
|
dispatch(current_user, predict, pw.pk, prediction_setting.pk, limit=limit)
|
||||||
|
|
||||||
return redirect(pw.url)
|
return redirect(pw.url)
|
||||||
|
|
||||||
@ -1889,10 +1952,16 @@ def package_pathway(request, package_uuid, pathway_uuid):
|
|||||||
if node_url:
|
if node_url:
|
||||||
n = current_pathway.get_node(node_url)
|
n = current_pathway.get_node(node_url)
|
||||||
|
|
||||||
from .tasks import predict
|
from .tasks import dispatch, predict
|
||||||
|
|
||||||
|
dispatch(
|
||||||
|
current_user,
|
||||||
|
predict,
|
||||||
|
current_pathway.pk,
|
||||||
|
current_pathway.setting.pk,
|
||||||
|
node_pk=n.pk,
|
||||||
|
)
|
||||||
|
|
||||||
# Dont delay?
|
|
||||||
predict(current_pathway.pk, current_pathway.setting.pk, node_pk=n.pk)
|
|
||||||
return JsonResponse({"success": current_pathway.url})
|
return JsonResponse({"success": current_pathway.url})
|
||||||
|
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
@ -1969,9 +2038,42 @@ def package_pathway_node(request, package_uuid, pathway_uuid, node_uuid):
|
|||||||
|
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
is_image_request = request.GET.get("image")
|
is_image_request = request.GET.get("image")
|
||||||
|
is_highlight_request = request.GET.get("highlight", False)
|
||||||
|
is_highlight_reactivity = request.GET.get("highlightReactivity", False)
|
||||||
if is_image_request:
|
if is_image_request:
|
||||||
if is_image_request == "svg":
|
if is_image_request == "svg":
|
||||||
svg_data = current_node.as_svg
|
# TODO optimize this chain
|
||||||
|
if is_highlight_request:
|
||||||
|
# User functional groups covered by the model training data
|
||||||
|
fgs = {}
|
||||||
|
if current_pathway.setting:
|
||||||
|
if current_pathway.setting.model:
|
||||||
|
if current_pathway.setting.model.app_domain:
|
||||||
|
fgs = current_pathway.setting.model.app_domain.functional_groups
|
||||||
|
|
||||||
|
svg_data = IndigoUtils.mol_to_svg(
|
||||||
|
current_node.default_node_label.smiles, functional_groups=fgs
|
||||||
|
)
|
||||||
|
elif is_highlight_reactivity:
|
||||||
|
# Use reactant smarts to show all reaction sites
|
||||||
|
# set a high count to obtain a strong color
|
||||||
|
ad_data = current_node.get_app_domain_assessment_data()
|
||||||
|
fgs = {}
|
||||||
|
for t in ad_data.get("assessment", {}).get("transformations", []):
|
||||||
|
r = Rule.objects.get(url=t["rule"]["url"])
|
||||||
|
|
||||||
|
if isinstance(r, SimpleAmbitRule):
|
||||||
|
fgs[r.reactants_smarts] = 1000
|
||||||
|
else:
|
||||||
|
for sr in r.srs:
|
||||||
|
fgs[sr.reactants_smarts] = 1000
|
||||||
|
|
||||||
|
svg_data = IndigoUtils.mol_to_svg(
|
||||||
|
current_node.default_node_label.smiles, functional_groups=fgs
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
svg_data = current_node.as_svg
|
||||||
|
|
||||||
return HttpResponse(svg_data, content_type="image/svg+xml")
|
return HttpResponse(svg_data, content_type="image/svg+xml")
|
||||||
|
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
@ -2631,6 +2733,24 @@ def setting(request, setting_uuid):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def jobs(request):
|
||||||
|
current_user = _anonymous_or_real(request)
|
||||||
|
context = get_base_context(request)
|
||||||
|
|
||||||
|
if request.method == "GET":
|
||||||
|
context["object_type"] = "joblog"
|
||||||
|
context["breadcrumbs"] = [
|
||||||
|
{"Home": s.SERVER_URL},
|
||||||
|
{"Jobs": s.SERVER_URL + "/jobs"},
|
||||||
|
]
|
||||||
|
if current_user.is_superuser:
|
||||||
|
context["jobs"] = JobLog.objects.all().order_by("-created")
|
||||||
|
else:
|
||||||
|
context["jobs"] = JobLog.objects.filter(user=current_user).order_by("-created")
|
||||||
|
|
||||||
|
return render(request, "collections/joblog.html", context)
|
||||||
|
|
||||||
|
|
||||||
###########
|
###########
|
||||||
# KETCHER #
|
# KETCHER #
|
||||||
###########
|
###########
|
||||||
@ -2705,49 +2825,49 @@ def userinfo(request):
|
|||||||
|
|
||||||
|
|
||||||
# Static Pages
|
# Static Pages
|
||||||
def terms_of_use(request):
|
def static_terms_of_use(request):
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = "enviPath - Terms of Use"
|
context["title"] = "enviPath - Terms of Use"
|
||||||
return render(request, "static/terms_of_use.html", context)
|
return render(request, "static/terms_of_use.html", context)
|
||||||
|
|
||||||
|
|
||||||
def privacy_policy(request):
|
def static_privacy_policy(request):
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = "enviPath - Privacy Policy"
|
context["title"] = "enviPath - Privacy Policy"
|
||||||
return render(request, "static/privacy_policy.html", context)
|
return render(request, "static/privacy_policy.html", context)
|
||||||
|
|
||||||
|
|
||||||
def cookie_policy(request):
|
def static_cookie_policy(request):
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = "enviPath - Cookie Policy"
|
context["title"] = "enviPath - Cookie Policy"
|
||||||
return render(request, "static/cookie_policy.html", context)
|
return render(request, "static/cookie_policy.html", context)
|
||||||
|
|
||||||
|
|
||||||
def about_us(request):
|
def static_about_us(request):
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = "enviPath - About Us"
|
context["title"] = "enviPath - About Us"
|
||||||
return render(request, "static/about_us.html", context)
|
return render(request, "static/about_us.html", context)
|
||||||
|
|
||||||
|
|
||||||
def contact_support(request):
|
def static_contact_support(request):
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = "enviPath - Contact & Support"
|
context["title"] = "enviPath - Contact & Support"
|
||||||
return render(request, "static/contact.html", context)
|
return render(request, "static/contact.html", context)
|
||||||
|
|
||||||
|
|
||||||
def jobs(request):
|
def static_jobs(request):
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = "enviPath - Jobs & Careers"
|
context["title"] = "enviPath - Jobs & Careers"
|
||||||
return render(request, "static/jobs.html", context)
|
return render(request, "static/jobs.html", context)
|
||||||
|
|
||||||
|
|
||||||
def cite(request):
|
def static_cite(request):
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = "enviPath - How to Cite"
|
context["title"] = "enviPath - How to Cite"
|
||||||
return render(request, "static/cite.html", context)
|
return render(request, "static/cite.html", context)
|
||||||
|
|
||||||
|
|
||||||
def legal(request):
|
def static_legal(request):
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context["title"] = "enviPath - Legal Information"
|
context["title"] = "enviPath - Legal Information"
|
||||||
return render(request, "static/legal.html", context)
|
return render(request, "static/legal.html", context)
|
||||||
|
|||||||
@ -13,7 +13,7 @@ dependencies = [
|
|||||||
"django-oauth-toolkit>=3.0.1",
|
"django-oauth-toolkit>=3.0.1",
|
||||||
"django-polymorphic>=4.1.0",
|
"django-polymorphic>=4.1.0",
|
||||||
"django-stubs>=5.2.4",
|
"django-stubs>=5.2.4",
|
||||||
#"enviformer",
|
"enviformer",
|
||||||
"envipy-additional-information",
|
"envipy-additional-information",
|
||||||
"envipy-ambit>=0.1.0",
|
"envipy-ambit>=0.1.0",
|
||||||
"envipy-plugins",
|
"envipy-plugins",
|
||||||
@ -31,9 +31,9 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[tool.uv.sources]
|
[tool.uv.sources]
|
||||||
#enviformer = { git = "ssh://git@git.envipath.com/enviPath/enviformer.git", rev = "v0.1.2" }
|
enviformer = { git = "ssh://git@git.envipath.com/enviPath/enviformer.git", rev = "v0.1.2" }
|
||||||
envipy-plugins = { git = "ssh://git@git.envipath.com/enviPath/enviPy-plugins.git", rev = "v0.1.0" }
|
envipy-plugins = { git = "ssh://git@git.envipath.com/enviPath/enviPy-plugins.git", rev = "v0.1.0" }
|
||||||
envipy-additional-information = { git = "ssh://git@git.envipath.com/enviPath/enviPy-additional-information.git", rev = "v0.1.4"}
|
envipy-additional-information = { git = "ssh://git@git.envipath.com/enviPath/enviPy-additional-information.git", rev = "v0.1.7"}
|
||||||
envipy-ambit = { git = "ssh://git@git.envipath.com/enviPath/enviPy-ambit.git" }
|
envipy-ambit = { git = "ssh://git@git.envipath.com/enviPath/enviPy-ambit.git" }
|
||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
@ -45,6 +45,8 @@ dev = [
|
|||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
ms-login = ["msal>=1.33.0"]
|
ms-login = ["msal>=1.33.0"]
|
||||||
dev = [
|
dev = [
|
||||||
|
"celery-stubs==0.1.3",
|
||||||
|
"django-stubs>=5.2.4",
|
||||||
"poethepoet>=0.37.0",
|
"poethepoet>=0.37.0",
|
||||||
"pre-commit>=4.3.0",
|
"pre-commit>=4.3.0",
|
||||||
"ruff>=0.13.3",
|
"ruff>=0.13.3",
|
||||||
|
|||||||
BIN
static/images/UoA-Logo-Primary-RGB-Large.png
Normal file
BIN
static/images/UoA-Logo-Primary-RGB-Large.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 114 KiB |
BIN
static/images/UoA-Logo-Primary-RGB-Reversed-Large.png
Normal file
BIN
static/images/UoA-Logo-Primary-RGB-Reversed-Large.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 114 KiB |
BIN
static/images/UoA-Logo-Primary-RGB-Reversed-Small.png
Normal file
BIN
static/images/UoA-Logo-Primary-RGB-Reversed-Small.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
BIN
static/images/UoA-Logo-Primary-RGB-Small.png
Normal file
BIN
static/images/UoA-Logo-Primary-RGB-Small.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB |
@ -646,8 +646,8 @@ function handleAssessmentResponse(depict_url, data) {
|
|||||||
var reactivityCentersImgSrc = null;
|
var reactivityCentersImgSrc = null;
|
||||||
|
|
||||||
if (data['assessment']['node'] !== undefined) {
|
if (data['assessment']['node'] !== undefined) {
|
||||||
functionalGroupsImgSrc = "<img width='400' src='" + data['assessment']['node']['image'] + "'>";
|
functionalGroupsImgSrc = "<img width='400' src='" + data['assessment']['node']['image'] + "&highlight=true'>";
|
||||||
reactivityCentersImgSrc = "<img width='400' src='" + data['assessment']['node']['image'] + "'>"
|
reactivityCentersImgSrc = "<img width='400' src='" + data['assessment']['node']['image'] + "&highlightReactivity=true'>"
|
||||||
} else {
|
} else {
|
||||||
functionalGroupsImgSrc = "<img width='400' src=\"" + depict_url + "?smiles=" + encodeURIComponent(data['assessment']['smiles']) + "\">";
|
functionalGroupsImgSrc = "<img width='400' src=\"" + depict_url + "?smiles=" + encodeURIComponent(data['assessment']['smiles']) + "\">";
|
||||||
reactivityCentersImgSrc = "<img width='400' src=\"" + depict_url + "?smiles=" + encodeURIComponent(data['assessment']['smiles']) + "\">"
|
reactivityCentersImgSrc = "<img width='400' src=\"" + depict_url + "?smiles=" + encodeURIComponent(data['assessment']['smiles']) + "\">"
|
||||||
|
|||||||
@ -444,6 +444,13 @@ function serializeSVG(svgElement) {
|
|||||||
line.setAttribute("fill", style.fill);
|
line.setAttribute("fill", style.fill);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
svgElement.querySelectorAll("line.link_no_arrow").forEach(line => {
|
||||||
|
const style = getComputedStyle(line);
|
||||||
|
line.setAttribute("stroke", style.stroke);
|
||||||
|
line.setAttribute("stroke-width", style.strokeWidth);
|
||||||
|
line.setAttribute("fill", style.fill);
|
||||||
|
});
|
||||||
|
|
||||||
const serializer = new XMLSerializer();
|
const serializer = new XMLSerializer();
|
||||||
let svgString = serializer.serializeToString(svgElement);
|
let svgString = serializer.serializeToString(svgElement);
|
||||||
|
|
||||||
@ -455,7 +462,26 @@ function serializeSVG(svgElement) {
|
|||||||
return svgString;
|
return svgString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function shrinkSVG(svgSelector) {
|
||||||
|
|
||||||
|
const svg = d3.select(svgSelector);
|
||||||
|
const node = svg.node();
|
||||||
|
|
||||||
|
// Compute bounding box of everything inside the SVG
|
||||||
|
const bbox = node.getBBox();
|
||||||
|
|
||||||
|
const padding = 10;
|
||||||
|
svg.attr("viewBox",
|
||||||
|
`${bbox.x - padding} ${bbox.y - padding} ${bbox.width + 2 * padding} ${bbox.height + 2 * padding}`
|
||||||
|
)
|
||||||
|
.attr("width", bbox.width + 2 * padding)
|
||||||
|
.attr("height", bbox.height + 2 * padding);
|
||||||
|
|
||||||
|
return bbox;
|
||||||
|
}
|
||||||
|
|
||||||
function downloadSVG(svgElement, filename = 'chart.svg') {
|
function downloadSVG(svgElement, filename = 'chart.svg') {
|
||||||
|
shrinkSVG("#" + svgElement.id);
|
||||||
const svgString = serializeSVG(svgElement);
|
const svgString = serializeSVG(svgElement);
|
||||||
const blob = new Blob([svgString], {type: 'image/svg+xml;charset=utf-8'});
|
const blob = new Blob([svgString], {type: 'image/svg+xml;charset=utf-8'});
|
||||||
const url = URL.createObjectURL(blob);
|
const url = URL.createObjectURL(blob);
|
||||||
|
|||||||
71
templates/collections/joblog.html
Normal file
71
templates/collections/joblog.html
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
{% extends "framework.html" %}
|
||||||
|
{% load static %}
|
||||||
|
{% load envipytags %}
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="panel-group" id="reviewListAccordion">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px">
|
||||||
|
Jobs
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<p>
|
||||||
|
Job Logs Desc
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="job-accordion-link" data-toggle="collapse" data-parent="#job-accordion" href="#jobs">
|
||||||
|
Jobs
|
||||||
|
</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="jobs"
|
||||||
|
class="panel-collapse collapse in">
|
||||||
|
<div class="panel-body list-group-item" id="job-content">
|
||||||
|
<table class="table table-bordered table-hover">
|
||||||
|
<tr style="background-color: rgba(0, 0, 0, 0.08);">
|
||||||
|
<th scope="col">ID</th>
|
||||||
|
<th scope="col">Name</th>
|
||||||
|
<th scope="col">Status</th>
|
||||||
|
<th scope="col">Queued</th>
|
||||||
|
<th scope="col">Done</th>
|
||||||
|
<th scope="col">Result</th>
|
||||||
|
</tr>
|
||||||
|
<tbody>
|
||||||
|
{% for job in jobs %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ job.task_id }}</td>
|
||||||
|
<td>{{ job.job_name }}</td>
|
||||||
|
<td>{{ job.status }}</td>
|
||||||
|
<td>{{ job.created }}</td>
|
||||||
|
<td>{{ job.done_at }}</td>
|
||||||
|
{% if job.task_result and job.task_result|is_url == True %}
|
||||||
|
<td><a href="{{ job.task_result }}">Result</a></td>
|
||||||
|
{% elif job.task_result %}
|
||||||
|
<td>{{ job.task_result|slice:"40" }}...</td>
|
||||||
|
{% else %}
|
||||||
|
<td>Empty</td>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Unreviewable objects such as User / Group / Setting -->
|
||||||
|
<ul class='list-group'>
|
||||||
|
{% for obj in objects %}
|
||||||
|
{% if object_type == 'user' %}
|
||||||
|
<a class="list-group-item" href="{{ obj.url }}">{{ obj.username }}</a>
|
||||||
|
{% else %}
|
||||||
|
<a class="list-group-item" href="{{ obj.url }}">{{ obj.name }}</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
||||||
@ -242,21 +242,23 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<ul class="nav nav-pills nav-justified">
|
<ul class="nav nav-pills nav-justified">
|
||||||
<li><a href="http://eawag.ch" target="_blank">
|
|
||||||
<img id="image-ealogo"
|
|
||||||
height="60"
|
|
||||||
src='{% static "/images/ealogo.gif" %}'
|
|
||||||
alt="Eawag"/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
<li>
|
||||||
<a href="http://ml.auckland.ac.nz" target="_blank">
|
<a href="http://ml.auckland.ac.nz" target="_blank">
|
||||||
<img id="image-uoalogo"
|
<img id="image-uoalogo" height="60" src='{% static "/images/UoA-Logo-Primary-RGB-Small.png" %}'
|
||||||
height="60"
|
|
||||||
src='{% static "/images/uoa.png" %}'
|
|
||||||
alt="The Univserity of Auckland"/>
|
alt="The Univserity of Auckland"/>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://eawag.ch" target="_blank">
|
||||||
|
<img id="image-ealogo" height="60" src='{% static "/images/ealogo.gif" %}' alt="Eawag"/>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://www.uzh.ch/" target="_blank">
|
||||||
|
<img id="image-ufzlogo" height="60" src='{% static "/images/uzh-logo.svg" %}'
|
||||||
|
alt="University of Zurich"/>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -18,113 +18,117 @@
|
|||||||
prediction. You just need to set a name and the packages
|
prediction. You just need to set a name and the packages
|
||||||
you want the object to be based on. There are multiple types of models available.
|
you want the object to be based on. There are multiple types of models available.
|
||||||
For additional information have a look at our
|
For additional information have a look at our
|
||||||
<a target="_blank" href="https://wiki.envipath.org/index.php/relative-reasoning" role="button">wiki >></a>
|
<a target="_blank" href="https://wiki.envipath.org/index.php/relative-reasoning" role="button">wiki
|
||||||
|
>></a>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Name -->
|
||||||
<label for="model-name">Name</label>
|
<label for="model-name">Name</label>
|
||||||
<input id="model-name" name="model-name" class="form-control" placeholder="Name"/>
|
<input id="model-name" name="model-name" class="form-control" placeholder="Name"/>
|
||||||
|
|
||||||
|
<!-- Description -->
|
||||||
<label for="model-description">Description</label>
|
<label for="model-description">Description</label>
|
||||||
<input id="model-description" name="model-description" class="form-control"
|
<input id="model-description" name="model-description" class="form-control"
|
||||||
placeholder="Description"/>
|
placeholder="Description"/>
|
||||||
|
|
||||||
|
<!-- Model Type -->
|
||||||
<label for="model-type">Model Type</label>
|
<label for="model-type">Model Type</label>
|
||||||
<select id="model-type" name="model-type" class="form-control" data-width='100%'>
|
<select id="model-type" name="model-type" class="form-control" data-width='100%'>
|
||||||
<option disabled selected>Select Model Type</option>
|
<option disabled selected>Select Model Type</option>
|
||||||
{% for k, v in model_types.items %}
|
{% for k, v in model_types.items %}
|
||||||
<option value="{{ v }}">{{ k }}</option>
|
<option value="{{ v }}">{{ k }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<!-- ML and Rule Based Based Form-->
|
|
||||||
<div id="package-based-relative-reasoning-specific-form">
|
<!-- Rule Packages -->
|
||||||
<!-- Rule Packages -->
|
<div id="rule-packages" class="ep-model-param mlrr rbrr">
|
||||||
<label for="package-based-relative-reasoning-rule-packages">Rule Packages</label>
|
<label for="model-rule-packages">Rule Packages</label>
|
||||||
<select id="package-based-relative-reasoning-rule-packages" name="package-based-relative-reasoning-rule-packages"
|
<select id="model-rule-packages" name="model-rule-packages" data-actions-box='true'
|
||||||
data-actions-box='true' class="form-control" multiple data-width='100%'>
|
class="form-control" multiple data-width='100%'>
|
||||||
<option disabled>Reviewed Packages</option>
|
<option disabled>Reviewed Packages</option>
|
||||||
{% for obj in meta.readable_packages %}
|
{% for obj in meta.readable_packages %}
|
||||||
{% if obj.reviewed %}
|
{% if obj.reviewed %}
|
||||||
<option value="{{ obj.url }}">{{ obj.name }}</option>
|
<option value="{{ obj.url }}">{{ obj.name }}</option>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
<option disabled>Unreviewed Packages</option>
|
<option disabled>Unreviewed Packages</option>
|
||||||
{% for obj in meta.readable_packages %}
|
{% for obj in meta.readable_packages %}
|
||||||
{% if not obj.reviewed %}
|
{% if not obj.reviewed %}
|
||||||
<option value="{{ obj.url }}">{{ obj.name }}</option>
|
<option value="{{ obj.url }}">{{ obj.name }}</option>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<!-- Data Packages -->
|
|
||||||
<label for="package-based-relative-reasoning-data-packages" >Data Packages</label>
|
|
||||||
<select id="package-based-relative-reasoning-data-packages" name="package-based-relative-reasoning-data-packages"
|
|
||||||
data-actions-box='true' class="form-control" multiple data-width='100%'>
|
|
||||||
<option disabled>Reviewed Packages</option>
|
|
||||||
{% for obj in meta.readable_packages %}
|
|
||||||
{% if obj.reviewed %}
|
|
||||||
<option value="{{ obj.url }}">{{ obj.name }}</option>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
<option disabled>Unreviewed Packages</option>
|
|
||||||
{% for obj in meta.readable_packages %}
|
|
||||||
{% if not obj.reviewed %}
|
|
||||||
<option value="{{ obj.url }}">{{ obj.name }}</option>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<div id="ml-relative-reasoning-specific-form">
|
|
||||||
<!-- Fingerprinter -->
|
|
||||||
<label for="ml-relative-reasoning-fingerprinter">Fingerprinter</label>
|
|
||||||
<select id="ml-relative-reasoning-fingerprinter" name="ml-relative-reasoning-fingerprinter"
|
|
||||||
class="form-control">
|
|
||||||
<option value="MACCS" selected>MACCS Fingerprinter</option>
|
|
||||||
</select>
|
|
||||||
{% if meta.enabled_features.PLUGINS and additional_descriptors %}
|
|
||||||
<!-- Property Plugins go here -->
|
|
||||||
<label for="ml-relative-reasoning-additional-fingerprinter">Additional Fingerprinter /
|
|
||||||
Descriptors</label>
|
|
||||||
<select id="ml-relative-reasoning-additional-fingerprinter"
|
|
||||||
name="ml-relative-reasoning-additional-fingerprinter" class="form-control">
|
|
||||||
<option disabled selected>Select Additional Fingerprinter / Descriptor</option>
|
|
||||||
{% for k, v in additional_descriptors.items %}
|
|
||||||
<option value="{{ v }}">{{ k }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<label for="ml-relative-reasoning-threshold">Threshold</label>
|
|
||||||
<input type="number" min="0" max="1" step="0.05" value="0.5"
|
|
||||||
id="ml-relative-reasoning-threshold"
|
|
||||||
name="ml-relative-reasoning-threshold" class="form-control">
|
|
||||||
</div>
|
|
||||||
{% if meta.enabled_features.APPLICABILITY_DOMAIN %}
|
|
||||||
<!-- Build AD? -->
|
|
||||||
<div class="checkbox">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" id="build-app-domain" name="build-app-domain">Also build an
|
|
||||||
Applicability Domain?
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div id="ad-params" style="display:none">
|
|
||||||
<!-- Num Neighbors -->
|
|
||||||
<label for="num-neighbors">Number of Neighbors</label>
|
|
||||||
<input id="num-neighbors" name="num-neighbors" type="number" class="form-control" value="5"
|
|
||||||
step="1" min="0" max="10">
|
|
||||||
<!-- Local Compatibility -->
|
|
||||||
<label for="local-compatibility-threshold">Local Compatibility Threshold</label>
|
|
||||||
<input id="local-compatibility-threshold" name="local-compatibility-threshold" type="number"
|
|
||||||
class="form-control" value="0.5" step="0.01" min="0" max="1">
|
|
||||||
<!-- Reliability -->
|
|
||||||
<label for="reliability-threshold">Reliability Threshold</label>
|
|
||||||
<input id="reliability-threshold" name="reliability-threshold" type="number"
|
|
||||||
class="form-control" value="0.5" step="0.01" min="0" max="1">
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
<!-- EnviFormer-->
|
|
||||||
<div id="enviformer-specific-form">
|
<!-- Data Packages -->
|
||||||
<label for="enviformer-threshold">Threshold</label>
|
<div id="data-packages" class="ep-model-param mlrr rbrr enviformer">
|
||||||
<input type="number" min="0" max="1" step="0.05" value="0.5" id="enviformer-threshold"
|
<label for="model-data-packages">Data Packages</label>
|
||||||
name="enviformer-threshold" class="form-control">
|
<select id="model-data-packages" name="model-data-packages" data-actions-box='true'
|
||||||
|
class="form-control" multiple data-width='100%'>
|
||||||
|
<option disabled>Reviewed Packages</option>
|
||||||
|
{% for obj in meta.readable_packages %}
|
||||||
|
{% if obj.reviewed %}
|
||||||
|
<option value="{{ obj.url }}">{{ obj.name }}</option>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<option disabled>Unreviewed Packages</option>
|
||||||
|
{% for obj in meta.readable_packages %}
|
||||||
|
{% if not obj.reviewed %}
|
||||||
|
<option value="{{ obj.url }}">{{ obj.name }}</option>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Fingerprinter -->
|
||||||
|
<div id="fingerprinter" class="ep-model-param mlrr">
|
||||||
|
<label for="model-fingerprinter">Fingerprinter</label>
|
||||||
|
<select id="model-fingerprinter" name="model-fingerprinter" data-actions-box='true'
|
||||||
|
class="form-control" multiple data-width='100%'>
|
||||||
|
<option value="MACCS" selected>MACCS Fingerprinter</option>
|
||||||
|
{% if meta.enabled_features.PLUGINS and additional_descriptors %}
|
||||||
|
<option disabled selected>Select Additional Fingerprinter / Descriptor</option>
|
||||||
|
{% for k, v in additional_descriptors.items %}
|
||||||
|
<option value="{{ v }}">{{ k }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Threshold -->
|
||||||
|
<div id="threshold" class="ep-model-param mlrr enviformer">
|
||||||
|
<label for="model-threshold">Threshold</label>
|
||||||
|
<input type="number" min="0" max="1" step="0.05" value="0.5" id="model-threshold"
|
||||||
|
name="model-threshold" class="form-control">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="appdomain" class="ep-model-param mlrr">
|
||||||
|
{% if meta.enabled_features.APPLICABILITY_DOMAIN %}
|
||||||
|
<!-- Build AD? -->
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="build-app-domain" name="build-app-domain">Also build an
|
||||||
|
Applicability Domain?
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div id="ad-params" style="display:none">
|
||||||
|
<!-- Num Neighbors -->
|
||||||
|
<label for="num-neighbors">Number of Neighbors</label>
|
||||||
|
<input id="num-neighbors" name="num-neighbors" type="number" class="form-control"
|
||||||
|
value="5"
|
||||||
|
step="1" min="0" max="10">
|
||||||
|
<!-- Local Compatibility -->
|
||||||
|
<label for="local-compatibility-threshold">Local Compatibility Threshold</label>
|
||||||
|
<input id="local-compatibility-threshold" name="local-compatibility-threshold"
|
||||||
|
type="number"
|
||||||
|
class="form-control" value="0.5" step="0.01" min="0" max="1">
|
||||||
|
<!-- Reliability -->
|
||||||
|
<label for="reliability-threshold">Reliability Threshold</label>
|
||||||
|
<input id="reliability-threshold" name="reliability-threshold" type="number"
|
||||||
|
class="form-control" value="0.5" step="0.01" min="0" max="1">
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -137,53 +141,47 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
$(function() {
|
$(function () {
|
||||||
// Initially hide all "specific" forms
|
// Built in Model Types
|
||||||
$("div[id$='-specific-form']").each( function() {
|
var nativeModelTypes = [
|
||||||
$(this).hide();
|
"mlrr",
|
||||||
});
|
"rbrr",
|
||||||
|
"enviformer",
|
||||||
|
]
|
||||||
|
|
||||||
$('#model-type').selectpicker();
|
// Initially hide all "specific" forms
|
||||||
$("#ml-relative-reasoning-fingerprinter").selectpicker();
|
$(".ep-model-param").each(function () {
|
||||||
$("#package-based-relative-reasoning-rule-packages").selectpicker();
|
|
||||||
$("#package-based-relative-reasoning-data-packages").selectpicker();
|
|
||||||
$("#package-based-relative-reasoning-evaluation-packages").selectpicker();
|
|
||||||
if ($('#ml-relative-reasoning-additional-fingerprinter').length > 0) {
|
|
||||||
$("#ml-relative-reasoning-additional-fingerprinter").selectpicker();
|
|
||||||
}
|
|
||||||
|
|
||||||
$("#build-app-domain").change(function () {
|
|
||||||
if ($(this).is(":checked")) {
|
|
||||||
$('#ad-params').show();
|
|
||||||
} else {
|
|
||||||
$('#ad-params').hide();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// On change hide all and show only selected
|
|
||||||
$("#model-type").change(function() {
|
|
||||||
$("div[id$='-specific-form']").each( function() {
|
|
||||||
$(this).hide();
|
$(this).hide();
|
||||||
});
|
});
|
||||||
val = $('option:selected', this).val();
|
|
||||||
|
|
||||||
if (val === 'ml-relative-reasoning' || val === 'rule-based-relative-reasoning') {
|
$('#model-type').selectpicker();
|
||||||
$("#package-based-relative-reasoning-specific-form").show();
|
$("#model-fingerprinter").selectpicker();
|
||||||
if (val === 'ml-relative-reasoning') {
|
$("#model-rule-packages").selectpicker();
|
||||||
$("#ml-relative-reasoning-specific-form").show();
|
$("#model-data-packages").selectpicker();
|
||||||
|
|
||||||
|
$("#build-app-domain").change(function () {
|
||||||
|
if ($(this).is(":checked")) {
|
||||||
|
$('#ad-params').show();
|
||||||
|
} else {
|
||||||
|
$('#ad-params').hide();
|
||||||
}
|
}
|
||||||
} else {
|
});
|
||||||
$("#" + val + "-specific-form").show();
|
|
||||||
}
|
// On change hide all and show only selected
|
||||||
|
$("#model-type").change(function () {
|
||||||
|
$('.ep-model-param').hide();
|
||||||
|
var modelType = $('#model-type').val();
|
||||||
|
if (nativeModelTypes.indexOf(modelType) !== -1) {
|
||||||
|
$('.' + modelType).show();
|
||||||
|
} else {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#new_model_modal_form_submit').on('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
$('#new_model_form').submit();
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#new_model_modal_form_submit').on('click', function(e){
|
|
||||||
e.preventDefault();
|
|
||||||
$('#new_model_form').submit();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -17,10 +17,10 @@
|
|||||||
For evaluation, you need to select the packages you want to use.
|
For evaluation, you need to select the packages you want to use.
|
||||||
While the model is evaluating, you can use the model for predictions.
|
While the model is evaluating, you can use the model for predictions.
|
||||||
</div>
|
</div>
|
||||||
<!-- Evaluation -->
|
<!-- Evaluation Packages -->
|
||||||
<label for="relative-reasoning-evaluation-packages">Evaluation Packages</label>
|
<label for="model-evaluation-packages">Evaluation Packages</label>
|
||||||
<select id="relative-reasoning-evaluation-packages" name=relative-reasoning-evaluation-packages"
|
<select id="model-evaluation-packages" name="model-evaluation-packages" data-actions-box='true'
|
||||||
data-actions-box='true' class="form-control" multiple data-width='100%'>
|
class="form-control" multiple data-width='100%'>
|
||||||
<option disabled>Reviewed Packages</option>
|
<option disabled>Reviewed Packages</option>
|
||||||
{% for obj in meta.readable_packages %}
|
{% for obj in meta.readable_packages %}
|
||||||
{% if obj.reviewed %}
|
{% if obj.reviewed %}
|
||||||
@ -35,7 +35,16 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<input type="hidden" name="hidden" value="evaluate">
|
|
||||||
|
<!-- Eval Type -->
|
||||||
|
<label for="model-evaluation-type">Evaluation Type</label>
|
||||||
|
<select id="model-evaluation-type" name="model-evaluation-type" class="form-control">
|
||||||
|
<option disabled selected>Select evaluation type</option>
|
||||||
|
<option value="sg">Single Generation</option>
|
||||||
|
<option value="mg">Multiple Generations</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<input type="hidden" name="hidden" value="evaluate">
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
@ -50,7 +59,7 @@
|
|||||||
|
|
||||||
$(function () {
|
$(function () {
|
||||||
|
|
||||||
$("#relative-reasoning-evaluation-packages").selectpicker();
|
$("#model-evaluation-packages").selectpicker();
|
||||||
|
|
||||||
$('#evaluate_model_form_submit').on('click', function (e) {
|
$('#evaluate_model_form_submit').on('click', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|||||||
@ -18,6 +18,7 @@
|
|||||||
<select id="scenario-select" name="selected-scenarios" data-actions-box='true' class="form-control"
|
<select id="scenario-select" name="selected-scenarios" data-actions-box='true' class="form-control"
|
||||||
multiple data-width='100%'>
|
multiple data-width='100%'>
|
||||||
<option disabled>Select Scenarios</option>
|
<option disabled>Select Scenarios</option>
|
||||||
|
<option value="" hidden></option>
|
||||||
</select>
|
</select>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -65,7 +66,7 @@
|
|||||||
$('#set_scenario_modal_form_submit').on('click', function (e) {
|
$('#set_scenario_modal_form_submit').on('click', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if ($('#scenario-select').val().length == 0) {
|
if ($('#scenario-select').val().length == 0) {
|
||||||
$('#scenario-select').val([''])
|
$('#scenario-select').val("")
|
||||||
}
|
}
|
||||||
$('#set_scenario_modal_form').submit();
|
$('#set_scenario_modal_form').submit();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -29,7 +29,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<p>
|
<p>
|
||||||
{{ rule.description }}
|
{{ rule.description|safe }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -87,19 +87,41 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<!-- EC Numbers -->
|
{% if rule.enzymelinks %}
|
||||||
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
<!-- EC Numbers -->
|
||||||
<h4 class="panel-title">
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
<a id="rule-ec-numbers-link" data-toggle="collapse" data-parent="#rule-detail"
|
<h4 class="panel-title">
|
||||||
href="#rule-ec-numbers">EC Numbers</a>
|
<a id="rule-ec-numbers-link" data-toggle="collapse" data-parent="#rule-detail"
|
||||||
</h4>
|
href="#rule-ec-numbers">EC Numbers</a>
|
||||||
</div>
|
</h4>
|
||||||
<div id="rule-ec-numbers" class="panel-collapse collapse">
|
|
||||||
<div class="panel-body list-group-item">
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div id="rule-ec-numbers" class="panel-collapse collapse in">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
{% for k, v in rule.get_grouped_enzymelinks.items %}
|
||||||
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="{{ k|slugify }}_Link" data-toggle="collapse"
|
||||||
|
data-parent="#{{ k|slugify }}_Accordion"
|
||||||
|
href="#{{ k|slugify }}">
|
||||||
|
{{ k }}
|
||||||
|
</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="{{ k|slugify }}" class="panel-collapse collapse in">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
{% for enzyme in v %}
|
||||||
|
<a class="list-group-item" href="{{ enzyme.url }}">
|
||||||
|
{{ enzyme.ec_number }}
|
||||||
|
<div style="position:absolute;bottom:10px;left:100px;">{{ enzyme.name }}</div>
|
||||||
|
<div style="float:right;">{{ enzyme.linking_method }}</div>
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@ -183,7 +183,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="compound-external-identifier" class="panel-collapse collapse in">
|
<div id="compound-external-identifier" class="panel-collapse collapse in">
|
||||||
<div class="panel-body list-group-item">
|
<div class="panel-body list-group-item">
|
||||||
{% if compound.get_pubchem_identifiers %}
|
{% if compound.get_pubchem_compound_identifiers %}
|
||||||
<div class="panel panel-default panel-heading list-group-item"
|
<div class="panel panel-default panel-heading list-group-item"
|
||||||
style="background-color:silver">
|
style="background-color:silver">
|
||||||
<h4 class="panel-title">
|
<h4 class="panel-title">
|
||||||
@ -193,12 +193,28 @@
|
|||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div id="compound-pubchem-identifier" class="panel-collapse collapse in">
|
<div id="compound-pubchem-identifier" class="panel-collapse collapse in">
|
||||||
{% for eid in compound.get_pubchem_identifiers %}
|
{% for eid in compound.get_pubchem_compound_identifiers %}
|
||||||
<a class="list-group-item"
|
<a class="list-group-item"
|
||||||
href="{{ eid.external_url }}">CID{{ eid.identifier_value }}</a>
|
href="{{ eid.external_url }}">CID{{ eid.identifier_value }}</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if compound.get_pubchem_substance_identifiers %}
|
||||||
|
<div class="panel panel-default panel-heading list-group-item"
|
||||||
|
style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="compound-pubchem-identifier-link" data-toggle="collapse"
|
||||||
|
data-parent="#compound-external-identifier"
|
||||||
|
href="#compound-pubchem-identifier">PubChem Substance Identifier</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="compound-pubchem-identifier" class="panel-collapse collapse in">
|
||||||
|
{% for eid in compound.get_pubchem_substance_identifiers %}
|
||||||
|
<a class="list-group-item"
|
||||||
|
href="{{ eid.external_url }}">SID{{ eid.identifier_value }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
{% if compound.get_chebi_identifiers %}
|
{% if compound.get_chebi_identifiers %}
|
||||||
<div class="panel panel-default panel-heading list-group-item"
|
<div class="panel panel-default panel-heading list-group-item"
|
||||||
style="background-color:silver">
|
style="background-color:silver">
|
||||||
|
|||||||
105
templates/objects/enzymelink.html
Normal file
105
templates/objects/enzymelink.html
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
{% extends "framework.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="panel-group" id="enzyme-detail">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px">
|
||||||
|
{{ enzymelink.ec_number }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Name -->
|
||||||
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="enzyme-name-link" data-toggle="collapse" data-parent="#enzyme-detail"
|
||||||
|
href="#enzyme-name">Enzyme Name</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="enzyme-name" class="panel-collapse collapse in">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
{{ enzymelink.name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Linking Method -->
|
||||||
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="enzyme-linking-link" data-toggle="collapse" data-parent="#enzyme-detail"
|
||||||
|
href="#enzyme-linking">Linking Method</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="enzyme-linking" class="panel-collapse collapse in">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
{{ enzymelink.linking_method }}. <a
|
||||||
|
href="https://wiki.envipath.org/index.php/Rules#EnzymeLinks" target="#">Learn more >></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if enzymelink.kegg_reaction_links %}
|
||||||
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="enzyme-evidence-link" data-toggle="collapse" data-parent="#enzyme-detail"
|
||||||
|
href="#enzyme-evidence">Linking Evidence</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="enzyme-evidence" class="panel-collapse collapse in">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
{% for kl in enzymelink.kegg_reaction_links %}
|
||||||
|
<a class="list-group-item"
|
||||||
|
href="{{ kl.external_url }}">{{ kl.identifier_value }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if enzymelink.reaction_evidence.all %}
|
||||||
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="enzyme-reaction-evidence-link" data-toggle="collapse" data-parent="#enzyme-detail"
|
||||||
|
href="#enzyme-reaction-evidence">Linking Evidence - enviPath Reactions</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="enzyme-reaction-evidence" class="panel-collapse collapse in">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
{% for r in enzymelink.reaction_evidence.all %}
|
||||||
|
<a class="list-group-item" href="{{ r.url }}">{{ r.name }} <i>({{ r.package.name }})</i></a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if enzymelink.edge_evidence.all %}
|
||||||
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="enzyme-edge-evidence-link" data-toggle="collapse" data-parent="#enzyme-detail"
|
||||||
|
href="#enzyme-edge-evidence">Linking Evidence - enviPath Pathways</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="enzyme-edge-evidence" class="panel-collapse collapse in">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
{% for e in enzymelink.edge_evidence.all %}
|
||||||
|
<a class="list-group-item" href="{{ e.pathway.url }}">{{ e.pathway.name }}
|
||||||
|
<i>({{ r.package.name }})</i></a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- External DB Reference -->
|
||||||
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="enzyme-external-identifier-link" data-toggle="collapse" data-parent="#enzyme-detail"
|
||||||
|
href="#enzyme-external-identifier">External DB References</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="enzyme-external-identifier" class="panel-collapse collapse in">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
<a class="list-group-item"
|
||||||
|
href="http://www.brenda-enzymes.org/enzyme.php?ecno={{ enzymelink.ec_number }}"
|
||||||
|
target="_blank"> Brenda entry for {{ enzymelink.ec_number }}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
||||||
@ -117,7 +117,7 @@
|
|||||||
<!-- End Predict Panel -->
|
<!-- End Predict Panel -->
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if model.app_domain %}
|
{% if model.ready_for_prediction and model.app_domain %}
|
||||||
<!-- App Domain -->
|
<!-- App Domain -->
|
||||||
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
<h4 class="panel-title">
|
<h4 class="panel-title">
|
||||||
|
|||||||
@ -177,9 +177,6 @@
|
|||||||
</nav>
|
</nav>
|
||||||
<div id="vizdiv" >
|
<div id="vizdiv" >
|
||||||
<svg id="pwsvg">
|
<svg id="pwsvg">
|
||||||
{% if debug %}
|
|
||||||
<rect width="100%" height="100%" fill="aliceblue"/>
|
|
||||||
{% endif %}
|
|
||||||
<defs>
|
<defs>
|
||||||
<marker id="arrow" viewBox="0 0 10 10" refX="43" refY="5" markerWidth="6" markerHeight="6"
|
<marker id="arrow" viewBox="0 0 10 10" refX="43" refY="5" markerWidth="6" markerHeight="6"
|
||||||
orient="auto-start-reverse" markerUnits="userSpaceOnUse">
|
orient="auto-start-reverse" markerUnits="userSpaceOnUse">
|
||||||
|
|||||||
@ -124,6 +124,23 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if reaction.get_related_enzymes %}
|
||||||
|
<!-- EC Numbers -->
|
||||||
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="rule-ec-numbers-link" data-toggle="collapse" data-parent="#rule-detail"
|
||||||
|
href="#rule-ec-numbers">EC Numbers</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="rule-ec-numbers" class="panel-collapse collapse in">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
{% for e in reaction.get_related_enzymes %}
|
||||||
|
<a class="list-group-item" href="http://www.brenda-enzymes.org/enzyme.php?ecno={{ e.ec_number }}">{{ e.name }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if reaction.related_pathways %}
|
{% if reaction.related_pathways %}
|
||||||
<!-- Pathways -->
|
<!-- Pathways -->
|
||||||
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
|||||||
@ -201,6 +201,43 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if rule.enzymelinks %}
|
||||||
|
<!-- EC Numbers -->
|
||||||
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="rule-ec-numbers-link" data-toggle="collapse" data-parent="#rule-detail"
|
||||||
|
href="#rule-ec-numbers">EC Numbers</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="rule-ec-numbers" class="panel-collapse collapse in">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
{% for k, v in rule.get_grouped_enzymelinks.items %}
|
||||||
|
<div class="panel panel-default panel-heading list-group-item"
|
||||||
|
style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="{{ k|slugify }}_Link" data-toggle="collapse"
|
||||||
|
data-parent="#{{ k|slugify }}_Accordion"
|
||||||
|
href="#{{ k|slugify }}">
|
||||||
|
{{ k }}
|
||||||
|
</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="{{ k|slugify }}" class="panel-collapse collapse in">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
{% for enzyme in v %}
|
||||||
|
<a class="list-group-item" href="{{ enzyme.url }}">
|
||||||
|
{{ enzyme.ec_number }}
|
||||||
|
<div style="position:absolute;bottom:10px;left:100px;">{{ enzyme.name }}</div>
|
||||||
|
<div style="float:right;">{{ enzyme.linking_method }}</div>
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@ -1,7 +1,27 @@
|
|||||||
|
from collections import defaultdict
|
||||||
|
from datetime import datetime
|
||||||
from tempfile import TemporaryDirectory
|
from tempfile import TemporaryDirectory
|
||||||
from django.test import TestCase, tag
|
from django.test import TestCase, tag
|
||||||
from epdb.logic import PackageManager
|
from epdb.logic import PackageManager
|
||||||
from epdb.models import User, EnviFormer, Package
|
from epdb.models import User, EnviFormer, Package, Setting
|
||||||
|
from epdb.tasks import predict_simple, predict
|
||||||
|
|
||||||
|
|
||||||
|
def measure_predict(mod, pathway_pk=None):
|
||||||
|
# Measure and return the prediction time
|
||||||
|
start = datetime.now()
|
||||||
|
if pathway_pk:
|
||||||
|
s = Setting()
|
||||||
|
s.model = mod
|
||||||
|
s.model_threshold = 0.2
|
||||||
|
s.max_depth = 4
|
||||||
|
s.max_nodes = 20
|
||||||
|
s.save()
|
||||||
|
pred_result = predict.delay(pathway_pk, s.pk, limit=s.max_depth)
|
||||||
|
else:
|
||||||
|
pred_result = predict_simple.delay(mod.pk, "C1=CC=C(CSCC2=CC=CC=C2)C=C1")
|
||||||
|
_ = pred_result.get()
|
||||||
|
return round((datetime.now() - start).total_seconds(), 2)
|
||||||
|
|
||||||
|
|
||||||
@tag("slow")
|
@tag("slow")
|
||||||
@ -28,8 +48,41 @@ class EnviFormerTest(TestCase):
|
|||||||
|
|
||||||
mod.build_dataset()
|
mod.build_dataset()
|
||||||
mod.build_model()
|
mod.build_model()
|
||||||
mod.multigen_eval = True
|
mod.evaluate_model(True, eval_packages_objs)
|
||||||
mod.save()
|
|
||||||
mod.evaluate_model()
|
|
||||||
|
|
||||||
mod.predict("CCN(CC)C(=O)C1=CC(=CC=C1)C")
|
mod.predict("CCN(CC)C(=O)C1=CC(=CC=C1)C")
|
||||||
|
|
||||||
|
def test_predict_runtime(self):
|
||||||
|
with TemporaryDirectory() as tmpdir:
|
||||||
|
with self.settings(MODEL_DIR=tmpdir):
|
||||||
|
threshold = float(0.5)
|
||||||
|
data_package_objs = [self.BBD_SUBSET]
|
||||||
|
eval_packages_objs = [self.BBD_SUBSET]
|
||||||
|
mods = []
|
||||||
|
for _ in range(4):
|
||||||
|
mod = EnviFormer.create(
|
||||||
|
self.package, data_package_objs, eval_packages_objs, threshold=threshold
|
||||||
|
)
|
||||||
|
mod.build_dataset()
|
||||||
|
mod.build_model()
|
||||||
|
mods.append(mod)
|
||||||
|
|
||||||
|
# Test prediction time drops after first prediction
|
||||||
|
times = [measure_predict(mods[0]) for _ in range(5)]
|
||||||
|
print(f"First prediction took {times[0]} seconds, subsequent ones took {times[1:]}")
|
||||||
|
|
||||||
|
# Test pathway prediction
|
||||||
|
times = [measure_predict(mods[1], self.BBD_SUBSET.pathways[0].pk) for _ in range(5)]
|
||||||
|
print(
|
||||||
|
f"First pathway prediction took {times[0]} seconds, subsequent ones took {times[1:]}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test eviction by performing three prediction with every model, twice.
|
||||||
|
times = defaultdict(list)
|
||||||
|
for _ in range(
|
||||||
|
2
|
||||||
|
): # Eviction should cause the second iteration here to have to reload the models
|
||||||
|
for mod in mods:
|
||||||
|
for _ in range(3):
|
||||||
|
times[mod.pk].append(measure_predict(mod))
|
||||||
|
print(times)
|
||||||
|
|||||||
@ -30,7 +30,6 @@ class ModelTest(TestCase):
|
|||||||
self.package,
|
self.package,
|
||||||
rule_package_objs,
|
rule_package_objs,
|
||||||
data_package_objs,
|
data_package_objs,
|
||||||
eval_packages_objs,
|
|
||||||
threshold=threshold,
|
threshold=threshold,
|
||||||
name="ECC - BBD - 0.5",
|
name="ECC - BBD - 0.5",
|
||||||
description="Created MLRelativeReasoning in Testcase",
|
description="Created MLRelativeReasoning in Testcase",
|
||||||
@ -50,9 +49,7 @@ class ModelTest(TestCase):
|
|||||||
|
|
||||||
mod.build_dataset()
|
mod.build_dataset()
|
||||||
mod.build_model()
|
mod.build_model()
|
||||||
mod.multigen_eval = True
|
mod.evaluate_model(True, eval_packages_objs)
|
||||||
mod.save()
|
|
||||||
mod.evaluate_model()
|
|
||||||
|
|
||||||
results = mod.predict("CCN(CC)C(=O)C1=CC(=CC=C1)C")
|
results = mod.predict("CCN(CC)C(=O)C1=CC(=CC=C1)C")
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ from epdb.logic import UserManager
|
|||||||
from epdb.models import Package, User
|
from epdb.models import Package, User
|
||||||
|
|
||||||
|
|
||||||
@override_settings(MODEL_DIR=s.FIXTURE_DIRS[0] / "models")
|
@override_settings(MODEL_DIR=s.FIXTURE_DIRS[0] / "models", CELERY_TASK_ALWAYS_EAGER=True)
|
||||||
class PathwayViewTest(TestCase):
|
class PathwayViewTest(TestCase):
|
||||||
fixtures = ["test_fixtures_incl_model.jsonl.gz"]
|
fixtures = ["test_fixtures_incl_model.jsonl.gz"]
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ from epdb.logic import UserManager, PackageManager
|
|||||||
from epdb.models import Pathway, Edge
|
from epdb.models import Pathway, Edge
|
||||||
|
|
||||||
|
|
||||||
@override_settings(MODEL_DIR=s.FIXTURE_DIRS[0] / "models")
|
@override_settings(MODEL_DIR=s.FIXTURE_DIRS[0] / "models", CELERY_TASK_ALWAYS_EAGER=True)
|
||||||
class PathwayViewTest(TestCase):
|
class PathwayViewTest(TestCase):
|
||||||
fixtures = ["test_fixtures_incl_model.jsonl.gz"]
|
fixtures = ["test_fixtures_incl_model.jsonl.gz"]
|
||||||
|
|
||||||
|
|||||||
@ -729,6 +729,7 @@ class IndigoUtils(object):
|
|||||||
height: int = 0,
|
height: int = 0,
|
||||||
educt_functional_groups: Dict[str, int] = None,
|
educt_functional_groups: Dict[str, int] = None,
|
||||||
product_functional_groups: Dict[str, int] = None,
|
product_functional_groups: Dict[str, int] = None,
|
||||||
|
debug: bool = False,
|
||||||
):
|
):
|
||||||
if educt_functional_groups is None:
|
if educt_functional_groups is None:
|
||||||
educt_functional_groups = {}
|
educt_functional_groups = {}
|
||||||
@ -739,6 +740,11 @@ class IndigoUtils(object):
|
|||||||
i = Indigo()
|
i = Indigo()
|
||||||
renderer = IndigoRenderer(i)
|
renderer = IndigoRenderer(i)
|
||||||
|
|
||||||
|
if debug:
|
||||||
|
i.setOption("render-atom-ids-visible", True)
|
||||||
|
i.setOption("render-bond-ids-visible", False)
|
||||||
|
i.setOption("render-atom-bond-ids-from-one", True)
|
||||||
|
|
||||||
i.setOption("render-output-format", "svg")
|
i.setOption("render-output-format", "svg")
|
||||||
i.setOption("render-coloring", True)
|
i.setOption("render-coloring", True)
|
||||||
i.setOption("render-image-size", width, height)
|
i.setOption("render-image-size", width, height)
|
||||||
|
|||||||
Reference in New Issue
Block a user