Skip to content

Commit f01dbb7

Browse files
committed
update
1 parent a00604c commit f01dbb7

15 files changed

Lines changed: 2164 additions & 132 deletions

data/transcriptions/transcriptTime.py

Lines changed: 403 additions & 0 deletions
Large diffs are not rendered by default.

pipeline/canalEspecifico.py

Lines changed: 514 additions & 0 deletions
Large diffs are not rendered by default.

pipeline/clean_transcripts.py

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
# Configuração de diretórios
1717
# ------------------------------------------------------------
1818
BASE_DIR = Path(__file__).resolve().parent.parent
19-
RAW_DB_PATH = BASE_DIR / "db" / "YouTubeStatsPipeline.sqlite3"
20-
OUTPUT_PATH = BASE_DIR / "data" / "processed" / "transcripts_limpos2Metric.csv"
19+
RAW_DB_PATH = BASE_DIR / "db" / "YouTubeStatsPipe2.sqlite3"
20+
OUTPUT_PATH = BASE_DIR / "data" / "processed" / "transcripts_limpos4ComMetric.csv"
2121

2222
# Configuração de memória - otimizada para 32GB RAM
2323
INITIAL_CHUNK_SIZE = 2000 # Aumentado de 500 para 2000
@@ -238,7 +238,7 @@ def preprocess_text_batch(texts, batch_size: int = 64, n_process: int = N_PROCES
238238
# ------------------------------------------------------------
239239
# Pipeline
240240
# ------------------------------------------------------------
241-
def process_chunk(chunk, start_date, end_date):
241+
def process_chunk(chunk):
242242
"""Processa um chunk de dados."""
243243
# Converte 'publishedAt' para datetime, tratando erros
244244
chunk['publishedAt'] = pd.to_datetime(chunk['publishedAt'], errors='coerce')
@@ -249,41 +249,37 @@ def process_chunk(chunk, start_date, end_date):
249249
if metric in chunk.columns:
250250
chunk[metric] = pd.to_numeric(chunk[metric], errors='coerce')
251251

252-
# Filtra o DataFrame para o período desejado
253-
mask = (chunk['publishedAt'] >= start_date) & (chunk['publishedAt'] < end_date)
254-
df_filtrado = chunk[mask].copy()
255-
256-
if len(df_filtrado) == 0:
252+
if len(chunk) == 0:
257253
return None
258254

259-
print(f"Processando chunk com {len(df_filtrado)} registros...")
255+
print(f"Processando chunk com {len(chunk)} registros...")
260256

261257
# Lista as colunas presentes para verificação
262-
print(f"Colunas disponíveis: {df_filtrado.columns.tolist()}")
258+
print(f"Colunas disponíveis: {chunk.columns.tolist()}")
263259

264260
# Verifica se as métricas de engajamento estão presentes
265-
metrics_present = [metric for metric in engagement_metrics if metric in df_filtrado.columns]
261+
metrics_present = [metric for metric in engagement_metrics if metric in chunk.columns]
266262
if metrics_present:
267263
print(f"Métricas de engajamento incluídas: {metrics_present}")
268264
else:
269265
print("AVISO: Nenhuma métrica de engajamento encontrada nos dados.")
270266

271267
# Mais otimizações para usar mais memória disponível
272-
df_filtrado["cleanTranscript"] = preprocess_text_batch(
273-
df_filtrado["videoTranscript"].tolist(),
268+
chunk["cleanTranscript"] = preprocess_text_batch(
269+
chunk["videoTranscript"].tolist(),
274270
batch_size=64,
275271
n_process=N_PROCESS,
276272
show_progress=True
277273
)
278274

279275
# Remove a coluna videoTranscript para economizar espaço
280-
df_filtrado = df_filtrado.drop(columns=['videoTranscript'])
276+
chunk = chunk.drop(columns=['videoTranscript'])
281277

282278
# Garantir que valores nulos nas métricas sejam substituídos por zeros
283279
for metric in metrics_present:
284-
df_filtrado[metric] = df_filtrado[metric].fillna(0).astype(int)
280+
chunk[metric] = chunk[metric].fillna(0).astype(int)
285281

286-
return df_filtrado
282+
return chunk
287283

288284
def main():
289285
# Add global declaration for CHUNK_SIZE
@@ -353,22 +349,33 @@ def main():
353349
print(f"Reduzindo para {CHUNK_SIZE} registros por chunk.")
354350
continue # Tente novamente com chunk menor
355351

356-
processed_chunk = process_chunk(chunk, start_date, end_date)
352+
processed_chunk = process_chunk(chunk)
357353

358354
# Liberar memória do chunk original imediatamente
359355
del chunk
360356
gc.collect()
361357

362358
if processed_chunk is not None and len(processed_chunk) > 0:
363-
# Verificar e informar métricas disponíveis
359+
# Filtra o DataFrame para o período desejado APÓS o processamento
360+
mask = (processed_chunk['publishedAt'] >= start_date) & (processed_chunk['publishedAt'] < end_date)
361+
df_filtrado = processed_chunk[mask].copy()
362+
363+
if len(df_filtrado) == 0:
364+
print("Nenhum registro no período para este chunk.")
365+
del processed_chunk
366+
del df_filtrado
367+
gc.collect()
368+
offset += CHUNK_SIZE
369+
continue
370+
364371
engagement_metrics = ['viewCount', 'likeCount', 'commentCount']
365-
metrics_present = [metric for metric in engagement_metrics if metric in processed_chunk.columns]
372+
metrics_present = [metric for metric in engagement_metrics if metric in df_filtrado.columns]
366373

367374
if metrics_present:
368375
print(f"Exportando com métricas de engajamento: {metrics_present}")
369376
# Mostrar estatísticas básicas
370377
for metric in metrics_present:
371-
print(f" - {metric}: média = {processed_chunk[metric].mean():.1f}, máx = {processed_chunk[metric].max()}")
378+
print(f" - {metric}: média = {df_filtrado[metric].mean():.1f}, máx = {df_filtrado[metric].max()}")
372379
else:
373380
print("AVISO: Nenhuma métrica de engajamento será exportada.")
374381

@@ -377,9 +384,9 @@ def main():
377384
header = first_chunk
378385

379386
# Escrever em pedaços maiores para economizar operações de I/O
380-
write_chunk_size = min(500, len(processed_chunk)) # Aumentado de 100 para 500
381-
for i in range(0, len(processed_chunk), write_chunk_size):
382-
sub_df = processed_chunk.iloc[i:i+write_chunk_size]
387+
write_chunk_size = min(500, len(df_filtrado)) # Aumentado de 100 para 500
388+
for i in range(0, len(df_filtrado), write_chunk_size):
389+
sub_df = df_filtrado.iloc[i:i+write_chunk_size]
383390
sub_df.to_csv(
384391
OUTPUT_PATH,
385392
index=False,
@@ -395,14 +402,16 @@ def main():
395402
if first_chunk:
396403
first_chunk = False
397404

398-
total_processed += len(processed_chunk)
399-
print(f"Salvos {len(processed_chunk)} registros no arquivo. Total: {total_processed}")
405+
total_processed += len(df_filtrado)
406+
print(f"Salvos {len(df_filtrado)} registros no arquivo. Total: {total_processed}")
400407

401408
chunks_processed += 1
402409
offset += CHUNK_SIZE
403410

404411
# Liberar memória do chunk processado explicitamente
405412
del processed_chunk
413+
if 'df_filtrado' in locals():
414+
del df_filtrado
406415
gc.collect()
407416

408417
# Verificar uso de memória e ajustar o tamanho do chunk se necessário

pipeline/getDataFromSQLite.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import sqlite3
2+
import csv
3+
import re
4+
from pathlib import Path
5+
import spacy
6+
7+
BASE_DIR = Path(__file__).resolve().parent.parent
8+
RAW_DB_PATH = BASE_DIR / "db" / "YouTubeStatsPipe2.sqlite3"
9+
OUTPUT_PATH = BASE_DIR / "data" / "processed" / "transcripts_limpos5ComMetric.csv"
10+
11+
# Carrega o modelo spaCy para português
12+
nlp = spacy.load("pt_core_news_sm")
13+
14+
def clean_transcript(text):
15+
if not text:
16+
return ""
17+
# Remove timestamps (format: [00:00], [12:34], [1:23:45], etc.)
18+
text = re.sub(r'\[\d{1,2}:\d{2}(?::\d{2})?\]', '', text)
19+
# Remove outros formatos de timestamp (ex: 00:00, 0:00:00, etc.)
20+
text = re.sub(r'\b\d{1,2}:\d{2}(?::\d{2})?\b', '', text)
21+
# Remove line breaks
22+
text = text.replace('\n', ' ').replace('\r', ' ')
23+
# Remove extra spaces
24+
text = re.sub(r'\s+', ' ', text).strip()
25+
# Limpeza e normalização com spaCy
26+
doc = nlp(text)
27+
# Mantém apenas tokens alfabéticos, lematizados e não stopwords
28+
cleaned = " ".join([token.lemma_ for token in doc if token.is_alpha and not token.is_stop])
29+
return cleaned
30+
31+
def export_videos_to_csv():
32+
conn = sqlite3.connect(RAW_DB_PATH)
33+
cursor = conn.cursor()
34+
query = """
35+
SELECT
36+
videoId,
37+
channelId,
38+
videoTitle,
39+
videoTranscript,
40+
publishedAt,
41+
transcriptLanguage,
42+
viewCount,
43+
likeCount,
44+
commentCount
45+
FROM Videos
46+
WHERE publishedAt >= '2022-10-31 00:00:00'
47+
AND publishedAt < '2023-04-01 00:00:00'
48+
"""
49+
cursor.execute(query)
50+
rows = cursor.fetchall()
51+
headers = [desc[0] for desc in cursor.description]
52+
53+
# Clean transcripts
54+
cleaned_rows = []
55+
for row in rows:
56+
row = list(row)
57+
# videoTranscript is at index 3
58+
row[3] = clean_transcript(row[3])
59+
cleaned_rows.append(row)
60+
61+
OUTPUT_PATH.parent.mkdir(parents=True, exist_ok=True)
62+
with open(OUTPUT_PATH, "w", newline='', encoding='utf-8') as f:
63+
writer = csv.writer(f)
64+
writer.writerow(headers)
65+
writer.writerows(cleaned_rows)
66+
67+
conn.close()
68+
69+
if __name__ == "__main__":
70+
export_videos_to_csv()
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Bigrama Frequência
2+
forças armadas 951
3+
todo mundo 869
4+
presidente bolsonaro 864
5+
alexandre moraes 582
6+
certo então 575
7+
artigo 142 489
8+
vou mostrar 464
9+
daqui pouco 445
10+
mil pessoas 417
11+
alguma coisa 365
12+
vamos vamos 360
13+
porta quartel 347
14+
boa noite 332
15+
esqueça dar 326
16+
tamo junto 323
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Bigrama Frequência
2+
quebra quebra 7
3+
trabalho jornalístico 5
4+
todo mundo 5
5+
qualquer tipo 4
6+
pingos is 3
7+
nada disso 3
8+
certo então 3
9+
tava acontecendo 3
10+
velha mídia 3
11+
volto repetir 3
12+
hora dessas 3
13+
então vamos 2
14+
então tô 2
15+
beijo coração 2
16+
coração cada 2
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Bigrama Frequência
2+
nesse vídeo 62
3+
deixa comentários 45
4+
presidente bolsonaro 40
5+
todo mundo 29
6+
aplausos aplausos 27
7+
forças armadas 27
8+
vou mostrar 21
9+
olha vídeo 19
10+
ontem noite 16
11+
boa tarde 16
12+
vídeo deixa 15
13+
olhadinha nesse 14
14+
vídeo vai 14
15+
comentários achou 14
16+
vai agora 14
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Bigrama Frequência
2+
presidente bolsonaro 2
3+
fala certeza 1
4+
certeza conhecem 1
5+
conhecem senadora 1
6+
senadora soraia 1
7+
soraia tronic 1
8+
tronic traiu 1
9+
traiu presidente 1
10+
bolsonaro candidata 1
11+
candidata presidenta 1
12+
presidenta contra 1
13+
contra próprio 1
14+
próprio presidente 1
15+
presidente mulherzinha 1
16+
mulherzinha mostrou 1

0 commit comments

Comments
 (0)