openfree commited on
Commit
97a6411
·
verified ·
1 Parent(s): f97dbc2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +90 -78
app.py CHANGED
@@ -122,7 +122,7 @@ def messages_to_history(messages: Messages) -> History:
122
 
123
  # API 클라이언트 초기화
124
  YOUR_ANTHROPIC_TOKEN = os.getenv('ANTHROPIC_API_KEY', '').strip()
125
- YOUR_OPENAI_TOKEN = os.getenv('OPENAI_API_KEY', '').strip()
126
 
127
  claude_client = anthropic.Anthropic(api_key=YOUR_ANTHROPIC_TOKEN)
128
  openai_client = openai.OpenAI(api_key=YOUR_OPENAI_TOKEN)
@@ -146,9 +146,7 @@ async def try_claude_api(system_message, claude_messages, timeout=15):
146
  collected_content += chunk.delta.text
147
  yield collected_content
148
  await asyncio.sleep(0)
149
-
150
  start_time = current_time
151
-
152
  except Exception as e:
153
  print(f"Claude API error: {str(e)}")
154
  raise e
@@ -168,7 +166,6 @@ async def try_openai_api(openai_messages):
168
  if chunk.choices[0].delta.content is not None:
169
  collected_content += chunk.choices[0].delta.content
170
  yield collected_content
171
-
172
  except Exception as e:
173
  print(f"OpenAI API error: {str(e)}")
174
  raise e
@@ -191,6 +188,10 @@ class Demo:
191
  mechanic_custom: str,
192
  view_option: str,
193
  view_custom: str):
 
 
 
 
194
  # 1) 최종 프롬프트 결합
195
  final_prompt = self.combine_options(user_prompt,
196
  genre_option, genre_custom,
@@ -199,6 +200,7 @@ class Demo:
199
  mechanic_option, mechanic_custom,
200
  view_option, view_custom)
201
 
 
202
  if not final_prompt.strip():
203
  final_prompt = random.choice(DEMO_LIST)['description']
204
 
@@ -209,7 +211,7 @@ class Demo:
209
  system_message = messages[0]['content']
210
 
211
  claude_messages = [
212
- {"role": msg["role"] if msg["role"] != "system" else "user", "content": msg["content"]}
213
  for msg in messages[1:] + [{'role': Role.USER, 'content': final_prompt}]
214
  if msg["content"].strip() != ''
215
  ]
@@ -223,6 +225,7 @@ class Demo:
223
  openai_messages.append({"role": "user", "content": final_prompt})
224
 
225
  try:
 
