File size: 5,326 Bytes
dca8ede
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import type { Resume, Experience, Education } from "@/types/resume"

interface ParsedResume {
  name: string
  email: string
  phone: string
  location: string
  title: string
  summary: string
  skills: string[]
  experience: Experience[]
  education: string[]
  educationDetails: Education[]
  certifications: string[]
  languages: string[]
  experienceLevel: string
}

/**
 * Parses resume text using DeepSeek LLM
 */
export async function parseResumeWithLLM(resumeText: string): Promise<ParsedResume> {
  try {
    const apiKey = process.env.DEEPSEEK_API_KEY || "sk-02f34bd0ea4849e8a4232bc656e28727"
    const apiUrl = "https://api.deepseek.com/v1/chat/completions"

    const prompt = `
      You are an expert resume parser. Extract the following information from the resume text below:
      
      1. Full Name
      2. Email Address (primary)
      3. Phone Number (primary)
      4. Location/Address
      5. Current Job Title
      6. Professional Summary
      7. Skills (as a list)
      8. Work Experience (for each position: title, company, duration, and description)
      9. Education (list of degrees/qualifications)
      10. Education Details (for each institution: degree, institution name, and graduation year)
      11. Certifications (as a list)
      12. Languages (as a list)
      13. Experience Level (Entry Level, Mid Level, Senior, or Executive)
      
      Format the output as a JSON object with these fields:
      {
        "name": string,
        "email": string,
        "phone": string,
        "location": string,
        "title": string,
        "summary": string,
        "skills": string[],
        "experience": [{ "title": string, "company": string, "duration": string, "description": string }],
        "education": string[],
        "educationDetails": [{ "degree": string, "institution": string, "year": string }],
        "certifications": string[],
        "languages": string[],
        "experienceLevel": string
      }
      
      If any information is missing, use empty strings for text fields and empty arrays for lists.
      
      Resume Text:
      ${resumeText}
    `

    const response = await fetch(apiUrl, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${apiKey}`,
      },
      body: JSON.stringify({
        model: "deepseek-chat",
        messages: [
          {
            role: "system",
            content: "You are an expert resume parser that extracts structured information from resume text.",
          },
          {
            role: "user",
            content: prompt,
          },
        ],
        temperature: 0.1,
        max_tokens: 4000,
      }),
    })

    if (!response.ok) {
      throw new Error(`DeepSeek API error: ${response.statusText}`)
    }

    const data = await response.json()
    const parsedContent = data.choices[0].message.content

    // Extract the JSON object from the response
    let parsedResume: ParsedResume
    try {
      // The LLM might return the JSON with markdown code blocks, so we need to extract it
      const jsonMatch = parsedContent.match(/```json\n([\s\S]*?)\n```/) ||
        parsedContent.match(/```\n([\s\S]*?)\n```/) || [null, parsedContent]

      const jsonString = jsonMatch[1] || parsedContent
      const rawParsed = JSON.parse(jsonString)

      // Ensure all required fields are present with correct types
      parsedResume = {
        name: rawParsed.name || "",
        email: rawParsed.email || "",
        phone: rawParsed.phone || "",
        location: rawParsed.location || "",
        title: rawParsed.title || "",
        summary: rawParsed.summary || "",
        skills: Array.isArray(rawParsed.skills) ? rawParsed.skills : [],
        experience: Array.isArray(rawParsed.experience) ? rawParsed.experience.map((exp: any) => ({
          title: exp.title || "",
          company: exp.company || "",
          duration: exp.duration || "",
          description: exp.description || "",
        })) : [],
        education: Array.isArray(rawParsed.education) ? rawParsed.education : [],
        educationDetails: Array.isArray(rawParsed.educationDetails) ? rawParsed.educationDetails.map((edu: any) => ({
          degree: edu.degree || "",
          institution: edu.institution || "",
          year: edu.year || "",
        })) : [],
        certifications: Array.isArray(rawParsed.certifications) ? rawParsed.certifications : [],
        languages: Array.isArray(rawParsed.languages) ? rawParsed.languages : [],
        experienceLevel: rawParsed.experienceLevel || "Not specified",
      }
    } catch (error) {
      console.error("Error parsing LLM response as JSON:", error)
      console.log("Raw LLM response:", parsedContent)

      // Fallback to a basic structure if parsing fails
      parsedResume = {
        name: "",
        email: "",
        phone: "",
        location: "",
        title: "",
        summary: "",
        skills: [],
        experience: [],
        education: [],
        educationDetails: [],
        certifications: [],
        languages: [],
        experienceLevel: "Not specified",
      }
    }

    return parsedResume
  } catch (error) {
    console.error("Error parsing resume with LLM:", error)
    throw new Error("Failed to parse resume with LLM")
  }
}