unknown
commited on
Commit
·
a6fd95e
1
Parent(s):
4274a31
try 2
Browse files- .env +1 -0
- data.py +47 -0
- examples/sample_product_catalog.txt +11 -0
- main.py +90 -0
- requirements.txt +8 -0
- static/images/logo.png +0 -0
- static/images/test.png +0 -0
- static/js/chatbot-widget.js +41 -0
- static/js/script.js +200 -0
- static/style.css +317 -0
- templates/bannner.html +37 -0
- thread_data/threads_db.bak +1 -0
- thread_data/threads_db.dat +0 -0
- thread_data/threads_db.dir +1 -0
.env
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
OPENAI_API_KEY = "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"
|
data.py
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
kb = """
|
2 |
+
|
3 |
+
Meandb Details :- https://meandb.shop/
|
4 |
+
|
5 |
+
ME&NT TO B
|
6 |
+
Inspiration behind the Me&nt to B collection
|
7 |
+
Our office space is directly connected to our sample room and warehouse, which means we’re constantly seeing the waste that is created throughout the production process. This could be anything from left-over stock, scrap fabric to reject garments that are not viable to sell. Seeing this on the daily got the team thinking about what we could do to improve our waste while still providing our customers with garments that are on trend, size inclusive and will become staple pieces in their wardrobes for years to come!
|
8 |
+
Our first Me&nt to B collection is largely focused on The Anglaise Dress, a garment that we loved SO much we made it in three colourways. We were confident that this dress would be a winner so produced too much stock for the season. The team had a brainstorming session on how to repurpose the leftover stock, it went from altering the garments elastic back to eventually repurposing the garment into a tee and skirt set! We’ve taken this same approach to a few other styles from our previous seasons like updating a button or adding an embroidery detail or updating the silhouette slightly. Keep an eye out because this is just the start of our circular fashion initiative, we are currently looking into subscriptions models and reselling plans to take this concept one step further
|
9 |
+
|
10 |
+
The collection and Me&B’s long-term sustainability goals
|
11 |
+
We’re not oblivious to the fact that the clothing industry is inherently unsustainable, but Me&nt to B has allowed us to include another step in our process that limits our overall wastage. We understand we have a responsibility to the planet and this is the least we can do. Every step of our process, from the design of garments to the packaging is a check point where we can ensure that we’re ticking one of the four R’s from the circular fashion concept: reduce, reuse, recycle, or remove.
|
12 |
+
Another one of our favourite aspects of the Me&nt to B range is the connection it has to the local communities, as all of our Me&nt to B garments are redesigned and altered either in house or at one of our local CMTs. This ensures that even when we’re mid-season and the factories are typically without work, we can keep our factories busy and thriving.
|
13 |
+
|
14 |
+
We’re feeling really optimistic about this new venture and are excited to see where it takes us!
|
15 |
+
|
16 |
+
Welcome to Me&B!
|
17 |
+
|
18 |
+
The mother-daughter fashion brand, made right here in the mother city!
|
19 |
+
|
20 |
+
Betina and Kelly founded this brand with a strong belief that the fashion industry deserved a shake-up - and that our team of South African designers and craftsmen could be just the people to deliver that ‘something different.’
|
21 |
+
|
22 |
+
In 2018 we gathered a team of experts who had studied fashion intently, and knew all the rules but also had the right amount of confidence and creativity to be able to deliver something completely new and fresh.
|
23 |
+
|
24 |
+
Tasked with proving that high-quality, fashion-forward clothing could be available at fair prices, we created piece after piece that is testament to our passion for making fashion more accessible to all. We see that same excitement, comfort and belief reflected in the eyes of every woman who tries on a Me&B piece.
|
25 |
+
|
26 |
+
Me&B delivers fashion that makes you feel comfortable. Both in your body and your style. We want to help you feel both confident with who you are and how you choose to express yourself. Each piece is designed to feel perfect for now but also fit for years to come.
|
27 |
+
|
28 |
+
We create clothing that invites you to step out and show the world who YOU are while still looking stylishly tailored AND feeling supremely comfortable.
|
29 |
+
|
30 |
+
|
31 |
+
Iris Apfel told the world that “when you don't dress like everybody else, you don't have to think like everybody else.” We believe this wholeheartedly. It’s part of the Me&B philosophy which is quite literally stitched into the fabric of everything we do, from inclusive sizing for every body type all the way through to using compostable delivery bags. So once again welcome to Me&B, we're so happy to have you!
|
32 |
+
|
33 |
+
|
34 |
+
Products :-
|
35 |
+
|
36 |
+
1. the dropped waist shirt dress in scattered floral
|
37 |
+
PRICE :- R899
|
38 |
+
image link :- https://cdn.shopify.com/s/files/1/3003/2366/files/Me_B_4Sept2023_021_80c53c3b-709e-4a18-b735-71fab899ba36.jpg
|
39 |
+
product link :- https://meandb.shop/collections/shop-all-clothing/products/the-dropped-waist-shirt-dress-in-scattered-floral
|
40 |
+
|
41 |
+
2. collared knit top in milk
|
42 |
+
PRICE :- R499
|
43 |
+
image link :- https://cdn.shopify.com/s/files/1/3003/2366/files/Mr_B_16Oct2023_343_fc023756-f4db-4091-af11-0d4437e38deb.jpg
|
44 |
+
product link :- https://meandb.shop/collections/shop-all-clothing/products/collared-knit-top-in-milk
|
45 |
+
|
46 |
+
|
47 |
+
"""
|
examples/sample_product_catalog.txt
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Products :-
|
2 |
+
|
3 |
+
1. the dropped waist shirt dress in scattered floral
|
4 |
+
PRICE :- R899
|
5 |
+
image link :- https://cdn.shopify.com/s/files/1/3003/2366/files/Me_B_4Sept2023_021_80c53c3b-709e-4a18-b735-71fab899ba36.jpg
|
6 |
+
product link :- https://meandb.shop/collections/shop-all-clothing/products/the-dropped-waist-shirt-dress-in-scattered-floral
|
7 |
+
|
8 |
+
2. collared knit top in milk
|
9 |
+
PRICE :- R499
|
10 |
+
image link :- https://cdn.shopify.com/s/files/1/3003/2366/files/Mr_B_16Oct2023_343_fc023756-f4db-4091-af11-0d4437e38deb.jpg
|
11 |
+
product link :- https://meandb.shop/collections/shop-all-clothing/products/collared-knit-top-in-milk
|
main.py
ADDED
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import logging
|
3 |
+
from flask import Flask, request, jsonify, render_template
|
4 |
+
from flask_cors import CORS
|
5 |
+
from dotenv import load_dotenv
|
6 |
+
from salesgpt.agents import SalesGPT
|
7 |
+
from langchain_community.chat_models import ChatLiteLLM
|
8 |
+
import sys
|
9 |
+
import io
|
10 |
+
|
11 |
+
#__import__('pysqlite3')
|
12 |
+
#import sys
|
13 |
+
|
14 |
+
#sys.modules['sqlite3'] = sys.modules.pop('pysqlite3')
|
15 |
+
|
16 |
+
# Load environment variables
|
17 |
+
load_dotenv()
|
18 |
+
|
19 |
+
# Set your OpenAI API key
|
20 |
+
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
|
21 |
+
|
22 |
+
# Initialize the SalesGPT agent
|
23 |
+
llm = ChatLiteLLM(temperature=0.4, model='gpt-3.5-turbo-16k')
|
24 |
+
|
25 |
+
instruction = """
|
26 |
+
|
27 |
+
As the Meandb AI, developed by Tab Robotics, your main responsibility is to provide users with assistance regarding the products offered by Meandb. When addressing users, please use the pronoun 'we' to refer to the company. Your integration on their website aims to ensure prompt and relevant support in a professional manner, enabling users to navigate through available options efficiently. As a user, my questions will solely pertain to Meandb, and not about the AI itself. Therefore, please only provide information based on the data provided. For instance, if I ask 'What products do you provide?', your response should be concise and informative, stating the specific services offered by Meandb. Additionally, when the user greets you at the start of the conversation, please respond with a good response according to the question and provide the info user asks and please continue the conversation like a human. Please look at what you are saying and make sure it makes sense if the user asks a question instead of greeting please answer the question and please continue the conversation like a human. Please try to answer in very short format but also provide the most important information in short. Please maintain some space between the sentences. Try to be happy and positive. When user asks to recommend a product also give him the image link with the product link and price, this is very very very important. If you cant find the link in the dataset please do not make it up because the link will be processed as an image to show to the user. Do not recommend or display any links that are not in the dataset.
|
28 |
+
|
29 |
+
Please provide the image links too that is the most important feature
|
30 |
+
|
31 |
+
"""
|
32 |
+
|
33 |
+
from data import kb
|
34 |
+
|
35 |
+
sales_agent = SalesGPT.from_llm(
|
36 |
+
llm,
|
37 |
+
use_tools=True,
|
38 |
+
product_catalog = "examples\sample_product_catalog.txt",
|
39 |
+
verbose=False,
|
40 |
+
salesperson_name="meandb AI",
|
41 |
+
salesperson_role=instruction + kb,
|
42 |
+
company_name="MeanDb",
|
43 |
+
company_business="Ecommerce")
|
44 |
+
|
45 |
+
# Initialize Flask app
|
46 |
+
app = Flask(__name__)
|
47 |
+
CORS(app)
|
48 |
+
|
49 |
+
|
50 |
+
# Generate response
|
51 |
+
def generate_response(user_input):
|
52 |
+
# Redirect stdout to capture the response
|
53 |
+
captured_output = io.StringIO()
|
54 |
+
sys.stdout = captured_output
|
55 |
+
|
56 |
+
# Process the user input and generate a response
|
57 |
+
sales_agent.human_step(user_input)
|
58 |
+
sales_agent.step()
|
59 |
+
|
60 |
+
# Restore stdout and get the captured output
|
61 |
+
sys.stdout = sys.__stdout__
|
62 |
+
full_response = captured_output.getvalue()
|
63 |
+
|
64 |
+
# Extract the response part after "Heyford AI:"
|
65 |
+
response = full_response.split("meandb AI:", 1)[-1].strip()
|
66 |
+
return response
|
67 |
+
|
68 |
+
|
69 |
+
# Flask routes
|
70 |
+
@app.route('/')
|
71 |
+
def home():
|
72 |
+
return render_template('bannner.html')
|
73 |
+
|
74 |
+
#hello
|
75 |
+
|
76 |
+
@app.route('/get-response', methods=['POST'])
|
77 |
+
def get_response():
|
78 |
+
user_input = request.json['message'].lower().strip()
|
79 |
+
user_id = request.json.get(
|
80 |
+
'user_id') # Get user/session identifier from the request
|
81 |
+
if not user_id:
|
82 |
+
return jsonify({'response': "Error: User ID is missing or invalid."})
|
83 |
+
|
84 |
+
response = generate_response(user_input) # Generate response from the AI
|
85 |
+
return jsonify({'response': response})
|
86 |
+
|
87 |
+
|
88 |
+
if __name__ == '__main__':
|
89 |
+
app.run(host='0.0.0.0', port=7860)
|
90 |
+
#done
|
requirements.txt
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
SalesGPT==0.1.1
|
2 |
+
Flask==2.3.3
|
3 |
+
Flask-Cors==4.0.0
|
4 |
+
langchain== 0.1.0
|
5 |
+
google-generativeai==0.3.2
|
6 |
+
python-dotenv==1.0.1
|
7 |
+
google-generativeai
|
8 |
+
gunicorn
|
static/images/logo.png
ADDED
static/images/test.png
ADDED
static/js/chatbot-widget.js
ADDED
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
(function(window) {
|
2 |
+
function createChatbot() {
|
3 |
+
// Code to create chat UI elements
|
4 |
+
// This can include creating a chat window, input box, send button, etc.
|
5 |
+
|
6 |
+
// Example:
|
7 |
+
var chatWindow = document.createElement('div');
|
8 |
+
chatWindow.id = 'chat-window';
|
9 |
+
// Add more styling and elements to chatWindow as needed
|
10 |
+
|
11 |
+
document.body.appendChild(chatWindow);
|
12 |
+
|
13 |
+
// Setup event listeners for chat interactions, like sending a message
|
14 |
+
setupChatEventListeners();
|
15 |
+
}
|
16 |
+
|
17 |
+
function setupChatEventListeners() {
|
18 |
+
// Code to handle chat input, send button click, etc.
|
19 |
+
// Example: document.getElementById('send-button').addEventListener('click', sendMessageToChatbot);
|
20 |
+
}
|
21 |
+
|
22 |
+
function sendMessageToChatbot(message) {
|
23 |
+
// Code to send the message to your Flask backend and handle the response
|
24 |
+
// Example using fetch API:
|
25 |
+
fetch('http://127.0.0.1:5000//', {
|
26 |
+
method: 'POST',
|
27 |
+
headers: { 'Content-Type': 'application/json' },
|
28 |
+
body: JSON.stringify({ message: message })
|
29 |
+
})
|
30 |
+
.then(response => response.json())
|
31 |
+
.then(data => {
|
32 |
+
// Code to display the chatbot's response in the chat window
|
33 |
+
})
|
34 |
+
.catch(error => {
|
35 |
+
console.error('Error:', error);
|
36 |
+
});
|
37 |
+
}
|
38 |
+
|
39 |
+
// Expose the chatbot initialization function to the window object
|
40 |
+
window.myChatbot = { load: createChatbot };
|
41 |
+
})(window);
|
static/js/script.js
ADDED
@@ -0,0 +1,200 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const chatbotToggler = document.querySelector(".chatbot-toggler");
|
2 |
+
const closeBtn = document.querySelector(".close-btn");
|
3 |
+
const chatbox = document.querySelector(".chatbox");
|
4 |
+
const chatInput = document.querySelector(".chat-input textarea");
|
5 |
+
const sendChatBtn = document.querySelector(".chat-input span");
|
6 |
+
const microphoneBtn = document.getElementById('microphone-btn');
|
7 |
+
|
8 |
+
let userMessage = null;
|
9 |
+
const inputInitHeight = chatInput.scrollHeight;
|
10 |
+
|
11 |
+
// Function to get or create a unique user ID
|
12 |
+
function getUserId() {
|
13 |
+
let userId = localStorage.getItem('userId');
|
14 |
+
if (!userId) {
|
15 |
+
userId = 'user_' + Math.random().toString(36).substr(2, 9);
|
16 |
+
localStorage.setItem('userId', userId);
|
17 |
+
}
|
18 |
+
return userId;
|
19 |
+
}
|
20 |
+
|
21 |
+
function linkify(inputText) {
|
22 |
+
var replacedText, replacePattern1, replacePattern2, replacePattern3;
|
23 |
+
|
24 |
+
//URLs starting with http://, https://, or ftp://
|
25 |
+
replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;
|
26 |
+
replacedText = inputText.replace(replacePattern1, (match) => {
|
27 |
+
// Check if the URL is an image link
|
28 |
+
if (match.match(/\.(jpeg|jpg|gif|png)$/) != null) {
|
29 |
+
return `<img src="${match}" alt="Image" style="max-width:100%;height:auto;">`;
|
30 |
+
} else {
|
31 |
+
return `<a href="${match}" target="_blank">here</a>`;
|
32 |
+
}
|
33 |
+
});
|
34 |
+
|
35 |
+
//URLs starting with "www." (without // before it, or it'd re-link the ones done above).
|
36 |
+
replacePattern2 = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
|
37 |
+
replacedText = replacedText.replace(replacePattern2, '$1<a href="http://$2" target="_blank">$2</a>');
|
38 |
+
|
39 |
+
//Change email addresses to mailto:: links.
|
40 |
+
replacePattern3 = /(([a-zA-Z0-9\-_.])+@[a-zA-Z0-9\-_.]+\.[a-zA-Z]{2,5})/gim;
|
41 |
+
replacedText = replacedText.replace(replacePattern3, '<a href="mailto:$1">$1</a>');
|
42 |
+
|
43 |
+
return replacedText;
|
44 |
+
}
|
45 |
+
|
46 |
+
const createChatLi = (message, className) => {
|
47 |
+
const chatLi = document.createElement("li");
|
48 |
+
chatLi.classList.add("chat", className);
|
49 |
+
let chatContent = className === "outgoing" ?
|
50 |
+
`<p>${message}</p>` :
|
51 |
+
`<span class="material-symbols-outlined">smart_toy</span><p>${linkify(message)}</p>`;
|
52 |
+
chatLi.innerHTML = chatContent;
|
53 |
+
return chatLi;
|
54 |
+
};
|
55 |
+
|
56 |
+
const generateResponse = (chatElement, typingInterval) => {
|
57 |
+
const SERVER_URL = "http://127.0.0.1:7860//get-response";
|
58 |
+
const userId = getUserId();
|
59 |
+
|
60 |
+
fetch(SERVER_URL, {
|
61 |
+
method: "POST",
|
62 |
+
headers: {
|
63 |
+
"Content-Type": "application/json"
|
64 |
+
},
|
65 |
+
body: JSON.stringify({
|
66 |
+
message: userMessage,
|
67 |
+
user_id: userId
|
68 |
+
})
|
69 |
+
})
|
70 |
+
.then(res => res.json())
|
71 |
+
.then(data => {
|
72 |
+
clearInterval(typingInterval); // Make sure to clear the typing animation
|
73 |
+
const incomingChatLi = createChatLi(data.response, "incoming"); // Create a new chat bubble for the response
|
74 |
+
chatbox.replaceChild(incomingChatLi, chatElement); // Replace the "Typing..." bubble with the response bubble
|
75 |
+
chatbox.scrollTo(0, chatbox.scrollHeight); // Scroll to the new message
|
76 |
+
})
|
77 |
+
.catch((error) => {
|
78 |
+
clearInterval(typingInterval); // Also clear the typing animation in case of error
|
79 |
+
console.error('Error:', error);
|
80 |
+
chatElement.querySelector("p").textContent = "Oops! Something went wrong. Please try again.";
|
81 |
+
});
|
82 |
+
}
|
83 |
+
|
84 |
+
const handleSend = () => {
|
85 |
+
userMessage = chatInput.value.trim();
|
86 |
+
if (!userMessage) return;
|
87 |
+
|
88 |
+
const outgoingChatLi = createChatLi(userMessage, "outgoing");
|
89 |
+
chatbox.appendChild(outgoingChatLi);
|
90 |
+
chatbox.scrollTo(0, chatbox.scrollHeight);
|
91 |
+
chatInput.value = "";
|
92 |
+
chatInput.style.height = `${inputInitHeight}px`;
|
93 |
+
|
94 |
+
setTimeout(() => {
|
95 |
+
const incomingChatLi = createChatLi("Typing.", "incoming");
|
96 |
+
chatbox.appendChild(incomingChatLi);
|
97 |
+
chatbox.scrollTo(0, chatbox.scrollHeight);
|
98 |
+
|
99 |
+
let dotCount = 1;
|
100 |
+
const typingInterval = setInterval(() => {
|
101 |
+
incomingChatLi.innerHTML = `<span class="material-symbols-outlined">smart_toy</span><p>Typing${'.'.repeat(dotCount)}</p>`;
|
102 |
+
dotCount = (dotCount % 6) + 1; // Cycle dotCount from 1 to 6
|
103 |
+
}, 500);
|
104 |
+
|
105 |
+
generateResponse(incomingChatLi, typingInterval); // Pass the typingInterval to the generateResponse function
|
106 |
+
}, 600);
|
107 |
+
};
|
108 |
+
|
109 |
+
function updateTypingMessage(message) {
|
110 |
+
const typingElements = document.getElementsByClassName('typing');
|
111 |
+
if(typingElements.length > 0) {
|
112 |
+
// Assuming there's only one typing element at a time
|
113 |
+
typingElements[0].innerText = message;
|
114 |
+
} else {
|
115 |
+
// Create new typing element if it doesn't exist
|
116 |
+
const incomingChatLi = createChatLi(message, "incoming");
|
117 |
+
chatbox.appendChild(incomingChatLi);
|
118 |
+
chatbox.scrollTo(0, chatbox.scrollHeight);
|
119 |
+
}
|
120 |
+
}
|
121 |
+
|
122 |
+
chatInput.addEventListener("input", () => {
|
123 |
+
chatInput.style.height = "auto";
|
124 |
+
chatInput.style.height = `${chatInput.scrollHeight}px`;
|
125 |
+
});
|
126 |
+
|
127 |
+
chatInput.addEventListener("keydown", (e) => {
|
128 |
+
if (e.key === "Enter" && !e.shiftKey) {
|
129 |
+
e.preventDefault(); // Prevent the default action to avoid a newline
|
130 |
+
handleSend(); // Call the send handler
|
131 |
+
}
|
132 |
+
});
|
133 |
+
|
134 |
+
sendChatBtn.addEventListener("click", handleSend);
|
135 |
+
closeBtn.addEventListener("click", () => document.body.classList.remove("show-chatbot"));
|
136 |
+
chatbotToggler.addEventListener("click", () => document.body.classList.toggle("show-chatbot"));
|
137 |
+
|
138 |
+
|
139 |
+
// Enhanced Speech Recognition setup
|
140 |
+
const recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
|
141 |
+
recognition.continuous = false;
|
142 |
+
recognition.lang = 'en-US';
|
143 |
+
recognition.interimResults = false;
|
144 |
+
recognition.maxAlternatives = 1;
|
145 |
+
|
146 |
+
let isSpeechDetected = false;
|
147 |
+
let recognitionTimeout;
|
148 |
+
|
149 |
+
function updateMicrophoneIcon(isListening) {
|
150 |
+
if (isListening) {
|
151 |
+
microphoneBtn.classList.add('listening');
|
152 |
+
} else {
|
153 |
+
microphoneBtn.classList.remove('listening');
|
154 |
+
}
|
155 |
+
}
|
156 |
+
|
157 |
+
recognition.onstart = function() {
|
158 |
+
console.log('Voice recognition activated. Start speaking.');
|
159 |
+
updateMicrophoneIcon(true);
|
160 |
+
clearTimeout(recognitionTimeout);
|
161 |
+
isSpeechDetected = false;
|
162 |
+
};
|
163 |
+
|
164 |
+
recognition.onspeechend = function() {
|
165 |
+
setTimeout(() => {
|
166 |
+
recognition.stop();
|
167 |
+
if (!isSpeechDetected) {
|
168 |
+
chatbox.appendChild(createChatLi("No speech detected. Please try again.", "incoming"));
|
169 |
+
}
|
170 |
+
}, 2000 + Math.random() * 2000); // Random delay between 2 to 4 seconds
|
171 |
+
};
|
172 |
+
|
173 |
+
recognition.onresult = function(event) {
|
174 |
+
isSpeechDetected = true;
|
175 |
+
const transcript = event.results[0][0].transcript;
|
176 |
+
chatInput.value = transcript;
|
177 |
+
updateMicrophoneIcon(false);
|
178 |
+
handleChat();
|
179 |
+
};
|
180 |
+
|
181 |
+
recognition.onerror = function(event) {
|
182 |
+
console.error('Speech recognition error detected: ' + event.error);
|
183 |
+
updateMicrophoneIcon(false);
|
184 |
+
chatbox.appendChild(createChatLi(`Error in speech recognition: ${event.error}`, "incoming"));
|
185 |
+
};
|
186 |
+
|
187 |
+
microphoneBtn.addEventListener('click', function() {
|
188 |
+
if (microphoneBtn.classList.contains('listening')) {
|
189 |
+
recognition.stop();
|
190 |
+
} else {
|
191 |
+
recognition.start();
|
192 |
+
recognitionTimeout = setTimeout(() => {
|
193 |
+
if (!isSpeechDetected) {
|
194 |
+
recognition.stop();
|
195 |
+
updateMicrophoneIcon(false);
|
196 |
+
chatbox.appendChild(createChatLi("No speech detected. Please try again.", "incoming"));
|
197 |
+
}
|
198 |
+
}, 12000); // Adjusted total time to 12 seconds (10 seconds listening + up to 2 seconds delay)
|
199 |
+
}
|
200 |
+
});
|
static/style.css
ADDED
@@ -0,0 +1,317 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap');
|
2 |
+
|
3 |
+
* {
|
4 |
+
margin: 0;
|
5 |
+
padding: 0;
|
6 |
+
box-sizing: border-box;
|
7 |
+
font-family: "Poppins", sans-serif;
|
8 |
+
}
|
9 |
+
|
10 |
+
body {
|
11 |
+
background: transparent;
|
12 |
+
}
|
13 |
+
|
14 |
+
.chatbot-toggler {
|
15 |
+
position: fixed;
|
16 |
+
bottom: 30px;
|
17 |
+
right: 35px;
|
18 |
+
outline: none;
|
19 |
+
border: none;
|
20 |
+
height: 50px;
|
21 |
+
width: 50px;
|
22 |
+
display: flex;
|
23 |
+
cursor: pointer;
|
24 |
+
align-items: center;
|
25 |
+
justify-content: center;
|
26 |
+
border-radius: 50%;
|
27 |
+
background: #000000;
|
28 |
+
transition: all 0.2s ease;
|
29 |
+
}
|
30 |
+
|
31 |
+
body.show-chatbot .chatbot-toggler {
|
32 |
+
transform: rotate(90deg);
|
33 |
+
}
|
34 |
+
|
35 |
+
.chatbot-toggler span {
|
36 |
+
color: #fff;
|
37 |
+
position: absolute;
|
38 |
+
}
|
39 |
+
|
40 |
+
.chatbot-toggler span:last-child,
|
41 |
+
body.show-chatbot .chatbot-toggler span:first-child {
|
42 |
+
opacity: 0;
|
43 |
+
}
|
44 |
+
|
45 |
+
body.show-chatbot .chatbot-toggler span:last-child {
|
46 |
+
opacity: 1;
|
47 |
+
}
|
48 |
+
|
49 |
+
.header-content {
|
50 |
+
display: flex;
|
51 |
+
align-items: center;
|
52 |
+
justify-content: start;
|
53 |
+
padding: 10px;
|
54 |
+
position: relative;
|
55 |
+
border-bottom: 2px solid #000000; /* Red border added */
|
56 |
+
}
|
57 |
+
|
58 |
+
.profile-pic {
|
59 |
+
width: 50px;
|
60 |
+
height: 50px;
|
61 |
+
border-radius: 50%;
|
62 |
+
margin-right: 10px;
|
63 |
+
}
|
64 |
+
|
65 |
+
h3, p {
|
66 |
+
margin: 0;
|
67 |
+
}
|
68 |
+
|
69 |
+
.chatbot {
|
70 |
+
position: fixed;
|
71 |
+
right: 35px;
|
72 |
+
bottom: 90px;
|
73 |
+
width: 420px;
|
74 |
+
background: #fff;
|
75 |
+
border-radius: 15px;
|
76 |
+
overflow: hidden;
|
77 |
+
opacity: 0;
|
78 |
+
pointer-events: none;
|
79 |
+
transform: scale(0.5);
|
80 |
+
transform-origin: bottom right;
|
81 |
+
/* Removed the box-shadow and added a black border */
|
82 |
+
border: 0.5px solid #000000; /* Black border added */
|
83 |
+
transition: all 0.1s ease;
|
84 |
+
}
|
85 |
+
|
86 |
+
body.show-chatbot .chatbot {
|
87 |
+
opacity: 1;
|
88 |
+
pointer-events: auto;
|
89 |
+
transform: scale(1);
|
90 |
+
}
|
91 |
+
|
92 |
+
.chatbot header {
|
93 |
+
padding: 5px 0;
|
94 |
+
position: relative;
|
95 |
+
text-align: center;
|
96 |
+
color: #ffffff;
|
97 |
+
border-bottom: 2px solid #000000;
|
98 |
+
bottom: 2.5px;
|
99 |
+
background: rgb(255, 255, 255);
|
100 |
+
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
101 |
+
}
|
102 |
+
|
103 |
+
.chatbot header span {
|
104 |
+
position: absolute;
|
105 |
+
right: 15px;
|
106 |
+
top: 50%;
|
107 |
+
display: none;
|
108 |
+
cursor: pointer;
|
109 |
+
transform: translateY(-50%);
|
110 |
+
}
|
111 |
+
|
112 |
+
.chat-icon {
|
113 |
+
width: 40px; /* Updated width */
|
114 |
+
height: 40px; /* Updated height */
|
115 |
+
border-radius: 50%;
|
116 |
+
margin-right: 10px;
|
117 |
+
vertical-align: middle; /* Aligns image with text */
|
118 |
+
margin-right: 10px; /* Adds some space between the icon and the text */
|
119 |
+
object-fit: cover; /* Ensures the image covers the area without being stretched */
|
120 |
+
border: none; /* Remove any border */
|
121 |
+
}
|
122 |
+
|
123 |
+
header h2 {
|
124 |
+
font-size: 1.4rem;
|
125 |
+
}
|
126 |
+
|
127 |
+
.chatbot .chatbox {
|
128 |
+
overflow-y: auto;
|
129 |
+
height: 510px;
|
130 |
+
padding: 30px 20px 100px;
|
131 |
+
}
|
132 |
+
|
133 |
+
.chatbot :where(.chatbox, textarea)::-webkit-scrollbar {
|
134 |
+
width: 6px;
|
135 |
+
}
|
136 |
+
|
137 |
+
.chatbot :where(.chatbox, textarea)::-webkit-scrollbar-track {
|
138 |
+
background: #fff;
|
139 |
+
border-radius: 25px;
|
140 |
+
}
|
141 |
+
|
142 |
+
.chatbot :where(.chatbox, textarea)::-webkit-scrollbar-thumb {
|
143 |
+
background: #ccc;
|
144 |
+
border-radius: 25px;
|
145 |
+
}
|
146 |
+
|
147 |
+
.chatbox .chat {
|
148 |
+
display: flex;
|
149 |
+
list-style: none;
|
150 |
+
}
|
151 |
+
|
152 |
+
.chatbox .outgoing {
|
153 |
+
margin: 20px 0;
|
154 |
+
color: #000;
|
155 |
+
justify-content: flex-end;
|
156 |
+
}
|
157 |
+
|
158 |
+
.chatbox .incoming span {
|
159 |
+
width: 32px;
|
160 |
+
height: 32px;
|
161 |
+
color: #fff;
|
162 |
+
cursor: default;
|
163 |
+
text-align: center;
|
164 |
+
line-height: 32px;
|
165 |
+
align-self: flex-end;
|
166 |
+
background: #000000;
|
167 |
+
border-radius: 4px;
|
168 |
+
margin: 0 10px 7px 0;
|
169 |
+
}
|
170 |
+
|
171 |
+
.chatbox .chat p {
|
172 |
+
white-space: pre-wrap;
|
173 |
+
padding: 12px 16px;
|
174 |
+
border-radius: 10px 10px 0 10px;
|
175 |
+
max-width: 75%;
|
176 |
+
color: #fffcfc;
|
177 |
+
font-size: 0.95rem;
|
178 |
+
background: #000000;
|
179 |
+
}
|
180 |
+
|
181 |
+
.chatbox .incoming p {
|
182 |
+
border-radius: 10px 10px 10px 0;
|
183 |
+
color: #303030; /* Darker text color for incoming messages */
|
184 |
+
background: #f2f2f2;
|
185 |
+
}
|
186 |
+
|
187 |
+
.chatbox .chat p.error {
|
188 |
+
color: #303030;
|
189 |
+
background: #f8d7da;
|
190 |
+
}
|
191 |
+
|
192 |
+
.chatbot .chat-input {
|
193 |
+
display: flex;
|
194 |
+
gap: 5px;
|
195 |
+
position: absolute;
|
196 |
+
bottom: 0;
|
197 |
+
width: 100%;
|
198 |
+
background: #fff;
|
199 |
+
padding: 3px 20px;
|
200 |
+
border-top: 1px solid #ddd;
|
201 |
+
}
|
202 |
+
|
203 |
+
@keyframes typing {
|
204 |
+
0% { content: 'Typing'; }
|
205 |
+
25% { content: 'Typing.'; }
|
206 |
+
50% { content: 'Typing..'; }
|
207 |
+
75% { content: 'Typing...'; }
|
208 |
+
}
|
209 |
+
|
210 |
+
.typing-animation {
|
211 |
+
display: inline-block;
|
212 |
+
position: relative;
|
213 |
+
}
|
214 |
+
|
215 |
+
.typing-animation::after {
|
216 |
+
content: 'Typing';
|
217 |
+
animation: typing 1.5s steps(4, end) infinite;
|
218 |
+
position: absolute;
|
219 |
+
left: 0;
|
220 |
+
bottom: 0;
|
221 |
+
}
|
222 |
+
|
223 |
+
.chat-input textarea {
|
224 |
+
height: 55px;
|
225 |
+
width: 100%;
|
226 |
+
border: none;
|
227 |
+
outline: none;
|
228 |
+
resize: none;
|
229 |
+
size: auto;
|
230 |
+
max-height: 60px;
|
231 |
+
padding: 17px 15px 15px 0;
|
232 |
+
font-size: 0.95rem;
|
233 |
+
}
|
234 |
+
|
235 |
+
.chat-input span {
|
236 |
+
align-self: flex-end;
|
237 |
+
color: #000000;
|
238 |
+
cursor: pointer;
|
239 |
+
height: 55px;
|
240 |
+
display: flex;
|
241 |
+
align-items: center;
|
242 |
+
visibility: hidden;
|
243 |
+
font-size: 1.35rem;
|
244 |
+
}
|
245 |
+
|
246 |
+
.chat-input textarea:valid ~ span {
|
247 |
+
visibility: visible;
|
248 |
+
}
|
249 |
+
|
250 |
+
/* Your existing styles */
|
251 |
+
header {
|
252 |
+
position: relative;
|
253 |
+
background-color: #913a3a; /* Adjust background color as needed */
|
254 |
+
}
|
255 |
+
|
256 |
+
.header-img {
|
257 |
+
width: 100%;
|
258 |
+
padding-right: 20px;
|
259 |
+
display: block;
|
260 |
+
}
|
261 |
+
|
262 |
+
.close-btn {
|
263 |
+
position: absolute;
|
264 |
+
right: 10px;
|
265 |
+
top: 10px;
|
266 |
+
color: #b82d2d; /* Adjust close button color as needed */
|
267 |
+
cursor: pointer;
|
268 |
+
}
|
269 |
+
|
270 |
+
/* New style for the chatbot icon within the chat messages */
|
271 |
+
.chat-icon {
|
272 |
+
width: 54px; /* Example size, adjust as needed */
|
273 |
+
height: fit-content; /* Example size, adjust as needed */
|
274 |
+
vertical-align: middle; /* Aligns image with text */
|
275 |
+
margin-right: 10px; /* Adds some space between the icon and the text */
|
276 |
+
}
|
277 |
+
|
278 |
+
.chat-input #microphone-btn {
|
279 |
+
align-self: flex-end;
|
280 |
+
color: #000000;
|
281 |
+
cursor: pointer;
|
282 |
+
height: 55px;
|
283 |
+
display: flex;
|
284 |
+
align-items: center;
|
285 |
+
font-size: 1.35rem;
|
286 |
+
background: transparent;
|
287 |
+
border: none;
|
288 |
+
margin-right: 10px;
|
289 |
+
}
|
290 |
+
|
291 |
+
@media (max-width: 490px) {
|
292 |
+
.chatbot-toggler {
|
293 |
+
right: 20px;
|
294 |
+
bottom: 20px;
|
295 |
+
}
|
296 |
+
|
297 |
+
.chatbot {
|
298 |
+
right: 0;
|
299 |
+
bottom: 0;
|
300 |
+
height: 100%;
|
301 |
+
border-radius: 0;
|
302 |
+
width: 100%;
|
303 |
+
}
|
304 |
+
|
305 |
+
.chatbot .chatbox {
|
306 |
+
height: 90%;
|
307 |
+
padding: 25px 15px 100px;
|
308 |
+
}
|
309 |
+
|
310 |
+
.chatbot .chat-input {
|
311 |
+
padding: 5px 15px;
|
312 |
+
}
|
313 |
+
|
314 |
+
.chatbot header span {
|
315 |
+
display: block;
|
316 |
+
}
|
317 |
+
}
|
templates/bannner.html
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html lang="en" dir="ltr">
|
3 |
+
<head>
|
4 |
+
<meta charset="utf-8">
|
5 |
+
<title>Chat AI</title>
|
6 |
+
<link rel="stylesheet" href="static/style.css"> <!-- Link to your external CSS file -->
|
7 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
8 |
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@48,400,0,0" />
|
9 |
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@48,400,1,0" />
|
10 |
+
<script src="{{ url_for('static', filename='js/script.js') }}" defer></script> <!-- Link to your external JavaScript file -->
|
11 |
+
</head>
|
12 |
+
<body>
|
13 |
+
<button class="chatbot-toggler">
|
14 |
+
<span class="material-symbols-rounded">mode_comment</span>
|
15 |
+
<span class="material-symbols-outlined">close</span>
|
16 |
+
</button>
|
17 |
+
<div class="chatbot">
|
18 |
+
<header>
|
19 |
+
<img src="static/images/test.png" alt="Chatbot Icon" class="header-img">
|
20 |
+
<span class="close-btn material-symbols-outlined">close</span>
|
21 |
+
</header>
|
22 |
+
<ul class="chatbox">
|
23 |
+
<li class="chat incoming">
|
24 |
+
<span class="material-symbols-outlined">smart_toy</span>
|
25 |
+
<p>Hello, welcome to meandb. <br>Can I answer any questions for you ?</p>
|
26 |
+
</li>
|
27 |
+
<!-- Additional chat messages can be added here -->
|
28 |
+
</ul>
|
29 |
+
<div class="chat-input">
|
30 |
+
<textarea placeholder="Enter a message..." spellcheck="false" required></textarea>
|
31 |
+
<button id="microphone-btn" class="material-symbols-rounded">mic</button>
|
32 |
+
<span id="send-btn" class="material-symbols-rounded">send</span>
|
33 |
+
</div>
|
34 |
+
</div>
|
35 |
+
<script src="static/js/script.js"></script> <!-- Link to your external JavaScript file -->
|
36 |
+
</body>
|
37 |
+
</html>
|
thread_data/threads_db.bak
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
'user_55ijq1r15', (0, 46)
|
thread_data/threads_db.dat
ADDED
Binary file (46 Bytes). View file
|
|
thread_data/threads_db.dir
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
'user_55ijq1r15', (0, 46)
|