BugZoid commited on
Commit
7127fcb
·
verified ·
1 Parent(s): fe176a4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +87 -220
app.py CHANGED
@@ -1,13 +1,12 @@
1
  import tweepy
2
- from transformers import pipeline, GPT2LMHeadModel, GPT2Tokenizer, AutoModelForSequenceClassification, AutoTokenizer
3
  import os
4
  import streamlit as st
5
  from datetime import datetime
6
  import time
7
  from tenacity import retry, stop_after_attempt, wait_exponential
8
- import torch
9
- from collections import Counter
10
  import re
 
11
 
12
  def debug_print(message):
13
  """Função para imprimir mensagens de debug tanto no console quanto no Streamlit"""
@@ -15,175 +14,109 @@ def debug_print(message):
15
  st.text(message)
16
 
17
  @retry(
18
- stop=stop_after_attempt(3),
19
- wait=wait_exponential(multiplier=1, min=4, max=10),
20
  retry=lambda e: isinstance(e, tweepy.errors.TooManyRequests)
21
  )
22
  def fetch_tweets(client, query, tweet_fields):
23
  try:
24
- debug_print(f"Iniciando busca com query: {query}")
25
- debug_print(f"Campos solicitados: {tweet_fields}")
26
-
27
  tweets = client.search_recent_tweets(
28
  query=query,
29
- max_results=100, # Aumentado para ter mais contexto
30
  tweet_fields=tweet_fields
31
  )
32
 
33
- if tweets is None:
34
- debug_print("Nenhum resultado retornado da API")
35
  return None
36
 
37
- if not hasattr(tweets, 'data'):
38
- debug_print("Resposta não contém dados")
39
- return None
40
-
41
- debug_print(f"Tweets encontrados: {len(tweets.data) if tweets.data else 0}")
42
  return tweets
43
 
44
- except tweepy.errors.TooManyRequests as e:
45
- debug_print(f"Rate limit atingido: {str(e)}")
46
- raise e
47
- except tweepy.errors.TwitterServerError as e:
48
- debug_print(f"Erro do servidor Twitter: {str(e)}")
49
- raise e
50
- except tweepy.errors.BadRequest as e:
51
- debug_print(f"Erro na requisição: {str(e)}")
52
- raise e
53
  except Exception as e:
54
- debug_print(f"Erro inesperado na busca: {str(e)}")
55
- raise e
56
 
57
- @retry(
58
- stop=stop_after_attempt(3),
59
- wait=wait_exponential(multiplier=1, min=4, max=10),
60
- retry=lambda e: isinstance(e, tweepy.errors.TooManyRequests)
61
- )
62
  def post_tweet(client, text):
63
  try:
64
  response = client.create_tweet(text=text)
65
  return response
66
  except Exception as e:
67
  debug_print(f"Erro ao postar tweet: {str(e)}")
68
- raise e
69
-
70
- def initialize_text_generator():
71
- """Inicializa o modelo de geração de texto"""
72
- # Usando um modelo GPT-2 em português maior para melhor qualidade
73
- model_name = "pierreguillou/gpt2-small-portuguese"
74
- tokenizer = GPT2Tokenizer.from_pretrained(model_name)
75
- model = GPT2LMHeadModel.from_pretrained(model_name)
76
- return model, tokenizer
77
 
78
  def extract_context_from_tweets(tweets_data):
79
- """Extrai contexto relevante dos tweets"""
80
  all_text = " ".join([tweet.text for tweet in tweets_data])
81
-
82
- # Remover URLs, mentions, RTs e caracteres especiais
83
  clean_text = re.sub(r'http\S+|@\S+|RT|[^\w\s]', ' ', all_text)
84
 
85
- # Encontrar nomes de participantes (palavras capitalizadas frequentes)
86
  words = clean_text.split()
87
  capitalized_words = [word for word in words if word.istitle() and len(word) > 2]
88
- participants = Counter(capitalized_words).most_common(5)
89
-
90
- # Encontrar temas/eventos importantes
91
- # Procurar por frases comuns que indicam eventos
92
- event_patterns = [
93
- r'paredão entre.*?(?=\s|$)',
94
- r'prova do líder.*?(?=\s|$)',
95
- r'prova do anjo.*?(?=\s|$)',
96
- r'eliminação.*?(?=\s|$)',
97
- r'briga entre.*?(?=\s|$)',
98
- r'jogo da discórdia.*?(?=\s|$)'
99
- ]
100
 
 
101
  events = []
102
- for pattern in event_patterns:
103
- matches = re.findall(pattern, all_text.lower())
104
- if matches:
105
- events.extend(matches)
106
 
