|
|
|
|
|
<div class="site-header"> |
|
|
<div class="header-inner"> |
|
|
<div class="logo-cluster"> |
|
|
<span (click)="navigateHome()" style="cursor:pointer;display:flex;align-items:center;"> |
|
|
<img src="/assets/pykara-logo.png" alt="PyDetect Logo" class="logo-img-header" /> |
|
|
</span> |
|
|
|
|
|
<div class="py-detect-title-header"> |
|
|
<span class="py-letter p">P</span> |
|
|
<span class="py-letter y">Y</span> |
|
|
<span class="py-shape"></span> |
|
|
<span class="py-letter d">D</span> |
|
|
<span class="py-letter e">E</span> |
|
|
<span class="py-letter t">T</span> |
|
|
<span class="py-letter e2">E</span> |
|
|
<span class="py-letter c">C</span> |
|
|
<span class="py-letter t2">T</span> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="header-actions-right"> |
|
|
<button class="back-btn" (click)="goBack()"> |
|
|
<span class="back-icon">←</span> Back |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="details-layout"> |
|
|
<aside class="details-sidebar modern-sidebar"> |
|
|
<div class="sidebar-section-heading">Analysis Modules</div> |
|
|
<div class="sidebar-btn-group"> |
|
|
<button class="sidebar-btn2" [class.active]="activeTab === 'audio'" (click)="setTab('audio')"> |
|
|
<span class="sidebar-icon material-icons">Audio Analysis</span> |
|
|
|
|
|
</button> |
|
|
<button class="sidebar-btn2" [class.active]="activeTab === 'video'" (click)="setTab('video')"> |
|
|
<span class="sidebar-icon material-icons">Video Analysis</span> |
|
|
|
|
|
</button> |
|
|
<button class="sidebar-btn2" [class.active]="activeTab === 'validation'" (click)="setTab('validation')"> |
|
|
<span class="sidebar-icon material-icons">verified Scores</span> |
|
|
|
|
|
</button> |
|
|
</div> |
|
|
|
|
|
</aside> |
|
|
|
|
|
<main class="details-main"> |
|
|
<div class="indigo-main-card wide" [@fadeInTab]> |
|
|
|
|
|
|
|
|
<div class="case-header" *ngIf="selectedQuestion || (questions && questions.length > 0)"> |
|
|
<div class="case-qa"> |
|
|
<div style="display:flex;align-items:center;justify-content:space-between;gap:12px;"> |
|
|
<div style="flex:1"> |
|
|
<div><strong>Question:</strong> {{ selectedQuestion?.question || questions[0]?.question || '—' }}</div> |
|
|
<div><strong>Answer:</strong> {{ selectedQuestion?.answer || questions[0]?.answer || '—' }}</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div style="display:flex;flex-direction:column;align-items:flex-end;min-width:140px;margin:8px;"> |
|
|
<div class="qa-counter" aria-live="polite" style="font-weight:700;color:#075985;"> |
|
|
Question |
|
|
{{ getCurrentIndex() >= 0 ? (getCurrentIndex() + 1) : (selectedQuestion ? 1 : 0) }} |
|
|
of {{ questions.length || 0 }} |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div style="display:flex;align-items:center;gap:8px;"> |
|
|
<button class="nav-btn" |
|
|
(click)="prevQuestion()" |
|
|
[disabled]="!hasPrev()" |
|
|
[class.prev-anim]="navAnimating === 'prev'"> |
|
|
Previous |
|
|
</button> |
|
|
<button class="nav-btn" |
|
|
(click)="nextQuestion()" |
|
|
[disabled]="!hasNext()" |
|
|
[class.next-anim]="navAnimating === 'next'"> |
|
|
Next |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<hr /> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div *ngIf="(!questions || questions.length === 0)" class="empty-message"> |
|
|
No question records available for Case ID {{ caseId }}. |
|
|
</div> |
|
|
|
|
|
|
|
|
<div *ngIf="questions && questions.length > 0 && activeTab === 'audio'"> |
|
|
<div *ngFor="let q of (selectedQuestion ? [selectedQuestion] : questions); let i = index" |
|
|
class="audio-analysis-card metrics-card audio-card" |
|
|
[@cardFade]> |
|
|
|
|
|
<div class="metrics-card-heading audio-analysis">Audio Analysis</div> |
|
|
|
|
|
<div class="metrics-list"> |
|
|
<ng-container *ngIf="layoutMode === 'single'"> |
|
|
<div class="metrics-grid-card"> |
|
|
<div class="metrics-grid"> |
|
|
<div class="metrics-card metrics-col"> |
|
|
<div class="metrics-card-heading">Core Metrics</div> |
|
|
<div *ngFor="let m of coreMetrics" class="metric-row"> |
|
|
<button class="metric-name metric-label" (click)="toggleTooltip(m.key)"> |
|
|
{{ m.label }} |
|
|
</button> |
|
|
<div class="metric-value">{{ getMetricValue(q, m.key) }}</div> |
|
|
<div class="tooltip" *ngIf="shownTooltip === m.key">{{ m.desc }}</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="metrics-card metrics-col"> |
|
|
<div class="metrics-card-heading">Stress & Tone</div> |
|
|
<div *ngFor="let m of stressToneMetrics" class="metric-row"> |
|
|
<button class="metric-name metric-label" (click)="toggleTooltip(m.key)"> |
|
|
{{ m.label }} |
|
|
</button> |
|
|
<div class="metric-value">{{ getMetricValue(q, m.key) }}</div> |
|
|
<div class="tooltip" *ngIf="shownTooltip === m.key">{{ m.desc }}</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="metrics-card metrics-col"> |
|
|
<div class="metrics-card-heading">Speech Behaviour</div> |
|
|
<div *ngFor="let m of speechBehaviourMetrics" class="metric-row"> |
|
|
<button class="metric-name metric-label" (click)="toggleTooltip(m.key)"> |
|
|
{{ m.label }} |
|
|
</button> |
|
|
<div class="metric-value">{{ getMetricValue(q, m.key) }}</div> |
|
|
<div class="tooltip" *ngIf="shownTooltip === m.key">{{ m.desc }}</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="metrics-card metrics-col"> |
|
|
<div class="metrics-card-heading">Advanced (optional)</div> |
|
|
<div *ngFor="let m of advancedMetrics" class="metric-row"> |
|
|
<button class="metric-name metric-label" (click)="toggleTooltip(m.key)"> |
|
|
{{ m.label }} |
|
|
</button> |
|
|
<div class="metric-value">{{ getMetricValue(q, m.key) }}</div> |
|
|
<div class="tooltip" *ngIf="shownTooltip === m.key">{{ m.desc }}</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</ng-container> |
|
|
|
|
|
<ng-container *ngIf="layoutMode === 'multiple'"> |
|
|
<div class="metrics-grid-multiple"> |
|
|
<div class="metrics-card" |
|
|
*ngFor="let group of [coreMetrics, stressToneMetrics, speechBehaviourMetrics, advancedMetrics]"> |
|
|
<div class="metrics-card-heading"> |
|
|
{{ |
|
|
group === coreMetrics ? 'Core Metrics' : |
|
|
group === stressToneMetrics ? 'Stress & Tone' : |
|
|
group === speechBehaviourMetrics ? 'Speech Behaviour' : |
|
|
'Advanced (optional)' |
|
|
}} |
|
|
</div> |
|
|
|
|
|
<div *ngFor="let m of group" class="metric-row"> |
|
|
<button class="metric-name metric-label" (click)="toggleTooltip(m.key)"> |
|
|
{{ m.label }} |
|
|
</button> |
|
|
<div class="metric-value">{{ getMetricValue(q, m.key) }}</div> |
|
|
<div class="tooltip" *ngIf="shownTooltip === m.key">{{ m.desc }}</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</ng-container> |
|
|
</div> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div *ngIf="questions && questions.length > 0 && activeTab === 'video'"> |
|
|
<div *ngFor="let q of (selectedQuestion ? [selectedQuestion] : questions); let i = index" |
|
|
class="video-analysis-card metrics-card video-card" |
|
|
[@cardFade]> |
|
|
|
|
|
<div class="metrics-card-heading video-analysis">Video Analysis</div> |
|
|
|
|
|
<ng-container *ngIf="layoutMode === 'single'"> |
|
|
<div class="metrics-grid-card"> |
|
|
<div class="metrics-grid"> |
|
|
<div class="metrics-card metrics-col"> |
|
|
<div class="metrics-card-heading">Core Metrics</div> |
|
|
<div *ngFor="let m of videoCoreMetrics" class="metric-row"> |
|
|
<button class="metric-name metric-label" (click)="toggleTooltip(m.key)"> |
|
|
{{ m.label }} |
|
|
</button> |
|
|
<div class="metric-value">{{ getMetricValue(q, m.key) }}</div> |
|
|
<div class="tooltip" *ngIf="shownTooltip === m.key">{{ m.desc }}</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="metrics-card metrics-col"> |
|
|
<div class="metrics-card-heading">Behavioural & Psychological</div> |
|
|
<div *ngFor="let m of videoBehaviourMetrics" class="metric-row"> |
|
|
<button class="metric-name metric-label" (click)="toggleTooltip(m.key)"> |
|
|
{{ m.label }} |
|
|
</button> |
|
|
<div class="metric-value">{{ getMetricValue(q, m.key) }}</div> |
|
|
<div class="tooltip" *ngIf="shownTooltip === m.key">{{ m.desc }}</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="metrics-card metrics-col"> |
|
|
<div class="metrics-card-heading">Advanced (optional)</div> |
|
|
<div *ngFor="let m of videoAdvancedMetrics" class="metric-row"> |
|
|
<button class="metric-name metric-label" (click)="toggleTooltip(m.key)"> |
|
|
{{ m.label }} |
|
|
</button> |
|
|
<div class="metric-value">{{ getMetricValue(q, m.key) }}</div> |
|
|
<div class="tooltip" *ngIf="shownTooltip === m.key">{{ m.desc }}</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</ng-container> |
|
|
|
|
|
<ng-container *ngIf="layoutMode === 'multiple'"> |
|
|
<div class="metrics-grid-multiple"> |
|
|
<div class="metrics-card" |
|
|
*ngFor="let group of [videoCoreMetrics, videoBehaviourMetrics, videoAdvancedMetrics]"> |
|
|
<div class="metrics-card-heading"> |
|
|
{{ |
|
|
group === videoCoreMetrics ? 'Core Metrics' : |
|
|
group === videoBehaviourMetrics ? 'Behavioural & Psychological' : |
|
|
'Advanced (optional)' |
|
|
}} |
|
|
</div> |
|
|
|
|
|
<div *ngFor="let m of group" class="metric-row"> |
|
|
<button class="metric-name metric-label" (click)="toggleTooltip(m.key)"> |
|
|
{{ m.label }} |
|
|
</button> |
|
|
<div class="metric-value">{{ getMetricValue(q, m.key) }}</div> |
|
|
<div class="tooltip" *ngIf="shownTooltip === m.key">{{ m.desc }}</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</ng-container> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div *ngIf="questions && questions.length > 0 && activeTab === 'validation'"> |
|
|
<div *ngFor="let q of (selectedQuestion ? [selectedQuestion] : questions); let i = index" |
|
|
class="validation-analysis-wrap"> |
|
|
|
|
|
<div class="indigo-main-card verified-scores" [@cardFade]> |
|
|
<div class="metrics-card-heading">Verified Scores</div> |
|
|
|
|
|
<ng-container *ngIf="layoutMode === 'single'"> |
|
|
<div class="verified-scores-grid"> |
|
|
|
|
|
<div class="verified-scores-row" style="display:flex;gap:16px;margin-bottom:16px;"> |
|
|
<div class="metrics-card verified-score-card" style="flex:1;min-width:220px;"> |
|
|
<div class="metrics-card-heading" style="font-weight:600;">Physical Expression</div> |
|
|
<div class="metric-value" style="font-weight:700;">Neutral, Low hand, Moderate leg, 2 detected</div> |
|
|
</div> |
|
|
<div class="metrics-card verified-score-card" style="flex:1;min-width:220px;"> |
|
|
<div class="metrics-card-heading" style="font-weight:600;">Physical Score (%)</div> |
|
|
<div class="metric-value" style="font-weight:700;">2%</div> |
|
|
</div> |
|
|
<div class="metrics-card verified-score-card" style="flex:1;min-width:220px;"> |
|
|
<div class="metrics-card-heading" style="font-weight:600;">Voice Expression</div> |
|
|
<div class="metric-value" style="font-weight:700;">Stress 68, Conf Moderate, Sent -45%, Delay 3.1 sec</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="verified-scores-row" style="display:flex;gap:16px;"> |
|
|
<div class="metrics-card verified-score-card" style="flex:1;min-width:220px;"> |
|
|
<div class="metrics-card-heading" style="font-weight:600;">Voice Score (%)</div> |
|
|
<div class="metric-value" style="font-weight:700;">23</div> |
|
|
</div> |
|
|
<div class="metrics-card verified-score-card" style="flex:1;min-width:220px;"> |
|
|
<div class="metrics-card-heading" style="font-weight:600;">Truth Probability (%)</div> |
|
|
<div class="metric-value" style="font-weight:700;">78%</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</ng-container> |
|
|
|
|
|
<ng-container *ngIf="layoutMode === 'multiple'"> |
|
|
<div class="metrics-grid-multiple"> |
|
|
<div class="metrics-card" *ngFor="let m of videoFinalMetrics"> |
|
|
<div class="metrics-card-heading" *ngIf="m.label !== 'Overall Score (%)'"> |
|
|
{{ m.label }} |
|
|
</div> |
|
|
|
|
|
<div class="metric-row" *ngIf="m.label !== 'Overall Score (%)'"> |
|
|
<div class="metric-value">{{ getFinalMetricValue(q, m.key) }}</div> |
|
|
</div> |
|
|
|
|
|
<div class="tooltip" *ngIf="shownTooltip === m.key">{{ m.desc }}</div> |
|
|
</div> |
|
|
</div> |
|
|
</ng-container> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
</div> |
|
|
</main> |
|
|
|
|
|
<footer> |
|
|
<p>©2025 Pykara Technologies Pvt. Ltd. All rights reserved.</p> |
|
|
</footer> |
|
|
</div> |
|
|
|