Spaces:
Running
Running
import streamlit as st | |
import os | |
from langchain.memory import ConversationBufferMemory | |
import uuid | |
from dotenv import load_dotenv | |
import time | |
from langchain.vectorstores import Chroma | |
from langchain.embeddings import HuggingFaceEmbeddings | |
from langchain.memory import ConversationBufferMemory | |
from langchain_core.prompts import ChatPromptTemplate, PromptTemplate | |
from langchain_groq import ChatGroq | |
from langchain.chains import RetrievalQA, LLMChain | |
from langchain.document_loaders import PyPDFLoader | |
from langchain.text_splitter import RecursiveCharacterTextSplitter | |
# Set page configuration with wide layout | |
st.set_page_config( | |
page_title="Dr. Radha: The Agro-Homeopath", | |
page_icon="🌿", | |
layout="wide" | |
) | |
# Enhanced CSS styling | |
st.markdown(""" | |
<style> | |
/* Main container styling */ | |
.stApp { | |
background-color: #1B4D3E; | |
} | |
/* Chat message styling */ | |
.stChatMessage { | |
background-color: rgba(255, 255, 255, 0.1); | |
border-radius: 15px; | |
padding: 15px; | |
margin: 10px 0; | |
border: 1px solid rgba(255, 255, 255, 0.2); | |
} | |
/* Input field styling */ | |
.stChatInput { | |
border-radius: 20px !important; | |
border: 2px solid rgba(255, 255, 255, 0.2) !important; | |
background-color: rgba(255, 255, 255, 0.05) !important; | |
} | |
/* Style all text elements in white */ | |
.stMarkdown, .stText, .stTitle, .stHeader, .stSubheader, | |
.stTextInput label, .stSelectbox label, .st-emotion-cache-10trblm, | |
.st-emotion-cache-1a7jz76, .st-emotion-cache-1629p8f, | |
[data-testid="stTitle"], [data-testid="stSubheader"] { | |
color: white !important; | |
} | |
/* Additional specific selectors for title and subheader */ | |
h1, h2, h3 { | |
color: white !important; | |
} | |
/* Button styling */ | |
.stButton > button { | |
background-color: #FFD700 !important; | |
color: #1B4D3E !important; | |
font-weight: bold; | |
border-radius: 25px; | |
padding: 10px 25px; | |
border: none; | |
transition: all 0.3s ease; | |
} | |
.stButton > button:hover { | |
transform: scale(1.05); | |
box-shadow: 0 5px 15px rgba(0,0,0,0.2); | |
} | |
/* Center alignment */ | |
.css-10trblm, .css-1a7jz76 { | |
text-align: center !important; | |
} | |
</style> | |
""", unsafe_allow_html=True) | |
st.markdown(""" | |
<style> | |
/* Sidebar styling */ | |
[data-testid="stSidebar"] { | |
background-color: #2fab1a !important; | |
} | |
/* Sidebar content styling */ | |
[data-testid="stSidebar"] .stMarkdown, | |
[data-testid="stSidebar"] .stText, | |
[data-testid="stSidebar"] .stTitle, | |
[data-testid="stSidebar"] label { | |
color: white !important; | |
} | |
/* Ensure text areas in sidebar maintain styling */ | |
[data-testid="stSidebar"] .stTextArea textarea { | |
background-color: #2fab1a !important; | |
color: black !important; | |
} | |
</style> | |
""", unsafe_allow_html=True) | |
# Initialize session state for chat history | |
if "messages" not in st.session_state: | |
st.session_state.messages = [] | |
st.session_state.messages.append({ | |
"role": "assistant", | |
"content": "👋 Hello! I'm Dr. Radha, your AI-powered Organic Farming Consultant. How can I assist you today?" | |
}) | |
# Your existing initialization code here | |
PERSISTENT_DIR = "vector_db" | |
# [Keep all your existing functions and variable definitions] | |
# Set persistent storage path | |
PERSISTENT_DIR = "vector_db" | |
def initialize_vector_db(): | |
# Check if vector database already exists in persistent storage | |
if os.path.exists(PERSISTENT_DIR) and os.listdir(PERSISTENT_DIR): | |
embeddings = HuggingFaceEmbeddings() | |
vector_db = Chroma(persist_directory=PERSISTENT_DIR, embedding_function=embeddings) | |
return None, vector_db | |
base_dir = os.path.dirname(os.path.abspath(__file__)) | |
pdf_files = [f for f in os.listdir(base_dir) if f.endswith('.pdf')] | |
loaders = [PyPDFLoader(os.path.join(base_dir, fn)) for fn in pdf_files] | |
documents = [] | |
for loader in loaders: | |
documents.extend(loader.load()) | |
text_splitter = RecursiveCharacterTextSplitter( | |
chunk_size=1000, | |
chunk_overlap=200, | |
length_function=len, | |
separators=["\n\n", "\n", " ", ""] | |
) | |
texts = text_splitter.split_documents(documents) | |
embeddings = HuggingFaceEmbeddings() | |
vector_db = Chroma.from_documents( | |
texts, | |
embeddings, | |
persist_directory=PERSISTENT_DIR | |
) | |
vector_db.persist() | |
return documents, vector_db | |
# System instructions for the LLM | |
system_prompt = """You are an expert organic farming consultant with specialization in Agro-Homeopathy. When providing suggestions and remedies: | |
1. Always specify medicine potency as 6c unless the uploaded text mentions some other value explicitly | |
3. Provide comprehensive diagnosis and treatment advice along with organic farming best practices applicable in the given context | |
4. Base recommendations on homeopathic and organic farming principles | |
""" | |
api_key1 = os.getenv("api_key") | |
start_time = time.time() | |
# Title and subheader | |
st.title("🌿 Dr. Radha: AI-Powered Organic Farming Consultant") | |
st.subheader("Specializing in Agro-Homeopathy | Free Consultation") | |
# Information message with centered alignment | |
st.markdown(""" | |
Please provide complete details about the issue, including:<br> | |
- Detailed description of plant problem<br> | |
- Current location, temperature & weather conditions | |
""", unsafe_allow_html=True) | |
human_image = "human.png" | |
robot_image = "bot.jpg" | |
# Set up Groq API with temperature 0.7 | |
llm = ChatGroq( | |
api_key=api_key1, | |
max_tokens=None, | |
timeout=None, | |
max_retries=2, | |
temperature=0.7, | |
model="llama-3.3-70b-versatile" | |
) | |
embeddings = HuggingFaceEmbeddings() | |
end_time = time.time() | |
print(f"Setting up Groq LLM & Embeddings took {end_time - start_time:.4f} seconds") | |
# Initialize session state | |
if "documents" not in st.session_state: | |
st.session_state["documents"] = None | |
if "vector_db" not in st.session_state: | |
st.session_state["vector_db"] = None | |
if "query" not in st.session_state: | |
st.session_state["query"] = "" | |
if "session_id" not in st.session_state: | |
st.session_state.session_id = str(uuid.uuid4()) | |
if "conversation_memory" not in st.session_state: | |
st.session_state.conversation_memory = ConversationBufferMemory( | |
memory_key="chat_history", | |
return_messages=True | |
) | |
if "saved_conversations" not in st.session_state: | |
st.session_state.saved_conversations = [] | |
start_time = time.time() | |
if st.session_state["documents"] is None or st.session_state["vector_db"] is None: | |
with st.spinner("Loading data..."): | |
documents, vector_db = initialize_vector_db() | |
st.session_state["documents"] = documents | |
st.session_state["vector_db"] = vector_db | |
else: | |
documents = st.session_state["documents"] | |
vector_db = st.session_state["vector_db"] | |
retriever = vector_db.as_retriever() | |
with st.sidebar: | |
st.title("Past Conversations") | |
# Display saved conversations | |
for idx, conv in enumerate(st.session_state.saved_conversations): | |
# Get the first message from user in the conversation | |
first_user_msg = next((msg["content"] for msg in conv if msg["role"] == "user"), "") | |
# Take first 30 characters of the message | |
preview = first_user_msg[:50] + "..." if len(first_user_msg) > 50 else first_user_msg | |
if st.button(f"Query {idx + 1}: {preview}", key=f"conv_{idx}"): | |
st.session_state.messages = conv.copy() | |
st.rerun() | |
prompt_template = """As an expert organic farming consultant with specialization in Agro-Homeopathy, analyze the following context and question to provide a clear, structured response. | |
Context: {context} | |
Previous conversation:{chat_history} | |
Question: {query} | |
Provide your response in the following format: | |
Analysis: Analyze the described plant condition | |
Treatment: Recommend relevant organic farming principles and specific homeopathic medicine(s) with exact potency and repetition frequency. Suggest a maximum of 4 medicines in the order of relevance for any single problem. | |
Instructions for Use: | |
Small Plots or Gardens: Make sure your dispensing equipment is not contaminated with | |
other chemicals or fertilisers as these may antidote the energetic effects of the treatment— | |
rinse well with hot water before use if necessary. Add one pill to each 200 ml of water, shake | |
vigorously, and then spray or water your plants. Avoid using other chemicals or fertilisers for | |
10 days following treatment so that the energetic effects of the treatment are not antidoted. | |
(One vial of 100 pills makes 20 litres. Plants remain insect or disease free for up to 3 months | |
following one treatment.) | |
Large Plots or Farms: Add the remedy to water and apply with the dispensing device of | |
your choice: watering can, backpack sprayer, boomspray, reticulation systems (add to tanks | |
or pumps). Make sure your dispensing equipment is not contaminated with other chemicals | |
or fertilisers as these may antidote the energetic effects of the treatment—rinse with hot | |
water or steam clean before use if necessary. Avoid using other chemicals or fertilisers for | |
10 days following treatment. | |
Dosage rates are approximate and may vary according to different circumstances and | |
experiences. Suggested doses are: | |
10 pills or 10ml/10 litre on small areas, | |
500 pills or 125ml/500l per hectare, | |
1000 pills or 250ml/500l per hectare, | |
2500 pills or 500ml/500l per hectare, | |
Add pills or liquid to your water and mix (with a stick if necessary for large containers). | |
Recommendations: Provide three key pertinent recommendations based on the query | |
Remember to maintain a professional, clear tone and ensure all medicine recommendations include specific potency. | |
Answer:""" | |
# Create the QA chain with correct variables | |
memory = ConversationBufferMemory( | |
memory_key="chat_history", | |
input_key="query", | |
output_key="answer" | |
) | |
qa = RetrievalQA.from_chain_type( | |
llm=llm, | |
chain_type="stuff", | |
retriever=retriever, | |
memory=memory, | |
chain_type_kwargs={ | |
"prompt": PromptTemplate( | |
template=prompt_template, | |
input_variables=["context", "query"] | |
) | |
} | |
) | |
# Create a separate LLMChain for fallback | |
fallback_template = """As an expert organic farming consultant with specialization in Agro-Homeopathy, analyze the following context and question to provide a clear, structured response. | |
Previous conversation:{chat_history} | |
Question: {query} | |
Format your response as follows: | |
Analysis: Analyze the described plant condition | |
Treatment: Recommend relevant organic farming principles and specific homeopathic medicine(s) with exact potency and repetition frequency. Suggest a maximum of 4 medicines in the order of relevance for any single problem. | |
Instructions for Use: | |
Small Plots or Gardens: Make sure your dispensing equipment is not contaminated with | |
other chemicals or fertilisers as these may antidote the energetic effects of the treatment— | |
rinse well with hot water before use if necessary. Add one pill to each 200 ml of water, shake | |
vigorously, and then spray or water your plants. Avoid using other chemicals or fertilisers for | |
10 days following treatment so that the energetic effects of the treatment are not antidoted. | |
(One vial of 100 pills makes 20 litres. Plants remain insect or disease free for up to 3 months | |
following one treatment.) | |
Large Plots or Farms: Add the remedy to water and apply with the dispensing device of | |
your choice: watering can, backpack sprayer, boomspray, reticulation systems (add to tanks | |
or pumps). Make sure your dispensing equipment is not contaminated with other chemicals | |
or fertilisers as these may antidote the energetic effects of the treatment—rinse with hot | |
water or steam clean before use if necessary. Avoid using other chemicals or fertilisers for | |
10 days following treatment. | |
Dosage rates are approximate and may vary according to different circumstances and | |
experiences. Suggested doses are: | |
10 pills or 10ml/10 litre on small areas | |
500 pills or 125ml/500l per hectare | |
1000 pills or 250ml/500l per hectare | |
2500 pills or 500ml/500l per hectare | |
Add pills or liquid to your water and mix (with a stick if necessary for large containers). | |
Recommendations: Provide three key pertinent recommendations based on the query | |
Maintain a professional tone and ensure all medicine recommendations include specific potency. | |
Answer:""" | |
fallback_prompt = PromptTemplate( | |
template=fallback_template, | |
input_variables=["query", "chat_history"] | |
) | |
fallback_chain = LLMChain( | |
llm=llm, | |
prompt=fallback_prompt, | |
memory=st.session_state.conversation_memory | |
) | |
# Replace your existing chat container and form section with this: | |
chat_container = st.container() | |
with chat_container: | |
# Display chat history | |
for message in st.session_state.messages: | |
with st.chat_message(message["role"], avatar="👤" if message["role"] == "user" else "👩⚕️"): | |
st.markdown(message["content"]) | |
with st.form(key='query_form', clear_on_submit=True): | |
query = st.text_input( | |
"Ask your question:", | |
placeholder="Describe your plant issue here...", | |
label_visibility="collapsed" | |
) | |
col1, col2 = st.columns([1, 1]) | |
with col1: | |
submit_button = st.form_submit_button(label='Submit 📤') | |
with col2: | |
new_conv_button = st.form_submit_button(label='New Conversation 🔄') | |
if new_conv_button and len(st.session_state.messages) > 1: | |
# Save current conversation | |
st.session_state.saved_conversations.append(st.session_state.messages.copy()) | |
# Clear current conversation | |
st.session_state.messages = [] | |
st.session_state.messages.append({ | |
"role": "assistant", | |
"content": "👋 Hello! I'm Dr. Radha, your AI-powered Organic Farming Consultant. How can I assist you today?" | |
}) | |
st.session_state.conversation_memory.clear() | |
st.rerun() | |
human_image = "human.png" | |
robot_image = "bot.jpg" | |
if submit_button and query: | |
# Add user message to history | |
st.session_state.messages.append({"role": "user", "content": query}) | |
# Show user message | |
with st.chat_message("user", avatar="👤"): | |
st.markdown(query) | |
# Show typing indicator while generating response "🌿" | |
with st.chat_message("assistant", avatar="👩⚕️"): | |
with st.status("Analyzing your query...", expanded=True): | |
st.write("🔍 Retrieving relevant information...") | |
st.write("📝 Generating personalized response...") | |
chat_history = st.session_state.conversation_memory.load_memory_variables({}).get("chat_history", "") | |
try: | |
result = qa({ | |
"query": query # Changed from "query" to "question" | |
}) | |
response = result['result'] if result['result'].strip() != "" else fallback_chain.run(query=query, chat_history=st.session_state.conversation_memory.load_memory_variables({})["chat_history"]) | |
except Exception as e: | |
response = fallback_chain.run(query=query, chat_history=st.session_state.conversation_memory.load_memory_variables({})["chat_history"]) | |
st.session_state.conversation_memory.save_context( | |
{"input": query}, | |
{"output": response} | |
) | |
# Display final response | |
st.markdown(response) | |
st.session_state.messages.append({"role": "assistant", "content": response}) | |
# Clear the form | |
st.session_state["query"] = "" | |
# Rerun to update chat history | |
st.rerun() | |