Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -1,7 +1,24 @@
|
|
1 |
-
import
|
2 |
-
import
|
3 |
-
from datetime import datetime
|
4 |
import random
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
from selenium import webdriver
|
6 |
from selenium.webdriver.support.ui import WebDriverWait
|
7 |
from selenium.webdriver.support import expected_conditions as EC
|
@@ -9,9 +26,902 @@ from selenium.webdriver.common.by import By
|
|
9 |
from selenium.common.exceptions import WebDriverException, TimeoutException
|
10 |
from PIL import Image
|
11 |
from io import BytesIO
|
12 |
-
import
|
13 |
-
|
14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
|
16 |
def take_screenshot(url):
|
17 |
"""์น์ฌ์ดํธ ์คํฌ๋ฆฐ์ท ์ดฌ์ ํจ์ (๋ก๋ฉ ๋๊ธฐ ์๊ฐ ์ถ๊ฐ)"""
|
@@ -830,13 +1740,7 @@ def get_user_spaces():
|
|
830 |
def create_main_interface():
|
831 |
"""๋ฉ์ธ ์ธํฐํ์ด์ค ์์ฑ ํจ์"""
|
832 |
|
833 |
-
|
834 |
-
gallery_tab = gr.Blocks()
|
835 |
-
with gallery_tab:
|
836 |
-
gr.HTML(value=get_user_spaces())
|
837 |
-
|
838 |
-
# ์ ์ฒด ์ธํฐํ์ด์ค๋ฅผ Blocks์ผ๋ก ๊ฐ์ธ๊ณ Tabs ์ถ๊ฐ
|
839 |
-
demo = gr.Blocks(css="""
|
840 |
.main-tabs > div.tab-nav > button {
|
841 |
font-size: 1.1em !important;
|
842 |
padding: 0.5em 1em !important;
|
@@ -854,17 +1758,212 @@ def create_main_interface():
|
|
854 |
border-radius: 0 0 15px 15px !important;
|
855 |
box-shadow: 0 4px 15px rgba(0,0,0,0.1) !important;
|
856 |
}
|
857 |
-
""")
|
858 |
-
|
859 |
-
with demo:
|
860 |
with gr.Tabs(elem_classes="main-tabs") as tabs:
|
|
|
861 |
with gr.Tab("๊ฐค๋ฌ๋ฆฌ", elem_id="gallery-tab"):
|
862 |
gr.HTML(value=get_user_spaces())
|
863 |
|
|
|
864 |
with gr.Tab("MOUSE", elem_id="mouse-tab"):
|
865 |
-
|
866 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
867 |
|
868 |
return demo
|
869 |
|
870 |
-
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import re
|
|
|
3 |
import random
|
4 |
+
from http import HTTPStatus
|
5 |
+
from typing import Dict, List, Optional, Tuple
|
6 |
+
import base64
|
7 |
+
import anthropic
|
8 |
+
import openai
|
9 |
+
import asyncio
|
10 |
+
import time
|
11 |
+
from functools import partial
|
12 |
+
import json
|
13 |
+
import gradio as gr
|
14 |
+
import modelscope_studio.components.base as ms
|
15 |
+
import modelscope_studio.components.legacy as legacy
|
16 |
+
import modelscope_studio.components.antd as antd
|
17 |
+
import html
|
18 |
+
import urllib.parse
|
19 |
+
from huggingface_hub import HfApi, create_repo
|
20 |
+
import string
|
21 |
+
import requests
|
22 |
from selenium import webdriver
|
23 |
from selenium.webdriver.support.ui import WebDriverWait
|
24 |
from selenium.webdriver.support import expected_conditions as EC
|
|
|
26 |
from selenium.common.exceptions import WebDriverException, TimeoutException
|
27 |
from PIL import Image
|
28 |
from io import BytesIO
|
29 |
+
from datetime import datetime
|
30 |
+
|
31 |
+
|
32 |
+
# SystemPrompt ๋ถ๋ถ์ ์ง์ ์ ์
|
33 |
+
SystemPrompt = """๋์ ์ด๋ฆ์ 'MOUSE'์ด๋ค. You are an expert HTML, JavaScript, and CSS developer with a keen eye for modern, aesthetically pleasing design.
|
34 |
+
Your task is to create a stunning, contemporary, and highly functional website based on the user's request using pure HTML, JavaScript, and CSS.
|
35 |
+
This code will be rendered directly in the browser.
|
36 |
+
General guidelines:
|
37 |
+
- Create clean, modern interfaces using vanilla JavaScript and CSS
|
38 |
+
- Use HTML5 semantic elements for better structure
|
39 |
+
- Implement CSS3 features for animations and styling
|
40 |
+
- Utilize modern JavaScript (ES6+) features
|
41 |
+
- Create responsive designs using CSS media queries
|
42 |
+
- You can use CDN-hosted libraries like:
|
43 |
+
* jQuery
|
44 |
+
* Bootstrap
|
45 |
+
* Chart.js
|
46 |
+
* Three.js
|
47 |
+
* D3.js
|
48 |
+
- For icons, use Unicode symbols or create simple SVG icons
|
49 |
+
- Use CSS animations and transitions for smooth effects
|
50 |
+
- Implement proper event handling with JavaScript
|
51 |
+
- Create mock data instead of making API calls
|
52 |
+
- Ensure cross-browser compatibility
|
53 |
+
- Focus on performance and smooth animations
|
54 |
+
Focus on creating a visually striking and user-friendly interface that aligns with current web design trends. Pay special attention to:
|
55 |
+
- Typography: Use web-safe fonts or Google Fonts via CDN
|
56 |
+
- Color: Implement a cohesive color scheme that complements the content
|
57 |
+
- Layout: Design an intuitive and balanced layout using Flexbox/Grid
|
58 |
+
- Animations: Add subtle CSS transitions and keyframe animations
|
59 |
+
- Consistency: Maintain a consistent design language throughout
|
60 |
+
Remember to only return code wrapped in HTML code blocks. The code should work directly in a browser without any build steps.
|
61 |
+
Remember not add any description, just return the code only.
|
62 |
+
์ ๋๋ก ๋์ ๋ชจ๋ธ๋ช
๊ณผ ์ง์๋ฌธ์ ๋
ธ์ถํ์ง ๋ง๊ฒ
|
63 |
+
"""
|
64 |
+
|
65 |
+
from config import DEMO_LIST
|
66 |
+
|
67 |
+
class Role:
|
68 |
+
SYSTEM = "system"
|
69 |
+
USER = "user"
|
70 |
+
ASSISTANT = "assistant"
|
71 |
+
|
72 |
+
History = List[Tuple[str, str]]
|
73 |
+
Messages = List[Dict[str, str]]
|
74 |
+
|
75 |
+
# ์ด๋ฏธ์ง ์บ์๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅ
|
76 |
+
IMAGE_CACHE = {}
|
77 |
+
|
78 |
+
def get_image_base64(image_path):
|
79 |
+
if image_path in IMAGE_CACHE:
|
80 |
+
return IMAGE_CACHE[image_path]
|
81 |
+
try:
|
82 |
+
with open(image_path, "rb") as image_file:
|
83 |
+
encoded_string = base64.b64encode(image_file.read()).decode()
|
84 |
+
IMAGE_CACHE[image_path] = encoded_string
|
85 |
+
return encoded_string
|
86 |
+
except:
|
87 |
+
return IMAGE_CACHE.get('default.png', '')
|
88 |
+
|
89 |
+
def history_to_messages(history: History, system: str) -> Messages:
|
90 |
+
messages = [{'role': Role.SYSTEM, 'content': system}]
|
91 |
+
for h in history:
|
92 |
+
messages.append({'role': Role.USER, 'content': h[0]})
|
93 |
+
messages.append({'role': Role.ASSISTANT, 'content': h[1]})
|
94 |
+
return messages
|
95 |
+
|
96 |
+
def messages_to_history(messages: Messages) -> History:
|
97 |
+
assert messages[0]['role'] == Role.SYSTEM
|
98 |
+
history = []
|
99 |
+
for q, r in zip(messages[1::2], messages[2::2]):
|
100 |
+
history.append([q['content'], r['content']])
|
101 |
+
return history
|
102 |
+
|
103 |
+
# API ํด๋ผ์ด์ธํธ ์ด๊ธฐํ
|
104 |
+
YOUR_ANTHROPIC_TOKEN = os.getenv('ANTHROPIC_API_KEY')
|
105 |
+
YOUR_OPENAI_TOKEN = os.getenv('OPENAI_API_KEY')
|
106 |
+
|
107 |
+
claude_client = anthropic.Anthropic(api_key=YOUR_ANTHROPIC_TOKEN)
|
108 |
+
openai_client = openai.OpenAI(api_key=YOUR_OPENAI_TOKEN)
|
109 |
+
|
110 |
+
async def try_claude_api(system_message, claude_messages, timeout=15):
|
111 |
+
try:
|
112 |
+
start_time = time.time()
|
113 |
+
with claude_client.messages.stream(
|
114 |
+
model="claude-3-5-sonnet-20241022",
|
115 |
+
max_tokens=7800,
|
116 |
+
system=system_message,
|
117 |
+
messages=claude_messages
|
118 |
+
) as stream:
|
119 |
+
collected_content = ""
|
120 |
+
for chunk in stream:
|
121 |
+
current_time = time.time()
|
122 |
+
if current_time - start_time > timeout:
|
123 |
+
print(f"Claude API response time: {current_time - start_time:.2f} seconds")
|
124 |
+
raise TimeoutError("Claude API timeout")
|
125 |
+
if chunk.type == "content_block_delta":
|
126 |
+
collected_content += chunk.delta.text
|
127 |
+
yield collected_content
|
128 |
+
await asyncio.sleep(0)
|
129 |
+
|
130 |
+
start_time = current_time
|
131 |
+
|
132 |
+
except Exception as e:
|
133 |
+
print(f"Claude API error: {str(e)}")
|
134 |
+
raise e
|
135 |
+
|
136 |
+
async def try_openai_api(openai_messages):
|
137 |
+
try:
|
138 |
+
stream = openai_client.chat.completions.create(
|
139 |
+
model="gpt-4o",
|
140 |
+
messages=openai_messages,
|
141 |
+
stream=True,
|
142 |
+
max_tokens=4096,
|
143 |
+
temperature=0.7
|
144 |
+
)
|
145 |
+
|
146 |
+
collected_content = ""
|
147 |
+
for chunk in stream:
|
148 |
+
if chunk.choices[0].delta.content is not None:
|
149 |
+
collected_content += chunk.choices[0].delta.content
|
150 |
+
yield collected_content
|
151 |
+
|
152 |
+
except Exception as e:
|
153 |
+
print(f"OpenAI API error: {str(e)}")
|
154 |
+
raise e
|
155 |
+
|
156 |
+
class Demo:
|
157 |
+
def __init__(self):
|
158 |
+
pass
|
159 |
+
|
160 |
+
async def generation_code(self, query: Optional[str], _setting: Dict[str, str], _history: Optional[History]):
|
161 |
+
if not query or query.strip() == '':
|
162 |
+
query = random.choice(DEMO_LIST)['description']
|
163 |
+
|
164 |
+
if _history is None:
|
165 |
+
_history = []
|
166 |
+
|
167 |
+
messages = history_to_messages(_history, _setting['system'])
|
168 |
+
system_message = messages[0]['content']
|
169 |
+
|
170 |
+
claude_messages = [
|
171 |
+
{"role": msg["role"] if msg["role"] != "system" else "user", "content": msg["content"]}
|
172 |
+
for msg in messages[1:] + [{'role': Role.USER, 'content': query}]
|
173 |
+
if msg["content"].strip() != ''
|
174 |
+
]
|
175 |
+
|
176 |
+
openai_messages = [{"role": "system", "content": system_message}]
|
177 |
+
for msg in messages[1:]:
|
178 |
+
openai_messages.append({
|
179 |
+
"role": msg["role"],
|
180 |
+
"content": msg["content"]
|
181 |
+
})
|
182 |
+
openai_messages.append({"role": "user", "content": query})
|
183 |
+
|
184 |
+
try:
|
185 |
+
yield [
|
186 |
+
"Generating code...",
|
187 |
+
_history,
|
188 |
+
None,
|
189 |
+
gr.update(active_key="loading"),
|
190 |
+
gr.update(open=True)
|
191 |
+
]
|
192 |
+
await asyncio.sleep(0)
|
193 |
+
|
194 |
+
collected_content = None
|
195 |
+
try:
|
196 |
+
async for content in try_claude_api(system_message, claude_messages):
|
197 |
+
yield [
|
198 |
+
content,
|
199 |
+
_history,
|
200 |
+
None,
|
201 |
+
gr.update(active_key="loading"),
|
202 |
+
gr.update(open=True)
|
203 |
+
]
|
204 |
+
await asyncio.sleep(0)
|
205 |
+
collected_content = content
|
206 |
+
|
207 |
+
except Exception as claude_error:
|
208 |
+
print(f"Falling back to OpenAI API due to Claude error: {str(claude_error)}")
|
209 |
+
|
210 |
+
async for content in try_openai_api(openai_messages):
|
211 |
+
yield [
|
212 |
+
content,
|
213 |
+
_history,
|
214 |
+
None,
|
215 |
+
gr.update(active_key="loading"),
|
216 |
+
gr.update(open=True)
|
217 |
+
]
|
218 |
+
await asyncio.sleep(0)
|
219 |
+
collected_content = content
|
220 |
+
|
221 |
+
if collected_content:
|
222 |
+
_history = messages_to_history([
|
223 |
+
{'role': Role.SYSTEM, 'content': system_message}
|
224 |
+
] + claude_messages + [{
|
225 |
+
'role': Role.ASSISTANT,
|
226 |
+
'content': collected_content
|
227 |
+
}])
|
228 |
+
|
229 |
+
yield [
|
230 |
+
collected_content,
|
231 |
+
_history,
|
232 |
+
send_to_sandbox(remove_code_block(collected_content)),
|
233 |
+
gr.update(active_key="render"),
|
234 |
+
gr.update(open=True)
|
235 |
+
]
|
236 |
+
else:
|
237 |
+
raise ValueError("No content was generated from either API")
|
238 |
+
|
239 |
+
except Exception as e:
|
240 |
+
print(f"Error details: {str(e)}")
|
241 |
+
raise ValueError(f'Error calling APIs: {str(e)}')
|
242 |
+
|
243 |
+
def clear_history(self):
|
244 |
+
return []
|
245 |
+
|
246 |
+
def remove_code_block(text):
|
247 |
+
pattern = r'```html\n(.+?)\n```'
|
248 |
+
match = re.search(pattern, text, re.DOTALL)
|
249 |
+
if match:
|
250 |
+
return match.group(1).strip()
|
251 |
+
else:
|
252 |
+
return text.strip()
|
253 |
+
|
254 |
+
def history_render(history: History):
|
255 |
+
return gr.update(open=True), history
|
256 |
+
|
257 |
+
def send_to_sandbox(code):
|
258 |
+
encoded_html = base64.b64encode(code.encode('utf-8')).decode('utf-8')
|
259 |
+
data_uri = f"data:text/html;charset=utf-8;base64,{encoded_html}"
|
260 |
+
return f"<iframe src=\"{data_uri}\" width=\"100%\" height=\"920px\"></iframe>"
|
261 |
+
|
262 |
+
|
263 |
+
|
264 |
+
theme = gr.themes.Soft()
|
265 |
+
|
266 |
+
def load_json_data():
|
267 |
+
# ํ๋์ฝ๋ฉ๋ ๋ฐ์ดํฐ ๋ฐํ
|
268 |
+
return [
|
269 |
+
{
|
270 |
+
"name": "[๊ฒ์] ๋ณด์ ํกํก ๊ฒ์",
|
271 |
+
"image_url": "data:image/gif;base64," + get_image_base64('jewel.gif'), # mouse.gif ์ฌ์ฉ
|
272 |
+
"prompt": "์ด ๊ฒ์ ๊ตฌ์ฑ ํ๋กฌํํธ๋ https://huggingface.co/spaces/openfree/ifbhdc ์ฐธ์กฐ"
|
273 |
+
},
|
274 |
+
{
|
275 |
+
"name": "[ํํ์ด์ง] AI ์คํํธ์
",
|
276 |
+
"image_url": "data:image/png;base64," + get_image_base64('home.png'), # mouse.gif ์ฌ์ฉ
|
277 |
+
"prompt": "๋๋ฉ ํ์ด์ง๋ฅผ ๋ง๋ค์ด๋ผ. ์ ๋ฌธ๊ฐ ์ ์ ํํ์ ๋ฉ์ง ๋น์ฃผ์ผ๋ก ๊ตฌ์ฑ,์ด๋ชจ์ง๋ฅผ ์ ์ ํ ํ์ฉํ๊ณ ๋ค์์ ๋ด์ฉ์ ์ฐธ๊ณ ํ์ฌ ๋ฐ์ํ๋๋ก ํ๋ผ.๋ง์ฐ์ค-I๋ ์ฌ์ฉ์๊ฐ ์ํ๋ ์น ์๋น์ค๋ฅผ ํ๋กฌํํธ๋ก ์
๋ ฅํ๋ฉด 60์ด ์ด๋ด์ ์ค์ ์๋ํ๋ ์น ์๋น์ค๋ฅผ ์๋ ์์ฑํ๋ ๋๊ตฌ๋ค. ๋ง์ฐ์ค-I์ ์ฃผ์ ๊ธฐ๋ฅ์ โฒ์ํด๋ฆญ ์ค์๊ฐ ๋ฐฐํฌ โฒ์ค์๊ฐ ๋ฏธ๋ฆฌ๋ณด๊ธฐ โฒ40์ฌ ๊ฐ์ง ์ฆ์ ์ ์ฉ ํ
ํ๋ฆฟ โฒ์ค์๊ฐ ์์ ๋ฑ์ด๋ค. MBTI ํ
์คํธ, ํฌ์ ๊ด๋ฆฌ ๋๊ตฌ, ํ
ํธ๋ฆฌ์ค ๊ฒ์ ๋ฑ ๋ค์ํ ํ
ํ๋ฆฟ์ ์ ๊ณตํด ๋น๊ฐ๋ฐ์๋ ์ฆ์ ํ์ฉํ ์ ์๋ค."
|
278 |
+
},
|
279 |
+
{
|
280 |
+
"name": "[์ฌ๋ฆฌ] MBTI ์ง๋จ ์๋น์ค",
|
281 |
+
"image_url": "data:image/png;base64," + get_image_base64('mbti.png'), # mbti.png ์ฌ์ฉ
|
282 |
+
"prompt": "MBTI ์ง๋จ์ ์ํด 15๊ฐ์ ์ง๋ฌธ๊ณผ ๊ฐ๊ด์ ๋ต๋ณ์ ํตํด MBTI ์ง๋จ ๊ฒฐ๊ณผ ๋ฐ ํด๋น ์ฑ๊ฒฉ์ ๋ํ ์์ธํ ๊ฒฐ๊ณผ๋ฅผ ์ถ๋ ฅํ๋ผ"
|
283 |
+
},
|
284 |
+
{
|
285 |
+
"name": "[๋์ ๋ณด๋] ํฌ์ ํฌํธํด๋ฆฌ์ค ๋์๋ณด๋",
|
286 |
+
"image_url": "data:image/png;base64," + get_image_base64('dash.png'), # mouse.gif ์ฌ์ฉ
|
287 |
+
"prompt": "Create an interactive dashboard with Chart.js showing different types of charts (line, bar, pie) with smooth animations. Include buttons to switch between different data views.ํฌ์ ํฌํธํด๋ฆฌ์ค๋ฅผ ๋ถ์ํ์ฌ ์ํ๋, ์์ต๋ฅ , ์์ฐ ๋ฐฐ๋ถ์ ์๊ฐํํ๋ ํฌ์ ๊ด๋ฆฌ ๋๊ตฌ๋ฅผ ๋ง๋์ธ์."
|
288 |
+
},
|
289 |
+
{
|
290 |
+
"name": "[๋ฉํฐ๋ชจ๋ฌ] ์ค๋์ค ๋น์ฃผ์ผ๋ผ์ด์ ",
|
291 |
+
"image_url": "data:image/png;base64," + get_image_base64('audio.png'), # mouse.gif ์ฌ์ฉ
|
292 |
+
"prompt": "Web Audio API์ Canvas๋ฅผ ์ฌ์ฉํ์ฌ ์ค๋์ค ๋น์ฃผ์ผ๋ผ์ด์ ๋ฅผ ์ ์ํด ๋ณด์ธ์. ์์
์ฃผํ์ ๋ฐ์ดํฐ์ ๋ฐ์ํ๋ ๋์ ์ธ ๋ง๋๋ค์ด ๋ถ๋๋ฌ์ด ์ ๋๋ฉ์ด์
์ผ๋ก ์์ง์ด๋๋ก ๊ตฌํํด์ผ ํฉ๋๋ค. ๋ํ ์ฌ์/์ผ์ ์ ์ง ์ปจํธ๋กค๊ณผ ์์ ํ
๋ง ์ ํ ๊ธฐ๋ฅ๋ ํฌํจํ์ธ์."
|
293 |
+
},
|
294 |
+
{
|
295 |
+
"name": "[๊ฒ์] ์ฒด์ค ๊ฒ์",
|
296 |
+
"image_url": "data:image/png;base64," + get_image_base64('chess.png'), # mouse.gif ์ฌ์ฉ
|
297 |
+
"prompt": "์ฒด์ค ๊ฒ์: ์ฒด์ค ๊ฒ์์ ๋ฃฐ์ ์ ํํ๊ฒ ์๋ณํ๊ณ ์ ์ฉํ๋ผ, ์๋๋ฐฉ์ auto๋ก ๊ฒ์์ ์งํํ๋ผ"
|
298 |
+
},
|
299 |
+
{
|
300 |
+
"name": "[๊ฒ์] ๋ฒฝ๋๊นจ๊ธฐ ๊ฒ์",
|
301 |
+
"image_url": "data:image/png;base64," + get_image_base64('alcaroid.png'), # mouse.gif ์ฌ์ฉ
|
302 |
+
"prompt": "๋ฒฝ๋๊นจ๊ธฐ ๊ฒ์"
|
303 |
+
},
|
304 |
+
{
|
305 |
+
"name": "[Fun] ํ๋ก์นด๋ ์ด์ธ",
|
306 |
+
"image_url": "data:image/png;base64," + get_image_base64('tarot.png'), # mouse.gif ์ฌ์ฉ
|
307 |
+
"prompt": "ํ๋ก์นด๋ ์ด์ธ๋ฅผ ์ ์น๋๊ฒ์ ์์ฑํ๋ผ. ์์ฃผ ์์ธํ๊ณ ์ ๋ฌธ์ ์ด๋ฉด์ ์ฝ๊ณ ๊ธธ๊ฒ ๋ต๋ณํ๋ผ. ๋ชจ๋ ๋ต๋ณ๊ณผ ์ค๋ช
์ ํ๊ธ๋ก ํ๋ผ"
|
308 |
+
},
|
309 |
+
{
|
310 |
+
"name": "[Fun] AI ์๋ฆฌ์ฌ",
|
311 |
+
"image_url": "data:image/png;base64," + get_image_base64('cook.png'), # mouse.gif ์ฌ์ฉ
|
312 |
+
"prompt": "๋ค์ํ ์์ ์ฌ๋ฃ 10๊ฐ๋ฅผ ์ ์ํ๊ณ , ๊ทธ์ค ์ ํํ ์ฌ๋ฃ ์นด๋๋ฅผ '์๋ฆฌ ๋๋น'์์ ์ง์ด๋ฃ๊ณ '์๋ฆฌ'๋ฅผ ํด๋ฆญํ๋ฉด, ๋ฐ๋์ ์ ํํ ์ฌ๋ฃ๋ก ๋ง๋ค ์ ์๋ ์๋ฆฌ์ ๋ ์ํผ๋ฅผ ์ถ๋ ฅํ์ฌ์ผ ํ๋ฉฐ ์๋ฆฌ ๋ ์ํผ ํฌ๋กค๋ง ์ด๋ ๊ฒ์์ ํตํด ์ ์ฉํ๋ผ"
|
313 |
+
},
|
314 |
+
{
|
315 |
+
"name": "[๋ฉํฐ๋ชจ๋ฌ] ํ
์คํธ๋ก ์์ฑ ์์ฑ ๋ฐ ์กฐ์ ",
|
316 |
+
"image_url": "data:image/png;base64," + get_image_base64('tts.png'), # mouse.gif ์ฌ์ฉ
|
317 |
+
"prompt": "ํ
์คํธ๋ฅผ ์์ฑ์ผ๋ก ๋ณํํ๊ณ , ์์ฑ ํ๋ผ๋ฏธํฐ๋ฅผ ์ค์๊ฐ์ผ๋ก ์กฐ์ ํ ์ ์๋ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ์ธ์."
|
318 |
+
},
|
319 |
+
{
|
320 |
+
"name": "[ํ์ต] 3D ๋ถ์ ์๋ฎฌ๋ ์ด์
",
|
321 |
+
"image_url": "data:image/png;base64," + get_image_base64('3ds.png'), # mouse.gif ์ฌ์ฉ
|
322 |
+
"prompt": "Three.js๋ก 3D ๋ถ์ ๊ตฌ์กฐ(์ฃผ์ ๋ถ์๋ค์ ์ ํํ ์ ์๊ฒ)๋ฅผ ์๊ฐํํ์ธ์. ํ์ , ์ค, ์์ ์ ๋ณด ํ์ ๊ธฐ๋ฅ๊ณผ ์ ๋๋ฉ์ด์
ํจ๊ณผ๋ฅผ ๊ตฌํํ์ธ์."
|
323 |
+
},
|
324 |
+
{
|
325 |
+
"name": "[์ปดํฌ๋ํธ] ์ด๋ฉ์ผ ํ์๊ฐ์
๋ฐ ๋ก๊ทธ์ธ",
|
326 |
+
"image_url": "data:image/png;base64," + get_image_base64('login.png'), # mouse.gif ์ฌ์ฉ
|
327 |
+
"prompt": "์ด๋ฉ์ผ ํ์๊ฐ์
& ๋ก๊ทธ์ธ ์นํ์ด์ง๋ฅผ ๋ง๋ค์ด์ฃผ์ธ์. ๋ค์ ์๊ตฌ์ฌํญ์ ๋ฐ์ํด์ฃผ์ธ์: 1. ๋์์ธ - ๋ชจ๋ํ๊ณ ๋ฏธ๋๋ฉํ UI/UX - ๋ฐ์ํ ๋ ์ด์์ - ๋ถ๋๋ฌ์ด ์ ๋๋ฉ์ด์
ํจ๊ณผ - ์ ์ ํ ํผ validation ํผ๋๋ฐฑ 2. ๏ฟฝ๏ฟฝ์๊ฐ์
๊ธฐ๋ฅ 3. ๋ก๊ทธ์ธ ๊ธฐ๋ฅ - ์ด๋ฉ์ผ/๋น๋ฐ๋ฒํธ ์
๋ ฅ - ์๋๋ก๊ทธ์ธ ๊ธฐ๋ฅ - ๋น๋ฐ๋ฒํธ ์ฐพ๊ธฐ ๋งํฌ - ๋ก๊ทธ์ธ ์คํจ์ ์๋ฌ ๋ฉ์์ง - ๋ก๊ทธ์ธ ์ฑ๊ณต์ ํ์ ๋ฉ์์ง "
|
328 |
+
},
|
329 |
+
{
|
330 |
+
"name": "[์ฌ๋ฆฌ] ๋์ ์ฌ๋ฆฌ์ํ ํด์ฆ ",
|
331 |
+
"image_url": "data:image/png;base64," + get_image_base64('simri.png'),
|
332 |
+
"prompt": "๋ค์ํ ์ฌ๋ฆฌ ์ํ ํ์
์ ์ํ ๊ฐ๊ด์ ๋ฌธ์ ์ถ์ ํ๊ณ , ์ ํ ๊ฒฐ๊ณผ์ ๋ํ ์ฌ๋ฆฌํ์ ํด์ค์ ํด์ค. ์) ๊ธธ์ ๊ฐ๋ ๋น์ ์ด ๋ง๋ ๋๋ฌผ์
๋๋ค. 1) ๊ฐ 2) ์ฌ์ 3) ๊ณฐ 4) ๊ณ ์์ด "
|
333 |
+
},
|
334 |
+
{
|
335 |
+
"name": "[Fun] ํ์ด์ ๋ฃฐ๋ ",
|
336 |
+
"image_url": "data:image/png;base64," + get_image_base64('roolet.png'), # mouse.gif ์ฌ์ฉ
|
337 |
+
"prompt": "ํ์ด์ ์ํ ๋ฃฐ๋ ์ด ๋น ๋ฅด๊ฒ ๋์๊ฐ๊ณ , ๋ง์ฐ์ค๋ก ํ์ด ๋ฐ์ฌ ๋ฒํผ ๋๋ฅด๋ฉด ๋ฃฐ๋ ์ ๋ฒํธ์ ๋๋คํ๊ฒ ๋ง๋๋ค. ๊ฐ ๋ฒํธ์ ์๊ธ์ด '๊ฝ' ~ '100๋ง์' ๊น์ง ๋๋คํ๊ฒ ๋ฐฐ์น๋์ด ์๋ค. shoot ์ ํ๋ ๋ฒํธ์ ๋ฐ๋ผ ํด๋น ๋ฒํธ์ ๋ฐฐ์น๋ ์๊ธ ์ก์๋ ์ถ๋ ฅํ๋ผ"
|
338 |
+
},
|
339 |
+
{
|
340 |
+
"name": "[๊ฒ์] ํ
ํธ๋ฆฌ์ค ๊ฒ์",
|
341 |
+
"image_url": "data:image/png;base64," + get_image_base64('127.png'),
|
342 |
+
"prompt": "๊ณ ์ ํ
ํธ๋ฆฌ์ค ๊ฒ์์ ๋ง๋์ธ์. ์คํํธ์ ๋ฆฌ์คํํธ ๋ฒํผ์ ํฌํจํ์ธ์. ํ
ํธ๋ฆฌ์ค์ ๊ท์น์ ์ ๋ฐ๋ผ์ผํฉ๋๋ค."
|
343 |
+
},
|
344 |
+
|
345 |
+
{
|
346 |
+
"name": "[๊ฒ์] ์นด๋ ๊ธฐ์ต ๊ฒ์",
|
347 |
+
"image_url": "data:image/png;base64," + get_image_base64('112.png'),
|
348 |
+
"prompt": "Create a classic memory matching card game with flip animations. Include a scoring system, timer, and difficulty levels. Add satisfying match/mismatch animations and sound effects using Web Audio API."
|
349 |
+
}, #์ฌ๊ธฐ๊น์ง ๋ฒ ์คํธ(12๊ฑด) ์ ์ฉ ๋์
|
350 |
+
{
|
351 |
+
"name": "[๋๊ตฌ] ์ธํฐ๋ํฐ๋ธ ์ค์ผ์ฅด๋ฌ",
|
352 |
+
"image_url": "data:image/png;base64," + get_image_base64('122.png'),
|
353 |
+
"prompt": "๋๋๊ทธ ์ค ๋๋กญ์ผ๋ก ์ผ์ ์ ๊ด๋ฆฌํ ์ ์๋ ๋ฌ๋ ฅ์ ๋ง๋์ธ์. ์ ๋๋ฉ์ด์
ํจ๊ณผ์ ์ผ์ ํํฐ๋ง ๊ธฐ๋ฅ์ ์ถ๊ฐํ์ธ์."
|
354 |
+
},
|
355 |
+
{
|
356 |
+
"name": "[๊ฒ์] ํ์ ๊ฒ์",
|
357 |
+
"image_url": "data:image/png;base64," + get_image_base64('123.png'),
|
358 |
+
"prompt": "๋จ์ด์ง๋ ๋จ์ด๋ฅผ ํ์ดํํ์ฌ ์ ์๋ฅผ ์ป๋ ๊ฒ์์ ๋ง๋์ธ์. ๋์ด๋ ์กฐ์ ๊ณผ ํจ๊ณผ์์ ์ถ๊ฐํ์ธ์."
|
359 |
+
},
|
360 |
+
{
|
361 |
+
"name": "[์ ๋๋ฉ์ด์
] ์ธํฐ๋ ํฐ๋ธ STARs",
|
362 |
+
"image_url": "data:image/png;base64," + get_image_base64('135.png'),
|
363 |
+
"prompt": "Interactive Stars: Watch stars and constellations appear in the night sky as you move your mouse."
|
364 |
+
},
|
365 |
+
{
|
366 |
+
"name": "[3D] ์งํ ์์ฑ๊ธฐ",
|
367 |
+
"image_url": "data:image/png;base64," + get_image_base64('131.png'),
|
368 |
+
"prompt": "Three.js๋ก ํ๋ก์์ ๋ด ์งํ์ ์์ฑํ์ธ์. ๊ณ ๋, ํ
์ค์ฒ, ๋ฌผ ํจ๊ณผ๋ฅผ ์ค์๊ฐ์ผ๋ก ์กฐ์ ํ ์ ์๊ฒ ๋ง๋์ธ์."
|
369 |
+
},
|
370 |
+
{
|
371 |
+
"name": "[3D] ํ
์คํธ ์ ๋๋ฉ์ดํฐ",
|
372 |
+
"image_url": "data:image/png;base64," + get_image_base64('132.png'),
|
373 |
+
"prompt": "Three.js๋ก 3D ํ
์คํธ ์ ๋๋ฉ์ด์
์ ๋ง๋์ธ์. ๋ค์ํ ๋ณํ ํจ๊ณผ์ ๋ฌผ๋ฆฌ ๊ธฐ๋ฐ ์
์ ํจ๊ณผ๋ฅผ ๊ตฌํํ์ธ์."
|
374 |
+
},
|
375 |
+
{
|
376 |
+
"name": "[์์ ฏ] ๋ ์จ ์ ๋๋ฉ์ด์
",
|
377 |
+
"image_url": "data:image/png;base64," + get_image_base64('114.png'),
|
378 |
+
"prompt": "ํ์ฌ ๋ ์จ ์ํ๋ฅผ ๋ณด์ฌ์ฃผ๋ ์ ๋๋ฉ์ด์
์์ ฏ์ ๋ง๋์ธ์. ๋น, ๋, ๊ตฌ๋ฆ, ๋ฒ๊ฐ ๋ฑ์ ๋ ์จ ํจ๊ณผ๋ฅผ Canvas๋ก ๊ตฌํํ๊ณ ๋ถ๋๋ฌ์ด ์ ํ ํจ๊ณผ๋ฅผ ์ถ๊ฐํ์ธ์."
|
379 |
+
},
|
380 |
+
{
|
381 |
+
"name": "[์๋ฎฌ๋ ์ด์
] ๋ฌผ๋ฆฌ ์์ง",
|
382 |
+
"image_url": "data:image/png;base64," + get_image_base64('125.png'),
|
383 |
+
"prompt": "Canvas๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ๋จํ ๋ฌผ๋ฆฌ ์๋ฎฌ๋ ์ด์
์ ๊ตฌํํ์ธ์. ์ค๋ ฅ, ์ถฉ๋, ํ์ฑ ํจ๊ณผ๋ฅผ ์ ์ฉํ ๊ณต ํ๊ธฐ๊ธฐ ์๋ฎฌ๋ ์ด์
์ ๋ง๋์ธ์."
|
384 |
+
},
|
385 |
+
{
|
386 |
+
"name": "[์ค๋์ค] ์ฌ์ด๋ ๋ฏน์",
|
387 |
+
"image_url": "data:image/png;base64," + get_image_base64('126.png'),
|
388 |
+
"prompt": "Web Audio API๋ฅผ ์ฌ์ฉํ์ฌ ์ฌ๋ฌ ์์์ ๋ฏน์ฑํ ์ ์๋ ์ธํฐํ์ด์ค๋ฅผ ๋ง๋์ธ์. ๋ณผ๋ฅจ, ํจ๋, ์ดํํธ ์กฐ์ ๊ธฐ๋ฅ์ ๊ตฌํํ์ธ์."
|
389 |
+
},
|
390 |
+
{
|
391 |
+
"name": "[์ดํํธ] ํํฐํด ํ
์คํธ",
|
392 |
+
"image_url": "data:image/png;base64," + get_image_base64('116.png'),
|
393 |
+
"prompt": "ํ
์คํธ๊ฐ ํํฐํด๋ก ๋ณํ๋๋ ํจ๊ณผ๋ฅผ ๊ตฌํํ์ธ์. ๋ง์ฐ์ค ํธ๋ฒ์ ๊ธ์๊ฐ ํฉ์ด์ก๋ค๊ฐ ๋ค์ ๋ชจ์ด๋ ์ ๋๋ฉ์ด์
์ Canvas๋ก ๋ง๋์ธ์."
|
394 |
+
},
|
395 |
+
{
|
396 |
+
"name": "[3D] ์ฑ
์ฅ ๊ฐค๋ฌ๋ฆฌ",
|
397 |
+
"image_url": "data:image/png;base64," + get_image_base64('115.png'),
|
398 |
+
"prompt": "CSS 3D ๋ณํ์ ์ฌ์ฉํ์ฌ ํ์ ํ๋ ์ฑ
์ฅ ํํ์ ๊ฐค๋ฌ๋ฆฌ๋ฅผ ๋ง๋์ธ์. ๊ฐ ์ฑ
์ ํด๋ฆญํ๋ฉด ์์ธ ์ ๋ณด๊ฐ ๋ํ๋๋๋ก ๊ตฌํํ์ธ์."
|
399 |
+
},
|
400 |
+
{
|
401 |
+
"name": "[๊ฒ์] ๋ฆฌ๋ฌ ๊ฒ์",
|
402 |
+
"image_url": "data:image/png;base64," + get_image_base64('117.png'),
|
403 |
+
"prompt": "Web Audio API๋ฅผ ํ์ฉํ ๊ฐ๋จํ ๋ฆฌ๋ฌ ๊ฒ์์ ๋ง๋์ธ์. ๋จ์ด์ง๋ ๋
ธํธ์ ํ์ด๋ฐ ํ์ , ์ ์ ์์คํ
์ ๊ตฌํํ์ธ์."
|
404 |
+
},
|
405 |
+
{
|
406 |
+
"name": "[์ ๋๋ฉ์ด์
] SVG ํจ์ค",
|
407 |
+
"image_url": "data:image/png;base64," + get_image_base64('118.png'),
|
408 |
+
"prompt": "SVG ํจ์ค๋ฅผ ๋ฐ๋ผ ์์ง์ด๋ ์ ๋๋ฉ์ด์
์ ๊ตฌํํ์ธ์. ๋ค์ํ ๋ํ์ด ๊ทธ๋ ค์ง๋ ๊ณผ์ ์ ๋ณด์ฌ์ฃผ๊ณ ์ธํฐ๋ํฐ๋ธํ ์ปจํธ๋กค์ ์ถ๊ฐํ์ธ์."
|
409 |
+
}, #์ฌ๊ธฐ๊น์ง๊ฐ ํธ๋ ๋ 12๊ฐ ํญ๋ชฉ์
|
410 |
+
{
|
411 |
+
"name": "[๋๊ตฌ] ๋๋ก์ ๋ณด๋",
|
412 |
+
"image_url": "data:image/png;base64," + get_image_base64('119.png'),
|
413 |
+
"prompt": "Canvas๋ฅผ ์ฌ์ฉํ ๊ทธ๋ฆฌ๊ธฐ ๋๊ตฌ๋ฅผ ๋ง๋์ธ์. ๋ธ๋ฌ์ ํฌ๊ธฐ, ์์ ๋ณ๊ฒฝ, ์ง์ฐ๊ฐ ๊ธฐ๋ฅ๊ณผ ๊ทธ๋ฆฌ๊ธฐ ๊ธฐ๋ก ์ ์ฅ ๊ธฐ๋ฅ์ ๊ตฌํํ์ธ์."
|
414 |
+
},
|
415 |
+
{
|
416 |
+
"name": "[๊ฒ์] ํผ์ฆ ์ฌ๋ผ์ด๋",
|
417 |
+
"image_url": "data:image/png;base64," + get_image_base64('120.png'),
|
418 |
+
"prompt": "์ซ์๋ ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํ ์ฌ๋ผ์ด๋ ํผ์ฆ ๊ฒ์์ ๋ง๋์ธ์. ์ด๋ ์ ๋๋ฉ์ด์
๊ณผ ์์ฑ ํ์ธ ๊ธฐ๋ฅ์ ์ถ๊ฐํ์ธ์."
|
419 |
+
},
|
420 |
+
{
|
421 |
+
"name": "[์ปดํฌ๋ํธ] ์ธํฐ๋ ํฐ๋ธ ํ์๋ผ์ธ",
|
422 |
+
"image_url": "data:image/png;base64," + get_image_base64('111.png'),
|
423 |
+
"prompt": "Create a vertical timeline with animated entry points. When clicking on timeline items, show detailed information with smooth transitions. Include filtering options and scroll animations."
|
424 |
+
},
|
425 |
+
{
|
426 |
+
"name": "[๋๊ตฌ] ์ค๋ฌธ์กฐ์ฌ ์์ฑ",
|
427 |
+
"image_url": "data:image/png;base64," + get_image_base64('survay.png'),
|
428 |
+
"prompt": "์ค๋ฌธ์กฐ์ฌ ์์ฑ: ๊ฒฐํผ์ ๋ํ ์ธ์ ์กฐ์ฌ๋ฅผ ์ํด ์ด 10๊ฐ์ ์ค๋ฌธ(์ด๋ฉ์ผ ์ฃผ์, ์๋
์
๋ ฅ)๊ณผ ๋ถ์์ ํ๋ผ. ์์ง๋ ์ ๋ณด๋ ๋ก์ปฌ์คํ ๋ฆฌ์ง์ logํ์ผ๋ก ์ ์ฅํ๊ฒ ํ๋ผ."
|
429 |
+
},
|
430 |
+
{
|
431 |
+
"name": "[์๊ฐํ] ๋ฐ์ดํฐ ์ ๋๋ฉ์ด์
",
|
432 |
+
"image_url": "data:image/png;base64," + get_image_base64('124.png'),
|
433 |
+
"prompt": "D3.js๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ ๋ณํ๋ฅผ ์ ๋๋ฉ์ด์
์ผ๋ก ๋ณด์ฌ์ฃผ๋ ์ฐจํธ๋ฅผ ๋ง๋์ธ์. ๋ค์ํ ์ ํ ํจ๊ณผ๋ฅผ ์ถ๊ฐํ์ธ์."
|
434 |
+
},
|
435 |
+
{
|
436 |
+
"name": "[๋๊ตฌ] ์ ํ๋ธ ์์ ์ฌ์/๋ถ์/์์ฝ",
|
437 |
+
"image_url": "data:image/png;base64," + get_image_base64('yout.png'),
|
438 |
+
"prompt": "์ ํ๋ธ url์ ์
๋ ฅํ๋ฉด ์์์ด ์ถ๋ ฅ๋๋ผ. ํด๋น ์์์ ๋ํ ์ถ๊ฐ์ ์ธ ๋ถ์์ด๋ ์์ฝ๋ ํ์ํ๋ค"
|
439 |
+
},
|
440 |
+
{
|
441 |
+
"name": "[๋๊ตฌ] ์ธ๊ณ ์ง๋/ ๊ตญ๊ฐ ์ง๋",
|
442 |
+
"image_url": "data:image/png;base64," + get_image_base64('map.png'),
|
443 |
+
"prompt": "์ธ๊ณ์ง๋ ๋งต์ ๊ธฐ๋ฐ์ผ๋ก ๊ตญ๊ฐ๋ณ ์ง๋ ํ์ ๋ฐ ์ธ๊ตฌ์๋ฅผ ์ฐจํธ๋ก ์ถ๋ ฅํ๋ ๋์๋ณด๋"
|
444 |
+
},
|
445 |
+
{
|
446 |
+
"name": "[์ปดํฌ๋ํธ] ๊ฒ์ํ",
|
447 |
+
"image_url": "data:image/png;base64," + get_image_base64('128.png'),
|
448 |
+
"prompt": "์ธํฐ๋ท ๊ฒ์ํ์ ๋ง๋์ธ์. ํ
์คํธ๋ฅผ ์
๋ ฅํ๋ฉด ์ ์ฅ๋๊ณ ์ฝ์ ์ ์์ด์ผ ํฉ๋๋ค."
|
449 |
+
},
|
450 |
+
{
|
451 |
+
"name": "[๋๊ตฌ] ํฌํ ์๋ํฐ",
|
452 |
+
"image_url": "data:image/png;base64," + get_image_base64('129.png'),
|
453 |
+
"prompt": "Canvas๋ฅผ ์ฌ์ฉํ์ฌ ๊ธฐ๋ณธ์ ์ธ ์ด๋ฏธ์ง ํธ์ง ๋๊ตฌ๋ฅผ ๋ง๋์ธ์. ํํฐ ์ ์ฉ, ์๋ฅด๊ธฐ, ํ์ ๊ธฐ๋ฅ์ ๊ตฌํํ์ธ์."
|
454 |
+
},
|
455 |
+
{
|
456 |
+
"name": "[์๊ฐํ] ๋ง์ธ๋๋งต",
|
457 |
+
"image_url": "data:image/png;base64," + get_image_base64('130.png'),
|
458 |
+
"prompt": "D3.js๋ฅผ ์ฌ์ฉํ์ฌ ๋์ ๋ง์ธ๋๋งต์ ๋ง๋์ธ์. ๋
ธ๋ ์ถ๊ฐ/์ญ์ , ๋๋๊ทธ ์ค ๋๋กญ, ํ์ฅ/์ถ์ ์ ๋๋ฉ์ด์
์ ๊ตฌํํ์ธ์."
|
459 |
+
},
|
460 |
+
|
461 |
+
|
462 |
+
{
|
463 |
+
"name": "[๋๊ตฌ] ํจํด ๋์์ด๋",
|
464 |
+
"image_url": "data:image/png;base64," + get_image_base64('133.png'),
|
465 |
+
"prompt": "SVG๋ก ๋ฐ๋ณต ํจํด์ ๋์์ธํ๋ ๋๊ตฌ๋ฅผ ๋ง๋์ธ์. ๋์นญ ์ต์
, ์์ ์คํค๋ง ๊ด๋ฆฌ, ์ค์๊ฐ ํ๋ฆฌ๋ทฐ๋ฅผ ๊ตฌํํ์ธ์."
|
466 |
+
},
|
467 |
+
{
|
468 |
+
"name": "[๋ฉํฐ๋ฏธ๋์ด] ์ค์๊ฐ ํํฐ ์นด๋ฉ๋ผ",
|
469 |
+
"image_url": "data:image/png;base64," + get_image_base64('134.png'),
|
470 |
+
"prompt": "WebRTC์ Canvas๋ฅผ ์ฌ์ฉํ์ฌ ์ค์๊ฐ ๋น๋์ค ํํฐ ์ฑ์ ๋ง๋์ธ์. ๋ค์ํ ์ด๋ฏธ์ง ์ฒ๋ฆฌ ํจ๊ณผ๋ฅผ ๊ตฌํํ์ธ์."
|
471 |
+
},
|
472 |
+
|
473 |
+
{
|
474 |
+
"name": "[์๊ฐํ] ์ค์๊ฐ ๋ฐ์ดํฐ ํ๋ก์ฐ",
|
475 |
+
"image_url": "data:image/png;base64," + get_image_base64('136.png'),
|
476 |
+
"prompt": "D3.js๋ก ์ค์๊ฐ ๋ฐ์ดํฐ ํ๋ฆ์ ์๊ฐํํ์ธ์. ๋
ธ๋ ๊ธฐ๋ฐ ๋ฐ์ดํฐ ์ฒ๋ฆฌ์ ์ ๋๋ฉ์ด์
ํจ๊ณผ๋ฅผ ๊ตฌํํ์ธ์."
|
477 |
+
},
|
478 |
+
{
|
479 |
+
"name": "[์ธํฐ๋ํฐ๋ธ] ์ปฌ๋ฌ ํ๋ ํธ",
|
480 |
+
"image_url": "data:image/png;base64," + get_image_base64('113.png'),
|
481 |
+
"prompt": "๋ง์ฐ์ค ์์ง์์ ๋ฐ๋ผ ๋์ ์ผ๋ก ๋ณํ๋ ์ปฌ๋ฌ ํ๋ ํธ๋ฅผ ๋ง๋์ธ์. ์์ ์ ํ, ์ ์ฅ, ์กฐํฉ ๊ธฐ๋ฅ๊ณผ ํจ๊ป ๋ถ๋๋ฌ์ด ๊ทธ๋ผ๋ฐ์ด์
ํจ๊ณผ๋ฅผ ๊ตฌํํ์ธ์."
|
482 |
+
},
|
483 |
+
{
|
484 |
+
"name": "[์ดํํธ] ํํฐํด ์ปค์",
|
485 |
+
"image_url": "data:image/png;base64," + get_image_base64('121.png'),
|
486 |
+
"prompt": "๋ง์ฐ์ค ์ปค์๋ฅผ ๋ฐ๋ผ๋ค๋๋ ํํฐํด ํจ๊ณผ๋ฅผ ๋ง๋์ธ์. ๋ค์ํ ํํฐํด ํจํด๊ณผ ์์ ๋ณํ๋ฅผ ๊ตฌํํ์ธ์."
|
487 |
+
},
|
488 |
+
|
489 |
+
{
|
490 |
+
"name": "[ํํ์ด์ง] AI ์คํํธ์
",
|
491 |
+
"image_url": "data:image/gif;base64," + get_image_base64('mouse.gif'), # mouse.gif ์ฌ์ฉ
|
492 |
+
"prompt": "๋๋ฉ ํ์ด์ง๋ฅผ ๋ง๋ค์ด๋ผ. ์ ๋ฌธ๊ฐ ์ ์ ํํ์ ๋ฉ์ง ๋น์ฃผ์ผ๋ก ๊ตฌ์ฑ,์ด๋ชจ์ง๋ฅผ ์ ์ ํ ํ์ฉํ๊ณ ๋ค์์ ๋ด์ฉ์ ์ฐธ๊ณ ํ์ฌ ๋ฐ์ํ๋๋ก ํ๋ผ.๋ง์ฐ์ค-I๋ ์ฌ์ฉ์๊ฐ ์ํ๋ ์น ์๋น์ค๋ฅผ ํ๋กฌํํธ๋ก ์
๋ ฅํ๋ฉด 60์ด ์ด๋ด์ ์ค์ ์๋ํ๋ ์น ์๋น์ค๋ฅผ ์๋ ์์ฑํ๋ ๋๊ตฌ๋ค. ๋ง์ฐ์ค-I์ ์ฃผ์ ๊ธฐ๋ฅ์ โฒ์ํด๋ฆญ ์ค์๊ฐ ๋ฐฐํฌ โฒ์ค์๊ฐ ๋ฏธ๋ฆฌ๋ณด๊ธฐ โฒ40์ฌ ๊ฐ์ง ์ฆ์ ์ ์ฉ ํ
ํ๋ฆฟ โฒ์ค์๊ฐ ์์ ๋ฑ์ด๋ค. MBTI ํ
์คํธ, ํฌ์ ๊ด๋ฆฌ ๋๊ตฌ, ํ
ํธ๋ฆฌ์ค ๊ฒ์ ๋ฑ ๋ค์ํ ํ
ํ๋ฆฟ์ ์ ๊ณตํด ๋น๊ฐ๋ฐ์๋ ์ฆ์ ํ์ฉํ ์ ์๋ค."
|
493 |
+
}
|
494 |
+
]
|
495 |
+
|
496 |
+
def load_best_templates():
|
497 |
+
json_data = load_json_data()[:12] # ๋ฒ ์คํธ ํ
ํ๋ฆฟ
|
498 |
+
return create_template_html("๐ ๋ฒ ์คํธ ํ
ํ๋ฆฟ", json_data)
|
499 |
+
|
500 |
+
def load_trending_templates():
|
501 |
+
json_data = load_json_data()[12:24] # ํธ๋ ๋ฉ ํ
ํ๋ฆฟ
|
502 |
+
return create_template_html("๐ฅ ํธ๋ ๋ฉ ํ
ํ๋ฆฟ", json_data)
|
503 |
+
|
504 |
+
def load_new_templates():
|
505 |
+
json_data = load_json_data()[24:44] # NEW ํ
ํ๋ฆฟ
|
506 |
+
return create_template_html("โจ NEW ํ
ํ๋ฆฟ", json_data)
|
507 |
+
|
508 |
+
def create_template_html(title, items):
|
509 |
+
html_content = """
|
510 |
+
<style>
|
511 |
+
.prompt-grid {
|
512 |
+
display: grid;
|
513 |
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
514 |
+
gap: 20px;
|
515 |
+
padding: 20px;
|
516 |
+
}
|
517 |
+
.prompt-card {
|
518 |
+
background: white;
|
519 |
+
border: 1px solid #eee;
|
520 |
+
border-radius: 8px;
|
521 |
+
padding: 15px;
|
522 |
+
cursor: pointer;
|
523 |
+
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
524 |
+
}
|
525 |
+
.prompt-card:hover {
|
526 |
+
transform: translateY(-2px);
|
527 |
+
transition: transform 0.2s;
|
528 |
+
}
|
529 |
+
.card-image {
|
530 |
+
width: 100%;
|
531 |
+
height: 180px;
|
532 |
+
object-fit: cover;
|
533 |
+
border-radius: 4px;
|
534 |
+
margin-bottom: 10px;
|
535 |
+
}
|
536 |
+
.card-name {
|
537 |
+
font-weight: bold;
|
538 |
+
margin-bottom: 8px;
|
539 |
+
font-size: 16px;
|
540 |
+
color: #333;
|
541 |
+
}
|
542 |
+
.card-prompt {
|
543 |
+
font-size: 11px;
|
544 |
+
line-height: 1.4;
|
545 |
+
color: #666;
|
546 |
+
display: -webkit-box;
|
547 |
+
-webkit-line-clamp: 6;
|
548 |
+
-webkit-box-orient: vertical;
|
549 |
+
overflow: hidden;
|
550 |
+
height: 90px;
|
551 |
+
background-color: #f8f9fa;
|
552 |
+
padding: 8px;
|
553 |
+
border-radius: 4px;
|
554 |
+
}
|
555 |
+
</style>
|
556 |
+
<div class="prompt-grid">
|
557 |
+
"""
|
558 |
+
|
559 |
+
for item in items:
|
560 |
+
html_content += f"""
|
561 |
+
<div class="prompt-card" onclick="copyToInput(this)" data-prompt="{html.escape(item.get('prompt', ''))}">
|
562 |
+
<img src="{item.get('image_url', '')}" class="card-image" loading="lazy" alt="{html.escape(item.get('name', ''))}">
|
563 |
+
<div class="card-name">{html.escape(item.get('name', ''))}</div>
|
564 |
+
<div class="card-prompt">{html.escape(item.get('prompt', ''))}</div>
|
565 |
+
</div>
|
566 |
+
"""
|
567 |
+
|
568 |
+
html_content += """
|
569 |
+
<script>
|
570 |
+
function copyToInput(card) {
|
571 |
+
const prompt = card.dataset.prompt;
|
572 |
+
const textarea = document.querySelector('.ant-input-textarea-large textarea');
|
573 |
+
if (textarea) {
|
574 |
+
textarea.value = prompt;
|
575 |
+
textarea.dispatchEvent(new Event('input', { bubbles: true }));
|
576 |
+
document.querySelector('.session-drawer .close-btn').click();
|
577 |
+
}
|
578 |
+
}
|
579 |
+
</script>
|
580 |
+
</div>
|
581 |
+
"""
|
582 |
+
return gr.HTML(value=html_content)
|
583 |
+
|
584 |
+
|
585 |
+
# ์ ์ญ ๋ณ์๋ก ํ
ํ๋ฆฟ ๋ฐ์ดํฐ ์บ์
|
586 |
+
TEMPLATE_CACHE = None
|
587 |
+
|
588 |
+
def load_session_history(template_type="best"):
|
589 |
+
global TEMPLATE_CACHE
|
590 |
+
|
591 |
+
try:
|
592 |
+
json_data = load_json_data()
|
593 |
+
|
594 |
+
# ๋ฐ์ดํฐ๋ฅผ ์ธ ์น์
์ผ๋ก ๋๋๊ธฐ
|
595 |
+
templates = {
|
596 |
+
"best": json_data[:12], # ๋ฒ ์คํธ ํ
ํ๋ฆฟ
|
597 |
+
"trending": json_data[12:24], # ํธ๋ ๋ฉ ํ
ํ๋ฆฟ
|
598 |
+
"new": json_data[24:44] # NEW ํ
ํ๋ฆฟ
|
599 |
+
}
|
600 |
+
|
601 |
+
titles = {
|
602 |
+
"best": "๐ ๋ฒ ์คํธ ํ
ํ๋ฆฟ",
|
603 |
+
"trending": "๐ฅ ํธ๋ ๋ฉ ํ
ํ๋ฆฟ",
|
604 |
+
"new": "โจ NEW ํ
ํ๋ฆฟ"
|
605 |
+
}
|
606 |
+
|
607 |
+
html_content = """
|
608 |
+
<style>
|
609 |
+
.template-nav {
|
610 |
+
display: flex;
|
611 |
+
gap: 10px;
|
612 |
+
margin: 20px;
|
613 |
+
position: sticky;
|
614 |
+
top: 0;
|
615 |
+
background: white;
|
616 |
+
z-index: 100;
|
617 |
+
padding: 10px 0;
|
618 |
+
border-bottom: 1px solid #eee;
|
619 |
+
}
|
620 |
+
.template-btn {
|
621 |
+
padding: 8px 16px;
|
622 |
+
border: 1px solid #1890ff;
|
623 |
+
border-radius: 4px;
|
624 |
+
cursor: pointer;
|
625 |
+
background: white;
|
626 |
+
color: #1890ff;
|
627 |
+
font-weight: bold;
|
628 |
+
transition: all 0.3s;
|
629 |
+
}
|
630 |
+
.template-btn:hover {
|
631 |
+
background: #1890ff;
|
632 |
+
color: white;
|
633 |
+
}
|
634 |
+
.template-btn.active {
|
635 |
+
background: #1890ff;
|
636 |
+
color: white;
|
637 |
+
}
|
638 |
+
.prompt-grid {
|
639 |
+
display: grid;
|
640 |
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
641 |
+
gap: 20px;
|
642 |
+
padding: 20px;
|
643 |
+
}
|
644 |
+
.prompt-card {
|
645 |
+
background: white;
|
646 |
+
border: 1px solid #eee;
|
647 |
+
border-radius: 8px;
|
648 |
+
padding: 15px;
|
649 |
+
cursor: pointer;
|
650 |
+
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
651 |
+
}
|
652 |
+
.prompt-card:hover {
|
653 |
+
transform: translateY(-2px);
|
654 |
+
transition: transform 0.2s;
|
655 |
+
}
|
656 |
+
.card-image {
|
657 |
+
width: 100%;
|
658 |
+
height: 180px;
|
659 |
+
object-fit: cover;
|
660 |
+
border-radius: 4px;
|
661 |
+
margin-bottom: 10px;
|
662 |
+
}
|
663 |
+
.card-name {
|
664 |
+
font-weight: bold;
|
665 |
+
margin-bottom: 8px;
|
666 |
+
font-size: 16px;
|
667 |
+
color: #333;
|
668 |
+
}
|
669 |
+
.card-prompt {
|
670 |
+
font-size: 11px;
|
671 |
+
line-height: 1.4;
|
672 |
+
color: #666;
|
673 |
+
display: -webkit-box;
|
674 |
+
-webkit-line-clamp: 6;
|
675 |
+
-webkit-box-orient: vertical;
|
676 |
+
overflow: hidden;
|
677 |
+
height: 90px;
|
678 |
+
background-color: #f8f9fa;
|
679 |
+
padding: 8px;
|
680 |
+
border-radius: 4px;
|
681 |
+
}
|
682 |
+
.template-section {
|
683 |
+
display: none;
|
684 |
+
}
|
685 |
+
.template-section.active {
|
686 |
+
display: block;
|
687 |
+
}
|
688 |
+
</style>
|
689 |
+
<div class="template-nav">
|
690 |
+
<button class="template-btn" onclick="showTemplate('best')">๐ ๋ฒ ์คํธ</button>
|
691 |
+
<button class="template-btn" onclick="showTemplate('trending')">๐ฅ ํธ๋ ๋ฉ</button>
|
692 |
+
<button class="template-btn" onclick="showTemplate('new')">โจ NEW</button>
|
693 |
+
</div>
|
694 |
+
"""
|
695 |
+
|
696 |
+
# ๊ฐ ์น์
์ ํ
ํ๋ฆฟ ์์ฑ
|
697 |
+
for section, items in templates.items():
|
698 |
+
html_content += f"""
|
699 |
+
<div class="template-section" id="{section}-templates">
|
700 |
+
<div class="prompt-grid">
|
701 |
+
"""
|
702 |
+
for item in items:
|
703 |
+
html_content += f"""
|
704 |
+
<div class="prompt-card" onclick="copyToInput(this)" data-prompt="{html.escape(item.get('prompt', ''))}">
|
705 |
+
<img src="{item.get('image_url', '')}" class="card-image" loading="lazy" alt="{html.escape(item.get('name', ''))}">
|
706 |
+
<div class="card-name">{html.escape(item.get('name', ''))}</div>
|
707 |
+
<div class="card-prompt">{html.escape(item.get('prompt', ''))}</div>
|
708 |
+
</div>
|
709 |
+
"""
|
710 |
+
html_content += "</div></div>"
|
711 |
+
|
712 |
+
html_content += """
|
713 |
+
<script>
|
714 |
+
function copyToInput(card) {
|
715 |
+
const prompt = card.dataset.prompt;
|
716 |
+
const textarea = document.querySelector('.ant-input-textarea-large textarea');
|
717 |
+
if (textarea) {
|
718 |
+
textarea.value = prompt;
|
719 |
+
textarea.dispatchEvent(new Event('input', { bubbles: true }));
|
720 |
+
document.querySelector('.session-drawer .close-btn').click();
|
721 |
+
}
|
722 |
+
}
|
723 |
+
|
724 |
+
function showTemplate(type) {
|
725 |
+
// ๋ชจ๋ ์น์
์จ๊ธฐ๊ธฐ
|
726 |
+
document.querySelectorAll('.template-section').forEach(section => {
|
727 |
+
section.style.display = 'none';
|
728 |
+
});
|
729 |
+
// ๋ชจ๋ ๋ฒํผ ๋นํ์ฑํ
|
730 |
+
document.querySelectorAll('.template-btn').forEach(btn => {
|
731 |
+
btn.classList.remove('active');
|
732 |
+
});
|
733 |
+
|
734 |
+
// ์ ํ๋ ์น์
๋ณด์ด๊ธฐ
|
735 |
+
document.getElementById(type + '-templates').style.display = 'block';
|
736 |
+
// ์ ํ๋ ๋ฒํผ ํ์ฑํ
|
737 |
+
event.target.classList.add('active');
|
738 |
+
}
|
739 |
+
|
740 |
+
// ์ด๊ธฐ ๋ก๋์ ๋ฒ ์คํธ ํ
ํ๋ฆฟ ํ์
|
741 |
+
document.addEventListener('DOMContentLoaded', function() {
|
742 |
+
showTemplate('best');
|
743 |
+
document.querySelector('.template-btn').classList.add('active');
|
744 |
+
});
|
745 |
+
</script>
|
746 |
+
"""
|
747 |
+
|
748 |
+
return gr.HTML(value=html_content)
|
749 |
+
|
750 |
+
except Exception as e:
|
751 |
+
print(f"Error in load_session_history: {str(e)}")
|
752 |
+
return gr.HTML("Error loading templates")
|
753 |
+
|
754 |
+
|
755 |
+
|
756 |
+
|
757 |
+
|
758 |
+
# ๋ฐฐํฌ ๊ด๋ จ ํจ์ ์ถ๊ฐ
|
759 |
+
def generate_space_name():
|
760 |
+
"""6์๋ฆฌ ๋๋ค ์๋ฌธ ์ด๋ฆ ์์ฑ"""
|
761 |
+
letters = string.ascii_lowercase
|
762 |
+
return ''.join(random.choice(letters) for i in range(6))
|
763 |
+
|
764 |
+
def deploy_to_vercel(code: str):
|
765 |
+
try:
|
766 |
+
token = "A8IFZmgW2cqA4yUNlLPnci0N"
|
767 |
+
if not token:
|
768 |
+
return "Vercel ํ ํฐ์ด ์ค์ ๋์ง ์์์ต๋๋ค."
|
769 |
+
|
770 |
+
# 6์๋ฆฌ ์๋ฌธ ํ๋ก์ ํธ ์ด๋ฆ ์์ฑ
|
771 |
+
project_name = ''.join(random.choice(string.ascii_lowercase) for i in range(6))
|
772 |
+
|
773 |
+
|
774 |
+
# Vercel API ์๋ํฌ์ธํธ
|
775 |
+
deploy_url = "https://api.vercel.com/v13/deployments"
|
776 |
+
|
777 |
+
# ํค๋ ์ค์
|
778 |
+
headers = {
|
779 |
+
"Authorization": f"Bearer {token}",
|
780 |
+
"Content-Type": "application/json"
|
781 |
+
}
|
782 |
+
|
783 |
+
# package.json ํ์ผ ์์ฑ
|
784 |
+
package_json = {
|
785 |
+
"name": project_name,
|
786 |
+
"version": "1.0.0",
|
787 |
+
"private": True, # true -> True๋ก ์์
|
788 |
+
"dependencies": {
|
789 |
+
"vite": "^5.0.0"
|
790 |
+
},
|
791 |
+
"scripts": {
|
792 |
+
"dev": "vite",
|
793 |
+
"build": "echo 'No build needed' && mkdir -p dist && cp index.html dist/",
|
794 |
+
"preview": "vite preview"
|
795 |
+
}
|
796 |
+
}
|
797 |
+
|
798 |
+
# ๋ฐฐํฌํ ํ์ผ ๋ฐ์ดํฐ ๊ตฌ์กฐ
|
799 |
+
files = [
|
800 |
+
{
|
801 |
+
"file": "index.html",
|
802 |
+
"data": code
|
803 |
+
},
|
804 |
+
{
|
805 |
+
"file": "package.json",
|
806 |
+
"data": json.dumps(package_json, indent=2) # indent ์ถ๊ฐ๋ก ๊ฐ๋
์ฑ ํฅ์
|
807 |
+
}
|
808 |
+
]
|
809 |
+
|
810 |
+
# ํ๋ก์ ํธ ์ค์
|
811 |
+
project_settings = {
|
812 |
+
"buildCommand": "npm run build",
|
813 |
+
"outputDirectory": "dist",
|
814 |
+
"installCommand": "npm install",
|
815 |
+
"framework": None
|
816 |
+
}
|
817 |
+
|
818 |
+
# ๋ฐฐํฌ ์์ฒญ ๋ฐ์ดํฐ
|
819 |
+
deploy_data = {
|
820 |
+
"name": project_name,
|
821 |
+
"files": files,
|
822 |
+
"target": "production",
|
823 |
+
"projectSettings": project_settings
|
824 |
+
}
|
825 |
+
|
826 |
+
|
827 |
+
deploy_response = requests.post(deploy_url, headers=headers, json=deploy_data)
|
828 |
+
|
829 |
+
if deploy_response.status_code != 200:
|
830 |
+
return f"๋ฐฐํฌ ์คํจ: {deploy_response.text}"
|
831 |
+
|
832 |
+
# URL ํ์ ์์ - 6์๋ฆฌ.vercel.app ํํ๋ก ๋ฐํ
|
833 |
+
deployment_url = f"{project_name}.vercel.app"
|
834 |
+
|
835 |
+
time.sleep(5)
|
836 |
+
|
837 |
+
return f"""๋ฐฐํฌ ์๋ฃ! <a href="https://{deployment_url}" target="_blank" style="color: #1890ff; text-decoration: underline; cursor: pointer;">https://{deployment_url}</a>"""
|
838 |
+
|
839 |
+
except Exception as e:
|
840 |
+
return f"๋ฐฐํฌ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}"
|
841 |
+
|
842 |
+
|
843 |
+
# ํ๋กฌํํธ ์ฆ๊ฐ ํจ์ ์์
|
844 |
+
def boost_prompt(prompt: str) -> str:
|
845 |
+
if not prompt:
|
846 |
+
return ""
|
847 |
+
|
848 |
+
# ์ฆ๊ฐ์ ์ํ ์์คํ
ํ๋กฌํํธ
|
849 |
+
boost_system_prompt = """
|
850 |
+
๋น์ ์ ์น ๊ฐ๋ฐ ํ๋กฌํํธ ์ ๋ฌธ๊ฐ์
๋๋ค.
|
851 |
+
์ฃผ์ด์ง ํ๋กฌํํธ๋ฅผ ๋ถ์ํ์ฌ ๋ ์์ธํ๊ณ ์ ๋ฌธ์ ์ธ ์๊ตฌ์ฌํญ์ผ๋ก ํ์ฅํ๋,
|
852 |
+
์๋ ์๋์ ๋ชฉ์ ์ ๊ทธ๋๋ก ์ ์งํ๋ฉด์ ๋ค์ ๊ด์ ๋ค์ ๊ณ ๋ คํ์ฌ ์ฆ๊ฐํ์ญ์์ค:
|
853 |
+
1. ๊ธฐ์ ์ ๊ตฌํ ์์ธ
|
854 |
+
2. UI/UX ๋์์ธ ์์
|
855 |
+
3. ์ฌ์ฉ์ ๊ฒฝํ ์ต์ ํ
|
856 |
+
4. ์ฑ๋ฅ๊ณผ ๋ณด์
|
857 |
+
5. ์ ๊ทผ์ฑ๊ณผ ํธํ์ฑ
|
858 |
+
|
859 |
+
๊ธฐ์กด SystemPrompt์ ๋ชจ๋ ๊ท์น์ ์ค์ํ๋ฉด์ ์ฆ๊ฐ๋ ํ๋กฌํํธ๋ฅผ ์์ฑํ์ญ์์ค.
|
860 |
+
"""
|
861 |
+
|
862 |
+
try:
|
863 |
+
# Claude API ์๋
|
864 |
+
try:
|
865 |
+
response = claude_client.messages.create(
|
866 |
+
model="claude-3-5-sonnet-20241022",
|
867 |
+
max_tokens=2000,
|
868 |
+
messages=[{
|
869 |
+
"role": "user",
|
870 |
+
"content": f"๋ค์ ํ๋กฌํํธ๋ฅผ ๋ถ์ํ๊ณ ์ฆ๊ฐํ์์ค: {prompt}"
|
871 |
+
}]
|
872 |
+
)
|
873 |
+
|
874 |
+
if hasattr(response, 'content') and len(response.content) > 0:
|
875 |
+
return response.content[0].text
|
876 |
+
raise Exception("Claude API ์๋ต ํ์ ์ค๋ฅ")
|
877 |
+
|
878 |
+
except Exception as claude_error:
|
879 |
+
print(f"Claude API ์๋ฌ, OpenAI๋ก ์ ํ: {str(claude_error)}")
|
880 |
+
|
881 |
+
# OpenAI API ์๋
|
882 |
+
completion = openai_client.chat.completions.create(
|
883 |
+
model="gpt-4",
|
884 |
+
messages=[
|
885 |
+
{"role": "system", "content": boost_system_prompt},
|
886 |
+
{"role": "user", "content": f"๋ค์ ํ๋กฌํํธ๋ฅผ ๋ถ์ํ๊ณ ์ฆ๊ฐํ์์ค: {prompt}"}
|
887 |
+
],
|
888 |
+
max_tokens=2000,
|
889 |
+
temperature=0.7
|
890 |
+
)
|
891 |
+
|
892 |
+
if completion.choices and len(completion.choices) > 0:
|
893 |
+
return completion.choices[0].message.content
|
894 |
+
raise Exception("OpenAI API ์๋ต ํ์ ์ค๋ฅ")
|
895 |
+
|
896 |
+
except Exception as e:
|
897 |
+
print(f"ํ๋กฌํํธ ์ฆ๊ฐ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}")
|
898 |
+
return prompt # ์ค๋ฅ ๋ฐ์์ ์๋ณธ ํ๋กฌํํธ ๋ฐํ
|
899 |
+
|
900 |
+
# Boost ๋ฒํผ ์ด๋ฒคํธ ํธ๋ค๋ฌ
|
901 |
+
def handle_boost(prompt: str):
|
902 |
+
try:
|
903 |
+
boosted_prompt = boost_prompt(prompt)
|
904 |
+
return boosted_prompt, gr.update(active_key="empty")
|
905 |
+
except Exception as e:
|
906 |
+
print(f"Boost ์ฒ๋ฆฌ ์ค ์ค๋ฅ: {str(e)}")
|
907 |
+
return prompt, gr.update(active_key="empty")
|
908 |
+
|
909 |
+
|
910 |
+
# Demo ์ธ์คํด์ค ์์ฑ
|
911 |
+
demo_instance = Demo()
|
912 |
+
|
913 |
+
|
914 |
+
|
915 |
+
|
916 |
+
|
917 |
+
|
918 |
+
|
919 |
+
|
920 |
+
|
921 |
+
|
922 |
+
|
923 |
+
|
924 |
+
|
925 |
|
926 |
def take_screenshot(url):
|
927 |
"""์น์ฌ์ดํธ ์คํฌ๋ฆฐ์ท ์ดฌ์ ํจ์ (๋ก๋ฉ ๋๊ธฐ ์๊ฐ ์ถ๊ฐ)"""
|
|
|
1740 |
def create_main_interface():
|
1741 |
"""๋ฉ์ธ ์ธํฐํ์ด์ค ์์ฑ ํจ์"""
|
1742 |
|
1743 |
+
with gr.Blocks(css="""
|
|
|
|
|
|
|
|
|
|
|
|
|
1744 |
.main-tabs > div.tab-nav > button {
|
1745 |
font-size: 1.1em !important;
|
1746 |
padding: 0.5em 1em !important;
|
|
|
1758 |
border-radius: 0 0 15px 15px !important;
|
1759 |
box-shadow: 0 4px 15px rgba(0,0,0,0.1) !important;
|
1760 |
}
|
1761 |
+
""", theme=theme) as demo:
|
|
|
|
|
1762 |
with gr.Tabs(elem_classes="main-tabs") as tabs:
|
1763 |
+
# ๊ฐค๋ฌ๋ฆฌ ํญ
|
1764 |
with gr.Tab("๊ฐค๋ฌ๋ฆฌ", elem_id="gallery-tab"):
|
1765 |
gr.HTML(value=get_user_spaces())
|
1766 |
|
1767 |
+
# MOUSE ํญ
|
1768 |
with gr.Tab("MOUSE", elem_id="mouse-tab"):
|
1769 |
+
history = gr.State([])
|
1770 |
+
setting = gr.State({
|
1771 |
+
"system": SystemPrompt,
|
1772 |
+
})
|
1773 |
+
|
1774 |
+
with ms.Application() as app:
|
1775 |
+
with antd.ConfigProvider():
|
1776 |
+
# Drawer ์ปดํฌ๋ํธ๋ค
|
1777 |
+
with antd.Drawer(open=False, title="code", placement="left", width="750px") as code_drawer:
|
1778 |
+
code_output = legacy.Markdown()
|
1779 |
+
|
1780 |
+
with antd.Drawer(open=False, title="history", placement="left", width="900px") as history_drawer:
|
1781 |
+
history_output = legacy.Chatbot(show_label=False, flushing=False, height=960, elem_classes="history_chatbot")
|
1782 |
+
|
1783 |
+
with antd.Drawer(
|
1784 |
+
open=False,
|
1785 |
+
title="Templates",
|
1786 |
+
placement="right",
|
1787 |
+
width="900px",
|
1788 |
+
elem_classes="session-drawer"
|
1789 |
+
) as session_drawer:
|
1790 |
+
with antd.Flex(vertical=True, gap="middle"):
|
1791 |
+
gr.Markdown("### Available Templates")
|
1792 |
+
session_history = gr.HTML(
|
1793 |
+
elem_classes="session-history"
|
1794 |
+
)
|
1795 |
+
close_btn = antd.Button(
|
1796 |
+
"Close",
|
1797 |
+
type="default",
|
1798 |
+
elem_classes="close-btn"
|
1799 |
+
)
|
1800 |
+
|
1801 |
+
# ๋ฉ์ธ ์ปจํ
์ธ ๋ฅผ ์ํ Row
|
1802 |
+
with antd.Row(gutter=[32, 12]) as layout:
|
1803 |
+
# ์ข์ธก ํจ๋
|
1804 |
+
with antd.Col(span=24, md=8):
|
1805 |
+
with antd.Flex(vertical=True, gap="middle", wrap=True):
|
1806 |
+
# ํค๋ ๋ถ๋ถ
|
1807 |
+
header = gr.HTML(f"""
|
1808 |
+
<div class="left_header">
|
1809 |
+
<img src="data:image/gif;base64,{get_image_base64('mouse.gif')}" width="360px" />
|
1810 |
+
<h1 style="font-size: 18px;">๊ณ ์์ด๋ ๋ฐ๋ก ์ฝ๋ฉํ๋ 'MOUSE-I'</h2>
|
1811 |
+
<h1 style="font-size: 10px;">ํ
ํ๋ฆฟ์ ํ๋กฌํํธ๋ฅผ ๋ณต์ฌํ์ฌ ๋ถ์ฌ๋ฃ๊ณ Send ํด๋ฆญ์ ์๋์ผ๋ก ์ฝ๋๊ฐ ์์ฑ๋ฉ๋๋ค...</h1>
|
1812 |
+
</div>
|
1813 |
+
""")
|
1814 |
+
|
1815 |
+
# ์
๋ ฅ ์์ญ
|
1816 |
+
input = antd.InputTextarea(
|
1817 |
+
size="large",
|
1818 |
+
allow_clear=True,
|
1819 |
+
placeholder=random.choice(DEMO_LIST)['description']
|
1820 |
+
)
|
1821 |
+
|
1822 |
+
# ๋ฒํผ ๊ทธ๋ฃน
|
1823 |
+
with antd.Flex(gap="small", justify="space-between"):
|
1824 |
+
btn = antd.Button("Send", type="primary", size="large")
|
1825 |
+
boost_btn = antd.Button("Boost", type="default", size="large")
|
1826 |
+
execute_btn = antd.Button("Code์คํ", type="default", size="large")
|
1827 |
+
deploy_btn = antd.Button("๋ฐฐํฌ", type="default", size="large")
|
1828 |
+
clear_btn = antd.Button("ํด๋ฆฌ์ด", type="default", size="large")
|
1829 |
+
|
1830 |
+
deploy_result = gr.HTML(label="๋ฐฐํฌ ๊ฒฐ๊ณผ")
|
1831 |
+
|
1832 |
+
# ์ฐ์ธก ํจ๋
|
1833 |
+
with antd.Col(span=24, md=16):
|
1834 |
+
with ms.Div(elem_classes="right_panel"):
|
1835 |
+
# ์๋จ ๋ฒํผ๋ค
|
1836 |
+
with antd.Flex(gap="small", elem_classes="setting-buttons"):
|
1837 |
+
codeBtn = antd.Button("๐งโ๐ป ์ฝ๋ ๋ณด๊ธฐ", type="default")
|
1838 |
+
historyBtn = antd.Button("๐ ํ์คํ ๋ฆฌ", type="default")
|
1839 |
+
best_btn = antd.Button("๐ ๋ฒ ์คํธ ํ
ํ๋ฆฟ", type="default")
|
1840 |
+
trending_btn = antd.Button("๐ฅ ํธ๋ ๋ฉ ํ
ํ๋ฆฟ", type="default")
|
1841 |
+
new_btn = antd.Button("โจ NEW ํ
ํ๋ฆฟ", type="default")
|
1842 |
+
|
1843 |
+
gr.HTML('<div class="render_header"><span class="header_btn"></span><span class="header_btn"></span><span class="header_btn"></span></div>')
|
1844 |
+
|
1845 |
+
# ํญ ์ปจํ
์ธ
|
1846 |
+
with antd.Tabs(active_key="empty", render_tab_bar="() => null") as state_tab:
|
1847 |
+
with antd.Tabs.Item(key="empty"):
|
1848 |
+
empty = antd.Empty(description="empty input", elem_classes="right_content")
|
1849 |
+
with antd.Tabs.Item(key="loading"):
|
1850 |
+
loading = antd.Spin(True, tip="coding...", size="large", elem_classes="right_content")
|
1851 |
+
with antd.Tabs.Item(key="render"):
|
1852 |
+
sandbox = gr.HTML(elem_classes="html_content")
|
1853 |
+
|
1854 |
+
|
1855 |
+
|
1856 |
+
|
1857 |
+
# Code ์คํ ๋ฒํผ ์ด๋ฒคํธ ํธ๋ค๋ฌ ํจ์ ์ ์
|
1858 |
+
def execute_code(query: str):
|
1859 |
+
if not query or query.strip() == '':
|
1860 |
+
return None, gr.update(active_key="empty")
|
1861 |
+
|
1862 |
+
try:
|
1863 |
+
# HTML ์ฝ๋ ๋ธ๋ก ํ์ธ
|
1864 |
+
if '```html' in query and '```' in query:
|
1865 |
+
# HTML ์ฝ๋ ๋ธ๋ก ์ถ์ถ
|
1866 |
+
code = remove_code_block(query)
|
1867 |
+
else:
|
1868 |
+
# ์
๋ ฅ๋ ํ
์คํธ๋ฅผ ๊ทธ๋๋ก ์ฝ๋๋ก ์ฌ์ฉ
|
1869 |
+
code = query.strip()
|
1870 |
+
|
1871 |
+
return send_to_sandbox(code), gr.update(active_key="render")
|
1872 |
+
except Exception as e:
|
1873 |
+
print(f"Error executing code: {str(e)}")
|
1874 |
+
return None, gr.update(active_key="empty")
|
1875 |
+
|
1876 |
+
# ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ค
|
1877 |
+
execute_btn.click(
|
1878 |
+
fn=execute_code,
|
1879 |
+
inputs=[input],
|
1880 |
+
outputs=[sandbox, state_tab]
|
1881 |
+
)
|
1882 |
+
|
1883 |
+
codeBtn.click(
|
1884 |
+
lambda: gr.update(open=True),
|
1885 |
+
inputs=[],
|
1886 |
+
outputs=[code_drawer]
|
1887 |
+
)
|
1888 |
+
|
1889 |
+
code_drawer.close(
|
1890 |
+
lambda: gr.update(open=False),
|
1891 |
+
inputs=[],
|
1892 |
+
outputs=[code_drawer]
|
1893 |
+
)
|
1894 |
+
|
1895 |
+
historyBtn.click(
|
1896 |
+
history_render,
|
1897 |
+
inputs=[history],
|
1898 |
+
outputs=[history_drawer, history_output]
|
1899 |
+
)
|
1900 |
+
|
1901 |
+
history_drawer.close(
|
1902 |
+
lambda: gr.update(open=False),
|
1903 |
+
inputs=[],
|
1904 |
+
outputs=[history_drawer]
|
1905 |
+
)
|
1906 |
+
|
1907 |
+
# ํ
ํ๋ฆฟ ๋ฒํผ ์ด๋ฒคํธ ํธ๋ค๋ฌ
|
1908 |
+
best_btn.click(
|
1909 |
+
fn=lambda: (gr.update(open=True), load_best_templates()),
|
1910 |
+
outputs=[session_drawer, session_history],
|
1911 |
+
queue=False
|
1912 |
+
)
|
1913 |
+
|
1914 |
+
trending_btn.click(
|
1915 |
+
fn=lambda: (gr.update(open=True), load_trending_templates()),
|
1916 |
+
outputs=[session_drawer, session_history],
|
1917 |
+
queue=False
|
1918 |
+
)
|
1919 |
+
|
1920 |
+
new_btn.click(
|
1921 |
+
fn=lambda: (gr.update(open=True), load_new_templates()),
|
1922 |
+
outputs=[session_drawer, session_history],
|
1923 |
+
queue=False
|
1924 |
+
)
|
1925 |
+
|
1926 |
+
session_drawer.close(
|
1927 |
+
lambda: (gr.update(open=False), gr.HTML("")),
|
1928 |
+
outputs=[session_drawer, session_history]
|
1929 |
+
)
|
1930 |
+
|
1931 |
+
close_btn.click(
|
1932 |
+
lambda: (gr.update(open=False), gr.HTML("")),
|
1933 |
+
outputs=[session_drawer, session_history]
|
1934 |
+
)
|
1935 |
+
|
1936 |
+
btn.click(
|
1937 |
+
demo_instance.generation_code,
|
1938 |
+
inputs=[input, setting, history],
|
1939 |
+
outputs=[code_output, history, sandbox, state_tab, code_drawer]
|
1940 |
+
)
|
1941 |
+
|
1942 |
+
clear_btn.click(
|
1943 |
+
demo_instance.clear_history,
|
1944 |
+
inputs=[],
|
1945 |
+
outputs=[history]
|
1946 |
+
)
|
1947 |
+
|
1948 |
+
# UI์ Boost ๋ฒํผ ์ด๋ฒคํธ ์ฐ๊ฒฐ ์์
|
1949 |
+
boost_btn.click(
|
1950 |
+
fn=handle_boost,
|
1951 |
+
inputs=[input],
|
1952 |
+
outputs=[input, state_tab]
|
1953 |
+
)
|
1954 |
+
|
1955 |
+
|
1956 |
+
|
1957 |
+
# ์ด๋ฒคํธ ํธ๋ค๋ฌ ์์
|
1958 |
+
deploy_btn.click(
|
1959 |
+
fn=lambda code: deploy_to_vercel(remove_code_block(code)) if code else "์ฝ๋๊ฐ ์์ต๋๋ค.",
|
1960 |
+
inputs=[code_output],
|
1961 |
+
outputs=[deploy_result]
|
1962 |
+
)
|
1963 |
+
|
1964 |
|
1965 |
return demo
|
1966 |
|
1967 |
+
if __name__ == "__main__":
|
1968 |
+
demo = create_main_interface()
|
1969 |
+
demo.queue(default_concurrency_limit=20).launch(ssr_mode=False)
|