diff --git a/.app.pid b/.app.pid
index b2573f7..41fc841 100644
--- a/.app.pid
+++ b/.app.pid
@@ -1 +1 @@
-95217
+95660
diff --git a/server.ts b/server.ts
index ce399a4..c748a66 100644
--- a/server.ts
+++ b/server.ts
@@ -223,6 +223,105 @@ Extract the following fields accurately and output JSON:
}
});
+// API 2B: Parse Master Resume Text / Document into User Profile
+app.post("/api/gemini/parse-resume", async (req, res) => {
+ try {
+ const { resumeText, llmConfig } = req.body;
+
+ if (!resumeText || typeof resumeText !== 'string' || resumeText.trim().length === 0) {
+ return res.status(400).json({ success: false, error: "Resume text content is required." });
+ }
+
+ const prompt = `Analyze the following resume text and extract all candidate information into structured JSON:
+
+Resume Content:
+${resumeText}
+
+Extract the following fields accurately:
+- fullName: Full Name of candidate
+- email: Email address
+- phone: Phone number
+- location: City, State or location preference
+- linkedinUrl: LinkedIn profile URL if found
+- githubUrl: GitHub profile URL if found
+- portfolioUrl: Personal website/portfolio URL if found
+- summary: Professional summary or objective paragraph
+- skills: Array of technical & soft skills
+- experience: Array of work experience objects, each with:
+ - id: unique string
+ - title: Job title
+ - company: Company name
+ - period: Date range (e.g. 2022 - Present)
+ - bullets: Array of accomplishment bullet points
+- education: Array of education objects, each with:
+ - degree: Degree title
+ - institution: School or University name
+ - year: Graduation year`;
+
+ const schema = {
+ type: Type.OBJECT,
+ properties: {
+ fullName: { type: Type.STRING },
+ email: { type: Type.STRING },
+ phone: { type: Type.STRING },
+ location: { type: Type.STRING },
+ linkedinUrl: { type: Type.STRING },
+ githubUrl: { type: Type.STRING },
+ portfolioUrl: { type: Type.STRING },
+ summary: { type: Type.STRING },
+ skills: {
+ type: Type.ARRAY,
+ items: { type: Type.STRING }
+ },
+ experience: {
+ type: Type.ARRAY,
+ items: {
+ type: Type.OBJECT,
+ properties: {
+ id: { type: Type.STRING },
+ title: { type: Type.STRING },
+ company: { type: Type.STRING },
+ period: { type: Type.STRING },
+ bullets: {
+ type: Type.ARRAY,
+ items: { type: Type.STRING }
+ }
+ }
+ }
+ },
+ education: {
+ type: Type.ARRAY,
+ items: {
+ type: Type.OBJECT,
+ properties: {
+ degree: { type: Type.STRING },
+ institution: { type: Type.STRING },
+ year: { type: Type.STRING }
+ }
+ }
+ }
+ },
+ required: ["fullName", "skills", "experience"]
+ };
+
+ const { text, providerUsed } = await generateTextWithLLMFallback(prompt, schema, llmConfig);
+ const parsedProfile = JSON.parse(text || "{}");
+
+ // Ensure IDs on experience items
+ if (Array.isArray(parsedProfile.experience)) {
+ parsedProfile.experience = parsedProfile.experience.map((exp: any, index: number) => ({
+ ...exp,
+ id: exp.id || `exp_parsed_${Date.now()}_${index}`
+ }));
+ }
+
+ res.json({ success: true, profile: parsedProfile, providerUsed });
+ } catch (error: any) {
+ console.error("Error parsing resume:", error);
+ res.status(500).json({ success: false, error: error.message || "Failed to parse resume" });
+ }
+});
+
// API 3: Tailor Resume & Calculate Match Score
app.post("/api/gemini/tailor-resume", async (req, res) => {
try {
diff --git a/src/components/ProfileSettings.tsx b/src/components/ProfileSettings.tsx
index 302826e..41251e8 100644
--- a/src/components/ProfileSettings.tsx
+++ b/src/components/ProfileSettings.tsx
@@ -99,6 +99,54 @@ export const ProfileSettings: React.FC