openfree commited on
Commit
464a9ee
·
verified ·
1 Parent(s): 7fce583

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +29 -228
app.py CHANGED
@@ -709,21 +709,18 @@ def deploy_to_vercel(code: str):
709
 
710
  deployment_url = f"https://{project_name}.vercel.app"
711
  print(f"[DEBUG] 배포 성공 -> URL: {deployment_url}")
712
- time.sleep(3)
713
 
714
- # 자바스크립트 없이, 링크만
 
715
  return f"""
716
- <div style="border:1px solid #34c759; padding:15px; border-radius:8px;">
717
- <h3 style="margin:0; color:#34c759;">✅ Deployment complete!</h3>
718
- <p style="margin:0;">
719
- Your app is live at:
720
- <a href="{deployment_url}" target="_blank" style="color: #0066cc; text-decoration: underline;">
721
- {deployment_url}
722
- </a>
723
- </p>
724
- </div>
725
- """
726
 
 
727
  except Exception as e:
728
  print("[ERROR] deploy_to_vercel() 예외:", e)
729
  return f"Error during deployment: {str(e)}"
@@ -772,196 +769,36 @@ theme = gr.themes.Soft(
772
  )
773
 
774
  with gr.Blocks(css_paths=["app.css"], theme=theme) as demo:
