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

Improve labeling #2

Open
wants to merge 26 commits into
base: improve_labeling
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
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
.idea/
data/
dist/
.env/
.ipynb_checkpoints/
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ __pycache__
/data/
/dist/
/.idea/
/node_modules
.env
6 changes: 3 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
FROM python:3.9-slim-bookworm as base
#------------------------------------

RUN apt-get update \
&& apt-get upgrade \
&& rm -rf /var/lib/apt/lists/*
# RUN apt-get update \
# && apt-get upgrade \
# # && rm -rf /var/lib/apt/lists/*

WORKDIR /app/

Expand Down
32 changes: 22 additions & 10 deletions client/src/App.svelte
Original file line number Diff line number Diff line change
@@ -1,23 +1,32 @@
<script lang="ts">
import { Router, Link, Route } from "svelte-routing";
import { onMount } from "svelte";
import { labelStore } from "./lib/stores";
import { descriptionsStore, 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
import SearchText from "./lib/SearchText.svelte";

export let url = "";

onMount(async () => {
console.log("Loading labels...");
const remoteLabels = await api.loadLabels();
labelStore.update((labels: string[]) => [
...new Set([...labels, ...remoteLabels.labels]),
console.log("Loading positive keywords");
const remotePositivekeywords = await api.loadLabels("description");
descriptionsStore.update((labels: string[]) => [
...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 +38,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 +59,10 @@
</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="/search/seller" getProps={getLinkProps}>Seller Search</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 +80,8 @@
location={window.location}
/>
<Route path="/labels" component={LabeledData} />
<Route path="/search/seller" component={SearchText} />
<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
86 changes: 79 additions & 7 deletions client/src/lib/Api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,24 @@ export interface Hits {
hits: Hit[];
}

export type LabelType = "relevant" | "animal" | "description" | "keywords";

export interface Hit {
_distance: number;
image_path: string;
labels?: string[];
title: string;
metadata?: string;
labels_types_dict: {[key: string]: LabelType; };
}


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;
Expand All @@ -28,26 +34,52 @@ export async function similarSearch(imagePath: string, limit: number, excludeLab
"exclude_labeled": excludeLabeled,
limit: limit.toString(),
}).catch((e) => {
console.error(e);
throw new Error("Failed to search for similar images.", { cause: e })
});
return response;
}

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

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;
}

export async function labeled(): Promise<Hits> {
const response = await fetchJSON<Hits>("/labeled", {
}).catch((e) => {
console.error(e);
throw new Error("Failed to retrieve labeled search results.", { cause: e })
});
return response;
}

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 @@ -57,11 +89,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 @@ -71,11 +105,15 @@ 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> {
console.log("api.removeLabel()", image_path, label, table);

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 @@ -90,6 +128,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>
37 changes: 37 additions & 0 deletions client/src/lib/Descriptions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
export const animals = [
"shark","mako","thresher","hammerhead","whaler","dogfish","spurdog","smooth hound","tope", "ray","skate","guitarfish","wedgefish","sawfish","manta","chimaera","ghost shark","spookfish","elephantfish",
];

export const negativeKeywords = [
"Mobile Case",
"Tool",
"Faux leather",
"Crystal",
"Print",
"Appliance",
"Mask",
"Artificial",
"Mock leather",
"Painting",
"PU leather",
"Fake leather",
"Photograph",
"Oil Tank",
"Gem",
"Vinyl",
"wooden",
"Glass",
"Print",
"Toy",
"Pajamas",
"Custom",
"Figurine",
"Plastic",
"T-shirt",
"Resin",
"Photo",
];

export const descriptions = [
"jaw","tooth","teeth","vertebra","fin","head","taxidermy","specimen","wing","barb","rostrum",
];
Loading