aletrn commited on
Commit
59ebac7
·
1 Parent(s): e9833fa

[feat] handle requests with errors

Browse files
.gitignore ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ venv/
2
+ *.pyc
3
+ __cache__
4
+ .idea
5
+ tmp/
6
+ .env*
Dockerfile ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM ghcr.io/osgeo/gdal:ubuntu-small-3.7.2
2
+
3
+ WORKDIR /code
4
+ COPY ./requirements.txt /code/requirements.txt
5
+ COPY ./requirements_pip.txt /code/requirements_pip.txt
6
+
7
+ RUN apt update && apt install -y g++ make cmake unzip libcurl4-openssl-dev python3-pip
8
+
9
+ # avoid segment-geospatial exception caused by missing libGL.so.1 library
10
+ RUN apt install -y libgl1 curl
11
+ RUN ls -ld /usr/lib/x86_64-linux-gnu/libGL.so* || echo "libGL.so* not found..."
12
+
13
+ RUN which python
14
+ RUN python --version
15
+ RUN python -m pip install --no-cache-dir --upgrade -r /code/requirements_pip.txt
16
+ RUN python -m pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu
17
+ RUN python -m pip install --no-cache-dir -r /code/requirements.txt
18
+
19
+ RUN useradd -m -u 1000 user
20
+
21
+ USER user
22
+
23
+ ENV HOME=/home/user \
24
+ PATH=/home/user/.local/bin:$PATH
25
+
26
+ WORKDIR $HOME/app
27
+
28
+ RUN curl -o ${HOME}/sam_vit_h_4b8939.pth https://dl.fbaipublicfiles.com/segment_anything/sam_vit_h_4b8939.pth
29
+ RUN ls -l ${HOME}/
30
+ COPY --chown=user . $HOME/app
31
+
32
+ CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "7860"]
README.md CHANGED
@@ -1,5 +1,5 @@
1
  ---
2
- title: Segment Anything
3
  emoji: 📉
4
  colorFrom: red
5
  colorTo: blue
@@ -7,4 +7,27 @@ sdk: docker
7
  pinned: false
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: Segment Geospatial
3
  emoji: 📉
4
  colorFrom: red
5
  colorTo: blue
 
7
  pinned: false
8
  ---
9
 
