File size: 12,914 Bytes
038ca43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bab571f
2c38b79
038ca43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bab571f
038ca43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e17007c
038ca43
 
 
 
e17007c
038ca43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78741dc
038ca43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# Install all of it
#!pip install python-dotenv
#!pip install -q -U google-generativeai
#!pip install -U langchain-community
#!pip install faiss-cpu
#!pip install langchain_google_genai
#!pip install gradio
# import all library, framework and load all model we need
from joblib import load
import gradio as gr
import re
import nltk
from nltk.tokenize.toktok import ToktokTokenizer
from nltk.stem import LancasterStemmer
from nltk.corpus import stopwords
from transformers import pipeline, AutoTokenizer, AutoModelForSeq2SeqLM
import torch
import torch.nn as nn
import cv2
import numpy as np
from torchvision import models,transforms
import pickle
import os
from dotenv import load_dotenv
import google.generativeai as genai
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_google_genai import GoogleGenerativeAIEmbeddings,ChatGoogleGenerativeAI
from langchain_community.vectorstores import FAISS
from langchain.chains import RetrievalQA
from langchain_google_genai import GoogleGenerativeAI
from langchain.chains import ConversationChain
from langchain.schema import HumanMessage, AIMessage
from langchain.memory import ConversationBufferMemory
nltk.download('stopwords')
# load all model and API
device = 0 if torch.cuda.is_available() else -1 # check if GPU available using GPU
translator_eng_id = pipeline('translation', model='Helsinki-NLP/opus-mt-en-id', device = device)# eng-indo
translator_id_eng = pipeline('translation', model='Helsinki-NLP/opus-mt-id-en', device = device)# indo-eng
summarizer = pipeline('summarization', model='facebook/bart-large-cnn', device = device) # summarize the news
ner = pipeline('ner',tokenizer = 'dbmdz/bert-large-cased-finetuned-conll03-english', model='dbmdz/bert-large-cased-finetuned-conll03-english', device = device) # Analyze NER on news
lang_detector = pipeline('text-classification', model = 'papluca/xlm-roberta-base-language-detection', device = device) #detect language
news_encoder = load('news_encoder.pkl') #encoder for the news (3 class)
news_classifier = load("news_classifier.pkl") #classify news into 3 category (Politic, Technology, Science)
emotion_text_encoder = load("emotion_encoder.pkl") # Encoder for Emotion detection(text version)
emotion_classifier = load("emotion_model_classifier.pkl") #Detect emotion user based on their comment about news
with open('class_names_face_recognition.pkl', 'rb') as f: # import and using it as encoder for emotion detection(image version)
    emotion_face_class = pickle.load(f)
face_emotion = models.resnet18(pretrained=False) # Detect user emotion based on their expression (selfie)
face_emotion.fc = nn.Linear(face_emotion.fc.in_features, 5)
#face_emotion = face_emotion.load_state_dict(torch.load('Best_emotion_face_model.pth'),map_location=torch.device('cpu'))
device = torch.device("cuda" if torch.cuda.is_available() else 'cpu') # move into GPU if available, so model will using GPU
state_dict = torch.load('Best_emotion_face_model.pth', map_location=device)
face_emotion.load_state_dict(state_dict)
face_emotion.to(device)
face_emotion.eval()
# using API Gemini for chatbot
GOOGLE_API_KEY = os.getenv("GEMINI_API_KEY")
genai.configure(api_key=GOOGLE_API_KEY)

# Support Function
#detect language
def detect_language(text):
  result = lang_detector(text)
  return result[0]['label']
#translate to english if user language not english
def translate_to_english(text,source_lang):
  if source_lang.lower() == 'indonesia':
    return translator_id_eng(text)[0]['translation_text']
  else:
    return text
def translate_to_original(text,target_lang):
  if target_lang.lower() == 'indonesia':
    return translator_eng_id(text)[0]['translation_text']
  else:
    return text
# upload reaction
def process_image_reaction(image_path):
  image = cv2.imread(image_path)
  image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
  image = image.astype(np.float32)/255.0
  image = np.transpose(image, (2,0,1))
  image = torch.tensor(image).unsqueeze(0).to(device)
  #predict
  with torch.no_grad():
    outputs = face_emotion(image)
    _,predicted = torch.max(outputs,1)
  return emotion_face_class[predicted.item()]
