kyle8581's picture
.
594e237
import os
import json
import re
import yaml
from openai import OpenAI
# OpenAI ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™”
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
# ํ”„๋กฌํ”„ํŠธ ํ…œํ”Œ๋ฆฟ ๋กœ๋“œ
import os
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 f:
prompt_data = yaml.safe_load(f)
prompt_template = prompt_data['prompt']
def parse_context_report(content):
"""
AI ์‘๋‹ต์—์„œ ์ปจํ…์ŠคํŠธ ๋ฆฌํฌํŠธ JSON์„ ํŒŒ์‹ฑํ•˜๋Š” ํ•จ์ˆ˜
"""
try:
print(f"ํŒŒ์‹ฑํ•  ์ปจํ…์ธ  ๊ธธ์ด: {len(content)}")
print(f"ํŒŒ์‹ฑํ•  ์ปจํ…์ธ  ์ฒซ 200์ž: {repr(content[:200])}")
# ํ…์ŠคํŠธ ์ „์ฒ˜๋ฆฌ
cleaned_content = content.strip()
# 1. JSON ์ฝ”๋“œ ๋ธ”๋ก ์ฐพ๊ธฐ (```json ... ``` ํ˜•์‹)
json_patterns = [
r'```json\s*(\{.*?\})\s*```',
r'```\s*(\{.*?\})\s*```',
r'```json\s*(.*?)\s*```',
r'```\s*(.*?)\s*```'
]
for pattern in json_patterns:
json_match = re.search(pattern, cleaned_content, re.DOTALL)
if json_match:
json_str = json_match.group(1).strip()
print(f"JSON ๋ธ”๋ก ๋ฐœ๊ฒฌ: {repr(json_str[:100])}")
# JSON ๋ฌธ์ž์—ด ์ •๋ฆฌ
json_str = re.sub(r'\n\s*', ' ', json_str)
json_str = re.sub(r',\s*}', '}', json_str)
json_str = re.sub(r',\s*]', ']', json_str)
try:
parsed_json = json.loads(json_str)
if isinstance(parsed_json, dict) and 'company_profile' in parsed_json:
return parsed_json
except json.JSONDecodeError as e:
print(f"JSON ๋ธ”๋ก ํŒŒ์‹ฑ ์‹คํŒจ: {e}")
# 2. ์ค‘๊ด„ํ˜ธ๋กœ ๋‘˜๋Ÿฌ์‹ธ์ธ JSON ์ฐพ๊ธฐ
brace_patterns = [
r'\{.*?\}'
]
for pattern in brace_patterns:
brace_match = re.search(pattern, cleaned_content, re.DOTALL)
if brace_match:
json_str = brace_match.group(0).strip()
print(f"์ค‘๊ด„ํ˜ธ ๋ธ”๋ก ๋ฐœ๊ฒฌ: {repr(json_str[:100])}")
# JSON ๋ฌธ์ž์—ด ์ •๋ฆฌ
json_str = re.sub(r'\n\s*', ' ', json_str)
json_str = re.sub(r',\s*}', '}', json_str)
json_str = re.sub(r',\s*]', ']', json_str)
try:
parsed_json = json.loads(json_str)
if isinstance(parsed_json, dict) and 'company_profile' in parsed_json:
return parsed_json
except json.JSONDecodeError as e:
print(f"์ค‘๊ด„ํ˜ธ ๋ธ”๋ก ํŒŒ์‹ฑ ์‹คํŒจ: {e}")
# 3. ์ „์ฒด ํ…์ŠคํŠธ๋ฅผ JSON์œผ๋กœ ํŒŒ์‹ฑ ์‹œ๋„
try:
# ์ฝ”๋“œ ๋ธ”๋ก ๋งˆ์ปค ์ œ๊ฑฐ
if cleaned_content.startswith('```'):
lines = cleaned_content.split('\n')
start_idx = 1 if lines[0].startswith('```') else 0
end_idx = len(lines)
for i in range(len(lines)-1, -1, -1):
if lines[i].strip() == '```':
end_idx = i
break
cleaned_content = '\n'.join(lines[start_idx:end_idx])
cleaned_content = cleaned_content.strip()
parsed_json = json.loads(cleaned_content)
if isinstance(parsed_json, dict) and 'company_profile' in parsed_json:
return parsed_json
except json.JSONDecodeError as e:
print(f"์ „์ฒด JSON ํŒŒ์‹ฑ ์‹คํŒจ: {e}")
# 4. ๊ธฐ๋ณธ ๊ตฌ์กฐ ๋ฐ˜ํ™˜ (ํŒŒ์‹ฑ ์‹คํŒจ ์‹œ)
print("JSON ํŒŒ์‹ฑ ์‹คํŒจ, ๊ธฐ๋ณธ ๊ตฌ์กฐ ๋ฐ˜ํ™˜")
return {
"company_profile": {
"name": "ํŒŒ์‹ฑ ์‹คํŒจ",
"vision_mission": "์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.",
"core_values": ["์ •๋ณด ์—†์Œ"],
"talent_philosophy": "์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.",
"recent_news_summary": "์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.",
"main_products_services": ["์ •๋ณด ์—†์Œ"]
},
"position_analysis": {
"role_summary": "์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.",
"required_skills": {
"hard": ["์ •๋ณด ์—†์Œ"],
"soft": ["์ •๋ณด ์—†์Œ"]
},
"keywords": ["์ •๋ณด ์—†์Œ"]
},
"industry_context": {
"trends": ["์ •๋ณด ์—†์Œ"],
"competitors": ["์ •๋ณด ์—†์Œ"]
}
}
except Exception as e:
print(f"์ปจํ…์ŠคํŠธ ๋ฆฌํฌํŠธ ํŒŒ์‹ฑ ์ „์ฒด ์˜ค๋ฅ˜: {e}")
print(f"ํŒŒ์‹ฑ ์‹คํŒจํ•œ ์ปจํ…์ธ : {repr(content)}")
return {
"company_profile": {
"name": "์˜ค๋ฅ˜ ๋ฐœ์ƒ",
"vision_mission": f"ํŒŒ์‹ฑ ์˜ค๋ฅ˜: {str(e)}",
"core_values": ["์˜ค๋ฅ˜"],
"talent_philosophy": f"ํŒŒ์‹ฑ ์˜ค๋ฅ˜: {str(e)}",
"recent_news_summary": f"ํŒŒ์‹ฑ ์˜ค๋ฅ˜: {str(e)}",
"main_products_services": ["์˜ค๋ฅ˜"]
},
"position_analysis": {
"role_summary": f"ํŒŒ์‹ฑ ์˜ค๋ฅ˜: {str(e)}",
"required_skills": {
"hard": ["์˜ค๋ฅ˜"],
"soft": ["์˜ค๋ฅ˜"]
},
"keywords": ["์˜ค๋ฅ˜"]
},
"industry_context": {
"trends": ["์˜ค๋ฅ˜"],
"competitors": ["์˜ค๋ฅ˜"]
}
}
def generate_context_report(job_title, company_name, experience_level):
"""
OpenAI API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž์†Œ์„œ ์ปจํ…์ŠคํŠธ ๋ฆฌํฌํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ํ•จ์ˆ˜
"""
try:
if not job_title or not company_name or not experience_level:
return "์ง๋ฌด, ํšŒ์‚ฌ๋ช…, ๊ฒฝ๋ ฅ ์ˆ˜์ค€์„ ๋ชจ๋‘ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.", {}
# ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ
prompt = prompt_template.format(
job_title=job_title,
company_name=company_name,
experience_level=experience_level
)
# OpenAI Responses API ํ˜ธ์ถœ (Web Search Preview ์‚ฌ์šฉ)
response = client.responses.create(
model="gpt-4o-mini",
tools=[{
"type": "web_search_preview",
"search_context_size": "high",
}],
input=f"๋‹น์‹ ์€ ์ž๊ธฐ์†Œ๊ฐœ์„œ ์ž‘์„ฑ์„ ์œ„ํ•œ ๊ธฐ์—… ๋ฐ ์ง๋ฌด ๋ถ„์„ ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. ์›น ๊ฒ€์ƒ‰์„ ํ†ตํ•ด ์ตœ์‹  ๊ธฐ์—… ์ •๋ณด์™€ ์‚ฐ์—… ๋™ํ–ฅ์„ ํ™•์ธํ•˜๊ณ  ์ •ํ™•ํ•œ JSON ํ˜•์‹์œผ๋กœ ๊ตฌ์กฐํ™”๋œ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•ด์ฃผ์„ธ์š”.\n\n{prompt}"
)
content = response.output_text
print(f"=== AI ์‘๋‹ต ์›๋ณธ ===")
print(content)
print(f"=== ์ „์ฒด ์‘๋‹ต ๊ฐ์ฒด ===")
print(response)
# ์›น ๊ฒ€์ƒ‰ ์ฐธ๊ณ  ๋งํฌ ์ถœ๋ ฅ
if hasattr(response, 'web_search_results') and response.web_search_results:
print(f"=== ์ฐธ๊ณ ํ•œ ์›น ๊ฒ€์ƒ‰ ๋งํฌ ===")
for i, result in enumerate(response.web_search_results, 1):
if hasattr(result, 'url'):
print(f"{i}. {result.url}")
elif hasattr(result, 'link'):
print(f"{i}. {result.link}")
print(f"=== AI ์‘๋‹ต ๋ ===")
report_data = parse_context_report(content)
if not report_data or 'company_profile' not in report_data:
return "์ปจํ…์ŠคํŠธ ๋ฆฌํฌํŠธ ์ƒ์„ฑ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.", {}
# ๊ฒฐ๊ณผ ํฌ๋งทํŒ…
result = f"""## ๐Ÿ“Š {company_name} - {job_title} ์ปจํ…์ŠคํŠธ ๋ฆฌํฌํŠธ
### ๐Ÿข **๊ธฐ์—… ํ”„๋กœํ•„**
**๐ŸŽฏ ๋น„์ „ & ๋ฏธ์…˜**
{report_data['company_profile']['vision_mission']}
**๐Ÿ’Ž ํ•ต์‹ฌ ๊ฐ€์น˜**
"""
for i, value in enumerate(report_data['company_profile']['core_values'], 1):
result += f"**{i}.** {value}\n"
result += f"""
**๐Ÿ‘ฅ ์ธ์žฌ์ƒ**
{report_data['company_profile']['talent_philosophy']}
**๐Ÿ“ฐ ์ตœ๊ทผ ๋™ํ–ฅ**
{report_data['company_profile']['recent_news_summary']}
**๐Ÿ›๏ธ ์ฃผ์š” ์ œํ’ˆ/์„œ๋น„์Šค**
"""
for i, service in enumerate(report_data['company_profile']['main_products_services'], 1):
result += f"**{i}.** {service}\n"
result += f"""
### ๐Ÿ’ผ **์ง๋ฌด ๋ถ„์„**
**๐Ÿ“‹ ์—ญํ•  ์š”์•ฝ**
{report_data['position_analysis']['role_summary']}
**๐Ÿ”ง ํ•„์š” ์Šคํ‚ฌ**
*ํ•˜๋“œ ์Šคํ‚ฌ:*
"""
for skill in report_data['position_analysis']['required_skills']['hard']:
result += f"โ€ข {skill}\n"
result += "\n*์†Œํ”„ํŠธ ์Šคํ‚ฌ:*\n"
for skill in report_data['position_analysis']['required_skills']['soft']:
result += f"โ€ข {skill}\n"
result += f"""
**๐Ÿท๏ธ ํ•ต์‹ฌ ํ‚ค์›Œ๋“œ**
"""
for keyword in report_data['position_analysis']['keywords']:
result += f"`{keyword}` "
result += f"""
### ๐ŸŒ **์‚ฐ์—… ๋งฅ๋ฝ**
**๐Ÿ“ˆ ์ฃผ์š” ํŠธ๋ Œ๋“œ**
"""
for i, trend in enumerate(report_data['industry_context']['trends'], 1):
result += f"**{i}.** {trend}\n"
result += f"""
**๐Ÿ† ์ฃผ์š” ๊ฒฝ์Ÿ์‚ฌ**
"""
for i, competitor in enumerate(report_data['industry_context']['competitors'], 1):
result += f"**{i}.** {competitor}\n"
result += f"""
---
**๐Ÿ“ ์ž…๋ ฅ ์ •๋ณด:**
- ํšŒ์‚ฌ: {company_name}
- ์ง๋ฌด: {job_title}
- ๊ฒฝ๋ ฅ: {experience_level}
*๋ณธ ๋ฆฌํฌํŠธ๋Š” AI๊ฐ€ ์ƒ์„ฑํ•œ ๊ฒƒ์œผ๋กœ, ์‹ค์ œ ์ •๋ณด์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ž์†Œ์„œ ์ž‘์„ฑ ์‹œ ์ฐธ๊ณ ์šฉ์œผ๋กœ ํ™œ์šฉํ•˜์„ธ์š”.*
"""
return result, report_data
except Exception as e:
error_msg = f"""## โŒ ์˜ค๋ฅ˜ ๋ฐœ์ƒ
์ปจํ…์ŠคํŠธ ๋ฆฌํฌํŠธ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.
**์˜ค๋ฅ˜ ๋‚ด์šฉ:** {str(e)}
๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.
"""
return error_msg, {}