Spaces:
Runtime error
Runtime error
Upload 5 files
Browse files- index.html +69 -0
- script.js +204 -0
- server.py +55 -0
- style.css +219 -0
- worker_huggingFace.py +83 -0
index.html
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<link
|
| 5 |
+
rel="stylesheet"
|
| 6 |
+
href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
|
| 7 |
+
integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z"
|
| 8 |
+
crossorigin="anonymous"
|
| 9 |
+
/>
|
| 10 |
+
<link
|
| 11 |
+
rel="stylesheet"
|
| 12 |
+
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
| 13 |
+
/>
|
| 14 |
+
<link rel="stylesheet" href="../static/style.css"/>
|
| 15 |
+
<link
|
| 16 |
+
rel="stylesheet"
|
| 17 |
+
href="{{ url_for('static', filename='style.css') }}"
|
| 18 |
+
/>
|
| 19 |
+
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
|
| 20 |
+
<script src="../static/script.js"></script>
|
| 21 |
+
</head>
|
| 22 |
+
<body>
|
| 23 |
+
<div class="container d-flex flex-column vh-100">
|
| 24 |
+
<div class="row">
|
| 25 |
+
<div class="col-12" style="margin-top: 2rem">
|
| 26 |
+
<h1 class="text-center mb-3">Personal Data Assistant</h1>
|
| 27 |
+
</div>
|
| 28 |
+
<div class="col-12 text-center">
|
| 29 |
+
<div class="custom-control custom-switch mb-3">
|
| 30 |
+
<input type="checkbox" class="custom-control-input" id="light-dark-mode-switch" />
|
| 31 |
+
<label class="custom-control-label" for="light-dark-mode-switch">Toggle light/dark mode</label>
|
| 32 |
+
</div>
|
| 33 |
+
</div>
|
| 34 |
+
</div>
|
| 35 |
+
<div class="row flex-grow-1 overflow-auto">
|
| 36 |
+
<div class="col-12 col-md-8 mx-auto d-flex flex-column">
|
| 37 |
+
<div id="chat-window" class="p-3">
|
| 38 |
+
<div id="message-list"></div>
|
| 39 |
+
<div class="loading-animation my-loading">
|
| 40 |
+
<div class="loading-dots my-loading">
|
| 41 |
+
<div class="dot"></div>
|
| 42 |
+
<div class="dot"></div>
|
| 43 |
+
<div class="dot"></div>
|
| 44 |
+
</div>
|
| 45 |
+
</div>
|
| 46 |
+
<div class="loading-animation">
|
| 47 |
+
<div class="loading-dots">
|
| 48 |
+
<div class="dot"></div>
|
| 49 |
+
<div class="dot"></div>
|
| 50 |
+
<div class="dot"></div>
|
| 51 |
+
</div>
|
| 52 |
+
</div>
|
| 53 |
+
</div>
|
| 54 |
+
<div class="input-group mt-1">
|
| 55 |
+
<input type="text" id="message-input" class="form-control" placeholder="Type your message here..." />
|
| 56 |
+
<div class="input-group-append">
|
| 57 |
+
<button id="send-button" class="btn btn-primary send">
|
| 58 |
+
<i class='fa fa-paper-plane'></i>
|
| 59 |
+
</button>
|
| 60 |
+
<button id="reset-button" class="btn btn-primary reset">
|
| 61 |
+
<i class="fa fa-refresh"></i>
|
| 62 |
+
</button>
|
| 63 |
+
</div>
|
| 64 |
+
</div>
|
| 65 |
+
</div>
|
| 66 |
+
</div>
|
| 67 |
+
</div>
|
| 68 |
+
</body>
|
| 69 |
+
</html>
|
script.js
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
let lightMode = true;
|
| 2 |
+
let recorder = null;
|
| 3 |
+
let recording = false;
|
| 4 |
+
const responses = [];
|
| 5 |
+
const botRepeatButtonIDToIndexMap = {};
|
| 6 |
+
const userRepeatButtonIDToRecordingMap = {};
|
| 7 |
+
const baseUrl = window.location.origin
|
| 8 |
+
|
| 9 |
+
async function showBotLoadingAnimation() {
|
| 10 |
+
await sleep(200);
|
| 11 |
+
$(".loading-animation")[1].style.display = "inline-block";
|
| 12 |
+
document.getElementById('send-button').disabled = true;
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
function hideBotLoadingAnimation() {
|
| 16 |
+
$(".loading-animation")[1].style.display = "none";
|
| 17 |
+
if(!isFirstMessage){
|
| 18 |
+
document.getElementById('send-button').disabled = false;
|
| 19 |
+
}
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
async function showUserLoadingAnimation() {
|
| 23 |
+
await sleep(100);
|
| 24 |
+
$(".loading-animation")[0].style.display = "flex";
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
function hideUserLoadingAnimation() {
|
| 28 |
+
$(".loading-animation")[0].style.display = "none";
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
const processUserMessage = async (userMessage) => {
|
| 33 |
+
let response = await fetch(baseUrl + "/process-message", {
|
| 34 |
+
method: "POST",
|
| 35 |
+
headers: { Accept: "application/json", "Content-Type": "application/json" },
|
| 36 |
+
body: JSON.stringify({ userMessage: userMessage }),
|
| 37 |
+
});
|
| 38 |
+
response = await response.json();
|
| 39 |
+
console.log(response);
|
| 40 |
+
return response;
|
| 41 |
+
};
|
| 42 |
+
|
| 43 |
+
const cleanTextInput = (value) => {
|
| 44 |
+
return value
|
| 45 |
+
.trim() // remove starting and ending spaces
|
| 46 |
+
.replace(/[\n\t]/g, "") // remove newlines and tabs
|
| 47 |
+
.replace(/<[^>]*>/g, "") // remove HTML tags
|
| 48 |
+
.replace(/[<>&;]/g, ""); // sanitize inputs
|
| 49 |
+
};
|
| 50 |
+
|
| 51 |
+
const sleep = (time) => new Promise((resolve) => setTimeout(resolve, time));
|
| 52 |
+
|
| 53 |
+
const scrollToBottom = () => {
|
| 54 |
+
// Scroll the chat window to the bottom
|
| 55 |
+
$("#chat-window").animate({
|
| 56 |
+
scrollTop: $("#chat-window")[0].scrollHeight,
|
| 57 |
+
});
|
| 58 |
+
};
|
| 59 |
+
|
| 60 |
+
const populateUserMessage = (userMessage, userRecording) => {
|
| 61 |
+
// Clear the input field
|
| 62 |
+
$("#message-input").val("");
|
| 63 |
+
|
| 64 |
+
// Append the user's message to the message list
|
| 65 |
+
$("#message-list").append(
|
| 66 |
+
`<div class='message-line my-text'><div class='message-box my-text${
|
| 67 |
+
!lightMode ? " dark" : ""
|
| 68 |
+
}'><div class='me'>${userMessage}</div></div></div>`
|
| 69 |
+
);
|
| 70 |
+
|
| 71 |
+
scrollToBottom();
|
| 72 |
+
};
|
| 73 |
+
|
| 74 |
+
let isFirstMessage = true;
|
| 75 |
+
|
| 76 |
+
const populateBotResponse = async (userMessage) => {
|
| 77 |
+
await showBotLoadingAnimation();
|
| 78 |
+
|
| 79 |
+
let response;
|
| 80 |
+
let uploadButtonHtml = '';
|
| 81 |
+
|
| 82 |
+
if (isFirstMessage) {
|
| 83 |
+
response = { botResponse: "Hello there! I'm your friendly data assistant, ready to answer any questions regarding your data. Could you please upload a PDF file for me to analyze?"};
|
| 84 |
+
uploadButtonHtml = `
|
| 85 |
+
<input type="file" id="file-upload" accept=".pdf" hidden>
|
| 86 |
+
<button id="upload-button" class="btn btn-primary btn-sm">Upload File</button>
|
| 87 |
+
`;
|
| 88 |
+
|
| 89 |
+
} else {
|
| 90 |
+
response = await processUserMessage(userMessage);
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
renderBotResponse(response, uploadButtonHtml)
|
| 94 |
+
|
| 95 |
+
// Event listener for file upload
|
| 96 |
+
if (isFirstMessage) {
|
| 97 |
+
$("#upload-button").on("click", function () {
|
| 98 |
+
$("#file-upload").click();
|
| 99 |
+
});
|
| 100 |
+
|
| 101 |
+
$("#file-upload").on("change", async function () {
|
| 102 |
+
const file = this.files[0];
|
| 103 |
+
|
| 104 |
+
await showBotLoadingAnimation();
|
| 105 |
+
|
| 106 |
+
// Create a new FormData instance
|
| 107 |
+
const formData = new FormData();
|
| 108 |
+
|
| 109 |
+
// Append the file to the FormData instance
|
| 110 |
+
formData.append('file', file);
|
| 111 |
+
|
| 112 |
+
// Now send this data to /process-document endpoint
|
| 113 |
+
let response = await fetch(baseUrl + "/process-document", {
|
| 114 |
+
method: "POST",
|
| 115 |
+
headers: { Accept: "application/json" }, // "Content-Type" should not be explicitly set here, the browser will automatically set it to "multipart/form-data"
|
| 116 |
+
body: formData, // send the FormData instance as the body
|
| 117 |
+
});
|
| 118 |
+
|
| 119 |
+
if (response.status !== 400) {
|
| 120 |
+
document.querySelector('#upload-button').disabled = true;
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
response = await response.json();
|
| 124 |
+
console.log('/process-document', response)
|
| 125 |
+
renderBotResponse(response, '')
|
| 126 |
+
});
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
isFirstMessage = false; // after the first message, set this to false
|
| 130 |
+
}
|
| 131 |
+
};
|
| 132 |
+
|
| 133 |
+
const renderBotResponse = (response, uploadButtonHtml) => {
|
| 134 |
+
responses.push(response);
|
| 135 |
+
|
| 136 |
+
hideBotLoadingAnimation();
|
| 137 |
+
|
| 138 |
+
$("#message-list").append(
|
| 139 |
+
`<div class='message-line'><div class='message-box${!lightMode ? " dark" : ""}'>${response.botResponse.trim()}<br>${uploadButtonHtml}</div></div>`
|
| 140 |
+
);
|
| 141 |
+
|
| 142 |
+
scrollToBottom();
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
populateBotResponse()
|
| 146 |
+
|
| 147 |
+
|
| 148 |
+
$(document).ready(function () {
|
| 149 |
+
|
| 150 |
+
//start the chat with send button disabled
|
| 151 |
+
document.getElementById('send-button').disabled = true;
|
| 152 |
+
|
| 153 |
+
// Listen for the "Enter" key being pressed in the input field
|
| 154 |
+
$("#message-input").keyup(function (event) {
|
| 155 |
+
let inputVal = cleanTextInput($("#message-input").val());
|
| 156 |
+
|
| 157 |
+
if (event.keyCode === 13 && inputVal != "") {
|
| 158 |
+
const message = inputVal;
|
| 159 |
+
|
| 160 |
+
populateUserMessage(message, null);
|
| 161 |
+
populateBotResponse(message);
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
inputVal = $("#message-input").val();
|
| 165 |
+
});
|
| 166 |
+
|
| 167 |
+
// When the user clicks the "Send" button
|
| 168 |
+
$("#send-button").click(async function () {
|
| 169 |
+
// Get the message the user typed in
|
| 170 |
+
const message = cleanTextInput($("#message-input").val());
|
| 171 |
+
|
| 172 |
+
populateUserMessage(message, null);
|
| 173 |
+
populateBotResponse(message);
|
| 174 |
+
|
| 175 |
+
});
|
| 176 |
+
|
| 177 |
+
//reset chat
|
| 178 |
+
// When the user clicks the "Reset" button
|
| 179 |
+
$("#reset-button").click(async function () {
|
| 180 |
+
// Clear the message list
|
| 181 |
+
$("#message-list").empty();
|
| 182 |
+
|
| 183 |
+
// Reset the responses array
|
| 184 |
+
responses.length = 0;
|
| 185 |
+
|
| 186 |
+
// Reset isFirstMessage flag
|
| 187 |
+
isFirstMessage = true;
|
| 188 |
+
|
| 189 |
+
document.querySelector('#upload-button').disabled = false;
|
| 190 |
+
|
| 191 |
+
// Start over
|
| 192 |
+
populateBotResponse();
|
| 193 |
+
});
|
| 194 |
+
|
| 195 |
+
|
| 196 |
+
// handle the event of switching light-dark mode
|
| 197 |
+
$("#light-dark-mode-switch").change(function () {
|
| 198 |
+
$("body").toggleClass("dark-mode");
|
| 199 |
+
$(".message-box").toggleClass("dark");
|
| 200 |
+
$(".loading-dots").toggleClass("dark");
|
| 201 |
+
$(".dot").toggleClass("dark-dot");
|
| 202 |
+
lightMode = !lightMode;
|
| 203 |
+
});
|
| 204 |
+
});
|
server.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import logging
|
| 2 |
+
import os
|
| 3 |
+
from flask import Flask, render_template, request, jsonify
|
| 4 |
+
from flask_cors import CORS
|
| 5 |
+
import worker # Import the worker module
|
| 6 |
+
|
| 7 |
+
# Initialize Flask app and CORS
|
| 8 |
+
app = Flask(__name__)
|
| 9 |
+
cors = CORS(app, resources={r"/*": {"origins": "*"}})
|
| 10 |
+
app.logger.setLevel(logging.ERROR)
|
| 11 |
+
|
| 12 |
+
# Define the route for the index page
|
| 13 |
+
@app.route('/', methods=['GET'])
|
| 14 |
+
def index():
|
| 15 |
+
return render_template('index.html') # Render the index.html template
|
| 16 |
+
|
| 17 |
+
# Define the route for processing messages
|
| 18 |
+
@app.route('/process-message', methods=['POST'])
|
| 19 |
+
def process_message_route():
|
| 20 |
+
user_message = request.json['userMessage'] # Extract the user's message from the request
|
| 21 |
+
print('user_message', user_message)
|
| 22 |
+
|
| 23 |
+
bot_response = worker.process_prompt(user_message) # Process the user's message using the worker module
|
| 24 |
+
|
| 25 |
+
# Return the bot's response as JSON
|
| 26 |
+
return jsonify({
|
| 27 |
+
"botResponse": bot_response
|
| 28 |
+
}), 200
|
| 29 |
+
|
| 30 |
+
# Define the route for processing documents
|
| 31 |
+
@app.route('/process-document', methods=['POST'])
|
| 32 |
+
def process_document_route():
|
| 33 |
+
# Check if a file was uploaded
|
| 34 |
+
if 'file' not in request.files:
|
| 35 |
+
return jsonify({
|
| 36 |
+
"botResponse": "It seems like the file was not uploaded correctly, can you try "
|
| 37 |
+
"again. If the problem persists, try using a different file"
|
| 38 |
+
}), 400
|
| 39 |
+
|
| 40 |
+
file = request.files['file'] # Extract the uploaded file from the request
|
| 41 |
+
|
| 42 |
+
file_path = file.filename # Define the path where the file will be saved
|
| 43 |
+
file.save(file_path) # Save the file
|
| 44 |
+
|
| 45 |
+
worker.process_document(file_path) # Process the document using the worker module
|
| 46 |
+
|
| 47 |
+
# Return a success message as JSON
|
| 48 |
+
return jsonify({
|
| 49 |
+
"botResponse": "Thank you for providing your PDF document. I have analyzed it, so now you can ask me any "
|
| 50 |
+
"questions regarding it!"
|
| 51 |
+
}), 200
|
| 52 |
+
|
| 53 |
+
# Run the Flask app
|
| 54 |
+
if __name__ == "__main__":
|
| 55 |
+
app.run(debug=True, port=8000, host='0.0.0.0')
|
style.css
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* Light mode */
|
| 2 |
+
body {
|
| 3 |
+
background-color: #d6ddec;
|
| 4 |
+
color: #121717;
|
| 5 |
+
}
|
| 6 |
+
|
| 7 |
+
/* Dark mode */
|
| 8 |
+
.dark-mode {
|
| 9 |
+
background-color: #121717;
|
| 10 |
+
color: #c9c9c9;
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
#chat-window {
|
| 14 |
+
position: relative;
|
| 15 |
+
height: 70vh;
|
| 16 |
+
overflow: auto;
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
.message-line {
|
| 20 |
+
padding-bottom: 8px;
|
| 21 |
+
width: 70%;
|
| 22 |
+
word-break: break-word;
|
| 23 |
+
display: flex;
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
.message-box {
|
| 27 |
+
padding: 12px;
|
| 28 |
+
border-radius: 15px;
|
| 29 |
+
display: inline-block;
|
| 30 |
+
position: relative;
|
| 31 |
+
background-color: #efefef;
|
| 32 |
+
min-width: 26px;
|
| 33 |
+
border-top-left-radius: 0;
|
| 34 |
+
word-wrap: break-word;
|
| 35 |
+
flex-grow: 0;
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
.message-line.my-text {
|
| 39 |
+
flex-direction: row-reverse;
|
| 40 |
+
width: 100%;
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
.message-box.my-text {
|
| 44 |
+
transform: rotateY(180deg);
|
| 45 |
+
background-color: #e7f9d8;
|
| 46 |
+
margin-left:150px;
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
.me {
|
| 50 |
+
transform: scale(-1, 1);
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
.message-box.my-text.dark {
|
| 54 |
+
background-color: #0f4c9e;
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
.message-box.dark {
|
| 58 |
+
background-color: #263443;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
/* Input container */
|
| 62 |
+
#message-input {
|
| 63 |
+
bottom: 0;
|
| 64 |
+
width: 100%;
|
| 65 |
+
flex-grow: 1;
|
| 66 |
+
font-size: 16px;
|
| 67 |
+
box-sizing: border-box;
|
| 68 |
+
border: none;
|
| 69 |
+
padding: 10px 0 10px 12px;
|
| 70 |
+
border-radius: 40px 0 0 40px;
|
| 71 |
+
background-color: transparent;
|
| 72 |
+
height: auto;
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
#send-button {
|
| 76 |
+
border: none;
|
| 77 |
+
font: inherit;
|
| 78 |
+
background-color: transparent;
|
| 79 |
+
margin: 0;
|
| 80 |
+
appearance: none;
|
| 81 |
+
padding: 10px 12px;
|
| 82 |
+
cursor: pointer;
|
| 83 |
+
font-size: 24px;
|
| 84 |
+
display: flex;
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
#reset-button {
|
| 88 |
+
border: none;
|
| 89 |
+
font: inherit;
|
| 90 |
+
background-color: transparent;
|
| 91 |
+
margin: 0;
|
| 92 |
+
appearance: none;
|
| 93 |
+
padding: 10px 12px;
|
| 94 |
+
cursor: pointer;
|
| 95 |
+
font-size: 24px;
|
| 96 |
+
display: flex;
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
#repeat-button {
|
| 100 |
+
border: none;
|
| 101 |
+
background-color: transparent;
|
| 102 |
+
margin: 0 0 2px 0;
|
| 103 |
+
padding: 0 10px;
|
| 104 |
+
font-size: 24px;
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
.input-group {
|
| 108 |
+
position: relative;
|
| 109 |
+
display: flex;
|
| 110 |
+
flex-wrap: nowrap;
|
| 111 |
+
align-items: stretch;
|
| 112 |
+
width: 100%;
|
| 113 |
+
border-radius: 40px;
|
| 114 |
+
border: 1px solid #2d2d2d;
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
#upload-button {
|
| 118 |
+
color: white;
|
| 119 |
+
background-color: #007bff;
|
| 120 |
+
border: none;
|
| 121 |
+
padding: 5px 10px;
|
| 122 |
+
border-radius: 5px;
|
| 123 |
+
font-size: 14px;
|
| 124 |
+
cursor: pointer;
|
| 125 |
+
transition: background-color 0.3s ease;
|
| 126 |
+
margin-top: 12px;
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
#upload-button:hover {
|
| 130 |
+
background-color: #0056b3;
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
.send i {
|
| 134 |
+
display: block;
|
| 135 |
+
width: 25px;
|
| 136 |
+
color: #125ee5;
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
.reset i {
|
| 140 |
+
display: block;
|
| 141 |
+
width: 25px;
|
| 142 |
+
color: #125ee5;
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
.loading-animation {
|
| 147 |
+
padding-bottom: 8px;
|
| 148 |
+
word-break: break-word;
|
| 149 |
+
display: none;
|
| 150 |
+
width: 70%;
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
.loading-animation.my-loading {
|
| 154 |
+
flex-direction: row-reverse;
|
| 155 |
+
width: 100%;
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
.loading-dots {
|
| 159 |
+
padding: 12px;
|
| 160 |
+
border-radius: 15px;
|
| 161 |
+
position: relative;
|
| 162 |
+
background-color: #efefef;
|
| 163 |
+
min-width: 26px;
|
| 164 |
+
border-top-left-radius: 0;
|
| 165 |
+
display: flex;
|
| 166 |
+
justify-content: center;
|
| 167 |
+
align-items: baseline;
|
| 168 |
+
width: fit-content;
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
+
.loading-dots.my-loading {
|
| 172 |
+
transform: rotateY(180deg);
|
| 173 |
+
background-color: #e7f9d8;
|
| 174 |
+
float: right;
|
| 175 |
+
}
|
| 176 |
+
|
| 177 |
+
.dot {
|
| 178 |
+
width: 7px;
|
| 179 |
+
height: 7px;
|
| 180 |
+
margin: 0 2px;
|
| 181 |
+
border-radius: 50%;
|
| 182 |
+
animation: bounce 1.5s ease-in-out infinite;
|
| 183 |
+
background: #5a5a5a;
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
.loading-dots.my-loading.dark {
|
| 187 |
+
background-color: #0e4d9e;
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
.dark {
|
| 191 |
+
background-color: #263443;
|
| 192 |
+
}
|
| 193 |
+
|
| 194 |
+
.dark-dot {
|
| 195 |
+
background: #c9c9c9;
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
.dot:nth-of-type(1) {
|
| 199 |
+
margin-left: 5px;
|
| 200 |
+
animation-delay: 0s;
|
| 201 |
+
}
|
| 202 |
+
|
| 203 |
+
.dot:nth-of-type(2) {
|
| 204 |
+
animation-delay: 0.2s;
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
.dot:nth-of-type(3) {
|
| 208 |
+
animation-delay: 0.4s;
|
| 209 |
+
}
|
| 210 |
+
|
| 211 |
+
@keyframes bounce {
|
| 212 |
+
0%,
|
| 213 |
+
40% {
|
| 214 |
+
transform: translateY(0);
|
| 215 |
+
}
|
| 216 |
+
20% {
|
| 217 |
+
transform: translateY(-10px);
|
| 218 |
+
}
|
| 219 |
+
}
|
worker_huggingFace.py
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import torch
|
| 3 |
+
from langchain import PromptTemplate
|
| 4 |
+
from langchain.chains import RetrievalQA
|
| 5 |
+
from langchain.embeddings import HuggingFaceInstructEmbeddings
|
| 6 |
+
from langchain.document_loaders import PyPDFLoader
|
| 7 |
+
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
| 8 |
+
from langchain.vectorstores import Chroma
|
| 9 |
+
from langchain.llms import HuggingFaceHub
|
| 10 |
+
|
| 11 |
+
# Check for GPU availability and set the appropriate device for computation.
|
| 12 |
+
DEVICE = "cuda:0" if torch.cuda.is_available() else "cpu"
|
| 13 |
+
|
| 14 |
+
# Global variables
|
| 15 |
+
conversation_retrieval_chain = None
|
| 16 |
+
chat_history = []
|
| 17 |
+
llm_hub = None
|
| 18 |
+
embeddings = None
|
| 19 |
+
|
| 20 |
+
# Function to initialize the language model and its embeddings
|
| 21 |
+
def init_llm():
|
| 22 |
+
global llm_hub, embeddings
|
| 23 |
+
# Set up the environment variable for HuggingFace and initialize the desired model.
|
| 24 |
+
os.environ["HUGGINGFACEHUB_API_TOKEN"] = "YOUR API KEY"
|
| 25 |
+
|
| 26 |
+
# repo name for the model
|
| 27 |
+
model_id = "tiiuae/falcon-7b-instruct"
|
| 28 |
+
# load the model into the HuggingFaceHub
|
| 29 |
+
llm_hub = HuggingFaceHub(repo_id=model_id, model_kwargs={"temperature": 0.1, "max_new_tokens": 600, "max_length": 600})
|
| 30 |
+
|
| 31 |
+
#Initialize embeddings using a pre-trained model to represent the text data.
|
| 32 |
+
embeddings = HuggingFaceInstructEmbeddings(
|
| 33 |
+
model_name="sentence-transformers/all-MiniLM-L6-v2", model_kwargs={"device": DEVICE}
|
| 34 |
+
)
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
# Function to process a PDF document
|
| 38 |
+
def process_document(document_path):
|
| 39 |
+
global conversation_retrieval_chain
|
| 40 |
+
|
| 41 |
+
# Load the document
|
| 42 |
+
loader = PyPDFLoader(document_path)
|
| 43 |
+
documents = loader.load()
|
| 44 |
+
|
| 45 |
+
# Split the document into chunks
|
| 46 |
+
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1024, chunk_overlap=64)
|
| 47 |
+
texts = text_splitter.split_documents(documents)
|
| 48 |
+
|
| 49 |
+
# Create an embeddings database using Chroma from the split text chunks.
|
| 50 |
+
db = Chroma.from_documents(texts, embedding=embeddings)
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
# --> Build the QA chain, which utilizes the LLM and retriever for answering questions.
|
| 54 |
+
# By default, the vectorstore retriever uses similarity search.
|
| 55 |
+
# If the underlying vectorstore support maximum marginal relevance search, you can specify that as the search type (search_type="mmr").
|
| 56 |
+
# You can also specify search kwargs like k to use when doing retrieval. k represent how many search results send to llm
|
| 57 |
+
conversation_retrieval_chain = RetrievalQA.from_chain_type(
|
| 58 |
+
llm=llm_hub,
|
| 59 |
+
chain_type="stuff",
|
| 60 |
+
retriever=db.as_retriever(search_type="mmr", search_kwargs={'k': 6, 'lambda_mult': 0.25}),
|
| 61 |
+
return_source_documents=False,
|
| 62 |
+
input_key = "question"
|
| 63 |
+
# chain_type_kwargs={"prompt": prompt} # if you are using prompt template, you need to uncomment this part
|
| 64 |
+
)
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
# Function to process a user prompt
|
| 68 |
+
def process_prompt(prompt):
|
| 69 |
+
global conversation_retrieval_chain
|
| 70 |
+
global chat_history
|
| 71 |
+
|
| 72 |
+
# Query the model
|
| 73 |
+
output = conversation_retrieval_chain({"question": prompt, "chat_history": chat_history})
|
| 74 |
+
answer = output["result"]
|
| 75 |
+
|
| 76 |
+
# Update the chat history
|
| 77 |
+
chat_history.append((prompt, answer))
|
| 78 |
+
|
| 79 |
+
# Return the model's response
|
| 80 |
+
return answer
|
| 81 |
+
|
| 82 |
+
# Initialize the language model
|
| 83 |
+
init_llm()
|