geoai 1.0.7 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.0.8] - 2026-09-29
11
+
12
+ ### Added
13
+ - Image geolocation task (`image-geolocation`) powered by GeoCLIP Q4 (`Xenova/geoclip-large-patch14`)
14
+ - Live demo and docs for image geolocation (`/tasks/image-geolocation`)
15
+ - Google Maps provider (`provider: "google"`) via Map Tiles API session + 2D satellite XYZ tiles
16
+
17
+ ### Fixed
18
+ - OAM item tile URLs: drop deprecated HOT TiTiler `@1x` path suffix (was returning HTTP 422)
19
+
10
20
  ## [1.0.7] - 2026-07-17
11
21
 
12
22
  ### Added
package/README.md CHANGED
@@ -1,295 +1,250 @@
1
1
  <h1 align="center">
2
- GeoAI <img src="https://cdn-icons-png.flaticon.com/256/5968/5968292.png" alt="JavaScript logo" height="24" style="vertical-align:middle" />
2
+ GeoAI.js
3
3
  </h1>
4
4
 
5
- <p align="center" style="margin-top:8px;">A lightweight JavaScript library for running Geo AI models in frontend applications.</p>
5
+ <p align="center">
6
+ <strong>Geospatial AI that runs in the browser.</strong><br/>
7
+ Detect buildings, vehicles, ships, solar panels, and more — on satellite &amp; aerial imagery — without a GPU backend.
8
+ </p>
6
9
 
7
- <p align="center" style="margin:12px 0;">
10
+ <p align="center">
8
11
  <a href="https://www.npmjs.com/package/geoai"><img alt="npm version" src="https://img.shields.io/npm/v/geoai.svg"></a>
9
- <a href="https://github.com/decision-labs/geoai.js/actions/workflows/main.yml" style="margin-left:6px"><img alt="main" src="https://github.com/decision-labs/geoai.js/actions/workflows/main.yml/badge.svg"></a>
10
- <a href="https://www.npmjs.com/package/geoai" style="margin-left:6px"><img alt="npm downloads" src="https://img.shields.io/npm/dm/geoai.svg"></a>
11
- <a href="https://docs.geobase.app/geoai" style="margin-left:6px"><img alt="docs" src="https://img.shields.io/badge/docs-online-blue"></a>
12
+ <a href="https://github.com/decision-labs/geoai.js/actions/workflows/main.yml"><img alt="CI" src="https://github.com/decision-labs/geoai.js/actions/workflows/main.yml/badge.svg"></a>
13
+ <a href="https://www.npmjs.com/package/geoai"><img alt="npm downloads" src="https://img.shields.io/npm/dm/geoai.svg"></a>
14
+ <a href="https://docs.geobase.app/geoai"><img alt="docs" src="https://img.shields.io/badge/docs-online-blue"></a>
15
+ <a href="LICENSE.md"><img alt="license" src="https://img.shields.io/badge/license-MIT-green"></a>
16
+ </p>
17
+
18
+ <p align="center">
19
+ <a href="https://docs.geobase.app/geoai-live"><strong>Live demos →</strong></a>
20
+ ·
21
+ <a href="https://docs.geobase.app/geoai"><strong>Docs →</strong></a>
22
+ ·
23
+ <a href="#agents--llms"><strong>Agent skill →</strong></a>
12
24
  </p>
13
25
 
14
26
  <div align="center">
15
- <img src="_docs4devs/geoai.gif" alt="GeoAI Demo" width="80%" style="border-radius: 16px;">
27
+ <img src="_docs4devs/geoai.gif" alt="GeoAI.js DINOv3 feature extraction demo" width="85%">
16
28
  </div>
17
29
 
18
- <p align="center" style="font-style:italic; margin:2px;">
19
- Caption: <i>example of feature extraction using the transformerjs version of dino v3, see examples at <a href="https://docs.geobase.app/geoai-live/" style="font-style:normal;">docs.geobase.app/geoai-live</a></i>
20
- </p>
30
+ <p align="center"><em>DINOv3 image feature extraction in the browser — try it at <a href="https://docs.geobase.app/geoai-live">docs.geobase.app/geoai-live</a></em></p>
21
31
 
22
- ### Quick install
32
+ ---
23
33
 
24
- ### NPM Package
34
+ ## Why GeoAI.js?
25
35
 
