File size: 5,084 Bytes
2b267d0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
from openai import OpenAI
from dotenv import load_dotenv
import yaml
import os
import json
import re

load_dotenv()

client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

# load prompt
try:
    current_dir = os.path.dirname(os.path.abspath(__file__))
    prompt_path = os.path.join(current_dir, 'prompt.yaml')
    with open(prompt_path, "r", encoding='utf-8') as file:
        prompt = yaml.safe_load(file)["prompt"]
except Exception as e:
    print(f"Warning: prompt.yaml λ‘œλ“œ μ‹€νŒ¨. κΈ°λ³Έ ν”„λ‘¬ν”„νŠΈλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€. 였λ₯˜: {e}")
    prompt = "Question: {question}\nJD: {jd}\nCompany: {company_name}\nExperience: {experience_level}\nGenerate a guide based on this information in markdown table format."


def parse_json_from_response(text: str) -> dict | None:
    """
    Markdown μ½”λ“œ 블둝 μ•ˆμ— 포함될 수 μžˆλŠ” JSON λ¬Έμžμ—΄μ„ μΆ”μΆœν•˜κ³  νŒŒμ‹±ν•©λ‹ˆλ‹€.
    
    Deprecated: 이 ν•¨μˆ˜λŠ” JSON νŒŒμ‹±μš©μ΄λ―€λ‘œ guide generationμ—μ„œλŠ” 더 이상 μ‚¬μš©λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

    Args:
        text (str): LLM이 λ°˜ν™˜ν•œ 전체 ν…μŠ€νŠΈ 응닡.

    Returns:
        dict | None: νŒŒμ‹±λœ λ”•μ…”λ„ˆλ¦¬ 객체, λ˜λŠ” μ‹€νŒ¨ μ‹œ None.
    """
    if not text:
        return None

    # ```json ... ``` λ˜λŠ” ``` ... ``` ν˜•μ‹μ˜ μ½”λ“œ λΈ”λ‘μ—μ„œ JSON μΆ”μΆœ
    match = re.search(r"```(?:json)?\s*([\s\S]*?)\s*```", text)
    if match:
        json_str = match.group(1)
    else:
        # μ½”λ“œ 블둝이 μ—†λ‹€λ©΄, 전체 ν…μŠ€νŠΈλ₯Ό JSON으둜 κ°€μ •
        json_str = text

    try:
        return json.loads(json_str)
    except json.JSONDecodeError:
        # 전체 νŒŒμ‹±μ΄ μ‹€νŒ¨ν•˜λ©΄, 첫 '{'와 λ§ˆμ§€λ§‰ '}'λ₯Ό κΈ°μ€€μœΌλ‘œ λ‹€μ‹œ μ‹œλ„
        start_index = json_str.find('{')
        end_index = json_str.rfind('}')
        if start_index != -1 and end_index != -1 and start_index < end_index:
            potential_json = json_str[start_index:end_index+1]
            try:
                return json.loads(potential_json)
            except json.JSONDecodeError:
                pass  # μ΄λ§ˆμ €λ„ μ‹€νŒ¨ν•˜λ©΄ κ·Έλƒ₯ None λ°˜ν™˜

    return None

