Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -23,7 +23,7 @@ def process_uploaded_file(file):
|
|
| 23 |
return None
|
| 24 |
return file
|
| 25 |
|
| 26 |
-
# If file is a dict, expect the "data" key to contain
|
| 27 |
if isinstance(file, dict):
|
| 28 |
if "data" in file and file["data"]:
|
| 29 |
temp_path = "/tmp/uploaded.csv"
|
|
@@ -48,16 +48,9 @@ def process_uploaded_file(file):
|
|
| 48 |
return None
|
| 49 |
|
| 50 |
# -------------------------
|
| 51 |
-
#
|
| 52 |
# -------------------------
|
| 53 |
def build_tree(df):
|
| 54 |
-
"""
|
| 55 |
-
Build a tree structure from CSV data.
|
| 56 |
-
Returns:
|
| 57 |
-
- employees: dict mapping employee name to HTML-formatted label
|
| 58 |
-
- children: dict mapping manager name to list of subordinate names.
|
| 59 |
-
- roots: list of root node names.
|
| 60 |
-
"""
|
| 61 |
employees = {}
|
| 62 |
children = {}
|
| 63 |
all_emps = set()
|
|
@@ -83,18 +76,25 @@ def build_tree(df):
|
|
| 83 |
roots = [df.iloc[0]["Name"].strip()]
|
| 84 |
return employees, children, roots
|
| 85 |
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 90 |
label = employees.get(node, node)
|
| 91 |
html = f"<li><div class='node'>{label}</div>"
|
| 92 |
if node in children and children[node]:
|
| 93 |
html += "<ul>"
|
| 94 |
for child in children[node]:
|
| 95 |
-
html += generate_node_html(child, employees, children)
|
| 96 |
html += "</ul>"
|
| 97 |
html += "</li>"
|
|
|
|
| 98 |
return html
|
| 99 |
|
| 100 |
def generate_org_chart_html(df, title):
|
|
@@ -116,7 +116,7 @@ def generate_org_chart_html(df, title):
|
|
| 116 |
margin: 20px;
|
| 117 |
}}
|
| 118 |
.org-chart ul {{
|
| 119 |
-
padding-top: 20px;
|
| 120 |
position: relative;
|
| 121 |
display: inline-block;
|
| 122 |
}}
|
|
@@ -171,10 +171,10 @@ def generate_org_chart_html(df, title):
|
|
| 171 |
return html_content
|
| 172 |
|
| 173 |
# -------------------------
|
| 174 |
-
# Main
|
| 175 |
# -------------------------
|
| 176 |
def generate_chart(file, title):
|
| 177 |
-
logging.info(
|
| 178 |
if not file:
|
| 179 |
return None, "Please upload a CSV file."
|
| 180 |
file_path = process_uploaded_file(file)
|
|
@@ -185,6 +185,7 @@ def generate_chart(file, title):
|
|
| 185 |
return None, "Uploaded file is a directory. Please upload a valid CSV file."
|
| 186 |
try:
|
| 187 |
df = pd.read_csv(file_path)
|
|
|
|
| 188 |
except Exception as e:
|
| 189 |
logging.error(f"Error reading CSV: {e}")
|
| 190 |
return None, f"Error reading CSV: {e}"
|
|
@@ -192,13 +193,14 @@ def generate_chart(file, title):
|
|
| 192 |
if not expected_columns.issubset(set(df.columns)):
|
| 193 |
return None, "CSV must contain Name, Role, and Reporting To columns."
|
| 194 |
|
| 195 |
-
# Generate
|
| 196 |
html_content = generate_org_chart_html(df, title)
|
| 197 |
|
| 198 |
# Generate PDF using WeasyPrint.
|
| 199 |
pdf_path = "/tmp/chart.pdf"
|
| 200 |
try:
|
| 201 |
HTML(string=html_content).write_pdf(pdf_path)
|
|
|
|
| 202 |
except Exception as e:
|
| 203 |
logging.error(f"Error generating PDF: {e}")
|
| 204 |
dummy_pdf = "/tmp/no_pdf.pdf"
|
|
@@ -208,10 +210,12 @@ def generate_chart(file, title):
|
|
| 208 |
|
| 209 |
# Convert PDF to PNG for preview using pdf2image.
|
| 210 |
try:
|
|
|
|
| 211 |
images = convert_from_path(pdf_path, dpi=150)
|
| 212 |
if images and len(images) > 0:
|
| 213 |
image_path = "/tmp/chart.png"
|
| 214 |
images[0].save(image_path, 'PNG')
|
|
|
|
| 215 |
else:
|
| 216 |
image_path = ""
|
| 217 |
except Exception as e:
|
|
@@ -221,7 +225,7 @@ def generate_chart(file, title):
|
|
| 221 |
return image_path, pdf_path
|
| 222 |
|
| 223 |
# -------------------------
|
| 224 |
-
# Template
|
| 225 |
# -------------------------
|
| 226 |
def download_template():
|
| 227 |
template_path = "/tmp/template.csv"
|
|
@@ -247,17 +251,14 @@ with gr.Blocks() as demo:
|
|
| 247 |
"Upload a CSV file (with columns: **Name, Role, Reporting To**) to generate an interactive organization chart. "
|
| 248 |
"Use the button below to download a CSV template."
|
| 249 |
)
|
| 250 |
-
|
| 251 |
with gr.Row():
|
| 252 |
template_button = gr.Button("Download CSV Template")
|
| 253 |
file_input = gr.File(label="Upload CSV File")
|
| 254 |
title_input = gr.Textbox(label="Enter PDF Title", placeholder="Company Org Chart")
|
| 255 |
submit_button = gr.Button("Generate Chart")
|
| 256 |
-
|
| 257 |
image_output = gr.Image(label="Generated Chart (PNG)")
|
| 258 |
pdf_output = gr.File(label="Download PDF")
|
| 259 |
template_output = gr.File(label="CSV Template")
|
| 260 |
-
|
| 261 |
template_button.click(download_template, outputs=template_output)
|
| 262 |
submit_button.click(generate_chart, inputs=[file_input, title_input], outputs=[image_output, pdf_output])
|
| 263 |
|
|
|
|
| 23 |
return None
|
| 24 |
return file
|
| 25 |
|
| 26 |
+
# If file is a dict, expect the "data" key to contain file content.
|
| 27 |
if isinstance(file, dict):
|
| 28 |
if "data" in file and file["data"]:
|
| 29 |
temp_path = "/tmp/uploaded.csv"
|
|
|
|
| 48 |
return None
|
| 49 |
|
| 50 |
# -------------------------
|
| 51 |
+
# Build tree structure from CSV
|
| 52 |
# -------------------------
|
| 53 |
def build_tree(df):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
employees = {}
|
| 55 |
children = {}
|
| 56 |
all_emps = set()
|
|
|
|
| 76 |
roots = [df.iloc[0]["Name"].strip()]
|
| 77 |
return employees, children, roots
|
| 78 |
|
| 79 |
+
# -------------------------
|
| 80 |
+
# Recursive HTML generation with cycle detection
|
| 81 |
+
# -------------------------
|
| 82 |
+
def generate_node_html(node, employees, children, visited=None):
|
| 83 |
+
if visited is None:
|
| 84 |
+
visited = set()
|
| 85 |
+
if node in visited:
|
| 86 |
+
# Cycle detected; indicate with a note.
|
| 87 |
+
return f"<li><div class='node'>{employees.get(node, node)} (cycle)</div></li>"
|
| 88 |
+
visited.add(node)
|
| 89 |
label = employees.get(node, node)
|
| 90 |
html = f"<li><div class='node'>{label}</div>"
|
| 91 |
if node in children and children[node]:
|
| 92 |
html += "<ul>"
|
| 93 |
for child in children[node]:
|
| 94 |
+
html += generate_node_html(child, employees, children, visited)
|
| 95 |
html += "</ul>"
|
| 96 |
html += "</li>"
|
| 97 |
+
visited.remove(node)
|
| 98 |
return html
|
| 99 |
|
| 100 |
def generate_org_chart_html(df, title):
|
|
|
|
| 116 |
margin: 20px;
|
| 117 |
}}
|
| 118 |
.org-chart ul {{
|
| 119 |
+
padding-top: 20px;
|
| 120 |
position: relative;
|
| 121 |
display: inline-block;
|
| 122 |
}}
|
|
|
|
| 171 |
return html_content
|
| 172 |
|
| 173 |
# -------------------------
|
| 174 |
+
# Main function: Generate Chart & PDF
|
| 175 |
# -------------------------
|
| 176 |
def generate_chart(file, title):
|
| 177 |
+
logging.info("Starting chart generation...")
|
| 178 |
if not file:
|
| 179 |
return None, "Please upload a CSV file."
|
| 180 |
file_path = process_uploaded_file(file)
|
|
|
|
| 185 |
return None, "Uploaded file is a directory. Please upload a valid CSV file."
|
| 186 |
try:
|
| 187 |
df = pd.read_csv(file_path)
|
| 188 |
+
logging.info(f"CSV read successfully with {df.shape[0]} rows.")
|
| 189 |
except Exception as e:
|
| 190 |
logging.error(f"Error reading CSV: {e}")
|
| 191 |
return None, f"Error reading CSV: {e}"
|
|
|
|
| 193 |
if not expected_columns.issubset(set(df.columns)):
|
| 194 |
return None, "CSV must contain Name, Role, and Reporting To columns."
|
| 195 |
|
| 196 |
+
# Generate HTML org chart.
|
| 197 |
html_content = generate_org_chart_html(df, title)
|
| 198 |
|
| 199 |
# Generate PDF using WeasyPrint.
|
| 200 |
pdf_path = "/tmp/chart.pdf"
|
| 201 |
try:
|
| 202 |
HTML(string=html_content).write_pdf(pdf_path)
|
| 203 |
+
logging.info("PDF generated successfully.")
|
| 204 |
except Exception as e:
|
| 205 |
logging.error(f"Error generating PDF: {e}")
|
| 206 |
dummy_pdf = "/tmp/no_pdf.pdf"
|
|
|
|
| 210 |
|
| 211 |
# Convert PDF to PNG for preview using pdf2image.
|
| 212 |
try:
|
| 213 |
+
from pdf2image import convert_from_path
|
| 214 |
images = convert_from_path(pdf_path, dpi=150)
|
| 215 |
if images and len(images) > 0:
|
| 216 |
image_path = "/tmp/chart.png"
|
| 217 |
images[0].save(image_path, 'PNG')
|
| 218 |
+
logging.info("PDF converted to PNG successfully.")
|
| 219 |
else:
|
| 220 |
image_path = ""
|
| 221 |
except Exception as e:
|
|
|
|
| 225 |
return image_path, pdf_path
|
| 226 |
|
| 227 |
# -------------------------
|
| 228 |
+
# Template download helper
|
| 229 |
# -------------------------
|
| 230 |
def download_template():
|
| 231 |
template_path = "/tmp/template.csv"
|
|
|
|
| 251 |
"Upload a CSV file (with columns: **Name, Role, Reporting To**) to generate an interactive organization chart. "
|
| 252 |
"Use the button below to download a CSV template."
|
| 253 |
)
|
|
|
|
| 254 |
with gr.Row():
|
| 255 |
template_button = gr.Button("Download CSV Template")
|
| 256 |
file_input = gr.File(label="Upload CSV File")
|
| 257 |
title_input = gr.Textbox(label="Enter PDF Title", placeholder="Company Org Chart")
|
| 258 |
submit_button = gr.Button("Generate Chart")
|
|
|
|
| 259 |
image_output = gr.Image(label="Generated Chart (PNG)")
|
| 260 |
pdf_output = gr.File(label="Download PDF")
|
| 261 |
template_output = gr.File(label="CSV Template")
|
|
|
|
| 262 |
template_button.click(download_template, outputs=template_output)
|
| 263 |
submit_button.click(generate_chart, inputs=[file_input, title_input], outputs=[image_output, pdf_output])
|
| 264 |
|