File size: 5,435 Bytes
8b11442
5d2ac6d
1cf083d
6059561
ffdc606
1cf083d
8b11442
72b5d06
6059561
 
72b5d06
5d2ac6d
 
a34c24c
 
 
5d2ac6d
a34c24c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ffdc606
72b5d06
 
 
5d2ac6d
 
 
5250769
72b5d06
1cf083d
6059561
a34c24c
72b5d06
a34c24c
72b5d06
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a34c24c
72b5d06
 
 
 
 
 
1cf083d
6059561
a34c24c
ffdc606
1cf083d
 
 
a34c24c
72b5d06
a34c24c
 
72b5d06
a34c24c
 
6059561
1cf083d
8b11442
 
72b5d06
5250769
1cf083d
a34c24c
6059561
a34c24c
72b5d06
5250769
72b5d06
6059561
 
72b5d06
 
 
 
 
 
 
 
 
 
 
 
 
 
6059561
1cf083d
72b5d06
6059561
 
 
 
 
72b5d06
6059561
 
72b5d06
a34c24c
72b5d06
a34c24c
 
6059561
a34c24c
 
72b5d06
 
a34c24c
 
 
 
 
 
 
 
72b5d06
a34c24c
 
 
 
 
 
 
5250769
a34c24c
6059561
a34c24c
8b11442
 
1cf083d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import streamlit as st
import pandas as pd
from graphviz import Digraph
import os
import base64
from io import StringIO

# Configure system path for Hugging Face Spaces
os.environ["PATH"] += os.pathsep + '/usr/bin/graphviz'

# Enhanced 3D styling CSS
st.markdown("""
<style>
    .stApp {
        background: #f8f9fa;
        font-family: 'Segoe UI', system-ui;
    }
    .st-emotion-cache-1kyxreq {
        justify-content: center;
    }
    .stButton>button {
        background: linear-gradient(135deg, #4CAF50, #45a049);
        color: white;
        border-radius: 8px;
        padding: 12px 24px;
        border: none;
        font-weight: 600;
        transition: transform 0.3s;
        box-shadow: 0 4px 12px rgba(76,175,80,0.3);
    }
    .stDownloadButton>button {
        background: linear-gradient(135deg, #2196F3, #1976D2);
    }
    .st-eb {
        border-radius: 10px;
        box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    }
    .node rect {
        filter: drop-shadow(2px 2px 2px rgba(0,0,0,0.2));
    }
</style>
""", unsafe_allow_html=True)

def create_org_chart(df, title):
    """Create professional org chart with 3D effects"""
    dot = Digraph(comment=title)
    dot.attr(rankdir='TB', labelloc='t', label=title, 
            fontsize='24', fontname='Arial', margin='0.5',
            splines='ortho', bgcolor='transparent')
    
    # 3D Node styling with gradient and shadow
    dot.attr('node', 
            shape='box',
            style='filled,rounded',
            fillcolor='linear-gradient(45deg, #45a049 0%, #4CAF50 100%)',
            gradientangle='270',
            fontname='Arial', 
            fontcolor='white',
            margin='0.4', 
            width='2', 
            height='0.9',
            fixedsize='false', 
            fontsize='14',
            penwidth='0',
            color='#2c3e50')
    
    # Edge styling for 3D effect
    dot.attr('edge', 
            color='#666666', 
            arrowsize='0.8', 
            penwidth='1.5', 
            dir='forward')

    # Process relationships
    added_nodes = set()
    for _, row in df.iterrows():
        parent = row['Parent'].strip()
        child = row['Child'].strip()
        if parent and child:
            if parent not in added_nodes:
                dot.node(parent, _attributes={'label': f'<<B>{parent}</B>>'})
                added_nodes.add(parent)
            if child not in added_nodes:
                dot.node(child, _attributes={'label': f'<<B>{child}</B>>'})
                added_nodes.add(child)
            dot.edge(parent, child)
    
    return dot

def main():
    st.title("🏒 3D Organization Chart Generator")
    
    with st.sidebar:
        st.header("βš™οΈ Configuration")
        chart_title = st.text_input("Chart Title", "Company Structure")
        st.markdown("---")
        st.markdown("### πŸ“‹ CSV Template")
        
        # CSV template download with 3D styling
        template = "Parent,Child\nCEO,CTO\nCEO,CFO\nCTO,Engineering Manager"
        b64 = base64.b64encode(template.encode()).decode()
        href = f'''
        <a href="data:file/csv;base64,{b64}" download="template.csv" 
           style="display: inline-block;
                  padding: 12px 24px;
                  border-radius: 8px;
                  background: linear-gradient(135deg, #4CAF50, #45a049);
                  color: white;
                  text-decoration: none;
                  font-weight: bold;
                  box-shadow: 0 4px 12px rgba(76,175,80,0.3);
                  transition: transform 0.3s;">
           πŸ“₯ Download Template
        </a>
        '''
        st.markdown(href, unsafe_allow_html=True)

    uploaded_file = st.file_uploader("πŸ“€ Upload CSV File", type=["csv"])
    
    if uploaded_file:
        try:
            df = pd.read_csv(uploaded_file)
            if {'Parent', 'Child'}.issubset(df.columns):
                with st.spinner("πŸ” Generating 3D visualization..."):
                    chart = create_org_chart(df, chart_title)
                    
                    # Two-column layout
                    col1, col2 = st.columns([3, 1])
                    
                    with col1:
                        st.graphviz_chart(chart, use_container_width=True)
                    
                    with col2:
                        st.markdown("### πŸ“€ Export Options")
                        
                        # PDF Export
                        pdf_bytes = chart.pipe(format='pdf')
                        st.download_button(
                            label="πŸ“„ Download PDF",
                            data=pdf_bytes,
                            file_name=f"{chart_title.replace(' ', '_')}.pdf",
                            mime="application/pdf",
                        )
                        
                        # PNG Export
                        png_bytes = chart.pipe(format='png')
                        st.download_button(
                            label="πŸ–ΌοΈ Download PNG",
                            data=png_bytes,
                            file_name=f"{chart_title.replace(' ', '_')}.png",
                            mime="image/png",
                        )
            else:
                st.error("❌ CSV must contain 'Parent' and 'Child' columns")
        except Exception as e:
            st.error(f"🚨 Error processing file: {str(e)}")

if __name__ == "__main__":
    main()