Skip to content

Commit

Permalink
feature: OCR capabilities (#210)
Browse files Browse the repository at this point in the history
* chore: changed text extraction into API

* feature: working OCR capabilities
  • Loading branch information
EdmelKun authored Nov 30, 2023
1 parent 545f67d commit 9657e6b
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 21 deletions.
1 change: 1 addition & 0 deletions apps/expo/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const defineConfig = (_ctx: ConfigContext): ExpoConfig => ({
foregroundImage: "./assets/icon.png",
backgroundColor: "#fff",
},
permissions: ["READ_EXTERNAL_STORAGE", "WRITE_EXTERNAL_STORAGE"],
},
extra: {
eas: {
Expand Down
119 changes: 111 additions & 8 deletions apps/expo/src/screens/create-reviewer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,19 @@ import { NUMBER_OF_QUESTIONS_OPTIONS } from "./constants";
import useQuestionStore, { QuestionType } from "../../stores/useQuestionStore";
import { AppButton } from "../../components/buttons/AppButton";
import * as DocumentPicker from "expo-document-picker";
import * as FileSystem from "expo-file-system";
import { mapQuestionType } from "../../utils/helpers/strings";

interface CacheOptions {
name: string;
uri: string;
}

interface FilePickerType {
fileType: string;
base64ContentType: string;
}

export const CreateReviewerScreen = ({
navigation,
route,
Expand Down Expand Up @@ -73,6 +84,8 @@ export const CreateReviewerScreen = ({
);
const [isHighlighterToggled, setIsHighlighterToggled] = useState(false);
const [isChoiceModalToggled, setIsChoiceModalToggled] = useState(false);
const [isPDFUploading, setIsPDFUploading] = useState(false);
const [isImageUploading, setIsImageUploading] = useState(false);
const [openAlert, setOpenAlert] = useState(false);
const [numberOfQuestionOptions, setNumberOfQuestionOptions] = useState<
Option[]
Expand Down Expand Up @@ -101,6 +114,8 @@ export const CreateReviewerScreen = ({
},
);

const { mutate: readFile } = trpc.pdfTextExtraction.extractText.useMutation();

const { mutate: generateMultipleQuestions, isLoading: isGenerating } =
trpc.gptApi.generateMultipleQuestions.useMutation();

Expand Down Expand Up @@ -201,14 +216,79 @@ export const CreateReviewerScreen = ({
});
}, [reviewerImage]);

const filePicker = async () => {
const createCacheFile = async ({ name, uri }: CacheOptions) => {
if (
!(await FileSystem.getInfoAsync(FileSystem.cacheDirectory + "uploads/"))
.exists
) {
await FileSystem.makeDirectoryAsync(
FileSystem.cacheDirectory + "uploads/",
);
}
const cacheFilePath = FileSystem.cacheDirectory + "uploads/" + name;
await FileSystem.copyAsync({ from: uri, to: cacheFilePath });
return cacheFilePath;
};

const filePicker = async ({
fileType,
base64ContentType,
}: FilePickerType) => {
const result = await DocumentPicker.getDocumentAsync({
type: "application/pdf",
copyToCacheDirectory: true,
type: fileType,
copyToCacheDirectory: false,
multiple: false,
});

if (result.type === "success") {
console.log(result.uri);
if (result.type !== "cancel") {
if (fileType === "image/*") {
setIsImageUploading(true);
} else {
setIsPDFUploading(true);
}

const convertedFile = await createCacheFile({
name: result.name,
uri: result.uri,
});

const base64 = await FileSystem.readAsStringAsync(convertedFile, {
encoding: "base64",
});

if (base64) {
const formatBase64 = `data:${base64ContentType};base64,${base64}`;
readFile(
{
file: formatBase64,
fileType: `${fileType === "image/*" ? "JPG" : "PDF"}`,
},
{
onSuccess: (data) => {
if (richText.current) {
richText.current.insertHTML(data.text);
}
successToast({
title: "Success",
message: `${
fileType === "image/*" ? "Image" : "File"
} transcribed successfully`,
});

setIsImageUploading(false);
setIsPDFUploading(false);
},
onError: (error) => {
errorToast({
title: "Error",
message: error.message,
});
setIsImageUploading(false);
setIsPDFUploading(false);
},
},
);
}
}
};

Expand Down Expand Up @@ -569,17 +649,40 @@ export const CreateReviewerScreen = ({
name="content"
/>
</View>
<View>
<View className="w-[90%] flex-row justify-around self-center">
<AppButton
text="Upload PDF"
buttonColor="violet-600"
borderShadowColor="indigo-800"
borderRadius="full"
fontStyle="bold"
textColor="white"
TOwidth="36"
Vwidth="36"
isLoading={isPDFUploading}
onPress={() =>
filePicker({
fileType: "application/pdf",
base64ContentType: "application/pdf",
})
}
/>
<AppButton
text="Upload PDF file"
text="Upload Image"
buttonColor="violet-600"
borderShadowColor="indigo-800"
borderRadius="full"
fontStyle="bold"
textColor="white"
TOwidth="36"
Vwidth="36"
onPress={filePicker}
isLoading={isImageUploading}
onPress={() =>
filePicker({
fileType: "image/*",
base64ContentType: "image/jpg",
})
}
/>
</View>
</ScrollView>
Expand Down
34 changes: 30 additions & 4 deletions packages/api/src/router/pdfTextExtraction.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,45 @@
import { router, protectedProcedure } from "../trpc";
import { z } from "zod";
import { readPDFFile } from "../services/pdfTextExtractor";

type OCRResult = {
text: string;
};

export const textExtractionRouter = router({
extractText: protectedProcedure
.input(
z.object({
file: z.string(),
fileType: z.string(),
}),
)
.mutation(async ({ input }) => {
const { file } = input;
const { file, fileType } = input;

const apiKey = process.env.OCR_API;
const apiEndpoint = "https://api.ocr.space/parse/image";

const formData = new FormData();
formData.append("base64image", file);
formData.append("filetype", fileType);
if (apiKey) {
formData.append("apikey", apiKey);
}

const response = await fetch(apiEndpoint, {
method: "POST",
body: formData,
});

if (!response.ok) {
throw new Error("OCR request failed");
}

const content = await readPDFFile(file);
const data = await response.json();
const ocrResult: OCRResult = {
text: data.ParsedResults?.[0]?.ParsedText || "",
};

return content;
return ocrResult;
}),
});
9 changes: 0 additions & 9 deletions packages/api/src/services/pdfTextExtractor.ts

This file was deleted.

1 comment on commit 9657e6b

@vercel
Copy link

@vercel vercel bot commented on 9657e6b Nov 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

test-trek-backend – ./apps/nextjs

test-trek-backend-dadili-test-trek.vercel.app
test-trek-backend.vercel.app
test-trek-backend-git-main-dadili-test-trek.vercel.app

Please sign in to comment.