Skip to content

Commit

Permalink
πŸŽπŸ”οΈ ↝ [SSM-81]: Annotation tool can now take in an imageUrl
Browse files Browse the repository at this point in the history
  • Loading branch information
Gizmotronn committed Jan 2, 2025
1 parent e3f2531 commit 8ef8667
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 104 deletions.
27 changes: 12 additions & 15 deletions components/Projects/(classifications)/Annotating/Annotator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@

import { useRef, useState } from 'react';
import { Button } from '@/components/ui/button';
import { Download, Upload } from 'lucide-react';
import { Download } from 'lucide-react';
import { ImageUploader } from './ImageUploader';
import { DrawingCanvas } from './DrawingCanvas';
import { DrawingControls } from './DrawingControls';
import { downloadAnnotatedImage } from './DrawingUtils';
import type { Point, Line, Shape, DrawingMode } from '@/types/Annotation';
import { useToast } from "@/hooks/toast";

export function ImageAnnotator() {
const [imageUrl, setImageUrl] = useState<string | null>(null);
export function ImageAnnotator({ initialImageUrl }: { initialImageUrl?: string }) {
const [imageUrl, setImageUrl] = useState<string | null>(initialImageUrl || null);
const [isDrawing, setIsDrawing] = useState(false);
const [currentLine, setCurrentLine] = useState<Line>({ points: [], color: '#ff0000', width: 2 });
const [currentShape, setCurrentShape] = useState<Shape | null>(null);
Expand Down Expand Up @@ -104,10 +104,10 @@ export function ImageAnnotator() {
});
return;
}

