openfree commited on
Commit
9407149
·
verified ·
1 Parent(s): 0de0de4

Create app-backup.py

Browse files
Files changed (1) hide show
  1. app-backup.py +619 -0
app-backup.py ADDED
@@ -0,0 +1,619 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
25
+ from selenium.webdriver.common.by import By
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
+ # SystemPrompt 부분을 직접 정의
32
+ SystemPrompt = """You are 'MOUSE-I', an advanced AI visualization expert. Your mission is to transform every response into a visually stunning and highly informative presentation.
33
+
34
+ Core Capabilities:
35
+ - Transform text responses into rich visual experiences
36
+ - Create interactive data visualizations and charts
37
+ - Design beautiful and intuitive user interfaces
38
+ - Utilize engaging animations and transitions
39
+ - Present information in a clear, structured manner
40
+
41
+ Visual Elements to Include:
42
+ - Charts & Graphs (using Chart.js, D3.js)
43
+ - Interactive Data Visualizations
44
+ - Modern UI Components
45
+ - Engaging Animations
46
+ - Informative Icons & Emojis
47
+ - Color-coded Information Blocks
48
+ - Progress Indicators
49
+ - Timeline Visualizations
50
+ - Statistical Representations
51
+ - Comparison Tables
52
+
53
+ Technical Requirements:
54
+ - Modern HTML5/CSS3/JavaScript
55
+ - Responsive Design
56
+ - Interactive Elements
57
+ - Clean Typography
58
+ - Professional Color Schemes
59
+ - Smooth Animations
60
+ - Cross-browser Compatibility
61
+
62
+ Libraries Available:
63
+ - Chart.js for Data Visualization
64
+ - D3.js for Complex Graphics
65
+ - Bootstrap for Layout
66
+ - jQuery for Interactions
67
+ - Three.js for 3D Elements
68
+
69
+ Design Principles:
70
+ - Visual Hierarchy
71
+ - Clear Information Flow
72
+ - Consistent Styling
73
+ - Intuitive Navigation
74
+ - Engaging User Experience
75
+ - Accessibility Compliance
76
+
77
+ Remember to:
78
+ - Present data in the most visually appealing way
79
+ - Use appropriate charts for different data types
80
+ - Include interactive elements where relevant
81
+ - Maintain a professional and modern aesthetic
82
+ - Ensure responsive design for all devices
83
+
84
+ Return only HTML code wrapped in code blocks, focusing on creating visually stunning and informative presentations.
85
+ """
86
+
87
+ from config import DEMO_LIST
88
+
89
+ class Role:
90
+ SYSTEM = "system"
91
+ USER = "user"
92
+ ASSISTANT = "assistant"
93
+
94
+ History = List[Tuple[str, str]]
95
+ Messages = List[Dict[str, str]]
96
+
97
+ # 이미지 캐시를 메모리에 저장
98
+ IMAGE_CACHE = {}
99
+
100
+ # boost_prompt 함수와 handle_boost 함수를 추가합니다
101
+ def boost_prompt(prompt: str) -> str:
102
+ if not prompt:
103
+ return ""
104
+
105
+ # 증강을 위한 시스템 프롬프트
106
+ boost_system_prompt = """
107
+ 당신은 웹 개발 프롬프트 전문가입니다.
108
+ 주어진 프롬프트를 분석하여 더 상세하고 전문적인 요구사항으로 확장하되,
109
+ 원래 의도와 목적은 그대로 유지하면서 다음 관점들을 고려하여 증강하십시오:
110
+ 1. 기술적 구현 상세
111
+ 2. UI/UX 디자인 요소
112
+ 3. 사용자 경험 최적화
113
+ 4. 성능과 보안
114
+ 5. 접근성과 호환성
115
+
116
+ 기존 SystemPrompt의 모든 규칙을 준수하면서 증강된 프롬프트를 생성하십시오.
117
+ """
118
+
119
+ try:
120
+ # Claude API 시도
121
+ try:
122
+ response = claude_client.messages.create(
123
+ model="claude-3-5-sonnet-20241022",
124
+ max_tokens=2000,
125
+ messages=[{
126
+ "role": "user",
127
+ "content": f"다음 프롬프트를 분석하고 증강하시오: {prompt}"
128
+ }]
129
+ )
130
+
131
+ if hasattr(response, 'content') and len(response.content) > 0:
132
+ return response.content[0].text
133
+ raise Exception("Claude API 응답 형식 오류")
134
+
135
+ except Exception as claude_error:
136
+ print(f"Claude API 에러, OpenAI로 전환: {str(claude_error)}")
137
+
138
+ # OpenAI API 시도
139
+ completion = openai_client.chat.completions.create(
140
+ model="gpt-4",
141
+ messages=[
142
+ {"role": "system", "content": boost_system_prompt},
143
+ {"role": "user", "content": f"다음 프롬프트를 분석하고 증강하시오: {prompt}"}
144
+ ],
145
+ max_tokens=2000,
146
+ temperature=0.7
147
+ )
148
+
149
+ if completion.choices and len(completion.choices) > 0:
150
+ return completion.choices[0].message.content
151
+ raise Exception("OpenAI API 응답 형식 오류")
152
+
153
+ except Exception as e:
154
+ print(f"프롬프트 증강 중 오류 발생: {str(e)}")
155
+ return prompt # 오류 발생시 원본 프롬프트 반환
156
+
157
+ # Boost 버튼 이벤트 핸들러
158
+ def handle_boost(prompt: str):
159
+ try:
160
+ boosted_prompt = boost_prompt(prompt)
161
+ return boosted_prompt, gr.update(active_key="empty")
162
+ except Exception as e:
163
+ print(f"Boost 처리 중 오류: {str(e)}")
164
+ return prompt, gr.update(active_key="empty")
165
+
166
+ def get_image_base64(image_path):
167
+ if image_path in IMAGE_CACHE:
168
+ return IMAGE_CACHE[image_path]
169
+ try:
170
+ with open(image_path, "rb") as image_file:
171
+ encoded_string = base64.b64encode(image_file.read()).decode()
172
+ IMAGE_CACHE[image_path] = encoded_string
173
+ return encoded_string
174
+ except:
175
+ return IMAGE_CACHE.get('default.png', '')
176
+
177
+ def history_to_messages(history: History, system: str) -> Messages:
178
+ messages = [{'role': Role.SYSTEM, 'content': system}]
179
+ for h in history:
180
+ messages.append({'role': Role.USER, 'content': h[0]})
181
+ messages.append({'role': Role.ASSISTANT, 'content': h[1]})
182
+ return messages
183
+
184
+ def messages_to_history(messages: Messages) -> History:
185
+ assert messages[0]['role'] == Role.SYSTEM
186
+ history = []
187
+ for q, r in zip(messages[1::2], messages[2::2]):
188
+ history.append([q['content'], r['content']])
189
+ return history
190
+
191
+ # API 클라이언트 초기화
192
+ YOUR_ANTHROPIC_TOKEN = os.getenv('ANTHROPIC_API_KEY', '') # 기본값 추가
193
+ YOUR_OPENAI_TOKEN = os.getenv('OPENAI_API_KEY', '') # 기본값 추가
194
+
195
+ # API 키 검증
196
+ if not YOUR_ANTHROPIC_TOKEN or not YOUR_OPENAI_TOKEN:
197
+ print("Warning: API keys not found in environment variables")
198
+
199
+ # API 클라이언트 초기화 시 예외 처리 추가
200
+ try:
201
+ claude_client = anthropic.Anthropic(api_key=YOUR_ANTHROPIC_TOKEN)
202
+ openai_client = openai.OpenAI(api_key=YOUR_OPENAI_TOKEN)
203
+ except Exception as e:
204
+ print(f"Error initializing API clients: {str(e)}")
205
+ claude_client = None
206
+ openai_client = None
207
+
208
+ # try_claude_api 함수 수정
209
+ async def try_claude_api(system_message, claude_messages, timeout=15):
210
+ try:
211
+ start_time = time.time()
212
+ with claude_client.messages.stream(
213
+ model="claude-3-5-sonnet-20241022",
214
+ max_tokens=7800,
215
+ system=system_message,
216
+ messages=claude_messages
217
+ ) as stream:
218
+ collected_content = ""
219
+ for chunk in stream:
220
+ current_time = time.time()
221
+ if current_time - start_time > timeout:
222
+ print(f"Claude API response time: {current_time - start_time:.2f} seconds")
223
+ raise TimeoutError("Claude API timeout")
224
+ if chunk.type == "content_block_delta":
225
+ collected_content += chunk.delta.text
226
+ yield collected_content
227
+ await asyncio.sleep(0)
228
+
229
+ start_time = current_time
230
+
231
+ except Exception as e:
232
+ print(f"Claude API error: {str(e)}")
233
+ raise e
234
+
235
+ async def try_openai_api(openai_messages):
236
+ try:
237
+ stream = openai_client.chat.completions.create(
238
+ model="gpt-4o",
239
+ messages=openai_messages,
240
+ stream=True,
241
+ max_tokens=4096,
242
+ temperature=0.7
243
+ )
244
+
245
+ collected_content = ""
246
+ for chunk in stream:
247
+ if chunk.choices[0].delta.content is not None:
248
+ collected_content += chunk.choices[0].delta.content
249
+ yield collected_content
250
+
251
+ except Exception as e:
252
+ print(f"OpenAI API error: {str(e)}")
253
+ raise e
254
+
255
+ class Demo:
256
+ def __init__(self):
257
+ pass
258
+
259
+ async def generation_code(self, query: Optional[str], _setting: Dict[str, str], _history: Optional[History]):
260
+ if not query or query.strip() == '':
261
+ query = random.choice(DEMO_LIST)['description']
262
+
263
+ if _history is None:
264
+ _history = []
265
+
266
+ messages = history_to_messages(_history, _setting['system'])
267
+ system_message = messages[0]['content']
268
+
269
+ claude_messages = [
270
+ {"role": msg["role"] if msg["role"] != "system" else "user", "content": msg["content"]}
271
+ for msg in messages[1:] + [{'role': Role.USER, 'content': query}]
272
+ if msg["content"].strip() != ''
273
+ ]
274
+
275
+ openai_messages = [{"role": "system", "content": system_message}]
276
+ for msg in messages[1:]:
277
+ openai_messages.append({
278
+ "role": msg["role"],
279
+ "content": msg["content"]
280
+ })
281
+ openai_messages.append({"role": "user", "content": query})
282
+
283
+ try:
284
+ yield [
285
+ "Generating code...",
286
+ _history,
287
+ None,
288
+ gr.update(active_key="loading"),
289
+ gr.update(open=True)
290
+ ]
291
+ await asyncio.sleep(0)
292
+
293
+ collected_content = None
294
+ try:
295
+ async for content in try_claude_api(system_message, claude_messages):
296
+ yield [
297
+ content,
298
+ _history,
299
+ None,
300
+ gr.update(active_key="loading"),
301
+ gr.update(open=True)
302
+ ]
303
+ await asyncio.sleep(0)
304
+ collected_content = content
305
+
306
+ except Exception as claude_error:
307
+ print(f"Falling back to OpenAI API due to Claude error: {str(claude_error)}")
308
+
309
+ async for content in try_openai_api(openai_messages):
310
+ yield [
311
+ content,
312
+ _history,
313
+ None,
314
+ gr.update(active_key="loading"),
315
+ gr.update(open=True)
316
+ ]
317
+ await asyncio.sleep(0)
318
+ collected_content = content
319
+
320
+ if collected_content:
321
+ _history = messages_to_history([
322
+ {'role': Role.SYSTEM, 'content': system_message}
323
+ ] + claude_messages + [{
324
+ 'role': Role.ASSISTANT,
325
+ 'content': collected_content
326
+ }])
327
+
328
+ # code_drawer를 닫도록 수정
329
+ yield [
330
+ collected_content,
331
+ _history,
332
+ send_to_sandbox(remove_code_block(collected_content)),
333
+ gr.update(active_key="render"),
334
+ gr.update(open=False) # code_drawer를 닫음
335
+ ]
336
+
337
+ else:
338
+ raise ValueError("No content was generated from either API")
339
+
340
+ except Exception as e:
341
+ print(f"Error details: {str(e)}")
342
+ raise ValueError(f'Error calling APIs: {str(e)}')
343
+
344
+ def clear_history(self):
345
+ return []
346
+
347
+ def remove_code_block(text):
348
+ pattern = r'```html\n(.+?)\n```'
349
+ match = re.search(pattern, text, re.DOTALL)
350
+ if match:
351
+ return match.group(1).strip()
352
+ else:
353
+ return text.strip()
354
+
355
+ def history_render(history: History):
356
+ return gr.update(open=True), history
357
+
358
+ def send_to_sandbox(code):
359
+ encoded_html = base64.b64encode(code.encode('utf-8')).decode('utf-8')
360
+ data_uri = f"data:text/html;charset=utf-8;base64,{encoded_html}"
361
+ return f"""
362
+ <iframe
363
+ src="{data_uri}"
364
+ style="width:100%; height:800px; border:none;"
365
+ frameborder="0"
366
+ ></iframe>
367
+ """
368
+ # 배포 관련 함수 추가
369
+ def generate_space_name():
370
+ """6자리 랜덤 영문 이름 생성"""
371
+ letters = string.ascii_lowercase
372
+ return ''.join(random.choice(letters) for i in range(6))
373
+
374
+ def deploy_to_vercel(code: str):
375
+ try:
376
+ token = "A8IFZmgW2cqA4yUNlLPnci0N"
377
+ if not token:
378
+ return "Vercel 토큰이 설정되지 않았습니다."
379
+
380
+ # 6자리 영문 프로젝트 이름 생성
381
+ project_name = ''.join(random.choice(string.ascii_lowercase) for i in range(6))
382
+
383
+
384
+ # Vercel API 엔드포인트
385
+ deploy_url = "https://api.vercel.com/v13/deployments"
386
+
387
+ # 헤더 설정
388
+ headers = {
389
+ "Authorization": f"Bearer {token}",
390
+ "Content-Type": "application/json"
391
+ }
392
+
393
+ # package.json 파일 생성
394
+ package_json = {
395
+ "name": project_name,
396
+ "version": "1.0.0",
397
+ "private": True, # true -> True로 수정
398
+ "dependencies": {
399
+ "vite": "^5.0.0"
400
+ },
401
+ "scripts": {
402
+ "dev": "vite",
403
+ "build": "echo 'No build needed' && mkdir -p dist && cp index.html dist/",
404
+ "preview": "vite preview"
405
+ }
406
+ }
407
+
408
+ # 배포할 파일 데이터 구조
409
+ files = [
410
+ {
411
+ "file": "index.html",
412
+ "data": code
413
+ },
414
+ {
415
+ "file": "package.json",
416
+ "data": json.dumps(package_json, indent=2) # indent 추가로 가독성 향상
417
+ }
418
+ ]
419
+
420
+ # 프로젝트 설정
421
+ project_settings = {
422
+ "buildCommand": "npm run build",
423
+ "outputDirectory": "dist",
424
+ "installCommand": "npm install",
425
+ "framework": None
426
+ }
427
+
428
+ # 배포 요청 데이터
429
+ deploy_data = {
430
+ "name": project_name,
431
+ "files": files,
432
+ "target": "production",
433
+ "projectSettings": project_settings
434
+ }
435
+
436
+
437
+ deploy_response = requests.post(deploy_url, headers=headers, json=deploy_data)
438
+
439
+ if deploy_response.status_code != 200:
440
+ return f"배포 실패: {deploy_response.text}"
441
+
442
+ # URL 형식 수정 - 6자리.vercel.app 형태로 반환
443
+ deployment_url = f"{project_name}.vercel.app"
444
+
445
+ time.sleep(5)
446
+
447
+ return f"""배포 완료! <a href="https://{deployment_url}" target="_blank" style="color: #1890ff; text-decoration: underline; cursor: pointer;">https://{deployment_url}</a>"""
448
+
449
+ except Exception as e:
450
+ return f"배포 중 오류 발생: {str(e)}"
451
+
452
+ theme = gr.themes.Soft()
453
+
454
+ def get_random_placeholder():
455
+ return random.choice(DEMO_LIST)['description']
456
+
457
+ def update_placeholder():
458
+ return gr.update(placeholder=get_random_placeholder())
459
+
460
+ def create_main_interface():
461
+ """메인 인터페이스 생성 함수"""
462
+
463
+ def execute_code(query: str):
464
+ if not query or query.strip() == '':
465
+ return None, gr.update(active_key="empty")
466
+
467
+ try:
468
+ if '```html' in query and '```' in query:
469
+ code = remove_code_block(query)
470
+ else:
471
+ code = query.strip()
472
+
473
+ return send_to_sandbox(code), gr.update(active_key="render")
474
+ except Exception as e:
475
+ print(f"Error executing code: {str(e)}")
476
+ return None, gr.update(active_key="empty")
477
+
478
+ # CSS 파일 내용을 직접 적용
479
+ with open('app.css', 'r', encoding='utf-8') as f:
480
+ custom_css = f.read()
481
+
482
+ demo = gr.Blocks(css=custom_css, theme=theme)
483
+
484
+ with demo:
485
+ with gr.Tabs(elem_classes="main-tabs") as tabs:
486
+ # MOUSE 탭
487
+ with gr.Tab("Visual AI Assistant", elem_id="mouse-tab", elem_classes="mouse-tab"):
488
+
489
+ history = gr.State([])
490
+ setting = gr.State({
491
+ "system": SystemPrompt,
492
+ })
493
+
494
+ with ms.Application() as app:
495
+ with antd.ConfigProvider():
496
+ # Drawer 컴포넌트들
497
+ with antd.Drawer(open=False, title="Thinking", placement="left", width="750px") as code_drawer:
498
+ code_output = legacy.Markdown()
499
+
500
+ with antd.Drawer(open=False, title="history", placement="left", width="900px") as history_drawer:
501
+ history_output = legacy.Chatbot(show_label=False, flushing=False, height=960, elem_classes="history_chatbot")
502
+
503
+ # 메인 컨텐츠를 위한 Row
504
+ with antd.Row(gutter=[32, 12]) as layout:
505
+ # 좌측 패널
506
+ with antd.Col(span=24, md=8):
507
+ with antd.Flex(vertical=True, gap="middle", wrap=True):
508
+ # 헤더 부분
509
+ header = gr.HTML(f"""
510
+ <div class="left_header">
511
+ <img src="data:image/gif;base64,{get_image_base64('mouse.gif')}" width="360px" />
512
+ <h1 style="font-size: 18px;">MOUSE-Chat: Visual AI Assistant</h1>
513
+ <h1 style="font-size: 10px;">Transform your questions into stunning visual presentations. Every response is crafted with beautiful graphics, charts, and interactive elements.</h1>
514
+ </div>
515
+ """)
516
+
517
+
518
+
519
+ # 입력 영역
520
+ input = antd.InputTextarea(
521
+ size="large",
522
+ allow_clear=True,
523
+
524
+ placeholder=get_random_placeholder()
525
+ )
526
+
527
+ # 버튼 그룹
528
+ with antd.Flex(gap="small", justify="space-between"):
529
+ btn = antd.Button("Generate", type="primary", size="large")
530
+ boost_btn = antd.Button("Enhance", type="default", size="large")
531
+ deploy_btn = antd.Button("Share", type="default", size="large")
532
+ clear_btn = antd.Button("Clear", type="default", size="large")
533
+ historyBtn = antd.Button("📜 History", type="default")
534
+
535
+
536
+
537
+ deploy_result = gr.HTML(label="배포 결과")
538
+
539
+ # 우측 패널
540
+ with antd.Col(span=24, md=16):
541
+ with ms.Div(elem_classes="right_panel"):
542
+ # 상단 버튼들
543
+ with antd.Flex(gap="small", elem_classes="setting-buttons"):
544
+ historyBtn = antd.Button("📜 히스토리", type="default")
545
+
546
+ gr.HTML('<div class="render_header"><span class="header_btn"></span><span class="header_btn"></span><span class="header_btn"></span></div>')
547
+
548
+ # 탭 컨텐츠
549
+ with antd.Tabs(active_key="empty", render_tab_bar="() => null") as state_tab:
550
+ with antd.Tabs.Item(key="empty"):
551
+
552
+ empty = antd.Empty(description="Enter your question to begin", elem_classes="right_content")
553
+
554
+ with antd.Tabs.Item(key="loading"):
555
+ loading = antd.Spin(True, tip="Creating visual presentation...", size="large", elem_classes="right_content")
556
+ with antd.Tabs.Item(key="render"):
557
+ sandbox = gr.HTML(elem_classes="html_content")
558
+
559
+
560
+
561
+
562
+ # 이벤트 핸들러 연결
563
+ historyBtn.click(
564
+ history_render,
565
+ inputs=[history],
566
+ outputs=[history_drawer, history_output]
567
+ )
568
+
569
+ history_drawer.close(
570
+ lambda: gr.update(open=False),
571
+ inputs=[],
572
+ outputs=[history_drawer]
573
+ )
574
+
575
+ btn.click(
576
+ demo_instance.generation_code,
577
+ inputs=[input, setting, history],
578
+ outputs=[code_output, history, sandbox, state_tab, code_drawer]
579
+ ).then( # then을 사용하여 연속 동작 추가
580
+ fn=update_placeholder,
581
+ inputs=[],
582
+ outputs=[input]
583
+ )
584
+
585
+
586
+
587
+ clear_btn.click(
588
+ fn=lambda: (
589
+ demo_instance.clear_history(), # history 초기화
590
+ update_placeholder() # placeholder 업데이트
591
+ ),
592
+ inputs=[],
593
+ outputs=[history, input] # input도 출력에 추가
594
+ )
595
+
596
+
597
+ boost_btn.click(
598
+ fn=handle_boost,
599
+ inputs=[input],
600
+ outputs=[input, state_tab]
601
+ )
602
+
603
+ deploy_btn.click(
604
+ fn=lambda code: deploy_to_vercel(remove_code_block(code)) if code else "코드가 없습니다.",
605
+ inputs=[code_output],
606
+ outputs=[deploy_result]
607
+ )
608
+
609
+ return demo
610
+
611
+ # 메인 실행 부분
612
+ if __name__ == "__main__":
613
+ try:
614
+ demo_instance = Demo() # Demo 인스턴스 생성
615
+ demo = create_main_interface() # 인터페이스 생성
616
+ demo.queue(default_concurrency_limit=20).launch(server_name="0.0.0.0", server_port=7860) # 서버 설정 추가
617
+ except Exception as e:
618
+ print(f"Initialization error: {e}")
619
+ raise