226
  yield [
227
  "Generating code...",
228
  _history,
@@ -234,6 +237,7 @@ class Demo:
234
 
235
  collected_content = None
236
  try:
 
237
  async for content in try_claude_api(system_message, claude_messages):
238
  yield [
239
  content,
@@ -248,6 +252,7 @@ class Demo:
248
  except Exception as claude_error:
249
  print(f"Falling back to OpenAI API due to Claude error: {str(claude_error)}")
250
 
 
251
  async for content in try_openai_api(openai_messages):
252
  yield [
253
  content,
@@ -260,6 +265,7 @@ class Demo:
260
  collected_content = content
261
 
262
  if collected_content:
 
263
  _history = messages_to_history([
264
  {'role': Role.SYSTEM, 'content': system_message}
265
  ] + claude_messages + [{
@@ -267,6 +273,7 @@ class Demo:
267
  'content': collected_content
268
  }])
269
 
 
270
  yield [
271
  collected_content,
272
  _history,
@@ -292,9 +299,7 @@ class Demo:
292
  mechanic_opt, mechanic_custom,
293
  view_opt, view_custom):
294
  """
295
- 사용자가 선택한 옵션 커스텀 내용을 base_prompt에 합쳐서 최종 프롬프트를 생성.
296
- 옵션이 '선택안함'이 아닐 경우 그 내용을 추가하고,
297
- 커스텀 입력이 비어있지 않을 경우도 추가.
298
  """
299
  final_prompt = base_prompt.strip()
300
 
@@ -346,8 +351,6 @@ def send_to_sandbox(code):
346
  data_uri = f"data:text/html;charset=utf-8;base64,{encoded_html}"
347
  return f"<iframe src=\"{data_uri}\" width=\"100%\" height=\"920px\"></iframe>"
348
 
349
- theme = gr.themes.Soft()
350
-
351
  def load_json_data():
352
  # 하드코딩된 데이터 반환 (게임 목록)
353
  return [
@@ -677,7 +680,6 @@ def deploy_to_vercel(code: str):
677
  deployment_url = f"{project_name}.vercel.app"
678
 
679
  time.sleep(5)
680
-
681
  return f"""배포 완료! <a href="https://{deployment_url}" target="_blank" style="color: #1890ff; text-decoration: underline; cursor: pointer;">https://{deployment_url}</a>"""
682
 
683
  except Exception as e:
@@ -756,69 +758,69 @@ with gr.Blocks(css_paths="app.css", theme=theme) as demo:
756
 
757
  with ms.Application() as app:
758
  with antd.ConfigProvider():
759
- # -- 좌측 상단 설명 박스 제거: 기존 header 부분 삭제 --
760
-
761
- # -- 상단에 "옵션" 구성 추가 --
762
- with antd.Collapse(
763
- accordion=True,
764
- default_active_key=[],
765
- title="옵션 설정 (선택 시 프롬프트에 자동 반영)",
766
- ghost=True
767
- ) as options_panel:
768
- with antd.CollapsePanel(header="게임 장르", key="genre"):
769
- genre_option = antd.RadioGroup(
770
- choices=["선택안함", "아케이드", "퍼즐", "액션", "전략", "캐주얼"],
771
- default_value="선택안함"
772
- )
773
- genre_custom = antd.Input(
774
- placeholder="장르에 대한 추가 요구사항을 입력해보세요 (선택)",
775
- allow_clear=True,
776
- size="small"
777
- )
778
-
779
- with antd.CollapsePanel(header="난이도", key="difficulty"):
780
- difficulty_option = antd.RadioGroup(
781
- choices=["선택안함", "고정", "진행", "선택", "레벨"],
782
- default_value="선택안함"
783
- )
784
- difficulty_custom = antd.Input(
785
- placeholder="난이도에 대한 추가 요구사항을 입력해보세요 (선택)",
786
- allow_clear=True,
787
- size="small"
788
- )
789
-
790
- with antd.CollapsePanel(header="그래픽", key="graphic"):
791
- graphic_option = antd.RadioGroup(
792
- choices=["선택안함", "미니멀", "픽셀", "카툰", "플랫"],
793
- default_value="선택안함"
794
- )
795
- graphic_custom = antd.Input(
796
- placeholder="그래픽 스타일에 대한 추가 요구사항 (선택)",
797
- allow_clear=True,
798
- size="small"
799
- )
800
-
801
- with antd.CollapsePanel(header="게임 메커닉", key="mechanic"):
802
- mechanic_option = antd.RadioGroup(
803
- choices=["선택안함", "타이밍", "충돌", "타일", "물리"],
804
- default_value="선택안함"
805
- )
806
- mechanic_custom = antd.Input(
807
- placeholder="게임 메커닉 추가 요구사항 (선택)",
808
- allow_clear=True,
809
- size="small"
810
- )
811
-
812
- with antd.CollapsePanel(header="게임 관점(뷰)", key="view"):
813
- view_option = antd.RadioGroup(
814
- choices=["선택안함", "탑다운", "사이드뷰", "아이소메트릭", "1인칭", "고정 화면"],
815
- default_value="선택안함"
816
- )
817
- view_custom = antd.Input(
818
- placeholder="게임 뷰에 대한 추가 요구사항 (선택)",
819
- allow_clear=True,
820
- size="small"
821
- )
822
 
823
  with antd.Row(gutter=[32, 12]) as layout:
824
  with antd.Col(span=24, md=8):
@@ -861,7 +863,6 @@ with gr.Blocks(css_paths="app.css", theme=theme) as demo:
861
  def execute_code(query: str):
862
  if not query or query.strip() == '':
863
  return None, gr.update(active_key="empty")
864
-
865
  try:
866
  if '```html' in query and '```' in query:
867
  code = remove_code_block(query)
@@ -885,6 +886,9 @@ with gr.Blocks(css_paths="app.css", theme=theme) as demo:
885
  outputs=[code_drawer]
886
  )
887
 
 
 
 
888
  code_drawer.close(
889
  lambda: gr.update(open=False),
890
  inputs=[],
@@ -894,9 +898,12 @@ with gr.Blocks(css_paths="app.css", theme=theme) as demo:
894
  historyBtn.click(
895
  history_render,
896
  inputs=[history],
897
- outputs=[history_drawer, history_output]
898
  )
899
 
 
 
 
900
  history_drawer.close(
901
  lambda: gr.update(open=False),
902
  inputs=[],
@@ -921,6 +928,11 @@ with gr.Blocks(css_paths="app.css", theme=theme) as demo:
921
  queue=False
922
  )
923
 
 
 
 
 
 
924
  session_drawer.close(
925
  lambda: (gr.update(open=False), gr.HTML("")),
926
  outputs=[session_drawer, session_history]
@@ -934,8 +946,8 @@ with gr.Blocks(css_paths="app.css", theme=theme) as demo:
934
  btn.click(
935
  demo_instance.generation_code,
936
  inputs=[
937
- input_prompt,
938
- setting,
939
  history,
940
  genre_option, genre_custom,
941
  difficulty_option, difficulty_custom,
 
122
 
123
  # API 클라이언트 초기화
124
  YOUR_ANTHROPIC_TOKEN = os.getenv('ANTHROPIC_API_KEY', '').strip()
125
+ YOUR_OPENAI_TOKEN = os.getenv('OPENAI_API_KEY', '').strip()
126
 
127
  claude_client = anthropic.Anthropic(api_key=YOUR_ANTHROPIC_TOKEN)
128
  openai_client = openai.OpenAI(api_key=YOUR_OPENAI_TOKEN)
 
146
  collected_content += chunk.delta.text
147
  yield collected_content
148
  await asyncio.sleep(0)
 
149
  start_time = current_time
 
150
  except Exception as e:
151
  print(f"Claude API error: {str(e)}")
152
  raise e
 
166
  if chunk.choices[0].delta.content is not None:
167
  collected_content += chunk.choices[0].delta.content
168
  yield collected_content
 
169
  except Exception as e:
170
  print(f"OpenAI API error: {str(e)}")
171
  raise e
 
188
  mechanic_custom: str,
189
  view_option: str,
190
  view_custom: str):
191
+ """
192
+ 옵션(장르/난이도/그래픽/메커닉/뷰)과 메인 프롬프트를 합쳐 최종 명령을 구성한 뒤,
193
+ Claude -> OpenAI 순으로 코드 생성을 시도합니다.
194
+ """
195
  # 1) 최종 프롬프트 결합
196
  final_prompt = self.combine_options(user_prompt,
197
  genre_option, genre_custom,
 
200
  mechanic_option, mechanic_custom,
201
  view_option, view_custom)
202
 
203
+ # 기본 입력이 비어 있으면 임의 DEMO_LIST 중 하나를 사용
204
  if not final_prompt.strip():
205
  final_prompt = random.choice(DEMO_LIST)['description']
206
 
 
211
  system_message = messages[0]['content']
212
 
213
  claude_messages = [
214
+ {"role": msg["role"] if msg["role"] != "system" else "user", "content": msg["content"]}
215
  for msg in messages[1:] + [{'role': Role.USER, 'content': final_prompt}]
216
  if msg["content"].strip() != ''
217
  ]
 
225
  openai_messages.append({"role": "user", "content": final_prompt})
226
 
227
  try:
228
+ # 첫 yield (로딩 상태)
229
  yield [
230
  "Generating code...",
231
  _history,
 
237
 
238
  collected_content = None
239
  try:
240
+ # Claude 시도
241
  async for content in try_claude_api(system_message, claude_messages):
242
  yield [
243
  content,
 
252
  except Exception as claude_error:
253
  print(f"Falling back to OpenAI API due to Claude error: {str(claude_error)}")
254
 
255
+ # OpenAI 시도
256
  async for content in try_openai_api(openai_messages):
257
  yield [
258
  content,
 
265
  collected_content = content
266
 
267
  if collected_content:
268
+ # 히스토리 업데이트
269
  _history = messages_to_history([
270
  {'role': Role.SYSTEM, 'content': system_message}
271
  ] + claude_messages + [{
 
273
  'content': collected_content
274
  }])
275
 
276
+ # 최종 결과 yield
277
  yield [
278
  collected_content,
279
  _history,
 
299
  mechanic_opt, mechanic_custom,
300
  view_opt, view_custom):
301
  """
302
+ 사용자가 선택한 옵션 + 커스텀 내용 -> base_prompt에 합쳐 최종 프롬프트로 만든다.
 
 
303
  """
304
  final_prompt = base_prompt.strip()
305
 
 
351
  data_uri = f"data:text/html;charset=utf-8;base64,{encoded_html}"
352
  return f"<iframe src=\"{data_uri}\" width=\"100%\" height=\"920px\"></iframe>"
353
 
 
 
354
  def load_json_data():
355
  # 하드코딩된 데이터 반환 (게임 목록)
356
  return [
 
680
  deployment_url = f"{project_name}.vercel.app"
681
 
682
  time.sleep(5)
 
683
  return f"""배포 완료! <a href="https://{deployment_url}" target="_blank" style="color: #1890ff; text-decoration: underline; cursor: pointer;">https://{deployment_url}</a>"""
684
 
685
  except Exception as e:
 
758
 
759
  with ms.Application() as app:
760
  with antd.ConfigProvider():
761
+ # (1) 상단 설명 박스 제거, 대신 단순 안내 문구
762
+ gr.Markdown("### [옵션을 선택하면 자동으로 프롬프트에 포함됩니다.]")
763
+
764
+ # (2) Collapse에 'title' 대신 Panel을 직접 구성
765
+ with antd.Collapse(accordion=True, default_active_key=[], ghost=True) as options_panel:
766
+ # 전체 옵션 제목용 Panel
767
+ with antd.CollapsePanel(header="옵션 설정 (선택 시 프롬프트에 자동 반영)", key="option_header"):
768
+ # 세부 패널은 필요시 추가 (현재는 바로 RadioGroup 등을 사용)
769
+ with antd.Collapse(accordion=True, default_active_key=[]):
770
+ with antd.CollapsePanel(header="게임 장르", key="genre"):
771
+ genre_option = antd.RadioGroup(
772
+ choices=["선택안함", "아케이드", "퍼즐", "액션", "전략", "캐주얼"],
773
+ default_value="선택안함"
774
+ )
775
+ genre_custom = antd.Input(
776
+ placeholder="장르에 대한 추가 요구사항 (선택)",
777
+ allow_clear=True,
778
+ size="small"
779
+ )
780
+
781
+ with antd.CollapsePanel(header="난이도", key="difficulty"):
782
+ difficulty_option = antd.RadioGroup(
783
+ choices=["선택안함", "고정", "진행", "선택", "레벨"],
784
+ default_value="선택안함"
785
+ )
786
+ difficulty_custom = antd.Input(
787
+ placeholder="난이도에 대한 추가 요구사항 (선택)",
788
+ allow_clear=True,
789
+ size="small"
790
+ )
791
+
792
+ with antd.CollapsePanel(header="그래픽", key="graphic"):
793
+ graphic_option = antd.RadioGroup(
794
+ choices=["선택안함", "미니멀", "픽셀", "카툰", "플랫"],
795
+ default_value="선택안함"
796
+ )
797
+ graphic_custom = antd.Input(
798
+ placeholder="그래픽 스타일에 대한 추가 요구사항 (선택)",
799
+ allow_clear=True,
800
+ size="small"
801
+ )
802
+
803
+ with antd.CollapsePanel(header="게임 메커닉", key="mechanic"):
804
+ mechanic_option = antd.RadioGroup(
805
+ choices=["선택안함", "타이밍", "충돌", "타일", "물리"],
806
+ default_value="선택안함"
807
+ )
808
+ mechanic_custom = antd.Input(
809
+ placeholder="게임 메커닉 추가 요구사항 (선택)",
810
+ allow_clear=True,
811
+ size="small"
812
+ )
813
+
814
+ with antd.CollapsePanel(header="게임 관점(뷰)", key="view"):
815
+ view_option = antd.RadioGroup(
816
+ choices=["선택안함", "탑다운", "사이드뷰", "아이소메트릭", "1인칭", "고정 화면"],
817
+ default_value="선택안함"
818
+ )
819
+ view_custom = antd.Input(
820
+ placeholder="게임 뷰에 대한 추가 요구사항 (선택)",
821
+ allow_clear=True,
822
+ size="small"
823
+ )
824
 
825
  with antd.Row(gutter=[32, 12]) as layout:
826
  with antd.Col(span=24, md=8):
 
863
  def execute_code(query: str):
864
  if not query or query.strip() == '':
865
  return None, gr.update(active_key="empty")
 
866
  try:
867
  if '```html' in query and '```' in query:
868
  code = remove_code_block(query)
 
886
  outputs=[code_drawer]
887
  )
888
 
889
+ with antd.Drawer(open=False, placement="left", width="750px") as code_drawer:
890
+ code_output = legacy.Markdown()
891
+
892
  code_drawer.close(
893
  lambda: gr.update(open=False),
894
  inputs=[],
 
898
  historyBtn.click(
899
  history_render,
900
  inputs=[history],
901
+ outputs=[history_drawer, None]
902
  )
903
 
904
+ with antd.Drawer(open=False, placement="left", width="900px") as history_drawer:
905
+ history_output = legacy.Chatbot(show_label=False, flushing=False, height=960, elem_classes="history_chatbot")
906
+
907
  history_drawer.close(
908
  lambda: gr.update(open=False),
909
  inputs=[],
 
928
  queue=False
929
  )
930
 
931
+ with antd.Drawer(open=False, placement="right", width="900px", elem_classes="session-drawer") as session_drawer:
932
+ with antd.Flex(vertical=True, gap="middle"):
933
+ session_history = gr.HTML(elem_classes="session-history")
934
+ close_btn = antd.Button("Close", type="default", elem_classes="close-btn")
935
+
936
  session_drawer.close(
937
  lambda: (gr.update(open=False), gr.HTML("")),
938
  outputs=[session_drawer, session_history]
 
946
  btn.click(
947
  demo_instance.generation_code,
948
  inputs=[
949
+ input_prompt,
950
+ setting,
951
  history,
952
  genre_option, genre_custom,
953
  difficulty_option, difficulty_custom,