Image OCR in transcript tool + side by side
This commit is contained in:
parent
0c1f252641
commit
ca12dc2c29
|
@ -171,6 +171,7 @@ NEXT_PUBLIC_URL_MEILISEARCH=https://url-to.search-accords-library.com
|
||||||
NEXT_PUBLIC_MEILISEARCH_KEY=abcdef0123456789
|
NEXT_PUBLIC_MEILISEARCH_KEY=abcdef0123456789
|
||||||
NEXT_PUBLIC_UMAMI_URL=https://url-to.umami-accords-library.com
|
NEXT_PUBLIC_UMAMI_URL=https://url-to.umami-accords-library.com
|
||||||
NEXT_PUBLIC_UMAMI_ID=abcdef0123456789
|
NEXT_PUBLIC_UMAMI_ID=abcdef0123456789
|
||||||
|
NEXT_PUBLIC_API_OCR_KEY=abcdef0123456789
|
||||||
```
|
```
|
||||||
|
|
||||||
Run in dev mode:
|
Run in dev mode:
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import "@fontsource/noto-serif-jp";
|
import "@fontsource/noto-serif-jp";
|
||||||
import { GetStaticProps } from "next";
|
import { GetStaticProps } from "next";
|
||||||
import { useCallback, useRef, useState } from "react";
|
import { ChangeEvent, useCallback, useRef, useState } from "react";
|
||||||
import { atomWithStorage } from "jotai/utils";
|
import { atomWithStorage } from "jotai/utils";
|
||||||
|
import { TransformComponent, TransformWrapper } from "react-zoom-pan-pinch";
|
||||||
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
||||||
import { Button } from "components/Inputs/Button";
|
import { Button } from "components/Inputs/Button";
|
||||||
import { ButtonGroup } from "components/Inputs/ButtonGroup";
|
import { ButtonGroup } from "components/Inputs/ButtonGroup";
|
||||||
|
@ -10,6 +11,7 @@ import { ToolTip } from "components/ToolTip";
|
||||||
import { getOpenGraph } from "helpers/openGraph";
|
import { getOpenGraph } from "helpers/openGraph";
|
||||||
import { getFormat } from "helpers/i18n";
|
import { getFormat } from "helpers/i18n";
|
||||||
import { atomPairing, useAtomPair } from "helpers/atoms";
|
import { atomPairing, useAtomPair } from "helpers/atoms";
|
||||||
|
import { cIf, cJoin } from "helpers/className";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ╭─────────────╮
|
* ╭─────────────╮
|
||||||
|
@ -366,27 +368,81 @@ const Transcript = (props: Props): JSX.Element => {
|
||||||
[updateDisplayedText]
|
[updateDisplayedText]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const [image, setImage] = useState<string>();
|
||||||
|
|
||||||
|
const onImageUploaded = useCallback(
|
||||||
|
async (event: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const file = event.target.files?.[0];
|
||||||
|
if (file) {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("file", file);
|
||||||
|
formData.append("language", "jpn");
|
||||||
|
formData.append("FileType", ".Auto");
|
||||||
|
formData.append("scale", "true");
|
||||||
|
formData.append("OCREngine", "1");
|
||||||
|
|
||||||
|
type OCRApiResponse = {
|
||||||
|
ParsedResults: {
|
||||||
|
ParsedText: string;
|
||||||
|
}[];
|
||||||
|
OCRExitCode: number;
|
||||||
|
IsErroredOnProcessing: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await fetch("https://api.ocr.space/parse/image", {
|
||||||
|
method: "POST",
|
||||||
|
body: formData,
|
||||||
|
headers: { apiKey: "d35acb001e88957" },
|
||||||
|
});
|
||||||
|
|
||||||
|
const jsonData: OCRApiResponse = await response.json();
|
||||||
|
const ocrText = jsonData.ParsedResults[0]?.ParsedText;
|
||||||
|
|
||||||
|
if (ocrText) {
|
||||||
|
setText(ocrText);
|
||||||
|
}
|
||||||
|
|
||||||
|
setImage(URL.createObjectURL(file));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[setText]
|
||||||
|
);
|
||||||
|
|
||||||
const contentPanel = (
|
const contentPanel = (
|
||||||
<ContentPanel width={ContentPanelWidthSizes.Full} className="overflow-hidden !pr-0 !pt-4">
|
<ContentPanel width={ContentPanelWidthSizes.Full} className="!pr-0 !pt-0">
|
||||||
<div className="grid grid-flow-col grid-cols-[1fr_5rem]">
|
<div
|
||||||
|
className={cJoin("grid", cIf(image, "grid-cols-[1fr_5rem_20rem]", "grid-cols-[1fr_5rem]"))}>
|
||||||
<textarea
|
<textarea
|
||||||
ref={textAreaRef}
|
ref={textAreaRef}
|
||||||
onChange={updateDisplayedText}
|
onChange={updateDisplayedText}
|
||||||
onClick={updateLineIndex}
|
onClick={updateLineIndex}
|
||||||
onKeyUp={updateLineIndex}
|
onKeyUp={updateLineIndex}
|
||||||
title="Input textarea"
|
title="Input textarea"
|
||||||
className="whitespace-pre"
|
className="mt-4 whitespace-pre"
|
||||||
value={text}
|
value={text}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<p
|
<p
|
||||||
className="h-[80vh] whitespace-nowrap font-bold [font-family:Noto_Serif_JP]
|
className="z-10 mt-4 h-[80vh] whitespace-nowrap
|
||||||
[transform-origin:top_right] [writing-mode:vertical-rl]"
|
font-bold [font-family:Noto_Serif_JP] [transform-origin:top_right]
|
||||||
|
[writing-mode:vertical-rl]"
|
||||||
style={{
|
style={{
|
||||||
transform: `scale(${fontSize}) translateX(${fontSize * xOffset}px)`,
|
transform: `scale(${fontSize}) translateX(${fontSize * xOffset}px)`,
|
||||||
}}>
|
}}>
|
||||||
{text.split("\n")[lineIndex]}
|
{text.split("\n")[lineIndex]}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
{image && (
|
||||||
|
<TransformWrapper
|
||||||
|
panning={{ velocityDisabled: true }}
|
||||||
|
alignmentAnimation={{ disabled: true }}
|
||||||
|
wheel={{ step: 0.05 }}
|
||||||
|
limitToBounds={false}>
|
||||||
|
<TransformComponent wrapperStyle={{ height: "95vh" }}>
|
||||||
|
<img src={image} alt="This provided image" className="w-full object-cover" />
|
||||||
|
</TransformComponent>
|
||||||
|
</TransformWrapper>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-wrap place-items-center gap-4 pr-24">
|
<div className="flex flex-wrap place-items-center gap-4 pr-24">
|
||||||
|
@ -397,8 +453,8 @@ const Transcript = (props: Props): JSX.Element => {
|
||||||
type="range"
|
type="range"
|
||||||
min="0"
|
min="0"
|
||||||
max="100"
|
max="100"
|
||||||
value={xOffset * 10}
|
value={xOffset * 5}
|
||||||
onChange={(event) => setXOffset(parseInt(event.target.value, 10) / 10)}
|
onChange={(event) => setXOffset(parseInt(event.target.value, 10) / 5)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -527,6 +583,12 @@ const Transcript = (props: Props): JSX.Element => {
|
||||||
}>
|
}>
|
||||||
<Button text="Insert" />
|
<Button text="Insert" />
|
||||||
</ToolTip>
|
</ToolTip>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
accept="image/png, image/jpeg, image/webp"
|
||||||
|
onChange={onImageUploaded}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</ContentPanel>
|
</ContentPanel>
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue