f2sdfss-2 / app.py
ssboost's picture
Create app.py
2ef5632 verified
import gradio as gr
import os
import tempfile
import datetime
import pytz
from gradio_client import Client, handle_file
import dotenv
# ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๋กœ๋“œ
dotenv.load_dotenv()
# API ์—”๋“œํฌ์ธํŠธ๋ฅผ ํ™˜๊ฒฝ๋ณ€์ˆ˜์—์„œ ๊ฐ€์ ธ์˜ด (๋กœ๊ทธ์— ์ถœ๋ ฅํ•˜์ง€ ์•Š์Œ)
API_ENDPOINT = os.getenv("API_ENDPOINT")
if not API_ENDPOINT:
raise ValueError("API_ENDPOINT ํ™˜๊ฒฝ๋ณ€์ˆ˜๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
# ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” (๋กœ๊ทธ์— ์ถœ๋ ฅํ•˜์ง€ ์•Š์Œ)
client = Client(API_ENDPOINT)
# ===================== ์‚ฌ์šฉ ๊ฐ€์ด๋“œ HTML ์ •์˜ =====================
fontawesome_link = """
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" crossorigin="anonymous" referrerpolicy="no-referrer" />
"""
# ===================== CSS ์Šคํƒ€์ผ ์ •์˜ =====================
custom_css = """
:root {
--primary-color: #FB7F0D;
--secondary-color: #ff9a8b;
--accent-color: #FF6B6B;
--background-color: #FFF3E9;
--card-bg: #ffffff;
--text-color: #334155;
--border-radius: 18px;
--shadow: 0 8px 30px rgba(251, 127, 13, 0.08);
}
/* โ”€โ”€ ํƒญ ๋‚ด๋ถ€ ํŒจ๋„ ๋ฐฐ๊ฒฝ ์ œ๊ฑฐ โ”€โ”€ */
.gr-tabs-panel {
background-color: var(--background-color) !important;
box-shadow: none !important;
}
.gr-tabs-panel::before,
.gr-tabs-panel::after {
display: none !important;
content: none !important;
}
/* โ”€โ”€ ๊ทธ๋ฃน ๋ž˜ํผ ๋ฐฐ๊ฒฝ ์™„์ „ ์ œ๊ฑฐ โ”€โ”€ */
.custom-section-group,
.gr-block.gr-group {
background-color: var(--background-color) !important;
box-shadow: none !important;
}
.custom-section-group::before,
.custom-section-group::after,
.gr-block.gr-group::before,
.gr-block.gr-group::after {
display: none !important;
content: none !important;
}
/* ๊ทธ๋ฃน ์ปจํ…Œ์ด๋„ˆ ๋ฐฐ๊ฒฝ์„ ์•„์ด๋ณด๋ฆฌ๋กœ, ๊ทธ๋ฆผ์ž ์ œ๊ฑฐ */
.custom-section-group {
background-color: var(--background-color) !important;
box-shadow: none !important;
}
/* ์ƒ๋‹จยทํ•˜๋‹จ์— ๊ทธ๋ ค์ง€๋Š” ํšŒ์ƒ‰ ์บก(๋‘ฅ๊ทผ ๋ชจ์„œ๋ฆฌ) ์ œ๊ฑฐ */
.custom-section-group::before,
.custom-section-group::after {
display: none !important;
content: none !important;
}
body {
font-family: 'Pretendard', 'Noto Sans KR', -apple-system, BlinkMacSystemFont, sans-serif;
background-color: var(--background-color);
color: var(--text-color);
line-height: 1.6;
margin: 0;
padding: 0;
}
.gradio-container {
width: 100%; /* ์ „์ฒด ๋„ˆ๋น„ 100% ๊ณ ์ • */
margin: 0 auto;
padding: 20px;
background-color: var(--background-color);
}
/* ํ—ค๋” ์Šคํƒ€์ผ - ์ฃผํ™ฉ์ƒ‰ ๋ฐ•์Šค ํ˜•ํƒœ๋กœ ๋ณ€๊ฒฝ */
.custom-header {
background: #FF7F00; /* ๋‹จ์ƒ‰ ์ฃผํ™ฉ์ƒ‰ */
padding: 2rem;
border-radius: 15px; /* ๋ผ์šด๋“œ ์ฒ˜๋ฆฌ๋ฅผ ์•ฝํ•˜๊ฒŒ ์กฐ์ • */
margin-bottom: 20px;
box-shadow: var(--shadow);
text-align: center;
}
.custom-header h1 {
margin: 0;
font-size: 2.5rem;
font-weight: 700;
color: black; /* ๊ธ€์ž์ƒ‰์„ ๊ฒ€์€์ƒ‰์œผ๋กœ ๋ณ€๊ฒฝ */
}
.custom-header p {
margin: 10px 0 0;
font-size: 1.2rem;
color: black; /* ์†Œ์ œ๋ชฉ๋„ ๊ฒ€์€์ƒ‰์œผ๋กœ ๋ณ€๊ฒฝ */
}
/* ์ฝ˜ํ…์ธ  ๋ฐ•์Šค (ํ”„๋ ˆ์ž„) ์Šคํƒ€์ผ */
.custom-frame {
background-color: var(--card-bg);
border: 1px solid rgba(0, 0, 0, 0.04);
border-radius: var(--border-radius);
padding: 20px;
margin: 10px 0;
box-shadow: var(--shadow);
}
/* ์„น์…˜ ๊ทธ๋ฃน ์Šคํƒ€์ผ - ํšŒ์ƒ‰ ๋ฐฐ๊ฒฝ ์™„์ „ ์ œ๊ฑฐ */
.custom-section-group {
margin-top: 20px;
padding: 0;
border: none;
border-radius: 0;
background-color: var(--background-color); /* ํšŒ์ƒ‰ โ†’ ์•„์ด๋ณด๋ฆฌ(์ „์ฒด ๋ฐฐ๊ฒฝ์ƒ‰) */
box-shadow: none !important; /* ํ˜น์‹œ ๋‚จ์•„์žˆ๋Š” ๊ทธ๋ฆผ์ž๋„ ๊ฐ™์ด ์ œ๊ฑฐ */
}
/* ๋ฒ„ํŠผ ์Šคํƒ€์ผ - ๊ธ€์ž ํฌ๊ธฐ 18px */
.custom-button {
border-radius: 30px !important;
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)) !important;
color: white !important;
font-size: 18px !important;
padding: 10px 20px !important;
border: none;
box-shadow: 0 4px 8px rgba(251, 127, 13, 0.25);
transition: transform 0.3s ease;
}
.custom-button:hover {
transform: translateY(-2px);
box-shadow: 0 6px 12px rgba(251, 127, 13, 0.3);
}
/* ์ œ๋ชฉ ์Šคํƒ€์ผ (๋ชจ๋“  ํ•ญ๋ชฉ๋ช…์ด ๋™์ผํ•˜๊ฒŒ custom-title ํด๋ž˜์Šค๋กœ) */
.custom-title {
font-size: 28px;
font-weight: bold;
margin-bottom: 10px;
color: var(--text-color);
border-bottom: 2px solid var(--primary-color);
padding-bottom: 5px;
}
/* ์‚ฌ์šฉ ๊ฐ€์ด๋“œ ์Šคํƒ€์ผ ์ถ”๊ฐ€ */
.guide-container {
background-color: var(--card-bg);
border-radius: var(--border-radius);
box-shadow: var(--shadow);
padding: 1.5rem;
margin-bottom: 1.5rem;
border: 1px solid rgba(0, 0, 0, 0.04);
}
.guide-title {
font-size: 1.5rem;
font-weight: 700;
color: var(--primary-color);
margin-bottom: 1.5rem;
padding-bottom: 0.5rem;
border-bottom: 2px solid var(--primary-color);
display: flex;
align-items: center;
}
.guide-title i {
margin-right: 0.8rem;
font-size: 1.5rem;
}
.guide-item {
display: flex;
margin-bottom: 1rem;
align-items: flex-start;
}
.guide-number {
background-color: var(--primary-color);
color: white;
width: 25px;
height: 25px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
margin-right: 10px;
flex-shrink: 0;
}
.guide-text {
flex: 1;
line-height: 1.6;
}
.guide-text a {
color: var(--primary-color);
text-decoration: underline;
font-weight: 600;
}
"""
# ===================== API ํ˜ธ์ถœ ํ•จ์ˆ˜๋“ค =====================
def call_analyze_options(uploaded_file, selected_year):
"""์˜ต์…˜ ๋ถ„์„ API ํ˜ธ์ถœ"""
try:
if uploaded_file is None:
return None, gr.update(visible=False), gr.update(choices=["์ „์ฒด์˜ต์…˜๋ถ„์„"], value="์ „์ฒด์˜ต์…˜๋ถ„์„")
# API ํ˜ธ์ถœ
result = client.predict(
uploaded_file=handle_file(uploaded_file),
selected_year=selected_year,
api_name="/on_click_analyze_options"
)
# ๊ฒฐ๊ณผ ์ฒ˜๋ฆฌ
choices = result if isinstance(result, list) else ["์ „์ฒด์˜ต์…˜๋ถ„์„"]
return "success", gr.update(visible=True), gr.update(choices=choices, value=choices[0] if choices else "์ „์ฒด์˜ต์…˜๋ถ„์„")
except Exception as e:
print(f"์˜ต์…˜ ๋ถ„์„ API ํ˜ธ์ถœ ์ค‘ ์˜ค๋ฅ˜: {e}")
return None, gr.update(visible=False), gr.update(choices=["์ „์ฒด์˜ต์…˜๋ถ„์„"], value="์ „์ฒด์˜ต์…˜๋ถ„์„")
def call_analyze_reviews(selected_option, analysis_state):
"""๋ฆฌ๋ทฐ ๋ถ„์„ API ํ˜ธ์ถœ"""
try:
if analysis_state is None:
return None, "", "", "", "", "", "", "", ""
# API ํ˜ธ์ถœ
result = client.predict(
selected_option=selected_option,
api_name="/on_click_analyze_reviews"
)
# ๊ฒฐ๊ณผ ์–ธํŒจํ‚น
if isinstance(result, tuple) and len(result) >= 9:
return result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7], result[8]
else:
return None, "", "", "", "", "", "", "", ""
except Exception as e:
print(f"๋ฆฌ๋ทฐ ๋ถ„์„ API ํ˜ธ์ถœ ์ค‘ ์˜ค๋ฅ˜: {e}")
return None, "", "", "", "", "", "", "", ""
def call_direct_analyze(positive_input, negative_input):
"""์ง์ ‘ ์ž…๋ ฅ ๋ถ„์„ API ํ˜ธ์ถœ"""
try:
# API ํ˜ธ์ถœ
result = client.predict(
positive_input=positive_input,
negative_input=negative_input,
api_name="/on_click_direct_analyze"
)
# ๊ฒฐ๊ณผ ์–ธํŒจํ‚น
if isinstance(result, tuple) and len(result) >= 7:
return result[0], result[1], result[2], result[3], result[4], result[5], result[6]
else:
return None, "", "", "", "", "", ""
except Exception as e:
print(f"์ง์ ‘ ์ž…๋ ฅ ๋ถ„์„ API ํ˜ธ์ถœ ์ค‘ ์˜ค๋ฅ˜: {e}")
return None, "", "", "", "", "", ""
def call_apply_excel_example():
"""์—‘์…€ ์˜ˆ์‹œ ์ ์šฉ API ํ˜ธ์ถœ"""
try:
result = client.predict(api_name="/apply_excel_example")
if isinstance(result, tuple) and len(result) >= 2:
return result[0], result[1]
else:
return None, gr.update()
except Exception as e:
print(f"์—‘์…€ ์˜ˆ์‹œ ์ ์šฉ API ํ˜ธ์ถœ ์ค‘ ์˜ค๋ฅ˜: {e}")
return None, gr.update()
def call_apply_direct_example():
"""์ง์ ‘ ์ž…๋ ฅ ์˜ˆ์‹œ ์ ์šฉ API ํ˜ธ์ถœ"""
try:
result = client.predict(api_name="/apply_direct_example")
if isinstance(result, tuple) and len(result) >= 2:
return result[0], result[1]
else:
return "", ""
except Exception as e:
print(f"์ง์ ‘ ์ž…๋ ฅ ์˜ˆ์‹œ ์ ์šฉ API ํ˜ธ์ถœ ์ค‘ ์˜ค๋ฅ˜: {e}")
return "", ""
# ===================== Gradio UI ๊ตฌ์„ฑ =====================
demo = gr.Blocks(css=custom_css, theme=gr.themes.Default(
primary_hue="orange",
secondary_hue="orange",
font=[gr.themes.GoogleFont("Noto Sans KR"), "ui-sans-serif", "system-ui"]
))
with demo:
gr.HTML(fontawesome_link)
# ํƒญ ๊ตฌ์„ฑ: ์—‘์…€ ๋ถ„์„ ๋ชจ๋“œ์™€ ์ง์ ‘ ์ž…๋ ฅ ๋ถ„์„ ๋ชจ๋“œ
with gr.Tabs() as tabs:
#############################
# ์—‘์…€ ๋ถ„์„ ๋ชจ๋“œ
#############################
with gr.TabItem("๐Ÿ’พ ์Šค๋งˆํŠธ์Šคํ† ์–ด ์—‘์…€๋ฆฌ๋ทฐ๋ฐ์ดํ„ฐ ํ™œ์šฉ"):
# ์ขŒ์ธก: ๋ฐ์ดํ„ฐ ์ž…๋ ฅ ์„น์…˜
with gr.Row():
with gr.Column(elem_classes="custom-frame"):
gr.HTML("<div class='custom-title'>๐Ÿ“‘ ๋ฐ์ดํ„ฐ ์ž…๋ ฅ</div>")
file_input = gr.File(label="์›๋ณธ ์—‘์…€ ํŒŒ์ผ ์—…๋กœ๋“œ", file_types=[".xlsx"])
year_radio = gr.Radio(
choices=[f"{str(y)[-2:]}๋…„" for y in range(datetime.datetime.now().year, datetime.datetime.now().year-5, -1)],
label="๋ถ„์„๋…„๋„ ์„ ํƒ",
value=f"{str(datetime.datetime.now().year)[-2:]}๋…„"
)
analyze_button = gr.Button("์˜ต์…˜ ๋ถ„์„ํ•˜๊ธฐ", elem_classes="custom-button")
with gr.Column(elem_classes="custom-frame"):
gr.HTML("<div class='custom-title'>๐Ÿ“‘ ๋ถ„์„๋ณด๊ณ ์„œ ๋‹ค์šด๋กœ๋“œ</div>")
download_final_output = gr.File(label="๋ณด๊ณ ์„œ ๋‹ค์šด๋กœ๋“œ")
# ๋ฆฌ๋ทฐ๋ถ„์„ ์„น์…˜
with gr.Column(elem_classes="custom-frame", visible=False) as review_analysis_frame:
gr.HTML("<div class='custom-title'>๐Ÿ“‘ ๋ฆฌ๋ทฐ๋ถ„์„</div>")
top20_dropdown = gr.Dropdown(
label="์•„์ดํ…œ์˜ต์…˜ ๋ถ„์„",
choices=["์ „์ฒด์˜ต์…˜๋ถ„์„"],
value="์ „์ฒด์˜ต์…˜๋ถ„์„"
)
review_button = gr.Button("๋ฆฌ๋ทฐ ๋ถ„์„ํ•˜๊ธฐ", elem_classes="custom-button")
# โ”€โ”€โ”€ ๋ถ„์„ ๊ฒฐ๊ณผ: 4ํ–‰ ร— 2์—ด โ”€โ”€โ”€
# 1ํ–‰: โœจ ์ฃผ์š”๊ธ์ •๋ฆฌ๋ทฐ / โœจ ์ฃผ์š”๋ถ€์ •๋ฆฌ๋ทฐ
with gr.Row():
with gr.Column(elem_classes="custom-frame"):
gr.HTML("<div class='custom-title'>โœจ ์ฃผ์š”๊ธ์ •๋ฆฌ๋ทฐ</div>")
positive_output = gr.Textbox(label="๊ธ์ •๋ฆฌ๋ทฐ๋ฆฌ์ŠคํŠธ (20๊ฐœ)", lines=10)
with gr.Column(elem_classes="custom-frame"):
gr.HTML("<div class='custom-title'>โœจ ์ฃผ์š”๋ถ€์ •๋ฆฌ๋ทฐ</div>")
negative_output = gr.Textbox(label="๋ถ€์ •๋ฆฌ๋ทฐ๋ฆฌ์ŠคํŠธ (30๊ฐœ)", lines=10)
# 2ํ–‰: ๐Ÿ“ข ๊ธ์ •๋ฆฌ๋ทฐ ๋ถ„์„ / ๐Ÿ“ข ๋ถ€์ •๋ฆฌ๋ทฐ ๋ถ„์„
with gr.Row():
with gr.Column(elem_classes="custom-frame"):
gr.HTML("<div class='custom-title'>๐Ÿ“ข ๊ธ์ •๋ฆฌ๋ทฐ ๋ถ„์„</div>")
positive_analysis_output = gr.Textbox(label="๊ธ์ •๋ฆฌ๋ทฐ ๋ถ„์„", lines=8)
with gr.Column(elem_classes="custom-frame"):
gr.HTML("<div class='custom-title'>๐Ÿ“ข ๋ถ€์ •๋ฆฌ๋ทฐ ๋ถ„์„</div>")
negative_analysis_output = gr.Textbox(label="๋ถ€์ •๋ฆฌ๋ทฐ ๋ถ„์„", lines=8)
# 3ํ–‰: ๐Ÿ“Š ๋‹ˆ์ฆˆ ์›์ธ  ๋ถ„์„ / ๐Ÿ”ง ํŒ๋งค์ „๋žต ์ˆ˜๋ฆฝ
with gr.Row():
with gr.Column(elem_classes="custom-frame"):
gr.HTML("<div class='custom-title'>๐Ÿ“Š ๋‹ˆ์ฆˆ์›์ธ ๋ถ„์„</div>")
insight_analysis_output = gr.Textbox(label="๋‹ˆ์ฆˆ์›์ธ ๋ถ„์„", lines=8)
with gr.Column(elem_classes="custom-frame"):
gr.HTML("<div class='custom-title'>๐Ÿ”ง ์ƒํ’ˆํŒ๋งค๋ฐฉํ–ฅ์„ฑ</div>")
strategy_analysis_output = gr.Textbox(label="์ƒํ’ˆํŒ๋งค๋ฐฉํ–ฅ์„ฑ", lines=8)
# 4ํ–‰: ๐Ÿ” ์†Œ์‹ฑ์ „๋žต / ๐Ÿ–ผ๏ธ ์ƒ์„ธํŽ˜์ด์ง€ ์ „๋žต
with gr.Row():
with gr.Column(elem_classes="custom-frame"):
gr.HTML("<div class='custom-title'>๐Ÿ” ์†Œ์‹ฑ์ „๋žต</div>")
sourcing_analysis_output = gr.Textbox(label="์†Œ์‹ฑ์ „๋žต", lines=8)
with gr.Column(elem_classes="custom-frame"):
gr.HTML("<div class='custom-title'>๐Ÿ–ผ๏ธ ๋งˆ์ผ€ํŒ…์ „๋žต</div>")
detail_page_analysis_output = gr.Textbox(label="๋งˆ์ผ€ํŒ…์ „๋žต", lines=8)
# ์ƒํƒœ ๋ณ€์ˆ˜
analysis_state = gr.State()
# ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ
analyze_button.click(
fn=call_analyze_options,
inputs=[file_input, year_radio],
outputs=[analysis_state, review_analysis_frame, top20_dropdown]
)
review_button.click(
fn=call_analyze_reviews,
inputs=[top20_dropdown, analysis_state],
outputs=[download_final_output, positive_output, negative_output,
positive_analysis_output, negative_analysis_output,
insight_analysis_output, strategy_analysis_output,
sourcing_analysis_output, detail_page_analysis_output]
)
#############################
# ์ง์ ‘ ์ž…๋ ฅ ๋ถ„์„ ๋ชจ๋“œ
#############################
with gr.TabItem("๐Ÿ“– ์ง์ ‘ ์ž…๋ ฅํ•œ ์ž๋ฃŒํ™œ์šฉ"):
with gr.Row():
with gr.Column(elem_classes="custom-frame"):
gr.HTML("<div class='custom-title'>๐Ÿ“ ๋ฆฌ๋ทฐ ์ง์ ‘ ์ž…๋ ฅ</div>")
direct_positive_input = gr.Textbox(
label="๊ธ์ • ๋ฆฌ๋ทฐ ์ž…๋ ฅ",
placeholder="๊ธ์ • ๋ฆฌ๋ทฐ๋ฅผ ์—ฌ๊ธฐ์— ์ž…๋ ฅํ•˜์„ธ์š”.(์ตœ๋Œ€ 8000์ž)",
lines=10, max_length=8000
)
direct_negative_input = gr.Textbox(
label="๋ถ€์ • ๋ฆฌ๋ทฐ ์ž…๋ ฅ",
placeholder="๋ถ€์ • ๋ฆฌ๋ทฐ๋ฅผ ์—ฌ๊ธฐ์— ์ž…๋ ฅํ•˜์„ธ์š”.(์ตœ๋Œ€ 8000์ž)",
lines=10, max_length=8000
)
direct_review_button = gr.Button("๋ฆฌ๋ทฐ ๋ถ„์„ํ•˜๊ธฐ", elem_classes="custom-button")
with gr.Column(elem_classes="custom-frame"):
gr.HTML("<div class='custom-title'>๐Ÿ“‘ ๋ถ„์„๋ณด๊ณ ์„œ ๋‹ค์šด๋กœ๋“œ</div>")
direct_download_output = gr.File(label="๋ถ„์„ ๋ณด๊ณ ์„œ ๋‹ค์šด๋กœ๋“œ")
# 2ํ–‰: ๐Ÿ“ข ๊ธ์ •๋ฆฌ๋ทฐ ๋ถ„์„ / ๐Ÿ“ข ๋ถ€์ •๋ฆฌ๋ทฐ ๋ถ„์„
with gr.Row():
with gr.Column(elem_classes="custom-frame"):
gr.HTML("<div class='custom-title'>๐Ÿ“ข ๊ธ์ •๋ฆฌ๋ทฐ๋ถ„์„</div>")
direct_positive_analysis_output = gr.Textbox(
label="๊ธ์ •๋ฆฌ๋ทฐ๋ถ„์„", lines=8
)
with gr.Column(elem_classes="custom-frame"):
gr.HTML("<div class='custom-title'>๐Ÿ“ข ๋ถ€์ •๋ฆฌ๋ทฐ๋ถ„์„</div>")
direct_negative_analysis_output = gr.Textbox(
label="๋ถ€์ •๋ฆฌ๋ทฐ๋ถ„์„", lines=8
)
# 3ํ–‰: ๐Ÿ“Š ๋‹ˆ์ฆˆ ์›์ธ  ๋ถ„์„ / ๐Ÿ”ง ํŒ๋งค์ „๋žต ์ˆ˜๋ฆฝ
with gr.Row():
with gr.Column(elem_classes="custom-frame"):
gr.HTML("<div class='custom-title'>๐Ÿ“Š ๋‹ˆ์ฆˆ์›์ธ ๋ถ„์„</div>")
direct_insight_analysis_output = gr.Textbox(
label="๋‹ˆ์ฆˆ์›์ธ ๋ถ„์„", lines=8
)
with gr.Column(elem_classes="custom-frame"):
gr.HTML("<div class='custom-title'>๐Ÿ”ง ์ƒํ’ˆํŒ๋งค๋ฐฉํ–ฅ์„ฑ</div>")
direct_strategy_analysis_output = gr.Textbox(
label="์ƒํ’ˆํŒ๋งค๋ฐฉํ–ฅ์„ฑ", lines=8
)
# 4ํ–‰: ๐Ÿ” ์†Œ์‹ฑ์ „๋žต / ๐Ÿ–ผ๏ธ ์ƒ์„ธํŽ˜์ด์ง€ ์ „๋žต
with gr.Row():
with gr.Column(elem_classes="custom-frame"):
gr.HTML("<div class='custom-title'>๐Ÿ” ์†Œ์‹ฑ์ „๋žต</div>")
direct_sourcing_analysis_output = gr.Textbox(
label="์†Œ์‹ฑ์ „๋žต", lines=8
)
with gr.Column(elem_classes="custom-frame"):
gr.HTML("<div class='custom-title'>๐Ÿ–ผ๏ธ ๋งˆ์ผ€ํŒ…์ „๋žต</div>")
direct_detail_page_analysis_output = gr.Textbox(
label="๋งˆ์ผ€ํŒ…์ „๋žต", lines=8
)
# ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ
direct_review_button.click(
fn=call_direct_analyze,
inputs=[direct_positive_input, direct_negative_input],
outputs=[direct_download_output, direct_positive_analysis_output, direct_negative_analysis_output,
direct_insight_analysis_output, direct_strategy_analysis_output,
direct_sourcing_analysis_output, direct_detail_page_analysis_output]
)
# ์˜ˆ์‹œ ์ ์šฉ ์„น์…˜
with gr.Column(elem_classes="custom-frame"):
gr.HTML("<div class='custom-title'>๐Ÿ“š ์˜ˆ์‹œ ์ ์šฉํ•˜๊ธฐ</div>")
with gr.Row():
example_excel_button = gr.Button("๐Ÿ“Š ์—‘์…€ ๋ถ„์„ ์˜ˆ์‹œ ์ ์šฉํ•˜๊ธฐ", elem_classes="custom-button")
example_direct_button = gr.Button("๐Ÿ“ ์ง์ ‘ ์ž…๋ ฅ ์˜ˆ์‹œ ์ ์šฉํ•˜๊ธฐ", elem_classes="custom-button")
# ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ
example_excel_button.click(
fn=call_apply_excel_example,
outputs=[file_input, year_radio]
)
example_direct_button.click(
fn=call_apply_direct_example,
outputs=[direct_positive_input, direct_negative_input]
)
if __name__ == "__main__":
demo.launch()