Update app.py
Browse files
app.py
CHANGED
@@ -442,6 +442,95 @@ def load_json_data():
|
|
442 |
}
|
443 |
]
|
444 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
445 |
# 전역 변수로 템플릿 데이터 캐시
|
446 |
TEMPLATE_CACHE = None
|
447 |
|
@@ -649,26 +738,6 @@ with gr.Blocks(css_paths="app.css",theme=theme) as demo:
|
|
649 |
elem_classes="close-btn"
|
650 |
)
|
651 |
|
652 |
-
# 세션 드로어에서 카드 클릭 시 실행할 함수 (Drawer 컴포넌트들 다음에 위치)
|
653 |
-
def execute_history_item(evt: gr.SelectData): # gr.SelectData로 이벤트 데이터 받기
|
654 |
-
try:
|
655 |
-
# 클릭된 카드의 데이터 가져오기
|
656 |
-
prompt = evt.value["prompt"]
|
657 |
-
response = evt.value["response"]
|
658 |
-
|
659 |
-
# 코드 실행
|
660 |
-
code = remove_code_block(response) if '```html' in response else response
|
661 |
-
|
662 |
-
return (
|
663 |
-
gr.update(value=prompt), # 입력 필드 업데이트
|
664 |
-
send_to_sandbox(code), # 코드 실행
|
665 |
-
gr.update(active_key="render"), # 탭 상태 업데이트
|
666 |
-
gr.update(open=False) # 세션 드로어 닫기
|
667 |
-
)
|
668 |
-
except Exception as e:
|
669 |
-
print(f"Error executing history item: {e}")
|
670 |
-
return None, None, gr.update(active_key="empty"), gr.update(open=True)
|
671 |
-
|
672 |
# 메인 컨텐츠를 위한 Row
|
673 |
with antd.Row(gutter=[32, 12]) as layout:
|
674 |
# 좌측 패널
|
@@ -693,6 +762,11 @@ with gr.Blocks(css_paths="app.css",theme=theme) as demo:
|
|
693 |
execute_btn = antd.Button("Code 실행", type="default", size="large")
|
694 |
clear_btn = antd.Button("Clear", type="default", size="large")
|
695 |
|
|
|
|
|
|
|
|
|
|
|
696 |
|
697 |
# 우측 패널
|
698 |
with antd.Col(span=24, md=16):
|
@@ -711,25 +785,6 @@ with gr.Blocks(css_paths="app.css",theme=theme) as demo:
|
|
711 |
with antd.Tabs.Item(key="render"):
|
712 |
sandbox = gr.HTML(elem_classes="html_content")
|
713 |
|
714 |
-
# Code 실행 버튼 이벤트 핸들러 함수 정의
|
715 |
-
def execute_code(query: str):
|
716 |
-
if not query or query.strip() == '':
|
717 |
-
return None, gr.update(active_key="empty")
|
718 |
-
|
719 |
-
try:
|
720 |
-
# HTML 코드 블록 확인
|
721 |
-
if '```html' in query and '```' in query:
|
722 |
-
# HTML 코드 블록 추출
|
723 |
-
code = remove_code_block(query)
|
724 |
-
else:
|
725 |
-
# 입력된 텍스트를 그대로 코드로 사용
|
726 |
-
code = query.strip()
|
727 |
-
|
728 |
-
return send_to_sandbox(code), gr.update(active_key="render")
|
729 |
-
except Exception as e:
|
730 |
-
print(f"Error executing code: {str(e)}")
|
731 |
-
return None, gr.update(active_key="empty")
|
732 |
-
|
733 |
# 이벤트 핸들러들
|
734 |
execute_btn.click(
|
735 |
fn=execute_code,
|
@@ -761,7 +816,26 @@ with gr.Blocks(css_paths="app.css",theme=theme) as demo:
|
|
761 |
outputs=[history_drawer]
|
762 |
)
|
763 |
|
764 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
765 |
sessionBtn.click(
|
766 |
fn=lambda: (gr.update(open=True), load_session_history()),
|
767 |
inputs=[],
|
@@ -769,9 +843,6 @@ with gr.Blocks(css_paths="app.css",theme=theme) as demo:
|
|
769 |
queue=False
|
770 |
)
|
771 |
|
772 |
-
|
773 |
-
|
774 |
-
# 세션 드로어 닫기 이벤트 수정
|
775 |
session_drawer.close(
|
776 |
lambda: (gr.update(open=False), gr.HTML("")),
|
777 |
outputs=[session_drawer, session_history]
|
@@ -782,8 +853,6 @@ with gr.Blocks(css_paths="app.css",theme=theme) as demo:
|
|
782 |
outputs=[session_drawer, session_history]
|
783 |
)
|
784 |
|
785 |
-
|
786 |
-
|
787 |
btn.click(
|
788 |
demo_instance.generation_code,
|
789 |
inputs=[input, setting, history],
|
@@ -796,8 +865,6 @@ with gr.Blocks(css_paths="app.css",theme=theme) as demo:
|
|
796 |
outputs=[history]
|
797 |
)
|
798 |
|
799 |
-
# 마지막 부분을 다음과 같이 수정하세요
|
800 |
-
|
801 |
if __name__ == "__main__":
|
802 |
try:
|
803 |
demo_instance = Demo()
|
|
|
442 |
}
|
443 |
]
|
444 |
|
445 |
+
def load_best_templates():
|
446 |
+
json_data = load_json_data()[:12] # 베스트 템플릿
|
447 |
+
return create_template_html("🏆 베스트 템플릿", json_data)
|
448 |
+
|
449 |
+
def load_trending_templates():
|
450 |
+
json_data = load_json_data()[12:24] # 트렌딩 템플릿
|
451 |
+
return create_template_html("🔥 트렌딩 템플릿", json_data)
|
452 |
+
|
453 |
+
def load_new_templates():
|
454 |
+
json_data = load_json_data()[24:36] # NEW 템플릿
|
455 |
+
return create_template_html("✨ NEW 템플릿", json_data)
|
456 |
+
|
457 |
+
def create_template_html(title, items):
|
458 |
+
html_content = """
|
459 |
+
<style>
|
460 |
+
.prompt-grid {
|
461 |
+
display: grid;
|
462 |
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
463 |
+
gap: 20px;
|
464 |
+
padding: 20px;
|
465 |
+
}
|
466 |
+
.prompt-card {
|
467 |
+
background: white;
|
468 |
+
border: 1px solid #eee;
|
469 |
+
border-radius: 8px;
|
470 |
+
padding: 15px;
|
471 |
+
cursor: pointer;
|
472 |
+
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
473 |
+
}
|
474 |
+
.prompt-card:hover {
|
475 |
+
transform: translateY(-2px);
|
476 |
+
transition: transform 0.2s;
|
477 |
+
}
|
478 |
+
.card-image {
|
479 |
+
width: 100%;
|
480 |
+
height: 180px;
|
481 |
+
object-fit: cover;
|
482 |
+
border-radius: 4px;
|
483 |
+
margin-bottom: 10px;
|
484 |
+
}
|
485 |
+
.card-name {
|
486 |
+
font-weight: bold;
|
487 |
+
margin-bottom: 8px;
|
488 |
+
font-size: 16px;
|
489 |
+
color: #333;
|
490 |
+
}
|
491 |
+
.card-prompt {
|
492 |
+
font-size: 11px;
|
493 |
+
line-height: 1.4;
|
494 |
+
color: #666;
|
495 |
+
display: -webkit-box;
|
496 |
+
-webkit-line-clamp: 6;
|
497 |
+
-webkit-box-orient: vertical;
|
498 |
+
overflow: hidden;
|
499 |
+
height: 90px;
|
500 |
+
background-color: #f8f9fa;
|
501 |
+
padding: 8px;
|
502 |
+
border-radius: 4px;
|
503 |
+
}
|
504 |
+
</style>
|
505 |
+
<div class="prompt-grid">
|
506 |
+
"""
|
507 |
+
|
508 |
+
for item in items:
|
509 |
+
html_content += f"""
|
510 |
+
<div class="prompt-card" onclick="copyToInput(this)" data-prompt="{html.escape(item.get('prompt', ''))}">
|
511 |
+
<img src="{item.get('image_url', '')}" class="card-image" loading="lazy" alt="{html.escape(item.get('name', ''))}">
|
512 |
+
<div class="card-name">{html.escape(item.get('name', ''))}</div>
|
513 |
+
<div class="card-prompt">{html.escape(item.get('prompt', ''))}</div>
|
514 |
+
</div>
|
515 |
+
"""
|
516 |
+
|
517 |
+
html_content += """
|
518 |
+
<script>
|
519 |
+
function copyToInput(card) {
|
520 |
+
const prompt = card.dataset.prompt;
|
521 |
+
const textarea = document.querySelector('.ant-input-textarea-large textarea');
|
522 |
+
if (textarea) {
|
523 |
+
textarea.value = prompt;
|
524 |
+
textarea.dispatchEvent(new Event('input', { bubbles: true }));
|
525 |
+
document.querySelector('.session-drawer .close-btn').click();
|
526 |
+
}
|
527 |
+
}
|
528 |
+
</script>
|
529 |
+
</div>
|
530 |
+
"""
|
531 |
+
return gr.HTML(value=html_content)
|
532 |
+
|
533 |
+
|
534 |
# 전역 변수로 템플릿 데이터 캐시
|
535 |
TEMPLATE_CACHE = None
|
536 |
|
|
|
738 |
elem_classes="close-btn"
|
739 |
)
|
740 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
741 |
# 메인 컨텐츠를 위한 Row
|
742 |
with antd.Row(gutter=[32, 12]) as layout:
|
743 |
# 좌측 패널
|
|
|
762 |
execute_btn = antd.Button("Code 실행", type="default", size="large")
|
763 |
clear_btn = antd.Button("Clear", type="default", size="large")
|
764 |
|
765 |
+
# 템플릿 버튼들 추가
|
766 |
+
with antd.Flex(gap="small", justify="space-between", style={"marginTop": "10px"}):
|
767 |
+
best_btn = antd.Button("🏆 베스트 템플릿", type="default", size="large")
|
768 |
+
trending_btn = antd.Button("🔥 트렌딩 템플릿", type="default", size="large")
|
769 |
+
new_btn = antd.Button("✨ NEW 템플릿", type="default", size="large")
|
770 |
|
771 |
# 우측 패널
|
772 |
with antd.Col(span=24, md=16):
|
|
|
785 |
with antd.Tabs.Item(key="render"):
|
786 |
sandbox = gr.HTML(elem_classes="html_content")
|
787 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
788 |
# 이벤트 핸들러들
|
789 |
execute_btn.click(
|
790 |
fn=execute_code,
|
|
|
816 |
outputs=[history_drawer]
|
817 |
)
|
818 |
|
819 |
+
# 템플릿 버튼 이벤트 핸들러
|
820 |
+
best_btn.click(
|
821 |
+
fn=lambda: (gr.update(open=True), load_best_templates()),
|
822 |
+
outputs=[session_drawer, session_history],
|
823 |
+
queue=False
|
824 |
+
)
|
825 |
+
|
826 |
+
trending_btn.click(
|
827 |
+
fn=lambda: (gr.update(open=True), load_trending_templates()),
|
828 |
+
outputs=[session_drawer, session_history],
|
829 |
+
queue=False
|
830 |
+
)
|
831 |
+
|
832 |
+
new_btn.click(
|
833 |
+
fn=lambda: (gr.update(open=True), load_new_templates()),
|
834 |
+
outputs=[session_drawer, session_history],
|
835 |
+
queue=False
|
836 |
+
)
|
837 |
+
|
838 |
+
# 기존 세션 버튼 이벤트
|
839 |
sessionBtn.click(
|
840 |
fn=lambda: (gr.update(open=True), load_session_history()),
|
841 |
inputs=[],
|
|
|
843 |
queue=False
|
844 |
)
|
845 |
|
|
|
|
|
|
|
846 |
session_drawer.close(
|
847 |
lambda: (gr.update(open=False), gr.HTML("")),
|
848 |
outputs=[session_drawer, session_history]
|
|
|
853 |
outputs=[session_drawer, session_history]
|
854 |
)
|
855 |
|
|
|
|
|
856 |
btn.click(
|
857 |
demo_instance.generation_code,
|
858 |
inputs=[input, setting, history],
|
|
|
865 |
outputs=[history]
|
866 |
)
|
867 |
|
|
|
|
|
868 |
if __name__ == "__main__":
|
869 |
try:
|
870 |
demo_instance = Demo()
|