File size: 8,229 Bytes
d6c9678
 
 
 
 
3ee46e7
d6c9678
 
 
3ee46e7
385f196
 
d6c9678
 
 
 
 
 
 
 
 
 
c485ae0
 
 
 
d6c9678
 
c485ae0
d6c9678
 
9e7c650
 
 
 
 
1426bed
 
 
 
d6c9678
 
 
1426bed
 
d6c9678
 
21fc066
 
1426bed
 
21fc066
 
d6c9678
 
 
 
 
 
 
 
 
2a8204e
 
 
 
d6c9678
 
 
 
 
 
 
 
 
 
 
2a8204e
385f196
 
 
 
 
 
 
 
 
 
 
2a8204e
 
 
385f196
2a8204e
385f196
 
 
 
 
 
 
 
 
 
 
2a8204e
 
d6c9678
c485ae0
d6c9678
1426bed
 
c485ae0
1426bed
 
9e7c650
 
 
 
 
 
 
 
 
 
 
 
1426bed
d6c9678
 
614e632
 
 
 
 
 
d6c9678
1426bed
d6c9678
1426bed
 
 
c485ae0
1426bed
 
 
 
 
 
 
 
 
d6c9678
 
3ee46e7
 
 
 
 
 
 
 
 
d6c9678
 
 
 
 
 
 
385f196
d6c9678
385f196
1426bed
 
 
 
 
 
 
385f196
 
 
 
 
 
 
 
 
d6c9678
 
21fc066
 
 
 
1426bed
 
 
 
 
 
21fc066
 
 
 
 
 
 
 
 
 
d6c9678
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9a6f968
 
 
 
 
 
 
 
 
 
 
d6c9678
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
from __future__ import annotations

import os
from typing import Any

from fastapi import APIRouter, File, Form, HTTPException, Request, UploadFile
from fastapi.responses import FileResponse
from pydantic import BaseModel

from app.core.map_layers import get_bairros_geojson
from app.services import auth_service, elaboracao_service, visualizacao_service
from app.services.audit_log_service import log_event
from app.services.session_store import session_store


router = APIRouter(prefix="/api/visualizacao", tags=["visualizacao"])


class SessionPayload(BaseModel):
    session_id: str


class ExibirPayload(SessionPayload):
    trabalhos_tecnicos_modelos_modo: str | None = None


class MapaPayload(SessionPayload):
    variavel_mapa: str | None = None
    trabalhos_tecnicos_modelos_modo: str | None = None


class SecaoPayload(SessionPayload):
    secao: str
    trabalhos_tecnicos_modelos_modo: str | None = None


class MapaPopupPayload(SessionPayload):
    row_id: int


class AvaliacaoPayload(SessionPayload):
    valores_x: dict[str, Any]
    indice_base: str | None = None
    avaliando_lat: float | None = None
    avaliando_lon: float | None = None


class AvaliacaoKnnDetalhesPayload(SessionPayload):
    valores_x: dict[str, Any]
    avaliando_lat: float | None = None
    avaliando_lon: float | None = None


class AvaliacaoDeletePayload(SessionPayload):
    indice: str | None = None
    indice_base: str | None = None


class AvaliacaoBasePayload(SessionPayload):
    indice_base: str | None = None


class RepositorioModeloPayload(SessionPayload):
    modelo_id: str


@router.post("/upload")
async def upload_file(
    session_id: str = Form(...),
    file: UploadFile = File(...),
) -> dict[str, Any]:
    session = session_store.get(session_id)
    conteudo = await file.read()
    caminho = elaboracao_service.save_uploaded_file(session, file.filename, conteudo)
    return visualizacao_service.carregar_modelo(session, caminho)


@router.get("/repositorio-modelos")
def repositorio_modelos(request: Request) -> dict[str, Any]:
    user = auth_service.require_user(request)
    resposta = visualizacao_service.listar_modelos_repositorio()
    log_event(
        "repositorio",
        "listar_modelos_visualizacao",
        user=user,
        request=request,
        details={"total_modelos": resposta.get("total_modelos")},
    )
    return resposta


@router.post("/repositorio-carregar")
def repositorio_carregar(payload: RepositorioModeloPayload, request: Request) -> dict[str, Any]:
    session = session_store.get(payload.session_id)
    user = auth_service.require_user(request)
    resposta = visualizacao_service.carregar_modelo_repositorio(session, payload.modelo_id)
    log_event(
        "repositorio",
        "carregar_modelo_visualizacao",
        user=user,
        session_id=payload.session_id,
        request=request,
        details={"modelo_id": payload.modelo_id},
    )
    return resposta


@router.post("/exibir")
def exibir(payload: ExibirPayload, request: Request) -> dict[str, Any]:
    session = session_store.get(payload.session_id)
    return visualizacao_service.exibir_modelo(
        session,
        trabalhos_tecnicos_modelos_modo=payload.trabalhos_tecnicos_modelos_modo,
        api_base_url=str(request.base_url).rstrip("/"),
        popup_auth_token=getattr(request.state, "auth_token", None),
    )


