Py-detect / src /app /py-detect /py-detect.component.html
pykara's picture
fix
73566f6
raw
history blame
15 kB
<!-- Modern UI header with logo and PyDetect title -->
<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>
<!-- Header action bar with buttons and divider line -->
<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>
<!-- Investigation Summary Toggle Button (moved below header, above camera box) -->
<main class="main-flex-layout">
<!-- Left Panel: Case Info + Question -->
<section class="left-panel">
<div class="animated-divider"></div>
<!-- Remove old question/status block, keep only the new decorated card -->
<!-- In tts-question-card, show AI question if available -->
<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>
<!-- Manual answer input for testing -->
<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>
<!-- Results Section: Truth Score, Face Detection, Involvement -->
<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>
<!-- Right Panel: Video + Transcript -->
<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>
<!-- <a *ngIf="recordedVideoUrl" [href]="recordedVideoUrl" download="investigation-video.webm" class="download-btn" style="margin-left: 12px; background: #3a8bfd; color: #fff; padding: 10px 22px; border-radius: 8px; font-weight: 500; text-decoration: none; box-shadow: 0 1px 4px #0001; vertical-align: middle;">Download Video</a> -->
</section>
</main>
<!-- Evidence Panel Sidebar (directly below button bar) -->
<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>
<!-- Summary Sidebar -->
<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>
<!-- Blur background when evidence or summary panel is open -->
<div class="blur-bg" [class.hide]="!showEvidencePanel && !showSummaryPanel"></div>
<footer>
<p>© 2025 Pykara Technologies Pvt. Ltd. All rights reserved.</p>
</footer>