#make template  for cleaning
def cleaning_text(text, is_lower_case = False):
  text = text.lower()
  pattern = r'[^a-zA-z0-9\s]'
  text = re.sub(pattern,'',text)
  tokenizer = ToktokTokenizer()
  stopword = stopwords.words('english')
  tokens = tokenizer.tokenize(text)
  tokens = [token.strip() for token in tokens]
  if is_lower_case:
    filtered_tokens = [token for token in tokens if token not in stopword]
  else:
    filtered_tokens = [token for token in tokens if token.lower() not in stopword]
  filtered_text =' '.join(filtered_tokens)
  st = LancasterStemmer()
  text = ' '.join([st.stem(word) for word in filtered_text.split()])
  return text

#Step 1 to classify, summary and get NER from news
def extract_article(url):
   model = genai.GenerativeModel('gemini-1.5-flash')
   extract = model.generate_content(f"Extract the content from this news article: {url}, make sure extract all news part. Extract based on the news language used, if the news using Indonesia language just extract with Indonesian language, and so on if the news using english language. Make sure minimum is 200 words and maximum is 250 words").text
   return extract
def process_news_pipeline(news_text, user_language):
    news_text = extract_article(news_text)
    #detect the  language
    detected_lang = detect_language(news_text)
#translate news if not in english
    if detected_lang.lower() != 'english':
        news_text = translate_to_english(news_text,detected_lang)
    #analyze the news
    #classify the news category
    summary = summarizer(news_text, min_length = 25, do_sample = False)[0]['summary_text']
    clean_text = cleaning_text(summary)
    classification = news_classifier.predict([clean_text])[0]
    classification = news_encoder.inverse_transform([classification])[0]
    ner_result = ner(news_text)
    ner_filter = [{"entity":result['entity'],'word':result['word']} for result in ner_result]
    ner_filter = ner_filter[:5]
    #translate result into original language if not english
    if user_language.lower() != 'english':
        classification = translate_to_original(classification, user_language)
        summary = translate_to_original(summary, user_language)
    return classification, summary, ner_filter
def bring_together_all_of_it(news_text, user_language):
    news_text = extract_article(news_text)
    classification, summary, ner_results = process_news_pipeline(news_text,user_language)
    ner_results = "\n".join([f"Entity: {item['entity']}, Word: {item['word']}" for item in ner_results])
    return classification, summary, ner_results, news_text

#Step 2 for predict user emotion based on text or image
def process_user_response(response_type, response_content, user_language):
    if response_type == "Text" and response_content:
      sentiment = emotion_text_encoder.inverse_transform([emotion_classifier.predict([response_content])[0]])[0] #predict output using sentiment analysis model
      if user_language != 'English':
        translate = translate_to_english(response_content,user_language)
        sentiment = emotion_text_encoder.inverse_transform([emotion_classifier.predict([translate])[0]])[0] #predict output using sentiment analysis model
        sentiment = translate_to_original(sentiment,user_language)
    elif response_type == "Selfie" and response_content:
      sentiment = process_image_reaction(response_content) # predict output using image classification model
      if user_language != 'English':
        sentiment = translate_to_original(sentiment,user_language)
    else:
      return "Please provide valid input."
    return f"Your Expression: {sentiment}"
 
#Step 3, make chatbot for discussion about the news
#load model and memory, to save context while discuss with chatbot
model = GoogleGenerativeAI(model="gemini-1.5-flash", temperature=0.1)
memory = ConversationBufferMemory()
conversation = ConversationChain(
    llm=model,
    verbose=False,
    memory=memory
)
def chatbot_interaction(user_message, history, news, user_reaction, user_language):
  logo = "https://i.ibb.co.com/rwft0JQ/output-removebg-preview-1.png"
  if history is None:
    history = []
  # first response based on bot response to know the context and save it into history
  if len(history) == 0:
      initial_response = f"Hi genius! wanna discuss something?"
      memory.chat_memory.add_ai_message(initial_response)
      memory.chat_memory.add_user_message(f"Learn and become good presenter based on this news {news}, after that you will discuss with user about this news and make sure using {user_language} language and their ekspression : {user_reaction}")
      history.append([f"👤 {user_message}", f"<img src='{logo}' style='width:30px; height:30px;'> { initial_response}"])
      return history, ""
  memory.chat_memory.add_user_message(user_message)
  gpt_response = conversation.predict(input=user_message)
  memory.chat_memory.add_ai_message(gpt_response)
  history.append([f"👤 {user_message}",f"<img src='{logo}' style='width:30px; height:30px;'> {gpt_response}"] )
  return history, ""

