|
|
|
|
|
<header class="site-header"> |
|
|
<div class="header-inner"> |
|
|
<div class="logo-cluster"> |
|
|
<span (click)="navigateHome()" style="cursor:pointer"> |
|
|
<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-group"> |
|
|
<button class="back-btn" (click)="navigateBackToCaseDetails()"> |
|
|
<i class="fas fa-arrow-left"></i> |
|
|
<span>Back to Case Details</span> |
|
|
</button> |
|
|
<div class="header-actions-icons"> |
|
|
<button class="evidence-btn" (click)="showEvidencePanel = !showEvidencePanel" title="Upload Evidence"> |
|
|
<i class="fas fa-file-upload"></i> |
|
|
</button> |
|
|
<button class="summary-btn" (click)="showSummaryPanel = !showSummaryPanel" title="Investigation Summary"> |
|
|
<i class="fas fa-clipboard-list"></i> |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</header> |
|
|
|
|
|
|
|
|
<div class="main-content-card"> |
|
|
<div class="card-inner"> |
|
|
<div class="content-grid"> |
|
|
|
|
|
<div class="left-panel"> |
|
|
|
|
|
<div *ngIf="currentQuestionIndex < 0" class="guidance-banner"> |
|
|
<div class="guidance-content"> |
|
|
<div class="guidance-icon"> |
|
|
<i class="fas fa-lightbulb"></i> |
|
|
</div> |
|
|
<div class="guidance-text"> |
|
|
<h3>Ready to Begin Investigation</h3> |
|
|
<p>Click "Start Investigation" to activate camera and begin questioning</p> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<button class="start-investigation-btn" (click)="onStartInvestigation()"> |
|
|
<i class="fas fa-search"></i> |
|
|
Start Investigation |
|
|
</button> |
|
|
|
|
|
|
|
|
<div class="question-section"> |
|
|
<div class="question-header"> |
|
|
<div class="question-badge">Question {{ currentQuestionIndex + 1 }}</div> |
|
|
<div class="status-indicator" *ngIf="infoText"> |
|
|
<i class="fas fa-info-circle"></i> |
|
|
{{ infoText }} |
|
|
</div> |
|
|
</div> |
|
|
<div class="question-content"> |
|
|
<h3>Current Question</h3> |
|
|
<div class="question-text"> |
|
|
<ng-container *ngIf="questions.length > 0 && currentQuestionIndex >= 0"> |
|
|
{{ questions[currentQuestionIndex] }} |
|
|
</ng-container> |
|
|
<ng-container *ngIf="!questions.length || currentQuestionIndex < 0"> |
|
|
<span *ngIf="currentQuestionText">{{ currentQuestionText }}</span> |
|
|
<span *ngIf="!currentQuestionText" class="no-question"> |
|
|
Awaiting first question. Click "Start Investigation" to begin. |
|
|
</span> |
|
|
</ng-container> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="answer-section"> |
|
|
<h3>Your Answer</h3> |
|
|
<textarea id="answerInput" |
|
|
[(ngModel)]="textAnswer" |
|
|
(focus)="captureTextStart()" |
|
|
class="answer-input" |
|
|
placeholder="Type or speak your answer here..." |
|
|
rows="5" |
|
|
maxlength="3000"> |
|
|
</textarea> |
|
|
|
|
|
<div class="answer-actions"> |
|
|
<button (click)="submitCombinedAnswer()" class="btn-primary"> |
|
|
<i class="fas fa-paper-plane"></i> |
|
|
Submit Answer |
|
|
</button> |
|
|
<button (click)="toggleVoiceRecording()" class="btn-secondary"> |
|
|
<i class="fas fa-microphone"></i> |
|
|
<span *ngIf="!isVoiceRecording">Start Recording</span> |
|
|
<span *ngIf="isVoiceRecording">Stop Recording</span> |
|
|
</button> |
|
|
</div> |
|
|
|
|
|
<div *ngIf="isVoiceRecording" class="recording-status"> |
|
|
<div class="recording-dot"></div> |
|
|
<span>Recording... Speak now</span> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="results-section"> |
|
|
|
|
|
<div *ngIf="truthScore !== null" class="result-card"> |
|
|
<div class="result-header"> |
|
|
<div class="result-icon truth"> |
|
|
<i class="fas fa-check-circle"></i> |
|
|
</div> |
|
|
<div class="result-title">Truth Score</div> |
|
|
<div class="result-value">{{ truthScore }}</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div *ngIf="faceDetectionScore !== null" class="result-card"> |
|
|
<div class="result-header"> |
|
|
<div class="result-icon face"> |
|
|
<i class="fas fa-user-check"></i> |
|
|
</div> |
|
|
<div class="result-title">Face Detection</div> |
|
|
<div class="result-value">{{ faceDetectionScore }}</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div *ngIf="involvementScore !== null" class="result-card"> |
|
|
<div class="result-header"> |
|
|
<div class="result-icon involvement"> |
|
|
<i class="fas fa-user-tag"></i> |
|
|
</div> |
|
|
<div class="result-title">Involvement Score</div> |
|
|
<div class="result-value">{{ involvementScore | number:'1.1-1' }}</div> |
|
|
</div> |
|
|
<div class="progress-bar"> |
|
|
<div class="progress-fill" [style.width]="involvementScore + '%'"></div> |
|
|
</div> |
|
|
|
|
|
<div *ngIf="involvementCues.length" class="cues-container"> |
|
|
<span *ngFor="let cue of involvementCues" class="cue-tag"> |
|
|
{{ cue.replace('_cue','').replace('_',' ') }} |
|
|
</span> |
|
|
</div> |
|
|
|
|
|
<div *ngIf="bodyLanguageMeaning || bodyLanguageExplanation" style="margin-top: 12px; font-size: 12px; color: #64748b;"> |
|
|
<div *ngIf="bodyLanguageMeaning" style="margin-bottom: 4px;"> |
|
|
<strong>Body Language:</strong> {{ bodyLanguageMeaning }} |
|
|
</div> |
|
|
<div *ngIf="bodyLanguageExplanation"> |
|
|
<strong>Analysis:</strong> {{ bodyLanguageExplanation }} |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div *ngIf="ferEmotion" class="result-card"> |
|
|
<div class="result-header"> |
|
|
<div class="result-icon emotion"> |
|
|
<i class="fas fa-smile"></i> |
|
|
</div> |
|
|
<div class="result-title">Emotion (FER)</div> |
|
|
<div class="result-value">{{ ferEmotion }}</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="right-panel"> |
|
|
|
|
|
<div class="camera-section"> |
|
|
<ng-container *ngIf="!videoStream"> |
|
|
<div class="camera-placeholder"> |
|
|
<div class="camera-icon"> |
|
|
<i class="fas fa-video"></i> |
|
|
</div> |
|
|
<h3>Camera Inactive</h3> |
|
|
<p>Click "Start Investigation" to begin video recording and analysis</p> |
|
|
</div> |
|
|
</ng-container> |
|
|
|
|
|
<ng-container *ngIf="videoStream"> |
|
|
<div class="video-active"> |
|
|
<video #videoElement [srcObject]="videoStream" autoplay muted playsinline class="camera-video"></video> |
|
|
<div *ngIf="isRecording && currentQuestionIndex >= 0 && currentQuestionIndex < totalQuestions" class="recording-overlay"> |
|
|
<i class="fas fa-circle" style="font-size: 8px;"></i> |
|
|
LIVE RECORDING |
|
|
</div> |
|
|
</div> |
|
|
</ng-container> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="transcription-section"> |
|
|
<div class="transcription-header"> |
|
|
<h3> |
|
|
<i class="fas fa-comments"></i> |
|
|
Transcription |
|
|
<span class="live-badge">LIVE</span> |
|
|
</h3> |
|
|
</div> |
|
|
<div class="transcription-content"> |
|
|
<div *ngFor="let line of transcriptLines" class="transcription-line"> |
|
|
{{ line }} |
|
|
</div> |
|
|
<div *ngIf="!transcriptLines.length" class="transcription-line" style="text-align: center; color: #94a3b8;"> |
|
|
<i class="fas fa-microphone-alt"></i> |
|
|
<div style="margin-top: 8px;">Waiting for speech input...</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="final-action"> |
|
|
<button class="evaluate-btn" (click)="navigateToValidationPage()"> |
|
|
<i class="fas fa-check-circle"></i> |
|
|
Submit & Evaluate |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="evidence-sidebar" [class.open]="showEvidencePanel"> |
|
|
<div class="sidebar-header"> |
|
|
<div class="sidebar-title"> |
|
|
<i class="fas fa-file-upload"></i> |
|
|
Evidence Panel |
|
|
</div> |
|
|
<button class="close-btn" (click)="showEvidencePanel = false" title="Close"> |
|
|
<i class="fas fa-times"></i> |
|
|
</button> |
|
|
</div> |
|
|
<div class="sidebar-content"> |
|
|
<form class="evidence-upload-form" (submit)="$event.preventDefault(); uploadDocument()"> |
|
|
<div style="margin-bottom: 24px;"> |
|
|
<label style="display: block; margin-bottom: 8px; font-weight: 600; color: #1e293b;">Upload Document</label> |
|
|
<input type="file" (change)="onEvidenceFileSelect($event, 'document')" |
|
|
style="width: 100%; padding: 12px; border: 2px dashed #cbd5e1; border-radius: 10px; background: #f8fafc; cursor: pointer;"> |
|
|
</div> |
|
|
<div style="margin-bottom: 24px;"> |
|
|
<label style="display: block; margin-bottom: 8px; font-weight: 600; color: #1e293b;">Upload Photo</label> |
|
|
<input type="file" accept="image/*" (change)="onEvidenceFileSelect($event, 'photo')" |
|
|
style="width: 100%; padding: 12px; border: 2px dashed #cbd5e1; border-radius: 10px; background: #f8fafc; cursor: pointer;"> |
|
|
</div> |
|
|
<div style="margin-bottom: 24px;"> |
|
|
<label style="display: block; margin-bottom: 8px; font-weight: 600; color: #1e293b;">Upload Recording</label> |
|
|
<input type="file" accept="audio/*,video/*" (change)="onEvidenceFileSelect($event, 'recording')" |
|
|
style="width: 100%; padding: 12px; border: 2px dashed #cbd5e1; border-radius: 10px; background: #f8fafc; cursor: pointer;"> |
|
|
</div> |
|
|
|
|
|
<div style="margin-bottom: 24px;"> |
|
|
<label style="display: block; margin-bottom: 8px; font-weight: 600; color: #1e293b;">Remarks</label> |
|
|
<textarea [(ngModel)]="evidenceSummary" [ngModelOptions]="{standalone: true}" |
|
|
rows="4" placeholder="Enter any additional remarks..." |
|
|
style="width: 100%; padding: 12px; border: 2px solid #cbd5e1; border-radius: 10px; background: white; font-family: inherit;"></textarea> |
|
|
</div> |
|
|
|
|
|
<button type="submit" class="btn-primary" style="width: 100%;"> |
|
|
<i class="fas fa-paper-plane"></i> |
|
|
Submit Evidence |
|
|
</button> |
|
|
</form> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="summary-sidebar" [class.open]="showSummaryPanel"> |
|
|
<div class="sidebar-header"> |
|
|
<div class="sidebar-title"> |
|
|
<i class="fas fa-clipboard-list"></i> |
|
|
Investigation Summary |
|
|
</div> |
|
|
<button class="close-btn" (click)="showSummaryPanel = false" title="Close"> |
|
|
<i class="fas fa-times"></i> |
|
|
</button> |
|
|
</div> |
|
|
<div class="sidebar-content"> |
|
|
<div style="margin-bottom: 24px;"> |
|
|
<h4 style="color: #2563eb; margin-bottom: 12px; font-size: 14px; font-weight: 600;">Case Details</h4> |
|
|
<div style="background: #f0f9ff; border-radius: 10px; padding: 16px;"> |
|
|
<div style="display: flex; justify-content: space-between; margin-bottom: 8px;"> |
|
|
<span style="color: #475569; font-size: 13px;">Case ID:</span> |
|
|
<span style="font-weight: 600; color: #1e293b;">{{ caseId }}</span> |
|
|
</div> |
|
|
<div style="display: flex; justify-content: space-between; margin-bottom: 8px;"> |
|
|
<span style="color: #475569; font-size: 13px;">Crime Type:</span> |
|
|
<span style="font-weight: 600; color: #1e293b;">{{ crimeType }}</span> |
|
|
</div> |
|
|
<div style="display: flex; justify-content: space-between; margin-bottom: 8px;"> |
|
|
<span style="color: #475569; font-size: 13px;">Date & Time:</span> |
|
|
<span style="font-weight: 600; color: #1e293b;">{{ dateTime }}</span> |
|
|
</div> |
|
|
<div style="display: flex; justify-content: space-between; margin-bottom: 8px;"> |
|
|
<span style="color: #475569; font-size: 13px;">Location:</span> |
|
|
<span style="font-weight: 600; color: #1e293b;">{{ location }}</span> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div style="margin-bottom: 24px;"> |
|
|
<h4 style="color: #2563eb; margin-bottom: 12px; font-size: 14px; font-weight: 600;">Person Details</h4> |
|
|
<div style="background: #f0f9ff; border-radius: 10px; padding: 16px;"> |
|
|
<div style="display: flex; justify-content: space-between; margin-bottom: 8px;"> |
|
|
<span style="color: #475569; font-size: 13px;">Suspect Name:</span> |
|
|
<span style="font-weight: 600; color: #1e293b;">{{ suspectName }}</span> |
|
|
</div> |
|
|
<div style="display: flex; justify-content: space-between;"> |
|
|
<span style="color: #475569; font-size: 13px;">Investigation Officer:</span> |
|
|
<span style="font-weight: 600; color: #1e293b;">{{ investigationOfficer }}</span> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div> |
|
|
<h4 style="color: #2563eb; margin-bottom: 12px; font-size: 14px; font-weight: 600;">Progress Details</h4> |
|
|
<div style="background: #f0f9ff; border-radius: 10px; padding: 16px;"> |
|
|
<div style="display: flex; justify-content: space-between; margin-bottom: 8px;"> |
|
|
<span style="color: #475569; font-size: 13px;">Status:</span> |
|
|
<span style="font-weight: 600; color: #1e293b;">{{ statusText }}</span> |
|
|
</div> |
|
|
<div style="display: flex; justify-content: space-between; margin-bottom: 8px;"> |
|
|
<span style="color: #475569; font-size: 13px;">Progress:</span> |
|
|
<span style="font-weight: 600; color: #1e293b;">{{progress}}% ({{ progressStage }})</span> |
|
|
</div> |
|
|
<div style="display: flex; justify-content: space-between;"> |
|
|
<span style="color: #475569; font-size: 13px;">Session Time:</span> |
|
|
<span style="font-weight: 600; color: #1e293b;">{{ sessionTime }}</span> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="blur-bg" [class.active]="showEvidencePanel || showSummaryPanel"></div> |
|
|
|
|
|
|
|
|
<footer> |
|
|
<p>© 2025 Pykara Technologies Pvt. Ltd. All rights reserved.</p> |
|
|
</footer> |
|
|
|