107
  return {
108
  'participants': [p[0] for p in participants],
109
- 'events': list(set(events))[:3], # Top 3 eventos únicos
110
  'raw_text': clean_text
111
  }
112
 
113
  def generate_comment(context, sentiment_ratio, model, tokenizer):
114
- """Gera um comentário contextualizado sobre o BBB"""
115
-
116
- # Criar prompt baseado no contexto e sentimento
117
- sentiment_tone = ""
118
  if sentiment_ratio['positive'] > 0.5:
119
- sentiment_tone = "positivo"
120
  elif sentiment_ratio['negative'] > 0.5:
121
- sentiment_tone = "negativo"
122
  else:
123
- sentiment_tone = "dividido"
124
 
125
- # Construir contexto para o prompt
126
- prompt = f"No BBB25, com clima {sentiment_tone}"
127
 
128
- # Adicionar participantes relevantes
129
  if context['participants']:
130
- participants_str = ", ".join(context['participants'][:2])
131
- prompt += f", {participants_str} se destacam"
132
-
133
- # Adicionar eventos relevantes
134
  if context['events']:
135
- event_str = context['events'][0]
136
- prompt += f". {event_str.capitalize()}"
137
 
138
  # Gerar texto
139
- inputs = tokenizer.encode(prompt, return_tensors='pt', max_length=150, truncation=True)
140
-
141
- outputs = model.generate(
142
- inputs,
143
- max_length=200,
144
- num_return_sequences=3,
145
- temperature=0.9,
146
- top_k=50,
147
- top_p=0.95,
148
- do_sample=True,
149
- no_repeat_ngram_size=2,
150
- pad_token_id=tokenizer.eos_token_id
151
- )
152
-
153
- # Gerar múltiplas opções e escolher a melhor
154
- generated_texts = []
155
- for output in outputs:
156
- text = tokenizer.decode(output, skip_special_tokens=True)
157
- # Limpar e formatar o texto
158
  text = re.sub(r'\s+', ' ', text).strip()
159
- if len(text) > 30: # Garantir que temos um texto substancial
160
- generated_texts.append(text)
161
-
162
- # Escolher o melhor texto
163
- best_text = max(generated_texts, key=len) if generated_texts else prompt
164
-
165
- # Adicionar hashtags relevantes
166
- hashtags = " #BBB25"
167
- if context['participants']:
168
- hashtags += f" #{context['participants'][0].replace(' ', '')}"
169
- if context['events']:
170
- event_tag = context['events'][0].split()[0].capitalize()
171
- hashtags += f" #{event_tag}"
172
-
173
- # Garantir que está dentro do limite do Twitter
174
- max_length = 280 - len(hashtags)
175
- if len(best_text) > max_length:
176
- best_text = best_text[:max_length-3] + "..."
177
-
178
- return best_text + hashtags
179
 
180
  def main():
181
  try:
182
  st.title("Análise de Sentimentos - BBB25")
183
 
184
- # Verificar variáveis de ambiente
185
- debug_print("Verificando variáveis de ambiente...")
186
-
187
  required_vars = [
188
  'TWITTER_API_KEY',
189
  'TWITTER_API_SECRET_KEY',
@@ -192,20 +125,10 @@ def main():
192
  'TWITTER_BEARER_TOKEN'
193
  ]
194
 
195
- missing_vars = []
196
- for var in required_vars:
197
- if os.getenv(var) is None:
198
- missing_vars.append(var)
199
- debug_print(f"Erro: A variável de ambiente '{var}' não está definida.")
200
- else:
201
- debug_print(f"{var} carregada com sucesso.")
202
-
203
- if missing_vars:
204
- raise ValueError(f"Variáveis de ambiente faltando: {', '.join(missing_vars)}")
205
-
206
- debug_print("Iniciando autenticação com Twitter...")
207
 
208
- # Autenticação com Twitter
209
  client = tweepy.Client(
210
  bearer_token=os.getenv('TWITTER_BEARER_TOKEN'),
211
  consumer_key=os.getenv('TWITTER_API_KEY'),
@@ -215,132 +138,76 @@ def main():
215
  wait_on_rate_limit=True
216
  )
217
 
218
- # Inicializar modelo de geração de texto
219
- debug_print("Inicializando modelo de geração de texto...")
220
- model, tokenizer = initialize_text_generator()
 
221
 
222
- # Query principal
223
  query = 'BBB25 lang:pt -is:retweet -is:reply'
224
- tweet_fields = ['text', 'created_at', 'lang', 'public_metrics']
225
-
226
- debug_print("Iniciando busca principal de tweets...")
227
 
