openfree commited on
Commit
83e5933
ยท
verified ยท
1 Parent(s): d940931

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +454 -388
app.py CHANGED
@@ -571,8 +571,8 @@ def create_main_interface():
571
  """๋ฉ”์ธ ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ ํ•จ์ˆ˜"""
572
 
573
  #NEW - ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋ฅผ ํ†ตํ•ฉํ•œ ์‘๋‹ต ์ƒ์„ฑ ํ•จ์ˆ˜
574
- async def execute_search_and_generate(query, setting):
575
- try:
576
  print(f"Executing search for query: {query}")
577
 
578
  # ๊ฒ€์ƒ‰ ์‹คํ–‰
@@ -642,7 +642,7 @@ The response should be in HTML format with appropriate styling."""
642
  print("Response generation completed") # ๋””๋ฒ„๊น…์šฉ
643
  return final_result
644
 
645
- except Exception as e:
646
  print(f"Search error: {str(e)}")
647
  print(f"Full error details: {str(e.__class__.__name__)}: {str(e)}")
648
  return [
@@ -652,24 +652,23 @@ The response should be in HTML format with appropriate styling."""
652
  gr.update(open=False)
653
  ]
654
 
655
- def execute_code(query: str):
656
- if not query or query.strip() == '':
657
  return None, gr.update(active_key="empty")
658
 
659
- try:
660
  if '```html' in query and '```' in query:
661
  code = remove_code_block(query)
662
  else:
663
  code = query.strip()
664
 
665
  return send_to_sandbox(code), gr.update(active_key="render")
666
- except Exception as e:
667
  print(f"Error executing code: {str(e)}")
668
  return None, gr.update(active_key="empty")
669
 
670
-
671
- async def handle_generation(query, setting, is_search):
672
- try:
673
  print(f"Mode: {'Web Search' if is_search else 'Generate'}") # ๋””๋ฒ„๊น…์šฉ
674
  if is_search:
675
  print("Executing search and generate...") # ๋””๋ฒ„๊น…์šฉ
@@ -679,12 +678,12 @@ The response should be in HTML format with appropriate styling."""
679
  async for result in demo_instance.generation_code(query, setting):
680
  final_result = result
681
  return final_result
682
- except Exception as e:
683
  print(f"Generation error: {str(e)}")
684
  return ["", None, gr.update(active_key="error"), gr.update(open=False)]
685
 
686
  # CSS ํŒŒ์ผ ๋‚ด์šฉ์„ ์ง์ ‘ ์ ์šฉ
687
- with open('app.css', 'r', encoding='utf-8') as f:
688
  custom_css = f.read()
689
 
690
  #NEW - ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์Šคํƒ€์ผ ์ถ”๊ฐ€
@@ -757,386 +756,453 @@ The response should be in HTML format with appropriate styling."""
757
  }
