Volver a la wiki

AutoPlanService: Digitalizaci\u00f3n de planos con IA

{“sources”: [{“type”: “code”, “ref”: “blueprints/services/autoplan.py”}, {“type”: “code”, “ref”: “blueprints/models.py”}, {“type”: “commit”, “ref”: “PR#55”}, {“type”: “commit”, “ref”: “cc828f2aad1cf173c4652e7a917ef5c5d1a818af”}], “related”: [“feature—blueprints—autoplan-hito-f-hardening”, “decision—20260601—retirada-provider-gemini-autoplan”, “entity—blueprints—endpoint—autoplan-import”, “entity—blueprints—model—blueprint”, “entity—blueprints—model—aiprompt”, “entity—blueprints—service—uploads”], “content”: ”## Descripción\n\n**blueprints.services.autoplan.AutoPlanService** es el servicio core de Auto-Plan, responsable de:\n- Análisis de imágenes de planos usando IA (Gemma 4 o Ollama)\n- Extracción estructurada de racks, conexiones, anotaciones y símbolos\n- Creación de entidades (modelos Blueprint, BlueprintPlacement, MapAnnotation)\n\nMigrado originalmente desde Flask (sesión s8) con enhancements Django (type hints, transaccionalidad, constrained decoding).\n\n## Módulo\n\n\nblueprints/services/autoplan.py\n\n\nClase principal: AutoPlanService (7 métodos, sin herencia)\n\n## Métodos públicos\n\n| Método | Propósito | Entrada | Salida |\n|--------|-----------|---------|--------|\n| get_image_scaling | Calcula factor de escala del plano | ruta imagen | (float, float) |\n| safe_float | Conversión segura a float con default | valor, default | float |\n| snap | Redondea valor al paso más cercano | valor, step | float |\n| normalize_label | Limpia/estandariza etiquetas de texto | string | string |\n| analyze_blueprint_image | Principal: analiza imagen, devuelve JSON estructurado | api_key, file_path, prompt, provider | dict |\n| create_blueprint_entities | Crea modelos Rack, BlueprintPlacement desde datos AI (tolerante: elementos no-dict se saltan y se anotan) | blueprint, ai_data, scale_x, scale_y, warnings=None | int (nº racks creados) |\n| create_blueprint_annotations | Crea modelos MapAnnotation desde datos AI | blueprint, ai_data, scale_x, scale_y, warnings=None | int (nº elementos que fallaron) |\n\n## Flujo principal: analyze_blueprint_image\n\n\nInput:\n api_key (str): clave del provider seleccionado\n file_path (str): ruta temporal de imagen subida\n prompt (str): instrucción IA (from AIPrompt model)\n provider (str): \"google_genai\" (default) o \"ollama\"\n\nProceso:\n 1. Si provider == \"ollama\" → _analyze_with_ollama(file_path, prompt)\n 2. Si no → _analyze_with_gemma4(api_key, file_path, prompt)\n 3. Procesa imagen: resize max 2048px, conversión RGB, JPEG quality=90\n\nOutput:\n dict con estructura:\n {\n \"racks\": [{\"id\": str, \"position\": {\"x\": float, \"y\": float}, \"size\": {...}, ...}],\n \"connections\": [{\"from\": str, \"to\": str, \"type\": str, ...}],\n \"walls\": [{\"x1\": float, \"y1\": float, \"x2\": float, \"y2\": float, ...}],\n \"texts\": [{\"content\": str, \"position\": {...}, ...}],\n \"symbols\": [{\"type\": str, \"position\": {...}, ...}]\n }\n\n\nResponsables de calidad:\n- Prompt (AIPrompt model, versionado en git)\n- Constrained decoding (response_mime_type=\"application/json\" en Gemma 4)\n- Tests de regresión (scripts/test_autoplan_quality.py)\n\n## Import tolerante (cola auditoría B, s300)\n\nA partir de PR#493 (task #286), create_blueprint_entities y create_blueprint_annotations aceptan un parámetro opcional warnings: list[str] | None donde acumulan lo que el import se saltó o no pudo casar, en vez de tragárselo en silencio:\n\n- Elementos no-dict en racks/connections (el modelo IA devolvió un string o número en vez de un objeto) se saltan y se anotan — antes reventaban .get() y abortaban TODO el import.\n- label/zone demasiado largos se recortan a los 100 caracteres de Rack.name/Rack.location (constante MAX_TEXT_FIELD) — antes el DataError de Postgres abortaba el import entero.\n- Fallos por elemento en create_blueprint_annotations (muro/texto/símbolo corrupto) se siguen tragando uno a uno (no tira el import completo) pero ahora se cuentan: la función devuelve cuántos fallaron y los añade a warnings.\n\nLa lista warnings la recoge la task run_autoplan_import (ver [[entity—blueprints—service—run-autoplan-import]]) y llega al resultado del AsyncJob — antes un import que perdía racks o anotaciones podía reportar éxito limpio.\n\n## Proveedores soportados\n\n### google_genai (default) — Gemma 4\n\n- SDK: google-genai (nuevo SDK unificado)\n- Modelo: gemma-4-26b-a4b-it (configurable vía GEMMA4_GENAI_MODEL)\n- Tier: Google AI Studio Paid\n- Constrained decoding: ✅ response_mime_type=\"application/json\"\n- Temperatura: 0.1 (determinístico)\n- Introducido: s49 (A/B test)\n- PROD status: ✅ Activo\n\n### ollama — Local inference (dev)\n\n- Soporte: offline, sin API key\n- Modelo: configurable vía OLLAMA_MODEL_NAME (default: llama3.2:latest)\n- Base URL: configurable vía OLLAMA_BASE_URL (default: http://localhost:11434)\n- Constrained decoding: ⚠️ No soportado (validación post-generación recomendada)\n- Use case: desarrollo local, testing sin costo\n\n## Imports\n\npython\nfrom django.db import transaction\nfrom PIL import Image\nfrom blueprints.models import Blueprint, BlueprintPlacement, MapAnnotation\nfrom blueprints.prompts import get_blueprint_analysis_prompt\n\n\nDependencias externas:\n- Pillow — procesamiento de imagen\n- google-genai — provider Gemma 4 (opcional con ollama)\n- requests — cliente HTTP para Ollama\n\n## Historial de cambios\n\n| Versión | Cambio | Sesión | PR |\n|---------|--------|--------|-----|\n| Inicial | Migración desde Flask + type hints | s8 | — |\n| s49 | Introducción google_genai (Gemma 4) | s49 | #39 |\n| s101 | Retirada provider Gemini legacy | s101 | #55 |\n| s300 | Import tolerante (warnings) + validación de subida movida a blueprints/services/uploads.py | s300 | #493 |\n\nCambios en s101:\n- Eliminado método _analyze_with_gemini (~153 LOC)\n- Eliminado import google.genai.types\n- Simplificado dispatcher en analyze_blueprint_image\n- Actualizado docstring: Gemma 4 como único default\n\nVer [[decision—20260601—retirada-provider-gemini-autoplan]] para contexto completo.\n\nCambios en s300 — ver sección [[#Import tolerante (cola auditoría B, s300)]] arriba.\n\n## Tests\n\nSuite de regresión:\n\nscripts/test_autoplan_quality.py\n\n\nCubre:\n- Detección de racks/conexiones/anotaciones\n- Formato JSON válido (constrained decoding)\n- Escalado de imagen\n- Manejo de errores (timeout, overload)\n\n## Notas de arquitectura\n\n1. Transaccionalidad: método create_blueprint_entities usa @transaction.atomic para garantizar consistencia (crear racks + placements juntos o nada)\n2. Retry logic: reintentos automáticos en errores 503/504 de API (backoff exponencial)\n3. Image optimization: resize + JPEG quality=90 reduce latencia API ~60%\n4. Provider separation: lógica de Gemma 4 vs Ollama aislada en _analyze_with_* methods para facilitar futuros providers\n\n## Véase también\n\n- [[feature—blueprints—autoplan-hito-f-hardening]]\n- [[decision—20260601—retirada-provider-gemini-autoplan]]\n- [[entity—blueprints—endpoint—autoplan-import]]\n- [[entity—blueprints—model—blueprint]]\n- [[entity—blueprints—model—aiprompt]]\n- [[entity—blueprints—service—uploads]]\n”}

Subir