mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-07-20 15:05:48 +10:00
fix: resolve multi-page PDF crashes and Gemini API ingestion errors (#2781)
* fix: resolve multi-page PDF crashes and Gemini API ingestion errors * fix type errors * refactor: address PR review feedback and prevent call stack recursion in regex payload scanner --------- Co-authored-by: Ofir <ofir@example.com> Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
This commit is contained in:
@@ -3,6 +3,7 @@ import { t } from "@lingui/core/macro";
|
||||
import { Trans } from "@lingui/react/macro";
|
||||
import { DownloadSimpleIcon, FileIcon, UploadSimpleIcon } from "@phosphor-icons/react";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { useNavigate } from "@tanstack/react-router";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useForm, useWatch } from "react-hook-form";
|
||||
import { toast } from "sonner";
|
||||
@@ -63,7 +64,21 @@ const formSchema = z.discriminatedUnion("type", [
|
||||
|
||||
type FormValues = z.infer<typeof formSchema>;
|
||||
|
||||
function fileToBase64(file: File): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
const result = reader.result as string;
|
||||
// remove data URL prefix (e.g., "data:application/pdf;base64," or "data:application/vnd...;base64,")
|
||||
resolve(result.split(",")[1]);
|
||||
};
|
||||
reader.onerror = reject;
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
|
||||
export function ImportResumeDialog(_: DialogProps<"resume.import">) {
|
||||
const navigate = useNavigate();
|
||||
const { enabled: isAIEnabled, provider, model, apiKey, baseURL } = useAIStore();
|
||||
const closeDialog = useDialogStore((state) => state.closeDialog);
|
||||
|
||||
@@ -135,8 +150,8 @@ export function ImportResumeDialog(_: DialogProps<"resume.import">) {
|
||||
if (!isAIEnabled)
|
||||
throw new Error(t`This feature requires AI Integration to be enabled. Please enable it in the settings.`);
|
||||
|
||||
const arrayBuffer = await values.file.arrayBuffer();
|
||||
const base64 = btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)));
|
||||
// const arrayBuffer = await values.file.arrayBuffer();
|
||||
const base64 = await fileToBase64(values.file);
|
||||
|
||||
data = await client.ai.parsePdf({
|
||||
provider,
|
||||
@@ -151,8 +166,9 @@ export function ImportResumeDialog(_: DialogProps<"resume.import">) {
|
||||
if (!isAIEnabled)
|
||||
throw new Error(t`This feature requires AI Integration to be enabled. Please enable it in the settings.`);
|
||||
|
||||
const arrayBuffer = await values.file.arrayBuffer();
|
||||
const base64 = btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)));
|
||||
// const arrayBuffer = await values.file.arrayBuffer();
|
||||
const base64 = await fileToBase64(values.file);
|
||||
|
||||
const mediaType =
|
||||
values.file.type === "application/msword"
|
||||
? ("application/msword" as const)
|
||||
@@ -170,9 +186,10 @@ export function ImportResumeDialog(_: DialogProps<"resume.import">) {
|
||||
|
||||
if (!data) throw new Error("No data was returned from the AI provider.");
|
||||
|
||||
await importResume({ data });
|
||||
const id = await importResume({ data });
|
||||
toast.success(t`Your resume has been imported successfully.`, { id: toastId, description: null });
|
||||
closeDialog();
|
||||
navigate({ to: `/builder/$resumeId`, params: { resumeId: id } });
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
toast.error(error.message, { id: toastId, description: null });
|
||||
|
||||
Reference in New Issue
Block a user