228
  with st.spinner('Buscando tweets...'):
229
  tweets = fetch_tweets(client, query, tweet_fields)
230
 
231
- if tweets is None:
232
  st.error("Não foi possível obter tweets")
233
  return
234
 
235
- if not tweets.data:
236
- st.warning("Nenhum tweet encontrado com os critérios especificados")
237
- debug_print("Busca retornou vazia")
238
- return
239
-
240
- debug_print(f"Encontrados {len(tweets.data)} tweets")
241
-
242
- # Extrair contexto dos tweets
243
  context = extract_context_from_tweets(tweets.data)
244
- debug_print("Contexto extraído dos tweets:")
245
- debug_print(f"Participantes mencionados: {context['participants']}")
246
- debug_print(f"Eventos detectados: {context['events']}")
247
 
248
  # Análise de sentimentos
249
  with st.spinner('Analisando sentimentos...'):
250
- debug_print("Iniciando análise de sentimentos...")
251
-
252
  sentiment_pipeline = pipeline(
253
  "sentiment-analysis",
254
  model="nlptown/bert-base-multilingual-uncased-sentiment"
255
  )
256
 
257
  sentiments = []
258
- for tweet in tweets.data:
259
- if hasattr(tweet, 'lang') and tweet.lang == 'pt':
260
- result = sentiment_pipeline(tweet.text)
261
- rating = int(result[0]['label'].split()[0])
262
- if rating >= 4:
263
- sentiments.append('positive')
264
- elif rating <= 2:
265
- sentiments.append('negative')
266
- else:
267
- sentiments.append('neutral')
268
- debug_print(f"Sentimento analisado: {rating} estrelas")
269
-
270
- time.sleep(1)
271
-
272
  # Calcular taxas
273
  if sentiments:
274
- positive = sentiments.count('positive')
275
- negative = sentiments.count('negative')
276
- neutral = sentiments.count('neutral')
277
  total = len(sentiments)
278
-
279
- debug_print(f"Total de sentimentos analisados: {total}")
280
-
281
  sentiment_ratios = {
282
- 'positive': positive / total,
283
- 'negative': negative / total,
284
- 'neutral': neutral / total
285
  }
286
 
287
- # Gerar comentário usando IA
288
- with st.spinner('Gerando novo comentário...'):
289
- debug_print("Iniciando geração de comentário com IA...")
290
  tweet_text = generate_comment(context, sentiment_ratios, model, tokenizer)
291
- debug_print(f"Comentário gerado: {tweet_text}")
292
-
293
- # Postar tweet
294
- with st.spinner('Postando tweet...'):
295
- debug_print("Tentando postar tweet...")
296
- try:
297
- post_tweet(client, tweet_text)
298
- st.success("Tweet postado com sucesso!")
299
- debug_print("Tweet postado com sucesso")
300
- except Exception as e:
301
- st.error(f"Erro ao postar tweet: {str(e)}")
302
- debug_print(f"Erro ao postar tweet: {str(e)}")
303
 
304
- # Interface Streamlit
305
- st.title("Resultados da Análise")
306
 
307
- # Mostrar estatísticas
308
  col1, col2, col3 = st.columns(3)
309
  with col1:
310
- st.metric("Sentimento Positivo", f"{sentiment_ratios['positive']:.1%}")
311
  with col2:
312
- st.metric("Sentimento Neutro", f"{sentiment_ratios['neutral']:.1%}")
313
  with col3:
314
- st.metric("Sentimento Negativo", f"{sentiment_ratios['negative']:.1%}")
315
-
316
- # Mostrar contexto extraído
317
- st.subheader("Contexto Analisado")
318
- st.write("Participantes em destaque:", ", ".join(context['participants']))
319
- st.write("Eventos detectados:", ", ".join(context['events']))
320
 
321
- # Mostrar tweet gerado
322
- st.subheader("Tweet Gerado e Postado")
323
  st.write(tweet_text)
324
 
325
- # Logging
326
- debug_print("Salvando log...")
327
- log_entry = {
328
- 'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
329
- 'positive_ratio': sentiment_ratios['positive'],
330
- 'negative_ratio': sentiment_ratios['negative'],
331
- 'neutral_ratio': sentiment_ratios['neutral'],
332
- 'context': context,
333
- 'tweet': tweet_text
334
- }
335
-
336
  with open('posting_log.txt', 'a') as f:
337
- f.write(f"{str(log_entry)}\n")
338
- debug_print("Log salvo com sucesso")
339
 
