jasoseo-agent / app.py
kyle8581's picture
modified the file name:
f4fd9fa
import gradio as gr
import os
import sys
import importlib.util
from pathlib import Path
import dotenv
dotenv.load_dotenv()
# ํ˜„์žฌ ๋””๋ ‰ํ† ๋ฆฌ ์„ค์ •
current_dir = Path(__file__).parent
# ๊ฐ ๊ธฐ๋Šฅ๋ณ„ ๋ชจ๋“ˆ ๋กœ๋“œ ํ•จ์ˆ˜
def load_module_from_path(module_name, file_path):
"""๋™์ ์œผ๋กœ ๋ชจ๋“ˆ์„ ๋กœ๋“œํ•˜๋Š” ํ•จ์ˆ˜"""
try:
spec = importlib.util.spec_from_file_location(module_name, file_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
except Exception as e:
print(f"๋ชจ๋“ˆ ๋กœ๋“œ ์‹คํŒจ {module_name}: {e}")
return None
# ๊ฐ ๊ธฐ๋Šฅ๋ณ„ ๋ชจ๋“ˆ ๋ฐ ํ•จ์ˆ˜ ๋กœ๋“œ
modules = {}
available_features = {}
# 1. commonly-asked-question
try:
llm_functions_path = current_dir / "commonly-asked-question" / "llm_functions.py"
if llm_functions_path.exists():
modules['commonly_asked'] = load_module_from_path("commonly_asked_llm", llm_functions_path)
available_features['commonly_asked'] = modules['commonly_asked'] is not None
else:
available_features['commonly_asked'] = False
except Exception as e:
print(f"commonly-asked-question ๋ชจ๋“ˆ ๋กœ๋“œ ์‹คํŒจ: {e}")
available_features['commonly_asked'] = False
# 2. question-recommendation
try:
llm_functions_path = current_dir / "question-recommendation" / "llm_functions.py"
if llm_functions_path.exists():
modules['question_rec'] = load_module_from_path("question_rec_llm", llm_functions_path)
available_features['question_rec'] = modules['question_rec'] is not None
else:
available_features['question_rec'] = False
except Exception as e:
print(f"question-recommendation ๋ชจ๋“ˆ ๋กœ๋“œ ์‹คํŒจ: {e}")
available_features['question_rec'] = False
# 3. jd-recommendation
try:
llm_functions_path = current_dir / "jd-recommendation" / "llm_functions.py"
if llm_functions_path.exists():
modules['jd_rec'] = load_module_from_path("jd_rec_llm", llm_functions_path)
available_features['jd_rec'] = modules['jd_rec'] is not None
else:
available_features['jd_rec'] = False
except Exception as e:
print(f"jd-recommendation ๋ชจ๋“ˆ ๋กœ๋“œ ์‹คํŒจ: {e}")
available_features['jd_rec'] = False
# 4. industry-classification
try:
llm_functions_path = current_dir / "industry-classification" / "llm_functions.py"
if llm_functions_path.exists():
modules['industry'] = load_module_from_path("industry_llm", llm_functions_path)
available_features['industry'] = modules['industry'] is not None
else:
available_features['industry'] = False
except Exception as e:
print(f"industry-classification ๋ชจ๋“ˆ ๋กœ๋“œ ์‹คํŒจ: {e}")
available_features['industry'] = False
# 5. jasoseo-context-report
try:
llm_functions_path = current_dir / "jasoseo-context-report" / "llm_functions.py"
if llm_functions_path.exists():
modules['jasoseo'] = load_module_from_path("jasoseo_llm", llm_functions_path)
available_features['jasoseo'] = modules['jasoseo'] is not None
else:
available_features['jasoseo'] = False
except Exception as e:
print(f"jasoseo-context-report ๋ชจ๋“ˆ ๋กœ๋“œ ์‹คํŒจ: {e}")
available_features['jasoseo'] = False
# 6. company-size-classification
try:
llm_functions_path = current_dir / "company-size-classification" / "llm_functions.py"
if llm_functions_path.exists():
modules['company_size'] = load_module_from_path("company_size_llm", llm_functions_path)
available_features['company_size'] = modules['company_size'] is not None
else:
available_features['company_size'] = False
except Exception as e:
print(f"company-size-classification ๋ชจ๋“ˆ ๋กœ๋“œ ์‹คํŒจ: {e}")
available_features['company_size'] = False
# OpenAI ๊ด€๋ จ ๋ชจ๋“ˆ
try:
from openai import OpenAI
import yaml
openai_available = True
except ImportError:
openai_available = False
# OpenAI ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™”
client = None
if openai_available and os.getenv("OPENAI_API_KEY"):
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
# ๊ณตํ†ต CSS ์Šคํƒ€์ผ
common_css = """
.main-header {
text-align: center;
padding: 20px;
background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
color: white;
border-radius: 10px;
margin-bottom: 20px;
}
.input-section {
background-color: #f8f9fa;
padding: 20px;
border-radius: 8px;
margin: 10px 0;
}
.example-section {
background-color: #f0f9ff;
padding: 15px;
border-radius: 8px;
margin: 10px 0;
}
.tab-container {
margin: 20px 0;
height: 100%;
}
"""
# ์˜ˆ์ œ ๋ฐ์ดํ„ฐ
example_companies = ["์‚ผ์„ฑ์ „์ž", "ํ† ์Šค", "์นด์นด์˜ค", "๋„ค์ด๋ฒ„", "LG์ „์ž", "ํ˜„๋Œ€์ž๋™์ฐจ", "CJ์ œ์ผ์ œ๋‹น", "ํ•˜์ด๋ธŒ", "์ฟ ํŒก", "๋ฐฐ๋‹ฌ์˜๋ฏผ์กฑ", "์‹ ํ•œ์€ํ–‰", "SKT", "ํฌ์Šค์ฝ”", "ํ˜„๋Œ€๊ฑด์„ค", "์•„๋ชจ๋ ˆํผ์‹œํ”ฝ"]
example_jobs = ["๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ", "ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ", "๋ฐ์ดํ„ฐ ์‚ฌ์ด์–ธํ‹ฐ์ŠคํŠธ", "๋งˆ์ผ€ํŒ…", "์˜์—…", "๊ธฐํš", "๋””์ž์ธ", "HR", "์žฌ๋ฌด", "A&R", "๊ฒฝ์˜๊ธฐํš", "ํ•ด์™ธ์˜์—…", "์˜จ๋ผ์ธ๋งˆ์ผ€ํŒ…", "์‹ํ’ˆ๋งˆ์ผ€ํŒ…", "HRM(์ธ์‚ฌ์šด์˜)"]
experience_levels = ["์‹ ์ž…", "๊ฒฝ๋ ฅ", "์ธํ„ด", "๊ธฐํƒ€"]
# ๊ณตํ†ต ํ•จ์ˆ˜๋“ค
def create_example_buttons(companies, jobs, company_input, job_input):
"""์˜ˆ์ œ ๋ฒ„ํŠผ๋“ค์„ ์ƒ์„ฑํ•˜๋Š” ํ•จ์ˆ˜"""
gr.Markdown("### ๐Ÿ’ก **์˜ˆ์ œ ํšŒ์‚ฌ**")
with gr.Row():
for company in companies[:5]:
btn = gr.Button(company, size="sm", variant="secondary")
btn.click(fn=lambda x=company: x, outputs=company_input)
with gr.Row():
for company in companies[5:10]:
btn = gr.Button(company, size="sm", variant="secondary")
btn.click(fn=lambda x=company: x, outputs=company_input)
gr.Markdown("### ๐Ÿ’ผ **์˜ˆ์ œ ์ง๋ฌด**")
with gr.Row():
for job in jobs[:5]:
btn = gr.Button(job, size="sm", variant="secondary")
btn.click(fn=lambda x=job: x, outputs=job_input)
with gr.Row():
for job in jobs[5:10]:
btn = gr.Button(job, size="sm", variant="secondary")
btn.click(fn=lambda x=job: x, outputs=job_input)
# 1. ์ผ๋ฐ˜์ ์ธ ๋ฉด์ ‘ ์งˆ๋ฌธ ์ƒ์„ฑ ํƒญ
def create_commonly_asked_tab():
if not available_features.get('commonly_asked'):
gr.Markdown("โŒ **์ผ๋ฐ˜์ ์ธ ๋ฉด์ ‘ ์งˆ๋ฌธ ์ƒ์„ฑ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.** (๋ชจ๋“ˆ ๋กœ๋“œ ์‹คํŒจ)")
return
gr.HTML("""
<div class="main-header">
<h2>๐ŸŽฏ ์ผ๋ฐ˜์ ์ธ ๋ฉด์ ‘ ์งˆ๋ฌธ ์ƒ์„ฑ</h2>
<p>ํšŒ์‚ฌ์™€ ์ง๋ฌด์— ๋งž์ถคํ˜• ๋ฉด์ ‘ ์งˆ๋ฌธ์„ AI๊ฐ€ ์ƒ์„ฑํ•ด๋“œ๋ฆฝ๋‹ˆ๋‹ค</p>
</div>
""")
with gr.Row():
with gr.Column(scale=2):
gr.Markdown("### ๐Ÿ“ **๊ธฐ๋ณธ ์ •๋ณด ์ž…๋ ฅ**")
company_input = gr.Textbox(label="๐Ÿข ํšŒ์‚ฌ๋ช…", placeholder="์˜ˆ: ์‚ผ์„ฑ์ „์ž, ํ† ์Šค, ์นด์นด์˜ค ๋“ฑ")
job_input = gr.Textbox(label="๐Ÿ’ผ ์ง๋ฌด", placeholder="์˜ˆ: ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ, ๋งˆ์ผ€ํŒ…, ๊ธฐํš ๋“ฑ")
with gr.Row():
experience_input = gr.Dropdown(label="๐Ÿ“Š ๊ฒฝ๋ ฅ ์ˆ˜์ค€", choices=experience_levels, value="์‹ ์ž…", interactive=True)
num_questions_input = gr.Dropdown(label="๐Ÿ“‹ ์ƒ์„ฑํ•  ์งˆ๋ฌธ ์ˆ˜", choices=[1, 2, 3, 4, 5], value=3, interactive=True)
common_questions_list = [
"์ž๊ธฐ์†Œ๊ฐœ๋ฅผ ํ•ด๋ณด์„ธ์š”", "์ง€์› ๋™๊ธฐ๊ฐ€ ๋ฌด์—‡์ธ๊ฐ€์š”", "๋ณธ์ธ์˜ ๊ฐ•์ ์€ ๋ฌด์—‡์ธ๊ฐ€์š”",
"๊ฐ€์žฅ ๋„์ „์ ์ธ ๊ฒฝํ—˜์€ ๋ฌด์—‡์ธ๊ฐ€์š”", "์„ฑ๊ณต ๊ฒฝํ—˜์„ ๋งํ•ด์ฃผ์„ธ์š”", "์‹คํŒจ ๊ฒฝํ—˜์„ ๋งํ•ด์ฃผ์„ธ์š”",
"์ž…์‚ฌ ํ›„ ํฌ๋ถ€๋Š” ๋ฌด์—‡์ธ๊ฐ€์š”", "์„ฑ๊ฒฉ์˜ ์žฅ๋‹จ์ ์„ ๋งํ•ด์ฃผ์„ธ์š”", "์กด๊ฒฝํ•˜๋Š” ์ธ๋ฌผ์€ ๋ˆ„๊ตฌ์ธ๊ฐ€์š”",
"๋งˆ์ง€๋ง‰์œผ๋กœ ํ•˜๊ณ  ์‹ถ์€ ๋ง์€?"
]
selected_questions = gr.CheckboxGroup(label="๐Ÿ“ ์ฐธ๊ณ ํ•  ์ผ๋ฐ˜ ์งˆ๋ฌธ (์„ ํƒ)", choices=common_questions_list, value=common_questions_list[:3])
generate_btn = gr.Button("๐ŸŽฏ ๋ฉด์ ‘ ์งˆ๋ฌธ ์ƒ์„ฑ", variant="primary", size="lg")
with gr.Column(scale=1):
create_example_buttons(example_companies, example_jobs, company_input, job_input)
gr.Markdown("### ๐Ÿ“‹ **์ƒ์„ฑ๋œ ๋ฉด์ ‘ ์งˆ๋ฌธ**")
result_output = gr.Markdown("์œ„ ์ •๋ณด๋ฅผ ์ž…๋ ฅํ•˜๊ณ  '๋ฉด์ ‘ ์งˆ๋ฌธ ์ƒ์„ฑ' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์„ธ์š”.")
def process_question_generation(company, job, experience, selected, num):
try:
content, _ = modules['commonly_asked'].generate_interview_questions(company, job, experience, selected, num)
return content
except Exception as e:
return f"โŒ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {e}"
generate_btn.click(
fn=process_question_generation,
inputs=[company_input, job_input, experience_input, selected_questions, num_questions_input],
outputs=result_output
)
# 2. ๋ฉด์ ‘ ์งˆ๋ฌธ ์ถ”์ฒœ ํƒญ
def create_question_recommendation_tab():
if not available_features.get('question_rec') or not openai_available:
gr.Markdown("โŒ **๋ฉด์ ‘ ์งˆ๋ฌธ ์ถ”์ฒœ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.** (๋ชจ๋“ˆ ๋กœ๋“œ ์‹คํŒจ ๋˜๋Š” API ํ‚ค ์—†์Œ)")
return
gr.HTML("""
<div class="main-header">
<h2>๐Ÿ’ก ๋ฉด์ ‘ ์งˆ๋ฌธ ์ถ”์ฒœ</h2>
<p>์ง๋ฌด, ํšŒ์‚ฌ๋ช…, ๊ฒฝ๋ ฅ ์ˆ˜์ค€์„ ์ž…๋ ฅํ•˜๋ฉด AI๊ฐ€ ๋งž์ถคํ˜• ์งˆ๋ฌธ์„ ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค</p>
</div>
""")
with gr.Row():
with gr.Column(scale=2):
gr.Markdown("### ๐Ÿ“ **์ •๋ณด ์ž…๋ ฅ**")
job_input = gr.Textbox(label="๐Ÿ’ผ ์ง๋ฌด", placeholder="์˜ˆ: ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ, ๋งˆ์ผ€ํŒ…, ๊ธฐํš ๋“ฑ")
company_input = gr.Textbox(label="๐Ÿข ํšŒ์‚ฌ๋ช…", placeholder="์˜ˆ: ํ† ์Šค, ์‚ผ์„ฑ์ „์ž, ๋„ค์ด๋ฒ„ ๋“ฑ")
experience_input = gr.Dropdown(label="๐Ÿ“Š ๊ฒฝ๋ ฅ ์ˆ˜์ค€", choices=experience_levels, value="์‹ ์ž…")
submit_btn = gr.Button("๐Ÿ’ก ๋ฉด์ ‘ ์งˆ๋ฌธ ์ถ”์ฒœ๋ฐ›๊ธฐ", variant="primary", size="lg")
with gr.Column(scale=1):
create_example_buttons(example_companies, example_jobs, company_input, job_input)
gr.Markdown("### ๐Ÿ’ฌ **์ถ”์ฒœ ๋ฉด์ ‘ ์งˆ๋ฌธ**")
result_output = gr.Textbox(label="", placeholder="์ถ”์ฒœ๋œ ๋ฉด์ ‘ ์งˆ๋ฌธ์ด ์—ฌ๊ธฐ์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.", lines=5, show_label=False, interactive=False)
def recommend_question(job, company, experience):
try:
if not client: return "โŒ OpenAI API ํ‚ค๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค."
prompt_path = current_dir / "question-recommendation" / "prompt.yaml"
with open(prompt_path, 'r', encoding='utf-8') as f:
prompts = yaml.safe_load(f)
result = modules['question_rec'].generate_question_recommendation(client, prompts, job, company, experience)
parsed = modules['question_rec'].parse_question_recommendation(result)
return parsed.get('recommended_question', "์งˆ๋ฌธ ์ƒ์„ฑ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.")
except Exception as e:
return f"โŒ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {e}"
submit_btn.click(fn=recommend_question, inputs=[job_input, company_input, experience_input], outputs=result_output)
# 3. ์ง๋ฌด๊ธฐ์ˆ ์„œ ์ƒ์„ฑ ํƒญ
def create_jd_recommendation_tab():
if not available_features.get('jd_rec'):
gr.Markdown("โŒ **์ง๋ฌด๊ธฐ์ˆ ์„œ ์ƒ์„ฑ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.** (๋ชจ๋“ˆ ๋กœ๋“œ ์‹คํŒจ)")
return
gr.HTML("""
<div class="main-header">
<h2>๐Ÿ“‹ AI ์ง๋ฌด๊ธฐ์ˆ ์„œ ์ƒ์„ฑ๊ธฐ</h2>
<p>๋งž์ถคํ˜• ์ง๋ฌด๊ธฐ์ˆ ์„œ๋กœ ์™„๋ฒฝํ•œ ์ž๊ธฐ์†Œ๊ฐœ์„œ๋ฅผ ์ค€๋น„ํ•˜์„ธ์š”</p>
</div>
""")
with gr.Row():
with gr.Column(scale=2):
gr.Markdown("### ๐Ÿ“ **๊ธฐ๋ณธ ์ •๋ณด ์ž…๋ ฅ**")
job_input = gr.Textbox(label="๐Ÿ’ผ ์ง๋ฌด", placeholder="์˜ˆ: ๊ฒฝ์˜๊ธฐํš, ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ, ์˜จ๋ผ์ธ๋งˆ์ผ€ํŒ… ๋“ฑ")
company_input = gr.Textbox(label="๐Ÿข ํšŒ์‚ฌ๋ช…", placeholder="์˜ˆ: ์‚ผ์„ฑ์ „์ž, ํ† ์Šค, ์นด์นด์˜ค ๋“ฑ")
experience_input = gr.Dropdown(label="๐Ÿ“ˆ ๊ฒฝ๋ ฅ ์ˆ˜์ค€", choices=experience_levels, value="์‹ ์ž…", interactive=True)
generate_btn = gr.Button("๐Ÿ“‹ ์ง๋ฌด๊ธฐ์ˆ ์„œ ์ƒ์„ฑ", variant="primary", size="lg")
with gr.Column(scale=1):
create_example_buttons(example_companies, example_jobs, company_input, job_input)
gr.Markdown("### ๐Ÿ“œ **์ƒ์„ฑ๋œ ์ง๋ฌด๊ธฐ์ˆ ์„œ**")
result_output = gr.Markdown("์œ„ ์ •๋ณด๋ฅผ ์ž…๋ ฅํ•˜๊ณ  '์ง๋ฌด๊ธฐ์ˆ ์„œ ์ƒ์„ฑ' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์„ธ์š”.")
def process_jd_generation(job, company, experience):
try:
content, _ = modules['jd_rec'].generate_jd_recommendation(job, company, experience)
return content
except Exception as e:
return f"โŒ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {e}"
generate_btn.click(fn=process_jd_generation, inputs=[job_input, company_input, experience_input], outputs=result_output)
# 4. ์‚ฐ์—… ๋ถ„๋ฅ˜ ํƒญ
def create_industry_classification_tab():
if not available_features.get('industry'):
gr.Markdown("โŒ **์‚ฐ์—… ๋ถ„๋ฅ˜ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.** (๋ชจ๋“ˆ ๋กœ๋“œ ์‹คํŒจ)")
return
gr.HTML("""
<div class="main-header">
<h2>๐Ÿท๏ธ AI ์‚ฐ์—… ๋ถ„๋ฅ˜๊ธฐ</h2>
<p>์ง๋ฌด์™€ ํšŒ์‚ฌ๋ช…์„ ๋ฐ”ํƒ•์œผ๋กœ ์ •ํ™•ํ•œ ์‚ฐ์—… ๋ถ„์•ผ๋ฅผ ๋ถ„๋ฅ˜ํ•ฉ๋‹ˆ๋‹ค</p>
</div>
""")
with gr.Row():
with gr.Column(scale=2):
gr.Markdown("### ๐Ÿ“ **๊ธฐ๋ณธ ์ •๋ณด ์ž…๋ ฅ**")
job_input = gr.Textbox(label="๐Ÿ’ผ ์ง๋ฌด", placeholder="์˜ˆ: ๊ฒฝ์˜๊ธฐํš, ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ, ์˜จ๋ผ์ธ๋งˆ์ผ€ํŒ… ๋“ฑ")
company_input = gr.Textbox(label="๐Ÿข ํšŒ์‚ฌ๋ช…", placeholder="์˜ˆ: ์‚ผ์„ฑ์ „์ž, ํ† ์Šค, ์นด์นด์˜ค ๋“ฑ")
classify_btn = gr.Button("๐Ÿท๏ธ ์‚ฐ์—… ๋ถ„๋ฅ˜", variant="primary", size="lg")
with gr.Column(scale=1):
create_example_buttons(example_companies, example_jobs, company_input, job_input)
gr.Markdown("### ๐Ÿ“‘ **๋ถ„๋ฅ˜ ๊ฒฐ๊ณผ**")
result_output = gr.Markdown("์œ„ ์ •๋ณด๋ฅผ ์ž…๋ ฅํ•˜๊ณ  '์‚ฐ์—… ๋ถ„๋ฅ˜' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์„ธ์š”.")
def process_classification(job, company):
try:
content, _ = modules['industry'].classify_industry(job, company)
return content
except Exception as e:
return f"โŒ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {e}"
classify_btn.click(fn=process_classification, inputs=[job_input, company_input], outputs=result_output)
# 5. ์ž์†Œ์„œ ์ปจํ…์ŠคํŠธ ๋ฆฌํฌํŠธ ํƒญ
def create_jasoseo_context_tab():
if not available_features.get('jasoseo'):
gr.Markdown("โŒ **์ž์†Œ์„œ ์ปจํ…์ŠคํŠธ ๋ฆฌํฌํŠธ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.** (๋ชจ๋“ˆ ๋กœ๋“œ ์‹คํŒจ)")
return
gr.HTML("""
<div class="main-header">
<h2>๐Ÿ“Š ์ž์†Œ์„œ ์ปจํ…์ŠคํŠธ ๋ฆฌํฌํŠธ</h2>
<p>๊ธฐ์—…๊ณผ ์ง๋ฌด์— ๋Œ€ํ•œ ์ข…ํ•ฉ์ ์ธ ๋ถ„์„์œผ๋กœ ์™„๋ฒฝํ•œ ์ž๊ธฐ์†Œ๊ฐœ์„œ๋ฅผ ์ค€๋น„ํ•˜์„ธ์š”</p>
</div>
""")
with gr.Row():
with gr.Column(scale=2):
gr.Markdown("### ๐Ÿ“ **๊ธฐ๋ณธ ์ •๋ณด ์ž…๋ ฅ**")
job_input = gr.Textbox(label="๐Ÿ’ผ ์ง๋ฌด", placeholder="์˜ˆ: ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ, ๊ฒฝ์˜๊ธฐํš, ๋งˆ์ผ€ํŒ… ๋“ฑ")
company_input = gr.Textbox(label="๐Ÿข ํšŒ์‚ฌ๋ช…", placeholder="์˜ˆ: ํ† ์Šค, ์‚ผ์„ฑ์ „์ž, ์นด์นด์˜ค ๋“ฑ")
experience_input = gr.Dropdown(label="๐Ÿ“ˆ ๊ฒฝ๋ ฅ ์ˆ˜์ค€", choices=experience_levels, value="์‹ ์ž…", interactive=True)
generate_btn = gr.Button("๐Ÿ“Š ๋ฆฌํฌํŠธ ์ƒ์„ฑ", variant="primary", size="lg")
with gr.Column(scale=1):
create_example_buttons(example_companies, example_jobs, company_input, job_input)
gr.Markdown("### ๐Ÿ“ˆ **์ปจํ…์ŠคํŠธ ๋ฆฌํฌํŠธ**")
result_output = gr.Markdown("์œ„ ์ •๋ณด๋ฅผ ์ž…๋ ฅํ•˜๊ณ  '๋ฆฌํฌํŠธ ์ƒ์„ฑ' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์„ธ์š”.")
def process_report_generation(job, company, experience):
try:
content, _ = modules['jasoseo'].generate_context_report(job, company, experience)
return content
except Exception as e:
return f"โŒ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {e}"
generate_btn.click(fn=process_report_generation, inputs=[job_input, company_input, experience_input], outputs=result_output)
# 6. ๊ธฐ์—… ๊ทœ๋ชจ ๋ถ„๋ฅ˜ ํƒญ
def create_company_size_tab():
if not available_features.get('company_size'):
gr.Markdown("โŒ **๊ธฐ์—… ๊ทœ๋ชจ ๋ถ„๋ฅ˜ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.** (๋ชจ๋“ˆ ๋กœ๋“œ ์‹คํŒจ)")
return
gr.HTML("""
<div class="main-header">
<h2>๐Ÿข AI ๊ธฐ์—… ๊ทœ๋ชจ ์˜ˆ์ธก๊ธฐ</h2>
<p>์‹ค์‹œ๊ฐ„ ์›น ์ •๋ณด๋ฅผ ํ™œ์šฉํ•œ ๊ธฐ์—… ์ •๋ณด ๋ถ„์„</p>
</div>
""")
with gr.Row():
with gr.Column(scale=2):
gr.Markdown("### ๐Ÿ“ **๊ธฐ์—… ์ •๋ณด ์ž…๋ ฅ**")
company_input = gr.Textbox(label="๐Ÿข ๊ธฐ์—…๋ช… ์ž…๋ ฅ", placeholder="๋ถ„์„ํ•˜๊ณ  ์‹ถ์€ ๊ธฐ์—…๋ช…์„ ์ž…๋ ฅํ•˜์„ธ์š” (์˜ˆ: ์‚ผ์„ฑ์ „์ž, ์นด์นด์˜ค ๋“ฑ)")
analyze_btn = gr.Button("๐Ÿ” ๊ธฐ์—… ๊ทœ๋ชจ ๋ถ„์„", variant="primary", size="lg")
with gr.Column(scale=1):
gr.Markdown("""
### โ„น๏ธ **๋ถ„๋ฅ˜ ๊ธฐ์ค€**
- **๋Œ€๊ธฐ์—…**: ๋งค์ถœ 1์กฐ์› ์ด์ƒ
- **์ค‘๊ฒฌ๊ธฐ์—…**: ๋งค์ถœ 1000์–ต-1์กฐ์›
- **์ค‘์†Œ๊ธฐ์—…**: ๋งค์ถœ 1000์–ต์› ๋ฏธ๋งŒ
- **์Šคํƒ€ํŠธ์—…**: ์„ค๋ฆฝ 10๋…„ ์ด๋‚ด
- **์™ธ๊ตญ๊ณ„๊ธฐ์—…**: ํ•ด์™ธ ๋ณธ์‚ฌ
- **๊ณต๊ณต๊ธฐ๊ด€/๊ณต๊ธฐ์—…**: ์ •๋ถ€ ์ถœ์ž/์ถœ์—ฐ
""")
gr.Markdown("### ๐Ÿ’ผ **์˜ˆ์ œ ๊ธฐ์—… ์„ ํƒ** (ํด๋ฆญํ•˜๋ฉด ์ž๋™ ์ž…๋ ฅ๋ฉ๋‹ˆ๋‹ค)")
example_company_names = ["์‚ผ์„ฑ์ „์ž", "ํ˜„๋Œ€์ž๋™์ฐจ", "SKํ•˜์ด๋‹‰์Šค", "ํฌ์Šค์ฝ”ํ™€๋”ฉ์Šค", "ํ† ์Šค", "์นด์นด์˜ค", "๋„ค์ด๋ฒ„", "์ฟ ํŒก", "๋ฐฐ๋‹ฌ์˜๋ฏผ์กฑ", "๋‹น๊ทผ๋งˆ์ผ“"]
with gr.Row():
for company in example_company_names[:5]:
btn = gr.Button(company, size="sm", variant="secondary")
btn.click(fn=lambda x=company: x, outputs=company_input)
with gr.Row():
for company in example_company_names[5:]:
btn = gr.Button(company, size="sm", variant="secondary")
btn.click(fn=lambda x=company: x, outputs=company_input)
gr.Markdown("### ๐Ÿ“Š **๋ถ„์„ ๊ฒฐ๊ณผ**")
result_output = gr.Markdown("๊ธฐ์—…๋ช…์„ ์ž…๋ ฅํ•˜๊ณ  '๊ธฐ์—… ๊ทœ๋ชจ ๋ถ„์„' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์„ธ์š”.")
def process_analysis_result(company):
try:
content, _ = modules['company_size'].analyze_company_size(company)
return content
except Exception as e:
return f"โŒ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {e}"
analyze_btn.click(fn=process_analysis_result, inputs=[company_input], outputs=result_output)
# ๋ฉ”์ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ƒ์„ฑ
def create_main_app():
with gr.Blocks(
title="๐Ÿš€ JasoSeo Agent - ์ทจ์—… ์ง€์› AI ๋„๊ตฌ",
theme=gr.themes.Soft(primary_hue="purple", secondary_hue="pink", neutral_hue="gray"),
css=common_css
) as app:
gr.HTML("""
<div style="text-align: center; padding: 30px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 15px; margin-bottom: 30px;">
<h1 style="font-size: 32px; margin-bottom: 10px;">๐Ÿš€ JasoSeo Agent</h1>
<p style="font-size: 18px; margin-bottom: 0; opacity: 0.9;">AI ๊ธฐ๋ฐ˜ ์ทจ์—… ์ง€์› ํ†ตํ•ฉ ํ”Œ๋žซํผ</p>
</div>
""")
status_items = [name for name, ok in available_features.items() if ok]
status_text = f"โœ… ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๊ธฐ๋Šฅ ({len(status_items)}/{len(available_features)}): {', '.join(status_items)}" if status_items else "โŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๊ธฐ๋Šฅ์ด ์—†์Šต๋‹ˆ๋‹ค."
gr.Markdown(f"**{status_text}**")
with gr.Tabs(elem_classes="tab-container"):
with gr.Tab("๐ŸŽฏ ๋ฉด์ ‘ ์งˆ๋ฌธ ์ƒ์„ฑ", elem_id="commonly-asked-tab"):
create_commonly_asked_tab()
with gr.Tab("๐Ÿ’ก ์งˆ๋ฌธ ์ถ”์ฒœ", elem_id="question-recommendation-tab"):
create_question_recommendation_tab()
with gr.Tab("๐Ÿ“‹ ์ง๋ฌด๊ธฐ์ˆ ์„œ", elem_id="jd-recommendation-tab"):
create_jd_recommendation_tab()
with gr.Tab("๐Ÿท๏ธ ์‚ฐ์—… ๋ถ„๋ฅ˜", elem_id="industry-classification-tab"):
create_industry_classification_tab()
with gr.Tab("๐Ÿ“Š ์ปจํ…์ŠคํŠธ ๋ฆฌํฌํŠธ", elem_id="jasoseo-context-tab"):
create_jasoseo_context_tab()
with gr.Tab("๐Ÿข ๊ธฐ์—… ๊ทœ๋ชจ", elem_id="company-size-tab"):
create_company_size_tab()
return app
if __name__ == "__main__":
if not os.getenv("OPENAI_API_KEY"):
print("โš ๏ธ OPENAI_API_KEY ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์ผ๋ถ€ ๊ธฐ๋Šฅ์ด ์ œํ•œ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.")
print("\n๐Ÿ“Š ๋ชจ๋“ˆ ๋กœ๋“œ ์ƒํƒœ:")
for feature, available in available_features.items():
print(f" {'โœ…' if available else 'โŒ'} {feature}")
print("\n๐Ÿš€ JasoSeo Agent ์‹œ์ž‘ ์ค‘...")
app = create_main_app()
app.launch(share=True, show_error=True, debug=True)