Spaces:
Sleeping
Sleeping
Tool extração audio
Browse files- .gitignore +2 -0
- tool_audio_extractor.py +52 -79
.gitignore
CHANGED
@@ -2,3 +2,5 @@
|
|
2 |
*.xlsx
|
3 |
video_analysis_output/
|
4 |
get-pip.py
|
|
|
|
|
|
2 |
*.xlsx
|
3 |
video_analysis_output/
|
4 |
get-pip.py
|
5 |
+
*.m4a
|
6 |
+
*.mp4
|
tool_audio_extractor.py
CHANGED
@@ -10,13 +10,15 @@ import base64
|
|
10 |
import time
|
11 |
import json
|
12 |
import re
|
|
|
13 |
|
14 |
# --- Configurações (Substitua os placeholders) ---
|
15 |
-
VIDEO_URL = "https://www.youtube.com/watch?v=
|
16 |
-
|
17 |
-
OUTPUT_DIR = "./video_analysis_output" # Diretório para salvar o vídeo e os frames
|
18 |
AUDIO_FILENAME = "downloaded_audio"
|
19 |
-
|
|
|
|
|
20 |
|
21 |
# Verifica se a URL foi definida
|
22 |
if VIDEO_URL == "URL_DO_SEU_VIDEO_AQUI":
|
@@ -47,14 +49,15 @@ def download_audio(url, output_path):
|
|
47 |
print(f"Baixando áudio de {url} para {output_path}...")
|
48 |
try:
|
49 |
# Comando yt-dlp para baixar o melhor áudio disponível e convertê-lo para mp3
|
|
|
|
|
50 |
command = [
|
51 |
'yt-dlp',
|
52 |
-
'-f', 'bestaudio',
|
53 |
-
'--extract-audio',
|
54 |
-
'--audio-format', 'mp3', # Pode ser 'mp3', 'm4a', 'wav', etc.
|
55 |
'-o', output_path,
|
56 |
url
|
57 |
]
|
|
|
58 |
result = subprocess.run(command, check=True, capture_output=True, text=True)
|
59 |
retirar_sufixo_codec_arquivo(OUTPUT_DIR)
|
60 |
|
@@ -68,6 +71,37 @@ def download_audio(url, output_path):
|
|
68 |
print("Erro: O comando 'yt-dlp' não foi encontrado. Certifique-se de que ele está instalado e no PATH do sistema.")
|
69 |
return False
|
70 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
|
72 |
|
73 |
# --- Atualização do Bloco Principal ---
|
@@ -78,85 +112,24 @@ if __name__ == "__main__":
|
|
78 |
# Etapa 1: Baixar o vídeo
|
79 |
video_downloaded_or_exists = False
|
80 |
if VIDEO_URL != "URL_DO_SEU_VIDEO_AQUI":
|
81 |
-
if
|
82 |
-
print(f"Vídeo salvo em: {
|
83 |
video_downloaded_or_exists = True
|
84 |
else:
|
85 |
print("Falha no download do vídeo. Pulando etapas dependentes.")
|
86 |
-
elif os.path.exists(
|
87 |
-
print(f"URL não fornecida, mas vídeo encontrado em {
|
88 |
video_downloaded_or_exists = True
|
89 |
else:
|
90 |
print("URL do vídeo não fornecida e vídeo local não encontrado. Pulando download e extração.")
|
91 |
|
92 |
-
|
93 |
-
if video_downloaded_or_exists:
|
94 |
-
extracted_frames = extract_frames(VIDEO_PATH, OUTPUT_DIR, FRAME_INTERVAL_SECONDS)
|
95 |
-
else:
|
96 |
-
print("Pulando extração de frames pois o vídeo não está disponível.")
|
97 |
-
|
98 |
-
# Etapa 3 e 4: Codificar e Analisar Frames
|
99 |
-
if extracted_frames and openai_client:
|
100 |
-
print(f"\nIniciando análise de {len(extracted_frames)} frames com {GPT_MODEL}...")
|
101 |
-
for frame_path in extracted_frames:
|
102 |
-
print(f"\nProcessando frame: {frame_path}")
|
103 |
-
# Extrai timestamp do nome do arquivo, se possível
|
104 |
-
timestamp_str = "unknown"
|
105 |
-
try:
|
106 |
-
# Exemplo: frame_0000_time_0.00s.png
|
107 |
-
parts = os.path.basename(frame_path).split('_')
|
108 |
-
if len(parts) >= 4 and parts[2] == 'time':
|
109 |
-
timestamp_str = parts[3].replace('s.png','')
|
110 |
-
except Exception:
|
111 |
-
pass # Mantém 'unknown' se o parsing falhar
|
112 |
-
|
113 |
-
# Codifica o frame
|
114 |
-
base64_image = encode_frame_to_base64(frame_path)
|
115 |
-
|
116 |
-
if base64_image:
|
117 |
-
# Analisa o frame com GPT-4o
|
118 |
-
# analysis_result = analyze_frame_with_gpt4o(openai_client, base64_image, PROMPT_TEXT)
|
119 |
-
result_entry = {
|
120 |
-
"frame_path": frame_path,
|
121 |
-
"timestamp_approx_sec": timestamp_str,
|
122 |
-
"analysis": f' pulado frame {frame_path}' #analysis_result
|
123 |
-
}
|
124 |
-
analysis_results_list.append(result_entry)
|
125 |
-
|
126 |
-
# Pausa opcional para evitar rate limiting
|
127 |
-
time.sleep(1) # Pausa de 1 segundo entre as chamadas
|
128 |
-
else:
|
129 |
-
print(f"Falha ao codificar o frame {frame_path}. Pulando análise.")
|
130 |
-
analysis_results_list.append({
|
131 |
-
"frame_path": frame_path,
|
132 |
-
"timestamp_approx_sec": timestamp_str,
|
133 |
-
"analysis": {"error": "Failed to encode frame to base64."}
|
134 |
-
})
|
135 |
-
print("\nAnálise de todos os frames concluída.")
|
136 |
-
elif not extracted_frames:
|
137 |
-
print("Nenhum frame foi extraído. Pulando etapa de análise.")
|
138 |
-
elif not openai_client:
|
139 |
-
print("Cliente OpenAI não inicializado (verifique a API Key). Pulando etapa de análise.")
|
140 |
-
|
141 |
-
# Próxima etapa: Compilar resultados
|
142 |
-
print(f"\nPróxima etapa a ser implementada: Compilação dos resultados ({len(analysis_results_list)} análises) em um relatório.")
|
143 |
-
|
144 |
-
|
145 |
-
# ... (código anterior para inicialização, download, extração, análise) ...
|
146 |
-
|
147 |
-
# Etapa 5: Compilar e Salvar Resultados
|
148 |
-
if analysis_results_list:
|
149 |
-
print(f"\nCompilando {len(analysis_results_list)} resultados da análise...")
|
150 |
-
if save_results_to_json(analysis_results_list, RESULTS_FILE):
|
151 |
-
print("Compilação e salvamento dos resultados concluídos.")
|
152 |
-
else:
|
153 |
-
print("Falha ao salvar os resultados da análise.")
|
154 |
-
else:
|
155 |
-
print("Nenhum resultado de análise para compilar.")
|
156 |
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
|
|
161 |
|
|
|
162 |
|
|
|
10 |
import time
|
11 |
import json
|
12 |
import re
|
13 |
+
import openai
|
14 |
|
15 |
# --- Configurações (Substitua os placeholders) ---
|
16 |
+
VIDEO_URL = "https://www.youtube.com/watch?v=1htKBjuUWec" # Substitua pela URL do vídeo do YouTube
|
17 |
+
OUTPUT_DIR = "./audio_analysis_output" # Diretório para salvar o áudio
|
|
|
18 |
AUDIO_FILENAME = "downloaded_audio"
|
19 |
+
TRANSCRIPT_FILENAME = "transcript.txt"
|
20 |
+
AUDIO_PATH = os.path.join(OUTPUT_DIR, AUDIO_FILENAME)
|
21 |
+
TRANSCRIPT_PATH = os.path.join(OUTPUT_DIR, TRANSCRIPT_FILENAME)
|
22 |
|
23 |
# Verifica se a URL foi definida
|
24 |
if VIDEO_URL == "URL_DO_SEU_VIDEO_AQUI":
|
|
|
49 |
print(f"Baixando áudio de {url} para {output_path}...")
|
50 |
try:
|
51 |
# Comando yt-dlp para baixar o melhor áudio disponível e convertê-lo para mp3
|
52 |
+
|
53 |
+
|
54 |
command = [
|
55 |
'yt-dlp',
|
56 |
+
'-f', 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best',
|
|
|
|
|
57 |
'-o', output_path,
|
58 |
url
|
59 |
]
|
60 |
+
|
61 |
result = subprocess.run(command, check=True, capture_output=True, text=True)
|
62 |
retirar_sufixo_codec_arquivo(OUTPUT_DIR)
|
63 |
|
|
|
71 |
print("Erro: O comando 'yt-dlp' não foi encontrado. Certifique-se de que ele está instalado e no PATH do sistema.")
|
72 |
return False
|
73 |
|
74 |
+
def extract_text_from_audio(audio_path, output_txt_path=None) -> str:
|
75 |
+
"""
|
76 |
+
Usa a API Whisper da OpenAI para transcrever o áudio em texto com quebras de linha naturais,
|
77 |
+
removendo timestamps e IDs. Salva em arquivo .txt se o caminho for fornecido.
|
78 |
+
"""
|
79 |
+
try:
|
80 |
+
openai.api_key = os.getenv("OPENAI_API_KEY")
|
81 |
+
print(f"Iniciando transcrição (formato SRT simplificado): {audio_path}")
|
82 |
+
|
83 |
+
with open(audio_path, "rb") as audio_file:
|
84 |
+
srt_result = openai.Audio.transcribe(
|
85 |
+
model="whisper-1",
|
86 |
+
file=audio_file,
|
87 |
+
response_format="srt"
|
88 |
+
)
|
89 |
+
|
90 |
+
# Remove linhas com números e timestamps
|
91 |
+
lines = srt_result.splitlines()
|
92 |
+
only_text = [line.strip() for line in lines if not re.match(r"^\d+$", line) and "-->" not in line]
|
93 |
+
formatted_text = "\n".join(only_text)
|
94 |
+
|
95 |
+
# Salva em .txt se desejado
|
96 |
+
if output_txt_path:
|
97 |
+
with open(output_txt_path, "w", encoding="utf-8") as f:
|
98 |
+
f.write(formatted_text)
|
99 |
+
print(f"Transcrição salva em: {output_txt_path}")
|
100 |
+
|
101 |
+
return formatted_text
|
102 |
+
except Exception as e:
|
103 |
+
print(f"Erro ao transcrever áudio: {e}")
|
104 |
+
return ""
|
105 |
|
106 |
|
107 |
# --- Atualização do Bloco Principal ---
|
|
|
112 |
# Etapa 1: Baixar o vídeo
|
113 |
video_downloaded_or_exists = False
|
114 |
if VIDEO_URL != "URL_DO_SEU_VIDEO_AQUI":
|
115 |
+
if download_audio(VIDEO_URL, AUDIO_PATH):
|
116 |
+
print(f"Vídeo salvo em: {AUDIO_PATH}")
|
117 |
video_downloaded_or_exists = True
|
118 |
else:
|
119 |
print("Falha no download do vídeo. Pulando etapas dependentes.")
|
120 |
+
elif os.path.exists(AUDIO_PATH):
|
121 |
+
print(f"URL não fornecida, mas vídeo encontrado em {AUDIO_PATH}. Tentando processar.")
|
122 |
video_downloaded_or_exists = True
|
123 |
else:
|
124 |
print("URL do vídeo não fornecida e vídeo local não encontrado. Pulando download e extração.")
|
125 |
|
126 |
+
if False:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
127 |
|
128 |
+
# Etapa 2: Extrair frames
|
129 |
+
if video_downloaded_or_exists:
|
130 |
+
extract_text_from_audio(AUDIO_PATH + '.mp3', TRANSCRIPT_PATH)
|
131 |
+
else:
|
132 |
+
print("Pulando extração de frames pois o vídeo não está disponível.")
|
133 |
|
134 |
+
|
135 |
|