Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -137,7 +137,84 @@ def sanitizar_texto(texto: str) -> str:
|
|
| 137 |
return texto_limpo.strip()
|
| 138 |
|
| 139 |
# ATUALIZADO: Função totalmente refatorada para usar a nova chamada de API.
|
| 140 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 141 |
prompt_completo = f"{prompt}\n\n---\n\n**INSTRUÇÃO OBRIGATÓRIA: Sua resposta DEVE ser um único e válido objeto JSON.**"
|
| 142 |
print(f"\n{'='*25} 💬 API INPUT PARA [{model_name}] {'='*25}\n{prompt_completo}\n{'='*78}\n")
|
| 143 |
|
|
|
|
| 137 |
return texto_limpo.strip()
|
| 138 |
|
| 139 |
# ATUALIZADO: Função totalmente refatorada para usar a nova chamada de API.
|
| 140 |
+
d# ============================================================================
|
| 141 |
+
# CORREÇÃO DA FUNÇÃO DE CHAMADA DA API (google-genai v1.0+)
|
| 142 |
+
# ============================================================================
|
| 143 |
+
|
| 144 |
+
def chamar_gemini_json(model_name: str, prompt: str, temperatura: float = 0.4, max_tokens: int = 8192) -> Dict:
|
| 145 |
+
prompt_completo = f"{prompt}\n\n---\n\n**INSTRUÇÃO OBRIGATÓRIA: Sua resposta DEVE ser um único e válido objeto JSON.**"
|
| 146 |
+
print(f"\n{'='*25} 💬 API INPUT PARA [{model_name}] {'='*25}\n{prompt_completo}\n{'='*78}\n")
|
| 147 |
+
|
| 148 |
+
try:
|
| 149 |
+
# 1. Monta a estrutura de `contents`
|
| 150 |
+
contents = [
|
| 151 |
+
types.Content(
|
| 152 |
+
role="user",
|
| 153 |
+
parts=[types.Part.from_text(text=prompt_completo)],
|
| 154 |
+
),
|
| 155 |
+
]
|
| 156 |
+
|
| 157 |
+
# 2. Define as ferramentas (Google Search)
|
| 158 |
+
tools = [
|
| 159 |
+
types.Tool(google_search=types.GoogleSearch()),
|
| 160 |
+
]
|
| 161 |
+
|
| 162 |
+
# 3. Monta a configuração
|
| 163 |
+
# NOTA: Verifique se o modelo suporta 'thinking_config'. Se der erro, remova essa linha.
|
| 164 |
+
# Models como gemini-2.0-flash-thinking suportam. O 2.5-pro padrão pode não suportar.
|
| 165 |
+
thinking_config = None
|
| 166 |
+
# if "thinking" in model_name: # Lógica opcional para ativar apenas se for modelo thinking
|
| 167 |
+
# thinking_config = types.ThinkingConfig(thinking_budget=8192)
|
| 168 |
+
|
| 169 |
+
generate_content_config = types.GenerateContentConfig(
|
| 170 |
+
temperature=temperatura,
|
| 171 |
+
max_output_tokens=max_tokens,
|
| 172 |
+
# thinking_config=thinking_config, # Descomente se tiver certeza que o modelo suporta
|
| 173 |
+
tools=tools,
|
| 174 |
+
response_mime_type="application/json" # Força JSON nativo se o modelo suportar
|
| 175 |
+
)
|
| 176 |
+
|
| 177 |
+
# 4. Chamada de API Corrigida
|
| 178 |
+
# A nova SDK usa client.models.generate_content_stream
|
| 179 |
+
# O parâmetro de configuração chama-se 'config', não 'generation_config'
|
| 180 |
+
stream = CLIENT.models.generate_content_stream(
|
| 181 |
+
model=model_name,
|
| 182 |
+
contents=contents,
|
| 183 |
+
config=generate_content_config,
|
| 184 |
+
)
|
| 185 |
+
|
| 186 |
+
# Agrega a resposta do stream
|
| 187 |
+
resposta_bruta = ""
|
| 188 |
+
for chunk in stream:
|
| 189 |
+
if chunk.text:
|
| 190 |
+
resposta_bruta += chunk.text
|
| 191 |
+
|
| 192 |
+
print(f"\n{'='*25} 📥 API RAW OUTPUT DE [{model_name}] {'='*25}\n{resposta_bruta}\n{'='*78}\n")
|
| 193 |
+
|
| 194 |
+
resposta_sanitizada = sanitizar_texto(resposta_bruta)
|
| 195 |
+
|
| 196 |
+
if not resposta_sanitizada:
|
| 197 |
+
logger.log("A API retornou uma resposta vazia. Causa provável: Filtros de segurança.", "WARN")
|
| 198 |
+
return {"erro": "API_EMPTY_RESPONSE", "causa_provavel": "Filtro de segurança do modelo."}
|
| 199 |
+
|
| 200 |
+
# Tenta extrair JSON (caso o response_mime_type não seja estritamente respeitado ou venha markdown)
|
| 201 |
+
match = re.search(r'\{.*\}', resposta_sanitizada, re.DOTALL)
|
| 202 |
+
if not match:
|
| 203 |
+
# Tenta parsear direto caso a string inteira seja o JSON
|
| 204 |
+
try:
|
| 205 |
+
return json.loads(resposta_sanitizada)
|
| 206 |
+
except:
|
| 207 |
+
return {"erro": "JSON_NOT_FOUND", "detalhes": "Nenhum objeto JSON encontrado na resposta da API.", "raw": resposta_sanitizada}
|
| 208 |
+
|
| 209 |
+
return json.loads(match.group(0))
|
| 210 |
+
|
| 211 |
+
except Exception as e:
|
| 212 |
+
logger.log(f"Falha na chamada da API ou no parse do JSON: {e}", "ERROR")
|
| 213 |
+
return {"erro": "API_CALL_OR_PARSE_FAILED", "detalhes": str(e)}
|
| 214 |
+
|
| 215 |
+
|
| 216 |
+
|
| 217 |
+
ef chamar_gemini_json1(model_name: str, prompt: str, temperatura: float = 0.4, max_tokens: int = 92048) -> Dict:
|
| 218 |
prompt_completo = f"{prompt}\n\n---\n\n**INSTRUÇÃO OBRIGATÓRIA: Sua resposta DEVE ser um único e válido objeto JSON.**"
|
| 219 |
print(f"\n{'='*25} 💬 API INPUT PARA [{model_name}] {'='*25}\n{prompt_completo}\n{'='*78}\n")
|
| 220 |
|