Spaces:
Sleeping
Sleeping
Commit ·
ec3c776
1
Parent(s): d527b21
Fix HF Space deployment - lazy load chatbot
Browse files- Dockerfile +7 -1
- app.py +31 -8
- requirements.txt +6 -0
- templates/base.html +10 -3
Dockerfile
CHANGED
|
@@ -2,6 +2,11 @@ FROM python:3.11-slim
|
|
| 2 |
|
| 3 |
WORKDIR /app
|
| 4 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
# Copy requirements and install dependencies
|
| 6 |
COPY requirements.txt .
|
| 7 |
RUN pip install --no-cache-dir -r requirements.txt
|
|
@@ -13,4 +18,5 @@ COPY . .
|
|
| 13 |
EXPOSE 7860
|
| 14 |
|
| 15 |
# Run the application with gunicorn
|
| 16 |
-
|
|
|
|
|
|
| 2 |
|
| 3 |
WORKDIR /app
|
| 4 |
|
| 5 |
+
# Install system dependencies
|
| 6 |
+
RUN apt-get update && apt-get install -y \
|
| 7 |
+
build-essential \
|
| 8 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 9 |
+
|
| 10 |
# Copy requirements and install dependencies
|
| 11 |
COPY requirements.txt .
|
| 12 |
RUN pip install --no-cache-dir -r requirements.txt
|
|
|
|
| 18 |
EXPOSE 7860
|
| 19 |
|
| 20 |
# Run the application with gunicorn
|
| 21 |
+
# Reduced workers to 2 and increased timeout for model loading
|
| 22 |
+
CMD ["gunicorn", "--bind", "0.0.0.0:7860", "--workers", "2", "--timeout", "300", "--preload", "app:app"]
|
app.py
CHANGED
|
@@ -10,7 +10,6 @@ load_dotenv()
|
|
| 10 |
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src'))
|
| 11 |
from recommendation_engine import RecommendationEngine
|
| 12 |
from recommendation_explainer import RecommendationExplainer
|
| 13 |
-
from rag import RAGChatbot
|
| 14 |
|
| 15 |
app = Flask(__name__)
|
| 16 |
app.secret_key = os.environ.get('SECRET_KEY', 'dev-secret-key-change-in-production')
|
|
@@ -21,14 +20,29 @@ recommendation_explainer = RecommendationExplainer()
|
|
| 21 |
|
| 22 |
# Initialize RAG chatbot (lazy initialization on first request)
|
| 23 |
rag_chatbot = None
|
|
|
|
|
|
|
| 24 |
|
| 25 |
def get_chatbot():
|
| 26 |
"""Get or initialize the RAG chatbot"""
|
| 27 |
-
global rag_chatbot
|
| 28 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
rag_chatbot = RAGChatbot()
|
| 30 |
rag_chatbot.initialize()
|
| 31 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
|
| 33 |
# Custom Jinja filter for simple markdown rendering
|
| 34 |
import re
|
|
@@ -130,6 +144,13 @@ def chat():
|
|
| 130 |
|
| 131 |
# Get chatbot and generate response
|
| 132 |
chatbot = get_chatbot()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 133 |
response = chatbot.chat(query)
|
| 134 |
|
| 135 |
return jsonify({
|
|
@@ -137,11 +158,13 @@ def chat():
|
|
| 137 |
"status": "success"
|
| 138 |
})
|
| 139 |
except Exception as e:
|
| 140 |
-
print(f"Error in chat endpoint: {e}")
|
|
|
|
|
|
|
| 141 |
return jsonify({
|
| 142 |
-
"
|
| 143 |
-
"status": "
|
| 144 |
-
})
|
| 145 |
|
| 146 |
if __name__ == '__main__':
|
| 147 |
app.run(debug=True, host='0.0.0.0', port=5555)
|
|
|
|
| 10 |
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src'))
|
| 11 |
from recommendation_engine import RecommendationEngine
|
| 12 |
from recommendation_explainer import RecommendationExplainer
|
|
|
|
| 13 |
|
| 14 |
app = Flask(__name__)
|
| 15 |
app.secret_key = os.environ.get('SECRET_KEY', 'dev-secret-key-change-in-production')
|
|
|
|
| 20 |
|
| 21 |
# Initialize RAG chatbot (lazy initialization on first request)
|
| 22 |
rag_chatbot = None
|
| 23 |
+
chatbot_initialized = False
|
| 24 |
+
chatbot_error = None
|
| 25 |
|
| 26 |
def get_chatbot():
|
| 27 |
"""Get or initialize the RAG chatbot"""
|
| 28 |
+
global rag_chatbot, chatbot_initialized, chatbot_error
|
| 29 |
+
|
| 30 |
+
if chatbot_initialized:
|
| 31 |
+
return rag_chatbot
|
| 32 |
+
|
| 33 |
+
try:
|
| 34 |
+
print("🤖 Initializing RAG chatbot...")
|
| 35 |
+
from rag import RAGChatbot
|
| 36 |
rag_chatbot = RAGChatbot()
|
| 37 |
rag_chatbot.initialize()
|
| 38 |
+
chatbot_initialized = True
|
| 39 |
+
print("✅ RAG chatbot initialized successfully")
|
| 40 |
+
return rag_chatbot
|
| 41 |
+
except Exception as e:
|
| 42 |
+
chatbot_error = str(e)
|
| 43 |
+
chatbot_initialized = True # Mark as initialized to avoid retrying
|
| 44 |
+
print(f"❌ Failed to initialize chatbot: {e}")
|
| 45 |
+
return None
|
| 46 |
|
| 47 |
# Custom Jinja filter for simple markdown rendering
|
| 48 |
import re
|
|
|
|
| 144 |
|
| 145 |
# Get chatbot and generate response
|
| 146 |
chatbot = get_chatbot()
|
| 147 |
+
|
| 148 |
+
if chatbot is None:
|
| 149 |
+
return jsonify({
|
| 150 |
+
"response": "Sorry, the chatbot is currently unavailable. Please try again later or contact support.",
|
| 151 |
+
"status": "success"
|
| 152 |
+
})
|
| 153 |
+
|
| 154 |
response = chatbot.chat(query)
|
| 155 |
|
| 156 |
return jsonify({
|
|
|
|
| 158 |
"status": "success"
|
| 159 |
})
|
| 160 |
except Exception as e:
|
| 161 |
+
print(f"❌ Error in chat endpoint: {e}")
|
| 162 |
+
import traceback
|
| 163 |
+
traceback.print_exc()
|
| 164 |
return jsonify({
|
| 165 |
+
"response": "Sorry, I encountered an error processing your question. Please try again.",
|
| 166 |
+
"status": "success"
|
| 167 |
+
})
|
| 168 |
|
| 169 |
if __name__ == '__main__':
|
| 170 |
app.run(debug=True, host='0.0.0.0', port=5555)
|
requirements.txt
CHANGED
|
@@ -9,3 +9,9 @@ pandas==2.3.0
|
|
| 9 |
plotly==5.24.1
|
| 10 |
openai>=1.0.0
|
| 11 |
gunicorn==23.0.0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
plotly==5.24.1
|
| 10 |
openai>=1.0.0
|
| 11 |
gunicorn==23.0.0
|
| 12 |
+
requests>=2.32.0
|
| 13 |
+
python-frontmatter>=1.1.0
|
| 14 |
+
sentence-transformers>=2.2.0
|
| 15 |
+
tqdm>=4.65.0
|
| 16 |
+
numpy>=1.24.0
|
| 17 |
+
minsearch>=0.0.7
|
templates/base.html
CHANGED
|
@@ -335,21 +335,28 @@
|
|
| 335 |
headers: {
|
| 336 |
'Content-Type': 'application/json',
|
| 337 |
},
|
| 338 |
-
body: JSON.stringify({ message: message })
|
|
|
|
| 339 |
});
|
| 340 |
|
| 341 |
const data = await response.json();
|
| 342 |
removeTyping();
|
| 343 |
|
| 344 |
-
if (data.status === 'success') {
|
| 345 |
addMessage(data.response);
|
|
|
|
|
|
|
| 346 |
} else {
|
| 347 |
addMessage('Sorry, I encountered an error. Please try again.');
|
| 348 |
}
|
| 349 |
} catch (error) {
|
| 350 |
console.error('Chat error:', error);
|
| 351 |
removeTyping();
|
| 352 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 353 |
} finally {
|
| 354 |
// Re-enable input
|
| 355 |
chatbotInput.disabled = false;
|
|
|
|
| 335 |
headers: {
|
| 336 |
'Content-Type': 'application/json',
|
| 337 |
},
|
| 338 |
+
body: JSON.stringify({ message: message }),
|
| 339 |
+
signal: AbortSignal.timeout(60000) // 60 second timeout
|
| 340 |
});
|
| 341 |
|
| 342 |
const data = await response.json();
|
| 343 |
removeTyping();
|
| 344 |
|
| 345 |
+
if (data.status === 'success' && data.response) {
|
| 346 |
addMessage(data.response);
|
| 347 |
+
} else if (data.error) {
|
| 348 |
+
addMessage(data.error);
|
| 349 |
} else {
|
| 350 |
addMessage('Sorry, I encountered an error. Please try again.');
|
| 351 |
}
|
| 352 |
} catch (error) {
|
| 353 |
console.error('Chat error:', error);
|
| 354 |
removeTyping();
|
| 355 |
+
if (error.name === 'TimeoutError') {
|
| 356 |
+
addMessage('Sorry, the request timed out. The chatbot may be initializing. Please try again in a moment.');
|
| 357 |
+
} else {
|
| 358 |
+
addMessage('Sorry, I encountered an error. Please try again later.');
|
| 359 |
+
}
|
| 360 |
} finally {
|
| 361 |
// Re-enable input
|
| 362 |
chatbotInput.disabled = false;
|