Spaces:
Running
Running
Update templates/result.html
Browse files- templates/result.html +628 -536
templates/result.html
CHANGED
@@ -4,38 +4,14 @@
|
|
4 |
<meta charset="UTF-8">
|
5 |
<title>AI SBOM Generated</title>
|
6 |
<style>
|
7 |
-
body { font-family: Arial, sans-serif; margin:
|
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 |
-
.
|
35 |
-
.
|
36 |
-
.
|
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; }
|
@@ -152,9 +128,6 @@
|
|
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 */
|
@@ -192,7 +165,18 @@
|
|
192 |
color: white;
|
193 |
font-size: 0.8em;
|
194 |
margin-left: 5px;
|
195 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
196 |
}
|
197 |
.total-score-container {
|
198 |
display: flex;
|
@@ -206,6 +190,7 @@
|
|
206 |
}
|
207 |
.total-progress {
|
208 |
flex: 1;
|
|
|
209 |
}
|
210 |
|
211 |
/* New styles for improved user understanding */
|
@@ -382,575 +367,682 @@
|
|
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 |
-
|
407 |
-
<
|
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="
|
417 |
-
<
|
418 |
-
|
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 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
452 |
<div class="aibom-property">
|
453 |
-
<div class="property-name">Model
|
454 |
-
<div class="property-value">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
455 |
</div>
|
|
|
|
|
|
|
456 |
<div class="aibom-property">
|
457 |
-
<div class="property-name">
|
458 |
-
<div class="property-value">
|
|
|
|
|
|
|
|
|
|
|
|
|
459 |
</div>
|
|
|
|
|
|
|
460 |
<div class="aibom-property">
|
461 |
-
<div class="property-name">
|
462 |
-
<div class="property-value">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
463 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
464 |
<div class="aibom-property">
|
465 |
-
<div class="property-name">
|
466 |
-
<div class="property-value">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
467 |
</div>
|
468 |
-
{%
|
|
|
|
|
469 |
<div class="aibom-property">
|
470 |
-
<div class="property-name">
|
471 |
-
<div class="property-value">{{ aibom.components[0].
|
472 |
</div>
|
473 |
{% endif %}
|
474 |
</div>
|
|
|
|
|
475 |
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
|
495 |
-
{% endfor %}
|
496 |
-
</ul>
|
497 |
-
{% endif %}
|
498 |
-
</div>
|
499 |
-
</div>
|
500 |
-
{% endif %}
|
501 |
-
|
502 |
-
{% if aibom.components[0].modelCard.considerations %}
|
503 |
-
<div class="aibom-property">
|
504 |
-
<div class="property-name">Considerations:</div>
|
505 |
-
<div class="property-value">
|
506 |
-
<ul>
|
507 |
-
{% for key, value in aibom.components[0].modelCard.considerations.items() %}
|
508 |
-
<li><strong>{{ key }}:</strong> {{ value }}</li>
|
509 |
-
{% endfor %}
|
510 |
-
</ul>
|
511 |
-
</div>
|
512 |
</div>
|
513 |
-
{% endif %}
|
514 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
515 |
</div>
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
<
|
530 |
-
{% endif %}
|
531 |
-
</li>
|
532 |
{% endfor %}
|
533 |
-
</
|
534 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
535 |
</div>
|
536 |
-
{% endif %}
|
537 |
</div>
|
538 |
-
|
539 |
|
540 |
-
|
541 |
-
|
542 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
543 |
</div>
|
544 |
-
|
545 |
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
<
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
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 |
-
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
|
626 |
-
|
627 |
-
<
|
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 |
-
|
635 |
-
|
636 |
-
|
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 |
-
|
664 |
-
|
665 |
-
<div class="validation-penalty-info">
|
666 |
-
<h4>About the Validation Penalty</h4>
|
667 |
-
<p>Your score includes a penalty because the AI SBOM 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
671 |
|
672 |
-
<!--
|
673 |
-
<
|
674 |
-
<
|
675 |
-
|
676 |
-
|
677 |
-
|
678 |
-
|
679 |
-
|
680 |
-
|
681 |
-
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
-
|
686 |
-
|
687 |
-
|
688 |
-
|
689 |
-
|
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 |
-
<!--
|
732 |
-
<
|
733 |
-
<
|
734 |
-
|
735 |
-
|
736 |
-
|
737 |
-
|
738 |
-
|
739 |
-
|
740 |
-
|
741 |
-
|
742 |
-
|
743 |
-
|
744 |
-
|
745 |
-
|
746 |
-
|
747 |
-
|
748 |
-
|
749 |
-
|
750 |
-
|
751 |
-
|
752 |
-
|
753 |
-
|
754 |
-
|
755 |
-
|
756 |
-
|
757 |
-
|
758 |
-
|
759 |
-
|
760 |
-
|
761 |
-
|
762 |
-
|
763 |
-
|
764 |
-
|
765 |
-
|
766 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
767 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
768 |
|
769 |
-
|
770 |
-
<
|
771 |
-
|
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 |
-
|
869 |
-
<
|
870 |
-
|
871 |
-
|
872 |
-
|
873 |
-
|
874 |
-
|
875 |
-
|
876 |
-
|
877 |
-
|
878 |
-
|
879 |
-
|
880 |
-
|
881 |
-
|
882 |
-
|
883 |
-
|
884 |
-
|
885 |
-
|
886 |
-
|
887 |
-
|
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>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
906 |
function switchTab(tabId) {
|
907 |
// Hide all tab contents
|
908 |
-
|
909 |
-
for (
|
910 |
tabContents[i].classList.remove('active');
|
911 |
}
|
912 |
|
913 |
// Deactivate all tabs
|
914 |
-
|
915 |
-
for (
|
916 |
tabs[i].classList.remove('active');
|
917 |
}
|
918 |
|
919 |
// Activate the selected tab and content
|
920 |
document.getElementById(tabId).classList.add('active');
|
921 |
-
|
922 |
-
selectedTab.classList.add('active');
|
923 |
}
|
924 |
|
925 |
function toggleCollapsible(element) {
|
926 |
element.classList.toggle('active');
|
927 |
-
|
928 |
-
content.classList.toggle('active');
|
929 |
-
|
930 |
if (content.classList.contains('active')) {
|
931 |
-
content.
|
932 |
} else {
|
933 |
-
content.
|
934 |
}
|
935 |
}
|
936 |
-
|
937 |
-
function downloadJSON() {
|
938 |
-
var dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify({{ aibom|tojson }}, null, 2));
|
939 |
-
var downloadAnchorNode = document.createElement('a');
|
940 |
-
downloadAnchorNode.setAttribute("href", dataStr);
|
941 |
-
downloadAnchorNode.setAttribute("download", "{{ model_id|replace('/', '_') }}_aibom.json");
|
942 |
-
document.body.appendChild(downloadAnchorNode);
|
943 |
-
downloadAnchorNode.click();
|
944 |
-
downloadAnchorNode.remove();
|
945 |
-
}
|
946 |
-
|
947 |
-
// Initialize collapsible sections
|
948 |
-
document.addEventListener('DOMContentLoaded', function() {
|
949 |
-
var collapsibles = document.getElementsByClassName('collapsible');
|
950 |
-
for (var i = 0; i < collapsibles.length; i++) {
|
951 |
-
toggleCollapsible(collapsibles[i]);
|
952 |
-
}
|
953 |
-
});
|
954 |
</script>
|
955 |
</body>
|
956 |
</html>
|
|
|
4 |
<meta charset="UTF-8">
|
5 |
<title>AI SBOM Generated</title>
|
6 |
<style>
|
7 |
+
body { font-family: Arial, sans-serif; margin: 20px; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
table { border-collapse: collapse; width: 60%; margin-top: 15px; }
|
9 |
th, td { border: 1px solid #ddd; padding: 8px; }
|
10 |
th { background-color: #f4f4f4; }
|
|
|
11 |
/* Fixed color styling for field checklist items */
|
12 |
+
.missing { color: #e74c3c; } /* Red color for missing fields */
|
13 |
+
.present { color: #27ae60; } /* Green color for present fields */
|
14 |
+
.unknown { color: #f39c12; } /* Orange color for unknown status */
|
|
|
|
|
15 |
.improvement { color: #2c3e50; background-color: #ecf0f1; padding: 15px; border-radius: 5px; margin-bottom: 20px; }
|
16 |
.improvement-value { color: #27ae60; font-weight: bold; }
|
17 |
.ai-badge { background-color: #3498db; color: white; padding: 3px 8px; border-radius: 3px; font-size: 0.8em; margin-left: 10px; }
|
|
|
128 |
line-height: 20px;
|
129 |
color: white;
|
130 |
font-size: 12px;
|
|
|
|
|
|
|
131 |
}
|
132 |
.progress-excellent {
|
133 |
background-color: #4CAF50; /* Green */
|
|
|
165 |
color: white;
|
166 |
font-size: 0.8em;
|
167 |
margin-left: 5px;
|
168 |
+
}
|
169 |
+
.label-excellent {
|
170 |
+
background-color: #4CAF50;
|
171 |
+
}
|
172 |
+
.label-good {
|
173 |
+
background-color: #2196F3;
|
174 |
+
}
|
175 |
+
.label-fair {
|
176 |
+
background-color: #FF9800;
|
177 |
+
}
|
178 |
+
.label-poor {
|
179 |
+
background-color: #f44336;
|
180 |
}
|
181 |
.total-score-container {
|
182 |
display: flex;
|
|
|
190 |
}
|
191 |
.total-progress {
|
192 |
flex: 1;
|
193 |
+
max-width: 300px;
|
194 |
}
|
195 |
|
196 |
/* New styles for improved user understanding */
|
|
|
367 |
margin-top: 0;
|
368 |
color: #e65100;
|
369 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
370 |
</style>
|
371 |
</head>
|
372 |
<body>
|
373 |
+
<a href="/">Generate another AI SBOM</a>
|
374 |
+
<h2>AI SBOM Generated for {{ model_id }}</h2>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
375 |
|
376 |
+
<div class="download-section">
|
377 |
+
<p>Download generated AI SBOM in CycloneDX format <button onclick="downloadJSON()">Download JSON</button></p>
|
378 |
+
</div>
|
|
|
|
|
|
|
|
|
379 |
|
380 |
+
{% if enhancement_report and enhancement_report.ai_enhanced %}
|
381 |
+
<div class="improvement">
|
382 |
+
<h3>AI Enhancement Results</h3>
|
383 |
+
<p>This AI SBOM was enhanced using <strong>{{ enhancement_report.ai_model }}</strong></p>
|
384 |
+
<p>Original Score: {{ enhancement_report.original_score.total_score|default(0)|round(1) }}/100</p>
|
385 |
+
<p>Enhanced Score: {{ enhancement_report.final_score.total_score|default(0)|round(1) }}/100</p>
|
386 |
+
<p>Improvement: <span class="improvement-value">+{{ enhancement_report.improvement|default(0)|round(1) }} points</span></p>
|
387 |
+
</div>
|
388 |
+
{% endif %}
|
389 |
|
390 |
+
<!-- Human-friendly AI SBOM Viewer -->
|
391 |
+
<div class="note-box">
|
392 |
+
<p><strong>Note:</strong> This page displays the AI SBOM in a human-friendly format for easier readability.
|
393 |
+
The downloaded JSON file follows the standard CycloneDX format required for interoperability with other tools.</p>
|
394 |
+
</div>
|
395 |
+
|
396 |
+
<div class="aibom-tabs">
|
397 |
+
<div class="aibom-tab active" onclick="switchTab('human-view')">Human-Friendly View</div>
|
398 |
+
<div class="aibom-tab" onclick="switchTab('json-view')">JSON View</div>
|
399 |
+
<div class="aibom-tab" onclick="switchTab('field-checklist')">Field Checklist</div>
|
400 |
+
<div class="aibom-tab" onclick="switchTab('score-view')">Score Report</div>
|
401 |
+
</div>
|
402 |
|
403 |
+
<div id="human-view" class="tab-content active">
|
404 |
+
<div class="aibom-viewer">
|
405 |
+
<!-- Key Information Section -->
|
406 |
+
<div class="aibom-section key-info">
|
407 |
+
<h4>Key Information</h4>
|
408 |
+
<div class="aibom-property">
|
409 |
+
<div class="property-name">Model Name:</div>
|
410 |
+
<div class="property-value">{{ aibom.components[0].name if aibom.components and aibom.components[0].name else 'Not specified' }}</div>
|
411 |
+
</div>
|
412 |
+
<div class="aibom-property">
|
413 |
+
<div class="property-name">Type:</div>
|
414 |
+
<div class="property-value">{{ aibom.components[0].type if aibom.components and aibom.components[0].type else 'Not specified' }}</div>
|
415 |
+
</div>
|
416 |
+
<div class="aibom-property">
|
417 |
+
<div class="property-name">Version:</div>
|
418 |
+
<div class="property-value">{{ aibom.components[0].version if aibom.components and aibom.components[0].version else 'Not specified' }}</div>
|
419 |
+
</div>
|
420 |
+
<div class="aibom-property">
|
421 |
+
<div class="property-name">PURL:</div>
|
422 |
+
<div class="property-value">{{ aibom.components[0].purl if aibom.components and aibom.components[0].purl else 'Not specified' }}</div>
|
423 |
+
</div>
|
424 |
+
{% if aibom.components and aibom.components[0].description %}
|
425 |
+
<div class="aibom-property">
|
426 |
+
<div class="property-name">Description:</div>
|
427 |
+
<div class="property-value">{{ aibom.components[0].description }}</div>
|
428 |
+
</div>
|
429 |
+
{% endif %}
|
430 |
+
</div>
|
431 |
+
|
432 |
+
<!-- Model Card Section -->
|
433 |
+
{% if aibom.components and aibom.components[0].modelCard %}
|
434 |
+
<div class="aibom-section">
|
435 |
+
<h4 class="collapsible" onclick="toggleCollapsible(this)">Model Card</h4>
|
436 |
+
<div class="collapsible-content">
|
437 |
+
{% if aibom.components[0].modelCard.modelParameters %}
|
438 |
<div class="aibom-property">
|
439 |
+
<div class="property-name">Model Parameters:</div>
|
440 |
+
<div class="property-value">
|
441 |
+
{% if aibom.components[0].modelCard.modelParameters.properties %}
|
442 |
+
{% for prop in aibom.components[0].modelCard.modelParameters.properties %}
|
443 |
+
<div><strong>{{ prop.name }}:</strong> {{ prop.value }}</div>
|
444 |
+
{% endfor %}
|
445 |
+
{% elif aibom.components[0].modelCard.modelParameters.description %}
|
446 |
+
{{ aibom.components[0].modelCard.modelParameters.description }}
|
447 |
+
{% endif %}
|
448 |
+
</div>
|
449 |
</div>
|
450 |
+
{% endif %}
|
451 |
+
|
452 |
+
{% if aibom.components[0].modelCard.quantitativeAnalysis %}
|
453 |
<div class="aibom-property">
|
454 |
+
<div class="property-name">Performance Metrics:</div>
|
455 |
+
<div class="property-value">
|
456 |
+
{% if aibom.components[0].modelCard.quantitativeAnalysis.performanceMetrics %}
|
457 |
+
{% for metric in aibom.components[0].modelCard.quantitativeAnalysis.performanceMetrics %}
|
458 |
+
<div><strong>{{ metric.type if metric.type else 'Metric' }}:</strong> {{ metric.value if metric.value else 'Not specified' }}</div>
|
459 |
+
{% endfor %}
|
460 |
+
{% endif %}
|
461 |
+
</div>
|
462 |
</div>
|
463 |
+
{% endif %}
|
464 |
+
|
465 |
+
{% if aibom.components[0].modelCard.considerations %}
|
466 |
<div class="aibom-property">
|
467 |
+
<div class="property-name">Considerations:</div>
|
468 |
+
<div class="property-value">
|
469 |
+
{% if aibom.components[0].modelCard.considerations.ethicalConsiderations %}
|
470 |
+
<div><strong>Ethical Considerations:</strong> {{ aibom.components[0].modelCard.considerations.ethicalConsiderations }}</div>
|
471 |
+
{% endif %}
|
472 |
+
{% if aibom.components[0].modelCard.considerations.limitations %}
|
473 |
+
<div><strong>Limitations:</strong> {{ aibom.components[0].modelCard.considerations.limitations }}</div>
|
474 |
+
{% endif %}
|
475 |
+
{% if aibom.components[0].modelCard.considerations.tradeoffs %}
|
476 |
+
<div><strong>Tradeoffs:</strong> {{ aibom.components[0].modelCard.considerations.tradeoffs }}</div>
|
477 |
+
{% endif %}
|
478 |
+
</div>
|
479 |
</div>
|
480 |
+
{% endif %}
|
481 |
+
</div>
|
482 |
+
</div>
|
483 |
+
{% endif %}
|
484 |
+
|
485 |
+
<!-- Training Data Section -->
|
486 |
+
{% if aibom.components and aibom.components[0].trainingData %}
|
487 |
+
<div class="aibom-section">
|
488 |
+
<h4 class="collapsible" onclick="toggleCollapsible(this)">Training Data</h4>
|
489 |
+
<div class="collapsible-content">
|
490 |
+
{% if aibom.components[0].trainingData.datasets %}
|
491 |
<div class="aibom-property">
|
492 |
+
<div class="property-name">Datasets:</div>
|
493 |
+
<div class="property-value">
|
494 |
+
{% for dataset in aibom.components[0].trainingData.datasets %}
|
495 |
+
<div>
|
496 |
+
<strong>{{ dataset.name if dataset.name else 'Dataset' }}:</strong>
|
497 |
+
{% if dataset.description %} {{ dataset.description }}{% endif %}
|
498 |
+
{% if dataset.url %} <a href="{{ dataset.url }}" target="_blank">Link</a>{% endif %}
|
499 |
+
</div>
|
500 |
+
{% endfor %}
|
501 |
+
</div>
|
502 |
</div>
|
503 |
+
{% endif %}
|
504 |
+
|
505 |
+
{% if aibom.components[0].trainingData.preprocessing %}
|
506 |
<div class="aibom-property">
|
507 |
+
<div class="property-name">Preprocessing:</div>
|
508 |
+
<div class="property-value">{{ aibom.components[0].trainingData.preprocessing }}</div>
|
509 |
</div>
|
510 |
{% endif %}
|
511 |
</div>
|
512 |
+
</div>
|
513 |
+
{% endif %}
|
514 |
|
515 |
+
<!-- Training Process Section -->
|
516 |
+
{% if aibom.components and aibom.components[0].trainingProcess %}
|
517 |
+
<div class="aibom-section">
|
518 |
+
<h4 class="collapsible" onclick="toggleCollapsible(this)">Training Process</h4>
|
519 |
+
<div class="collapsible-content">
|
520 |
+
{% if aibom.components[0].trainingProcess.trainingMethod %}
|
521 |
+
<div class="aibom-property">
|
522 |
+
<div class="property-name">Training Method:</div>
|
523 |
+
<div class="property-value">{{ aibom.components[0].trainingProcess.trainingMethod }}</div>
|
524 |
+
</div>
|
525 |
+
{% endif %}
|
526 |
+
|
527 |
+
{% if aibom.components[0].trainingProcess.hyperparameters %}
|
528 |
+
<div class="aibom-property">
|
529 |
+
<div class="property-name">Hyperparameters:</div>
|
530 |
+
<div class="property-value">
|
531 |
+
{% for param in aibom.components[0].trainingProcess.hyperparameters %}
|
532 |
+
<div><strong>{{ param.name }}:</strong> {{ param.value }}</div>
|
533 |
+
{% endfor %}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
534 |
</div>
|
|
|
535 |
</div>
|
536 |
+
{% endif %}
|
537 |
+
|
538 |
+
{% if aibom.components[0].trainingProcess.computeInfrastructure %}
|
539 |
+
<div class="aibom-property">
|
540 |
+
<div class="property-name">Compute Infrastructure:</div>
|
541 |
+
<div class="property-value">{{ aibom.components[0].trainingProcess.computeInfrastructure }}</div>
|
542 |
+
</div>
|
543 |
+
{% endif %}
|
544 |
</div>
|
545 |
+
</div>
|
546 |
+
{% endif %}
|
547 |
+
|
548 |
+
<!-- Evaluation Section -->
|
549 |
+
{% if aibom.components and aibom.components[0].evaluation %}
|
550 |
+
<div class="aibom-section">
|
551 |
+
<h4 class="collapsible" onclick="toggleCollapsible(this)">Evaluation</h4>
|
552 |
+
<div class="collapsible-content">
|
553 |
+
{% if aibom.components[0].evaluation.metrics %}
|
554 |
+
<div class="aibom-property">
|
555 |
+
<div class="property-name">Metrics:</div>
|
556 |
+
<div class="property-value">
|
557 |
+
{% for metric in aibom.components[0].evaluation.metrics %}
|
558 |
+
<div><strong>{{ metric.name }}:</strong> {{ metric.value }}</div>
|
|
|
|
|
559 |
{% endfor %}
|
560 |
+
</div>
|
561 |
</div>
|
562 |
+
{% endif %}
|
563 |
+
|
564 |
+
{% if aibom.components[0].evaluation.datasets %}
|
565 |
+
<div class="aibom-property">
|
566 |
+
<div class="property-name">Evaluation Datasets:</div>
|
567 |
+
<div class="property-value">
|
568 |
+
{% for dataset in aibom.components[0].evaluation.datasets %}
|
569 |
+
<div>
|
570 |
+
<strong>{{ dataset.name if dataset.name else 'Dataset' }}:</strong>
|
571 |
+
{% if dataset.description %} {{ dataset.description }}{% endif %}
|
572 |
+
{% if dataset.url %} <a href="{{ dataset.url }}" target="_blank">Link</a>{% endif %}
|
573 |
+
</div>
|
574 |
+
{% endfor %}
|
575 |
+
</div>
|
576 |
+
</div>
|
577 |
+
{% endif %}
|
578 |
</div>
|
|
|
579 |
</div>
|
580 |
+
{% endif %}
|
581 |
|
582 |
+
<!-- Usage Section -->
|
583 |
+
{% if aibom.components and aibom.components[0].usage %}
|
584 |
+
<div class="aibom-section">
|
585 |
+
<h4 class="collapsible" onclick="toggleCollapsible(this)">Usage</h4>
|
586 |
+
<div class="collapsible-content">
|
587 |
+
{% if aibom.components[0].usage.intendedUse %}
|
588 |
+
<div class="aibom-property">
|
589 |
+
<div class="property-name">Intended Use:</div>
|
590 |
+
<div class="property-value">{{ aibom.components[0].usage.intendedUse }}</div>
|
591 |
+
</div>
|
592 |
+
{% endif %}
|
593 |
+
|
594 |
+
{% if aibom.components[0].usage.outOfScopeUses %}
|
595 |
+
<div class="aibom-property">
|
596 |
+
<div class="property-name">Out of Scope Uses:</div>
|
597 |
+
<div class="property-value">{{ aibom.components[0].usage.outOfScopeUses }}</div>
|
598 |
+
</div>
|
599 |
+
{% endif %}
|
600 |
+
|
601 |
+
{% if aibom.components[0].usage.guidelines %}
|
602 |
+
<div class="aibom-property">
|
603 |
+
<div class="property-name">Usage Guidelines:</div>
|
604 |
+
<div class="property-value">{{ aibom.components[0].usage.guidelines }}</div>
|
605 |
+
</div>
|
606 |
+
{% endif %}
|
607 |
+
</div>
|
608 |
</div>
|
609 |
+
{% endif %}
|
610 |
|
611 |
+
<!-- Licenses Section -->
|
612 |
+
{% if aibom.components and aibom.components[0].licenses %}
|
613 |
+
<div class="aibom-section">
|
614 |
+
<h4 class="collapsible" onclick="toggleCollapsible(this)">Licenses</h4>
|
615 |
+
<div class="collapsible-content">
|
616 |
+
{% for license in aibom.components[0].licenses %}
|
617 |
+
<div class="aibom-property">
|
618 |
+
<div class="property-name">License:</div>
|
619 |
+
<div class="property-value">
|
620 |
+
<strong>{{ license.name }}</strong>
|
621 |
+
{% if license.url %} <a href="{{ license.url }}" target="_blank">Link</a>{% endif %}
|
622 |
+
</div>
|
623 |
+
</div>
|
624 |
+
{% endfor %}
|
|
|
|
|
625 |
</div>
|
626 |
</div>
|
627 |
+
{% endif %}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
628 |
</div>
|
629 |
+
</div>
|
630 |
|
631 |
+
<div id="json-view" class="tab-content">
|
632 |
+
<div class="json-view">
|
633 |
+
<pre>{{ aibom|tojson(indent=2) }}</pre>
|
634 |
+
</div>
|
635 |
+
</div>
|
636 |
+
|
637 |
+
<div id="field-checklist" class="tab-content">
|
638 |
+
<h3>AI SBOM Field Completeness</h3>
|
639 |
+
|
640 |
+
<div class="tier-legend">
|
641 |
+
<div class="tier-legend-item">
|
642 |
+
<div class="field-tier tier-critical"></div>
|
643 |
+
<span>Critical Fields</span>
|
|
|
|
|
|
|
|
|
644 |
</div>
|
645 |
+
<div class="tier-legend-item">
|
646 |
+
<div class="field-tier tier-important"></div>
|
647 |
+
<span>Important Fields</span>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
648 |
</div>
|
649 |
+
<div class="tier-legend-item">
|
650 |
+
<div class="field-tier tier-supplementary"></div>
|
651 |
+
<span>Supplementary Fields</span>
|
|
|
|
|
|
|
|
|
652 |
</div>
|
653 |
+
</div>
|
654 |
+
|
655 |
+
<table>
|
656 |
+
<tr>
|
657 |
+
<th>Field</th>
|
658 |
+
<th>Status</th>
|
659 |
+
</tr>
|
660 |
+
<!-- Basic Information -->
|
661 |
+
<tr>
|
662 |
+
<td><div class="field-tier tier-critical"></div> Model Name</td>
|
663 |
+
<td class="{{ 'present' if aibom.components and aibom.components[0].name else 'missing' }}">
|
664 |
+
{{ 'Present' if aibom.components and aibom.components[0].name else 'Missing' }}
|
665 |
+
</td>
|
666 |
+
</tr>
|
667 |
+
<tr>
|
668 |
+
<td><div class="field-tier tier-critical"></div> Model Type</td>
|
669 |
+
<td class="{{ 'present' if aibom.components and aibom.components[0].type else 'missing' }}">
|
670 |
+
{{ 'Present' if aibom.components and aibom.components[0].type else 'Missing' }}
|
671 |
+
</td>
|
672 |
+
</tr>
|
673 |
+
<tr>
|
674 |
+
<td><div class="field-tier tier-critical"></div> Model Version</td>
|
675 |
+
<td class="{{ 'present' if aibom.components and aibom.components[0].version else 'missing' }}">
|
676 |
+
{{ 'Present' if aibom.components and aibom.components[0].version else 'Missing' }}
|
677 |
+
</td>
|
678 |
+
</tr>
|
679 |
+
<tr>
|
680 |
+
<td><div class="field-tier tier-important"></div> Model Description</td>
|
681 |
+
<td class="{{ 'present' if aibom.components and aibom.components[0].description else 'missing' }}">
|
682 |
+
{{ 'Present' if aibom.components and aibom.components[0].description else 'Missing' }}
|
683 |
+
</td>
|
684 |
+
</tr>
|
685 |
|
686 |
+
<!-- Model Card -->
|
687 |
+
<tr>
|
688 |
+
<td><div class="field-tier tier-important"></div> Model Parameters</td>
|
689 |
+
<td class="{{ 'present' if aibom.components and aibom.components[0].modelCard and aibom.components[0].modelCard.modelParameters else 'missing' }}">
|
690 |
+
{{ 'Present' if aibom.components and aibom.components[0].modelCard and aibom.components[0].modelCard.modelParameters else 'Missing' }}
|
691 |
+
</td>
|
692 |
+
</tr>
|
693 |
+
<tr>
|
694 |
+
<td><div class="field-tier tier-important"></div> Performance Metrics</td>
|
695 |
+
<td class="{{ 'present' if aibom.components and aibom.components[0].modelCard and aibom.components[0].modelCard.quantitativeAnalysis and aibom.components[0].modelCard.quantitativeAnalysis.performanceMetrics else 'missing' }}">
|
696 |
+
{{ 'Present' if aibom.components and aibom.components[0].modelCard and aibom.components[0].modelCard.quantitativeAnalysis and aibom.components[0].modelCard.quantitativeAnalysis.performanceMetrics else 'Missing' }}
|
697 |
+
</td>
|
698 |
+
</tr>
|
699 |
+
<tr>
|
700 |
+
<td><div class="field-tier tier-supplementary"></div> Ethical Considerations</td>
|
701 |
+
<td class="{{ 'present' if aibom.components and aibom.components[0].modelCard and aibom.components[0].modelCard.considerations and aibom.components[0].modelCard.considerations.ethicalConsiderations else 'missing' }}">
|
702 |
+
{{ 'Present' if aibom.components and aibom.components[0].modelCard and aibom.components[0].modelCard.considerations and aibom.components[0].modelCard.considerations.ethicalConsiderations else 'Missing' }}
|
703 |
+
</td>
|
704 |
+
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
705 |
|
706 |
+
<!-- Training Data -->
|
707 |
+
<tr>
|
708 |
+
<td><div class="field-tier tier-critical"></div> Training Datasets</td>
|
709 |
+
<td class="{{ 'present' if aibom.components and aibom.components[0].trainingData and aibom.components[0].trainingData.datasets else 'missing' }}">
|
710 |
+
{{ 'Present' if aibom.components and aibom.components[0].trainingData and aibom.components[0].trainingData.datasets else 'Missing' }}
|
711 |
+
</td>
|
712 |
+
</tr>
|
713 |
+
<tr>
|
714 |
+
<td><div class="field-tier tier-important"></div> Data Preprocessing</td>
|
715 |
+
<td class="{{ 'present' if aibom.components and aibom.components[0].trainingData and aibom.components[0].trainingData.preprocessing else 'missing' }}">
|
716 |
+
{{ 'Present' if aibom.components and aibom.components[0].trainingData and aibom.components[0].trainingData.preprocessing else 'Missing' }}
|
717 |
+
</td>
|
718 |
+
</tr>
|
719 |
+
|
720 |
+
<!-- Training Process -->
|
721 |
+
<tr>
|
722 |
+
<td><div class="field-tier tier-important"></div> Training Method</td>
|
723 |
+
<td class="{{ 'present' if aibom.components and aibom.components[0].trainingProcess and aibom.components[0].trainingProcess.trainingMethod else 'missing' }}">
|
724 |
+
{{ 'Present' if aibom.components and aibom.components[0].trainingProcess and aibom.components[0].trainingProcess.trainingMethod else 'Missing' }}
|
725 |
+
</td>
|
726 |
+
</tr>
|
727 |
+
<tr>
|
728 |
+
<td><div class="field-tier tier-important"></div> Hyperparameters</td>
|
729 |
+
<td class="{{ 'present' if aibom.components and aibom.components[0].trainingProcess and aibom.components[0].trainingProcess.hyperparameters else 'missing' }}">
|
730 |
+
{{ 'Present' if aibom.components and aibom.components[0].trainingProcess and aibom.components[0].trainingProcess.hyperparameters else 'Missing' }}
|
731 |
+
</td>
|
732 |
+
</tr>
|
733 |
+
<tr>
|
734 |
+
<td><div class="field-tier tier-supplementary"></div> Compute Infrastructure</td>
|
735 |
+
<td class="{{ 'present' if aibom.components and aibom.components[0].trainingProcess and aibom.components[0].trainingProcess.computeInfrastructure else 'missing' }}">
|
736 |
+
{{ 'Present' if aibom.components and aibom.components[0].trainingProcess and aibom.components[0].trainingProcess.computeInfrastructure else 'Missing' }}
|
737 |
+
</td>
|
738 |
+
</tr>
|
739 |
+
|
740 |
+
<!-- Evaluation -->
|
741 |
+
<tr>
|
742 |
+
<td><div class="field-tier tier-important"></div> Evaluation Metrics</td>
|
743 |
+
<td class="{{ 'present' if aibom.components and aibom.components[0].evaluation and aibom.components[0].evaluation.metrics else 'missing' }}">
|
744 |
+
{{ 'Present' if aibom.components and aibom.components[0].evaluation and aibom.components[0].evaluation.metrics else 'Missing' }}
|
745 |
+
</td>
|
746 |
+
</tr>
|
747 |
+
<tr>
|
748 |
+
<td><div class="field-tier tier-important"></div> Evaluation Datasets</td>
|
749 |
+
<td class="{{ 'present' if aibom.components and aibom.components[0].evaluation and aibom.components[0].evaluation.datasets else 'missing' }}">
|
750 |
+
{{ 'Present' if aibom.components and aibom.components[0].evaluation and aibom.components[0].evaluation.datasets else 'Missing' }}
|
751 |
+
</td>
|
752 |
+
</tr>
|
753 |
+
|
754 |
+
<!-- Usage -->
|
755 |
+
<tr>
|
756 |
+
<td><div class="field-tier tier-important"></div> Intended Use</td>
|
757 |
+
<td class="{{ 'present' if aibom.components and aibom.components[0].usage and aibom.components[0].usage.intendedUse else 'missing' }}">
|
758 |
+
{{ 'Present' if aibom.components and aibom.components[0].usage and aibom.components[0].usage.intendedUse else 'Missing' }}
|
759 |
+
</td>
|
760 |
+
</tr>
|
761 |
+
<tr>
|
762 |
+
<td><div class="field-tier tier-supplementary"></div> Out of Scope Uses</td>
|
763 |
+
<td class="{{ 'present' if aibom.components and aibom.components[0].usage and aibom.components[0].usage.outOfScopeUses else 'missing' }}">
|
764 |
+
{{ 'Present' if aibom.components and aibom.components[0].usage and aibom.components[0].usage.outOfScopeUses else 'Missing' }}
|
765 |
+
</td>
|
766 |
+
</tr>
|
767 |
+
|
768 |
+
<!-- Licenses -->
|
769 |
+
<tr>
|
770 |
+
<td><div class="field-tier tier-critical"></div> Licenses</td>
|
771 |
+
<td class="{{ 'present' if aibom.components and aibom.components[0].licenses else 'missing' }}">
|
772 |
+
{{ 'Present' if aibom.components and aibom.components[0].licenses else 'Missing' }}
|
773 |
+
</td>
|
774 |
+
</tr>
|
775 |
+
</table>
|
776 |
+
</div>
|
777 |
+
|
778 |
+
<div id="score-view" class="tab-content">
|
779 |
+
<h3>AI SBOM Completeness Score</h3>
|
780 |
+
|
781 |
+
<div class="total-score-container">
|
782 |
+
<div class="total-score">{{ enhancement_report.final_score.total_score|default(0)|round(1) }}/100</div>
|
783 |
+
<div class="total-progress">
|
784 |
+
<div class="progress-container">
|
785 |
+
{% set score = enhancement_report.final_score.total_score|default(0) %}
|
786 |
+
<div class="progress-bar
|
787 |
+
{{- ' progress-excellent' if score >= 80 -}}
|
788 |
+
{{- ' progress-good' if score >= 60 and score < 80 -}}
|
789 |
+
{{- ' progress-fair' if score >= 40 and score < 60 -}}
|
790 |
+
{{- ' progress-poor' if score < 40 -}}"
|
791 |
+
style="width: {{ score }}%">
|
792 |
+
{{ score|round(1) }}%
|
793 |
+
</div>
|
794 |
</div>
|
795 |
+
</div>
|
796 |
+
</div>
|
797 |
+
|
798 |
+
<div class="completeness-profile">
|
799 |
+
{% set score = enhancement_report.final_score.total_score|default(0) %}
|
800 |
+
<h4>Completeness Profile:
|
801 |
+
{% if score >= 80 %}
|
802 |
+
<span class="profile-badge profile-advanced">Advanced</span>
|
803 |
+
{% elif score >= 60 %}
|
804 |
+
<span class="profile-badge profile-standard">Standard</span>
|
805 |
+
{% elif score >= 40 %}
|
806 |
+
<span class="profile-badge profile-basic">Basic</span>
|
807 |
+
{% else %}
|
808 |
+
<span class="profile-badge profile-incomplete">Incomplete</span>
|
809 |
+
{% endif %}
|
810 |
+
</h4>
|
811 |
+
<p>
|
812 |
+
{% if score >= 80 %}
|
813 |
+
This AI SBOM provides comprehensive information about the model, including detailed training data, process, evaluation metrics, and usage guidelines. It meets advanced transparency requirements.
|
814 |
+
{% elif score >= 60 %}
|
815 |
+
This AI SBOM provides good information about the model, covering most key aspects of its development and usage. It meets standard transparency requirements.
|
816 |
+
{% elif score >= 40 %}
|
817 |
+
This AI SBOM provides basic information about the model but lacks detail in several areas. It meets minimal transparency requirements.
|
818 |
+
{% else %}
|
819 |
+
This AI SBOM is incomplete and missing critical information. It does not meet basic transparency requirements.
|
820 |
+
{% endif %}
|
821 |
+
</p>
|
822 |
+
</div>
|
823 |
+
|
824 |
+
<table class="score-table">
|
825 |
+
<tr>
|
826 |
+
<th>Category</th>
|
827 |
+
<th>Score</th>
|
828 |
+
<th>Details</th>
|
829 |
+
</tr>
|
830 |
+
<tr>
|
831 |
+
<td>Basic Information <span class="score-weight">(20%)</span></td>
|
832 |
+
<td>
|
833 |
+
{% set basic_score = 0 %}
|
834 |
+
{% if aibom.components and aibom.components[0].name %}{% set basic_score = basic_score + 5 %}{% endif %}
|
835 |
+
{% if aibom.components and aibom.components[0].type %}{% set basic_score = basic_score + 5 %}{% endif %}
|
836 |
+
{% if aibom.components and aibom.components[0].version %}{% set basic_score = basic_score + 5 %}{% endif %}
|
837 |
+
{% if aibom.components and aibom.components[0].description %}{% set basic_score = basic_score + 5 %}{% endif %}
|
838 |
+
{{ basic_score }}/20
|
839 |
+
{% if basic_score >= 15 %}
|
840 |
+
<span class="score-label label-excellent">Excellent</span>
|
841 |
+
{% elif basic_score >= 10 %}
|
842 |
+
<span class="score-label label-good">Good</span>
|
843 |
+
{% elif basic_score >= 5 %}
|
844 |
+
<span class="score-label label-fair">Fair</span>
|
845 |
+
{% else %}
|
846 |
+
<span class="score-label label-poor">Poor</span>
|
847 |
+
{% endif %}
|
848 |
+
</td>
|
849 |
+
<td>
|
850 |
+
{% if basic_score < 20 %}
|
851 |
+
Missing:
|
852 |
+
{% if not aibom.components or not aibom.components[0].name %}Model Name, {% endif %}
|
853 |
+
{% if not aibom.components or not aibom.components[0].type %}Model Type, {% endif %}
|
854 |
+
{% if not aibom.components or not aibom.components[0].version %}Model Version, {% endif %}
|
855 |
+
{% if not aibom.components or not aibom.components[0].description %}Model Description{% endif %}
|
856 |
+
{% else %}
|
857 |
+
All basic information is present.
|
858 |
+
{% endif %}
|
859 |
+
</td>
|
860 |
+
</tr>
|
861 |
+
<tr>
|
862 |
+
<td>Training Data <span class="score-weight">(25%)</span></td>
|
863 |
+
<td>
|
864 |
+
{% set training_score = 0 %}
|
865 |
+
{% if aibom.components and aibom.components[0].trainingData and aibom.components[0].trainingData.datasets %}{% set training_score = training_score + 15 %}{% endif %}
|
866 |
+
{% if aibom.components and aibom.components[0].trainingData and aibom.components[0].trainingData.preprocessing %}{% set training_score = training_score + 10 %}{% endif %}
|
867 |
+
{{ training_score }}/25
|
868 |
+
{% if training_score >= 20 %}
|
869 |
+
<span class="score-label label-excellent">Excellent</span>
|
870 |
+
{% elif training_score >= 15 %}
|
871 |
+
<span class="score-label label-good">Good</span>
|
872 |
+
{% elif training_score >= 10 %}
|
873 |
+
<span class="score-label label-fair">Fair</span>
|
874 |
+
{% else %}
|
875 |
+
<span class="score-label label-poor">Poor</span>
|
876 |
+
{% endif %}
|
877 |
+
</td>
|
878 |
+
<td>
|
879 |
+
{% if training_score < 25 %}
|
880 |
+
Missing:
|
881 |
+
{% if not aibom.components or not aibom.components[0].trainingData or not aibom.components[0].trainingData.datasets %}Training Datasets, {% endif %}
|
882 |
+
{% if not aibom.components or not aibom.components[0].trainingData or not aibom.components[0].trainingData.preprocessing %}Data Preprocessing{% endif %}
|
883 |
+
{% else %}
|
884 |
+
All training data information is present.
|
885 |
+
{% endif %}
|
886 |
+
</td>
|
887 |
+
</tr>
|
888 |
+
<tr>
|
889 |
+
<td>Training Process <span class="score-weight">(20%)</span></td>
|
890 |
+
<td>
|
891 |
+
{% set process_score = 0 %}
|
892 |
+
{% if aibom.components and aibom.components[0].trainingProcess and aibom.components[0].trainingProcess.trainingMethod %}{% set process_score = process_score + 8 %}{% endif %}
|
893 |
+
{% if aibom.components and aibom.components[0].trainingProcess and aibom.components[0].trainingProcess.hyperparameters %}{% set process_score = process_score + 8 %}{% endif %}
|
894 |
+
{% if aibom.components and aibom.components[0].trainingProcess and aibom.components[0].trainingProcess.computeInfrastructure %}{% set process_score = process_score + 4 %}{% endif %}
|
895 |
+
{{ process_score }}/20
|
896 |
+
{% if process_score >= 16 %}
|
897 |
+
<span class="score-label label-excellent">Excellent</span>
|
898 |
+
{% elif process_score >= 12 %}
|
899 |
+
<span class="score-label label-good">Good</span>
|
900 |
+
{% elif process_score >= 8 %}
|
901 |
+
<span class="score-label label-fair">Fair</span>
|
902 |
+
{% else %}
|
903 |
+
<span class="score-label label-poor">Poor</span>
|
904 |
+
{% endif %}
|
905 |
+
</td>
|
906 |
+
<td>
|
907 |
+
{% if process_score < 20 %}
|
908 |
+
Missing:
|
909 |
+
{% if not aibom.components or not aibom.components[0].trainingProcess or not aibom.components[0].trainingProcess.trainingMethod %}Training Method, {% endif %}
|
910 |
+
{% if not aibom.components or not aibom.components[0].trainingProcess or not aibom.components[0].trainingProcess.hyperparameters %}Hyperparameters, {% endif %}
|
911 |
+
{% if not aibom.components or not aibom.components[0].trainingProcess or not aibom.components[0].trainingProcess.computeInfrastructure %}Compute Infrastructure{% endif %}
|
912 |
+
{% else %}
|
913 |
+
All training process information is present.
|
914 |
+
{% endif %}
|
915 |
+
</td>
|
916 |
+
</tr>
|
917 |
+
<tr>
|
918 |
+
<td>Evaluation <span class="score-weight">(15%)</span></td>
|
919 |
+
<td>
|
920 |
+
{% set eval_score = 0 %}
|
921 |
+
{% if aibom.components and aibom.components[0].evaluation and aibom.components[0].evaluation.metrics %}{% set eval_score = eval_score + 8 %}{% endif %}
|
922 |
+
{% if aibom.components and aibom.components[0].evaluation and aibom.components[0].evaluation.datasets %}{% set eval_score = eval_score + 7 %}{% endif %}
|
923 |
+
{{ eval_score }}/15
|
924 |
+
{% if eval_score >= 12 %}
|
925 |
+
<span class="score-label label-excellent">Excellent</span>
|
926 |
+
{% elif eval_score >= 8 %}
|
927 |
+
<span class="score-label label-good">Good</span>
|
928 |
+
{% elif eval_score >= 4 %}
|
929 |
+
<span class="score-label label-fair">Fair</span>
|
930 |
+
{% else %}
|
931 |
+
<span class="score-label label-poor">Poor</span>
|
932 |
+
{% endif %}
|
933 |
+
</td>
|
934 |
+
<td>
|
935 |
+
{% if eval_score < 15 %}
|
936 |
+
Missing:
|
937 |
+
{% if not aibom.components or not aibom.components[0].evaluation or not aibom.components[0].evaluation.metrics %}Evaluation Metrics, {% endif %}
|
938 |
+
{% if not aibom.components or not aibom.components[0].evaluation or not aibom.components[0].evaluation.datasets %}Evaluation Datasets{% endif %}
|
939 |
+
{% else %}
|
940 |
+
All evaluation information is present.
|
941 |
+
{% endif %}
|
942 |
+
</td>
|
943 |
+
</tr>
|
944 |
+
<tr>
|
945 |
+
<td>Usage & Licensing <span class="score-weight">(20%)</span></td>
|
946 |
+
<td>
|
947 |
+
{% set usage_score = 0 %}
|
948 |
+
{% if aibom.components and aibom.components[0].usage and aibom.components[0].usage.intendedUse %}{% set usage_score = usage_score + 8 %}{% endif %}
|
949 |
+
{% if aibom.components and aibom.components[0].usage and aibom.components[0].usage.outOfScopeUses %}{% set usage_score = usage_score + 2 %}{% endif %}
|
950 |
+
{% if aibom.components and aibom.components[0].licenses %}{% set usage_score = usage_score + 10 %}{% endif %}
|
951 |
+
{{ usage_score }}/20
|
952 |
+
{% if usage_score >= 16 %}
|
953 |
+
<span class="score-label label-excellent">Excellent</span>
|
954 |
+
{% elif usage_score >= 12 %}
|
955 |
+
<span class="score-label label-good">Good</span>
|
956 |
+
{% elif usage_score >= 8 %}
|
957 |
+
<span class="score-label label-fair">Fair</span>
|
958 |
+
{% else %}
|
959 |
+
<span class="score-label label-poor">Poor</span>
|
960 |
+
{% endif %}
|
961 |
+
</td>
|
962 |
+
<td>
|
963 |
+
{% if usage_score < 20 %}
|
964 |
+
Missing:
|
965 |
+
{% if not aibom.components or not aibom.components[0].usage or not aibom.components[0].usage.intendedUse %}Intended Use, {% endif %}
|
966 |
+
{% if not aibom.components or not aibom.components[0].usage or not aibom.components[0].usage.outOfScopeUses %}Out of Scope Uses, {% endif %}
|
967 |
+
{% if not aibom.components or not aibom.components[0].licenses %}Licenses{% endif %}
|
968 |
+
{% else %}
|
969 |
+
All usage and licensing information is present.
|
970 |
+
{% endif %}
|
971 |
+
</td>
|
972 |
+
</tr>
|
973 |
+
</table>
|
974 |
+
|
975 |
+
<div class="recommendations">
|
976 |
+
<h4>Recommendations for Improvement</h4>
|
977 |
+
<ul>
|
978 |
+
{% if not aibom.components or not aibom.components[0].name or not aibom.components[0].type or not aibom.components[0].version %}
|
979 |
+
<li><span class="importance-indicator high-importance">β
β
β
</span> Add basic model information (name, type, version)</li>
|
980 |
+
{% endif %}
|
981 |
|
982 |
+
{% if not aibom.components or not aibom.components[0].trainingData or not aibom.components[0].trainingData.datasets %}
|
983 |
+
<li><span class="importance-indicator high-importance">β
β
β
</span> Add information about training datasets</li>
|
984 |
+
{% endif %}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
985 |
|
986 |
+
{% if not aibom.components or not aibom.components[0].licenses %}
|
987 |
+
<li><span class="importance-indicator high-importance">β
β
β
</span> Add licensing information</li>
|
988 |
+
{% endif %}
|
989 |
+
|
990 |
+
{% if not aibom.components or not aibom.components[0].trainingProcess or not aibom.components[0].trainingProcess.trainingMethod or not aibom.components[0].trainingProcess.hyperparameters %}
|
991 |
+
<li><span class="importance-indicator medium-importance">β
β
β</span> Add training process details (method, hyperparameters)</li>
|
992 |
+
{% endif %}
|
993 |
+
|
994 |
+
{% if not aibom.components or not aibom.components[0].evaluation or not aibom.components[0].evaluation.metrics %}
|
995 |
+
<li><span class="importance-indicator medium-importance">β
β
β</span> Add evaluation metrics</li>
|
996 |
+
{% endif %}
|
997 |
+
|
998 |
+
{% if not aibom.components or not aibom.components[0].usage or not aibom.components[0].usage.intendedUse %}
|
999 |
+
<li><span class="importance-indicator medium-importance">β
β
β</span> Add intended use information</li>
|
1000 |
+
{% endif %}
|
1001 |
+
|
1002 |
+
{% if not aibom.components or not aibom.components[0].modelCard or not aibom.components[0].modelCard.considerations or not aibom.components[0].modelCard.considerations.ethicalConsiderations %}
|
1003 |
+
<li><span class="importance-indicator low-importance">β
ββ</span> Add ethical considerations</li>
|
1004 |
+
{% endif %}
|
1005 |
+
</ul>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1006 |
</div>
|
1007 |
</div>
|
1008 |
|
1009 |
<script>
|
1010 |
+
function downloadJSON() {
|
1011 |
+
const a = document.createElement('a');
|
1012 |
+
a.href = '{{ download_url }}';
|
1013 |
+
a.download = '{{ model_id|replace("/", "_") }}_aibom.json';
|
1014 |
+
document.body.appendChild(a);
|
1015 |
+
a.click();
|
1016 |
+
document.body.removeChild(a);
|
1017 |
+
}
|
1018 |
+
|
1019 |
function switchTab(tabId) {
|
1020 |
// Hide all tab contents
|
1021 |
+
const tabContents = document.getElementsByClassName('tab-content');
|
1022 |
+
for (let i = 0; i < tabContents.length; i++) {
|
1023 |
tabContents[i].classList.remove('active');
|
1024 |
}
|
1025 |
|
1026 |
// Deactivate all tabs
|
1027 |
+
const tabs = document.getElementsByClassName('aibom-tab');
|
1028 |
+
for (let i = 0; i < tabs.length; i++) {
|
1029 |
tabs[i].classList.remove('active');
|
1030 |
}
|
1031 |
|
1032 |
// Activate the selected tab and content
|
1033 |
document.getElementById(tabId).classList.add('active');
|
1034 |
+
document.querySelector('.aibom-tab[onclick="switchTab(\'' + tabId + '\')"]').classList.add('active');
|
|
|
1035 |
}
|
1036 |
|
1037 |
function toggleCollapsible(element) {
|
1038 |
element.classList.toggle('active');
|
1039 |
+
const content = element.nextElementSibling;
|
|
|
|
|
1040 |
if (content.classList.contains('active')) {
|
1041 |
+
content.classList.remove('active');
|
1042 |
} else {
|
1043 |
+
content.classList.add('active');
|
1044 |
}
|
1045 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1046 |
</script>
|
1047 |
</body>
|
1048 |
</html>
|