|
|
|
|
|
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" /> |
|
|
""" |
|
|
|
|
|
|
|
|
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) |
|
|
|
|
|
|
|
|
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 |
|
|
) |