| |
| <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> |
|
|