Skip to content

Commit aecf3bc

Browse files
authored
feat(185): Add extraction page with part 1 of integration (#231)
* feat(185): Add extraction page with part 1 of integration * feat(185): Add Cors, update shape type feat(185): Add Cors, update shape type * feat(185): Add Cors, update shape type
1 parent 1845c26 commit aecf3bc

15 files changed

+420
-65
lines changed

OCR/frontend/api/api.ts

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { Page } from "../src/contexts/FilesContext";
2+
import { ImageToTextResponse } from "./types/types";
3+
4+
export const AddFormData = async (args: Page): Promise<ImageToTextResponse | null> => {
5+
6+
const { sourceImage, templateImage, fieldNames } = args;
7+
const form = new FormData();
8+
form.append("source_image", sourceImage);
9+
form.append("segmentation_template", templateImage);
10+
form.append("labels", JSON.stringify(fieldNames));
11+
form.append("", "");
12+
console.log(args)
13+
try {
14+
const response = await fetch("http://localhost:8000/image_to_text/", {
15+
"method": "POST",
16+
body: form
17+
})
18+
return await response.json() as ImageToTextResponse;
19+
} catch (error) {
20+
console.error(error);
21+
return null;
22+
}
23+
24+
}

OCR/frontend/api/types/types.ts

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
export interface Label {
2+
color: string;
3+
label: string;
4+
type: string;
5+
}
6+
7+
export type Labels = Label[];
8+
9+
export interface ImageToTextArgs {
10+
fieldNames: Labels;
11+
sourceImage: string;
12+
templateImage: string;
13+
}
14+
15+
export type ImageToTextResponse = {
16+
[key: string]: [string, number];
17+
};
18+
19+
export interface ResultItem {
20+
text: string;
21+
confidence: number;
22+
}
23+
24+
export interface Submission {
25+
template_name: string;
26+
template_image: string; // Base64-encoded image string
27+
file_name: string;
28+
file_image: string; // Base64-encoded image string
29+
results: {
30+
[key: string]: ResultItem; // Allows any key with a ResultItem value
31+
};
32+
}

OCR/frontend/package-lock.json

+24-9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

OCR/frontend/package.json

+3
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@
1616
},
1717
"dependencies": {
1818
"@trussworks/react-uswds": "^9.0.0",
19+
"@types/hex-rgb": "^3.0.0",
20+
"@uswds/uswds": "^3.8.1",
1921
"classnames": "^2.5.1",
2022
"focus-trap-react": "^10.2.3",
23+
"hex-rgb": "^5.0.0",
2124
"html2canvas": "^1.4.1",
2225
"pdfjs-dist": "^4.5.136",
2326
"prop-types": "^15.8.1",

OCR/frontend/src/components/ImageAnnotator.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ export const MultiImageAnnotator: FC<MultiImageAnnotatorProps> = ({ images, cate
3434
const fields = [...LABELS.patientInformation.items, ...LABELS.organizationInformation.items];
3535
const field = fields.find(field => field.name === selectedField?.name);
3636
const updatedShapes = [...shapes];
37-
// todo fix typing but for now this is fine
38-
updatedShapes[index] = [...(updatedShapes[index] || []), {...shape, field: selectedField?.name as string, color: field?.color}];
37+
// for field?.color.slice(0,7) to remove the alpha channel from the hexcode
38+
updatedShapes[index] = [...(updatedShapes[index] || []), {...shape, field: selectedField?.name as string, color: field?.color.slice(0,7)}];
3939
setShapes(updatedShapes);
4040
localStorage.setItem('shapes', JSON.stringify(updatedShapes));
4141
annotator?.updateCategories(shape.id, [], field?.color);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
.loading-wrapper {
2+
position: relative;
3+
}
4+
5+
.loading-overlay {
6+
position: absolute;
7+
top: 0;
8+
left: 0;
9+
width: 100%;
10+
height: 100%;
11+
background-color: rgba(255, 255, 255, 0.8); /* Semi-transparent white */
12+
display: flex;
13+
flex-direction: column;
14+
justify-content: center;
15+
align-items: center;
16+
z-index: 10;
17+
}
18+
19+
.loading-spinner {
20+
border: 8px solid rgba(0, 0, 0, 0.1);
21+
border-left-color: #000;
22+
border-radius: 50%;
23+
width: 50px;
24+
height: 50px;
25+
animation: spin 1s linear infinite;
26+
}
27+
28+
@keyframes spin {
29+
0% {
30+
transform: rotate(0deg);
31+
}
32+
100% {
33+
transform: rotate(360deg);
34+
}
35+
}
36+
37+
.loading-text {
38+
text-align: center;
39+
margin-top: 20px;
40+
color: #333; /* Color for the text */
41+
}
42+
43+
.loading-text h2 {
44+
font-size: 24px;
45+
margin-bottom: 10px;
46+
}
47+
48+
.loading-text p {
49+
font-size: 16px;
50+
color: #666; /* Lighter color for subtitle */
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React from 'react';
2+
import './LoadingWrapper.scss'; // You'll define some styles here
3+
4+
interface LoadingWrapperProps {
5+
isLoading: boolean;
6+
children: React.ReactNode;
7+
title?: string;
8+
subtitle?: string;
9+
}
10+
11+
const LoadingWrapper: React.FC<LoadingWrapperProps> = ({
12+
isLoading,
13+
children,
14+
title = 'Loading',
15+
subtitle = 'Please wait a moment...',
16+
}) => {
17+
return (
18+
<div className="loading-wrapper">
19+
{children}
20+
{isLoading && (
21+
<div className="loading-overlay">
22+
<div className="loading-spinner"></div>
23+
<div className="loading-text">
24+
<h2>{title}</h2>
25+
<p>{subtitle}</p>
26+
</div>
27+
</div>
28+
)}
29+
</div>
30+
);
31+
};
32+
33+
export default LoadingWrapper;

OCR/frontend/src/contexts/AnnotationContext.tsx

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
import { createContext, useState, useContext, ReactNode } from 'react';
2-
import { Shape, useImageAnnotator } from 'react-image-label';
2+
import { useImageAnnotator } from 'react-image-label';
33

4-
interface CustomShape extends Shape {
5-
field: string;
4+
export interface Shape {
5+
categories: string[];
6+
phi: number;
7+
color?: string | undefined;
8+
id: number;
9+
}
10+
11+
export interface CustomShape extends Shape {
12+
field: string;
613
}
714

815
interface Field {

OCR/frontend/src/contexts/FilesContext.tsx

+16-7
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,39 @@
11
import { createContext, useContext, useState, ReactNode } from 'react';
2+
import { Shape } from './AnnotationContext';
3+
4+
export interface Field {
5+
color: string;
6+
label: string;
7+
type: string;
8+
}
29

310
export interface Page {
411
// base 64 encoded image
5-
image: string ;
6-
fieldNames: string[];
12+
sourceImage: string;
13+
templateImage: string;
14+
fieldNames: Field[];
15+
shapes: Shape[];
716
}
817

9-
export interface File {
18+
export interface FileType {
1019
name: string;
1120
description: string;
1221
pages: Page[];
1322
}
1423

1524
interface FileContextType {
16-
files: File[];
17-
addFile: (file: File) => void;
25+
files: FileType[];
26+
addFile: (file: FileType) => void;
1827
removeFile: (fileName: string) => void;
1928
clearFiles: () => void;
2029
}
2130

2231
const FilesContext = createContext<FileContextType | undefined>(undefined);
2332

2433
export const FilesProvider = ({ children }: { children: ReactNode }) => {
25-
const [files, setFiles] = useState<File[]>([]);
34+
const [files, setFiles] = useState<FileType[]>([]);
2635

27-
const addFile = (file: File) => {
36+
const addFile = (file: FileType) => {
2837
setFiles(() => [file]);
2938
};
3039

OCR/frontend/src/pages/AnnotateTemplate.tsx

+5-4
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ const AnnotateTemplate: React.FC = () => {
3838
setFields,
3939
fields,
4040
setAnnotatedImages,
41-
annotatedImages,
4241
index,
4342
setIndex,
4443
} = useAnnotationContext();
@@ -97,9 +96,10 @@ const AnnotateTemplate: React.FC = () => {
9796
className="display-flex flex-justify space-between flex-align-center padding-y-1 label-container margin-0"
9897
onClick={() => {
9998
setSelectedField({
100-
name: item.name,
101-
id: String(idx + 1),
102-
color: item.color,
99+
100+
name: item.name,
101+
id: String(idx + 1),
102+
color: item.color.slice(0, 7),
103103
});
104104
let tempFields = [...fields];
105105
if (fields.length === 0) {
@@ -143,6 +143,7 @@ const AnnotateTemplate: React.FC = () => {
143143
);
144144

145145
const handleSubmit = async () => {
146+
annotator!.stop();
146147
const delay = (ms: number) =>
147148
new Promise((resolve) => setTimeout(resolve, ms));
148149

0 commit comments

Comments
 (0)