ProfRod100 commited on
Commit
5135aaf
·
verified ·
1 Parent(s): 00d2e51

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +162 -79
app.py CHANGED
@@ -26,10 +26,7 @@ def train_small_baseline(save_path: str = BASELINE_PATH,
26
  from datasets import load_dataset
27
  import pandas as pd
28
 
29
- # Carrega o split de treino inteiro
30
  ds = load_dataset("amazon_polarity", split="train")
31
-
32
- # Embaralha e pega apenas max_samples exemplos (para ficar leve)
33
  ds_small = ds.shuffle(seed=42).select(range(min(max_samples, len(ds))))
34
 
35
  df = pd.DataFrame(
@@ -90,123 +87,209 @@ def classify_only(text: str):
90
 
91
 
92
  # ======================================================================
93
- # 2. IA Generativa (FLAN-T5) para resposta ao cliente
94
  # ======================================================================
95
 
96
- GEN_MODEL_ID = os.getenv("GEN_MODEL_ID", "google/flan-t5-base")
97
-
98
- generator = hf_pipeline("text2text-generation", model=GEN_MODEL_ID)
 
 
99
 
100
- SYSTEM_PROMPT = (
101
- "Voce e um atendente virtual educado que responde em portugues do Brasil. "
102
- "Use poucas frases, tom empatico e pratico."
 
103
  )
104
 
105
 
106
- def generate_reply(user_text: str, sentimento_json):
107
  """
108
- Gera uma resposta em PT-BR condicionada ao sentimento detectado.
 
109
  """
110
- if not user_text or user_text.strip() == "":
111
- return "Digite uma mensagem."
112
-
113
  sentimento = None
114
  confianca = None
115
-
116
  if isinstance(sentimento_json, dict):
117
- sentimento = sentimento_json.get("sentimento", None)
118
- confianca = sentimento_json.get("confianca", None)
119
 
120
  if sentimento is None:
121
  sentimento = "nao identificado"
122
 
123
- # Prompt estruturado para evitar meta-respostas
124
- prompt = f"""
125
- ### CONTEXTO DO SISTEMA ###
126
- {SYSTEM_PROMPT}
127
- Voce e um atendente virtual profissional e empatico.
128
- Nunca explique instrucoes internas e nunca repita este texto.
 
 
 
 
 
 
 
129
 
130
- ### ORIENTACAO ###
131
- - Responda sempre em PORTUGUES DO BRASIL.
132
- - Use entre 2 e 4 frases.
133
- - Seja empatico em mensagens negativas.
134
- - Seja caloroso em mensagens positivas.
135
- - Seja neutro e cordial se o sentimento nao for claro.
136
 
137
- ### DADOS DA ANALISE ###
138
- Sentimento detectado: {sentimento}
139
- Confianca do classificador: {confianca}
140
 
141
- Mensagem do cliente:
142
- \"\"\"{user_text}\"\"\"
143
 
144
 
145
- ### RESPOSTA FINAL ###
146
- Gere apenas a resposta ao cliente, sem comentarios adicionais.
147
- """
 
 
 
 
 
148
 
149
- out = generator(
150
  prompt,
151
- max_length=128,
152
- do_sample=True,
153
- temperature=0.6,
154
  top_p=0.9,
155
- )[0]["generated_text"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
 
157
- return out
 
 
 
 
 
 
 
 
158
 
159
 
160
  # ======================================================================
161
- # 3. Interface Gradio - duas abas (Analise e Chatbot)
162
  # ======================================================================
163
 
164
- with gr.Blocks(title="Chatbot de Sentimentos - Professor Rodrigo") as demo:
 
 
 
 
 
 
 
 
 
 
 
165
  gr.Markdown(
166
  """
 
 
167
  # Chatbot de Sentimentos (ML + IA Generativa)
168
- **Professor Rodrigo** - Projeto Final ML & DL
169
 
170
- - Classificacao: TF-IDF + Regressao Logistica (baseline).
171
- - Geracao: `google/flan-t5-base` para redigir respostas em PT-BR.
172
 
173
- > Dica: envie `baseline_pipe.pkl` na aba *Files* para usar um modelo treinado por voce.
174
- """
 
 
 
 
 
 
 
175
  )
176
 
177
- # Aba 1 - somente analise de sentimento
178
- with gr.Tab("Analise de Sentimento"):
179
- input_text = gr.Textbox(
180
- label="Digite uma avaliacao de produto",
181
- lines=4,
182
- placeholder="Ex.: O produto chegou rapido e superou minhas expectativas.",
183
- )
184
- output_json = gr.JSON(label="Resultado da classificacao")
185
- btn_analisar = gr.Button("Analisar")
 
 
 
 
 
 
 
 
186
  btn_analisar.click(classify_only, inputs=input_text, outputs=output_json)
187
 
188
- # Aba 2 - Chatbot (analise + resposta generativa)
189
- with gr.Tab("Chatbot (Analise + Resposta)"):
190
- chat_input = gr.Textbox(
191
- label="Mensagem do cliente",
192
- lines=4,
193
- placeholder="Ex.: Estou chateado, o produto chegou quebrado.",
194
- )
195
  with gr.Row():
196
- btn_analise_chat = gr.Button("1) Analisar sentimento")
197
- btn_resposta = gr.Button("2) Gerar resposta")
198
-
199
- chat_analysis = gr.JSON(label="Sentimento detectado")
200
- chat_reply = gr.Textbox(
201
- label="Resposta gerada pela IA",
202
- lines=6,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
  )
204
 
205
- btn_analise_chat.click(
206
- classify_only, inputs=chat_input, outputs=chat_analysis
207
- )
208
- btn_resposta.click(
209
- generate_reply, inputs=[chat_input, chat_analysis], outputs=chat_reply
 
 
210
  )
211
 
212
 
 
26
  from datasets import load_dataset
27
  import pandas as pd
28
 
 
29
  ds = load_dataset("amazon_polarity", split="train")
 
 
30
  ds_small = ds.shuffle(seed=42).select(range(min(max_samples, len(ds))))
31
 
32
  df = pd.DataFrame(
 
87
 
88
 
89
  # ======================================================================
90
+ # 2. IA Generativa (LLaMA 3) para resposta ao cliente
91
  # ======================================================================
92
 
93
+ # Troque por outro modelo se quiser algo mais leve
94
+ GEN_MODEL_ID = os.getenv(
95
+ "GEN_MODEL_ID",
96
+ "meta-llama/Meta-Llama-3-8B-Instruct",
97
+ )
98
 
99
+ generator = hf_pipeline(
100
+ "text-generation",
101
+ model=GEN_MODEL_ID,
102
+ tokenizer=GEN_MODEL_ID,
103
  )
104
 
105
 
106
+ def build_prompt(history, user_text, sentimento_json):
107
  """
108
+ Constroi um prompt amigavel para LLaMA 3, usando historico + sentimento.
109
+ NENHUMA referencia a processo interno aparece na resposta.
110
  """
 
 
 
111
  sentimento = None
112
  confianca = None
 
113
  if isinstance(sentimento_json, dict):
114
+ sentimento = sentimento_json.get("sentimento")
115
+ confianca = sentimento_json.get("confianca")
116
 
117
  if sentimento is None:
118
  sentimento = "nao identificado"
119
 
120
+ # Cabecalho de instrucao (o modelo ve, o cliente nao)
121
+ prompt = (
122
+ "Você é um atendente virtual educado, empático e profissional "
123
+ "de uma loja online. Responda SEMPRE em português do Brasil, "
124
+ "usando entre 2 e 4 frases curtas, claras e naturais.\n\n"
125
+ "Informação de contexto (não revele isso na resposta): "
126
+ f"a última mensagem do cliente foi classificada com sentimento "
127
+ f"'{sentimento}' (confiança {confianca}). "
128
+ "Use isso apenas para ajustar o tom (mais empático se negativo, "
129
+ "mais entusiasmado se positivo), mas não mencione a palavra "
130
+ "'sentimento', 'classificação' ou 'modelo'.\n\n"
131
+ "Histórico da conversa:\n"
132
+ )
133
 
134
+ # Historico anterior
135
+ if history:
136
+ for user, bot in history:
137
+ prompt += f"Cliente: {user}\n"
138
+ prompt += f"Atendente: {bot}\n"
 
139
 
140
+ # Nova mensagem
141
+ prompt += f"Cliente: {user_text}\n"
142
+ prompt += "Atendente:"
143
 
144
+ return prompt
 
145
 
146
 
147
+ def generate_reply_with_history(history, user_text, sentimento_json):
148
+ """
149
+ Gera uma resposta levando em conta historico + sentimento.
150
+ """
151
+ if not user_text or user_text.strip() == "":
152
+ return "Digite uma mensagem."
153
+
154
+ prompt = build_prompt(history, user_text, sentimento_json)
155
 
156
+ outputs = generator(
157
  prompt,
158
+ max_new_tokens=160,
159
+ temperature=0.7,
 
160
  top_p=0.9,
161
+ do_sample=True,
162
+ return_full_text=False,
163
+ )
164
+
165
+ reply = outputs[0]["generated_text"]
166
+ return reply.strip()
167
+
168
+
169
+ # ======================================================================
170
+ # 3. Função de passo do Chatbot (para o Gradio)
171
+ # ======================================================================
172
+
173
+ def chatbot_step(history, user_text):
174
+ """
175
+ - Analisa sentimento da nova mensagem
176
+ - Gera resposta com LLaMA 3
177
+ - Atualiza historico
178
+ """
179
+ if not user_text or user_text.strip() == "":
180
+ return history, "", {}, history
181
 
182
+ sentiment = classify_only(user_text)
183
+ reply = generate_reply_with_history(history, user_text, sentiment)
184
+
185
+ if history is None:
186
+ history = []
187
+
188
+ history = history + [(user_text, reply)]
189
+
190
+ return history, "", sentiment, history
191
 
192
 
193
  # ======================================================================
194
+ # 4. Interface Gradio - abas, design e historico
195
  # ======================================================================
196
 
197
+ with gr.Blocks(
198
+ title="Chatbot de Sentimentos - Professor Rodrigo",
199
+ theme=gr.themes.Default().set(
200
+ border_radius="8px",
201
+ shadow_drop="small",
202
+ font=["Inter", "system-ui", "sans-serif"],
203
+ ),
204
+ css="""
205
+ #header-markdown h1 { font-size: 1.8rem; }
206
+ #header-markdown p { font-size: 0.95rem; }
207
+ """
208
+ ) as demo:
209
  gr.Markdown(
210
  """
211
+ <div id="header-markdown">
212
+
213
  # Chatbot de Sentimentos (ML + IA Generativa)
 
214
 
215
+ **Professor Rodrigo** Projeto Final de Machine Learning & Deep Learning
 
216
 
217
+ - Classificação: TF-IDF + Regressão Logística (baseline).
218
+ - Geração: modelo `LLaMA 3` (Instruct) para respostas em PT-BR.
219
+
220
+ > Dica didática: envie **`baseline_pipe.pkl`** na aba *Files* do Space
221
+ > para usar um modelo de sentimentos treinado pelo seu grupo.
222
+
223
+ </div>
224
+ """,
225
+ elem_id="header-markdown",
226
  )
227
 
228
+ with gr.Tab("Análise de Sentimento (isolada)"):
229
+ with gr.Row():
230
+ with gr.Column(scale=3):
231
+ input_text = gr.Textbox(
232
+ label="Digite uma avaliação de produto",
233
+ lines=5,
234
+ placeholder=(
235
+ "Ex.: O produto chegou rápido e superou minhas expectativas "
236
+ "ou: O produto chegou quebrado, estou muito chateado."
237
+ ),
238
+ )
239
+ btn_analisar = gr.Button("Analisar sentimento", variant="primary")
240
+ with gr.Column(scale=2):
241
+ output_json = gr.JSON(
242
+ label="Resultado da classificação (baseline)",
243
+ )
244
+
245
  btn_analisar.click(classify_only, inputs=input_text, outputs=output_json)
246
 
247
+ with gr.Tab("Chatbot (Análise + Resposta com histórico)"):
 
 
 
 
 
 
248
  with gr.Row():
249
+ with gr.Column(scale=3):
250
+ chat_history = gr.Chatbot(
251
+ label="Conversa com o atendente virtual",
252
+ height=400,
253
+ )
254
+ user_input = gr.Textbox(
255
+ label="Mensagem do cliente",
256
+ lines=4,
257
+ placeholder="Ex.: Estou chateado, o produto é ruim.",
258
+ )
259
+ with gr.Row():
260
+ send_btn = gr.Button("Enviar", variant="primary")
261
+ clear_btn = gr.Button("Limpar conversa")
262
+
263
+ with gr.Column(scale=2):
264
+ last_sentiment = gr.JSON(
265
+ label="Sentimento da última mensagem",
266
+ )
267
+ gr.Markdown(
268
+ """
269
+ **Como funciona esta aba?**
270
+
271
+ 1. O cliente envia uma mensagem.
272
+ 2. O baseline classifica o sentimento (positivo/negativo).
273
+ 3. O modelo LLaMA 3 gera uma resposta empática, usando o sentimento apenas como contexto.
274
+ 4. O histórico da conversa é mantido e influencia as respostas seguintes.
275
+ """
276
+ )
277
+
278
+ state_history = gr.State([])
279
+
280
+ send_btn.click(
281
+ chatbot_step,
282
+ inputs=[state_history, user_input],
283
+ outputs=[chat_history, user_input, last_sentiment, state_history],
284
  )
285
 
286
+ def clear_chat():
287
+ return [], {}, []
288
+
289
+ clear_btn.click(
290
+ clear_chat,
291
+ inputs=None,
292
+ outputs=[chat_history, last_sentiment, state_history],
293
  )
294
 
295