chatbot / api.py
Shaheryar Shah
Add application file
d6bb2ba
from flask import Flask, request, jsonify
from flask_cors import CORS
import sys
import os
# Add the src/python directory to the path so we can import our modules
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
from src.python.vector_store import VectorStore
from backend.embedder_wrapper import SyncEmbedder
from src.python.config import OPENAI_API_KEY, QDRANT_URL, QDRANT_API_KEY, COLLECTION_NAME
import logging
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
app = Flask(__name__)
CORS(app, origins=["http://localhost:3000", "http://localhost:5000", "http://127.0.0.1:3000", "http://127.0.0.1:5000"], supports_credentials=True, allow_headers=["Content-Type", "Authorization"])
# Initialize our components
try:
vector_store = VectorStore()
embedder = SyncEmbedder()
logger.info("Service initialized successfully")
logger.info(f"Connected to Qdrant at: {QDRANT_URL}")
except Exception as e:
logger.error(f"Failed to initialize services: {str(e)}")
raise
@app.route('/chat', methods=['POST'])
def chat():
"""
Chat endpoint that takes user query and returns a response based on RAG
Expected JSON format: {"message": "user question"}
"""
try:
data = request.get_json()
if not data or 'message' not in data:
return jsonify({'error': 'Message field is required'}), 400
user_message = data['message']
# Create embedding for the user message
try:
query_embedding = embedder.embed_text(user_message)
except Exception as e:
logger.error(f"Error creating embedding: {str(e)}")
return jsonify({'error': f'Error processing your message: {str(e)}'}), 500
# Search for similar documents in the vector store
try:
similar_docs = vector_store.search_similar(query_embedding, top_k=5)
except Exception as e:
logger.error(f"Error searching for documents: {str(e)}")
return jsonify({'error': f'Error retrieving documents: {str(e)}'}), 500
# Format the retrieved documents as context
context = "\n".join([doc['content'] for doc in similar_docs])
# Prepare the prompt for the LLM
if context.strip() == "":
# If no context is found, let the model respond without it
prompt = f"""
Please answer the following question. If you don't know the answer, please say so.
Question: {user_message}
Answer:
"""
else:
prompt = f"""
Answer the question based on the context provided.
If the answer is not in the context, say "I don't have enough information to answer that question."
Context: {context}
Question: {user_message}
Answer:
"""
# Use OpenAI API to generate the response
try:
from openai import OpenAI
client = OpenAI(api_key=OPENAI_API_KEY)
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": prompt}],
temperature=0.3,
max_tokens=500
)
bot_response = response.choices[0].message.content.strip()
except Exception as e:
logger.error(f"Error calling LLM: {str(e)}")
return jsonify({'error': f'Error generating response: {str(e)}'}), 500
return jsonify({
'response': bot_response,
'sources': [doc.get('source', '') for doc in similar_docs],
'scores': [doc.get('score', 0.0) for doc in similar_docs],
'retrieved_context': context
})
except Exception as e:
logger.error(f"Unexpected error in chat endpoint: {str(e)}")
return jsonify({'error': str(e)}), 500
@app.route('/health', methods=['GET'])
def health():
"""Health check endpoint"""
return jsonify({'status': 'healthy'})
@app.route('/documents/count', methods=['GET'])
def document_count():
"""Get the count of documents in the vector store"""
try:
count = vector_store.get_all_documents_count()
return jsonify({'count': count})
except Exception as e:
logger.error(f"Error getting document count: {str(e)}")
return jsonify({'error': str(e)}), 500
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000)