Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KPI Integration #295

Merged
merged 3 commits into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions frontend/src/app/routes/models/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,12 @@ const LayoutToggle = ({
query,
updateQuery,
isMobile,
disabled=false
disabled = false,
}: {
updateQuery: (params: TQueryParams) => void;
query: TQueryParams;
isMobile?: boolean;
disabled?:boolean
disabled?: boolean;
}) => {
const activeLayout = query[SEARCH_PARAMS.layout];
return (
Expand All @@ -134,7 +134,7 @@ const LayoutToggle = ({
disabled={disabled}
>
{activeLayout !== LayoutView.LIST ? (
<ListIcon className="icon-lg"/>
<ListIcon className="icon-lg" />
) : (
<CategoryIcon className="icon-lg" />
)}
Expand Down Expand Up @@ -295,7 +295,10 @@ export const ModelsPage = () => {
<div className="w-full grid md:grid-cols-4 md:border rounded-md p-2 md:border-gray-border gap-x-2 mt-10 grid-rows-2 md:grid-rows-1 gap-y-6 md:gap-y-0 h-screen">
<div className="overflow-scroll md:row-start-1 col-span-1 md:col-span-2">
<div className="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 gap-x-4 gap-y-10">
<ModelListGridLayout models={data?.results} isPending={isPending} />
<ModelListGridLayout
models={data?.results}
isPending={isPending}
/>
</div>
</div>
<div className="col-span-2 md:col-span-2 row-start-1 ">
Expand Down Expand Up @@ -360,7 +363,11 @@ export const ModelsPage = () => {
<div className="md:flex items-center gap-x-10 hidden">
{/* Desktop */}
<SetMapToggle updateQuery={updateQuery} query={query} />
<LayoutToggle updateQuery={updateQuery} query={query} disabled={mapViewIsActive as boolean}/>
<LayoutToggle
updateQuery={updateQuery}
query={query}
disabled={mapViewIsActive as boolean}
/>
</div>
</div>
{/* Mobile */}
Expand Down
19 changes: 11 additions & 8 deletions frontend/src/components/landing/cta/cta.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@ import HOTTeam from "@/assets/images/hot_team_2.jpg";
import styles from "./cta.module.css";
import { APP_CONTENT } from "@/utils";
import { Image } from "@/components/ui/image";
import { Link } from "@/components/ui/link";

const CallToAction = () => {
const joinTheCommunityClick = () =>
{
window.open("https://slack.hotosm.org/")
}
return (
<section className={styles.container}>
<div className={styles.cta}>
Expand All @@ -17,10 +14,16 @@ const CallToAction = () => {
<p>{APP_CONTENT.homepage.callToAction.paragraph}</p>
</div>
<div className={styles.ctaButtonContainer}>
<Button variant="primary" onClick={joinTheCommunityClick}>
{" "}
{APP_CONTENT.homepage.callToAction.ctaButton}
</Button>
<Link
href={APP_CONTENT.homepage.callToAction.ctaLink}
title={APP_CONTENT.homepage.callToAction.ctaButton}
nativeAnchor
blank
>
<Button variant="primary">
{APP_CONTENT.homepage.callToAction.ctaButton}
</Button>
</Link>
</div>
</div>
<div className={styles.imageBlock}>
Expand Down
77 changes: 52 additions & 25 deletions frontend/src/components/landing/kpi/kpi.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,68 @@
import { APP_CONTENT } from "@/utils";
import styles from "./kpi.module.css";
import { API_ENDPOINTS, apiClient } from "@/services";
import { useQuery } from "@tanstack/react-query";

type TKPIS = {
figure: string;
figure?: number;
label: string;
}[];

const KPIs: TKPIS = [
{
figure: "15",
label: APP_CONTENT.homepage.kpi.publishedAIModels,
},
{
figure: "120",
label: APP_CONTENT.homepage.kpi.totalUsers,
},
{
figure: "100",
label: APP_CONTENT.homepage.kpi.humanFeedback,
},
{
figure: "15",
label: APP_CONTENT.homepage.kpi.acceptedPrediction,
}
// ,
// {
// figure: "86",
// label: "Mappers",
// },
];
type TKPIResponse = {
total_accepted_predictions: number;
total_feedback_labels: number;
total_models_published: number;
total_registered_users: number;
};

const fetchKPIStats = async (): Promise<TKPIResponse> => {
const { data } = await apiClient.get(API_ENDPOINTS.GET_KPI_STATS);
return data;
};

const Kpi = () => {
const { data, isLoading,isError,error} = useQuery({
queryKey: ["kpis"],
queryFn: fetchKPIStats,
});

if (isError) {
return (
<section className={styles.kpiContainer}>
<div>
<h2>Error fetching KPI Stats</h2>
<p>{(error as Error)?.message || 'An unknown error occurred.'}</p>
</div>
</section>
);
}

const KPIs: TKPIS = [
{
figure: data?.total_models_published ?? 0,
label: APP_CONTENT.homepage.kpi.publishedAIModels,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can add some format for the numbers

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean like 12k, 20k etc @omranlm ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

like 1,546 instead of 1546... no worries, I will do that with other text changes ...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, okay. Thanks!

},
{
figure: data?.total_registered_users ?? 0,
label: APP_CONTENT.homepage.kpi.totalUsers,
},
{
figure: data?.total_feedback_labels ?? 0,
label: APP_CONTENT.homepage.kpi.humanFeedback,
},
{
figure: data?.total_accepted_predictions ?? 0,
label: APP_CONTENT.homepage.kpi.acceptedPrediction,
},
];

return (
<section className={styles.kpiContainer}>
{KPIs.map((kpi, id) => (
<div key={`kpi-${id}`} className={styles.kpiItem}>
<h1>{kpi.figure}</h1>
<h1 className={`${isLoading ? "animate-pulse" : ""}`}>
{kpi.figure}
</h1>
<h3>{kpi.label}</h3>
</div>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ type TrainingDetailsDialogProps = {
isOpened: boolean;
closeDialog: () => void;
trainingId: number;
datasetId:number
datasetId: number;
};

const TrainingDetailsDialog: React.FC<TrainingDetailsDialogProps> = ({
isOpened,
closeDialog,
trainingId,datasetId
trainingId,
datasetId,
}) => {
const isMobile = useDevice();

Expand All @@ -23,7 +24,11 @@ const TrainingDetailsDialog: React.FC<TrainingDetailsDialogProps> = ({
label={`Training ${trainingId}`}
size={isMobile ? "extra-large" : "medium"}
>
<ModelProperties trainingId={trainingId} isTrainingDetailsDialog datasetId={datasetId}/>
<ModelProperties
trainingId={trainingId}
isTrainingDetailsDialog
datasetId={datasetId}
/>
</Dialog>
);
};
Expand Down
7 changes: 2 additions & 5 deletions frontend/src/features/models/components/model-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,11 @@ import { Link } from "@/components/ui/link";
import { truncateString } from "@/utils";
import { roundNumber } from "@/utils/number-utils";


type ModelCardProps = {
model: TModel;
};


const ModelCard: React.FC<ModelCardProps> = ({ model }) => {

return (
<div className="flex items-center w-full">
<Link
Expand All @@ -25,8 +22,8 @@ const ModelCard: React.FC<ModelCardProps> = ({ model }) => {
>
<div className="h-[200px] w-full">
<Image
height='256px'
width='256px'
height="256px"
width="256px"
src={
model.thumbnail_url
? `${model.thumbnail_url}.png`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,8 @@ const ModelProperties: React.FC<ModelPropertiesProps> = ({
source_imagery,
} = data || {};


const trainingResultsGraph = `${ENVS.BASE_API_URL}workspace/download/dataset_${datasetId}/output/training_${data?.id}/graphs/training_validation_sparse_categorical_accuracy.png`

const trainingResultsGraph = `${ENVS.BASE_API_URL}workspace/download/dataset_${datasetId}/output/training_${data?.id}/graphs/training_validation_sparse_categorical_accuracy.png`;

const content = useMemo(() => {
if (isPending) {
return <ModelPropertiesSkeleton isTrainingDetailsDialog />;
Expand Down Expand Up @@ -201,9 +200,11 @@ const ModelProperties: React.FC<ModelPropertiesProps> = ({
isTMS
/>
</div>

<div className={`col-span-3 lg:col-span-2 ${isTrainingDetailsDialog && 'lg:col-span-3'}`}>
<Image src={trainingResultsGraph} alt={""} />

<div
className={`col-span-3 lg:col-span-2 ${isTrainingDetailsDialog && "lg:col-span-3"}`}
>
<Image src={trainingResultsGraph} alt={""} />
</div>
{/* Show logs only in modal and when status failed */}
{isTrainingDetailsDialog && data?.status === TrainingStatus.FAILED && (
Expand All @@ -221,7 +222,7 @@ const ModelProperties: React.FC<ModelPropertiesProps> = ({
input_contact_spacing,
input_boundary_width,
source_imagery,
trainingResultsGraph
trainingResultsGraph,
]);

return isError ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ type TrainingHistoryTableProps = {
modelId: string;
trainingId: number;
modelOwner: string;
datasetId:number
datasetId: number;
};

const columnDefinitions = (
Expand Down Expand Up @@ -226,7 +226,7 @@ const TrainingHistoryTable: React.FC<TrainingHistoryTableProps> = ({
trainingId,
modelId,
modelOwner,
datasetId
datasetId,
}) => {
const [offset, setOffset] = useState(0);
const { data, isPending, isPlaceholderData } = useTrainingHistory(
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/services/api-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ export const API_ENDPOINTS = {
AUTH_CALLBACK: "auth/callback/",
USER: "auth/me/",

//KPIs

GET_KPI_STATS: "kpi/stats/ ",

//Models
GET_MODELS: "model/",
GET_MODEL_DETAILS: (id: string) => `model/${id}`,
Expand Down
14 changes: 8 additions & 6 deletions frontend/src/utils/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@ export const APP_CONTENT = {
ctaSecondaryButton: "Start Mapping",
jumbotronImageAlt: "A user engaging in a mapping activity",
kpi: {
publishedAIModels:"Published AI Models",
totalUsers:"Total Registered Users",
publishedAIModels: "Published AI Models",
totalUsers: "Total Registered Users",
humanFeedback: "Human Feedbacks",
acceptedPrediction: "Accepted Prediction"
acceptedPrediction: "Accepted Prediction",
},
aboutTitle: "WHAT IS fAIr?",
aboutContent: `fAIr is an open AI-assisted mapping service developed by the Humanitarian OpenStreetMap Team (HOT) that aims to improve the efficiency and accuracy of mapping efforts for humanitarian purposes. The service uses AI models, specifically computer vision techniques, to detect objects in satellite and UAV imagery.`,
Expand Down Expand Up @@ -144,7 +144,7 @@ export const APP_CONTENT = {
{
question: "Can I use fAIr without having a sound knowledge of AI?",
answer:
"fAIr is design for users without the need for python or any programming skills. However, basic knowledge in humanitarian mapping and Geographical Information Systems (GIS) would be sufficient for self exploration.",
"fAIr is designed for users without the need for Python or any programming skills. However, basic knowledge in humanitarian mapping and Geographical Information Systems (GIS) would be sufficient for self exploration.",
},
],
},
Expand All @@ -158,7 +158,9 @@ export const APP_CONTENT = {
callToAction: {
title: `We can't do it without you`,
ctaButton: "Join The Community",
paragraph: "fAIr is a collaborative project. We welcome all types of experience to join our community on HOTOSM Slack. There is always a room for AI/ML for earth observation expertise, community engagement enthusiastic, academic researcher or student looking for an academic challenge around social impact."
ctaLink: "https://slack.hotosm.org",
paragraph:
"fAIr is a collaborative project. We welcome all types of experience to join our community on HOTOSM Slack. There is always a room for AI/ML for earth observation expertise, community engagement enthusiastic, academic researcher or student looking for an academic challenge around social impact.",
},
},
pageNotFound: {
Expand Down Expand Up @@ -212,7 +214,7 @@ export const APP_CONTENT = {
},
},
modelsDetailsCard: {
modelId: "Model ID",
modelId: "Model ID:",
detailsSectionTitle: "Details",
createdBy: "Created By",
createdOn: "Created On",
Expand Down
Loading