Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -17,6 +17,18 @@ from dotenv import load_dotenv
|
|
17 |
load_dotenv()
|
18 |
|
19 |
# ๋ก๊น
์ค์ (API ์๋ํฌ์ธํธ ์ ๋ณด๋ ์ ์ธ)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
logging.basicConfig(
|
21 |
level=logging.INFO,
|
22 |
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
@@ -27,6 +39,11 @@ logging.basicConfig(
|
|
27 |
)
|
28 |
|
29 |
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
30 |
|
31 |
# API ํด๋ผ์ด์ธํธ ์ด๊ธฐํ
|
32 |
def get_api_client():
|
@@ -123,8 +140,14 @@ def get_app_temp_dir():
|
|
123 |
return os.environ.get('CONTROL_TOWER_TEMP', tempfile.gettempdir())
|
124 |
|
125 |
def get_session_id():
|
126 |
-
"""์ธ์
ID ์์ฑ"""
|
127 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
128 |
|
129 |
def cleanup_session_files(session_id, delay=300):
|
130 |
"""์ธ์
๋ณ ์์ ํ์ผ ์ ๋ฆฌ ํจ์"""
|
@@ -199,99 +222,92 @@ def create_session_temp_file(session_id, suffix='.xlsx'):
|
|
199 |
register_session_file(session_id, temp_file_path)
|
200 |
return temp_file_path
|
201 |
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
206 |
try:
|
207 |
client = get_api_client()
|
208 |
-
|
209 |
-
# API ํธ์ถ
|
210 |
result = client.predict(
|
211 |
keyword=keyword,
|
212 |
korean_only=korean_only,
|
213 |
-
apply_main_keyword=
|
214 |
exclude_zero_volume=exclude_zero_volume,
|
215 |
api_name="/process_search_results"
|
216 |
)
|
217 |
|
218 |
-
#
|
219 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
220 |
|
221 |
# ๋ค์ด๋ก๋ ํ์ผ์ด ์๋ ๊ฒฝ์ฐ ๋ก์ปฌ๋ก ๋ณต์ฌ
|
222 |
-
|
223 |
if download_file:
|
224 |
-
|
225 |
-
|
226 |
try:
|
227 |
-
|
228 |
-
shutil.copy2(download_file, excel_path)
|
229 |
except Exception as e:
|
230 |
logger.error(f"ํ์ผ ๋ณต์ฌ ์ค๋ฅ: {e}")
|
231 |
-
|
232 |
|
233 |
-
|
234 |
-
df_state = pd.DataFrame()
|
235 |
|
236 |
-
if table_html and "๊ฒ์ ๊ฒฐ๊ณผ๊ฐ ์์ต๋๋ค" not in table_html:
|
237 |
-
return (gr.update(value=table_html), gr.update(choices=cat_choices),
|
238 |
-
gr.update(choices=vol_choices), df_state,
|
239 |
-
gr.update(choices=cat_choices, value=selected_cat), excel_path,
|
240 |
-
gr.update(visible=True), gr.update(visible=True), keyword)
|
241 |
-
else:
|
242 |
-
return (gr.update(value="<p>๊ฒ์ ๊ฒฐ๊ณผ๊ฐ ์์ต๋๋ค. ๋ค๋ฅธ ํค์๋๋ก ์๋ํด๋ณด์ธ์.</p>"),
|
243 |
-
gr.update(choices=["์ ์ฒด ๋ณด๊ธฐ"]), gr.update(choices=["์ ์ฒด"]),
|
244 |
-
df_state, gr.update(choices=["์ ์ฒด ๋ณด๊ธฐ"], value="์ ์ฒด ๋ณด๊ธฐ"), None,
|
245 |
-
gr.update(visible=False), gr.update(visible=False), keyword)
|
246 |
-
|
247 |
except Exception as e:
|
248 |
logger.error(f"API ํธ์ถ ์ค๋ฅ: {e}")
|
249 |
-
return (
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
def
|
255 |
-
"""
|
256 |
-
update_session_activity(session_id)
|
257 |
-
|
258 |
try:
|
259 |
client = get_api_client()
|
260 |
-
|
261 |
-
# API ํธ์ถ
|
262 |
result = client.predict(
|
263 |
-
|
264 |
-
|
265 |
-
|
|
|
|
|
|
|
|
|
266 |
)
|
267 |
-
|
268 |
-
analysis_result, download_file = result
|
269 |
-
|
270 |
-
# ๋ค์ด๋ก๋ ํ์ผ์ด ์๋ ๊ฒฝ์ฐ ๋ก์ปฌ๋ก ๋ณต์ฌ
|
271 |
-
excel_path = None
|
272 |
-
if download_file:
|
273 |
-
excel_path = create_session_temp_file(session_id, '.xlsx')
|
274 |
-
try:
|
275 |
-
import shutil
|
276 |
-
shutil.copy2(download_file, excel_path)
|
277 |
-
except Exception as e:
|
278 |
-
logger.error(f"๋ถ์ ๊ฒฐ๊ณผ ํ์ผ ๋ณต์ฌ ์ค๋ฅ: {e}")
|
279 |
-
excel_path = None
|
280 |
-
|
281 |
-
return analysis_result, excel_path, gr.update(visible=True)
|
282 |
-
|
283 |
except Exception as e:
|
284 |
-
logger.error(f"
|
285 |
-
return "
|
286 |
|
287 |
-
def
|
288 |
-
"""
|
289 |
-
update_session_activity(session_id)
|
290 |
-
|
291 |
try:
|
292 |
client = get_api_client()
|
293 |
-
|
294 |
-
# API ํธ์ถ
|
295 |
result = client.predict(
|
296 |
selected_cat=selected_cat,
|
297 |
keyword_sort=keyword_sort,
|
@@ -299,122 +315,222 @@ def filter_and_sort_table(df, selected_cat, keyword_sort, total_volume_sort, usa
|
|
299 |
usage_count_sort=usage_count_sort,
|
300 |
selected_volume_range=selected_volume_range,
|
301 |
exclude_zero_volume=exclude_zero_volume,
|
302 |
-
api_name="/
|
303 |
)
|
304 |
-
|
305 |
return result
|
306 |
-
|
307 |
except Exception as e:
|
308 |
-
logger.error(f"
|
309 |
return "<p>ํํฐ๋ง ์๋น์ค ์ฐ๊ฒฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.</p>"
|
310 |
|
311 |
-
def
|
312 |
-
"""
|
313 |
-
|
314 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
315 |
try:
|
316 |
client = get_api_client()
|
317 |
-
|
318 |
result = client.predict(
|
319 |
selected_cat=selected_cat,
|
320 |
api_name="/update_category_selection"
|
321 |
)
|
322 |
-
|
323 |
return gr.update(value=result)
|
324 |
-
|
325 |
except Exception as e:
|
326 |
-
logger.error(f"
|
327 |
return gr.update(value=selected_cat)
|
328 |
|
329 |
-
def
|
330 |
-
"""
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
336 |
try:
|
337 |
-
|
338 |
-
os.remove(file_path)
|
339 |
-
logger.info(f"์ธ์
{session_id[:8]}... ๋ฆฌ์
์ ํ์ผ ์ญ์ : {file_path}")
|
340 |
except Exception as e:
|
341 |
-
logger.error(f"
|
342 |
-
|
343 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
344 |
try:
|
345 |
client = get_api_client()
|
346 |
-
|
347 |
result = client.predict(api_name="/reset_interface")
|
348 |
-
|
349 |
return result
|
350 |
-
|
351 |
except Exception as e:
|
352 |
-
logger.error(f"
|
353 |
-
# ๊ธฐ๋ณธ ๋ฆฌ์
๊ฐ ๋ฐํ
|
354 |
return (
|
355 |
"", # ๊ฒ์ ํค์๋
|
356 |
True, # ํ๊ธ๋ง ์ถ์ถ
|
357 |
False, # ๊ฒ์๋ 0 ํค์๋ ์ ์ธ
|
358 |
"๋ฉ์ธํค์๋ ์ ์ฉ", # ์กฐํฉ ๋ฐฉ์
|
359 |
"", # HTML ํ
์ด๋ธ
|
360 |
-
["์ ์ฒด ๋ณด๊ธฐ"], # ์นดํ
๊ณ ๋ฆฌ ํํฐ
|
361 |
-
"์ ์ฒด ๋ณด๊ธฐ", # ์นดํ
๊ณ ๋ฆฌ ํํฐ
|
362 |
-
["์ ์ฒด"], # ๊ฒ์๋ ๊ตฌ๊ฐ ํํฐ
|
363 |
-
"์ ์ฒด", # ๊ฒ์๋ ๊ตฌ๊ฐ
|
364 |
"์ ๋ ฌ ์์", # ์ด๊ฒ์๋ ์ ๋ ฌ
|
365 |
"์ ๋ ฌ ์์", # ํค์๋ ์ฌ์ฉํ์ ์ ๋ ฌ
|
366 |
-
["์ ์ฒด ๋ณด๊ธฐ"], # ๋ถ์ํ ์นดํ
๊ณ ๋ฆฌ
|
367 |
-
"์ ์ฒด ๋ณด๊ธฐ", # ๋ถ์ํ ์นดํ
๊ณ ๋ฆฌ
|
368 |
"", # ํค์๋ ์
๋ ฅ
|
369 |
"", # ๋ถ์ ๊ฒฐ๊ณผ
|
370 |
-
None
|
371 |
-
gr.update(visible=False), # ํค์๋ ๋ถ์ ์น์
|
372 |
-
gr.update(visible=False), # ๋ถ์ ๊ฒฐ๊ณผ ์ถ๋ ฅ ์น์
|
373 |
-
"" # ํค์๋ ์ํ
|
374 |
)
|
375 |
|
376 |
-
# ๋ํผ ํจ์๋ค
|
377 |
-
|
378 |
-
|
|
|
|
|
379 |
return (
|
380 |
-
gr.update(visible=True),
|
381 |
-
gr.update(visible=False)
|
382 |
)
|
383 |
|
384 |
-
def
|
385 |
-
|
386 |
-
|
387 |
-
result = wrapper_modified(keyword, korean_only, apply_main_keyword, exclude_zero_volume, session_id)
|
388 |
|
389 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
390 |
|
391 |
-
|
392 |
-
|
393 |
keyword_section_visibility = True
|
|
|
|
|
394 |
execution_section_visibility = True
|
395 |
else:
|
396 |
-
empty_placeholder_vis = True
|
397 |
keyword_section_visibility = False
|
|
|
|
|
398 |
execution_section_visibility = False
|
399 |
|
|
|
|
|
|
|
400 |
return (
|
401 |
-
table_html,
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
|
|
|
|
|
|
|
|
|
|
408 |
)
|
409 |
|
410 |
-
def
|
411 |
-
|
412 |
-
|
|
|
413 |
|
414 |
-
def
|
415 |
-
|
416 |
-
|
417 |
-
return
|
|
|
|
|
|
|
|
|
|
|
418 |
|
419 |
# ์ธ์
์ ๋ฆฌ ์ค์ผ์ค๋ฌ
|
420 |
def start_session_cleanup_scheduler():
|
@@ -423,7 +539,6 @@ def start_session_cleanup_scheduler():
|
|
423 |
while True:
|
424 |
time.sleep(600) # 10๋ถ๋ง๋ค ์คํ
|
425 |
cleanup_old_sessions()
|
426 |
-
# ์ถ๊ฐ๋ก ํ๊น
ํ์ด์ค ์์ ํด๋๋ ์ฃผ๊ธฐ์ ์ ๋ฆฌ
|
427 |
cleanup_huggingface_temp_folders()
|
428 |
|
429 |
threading.Thread(target=cleanup_scheduler, daemon=True).start()
|
@@ -487,9 +602,6 @@ def create_app():
|
|
487 |
)) as demo:
|
488 |
gr.HTML(fontawesome_html)
|
489 |
|
490 |
-
# ์ธ์
ID ์ํ (๊ฐ ์ฌ์ฉ์๋ณ๋ก ๊ณ ์ )
|
491 |
-
session_id = gr.State(get_session_id)
|
492 |
-
|
493 |
# ํค์๋ ์ํ ๊ด๋ฆฌ
|
494 |
keyword_state = gr.State("")
|
495 |
|
@@ -662,14 +774,14 @@ def create_app():
|
|
662 |
# ์ํ ์ ์ฅ์ฉ ๋ณ์
|
663 |
state_df = gr.State()
|
664 |
|
665 |
-
# ์ด๋ฒคํธ ์ฐ๊ฒฐ
|
666 |
search_btn.click(
|
667 |
-
fn=
|
668 |
-
inputs=[keyword, korean_only, apply_main_keyword, exclude_zero_volume
|
669 |
outputs=[progress_section, empty_table_html]
|
670 |
).then(
|
671 |
-
fn=
|
672 |
-
inputs=[keyword, korean_only, apply_main_keyword, exclude_zero_volume
|
673 |
outputs=[
|
674 |
table_output, category_filter, search_volume_filter,
|
675 |
state_df, selected_category, download_output,
|
@@ -679,29 +791,29 @@ def create_app():
|
|
679 |
]
|
680 |
)
|
681 |
|
682 |
-
# ํํฐ ๋ฐ ์ ๋ ฌ ๋ณ๊ฒฝ ์ด๋ฒคํธ ์ฐ๊ฒฐ
|
683 |
category_filter.change(
|
684 |
fn=filter_and_sort_table,
|
685 |
inputs=[
|
686 |
-
|
687 |
total_volume_sort, usage_count_sort,
|
688 |
-
search_volume_filter, exclude_zero_volume
|
689 |
],
|
690 |
outputs=[table_output]
|
691 |
)
|
692 |
|
693 |
category_filter.change(
|
694 |
fn=update_category_selection,
|
695 |
-
inputs=[category_filter
|
696 |
outputs=[selected_category]
|
697 |
)
|
698 |
|
699 |
total_volume_sort.change(
|
700 |
fn=filter_and_sort_table,
|
701 |
inputs=[
|
702 |
-
|
703 |
total_volume_sort, usage_count_sort,
|
704 |
-
search_volume_filter, exclude_zero_volume
|
705 |
],
|
706 |
outputs=[table_output]
|
707 |
)
|
@@ -709,9 +821,9 @@ def create_app():
|
|
709 |
usage_count_sort.change(
|
710 |
fn=filter_and_sort_table,
|
711 |
inputs=[
|
712 |
-
|
713 |
total_volume_sort, usage_count_sort,
|
714 |
-
search_volume_filter, exclude_zero_volume
|
715 |
],
|
716 |
outputs=[table_output]
|
717 |
)
|
@@ -719,9 +831,9 @@ def create_app():
|
|
719 |
search_volume_filter.change(
|
720 |
fn=filter_and_sort_table,
|
721 |
inputs=[
|
722 |
-
|
723 |
total_volume_sort, usage_count_sort,
|
724 |
-
search_volume_filter, exclude_zero_volume
|
725 |
],
|
726 |
outputs=[table_output]
|
727 |
)
|
@@ -729,87 +841,36 @@ def create_app():
|
|
729 |
exclude_zero_volume.change(
|
730 |
fn=filter_and_sort_table,
|
731 |
inputs=[
|
732 |
-
|
733 |
total_volume_sort, usage_count_sort,
|
734 |
-
search_volume_filter, exclude_zero_volume
|
735 |
],
|
736 |
outputs=[table_output]
|
737 |
)
|
738 |
|
739 |
-
# ์นดํ
๊ณ ๋ฆฌ ๋ถ์ ๋ฒํผ ์ด๋ฒคํธ
|
740 |
analyze_btn.click(
|
741 |
-
fn=
|
742 |
-
inputs=[analysis_keywords, selected_category, state_df
|
743 |
outputs=[progress_section]
|
744 |
).then(
|
745 |
-
fn=
|
746 |
-
inputs=[analysis_keywords, selected_category, state_df
|
747 |
outputs=[analysis_result, download_output, analysis_output_section, progress_section]
|
748 |
)
|
749 |
|
750 |
-
# ๋ฆฌ์
๋ฒํผ ์ด๋ฒคํธ ์ฐ๊ฒฐ
|
751 |
reset_btn.click(
|
752 |
fn=reset_interface,
|
753 |
-
inputs=[
|
754 |
outputs=[
|
755 |
keyword, korean_only, exclude_zero_volume, apply_main_keyword,
|
756 |
table_output, category_filter, category_filter,
|
757 |
search_volume_filter, search_volume_filter,
|
758 |
total_volume_sort, usage_count_sort,
|
759 |
selected_category, selected_category,
|
760 |
-
analysis_keywords, analysis_result, download_output
|
761 |
-
keyword_analysis_section, analysis_output_section,
|
762 |
-
keyword_state
|
763 |
]
|
764 |
)
|
765 |
|
766 |
-
return demo
|
767 |
-
|
768 |
-
if __name__ == "__main__":
|
769 |
-
# ========== ์์ ์ ์ ์ฒด ์ด๊ธฐํ ==========
|
770 |
-
logger.info("๐ ์ปจํธ๋กค ํ์ ์ ํ๋ฆฌ์ผ์ด์
์์...")
|
771 |
-
|
772 |
-
# 1. ์ฒซ ๋ฒ์งธ: ํ๊น
ํ์ด์ค ์์ ํด๋ ์ ๋ฆฌ ๋ฐ ํ๊ฒฝ ์ค์
|
773 |
-
app_temp_dir = cleanup_on_startup()
|
774 |
-
|
775 |
-
# 2. ์ธ์
์ ๋ฆฌ ์ค์ผ์ค๋ฌ ์์
|
776 |
-
start_session_cleanup_scheduler()
|
777 |
-
|
778 |
-
# 3. API ์ฐ๊ฒฐ ํ
์คํธ
|
779 |
-
try:
|
780 |
-
test_client = get_api_client()
|
781 |
-
logger.info("โ
API ์ฐ๊ฒฐ ํ
์คํธ ์ฑ๊ณต")
|
782 |
-
except Exception as e:
|
783 |
-
logger.error(f"โ API ์ฐ๊ฒฐ ์คํจ: {e}")
|
784 |
-
raise
|
785 |
-
|
786 |
-
logger.info("===== ์ปจํธ๋กค ํ์ ์ ํ๋ฆฌ์ผ์ด์
์์ ์๋ฃ at %s =====", time.strftime("%Y-%m-%d %H:%M:%S"))
|
787 |
-
logger.info(f"๐ ์์ ํ์ผ ์ ์ฅ ์์น: {app_temp_dir}")
|
788 |
-
|
789 |
-
# ========== ์ฑ ์คํ ==========
|
790 |
-
try:
|
791 |
-
app = create_app()
|
792 |
-
app.launch(
|
793 |
-
share=False, # ๋ณด์์ ์ํด share ๋นํ์ฑํ
|
794 |
-
server_name="0.0.0.0", # ๋ชจ๋ IP์์ ์ ๊ทผ ํ์ฉ
|
795 |
-
server_port=7860, # ํฌํธ ์ง์
|
796 |
-
max_threads=40, # ๋ฉํฐ์ ์ ๋ฅผ ์ํ ์ค๋ ๋ ์ ์ฆ๊ฐ
|
797 |
-
auth=None, # ํ์์ ์ธ์ฆ ์ถ๊ฐ ๊ฐ๋ฅ
|
798 |
-
show_error=True, # ์๋ฌ ํ์
|
799 |
-
quiet=False, # ๋ก๊ทธ ํ์
|
800 |
-
favicon_path=None, # ํ๋น์ฝ ์ค์
|
801 |
-
ssl_verify=False # SSL ๊ฒ์ฆ ๋นํ์ฑํ (๊ฐ๋ฐ์ฉ)
|
802 |
-
)
|
803 |
-
except Exception as e:
|
804 |
-
logger.error(f"์ ํ๋ฆฌ์ผ์ด์
์คํ ์คํจ: {e}")
|
805 |
-
raise
|
806 |
-
finally:
|
807 |
-
# ์ ํ๋ฆฌ์ผ์ด์
์ข
๋ฃ ์ ์ ๋ฆฌ
|
808 |
-
logger.info("๐งน ์ปจํธ๋กค ํ์ ์ ํ๋ฆฌ์ผ์ด์
์ข
๋ฃ - ์ต์ข
์ ๋ฆฌ ์์
...")
|
809 |
-
try:
|
810 |
-
cleanup_huggingface_temp_folders()
|
811 |
-
if os.path.exists(app_temp_dir):
|
812 |
-
shutil.rmtree(app_temp_dir, ignore_errors=True)
|
813 |
-
logger.info("โ
์ต์ข
์ ๋ฆฌ ์๋ฃ")
|
814 |
-
except Exception as e:
|
815 |
-
logger.error(f"์ต์ข
์ ๋ฆฌ ์ค ์ค๋ฅ: {e}")
|
|
|
17 |
load_dotenv()
|
18 |
|
19 |
# ๋ก๊น
์ค์ (API ์๋ํฌ์ธํธ ์ ๋ณด๋ ์ ์ธ)
|
20 |
+
class SecureFilter(logging.Filter):
|
21 |
+
"""API ์๋ํฌ์ธํธ ์ ๋ณด๋ฅผ ๋ก๊ทธ์์ ์ ๊ฑฐํ๋ ํํฐ"""
|
22 |
+
def filter(self, record):
|
23 |
+
# API ์๋ํฌ์ธํธ ๊ด๋ จ ๋ก๊ทธ ํํฐ๋ง
|
24 |
+
message = record.getMessage()
|
25 |
+
if any(keyword in message.lower() for keyword in ['hf.space', 'happydoggg', 'gradio_api', 'http request']):
|
26 |
+
return False
|
27 |
+
return True
|
28 |
+
|
29 |
+
# ๋ณด์ ํํฐ ์ ์ฉ
|
30 |
+
secure_filter = SecureFilter()
|
31 |
+
|
32 |
logging.basicConfig(
|
33 |
level=logging.INFO,
|
34 |
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
|
|
39 |
)
|
40 |
|
41 |
logger = logging.getLogger(__name__)
|
42 |
+
logger.addFilter(secure_filter)
|
43 |
+
|
44 |
+
# HTTP ์์ฒญ ๋ก๊ทธ๋ ์จ๊น
|
45 |
+
logging.getLogger("httpx").setLevel(logging.WARNING)
|
46 |
+
logging.getLogger("gradio_client").setLevel(logging.WARNING)
|
47 |
|
48 |
# API ํด๋ผ์ด์ธํธ ์ด๊ธฐํ
|
49 |
def get_api_client():
|
|
|
140 |
return os.environ.get('CONTROL_TOWER_TEMP', tempfile.gettempdir())
|
141 |
|
142 |
def get_session_id():
|
143 |
+
"""์ธ์
ID ์์ฑ - ์๋ณธ API์ ๋์ผ"""
|
144 |
+
try:
|
145 |
+
client = get_api_client()
|
146 |
+
result = client.predict(api_name="/get_session_id")
|
147 |
+
return result
|
148 |
+
except Exception as e:
|
149 |
+
logger.error(f"์ธ์
ID ์์ฑ API ํธ์ถ ์ค๋ฅ: {e}")
|
150 |
+
return str(uuid.uuid4())
|
151 |
|
152 |
def cleanup_session_files(session_id, delay=300):
|
153 |
"""์ธ์
๋ณ ์์ ํ์ผ ์ ๋ฆฌ ํจ์"""
|
|
|
222 |
register_session_file(session_id, temp_file_path)
|
223 |
return temp_file_path
|
224 |
|
225 |
+
# ========== ์๋ณธ API์ ์ ํํ ๋์ผํ ํจ์๋ค ==========
|
226 |
+
|
227 |
+
def search_with_loading(keyword, korean_only, apply_main_keyword, exclude_zero_volume):
|
228 |
+
"""์๋ณธ API: /search_with_loading (4๊ฐ ๋งค๊ฐ๋ณ์, 1๊ฐ ๋ฐํ๊ฐ)"""
|
229 |
+
try:
|
230 |
+
client = get_api_client()
|
231 |
+
result = client.predict(
|
232 |
+
keyword=keyword,
|
233 |
+
korean_only=korean_only,
|
234 |
+
apply_main_keyword=apply_main_keyword,
|
235 |
+
exclude_zero_volume=exclude_zero_volume,
|
236 |
+
api_name="/search_with_loading"
|
237 |
+
)
|
238 |
+
return result
|
239 |
+
except Exception as e:
|
240 |
+
logger.error(f"search_with_loading API ํธ์ถ ์ค๋ฅ: {e}")
|
241 |
+
return gr.update(visible=True)
|
242 |
+
|
243 |
+
def process_search_results(keyword, korean_only, apply_main_keyword, exclude_zero_volume):
|
244 |
+
"""์๋ณธ API: /process_search_results (4๊ฐ ๋งค๊ฐ๋ณ์, 6๊ฐ ๋ฐํ๊ฐ)"""
|
245 |
try:
|
246 |
client = get_api_client()
|
|
|
|
|
247 |
result = client.predict(
|
248 |
keyword=keyword,
|
249 |
korean_only=korean_only,
|
250 |
+
apply_main_keyword=apply_main_keyword,
|
251 |
exclude_zero_volume=exclude_zero_volume,
|
252 |
api_name="/process_search_results"
|
253 |
)
|
254 |
|
255 |
+
# ์๋ณธ API ๋ฌธ์์ ๋ฐ๋ฅด๋ฉด 6๊ฐ ๋ฐํ๊ฐ์ด์ง๋ง ์ค์ ๋ก๋ 5๊ฐ์ผ ์ ์์
|
256 |
+
# ์์ ํ๊ฒ ์ฒ๋ฆฌ
|
257 |
+
if len(result) == 6:
|
258 |
+
table_html, cat_choices, vol_choices, selected_cat, download_file, progress_html = result
|
259 |
+
elif len(result) == 5:
|
260 |
+
table_html, cat_choices, vol_choices, selected_cat, download_file = result
|
261 |
+
progress_html = ""
|
262 |
+
else:
|
263 |
+
logger.error(f"์์๊ณผ ๋ค๋ฅธ ๋ฐํ๊ฐ ๊ฐ์: {len(result)}")
|
264 |
+
return (
|
265 |
+
"<p>์๋น์ค ์๋ต ํ์์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.</p>",
|
266 |
+
["์ ์ฒด ๋ณด๊ธฐ"], ["์ ์ฒด"], "์ ์ฒด ๋ณด๊ธฐ", None, ""
|
267 |
+
)
|
268 |
|
269 |
# ๋ค์ด๋ก๋ ํ์ผ์ด ์๋ ๊ฒฝ์ฐ ๋ก์ปฌ๋ก ๋ณต์ฌ
|
270 |
+
local_download_file = None
|
271 |
if download_file:
|
272 |
+
session_id = get_session_id()
|
273 |
+
local_download_file = create_session_temp_file(session_id, '.xlsx')
|
274 |
try:
|
275 |
+
shutil.copy2(download_file, local_download_file)
|
|
|
276 |
except Exception as e:
|
277 |
logger.error(f"ํ์ผ ๋ณต์ฌ ์ค๋ฅ: {e}")
|
278 |
+
local_download_file = None
|
279 |
|
280 |
+
return table_html, cat_choices, vol_choices, selected_cat, local_download_file, progress_html
|
|
|
281 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
282 |
except Exception as e:
|
283 |
logger.error(f"API ํธ์ถ ์ค๋ฅ: {e}")
|
284 |
+
return (
|
285 |
+
"<p>์๋น์ค ์ฐ๊ฒฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค. ์ ์ ํ ๋ค์ ์๋ํด์ฃผ์ธ์.</p>",
|
286 |
+
["์ ์ฒด ๋ณด๊ธฐ"], ["์ ์ฒด"], "์ ์ฒด ๋ณด๊ธฐ", None, ""
|
287 |
+
)
|
288 |
+
|
289 |
+
def filter_and_sort_table(selected_cat, keyword_sort, total_volume_sort, usage_count_sort, selected_volume_range, exclude_zero_volume):
|
290 |
+
"""์๋ณธ API: /filter_and_sort_table (6๊ฐ ๋งค๊ฐ๋ณ์, 1๊ฐ ๋ฐํ๊ฐ)"""
|
|
|
|
|
291 |
try:
|
292 |
client = get_api_client()
|
|
|
|
|
293 |
result = client.predict(
|
294 |
+
selected_cat=selected_cat,
|
295 |
+
keyword_sort=keyword_sort,
|
296 |
+
total_volume_sort=total_volume_sort,
|
297 |
+
usage_count_sort=usage_count_sort,
|
298 |
+
selected_volume_range=selected_volume_range,
|
299 |
+
exclude_zero_volume=exclude_zero_volume,
|
300 |
+
api_name="/filter_and_sort_table"
|
301 |
)
|
302 |
+
return result
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
303 |
except Exception as e:
|
304 |
+
logger.error(f"filter_and_sort_table API ํธ์ถ ์ค๋ฅ: {e}")
|
305 |
+
return "<p>ํํฐ๋ง ์๋น์ค ์ฐ๊ฒฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.</p>"
|
306 |
|
307 |
+
def filter_and_sort_table_1(selected_cat, keyword_sort, total_volume_sort, usage_count_sort, selected_volume_range, exclude_zero_volume):
|
308 |
+
"""์๋ณธ API: /filter_and_sort_table_1"""
|
|
|
|
|
309 |
try:
|
310 |
client = get_api_client()
|
|
|
|
|
311 |
result = client.predict(
|
312 |
selected_cat=selected_cat,
|
313 |
keyword_sort=keyword_sort,
|
|
|
315 |
usage_count_sort=usage_count_sort,
|
316 |
selected_volume_range=selected_volume_range,
|
317 |
exclude_zero_volume=exclude_zero_volume,
|
318 |
+
api_name="/filter_and_sort_table_1"
|
319 |
)
|
|
|
320 |
return result
|
|
|
321 |
except Exception as e:
|
322 |
+
logger.error(f"filter_and_sort_table_1 API ํธ์ถ ์ค๋ฅ: {e}")
|
323 |
return "<p>ํํฐ๋ง ์๋น์ค ์ฐ๊ฒฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.</p>"
|
324 |
|
325 |
+
def filter_and_sort_table_2(selected_cat, keyword_sort, total_volume_sort, usage_count_sort, selected_volume_range, exclude_zero_volume):
|
326 |
+
"""์๋ณธ API: /filter_and_sort_table_2"""
|
327 |
+
try:
|
328 |
+
client = get_api_client()
|
329 |
+
result = client.predict(
|
330 |
+
selected_cat=selected_cat,
|
331 |
+
keyword_sort=keyword_sort,
|
332 |
+
total_volume_sort=total_volume_sort,
|
333 |
+
usage_count_sort=usage_count_sort,
|
334 |
+
selected_volume_range=selected_volume_range,
|
335 |
+
exclude_zero_volume=exclude_zero_volume,
|
336 |
+
api_name="/filter_and_sort_table_2"
|
337 |
+
)
|
338 |
+
return result
|
339 |
+
except Exception as e:
|
340 |
+
logger.error(f"filter_and_sort_table_2 API ํธ์ถ ์ค๋ฅ: {e}")
|
341 |
+
return "<p>ํํฐ๋ง ์๋น์ค ์ฐ๊ฒฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.</p>"
|
342 |
+
|
343 |
+
def filter_and_sort_table_3(selected_cat, keyword_sort, total_volume_sort, usage_count_sort, selected_volume_range, exclude_zero_volume):
|
344 |
+
"""์๋ณธ API: /filter_and_sort_table_3"""
|
345 |
+
try:
|
346 |
+
client = get_api_client()
|
347 |
+
result = client.predict(
|
348 |
+
selected_cat=selected_cat,
|
349 |
+
keyword_sort=keyword_sort,
|
350 |
+
total_volume_sort=total_volume_sort,
|
351 |
+
usage_count_sort=usage_count_sort,
|
352 |
+
selected_volume_range=selected_volume_range,
|
353 |
+
exclude_zero_volume=exclude_zero_volume,
|
354 |
+
api_name="/filter_and_sort_table_3"
|
355 |
+
)
|
356 |
+
return result
|
357 |
+
except Exception as e:
|
358 |
+
logger.error(f"filter_and_sort_table_3 API ํธ์ถ ์ค๋ฅ: {e}")
|
359 |
+
return "<p>ํํฐ๋ง ์๋น์ค ์ฐ๊ฒฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.</p>"
|
360 |
+
|
361 |
+
def filter_and_sort_table_4(selected_cat, keyword_sort, total_volume_sort, usage_count_sort, selected_volume_range, exclude_zero_volume):
|
362 |
+
"""์๋ณธ API: /filter_and_sort_table_4"""
|
363 |
+
try:
|
364 |
+
client = get_api_client()
|
365 |
+
result = client.predict(
|
366 |
+
selected_cat=selected_cat,
|
367 |
+
keyword_sort=keyword_sort,
|
368 |
+
total_volume_sort=total_volume_sort,
|
369 |
+
usage_count_sort=usage_count_sort,
|
370 |
+
selected_volume_range=selected_volume_range,
|
371 |
+
exclude_zero_volume=exclude_zero_volume,
|
372 |
+
api_name="/filter_and_sort_table_4"
|
373 |
+
)
|
374 |
+
return result
|
375 |
+
except Exception as e:
|
376 |
+
logger.error(f"filter_and_sort_table_4 API ํธ์ถ ์ค๋ฅ: {e}")
|
377 |
+
return "<p>ํํฐ๋ง ์๋น์ค ์ฐ๊ฒฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.</p>"
|
378 |
+
|
379 |
+
def update_category_selection(selected_cat):
|
380 |
+
"""์๋ณธ API: /update_category_selection (1๊ฐ ๋งค๊ฐ๋ณ์, 1๊ฐ ๋ฐํ๊ฐ)"""
|
381 |
try:
|
382 |
client = get_api_client()
|
|
|
383 |
result = client.predict(
|
384 |
selected_cat=selected_cat,
|
385 |
api_name="/update_category_selection"
|
386 |
)
|
|
|
387 |
return gr.update(value=result)
|
|
|
388 |
except Exception as e:
|
389 |
+
logger.error(f"update_category_selection API ํธ์ถ ์ค๋ฅ: {e}")
|
390 |
return gr.update(value=selected_cat)
|
391 |
|
392 |
+
def analyze_with_loading(analysis_keywords, selected_category):
|
393 |
+
"""์๋ณธ API: /analyze_with_loading (2๊ฐ ๋งค๊ฐ๋ณ์, 1๊ฐ ๋ฐํ๊ฐ)"""
|
394 |
+
try:
|
395 |
+
client = get_api_client()
|
396 |
+
result = client.predict(
|
397 |
+
analysis_keywords=analysis_keywords,
|
398 |
+
selected_category=selected_category,
|
399 |
+
api_name="/analyze_with_loading"
|
400 |
+
)
|
401 |
+
return result
|
402 |
+
except Exception as e:
|
403 |
+
logger.error(f"analyze_with_loading API ํธ์ถ ์ค๋ฅ: {e}")
|
404 |
+
return gr.update(visible=True)
|
405 |
+
|
406 |
+
def process_analyze_results(analysis_keywords, selected_category):
|
407 |
+
"""์๋ณธ API: /process_analyze_results (2๊ฐ ๋งค๊ฐ๋ณ์, 2๊ฐ ๋ฐํ๊ฐ)"""
|
408 |
+
try:
|
409 |
+
client = get_api_client()
|
410 |
+
result = client.predict(
|
411 |
+
analysis_keywords=analysis_keywords,
|
412 |
+
selected_category=selected_category,
|
413 |
+
api_name="/process_analyze_results"
|
414 |
+
)
|
415 |
+
|
416 |
+
analysis_result, download_file = result
|
417 |
+
|
418 |
+
# ๋ค์ด๋ก๋ ํ์ผ์ด ์๋ ๊ฒฝ์ฐ ๋ก์ปฌ๋ก ๋ณต์ฌ
|
419 |
+
local_download_file = None
|
420 |
+
if download_file:
|
421 |
+
session_id = get_session_id()
|
422 |
+
local_download_file = create_session_temp_file(session_id, '.xlsx')
|
423 |
try:
|
424 |
+
shutil.copy2(download_file, local_download_file)
|
|
|
|
|
425 |
except Exception as e:
|
426 |
+
logger.error(f"๋ถ์ ๊ฒฐ๊ณผ ํ์ผ ๋ณต์ฌ ์ค๋ฅ: {e}")
|
427 |
+
local_download_file = None
|
428 |
+
|
429 |
+
return analysis_result, local_download_file
|
430 |
+
|
431 |
+
except Exception as e:
|
432 |
+
logger.error(f"process_analyze_results API ํธ์ถ ์ค๋ฅ: {e}")
|
433 |
+
return "๋ถ์ ์๋น์ค ์ฐ๊ฒฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค. ์ ์ ํ ๋ค์ ์๋ํด์ฃผ์ธ์.", None
|
434 |
+
|
435 |
+
def reset_interface():
|
436 |
+
"""์๋ณธ API: /reset_interface (0๊ฐ ๋งค๊ฐ๋ณ์, 16๊ฐ ๋ฐํ๊ฐ)"""
|
437 |
try:
|
438 |
client = get_api_client()
|
|
|
439 |
result = client.predict(api_name="/reset_interface")
|
|
|
440 |
return result
|
|
|
441 |
except Exception as e:
|
442 |
+
logger.error(f"reset_interface API ํธ์ถ ์ค๋ฅ: {e}")
|
443 |
+
# ๊ธฐ๋ณธ ๋ฆฌ์
๊ฐ ๋ฐํ (16๊ฐ)
|
444 |
return (
|
445 |
"", # ๊ฒ์ ํค์๋
|
446 |
True, # ํ๊ธ๋ง ์ถ์ถ
|
447 |
False, # ๊ฒ์๋ 0 ํค์๋ ์ ์ธ
|
448 |
"๋ฉ์ธํค์๋ ์ ์ฉ", # ์กฐํฉ ๋ฐฉ์
|
449 |
"", # HTML ํ
์ด๋ธ
|
450 |
+
["์ ์ฒด ๋ณด๊ธฐ"], # ์นดํ
๊ณ ๋ฆฌ ํํฐ choices
|
451 |
+
"์ ์ฒด ๋ณด๊ธฐ", # ์นดํ
๊ณ ๋ฆฌ ํํฐ value
|
452 |
+
["์ ์ฒด"], # ๊ฒ์๋ ๊ตฌ๊ฐ ํํฐ choices
|
453 |
+
"์ ์ฒด", # ๊ฒ์๋ ๊ตฌ๊ฐ ํํฐ value
|
454 |
"์ ๋ ฌ ์์", # ์ด๊ฒ์๋ ์ ๋ ฌ
|
455 |
"์ ๋ ฌ ์์", # ํค์๋ ์ฌ์ฉํ์ ์ ๋ ฌ
|
456 |
+
["์ ์ฒด ๋ณด๊ธฐ"], # ๋ถ์ํ ์นดํ
๊ณ ๋ฆฌ choices
|
457 |
+
"์ ์ฒด ๋ณด๊ธฐ", # ๋ถ์ํ ์นดํ
๊ณ ๋ฆฌ value
|
458 |
"", # ํค์๋ ์
๋ ฅ
|
459 |
"", # ๋ถ์ ๊ฒฐ๊ณผ
|
460 |
+
None # ๋ค์ด๋ก๋ ํ์ผ
|
|
|
|
|
|
|
461 |
)
|
462 |
|
463 |
+
# ========== UI ์ฒ๋ฆฌ ๋ํผ ํจ์๋ค ==========
|
464 |
+
|
465 |
+
def wrapper_search_with_loading(keyword, korean_only, apply_main_keyword, exclude_zero_volume):
|
466 |
+
"""๊ฒ์ ๋ก๋ฉ UI ์ฒ๋ฆฌ"""
|
467 |
+
result = search_with_loading(keyword, korean_only, apply_main_keyword, exclude_zero_volume)
|
468 |
return (
|
469 |
+
gr.update(visible=True), # progress_section
|
470 |
+
gr.update(visible=False) # empty_table_html
|
471 |
)
|
472 |
|
473 |
+
def wrapper_process_search_results(keyword, korean_only, apply_main_keyword, exclude_zero_volume):
|
474 |
+
"""๊ฒ์ ๊ฒฐ๊ณผ ์ฒ๋ฆฌ UI"""
|
475 |
+
result = process_search_results(keyword, korean_only, apply_main_keyword, exclude_zero_volume)
|
|
|
476 |
|
477 |
+
# ์์ ํ๊ฒ ๊ฒฐ๊ณผ ์ฒ๋ฆฌ
|
478 |
+
if len(result) >= 5:
|
479 |
+
table_html, cat_choices, vol_choices, selected_cat, download_file = result[:5]
|
480 |
+
progress_html = result[5] if len(result) > 5 else ""
|
481 |
+
else:
|
482 |
+
logger.error(f"๊ฒ์ ๊ฒฐ๊ณผ ์ฒ๋ฆฌ ์ค๋ฅ: ์์๋ณด๋ค ์ ์ ๋ฐํ๊ฐ {len(result)}")
|
483 |
+
table_html = "<p>๊ฒ์ ๊ฒฐ๊ณผ ์ฒ๋ฆฌ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.</p>"
|
484 |
+
cat_choices = ["์ ์ฒด ๋ณด๊ธฐ"]
|
485 |
+
vol_choices = ["์ ์ฒด"]
|
486 |
+
selected_cat = "์ ์ฒด ๋ณด๊ธฐ"
|
487 |
+
download_file = None
|
488 |
+
progress_html = ""
|
489 |
|
490 |
+
# UI ํ์ ์ฌ๋ถ ๊ฒฐ์
|
491 |
+
if table_html and "๊ฒ์ ๊ฒฐ๊ณผ๊ฐ ์์ต๋๋ค" not in table_html and "๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค" not in table_html:
|
492 |
keyword_section_visibility = True
|
493 |
+
category_section_visibility = True
|
494 |
+
empty_placeholder_vis = False
|
495 |
execution_section_visibility = True
|
496 |
else:
|
|
|
497 |
keyword_section_visibility = False
|
498 |
+
category_section_visibility = False
|
499 |
+
empty_placeholder_vis = True
|
500 |
execution_section_visibility = False
|
501 |
|
502 |
+
# ๊ฐ์์ state_df (์๋ณธ๊ณผ ํธํ์ฑ์ ์ํด)
|
503 |
+
state_df = pd.DataFrame()
|
504 |
+
|
505 |
return (
|
506 |
+
table_html, # table_output
|
507 |
+
cat_choices, # category_filter choices
|
508 |
+
vol_choices, # search_volume_filter choices
|
509 |
+
state_df, # state_df
|
510 |
+
selected_cat, # selected_category value
|
511 |
+
download_file, # download_output
|
512 |
+
gr.update(visible=keyword_section_visibility), # keyword_analysis_section
|
513 |
+
gr.update(visible=category_section_visibility), # category_analysis_section
|
514 |
+
gr.update(visible=False), # progress_section
|
515 |
+
gr.update(visible=empty_placeholder_vis), # empty_table_html
|
516 |
+
gr.update(visible=execution_section_visibility), # execution_section
|
517 |
+
keyword # keyword_state
|
518 |
)
|
519 |
|
520 |
+
def wrapper_analyze_with_loading(analysis_keywords, selected_category, state_df):
|
521 |
+
"""๋ถ์ ๋ก๋ฉ UI ์ฒ๋ฆฌ"""
|
522 |
+
result = analyze_with_loading(analysis_keywords, selected_category)
|
523 |
+
return gr.update(visible=True) # progress_section
|
524 |
|
525 |
+
def wrapper_process_analyze_results(analysis_keywords, selected_category, state_df):
|
526 |
+
"""๋ถ์ ๊ฒฐ๊ณผ ์ฒ๋ฆฌ UI"""
|
527 |
+
analysis_result, download_file = process_analyze_results(analysis_keywords, selected_category)
|
528 |
+
return (
|
529 |
+
analysis_result, # analysis_result
|
530 |
+
download_file, # download_output
|
531 |
+
gr.update(visible=True), # analysis_output_section
|
532 |
+
gr.update(visible=False) # progress_section
|
533 |
+
)
|
534 |
|
535 |
# ์ธ์
์ ๋ฆฌ ์ค์ผ์ค๋ฌ
|
536 |
def start_session_cleanup_scheduler():
|
|
|
539 |
while True:
|
540 |
time.sleep(600) # 10๋ถ๋ง๋ค ์คํ
|
541 |
cleanup_old_sessions()
|
|
|
542 |
cleanup_huggingface_temp_folders()
|
543 |
|
544 |
threading.Thread(target=cleanup_scheduler, daemon=True).start()
|
|
|
602 |
)) as demo:
|
603 |
gr.HTML(fontawesome_html)
|
604 |
|
|
|
|
|
|
|
605 |
# ํค์๋ ์ํ ๊ด๋ฆฌ
|
606 |
keyword_state = gr.State("")
|
607 |
|
|
|
774 |
# ์ํ ์ ์ฅ์ฉ ๋ณ์
|
775 |
state_df = gr.State()
|
776 |
|
777 |
+
# ์ด๋ฒคํธ ์ฐ๊ฒฐ
|
778 |
search_btn.click(
|
779 |
+
fn=wrapper_search_with_loading,
|
780 |
+
inputs=[keyword, korean_only, apply_main_keyword, exclude_zero_volume],
|
781 |
outputs=[progress_section, empty_table_html]
|
782 |
).then(
|
783 |
+
fn=wrapper_process_search_results,
|
784 |
+
inputs=[keyword, korean_only, apply_main_keyword, exclude_zero_volume],
|
785 |
outputs=[
|
786 |
table_output, category_filter, search_volume_filter,
|
787 |
state_df, selected_category, download_output,
|
|
|
791 |
]
|
792 |
)
|
793 |
|
794 |
+
# ํํฐ ๋ฐ ์ ๋ ฌ ๋ณ๊ฒฝ ์ด๋ฒคํธ ์ฐ๊ฒฐ
|
795 |
category_filter.change(
|
796 |
fn=filter_and_sort_table,
|
797 |
inputs=[
|
798 |
+
category_filter, gr.Textbox(value="์ ๋ ฌ ์์", visible=False),
|
799 |
total_volume_sort, usage_count_sort,
|
800 |
+
search_volume_filter, exclude_zero_volume
|
801 |
],
|
802 |
outputs=[table_output]
|
803 |
)
|
804 |
|
805 |
category_filter.change(
|
806 |
fn=update_category_selection,
|
807 |
+
inputs=[category_filter],
|
808 |
outputs=[selected_category]
|
809 |
)
|
810 |
|
811 |
total_volume_sort.change(
|
812 |
fn=filter_and_sort_table,
|
813 |
inputs=[
|
814 |
+
category_filter, gr.Textbox(value="์ ๋ ฌ ์์", visible=False),
|
815 |
total_volume_sort, usage_count_sort,
|
816 |
+
search_volume_filter, exclude_zero_volume
|
817 |
],
|
818 |
outputs=[table_output]
|
819 |
)
|
|
|
821 |
usage_count_sort.change(
|
822 |
fn=filter_and_sort_table,
|
823 |
inputs=[
|
824 |
+
category_filter, gr.Textbox(value="์ ๋ ฌ ์์", visible=False),
|
825 |
total_volume_sort, usage_count_sort,
|
826 |
+
search_volume_filter, exclude_zero_volume
|
827 |
],
|
828 |
outputs=[table_output]
|
829 |
)
|
|
|
831 |
search_volume_filter.change(
|
832 |
fn=filter_and_sort_table,
|
833 |
inputs=[
|
834 |
+
category_filter, gr.Textbox(value="์ ๋ ฌ ์์", visible=False),
|
835 |
total_volume_sort, usage_count_sort,
|
836 |
+
search_volume_filter, exclude_zero_volume
|
837 |
],
|
838 |
outputs=[table_output]
|
839 |
)
|
|
|
841 |
exclude_zero_volume.change(
|
842 |
fn=filter_and_sort_table,
|
843 |
inputs=[
|
844 |
+
category_filter, gr.Textbox(value="์ ๋ ฌ ์์", visible=False),
|
845 |
total_volume_sort, usage_count_sort,
|
846 |
+
search_volume_filter, exclude_zero_volume
|
847 |
],
|
848 |
outputs=[table_output]
|
849 |
)
|
850 |
|
851 |
+
# ์นดํ
๊ณ ๋ฆฌ ๋ถ์ ๋ฒํผ ์ด๋ฒคํธ
|
852 |
analyze_btn.click(
|
853 |
+
fn=wrapper_analyze_with_loading,
|
854 |
+
inputs=[analysis_keywords, selected_category, state_df],
|
855 |
outputs=[progress_section]
|
856 |
).then(
|
857 |
+
fn=wrapper_process_analyze_results,
|
858 |
+
inputs=[analysis_keywords, selected_category, state_df],
|
859 |
outputs=[analysis_result, download_output, analysis_output_section, progress_section]
|
860 |
)
|
861 |
|
862 |
+
# ๋ฆฌ์
๋ฒํผ ์ด๋ฒคํธ ์ฐ๊ฒฐ
|
863 |
reset_btn.click(
|
864 |
fn=reset_interface,
|
865 |
+
inputs=[],
|
866 |
outputs=[
|
867 |
keyword, korean_only, exclude_zero_volume, apply_main_keyword,
|
868 |
table_output, category_filter, category_filter,
|
869 |
search_volume_filter, search_volume_filter,
|
870 |
total_volume_sort, usage_count_sort,
|
871 |
selected_category, selected_category,
|
872 |
+
analysis_keywords, analysis_result, download_output
|
|
|
|
|
873 |
]
|
874 |
)
|
875 |
|
876 |
+
return demo
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|