26
- [![npm version](https://img.shields.io/npm/v/geoai.svg)](https://www.npmjs.com/package/geoai)
27
- [![npm downloads](https://img.shields.io/npm/dm/geoai.svg)](https://www.npmjs.com/package/geoai)
36
+ | | |
37
+ |---|---|
38
+ | **Client-side** | Models run in the browser (WebGPU / WASM) via Transformers.js + ONNX Runtime |
39
+ | **Draw → detect** | Pass a GeoJSON polygon; get detections back as GeoJSON |
40
+ | **Your imagery** | ESRI, Mapbox, Geobase COGs, TMS, WMS, OpenAerialMap, Google Map Tiles |
41
+ | **Pipeline-ready** | Chain tasks; run inference off the main thread with workers |
28
42
 
29
43
  ```bash
30
44
  npm i geoai
45
+ # peers
46
+ npm i @huggingface/transformers onnxruntime-web
31
47
  ```
32
48
 
33
- 📦 **Package Links:**
34
- - [npm package](https://www.npmjs.com/package/geoai)
35
- - [jsDelivr CDN](https://www.jsdelivr.com/package/npm/geoai)
36
-
37
- ### CDN (Browser)
49
+ ```javascript
50
+ import { geoai } from "geoai";
38
51
 
39
- You can also use GeoAI directly in the browser via CDN:
52
+ const pipeline = await geoai.pipeline([{ task: "building-detection" }], {
53
+ provider: "esri", // no API key
54
+ });
40
55
 
41
- #### Unpkg CDN
42
- ```html
43
- <script src="https://unpkg.com/geoai@1.0.7/geoai.js"></script>
56
+ const result = await pipeline.inference({
57
+ inputs: { polygon: myGeoJsonPolygon },
58
+ mapSourceParams: { zoomLevel: 18 },
59
+ });
60
+ // result.detections → GeoJSON FeatureCollection
44
61
  ```
45
62
 
46
- #### jsDelivr CDN
63
+ CDN:
64
+
47
65
  ```html
48
- <script src="https://cdn.jsdelivr.net/npm/geoai@1.0.7/geoai.min.js"></script>
66
+ <script src="https://unpkg.com/geoai@1.0.8/geoai.js"></script>
67
+ <!-- or -->
68
+ <script src="https://cdn.jsdelivr.net/npm/geoai@1.0.8/geoai.min.js"></script>
49
69
  ```
50
70
 
51
- When using CDN, the library is available globally as `geoai`.
71
+ ---
52
72
 
53
- Get Started: Follow the [Quickstart Guide](https://docs.geobase.app/geoai) or clone the quick start example.
73
+ ## Use cases
54
74
 
55
- ```bash
56
- git init
57
- touch README.md
58
- git add .
59
- git commit -m "Initial commit"
60
- git subtree add --prefix=examples/01-quickstart https://github.com/decision-labs/geoai.js main --squash
61
- ```
75
+ GeoAI.js is built for product teams and researchers who need **interactive** geospatial AI — not batch jobs on a remote GPU cluster.
62
76
 
63
- ## Usage
77
+ - **Urban inventory** — building footprints & boxes for planning, insurance, or change tracking
78
+ - **Energy & infrastructure** — solar panels, oil storage tanks, utility assets
79
+ - **Transport & logistics** — cars, trucks, ships in ports and yards
80
+ - **Environment** — land cover and wetland segmentation over AOIs
81
+ - **Exploration** — zero-shot detection, DINOv3 embeddings, and image geolocation (GeoCLIP)
64
82
 
65
- ### Core Library (Node.js and Browser)
83
+ Draw an AOI on a map, run a model, store or style the GeoJSON — all in one frontend session.
66
84
 
67
- #### NPM Installation
68
- ```javascript
69
- import { geoai } from "geoai";
70
-
71
- // Initialize the pipeline with ESRI provider (no API key required)
72
- const pipeline = await geoai.pipeline([{ task: "object-detection" }], {
73
- provider: "esri",
74
- });
85
+ ### Image geolocation
75
86
 
76
- // Run inference
87
+ ```javascript
88
+ const pipeline = await geoai.pipeline(
89
+ [
90
+ {
91
+ task: "image-geolocation",
92
+ modelParams: { dtype: "q4", device: "webgpu" },
93
+ },
94
+ ],
95
+ { provider: "esri" }
96
+ );
77
97
  const result = await pipeline.inference({
78
- inputs: {
79
- polygon: geoJsonFeature,
80
- },
81
- mapSourceParams: {
82
- zoomLevel: 18,
83
- },
98
+ inputs: { image: uploadedFile, topK: 5 },
84
99
  });
100
+ // result.predictions → ranked [lat, lon] pairs
85
101
  ```
86
102
 
87
- #### CDN Usage
88
- ```javascript
89
- // When using CDN, geoai is available globally
90
- const pipeline = await geoai.pipeline([{ task: "object-detection" }], {
91
- provider: "esri",
92
- });
103
+ See the [image geolocation docs](https://docs.geobase.app/geoai/supported-tasks/image-geolocation).
93
104
 
94
- const result = await pipeline.inference({
95
- inputs: {
96
- polygon: geoJsonFeature,
97
- },
98
- mapSourceParams: {
99
- zoomLevel: 18,
100
- },
101
- });
102
- ```
105
+ ---
103
106
 
104
- ### React Hooks
107
+ ## Integrations
105
108
 
106
- ```javascript
107
- import { useGeoAIWorker } from "geoai/react";
108
-
109
- function MyComponent() {
110
- const { inference, isLoading, error } = useGeoAIWorker({
111
- tasks: ["object-detection"],
112
- provider: "esri", // No API key required for ESRI
113
- });
114
-
115
- const handleInference = async () => {
116
- const result = await inference({
117
- inputs: { polygon: geoJsonFeature },
118
- mapSourceParams: { zoomLevel: 18 },
119
- });
120
- };
121
-
122
- return (
123
- <div>
124
- <button onClick={handleInference} disabled={isLoading}>
125
- {isLoading ? "Processing..." : "Run Detection"}
126
- </button>
127
- {error && <div>Error: {error.message}</div>}
128
- </div>
129
- );
130
- }
131
- ```
109
+ Persist detections, sync in real time, and serve results as vector tiles.
132
110
 
133
- ## Features
111
+ <div align="center">
112
+ <img
113
+ src="examples/04-geoai-supabase-geobase-integration/docs/screenshot.jpg"
114
+ alt="GeoAI.js + Supabase + Geobase — map, detections, and workflow panel"
115
+ width="85%"
116
+ >
117
+ </div>
118
+
119
+ <p align="center"><em>Full-stack demo: draw → detect → save to PostGIS (Supabase or Geobase) with live map layers</em></p>
134
120
 
135
- - **Multiple AI Tasks**: Object detection, segmentation, classification, and more
136
- - **Map Provider Support**: Geobase, Mapbox, ESRI, TMS, and Google Maps
137
- - **React Integration**: Hooks for easy React integration
138
- - **TypeScript Support**: Full TypeScript definitions
139
- - **Web Worker Support**: Run AI models in background threads
140
- - **Optimized Performance**: Efficient model loading and inference
141
- - **CDN Ready**: Available via npm and popular CDNs (unpkg, jsDelivr)
121
+ | Stack | What you get |
122
+ |-------|----------------|
123
+ | **[Supabase](examples/04-geoai-supabase-geobase-integration)** | Auth, PostGIS storage, realtime subscriptions for detection history |
124
+ | **[Geobase](examples/04-geoai-supabase-geobase-integration)** | Same PostGIS path **plus** vector tileserver for thousands of styled detections |
125
+ | **[MapLibre / React](examples/live-examples-nextjs)** | Interactive task demos ([live](https://docs.geobase.app/geoai-live)); also [`01-quickstart`](examples/01-quickstart) |
126
+ | **[deck.gl](examples/deckgl-demo)** | GPU-friendly overlay workflows |
127
+ | **Agent skill** | Cursor / Claude / Codex integration via [`skills/geoai`](skills/geoai) |
142
128
 
143
- ## Supported Tasks
129
+ Quick links:
144
130
 
145
- - Object Detection
146
- - Building Detection
147
- - Car Detection
148
- - Ship Detection
149
- - Solar Panel Detection
150
- - Oil Storage Tank Detection
151
- - Land Cover Classification
152
- - Wetland Segmentation
153
- - Building Footprint Segmentation
154
- - Mask Generation
155
- - Zero-shot Object Detection
156
- - Zero-shot Segmentation
157
- - Image Feature Extraction
131
+ - Example app + guide: [`examples/04-geoai-supabase-geobase-integration`](examples/04-geoai-supabase-geobase-integration)
132
+ - Integration write-up: [`INTEGRATION_GUIDE.md`](examples/04-geoai-supabase-geobase-integration/INTEGRATION_GUIDE.md)
133
+ - Interactive tasks: [docs.geobase.app/geoai-live](https://docs.geobase.app/geoai-live)
158
134
 
159
- For more see the [supported tasks](https://docs.geobase.app/geoai/supported-tasks)
135
+ ---
160
136
 
161
- ## Map Providers
137
+ ## Map providers
162
138
 
163
- GeoAI.js supports multiple map tile providers:
139
+ Point the pipeline at the imagery you already use:
164
140
 
165
- ### TMS (Tile Map Service)
166
- TMS is a tile-based map specification that uses a bottom-left origin coordinate system. Perfect for custom tile servers and OpenAerialMap.
141
+ | Provider | Auth | Notes |
142
+ |----------|------|--------|
143
+ | **ESRI** | None | World Imagery — great default for demos |
144
+ | **Mapbox** | Token | Satellite styles |
145
+ | **Geobase** | Project + API key | Your COG / tileserver |
146
+ | **TMS** | Optional | Any `{z}/{x}/{y}` raster URL |
147
+ | **WMS** | Usually none | OGC GetMap (e.g. NRW orthophotos) |
148
+ | **OpenAerialMap** | None | HOT Imagery STAC + TiTiler |
149
+ | **Google** | API key | Map Tiles API (session + XYZ); prefer a server proxy in browsers |
167
150
 
168
151
  ```javascript
169
- // Option 1: Using URL template with placeholders (recommended)
170
- const pipeline = await geoai.pipeline([{ task: "object-detection" }], {
171
- provider: "tms",
172
- baseUrl: "https://tile.example.com/tiles/{z}/{x}/{y}.png",
173
- apiKey: "your-api-key", // optional
174
- tileSize: 256, // optional, defaults to 256
175
- attribution: "Custom TMS Provider", // optional
176
- });
152
+ // Free public imagery
153
+ { provider: "esri" }
177
154
 
178
- // Option 2: Using base URL (legacy format, still supported)
179
- const pipeline = await geoai.pipeline([{ task: "object-detection" }], {
180
- provider: "tms",
181
- baseUrl: "https://tile.example.com/tiles",
182
- extension: "png", // optional, defaults to "png"
183
- apiKey: "your-api-key", // optional
184
- tileSize: 256, // optional, defaults to 256
185
- attribution: "Custom TMS Provider", // optional
186
- });
187
- ```
155
+ // Community aerial (OAM)
156
+ { provider: "oam" /* , itemId, mosaic: true */ }
188
157
 
189
- ### OpenAerialMap (OAM)
190
- Community aerial imagery via HOT Imagery STAC + TiTiler — no API key.
158
+ // Your COG on Geobase
159
+ {
160
+ provider: "geobase",
161
+ projectRef: "...",
162
+ apikey: "...",
163
+ cogImagery: "https://path-to-your-cog.tif",
164
+ }
191
165
 
192
- ```javascript
193
- const pipeline = await geoai.pipeline([{ task: "object-detection" }], {
194
- provider: "oam",
195
- // itemId: "67826781a07cc20001818cdb", // optional pin
196
- // mosaic: true, // optional: collection mosaic only
197
- });
166
+ // Google Map Tiles (enable Map Tiles API; avoid HTTP-referrer–only keys)
167
+ { provider: "google", apiKey: process.env.GOOGLE_MAPS_API_KEY }
198
168
  ```
199
169
 
200
- ### ESRI
201
- ESRI World Imagery - no API key required.
170
+ Docs: [Map providers](https://docs.geobase.app/geoai/map-providers)
202
171
 
203
- ```javascript
204
- const pipeline = await geoai.pipeline([{ task: "object-detection" }], {
205
- provider: "esri",
206
- });
207
- ```
172
+ ---
208
173
 
209
- ### Mapbox
210
- Requires a Mapbox API key.
174
+ ## Supported tasks
211
175
 
212
- ```javascript
213
- const pipeline = await geoai.pipeline([{ task: "object-detection" }], {
214
- provider: "mapbox",
215
- apiKey: "your-mapbox-api-key",
216
- style: "mapbox://styles/mapbox/satellite-v9",
217
- });
218
- ```
176
+ Object detection · Building detection · Building footprint segmentation (ChangeStar) · Car · Ship · Solar panel · Oil storage tank · Oriented object detection · Land cover · Wetland · Mask generation · Zero-shot detection & segmentation · Image feature extraction (DINOv3)
219
177
 
220
- ### Geobase
221
- Requires Geobase project credentials.
178
+ → [Full task reference](https://docs.geobase.app/geoai/supported-tasks)
222
179
 
223
- ```javascript
224
- const pipeline = await geoai.pipeline([{ task: "object-detection" }], {
225
- provider: "geobase",
226
- projectRef: "your-project-ref",
227
- apikey: "your-api-key",
228
- cogImagery: "https://path-to-your-cog.tif",
229
- });
230
- ```
180
+ ---
231
181
 
232
- ## Talk
182
+ ## Workers & React
233
183
 
234
- **[Bringing Earth Observation AI to the Browser with WebGPU](talks/lightning-talk-webgpu-geoai.md)** — lightning talk at Big Data from Space 2025 (Decision Labs).
184
+ Keep the UI smooth — run inference in a **Web Worker**. Patterns for vanilla JS and React live in the skill and docs (there is no separate `geoai/react` package export; use the worker + hook examples).
235
185
 
236
- <div align="center">
237
- <a href="https://geobase-docs.s3.amazonaws.com/geobase-ai-assets/talks/lightning-talk-webgpu-geoai.pdf">
238
- <img src="https://geobase-docs.s3.amazonaws.com/geobase-ai-assets/talks/geoaijs.png" alt="GeoAI.js talk preview" width="480">
239
- </a>
240
- </div>
186
+ - [Workers guide](https://docs.geobase.app/geoai/workers)
187
+ - [React quickstart](https://docs.geobase.app/geoai/frontend-frameworks/react-quickstart)
188
+ - Example: [`examples/02-quickstart-with-workers`](examples/02-quickstart-with-workers)
241
189
 
242
- - [Slides (PDF)](https://geobase-docs.s3.amazonaws.com/geobase-ai-assets/talks/lightning-talk-webgpu-geoai.pdf)
243
- - [Slide source (Marp)](talks/lightning-talk-webgpu-geoai.md)
190
+ ---
244
191
 
245
- ## Agents & LLMs
192
+ ## Quickstart clone
193
+
194
+ ```bash
195
+ git init
196
+ git subtree add --prefix=examples/01-quickstart \
197
+ https://github.com/decision-labs/geoai.js main --squash
198
+ cd examples/01-quickstart && npm install && npm run dev
199
+ ```
246
200
 
247
- ### Install the GeoAI agent skill
201
+ ---
248
202
 
249
- Use the [Skills CLI](https://skills.sh/) so coding agents (Cursor, Claude Code, Codex, etc.) load GeoAI.js integration guidance automatically:
203
+ ## Agents & LLMs
204
+
205
+ Teach coding agents how to integrate GeoAI.js:
250
206
 
251
207
  ```bash
252
- # Install into the current project (recommended)
253
208
  npx skills add decision-labs/geoai.js --skill geoai -y
254
-
255
- # Or install globally for all projects
209
+ # or globally
256
210
  npx skills add decision-labs/geoai.js --skill geoai -g -y
257
211
  ```
258
212
 
259
- List what you have installed:
213
+ - Skill source: [`skills/geoai`](skills/geoai)
214
+ - LLM docs index: [llms.txt](https://docs.geobase.app/geoai/llms.txt)
215
+ - Full corpus: [llms-full.txt](https://docs.geobase.app/geoai/llms-full.txt) (`pnpm docs:llms`)
260
216
 
261
- ```bash
262
- npx skills list
263
- ```
217
+ ---
264
218
 
265
- Use the skill once without installing (pipes a prompt into an agent):
219
+ ## Talk
266
220
 
267
- ```bash
268
- npx skills use decision-labs/geoai.js@geoai
269
- ```
221
+ **[Bringing Earth Observation AI to the Browser with WebGPU](talks/lightning-talk-webgpu-geoai.md)** — Big Data from Space 2025 (Decision Labs).
270
222
 
271
- Source: [`skills/geoai`](skills/geoai) — pipeline API, task picker, providers, and Web Worker patterns for background inference.
223
+ <div align="center">
224
+ <a href="https://geobase-docs.s3.amazonaws.com/geobase-ai-assets/talks/lightning-talk-webgpu-geoai.pdf">
225
+ <img src="https://geobase-docs.s3.amazonaws.com/geobase-ai-assets/talks/geoaijs.png" alt="GeoAI.js talk preview" width="480">
226
+ </a>
227
+ </div>
272
228
 
273
- ### LLM-readable docs
229
+ - [Slides (PDF)](https://geobase-docs.s3.amazonaws.com/geobase-ai-assets/talks/lightning-talk-webgpu-geoai.pdf)
274
230
 
275
- - **Index**: [docs.geobase.app/geoai/llms.txt](https://docs.geobase.app/geoai/llms.txt)
276
- - **Full corpus**: [docs.geobase.app/geoai/llms-full.txt](https://docs.geobase.app/geoai/llms-full.txt) — regenerate with `pnpm docs:llms`
231
+ ---
277
232
 
278
233
  ## Links
279
234
 
280
- - **Documentation**: [docs.geobase.app/geoai](https://docs.geobase.app/geoai) - Comprehensive documentation, examples, and API reference
281
- - **Live Examples**: [docs.geobase.app/geoai-live](https://docs.geobase.app/geoai-live) - Interactive examples and demos
282
- - **Roadmap**: [_docs4devs/ROADMAP.md](_docs4devs/ROADMAP.md) - Planned docs, quantization pipeline, and related backlog
283
- - **Community**: [GitHub Discussions](https://github.com/decision-labs/geoai.js/discussions) - Ask questions, share ideas, and connect with other developers
284
- - **Code**: [GitHub Repository](https://github.com/decision-labs/geoai.js) - Source code and contributions
285
- - **Issues**: [GitHub Issues](https://github.com/decision-labs/geoai.js/issues) - Report bugs and request features
235
+ - **Docs** — [docs.geobase.app/geoai](https://docs.geobase.app/geoai)
236
+ - **Live examples** — [docs.geobase.app/geoai-live](https://docs.geobase.app/geoai-live)
237
+ - **npm** — [geoai](https://www.npmjs.com/package/geoai)
238
+ - **Roadmap** — [_docs4devs/ROADMAP.md](_docs4devs/ROADMAP.md)
239
+ - **Discussions** — [GitHub Discussions](https://github.com/decision-labs/geoai.js/discussions)
240
+ - **Issues** — [GitHub Issues](https://github.com/decision-labs/geoai.js/issues)
286
241
 
287
242
  ## Contributing
288
243
 
289
- We welcome contributions! Please see our [contributing guide](CONTRIBUTING.md) for details.
244
+ See [CONTRIBUTING.md](CONTRIBUTING.md).
290
245
 
291
246
  ## License
292
247
 
293
- MIT License - see [LICENSE.md](LICENSE.md) for details.
248
+ MIT — [LICENSE.md](LICENSE.md)
294
249
 
295
250
  [//]: <> (Toggle CI off)
package/geoai.js CHANGED
@@ -390,7 +390,7 @@ const postProcessYoloOutput = (model_outputs, pixel_values, rawImage, id2label)
390
390
  return model_output;
391
391
  };
392
392
  const parametersChanged = (instance, model_id, providerParams, modelParams) => {
393
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
393
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u;
394
394
  if (instance.model_id !== model_id) {
395
395
  return true;
396
396
  }
@@ -430,6 +430,11 @@ const parametersChanged = (instance, model_id, providerParams, modelParams) => {
430
430
  return true;
431
431
  }
432
432
  break;
433
+ case "google":
434
+ if (((_s = instance.providerParams) == null ? void 0 : _s.apiKey) !== (providerParams == null ? void 0 : providerParams.apiKey) || ((_t = instance.providerParams) == null ? void 0 : _t.mapType) !== (providerParams == null ? void 0 : providerParams.mapType) || ((_u = instance.providerParams) == null ? void 0 : _u.sessionToken) !== (providerParams == null ? void 0 : providerParams.sessionToken)) {
435
+ return true;
436
+ }
437
+ break;
433
438
  }
434
439
  if (modelParams) {
435
440
  const instanceModelParams = instance.modelParams || {};
@@ -1395,7 +1400,7 @@ function buildOamMosaicTileUrlTemplate(rasterUrl = DEFAULT_OAM_RASTER_URL, colle
1395
1400
  }
1396
1401
  function buildOamItemTileUrlTemplate(itemId, rasterUrl = DEFAULT_OAM_RASTER_URL, collection = DEFAULT_OAM_COLLECTION, asset = DEFAULT_OAM_ASSET) {
1397
1402
  const base = rasterUrl.replace(/\/$/, "");
1398
- return `${base}/collections/${encodeURIComponent(collection)}/items/${encodeURIComponent(itemId)}/tiles/WebMercatorQuad/{z}/{x}/{y}@1x?assets=${encodeURIComponent(asset)}`;
1403
+ return `${base}/collections/${encodeURIComponent(collection)}/items/${encodeURIComponent(itemId)}/tiles/WebMercatorQuad/{z}/{x}/{y}?assets=${encodeURIComponent(asset)}`;
1399
1404
  }
1400
1405
  function pickBestOamItem(features) {
1401
1406
  if (!features.length) return void 0;
@@ -1554,6 +1559,154 @@ class Oam extends MapSource {
1554
1559
  return instance.tileUrlTemplate.replaceAll("{z}", z.toString()).replaceAll("{x}", x.toString()).replaceAll("{y}", y.toString());
1555
1560
  }
1556
1561
  }
1562
+ const DEFAULT_GOOGLE_TILE_API_URL = "https://tile.googleapis.com";
1563
+ const DEFAULT_GOOGLE_MAP_TYPE = "satellite";
1564
+ function buildGoogleCreateSessionUrl(apiKey, tileApiUrl = DEFAULT_GOOGLE_TILE_API_URL, includeApiKey = true) {
1565
+ const base = tileApiUrl.replace(/\/$/, "");
1566
+ if (!includeApiKey) {
1567
+ return `${base}/v1/createSession`;
1568
+ }
1569
+ return `${base}/v1/createSession?key=${encodeURIComponent(apiKey)}`;
1570
+ }
1571
+ function buildGoogleTileUrl(z, x, y, sessionToken, apiKey, tileApiUrl = DEFAULT_GOOGLE_TILE_API_URL, includeApiKey = true) {
1572
+ const base = tileApiUrl.replace(/\/$/, "");
1573
+ let url = `${base}/v1/2dtiles/${z}/${x}/${y}?session=${encodeURIComponent(sessionToken)}`;
1574
+ if (includeApiKey) {
1575
+ url += `&key=${encodeURIComponent(apiKey)}`;
1576
+ }
1577
+ return url;
1578
+ }
1579
+ async function createGoogleSession(options) {
1580
+ const apiKey = options.apiKey;
1581
+ const includeApiKey = options.includeApiKey !== false;
1582
+ if (includeApiKey && !apiKey) {
1583
+ throw new Error("Google Maps provider requires an apiKey");
1584
+ }
1585
+ const fetchImpl = options.fetchImpl || fetch;
1586
+ const url = buildGoogleCreateSessionUrl(
1587
+ apiKey,
1588
+ options.tileApiUrl || DEFAULT_GOOGLE_TILE_API_URL,
1589
+ includeApiKey
1590
+ );
1591
+ const response = await fetchImpl(url, {
1592
+ method: "POST",
1593
+ headers: {
1594
+ "Content-Type": "application/json",
1595
+ ...options.headers || {}
1596
+ },
1597
+ body: JSON.stringify({
1598
+ mapType: options.mapType || DEFAULT_GOOGLE_MAP_TYPE,
1599
+ language: options.language || "en-US",
1600
+ region: options.region || "US"
1601
+ })
1602
+ });
1603
+ if (!response.ok) {
1604
+ const body = await response.text().catch(() => "");
1605
+ throw new Error(
1606
+ `Google Map Tiles createSession failed (${response.status}): ${body || response.statusText}`
1607
+ );
1608
+ }
1609
+ const data = await response.json();
1610
+ if (!data.session) {
1611
+ throw new Error("Google Map Tiles createSession returned no session token");
1612
+ }
1613
+ return data;
1614
+ }
1615
+ class GoogleMaps extends MapSource {
1616
+ constructor(config) {
1617
+ super();
1618
+ __publicField(this, "apiKey");
1619
+ __publicField(this, "mapType");
1620
+ __publicField(this, "language");
1621
+ __publicField(this, "region");
1622
+ __publicField(this, "tileApiUrl");
1623
+ __publicField(this, "includeApiKey");
1624
+ __publicField(this, "attribution");
1625
+ __publicField(this, "tileSize");
1626
+ __publicField(this, "headers");
1627
+ __publicField(this, "fetchImpl");
1628
+ __publicField(this, "sessionToken");
1629
+ /** Unix epoch seconds when the session expires. */
1630
+ __publicField(this, "sessionExpiry");
1631
+ this.includeApiKey = config.includeApiKey !== false;
1632
+ if (this.includeApiKey && !config.apiKey) {
1633
+ throw new Error("Google Maps provider requires an apiKey");
1634
+ }
1635
+ this.apiKey = config.apiKey || "";
1636
+ this.mapType = config.mapType || DEFAULT_GOOGLE_MAP_TYPE;
1637
+ this.language = config.language || "en-US";
1638
+ this.region = config.region || "US";
1639
+ this.tileApiUrl = (config.tileApiUrl || DEFAULT_GOOGLE_TILE_API_URL).replace(/\/$/, "");
1640
+ this.attribution = config.attribution || "© Google Maps / Map Tiles API";
1641
+ this.tileSize = config.tileSize || 256;
1642
+ this.headers = config.headers;
1643
+ this.fetchImpl = config.fetchImpl || fetch;
1644
+ this.sessionToken = config.sessionToken;
1645
+ }
1646
+ isSessionValid(skewSeconds = 60) {
1647
+ if (!this.sessionToken) {
1648
+ return false;
1649
+ }
1650
+ if (this.sessionExpiry == null) {
1651
+ return true;
1652
+ }
1653
+ const now = Math.floor(Date.now() / 1e3);
1654
+ return this.sessionExpiry - skewSeconds > now;
1655
+ }
1656
+ /**
1657
+ * Ensure a valid Map Tiles session exists (create or refresh).
1658
+ */
1659
+ async ensureSession() {
1660
+ if (this.isSessionValid()) {
1661
+ return this.sessionToken;
1662
+ }
1663
+ const data = await createGoogleSession({
1664
+ apiKey: this.apiKey,
1665
+ mapType: this.mapType,
1666
+ language: this.language,
1667
+ region: this.region,
1668
+ tileApiUrl: this.tileApiUrl,
1669
+ includeApiKey: this.includeApiKey,
1670
+ headers: this.headers,
1671
+ fetchImpl: this.fetchImpl
1672
+ });
1673
+ this.sessionToken = data.session;
1674
+ const expiry = Number(data.expiry);
1675
+ this.sessionExpiry = Number.isFinite(expiry) ? expiry : void 0;
1676
+ if (typeof data.tileWidth === "number") {
1677
+ this.tileSize = data.tileWidth;
1678
+ }
1679
+ return this.sessionToken;
1680
+ }
1681
+ async getImage(polygon2, bands, expression, zoomLevel, requiresSquare = false, stitch = true) {
1682
+ await this.ensureSession();
1683
+ return super.getImage(
1684
+ polygon2,
1685
+ bands,
1686
+ expression,
1687
+ zoomLevel,
1688
+ requiresSquare,
1689
+ stitch
1690
+ );
1691
+ }
1692
+ getTileUrlFromTileCoords(tileCoords, instance) {
1693
+ if (!instance.sessionToken) {
1694
+ throw new Error(
1695
+ "Google Maps session is not ready. Call ensureSession() or getImage() first."
1696
+ );
1697
+ }
1698
+ const [x, y, z] = tileCoords;
1699
+ return buildGoogleTileUrl(
1700
+ z,
1701
+ x,
1702
+ y,
1703
+ instance.sessionToken,
1704
+ instance.apiKey,
1705
+ instance.tileApiUrl,
1706
+ instance.includeApiKey
1707
+ );
1708
+ }
1709
+ }
1557
1710
  class BaseModel {
1558
1711
  constructor(model_id, providerParams, modelParams) {
1559
1712
  __publicField(this, "providerParams");
@@ -1636,6 +1789,20 @@ class BaseModel {
1636
1789
  headers: this.providerParams.headers
1637
1790
  });
1638
1791
  break;
1792
+ case "google":
1793
+ this.dataProvider = new GoogleMaps({
1794
+ apiKey: this.providerParams.apiKey,
1795
+ mapType: this.providerParams.mapType,
1796
+ language: this.providerParams.language,
1797
+ region: this.providerParams.region,
1798
+ sessionToken: this.providerParams.sessionToken,
1799
+ tileApiUrl: this.providerParams.tileApiUrl,
1800
+ includeApiKey: this.providerParams.includeApiKey,
1801
+ attribution: this.providerParams.attribution,
1802
+ tileSize: this.providerParams.tileSize,
1803
+ headers: this.providerParams.headers
1804
+ });
1805
+ break;
1639
1806
  case "sentinel":
1640
1807
  throw new Error("Sentinel provider not implemented yet");
1641
1808
  default:
@@ -3872,7 +4039,147 @@ const BuildingSegmentationFactory = {
3872
4039
  return create(params, resolvedId, modelParams);
3873
4040
  }
3874
4041
  };
4042
+ const GPS_GALLERY_URL = "https://huggingface.co/Xenova/geoclip-large-patch14/resolve/main/gps_gallery/coordinates_100K.json";
4043
+ const DEFAULT_TOP_K = 5;
4044
+ const COORDINATE_BATCH_SIZE = 512;
4045
+ const LOGIT_SCALE = Math.exp(3.681034803390503);
4046
+ const _ImageGeolocation = class _ImageGeolocation extends BaseModel {
4047
+ constructor(modelId, providerParams, modelParams) {
4048
+ super(modelId, providerParams, modelParams);
4049
+ __publicField(this, "visionModel");
4050
+ __publicField(this, "locationModel");
4051
+ __publicField(this, "processor");
4052
+ __publicField(this, "gpsGallery");
4053
+ }
4054
+ static async getInstance(modelId, providerParams, modelParams) {
4055
+ if (!_ImageGeolocation.instance || parametersChanged(
4056
+ _ImageGeolocation.instance,
4057
+ modelId,
4058
+ providerParams,
4059
+ modelParams
4060
+ )) {
4061
+ _ImageGeolocation.instance = new _ImageGeolocation(
4062
+ modelId,
4063
+ providerParams,
4064
+ modelParams
4065
+ );
4066
+ await _ImageGeolocation.instance.initialize();
4067
+ }
4068
+ return { instance: _ImageGeolocation.instance };
4069
+ }
4070
+ async initializeModel() {
4071
+ var _a;
4072
+ this.visionModel = await AutoModel.from_pretrained(this.model_id, {
4073
+ ...this.modelParams,
4074
+ model_file_name: "vision_model"
4075
+ });
4076
+ this.locationModel = await AutoModel.from_pretrained(this.model_id, {
4077
+ model_file_name: "location_model",
4078
+ dtype: "fp32",
4079
+ device: (_a = this.modelParams) == null ? void 0 : _a.device
4080
+ });
4081
+ this.processor = await AutoProcessor.from_pretrained(
4082
+ "openai/clip-vit-large-patch14"
4083
+ );
4084
+ }
4085
+ async getGpsGallery() {
4086
+ if (!this.gpsGallery) {
4087
+ const response = await fetch(GPS_GALLERY_URL);
4088
+ if (!response.ok)
4089
+ throw new Error(
4090
+ `Unable to load GeoCLIP's GPS gallery (${response.status})`
4091
+ );
4092
+ this.gpsGallery = await response.json();
4093
+ }
4094
+ return this.gpsGallery;
4095
+ }
4096
+ async inference(params) {
4097
+ var _a, _b, _c;
4098
+ const { polygon: polygon2, image, topK = DEFAULT_TOP_K } = params.inputs;
4099
+ if (!(image instanceof Blob) && (!polygon2 || !polygon2.geometry || polygon2.geometry.type !== "Polygon")) {
4100
+ throw new Error(
4101
+ "Provide an uploaded image or a valid GeoJSON Polygon feature for image geolocation"
4102
+ );
4103
+ }
4104
+ if (!this.initialized) await this.initialize();
4105
+ if (!this.visionModel || !this.locationModel || !this.processor)
4106
+ throw new Error("GeoCLIP model was not initialized");
4107
+ const geoRawImage = image instanceof Blob ? void 0 : await this.polygonToImage(
4108
+ polygon2,
4109
+ (_a = params.mapSourceParams) == null ? void 0 : _a.zoomLevel,
4110
+ (_b = params.mapSourceParams) == null ? void 0 : _b.bands,
4111
+ (_c = params.mapSourceParams) == null ? void 0 : _c.expression
4112
+ );
4113
+ const inputImage = image instanceof Blob ? await RawImage.fromBlob(image) : geoRawImage;
4114
+ const visionOutput = await this.visionModel(
4115
+ await this.processor(inputImage)
4116
+ );
4117
+ const imageEmbeds = visionOutput.image_embeds;
4118
+ if (!imageEmbeds)
4119
+ throw new Error("GeoCLIP vision model did not return image embeddings");
4120
+ const normalizedImage = imageEmbeds.normalize().data;
4121
+ const gallery = await this.getGpsGallery();
4122
+ const candidates = [];
4123
+ for (let offset = 0; offset < gallery.length; offset += COORDINATE_BATCH_SIZE) {
4124
+ const coordinates = gallery.slice(offset, offset + COORDINATE_BATCH_SIZE);
4125
+ const locationOutput = await this.locationModel({
4126
+ location: new Tensor("float32", coordinates.flat(), [
4127
+ coordinates.length,
4128
+ 2
4129
+ ])
4130
+ });
4131
+ const locationEmbeds = locationOutput.location_embeds;
4132
+ if (!locationEmbeds)
4133
+ throw new Error(
4134
+ "GeoCLIP location model did not return location embeddings"
4135
+ );
4136
+ const normalizedLocations = locationEmbeds.normalize().data;
4137
+ for (let coordinateIndex = 0; coordinateIndex < coordinates.length; coordinateIndex++) {
4138
+ let dotProduct = 0;
4139
+ for (let dimension = 0; dimension < normalizedImage.length; dimension++) {
4140
+ dotProduct += normalizedImage[dimension] * normalizedLocations[coordinateIndex * normalizedImage.length + dimension];
4141
+ }
4142
+ candidates.push({
4143
+ index: offset + coordinateIndex,
4144
+ gps: coordinates[coordinateIndex],
4145
+ score: LOGIT_SCALE * dotProduct
4146
+ });
4147
+ }
4148
+ }
4149
+ const maxScore = candidates.reduce(
4150
+ (maximum, candidate) => Math.max(maximum, candidate.score),
4151
+ Number.NEGATIVE_INFINITY
4152
+ );
4153
+ const scoreTotal = candidates.reduce(
4154
+ (total, candidate) => total + Math.exp(candidate.score - maxScore),
4155
+ 0
4156
+ );
4157
+ const predictions = candidates.map((candidate) => ({
4158
+ ...candidate,
4159
+ score: Math.exp(candidate.score - maxScore) / scoreTotal
4160
+ })).sort((a, b) => b.score - a.score).slice(0, Math.max(1, Math.floor(Number(topK) || DEFAULT_TOP_K)));
4161
+ return {
4162
+ predictions,
4163
+ geoRawImage,
4164
+ metadata: { modelId: this.model_id, gallerySize: gallery.length }
4165
+ };
4166
+ }
4167
+ };
4168
+ __publicField(_ImageGeolocation, "instance", null);
4169
+ let ImageGeolocation = _ImageGeolocation;
3875
4170
  const modelRegistry = [
4171
+ {
4172
+ task: "image-geolocation",
4173
+ library: "@huggingface/transformers",
4174
+ description: "Estimates where an image was taken by matching visual features against GeoCLIP's worldwide GPS gallery.",
4175
+ examples: [
4176
+ "Estimate where this landscape image was taken.",
4177
+ "Find likely locations for this aerial image.",
4178
+ "Geolocate this landmark photograph."
4179
+ ],
4180
+ ioConfig: {},
4181
+ geobase_ai_pipeline: (params, modelId = "Xenova/geoclip-large-patch14", modelParams = { dtype: "q4" }) => ImageGeolocation.getInstance(modelId, params, modelParams)
4182
+ },
3876
4183
  {
3877
4184
  task: "zero-shot-object-detection",
3878
4185
  library: "@huggingface/transformers",
package/index.d.ts CHANGED
@@ -247,10 +247,63 @@ declare class Oam extends MapSource {
247
247
  number
248
248
  ], instance: Oam): string;
249
249
  }
250
+ export type GoogleMapType = "satellite" | "roadmap" | "terrain";
251
+ export interface GoogleConfig {
252
+ /** Google Maps Platform API key with Map Tiles API enabled. */
253
+ apiKey: string;
254
+ /** 2D map type for the session (default `satellite`). */
255
+ mapType?: GoogleMapType;
256
+ language?: string;
257
+ region?: string;
258
+ /**
259
+ * Optional pre-created session token. When omitted, the provider creates
260
+ * one via `POST /v1/createSession` and refreshes near expiry.
261
+ */
262
+ sessionToken?: string;
263
+ /** Session/tile API root (default https://tile.googleapis.com). */
264
+ tileApiUrl?: string;
265
+ /**
266
+ * When false, omit `key=` from createSession/tile URLs (use with a same-origin
267
+ * proxy that injects the server-side API key). Default true.
268
+ */
269
+ includeApiKey?: boolean;
270
+ attribution?: string;
271
+ tileSize?: number;
272
+ headers?: Record<string, string>;
273
+ /** Injected for tests. */
274
+ fetchImpl?: typeof fetch;
275
+ }
276
+ declare class GoogleMaps extends MapSource {
277
+ apiKey: string;
278
+ mapType: GoogleMapType;
279
+ language: string;
280
+ region: string;
281
+ tileApiUrl: string;
282
+ includeApiKey: boolean;
283
+ attribution: string;
284
+ tileSize: number;
285
+ headers?: Record<string, string>;
286
+ fetchImpl: typeof fetch;
287
+ sessionToken?: string;
288
+ /** Unix epoch seconds when the session expires. */
289
+ sessionExpiry?: number;
290
+ constructor(config: GoogleConfig);
291
+ private isSessionValid;
292
+ /**
293
+ * Ensure a valid Map Tiles session exists (create or refresh).
294
+ */
295
+ ensureSession(): Promise<string>;
296
+ getImage(polygon: any, bands?: number[], expression?: string, zoomLevel?: number, requiresSquare?: boolean, stitch?: boolean): Promise<GeoRawImage | GeoRawImage[][]>;
297
+ protected getTileUrlFromTileCoords(tileCoords: [
298
+ number,
299
+ number,
300
+ number
301
+ ], instance: GoogleMaps): string;
302
+ }
250
303
  declare abstract class BaseModel {
251
304
  protected static instance: BaseModel | null;
252
305
  protected providerParams: ProviderParams;
253
- protected dataProvider: Mapbox | Geobase | Esri | Tms | Wms | Oam | undefined;
306
+ protected dataProvider: Mapbox | Geobase | Esri | Tms | Wms | Oam | GoogleMaps | undefined;
254
307
  protected model_id: string;
255
308
  protected initialized: boolean;
256
309
  protected modelParams?: PretrainedModelOptions;
@@ -571,6 +624,20 @@ declare class ChangeStarBuildingSegmentation extends BaseDenseSegmentationModel
571
624
  instance: ChangeStarBuildingSegmentation;
572
625
  }>;
573
626
  }
627
+ declare class ImageGeolocation extends BaseModel {
628
+ protected static instance: ImageGeolocation | null;
629
+ private visionModel;
630
+ private locationModel;
631
+ private processor;
632
+ private gpsGallery;
633
+ private constructor();
634
+ static getInstance(modelId: string, providerParams: ProviderParams, modelParams?: PretrainedModelOptions): Promise<{
635
+ instance: ImageGeolocation;
636
+ }>;
637
+ protected initializeModel(): Promise<void>;
638
+ private getGpsGallery;
639
+ inference(params: InferenceParams): Promise<ImageGeolocationResults>;
640
+ }
574
641
  export type MapboxParams = {
575
642
  provider: "mapbox";
576
643
  apiKey: string;
@@ -635,8 +702,29 @@ export type OamParams = {
635
702
  tileSize?: number;
636
703
  headers?: Record<string, string>;
637
704
  };
705
+ export type GoogleMapsParams = {
706
+ provider: "google";
707
+ /** Google Maps Platform API key with Map Tiles API enabled. */
708
+ apiKey: string;
709
+ /** 2D map type for the session (default satellite). */
710
+ mapType?: "satellite" | "roadmap" | "terrain";
711
+ language?: string;
712
+ region?: string;
713
+ /** Optional pre-created session token (skips createSession until expiry). */
714
+ sessionToken?: string;
715
+ /** Override API root (e.g. same-origin proxy). Default https://tile.googleapis.com */
716
+ tileApiUrl?: string;
717
+ /**
718
+ * When false, omit `key=` from requests (proxy injects the server key).
719
+ * Default true.
720
+ */
721
+ includeApiKey?: boolean;
722
+ attribution?: string;
723
+ tileSize?: number;
724
+ headers?: Record<string, string>;
725
+ };
638
726
  export interface InferenceInputs {
639
- polygon: GeoJSON.Feature;
727
+ polygon?: GeoJSON.Feature;
640
728
  classLabel?: string;
641
729
  [key: string]: unknown;
642
730
  }
@@ -653,10 +741,10 @@ export interface InferenceParams {
653
741
  postProcessingParams?: PostProcessingParams;
654
742
  mapSourceParams?: MapSourceParams;
655
743
  }
656
- export type ProviderParams = MapboxParams | SentinelParams | GeobaseParams | EsriParams | TmsParams | WmsParams | OamParams;
657
- export type HuggingFaceModelTask = "mask-generation" | "zero-shot-object-detection" | "zero-shot-image-classification" | "object-detection" | "oriented-object-detection" | "image-feature-extraction";
744
+ export type ProviderParams = MapboxParams | SentinelParams | GeobaseParams | EsriParams | TmsParams | WmsParams | OamParams | GoogleMapsParams;
745
+ export type HuggingFaceModelTask = "mask-generation" | "zero-shot-object-detection" | "zero-shot-image-classification" | "object-detection" | "oriented-object-detection" | "image-feature-extraction" | "image-geolocation";
658
746
  export type GeobaseAiModelTask = "damage-assessment" | "vegetation-classification" | "land-cover-classification" | "land-use-classification" | "land-cover-change-detection" | "land-use-change-detection" | "solar-panel-detection" | "ship-detection" | "car-detection" | "wetland-segmentation" | "building-detection" | "oil-storage-tank-detection" | "building-footprint-segmentation";
659
- export type ModelInstance = MaskGeneration | ZeroShotObjectDetection | ObjectDetection | OrientedObjectDetection | LandCoverClassification | SolarPanelDetection | ShipDetection | CarDetection | WetLandSegmentation | BuildingDetection | ChangeStarBuildingSegmentation | OilStorageTankDetection | BuildingFootPrintSegmentation | ImageFeatureExtraction;
747
+ export type ModelInstance = MaskGeneration | ZeroShotObjectDetection | ObjectDetection | OrientedObjectDetection | LandCoverClassification | SolarPanelDetection | ShipDetection | CarDetection | WetLandSegmentation | BuildingDetection | ChangeStarBuildingSegmentation | OilStorageTankDetection | BuildingFootPrintSegmentation | ImageFeatureExtraction | ImageGeolocation;
660
748
  export type ModelConfig = {
661
749
  task: HuggingFaceModelTask | GeobaseAiModelTask;
662
750
  library: string;
@@ -694,6 +782,21 @@ export interface ImageFeatureExtractionResults {
694
782
  modelId: string;
695
783
  };
696
784
  }
785
+ export interface ImageGeolocationResults {
786
+ predictions: Array<{
787
+ index: number;
788
+ gps: [
789
+ number,
790
+ number
791
+ ];
792
+ score: number;
793
+ }>;
794
+ geoRawImage?: GeoRawImage;
795
+ metadata: {
796
+ modelId: string;
797
+ gallerySize: number;
798
+ };
799
+ }
697
800
  export interface ChainInstance {
698
801
  inference: (inputs: InferenceParams) => Promise<ObjectDetectionResults | SegmentationResults>;
699
802
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "geoai",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "A JavaScript library for running Geo AI models in frontend applications",
5
5
  "keywords": [
6
6
  "geoai",