patrickbdevaney's picture
Update app.py
2c9375c verified
import os
import openai
import chromadb
import numpy as np
from dotenv import load_dotenv
import gradio as gr
import logging
from huggingface_hub import HfApi, HfFolder
# Load environment variables
load_dotenv()
# Define OpenAI-based model
class OpenAIChatbot:
def __init__(self, api_key):
self.embedding_model = "text-embedding-3-large" # OpenAI model with 3072 dimensions
self.chat_model = "gpt-4o"
self.api_key = api_key
def get_response(self, prompt):
"""Get a response from OpenAI GPT-4 model."""
try:
openai.api_key = self.api_key
response = openai.chat.completions.create(
model=self.chat_model,
messages=[
{"role": "system", "content": "You are a helpful AI assistant."},
{"role": "user", "content": prompt}
]
)
# Correctly access the message content in the response
return response.choices[0].message.content
except Exception as e:
print(f"Error generating response: {e}")
return "Error: Unable to generate a response."
def text_to_embedding(self, text):
"""Convert text to embedding using OpenAI embedding model."""
try:
openai.api_key = self.api_key
response = openai.embeddings.create(
model=self.embedding_model,
input=text
)
# Access the embedding using the 'data' attribute
embedding = np.array(response.data[0].embedding)
print(f"Generated embedding for text: {text}")
return embedding
except Exception as e:
print(f"Error generating embedding: {e}")
return None
# Modify LocalEmbeddingStore to ensure correct dimensionality (3072) in ChromaDB
class LocalEmbeddingStore:
def __init__(self, storage_dir="./chromadb_storage_openai_upgrade"):
# Use ChromaDB client with persistent storage
self.client = chromadb.PersistentClient(path=storage_dir)
self.collection_name = "chatbot_docs"
# Get the collection without adding new embeddings
self.collection = self.client.get_or_create_collection(name=self.collection_name)
def search_embedding(self, query_embedding, num_results=3):
"""Search for the most relevant document based on embedding similarity."""
if query_embedding.shape[0] != 3072:
raise ValueError("Query embedding dimensionality must be 3072.")
print(f"Query embedding: {query_embedding}") # Debugging: Log the query embedding
results = self.collection.query(
query_embeddings=[query_embedding.tolist()], # Ensure embeddings are converted to list format
n_results=num_results
)
print(f"Search results: {results}") # Debugging: Print results to check for any issues
return results['documents'], results['distances']
def add_embedding(self, document_id, embedding, metadata=None):
"""Add a new embedding to the collection."""
self.collection.add(
ids=[document_id],
embeddings=[embedding.tolist()],
metadatas=[metadata] if metadata else None
)
print(f"Added embedding for document ID: {document_id}")
# Modify RAGSystem to integrate ChromaDB search
class RAGSystem:
def __init__(self, openai_client, embedding_store):
self.openai_client = openai_client
self.embedding_store = embedding_store
def get_most_relevant_document(self, query_embedding, similarity_threshold=0.7):
"""Retrieve the most relevant document based on cosine similarity."""
docs, distances = self.embedding_store.search_embedding(query_embedding)
# Check if the results are empty or have low relevance
if not docs or not distances or distances[0][0] < similarity_threshold:
print("No relevant documents found or similarity is too low.")
return None, None # Return None if no relevant documents found
return docs[0], distances[0][0] # Return the most relevant document and the first distance value
def chat_with_rag(self, user_input):
"""Handle the RAG process."""
query_embedding = self.openai_client.text_to_embedding(user_input)
if query_embedding is None or query_embedding.size == 0:
return "Failed to generate embeddings."
context_document_id, similarity_score = self.get_most_relevant_document(query_embedding)
if not context_document_id:
return "No relevant documents found."
# Assuming metadata retrieval works
context_metadata = f"Metadata for {context_document_id}" # Placeholder, implement as needed
prompt = f"""Context (similarity score {similarity_score:.2f}):
{context_metadata}
User: {user_input}
AI:"""
return self.openai_client.get_response(prompt)
# Gradio UI
def chat_ui(user_input, api_key, chat_history):
"""Handle chat interactions and update history."""
if not api_key.strip():
return "Please provide your OpenAI API key before proceeding."
# Initialize OpenAIChatbot with the user's API key
chatbot = OpenAIChatbot(api_key)
embedding_store = LocalEmbeddingStore(storage_dir="./chromadb_storage_openai_upgrade")
rag_system = RAGSystem(openai_client=chatbot, embedding_store=embedding_store)
if not user_input.strip():
return chat_history
ai_response = rag_system.chat_with_rag(user_input)
chat_history.append((user_input, ai_response))
return chat_history
# Gradio interface
with gr.Blocks() as demo:
api_key_input = gr.Textbox(label="Enter your OpenAI API Key", placeholder="API Key here...", type="password")
chat_history = gr.Chatbot(label="OpenAI Chatbot with RAG", elem_id="chatbox")
user_input = gr.Textbox(placeholder="Enter your prompt here...")
submit_button = gr.Button("Submit")
submit_button.click(chat_ui, inputs=[user_input, api_key_input, chat_history], outputs=chat_history)
if __name__ == "__main__":
# Load Hugging Face token from environment variables
hf_token = os.getenv("HUGGINGFACE_TOKEN")
if not hf_token:
raise ValueError("Hugging Face token not found in environment variables.")
# Set up the Hugging Face token for any necessary API calls
os.environ["HUGGINGFACE_TOKEN"] = hf_token
# Verify token permissions (optional)
try:
api = HfApi()
api.whoami(token=hf_token)
print("Hugging Face token is valid and has the necessary permissions.")
except Exception as e:
print(f"Error verifying Hugging Face token: {e}")
raise ValueError("Invalid Hugging Face token or insufficient permissions.")
demo.launch()