Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| from src.data_manager import initialize_data | |
| from src.node_functions import ( | |
| get_nodes_dataframe, | |
| add_keyword, | |
| create_node, | |
| filter_nodes_multi, | |
| ) | |
| from src.idea_functions import ( | |
| get_ideas_dataframe, | |
| generate_idea_with_chatgpt, | |
| generate_idea_with_gemini, | |
| ) | |
| from src.ui_handlers import ( | |
| refresh_and_reset, | |
| handle_idea_selection, | |
| handle_delete_idea, | |
| handle_node_selection, | |
| handle_edit_node, | |
| handle_delete_node, | |
| filter_ideas, | |
| refresh_and_clear_status, | |
| refresh_idea_nodes, | |
| ) | |
| from src.about_content import get_about_content | |
| # μ± μμ μ λ°μ΄ν° μ΄κΈ°ν | |
| initialize_data() | |
| # Gradio μΈν°νμ΄μ€ κ΅¬μ± | |
| with gr.Blocks(title="", theme=gr.themes.Soft()) as demo: | |
| # ν€λ | |
| gr.Markdown("# π GGG Idea Studio") | |
| gr.Markdown("---") | |
| # ν κ΅¬μ± | |
| with gr.Tabs(): | |
| # 1. About ν | |
| with gr.Tab("π About") as about_tab: | |
| gr.Markdown(get_about_content()) | |
| # 2. λ Έλ μ λ ₯νκΈ° ν | |
| with gr.Tab("βοΈ λ Έλ μ λ ₯νκΈ°") as node_input_tab: | |
| gr.Markdown("### λ Έλλ₯Ό μμ±νμΈμ") | |
| with gr.Column(): | |
| title_input = gr.Textbox( | |
| label="1. λ Έλ μ λͺ©", placeholder="λ Έλ μ λͺ©μ μ λ ₯νμΈμ" | |
| ) | |
| description_input = gr.Textbox( | |
| label="2. λ Έλμ λν΄ μκ°ν΄μ£ΌμΈμ. (ν΅μ¬κΈ°λ₯κ³Ό μ¬μ© κΈ°μ μ ν¬ν¨νμ¬ μμ±ν΄μ£ΌμΈμ.)", | |
| lines=5, | |
| placeholder="λ Έλμ ν΅μ¬ κΈ°λ₯κ³Ό μ¬μ©λ κΈ°μ μ ν¬ν¨νμ¬ μμΈν μ€λͺ ν΄μ£ΌμΈμ", | |
| ) | |
| tenant_input = gr.Textbox( | |
| label="3. ν λνΈ (κ·Έλ£Ή)", | |
| placeholder="μ΄ λ Έλκ° μν κ·Έλ£Ήμ μ λ ₯νμΈμ (μ: κ΅λ―Όλ, SuperbAI)", | |
| ) | |
| with gr.Row(): | |
| keyword_input = gr.Textbox( | |
| label="ν€μλ", | |
| placeholder="ν€μλλ₯Ό μ λ ₯νμΈμ (μ: νμ΄μ¬, μΈκ³΅μ§λ₯, AWS)", | |
| scale=2, | |
| ) | |
| add_keyword_btn = gr.Button( | |
| "β ν€μλ μΆκ°", | |
| variant="secondary", | |
| scale=1, | |
| ) | |
| tags_display = gr.Textbox( | |
| label="μΆκ°λ ν€μλ", | |
| interactive=False, | |
| placeholder="ν€μλκ° μ¬κΈ°μ νμλ©λλ€", | |
| ) | |
| keyword_status = gr.Textbox(label="ν€μλ μΆκ° μν", interactive=False) | |
| create_btn = gr.Button("β¨ λ Έλ μμ±νκΈ°", variant="primary", size="lg") | |
| create_status = gr.Textbox(label="μμ± κ²°κ³Ό", interactive=False) | |
| # μ΄λ²€νΈ μ°κ²° | |
| add_keyword_btn.click( | |
| add_keyword, | |
| inputs=[keyword_input, tags_display], | |
| outputs=[tags_display, keyword_input, keyword_status], | |
| ) | |
| # μν°ν€λ‘λ ν€μλ μΆκ° κ°λ₯ | |
| keyword_input.submit( | |
| add_keyword, | |
| inputs=[keyword_input, tags_display], | |
| outputs=[tags_display, keyword_input, keyword_status], | |
| ) | |
| create_btn.click( | |
| create_node, | |
| inputs=[title_input, description_input, tenant_input, tags_display], | |
| outputs=[ | |
| create_status, | |
| title_input, | |
| description_input, | |
| tenant_input, | |
| keyword_input, | |
| tags_display, | |
| keyword_status, | |
| ], | |
| ) | |
| # 3. λ΄ λ Έλ νμΈνκΈ° ν | |
| with gr.Tab("π λ΄ λ Έλ νμΈνκΈ°") as node_view_tab: | |
| gr.Markdown("### μμ±λ λͺ¨λ λ Έλλ₯Ό νμΈνκ³ κ΄λ¦¬νμΈμ") | |
| # νν°λ§ μ΅μ λ€ | |
| with gr.Row(): | |
| search_input = gr.Textbox( | |
| label="π λ Έλ μ΄λ¦ κ²μ", | |
| placeholder="κ²μν λ Έλ μ΄λ¦μ μ λ ₯νμΈμ...", | |
| scale=2, | |
| ) | |
| with gr.Row(): | |
| tenant_filter = gr.Dropdown( | |
| label="π’ ν λνΈ νν° (λ€μ€μ ν)", | |
| choices=[], # μ΄κΈ°μλ λΉ λ¦¬μ€νΈ | |
| multiselect=True, | |
| scale=1, | |
| ) | |
| tag_filter = gr.Dropdown( | |
| label="π·οΈ νκ·Έ νν° (λ€μ€μ ν)", | |
| choices=[], # μ΄κΈ°μλ λΉ λ¦¬μ€νΈ | |
| multiselect=True, | |
| scale=1, | |
| ) | |
| nodes_dataframe = gr.Dataframe( | |
| value=get_nodes_dataframe(), | |
| headers=["μμ±μΌμ", "λ Έλ μ΄λ¦", "ν λνΈ", "μ€λͺ ", "νκ·Έ"], | |
| interactive=False, | |
| wrap=False, | |
| elem_id="nodes_table", | |
| ) | |
| # μ νλ λ Έλ μμΈ μ 보 | |
| gr.Markdown("#### π μ νλ λ Έλ μμΈ μ 보") | |
| gr.Markdown( | |
| "*μ ν μ΄λΈμμ νμ ν΄λ¦νλ©΄ ν΄λΉ λ Έλμ μμΈ μ λ³΄κ° νμλ©λλ€.*" | |
| ) | |
| with gr.Accordion("π§ λ Έλ μμΈ μ 보", open=True): | |
| selected_node_title = gr.Textbox(label="λ Έλ μ λͺ©", interactive=True) | |
| selected_node_description = gr.Textbox( | |
| label="λ Έλ μ€λͺ ", lines=4, interactive=True | |
| ) | |
| selected_node_tenant = gr.Textbox(label="ν λνΈ", interactive=True) | |
| selected_node_tags = gr.Textbox( | |
| label="νκ·Έ (μ½€λ§λ‘ ꡬλΆ)", interactive=True | |
| ) | |
| selected_node_created_at = gr.Textbox( | |
| label="μμ±μΌμ", interactive=False | |
| ) | |
| # νΈμ§/μμ κ΄λ ¨ UI | |
| selected_node_index = gr.State(-1) # μ νλ λ Έλ μΈλ±μ€ | |
| with gr.Row(): | |
| edit_node_btn = gr.Button( | |
| "βοΈ μ νλ λ Έλ νΈμ§", variant="primary", visible=False | |
| ) | |
| delete_node_btn = gr.Button( | |
| "ποΈ μ νλ λ Έλ μμ ", variant="stop", visible=False | |
| ) | |
| node_action_status = gr.Textbox( | |
| label="", interactive=False, visible=False, show_label=False | |
| ) | |
| # μ΄λ²€νΈ μ°κ²° - λͺ¨λ νν° λ³κ²½ μ μ€μκ° νν°λ§ | |
| for filter_component in [search_input, tenant_filter, tag_filter]: | |
| filter_component.change( | |
| filter_nodes_multi, | |
| inputs=[search_input, tenant_filter, tag_filter], | |
| outputs=[nodes_dataframe], | |
| ) | |
| # λ Έλ μ ν μ΄λ²€νΈ | |
| nodes_dataframe.select( | |
| fn=handle_node_selection, | |
| outputs=[ | |
| selected_node_title, | |
| selected_node_description, | |
| selected_node_tenant, | |
| selected_node_tags, | |
| selected_node_created_at, | |
| selected_node_index, | |
| edit_node_btn, | |
| delete_node_btn, | |
| node_action_status, | |
| ], | |
| ) | |
| # λ Έλ νΈμ§ μ΄λ²€νΈ | |
| edit_node_btn.click( | |
| fn=handle_edit_node, | |
| inputs=[ | |
| selected_node_index, | |
| selected_node_title, | |
| selected_node_description, | |
| selected_node_tenant, | |
| selected_node_tags, | |
| ], | |
| outputs=[ | |
| node_action_status, | |
| nodes_dataframe, | |
| ], | |
| ) | |
| # λ Έλ μμ μ΄λ²€νΈ | |
| delete_node_btn.click( | |
| fn=handle_delete_node, | |
| inputs=[selected_node_index], | |
| outputs=[ | |
| node_action_status, | |
| nodes_dataframe, | |
| edit_node_btn, | |
| delete_node_btn, | |
| selected_node_title, | |
| selected_node_description, | |
| selected_node_tenant, | |
| selected_node_tags, | |
| selected_node_created_at, | |
| ], | |
| ) | |
| # 4. AI μμ΄λμ΄ μμ± ν | |
| with gr.Tab("π AI μμ΄λμ΄ μμ±") as idea_generation_tab: | |
| gr.Markdown("### AI μμ΄λμ΄λ₯Ό μμ±νμΈμ") | |
| # 곡λͺ¨μ μ 보 μΉμ | |
| contest_title = gr.Textbox( | |
| label="곡λͺ¨μ μ λͺ©", placeholder="μ°Έκ°ν 곡λͺ¨μ μ λͺ©μ μ λ ₯νμΈμ" | |
| ) | |
| contest_theme = gr.Textbox( | |
| label="곡λͺ¨μ μ£Όμ [Domain]", | |
| placeholder="곡λͺ¨μ μ μ£Όμ μ£Όμ νΉμ 곡λͺ¨μ μ λλ©μΈμ μ λ ₯νμΈμ", | |
| ) | |
| contest_description = gr.Textbox( | |
| label="곡λͺ¨μ μ€λͺ [Context]", | |
| lines=3, | |
| placeholder="곡λͺ¨μ μ λν μμΈ μ€λͺ κ³Ό μΆκ°μ μΈ λ§₯λ½ μ 보λ₯Ό μ λ ₯νμΈμ", | |
| ) | |
| contest_context = gr.Textbox( | |
| label="곡λͺ¨μ λ§₯λ½ [Igniter] (μ νμ¬ν)", | |
| lines=2, | |
| placeholder="μμ΄λμμ΄μ μ λ°©ν₯μ±μ κ²°μ νλ ν΅μ¬ ν¬μΈνΈλ₯Ό μ λ ₯νμΈμ (μ νμ¬ν)", | |
| ) | |
| # λ Έλ μ°κ²° μΉμ | |
| gr.Markdown("#### π λ Έλ μ°κ²°") | |
| gr.Markdown("*μμ΄λμ΄ μμ±μ μ¬μ©ν λ Έλλ€μ νν°λ§νμ¬ μ ννμΈμ*") | |
| # λ Έλ νν°λ§ μ΅μ λ€ | |
| with gr.Row(): | |
| idea_node_search_input = gr.Textbox( | |
| label="π λ Έλ μ΄λ¦ κ²μ", | |
| placeholder="κ²μν λ Έλ μ΄λ¦μ μ λ ₯νμΈμ...", | |
| scale=2, | |
| ) | |
| with gr.Row(): | |
| idea_tenant_filter = gr.Dropdown( | |
| label="π’ ν λνΈ νν° (λ€μ€μ ν)", | |
| choices=[], # μ΄κΈ°μλ λΉ λ¦¬μ€νΈ | |
| multiselect=True, | |
| scale=1, | |
| ) | |
| idea_tag_filter = gr.Dropdown( | |
| label="π·οΈ νκ·Έ νν° (λ€μ€μ ν)", | |
| choices=[], # μ΄κΈ°μλ λΉ λ¦¬μ€νΈ | |
| multiselect=True, | |
| scale=1, | |
| ) | |
| idea_nodes_dataframe = gr.Dataframe( | |
| value=get_nodes_dataframe(), | |
| headers=["μμ±μΌμ", "λ Έλ μ΄λ¦", "ν λνΈ", "μ€λͺ ", "νκ·Έ"], | |
| interactive=False, | |
| wrap=False, | |
| elem_id="idea_nodes_table", | |
| ) | |
| # μμ΄λμ΄ μμ± μΉμ | |
| gr.Markdown("#### π€ μμ΄λμ΄ μμ±νκΈ°") | |
| with gr.Row(): | |
| chatgpt_btn = gr.Button( | |
| "π€ ChatGPTλ‘ μμ΄λμ΄ μμ±", variant="primary", size="lg" | |
| ) | |
| gemini_btn = gr.Button( | |
| "π Geminiλ‘ μμ± (μ€λΉμ€)", | |
| variant="secondary", | |
| size="lg", | |
| interactive=False, | |
| ) | |
| idea_generation_status = gr.Textbox(label="μμ± μν", interactive=False) | |
| # μ΄λ²€νΈ μ°κ²° | |
| # λ Έλ νν°λ§ μ΄λ²€νΈλ€ | |
| for filter_component in [ | |
| idea_node_search_input, | |
| idea_tenant_filter, | |
| idea_tag_filter, | |
| ]: | |
| filter_component.change( | |
| filter_nodes_multi, | |
| inputs=[ | |
| idea_node_search_input, | |
| idea_tenant_filter, | |
| idea_tag_filter, | |
| ], | |
| outputs=[idea_nodes_dataframe], | |
| ) | |
| chatgpt_btn.click( | |
| generate_idea_with_chatgpt, | |
| inputs=[ | |
| contest_title, | |
| contest_theme, | |
| contest_description, | |
| contest_context, | |
| idea_node_search_input, | |
| idea_tenant_filter, | |
| idea_tag_filter, | |
| ], | |
| outputs=[ | |
| idea_generation_status, | |
| contest_title, | |
| contest_theme, | |
| contest_description, | |
| contest_context, | |
| ], | |
| ) | |
| gemini_btn.click( | |
| generate_idea_with_gemini, | |
| inputs=[ | |
| contest_title, | |
| contest_theme, | |
| contest_description, | |
| contest_context, | |
| idea_node_search_input, | |
| idea_tenant_filter, | |
| idea_tag_filter, | |
| ], | |
| outputs=[ | |
| idea_generation_status, | |
| contest_title, | |
| contest_theme, | |
| contest_description, | |
| contest_context, | |
| ], | |
| ) | |
| # ν ν΄λ¦μ μλ μ΄κΈ°ν κΈ°λ₯ μ κ±° (μ¬μ©μ μμ²) | |
| # 5. μμ±λ μμ΄λμ΄ νμΈνκΈ° ν | |
| with gr.Tab("π μμ±λ μμ΄λμ΄ νμΈνκΈ°") as ideas_view_tab: | |
| gr.Markdown( | |
| "### AIλ‘ μμ±λ μμ΄λμ΄λ₯Ό νμΈνκ³ μμΈ λ΄μ©μ λ³Ό μ μμ΅λλ€" | |
| ) | |
| # κ²μ νλ | |
| idea_search_input = gr.Textbox( | |
| label="π 곡λͺ¨μ μ λͺ© λλ μμ΄λμ΄ μ λͺ© κ²μ", | |
| placeholder="κ²μν μ λͺ©μ μ λ ₯νμΈμ...", | |
| scale=2, | |
| ) | |
| # μμ΄λμ΄ λͺ©λ‘ | |
| ideas_dataframe = gr.Dataframe( | |
| value=get_ideas_dataframe(), | |
| headers=[ | |
| "μμ±μΌμ", | |
| "곡λͺ¨μ μ λͺ©", | |
| "μμ΄λμ΄ μ λͺ©", | |
| "μμ΄λμ΄ κ°μ", | |
| "AI μ΄λ¦", | |
| ], | |
| interactive=False, | |
| elem_id="ideas_table", | |
| ) | |
| # μ νλ μμ΄λμ΄ μμΈ μ 보 | |
| gr.Markdown("#### π μ νλ μμ΄λμ΄ μμΈ μ 보") | |
| gr.Markdown( | |
| "*μ ν μ΄λΈμμ νμ ν΄λ¦νλ©΄ ν΄λΉ μμ΄λμ΄μ μμΈ μ λ³΄κ° νμλ©λλ€.*" | |
| ) | |
| with gr.Accordion("π― μμ΄λμ΄ μμΈ μ 보", open=True): | |
| selected_title = gr.Textbox(label="μμ΄λμ΄ μ λͺ©", interactive=False) | |
| contest_info_display = gr.Textbox( | |
| label="곡λͺ¨μ μ 보", lines=4, interactive=False | |
| ) | |
| problem_display = gr.Textbox( | |
| label="λ¬Έμ μμ", lines=3, interactive=False | |
| ) | |
| solution_display = gr.Textbox( | |
| label="μ루μ ν΄κ²° λ°©μ", lines=4, interactive=False | |
| ) | |
| implementation_display = gr.Textbox( | |
| label="ꡬν λ°©μ", lines=3, interactive=False | |
| ) | |
| expected_effect_display = gr.Textbox( | |
| label="κΈ°λ ν¨κ³Ό", lines=3, interactive=False | |
| ) | |
| created_at_display = gr.Textbox(label="μμ±μΌμ", interactive=False) | |
| with gr.Accordion("π μ¬μ©λ λ Έλ λ° νν° μ 보", open=False): | |
| used_nodes_display = gr.Textbox( | |
| label="μ¬μ©λ λ Έλ", lines=5, interactive=False | |
| ) | |
| used_filters_display = gr.Textbox( | |
| label="μ¬μ©λ νν°", lines=5, interactive=False | |
| ) | |
| rationale_display = gr.Textbox( | |
| label="μμ΄λμ΄ μμ± κ·Όκ±° (Connecting the Dots)", | |
| lines=8, | |
| interactive=False, | |
| ) | |
| # μμ κ΄λ ¨ UI | |
| selected_idea_index = gr.State(-1) # μ νλ μμ΄λμ΄ μΈλ±μ€ | |
| with gr.Row(): | |
| delete_idea_btn = gr.Button( | |
| "ποΈ μ νλ μμ΄λμ΄ μμ ", variant="stop", visible=False | |
| ) | |
| delete_status = gr.Textbox( | |
| label="", interactive=False, visible=False, show_label=False | |
| ) | |
| # μ΄λ²€νΈ μ°κ²° | |
| # κ²μ νλ μ΄λ²€νΈ | |
| idea_search_input.change( | |
| fn=filter_ideas, | |
| inputs=[idea_search_input], | |
| outputs=[ideas_dataframe], | |
| ) | |
| ideas_dataframe.select( | |
| fn=handle_idea_selection, | |
| outputs=[ | |
| selected_title, | |
| contest_info_display, | |
| problem_display, | |
| solution_display, | |
| implementation_display, | |
| expected_effect_display, | |
| created_at_display, | |
| used_nodes_display, | |
| used_filters_display, | |
| rationale_display, | |
| selected_idea_index, | |
| delete_idea_btn, | |
| delete_status, | |
| ], | |
| ) | |
| delete_idea_btn.click( | |
| fn=handle_delete_idea, | |
| inputs=[selected_idea_index], | |
| outputs=[ | |
| delete_status, | |
| ideas_dataframe, | |
| delete_idea_btn, | |
| selected_title, | |
| contest_info_display, | |
| problem_display, | |
| solution_display, | |
| implementation_display, | |
| expected_effect_display, | |
| created_at_display, | |
| used_nodes_display, | |
| used_filters_display, | |
| rationale_display, | |
| ], | |
| ) | |
| # ν ν΄λ¦μ μλ μλ‘κ³ μΉ¨ λ° μμ΄λμ΄ μμ± μν μ΄κΈ°ν | |
| ideas_view_tab.select( | |
| fn=refresh_and_reset, | |
| outputs=[ | |
| ideas_dataframe, | |
| delete_idea_btn, | |
| delete_status, | |
| selected_title, | |
| contest_info_display, | |
| problem_display, | |
| solution_display, | |
| implementation_display, | |
| expected_effect_display, | |
| created_at_display, | |
| used_nodes_display, | |
| used_filters_display, | |
| rationale_display, | |
| idea_generation_status, # μμ΄λμ΄ μμ± μν μ΄κΈ°ν | |
| idea_search_input, # κ²μ νλ μ΄κΈ°ν | |
| ], | |
| ) | |
| # ν κ° μν μ΄κΈ°ν μ΄λ²€νΈ (λͺ¨λ μ»΄ν¬λνΈ μ μ ν) | |
| # AI μμ΄λμ΄ μμ± ν ν΄λ¦μ μν μ΄κΈ°ν λ° λ Έλ νν° μ΄κΈ°ν | |
| idea_generation_tab.select( | |
| fn=refresh_idea_nodes, | |
| outputs=[ | |
| idea_nodes_dataframe, | |
| idea_node_search_input, | |
| idea_tenant_filter, | |
| idea_tag_filter, | |
| create_status, | |
| ], | |
| ) | |
| # λ Έλ μ λ ₯νκΈ° ν ν΄λ¦μ μμ΄λμ΄ μμ± μν, λ Έλ μμ± μνλ§ μ΄κΈ°ν | |
| node_input_tab.select( | |
| fn=lambda: ("", ""), | |
| outputs=[idea_generation_status, create_status], | |
| ) | |
| # λ΄ λ Έλ νμΈνκΈ° ν ν΄λ¦μ μλ μλ‘κ³ μΉ¨ λ° μν μ΄κΈ°ν | |
| node_view_tab.select( | |
| fn=refresh_and_clear_status, | |
| outputs=[ | |
| nodes_dataframe, | |
| search_input, | |
| tenant_filter, | |
| tag_filter, | |
| idea_generation_status, | |
| create_status, | |
| selected_node_title, | |
| selected_node_description, | |
| selected_node_tenant, | |
| selected_node_tags, | |
| selected_node_created_at, | |
| selected_node_index, | |
| edit_node_btn, | |
| delete_node_btn, | |
| node_action_status, | |
| ], | |
| ) | |
| # AI μμ΄λμ΄ μμ± ν ν΄λ¦μ μν μ΄κΈ°ν λ° λ Έλ νν° μ΄κΈ°ν | |
| idea_generation_tab.select( | |
| fn=refresh_idea_nodes, | |
| outputs=[ | |
| idea_nodes_dataframe, | |
| idea_node_search_input, | |
| idea_tenant_filter, | |
| idea_tag_filter, | |
| create_status, | |
| ], | |
| ) | |
| # λ Έλ μ λ ₯νκΈ° ν ν΄λ¦μ μμ΄λμ΄ μμ± μν, λ Έλ μμ± μνλ§ μ΄κΈ°ν | |
| node_input_tab.select( | |
| fn=lambda: ("", ""), | |
| outputs=[idea_generation_status, create_status], | |
| ) | |
| # λ΄ λ Έλ νμΈνκΈ° ν ν΄λ¦μ μλ μλ‘κ³ μΉ¨ λ° μν μ΄κΈ°ν | |
| node_view_tab.select( | |
| fn=refresh_and_clear_status, | |
| outputs=[ | |
| nodes_dataframe, | |
| search_input, | |
| tenant_filter, | |
| tag_filter, | |
| idea_generation_status, | |
| create_status, | |
| selected_node_title, | |
| selected_node_description, | |
| selected_node_tenant, | |
| selected_node_tags, | |
| selected_node_created_at, | |
| selected_node_index, | |
| edit_node_btn, | |
| delete_node_btn, | |
| node_action_status, | |
| ], | |
| ) | |
| # μ± μ€ν | |
| if __name__ == "__main__": | |
| demo.launch(share=False, debug=True, server_name="0.0.0.0", server_port=7860) | |