775
- # 헤더 HTML
776
  header_html = gr.HTML("""
777
  <div class="app-header">
778
  <h1>🎮 Vibe Game Craft</h1>
779
  <p>설명을 입력하면 웹 기반 HTML5, JavaScript, CSS 게임을 생성합니다. 실시간 미리보기와 배포 기능도 지원됩니다.</p>
780
  </div>
781
-
782
  <!-- 배포 결과 박스 - 헤더 바로 아래 위치 -->
783
  <div id="deploy-banner" style="display:none;" class="deploy-banner">
784
- <div class="deploy-banner-content">
785
- <div class="deploy-banner-icon">🚀</div>
786
- <div class="deploy-banner-info">
787
- <div id="deploy-banner-title" class="deploy-banner-title">배포 상태</div>
788
- <div id="deploy-banner-message" class="deploy-banner-message"></div>
789
- </div>
790
- <div id="deploy-banner-url-container" class="deploy-banner-url-container" style="display:none;">
791
- <a id="deploy-banner-url" href="#" target="_blank" class="deploy-banner-url"></a>
792
- <button onclick="copyBannerUrl()" class="deploy-banner-copy-btn">복사</button>
793
- </div>
794
- </div>
795
  </div>
796
-
797
  <style>
798
- :root {
799
- --primary-color: #9c89b8;
800
- --secondary-color: #f0a6ca;
801
- --accent-color: #b8bedd;
802
- --background-color: #f9f7fd;
803
- --panel-color: #ffffff;
804
- --text-color: #3a3042;
805
- --button-hover: #efc3e6;
806
- --shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08);
807
- --radius: 12px;
808
- }
809
- body {
810
- background-color: var(--background-color);
811
- color: var(--text-color);
812
- font-family: 'Poppins', sans-serif;
813
- }
814
- .app-header {
815
- text-align: center;
816
- padding: 1.5rem 1rem;
817
- margin-bottom: 0.5rem;
818
- background: linear-gradient(to right, var(--primary-color), var(--secondary-color));
819
- border-radius: var(--radius);
820
- box-shadow: var(--shadow);
821
- color: white;
822
- }
823
- .app-header h1 {
824
- font-size: 2.5rem;
825
- font-weight: 700;
826
- margin-bottom: 0.5rem;
827
- text-shadow: 0 2px 4px rgba(0,0,0,0.1);
828
- }
829
- .app-header p {
830
- font-size: 1.1rem;
831
- opacity: 0.9;
832
- max-width: 800px;
833
- margin: 0 auto;
834
- }
835
- .deploy-banner {
836
- background: white;
837
- border-radius: var(--radius);
838
- margin: 0.5rem auto 1.5rem auto;
839
- box-shadow: var(--shadow);
840
- max-width: 1200px;
841
- border: 1px solid #ddd;
842
- overflow: hidden;
843
- transition: all 0.3s ease;
844
- }
845
- .deploy-banner.success {
846
- border-left: 5px solid #34c759;
847
- }
848
- .deploy-banner.error {
849
- border-left: 5px solid #ff3b30;
850
- }
851
- .deploy-banner.loading {
852
- border-left: 5px solid #007aff;
853
- }
854
- .deploy-banner-content {
855
- display: flex;
856
- align-items: center;
857
- padding: 15px 20px;
858
- }
859
- .deploy-banner-icon {
860
- font-size: 24px;
861
- margin-right: 15px;
862
- }
863
- .deploy-banner-info {
864
- flex: 1;
865
- }
866
- .deploy-banner-title {
867
- font-weight: bold;
868
- font-size: 16px;
869
- margin-bottom: 5px;
870
- }
871
- .deploy-banner-message {
872
- color: #666;
873
- }
874
- .deploy-banner-url-container {
875
- background: #f5f8ff;
876
- padding: 10px 15px;
877
- border-radius: 8px;
878
- margin-left: 20px;
879
- max-width: 400px;
880
- display: flex;
881
- align-items: center;
882
- }
883
- .deploy-banner-url {
884
- color: #0066cc;
885
- text-decoration: none;
886
- font-weight: 500;
887
- word-break: break-all;
888
- flex: 1;
889
- }
890
- .deploy-banner-copy-btn {
891
- background: #0066cc;
892
- color: white;
893
- border: none;
894
- border-radius: 4px;
895
- padding: 5px 10px;
896
- margin-left: 10px;
897
- cursor: pointer;
898
- font-size: 12px;
899
- }
900
- .deploy-banner-copy-btn:hover {
901
- background: #0052a3;
902
- }
903
  </style>
904
-
905
  <script>
906
- function copyBannerUrl() {
907
- const url = document.getElementById('deploy-banner-url').href;
908
- navigator.clipboard.writeText(url)
909
- .then(() => {
910
- const copyBtn = document.querySelector('.deploy-banner-copy-btn');
911
- const originalText = copyBtn.textContent;
912
- copyBtn.textContent = '복사됨!';
913
- setTimeout(() => {
914
- copyBtn.textContent = originalText;
915
- }, 1000);
916
- });
917
- }
918
- function showDeployBanner(type, title, message, url) {
919
- const banner = document.getElementById('deploy-banner');
920
- const bannerTitle = document.getElementById('deploy-banner-title');
921
- const bannerMessage = document.getElementById('deploy-banner-message');
922
- const bannerUrlContainer = document.getElementById('deploy-banner-url-container');
923
- const bannerUrl = document.getElementById('deploy-banner-url');
924
-
925
- banner.className = 'deploy-banner ' + type;
926
- bannerTitle.textContent = title;
927
- bannerMessage.textContent = message;
928
-
929
- if (url) {
930
- bannerUrl.href = url;
931
- bannerUrl.textContent = url;
932
- bannerUrlContainer.style.display = 'flex';
933
- } else {
934
- bannerUrlContainer.style.display = 'none';
935
- }
936
-
937
- banner.style.display = 'block';
938
- }
939
  </script>
940
  """)
941
 
942
  history = gr.State([])
943
  setting = gr.State({"system": SystemPrompt})
944
-
945
- # 배포 상태를 저장할 변수
946
- deploy_status = gr.State({
947
- "is_deployed": False,
948
- "status": "",
949
- "url": "",
950
- "message": ""
951
- })
952
 
953
  with ms.Application() as app:
954
  with antd.ConfigProvider():
955
 
956
- # code Drawer
957
  with antd.Drawer(open=False, title="코드 보기", placement="left", width="750px") as code_drawer:
958
  code_output = legacy.Markdown()
959
 
960
- # history Drawer
961
  with antd.Drawer(open=False, title="히스토리", placement="left", width="900px") as history_drawer:
