Spaces:
Runtime error
Runtime error
Commit
•
3f4d0b1
1
Parent(s):
2d26353
final_commit
Browse files- Dockerfile +27 -0
- main.py +186 -0
- requirements.txt +0 -0
- static/script.js +96 -0
- static/styles.css +172 -0
- templates/index.html +46 -0
Dockerfile
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Use the official Python 3.9 image
|
2 |
+
FROM python:3.9
|
3 |
+
|
4 |
+
# Set the working directory to /code
|
5 |
+
WORKDIR /code
|
6 |
+
|
7 |
+
# Copy the current directory contents into the container at /code
|
8 |
+
COPY ./requirements.txt /code/requirements.txt
|
9 |
+
|
10 |
+
# Install requirements.txt
|
11 |
+
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
12 |
+
|
13 |
+
# Set up a new user named "user" with user ID 1000
|
14 |
+
RUN useradd -m -u 1000 user
|
15 |
+
# Switch to the "user" user
|
16 |
+
USER user
|
17 |
+
# Set home to the user's home directory
|
18 |
+
ENV HOME=/home/user \
|
19 |
+
PATH=/home/user/.local/bin:$PATH
|
20 |
+
|
21 |
+
# Set the working directory to the user's home directory
|
22 |
+
WORKDIR $HOME/app
|
23 |
+
|
24 |
+
# Copy the current directory contents into the container at $HOME/app setting the owner to the user
|
25 |
+
COPY --chown=user . $HOME/app
|
26 |
+
|
27 |
+
CMD ["uvicorn", "mai:app", "--host", "0.0.0.0", "--port", "7860"]
|
main.py
ADDED
@@ -0,0 +1,186 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Import necessary libraries
|
2 |
+
from flask import Flask, render_template, request, jsonify
|
3 |
+
from PIL import Image
|
4 |
+
from peft import PeftModel
|
5 |
+
from PIL import Image
|
6 |
+
import torch
|
7 |
+
from transformers import AutoProcessor, LlavaForConditionalGeneration, BitsAndBytesConfig
|
8 |
+
from deep_translator import GoogleTranslator
|
9 |
+
from transformers import M2M100ForConditionalGeneration, M2M100Tokenizer
|
10 |
+
from fastapi import FastAPI
|
11 |
+
import warnings
|
12 |
+
# from flask import Flask
|
13 |
+
|
14 |
+
# from flask_ngrok import run_with_ngrok
|
15 |
+
# app = Flask(__name__)
|
16 |
+
# run_with_ngrok(app)
|
17 |
+
app = FastAPI()
|
18 |
+
|
19 |
+
warnings.filterwarnings('ignore')
|
20 |
+
|
21 |
+
# model_id = "HuggingFaceH4/vsft-llava-1.5-7b-hf-trl"
|
22 |
+
# quantization_config = BitsAndBytesConfig(load_in_4bit=True)
|
23 |
+
# base_model = LlavaForConditionalGeneration.from_pretrained(model_id, quantization_config=quantization_config, torch_dtype=torch.float16)
|
24 |
+
|
25 |
+
# # Load the PEFT Lora adapter
|
26 |
+
# peft_lora_adapter_path = "Praveen0309/llava-1.5-7b-hf-ft-mix-vsft-3"
|
27 |
+
# peft_lora_adapter = PeftModel.from_pretrained(base_model, peft_lora_adapter_path, adapter_name="lora_adapter")
|
28 |
+
# base_model.load_adapter(peft_lora_adapter_path, adapter_name="lora_adapter")
|
29 |
+
|
30 |
+
# processor = AutoProcessor.from_pretrained("HuggingFaceH4/vsft-llava-1.5-7b-hf-trl")
|
31 |
+
# model = M2M100ForConditionalGeneration.from_pretrained("facebook/m2m100_418M")
|
32 |
+
# tokenizer = M2M100Tokenizer.from_pretrained("facebook/m2m100_418M")
|
33 |
+
|
34 |
+
|
35 |
+
# model_id = r"C:\Users\prave\OneDrive\Desktop\MLOPS\Mlops_2\huggingface_model"
|
36 |
+
# quantization_config = BitsAndBytesConfig(
|
37 |
+
# load_in_4bit=True,
|
38 |
+
# )
|
39 |
+
# base_model = LlavaForConditionalGeneration.from_pretrained(model_id)
|
40 |
+
|
41 |
+
# processor = AutoProcessor.from_pretrained(r"C:\Users\prave\OneDrive\Desktop\MLOPS\Mlops_2\huggingface_processor")
|
42 |
+
|
43 |
+
# Load the PEFT Lora model (adapter)
|
44 |
+
# peft_lora_adapter_path = r"C:\Users\prave\OneDrive\Desktop\MLOPS\Mlops_2\huggingface_adapter"
|
45 |
+
|
46 |
+
# Merge the adapters into the base model
|
47 |
+
# model = M2M100ForConditionalGeneration.from_pretrained("facebook/m2m100_418M")
|
48 |
+
# tokenizer = M2M100Tokenizer.from_pretrained("facebook/m2m100_418M")
|
49 |
+
|
50 |
+
|
51 |
+
def inference(image_prompt, image):
|
52 |
+
prompt = f"USER: <image>\n{image_prompt} ASSISTANT:"
|
53 |
+
inputs = processor(text=prompt, images=image, return_tensors="pt")
|
54 |
+
generate_ids = base_model.generate(**inputs, max_new_tokens=1024)
|
55 |
+
decoded_response = processor.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]
|
56 |
+
|
57 |
+
# prompt = "USER: <image>\nWhat's the content of the image? ASSISTANT:"
|
58 |
+
# url = "https://www.ilankelman.org/stopsigns/australia.jpg"
|
59 |
+
# url = "/kaggle/input/images/images/1921.428_web.jpg"
|
60 |
+
# image = Image.open(url)
|
61 |
+
# image = Image.open(requests.get(url, stream=True).raw)
|
62 |
+
# processor = AutoProcessor.from_pretrained("llava-hf/llava-1.5-7b-hf")
|
63 |
+
# ... process the image and create inputs ...
|
64 |
+
# print("Generated response:", decoded_response)
|
65 |
+
return decoded_response
|
66 |
+
|
67 |
+
def deep_translator_bn_en(input_sentence):
|
68 |
+
english_translation = GoogleTranslator(source="bn", target="en").translate(input_sentence)
|
69 |
+
return english_translation
|
70 |
+
|
71 |
+
def deep_translator_en_bn(input_sentence):
|
72 |
+
bengali_translation = GoogleTranslator(source="en", target="bn").translate(input_sentence)
|
73 |
+
return bengali_translation
|
74 |
+
|
75 |
+
def google_response(image, input_sentence):
|
76 |
+
image_prompt = deep_translator_bn_en(input_sentence)
|
77 |
+
response = inference(image_prompt, image)
|
78 |
+
assistant_index = response.find("ASSISTANT:")
|
79 |
+
extracted_string = response[assistant_index + len("ASSISTANT:"):].strip()
|
80 |
+
output = deep_translator_en_bn(extracted_string)
|
81 |
+
# print("বটী: ", output)
|
82 |
+
|
83 |
+
# url = input("ইমেজ url লিখুন: ")
|
84 |
+
# input_sentence = input("ছবি সম্পর্কে আপনার প্রশ্ন লিখুন: ")
|
85 |
+
return output
|
86 |
+
|
87 |
+
|
88 |
+
def facebook_bn_en(input_sentence):
|
89 |
+
|
90 |
+
# Translate Bengali to English
|
91 |
+
tokenizer.src_lang = "bn"
|
92 |
+
encoded_bn = tokenizer(input_sentence, return_tensors="pt")
|
93 |
+
generated_tokens = model.generate(**encoded_bn, forced_bos_token_id=tokenizer.get_lang_id("en"))
|
94 |
+
translated_text_en = tokenizer.batch_decode(generated_tokens, skip_special_tokens=True)[0]
|
95 |
+
return translated_text_en
|
96 |
+
# print("Translated English:", translated_text_en)
|
97 |
+
|
98 |
+
def facebook_en_bn(input_sentence):
|
99 |
+
# Translate English to Bengali
|
100 |
+
# model = M2M100ForConditionalGeneration.from_pretrained("facebook/m2m100_418M")
|
101 |
+
# tokenizer = M2M100Tokenizer.from_pretrained("facebook/m2m100_418M")
|
102 |
+
tokenizer.src_lang = "en"
|
103 |
+
encoded_en = tokenizer(input_sentence, return_tensors="pt")
|
104 |
+
generated_tokens = model.generate(**encoded_en, forced_bos_token_id=tokenizer.get_lang_id("bn"))
|
105 |
+
translated_text_bn = tokenizer.batch_decode(generated_tokens, skip_special_tokens=True)[0]
|
106 |
+
return translated_text_bn
|
107 |
+
|
108 |
+
def facebook_response(url, input_sentence):
|
109 |
+
url = input("ইমেজ url লিখুন: ")
|
110 |
+
input_sentence = input("ছবি সম্পর্কে আপনার প্রশ্ন লিখুন: ")
|
111 |
+
image_prompt = facebook_bn_en(input_sentence)
|
112 |
+
response = inference(image_prompt, url)
|
113 |
+
assistant_index = response.find("ASSISTANT:")
|
114 |
+
extracted_string = response[assistant_index + len("ASSISTANT:"):].strip()
|
115 |
+
output = facebook_en_bn(extracted_string)
|
116 |
+
print("বটী: ", output)
|
117 |
+
return output
|
118 |
+
|
119 |
+
|
120 |
+
image_cache = {}
|
121 |
+
@app.post('/upload/')
|
122 |
+
def upload_file():
|
123 |
+
try:
|
124 |
+
file = request.files['file']
|
125 |
+
if file.filename.endswith('.jpg'):
|
126 |
+
image = Image.open(file.stream)
|
127 |
+
# Store the image in cache (replace with a more suitable storage approach)
|
128 |
+
image_cache['image'] = image
|
129 |
+
# print("Processing complete. Image stored in cache.")
|
130 |
+
return jsonify({'status': 'success'})
|
131 |
+
else:
|
132 |
+
return jsonify({'status': 'error', 'message': 'Uploaded file is not a jpg image.'})
|
133 |
+
except Exception as e:
|
134 |
+
# print(f"Error during file upload: {e}")
|
135 |
+
return jsonify({'status': 'error', 'message': str(e)})
|
136 |
+
|
137 |
+
|
138 |
+
@app.get("/")
|
139 |
+
def home():
|
140 |
+
return render_template("index.html")
|
141 |
+
|
142 |
+
@app.get("/get/")
|
143 |
+
def get_bot_response():
|
144 |
+
try:
|
145 |
+
if 'image' in image_cache:
|
146 |
+
image = image_cache['image']
|
147 |
+
# print(image)
|
148 |
+
query = request.args.get('msg')
|
149 |
+
output = query
|
150 |
+
# output = google_response(image, query)
|
151 |
+
return output
|
152 |
+
else:
|
153 |
+
return "Please upload an image to continue"
|
154 |
+
except Exception as e:
|
155 |
+
return f"Error: {str(e)}"
|
156 |
+
|
157 |
+
|
158 |
+
# Run the Flask app
|
159 |
+
# if __name__ == "__main__":
|
160 |
+
app.run(debug = True)
|
161 |
+
|
162 |
+
|
163 |
+
# from pymongo import MongoClient
|
164 |
+
|
165 |
+
# # Connect to MongoDB
|
166 |
+
# mongodb_client = MongoClient('mongodb://localhost:27017/')
|
167 |
+
# database_name = 'your_database'
|
168 |
+
# collection_name = 'file_store'
|
169 |
+
|
170 |
+
# db = mongodb_client[database_name]
|
171 |
+
# collection = db[collection_name]
|
172 |
+
|
173 |
+
# # Store documents with unique ID and their chunks
|
174 |
+
# for i, doc in enumerate(documents):
|
175 |
+
# doc_id = f'doc_{i}' # Create a unique ID for each document
|
176 |
+
# collection.insert_one({'_id': doc_id, 'document': doc})
|
177 |
+
|
178 |
+
# # Check if index exists, if not create a new one
|
179 |
+
# if 'index' not in collection.list_indexes():
|
180 |
+
# index = VectorStoreIndex.from_documents(documents, storage_context=storage_context)
|
181 |
+
# collection.insert_one({'_id': 'index', 'index': index})
|
182 |
+
# else:
|
183 |
+
# index = collection.find_one({'_id': 'index'})['index']
|
184 |
+
|
185 |
+
# # Retrieve documents
|
186 |
+
# retrieved_text_chunks = index.as_retriever().retrieve(question)
|
requirements.txt
ADDED
Binary file (1.62 kB). View file
|
|
static/script.js
ADDED
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
$(document).ready(function(){
|
2 |
+
$('#uploadForm').on('submit', function(e){
|
3 |
+
e.preventDefault();
|
4 |
+
$('#uploadStatus').html('<p>Status: Processing...</p>');
|
5 |
+
$.ajax({
|
6 |
+
url: '/upload',
|
7 |
+
type: 'POST',
|
8 |
+
data: new FormData(this),
|
9 |
+
contentType: false,
|
10 |
+
cache: false,
|
11 |
+
processData:false,
|
12 |
+
success: function(response){
|
13 |
+
$('#uploadStatus').html('<p>Status: '+response.status+'</p>');
|
14 |
+
}
|
15 |
+
});
|
16 |
+
});
|
17 |
+
});
|
18 |
+
|
19 |
+
|
20 |
+
(function () {
|
21 |
+
var Message;
|
22 |
+
Message = function (arg) {
|
23 |
+
this.text = arg.text, this.message_side = arg.message_side;
|
24 |
+
this.draw = function (_this) {
|
25 |
+
return function () {
|
26 |
+
var $message;
|
27 |
+
$message = $($('.message_template').clone().html());
|
28 |
+
$message.addClass(_this.message_side === 'user' ? 'user-message' : 'bot-message')
|
29 |
+
.find('.text').html(_this.text);
|
30 |
+
$('.messages').append($message);
|
31 |
+
return setTimeout(function () {
|
32 |
+
return $message.addClass('appeared');
|
33 |
+
}, 0);
|
34 |
+
};
|
35 |
+
}(this);
|
36 |
+
return this;
|
37 |
+
};
|
38 |
+
|
39 |
+
$(function () {
|
40 |
+
var getMessageText, sendMessage;
|
41 |
+
getMessageText = function () {
|
42 |
+
var $message_input;
|
43 |
+
$message_input = $('.message_input');
|
44 |
+
return $message_input.val();
|
45 |
+
};
|
46 |
+
|
47 |
+
sendMessage = function (text) {
|
48 |
+
var $messages, message;
|
49 |
+
if (text.trim() === '') {
|
50 |
+
return;
|
51 |
+
}
|
52 |
+
$('.message_input').val('');
|
53 |
+
$messages = $('.messages');
|
54 |
+
|
55 |
+
// Set message_side based on whether the message is from the user or chatbot
|
56 |
+
var userMessageSide = 'user';
|
57 |
+
var botMessageSide = 'bot';
|
58 |
+
|
59 |
+
// Draw user message with user-message class
|
60 |
+
message = new Message({
|
61 |
+
text: text,
|
62 |
+
message_side: userMessageSide
|
63 |
+
});
|
64 |
+
message.draw();
|
65 |
+
|
66 |
+
// Call getResponse() to get the chatbot's response
|
67 |
+
$.get("/get", { msg: text }).done(function(data) {
|
68 |
+
// Draw bot message with bot-message class
|
69 |
+
var botMessage = new Message({
|
70 |
+
text: data,
|
71 |
+
message_side: botMessageSide
|
72 |
+
});
|
73 |
+
botMessage.draw();
|
74 |
+
$messages.animate({ scrollTop: $messages.prop('scrollHeight') }, 300);
|
75 |
+
});
|
76 |
+
|
77 |
+
return $messages.animate({ scrollTop: $messages.prop('scrollHeight') }, 300);
|
78 |
+
};
|
79 |
+
|
80 |
+
$('.send_message').click(function (e) {
|
81 |
+
return sendMessage(getMessageText());
|
82 |
+
});
|
83 |
+
$('.message_input').keyup(function (e) {
|
84 |
+
if (e.which === 13) {
|
85 |
+
return sendMessage(getMessageText());
|
86 |
+
}
|
87 |
+
});
|
88 |
+
|
89 |
+
// Add initial bot message
|
90 |
+
var initialBotMessage = new Message({
|
91 |
+
text: 'How can I help you?',
|
92 |
+
message_side: 'bot'
|
93 |
+
});
|
94 |
+
initialBotMessage.draw();
|
95 |
+
});
|
96 |
+
})();
|
static/styles.css
ADDED
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
body {
|
2 |
+
margin: 0;
|
3 |
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
4 |
+
background-color: #f8f9fa;
|
5 |
+
}
|
6 |
+
|
7 |
+
.container {
|
8 |
+
background-color: #ff0000;
|
9 |
+
padding: 10px;
|
10 |
+
text-align: center;
|
11 |
+
color: white;
|
12 |
+
}
|
13 |
+
|
14 |
+
|
15 |
+
.chat_window {
|
16 |
+
position: absolute;
|
17 |
+
width: 80%;
|
18 |
+
max-width: 800px;
|
19 |
+
border-radius: 10px;
|
20 |
+
background-color: #fff;
|
21 |
+
left: 50%;
|
22 |
+
top: 50%;
|
23 |
+
transform: translateX(-50%) translateY(-50%);
|
24 |
+
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
|
25 |
+
margin-top: 20px;
|
26 |
+
}
|
27 |
+
|
28 |
+
.top_menu {
|
29 |
+
background-color: #007bff;
|
30 |
+
width: 100%;
|
31 |
+
padding: 15px;
|
32 |
+
box-shadow: 0 1px 30px rgba(0, 0, 0, 0.1);
|
33 |
+
}
|
34 |
+
|
35 |
+
.top_menu .title {
|
36 |
+
text-align: center;
|
37 |
+
color: white;
|
38 |
+
font-size: 24px;
|
39 |
+
margin: 0;
|
40 |
+
}
|
41 |
+
|
42 |
+
.messages {
|
43 |
+
list-style: none;
|
44 |
+
padding: 20px 10px 0 10px;
|
45 |
+
margin: 0;
|
46 |
+
height: 347px;
|
47 |
+
overflow-y: scroll;
|
48 |
+
}
|
49 |
+
|
50 |
+
.messages::-webkit-scrollbar {
|
51 |
+
width: 8px;
|
52 |
+
}
|
53 |
+
|
54 |
+
.messages::-webkit-scrollbar-thumb {
|
55 |
+
background-color: #007bff;
|
56 |
+
border-radius: 10px;
|
57 |
+
}
|
58 |
+
|
59 |
+
.bottom_wrapper {
|
60 |
+
width: 100%;
|
61 |
+
background-color: #f8f9fa;
|
62 |
+
padding: 20px 20px;
|
63 |
+
display: flex;
|
64 |
+
flex-direction: column;
|
65 |
+
align-items: stretch;
|
66 |
+
}
|
67 |
+
|
68 |
+
.message_input_wrapper {
|
69 |
+
display: inline-block;
|
70 |
+
height: 50px;
|
71 |
+
border-radius: 25px;
|
72 |
+
border: 1px solid #bcbdc0;
|
73 |
+
width: calc(100% - 20px);
|
74 |
+
position: relative;
|
75 |
+
padding: 0 20px;
|
76 |
+
margin-bottom: 10px;
|
77 |
+
}
|
78 |
+
.send_message {
|
79 |
+
width: 100%;
|
80 |
+
height: 50px;
|
81 |
+
border-radius: 50px;
|
82 |
+
background-color: #007bff;
|
83 |
+
border: 2px solid #007bff;
|
84 |
+
color: #fff;
|
85 |
+
cursor: pointer;
|
86 |
+
transition: all 0.2s linear;
|
87 |
+
text-align: center;
|
88 |
+
margin-bottom: 10px;
|
89 |
+
}
|
90 |
+
|
91 |
+
|
92 |
+
.message_input {
|
93 |
+
border: none;
|
94 |
+
height: 100%;
|
95 |
+
box-sizing: border-box;
|
96 |
+
width: calc(100% - 40px);
|
97 |
+
position: absolute;
|
98 |
+
outline-width: 0;
|
99 |
+
color: gray;
|
100 |
+
}
|
101 |
+
|
102 |
+
|
103 |
+
.send_message:hover {
|
104 |
+
color: #007bff;
|
105 |
+
background-color: #fff;
|
106 |
+
}
|
107 |
+
|
108 |
+
.send_message .text {
|
109 |
+
font-size: 18px;
|
110 |
+
font-weight: 300;
|
111 |
+
display: inline-block;
|
112 |
+
line-height: 48px;
|
113 |
+
}
|
114 |
+
|
115 |
+
|
116 |
+
.message_template {
|
117 |
+
text-align: center;
|
118 |
+
}
|
119 |
+
|
120 |
+
|
121 |
+
.text_wrapper {
|
122 |
+
display: inline-block;
|
123 |
+
text-align: left;
|
124 |
+
}
|
125 |
+
|
126 |
+
.user-message {
|
127 |
+
background-color: #007bff;
|
128 |
+
color: #fff;
|
129 |
+
border-radius: 5px;
|
130 |
+
padding: 10px;
|
131 |
+
margin-bottom: 10px;
|
132 |
+
text-align: left;
|
133 |
+
float: right;
|
134 |
+
clear: both;
|
135 |
+
}
|
136 |
+
|
137 |
+
.bot-message {
|
138 |
+
background-color: #28a745;
|
139 |
+
color: #fff;
|
140 |
+
border-radius: 5px;
|
141 |
+
padding: 10px;
|
142 |
+
margin-bottom: 10px;
|
143 |
+
text-align: left;
|
144 |
+
float: left;
|
145 |
+
clear: both;
|
146 |
+
}
|
147 |
+
|
148 |
+
.upload_wrapper {
|
149 |
+
display: flex;
|
150 |
+
justify-content: space-between;
|
151 |
+
width: 100%;
|
152 |
+
margin-top: 10px;
|
153 |
+
}
|
154 |
+
|
155 |
+
#fileUpload {
|
156 |
+
width: calc(50% - 10px);
|
157 |
+
margin-right: 20px;
|
158 |
+
}
|
159 |
+
|
160 |
+
#uploadBtn {
|
161 |
+
width: calc(50% - 10px);
|
162 |
+
height: 50px;
|
163 |
+
border-radius: 50px;
|
164 |
+
background-color: #007bff;
|
165 |
+
border: 2px solid #007bff;
|
166 |
+
color: #fff;
|
167 |
+
cursor: pointer;
|
168 |
+
transition: all 0.2s linear;
|
169 |
+
text-align: center;
|
170 |
+
}
|
171 |
+
|
172 |
+
|
templates/index.html
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
|
7 |
+
<link rel="stylesheet" href="static/styles.css"> <!-- Link to the new CSS file -->
|
8 |
+
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
|
9 |
+
</head>
|
10 |
+
<body>
|
11 |
+
<div class="container">
|
12 |
+
<h1>Welcome to the chat world</h1>
|
13 |
+
</div>
|
14 |
+
|
15 |
+
<div class="chat_window">
|
16 |
+
<div class="top_menu">
|
17 |
+
<div class="title">Chat With Your Document</div>
|
18 |
+
</div>
|
19 |
+
<ul class="messages"></ul>
|
20 |
+
|
21 |
+
<div class="bottom_wrapper clearfix">
|
22 |
+
<div class="message_input_wrapper">
|
23 |
+
<input class="message_input" placeholder="Type your message here..." />
|
24 |
+
</div>
|
25 |
+
<div class="send_message">
|
26 |
+
<div class="icon"></div>
|
27 |
+
<div class="text">Send</div>
|
28 |
+
</div>
|
29 |
+
<form id="uploadForm" enctype="multipart/form-data" class="upload_wrapper">
|
30 |
+
<input type="file" name="file" id="fileInput" accept=".jpg">
|
31 |
+
<button type="submit">Upload</button>
|
32 |
+
</form>
|
33 |
+
<div id="uploadStatus"></div>
|
34 |
+
</div>
|
35 |
+
</div>
|
36 |
+
<div class="message_template">
|
37 |
+
|
38 |
+
<div class="text_wrapper">
|
39 |
+
<div class="text"></div>
|
40 |
+
</div>
|
41 |
+
|
42 |
+
</div>
|
43 |
+
|
44 |
+
<script src="static/script.js"></script>
|
45 |
+
</body>
|
46 |
+
</html>
|