Skip to content

Commit

Permalink
Read and resolve schema from open API
Browse files Browse the repository at this point in the history
  • Loading branch information
ridoo committed Sep 10, 2024
1 parent 23b6eff commit 4455bdf
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 47 deletions.
166 changes: 119 additions & 47 deletions geonode_mapstore_client/client/js/plugins/LitterAssessment.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,51 @@ import { createSelector } from "reselect";
import { Glyphicon } from "react-bootstrap";
import assign from "object-assign";

import jp from "jsonpath";

import axios from "@mapstore/framework/libs/ajax";
import { createPlugin } from "@mapstore/framework/utils/PluginsUtils";
import { setControlProperty } from "@mapstore/framework/actions/controls";
import { addAuthenticationParameter } from "@mapstore/framework/utils/SecurityUtils";
import Message from "@mapstore/framework/components/I18N/Message";
import controls from "@mapstore/framework/reducers/controls";

import {
parseDevHostname,
getGeoNodeLocalConfig,
} from '@js/utils/APIUtils';
import { parseDevHostname, getGeoNodeLocalConfig } from "@js/utils/APIUtils";
import Button from "@js/components/Button";
import OverlayContainer from "@js/components/OverlayContainer";
import { getResourceId } from "@js/selectors/resource";

import Form from "@rjsf/core";


const log = (type) => console.log.bind(console, type);

async function getUiSchemas() {
const baseUrl = getGeoNodeLocalConfig(
"geoNodeSettings.staticPath",
"/static/"
);
return axios.get(baseUrl + "litterassessment/litterassessmentConfig.json");
}

async function getOpenApiSchema() {
const url = parseDevHostname("/litterassessment");
return axios.get(`${url}/openapi.json`);
}

async function getModels() {
const configPath = "litterassessment/litterassessmentConfig.json";
const configUrl =
getGeoNodeLocalConfig("geoNodeSettings.staticPath", "/static/") +
configPath;
const url = parseDevHostname("/litterassessment");
const configUrl = `${url}/models`;
return axios.get(configUrl);
}

function triggerAiInference({ formData }) {

function triggerAiInference(selectedModel, { formData }) {
const headers = {
"Content-type": "application/x-www-form-urlencoded;charset=utf-8",
"Content-type": "application/json",
Accept: "application/json",
};

const url = parseDevHostname("/litterassessment/")
const path = `/litterassessment/models/${selectedModel}/`
const url = parseDevHostname(path);
return axios
.post(url, formData, headers)
.then((response) => {
Expand Down Expand Up @@ -77,32 +86,84 @@ function toWmsUrl(wmsLayerOptions, securityToken) {
return new URL(`${url}?${query}`).toString();
}

function LitterAssessment({ enabled, pk, wmsLayers = [], securityToken, onClose }) {
const [models, setModels] = useState({
"model a": { jsonSchema: {}, uiSchema: {} },
"model b": { jsonSchema: {}, uiSchema: {} },
});

function LitterAssessment({
enabled,
pk,
wmsLayers = [],
securityToken,
onClose,
}) {
const [models, setModels] = useState({});
const [uischemas, setSchemas] = useState({});
const [jsonSchemas, setJsonSchemas] = useState({});
const [selectedModel, setSelectedModel] = useState("");

const isMounted = useRef(false);
useEffect(() => {
isMounted.current = true;
return () => {
isMounted.current = false;
};
}, []);

useEffect(() => {
getOpenApiSchema()
.then(async (response) => {
const openApiSchema = response.data;
const re = new RegExp("/models/");
const models = {};
Object.entries(openApiSchema.paths).forEach(async ([k, v]) => {
if (k.includes("/models/") && k !== "/models/") {
const key = k.replace(re, "");
const modelName = key.endsWith("/") ? key.slice(0, -1) : key;

const resolve = function (ref) {
if (ref === undefined || !ref.startsWith("#/")) {
return undefined;
}
const jsonPath = ref.replace("#/", "$.").replaceAll("/", ".");
return jp.query(openApiSchema, jsonPath)[0] || undefined;
};

const responseBody =
v.post?.requestBody?.content["application/json"];
const schema = resolve(responseBody?.schema["$ref"]);

jp.apply(schema, "$.properties.*['$ref']", (ref) =>
resolve(ref)
).forEach((rr) => {
schema.properties[rr.path.slice(-1)] = rr.value;
});

models[modelName] = schema;
}
});
setJsonSchemas(models);
})
.catch((err) => {
console.error("could not get OpenAPI schema!", err);
});

getUiSchemas()
.then((response) => {
const schemas = response.data.schemas;
setSchemas(schemas);
})
.catch((err) => {
console.error("could get schemas from config!", err);
});

getModels()
.then((response) => {
const models = response.data.models;
setSelectedModel(Object.keys(models)[0] || null)
const models = response.data.models?.reduce(
(acc, m) => ({ ...acc, [m.name]: m }),
{}
);
setSelectedModel(Object.keys(models)[0] || null);
setModels(models);
})
.catch((err) => {
console.error("could get models from config!", err);
});

return () => {
isMounted.current = false;
};
}, []);

const wmsLayer = wmsLayers?.length
Expand All @@ -127,31 +188,42 @@ function LitterAssessment({ enabled, pk, wmsLayers = [], securityToken, onClose
<Message msgId="gnviewer.litterassessment.model" />
</label>

<select id="model-select"
onChange={(event) => setSelectedModel(event.target.value)}
<select
id="model-select"
onChange={(event) => {
setSelectedModel(event.target.value);
}}
value={selectedModel}
>
{Object.keys(models)
.map((modelName, index) => (
<option key={index} value={modelName}>
{modelName}
</option>
))}
{Object.keys(models).map((model, index) => (
<option key={index} value={model}>
{model}
</option>
))}
</select>

<Form
schema={models[selectedModel]?.jsonSchema || {}}
uiSchema={models[selectedModel]?.uiSchema || {}}
formData={{ imageUrl: wmsLayer, pk }}
onSubmit={(e) => triggerAiInference(e)}
onError={log("errors")}
>
<div>
<button type="submit" onClick="triggerAiInference">
Submit
</button>
</div>
</Form>
<div>
<h3>Description</h3>
<span class="model-description">
{models[selectedModel]?.description}
</span>
</div>

<div class="model-input">
<Form
schema={jsonSchemas[selectedModel] || {}}
uiSchema={uischemas[selectedModel] || {}}
formData={{ imageUrl: wmsLayer, pk }}
onSubmit={(e) => triggerAiInference(selectedModel, e)}
onError={log("errors")}
>
<div class="submit-btn">
<button type="submit" onClick="triggerAiInference">
Submit
</button>
</div>
</Form>
</div>
</div>
</div>
</section>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,19 @@
#model-select {
margin-left: 1em;
}

.model-description {

}

.model-input {

.submit-btn {
margin-top: 1em;
}

}

}
.ms-popover {
display: inline-block;
Expand Down

0 comments on commit 4455bdf

Please sign in to comment.