962
  history_output = legacy.Chatbot(show_label=False, flushing=False, height=960, elem_classes="history_chatbot")
963
 
964
- # templates Drawer
965
  with antd.Drawer(
966
  open=False,
967
  title="게임 템플릿",
@@ -974,7 +811,6 @@ with gr.Blocks(css_paths=["app.css"], theme=theme) as demo:
974
  session_history = gr.HTML(elem_classes="session-history")
975
  close_btn = antd.Button("닫기", type="default", elem_classes="close-btn")
976
 
977
- # 좌우 레이아웃
978
  with antd.Row(gutter=[32, 12], align="top", elem_classes="equal-height-container") as layout:
979
 
980
  # 왼쪽 Col
@@ -982,31 +818,25 @@ with gr.Blocks(css_paths=["app.css"], theme=theme) as demo:
982
  with ms.Div(elem_classes="right_panel panel"):
983
  gr.HTML(r"""
984
  <div class="render_header">
985
- <span class="header_btn"></span>
986
- <span class="header_btn"></span>
987
- <span class="header_btn"></span>
988
  </div>
989
  """)
990
  with antd.Tabs(active_key="empty", render_tab_bar="() => null") as state_tab:
991
  with antd.Tabs.Item(key="empty"):
992
  empty = antd.Empty(description="게임을 만들려면 설명을 입력하세요", elem_classes="right_content")
993
  with antd.Tabs.Item(key="loading"):
994
- loading = antd.Spin(
995
- True, tip="게임 코드 생성 중...", size="large", elem_classes="right_content"
996
- )
997
  with antd.Tabs.Item(key="render"):
998
  sandbox = gr.HTML(elem_classes="html_content")
999
 
1000
  # 오른쪽 Col
1001
  with antd.Col(span=24, md=8, elem_classes="equal-height-col"):
1002
  with antd.Flex(vertical=True, gap="small", elem_classes="right-top-buttons"):
1003
- # 상단 메뉴 버튼들
1004
  with antd.Flex(gap="small", elem_classes="setting-buttons", justify="space-between"):
1005
  codeBtn = antd.Button("🧑‍💻 코드 보기", type="default", elem_classes="code-btn")
1006
  historyBtn = antd.Button("📜 히스토리", type="default", elem_classes="history-btn")
1007
  template_btn = antd.Button("🎮 템플릿", type="default", elem_classes="template-btn")
1008
 
1009
- # 액션 버튼들
1010
  with antd.Flex(gap="small", justify="space-between", elem_classes="action-buttons"):
1011
  btn = antd.Button("전송", type="primary", size="large", elem_classes="send-btn")
1012
  boost_btn = antd.Button("증강", type="default", size="large", elem_classes="boost-btn")
@@ -1023,38 +853,19 @@ with gr.Blocks(css_paths=["app.css"], theme=theme) as demo:
1023
  )
1024
  gr.HTML('<div class="help-text">💡 원하는 게임의 설명을 입력하세요. 예: "테트리스 게임 제작해줘."</div>')
1025
 
1026
- deploy_result_container = gr.HTML(
1027
- label="Deployment Result",
1028
- value="아직 배포 안됨...",
1029
- unsafe_allow_html=True
1030
  )
1031
 
1032
-
 
 
1033
 
1034
- # 이벤트 / 콜백
1035
- # Code Drawer
1036
- codeBtn.click(
1037
- lambda: gr.update(open=True),
1038
- inputs=[],
1039
- outputs=[code_drawer]
1040
- )
1041
- code_drawer.close(
1042
- lambda: gr.update(open=False),
1043
- inputs=[],
1044
- outputs=[code_drawer]
1045
- )
1046
-
1047
- # History Drawer
1048
- historyBtn.click(
1049
- history_render,
1050
- inputs=[history],
1051
- outputs=[history_drawer, history_output]
1052
- )
1053
- history_drawer.close(
1054
- lambda: gr.update(open=False),
1055
- inputs=[],
1056
- outputs=[history_drawer]
1057
- )
1058
 
1059
  # Template Drawer
