forked from MapComplete/MapComplete
Integrating plantnet-API, add rudimentary UI
This commit is contained in:
parent
89eecdb38a
commit
a8959fc934
4 changed files with 80 additions and 9 deletions
File diff suppressed because one or more lines are too long
|
@ -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<T>(keys: string[], statements: string[]):Promise< (T & Record<string, {type: string, value: string}>) []> {
|
||||
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
|
||||
|
|
|
@ -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,7 @@ export default class WikidataPreviewBox extends VariableUiElement {
|
|||
}
|
||||
]
|
||||
|
||||
constructor(wikidataId: UIEventSource<string>, options?: {noImages?: boolean}) {
|
||||
constructor(wikidataId: Store<string>, options?: {noImages?: boolean, whileLoading?: BaseUIElement | string, extraItems?: (BaseUIElement | string)[]}) {
|
||||
let inited = false;
|
||||
const wikidata = wikidataId
|
||||
.stabilized(250)
|
||||
|
@ -71,7 +71,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 +87,7 @@ export default class WikidataPreviewBox extends VariableUiElement {
|
|||
|
||||
}
|
||||
|
||||
public static WikidataResponsePreview(wikidata: WikidataResponse, options?: {noImages?: boolean}): BaseUIElement {
|
||||
public static WikidataResponsePreview(wikidata: WikidataResponse, options?: {noImages?: boolean, extraItems?: (BaseUIElement | string)[]}): BaseUIElement {
|
||||
let link = new Link(
|
||||
new Combine([
|
||||
wikidata.id,
|
||||
|
@ -100,7 +100,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,8 +109,6 @@ 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"),
|
||||
|
|
53
test.ts
53
test.ts
|
@ -0,0 +1,53 @@
|
|||
import PlantNet from "./Logic/Web/PlantNet";
|
||||
import {UIEventSource} from "./Logic/UIEventSource";
|
||||
import {VariableUiElement} from "./UI/Base/VariableUIElement";
|
||||
import List from "./UI/Base/List";
|
||||
import Combine from "./UI/Base/Combine";
|
||||
import {FixedUiElement} from "./UI/Base/FixedUiElement";
|
||||
import Wikidata from "./Logic/Web/Wikidata";
|
||||
import WikidataPreviewBox from "./UI/Wikipedia/WikidataPreviewBox";
|
||||
import Loading from "./UI/Base/Loading";
|
||||
|
||||
function build(images: UIEventSource<string[]>) {
|
||||
return new VariableUiElement(images
|
||||
.bind(images => {
|
||||
if (images.length === 0) {
|
||||
return null
|
||||
}
|
||||
return new UIEventSource({success: PlantNet.exampleResultPrunus}) /*/ UIEventSource.FromPromiseWithErr(PlantNet.query(images.slice(0,5))); //*/
|
||||
})
|
||||
.map(result => {
|
||||
if (result === undefined) {
|
||||
return new Loading()
|
||||
}
|
||||
if (result === null) {
|
||||
return "Take images of the tree to automatically detect the tree type"
|
||||
}
|
||||
if (result["error"] !== undefined) {
|
||||
return result["error"]
|
||||
}
|
||||
console.log(result)
|
||||
const success = result["success"]
|
||||
return new Combine(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 + "\""]));
|
||||
|
||||
return new WikidataPreviewBox(wikidata.map(wd => wd == undefined ? undefined : wd[0]?.species?.value),
|
||||
{
|
||||
whileLoading: new Loading("Loading information about " + species.species.scientificNameWithoutAuthor),
|
||||
extraItems: [Math.round(species.score * 100) + "% match"]
|
||||
})
|
||||
.SetClass("border-2 border-subtle rounded-xl block mb-2")
|
||||
}
|
||||
)).SetClass("flex flex-col")
|
||||
}
|
||||
))
|
||||
|
||||
|
||||
}
|
||||
|
||||
const images = ["https://i.imgur.com/VJp1qG1.jpg"]
|
||||
|
||||
build(new UIEventSource(images)).AttachTo("maindiv")
|
Loading…
Reference in a new issue