#Building UI from Gradio
#Step 1
with gr.Blocks() as news_analysis_interface:
  news_text = gr.Textbox(label="Put the news link")
  user_language = gr.Radio(choices=["English", "Indonesia"], label="User Language")
  submit_analysis = gr.Button("Analyze News")
  summary_result = gr.Textbox(label="News Classification", elem_id="summary_result_box")
  classification_result = gr.Textbox(label="News Summary")
  ner_result = gr.Textbox(label="Named Entities")
  news_state = gr.Textbox(label="News")
  submit_analysis.click(
      fn=bring_together_all_of_it,
      inputs=[news_text, user_language],
      outputs=[summary_result, classification_result, ner_result, news_state]
  )

#step 2
with gr.Blocks() as reaction_interface:
  response_type = gr.Radio(["Text", "Selfie"], label="Response Type")
  text_input = gr.Textbox(label="Enter Text (only understand english comment)", visible=False)
  image_input = gr.Image(type="filepath", label="Upload Image", visible=False)
  reaction_result = gr.Textbox(label="Detected Reaction", interactive=False)
  def update_visibility(selected_response):
      if selected_response == "Text":
          return gr.update(visible=True), gr.update(visible=False)
      elif selected_response == "Selfie":
          return gr.update(visible=False), gr.update(visible=True)
      else:
          return gr.update(visible=False), gr.update(visible=False)
  response_type.change(
      fn=update_visibility,
      inputs=response_type,
      outputs=[text_input, image_input]
  )
  submit_button = gr.Button("Submit Reaction")
  def submit_click(response_type_value, text_value, image_value,language_value):
    if response_type_value == "Text" and text_value:
      processed_reaction = process_user_response(response_type_value, text_value,language_value)
      return processed_reaction
    elif response_type_value == "Selfie" and image_value:
      processed_reaction = process_user_response(response_type_value, image_value,language_value)
      return processed_reaction
    else:
      return "Please provide valid input."
  submit_button.click(
      fn = submit_click,
      inputs=[response_type, text_input, image_input, user_language],
      outputs=[reaction_result]
  )

#step 3
with gr.Blocks() as chatbot_interface:
  chatbot_chatbox = gr.Chatbot(label="Chatbot Interaction")
  chatbot_input = gr.Textbox(label="Your Message", placeholder="Type your message here...")
  chatbot_submit_button = gr.Button("Send")
  chatbot_history = gr.State(value=[])
  chatbot_submit_button.click(
      fn=chatbot_interaction,
      inputs=[chatbot_input,chatbot_history,news_state,reaction_result,user_language],
      outputs=[chatbot_chatbox,chatbot_input]
  )
  chatbot_input.submit(fn=chatbot_interaction,
                        inputs=[chatbot_input,chatbot_history,news_state,reaction_result,user_language],
      outputs=[chatbot_chatbox,chatbot_input]
  )
##
#Bring it all and launch
with gr.Blocks(theme=gr.themes.Default(primary_hue='gray', secondary_hue='zinc')) as full_app:
  with gr.Column():
    # Membuat gambar terpusat di atas
    gr.HTML("""
      <div style="text-align: center;">
          <img src="https://i.ibb.co.com/rwft0JQ/output-removebg-preview-1.png" alt="Robot Logo" style="width:150px; display: block; margin: 0 auto;">
      </div>
      """)
    # Menambahkan judul
    gr.Markdown("<h1 style='text-align: center;'>Your Discussion Friend</h1>")
  #gr.Markdown("# Your Discussion Friend")
  gr.Markdown("**Step 1**: Analyze the News")
  news_analysis_interface.render()
  gr.Markdown("**Step 2**: Choose Your Reaction")
  reaction_interface.render()
  gr.Markdown("**Step 3**: Interact with Chatbot")
  chatbot_interface.render()
full_app.launch()