Shaheryar Shah commited on
Commit
d6bb2ba
·
1 Parent(s): 46a8bda

Add application file

Browse files
Files changed (3) hide show
  1. Dockerfile +12 -0
  2. api.py +130 -0
  3. requirements.txt +8 -0
Dockerfile ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+ WORKDIR /
4
+
5
+ COPY requirements.txt .
6
+ RUN pip install --no-cache-dir -r requirements.txt
7
+
8
+ COPY . .
9
+
10
+ EXPOSE 7860
11
+
12
+ CMD ["uvicorn", "app.api:app", "--host", "0.0.0.0", "--port", "7860"]
api.py ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, jsonify
2
+ from flask_cors import CORS
3
+ import sys
4
+ import os
5
+
6
+ # Add the src/python directory to the path so we can import our modules
7
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
8
+
9
+ from src.python.vector_store import VectorStore
10
+ from backend.embedder_wrapper import SyncEmbedder
11
+ from src.python.config import OPENAI_API_KEY, QDRANT_URL, QDRANT_API_KEY, COLLECTION_NAME
12
+ import logging
13
+
14
+ # Configure logging
15
+ logging.basicConfig(level=logging.INFO)
16
+ logger = logging.getLogger(__name__)
17
+
18
+ app = Flask(__name__)
19
+ 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"])
20
+
21
+ # Initialize our components
22
+ try:
23
+ vector_store = VectorStore()
24
+ embedder = SyncEmbedder()
25
+ logger.info("Service initialized successfully")
26
+ logger.info(f"Connected to Qdrant at: {QDRANT_URL}")
27
+ except Exception as e:
28
+ logger.error(f"Failed to initialize services: {str(e)}")
29
+ raise
30
+
31
+ @app.route('/chat', methods=['POST'])
32
+ def chat():
33
+ """
34
+ Chat endpoint that takes user query and returns a response based on RAG
35
+ Expected JSON format: {"message": "user question"}
36
+ """
37
+ try:
38
+ data = request.get_json()
39
+
40
+ if not data or 'message' not in data:
41
+ return jsonify({'error': 'Message field is required'}), 400
42
+
43
+ user_message = data['message']
44
+
45
+ # Create embedding for the user message
46
+ try:
47
+ query_embedding = embedder.embed_text(user_message)
48
+ except Exception as e:
49
+ logger.error(f"Error creating embedding: {str(e)}")
50
+ return jsonify({'error': f'Error processing your message: {str(e)}'}), 500
51
+
52
+ # Search for similar documents in the vector store
53
+ try:
54
+ similar_docs = vector_store.search_similar(query_embedding, top_k=5)
55
+ except Exception as e:
56
+ logger.error(f"Error searching for documents: {str(e)}")
57
+ return jsonify({'error': f'Error retrieving documents: {str(e)}'}), 500
58
+
59
+ # Format the retrieved documents as context
60
+ context = "\n".join([doc['content'] for doc in similar_docs])
61
+
62
+ # Prepare the prompt for the LLM
63
+ if context.strip() == "":
64
+ # If no context is found, let the model respond without it
65
+ prompt = f"""
66
+ Please answer the following question. If you don't know the answer, please say so.
67
+
68
+ Question: {user_message}
69
+ Answer:
70
+ """
71
+ else:
72
+ prompt = f"""
73
+ Answer the question based on the context provided.
74
+ If the answer is not in the context, say "I don't have enough information to answer that question."
75
+
76
+ Context: {context}
77
+
78
+ Question: {user_message}
79
+ Answer:
80
+ """
81
+
82
+ # Use OpenAI API to generate the response
83
+ try:
84
+ from openai import OpenAI
85
+
86
+ client = OpenAI(api_key=OPENAI_API_KEY)
87
+
88
+ response = client.chat.completions.create(
89
+ model="gpt-3.5-turbo",
90
+ messages=[{"role": "user", "content": prompt}],
91
+ temperature=0.3,
92
+ max_tokens=500
93
+ )
94
+
95
+ bot_response = response.choices[0].message.content.strip()
96
+ except Exception as e:
97
+ logger.error(f"Error calling LLM: {str(e)}")
98
+ return jsonify({'error': f'Error generating response: {str(e)}'}), 500
99
+
100
+ return jsonify({
101
+ 'response': bot_response,
102
+ 'sources': [doc.get('source', '') for doc in similar_docs],
103
+ 'scores': [doc.get('score', 0.0) for doc in similar_docs],
104
+ 'retrieved_context': context
105
+ })
106
+
107
+ except Exception as e:
108
+ logger.error(f"Unexpected error in chat endpoint: {str(e)}")
109
+ return jsonify({'error': str(e)}), 500
110
+
111
+
112
+ @app.route('/health', methods=['GET'])
113
+ def health():
114
+ """Health check endpoint"""
115
+ return jsonify({'status': 'healthy'})
116
+
117
+
118
+ @app.route('/documents/count', methods=['GET'])
119
+ def document_count():
120
+ """Get the count of documents in the vector store"""
121
+ try:
122
+ count = vector_store.get_all_documents_count()
123
+ return jsonify({'count': count})
124
+ except Exception as e:
125
+ logger.error(f"Error getting document count: {str(e)}")
126
+ return jsonify({'error': str(e)}), 500
127
+
128
+
129
+ if __name__ == '__main__':
130
+ app.run(debug=True, host='0.0.0.0', port=5000)
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ Flask>=2.3.0
2
+ Flask-CORS>=4.0.0
3
+ openai>=1.0.0
4
+ qdrant-client>=1.6.0
5
+ python-dotenv>=1.0.0
6
+ tiktoken>=0.5.0
7
+ langchain>=0.0.335
8
+ langchain-openai>=0.0.5