def parse_markdown_table_from_response(text: str) -> str:
    """
    LLM μ‘λ‹΅μ—μ„œ λ§ˆν¬λ‹€μš΄ ν…Œμ΄λΈ”μ„ μΆ”μΆœν•˜μ—¬ λ°˜ν™˜ν•©λ‹ˆλ‹€.
    
    Args:
        text (str): LLM이 λ°˜ν™˜ν•œ 전체 ν…μŠ€νŠΈ 응닡.
        
    Returns:
        str: μΆ”μΆœλœ λ§ˆν¬λ‹€μš΄ ν…Œμ΄λΈ” λ¬Έμžμ—΄, μ‹€νŒ¨ μ‹œ 전체 ν…μŠ€νŠΈ λ°˜ν™˜
    """
    if not text:
        return ""
    
    # λ§ˆν¬λ‹€μš΄ μ½”λ“œ λΈ”λ‘μ—μ„œ ν…Œμ΄λΈ” μΆ”μΆœ μ‹œλ„
    markdown_match = re.search(r"```(?:markdown)?\s*([\s\S]*?)\s*```", text)
    if markdown_match:
        return markdown_match.group(1).strip()
    
    # ν…Œμ΄λΈ” νŒ¨ν„΄ 직접 μ°ΎκΈ° (| ... | ... | ν˜•νƒœ)
    lines = text.split('\n')
    table_lines = []
    in_table = False
    
    for line in lines:
        line = line.strip()
        if '|' in line and ('단계' in line or '---' in line or 'β‘ ' in line):
            in_table = True
            table_lines.append(line)
        elif in_table and '|' in line:
            table_lines.append(line)
        elif in_table and not line:
            # 빈 쀄이면 ν…Œμ΄λΈ” 끝
            break
    
    if table_lines:
        return '\n'.join(table_lines)
    
    # ν…Œμ΄λΈ”μ„ μ°Ύμ§€ λͺ»ν–ˆμœΌλ©΄ 전체 ν…μŠ€νŠΈ λ°˜ν™˜
    return text.strip()

def generate_guide(question, jd, company_name, experience_level):
    """
    μžκΈ°μ†Œκ°œμ„œ λ¬Έν•­ κ°€μ΄λ“œλ₯Ό μƒμ„±ν•˜κ³ , λ§ˆν¬λ‹€μš΄ ν…Œμ΄λΈ”κ³Ό 전체 응닡 객체λ₯Ό λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜
    """
    try:
        response = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[{"role": "user", "content": prompt.format(question=question, jd=jd, company_name=company_name, experience_level=experience_level)}],
            # response_format을 μ œκ±°ν•˜μ—¬ 일반 ν…μŠ€νŠΈ 응닡을 λ°›μŒ
        )
        
        # λ§ˆν¬λ‹€μš΄ ν…Œμ΄λΈ” νŒŒμ‹±
        guide_content = parse_markdown_table_from_response(response.choices[0].message.content)
        
        # ν˜Έν™˜μ„±μ„ μœ„ν•΄ λ”•μ…”λ„ˆλ¦¬ ν˜•νƒœλ‘œ λ°˜ν™˜
        guide_dict = {"guide": guide_content}
        return guide_dict, response

    except Exception as e:
        print(f"κ°€μ΄λ“œ 생성 λ˜λŠ” νŒŒμ‹± 쀑 였λ₯˜ λ°œμƒ: {e}")
        return {"error": f"Failed to generate or parse guide: {str(e)}", "guide": ""}, None


if __name__ == "__main__":
    example_input = {
        "question": "μ‚Όμ„±μ „μžλ₯Ό μ§€μ›ν•œ μ΄μœ μ™€ μž…μ‚¬ ν›„ 이루고 싢은 κΏˆμ„ κΈ°μˆ ν•˜μ‹œμ˜€.",
        "jd": "μ‚Όμ„±μ „μžλŠ” 세계적인 기술 κΈ°μ—…μœΌλ‘œ, λ‹€μ–‘ν•œ λΆ„μ•Όμ—μ„œ 선도적인 κΈ°μˆ μ„ κ°œλ°œν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. ν”„λ‘ νŠΈμ—”λ“œ 개발자둜 μž…μ‚¬ν•˜λ©΄ λ‹€μ–‘ν•œ ν”„λ‘œμ νŠΈμ— μ°Έμ—¬ν•˜λ©°, μ΅œμ‹  κΈ°μˆ μ„ μ μš©ν•˜μ—¬ μ‚¬μš©μž κ²½ν—˜μ„ κ°œμ„ ν•  수 μžˆμŠ΅λ‹ˆλ‹€.",
        "company_name": "μ‚Όμ„±μ „μž",
        "experience_level": "μ‹ μž…"
    }
    guide_dict, _ = generate_guide(**example_input)
    print("Guide content:")
    print(guide_dict.get("guide", "No guide generated"))