File size: 11,046 Bytes
09db53f
 
 
1e0350f
 
09db53f
1e0350f
09db53f
 
 
1e0350f
 
 
 
09db53f
 
1e0350f
09db53f
 
 
 
 
1e0350f
85e6b5b
09db53f
 
 
 
1e0350f
 
09db53f
1e0350f
09db53f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1e0350f
09db53f
 
 
 
1e0350f
09db53f
1e0350f
09db53f
1e0350f
d576bd9
a1bb249
09db53f
1e0350f
09db53f
1e0350f
09db53f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1e0350f
 
09db53f
1e0350f
09db53f
1e0350f
09db53f
 
 
 
 
85e6b5b
 
09db53f
85e6b5b
1e0350f
09db53f
1e0350f
09db53f
1e0350f
09db53f
1e0350f
09db53f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1e0350f
09db53f
 
 
 
 
 
 
1e0350f
09db53f
1e0350f
09db53f
 
 
 
 
85e6b5b
 
1e0350f
09db53f
1e0350f
 
 
 
 
 
09db53f
 
1e0350f
 
 
 
 
09db53f
1e0350f
09db53f
 
1e0350f
 
 
 
 
09db53f
1e0350f
09db53f
 
 
 
85e6b5b
09db53f
 
 
 
1e0350f
 
09db53f
1e0350f
09db53f
 
1e0350f
 
09db53f
1e0350f
09db53f
1e0350f
09db53f
1e0350f
09db53f
 
 
1e0350f
09db53f
1e0350f
09db53f
 
 
 
 
 
 
 
 
a1bb249
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# Drug Repurposing Advisor: A Multi-Agent Workflow Example
# This example uses dummy data for demonstration.
# In a production system, replace the dummy data with real pharmaceutical databases.

import os
import json
import requests
import streamlit as st
from typing import List, Union, Tuple
from langchain_core.messages import HumanMessage, AIMessage, ToolMessage
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langgraph.graph import END, StateGraph, START
from langgraph.prebuilt import ToolNode
from langgraph.graph.message import add_messages
from typing_extensions import TypedDict, Annotated
from typing import Sequence

# Dummy data for drug mechanism research and clinical trial outcomes
drug_mechanism_texts = [
    "Drug A: Inhibits enzyme X and modulates receptor Y; potential anti-inflammatory effects.",
    "Drug B: Blocks ion channel Z; has been shown to reduce oxidative stress in preclinical models.",
    "Drug C: Activates nuclear receptor W; exhibits neuroprotective properties."
]

clinical_trials_texts = [
    "Trial 1: Drug A repurposed for rheumatoid arthritis showed a 30% improvement in joint function.",
    "Trial 2: Drug B evaluated in a pilot study for neurodegenerative disorders demonstrated a reduction in symptom severity.",
    "Trial 3: Drug C tested in a phase II trial for multiple sclerosis reported significant reduction in relapse rates."
]

# Text splitting settings
splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=10)
mechanism_docs = splitter.create_documents(drug_mechanism_texts)
clinical_docs = splitter.create_documents(clinical_trials_texts)

# Here you would typically create vector embeddings and vectorstores (e.g., using ChromaDB)
# For demonstration, we define simple retriever functions that return dummy results.
def mechanism_retriever(query: str) -> str:
    # Dummy search: return first document that mentions a keyword from the query
    for doc in drug_mechanism_texts:
        if any(word.lower() in doc.lower() for word in query.split()):
            return f"[Mechanism Doc]: {doc}"
    return "No relevant mechanism data found."

def clinical_retriever(query: str) -> str:
    for doc in clinical_trials_texts:
        if any(word.lower() in doc.lower() for word in query.split()):
            return f"[Clinical Trial Doc]: {doc}"
    return "No relevant clinical trial data found."

