open-ia-key / app.py
doctorlinux's picture
Upload 3 files
051c2be verified
import os
import time
import gradio as gr
# Evitar analíticas y minimizar logs
os.environ["GRADIO_ANALYTICS_ENABLED"] = "false"
try:
from openai import OpenAI
from openai import APIError, APIConnectionError, RateLimitError, AuthenticationError
except Exception:
# En algunas versiones, las clases de error cambian; mantenemos compatibilidad amplia
OpenAI = None
APIError = Exception
APIConnectionError = Exception
RateLimitError = Exception
AuthenticationError = Exception
DEFAULT_MODEL = os.getenv("OPENAI_TEST_MODEL", "gpt-4o-mini")
def mask_key(key: str) -> str:
if not key or len(key) < 12:
return "****"
return key[:8] + "..." + key[-4:]
def quick_healthcheck(client: "OpenAI", model: str) -> dict:
"""
Llamada mínima al endpoint para validar la clave y medir latencia.
Usamos Responses API con salida de 1-2 tokens para costo mínimo.
"""
t0 = time.time()
try:
# Preferir Responses API (SDK v1)
resp = client.responses.create(
model=model,
input="ping",
max_output_tokens=2,
)
latency_ms = int((time.time() - t0) * 1000)
out = getattr(resp, "output", None) or getattr(resp, "output_text", None)
# Respuesta normalizada
return {
"ok": True,
"latency_ms": latency_ms,
"model_used": model,
"output_preview": (out[:120] + "…") if isinstance(out, str) and len(out) > 120 else out,
}
except AuthenticationError as e:
return {"ok": False, "error_type": "auth", "message": str(e)}
except RateLimitError as e:
return {"ok": False, "error_type": "rate_limit", "message": str(e)}
except APIConnectionError as e:
return {"ok": False, "error_type": "network", "message": str(e)}
except APIError as e:
# Errores con status_code (ej. 404 modelo no encontrado, 429, 500s)
status = getattr(e, "status_code", None)
if status == 404:
return {"ok": False, "error_type": "model_not_found", "message": str(e)}
elif status == 401:
return {"ok": False, "error_type": "auth", "message": str(e)}
elif status == 429:
return {"ok": False, "error_type": "rate_limit", "message": str(e)}
else:
return {"ok": False, "error_type": f"api_{status}", "message": str(e)}
except Exception as e:
return {"ok": False, "error_type": "unknown", "message": str(e)}
def test_key(use_secret: bool, pasted_key: str, model: str):
"""
Prueba la API Key. Si `use_secret` es True, usa la de entorno (Space Secret).
Si es False, toma la pegada en la UI (no se persiste).
"""
key_source = "SECRET del Space" if use_secret else "Clave pegada en UI"
api_key = None
if use_secret:
api_key = os.getenv("OPENAI_API_KEY", "").strip()
if not api_key:
return {
"estado": "❌ No se encontró `OPENAI_API_KEY` en los Secrets del Space.",
"detalle": "Ve a Settings → Repository secrets y crea uno llamado OPENAI_API_KEY.",
"clave_usada": "—",
}
else:
pasted_key = (pasted_key or "").strip()
if not pasted_key:
return {
"estado": "❌ Debes pegar una API Key o marcar 'Usar SECRET del Space'.",
"detalle": "La clave no se guarda; se usa solo para esta prueba.",
"clave_usada": "—",
}
api_key = pasted_key
if OpenAI is None:
return {
"estado": "❌ SDK de OpenAI no disponible",
"detalle": "Revisa versión del paquete `openai`.",
"clave_usada": mask_key(api_key),
}
client = OpenAI(api_key=api_key)
# Validar con llamada mínima
result = quick_healthcheck(client, model=model)
if result.get("ok"):
return {
"estado": f"✅ ¡Clave válida! ({key_source})",
"detalle": f"Modelo: {result['model_used']} | Latencia: {result['latency_ms']} ms | Vista previa: {result['output_preview']}",
"clave_usada": mask_key(api_key),
}
else:
et = result.get("error_type")
msg = result.get("message", "")
explanation = {
"auth": "La clave parece inválida o no pertenece a tu organización/proyecto.",
"rate_limit": "Se alcanzó el límite de velocidad/cuota. Intenta de nuevo más tarde o ajusta el plan.",
"model_not_found": "El modelo indicado no existe o no tienes acceso. Prueba con otro modelo.",
"network": "Fallo de conexión. Verifica la red saliente del Space/servidor.",
}.get(et, "Error no especificado.")
return {
"estado": f"❌ Error: {et}",
"detalle": f"{explanation}\nMensaje de la API: {msg}",
"clave_usada": mask_key(api_key),
}
with gr.Blocks(title="Verificador de OpenAI API Key") as demo:
gr.Markdown("# 🔐 Verificador de OpenAI API Key\nPrueba tu clave de forma segura antes de usarla en otras apps.")
with gr.Row():
use_secret = gr.Checkbox(label="Usar SECRET del Space (`OPENAI_API_KEY`)", value=True)
model = gr.Dropdown(choices=["gpt-4o-mini", "gpt-4o", "gpt-4o-realtime-preview-2024-12-17", "gpt-4.1-mini"], value=DEFAULT_MODEL, label="Modelo para prueba")
pasted_key = gr.Textbox(label="Pega tu API Key (opcional si usas SECRET)", type="password", placeholder="sk-xxxxxxxxxxxxxxxxxxxxxxxx")
btn = gr.Button("Probar clave")
out = gr.JSON(label="Resultado")
btn.click(fn=test_key, inputs=[use_secret, pasted_key, model], outputs=out)
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0", server_port=int(os.getenv("PORT", "7860")))