ProfRod100 commited on
Commit
7b7ba20
·
verified ·
1 Parent(s): e2e4813

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +20 -215
app.py CHANGED
@@ -1,228 +1,33 @@
1
-
2
- import os
3
- import numpy as np
4
  import gradio as gr
5
  import joblib
 
 
6
 
7
- from sklearn.pipeline import Pipeline
8
- from sklearn.feature_extraction.text import TfidfVectorizer
9
- from sklearn.linear_model import LogisticRegression
10
-
11
- from transformers import pipeline as hf_pipeline
12
-
13
-
14
- # ======================================================================
15
- # 1. Baseline de Sentimentos (TF-IDF + Logistic Regression)
16
- # ======================================================================
17
-
18
- BASELINE_PATH = os.getenv("MODEL_PATH", "baseline_pipe.pkl")
19
-
20
-
21
- def train_small_baseline(save_path: str = BASELINE_PATH,
22
- max_samples: int = 10000):
23
- """
24
- Treina um baseline pequeno usando uma amostra do dataset amazon_polarity.
25
- Usado apenas se baseline_pipe.pkl nao existir no Space.
26
- """
27
- from datasets import load_dataset
28
- import pandas as pd
29
-
30
- # Carrega o split de treino inteiro
31
- ds = load_dataset("amazon_polarity", split="train")
32
-
33
- # Embaralha e pega apenas max_samples exemplos (para ficar leve)
34
- ds_small = ds.shuffle(seed=42).select(range(min(max_samples, len(ds))))
35
-
36
- df = pd.DataFrame({"text": ds_small["content"], "label": ds_small["label"]})
37
-
38
- pipe = Pipeline(
39
- [
40
- ("tfidf", TfidfVectorizer(max_features=30000, ngram_range=(1, 2))),
41
- ("clf", LogisticRegression(max_iter=1000)),
42
- ]
43
- )
44
-
45
- pipe.fit(df["text"], df["label"])
46
- joblib.dump(pipe, save_path)
47
- return pipe
48
-
49
-
50
- def load_or_bootstrap_baseline():
51
- """
52
- Se existir baseline_pipe.pkl, carrega.
53
- Se nao existir e DISABLE_AUTOTRAIN != 1, treina um baseline pequeno.
54
- """
55
- if os.path.exists(BASELINE_PATH):
56
- return joblib.load(BASELINE_PATH)
57
-
58
- disable_auto = os.getenv("DISABLE_AUTOTRAIN", "0")
59
- if disable_auto == "1":
60
- return None
61
-
62
- return train_small_baseline()
63
-
64
-
65
- baseline_model = load_or_bootstrap_baseline()
66
 
 
 
 
67
 
68
- def classify_only(text: str):
69
- """
70
- Apenas classifica o sentimento (positivo/negativo) e retorna JSON.
71
- """
72
  if not text or text.strip() == "":
73
- return {"erro": "Digite um texto."}
74
-
75
- if baseline_model is None:
76
- return {
77
- "erro": (
78
- "Modelo baseline nao encontrado. "
79
- "Envie baseline_pipe.pkl na aba Files ou remova DISABLE_AUTOTRAIN."
80
- )
81
- }
82
-
83
- proba = baseline_model.predict_proba([text])[0]
84
  pred = int(np.argmax(proba))
85
  label = "positivo" if pred == 1 else "negativo"
86
  conf = float(np.max(proba))
87
-
88
- return {"sentimento": label, "confianca": round(conf, 3)}
89
-
90
-
91
- # ======================================================================
92
- # 2. IA Generativa (FLAN-T5) para resposta ao cliente
93
- # ======================================================================
94
-
95
- GEN_MODEL_ID = os.getenv("GEN_MODEL_ID", "google/flan-t5-base")
96
-
97
- generator = hf_pipeline("text2text-generation", model=GEN_MODEL_ID)
98
-
99
- SYSTEM_PROMPT = (
100
- "Voce e um atendente virtual educado que responde em portugues do Brasil. "
101
- "Use poucas frases, tom empatico e pratico."
102
  )
103
 