1060
  template_btn.click(
@@ -1062,14 +873,8 @@ with gr.Blocks(css_paths=["app.css"], theme=theme) as demo:
1062
  outputs=[session_drawer, session_history],
1063
  queue=False
1064
  )
1065
- session_drawer.close(
1066
- lambda: (gr.update(open=False), gr.HTML("")),
1067
- outputs=[session_drawer, session_history]
1068
- )
1069
- close_btn.click(
1070
- lambda: (gr.update(open=False), gr.HTML("")),
1071
- outputs=[session_drawer, session_history]
1072
- )
1073
 
1074
  # 전송 버튼
1075
  btn.click(
@@ -1079,11 +884,7 @@ with gr.Blocks(css_paths=["app.css"], theme=theme) as demo:
1079
  )
1080
 
1081
  # 클리어 버튼
1082
- clear_btn.click(
1083
- demo_instance.clear_history,
1084
- inputs=[],
1085
- outputs=[history]
1086
- )
1087
 
1088
  # 증강 버튼
1089
  boost_btn.click(
@@ -1099,7 +900,7 @@ with gr.Blocks(css_paths=["app.css"], theme=theme) as demo:
1099
  outputs=[sandbox, state_tab]
1100
  )
1101
 
1102
- # 여기서 outputs=[deploy_result_container]가 핵심 수정
1103
  deploy_btn.click(
1104
  fn=lambda code: deploy_to_vercel(remove_code_block(code)) if code else "No code generated.",
1105
  inputs=[code_output],
 
709
 
710
  deployment_url = f"https://{project_name}.vercel.app"
711
  print(f"[DEBUG] 배포 성공 -> URL: {deployment_url}")
712
+ time.sleep(5)
713
 
714
+
715
+ # Markdown 링크로 반환
716
  return f"""
717
+ **Deployment complete!**
718
+ Your app is live at:
719
+ [**{deployment_url}**]({deployment_url})
720
+ """
721
+
 
 
 
 
 
722
 
723
+
724
  except Exception as e:
725
  print("[ERROR] deploy_to_vercel() 예외:", e)
726
  return f"Error during deployment: {str(e)}"
 
769
  )
770
 
771
  with gr.Blocks(css_paths=["app.css"], theme=theme) as demo:
 
772
  header_html = gr.HTML("""
773
  <div class="app-header">
774
  <h1>🎮 Vibe Game Craft</h1>
775
  <p>설명을 입력하면 웹 기반 HTML5, JavaScript, CSS 게임을 생성합니다. 실시간 미리보기와 배포 기능도 지원됩니다.</p>
776
  </div>
 
777
  <!-- 배포 결과 박스 - 헤더 바로 아래 위치 -->
778
  <div id="deploy-banner" style="display:none;" class="deploy-banner">
779
+ <!-- (생략) ... 배너 스타일/스크립트 ... -->
 
 
 
 
 
 
 
 
 
 
780
  </div>
 
781
  <style>
782
+ /* (생략) ... CSS ... */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
783
  </style>
 
784
  <script>
785
+ /* (생략) ... JS copyBannerUrl / showDeployBanner ... */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
786
  </script>
787
  """)
788
 
789
  history = gr.State([])
790
  setting = gr.State({"system": SystemPrompt})
791
+ deploy_status = gr.State({"is_deployed": False,"status": "","url": "","message": ""})
 
 
 
 
 
 
 
792
 
793
  with ms.Application() as app:
794
  with antd.ConfigProvider():
795
 
 
796
  with antd.Drawer(open=False, title="코드 보기", placement="left", width="750px") as code_drawer:
797
  code_output = legacy.Markdown()
798
 
 
799
  with antd.Drawer(open=False, title="히스토리", placement="left", width="900px") as history_drawer:
800
  history_output = legacy.Chatbot(show_label=False, flushing=False, height=960, elem_classes="history_chatbot")
