|
import gradio as gr |
|
import os |
|
import sys |
|
import json |
|
import requests |
|
|
|
|
|
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) |
|
FONT_PATH = os.path.join(CURRENT_DIR, 'NanumGothic-Regular.ttf') |
|
FONTS_CONF_PATH = os.path.join(CURRENT_DIR, 'fonts.conf') |
|
|
|
|
|
def create_fonts_conf(): |
|
"""Graphviz๊ฐ ๋ก์ปฌ ํฐํธ๋ฅผ ์ธ์ํ ์ ์๋๋ก fonts.conf ํ์ผ ์์ฑ""" |
|
fonts_conf_content = f"""<?xml version="1.0"?> |
|
<!DOCTYPE fontconfig SYSTEM "fonts.dtd"> |
|
<fontconfig> |
|
<!-- ๋ก์ปฌ ํฐํธ ๋๋ ํ ๋ฆฌ ์ถ๊ฐ --> |
|
<dir>{CURRENT_DIR}</dir> |
|
|
|
<!-- NanumGothic ํฐํธ ๋ณ์นญ ์ค์ --> |
|
<alias> |
|
<family>NanumGothic</family> |
|
<prefer> |
|
<family>NanumGothic-Regular</family> |
|
</prefer> |
|
</alias> |
|
|
|
<alias> |
|
<family>NanumGothic-Regular</family> |
|
<default> |
|
<family>NanumGothic-Regular</family> |
|
</default> |
|
</alias> |
|
|
|
<!-- ํ๊ธ ํฐํธ ๋งคํ --> |
|
<match target="pattern"> |
|
<test name="family"> |
|
<string>NanumGothic</string> |
|
</test> |
|
<edit name="family" mode="assign"> |
|
<string>NanumGothic-Regular</string> |
|
</edit> |
|
</match> |
|
</fontconfig> |
|
""" |
|
|
|
with open(FONTS_CONF_PATH, 'w', encoding='utf-8') as f: |
|
f.write(fonts_conf_content) |
|
print(f"fonts.conf ํ์ผ ์์ฑ๋จ: {FONTS_CONF_PATH}") |
|
|
|
|
|
if os.path.exists(FONT_PATH): |
|
print(f"ํ๊ธ ํฐํธ ํ์ผ ๋ฐ๊ฒฌ: {FONT_PATH}") |
|
|
|
|
|
create_fonts_conf() |
|
|
|
|
|
os.environ['GDFONTPATH'] = CURRENT_DIR |
|
os.environ['FONTCONFIG_PATH'] = CURRENT_DIR |
|
os.environ['FONTCONFIG_FILE'] = FONTS_CONF_PATH |
|
|
|
print(f"GDFONTPATH ์ค์ : {CURRENT_DIR}") |
|
print(f"FONTCONFIG_FILE ์ค์ : {FONTS_CONF_PATH}") |
|
else: |
|
print(f"๊ฒฝ๊ณ : ํ๊ธ ํฐํธ ํ์ผ์ ์ฐพ์ ์ ์์ต๋๋ค: {FONT_PATH}") |
|
|
|
|
|
os.environ['KOREAN_FONT_PATH'] = FONT_PATH |
|
|
|
from concept_map_generator import generate_concept_map |
|
from synoptic_chart_generator import generate_synoptic_chart |
|
from radial_diagram_generator import generate_radial_diagram |
|
from process_flow_generator import generate_process_flow_diagram |
|
from wbs_diagram_generator import generate_wbs_diagram |
|
|
|
from sample_data import CONCEPT_MAP_JSON, SYNOPTIC_CHART_JSON, RADIAL_DIAGRAM_JSON, PROCESS_FLOW_JSON, WBS_DIAGRAM_JSON |
|
|
|
|
|
def call_llm_api(prompt, diagram_type): |
|
"""Friendli AI API๋ฅผ ํธ์ถํ์ฌ JSON ์์ฑ""" |
|
token = os.environ.get("FRIENDLI_TOKEN") or "YOUR_FRIENDLI_TOKEN" |
|
url = "https://api.friendli.ai/dedicated/v1/chat/completions" |
|
headers = { |
|
"Authorization": "Bearer " + token, |
|
"Content-Type": "application/json" |
|
} |
|
|
|
|
|
json_guides = { |
|
"Concept Map": """Generate a JSON for a concept map with the EXACT following structure: |
|
{ |
|
"central_node": "Main Topic", |
|
"nodes": [ |
|
{ |
|
"id": "node1", |
|
"label": "First Concept", |
|
"relationship": "is part of", |
|
"subnodes": [ |
|
{ |
|
"id": "node1_1", |
|
"label": "Sub Concept 1", |
|
"relationship": "includes", |
|
"subnodes": [] |
|
} |
|
] |
|
}, |
|
{ |
|
"id": "node2", |
|
"label": "Second Concept", |
|
"relationship": "relates to", |
|
"subnodes": [] |
|
} |
|
] |
|
}""", |
|
"Synoptic Chart": """Generate a JSON for a synoptic chart with the EXACT following structure: |
|
{ |
|
"central_node": "Chart Title", |
|
"nodes": [ |
|
{ |
|
"id": "phase1", |
|
"label": "Phase 1 Name", |
|
"relationship": "starts with", |
|
"subnodes": [ |
|
{ |
|
"id": "sub1_1", |
|
"label": "Sub Item 1", |
|
"relationship": "includes", |
|
"subnodes": [] |
|
} |
|
] |
|
} |
|
] |
|
}""", |
|
"Radial Diagram": """Generate a JSON for a radial diagram with the EXACT following structure: |
|
{ |
|
"central_node": "Central Concept", |
|
"nodes": [ |
|
{ |
|
"id": "branch1", |
|
"label": "Branch 1", |
|
"relationship": "connected to", |
|
"subnodes": [ |
|
{ |
|
"id": "item1", |
|
"label": "Item 1", |
|
"relationship": "example", |
|
"subnodes": [] |
|
} |
|
] |
|
} |
|
] |
|
}""", |
|
"Process Flow": """Generate a JSON for a process flow diagram with the EXACT following structure: |
|
{ |
|
"start_node": "Start Process", |
|
"nodes": [ |
|
{"id": "step1", "label": "First Step", "type": "process"}, |
|
{"id": "step2", "label": "Decision Point", "type": "decision"}, |
|
{"id": "step3", "label": "Another Step", "type": "process"}, |
|
{"id": "end", "label": "End Process", "type": "end"} |
|
], |
|
"connections": [ |
|
{"from": "start_node", "to": "step1", "label": "Begin"}, |
|
{"from": "step1", "to": "step2", "label": "Next"}, |
|
{"from": "step2", "to": "step3", "label": "Yes"}, |
|
{"from": "step3", "to": "end", "label": "Complete"} |
|
] |
|
}""", |
|
"WBS Diagram": """Generate a JSON for a WBS diagram with the EXACT following structure: |
|
{ |
|
"project_title": "Project Name", |
|
"phases": [ |
|
{ |
|
"id": "phase1", |
|
"label": "Phase 1", |
|
"tasks": [ |
|
{ |
|
"id": "task1_1", |
|
"label": "Task 1.1", |
|
"subtasks": [ |
|
{ |
|
"id": "subtask1_1_1", |
|
"label": "Subtask 1.1.1", |
|
"sub_subtasks": [] |
|
} |
|
] |
|
} |
|
] |
|
} |
|
] |
|
}""" |
|
} |
|
|
|
system_prompt = f"""You are a helpful assistant that generates JSON structures for diagrams. |
|
{json_guides.get(diagram_type, '')} |
|
|
|
Important rules: |
|
1. Generate ONLY valid JSON without any explanation or markdown formatting |
|
2. The JSON must follow the EXACT structure shown above - do not change field names |
|
3. Make the content relevant to the user's prompt |
|
4. Use the user's language (Korean or English) for the content values |
|
5. For IDs, use simple alphanumeric strings without spaces (e.g., "node1", "task1_1") |
|
6. Ensure all connections reference existing node IDs |
|
7. For Process Flow: 'type' can be: "process", "decision", "start", "end", "io" |
|
8. For nested structures (Concept Map, Synoptic Chart, Radial, WBS), include empty 'subnodes' or 'subtasks' arrays when there are no children |
|
9. Do not add any additional fields not shown in the example structure""" |
|
|
|
payload = { |
|
"model": "dep89a2fld32mcm", |
|
"messages": [ |
|
{"role": "system", "content": system_prompt}, |
|
{"role": "user", "content": f"Create a {diagram_type} JSON for: {prompt}"} |
|
], |
|
"max_tokens": 16384, |
|
"top_p": 0.8, |
|
"stream": False |
|
} |
|
|
|
try: |
|
response = requests.post(url, json=payload, headers=headers, timeout=30) |
|
|
|
|
|
if response.status_code != 200: |
|
return json.dumps({"error": f"API returned status code {response.status_code}: {response.text}"}) |
|
|
|
response_data = response.json() |
|
|
|
if 'choices' in response_data and len(response_data['choices']) > 0: |
|
content = response_data['choices'][0]['message']['content'] |
|
|
|
content = content.strip() |
|
if content.startswith("```json"): |
|
content = content[7:] |
|
if content.startswith("```"): |
|
content = content[3:] |
|
if content.endswith("```"): |
|
content = content[:-3] |
|
|
|
|
|
content = content.strip() |
|
|
|
json_start = content.find('{') |
|
if json_start != -1: |
|
content = content[json_start:] |
|
|
|
bracket_count = 0 |
|
json_end = -1 |
|
for i, char in enumerate(content): |
|
if char == '{': |
|
bracket_count += 1 |
|
elif char == '}': |
|
bracket_count -= 1 |
|
if bracket_count == 0: |
|
json_end = i |
|
break |
|
if json_end != -1: |
|
content = content[:json_end + 1] |
|
|
|
return content.strip() |
|
else: |
|
return json.dumps({"error": "No response from LLM"}) |
|
except requests.exceptions.Timeout: |
|
return json.dumps({"error": "Request timed out"}) |
|
except requests.exceptions.RequestException as e: |
|
print(f"LLM API Request Error: {str(e)}") |
|
return json.dumps({"error": f"Request failed: {str(e)}"}) |
|
except Exception as e: |
|
print(f"LLM API Error: {str(e)}") |
|
return json.dumps({"error": str(e)}) |
|
|
|
def generate_with_llm(prompt, diagram_type, output_format): |
|
"""LLM์ผ๋ก JSON์ ์์ฑํ๊ณ ๋ค์ด์ด๊ทธ๋จ์ ์์ฑ""" |
|
if not prompt: |
|
return None, "Please enter a prompt" |
|
|
|
|
|
generated_json = call_llm_api(prompt, diagram_type) |
|
|
|
try: |
|
|
|
json_data = json.loads(generated_json) |
|
json_str = json.dumps(json_data, indent=2, ensure_ascii=False) |
|
|
|
|
|
if diagram_type in ["Concept Map", "Synoptic Chart", "Radial Diagram"]: |
|
if "central_node" not in json_data or "nodes" not in json_data: |
|
return None, f"Invalid JSON structure for {diagram_type}. Missing 'central_node' or 'nodes'. Generated JSON:\n{json_str}" |
|
elif diagram_type == "Process Flow": |
|
if "start_node" not in json_data or "nodes" not in json_data or "connections" not in json_data: |
|
return None, f"Invalid JSON structure for Process Flow. Missing 'start_node', 'nodes', or 'connections'. Generated JSON:\n{json_str}" |
|
elif diagram_type == "WBS Diagram": |
|
if "project_title" not in json_data or "phases" not in json_data: |
|
return None, f"Invalid JSON structure for WBS. Missing 'project_title' or 'phases'. Generated JSON:\n{json_str}" |
|
|
|
|
|
try: |
|
if diagram_type == "Concept Map": |
|
diagram = generate_concept_map(json_str, output_format) |
|
elif diagram_type == "Synoptic Chart": |
|
diagram = generate_synoptic_chart(json_str, output_format) |
|
elif diagram_type == "Radial Diagram": |
|
diagram = generate_radial_diagram(json_str, output_format) |
|
elif diagram_type == "Process Flow": |
|
diagram = generate_process_flow_diagram(json_str, output_format) |
|
elif diagram_type == "WBS Diagram": |
|
diagram = generate_wbs_diagram(json_str, output_format) |
|
else: |
|
return None, "Invalid diagram type" |
|
|
|
|
|
if isinstance(diagram, str) and diagram.startswith("Error:"): |
|
return None, f"Diagram generation error: {diagram}\n\nGenerated JSON:\n{json_str}" |
|
|
|
return diagram, json_str |
|
|
|
except Exception as e: |
|
return None, f"Error generating diagram: {str(e)}\n\nGenerated JSON:\n{json_str}" |
|
|
|
except json.JSONDecodeError as e: |
|
return None, f"Invalid JSON generated: {str(e)}\n\nGenerated content:\n{generated_json}" |
|
except Exception as e: |
|
return None, f"Unexpected error: {str(e)}\n\nGenerated content:\n{generated_json}" |
|
|
|
if __name__ == "__main__": |
|
DEFAULT_BASE_COLOR = '#19191a' |
|
|
|
with gr.Blocks( |
|
title="Advanced Graph Generator", |
|
theme=gr.themes.Soft( |
|
primary_hue="violet", |
|
secondary_hue="purple", |
|
), |
|
css=""" |
|
/* ๊ทธ๋ผ๋์ธํธ ๋ฐฐ๊ฒฝ */ |
|
.gradio-container { |
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif !important; |
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
|
min-height: 100vh; |
|
} |
|
|
|
/* ๋ฉ์ธ ์ปจํ
์ด๋ ์คํ์ผ */ |
|
.main-container { |
|
background: rgba(255, 255, 255, 0.95); |
|
backdrop-filter: blur(10px); |
|
border-radius: 20px; |
|
padding: 30px; |
|
margin: 20px auto; |
|
max-width: 1400px; |
|
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1); |
|
} |
|
|
|
/* ํค๋ ์คํ์ผ */ |
|
.header-section { |
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
|
color: white; |
|
padding: 40px; |
|
border-radius: 15px; |
|
margin-bottom: 30px; |
|
text-align: center; |
|
box-shadow: 0 10px 30px rgba(102, 126, 234, 0.3); |
|
} |
|
|
|
.header-section h1 { |
|
font-size: 2.5em; |
|
font-weight: 700; |
|
margin-bottom: 10px; |
|
} |
|
|
|
.header-section p { |
|
font-size: 1.2em; |
|
opacity: 0.9; |
|
} |
|
|
|
/* ํญ ์คํ์ผ */ |
|
.gr-tab-item { |
|
padding: 15px 30px; |
|
font-size: 1.1em; |
|
font-weight: 600; |
|
background: white; |
|
border-radius: 10px 10px 0 0; |
|
transition: all 0.3s ease; |
|
margin-right: 5px; |
|
} |
|
|
|
.gr-tab-item:hover { |
|
background: linear-gradient(135deg, #f5f7fa 0%, #e9ecef 100%); |
|
} |
|
|
|
.gr-tab-item.selected { |
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
|
color: white !important; |
|
} |
|
|
|
/* ๋ฒํผ ์คํ์ผ */ |
|
.gr-button { |
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
|
color: white; |
|
border: none; |
|
padding: 12px 30px; |
|
font-size: 1.1em; |
|
font-weight: 600; |
|
border-radius: 10px; |
|
transition: all 0.3s ease; |
|
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3); |
|
} |
|
|
|
.gr-button:hover { |
|
transform: translateY(-2px); |
|
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4); |
|
} |
|
|
|
.gr-button.primary { |
|
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); |
|
} |
|
|
|
/* ์
๋ ฅ ํ๋ ์คํ์ผ */ |
|
.gr-textbox, .gr-dropdown { |
|
border: 2px solid #e9ecef; |
|
border-radius: 10px; |
|
padding: 12px; |
|
font-size: 1em; |
|
transition: all 0.3s ease; |
|
background: white; |
|
} |
|
|
|
.gr-textbox:focus, .gr-dropdown:focus { |
|
border-color: #667eea; |
|
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); |
|
} |
|
|
|
/* ํจ๋ ์คํ์ผ */ |
|
.panel-section { |
|
background: white; |
|
border-radius: 15px; |
|
padding: 25px; |
|
margin-bottom: 20px; |
|
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08); |
|
} |
|
|
|
/* ์ด๋ฏธ์ง ์ปจํ
์ด๋ ์คํ์ผ */ |
|
.gr-image { |
|
border-radius: 15px; |
|
overflow: hidden; |
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); |
|
} |
|
|
|
/* ์์ ์ด๋ฏธ์ง ์คํ์ผ */ |
|
.example-images { |
|
gap: 20px; |
|
} |
|
|
|
.example-images .gr-image { |
|
transition: transform 0.3s ease; |
|
} |
|
|
|
.example-images .gr-image:hover { |
|
transform: scale(1.02); |
|
} |
|
|
|
/* ๋ผ๋์ค ๋ฒํผ ์คํ์ผ */ |
|
.gr-radio { |
|
background: white; |
|
padding: 15px; |
|
border-radius: 10px; |
|
border: 2px solid #e9ecef; |
|
} |
|
|
|
/* LLM ํญ ํน๋ณ ์คํ์ผ */ |
|
.llm-tab { |
|
background: linear-gradient(135deg, #f5f7fa 0%, #ffffff 100%); |
|
padding: 30px; |
|
border-radius: 15px; |
|
} |
|
|
|
.llm-input-section { |
|
background: white; |
|
padding: 25px; |
|
border-radius: 15px; |
|
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05); |
|
margin-bottom: 20px; |
|
} |
|
|
|
/* ๋ฐ์ํ ๋์์ธ */ |
|
@media (max-width: 768px) { |
|
.main-container { |
|
padding: 15px; |
|
margin: 10px; |
|
} |
|
|
|
.header-section h1 { |
|
font-size: 2em; |
|
} |
|
|
|
.gr-tab-item { |
|
padding: 10px 15px; |
|
font-size: 1em; |
|
} |
|
} |
|
""" |
|
) as demo: |
|
with gr.Column(elem_classes=["main-container"]): |
|
with gr.Column(elem_classes=["header-section"]): |
|
gr.Markdown( |
|
""" |
|
# ๐จ Graphify: AI-Powered Diagram Generator |
|
### Transform your ideas into beautiful diagrams instantly with AI โก |
|
""" |
|
) |
|
|
|
with gr.Row(variant="panel", elem_classes=["panel-section"]): |
|
output_format_radio = gr.Radio( |
|
choices=["png", "svg"], |
|
value="png", |
|
label="๐ Output Format", |
|
interactive=True |
|
) |
|
|
|
with gr.Tabs(): |
|
|
|
with gr.TabItem("๐ค AI Assistant", elem_classes=["llm-tab"]): |
|
gr.Markdown( |
|
""" |
|
### ๐ก Describe your diagram in Korean or English, and AI will create it for you! |
|
""" |
|
) |
|
|
|
with gr.Row(): |
|
with gr.Column(scale=1, elem_classes=["llm-input-section"]): |
|
prompt_input = gr.Textbox( |
|
placeholder="์: '๋จธ์ ๋ฌ๋ ํ๋ก์ธ์ค๋ฅผ ๋ณด์ฌ์ฃผ๋ ํ๋ก์ฐ์ฐจํธ๋ฅผ ๋ง๋ค์ด์ค' or 'Create a concept map about climate change'", |
|
label="๐ Enter your prompt", |
|
lines=3 |
|
) |
|
|
|
diagram_type_select = gr.Dropdown( |
|
choices=["Concept Map", "Synoptic Chart", "Radial Diagram", "Process Flow", "WBS Diagram"], |
|
value="Concept Map", |
|
label="๐ Select Diagram Type", |
|
interactive=True |
|
) |
|
|
|
generate_btn = gr.Button("โจ Generate with AI", variant="primary", size="lg") |
|
|
|
generated_json_output = gr.Textbox( |
|
label="๐ Generated JSON", |
|
lines=15, |
|
interactive=True, |
|
visible=True |
|
) |
|
|
|
with gr.Column(scale=2): |
|
ai_output_image = gr.Image( |
|
label="๐จ Generated Diagram", |
|
type="filepath", |
|
show_download_button=True, |
|
height=600 |
|
) |
|
|
|
generate_btn.click( |
|
fn=generate_with_llm, |
|
inputs=[prompt_input, diagram_type_select, output_format_radio], |
|
outputs=[ai_output_image, generated_json_output] |
|
) |
|
|
|
with gr.Row(elem_classes=["panel-section"]): |
|
gr.Examples( |
|
examples=[ |
|
["์ํํธ์จ์ด ๊ฐ๋ฐ ์๋ช
์ฃผ๊ธฐ๋ฅผ ๋ณด์ฌ์ฃผ๋ ํ๋ก์ธ์ค ํ๋ก์ฐ๋ฅผ ๋ง๋ค์ด์ค", "Process Flow"], |
|
["์ธ๊ณต์ง๋ฅ์ ์ข
๋ฅ์ ์์ฉ ๋ถ์ผ์ ๋ํ ์ปจ์
๋งต์ ๋ง๋ค์ด์ค", "Concept Map"], |
|
["์จ๋ผ์ธ ์ผํ๋ชฐ ๊ตฌ์ถ ํ๋ก์ ํธ์ WBS๋ฅผ ๋ง๋ค์ด์ค", "WBS Diagram"], |
|
["์ฌ์ ๊ฐ๋ฅ ์๋์ง์ ์ข
๋ฅ๋ฅผ ์ค์ฌ์ผ๋ก ๋ฐฉ์ฌํ ๋ค์ด์ด๊ทธ๋จ์ ๋ง๋ค์ด์ค", "Radial Diagram"], |
|
["๋จธ์ ๋ฌ๋ ํ์ดํ๋ผ์ธ์ ๋จ๊ณ๋ณ ๊ตฌ์ฑ์ ์๋ํฑ ์ฐจํธ๋ก ๋ณด์ฌ์ค", "Synoptic Chart"] |
|
], |
|
inputs=[prompt_input, diagram_type_select], |
|
label="๐ญ Example Prompts" |
|
) |
|
|
|
|
|
with gr.TabItem("๐บ๏ธ Concept Map"): |
|
with gr.Row(): |
|
with gr.Column(scale=1, elem_classes=["panel-section"]): |
|
json_input_cm = gr.Textbox( |
|
value=CONCEPT_MAP_JSON, |
|
placeholder="Paste JSON following the documented format", |
|
label="JSON Input", |
|
lines=20 |
|
) |
|
submit_btn_cm = gr.Button("Generate Concept Map", variant="primary") |
|
|
|
with gr.Column(scale=2): |
|
output_cm = gr.Image( |
|
label="Generated Diagram", |
|
type="filepath", |
|
show_download_button=True, |
|
height=500 |
|
) |
|
|
|
submit_btn_cm.click( |
|
fn=generate_concept_map, |
|
inputs=[json_input_cm, output_format_radio], |
|
outputs=output_cm |
|
) |
|
|
|
gr.Markdown("## ๐ธ Examples") |
|
with gr.Row(elem_classes=["example-images"]): |
|
gr.Image(value="./images/cm1.svg", label="Sample 1", show_label=True, interactive=False) |
|
gr.Image(value="./images/cm2.svg", label="Sample 2", show_label=True, interactive=False) |
|
|
|
with gr.TabItem("๐ Synoptic Chart"): |
|
with gr.Row(): |
|
with gr.Column(scale=1, elem_classes=["panel-section"]): |
|
json_input_sc = gr.Textbox( |
|
value=SYNOPTIC_CHART_JSON, |
|
placeholder="Paste JSON following the documented format", |
|
label="JSON Input", |
|
lines=20 |
|
) |
|
submit_btn_sc = gr.Button("Generate Synoptic Chart", variant="primary") |
|
|
|
with gr.Column(scale=2): |
|
output_sc = gr.Image( |
|
label="Generated Diagram", |
|
type="filepath", |
|
show_download_button=True, |
|
height=500 |
|
) |
|
|
|
submit_btn_sc.click( |
|
fn=generate_synoptic_chart, |
|
inputs=[json_input_sc, output_format_radio], |
|
outputs=output_sc |
|
) |
|
|
|
gr.Markdown("## ๐ธ Examples") |
|
with gr.Row(elem_classes=["example-images"]): |
|
gr.Image(value="./images/sc1.svg", label="Sample 1", show_label=True, interactive=False) |
|
gr.Image(value="./images/sc2.svg", label="Sample 2", show_label=True, interactive=False) |
|
|
|
with gr.TabItem("โ๏ธ Radial Diagram"): |
|
with gr.Row(): |
|
with gr.Column(scale=1, elem_classes=["panel-section"]): |
|
json_input_rd = gr.Textbox( |
|
value=RADIAL_DIAGRAM_JSON, |
|
placeholder="Paste JSON following the documented format", |
|
label="JSON Input", |
|
lines=20 |
|
) |
|
submit_btn_rd = gr.Button("Generate Radial Diagram", variant="primary") |
|
|
|
with gr.Column(scale=2): |
|
output_rd = gr.Image( |
|
label="Generated Diagram", |
|
type="filepath", |
|
show_download_button=True, |
|
height=500 |
|
) |
|
|
|
submit_btn_rd.click( |
|
fn=generate_radial_diagram, |
|
inputs=[json_input_rd, output_format_radio], |
|
outputs=output_rd |
|
) |
|
|
|
gr.Markdown("## ๐ธ Examples") |
|
with gr.Row(elem_classes=["example-images"]): |
|
gr.Image(value="./images/rd1.svg", label="Sample 1", show_label=True, interactive=False) |
|
gr.Image(value="./images/rd2.svg", label="Sample 2", show_label=True, interactive=False) |
|
gr.Image(value="./images/rd3.svg", label="Sample 3", show_label=True, interactive=False) |
|
gr.Image(value="./images/rd4.svg", label="Sample 4", show_label=True, interactive=False) |
|
|
|
with gr.TabItem("๐ Process Flow"): |
|
with gr.Row(): |
|
with gr.Column(scale=1, elem_classes=["panel-section"]): |
|
json_input_pf = gr.Textbox( |
|
value=PROCESS_FLOW_JSON, |
|
placeholder="Paste JSON following the documented format", |
|
label="JSON Input", |
|
lines=20 |
|
) |
|
submit_btn_pf = gr.Button("Generate Process Flow", variant="primary") |
|
|
|
with gr.Column(scale=2): |
|
output_pf = gr.Image( |
|
label="Generated Diagram", |
|
type="filepath", |
|
show_download_button=True, |
|
height=500 |
|
) |
|
|
|
submit_btn_pf.click( |
|
fn=generate_process_flow_diagram, |
|
inputs=[json_input_pf, output_format_radio], |
|
outputs=output_pf |
|
) |
|
|
|
gr.Markdown("## ๐ธ Examples") |
|
with gr.Row(elem_classes=["example-images"]): |
|
gr.Image(value="./images/pf1.svg", label="Sample 1", show_label=True, interactive=False) |
|
gr.Image(value="./images/pf2.svg", label="Sample 2", show_label=True, interactive=False) |
|
|
|
with gr.TabItem("๐ WBS Diagram"): |
|
with gr.Row(): |
|
with gr.Column(scale=1, elem_classes=["panel-section"]): |
|
json_input_wbs = gr.Textbox( |
|
value=WBS_DIAGRAM_JSON, |
|
placeholder="Paste JSON following the documented format", |
|
label="JSON Input", |
|
lines=20 |
|
) |
|
submit_btn_wbs = gr.Button("Generate WBS Diagram", variant="primary") |
|
|
|
with gr.Column(scale=2): |
|
output_wbs = gr.Image( |
|
label="Generated Diagram", |
|
type="filepath", |
|
show_download_button=True, |
|
height=500 |
|
) |
|
|
|
submit_btn_wbs.click( |
|
fn=generate_wbs_diagram, |
|
inputs=[json_input_wbs, output_format_radio], |
|
outputs=output_wbs |
|
) |
|
|
|
gr.Markdown("## ๐ธ Examples") |
|
with gr.Row(elem_classes=["example-images"]): |
|
gr.Image(value="./images/wd1.svg", label="Sample 1", show_label=True, interactive=False) |
|
gr.Image(value="./images/wd2.svg", label="Sample 2", show_label=True, interactive=False) |
|
|
|
demo.launch( |
|
mcp_server=True, |
|
share=False, |
|
server_port=7860, |
|
server_name="0.0.0.0" |
|
) |