Spaces:
Running
Running
Update src/aibom_generator/utils.py
Browse files- src/aibom_generator/utils.py +63 -35
src/aibom_generator/utils.py
CHANGED
@@ -102,19 +102,24 @@ def normalize_license_id(license_text):
|
|
102 |
return license_text
|
103 |
|
104 |
|
105 |
-
def calculate_completeness_score(aibom: Dict[str, Any]) ->
|
106 |
"""
|
107 |
Calculate a completeness score for the AIBOM.
|
108 |
-
|
109 |
Args:
|
110 |
aibom: The AIBOM dictionary
|
111 |
-
|
112 |
Returns:
|
113 |
-
|
|
|
|
|
|
|
114 |
"""
|
115 |
score = 0
|
116 |
max_score = 100
|
117 |
-
|
|
|
|
|
118 |
# Define scoring weights for different sections
|
119 |
weights = {
|
120 |
"required_fields": 20,
|
@@ -123,39 +128,62 @@ def calculate_completeness_score(aibom: Dict[str, Any]) -> int:
|
|
123 |
"component_model_card": 30,
|
124 |
"external_references": 10,
|
125 |
}
|
126 |
-
|
127 |
-
#
|
128 |
required_fields = ["bomFormat", "specVersion", "serialNumber", "version"]
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
|
|
|
|
|
|
|
|
133 |
if "metadata" in aibom:
|
134 |
-
metadata = aibom["metadata"]
|
135 |
metadata_fields = ["timestamp", "tools", "authors", "component"]
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
159 |
|
160 |
def merge_metadata(primary: Dict[str, Any], secondary: Dict[str, Any]) -> Dict[str, Any]:
|
161 |
"""
|
|
|
102 |
return license_text
|
103 |
|
104 |
|
105 |
+
def calculate_completeness_score(aibom: Dict[str, Any]) -> Dict[str, Any]:
|
106 |
"""
|
107 |
Calculate a completeness score for the AIBOM.
|
108 |
+
|
109 |
Args:
|
110 |
aibom: The AIBOM dictionary
|
111 |
+
|
112 |
Returns:
|
113 |
+
Dictionary containing:
|
114 |
+
- total_score: overall completeness score (0-100)
|
115 |
+
- section_scores: points earned per section
|
116 |
+
- field_checklist: dictionary showing presence (β) or absence (β) of key fields
|
117 |
"""
|
118 |
score = 0
|
119 |
max_score = 100
|
120 |
+
section_scores = {}
|
121 |
+
field_checklist = {}
|
122 |
+
|
123 |
# Define scoring weights for different sections
|
124 |
weights = {
|
125 |
"required_fields": 20,
|
|
|
128 |
"component_model_card": 30,
|
129 |
"external_references": 10,
|
130 |
}
|
131 |
+
|
132 |
+
# Required Fields
|
133 |
required_fields = ["bomFormat", "specVersion", "serialNumber", "version"]
|
134 |
+
required_present = [field for field in required_fields if field in aibom]
|
135 |
+
required_score = (len(required_present) / len(required_fields)) * weights["required_fields"]
|
136 |
+
section_scores["required_fields"] = round(required_score)
|
137 |
+
for field in required_fields:
|
138 |
+
field_checklist[field] = "β" if field in required_present else "β"
|
139 |
+
|
140 |
+
# Metadata Fields
|
141 |
+
metadata_score = 0
|
142 |
if "metadata" in aibom:
|
|
|
143 |
metadata_fields = ["timestamp", "tools", "authors", "component"]
|
144 |
+
present = [field for field in metadata_fields if field in aibom["metadata"]]
|
145 |
+
metadata_score = (len(present) / len(metadata_fields)) * weights["metadata"]
|
146 |
+
for field in metadata_fields:
|
147 |
+
field_checklist[f"metadata.{field}"] = "β" if field in present else "β"
|
148 |
+
section_scores["metadata"] = round(metadata_score)
|
149 |
+
|
150 |
+
# Component Basic Info
|
151 |
+
component_score = 0
|
152 |
+
component = aibom.get("components", [{}])[0]
|
153 |
+
component_fields = ["type", "name", "bom-ref", "purl", "description", "licenses"]
|
154 |
+
present = [field for field in component_fields if field in component]
|
155 |
+
component_score = (len(present) / len(component_fields)) * weights["component_basic"]
|
156 |
+
section_scores["component_basic"] = round(component_score)
|
157 |
+
for field in component_fields:
|
158 |
+
field_checklist[f"component.{field}"] = "β" if field in present else "β"
|
159 |
+
|
160 |
+
# Model Card Section
|
161 |
+
model_card_score = 0
|
162 |
+
model_card_fields = ["modelParameters", "quantitativeAnalysis", "considerations"]
|
163 |
+
if "modelCard" in component:
|
164 |
+
model_card = component["modelCard"]
|
165 |
+
present = [field for field in model_card_fields if field in model_card]
|
166 |
+
model_card_score = (len(present) / len(model_card_fields)) * weights["component_model_card"]
|
167 |
+
for field in model_card_fields:
|
168 |
+
field_checklist[f"modelCard.{field}"] = "β" if field in present else "β"
|
169 |
+
else:
|
170 |
+
for field in model_card_fields:
|
171 |
+
field_checklist[f"modelCard.{field}"] = "β"
|
172 |
+
section_scores["component_model_card"] = round(model_card_score)
|
173 |
+
|
174 |
+
# External References
|
175 |
+
ext_score = weights["external_references"] if aibom.get("externalReferences") else 0
|
176 |
+
section_scores["external_references"] = round(ext_score)
|
177 |
+
field_checklist["externalReferences"] = "β" if ext_score else "β"
|
178 |
+
|
179 |
+
# Final total score
|
180 |
+
total_score = round(sum(section_scores.values()))
|
181 |
+
|
182 |
+
return {
|
183 |
+
"total_score": total_score,
|
184 |
+
"section_scores": section_scores,
|
185 |
+
"field_checklist": field_checklist
|
186 |
+
}
|
187 |
|
188 |
def merge_metadata(primary: Dict[str, Any], secondary: Dict[str, Any]) -> Dict[str, Any]:
|
189 |
"""
|