Pauloeocadia commited on
Commit
1d36c93
·
verified ·
1 Parent(s): d17773d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +104 -238
app.py CHANGED
@@ -1,256 +1,122 @@
 
1
 
 
2
  import requests
3
  import json
4
  from transformers import pipeline
 
5
 
6
- # 1) Lista completa das perguntas
7
- questions = [
8
- {
9
- "id": 1,
10
- "question": "1.1 - Unidade do CEU:",
11
- "type": "radio",
12
- "options": [
13
- "CEU itapoã",
14
- "CEU Recanto",
15
- "CEU QNR 02",
16
- "CEU QMN 28",
17
- "CEU QNN 13",
18
- "Outro"
19
- ],
20
- "otherOption": True,
21
- "section": "1. Informações Gerais",
22
- "allowComment": False
23
- },
24
- {
25
- "id": 2,
26
- "question": "1.2 - Categoria de Participante:",
27
- "type": "radio",
28
- "options": [
29
- "Aluno(a)",
30
- "Pai/Mãe/Responsável",
31
- "Professor(a)",
32
- "Gestor(a)",
33
- "Monitor(a)",
34
- "Outro"
35
- ],
36
- "otherOption": True,
37
- "section": "1. Informações Gerais",
38
- "allowComment": False,
39
- "interpretation": "A pergunta identifica qual o tipo de envolvimento do participante com o CEU..."
40
- },
41
- {
42
- "id": 3,
43
- "question": "2.1 - Como você avalia a infraestrutura da unidade do CEU que frequenta?",
44
- "type": "radio",
45
- "options": ["Excelente", "Boa", "Regular", "Ruim", "Muito Ruim"],
46
- "section": "2. Avaliação Geral",
47
- "allowComment": True,
48
- "interpretation": "A maioria dos alunos avalia a infraestrutura como boa ou excelente..."
49
- },
50
- {
51
- "id": 4,
52
- "question": "2.3 - Como você avalia os programas e atividades oferecidos?",
53
- "type": "radio",
54
- "options": ["Excelente", "Boa", "Regular", "Ruim", "Muito Ruim"],
55
- "section": "2. Avaliação Geral",
56
- "allowComment": True,
57
- "interpretation": "Os programas e atividades oferecidos são amplamente bem avaliados..."
58
- },
59
- {
60
- "id": 5,
61
- "question": "2.4 - Os horários das atividades atendem às suas necessidades?",
62
- "type": "radio",
63
- "options": ["Sim", "Parcialmente", "Não"],
64
- "section": "2. Avaliação Geral",
65
- "allowComment": True,
66
- "interpretation": "Horários adequados facilitam a participação..."
67
- },
68
- {
69
- "id": 6,
70
- "question": "2.5 - Você sente que sua participação nas atividades contribui para seu desenvolvimento pessoal/profissional?",
71
- "type": "radio",
72
- "options": ["Sim", "Parcialmente", "Não"],
73
- "section": "2. Avaliação Geral",
74
- "allowComment": True,
75
- "interpretation": "A percepção de ganho pessoal/profissional é um indicador..."
76
- },
77
- {
78
- "id": 7,
79
- "question": "3.1 - Como você avalia o atendimento da equipe do CEU (monitores, professores, gestores)?",
80
- "type": "radio",
81
- "options": ["Excelente", "Boa", "Regular", "Ruim", "Muito Ruim"],
82
- "section": "3. Atendimento e Qualidade do Serviço",
83
- "allowComment": True,
84
- "interpretation": "O atendimento da equipe é crucial para a satisfação..."
85
- },
86
- {
87
- "id": 8,
88
- "question": "3.2 - Você sente que a equipe do CEU está disponível e pronta para ajudar quando necessário?",
89
- "type": "radio",
90
- "options": ["Sempre", "Na maioria das vezes", "Às vezes", "Raramente", "Nunca"],
91
- "section": "3. Atendimento e Qualidade do Serviço",
92
- "allowComment": True,
93
- "interpretation": "Disponibilidade e prontidão da equipe refletem diretamente no bem-estar..."
94
- },
95
- {
96
- "id": 9,
97
- "question": "3.3 - Como você avalia a comunicação da unidade (informação sobre eventos, mudanças, etc.)?",
98
- "type": "radio",
99
- "options": ["Excelente", "Boa", "Regular", "Ruim", "Muito Ruim"],
100
- "section": "3. Atendimento e Qualidade do Serviço",
101
- "allowComment": True,
102
- "interpretation": "Uma boa comunicação é essencial para engajamento..."
103
- },
104
- {
105
- "id": 10,
106
- "question": "4.1 - As atividades do CEU têm impacto positivo na sua vida ou na de seus filhos?",
107
- "type": "radio",
108
- "options": ["Sim", "Parcialmente", "Não"],
109
- "section": "4. Impacto e Satisfação Pessoal",
110
- "allowComment": True,
111
- "interpretation": "Medir o impacto positivo demonstra o valor social do CEU..."
112
- },
113
- {
114
- "id": 11,
115
- "question": "4.2 - Você indicaria o CEU para amigos ou familiares?",
116
- "type": "radio",
117
- "options": ["Sim", "Talvez", "Não"],
118
- "section": "4. Impacto e Satisfação Pessoal",
119
- "allowComment": True,
120
- "interpretation": "O indicador de recomendação sugere grau de satisfação..."
121
- },
122
- {
123
- "id": 12,
124
- "question": "5.1 - Há algo que você gostaria de ver melhorado no CEU?",
125
- "type": "radio",
126
- "options": ["Sim", "Não"],
127
- "section": "5. Sugestões e Melhorias",
128
- "allowComment": True,
129
- "interpretation": "Esta pergunta abre espaço para melhorias pontuais e específicas..."
130
- },
131
- {
132
- "id": 13,
133
- "question": "5.2 - Que tipo de novas atividades ou programas você gostaria de ver no CEU?",
134
- "type": "radio",
135
- "options": ["Sim", "Não"],
136
- "section": "5. Sugestões e Melhorias",
137
- "allowComment": True,
138
- "interpretation": "Novas atividades ou programas expandem a atratividade do CEU..."
139
- },
140
- {
141
- "id": 14,
142
- "question": "5.3 - Há algum outro comentário ou sugestão que gostaria de compartilhar?",
143
- "type": "radio",
144
- "options": ["Sim", "Não"],
145
- "section": "5. Sugestões e Melhorias",
146
- "allowComment": True,
147
- "interpretation": "Um espaço aberto para o participante expressar livremente..."
148
- }
149
- ]
150
 
