openfree commited on
Commit
7f1e73f
ยท
verified ยท
1 Parent(s): df04dee

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +431 -225
app.py CHANGED
@@ -1,3 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
  import os
2
  import re
3
  import random
@@ -20,8 +32,9 @@ import urllib.parse
20
  from huggingface_hub import HfApi, create_repo
21
  import string
22
  import random
 
23
 
24
-
25
  SystemPrompt = """๋„ˆ์˜ ์ด๋ฆ„์€ 'MOUSE'์ด๋‹ค. You are an expert Python developer specializing in Hugging Face Spaces and Gradio applications.
26
  Your task is to create functional and aesthetically pleasing web applications using Python, Gradio, and Hugging Face integration.
27
 
@@ -85,16 +98,17 @@ from config import DEMO_LIST
85
 
86
  class Role:
87
  SYSTEM = "system"
88
- USER = "user"
89
  ASSISTANT = "assistant"
90
 
91
  History = List[Tuple[str, str]]
92
  Messages = List[Dict[str, str]]
93
 
94
- # ์ด๋ฏธ์ง€ ์บ์‹œ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅ
95
  IMAGE_CACHE = {}
96
 
97
  def get_image_base64(image_path):
 
98
  if image_path in IMAGE_CACHE:
99
  return IMAGE_CACHE[image_path]
100
  try:
@@ -102,9 +116,10 @@ def get_image_base64(image_path):
102
  encoded_string = base64.b64encode(image_file.read()).decode()
103
  IMAGE_CACHE[image_path] = encoded_string
104
  return encoded_string
105
- except:
 
106
  return IMAGE_CACHE.get('default.png', '')
107
-
108
  def history_to_messages(history: History, system: str) -> Messages:
109
  messages = [{'role': Role.SYSTEM, 'content': system}]
110
  for h in history:
@@ -126,52 +141,6 @@ YOUR_OPENAI_TOKEN = os.getenv('OPENAI_API_KEY')
126
  claude_client = anthropic.Anthropic(api_key=YOUR_ANTHROPIC_TOKEN)
127
  openai_client = openai.OpenAI(api_key=YOUR_OPENAI_TOKEN)
128
 
129
- async def try_claude_api(system_message, claude_messages, timeout=15):
130
- try:
131
- start_time = time.time()
132
- with claude_client.messages.stream(
133
- model="claude-3-5-sonnet-20241022",
134
- max_tokens=7800,
135
- system=system_message,
136
- messages=claude_messages
137
- ) as stream:
138
- collected_content = ""
139
- for chunk in stream:
140
- current_time = time.time()
141
- if current_time - start_time > timeout:
142
- print(f"Claude API response time: {current_time - start_time:.2f} seconds")
143
- raise TimeoutError("Claude API timeout")
144
- if chunk.type == "content_block_delta":
145
- collected_content += chunk.delta.text
146
- yield collected_content
147
- await asyncio.sleep(0)
148
-
149
- start_time = current_time
150
-
151
- except Exception as e:
152
- print(f"Claude API error: {str(e)}")
153
- raise e
154
-
155
- async def try_openai_api(openai_messages):
156
- try:
157
- stream = openai_client.chat.completions.create(
158
- model="gpt-4o",
159
- messages=openai_messages,
160
- stream=True,
161
- max_tokens=4096,
162
- temperature=0.7
163
- )
164
-
165
- collected_content = ""
166
- for chunk in stream:
167
- if chunk.choices[0].delta.content is not None:
168
- collected_content += chunk.choices[0].delta.content
169
- yield collected_content
170
-
171
- except Exception as e:
172
- print(f"OpenAI API error: {str(e)}")
173
- raise e
174
-
175
  # Built-in modules that don't need to be in requirements.txt
176
  BUILTIN_MODULES = {
177
  'os', 'sys', 're', 'time', 'json', 'csv', 'math', 'random', 'datetime', 'calendar',
@@ -322,20 +291,12 @@ IMPORT_TO_PACKAGE = {
322
 
323
  def get_package_name(import_name):
324
  """์ž„ํฌํŠธ๋ช…์œผ๋กœ๋ถ€ํ„ฐ ์‹ค์ œ ํŒจํ‚ค์ง€๋ช…์„ ๋ฐ˜ํ™˜"""
325
- # ๋‚ด์žฅ ๋ชจ๋“ˆ์ด๋ฉด None ๋ฐ˜ํ™˜
326
  if import_name in BUILTIN_MODULES:
327
  return None
328
-
329
- # ์ ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ์ฒซ ๋ถ€๋ถ„๋งŒ ์‚ฌ์šฉ (์˜ˆ: matplotlib.pyplot -> matplotlib)
330
  base_import = import_name.split('.')[0]
331
-
332
- # ๋‚ด์žฅ ๋ชจ๋“ˆ์ด๋ฉด None ๋ฐ˜ํ™˜
333
  if base_import in BUILTIN_MODULES:
334
  return None
335
-
336
  return IMPORT_TO_PACKAGE.get(base_import, base_import)
337
-
338
-
339
 
340
  def analyze_code(code: str) -> str:
341
  """์ฝ”๋“œ ๋ถ„์„ ๊ฒฐ๊ณผ๋ฅผ HTML ํ˜•์‹์œผ๋กœ ๋ฐ˜ํ™˜"""
@@ -359,15 +320,13 @@ def analyze_code(code: str) -> str:
359
  for line in code.split('\n'):
360
  if line.startswith('import ') or line.startswith('from '):
361
  imports.append(line.strip())
362
- # ํŒจํ‚ค์ง€ ์ด๋ฆ„ ์ถ”์ถœ ๋ฐ ๋ณ€ํ™˜
363
  if line.startswith('import '):
364
  package = line.split('import ')[1].split()[0].split('.')[0]
365
  else:
366
  package = line.split('from ')[1].split()[0].split('.')[0]
367
 
368
- # ๋‚ด์žฅ ๋ชจ๋“ˆ์ด ์•„๋‹Œ ๊ฒฝ์šฐ๋งŒ ํŒจํ‚ค์ง€ ์ถ”๊ฐ€
369
  package_name = get_package_name(package)
370
- if package_name: # None์ด ์•„๋‹Œ ๊ฒฝ์šฐ๋งŒ ์ถ”๊ฐ€
371
  required_packages.add(package_name)
372
 
373
  if imports:
@@ -377,16 +336,12 @@ def analyze_code(code: str) -> str:
377
  analysis.append(f"<li><code>{imp}</code></li>")
378
  analysis.append("</ul>")
379
 
380
- # requirements.txt ์„ค๋ช… ์ถ”๊ฐ€
381
  analysis.append("<h3>๐Ÿ“‹ Requirements.txt</h3>")
382
  analysis.append("<p>์ด ์•ฑ์„ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ํŒจํ‚ค์ง€๋“ค์ž…๋‹ˆ๋‹ค:</p>")
383
  analysis.append("<pre>")
384
  for pkg in sorted(required_packages):
385
- if pkg and pkg not in BUILTIN_MODULES: # None์ด ์•„๋‹ˆ๊ณ  ๋‚ด์žฅ ๋ชจ๋“ˆ์ด ์•„๋‹Œ ๊ฒฝ์šฐ๋งŒ ์ถ”๊ฐ€
386
- if pkg == 'gradio':
387
- analysis.append("gradio==5.5.0")
388
- else:
389
- analysis.append(pkg)
390
  analysis.append("</pre>")
391
 
392
  # 2. ํ•จ์ˆ˜ ๋ถ„์„
@@ -409,12 +364,10 @@ def analyze_code(code: str) -> str:
409
  current_func = []
410
 
411
  if functions:
412
- analysis.append("<h2>๐Ÿ”ง ์ฃผ์š” ํ•จ์ˆ˜ ์„ค๋ช…</h2>")
413
  for func in functions:
414
  func_name = func.split('def ')[1].split('(')[0]
415
  analysis.append(f"<h3><code>{func_name}</code></h3>")
416
- analysis.append(f"<p>{get_function_description(func)}</p>")
417
- # ํ•จ์ˆ˜ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ถ„์„
418
  params = func.split('(')[1].split(')')[0]
419
  if params.strip():
420
  analysis.append("<p>ํŒŒ๋ผ๋ฏธํ„ฐ:</p><ul>")
@@ -434,35 +387,14 @@ def analyze_code(code: str) -> str:
434
 
435
  if ui_components:
436
  analysis.append("<h2>๐ŸŽจ UI ๊ตฌ์„ฑ์š”์†Œ</h2>")
437
- analysis.append("<p>์ด ์•ฑ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ Gradio ์ปดํฌ๋„ŒํŠธ๋“ค๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค:</p>")
438
  analysis.append("<ul>")
439
  for component in ui_components:
440
- analysis.append(f"<li><strong>{component}</strong>: {get_component_description(component)}</li>")
441
  analysis.append("</ul>")
442
 
443
- # 4. ํŠน์ง• ๋ฐ ๊ธฐ๋Šฅ
444
- analysis.append("<h2>โœจ ์ฃผ์š” ํŠน์ง•</h2>")
445
- analysis.append("<ul>")
446
- if 'theme=' in code:
447
- analysis.append("<li>์ปค์Šคํ…€ ํ…Œ๋งˆ ์ ์šฉ์œผ๋กœ ์ผ๊ด€๋œ ๋””์ž์ธ</li>")
448
- if 'with gr.Row' in code:
449
- analysis.append("<li>๋ฐ˜์‘ํ˜• ๋ ˆ์ด์•„์›ƒ์œผ๋กœ ๋‹ค์–‘ํ•œ ํ™”๋ฉด ํฌ๊ธฐ ์ง€์›</li>")
450
- if 'gr.State' in code:
451
- analysis.append("<li>์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ํ†ตํ•œ ๋ฐ์ดํ„ฐ ์œ ์ง€</li>")
452
- if '.click(' in code:
453
- analysis.append("<li>์ด๋ฒคํŠธ ํ•ธ๋“ค๋ง์„ ํ†ตํ•œ ๋™์  ์ƒํ˜ธ์ž‘์šฉ</li>")
454
- analysis.append("</ul>")
455
-
456
- # 5. ์‹คํ–‰ ๋ฐฉ๋ฒ•
457
- analysis.append("<h2>โ–ถ๏ธ ์‹คํ–‰ ๋ฐฉ๋ฒ•</h2>")
458
- analysis.append("<ol>")
459
- analysis.append("<li>'์‹คํ–‰ํ•˜๊ธฐ' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์—ฌ Hugging Face Space์— ๋ฐฐํฌ</li>")
460
- analysis.append("<li>์ƒ์„ฑ๋œ ๋งํฌ๋ฅผ ํด๋ฆญํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰</li>")
461
- analysis.append("<li>ํ•„์š”ํ•œ ์ž…๋ ฅ๊ฐ’์„ ์ œ๊ณตํ•˜๊ณ  ์ƒํ˜ธ์ž‘์šฉ ์‹œ์ž‘</li>")
462
- analysis.append("</ol>")
463
-
464
  return "\n".join(analysis)
465
 
 
466
  def get_function_description(func: str) -> str:
467
  """ํ•จ์ˆ˜์˜ ๋ชฉ์ ์„ ์„ค๋ช…ํ•˜๋Š” ๋ฌธ์ž์—ด ๋ฐ˜ํ™˜"""
468
  if 'get_multiplication_table' in func:
@@ -499,6 +431,323 @@ def get_component_description(component: str) -> str:
499
  return descriptions.get(component, '์ปดํฌ๋„ŒํŠธ ์„ค๋ช…')
500
 
501
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
502
 
503
  class Demo:
504
  def __init__(self):
@@ -546,7 +795,7 @@ class Demo:
546
  yield [
547
  code,
548
  _history,
549
- analysis, # ๋ถ„์„ ๊ฒฐ๊ณผ๋ฅผ HTML๋กœ ์ „๋‹ฌ
550
  gr.update(active_key="loading"),
551
  gr.update(open=True)
552
  ]
@@ -562,7 +811,7 @@ class Demo:
562
  yield [
563
  code,
564
  _history,
565
- analysis, # ๋ถ„์„ ๊ฒฐ๊ณผ๋ฅผ HTML๋กœ ์ „๋‹ฌ
566
  gr.update(active_key="loading"),
567
  gr.update(open=True)
568
  ]
@@ -580,7 +829,7 @@ class Demo:
580
  yield [
581
  collected_content,
582
  _history,
583
- analyze_code(collected_content), # ์ตœ์ข… ๋ถ„์„ ๊ฒฐ๊ณผ๋ฅผ HTML๋กœ ์ „๋‹ฌ
584
  gr.update(active_key="render"),
585
  gr.update(open=True)
586
  ]
@@ -594,49 +843,9 @@ class Demo:
594
  def clear_history(self):
595
  return []
596
 
597
- def remove_code_block(text):
598
- # Remove markdown code block syntax
599
- text = re.sub(r'```[python|html]?\n', '', text)
600
- text = re.sub(r'\n```', '', text)
601
-
602
- # Remove duplicate imports and launch configurations
603
- lines = text.split('\n')
604
- filtered_lines = []
605
- seen_imports = set()
606
-
607
- for line in lines:
608
- # Skip empty lines
609
- if not line.strip():
610
- continue
611
-
612
- # Skip duplicate imports
613
- if line.startswith('import ') or line.startswith('from '):
614
- import_key = line.split('#')[0].strip()
615
- if import_key in seen_imports:
616
- continue
617
- seen_imports.add(import_key)
618
-
619
- # Skip duplicate launch configurations
620
- if 'if __name__ == "__main__":' in line:
621
- continue
622
- if 'demo.launch()' in line:
623
- continue
624
-
625
- filtered_lines.append(line)
626
-
627
- return '\n'.join(filtered_lines)
628
-
629
- def history_render(history: History):
630
- return gr.update(open=True), history
631
-
632
- def send_to_sandbox(code):
633
- encoded_html = base64.b64encode(code.encode('utf-8')).decode('utf-8')
634
- data_uri = f"data:text/html;charset=utf-8;base64,{encoded_html}"
635
- return f"<iframe src=\"{data_uri}\" width=\"100%\" height=\"920px\"></iframe>"
636
 
637
-
638
-
639
- theme = gr.themes.Soft()
640
 
641
  def load_json_data():
642
  return [
@@ -951,20 +1160,18 @@ def create_template_html(title, items):
951
  padding: 8px;
952
  border-radius: 4px;
953
  }
 
 
 
 
 
 
954
  </style>
955
- <div class="prompt-grid">
956
- """
957
-
958
- for item in items:
959
- html_content += f"""
960
- <div class="prompt-card" onclick="copyToInput(this)" data-prompt="{html.escape(item.get('prompt', ''))}">
961
- <img src="{item.get('image_url', '')}" class="card-image" loading="lazy" alt="{html.escape(item.get('name', ''))}">
962
- <div class="card-name">{html.escape(item.get('name', ''))}</div>
963
- <div class="card-prompt">{html.escape(item.get('prompt', ''))}</div>
964
- </div>
965
- """
966
-
967
- html_content += """
968
  <script>
969
  function copyToInput(card) {
970
  const prompt = card.dataset.prompt;
@@ -975,14 +1182,37 @@ def create_template_html(title, items):
975
  document.querySelector('.session-drawer .close-btn').click();
976
  }
977
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
978
  </script>
979
- </div>
980
  """
