Skip to content

사이드 프로젝트 이력서 시각화 서비스 제작기 5편

텍스트를 숫자로: 인생의 굴곡을 수치화하기

지난 4편에서 Qwen2.5 모델을 통해 이력서의 핵심 성과를 성공적으로 요약했습니다. 하지만 그래프를 그리기 위해서는 "성공적인 프로젝트 수행"이라는 말보다 "85점"이라는 **숫자(Score)**가 필요합니다. 오늘은 텍스트 데이터를 좌표값으로 변환하는 과정을 다뤄봅니다.

1. 에이전트에게 맥락 공유하기 (Context Injection)

Antigravity 에이전트와 새 세션을 시작할 때는, 이전 단계의 결과물을 다시 알려주는 과정이 필요합니다. 저는 4편에서 AI가 출력했던 분석 결과 샘플을 에이전트에게 전달하며 질문을 던졌습니다.

Agent Prompt

지난번에 네가 분석해준 이력서 요약 결과가 아래와 같아

- **경력 항목**:
  - 2021.03 - 2022.12: (주)레몬소프트 인턴 및 주임

    - 활동 기간: 2021년부터 2022년까지
    - 주요 성과: 파이썬 기반 레거시 시스템 리팩토링 및 API 성능 개선, Redis 캐싱 도입으로 데이터 조회 속도 25% 향상

- **경력 항목**:
  - 2023.01 - 2025.02: 파인애플 테크놀로지 대리

    - 활동 기간: 2023년부터 2025년까지
    - 주요 성과: MSA 기반 결제 서비스 마이크로서비스 설계 및 구축, Kafka를 활용한 실시간 결제 로그 수집 파이프라인 개발

    - 성공적인 활동: 클라우드 아키텍처 최적화 및 주니어 개발자 멘토링

- **경력 항목**:
  - 현재: 스타트업 '오렌지랩' 백엔드 리드

    - 활동 기간: 2025년까지
    - 주요 성과: 클라우드 아키텍처 최적화 및 주니어 개발자 멘토링

    - 성공적인 활동: 클래스 제안 및 프로그래밍 교육 제공

**총 경험**: [모든 경력 항목의 핵심 성과]

위와 같이 나온 요약된 내용을 기반으로 각 항목의 '성취도 점수(0~100)'를 매기는 파이썬 함수를 `utils.py`에 작성해줘. '설계', '최적화' 같은 핵심 키워드가 있거나 숫자로 된 성과(예: 25% 개선)가 있으면 가산점을 줬으면 좋겠어. 결과는 시각화하기 좋게 `{'year': 2023, 'score': 85}` 형태의 리스트로 반환해줘."

2. utils.py: 데이터 가공 및 점수 산출 로직

에이전트는 단순히 텍스트를 읽는 수준을 넘어, **정규표현식(Regex)**을 활용해 날짜 패턴을 분석하고 연도별로 점수를 매핑하는 꽤나 본격적인 로직을 제안했습니다. 특히 AI 요약문의 특징적인 구분자들을 기준으로 데이터를 쪼개는 방식이 인상적입니다.

import re

def calculate_achievement_scores(summary_text: str):
    """
    이력서 요약 텍스트를 분석하여 연도별 성취도 점수를 계산합니다.
    """
    # 1. 경력 항목별로 텍스트 분할 (AI 요약 형식 지원)
    blocks = re.split(r'- \*\*경력 항목\*\*:|- 기간:', summary_text)
    blocks = [b.strip() for b in blocks if b.strip()]

    year_scores = {}
    current_year = 2026 # 현재 시점 기준

    # 가산점 키워드 설정
    core_keywords = ['설계', '최적화', '구축', '아키텍처', '리팩토링', 'MSA', '파이프라인']
    performance_keywords = ['성능 개선', '향상', '절감', '단축', '증가', '속도']

    for block in blocks:
        active_years = set()
        # 패턴 1: 2021.03 - 2022.12 형태 추출
        range_match = re.findall(r'(\d{4})\.\d{2}', block)
        if len(range_match) >= 2:
            start_y, end_y = int(range_match[0]), int(range_match[1])
            for y in range(start_y, end_y + 1): active_years.add(y)
        elif len(range_match) == 1:
            # 패턴 2: 현재 진행형 경력 처리
            if '현재' in block:
                start_y = int(range_match[0])
                for y in range(start_y, current_year + 1): active_years.add(y)
            else:
                active_years.add(int(range_match[0]))
        else:
            # 패턴 3: '2021년부터'와 같은 한글 표현 추출
            year_mentions = re.findall(r'(\d{4})\ub144', block)
            if year_mentions:
                y_list = sorted(map(int, set(year_mentions)))
                for y in range(y_list[0], y_list[-1] + 1): active_years.add(y)

        if not active_years: continue

        # 점수 계산 루틴 (기본 60점)
        score = 60
        for kw in core_keywords:
            if kw in block: score += 10
        for kw in performance_keywords:
            if kw in block: score += 5
        # 수치형 성과 가산점 (25%, 3배 등)
        if re.search(r'\d+(?:\.\d+)?%', block) or re.search(r'\d+\s*\ubc30', block):
            score += 15

        score = min(max(score, 0), 100)

        # 연도별 매핑 (중복 연도 발생 시 최고점 유지)
        for y in active_years:
            if y not in year_scores or score > year_scores[y]:
                year_scores[y] = int(score)

    results = [{'year': y, 'score': s} for y, s in year_scores.items()]
    results.sort(key=lambda x: x['year'])
    return results