151
- # Mapeia id da pergunta => texto
152
- questions_map = {q["id"]: q["question"] for q in questions}
 
153
 
154
- # URL da API
155
- url = "https://proced.datasavvy.com.br/api/responses"
 
 
 
 
 
156
 
157
- # Consome a API
158
- response = requests.get(url)
159
- if response.status_code == 200:
160
- data = response.json()
161
- else:
162
- print("Erro ao acessar a API:", response.status_code)
163
- exit()
164
 
165
- # Montar lista de associações
166
- associacoes = []
167
- for registro in data:
168
- if "answers" in registro and "comments" in registro:
169
- for pergunta_id_str, resposta in registro["answers"].items():
170
- try:
171
- pergunta_id = int(pergunta_id_str)
172
- except ValueError:
173
- pergunta_id = None
174
-
175
- comentario = registro["comments"].get(pergunta_id_str, None)
 
176
 
177
- # Aqui, ao invés de "studentId": registro["studentId"]
178
- # Usamos o token que está em registro["student_info"]["token"]
179
  associacoes.append({
180
- "studentId": registro["student_info"]["token"], # <== Mudança aqui
181
  "perguntaId": pergunta_id_str,
182
- "perguntaTexto": questions_map.get(pergunta_id, f"Pergunta {pergunta_id_str}"),
183
  "resposta": resposta,
184
  "comentario": comentario
185
  })
186
-
187
- # Inicializar o pipeline de Zero-Shot Classification
188
- classifier = pipeline(
189
- task="zero-shot-classification",
190
- model="joeddav/xlm-roberta-large-xnli" # modelo multilíngue PT
191
- )
192
-
193
- candidate_labels = [
194
- "sugestões de melhoria",
195
- "elogios",
196
- "reclamações",
197
- "solicitações de serviços ou infraestrutura"
198
- ]
199
-
200
- classified_comments = []
201
- for registro in data:
202
- if "comments" not in registro or "answers" not in registro:
203
- continue
 
 
 
 
204
 
205
- for question_id_str, comment in registro["comments"].items():
206
- if not comment or not comment.strip():
207
- continue
208
-
209
- answer = registro["answers"].get(question_id_str, "Sem resposta")
210
-
211
- try:
212
- q_id = int(question_id_str)
213
- except ValueError:
214
- q_id = None
215
-
216
- question_text = questions_map.get(q_id, f"Pergunta {question_id_str}")
217
-
218
- text_for_model = f"Pergunta: {question_text}. Comentário: {comment}"
219
-
220
- classification_result = classifier(
221
- text_for_model,
222
- candidate_labels,
223
- multi_label=False
224
- )
225
-
226
- best_label = classification_result["labels"][0]
227
- best_score = classification_result["scores"][0]
228
-
229
- # Aqui também
230
- classified_comments.append({
231
- "studentId": registro["student_info"]["token"], # <== Mudança aqui
232
- "questionId": question_id_str,
233
- "questionText": question_text,
234
- "answer": answer,
235
- "comment": comment,
236
- "classification": best_label,
237
- "confidence": best_score
238
- })
239
 
240
- # Salvar resultados em JSON
241
- with open("associacoes.json", "w", encoding="utf-8") as assoc_file:
242
- json.dump(associacoes, assoc_file, indent=4, ensure_ascii=False)
243
- print("Arquivo 'associacoes.json' criado com sucesso!")
244
-
245
- with open("classified_comments.json", "w", encoding="utf-8") as classified_file:
246
- json.dump(classified_comments, classified_file, indent=4, ensure_ascii=False)
247
- print("Arquivo 'classified_comments.json' criado com sucesso!")
248
-
249
- # Mostra uma amostra
250
- print("\n--- Associações (amostra) ---")
251
- for assoc in associacoes[:5]:
252
- print(assoc)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253
 
