daetheris's picture
Initial commit after cleanup
80e0598 verified
raw
history blame
5.69 kB
"""
CLI interface for the AIBOM Generator.
"""
import argparse
import json
import os
import sys
from typing import Optional
from aibom_generator.generator import AIBOMGenerator
def parse_args():
"""Parse command line arguments."""
parser = argparse.ArgumentParser(
description="Generate AI Bills of Materials (AIBOMs) in CycloneDX format for Hugging Face models."
)
parser.add_argument(
"model_id",
help="Hugging Face model ID (e.g., 'google/bert-base-uncased')"
)
parser.add_argument(
"-o", "--output",
help="Output file path (default: <model_id>.aibom.json)",
default=None
)
parser.add_argument(
"--token",
help="Hugging Face API token for accessing private models",
default=os.environ.get("HF_TOKEN")
)
parser.add_argument(
"--inference-url",
help="URL of the inference model service for metadata extraction",
default=os.environ.get("AIBOM_INFERENCE_URL")
)
parser.add_argument(
"--no-inference",
help="Disable inference model for metadata extraction",
action="store_true"
)
parser.add_argument(
"--cache-dir",
help="Directory to cache API responses and model cards",
default=os.environ.get("AIBOM_CACHE_DIR", ".aibom_cache")
)
parser.add_argument(
"--completeness-threshold",
help="Minimum completeness score (0-100) required for the AIBOM",
type=int,
default=0
)
parser.add_argument(
"--format",
help="Output format (json or yaml)",
choices=["json", "yaml"],
default="json"
)
parser.add_argument(
"--pretty",
help="Pretty-print the output",
action="store_true"
)
return parser.parse_args()
def main():
"""Main entry point for the CLI."""
args = parse_args()
# Determine output file if not specified
if not args.output:
model_name = args.model_id.replace("/", "_")
args.output = f"{model_name}.aibom.json"
# Create the generator
generator = AIBOMGenerator(
hf_token=args.token,
inference_model_url=args.inference_url,
use_inference=not args.no_inference,
cache_dir=args.cache_dir
)
try:
# Generate the AIBOM
aibom = generator.generate_aibom(
model_id=args.model_id,
output_file=None # We'll handle saving ourselves
)
# Calculate completeness score (placeholder for now)
completeness_score = calculate_completeness_score(aibom)
# Check if it meets the threshold
if completeness_score < args.completeness_threshold:
print(f"Warning: AIBOM completeness score ({completeness_score}) is below threshold ({args.completeness_threshold})")
# Save the output
save_output(aibom, args.output, args.format, args.pretty)
print(f"AIBOM generated successfully: {args.output}")
print(f"Completeness score: {completeness_score}/100")
return 0
except Exception as e:
print(f"Error generating AIBOM: {e}", file=sys.stderr)
return 1
def calculate_completeness_score(aibom):
"""
Calculate a completeness score for the AIBOM.
This is a placeholder implementation that will be replaced with a more
sophisticated scoring algorithm based on the field mapping framework.
"""
# TODO: Implement proper completeness scoring
score = 0
# Check required fields
if all(field in aibom for field in ["bomFormat", "specVersion", "serialNumber", "version"]):
score += 20
# Check metadata
if "metadata" in aibom:
metadata = aibom["metadata"]
if "timestamp" in metadata:
score += 5
if "tools" in metadata and metadata["tools"]:
score += 5
if "authors" in metadata and metadata["authors"]:
score += 5
if "component" in metadata:
score += 5
# Check components
if "components" in aibom and aibom["components"]:
component = aibom["components"][0]
if "type" in component and component["type"] == "machine-learning-model":
score += 10
if "name" in component:
score += 5
if "bom-ref" in component:
score += 5
if "licenses" in component:
score += 5
if "externalReferences" in component:
score += 5
if "modelCard" in component:
model_card = component["modelCard"]
if "modelParameters" in model_card:
score += 10
if "quantitativeAnalysis" in model_card:
score += 10
if "considerations" in model_card:
score += 10
return score
def save_output(aibom, output_file, format_type, pretty):
"""Save the AIBOM to the specified output file."""
if format_type == "json":
with open(output_file, "w") as f:
if pretty:
json.dump(aibom, f, indent=2)
else:
json.dump(aibom, f)
else: # yaml
try:
import yaml
with open(output_file, "w") as f:
yaml.dump(aibom, f, default_flow_style=False)
except ImportError:
print("Warning: PyYAML not installed. Falling back to JSON format.")
with open(output_file, "w") as f:
json.dump(aibom, f, indent=2 if pretty else None)
if __name__ == "__main__":
sys.exit(main())