3. 통합 테스트: AI 분석부터 스코어링까지 한 번에

이제 하드코딩된 텍스트가 아니라, analyzer.py의 AI 결과물이 utils.py로 막힘없이 흘러가는지 확인하기 위해 통합 테스트(utils-test.py)를 수행했습니다.

from analyzer import ResumeAnalyzer
from utils import calculate_achievement_scores

def run_integration_test():
    # 1. 분석기 초기화
    print("="*50)
    print("ResumeAnalyzer 초기화 중...")
    analyzer = ResumeAnalyzer()
    print("모델 로드 완료!")
    print("="*50)

    # 2. 테스트용 Mock 데이터 (김철수 님)
    # 이 데이터는 analyzer.py의 AI를 거쳐 요약 텍스트로 변환될 것입니다.
    mock_resume_data = [
        "김철수 | 백엔드 개발자",
        "2021.03 - 2022.12: (주)망고소프트 인턴 및 주임",
        "파이썬 기반 레거시 시스템 리팩토링 및 API 성능 개선",
        "Redis 캐싱 도입으로 데이터 조회 속도 25% 향상",
        "2023.01 - 2025.02: 파인애플 테크놀로지 대리",
        "MSA 기반 결제 서비스 마이크로서비스 설계 및 구축",
        "Kafka를 활용한 실시간 결제 로그 수집 파이프라인 개발",
        "2025.03 - 현재: 스타트업 '오렌지랩' 백엔드 리드",
        "클라우드 아키텍처 최적화 및 주니어 개발자 멘토링"
    ]

    # 3. AI를 통한 요약 결과 추출 (analyzer.py)
    print("\n[Step 1] AI 분석을 통해 이력서 요약을 생성합니다...\n")
    try:
        summary_result = analyzer.extract_achievements(mock_resume_data)
        print("=== AI 요약 결과 ===")
        print(summary_result)
        print("-" * 30)

        # 4. 요약 결과를 기반으로 성취도 점수 계산 (utils.py)
        print("\n[Step 2] 요약된 텍스트에서 연도별 성취도 점수를 계산합니다...\n")
        scoring_results = calculate_achievement_scores(summary_result)

        print("=== 최종 성취도 분석 결과 ===")
        for item in scoring_results:
            print(f"연도: {item['year']} | 성취도 점수: {item['score']}")

        print("\n데이터 구조 결과:", scoring_results)

    except Exception as e:
        print(f"테스트 진행 중 오류가 발생했습니다: {e}")

if __name__ == "__main__":
    run_integration_test()

[object Object]

==================================================
ResumeAnalyzer 초기화 중...
Loading model on cpu...
Loading weights: 100%|| 290/290 [00:00<00:00, 2851.96it/s, Materializing
모델 로드 완료!
==================================================

[Step 1] AI 분석을 통해 이력서 요약을 생성합니다...

=== AI 요약 결과 ===
- 기간: 2021.03 - 2022.12, 2023.01 - 2025.02
  성과: 파이썬 기반 레거시 시스템 리팩토링 및 API 성능 개선, MSA 기반 결제 서비스 마이크로서비스 설계 및 구축, Kafka를 활용한 실시간 결제 로그 수집 파이프라인 개발

- 기간: 2025.03 - 현재
  성과: 스타트업 '오렌지랩' 백엔드 리드, 클라우드 아키텍처 최적화 및 주니 어 개발자 멘토링
------------------------------

[Step 2] 요약된 텍스트에서 연도별 성취도 점수를 계산합니다...

=== 최종 성취도 분석 결과 ===
연도: 2021 | 성취도 점수: 100
연도: 2022 | 성취도 점수: 100
연도: 2025 | 성취도 점수: 80
연도: 2026 | 성취도 점수: 80

데이터 구조 결과: [{'year': 2021, 'score': 100}, {'year': 2022, 'score': 100}, {'year': 2025, 'score': 80}, {'year': 2026, 'score': 80}]

회고

단순히 글을 요약하는 수준을 넘어, 당신의 2023년 성취도는 100점입니다라고 숫자로 말해줄 수 있는 엔진이 완성되었습니다.

정성적인 이력서 텍스트가 정량적인 데이터 좌표로 변하는 과정을 보며, 사이드 프로젝트의 기술적 뼈대가 단단해졌음을 느낍니다.

이제 이 숫자들을 시각화할 차례입니다. 다음 6편에서는 이 좌표들을 바탕으로 실제 '인생 그래프' 이미지를 그려내는 시각화 로직을 구현해 보겠습니다.