254
- print("\n--- Classificações (amostra) ---")
255
- for classified in classified_comments[:5]:
256
- print(classified)
 
1
+ # app.py
2
 
3
+ import streamlit as st
4
  import requests
5
  import json
6
  from transformers import pipeline
7
+ from questions import questions
8
 
9
+ st.title("Classificação de Comentários do CEU")
10
+ st.write("Este aplicativo baixa respostas da API, classifica os comentários e exibe os resultados.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
+ @st.cache(allow_output_mutation=True)
13
+ def get_questions_map(questions_list):
14
+ return {str(q["id"]): q["question"] for q in questions_list}
15
 
16
+ @st.cache(allow_output_mutation=True)
17
+ def load_classifier():
18
+ classifier = pipeline(
19
+ task="zero-shot-classification",
20
+ model="joeddav/xlm-roberta-large-xnli" # Modelo multilíngue
21
+ )
22
+ return classifier
23
 
24
+ def fetch_data(api_url):
25
+ response = requests.get(api_url)
26
+ if response.status_code == 200:
27
+ return response.json()
28
+ else:
29
+ st.error(f"Erro ao acessar a API: {response.status_code}")
30
+ return None
31
 
32
+ def process_data(data, questions_map, classifier, candidate_labels):
33
+ associacoes = []
34
+ classified_comments = []
35
+
36
+ for registro in data:
37
+ token = registro.get("student_info", {}).get("token", "Sem Token")
38
+ answers = registro.get("answers", {})
39
+ comments = registro.get("comments", {})
40
+
41
+ for pergunta_id_str, resposta in answers.items():
42
+ pergunta_texto = questions_map.get(pergunta_id_str, f"Pergunta {pergunta_id_str}")
43
+ comentario = comments.get(pergunta_id_str, "Sem comentário")
44
 
 
 
45
  associacoes.append({
46
+ "token": token,
47
  "perguntaId": pergunta_id_str,
48
+ "perguntaTexto": pergunta_texto,
49
  "resposta": resposta,
50
  "comentario": comentario
51
  })
52
+
53
+ # Classificação do comentário, se existir
54
+ if comentario and comentario.strip():
55
+ text_for_model = f"Pergunta: {pergunta_texto}. Comentário: {comentario}"
56
+ classification_result = classifier(
57
+ text_for_model,
58
+ candidate_labels,
59
+ multi_label=False
60
+ )
61
+
62
+ best_label = classification_result["labels"][0]
63
+ best_score = classification_result["scores"][0]
64
+
65
+ classified_comments.append({
66
+ "token": token,
67
+ "perguntaId": pergunta_id_str,
68
+ "perguntaTexto": pergunta_texto,
69
+ "resposta": resposta,
70
+ "comentario": comentario,
71
+ "classificacao": best_label,
72
+ "confiança": round(best_score, 4)
73
+ })
74
 
75
+ return associacoes, classified_comments
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
 
77
+ def main():
78
+ api_url = st.text_input("URL da API", "https://proced.datasavvy.com.br/api/responses")
79
+ if st.button("Processar Dados"):
80
+ data = fetch_data(api_url)
81
+ if data:
82
+ with st.spinner("Carregando modelo de classificação..."):
83
+ classifier = load_classifier()
84
+ questions_map = get_questions_map(questions)
85
+ candidate_labels = [
86
+ "sugestões de melhoria",
87
+ "elogios",
88
+ "reclamações",
89
+ "solicitações de serviços ou infraestrutura"
90
+ ]
91
+ with st.spinner("Processando e classificando comentários..."):
92
+ associacoes, classified_comments = process_data(data, questions_map, classifier, candidate_labels)
93
+
94
+ st.success("Processamento concluído!")
95
+
96
+ st.header("Associações de Perguntas, Respostas e Comentários")
97
+ st.dataframe(associacoes)
98
+
99
+ st.header("Comentários Classificados")
100
+ st.dataframe(classified_comments)
101
+
102
+ # Opção para baixar os resultados
103
+ st.subheader("Baixar Resultados")
104
+ associacoes_json = json.dumps(associacoes, indent=4, ensure_ascii=False)
105
+ classified_comments_json = json.dumps(classified_comments, indent=4, ensure_ascii=False)
106
+
107
+ st.download_button(
108
+ label="Baixar Associações (JSON)",
109
+ data=associacoes_json,
110
+ file_name="associacoes.json",
111
+ mime="application/json"
112
+ )
113
+
114
+ st.download_button(
115
+ label="Baixar Classificações (JSON)",
116
+ data=classified_comments_json,
117
+ file_name="classified_comments.json",
118
+ mime="application/json"
119
+ )
120
 
121
+ if __name__ == "__main__":
122
+ main()