Graphify / app.py
ZahirJS's picture
Create app.py
7c43635 verified
raw
history blame
4.58 kB
import gradio as gr
import json
from graphviz import Digraph
import os
from typing import Dict, Any
def generate_concept_map(json_input: str) -> str:
"""
Generates a concept map from structured JSON
Args:
json_input (str): JSON describing the concept map structure.
Required format:
{
"central_node": "Main concept",
"nodes": [
{
"id": "unique_identifier",
"label": "Node label",
"relationship": "Relationship to parent",
"subnodes": [...] # Optional
}
]
}
Returns:
str: Image URL (compatible with Hugging Face Spaces)
Raises:
ValueError: If JSON doesn't meet required format
"""
try:
# Validate input
if not json_input.strip():
return "Error: Empty input"
data = json.loads(json_input)
# Validate basic structure
if 'central_node' not in data or 'nodes' not in data:
raise ValueError("Missing required fields: central_node or nodes")
# Create graph
dot = Digraph(
name='ConceptMap',
format='png',
graph_attr={
'rankdir': 'TB',
'splines': 'ortho',
'bgcolor': 'transparent'
}
)
# Central node
dot.node(
'central',
data['central_node'],
shape='ellipse',
style='filled',
fillcolor='#2196F3',
fontcolor='white',
fontsize='14'
)
# Process nodes
for node in data['nodes']:
node_id = node.get('id')
label = node.get('label')
relationship = node.get('relationship')
# Validate node
if not all([node_id, label, relationship]):
raise ValueError(f"Invalid node: {node}")
# Create main node
dot.node(
node_id,
label,
shape='box',
style='filled',
fillcolor='#4CAF50',
fontcolor='white',
fontsize='12'
)
# Connect to central node
dot.edge(
'central',
node_id,
label=relationship,
color='#9C27B0',
fontsize='10'
)
# Process subnodes
for subnode in node.get('subnodes', []):
sub_id = subnode.get('id')
sub_label = subnode.get('label')
sub_rel = subnode.get('relationship')
if not all([sub_id, sub_label, sub_rel]):
raise ValueError(f"Invalid subnode: {subnode}")
dot.node(
sub_id,
sub_label,
shape='diamond',
style='filled',
fillcolor='#FF5722',
fontcolor='white',
fontsize='10'
)
dot.edge(
node_id,
sub_id,
label=sub_rel,
color='#E91E63',
fontsize='8'
)
# Save image
filename = f"/tmp/concept_map_{hash(json_input)}.gv"
dot.render(filename, format='png', cleanup=True)
# Return Hugging Face compatible URL
return f"/file={filename}.png"
except json.JSONDecodeError:
return "Error: Invalid JSON"
except Exception as e:
return f"Error: {str(e)}"
if __name__ == "__main__":
demo = gr.Interface(
fn=generate_concept_map,
inputs=gr.Textbox(
placeholder="Paste structured JSON here...",
label="JSON Input",
lines=15
),
outputs=gr.Textbox(
label="Image URL",
placeholder="Concept map URL will be generated here"
),
title="Concept Map Generator",
description="Create concept maps from JSON (Claude compatible)"
)
# Hugging Face Spaces configuration
demo.launch(
mcp_server=True,
share=False,
server_port=int(os.getenv('PORT', 7860)),
server_name="0.0.0.0"
)