f2sdfss-2 / app.py
ssboost's picture
Update app.py
09221d2 verified
Raw History Blame Contribute Delete
26.5 kB
#app.py
import gradio as gr
import pandas as pd
import openpyxl
import datetime
import tempfile
import os
import uuid
import time
from openpyxl.utils.dataframe import dataframe_to_rows
import pytz
import random
import google.generativeai as genai
# ํ™˜๊ฒฝ๋ณ€์ˆ˜์—์„œ ์ฝ”๋“œ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
api_manager_code = os.getenv('API_MANAGER_CODE', '')
styles_code = os.getenv('STYLES_CODE', '')
review_analyzer_code = os.getenv('REVIEW_ANALYZER_CODE', '')
# ๋™์ ์œผ๋กœ ์ฝ”๋“œ ์‹คํ–‰ํ•˜์—ฌ ํด๋ž˜์Šค ์ •์˜
exec(api_manager_code)
exec(review_analyzer_code)
# ์Šคํƒ€์ผ ์ •๋ณด ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
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 = os.getenv('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);
}
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%;
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-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 {
font-size: 28px;
font-weight: bold;
margin-bottom: 10px;
color: var(--text-color);
border-bottom: 2px solid var(--primary-color);
padding-bottom: 5px;
}
.gr-tabs-panel {
background-color: var(--background-color) !important;
box-shadow: none !important;
}
.custom-section-group {
background-color: var(--background-color) !important;
box-shadow: none !important;
}
.gr-textbox textarea,
.gr-textbox input {
border-radius: 12px !important;
border: 2px solid rgba(251, 127, 13, 0.2) !important;
font-size: 14px;
transition: border-color 0.3s ease;
}
.gr-textbox textarea:focus,
.gr-textbox input:focus {
border-color: var(--primary-color) !important;
box-shadow: 0 0 0 3px rgba(251, 127, 13, 0.1) !important;
}
.gr-file {
border-radius: var(--border-radius) !important;
border: 2px dashed var(--primary-color) !important;
background-color: rgba(251, 127, 13, 0.05) !important;
transition: all 0.3s ease;
}
.gr-file:hover {
background-color: rgba(251, 127, 13, 0.1) !important;
border-color: var(--secondary-color) !important;
}
@media (max-width: 768px) {
.gradio-container {
padding: 10px;
}
.custom-header h1 {
font-size: 2rem;
}
.custom-title {
font-size: 24px;
}
.custom-frame {
padding: 15px;
margin: 5px 0;
}
.custom-button {
font-size: 16px !important;
padding: 8px 16px !important;
}
}
''')
class SessionManager:
"""์„ธ์…˜๋ณ„ ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ"""
def __init__(self):
self.sessions = {}
def create_session(self):
"""์ƒˆ๋กœ์šด ์„ธ์…˜ ์ƒ์„ฑ"""
session_id = str(uuid.uuid4())
self.sessions[session_id] = {
'created_at': time.time(),
'data': {},
'temp_files': []
}
return session_id
def get_session_data(self, session_id, key, default=None):
"""์„ธ์…˜ ๋ฐ์ดํ„ฐ ์กฐํšŒ"""
if session_id in self.sessions:
return self.sessions[session_id]['data'].get(key, default)
return default
def set_session_data(self, session_id, key, value):
"""์„ธ์…˜ ๋ฐ์ดํ„ฐ ์ €์žฅ"""
if session_id in self.sessions:
self.sessions[session_id]['data'][key] = value
def add_temp_file(self, session_id, file_path):
"""์„ธ์…˜์— ์ž„์‹œ ํŒŒ์ผ ์ถ”๊ฐ€"""
if session_id in self.sessions:
self.sessions[session_id]['temp_files'].append(file_path)
def cleanup_session(self, session_id):
"""์„ธ์…˜ ์ •๋ฆฌ"""
if session_id in self.sessions:
# ์ž„์‹œ ํŒŒ์ผ๋“ค ์‚ญ์ œ
for file_path in self.sessions[session_id]['temp_files']:
try:
if os.path.exists(file_path):
os.remove(file_path)
except Exception as e:
print(f"ํŒŒ์ผ ์‚ญ์ œ ์˜ค๋ฅ˜: {e}")
# ์„ธ์…˜ ๋ฐ์ดํ„ฐ ์‚ญ์ œ
del self.sessions[session_id]
def cleanup_old_sessions(self, max_age_hours=2):
"""์˜ค๋ž˜๋œ ์„ธ์…˜ ์ •๋ฆฌ (2์‹œ๊ฐ„ ์ด์ƒ)"""
current_time = time.time()
old_sessions = []
for session_id, session_data in self.sessions.items():
if (current_time - session_data['created_at']) > (max_age_hours * 3600):
old_sessions.append(session_id)
for session_id in old_sessions:
self.cleanup_session(session_id)
# ์ „์—ญ ์„ธ์…˜ ๋งค๋‹ˆ์ €
session_manager = SessionManager()
def create_app():
"""๋ฉ”์ธ Gradio ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ƒ์„ฑ"""
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)
# ์„ธ์…˜ ID๋ฅผ ์ˆจ๊ฒจ์ง„ ์ƒํƒœ๋กœ ๊ด€๋ฆฌ
session_id_state = gr.State(value="")
# ์„ธ์…˜ ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜
def initialize_session():
session_id = session_manager.create_session()
# ๊ฐ ์„ธ์…˜๋งˆ๋‹ค ์ƒˆ๋กœ์šด ๋ถ„์„๊ธฐ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
api_manager = APIManager()
analyzer = ReviewAnalyzer(api_manager)
session_manager.set_session_data(session_id, 'analyzer', analyzer)
return session_id
# ์„ธ์…˜๋ณ„ ๋ถ„์„๊ธฐ ๊ฐ€์ ธ์˜ค๊ธฐ
def get_session_analyzer(session_id):
if not session_id:
session_id = initialize_session()
analyzer = session_manager.get_session_data(session_id, 'analyzer')
if analyzer is None:
api_manager = APIManager()
analyzer = ReviewAnalyzer(api_manager)
session_manager.set_session_data(session_id, 'analyzer', analyzer)
return analyzer, session_id
# ํƒญ ๊ตฌ์„ฑ
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(2025, 2020, -1)],
label="๋ถ„์„๋…„๋„ ์„ ํƒ",
value="25๋…„"
)
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")
# ๋ถ„์„ ๊ฒฐ๊ณผ ์„น์…˜๋“ค
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, value="")
with gr.Column(elem_classes="custom-frame"):
gr.HTML("<div class='custom-title'>โœจ ์ฃผ์š”๋ถ€์ •๋ฆฌ๋ทฐ</div>")
negative_output = gr.Textbox(label="๋ถ€์ •๋ฆฌ๋ทฐ๋ฆฌ์ŠคํŠธ (30๊ฐœ)", lines=10, value="")
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, value="")
with gr.Column(elem_classes="custom-frame"):
gr.HTML("<div class='custom-title'>๐Ÿ“ข ๋ถ€์ •๋ฆฌ๋ทฐ ๋ถ„์„</div>")
negative_analysis_output = gr.Textbox(label="๋ถ€์ •๋ฆฌ๋ทฐ ๋ถ„์„", lines=8, value="")
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, value="")
with gr.Column(elem_classes="custom-frame"):
gr.HTML("<div class='custom-title'>๐Ÿ”ง ์ƒํ’ˆํŒ๋งค๋ฐฉํ–ฅ์„ฑ</div>")
strategy_analysis_output = gr.Textbox(label="์ƒํ’ˆํŒ๋งค๋ฐฉํ–ฅ์„ฑ", lines=8, value="")
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, value="")
with gr.Column(elem_classes="custom-frame"):
gr.HTML("<div class='custom-title'>๐Ÿ–ผ๏ธ ๋งˆ์ผ€ํŒ…์ „๋žต</div>")
detail_page_analysis_output = gr.Textbox(label="๋งˆ์ผ€ํŒ…์ „๋žต", lines=8, value="")
# ์„ธ์…˜๋ณ„ ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ ์ˆจ๊ฒจ์ง„ ์ƒํƒœ
partial_file_state = gr.State(value=None)
# ์˜ต์…˜ ๋ถ„์„ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ
def on_analyze_options(uploaded_file, selected_year, session_id):
analyzer, session_id = get_session_analyzer(session_id)
try:
result = analyzer.analyze_options(uploaded_file, selected_year)
print(f"analyze_options ๊ฒฐ๊ณผ ํƒ€์ž…: {type(result)}")
print(f"analyze_options ๊ฒฐ๊ณผ ๋‚ด์šฉ: {result}")
partial_file = None
top20_list = ["์ „์ฒด์˜ต์…˜๋ถ„์„"]
if result is not None:
if isinstance(result, (list, tuple)) and len(result) >= 2:
partial_file = result[0]
top20_list = result[1] if result[1] else ["์ „์ฒด์˜ต์…˜๋ถ„์„"]
elif hasattr(result, '__getitem__'):
try:
partial_file = result[0]
top20_list = result[1] if len(result) > 1 else ["์ „์ฒด์˜ต์…˜๋ถ„์„"]
except (IndexError, KeyError, TypeError):
print("๊ฒฐ๊ณผ ์ธ๋ฑ์‹ฑ ์‹คํŒจ, ๊ธฐ๋ณธ๊ฐ’ ์‚ฌ์šฉ")
if not isinstance(top20_list, list):
top20_list = ["์ „์ฒด์˜ต์…˜๋ถ„์„"]
if len(top20_list) == 0:
top20_list = ["์ „์ฒด์˜ต์…˜๋ถ„์„"]
if partial_file:
session_manager.add_temp_file(session_id, partial_file)
return (
partial_file,
gr.update(visible=True if partial_file else False),
gr.update(choices=top20_list, value=top20_list[0]),
session_id
)
except Exception as e:
print(f"์˜ต์…˜ ๋ถ„์„ ์˜ค๋ฅ˜: {e}")
import traceback
traceback.print_exc()
return None, gr.update(visible=False), gr.update(choices=["์ „์ฒด์˜ต์…˜๋ถ„์„"], value="์ „์ฒด์˜ต์…˜๋ถ„์„"), session_id
analyze_button.click(
fn=on_analyze_options,
inputs=[file_input, year_radio, session_id_state],
outputs=[partial_file_state, review_analysis_frame, top20_dropdown, session_id_state]
)
# ๋ฆฌ๋ทฐ ๋ถ„์„ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ
def on_analyze_reviews(partial_file, selected_option, session_id):
analyzer, session_id = get_session_analyzer(session_id)
try:
result = analyzer.analyze_reviews(partial_file, selected_option)
if isinstance(result, tuple) and len(result) >= 9:
results = result
else:
results = (None, "", "", "", "", "", "", "", "")
final_file = results[0]
if final_file:
session_manager.add_temp_file(session_id, final_file)
return results + (session_id,)
except Exception as e:
print(f"๋ฆฌ๋ทฐ ๋ถ„์„ ์˜ค๋ฅ˜: {e}")
import traceback
traceback.print_exc()
return (None, "", "", "", "", "", "", "", "", session_id)
review_button.click(
fn=on_analyze_reviews,
inputs=[partial_file_state, top20_dropdown, session_id_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, session_id_state]
)
#############################
# ์ง์ ‘ ์ž…๋ ฅ ๋ถ„์„ ๋ชจ๋“œ
#############################
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, value=""
)
direct_negative_input = gr.Textbox(
label="๋ถ€์ • ๋ฆฌ๋ทฐ ์ž…๋ ฅ",
placeholder="๋ถ€์ • ๋ฆฌ๋ทฐ๋ฅผ ์—ฌ๊ธฐ์— ์ž…๋ ฅํ•˜์„ธ์š”.(์ตœ๋Œ€ 8000์ž)",
lines=10, max_length=8000, value=""
)
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="๋ถ„์„ ๋ณด๊ณ ์„œ ๋‹ค์šด๋กœ๋“œ")
# ์ง์ ‘ ์ž…๋ ฅ ๋ถ„์„ ๊ฒฐ๊ณผ
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, value=""
)
with gr.Column(elem_classes="custom-frame"):
gr.HTML("<div class='custom-title'>๐Ÿ“ข ๋ถ€์ •๋ฆฌ๋ทฐ๋ถ„์„</div>")
direct_negative_analysis_output = gr.Textbox(
label="๋ถ€์ •๋ฆฌ๋ทฐ๋ถ„์„", lines=8, value=""
)
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, value=""
)
with gr.Column(elem_classes="custom-frame"):
gr.HTML("<div class='custom-title'>๐Ÿ”ง ์ƒํ’ˆํŒ๋งค๋ฐฉํ–ฅ์„ฑ</div>")
direct_strategy_analysis_output = gr.Textbox(
label="์ƒํ’ˆํŒ๋งค๋ฐฉํ–ฅ์„ฑ", lines=8, value=""
)
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, value=""
)
with gr.Column(elem_classes="custom-frame"):
gr.HTML("<div class='custom-title'>๐Ÿ–ผ๏ธ ๋งˆ์ผ€ํŒ…์ „๋žต</div>")
direct_detail_page_analysis_output = gr.Textbox(
label="๋งˆ์ผ€ํŒ…์ „๋žต", lines=8, value=""
)
# ์ง์ ‘ ์ž…๋ ฅ ๋ถ„์„ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ
def on_direct_analyze(positive_input, negative_input, session_id):
analyzer, session_id = get_session_analyzer(session_id)
try:
result = analyzer.analyze_direct_reviews(positive_input, negative_input)
if isinstance(result, tuple) and len(result) >= 9:
results = result
else:
results = (None, "", "", "", "", "", "", "", "")
final_file = results[0]
if final_file:
session_manager.add_temp_file(session_id, final_file)
return results + (session_id,)
except Exception as e:
print(f"์ง์ ‘ ๋ถ„์„ ์˜ค๋ฅ˜: {e}")
import traceback
traceback.print_exc()
return (None, "", "", "", "", "", "", "", "", session_id)
direct_review_button.click(
fn=on_direct_analyze,
inputs=[direct_positive_input, direct_negative_input, session_id_state],
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, session_id_state]
)
# ์˜ˆ์‹œ ์ ์šฉ ์„น์…˜
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")
clear_all_button = gr.Button("๐Ÿ—‘๏ธ ์ „์ฒด ์ดˆ๊ธฐํ™”", elem_classes="custom-button")
# ์˜ˆ์‹œ ์ ์šฉ ์ด๋ฒคํŠธ
def apply_excel_example(session_id):
analyzer, session_id = get_session_analyzer(session_id)
excel_file, year = analyzer.apply_excel_example()
return excel_file, year, session_id
example_excel_button.click(
fn=apply_excel_example,
inputs=[session_id_state],
outputs=[file_input, year_radio, session_id_state]
)
def apply_direct_example(session_id):
analyzer, session_id = get_session_analyzer(session_id)
positive_text, negative_text = analyzer.apply_direct_example()
return positive_text, negative_text, session_id
example_direct_button.click(
fn=apply_direct_example,
inputs=[session_id_state],
outputs=[direct_positive_input, direct_negative_input, session_id_state]
)
# ์ „์ฒด ์ดˆ๊ธฐํ™” ๊ธฐ๋Šฅ
def clear_all_data(session_id):
if session_id:
session_manager.cleanup_session(session_id)
new_session_id = initialize_session()
return (
None, "25๋…„", gr.update(visible=False),
["์ „์ฒด์˜ต์…˜๋ถ„์„"], "์ „์ฒด์˜ต์…˜๋ถ„์„", None,
"", "", "", "", "", "", "", "",
"", "", None, "", "", "", "", "", "",
new_session_id
)
clear_all_button.click(
fn=clear_all_data,
inputs=[session_id_state],
outputs=[
file_input, year_radio, review_analysis_frame,
top20_dropdown, top20_dropdown,
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,
direct_positive_input, direct_negative_input,
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,
session_id_state
]
)
# ํŽ˜์ด์ง€ ๋กœ๋“œ ์‹œ ์™„์ „ํ•œ ์ดˆ๊ธฐํ™”
def init_on_load():
session_id = initialize_session()
return (
session_id, None, "25๋…„", gr.update(visible=False),
gr.update(choices=["์ „์ฒด์˜ต์…˜๋ถ„์„"], value="์ „์ฒด์˜ต์…˜๋ถ„์„"), None,
"", "", "", "", "", "", "", "",
"", "", None, "", "", "", "", "", ""
)
demo.load(
fn=init_on_load,
outputs=[
session_id_state,
file_input, year_radio, review_analysis_frame, top20_dropdown,
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,
direct_positive_input, direct_negative_input,
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
]
)
return demo
if __name__ == "__main__":
app = create_app()
# ์ฃผ๊ธฐ์ ์œผ๋กœ ์˜ค๋ž˜๋œ ์„ธ์…˜ ์ •๋ฆฌ
import threading
def cleanup_timer():
while True:
time.sleep(3600)
session_manager.cleanup_old_sessions()
cleanup_thread = threading.Thread(target=cleanup_timer, daemon=True)
cleanup_thread.start()
app.launch(
share=False,
server_name="0.0.0.0",
server_port=7860,
show_error=True,
debug=False
)