981
- return gr.HTML(value=html_content)
982
 
983
-
984
- # ์ „์—ญ ๋ณ€์ˆ˜๋กœ ํ…œํ”Œ๋ฆฟ ๋ฐ์ดํ„ฐ ์บ์‹œ
985
- TEMPLATE_CACHE = None
 
 
 
 
 
 
 
 
 
 
986
 
987
  def load_session_history(template_type="best"):
988
  global TEMPLATE_CACHE
@@ -1150,10 +1380,6 @@ def load_session_history(template_type="best"):
1150
  print(f"Error in load_session_history: {str(e)}")
1151
  return gr.HTML("Error loading templates")
1152
 
1153
-
1154
-
1155
-
1156
-
1157
  # ๋ฐฐํฌ ๊ด€๋ จ ํ•จ์ˆ˜ ์ถ”๊ฐ€
1158
  def generate_space_name():
1159
  """6์ž๋ฆฌ ๋žœ๋ค ์˜๋ฌธ ์ด๋ฆ„ ์ƒ์„ฑ"""
@@ -1217,7 +1443,7 @@ def deploy_to_huggingface(code: str):
1217
 
1218
  # ๊ธฐ๋ณธ requirements ์„ค์ •
1219
  default_requirements = [
1220
- 'gradio==5.5.0',
1221
  'huggingface_hub',
1222
  'transformers',
1223
  'torch',
@@ -1243,7 +1469,6 @@ def deploy_to_huggingface(code: str):
1243
  if requirements:
1244
  for req in requirements.split('\n'):
1245
  if req.strip():
1246
- pkg_name = req.split('==')[0] if '==' in req else req
1247
  final_requirements.add(req.strip())
1248
 
1249
  # ๊ธฐ๋ณธ requirements ์ถ”๊ฐ€ (์—†๋Š” ๊ฒƒ๋งŒ)
@@ -1272,7 +1497,6 @@ def deploy_to_huggingface(code: str):
1272
  # Demo ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
1273
  demo_instance = Demo()
1274
 
1275
-
1276
  with gr.Blocks(css_paths="app.css",theme=theme) as demo:
1277
  history = gr.State([])
1278
  setting = gr.State({
@@ -1309,32 +1533,29 @@ with gr.Blocks(css_paths="app.css",theme=theme) as demo:
1309
  # ๋ฉ”์ธ ์ปจํ…์ธ ๋ฅผ ์œ„ํ•œ Row
1310
  with antd.Row(gutter=[32, 12]) as layout:
1311
  # ์ขŒ์ธก ํŒจ๋„
1312
-
1313
- # ์ขŒ์ธก ํŒจ๋„ ๋ถ€๋ถ„์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ •
1314
  with antd.Col(span=24, md=8):
1315
  with antd.Flex(vertical=True, gap="middle", wrap=True):
1316
  header = gr.HTML(f"""
1317
- <div class="left_header">
1318
- <img src="data:image/gif;base64,{get_image_base64('mouse.gif')}" width="360px" />
1319
- <h1 style="font-size: 18px;">๊ณ ์–‘์ด๋„ ๋ฐœ๋กœ ์ฝ”๋”ฉํ•˜๋Š” 'MOUSE-II'</h2>
1320
- <h1 style="font-size: 10px;">ํ…œํ”Œ๋ฆฟ์˜ ํ”„๋กฌํ”„ํŠธ ๋‚ด์šฉ์„ ๋ณต์‚ฌํ•ด ํ”„๋กฌํ”„ํŠธ์— ์ž…๋ ฅ 'Send'๋ฒ„ํŠผ ํด๋ฆญ -> '์‹คํ–‰ํ•˜๊ธฐ' ๋ฒ„ํŠผ ํด๋ฆญํ•˜์—ฌ ์ฝ”๋“œ ์‹คํ–‰. ๋ฌธ์˜: [email protected] </h2>
1321
- </div>
1322
- """)
 
1323
  input = antd.InputTextarea(
1324
  size="large",
1325
  allow_clear=True,
1326
  placeholder=random.choice(DEMO_LIST)['description']
1327
  )
1328
 
1329
-
1330
- # UI ์ˆ˜์ • ๋ถ€๋ถ„ - antd.Col(span=24, md=8) ๋‚ด๋ถ€์˜ ๋ฒ„ํŠผ ์ปจํ…Œ์ด๋„ˆ์— ๋ฐฐํฌ ๋ฒ„ํŠผ ์ถ”๊ฐ€:
1331
  with antd.Flex(gap="small", justify="space-between"):
1332
  btn = antd.Button("Send", type="primary", size="large")
1333
- deploy_btn = antd.Button("์‹คํ–‰ํ•˜๊ธฐ", type="default", size="large") # ์ถ”๊ฐ€
1334
- clear_btn = antd.Button("Clear", type="default", size="large")
 
 
1335
 
1336
- # ๋ฐฐํฌ ๊ฒฐ๊ณผ๋ฅผ ๏ฟฝ๏ฟฝ์‹œํ•  ํ…์ŠคํŠธ ์˜์—ญ ์ถ”๊ฐ€
1337
-
1338
  deploy_result = gr.HTML(label="๋ฐฐํฌ ๊ฒฐ๊ณผ")
1339
 
1340
  with antd.Col(span=24, md=16):
@@ -1342,14 +1563,12 @@ with gr.Blocks(css_paths="app.css",theme=theme) as demo:
1342
  with antd.Flex(gap="small", elem_classes="setting-buttons"):
1343
  codeBtn = antd.Button("๐Ÿง‘โ€๐Ÿ’ป ์ฝ”๋“œ ๋ณด๊ธฐ", type="default")
1344
  historyBtn = antd.Button("๐Ÿ“œ ํžˆ์Šคํ† ๋ฆฌ", type="default")
1345
- best_btn = antd.Button("๐Ÿ† ๊ธฐ๋ณธ ํ…œํ”Œ๋ฆฟ", type="default")
1346
- trending_btn = antd.Button("๐Ÿ”ฅ ์‘์šฉ ํ…œํ”Œ๋ฆฟ", type="default")
1347
- new_btn = antd.Button("โœจ ํ™œ์šฉ ํ…œํ”Œ๋ฆฟ", type="default")
1348
 
1349
  gr.HTML('<div class="render_header"><span class="header_btn"></span><span class="header_btn"></span><span class="header_btn"></span></div>')
1350
 
1351
-
1352
-
1353
  with antd.Tabs(active_key="empty", render_tab_bar="() => null") as state_tab:
1354
  with antd.Tabs.Item(key="empty"):
1355
  empty = antd.Empty(description="empty input", elem_classes="right_content")
@@ -1358,27 +1577,36 @@ with gr.Blocks(css_paths="app.css",theme=theme) as demo:
1358
  with antd.Tabs.Item(key="render"):
1359
  sandbox = gr.HTML(elem_classes="html_content")
1360
 
1361
- # Code ์‹คํ–‰ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ํ•จ์ˆ˜ ์ •์˜
1362
- def execute_code(query: str):
1363
- if not query or query.strip() == '':
1364
- return None, gr.update(active_key="empty")
1365
-
1366
- try:
1367
- # HTML ์ฝ”๋“œ ๋ธ”๋ก ํ™•์ธ
1368
- if '```html' in query and '```' in query:
1369
- # HTML ์ฝ”๋“œ ๋ธ”๋ก ์ถ”์ถœ
1370
- code = remove_code_block(query)
1371
- else:
1372
- # ์ž…๋ ฅ๋œ ํ…์ŠคํŠธ๋ฅผ ๊ทธ๋Œ€๋กœ ์ฝ”๋“œ๋กœ ์‚ฌ์šฉ
1373
- code = query.strip()
1374
-
1375
- return send_to_sandbox(code), gr.update(active_key="render")
1376
- except Exception as e:
1377
- print(f"Error executing code: {str(e)}")
1378
- return None, gr.update(active_key="empty")
1379
-
1380
- # ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋“ค
 
 
 
 
1381
 
 
 
 
 
 
1382
 
1383
  codeBtn.click(
1384
  lambda: gr.update(open=True),
@@ -1404,7 +1632,6 @@ with gr.Blocks(css_paths="app.css",theme=theme) as demo:
1404
  outputs=[history_drawer]
1405
  )
1406
 
1407
- # ํ…œํ”Œ๋ฆฟ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ
1408
  best_btn.click(
1409
  fn=lambda: (gr.update(open=True), load_best_templates()),
1410
  outputs=[session_drawer, session_history],
@@ -1433,26 +1660,6 @@ with gr.Blocks(css_paths="app.css",theme=theme) as demo:
1433
  outputs=[session_drawer, session_history]
1434
  )
1435
 
1436
- btn.click(
1437
- demo_instance.generation_code,
1438
- inputs=[input, setting, history],
1439
- outputs=[code_output, history, sandbox, state_tab, code_drawer]
1440
- )
1441
-
1442
- clear_btn.click(
1443
- demo_instance.clear_history,
1444
- inputs=[],
1445
- outputs=[history]
1446
- )
1447
-
1448
- # ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ์ถ”๊ฐ€
1449
- deploy_btn.click(
1450
- fn=lambda code: deploy_to_huggingface(remove_code_block(code)) if code else "์ฝ”๋“œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.",
1451
- inputs=[code_output],
1452
- outputs=[deploy_result]
1453
- )
1454
-
1455
-
1456
  if __name__ == "__main__":
1457
  try:
1458
  demo_instance = Demo()
@@ -1460,4 +1667,3 @@ if __name__ == "__main__":
1460
  except Exception as e:
1461
  print(f"Initialization error: {e}")
1462
  raise
1463
-
 
1
+ # ๊ฐœ์„  ์•„์ด๋””์–ด (ํ•œ๊ธ€):
2
+ # 1. ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง(์˜ˆ: API ํ˜ธ์ถœ, ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜)๊ณผ UI ๊ตฌ์„ฑ์„ ๋ถ„๋ฆฌํ•˜์—ฌ ์ฝ”๋“œ ๊ตฌ์กฐ๋ฅผ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์œ ์ง€ํ•˜์„ธ์š”.
3
+ # 2. ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๊ตฌ๊ฐ„์—์„œ ๊ตฌ์ฒด์ ์ธ ์˜ˆ์™ธ ํƒ€์ž…(ValueError, TimeoutError ๋“ฑ)์„ ์‚ฌ์šฉํ•˜๊ณ  logging ๋ชจ๋“ˆ์„ ํ™œ์šฉํ•ด ๋””๋ฒ„๊น…๊ณผ ์œ ์ง€๋ณด์ˆ˜๋ฅผ ๊ฐœ์„ ํ•˜์„ธ์š”.
4
+ # 3. ๋ฐฐํฌ์™€ ๊ด€๋ จ๋œ ๋ฏผ๊ฐํ•œ ํ† ํฐ์ด๋‚˜ ํ‚ค๋Š” ์ ˆ๋Œ€๋กœ ์ฝ”๋“œ์— ์ง์ ‘ ์ž‘์„ฑํ•˜์ง€ ๋ง๊ณ  ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋‚˜ ์•ˆ์ „ํ•œ ์„ค์ • ํŒŒ์ผ์„ ํ†ตํ•ด ๊ด€๋ฆฌํ•˜์„ธ์š”.
5
+ # 4. ๋ฐ˜๋ณต๋˜๋Š” ์ฝ”๋“œ(์˜ˆ: load_json_data, create_template_html ๋“ฑ)๋ฅผ ํ†ตํ•ฉํ•˜๊ฑฐ๋‚˜ ์ž‘์€ ํ•จ์ˆ˜๋กœ ๋‚˜๋ˆ„์–ด ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์ด์„ธ์š”.
6
+ # 5. ๋Œ€๊ทœ๋ชจ ํ•จ์ˆ˜๋ฅผ ์ž‘์€ ๊ธฐ๋Šฅ ๋‹จ์œ„๋กœ ๋ถ„๋ฆฌํ•ด ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ํ–ฅ์ƒ์‹œํ‚ค๊ณ , ํ•จ์ˆ˜๋งˆ๋‹ค ๋ช…ํ™•ํ•œ ์ฃผ์„๊ณผ ํƒ€์ž… ํžŒํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜์„ธ์š”.
7
+ # 6. ์™ธ๋ถ€ API ํ˜ธ์ถœ ์‹œ asyncio์™€ aiohttp ๋“ฑ์„ ์ ์šฉํ•ด ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ํ†ตํ•ด ๋” ๋‚˜์€ ์‘๋‹ต ์‹œ๊ฐ„์„ ์ง€์›ํ•˜๋„๋ก ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
8
+ # 7. ํ™˜๊ฒฝ์„ค์ •(ํ…Œ๋งˆ, CSS, HTML ํ…œํ”Œ๋ฆฟ ๋“ฑ)์„ ๋ณ„๋„์˜ ํŒŒ์ผ์ด๋‚˜ ์ƒ์ˆ˜๋กœ ๊ด€๋ฆฌํ•˜์—ฌ ์ฝ”๋“œ ๋ณธ๋ฌธ ๊ฐ€๋…์„ฑ์„ ๋†’์ด์„ธ์š”.
9
+ # 8. ์‚ฌ์šฉ์ž ์ž…๋ ฅ์— ๋Œ€ํ•œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์™€ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ๊ฐ•ํ™”ํ•˜์—ฌ, ๋ถˆ์™„์ „ํ•œ ์ž…๋ ฅ์ด ๋“ค์–ด์™€๋„ ํ”„๋กœ๊ทธ๋žจ์ด ์•ˆ์ „ํ•˜๊ฒŒ ๋™์ž‘ํ•˜๋„๋ก ๊ฐœ์„ ํ•˜์„ธ์š”.
10
+ # 9. ์ฃผ์š” ํ•จ์ˆ˜์— ๋Œ€ํ•œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ, ์ˆ˜์ • ์‹œ ๊ธฐ๋Šฅ์ด ์ •์ƒ ๋™์ž‘ํ•˜๋Š”์ง€ ์‰ฝ๊ฒŒ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์„ธ์š”.
11
+ # 10. Gradio ๋ฒ„์ „์„ 5.6.0์œผ๋กœ ๋ช…์‹œํ•˜์—ฌ, ์‹œ์Šคํ…œ ์š”๊ตฌ์‚ฌํ•ญ ๋ฐ ํ˜ธํ™˜์„ฑ์„ ๋ณด์žฅํ•˜์„ธ์š”.
12
+
13
  import os
14
  import re
15
  import random
 
32
  from huggingface_hub import HfApi, create_repo
33
  import string
34
  import random
35
+ import requests
36
 
37
+ # SystemPrompt ์ •์˜
38
  SystemPrompt = """๋„ˆ์˜ ์ด๋ฆ„์€ 'MOUSE'์ด๋‹ค. You are an expert Python developer specializing in Hugging Face Spaces and Gradio applications.
39
  Your task is to create functional and aesthetically pleasing web applications using Python, Gradio, and Hugging Face integration.
40
 
 
98
 
99
  class Role:
100
  SYSTEM = "system"
101
+ USER = "user"
102
  ASSISTANT = "assistant"
103
 
104
  History = List[Tuple[str, str]]
105
  Messages = List[Dict[str, str]]
106
 
107
+ # ์ด๋ฏธ์ง€ ์บ์‹œ
108
  IMAGE_CACHE = {}
109
 
110
  def get_image_base64(image_path):
111
+ # Improvement: Consider adding logging and handling specific exceptions
112
  if image_path in IMAGE_CACHE:
113
  return IMAGE_CACHE[image_path]
114
  try:
 
116
  encoded_string = base64.b64encode(image_file.read()).decode()
117
  IMAGE_CACHE[image_path] = encoded_string
118
  return encoded_string
119
+ except Exception as e:
120
+ # TODO: Log exception details
121
  return IMAGE_CACHE.get('default.png', '')
122
+
123
  def history_to_messages(history: History, system: str) -> Messages:
124
  messages = [{'role': Role.SYSTEM, 'content': system}]
125
  for h in history:
 
141
  claude_client = anthropic.Anthropic(api_key=YOUR_ANTHROPIC_TOKEN)
142
  openai_client = openai.OpenAI(api_key=YOUR_OPENAI_TOKEN)
143
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  # Built-in modules that don't need to be in requirements.txt
145
  BUILTIN_MODULES = {
146
  'os', 'sys', 're', 'time', 'json', 'csv', 'math', 'random', 'datetime', 'calendar',
 
291
 
292
  def get_package_name(import_name):
293
  """์ž„ํฌํŠธ๋ช…์œผ๋กœ๋ถ€ํ„ฐ ์‹ค์ œ ํŒจํ‚ค์ง€๋ช…์„ ๋ฐ˜ํ™˜"""
 
294
  if import_name in BUILTIN_MODULES:
295
  return None
 
 
296
  base_import = import_name.split('.')[0]
 
 
297
  if base_import in BUILTIN_MODULES:
298
  return None
 
299
  return IMPORT_TO_PACKAGE.get(base_import, base_import)
 
 
300
 
301
  def analyze_code(code: str) -> str:
302
  """์ฝ”๋“œ ๋ถ„์„ ๊ฒฐ๊ณผ๋ฅผ HTML ํ˜•์‹์œผ๋กœ ๋ฐ˜ํ™˜"""
 
320
  for line in code.split('\n'):
321
  if line.startswith('import ') or line.startswith('from '):
322
  imports.append(line.strip())
 
323
  if line.startswith('import '):
324
  package = line.split('import ')[1].split()[0].split('.')[0]
325
  else:
326
  package = line.split('from ')[1].split()[0].split('.')[0]
327
 
 
328
  package_name = get_package_name(package)
329
+ if package_name:
330
  required_packages.add(package_name)
331
 
332
  if imports:
 
336
  analysis.append(f"<li><code>{imp}</code></li>")
337
  analysis.append("</ul>")
338
 
 
339
  analysis.append("<h3>๐Ÿ“‹ Requirements.txt</h3>")
340
  analysis.append("<p>์ด ์•ฑ์„ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ํŒจํ‚ค์ง€๋“ค์ž…๋‹ˆ๋‹ค:</p>")
341
  analysis.append("<pre>")
342
  for pkg in sorted(required_packages):
343
+ if pkg and pkg not in BUILTIN_MODULES:
344
+ analysis.append(pkg)
 
 
 
345
  analysis.append("</pre>")
346
 
347
  # 2. ํ•จ์ˆ˜ ๋ถ„์„
 
364
  current_func = []
365
 
366
  if functions:
367
+ analysis.append("<h2>๐Ÿ”ง ์ฃผ์š” ํ•จ์ˆ˜</h2>")
368
  for func in functions:
369
  func_name = func.split('def ')[1].split('(')[0]
370
  analysis.append(f"<h3><code>{func_name}</code></h3>")
 
 
371
  params = func.split('(')[1].split(')')[0]
372
  if params.strip():
373
  analysis.append("<p>ํŒŒ๋ผ๋ฏธํ„ฐ:</p><ul>")
 
387
 
388
  if ui_components:
389
  analysis.append("<h2>๐ŸŽจ UI ๊ตฌ์„ฑ์š”์†Œ</h2>")
 
390
  analysis.append("<ul>")
391
  for component in ui_components:
392
+ analysis.append(f"<li><strong>{component}</strong></li>")
393
  analysis.append("</ul>")
394
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
395
  return "\n".join(analysis)
396
 
397
+
398
  def get_function_description(func: str) -> str:
399
  """ํ•จ์ˆ˜์˜ ๋ชฉ์ ์„ ์„ค๋ช…ํ•˜๋Š” ๋ฌธ์ž์—ด ๋ฐ˜ํ™˜"""
400
  if 'get_multiplication_table' in func:
 
431
  return descriptions.get(component, '์ปดํฌ๋„ŒํŠธ ์„ค๋ช…')
432
 
433
 
434
+ async def try_claude_api(system_message, claude_messages, timeout=15):
435
+ try:
436
+ start_time = time.time()
437
+ with claude_client.messages.stream(
438
+ model="claude-3-5-sonnet-20241022",
439
+ max_tokens=7800,
440
+ system=system_message,
441
+ messages=claude_messages
442
+ ) as stream:
443
+ collected_content = ""
444
+ for chunk in stream:
445
+ current_time = time.time()
446
+ if current_time - start_time > timeout:
447
+ print(f"Claude API response time: {current_time - start_time:.2f} seconds")
448
+ raise TimeoutError("Claude API timeout")
449
+ if chunk.type == "content_block_delta":
450
+ collected_content += chunk.delta.text
451
+ yield collected_content
452
+ await asyncio.sleep(0)
453
+
454
+ start_time = current_time
455
+
456
+ except Exception as e:
457
+ print(f"Claude API error: {str(e)}")
458
+ raise e
459
+
460
+ async def try_openai_api(openai_messages):
461
+ try:
462
+ stream = openai_client.chat.completions.create(
463
+ model="gpt-4",
464
+ messages=openai_messages,
465
+ stream=True,
466
+ max_tokens=4096,
467
+ temperature=0.7
468
+ )
469
+
470
+ collected_content = ""
471
+ for chunk in stream:
472
+ if chunk.choices[0].delta.content is not None:
473
+ collected_content += chunk.choices[0].delta.content
474
+ yield collected_content
475
+
476
+ except Exception as e:
477
+ print(f"OpenAI API error: {str(e)}")
478
+ raise e
479
+
480
+ def deploy_to_vercel(code: str):
481
+ try:
482
+ token = "A8IFZmgW2cqA4yUNlLPnci0N" # Improvement: Do not hardcode tokens; use environment variables.
483
+ if not token:
484
+ return "Vercel ํ† ํฐ์ด ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค."
485
+
486
+ project_name = ''.join(random.choice(string.ascii_lowercase) for i in range(6))
487
+ deploy_url = "https://api.vercel.com/v13/deployments"
488
+
489
+ headers = {
490
+ "Authorization": f"Bearer {token}",
491
+ "Content-Type": "application/json"
492
+ }
493
+
494
+ package_json = {
495
+ "name": project_name,
496
+ "version": "1.0.0",
497
+ "private": True,
498
+ "dependencies": {
499
+ "vite": "^5.0.0"
500
+ },
501
+ "scripts": {
502
+ "dev": "vite",
503
+ "build": "echo 'No build needed' && mkdir -p dist && cp index.html dist/",
504
+ "preview": "vite preview"
505
+ }
506
+ }
507
+
508
+ files = [
509
+ {
510
+ "file": "index.html",
511
+ "data": code
512
+ },
513
+ {
514
+ "file": "package.json",
515
+ "data": json.dumps(package_json, indent=2)
516
+ }
517
+ ]
518
+
519
+ project_settings = {
520
+ "buildCommand": "npm run build",
521
+ "outputDirectory": "dist",
522
+ "installCommand": "npm install",
523
+ "framework": None
524
+ }
525
+
526
+ deploy_data = {
527
+ "name": project_name,
528
+ "files": files,
529
+ "target": "production",
530
+ "projectSettings": project_settings
531
+ }
532
+
533
+ deploy_response = requests.post(deploy_url, headers=headers, json=deploy_data)
534
+
535
+ if deploy_response.status_code != 200:
536
+ return f"๋ฐฐํฌ ์‹คํŒจ: {deploy_response.text}"
537
+
538
+ deployment_url = f"{project_name}.vercel.app"
539
+ time.sleep(5)
540
+
541
+ return f"""๋ฐฐํฌ ์™„๋ฃŒ! <a href="https://{deployment_url}" target="_blank" style="color: #1890ff; text-decoration: underline; cursor: pointer;">https://{deployment_url}</a>"""
542
+
543
+ except Exception as e:
544
+ return f"๋ฐฐํฌ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
545
+
546
+ def boost_prompt(prompt: str) -> str:
547
+ if not prompt:
548
+ return ""
549
+
550
+ boost_system_prompt = """
551
+ ๋‹น์‹ ์€ Gradio ์›น์•ฑ ๊ฐœ๋ฐœ ํ”„๋กฌํ”„ํŠธ ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค.
552
+ ์ฃผ์–ด์ง„ ํ”„๋กฌํ”„ํŠธ๋ฅผ ๋ถ„์„ํ•˜์—ฌ ๋” ์ƒ์„ธํ•˜๊ณ  ์ „๋ฌธ์ ์ธ ์š”๊ตฌ์‚ฌํ•ญ์œผ๋กœ ํ™•์žฅํ•˜๋˜,
553
+ ์›๋ž˜ ์˜๋„์™€ ๋ชฉ์ ์€ ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•˜๋ฉด์„œ ๋‹ค์Œ ๊ด€์ ๋“ค์„ ๊ณ ๋ คํ•˜์—ฌ ์ฆ๊ฐ•ํ•˜์‹ญ์‹œ์˜ค:
554
+
555
+ 1. UI/UX ๋””์ž์ธ ์š”์†Œ
556
+ 2. Gradio ์ปดํฌ๋„ŒํŠธ ํ™œ์šฉ
557
+ 3. ์‚ฌ์šฉ์ž ๊ฒฝํ—˜ ์ตœ์ ํ™”
558
+ 4. ์„ฑ๋Šฅ๊ณผ ๋ณด์•ˆ
559
+ 5. ์ ‘๊ทผ์„ฑ๊ณผ ํ˜ธํ™˜์„ฑ
560
+
561
+ ๊ธฐ์กด SystemPrompt์˜ ๋ชจ๋“  ๊ทœ์น™์„ ์ค€์ˆ˜ํ•˜๋ฉด์„œ ์ฆ๊ฐ•๋œ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ƒ์„ฑํ•˜์‹ญ์‹œ์˜ค.
562
+ """
563
+
564
+ try:
565
+ try:
566
+ response = claude_client.messages.create(
567
+ model="claude-3-5-sonnet-20241022",
568
+ max_tokens=2000,
569
+ messages=[{
570
+ "role": "user",
571
+ "content": f"๋‹ค์Œ ํ”„๋กฌํ”„ํŠธ๋ฅผ ๋ถ„์„ํ•˜๊ณ  ์ฆ๊ฐ•ํ•˜์‹œ์˜ค: {prompt}"
572
+ }]
573
+ )
574
+
575
+ if hasattr(response, 'content') and len(response.content) > 0:
576
+ return response.content[0].text
577
+ raise Exception("Claude API ์‘๋‹ต ํ˜•์‹ ์˜ค๋ฅ˜")
578
+
579
+ except Exception as claude_error:
580
+ print(f"Claude API ์—๋Ÿฌ, OpenAI๋กœ ์ „ํ™˜: {str(claude_error)}")
581
+
582
+ completion = openai_client.chat.completions.create(
583
+ model="gpt-4",
584
+ messages=[
585
+ {"role": "system", "content": boost_system_prompt},
586
+ {"role": "user", "content": f"๋‹ค์Œ ํ”„๋กฌํ”„ํŠธ๋ฅผ ๋ถ„์„ํ•˜๊ณ  ์ฆ๊ฐ•ํ•˜์‹œ์˜ค: {prompt}"}
587
+ ],
588
+ max_tokens=2000,
589
+ temperature=0.7
590
+ )
591
+
592
+ if completion.choices and len(completion.choices) > 0:
593
+ return completion.choices[0].message.content
594
+ raise Exception("OpenAI API ์‘๋‹ต ํ˜•์‹ ์˜ค๋ฅ˜")
595
+
596
+ except Exception as e:
597
+ print(f"ํ”„๋กฌํ”„ํŠธ ์ฆ๊ฐ• ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}")
598
+ return prompt
599
+
600
+ def handle_boost(prompt: str):
601
+ try:
602
+ boosted_prompt = boost_prompt(prompt)
603
+ return boosted_prompt, gr.update(active_key="empty")
604
+ except Exception as e:
605
+ print(f"Boost ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜: {str(e)}")
606
+ return prompt, gr.update(active_key="empty")
607
+
608
+ def execute_code(query: str):
609
+ if not query or query.strip() == '':
610
+ return None, gr.update(active_key="empty")
611
+
612
+ try:
613
+ if '```html' in query and '```' in query:
614
+ code = remove_code_block(query)
615
+ else:
616
+ code = query.strip()
617
+
618
+ return send_to_sandbox(code), gr.update(active_key="render")
619
+ except Exception as e:
620
+ print(f"Error executing code: {str(e)}")
621
+ return None, gr.update(active_key="empty")
622
+
623
+ def remove_code_block(text):
624
+ text = re.sub(r'```[python|html]?\n', '', text)
625
+ text = re.sub(r'\n```', '', text)
626
+
627
+ lines = text.split('\n')
628
+ filtered_lines = []
629
+ seen_imports = set()
630
+
631
+ for line in lines:
632
+ if not line.strip():
633
+ continue
634
+
635
+ if line.startswith('import ') or line.startswith('from '):
636
+ import_key = line.split('#')[0].strip()
637
+ if import_key in seen_imports:
638
+ continue
639
+ seen_imports.add(import_key)
640
+
641
+ if 'if __name__ == "__main__":' in line:
642
+ continue
643
+ if 'demo.launch()' in line:
644
+ continue
645
+
646
+ filtered_lines.append(line)
647
+
648
+ return '\n'.join(filtered_lines)
649
+
650
+ def history_render(history: History):
651
+ return gr.update(open=True), history
652
+
653
+ def send_to_sandbox(code):
654
+ encoded_html = base64.b64encode(code.encode('utf-8')).decode('utf-8')
655
+ data_uri = f"data:text/html;charset=utf-8;base64,{encoded_html}"
656
+ return f"<iframe src=\"{data_uri}\" width=\"100%\" height=\"920px\"></iframe>"
657
+
658
+ def load_json_data():
659
+ # ํ…œํ”Œ๋ฆฟ ๋ฐ์ดํ„ฐ ๋ฐ˜ํ™˜
660
+ return [
661
+ # ... (์ด์ „์— ์ •์˜๋œ ํ…œํ”Œ๋ฆฟ ๋ฐ์ดํ„ฐ)
662
+ ]
663
+
664
+ def load_best_templates():
665
+ json_data = load_json_data()[:12]
666
+ return create_template_html("๐Ÿ† ๋ฒ ์ŠคํŠธ ํ…œํ”Œ๋ฆฟ", json_data)
667
+
668
+ def load_trending_templates():
669
+ json_data = load_json_data()[12:24]
670
+ return create_template_html("๐Ÿ”ฅ ํŠธ๋ Œ๋”ฉ ํ…œํ”Œ๋ฆฟ", json_data)
671
+
672
+ def load_new_templates():
673
+ json_data = load_json_data()[24:44]
674
+ return create_template_html("โœจ NEW ํ…œํ”Œ๋ฆฟ", json_data)
675
+
676
+ def create_template_html(title, items):
677
+ html_content = """
678
+ <style>
679
+ .prompt-grid {
680
+ display: grid;
681
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
682
+ gap: 20px;
683
+ padding: 20px;
684
+ }
685
+ .prompt-card {
686
+ background: white;
687
+ border: 1px solid #eee;
688
+ border-radius: 8px;
689
+ padding: 15px;
690
+ cursor: pointer;
691
+ box-shadow: 0 2px 5px rgba(0,0,0,0.1);
692
+ }
693
+ .prompt-card:hover {
694
+ transform: translateY(-2px);
695
+ transition: transform 0.2s;
696
+ }
697
+ .card-image {
698
+ width: 100%;
699
+ height: 180px;
700
+ object-fit: cover;
701
+ border-radius: 4px;
702
+ margin-bottom: 10px;
703
+ }
704
+ .card-name {
705
+ font-weight: bold;
706
+ margin-bottom: 8px;
707
+ font-size: 16px;
708
+ color: #333;
709
+ }
710
+ .card-prompt {
711
+ font-size: 11px;
712
+ line-height: 1.4;
713
+ color: #666;
714
+ display: -webkit-box;
715
+ -webkit-line-clamp: 6;
716
+ -webkit-box-orient: vertical;
717
+ overflow: hidden;
718
+ height: 90px;
719
+ background-color: #f8f9fa;
720
+ padding: 8px;
721
+ border-radius: 4px;
722
+ }
723
+ </style>
724
+ <div class="prompt-grid">
725
+ """
726
+
727
+ for item in items:
728
+ html_content += f"""
729
+ <div class="prompt-card" onclick="copyToInput(this)" data-prompt="{html.escape(item.get('prompt', ''))}">
730
+ <img src="{item.get('image_url', '')}" class="card-image" loading="lazy" alt="{html.escape(item.get('name', ''))}">
731
+ <div class="card-name">{html.escape(item.get('name', ''))}</div>
732
+ <div class="card-prompt">{html.escape(item.get('prompt', ''))}</div>
733
+ </div>
734
+ """
735
+
736
+ html_content += """
737
+ <script>
738
+ function copyToInput(card) {
739
+ const prompt = card.dataset.prompt;
740
+ const textarea = document.querySelector('.ant-input-textarea-large textarea');
741
+ if (textarea) {
742
+ textarea.value = prompt;
743
+ textarea.dispatchEvent(new Event('input', { bubbles: true }));
744
+ document.querySelector('.session-drawer .close-btn').click();
745
+ }
746
+ }
747
+ </script>
748
+ </div>
749
+ """
750
+ return gr.HTML(value=html_content)
751
 
752
  class Demo:
753
  def __init__(self):
 
795
  yield [
796
  code,
797
  _history,
798
+ analysis,
799
  gr.update(active_key="loading"),
800
  gr.update(open=True)
801
  ]
 
811
  yield [
812
  code,
813
  _history,
814
+ analysis,
815
  gr.update(active_key="loading"),
816
  gr.update(open=True)
817
  ]
 
829
  yield [
830
  collected_content,
831
  _history,
832
+ analyze_code(collected_content),
833
  gr.update(active_key="render"),
834
  gr.update(open=True)
835
  ]
 
843
  def clear_history(self):
844
  return []
845
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
846
 
847
+ # theme = gr.themes.Soft()
848
+ theme='earneleh/paris'
 
849
 
850
  def load_json_data():
851
  return [
 
1160
  padding: 8px;
1161
  border-radius: 4px;
1162
  }
1163
+ .template-section {
1164
+ display: none;
1165
+ }
1166
+ .template-section.active {
1167
+ display: block;
1168
+ }
1169
  </style>
1170
+ <div class="template-nav">
1171
+ <button class="template-btn" onclick="showTemplate('best')">๐Ÿ† ๋ฒ ์ŠคํŠธ</button>
1172
+ <button class="template-btn" onclick="showTemplate('trending')">๐Ÿ”ฅ ํŠธ๋ Œ๋”ฉ</button>
1173
+ <button class="template-btn" onclick="showTemplate('new')">โœจ NEW</button>
1174
+ </div>
 
 
 
 
 
 
 
 
1175
  <script>
1176
  function copyToInput(card) {
1177
  const prompt = card.dataset.prompt;
 
1182
  document.querySelector('.session-drawer .close-btn').click();
1183
  }
1184
  }
1185
+
1186
+ function showTemplate(type) {
1187
+ document.querySelectorAll('.template-section').forEach(section => {
1188
+ section.style.display = 'none';
1189
+ });
1190
+ document.querySelectorAll('.template-btn').forEach(btn => {
1191
+ btn.classList.remove('active');
1192
+ });
1193
+ document.getElementById(type + '-templates').style.display = 'block';
1194
+ event.target.classList.add('active');
1195
+ }
1196
+ document.addEventListener('DOMContentLoaded', function() {
1197
+ showTemplate('best');
1198
+ document.querySelector('.template-btn').classList.add('active');
1199
+ });
1200
  </script>
 
1201
  """
 
1202
 
1203
+ # ํƒญ๋ณ„ ํ…œํ”Œ๋ฆฟ ๋ชฉ๋ก
1204
+ html_content += f'<div id="best-templates" class="template-section">'
1205
+ html_content += '<div class="prompt-grid">'
1206
+ for item in items:
1207
+ html_content += f"""
1208
+ <div class="prompt-card" onclick="copyToInput(this)" data-prompt="{html.escape(item.get('prompt', ''))}">
1209
+ <img src="{item.get('image_url', '')}" class="card-image" loading="lazy" alt="{html.escape(item.get('name', ''))}">
1210
+ <div class="card-name">{html.escape(item.get('name', ''))}</div>
1211
+ <div class="card-prompt">{html.escape(item.get('prompt', ''))}</div>
1212
+ </div>
1213
+ """
1214
+ html_content += '</div></div>'
1215
+ return gr.HTML(value=html_content)
1216
 
1217
  def load_session_history(template_type="best"):
1218
  global TEMPLATE_CACHE
 
1380
  print(f"Error in load_session_history: {str(e)}")
1381
  return gr.HTML("Error loading templates")
1382
 
 
 
 
 
1383
  # ๋ฐฐํฌ ๊ด€๋ จ ํ•จ์ˆ˜ ์ถ”๊ฐ€
1384
  def generate_space_name():
1385
  """6์ž๋ฆฌ ๋žœ๋ค ์˜๋ฌธ ์ด๋ฆ„ ์ƒ์„ฑ"""
 
1443
 
1444
  # ๊ธฐ๋ณธ requirements ์„ค์ •
1445
  default_requirements = [
1446
+ 'gradio==5.6.0',
1447
  'huggingface_hub',
1448
  'transformers',
1449
  'torch',
 
1469
  if requirements:
1470
  for req in requirements.split('\n'):
1471
  if req.strip():
 
1472
  final_requirements.add(req.strip())
1473
 
1474
  # ๊ธฐ๋ณธ requirements ์ถ”๊ฐ€ (์—†๋Š” ๊ฒƒ๋งŒ)
 
1497
  # Demo ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
1498
  demo_instance = Demo()
1499
 
 
1500
  with gr.Blocks(css_paths="app.css",theme=theme) as demo:
1501
  history = gr.State([])
1502
  setting = gr.State({
 
1533
  # ๋ฉ”์ธ ์ปจํ…์ธ ๋ฅผ ์œ„ํ•œ Row
1534
  with antd.Row(gutter=[32, 12]) as layout:
1535
  # ์ขŒ์ธก ํŒจ๋„
 
 
1536
  with antd.Col(span=24, md=8):
1537
  with antd.Flex(vertical=True, gap="middle", wrap=True):
1538
  header = gr.HTML(f"""
1539
+ <div class="left_header">
1540
+ <img src="data:image/gif;base64,{get_image_base64('mouse.gif')}" width="360px" />
1541
+ <h1 style="font-size: 18px;">๊ณ ์–‘์ด๋„ ๋ฐœ๋กœ ์ฝ”๋”ฉํ•˜๋Š” 'MOUSE-II'</h2>
1542
+ <h1 style="font-size: 10px;">ํ…œํ”Œ๋ฆฟ์˜ ํ”„๋กฌํ”„ํŠธ๋ฅผ ๋ณต์‚ฌํ•˜๊ฑฐ๋‚˜ ์›ํ•˜๋Š” ๋‚ด์šฉ์„ ํ”„๋กฌํ”„ํŠธ์— ์ž…๋ ฅํ•˜๊ณ  Boost ๋ฒ„ํŠผ ํด๋ฆญ์‹œ ํ”„๋กฌํ”„ํŠธ ์ฆ๊ฐ•์ด ๋จ. -> ๋ฐฐํฌํ•˜๊ธฐ ํด๋ฆญํ•˜๋ฉด ํ—ˆ๊น…ํŽ˜์ด์Šค๋ฅผ ํ†ตํ•ด ์›น์„œ๋น„์Šค๊ฐ€ ๋ฐฐํฌ๋ฉ๋‹ˆ๋‹ค. ๋ฌธ์˜: [email protected] </h2>
1543
+ </div>
1544
+ """)
1545
+
1546
  input = antd.InputTextarea(
1547
  size="large",
1548
  allow_clear=True,
1549
  placeholder=random.choice(DEMO_LIST)['description']
1550
  )
1551
 
 
 
1552
  with antd.Flex(gap="small", justify="space-between"):
1553
  btn = antd.Button("Send", type="primary", size="large")
1554
+ boost_btn = antd.Button("Boost", type="default", size="large")
1555
+ execute_btn = antd.Button("Code์‹คํ–‰", type="default", size="large")
1556
+ deploy_btn = antd.Button("๋ฐฐํฌ", type="default", size="large")
1557
+ clear_btn = antd.Button("ํด๋ฆฌ์–ด", type="default", size="large")
1558
 
 
 
1559
  deploy_result = gr.HTML(label="๋ฐฐํฌ ๊ฒฐ๊ณผ")
1560
 
1561
  with antd.Col(span=24, md=16):
 
1563
  with antd.Flex(gap="small", elem_classes="setting-buttons"):
1564
  codeBtn = antd.Button("๐Ÿง‘โ€๐Ÿ’ป ์ฝ”๋“œ ๋ณด๊ธฐ", type="default")
1565
  historyBtn = antd.Button("๐Ÿ“œ ํžˆ์Šคํ† ๋ฆฌ", type="default")
1566
+ best_btn = antd.Button("๐Ÿ† ๋ฒ ์ŠคํŠธ ํ…œํ”Œ๋ฆฟ", type="default")
1567
+ trending_btn = antd.Button("๐Ÿ”ฅ ํŠธ๋ Œ๋”ฉ ํ…œํ”Œ๋ฆฟ", type="default")
1568
+ new_btn = antd.Button("โœจ NEW ํ…œํ”Œ๋ฆฟ", type="default")
1569
 
1570
  gr.HTML('<div class="render_header"><span class="header_btn"></span><span class="header_btn"></span><span class="header_btn"></span></div>')
1571
 
 
 
1572
  with antd.Tabs(active_key="empty", render_tab_bar="() => null") as state_tab:
1573
  with antd.Tabs.Item(key="empty"):
1574
  empty = antd.Empty(description="empty input", elem_classes="right_content")
 
1577
  with antd.Tabs.Item(key="render"):
1578
  sandbox = gr.HTML(elem_classes="html_content")
1579
 
1580
+ # ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ์—ฐ๊ฒฐ
1581
+ execute_btn.click(
1582
+ fn=execute_code,
1583
+ inputs=[input],
1584
+ outputs=[sandbox, state_tab]
1585
+ )
1586
+
1587
+ boost_btn.click(
1588
+ fn=handle_boost,
1589
+ inputs=[input],
1590
+ outputs=[input, state_tab]
1591
+ )
1592
+
1593
+ btn.click(
1594
+ demo_instance.generation_code,
1595
+ inputs=[input, setting, history],
1596
+ outputs=[code_output, history, sandbox, state_tab, code_drawer]
1597
+ )
1598
+
1599
+ clear_btn.click(
1600
+ demo_instance.clear_history,
1601
+ inputs=[],
1602
+ outputs=[history]
1603
+ )
1604
 
1605
+ deploy_btn.click(
1606
+ fn=lambda code: deploy_to_huggingface(remove_code_block(code)) if code else "์ฝ”๋“œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.",
1607
+ inputs=[code_output],
1608
+ outputs=[deploy_result]
1609
+ )
1610
 
1611
  codeBtn.click(
1612
  lambda: gr.update(open=True),
 
1632
  outputs=[history_drawer]
1633
  )
1634
 
 
1635
  best_btn.click(
1636
  fn=lambda: (gr.update(open=True), load_best_templates()),
1637
  outputs=[session_drawer, session_history],
 
1660
  outputs=[session_drawer, session_history]
1661
  )
1662
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1663
  if __name__ == "__main__":
1664
  try:
1665
  demo_instance = Demo()
 
1667
  except Exception as e:
1668
  print(f"Initialization error: {e}")
1669
  raise