185 lines
6.2 KiB
Python
185 lines
6.2 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Generate bicorder.txt from bicorder.json
|
|
"""
|
|
|
|
import json
|
|
import argparse
|
|
import sys
|
|
|
|
|
|
def center_text(text, width):
|
|
"""Center text within a given width"""
|
|
return text.center(width)
|
|
|
|
|
|
def format_gradient_bar(value):
|
|
"""
|
|
Format the gradient bar based on value.
|
|
If value is None, show all bars: [|||||||||]
|
|
If value is 0-8, replace that position with #: [|#||||||||]
|
|
"""
|
|
if value is None:
|
|
return "[|||||||||]"
|
|
|
|
# Ensure value is in valid range
|
|
if not isinstance(value, int) or value < 0 or value > 8:
|
|
return "[|||||||||]"
|
|
|
|
bars = list("|||||||||")
|
|
bars[value] = "#"
|
|
return "[" + "".join(bars) + "]"
|
|
|
|
|
|
def format_gradient_line(term_left, term_right, value, left_width, right_width, center_width):
|
|
"""
|
|
Format a gradient line with proper spacing.
|
|
Example: " explicit < [|||||||||] > implicit "
|
|
"""
|
|
bar = format_gradient_bar(value)
|
|
# Right-align the left term, add the bar, then left-align the right term
|
|
line = f"{term_left.rjust(left_width)} < {bar} > {term_right.ljust(right_width)}"
|
|
return center_text(line, center_width)
|
|
|
|
|
|
def format_metadata_field(field_value, field_name):
|
|
"""
|
|
Format metadata field - show value if provided, otherwise show field name in brackets
|
|
"""
|
|
if field_value is None or field_value == "":
|
|
return f"[{field_name}]"
|
|
return str(field_value)
|
|
|
|
|
|
def generate_bicorder_text(json_data):
|
|
"""Generate the formatted bicorder text from JSON data"""
|
|
lines = []
|
|
|
|
# First pass: calculate maximum widths for left and right terms
|
|
max_left_width = 0
|
|
max_right_width = 0
|
|
|
|
# Check diagnostic gradients
|
|
for diagnostic_set in json_data.get("diagnostic", []):
|
|
for gradient in diagnostic_set.get("gradients", []):
|
|
term_left = gradient.get("term_left", "")
|
|
term_right = gradient.get("term_right", "")
|
|
max_left_width = max(max_left_width, len(term_left))
|
|
max_right_width = max(max_right_width, len(term_right))
|
|
|
|
# Check analysis items
|
|
for analysis_item in json_data.get("analysis", []):
|
|
term_left = analysis_item.get("term_left", "")
|
|
term_right = analysis_item.get("term_right", "")
|
|
max_left_width = max(max_left_width, len(term_left))
|
|
max_right_width = max(max_right_width, len(term_right))
|
|
|
|
# Calculate the width needed for centering
|
|
# Gradient line format: "{left_term} < [|||||||||] > {right_term}"
|
|
# That's: max_left_width + 3 + 11 + 3 + max_right_width
|
|
gradient_line_width = max_left_width + max_right_width + 17
|
|
|
|
# Also check metadata and headers
|
|
metadata = json_data.get("metadata", {})
|
|
max_text_width = max(
|
|
len("Protocol"),
|
|
len("BICORDER"),
|
|
len(format_metadata_field(metadata.get("protocol"), "Protocol")),
|
|
len(format_metadata_field(metadata.get("analyst"), "Analyst")),
|
|
len(format_metadata_field(metadata.get("standpoint"), "Standpoint")),
|
|
len(format_metadata_field(metadata.get("timestamp"), "Timestamp")),
|
|
len("ANALYSIS")
|
|
)
|
|
|
|
# Check diagnostic set names
|
|
for diagnostic_set in json_data.get("diagnostic", []):
|
|
set_name = diagnostic_set.get("set_name", "").upper()
|
|
max_text_width = max(max_text_width, len(set_name))
|
|
|
|
# Use the maximum of gradient line width and text width
|
|
center_width = max(gradient_line_width, max_text_width)
|
|
|
|
# Header
|
|
lines.append(center_text("Protocol", center_width))
|
|
lines.append(center_text("BICORDER", center_width))
|
|
lines.append("")
|
|
|
|
# Metadata section
|
|
lines.append(center_text(format_metadata_field(metadata.get("protocol"), "Protocol"), center_width))
|
|
lines.append(center_text(format_metadata_field(metadata.get("analyst"), "Analyst"), center_width))
|
|
lines.append(center_text(format_metadata_field(metadata.get("standpoint"), "Standpoint"), center_width))
|
|
lines.append(center_text(format_metadata_field(metadata.get("timestamp"), "Timestamp"), center_width))
|
|
lines.append("")
|
|
|
|
# Diagnostic sections
|
|
for diagnostic_set in json_data.get("diagnostic", []):
|
|
set_name = diagnostic_set.get("set_name", "").upper()
|
|
lines.append(center_text(set_name, center_width))
|
|
|
|
for gradient in diagnostic_set.get("gradients", []):
|
|
term_left = gradient.get("term_left", "")
|
|
term_right = gradient.get("term_right", "")
|
|
value = gradient.get("value")
|
|
|
|
lines.append(format_gradient_line(term_left, term_right, value, max_left_width, max_right_width, center_width))
|
|
|
|
lines.append("")
|
|
|
|
# Analysis section
|
|
lines.append(center_text("ANALYSIS", center_width))
|
|
for analysis_item in json_data.get("analysis", []):
|
|
term_left = analysis_item.get("term_left", "")
|
|
term_right = analysis_item.get("term_right", "")
|
|
value = analysis_item.get("value")
|
|
|
|
lines.append(format_gradient_line(term_left, term_right, value, max_left_width, max_right_width, center_width))
|
|
|
|
lines.append("")
|
|
|
|
return "\n".join(lines)
|
|
|
|
|
|
def main():
|
|
"""Main function to read JSON and generate text output"""
|
|
# Set up argument parser
|
|
parser = argparse.ArgumentParser(
|
|
description="Generate formatted bicorder text from JSON input"
|
|
)
|
|
parser.add_argument(
|
|
"input_json",
|
|
help="Path to input JSON file"
|
|
)
|
|
parser.add_argument(
|
|
"output_txt",
|
|
help="Path to output TXT file"
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
# Read the JSON file
|
|
try:
|
|
with open(args.input_json, "r") as f:
|
|
data = json.load(f)
|
|
except FileNotFoundError:
|
|
print(f"Error: Input file '{args.input_json}' not found.", file=sys.stderr)
|
|
sys.exit(1)
|
|
except json.JSONDecodeError as e:
|
|
print(f"Error: Invalid JSON in '{args.input_json}': {e}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
# Generate the formatted text
|
|
output = generate_bicorder_text(data)
|
|
|
|
# Write to output file
|
|
try:
|
|
with open(args.output_txt, "w") as f:
|
|
f.write(output)
|
|
print(f"Successfully generated '{args.output_txt}'")
|
|
except IOError as e:
|
|
print(f"Error: Could not write to '{args.output_txt}': {e}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|