104
-
105
- def generate_reply(user_text: str, sentimento_json):
106
- """
107
- Gera uma resposta em PT-BR condicionada ao sentimento detectado.
108
- """
109
- if not user_text or user_text.strip() == "":
110
- return "Digite uma mensagem."
111
-
112
- sentimento = None
113
- if isinstance(sentimento_json, dict) and "sentimento" in sentimento_json:
114
- sentimento = sentimento_json["sentimento"]
115
-
116
- if sentimento == "negativo":
117
- intent = (
118
- "A avaliacao do cliente e NEGATIVA. "
119
- "Peca desculpas, reconheca o problema, ofereca ajuda objetiva "
120
- "e solicite informacoes adicionais (numero do pedido, produto, contato)."
121
- )
122
- elif sentimento == "positivo":
123
- intent = (
124
- "A avaliacao do cliente e POSITIVA. "
125
- "Agradeca de forma calorosa, reforce os pontos positivos citados "
126
- "e convide o cliente a continuar comprando."
127
- )
128
- else:
129
- intent = (
130
- "O sentimento nao foi identificado. "
131
- "Responda de forma neutra, cordial e util."
132
- )
133
-
134
- # opcional: pegar a confianca pra colocar no prompt
135
- conf = None
136
- if isinstance(sentimento_json, dict) and "confianca" in sentimento_json:
137
- conf = sentimento_json["confianca"]
138
-
139
- prompt = f"""
140
- Voce e um assistente de atendimento ao cliente.
141
-
142
- Com base na mensagem do usuario e no sentimento detectado,
143
- gere uma resposta educada, objetiva e natural em PORTUGUES DO BRASIL,
144
- usando entre 2 e 4 frases.
145
-
146
- Mensagem do usuario:
147
- \"\"\"{user_text}\"\"\"
148
-
149
- Sentimento identificado: {sentimento}
150
- Confianca do classificador: {conf}
151
-
152
- Sua resposta deve:
153
- - demonstrar empatia,
154
- - responder diretamente ao que o cliente escreveu,
155
- - NUNCA mencionar que esta gerando uma "resposta curta",
156
- - NUNCA explicar o que esta fazendo,
157
- - NUNCA repetir estas instrucoes internas.
158
-
159
- Agora responda ao cliente da forma mais natural possivel.
160
- """
161
-
162
- out = generator(
163
- prompt,
164
- max_length=128,
165
- do_sample=True,
166
- temperature=0.6,
167
- top_p=0.9,
168
- )[0]["generated_text"]
169
-
170
- return out
171
-
172
-
173
- # ======================================================================
174
- # 3. Interface Gradio - duas abas (Analise e Chatbot)
175
- # ======================================================================
176
-
177
- with gr.Blocks(title="Chatbot de Sentimentos - Professor Rodrigo") as demo:
178
- gr.Markdown(
179
- """
180
- # Chatbot de Sentimentos (ML + IA Generativa)
181
- **Professor Rodrigo** - Projeto Final ML & DL
182
-
183
- - Classificacao: TF-IDF + Regressao Logistica (baseline).
184
- - Geracao: `google/flan-t5-base` para redigir respostas em PT-BR.
185
-
186
- > Dica: envie `baseline_pipe.pkl` na aba *Files* para usar um modelo treinado por voce.
187
- """
188
- )
189
-
190
- # Aba 1 - somente analise de sentimento
191
- with gr.Tab("Analise de Sentimento"):
192
- input_text = gr.Textbox(
193
- label="Digite uma avaliacao de produto",
194
- lines=4,
195
- placeholder="Ex.: O produto chegou rapido e superou minhas expectativas.",
196
- )
197
- output_json = gr.JSON(label="Resultado da classificacao")
198
- btn_analisar = gr.Button("Analisar")
199
- btn_analisar.click(classify_only, inputs=input_text, outputs=output_json)
200
-
201
- # Aba 2 - Chatbot (analise + resposta generativa)
202
- with gr.Tab("Chatbot (Analise + Resposta)"):
203
- chat_input = gr.Textbox(
204
- label="Mensagem do cliente",
205
- lines=4,
206
- placeholder="Ex.: Estou chateado, o produto chegou quebrado.",
207
- )
208
- with gr.Row():
209
- btn_analise_chat = gr.Button("1) Analisar sentimento")
210
- btn_resposta = gr.Button("2) Gerar resposta")
211
-
212
- chat_analysis = gr.JSON(label="Sentimento detectado")
213
- chat_reply = gr.Textbox(
214
- label="Resposta gerada pela IA",
215
- lines=6,
216
- )
217
-
218
- btn_analise_chat.click(
219
- classify_only, inputs=chat_input, outputs=chat_analysis
220
- )
221
- btn_resposta.click(
222
- generate_reply, inputs=[chat_input, chat_analysis], outputs=chat_reply
223
- )
224
-
225
-
226
  if __name__ == "__main__":
227
  demo.launch()
228
-
 
 
 
 
1
  import gradio as gr
2
  import joblib
3
+ import numpy as np
4
+ import os
5
 
6
+ MODEL_PATH = os.getenv("MODEL_PATH", "baseline_pipe.pkl")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
+ baseline = None
9
+ if os.path.exists(MODEL_PATH):
10
+ baseline = joblib.load(MODEL_PATH)
11
 
12
+ def predict_sentiment(text: str):
 
 
 
13
  if not text or text.strip() == "":
14
+ return {"predição": "n/a", "confiança": 0.0}
15
+ if baseline is None:
16
+ # Mensagem amigável quando o modelo ainda não foi enviado
17
+ return {"erro": "Modelo não encontrado. Envie baseline_pipe.pkl nos Files do Space."}
18
+ proba = baseline.predict_proba([text])[0]
 
 
 
 
 
 
19
  pred = int(np.argmax(proba))
20
  label = "positivo" if pred == 1 else "negativo"
21
  conf = float(np.max(proba))
22
+ return {"predição": label, "confiança": conf}
23
+
24
+ demo = gr.Interface(
25
+ fn=predict_sentiment,
26
+ inputs=gr.Textbox(label="Digite uma avaliação de produto"),
27
+ outputs=gr.JSON(label="Resultado"),
28
+ title="Análise de Sentimentos (Amazon Polarity)",
29
+ description="Envie o arquivo baseline_pipe.pkl na aba Files para ativar o modelo."
 
 
 
 
 
 
 
30
  )
31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  if __name__ == "__main__":
33
  demo.launch()