File size: 12,711 Bytes
ca5d3dd
 
865160b
 
 
 
 
3fde113
 
a17e48f
783df49
865160b
a17e48f
 
 
 
865160b
a17e48f
783df49
9aab6a2
865160b
 
 
 
 
9aab6a2
 
 
 
 
865160b
9aab6a2
865160b
4083e28
9aab6a2
393770d
865160b
 
9aab6a2
865160b
393770d
918e81f
 
 
e0ab7f1
865160b
 
 
 
 
 
3daae96
9261560
865160b
a17e48f
9261560
865160b
 
 
918e81f
865160b
 
 
 
 
 
 
a17e48f
865160b
9261560
865160b
9261560
865160b
 
a17e48f
 
 
9261560
a17e48f
 
865160b
3fde113
 
a17e48f
 
865160b
a17e48f
3fde113
 
865160b
 
 
 
 
 
cf19404
 
 
865160b
 
 
 
 
cf19404
865160b
 
918e81f
865160b
 
 
 
 
 
 
 
 
 
 
918e81f
865160b
 
 
 
 
 
 
 
 
 
 
 
918e81f
865160b
 
918e81f
ed4a174
7168ed6
 
ed4a174
 
865160b
 
918e81f
0cece18
865160b
918e81f
9aab6a2
865160b
9aab6a2
918e81f
9aab6a2
 
 
 
 
76e8490
918e81f
865160b
 
 
 
 
 
 
 
 
 
 
4083e28
a17e48f
 
4083e28
 
 
865160b
4083e28
918e81f
 
f87fc7c
7168ed6
 
f293b15
 
4083e28
f87fc7c
4083e28
3bf57af
9aab6a2
4083e28
9aab6a2
4083e28
 
865160b
 
4083e28
de3ab4f
865160b
 
9aab6a2
b6be7ba
de3ab4f
 
7168ed6
de3ab4f
 
93495fe
de3ab4f
3fde113
9aab6a2
865160b
9aab6a2
865160b
 
 
 
 
 
 
 
 
9aab6a2
865160b
 
 
9aab6a2
 
865160b
 
 
 
 
f87fc7c
4083e28
 
865160b
4083e28
 
 
 
 
 
 
 
f41a82a
a17e48f
865160b
33a475f
 
865160b
f41a82a
3fde113
865160b
 
 
 
 
bf69658
a17e48f
bc333a8
5101b3b
 
 
 
 
 
 
 
53c7bc2
 
 
 
 
 
 
 
a17e48f
 
bf69658
5101b3b
865160b
 
 
 
 
a17e48f
 
 
 
f41a82a
 
865160b
f41a82a
865160b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
# app.py

"""
=========================================================
 1) IMPORTS & DEPENDENCIES
=========================================================
"""
import gradio as gr
import torch
import theme
theme = theme.Theme()

from huggingface_hub import from_pretrained_keras
from tensorflow.keras.applications import EfficientNetB0
import tensorflow as tf
from tensorflow import keras

from PIL import Image
import shutil

import tenacity  # for retrying failed requests
from fake_useragent import UserAgent

# LangChain
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.prompts import PromptTemplate
from langchain.schema import StrOutputParser
from langchain.schema.runnable import Runnable
from langchain.schema.runnable.config import RunnableConfig
from langchain.chains import RetrievalQA, ConversationalRetrievalChain, LLMChain
from langchain.prompts.chat import ChatPromptTemplate, SystemMessagePromptTemplate
from langchain.prompts import SystemMessagePromptTemplate, HumanMessagePromptTemplate, ChatPromptTemplate, MessagesPlaceholder
from langchain.output_parsers import PydanticOutputParser
from langchain_community.llms import HuggingFaceHub
from langchain_community.document_loaders import WebBaseLoader
from langchain.vectorstores import Chroma
from langchain.memory import ConversationBufferMemory

from pydantic.v1 import BaseModel, Field

# Import the separate file that contains our list of URLs
from url_list import URLS


"""
=========================================================
 2) IMAGE CLASSIFICATION MODEL SETUP
=========================================================
"""
# Load a Keras model from HuggingFace Hub
model1 = from_pretrained_keras("rocioadlc/efficientnetB0_trash")

# Define class labels for the trash classification
class_labels = ['cardboard', 'glass', 'metal', 'paper', 'plastic', 'trash']

def predict_image(input_image):
    """
    Resize the user-uploaded image and preprocess it so that it can be fed
    into the EfficientNetB0 model. The model then returns a dictionary of
    class probabilities.
    """
    # Resize the image (note the target dimensions)
    image_array = tf.keras.preprocessing.image.img_to_array(
        input_image.resize((244, 224))
    )
    # Normalize/prescale the image for EfficientNet
    image_array = tf.keras.applications.efficientnet.preprocess_input(image_array)
    # Expand the dimensions to create a batch of size 1
    image_array = tf.expand_dims(image_array, 0)
    # Get predictions
    predictions = model1.predict(image_array)
    
    # Convert predictions into a dictionary {class_label: score}
    category_scores = {}
    for i, class_label in enumerate(class_labels):
        category_scores[class_label] = predictions[0][i].item()
    
    return category_scores