@router.post("/section")
def section(payload: SecaoPayload, request: Request) -> dict[str, Any]:
    session = session_store.get(payload.session_id)
    return visualizacao_service.carregar_secao_modelo(
        session,
        payload.secao,
        trabalhos_tecnicos_modelos_modo=payload.trabalhos_tecnicos_modelos_modo,
        api_base_url=str(request.base_url).rstrip("/"),
        popup_auth_token=getattr(request.state, "auth_token", None),
    )


@router.post("/evaluation/context")
def evaluation_context(payload: SessionPayload) -> dict[str, Any]:
    session = session_store.get(payload.session_id)
    return visualizacao_service.exibir_contexto_avaliacao(session)


@router.post("/map/update")
def map_update(payload: MapaPayload, request: Request) -> dict[str, Any]:
    session = session_store.get(payload.session_id)
    return visualizacao_service.atualizar_mapa(
        session,
        payload.variavel_mapa,
        trabalhos_tecnicos_modelos_modo=payload.trabalhos_tecnicos_modelos_modo,
        api_base_url=str(request.base_url).rstrip("/"),
        popup_auth_token=getattr(request.state, "auth_token", None),
    )


@router.post("/map/popup")
def map_popup(payload: MapaPopupPayload) -> dict[str, Any]:
    session = session_store.get(payload.session_id)
    return visualizacao_service.carregar_popup_ponto_mapa(session, payload.row_id)


@router.get("/map/bairros.geojson")
def map_bairros_geojson(request: Request) -> dict[str, Any]:
    auth_service.require_user(request)
    geojson = get_bairros_geojson()
    if not isinstance(geojson, dict):
        raise HTTPException(status_code=404, detail="Camada de bairros indisponivel")
    return geojson


@router.post("/evaluation/fields")
def evaluation_fields(payload: SessionPayload) -> dict[str, Any]:
    session = session_store.get(payload.session_id)
    return {"campos": visualizacao_service.campos_avaliacao(session)}


@router.post("/evaluation/calculate")
def evaluation_calculate(payload: AvaliacaoPayload, request: Request) -> dict[str, Any]:
    session = session_store.get(payload.session_id)
    user = auth_service.require_user(request)
    resposta = visualizacao_service.calcular_avaliacao(
        session,
        payload.valores_x,
        payload.indice_base,
        payload.avaliando_lat,
        payload.avaliando_lon,
    )
    log_event(
        "visualizacao",
        "avaliacao_calcular",
        user=user,
        session_id=payload.session_id,
        request=request,
        details={"total_avaliacoes": len(resposta.get("avaliacoes") or [])},
    )
    return resposta


@router.post("/evaluation/knn-details")
def evaluation_knn_details(payload: AvaliacaoKnnDetalhesPayload, request: Request) -> dict[str, Any]:
    session = session_store.get(payload.session_id)
    user = auth_service.require_user(request)
    resposta = visualizacao_service.detalhes_knn_avaliacao(
        session,
        payload.valores_x,
        payload.avaliando_lat,
        payload.avaliando_lon,
    )
    log_event(
        "visualizacao",
        "avaliacao_knn_detalhes",
        user=user,
        session_id=payload.session_id,
        request=request,
    )
    return resposta


@router.post("/evaluation/clear")
def evaluation_clear(payload: SessionPayload) -> dict[str, Any]:
    session = session_store.get(payload.session_id)
    return visualizacao_service.limpar_avaliacoes(session)


@router.post("/evaluation/delete")
def evaluation_delete(payload: AvaliacaoDeletePayload) -> dict[str, Any]:
    session = session_store.get(payload.session_id)
    return visualizacao_service.excluir_avaliacao(session, payload.indice, payload.indice_base)


@router.post("/evaluation/base")
def evaluation_base(payload: AvaliacaoBasePayload) -> dict[str, Any]:
    session = session_store.get(payload.session_id)
    return visualizacao_service.atualizar_base(session, payload.indice_base)


@router.get("/evaluation/export")
def evaluation_export(session_id: str) -> FileResponse:
    session = session_store.get(session_id)
    caminho = visualizacao_service.exportar_avaliacoes(session)
    return FileResponse(
        path=caminho,
        media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        filename=os.path.basename(caminho),
    )


@router.get("/equation/export")
def equation_export(session_id: str, mode: str = "excel") -> FileResponse:
    session = session_store.get(session_id)
    caminho, nome = visualizacao_service.exportar_equacao(session, mode)
    return FileResponse(
        path=caminho,
        media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        filename=nome,
    )


@router.post("/clear")
def clear(payload: SessionPayload) -> dict[str, Any]:
    session = session_store.get(payload.session_id)
    return visualizacao_service.limpar_tudo_visualizacao(session)