Spaces:
Sleeping
Sleeping
File size: 11,173 Bytes
f92dacb 1974685 f92dacb 4348b11 f92dacb 4348b11 f92dacb 4348b11 f92dacb 4348b11 f92dacb 4348b11 f92dacb 4348b11 1974685 e934a7f 1974685 4348b11 e934a7f 4348b11 e934a7f 4348b11 eeb4280 1974685 4348b11 1974685 f92dacb 4348b11 e934a7f 4348b11 f92dacb 705a4b7 3469ded e934a7f 4348b11 e934a7f 4348b11 8d6ccfc 4348b11 8d6ccfc 4348b11 8d6ccfc 4348b11 | 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 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 | import os
import openai
import streamlit as st
from pinecone import Pinecone, ServerlessSpec
from agents import Head_Agent
import logging
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# Streamlit page configuration
st.set_page_config(
page_title="Multi-Agent Chatbot System",
page_icon="π€",
layout="wide",
initial_sidebar_state="expanded"
)
# Load API keys from environment variables
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
PINECONE_API_KEY = os.getenv("PINECONE_API_KEY")
PINECONE_INDEX_NAME = "miniproject2-multi-agent-chatbot"
# Header section
st.title("π€ Multi-Agent Chatbot System")
st.markdown("""
This chatbot uses multiple specialized agents to answer your questions about machine learning.
Each agent has a specific role in processing your query and generating a response.
""")
# Check if API keys are set
if not OPENAI_API_KEY or not PINECONE_API_KEY:
st.error("β API keys are missing! Please set them in environment variables.")
st.stop()
# Initialize OpenAI client
try:
openai_client = openai.OpenAI(api_key=OPENAI_API_KEY)
logger.info("OpenAI client initialized successfully")
except Exception as e:
st.error(f"β Failed to initialize OpenAI client: {str(e)}")
logger.error(f"OpenAI initialization error: {e}")
st.stop()
# Initialize Pinecone
try:
pc = Pinecone(api_key=PINECONE_API_KEY)
# First, check if the index exists
try:
all_indexes = pc.list_indexes().names()
index_exists = PINECONE_INDEX_NAME in all_indexes
except Exception as e:
logger.error(f"Failed to list Pinecone indexes: {e}")
index_exists = False
st.warning("β οΈ Could not verify if the Pinecone index exists. Will attempt to create it.")
if not index_exists:
st.warning(f"β οΈ Pinecone index '{PINECONE_INDEX_NAME}' not found. Creating a new one...")
logger.warning(f"Creating new Pinecone index: {PINECONE_INDEX_NAME}")
try:
pc.create_index(
name=PINECONE_INDEX_NAME,
dimension=1536, # OpenAI embedding dimension
metric="cosine",
spec=ServerlessSpec(cloud="aws", region="us-east-1")
)
logger.info(f"Successfully created Pinecone index: {PINECONE_INDEX_NAME}")
except Exception as e:
st.error(f"β Failed to create Pinecone index: {str(e)}")
logger.error(f"Pinecone index creation error: {e}")
st.stop()
# Connect to the index
try:
pinecone_index = pc.Index(PINECONE_INDEX_NAME)
logger.info(f"Pinecone index '{PINECONE_INDEX_NAME}' connected")
except Exception as e:
st.error(f"β Failed to connect to Pinecone index: {str(e)}")
logger.error(f"Pinecone index connection error: {e}")
st.stop()
# Check if the index has any vectors
try:
index_stats = pinecone_index.describe_index_stats()
vector_count = index_stats.get('total_vector_count', 0)
# Display vector count in sidebar
st.sidebar.info(f"π Vector count in Pinecone index: {vector_count}")
if vector_count == 0:
st.warning(
"β οΈ Your Pinecone index is empty. You need to add document embeddings before using the chatbot effectively.")
logger.warning("Pinecone index is empty - no vectors found")
except Exception as e:
logger.error(f"Failed to get index stats: {e}")
st.warning("β οΈ Could not verify if the Pinecone index contains vectors.")
except Exception as e:
st.error(f"β Failed to initialize Pinecone: {str(e)}")
logger.error(f"Pinecone initialization error: {e}")
st.stop()
# Sidebar with mode selection and information
with st.sidebar:
st.header("Agent Configuration")
# Mode selection
if "chatbot_mode" not in st.session_state:
st.session_state.chatbot_mode = "precise"
mode = st.radio(
"Select Agent Mode:",
["precise", "chatty"],
help="Precise mode gives concise, factual answers. Chatty mode is more conversational."
)
if mode != st.session_state.chatbot_mode:
st.session_state.chatbot_mode = mode
# If we already have a chatbot agent, update its mode
if "chatbot_agent" in st.session_state:
try:
st.session_state.chatbot_agent.set_mode(mode)
st.success(f"β
Mode changed to '{mode}'")
logger.info(f"Agent mode changed to: {mode}")
except Exception as e:
st.error(f"Failed to change mode: {str(e)}")
logger.error(f"Mode change error: {e}")
st.header("Agent Information")
if st.button("ποΈ Show Agent Architecture"):
with st.expander("Agent Architecture", expanded=True):
st.markdown("""
### Multi-Agent System Architecture
1. **Head Agent (Controller)**
- Coordinates all other agents
- Manages conversation history
2. **Obnoxious Agent**
- Checks if user input is appropriate
- Filters out harmful or offensive content
3. **Pinecone Query Agent**
- Determines if query relates to domain knowledge
- Routes irrelevant questions appropriately
4. **Query Agent**
- Converts user query to embeddings
- Retrieves potential relevant documents
5. **Relevant Documents Agent**
- Filters retrieved documents by relevance
- Ensures responses are backed by appropriate context
6. **Answering Agent**
- Generates final response based on relevant documents
- Fallback to general knowledge when needed
""")
st.header("Actions")
if st.button("ποΈ Clear Chat History"):
# Reset conversation but keep the agent
if "messages" in st.session_state:
st.session_state.messages = []
logger.info("Chat history cleared")
if "chatbot_agent" in st.session_state:
# Reset agent's conversation history too
st.session_state.chatbot_agent.conv_history = []
st.success("Chat history cleared!")
st.experimental_rerun()
# In the sidebar, add PDF processing section
st.header("PDF Processing")
if st.button("Process Machine Learning PDF"):
try:
st.info("Starting PDF processing...")
# Import data_loader module
import data_loader
# Show progress information
with st.spinner("Step 1/3: Loading PDF file..."):
page_texts, page_numbers = data_loader.load_pdf()
st.success(f"β Loaded {len(page_texts)} pages from PDF")
with st.spinner("Step 2/3: Chunking text and generating embeddings..."):
chunks, chunk_page_numbers = data_loader.chunk_text(page_texts, page_numbers)
df = data_loader.prepare_data(chunks, chunk_page_numbers)
st.success(f"β Generated embeddings for {len(df)} text chunks")
with st.spinner("Step 3/3: Uploading to Pinecone..."):
stats = data_loader.create_pinecone_index(df)
vector_count = stats.get('total_vector_count', 0)
st.success(f"β Successfully uploaded to Pinecone. Total vectors: {vector_count}")
# Reload the page to update index status
st.success("PDF processing complete! Refreshing page...")
st.experimental_rerun()
except Exception as e:
st.error(f"Error processing PDF: {str(e)}")
st.error("Please check logs for more details")
# Test direct query to Pinecone if index is empty
if "vector_count" in locals() and vector_count == 0:
if st.button("π§ͺ Test Pinecone Connection"):
try:
st.info("Testing Pinecone connection with a sample query...")
# Generate an embedding
test_response = openai_client.embeddings.create(
model="text-embedding-ada-002",
input=["machine learning basics"]
)
test_embedding = test_response.data[0].embedding
# Query Pinecone
test_results = pinecone_index.query(
vector=test_embedding,
top_k=1,
include_values=False,
include_metadata=True
)
st.json(test_results)
st.success("Pinecone query test completed successfully!")
except Exception as e:
st.error(f"Test query failed: {str(e)}")
logger.error(f"Pinecone test query error: {e}")
# Initialize or update chatbot agent with current mode
if "chatbot_agent" not in st.session_state:
try:
st.session_state.chatbot_agent = Head_Agent(
openai_client,
pinecone_index,
domain="machine learning",
mode=st.session_state.chatbot_mode
)
logger.info(f"Initialized chatbot agent in {st.session_state.chatbot_mode} mode")
except Exception as e:
st.error(f"Failed to initialize chatbot agent: {str(e)}")
logger.error(f"Chatbot agent initialization error: {e}")
st.stop()
# Initialize conversation history if not present
if "messages" not in st.session_state:
st.session_state.messages = []
logger.info("Initialized empty message history")
# Display chat messages
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.markdown(message["content"])
# Chat input
user_query = st.chat_input("Ask me about machine learning...")
if user_query:
# Display user message
with st.chat_message("user"):
st.markdown(user_query)
# Add to message history
st.session_state.messages.append({"role": "user", "content": user_query})
# Get response (with spinner to show processing)
with st.spinner("Thinking..."):
logger.info(f"Processing user query: {user_query[:50]}...")
try:
chatbot_response = st.session_state.chatbot_agent.process_query(user_query)
logger.info(f"Generated response of length {len(chatbot_response)}")
except Exception as e:
logger.error(f"Error generating response: {e}")
chatbot_response = "I encountered an error while processing your query. Please try again or ask something different."
# Display assistant response
with st.chat_message("assistant"):
st.markdown(chatbot_response)
# Add to message history
st.session_state.messages.append({"role": "assistant", "content": chatbot_response}) |