diff --git a/Logic/Osm/Actions/ChangeTagAction.ts b/Logic/Osm/Actions/ChangeTagAction.ts index c4a08f34f..199eab28d 100644 --- a/Logic/Osm/Actions/ChangeTagAction.ts +++ b/Logic/Osm/Actions/ChangeTagAction.ts @@ -2,15 +2,17 @@ import OsmChangeAction from "./OsmChangeAction"; import {Changes} from "../Changes"; import {ChangeDescription} from "./ChangeDescription"; import {TagsFilter} from "../../Tags/TagsFilter"; +import {OsmTags} from "../../../Models/OsmFeature"; export default class ChangeTagAction extends OsmChangeAction { private readonly _elementId: string; private readonly _tagsFilter: TagsFilter; - private readonly _currentTags: any; + private readonly _currentTags: Record | OsmTags; private readonly _meta: { theme: string, changeType: string }; constructor(elementId: string, - tagsFilter: TagsFilter, currentTags: any, meta: { + tagsFilter: TagsFilter, + currentTags: Record, meta: { theme: string, changeType: "answer" | "soft-delete" | "add-image" | string }) { diff --git a/Logic/Web/PlantNet.ts b/Logic/Web/PlantNet.ts new file mode 100644 index 000000000..d980cf403 --- /dev/null +++ b/Logic/Web/PlantNet.ts @@ -0,0 +1,346 @@ +import {Utils} from "../../Utils"; + +export default class PlantNet { + private static baseUrl = "https://my-api.plantnet.org/v2/identify/all?api-key=2b10AAsjzwzJvucA5Ncm5qxe" + + public static query(imageUrls: string[]) : Promise{ + if (imageUrls.length > 5) { + throw "At most 5 images can be given to PlantNet.query" + } + if (imageUrls.length == 0) { + throw "At least one image should be given to PlantNet.query" + } + let url = PlantNet. baseUrl; + for (const image of imageUrls) { + url += "&images="+encodeURIComponent(image) + } + return Utils.downloadJsonCached(url, 365*24*60*60*1000) + } + + public static exampleResult: PlantNetResult = { + "query": { + "project": "all", + "images": ["https://my.plantnet.org/images/image_1.jpeg", "https://my.plantnet.org/images/image_2.jpeg"], + "organs": ["flower", "leaf"], + "includeRelatedImages": false + }, + "language": "en", + "preferedReferential": "the-plant-list", + "bestMatch": "Hibiscus rosa-sinensis L.", + "results": [{ + "score": 0.91806, + "species": { + "scientificNameWithoutAuthor": "Hibiscus rosa-sinensis", + "scientificNameAuthorship": "L.", + "genus": { + "scientificNameWithoutAuthor": "Hibiscus", + "scientificNameAuthorship": "", + "scientificName": "Hibiscus" + }, + "family": { + "scientificNameWithoutAuthor": "Malvaceae", + "scientificNameAuthorship": "", + "scientificName": "Malvaceae" + }, + "commonNames": ["Hawaiian hibiscus", "Hibiscus", "Chinese hibiscus"], + "scientificName": "Hibiscus rosa-sinensis L." + }, + "gbif": {"id": "3152559"} + }, { + "score": 0.00759, + "species": { + "scientificNameWithoutAuthor": "Hibiscus moscheutos", + "scientificNameAuthorship": "L.", + "genus": { + "scientificNameWithoutAuthor": "Hibiscus", + "scientificNameAuthorship": "", + "scientificName": "Hibiscus" + }, + "family": { + "scientificNameWithoutAuthor": "Malvaceae", + "scientificNameAuthorship": "", + "scientificName": "Malvaceae" + }, + "commonNames": ["Crimsoneyed rosemallow", "Mallow-rose", "Swamp rose-mallow"], + "scientificName": "Hibiscus moscheutos L." + }, + "gbif": {"id": "3152596"} + }, { + "score": 0.00676, + "species": { + "scientificNameWithoutAuthor": "Hibiscus schizopetalus", + "scientificNameAuthorship": "(Dyer) Hook.f.", + "genus": { + "scientificNameWithoutAuthor": "Hibiscus", + "scientificNameAuthorship": "", + "scientificName": "Hibiscus" + }, + "family": { + "scientificNameWithoutAuthor": "Malvaceae", + "scientificNameAuthorship": "", + "scientificName": "Malvaceae" + }, + "commonNames": ["Campanilla", "Chinese lantern", "Fringed rosemallow"], + "scientificName": "Hibiscus schizopetalus (Dyer) Hook.f." + }, + "gbif": {"id": "9064581"} + }, { + "score": 0.00544, + "species": { + "scientificNameWithoutAuthor": "Hibiscus palustris", + "scientificNameAuthorship": "L.", + "genus": { + "scientificNameWithoutAuthor": "Hibiscus", + "scientificNameAuthorship": "", + "scientificName": "Hibiscus" + }, + "family": { + "scientificNameWithoutAuthor": "Malvaceae", + "scientificNameAuthorship": "", + "scientificName": "Malvaceae" + }, + "commonNames": ["Swamp Rose Mallow", "Hardy Hidiscus", "Twisted Hibiscus"], + "scientificName": "Hibiscus palustris L." + }, + "gbif": {"id": "6377046"} + }, { + "score": 0.0047, + "species": { + "scientificNameWithoutAuthor": "Hibiscus sabdariffa", + "scientificNameAuthorship": "L.", + "genus": { + "scientificNameWithoutAuthor": "Hibiscus", + "scientificNameAuthorship": "", + "scientificName": "Hibiscus" + }, + "family": { + "scientificNameWithoutAuthor": "Malvaceae", + "scientificNameAuthorship": "", + "scientificName": "Malvaceae" + }, + "commonNames": ["Indian-sorrel", "Roselle", "Jamaica-sorrel"], + "scientificName": "Hibiscus sabdariffa L." + }, + "gbif": {"id": "3152582"} + }, { + "score": 0.0037, + "species": { + "scientificNameWithoutAuthor": "Abelmoschus moschatus", + "scientificNameAuthorship": "Medik.", + "genus": { + "scientificNameWithoutAuthor": "Abelmoschus", + "scientificNameAuthorship": "", + "scientificName": "Abelmoschus" + }, + "family": { + "scientificNameWithoutAuthor": "Malvaceae", + "scientificNameAuthorship": "", + "scientificName": "Malvaceae" + }, + "commonNames": ["Musk okra", "Musk-mallow", "Tropical jewel-hibiscus"], + "scientificName": "Abelmoschus moschatus Medik." + }, + "gbif": {"id": "8312665"} + }, { + "score": 0.00278, + "species": { + "scientificNameWithoutAuthor": "Hibiscus grandiflorus", + "scientificNameAuthorship": "Michx.", + "genus": { + "scientificNameWithoutAuthor": "Hibiscus", + "scientificNameAuthorship": "", + "scientificName": "Hibiscus" + }, + "family": { + "scientificNameWithoutAuthor": "Malvaceae", + "scientificNameAuthorship": "", + "scientificName": "Malvaceae" + }, + "commonNames": ["Swamp rosemallow", "Swamp Rose-Mallow"], + "scientificName": "Hibiscus grandiflorus Michx." + }, + "gbif": {"id": "3152592"} + }, { + "score": 0.00265, + "species": { + "scientificNameWithoutAuthor": "Hibiscus acetosella", + "scientificNameAuthorship": "Welw. ex Hiern", + "genus": { + "scientificNameWithoutAuthor": "Hibiscus", + "scientificNameAuthorship": "", + "scientificName": "Hibiscus" + }, + "family": { + "scientificNameWithoutAuthor": "Malvaceae", + "scientificNameAuthorship": "", + "scientificName": "Malvaceae" + }, + "commonNames": ["False roselle", "Red-leaf hibiscus", "African rosemallow"], + "scientificName": "Hibiscus acetosella Welw. ex Hiern" + }, + "gbif": {"id": "3152551"} + }, { + "score": 0.00253, + "species": { + "scientificNameWithoutAuthor": "Bixa orellana", + "scientificNameAuthorship": "L.", + "genus": { + "scientificNameWithoutAuthor": "Bixa", + "scientificNameAuthorship": "", + "scientificName": "Bixa" + }, + "family": { + "scientificNameWithoutAuthor": "Bixaceae", + "scientificNameAuthorship": "", + "scientificName": "Bixaceae" + }, + "commonNames": ["Arnatto", "Lipsticktree", "Annatto"], + "scientificName": "Bixa orellana L." + }, + "gbif": {"id": "2874863"} + }, { + "score": 0.00179, + "species": { + "scientificNameWithoutAuthor": "Malvaviscus penduliflorus", + "scientificNameAuthorship": "Moc. & Sessé ex DC.", + "genus": { + "scientificNameWithoutAuthor": "Malvaviscus", + "scientificNameAuthorship": "", + "scientificName": "Malvaviscus" + }, + "family": { + "scientificNameWithoutAuthor": "Malvaceae", + "scientificNameAuthorship": "", + "scientificName": "Malvaceae" + }, + "commonNames": ["Mazapan"], + "scientificName": "Malvaviscus penduliflorus Moc. & Sessé ex DC." + }, + "gbif": {"id": "3152776"} + }, { + "score": 0.00145, + "species": { + "scientificNameWithoutAuthor": "Hibiscus diversifolius", + "scientificNameAuthorship": "Jacq.", + "genus": { + "scientificNameWithoutAuthor": "Hibiscus", + "scientificNameAuthorship": "", + "scientificName": "Hibiscus" + }, + "family": { + "scientificNameWithoutAuthor": "Malvaceae", + "scientificNameAuthorship": "", + "scientificName": "Malvaceae" + }, + "commonNames": ["Cape hibiscus", "Swamp hibiscus", "Comfortroot"], + "scientificName": "Hibiscus diversifolius Jacq." + }, + "gbif": {"id": "7279239"} + }, { + "score": 0.00141, + "species": { + "scientificNameWithoutAuthor": "Hippeastrum reginae", + "scientificNameAuthorship": "(L.) Herb.", + "genus": { + "scientificNameWithoutAuthor": "Hippeastrum", + "scientificNameAuthorship": "", + "scientificName": "Hippeastrum" + }, + "family": { + "scientificNameWithoutAuthor": "Amaryllidaceae", + "scientificNameAuthorship": "", + "scientificName": "Amaryllidaceae" + }, + "commonNames": ["Amaryllis", "Cheryl's Treasure", "Easter lily"], + "scientificName": "Hippeastrum reginae (L.) Herb." + }, + "gbif": {"id": "2854474"} + }, { + "score": 0.00114, + "species": { + "scientificNameWithoutAuthor": "Hibiscus martianus", + "scientificNameAuthorship": "Zucc.", + "genus": { + "scientificNameWithoutAuthor": "Hibiscus", + "scientificNameAuthorship": "", + "scientificName": "Hibiscus" + }, + "family": { + "scientificNameWithoutAuthor": "Malvaceae", + "scientificNameAuthorship": "", + "scientificName": "Malvaceae" + }, + "commonNames": ["Heartleaf rosemallow", "Mountain rosemallow", "Heartleaf rose-mallow"], + "scientificName": "Hibiscus martianus Zucc." + }, + "gbif": {"id": "3152578"} + }, { + "score": 0.00109, + "species": { + "scientificNameWithoutAuthor": "Acalypha hispida", + "scientificNameAuthorship": "Burm.f.", + "genus": { + "scientificNameWithoutAuthor": "Acalypha", + "scientificNameAuthorship": "", + "scientificName": "Acalypha" + }, + "family": { + "scientificNameWithoutAuthor": "Euphorbiaceae", + "scientificNameAuthorship": "", + "scientificName": "Euphorbiaceae" + }, + "commonNames": ["Philippine-medusa", "Bristly copperleaf", "Chenilleplant"], + "scientificName": "Acalypha hispida Burm.f." + }, + "gbif": {"id": "3056375"} + }, { + "score": 0.00071, + "species": { + "scientificNameWithoutAuthor": "Hibiscus arnottianus", + "scientificNameAuthorship": "A. Gray", + "genus": { + "scientificNameWithoutAuthor": "Hibiscus", + "scientificNameAuthorship": "", + "scientificName": "Hibiscus" + }, + "family": { + "scientificNameWithoutAuthor": "Malvaceae", + "scientificNameAuthorship": "", + "scientificName": "Malvaceae" + }, + "commonNames": ["White rosemallow", "Native Hawaiian White Hibiscus", "Native White Rose-Mallow"], + "scientificName": "Hibiscus arnottianus A. Gray" + }, + "gbif": {"id": "3152543"} + }], + "version": "2022-06-14 (6.0)", + "remainingIdentificationRequests": 499 + } +public static exampleResultPrunus : PlantNetResult = {"query":{"project":"all","images":["https://i.imgur.com/VJp1qG1.jpg"],"organs":["auto"],"includeRelatedImages":false},"language":"en","preferedReferential":"the-plant-list","bestMatch":"Malus halliana Koehne","results":[{"score":0.23548,"species":{"scientificNameWithoutAuthor":"Malus halliana","scientificNameAuthorship":"Koehne","genus":{"scientificNameWithoutAuthor":"Malus","scientificNameAuthorship":"","scientificName":"Malus"},"family":{"scientificNameWithoutAuthor":"Rosaceae","scientificNameAuthorship":"","scientificName":"Rosaceae"},"commonNames":["Hall crab apple","Adirondack Crabapple","Hall's crabapple"],"scientificName":"Malus halliana Koehne"},"gbif":{"id":"3001220"}},{"score":0.1514,"species":{"scientificNameWithoutAuthor":"Prunus campanulata","scientificNameAuthorship":"Maxim.","genus":{"scientificNameWithoutAuthor":"Prunus","scientificNameAuthorship":"","scientificName":"Prunus"},"family":{"scientificNameWithoutAuthor":"Rosaceae","scientificNameAuthorship":"","scientificName":"Rosaceae"},"commonNames":["Formosan cherry","Bellflower cherry","Taiwan cherry"],"scientificName":"Prunus campanulata Maxim."},"gbif":{"id":"3021408"}},{"score":0.14758,"species":{"scientificNameWithoutAuthor":"Malus coronaria","scientificNameAuthorship":"(L.) Mill.","genus":{"scientificNameWithoutAuthor":"Malus","scientificNameAuthorship":"","scientificName":"Malus"},"family":{"scientificNameWithoutAuthor":"Rosaceae","scientificNameAuthorship":"","scientificName":"Rosaceae"},"commonNames":["Sweet crab apple","American crabapple","Fragrant crabapple"],"scientificName":"Malus coronaria (L.) Mill."},"gbif":{"id":"3001166"}},{"score":0.13092,"species":{"scientificNameWithoutAuthor":"Prunus serrulata","scientificNameAuthorship":"Lindl.","genus":{"scientificNameWithoutAuthor":"Prunus","scientificNameAuthorship":"","scientificName":"Prunus"},"family":{"scientificNameWithoutAuthor":"Rosaceae","scientificNameAuthorship":"","scientificName":"Rosaceae"},"commonNames":["Japanese flowering cherry","Japanese cherry","Oriental cherry"],"scientificName":"Prunus serrulata Lindl."},"gbif":{"id":"3022609"}},{"score":0.10147,"species":{"scientificNameWithoutAuthor":"Malus floribunda","scientificNameAuthorship":"Siebold ex Van Houtte","genus":{"scientificNameWithoutAuthor":"Malus","scientificNameAuthorship":"","scientificName":"Malus"},"family":{"scientificNameWithoutAuthor":"Rosaceae","scientificNameAuthorship":"","scientificName":"Rosaceae"},"commonNames":["Japanese flowering Crabapple","Japanese crab","Japanese crab apple"],"scientificName":"Malus floribunda Siebold ex Van Houtte"},"gbif":{"id":"3001365"}},{"score":0.05122,"species":{"scientificNameWithoutAuthor":"Prunus sargentii","scientificNameAuthorship":"Rehder","genus":{"scientificNameWithoutAuthor":"Prunus","scientificNameAuthorship":"","scientificName":"Prunus"},"family":{"scientificNameWithoutAuthor":"Rosaceae","scientificNameAuthorship":"","scientificName":"Rosaceae"},"commonNames":["Sargent's cherry","Northern Japanese hill cherry","Sargent Cherry"],"scientificName":"Prunus sargentii Rehder"},"gbif":{"id":"3020955"}},{"score":0.02576,"species":{"scientificNameWithoutAuthor":"Malus × spectabilis","scientificNameAuthorship":"(Sol.) Borkh.","genus":{"scientificNameWithoutAuthor":"Malus","scientificNameAuthorship":"","scientificName":"Malus"},"family":{"scientificNameWithoutAuthor":"Rosaceae","scientificNameAuthorship":"","scientificName":"Rosaceae"},"commonNames":["Asiatic apple","Chinese crab","Chinese flowering apple"],"scientificName":"Malus × spectabilis (Sol.) Borkh."},"gbif":{"id":"3001108"}},{"score":0.01802,"species":{"scientificNameWithoutAuthor":"Prunus triloba","scientificNameAuthorship":"Lindl.","genus":{"scientificNameWithoutAuthor":"Prunus","scientificNameAuthorship":"","scientificName":"Prunus"},"family":{"scientificNameWithoutAuthor":"Rosaceae","scientificNameAuthorship":"","scientificName":"Rosaceae"},"commonNames":["Flowering almond","Flowering plum"],"scientificName":"Prunus triloba Lindl."},"gbif":{"id":"3023130"}},{"score":0.01206,"species":{"scientificNameWithoutAuthor":"Prunus japonica","scientificNameAuthorship":"Thunb.","genus":{"scientificNameWithoutAuthor":"Prunus","scientificNameAuthorship":"","scientificName":"Prunus"},"family":{"scientificNameWithoutAuthor":"Rosaceae","scientificNameAuthorship":"","scientificName":"Rosaceae"},"commonNames":["Chinese bush cherry","Japanese bush cherry","Oriental bush cherry"],"scientificName":"Prunus japonica Thunb."},"gbif":{"id":"3020565"}},{"score":0.01161,"species":{"scientificNameWithoutAuthor":"Prunus × yedoensis","scientificNameAuthorship":"Matsum.","genus":{"scientificNameWithoutAuthor":"Prunus","scientificNameAuthorship":"","scientificName":"Prunus"},"family":{"scientificNameWithoutAuthor":"Rosaceae","scientificNameAuthorship":"","scientificName":"Rosaceae"},"commonNames":["Yoshino cherry","Potomac cherry","Tokyo cherry"],"scientificName":"Prunus × yedoensis Matsum."},"gbif":{"id":"3021335"}},{"score":0.00914,"species":{"scientificNameWithoutAuthor":"Prunus mume","scientificNameAuthorship":"(Siebold) Siebold & Zucc.","genus":{"scientificNameWithoutAuthor":"Prunus","scientificNameAuthorship":"","scientificName":"Prunus"},"family":{"scientificNameWithoutAuthor":"Rosaceae","scientificNameAuthorship":"","scientificName":"Rosaceae"},"commonNames":["Japanese apricot","Ume","Chinese Plum"],"scientificName":"Prunus mume (Siebold) Siebold & Zucc."},"gbif":{"id":"3021046"}},{"score":0.0088,"species":{"scientificNameWithoutAuthor":"Malus niedzwetzkyana","scientificNameAuthorship":"Dieck ex Koehne","genus":{"scientificNameWithoutAuthor":"Malus","scientificNameAuthorship":"","scientificName":"Malus"},"family":{"scientificNameWithoutAuthor":"Rosaceae","scientificNameAuthorship":"","scientificName":"Rosaceae"},"commonNames":["Apple","Paradise apple","Kulturapfel"],"scientificName":"Malus niedzwetzkyana Dieck ex Koehne"},"gbif":{"id":"3001327"}},{"score":0.00734,"species":{"scientificNameWithoutAuthor":"Malus hupehensis","scientificNameAuthorship":"(Pamp.) Rehder","genus":{"scientificNameWithoutAuthor":"Malus","scientificNameAuthorship":"","scientificName":"Malus"},"family":{"scientificNameWithoutAuthor":"Rosaceae","scientificNameAuthorship":"","scientificName":"Rosaceae"},"commonNames":["Chinese crab apple","Hupeh crab","Tea crab apple"],"scientificName":"Malus hupehensis (Pamp.) Rehder"},"gbif":{"id":"3001077"}},{"score":0.00688,"species":{"scientificNameWithoutAuthor":"Malus angustifolia","scientificNameAuthorship":"(Aiton) Michx.","genus":{"scientificNameWithoutAuthor":"Malus","scientificNameAuthorship":"","scientificName":"Malus"},"family":{"scientificNameWithoutAuthor":"Rosaceae","scientificNameAuthorship":"","scientificName":"Rosaceae"},"commonNames":["Southern crab apple","Narrow-leaved crabapple","Southern crabapple"],"scientificName":"Malus angustifolia (Aiton) Michx."},"gbif":{"id":"3001548"}},{"score":0.00614,"species":{"scientificNameWithoutAuthor":"Prunus subhirtella","scientificNameAuthorship":"Miq.","genus":{"scientificNameWithoutAuthor":"Prunus","scientificNameAuthorship":"","scientificName":"Prunus"},"family":{"scientificNameWithoutAuthor":"Rosaceae","scientificNameAuthorship":"","scientificName":"Rosaceae"},"commonNames":["Rosebud cherry","Spring cherry","Autumn cherry"],"scientificName":"Prunus subhirtella Miq."},"gbif":{"id":"3021229"}},{"score":0.00267,"species":{"scientificNameWithoutAuthor":"Robinia viscosa","scientificNameAuthorship":"Vent.","genus":{"scientificNameWithoutAuthor":"Robinia","scientificNameAuthorship":"","scientificName":"Robinia"},"family":{"scientificNameWithoutAuthor":"Leguminosae","scientificNameAuthorship":"","scientificName":"Leguminosae"},"commonNames":["Clammy locust","Rose acacia","Clammy-bark locust"],"scientificName":"Robinia viscosa Vent."},"gbif":{"id":"5352245"}},{"score":0.0026,"species":{"scientificNameWithoutAuthor":"Handroanthus impetiginosus","scientificNameAuthorship":"(Mart. ex DC.) Mattos","genus":{"scientificNameWithoutAuthor":"Handroanthus","scientificNameAuthorship":"","scientificName":"Handroanthus"},"family":{"scientificNameWithoutAuthor":"Bignoniaceae","scientificNameAuthorship":"","scientificName":"Bignoniaceae"},"commonNames":["Pink trumpet-tree","Taheebo","Pink Trumpet Tree"],"scientificName":"Handroanthus impetiginosus (Mart. ex DC.) Mattos"},"gbif":{"id":"4092242"}},{"score":0.00187,"species":{"scientificNameWithoutAuthor":"Prunus glandulosa","scientificNameAuthorship":"Thunb.","genus":{"scientificNameWithoutAuthor":"Prunus","scientificNameAuthorship":"","scientificName":"Prunus"},"family":{"scientificNameWithoutAuthor":"Rosaceae","scientificNameAuthorship":"","scientificName":"Rosaceae"},"commonNames":["Chinese bush cherry","Dwarf flowering almond","Flowering almond"],"scientificName":"Prunus glandulosa Thunb."},"gbif":{"id":"3022160"}},{"score":0.00162,"species":{"scientificNameWithoutAuthor":"Prunus persica","scientificNameAuthorship":"(L.) Batsch","genus":{"scientificNameWithoutAuthor":"Prunus","scientificNameAuthorship":"","scientificName":"Prunus"},"family":{"scientificNameWithoutAuthor":"Rosaceae","scientificNameAuthorship":"","scientificName":"Rosaceae"},"commonNames":["Peach","هلو","Peach tree"],"scientificName":"Prunus persica (L.) Batsch"},"gbif":{"id":"3022511"}},{"score":0.00162,"species":{"scientificNameWithoutAuthor":"Prunus cerasifera","scientificNameAuthorship":"Ehrh.","genus":{"scientificNameWithoutAuthor":"Prunus","scientificNameAuthorship":"","scientificName":"Prunus"},"family":{"scientificNameWithoutAuthor":"Rosaceae","scientificNameAuthorship":"","scientificName":"Rosaceae"},"commonNames":["Cherry plum, myrobalan","Cherry plum","Myrobalan plum"],"scientificName":"Prunus cerasifera Ehrh."},"gbif":{"id":"3021730"}},{"score":0.00159,"species":{"scientificNameWithoutAuthor":"Malus prattii","scientificNameAuthorship":"(Hemsl.) C.K.Schneid.","genus":{"scientificNameWithoutAuthor":"Malus","scientificNameAuthorship":"","scientificName":"Malus"},"family":{"scientificNameWithoutAuthor":"Rosaceae","scientificNameAuthorship":"","scientificName":"Rosaceae"},"commonNames":["Pratt apple","Pratt's Crab Apple"],"scientificName":"Malus prattii (Hemsl.) C.K.Schneid."},"gbif":{"id":"3001504"}},{"score":0.00159,"species":{"scientificNameWithoutAuthor":"Prunus pedunculata","scientificNameAuthorship":"(Pall.) Maxim.","genus":{"scientificNameWithoutAuthor":"Prunus","scientificNameAuthorship":"","scientificName":"Prunus"},"family":{"scientificNameWithoutAuthor":"Rosaceae","scientificNameAuthorship":"","scientificName":"Rosaceae"},"commonNames":[],"scientificName":"Prunus pedunculata (Pall.) Maxim."},"gbif":{"id":"3022277"}},{"score":0.00153,"species":{"scientificNameWithoutAuthor":"Cercis siliquastrum","scientificNameAuthorship":"L.","genus":{"scientificNameWithoutAuthor":"Cercis","scientificNameAuthorship":"","scientificName":"Cercis"},"family":{"scientificNameWithoutAuthor":"Leguminosae","scientificNameAuthorship":"","scientificName":"Leguminosae"},"commonNames":["Judastree","Lovetree","Judas-tree"],"scientificName":"Cercis siliquastrum L."},"gbif":{"id":"5353590"}},{"score":0.00128,"species":{"scientificNameWithoutAuthor":"Malus sylvestris","scientificNameAuthorship":"(L.) Mill.","genus":{"scientificNameWithoutAuthor":"Malus","scientificNameAuthorship":"","scientificName":"Malus"},"family":{"scientificNameWithoutAuthor":"Rosaceae","scientificNameAuthorship":"","scientificName":"Rosaceae"},"commonNames":["Crab apple","European crab apple","Lopâr"],"scientificName":"Malus sylvestris (L.) Mill."},"gbif":{"id":"3001509"}},{"score":0.0012,"species":{"scientificNameWithoutAuthor":"Magnolia × soulangeana","scientificNameAuthorship":"Soul.-Bod.","genus":{"scientificNameWithoutAuthor":"Magnolia","scientificNameAuthorship":"","scientificName":"Magnolia"},"family":{"scientificNameWithoutAuthor":"Magnoliaceae","scientificNameAuthorship":"","scientificName":"Magnoliaceae"},"commonNames":["Chinese magnolia","Saucer magnolia"],"scientificName":"Magnolia × soulangeana Soul.-Bod."},"gbif":{"id":"7925303"}},{"score":0.00118,"species":{"scientificNameWithoutAuthor":"Cercis canadensis","scientificNameAuthorship":"L.","genus":{"scientificNameWithoutAuthor":"Cercis","scientificNameAuthorship":"","scientificName":"Cercis"},"family":{"scientificNameWithoutAuthor":"Leguminosae","scientificNameAuthorship":"","scientificName":"Leguminosae"},"commonNames":["Eastern redbud","Judastree","Redbud"],"scientificName":"Cercis canadensis L."},"gbif":{"id":"5353583"}},{"score":0.00114,"species":{"scientificNameWithoutAuthor":"Malus × prunifolia","scientificNameAuthorship":"(Willd.) Borkh.","genus":{"scientificNameWithoutAuthor":"Malus","scientificNameAuthorship":"","scientificName":"Malus"},"family":{"scientificNameWithoutAuthor":"Rosaceae","scientificNameAuthorship":"","scientificName":"Rosaceae"},"commonNames":["Plumleaf crab apple","Chinese apple","Crab apple"],"scientificName":"Malus × prunifolia (Willd.) Borkh."},"gbif":{"id":"3001157"}},{"score":0.00111,"species":{"scientificNameWithoutAuthor":"Prunus serrula","scientificNameAuthorship":"Franch.","genus":{"scientificNameWithoutAuthor":"Prunus","scientificNameAuthorship":"","scientificName":"Prunus"},"family":{"scientificNameWithoutAuthor":"Rosaceae","scientificNameAuthorship":"","scientificName":"Rosaceae"},"commonNames":["Birchbark cherry"],"scientificName":"Prunus serrula Franch."},"gbif":{"id":"3023582"}},{"score":0.00106,"species":{"scientificNameWithoutAuthor":"Malus pumila","scientificNameAuthorship":"Mill.","genus":{"scientificNameWithoutAuthor":"Malus","scientificNameAuthorship":"","scientificName":"Malus"},"family":{"scientificNameWithoutAuthor":"Rosaceae","scientificNameAuthorship":"","scientificName":"Rosaceae"},"commonNames":["Apple","Paradise apple","Kulturapfel"],"scientificName":"Malus pumila Mill."},"gbif":{"id":"3001093"}},{"score":0.00101,"species":{"scientificNameWithoutAuthor":"Viburnum farreri","scientificNameAuthorship":"Stearn","genus":{"scientificNameWithoutAuthor":"Viburnum","scientificNameAuthorship":"","scientificName":"Viburnum"},"family":{"scientificNameWithoutAuthor":"Adoxaceae","scientificNameAuthorship":"","scientificName":"Adoxaceae"},"commonNames":["Fragrant viburnum","Culver's root","Farrer's Viburnum"],"scientificName":"Viburnum farreri Stearn"},"gbif":{"id":"6369599"}}],"version":"2022-06-14 (6.0)","remainingIdentificationRequests":498} +} + +export interface PlantNetResult { + "query": { + "project": string, "images": string[], + "organs": string[], + "includeRelatedImages": boolean + }, + "language": string, + "preferedReferential": string, + "bestMatch": string, + "results": { + "score": number, + "gbif": { "id": string /*Actually a number*/ } + "species": + { + "scientificNameWithoutAuthor": string, + "scientificNameAuthorship": string, + "genus": { "scientificNameWithoutAuthor": string, scientificNameAuthorship: string, "scientificName": string }, + "family": { "scientificNameWithoutAuthor": string, scientificNameAuthorship: string, "scientificName": string }, + "commonNames": string [], + "scientificName": string + }, + }[], + "version": string, + "remainingIdentificationRequests": number +} diff --git a/Logic/Web/Wikidata.ts b/Logic/Web/Wikidata.ts index 68f7242a3..910b26d0d 100644 --- a/Logic/Web/Wikidata.ts +++ b/Logic/Web/Wikidata.ts @@ -354,6 +354,25 @@ export default class Wikidata { throw "Unknown id type: " + id } + /** + * Build a SPARQL-query, return the result + * + * @param keys: how variables are named. Every key not ending with 'Label' should appear in at least one statement + * @param statements + * @constructor + */ + public static async Sparql(keys: string[], statements: string[]):Promise< (T & Record) []> { + const query = "SELECT "+keys.map(k => k.startsWith("?") ? k : "?"+k).join(" ")+"\n" + + "WHERE\n" + + "{\n" + + statements.map(stmt => stmt.endsWith(".") ? stmt : stmt+".").join("\n") + + " SERVICE wikibase:label { bd:serviceParam wikibase:language \"[AUTO_LANGUAGE]\". }\n" + + "}" + const url = wds.sparqlQuery(query) + const result = await Utils.downloadJsonCached(url, 24 * 60 * 60 * 1000) + return result.results.bindings + } + /** * Loads a wikidata page * @returns the entity of the given value diff --git a/UI/Base/Button.ts b/UI/Base/Button.ts index 8d4e0dc1e..aa5fc299e 100644 --- a/UI/Base/Button.ts +++ b/UI/Base/Button.ts @@ -3,12 +3,11 @@ import BaseUIElement from "../BaseUIElement"; export class Button extends BaseUIElement { private _text: BaseUIElement; - private _onclick: () => void; - constructor(text: string | BaseUIElement, onclick: (() => void)) { + constructor(text: string | BaseUIElement, onclick: (() => void | Promise)) { super(); this._text = Translations.W(text); - this._onclick = onclick; + this.onClick(onclick) } protected InnerConstructElement(): HTMLElement { @@ -20,7 +19,6 @@ export class Button extends BaseUIElement { const button = document.createElement("button") button.type = "button" button.appendChild(el) - button.onclick = this._onclick form.appendChild(button) return form; } diff --git a/UI/BaseUIElement.ts b/UI/BaseUIElement.ts index e4e1becd8..af75841bc 100644 --- a/UI/BaseUIElement.ts +++ b/UI/BaseUIElement.ts @@ -1,5 +1,3 @@ -import { Utils } from "../Utils"; - /** * A thin wrapper around a html element, which allows to generate a HTML-element. * @@ -11,7 +9,7 @@ export default abstract class BaseUIElement { protected isDestroyed = false; protected readonly clss: Set = new Set(); protected style: string; - private _onClick: () => void; + private _onClick: () => void | Promise; public onClick(f: (() => void)) { this._onClick = f; @@ -127,12 +125,15 @@ export default abstract class BaseUIElement { if (this._onClick !== undefined) { const self = this; - el.onclick = (e) => { + el.onclick = async (e) => { // @ts-ignore if (e.consumed) { return; } - self._onClick(); + const v = self._onClick(); + if(typeof v === "object"){ + await v + } // @ts-ignore e.consumed = true; } diff --git a/UI/BigComponents/PlantNetSpeciesSearch.ts b/UI/BigComponents/PlantNetSpeciesSearch.ts new file mode 100644 index 000000000..70e456385 --- /dev/null +++ b/UI/BigComponents/PlantNetSpeciesSearch.ts @@ -0,0 +1,121 @@ +import {VariableUiElement} from "../Base/VariableUIElement"; +import {Store, UIEventSource} from "../../Logic/UIEventSource"; +import PlantNet from "../../Logic/Web/PlantNet"; +import Loading from "../Base/Loading"; +import Wikidata from "../../Logic/Web/Wikidata"; +import WikidataPreviewBox from "../Wikipedia/WikidataPreviewBox"; +import {Button} from "../Base/Button"; +import Combine from "../Base/Combine"; +import Title from "../Base/Title"; +import WikipediaBox from "../Wikipedia/WikipediaBox"; +import Translations from "../i18n/Translations"; +import List from "../Base/List"; +import Svg from "../../Svg"; + + +export default class PlantNetSpeciesSearch extends VariableUiElement { + /*** + * Given images, queries plantnet to search a species matching those images. + * A list of species will be presented to the user, after which they can confirm an item. + * The wikidata-url is returned in the callback when the user selects one + */ + constructor(images: Store, onConfirm: (wikidataUrl: string) => Promise) { + const t = Translations.t.plantDetection + super( + images + .bind(images => { + if (images.length === 0) { + return null + } + return UIEventSource.FromPromiseWithErr(PlantNet.query(images.slice(0,5))); + }) + .map(result => { + if (images.data.length === 0) { + return new Combine([t.takeImages, t.howTo.intro, new List( + [ + t.howTo.li0, + t.howTo.li1, + t.howTo.li2, + t.howTo.li3 + ] + )]).SetClass("flex flex-col") + } + if (result === undefined) { + return new Loading(t.querying.Subs(images.data)) + } + + if (result["error"] !== undefined) { + return t.error.Subs(result).SetClass("alert") + } + console.log(result) + const success = result["success"] + + const selectedSpecies = new UIEventSource(undefined) + const speciesInformation = success.results + .filter(species => species.score >= 0.005) + .map(species => { + const wikidata = UIEventSource.FromPromise(Wikidata.Sparql<{ species }>(["?species", "?speciesLabel"], + ["?species wdt:P846 \"" + species.gbif.id + "\""])); + + const confirmButton = new Button(t.seeInfo, async() => { + await selectedSpecies.setData(wikidata.data[0].species?.value) + }).SetClass("btn") + + const match = t.matchPercentage.Subs({match: Math.round(species.score * 100)}).SetClass("font-bold") + + const extraItems = new Combine([match, confirmButton]).SetClass("flex flex-col") + + return new WikidataPreviewBox(wikidata.map(wd => wd == undefined ? undefined : wd[0]?.species?.value), + { + whileLoading: new Loading( + t.loadingWikidata.Subs({species: species.species.scientificNameWithoutAuthor})), + extraItems: [new Combine([extraItems])], + + imageStyle: "max-width: 8rem; width: unset; height: 8rem" + }) + .SetClass("border-2 border-subtle rounded-xl block mb-2") + } + ); + const plantOverview = new Combine([ + new Title(t.overviewTitle), + t.overviewIntro, + t.overviewVerify.SetClass("font-bold"), + ...speciesInformation]).SetClass("flex flex-col") + + + return new VariableUiElement(selectedSpecies.map(wikidataSpecies => { + if (wikidataSpecies === undefined) { + return plantOverview + } + const buttons = new Combine([ + new Button( + new Combine([ + Svg.back_svg().SetClass("w-6 mr-1 bg-white rounded-full p-1"), + t.back]).SetClass("flex"), + () => { + selectedSpecies.setData(undefined) + }).SetClass("btn btn-secondary"), + + new Button( + new Combine([Svg.confirm_svg().SetClass("w-6 mr-1"), t.confirm]).SetClass("flex") + , () => { + onConfirm(wikidataSpecies) + }).SetClass("btn"), + + ]).SetClass("flex justify-between"); + + return new Combine([ + new WikipediaBox([wikidataSpecies], { + firstParagraphOnly: false, + noImages: false, + addHeader: false + }).SetClass("h-96"), + buttons + ]).SetClass("flex flex-col self-end") + })) + + } + )) + } + +} \ No newline at end of file diff --git a/UI/Image/ImageUploadFlow.ts b/UI/Image/ImageUploadFlow.ts index 033aecd03..1c4f49001 100644 --- a/UI/Image/ImageUploadFlow.ts +++ b/UI/Image/ImageUploadFlow.ts @@ -130,16 +130,17 @@ export class ImageUploadFlow extends Toggle { return undefined; } if (l == 1) { - return t.uploadingPicture.Clone().SetClass("alert") + return new Loading( t.uploadingPicture).SetClass("alert") } else { - return t.uploadingMultiple.Subs({count: "" + l}).SetClass("alert") + return new Loading(t.uploadingMultiple.Subs({count: "" + l})).SetClass("alert") } })), new VariableUiElement(uploader.failed.map(q => q.length).map(l => { if (l == 0) { return undefined } - return new Loading(t.uploadFailed).SetClass("alert"); + console.log(l) + return t.uploadFailed.SetClass("block alert"); })), new VariableUiElement(uploadedCount.map(l => { if (l == 0) { diff --git a/UI/SpecialVisualizations.ts b/UI/SpecialVisualizations.ts index fe12e191f..8602ba60d 100644 --- a/UI/SpecialVisualizations.ts +++ b/UI/SpecialVisualizations.ts @@ -61,6 +61,8 @@ import StatisticsPanel from "./BigComponents/StatisticsPanel"; import {OsmFeature} from "../Models/OsmFeature"; import EditableTagRendering from "./Popup/EditableTagRendering"; import TagRenderingConfig from "../Models/ThemeConfig/TagRenderingConfig"; +import {ProvidedImage} from "../Logic/ImageProviders/ImageProvider"; +import PlantNetSpeciesSearch from "./BigComponents/PlantNetSpeciesSearch"; export interface SpecialVisualization { funcName: string, @@ -196,7 +198,7 @@ class NearbyImageVis implements SpecialVisualization { new ChangeTagAction( id, new And(tags), - tagSource, + tagSource.data, { theme: state?.layoutToUse.id, changeType: "link-image" @@ -1302,6 +1304,53 @@ export default class SpecialVisualizations { const [layerId, __] = tagRenderingId.split(".") return [layerId] } + }, + { + funcName: "plantnet_detection", + + docs: "Sends the images linked to the current object to plantnet.org and asks it what plant species is shown on it. The user can then select the correct species; the corresponding wikidata-identifier will then be added to the object (together with `source:species:wikidata=plantnet.org AI`). ", + args: [{ + name: "image_key", + defaultValue: AllImageProviders.defaultKeys.join(","), + doc: "The keys given to the images, e.g. if image is given, the first picture URL will be added as image, the second as image:0, the third as image:1, etc... Multiple values are allowed if ';'-separated " + }], + constr: (state, tags, args) => { + let imagePrefixes: string[] = undefined; + if (args.length > 0) { + imagePrefixes = [].concat(...args.map(a => a.split(","))); + } + + const detect = new UIEventSource(false) + const toggle = new Toggle( + new Lazy(() => { + const allProvidedImages: Store = AllImageProviders.LoadImagesFor(tags, imagePrefixes) + const allImages: Store = allProvidedImages.map(pi => pi.map(pi => pi.url)) + return new PlantNetSpeciesSearch(allImages, async selectedWikidata => { + selectedWikidata = Wikidata.ExtractKey(selectedWikidata) + const change = new ChangeTagAction(tags.data.id, + new And([new Tag("species:wikidata", selectedWikidata), + new Tag("source:species:wikidata","PlantNet.org AI") + ]), + tags.data, + { + theme: state.layoutToUse.id, + changeType: "plantnet-ai-detection" + } + ) + await state.changes.applyAction(change) + }) + }), + new SubtleButton(undefined, "Detect plant species with plantnet.org").onClick(() => detect.setData(true)), + detect + ) + + return new Combine([ + toggle, + new Combine([Svg.plantnet_logo_svg().SetClass("w-10 h-10 p-1 mr-1 bg-white rounded-full"), + Translations.t.plantDetection.poweredByPlantnet]) + .SetClass("flex p-2 bg-gray-200 rounded-xl self-end") + ]).SetClass("flex flex-col") + } } ] diff --git a/UI/Wikipedia/WikidataPreviewBox.ts b/UI/Wikipedia/WikidataPreviewBox.ts index ca997d42d..2af1f230d 100644 --- a/UI/Wikipedia/WikidataPreviewBox.ts +++ b/UI/Wikipedia/WikidataPreviewBox.ts @@ -1,5 +1,5 @@ import {VariableUiElement} from "../Base/VariableUIElement"; -import {UIEventSource} from "../../Logic/UIEventSource"; +import {Store, UIEventSource} from "../../Logic/UIEventSource"; import Wikidata, {WikidataResponse} from "../../Logic/Web/Wikidata"; import {Translation, TypedTranslation} from "../i18n/Translation"; import {FixedUiElement} from "../Base/FixedUiElement"; @@ -57,7 +57,11 @@ export default class WikidataPreviewBox extends VariableUiElement { } ] - constructor(wikidataId: UIEventSource, options?: {noImages?: boolean}) { + constructor(wikidataId: Store, options?: { + noImages?: boolean, + imageStyle?: string, + whileLoading?: BaseUIElement | string, + extraItems?: (BaseUIElement | string)[]}) { let inited = false; const wikidata = wikidataId .stabilized(250) @@ -71,7 +75,7 @@ export default class WikidataPreviewBox extends VariableUiElement { super(wikidata.map(maybeWikidata => { if (maybeWikidata === null || !inited) { - return undefined; + return options?.whileLoading; } if (maybeWikidata === undefined) { @@ -87,7 +91,10 @@ export default class WikidataPreviewBox extends VariableUiElement { } - public static WikidataResponsePreview(wikidata: WikidataResponse, options?: {noImages?: boolean}): BaseUIElement { + public static WikidataResponsePreview(wikidata: WikidataResponse, options?: { + noImages?: boolean, + imageStyle?: string, + extraItems?: (BaseUIElement | string)[]}): BaseUIElement { let link = new Link( new Combine([ wikidata.id, @@ -100,7 +107,8 @@ export default class WikidataPreviewBox extends VariableUiElement { [Translation.fromMap(wikidata.labels)?.SetClass("font-bold"), link]).SetClass("flex justify-between"), Translation.fromMap(wikidata.descriptions), - WikidataPreviewBox.QuickFacts(wikidata, options) + WikidataPreviewBox.QuickFacts(wikidata, options), + ...(options.extraItems ?? []) ]).SetClass("flex flex-col link-underline") @@ -108,11 +116,9 @@ export default class WikidataPreviewBox extends VariableUiElement { if (wikidata.claims.get("P18")?.size > 0) { imageUrl = Array.from(wikidata.claims.get("P18"))[0] } - - if (imageUrl && !options?.noImages) { imageUrl = WikimediaImageProvider.singleton.PrepUrl(imageUrl).url - info = new Combine([new Img(imageUrl).SetStyle("max-width: 5rem; width: unset; height: 4rem").SetClass("rounded-xl mr-2"), + info = new Combine([new Img(imageUrl).SetStyle(options?.imageStyle ?? "max-width: 5rem; width: unset; height: 4rem").SetClass("rounded-xl mr-2"), info.SetClass("w-full")]).SetClass("flex") } diff --git a/assets/layers/tree_node/tree_node.json b/assets/layers/tree_node/tree_node.json index 3d020aac5..5ad4d9124 100644 --- a/assets/layers/tree_node/tree_node.json +++ b/assets/layers/tree_node/tree_node.json @@ -105,80 +105,49 @@ ] }, { - "id": "tree-leaf_type", + "id": "plantnet", + "render": "{plantnet_detection()}", + "condition": "species:wikidata=" + }, + { + "id": "tree-species-wikidata", "question": { - "nl": "Is dit een naald- of loofboom?", - "en": "Is this a broadleaved or needleleaved tree?", - "it": "Si tratta di un albero latifoglia o aghifoglia?", - "fr": "Cet arbre est-il un feuillu ou un résineux ?", - "de": "Ist dies ein Laub- oder Nadelbaum?", - "es": "¿Es un árbol de hoja ancha o de hoja aguja?" + "en": "What species is this tree?", + "de": "Um welche Baumart handelt es sich?", + "id": "Spesies pohon apa ini?", + "es": "¿De qué especie es este árbol?", + "nl": "Wat is de boomsoort?", + "fr": "Quelle est l'espèce de cet arbre ?" }, - "mappings": [ - { - "if": { - "and": [ - "leaf_type=broadleaved" + "render": { + "*": "{wikipedia(species:wikidata):max-height: 25rem}" + }, + "freeform": { + "key": "species:wikidata", + "type": "wikidata", + "helperArgs": [ + "species", + { + "instanceOf": [ + 10884, + 16521 ] - }, - "then": { - "nl": "Loofboom", - "en": "Broadleaved", - "it": "Latifoglia", - "fr": "Feuillu", - "de": "Laubbaum", - "ca": "De fulla ampla", - "es": "Latifoliada", - "id": "Berdaun lebar" - }, - "icon": { - "path": "./assets/layers/tree_node/broadleaved.svg", - "class": "small" } - }, - { - "if": { - "and": [ - "leaf_type=needleleaved" - ] - }, - "then": { - "nl": "Naaldboom", - "en": "Needleleaved", - "it": "Aghifoglia", - "fr": "Résineux", - "de": "Nadelbaum", - "ca": "Amb fulles d'agulla", - "es": "Hoja aguja", - "id": "Berdaun jarum" - }, - "icon": { - "path": "./assets/layers/tree_node/needleleaved.svg", - "class": "small" - } - }, - { - "if": { - "and": [ - "leaf_type=leafless" - ] - }, - "then": { - "nl": "Permanent bladloos", - "en": "Permanently leafless", - "it": "Privo di foglie (permanente)", - "fr": "Sans feuilles (Permanent)", - "de": "Dauerhaft blattlos", - "es": "Permanentemente sin hojas", - "id": "Tanpa daun permanen" - }, - "hideInAnswer": true, - "icon": { - "path": "./assets/layers/tree_node/leafless.svg", - "class": "small" - } - } - ] + ] + } + }, + { + "id": "tree-wikipedia", + "#": "If this tree has a wikipedia article, show it. People can _only_ set the species though!", + "render": { + "*": "{wikipedia()}" + }, + "condition": { + "or": [ + "wikipedia~*", + "wikidata~*" + ] + } }, { "id": "tree-denotation", @@ -313,6 +282,88 @@ } ] }, + { + "id": "tree-leaf_type", + "question": { + "nl": "Is dit een naald- of loofboom?", + "en": "Is this a broadleaved or needleleaved tree?", + "it": "Si tratta di un albero latifoglia o aghifoglia?", + "fr": "Cet arbre est-il un feuillu ou un résineux ?", + "de": "Ist dies ein Laub- oder Nadelbaum?", + "es": "¿Es un árbol de hoja ancha o de hoja aguja?" + }, + "mappings": [ + { + "if": { + "and": [ + "leaf_type=broadleaved" + ] + }, + "then": { + "nl": "Loofboom", + "en": "Broadleaved", + "it": "Latifoglia", + "fr": "Feuillu", + "de": "Laubbaum", + "ca": "De fulla ampla", + "es": "Latifoliada", + "id": "Berdaun lebar" + }, + "icon": { + "path": "./assets/layers/tree_node/broadleaved.svg", + "class": "small" + } + }, + { + "if": { + "and": [ + "leaf_type=needleleaved" + ] + }, + "then": { + "nl": "Naaldboom", + "en": "Needleleaved", + "it": "Aghifoglia", + "fr": "Résineux", + "de": "Nadelbaum", + "ca": "Amb fulles d'agulla", + "es": "Hoja aguja", + "id": "Berdaun jarum" + }, + "icon": { + "path": "./assets/layers/tree_node/needleleaved.svg", + "class": "small" + } + }, + { + "if": { + "and": [ + "leaf_type=leafless" + ] + }, + "then": { + "nl": "Permanent bladloos", + "en": "Permanently leafless", + "it": "Privo di foglie (permanente)", + "fr": "Sans feuilles (Permanent)", + "de": "Dauerhaft blattlos", + "es": "Permanentemente sin hojas", + "id": "Tanpa daun permanen" + }, + "hideInAnswer": true, + "icon": { + "path": "./assets/layers/tree_node/leafless.svg", + "class": "small" + } + } + ], + "condition": { + "#": "If the wikidata entry is known, no need to ask for redundant data such as leaf type", + "and": [ + "species:wikidata=" + ] + } + }, { "id": "tree-decidouous", "question": { @@ -360,48 +411,10 @@ } ], "condition": { + "#": "If the wikidata entry is known, no need to ask for redundant data such as leaf type", "and": [ - "leaf_type!~^leafless$" - ] - } - }, - { - "id": "tree-species-wikidata", - "question": { - "en": "What species is this tree?", - "de": "Um welche Baumart handelt es sich?", - "id": "Spesies pohon apa ini?", - "es": "¿De qué especie es este árbol?", - "nl": "Wat is de boomsoort?", - "fr": "Quelle est l'espèce de cet arbre ?" - }, - "render": { - "*": "{wikipedia(species:wikidata):max-height: 25rem}" - }, - "freeform": { - "key": "species:wikidata", - "type": "wikidata", - "helperArgs": [ - "species", - { - "instanceOf": [ - 10884, - 16521 - ] - } - ] - } - }, - { - "id": "tree-wikipedia", - "#": "If this tree has a wikipedia article, show it. People can _only_ set the species though!", - "render": { - "*": "{wikipedia()}" - }, - "condition": { - "or": [ - "wikipedia~*", - "wikidata~*" + "leaf_type!~^leafless$", + "species:wikidata=" ] } }, diff --git a/assets/svg/license_info.json b/assets/svg/license_info.json index 6d1d8401e..f645f3eb1 100644 --- a/assets/svg/license_info.json +++ b/assets/svg/license_info.json @@ -985,6 +985,16 @@ "authors": [], "sources": [] }, + { + "path": "plantnet_logo.svg", + "license": "Logo (fair usage)", + "authors": [ + "https://plantnet.org" + ], + "sources": [ + "https://plantnet.org" + ] + }, { "path": "plus.svg", "license": "CC0; trivial", diff --git a/assets/svg/plantnet_logo.svg b/assets/svg/plantnet_logo.svg new file mode 100644 index 000000000..a9966e2f4 --- /dev/null +++ b/assets/svg/plantnet_logo.svg @@ -0,0 +1,22 @@ + + + + + + + + + diff --git a/css/index-tailwind-output.css b/css/index-tailwind-output.css index ea63028b9..800165275 100644 --- a/css/index-tailwind-output.css +++ b/css/index-tailwind-output.css @@ -858,6 +858,10 @@ video { margin-bottom: 0.75rem; } +.mb-2 { + margin-bottom: 0.5rem; +} + .ml-3 { margin-left: 0.75rem; } @@ -886,6 +890,10 @@ video { margin-top: 1.5rem; } +.mr-1 { + margin-right: 0.25rem; +} + .mr-2 { margin-right: 0.5rem; } @@ -906,10 +914,6 @@ video { margin-right: 1rem; } -.mb-2 { - margin-bottom: 0.5rem; -} - .ml-2 { margin-left: 0.5rem; } @@ -962,10 +966,6 @@ video { margin-top: -3rem; } -.mr-1 { - margin-right: 0.25rem; -} - .mb-0 { margin-bottom: 0px; } @@ -1074,6 +1074,10 @@ video { height: 2rem; } +.h-14 { + height: 3.5rem; +} + .h-4 { height: 1rem; } @@ -1098,6 +1102,10 @@ video { height: 8rem; } +.h-96 { + height: 24rem; +} + .h-16 { height: 4rem; } @@ -1162,6 +1170,14 @@ video { width: 2rem; } +.w-14 { + width: 3.5rem; +} + +.w-1\/3 { + width: 33.333333%; +} + .w-4 { width: 1rem; } @@ -1407,6 +1423,10 @@ video { border-radius: 9999px; } +.rounded-xl { + border-radius: 0.75rem; +} + .rounded-3xl { border-radius: 1.5rem; } @@ -1423,10 +1443,6 @@ video { border-radius: 0.5rem; } -.rounded-xl { - border-radius: 0.75rem; -} - .rounded-sm { border-radius: 0.125rem; } @@ -1436,14 +1452,14 @@ video { border-bottom-left-radius: 0.25rem; } -.border { - border-width: 1px; -} - .border-2 { border-width: 2px; } +.border { + border-width: 1px; +} + .border-4 { border-width: 4px; } @@ -1504,6 +1520,11 @@ video { background-color: rgba(255, 255, 255, var(--tw-bg-opacity)); } +.bg-gray-200 { + --tw-bg-opacity: 1; + background-color: rgba(229, 231, 235, var(--tw-bg-opacity)); +} + .bg-red-400 { --tw-bg-opacity: 1; background-color: rgba(248, 113, 113, var(--tw-bg-opacity)); @@ -1524,11 +1545,6 @@ video { background-color: rgba(0, 0, 0, var(--tw-bg-opacity)); } -.bg-gray-200 { - --tw-bg-opacity: 1; - background-color: rgba(229, 231, 235, var(--tw-bg-opacity)); -} - .bg-gray-100 { --tw-bg-opacity: 1; background-color: rgba(243, 244, 246, var(--tw-bg-opacity)); diff --git a/langs/en.json b/langs/en.json index f359f52a9..44f5a6df1 100644 --- a/langs/en.json +++ b/langs/en.json @@ -685,6 +685,27 @@ "typeText": "Type some text to add a comment", "warnAnonymous": "You are not logged in. We won't be able to contact you to resolve your issue." }, + "plantDetection": { + "back": "Back to species overview", + "confirm": "Select species", + "error": "Something went wrong while detecting the tree species: {error}", + "howTo": { + "intro": "For optimal results,", + "li0": "take a picture which show the tree in the center without much background", + "li1": "take a picture which shows a single leaf", + "li2": "take a picture which shows the bark", + "li3": "take a picture of the flowers" + }, + "loadingWikidata": "Loading information about {species}", + "matchPercentage": "{match}% match", + "overviewIntro": "The AI on PlantNet.org thinks the images show the species below.", + "overviewTitle": "Automatically detected species", + "overviewVerify": "Please verify that correct species and link it to the tree", + "poweredByPlantnet": "Powered by plantnet.org", + "querying": "Querying plantnet.org with {length} images", + "seeInfo": "See more information about the species", + "takeImages": "Take images of the tree to automatically detect the tree type" + }, "privacy": { "editing": "When you make a change to the map, this change is recorded on OpenStreetMap and is publicly available to anyone. A changeset made with MapComplete includes the following data:
  • The changes you made
  • Your username
  • When this change is made
  • The theme you used while making the change
  • The language of the user interface
  • An indication of how close you were to changed objects. Other mappers can use this information to determine if a change was made based on survey or on remote research
Please refer to the privacy policy on OpenStreetMap.org for detailed information. We'd like to remind you that you can use a fictional name when signing up.", "editingTitle": "When making changes", diff --git a/test.ts b/test.ts index 097e8bb36..e69de29bb 100644 --- a/test.ts +++ b/test.ts @@ -1,3 +0,0 @@ -import StatisticsGUI from "./UI/StatisticsGUI"; - -new StatisticsGUI().AttachTo("maindiv") \ No newline at end of file