Spaces:
Sleeping
Sleeping
Ritesh Thawkar
commited on
Commit
•
6e443ec
1
Parent(s):
d514a44
initial commit
Browse files- .env +4 -0
- Dockerfile +16 -0
- app.py +214 -0
- requirements.txt +101 -0
- saudi-arabia-moj.json +0 -0
- semantic-saudi-arabia-moj.json +0 -0
- static/script.js +95 -0
- static/styles.css +130 -0
- templates/chat.html +28 -0
- test.ipynb +199 -0
.env
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
GROQ_API_KEY=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
|
2 |
+
PINECONE_API_KEY=30da2936-0cb1-49b8-a217-767e624dc745
|
3 |
+
USER_AGENT=myagent
|
4 |
+
SECRET_KEY=QKj6DmiZqULOmYRFWWiOWGdyb3FYPRoLPlLNZe9JUGhwkUylIe6s
|
Dockerfile
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Read the doc: https://huggingface.co/docs/hub/spaces-sdks-docker
|
2 |
+
# you will also find guides on how best to write your Dockerfile
|
3 |
+
|
4 |
+
FROM python:3.9
|
5 |
+
|
6 |
+
RUN useradd -m -u 1000 user
|
7 |
+
USER user
|
8 |
+
ENV PATH="/home/user/.local/bin:$PATH"
|
9 |
+
|
10 |
+
WORKDIR /app
|
11 |
+
|
12 |
+
COPY --chown=user ./requirements.txt requirements.txt
|
13 |
+
RUN pip install --no-cache-dir --upgrade -r requirements.txt
|
14 |
+
|
15 |
+
COPY --chown=user . /app
|
16 |
+
CMD ["gunicorn", "-b", "0.0.0.0:7860", "-k", "eventlet", "app:app"]
|
app.py
ADDED
@@ -0,0 +1,214 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import nltk
|
2 |
+
nltk.download('punkt_tab')
|
3 |
+
|
4 |
+
import os
|
5 |
+
from dotenv import load_dotenv
|
6 |
+
from flask import Flask, request, render_template
|
7 |
+
from flask_cors import CORS
|
8 |
+
from flask_socketio import SocketIO, emit, join_room, leave_room
|
9 |
+
from langchain.chains import create_history_aware_retriever, create_retrieval_chain
|
10 |
+
from langchain.chains.combine_documents import create_stuff_documents_chain
|
11 |
+
from langchain_community.chat_message_histories import ChatMessageHistory
|
12 |
+
from langchain_core.chat_history import BaseChatMessageHistory
|
13 |
+
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
14 |
+
from langchain_core.runnables.history import RunnableWithMessageHistory
|
15 |
+
from pinecone import Pinecone
|
16 |
+
from pinecone_text.sparse import BM25Encoder
|
17 |
+
from langchain_huggingface import HuggingFaceEmbeddings
|
18 |
+
from langchain_community.retrievers import PineconeHybridSearchRetriever
|
19 |
+
from langchain_groq import ChatGroq
|
20 |
+
|
21 |
+
# Load environment variables
|
22 |
+
load_dotenv(".env")
|
23 |
+
USER_AGENT = os.getenv("USER_AGENT")
|
24 |
+
GROQ_API_KEY = os.getenv("GROQ_API_KEY")
|
25 |
+
SECRET_KEY = os.getenv("SECRET_KEY")
|
26 |
+
PINECONE_API_KEY = os.getenv("PINECONE_API_KEY")
|
27 |
+
SESSION_ID_DEFAULT = "abc123"
|
28 |
+
|
29 |
+
# Set environment variables
|
30 |
+
os.environ['USER_AGENT'] = USER_AGENT
|
31 |
+
os.environ["GROQ_API_KEY"] = GROQ_API_KEY
|
32 |
+
os.environ["TOKENIZERS_PARALLELISM"] = 'true'
|
33 |
+
|
34 |
+
# Initialize Flask app and SocketIO with CORS
|
35 |
+
app = Flask(__name__)
|
36 |
+
CORS(app)
|
37 |
+
socketio = SocketIO(app, cors_allowed_origins="*")
|
38 |
+
app.config['SESSION_COOKIE_SECURE'] = True # Use HTTPS
|
39 |
+
app.config['SESSION_COOKIE_HTTPONLY'] = True
|
40 |
+
app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'
|
41 |
+
app.config['SECRET_KEY'] = SECRET_KEY
|
42 |
+
|
43 |
+
# Function to initialize Pinecone connection
|
44 |
+
def initialize_pinecone(index_name: str):
|
45 |
+
try:
|
46 |
+
pc = Pinecone(api_key=PINECONE_API_KEY)
|
47 |
+
return pc.Index(index_name)
|
48 |
+
except Exception as e:
|
49 |
+
print(f"Error initializing Pinecone: {e}")
|
50 |
+
raise
|
51 |
+
|
52 |
+
|
53 |
+
##################################################
|
54 |
+
## Change down here
|
55 |
+
##################################################
|
56 |
+
|
57 |
+
# Initialize Pinecone index and BM25 encoder
|
58 |
+
# pinecone_index = initialize_pinecone("uae-national-library-and-archives-vectorstore")
|
59 |
+
# bm25 = BM25Encoder().load("./UAE-NLA.json")
|
60 |
+
|
61 |
+
### This is for UAE Legislation Website
|
62 |
+
# pinecone_index = initialize_pinecone("uae-legislation-site-data")
|
63 |
+
# bm25 = BM25Encoder().load("./bm25_uae_legislation_data.json")
|
64 |
+
|
65 |
+
|
66 |
+
### This is for u.ae Website
|
67 |
+
# pinecone_index = initialize_pinecone("vector-store-index")
|
68 |
+
# bm25 = BM25Encoder().load("./bm25_u.ae.json")
|
69 |
+
|
70 |
+
|
71 |
+
# #### This is for UAE Economic Department Website
|
72 |
+
pinecone_index = initialize_pinecone("semantic-saudi-arabia-ministry-of-justice")
|
73 |
+
bm25 = BM25Encoder().load("./semantic-saudi-arabia-moj.json")
|
74 |
+
|
75 |
+
|
76 |
+
|
77 |
+
##################################################
|
78 |
+
##################################################
|
79 |
+
|
80 |
+
|
81 |
+
# Initialize models and retriever
|
82 |
+
embed_model = HuggingFaceEmbeddings(model_name="jinaai/jina-embeddings-v3", model_kwargs={"trust_remote_code":True})
|
83 |
+
retriever = PineconeHybridSearchRetriever(
|
84 |
+
embeddings=embed_model,
|
85 |
+
sparse_encoder=bm25,
|
86 |
+
index=pinecone_index,
|
87 |
+
top_k=20,
|
88 |
+
alpha=0.5
|
89 |
+
)
|
90 |
+
|
91 |
+
# Initialize LLM
|
92 |
+
llm = ChatGroq(model="llama-3.1-70b-versatile", temperature=0, max_tokens=1024, max_retries=2)
|
93 |
+
|
94 |
+
# Contextualization prompt and retriever
|
95 |
+
contextualize_q_system_prompt = """Given a chat history and the latest user question \
|
96 |
+
which might reference context in the chat history, formulate a standalone question \
|
97 |
+
which can be understood without the chat history. Do NOT answer the question, \
|
98 |
+
just reformulate it if needed and otherwise return it as is.
|
99 |
+
"""
|
100 |
+
contextualize_q_prompt = ChatPromptTemplate.from_messages(
|
101 |
+
[
|
102 |
+
("system", contextualize_q_system_prompt),
|
103 |
+
MessagesPlaceholder("chat_history"),
|
104 |
+
("human", "{input}")
|
105 |
+
]
|
106 |
+
)
|
107 |
+
history_aware_retriever = create_history_aware_retriever(llm, retriever, contextualize_q_prompt)
|
108 |
+
|
109 |
+
# QA system prompt and chain
|
110 |
+
qa_system_prompt = """You are a highly skilled information retrieval assistant. Use the following context to answer questions effectively. \
|
111 |
+
If you don't know the answer, simply state that you don't know. \
|
112 |
+
Your answer should be in {language} language. \
|
113 |
+
Provide answers in proper HTML format and keep them concise. \
|
114 |
+
|
115 |
+
When responding to queries, follow these guidelines: \
|
116 |
+
|
117 |
+
1. Provide Clear Answers: \
|
118 |
+
- Based on the language of the question, you have to answer in that language. E.g. if the question is in English language then answer in the English language or if the question is in Arabic language then you should answer in Arabic language. /
|
119 |
+
- Ensure the response directly addresses the query with accurate and relevant information.\
|
120 |
+
|
121 |
+
2. Include Detailed References: \
|
122 |
+
- Links to Sources: Include URLs to credible sources where users can verify information or explore further. \
|
123 |
+
- Reference Sites: Mention specific websites or platforms that offer additional information. \
|
124 |
+
- Downloadable Materials: Provide links to any relevant downloadable resources if applicable. \
|
125 |
+
|
126 |
+
3. Formatting for Readability: \
|
127 |
+
- The answer should be in a proper HTML format with appropriate tags. \
|
128 |
+
- For arabic language response align the text to right and convert numbers also.
|
129 |
+
- Double check if the language of answer is correct or not.
|
130 |
+
- Use bullet points or numbered lists where applicable to present information clearly. \
|
131 |
+
- Highlight key details using bold or italics. \
|
132 |
+
- Provide proper and meaningful abbreviations for urls. Do not include naked urls. \
|
133 |
+
|
134 |
+
4. Organize Content Logically: \
|
135 |
+
- Structure the content in a logical order, ensuring easy navigation and understanding for the user. \
|
136 |
+
|
137 |
+
{context}
|
138 |
+
"""
|
139 |
+
qa_prompt = ChatPromptTemplate.from_messages(
|
140 |
+
[
|
141 |
+
("system", qa_system_prompt),
|
142 |
+
MessagesPlaceholder("chat_history"),
|
143 |
+
("human", "{input}")
|
144 |
+
]
|
145 |
+
)
|
146 |
+
question_answer_chain = create_stuff_documents_chain(llm, qa_prompt)
|
147 |
+
|
148 |
+
# Retrieval and Generative (RAG) Chain
|
149 |
+
rag_chain = create_retrieval_chain(history_aware_retriever, question_answer_chain)
|
150 |
+
|
151 |
+
# Chat message history storage
|
152 |
+
store = {}
|
153 |
+
|
154 |
+
def clean_temporary_data():
|
155 |
+
store.clear()
|
156 |
+
|
157 |
+
def get_session_history(session_id: str) -> BaseChatMessageHistory:
|
158 |
+
if session_id not in store:
|
159 |
+
store[session_id] = ChatMessageHistory()
|
160 |
+
return store[session_id]
|
161 |
+
|
162 |
+
# Conversational RAG chain with message history
|
163 |
+
conversational_rag_chain = RunnableWithMessageHistory(
|
164 |
+
rag_chain,
|
165 |
+
get_session_history,
|
166 |
+
input_messages_key="input",
|
167 |
+
history_messages_key="chat_history",
|
168 |
+
language_message_key="language",
|
169 |
+
output_messages_key="answer",
|
170 |
+
)
|
171 |
+
|
172 |
+
# Function to handle WebSocket connection
|
173 |
+
@socketio.on('connect')
|
174 |
+
def handle_connect():
|
175 |
+
print(f"Client connected: {request.sid}")
|
176 |
+
emit('connection_response', {'message': 'Connected successfully.'})
|
177 |
+
|
178 |
+
# Function to handle WebSocket disconnection
|
179 |
+
@socketio.on('disconnect')
|
180 |
+
def handle_disconnect():
|
181 |
+
print(f"Client disconnected: {request.sid}")
|
182 |
+
clean_temporary_data()
|
183 |
+
|
184 |
+
# Function to handle WebSocket messages
|
185 |
+
@socketio.on('message')
|
186 |
+
def handle_message(data):
|
187 |
+
question = data.get('question')
|
188 |
+
language = data.get('language')
|
189 |
+
if "en" in language:
|
190 |
+
language = "English"
|
191 |
+
else:
|
192 |
+
language = "Arabic"
|
193 |
+
session_id = data.get('session_id', SESSION_ID_DEFAULT)
|
194 |
+
chain = conversational_rag_chain.pick("answer")
|
195 |
+
|
196 |
+
try:
|
197 |
+
for chunk in chain.stream(
|
198 |
+
{"input": question, 'language': language},
|
199 |
+
config={"configurable": {"session_id": session_id}},
|
200 |
+
):
|
201 |
+
emit('response', chunk, room=request.sid)
|
202 |
+
except Exception as e:
|
203 |
+
print(f"Error during message handling: {e}")
|
204 |
+
emit('response', {"error": "An error occurred while processing your request."}, room=request.sid)
|
205 |
+
|
206 |
+
|
207 |
+
# Home route
|
208 |
+
@app.route("/")
|
209 |
+
def index_view():
|
210 |
+
return render_template('chat.html')
|
211 |
+
|
212 |
+
# Main function to run the app
|
213 |
+
if __name__ == '__main__':
|
214 |
+
socketio.run(app, debug=True)
|
requirements.txt
ADDED
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
aiohttp==3.9.5
|
2 |
+
aiosignal==1.3.1
|
3 |
+
annotated-types==0.7.0
|
4 |
+
anyio==4.4.0
|
5 |
+
async-timeout==4.0.3
|
6 |
+
attrs==23.2.0
|
7 |
+
bidict==0.23.1
|
8 |
+
blinker==1.8.2
|
9 |
+
certifi==2024.7.4
|
10 |
+
charset-normalizer==3.3.2
|
11 |
+
click==8.1.7
|
12 |
+
dataclasses-json==0.6.7
|
13 |
+
distro==1.9.0
|
14 |
+
dnspython==2.6.1
|
15 |
+
eventlet==0.36.1
|
16 |
+
exceptiongroup==1.2.2
|
17 |
+
filelock==3.15.4
|
18 |
+
flask==3.0.3
|
19 |
+
Flask-Cors==4.0.1
|
20 |
+
Flask-SocketIO==5.3.6
|
21 |
+
frozenlist==1.4.1
|
22 |
+
fsspec==2024.6.1
|
23 |
+
greenlet==3.0.3
|
24 |
+
groq==0.9.0
|
25 |
+
gunicorn==23.0.0
|
26 |
+
h11==0.14.0
|
27 |
+
httpcore==1.0.5
|
28 |
+
httpx==0.27.0
|
29 |
+
huggingface-hub==0.24.2
|
30 |
+
idna==3.7
|
31 |
+
importlib-metadata==8.2.0
|
32 |
+
itsdangerous==2.2.0
|
33 |
+
jinja2==3.1.4
|
34 |
+
joblib==1.4.2
|
35 |
+
jsonpatch==1.33
|
36 |
+
jsonpointer==3.0.0
|
37 |
+
langchain
|
38 |
+
langchain-community
|
39 |
+
langchain-core
|
40 |
+
langchain-groq
|
41 |
+
langchain-huggingface
|
42 |
+
langchain-text-splitters
|
43 |
+
MarkupSafe==2.1.5
|
44 |
+
marshmallow==3.21.3
|
45 |
+
mmh3==4.1.0
|
46 |
+
mpmath==1.3.0
|
47 |
+
multidict==6.0.5
|
48 |
+
mypy-extensions==1.0.0
|
49 |
+
networkx==3.1
|
50 |
+
nltk==3.8.1
|
51 |
+
# numpy==1.24.4
|
52 |
+
# nvidia-cublas-cu12==12.1.3.1
|
53 |
+
# nvidia-cuda-cupti-cu12==12.1.105
|
54 |
+
# nvidia-cuda-nvrtc-cu12==12.1.105
|
55 |
+
# nvidia-cuda-runtime-cu12==12.1.105
|
56 |
+
# nvidia-cudnn-cu12==9.1.0.70
|
57 |
+
# nvidia-cufft-cu12==11.0.2.54
|
58 |
+
# nvidia-curand-cu12==10.3.2.106
|
59 |
+
# nvidia-cusolver-cu12==11.4.5.107
|
60 |
+
# nvidia-cusparse-cu12==12.1.0.106
|
61 |
+
# nvidia-nccl-cu12==2.20.5
|
62 |
+
# nvidia-nvjitlink-cu12==12.5.82
|
63 |
+
# nvidia-nvtx-cu12==12.1.105
|
64 |
+
orjson==3.10.6
|
65 |
+
packaging==24.1
|
66 |
+
pillow==10.4.0
|
67 |
+
pinecone==4.0.0
|
68 |
+
pinecone-text==0.9.0
|
69 |
+
pydantic==2.8.2
|
70 |
+
pydantic-core==2.20.1
|
71 |
+
python-dotenv==1.0.1
|
72 |
+
python-engineio==4.9.1
|
73 |
+
python-socketio==5.11.3
|
74 |
+
PyYAML==6.0.1
|
75 |
+
regex==2024.7.24
|
76 |
+
requests==2.32.3
|
77 |
+
safetensors==0.4.3
|
78 |
+
scikit-learn==1.3.2
|
79 |
+
scipy==1.10.1
|
80 |
+
sentence-transformers==3.0.1
|
81 |
+
simple-websocket==1.0.0
|
82 |
+
sniffio==1.3.1
|
83 |
+
SQLAlchemy==2.0.31
|
84 |
+
sympy==1.13.1
|
85 |
+
tenacity==8.5.0
|
86 |
+
threadpoolctl==3.5.0
|
87 |
+
tokenizers==0.19.1
|
88 |
+
torch==2.4.0
|
89 |
+
tqdm==4.66.4
|
90 |
+
transformers==4.43.3
|
91 |
+
triton==3.0.0
|
92 |
+
types-requests==2.32.0.20240712
|
93 |
+
typing-extensions==4.12.2
|
94 |
+
typing-inspect==0.9.0
|
95 |
+
urllib3==2.2.2
|
96 |
+
werkzeug==3.0.3
|
97 |
+
wget==3.2
|
98 |
+
wsproto==1.2.0
|
99 |
+
yarl==1.9.4
|
100 |
+
zipp==3.19.2
|
101 |
+
einops==0.8.0
|
saudi-arabia-moj.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
semantic-saudi-arabia-moj.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
static/script.js
ADDED
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const socket = io.connect(document.baseURI);
|
2 |
+
|
3 |
+
const chatBox = document.getElementById('chat-box');
|
4 |
+
const chatInput = document.getElementById('chat-input');
|
5 |
+
const sendButton = document.getElementById('send-button');
|
6 |
+
const converter = new showdown.Converter(); // If you're using showdown.js for markdown to HTML conversion
|
7 |
+
|
8 |
+
let response = "";
|
9 |
+
|
10 |
+
// Function to add a loader element
|
11 |
+
function addLoader() {
|
12 |
+
const loaderEle = document.createElement('div');
|
13 |
+
loaderEle.classList.add('dot-loader');
|
14 |
+
loaderEle.innerHTML = `
|
15 |
+
<div></div>
|
16 |
+
<div></div>
|
17 |
+
<div></div>
|
18 |
+
`;
|
19 |
+
chatBox.appendChild(loaderEle);
|
20 |
+
}
|
21 |
+
|
22 |
+
// Function to append a message to the chat box
|
23 |
+
function appendMessage(message, sender) {
|
24 |
+
if (sender === 'bot') {
|
25 |
+
response += message;
|
26 |
+
console.log(response);
|
27 |
+
const loaderEle = chatBox.lastElementChild;
|
28 |
+
|
29 |
+
if (loaderEle && loaderEle.classList.contains('dot-loader')) {
|
30 |
+
chatBox.removeChild(loaderEle);
|
31 |
+
const messageElement = document.createElement('div');
|
32 |
+
messageElement.classList.add('chat-message', sender);
|
33 |
+
messageElement.innerHTML = `<span>${response}</span>`;
|
34 |
+
chatBox.append(messageElement);
|
35 |
+
chatBox.scrollTop = chatBox.scrollHeight;
|
36 |
+
} else {
|
37 |
+
const lastMessageEle = chatBox.lastElementChild;
|
38 |
+
if (lastMessageEle) {
|
39 |
+
lastMessageEle.innerHTML = response;
|
40 |
+
}
|
41 |
+
chatBox.scrollTop = chatBox.scrollHeight;
|
42 |
+
}
|
43 |
+
} else {
|
44 |
+
const messageElement = document.createElement('div');
|
45 |
+
messageElement.classList.add('chat-message', sender);
|
46 |
+
messageElement.innerHTML = `<span>${message}</span>`;
|
47 |
+
chatBox.append(messageElement);
|
48 |
+
chatBox.scrollTop = chatBox.scrollHeight;
|
49 |
+
|
50 |
+
// Add a loader after a slight delay
|
51 |
+
setTimeout(addLoader, 500);
|
52 |
+
}
|
53 |
+
}
|
54 |
+
|
55 |
+
// Event listener for the send button
|
56 |
+
sendButton.addEventListener('click', () => {
|
57 |
+
const message = chatInput.value.trim();
|
58 |
+
if (message) {
|
59 |
+
appendMessage(message, 'user');
|
60 |
+
socket.emit('message', { question: message, language:"en", session_id: 'abc123' });
|
61 |
+
chatInput.value = '';
|
62 |
+
response = "";
|
63 |
+
} else {
|
64 |
+
console.error("Message cannot be empty.");
|
65 |
+
}
|
66 |
+
});
|
67 |
+
|
68 |
+
// Event listener for 'Enter' key press in the chat input
|
69 |
+
chatInput.addEventListener('keypress', (e) => {
|
70 |
+
if (e.key === 'Enter') {
|
71 |
+
sendButton.click();
|
72 |
+
}
|
73 |
+
});
|
74 |
+
|
75 |
+
// Handle incoming responses from the server
|
76 |
+
socket.on('response', (data) => {
|
77 |
+
console.log(data);
|
78 |
+
if (data && typeof data === 'string') {
|
79 |
+
appendMessage(data, 'bot');
|
80 |
+
} else {
|
81 |
+
console.error("Invalid response format received from the server.");
|
82 |
+
}
|
83 |
+
});
|
84 |
+
|
85 |
+
// Handle connection errors
|
86 |
+
socket.on('connect_error', (error) => {
|
87 |
+
console.error("Connection error:", error);
|
88 |
+
appendMessage("Sorry, there was a problem connecting to the server. Please try again later.", 'bot');
|
89 |
+
});
|
90 |
+
|
91 |
+
// Handle disconnection
|
92 |
+
socket.on('disconnect', (reason) => {
|
93 |
+
console.warn("Disconnected from server:", reason);
|
94 |
+
appendMessage("You have been disconnected from the server. Please refresh the page to reconnect.", 'bot');
|
95 |
+
});
|
static/styles.css
ADDED
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
body {
|
2 |
+
font-family: Arial, sans-serif;
|
3 |
+
background-color: #f4f4f4;
|
4 |
+
margin: 0;
|
5 |
+
padding: 0;
|
6 |
+
display: flex;
|
7 |
+
flex-direction: column;
|
8 |
+
justify-content: center;
|
9 |
+
align-items: center;
|
10 |
+
height: 100vh;
|
11 |
+
overflow: scroll;
|
12 |
+
}
|
13 |
+
|
14 |
+
.chat-container {
|
15 |
+
max-width: 800px;
|
16 |
+
max-height: 1200px;
|
17 |
+
width: 100%;
|
18 |
+
height: 70vh;
|
19 |
+
background-color: #fff;
|
20 |
+
border-radius: 8px;
|
21 |
+
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
22 |
+
display: flex;
|
23 |
+
flex-direction: column;
|
24 |
+
overflow: hidden;
|
25 |
+
}
|
26 |
+
|
27 |
+
.chat-box {
|
28 |
+
flex: 1;
|
29 |
+
padding: 20px;
|
30 |
+
overflow-y: auto;
|
31 |
+
border-bottom: 1px solid #ddd;
|
32 |
+
}
|
33 |
+
|
34 |
+
.chat-message {
|
35 |
+
margin-bottom: 15px;
|
36 |
+
}
|
37 |
+
|
38 |
+
.chat-message.user {
|
39 |
+
text-align: right;
|
40 |
+
}
|
41 |
+
|
42 |
+
.chat-message.user span {
|
43 |
+
background-color: #007bff;
|
44 |
+
color: #fff;
|
45 |
+
padding: 10px;
|
46 |
+
border-radius: 12px;
|
47 |
+
display: inline-block;
|
48 |
+
max-width: 70%;
|
49 |
+
}
|
50 |
+
|
51 |
+
.chat-message.bot span {
|
52 |
+
background-color: #e0e0e0;
|
53 |
+
color: #333;
|
54 |
+
padding: 6px 10px;
|
55 |
+
border-radius: 12px;
|
56 |
+
display: inline-block;
|
57 |
+
max-width: 70%;
|
58 |
+
}
|
59 |
+
|
60 |
+
.input-container {
|
61 |
+
display: flex;
|
62 |
+
padding: 15px;
|
63 |
+
background-color: #f4f4f4;
|
64 |
+
}
|
65 |
+
|
66 |
+
#chat-input {
|
67 |
+
flex: 1;
|
68 |
+
padding: 10px;
|
69 |
+
border: 1px solid #ddd;
|
70 |
+
border-radius: 4px;
|
71 |
+
font-size: 16px;
|
72 |
+
}
|
73 |
+
|
74 |
+
#send-button {
|
75 |
+
padding: 10px 15px;
|
76 |
+
background-color: #007bff;
|
77 |
+
color: #fff;
|
78 |
+
border: none;
|
79 |
+
border-radius: 4px;
|
80 |
+
cursor: pointer;
|
81 |
+
margin-left: 10px;
|
82 |
+
font-size: 16px;
|
83 |
+
}
|
84 |
+
|
85 |
+
#send-button:hover {
|
86 |
+
background-color: #0056b3;
|
87 |
+
}
|
88 |
+
|
89 |
+
/* Dot Loader styles */
|
90 |
+
.dot-loader {
|
91 |
+
background-color: #e0e0e0;
|
92 |
+
color: #333;
|
93 |
+
padding: 15px;
|
94 |
+
border-radius: 10px;
|
95 |
+
width: fit-content;
|
96 |
+
display: flex;
|
97 |
+
justify-content: center;
|
98 |
+
align-items: center;
|
99 |
+
margin-top: 20px;
|
100 |
+
}
|
101 |
+
|
102 |
+
.dot-loader div {
|
103 |
+
width: 5px;
|
104 |
+
height: 5px;
|
105 |
+
margin: 0 5px;
|
106 |
+
background-color: #8a8a8a;
|
107 |
+
border-radius: 50%;
|
108 |
+
animation: dot 1.2s infinite ease-in-out;
|
109 |
+
}
|
110 |
+
|
111 |
+
.dot-loader div:nth-child(1) {
|
112 |
+
animation-delay: -0.32s;
|
113 |
+
}
|
114 |
+
|
115 |
+
.dot-loader div:nth-child(2) {
|
116 |
+
animation-delay: -0.16s;
|
117 |
+
}
|
118 |
+
|
119 |
+
@keyframes dot {
|
120 |
+
0%, 80%, 100% {
|
121 |
+
transform: scale(0);
|
122 |
+
}
|
123 |
+
40% {
|
124 |
+
transform: scale(1);
|
125 |
+
}
|
126 |
+
}
|
127 |
+
|
128 |
+
.hidden {
|
129 |
+
display: none;
|
130 |
+
}
|
templates/chat.html
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html lang="en">
|
3 |
+
<head>
|
4 |
+
<meta charset="UTF-8">
|
5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
+
<title>Chat with LLM</title>
|
7 |
+
<link rel="stylesheet" href="../static/styles.css">
|
8 |
+
</head>
|
9 |
+
<body>
|
10 |
+
<h3>This is a RAG application over the website <a href="https://uaelegislation.gov.ae/en">https://uaelegislation.gov.ae/en</a></h3>
|
11 |
+
<div class="chat-container">
|
12 |
+
<md-block class="chat-box" id="chat-box">
|
13 |
+
|
14 |
+
|
15 |
+
|
16 |
+
</md-block>
|
17 |
+
<div class="input-container">
|
18 |
+
<input type="text" id="chat-input" placeholder="Type your message here...">
|
19 |
+
<button id="send-button">Send</button>
|
20 |
+
</div>
|
21 |
+
</div>
|
22 |
+
<script type="module" src="https://md-block.verou.me/md-block.js"></script>
|
23 |
+
<script src="https://cdn.socket.io/4.5.0/socket.io.min.js"></script>
|
24 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/2.1.0/showdown.min.js" integrity="sha512-LhccdVNGe2QMEfI3x4DVV3ckMRe36TfydKss6mJpdHjNFiV07dFpS2xzeZedptKZrwxfICJpez09iNioiSZ3hA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
25 |
+
|
26 |
+
<script src="../static/script.js"></script>
|
27 |
+
</body>
|
28 |
+
</html>
|
test.ipynb
ADDED
@@ -0,0 +1,199 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"cells": [
|
3 |
+
{
|
4 |
+
"cell_type": "code",
|
5 |
+
"execution_count": 1,
|
6 |
+
"metadata": {},
|
7 |
+
"outputs": [
|
8 |
+
{
|
9 |
+
"name": "stdout",
|
10 |
+
"output_type": "stream",
|
11 |
+
"text": [
|
12 |
+
"hello world\n"
|
13 |
+
]
|
14 |
+
}
|
15 |
+
],
|
16 |
+
"source": [
|
17 |
+
"print(\"hello world\")"
|
18 |
+
]
|
19 |
+
},
|
20 |
+
{
|
21 |
+
"cell_type": "code",
|
22 |
+
"execution_count": 2,
|
23 |
+
"metadata": {},
|
24 |
+
"outputs": [
|
25 |
+
{
|
26 |
+
"name": "stderr",
|
27 |
+
"output_type": "stream",
|
28 |
+
"text": [
|
29 |
+
"c:\\Users\\Ritesh.Thawkar\\Desktop\\website-demos\\env\\Lib\\site-packages\\pinecone\\data\\index.py:1: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
|
30 |
+
" from tqdm.autonotebook import tqdm\n"
|
31 |
+
]
|
32 |
+
}
|
33 |
+
],
|
34 |
+
"source": [
|
35 |
+
"from pinecone import Pinecone\n",
|
36 |
+
"\n",
|
37 |
+
"# Initialize the Pinecone client\n",
|
38 |
+
"pc = Pinecone(api_key='ca8e6a33-7355-453f-ad4b-80c8a1c6a9c7')"
|
39 |
+
]
|
40 |
+
},
|
41 |
+
{
|
42 |
+
"cell_type": "code",
|
43 |
+
"execution_count": 3,
|
44 |
+
"metadata": {},
|
45 |
+
"outputs": [],
|
46 |
+
"source": [
|
47 |
+
"# Define your index name\n",
|
48 |
+
"index_name = 'vector-store-index'\n",
|
49 |
+
"index = pc.Index(index_name)"
|
50 |
+
]
|
51 |
+
},
|
52 |
+
{
|
53 |
+
"cell_type": "code",
|
54 |
+
"execution_count": 4,
|
55 |
+
"metadata": {},
|
56 |
+
"outputs": [
|
57 |
+
{
|
58 |
+
"data": {
|
59 |
+
"text/plain": [
|
60 |
+
"{'dimension': 768,\n",
|
61 |
+
" 'index_fullness': 0.0,\n",
|
62 |
+
" 'namespaces': {'': {'vector_count': 16294}},\n",
|
63 |
+
" 'total_vector_count': 16294}"
|
64 |
+
]
|
65 |
+
},
|
66 |
+
"execution_count": 4,
|
67 |
+
"metadata": {},
|
68 |
+
"output_type": "execute_result"
|
69 |
+
}
|
70 |
+
],
|
71 |
+
"source": [
|
72 |
+
"index.describe_index_stats()"
|
73 |
+
]
|
74 |
+
},
|
75 |
+
{
|
76 |
+
"cell_type": "code",
|
77 |
+
"execution_count": 5,
|
78 |
+
"metadata": {},
|
79 |
+
"outputs": [],
|
80 |
+
"source": [
|
81 |
+
"vector_ids = [str(i) for i in range(1, 16295)]"
|
82 |
+
]
|
83 |
+
},
|
84 |
+
{
|
85 |
+
"cell_type": "code",
|
86 |
+
"execution_count": 6,
|
87 |
+
"metadata": {},
|
88 |
+
"outputs": [],
|
89 |
+
"source": [
|
90 |
+
"from concurrent.futures import ThreadPoolExecutor, as_completed"
|
91 |
+
]
|
92 |
+
},
|
93 |
+
{
|
94 |
+
"cell_type": "code",
|
95 |
+
"execution_count": 7,
|
96 |
+
"metadata": {},
|
97 |
+
"outputs": [],
|
98 |
+
"source": [
|
99 |
+
"def update_vector(vector_id):\n",
|
100 |
+
" try:\n",
|
101 |
+
" # Fetch the vector\n",
|
102 |
+
" vector = index.fetch([vector_id])\n",
|
103 |
+
" \n",
|
104 |
+
" # Check if the vector exists\n",
|
105 |
+
" if vector and vector['vectors']:\n",
|
106 |
+
" prev_text = vector['vectors'][vector_id].metadata['text']\n",
|
107 |
+
" \n",
|
108 |
+
" # Update the vector's metadata\n",
|
109 |
+
" index.update(\n",
|
110 |
+
" id=vector_id, \n",
|
111 |
+
" set_metadata={\"context\": prev_text},\n",
|
112 |
+
" )\n",
|
113 |
+
" return f\"Updated vector {vector_id}.\"\n",
|
114 |
+
" else:\n",
|
115 |
+
" return f\"Vector {vector_id} not found.\"\n",
|
116 |
+
" except Exception as e:\n",
|
117 |
+
" return f\"Error updating vector {vector_id}: {e}\""
|
118 |
+
]
|
119 |
+
},
|
120 |
+
{
|
121 |
+
"cell_type": "code",
|
122 |
+
"execution_count": 8,
|
123 |
+
"metadata": {},
|
124 |
+
"outputs": [],
|
125 |
+
"source": [
|
126 |
+
"# Use ThreadPoolExecutor for parallel execution\n",
|
127 |
+
"with ThreadPoolExecutor(max_workers=10) as executor: # Adjust max_workers as needed\n",
|
128 |
+
" future_to_vector_id = {executor.submit(update_vector, vector_id): vector_id for vector_id in vector_ids}\n",
|
129 |
+
" \n",
|
130 |
+
" for future in as_completed(future_to_vector_id):\n",
|
131 |
+
" vector_id = future_to_vector_id[future]\n",
|
132 |
+
" try:\n",
|
133 |
+
" result = future.result()\n",
|
134 |
+
" except Exception as e:\n",
|
135 |
+
" print(f\"Error processing vector {vector_id}: {e}\")"
|
136 |
+
]
|
137 |
+
},
|
138 |
+
{
|
139 |
+
"cell_type": "code",
|
140 |
+
"execution_count": null,
|
141 |
+
"metadata": {},
|
142 |
+
"outputs": [],
|
143 |
+
"source": [
|
144 |
+
"# Specify the ID of the vector you want to update\n",
|
145 |
+
"vector_ids = [str(i) for i in range(1, 16295)]\n",
|
146 |
+
"\n",
|
147 |
+
"for vector_id in vector_ids:\n",
|
148 |
+
" # Fetch the vector\n",
|
149 |
+
" vector = index.fetch([vector_id])\n",
|
150 |
+
"\n",
|
151 |
+
" prev_text = vector['vectors'][vector_id].metadata['text']\n",
|
152 |
+
"\n",
|
153 |
+
" index.update(\n",
|
154 |
+
" id=vector_id, \n",
|
155 |
+
" set_metadata={\"context\": prev_text},\n",
|
156 |
+
" )\n",
|
157 |
+
"\n",
|
158 |
+
"# Check if the vector exists\n",
|
159 |
+
"# if vector and vector.ids:\n",
|
160 |
+
"# # Get the current metadata\n",
|
161 |
+
"# current_metadata = vector.vectors[vector_id].metadata\n",
|
162 |
+
" \n",
|
163 |
+
"# # Update the key name in the metadata\n",
|
164 |
+
"# if 'text' in current_metadata:\n",
|
165 |
+
"# current_metadata['context'] = current_metadata.pop('text')\n",
|
166 |
+
" \n",
|
167 |
+
"# # Upsert the updated vector back to the index\n",
|
168 |
+
"# index.upsert(vectors=[(vector_id, vector.vectors[vector_id].values, current_metadata)])\n",
|
169 |
+
"# print(f\"Updated metadata for vector {vector_id}.\")\n",
|
170 |
+
"# else:\n",
|
171 |
+
"# print(f\"Vector with ID {vector_id} not found.\")\n",
|
172 |
+
"\n",
|
173 |
+
"# Optionally, close the index\n",
|
174 |
+
"# index.close()\n"
|
175 |
+
]
|
176 |
+
}
|
177 |
+
],
|
178 |
+
"metadata": {
|
179 |
+
"kernelspec": {
|
180 |
+
"display_name": "env",
|
181 |
+
"language": "python",
|
182 |
+
"name": "python3"
|
183 |
+
},
|
184 |
+
"language_info": {
|
185 |
+
"codemirror_mode": {
|
186 |
+
"name": "ipython",
|
187 |
+
"version": 3
|
188 |
+
},
|
189 |
+
"file_extension": ".py",
|
190 |
+
"mimetype": "text/x-python",
|
191 |
+
"name": "python",
|
192 |
+
"nbconvert_exporter": "python",
|
193 |
+
"pygments_lexer": "ipython3",
|
194 |
+
"version": "3.12.6"
|
195 |
+
}
|
196 |
+
},
|
197 |
+
"nbformat": 4,
|
198 |
+
"nbformat_minor": 2
|
199 |
+
}
|