{“related”: [“entity—blueprints—service—autoplan”, “decision—20260601—retirada-provider-gemini-autoplan”, “feature—blueprints—autoplan-hito-f-hardening”, “entity—blueprints—model—blueprint”, “entity—blueprints—model—aiprompt”, “entity—blueprints—service—uploads”], “content”: ”## Descripción\n\nEndpoint público que digitaliza un plano en imagen (JPG/PNG) mediante IA, extrayendo racks, conexiones, anotaciones y símbolos. Crea automáticamente la entidad Blueprint con toda la información estructurada.\n\nRuta: POST /api/blueprints/autoplan/import\nOperación Ninja API: blueprints_api_autoplan_magic_import_blueprint\nTag OpenAPI: Blueprints\n\n## Parámetros\n\n### Query / Form\n\n| Parámetro | Tipo | Requerido | Descripción |\n|-----------|------|-----------|-------------|\n| file | UploadedFile (multipart) | ✅ | Imagen del plano (JPG/PNG, máx tamaño por Django FILE_UPLOAD_MAX_MEMORY_SIZE) |\n| name | str | ✅ | Nombre del plano a crear |\n\n### Headers de autenticación\n\n- Authorization: Bearer <token> — requerido (Ninja API token auth)\n- Aplicable la Regla 1 (portero global de API, CLAUDE.md)\n\n## Respuesta\n\n### 200 OK\n\njson\n{\n \"blueprint_id\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"name\": \"Plano Datacenter A\",\n \"organization_id\": \"550e8400-e29b-41d4-a716-446655440001\",\n \"racks_created\": 12,\n \"connections_created\": 34,\n \"walls_created\": 2,\n \"texts_created\": 18,\n \"symbols_created\": 5,\n \"image_processed\": true,\n \"scale_x\": 1.5,\n \"scale_y\": 1.5\n}\n\n\n### 400 Bad Request\n\njson\n{\n \"message\": \"Gemini API key not configured. Set GEMINI_API_KEY in environment.\"\n}\n\n\n(Nota: Este error fue eliminado en s101; ahora solo retorna 400 si OLLAMA_BASE_URL está mal configurada con provider ollama)\n\n### 401 Unauthorized\n\njson\n{\n \"detail\": \"Unauthorized\"\n}\n\n\n(Por falta de token válido — Portero global)\n\n## Implementación\n\nArchivo: blueprints/api/autoplan.py\n\npython\n@api.post(\"/autoplan/import\")\ndef magic_import_blueprint(\n request, \n file: UploadedFile = File(...), \n name: str = Query(...)\n) -> dict:\n \"\"\"\n Auto-Plan: AI-powered blueprint digitization.\n Default provider is google_genai / Gemma 4 vía Google AI Studio Paid Tier\n (CLAUDE.md Regla 8). Alternativa: ollama (self-host dev).\n \"\"\"\n provider = getattr(settings, \"AUTOPLAN_PROVIDER\", \"google_genai\")\n \n if provider == \"ollama\":\n api_key = \"ollama\"\n ollama_url = getattr(settings, \"OLLAMA_BASE_URL\", \"http://localhost:11434\")\n logger.info(f\"[AutoPlan] Using Ollama provider at {ollama_url}\")\n else:\n # google_genai (default)\n api_key = getattr(settings, \"GEMINI_API_KEY\", None)\n # ... resto del flujo\n\n\nFlujo:\n1. Validar token (middleware Ninja)\n2. Resolver provider desde AUTOPLAN_PROVIDER env var\n3. Obtener API key correspondiente\n4. Validar y guardar imagen (extensión/tamaño/imagen real vía blueprints/services/uploads.py, ver [[entity—blueprints—service—uploads]])\n5. Llamar a AutoPlanService.analyze_blueprint_image(api_key, file_path, prompt, provider)\n6. Crear Blueprint model\n7. Llamar a AutoPlanService.create_blueprint_entities() (racks, placements)\n8. Llamar a AutoPlanService.create_blueprint_annotations() (anotaciones)\n9. Retornar resumen\n\n## Proveedores soportados (a partir de s101)\n\n| Provider | Env var | Modelo | Status |\n|----------|---------|--------|--------|\n| google_genai | GEMINI_API_KEY | Gemma 4 (configurable) | ✅ Default, PROD |\n| ollama | (no aplica) | Local (configurable) | ✅ Dev/test |\n| gemini | GEMINI_API_KEY | Gemini 3.1 Flash | ❌ Retirado s101 |\n\nCambio en s101 (PR #55):\n- Provider gemini eliminado (violaba Regla 8)\n- Ahora solo 2 opciones: google_genai (default) u ollama\n\nVer [[decision—20260601—retirada-provider-gemini-autoplan]] para contexto.\n\n## Prompts\n\nEl prompt utilizado está versionado en el modelo AIPrompt. Default:\n\n- Key: blueprint_analysis_default (o según configuración)\n- Responsabilidad: instrucciones específicas para extracción de racks, conexiones, anotaciones\n- Actualización: cambios requieren PR + sesión Edu para validación en PROD\n\n## Rate limiting (actualizado s300, PR#493)\n\n- Tope de imports de IA EN CURSO por organización: MAX_AUTOPLAN_IN_FLIGHT_PER_ORG = 3 (constante en blueprints/api/autoplan.py). El import que excede el tope recibe 429, comprobado ANTES de escribir el fichero (para no dejar huérfanos en disco al rechazar).\n- No es una ventana de tiempo — es un conteo de AsyncJob de kind AUTOPLAN en estado pending/processing para esa organización. El análisis dura ~4 min y es facturable; sin este tope, una org podía encolar N imports y ocupar workers/factura de todos.\n- Sin límite en DEBUG=True (dev).\n\n## Observabilidad\n\n### Logs\n\n\n[AutoPlan] Using Ollama provider at http://localhost:11434\n[AutoPlan] Input file: /tmp/tmp_abc123.jpg\n[AutoPlan] Original image size: (3840, 2160), mode: RGB\n[AutoPlan] Resized image from (3840, 2160) to (2048, 1152)\n[AutoPlan] Processed image: (2048, 1152), format=JPEG, size=512.3KB (prep: 0.45s)\n[AutoPlan] Sending to Gemma 4 (attempt 1/3)...\n[AutoPlan] Gemma 4 API completed in 4.23s (2105 chars)\n[AutoPlan] Detection summary: 12 racks, 34 connections, 2 walls, 18 texts, 5 symbols\n\n\n### Métricas (si Prometheus habilitado)\n\n- autoplan_requests_total{provider=\"google_genai\",status=\"success\"} — contador de requestss exitosas\n- autoplan_request_duration_seconds{provider=\"google_genai\"} — histograma de latencias\n- autoplan_image_size_bytes — tamaño de imágenes procesadas\n\n## Restricciones y notas\n\n1. Tamaño máximo de imagen: techo configurable vía settings.BLUEPRINT_IMAGE_MAX_BYTES (default 25 MB, ver [[entity—blueprints—service—uploads]]). Se redimensiona a máx 2048px antes de enviar a API.\n2. Formatos soportados: JPG, PNG, GIF, BMP, WEBP. Convertidos internamente a RGB JPEG para el envío a IA.\n3. Timeout API: 30s (configurable vía AUTOPLAN_API_TIMEOUT). Con reintentos automáticos en caso de overload.\n4. Validación JSON: constrained decoding de Gemma 4 (no validador pydantic post-generación, basado en investigación s101).\n5. Import tolerante (s300): elementos malformados del análisis IA ya no abortan el import completo — se saltan/recortan y se reportan como warnings en el job. Ver [[entity—blueprints—service—run-autoplan-import]] y [[entity—blueprints—service—autoplan]].\n\n## Historial\n\n| Versión | Cambio | Sesión |\n|---------|--------|--------|\n| Inicial | Creación del endpoint | s7 |\n| s101 | Retirada provider gemini legacy | s101 |\n| s300 | Validación de subida movida a uploads.py compartido + tope de imports en curso por org (429) — PR#493 | s300 |\n\n## Véase también\n\n- [[entity—blueprints—service—autoplan]]\n- [[decision—20260601—retirada-provider-gemini-autoplan]]\n- [[feature—blueprints—autoplan-hito-f-hardening]]\n- [[entity—blueprints—model—blueprint]]\n- [[entity—blueprints—model—aiprompt]]\n- [[entity—blueprints—service—uploads]]\n”}
Referenciado desde
- Auto-Plan LLM Resilience — log provider, retry JSON, regex glitch s49
- Auto-Plan: Resiliencia OpenRouter — retry JSONDecodeError + logging diagnóstico + regex clave faltante
- AutoPlanService: Digitalizaci\u00f3n de planos con IA
- blueprints.services.uploads — validación compartida de subida de imágenes
- Feature: AutoPlan — Provider google_genai (Gemma 4 directo, Google AI Studio Paid)
- Hito F: Auto-Plan refactor + investigación de calidad (Plan Hardening post-Máster)
- Incident s49 — Varianza extrema Auto-Plan en Vertex (C1+C2+C3)