801
 
 
802
  with antd.Drawer(
803
  open=False,
804
  title="게임 템플릿",
 
811
  session_history = gr.HTML(elem_classes="session-history")
812
  close_btn = antd.Button("닫기", type="default", elem_classes="close-btn")
813
 
 
814
  with antd.Row(gutter=[32, 12], align="top", elem_classes="equal-height-container") as layout:
815
 
816
  # 왼쪽 Col
 
818
  with ms.Div(elem_classes="right_panel panel"):
819
  gr.HTML(r"""
820
  <div class="render_header">
821
+ <span class="header_btn"></span><span class="header_btn"></span><span class="header_btn"></span>
 
 
822
  </div>
823
  """)
824
  with antd.Tabs(active_key="empty", render_tab_bar="() => null") as state_tab:
825
  with antd.Tabs.Item(key="empty"):
826
  empty = antd.Empty(description="게임을 만들려면 설명을 입력하세요", elem_classes="right_content")
827
  with antd.Tabs.Item(key="loading"):
828
+ loading = antd.Spin(True, tip="게임 코드 생성 중...", size="large", elem_classes="right_content")
 
 
829
  with antd.Tabs.Item(key="render"):
830
  sandbox = gr.HTML(elem_classes="html_content")
831
 
832
  # 오른쪽 Col
833
  with antd.Col(span=24, md=8, elem_classes="equal-height-col"):
834
  with antd.Flex(vertical=True, gap="small", elem_classes="right-top-buttons"):
 
835
  with antd.Flex(gap="small", elem_classes="setting-buttons", justify="space-between"):
836
  codeBtn = antd.Button("🧑‍💻 코드 보기", type="default", elem_classes="code-btn")
837
  historyBtn = antd.Button("📜 히스토리", type="default", elem_classes="history-btn")
838
  template_btn = antd.Button("🎮 템플릿", type="default", elem_classes="template-btn")
839
 
 
840
  with antd.Flex(gap="small", justify="space-between", elem_classes="action-buttons"):
841
  btn = antd.Button("전송", type="primary", size="large", elem_classes="send-btn")
842
  boost_btn = antd.Button("증강", type="default", size="large", elem_classes="boost-btn")
 
853
  )
854
  gr.HTML('<div class="help-text">💡 원하는 게임의 설명을 입력하세요. 예: "테트리스 게임 제작해줘."</div>')
855
 
856
+ # Markdown으로 배포 결과 표시
857
+ deploy_result_container = gr.Markdown(
858
+ value="아직 배포된 게임이 없습니다.",
859
+ label="Deployment Result"
860
  )
861
 
862
+ # Code Drawer 열기/닫기
863
+ codeBtn.click(lambda: gr.update(open=True), inputs=[], outputs=[code_drawer])
864
+ code_drawer.close(lambda: gr.update(open=False), inputs=[], outputs=[code_drawer])
865
 
866
+ # History Drawer 열기/닫기
867
+ historyBtn.click(history_render, inputs=[history], outputs=[history_drawer, history_output])
868
+ history_drawer.close(lambda: gr.update(open=False), inputs=[], outputs=[history_drawer])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
869
 
870
  # Template Drawer
871
  template_btn.click(
 
873
  outputs=[session_drawer, session_history],
874
  queue=False
875
  )
876
+ session_drawer.close(lambda: (gr.update(open=False), gr.HTML("")), outputs=[session_drawer, session_history])
877
+ close_btn.click(lambda: (gr.update(open=False), gr.HTML("")), outputs=[session_drawer, session_history])
 
 
 
 
 
 
878
 
879
  # 전송 버튼
880
  btn.click(
 
884
  )
885
 
886
  # 클리어 버튼
887
+ clear_btn.click(demo_instance.clear_history, inputs=[], outputs=[history])
 
 
 
 
888
 
889
  # 증강 버튼
890
  boost_btn.click(
 
900
  outputs=[sandbox, state_tab]
901
  )
902
 
903
+ # 배포 버튼 → deploy_result_container (Markdown)
904
  deploy_btn.click(
905
  fn=lambda code: deploy_to_vercel(remove_code_block(code)) if code else "No code generated.",
906
  inputs=[code_output],