|
|
|
|
|
<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-group"> |
|
|
<button class="back-btn" (click)="navigateBackToCaseDetails()"> |
|
|
<span class="back-icon">←</span> Back to Case Details |
|
|
</button> |
|
|
<div class="header-actions-icons"> |
|
|
<button class="icon-btn" (click)="showEvidencePanel = !showEvidencePanel" title="Upload Evidence"> |
|
|
<i class="fas fa-file-upload"></i> |
|
|
</button> |
|
|
<button class="icon-btn" (click)="showSummaryPanel = !showSummaryPanel" title="Investigation Summary"> |
|
|
<i class="fas fa-clipboard-list"></i> |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="header-action-bar"> |
|
|
<div class="header-action-left" style="position:relative;"> |
|
|
<button class="small-btn" (click)="onStartInvestigation()"> |
|
|
<i class="fas fa-search"></i> Start Investigation |
|
|
</button> |
|
|
<div *ngIf="currentQuestionIndex < 0" class="guidance-tooltip"> |
|
|
<span style="font-size:1.3em;">💡</span> |
|
|
Click Start Investigation to activate camera and begin questioning. |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<div class="header-divider-line"></div> |
|
|
|
|
|
<main class="main-flex-layout"> |
|
|
|
|
|
<section class="left-panel"> |
|
|
<div class="animated-divider"></div> |
|
|
|
|
|
|
|
|
<div class="tts-question-card"> |
|
|
<div class="tts-question-title">Question {{ currentQuestionIndex + 1 }}</div> |
|
|
<div class="tts-question-text"> |
|
|
<ng-container *ngIf="questions.length > 0; else noQuestion"> |
|
|
{{ questions[currentQuestionIndex] }} |
|
|
</ng-container> |
|
|
<ng-template #noQuestion> |
|
|
<span *ngIf="currentQuestionText">{{ currentQuestionText }}</span> |
|
|
<span *ngIf="!currentQuestionText">No question available.</span> |
|
|
</ng-template> |
|
|
</div> |
|
|
<div *ngIf="infoText" class="tts-status-row">{{ infoText }}</div> |
|
|
|
|
|
|
|
|
<div class="answer-section"> |
|
|
<div class="answer-card" style="background: #f8fbff; border-radius: 12px; box-shadow: 0 2px 8px #0001; padding: 18px 20px; margin-top: 10px; display: flex; flex-direction: column; gap: 18px; max-width: 650px; width: 100%;"> |
|
|
<label for="answerInput" style="font-weight: 500; margin-bottom: 4px; color: #2a3b5c;">Your Answer:</label> |
|
|
<textarea id="answerInput" [(ngModel)]="textAnswer" (focus)="captureTextStart()" class="answer-input" placeholder="Type or speak your answer here..." rows="4" maxlength="3000" style="width: 100%; font-size: 1.08em; border-radius: 8px; border: 1px solid #bcd0ee; padding: 10px; resize: vertical; background: #fff; box-shadow: 0 1px 4px #0001; min-height: 60px;"></textarea> |
|
|
<div style="display: flex; gap: 10px; margin-top: 6px;"> |
|
|
<button (click)="submitCombinedAnswer()" class="small-btn" style="background: linear-gradient(90deg,#3a8bfd,#6ad1ff); color: #fff; border-radius: 6px; font-weight: 500; padding: 7px 18px; border: none; box-shadow: 0 1px 4px #0001; cursor: pointer;">Submit Answer</button> |
|
|
<button (click)="toggleVoiceRecording()" class="mic-btn" style="background: #fff; color: #3a8bfd; border-radius: 6px; font-weight: 500; padding: 7px 18px; border: 1px solid #3a8bfd; box-shadow: 0 1px 4px #0001; cursor: pointer;"> |
|
|
<span *ngIf="!isVoiceRecording">🎤 Start Recording</span> |
|
|
<span *ngIf="isVoiceRecording">⏹️ Stop Recording</span> |
|
|
</button> |
|
|
</div> |
|
|
<div *ngIf="isVoiceRecording" class="voice-hint" style="color: #e74c3c; font-weight: 500; margin-top: 4px;">🎤 Recording... Speak now.</div> |
|
|
|
|
|
<div class="results-section" style="display: flex; flex-direction: column; gap: 16px; margin-top: 10px;"> |
|
|
<div *ngIf="truthScore !== null" class="result-card" style="background: #e0f7fa; border-radius: 10px; box-shadow: 0 1px 6px #38bdf822; padding: 12px 16px; margin-bottom: 0;"> |
|
|
<div style="display: flex; align-items: center; gap: 10px;"> |
|
|
<i class="fas fa-check-circle" style="color: #38bdf8; font-size: 1.3em;"></i> |
|
|
<span style="font-weight: 600; color: #2563eb; font-size: 1.08em;">Truth Score</span> |
|
|
<span style="font-weight: 700; color: #222; font-size: 1.15em; margin-left: auto;">{{ truthScore }}</span> |
|
|
</div> |
|
|
</div> |
|
|
<div *ngIf="faceDetectionScore !== null" class="result-card" style="background: #fffde7; border-radius: 10px; box-shadow: 0 1px 6px #ffe08244; padding: 12px 16px; margin-bottom: 0;"> |
|
|
<div style="display: flex; align-items: center; gap: 10px;"> |
|
|
<i class="fas fa-user-check" style="color: #ff9800; font-size: 1.3em;"></i> |
|
|
<span style="font-weight: 600; color: #ff9800; font-size: 1.08em;">Face Detection Score</span> |
|
|
<span style="font-weight: 700; color: #222; font-size: 1.15em; margin-left: auto;">{{ faceDetectionScore }}</span> |
|
|
</div> |
|
|
</div> |
|
|
<div *ngIf="involvementScore !== null" class="result-card" style="background: #f3e8ff; border-radius: 10px; box-shadow: 0 1px 6px #a78bfa44; padding: 12px 16px; margin-bottom: 0;"> |
|
|
<div style="font-weight:600;color:#6d28d9;display:flex;align-items:center;gap:8px;"> |
|
|
<i class="fas fa-user-tag" style="color: #6d28d9; font-size: 1.3em;"></i> |
|
|
<span>Involvement Score</span> |
|
|
<span style="font-weight: 700; color: #222; font-size: 1.15em; margin-left: auto;">{{ involvementScore | number:'1.1-1' }}</span> |
|
|
</div> |
|
|
<div style="flex:1;background:#e0ecf8;height:14px;border-radius:6px;overflow:hidden;margin-top:8px;"> |
|
|
<div [style.width]="involvementScore + '%'" [style.background]="'linear-gradient(90deg,#4caf50,#ff9800,#f44336)'" style="height:100%;"></div> |
|
|
</div> |
|
|
<div *ngIf="involvementCues.length" style="margin-top:6px;display:flex;flex-wrap:wrap;gap:6px;"> |
|
|
<span *ngFor="let cue of involvementCues" style="background:#3a8bfd11;color:#1d3e63;padding:4px 10px;border:1px solid #3a8bfd33;border-radius:16px;font-size:0.75rem;font-weight:500;">{{ cue.replace('_cue','').replace('_',' ') }}</span> |
|
|
</div> |
|
|
<div *ngIf="dominantInvestigativeExpression" style="margin-top:4px;font-size:0.75rem;color:#445;">Dominant Investigative Expression: <strong>{{ dominantInvestigativeExpression }}</strong></div> |
|
|
<div class="body-language-explanation" *ngIf="bodyLanguageMeaning || bodyLanguageExplanation"> |
|
|
<span *ngIf="bodyLanguageMeaning" class="explanation-label">Body Language Meaning:</span> |
|
|
<span *ngIf="bodyLanguageMeaning" class="explanation-text">{{ bodyLanguageMeaning }}</span><br *ngIf="bodyLanguageMeaning && bodyLanguageExplanation"> |
|
|
<span *ngIf="bodyLanguageExplanation" class="explanation-label">Body Language Explanation:</span> |
|
|
<span *ngIf="bodyLanguageExplanation" class="explanation-text">{{ bodyLanguageExplanation }}</span> |
|
|
</div> |
|
|
</div> |
|
|
<div *ngIf="ferEmotion" class="result-card" style="background: #e3f6ff; border-radius: 10px; box-shadow: 0 1px 6px #38bdf822; padding: 12px 16px; margin-bottom: 0;"> |
|
|
<div style="display: flex; align-items: center; gap: 10px;"> |
|
|
<i class="fas fa-smile" style="color: #38bdf8; font-size: 1.3em;"></i> |
|
|
<span style="font-weight: 600; color: #2563eb; font-size: 1.08em;">Emotion (FER)</span> |
|
|
<span style="font-weight: 700; color: #222; font-size: 1.15em; margin-left: auto;">{{ ferEmotion }}</span> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<div *ngIf="guidanceCommand" style="margin-top:6px;font-size:0.72rem;color:#555;background:#ffeecd;padding:6px 8px;border-radius:6px;box-shadow:0 1px 3px #0001;">Guidance: {{ guidanceCommand }}</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</section> |
|
|
|
|
|
<section class="right-panel"> |
|
|
<div class="video-preview"> |
|
|
<ng-container *ngIf="!videoStream"> |
|
|
<div class="camera-inactive-block"> |
|
|
<i class="fas fa-camera camera-placeholder-icon"></i> |
|
|
<div class="camera-inactive-title">Camera Inactive</div> |
|
|
<div class="camera-inactive-sub">Click "Start Investigation" to begin video recording</div> |
|
|
</div> |
|
|
</ng-container> |
|
|
<ng-container *ngIf="videoStream"> |
|
|
<video #videoElement [srcObject]="videoStream" autoplay muted playsinline class="camera-video"></video> |
|
|
<div *ngIf="isRecording && currentQuestionIndex >= 0 && currentQuestionIndex < totalQuestions" class="recording-indicator"> |
|
|
<span style="font-size:1.3em;">🔴</span> Recording... |
|
|
</div> |
|
|
<div class="video-status stylish-font">{{ videoStatus }}</div> |
|
|
<div class="waveform-animation" *ngIf="isRecording"> |
|
|
<span></span><span></span><span></span><span></span><span></span> |
|
|
</div> |
|
|
</ng-container> |
|
|
</div> |
|
|
<div class="section-line"></div> |
|
|
<div class="transcript-panel"> |
|
|
<div class="transcript-title">Transcription (Live):</div> |
|
|
<div class="transcript-scrollable"> |
|
|
<div *ngFor="let line of transcriptLines" class="transcript-line">{{ line }}</div> |
|
|
</div> |
|
|
</div> |
|
|
<button class="submit-evaluate-btn" (click)="navigateToValidationPage()"> |
|
|
Submit & Evaluate |
|
|
</button> |
|
|
|
|
|
</section> |
|
|
</main> |
|
|
|
|
|
<div class="evidence-sidebar" [class.open]="showEvidencePanel"> |
|
|
<div class="evidence-title-bar"> |
|
|
<span class="evidence-title">Evidence Panel</span> |
|
|
<button class="evidence-close-btn" (click)="showEvidencePanel = false" title="Close"> |
|
|
<i class="fas fa-times"></i> |
|
|
</button> |
|
|
</div> |
|
|
<div class="evidence-form-card"> |
|
|
<form class="evidence-upload-form" (submit)="$event.preventDefault(); uploadDocument()"> |
|
|
<div class="evidence-upload-row"> |
|
|
<label for="evidenceFileDoc" class="evidence-upload-label"> |
|
|
<i class="fas fa-file-upload evidence-field-icon"></i> |
|
|
<span>Upload Document</span> |
|
|
</label> |
|
|
<input id="evidenceFileDoc" type="file" (change)="onEvidenceFileSelect($event, 'document')" /> |
|
|
</div> |
|
|
<div class="evidence-upload-row"> |
|
|
<label for="evidenceFilePhoto" class="evidence-upload-label"> |
|
|
<i class="fas fa-image evidence-field-icon"></i> |
|
|
<span>Upload Photo</span> |
|
|
</label> |
|
|
<input id="evidenceFilePhoto" type="file" accept="image/*" (change)="onEvidenceFileSelect($event, 'photo')" /> |
|
|
</div> |
|
|
<div class="evidence-upload-row"> |
|
|
<label for="evidenceFileRec" class="evidence-upload-label"> |
|
|
<i class="fas fa-microphone evidence-field-icon"></i> |
|
|
<span>Upload Recording</span> |
|
|
</label> |
|
|
<input id="evidenceFileRec" type="file" accept="audio/*,video/*" (change)="onEvidenceFileSelect($event, 'recording')" /> |
|
|
</div> |
|
|
<hr class="evidence-divider" /> |
|
|
<div class="evidence-summary-row"> |
|
|
<label for="evidenceSummary" class="evidence-summary-label">Remark</label> |
|
|
<textarea id="evidenceSummary" [(ngModel)]="evidenceSummary" [ngModelOptions]="{standalone: true}" rows="3" placeholder="Enter Remark..." class="evidence-summary-textarea"></textarea> |
|
|
</div> |
|
|
<button type="submit" class="evidence-submit-btn">Submit</button> |
|
|
</form> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="summary-sidebar" [class.open]="showSummaryPanel"> |
|
|
<div class="summary-title-bar"> |
|
|
<span class="summary-title">Investigation Summary</span> |
|
|
<button class="summary-close-btn" (click)="showSummaryPanel = false" title="Close"> |
|
|
<i class="fas fa-times"></i> |
|
|
</button> |
|
|
</div> |
|
|
<div class="summary-content-card"> |
|
|
<div class="case-section-title">Case Details</div> |
|
|
<div class="case-row"><span class="case-label">Case ID:</span> <span class="case-value">{{ caseId }}</span></div> |
|
|
<div class="case-row"><span class="case-label">Crime Type:</span> <span class="case-value">{{ crimeType }}</span></div> |
|
|
<div class="case-row"><span class="case-label">Date & Time:</span> <span class="case-value">{{ dateTime }}</span></div> |
|
|
<div class="case-row"><span class="case-label">Location:</span> <span class="case-value">{{ location }}</span></div> |
|
|
<div class="divider-line"></div> |
|
|
<div class="case-section-title">Person Details</div> |
|
|
<div class="case-row"><span class="case-label">Suspect Name:</span> <span class="case-value">{{ suspectName }}</span></div> |
|
|
<div class="case-row"><span class="case-label">Investigation Officer:</span> <span class="case-value">{{ investigationOfficer }}</span></div> |
|
|
<div class="divider-line"></div> |
|
|
<div class="case-section-title">Progress Details</div> |
|
|
<div class="case-row"><span class="case-label">Status:</span> <span class="case-value">{{ statusText }}</span></div> |
|
|
<div class="case-row"><span class="case-label">Progress:</span> <span class="case-value">{{progress}}% (Stage: {{ progressStage }})</span></div> |
|
|
<div class="case-row"><span class="case-label">Session Time:</span> <span class="case-value">{{ sessionTime }}</span></div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="blur-bg" [class.hide]="!showEvidencePanel && !showSummaryPanel"></div> |
|
|
|
|
|
<footer> |
|
|
<p>© 2025 Pykara Technologies Pvt. Ltd. All rights reserved.</p> |
|
|
</footer> |
|
|
|
|
|
|