setIsDownloading(true);
try {
await downloadAnnotatedImage(svgRef.current, imageRef.current);
await downloadAnnotatedImage(svgRef.current, imageRef.current, { returnBlob: true });
toast({
title: "Success",
description: "Image downloaded successfully",
Expand All @@ -121,13 +121,16 @@ export function ImageAnnotator() {
} finally {
setIsDownloading(false);
}
};
};

return (
<div className="flex flex-col items-center gap-4 p-4">
<div className="flex gap-4">
{!initialImageUrl && !imageUrl && (
<ImageUploader onImageUpload={handleImageUpload} />
{imageUrl && (
)}

{imageUrl && (
<>
<Button
variant="outline"
onClick={handleDownload}
Expand All @@ -136,11 +139,6 @@ export function ImageAnnotator() {
<Download className="mr-2 h-4 w-4" />
{isDownloading ? 'Downloading...' : 'Download'}
</Button>
)}
</div>

{imageUrl && (
<>
<DrawingControls
strokeColor={strokeColor}
strokeWidth={strokeWidth}
Expand Down Expand Up @@ -178,10 +176,9 @@ export function ImageAnnotator() {

{!imageUrl && (
<div className="flex flex-col items-center justify-center w-full h-64 border-2 border-dashed rounded-lg bg-gray-50 dark:bg-gray-800">
<Upload className="h-12 w-12 text-gray-400" />
<p className="mt-2 text-sm text-gray-500">Upload an image to begin annotating</p>
</div>
)}
</div>
);
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,7 @@ export const getMousePosition = (
};

export const downloadAnnotatedImage = async (
svgElement: SVGSVGElement,
imageElement: HTMLImageElement
): Promise<void> => {
svgElement: SVGSVGElement, imageElement: HTMLImageElement, p0: { returnBlob: boolean; }): Promise<void> => {
// Create canvas with the correct dimensions
const canvas = document.createElement('canvas');
const width = imageElement.naturalWidth;
Expand Down
156 changes: 70 additions & 86 deletions components/Projects/Auto/AI4Mars.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import React, { useState, useEffect } from "react";
import { useSession, useSupabaseClient } from "@supabase/auth-helpers-react";
import { useActivePlanet } from "@/context/ActivePlanet";
import ClassificationForm from "../(classifications)/PostForm";

import { Anomaly } from "../Zoodex/ClassifyOthersAnimals";
import { ImageAnnotator } from "../(classifications)/Annotating/Annotator";

interface Props {
anomalyid: number | bigint;
};
Expand All @@ -16,6 +17,7 @@ export function StarterAiForMars({ anomalyid }: Props) {

const [part, setPart] = useState(1);
const [line, setLine] = useState(1);

const nextLine = () => setLine(prevLine => prevLine + 1);
const nextPart = () => {
setPart(2);
Expand Down Expand Up @@ -145,135 +147,117 @@ export function StarterAiForMars({ anomalyid }: Props) {
export function AiForMarsProject() {
const supabase = useSupabaseClient();
const session = useSession();

const { activePlanet } = useActivePlanet();

const [anomaly, setAnomaly] = useState<Anomaly | null>(null);
const [showTutorial, setShowTutorial] = useState<boolean>(false);
const [showTutorial, setShowTutorial] = useState(false);
const [imageUrl, setImageUrl] = useState<string | null>(null);
const [loading, setLoading] = useState(true);
const [hasMission20000006, setHasMission20000006] = useState<boolean | null>(null);

const [loading, setLoading] = useState<boolean>(true);
useEffect(() => {
const checkTutorialMission = async () => {
if (!session) return;

const [hasMission20000006, setHasMission20000006] = useState<boolean | null>(null);
try {
const { data: missionData, error: missionError } = await supabase
.from("missions")
.select("id")
.eq("user", session.user.id)
.eq("mission", "20000006")
.limit(1);

if (missionError) {
console.error("Error fetching mission data:", missionError);
setHasMission20000006(false);
return;
}

setHasMission20000006(missionData && missionData.length > 0);
} catch (error) {
console.error("Error checking user mission: ", error);
setHasMission20000006(false);
}
};

checkTutorialMission();
}, [session, supabase]);

// useEffect(() => {
// const checkTutorialMission = async () => {
// if (!session) return;

// try {
// const { data: missionData, error: missionError } = await supabase
// .from('missions')
// .select('id')
// .eq('user', session.user.id)
// .eq('mission', '20000006')
// .limit(1);

// if (missionError) {
// console.error("Error fetching mission data:", missionError);
// setHasMission20000006(false);
// return;
// };

// setHasMission20000006(missionData && missionData.length > 0);
// } catch (error) {
// console.error("Error checking user mission: ", error);
// setHasMission20000006(false);
// };
// };

// checkTutorialMission();
// }, [session, supabase]);

useEffect(() => {
async function fetchAnomaly() {
if (!session) {
setLoading(false);
return;
};
}

try {
const { data: anomalyData, error: anomalyError } = await supabase
.from("anomalies")
.select("*")
.eq("anomalySet", 'automaton-aiForMars')

if (anomalyError) {
throw anomalyError;
};

.eq("anomalySet", "automaton-aiForMars");

if (anomalyError) throw anomalyError;

const randomAnomaly = anomalyData[Math.floor(Math.random() * anomalyData.length)] as Anomaly;
setAnomaly(randomAnomaly);
setImageUrl(`${process.env.NEXT_PUBLIC_SUPABASE_URL}/storage/v1/object/public/telescope/automaton-aiForMars/${randomAnomaly.id}.jpeg`);
setImageUrl(
`${process.env.NEXT_PUBLIC_SUPABASE_URL}/storage/v1/object/public/telescope/automaton-aiForMars/${randomAnomaly.id}.jpeg`
);
} catch (error: any) {
console.error("Error fetching anomaly", error.message);
setAnomaly(null);
} finally {
setLoading(false);
};
};

if (session) { // && hasMission20000006) {
fetchAnomaly();
};
}, [session, hasMission20000006, supabase]);

}
}

fetchAnomaly();
}, [session, supabase]);

if (loading) {
return (
<div>
<p>
Loading...
</p>
<p>Loading...</p>
</div>
);
};
}

if (!anomaly) {
return (
<div>
<p>No anomaly found.</p>
</div>
);
};
}

const startTutorial = () => setShowTutorial(true);

const content = !hasMission20000006
? <StarterAiForMars anomalyid={anomaly?.id || 69592674} />
: (
<>
{loading && <p>Loading...</p>}
{!loading && !anomaly && <p>No anomaly found.</p>}
{!loading && anomaly && (
return (
<div className="flex flex-col items-start gap-4 pb-4 relative w-full max-w-lg overflow-y-auto max-h-[90vh] rounded-lg">
{!hasMission20000006 ? (
<StarterAiForMars anomalyid={anomaly.id || 69592674} />
) : (
<>
<div className="p-4 rounded-md relative w-full">
{imageUrl && <img src={imageUrl} alt="Anomaly" className="w-64 h-64 contained" />}
</div>
{imageUrl && (
<ClassificationForm
anomalyId={anomaly?.id.toString() || ""}
anomalyType='automaton-aiForMars'
missionNumber={200000062}
assetMentioned={imageUrl}
structureItemId={3102}
/>
<>
<ImageAnnotator initialImageUrl={imageUrl} />
<ClassificationForm
anomalyId={anomaly.id.toString()}
anomalyType="automaton-aiForMars"
missionNumber={200000062}
assetMentioned={imageUrl}
structureItemId={3102}
/>
</>
)}
</>
)}
<button
<button
onClick={startTutorial}
className="mt-4 px-4 py-2 bg-[#85DDA2] text-[#2C3A4A] rounded-md shadow-md"
>
Reopen Tutorial
</button>
</>
</>
)}
</div>
);

return (
<div className="flex flex-col items-start gap-4 pb-4 relative w-full max-w-lg overflow-y-auto max-h-[90vh] rounded-lg">
{content}
</div>
);

};

// I did get conflicted between 3102 and 3103, going with 3102 until the satellite comes into play
};

0 comments on commit 8ef8667

Please sign in to comment.