Spaces:
Sleeping
Sleeping
Upload 5 files
Browse files- LICENSE +21 -0
- README.md +30 -13
- main.py +71 -0
- model/model.py +52 -0
- requirements.txt +5 -0
LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
MIT License
|
2 |
+
|
3 |
+
Copyright (c) 2023 Gabriel
|
4 |
+
|
5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6 |
+
of this software and associated documentation files (the "Software"), to deal
|
7 |
+
in the Software without restriction, including without limitation the rights
|
8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9 |
+
copies of the Software, and to permit persons to whom the Software is
|
10 |
+
furnished to do so, subject to the following conditions:
|
11 |
+
|
12 |
+
The above copyright notice and this permission notice shall be included in all
|
13 |
+
copies or substantial portions of the Software.
|
14 |
+
|
15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21 |
+
SOFTWARE.
|
README.md
CHANGED
@@ -1,13 +1,30 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# My Own Chatbot
|
2 |
+
- My Own Chatbot with an interface implemented without APIs using a pre-trained model.
|
3 |
+
|
4 |
+
# Why
|
5 |
+
- Just to see if it was possible. (and to see if I could)
|
6 |
+
|
7 |
+
# Model Information
|
8 |
+
- The template I'm using is [distilbert-base-uncased-distilled-squad](https://huggingface.co/distilbert-base-uncased-distilled-squad) by [huggingface](https://huggingface.co/) team.<br>
|
9 |
+
- This model has: `66.4M parameters.`
|
10 |
+
- The reason i chose this model is because i like huggingface models and because this model is a base model and very light. it can be trained and has good documentation and performance.
|
11 |
+
- The license of this model is: `Apache 2.0`
|
12 |
+
- The Language(s): English
|
13 |
+
- The Model Type: Transformer-based language model.
|
14 |
+
- The Token Limit: `512 tokens` for this model.
|
15 |
+
# Credits
|
16 |
+
- huggingface: by model and transformers library
|
17 |
+
- gradio: by the gradio library making it easy to create UI for machine learning models easily.
|
18 |
+
- pytorch: very fast and lightweight tensor framework.
|
19 |
+
- loguru: quick and easy log library.
|
20 |
+
- [how-to-generate#greedy-search](https://huggingface.co/blog/how-to-generate#greedy-search) a very detailed guide on huggingface's website: How to generate text: using different decoding methods for language generation with Transformers
|
21 |
+
- [gpt2#openai-gpt2](https://huggingface.co/docs/transformers/model_doc/gpt2#openai-gpt2) gpt2 documentation made by huggingface team
|
22 |
+
|
23 |
+
# Not Implemented
|
24 |
+
- Context manager: as the token limit is low (`512 tokens`), for this project to become usable for small things, it would be necessary to implement a system to avoid overflowing too many tokens into the model.
|
25 |
+
|
26 |
+
# Demonstration
|
27 |
+
[screen-capture.webm](https://github.com/0x41337/my-own-chatbot/assets/88632118/48b97fa1-fbae-493d-8311-f6c381e13c23)
|
28 |
+
|
29 |
+
# License
|
30 |
+
- this project is under the MIT license resources used may be under other licenses.
|
main.py
ADDED
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# gradio is a UI library for machine learning models
|
2 |
+
import gradio as gr
|
3 |
+
|
4 |
+
# loguru is a library for logging
|
5 |
+
from loguru import logger
|
6 |
+
|
7 |
+
# generative pre-trained transformer model
|
8 |
+
from model.model import Model
|
9 |
+
|
10 |
+
# load model
|
11 |
+
model = Model()
|
12 |
+
|
13 |
+
# These functions are responsible for defining the chatbot's behavior
|
14 |
+
# when the user interacts with the interface. The respond function
|
15 |
+
# receives a question and a conversation history. It defines the
|
16 |
+
# question in the model (model.question) and calls the
|
17 |
+
# question_answerer method to get the answer. The response
|
18 |
+
# is added to the history and returned as a result.
|
19 |
+
def respond(question, history):
|
20 |
+
model.question = question
|
21 |
+
history.append((question, model.question_answerer()))
|
22 |
+
return "", history
|
23 |
+
|
24 |
+
# The set_context function takes a context and sets that context in
|
25 |
+
# the model (model.context).
|
26 |
+
def set_context(context):
|
27 |
+
model.context = context
|
28 |
+
|
29 |
+
|
30 |
+
# In this part, the Gradio interface is created.
|
31 |
+
# the interface has two tabs: "Chat" and "Context".
|
32 |
+
with gr.Blocks() as interface:
|
33 |
+
# In the "Chat" tab, there is a Chatbot component which is
|
34 |
+
# used to display the chatbot conversation. There is also
|
35 |
+
# a Textbox component called prompt_gradio_component
|
36 |
+
# used to receive the question from the user. The
|
37 |
+
# generate_gradio_component button is responsible
|
38 |
+
# for calling the respond function when clicked.
|
39 |
+
# The clear_gradio_component button is used to
|
40 |
+
# clear input fields and conversation.
|
41 |
+
with gr.Tab("Chat"):
|
42 |
+
chatbot_gradio_component = gr.Chatbot(label="My Own Chatbot")
|
43 |
+
|
44 |
+
prompt_gradio_component = gr.Textbox(label="Prompt", lines=2)
|
45 |
+
generate_gradio_component = gr.Button("Generate")
|
46 |
+
clear_gradio_component = gr.ClearButton([prompt_gradio_component, chatbot_gradio_component])
|
47 |
+
|
48 |
+
generate_gradio_component.click(respond, [prompt_gradio_component, chatbot_gradio_component], [prompt_gradio_component, chatbot_gradio_component])
|
49 |
+
|
50 |
+
# In the "Context" tab, there is a Textbox component called
|
51 |
+
# context_gradio_component used to receive the chatbot
|
52 |
+
# context. The set_context_gradio_component button is
|
53 |
+
# responsible for calling the set_context function
|
54 |
+
# when clicked. The clear_gradio_component button
|
55 |
+
# is used to clear the input field.
|
56 |
+
with gr.Tab("Context"):
|
57 |
+
context_gradio_component = gr.Textbox(label="Context", lines=10)
|
58 |
+
set_context_gradio_component = gr.Button("Set")
|
59 |
+
clear_gradio_component = gr.ClearButton([context_gradio_component])
|
60 |
+
|
61 |
+
set_context_gradio_component.click(set_context, [context_gradio_component])
|
62 |
+
|
63 |
+
# In this part, the interface is launched and executed. The launch()
|
64 |
+
# function is called to launch the Gradio interface.
|
65 |
+
# If any errors occur during runtime, they are
|
66 |
+
# caught and logged using the loguru library.
|
67 |
+
if __name__ == "__main__":
|
68 |
+
try:
|
69 |
+
interface.launch()
|
70 |
+
except Exception as error:
|
71 |
+
logger.error(error)
|
model/model.py
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# PyTorch is a library for deep learning and machine learning
|
2 |
+
import torch
|
3 |
+
|
4 |
+
# Huggingface transformer library is State-of-the-art Machine Learning for PyTorch, TensorFlow, and JAX.
|
5 |
+
from transformers import DistilBertTokenizer, DistilBertForQuestionAnswering
|
6 |
+
|
7 |
+
# the model
|
8 |
+
class Model:
|
9 |
+
# The DistilBERT model and tokenizer are loaded with the pre-trained weights
|
10 |
+
# of the "distilbert-base-uncased-distilled-squad" model. The variables
|
11 |
+
# answer, context and question are initialized empty.
|
12 |
+
def __init__(self):
|
13 |
+
self.model = DistilBertForQuestionAnswering.from_pretrained("distilbert-base-uncased-distilled-squad")
|
14 |
+
self.tokenizer = DistilBertTokenizer.from_pretrained("distilbert-base-uncased-distilled-squad")
|
15 |
+
|
16 |
+
self.answer = ""
|
17 |
+
self.context = ""
|
18 |
+
self.question = ""
|
19 |
+
|
20 |
+
# This method receives a question (self.question) and a context (self.context).
|
21 |
+
# It tokenizes the question and context using DistilBERT's tokenizer and
|
22 |
+
# returns the inputs to the model, which are wrapped in the self.inputs
|
23 |
+
# object.
|
24 |
+
|
25 |
+
# Then, the method performs an inference with the DistilBERT model, passing
|
26 |
+
# the inputs to the self.model(**self.inputs) method. The call to
|
27 |
+
# torch.no_grad() indicates that it is not necessary to compute
|
28 |
+
# gradients during this inference, which saves memory resources.
|
29 |
+
|
30 |
+
# After the inference, the start and end indices of the response
|
31 |
+
# within the context are obtained, using torch.argmax to find
|
32 |
+
# the indices with the highest probability. These indexes are
|
33 |
+
# used to extract the corresponding tokens from the predicted
|
34 |
+
# response.
|
35 |
+
|
36 |
+
# Finally, the response tokens are decoded using the tokenizer,
|
37 |
+
# resulting in the final response. The answer is stored in
|
38 |
+
# the self.answer variable and returned by the method.
|
39 |
+
def question_answerer(self):
|
40 |
+
self.inputs = self.tokenizer(self.question, self.context, return_tensors="pt")
|
41 |
+
|
42 |
+
# disable gradient calculations
|
43 |
+
with torch.no_grad():
|
44 |
+
self.outputs = self.model(**self.inputs)
|
45 |
+
|
46 |
+
self.answer_start_index = torch.argmax(self.outputs.start_logits)
|
47 |
+
self.answer_end_index = torch.argmax(self.outputs.end_logits)
|
48 |
+
|
49 |
+
self.predict_answer_tokens = self.inputs.input_ids[0, self.answer_start_index : self.answer_end_index + 1]
|
50 |
+
self.answer = self.tokenizer.decode(self.predict_answer_tokens)
|
51 |
+
return self.answer
|
52 |
+
|
requirements.txt
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
torch>=1.10.1
|
2 |
+
loguru>=0.7.0
|
3 |
+
gradio>=3.35.2
|
4 |
+
torchvision>=0.11.2
|
5 |
+
gradio-client>=0.2.7
|