Spaces:
Running
Running
""" | |
app.py βββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
β π Preview JSON : μ½λ μ°½μ νμ¬ μν¬νλ‘ JSON νμ | |
β πΎ Save JSON : JSON νμΌ λ€μ΄λ‘λ | |
β π Load JSON : JSON μ λ‘λ β λ ΈλΒ·μ’νΒ·μ°κ²° μ¦μ 볡μ | |
""" | |
import os, json, typing, tempfile | |
import gradio as gr | |
from gradio_workflowbuilder import WorkflowBuilder | |
# ------------------------------------------------------------------- | |
# π οΈ ν¬νΌ ν¨μ | |
# ------------------------------------------------------------------- | |
def export_pretty(data: typing.Dict[str, typing.Any]) -> str: | |
"""μ½λλ·° λ―Έλ¦¬λ³΄κΈ°μ© λ¬Έμμ΄.""" | |
return json.dumps(data, indent=2, ensure_ascii=False) if data else "No workflow to export" | |
def export_file(data: typing.Dict[str, typing.Any]) -> str | None: | |
"""μμ JSON νμΌ κ²½λ‘ λ°ν(DownloadButton μ©).""" | |
if not data: | |
return None | |
fd, path = tempfile.mkstemp(suffix=".json") | |
with os.fdopen(fd, "w", encoding="utf-8") as f: | |
json.dump(data, f, ensure_ascii=False, indent=2) | |
return path | |
def import_workflow(file_obj: gr.File) -> tuple[gr.Update | None, str]: | |
"""μ λ‘λλ JSON β WorkflowBuilder κ° & μ½λλ·° λμ κ°±μ .""" | |
if file_obj is None: | |
return None, "No workflow loaded" | |
with open(file_obj.name, "r", encoding="utf-8") as f: | |
data = json.load(f) | |
# gr.update λ‘ κ°μΈμΌ μκ°μ μΌλ‘ μ¬λ λλ§λ¨ | |
return gr.update(value=data), json.dumps(data, indent=2, ensure_ascii=False) | |
# ------------------------------------------------------------------- | |
# π¨ UI (μΈλΌμΈ CSS) | |
# ------------------------------------------------------------------- | |
CSS = """ | |
.main-container{max-width:1600px;margin:0 auto;} | |
.workflow-section{margin-bottom:2rem;} | |
.button-row{display:flex;gap:1rem;justify-content:center;margin:1rem 0;} | |
.component-description{ | |
padding:24px;background:linear-gradient(135deg,#f8fafc 0%,#e2e8f0 100%); | |
border-left:4px solid #3b82f6;border-radius:12px; | |
box-shadow:0 2px 8px rgba(0,0,0,.05);margin:16px 0; | |
font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif; | |
} | |
.component-description p{margin:10px 0;line-height:1.6;color:#374151;} | |
.base-description{font-size:17px;font-weight:600;color:#1e293b;} | |
.base-description strong{color:#3b82f6;font-weight:700;} | |
.feature-description{font-size:16px;font-weight:500;color:#1e293b;} | |
.customization-note{font-size:15px;font-style:italic;color:#64748b;} | |
.sample-intro{font-size:15px;font-weight:600;color:#1e293b;margin-top:16px; | |
border-top:1px solid #e2e8f0;padding-top:16px;} | |
""" | |
# ------------------------------------------------------------------- | |
# π₯οΈ Gradio μ± | |
# ------------------------------------------------------------------- | |
with gr.Blocks(title="π¨ Visual Workflow Builder", theme=gr.themes.Soft(), css=CSS) as demo: | |
with gr.Column(elem_classes=["main-container"]): | |
gr.Markdown("# π¨ Visual Workflow Builder \n**Create sophisticated workflows with drag-and-drop simplicity.**") | |
gr.HTML( | |
""" | |
<div class="component-description"> | |
<p class="base-description">Base custom component powered by <strong>svelteflow</strong>.</p> | |
<p class="feature-description">Create custom workflows.</p> | |
<p class="customization-note">You can customise the nodes as well as the design of the workflow.</p> | |
<p class="sample-intro">Here is a sample:</p> | |
</div> | |
""" | |
) | |
# βββ Workflow Builder βββ | |
with gr.Column(elem_classes=["workflow-section"]): | |
workflow_builder = WorkflowBuilder( | |
label="π¨ Visual Workflow Designer", | |
info="Drag from output β input β’ Click nodes to edit properties", | |
) | |
# βββ Export / Import 컨νΈλ‘€ βββ | |
gr.Markdown("## πΎ Export Β· π Import") | |
with gr.Row(elem_classes=["button-row"]): | |
btn_preview = gr.Button("π Preview JSON") | |
btn_download = gr.DownloadButton("πΎ Save JSON file") | |
file_upload = gr.File(label="π Load JSON", file_types=[".json"]) | |
code_view = gr.Code(language="json", label="Workflow Configuration", lines=14) | |
# μ΄λ²€νΈ μ°κ²° | |
btn_preview.click(fn=export_pretty, inputs=workflow_builder, outputs=code_view) | |
btn_download.click(fn=export_file, inputs=workflow_builder) | |
file_upload.change(fn=import_workflow, inputs=file_upload, outputs=[workflow_builder, code_view]) | |
# μ¬μ©λ² | |
with gr.Accordion("π How to Use", open=False): | |
gr.Markdown( | |
""" | |
1. **Add Components** β drag items from the sidebar onto the canvas | |
2. **Connect Nodes** β drag from blue handle (output) β gray handle (input) | |
3. **Edit** β click any node to change its properties | |
4. **Save** β *Save JSON file* to download your workflow | |
5. **Load** β *Load JSON* to restore (nodes auto-position) | |
""" | |
) | |
# ------------------------------------------------------------------- | |
# π μ€ν | |
# ------------------------------------------------------------------- | |
if __name__ == "__main__": | |
demo.launch(server_name="0.0.0.0", show_error=True) | |