alessandro trinca tornidor
commited on
Commit
Β·
8783164
1
Parent(s):
2b9f7fd
feat: first attempt to support samgis-lisa-on-cuda on ZeroGPU huggingface space
Browse files- .idea/inspectionProfiles/Project_Default.xml +6 -0
- .idea/misc.xml +2 -2
- Dockerfile +0 -208
- README.md +9 -131
- wrappers/fastapi_wrapper.py β app.py +46 -21
- dockerfiles/dockerfile-lisa-predictions +1 -1
- packages.txt +2 -0
- poetry.lock +0 -0
- pyproject.toml +14 -42
- requirements.txt +15 -0
- {samgis_lisa_on_cuda β samgis_lisa_on_zero}/__init__.py +2 -2
- {samgis_lisa_on_cuda β samgis_lisa_on_zero}/__version__.py +0 -0
- {samgis_lisa_on_cuda β samgis_lisa_on_zero}/io/__init__.py +0 -0
- {samgis_lisa_on_cuda β samgis_lisa_on_zero}/io/coordinates_pixel_conversion.py +4 -4
- {samgis_lisa_on_cuda β samgis_lisa_on_zero}/io/geo_helpers.py +1 -1
- {samgis_lisa_on_cuda β samgis_lisa_on_zero}/io/raster_helpers.py +5 -5
- {samgis_lisa_on_cuda β samgis_lisa_on_zero}/io/tms2geotiff.py +6 -6
- {samgis_lisa_on_cuda β samgis_lisa_on_zero}/io/wrappers_helpers.py +4 -4
- {samgis_lisa_on_cuda β samgis_lisa_on_zero}/prediction_api/__init__.py +0 -0
- {samgis_lisa_on_cuda β samgis_lisa_on_zero}/prediction_api/global_models.py +1 -1
- {samgis_lisa_on_cuda β samgis_lisa_on_zero}/prediction_api/lisa.py +25 -13
- {samgis_lisa_on_cuda β samgis_lisa_on_zero}/prediction_api/predictors.py +7 -7
- {samgis_lisa_on_cuda β samgis_lisa_on_zero}/utilities/__init__.py +0 -0
- {samgis_lisa_on_cuda β samgis_lisa_on_zero}/utilities/constants.py +1 -0
- {samgis_lisa_on_cuda β samgis_lisa_on_zero}/utilities/session_logger.py +0 -0
- {samgis_lisa_on_cuda β samgis_lisa_on_zero}/utilities/type_hints.py +0 -0
- scripts/extract-openapi-fastapi.py +1 -1
- scripts/extract-openapi-lambda.py +2 -2
- static/vite.config.ts +24 -21
- tests/__init__.py +1 -1
- tests/io/test_coordinates_pixel_conversion.py +2 -2
- tests/io/test_geo_helpers.py +3 -3
- tests/io/test_raster_helpers.py +3 -3
- tests/io/test_tms2geotiff.py +2 -2
- tests/io/test_wrappers_helpers.py +5 -5
- tests/prediction_api/test_predictors.py +2 -2
- tests/test_fastapi_app.py +4 -4
- tests/test_lambda_app.py +2 -2
- wrappers/__init__.py +0 -0
- wrappers/lambda_wrapper.py +0 -58
.idea/inspectionProfiles/Project_Default.xml
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<component name="InspectionProjectProfileManager">
|
2 |
+
<profile version="1.0">
|
3 |
+
<option name="myName" value="Project Default" />
|
4 |
+
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
5 |
+
</profile>
|
6 |
+
</component>
|
.idea/misc.xml
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
<project version="4">
|
3 |
<component name="Black">
|
4 |
-
<option name="sdkName" value="Poetry (samgis-lisa-on-
|
5 |
</component>
|
6 |
-
<component name="ProjectRootManager" version="2" project-jdk-name="Poetry (samgis-lisa-on-
|
7 |
</project>
|
|
|
1 |
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
<project version="4">
|
3 |
<component name="Black">
|
4 |
+
<option name="sdkName" value="Poetry (samgis-lisa-on-zero)" />
|
5 |
</component>
|
6 |
+
<component name="ProjectRootManager" version="2" project-jdk-name="Poetry (samgis-lisa-on-zero)" project-jdk-type="Python SDK" />
|
7 |
</project>
|
Dockerfile
DELETED
@@ -1,208 +0,0 @@
|
|
1 |
-
# Include global ARGs at the dockerfile top
|
2 |
-
ARG ARCH="x86_64"
|
3 |
-
ARG LAMBDA_TASK_ROOT="/var/task"
|
4 |
-
ARG FASTAPI_STATIC="${LAMBDA_TASK_ROOT}/static"
|
5 |
-
ARG PYTHONPATH="${LAMBDA_TASK_ROOT}:${PYTHONPATH}:/usr/local/lib/python3/dist-packages"
|
6 |
-
ARG POETRY_NO_INTERACTION=1
|
7 |
-
ARG POETRY_VIRTUALENVS_IN_PROJECT=1
|
8 |
-
ARG POETRY_VIRTUALENVS_CREATE=1
|
9 |
-
ARG POETRY_CACHE_DIR=/tmp/poetry_cache
|
10 |
-
ARG DEPENDENCY_GROUP=fastapi
|
11 |
-
|
12 |
-
|
13 |
-
FROM pytorch/pytorch:2.2.2-cuda12.1-cudnn8-runtime as builder_global
|
14 |
-
|
15 |
-
LABEL authors="alessandro@trinca.tornidor.com"
|
16 |
-
|
17 |
-
ARG ARCH
|
18 |
-
ARG LAMBDA_TASK_ROOT
|
19 |
-
ARG PYTHONPATH
|
20 |
-
ARG POETRY_NO_INTERACTION
|
21 |
-
ARG POETRY_VIRTUALENVS_IN_PROJECT
|
22 |
-
ARG POETRY_VIRTUALENVS_CREATE
|
23 |
-
ARG POETRY_CACHE_DIR
|
24 |
-
ARG DEPENDENCY_GROUP
|
25 |
-
|
26 |
-
RUN echo "ARCH: $ARCH ..."
|
27 |
-
|
28 |
-
RUN echo "ARG POETRY_CACHE_DIR: ${POETRY_CACHE_DIR} ..."
|
29 |
-
RUN echo "ARG PYTHONPATH: $PYTHONPATH ..."
|
30 |
-
RUN test -n ${DEPENDENCY_GROUP:?}
|
31 |
-
RUN echo "python DEPENDENCY_GROUP: ${DEPENDENCY_GROUP} ..."
|
32 |
-
RUN echo "arg dep:"
|
33 |
-
|
34 |
-
# Set working directory to function root directory
|
35 |
-
WORKDIR ${LAMBDA_TASK_ROOT}
|
36 |
-
COPY requirements_poetry.txt pyproject.toml poetry.lock README.md ${LAMBDA_TASK_ROOT}/
|
37 |
-
|
38 |
-
RUN cat /etc/lsb-release
|
39 |
-
# avoid segment-geospatial exception caused by missing libGL.so.1 library
|
40 |
-
RUN echo "BUILDER: check libz.s* before start" && ls -l /usr/lib/${ARCH}-linux-gnu/libz.so*
|
41 |
-
|
42 |
-
RUN apt update && apt upgrade -y && apt install -y libgl1 curl python3-pip git-lfs && apt clean
|
43 |
-
COPY ./dockerfiles/apt_preferences_ubuntu /etc/apt/preferences
|
44 |
-
COPY ./dockerfiles/ubuntu.sources /etc/apt/sources.list.d/ubuntu.sources
|
45 |
-
#RUN echo "run update noble..."
|
46 |
-
#RUN apt update
|
47 |
-
#RUN apt update && apt install -t noble zlib1g -y
|
48 |
-
RUN git lfs install
|
49 |
-
RUN echo "BUILDER: check libz.s* after install from trixie" && ls -l /usr/lib/${ARCH}-linux-gnu/libz.so*
|
50 |
-
|
51 |
-
RUN ls -l /etc/apt/sources* /etc/apt/preferences*
|
52 |
-
|
53 |
-
# poetry installation path is NOT within ${LAMBDA_TASK_ROOT}: not needed for runtime docker image
|
54 |
-
RUN python -m pip install -r ${LAMBDA_TASK_ROOT}/requirements_poetry.txt
|
55 |
-
|
56 |
-
RUN which poetry && poetry --version && poetry config --list
|
57 |
-
RUN poetry config virtualenvs.path ${LAMBDA_TASK_ROOT}
|
58 |
-
RUN poetry config installer.max-workers 7
|
59 |
-
RUN echo "# poetry config --list #" && poetry config --list
|
60 |
-
RUN ls -ld ${LAMBDA_TASK_ROOT}/
|
61 |
-
#RUN . ${LAMBDA_TASK_ROOT}/.venv/bin/activate && ${LAMBDA_TASK_ROOT}/.venv/bin/python --version && ${LAMBDA_TASK_ROOT}/.venv/bin/python -m pip install pip wheel setuptools --upgrade
|
62 |
-
RUN poetry run python -m pip install pip wheel setuptools --upgrade
|
63 |
-
RUN poetry install --with ${DEPENDENCY_GROUP} --no-root
|
64 |
-
|
65 |
-
RUN git clone https://huggingface.co/aletrn/sam-quantized/ ${LAMBDA_TASK_ROOT}/sam-quantized
|
66 |
-
RUN git clone -n --depth=1 --filter=tree:0 https://huggingface.co/spaces/aletrn/lisa-on-cuda ${LAMBDA_TASK_ROOT}/lisa-on-cuda && \
|
67 |
-
cd ${LAMBDA_TASK_ROOT}/lisa-on-cuda && \
|
68 |
-
git sparse-checkout set --no-cone resources && \
|
69 |
-
git checkout
|
70 |
-
WORKDIR ${LAMBDA_TASK_ROOT}
|
71 |
-
RUN ls -l ${LAMBDA_TASK_ROOT}/*
|
72 |
-
|
73 |
-
|
74 |
-
FROM pytorch/pytorch:2.2.2-cuda12.1-cudnn8-runtime as runtime
|
75 |
-
|
76 |
-
ARG ARCH
|
77 |
-
ARG LAMBDA_TASK_ROOT
|
78 |
-
|
79 |
-
ENV VIRTUAL_ENV=${LAMBDA_TASK_ROOT}/.venv \
|
80 |
-
PATH="${LAMBDA_TASK_ROOT}/.venv/bin:$PATH"
|
81 |
-
|
82 |
-
RUN echo "COPY --from=builder_global /usr/lib/${ARCH}-linux-gnu/libGL.so* /usr/lib/${ARCH}-linux-gnu/"
|
83 |
-
COPY --from=builder_global /usr/lib/${ARCH}-linux-gnu/libGL.so* /usr/lib/${ARCH}-linux-gnu/
|
84 |
-
RUN echo "RUNTIME: check libz.s* before upgrade" && ls -l /usr/lib/${ARCH}-linux-gnu/libz.so*
|
85 |
-
RUN echo "RUNTIME: remove libz.s* to force upgrade" && rm /usr/lib/${ARCH}-linux-gnu/libz.so*
|
86 |
-
COPY --from=builder_global /usr/lib/${ARCH}-linux-gnu/libz.so* /usr/lib/${ARCH}-linux-gnu/
|
87 |
-
RUN echo "RUNTIME: check libz.s* after copy" && ls -l /usr/lib/${ARCH}-linux-gnu/libz.so*
|
88 |
-
COPY --from=builder_global ${LAMBDA_TASK_ROOT}/.venv ${LAMBDA_TASK_ROOT}/.venv
|
89 |
-
|
90 |
-
RUN echo "new LAMBDA_TASK_ROOT after hidden venv copy => ${LAMBDA_TASK_ROOT}"
|
91 |
-
RUN ls -ld ${LAMBDA_TASK_ROOT}/
|
92 |
-
RUN ls -lA ${LAMBDA_TASK_ROOT}/
|
93 |
-
RUN echo "content of LAMBDA_TASK_ROOT/.venv => ${LAMBDA_TASK_ROOT}/.venv"
|
94 |
-
RUN ls -ld ${LAMBDA_TASK_ROOT}/.venv
|
95 |
-
RUN ls -lA ${LAMBDA_TASK_ROOT}/.venv
|
96 |
-
|
97 |
-
|
98 |
-
### conditional section
|
99 |
-
FROM node:20-slim AS node_fastapi
|
100 |
-
|
101 |
-
ARG DEPENDENCY_GROUP
|
102 |
-
ENV PNPM_HOME="/pnpm"
|
103 |
-
ENV PATH="$PNPM_HOME:$PATH"
|
104 |
-
|
105 |
-
RUN corepack enable
|
106 |
-
|
107 |
-
COPY ./static /appnode
|
108 |
-
WORKDIR /appnode
|
109 |
-
# RUN if [ "${DEPENDENCY_GROUP}" = "fastapi" ]; then echo "pnpm store path:" && pnpm store path; fi
|
110 |
-
RUN ls -l /appnode
|
111 |
-
RUN ls -l /appnode/list_files.html
|
112 |
-
|
113 |
-
|
114 |
-
FROM node_fastapi AS node_prod_deps
|
115 |
-
|
116 |
-
ARG DEPENDENCY_GROUP
|
117 |
-
RUN --mount=type=cache,id=pnpm,target=/pnpm/store if [ "${DEPENDENCY_GROUP}" = "fastapi" ]; then \
|
118 |
-
pnpm install --prod --frozen-lockfile; else \
|
119 |
-
echo "DEPENDENCY_GROUP 1: ${DEPENDENCY_GROUP} ..."; fi
|
120 |
-
# here multiple conditions concatenated to avoid failing on check
|
121 |
-
RUN if [ "${DEPENDENCY_GROUP}" = "fastapi" ]; then if [ ! -d /appnode/node_modules ]; then \
|
122 |
-
echo "no node_modules folder" && exit 1; fi; fi
|
123 |
-
|
124 |
-
|
125 |
-
FROM node_fastapi AS node_build
|
126 |
-
|
127 |
-
ARG DEPENDENCY_GROUP
|
128 |
-
ARG VITE__MAP_DESCRIPTION
|
129 |
-
ARG VITE__SAMGIS_SPACE
|
130 |
-
RUN echo "VITE__MAP_DESCRIPTION:" ${VITE__MAP_DESCRIPTION}
|
131 |
-
RUN echo "VITE__SAMGIS_SPACE:" ${VITE__SAMGIS_SPACE}
|
132 |
-
|
133 |
-
RUN --mount=type=cache,id=pnpm,target=/pnpm/store if [ "${DEPENDENCY_GROUP}" = "fastapi" ]; then \
|
134 |
-
pnpm install --frozen-lockfile; else \
|
135 |
-
echo "DEPENDENCY_GROUP 2: ${DEPENDENCY_GROUP} ..."; fi
|
136 |
-
RUN --mount=type=cache,id=pnpm,target=/pnpm/store if [ "${DEPENDENCY_GROUP}" = "fastapi" ]; then pnpm build; fi
|
137 |
-
RUN --mount=type=cache,id=pnpm,target=/pnpm/store if [ "${DEPENDENCY_GROUP}" = "fastapi" ]; then \
|
138 |
-
pnpm tailwindcss -i /appnode/src/input.css -o /appnode/dist/output.css; fi
|
139 |
-
RUN if [ "${DEPENDENCY_GROUP}" = "fastapi" ]; then if [ ! -d /appnode/dist ]; then echo "no dist folder" && exit 1; fi; fi
|
140 |
-
|
141 |
-
|
142 |
-
FROM runtime
|
143 |
-
ARG FASTAPI_STATIC
|
144 |
-
|
145 |
-
RUN echo "show disk space, df -h ..."
|
146 |
-
RUN df -h
|
147 |
-
RUN echo "creating FASTAPI_STATIC folder: ${FASTAPI_STATIC}, use `mkdir -p` to avoid failure if missing parent folder ..."
|
148 |
-
RUN mkdir -p ${FASTAPI_STATIC}
|
149 |
-
|
150 |
-
COPY --from=builder_global ${LAMBDA_TASK_ROOT}/sam-quantized/machine_learning_models \
|
151 |
-
${LAMBDA_TASK_ROOT}/machine_learning_models
|
152 |
-
RUN ls -ld ${LAMBDA_TASK_ROOT}/machine_learning_models
|
153 |
-
RUN ls -lh ${LAMBDA_TASK_ROOT}/machine_learning_models
|
154 |
-
COPY --from=builder_global ${LAMBDA_TASK_ROOT}/lisa-on-cuda/resources ${LAMBDA_TASK_ROOT}/resources
|
155 |
-
COPY --from=node_prod_deps /appnode/node_modules* ${FASTAPI_STATIC}/node_modules
|
156 |
-
COPY --from=node_build /appnode/dist* ${FASTAPI_STATIC}/dist
|
157 |
-
COPY --from=node_build /appnode/list_files.html ${FASTAPI_STATIC}/list_files.html
|
158 |
-
RUN ls -l ${FASTAPI_STATIC}/
|
159 |
-
RUN ls -l ${FASTAPI_STATIC}/list_files.html
|
160 |
-
|
161 |
-
|
162 |
-
# Include global arg in this stage of the build
|
163 |
-
ARG LAMBDA_TASK_ROOT="/var/task"
|
164 |
-
ARG PYTHONPATH="${LAMBDA_TASK_ROOT}:${PYTHONPATH}:/usr/local/lib/python3/dist-packages"
|
165 |
-
ENV VIRTUAL_ENV=${LAMBDA_TASK_ROOT}/.venv \
|
166 |
-
PATH="${LAMBDA_TASK_ROOT}/.venv/bin:$PATH"
|
167 |
-
ENV IS_AWS_LAMBDA=""
|
168 |
-
|
169 |
-
# Set working directory to function root directory
|
170 |
-
WORKDIR ${LAMBDA_TASK_ROOT}
|
171 |
-
|
172 |
-
COPY samgis_lisa_on_cuda ${LAMBDA_TASK_ROOT}/samgis_lisa_on_cuda
|
173 |
-
COPY wrappers ${LAMBDA_TASK_ROOT}/wrappers
|
174 |
-
COPY scripts ${LAMBDA_TASK_ROOT}/scripts
|
175 |
-
RUN chmod +x ${LAMBDA_TASK_ROOT}/scripts/entrypoint.sh
|
176 |
-
RUN chmod +x ${LAMBDA_TASK_ROOT}/scripts/docker_entrypoint.sh
|
177 |
-
RUN ls -l ${LAMBDA_TASK_ROOT}/scripts/entrypoint.sh ${LAMBDA_TASK_ROOT}/scripts/docker_entrypoint.sh
|
178 |
-
|
179 |
-
RUN ls -l /usr/bin/which
|
180 |
-
RUN /usr/bin/which python
|
181 |
-
RUN python --version
|
182 |
-
RUN echo "PYTHONPATH: ${PYTHONPATH}."
|
183 |
-
RUN echo "PATH: ${PATH}."
|
184 |
-
RUN echo "LAMBDA_TASK_ROOT: ${LAMBDA_TASK_ROOT}."
|
185 |
-
RUN ls -l ${LAMBDA_TASK_ROOT}
|
186 |
-
RUN ls -ld ${LAMBDA_TASK_ROOT}
|
187 |
-
RUN ls -l ${LAMBDA_TASK_ROOT}/machine_learning_models
|
188 |
-
RUN python -c "import sys; print(sys.path)"
|
189 |
-
RUN python -c "import cv2"
|
190 |
-
RUN python -c "import fastapi"
|
191 |
-
RUN python -c "import geopandas"
|
192 |
-
RUN python -c "import loguru"
|
193 |
-
RUN python -c "import onnxruntime"
|
194 |
-
RUN python -c "import rasterio"
|
195 |
-
RUN python -c "import uvicorn"
|
196 |
-
RUN df -h
|
197 |
-
RUN ls -l ${LAMBDA_TASK_ROOT}/samgis_lisa_on_cuda/
|
198 |
-
RUN ls -l ${LAMBDA_TASK_ROOT}/wrappers/
|
199 |
-
RUN echo "LAMBDA_TASK_ROOT /static/:"
|
200 |
-
RUN ls -l ${LAMBDA_TASK_ROOT}/static/ || true
|
201 |
-
RUN ls -l ${LAMBDA_TASK_ROOT}/static/dist || true
|
202 |
-
RUN ls -l ${LAMBDA_TASK_ROOT}/static/node_modules || true
|
203 |
-
RUN echo "FASTAPI_STATIC:"
|
204 |
-
RUN ls -l ${FASTAPI_STATIC}/ || true
|
205 |
-
RUN ls -l ${FASTAPI_STATIC}/dist || true
|
206 |
-
RUN ls -l ${FASTAPI_STATIC}/node_modules || true
|
207 |
-
|
208 |
-
CMD ["/var/task/scripts/docker_entrypoint.sh"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
README.md
CHANGED
@@ -1,143 +1,21 @@
|
|
1 |
---
|
2 |
-
title: SamGIS - LISA on
|
3 |
emoji: πΊοΈ
|
4 |
colorFrom: red
|
5 |
colorTo: blue
|
6 |
-
sdk:
|
7 |
-
|
|
|
|
|
8 |
license: mit
|
9 |
---
|
10 |
|
11 |
-
# [LISA](https://github.com/dvlab-research/LISA)
|
12 |
|
13 |
[LISA](https://github.com/dvlab-research/LISA) (Reasoning Segmentation via Large Language Model) applied to geospatial data thanks to [SamGIS](https://github.com/trincadev/samgis-be).
|
14 |
|
15 |
-
|
16 |
|
17 |
-
|
18 |
-
from https://huggingface.co/aletrn/sam-quantized (copy them within the folder `/machine_learning_models`).
|
19 |
|
20 |
-
|
21 |
-
|
22 |
-
The SamGIS HuggingSpace url is https://huggingface.co/spaces/aletrn/samgis-lisa-on-cuda.
|
23 |
-
Build the docker image this way:
|
24 |
-
|
25 |
-
```bash
|
26 |
-
# clean any old active containers
|
27 |
-
docker stop $(docker ps -a -q); docker rm $(docker ps -a -q)
|
28 |
-
|
29 |
-
# build the base docker image from the repository root folder using ARGs:
|
30 |
-
# - DEPENDENCY_GROUP=fastapi used by poetry
|
31 |
-
# VITE__MAP_DESCRIPTION, VITE__SAMGIS_SPACE used by 'docker build'
|
32 |
-
(
|
33 |
-
set -o allexport && source <(cat ./static/.env|grep VITE__) && set +o allexport;
|
34 |
-
env|grep VITE__;
|
35 |
-
docker build . -f dockerfiles/dockerfile-samgis-base --progress=plain \
|
36 |
-
--build-arg DEPENDENCY_GROUP=fastapi \
|
37 |
-
--build-arg VITE__MAP_DESCRIPTION=${VITE__MAP_DESCRIPTION} \
|
38 |
-
--build-arg VITE__SAMGIS_SPACE=${VITE__SAMGIS_SPACE} \
|
39 |
-
--tag registry.gitlab.com/aletrn/gis-prediction
|
40 |
-
)
|
41 |
-
|
42 |
-
# build the image, use the tag "samgis-huggingface"
|
43 |
-
docker build . --tag example-docker-namespace/samgis-huggingface --progress=plain
|
44 |
-
```
|
45 |
-
|
46 |
-
Run the container (keep it on background) and show logs
|
47 |
-
|
48 |
-
```bash
|
49 |
-
docker run -d --name samgis-huggingface -p 7860:7860 example-docker-namespace/samgis-huggingface; docker logs -f samgis-huggingface
|
50 |
-
```
|
51 |
-
|
52 |
-
Test it with curl using a json payload:
|
53 |
-
|
54 |
-
```bash
|
55 |
-
URL=http://localhost:7860/infer_samgis
|
56 |
-
curl -d@./events/payload_point_eolie.json -H 'accept: application/json' ${URL}
|
57 |
-
```
|
58 |
-
|
59 |
-
or better visiting the swagger page on http://localhost:7860/docs
|
60 |
-
|
61 |
-
### Dependencies installation and local tests
|
62 |
-
The docker build process needs only the base dependency group plus the `aws_lambda` or `fastapi` optional one.
|
63 |
-
Install also the `test` and/or `docs` groups if needed.
|
64 |
-
|
65 |
-
### Tests
|
66 |
-
|
67 |
-
Tests are defined in the `tests` folder in this project. Use PIP to install the test dependencies and run tests.
|
68 |
-
|
69 |
-
```bash
|
70 |
-
python -m pytest --cov=samgis_lisa_on_cuda --cov-report=term-missing && coverage html
|
71 |
-
```
|
72 |
-
|
73 |
-
### How to update the static documentation with sphinx
|
74 |
-
|
75 |
-
This project documentation uses sphinx-apidoc: it's a tool for automatic generation of Sphinx sources that, using the autodoc
|
76 |
-
extension, document a whole package in the style of other automatic API documentation tools. See the
|
77 |
-
[documentation page](https://www.sphinx-doc.org/en/master/man/sphinx-apidoc.html) for details.
|
78 |
-
Run the command from the project root:
|
79 |
-
|
80 |
-
```bash
|
81 |
-
# missing docs folder (run from project root) initialize this way
|
82 |
-
cd docs && sphinx-quickstart -p SamGIS -r 1.0.0 -l python --master index
|
83 |
-
|
84 |
-
# update docs folder (from project root)
|
85 |
-
sphinx-apidoc -f -o docs samgis
|
86 |
-
```
|
87 |
-
|
88 |
-
Then it's possible to generate the HTML pages
|
89 |
-
|
90 |
-
```bash
|
91 |
-
cd docs && make html && ../
|
92 |
-
|
93 |
-
# to clean old files
|
94 |
-
cd docs && make clean html && cd ../
|
95 |
-
```
|
96 |
-
|
97 |
-
The static documentation it's now ready at the path `docs/_build/html/index.html`.
|
98 |
-
|
99 |
-
To create a work in progress openapi json or yaml file use
|
100 |
-
|
101 |
-
- `extract-openapi-fastapi.py`
|
102 |
-
- `extract-openapi-lambda.py` (useful to export the json schema request and response from lambda app api)
|
103 |
-
|
104 |
-
### Handle dynamic folder creation
|
105 |
-
|
106 |
-
it's possible to dynamically create a new support folder adding it to a json string env FOLDERS_MAP, e.g.:
|
107 |
-
|
108 |
-
```json
|
109 |
-
{
|
110 |
-
"WORKDIR": "/var/task",
|
111 |
-
"XDG_CACHE_HOME": "/data",
|
112 |
-
"PROJECT_ROOT_FOLDER": "/data",
|
113 |
-
"MPLCONFIGDIR": "/data/.cache/matplotlib",
|
114 |
-
"TRANSFORMERS_CACHE": "/data/.cache/transformers",
|
115 |
-
"PYTORCH_KERNEL_CACHE_PATH": "/data/.cache/torch/kernels",
|
116 |
-
"FASTAPI_STATIC": "/var/task/static",
|
117 |
-
"VIS_OUTPUT": "/data/vis_output"
|
118 |
-
}
|
119 |
-
```
|
120 |
-
|
121 |
-
The python script create_folders_and_variables_if_not_exists.py will read this env variable, removing any files that exists with these pathnames and assert the correct creation of all the folders. Also these folders must exist as env variables, so the script assert that an env variable exists with its path.
|
122 |
-
|
123 |
-
It's possible to use the project in a bare metal installation (not within a docker container). To do this
|
124 |
-
|
125 |
-
- download this project
|
126 |
-
- prepare a virtualenv and install the python dependencies
|
127 |
-
- install nodejs LTS
|
128 |
-
- create a .env_source file (in this case `HOME=/home/jovyan`)
|
129 |
-
|
130 |
-
```bash
|
131 |
-
export FOLDERS_MAP='{"WORKDIR":"/home/jovyan/workspace/samgis-lisa-on-cuda","XDG_CACHE_HOME":"/home/jovyan/.cache","PROJECT_ROOT_FOLDER":"/home/jovyan/","MPLCONFIGDIR":"/home/jovyan/.cache/matplotlib","TRANSFORMERS_CACHE":"/home/jovyan/.cache/transformers","PYTORCH_KERNEL_CACHE_PATH":"/home/jovyan/.cache/torch/kernels","FASTAPI_STATIC":"/home/jovyan/workspace/samgis-lisa-on-cuda/static","VIS_OUTPUT":"/home/jovyan/workspace/samgis-lisa-on-cuda/vis_output"}'
|
132 |
-
export WORKDIR="$HOME/workspace/samgis-lisa-on-cuda"
|
133 |
-
export XDG_CACHE_HOME="$HOME/.cache"
|
134 |
-
export PROJECT_ROOT_FOLDER="$HOME/"
|
135 |
-
export MPLCONFIGDIR="$HOME/.cache/matplotlib"
|
136 |
-
export TRANSFORMERS_CACHE="$HOME/.cache/transformers"
|
137 |
-
export PYTORCH_KERNEL_CACHE_PATH="$HOME/.cache/torch/kernels"
|
138 |
-
export FASTAPI_STATIC="$HOME/workspace/samgis-lisa-on-cuda/static"
|
139 |
-
export VIS_OUTPUT="$HOME/workspace/samgis-lisa-on-cuda/vis_output"
|
140 |
-
export WRITE_TMP_ON_DISK=${VIS_OUTPUT}
|
141 |
-
```
|
142 |
-
|
143 |
-
- execute the script `baremetal_entrypoint.sh` instead than `docker_entrypoint.sh`.
|
|
|
1 |
---
|
2 |
+
title: SamGIS - LISA on CUDA
|
3 |
emoji: πΊοΈ
|
4 |
colorFrom: red
|
5 |
colorTo: blue
|
6 |
+
sdk: gradio
|
7 |
+
sdk_version: 4.37.2
|
8 |
+
app_file: app.py
|
9 |
+
pinned: true
|
10 |
license: mit
|
11 |
---
|
12 |
|
13 |
+
# [LISA](https://github.com/dvlab-research/LISA) + [SamGIS](https://github.com/trincadev/samgis-be) on Zero GPU!
|
14 |
|
15 |
[LISA](https://github.com/dvlab-research/LISA) (Reasoning Segmentation via Large Language Model) applied to geospatial data thanks to [SamGIS](https://github.com/trincadev/samgis-be).
|
16 |
|
17 |
+
About SamGIS - LISA on CUDA see the [samgis-lisa-on-cuda demo](https://huggingface.co/spaces/aletrn/samgis-lisa-on-cuda).
|
18 |
|
19 |
+
To change the base relative url for custom frontend add the VITE_PREFIX environment variable, e.g.:
|
|
|
20 |
|
21 |
+
VITE_PREFIX="/custom-url"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
wrappers/fastapi_wrapper.py β app.py
RENAMED
@@ -3,21 +3,29 @@ import os
|
|
3 |
import pathlib
|
4 |
import uuid
|
5 |
|
6 |
-
from fastapi.templating import Jinja2Templates
|
7 |
import uvicorn
|
8 |
from fastapi import FastAPI, HTTPException, Request, status
|
9 |
from fastapi.exceptions import RequestValidationError
|
10 |
from fastapi.responses import FileResponse, HTMLResponse, JSONResponse
|
11 |
from fastapi.staticfiles import StaticFiles
|
|
|
|
|
12 |
from pydantic import ValidationError
|
13 |
-
|
14 |
-
from samgis_lisa_on_cuda import PROJECT_ROOT_FOLDER, WORKDIR
|
15 |
-
from samgis_lisa_on_cuda.utilities.type_hints import ApiRequestBody, StringPromptApiRequestBody
|
16 |
from samgis_core.utilities.fastapi_logger import setup_logging
|
17 |
|
|
|
|
|
|
|
|
|
18 |
|
19 |
-
|
20 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
|
22 |
|
23 |
@app.middleware("http")
|
@@ -42,7 +50,7 @@ async def request_middleware(request, call_next):
|
|
42 |
|
43 |
@app.post("/post_test_dictlist")
|
44 |
def post_test_dictlist2(request_input: ApiRequestBody) -> JSONResponse:
|
45 |
-
from
|
46 |
|
47 |
request_body = get_parsed_bbox_points_with_dictlist_prompt(request_input)
|
48 |
app_logger.info(f"request_body:{request_body}.")
|
@@ -57,13 +65,13 @@ async def health() -> JSONResponse:
|
|
57 |
import importlib.metadata
|
58 |
from importlib.metadata import PackageNotFoundError
|
59 |
|
|
|
60 |
try:
|
61 |
core_version = importlib.metadata.version('samgis_core')
|
62 |
lisa_on_cuda_version = importlib.metadata.version('lisa-on-cuda')
|
63 |
samgis_lisa_on_cuda_version = importlib.metadata.version('samgis-lisa-on-cuda')
|
64 |
except PackageNotFoundError as pe:
|
65 |
app_logger.error(f"pe:{pe}.")
|
66 |
-
samgis_lisa_on_cuda_version = "0.0.0"
|
67 |
|
68 |
msg = "still alive, "
|
69 |
msg += f"""version:{samgis_lisa_on_cuda_version}, core version:{core_version},"""
|
@@ -76,7 +84,7 @@ async def health() -> JSONResponse:
|
|
76 |
@app.post("/post_test_string")
|
77 |
def post_test_string(request_input: StringPromptApiRequestBody) -> JSONResponse:
|
78 |
from lisa_on_cuda.utils import app_helpers
|
79 |
-
from
|
80 |
|
81 |
request_body = get_parsed_bbox_points_with_string_prompt(request_input)
|
82 |
app_logger.info(f"request_body:{request_body}.")
|
@@ -90,8 +98,8 @@ def post_test_string(request_input: StringPromptApiRequestBody) -> JSONResponse:
|
|
90 |
|
91 |
@app.post("/infer_lisa")
|
92 |
def infer_lisa(request_input: StringPromptApiRequestBody) -> JSONResponse:
|
93 |
-
from
|
94 |
-
from
|
95 |
|
96 |
app_logger.info("starting lisa inference request...")
|
97 |
|
@@ -107,7 +115,7 @@ def infer_lisa(request_input: StringPromptApiRequestBody) -> JSONResponse:
|
|
107 |
app_logger.info(f"source_name = {source_name}.")
|
108 |
output = lisa.lisa_predict(
|
109 |
bbox=body_request["bbox"], prompt=body_request["prompt"], zoom=body_request["zoom"],
|
110 |
-
source=body_request["source"], source_name=source_name
|
111 |
)
|
112 |
duration_run = time.time() - time_start_run
|
113 |
app_logger.info(f"duration_run:{duration_run}.")
|
@@ -136,8 +144,8 @@ def infer_lisa(request_input: StringPromptApiRequestBody) -> JSONResponse:
|
|
136 |
|
137 |
@app.post("/infer_samgis")
|
138 |
def infer_samgis(request_input: ApiRequestBody) -> JSONResponse:
|
139 |
-
from
|
140 |
-
from
|
141 |
|
142 |
app_logger.info("starting plain samgis inference request...")
|
143 |
|
@@ -237,32 +245,49 @@ if bool(write_tmp_on_disk):
|
|
237 |
)
|
238 |
|
239 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
240 |
# important: the index() function and the app.mount MUST be at the end
|
241 |
# samgis.html
|
242 |
-
app.mount("/samgis", StaticFiles(directory=
|
243 |
|
244 |
|
245 |
@app.get("/samgis")
|
246 |
async def samgis() -> FileResponse:
|
247 |
-
return FileResponse(path=
|
248 |
|
249 |
|
250 |
# lisa.html
|
251 |
-
app.mount("/lisa", StaticFiles(directory=
|
252 |
|
253 |
|
254 |
@app.get("/lisa")
|
255 |
async def lisa() -> FileResponse:
|
256 |
-
return FileResponse(path=
|
257 |
|
258 |
|
259 |
-
# index.html (lisa.html copy)
|
260 |
-
app.mount("/", StaticFiles(directory=
|
261 |
|
262 |
|
263 |
@app.get("/")
|
264 |
async def index() -> FileResponse:
|
265 |
-
return FileResponse(path=
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
266 |
|
267 |
|
268 |
if __name__ == '__main__':
|
|
|
3 |
import pathlib
|
4 |
import uuid
|
5 |
|
|
|
6 |
import uvicorn
|
7 |
from fastapi import FastAPI, HTTPException, Request, status
|
8 |
from fastapi.exceptions import RequestValidationError
|
9 |
from fastapi.responses import FileResponse, HTMLResponse, JSONResponse
|
10 |
from fastapi.staticfiles import StaticFiles
|
11 |
+
from fastapi.templating import Jinja2Templates
|
12 |
+
from lisa_on_cuda.utils import app_helpers, frontend_builder, create_folders_and_variables_if_not_exists
|
13 |
from pydantic import ValidationError
|
|
|
|
|
|
|
14 |
from samgis_core.utilities.fastapi_logger import setup_logging
|
15 |
|
16 |
+
from samgis_lisa_on_zero import PROJECT_ROOT_FOLDER, WORKDIR
|
17 |
+
from samgis_lisa_on_zero.prediction_api.global_models import models_dict
|
18 |
+
from samgis_lisa_on_zero.utilities.constants import LISA_INFERENCE_FN
|
19 |
+
from samgis_lisa_on_zero.utilities.type_hints import ApiRequestBody, StringPromptApiRequestBody
|
20 |
|
21 |
+
|
22 |
+
loglevel = os.getenv('LOGLEVEL', 'INFO').upper()
|
23 |
+
app_logger = setup_logging(debug=loglevel)
|
24 |
+
|
25 |
+
CUSTOM_GRADIO_PATH = "/"
|
26 |
+
CUSTOM_STATIC_PATH = "/static"
|
27 |
+
FASTAPI_TITLE = "samgis-lisa-on-zero"
|
28 |
+
app = FastAPI(title=FASTAPI_TITLE, version="1.0")
|
29 |
|
30 |
|
31 |
@app.middleware("http")
|
|
|
50 |
|
51 |
@app.post("/post_test_dictlist")
|
52 |
def post_test_dictlist2(request_input: ApiRequestBody) -> JSONResponse:
|
53 |
+
from samgis_lisa_on_zero.io.wrappers_helpers import get_parsed_bbox_points_with_dictlist_prompt
|
54 |
|
55 |
request_body = get_parsed_bbox_points_with_dictlist_prompt(request_input)
|
56 |
app_logger.info(f"request_body:{request_body}.")
|
|
|
65 |
import importlib.metadata
|
66 |
from importlib.metadata import PackageNotFoundError
|
67 |
|
68 |
+
core_version = lisa_on_cuda_version = samgis_lisa_on_cuda_version = ""
|
69 |
try:
|
70 |
core_version = importlib.metadata.version('samgis_core')
|
71 |
lisa_on_cuda_version = importlib.metadata.version('lisa-on-cuda')
|
72 |
samgis_lisa_on_cuda_version = importlib.metadata.version('samgis-lisa-on-cuda')
|
73 |
except PackageNotFoundError as pe:
|
74 |
app_logger.error(f"pe:{pe}.")
|
|
|
75 |
|
76 |
msg = "still alive, "
|
77 |
msg += f"""version:{samgis_lisa_on_cuda_version}, core version:{core_version},"""
|
|
|
84 |
@app.post("/post_test_string")
|
85 |
def post_test_string(request_input: StringPromptApiRequestBody) -> JSONResponse:
|
86 |
from lisa_on_cuda.utils import app_helpers
|
87 |
+
from samgis_lisa_on_zero.io.wrappers_helpers import get_parsed_bbox_points_with_string_prompt
|
88 |
|
89 |
request_body = get_parsed_bbox_points_with_string_prompt(request_input)
|
90 |
app_logger.info(f"request_body:{request_body}.")
|
|
|
98 |
|
99 |
@app.post("/infer_lisa")
|
100 |
def infer_lisa(request_input: StringPromptApiRequestBody) -> JSONResponse:
|
101 |
+
from samgis_lisa_on_zero.prediction_api import lisa
|
102 |
+
from samgis_lisa_on_zero.io.wrappers_helpers import get_parsed_bbox_points_with_string_prompt, get_source_name
|
103 |
|
104 |
app_logger.info("starting lisa inference request...")
|
105 |
|
|
|
115 |
app_logger.info(f"source_name = {source_name}.")
|
116 |
output = lisa.lisa_predict(
|
117 |
bbox=body_request["bbox"], prompt=body_request["prompt"], zoom=body_request["zoom"],
|
118 |
+
source=body_request["source"], source_name=source_name, inference_function_name_key=LISA_INFERENCE_FN
|
119 |
)
|
120 |
duration_run = time.time() - time_start_run
|
121 |
app_logger.info(f"duration_run:{duration_run}.")
|
|
|
144 |
|
145 |
@app.post("/infer_samgis")
|
146 |
def infer_samgis(request_input: ApiRequestBody) -> JSONResponse:
|
147 |
+
from samgis_lisa_on_zero.prediction_api import predictors
|
148 |
+
from samgis_lisa_on_zero.io.wrappers_helpers import get_parsed_bbox_points_with_dictlist_prompt, get_source_name
|
149 |
|
150 |
app_logger.info("starting plain samgis inference request...")
|
151 |
|
|
|
245 |
)
|
246 |
|
247 |
|
248 |
+
static_dist_folder = WORKDIR / "static" / "dist"
|
249 |
+
frontend_builder.build_frontend(
|
250 |
+
project_root_folder=frontend_builder.env_project_root_folder,
|
251 |
+
input_css_path=frontend_builder.env_input_css_path,
|
252 |
+
output_dist_folder=static_dist_folder
|
253 |
+
)
|
254 |
+
create_folders_and_variables_if_not_exists.folders_creation()
|
255 |
+
|
256 |
+
|
257 |
# important: the index() function and the app.mount MUST be at the end
|
258 |
# samgis.html
|
259 |
+
app.mount("/samgis", StaticFiles(directory=static_dist_folder, html=True), name="samgis")
|
260 |
|
261 |
|
262 |
@app.get("/samgis")
|
263 |
async def samgis() -> FileResponse:
|
264 |
+
return FileResponse(path=static_dist_folder / "samgis.html", media_type="text/html")
|
265 |
|
266 |
|
267 |
# lisa.html
|
268 |
+
app.mount("/lisa", StaticFiles(directory=static_dist_folder, html=True), name="lisa")
|
269 |
|
270 |
|
271 |
@app.get("/lisa")
|
272 |
async def lisa() -> FileResponse:
|
273 |
+
return FileResponse(path=static_dist_folder / "lisa.html", media_type="text/html")
|
274 |
|
275 |
|
276 |
+
# # index.html (lisa.html copy)
|
277 |
+
app.mount("/", StaticFiles(directory=static_dist_folder, html=True), name="index")
|
278 |
|
279 |
|
280 |
@app.get("/")
|
281 |
async def index() -> FileResponse:
|
282 |
+
return FileResponse(path=static_dist_folder / "index.html", media_type="text/html")
|
283 |
+
|
284 |
+
|
285 |
+
lisa.load_model_and_inference_fn(LISA_INFERENCE_FN)
|
286 |
+
inference_fn = models_dict[LISA_INFERENCE_FN]["inference"]
|
287 |
+
|
288 |
+
|
289 |
+
io = app_helpers.get_gradio_interface(inference_fn)
|
290 |
+
app_logger.info("mounting gradio app within FastAPI...")
|
291 |
|
292 |
|
293 |
if __name__ == '__main__':
|
dockerfiles/dockerfile-lisa-predictions
CHANGED
@@ -31,7 +31,7 @@ RUN python -c "import onnxruntime"
|
|
31 |
RUN python -c "import rasterio"
|
32 |
RUN python -c "import uvicorn"
|
33 |
RUN df -h
|
34 |
-
RUN ls -l ${LAMBDA_TASK_ROOT}/
|
35 |
RUN ls -l ${LAMBDA_TASK_ROOT}/wrappers/
|
36 |
RUN ls -l ${FASTAPI_STATIC}/
|
37 |
RUN ls -l ${FASTAPI_STATIC}/dist
|
|
|
31 |
RUN python -c "import rasterio"
|
32 |
RUN python -c "import uvicorn"
|
33 |
RUN df -h
|
34 |
+
RUN ls -l ${LAMBDA_TASK_ROOT}/samgis_lisa_on_zero/
|
35 |
RUN ls -l ${LAMBDA_TASK_ROOT}/wrappers/
|
36 |
RUN ls -l ${FASTAPI_STATIC}/
|
37 |
RUN ls -l ${FASTAPI_STATIC}/dist
|
packages.txt
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
npm
|
2 |
+
nodejs
|
poetry.lock
CHANGED
The diff for this file is too large to render.
See raw diff
|
|
pyproject.toml
CHANGED
@@ -1,66 +1,38 @@
|
|
1 |
[tool.poetry]
|
2 |
-
name = "samgis-lisa-on-
|
3 |
-
version = "1.
|
4 |
description = "A VLM backend for machine learning instance segmentation on geospatial data that uses LISA (Reasoning Segmentation via Large Language Model)."
|
5 |
authors = ["alessandro trinca tornidor <alessandro@trinca.tornidor.com>"]
|
6 |
license = "MIT license"
|
7 |
readme = "README.md"
|
8 |
|
9 |
[metadata]
|
10 |
-
name = "samgis-lisa-on-
|
11 |
-
version = "1.
|
12 |
|
13 |
[tool.poetry.dependencies]
|
14 |
bson = "^0.5.10"
|
15 |
-
contextily = "^1.
|
16 |
-
geopandas = "^0.
|
17 |
loguru = "^0.7.2"
|
18 |
numpy = "1.25.2"
|
19 |
-
onnxruntime = "1.16.3"
|
20 |
opencv-python-headless = "^4.8.1.78"
|
21 |
-
pillow = "^10.
|
22 |
python = "~3.10"
|
23 |
python-dotenv = "^1.0.1"
|
24 |
-
rasterio = "^1.3.
|
25 |
-
requests = "^2.
|
26 |
-
samgis-core = "^
|
27 |
-
lisa-on-cuda = "
|
28 |
-
|
29 |
-
[tool.poetry.group.aws_lambda]
|
30 |
-
optional = true
|
31 |
-
|
32 |
-
[tool.poetry.group.aws_lambda.dependencies]
|
33 |
-
aws-lambda-powertools = "^2.30.2"
|
34 |
-
awslambdaric = "^2.0.10"
|
35 |
-
jmespath = "^1.0.1"
|
36 |
-
pydantic = "^2.5.3"
|
37 |
-
|
38 |
-
[tool.poetry.group.test]
|
39 |
-
optional = true
|
40 |
-
|
41 |
-
[tool.poetry.group.test.dependencies]
|
42 |
-
pytest = "7.4.4"
|
43 |
-
pytest-cov = "4.1.0"
|
44 |
-
python-dotenv = "^1.0.1"
|
45 |
-
httpx = "^0.26.0"
|
46 |
-
|
47 |
-
[tool.poetry.group.docs]
|
48 |
-
optional = true
|
49 |
-
|
50 |
-
[tool.poetry.group.docs.dependencies]
|
51 |
-
sphinx = "^7.2.6"
|
52 |
-
sphinx-autodoc-typehints = "^1.25.2"
|
53 |
-
sphinxcontrib-openapi = "^0.8.4"
|
54 |
-
myst-parser = "^2.0.0"
|
55 |
|
56 |
[tool.poetry.group.fastapi]
|
57 |
optional = true
|
58 |
|
59 |
[tool.poetry.group.fastapi.dependencies]
|
60 |
-
fastapi = "^0.
|
61 |
loguru = "^0.7.2"
|
62 |
-
pydantic = "^2.
|
63 |
-
uvicorn = "^0.
|
64 |
|
65 |
[build-system]
|
66 |
requires = ["poetry-core"]
|
|
|
1 |
[tool.poetry]
|
2 |
+
name = "samgis-lisa-on-zero"
|
3 |
+
version = "1.4.0"
|
4 |
description = "A VLM backend for machine learning instance segmentation on geospatial data that uses LISA (Reasoning Segmentation via Large Language Model)."
|
5 |
authors = ["alessandro trinca tornidor <alessandro@trinca.tornidor.com>"]
|
6 |
license = "MIT license"
|
7 |
readme = "README.md"
|
8 |
|
9 |
[metadata]
|
10 |
+
name = "samgis-lisa-on-zero"
|
11 |
+
version = "1.4.0"
|
12 |
|
13 |
[tool.poetry.dependencies]
|
14 |
bson = "^0.5.10"
|
15 |
+
contextily = "^1.6.0"
|
16 |
+
geopandas = "^1.0.1"
|
17 |
loguru = "^0.7.2"
|
18 |
numpy = "1.25.2"
|
|
|
19 |
opencv-python-headless = "^4.8.1.78"
|
20 |
+
pillow = "^10.4.0"
|
21 |
python = "~3.10"
|
22 |
python-dotenv = "^1.0.1"
|
23 |
+
rasterio = "^1.3.10"
|
24 |
+
requests = "^2.32.3"
|
25 |
+
samgis-core = "^2.0.2"
|
26 |
+
lisa-on-cuda = "1.3.3"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
|
28 |
[tool.poetry.group.fastapi]
|
29 |
optional = true
|
30 |
|
31 |
[tool.poetry.group.fastapi.dependencies]
|
32 |
+
fastapi = "^0.111.0"
|
33 |
loguru = "^0.7.2"
|
34 |
+
pydantic = "^2.8.2"
|
35 |
+
uvicorn = "^0.30.1"
|
36 |
|
37 |
[build-system]
|
38 |
requires = ["poetry-core"]
|
requirements.txt
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
bson==0.5.10
|
2 |
+
contextily==1.6.0
|
3 |
+
fastapi==0.111.0
|
4 |
+
geopandas==1.0.1
|
5 |
+
lisa-on-cuda==1.3.3
|
6 |
+
loguru==0.7.2
|
7 |
+
numpy==1.25.2
|
8 |
+
opencv-python-headless==4.8.1.78
|
9 |
+
pillow==10.4.0
|
10 |
+
pydantic==2.8.2
|
11 |
+
python-dotenv==1.0.1
|
12 |
+
rasterio==1.3.10
|
13 |
+
requests==2.32.3
|
14 |
+
samgis-core==2.0.2
|
15 |
+
uvicorn==0.30.1
|
{samgis_lisa_on_cuda β samgis_lisa_on_zero}/__init__.py
RENAMED
@@ -1,10 +1,10 @@
|
|
1 |
"""Get machine learning predictions from geodata raster images"""
|
2 |
import os
|
3 |
|
4 |
-
# not used here but contextily_tile is imported in
|
5 |
from contextily import tile as contextily_tile
|
6 |
from pathlib import Path
|
7 |
-
from
|
8 |
|
9 |
ROOT = Path(globals().get("__file__", "./_")).absolute().parent.parent
|
10 |
PROJECT_ROOT_FOLDER = Path(os.getenv("PROJECT_ROOT_FOLDER", ROOT))
|
|
|
1 |
"""Get machine learning predictions from geodata raster images"""
|
2 |
import os
|
3 |
|
4 |
+
# not used here but contextily_tile is imported in samgis_lisa_on_zero.io.tms2geotiff
|
5 |
from contextily import tile as contextily_tile
|
6 |
from pathlib import Path
|
7 |
+
from samgis_lisa_on_zero.utilities.constants import SERVICE_NAME
|
8 |
|
9 |
ROOT = Path(globals().get("__file__", "./_")).absolute().parent.parent
|
10 |
PROJECT_ROOT_FOLDER = Path(os.getenv("PROJECT_ROOT_FOLDER", ROOT))
|
{samgis_lisa_on_cuda β samgis_lisa_on_zero}/__version__.py
RENAMED
File without changes
|
{samgis_lisa_on_cuda β samgis_lisa_on_zero}/io/__init__.py
RENAMED
File without changes
|
{samgis_lisa_on_cuda β samgis_lisa_on_zero}/io/coordinates_pixel_conversion.py
RENAMED
@@ -1,10 +1,10 @@
|
|
1 |
"""functions useful to convert to/from latitude-longitude coordinates to pixel image coordinates"""
|
2 |
from samgis_core.utilities.type_hints import TupleFloat, TupleFloatAny
|
3 |
|
4 |
-
from
|
5 |
-
from
|
6 |
-
from
|
7 |
-
from
|
8 |
|
9 |
|
10 |
def _get_latlng2pixel_projection(latlng: LatLngDict) -> ImagePixelCoordinates:
|
|
|
1 |
"""functions useful to convert to/from latitude-longitude coordinates to pixel image coordinates"""
|
2 |
from samgis_core.utilities.type_hints import TupleFloat, TupleFloatAny
|
3 |
|
4 |
+
from samgis_lisa_on_zero import app_logger
|
5 |
+
from samgis_lisa_on_zero.utilities.constants import TILE_SIZE, EARTH_EQUATORIAL_RADIUS
|
6 |
+
from samgis_lisa_on_zero.utilities.type_hints import ImagePixelCoordinates
|
7 |
+
from samgis_lisa_on_zero.utilities.type_hints import LatLngDict
|
8 |
|
9 |
|
10 |
def _get_latlng2pixel_projection(latlng: LatLngDict) -> ImagePixelCoordinates:
|
{samgis_lisa_on_cuda β samgis_lisa_on_zero}/io/geo_helpers.py
RENAMED
@@ -3,7 +3,7 @@ from affine import Affine
|
|
3 |
from numpy import ndarray as np_ndarray
|
4 |
|
5 |
from samgis_core.utilities.type_hints import ListFloat, TupleFloat, DictStrInt
|
6 |
-
from
|
7 |
|
8 |
|
9 |
def load_affine_transformation_from_matrix(matrix_source_coefficients: ListFloat) -> Affine:
|
|
|
3 |
from numpy import ndarray as np_ndarray
|
4 |
|
5 |
from samgis_core.utilities.type_hints import ListFloat, TupleFloat, DictStrInt
|
6 |
+
from samgis_lisa_on_zero import app_logger
|
7 |
|
8 |
|
9 |
def load_affine_transformation_from_matrix(matrix_source_coefficients: ListFloat) -> Affine:
|
{samgis_lisa_on_cuda β samgis_lisa_on_zero}/io/raster_helpers.py
RENAMED
@@ -3,10 +3,10 @@ import numpy as np
|
|
3 |
from numpy import ndarray, bitwise_not
|
4 |
from rasterio import open as rasterio_open
|
5 |
|
6 |
-
from
|
7 |
-
from
|
8 |
-
from
|
9 |
-
from
|
10 |
|
11 |
|
12 |
def get_nextzen_terrain_rgb_formula(red: ndarray, green: ndarray, blue: ndarray) -> ndarray:
|
@@ -83,7 +83,7 @@ def get_rgb_prediction_image(raster_cropped: ndarray, slope_cellsize: int, inver
|
|
83 |
Returns:
|
84 |
tuple of str: image filename, image path (with filename)
|
85 |
"""
|
86 |
-
from
|
87 |
|
88 |
try:
|
89 |
slope, curvature = get_slope_curvature(raster_cropped, slope_cellsize=slope_cellsize)
|
|
|
3 |
from numpy import ndarray, bitwise_not
|
4 |
from rasterio import open as rasterio_open
|
5 |
|
6 |
+
from samgis_lisa_on_zero import PROJECT_ROOT_FOLDER
|
7 |
+
from samgis_lisa_on_zero import app_logger
|
8 |
+
from samgis_lisa_on_zero.utilities.constants import OUTPUT_CRS_STRING
|
9 |
+
from samgis_lisa_on_zero.utilities.type_hints import XYZTerrainProvidersNames
|
10 |
|
11 |
|
12 |
def get_nextzen_terrain_rgb_formula(red: ndarray, green: ndarray, blue: ndarray) -> ndarray:
|
|
|
83 |
Returns:
|
84 |
tuple of str: image filename, image path (with filename)
|
85 |
"""
|
86 |
+
from samgis_lisa_on_zero.utilities.constants import CHANNEL_EXAGGERATIONS_LIST
|
87 |
|
88 |
try:
|
89 |
slope, curvature = get_slope_curvature(raster_cropped, slope_cellsize=slope_cellsize)
|
{samgis_lisa_on_cuda β samgis_lisa_on_zero}/io/tms2geotiff.py
RENAMED
@@ -4,10 +4,10 @@ from numpy import ndarray
|
|
4 |
from samgis_core.utilities.type_hints import TupleFloat
|
5 |
from xyzservices import TileProvider
|
6 |
|
7 |
-
from
|
8 |
-
from
|
9 |
-
|
10 |
-
from
|
11 |
|
12 |
|
13 |
bool_use_cache = int(os.getenv("BOOL_USE_CACHE", BOOL_USE_CACHE))
|
@@ -51,8 +51,8 @@ def download_extent(w: float, s: float, e: float, n: float, zoom: int or str = z
|
|
51 |
parsed request input
|
52 |
"""
|
53 |
try:
|
54 |
-
from
|
55 |
-
from
|
56 |
|
57 |
app_logger.info(f"connection number:{n_connections}, type:{type(n_connections)}.")
|
58 |
app_logger.info(f"zoom:{zoom}, type:{type(zoom)}.")
|
|
|
4 |
from samgis_core.utilities.type_hints import TupleFloat
|
5 |
from xyzservices import TileProvider
|
6 |
|
7 |
+
from samgis_lisa_on_zero import app_logger
|
8 |
+
from samgis_lisa_on_zero.utilities.constants import (OUTPUT_CRS_STRING, DRIVER_RASTERIO_GTIFF, N_MAX_RETRIES, N_CONNECTION, N_WAIT,
|
9 |
+
ZOOM_AUTO, BOOL_USE_CACHE)
|
10 |
+
from samgis_lisa_on_zero.utilities.type_hints import tuple_ndarray_transform
|
11 |
|
12 |
|
13 |
bool_use_cache = int(os.getenv("BOOL_USE_CACHE", BOOL_USE_CACHE))
|
|
|
51 |
parsed request input
|
52 |
"""
|
53 |
try:
|
54 |
+
from samgis_lisa_on_zero import contextily_tile
|
55 |
+
from samgis_lisa_on_zero.io.coordinates_pixel_conversion import _from4326_to3857
|
56 |
|
57 |
app_logger.info(f"connection number:{n_connections}, type:{type(n_connections)}.")
|
58 |
app_logger.info(f"zoom:{zoom}, type:{type(zoom)}.")
|
{samgis_lisa_on_cuda β samgis_lisa_on_zero}/io/wrappers_helpers.py
RENAMED
@@ -7,10 +7,10 @@ import loguru
|
|
7 |
from xyzservices import providers, TileProvider
|
8 |
|
9 |
from lisa_on_cuda.utils.app_helpers import get_cleaned_input
|
10 |
-
from
|
11 |
-
from
|
12 |
-
from
|
13 |
-
from
|
14 |
XYZDefaultProvidersNames, StringPromptApiRequestBody
|
15 |
from samgis_core.utilities.utilities import base64_decode
|
16 |
|
|
|
7 |
from xyzservices import providers, TileProvider
|
8 |
|
9 |
from lisa_on_cuda.utils.app_helpers import get_cleaned_input
|
10 |
+
from samgis_lisa_on_zero import app_logger
|
11 |
+
from samgis_lisa_on_zero.io.coordinates_pixel_conversion import get_latlng_to_pixel_coordinates
|
12 |
+
from samgis_lisa_on_zero.utilities.constants import COMPLETE_URL_TILES_MAPBOX, COMPLETE_URL_TILES_NEXTZEN, CUSTOM_RESPONSE_MESSAGES
|
13 |
+
from samgis_lisa_on_zero.utilities.type_hints import ApiRequestBody, ContentTypes, XYZTerrainProvidersNames, \
|
14 |
XYZDefaultProvidersNames, StringPromptApiRequestBody
|
15 |
from samgis_core.utilities.utilities import base64_decode
|
16 |
|
{samgis_lisa_on_cuda β samgis_lisa_on_zero}/prediction_api/__init__.py
RENAMED
File without changes
|
{samgis_lisa_on_cuda β samgis_lisa_on_zero}/prediction_api/global_models.py
RENAMED
@@ -3,4 +3,4 @@ models_dict = {
|
|
3 |
"lisa": {"inference": None}
|
4 |
}
|
5 |
embedding_dict = {}
|
6 |
-
|
|
|
3 |
"lisa": {"inference": None}
|
4 |
}
|
5 |
embedding_dict = {}
|
6 |
+
inference_fn_dict = {}
|
{samgis_lisa_on_cuda β samgis_lisa_on_zero}/prediction_api/lisa.py
RENAMED
@@ -1,22 +1,36 @@
|
|
1 |
from datetime import datetime
|
|
|
2 |
|
3 |
-
from lisa_on_cuda.utils import app_helpers
|
4 |
from samgis_core.utilities.type_hints import LlistFloat, DictStrInt
|
5 |
-
from
|
6 |
-
from
|
7 |
-
from
|
8 |
-
from
|
9 |
-
from samgis_lisa_on_cuda.prediction_api.global_models import models_dict
|
10 |
-
from samgis_lisa_on_cuda.utilities.constants import DEFAULT_URL_TILES
|
11 |
|
12 |
msg_write_tmp_on_disk = "found option to write images and geojson output..."
|
13 |
|
14 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
def lisa_predict(
|
16 |
bbox: LlistFloat,
|
17 |
prompt: str,
|
18 |
zoom: float,
|
19 |
-
inference_function_name_key: str =
|
20 |
source: str = DEFAULT_URL_TILES,
|
21 |
source_name: str = None
|
22 |
) -> DictStrInt:
|
@@ -40,13 +54,11 @@ def lisa_predict(
|
|
40 |
Affine transform
|
41 |
"""
|
42 |
from os import getenv
|
|
|
|
|
43 |
|
44 |
app_logger.info("start lisa inference...")
|
45 |
-
|
46 |
-
app_logger.info(f"missing inference function {inference_function_name_key}, instantiating it now!")
|
47 |
-
parsed_args = app_helpers.parse_args([])
|
48 |
-
inference_fn = app_helpers.get_inference_model_by_args(parsed_args)
|
49 |
-
models_dict[inference_function_name_key]["inference"] = inference_fn
|
50 |
app_logger.debug(f"using a {inference_function_name_key} instance model...")
|
51 |
inference_fn = models_dict[inference_function_name_key]["inference"]
|
52 |
|
|
|
1 |
from datetime import datetime
|
2 |
+
from spaces import GPU as SPACES_GPU
|
3 |
|
|
|
4 |
from samgis_core.utilities.type_hints import LlistFloat, DictStrInt
|
5 |
+
from samgis_lisa_on_zero.io.geo_helpers import get_vectorized_raster_as_geojson
|
6 |
+
from samgis_lisa_on_zero.io.raster_helpers import write_raster_png, write_raster_tiff
|
7 |
+
from samgis_lisa_on_zero.io.tms2geotiff import download_extent
|
8 |
+
from samgis_lisa_on_zero.utilities.constants import DEFAULT_URL_TILES, LISA_INFERENCE_FN
|
|
|
|
|
9 |
|
10 |
msg_write_tmp_on_disk = "found option to write images and geojson output..."
|
11 |
|
12 |
|
13 |
+
def load_model_and_inference_fn(inference_function_name_key):
|
14 |
+
from samgis_lisa_on_zero import app_logger
|
15 |
+
from lisa_on_cuda.utils import app_helpers
|
16 |
+
from samgis_lisa_on_zero.prediction_api.global_models import models_dict
|
17 |
+
|
18 |
+
if models_dict[inference_function_name_key]["inference"] is None:
|
19 |
+
app_logger.info(f"missing inference function {inference_function_name_key}, instantiating it now!")
|
20 |
+
parsed_args = app_helpers.parse_args([])
|
21 |
+
inference_fn = app_helpers.get_inference_model_by_args(
|
22 |
+
parsed_args,
|
23 |
+
internal_logg=app_logger,
|
24 |
+
inference_decorator=SPACES_GPU
|
25 |
+
)
|
26 |
+
models_dict[inference_function_name_key]["inference"] = inference_fn
|
27 |
+
|
28 |
+
|
29 |
def lisa_predict(
|
30 |
bbox: LlistFloat,
|
31 |
prompt: str,
|
32 |
zoom: float,
|
33 |
+
inference_function_name_key: str = LISA_INFERENCE_FN,
|
34 |
source: str = DEFAULT_URL_TILES,
|
35 |
source_name: str = None
|
36 |
) -> DictStrInt:
|
|
|
54 |
Affine transform
|
55 |
"""
|
56 |
from os import getenv
|
57 |
+
from samgis_lisa_on_zero import app_logger
|
58 |
+
from samgis_lisa_on_zero.prediction_api.global_models import models_dict
|
59 |
|
60 |
app_logger.info("start lisa inference...")
|
61 |
+
load_model_and_inference_fn(inference_function_name_key)
|
|
|
|
|
|
|
|
|
62 |
app_logger.debug(f"using a {inference_function_name_key} instance model...")
|
63 |
inference_fn = models_dict[inference_function_name_key]["inference"]
|
64 |
|
{samgis_lisa_on_cuda β samgis_lisa_on_zero}/prediction_api/predictors.py
RENAMED
@@ -1,11 +1,11 @@
|
|
1 |
"""functions using machine learning instance model(s)"""
|
2 |
-
from
|
3 |
-
from
|
4 |
-
from
|
5 |
-
from
|
6 |
-
from
|
7 |
-
from
|
8 |
-
from
|
9 |
from samgis_core.prediction_api.sam_onnx import SegmentAnythingONNX, get_raster_inference_with_embedding_from_dict
|
10 |
from samgis_core.utilities.constants import MODEL_ENCODER_NAME, MODEL_DECODER_NAME, DEFAULT_INPUT_SHAPE
|
11 |
from samgis_core.utilities.type_hints import LlistFloat, DictStrInt, ListDict
|
|
|
1 |
"""functions using machine learning instance model(s)"""
|
2 |
+
from samgis_lisa_on_zero import app_logger, MODEL_FOLDER
|
3 |
+
from samgis_lisa_on_zero.io.geo_helpers import get_vectorized_raster_as_geojson
|
4 |
+
from samgis_lisa_on_zero.io.raster_helpers import get_raster_terrain_rgb_like, get_rgb_prediction_image
|
5 |
+
from samgis_lisa_on_zero.io.tms2geotiff import download_extent
|
6 |
+
from samgis_lisa_on_zero.io.wrappers_helpers import check_source_type_is_terrain
|
7 |
+
from samgis_lisa_on_zero.prediction_api.global_models import models_dict, embedding_dict
|
8 |
+
from samgis_lisa_on_zero.utilities.constants import DEFAULT_URL_TILES, SLOPE_CELLSIZE
|
9 |
from samgis_core.prediction_api.sam_onnx import SegmentAnythingONNX, get_raster_inference_with_embedding_from_dict
|
10 |
from samgis_core.utilities.constants import MODEL_ENCODER_NAME, MODEL_DECODER_NAME, DEFAULT_INPUT_SHAPE
|
11 |
from samgis_core.utilities.type_hints import LlistFloat, DictStrInt, ListDict
|
{samgis_lisa_on_cuda β samgis_lisa_on_zero}/utilities/__init__.py
RENAMED
File without changes
|
{samgis_lisa_on_cuda β samgis_lisa_on_zero}/utilities/constants.py
RENAMED
@@ -37,3 +37,4 @@ RELATIVE_URL_TILES_NEXTZEN = "elevation-tiles-prod/terrarium/{z}/{x}/{y}.png" #
|
|
37 |
COMPLETE_URL_TILES_NEXTZEN = f"https://{DOMAIN_URL_TILES_NEXTZEN}/{RELATIVE_URL_TILES_NEXTZEN}"
|
38 |
CHANNEL_EXAGGERATIONS_LIST = [2.5, 1.1, 2.0]
|
39 |
SLOPE_CELLSIZE = 61
|
|
|
|
37 |
COMPLETE_URL_TILES_NEXTZEN = f"https://{DOMAIN_URL_TILES_NEXTZEN}/{RELATIVE_URL_TILES_NEXTZEN}"
|
38 |
CHANNEL_EXAGGERATIONS_LIST = [2.5, 1.1, 2.0]
|
39 |
SLOPE_CELLSIZE = 61
|
40 |
+
LISA_INFERENCE_FN = "lisa"
|
{samgis_lisa_on_cuda β samgis_lisa_on_zero}/utilities/session_logger.py
RENAMED
File without changes
|
{samgis_lisa_on_cuda β samgis_lisa_on_zero}/utilities/type_hints.py
RENAMED
File without changes
|
scripts/extract-openapi-fastapi.py
CHANGED
@@ -7,7 +7,7 @@ import sys
|
|
7 |
import yaml
|
8 |
from uvicorn.importer import import_from_string
|
9 |
|
10 |
-
from
|
11 |
|
12 |
parser = argparse.ArgumentParser(prog="extract-openapi-fastapi.py")
|
13 |
parser.add_argument("app", help='App import string. Eg. "main:app"', default="main:app")
|
|
|
7 |
import yaml
|
8 |
from uvicorn.importer import import_from_string
|
9 |
|
10 |
+
from samgis_lisa_on_zero import PROJECT_ROOT_FOLDER
|
11 |
|
12 |
parser = argparse.ArgumentParser(prog="extract-openapi-fastapi.py")
|
13 |
parser.add_argument("app", help='App import string. Eg. "main:app"', default="main:app")
|
scripts/extract-openapi-lambda.py
CHANGED
@@ -1,9 +1,9 @@
|
|
1 |
import json
|
2 |
|
3 |
-
from
|
4 |
|
5 |
if __name__ == '__main__':
|
6 |
-
from
|
7 |
|
8 |
with open(PROJECT_ROOT_FOLDER / "docs" / "specs" / "openapi_lambda_wip.json", "w") as output_json:
|
9 |
json.dump({
|
|
|
1 |
import json
|
2 |
|
3 |
+
from samgis_lisa_on_zero import PROJECT_ROOT_FOLDER
|
4 |
|
5 |
if __name__ == '__main__':
|
6 |
+
from samgis_lisa_on_zero.utilities.type_hints import ApiRequestBody, ApiResponseBodyFailure, ApiResponseBodySuccess
|
7 |
|
8 |
with open(PROJECT_ROOT_FOLDER / "docs" / "specs" / "openapi_lambda_wip.json", "w") as output_json:
|
9 |
json.dump({
|
static/vite.config.ts
CHANGED
@@ -1,26 +1,29 @@
|
|
1 |
-
import {
|
2 |
-
import {
|
3 |
-
|
4 |
-
import { defineConfig } from 'vite'
|
5 |
import vue from '@vitejs/plugin-vue'
|
6 |
|
7 |
// https://vitejs.dev/config/
|
8 |
-
export default defineConfig({
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
}
|
16 |
-
},
|
17 |
-
build: {
|
18 |
-
rollupOptions: {
|
19 |
-
input: {
|
20 |
-
samgis: resolve(__dirname, 'samgis.html'),
|
21 |
-
lisa: resolve(__dirname, 'lisa.html'),
|
22 |
-
index: resolve(__dirname, "index.html"),
|
23 |
-
},
|
24 |
-
},
|
25 |
-
},
|
26 |
})
|
|
|
1 |
+
import {fileURLToPath, URL} from 'node:url'
|
2 |
+
import {resolve} from 'node:path'
|
3 |
+
import {defineConfig, loadEnv} from 'vite'
|
|
|
4 |
import vue from '@vitejs/plugin-vue'
|
5 |
|
6 |
// https://vitejs.dev/config/
|
7 |
+
export default defineConfig(({mode}) => {
|
8 |
+
const env = loadEnv(mode, process.cwd())
|
9 |
+
const frontendPrefix = env.VITE_PREFIX ? env.VITE_PREFIX : "/"
|
10 |
+
console.log(`VITE_PREFIX:${env.VITE_PREFIX}, frontend_prefix:${frontendPrefix}, mode:${mode} ...`)
|
11 |
+
return {
|
12 |
+
plugins: [vue()],
|
13 |
+
base: frontendPrefix,
|
14 |
+
resolve: {
|
15 |
+
alias: {
|
16 |
+
'@': fileURLToPath(new URL('./src', import.meta.url))
|
17 |
+
}
|
18 |
+
},
|
19 |
+
build: {
|
20 |
+
rollupOptions: {
|
21 |
+
input: {
|
22 |
+
samgis: resolve(__dirname, 'samgis.html'),
|
23 |
+
lisa: resolve(__dirname, 'lisa.html'),
|
24 |
+
index: resolve(__dirname, "index.html"),
|
25 |
+
},
|
26 |
+
},
|
27 |
+
}
|
28 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
})
|
tests/__init__.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
from
|
2 |
|
3 |
|
4 |
TEST_ROOT_FOLDER = PROJECT_ROOT_FOLDER / "tests"
|
|
|
1 |
+
from samgis_lisa_on_zero import PROJECT_ROOT_FOLDER
|
2 |
|
3 |
|
4 |
TEST_ROOT_FOLDER = PROJECT_ROOT_FOLDER / "tests"
|
tests/io/test_coordinates_pixel_conversion.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
import json
|
2 |
|
3 |
-
from
|
4 |
-
from
|
5 |
from tests import TEST_EVENTS_FOLDER
|
6 |
|
7 |
|
|
|
1 |
import json
|
2 |
|
3 |
+
from samgis_lisa_on_zero.io.coordinates_pixel_conversion import get_latlng_to_pixel_coordinates
|
4 |
+
from samgis_lisa_on_zero.utilities.type_hints import LatLngDict
|
5 |
from tests import TEST_EVENTS_FOLDER
|
6 |
|
7 |
|
tests/io/test_geo_helpers.py
CHANGED
@@ -3,7 +3,7 @@ import unittest
|
|
3 |
import numpy as np
|
4 |
import shapely
|
5 |
|
6 |
-
from
|
7 |
from tests import TEST_EVENTS_FOLDER
|
8 |
|
9 |
|
@@ -63,7 +63,7 @@ class TestGeoHelpers(unittest.TestCase):
|
|
63 |
|
64 |
def test_get_vectorized_raster_as_geojson_ok(self):
|
65 |
from rasterio.transform import Affine
|
66 |
-
from
|
67 |
|
68 |
name_fn = "samexporter_predict"
|
69 |
|
@@ -81,7 +81,7 @@ class TestGeoHelpers(unittest.TestCase):
|
|
81 |
assert shapely.equals_exact(output_geojson, expected_output_geojson, tolerance=0.000006)
|
82 |
|
83 |
def test_get_vectorized_raster_as_geojson_fail(self):
|
84 |
-
from
|
85 |
|
86 |
name_fn = "samexporter_predict"
|
87 |
|
|
|
3 |
import numpy as np
|
4 |
import shapely
|
5 |
|
6 |
+
from samgis_lisa_on_zero.io.geo_helpers import load_affine_transformation_from_matrix
|
7 |
from tests import TEST_EVENTS_FOLDER
|
8 |
|
9 |
|
|
|
63 |
|
64 |
def test_get_vectorized_raster_as_geojson_ok(self):
|
65 |
from rasterio.transform import Affine
|
66 |
+
from samgis_lisa_on_zero.io.geo_helpers import get_vectorized_raster_as_geojson
|
67 |
|
68 |
name_fn = "samexporter_predict"
|
69 |
|
|
|
81 |
assert shapely.equals_exact(output_geojson, expected_output_geojson, tolerance=0.000006)
|
82 |
|
83 |
def test_get_vectorized_raster_as_geojson_fail(self):
|
84 |
+
from samgis_lisa_on_zero.io.geo_helpers import get_vectorized_raster_as_geojson
|
85 |
|
86 |
name_fn = "samexporter_predict"
|
87 |
|
tests/io/test_raster_helpers.py
CHANGED
@@ -3,7 +3,7 @@ from unittest.mock import patch
|
|
3 |
import numpy as np
|
4 |
|
5 |
from samgis_core.utilities.utilities import hash_calculate
|
6 |
-
from
|
7 |
|
8 |
|
9 |
def get_three_channels(size=5, param1=1000, param2=3, param3=-88):
|
@@ -101,7 +101,7 @@ class Test(unittest.TestCase):
|
|
101 |
assert hash_slope == b'IYf6x4G0lmR47j6HRS5kUYWdtmimhLz2nak8py75nwc='
|
102 |
|
103 |
def test_get_slope_curvature_value_error(self):
|
104 |
-
from
|
105 |
|
106 |
with self.assertRaises(ValueError):
|
107 |
try:
|
@@ -242,7 +242,7 @@ class Test(unittest.TestCase):
|
|
242 |
assert hash_output == b'RU7CcoKoR3Fkh5LE+m48DHRVUy/vGq6UgfOFUMXx07M='
|
243 |
|
244 |
def test_get_raster_terrain_rgb_like(self):
|
245 |
-
from
|
246 |
|
247 |
arr_input = raster_helpers.get_rgb_image(channel0, channel1, channel2, invert_image=True)
|
248 |
output_nextzen = raster_helpers.get_raster_terrain_rgb_like(
|
|
|
3 |
import numpy as np
|
4 |
|
5 |
from samgis_core.utilities.utilities import hash_calculate
|
6 |
+
from samgis_lisa_on_zero.io import raster_helpers
|
7 |
|
8 |
|
9 |
def get_three_channels(size=5, param1=1000, param2=3, param3=-88):
|
|
|
101 |
assert hash_slope == b'IYf6x4G0lmR47j6HRS5kUYWdtmimhLz2nak8py75nwc='
|
102 |
|
103 |
def test_get_slope_curvature_value_error(self):
|
104 |
+
from samgis_lisa_on_zero.io import raster_helpers
|
105 |
|
106 |
with self.assertRaises(ValueError):
|
107 |
try:
|
|
|
242 |
assert hash_output == b'RU7CcoKoR3Fkh5LE+m48DHRVUy/vGq6UgfOFUMXx07M='
|
243 |
|
244 |
def test_get_raster_terrain_rgb_like(self):
|
245 |
+
from samgis_lisa_on_zero.utilities.type_hints import XYZTerrainProvidersNames
|
246 |
|
247 |
arr_input = raster_helpers.get_rgb_image(channel0, channel1, channel2, invert_image=True)
|
248 |
output_nextzen = raster_helpers.get_raster_terrain_rgb_like(
|
tests/io/test_tms2geotiff.py
CHANGED
@@ -3,8 +3,8 @@ import unittest
|
|
3 |
import numpy as np
|
4 |
from samgis_core.utilities.utilities import hash_calculate
|
5 |
|
6 |
-
from
|
7 |
-
from
|
8 |
from tests import LOCAL_URL_TILE, TEST_EVENTS_FOLDER
|
9 |
|
10 |
|
|
|
3 |
import numpy as np
|
4 |
from samgis_core.utilities.utilities import hash_calculate
|
5 |
|
6 |
+
from samgis_lisa_on_zero import app_logger
|
7 |
+
from samgis_lisa_on_zero.io.tms2geotiff import download_extent
|
8 |
from tests import LOCAL_URL_TILE, TEST_EVENTS_FOLDER
|
9 |
|
10 |
|
tests/io/test_wrappers_helpers.py
CHANGED
@@ -5,9 +5,9 @@ import unittest
|
|
5 |
from http import HTTPStatus
|
6 |
from unittest.mock import patch
|
7 |
|
8 |
-
from
|
9 |
-
from
|
10 |
-
from
|
11 |
from tests import TEST_EVENTS_FOLDER
|
12 |
|
13 |
|
@@ -95,7 +95,7 @@ class WrappersHelpersTest(unittest.TestCase):
|
|
95 |
@patch.object(wrappers_helpers, "providers")
|
96 |
def test_get_url_tile(self, providers_mocked):
|
97 |
import xyzservices
|
98 |
-
from
|
99 |
|
100 |
from tests import LOCAL_URL_TILE
|
101 |
|
@@ -115,7 +115,7 @@ class WrappersHelpersTest(unittest.TestCase):
|
|
115 |
|
116 |
@staticmethod
|
117 |
def test_get_url_tile_real():
|
118 |
-
from
|
119 |
|
120 |
assert get_url_tile("OpenStreetMap") == {
|
121 |
'url': 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', 'max_zoom': 19,
|
|
|
5 |
from http import HTTPStatus
|
6 |
from unittest.mock import patch
|
7 |
|
8 |
+
from samgis_lisa_on_zero.io import wrappers_helpers
|
9 |
+
from samgis_lisa_on_zero.io.wrappers_helpers import get_parsed_bbox_points_with_dictlist_prompt, get_parsed_request_body, get_response
|
10 |
+
from samgis_lisa_on_zero.utilities.type_hints import ApiRequestBody
|
11 |
from tests import TEST_EVENTS_FOLDER
|
12 |
|
13 |
|
|
|
95 |
@patch.object(wrappers_helpers, "providers")
|
96 |
def test_get_url_tile(self, providers_mocked):
|
97 |
import xyzservices
|
98 |
+
from samgis_lisa_on_zero.io.wrappers_helpers import get_url_tile
|
99 |
|
100 |
from tests import LOCAL_URL_TILE
|
101 |
|
|
|
115 |
|
116 |
@staticmethod
|
117 |
def test_get_url_tile_real():
|
118 |
+
from samgis_lisa_on_zero.io.wrappers_helpers import get_url_tile
|
119 |
|
120 |
assert get_url_tile("OpenStreetMap") == {
|
121 |
'url': 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', 'max_zoom': 19,
|
tests/prediction_api/test_predictors.py
CHANGED
@@ -3,8 +3,8 @@ from unittest.mock import patch
|
|
3 |
|
4 |
import numpy as np
|
5 |
|
6 |
-
from
|
7 |
-
from
|
8 |
from tests import TEST_EVENTS_FOLDER
|
9 |
|
10 |
|
|
|
3 |
|
4 |
import numpy as np
|
5 |
|
6 |
+
from samgis_lisa_on_zero.prediction_api import predictors
|
7 |
+
from samgis_lisa_on_zero.prediction_api.predictors import get_raster_inference, samexporter_predict
|
8 |
from tests import TEST_EVENTS_FOLDER
|
9 |
|
10 |
|
tests/test_fastapi_app.py
CHANGED
@@ -5,12 +5,12 @@ from unittest.mock import patch
|
|
5 |
|
6 |
from fastapi.testclient import TestClient
|
7 |
|
8 |
-
from
|
9 |
-
from
|
10 |
from tests import TEST_EVENTS_FOLDER
|
11 |
from tests.local_tiles_http_server import LocalTilesHttpServer
|
12 |
-
|
13 |
-
from
|
14 |
|
15 |
|
16 |
infer_samgis = "/infer_samgis"
|
|
|
5 |
|
6 |
from fastapi.testclient import TestClient
|
7 |
|
8 |
+
from samgis_lisa_on_zero import PROJECT_ROOT_FOLDER
|
9 |
+
from samgis_lisa_on_zero.io import wrappers_helpers
|
10 |
from tests import TEST_EVENTS_FOLDER
|
11 |
from tests.local_tiles_http_server import LocalTilesHttpServer
|
12 |
+
import app
|
13 |
+
from app import app
|
14 |
|
15 |
|
16 |
infer_samgis = "/infer_samgis"
|
tests/test_lambda_app.py
CHANGED
@@ -3,13 +3,13 @@ import time
|
|
3 |
import unittest
|
4 |
from unittest.mock import patch
|
5 |
|
6 |
-
from
|
7 |
|
8 |
if IS_AWS_LAMBDA:
|
9 |
try:
|
10 |
from awslambdaric.lambda_context import LambdaContext
|
11 |
|
12 |
-
from
|
13 |
from wrappers import lambda_wrapper
|
14 |
from tests.local_tiles_http_server import LocalTilesHttpServer
|
15 |
|
|
|
3 |
import unittest
|
4 |
from unittest.mock import patch
|
5 |
|
6 |
+
from samgis_lisa_on_zero import IS_AWS_LAMBDA
|
7 |
|
8 |
if IS_AWS_LAMBDA:
|
9 |
try:
|
10 |
from awslambdaric.lambda_context import LambdaContext
|
11 |
|
12 |
+
from samgis_lisa_on_zero.io import wrappers_helpers
|
13 |
from wrappers import lambda_wrapper
|
14 |
from tests.local_tiles_http_server import LocalTilesHttpServer
|
15 |
|
wrappers/__init__.py
DELETED
File without changes
|
wrappers/lambda_wrapper.py
DELETED
@@ -1,58 +0,0 @@
|
|
1 |
-
"""Lambda entry point"""
|
2 |
-
from http import HTTPStatus
|
3 |
-
from typing import Dict
|
4 |
-
|
5 |
-
from aws_lambda_powertools.utilities.typing import LambdaContext
|
6 |
-
from pydantic import ValidationError
|
7 |
-
|
8 |
-
from samgis_lisa_on_cuda import app_logger
|
9 |
-
from samgis_lisa_on_cuda.io.wrappers_helpers import get_parsed_request_body, get_parsed_bbox_points_with_dictlist_prompt, get_response
|
10 |
-
from samgis_lisa_on_cuda.prediction_api.predictors import samexporter_predict
|
11 |
-
|
12 |
-
|
13 |
-
def lambda_handler(event: Dict, context: LambdaContext) -> str:
|
14 |
-
"""
|
15 |
-
Handle the request for the serverless backend and return the response
|
16 |
-
(success or a type of error based on the exception raised).
|
17 |
-
|
18 |
-
Args:
|
19 |
-
event: request content
|
20 |
-
context: request context
|
21 |
-
|
22 |
-
Returns:
|
23 |
-
json response from get_response() function
|
24 |
-
|
25 |
-
"""
|
26 |
-
from time import time
|
27 |
-
app_logger.info(f"start with aws_request_id:{context.aws_request_id}.")
|
28 |
-
start_time = time()
|
29 |
-
|
30 |
-
if "version" in event:
|
31 |
-
app_logger.info(f"event version: {event['version']}.")
|
32 |
-
|
33 |
-
try:
|
34 |
-
app_logger.info("try get_parsed_event...")
|
35 |
-
request_input = get_parsed_request_body(event)
|
36 |
-
app_logger.info("event parsed: ok")
|
37 |
-
body_request = get_parsed_bbox_points_with_dictlist_prompt(request_input)
|
38 |
-
app_logger.info(f"body_request => {type(body_request)}, {body_request}.")
|
39 |
-
|
40 |
-
try:
|
41 |
-
body_response = samexporter_predict(
|
42 |
-
body_request["bbox"], body_request["prompt"], body_request["zoom"], source=body_request["source"]
|
43 |
-
)
|
44 |
-
app_logger.info(f"output body_response length:{len(body_response)}.")
|
45 |
-
app_logger.debug(f"output body_response:{body_response}.")
|
46 |
-
response = get_response(HTTPStatus.OK.value, start_time, context.aws_request_id, body_response)
|
47 |
-
except Exception as ex2:
|
48 |
-
app_logger.exception(f"exception2:{ex2}.", exc_info=True)
|
49 |
-
response = get_response(HTTPStatus.INTERNAL_SERVER_ERROR.value, start_time, context.aws_request_id, {})
|
50 |
-
except ValidationError as va1:
|
51 |
-
app_logger.exception(f"ValidationError:{va1}.", exc_info=True)
|
52 |
-
response = get_response(HTTPStatus.UNPROCESSABLE_ENTITY.value, start_time, context.aws_request_id, {})
|
53 |
-
except Exception as ex1:
|
54 |
-
app_logger.exception(f"exception1:{ex1}.", exc_info=True)
|
55 |
-
response = get_response(HTTPStatus.BAD_REQUEST.value, start_time, context.aws_request_id, {})
|
56 |
-
|
57 |
-
app_logger.debug(f"response_dumped:{response}...")
|
58 |
-
return response
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|