summaryrefslogtreecommitdiff
path: root/src/components/Main.tsx
diff options
context:
space:
mode:
authorpolwex <polwex@sortug.com>2025-05-15 15:50:51 +0700
committerpolwex <polwex@sortug.com>2025-05-15 15:50:51 +0700
commit05d13b6f166eae5c2de8fe6f6038819b1b6ba1a0 (patch)
tree795ca33a3319d11bd9daa0366d4d15f31eabf024 /src/components/Main.tsx
parent92139f14a92a535f123ad49a60498138dd2ec6cf (diff)
m
Diffstat (limited to 'src/components/Main.tsx')
-rw-r--r--src/components/Main.tsx128
1 files changed, 58 insertions, 70 deletions
diff --git a/src/components/Main.tsx b/src/components/Main.tsx
index fc587e2..2157a91 100644
--- a/src/components/Main.tsx
+++ b/src/components/Main.tsx
@@ -24,10 +24,8 @@ const SorlangPage: React.FC = () => {
const [textValue, setTextValue] = useState<string>("");
const [pastedImageUrl, setPastedImageUrl] = useState<string | null>(null);
const [pastedImageFile, setPastedImageFile] = useState<File | null>(null); // Store the file for extraction
+ const [isAnalyzing, setIsAnalyzing] = useState<boolean>(false);
const [isExtracting, setIsExtracting] = useState<boolean>(false);
- const [extractedTextResult, setExtractedTextResult] = useState<string | null>(
- null,
- );
const textareaRef = useRef<HTMLTextAreaElement>(null);
@@ -41,15 +39,13 @@ const SorlangPage: React.FC = () => {
}, [pastedImageUrl]);
const handlePaste = useCallback(
- (event: React.ClipboardEvent<HTMLTextAreaElement>) => {
+ (event: ClipboardEvent) => {
const items = event.clipboardData?.items;
console.log({ items });
if (!items) return;
let imageFound = false;
- for (let i = 0; i < items.length; i++) {
- const item = items[i];
- if (!item) return;
+ for (const item of items) {
if (item.kind === "file" && item.type.startsWith("image/")) {
event.preventDefault(); // Prevent pasting image data as text
const file = item.getAsFile();
@@ -60,90 +56,85 @@ const SorlangPage: React.FC = () => {
const newImageUrl = URL.createObjectURL(file);
setPastedImageUrl(newImageUrl);
setPastedImageFile(file);
- setTextValue(""); // Clear textarea when image is pasted, or decide on desired behavior
- setExtractedTextResult(null); // Clear previous extraction results
imageFound = true;
}
break; // Handle first image found
}
}
- // If no image was found, let the default text paste happen
- // Or, if you want to explicitly handle text paste:
- if (!imageFound) {
- // Let the default textarea paste handle it, or:
- // event.preventDefault();
- // const text = event.clipboardData.getData('text/plain');
- // setTextValue(prev => prev + text); // Or replace, depending on desired behavior
- // setPastedImageUrl(null); // Clear image if text is pasted
- // setPastedImageFile(null);
- }
+ // // If no image was found, let the default text paste happen
+ // // Or, if you want to explicitly handle text paste:
+ // if (!imageFound) {
+ // // Let the default textarea paste handle it, or:
+ // // event.preventDefault();
+ // // const text = event.clipboardData.getData('text/plain');
+ // // setTextValue(prev => prev + text); // Or replace, depending on desired behavior
+ // // setPastedImageUrl(null); // Clear image if text is pasted
+ // // setPastedImageFile(null);
+ // }
},
[pastedImageUrl],
);
+ useEffect(() => {
+ window.addEventListener("paste", handlePaste);
+ return () => {
+ window.removeEventListener("paste", handlePaste);
+ };
+ }, [handlePaste]);
- const handleProcessText = () => {
- if (!textValue.trim()) {
+ const handleProcessText = async () => {
+ setIsAnalyzing(true);
+ const text = textValue.trim();
+ if (!text) {
alert("Text area is empty!");
return;
}
- console.log("Processing text:", textValue);
- // Add your text processing logic here
- alert(
- `Text submitted: "${textValue.substring(0, 50)}${textValue.length > 50 ? "..." : ""}"`,
- );
+ const opts = {
+ method: "POST",
+ headers: { "Content-type": "application/json" },
+ body: JSON.stringify({ text, app: "spacy" }),
+ };
+ const res = await fetch("/api/nlp", opts);
+ const j = await res.json();
+ console.log("j", j);
+ if ("ok" in j) {
+ console.log("good");
+ }
+ setIsAnalyzing(false);
};
- const [isPending, startTransition] = useTransition();
- const onClick = () => {
- startTransition(async () => {
- const lol = "lmao";
- });
- };
+ // const [isPending, startTransition] = useTransition();
const handleExtractTextFromImage = async () => {
if (!pastedImageFile) {
alert("No image to extract text from!");
return;
}
setIsExtracting(true);
- setExtractedTextResult(null);
+ const formData = new FormData();
+ formData.append("file", pastedImageFile, pastedImageFile.name);
console.log("Extracting text from image:", pastedImageFile.name);
-
- // --- SIMULATE OCR API CALL ---
- // In a real app, you would send `pastedImageFile` to a backend
- // or use a client-side OCR library like Tesseract.js
- await new Promise((resolve) => setTimeout(resolve, 2000)); // Simulate network delay
-
- // Example: Simulate successful extraction
- const mockExtractedText = `This is simulated extracted text from "${pastedImageFile.name}".\nIt could be multiple lines.`;
-
- // Example: Simulate an error
- // const mockExtractedText = null;
- // alert("Failed to extract text (simulated).");
-
- if (mockExtractedText) {
- setTextValue(mockExtractedText); // Put extracted text into the textarea
- setExtractedTextResult(
- `Successfully extracted text and placed it in the textarea.`,
- );
- } else {
- setExtractedTextResult("Failed to extract text (simulated).");
+ const res = await fetch("/api/formdata/ocr", {
+ method: "POST",
+ body: formData,
+ });
+ const j = await res.json();
+ console.log("ocr res", j);
+ if ("ok" in j) {
+ setTextValue((t) => t + j.ok.join("\n"));
}
- // --- END SIMULATION ---
-
setIsExtracting(false);
- // Optionally clear the image after attempting extraction
- // setPastedImageUrl(null);
- // setPastedImageFile(null);
+ // handleClearImage();
};
+ // setPastedImageUrl(null);
+ // setPastedImageFile(null);
+
const handleClearImage = () => {
if (pastedImageUrl) {
URL.revokeObjectURL(pastedImageUrl);
}
setPastedImageUrl(null);
setPastedImageFile(null);
- setExtractedTextResult(null);
};
return (
@@ -159,9 +150,8 @@ const SorlangPage: React.FC = () => {
ref={textareaRef}
value={textValue}
onChange={(e) => setTextValue(e.target.value)}
- onPaste={handlePaste}
placeholder="Paste text here, or paste an image..."
- className="min-h-[200px] text-base"
+ className="min-h-[200px] w-full text-base"
aria-label="Input text area"
/>
@@ -185,14 +175,6 @@ const SorlangPage: React.FC = () => {
/>
</div>
)}
-
- {extractedTextResult && (
- <p
- className={`mt-2 text-sm ${extractedTextResult.startsWith("Failed") ? "text-destructive" : "text-green-600"}`}
- >
- {extractedTextResult}
- </p>
- )}
</CardContent>
<CardFooter className="flex flex-col sm:flex-row justify-center gap-4">
{pastedImageUrl ? (
@@ -212,7 +194,13 @@ const SorlangPage: React.FC = () => {
</Button>
) : (
<Button onClick={handleProcessText} className="w-full sm:w-auto">
- Process Text
+ {isAnalyzing ? (
+ <>
+ <Loader2 className="mr-2 h-4 w-4 animate-spin" /> Analyzing...
+ </>
+ ) : (
+ "Process Text"
+ )}
</Button>
)}
</CardFooter>