habulaj commited on
Commit
47a6536
·
verified ·
1 Parent(s): ca15e7a

Update routers/inference.py

Browse files
Files changed (1) hide show
  1. routers/inference.py +119 -9
routers/inference.py CHANGED
@@ -10,6 +10,7 @@ from datetime import datetime
10
  from zoneinfo import ZoneInfo
11
  import locale
12
  import re
 
13
 
14
  # Configurar logging
15
  logger = logging.getLogger(__name__)
@@ -105,15 +106,118 @@ def get_brazilian_date_string():
105
 
106
  def download_sources_file(url: str) -> str:
107
  """
108
- Baixa o arquivo fontes.txt da URL fornecida.
109
  """
110
- try:
111
- response = requests.get(url, timeout=30)
112
- response.raise_for_status()
113
- return response.text
114
- except Exception as e:
115
- logger.error(f"Erro ao baixar arquivo de fontes: {e}")
116
- raise HTTPException(status_code=400, detail=f"Erro ao baixar arquivo de fontes: {str(e)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
 
118
  def extract_text_from_response(response):
119
  """
@@ -187,8 +291,10 @@ async def rewrite_news(news: NewsRequest):
187
  if not api_key:
188
  raise HTTPException(status_code=500, detail="API key não configurada")
189
 
190
- # Baixar arquivo de fontes
 
191
  sources_content = download_sources_file(news.sources_url)
 
192
 
193
  client = genai.Client(api_key=api_key)
194
  model = "gemini-2.5-pro"
@@ -287,6 +393,7 @@ News base: Ed Helms revealed in an interview that he was nervous about his paren
287
  ]
288
 
289
  # Gerar conteúdo
 
290
  response = client.models.generate_content(
291
  model=model,
292
  contents=contents,
@@ -296,6 +403,8 @@ News base: Ed Helms revealed in an interview that he was nervous about his paren
296
  # Extrair texto e fontes
297
  response_text = extract_text_from_response(response)
298
  sources = extract_sources_from_response(response)
 
 
299
 
300
  # Verificar se o texto está vazio
301
  if not response_text or response_text.strip() == "":
@@ -321,6 +430,7 @@ News base: Ed Helms revealed in an interview that he was nervous about his paren
321
  else:
322
  content = "Conteúdo não encontrado"
323
 
 
324
  return NewsResponse(title=title, subhead=subhead, content=content, sources=sources)
325
 
326
  except HTTPException:
 
10
  from zoneinfo import ZoneInfo
11
  import locale
12
  import re
13
+ import time
14
 
15
  # Configurar logging
16
  logger = logging.getLogger(__name__)
 
106
 
107
  def download_sources_file(url: str) -> str:
108
  """
109
+ Baixa o arquivo fontes.txt da URL fornecida com retry e headers apropriados.
110
  """
111
+ max_retries = 3
112
+ base_timeout = 45
113
+
114
+ # Headers que simulam um navegador real
115
+ headers = {
116
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
117
+ 'Accept': 'text/plain,text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
118
+ 'Accept-Language': 'pt-BR,pt;q=0.9,en;q=0.8',
119
+ 'Accept-Encoding': 'gzip, deflate, br',
120
+ 'Connection': 'keep-alive',
121
+ 'Upgrade-Insecure-Requests': '1',
122
+ 'Sec-Fetch-Dest': 'document',
123
+ 'Sec-Fetch-Mode': 'navigate',
124
+ 'Sec-Fetch-Site': 'none',
125
+ 'Cache-Control': 'max-age=0'
126
+ }
127
+
128
+ for attempt in range(max_retries):
129
+ try:
130
+ logger.info(f"Tentativa {attempt + 1} de download do arquivo: {url}")
131
+
132
+ # Timeout progressivo: 45s, 60s, 90s
133
+ timeout = base_timeout + (attempt * 15)
134
+
135
+ # Configuração de sessão com retry automático
136
+ session = requests.Session()
137
+
138
+ # Adapter com retry automático
139
+ from requests.adapters import HTTPAdapter
140
+ from urllib3.util.retry import Retry
141
+
142
+ retry_strategy = Retry(
143
+ total=2,
144
+ backoff_factor=1,
145
+ status_forcelist=[429, 500, 502, 503, 504],
146
+ )
147
+
148
+ adapter = HTTPAdapter(max_retries=retry_strategy)
149
+ session.mount("http://", adapter)
150
+ session.mount("https://", adapter)
151
+
152
+ # Fazer a requisição
153
+ response = session.get(
154
+ url,
155
+ headers=headers,
156
+ timeout=timeout,
157
+ allow_redirects=True,
158
+ stream=False # Não usar stream para arquivos pequenos
159
+ )
160
+
161
+ response.raise_for_status()
162
+
163
+ content = response.text
164
+ logger.info(f"Download bem-sucedido na tentativa {attempt + 1}. Tamanho: {len(content)} caracteres")
165
+
166
+ # Validação básica do conteúdo
167
+ if len(content.strip()) < 10:
168
+ raise ValueError("Conteúdo do arquivo muito pequeno ou vazio")
169
+
170
+ # Verifica se é um JSON válido (assumindo que o arquivo contém JSON)
171
+ try:
172
+ json.loads(content)
173
+ logger.info("Arquivo JSON válido confirmado")
174
+ except json.JSONDecodeError:
175
+ logger.warning("Arquivo não é um JSON válido, mas continuando...")
176
+
177
+ return content
178
+
179
+ except requests.exceptions.Timeout as e:
180
+ logger.warning(f"Timeout na tentativa {attempt + 1}: {e}")
181
+ if attempt == max_retries - 1:
182
+ raise HTTPException(
183
+ status_code=408,
184
+ detail=f"Timeout ao baixar arquivo após {max_retries} tentativas. O servidor pode estar sobrecarregado."
185
+ )
186
+
187
+ except requests.exceptions.ConnectionError as e:
188
+ logger.warning(f"Erro de conexão na tentativa {attempt + 1}: {e}")
189
+ if attempt == max_retries - 1:
190
+ raise HTTPException(
191
+ status_code=503,
192
+ detail=f"Erro de conexão após {max_retries} tentativas. Verifique se a URL está correta: {url}"
193
+ )
194
+
195
+ except requests.exceptions.HTTPError as e:
196
+ status_code = e.response.status_code if e.response else 500
197
+ logger.error(f"Erro HTTP {status_code} na tentativa {attempt + 1}: {e}")
198
+
199
+ if status_code == 404:
200
+ raise HTTPException(status_code=404, detail="Arquivo não encontrado. Verifique se a URL está correta.")
201
+ elif status_code in [500, 502, 503, 504]:
202
+ if attempt == max_retries - 1:
203
+ raise HTTPException(status_code=status_code, detail=f"Erro do servidor ({status_code}) após {max_retries} tentativas.")
204
+ else:
205
+ raise HTTPException(status_code=status_code, detail=f"Erro HTTP {status_code}: {str(e)}")
206
+
207
+ except ValueError as e:
208
+ logger.error(f"Erro de validação na tentativa {attempt + 1}: {e}")
209
+ raise HTTPException(status_code=422, detail=f"Conteúdo do arquivo inválido: {str(e)}")
210
+
211
+ except Exception as e:
212
+ logger.error(f"Erro inesperado na tentativa {attempt + 1}: {e}")
213
+ if attempt == max_retries - 1:
214
+ raise HTTPException(status_code=500, detail=f"Erro inesperado ao baixar arquivo: {str(e)}")
215
+
216
+ # Wait before retry (exponential backoff)
217
+ if attempt < max_retries - 1:
218
+ wait_time = (attempt + 1) * 2
219
+ logger.info(f"Aguardando {wait_time}s antes da próxima tentativa...")
220
+ time.sleep(wait_time)
221
 
222
  def extract_text_from_response(response):
223
  """
 
291
  if not api_key:
292
  raise HTTPException(status_code=500, detail="API key não configurada")
293
 
294
+ # Baixar arquivo de fontes com retry melhorado
295
+ logger.info(f"Iniciando download do arquivo de fontes: {news.sources_url}")
296
  sources_content = download_sources_file(news.sources_url)
297
+ logger.info("Download do arquivo de fontes concluído com sucesso")
298
 
299
  client = genai.Client(api_key=api_key)
300
  model = "gemini-2.5-pro"
 
393
  ]
394
 
395
  # Gerar conteúdo
396
+ logger.info("Iniciando geração de conteúdo com Gemini...")
397
  response = client.models.generate_content(
398
  model=model,
399
  contents=contents,
 
403
  # Extrair texto e fontes
404
  response_text = extract_text_from_response(response)
405
  sources = extract_sources_from_response(response)
406
+
407
+ logger.info("Conteúdo gerado com sucesso pelo Gemini")
408
 
409
  # Verificar se o texto está vazio
410
  if not response_text or response_text.strip() == "":
 
430
  else:
431
  content = "Conteúdo não encontrado"
432
 
433
+ logger.info("Processamento concluído com sucesso")
434
  return NewsResponse(title=title, subhead=subhead, content=content, sources=sources)
435
 
436
  except HTTPException: