@webmcp-auto-ui/agent 2.5.8 → 2.5.10
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/package.json +1 -1
- package/src/autoui-server.ts +134 -134
- package/src/diagnostics.ts +3 -3
- package/src/loop.ts +6 -6
- package/src/providers/wasm.ts +5 -5
- package/src/recipes/_generated.ts +446 -446
- package/src/recipes/afficher-oeuvres-art-collection-musee.md +45 -45
- package/src/recipes/analyser-actualites-hacker-news.md +52 -52
- package/src/recipes/cartographier-observations-biodiversite.md +44 -44
- package/src/recipes/cross-server.md +48 -48
- package/src/recipes/dashboard-kpi.md +45 -45
- package/src/recipes/explorer-dossiers-legislatifs-parcours-texte.md +48 -48
- package/src/recipes/gallery-images.md +33 -33
- package/src/recipes/parlementaire-profile.md +58 -58
- package/src/recipes/rechercher-textes-juridiques-legifrance.md +38 -38
- package/src/recipes/weather-viz.md +35 -35
- package/src/recipes/widgets/actions.md +6 -6
- package/src/recipes/widgets/alert.md +6 -6
- package/src/recipes/widgets/cards.md +10 -10
- package/src/recipes/widgets/carousel.md +8 -8
- package/src/recipes/widgets/chart-rich.md +10 -10
- package/src/recipes/widgets/chart.md +9 -9
- package/src/recipes/widgets/code.md +6 -6
- package/src/recipes/widgets/d3.md +10 -10
- package/src/recipes/widgets/data-table.md +10 -10
- package/src/recipes/widgets/gallery.md +10 -10
- package/src/recipes/widgets/grid-data.md +11 -11
- package/src/recipes/widgets/hemicycle.md +9 -9
- package/src/recipes/widgets/js-sandbox.md +10 -10
- package/src/recipes/widgets/json-viewer.md +8 -8
- package/src/recipes/widgets/kv.md +9 -9
- package/src/recipes/widgets/list.md +7 -7
- package/src/recipes/widgets/log.md +6 -6
- package/src/recipes/widgets/map.md +10 -10
- package/src/recipes/widgets/profile.md +9 -9
- package/src/recipes/widgets/recipe-browser.md +33 -33
- package/src/recipes/widgets/sankey.md +10 -10
- package/src/recipes/widgets/stat-card.md +7 -7
- package/src/recipes/widgets/stat.md +10 -10
- package/src/recipes/widgets/tags.md +6 -6
- package/src/recipes/widgets/text.md +6 -6
- package/src/recipes/widgets/timeline.md +6 -6
- package/src/recipes/widgets/trombinoscope.md +8 -8
- package/src/summarize.ts +6 -6
- package/src/tool-layers.ts +26 -26
|
@@ -1,48 +1,48 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: afficher-oeuvres-art-collection-musee
|
|
3
|
-
name:
|
|
3
|
+
name: Display artworks from a museum collection in a visual gallery
|
|
4
4
|
components_used: [gallery, cards, kv, stat-card]
|
|
5
|
-
when:
|
|
5
|
+
when: the user asks for artworks, museum collections, paintings, sculptures, or art objects from the Metropolitan Museum of Art
|
|
6
6
|
servers: [metmuseum]
|
|
7
7
|
layout:
|
|
8
8
|
type: grid
|
|
9
9
|
columns: 2
|
|
10
|
-
arrangement: stats
|
|
10
|
+
arrangement: stats at top, full-width gallery in the center, details at the bottom
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## When to use
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
- "
|
|
17
|
-
- "
|
|
18
|
-
- "
|
|
19
|
-
- "
|
|
20
|
-
- "
|
|
15
|
+
The user is interested in artworks or museum collections:
|
|
16
|
+
- "Show me Impressionist paintings from the Met Museum"
|
|
17
|
+
- "Greek sculptures at the Metropolitan"
|
|
18
|
+
- "What Van Gogh works are at the Met?"
|
|
19
|
+
- "Egyptian art objects from the museum"
|
|
20
|
+
- "Search for Japanese woodblock prints"
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
The Met Museum server provides access to the Metropolitan Museum of Art collection in New York (more than 470,000 objects, many with public domain images).
|
|
23
23
|
|
|
24
|
-
##
|
|
24
|
+
## How to use
|
|
25
25
|
|
|
26
|
-
1. **
|
|
26
|
+
1. **Search for artworks** by theme, artist, or department:
|
|
27
27
|
```
|
|
28
28
|
search_objects({query: "impressionism sunflower", hasImages: true})
|
|
29
29
|
```
|
|
30
|
-
|
|
30
|
+
Returns a list of `objectID`s.
|
|
31
31
|
|
|
32
|
-
2. **
|
|
32
|
+
2. **Fetch the details** of each artwork (limit to 5-10 for performance):
|
|
33
33
|
```
|
|
34
34
|
get_object({objectID: 436524})
|
|
35
35
|
```
|
|
36
|
-
|
|
36
|
+
Returns: `title`, `artistDisplayName`, `primaryImage`, `objectDate`, `medium`, `department`, `culture`, etc.
|
|
37
37
|
|
|
38
|
-
3. **
|
|
38
|
+
3. **Display search statistics**:
|
|
39
39
|
```
|
|
40
|
-
component("stat-card", {label: "
|
|
41
|
-
component("stat-card", {label: "
|
|
42
|
-
component("stat-card", {label: "
|
|
40
|
+
component("stat-card", {label: "Results", value: total, icon: "image"})
|
|
41
|
+
component("stat-card", {label: "With image", value: withImage, icon: "camera"})
|
|
42
|
+
component("stat-card", {label: "Public domain", value: publicDomain, icon: "unlock"})
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
4. **
|
|
45
|
+
4. **Artwork gallery** with high-resolution images:
|
|
46
46
|
```
|
|
47
47
|
component("gallery", {
|
|
48
48
|
images: objects
|
|
@@ -55,64 +55,64 @@ Le serveur Met Museum donne acces a la collection du Metropolitan Museum of Art
|
|
|
55
55
|
})
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
5. **
|
|
58
|
+
5. **Detailed cards** for the main artworks:
|
|
59
59
|
```
|
|
60
60
|
component("cards", {
|
|
61
61
|
items: objects.map(o => ({
|
|
62
62
|
title: o.title,
|
|
63
|
-
subtitle: o.artistDisplayName || "
|
|
63
|
+
subtitle: o.artistDisplayName || "Unknown artist",
|
|
64
64
|
image: o.primaryImageSmall,
|
|
65
65
|
body: [o.objectDate, o.medium, o.department].filter(Boolean).join(" — ")
|
|
66
66
|
}))
|
|
67
67
|
})
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
6. **Details
|
|
70
|
+
6. **Details of a specific artwork** in kv:
|
|
71
71
|
```
|
|
72
72
|
component("kv", {pairs: [
|
|
73
|
-
["
|
|
74
|
-
["
|
|
73
|
+
["Title", obj.title],
|
|
74
|
+
["Artist", obj.artistDisplayName],
|
|
75
75
|
["Date", obj.objectDate],
|
|
76
76
|
["Medium", obj.medium],
|
|
77
77
|
["Dimensions", obj.dimensions],
|
|
78
|
-
["
|
|
78
|
+
["Department", obj.department],
|
|
79
79
|
["Culture", obj.culture],
|
|
80
80
|
["Credit", obj.creditLine],
|
|
81
|
-
["
|
|
81
|
+
["Public domain", obj.isPublicDomain ? "Yes" : "No"]
|
|
82
82
|
]})
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
-
##
|
|
85
|
+
## Examples
|
|
86
86
|
|
|
87
|
-
###
|
|
87
|
+
### Van Gogh paintings
|
|
88
88
|
```
|
|
89
|
-
// 1.
|
|
89
|
+
// 1. Search
|
|
90
90
|
search_objects({query: "van gogh", hasImages: true}) // → [436532, 436529, ...]
|
|
91
91
|
|
|
92
|
-
// 2. Details (
|
|
92
|
+
// 2. Details (first 8 results)
|
|
93
93
|
objectIDs.slice(0, 8).forEach(id => get_object({objectID: id}))
|
|
94
94
|
|
|
95
|
-
// 3.
|
|
96
|
-
component("stat-card", {label: "
|
|
95
|
+
// 3. Render
|
|
96
|
+
component("stat-card", {label: "Van Gogh works", value: "8", icon: "palette"})
|
|
97
97
|
component("gallery", {images: vanGoghWorks.map(w => ({src: w.primaryImageSmall, alt: w.title, caption: w.objectDate}))})
|
|
98
98
|
component("cards", {items: vanGoghWorks.map(w => ({title: w.title, subtitle: w.objectDate, image: w.primaryImageSmall, body: w.medium}))})
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
-
###
|
|
101
|
+
### Egyptian art
|
|
102
102
|
```
|
|
103
|
-
// 1.
|
|
103
|
+
// 1. Search by department
|
|
104
104
|
search_objects({query: "egypt pharaoh", departmentId: 10, hasImages: true})
|
|
105
105
|
|
|
106
|
-
// 2.
|
|
106
|
+
// 2. Render with cultural metadata
|
|
107
107
|
component("gallery", {images: egyptWorks.map(w => ({src: w.primaryImageSmall, alt: w.title}))})
|
|
108
|
-
component("table", {columns: ["
|
|
109
|
-
component("kv", {pairs: [["
|
|
108
|
+
component("table", {columns: ["Title", "Period", "Culture", "Medium"], rows: egyptDetails})
|
|
109
|
+
component("kv", {pairs: [["Department", "Egyptian Art"], ["Source", "Met Museum — Open Access"]]})
|
|
110
110
|
```
|
|
111
111
|
|
|
112
|
-
##
|
|
112
|
+
## Common mistakes
|
|
113
113
|
|
|
114
|
-
- **
|
|
115
|
-
- **
|
|
116
|
-
- **
|
|
117
|
-
- **
|
|
118
|
-
- **
|
|
114
|
+
- **Too many `get_object` calls**: a search sometimes returns hundreds of IDs — limit to 5-10 detail calls for performance
|
|
115
|
+
- **Artworks without images**: many Met objects have no `primaryImage` — always filter with `hasImages: true` in the search or check the field
|
|
116
|
+
- **Broken high-resolution images**: use `primaryImageSmall` (web-large) for the gallery and cards — `primaryImage` (original) URLs often return 404s
|
|
117
|
+
- **Forgetting the license**: works in the public domain (`isPublicDomain: true`) can be displayed freely; others have a `rights` field to respect
|
|
118
|
+
- **Unknown artist**: many ancient works have no `artistDisplayName` — display "Unknown artist" or the culture/period instead
|
|
@@ -1,59 +1,59 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: analyser-actualites-hacker-news
|
|
3
|
-
name:
|
|
3
|
+
name: Analyze Hacker News news and trends with tables and charts
|
|
4
4
|
components_used: [table, chart, stat-card, cards]
|
|
5
|
-
when:
|
|
5
|
+
when: the user asks for tech news, Hacker News trends, top stories, or an analysis of HN discussions and comments
|
|
6
6
|
servers: [hackernews]
|
|
7
7
|
layout:
|
|
8
8
|
type: grid
|
|
9
9
|
columns: 2
|
|
10
|
-
arrangement: stats
|
|
10
|
+
arrangement: stats in a row, full-width table, chart at the bottom
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## When to use
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
- "
|
|
17
|
-
- "
|
|
18
|
-
- "
|
|
19
|
-
- "
|
|
20
|
-
- "
|
|
15
|
+
The user is interested in technology news or Hacker News community trends:
|
|
16
|
+
- "What are the top Hacker News stories?"
|
|
17
|
+
- "Show me the most commented posts today"
|
|
18
|
+
- "This week's tech trends on HN"
|
|
19
|
+
- "Analyze recent Ask HN posts"
|
|
20
|
+
- "What topics are dominating Hacker News right now?"
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
The Hacker News server provides access to stories, comments, rankings, and post metadata.
|
|
23
23
|
|
|
24
|
-
##
|
|
24
|
+
## How to use
|
|
25
25
|
|
|
26
|
-
1. **
|
|
26
|
+
1. **Fetch the top stories**:
|
|
27
27
|
```
|
|
28
28
|
get_top_stories({limit: 30})
|
|
29
29
|
```
|
|
30
|
-
|
|
30
|
+
Returns the IDs of the most popular stories.
|
|
31
31
|
|
|
32
|
-
2. **
|
|
32
|
+
2. **Fetch the details** of each story:
|
|
33
33
|
```
|
|
34
34
|
get_item({id: storyId})
|
|
35
35
|
```
|
|
36
|
-
|
|
36
|
+
Returns: `title`, `url`, `score`, `by` (author), `descendants` (comment count), `time`, `type`.
|
|
37
37
|
|
|
38
|
-
3. **
|
|
38
|
+
3. **Display KPIs** in stat-cards:
|
|
39
39
|
```
|
|
40
40
|
component("stat-card", {label: "Top Stories", value: "30", icon: "newspaper"})
|
|
41
|
-
component("stat-card", {label: "
|
|
42
|
-
component("stat-card", {label: "
|
|
43
|
-
component("stat-card", {label: "
|
|
41
|
+
component("stat-card", {label: "Average score", value: Math.round(avgScore), icon: "trending-up"})
|
|
42
|
+
component("stat-card", {label: "Average comments", value: Math.round(avgComments), icon: "message-circle"})
|
|
43
|
+
component("stat-card", {label: "Max score", value: maxScore + " pts", icon: "award"})
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
4. **
|
|
46
|
+
4. **Stories table** sorted by score:
|
|
47
47
|
```
|
|
48
48
|
component("table", {
|
|
49
|
-
columns: ["#", "
|
|
49
|
+
columns: ["#", "Title", "Score", "Comments", "Author"],
|
|
50
50
|
rows: stories.sort((a, b) => b.score - a.score).map((s, i) => [
|
|
51
51
|
i + 1, s.title, s.score, s.descendants, s.by
|
|
52
52
|
])
|
|
53
53
|
})
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
5. **
|
|
56
|
+
5. **Score distribution chart**:
|
|
57
57
|
```
|
|
58
58
|
component("chart", {
|
|
59
59
|
type: "bar",
|
|
@@ -62,66 +62,66 @@ Le serveur Hacker News donne acces aux stories, commentaires, classements et met
|
|
|
62
62
|
})
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
6. **Cards
|
|
65
|
+
6. **Cards for featured stories** (top 5):
|
|
66
66
|
```
|
|
67
67
|
component("cards", {
|
|
68
68
|
items: top5.map(s => ({
|
|
69
69
|
title: s.title,
|
|
70
70
|
subtitle: s.by + " — " + s.score + " points",
|
|
71
|
-
body: s.descendants + "
|
|
71
|
+
body: s.descendants + " comments | " + new Date(s.time * 1000).toLocaleDateString(),
|
|
72
72
|
url: s.url
|
|
73
73
|
}))
|
|
74
74
|
})
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
-
##
|
|
77
|
+
## Examples
|
|
78
78
|
|
|
79
|
-
### Top 10 stories
|
|
79
|
+
### Top 10 stories right now
|
|
80
80
|
```
|
|
81
|
-
// 1.
|
|
81
|
+
// 1. Fetch
|
|
82
82
|
get_top_stories({limit: 10})
|
|
83
|
-
//
|
|
83
|
+
// For each ID: get_item({id})
|
|
84
84
|
|
|
85
|
-
// 2.
|
|
86
|
-
component("stat-card", {label: "
|
|
87
|
-
component("stat-card", {label: "
|
|
85
|
+
// 2. Render
|
|
86
|
+
component("stat-card", {label: "Total score", value: totalScore, icon: "zap"})
|
|
87
|
+
component("stat-card", {label: "Total comments", value: totalComments, icon: "message-circle"})
|
|
88
88
|
component("table", {
|
|
89
|
-
columns: ["
|
|
89
|
+
columns: ["Rank", "Title", "Score", "Comments", "Author", "Age"],
|
|
90
90
|
rows: rankedStories
|
|
91
91
|
})
|
|
92
92
|
component("cards", {items: top3Stories})
|
|
93
93
|
```
|
|
94
94
|
|
|
95
|
-
###
|
|
95
|
+
### Ask HN analysis
|
|
96
96
|
```
|
|
97
|
-
// 1.
|
|
97
|
+
// 1. Fetch recent Ask HN posts
|
|
98
98
|
get_ask_stories({limit: 20})
|
|
99
99
|
|
|
100
|
-
// 2.
|
|
101
|
-
component("stat-card", {label: "Ask HN
|
|
102
|
-
component("stat-card", {label: "
|
|
103
|
-
component("table", {columns: ["
|
|
104
|
-
component("chart", {type: "bar", labels: titles, datasets: [{label: "
|
|
100
|
+
// 2. Render
|
|
101
|
+
component("stat-card", {label: "Recent Ask HN", value: "20", icon: "help-circle"})
|
|
102
|
+
component("stat-card", {label: "Average replies", value: avgReplies, icon: "message-circle"})
|
|
103
|
+
component("table", {columns: ["Title", "Replies", "Score", "Author"], rows: askStories})
|
|
104
|
+
component("chart", {type: "bar", labels: titles, datasets: [{label: "Replies", data: replyCounts}]})
|
|
105
105
|
```
|
|
106
106
|
|
|
107
|
-
###
|
|
107
|
+
### Trends by domain
|
|
108
108
|
```
|
|
109
|
-
// 1.
|
|
109
|
+
// 1. Fetch top stories and extract domains from URLs
|
|
110
110
|
get_top_stories({limit: 50})
|
|
111
111
|
|
|
112
|
-
// 2.
|
|
112
|
+
// 2. Group by domain
|
|
113
113
|
const domains = groupBy(stories, s => new URL(s.url).hostname)
|
|
114
114
|
|
|
115
|
-
// 3.
|
|
116
|
-
component("stat-card", {label: "
|
|
115
|
+
// 3. Render
|
|
116
|
+
component("stat-card", {label: "Unique domains", value: Object.keys(domains).length, icon: "globe"})
|
|
117
117
|
component("chart", {type: "bar", labels: topDomains.map(d => d.name), datasets: [{label: "Stories", data: topDomains.map(d => d.count)}]})
|
|
118
|
-
component("table", {columns: ["
|
|
118
|
+
component("table", {columns: ["Domain", "Stories", "Total score"], rows: domainStats})
|
|
119
119
|
```
|
|
120
120
|
|
|
121
|
-
##
|
|
121
|
+
## Common mistakes
|
|
122
122
|
|
|
123
|
-
- **
|
|
124
|
-
- **
|
|
125
|
-
- **
|
|
126
|
-
- **
|
|
127
|
-
- **
|
|
123
|
+
- **Too many `get_item` calls**: each story requires an individual call — limit to 20-30 to avoid slowness
|
|
124
|
+
- **Unconverted timestamps**: HN returns Unix timestamps — convert them to human-readable dates
|
|
125
|
+
- **Truncated titles in charts**: HN titles are long — truncate to 30-40 characters for chart labels
|
|
126
|
+
- **Forgetting stories without a URL**: "Ask HN", "Show HN", and "Tell HN" posts don't always have an external URL — handle this case
|
|
127
|
+
- **Not distinguishing types**: HN has stories, jobs, and polls — filter by type if the user asks for a specific type
|
|
@@ -1,38 +1,38 @@
|
|
|
1
1
|
---
|
|
2
|
-
id:
|
|
3
|
-
name:
|
|
2
|
+
id: map-biodiversity-observations
|
|
3
|
+
name: Map biodiversity observations on a geographic area
|
|
4
4
|
components_used: [map, gallery, table, stat-card]
|
|
5
|
-
when:
|
|
5
|
+
when: the user asks for a map of naturalist observations, the biodiversity of an area, the species present in a location, or iNaturalist observations in a region
|
|
6
6
|
servers: [inaturalist]
|
|
7
7
|
layout:
|
|
8
8
|
type: grid
|
|
9
9
|
columns: 2
|
|
10
|
-
arrangement:
|
|
10
|
+
arrangement: full-width map at top, gallery + stats below
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## When to use
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
- "
|
|
17
|
-
- "
|
|
18
|
-
- "
|
|
19
|
-
- "
|
|
15
|
+
The user asks a question about the biodiversity of a location or requests a map of observations:
|
|
16
|
+
- "What bird species are observed in Paris?"
|
|
17
|
+
- "Show me a map of butterfly observations in the Alps"
|
|
18
|
+
- "What is the biodiversity around Lake Annecy?"
|
|
19
|
+
- "Endangered species observed in Ile-de-France"
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
The iNaturalist server provides georeferenced observations with photos, taxa, dates, and observers.
|
|
22
22
|
|
|
23
|
-
##
|
|
23
|
+
## How to use
|
|
24
24
|
|
|
25
|
-
1. **
|
|
25
|
+
1. **Search for observations** in the target area:
|
|
26
26
|
```
|
|
27
27
|
search_observations({lat: 48.85, lng: 2.35, radius: 10, taxon_name: "Aves", per_page: 50})
|
|
28
28
|
```
|
|
29
|
-
|
|
30
|
-
- `lat`, `lng`, `radius
|
|
31
|
-
- `taxon_name
|
|
32
|
-
- `quality_grade
|
|
33
|
-
- `per_page
|
|
29
|
+
Useful parameters:
|
|
30
|
+
- `lat`, `lng`, `radius`: center and radius of the area in km
|
|
31
|
+
- `taxon_name`: taxonomic filter ("Aves", "Lepidoptera", "Mammalia", etc.)
|
|
32
|
+
- `quality_grade`: "research" for verified observations
|
|
33
|
+
- `per_page`: number of results (max 200)
|
|
34
34
|
|
|
35
|
-
2. **
|
|
35
|
+
2. **Display the map** with observation markers:
|
|
36
36
|
```
|
|
37
37
|
component("map", {
|
|
38
38
|
center: [48.85, 2.35],
|
|
@@ -46,15 +46,15 @@ Le serveur iNaturalist fournit des observations georeferencees avec photos, taxo
|
|
|
46
46
|
})
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
3. **
|
|
49
|
+
3. **Area statistics** in stat-cards:
|
|
50
50
|
```
|
|
51
51
|
component("stat-card", {label: "Observations", value: total_results, icon: "eye"})
|
|
52
|
-
component("stat-card", {label: "
|
|
53
|
-
component("stat-card", {label: "
|
|
54
|
-
component("stat-card", {label: "
|
|
52
|
+
component("stat-card", {label: "Unique species", value: uniqueSpecies.length, icon: "leaf"})
|
|
53
|
+
component("stat-card", {label: "Observers", value: uniqueObservers.length, icon: "users"})
|
|
54
|
+
component("stat-card", {label: "Research grade", value: researchGradeCount, icon: "check-circle"})
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
4. **
|
|
57
|
+
4. **Species gallery with photos**:
|
|
58
58
|
```
|
|
59
59
|
component("gallery", {
|
|
60
60
|
images: observations
|
|
@@ -67,45 +67,45 @@ Le serveur iNaturalist fournit des observations georeferencees avec photos, taxo
|
|
|
67
67
|
})
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
5. **
|
|
70
|
+
5. **Summary table** of species:
|
|
71
71
|
```
|
|
72
72
|
component("table", {
|
|
73
|
-
columns: ["
|
|
73
|
+
columns: ["Species", "Scientific name", "Observations", "Last obs."],
|
|
74
74
|
rows: speciesSummary
|
|
75
75
|
})
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
##
|
|
78
|
+
## Examples
|
|
79
79
|
|
|
80
|
-
###
|
|
80
|
+
### Birds of Paris
|
|
81
81
|
```
|
|
82
|
-
// 1.
|
|
82
|
+
// 1. Search
|
|
83
83
|
search_observations({lat: 48.8566, lng: 2.3522, radius: 10, taxon_name: "Aves", quality_grade: "research", per_page: 100})
|
|
84
84
|
|
|
85
|
-
// 2.
|
|
85
|
+
// 2. Render
|
|
86
86
|
component("map", {center: [48.8566, 2.3522], zoom: 12, markers: birdMarkers})
|
|
87
|
-
component("stat-card", {label: "
|
|
88
|
-
component("stat-card", {label: "
|
|
87
|
+
component("stat-card", {label: "Bird species", value: "47", icon: "bird"})
|
|
88
|
+
component("stat-card", {label: "Verified observations", value: "312", icon: "check"})
|
|
89
89
|
component("gallery", {images: birdPhotos})
|
|
90
|
-
component("table", {columns: ["
|
|
90
|
+
component("table", {columns: ["Species", "Observations", "Last"], rows: birdSummary})
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
-
###
|
|
93
|
+
### Butterflies in the Alps
|
|
94
94
|
```
|
|
95
|
-
// 1.
|
|
95
|
+
// 1. Wide area around Chamonix
|
|
96
96
|
search_observations({lat: 45.9237, lng: 6.8694, radius: 30, taxon_name: "Lepidoptera", per_page: 100})
|
|
97
97
|
|
|
98
|
-
// 2.
|
|
98
|
+
// 2. Render with clustering on the map
|
|
99
99
|
component("map", {center: [45.9237, 6.8694], zoom: 10, markers: butterflyMarkers, cluster: true})
|
|
100
|
-
component("stat-card", {label: "
|
|
100
|
+
component("stat-card", {label: "Butterfly species", value: uniqueSpecies.length})
|
|
101
101
|
component("gallery", {images: butterflyPhotos})
|
|
102
|
-
component("table", {columns: ["
|
|
102
|
+
component("table", {columns: ["Species", "Altitude", "Month", "Observer"], rows: enrichedData})
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
-
##
|
|
105
|
+
## Common mistakes
|
|
106
106
|
|
|
107
|
-
- **
|
|
108
|
-
- **
|
|
109
|
-
- **
|
|
110
|
-
- **
|
|
111
|
-
- **
|
|
107
|
+
- **Radius too large**: a 100 km radius returns too many results and buries the information — prefer 5-20 km and increase if few results are found
|
|
108
|
+
- **iNaturalist thumbnails**: default URLs are in "square" format (75x75) — replace "square" with "medium" (200px) or "large" (500px)
|
|
109
|
+
- **No taxonomic filter**: without a filter, iNaturalist returns plants + animals + fungi together — always filter by group if the user mentions one
|
|
110
|
+
- **Forgetting the quality grade**: "casual" observations may be misidentified — prefer `quality_grade: "research"` for reliable data
|
|
111
|
+
- **Map with wrong zoom level**: adjust zoom based on the search radius (5 km → zoom 13, 20 km → zoom 11, 50 km → zoom 9)
|