a1c00l commited on
Commit
371e54c
·
verified ·
1 Parent(s): ab0a6f3

Update templates/result.html

Browse files
Files changed (1) hide show
  1. templates/result.html +623 -446
templates/result.html CHANGED
@@ -2,33 +2,129 @@
2
  <html lang="en">
3
  <head>
4
  <meta charset="UTF-8">
 
5
  <title>AI SBOM Generated</title>
6
  <style>
7
- body { font-family: Arial, sans-serif; margin: 0; padding: 0; }
8
- .container { margin: 0 20px; }
 
 
 
 
 
 
 
 
 
 
 
9
 
10
  /* Header styling */
11
  .header {
12
- background-color: #f8f9fa;
13
  padding: 15px 20px;
14
  border-bottom: 1px solid #e9ecef;
 
15
  display: flex;
16
  align-items: center;
17
- margin-bottom: 20px;
18
  }
19
  .header img {
20
- height: 40px;
21
  margin-right: 15px;
22
  }
23
  .header h1 {
24
  margin: 0;
25
- font-size: 24px;
26
- color: #333;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  }
28
 
29
- table { border-collapse: collapse; width: 60%; margin-top: 15px; }
30
- th, td { border: 1px solid #ddd; padding: 8px; }
31
- th { background-color: #f4f4f4; }
 
 
 
 
 
 
 
 
 
 
 
 
 
32
 
33
  /* Fixed color styling for field checklist items */
34
  .check-mark { color: #27ae60; } /* Green color for check marks */
@@ -36,34 +132,50 @@
36
  .field-name { color: #000; } /* Black color for field names */
37
  .field-stars { color: #000; } /* Black color for importance stars */
38
 
39
- .improvement { color: #2c3e50; background-color: #ecf0f1; padding: 15px; border-radius: 5px; margin-bottom: 20px; }
 
 
 
 
 
 
 
40
  .improvement-value { color: #27ae60; font-weight: bold; }
41
- .ai-badge { background-color: #3498db; color: white; padding: 3px 8px; border-radius: 3px; font-size: 0.8em; margin-left: 10px; }
 
 
 
 
 
 
 
42
 
43
  /* New styles for human-friendly viewer */
44
  .aibom-viewer {
45
  margin: 20px 0;
46
- border: 1px solid #ddd;
47
- border-radius: 5px;
48
  padding: 20px;
49
  background-color: #f9f9f9;
50
  }
51
  .aibom-section {
52
  margin-bottom: 20px;
53
- padding: 15px;
54
- border-radius: 5px;
55
  background-color: white;
56
- box-shadow: 0 1px 3px rgba(0,0,0,0.1);
57
  }
58
  .aibom-section h4 {
59
  margin-top: 0;
60
  color: #2c3e50;
61
- border-bottom: 1px solid #eee;
62
- padding-bottom: 8px;
 
 
63
  }
64
  .aibom-property {
65
  display: flex;
66
- margin: 5px 0;
67
  }
68
  .property-name {
69
  font-weight: bold;
@@ -72,23 +184,30 @@
72
  }
73
  .property-value {
74
  flex: 1;
 
 
75
  }
76
  .aibom-tabs {
77
  display: flex;
78
- border-bottom: 1px solid #ddd;
79
  margin-bottom: 20px;
80
  }
81
  .aibom-tab {
82
- padding: 10px 20px;
83
  cursor: pointer;
84
- background-color: #f4f4f4;
85
  margin-right: 5px;
86
- border-radius: 5px 5px 0 0;
 
 
87
  }
88
  .aibom-tab.active {
89
  background-color: #3498db;
90
  color: white;
91
  }
 
 
 
92
  .tab-content {
93
  display: none;
94
  }
@@ -96,21 +215,25 @@
96
  display: block;
97
  }
98
  .json-view {
99
- background-color: #f8f8f8;
100
- border: 1px solid #ddd;
101
- border-radius: 5px;
102
- padding: 15px;
103
  overflow: auto;
104
  max-height: 500px;
 
 
105
  }
106
  .collapsible {
107
  cursor: pointer;
108
  position: relative;
 
109
  }
110
  .collapsible:after {
111
  content: '+';
112
  position: absolute;
113
  right: 10px;
 
114
  }
115
  .collapsible.active:after {
116
  content: '-';
@@ -118,43 +241,47 @@
118
  .collapsible-content {
119
  max-height: 0;
120
  overflow: hidden;
121
- transition: max-height 0.2s ease-out;
122
  }
123
  .collapsible-content.active {
124
  max-height: 500px;
125
  }
126
  .tag {
127
  display: inline-block;
128
- background-color: #e0e0e0;
129
- padding: 2px 8px;
130
- border-radius: 12px;
131
- margin: 2px;
132
  font-size: 0.9em;
133
  }
134
  .key-info {
135
  background-color: #e3f2fd;
136
  border-left: 4px solid #2196F3;
137
- padding: 10px;
138
- margin-bottom: 15px;
 
139
  }
140
 
141
  /* Progress bar styles */
142
  .progress-container {
143
  width: 100%;
144
  background-color: #f1f1f1;
145
- border-radius: 4px;
146
- margin: 5px 0;
 
147
  }
148
  .progress-bar {
149
- height: 20px;
150
- border-radius: 4px;
151
  text-align: center;
152
- line-height: 20px;
153
  color: white;
154
- font-size: 12px;
 
155
  display: flex;
156
  align-items: center;
157
  justify-content: center;
 
158
  }
159
  .progress-excellent {
160
  background-color: #4CAF50; /* Green */
@@ -174,35 +301,40 @@
174
  }
175
  .score-table th {
176
  text-align: left;
177
- padding: 8px;
178
- background-color: #f4f4f4;
179
  }
180
  .score-table td {
181
- padding: 8px;
182
  }
183
  .score-weight {
184
- font-size: 0.8em;
185
  color: #666;
186
  margin-left: 5px;
187
  }
188
  .score-label {
189
  display: inline-block;
190
- padding: 2px 6px;
191
- border-radius: 3px;
192
  color: white;
193
- font-size: 0.8em;
194
  margin-left: 5px;
195
  background-color: transparent; /* Make background transparent */
196
  }
197
  .total-score-container {
198
  display: flex;
199
  align-items: center;
200
- margin-bottom: 20px;
 
 
 
 
201
  }
202
  .total-score {
203
- font-size: 24px;
204
  font-weight: bold;
205
- margin-right: 15px;
 
206
  }
207
  .total-progress {
208
  flex: 1;
@@ -217,11 +349,11 @@
217
  .tooltip .tooltiptext {
218
  visibility: hidden;
219
  width: 300px;
220
- background-color: #555;
221
  color: #fff;
222
  text-align: left;
223
  border-radius: 6px;
224
- padding: 10px;
225
  position: absolute;
226
  z-index: 1;
227
  bottom: 125%;
@@ -230,7 +362,8 @@
230
  opacity: 0;
231
  transition: opacity 0.3s;
232
  font-size: 0.9em;
233
- line-height: 1.4;
 
234
  }
235
  .tooltip:hover .tooltiptext {
236
  visibility: visible;
@@ -244,32 +377,35 @@
244
  margin-left: -5px;
245
  border-width: 5px;
246
  border-style: solid;
247
- border-color: #555 transparent transparent transparent;
248
  }
249
  .missing-fields {
250
  background-color: #ffebee;
251
  border-left: 4px solid #f44336;
252
- padding: 10px;
253
- margin: 10px 0;
254
- border-radius: 4px;
255
  }
256
  .missing-fields h4 {
257
  margin-top: 0;
258
  color: #d32f2f;
 
259
  }
260
  .missing-fields ul {
261
  margin-bottom: 0;
 
262
  }
263
  .recommendations {
264
  background-color: #e8f5e9;
265
  border-left: 4px solid #4caf50;
266
- padding: 10px;
267
- margin: 10px 0;
268
- border-radius: 4px;
269
  }
270
  .recommendations h4 {
271
  margin-top: 0;
272
  color: #2e7d32;
 
273
  }
274
  .importance-indicator {
275
  display: inline-block;
@@ -287,44 +423,52 @@
287
  .scoring-rubric {
288
  background-color: #e3f2fd;
289
  border-left: 4px solid #2196f3;
290
- padding: 10px;
291
- margin: 10px 0;
292
- border-radius: 4px;
293
  }
294
  .scoring-rubric h4 {
295
  margin-top: 0;
296
  color: #1565c0;
 
297
  }
298
  .scoring-rubric table {
299
  width: 100%;
300
- margin-top: 10px;
301
  }
302
  .scoring-rubric th, .scoring-rubric td {
303
- padding: 6px;
304
  text-align: left;
305
  }
306
  .note-box {
307
  background-color: #fffbea; /* Lighter yellow background */
308
  border-left: 4px solid #ffc107;
309
- padding: 10px;
310
- margin: 15px 0;
 
311
  }
312
  .download-section {
313
- margin: 15px 0;
 
 
 
 
 
 
314
  }
315
 
316
  /* New styles for completeness profile */
317
  .completeness-profile {
318
  background-color: #e8f5e9;
319
- border-radius: 5px;
320
- padding: 15px;
321
- margin: 15px 0;
322
  border-left: 4px solid #4caf50;
323
  }
324
  .profile-badge {
325
  display: inline-block;
326
- padding: 3px 10px;
327
- border-radius: 15px;
328
  color: white;
329
  font-weight: bold;
330
  margin-right: 10px;
@@ -361,7 +505,7 @@
361
  }
362
  .tier-legend {
363
  display: flex;
364
- margin: 10px 0;
365
  font-size: 0.9em;
366
  }
367
  .tier-legend-item {
@@ -373,63 +517,102 @@
373
  .validation-penalty-info {
374
  background-color: #fff3e0;
375
  border-left: 4px solid #ff9800;
376
- padding: 10px;
377
- margin: 10px 0;
378
- border-radius: 4px;
379
- font-size: 0.9em;
380
  }
381
  .validation-penalty-info h4 {
382
  margin-top: 0;
383
  color: #e65100;
 
384
  }
385
 
386
  /* New section for score calculation explanation */
387
  .score-calculation {
388
  margin-top: 30px;
389
- padding: 15px;
390
- background-color: #f5f5f5;
391
- border-radius: 5px;
 
392
  }
393
  .score-calculation h3 {
394
  margin-top: 0;
395
- color: #333;
396
- border-bottom: 1px solid #ddd;
397
  padding-bottom: 10px;
398
- margin-bottom: 15px;
399
  }
400
  .calculation-section {
401
- margin-bottom: 20px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
402
  }
403
  </style>
404
  </head>
405
  <body>
406
  <!-- Header with logo and title -->
407
  <div class="header">
408
- <div class="header" style="display: flex; align-items: center; gap: 10px;">
409
- <a href="https://aetheris.ai/" target="_blank">
410
- <img src="https://huggingface.co/spaces/aetheris-ai/aibom-generator/resolve/main/templates/images/AetherisAI-logo.png" alt="Aetheris AI Logo" style="height: 60px;">
411
- </a>
412
- <h1 style="margin: 0;">AI SBOM Generator</h1>
413
- </div>
414
  </div>
415
 
416
  <div class="container">
417
- <a href="/">Generate another AI SBOM</a>
418
- <h2>AI SBOM Generated for {{ model_id }}</h2>
419
-
420
- <div class="download-section">
421
- <p>Download generated AI SBOM in CycloneDX format <button onclick="downloadJSON()">Download JSON</button></p>
422
- </div>
 
 
 
423
 
424
- {% if enhancement_report and enhancement_report.ai_enhanced %}
425
- <div class="improvement">
426
- <h3>AI Enhancement Results</h3>
427
- <p>This AI SBOM was enhanced using <strong>{{ enhancement_report.ai_model }}</strong></p>
428
- <p>Original Score: {{ enhancement_report.original_score.total_score|round(1) }}/100</p>
429
- <p>Enhanced Score: {{ enhancement_report.final_score.total_score|round(1) }}/100</p>
430
- <p>Improvement: <span class="improvement-value">+{{ enhancement_report.improvement|round(1) }} points</span></p>
 
 
431
  </div>
432
- {% endif %}
433
 
434
  <!-- Human-friendly AI SBOM Viewer -->
435
  <div class="note-box">
@@ -482,19 +665,11 @@
482
  <div class="aibom-property">
483
  <div class="property-name">Model Parameters:</div>
484
  <div class="property-value">
485
- {% if aibom.components[0].modelCard.modelParameters.properties %}
486
- <ul>
487
- {% for prop in aibom.components[0].modelCard.modelParameters.properties %}
488
- <li><strong>{{ prop.name }}:</strong> {{ prop.value }}</li>
489
- {% endfor %}
490
- </ul>
491
- {% else %}
492
  <ul>
493
  {% for key, value in aibom.components[0].modelCard.modelParameters.items() %}
494
  <li><strong>{{ key }}:</strong> {{ value }}</li>
495
  {% endfor %}
496
  </ul>
497
- {% endif %}
498
  </div>
499
  </div>
500
  {% endif %}
@@ -544,362 +719,364 @@
544
  </div>
545
 
546
  <div id="field-checklist" class="tab-content">
547
- <h3>Field Checklist</h3>
548
-
549
- <!-- Field Tier Legend -->
550
- <div class="tier-legend">
551
- <div class="tier-legend-item">
552
- <span class="field-tier tier-critical"></span>
553
- <span>Critical</span>
554
- </div>
555
- <div class="tier-legend-item">
556
- <span class="field-tier tier-important"></span>
557
- <span>Important</span>
558
- </div>
559
- <div class="tier-legend-item">
560
- <span class="field-tier tier-supplementary"></span>
561
- <span>Supplementary</span>
 
 
562
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
563
  </div>
564
-
565
- <ul>
566
- {% for field, status in completeness_score.field_checklist.items() %}
567
- {% if "✔" in status %}
568
- <li>
569
- <span class="check-mark">✔</span>
570
- <span class="field-name">{{ field }}</span>
571
- <span class="field-stars">{{ status.split('✔')[1] }}</span>
572
- {% if completeness_score.field_tiers and field in completeness_score.field_tiers %}
573
- <span class="field-tier tier-{{ completeness_score.field_tiers[field] }}"></span>
574
- {% endif %}
575
- </li>
576
- {% else %}
577
- <li>
578
- <span class="x-mark">✘</span>
579
- <span class="field-name">{{ field }}</span>
580
- <span class="field-stars">{{ status.split('✘')[1] }}</span>
581
- {% if completeness_score.field_tiers and field in completeness_score.field_tiers %}
582
- <span class="field-tier tier-{{ completeness_score.field_tiers[field] }}"></span>
583
- {% endif %}
584
-
585
- {% if field == "component.description" %}
586
- <span class="tooltip">(?)
587
- <span class="tooltiptext">A detailed description of the model is essential for users to understand its purpose and capabilities. Add a description that is at least 20 characters long.</span>
588
- </span>
589
- {% elif field == "component.purl" %}
590
- <span class="tooltip">(?)
591
- <span class="tooltiptext">Package URL (PURL) is critical for uniquely identifying the model. It should follow the format pkg:huggingface/[owner]/[name]@[version].</span>
592
- </span>
593
- {% elif field == "modelCard.modelParameters" %}
594
- <span class="tooltip">(?)
595
- <span class="tooltiptext">Model parameters provide essential technical details about the model architecture, training, and capabilities.</span>
596
- </span>
597
- {% elif field == "modelCard.considerations" %}
598
- <span class="tooltip">(?)
599
- <span class="tooltiptext">Considerations section should include ethical considerations, limitations, and risks associated with the model.</span>
600
- </span>
601
- {% elif field == "externalReferences" %}
602
- <span class="tooltip">(?)
603
- <span class="tooltiptext">External references provide links to additional resources like model cards, repositories, and datasets.</span>
604
- </span>
605
- {% else %}
606
- <span class="tooltip">(?)
607
- <span class="tooltiptext">This field contributes to the completeness of your AI SBOM.</span>
608
- </span>
609
- {% endif %}
610
- </li>
611
- {% endif %}
612
- {% endfor %}
613
- </ul>
614
  </div>
615
 
616
  <div id="score-view" class="tab-content">
617
- <h3>AI SBOM Completeness Score</h3>
618
-
619
- <!-- Completeness Profile Section -->
620
- {% if completeness_score.completeness_profile %}
621
- <div class="completeness-profile">
622
- <h4>Completeness Profile:
623
- <span class="profile-badge profile-{{ completeness_score.completeness_profile.name|lower }}">
624
- {{ completeness_score.completeness_profile.name }}
625
- </span>
626
- </h4>
627
- <p>{{ completeness_score.completeness_profile.description }}</p>
628
 
629
- {% if completeness_score.completeness_profile.next_level %}
630
- <p><strong>Next level:</strong> {{ completeness_score.completeness_profile.next_level.name }}
631
- ({{ completeness_score.completeness_profile.next_level.missing_fields_count }} fields to add)</p>
 
 
 
 
 
 
 
 
 
 
 
 
632
  {% endif %}
633
- </div>
634
- {% endif %}
635
-
636
- <!-- Total Score with Progress Bar -->
637
- <div class="total-score-container">
638
- <div class="total-score">{{ completeness_score.total_score|round(1) }}/100</div>
639
- <div class="total-progress">
640
- <div class="progress-container">
641
- {% set score_percent = (completeness_score.total_score / 100) * 100 %}
642
- {% set score_class = 'progress-poor' %}
643
- {% set score_label = 'Poor' %}
644
-
645
- {% if score_percent >= 90 %}
646
- {% set score_class = 'progress-excellent' %}
647
- {% set score_label = 'Excellent' %}
648
- {% elif score_percent >= 70 %}
649
- {% set score_class = 'progress-good' %}
650
- {% set score_label = 'Good' %}
651
- {% elif score_percent >= 50 %}
652
- {% set score_class = 'progress-fair' %}
653
- {% set score_label = 'Fair' %}
654
- {% endif %}
655
-
656
- <div class="progress-bar {{ score_class }}" style="width: {{ score_percent }}%">
657
- {{ score_percent|int }}% {{ score_label }}
658
  </div>
659
  </div>
660
  </div>
661
- </div>
662
-
663
- <!-- Validation Penalty Explanation -->
664
- {% if completeness_score.validation_penalty %}
665
- <div class="validation-penalty-info">
666
- <h4>About the Validation Penalty</h4>
667
- <p>Your score includes a penalty because the AIBOM has schema validation issues. These are structural problems that don't comply with the CycloneDX specification requirements.</p>
668
- <p><strong>How to fix this:</strong> Look at the "Fix Validation Issues" section in the recommendations below. Fixing these issues will remove the penalty and improve your overall score.</p>
669
- </div>
670
- {% endif %}
671
-
672
- <!-- Section Scores with Progress Bars and Tooltips -->
673
- <table class="score-table">
674
- <thead>
675
- <tr>
676
- <th>Section</th>
677
- <th>Score</th>
678
- <th>Weight</th>
679
- <th>Progress</th>
680
- </tr>
681
- </thead>
682
- <tbody>
683
- {% set weights = {'required_fields': 20, 'metadata': 20, 'component_basic': 20, 'component_model_card': 30, 'external_references': 10} %}
684
- {% set tooltips = {
685
- 'required_fields': 'Basic SBOM fields required by the CycloneDX specification: bomFormat, specVersion, serialNumber, and version.',
686
- 'metadata': 'Information about the AI SBOM itself: timestamp, tools used to generate it, authors, and component metadata.',
687
- 'component_basic': 'Basic information about the AI model: type, name, bom-ref, PURL, description, and licenses.',
688
- 'component_model_card': 'Detailed information about the model: parameters, quantitative analysis, and ethical considerations.',
689
- 'external_references': 'Links to external resources like model cards, repositories, and datasets.'
690
- } %}
691
- {% set display_names = {
692
- 'required_fields': 'Required Fields',
693
- 'metadata': 'Metadata',
694
- 'component_basic': 'Component Basic',
695
- 'component_model_card': 'Model Card',
696
- 'external_references': 'External References'
697
- } %}
698
- {% for section, score in completeness_score.section_scores.items() %}
699
  <tr>
700
- <td>
701
- {{ display_names[section] }}
702
- <span class="tooltip">(?)
703
- <span class="tooltiptext">{{ tooltips[section] }}</span>
704
- </span>
705
- </td>
706
- <td>{{ score|round(1) }}/{{ completeness_score.max_scores[section] }}</td>
707
- <td>{{ weights[section] }}%</td>
708
- <td style="width: 50%;">
709
- <div class="progress-container">
710
- {% set percent = (score / completeness_score.max_scores[section]) * 100 %}
711
- {% set class = 'progress-poor' %}
712
-
713
- {% if percent >= 90 %}
714
- {% set class = 'progress-excellent' %}
715
- {% elif percent >= 70 %}
716
- {% set class = 'progress-good' %}
717
- {% elif percent >= 50 %}
718
- {% set class = 'progress-fair' %}
719
- {% endif %}
720
-
721
- <div class="progress-bar {{ class }}" style="width: {{ percent }}%">
722
- {{ percent|int }}%
723
- </div>
724
- </div>
725
- </td>
726
  </tr>
727
- {% endfor %}
728
- </tbody>
729
- </table>
730
-
731
- <!-- How the Overall Score is Calculated Section -->
732
- <div class="score-calculation">
733
- <h3>How the Overall Score is Calculated</h3>
734
-
735
- <!-- Missing Fields Section -->
736
- <div class="calculation-section missing-fields">
737
- <h4>Critical Missing Fields</h4>
738
- <p>The following fields are missing or incomplete and have the biggest impact on your score:</p>
739
- <ul>
740
- {% set missing_critical = [] %}
741
- {% for field, status in completeness_score.field_checklist.items() %}
742
- {% if "✘" in status %}
743
- {% if completeness_score.field_tiers and field in completeness_score.field_tiers and completeness_score.field_tiers[field] == 'critical' %}
744
- {% set _ = missing_critical.append(field) %}
745
- <li>
746
- <strong>{{ field }}</strong>
747
- <span class="field-tier tier-critical"></span>
748
- {% if field == "component.description" %}
749
- - Add a detailed description of the model (at least 20 characters)
750
- {% elif field == "component.purl" %}
751
- - Add a valid PURL in the format pkg:huggingface/[owner]/[name]@[version]
752
- {% elif field == "modelCard.modelParameters" %}
753
- - Add model parameters section with architecture, size, and training details
754
- {% elif field == "primaryPurpose" %}
755
- - Add primary purpose information (what the model is designed for)
756
- {% else %}
757
- - This field is required for comprehensive documentation
 
 
 
 
 
 
 
758
  {% endif %}
759
- </li>
760
- {% endif %}
761
- {% endif %}
 
 
 
 
762
  {% endfor %}
763
- {% if missing_critical|length == 0 %}
764
- <li>No critical fields are missing. Great job!</li>
765
- {% endif %}
766
- </ul>
767
- </div>
768
 
769
- <!-- Recommendations Section -->
770
- <div class="calculation-section recommendations">
771
- <h4>Recommendations to Improve Your Score</h4>
772
- <ol>
773
- {% if completeness_score.section_scores.component_model_card < completeness_score.max_scores.component_model_card %}
774
- <li>
775
- <strong>Enhance Model Card</strong> (+{{ ((completeness_score.max_scores.component_model_card - completeness_score.section_scores.component_model_card) * 0.3)|round(1) }} points):
776
- <ul>
777
- {% if completeness_score.missing_fields.critical %}
778
- {% for field in completeness_score.missing_fields.critical %}
779
- {% if field.startswith('modelCard') %}
780
- <li>Add {{ field }} section</li>
781
- {% endif %}
782
- {% endfor %}
783
- {% endif %}
784
- {% if completeness_score.missing_fields.important %}
785
- {% for field in completeness_score.missing_fields.important %}
786
- {% if field.startswith('modelCard') %}
787
- <li>Add {{ field }} section</li>
788
- {% endif %}
789
- {% endfor %}
790
- {% endif %}
791
- </ul>
792
- </li>
793
- {% endif %}
794
-
795
- {% if completeness_score.section_scores.component_basic < completeness_score.max_scores.component_basic %}
796
- <li>
797
- <strong>Improve Component Information</strong> (+{{ ((completeness_score.max_scores.component_basic - completeness_score.section_scores.component_basic) * 0.2)|round(1) }} points):
798
- <ul>
799
- {% if completeness_score.missing_fields.critical %}
800
- {% for field in completeness_score.missing_fields.critical %}
801
- {% if field == "name" or field == "description" or field == "purl" %}
802
- <li>Add {{ field }} information</li>
803
  {% endif %}
804
- {% endfor %}
805
  {% endif %}
806
- {% if completeness_score.missing_fields.important %}
807
- {% for field in completeness_score.missing_fields.important %}
808
- {% if field == "type" or field == "licenses" %}
809
- <li>Add {{ field }} information</li>
810
- {% endif %}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
811
  {% endfor %}
812
- {% endif %}
813
- </ul>
814
- </li>
815
- {% endif %}
 
 
 
 
 
 
 
 
 
 
 
 
816
 
817
- {% if completeness_score.section_scores.metadata < completeness_score.max_scores.metadata %}
818
- <li>
819
- <strong>Add Metadata</strong> (+{{ ((completeness_score.max_scores.metadata - completeness_score.section_scores.metadata) * 0.2)|round(1) }} points):
820
- <ul>
821
- {% if completeness_score.missing_fields.critical %}
822
- {% for field in completeness_score.missing_fields.critical %}
823
- {% if field == "primaryPurpose" or field == "suppliedBy" %}
824
- <li>Add {{ field }} information</li>
825
- {% endif %}
826
- {% endfor %}
827
- {% endif %}
828
- {% if completeness_score.missing_fields.supplementary %}
829
- {% for field in completeness_score.missing_fields.supplementary %}
830
- {% if field == "standardCompliance" or field == "domain" or field == "autonomyType" %}
831
- <li>Add {{ field }} information</li>
832
- {% endif %}
833
- {% endfor %}
834
- {% endif %}
835
- </ul>
836
- </li>
837
- {% endif %}
838
 
839
- {% if completeness_score.section_scores.external_references < completeness_score.max_scores.external_references %}
840
- <li>
841
- <strong>Add External References</strong> (+{{ ((completeness_score.max_scores.external_references - completeness_score.section_scores.external_references) * 0.1)|round(1) }} points):
842
- <ul>
843
- {% if completeness_score.missing_fields.critical %}
844
- {% for field in completeness_score.missing_fields.critical %}
845
- {% if field == "downloadLocation" %}
846
- <li>Add download location reference</li>
847
- {% endif %}
848
- {% endfor %}
849
- {% endif %}
850
- <li>Add links to model card, repository, and dataset</li>
851
- </ul>
852
- </li>
853
- {% endif %}
854
 
855
- {% if completeness_score.validation and not completeness_score.validation.valid %}
856
- <li>
857
- <strong>Fix Validation Issues</strong> (remove validation penalty):
858
- <ul>
859
- {% for recommendation in completeness_score.validation.recommendations %}
860
- <li>{{ recommendation }}</li>
861
- {% endfor %}
862
- </ul>
863
- </li>
864
  {% endif %}
865
- </ol>
866
- </div>
867
-
868
- <!-- Scoring Rubric Section -->
869
- <div class="calculation-section scoring-rubric">
870
- <h4>Scoring Rubric</h4>
871
- <p>The overall score is calculated using a weighted category approach:</p>
872
- <p><strong>Total Score = (Sum of (Category Score × Category Weight)) × 100</strong></p>
873
- <p>Where:</p>
874
- <ul>
875
- <li>Category Score = Sum of weights for present fields in that category</li>
876
- <li>Category Weight = Max Category Score ÷ Sum of All Max Category Scores</li>
877
- </ul>
878
-
879
- <p>Fields are classified into three tiers based on importance:</p>
880
- <ul>
881
- <li><span class="field-tier tier-critical"></span> <strong>Critical fields</strong>: Highest weight (3-4 points each)</li>
882
- <li><span class="field-tier tier-important"></span> <strong>Important fields</strong>: Medium weight (2-4 points each)</li>
883
- <li><span class="field-tier tier-supplementary"></span> <strong>Supplementary fields</strong>: Lower weight (1-2 points each)</li>
884
- </ul>
885
-
886
- <p>Penalties are applied for missing critical fields:</p>
887
- <ul>
888
- <li>Missing >3 critical fields: 20% penalty (score × 0.8)</li>
889
- <li>Missing 1-3 critical fields: 10% penalty (score × 0.9)</li>
890
- <li>Missing >5 important fields: 5% penalty (score × 0.95)</li>
891
- </ul>
892
-
893
- {% if completeness_score.validation_penalty %}
894
- <p>Additional penalties are applied based on validation results:</p>
895
- <ul>
896
- <li>Schema errors: Up to 50% reduction (10% per error)</li>
897
- <li>Schema warnings: Up to 20% reduction (5% per warning)</li>
898
- </ul>
899
- {% endif %}
900
  </div>
901
  </div>
902
  </div>
 
 
 
 
 
903
  </div>
904
 
905
  <script>
@@ -953,4 +1130,4 @@
953
  });
954
  </script>
955
  </body>
956
- </html>
 
2
  <html lang="en">
3
  <head>
4
  <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>AI SBOM Generated</title>
7
  <style>
8
+ body {
9
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
10
+ margin: 0;
11
+ padding: 0;
12
+ line-height: 1.6;
13
+ color: #333;
14
+ background-color: #f9f9f9;
15
+ }
16
+ .container {
17
+ max-width: 1000px;
18
+ margin: 0 auto;
19
+ padding: 0 20px;
20
+ }
21
 
22
  /* Header styling */
23
  .header {
24
+ background-color: #ffffff;
25
  padding: 15px 20px;
26
  border-bottom: 1px solid #e9ecef;
27
+ box-shadow: 0 2px 5px rgba(0,0,0,0.05);
28
  display: flex;
29
  align-items: center;
30
+ margin-bottom: 30px;
31
  }
32
  .header img {
33
+ height: 60px;
34
  margin-right: 15px;
35
  }
36
  .header h1 {
37
  margin: 0;
38
+ font-size: 28px;
39
+ color: #2c3e50;
40
+ font-weight: 600;
41
+ }
42
+
43
+ /* Content styling */
44
+ .content-section {
45
+ background-color: #ffffff;
46
+ border-radius: 8px;
47
+ padding: 25px;
48
+ margin-bottom: 30px;
49
+ box-shadow: 0 2px 10px rgba(0,0,0,0.05);
50
+ }
51
+
52
+ .content-section h2 {
53
+ color: #2c3e50;
54
+ margin-top: 0;
55
+ margin-bottom: 20px;
56
+ font-size: 22px;
57
+ border-bottom: 2px solid #f0f0f0;
58
+ padding-bottom: 10px;
59
+ }
60
+
61
+ .content-section h3 {
62
+ color: #2c3e50;
63
+ margin-top: 0;
64
+ margin-bottom: 15px;
65
+ font-size: 20px;
66
+ }
67
+
68
+ .content-section p {
69
+ margin-bottom: 20px;
70
+ font-size: 16px;
71
+ line-height: 1.7;
72
+ color: #555;
73
+ }
74
+
75
+ /* Button styling */
76
+ .button {
77
+ display: inline-block;
78
+ padding: 12px 20px;
79
+ background-color: #3498db;
80
+ color: white;
81
+ border: none;
82
+ border-radius: 6px;
83
+ cursor: pointer;
84
+ font-size: 15px;
85
+ font-weight: 500;
86
+ text-decoration: none;
87
+ transition: background-color 0.3s;
88
+ margin-bottom: 20px;
89
+ }
90
+
91
+ .button:hover {
92
+ background-color: #2980b9;
93
+ text-decoration: none;
94
+ }
95
+
96
+ button {
97
+ padding: 12px 20px;
98
+ background-color: #3498db;
99
+ color: white;
100
+ border: none;
101
+ border-radius: 6px;
102
+ cursor: pointer;
103
+ font-size: 15px;
104
+ font-weight: 500;
105
+ transition: background-color 0.3s;
106
+ }
107
+
108
+ button:hover {
109
+ background-color: #2980b9;
110
  }
111
 
112
+ /* Table styling */
113
+ table {
114
+ border-collapse: collapse;
115
+ width: 100%;
116
+ margin-top: 15px;
117
+ margin-bottom: 20px;
118
+ }
119
+ th, td {
120
+ border: 1px solid #e9ecef;
121
+ padding: 12px;
122
+ }
123
+ th {
124
+ background-color: #f8f9fa;
125
+ color: #2c3e50;
126
+ font-weight: 600;
127
+ }
128
 
129
  /* Fixed color styling for field checklist items */
130
  .check-mark { color: #27ae60; } /* Green color for check marks */
 
132
  .field-name { color: #000; } /* Black color for field names */
133
  .field-stars { color: #000; } /* Black color for importance stars */
134
 
135
+ .improvement {
136
+ color: #2c3e50;
137
+ background-color: #ecf0f1;
138
+ padding: 20px;
139
+ border-radius: 8px;
140
+ margin-bottom: 30px;
141
+ border-left: 4px solid #3498db;
142
+ }
143
  .improvement-value { color: #27ae60; font-weight: bold; }
144
+ .ai-badge {
145
+ background-color: #3498db;
146
+ color: white;
147
+ padding: 3px 8px;
148
+ border-radius: 3px;
149
+ font-size: 0.8em;
150
+ margin-left: 10px;
151
+ }
152
 
153
  /* New styles for human-friendly viewer */
154
  .aibom-viewer {
155
  margin: 20px 0;
156
+ border: 1px solid #e9ecef;
157
+ border-radius: 8px;
158
  padding: 20px;
159
  background-color: #f9f9f9;
160
  }
161
  .aibom-section {
162
  margin-bottom: 20px;
163
+ padding: 20px;
164
+ border-radius: 8px;
165
  background-color: white;
166
+ box-shadow: 0 2px 10px rgba(0,0,0,0.05);
167
  }
168
  .aibom-section h4 {
169
  margin-top: 0;
170
  color: #2c3e50;
171
+ border-bottom: 2px solid #f0f0f0;
172
+ padding-bottom: 10px;
173
+ margin-bottom: 15px;
174
+ font-size: 18px;
175
  }
176
  .aibom-property {
177
  display: flex;
178
+ margin: 10px 0;
179
  }
180
  .property-name {
181
  font-weight: bold;
 
184
  }
185
  .property-value {
186
  flex: 1;
187
+ color: #555;
188
+ line-height: 1.6;
189
  }
190
  .aibom-tabs {
191
  display: flex;
192
+ border-bottom: 1px solid #e9ecef;
193
  margin-bottom: 20px;
194
  }
195
  .aibom-tab {
196
+ padding: 12px 20px;
197
  cursor: pointer;
198
+ background-color: #f8f9fa;
199
  margin-right: 5px;
200
+ border-radius: 8px 8px 0 0;
201
+ font-weight: 500;
202
+ transition: all 0.3s ease;
203
  }
204
  .aibom-tab.active {
205
  background-color: #3498db;
206
  color: white;
207
  }
208
+ .aibom-tab:hover:not(.active) {
209
+ background-color: #e9ecef;
210
+ }
211
  .tab-content {
212
  display: none;
213
  }
 
215
  display: block;
216
  }
217
  .json-view {
218
+ background-color: #f8f9fa;
219
+ border: 1px solid #e9ecef;
220
+ border-radius: 8px;
221
+ padding: 20px;
222
  overflow: auto;
223
  max-height: 500px;
224
+ font-family: monospace;
225
+ line-height: 1.5;
226
  }
227
  .collapsible {
228
  cursor: pointer;
229
  position: relative;
230
+ transition: all 0.3s ease;
231
  }
232
  .collapsible:after {
233
  content: '+';
234
  position: absolute;
235
  right: 10px;
236
+ font-weight: bold;
237
  }
238
  .collapsible.active:after {
239
  content: '-';
 
241
  .collapsible-content {
242
  max-height: 0;
243
  overflow: hidden;
244
+ transition: max-height 0.3s ease-out;
245
  }
246
  .collapsible-content.active {
247
  max-height: 500px;
248
  }
249
  .tag {
250
  display: inline-block;
251
+ background-color: #e9ecef;
252
+ padding: 4px 10px;
253
+ border-radius: 16px;
254
+ margin: 3px;
255
  font-size: 0.9em;
256
  }
257
  .key-info {
258
  background-color: #e3f2fd;
259
  border-left: 4px solid #2196F3;
260
+ padding: 20px;
261
+ margin-bottom: 20px;
262
+ border-radius: 8px;
263
  }
264
 
265
  /* Progress bar styles */
266
  .progress-container {
267
  width: 100%;
268
  background-color: #f1f1f1;
269
+ border-radius: 8px;
270
+ margin: 8px 0;
271
+ overflow: hidden;
272
  }
273
  .progress-bar {
274
+ height: 24px;
275
+ border-radius: 8px;
276
  text-align: center;
277
+ line-height: 24px;
278
  color: white;
279
+ font-size: 14px;
280
+ font-weight: 500;
281
  display: flex;
282
  align-items: center;
283
  justify-content: center;
284
+ transition: width 0.5s ease;
285
  }
286
  .progress-excellent {
287
  background-color: #4CAF50; /* Green */
 
301
  }
302
  .score-table th {
303
  text-align: left;
304
+ padding: 12px;
305
+ background-color: #f8f9fa;
306
  }
307
  .score-table td {
308
+ padding: 12px;
309
  }
310
  .score-weight {
311
+ font-size: 0.9em;
312
  color: #666;
313
  margin-left: 5px;
314
  }
315
  .score-label {
316
  display: inline-block;
317
+ padding: 3px 8px;
318
+ border-radius: 4px;
319
  color: white;
320
+ font-size: 0.9em;
321
  margin-left: 5px;
322
  background-color: transparent; /* Make background transparent */
323
  }
324
  .total-score-container {
325
  display: flex;
326
  align-items: center;
327
+ margin-bottom: 25px;
328
+ background-color: white;
329
+ padding: 20px;
330
+ border-radius: 8px;
331
+ box-shadow: 0 2px 10px rgba(0,0,0,0.05);
332
  }
333
  .total-score {
334
+ font-size: 28px;
335
  font-weight: bold;
336
+ margin-right: 20px;
337
+ color: #2c3e50;
338
  }
339
  .total-progress {
340
  flex: 1;
 
349
  .tooltip .tooltiptext {
350
  visibility: hidden;
351
  width: 300px;
352
+ background-color: #34495e;
353
  color: #fff;
354
  text-align: left;
355
  border-radius: 6px;
356
+ padding: 12px;
357
  position: absolute;
358
  z-index: 1;
359
  bottom: 125%;
 
362
  opacity: 0;
363
  transition: opacity 0.3s;
364
  font-size: 0.9em;
365
+ line-height: 1.5;
366
+ box-shadow: 0 5px 15px rgba(0,0,0,0.1);
367
  }
368
  .tooltip:hover .tooltiptext {
369
  visibility: visible;
 
377
  margin-left: -5px;
378
  border-width: 5px;
379
  border-style: solid;
380
+ border-color: #34495e transparent transparent transparent;
381
  }
382
  .missing-fields {
383
  background-color: #ffebee;
384
  border-left: 4px solid #f44336;
385
+ padding: 20px;
386
+ margin: 20px 0;
387
+ border-radius: 8px;
388
  }
389
  .missing-fields h4 {
390
  margin-top: 0;
391
  color: #d32f2f;
392
+ margin-bottom: 15px;
393
  }
394
  .missing-fields ul {
395
  margin-bottom: 0;
396
+ padding-left: 20px;
397
  }
398
  .recommendations {
399
  background-color: #e8f5e9;
400
  border-left: 4px solid #4caf50;
401
+ padding: 20px;
402
+ margin: 20px 0;
403
+ border-radius: 8px;
404
  }
405
  .recommendations h4 {
406
  margin-top: 0;
407
  color: #2e7d32;
408
+ margin-bottom: 15px;
409
  }
410
  .importance-indicator {
411
  display: inline-block;
 
423
  .scoring-rubric {
424
  background-color: #e3f2fd;
425
  border-left: 4px solid #2196f3;
426
+ padding: 20px;
427
+ margin: 20px 0;
428
+ border-radius: 8px;
429
  }
430
  .scoring-rubric h4 {
431
  margin-top: 0;
432
  color: #1565c0;
433
+ margin-bottom: 15px;
434
  }
435
  .scoring-rubric table {
436
  width: 100%;
437
+ margin-top: 15px;
438
  }
439
  .scoring-rubric th, .scoring-rubric td {
440
+ padding: 10px;
441
  text-align: left;
442
  }
443
  .note-box {
444
  background-color: #fffbea; /* Lighter yellow background */
445
  border-left: 4px solid #ffc107;
446
+ padding: 20px;
447
+ margin: 20px 0;
448
+ border-radius: 8px;
449
  }
450
  .download-section {
451
+ margin: 20px 0;
452
+ display: flex;
453
+ align-items: center;
454
+ }
455
+ .download-section p {
456
+ margin: 0;
457
+ margin-right: 15px;
458
  }
459
 
460
  /* New styles for completeness profile */
461
  .completeness-profile {
462
  background-color: #e8f5e9;
463
+ border-radius: 8px;
464
+ padding: 20px;
465
+ margin: 20px 0;
466
  border-left: 4px solid #4caf50;
467
  }
468
  .profile-badge {
469
  display: inline-block;
470
+ padding: 5px 12px;
471
+ border-radius: 20px;
472
  color: white;
473
  font-weight: bold;
474
  margin-right: 10px;
 
505
  }
506
  .tier-legend {
507
  display: flex;
508
+ margin: 15px 0;
509
  font-size: 0.9em;
510
  }
511
  .tier-legend-item {
 
517
  .validation-penalty-info {
518
  background-color: #fff3e0;
519
  border-left: 4px solid #ff9800;
520
+ padding: 20px;
521
+ margin: 20px 0;
522
+ border-radius: 8px;
523
+ font-size: 0.95em;
524
  }
525
  .validation-penalty-info h4 {
526
  margin-top: 0;
527
  color: #e65100;
528
+ margin-bottom: 15px;
529
  }
530
 
531
  /* New section for score calculation explanation */
532
  .score-calculation {
533
  margin-top: 30px;
534
+ padding: 25px;
535
+ background-color: #ffffff;
536
+ border-radius: 8px;
537
+ box-shadow: 0 2px 10px rgba(0,0,0,0.05);
538
  }
539
  .score-calculation h3 {
540
  margin-top: 0;
541
+ color: #2c3e50;
542
+ border-bottom: 2px solid #f0f0f0;
543
  padding-bottom: 10px;
544
+ margin-bottom: 20px;
545
  }
546
  .calculation-section {
547
+ margin-bottom: 25px;
548
+ }
549
+
550
+ /* Footer styling */
551
+ .footer {
552
+ text-align: center;
553
+ padding: 20px;
554
+ color: #7f8c8d;
555
+ font-size: 14px;
556
+ margin-top: 30px;
557
+ }
558
+
559
+ /* Responsive adjustments */
560
+ @media (max-width: 768px) {
561
+ .aibom-property {
562
+ flex-direction: column;
563
+ }
564
+ .property-name {
565
+ width: 100%;
566
+ margin-bottom: 5px;
567
+ }
568
+ .total-score-container {
569
+ flex-direction: column;
570
+ align-items: flex-start;
571
+ }
572
+ .total-score {
573
+ margin-bottom: 10px;
574
+ }
575
+ .aibom-tabs {
576
+ flex-wrap: wrap;
577
+ }
578
+ .aibom-tab {
579
+ margin-bottom: 5px;
580
+ }
581
  }
582
  </style>
583
  </head>
584
  <body>
585
  <!-- Header with logo and title -->
586
  <div class="header">
587
+ <div style="display: flex; align-items: center; gap: 10px;">
588
+ <a href="https://aetheris.ai/" target="_blank">
589
+ <img src="https://huggingface.co/spaces/aetheris-ai/aibom-generator/resolve/main/templates/images/AetherisAI-logo.png" alt="Aetheris AI Logo">
590
+ </a>
591
+ <h1>AI SBOM Generator</h1>
592
+ </div>
593
  </div>
594
 
595
  <div class="container">
596
+ <div class="content-section">
597
+ <h2>AI SBOM Generated for {{ model_id }}</h2>
598
+
599
+ <a href="/" class="button">Generate another AI SBOM</a>
600
+
601
+ <div class="download-section">
602
+ <p>Download generated AI SBOM in CycloneDX format</p>
603
+ <button onclick="downloadJSON()">Download JSON</button>
604
+ </div>
605
 
606
+ {% if enhancement_report and enhancement_report.ai_enhanced %}
607
+ <div class="improvement">
608
+ <h3>AI Enhancement Results</h3>
609
+ <p>This AI SBOM was enhanced using <strong>{{ enhancement_report.ai_model }}</strong></p>
610
+ <p>Original Score: {{ enhancement_report.original_score.total_score|round(1) }}/100</p>
611
+ <p>Enhanced Score: {{ enhancement_report.final_score.total_score|round(1) }}/100</p>
612
+ <p>Improvement: <span class="improvement-value">+{{ enhancement_report.improvement|round(1) }} points</span></p>
613
+ </div>
614
+ {% endif %}
615
  </div>
 
616
 
617
  <!-- Human-friendly AI SBOM Viewer -->
618
  <div class="note-box">
 
665
  <div class="aibom-property">
666
  <div class="property-name">Model Parameters:</div>
667
  <div class="property-value">
 
 
 
 
 
 
 
668
  <ul>
669
  {% for key, value in aibom.components[0].modelCard.modelParameters.items() %}
670
  <li><strong>{{ key }}:</strong> {{ value }}</li>
671
  {% endfor %}
672
  </ul>
 
673
  </div>
674
  </div>
675
  {% endif %}
 
719
  </div>
720
 
721
  <div id="field-checklist" class="tab-content">
722
+ <div class="content-section">
723
+ <h3>Field Checklist</h3>
724
+
725
+ <!-- Field Tier Legend -->
726
+ <div class="tier-legend">
727
+ <div class="tier-legend-item">
728
+ <span class="field-tier tier-critical"></span>
729
+ <span>Critical</span>
730
+ </div>
731
+ <div class="tier-legend-item">
732
+ <span class="field-tier tier-important"></span>
733
+ <span>Important</span>
734
+ </div>
735
+ <div class="tier-legend-item">
736
+ <span class="field-tier tier-supplementary"></span>
737
+ <span>Supplementary</span>
738
+ </div>
739
  </div>
740
+
741
+ <ul>
742
+ {% for field, status in completeness_score.field_checklist.items() %}
743
+ {% if "✔" in status %}
744
+ <li>
745
+ <span class="check-mark">✔</span>
746
+ <span class="field-name">{{ field }}</span>
747
+ <span class="field-stars">{{ status.split('✔')[1] }}</span>
748
+ {% if completeness_score.field_tiers and field in completeness_score.field_tiers %}
749
+ <span class="field-tier tier-{{ completeness_score.field_tiers[field] }}"></span>
750
+ {% endif %}
751
+ </li>
752
+ {% else %}
753
+ <li>
754
+ <span class="x-mark">✘</span>
755
+ <span class="field-name">{{ field }}</span>
756
+ <span class="field-stars">{{ status.split('✘')[1] }}</span>
757
+ {% if completeness_score.field_tiers and field in completeness_score.field_tiers %}
758
+ <span class="field-tier tier-{{ completeness_score.field_tiers[field] }}"></span>
759
+ {% endif %}
760
+
761
+ {% if field == "component.description" %}
762
+ <span class="tooltip">(?)
763
+ <span class="tooltiptext">A detailed description of the model is essential for users to understand its purpose and capabilities. Add a description that is at least 20 characters long.</span>
764
+ </span>
765
+ {% elif field == "component.purl" %}
766
+ <span class="tooltip">(?)
767
+ <span class="tooltiptext">Package URL (PURL) is critical for uniquely identifying the model. It should follow the format pkg:huggingface/[owner]/[name]@[version].</span>
768
+ </span>
769
+ {% elif field == "modelCard.modelParameters" %}
770
+ <span class="tooltip">(?)
771
+ <span class="tooltiptext">Model parameters provide essential technical details about the model architecture, training, and capabilities.</span>
772
+ </span>
773
+ {% elif field == "modelCard.considerations" %}
774
+ <span class="tooltip">(?)
775
+ <span class="tooltiptext">Considerations section should include ethical considerations, limitations, and risks associated with the model.</span>
776
+ </span>
777
+ {% elif field == "externalReferences" %}
778
+ <span class="tooltip">(?)
779
+ <span class="tooltiptext">External references provide links to additional resources like model cards, repositories, and datasets.</span>
780
+ </span>
781
+ {% else %}
782
+ <span class="tooltip">(?)
783
+ <span class="tooltiptext">This field contributes to the completeness of your AI SBOM.</span>
784
+ </span>
785
+ {% endif %}
786
+ </li>
787
+ {% endif %}
788
+ {% endfor %}
789
+ </ul>
790
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
791
  </div>
792
 
793
  <div id="score-view" class="tab-content">
794
+ <div class="content-section">
795
+ <h3>AI SBOM Completeness Score</h3>
 
 
 
 
 
 
 
 
 
796
 
797
+ <!-- Completeness Profile Section -->
798
+ {% if completeness_score.completeness_profile %}
799
+ <div class="completeness-profile">
800
+ <h4>Completeness Profile:
801
+ <span class="profile-badge profile-{{ completeness_score.completeness_profile.name|lower }}">
802
+ {{ completeness_score.completeness_profile.name }}
803
+ </span>
804
+ </h4>
805
+ <p>{{ completeness_score.completeness_profile.description }}</p>
806
+
807
+ {% if completeness_score.completeness_profile.next_level %}
808
+ <p><strong>Next level:</strong> {{ completeness_score.completeness_profile.next_level.name }}
809
+ ({{ completeness_score.completeness_profile.next_level.missing_fields_count }} fields to add)</p>
810
+ {% endif %}
811
+ </div>
812
  {% endif %}
813
+
814
+ <!-- Total Score with Progress Bar -->
815
+ <div class="total-score-container">
816
+ <div class="total-score">{{ completeness_score.total_score|round(1) }}/100</div>
817
+ <div class="total-progress">
818
+ <div class="progress-container">
819
+ {% set score_percent = (completeness_score.total_score / 100) * 100 %}
820
+ {% set score_class = 'progress-poor' %}
821
+ {% set score_label = 'Poor' %}
822
+
823
+ {% if score_percent >= 90 %}
824
+ {% set score_class = 'progress-excellent' %}
825
+ {% set score_label = 'Excellent' %}
826
+ {% elif score_percent >= 70 %}
827
+ {% set score_class = 'progress-good' %}
828
+ {% set score_label = 'Good' %}
829
+ {% elif score_percent >= 50 %}
830
+ {% set score_class = 'progress-fair' %}
831
+ {% set score_label = 'Fair' %}
832
+ {% endif %}
833
+
834
+ <div class="progress-bar {{ score_class }}" style="width: {{ score_percent }}%">
835
+ {{ score_percent|int }}% {{ score_label }}
836
+ </div>
 
837
  </div>
838
  </div>
839
  </div>
840
+
841
+ <!-- Validation Penalty Explanation -->
842
+ {% if completeness_score.validation_penalty %}
843
+ <div class="validation-penalty-info">
844
+ <h4>About the Validation Penalty</h4>
845
+ <p>Your score includes a penalty because the AIBOM has schema validation issues. These are structural problems that don't comply with the CycloneDX specification requirements.</p>
846
+ <p><strong>How to fix this:</strong> Look at the "Fix Validation Issues" section in the recommendations below. Fixing these issues will remove the penalty and improve your overall score.</p>
847
+ </div>
848
+ {% endif %}
849
+
850
+ <!-- Section Scores with Progress Bars and Tooltips -->
851
+ <table class="score-table">
852
+ <thead>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
853
  <tr>
854
+ <th>Section</th>
855
+ <th>Score</th>
856
+ <th>Weight</th>
857
+ <th>Progress</th>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
858
  </tr>
859
+ </thead>
860
+ <tbody>
861
+ {% set weights = {'required_fields': 20, 'metadata': 20, 'component_basic': 20, 'component_model_card': 30, 'external_references': 10} %}
862
+ {% set tooltips = {
863
+ 'required_fields': 'Basic SBOM fields required by the CycloneDX specification: bomFormat, specVersion, serialNumber, and version.',
864
+ 'metadata': 'Information about the AI SBOM itself: timestamp, tools used to generate it, authors, and component metadata.',
865
+ 'component_basic': 'Basic information about the AI model: type, name, bom-ref, PURL, description, and licenses.',
866
+ 'component_model_card': 'Detailed information about the model: parameters, quantitative analysis, and ethical considerations.',
867
+ 'external_references': 'Links to external resources like model cards, repositories, and datasets.'
868
+ } %}
869
+ {% set display_names = {
870
+ 'required_fields': 'Required Fields',
871
+ 'metadata': 'Metadata',
872
+ 'component_basic': 'Component Basic',
873
+ 'component_model_card': 'Model Card',
874
+ 'external_references': 'External References'
875
+ } %}
876
+ {% for section, score in completeness_score.section_scores.items() %}
877
+ <tr>
878
+ <td>
879
+ {{ display_names[section] }}
880
+ <span class="tooltip">(?)
881
+ <span class="tooltiptext">{{ tooltips[section] }}</span>
882
+ </span>
883
+ </td>
884
+ <td>{{ score|round(1) }}/{{ completeness_score.max_scores[section] }}</td>
885
+ <td>{{ weights[section] }}%</td>
886
+ <td style="width: 50%;">
887
+ <div class="progress-container">
888
+ {% set percent = (score / completeness_score.max_scores[section]) * 100 %}
889
+ {% set class = 'progress-poor' %}
890
+
891
+ {% if percent >= 90 %}
892
+ {% set class = 'progress-excellent' %}
893
+ {% elif percent >= 70 %}
894
+ {% set class = 'progress-good' %}
895
+ {% elif percent >= 50 %}
896
+ {% set class = 'progress-fair' %}
897
  {% endif %}
898
+
899
+ <div class="progress-bar {{ class }}" style="width: {{ percent }}%">
900
+ {{ percent|int }}%
901
+ </div>
902
+ </div>
903
+ </td>
904
+ </tr>
905
  {% endfor %}
906
+ </tbody>
907
+ </table>
 
 
 
908
 
909
+ <!-- How the Overall Score is Calculated Section -->
910
+ <div class="score-calculation">
911
+ <h3>How the Overall Score is Calculated</h3>
912
+
913
+ <!-- Missing Fields Section -->
914
+ <div class="calculation-section missing-fields">
915
+ <h4>Critical Missing Fields</h4>
916
+ <p>The following fields are missing or incomplete and have the biggest impact on your score:</p>
917
+ <ul>
918
+ {% set missing_critical = [] %}
919
+ {% for field, status in completeness_score.field_checklist.items() %}
920
+ {% if "✘" in status %}
921
+ {% if completeness_score.field_tiers and field in completeness_score.field_tiers and completeness_score.field_tiers[field] == 'critical' %}
922
+ {% set _ = missing_critical.append(field) %}
923
+ <li>
924
+ <strong>{{ field }}</strong>
925
+ <span class="field-tier tier-critical"></span>
926
+ {% if field == "component.description" %}
927
+ - Add a detailed description of the model (at least 20 characters)
928
+ {% elif field == "component.purl" %}
929
+ - Add a valid PURL in the format pkg:huggingface/[owner]/[name]@[version]
930
+ {% elif field == "modelCard.modelParameters" %}
931
+ - Add model parameters section with architecture, size, and training details
932
+ {% elif field == "primaryPurpose" %}
933
+ - Add primary purpose information (what the model is designed for)
934
+ {% else %}
935
+ - This field is required for comprehensive documentation
 
 
 
 
 
 
 
936
  {% endif %}
937
+ </li>
938
  {% endif %}
939
+ {% endif %}
940
+ {% endfor %}
941
+ {% if missing_critical|length == 0 %}
942
+ <li>No critical fields are missing. Great job!</li>
943
+ {% endif %}
944
+ </ul>
945
+ </div>
946
+
947
+ <!-- Recommendations Section -->
948
+ <div class="calculation-section recommendations">
949
+ <h4>Recommendations to Improve Your Score</h4>
950
+ <ol>
951
+ {% if completeness_score.section_scores.component_model_card < completeness_score.max_scores.component_model_card %}
952
+ <li>
953
+ <strong>Enhance Model Card</strong> (+{{ ((completeness_score.max_scores.component_model_card - completeness_score.section_scores.component_model_card) * 0.3)|round(1) }} points):
954
+ <ul>
955
+ {% if completeness_score.missing_fields.critical %}
956
+ {% for field in completeness_score.missing_fields.critical %}
957
+ {% if field == "modelCard.modelParameters" or field == "modelCard.considerations" %}
958
+ <li>Add {{ field }} information</li>
959
+ {% endif %}
960
+ {% endfor %}
961
+ {% endif %}
962
+ </ul>
963
+ </li>
964
+ {% endif %}
965
+
966
+ {% if completeness_score.section_scores.component_basic < completeness_score.max_scores.component_basic %}
967
+ <li>
968
+ <strong>Add Basic Component Information</strong> (+{{ ((completeness_score.max_scores.component_basic - completeness_score.section_scores.component_basic) * 0.2)|round(1) }} points):
969
+ <ul>
970
+ {% if completeness_score.missing_fields.critical %}
971
+ {% for field in completeness_score.missing_fields.critical %}
972
+ {% if field == "name" or field == "description" or field == "purl" %}
973
+ <li>Add {{ field }} information</li>
974
+ {% endif %}
975
+ {% endfor %}
976
+ {% endif %}
977
+ {% if completeness_score.missing_fields.important %}
978
+ {% for field in completeness_score.missing_fields.important %}
979
+ {% if field == "type" or field == "licenses" %}
980
+ <li>Add {{ field }} information</li>
981
+ {% endif %}
982
+ {% endfor %}
983
+ {% endif %}
984
+ </ul>
985
+ </li>
986
+ {% endif %}
987
+
988
+ {% if completeness_score.section_scores.metadata < completeness_score.max_scores.metadata %}
989
+ <li>
990
+ <strong>Add Metadata</strong> (+{{ ((completeness_score.max_scores.metadata - completeness_score.section_scores.metadata) * 0.2)|round(1) }} points):
991
+ <ul>
992
+ {% if completeness_score.missing_fields.critical %}
993
+ {% for field in completeness_score.missing_fields.critical %}
994
+ {% if field == "primaryPurpose" or field == "suppliedBy" %}
995
+ <li>Add {{ field }} information</li>
996
+ {% endif %}
997
+ {% endfor %}
998
+ {% endif %}
999
+ {% if completeness_score.missing_fields.supplementary %}
1000
+ {% for field in completeness_score.missing_fields.supplementary %}
1001
+ {% if field == "standardCompliance" or field == "domain" or field == "autonomyType" %}
1002
+ <li>Add {{ field }} information</li>
1003
+ {% endif %}
1004
+ {% endfor %}
1005
+ {% endif %}
1006
+ </ul>
1007
+ </li>
1008
+ {% endif %}
1009
+
1010
+ {% if completeness_score.section_scores.external_references < completeness_score.max_scores.external_references %}
1011
+ <li>
1012
+ <strong>Add External References</strong> (+{{ ((completeness_score.max_scores.external_references - completeness_score.section_scores.external_references) * 0.1)|round(1) }} points):
1013
+ <ul>
1014
+ {% if completeness_score.missing_fields.critical %}
1015
+ {% for field in completeness_score.missing_fields.critical %}
1016
+ {% if field == "downloadLocation" %}
1017
+ <li>Add download location reference</li>
1018
+ {% endif %}
1019
+ {% endfor %}
1020
+ {% endif %}
1021
+ <li>Add links to model card, repository, and dataset</li>
1022
+ </ul>
1023
+ </li>
1024
+ {% endif %}
1025
+
1026
+ {% if completeness_score.validation and not completeness_score.validation.valid %}
1027
+ <li>
1028
+ <strong>Fix Validation Issues</strong> (remove validation penalty):
1029
+ <ul>
1030
+ {% for recommendation in completeness_score.validation.recommendations %}
1031
+ <li>{{ recommendation }}</li>
1032
  {% endfor %}
1033
+ </ul>
1034
+ </li>
1035
+ {% endif %}
1036
+ </ol>
1037
+ </div>
1038
+
1039
+ <!-- Scoring Rubric Section -->
1040
+ <div class="calculation-section scoring-rubric">
1041
+ <h4>Scoring Rubric</h4>
1042
+ <p>The overall score is calculated using a weighted category approach:</p>
1043
+ <p><strong>Total Score = (Sum of (Category Score × Category Weight)) × 100</strong></p>
1044
+ <p>Where:</p>
1045
+ <ul>
1046
+ <li>Category Score = Sum of weights for present fields in that category</li>
1047
+ <li>Category Weight = Max Category Score ÷ Sum of All Max Category Scores</li>
1048
+ </ul>
1049
 
1050
+ <p>Fields are classified into three tiers based on importance:</p>
1051
+ <ul>
1052
+ <li><span class="field-tier tier-critical"></span> <strong>Critical fields</strong>: Highest weight (3-4 points each)</li>
1053
+ <li><span class="field-tier tier-important"></span> <strong>Important fields</strong>: Medium weight (2-4 points each)</li>
1054
+ <li><span class="field-tier tier-supplementary"></span> <strong>Supplementary fields</strong>: Lower weight (1-2 points each)</li>
1055
+ </ul>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1056
 
1057
+ <p>Penalties are applied for missing critical fields:</p>
1058
+ <ul>
1059
+ <li>Missing >3 critical fields: 20% penalty (score × 0.8)</li>
1060
+ <li>Missing 1-3 critical fields: 10% penalty (score × 0.9)</li>
1061
+ <li>Missing >5 important fields: 5% penalty (score × 0.95)</li>
1062
+ </ul>
 
 
 
 
 
 
 
 
 
1063
 
1064
+ {% if completeness_score.validation_penalty %}
1065
+ <p>Additional penalties are applied based on validation results:</p>
1066
+ <ul>
1067
+ <li>Schema errors: Up to 50% reduction (10% per error)</li>
1068
+ <li>Schema warnings: Up to 20% reduction (5% per warning)</li>
1069
+ </ul>
 
 
 
1070
  {% endif %}
1071
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1072
  </div>
1073
  </div>
1074
  </div>
1075
+
1076
+ <!-- Footer -->
1077
+ <div class="footer">
1078
+ <p>© 2025 AI SBOM Generator | Powered by Aetheris AI</p>
1079
+ </div>
1080
  </div>
1081
 
1082
  <script>
 
1130
  });
1131
  </script>
1132
  </body>
1133
+ </html>