# Gradio interface for image classification
image_gradio_app = gr.Interface(
    fn=predict_image,
    inputs=gr.Image(label="Image", sources=['upload', 'webcam'], type="pil"),
    outputs=[gr.Label(label="Result")],
    title="<span style='color: rgb(243, 239, 224);'>Green Greta</span>",
    theme=theme
)

"""
=========================================================
 3) CHATBOT MODEL SETUP
=========================================================
"""
# 3.1) Define user agent to avoid blocking, etc.
user_agent = UserAgent().random
header_template = {"User-Agent": user_agent}


@tenacity.retry(
    wait=tenacity.wait_fixed(3),   # wait 3 seconds between retries
    stop=tenacity.stop_after_attempt(3),  # stop after 3 attempts
    reraise=True
)
def load_url(url):
    """
    Use the WebBaseLoader for a single URL.
    The function is retried if it fails due to connection issues.
    """
    loader = WebBaseLoader(
        web_paths=[url],
        header_template=header_template
    )
    return loader.load()


def safe_load_all_urls(urls):
    """
    Safely load documents from a list of URLs.
    Any URL that fails after the specified number of retries is skipped.
    """
    all_docs = []
    for link in urls:
        try:
            docs = load_url(link)
            all_docs.extend(docs)
        except Exception as e:
            # If load_url fails after all retries, skip that URL
            print(f"Skipping URL due to error: {link}\nError: {e}\n")
    return all_docs

# 3.2) Actually load the data from all URLs (imported from url_list.py)
all_loaded_docs = safe_load_all_urls(URLS)

# 3.3) Split the documents into manageable chunks
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1024,
    chunk_overlap=150,
    length_function=len
)
docs = text_splitter.split_documents(all_loaded_docs)

# 3.4) Create embeddings
embeddings = HuggingFaceEmbeddings(model_name='thenlper/gte-small')

# 3.5) Create a persistent directory to store vector DB
persist_directory = 'docs/chroma/'
shutil.rmtree(persist_directory, ignore_errors=True)  # remove old DB files

# 3.6) Build Chroma vector store
vectordb = Chroma.from_documents(
    documents=docs,
    embedding=embeddings,
    persist_directory=persist_directory
)

# 3.7) Create a retriever
retriever = vectordb.as_retriever(
    search_kwargs={"k": 2},
    search_type="mmr"
)

"""
=========================================================
 4) PROMPT & CHAIN SETUP
=========================================================
"""
# 4.1) Define the schema for final chatbot answers
class FinalAnswer(BaseModel):
    question: str = Field()
    answer: str = Field()

parser = PydanticOutputParser(pydantic_object=FinalAnswer)

# 4.2) Prompt template: system instructions
template = """
Your name is Greta and you are a recycling chatbot with the objective to answer questions from user in English or Spanish /
Has sido diseñado y creado por el Grupo 1 del Máster en Data Science & Big Data de la promoción 2023/2024 de la Universidad Complutense de Madrid. Este grupo está formado por Rocío, María Guillermo, Alejandra, Paloma y Álvaro /
Use the following pieces of context to answer the question /
If the question is English answer in English /
If the question is Spanish answer in Spanish /
Do not mention the word context when you answer a question /
Answer the question fully and provide as much relevant detail as possible. Do not cut your response short /
Context: {context}
User: {question}
{format_instructions}
"""

sys_prompt = SystemMessagePromptTemplate.from_template(template)
qa_prompt = ChatPromptTemplate(
    messages=[
        sys_prompt,
        HumanMessagePromptTemplate.from_template("{question}")
    ],
    partial_variables={"format_instructions": parser.get_format_instructions()}
)

# 4.3) Define the LLM from HuggingFace
llm = HuggingFaceHub(
    repo_id="mistralai/Mixtral-8x7B-Instruct-v0.1",
    task="text-generation",
    model_kwargs={
        "max_new_tokens": 2000,
        "top_k": 30,
        "temperature": 0.1,
        "repetition_penalty": 1.03
    },
)

# 4.4) Create a ConversationalRetrievalChain that uses the above LLM
qa_chain = ConversationalRetrievalChain.from_llm(
    llm=llm,
    memory=ConversationBufferMemory(
        llm=llm,
        memory_key="chat_history",
        input_key='question',
        output_key='output'
    ),
    retriever=retriever,
    verbose=True,
    combine_docs_chain_kwargs={'prompt': qa_prompt},
    get_chat_history=lambda h : h,  # pass memory directly
    rephrase_question=False,
    output_key='output'
)