# Define tools using a simple wrapper function
def create_retriever_tool(retriever_func, tool_name: str, description: str):
    def tool(query: str):
        return retriever_func(query)
    # Mimic a tool message (in a real system, you would wrap this in a ToolMessage object)
    tool.__name__ = tool_name
    tool.description = description
    return tool

mechanism_tool = create_retriever_tool(
    mechanism_retriever,
    "mechanism_db_tool",
    "Search drug mechanism data for repurposing insights."
)
clinical_tool = create_retriever_tool(
    clinical_retriever,
    "clinical_db_tool",
    "Search clinical trial outcomes for repurposing evidence."
)
tools = [mechanism_tool, clinical_tool]

# Define the AgentState type for our workflow
class AgentState(TypedDict):
    messages: Annotated[Sequence[AIMessage | HumanMessage | ToolMessage], add_messages]

# Agent function: Classifies queries as targeting drug mechanisms or clinical outcomes
def agent(state: AgentState):
    print("---CALL AGENT---")
    messages = state["messages"]
    user_message = messages[0].content if not isinstance(messages[0], tuple) else messages[0][1]

    # Build a prompt to classify the query
    prompt = f"""Given the user question: "{user_message}"
If the question is about the molecular mechanism or pharmacodynamics, respond EXACTLY in this format:
SEARCH_MECHANISM: <search terms>

If it's about clinical trial outcomes, efficacy, or safety evidence, respond EXACTLY in this format:
SEARCH_CLINICAL: <search terms>

Otherwise, answer directly with general repurposing insights.
    """
    # (Here we simulate a call to DeepSeek-R1 using a dummy response)
    # In a real implementation, make an API call to DeepSeek-R1.
    if "mechanism" in user_message.lower() or "how it works" in user_message.lower():
        response_text = f"SEARCH_MECHANISM: {user_message}"
    elif "trial" in user_message.lower() or "efficacy" in user_message.lower() or "safety" in user_message.lower():
        response_text = f"SEARCH_CLINICAL: {user_message}"
    else:
        response_text = "The system did not classify your query. Please rephrase to focus on drug mechanism or clinical data."
    
    print("Agent response:", response_text)
    # Format response into expected tool call format
    if "SEARCH_MECHANISM:" in response_text:
        query = response_text.split("SEARCH_MECHANISM:")[1].strip()
        result = mechanism_tool(query)
        return {"messages": [AIMessage(content=f'Action: mechanism_db_tool\n{{"query": "{query}"}}\n\nResults: {result}')]}

    elif "SEARCH_CLINICAL:" in response_text:
        query = response_text.split("SEARCH_CLINICAL:")[1].strip()
        result = clinical_tool(query)
        return {"messages": [AIMessage(content=f'Action: clinical_db_tool\n{{"query": "{query}"}}\n\nResults: {result}')]}

    else:
        return {"messages": [AIMessage(content=response_text)]}

# Grading function: Checks if retrieved documents were found
def simple_grade_documents(state: AgentState):
    messages = state["messages"]
    last_message = messages[-1]
    print("Evaluating message:", last_message.content)
    if "Results:" in last_message.content and "No relevant" not in last_message.content:
        print("---DATA FOUND, PROCEED TO GENERATE INSIGHTS---")
        return "generate"
    else:
        print("---NO DATA FOUND, TRY REWRITE---")
        return "rewrite"

# Generate function: Synthesizes repurposing insights from retrieved data
def generate(state: AgentState):
    print("---GENERATE FINAL INSIGHTS---")
    messages = state["messages"]
    question = messages[0].content
    last_message = messages[-1]
    # Extract data from results
    data_start = last_message.content.find("Results:")
    retrieved_data = last_message.content[data_start:] if data_start != -1 else "No data available"
    # Build a prompt to synthesize insights
    prompt = f"""Based on the following retrieved data:
    {retrieved_data}
and considering the question:
    {question}
Summarize potential drug repurposing opportunities and any recommended next steps for further investigation.
    """
    # Dummy generation using a simple echo for demonstration.
    final_answer = f"Summary Insight: Considering the data, a promising repurposing opportunity is to explore Drug A for anti-inflammatory applications beyond its original use, and Drug B might be repurposed for neurodegenerative conditions. Further research should validate these hypotheses."
    print("Final Answer:", final_answer)
    return {"messages": [AIMessage(content=final_answer)]}

