Implement drug refresh and view
This commit is contained in:
297
core/clients/sources/psychwiki.py
Normal file
297
core/clients/sources/psychwiki.py
Normal file
@@ -0,0 +1,297 @@
|
||||
from core.clients.base import BaseClient
|
||||
from core.clients.graphql import GraphQLClient
|
||||
from core.models import SEI, Dosage, Drug, Effect, Entry, Timing
|
||||
|
||||
|
||||
class PsychWikiClient(GraphQLClient, BaseClient):
|
||||
# url = "https://api.psychonautwiki.org"
|
||||
search_limit = 5000
|
||||
source_name = "Psychonaut Wiki GraphQL API"
|
||||
source_type = "DWIKI"
|
||||
source_endpoint = "https://api.psychonautwiki.org"
|
||||
source_score = 75
|
||||
|
||||
async def update_drugs(self):
|
||||
data = await self.get_all_data()
|
||||
self.store_data(data)
|
||||
return len(data)
|
||||
|
||||
def store_data(self, data):
|
||||
"""
|
||||
Store the data in the database.
|
||||
"""
|
||||
for drug in data["substances"]:
|
||||
try:
|
||||
drug_obj = Drug.objects.get(name=drug["name"])
|
||||
except Drug.DoesNotExist:
|
||||
drug_obj = Drug(name=drug["name"])
|
||||
|
||||
if "commonNames" in drug:
|
||||
if drug["commonNames"]:
|
||||
print("common names", drug["commonNames"])
|
||||
drug_obj.common_names = ",".join(drug["commonNames"])
|
||||
if "class" in drug:
|
||||
if drug["class"]:
|
||||
if "psychoactive" in drug["class"]:
|
||||
if drug["class"]["psychoactive"]:
|
||||
drug_obj.drug_class = ",".join(
|
||||
drug["class"]["psychoactive"]
|
||||
)
|
||||
try:
|
||||
entry = Entry.objects.get(source=self.source, url=drug["url"])
|
||||
except Entry.DoesNotExist:
|
||||
entry = Entry.objects.create(source=self.source, url=drug["url"])
|
||||
if not drug_obj.pk:
|
||||
drug_obj.save()
|
||||
if entry not in drug_obj.links.all():
|
||||
drug_obj.links.add(entry)
|
||||
if "roas" in drug:
|
||||
for roa in drug["roas"]:
|
||||
if "name" in roa:
|
||||
roa_name = roa["name"]
|
||||
|
||||
# Parsing dosage information
|
||||
dose = roa["dose"]
|
||||
|
||||
if dose:
|
||||
dosage_data = {
|
||||
"entry": entry,
|
||||
"roa": roa_name,
|
||||
"unit": dose["units"],
|
||||
}
|
||||
# Check and assign dosage values
|
||||
for dose_type in [
|
||||
"threshold",
|
||||
"light",
|
||||
"common",
|
||||
"strong",
|
||||
"heavy",
|
||||
]:
|
||||
if dose_type in dose:
|
||||
if isinstance(dose[dose_type], dict):
|
||||
dosage_data[f"{dose_type}_lower"] = dose[
|
||||
dose_type
|
||||
]["min"]
|
||||
dosage_data[f"{dose_type}_upper"] = dose[
|
||||
dose_type
|
||||
]["max"]
|
||||
else:
|
||||
dosage_data[f"{dose_type}_lower"] = dose[
|
||||
dose_type
|
||||
]
|
||||
dosage_data[f"{dose_type}_upper"] = dose[
|
||||
dose_type
|
||||
]
|
||||
|
||||
# Check if Dosage already exists and is linked to the Drug
|
||||
dosage, created = Dosage.objects.get_or_create(
|
||||
**dosage_data
|
||||
)
|
||||
if created or dosage not in drug_obj.dosages.all():
|
||||
drug_obj.dosages.add(dosage)
|
||||
|
||||
# Parsing timing information
|
||||
timing = roa["duration"]
|
||||
|
||||
print("TIMING", timing)
|
||||
# Check and assign timing values
|
||||
if timing:
|
||||
timing_data = {"entry": entry, "roa": roa_name}
|
||||
for time_type in [
|
||||
"onset",
|
||||
"comeup",
|
||||
"peak",
|
||||
"offset",
|
||||
"total",
|
||||
]:
|
||||
if (
|
||||
time_type in timing
|
||||
and timing[time_type] is not None
|
||||
):
|
||||
unit = timing[time_type].get("units", "hours")
|
||||
|
||||
# Handle case where timing value is a single integer
|
||||
if isinstance(timing[time_type], int):
|
||||
lower = timing[time_type]
|
||||
upper = None
|
||||
else:
|
||||
lower = timing[time_type].get("min")
|
||||
upper = timing[time_type].get("max")
|
||||
|
||||
if unit == "minutes" and lower is not None:
|
||||
lower = lower / 60.0
|
||||
if upper is not None:
|
||||
upper = upper / 60.0
|
||||
|
||||
timing_data[f"{time_type}_lower"] = lower
|
||||
timing_data[f"{time_type}_upper"] = upper
|
||||
timing_data[
|
||||
"unit"
|
||||
] = "HOURS" # Store all times in hours
|
||||
|
||||
# Check if Timing already exists and is linked to the Drug
|
||||
timing_obj, created = Timing.objects.get_or_create(
|
||||
**timing_data
|
||||
)
|
||||
if created or timing_obj not in drug_obj.timings.all():
|
||||
drug_obj.timings.add(timing_obj)
|
||||
if "effects" in drug:
|
||||
# Create or retrieve Effect object linked to the Entry
|
||||
effect_obj, effect_created = Effect.objects.get_or_create(entry=entry)
|
||||
|
||||
for effect in drug["effects"]:
|
||||
# Create or retrieve SEI object
|
||||
sei_obj, sei_created = SEI.objects.get_or_create(
|
||||
name=effect["name"],
|
||||
url=effect.get(
|
||||
"url", ""
|
||||
), # Using .get() to handle missing urls
|
||||
)
|
||||
|
||||
# Link SEI object to Effect if not already linked
|
||||
if (
|
||||
sei_created
|
||||
or sei_obj not in effect_obj.subjective_effects.all()
|
||||
):
|
||||
effect_obj.subjective_effects.add(sei_obj)
|
||||
# Link Effect object to Drug if not already linked
|
||||
if effect_created or effect_obj not in drug_obj.effects.all():
|
||||
drug_obj.effects.add(effect_obj)
|
||||
|
||||
print("SAVING DRUG", drug_obj)
|
||||
drug_obj.save()
|
||||
|
||||
async def get_drugs_list(self):
|
||||
"""
|
||||
Get all drug names from PsychWiki
|
||||
"""
|
||||
body = {"query": "{substances(limit: %i) {name}}" % self.search_limit}
|
||||
result = await self.call(
|
||||
"?",
|
||||
http_method="post",
|
||||
data=body,
|
||||
schema="GetDrugsList",
|
||||
append_slash=False,
|
||||
)
|
||||
print("RESULT", result)
|
||||
|
||||
return result["data"]
|
||||
|
||||
async def get_all_data(self):
|
||||
"""
|
||||
Get all the drug data from PsychWiki (warning - intensive)
|
||||
"""
|
||||
body = {
|
||||
"query": """
|
||||
{
|
||||
substances(limit: %i) {
|
||||
name
|
||||
url
|
||||
featured
|
||||
summary
|
||||
addictionPotential
|
||||
toxicity
|
||||
crossTolerances
|
||||
commonNames
|
||||
class {
|
||||
chemical
|
||||
psychoactive
|
||||
}
|
||||
tolerance {
|
||||
full
|
||||
half
|
||||
zero
|
||||
}
|
||||
roas {
|
||||
name
|
||||
dose {
|
||||
units
|
||||
threshold
|
||||
heavy
|
||||
common {
|
||||
min
|
||||
max
|
||||
}
|
||||
light {
|
||||
min
|
||||
max
|
||||
}
|
||||
strong {
|
||||
min
|
||||
max
|
||||
}
|
||||
}
|
||||
duration {
|
||||
afterglow {
|
||||
min
|
||||
max
|
||||
units
|
||||
}
|
||||
comeup {
|
||||
min
|
||||
max
|
||||
units
|
||||
}
|
||||
duration {
|
||||
min
|
||||
max
|
||||
units
|
||||
}
|
||||
offset {
|
||||
min
|
||||
max
|
||||
units
|
||||
}
|
||||
onset {
|
||||
min
|
||||
max
|
||||
units
|
||||
}
|
||||
peak {
|
||||
min
|
||||
max
|
||||
units
|
||||
}
|
||||
total {
|
||||
min
|
||||
max
|
||||
units
|
||||
}
|
||||
}
|
||||
bioavailability {
|
||||
min
|
||||
max
|
||||
}
|
||||
}
|
||||
effects {
|
||||
name
|
||||
url
|
||||
}
|
||||
images {
|
||||
thumb
|
||||
image
|
||||
}
|
||||
uncertainInteractions {
|
||||
name
|
||||
}
|
||||
unsafeInteractions {
|
||||
name
|
||||
}
|
||||
dangerousInteractions {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"""
|
||||
% self.search_limit
|
||||
}
|
||||
result = await self.call(
|
||||
"?",
|
||||
http_method="post",
|
||||
data=body,
|
||||
schema="GetDrugsList",
|
||||
append_slash=False,
|
||||
)
|
||||
|
||||
return result["data"]
|
||||
Reference in New Issue
Block a user