Update app.py
Browse files
app.py
CHANGED
@@ -29,7 +29,7 @@ API_ENDPOINTS = {
|
|
29 |
"pubmed": "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi",
|
30 |
"fda_drug_approval": "https://api.fda.gov/drug/label.json",
|
31 |
"faers_adverse_events": "https://api.fda.gov/drug/event.json",
|
32 |
-
# PharmGKB endpoints (
|
33 |
"pharmgkb_variant_clinical_annotations": "https://api.pharmgkb.org/v1/data/variant/{}/clinicalAnnotations",
|
34 |
"pharmgkb_gene": "https://api.pharmgkb.org/v1/data/gene/{}",
|
35 |
"pharmgkb_gene_variants": "https://api.pharmgkb.org/v1/data/gene/{}/variants",
|
@@ -37,7 +37,7 @@ API_ENDPOINTS = {
|
|
37 |
# RxNorm endpoints
|
38 |
"rxnorm_rxcui": "https://rxnav.nlm.nih.gov/REST/rxcui.json",
|
39 |
"rxnorm_properties": "https://rxnav.nlm.nih.gov/REST/rxcui/{}/properties.json",
|
40 |
-
# RxClass endpoint
|
41 |
"rxclass_by_drug": "https://rxnav.nlm.nih.gov/REST/class/byDrugName.json"
|
42 |
}
|
43 |
|
@@ -123,20 +123,19 @@ def _draw_molecule(smiles: str) -> Optional[Any]:
|
|
123 |
return None
|
124 |
|
125 |
def _get_pubchem_drug_details(drug_name: str) -> Optional[Dict[str, str]]:
|
126 |
-
"""Retrieves drug details
|
127 |
url = API_ENDPOINTS["pubchem"].format(drug_name)
|
128 |
data = _query_api(url)
|
|
|
129 |
if data and data.get("PC_Compounds"):
|
130 |
compound = data["PC_Compounds"][0]
|
131 |
-
details = {}
|
132 |
for prop in compound.get("props", []):
|
133 |
urn = prop.get("urn", {})
|
134 |
if urn.get("label") == "Molecular Formula":
|
135 |
details["Molecular Formula"] = prop["value"]["sval"]
|
136 |
-
|
137 |
-
# Use Preferred IUPAC name if available
|
138 |
details["IUPAC Name"] = prop["value"]["sval"]
|
139 |
-
|
140 |
details["Canonical SMILES"] = prop["value"]["sval"]
|
141 |
return details
|
142 |
return None
|
@@ -335,30 +334,65 @@ def get_rxclass_by_drug_name(drug_name: str) -> Optional[Dict]:
|
|
335 |
return _query_api(url)
|
336 |
|
337 |
# -----------------------------
|
338 |
-
# New Function:
|
339 |
# -----------------------------
|
340 |
-
def
|
341 |
-
"""
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
if
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
357 |
|
358 |
# -----------------------------
|
359 |
# Streamlit App Layout and Tabs
|
360 |
# -----------------------------
|
361 |
-
# Define tabs including a new "Drug Data Integration" tab.
|
362 |
tabs = st.tabs([
|
363 |
"π Drug Development",
|
364 |
"π Trial Analytics",
|
@@ -366,7 +400,8 @@ tabs = st.tabs([
|
|
366 |
"π Regulatory Intelligence",
|
367 |
"π Literature Search",
|
368 |
"π Dashboard",
|
369 |
-
"π§ͺ Drug Data Integration"
|
|
|
370 |
])
|
371 |
|
372 |
# -----------------------------
|
@@ -505,7 +540,7 @@ with tabs[2]:
|
|
505 |
# -----------------------------
|
506 |
with tabs[3]:
|
507 |
st.header("Global Regulatory Monitoring")
|
508 |
-
st.markdown("**Note:** EMA, WHO, and DailyMed
|
509 |
drug_name = st.text_input("Drug Product:", placeholder="Enter generic or brand name")
|
510 |
|
511 |
if st.button("Generate Regulatory Report"):
|
@@ -521,27 +556,27 @@ with tabs[3]:
|
|
521 |
if pubchem_details:
|
522 |
formula = pubchem_details.get("Molecular Formula", "N/A")
|
523 |
iupac = pubchem_details.get("IUPAC Name", "N/A")
|
524 |
-
|
525 |
else:
|
526 |
-
formula = iupac =
|
527 |
|
528 |
-
st.subheader("Regulatory Status")
|
529 |
col1, col2 = st.columns(2)
|
530 |
with col1:
|
531 |
st.markdown("**FDA Status**")
|
532 |
st.write(fda_status)
|
533 |
with col2:
|
534 |
-
st.markdown("**
|
535 |
st.write(f"**Molecular Formula:** {formula}")
|
536 |
st.write(f"**IUPAC Name:** {iupac}")
|
537 |
-
st.write(f"**Canonical SMILES:** {
|
538 |
|
539 |
regulatory_content = (
|
540 |
-
f"### Regulatory Report\n\n"
|
541 |
f"**FDA Status:** {fda_status}\n\n"
|
542 |
f"**Molecular Formula:** {formula}\n\n"
|
543 |
f"**IUPAC Name:** {iupac}\n\n"
|
544 |
-
f"**Canonical SMILES:** {
|
545 |
)
|
546 |
with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp_file:
|
547 |
report_file = _save_pdf_report(regulatory_content, tmp_file.name)
|
@@ -595,8 +630,6 @@ with tabs[5]:
|
|
595 |
|
596 |
# Placeholder KPI counts (replace with real aggregated data if available)
|
597 |
fda_count = 5000 # Example value
|
598 |
-
ema_count = 3000 # Example value (not used now)
|
599 |
-
who_count = 1500 # Example value (not used now)
|
600 |
trials_count = 12000 # Example value
|
601 |
pub_count = 250000 # Example value
|
602 |
|
@@ -666,7 +699,7 @@ with tabs[6]:
|
|
666 |
else:
|
667 |
st.write("No RxClass data found for the given drug.")
|
668 |
|
669 |
-
#
|
670 |
pubchem_details = _get_pubchem_drug_details(drug_query)
|
671 |
st.subheader("PubChem Drug Details")
|
672 |
if pubchem_details:
|
@@ -676,4 +709,16 @@ with tabs[6]:
|
|
676 |
else:
|
677 |
st.write("No PubChem details found for the given drug.")
|
678 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
679 |
|
|
|
29 |
"pubmed": "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi",
|
30 |
"fda_drug_approval": "https://api.fda.gov/drug/label.json",
|
31 |
"faers_adverse_events": "https://api.fda.gov/drug/event.json",
|
32 |
+
# PharmGKB endpoints (expecting a PharmGKB accession, e.g. PA1234)
|
33 |
"pharmgkb_variant_clinical_annotations": "https://api.pharmgkb.org/v1/data/variant/{}/clinicalAnnotations",
|
34 |
"pharmgkb_gene": "https://api.pharmgkb.org/v1/data/gene/{}",
|
35 |
"pharmgkb_gene_variants": "https://api.pharmgkb.org/v1/data/gene/{}/variants",
|
|
|
37 |
# RxNorm endpoints
|
38 |
"rxnorm_rxcui": "https://rxnav.nlm.nih.gov/REST/rxcui.json",
|
39 |
"rxnorm_properties": "https://rxnav.nlm.nih.gov/REST/rxcui/{}/properties.json",
|
40 |
+
# RxClass endpoint
|
41 |
"rxclass_by_drug": "https://rxnav.nlm.nih.gov/REST/class/byDrugName.json"
|
42 |
}
|
43 |
|
|
|
123 |
return None
|
124 |
|
125 |
def _get_pubchem_drug_details(drug_name: str) -> Optional[Dict[str, str]]:
|
126 |
+
"""Retrieves generic drug details (molecular formula, IUPAC name, and canonical SMILES) from PubChem."""
|
127 |
url = API_ENDPOINTS["pubchem"].format(drug_name)
|
128 |
data = _query_api(url)
|
129 |
+
details = {}
|
130 |
if data and data.get("PC_Compounds"):
|
131 |
compound = data["PC_Compounds"][0]
|
|
|
132 |
for prop in compound.get("props", []):
|
133 |
urn = prop.get("urn", {})
|
134 |
if urn.get("label") == "Molecular Formula":
|
135 |
details["Molecular Formula"] = prop["value"]["sval"]
|
136 |
+
if urn.get("name") == "Preferred":
|
|
|
137 |
details["IUPAC Name"] = prop["value"]["sval"]
|
138 |
+
if prop.get("name") == "Canonical SMILES":
|
139 |
details["Canonical SMILES"] = prop["value"]["sval"]
|
140 |
return details
|
141 |
return None
|
|
|
334 |
return _query_api(url)
|
335 |
|
336 |
# -----------------------------
|
337 |
+
# New Function: Generate AI Insights for a Drug
|
338 |
# -----------------------------
|
339 |
+
def generate_drug_insights(drug_name: str) -> str:
|
340 |
+
"""Gathers FDA, PubChem, RxNorm, and RxClass data for a drug and uses GPTβ4 to generate innovative insights."""
|
341 |
+
# FDA Data
|
342 |
+
fda_info = _get_fda_approval(drug_name)
|
343 |
+
fda_status = "Not Approved"
|
344 |
+
if fda_info and fda_info.get("openfda", {}).get("brand_name"):
|
345 |
+
fda_status = ", ".join(fda_info["openfda"]["brand_name"])
|
346 |
+
|
347 |
+
# PubChem Details
|
348 |
+
pubchem_details = _get_pubchem_drug_details(drug_name)
|
349 |
+
if pubchem_details:
|
350 |
+
formula = pubchem_details.get("Molecular Formula", "N/A")
|
351 |
+
iupac = pubchem_details.get("IUPAC Name", "N/A")
|
352 |
+
canonical_smiles = pubchem_details.get("Canonical SMILES", "N/A")
|
353 |
+
else:
|
354 |
+
formula = iupac = canonical_smiles = "Not Available"
|
355 |
+
|
356 |
+
# RxNorm Data
|
357 |
+
rxnorm_id = get_rxnorm_rxcui(drug_name)
|
358 |
+
if rxnorm_id:
|
359 |
+
rx_properties = get_rxnorm_properties(rxnorm_id)
|
360 |
+
rxnorm_info = f"RxCUI: {rxnorm_id}. Properties: {rx_properties}"
|
361 |
+
else:
|
362 |
+
rxnorm_info = "No RxNorm data available."
|
363 |
+
|
364 |
+
# RxClass Data
|
365 |
+
rxclass_data = get_rxclass_by_drug_name(drug_name)
|
366 |
+
if rxclass_data and rxclass_data.get("classMember"):
|
367 |
+
rxclass_info = f"RxClass: {rxclass_data}"
|
368 |
+
else:
|
369 |
+
rxclass_info = "No RxClass data available."
|
370 |
+
|
371 |
+
# Construct prompt for GPTβ4 with all the gathered data
|
372 |
+
prompt = (
|
373 |
+
f"Drug Analysis Report for '{drug_name}':\n\n"
|
374 |
+
f"**FDA Approval Status:** {fda_status}\n\n"
|
375 |
+
f"**PubChem Details:**\n"
|
376 |
+
f" - Molecular Formula: {formula}\n"
|
377 |
+
f" - IUPAC Name: {iupac}\n"
|
378 |
+
f" - Canonical SMILES: {canonical_smiles}\n\n"
|
379 |
+
f"**RxNorm Data:** {rxnorm_info}\n\n"
|
380 |
+
f"**RxClass Data:** {rxclass_info}\n\n"
|
381 |
+
f"As an advanced pharmacogenomics researcher and AI expert, please provide an innovative and comprehensive analysis of "
|
382 |
+
f"the drug '{drug_name}'. In your response, include:\n"
|
383 |
+
f"- Pharmacogenomic considerations\n"
|
384 |
+
f"- Potential repurposing opportunities\n"
|
385 |
+
f"- Regulatory insights and challenges\n"
|
386 |
+
f"- Suggestions for further research and data integration\n\n"
|
387 |
+
f"Present your answer in a clear, bullet-point format and feel free to add any novel ideas."
|
388 |
+
)
|
389 |
+
|
390 |
+
insights = generate_content(prompt)
|
391 |
+
return insights
|
392 |
|
393 |
# -----------------------------
|
394 |
# Streamlit App Layout and Tabs
|
395 |
# -----------------------------
|
|
|
396 |
tabs = st.tabs([
|
397 |
"π Drug Development",
|
398 |
"π Trial Analytics",
|
|
|
400 |
"π Regulatory Intelligence",
|
401 |
"π Literature Search",
|
402 |
"π Dashboard",
|
403 |
+
"π§ͺ Drug Data Integration",
|
404 |
+
"π€ AI Insights"
|
405 |
])
|
406 |
|
407 |
# -----------------------------
|
|
|
540 |
# -----------------------------
|
541 |
with tabs[3]:
|
542 |
st.header("Global Regulatory Monitoring")
|
543 |
+
st.markdown("**Note:** Due to persistent issues with EMA, WHO, and DailyMed APIs, this section now focuses on FDA data and generic drug details from PubChem.")
|
544 |
drug_name = st.text_input("Drug Product:", placeholder="Enter generic or brand name")
|
545 |
|
546 |
if st.button("Generate Regulatory Report"):
|
|
|
556 |
if pubchem_details:
|
557 |
formula = pubchem_details.get("Molecular Formula", "N/A")
|
558 |
iupac = pubchem_details.get("IUPAC Name", "N/A")
|
559 |
+
canonical_smiles = pubchem_details.get("Canonical SMILES", "N/A")
|
560 |
else:
|
561 |
+
formula = iupac = canonical_smiles = "Not Available"
|
562 |
|
563 |
+
st.subheader("Regulatory Status & Drug Details")
|
564 |
col1, col2 = st.columns(2)
|
565 |
with col1:
|
566 |
st.markdown("**FDA Status**")
|
567 |
st.write(fda_status)
|
568 |
with col2:
|
569 |
+
st.markdown("**Drug Details (PubChem)**")
|
570 |
st.write(f"**Molecular Formula:** {formula}")
|
571 |
st.write(f"**IUPAC Name:** {iupac}")
|
572 |
+
st.write(f"**Canonical SMILES:** {canonical_smiles}")
|
573 |
|
574 |
regulatory_content = (
|
575 |
+
f"### Regulatory Report for {drug_name}\n\n"
|
576 |
f"**FDA Status:** {fda_status}\n\n"
|
577 |
f"**Molecular Formula:** {formula}\n\n"
|
578 |
f"**IUPAC Name:** {iupac}\n\n"
|
579 |
+
f"**Canonical SMILES:** {canonical_smiles}\n"
|
580 |
)
|
581 |
with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp_file:
|
582 |
report_file = _save_pdf_report(regulatory_content, tmp_file.name)
|
|
|
630 |
|
631 |
# Placeholder KPI counts (replace with real aggregated data if available)
|
632 |
fda_count = 5000 # Example value
|
|
|
|
|
633 |
trials_count = 12000 # Example value
|
634 |
pub_count = 250000 # Example value
|
635 |
|
|
|
699 |
else:
|
700 |
st.write("No RxClass data found for the given drug.")
|
701 |
|
702 |
+
# PubChem Drug Details for generic information
|
703 |
pubchem_details = _get_pubchem_drug_details(drug_query)
|
704 |
st.subheader("PubChem Drug Details")
|
705 |
if pubchem_details:
|
|
|
709 |
else:
|
710 |
st.write("No PubChem details found for the given drug.")
|
711 |
|
712 |
+
# -----------------------------
|
713 |
+
# Tab 8: AI Insights
|
714 |
+
# -----------------------------
|
715 |
+
with tabs[7]:
|
716 |
+
st.header("π€ AI Insights")
|
717 |
+
ai_drug_query = st.text_input("Enter Drug Name for AI-Driven Analysis:", placeholder="e.g., aspirin")
|
718 |
+
if st.button("Generate AI Insights"):
|
719 |
+
with st.spinner("Generating AI insights..."):
|
720 |
+
insights = generate_drug_insights(ai_drug_query)
|
721 |
+
st.subheader("AI-Driven Drug Analysis")
|
722 |
+
st.markdown(insights)
|
723 |
+
|
724 |
|