import streamlit as st from langchain.document_loaders import PyPDFLoader, DirectoryLoader from langchain import PromptTemplate from langchain.embeddings import HuggingFaceEmbeddings from langchain.vectorstores import FAISS from langchain.llms import CTransformers from langchain.chains import RetrievalQA import geocoder from geopy.distance import geodesic import pandas as pd import folium from streamlit_folium import folium_static from transformers import pipeline import logging #----------------- # demonstrating use of a Vectordb store #----------------- DB_FAISS_PATH = 'vectorstores/db_faiss' #----------------- # Detecting the context if its to be a normal textual chat, load nearest clinic map or shopping link #----------------- classifier = pipeline("zero-shot-classification") #----------------- # Set up logging. mostly for debugging purposes only #----------------- logging.basicConfig(filename='app.log', level=logging.DEBUG, format='%(asctime)s %(message)s') custom_prompt_template = """Use the following pieces of information to answer the user's question. If you don't know the answer, just say that you don't know, don't try to make up an answer. Context: {context} Question: {question} Only return the helpful answer below and nothing else. Helpful answer: """ def set_custom_prompt(): prompt = PromptTemplate(template=custom_prompt_template, input_variables=['context', 'question']) return prompt def retrieval_qa_chain(llm, prompt, db): qa_chain = RetrievalQA.from_chain_type(llm=llm, chain_type='stuff', retriever=db.as_retriever(search_kwargs={'k': 2}), return_source_documents=True, chain_type_kwargs={'prompt': prompt} ) return qa_chain #----------------- #function to load LLM from huggingface #----------------- def load_llm(): llm = CTransformers( model="TheBloke/Llama-2-7B-Chat-GGML", model_type="llama", max_new_tokens=512, temperature=0.5 ) return llm #----------------- #function that does 3 things #1. loads maps using Folium if Context is nearest clinic (maps loads dataset from csv) #2. loads a shopee link if Context is to buy things #3. loads normal chat bubble which is to infer the chat bubble #----------------- def qa_bot(query, context=""): logging.info(f"Received query: {query}, Context: {context}") if context in ["nearest clinic","nearest TCM clinic","nearest TCM doctor","near me","nearest to me"]: #----------- # Loads map #----------- logging.info("Context matched for nearest TCM clinic.") # Get user's current location g = geocoder.ip('me') user_lat, user_lon = g.latlng # Load locations from the CSV file locations_df = pd.read_csv("dataset/locations.csv") # Filter locations within 5km from user's current location filtered_locations_df = locations_df[locations_df.apply(lambda row: geodesic((user_lat, user_lon), (row['latitude'], row['longitude'])).kilometers <= 5, axis=1)] # Create map centered at user's location my_map = folium.Map(location=[user_lat, user_lon], zoom_start=12) # Add markers with custom tooltips for filtered locations for index, location in filtered_locations_df.iterrows(): folium.Marker(location=[location['latitude'], location['longitude']], tooltip=f"{location['name']}
Reviews: {location['Stars_review']}
Avg Price $: {location['Price']}
Contact No: {location['Contact']}").add_to(my_map) # Display map folium_static(my_map) return "[Map of Clinic Locations 5km from your current location]" elif context in ["buy", "Ointment", "Hong You", "Feng You", "Fengyou", "Po chai pills"]: #----------- # Loads shopee link #----------- logging.info("Context matched for buying.") # Create a hyperlink to shopee.sg based on the search query shopee_link = f"at this Shopee link!" return f"You may visit this page to purchase {context} {shopee_link}!" else: #----------- # Loads normal chat bubble #----------- logging.info("Context not matched for nearest TCM clinic or buying.") embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2", model_kwargs={'device': 'cpu'}) db = FAISS.load_local(DB_FAISS_PATH, embeddings) llm = load_llm() qa_prompt = set_custom_prompt() qa = retrieval_qa_chain(llm, qa_prompt, db) # Implement the question-answering logic here response = qa({'query': query}) return response['result'] def add_vertical_space(spaces=1): for _ in range(spaces): st.markdown("---") def main(): st.set_page_config(page_title="Ask me anything about TCM") with st.sidebar: st.title('Welcome to Nexus AI TCM!') st.markdown(''' ''', unsafe_allow_html=True) add_vertical_space(1) # Adjust the number of spaces as needed st.title("Nexus AI TCM") st.markdown( """ """ , unsafe_allow_html=True) conversation = st.session_state.get("conversation", []) if "my_text" not in st.session_state: st.session_state.my_text = "" st.text_input("Enter text here", key="widget", on_change=submit) query = st.session_state.my_text if st.button("Ask"): if query: with st.spinner("Processing your question..."): # Display the processing message conversation.append({"role": "user", "message": query}) # Call your QA function answer = qa_bot(query, infer_context(query)) conversation.append({"role": "bot", "message": answer}) st.session_state.conversation = conversation else: st.warning("Please input a question.") # # Display the conversation history chat_container = st.empty() chat_bubbles = ''.join([f'
{c["message"]}
' for c in conversation]) chat_container.markdown(f'
{chat_bubbles}
', unsafe_allow_html=True) def submit(): st.session_state.my_text = st.session_state.widget st.session_state.widget = "" #----------- # Setting the Context #----------- def infer_context(query): """ Function to infer context based on the user's query. Modify this function to suit your context detection needs. """ labels = ["TCM","sick","herbs","traditional","nearest clinic","nearest TCM clinic","nearest TCM doctor","near me","nearest to me", "Ointment", "Hong You", "Feng You", "Fengyou", "Po chai pills"] result = classifier(query, labels) predicted_label = result["labels"][0] return predicted_label if __name__ == "__main__": main()