10
+ Build the docker image:
11
+
12
+ ```bash
13
+ # clean any old active containers
14
+ docker stop $(docker ps -a -q); docker rm $(docker ps -a -q)
15
+
16
+ # build the image, use the tag "semgeo"
17
+ docker build . --tag semgeo --progress=plain
18
+ ```
19
+
20
+ Run the container (keep it on background) and show logs
21
+
22
+ ```bash
23
+ docker run -d --name semgeo -p 7860:7860 semgeo; docker logs -f semgeo
24
+ ```
25
+
26
+ Test it with curl:
27
+
28
+ ```bash
29
+ curl -X 'POST' \
30
+ 'http://localhost:7860/infer_samgeo' \
31
+ -H 'accept: application/json' \
32
+ -d '{}'
33
+ ```
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ fastapi
2
+ bson
3
+ python-dotenv
4
+ segment-geospatial
5
+ uvicorn[standard]
requirements_pip.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ pip
2
+ wheel
3
+ setuptools
src/__init__.py ADDED
File without changes
src/main.py ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ from typing import List
3
+ from fastapi import FastAPI, HTTPException, Request, status
4
+ from fastapi.exceptions import RequestValidationError
5
+ from fastapi.responses import FileResponse, JSONResponse
6
+ from fastapi.staticfiles import StaticFiles
7
+ from pydantic import BaseModel
8
+
9
+ from src.utilities.utilities import setup_logging
10
+
11
+
12
+ app = FastAPI()
13
+ local_logger = setup_logging()
14
+
15
+
16
+ class Input(BaseModel):
17
+ name: str
18
+ bbox: List[float]
19
+ points_coords: List[List[float]]
20
+
21
+
22
+ @app.post("/post_test")
23
+ async def post_test(input: Input) -> JSONResponse:
24
+ bbox = input.bbox
25
+ name = input.name
26
+ points_coords = input.points_coords
27
+ return JSONResponse(
28
+ status_code=200,
29
+ content={
30
+ "msg": name, "bbox": bbox, "points_coords": points_coords
31
+ }
32
+ )
33
+
34
+
35
+ @app.get("/hello")
36
+ async def hello() -> JSONResponse:
37
+ return JSONResponse(status_code=200, content={"msg": "hello"})
38
+
39
+
40
+ @app.post("/infer_samgeo")
41
+ def samgeo():
42
+ import subprocess
43
+
44
+ from src.prediction_api.predictor import base_predict
45
+
46
+ local_logger = setup_logging()
47
+ local_logger.info("starting inference request...")
48
+
49
+ try:
50
+ import time
51
+
52
+ time_start_run = time.time()
53
+ # debug = True
54
+ # local_logger = setup_logging(debug)
55
+ message = "point_coords_segmentation"
56
+ bbox = [-122.1497, 37.6311, -122.1203, 37.6458]
57
+ point_coords = [[-122.1419, 37.6383]]
58
+ try:
59
+ output = base_predict(bbox=bbox, point_coords=point_coords)
60
+
61
+ duration_run = time.time() - time_start_run
62
+ body = {
63
+ "message": message,
64
+ "duration_run": duration_run,
65
+ # "request_id": request_id
66
+ }
67
+ local_logger.info(f"body:{body}.")
68
+ body["output"] = output
69
+ # local_logger.info(f"End_request::{request_id}...")
70
+ return JSONResponse(status_code=200, content={"body": json.dumps(body)})
71
+ except Exception as inference_exception:
72
+ home_content = subprocess.run("ls -l /home/user", shell=True, universal_newlines=True, stdout=subprocess.PIPE)
73
+ local_logger.error(f"/home/user ls -l: {home_content.stdout}.")
74
+ local_logger.error(f"inference error:{inference_exception}.")
75
+ return HTTPException(status_code=500, detail="Internal server error on inference")
76
+ except Exception as generic_exception:
77
+ local_logger.error(f"generic error:{generic_exception}.")
78
+ return HTTPException(status_code=500, detail="Generic internal server error")
79
+
80
+
81
+ @app.exception_handler(RequestValidationError)
82
+ async def request_validation_exception_handler(request: Request, exc: RequestValidationError) -> JSONResponse:
83
+ local_logger.error(f"exception errors: {exc.errors()}.")
84
+ local_logger.error(f"exception body: {exc.body}.")
85
+ headers = request.headers.items()
86
+ local_logger.error(f'request header: {dict(headers)}.' )
87
+ params = request.query_params.items()
88
+ local_logger.error(f'request query params: {dict(params)}.')
89
+ return JSONResponse(
90
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
91
+ content={"msg": "Error - Unprocessable Entity"}
92
+ )
93
+
94
+
95
+ @app.exception_handler(HTTPException)
96
+ async def http_exception_handler(request: Request, exc: HTTPException) -> JSONResponse:
97
+ local_logger.error(f"exception: {str(exc)}.")
98
+ headers = request.headers.items()
99
+ local_logger.error(f'request header: {dict(headers)}.' )
100
+ params = request.query_params.items()
101
+ local_logger.error(f'request query params: {dict(params)}.')
102
+ return JSONResponse(
103
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
104
+ content={"msg": "Error - Internal Server Error"}
105
+ )
106
+
107
+
108
+ # important: the index() function and the app.mount MUST be at the end
109
+ app.mount("/", StaticFiles(directory="static", html=True), name="static")
110
+
111
+
112
+ @app.get("/")
113
+ def index() -> FileResponse:
114
+ return FileResponse(path="/app/static/index.html", media_type="text/html")
115
+
src/prediction_api/__init__.py ADDED
File without changes
src/prediction_api/predictor.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Press the green button in the gutter to run the script.
2
+ import json
3
+
4
+ from src.utilities.constants import ROOT
5
+ from src.utilities.utilities import setup_logging
6
+
7
+
8
+ local_logger = setup_logging()
9
+
10
+
11
+ def base_predict(bbox, point_coords, point_crs="EPSG:4326", zoom=16, model_name:str="vit_h", root_folder:str=ROOT) -> str:
12
+ from samgeo import SamGeo, tms_to_geotiff
13
+
14
+ image = f"{root_folder}/satellite.tif"
15
+ local_logger.info("start tms_to_geotiff")
16
+ # bbox: image input coordinate
17
+ tms_to_geotiff(output=image, bbox=bbox, zoom=zoom, source="Satellite", overwrite=True)
18
+
19
+ local_logger.info(f"geotiff created, start to initialize samgeo instance (read model {model_name} from {root_folder})...")
20
+ predictor = SamGeo(
21
+ model_type=model_name,
22
+ checkpoint_dir=root_folder,
23
+ automatic=False,
24
+ sam_kwargs=None,
25
+ )
26
+ local_logger.info(f"initialized samgeo instance, start to set_image {image}...")
27
+ predictor.set_image(image)
28
+ output_name = f"{root_folder}/output.tif"
29
+
30
+ local_logger.info(f"done set_image, start prediction...")
31
+ predictor.predict(point_coords, point_labels=len(point_coords), point_crs=point_crs, output=output_name)
32
+
33
+ local_logger.info(f"done prediction, start tiff to geojson conversion...")
34
+
35
+ # geotiff to geojson
36
+ vector = f"{root_folder}/feats.geojson"
37
+ predictor.tiff_to_geojson(output_name, vector, bidx=1)
38
+ local_logger.info(f"start reading geojson...")
39
+
40
+ with open(vector) as out_gdf:
41
+ out_gdf_str = json.load(out_gdf)
42
+ local_logger.info(f"number of fields in geojson output:{len(out_gdf_str)}.")
43
+ return out_gdf_str
src/utilities/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ """various helpers utilities"""
src/utilities/constants.py ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Project constants"""
2
+ CHANNEL_EXAGGERATIONS_LIST = [2.5, 1.1, 2.0]
3
+ INPUT_CRS_STRING = "EPSG:4326"
4
+ OUTPUT_CRS_STRING = "EPSG:3857"
5
+ ROOT = "/home/user"
6
+ NODATA_VALUES = -32768
7
+ SKIP_CONDITIONS_LIST = [{"skip_key": "confidence", "skip_value": 0.5, "skip_condition": "major"}]
8
+ FEATURE_SQUARE_TEMPLATE = [
9
+ {'type': 'Feature', 'properties': {'id': 1},
10
+ 'geometry': {
11
+ 'type': 'MultiPolygon',
12
+ 'coordinates': [[]]
13
+ }}
14
+ ]
15
+ GEOJSON_SQUARE_TEMPLATE = {
16
+ 'type': 'FeatureCollection', 'name': 'etna_wgs84p',
17
+ 'crs': {'type': 'name', 'properties': {'name': 'urn:ogc:def:crs:OGC:1.3:CRS84'}},
18
+ 'features': FEATURE_SQUARE_TEMPLATE
19
+ }
src/utilities/measures.py ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """helpers for compute measures: hash, time benchmarks"""
2
+ from pathlib import Path
3
+
4
+
5
+ def hash_calculate(arr: any, debug: bool = False) -> str or bytes:
6
+ """
7
+ Return computed hash from input variable (typically a numpy array).
8
+
9
+ Args:
10
+ arr: input variable
11
+ debug: logging debug argument
12
+
13
+ Returns:
14
+ str or bytes: computed hash from input variable
15
+
16
+ """
17
+ import hashlib
18
+ import numpy as np
19
+ from base64 import b64encode
20
+
21
+ from src.utilities.utilities import setup_logging
22
+ local_logger = setup_logging(debug)
23
+
24
+ if isinstance(arr, np.ndarray):
25
+ hash_fn = hashlib.sha256(arr.data)
26
+ elif isinstance(arr, dict):
27
+ import json
28
+ from src.utilities.serialize import serialize
29
+
30
+ serialized = serialize(arr)
31
+ variable_to_hash = json.dumps(serialized, sort_keys=True).encode('utf-8')
32
+ hash_fn = hashlib.sha256(variable_to_hash)
33
+ elif isinstance(arr, str):
34
+ try:
35
+ hash_fn = hashlib.sha256(arr)
36
+ except TypeError:
37
+ local_logger.warning(f"TypeError, re-try encoding arg:{arr},type:{type(arr)}.")
38
+ hash_fn = hashlib.sha256(arr.encode('utf-8'))
39
+ elif isinstance(arr, bytes):
40
+ hash_fn = hashlib.sha256(arr)
41
+ else:
42
+ raise ValueError(f"variable 'arr':{arr} not yet handled.")
43
+ return b64encode(hash_fn.digest())
44
+
45
+
46
+ def sha256sum(filename: Path or str) -> str:
47
+ """
48
+ Return computed hash for input file.
49
+
50
+ Args:
51
+ filename: input variable
52
+
53
+ Returns:
54
+ str: computed hash
55
+
56
+ """
57
+ import hashlib
58
+ import mmap
59
+
60
+ h = hashlib.sha256()
61
+ with open(filename, 'rb') as f:
62
+ with mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ) as mm:
63
+ h.update(mm)
64
+ return h.hexdigest()
65
+
66
+
67
+ def perf_counter() -> float:
68
+ """
69
+ Performance counter for benchmarking.
70
+
71
+ Returns:
72
+ float: computed time value at execution time
73
+
74
+ """
75
+ import time
76
+ return time.perf_counter()
src/utilities/serialize.py ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Serialize objects"""
2
+ from typing import Mapping
3
+
4
+ from src.utilities.type_hints import ts_dict_str3, ts_dict_str2
5
+
6
+
7
+ def serialize(obj:any, include_none:bool=False) -> object:
8
+ """
9
+ Return the input object into a serializable one
10
+
11
+ Args:
12
+ obj: Object to serialize
13
+ include_none: bool to indicate if include also keys with None values during dict serialization
14
+
15
+ Returns:
16
+ object: serialized object
17
+
18
+ """
19
+ return _serialize(obj, include_none)
20
+
21
+
22
+ def _serialize(obj:any, include_none:bool) -> any:
23
+ import numpy as np
24
+
25
+ primitive = (int, float, str, bool)
26
+ # print(type(obj))
27
+ try:
28
+ if obj is None:
29
+ return None
30
+ elif isinstance(obj, np.integer):
31
+ return int(obj)
32
+ elif isinstance(obj, np.floating):
33
+ return float(obj)
34
+ elif isinstance(obj, np.ndarray):
35
+ return obj.tolist()
36
+ elif isinstance(obj, primitive):
37
+ return obj
38
+ elif type(obj) is list:
39
+ return _serialize_list(obj, include_none)
40
+ elif type(obj) is tuple:
41
+ return list(obj)
42
+ elif type(obj) is bytes:
43
+ return _serialize_bytes(obj)
44
+ elif isinstance(obj, Exception):
45
+ return _serialize_exception(obj)
46
+ # elif isinstance(obj, object):
47
+ # return _serialize_object(obj, include_none)
48
+ else:
49
+ return _serialize_object(obj, include_none)
50
+ except Exception as e_serialize:
51
+ from src.utilities.utilities import setup_logging
52
+ serialize_logger = setup_logging()
53
+ serialize_logger.error(f"e_serialize::{e_serialize}, type_obj:{type(obj)}, obj:{obj}.")
54
+ return f"object_name:{str(obj)}__object_type_str:{str(type(obj))}."
55
+
56
+
57
+ def _serialize_object(obj:Mapping[any, object], include_none:bool) -> dict[any]:
58
+ from bson import ObjectId
59
+
60
+ res = {}
61
+ if type(obj) is not dict:
62
+ keys = [i for i in obj.__dict__.keys() if (getattr(obj, i) is not None) or include_none]
63
+ else:
64
+ keys = [i for i in obj.keys() if (obj[i] is not None) or include_none]
65
+ for key in keys:
66
+ if type(obj) is not dict:
67
+ res[key] = _serialize(getattr(obj, key), include_none)
68
+ elif isinstance(obj[key], ObjectId):
69
+ continue
70
+ else:
71
+ res[key] = _serialize(obj[key], include_none)
72
+ return res
73
+
74
+
75
+ def _serialize_list(ls:list, include_none:bool) -> list:
76
+ return [_serialize(elem, include_none) for elem in ls]
77
+
78
+
79
+ def _serialize_bytes(b:bytes) -> ts_dict_str2:
80
+ import base64
81
+ encoded = base64.b64encode(b)
82
+ return {"value": encoded.decode('ascii'), "type": "bytes"}
83
+
84
+
85
+ def _serialize_exception(e: Exception) -> ts_dict_str3:
86
+ return {"msg": str(e), "type": str(type(e)), **e.__dict__}
src/utilities/type_hints.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """custom type hints"""
2
+ from typing import List, Dict, Tuple
3
+
4
+ import numpy as np
5
+
6
+ # ts_ddict1, ts_float64_1, ts_float64_2, ts_dict_str3, ts_dict_str2
7
+ input_floatlist = List[float]
8
+ input_floatlist2 = List[input_floatlist]
9
+ ts_ddict1 = Dict[str, Dict[str, any], Dict, Dict, any]
10
+ ts_dict_str2 = Dict[str, str]
11
+ ts_dict_str3 = Dict[str, str, any]
12
+ ts_float64_1 = Tuple[np.float64, np.float64, np.float64, np.float64, np.float64, np.float64]
13
+ ts_float64_2 = Tuple[np.float64, np.float64, np.float64, np.float64, np.float64, np.float64, np.float64]
14
+
15
+ """
16
+ ts_list_str1 = List[str]
17
+ ts_http2 = Tuple[ts_list_str1, ts_list_str1]
18
+ ts_list_float2 = List[float, float]
19
+ ts_llist_float2 = List[ts_list_float2, ts_list_float2]
20
+ ts_geojson = Dict[str, str, Dict[str, Dict[str]], List[str, Dict[int], Dict[str, List]]]
21
+ ts_dict_str2b = Dict[str, any]
22
+ ts_ddict2 = Dict[str, Dict, Dict[str, List]]
23
+ ts_tuple_str2 = Tuple[str, str]
24
+ ts_tuple_arr2 = Tuple[np.ndarray, np.ndarray]
25
+ ts_tuple_flat2 = Tuple[float, float]
26
+ ts_tuple_flat4 = Tuple[float, float, float, float]
27
+ ts_list_float4 = List[float, float, float, float]
28
+ ts_tuple_int4 = Tuple[int, int, int, int]
29
+ ts_ddict3 = Dict[List[Dict[float | int | str]], Dict[float | int]]
30
+ """
src/utilities/utilities.py ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Various utilities (logger, time benchmark, args dump, numerical and stats info)"""
2
+ import logging
3
+
4
+ from src.utilities.constants import ROOT
5
+
6
+
7
+ def setup_logging(debug: bool = False, formatter: str = '%(asctime)s - %(name)s - %(funcName)s(): line %(lineno)d - %(levelname)s - %(message)s') -> logging.Logger:
8
+ """
9
+ Create a logging instance with log string formatter.
10
+
11
+ Args:
12
+ debug: logging debug argument
13
+ formatter: log string formatter
14
+
15
+ Returns:
16
+ Logger
17
+
18
+ """
19
+ import logging
20
+ import sys
21
+
22
+ logger = logging.getLogger()
23
+ for h in logger.handlers:
24
+ logger.removeHandler(h)
25
+
26
+ h = logging.StreamHandler(sys.stdout)
27
+
28
+ h.setFormatter(logging.Formatter(formatter))
29
+ logger.addHandler(h)
30
+ logger.setLevel(logging.INFO)
31
+
32
+ if debug:
33
+ logger.setLevel(logging.DEBUG)
34
+ logger.debug(f"type_logger:{type(logger)}.")
35
+ return logger
36
+
37
+
38
+ def get_constants(event: dict, root: str = ROOT, dotenv_filename: str = ".env", debug=False) -> dict:
39
+ """
40
+ Return constants we need to use from event, context and environment variables (both production and test).
41
+
42
+ Args:
43
+ event: request event
44
+ root: path containing the dotenv file
45
+ dotenv_filename: dotenv filename
46
+ debug: logging debug argument
47
+
48
+ Returns:
49
+ dict: project constants object
50
+
51
+ """
52
+ import json
53
+ import os
54
+ # from dotenv import dotenv_values
55
+
56
+ from src.utilities.constants import SKIP_CONDITIONS_LIST
57
+ local_logger = setup_logging(debug)
58
+ try:
59
+ body = event["body"]
60
+ except Exception as e_constants1:
61
+ local_logger.error(f"e_constants1:{e_constants1}.")
62
+ body = event
63
+
64
+ if isinstance(body, str):
65
+ body = json.loads(event["body"])
66
+
67
+ try:
68
+ debug = body["debug"]
69
+ local_logger.info(f"re-try get debug value:{debug}, log_level:{local_logger.level}.")
70
+ local_logger = setup_logging(debug)
71
+ except KeyError:
72
+ local_logger.error("get_constants:: no debug key, pass...")
73
+ local_logger.debug(f"constants debug:{debug}, log_level:{local_logger.level}, body:{body}.")
74
+
75
+ try:
76
+ dotenv_file_path = os.path.join(root, dotenv_filename)
77
+ local_logger.info(f"root_path:{root}, dotenv file:{dotenv_file_path}.")
78
+ # secrets = dotenv_values(dotenv_file_path)
79
+
80
+ try:
81
+ skip_conditions_list = body["skip_conditions_list"]
82
+ local_logger.info(f"found skip_conditions_list, using it: {skip_conditions_list}.")
83
+ except KeyError:
84
+ skip_conditions_list = SKIP_CONDITIONS_LIST
85
+
86
+ return {
87
+ "bounding_box": body["bounding_box"],
88
+ "zoom": body["zoom"],
89
+ "debug": debug,
90
+ "slope_cellsize": body["slope_cellsize"],
91
+ "model_project_name": body["model_project_name"],
92
+ "model_version": body["model_version"],
93
+ "skip_conditions_list": skip_conditions_list
94
+ }
95
+ except KeyError as e_key_constants2:
96
+ local_logger.error(f"e_key_constants2:{e_key_constants2}.")
97
+ raise KeyError(f"e_key_constants2:{e_key_constants2}.")
98
+ except Exception as e_constants2:
99
+ local_logger.error(f"e_constants2:{e_constants2}.")
100
+ raise e_constants2
static/index.html ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <main>
2
+ <section id="coords-gen">
3
+ <h2>Segment Geospatial: Instance segmentation within images based on Segment Anything</h2>
4
+ <p>
5
+ Model:
6
+ <a
7
+ href="https://github.com/opengeos/segment-geospatial/"
8
+ rel="noreferrer"
9
+ target="_blank"
10
+ >opengeos/segment-geospatial
11
+ </a>
12
+ </p>
13
+ <form class="coords-gen-form">
14
+ <label for="coords-gen-input">Text prompt</label>
15
+ <input
16
+ id="coords-gen-input"
17
+ type="coords"
18
+ value=""
19
+ />
20
+ <button id="coords-gen-submit">Submit</button>
21
+ <p class="coords-gen-output"></p>
22
+ </form>
23
+ </section>
24
+ </main>
static/script.js ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const coordsGenForm = document.querySelector(".coords-gen-form");
2
+
3
+ const segmentCoords = async (coords) => {
4
+ const inferResponse = await fetch(`infer_samgeo?input=${coords}`);
5
+ const inferJson = await inferResponse.json();
6
+
7
+ return inferJson.output;
8
+ };
9
+
10
+ coordsGenForm.addEventListener("submit", async (event) => {
11
+ event.preventDefault();
12
+
13
+ const coordsGenInput = document.getElementById("coords-gen-input");
14
+ const coordsGenParagraph = document.querySelector(".coords-gen-output");
15
+
16
+ coordsGenParagraph.coordsContent = await segmentCoords(coordsGenInput.value);
17
+ });
static/style.css ADDED
File without changes