Spaces:
Running
Running
Guilherme Silberfarb Costa commited on
Commit ·
9c95fcc
1
Parent(s): a484189
Speed up model search warmup and first map load
Browse files
backend/app/core/map_layers.py
CHANGED
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
| 3 |
import json
|
| 4 |
from html import escape
|
| 5 |
from pathlib import Path
|
| 6 |
-
from threading import Lock
|
| 7 |
from typing import Any
|
| 8 |
|
| 9 |
import folium
|
|
@@ -19,6 +19,8 @@ _SIMPLIFY_TOLERANCE = 0.00005
|
|
| 19 |
_BAIRROS_CACHE_LOCK = Lock()
|
| 20 |
_BAIRROS_GEOJSON_CACHE: dict[str, Any] | None = None
|
| 21 |
_BAIRROS_SOURCE_SIGNATURE: tuple[tuple[str, int, int], ...] | None = None
|
|
|
|
|
|
|
| 22 |
|
| 23 |
|
| 24 |
def _assinatura_bairros_source() -> tuple[tuple[str, int, int], ...] | None:
|
|
@@ -38,61 +40,84 @@ def _assinatura_bairros_source() -> tuple[tuple[str, int, int], ...] | None:
|
|
| 38 |
|
| 39 |
def _carregar_bairros_geojson() -> dict[str, Any] | None:
|
| 40 |
global _BAIRROS_GEOJSON_CACHE, _BAIRROS_SOURCE_SIGNATURE
|
|
|
|
| 41 |
assinatura = _assinatura_bairros_source()
|
| 42 |
if assinatura is None or not _BAIRROS_SHP_PATH.exists():
|
| 43 |
return None
|
| 44 |
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
|
| 57 |
-
if gpd is not None:
|
| 58 |
try:
|
| 59 |
-
gdf = gpd.read_file(_BAIRROS_SHP_PATH, engine="fiona")
|
| 60 |
-
if gdf is not None and not gdf.empty:
|
| 61 |
-
if gdf.crs is not None:
|
| 62 |
-
gdf = gdf.to_crs("EPSG:4326")
|
| 63 |
-
campos = ["geometry"]
|
| 64 |
-
for campo in _TOOLTIP_FIELDS:
|
| 65 |
-
if campo in gdf.columns:
|
| 66 |
-
campos.insert(0, campo)
|
| 67 |
-
break
|
| 68 |
-
gdf = gdf.loc[:, campos].copy()
|
| 69 |
-
if _SIMPLIFY_TOLERANCE > 0:
|
| 70 |
-
gdf["geometry"] = gdf.geometry.simplify(_SIMPLIFY_TOLERANCE, preserve_topology=True)
|
| 71 |
-
geojson = json.loads(gdf.to_json(drop_id=True))
|
| 72 |
-
except Exception as exc:
|
| 73 |
-
append_runtime_log(f"[mesa] bairros: falha no geopandas para camada de bairros: {exc}")
|
| 74 |
-
|
| 75 |
-
if geojson is None:
|
| 76 |
-
try:
|
| 77 |
-
geojson = load_vector_geojson(
|
| 78 |
-
_BAIRROS_SHP_PATH,
|
| 79 |
-
target_crs="EPSG:4326",
|
| 80 |
-
property_fields=_TOOLTIP_FIELDS,
|
| 81 |
-
simplify_tolerance=_SIMPLIFY_TOLERANCE,
|
| 82 |
-
)
|
| 83 |
-
append_runtime_log("[mesa] bairros: usando fallback leve para camada de bairros")
|
| 84 |
-
except Exception as exc:
|
| 85 |
-
append_runtime_log(f"[mesa] bairros: fallback de bairros falhou: {exc}")
|
| 86 |
geojson = None
|
| 87 |
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 96 |
|
| 97 |
|
| 98 |
def get_bairros_geojson() -> dict[str, Any] | None:
|
|
|
|
| 3 |
import json
|
| 4 |
from html import escape
|
| 5 |
from pathlib import Path
|
| 6 |
+
from threading import Event, Lock
|
| 7 |
from typing import Any
|
| 8 |
|
| 9 |
import folium
|
|
|
|
| 19 |
_BAIRROS_CACHE_LOCK = Lock()
|
| 20 |
_BAIRROS_GEOJSON_CACHE: dict[str, Any] | None = None
|
| 21 |
_BAIRROS_SOURCE_SIGNATURE: tuple[tuple[str, int, int], ...] | None = None
|
| 22 |
+
_BAIRROS_INFLIGHT_SIGNATURE: tuple[tuple[str, int, int], ...] | None = None
|
| 23 |
+
_BAIRROS_INFLIGHT_EVENT: Event | None = None
|
| 24 |
|
| 25 |
|
| 26 |
def _assinatura_bairros_source() -> tuple[tuple[str, int, int], ...] | None:
|
|
|
|
| 40 |
|
| 41 |
def _carregar_bairros_geojson() -> dict[str, Any] | None:
|
| 42 |
global _BAIRROS_GEOJSON_CACHE, _BAIRROS_SOURCE_SIGNATURE
|
| 43 |
+
global _BAIRROS_INFLIGHT_SIGNATURE, _BAIRROS_INFLIGHT_EVENT
|
| 44 |
assinatura = _assinatura_bairros_source()
|
| 45 |
if assinatura is None or not _BAIRROS_SHP_PATH.exists():
|
| 46 |
return None
|
| 47 |
|
| 48 |
+
while True:
|
| 49 |
+
with _BAIRROS_CACHE_LOCK:
|
| 50 |
+
if _BAIRROS_SOURCE_SIGNATURE == assinatura and _BAIRROS_GEOJSON_CACHE is not None:
|
| 51 |
+
return _BAIRROS_GEOJSON_CACHE
|
| 52 |
+
|
| 53 |
+
if _BAIRROS_INFLIGHT_SIGNATURE == assinatura and _BAIRROS_INFLIGHT_EVENT is not None:
|
| 54 |
+
inflight = _BAIRROS_INFLIGHT_EVENT
|
| 55 |
+
is_builder = False
|
| 56 |
+
else:
|
| 57 |
+
inflight = Event()
|
| 58 |
+
_BAIRROS_INFLIGHT_SIGNATURE = assinatura
|
| 59 |
+
_BAIRROS_INFLIGHT_EVENT = inflight
|
| 60 |
+
is_builder = True
|
| 61 |
+
|
| 62 |
+
if not is_builder:
|
| 63 |
+
inflight.wait()
|
| 64 |
+
continue
|
| 65 |
|
|
|
|
| 66 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
geojson = None
|
| 68 |
|
| 69 |
+
try:
|
| 70 |
+
import geopandas as gpd
|
| 71 |
+
except Exception:
|
| 72 |
+
gpd = None
|
| 73 |
+
|
| 74 |
+
if gpd is not None:
|
| 75 |
+
try:
|
| 76 |
+
gdf = gpd.read_file(_BAIRROS_SHP_PATH, engine="fiona")
|
| 77 |
+
if gdf is not None and not gdf.empty:
|
| 78 |
+
if gdf.crs is not None:
|
| 79 |
+
gdf = gdf.to_crs("EPSG:4326")
|
| 80 |
+
campos = ["geometry"]
|
| 81 |
+
for campo in _TOOLTIP_FIELDS:
|
| 82 |
+
if campo in gdf.columns:
|
| 83 |
+
campos.insert(0, campo)
|
| 84 |
+
break
|
| 85 |
+
gdf = gdf.loc[:, campos].copy()
|
| 86 |
+
if _SIMPLIFY_TOLERANCE > 0:
|
| 87 |
+
gdf["geometry"] = gdf.geometry.simplify(_SIMPLIFY_TOLERANCE, preserve_topology=True)
|
| 88 |
+
geojson = json.loads(gdf.to_json(drop_id=True))
|
| 89 |
+
except Exception as exc:
|
| 90 |
+
append_runtime_log(f"[mesa] bairros: falha no geopandas para camada de bairros: {exc}")
|
| 91 |
+
|
| 92 |
+
if geojson is None:
|
| 93 |
+
try:
|
| 94 |
+
geojson = load_vector_geojson(
|
| 95 |
+
_BAIRROS_SHP_PATH,
|
| 96 |
+
target_crs="EPSG:4326",
|
| 97 |
+
property_fields=_TOOLTIP_FIELDS,
|
| 98 |
+
simplify_tolerance=_SIMPLIFY_TOLERANCE,
|
| 99 |
+
)
|
| 100 |
+
append_runtime_log("[mesa] bairros: usando fallback leve para camada de bairros")
|
| 101 |
+
except Exception as exc:
|
| 102 |
+
append_runtime_log(f"[mesa] bairros: fallback de bairros falhou: {exc}")
|
| 103 |
+
geojson = None
|
| 104 |
+
|
| 105 |
+
with _BAIRROS_CACHE_LOCK:
|
| 106 |
+
if geojson is not None:
|
| 107 |
+
_BAIRROS_GEOJSON_CACHE = geojson
|
| 108 |
+
_BAIRROS_SOURCE_SIGNATURE = assinatura
|
| 109 |
+
else:
|
| 110 |
+
_BAIRROS_GEOJSON_CACHE = None
|
| 111 |
+
_BAIRROS_SOURCE_SIGNATURE = None
|
| 112 |
+
return geojson
|
| 113 |
+
finally:
|
| 114 |
+
with _BAIRROS_CACHE_LOCK:
|
| 115 |
+
waiter = _BAIRROS_INFLIGHT_EVENT if _BAIRROS_INFLIGHT_SIGNATURE == assinatura else None
|
| 116 |
+
if _BAIRROS_INFLIGHT_SIGNATURE == assinatura:
|
| 117 |
+
_BAIRROS_INFLIGHT_SIGNATURE = None
|
| 118 |
+
_BAIRROS_INFLIGHT_EVENT = None
|
| 119 |
+
if waiter is not None:
|
| 120 |
+
waiter.set()
|
| 121 |
|
| 122 |
|
| 123 |
def get_bairros_geojson() -> dict[str, Any] | None:
|
backend/app/main.py
CHANGED
|
@@ -9,7 +9,7 @@ from fastapi.staticfiles import StaticFiles
|
|
| 9 |
|
| 10 |
from app.api import auth, elaboracao, health, logs, pesquisa, repositorio, session, trabalhos_tecnicos, visualizacao
|
| 11 |
from app.runtime_paths import resolve_frontend_dist_dir
|
| 12 |
-
from app.services import auth_service
|
| 13 |
|
| 14 |
app = FastAPI(
|
| 15 |
title="MESA Frame API",
|
|
@@ -57,6 +57,12 @@ app.include_router(trabalhos_tecnicos.router)
|
|
| 57 |
app.include_router(logs.router)
|
| 58 |
|
| 59 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
def _mount_frontend_if_exists() -> None:
|
| 61 |
frontend_dist = resolve_frontend_dist_dir()
|
| 62 |
index_file = frontend_dist / "index.html"
|
|
|
|
| 9 |
|
| 10 |
from app.api import auth, elaboracao, health, logs, pesquisa, repositorio, session, trabalhos_tecnicos, visualizacao
|
| 11 |
from app.runtime_paths import resolve_frontend_dist_dir
|
| 12 |
+
from app.services import auth_service, visualizacao_service
|
| 13 |
|
| 14 |
app = FastAPI(
|
| 15 |
title="MESA Frame API",
|
|
|
|
| 57 |
app.include_router(logs.router)
|
| 58 |
|
| 59 |
|
| 60 |
+
@app.on_event("startup")
|
| 61 |
+
async def schedule_app_support_warmup() -> None:
|
| 62 |
+
# Keep startup/login responsive and warm shared caches shortly after readiness.
|
| 63 |
+
visualizacao_service.schedule_visualizacao_support_warmup(delay_seconds=1.0)
|
| 64 |
+
|
| 65 |
+
|
| 66 |
def _mount_frontend_if_exists() -> None:
|
| 67 |
frontend_dist = resolve_frontend_dist_dir()
|
| 68 |
index_file = frontend_dist / "index.html"
|
backend/app/services/pesquisa_service.py
CHANGED
|
@@ -9,7 +9,7 @@ import unicodedata
|
|
| 9 |
from dataclasses import dataclass
|
| 10 |
from datetime import date, datetime
|
| 11 |
from pathlib import Path
|
| 12 |
-
from threading import Lock
|
| 13 |
from typing import Any
|
| 14 |
|
| 15 |
import folium
|
|
@@ -231,6 +231,7 @@ _ADMIN_FONTES_SESSION: dict[str, list[str]] = {}
|
|
| 231 |
_CATALOGO_VIAS_CACHE: list[dict[str, Any]] | None = None
|
| 232 |
_FAMILIAS_VERSOES_CACHE: dict[str, list[dict[str, Any]]] | None = None
|
| 233 |
_FAMILIAS_VERSOES_SIGNATURE: tuple[str, tuple[tuple[str, int, int], ...]] | None = None
|
|
|
|
| 234 |
|
| 235 |
|
| 236 |
def _resolver_repositorio_modelos() -> model_repository.ModelRepositoryResolution:
|
|
@@ -601,12 +602,11 @@ def _montar_familias_versoes_modelos(caminhos_modelo: list[Path]) -> dict[str, l
|
|
| 601 |
familias: dict[str, list[dict[str, Any]]] = {}
|
| 602 |
|
| 603 |
for caminho in caminhos_modelo:
|
| 604 |
-
resumo = _carregar_resumo_com_cache(caminho)
|
| 605 |
info = _extrair_info_versao_modelo(
|
| 606 |
{
|
| 607 |
-
"id":
|
| 608 |
"arquivo": caminho.name,
|
| 609 |
-
"nome_modelo":
|
| 610 |
}
|
| 611 |
)
|
| 612 |
if info is None:
|
|
@@ -618,7 +618,7 @@ def _montar_familias_versoes_modelos(caminhos_modelo: list[Path]) -> dict[str, l
|
|
| 618 |
"sufixo": sufixo,
|
| 619 |
"id": modelo_id,
|
| 620 |
"arquivo": caminho.name,
|
| 621 |
-
"nome_modelo":
|
| 622 |
}
|
| 623 |
)
|
| 624 |
|
|
@@ -646,26 +646,42 @@ def obter_familias_versoes_modelos_cache(caminhos_modelo: list[Path] | None = No
|
|
| 646 |
caminhos = list(caminhos_modelo) if caminhos_modelo is not None else list(resolved.modelos_dir.glob("*.dai"))
|
| 647 |
assinatura = (resolved.signature, _assinatura_modelos_familias(caminhos))
|
| 648 |
|
| 649 |
-
|
| 650 |
-
|
| 651 |
-
|
| 652 |
-
|
| 653 |
-
|
| 654 |
-
|
|
|
|
| 655 |
|
| 656 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 657 |
|
| 658 |
-
|
| 659 |
-
|
| 660 |
-
|
| 661 |
-
|
| 662 |
-
|
| 663 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 664 |
|
| 665 |
-
|
| 666 |
-
chave: [dict(item) for item in itens]
|
| 667 |
-
for chave, itens in familias.items()
|
| 668 |
-
}
|
| 669 |
|
| 670 |
|
| 671 |
def _agrupar_nomes_modelo_por_familia(values: list[Any]) -> dict[str, list[str]]:
|
|
|
|
| 9 |
from dataclasses import dataclass
|
| 10 |
from datetime import date, datetime
|
| 11 |
from pathlib import Path
|
| 12 |
+
from threading import Event, Lock
|
| 13 |
from typing import Any
|
| 14 |
|
| 15 |
import folium
|
|
|
|
| 231 |
_CATALOGO_VIAS_CACHE: list[dict[str, Any]] | None = None
|
| 232 |
_FAMILIAS_VERSOES_CACHE: dict[str, list[dict[str, Any]]] | None = None
|
| 233 |
_FAMILIAS_VERSOES_SIGNATURE: tuple[str, tuple[tuple[str, int, int], ...]] | None = None
|
| 234 |
+
_FAMILIAS_VERSOES_INFLIGHT: dict[tuple[str, tuple[tuple[str, int, int], ...]], Event] = {}
|
| 235 |
|
| 236 |
|
| 237 |
def _resolver_repositorio_modelos() -> model_repository.ModelRepositoryResolution:
|
|
|
|
| 602 |
familias: dict[str, list[dict[str, Any]]] = {}
|
| 603 |
|
| 604 |
for caminho in caminhos_modelo:
|
|
|
|
| 605 |
info = _extrair_info_versao_modelo(
|
| 606 |
{
|
| 607 |
+
"id": caminho.stem,
|
| 608 |
"arquivo": caminho.name,
|
| 609 |
+
"nome_modelo": caminho.stem,
|
| 610 |
}
|
| 611 |
)
|
| 612 |
if info is None:
|
|
|
|
| 618 |
"sufixo": sufixo,
|
| 619 |
"id": modelo_id,
|
| 620 |
"arquivo": caminho.name,
|
| 621 |
+
"nome_modelo": modelo_id,
|
| 622 |
}
|
| 623 |
)
|
| 624 |
|
|
|
|
| 646 |
caminhos = list(caminhos_modelo) if caminhos_modelo is not None else list(resolved.modelos_dir.glob("*.dai"))
|
| 647 |
assinatura = (resolved.signature, _assinatura_modelos_familias(caminhos))
|
| 648 |
|
| 649 |
+
while True:
|
| 650 |
+
with _CACHE_LOCK:
|
| 651 |
+
if _FAMILIAS_VERSOES_SIGNATURE == assinatura and isinstance(_FAMILIAS_VERSOES_CACHE, dict):
|
| 652 |
+
return {
|
| 653 |
+
chave: [dict(item) for item in itens]
|
| 654 |
+
for chave, itens in _FAMILIAS_VERSOES_CACHE.items()
|
| 655 |
+
}
|
| 656 |
|
| 657 |
+
inflight = _FAMILIAS_VERSOES_INFLIGHT.get(assinatura)
|
| 658 |
+
if inflight is None:
|
| 659 |
+
inflight = Event()
|
| 660 |
+
_FAMILIAS_VERSOES_INFLIGHT[assinatura] = inflight
|
| 661 |
+
is_builder = True
|
| 662 |
+
else:
|
| 663 |
+
is_builder = False
|
| 664 |
|
| 665 |
+
if is_builder:
|
| 666 |
+
try:
|
| 667 |
+
familias = _montar_familias_versoes_modelos(caminhos)
|
| 668 |
+
with _CACHE_LOCK:
|
| 669 |
+
_FAMILIAS_VERSOES_SIGNATURE = assinatura
|
| 670 |
+
_FAMILIAS_VERSOES_CACHE = {
|
| 671 |
+
chave: [dict(item) for item in itens]
|
| 672 |
+
for chave, itens in familias.items()
|
| 673 |
+
}
|
| 674 |
+
return {
|
| 675 |
+
chave: [dict(item) for item in itens]
|
| 676 |
+
for chave, itens in familias.items()
|
| 677 |
+
}
|
| 678 |
+
finally:
|
| 679 |
+
with _CACHE_LOCK:
|
| 680 |
+
waiter = _FAMILIAS_VERSOES_INFLIGHT.pop(assinatura, None)
|
| 681 |
+
if waiter is not None:
|
| 682 |
+
waiter.set()
|
| 683 |
|
| 684 |
+
inflight.wait()
|
|
|
|
|
|
|
|
|
|
| 685 |
|
| 686 |
|
| 687 |
def _agrupar_nomes_modelo_por_familia(values: list[Any]) -> dict[str, list[str]]:
|
backend/app/services/visualizacao_service.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
from __future__ import annotations
|
| 2 |
|
| 3 |
from pathlib import Path
|
|
|
|
| 4 |
from threading import Lock, Thread
|
| 5 |
from typing import Any
|
| 6 |
|
|
@@ -31,6 +32,7 @@ from app.core.elaboracao.core import (
|
|
| 31 |
from app.core.elaboracao.formatadores import formatar_avaliacao_html
|
| 32 |
from app.core.visualizacao.map_payload import build_leaflet_payload, build_visualizacao_map_payload
|
| 33 |
from app.models.session import SessionState
|
|
|
|
| 34 |
from app.services import model_repository, pesquisa_service, trabalhos_tecnicos_service
|
| 35 |
from app.services.equacao_service import build_equacoes_payload, exportar_planilha_equacao
|
| 36 |
from app.services.knn_avaliacao_service import estimar_valor_knn_avaliacao
|
|
@@ -421,7 +423,7 @@ def listar_modelos_repositorio() -> dict[str, Any]:
|
|
| 421 |
return sanitize_value(model_repository.list_repository_models())
|
| 422 |
|
| 423 |
|
| 424 |
-
def
|
| 425 |
global _MAP_SUPPORT_WARMUP_SIGNATURE
|
| 426 |
try:
|
| 427 |
signature = model_repository.resolve_model_repository().signature
|
|
@@ -434,16 +436,19 @@ def _warm_visualizacao_support_caches_async() -> None:
|
|
| 434 |
_MAP_SUPPORT_WARMUP_SIGNATURE = signature
|
| 435 |
|
| 436 |
def _worker() -> None:
|
|
|
|
|
|
|
|
|
|
| 437 |
try:
|
| 438 |
get_bairros_geojson()
|
| 439 |
-
except Exception:
|
| 440 |
-
|
| 441 |
try:
|
| 442 |
pesquisa_service.obter_familias_versoes_modelos_cache()
|
| 443 |
-
except Exception:
|
| 444 |
-
|
| 445 |
|
| 446 |
-
Thread(target=_worker, name="mesa-visualizacao-
|
| 447 |
|
| 448 |
|
| 449 |
def carregar_modelo_repositorio(session: SessionState, modelo_id: str) -> dict[str, Any]:
|
|
@@ -473,7 +478,6 @@ def carregar_modelo(session: SessionState, caminho_arquivo: str) -> dict[str, An
|
|
| 473 |
session.dados_visualizacao = None
|
| 474 |
session.avaliacoes_visualizacao = []
|
| 475 |
session.visualizacao_cache = {}
|
| 476 |
-
_warm_visualizacao_support_caches_async()
|
| 477 |
|
| 478 |
nome_modelo = Path(caminho_arquivo).stem
|
| 479 |
badge_html = viz_app._formatar_badge_completo(pacote, nome_modelo=nome_modelo)
|
|
|
|
| 1 |
from __future__ import annotations
|
| 2 |
|
| 3 |
from pathlib import Path
|
| 4 |
+
from time import sleep
|
| 5 |
from threading import Lock, Thread
|
| 6 |
from typing import Any
|
| 7 |
|
|
|
|
| 32 |
from app.core.elaboracao.formatadores import formatar_avaliacao_html
|
| 33 |
from app.core.visualizacao.map_payload import build_leaflet_payload, build_visualizacao_map_payload
|
| 34 |
from app.models.session import SessionState
|
| 35 |
+
from app.runtime_log import append_runtime_log
|
| 36 |
from app.services import model_repository, pesquisa_service, trabalhos_tecnicos_service
|
| 37 |
from app.services.equacao_service import build_equacoes_payload, exportar_planilha_equacao
|
| 38 |
from app.services.knn_avaliacao_service import estimar_valor_knn_avaliacao
|
|
|
|
| 423 |
return sanitize_value(model_repository.list_repository_models())
|
| 424 |
|
| 425 |
|
| 426 |
+
def schedule_visualizacao_support_warmup(*, delay_seconds: float = 0.0) -> None:
|
| 427 |
global _MAP_SUPPORT_WARMUP_SIGNATURE
|
| 428 |
try:
|
| 429 |
signature = model_repository.resolve_model_repository().signature
|
|
|
|
| 436 |
_MAP_SUPPORT_WARMUP_SIGNATURE = signature
|
| 437 |
|
| 438 |
def _worker() -> None:
|
| 439 |
+
delay = max(0.0, float(delay_seconds))
|
| 440 |
+
if delay > 0:
|
| 441 |
+
sleep(delay)
|
| 442 |
try:
|
| 443 |
get_bairros_geojson()
|
| 444 |
+
except Exception as exc:
|
| 445 |
+
append_runtime_log(f"[mesa] warmup: falha ao aquecer bairros: {exc}")
|
| 446 |
try:
|
| 447 |
pesquisa_service.obter_familias_versoes_modelos_cache()
|
| 448 |
+
except Exception as exc:
|
| 449 |
+
append_runtime_log(f"[mesa] warmup: falha ao aquecer familias de modelos: {exc}")
|
| 450 |
|
| 451 |
+
Thread(target=_worker, name="mesa-visualizacao-support-warmup", daemon=True).start()
|
| 452 |
|
| 453 |
|
| 454 |
def carregar_modelo_repositorio(session: SessionState, modelo_id: str) -> dict[str, Any]:
|
|
|
|
| 478 |
session.dados_visualizacao = None
|
| 479 |
session.avaliacoes_visualizacao = []
|
| 480 |
session.visualizacao_cache = {}
|
|
|
|
| 481 |
|
| 482 |
nome_modelo = Path(caminho_arquivo).stem
|
| 483 |
badge_html = viz_app._formatar_badge_completo(pacote, nome_modelo=nome_modelo)
|