import os import re import random from http import HTTPStatus from typing import Dict, List, Optional, Tuple import base64 import anthropic from functools import partial import gradio as gr import modelscope_studio.components.base as ms import modelscope_studio.components.legacy as legacy import modelscope_studio.components.antd as antd # SystemPrompt 부분을 직접 정의 SystemPrompt = """너의 이름은 'MOUSE'이다. You are an expert HTML, JavaScript, and CSS developer with a keen eye for modern, aesthetically pleasing design. Your task is to create a stunning, contemporary, and highly functional website based on the user's request using pure HTML, JavaScript, and CSS. This code will be rendered directly in the browser. General guidelines: - Create clean, modern interfaces using vanilla JavaScript and CSS - Use HTML5 semantic elements for better structure - Implement CSS3 features for animations and styling - Utilize modern JavaScript (ES6+) features - Create responsive designs using CSS media queries - You can use CDN-hosted libraries like: * jQuery * Bootstrap * Chart.js * Three.js * D3.js - For icons, use Unicode symbols or create simple SVG icons - Use CSS animations and transitions for smooth effects - Implement proper event handling with JavaScript - Create mock data instead of making API calls - Ensure cross-browser compatibility - Focus on performance and smooth animations Focus on creating a visually striking and user-friendly interface that aligns with current web design trends. Pay special attention to: - Typography: Use web-safe fonts or Google Fonts via CDN - Color: Implement a cohesive color scheme that complements the content - Layout: Design an intuitive and balanced layout using Flexbox/Grid - Animations: Add subtle CSS transitions and keyframe animations - Consistency: Maintain a consistent design language throughout Remember to only return code wrapped in HTML code blocks. The code should work directly in a browser without any build steps. Remember not add any description, just return the code only. """ # config.py에서 DEMO_LIST만 import from config import DEMO_LIST def get_image_base64(image_path): with open(image_path, "rb") as image_file: encoded_string = base64.b64encode(image_file.read()).decode() return encoded_string YOUR_API_TOKEN = os.getenv('ANTHROPIC_API_KEY') client = anthropic.Anthropic(api_key=YOUR_API_TOKEN) class Role: SYSTEM = "system" USER = "user" ASSISTANT = "assistant" History = List[Tuple[str, str]] Messages = List[Dict[str, str]] def history_to_messages(history: History, system: str) -> Messages: messages = [{'role': Role.SYSTEM, 'content': system}] for h in history: messages.append({'role': Role.USER, 'content': h[0]}) messages.append({'role': Role.ASSISTANT, 'content': h[1]}) return messages def messages_to_history(messages: Messages) -> History: assert messages[0]['role'] == Role.SYSTEM history = [] for q, r in zip(messages[1::2], messages[2::2]): history.append([q['content'], r['content']]) return history def remove_code_block(text): pattern = r'```html\n(.+?)\n```' match = re.search(pattern, text, re.DOTALL) if match: return match.group(1).strip() else: return text.strip() def history_render(history: History): return gr.update(open=True), history def clear_history(): return [] def send_to_sandbox(code): encoded_html = base64.b64encode(code.encode('utf-8')).decode('utf-8') data_uri = f"data:text/html;charset=utf-8;base64,{encoded_html}" return f"" with gr.Blocks(css_paths="app.css") as demo: history = gr.State([]) setting = gr.State({ "system": SystemPrompt, }) def generation_code(query: Optional[str], _setting: Dict[str, str], _history: Optional[History]): if not query or query.strip() == '': query = random.choice(DEMO_LIST)['description'] # 빈 쿼리일 경우 랜덤 예제 사용 if _history is None: _history = [] messages = history_to_messages(_history, _setting['system']) system_message = messages[0]['content'] claude_messages = [ {"role": msg["role"] if msg["role"] != "system" else "user", "content": msg["content"]} for msg in messages[1:] + [{'role': Role.USER, 'content': query}] if msg["content"].strip() != '' # 빈 메시지 필터링 ] try: yield [ "Generating code...", _history, None, gr.update(active_key="loading"), gr.update(open=True) ] with client.messages.stream( model="claude-3-5-sonnet-20241022", max_tokens=7800, system=system_message, messages=claude_messages ) as stream: collected_content = "" for chunk in stream: if chunk.type == "content_block_delta": delta = chunk.delta.text collected_content += delta yield [ collected_content, _history, None, gr.update(active_key="loading"), gr.update(open=True) ] _history = messages_to_history([ {'role': Role.SYSTEM, 'content': system_message} ] + claude_messages + [{ 'role': Role.ASSISTANT, 'content': collected_content }]) yield [ collected_content, _history, send_to_sandbox(remove_code_block(collected_content)), gr.update(active_key="render"), gr.update(open=True) ] except Exception as e: print(f"Error details: {str(e)}") # 디버깅을 위한 에러 출력 raise ValueError(f'Error calling Claude API: {str(e)}') with ms.Application() as app: with antd.ConfigProvider(): # 메인 컨텐츠를 위한 Row with antd.Row(gutter=[32, 12]) as layout: # 좌측 패널 with antd.Col(span=24, md=8): with antd.Flex(vertical=True, gap="middle", wrap=True): header = gr.HTML(f"""

고양이도 발로 코딩하는 'MOUSE-I'

