Spaces:
Running
Running
Update templates/result.html
Browse files- templates/result.html +773 -586
templates/result.html
CHANGED
@@ -4,7 +4,7 @@
|
|
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;
|
@@ -27,36 +27,71 @@
|
|
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 |
-
/* header-content div for layout */
|
44 |
-
.header .header-content {
|
45 |
display: flex;
|
46 |
-
|
47 |
}
|
48 |
-
.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
margin: 0;
|
50 |
-
font-size:
|
51 |
-
color: #
|
|
|
|
|
|
|
52 |
font-weight: 600;
|
53 |
-
|
54 |
}
|
55 |
-
/*
|
56 |
-
.
|
|
|
|
|
|
|
57 |
font-size: 14px;
|
58 |
-
|
59 |
-
font-weight: 500;
|
60 |
}
|
61 |
|
62 |
/* Content styling */
|
@@ -326,6 +361,19 @@
|
|
326 |
.score-table td {
|
327 |
padding: 12px;
|
328 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
329 |
.score-weight {
|
330 |
font-size: 0.9em;
|
331 |
color: #666;
|
@@ -426,6 +474,10 @@
|
|
426 |
color: #2e7d32;
|
427 |
margin-bottom: 15px;
|
428 |
}
|
|
|
|
|
|
|
|
|
429 |
.importance-indicator {
|
430 |
display: inline-block;
|
431 |
margin-left: 5px;
|
@@ -478,11 +530,11 @@
|
|
478 |
|
479 |
/* Styles for completeness profile */
|
480 |
.completeness-profile {
|
481 |
-
background-color: #
|
482 |
border-radius: 8px;
|
483 |
padding: 20px;
|
484 |
margin: 20px 0;
|
485 |
-
border-left: 4px solid #
|
486 |
}
|
487 |
.profile-badge {
|
488 |
display: inline-block;
|
@@ -547,656 +599,790 @@
|
|
547 |
margin-bottom: 15px;
|
548 |
}
|
549 |
|
550 |
-
/*
|
551 |
-
.
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
border-radius: 8px;
|
556 |
-
|
|
|
|
|
557 |
}
|
558 |
-
.
|
559 |
margin-top: 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
560 |
color: #2c3e50;
|
561 |
-
|
562 |
-
|
563 |
-
margin-bottom: 20px;
|
564 |
}
|
565 |
-
.
|
566 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
567 |
}
|
568 |
|
569 |
-
/*
|
570 |
-
.
|
571 |
-
|
|
|
572 |
padding: 20px;
|
573 |
-
|
574 |
-
|
575 |
-
|
576 |
}
|
577 |
-
|
578 |
-
|
579 |
-
|
580 |
-
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
}
|
600 |
}
|
601 |
</style>
|
602 |
</head>
|
603 |
<body>
|
604 |
-
<!-- Header with logo, title, and SBOM count -->
|
605 |
-
<div class="header">
|
606 |
-
<a href="https://aetheris.ai/" target="_blank">
|
607 |
-
<img src="https://huggingface.co/spaces/aetheris-ai/aibom-generator/resolve/main/templates/images/AetherisAI-logo.png" alt="Aetheris AI Logo">
|
608 |
-
</a>
|
609 |
-
<!-- Header-content div -->
|
610 |
-
<div class="header-content">
|
611 |
-
<h1>AI SBOM Generator</h1>
|
612 |
-
</div>
|
613 |
-
</div>
|
614 |
-
|
615 |
-
|
616 |
<div class="container">
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
<
|
624 |
-
|
|
|
625 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
626 |
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
<
|
632 |
-
<
|
633 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
634 |
</div>
|
635 |
-
{% endif %}
|
636 |
</div>
|
637 |
|
638 |
-
<!--
|
639 |
-
<div class="
|
640 |
-
<p><strong>
|
641 |
-
|
642 |
</div>
|
643 |
-
|
644 |
-
|
645 |
-
|
646 |
-
|
647 |
-
<
|
648 |
-
<div
|
|
|
|
|
|
|
|
|
|
|
649 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
650 |
|
651 |
-
|
652 |
-
<div class="
|
653 |
-
|
654 |
-
|
655 |
-
<
|
|
|
|
|
|
|
656 |
<div class="aibom-property">
|
657 |
-
<
|
658 |
-
<
|
659 |
</div>
|
660 |
<div class="aibom-property">
|
661 |
-
<
|
662 |
-
<
|
663 |
</div>
|
664 |
<div class="aibom-property">
|
665 |
-
<
|
666 |
-
<
|
667 |
</div>
|
668 |
<div class="aibom-property">
|
669 |
-
<
|
670 |
-
<
|
671 |
</div>
|
672 |
-
{% if aibom.components and aibom.components[0].
|
673 |
<div class="aibom-property">
|
674 |
-
<
|
675 |
-
<
|
|
|
|
|
|
|
|
|
676 |
</div>
|
677 |
{% endif %}
|
678 |
</div>
|
679 |
|
680 |
-
<!-- Model Card Section -->
|
681 |
{% if aibom.components and aibom.components[0].modelCard %}
|
682 |
<div class="aibom-section">
|
683 |
-
<h4
|
684 |
-
|
685 |
-
|
686 |
-
<
|
687 |
-
|
688 |
-
<div class="property-value">
|
689 |
-
<ul>
|
690 |
-
{% for key, value in aibom.components[0].modelCard.modelParameters.items() %}
|
691 |
-
<li><strong>{{ key }}:</strong> {{ value }}</li>
|
692 |
-
{% endfor %}
|
693 |
-
</ul>
|
694 |
-
</div>
|
695 |
-
</div>
|
696 |
-
{% endif %}
|
697 |
-
|
698 |
-
{% if aibom.components[0].modelCard.considerations %}
|
699 |
-
<div class="aibom-property">
|
700 |
-
<div class="property-name">Considerations:</div>
|
701 |
-
<div class="property-value">
|
702 |
-
<ul>
|
703 |
-
{% for key, value in aibom.components[0].modelCard.considerations.items() %}
|
704 |
-
<li><strong>{{ key }}:</strong> {{ value }}</li>
|
705 |
-
{% endfor %}
|
706 |
-
</ul>
|
707 |
-
</div>
|
708 |
-
</div>
|
709 |
-
{% endif %}
|
710 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
711 |
</div>
|
712 |
{% endif %}
|
713 |
-
|
714 |
-
|
715 |
-
{% if aibom.components and aibom.components[0].externalReferences %}
|
716 |
<div class="aibom-section">
|
717 |
-
<h4
|
718 |
-
|
719 |
-
|
720 |
-
|
721 |
-
|
722 |
-
<strong>{{ ref.type }}:</strong>
|
723 |
-
<a href="{{ ref.url }}" target="_blank">{{ ref.url }}</a>
|
724 |
-
{% if ref.comment %}
|
725 |
-
<br><em>{{ ref.comment }}</em>
|
726 |
-
{% endif %}
|
727 |
-
</li>
|
728 |
-
{% endfor %}
|
729 |
-
</ul>
|
730 |
</div>
|
|
|
731 |
</div>
|
732 |
{% endif %}
|
733 |
-
</div>
|
734 |
-
</div>
|
735 |
|
736 |
-
|
737 |
-
|
738 |
-
|
739 |
-
|
740 |
-
|
741 |
-
|
742 |
-
<div id="field-checklist" class="tab-content">
|
743 |
-
<div class="content-section">
|
744 |
-
<h3>Field Checklist & Mapping</h3>
|
745 |
-
|
746 |
-
<!-- Field Tier Legend -->
|
747 |
-
<div class="tier-legend">
|
748 |
-
<div class="tier-legend-item">
|
749 |
-
<span class="field-tier tier-critical"></span>
|
750 |
-
<span>Critical</span>
|
751 |
</div>
|
752 |
-
<div class="
|
753 |
-
<span class="
|
754 |
-
<span>
|
755 |
</div>
|
756 |
-
|
757 |
-
|
758 |
-
<span>
|
|
|
759 |
</div>
|
|
|
760 |
</div>
|
761 |
-
|
762 |
-
<p>This table shows how fields map to the CycloneDX specification and their status in your AI SBOM.</p>
|
763 |
-
|
764 |
-
<div class="field-mapping-container">
|
765 |
-
<h4>Standard CycloneDX Fields</h4>
|
766 |
-
<p>These fields are part of the official CycloneDX specification and are used in all SBOMs:</p>
|
767 |
-
<table class="field-mapping-table">
|
768 |
-
<thead>
|
769 |
-
<tr>
|
770 |
-
<th>Status</th>
|
771 |
-
<th>Field Name</th>
|
772 |
-
<th>CycloneDX JSON Path</th>
|
773 |
-
<th>Info</th>
|
774 |
-
<th>Importance</th>
|
775 |
-
</tr>
|
776 |
-
</thead>
|
777 |
-
<tbody>
|
778 |
-
{% for field_key, field_data in completeness_score.field_categorization.standard_cyclonedx_fields.items() %}
|
779 |
-
<tr class="{% if field_data.status == '✔' %}present-field{% else %}missing-field{% endif %}">
|
780 |
-
<td class="status-cell">
|
781 |
-
{% if field_data.status == "✔" %}
|
782 |
-
<span class="check-mark">✔</span>
|
783 |
-
{% else %}
|
784 |
-
<span class="x-mark">✘</span>
|
785 |
-
{% endif %}
|
786 |
-
</td>
|
787 |
-
<td>{{ field_data.field_name }}</td>
|
788 |
-
<td>{{ field_data.json_path }}</td>
|
789 |
-
<td>
|
790 |
-
<span class="tooltip">(?)
|
791 |
-
<span class="tooltiptext">{{ field_data.field_name }} field information.</span>
|
792 |
-
</span>
|
793 |
-
</td>
|
794 |
-
<td>
|
795 |
-
<span class="field-tier tier-{{ field_data.importance|lower }}"></span>
|
796 |
-
{{ field_data.importance }}
|
797 |
-
</td>
|
798 |
-
</tr>
|
799 |
-
{% endfor %}
|
800 |
-
</tbody>
|
801 |
-
</table>
|
802 |
|
803 |
-
|
804 |
-
|
805 |
-
|
806 |
-
|
807 |
-
|
808 |
-
|
809 |
-
|
810 |
-
|
811 |
-
|
812 |
-
|
813 |
-
|
814 |
-
|
815 |
-
|
816 |
-
|
817 |
-
|
818 |
-
|
819 |
-
|
820 |
-
|
821 |
-
|
822 |
-
|
823 |
-
|
824 |
-
|
825 |
-
|
826 |
-
|
827 |
-
|
828 |
-
<td>
|
829 |
-
<span class="tooltip">(?)
|
830 |
-
<span class="tooltiptext">{{ field_data.field_name }} field information.</span>
|
831 |
-
</span>
|
832 |
-
</td>
|
833 |
-
<td>
|
834 |
-
<span class="field-tier tier-{{ field_data.importance|lower }}"></span>
|
835 |
-
{{ field_data.importance }}
|
836 |
-
</td>
|
837 |
-
</tr>
|
838 |
-
{% endfor %}
|
839 |
-
</tbody>
|
840 |
-
</table>
|
841 |
-
</div>
|
842 |
-
|
843 |
-
<style>
|
844 |
-
.field-mapping-container {
|
845 |
-
margin-top: 20px;
|
846 |
-
max-width: 100%;
|
847 |
-
overflow-x: auto;
|
848 |
-
}
|
849 |
-
.field-mapping-table {
|
850 |
-
width: 100%;
|
851 |
-
border-collapse: collapse;
|
852 |
-
margin-bottom: 30px;
|
853 |
-
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
854 |
-
border-radius: 8px;
|
855 |
-
overflow: hidden;
|
856 |
-
table-layout: fixed;
|
857 |
-
}
|
858 |
-
.field-mapping-table th {
|
859 |
-
background-color: #f5f5f5;
|
860 |
-
padding: 12px 15px;
|
861 |
-
text-align: left;
|
862 |
-
font-weight: 600;
|
863 |
-
color: #333;
|
864 |
-
border-bottom: 2px solid #ddd;
|
865 |
-
}
|
866 |
-
.field-mapping-table td {
|
867 |
-
padding: 10px 15px;
|
868 |
-
border-bottom: 1px solid #eee;
|
869 |
-
vertical-align: middle;
|
870 |
-
word-wrap: break-word;
|
871 |
-
word-break: break-word;
|
872 |
-
max-width: 250px;
|
873 |
-
}
|
874 |
-
.field-mapping-table tr:last-child td {
|
875 |
-
border-bottom: none;
|
876 |
-
}
|
877 |
-
.field-mapping-table tr:hover {
|
878 |
-
background-color: #f9f9f9;
|
879 |
-
}
|
880 |
-
.status-cell {
|
881 |
-
text-align: center;
|
882 |
-
width: 60px;
|
883 |
-
}
|
884 |
-
.present-field {
|
885 |
-
background-color: #f0f7f0;
|
886 |
-
}
|
887 |
-
.missing-field {
|
888 |
-
background-color: #fff7f7;
|
889 |
-
}
|
890 |
-
.check-mark {
|
891 |
-
color: #4caf50;
|
892 |
-
font-weight: bold;
|
893 |
-
font-size: 18px;
|
894 |
-
}
|
895 |
-
.x-mark {
|
896 |
-
color: #f44336;
|
897 |
-
font-weight: bold;
|
898 |
-
font-size: 18px;
|
899 |
-
}
|
900 |
-
</style>
|
901 |
</div>
|
902 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
903 |
|
904 |
-
|
905 |
-
<div class="
|
906 |
-
<
|
907 |
-
|
908 |
-
|
909 |
-
|
910 |
-
|
911 |
-
|
912 |
-
|
913 |
-
|
914 |
-
|
915 |
-
|
916 |
-
|
917 |
-
|
918 |
-
|
919 |
-
|
920 |
-
|
921 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
922 |
</div>
|
923 |
-
|
924 |
-
|
925 |
-
|
926 |
-
|
927 |
-
|
928 |
-
|
929 |
-
|
930 |
-
|
931 |
-
|
932 |
-
|
933 |
-
|
934 |
-
|
935 |
-
|
936 |
-
|
937 |
-
|
938 |
-
|
939 |
-
|
940 |
-
|
941 |
-
|
942 |
-
|
943 |
-
|
944 |
-
|
945 |
-
|
946 |
-
|
947 |
-
|
948 |
-
|
949 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
950 |
</div>
|
951 |
-
|
952 |
-
|
953 |
-
|
954 |
-
|
955 |
-
|
956 |
-
|
957 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
958 |
</div>
|
959 |
-
|
960 |
-
|
961 |
-
|
962 |
-
|
|
|
|
|
963 |
<thead>
|
964 |
<tr>
|
965 |
-
<th>
|
966 |
-
<th>
|
967 |
-
<th>
|
968 |
-
<th>
|
|
|
969 |
</tr>
|
970 |
</thead>
|
971 |
<tbody>
|
972 |
-
{% set
|
973 |
-
{%
|
974 |
-
|
975 |
-
|
976 |
-
|
977 |
-
|
978 |
-
|
979 |
-
|
980 |
-
|
981 |
-
|
982 |
-
|
983 |
-
|
984 |
-
|
985 |
-
|
986 |
-
|
987 |
-
|
988 |
-
|
989 |
-
|
990 |
-
|
991 |
-
|
992 |
-
|
993 |
-
</span>
|
994 |
-
</td>
|
995 |
-
<td>{{ score|round(1) }}/{{ completeness_score.max_scores[section] }}</td>
|
996 |
-
<td>{{ weights[section] }}%</td>
|
997 |
-
<td style="width: 50%;">
|
998 |
-
<div class="progress-container">
|
999 |
-
{% set percent = (score / completeness_score.max_scores[section]) * 100 %}
|
1000 |
-
{% set class = 'progress-poor' %}
|
1001 |
-
|
1002 |
-
{% if percent >= 90 %}
|
1003 |
-
{% set class = 'progress-excellent' %}
|
1004 |
-
{% elif percent >= 70 %}
|
1005 |
-
{% set class = 'progress-good' %}
|
1006 |
-
{% elif percent >= 50 %}
|
1007 |
-
{% set class = 'progress-fair' %}
|
1008 |
-
{% endif %}
|
1009 |
-
|
1010 |
-
<div class="progress-bar {{ class }}" style="width: {{ percent }}%">
|
1011 |
-
{{ percent|int }}%
|
1012 |
-
</div>
|
1013 |
-
</div>
|
1014 |
-
</td>
|
1015 |
-
</tr>
|
1016 |
{% endfor %}
|
1017 |
</tbody>
|
1018 |
</table>
|
1019 |
-
|
1020 |
-
|
1021 |
-
|
1022 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1023 |
|
1024 |
-
<!--
|
1025 |
-
<div class="
|
1026 |
-
<
|
1027 |
-
<
|
1028 |
-
|
1029 |
-
|
1030 |
-
|
1031 |
-
|
1032 |
-
{%
|
1033 |
-
|
1034 |
-
|
1035 |
-
|
1036 |
-
|
1037 |
-
|
1038 |
-
|
1039 |
-
|
1040 |
-
|
1041 |
-
|
1042 |
-
- Add model parameters section with architecture, size, and training details
|
1043 |
-
{% elif field == "primaryPurpose" %}
|
1044 |
-
- Add primary purpose information (what the model is designed for)
|
1045 |
-
{% else %}
|
1046 |
-
- This field is required for comprehensive documentation
|
1047 |
-
{% endif %}
|
1048 |
-
</li>
|
1049 |
-
{% endif %}
|
1050 |
{% endif %}
|
1051 |
-
|
1052 |
-
|
1053 |
-
|
1054 |
-
|
1055 |
-
|
1056 |
-
|
1057 |
-
|
1058 |
-
<!-- Recommendations Section -->
|
1059 |
-
<div class="calculation-section recommendations">
|
1060 |
-
<h4>Recommendations to Improve Your Score</h4>
|
1061 |
-
<ol>
|
1062 |
-
{% if completeness_score.section_scores.component_model_card < completeness_score.max_scores.component_model_card %}
|
1063 |
-
<li>
|
1064 |
-
<strong>Enhance Model Card</strong> (+{{ ((completeness_score.max_scores.component_model_card - completeness_score.section_scores.component_model_card) * 0.3)|round(1) }} points):
|
1065 |
-
<ul>
|
1066 |
-
{% if completeness_score.missing_fields.critical %}
|
1067 |
-
{% for field in completeness_score.missing_fields.critical %}
|
1068 |
-
{% if field == "modelCard.modelParameters" or field == "modelCard.considerations" %}
|
1069 |
-
<li>Add {{ field }} information</li>
|
1070 |
-
{% endif %}
|
1071 |
-
{% endfor %}
|
1072 |
-
{% endif %}
|
1073 |
-
</ul>
|
1074 |
-
</li>
|
1075 |
-
{% endif %}
|
1076 |
-
|
1077 |
-
{% if completeness_score.section_scores.component_basic < completeness_score.max_scores.component_basic %}
|
1078 |
-
<li>
|
1079 |
-
<strong>Add Basic Component Information</strong> (+{{ ((completeness_score.max_scores.component_basic - completeness_score.section_scores.component_basic) * 0.2)|round(1) }} points):
|
1080 |
-
<ul>
|
1081 |
-
{% if completeness_score.missing_fields.critical %}
|
1082 |
-
{% for field in completeness_score.missing_fields.critical %}
|
1083 |
-
{% if field == "name" or field == "description" or field == "purl" %}
|
1084 |
-
<li>Add {{ field }} information</li>
|
1085 |
-
{% endif %}
|
1086 |
-
{% endfor %}
|
1087 |
-
{% endif %}
|
1088 |
-
{% if completeness_score.missing_fields.important %}
|
1089 |
-
{% for field in completeness_score.missing_fields.important %}
|
1090 |
-
{% if field == "type" or field == "licenses" %}
|
1091 |
-
<li>Add {{ field }} information</li>
|
1092 |
-
{% endif %}
|
1093 |
-
{% endfor %}
|
1094 |
-
{% endif %}
|
1095 |
-
</ul>
|
1096 |
-
</li>
|
1097 |
-
{% endif %}
|
1098 |
-
|
1099 |
-
{% if completeness_score.section_scores.metadata < completeness_score.max_scores.metadata %}
|
1100 |
-
<li>
|
1101 |
-
<strong>Add Metadata</strong> (+{{ ((completeness_score.max_scores.metadata - completeness_score.section_scores.metadata) * 0.2)|round(1) }} points):
|
1102 |
-
<ul>
|
1103 |
-
{% if completeness_score.missing_fields.critical %}
|
1104 |
-
{% for field in completeness_score.missing_fields.critical %}
|
1105 |
-
{% if field == "primaryPurpose" or field == "suppliedBy" %}
|
1106 |
-
<li>Add {{ field }} information</li>
|
1107 |
-
{% endif %}
|
1108 |
-
{% endfor %}
|
1109 |
-
{% endif %}
|
1110 |
-
{% if completeness_score.missing_fields.supplementary %}
|
1111 |
-
{% for field in completeness_score.missing_fields.supplementary %}
|
1112 |
-
{% if field == "standardCompliance" or field == "domain" or field == "autonomyType" %}
|
1113 |
-
<li>Add {{ field }} information</li>
|
1114 |
-
{% endif %}
|
1115 |
-
{% endfor %}
|
1116 |
-
{% endif %}
|
1117 |
-
</ul>
|
1118 |
-
</li>
|
1119 |
-
{% endif %}
|
1120 |
-
|
1121 |
-
{% if completeness_score.section_scores.external_references < completeness_score.max_scores.external_references %}
|
1122 |
-
<li>
|
1123 |
-
<strong>Add External References</strong> (+{{ ((completeness_score.max_scores.external_references - completeness_score.section_scores.external_references) * 0.1)|round(1) }} points):
|
1124 |
-
<ul>
|
1125 |
-
{% if completeness_score.missing_fields.critical %}
|
1126 |
-
{% for field in completeness_score.missing_fields.critical %}
|
1127 |
-
{% if field == "downloadLocation" %}
|
1128 |
-
<li>Add download location reference</li>
|
1129 |
-
{% endif %}
|
1130 |
-
{% endfor %}
|
1131 |
-
{% endif %}
|
1132 |
-
<li>Add links to model card, repository, and dataset</li>
|
1133 |
-
</ul>
|
1134 |
-
</li>
|
1135 |
-
{% endif %}
|
1136 |
-
|
1137 |
-
{% if completeness_score.validation and not completeness_score.validation.valid %}
|
1138 |
-
<li>
|
1139 |
-
<strong>Fix Validation Issues</strong> (remove validation penalty):
|
1140 |
-
<ul>
|
1141 |
-
{% for recommendation in completeness_score.validation.recommendations %}
|
1142 |
-
<li>{{ recommendation }}</li>
|
1143 |
-
{% endfor %}
|
1144 |
-
</ul>
|
1145 |
-
</li>
|
1146 |
-
{% endif %}
|
1147 |
-
</ol>
|
1148 |
</div>
|
1149 |
-
|
1150 |
-
<!-- Scoring
|
1151 |
-
<div class="
|
1152 |
-
<h4>
|
1153 |
-
<p>The
|
1154 |
-
<p><strong>Total Score = Sum of (Section Score × Section Weight)</strong></p>
|
1155 |
-
<p>Where:</p>
|
1156 |
<ul>
|
1157 |
-
<li>
|
1158 |
-
<li>
|
|
|
|
|
|
|
1159 |
</ul>
|
1160 |
|
1161 |
-
<
|
1162 |
-
|
1163 |
-
|
1164 |
-
|
1165 |
-
|
1166 |
-
|
1167 |
-
<li>Model Card: 10 points × 0.30 weight = 3.0 points</li>
|
1168 |
-
<li>External References: 5 points × 0.10 weight = 0.5 points</li>
|
1169 |
-
</ul>
|
1170 |
-
<p>The total score would be 12.5 points, even though the raw section scores sum to 60 points.</p>
|
1171 |
-
<p><strong>Note:</strong> The total score is <em>not</em> the sum of section scores. Each section contributes proportionally to its weight in the final score.</p>
|
1172 |
-
</div>
|
1173 |
-
|
1174 |
-
<p>Fields are classified into three tiers based on importance:</p>
|
1175 |
<ul>
|
1176 |
-
<li
|
1177 |
-
<li
|
1178 |
-
<li
|
1179 |
</ul>
|
1180 |
|
1181 |
-
<p>
|
1182 |
<ul>
|
1183 |
-
<li>
|
1184 |
-
<li>
|
1185 |
-
<li>Missing >5 important fields: 5% penalty (score × 0.95)</li>
|
1186 |
</ul>
|
1187 |
|
1188 |
-
|
1189 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1190 |
<ul>
|
1191 |
-
<li>
|
1192 |
-
<li>
|
|
|
1193 |
</ul>
|
|
|
|
|
|
|
1194 |
{% endif %}
|
1195 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1196 |
</div>
|
1197 |
</div>
|
1198 |
</div>
|
1199 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1200 |
<div class="content-section" style="text-align: center;">
|
1201 |
<h3>🗣️ Help Us Spread the Word</h3>
|
1202 |
<p>If you find this tool useful, share it with your network! <a href="https://sbom.aetheris.ai" target="_blank" rel="noopener noreferrer">https://sbom.aetheris.ai</a></p>
|
@@ -1209,17 +1395,17 @@
|
|
1209 |
</p>
|
1210 |
</div>
|
1211 |
|
1212 |
-
|
1213 |
-
<div class="content-section" style="text-align: center
|
1214 |
<!-- Display the SBOM count -->
|
1215 |
<div class="sbom-count">🚀 Generated AI SBOMs using this tool: <strong>{{ sbom_count if sbom_count else 'N/A' }}</strong></div>
|
1216 |
</div>
|
1217 |
-
|
1218 |
<!-- Footer -->
|
1219 |
<div class="footer">
|
1220 |
<p>© 2025 AI SBOM Generator | Powered by Aetheris AI</p>
|
1221 |
</div>
|
1222 |
-
|
1223 |
|
1224 |
<script>
|
1225 |
function switchTab(tabId) {
|
@@ -1272,4 +1458,5 @@
|
|
1272 |
});
|
1273 |
</script>
|
1274 |
</body>
|
1275 |
-
</html>
|
|
|
|
4 |
<meta charset="UTF-8">
|
5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
<title>AI SBOM Generated</title>
|
7 |
+
<script type="text/javascript" src="https://gc.kis.v2.scr.kaspersky-labs.com/FD126C42-EBFA-4E12-B309-BB3FDD723AC1/main.js?attr=tvQoyfSXq4JVDJvyoOAfThXMw9mgZRducLzTjUOnVphMAP2MBTXzDKF8WIUJETdEqCHXbUfgy-ihVF7QjtQfVIhhPZixhTUykm7ogEKcAY8g8XaCJjgLJ20ey7kvNW5yNFjtTgdjbiRHA4-4FfeZelCLWCOSbbpWpDquPezYp8V_SOTuYVK6EghRcNZgchGXWWoSOoga9DiwoB_4FVDoLZLAdtsEBybX-rcletazWXVi9vxFurtEiSBk3ewixUb_l1FR4W7mdhQXaDegmrEu__o1qNa73vqLlLY22wmjB5rhQnOItFstTw-BRsUtYRbY7d-jjDlvtLjvqrwMm8rYZlFzpvbgjkeQzbbyXQy0Wd0YNm11gR1z-q0xI-BTRItFmStcjfEWzrsnhOWvBeHrGvEpX8yWcLTOAOHXrE6Cp-i3mThNUiOErT99ZiPPmhieQZl6oq1Ed3sSldNMH1hsMsKuGxs-FhkmukdqA7jGa4gLoH44TqKyiB9xYz9SYuz02ngy3Z_jH7YuKbVCIqs3_GoXzOcbdzr0fRyP6CTomcBrIoSZQEx7ViPv0Lp4wf3pPt_zyOSVCeQ5kf3vjTsS-_0fs5KrbHNv79lNkBALSrNDDJTBFTo7RboIfhfsRdK0mZXAwzUgMuQVQSTVfe38SAk81t5hep59Nt9DAPECVEYO1j8YUeSPMHfFOcMXU8Jf2pWawwZYjHry6zfQ9Lf7gr-4QPIIvNjN_0kEGt6x-V8_QriVH4z1LkeLkLsy8a_i95Z5CadplFml5XZnt_MAi9rOfF1SVGfUjKYelOg1hUTRfDmFyHR4V1RCVJvdXCY17EHPfT7r0V6TUWFNhWAK2dkA8Be-CH_sb0LcyK1nb4zXrMlOQIB-XMsPxVl_tE3jLRTn9DREQDPnQ2G1-KeyjdI9zyutUVukG3EAdmJ-mH-9ATWfGuZQpRxblkXPiq4Ssi6jYLmE9yLcJyyZ3IfDsEMq4ZF7hNIutja3YPlCNUnE1U1yxqcNZvodlEKoTBpE0eZmq1_VVvZZmADz2CY6ZGrMMLb4-JPFw6mY8Y6sWSIuVok5nId4MmVrvMjf_M0DdPkRyCsqNBfw89fUFjUGWe6N0TTU4r595mfdPEg4HJJsq7qRlMCp3n1K8xMbz3zJDHe0OW-9_TcA7dSK7WpxkX8gaXemJddZjRuqJEIo4U5ortUQxCgYREMUAHYnWNZzy0qiyKYR17bA4apHq40wF3L-D_NUKkCP_i08dsCEabPqDHWM2HGW04kchwOlVcZeMKM592clkn4Fv6eIioqQIbFhFjAdnPiqSm4xWNtQxVn6VusRr4Sah0Vw5WYWaBqcZ4sJiQ6OslO0HKY8rg4MO6xo8niPr2tn9V_qwCIPLfYXfgub5tEofKtQkChKgIhtY8HIkFF25ZRyQf-MBu-bOfEG6WSBiuAqm25MqU00kqMHmv-y8tORjPhwHfl78Z1U0w3bz1NUoWtzB_qKFL1aCR6K0B2I59gS2ZvIj5BBM0rz0_u2QuogHNq1HluUEq6GkefCTZI8ovLHPFSVqWkQxqmvs7w3l2P3b9wXGzvnTR01bEVDNUETDHsDO9faiPkKoBS_vOwHNlJEJdPhfIpULJ0VgULPBrfN3XtHk14dcEGcXaFwIfXjeDMs5RXb38hs0wCmXcFQlr0TxIQ5t8jPMef3zCKlqqHm2l1HtJQJfzAOxbxZ2DQ6-LaeGBgHE6iW" nonce="508f6bedf744be51dd051f51433cdbea" charset="UTF-8"></script><link rel="stylesheet" crossorigin="anonymous" href="https://gc.kis.v2.scr.kaspersky-labs.com/E3E8934C-235A-4B0E-825A-35A08381A191/abn/main.css?attr=aHR0cHM6Ly9tYWlsLWF0dGFjaG1lbnQuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2F0dGFjaG1lbnQvdS8wLz91aT0yJmlrPTI5MzQwOTYwNGImYXR0aWQ9MC4xJnBlcm1tc2dpZD1tc2ctZjoxODM1MTQzNjcwMjEyNTQ2MDM4JnRoPTE5NzdiZDcxZWVkMzRkZjYmdmlldz1hdHQmZGlzcD1zYWZlJnJlYWxhdHRpZD1mX21ienh0cTdrMCZ6dyZzYWRkYmF0PUFOR2pkSjlXOXNjTFh3Q0hueU9Bd0VFcFlrYUNSSDd4dFlPUFBYd0p6VndUbHZuLUhxTjMtSTFwOVk0d0tCMU10YWxVcTBWeW03TUJKWGVfcGNwa1kxVkowTjFmQTZqM2xUSm9nZlNPQ0FqcGtzSHROS0tBTXRtQ1ZqYTFnWkhPZUNfNWU0T3ExcFQxdUF2WE9kb19neDBxMlFMQnJMSnNobWQxZGd4RjY1MjdRRUxkUUlWRm0xY3V3Q1RlVGREWnlxYjZtdDdBcUI4UTJhdlJGaFRkUTE5eEx2QlFzOFJ2cXgxeDY5Y09mUjFmYlJpb2s3VzQ5TFp4eVY5T05pbVdyZHRnZ3d5Y1NfY2I0SkNveXRhXzd5d2NDamVpQmxaTGlMLUg1LU5DNTQ1TjhSZVNZVWRkeTJCSExzaFg4a2xLejdwaG04SVBPTlB4YzhsTk5TVjN1TkZlTTVrdWpSNUYxM0RJMjVWZ184ZEY3eGtDeENKYnk4QVBiTkpYVW5sOHlmZWR3b0FqTmtOU0taZTRRaHRsMnBFbWhBNU9DQTM1eUpKcGxFMEEzM1VweE41WFNxM2pRdFZrZDlFckllNnNWcUEtWjRSbGVuaEFJNG03Q3J3ZXctSjhjbllXN2NuZVJuaHoySWtkNkdhdVFubzRmOUxYV25wUnZsTkpVdTVTV2VDanZtRmtZOUJ0UVFjNGFCZHBiMEdIMkNIOXFZM1JxOEhOVTltN040ZUJKdUJLT2lIMUJEaVFWNFdHa052YW9INEdJYXRSRmFWYzBXcGFubERWblJnZS1GNzdvMkJSY1FpQkIzMVdFM0pxN3ZDRDlYSVoxckJNZnNzdGhnNEcxUGliNC1jSk1FakNJUWE0SDVQZUFCYUt6R0xpRVRNRWp1cFFXVWJJV3ZJMktOdHpEd04wQkpWcjVrM20zQ19qMl9ady1Qd296VG1qbjA5X1ZOdzlOSERyeGd2VnZxR01GQ3JDRHpQX1lNNnhhRlM4Tk82bDc0LVByNVZUYlIzQTJGdlhlVTJSRWIzMGV3NDlYUGM0VDYyLTUwRkstM3dySFlNNmtTQ3l4ZXJYNXBZbmxpOWZlRlU1blpzTFQ0dENyOGx5R0FReVJ1ZEpBTVl6YnNzai1pdjZXMk5wNmFRWDZZNktfZ1l4VmtPTWU1bzctMWdiTTFfWG5lMklNZl83dE5oTERLNTFPMTBNWHZYTWJOblhaNjhEOGpCMmFhdHhfaHlFbEtSb0RMU05KTHJuMVJlY0xGMy1Nb1hMLVNQVFM2MlNhdUV5RGxoNDZ0T3p2TUJPeG95UjF4TEI0OWVOSWJkODBidVprY1BLQ1ZNUmI2OTNGVUQ3eHowZ3h3c1lWRTZsOTI3MXlOUml6MHRBX1BuSk4zbEZkTUkzNy1pQjJSTlFDV0ZYVHc"/><style>
|
8 |
body {
|
9 |
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
10 |
margin: 0;
|
|
|
27 |
box-shadow: 0 2px 5px rgba(0,0,0,0.05);
|
28 |
display: flex;
|
29 |
align-items: center;
|
30 |
+
justify-content: space-between;
|
31 |
margin-bottom: 30px;
|
32 |
}
|
33 |
+
.header-left {
|
34 |
+
display: flex;
|
35 |
+
align-items: center;
|
36 |
+
}
|
37 |
.header img {
|
38 |
height: 60px;
|
39 |
margin-right: 15px;
|
40 |
}
|
41 |
+
.header-content {
|
42 |
+
display: flex;
|
43 |
+
flex-direction: column;
|
44 |
+
}
|
45 |
.header h1 {
|
46 |
margin: 0;
|
47 |
font-size: 28px;
|
48 |
color: #2c3e50;
|
49 |
font-weight: 600;
|
50 |
+
margin-bottom: 5px;
|
51 |
}
|
52 |
+
.header-right {
|
|
|
|
|
53 |
display: flex;
|
54 |
+
gap: 10px;
|
55 |
}
|
56 |
+
.generate-another-btn {
|
57 |
+
padding: 12px 20px;
|
58 |
+
background-color: #3498db;
|
59 |
+
color: white;
|
60 |
+
text-decoration: none;
|
61 |
+
border-radius: 6px;
|
62 |
+
font-weight: 500;
|
63 |
+
font-size: 15px;
|
64 |
+
transition: background-color 0.3s;
|
65 |
+
}
|
66 |
+
.generate-another-btn:hover {
|
67 |
+
background-color: #2980b9;
|
68 |
+
text-decoration: none;
|
69 |
+
}
|
70 |
+
.success-message {
|
71 |
+
text-align: left;
|
72 |
+
padding: 15px;
|
73 |
+
background-color: #d4edda;
|
74 |
+
border: 1px solid #c3e6cb;
|
75 |
+
border-radius: 8px;
|
76 |
+
margin-bottom: 20px;
|
77 |
+
}
|
78 |
+
.success-message h2 {
|
79 |
margin: 0;
|
80 |
+
font-size: 18px;
|
81 |
+
color: #155724;
|
82 |
+
font-weight: 500;
|
83 |
+
}
|
84 |
+
.model-name {
|
85 |
font-weight: 600;
|
86 |
+
color: #2c3e50;
|
87 |
}
|
88 |
+
/* Footer styling */
|
89 |
+
.footer {
|
90 |
+
text-align: center;
|
91 |
+
padding: 20px;
|
92 |
+
color: #7f8c8d;
|
93 |
font-size: 14px;
|
94 |
+
margin-top: 30px;
|
|
|
95 |
}
|
96 |
|
97 |
/* Content styling */
|
|
|
361 |
.score-table td {
|
362 |
padding: 12px;
|
363 |
}
|
364 |
+
/* Adjust column widths for better progress bar display */
|
365 |
+
.score-table th:nth-child(1), .score-table td:nth-child(1) {
|
366 |
+
width: 25%; /* Category column */
|
367 |
+
}
|
368 |
+
.score-table th:nth-child(2), .score-table td:nth-child(2) {
|
369 |
+
width: 20%; /* Fields Present column */
|
370 |
+
}
|
371 |
+
.score-table th:nth-child(3), .score-table td:nth-child(3) {
|
372 |
+
width: 15%; /* Score column */
|
373 |
+
}
|
374 |
+
.score-table th:nth-child(4), .score-table td:nth-child(4) {
|
375 |
+
width: 40%; /* Progress column - wider for better display */
|
376 |
+
}
|
377 |
.score-weight {
|
378 |
font-size: 0.9em;
|
379 |
color: #666;
|
|
|
474 |
color: #2e7d32;
|
475 |
margin-bottom: 15px;
|
476 |
}
|
477 |
+
.recommendations ul {
|
478 |
+
margin-bottom: 0;
|
479 |
+
padding-left: 20px;
|
480 |
+
}
|
481 |
.importance-indicator {
|
482 |
display: inline-block;
|
483 |
margin-left: 5px;
|
|
|
530 |
|
531 |
/* Styles for completeness profile */
|
532 |
.completeness-profile {
|
533 |
+
background-color: #f6f5f5;
|
534 |
border-radius: 8px;
|
535 |
padding: 20px;
|
536 |
margin: 20px 0;
|
537 |
+
border-left: 4px solid #7f7c7c;
|
538 |
}
|
539 |
.profile-badge {
|
540 |
display: inline-block;
|
|
|
599 |
margin-bottom: 15px;
|
600 |
}
|
601 |
|
602 |
+
/* Validation warning box styling */
|
603 |
+
.validation-warning-box {
|
604 |
+
background-color: #fff3e0;
|
605 |
+
border: 1px solid #ff9800;
|
606 |
+
border-left: 4px solid #ff9800;
|
607 |
border-radius: 8px;
|
608 |
+
padding: 20px;
|
609 |
+
margin: 20px 0;
|
610 |
+
box-shadow: 0 2px 10px rgba(255, 152, 0, 0.1);
|
611 |
}
|
612 |
+
.validation-warning-box h4 {
|
613 |
margin-top: 0;
|
614 |
+
color: #e65100;
|
615 |
+
margin-bottom: 15px;
|
616 |
+
display: flex;
|
617 |
+
align-items: center;
|
618 |
+
}
|
619 |
+
.validation-warning-box .warning-icon {
|
620 |
+
margin-right: 10px;
|
621 |
+
font-size: 1.2em;
|
622 |
+
}
|
623 |
+
.validation-warning-box .issue-summary {
|
624 |
+
margin-bottom: 15px;
|
625 |
+
line-height: 1.6;
|
626 |
+
}
|
627 |
+
.validation-warning-box .issue-details {
|
628 |
+
margin-bottom: 15px;
|
629 |
+
}
|
630 |
+
.validation-warning-box .issue-list {
|
631 |
+
margin: 10px 0;
|
632 |
+
padding-left: 20px;
|
633 |
+
}
|
634 |
+
.validation-warning-box .issue-list li {
|
635 |
+
margin-bottom: 8px;
|
636 |
+
line-height: 1.5;
|
637 |
+
}
|
638 |
+
.validation-warning-box .call-to-action {
|
639 |
+
margin-top: 15px;
|
640 |
+
padding-top: 15px;
|
641 |
+
border-top: 1px solid #ffcc80;
|
642 |
+
}
|
643 |
+
.validation-warning-box .call-to-action p {
|
644 |
+
margin-bottom: 10px;
|
645 |
+
}
|
646 |
+
.issue-tracker-link {
|
647 |
+
display: inline-block;
|
648 |
+
padding: 8px 16px;
|
649 |
+
background-color: #3498db;
|
650 |
+
color: white;
|
651 |
+
text-decoration: none;
|
652 |
+
border-radius: 4px;
|
653 |
+
font-weight: 500;
|
654 |
+
transition: background-color 0.3s;
|
655 |
+
}
|
656 |
+
.issue-tracker-link:hover {
|
657 |
+
background-color: #2980b9;
|
658 |
+
text-decoration: none;
|
659 |
+
}
|
660 |
+
|
661 |
+
/* Category table styling */
|
662 |
+
.category-table {
|
663 |
+
margin-bottom: 30px;
|
664 |
+
}
|
665 |
+
.category-table h4 {
|
666 |
color: #2c3e50;
|
667 |
+
margin-bottom: 10px;
|
668 |
+
font-size: 18px;
|
|
|
669 |
}
|
670 |
+
.category-result {
|
671 |
+
background-color: #f8f9fa;
|
672 |
+
padding: 10px;
|
673 |
+
border-radius: 4px;
|
674 |
+
margin-top: 10px;
|
675 |
+
font-weight: bold;
|
676 |
+
}
|
677 |
+
.field-type-legend {
|
678 |
+
background-color: #e3f2fd;
|
679 |
+
border-left: 4px solid #2196f3;
|
680 |
+
padding: 15px;
|
681 |
+
margin: 20px 0;
|
682 |
+
border-radius: 8px;
|
683 |
+
font-size: 0.9em;
|
684 |
+
}
|
685 |
+
.field-type-legend h4 {
|
686 |
+
margin-top: 0;
|
687 |
+
color: #1565c0;
|
688 |
+
margin-bottom: 10px;
|
689 |
+
}
|
690 |
+
.legend-item {
|
691 |
+
display: inline-block;
|
692 |
+
margin-right: 20px;
|
693 |
+
margin-bottom: 5px;
|
694 |
}
|
695 |
|
696 |
+
/* Support section styling */
|
697 |
+
.support-section {
|
698 |
+
background-color: #f8f9fa;
|
699 |
+
border-left: 4px solid #6c757d;
|
700 |
padding: 20px;
|
701 |
+
margin: 30px 0;
|
702 |
+
border-radius: 8px;
|
703 |
+
text-align: center;
|
704 |
}
|
705 |
+
.support-section h3 {
|
706 |
+
margin-top: 0;
|
707 |
+
color: #495057;
|
708 |
+
margin-bottom: 15px;
|
709 |
+
}
|
710 |
+
.support-section p {
|
711 |
+
margin-bottom: 15px;
|
712 |
+
color: #6c757d;
|
713 |
+
}
|
714 |
+
.github-button {
|
715 |
+
display: inline-block;
|
716 |
+
padding: 12px 20px;
|
717 |
+
background-color: #3498db;
|
718 |
+
color: white;
|
719 |
+
text-decoration: none;
|
720 |
+
border-radius: 6px;
|
721 |
+
font-weight: 500;
|
722 |
+
transition: background-color 0.3s;
|
723 |
+
}
|
724 |
+
.github-button:hover {
|
725 |
+
background-color: #2980b9;
|
726 |
+
text-decoration: none;
|
|
|
727 |
}
|
728 |
</style>
|
729 |
</head>
|
730 |
<body>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
731 |
<div class="container">
|
732 |
+
<!-- Header -->
|
733 |
+
<div class="header">
|
734 |
+
<div class="header-left">
|
735 |
+
<a href="https://aetheris.ai/" target="_blank">
|
736 |
+
<img src="https://huggingface.co/spaces/aetheris-ai/aibom-generator/resolve/main/templates/images/AetherisAI-logo.png" alt="Aetheris AI Logo">
|
737 |
+
</a>
|
738 |
+
<div class="header-content">
|
739 |
+
<h1>AI SBOM Generator</h1>
|
740 |
+
</div>
|
741 |
</div>
|
742 |
+
<div class="header-right">
|
743 |
+
<!-- <a href="https://aetheris-ai-aibom-generator.hf.space/" class="generate-another-btn">🚀 Generate Another AI SBOM</a> -->
|
744 |
+
<a href="/" class="generate-another-btn">🚀 Generate Another AI SBOM</a>
|
745 |
+
</div>
|
746 |
+
</div>
|
747 |
+
|
748 |
+
<!-- Success Message
|
749 |
+
<div class="success-message">
|
750 |
+
<h2>✅ AI SBOM is Generated Successfully for <span class="model-name">{{ model_id }}</span></h2>
|
751 |
+
</div> -->
|
752 |
|
753 |
+
<!-- Key Information -->
|
754 |
+
<div class="key-info">
|
755 |
+
<h3>📋 AI SBOM Summary for model <span class="model-name">{{ model_id }}</span></h3>
|
756 |
+
<div class="aibom-property">
|
757 |
+
<span class="property-name">Model:</span>
|
758 |
+
<span class="property-value">{{ model_id }}</span>
|
759 |
+
</div>
|
760 |
+
<div class="aibom-property">
|
761 |
+
<span class="property-name">Generated:</span>
|
762 |
+
<span class="property-value">{{ aibom.metadata.timestamp }}</span>
|
763 |
+
</div>
|
764 |
+
<div class="aibom-property">
|
765 |
+
<span class="property-name">SBOM Format:</span>
|
766 |
+
<span class="property-value">{{ aibom.bomFormat }} {{ aibom.specVersion }}</span>
|
767 |
+
</div>
|
768 |
+
<div class="aibom-property">
|
769 |
+
<span class="property-name">Serial Number:</span>
|
770 |
+
<span class="property-value">{{ aibom.serialNumber }}</span>
|
771 |
</div>
|
|
|
772 |
</div>
|
773 |
|
774 |
+
<!-- Download Section -->
|
775 |
+
<div class="download-section">
|
776 |
+
<p><strong>Download your AI SBOM:</strong></p>
|
777 |
+
<button onclick="downloadJSON()">📥 Download JSON</button>
|
778 |
</div>
|
779 |
+
|
780 |
+
<!-- Completeness Profile -->
|
781 |
+
{% if completeness_score.completeness_profile %}
|
782 |
+
<div class="completeness-profile">
|
783 |
+
<h3>📊 Completeness Assessment</h3>
|
784 |
+
<div>
|
785 |
+
<span class="profile-badge profile-{{ completeness_score.completeness_profile.name|lower }}">
|
786 |
+
{{ completeness_score.completeness_profile.name }}
|
787 |
+
</span>
|
788 |
+
<span>{{ completeness_score.completeness_profile.description }}</span>
|
789 |
+
</div>
|
790 |
</div>
|
791 |
+
{% endif %}
|
792 |
+
|
793 |
+
<!-- Tabbed Content -->
|
794 |
+
<div class="aibom-viewer">
|
795 |
+
<div class="aibom-tabs">
|
796 |
+
<div class="aibom-tab active" onclick="switchTab('human-view')">Human-Friendly View</div>
|
797 |
+
<div class="aibom-tab" onclick="switchTab('field-checklist')">Field Checklist</div>
|
798 |
+
<div class="aibom-tab" onclick="switchTab('score-view')">Score Report</div>
|
799 |
+
<div class="aibom-tab" onclick="switchTab('json-view')">JSON View</div>
|
800 |
+
</div>
|
801 |
|
802 |
+
<!-- Human-Friendly View Tab -->
|
803 |
+
<div id="human-view" class="tab-content active">
|
804 |
+
<div class="aibom-section">
|
805 |
+
<h4>🤖 AI Model Information</h4>
|
806 |
+
<div class="aibom-property">
|
807 |
+
<span class="property-name">Name:</span>
|
808 |
+
<span class="property-value">{{ aibom.components[0].name if aibom.components else 'Not specified' }}</span>
|
809 |
+
</div>
|
810 |
<div class="aibom-property">
|
811 |
+
<span class="property-name">Type:</span>
|
812 |
+
<span class="property-value">{{ aibom.components[0].type if aibom.components else 'Not specified' }}</span>
|
813 |
</div>
|
814 |
<div class="aibom-property">
|
815 |
+
<span class="property-name">Version:</span>
|
816 |
+
<span class="property-value">{{ aibom.components[0].version if aibom.components else 'Not specified' }}</span>
|
817 |
</div>
|
818 |
<div class="aibom-property">
|
819 |
+
<span class="property-name">Description:</span>
|
820 |
+
<span class="property-value">{{ aibom.components[0].description if aibom.components and aibom.components[0].description else 'Not specified' }}</span>
|
821 |
</div>
|
822 |
<div class="aibom-property">
|
823 |
+
<span class="property-name">PURL:</span>
|
824 |
+
<span class="property-value">{{ aibom.components[0].purl if aibom.components and aibom.components[0].purl else 'Not specified' }}</span>
|
825 |
</div>
|
826 |
+
{% if aibom.components and aibom.components[0].licenses %}
|
827 |
<div class="aibom-property">
|
828 |
+
<span class="property-name">Licenses:</span>
|
829 |
+
<span class="property-value">
|
830 |
+
{% for license in aibom.components[0].licenses %}
|
831 |
+
<span class="tag">{{ license.license.id if license.license else 'Unknown' }}</span>
|
832 |
+
{% endfor %}
|
833 |
+
</span>
|
834 |
</div>
|
835 |
{% endif %}
|
836 |
</div>
|
837 |
|
|
|
838 |
{% if aibom.components and aibom.components[0].modelCard %}
|
839 |
<div class="aibom-section">
|
840 |
+
<h4>📊 Model Card</h4>
|
841 |
+
{% if aibom.components[0].modelCard.modelParameters %}
|
842 |
+
<div class="aibom-property">
|
843 |
+
<span class="property-name">Architecture:</span>
|
844 |
+
<span class="property-value">{{ aibom.components[0].modelCard.modelParameters.modelArchitecture if aibom.components[0].modelCard.modelParameters.modelArchitecture else 'Not specified' }}</span>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
845 |
</div>
|
846 |
+
<div class="aibom-property">
|
847 |
+
<span class="property-name">Task:</span>
|
848 |
+
<span class="property-value">{{ aibom.components[0].modelCard.modelParameters.task if aibom.components[0].modelCard.modelParameters.task else 'Not specified' }}</span>
|
849 |
+
</div>
|
850 |
+
{% endif %}
|
851 |
+
{% if aibom.components[0].modelCard.properties %}
|
852 |
+
<div class="aibom-property">
|
853 |
+
<span class="property-name">Additional Properties:</span>
|
854 |
+
<span class="property-value">
|
855 |
+
{% for prop in aibom.components[0].modelCard.properties %}
|
856 |
+
<span class="tag">{{ prop.name }}: {{ prop.value }}</span>
|
857 |
+
{% endfor %}
|
858 |
+
</span>
|
859 |
+
</div>
|
860 |
+
{% endif %}
|
861 |
</div>
|
862 |
{% endif %}
|
863 |
+
|
864 |
+
{% if aibom.externalReferences %}
|
|
|
865 |
<div class="aibom-section">
|
866 |
+
<h4>🔗 External References</h4>
|
867 |
+
{% for ref in aibom.externalReferences %}
|
868 |
+
<div class="aibom-property">
|
869 |
+
<span class="property-name">{{ ref.type|title }}:</span>
|
870 |
+
<span class="property-value"><a href="{{ ref.url }}" target="_blank">{{ ref.url }}</a></span>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
871 |
</div>
|
872 |
+
{% endfor %}
|
873 |
</div>
|
874 |
{% endif %}
|
|
|
|
|
875 |
|
876 |
+
<div class="aibom-section">
|
877 |
+
<h4>🛠️ Generation Metadata</h4>
|
878 |
+
<div class="aibom-property">
|
879 |
+
<span class="property-name">Generated by:</span>
|
880 |
+
<span class="property-value">{{ aibom.metadata.tools.components[0].name if aibom.metadata.tools and aibom.metadata.tools.components else 'Unknown' }}</span>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
881 |
</div>
|
882 |
+
<div class="aibom-property">
|
883 |
+
<span class="property-name">Timestamp:</span>
|
884 |
+
<span class="property-value">{{ aibom.metadata.timestamp }}</span>
|
885 |
</div>
|
886 |
+
{% if aibom.metadata.component %}
|
887 |
+
<div class="aibom-property">
|
888 |
+
<span class="property-name">Component Ref:</span>
|
889 |
+
<span class="property-value">{{ aibom.metadata.component['bom-ref'] }}</span>
|
890 |
</div>
|
891 |
+
{% endif %}
|
892 |
</div>
|
893 |
+
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
894 |
|
895 |
+
<!-- Field Checklist Tab -->
|
896 |
+
<div id="field-checklist" class="tab-content">
|
897 |
+
<div class="content-section">
|
898 |
+
<h3>Field Checklist & Mapping</h3>
|
899 |
+
|
900 |
+
<!-- Field Type Legend -->
|
901 |
+
<div class="field-type-legend">
|
902 |
+
<h4>Legend</h4>
|
903 |
+
<div class="legend-item">
|
904 |
+
<span class="field-tier tier-critical"></span>
|
905 |
+
<span>Critical</span>
|
906 |
+
</div>
|
907 |
+
<div class="legend-item">
|
908 |
+
<span class="field-tier tier-important"></span>
|
909 |
+
<span>Important</span>
|
910 |
+
</div>
|
911 |
+
<div class="legend-item">
|
912 |
+
<span class="field-tier tier-supplementary"></span>
|
913 |
+
<span>Supplementary</span>
|
914 |
+
</div>
|
915 |
+
<div class="legend-item">
|
916 |
+
<strong>CDX</strong> = CycloneDX Standard
|
917 |
+
</div>
|
918 |
+
<div class="legend-item">
|
919 |
+
<strong>AI</strong> = AI-Specific Extension
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
920 |
</div>
|
921 |
</div>
|
922 |
+
|
923 |
+
<p>This breakdown outlines field categories and statuses in the AI SBOM generated for model <strong>{{ model_id }}</strong>, showing how each field impacts the completeness score.</p>
|
924 |
+
|
925 |
+
{% if completeness_score.field_checklist %}
|
926 |
+
<!-- Required Fields Category -->
|
927 |
+
<div class="category-table">
|
928 |
+
<h4>Required Fields Category</h4>
|
929 |
+
<table>
|
930 |
+
<thead>
|
931 |
+
<tr>
|
932 |
+
<th>Status</th>
|
933 |
+
<th>Field Name</th>
|
934 |
+
<th>Actual Location</th>
|
935 |
+
<th>Tier</th>
|
936 |
+
<th>Type</th>
|
937 |
+
</tr>
|
938 |
+
</thead>
|
939 |
+
<tbody>
|
940 |
+
{% set required_fields = ['bomFormat', 'specVersion', 'serialNumber', 'version'] %}
|
941 |
+
{% for field in required_fields %}
|
942 |
+
<tr>
|
943 |
+
<td>
|
944 |
+
{% if completeness_score.field_checklist.get(field, '').startswith('✔') %}
|
945 |
+
<span class="check-mark">✔</span>
|
946 |
+
{% else %}
|
947 |
+
<span class="x-mark">✘</span>
|
948 |
+
{% endif %}
|
949 |
+
</td>
|
950 |
+
<td>{{ field }}</td>
|
951 |
+
<td>
|
952 |
+
{% if completeness_score.field_checklist.get(field, '').startswith('✔') %}
|
953 |
+
$.{{ field }}
|
954 |
+
{% else %}
|
955 |
+
Not found
|
956 |
+
{% endif %}
|
957 |
+
</td>
|
958 |
+
<td><span class="field-tier tier-critical"></span> Critical</td>
|
959 |
+
<td>CDX</td>
|
960 |
+
</tr>
|
961 |
+
{% endfor %}
|
962 |
+
</tbody>
|
963 |
+
</table>
|
964 |
+
<div class="category-result">
|
965 |
+
Result: {{ completeness_score.category_details.required_fields.present_fields if completeness_score.category_details else 'N/A' }}/{{ completeness_score.category_details.required_fields.total_fields if completeness_score.category_details else 'N/A' }} present
|
966 |
+
({{ completeness_score.category_details.required_fields.percentage if completeness_score.category_details else 'N/A' }}%) =
|
967 |
+
{{ completeness_score.section_scores.required_fields if completeness_score.section_scores else 'N/A' }}/20 points
|
968 |
+
</div>
|
969 |
+
</div>
|
970 |
|
971 |
+
<!-- Metadata Category -->
|
972 |
+
<div class="category-table">
|
973 |
+
<h4>Metadata Category</h4>
|
974 |
+
<table>
|
975 |
+
<thead>
|
976 |
+
<tr>
|
977 |
+
<th>Status</th>
|
978 |
+
<th>Field Name</th>
|
979 |
+
<th>Actual Location</th>
|
980 |
+
<th>Tier</th>
|
981 |
+
<th>Type</th>
|
982 |
+
</tr>
|
983 |
+
</thead>
|
984 |
+
<tbody>
|
985 |
+
{% set metadata_fields = [
|
986 |
+
('primaryPurpose', 'Critical'),
|
987 |
+
('suppliedBy', 'Critical'),
|
988 |
+
('standardCompliance', 'Supplementary'),
|
989 |
+
('domain', 'Supplementary'),
|
990 |
+
('autonomyType', 'Supplementary')
|
991 |
+
] %}
|
992 |
+
{% for field, tier in metadata_fields %}
|
993 |
+
<tr>
|
994 |
+
<td>
|
995 |
+
{% if completeness_score.field_checklist.get(field, '').startswith('✔') %}
|
996 |
+
<span class="check-mark">✔</span>
|
997 |
+
{% else %}
|
998 |
+
<span class="x-mark">✘</span>
|
999 |
+
{% endif %}
|
1000 |
+
</td>
|
1001 |
+
<td>{{ field }}</td>
|
1002 |
+
<td>
|
1003 |
+
{% if completeness_score.field_checklist.get(field, '').startswith('✔') %}
|
1004 |
+
$.metadata.properties[name="{{ field }}"]
|
1005 |
+
{% else %}
|
1006 |
+
Not found
|
1007 |
+
{% endif %}
|
1008 |
+
</td>
|
1009 |
+
<td><span class="field-tier tier-{{ tier.lower() }}"></span> {{ tier }}</td>
|
1010 |
+
<td>AI</td>
|
1011 |
+
</tr>
|
1012 |
+
{% endfor %}
|
1013 |
+
</tbody>
|
1014 |
+
</table>
|
1015 |
+
<div class="category-result">
|
1016 |
+
Result: {{ completeness_score.category_details.metadata.present_fields if completeness_score.category_details else 'N/A' }}/{{ completeness_score.category_details.metadata.total_fields if completeness_score.category_details else 'N/A' }} present
|
1017 |
+
({{ completeness_score.category_details.metadata.percentage if completeness_score.category_details else 'N/A' }}%) =
|
1018 |
+
{{ completeness_score.section_scores.metadata if completeness_score.section_scores else 'N/A' }}/20 points
|
1019 |
</div>
|
1020 |
+
</div>
|
1021 |
+
|
1022 |
+
<!-- Component Basic Category -->
|
1023 |
+
<div class="category-table">
|
1024 |
+
<h4>Component Basic Category</h4>
|
1025 |
+
<table>
|
1026 |
+
<thead>
|
1027 |
+
<tr>
|
1028 |
+
<th>Status</th>
|
1029 |
+
<th>Field Name</th>
|
1030 |
+
<th>Actual Location</th>
|
1031 |
+
<th>Tier</th>
|
1032 |
+
<th>Type</th>
|
1033 |
+
</tr>
|
1034 |
+
</thead>
|
1035 |
+
<tbody>
|
1036 |
+
{% set component_basic_fields = [
|
1037 |
+
('name', 'Critical'),
|
1038 |
+
('type', 'Important'),
|
1039 |
+
('purl', 'Important'),
|
1040 |
+
('description', 'Important'),
|
1041 |
+
('licenses', 'Important')
|
1042 |
+
] %}
|
1043 |
+
{% for field, tier in component_basic_fields %}
|
1044 |
+
<tr>
|
1045 |
+
<td>
|
1046 |
+
{% if completeness_score.field_checklist.get(field, '').startswith('✔') %}
|
1047 |
+
<span class="check-mark">✔</span>
|
1048 |
+
{% else %}
|
1049 |
+
<span class="x-mark">✘</span>
|
1050 |
+
{% endif %}
|
1051 |
+
</td>
|
1052 |
+
<td>{{ field }}</td>
|
1053 |
+
<td>
|
1054 |
+
{% if completeness_score.field_checklist.get(field, '').startswith('✔') %}
|
1055 |
+
$.components[0].{{ field }}
|
1056 |
+
{% else %}
|
1057 |
+
{% if field == 'description' %}
|
1058 |
+
Not found in component level
|
1059 |
+
{% else %}
|
1060 |
+
Not found
|
1061 |
+
{% endif %}
|
1062 |
+
{% endif %}
|
1063 |
+
</td>
|
1064 |
+
<td><span class="field-tier tier-{{ tier.lower() }}"></span> {{ tier }}</td>
|
1065 |
+
<td>CDX</td>
|
1066 |
+
</tr>
|
1067 |
+
{% endfor %}
|
1068 |
+
</tbody>
|
1069 |
+
</table>
|
1070 |
+
<div class="category-result">
|
1071 |
+
Result: {{ completeness_score.category_details.component_basic.present_fields if completeness_score.category_details else 'N/A' }}/{{ completeness_score.category_details.component_basic.total_fields if completeness_score.category_details else 'N/A' }} present
|
1072 |
+
({{ completeness_score.category_details.component_basic.percentage if completeness_score.category_details else 'N/A' }}%) =
|
1073 |
+
{{ completeness_score.section_scores.component_basic if completeness_score.section_scores else 'N/A' }}/20 points
|
1074 |
</div>
|
1075 |
+
</div>
|
1076 |
+
|
1077 |
+
<!-- Component Model Card Category -->
|
1078 |
+
<div class="category-table">
|
1079 |
+
<h4>Component Model Card Category</h4>
|
1080 |
+
<table>
|
1081 |
+
<thead>
|
1082 |
+
<tr>
|
1083 |
+
<th>Status</th>
|
1084 |
+
<th>Field Name</th>
|
1085 |
+
<th>Actual Location</th>
|
1086 |
+
<th>Tier</th>
|
1087 |
+
<th>Type</th>
|
1088 |
+
</tr>
|
1089 |
+
</thead>
|
1090 |
+
<tbody>
|
1091 |
+
{% set model_card_fields = [
|
1092 |
+
('energyConsumption', 'Important'),
|
1093 |
+
('hyperparameter', 'Important'),
|
1094 |
+
('limitation', 'Important'),
|
1095 |
+
('safetyRiskAssessment', 'Important'),
|
1096 |
+
('typeOfModel', 'Important'),
|
1097 |
+
('modelExplainability', 'Supplementary'),
|
1098 |
+
('energyQuantity', 'Supplementary'),
|
1099 |
+
('energyUnit', 'Supplementary'),
|
1100 |
+
('informationAboutTraining', 'Supplementary'),
|
1101 |
+
('informationAboutApplication', 'Supplementary'),
|
1102 |
+
('metric', 'Supplementary'),
|
1103 |
+
('metricDecisionThreshold', 'Supplementary'),
|
1104 |
+
('modelDataPreprocessing', 'Supplementary'),
|
1105 |
+
('useSensitivePersonalInformation', 'Supplementary')
|
1106 |
+
] %}
|
1107 |
+
{% for field, tier in model_card_fields %}
|
1108 |
+
<tr>
|
1109 |
+
<td>
|
1110 |
+
{% if completeness_score.field_checklist.get(field, '').startswith('✔') %}
|
1111 |
+
<span class="check-mark">✔</span>
|
1112 |
+
{% else %}
|
1113 |
+
<span class="x-mark">✘</span>
|
1114 |
+
{% endif %}
|
1115 |
+
</td>
|
1116 |
+
<td>{{ field }}</td>
|
1117 |
+
<td>
|
1118 |
+
{% if completeness_score.field_checklist.get(field, '').startswith('✔') %}
|
1119 |
+
{% if field == 'typeOfModel' %}
|
1120 |
+
$.metadata.properties[name="{{ field }}"]
|
1121 |
+
{% else %}
|
1122 |
+
$.components[0].modelCard.{{ field }}
|
1123 |
+
{% endif %}
|
1124 |
+
{% else %}
|
1125 |
+
Not found
|
1126 |
+
{% endif %}
|
1127 |
+
</td>
|
1128 |
+
<td><span class="field-tier tier-{{ tier.lower() }}"></span> {{ tier }}</td>
|
1129 |
+
<td>AI</td>
|
1130 |
+
</tr>
|
1131 |
+
{% endfor %}
|
1132 |
+
</tbody>
|
1133 |
+
</table>
|
1134 |
+
<div class="category-result">
|
1135 |
+
Result: {{ completeness_score.category_details.component_model_card.present_fields if completeness_score.category_details else 'N/A' }}/{{ completeness_score.category_details.component_model_card.total_fields if completeness_score.category_details else 'N/A' }} present
|
1136 |
+
({{ completeness_score.category_details.component_model_card.percentage if completeness_score.category_details else 'N/A' }}%) =
|
1137 |
+
{{ completeness_score.section_scores.component_model_card if completeness_score.section_scores else 'N/A' }}/30 points
|
1138 |
</div>
|
1139 |
+
</div>
|
1140 |
+
|
1141 |
+
<!-- External References Category -->
|
1142 |
+
<div class="category-table">
|
1143 |
+
<h4>External References Category</h4>
|
1144 |
+
<table>
|
1145 |
<thead>
|
1146 |
<tr>
|
1147 |
+
<th>Status</th>
|
1148 |
+
<th>Field Name</th>
|
1149 |
+
<th>Actual Location</th>
|
1150 |
+
<th>Tier</th>
|
1151 |
+
<th>Type</th>
|
1152 |
</tr>
|
1153 |
</thead>
|
1154 |
<tbody>
|
1155 |
+
{% set external_ref_fields = [('downloadLocation', 'Critical')] %}
|
1156 |
+
{% for field, tier in external_ref_fields %}
|
1157 |
+
<tr>
|
1158 |
+
<td>
|
1159 |
+
{% if completeness_score.field_checklist.get(field, '').startswith('✔') %}
|
1160 |
+
<span class="check-mark">✔</span>
|
1161 |
+
{% else %}
|
1162 |
+
<span class="x-mark">✘</span>
|
1163 |
+
{% endif %}
|
1164 |
+
</td>
|
1165 |
+
<td>{{ field }}</td>
|
1166 |
+
<td>
|
1167 |
+
{% if completeness_score.field_checklist.get(field, '').startswith('✔') %}
|
1168 |
+
$.externalReferences[type="distribution"]
|
1169 |
+
{% else %}
|
1170 |
+
Not found
|
1171 |
+
{% endif %}
|
1172 |
+
</td>
|
1173 |
+
<td><span class="field-tier tier-{{ tier.lower() }}"></span> {{ tier }}</td>
|
1174 |
+
<td>CDX</td>
|
1175 |
+
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1176 |
{% endfor %}
|
1177 |
</tbody>
|
1178 |
</table>
|
1179 |
+
<div class="category-result">
|
1180 |
+
Result: {{ completeness_score.category_details.external_references.present_fields if completeness_score.category_details else 'N/A' }}/{{ completeness_score.category_details.external_references.total_fields if completeness_score.category_details else 'N/A' }} present
|
1181 |
+
({{ completeness_score.category_details.external_references.percentage if completeness_score.category_details else 'N/A' }}%) =
|
1182 |
+
{{ completeness_score.section_scores.external_references if completeness_score.section_scores else 'N/A' }}/10 points
|
1183 |
+
</div>
|
1184 |
+
</div>
|
1185 |
+
|
1186 |
+
{% else %}
|
1187 |
+
<p>Field checklist data not available.</p>
|
1188 |
+
{% endif %}
|
1189 |
+
</div>
|
1190 |
+
</div>
|
1191 |
+
|
1192 |
+
<!-- Score Report Tab -->
|
1193 |
+
<div id="score-view" class="tab-content">
|
1194 |
+
<div class="content-section">
|
1195 |
+
<h3>📊 Completeness Score Report</h3>
|
1196 |
|
1197 |
+
<!-- Total Score Display -->
|
1198 |
+
<div class="total-score-container">
|
1199 |
+
<div class="total-score">{{ (completeness_score.total_score if completeness_score.total_score != "Undefined" else 0)|round(1) }}/100</div>
|
1200 |
+
<div class="total-progress">
|
1201 |
+
<div class="progress-container">
|
1202 |
+
{% set score_percent = completeness_score.total_score %}
|
1203 |
+
{% if score_percent >= 90 %}
|
1204 |
+
{% set score_class = 'progress-excellent' %}
|
1205 |
+
{% set score_label = 'Excellent' %}
|
1206 |
+
{% elif score_percent >= 70 %}
|
1207 |
+
{% set score_class = 'progress-good' %}
|
1208 |
+
{% set score_label = 'Good' %}
|
1209 |
+
{% elif score_percent >= 50 %}
|
1210 |
+
{% set score_class = 'progress-fair' %}
|
1211 |
+
{% set score_label = 'Fair' %}
|
1212 |
+
{% else %}
|
1213 |
+
{% set score_class = 'progress-poor' %}
|
1214 |
+
{% set score_label = 'Poor' %}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1215 |
{% endif %}
|
1216 |
+
|
1217 |
+
<div class="progress-bar {{ score_class }}" style="width: {{ score_percent }}%">
|
1218 |
+
{{ score_percent|int }}% {{ score_label }}
|
1219 |
+
</div>
|
1220 |
+
</div>
|
1221 |
+
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1222 |
</div>
|
1223 |
+
|
1224 |
+
<!-- Generic Scoring Explanation -->
|
1225 |
+
<div class="scoring-rubric">
|
1226 |
+
<h4>How AI SBOM Completeness is Scored</h4>
|
1227 |
+
<p>The completeness score evaluates how well your AI SBOM documents the model across five key categories:</p>
|
|
|
|
|
1228 |
<ul>
|
1229 |
+
<li><strong>Required Fields (20 points):</strong> Basic SBOM structure mandated by CycloneDX</li>
|
1230 |
+
<li><strong>Metadata (20 points):</strong> Information about the SBOM generation and model purpose</li>
|
1231 |
+
<li><strong>Component Basic (20 points):</strong> Essential model identification and licensing</li>
|
1232 |
+
<li><strong>Model Card (30 points):</strong> Detailed AI-specific documentation for transparency</li>
|
1233 |
+
<li><strong>External References (10 points):</strong> Links to model resources and documentation</li>
|
1234 |
</ul>
|
1235 |
|
1236 |
+
<p><strong>Calculation Method:</strong></p>
|
1237 |
+
<p>Each category score = (Present Fields ÷ Total Fields) × Maximum Points</p>
|
1238 |
+
<p>Subtotal = Sum of all category scores</p>
|
1239 |
+
<p>Final Score = Subtotal × Penalty Factor (if applicable)</p>
|
1240 |
+
<h4>Penalty Structure:</h4>
|
1241 |
+
<p><strong>Critical Fields Missing:</strong></p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1242 |
<ul>
|
1243 |
+
<li>0-1 missing: No penalty</li>
|
1244 |
+
<li>2-3 missing: 10% penalty (×0.9)</li>
|
1245 |
+
<li>4+ missing: 20% penalty (×0.8)</li>
|
1246 |
</ul>
|
1247 |
|
1248 |
+
<p><strong>Important Fields Missing:</strong></p>
|
1249 |
<ul>
|
1250 |
+
<li>0-4 missing: No penalty</li>
|
1251 |
+
<li>5+ missing: 5% penalty (×0.95)</li>
|
|
|
1252 |
</ul>
|
1253 |
|
1254 |
+
<p><strong>Note:</strong> Penalties are cumulative and applied to the subtotal. For example, if you have 3 critical fields missing AND 5 important fields missing, both penalties apply: Subtotal × 0.9 × 0.95 = Final Score.</p>
|
1255 |
+
|
1256 |
+
</div>
|
1257 |
+
|
1258 |
+
<!-- Specific Breakdown for This SBOM -->
|
1259 |
+
<div class="note-box">
|
1260 |
+
<h4>Your AI SBOM Breakdown</h4>
|
1261 |
+
<p><strong>Model:</strong> {{ model_id }}</p>
|
1262 |
+
|
1263 |
+
<table class="score-table">
|
1264 |
+
<thead>
|
1265 |
+
<tr>
|
1266 |
+
<th>Category</th>
|
1267 |
+
<th>Fields Present</th>
|
1268 |
+
<th>Score</th>
|
1269 |
+
<th>Progress</th>
|
1270 |
+
</tr>
|
1271 |
+
</thead>
|
1272 |
+
<tbody>
|
1273 |
+
{% if completeness_score.category_details and completeness_score.section_scores %}
|
1274 |
+
{% set categories = [
|
1275 |
+
('Required Fields', 'required_fields', 20),
|
1276 |
+
('Metadata', 'metadata', 20),
|
1277 |
+
('Component Basic', 'component_basic', 20),
|
1278 |
+
('Model Card', 'component_model_card', 30),
|
1279 |
+
('External References', 'external_references', 10)
|
1280 |
+
] %}
|
1281 |
+
{% for display_name, key, max_score in categories %}
|
1282 |
+
<tr>
|
1283 |
+
<td>{{ display_name }}</td>
|
1284 |
+
<td>{{ completeness_score.category_details[key].present_fields }}/{{ completeness_score.category_details[key].total_fields }}</td>
|
1285 |
+
<td>{{ completeness_score.section_scores[key]|round(1) }}/{{ max_score }}</td>
|
1286 |
+
<td>
|
1287 |
+
<div class="progress-container">
|
1288 |
+
{% set percentage = completeness_score.category_details[key].percentage %}
|
1289 |
+
{% if percentage >= 80 %}
|
1290 |
+
{% set progress_class = "progress-excellent" %}
|
1291 |
+
{% elif percentage >= 60 %}
|
1292 |
+
{% set progress_class = "progress-good" %}
|
1293 |
+
{% elif percentage >= 40 %}
|
1294 |
+
{% set progress_class = "progress-fair" %}
|
1295 |
+
{% else %}
|
1296 |
+
{% set progress_class = "progress-poor" %}
|
1297 |
+
{% endif %}
|
1298 |
+
<div class="progress-bar {{ progress_class }}" style="width: {{ percentage }}%">{{ percentage|round(0) }}%</div>
|
1299 |
+
</div>
|
1300 |
+
</td>
|
1301 |
+
</tr>
|
1302 |
+
{% endfor %}
|
1303 |
+
{% else %}
|
1304 |
+
<tr><td colspan="4">Breakdown data not available</td></tr>
|
1305 |
+
{% endif %}
|
1306 |
+
</tbody>
|
1307 |
+
</table>
|
1308 |
+
</div>
|
1309 |
+
|
1310 |
+
|
1311 |
+
<p><strong>Calculation:</strong></p>
|
1312 |
+
<p>Subtotal:
|
1313 |
+
{% if completeness_score.section_scores %}
|
1314 |
+
{% for category, score in completeness_score.section_scores.items() %}
|
1315 |
+
{{ score|round(1) }}{% if not loop.last %} + {% endif %}
|
1316 |
+
{% endfor %}
|
1317 |
+
= <strong>{{ completeness_score.subtotal_score|round(1) }}/100</strong>
|
1318 |
+
{% else %}
|
1319 |
+
<strong>{{ completeness_score.subtotal_score|round(1) }}/100</strong>
|
1320 |
+
{% endif %}
|
1321 |
+
</p>
|
1322 |
+
|
1323 |
+
{% if completeness_score.penalty_applied %}
|
1324 |
+
<p>Penalty Applied: <strong>-{{ completeness_score.penalty_percentage }}%</strong> ({{ completeness_score.penalty_reason }})</p>
|
1325 |
+
<p>Final Score: {{ completeness_score.subtotal_score|round(1) }} × {{ completeness_score.penalty_factor }} = <strong>{{ completeness_score.total_score|round(1) }}/100</strong></p>
|
1326 |
+
{% else %}
|
1327 |
+
<p>No penalties applied</p>
|
1328 |
+
<p>Final Score: <strong>{{ completeness_score.total_score|round(1) }}/100</strong></p>
|
1329 |
+
{% endif %}
|
1330 |
+
</div>
|
1331 |
+
|
1332 |
+
<!-- Missing Fields Analysis -->
|
1333 |
+
{% if completeness_score.missing_counts %}
|
1334 |
+
<div class="missing-fields">
|
1335 |
+
<h4>Missing Fields Summary</h4>
|
1336 |
<ul>
|
1337 |
+
<li><strong>Critical:</strong> {{ completeness_score.missing_counts.critical }} missing</li>
|
1338 |
+
<li><strong>Important:</strong> {{ completeness_score.missing_counts.important }} missing</li>
|
1339 |
+
<li><strong>Supplementary:</strong> {{ completeness_score.missing_counts.supplementary }} missing</li>
|
1340 |
</ul>
|
1341 |
+
|
1342 |
+
{% if completeness_score.missing_counts.important >= 5 %}
|
1343 |
+
<p><strong>Impact:</strong> Missing multiple critical and/or important fields will incur penalties according to the Penalty Structure.</p>
|
1344 |
{% endif %}
|
1345 |
</div>
|
1346 |
+
{% endif %}
|
1347 |
+
|
1348 |
+
<!-- Recommendations -->
|
1349 |
+
{% if completeness_score.recommendations %}
|
1350 |
+
<div class="recommendations">
|
1351 |
+
<h4>General Recommendations to Improve AI SBOM Completeness</h4>
|
1352 |
+
<ul>
|
1353 |
+
<li><strong>Required Fields:</strong> Ensure the model is published with a clear name, version, and hosting platform information to allow proper SBOM structuring.</li>
|
1354 |
+
<li><strong>Metadata:</strong> Include author or organization name, purpose of the model, and relevant timestamps in the model repository or card.</li>
|
1355 |
+
<li><strong>Component Basic:</strong> Provide a descriptive model title, a meaningful description, a valid license, and a consistent version reference (e.g., tags or commits).</li>
|
1356 |
+
<li><strong>Model Card:</strong> Fill out structured sections for model parameters, evaluation metrics, limitations, and ethical considerations to enable full transparency.</li>
|
1357 |
+
<li><strong>External References:</strong> Add links to source code, datasets, documentation, and versioned download locations to support traceability and reproducibility.</li>
|
1358 |
+
</ul>
|
1359 |
+
</div>
|
1360 |
+
{% endif %}
|
1361 |
+
</div>
|
1362 |
+
</div>
|
1363 |
+
|
1364 |
+
<!-- JSON View Tab -->
|
1365 |
+
<div id="json-view" class="tab-content">
|
1366 |
+
<div class="content-section">
|
1367 |
+
<h3>📄 Raw JSON View</h3>
|
1368 |
+
<p>This is the complete AI SBOM in CycloneDX JSON format:</p>
|
1369 |
+
<div class="json-view">
|
1370 |
+
<pre>{{ aibom|tojson(indent=2) }}</pre>
|
1371 |
+
</div>
|
1372 |
</div>
|
1373 |
</div>
|
1374 |
</div>
|
1375 |
|
1376 |
+
<!-- Support Section -->
|
1377 |
+
<div class="support-section">
|
1378 |
+
<h3>🛠️ Need Help or Found an Issue?</h3>
|
1379 |
+
<p>If you encountered any problems, found a bug, or have suggestions for improvement, we'd love to hear from you!</p>
|
1380 |
+
<a href="https://github.com/aetheris-ai/aibom-generator/issues" target="_blank" class="github-button">
|
1381 |
+
Report Issue on GitHub
|
1382 |
+
</a>
|
1383 |
+
</div>
|
1384 |
+
|
1385 |
+
<!-- Help us spread the word section -->
|
1386 |
<div class="content-section" style="text-align: center;">
|
1387 |
<h3>🗣️ Help Us Spread the Word</h3>
|
1388 |
<p>If you find this tool useful, share it with your network! <a href="https://sbom.aetheris.ai" target="_blank" rel="noopener noreferrer">https://sbom.aetheris.ai</a></p>
|
|
|
1395 |
</p>
|
1396 |
</div>
|
1397 |
|
1398 |
+
<!-- Info Section -->
|
1399 |
+
<div class="content-section" style="text-align: center;">
|
1400 |
<!-- Display the SBOM count -->
|
1401 |
<div class="sbom-count">🚀 Generated AI SBOMs using this tool: <strong>{{ sbom_count if sbom_count else 'N/A' }}</strong></div>
|
1402 |
</div>
|
1403 |
+
|
1404 |
<!-- Footer -->
|
1405 |
<div class="footer">
|
1406 |
<p>© 2025 AI SBOM Generator | Powered by Aetheris AI</p>
|
1407 |
</div>
|
1408 |
+
</div>
|
1409 |
|
1410 |
<script>
|
1411 |
function switchTab(tabId) {
|
|
|
1458 |
});
|
1459 |
</script>
|
1460 |
</body>
|
1461 |
+
</html>
|
1462 |
+
|