Spaces:
Paused
Paused
Commit
·
89511c3
1
Parent(s):
ce7ced7
chatbot updated
Browse files- app.py +30 -24
- backend/templates/base.html +39 -13
- requirements.txt +0 -3
app.py
CHANGED
|
@@ -34,13 +34,14 @@ import json
|
|
| 34 |
# -----------------------------------------------------------------------------
|
| 35 |
# Chatbot setup
|
| 36 |
#
|
| 37 |
-
# The chatbot
|
| 38 |
-
# ``chatbot/chatbot.txt`` knowledge base
|
| 39 |
-
#
|
| 40 |
-
#
|
| 41 |
-
#
|
| 42 |
-
#
|
| 43 |
-
#
|
|
|
|
| 44 |
|
| 45 |
# Paths for the chatbot knowledge base and persistent vector store. We
|
| 46 |
# compute these relative to the current file so that the app can be deployed
|
|
@@ -56,42 +57,47 @@ CHATBOT_DB_DIR = "/tmp/chroma_db"
|
|
| 56 |
# -----------------------------------------------------------------------------
|
| 57 |
# Hugging Face model configuration
|
| 58 |
#
|
| 59 |
-
# The
|
| 60 |
-
#
|
| 61 |
-
#
|
| 62 |
-
#
|
| 63 |
-
#
|
| 64 |
-
|
| 65 |
-
# another conversational model (e.g. ``microsoft/DialoGPT-medium``), update
|
| 66 |
-
# this constant accordingly. The model and tokenizer are loaded lazily in
|
| 67 |
-
# ``init_hf_model()`` to avoid impacting application startup time.
|
| 68 |
-
HF_MODEL_NAME = "facebook/blenderbot-400M-distill"
|
| 69 |
|
| 70 |
# Global Hugging Face model and tokenizer. These variables remain ``None``
|
| 71 |
# until ``init_hf_model()`` is called. They are reused across all chatbot
|
| 72 |
# requests to prevent repeatedly loading the large model into memory.
|
| 73 |
-
_hf_model = None
|
| 74 |
-
_hf_tokenizer = None
|
| 75 |
|
| 76 |
def init_hf_model() -> None:
|
| 77 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
global _hf_model, _hf_tokenizer
|
| 79 |
if _hf_model is not None and _hf_tokenizer is not None:
|
| 80 |
return
|
| 81 |
|
| 82 |
-
from transformers import AutoModelForSeq2SeqLM, AutoTokenizer
|
| 83 |
import torch
|
| 84 |
|
| 85 |
-
model_name =
|
| 86 |
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
| 87 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 88 |
tokenizer = AutoTokenizer.from_pretrained(model_name)
|
| 89 |
model = AutoModelForSeq2SeqLM.from_pretrained(model_name).to(device)
|
| 90 |
|
| 91 |
_hf_model = model
|
| 92 |
_hf_tokenizer = tokenizer
|
| 93 |
-
|
| 94 |
-
HF_MODEL_NAME = "facebook/blenderbot-400M-distill"
|
| 95 |
_chatbot_embedder = None
|
| 96 |
_chatbot_collection = None
|
| 97 |
|
|
|
|
| 34 |
# -----------------------------------------------------------------------------
|
| 35 |
# Chatbot setup
|
| 36 |
#
|
| 37 |
+
# The chatbot uses a local vector database (Chroma) to search the
|
| 38 |
+
# ``chatbot/chatbot.txt`` knowledge base. Retrieved passages are fed to
|
| 39 |
+
# a lightweight conversational model from Hugging Face (see
|
| 40 |
+
# ``init_hf_model`` below). To avoid the expensive model and database
|
| 41 |
+
# initialisation on every request, embeddings and the vector collection are
|
| 42 |
+
# loaded lazily the first time a chat query is processed. Subsequent
|
| 43 |
+
# requests reuse the same global objects. See ``init_chatbot`` and
|
| 44 |
+
# ``get_chatbot_response`` for implementation details.
|
| 45 |
|
| 46 |
# Paths for the chatbot knowledge base and persistent vector store. We
|
| 47 |
# compute these relative to the current file so that the app can be deployed
|
|
|
|
| 57 |
# -----------------------------------------------------------------------------
|
| 58 |
# Hugging Face model configuration
|
| 59 |
#
|
| 60 |
+
# The chatbot uses a small conversational model hosted on Hugging Face. To
|
| 61 |
+
# allow easy experimentation, the model name can be overridden via the
|
| 62 |
+
# ``HF_CHATBOT_MODEL`` environment variable. If unset, we fall back to
|
| 63 |
+
# ``facebook/blenderbot-400M-distill`` which provides a good balance of
|
| 64 |
+
# quality and resource usage and is freely available without authentication.
|
| 65 |
+
HF_MODEL_NAME = os.getenv("HF_CHATBOT_MODEL", "facebook/blenderbot-400M-distill")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
|
| 67 |
# Global Hugging Face model and tokenizer. These variables remain ``None``
|
| 68 |
# until ``init_hf_model()`` is called. They are reused across all chatbot
|
| 69 |
# requests to prevent repeatedly loading the large model into memory.
|
| 70 |
+
_hf_model: 'AutoModelForSeq2SeqLM | None' = None # type: ignore[type-arg]
|
| 71 |
+
_hf_tokenizer: 'AutoTokenizer | None' = None # type: ignore[type-arg]
|
| 72 |
|
| 73 |
def init_hf_model() -> None:
|
| 74 |
+
"""
|
| 75 |
+
Initialise the Hugging Face conversational model and tokenizer.
|
| 76 |
+
|
| 77 |
+
This function loads the specified ``HF_MODEL_NAME`` model and its
|
| 78 |
+
corresponding tokenizer. The model is moved to GPU if available,
|
| 79 |
+
otherwise it runs on CPU. Subsequent calls return immediately if
|
| 80 |
+
the model and tokenizer have already been instantiated.
|
| 81 |
+
"""
|
| 82 |
global _hf_model, _hf_tokenizer
|
| 83 |
if _hf_model is not None and _hf_tokenizer is not None:
|
| 84 |
return
|
| 85 |
|
| 86 |
+
from transformers import AutoModelForSeq2SeqLM, AutoTokenizer # type: ignore
|
| 87 |
import torch
|
| 88 |
|
| 89 |
+
model_name = HF_MODEL_NAME
|
| 90 |
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
| 91 |
|
| 92 |
+
# Load tokenizer and model from Hugging Face. We deliberately avoid
|
| 93 |
+
# specifying ``use_auth_token`` here since the default models are
|
| 94 |
+
# publicly accessible. Should you wish to use a private model, set
|
| 95 |
+
# HF_HOME/HF_TOKEN environment variables accordingly.
|
| 96 |
tokenizer = AutoTokenizer.from_pretrained(model_name)
|
| 97 |
model = AutoModelForSeq2SeqLM.from_pretrained(model_name).to(device)
|
| 98 |
|
| 99 |
_hf_model = model
|
| 100 |
_hf_tokenizer = tokenizer
|
|
|
|
|
|
|
| 101 |
_chatbot_embedder = None
|
| 102 |
_chatbot_collection = None
|
| 103 |
|
backend/templates/base.html
CHANGED
|
@@ -778,7 +778,13 @@
|
|
| 778 |
|
| 779 |
#CHATBOT START
|
| 780 |
<!-- Chatbot Toggle Button -->
|
| 781 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 782 |
|
| 783 |
<!-- Chatbox Popup -->
|
| 784 |
<div id="chatbot-box">
|
|
@@ -790,29 +796,41 @@
|
|
| 790 |
<style>
|
| 791 |
#chatbot-toggle {
|
| 792 |
position: fixed;
|
| 793 |
-
bottom:
|
| 794 |
-
right:
|
| 795 |
background-color: #4caf50;
|
| 796 |
color: white;
|
| 797 |
-
padding:
|
| 798 |
border-radius: 30px;
|
| 799 |
cursor: pointer;
|
| 800 |
z-index: 1000;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 801 |
}
|
| 802 |
|
| 803 |
#chatbot-box {
|
| 804 |
position: fixed;
|
| 805 |
-
bottom:
|
| 806 |
-
right:
|
| 807 |
/* Default dimensions for larger screens */
|
| 808 |
-
width:
|
| 809 |
-
height:
|
| 810 |
background: white;
|
| 811 |
border: 2px solid #ccc;
|
| 812 |
border-radius: 10px;
|
| 813 |
display: none;
|
| 814 |
flex-direction: column;
|
| 815 |
z-index: 1000;
|
|
|
|
| 816 |
}
|
| 817 |
|
| 818 |
#chat-header {
|
|
@@ -835,18 +853,26 @@
|
|
| 835 |
#chatbot-box {
|
| 836 |
width: 90vw;
|
| 837 |
height: 60vh;
|
| 838 |
-
bottom:
|
| 839 |
right: 5vw;
|
| 840 |
}
|
| 841 |
#chat-messages {
|
| 842 |
-
max-height: calc(60vh -
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 843 |
}
|
| 844 |
}
|
|
|
|
| 845 |
@media (max-width: 400px) {
|
| 846 |
#chatbot-toggle {
|
| 847 |
-
bottom:
|
| 848 |
-
right:
|
| 849 |
-
padding:
|
|
|
|
| 850 |
}
|
| 851 |
}
|
| 852 |
|
|
|
|
| 778 |
|
| 779 |
#CHATBOT START
|
| 780 |
<!-- Chatbot Toggle Button -->
|
| 781 |
+
<!--
|
| 782 |
+
The floating chat button toggles the visibility of the chat window.
|
| 783 |
+
We use a flex container here to ensure the emoji and text remain
|
| 784 |
+
centred on all screen sizes. Additional media queries adjust the
|
| 785 |
+
button's position and padding for very small viewports.
|
| 786 |
+
-->
|
| 787 |
+
<div id="chatbot-toggle" onclick="toggleChatbot()">💬 Chat</div>
|
| 788 |
|
| 789 |
<!-- Chatbox Popup -->
|
| 790 |
<div id="chatbot-box">
|
|
|
|
| 796 |
<style>
|
| 797 |
#chatbot-toggle {
|
| 798 |
position: fixed;
|
| 799 |
+
bottom: 1rem;
|
| 800 |
+
right: 1rem;
|
| 801 |
background-color: #4caf50;
|
| 802 |
color: white;
|
| 803 |
+
padding: 0.75rem 1rem;
|
| 804 |
border-radius: 30px;
|
| 805 |
cursor: pointer;
|
| 806 |
z-index: 1000;
|
| 807 |
+
display: flex;
|
| 808 |
+
align-items: center;
|
| 809 |
+
justify-content: center;
|
| 810 |
+
font-size: 1rem;
|
| 811 |
+
line-height: 1;
|
| 812 |
+
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);
|
| 813 |
+
transition: background-color 0.2s ease;
|
| 814 |
+
}
|
| 815 |
+
|
| 816 |
+
#chatbot-toggle:hover {
|
| 817 |
+
background-color: #43a047; /* slightly darker green on hover */
|
| 818 |
}
|
| 819 |
|
| 820 |
#chatbot-box {
|
| 821 |
position: fixed;
|
| 822 |
+
bottom: calc(1rem + 3.5rem); /* sit above the toggle on desktop */
|
| 823 |
+
right: 1rem;
|
| 824 |
/* Default dimensions for larger screens */
|
| 825 |
+
width: 20rem;
|
| 826 |
+
height: 25rem;
|
| 827 |
background: white;
|
| 828 |
border: 2px solid #ccc;
|
| 829 |
border-radius: 10px;
|
| 830 |
display: none;
|
| 831 |
flex-direction: column;
|
| 832 |
z-index: 1000;
|
| 833 |
+
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1);
|
| 834 |
}
|
| 835 |
|
| 836 |
#chat-header {
|
|
|
|
| 853 |
#chatbot-box {
|
| 854 |
width: 90vw;
|
| 855 |
height: 60vh;
|
| 856 |
+
bottom: calc(1rem + 3rem);
|
| 857 |
right: 5vw;
|
| 858 |
}
|
| 859 |
#chat-messages {
|
| 860 |
+
max-height: calc(60vh - 5.5rem);
|
| 861 |
+
}
|
| 862 |
+
#chatbot-toggle {
|
| 863 |
+
bottom: 1rem;
|
| 864 |
+
right: 1rem;
|
| 865 |
+
padding: 0.65rem 0.9rem;
|
| 866 |
+
font-size: 0.9rem;
|
| 867 |
}
|
| 868 |
}
|
| 869 |
+
|
| 870 |
@media (max-width: 400px) {
|
| 871 |
#chatbot-toggle {
|
| 872 |
+
bottom: 0.75rem;
|
| 873 |
+
right: 0.75rem;
|
| 874 |
+
padding: 0.6rem 0.8rem;
|
| 875 |
+
font-size: 0.85rem;
|
| 876 |
}
|
| 877 |
}
|
| 878 |
|
requirements.txt
CHANGED
|
@@ -1,6 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
flask
|
| 5 |
flask_login
|
| 6 |
flask_sqlalchemy
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
flask
|
| 2 |
flask_login
|
| 3 |
flask_sqlalchemy
|