def chat_interface(question, history):
    """
    This function processes the user's question through the qa_chain,
    then parses out the final answer from the chain's output.
    """
    result = qa_chain.invoke({'question': question})
    output_string = result['output']

    # Find the index of the last occurrence of '"answer":' in the string
    answer_index = output_string.rfind('"answer":')
    answer_part = output_string[answer_index + len('"answer":'):].strip()

    # Find the next occurrence of a double quote to get the start of the answer value
    quote_index = answer_part.find('"')
    answer_value = answer_part[quote_index + 1:answer_part.find('"', quote_index + 1)]
    
    return answer_value


# Gradio chat interface for the chatbot
chatbot_gradio_app = gr.ChatInterface(
    fn=chat_interface,
    title="<span style='color: rgb(243, 239, 224);'>Green Greta</span>"
)

"""
=========================================================
 5) BANNER / WELCOME TAB
=========================================================
"""
banner_tab_content = """
<div style="background-color: #d3e3c3; text-align: center; padding: 20px; display: flex; flex-direction: column; align-items: center;">
    <img src="https://huggingface.co/spaces/ALVHB95/TFM_DataScience_APP/resolve/main/front_4.jpg" alt="Banner Image" style="width: 50%; max-width: 500px; margin: 0 auto;">
    <h1 style="font-size: 24px; color: #4e6339; margin-top: 20px;">¡Bienvenido a nuestro clasificador de imágenes y chatbot para un reciclaje más inteligente!♻️</h1>
    <p style="font-size: 16px; color: #4e6339; text-align: justify;">¿Alguna vez te has preguntado si puedes reciclar un objeto en particular? ¿O te has sentido abrumado por la cantidad de residuos que generas y no sabes cómo manejarlos de manera más sostenible? ¡Estás en el lugar correcto!</p>
    <p style="font-size: 16px; color: #4e6339; text-align: justify;">Nuestra plataforma combina la potencia de la inteligencia artificial con la comodidad de un chatbot para brindarte respuestas rápidas y precisas sobre qué objetos son reciclables y cómo hacerlo de la manera más eficiente.</p>
    <p style="font-size: 16px; text-align:center;"><strong><span style="color: #4e6339;">¿Cómo usarlo?</span></strong></p>
    <ul style="list-style-type: disc; text-align: justify; margin-top: 20px; padding-left: 20px;">
        <li style="font-size: 16px; color: #4e6339;"><strong><span style="color: #4e6339;">Green Greta Image Classification:</span></strong> Ve a la pestaña Greta Image Classification y simplemente carga una foto del objeto que quieras reciclar, y nuestro modelo de identificará de qué se trata🕵️‍♂️ para que puedas desecharlo adecuadamente.</li>
        <li style="font-size: 16px; color: #4e6339;"><strong><span style="color: #4e6339;">Green Greta Chat:</span></strong> ¿Tienes preguntas sobre reciclaje, materiales específicos o prácticas sostenibles? ¡Pregunta a nuestro chatbot en la pestaña Green Greta Chat!📝 Está aquí para responder todas tus preguntas y ayudarte a tomar decisiones más informadas sobre tu reciclaje.</li>
    </ul>
    <h1 style="font-size: 24px; color: #4e6339; margin-top: 20px;">Welcome to our image classifier and chatbot for smarter recycling!♻️</h1>
    <p style="font-size: 16px; color: #4e6339; text-align: justify;">Have you ever wondered if you can recycle a particular object? Or felt overwhelmed by the amount of waste you generate and don't know how to handle it more sustainably? You're in the right place!</p>
    <p style="font-size: 16px; color: #4e6339; text-align: justify;">Our platform combines the power of artificial intelligence with the convenience of a chatbot to provide you with quick and accurate answers about which objects are recyclable and how to do it most efficiently.</p>
    <p style="font-size: 16px; text-align:center;"><strong><span style="color: #4e6339;">How to use it?</span></strong>
    <ul style="list-style-type: disc; text-align: justify; margin-top: 20px; padding-left: 20px;">
        <li style="font-size: 16px; color: #4e6339;"><strong><span style="color: #4e6339;">Green Greta Image Classification:</span></strong> Go to the Greta Image Classification tab and simply upload a photo of the object you want to recycle, and our model will identify what it is🕵️‍♂️ so you can dispose of it properly.</li>
        <li style="font-size: 16px; color: #4e6339;"><strong><span style="color: #4e6339;">Green Greta Chat:</span></strong> Have questions about recycling, specific materials, or sustainable practices? Ask our chatbot in the Green Greta Chat tab!📝 It's here to answer all your questions and help you make more informed decisions about your recycling.</li>
    </ul>
</div>
"""
banner_tab = gr.Markdown(banner_tab_content)

"""
=========================================================
 6) GRADIO FINAL APP: TABS
=========================================================
"""
app = gr.TabbedInterface(
    [banner_tab, image_gradio_app, chatbot_gradio_app],
    tab_names=["Welcome to Green Greta", "Green Greta Image Classification", "Green Greta Chat"],
    theme=theme
)

# Enable queue() for concurrency and launch the Gradio app
app.queue()
app.launch()