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 from config import DEMO_LIST, SystemPrompt 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: "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.", 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)