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

wildlife labeling #1

Open
wants to merge 9 commits into
base: minio_component
Choose a base branch
from
Open
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
27 changes: 18 additions & 9 deletions client/src/App.svelte
Original file line number Diff line number Diff line change
@@ -1,23 +1,31 @@
<script lang="ts">
import { Router, Link, Route } from "svelte-routing";
import { onMount } from "svelte";
import { labelStore } from "./lib/stores";
import { labelStore, negativeKeywordStore } from "./lib/stores";
import * as api from "./lib/Api";
import BootstrapComponents from "./BootstrapComponents.svelte";
import Search from "./lib/Search.svelte";
import Random from "./lib/Random.svelte";
import ImageSearch from "./lib/ImageSearch.svelte";
import LabeledData from "./lib/LabeledData.svelte";
import CSVLoader from "./lib/CSVLoader.svelte"; // Import the CSV Loader component

export let url = "";

onMount(async () => {
console.log("Loading labels...");
const remoteLabels = await api.loadLabels();
console.log("Loading positive keywords");
const remotePositivekeywords = await api.loadLabels("description");
labelStore.update((labels: string[]) => [
...new Set([...labels, ...remoteLabels.labels]),
...new Set([...labels, ...remotePositivekeywords.labels]),
]);
console.log("Labels loaded: ", remoteLabels);

console.log("Loading negative keywords");
const remoteNegativekeywords= await api.loadLabels("keywords");
negativeKeywordStore.update((labels: string[]) => [
...new Set([...labels, ...remoteNegativekeywords.labels]),
]);

console.log("Labels loaded");
});

function getLinkProps(args: Object): Object {
Expand All @@ -29,13 +37,14 @@
const isActive = href === "/" ? isCurrent : isPartiallyCurrent || isCurrent;
return isActive ? { class: "nav-link active" } : { class: "nav-link" };
}

</script>

<main>
<Router {url}>
<nav class="navbar navbar-expand-lg sticky-top">
<div class="container-fluid">
<Link class="navbar-brand fw-bold" to="/">MMDX</Link>
<Link class="navbar-brand fw-bold" to="/csv-loader">MMDX</Link>
<button
class="navbar-toggler"
type="button"
Expand All @@ -49,10 +58,9 @@
</button>
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
<div class="navbar-nav nav-underline">
<Link to="/csv-loader" getProps={getLinkProps}>Load CSV File</Link>
<Link to="/" getProps={getLinkProps}>Keyword Search</Link>
<Link to="/search/random" getProps={getLinkProps}
>Random Search</Link
>
<Link to="/search/random" getProps={getLinkProps}>Random Search</Link>
<Link to="/search/image" getProps={getLinkProps}>Image Search</Link>
<Link to="/labels" getProps={getLinkProps}>Labels</Link>
<!-- <Link to="/bootstrap" getProps={getLinkProps}>Bootstrap</Link> -->
Expand All @@ -70,6 +78,7 @@
location={window.location}
/>
<Route path="/labels" component={LabeledData} />
<Route path="/csv-loader" component={CSVLoader} /> <!-- Add the route for CSV Loader -->
<Route path="/bootstrap" component={BootstrapComponents} />
</div>
</Router>
Expand Down
15 changes: 15 additions & 0 deletions client/src/BootstrapComponents.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,27 @@
<a id="alerts" class="ht-anchor">Main Buttons</a>
<h5 class="mt-4 mb-3">Main Buttons</h5>


<div class="row mt-3">

<div class="col">
<a href="#!" class="btn btn-primary">Default Button</a>
<a href="#!" class="btn btn-outline-primary">Outline Button</a>
<a href="#!" class="btn btn-secondary">Default Button</a>
<a href="#!" class="btn btn-outline-secondary">Outline Button</a>
<button type="button" class="btn btn-primary position-relative">
Profile
<span class="position-absolute top-0 start-100 translate-middle p-2 bg-danger border border-light rounded-circle">
<span class="visually-hidden">New alerts</span>
</span>
</button>
<span class="badge rounded-pill bg-secondary me-1 mt-2 ">
<!-- style="background-color: {colors[idx]} !important;" -->
label
<span class="position-absolute top-0 start-100 translate-middle p-2 bg-danger border border-light rounded-circle">
<span class="visually-hidden">Remove label</span>
</span>
</span>
</div>
</div>

Expand Down
69 changes: 61 additions & 8 deletions client/src/lib/Api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,35 @@ export interface Hit {
_distance: number;
image_path: string;
title: string;
relevant: string;
labels?: string[];
animal?: string;
description?: string[];
keywords?: string[];
metadata?: string;
labels_types_dict?: {[key: string]: string; };
}