# Rewrite function: If no data is found, help rephrase the query for clarity
def rewrite(state: AgentState):
    print("---REWRITE QUESTION---")
    messages = state["messages"]
    original_question = messages[0].content if messages else "N/A"
    # Dummy rewrite that just appends "Please specify mechanism or trial data" for demonstration.
    rewritten = f"{original_question} (Please specify if you are asking about drug mechanism or clinical trial outcomes.)"
    print("Rewritten question:", rewritten)
    return {"messages": [AIMessage(content=rewritten)]}

# Decision function: Determines next step based on last message content
def custom_tools_condition(state: AgentState):
    messages = state["messages"]
    last_message = messages[-1]
    content = last_message.content
    if content.startswith("Action:"):
        print("Tool action detected. Proceed to retrieval.")
        return "tools"
    return END

# Create the workflow graph
workflow = StateGraph(AgentState)
workflow.add_node("agent", agent)
retrieve_node = ToolNode(tools)
workflow.add_node("retrieve", retrieve_node)
workflow.add_node("rewrite", rewrite)
workflow.add_node("generate", generate)

# Define workflow edges
workflow.add_edge(START, "agent")
workflow.add_conditional_edges("agent", custom_tools_condition, {"tools": "retrieve", END: END})
workflow.add_conditional_edges("retrieve", simple_grade_documents)
workflow.add_edge("generate", END)
workflow.add_edge("rewrite", "agent")
app = workflow.compile()

# Function to process a query through the workflow
def process_question(user_question: str, app, config: dict):
    events = []
    for event in app.stream({"messages": [("user", user_question)]}, config):
        events.append(event)
    return events

# Streamlit UI for the Drug Repurposing Advisor
def main():
    st.set_page_config(
        page_title="Drug Repurposing Advisor",
        layout="wide",
        initial_sidebar_state="expanded"
    )
    st.title("πŸ’Š Drug Repurposing Advisor")
    st.markdown("### Explore potential drug repurposing opportunities with AI-driven insights.")
    query = st.text_area("Enter your research question:",
                          placeholder="e.g., Can Drug A be repurposed for neurodegenerative diseases?")
    col1, col2 = st.columns([1, 2])
    with col1:
        if st.button("πŸ” Get Insights", use_container_width=True):
            if query:
                with st.spinner("Processing your query..."):
                    events = process_question(query, app, {"configurable": {"thread_id": "1"}})
                    for event in events:
                        if 'agent' in event:
                            with st.expander("Agent Processing Step", expanded=True):
                                content = event['agent']['messages'][0].content
                                st.markdown(f"**Agent Step Output:**\n\n{content}")
                        elif 'generate' in event:
                            st.markdown("### Final Insights:")
                            st.success(event['generate']['messages'][0].content)
                        elif 'rewrite' in event:
                            st.markdown("### Suggestion:")
                            st.warning(event['rewrite']['messages'][0].content)
            else:
                st.warning("⚠️ Please enter a query.")
    with col2:
        st.markdown("""
        **How to Use the Drug Repurposing Advisor:**
        1. **Input Query:** Describe your research question. Specify whether you are interested in drug mechanisms or clinical outcomes.
        2. **Get Insights:** Click "Get Insights" and let the system process your query.
        3. **Review Output:** Explore the retrieved data and the final synthesized insights.
        **Example Questions:**
        - "How does Drug A work and could its mechanism be useful in treating inflammatory diseases?"
        - "What are the clinical trial outcomes of Drug B and can it be repurposed for neurodegenerative conditions?"
        """)
if __name__ == "__main__":
    main()