ssboost commited on
Commit
0ea543e
ยท
verified ยท
1 Parent(s): 304e207

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +339 -1
app.py CHANGED
@@ -671,4 +671,342 @@ def create_app():
671
  margin-bottom: 10px;
672
  text-align: center;
673
  }
674
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
671
  margin-bottom: 10px;
672
  text-align: center;
673
  }
674
+ """
675
+
676
+ with gr.Blocks(css=custom_css, theme=gr.themes.Default(
677
+ primary_hue="orange",
678
+ secondary_hue="orange",
679
+ font=[gr.themes.GoogleFont("Noto Sans KR"), "ui-sans-serif", "system-ui"]
680
+ )) as demo:
681
+ gr.HTML(fontawesome_html)
682
+
683
+ # ์„ธ์…˜ ID ์ƒํƒœ (๊ฐ ์‚ฌ์šฉ์ž๋ณ„๋กœ ๊ณ ์œ )
684
+ session_id = gr.State(get_session_id)
685
+
686
+ # ํ‚ค์›Œ๋“œ ์ƒํƒœ ๊ด€๋ฆฌ
687
+ keyword_state = gr.State("")
688
+
689
+ # ์ž…๋ ฅ ์„น์…˜
690
+ with gr.Column(elem_classes="custom-frame fade-in"):
691
+ gr.HTML('<div class="section-title"><i class="fas fa-search"></i> ๊ฒ€์ƒ‰ ์ž…๋ ฅ</div>')
692
+
693
+ with gr.Row():
694
+ with gr.Column(scale=1):
695
+ keyword = gr.Textbox(
696
+ label="๋ฉ”์ธ ํ‚ค์›Œ๋“œ",
697
+ placeholder="์˜ˆ: ์˜ค์ง•์–ด"
698
+ )
699
+ with gr.Column(scale=1):
700
+ search_btn = gr.Button(
701
+ "๋ฉ”์ธํ‚ค์›Œ๋“œ ๋ถ„์„",
702
+ elem_classes="custom-button"
703
+ )
704
+
705
+ with gr.Accordion("์˜ต์…˜ ์„ค์ •", open=False):
706
+ with gr.Row():
707
+ with gr.Column(scale=1):
708
+ korean_only = gr.Checkbox(
709
+ label="ํ•œ๊ธ€๋งŒ ์ถ”์ถœ",
710
+ value=True
711
+ )
712
+ with gr.Column(scale=1):
713
+ exclude_zero_volume = gr.Checkbox(
714
+ label="๊ฒ€์ƒ‰๋Ÿ‰ 0 ํ‚ค์›Œ๋“œ ์ œ์™ธ",
715
+ value=False
716
+ )
717
+
718
+ with gr.Row():
719
+ with gr.Column(scale=1):
720
+ apply_main_keyword = gr.Radio(
721
+ ["๋ฉ”์ธํ‚ค์›Œ๋“œ ์ ์šฉ", "๋ฉ”์ธํ‚ค์›Œ๋“œ ๋ฏธ์ ์šฉ"],
722
+ label="์กฐํ•ฉ ๋ฐฉ์‹",
723
+ value="๋ฉ”์ธํ‚ค์›Œ๋“œ ์ ์šฉ"
724
+ )
725
+ with gr.Column(scale=1):
726
+ gr.HTML("")
727
+
728
+ # ์ง„ํ–‰ ์ƒํƒœ ํ‘œ์‹œ ์„น์…˜
729
+ with gr.Column(elem_classes="custom-frame fade-in", visible=False) as progress_section:
730
+ gr.HTML('<div class="section-title"><i class="fas fa-spinner"></i> ๋ถ„์„ ์ง„ํ–‰ ์ƒํƒœ</div>')
731
+ progress_html = gr.HTML("""
732
+ <div style="padding: 15px; background-color: #f9f9f9; border-radius: 5px; margin: 10px 0; border: 1px solid #ddd;">
733
+ <div style="margin-bottom: 10px; display: flex; align-items: center;">
734
+ <i class="fas fa-spinner fa-spin" style="color: #FB7F0D; margin-right: 10px;"></i>
735
+ <span>ํ‚ค์›Œ๋“œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„์„์ค‘์ž…๋‹ˆ๋‹ค. ์ž ์‹œ๋งŒ ๊ธฐ๋‹ค๋ ค์ฃผ์„ธ์š”...</span>
736
+ </div>
737
+ <div style="background-color: #e9ecef; height: 10px; border-radius: 5px; overflow: hidden;">
738
+ <div class="progress-bar"></div>
739
+ </div>
740
+ </div>
741
+ """)
742
+
743
+ # ๋ฉ”์ธํ‚ค์›Œ๋“œ ๋ถ„์„ ๊ฒฐ๊ณผ ์„น์…˜
744
+ with gr.Column(elem_classes="custom-frame fade-in") as main_keyword_section:
745
+ gr.HTML('<div class="section-title"><i class="fas fa-table"></i> ๋ฉ”์ธํ‚ค์›Œ๋“œ ๋ถ„์„ ๊ฒฐ๊ณผ</div>')
746
+
747
+ empty_table_html = gr.HTML("""
748
+ <table class="empty-table">
749
+ <thead>
750
+ <tr>
751
+ <th>์ˆœ๋ฒˆ</th>
752
+ <th>์กฐํ•ฉ ํ‚ค์›Œ๋“œ</th>
753
+ <th>PC๊ฒ€์ƒ‰๋Ÿ‰</th>
754
+ <th>๋ชจ๋ฐ”์ผ๊ฒ€์ƒ‰๋Ÿ‰</th>
755
+ <th>์ด๊ฒ€์ƒ‰๋Ÿ‰</th>
756
+ <th>๊ฒ€์ƒ‰๋Ÿ‰๊ตฌ๊ฐ„</th>
757
+ <th>ํ‚ค์›Œ๋“œ ์‚ฌ์šฉ์ž์ˆœ์œ„</th>
758
+ <th>ํ‚ค์›Œ๋“œ ์‚ฌ์šฉํšŸ์ˆ˜</th>
759
+ <th>์ƒํ’ˆ ๋“ฑ๋ก ์นดํ…Œ๊ณ ๋ฆฌ</th>
760
+ </tr>
761
+ </thead>
762
+ <tbody>
763
+ <tr>
764
+ <td colspan="9" style="padding: 30px; text-align: center;">
765
+ ๊ฒ€์ƒ‰์„ ์‹คํ–‰ํ•˜๋ฉด ์—ฌ๊ธฐ์— ๊ฒฐ๊ณผ๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค
766
+ </td>
767
+ </tr>
768
+ </tbody>
769
+ </table>
770
+ """)
771
+
772
+ with gr.Column(visible=False) as keyword_analysis_section:
773
+ with gr.Row():
774
+ with gr.Column(scale=1):
775
+ category_filter = gr.Dropdown(
776
+ choices=["์ „์ฒด ๋ณด๊ธฐ"],
777
+ label="์นดํ…Œ๊ณ ๋ฆฌ ํ•„ํ„ฐ",
778
+ value="์ „์ฒด ๋ณด๊ธฐ",
779
+ interactive=True
780
+ )
781
+ with gr.Column(scale=1):
782
+ total_volume_sort = gr.Dropdown(
783
+ choices=["์ •๋ ฌ ์—†์Œ", "์˜ค๋ฆ„์ฐจ์ˆœ", "๋‚ด๋ฆผ์ฐจ์ˆœ"],
784
+ label="์ด๊ฒ€์ƒ‰๋Ÿ‰ ์ •๋ ฌ",
785
+ value="์ •๋ ฌ ์—†์Œ",
786
+ interactive=True
787
+ )
788
+
789
+ with gr.Row():
790
+ with gr.Column(scale=1):
791
+ search_volume_filter = gr.Dropdown(
792
+ choices=["์ „์ฒด"],
793
+ label="๊ฒ€์ƒ‰๋Ÿ‰ ๊ตฌ๊ฐ„ ํ•„ํ„ฐ",
794
+ value="์ „์ฒด",
795
+ interactive=True
796
+ )
797
+ with gr.Column(scale=1):
798
+ usage_count_sort = gr.Dropdown(
799
+ choices=["์ •๋ ฌ ์—†์Œ", "์˜ค๋ฆ„์ฐจ์ˆœ", "๋‚ด๋ฆผ์ฐจ์ˆœ"],
800
+ label="ํ‚ค์›Œ๋“œ ์‚ฌ์šฉํšŸ์ˆ˜ ์ •๋ ฌ",
801
+ value="์ •๋ ฌ ์—†์Œ",
802
+ interactive=True
803
+ )
804
+
805
+ gr.HTML("<div class='data-container' id='table_container'></div>")
806
+ table_output = gr.HTML(elem_classes="fade-in")
807
+
808
+ # ์นดํ…Œ๊ณ ๋ฆฌ ๋ถ„์„ ์„น์…˜
809
+ with gr.Column(elem_classes="custom-frame fade-in", visible=False) as category_analysis_section:
810
+ gr.HTML('<div class="section-title"><i class="fas fa-chart-bar"></i> ํ‚ค์›Œ๋“œ ๋ถ„์„</div>')
811
+
812
+ with gr.Row():
813
+ with gr.Column(scale=1):
814
+ analysis_keywords = gr.Textbox(
815
+ label="ํ‚ค์›Œ๋“œ ์ž…๋ ฅ (์ตœ๋Œ€ 20๊ฐœ, ์‰ผํ‘œ ๋˜๋Š” ์—”ํ„ฐ๋กœ ๊ตฌ๋ถ„)",
816
+ placeholder="์˜ˆ: ์˜ค์ง•์–ด๋ณถ์Œ, ์˜ค์ง•์–ด ์†์งˆ, ์˜ค์ง•์–ด ์š”๋ฆฌ...",
817
+ lines=5
818
+ )
819
+
820
+ with gr.Column(scale=1):
821
+ selected_category = gr.Dropdown(
822
+ label="๋ถ„์„ํ•  ์นดํ…Œ๊ณ ๋ฆฌ(๋ถ„์„ ์ „ ๋ฐ˜๋“œ์‹œ ์„ ํƒํ•ด์ฃผ์„ธ์š”)",
823
+ choices=["์ „์ฒด ๋ณด๊ธฐ"],
824
+ value="์ „์ฒด ๋ณด๊ธฐ",
825
+ interactive=True
826
+ )
827
+
828
+ # ์‹คํ–‰ ์„น์…˜
829
+ with gr.Column(elem_classes="execution-section", visible=False) as execution_section:
830
+ gr.HTML('<div class="section-title"><i class="fas fa-play-circle"></i> ์‹คํ–‰</div>')
831
+ with gr.Row():
832
+ with gr.Column(scale=1):
833
+ analyze_btn = gr.Button(
834
+ "์นดํ…Œ๊ณ ๋ฆฌ ์ผ์น˜ ๋ถ„์„",
835
+ elem_classes=["execution-button", "primary-button"]
836
+ )
837
+ with gr.Column(scale=1):
838
+ reset_btn = gr.Button(
839
+ "๋ชจ๋“  ์ž…๋ ฅ ์ดˆ๊ธฐํ™”",
840
+ elem_classes=["execution-button", "secondary-button"]
841
+ )
842
+
843
+ # ๋ถ„์„ ๊ฒฐ๊ณผ ์ถœ๋ ฅ ์„น์…˜
844
+ with gr.Column(elem_classes="custom-frame fade-in", visible=False) as analysis_output_section:
845
+ gr.HTML('<div class="section-title"><i class="fas fa-list-ul"></i> ๋ถ„์„ ๊ฒฐ๊ณผ ์š”์•ฝ</div>')
846
+
847
+ analysis_result = gr.HTML(elem_classes="fade-in")
848
+
849
+ with gr.Row():
850
+ download_output = gr.File(
851
+ label="ํ‚ค์›Œ๋“œ ๋ชฉ๋ก ๋‹ค์šด๋กœ๋“œ",
852
+ visible=True
853
+ )
854
+
855
+ # ์ƒํƒœ ์ €์žฅ์šฉ ๋ณ€์ˆ˜
856
+ state_df = gr.State()
857
+
858
+ # ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ - ๋ชจ๋“  ํ•จ์ˆ˜์— session_id ์ถ”๊ฐ€
859
+ search_btn.click(
860
+ fn=search_with_loading,
861
+ inputs=[keyword, korean_only, apply_main_keyword, exclude_zero_volume, session_id],
862
+ outputs=[progress_section, empty_table_html]
863
+ ).then(
864
+ fn=process_search_results,
865
+ inputs=[keyword, korean_only, apply_main_keyword, exclude_zero_volume, session_id],
866
+ outputs=[
867
+ table_output, category_filter, search_volume_filter,
868
+ state_df, selected_category, download_output,
869
+ keyword_analysis_section, category_analysis_section,
870
+ progress_section, empty_table_html, execution_section,
871
+ keyword_state
872
+ ]
873
+ )
874
+
875
+ # ํ•„ํ„ฐ ๋ฐ ์ •๋ ฌ ๋ณ€๊ฒฝ ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ - session_id ์ถ”๊ฐ€
876
+ category_filter.change(
877
+ fn=filter_and_sort_table,
878
+ inputs=[
879
+ state_df, category_filter, gr.Textbox(value="์ •๋ ฌ ์—†์Œ", visible=False),
880
+ total_volume_sort, usage_count_sort,
881
+ search_volume_filter, exclude_zero_volume, session_id
882
+ ],
883
+ outputs=[table_output]
884
+ )
885
+
886
+ category_filter.change(
887
+ fn=update_category_selection,
888
+ inputs=[category_filter, session_id],
889
+ outputs=[selected_category]
890
+ )
891
+
892
+ total_volume_sort.change(
893
+ fn=filter_and_sort_table,
894
+ inputs=[
895
+ state_df, category_filter, gr.Textbox(value="์ •๋ ฌ ์—†์Œ", visible=False),
896
+ total_volume_sort, usage_count_sort,
897
+ search_volume_filter, exclude_zero_volume, session_id
898
+ ],
899
+ outputs=[table_output]
900
+ )
901
+
902
+ usage_count_sort.change(
903
+ fn=filter_and_sort_table,
904
+ inputs=[
905
+ state_df, category_filter, gr.Textbox(value="์ •๋ ฌ ์—†์Œ", visible=False),
906
+ total_volume_sort, usage_count_sort,
907
+ search_volume_filter, exclude_zero_volume, session_id
908
+ ],
909
+ outputs=[table_output]
910
+ )
911
+
912
+ search_volume_filter.change(
913
+ fn=filter_and_sort_table,
914
+ inputs=[
915
+ state_df, category_filter, gr.Textbox(value="์ •๋ ฌ ์—†์Œ", visible=False),
916
+ total_volume_sort, usage_count_sort,
917
+ search_volume_filter, exclude_zero_volume, session_id
918
+ ],
919
+ outputs=[table_output]
920
+ )
921
+
922
+ exclude_zero_volume.change(
923
+ fn=filter_and_sort_table,
924
+ inputs=[
925
+ state_df, category_filter, gr.Textbox(value="์ •๋ ฌ ์—†์Œ", visible=False),
926
+ total_volume_sort, usage_count_sort,
927
+ search_volume_filter, exclude_zero_volume, session_id
928
+ ],
929
+ outputs=[table_output]
930
+ )
931
+
932
+ # ์นดํ…Œ๊ณ ๋ฆฌ ๋ถ„์„ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ - session_id ์ถ”๊ฐ€
933
+ analyze_btn.click(
934
+ fn=analyze_with_loading,
935
+ inputs=[analysis_keywords, selected_category, state_df, session_id],
936
+ outputs=[progress_section]
937
+ ).then(
938
+ fn=process_analyze_results,
939
+ inputs=[analysis_keywords, selected_category, state_df, session_id],
940
+ outputs=[analysis_result, download_output, analysis_output_section, progress_section]
941
+ )
942
+
943
+ # ๋ฆฌ์…‹ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ - session_id ์ถ”๊ฐ€
944
+ reset_btn.click(
945
+ fn=reset_interface,
946
+ inputs=[session_id],
947
+ outputs=[
948
+ keyword, korean_only, exclude_zero_volume, apply_main_keyword,
949
+ table_output, category_filter, category_filter,
950
+ search_volume_filter, search_volume_filter,
951
+ total_volume_sort, usage_count_sort,
952
+ state_df, selected_category, selected_category,
953
+ analysis_keywords, analysis_result, download_output,
954
+ keyword_analysis_section, analysis_output_section,
955
+ keyword_state
956
+ ]
957
+ )
958
+
959
+ return demo
960
+
961
+ if __name__ == "__main__":
962
+ # ========== ์‹œ์ž‘ ์‹œ ์ „์ฒด ์ดˆ๊ธฐํ™” ==========
963
+ logger.info("๐Ÿš€ ๋ฉ”์ธํ‚ค์›Œ๋“œ ๋ถ„์„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘...")
964
+
965
+ # 1. ์ฒซ ๋ฒˆ์งธ: ํ—ˆ๊น…ํŽ˜์ด์Šค ์ž„์‹œ ํด๋” ์ •๋ฆฌ ๋ฐ ํ™˜๊ฒฝ ์„ค์ •
966
+ app_temp_dir = cleanup_on_startup()
967
+
968
+ # 2. ์„ธ์…˜ ์ •๋ฆฌ ์Šค์ผ€์ค„๋Ÿฌ ์‹œ์ž‘
969
+ start_session_cleanup_scheduler()
970
+
971
+ # 3. API ์„ค์ • ์ดˆ๊ธฐํ™”
972
+ try:
973
+ api_utils.initialize_api_configs()
974
+ except Exception as e:
975
+ logger.warning(f"API ์„ค์ • ์ดˆ๊ธฐํ™” ์ค‘ ์˜ค๋ฅ˜ (๊ณ„์† ์ง„ํ–‰): {e}")
976
+
977
+ # 4. Gemini ๋ชจ๋ธ ์ดˆ๊ธฐํ™”
978
+ try:
979
+ gemini_model = text_utils.get_gemini_model()
980
+ except Exception as e:
981
+ logger.warning(f"Gemini ๋ชจ๋ธ ์ดˆ๊ธฐํ™” ์ค‘ ์˜ค๋ฅ˜ (๊ณ„์† ์ง„ํ–‰): {e}")
982
+
983
+ logger.info("===== ๋ฉ€ํ‹ฐ์œ ์ € ๋ฉ”์ธํ‚ค์›Œ๋“œ ๋ถ„์„ Application Startup at %s =====", time.strftime("%Y-%m-%d %H:%M:%S"))
984
+ logger.info(f"๐Ÿ“ ์ž„์‹œ ํŒŒ์ผ ์ €์žฅ ์œ„์น˜: {app_temp_dir}")
985
+
986
+ # ========== ์•ฑ ์‹คํ–‰ ==========
987
+ try:
988
+ app = create_app()
989
+ app.launch(
990
+ share=False, # ๋ณด์•ˆ์„ ์œ„ํ•ด share ๋น„ํ™œ์„ฑํ™”
991
+ server_name="0.0.0.0", # ๋ชจ๋“  IP์—์„œ ์ ‘๊ทผ ํ—ˆ์šฉ
992
+ server_port=7860, # ํฌํŠธ ์ง€์ •
993
+ max_threads=40, # ๋ฉ€ํ‹ฐ์œ ์ €๋ฅผ ์œ„ํ•œ ์Šค๋ ˆ๋“œ ์ˆ˜ ์ฆ๊ฐ€
994
+ auth=None, # ํ•„์š”์‹œ ์ธ์ฆ ์ถ”๊ฐ€ ๊ฐ€๋Šฅ
995
+ show_error=True, # ์—๋Ÿฌ ํ‘œ์‹œ
996
+ quiet=False, # ๋กœ๊ทธ ํ‘œ์‹œ
997
+ favicon_path=None, # ํŒŒ๋น„์ฝ˜ ์„ค์ •
998
+ ssl_verify=False # SSL ๊ฒ€์ฆ ๋น„ํ™œ์„ฑํ™” (๊ฐœ๋ฐœ์šฉ)
999
+ )
1000
+ except Exception as e:
1001
+ logger.error(f"์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰ ์‹คํŒจ: {e}")
1002
+ raise
1003
+ finally:
1004
+ # ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ข…๋ฃŒ ์‹œ ์ •๋ฆฌ
1005
+ logger.info("๐Ÿงน ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ข…๋ฃŒ - ์ตœ์ข… ์ •๋ฆฌ ์ž‘์—…...")
1006
+ try:
1007
+ cleanup_huggingface_temp_folders()
1008
+ if os.path.exists(app_temp_dir):
1009
+ shutil.rmtree(app_temp_dir, ignore_errors=True)
1010
+ logger.info("โœ… ์ตœ์ข… ์ •๋ฆฌ ์™„๋ฃŒ")
1011
+ except Exception as e:
1012
+ logger.error(f"์ตœ์ข… ์ •๋ฆฌ ์ค‘ ์˜ค๋ฅ˜: {e}")