diff options
author | polwex <polwex@sortug.com> | 2025-05-15 15:50:51 +0700 |
---|---|---|
committer | polwex <polwex@sortug.com> | 2025-05-15 15:50:51 +0700 |
commit | 05d13b6f166eae5c2de8fe6f6038819b1b6ba1a0 (patch) | |
tree | 795ca33a3319d11bd9daa0366d4d15f31eabf024 /src/components/Main.tsx | |
parent | 92139f14a92a535f123ad49a60498138dd2ec6cf (diff) |
m
Diffstat (limited to 'src/components/Main.tsx')
-rw-r--r-- | src/components/Main.tsx | 128 |
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> |