340
  except Exception as e:
341
  st.error(f"Erro: {str(e)}")
342
- debug_print(f"Erro fatal: {str(e)}")
343
- raise e
344
 
345
  finally:
346
  st.markdown("---")
 
1
  import tweepy
2
+ from transformers import pipeline, GPT2LMHeadModel, GPT2Tokenizer
3
  import os
4
  import streamlit as st
5
  from datetime import datetime
6
  import time
7
  from tenacity import retry, stop_after_attempt, wait_exponential
 
 
8
  import re
9
+ from collections import Counter
10
 
11
  def debug_print(message):
12
  """Função para imprimir mensagens de debug tanto no console quanto no Streamlit"""
 
14
  st.text(message)
15
 
16
  @retry(
17
+ stop=stop_after_attempt(2), # Reduzido para 2 tentativas
18
+ wait=wait_exponential(multiplier=1, min=2, max=4), # Tempo de espera reduzido
19
  retry=lambda e: isinstance(e, tweepy.errors.TooManyRequests)
20
  )
21
  def fetch_tweets(client, query, tweet_fields):
22
  try:
 
 
 
23
  tweets = client.search_recent_tweets(
24
  query=query,
25
+ max_results=10, # Reduzido para 10 tweets
26
  tweet_fields=tweet_fields
27
  )
28
 
29
+ if not hasattr(tweets, 'data') or tweets.data is None:
 
30
  return None
31
 
 
 
 
 
 
32
  return tweets
33
 
 
 
 
 
 
 
 
 
 
34
  except Exception as e:
35
+ debug_print(f"Erro na busca: {str(e)}")
36
+ return None
37
 
 
 
 
 
 
38
  def post_tweet(client, text):
39
  try:
40
  response = client.create_tweet(text=text)
41
  return response
42
  except Exception as e:
43
  debug_print(f"Erro ao postar tweet: {str(e)}")
44
+ return None
 
 
 
 
 
 
 
 
45
 
46
  def extract_context_from_tweets(tweets_data):
47
+ """Versão simplificada da extração de contexto"""
48
  all_text = " ".join([tweet.text for tweet in tweets_data])
 
 
49
  clean_text = re.sub(r'http\S+|@\S+|RT|[^\w\s]', ' ', all_text)
50
 
51
+ # Encontrar nomes capitalizados frequentes
52
  words = clean_text.split()
53
  capitalized_words = [word for word in words if word.istitle() and len(word) > 2]
54
+ participants = Counter(capitalized_words).most_common(3) # Reduzido para 3
 
 
 
 
 
 
 
 
 
 
 
55
 
56
+ # Eventos simplificados
57
  events = []
58
+ event_keywords = ['paredão', 'prova', 'líder', 'eliminação', 'briga']
59
+ for keyword in event_keywords:
60
+ if keyword in clean_text.lower():
61
+ events.append(keyword)
62
 
63
  return {
64
  'participants': [p[0] for p in participants],
65
+ 'events': events[:2], # Limitado a 2 eventos
66
  'raw_text': clean_text
67
  }
68
 
69
  def generate_comment(context, sentiment_ratio, model, tokenizer):
70
+ """Versão otimizada da geração de comentários"""
71
+ # Determinar o tom com base no sentimento
 
 
72
  if sentiment_ratio['positive'] > 0.5:
73
+ tone = "clima animado"
74
  elif sentiment_ratio['negative'] > 0.5:
75
+ tone = "clima tenso"
76
  else:
77
+ tone = "opiniões divididas"
78
 
79
+ # Construir prompt base
80
+ prompt = f"BBB25 com {tone}"
81
 
82
+ # Adicionar contexto se disponível
83
  if context['participants']:
84
+ prompt += f", {context['participants'][0]}"
 
 
 
85
  if context['events']:
86
+ prompt += f", {context['events'][0]}"
 
87
 
88
  # Gerar texto
89
+ try:
90
+ inputs = tokenizer.encode(prompt, return_tensors='pt', max_length=100, truncation=True)
91
+ outputs = model.generate(
92
+ inputs,
93
+ max_length=150, # Reduzido para melhor performance
94
+ num_return_sequences=1, # Apenas uma sequência
95
+ temperature=0.8,
96
+ top_k=40,
97
+ do_sample=True,
98
+ pad_token_id=tokenizer.eos_token_id
99
+ )
100
+
101
+ text = tokenizer.decode(outputs[0], skip_special_tokens=True)
 
 
 
 
 
 
102
  text = re.sub(r'\s+', ' ', text).strip()