입력없이 'Send' 버튼 클릭시 랜덤한 예제 코드 생성. 생성된 코드만 프롬프트에 붙여넣고 'Code 실행' 버튼 클릭시 화면에 즉시 서비스가 실행. 문의: arxivgpt@gmail.com

""") input = antd.InputTextarea( size="large", allow_clear=True, placeholder=random.choice(DEMO_LIST)['description'] ) # 버튼들을 가로로 배치하기 위한 Flex 컨테이너 with antd.Flex(gap="small", justify="space-between"): btn = antd.Button("Send", type="primary", size="large") execute_btn = antd.Button("Code 실행", type="default", size="large") clear_btn = antd.Button("Clear", type="default", size="large") # Examples 버튼들 추가 antd.Divider("Try these examples") # 두 번째 예제 버튼 example_btn0 = antd.Button( "MBTI 진단 서비스", type="default", block=True, size="large" ) example_btn0.click( fn=lambda: "MBTI 진단을 위해 15개의 질문과 객관식 답변을 통해 MBTI 진단 결과 및 해당 성격에 대한 상세한 결과를 출력하라", inputs=[], outputs=[input] ) # 첫 번째 예제 버튼 example_btn1 = antd.Button( "다이나믹 차트 대쉬보드", type="default", block=True, size="large" ) example_btn1.click( fn=lambda: "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.", inputs=[], outputs=[input] ) # 두 번째 예제 버튼 example_btn2 = antd.Button( "[게임] 체스", type="default", block=True, size="large" ) example_btn2.click( fn=lambda: "체스 게임: 체스 체스 게임의 룰을 정확하게 식별하고 적용하라, 상대방은 auto로 게임을 진행하라", inputs=[], outputs=[input] ) # 두 번째 예제 버튼 example_btn3 = antd.Button( "타로카드 운새", type="default", block=True, size="large" ) example_btn3.click( fn=lambda: "타로카드 운세를 점치는것을 생성하라. 아주 상세하고 전문적이면서 쉽고 길게 답변하라. 모든 답변과 설명은 한글로 하라", inputs=[], outputs=[input] ) # 두 번째 예제 버튼 example_btn4 = antd.Button( "[게임] 테트리스", type="default", block=True, size="large" ) example_btn4.click( fn=lambda: "Classic Tetris Game: Start과 ReStart 버튼과 기능 적용, Game Over(막대가 가장 상단까지 누적해서 쌓였을때), 막대가 한줄 가득 채워졌을때 한줄이 삭제, 떨어진 막대는 사라지지 않고 반드시 누적해서 쌓을것. 막대 우측/좌측/내리기(space)/막대의 자체 모양만 바꿈(up) 버튼 지원, 나머지는 Tetris 기본 규칙을 따름", inputs=[], outputs=[input] ) example_btn5 = antd.Button( "텍스트로 음성 생성 및 조정", type="default", block=True, size="large" ) example_btn5.click( fn=lambda: "텍스트를 음성으로 변환하고, 음성 파라미터를 실시간으로 조정할 수 있는 인터페이스를 제공하세요.", inputs=[], outputs=[input] ) # Drawer 컴포넌트들 with antd.Drawer(open=False, title="code", placement="left", width="750px") as code_drawer: code_output = legacy.Markdown() with antd.Drawer(open=False, title="history", placement="left", width="900px") as history_drawer: history_output = legacy.Chatbot(show_label=False, flushing=False, height=960, elem_classes="history_chatbot") # 우측 패널 with antd.Col(span=24, md=16): with ms.Div(elem_classes="right_panel"): with antd.Flex(gap="small", elem_classes="setting-buttons"): codeBtn = antd.Button("🧑‍💻 view code", type="default") historyBtn = antd.Button("📜 history", type="default") gr.HTML('
') with antd.Tabs(active_key="empty", render_tab_bar="() => null") as state_tab: with antd.Tabs.Item(key="empty"): empty = antd.Empty(description="empty input", elem_classes="right_content") with antd.Tabs.Item(key="loading"): loading = antd.Spin(True, tip="coding...", size="large", elem_classes="right_content") with antd.Tabs.Item(key="render"): sandbox = gr.HTML(elem_classes="html_content") # Code 실행 버튼 이벤트 핸들러 def execute_code(query: str): if not query or query.strip() == '': return None, gr.update(active_key="empty") try: # HTML 코드 블록 확인 if '```html' in query and '```' in query: # HTML 코드 블록 추출 code = remove_code_block(query) else: # 입력된 텍스트를 그대로 코드로 사용 code = query.strip() return send_to_sandbox(code), gr.update(active_key="render") except Exception as e: print(f"Error executing code: {str(e)}") return None, gr.update(active_key="empty") # 이벤트 핸들러들 execute_btn.click( fn=execute_code, inputs=[input], outputs=[sandbox, state_tab] ) codeBtn.click(lambda: gr.update(open=True), inputs=[], outputs=[code_drawer]) code_drawer.close(lambda: gr.update( open=False), inputs=[], outputs=[code_drawer]) historyBtn.click(history_render, inputs=[history], outputs=[history_drawer, history_output]) history_drawer.close(lambda: gr.update( open=False), inputs=[], outputs=[history_drawer]) btn.click( generation_code, inputs=[input, setting, history], outputs=[code_output, history, sandbox, state_tab, code_drawer] ) clear_btn.click(clear_history, inputs=[], outputs=[history]) if __name__ == "__main__": demo.queue(default_concurrency_limit=20).launch(ssr_mode=False)