export async function keywordSearch(queryStr: string, limit: number): Promise<Hits> {

export async function keywordSearch(queryStr: string, limit: number, excludeLabeled: boolean): Promise<Hits> {
const response = await fetchJSON<Hits>("/keyword_search", {
"q": queryStr,
"exclude_labeled": excludeLabeled,
limit: limit.toString(),
}).catch((e) => {
console.error(e);
throw new Error("Failed to retrieve keyword search results.", { cause: e })
});
return response;
}

export async function similarSearch(imagePath: string, limit: number): Promise<Hits> {
export async function similarSearch(imagePath: string, limit: number, excludeLabeled: boolean): Promise<Hits> {
const response = await fetchJSON<Hits>("/image_search", {
"q": imagePath,
"exclude_labeled": excludeLabeled,
limit: limit.toString(),
}).catch((e) => {
console.error(e);
throw new Error("Failed to search for similar images.", { cause: e })
});
return response;
Expand All @@ -36,6 +47,7 @@ export async function random(limit: number): Promise<Hits> {
const response = await fetchJSON<Hits>("/random", {
limit: limit.toString(),
}).catch((e) => {
console.error(e);
throw new Error("Failed to retrieve random search results.", { cause: e })
});
return response;
Expand All @@ -45,8 +57,11 @@ interface LabelsResponse {
labels: string[];
}

export async function loadLabels(): Promise<LabelsResponse> {
const response = await fetchJSON<LabelsResponse>("/labels").catch((e) => {
export async function loadLabels(table: string): Promise<LabelsResponse> {
const response = await fetchJSON<LabelsResponse>("/labels", {
table
}).catch((e) => {
console.error(e);
throw new Error("Failed to load labels.", { cause: e })
});
return response;
Expand All @@ -56,11 +71,13 @@ interface AddLabelResponse {
success: boolean;
}

export async function addLabel(image_path: string, label: string): Promise<AddLabelResponse> {
export async function addLabel(image_path: string, label: string, table: string): Promise<AddLabelResponse> {
const response = await fetchJSON<AddLabelResponse>("/add_label", {
image_path,
label
label,
table
}).catch((e) => {
console.error(e);
throw new Error("Failed to save label.", { cause: e })
});
return response;
Expand All @@ -70,11 +87,13 @@ interface RemoveLabelResponse {
success: boolean;
}

export async function removeLabel(image_path: string, label: string): Promise<RemoveLabelResponse> {
export async function removeLabel(image_path: string, label: string, table: string): Promise<RemoveLabelResponse> {
const response = await fetchJSON<RemoveLabelResponse>("/remove_label", {
image_path,
label
label,
table
}).catch((e) => {
console.error(e);
throw new Error("Failed to remove label.", { cause: e })
});
return response;
Expand All @@ -89,6 +108,40 @@ export function downloadFile() {
document.body.removeChild(link);
}

export async function loadCSV(csv: any) {
const url = `${API_URL}/load/csv_data`;
let responseMessage = ''

try {
// Create a Blob with the CSV data and specify the line endings
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });

// Create FormData and append the Blob
const formData = new FormData();
formData.append('file', blob, 'filename.csv');

// Send the FormData using fetch
const response = await fetch(url, {
method: 'POST',
body: formData,
});

if (response.ok) {
const responseData = await response.json();
responseMessage = 'CSV data loaded successfully';
console.log('CSV data loaded successfully:', responseData);
} else {
responseMessage = 'Failed to load CSV data';
console.error('Failed to load CSV data:', response.statusText);
}
} catch (error) {
responseMessage = 'Error loading CSV data';
console.error('Error loading CSV data:', error);
}
return responseMessage;
}



export interface LabelCountsResponse {
counts: { [index: string]: number };
Expand Down
59 changes: 59 additions & 0 deletions client/src/lib/CSVLoader.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<script>
import * as api from "./Api";

export let dataToCSV = [];
let prevDataToCSV;

export let allowedFileExtensions = ["csv"];

let maxFileSize = 31457280;

// this is the variable that the file gets bound to
let uploader;

let uploading = false; // Add a variable to track the uploading state
let responseMessage = "";

async function uploadFile(event) {
event.preventDefault();
const file = uploader.files[0];
uploading = true; // Set uploading state to true
await onUpload(file);
uploading = false; // Reset uploading state
}

async function onUpload(file) {
try {
responseMessage = await api.loadCSV(file);
} catch (error) {
responseMessage = `Error loading CSV data: ${error.message}`;
}
}
</script>

<div class="container">
<div class="py-4">
<h1>Load CSV data</h1>
<p>Select a CSV file</p>
<input bind:this={uploader} type="file" class="form-control" style="max-width:400px"/>
<div class="pt-2">
<button class="btn btn-primary" on:click={uploadFile} >
<span class="fa fa-download mr-2" type="file" />
Load CSV
</button>
</div>

<div class="mt-2">
{#if uploading}
<span>
<i class="fa fa-spinner fa-spin" aria-hidden="true" />
Loading...
</span>
{:else if responseMessage}
<div>
<p>{responseMessage}</p>
</div>
{/if}
</div>
</div>
</div>
Loading