낙서장

Chat gpt(Open AI)를 사용해 이력서 수정해보기 최종본

AOIME 2026. 3. 1. 15:32

목적 : 구인구직 사이트에서 이력서를 작성 시 자기소개에 자신이 없는 사람을 위해 만든 기능입니다.

目的:求人サイトで履歴書を作成する際に、自己紹介に自信がない人のために作られた機能です

 

CHAT GPT 를 사용해서 이용해서 수정하는 기능이며 간단한 정보와 직업 정보만 넣어주면 거기에 맞게 프롬프트가 작동하는 코드 입니다. 

CHAT GPT を利用して修正する機能で、簡単な情報と職業情報を入力すれば、それに合わせてプロンプトが動作するコードです

 

구성 화면

 

1. 이력서

입력 값 :  

1 제목

2. 간단한 소개글

3. AI 카테고리 

2.이력서 AI로 수정한 화면

이력서가 간단한 소개글과 직업 카테고리에 작성한 직업을 인식해서 500자 이내의 글을 작성하게 했습니다.

3. 결과

 

수정한 결과 입니다.

더보기

 

 

 

Resume

더보기
package com.example.demo.resume;
import com.example.demo.user.User;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;
import java.time.LocalDateTime;

@Table(name = "resume_tb")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
public class Resume {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long resumeId;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "user_id")
    private User user;

    @Column(nullable = false)
    private String title;

    @Column(nullable = false, columnDefinition = "TEXT")
    private String content;

    @CreationTimestamp
    @Column(nullable = false)
    private LocalDateTime createdAt; }

ResumeAiService

더보기
package com.example.demo.resume;

import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.ChatModel;
import com.openai.models.responses.ResponseCreateParams;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class ResumeAiService {

    public String revise(String content, String jobCategory) {

        OpenAIClient client = OpenAIOkHttpClient.builder()
                .apiKey("본인의 키를 넣어주세요 이 코드는 Open AI 키를 넣어야합니다.")
                .build();

        String prompt =
                "あなたは日本企業の採用面接官が評価することを前提とした履歴書添削者です。\n" +
                        "職種カテゴリ: " + jobCategory + "\n\n" +
                        "【原文】\n" + content + "\n\n" +
                        "【指示】\n" +
                        "1. 必ず日本語で出力すること。\n" +
                        "2. 文字数は500字以内にまとめること。\n" +
                        "3. 原文にない事実・数値・経験は絶対に追加しないこと。\n" +
                        "4. 上記の職種カテゴリを意識し、その職種に適した表現へ改善すること。\n" +
                        "5. 評価基準(論理性・具体性・主体性)を満たす文章にすること。\n\n" +
                        "出力は添削後の履歴書本文のみ。説明は不要。";

        ResponseCreateParams params = ResponseCreateParams.builder()
                .model("gpt-4.1-mini")
                //.model(ChatModel.GPT_5_2)
                .input(prompt)
                .build();

        var response = client.responses().create(params);

        String raw = response.output().toString();

        String startKey = "text=";
        String endKey = ", type=";

        int start = raw.indexOf(startKey);
        if (start == -1) return "";

        start += startKey.length();

        int end = raw.indexOf(endKey, start);
        if (end == -1) return "";

        return raw.substring(start, end);
    }
}

ResumeController

더보기
package com.example.demo.resume;

import com.example.demo.user.User;
import com.example.demo.user.UserJpaRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

@Controller
@RequiredArgsConstructor //DI
public class ResumeController {

    private final UserJpaRepository userJpaRepository;
    private final ResumeJpaRepository resumeJpaRepository;
    private final ResumeService resumeService;
    private final ResumeAiService resumeAiService;

    @PostMapping("/resumes")
    public String create(ResumeRequest.CreateDTO createDTO) {
        User user = userJpaRepository.findById(1L)
                .orElseThrow(() -> new IllegalArgumentException("사용자를 찾을 수 없습니다."));
        Resume resume = createDTO.toEntity(user);
        resumeJpaRepository.save(resume);
        return "redirect:/resumes/" + resume.getResumeId();
    }

    @GetMapping("/resumes")
    public String list(Model model) {
        List<Resume> resumes = resumeJpaRepository.findAll();
        model.addAttribute("resumes", resumes);
        return "resume-list";
    }

    @GetMapping("/resumes/new")
    public String writeForm() {
        return "resume-new";
    }

    @GetMapping("/resumes/{id}")
    public String detail(@PathVariable Long id, Model model) {
        Resume resume = resumeJpaRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("이력서를 찾을 수 없습니다. id=" + id));
        model.addAttribute("resume", resume);
        return "resume-detail";
    }

    @PostMapping("/resumes/{id}/ai/preview")
    public String preview(@PathVariable Long id,
                          @RequestParam String jobCategory,
                          Model model) {

        Resume resume = resumeJpaRepository.findById(id).orElseThrow();

        String aiText = resumeAiService.revise(
                resume.getContent(),
                jobCategory
        );

        model.addAttribute("resume", resume);
        model.addAttribute("aiPreview", aiText);
//        model.addAttribute("jobCategory", jobCategory); // jobCategory 추가

        return "resume-detail";
    }

    @PostMapping("/resumes/{id}/ai/approve")
    public String approve(@PathVariable Long id,
                          @RequestParam String aiContent) {



        Long newId = resumeService.approve(id, aiContent);

        return "redirect:/resumes/" + newId;
    }
}

ResumeJpaRepository

더보기
package com.example.demo.resume;

import org.springframework.data.jpa.repository.JpaRepository;

public interface ResumeJpaRepository extends JpaRepository<Resume, Long> {
}

ResumeRequest

더보기
package com.example.demo.resume;

import com.example.demo.user.User;
import lombok.Data;

public class ResumeRequest {

    @Data
    public static class CreateDTO {
        private String title;
        private String content;

        public Resume toEntity(User user) {
            return Resume.builder()
                    .user(user)
                    .title(title)
                    .content(content)
                    .build();
        }
    }
}

ResumeService

더보기
package com.example.demo.resume;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
public class ResumeService {

    private final ResumeJpaRepository resumeJpaRepository;

    @Transactional
    public Long approve(Long originId, String aiContent) {

        Resume origin = resumeJpaRepository.findById(originId)
                .orElseThrow(() -> new IllegalArgumentException("resume 없음"));

        Resume newResume = new Resume();
        newResume.setTitle(origin.getTitle() + " (AI修正)");
        newResume.setContent(aiContent);
        newResume.setUser(origin.getUser());

        Resume saved = resumeJpaRepository.save(newResume);
        return saved.getResumeId();
    }
}
728x90