File size: 5,190 Bytes
b731d10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
from pydantic.v1 import BaseModel, Field
from langchain.tools import tool
import requests
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.agents.output_parsers import OpenAIFunctionsAgentOutputParser
from langchain.schema.agent import AgentFinish
from langchain.schema.runnable import RunnablePassthrough
from langchain.agents import AgentExecutor
from langchain.schema.output_parser import StrOutputParser
from langchain.schema.runnable import RunnableMap
from langchain.prompts import MessagesPlaceholder
from langchain.tools.render import format_tool_to_openai_function
from langchain.agents.format_scratchpad import format_to_openai_functions
from langchain.memory import ConversationBufferMemory
from dotenv import load_dotenv, find_dotenv
import openai
import os 
import gradio as gr



_ = load_dotenv(find_dotenv()) # read local .env file
openai.api_key = os.environ['OPENAI_API_KEY']
model_name = 'gpt-4-1106-preview'
model = ChatOpenAI(temperature=0, model='gpt-4-1106-preview')
output_parser = StrOutputParser()


def invoke_llm(query, context, template):
    prompt = ChatPromptTemplate.from_template(template)
    chain = prompt | model | output_parser
    return chain.invoke({"query": query, "context": context})


class SearchInput(BaseModel):
    medical_condition: str = Field(..., description="The medical condition to base the search on.")
    address: str = Field(..., description="The address or location to consider for proximity in the search.")

@tool(args_schema=SearchInput)
def search_healthcare_professionals(medical_condition: str, address: str) -> str:
    """
    Search for healthcare professionals details based on their relevance to a specified medical condition 
    and proximity to a given address. Results are approximate and based on available data.
    """
    BASE_URL = "http://localhost:8000/filter_by_address"
    
    # Parameters for the request
    params = {
        'address': address,
    }

    response = requests.get(BASE_URL, params=params)

    if response.status_code == 200:
        results = response.json()
    else:
        raise Exception(f"API Request failed with status code: {response.status_code}")

    # Part 2: Use LLM
    template = """ You are a medical expert and have been provided with a list of healthcare professionals 
    along with their details including title, name, specialization, experience, 
    company, address, and distance. The data is as follows:
    
    {context}

    Query: I am seeking healthcare professionals who specialize in {query}. Based
    on the provided data, please rank these professionals according to the relevance
    of their specialization to the medical condition and their distance as mentioned
    in the data. Provide a ranked tabular comparison, including their title, name,
    specialization, experience, company, address, and distance."""
    
    context = "Results from the database (within 10km):\n{df}".format(df=results)
    
    results = invoke_llm(query=medical_condition, context=context, template=template)
    return results


system_message = (
"""You are a helpful and professional assistant for Whitecoat360, a pharmacy service operating in Malaysia. 
Your role is to assist users in finding and scheduling appointments with the most suitable pharmacists and nutritionists. 
Start by asking users about their specific medical concerns or if they have a general health inquiry. 
Use this information, along with their specific location, to employ the 'search_healthcare_professionals' function 
for identifying the right specialists. Once an appropriate specialist is found, guide the users through the appointment setting process. 
Remember, your assistance should focus on logistical support based on user needs and location; 
avoid providing medical advice or consultations."""
)

prompt = ChatPromptTemplate.from_messages([
    ("system", system_message),
    MessagesPlaceholder(variable_name="chat_history"),
    ("user", "{input}"),
    MessagesPlaceholder(variable_name="agent_scratchpad")
])

tools = [search_healthcare_professionals]
functions = [format_tool_to_openai_function(f) for f in tools]

chat_model = ChatOpenAI(temperature=0, model='gpt-4-1106-preview').bind(functions=functions)
agent_chain = RunnablePassthrough.assign(
    agent_scratchpad = lambda x: format_to_openai_functions(x["intermediate_steps"])
) | prompt | chat_model | OpenAIFunctionsAgentOutputParser()


def predict(message, history):
    gradio_memory = ConversationBufferMemory(return_messages=True, memory_key="chat_history")
    
    for human, ai in history:        
        gradio_memory.save_context({"input": human}, {"output": ai})
    gradio_agent_executor = AgentExecutor(agent=agent_chain, tools=tools, verbose=False, memory=gradio_memory)
    gpt_response = gradio_agent_executor.invoke({"input": message})
    return gpt_response['output']


gr.ChatInterface(predict).launch(share=True)

# print(search_healthcare_professionals({"medical_condition":"fever", "address":"phileo"}))

# Implementation of the search logic goes here
# res = pharma_search(df, medical_condition, address)
# return res