Spaces:
Runtime error
Runtime error
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 |
|