Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -10,15 +10,10 @@ import os
|
|
10 |
import gc
|
11 |
from typing import Dict, Any, Optional, List, Tuple
|
12 |
import psutil
|
13 |
-
import threading
|
14 |
-
import concurrent.futures
|
15 |
from contextlib import contextmanager
|
16 |
-
import numpy as np
|
17 |
|
18 |
-
# -------- CONFIGURAÇÕES AVANÇADAS DE OTIMIZAÇÃO --------
|
19 |
-
# Configuração de CPU baseada no hardware disponível
|
20 |
num_cores = psutil.cpu_count(logical=False)
|
21 |
-
num_threads = min(4, num_cores)
|
22 |
|
23 |
os.environ["TOKENIZERS_PARALLELISM"] = "false"
|
24 |
os.environ["OMP_NUM_THREADS"] = str(num_threads)
|
@@ -29,53 +24,36 @@ os.environ["NUMEXPR_NUM_THREADS"] = str(num_threads)
|
|
29 |
|
30 |
torch.set_num_threads(num_threads)
|
31 |
torch.set_num_interop_threads(1)
|
32 |
-
|
33 |
-
# Configurações avançadas para otimização
|
34 |
torch.backends.mkl.enabled = True
|
35 |
torch.backends.mkldnn.enabled = True
|
36 |
torch.backends.quantized.engine = 'qnnpack'
|
|
|
37 |
|
38 |
-
# Configuração de flushing para memória
|
39 |
-
torch.cuda.empty_cache = lambda: None # Evita chamadas desnecessárias
|
40 |
-
|
41 |
-
# -------- LOGGING CONFIG --------
|
42 |
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
|
43 |
log = logging.getLogger("news-filter-optimized")
|
44 |
|
45 |
-
# Configuração global para usar CPU
|
46 |
device = "cpu"
|
47 |
torch.set_default_device(device)
|
48 |
|
49 |
-
# -------- OTIMIZAÇÕES DE MEMÓRIA --------
|
50 |
@contextmanager
|
51 |
def memory_efficient_context():
|
52 |
-
"""Context manager para otimizar uso de memória durante inferência"""
|
53 |
try:
|
54 |
-
# Força garbage collection antes da operação
|
55 |
gc.collect()
|
56 |
yield
|
57 |
finally:
|
58 |
-
# Limpa memória após a operação
|
59 |
gc.collect()
|
60 |
|
61 |
class OptimizedTokenizerWrapper:
|
62 |
-
"""Wrapper otimizado para tokenizer com cache de operações comuns"""
|
63 |
-
|
64 |
def __init__(self, tokenizer):
|
65 |
self.tokenizer = tokenizer
|
66 |
-
self._encode_cache = {}
|
67 |
-
self._decode_cache = {}
|
68 |
self._template_cache = {}
|
69 |
|
70 |
def apply_chat_template(self, messages, **kwargs):
|
71 |
-
"""Versão otimizada do chat template com cache"""
|
72 |
-
# Cria key baseada no conteúdo da mensagem
|
73 |
content = messages[0]['content'] if messages else ""
|
74 |
-
key = hash(content[:100])
|
75 |
|
76 |
if key not in self._template_cache:
|
77 |
result = self.tokenizer.apply_chat_template(messages, **kwargs)
|
78 |
-
# Limita cache a 100 entradas
|
79 |
if len(self._template_cache) > 100:
|
80 |
self._template_cache.clear()
|
81 |
self._template_cache[key] = result
|
@@ -83,91 +61,80 @@ class OptimizedTokenizerWrapper:
|
|
83 |
return self._template_cache[key]
|
84 |
|
85 |
def decode(self, *args, **kwargs):
|
86 |
-
"""Versão otimizada do decode"""
|
87 |
return self.tokenizer.decode(*args, **kwargs)
|
88 |
|
89 |
def __getattr__(self, name):
|
90 |
-
"""Proxy para outros métodos do tokenizer"""
|
91 |
return getattr(self.tokenizer, name)
|
92 |
|
93 |
-
|
94 |
-
|
95 |
-
log.info("🚀 Carregando modelo e tokenizer com otimizações avançadas...")
|
96 |
|
97 |
-
# Configurações de otimização para carregamento do modelo
|
98 |
model_config = {
|
99 |
"device_map": device,
|
100 |
-
"torch_dtype": torch.float16,
|
101 |
"low_cpu_mem_usage": True,
|
102 |
"use_cache": True,
|
103 |
"trust_remote_code": True,
|
104 |
-
"attn_implementation": "eager",
|
105 |
}
|
106 |
|
107 |
-
# Carrega modelo com configurações otimizadas
|
108 |
model = AutoPeftModelForCausalLM.from_pretrained(
|
109 |
"habulaj/filterinstruct180",
|
110 |
**model_config
|
111 |
)
|
112 |
|
113 |
-
# Configuração otimizada do tokenizer
|
114 |
tokenizer = AutoTokenizer.from_pretrained(
|
115 |
"habulaj/filterinstruct180",
|
116 |
use_fast=True,
|
117 |
padding_side="left",
|
118 |
-
model_max_length=1024,
|
119 |
-
clean_up_tokenization_spaces=False,
|
120 |
)
|
121 |
|
122 |
-
# Otimizações de tokenizer
|
123 |
if tokenizer.pad_token is None:
|
124 |
tokenizer.pad_token = tokenizer.eos_token
|
125 |
|
126 |
-
# Wrapper otimizado para tokenizer
|
127 |
tokenizer = OptimizedTokenizerWrapper(tokenizer)
|
128 |
|
129 |
-
# -------- OTIMIZAÇÕES DE MODELO --------
|
130 |
-
# Modo de avaliação com otimizações
|
131 |
model.eval()
|
132 |
-
|
133 |
-
# Otimizações específicas para inferência
|
134 |
for param in model.parameters():
|
135 |
param.requires_grad = False
|
136 |
|
137 |
-
# Compila o modelo para otimização (se disponível)
|
138 |
try:
|
139 |
model = torch.compile(model, mode="reduce-overhead")
|
140 |
-
log.info("✅ Modelo compilado
|
141 |
except Exception as e:
|
142 |
log.warning(f"⚠️ Torch compile não disponível: {e}")
|
143 |
|
144 |
-
# Otimização de fusão de operações
|
145 |
if hasattr(model, 'fuse_linear_layers'):
|
146 |
model.fuse_linear_layers()
|
147 |
|
148 |
-
log.info("✅ Modelo carregado
|
|
|
|
|
|
|
|
|
149 |
|
150 |
-
|
151 |
-
|
152 |
-
|
|
|
|
|
153 |
|
154 |
-
# Configuração otimizada de geração
|
155 |
generation_config = GenerationConfig(
|
156 |
-
max_new_tokens=150,
|
157 |
-
temperature=0.8,
|
158 |
-
do_sample=False,
|
159 |
use_cache=True,
|
160 |
eos_token_id=tokenizer.eos_token_id,
|
161 |
pad_token_id=tokenizer.eos_token_id,
|
162 |
repetition_penalty=1.1,
|
163 |
length_penalty=1.0,
|
164 |
-
num_beams=1,
|
165 |
early_stopping=True,
|
166 |
)
|
167 |
|
168 |
-
# -------- FUNÇÕES OTIMIZADAS --------
|
169 |
def extract_json_optimized(text: str) -> str:
|
170 |
-
"""Extração otimizada de JSON com regex compilado"""
|
171 |
if not hasattr(extract_json_optimized, 'pattern'):
|
172 |
extract_json_optimized.pattern = re.compile(r'\{.*?\}', re.DOTALL)
|
173 |
|
@@ -175,8 +142,6 @@ def extract_json_optimized(text: str) -> str:
|
|
175 |
return match.group(0) if match else text
|
176 |
|
177 |
def preprocess_input_optimized(title: str, content: str) -> List[Dict[str, str]]:
|
178 |
-
"""Preprocessamento otimizado de entrada"""
|
179 |
-
# Trunca entradas muito longas para acelerar processamento
|
180 |
max_title_length = 100
|
181 |
max_content_length = 500
|
182 |
|
@@ -195,26 +160,22 @@ Content: "{content}"
|
|
195 |
}]
|
196 |
|
197 |
def analyze_news_optimized(title: str, content: str) -> str:
|
198 |
-
"""Versão ultra-otimizada da análise de notícias"""
|
199 |
try:
|
200 |
with memory_efficient_context():
|
201 |
start_time = time.time()
|
202 |
|
203 |
-
# Prepara entrada otimizada
|
204 |
messages = preprocess_input_optimized(title, content)
|
205 |
|
206 |
-
# Tokenização otimizada
|
207 |
inputs = tokenizer.apply_chat_template(
|
208 |
messages,
|
209 |
tokenize=True,
|
210 |
add_generation_prompt=True,
|
211 |
return_tensors="pt",
|
212 |
-
padding=False,
|
213 |
truncation=True,
|
214 |
max_length=1024,
|
215 |
)
|
216 |
|
217 |
-
# Inferência otimizada com múltiplas optimizações
|
218 |
with torch.no_grad(), torch.inference_mode():
|
219 |
with torch.autocast(device_type='cpu', dtype=torch.float16):
|
220 |
outputs = model.generate(
|
@@ -226,10 +187,9 @@ def analyze_news_optimized(title: str, content: str) -> str:
|
|
226 |
output_attentions=False,
|
227 |
return_dict_in_generate=False,
|
228 |
use_cache=True,
|
229 |
-
do_sample=False,
|
230 |
)
|
231 |
|
232 |
-
# Decodificação otimizada
|
233 |
generated_tokens = outputs[0][inputs.shape[1]:]
|
234 |
generated_text = tokenizer.decode(
|
235 |
generated_tokens,
|
@@ -237,17 +197,13 @@ def analyze_news_optimized(title: str, content: str) -> str:
|
|
237 |
clean_up_tokenization_spaces=False
|
238 |
)
|
239 |
|
240 |
-
# Extração otimizada de JSON
|
241 |
json_result = extract_json_optimized(generated_text)
|
242 |
|
243 |
-
# Logging de performance
|
244 |
duration = time.time() - start_time
|
245 |
log.info(f"✅ Análise concluída em {duration:.2f}s")
|
246 |
|
247 |
-
# Limpeza de memória otimizada
|
248 |
del outputs, inputs, generated_tokens
|
249 |
|
250 |
-
# Validação de JSON otimizada
|
251 |
try:
|
252 |
parsed_json = json.loads(json_result)
|
253 |
return json.dumps(parsed_json, indent=2, ensure_ascii=False)
|
@@ -258,26 +214,19 @@ def analyze_news_optimized(title: str, content: str) -> str:
|
|
258 |
log.exception("❌ Erro durante análise:")
|
259 |
return f"Erro durante a análise: {str(e)}"
|
260 |
|
261 |
-
# -------- WARMUP OTIMIZADO --------
|
262 |
def warmup_optimized():
|
263 |
-
"
|
264 |
-
log.info("🔥 Executando warmup otimizado...")
|
265 |
try:
|
266 |
-
# Múltiplas execuções de warmup para otimizar cache
|
267 |
for i in range(3):
|
268 |
result = analyze_news_optimized(f"Test title {i}", f"Test content {i}")
|
269 |
log.info(f"Warmup {i+1}/3 concluído")
|
270 |
|
271 |
-
# Força garbage collection após warmup
|
272 |
gc.collect()
|
273 |
-
log.info("✅ Warmup
|
274 |
except Exception as e:
|
275 |
log.warning(f"⚠️ Warmup falhou: {e}")
|
276 |
|
277 |
-
# -------- INTERFACE OTIMIZADA --------
|
278 |
def create_optimized_interface():
|
279 |
-
"""Interface otimizada para melhor performance"""
|
280 |
-
|
281 |
with gr.Blocks(
|
282 |
title="Analisador de Notícias - Ultra Otimizado",
|
283 |
theme=gr.themes.Monochrome(),
|
@@ -291,19 +240,10 @@ def create_optimized_interface():
|
|
291 |
padding: 15px;
|
292 |
margin: 10px 0;
|
293 |
}
|
294 |
-
.status-success {
|
295 |
-
color: #28a745;
|
296 |
-
font-weight: bold;
|
297 |
-
}
|
298 |
-
.status-error {
|
299 |
-
color: #dc3545;
|
300 |
-
font-weight: bold;
|
301 |
-
}
|
302 |
"""
|
303 |
) as demo:
|
304 |
|
305 |
gr.Markdown("# 🚀 Analisador de Notícias - Ultra Otimizado")
|
306 |
-
gr.Markdown("🔥 Versão otimizada para máxima performance em CPU")
|
307 |
|
308 |
with gr.Row():
|
309 |
with gr.Column(scale=1):
|
@@ -319,9 +259,8 @@ def create_optimized_interface():
|
|
319 |
max_lines=6
|
320 |
)
|
321 |
|
322 |
-
analyze_btn = gr.Button("⚡ Analisar Notícia
|
323 |
|
324 |
-
# Exemplos
|
325 |
with gr.Row():
|
326 |
example_btn1 = gr.Button("📻 Exemplo 1", size="sm")
|
327 |
example_btn2 = gr.Button("⚽ Exemplo 2", size="sm")
|
@@ -335,15 +274,12 @@ def create_optimized_interface():
|
|
335 |
show_copy_button=True
|
336 |
)
|
337 |
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
interactive=False
|
344 |
-
)
|
345 |
|
346 |
-
# Função otimizada para análise
|
347 |
def analyze_with_status(title: str, content: str) -> Tuple[str, str]:
|
348 |
if not title.strip() or not content.strip():
|
349 |
return "❌ Preencha todos os campos", "Erro: Campos obrigatórios não preenchidos"
|
@@ -357,65 +293,39 @@ def create_optimized_interface():
|
|
357 |
except Exception as e:
|
358 |
return f"❌ Erro: {str(e)}", f"Erro: {str(e)}"
|
359 |
|
360 |
-
# Exemplos otimizados
|
361 |
examples = [
|
362 |
("Legendary Musician Carlos Mendes Dies at 78", "Carlos Mendes, the internationally acclaimed Brazilian guitarist and composer known for blending traditional bossa nova with modern jazz, has died at the age of 78."),
|
363 |
("Brazil Defeats Argentina 2-1 in Copa America Final", "In a thrilling match at the Maracana Stadium, Brazil secured victory over Argentina with goals from Neymar and Vinicius Jr. The match was watched by over 200 million viewers worldwide."),
|
364 |
("Tech Giant Announces Major Layoffs Affecting 10,000 Employees", "The technology company announced significant workforce reductions citing economic uncertainty and changing market conditions. The layoffs will affect multiple departments across different regions.")
|
365 |
]
|
366 |
|
367 |
-
# Event handlers
|
368 |
analyze_btn.click(
|
369 |
fn=analyze_with_status,
|
370 |
inputs=[title_input, content_input],
|
371 |
outputs=[status, output]
|
372 |
)
|
373 |
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
)
|
379 |
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
**Otimizações de Modelo:**
|
390 |
-
- Modo de inferência com torch.inference_mode()
|
391 |
-
- Cache de tokenização inteligente
|
392 |
-
- Processamento sem gradientes
|
393 |
-
- Fusão de camadas lineares
|
394 |
-
- Greedy decoding para máxima velocidade
|
395 |
-
|
396 |
-
**Otimizações de Memória:**
|
397 |
-
- Garbage collection otimizado
|
398 |
-
- Context manager para gestão de memória
|
399 |
-
- Limpeza automática de tensores
|
400 |
-
- Limite de tamanho de entrada
|
401 |
-
|
402 |
-
**Otimizações de I/O:**
|
403 |
-
- Regex compilado para extração JSON
|
404 |
-
- Preprocessamento otimizado
|
405 |
-
- Cache inteligente de operações
|
406 |
-
- Múltiplas execuções de warmup
|
407 |
-
|
408 |
-
⚡ **Resultado esperado:** 30-50% mais rápido que a versão anterior
|
409 |
-
""")
|
410 |
|
411 |
return demo
|
412 |
|
413 |
-
# -------- EXECUÇÃO PRINCIPAL --------
|
414 |
if __name__ == "__main__":
|
415 |
-
# Executa warmup otimizado
|
416 |
warmup_optimized()
|
417 |
|
418 |
-
print("🚀 Iniciando interface
|
419 |
demo = create_optimized_interface()
|
420 |
demo.launch(
|
421 |
share=False,
|
@@ -423,5 +333,5 @@ if __name__ == "__main__":
|
|
423 |
server_port=7860,
|
424 |
show_error=True,
|
425 |
max_threads=num_threads,
|
426 |
-
show_api=False,
|
427 |
)
|
|
|
10 |
import gc
|
11 |
from typing import Dict, Any, Optional, List, Tuple
|
12 |
import psutil
|
|
|
|
|
13 |
from contextlib import contextmanager
|
|
|
14 |
|
|
|
|
|
15 |
num_cores = psutil.cpu_count(logical=False)
|
16 |
+
num_threads = min(4, num_cores)
|
17 |
|
18 |
os.environ["TOKENIZERS_PARALLELISM"] = "false"
|
19 |
os.environ["OMP_NUM_THREADS"] = str(num_threads)
|
|
|
24 |
|
25 |
torch.set_num_threads(num_threads)
|
26 |
torch.set_num_interop_threads(1)
|
|
|
|
|
27 |
torch.backends.mkl.enabled = True
|
28 |
torch.backends.mkldnn.enabled = True
|
29 |
torch.backends.quantized.engine = 'qnnpack'
|
30 |
+
torch.cuda.empty_cache = lambda: None
|
31 |
|
|
|
|
|
|
|
|
|
32 |
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
|
33 |
log = logging.getLogger("news-filter-optimized")
|
34 |
|
|
|
35 |
device = "cpu"
|
36 |
torch.set_default_device(device)
|
37 |
|
|
|
38 |
@contextmanager
|
39 |
def memory_efficient_context():
|
|
|
40 |
try:
|
|
|
41 |
gc.collect()
|
42 |
yield
|
43 |
finally:
|
|
|
44 |
gc.collect()
|
45 |
|
46 |
class OptimizedTokenizerWrapper:
|
|
|
|
|
47 |
def __init__(self, tokenizer):
|
48 |
self.tokenizer = tokenizer
|
|
|
|
|
49 |
self._template_cache = {}
|
50 |
|
51 |
def apply_chat_template(self, messages, **kwargs):
|
|
|
|
|
52 |
content = messages[0]['content'] if messages else ""
|
53 |
+
key = hash(content[:100])
|
54 |
|
55 |
if key not in self._template_cache:
|
56 |
result = self.tokenizer.apply_chat_template(messages, **kwargs)
|
|
|
57 |
if len(self._template_cache) > 100:
|
58 |
self._template_cache.clear()
|
59 |
self._template_cache[key] = result
|
|
|
61 |
return self._template_cache[key]
|
62 |
|
63 |
def decode(self, *args, **kwargs):
|
|
|
64 |
return self.tokenizer.decode(*args, **kwargs)
|
65 |
|
66 |
def __getattr__(self, name):
|
|
|
67 |
return getattr(self.tokenizer, name)
|
68 |
|
69 |
+
print("🚀 Carregando modelo...")
|
70 |
+
log.info("🚀 Carregando modelo...")
|
|
|
71 |
|
|
|
72 |
model_config = {
|
73 |
"device_map": device,
|
74 |
+
"torch_dtype": torch.float16,
|
75 |
"low_cpu_mem_usage": True,
|
76 |
"use_cache": True,
|
77 |
"trust_remote_code": True,
|
78 |
+
"attn_implementation": "eager",
|
79 |
}
|
80 |
|
|
|
81 |
model = AutoPeftModelForCausalLM.from_pretrained(
|
82 |
"habulaj/filterinstruct180",
|
83 |
**model_config
|
84 |
)
|
85 |
|
|
|
86 |
tokenizer = AutoTokenizer.from_pretrained(
|
87 |
"habulaj/filterinstruct180",
|
88 |
use_fast=True,
|
89 |
padding_side="left",
|
90 |
+
model_max_length=1024,
|
91 |
+
clean_up_tokenization_spaces=False,
|
92 |
)
|
93 |
|
|
|
94 |
if tokenizer.pad_token is None:
|
95 |
tokenizer.pad_token = tokenizer.eos_token
|
96 |
|
|
|
97 |
tokenizer = OptimizedTokenizerWrapper(tokenizer)
|
98 |
|
|
|
|
|
99 |
model.eval()
|
|
|
|
|
100 |
for param in model.parameters():
|
101 |
param.requires_grad = False
|
102 |
|
|
|
103 |
try:
|
104 |
model = torch.compile(model, mode="reduce-overhead")
|
105 |
+
log.info("✅ Modelo compilado")
|
106 |
except Exception as e:
|
107 |
log.warning(f"⚠️ Torch compile não disponível: {e}")
|
108 |
|
|
|
109 |
if hasattr(model, 'fuse_linear_layers'):
|
110 |
model.fuse_linear_layers()
|
111 |
|
112 |
+
log.info("✅ Modelo carregado")
|
113 |
+
|
114 |
+
tokenizer.tokenizer.chat_template = """{% for message in messages %}{% if message['role'] == 'user' %}{% if loop.first %}<|begin_of_text|><|start_header_id|>user<|end_header_id|>
|
115 |
+
|
116 |
+
{{ message['content'] }}<|eot_id|>{% else %}<|start_header_id|>user<|end_header_id|>
|
117 |
|
118 |
+
{{ message['content'] }}<|eot_id|>{% endif %}{% elif message['role'] == 'assistant' %}<|start_header_id|>assistant<|end_header_id|>
|
119 |
+
|
120 |
+
{{ message['content'] }}<|eot_id|>{% endif %}{% endfor %}{% if add_generation_prompt %}<|start_header_id|>assistant<|end_header_id|>
|
121 |
+
|
122 |
+
{% endif %}"""
|
123 |
|
|
|
124 |
generation_config = GenerationConfig(
|
125 |
+
max_new_tokens=150,
|
126 |
+
temperature=0.8,
|
127 |
+
do_sample=False,
|
128 |
use_cache=True,
|
129 |
eos_token_id=tokenizer.eos_token_id,
|
130 |
pad_token_id=tokenizer.eos_token_id,
|
131 |
repetition_penalty=1.1,
|
132 |
length_penalty=1.0,
|
133 |
+
num_beams=1,
|
134 |
early_stopping=True,
|
135 |
)
|
136 |
|
|
|
137 |
def extract_json_optimized(text: str) -> str:
|
|
|
138 |
if not hasattr(extract_json_optimized, 'pattern'):
|
139 |
extract_json_optimized.pattern = re.compile(r'\{.*?\}', re.DOTALL)
|
140 |
|
|
|
142 |
return match.group(0) if match else text
|
143 |
|
144 |
def preprocess_input_optimized(title: str, content: str) -> List[Dict[str, str]]:
|
|
|
|
|
145 |
max_title_length = 100
|
146 |
max_content_length = 500
|
147 |
|
|
|
160 |
}]
|
161 |
|
162 |
def analyze_news_optimized(title: str, content: str) -> str:
|
|
|
163 |
try:
|
164 |
with memory_efficient_context():
|
165 |
start_time = time.time()
|
166 |
|
|
|
167 |
messages = preprocess_input_optimized(title, content)
|
168 |
|
|
|
169 |
inputs = tokenizer.apply_chat_template(
|
170 |
messages,
|
171 |
tokenize=True,
|
172 |
add_generation_prompt=True,
|
173 |
return_tensors="pt",
|
174 |
+
padding=False,
|
175 |
truncation=True,
|
176 |
max_length=1024,
|
177 |
)
|
178 |
|
|
|
179 |
with torch.no_grad(), torch.inference_mode():
|
180 |
with torch.autocast(device_type='cpu', dtype=torch.float16):
|
181 |
outputs = model.generate(
|
|
|
187 |
output_attentions=False,
|
188 |
return_dict_in_generate=False,
|
189 |
use_cache=True,
|
190 |
+
do_sample=False,
|
191 |
)
|
192 |
|
|
|
193 |
generated_tokens = outputs[0][inputs.shape[1]:]
|
194 |
generated_text = tokenizer.decode(
|
195 |
generated_tokens,
|
|
|
197 |
clean_up_tokenization_spaces=False
|
198 |
)
|
199 |
|
|
|
200 |
json_result = extract_json_optimized(generated_text)
|
201 |
|
|
|
202 |
duration = time.time() - start_time
|
203 |
log.info(f"✅ Análise concluída em {duration:.2f}s")
|
204 |
|
|
|
205 |
del outputs, inputs, generated_tokens
|
206 |
|
|
|
207 |
try:
|
208 |
parsed_json = json.loads(json_result)
|
209 |
return json.dumps(parsed_json, indent=2, ensure_ascii=False)
|
|
|
214 |
log.exception("❌ Erro durante análise:")
|
215 |
return f"Erro durante a análise: {str(e)}"
|
216 |
|
|
|
217 |
def warmup_optimized():
|
218 |
+
log.info("🔥 Executando warmup...")
|
|
|
219 |
try:
|
|
|
220 |
for i in range(3):
|
221 |
result = analyze_news_optimized(f"Test title {i}", f"Test content {i}")
|
222 |
log.info(f"Warmup {i+1}/3 concluído")
|
223 |
|
|
|
224 |
gc.collect()
|
225 |
+
log.info("✅ Warmup concluído")
|
226 |
except Exception as e:
|
227 |
log.warning(f"⚠️ Warmup falhou: {e}")
|
228 |
|
|
|
229 |
def create_optimized_interface():
|
|
|
|
|
230 |
with gr.Blocks(
|
231 |
title="Analisador de Notícias - Ultra Otimizado",
|
232 |
theme=gr.themes.Monochrome(),
|
|
|
240 |
padding: 15px;
|
241 |
margin: 10px 0;
|
242 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
243 |
"""
|
244 |
) as demo:
|
245 |
|
246 |
gr.Markdown("# 🚀 Analisador de Notícias - Ultra Otimizado")
|
|
|
247 |
|
248 |
with gr.Row():
|
249 |
with gr.Column(scale=1):
|
|
|
259 |
max_lines=6
|
260 |
)
|
261 |
|
262 |
+
analyze_btn = gr.Button("⚡ Analisar Notícia", variant="primary")
|
263 |
|
|
|
264 |
with gr.Row():
|
265 |
example_btn1 = gr.Button("📻 Exemplo 1", size="sm")
|
266 |
example_btn2 = gr.Button("⚽ Exemplo 2", size="sm")
|
|
|
274 |
show_copy_button=True
|
275 |
)
|
276 |
|
277 |
+
status = gr.Textbox(
|
278 |
+
label="Status",
|
279 |
+
value="⚡ Pronto para análise",
|
280 |
+
interactive=False
|
281 |
+
)
|
|
|
|
|
282 |
|
|
|
283 |
def analyze_with_status(title: str, content: str) -> Tuple[str, str]:
|
284 |
if not title.strip() or not content.strip():
|
285 |
return "❌ Preencha todos os campos", "Erro: Campos obrigatórios não preenchidos"
|
|
|
293 |
except Exception as e:
|
294 |
return f"❌ Erro: {str(e)}", f"Erro: {str(e)}"
|
295 |
|
|
|
296 |
examples = [
|
297 |
("Legendary Musician Carlos Mendes Dies at 78", "Carlos Mendes, the internationally acclaimed Brazilian guitarist and composer known for blending traditional bossa nova with modern jazz, has died at the age of 78."),
|
298 |
("Brazil Defeats Argentina 2-1 in Copa America Final", "In a thrilling match at the Maracana Stadium, Brazil secured victory over Argentina with goals from Neymar and Vinicius Jr. The match was watched by over 200 million viewers worldwide."),
|
299 |
("Tech Giant Announces Major Layoffs Affecting 10,000 Employees", "The technology company announced significant workforce reductions citing economic uncertainty and changing market conditions. The layoffs will affect multiple departments across different regions.")
|
300 |
]
|
301 |
|
|
|
302 |
analyze_btn.click(
|
303 |
fn=analyze_with_status,
|
304 |
inputs=[title_input, content_input],
|
305 |
outputs=[status, output]
|
306 |
)
|
307 |
|
308 |
+
example_btn1.click(
|
309 |
+
fn=lambda: examples[0],
|
310 |
+
outputs=[title_input, content_input]
|
311 |
+
)
|
|
|
312 |
|
313 |
+
example_btn2.click(
|
314 |
+
fn=lambda: examples[1],
|
315 |
+
outputs=[title_input, content_input]
|
316 |
+
)
|
317 |
+
|
318 |
+
example_btn3.click(
|
319 |
+
fn=lambda: examples[2],
|
320 |
+
outputs=[title_input, content_input]
|
321 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
322 |
|
323 |
return demo
|
324 |
|
|
|
325 |
if __name__ == "__main__":
|
|
|
326 |
warmup_optimized()
|
327 |
|
328 |
+
print("🚀 Iniciando interface...")
|
329 |
demo = create_optimized_interface()
|
330 |
demo.launch(
|
331 |
share=False,
|
|
|
333 |
server_port=7860,
|
334 |
show_error=True,
|
335 |
max_threads=num_threads,
|
336 |
+
show_api=False,
|
337 |
)
|