758
  """
759
 
760
- demo = gr.Blocks(css=custom_css, theme=theme)
 
 
761
 
762
  with demo:
763
- with gr.Tabs(elem_classes="main-tabs") as tabs:
764
- with gr.Tab("Visual AI Assistant", elem_id="mouse-tab", elem_classes="mouse-tab"):
765
- setting = gr.State({
766
- "system": SystemPrompt,
767
- })
768
-
769
- #NEW - ๊ฒ€์ƒ‰ ๋ชจ๋“œ ์ƒํƒœ ์ถ”๊ฐ€
770
- search_mode = gr.State(False)
771
-
772
- with ms.Application() as app:
773
- with antd.ConfigProvider():
774
- #NEW - ๋ชจ๋“œ ์„ ํƒ ๋ผ๋””์˜ค ๋ฒ„ํŠผ ์ถ”๊ฐ€
775
- with gr.Row():
776
- mode = gr.Radio(
777
- choices=["Generate", "Generate + Web Search"],
778
- label="Mode",
779
- value="Generate",
780
- info="Select 'Generate + Web Search' to include web search results",
781
-
782
- elem_classes="mode-selector"
783
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
784
 
785
-
786
-
787
- with antd.Drawer(open=False, title="AI is Creating...", placement="left", width="750px") as code_drawer:
788
- gr.HTML("""
789
- <div class="thinking-container">
790
- <style>
791
- .custom-textarea {
792
- background: #f8f9fa !important;
793
- border: 1px solid #e0e0e0 !important;
794
- border-radius: 10px !important;
795
- padding: 15px !important;
796
- min-height: 150px !important;
797
- font-family: -apple-system, BlinkMacSystemFont, sans-serif !important;
798
- }
799
-
800
- .custom-textarea:focus {
801
- border-color: #007aff !important;
802
- box-shadow: 0 0 0 2px rgba(0,122,255,0.2) !important;
803
- }
804
-
805
- .thinking-container {
806
- text-align: center;
807
- padding: 20px;
808
- background: #f8f9fa;
809
- border-radius: 15px;
810
- font-family: -apple-system, BlinkMacSystemFont, sans-serif;
811
- }
812
-
813
- .progress-bar {
814
- width: 100%;
815
- height: 4px;
816
- background: #e9ecef;
817
- border-radius: 4px;
818
- margin: 20px 0;
819
- overflow: hidden;
820
- }
821
-
822
- .progress-bar-inner {
823
- width: 30%;
824
- height: 100%;
825
- background: linear-gradient(90deg, #007aff, #28c840);
826
- animation: progress 2s ease-in-out infinite;
827
- }
828
-
829
- .thinking-icon {
830
- font-size: 48px;
831
- margin: 20px 0;
832
- animation: bounce 1s ease infinite;
833
- }
834
-
835
- .tip-box {
836
- background: white;
837
- padding: 20px;
838
- border-radius: 10px;
839
- box-shadow: 0 4px 12px rgba(0,0,0,0.1);
840
- margin: 20px 0;
841
- transition: all 0.3s ease;
842
- }
843
-
844
- .status-text {
845
- color: #007aff;
846
- font-size: 18px;
847
- margin: 15px 0;
848
- animation: fade 1.5s ease infinite;
849
- }
850
-
851
- .icon-grid {
852
- display: grid;
853
- grid-template-columns: repeat(4, 1fr);
854
- gap: 15px;
855
- margin: 20px 0;
856
- }
857
-
858
- .icon-item {
859
- padding: 10px;
860
- background: rgba(0,122,255,0.1);
861
- border-radius: 8px;
862
- animation: pulse 2s ease infinite;
863
- }
864
-
865
- @keyframes progress {
866
- 0% { transform: translateX(-100%); }
867
- 100% { transform: translateX(400%); }
868
- }
869
-
870
- @keyframes bounce {
871
- 0%, 100% { transform: translateY(0); }
872
- 50% { transform: translateY(-10px); }
873
- }
874
-
875
- @keyframes fade {
876
- 0%, 100% { opacity: 1; }
877
- 50% { opacity: 0.6; }
878
- }
879
-
880
- @keyframes pulse {
881
- 0% { transform: scale(1); }
882
- 50% { transform: scale(1.05); }
883
- 100% { transform: scale(1); }
884
- }
885
- </style>
886
-
887
- <div class="thinking-icon">๐ŸŽจ</div>
888
- <div class="status-text">Creating Your Visualization...</div>
889
- <div class="progress-bar">
890
- <div class="progress-bar-inner"></div>
891
- </div>
892
- <div class="icon-grid">
893
- <div class="icon-item">๐Ÿ“Š</div>
894
- <div class="icon-item">๐ŸŽฏ</div>
895
- <div class="icon-item">๐Ÿ’ก</div>
896
- <div class="icon-item">โœจ</div>
897
- </div>
898
- <div class="tip-box">
899
- <h3 style="color: #007aff; margin-bottom: 10px;">Did You Know?</h3>
900
- <div id="tip-content" style="font-size: 16px; line-height: 1.6;"></div>
901
- </div>
902
-
903
- <script>
904
- const tips = [
905
- "MOUSE-I is creating responsive and interactive visualizations! ๐Ÿ“Š",
906
- "We're applying modern design principles for the best user experience! ๐ŸŽจ",
907
- "Your content will be optimized for all devices! ๐Ÿ“ฑ",
908
- "Adding engaging animations to bring your data to life! โœจ",
909
- "Crafting a beautiful presentation just for you! ๐ŸŽฏ",
910
- "Implementing interactive elements for better engagement! ๐ŸŽฎ",
911
- "Optimizing colors and layout for visual appeal! ๐ŸŽช",
912
- "Creating smooth transitions and animations! ๐ŸŒŸ"
913
- ];
914
-
915
- function updateTip() {
916
- const tipElement = document.getElementById('tip-content');
917
- if (tipElement) {
918
- const randomTip = tips[Math.floor(Math.random() * tips.length)];
919
- tipElement.innerHTML = randomTip;
920
- tipElement.style.opacity = 0;
921
- setTimeout(() => {
922
- tipElement.style.transition = 'opacity 0.5s ease';
923
- tipElement.style.opacity = 1;
924
- }, 100);
925
- }
926
- }
927
-
928
- updateTip();
929
- setInterval(updateTip, 3000);
930
- </script>
931
- </div>
932
- """)
933
- code_output = legacy.Markdown(visible=False)
934
-
935
-
936
-
937
- # ๋ฉ”์ธ ์ปจํ…์ธ ๋ฅผ ์œ„ํ•œ Row
938
- with antd.Row(gutter=[32, 12]) as layout:
939
- # ์ขŒ์ธก ํŒจ๋„
940
- with antd.Col(span=24, md=8):
941
- with antd.Flex(vertical=True, gap="middle", wrap=True):
942
- header = gr.HTML("""
943
- <div class="window-frame">
944
- <div class="window-header">
945
- <div class="window-controls">
946
- <div class="control close"></div>
947
- <div class="control minimize"></div>
948
- <div class="control maximize"></div>
949
- </div>
950
- <div class="window-title">
951
- <div class="window-address">
952
- <div class="secure-icon">๐Ÿ”’</div>
953
- <div class="url-bar">https://VIDraft-mouse-chat.hf.space</div>
954
- </div>
955
- </div>
956
- </div>
957
- <div class="app-content">
958
- <img src="data:image/gif;base64,{}" width="360px" />
959
- <h1 class="app-title">MOUSE-Chat Visual AI</h1>
960
- <p class="app-description">Creates visualized web pages from text input, and when you include keywords like "image:", "๊ทธ๋ฆผ:", or "image:" in your input, it automatically generates AI images based on the description and incorporates them into the web page.
961
- Use the "Generate" button for basic creation, "Enhance" button for prompt improvement, "Share" button to deploy results to the web, and input like "image: a dog playing in the park" to create results containing both text and generated images.</p>
962
- </div>
963
- </div>
964
- """.format(get_image_base64('mouse.gif')))
965
-
966
- # ์ž…๋ ฅ ์˜์—ญ
967
- input = antd.InputTextarea(
968
- size="large",
969
- allow_clear=True,
970
- placeholder=get_random_placeholder(),
971
- elem_classes="custom-textarea" # style ๋Œ€์‹  class ์‚ฌ์šฉ
972
-
973
- )
974
-
975
-
976
- # ๋ฒ„ํŠผ ๊ทธ๋ฃน
977
- with antd.Flex(gap="small", justify="flex-start"):
978
- btn = antd.Button(
979
- "Generate",
980
- type="primary",
981
- size="large",
982
- elem_classes="generate-btn"
983
- )
984
- boost_btn = antd.Button(
985
- "Enhance",
986
- type="default",
987
- size="large",
988
- elem_classes="enhance-btn"
989
- )
990
- deploy_btn = antd.Button(
991
- "Share",
992
- type="default",
993
- size="large",
994
- elem_classes="share-btn"
995
- )
996
-
997
- deploy_result = gr.HTML(
998
- label="Share Result",
999
- elem_classes="deploy-result"
1000
- )
1001
-
1002
- # ์šฐ์ธก ํŒจ๋„
1003
- with antd.Col(span=24, md=16):
1004
- with ms.Div(elem_classes="right_panel"):
1005
- # macOS ์Šคํƒ€์ผ ์œˆ๋„์šฐ ํ—ค๋”
1006
- gr.HTML("""
1007
- <div class="window-frame">
1008
- <div class="window-header">
1009
- <div class="window-controls">
1010
- <div class="control close"></div>
1011
- <div class="control minimize"></div>
1012
- <div class="control maximize"></div>
1013
- </div>
1014
- <div class="window-title">Preview</div>
1015
- </div>
1016
- </div>
1017
- """)
1018
-
1019
- # ํƒญ ์ปจํ…์ธ 
1020
- with antd.Tabs(active_key="empty", render_tab_bar="() => null") as state_tab:
1021
- with antd.Tabs.Item(key="empty"):
1022
- empty = antd.Empty(
1023
- description="Enter your question to begin",
1024
- elem_classes="right_content empty-content"
1025
- )
1026
-
1027
- with antd.Tabs.Item(key="loading"):
1028
- loading = antd.Spin(
1029
- True,
1030
- tip="Creating visual presentation...",
1031
- size="large",
1032
- elem_classes="right_content"
1033
- )
1034
-
1035
- with antd.Tabs.Item(key="render"):
1036
- sandbox = gr.HTML(elem_classes="html_content")
1037
-
1038
-
1039
- with antd.Tabs.Item(key="error"):
1040
- error = antd.Empty(
1041
- description="An error occurred. Please try again.",
1042
- elem_classes="right_content error-content"
1043
- )
1044
-
1045
-
1046
- # ์—ฌ๊ธฐ์— ์ถ”๊ฐ€ (๋“ค์—ฌ์“ฐ๊ธฐ ๋งž์ถค)
1047
- mode.change(
1048
- fn=lambda x: x == "Generate + Web Search",
1049
- inputs=[mode],
1050
- outputs=[search_mode]
1051
- )
1052
-
1053
-
1054
- btn.click(
1055
- fn=handle_generation,
1056
- inputs=[input, setting, search_mode],
1057
- outputs=[code_output, sandbox, state_tab, code_drawer]
1058
- ).then(
1059
- fn=update_placeholder,
1060
- inputs=[],
1061
- outputs=[input]
1062
- )
1063
-
1064
-
1065
-
1066
- boost_btn.click(
1067
- fn=handle_boost,
1068
- inputs=[input],
1069
- outputs=[input, state_tab]
1070
- )
1071
-
1072
- deploy_btn.click(
1073
- fn=lambda code: deploy_to_vercel(remove_code_block(code)) if code else "No code to share.",
1074
- inputs=[code_output],
1075
- outputs=[deploy_result]
1076
- )
1077
-
1078
- gr.HTML("""
1079
- <style>
1080
- .generate-btn {
1081
- background: #007aff !important;
1082
- border-radius: 8px !important;
1083
- box-shadow: 0 2px 4px rgba(0,0,0,0.1) !important;
1084
- }
1085
-
1086
- .enhance-btn {
1087
- border-radius: 8px !important;
1088
- border: 1px solid #007aff !important;
1089
- color: #007aff !important;
1090
- }
1091
-
1092
- .share-btn {
1093
- border-radius: 8px !important;
1094
- border: 1px solid #28c840 !important;
1095
- color: #28c840 !important;
1096
- }
1097
-
1098
- .search-toggle-btn {
1099
- border-radius: 8px !important;
1100
- border: 1px solid #4285f4 !important;
1101
- color: #4285f4 !important;
1102
- }
1103
-
1104
- /* hover ํšจ๊ณผ */
1105
- .generate-btn:hover {
1106
- background: #0056b3 !important;
1107
- }
1108
-
1109
- .enhance-btn:hover {
1110
- background: rgba(0,122,255,0.1) !important;
1111
- }
1112
-
1113
- .share-btn:hover {
1114
- background: rgba(40,200,64,0.1) !important;
1115
- }
1116
-
1117
- .search-toggle-btn:hover {
1118
- background: rgba(66,133,244,0.1) !important;
1119
- }
1120
- </style>
1121
- """)
1122
 
1123
- return demo
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1124
 
1125
  # ๋ฉ”์ธ ์‹คํ–‰ ๋ถ€๋ถ„
1126
  if __name__ == "__main__":
1127
- try:
1128
- demo_instance = Demo()
1129
- demo = create_main_interface()
1130
- demo.queue(
1131
- default_concurrency_limit=20,
1132
- status_update_rate=10,
1133
- api_open=False
1134
- ).launch(
1135
- server_name="0.0.0.0",
1136
- server_port=7860,
1137
- share=False,
1138
- debug=False
1139
- )
1140
- except Exception as e:
1141
- print(f"Initialization error: {e}")
1142
- raise
 
571
  """๋ฉ”์ธ ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ ํ•จ์ˆ˜"""
572
 
573
  #NEW - ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋ฅผ ํ†ตํ•ฉํ•œ ์‘๋‹ต ์ƒ์„ฑ ํ•จ์ˆ˜
574
+ async def execute_search_and_generate(query, setting):
575
+ try:
576
  print(f"Executing search for query: {query}")
577
 
578
  # ๊ฒ€์ƒ‰ ์‹คํ–‰
 
642
  print("Response generation completed") # ๋””๋ฒ„๊น…์šฉ
643
  return final_result
644
 
645
+ except Exception as e:
646
  print(f"Search error: {str(e)}")
647
  print(f"Full error details: {str(e.__class__.__name__)}: {str(e)}")
648
  return [
 
652
  gr.update(open=False)
653
  ]
654
 
655
+ def execute_code(query: str):
656
+ if not query or query.strip() == '':
657
  return None, gr.update(active_key="empty")
658
 
659
+ try:
660
  if '```html' in query and '```' in query:
661
  code = remove_code_block(query)
662
  else:
663
  code = query.strip()
664
 
665
  return send_to_sandbox(code), gr.update(active_key="render")
666
+ except Exception as e:
667
  print(f"Error executing code: {str(e)}")
668
  return None, gr.update(active_key="empty")
669
 
670
+ async def handle_generation(query, setting, is_search):
671
+ try:
 
672
  print(f"Mode: {'Web Search' if is_search else 'Generate'}") # ๋””๋ฒ„๊น…์šฉ
673
  if is_search:
674
  print("Executing search and generate...") # ๋””๋ฒ„๊น…์šฉ
 
678
  async for result in demo_instance.generation_code(query, setting):
679
  final_result = result
680
  return final_result
681
+ except Exception as e:
682
  print(f"Generation error: {str(e)}")
683
  return ["", None, gr.update(active_key="error"), gr.update(open=False)]
684
 
685
  # CSS ํŒŒ์ผ ๋‚ด์šฉ์„ ์ง์ ‘ ์ ์šฉ
686
+ with open('app.css', 'r', encoding='utf-8') as f:
687
  custom_css = f.read()
688
 
689
  #NEW - ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์Šคํƒ€์ผ ์ถ”๊ฐ€
 
756
  }
757
  """
758
 
759
+ demo = gr.Blocks(css=custom_css, theme=theme)
760
+
761
+
762
 
763
  with demo:
764
+ with gr.Tabs(elem_classes="main-tabs") as tabs:
765
+ with gr.Tab("Visual AI Assistant", elem_id="mouse-tab", elem_classes="mouse-tab"):
766
+ setting = gr.State({
767
+ "system": SystemPrompt,
768
+ })
769
+
770
+ #NEW - ๊ฒ€์ƒ‰ ๋ชจ๋“œ ์ƒํƒœ ์ถ”๊ฐ€
771
+ search_mode = gr.State(False)
772
+
773
+ with ms.Application() as app:
774
+ with antd.ConfigProvider():
775
+ #NEW - ๋ชจ๋“œ ์„ ํƒ ๋ผ๋””์˜ค ๋ฒ„ํŠผ ์ถ”๊ฐ€
776
+ with gr.Row():
777
+ mode = gr.Radio(
778
+ choices=["Generate", "Generate + Web Search"],
779
+ label="Mode",
780
+ value="Generate",
781
+ info="Select 'Generate + Web Search' to include web search results",
782
+ elem_classes="mode-selector"
783
+ )
784
+
785
+ with antd.Drawer(open=False, title="AI is Creating...", placement="left", width="750px") as code_drawer:
786
+ gr.HTML("""
787
+ <div class="thinking-container">
788
+ <style>
789
+ .custom-textarea {
790
+ background: #f8f9fa !important;
791
+ border: 1px solid #e0e0e0 !important;
792
+ border-radius: 10px !important;
793
+ padding: 15px !important;
794
+ min-height: 150px !important;
795
+ font-family: -apple-system, BlinkMacSystemFont, sans-serif !important;
796
+ }
797
+
798
+ .custom-textarea:focus {
799
+ border-color: #007aff !important;
800
+ box-shadow: 0 0 0 2px rgba(0,122,255,0.2) !important;
801
+ }
802
+
803
+ .thinking-container {
804
+ text-align: center;
805
+ padding: 20px;
806
+ background: #f8f9fa;
807
+ border-radius: 15px;
808
+ font-family: -apple-system, BlinkMacSystemFont, sans-serif;
809
+ }
810
+
811
+ .progress-bar {
812
+ width: 100%;
813
+ height: 4px;
814
+ background: #e9ecef;
815
+ border-radius: 4px;
816
+ margin: 20px 0;
817
+ overflow: hidden;
818
+ }
819
+
820
+ .progress-bar-inner {
821
+ width: 30%;
822
+ height: 100%;
823
+ background: linear-gradient(90deg, #007aff, #28c840);
824
+ animation: progress 2s ease-in-out infinite;
825
+ }
826
+
827
+ .thinking-icon {
828
+ font-size: 48px;
829
+ margin: 20px 0;
830
+ animation: bounce 1s ease infinite;
831
+ }
832
+
833
+ .tip-box {
834
+ background: white;
835
+ padding: 20px;
836
+ border-radius: 10px;
837
+ box-shadow: 0 4px 12px rgba(0,0,0,0.1);
838
+ margin: 20px 0;
839
+ transition: all 0.3s ease;
840
+ }
841
+
842
+ .status-text {
843
+ color: #007aff;
844
+ font-size: 18px;
845
+ margin: 15px 0;
846
+ animation: fade 1.5s ease infinite;
847
+ }
848
+
849
+ .icon-grid {
850
+ display: grid;
851
+ grid-template-columns: repeat(4, 1fr);
852
+ gap: 15px;
853
+ margin: 20px 0;
854
+ }
855
+
856
+ .icon-item {
857
+ padding: 10px;
858
+ background: rgba(0,122,255,0.1);
859
+ border-radius: 8px;
860
+ animation: pulse 2s ease infinite;
861
+ }
862
+
863
+ @keyframes progress {
864
+ 0% { transform: translateX(-100%); }
865
+ 100% { transform: translateX(400%); }
866
+ }
867
+
868
+ @keyframes bounce {
869
+ 0%, 100% { transform: translateY(0); }
870
+ 50% { transform: translateY(-10px); }
871
+ }
872
+
873
+ @keyframes fade {
874
+ 0%, 100% { opacity: 1; }
875
+ 50% { opacity: 0.6; }
876
+ }
877
+
878
+ @keyframes pulse {
879
+ 0% { transform: scale(1); }
880
+ 50% { transform: scale(1.05); }
881
+ 100% { transform: scale(1); }
882
+ }
883
+ </style>
884
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
885
 
886
+
887
+ with demo:
888
+ with gr.Tabs(elem_classes="main-tabs") as tabs:
889
+ with gr.Tab("Visual AI Assistant", elem_id="mouse-tab", elem_classes="mouse-tab"):
890
+ setting = gr.State({
891
+ "system": SystemPrompt,
892
+ })
893
+
894
+ #NEW - ๊ฒ€์ƒ‰ ๋ชจ๋“œ ์ƒํƒœ ์ถ”๊ฐ€
895
+ search_mode = gr.State(False)
896
+
897
+ with ms.Application() as app:
898
+ with antd.ConfigProvider():
899
+ #NEW - ๋ชจ๋“œ ์„ ํƒ ๋ผ๋””์˜ค ๋ฒ„ํŠผ ์ถ”๊ฐ€
900
+ with gr.Row():
901
+ mode = gr.Radio(
902
+ choices=["Generate", "Generate + Web Search"],
903
+ label="Mode",
904
+ value="Generate",
905
+ info="Select 'Generate + Web Search' to include web search results",
906
+ elem_classes="mode-selector"
907
+ )
908
+
909
+ with antd.Drawer(open=False, title="AI is Creating...", placement="left", width="750px") as code_drawer:
910
+ gr.HTML("""
911
+ <div class="thinking-container">
912
+ <style>
913
+ .custom-textarea {
914
+ background: #f8f9fa !important;
915
+ border: 1px solid #e0e0e0 !important;
916
+ border-radius: 10px !important;
917
+ padding: 15px !important;
918
+ min-height: 150px !important;
919
+ font-family: -apple-system, BlinkMacSystemFont, sans-serif !important;
920
+ }
921
+
922
+ .custom-textarea:focus {
923
+ border-color: #007aff !important;
924
+ box-shadow: 0 0 0 2px rgba(0,122,255,0.2) !important;
925
+ }
926
+
927
+ .thinking-container {
928
+ text-align: center;
929
+ padding: 20px;
930
+ background: #f8f9fa;
931
+ border-radius: 15px;
932
+ font-family: -apple-system, BlinkMacSystemFont, sans-serif;
933
+ }
934
+
935
+ .progress-bar {
936
+ width: 100%;
937
+ height: 4px;
938
+ background: #e9ecef;
939
+ border-radius: 4px;
940
+ margin: 20px 0;
941
+ overflow: hidden;
942
+ }
943
+
944
+ .progress-bar-inner {
945
+ width: 30%;
946
+ height: 100%;
947
+ background: linear-gradient(90deg, #007aff, #28c840);
948
+ animation: progress 2s ease-in-out infinite;
949
+ }
950
+
951
+ .thinking-icon {
952
+ font-size: 48px;
953
+ margin: 20px 0;
954
+ animation: bounce 1s ease infinite;
955
+ }
956
+
957
+ .tip-box {
958
+ background: white;
959
+ padding: 20px;
960
+ border-radius: 10px;
961
+ box-shadow: 0 4px 12px rgba(0,0,0,0.1);
962
+ margin: 20px 0;
963
+ transition: all 0.3s ease;
964
+ }
965
+
966
+ .status-text {
967
+ color: #007aff;
968
+ font-size: 18px;
969
+ margin: 15px 0;
970
+ animation: fade 1.5s ease infinite;
971
+ }
972
+
973
+ .icon-grid {
974
+ display: grid;
975
+ grid-template-columns: repeat(4, 1fr);
976
+ gap: 15px;
977
+ margin: 20px 0;
978
+ }
979
+
980
+ .icon-item {
981
+ padding: 10px;
982
+ background: rgba(0,122,255,0.1);
983
+ border-radius: 8px;
984
+ animation: pulse 2s ease infinite;
985
+ }
986
+
987
+ @keyframes progress {
988
+ 0% { transform: translateX(-100%); }
989
+ 100% { transform: translateX(400%); }
990
+ }
991
+
992
+ @keyframes bounce {
993
+ 0%, 100% { transform: translateY(0); }
994
+ 50% { transform: translateY(-10px); }
995
+ }
996
+
997
+ @keyframes fade {
998
+ 0%, 100% { opacity: 1; }
999
+ 50% { opacity: 0.6; }
1000
+ }
1001
+
1002
+ @keyframes pulse {
1003
+ 0% { transform: scale(1); }
1004
+ 50% { transform: scale(1.05); }
1005
+ 100% { transform: scale(1); }
1006
+ }
1007
+ </style>
1008
+
1009
+
1010
+ header = gr.HTML("""
1011
+ <div class="window-frame">
1012
+ <div class="window-header">
1013
+ <div class="window-controls">
1014
+ <div class="control close"></div>
1015
+ <div class="control minimize"></div>
1016
+ <div class="control maximize"></div>
1017
+ </div>
1018
+ <div class="window-title">
1019
+ <div class="window-address">
1020
+ <div class="secure-icon">๐Ÿ”’</div>
1021
+ <div class="url-bar">https://VIDraft-mouse-chat.hf.space</div>
1022
+ </div>
1023
+ </div>
1024
+ </div>
1025
+ <div class="app-content">
1026
+ <img src="data:image/gif;base64,{}" width="360px" />
1027
+ <h1 class="app-title">MOUSE-Chat Visual AI</h1>
1028
+ <p class="app-description">Creates visualized web pages from text input, and when you include keywords like "image:", "๊ทธ๋ฆผ:", or "image:" in your input, it automatically generates AI images based on the description and incorporates them into the web page.
1029
+ Use the "Generate" button for basic creation, "Enhance" button for prompt improvement, "Share" button to deploy results to the web, and input like "image: a dog playing in the park" to create results containing both text and generated images.</p>
1030
+ </div>
1031
+ </div>
1032
+ """.format(get_image_base64('mouse.gif')))
1033
+
1034
+ # ์ž…๋ ฅ ์˜์—ญ
1035
+ input = antd.InputTextarea(
1036
+ size="large",
1037
+ allow_clear=True,
1038
+ placeholder=get_random_placeholder(),
1039
+ elem_classes="custom-textarea"
1040
+ )
1041
+
1042
+ # ๋ฒ„ํŠผ ๊ทธ๋ฃน
1043
+ with antd.Flex(gap="small", justify="flex-start"):
1044
+ btn = antd.Button(
1045
+ "Generate",
1046
+ type="primary",
1047
+ size="large",
1048
+ elem_classes="generate-btn"
1049
+ )
1050
+ boost_btn = antd.Button(
1051
+ "Enhance",
1052
+ type="default",
1053
+ size="large",
1054
+ elem_classes="enhance-btn"
1055
+ )
1056
+ deploy_btn = antd.Button(
1057
+ "Share",
1058
+ type="default",
1059
+ size="large",
1060
+ elem_classes="share-btn"
1061
+ )
1062
+
1063
+ deploy_result = gr.HTML(
1064
+ label="Share Result",
1065
+ elem_classes="deploy-result"
1066
+ )
1067
+
1068
+ # ์šฐ์ธก ํŒจ๋„
1069
+ with antd.Col(span=24, md=16):
1070
+ with ms.Div(elem_classes="right_panel"):
1071
+
1072
+
1073
+
1074
+ # macOS ์Šคํƒ€์ผ ์œˆ๋„์šฐ ํ—ค๋”
1075
+ gr.HTML("""
1076
+ <div class="window-frame">
1077
+ <div class="window-header">
1078
+ <div class="window-controls">
1079
+ <div class="control close"></div>
1080
+ <div class="control minimize"></div>
1081
+ <div class="control maximize"></div>
1082
+ </div>
1083
+ <div class="window-title">Preview</div>
1084
+ </div>
1085
+ </div>
1086
+ """)
1087
+
1088
+ # ํƒญ ์ปจํ…์ธ 
1089
+ with antd.Tabs(active_key="empty", render_tab_bar="() => null") as state_tab:
1090
+ with antd.Tabs.Item(key="empty"):
1091
+ empty = antd.Empty(
1092
+ description="Enter your question to begin",
1093
+ elem_classes="right_content empty-content"
1094
+ )
1095
+
1096
+ with antd.Tabs.Item(key="loading"):
1097
+ loading = antd.Spin(
1098
+ True,
1099
+ tip="Creating visual presentation...",
1100
+ size="large",
1101
+ elem_classes="right_content"
1102
+ )
1103
+
1104
+ with antd.Tabs.Item(key="render"):
1105
+ sandbox = gr.HTML(elem_classes="html_content")
1106
+
1107
+ with antd.Tabs.Item(key="error"):
1108
+ error = antd.Empty(
1109
+ description="An error occurred. Please try again.",
1110
+ elem_classes="right_content error-content"
1111
+ )
1112
+
1113
+ # ๋ชจ๋“œ ๋ณ€๊ฒฝ ์ด๋ฒคํŠธ
1114
+ mode.change(
1115
+ fn=lambda x: x == "Generate + Web Search",
1116
+ inputs=[mode],
1117
+ outputs=[search_mode]
1118
+ )
1119
+
1120
+ # ๋ฒ„ํŠผ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ
1121
+ btn.click(
1122
+ fn=handle_generation,
1123
+ inputs=[input, setting, search_mode],
1124
+ outputs=[code_output, sandbox, state_tab, code_drawer]
1125
+ ).then(
1126
+ fn=update_placeholder,
1127
+ inputs=[],
1128
+ outputs=[input]
1129
+ )
1130
+
1131
+ boost_btn.click(
1132
+ fn=handle_boost,
1133
+ inputs=[input],
1134
+ outputs=[input, state_tab]
1135
+ )
1136
+
1137
+ deploy_btn.click(
1138
+ fn=lambda code: deploy_to_vercel(remove_code_block(code)) if code else "No code to share.",
1139
+ inputs=[code_output],
1140
+ outputs=[deploy_result]
1141
+ )
1142
+
1143
+ gr.HTML("""
1144
+ <style>
1145
+ .generate-btn {
1146
+ background: #007aff !important;
1147
+ border-radius: 8px !important;
1148
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1) !important;
1149
+ }
1150
+
1151
+ .enhance-btn {
1152
+ border-radius: 8px !important;
1153
+ border: 1px solid #007aff !important;
1154
+ color: #007aff !important;
1155
+ }
1156
+
1157
+ .share-btn {
1158
+ border-radius: 8px !important;
1159
+ border: 1px solid #28c840 !important;
1160
+ color: #28c840 !important;
1161
+ }
1162
+
1163
+ .search-toggle-btn {
1164
+ border-radius: 8px !important;
1165
+ border: 1px solid #4285f4 !important;
1166
+ color: #4285f4 !important;
1167
+ }
1168
+
1169
+ /* hover ํšจ๊ณผ */
1170
+ .generate-btn:hover {
1171
+ background: #0056b3 !important;
1172
+ }
1173
+
1174
+ .enhance-btn:hover {
1175
+ background: rgba(0,122,255,0.1) !important;
1176
+ }
1177
+
1178
+ .share-btn:hover {
1179
+ background: rgba(40,200,64,0.1) !important;
1180
+ }
1181
+
1182
+ .search-toggle-btn:hover {
1183
+ background: rgba(66,133,244,0.1) !important;
1184
+ }
1185
+ </style>
1186
+ """)
1187
+
1188
+ return demo
1189
+
1190
 
1191
  # ๋ฉ”์ธ ์‹คํ–‰ ๋ถ€๋ถ„
1192
  if __name__ == "__main__":
1193
+ try:
1194
+ demo_instance = Demo()
1195
+ demo = create_main_interface()
1196
+ demo.queue(
1197
+ default_concurrency_limit=20,
1198
+ status_update_rate=10,
1199
+ api_open=False
1200
+ ).launch(
1201
+ server_name="0.0.0.0",
1202
+ server_port=7860,
1203
+ share=False,
1204
+ debug=False
1205
+ )
1206
+ except Exception as e:
1207
+ print(f"Initialization error: {e}")
1208
+ raise