kyle8581's picture
.
594e237
import gradio as gr
from llm_functions import generate_interview_questions
# LLM ๊ด€๋ จ ํ•จ์ˆ˜๋“ค์€ llm_functions.py๋กœ ์ด๋™๋จ
# ์˜ˆ์ œ ๋ฐ์ดํ„ฐ
example_companies = ["์‚ผ์„ฑ์ „์ž", "ํ† ์Šค", "์นด์นด์˜ค", "๋„ค์ด๋ฒ„", "LG์ „์ž", "ํ˜„๋Œ€์ž๋™์ฐจ", "CJ์ œ์ผ์ œ๋‹น", "ํ•˜์ด๋ธŒ", "์ฟ ํŒก", "๋ฐฐ๋‹ฌ์˜๋ฏผ์กฑ"]
example_jobs = ["๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ", "ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ", "๋ฐ์ดํ„ฐ ์‚ฌ์ด์–ธํ‹ฐ์ŠคํŠธ", "๋งˆ์ผ€ํŒ…", "์˜์—…", "๊ธฐํš", "๋””์ž์ธ", "HR", "์žฌ๋ฌด", "A&R"]
experience_levels = ["์‹ ์ž…", "๊ฒฝ๋ ฅ", "์ธํ„ด", "๊ธฐํƒ€"]
common_questions_list = [
"์ž๊ธฐ์†Œ๊ฐœ๋ฅผ ํ•ด๋ณด์„ธ์š”",
"์ง€์› ๋™๊ธฐ๊ฐ€ ๋ฌด์—‡์ธ๊ฐ€์š”",
"๋ณธ์ธ์˜ ๊ฐ•์ ์€ ๋ฌด์—‡์ธ๊ฐ€์š”",
"๊ฐ€์žฅ ๋„์ „์ ์ธ ๊ฒฝํ—˜์€ ๋ฌด์—‡์ธ๊ฐ€์š”",
"์„ฑ๊ณต ๊ฒฝํ—˜์„ ๋งํ•ด์ฃผ์„ธ์š”",
"์‹คํŒจ ๊ฒฝํ—˜์„ ๋งํ•ด์ฃผ์„ธ์š”",
"์ž…์‚ฌ ํ›„ ํฌ๋ถ€๋Š” ๋ฌด์—‡์ธ๊ฐ€์š”",
"์„ฑ๊ฒฉ์˜ ์žฅ๋‹จ์ ์„ ๋งํ•ด์ฃผ์„ธ์š”",
"์กด๊ฒฝํ•˜๋Š” ์ธ๋ฌผ์€ ๋ˆ„๊ตฌ์ธ๊ฐ€์š”",
"๋งˆ์ง€๋ง‰์œผ๋กœ ํ•˜๊ณ  ์‹ถ์€ ๋ง์€?"
]
# generate_interview_questions ํ•จ์ˆ˜๋Š” llm_functions.py๋กœ ์ด๋™๋จ
def create_question_cards(questions):
"""
์ƒ์„ฑ๋œ ์งˆ๋ฌธ๋“ค์„ ์นด๋“œ ํ˜•ํƒœ๋กœ ํ‘œ์‹œํ•˜๋Š” HTML ์ƒ์„ฑ
"""
if not questions:
return "<div style='text-align: center; color: #6B7280; padding: 20px;'>์งˆ๋ฌธ์„ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”</div>"
cards_html = "<div style='display: flex; flex-direction: column; gap: 15px;'>"
colors = ["#EBF8FF", "#ECFDF5", "#FEF2F2", "#F5F3FF", "#FFF7ED"]
border_colors = ["#1E40AF", "#059669", "#DC2626", "#7C3AED", "#EA580C"]
for i, question in enumerate(questions):
color = colors[i % len(colors)]
border_color = border_colors[i % len(border_colors)]
cards_html += f"""
<div style="
background-color: {color};
border: 2px solid {border_color};
border-radius: 12px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
">
<div style="
font-weight: bold;
color: {border_color};
font-size: 16px;
margin-bottom: 10px;
">์งˆ๋ฌธ {i+1}</div>
<div style="
color: #374151;
font-size: 15px;
line-height: 1.5;
">{question}</div>
</div>
"""
cards_html += "</div>"
return cards_html
def process_question_generation(company_name, job_title, experience_level, selected_questions, num_questions):
"""
์งˆ๋ฌธ ์ƒ์„ฑ ๊ฒฐ๊ณผ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  UI์— ํ‘œ์‹œํ•  ํ˜•ํƒœ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜
"""
try:
content, questions = generate_interview_questions(company_name, job_title, experience_level, selected_questions, num_questions)
question_cards = create_question_cards(questions)
return content, question_cards
except Exception as e:
error_content = f"""## โŒ ์˜ค๋ฅ˜ ๋ฐœ์ƒ
์งˆ๋ฌธ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.
**์˜ค๋ฅ˜ ๋‚ด์šฉ:** {str(e)}
๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.
"""
error_cards = create_question_cards([])
return error_content, error_cards
# ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ
class AppState:
def __init__(self):
self.companies = ["ํ† ์Šค", "๋„ค์ด๋ฒ„", "์นด์นด์˜ค", "์‚ผ์„ฑ์ „์ž", "LG์ „์ž", "ํ˜„๋Œ€์ž๋™์ฐจ", "SKํ•˜์ด๋‹‰์Šค", "CJ์ œ์ผ์ œ๋‹น", "ํ•˜์ด๋ธŒ", "ํ˜„๋Œ€๊ฑด์„ค"]
self.jobs = ["๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž", "ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž", "๋ฐ์ดํ„ฐ ์‚ฌ์ด์–ธํ‹ฐ์ŠคํŠธ", "๋งˆ์ผ€ํŒ…", "์˜์—…", "๊ธฐํš", "๋””์ž์ด๋„ˆ", "A&R", "ํ•ด์™ธ์˜์—…", "์‚ฌ์—…๊ธฐํš"]
self.questions = common_questions_list.copy()
app_state = AppState()
# ๋” ์ด์ƒ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ํ•จ์ˆ˜๋“ค ์ œ๊ฑฐ๋จ
def add_company(new_company):
"""์ƒˆ ํšŒ์‚ฌ ์ถ”๊ฐ€"""
if new_company and new_company.strip() and new_company.strip() not in app_state.companies:
app_state.companies.append(new_company.strip())
return gr.Dropdown.update(choices=app_state.companies), ""
return gr.Dropdown.update(), ""
def add_job(new_job):
"""์ƒˆ ์ง๋ฌด ์ถ”๊ฐ€"""
if new_job and new_job.strip() and new_job.strip() not in app_state.jobs:
app_state.jobs.append(new_job.strip())
return gr.Dropdown.update(choices=app_state.jobs), ""
return gr.Dropdown.update(), ""
def add_question(new_question):
"""์ƒˆ ์ผ๋ฐ˜ ์งˆ๋ฌธ ์ถ”๊ฐ€"""
if new_question and new_question.strip() and new_question.strip() not in app_state.questions:
app_state.questions.append(new_question.strip())
return gr.CheckboxGroup.update(choices=app_state.questions), ""
def create_interface():
"""
Gradio ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ
"""
with gr.Blocks(
title="๐ŸŽฏ AI ๋ฉด์ ‘ ์งˆ๋ฌธ ์ƒ์„ฑ๊ธฐ",
theme=gr.themes.Soft(),
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;
}
"""
) as demo:
# ํ—ค๋”
gr.HTML("""
<div class="main-header">
<h1>๐ŸŽฏ AI ๋ฉด์ ‘ ์งˆ๋ฌธ ์ƒ์„ฑ๊ธฐ</h1>
<p>ํšŒ์‚ฌ์™€ ์ง๋ฌด์— ๋งž์ถคํ˜• ๋ฉด์ ‘ ์งˆ๋ฌธ์„ AI๊ฐ€ ์ƒ์„ฑํ•ด๋“œ๋ฆฝ๋‹ˆ๋‹ค</p>
</div>
""")
# ์„ค๋ช…
gr.Markdown("""
### ๐Ÿš€ **์‚ฌ์šฉ ๋ฐฉ๋ฒ•**
1. **ํšŒ์‚ฌ๋ช…**: ์ง€์›ํ•˜๊ณ ์ž ํ•˜๋Š” ํšŒ์‚ฌ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”
2. **์ง๋ฌด**: ์ง€์› ์ง๋ฌด๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”
3. **๊ฒฝ๋ ฅ ์ˆ˜์ค€**: ๋ณธ์ธ์˜ ๊ฒฝ๋ ฅ ์ˆ˜์ค€์„ ์„ ํƒํ•˜์„ธ์š”
4. **์ผ๋ฐ˜ ์งˆ๋ฌธ**: ์ฐธ๊ณ ํ•  ์ผ๋ฐ˜์ ์ธ ๋ฉด์ ‘ ์งˆ๋ฌธ๋“ค์„ ์„ ํƒํ•˜์„ธ์š”
5. **์ƒ์„ฑ**: '์งˆ๋ฌธ ์ƒ์„ฑ' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์—ฌ ๋งž์ถคํ˜• ์งˆ๋ฌธ์„ ๋ฐ›์•„๋ณด์„ธ์š”
โœจ **ํŠน์ง•**: ํšŒ์‚ฌ์˜ ํŠน์„ฑ, ์ง๋ฌด ์š”๊ตฌ์‚ฌํ•ญ, ๊ฒฝ๋ ฅ ์ˆ˜์ค€์„ ๋ชจ๋‘ ๊ณ ๋ คํ•œ ๊ตฌ์ฒด์ ์ด๊ณ  ํ˜„์‹ค์ ์ธ ์งˆ๋ฌธ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
""")
with gr.Row():
with gr.Column(scale=2):
# ์ž…๋ ฅ ์„น์…˜
gr.HTML('<div class="input-section">')
gr.Markdown("### ๐Ÿ“ **๊ธฐ๋ณธ ์ •๋ณด ์ž…๋ ฅ**")
with gr.Row():
company_input = gr.Textbox(
label="๐Ÿข ํšŒ์‚ฌ๋ช…",
placeholder="์˜ˆ: ์‚ผ์„ฑ์ „์ž, ํ† ์Šค, ์นด์นด์˜ค ๋“ฑ",
value="",
scale=2,
elem_id="company_input"
)
job_input = gr.Textbox(
label="๐Ÿ’ผ ์ง๋ฌด",
placeholder="์˜ˆ: ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ, ๋งˆ์ผ€ํŒ…, ๊ธฐํš ๋“ฑ",
value="",
scale=2,
elem_id="job_input"
)
with gr.Row():
experience_input = gr.Dropdown(
label="๐Ÿ“Š ๊ฒฝ๋ ฅ ์ˆ˜์ค€",
choices=experience_levels,
value="์‹ ์ž…",
interactive=True,
scale=2
)
num_questions_input = gr.Dropdown(
label="๐Ÿ”ข ์งˆ๋ฌธ ๊ฐœ์ˆ˜",
choices=[1, 2, 3, 4, 5],
value=3,
interactive=True,
scale=1
)
common_questions_input = gr.CheckboxGroup(
label="๐Ÿ“‹ ์ฐธ๊ณ ํ•  ์ผ๋ฐ˜ ๋ฉด์ ‘ ์งˆ๋ฌธ (3-5๊ฐœ ์„ ํƒ ๊ถŒ์žฅ)",
choices=common_questions_list,
value=common_questions_list[:4],
interactive=True
)
generate_btn = gr.Button(
"๐ŸŽฏ ๋งž์ถคํ˜• ์งˆ๋ฌธ ์ƒ์„ฑ",
variant="primary",
size="lg"
)
gr.HTML('</div>')
with gr.Column(scale=1):
# ์˜ˆ์ œ ๋ฐ ๊ฐ€์ด๋“œ
gr.HTML('<div class="example-section">')
# ์‚ฌ์šฉ์ž ์ •์˜ ํšŒ์‚ฌ ์ถ”๊ฐ€
gr.Markdown("### ๐Ÿข **ํšŒ์‚ฌ ๊ด€๋ฆฌ**")
with gr.Row():
new_company_input = gr.Textbox(
label="์ƒˆ ํšŒ์‚ฌ ์ถ”๊ฐ€",
placeholder="ํšŒ์‚ฌ๋ช… ์ž…๋ ฅ",
scale=2
)
add_company_btn = gr.Button("์ถ”๊ฐ€", size="sm", scale=1)
# ์˜ˆ์ œ ํšŒ์‚ฌ ๋“œ๋กญ๋‹ค์šด
company_dropdown = gr.Dropdown(
label="์˜ˆ์ œ ํšŒ์‚ฌ ์„ ํƒ",
choices=app_state.companies,
value=None,
interactive=True
)
# ์‚ฌ์šฉ์ž ์ •์˜ ์ง๋ฌด ์ถ”๊ฐ€
gr.Markdown("### ๐Ÿ’ผ **์ง๋ฌด ๊ด€๋ฆฌ**")
with gr.Row():
new_job_input = gr.Textbox(
label="์ƒˆ ์ง๋ฌด ์ถ”๊ฐ€",
placeholder="์ง๋ฌด๋ช… ์ž…๋ ฅ",
scale=2
)
add_job_btn = gr.Button("์ถ”๊ฐ€", size="sm", scale=1)
# ์˜ˆ์ œ ์ง๋ฌด ๋“œ๋กญ๋‹ค์šด
job_dropdown = gr.Dropdown(
label="์˜ˆ์ œ ์ง๋ฌด ์„ ํƒ",
choices=app_state.jobs,
value=None,
interactive=True
)
# ์‚ฌ์šฉ์ž ์ •์˜ ์ผ๋ฐ˜ ์งˆ๋ฌธ ์ถ”๊ฐ€
gr.Markdown("### ๐Ÿ“‹ **์ผ๋ฐ˜ ์งˆ๋ฌธ ๊ด€๋ฆฌ**")
with gr.Row():
new_question_input = gr.Textbox(
label="์ƒˆ ์ผ๋ฐ˜ ์งˆ๋ฌธ ์ถ”๊ฐ€",
placeholder="์งˆ๋ฌธ ๋‚ด์šฉ ์ž…๋ ฅ",
scale=2
)
add_question_btn = gr.Button("์ถ”๊ฐ€", size="sm", scale=1)
gr.HTML('</div>')
# ๊ฒฐ๊ณผ ์ถœ๋ ฅ ์„น์…˜
with gr.Row():
with gr.Column(scale=2):
gr.Markdown("### ๐Ÿ“‹ **์ƒ์„ฑ ๊ฒฐ๊ณผ**")
result_output = gr.Markdown(
value="๊ธฐ๋ณธ ์ •๋ณด๋ฅผ ์ž…๋ ฅํ•˜๊ณ  '๋งž์ถคํ˜• ์งˆ๋ฌธ ์ƒ์„ฑ' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์„ธ์š”.",
elem_classes=["result-output"]
)
with gr.Column(scale=1):
gr.Markdown("### ๐ŸŽฏ **์งˆ๋ฌธ ์นด๋“œ**")
question_cards = gr.HTML(
value="<div style='text-align: center; color: #6B7280; padding: 20px;'>์งˆ๋ฌธ์„ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”</div>",
elem_classes=["question-cards"]
)
# ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ์—ฐ๊ฒฐ
add_company_btn.click(
fn=add_company,
inputs=[new_company_input],
outputs=[company_dropdown, new_company_input]
)
add_job_btn.click(
fn=add_job,
inputs=[new_job_input],
outputs=[job_dropdown, new_job_input]
)
add_question_btn.click(
fn=add_question,
inputs=[new_question_input],
outputs=[common_questions_input, new_question_input]
)
# ๋“œ๋กญ๋‹ค์šด ์„ ํƒ ์‹œ ์ž…๋ ฅ ํ•„๋“œ์— ์ž๋™ ์ž…๋ ฅ
company_dropdown.change(
fn=lambda x: x if x else "",
inputs=[company_dropdown],
outputs=[company_input]
)
job_dropdown.change(
fn=lambda x: x if x else "",
inputs=[job_dropdown],
outputs=[job_input]
)
# ์ƒ์„ฑ ๋ฒ„ํŠผ ํด๋ฆญ ์ด๋ฒคํŠธ
generate_btn.click(
fn=process_question_generation,
inputs=[company_input, job_input, experience_input, common_questions_input, num_questions_input],
outputs=[result_output, question_cards],
api_name="generate_questions"
)
# ํ‘ธํ„ฐ
gr.Markdown("""
---
**๐Ÿ’ก ์ƒ์„ฑ๋œ ์งˆ๋ฌธ ํ™œ์šฉ ํŒ**:
- ๊ฐ ์งˆ๋ฌธ์— ๋Œ€ํ•ด STAR(Situation, Task, Action, Result) ๊ธฐ๋ฒ•์œผ๋กœ ๋‹ต๋ณ€์„ ์ค€๋น„ํ•ด๋ณด์„ธ์š”
- ํšŒ์‚ฌ์™€ ์ง๋ฌด์— ๋Œ€ํ•œ ์‚ฌ์ „ ์กฐ์‚ฌ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ๊ตฌ์ฒด์ ์ธ ์‚ฌ๋ก€๋ฅผ ์ค€๋น„ํ•˜์„ธ์š”
- ์ƒ์„ฑ๋œ ์งˆ๋ฌธ์„ ๋ฐ”ํƒ•์œผ๋กœ ์ถ”๊ฐ€ ์งˆ๋ฌธ๋“ค๋„ ์˜ˆ์ƒํ•ด๋ณด์„ธ์š”
๐Ÿค– **Powered by**: OpenAI GPT-4o with Web Search
""")
return demo
if __name__ == "__main__":
# Gradio ์•ฑ ์‹คํ–‰
demo = create_interface()
demo.launch(
server_name="0.0.0.0",
# server_port=7864,
share=True,
show_error=True
)