mouse-web / app.py
seawolf2357's picture
Update app.py
cc452e6 verified
raw
history blame
13.4 kB
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"<iframe src=\"{data_uri}\" width=\"100%\" height=\"920px\"></iframe>"
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"""
<div class="left_header">
<img src="data:image/gif;base64,{get_image_base64('mouse.gif')}" width="360px" />
<h1 style="font-size: 18px;">고양이도 발둜 μ½”λ”©ν•˜λŠ” 'MOUSE-I'</h2>
<h1 style="font-size: 10px;">μž…λ ₯없이 'Send' λ²„νŠΌ ν΄λ¦­μ‹œ λžœλ€ν•œ 예제 μ½”λ“œ 생성. μƒμ„±λœ μ½”λ“œλ§Œ ν”„λ‘¬ν”„νŠΈμ— λΆ™μ—¬λ„£κ³  'Code μ‹€ν–‰' λ²„νŠΌ ν΄λ¦­μ‹œ 화면에 μ¦‰μ‹œ μ„œλΉ„μŠ€κ°€ μ‹€ν–‰. 문의: [email protected] </h2>
</div>
""")
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(
"ν…μŠ€νŠΈλ‘œ μŒμ„± 생성(TTS)",
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(λ§‰λŒ€κ°€ κ°€μž₯ μƒλ‹¨κΉŒμ§€ λˆ„μ ν•΄μ„œ μŒ“μ˜€μ„λ•Œ), λ§‰λŒ€κ°€ ν•œμ€„ 가득 μ±„μ› μ„λ•Œ ν•œμ€„μ΄ μ‚­μ œ, λ‚˜λ¨Έμ§€λŠ” Tetris κΈ°λ³Έ κ·œμΉ™μ„ 따름름",
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('<div class="render_header"><span class="header_btn"></span><span class="header_btn"></span><span class="header_btn"></span></div>')
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)