103
+
104
+ # Adicionar hashtags
105
+ hashtags = " #BBB25"
106
+ if len(text) + len(hashtags) > 280:
107
+ text = text[:277-len(hashtags)] + "..."
108
+
109
+ return text + hashtags
110
+
111
+ except Exception as e:
112
+ debug_print(f"Erro na geração: {str(e)}")
113
+ return f"BBB25: {tone} hoje! #BBB25" # Fallback simples
 
 
 
 
 
 
 
 
 
114
 
115
  def main():
116
  try:
117
  st.title("Análise de Sentimentos - BBB25")
118
 
119
+ # Verificação simplificada de variáveis de ambiente
 
 
120
  required_vars = [
121
  'TWITTER_API_KEY',
122
  'TWITTER_API_SECRET_KEY',
 
125
  'TWITTER_BEARER_TOKEN'
126
  ]
127
 
128
+ if any(os.getenv(var) is None for var in required_vars):
129
+ raise ValueError("Faltam variáveis de ambiente necessárias")
 
 
 
 
 
 
 
 
 
 
130
 
131
+ # Autenticação Twitter
132
  client = tweepy.Client(
133
  bearer_token=os.getenv('TWITTER_BEARER_TOKEN'),
134
  consumer_key=os.getenv('TWITTER_API_KEY'),
 
138
  wait_on_rate_limit=True
139
  )
140
 
141
+ # Inicializar modelo
142
+ model_name = "pierreguillou/gpt2-small-portuguese"
143
+ tokenizer = GPT2Tokenizer.from_pretrained(model_name)
144
+ model = GPT2LMHeadModel.from_pretrained(model_name)
145
 
146
+ # Buscar tweets
147
  query = 'BBB25 lang:pt -is:retweet -is:reply'
148
+ tweet_fields = ['text', 'created_at']
 
 
149
 
150
  with st.spinner('Buscando tweets...'):
151
  tweets = fetch_tweets(client, query, tweet_fields)
152
 
153
+ if tweets is None or not tweets.data:
154
  st.error("Não foi possível obter tweets")
155
  return
156
 
 
 
 
 
 
 
 
 
157
  context = extract_context_from_tweets(tweets.data)
 
 
 
158
 
159
  # Análise de sentimentos
160
  with st.spinner('Analisando sentimentos...'):
 
 
161
  sentiment_pipeline = pipeline(
162
  "sentiment-analysis",
163
  model="nlptown/bert-base-multilingual-uncased-sentiment"
164
  )
165
 
166
  sentiments = []
167
+ for tweet in tweets.data[:10]: # Limitado a 10 tweets
168
+ result = sentiment_pipeline(tweet.text[:512]) # Limitado a 512 caracteres
169
+ rating = int(result[0]['label'].split()[0])
170
+ if rating >= 4:
171
+ sentiments.append('positive')
172
+ elif rating <= 2:
173
+ sentiments.append('negative')
174
+ else:
175
+ sentiments.append('neutral')
176
+
 
 
 
 
177
  # Calcular taxas
178
  if sentiments:
 
 
 
179
  total = len(sentiments)
 
 
 
180
  sentiment_ratios = {
181
+ 'positive': sentiments.count('positive') / total,
182
+ 'negative': sentiments.count('negative') / total,
183
+ 'neutral': sentiments.count('neutral') / total
184
  }
185
 
186
+ # Gerar e postar tweet
187
+ with st.spinner('Gerando e postando tweet...'):
 
188
  tweet_text = generate_comment(context, sentiment_ratios, model, tokenizer)
189
+ post_tweet(client, tweet_text)
 
 
 
 
 
 
 
 
 
 
 
190
 
191
+ # Interface
192
+ st.title("Resultados")
193
 
 
194
  col1, col2, col3 = st.columns(3)
195
  with col1:
196
+ st.metric("Positivo", f"{sentiment_ratios['positive']:.1%}")
197
  with col2:
198
+ st.metric("Neutro", f"{sentiment_ratios['neutral']:.1%}")
199
  with col3:
200
+ st.metric("Negativo", f"{sentiment_ratios['negative']:.1%}")
 
 
 
 
 
201
 
202
+ st.subheader("Tweet Gerado")
 
203
  st.write(tweet_text)
204
 
205
+ # Log simplificado
 
 
 
 
 
 
 
 
 
 
206
  with open('posting_log.txt', 'a') as f:
207
+ f.write(f"{datetime.now()}: {tweet_text}\n")
 
208
 
209
  except Exception as e:
210
  st.error(f"Erro: {str(e)}")
 
 
211
 
212
  finally:
213
  st.markdown("---")