Skip to content

Commit 15c0c65

Browse files
authored
Merge pull request #65 from DefangLabs/jordan/uwsgi-lazy-apps
refactor RAGSystem initialization
2 parents d65b548 + 4e5921f commit 15c0c65

File tree

6 files changed

+18
-21
lines changed

6 files changed

+18
-21
lines changed

app/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,4 @@ RUN python test_intercom.py
4646
ENV FLASK_APP=app.py
4747

4848
# Run the application using uWSGI
49-
CMD ["uwsgi", "--http", "0.0.0.0:5050", "--wsgi-file", "app.py", "--callable", "app", "--processes", "4", "--threads", "2"]
49+
CMD ["uwsgi", "--lazy-apps", "--http", "0.0.0.0:5050", "--wsgi-file", "app.py", "--callable", "app", "--processes", "4", "--threads", "2"]

app/app.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from flask import Flask, request, jsonify, render_template, Response, stream_with_context, session, send_from_directory
22
from flask_wtf.csrf import CSRFProtect
3-
from rag_system import rag_system
3+
from rag_system import RAGSystem
44
import hashlib
55
import subprocess
66
import os
@@ -26,6 +26,8 @@
2626
app.config['SESSION_COOKIE_HTTPONLY'] = True
2727
app.config['SESSION_COOKIE_SECURE'] = bool(os.getenv('SESSION_COOKIE_SECURE'))
2828

29+
app.rag_system = RAGSystem()
30+
2931
csrf = CSRFProtect(app)
3032

3133
# Initialize Redis connection
@@ -52,13 +54,13 @@ def handle_ask_request(request, session):
5254
if 'anonymous_id' not in session:
5355
session['anonymous_id'] = str(uuid.uuid4())
5456
anonymous_id = session['anonymous_id']
55-
57+
5658
# Determine the source based on the user agent
5759
user_agent = request.headers.get('User-Agent', '')
5860
source = 'Ask Defang Discord Bot' if 'Discord Bot' in user_agent else 'Ask Defang Website'
5961

6062
# Use the shared generate function directly
61-
return Response(stream_with_context(generate(query, source, anonymous_id)), content_type='text/markdown')
63+
return Response(stream_with_context(generate(app.rag_system, query, source, anonymous_id)), content_type='text/markdown')
6264

6365
@app.route('/', methods=['GET', 'POST'])
6466
def index():
@@ -110,7 +112,7 @@ def trigger_rebuild():
110112

111113
print("Rebuilding embeddings...")
112114
try:
113-
rag_system.rebuild_embeddings()
115+
app.rag_system.rebuild_embeddings()
114116
except Exception as e:
115117
print(f"Error rebuilding embeddings: {str(e)}")
116118
return jsonify({"error": "Error rebuilding embeddings", "details": str(e)}), 500
@@ -136,7 +138,7 @@ def debug_context():
136138
query = data.get('query', '')
137139
if not query:
138140
return jsonify({"error": "Query is required"}), 400
139-
context = rag_system.get_context(query)
141+
context = app.rag_system.get_context(query)
140142
return jsonify({"context": context})
141143

142144

@@ -180,7 +182,7 @@ def handle_webhook():
180182
return 'OK'
181183
# Fetch the conversation and generate an LLM answer for the user
182184
logger.info(f"Detected a user reply in conversation {conversation_id}; fetching an answer from LLM...")
183-
answer_intercom_conversation(conversation_id)
185+
answer_intercom_conversation(app.rag_system, conversation_id)
184186
else:
185187
logger.info(f"Received webhook for unsupported topic: {topic}; no action taken.")
186188
return 'OK'

app/intercom.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def fetch_intercom_conversation(conversation_id):
4343
if response.status_code != 200:
4444
logger.error(f"Failed to fetch conversation {conversation_id} from Intercom; status code: {response.status_code}, response: {response.text}")
4545
return jsonify({"error": "Failed to fetch conversation from Intercom"}), response.status_code
46-
46+
4747
return response, response.status_code
4848

4949
# Determines the user query from the Intercom conversation response
@@ -123,7 +123,7 @@ def set_conversation_human_replied(conversation_id, redis_client):
123123
logger.info(f"Added conversation_id {conversation_id} to Redis set admin_replied_conversations")
124124
except Exception as e:
125125
logger.error(f"Error adding conversation_id to Redis: {e}")
126-
126+
127127
# Check if a conversation is already marked as replied by a human admin
128128
def is_conversation_human_replied(conversation_id, redis_client):
129129
try:
@@ -158,7 +158,7 @@ def post_intercom_reply(conversation_id, response_text):
158158

159159

160160
# Returns a generated LLM answer to the Intercom conversation based on previous user message history
161-
def answer_intercom_conversation(conversation_id):
161+
def answer_intercom_conversation(rag, conversation_id):
162162
logger.info(f"Received request to get conversation {conversation_id}")
163163
# Retrieves the history of the conversation thread in Intercom
164164
conversation, status_code = fetch_intercom_conversation(conversation_id)
@@ -174,9 +174,9 @@ def answer_intercom_conversation(conversation_id):
174174

175175
# Use a deterministic, non-reversible hash for anonymous_id for Intercom conversations
176176
anon_hash = hashlib.sha256(f"intercom-{conversation_id}".encode()).hexdigest()
177-
177+
178178
# Generate the exact response using the RAG system
179-
llm_response = "".join(generate(user_query, 'Intercom Conversation', anon_hash))
179+
llm_response = "".join(generate(rag, user_query, 'Intercom Conversation', anon_hash))
180180
llm_response = llm_response + " 🤖" # Add a marker to indicate the end of the response
181181

182182
logger.info(f"LLM response: {llm_response}")
@@ -200,5 +200,5 @@ def check_intercom_ip(request):
200200
if remote_ip not in INTERCOM_ALLOWED_IPS:
201201
# logger.info(f"Rejected webhook from unauthorized IP: {remote_ip}")
202202
return False
203-
203+
204204
return True

app/rag_system.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,3 @@ def get_context(self, retrieved_docs):
187187
for doc in retrieved_docs:
188188
retrieved_text.append(f"{doc['about']}. {doc['text']}")
189189
return "\n\n".join(retrieved_text)
190-
191-
# Instantiate the RAGSystem
192-
rag_system = RAGSystem()

app/utils.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
from rag_system import rag_system
21
import sys
32
import traceback
43
import segment.analytics as analytics
54

65
# Shared function to generate response stream from RAG system
7-
def generate(query, source, anonymous_id):
6+
def generate(rag, query, source, anonymous_id):
87
full_response = ""
98
print(f"Received query: {str(query)}", file=sys.stderr)
109
try:
11-
for token in rag_system.answer_query_stream(query):
10+
for token in rag.answer_query_stream(query):
1211
yield token
1312
full_response += token
1413
except Exception as e:
@@ -26,5 +25,5 @@ def generate(query, source, anonymous_id):
2625
event='Chatbot Question submitted',
2726
properties={'query': query, 'response': full_response, 'source': source}
2827
)
29-
28+
3029
return full_response

compose.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ services:
2626
INTERCOM_TOKEN:
2727
INTERCOM_ADMIN_ID:
2828
REDIS_URL: redis://redis:6379/0
29-
command: uwsgi --http 0.0.0.0:5050 --wsgi-file app.py --callable app --processes 4 --threads 2
3029
deploy:
3130
resources:
3231
reservations:

0 commit comments

Comments
 (0)