Marcus Vinicius Zerbini Canhaço
commited on
Commit
·
739fe61
1
Parent(s):
37eeee3
feat: atualização do detector com otimizações para GPU T4
Browse files- .env.huggingface +13 -2
- src/presentation/web/gradio_interface.py +73 -45
.env.huggingface
CHANGED
@@ -15,7 +15,8 @@ RESULT_CACHE_SIZE=1000
|
|
15 |
|
16 |
# Configurações de E-mail
|
17 |
NOTIFICATION_EMAIL="" # Configure no Hugging Face Space
|
18 |
-
SENDGRID_API_KEY=
|
|
|
19 |
|
20 |
# Configurações do Servidor
|
21 |
SERVER_HOST=0.0.0.0
|
@@ -30,4 +31,14 @@ DEFAULT_RESOLUTION=640
|
|
30 |
CUDA_VISIBLE_DEVICES=0
|
31 |
TORCH_CUDA_ARCH_LIST="7.5"
|
32 |
NVIDIA_VISIBLE_DEVICES=all
|
33 |
-
NVIDIA_DRIVER_CAPABILITIES=compute,utility
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
|
16 |
# Configurações de E-mail
|
17 |
NOTIFICATION_EMAIL="" # Configure no Hugging Face Space
|
18 |
+
SENDGRID_API_KEY=xxx
|
19 |
+
EMAIL_FROM=xxx@xxx.com
|
20 |
|
21 |
# Configurações do Servidor
|
22 |
SERVER_HOST=0.0.0.0
|
|
|
31 |
CUDA_VISIBLE_DEVICES=0
|
32 |
TORCH_CUDA_ARCH_LIST="7.5"
|
33 |
NVIDIA_VISIBLE_DEVICES=all
|
34 |
+
NVIDIA_DRIVER_CAPABILITIES=compute,utility
|
35 |
+
|
36 |
+
# Configurações do Hugging Face
|
37 |
+
HF_TOKEN=hf_xxx # Substitua com seu token real
|
38 |
+
|
39 |
+
# Configurações do Telegram
|
40 |
+
TELEGRAM_BOT_TOKEN=xxx
|
41 |
+
TELEGRAM_CHAT_ID=xxx
|
42 |
+
|
43 |
+
# Configurações do Discord
|
44 |
+
DISCORD_WEBHOOK_URL=xxx
|
src/presentation/web/gradio_interface.py
CHANGED
@@ -6,7 +6,8 @@ from src.application.use_cases.process_video import ProcessVideoUseCase, Process
|
|
6 |
from src.infrastructure.services.weapon_detector import WeaponDetectorService
|
7 |
from src.infrastructure.services.notification_services import NotificationServiceFactory
|
8 |
import logging
|
9 |
-
import
|
|
|
10 |
|
11 |
logger = logging.getLogger(__name__)
|
12 |
|
@@ -20,29 +21,31 @@ class GradioInterface:
|
|
20 |
self.default_resolution = "640" if self.detector.device_type == "GPU" else "480"
|
21 |
self.is_huggingface = os.getenv('SPACE_ID') is not None
|
22 |
|
23 |
-
#
|
24 |
-
self.
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
|
|
|
|
46 |
|
47 |
self.use_case = ProcessVideoUseCase(
|
48 |
detector=self.detector,
|
@@ -51,12 +54,38 @@ class GradioInterface:
|
|
51 |
default_resolution=int(self.default_resolution)
|
52 |
)
|
53 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
def list_sample_videos(self) -> list:
|
55 |
"""Lista os vídeos de exemplo do dataset ou da pasta local."""
|
56 |
try:
|
57 |
if self.is_huggingface:
|
58 |
-
logger.info("Ambiente Hugging Face detectado
|
59 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
else:
|
61 |
logger.info("Ambiente local detectado, usando pasta videos")
|
62 |
video_extensions = ['.mp4', '.avi', '.mov', '.mkv']
|
@@ -66,12 +95,10 @@ class GradioInterface:
|
|
66 |
os.makedirs(base_dir)
|
67 |
logger.info(f"Diretório videos criado: {base_dir}")
|
68 |
|
69 |
-
# Listar vídeos locais
|
70 |
for ext in video_extensions:
|
71 |
-
for video_path in base_dir.glob(f'
|
72 |
-
logger.info(f"Vídeo local encontrado: {video_path}")
|
73 |
videos.append({
|
74 |
-
'
|
75 |
'name': video_path.name,
|
76 |
'ground_truth': '📼 Vídeo de Teste'
|
77 |
})
|
@@ -82,20 +109,17 @@ class GradioInterface:
|
|
82 |
logger.error(f"Erro ao listar vídeos: {str(e)}")
|
83 |
return []
|
84 |
|
85 |
-
def load_sample_video(self,
|
86 |
-
"""Carrega um vídeo de exemplo
|
87 |
try:
|
88 |
-
if not
|
89 |
return ""
|
|
|
|
|
|
|
|
|
90 |
|
91 |
-
|
92 |
-
logger.info(f"Carregando vídeo da URL: {video_url}")
|
93 |
-
return video_url
|
94 |
-
elif os.path.exists(video_url):
|
95 |
-
logger.info(f"Carregando vídeo local: {video_url}")
|
96 |
-
return video_url
|
97 |
-
|
98 |
-
logger.warning(f"Vídeo não encontrado: {video_url}")
|
99 |
return ""
|
100 |
except Exception as e:
|
101 |
logger.error(f"Erro ao carregar vídeo: {str(e)}")
|
@@ -202,28 +226,32 @@ class GradioInterface:
|
|
202 |
with gr.Group():
|
203 |
gr.Markdown("### Vídeos de Exemplo")
|
204 |
with gr.Row():
|
205 |
-
with gr.Column(scale=
|
206 |
gr.Markdown("#### Vídeo")
|
|
|
|
|
207 |
with gr.Column(scale=1):
|
208 |
gr.Markdown("#### Ação")
|
209 |
|
210 |
for video in sample_videos:
|
211 |
with gr.Row():
|
212 |
-
with gr.Column(scale=
|
213 |
gr.Video(
|
214 |
-
value=video['
|
215 |
format="mp4",
|
216 |
height=150,
|
217 |
interactive=False,
|
218 |
show_label=False
|
219 |
)
|
|
|
|
|
220 |
with gr.Column(scale=1, min_width=100):
|
221 |
gr.Button(
|
222 |
"📥 Carregar",
|
223 |
size="sm"
|
224 |
).click(
|
225 |
fn=self.load_sample_video,
|
226 |
-
inputs=[gr.State(video['
|
227 |
outputs=[input_video]
|
228 |
)
|
229 |
|
|
|
6 |
from src.infrastructure.services.weapon_detector import WeaponDetectorService
|
7 |
from src.infrastructure.services.notification_services import NotificationServiceFactory
|
8 |
import logging
|
9 |
+
from huggingface_hub import hf_hub_download, HfApi
|
10 |
+
import tempfile
|
11 |
|
12 |
logger = logging.getLogger(__name__)
|
13 |
|
|
|
21 |
self.default_resolution = "640" if self.detector.device_type == "GPU" else "480"
|
22 |
self.is_huggingface = os.getenv('SPACE_ID') is not None
|
23 |
|
24 |
+
# Configurar dataset apenas no ambiente Hugging Face
|
25 |
+
if self.is_huggingface:
|
26 |
+
self.dataset_id = "marcuscanhaco/weapon-test"
|
27 |
+
self.cache_dir = os.path.join(tempfile.gettempdir(), 'weapon_detection_videos')
|
28 |
+
os.makedirs(self.cache_dir, exist_ok=True)
|
29 |
+
|
30 |
+
# Configurar API do Hugging Face
|
31 |
+
self.hf_token = os.getenv('HF_TOKEN')
|
32 |
+
self.api = HfApi(token=self.hf_token)
|
33 |
+
|
34 |
+
# Listar arquivos do dataset
|
35 |
+
try:
|
36 |
+
files = self.api.list_repo_files(self.dataset_id, repo_type="dataset")
|
37 |
+
self.sample_videos = [
|
38 |
+
{
|
39 |
+
'path': f,
|
40 |
+
'name': Path(f).stem.replace('_', ' ').title(),
|
41 |
+
'ground_truth': '🚨 Vídeo de Teste'
|
42 |
+
}
|
43 |
+
for f in files if f.lower().endswith(('.mp4', '.avi', '.mov', '.mkv'))
|
44 |
+
]
|
45 |
+
logger.info(f"Encontrados {len(self.sample_videos)} vídeos no dataset")
|
46 |
+
except Exception as e:
|
47 |
+
logger.error(f"Erro ao listar arquivos do dataset: {str(e)}")
|
48 |
+
self.sample_videos = []
|
49 |
|
50 |
self.use_case = ProcessVideoUseCase(
|
51 |
detector=self.detector,
|
|
|
54 |
default_resolution=int(self.default_resolution)
|
55 |
)
|
56 |
|
57 |
+
def _download_video(self, video_path: str) -> str:
|
58 |
+
"""Baixa um vídeo do dataset e retorna o caminho local."""
|
59 |
+
try:
|
60 |
+
local_path = hf_hub_download(
|
61 |
+
repo_id=self.dataset_id,
|
62 |
+
filename=video_path,
|
63 |
+
repo_type="dataset",
|
64 |
+
local_dir=self.cache_dir,
|
65 |
+
token=self.hf_token,
|
66 |
+
local_dir_use_symlinks=False
|
67 |
+
)
|
68 |
+
logger.info(f"Vídeo baixado com sucesso: {local_path}")
|
69 |
+
return local_path
|
70 |
+
except Exception as e:
|
71 |
+
logger.error(f"Erro ao baixar vídeo {video_path}: {str(e)}")
|
72 |
+
return ""
|
73 |
+
|
74 |
def list_sample_videos(self) -> list:
|
75 |
"""Lista os vídeos de exemplo do dataset ou da pasta local."""
|
76 |
try:
|
77 |
if self.is_huggingface:
|
78 |
+
logger.info("Ambiente Hugging Face detectado")
|
79 |
+
videos = []
|
80 |
+
for video in self.sample_videos:
|
81 |
+
local_path = self._download_video(video['path'])
|
82 |
+
if local_path:
|
83 |
+
videos.append({
|
84 |
+
'path': local_path,
|
85 |
+
'name': video['name'],
|
86 |
+
'ground_truth': video['ground_truth']
|
87 |
+
})
|
88 |
+
return videos
|
89 |
else:
|
90 |
logger.info("Ambiente local detectado, usando pasta videos")
|
91 |
video_extensions = ['.mp4', '.avi', '.mov', '.mkv']
|
|
|
95 |
os.makedirs(base_dir)
|
96 |
logger.info(f"Diretório videos criado: {base_dir}")
|
97 |
|
|
|
98 |
for ext in video_extensions:
|
99 |
+
for video_path in base_dir.glob(f'*{ext}'): # Removido o glob recursivo
|
|
|
100 |
videos.append({
|
101 |
+
'path': str(video_path),
|
102 |
'name': video_path.name,
|
103 |
'ground_truth': '📼 Vídeo de Teste'
|
104 |
})
|
|
|
109 |
logger.error(f"Erro ao listar vídeos: {str(e)}")
|
110 |
return []
|
111 |
|
112 |
+
def load_sample_video(self, video_path: str) -> str:
|
113 |
+
"""Carrega um vídeo de exemplo."""
|
114 |
try:
|
115 |
+
if not video_path:
|
116 |
return ""
|
117 |
+
|
118 |
+
if os.path.exists(video_path):
|
119 |
+
logger.info(f"Carregando vídeo: {video_path}")
|
120 |
+
return video_path
|
121 |
|
122 |
+
logger.warning(f"Vídeo não encontrado: {video_path}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
123 |
return ""
|
124 |
except Exception as e:
|
125 |
logger.error(f"Erro ao carregar vídeo: {str(e)}")
|
|
|
226 |
with gr.Group():
|
227 |
gr.Markdown("### Vídeos de Exemplo")
|
228 |
with gr.Row():
|
229 |
+
with gr.Column(scale=3):
|
230 |
gr.Markdown("#### Vídeo")
|
231 |
+
with gr.Column(scale=1):
|
232 |
+
gr.Markdown("#### Tipo")
|
233 |
with gr.Column(scale=1):
|
234 |
gr.Markdown("#### Ação")
|
235 |
|
236 |
for video in sample_videos:
|
237 |
with gr.Row():
|
238 |
+
with gr.Column(scale=3):
|
239 |
gr.Video(
|
240 |
+
value=video['path'],
|
241 |
format="mp4",
|
242 |
height=150,
|
243 |
interactive=False,
|
244 |
show_label=False
|
245 |
)
|
246 |
+
with gr.Column(scale=1):
|
247 |
+
gr.Markdown(video['ground_truth'])
|
248 |
with gr.Column(scale=1, min_width=100):
|
249 |
gr.Button(
|
250 |
"📥 Carregar",
|
251 |
size="sm"
|
252 |
).click(
|
253 |
fn=self.load_sample_video,
|
254 |
+
inputs=[gr.State(video['path'])],
|
255 |
outputs=[input_video]
|
256 |
)
|
257 |
|