InterroGen / app /templates /case_detail.html
yasserrmd's picture
Upload 21 files
e6ecc60 verified
{% extends "base_layout.html" %}
{% block title %}Case Details: {{ case.case_id_display }} - InterroGen{% endblock %}
{% block head_extra %}
<style>
.json-display {
background-color: #f8f9fa;
border: 1px solid #dee2e6;
padding: 15px;
border-radius: 5px;
white-space: pre-wrap;
word-wrap: break-word;
max-height: 400px; /* Added for scrollability */
overflow-y: auto; /* Added for scrollability */
}
.case-info-pre {
background-color: #f8f9fa;
border: 1px solid #eee;
padding: 10px;
border-radius: 4px;
white-space: pre-wrap;
word-wrap: break-word;
font-family: monospace;
}
</style>
{% endblock %}
{% block page_content %}
<div class="heading-container">
<h1 class="h3">Case Details: {{ case.case_id_display }}</h1>
<div>
<a href="{{ url_for('manage_cases') }}" class="btn btn-outline-secondary"><i class="bi bi-arrow-left-circle me-1"></i>Back to Cases List</a>
</div>
</div>
<div class="row">
<div class="col-lg-7">
<div class="card mb-3">
<div class="card-header">
<i class="bi bi-file-text me-2"></i>Case Information
</div>
<div class="card-body">
<dl class="row">
<dt class="col-sm-4">Case ID:</dt>
<dd class="col-sm-8">{{ case.case_id_display }}</dd>
<dt class="col-sm-4">Case Type:</dt>
<dd class="col-sm-8">{{ case.case_type }}</dd>
<dt class="col-sm-4">Suspect Name:</dt>
<dd class="col-sm-8">{{ case.suspect_name }}</dd>
<dt class="col-sm-4">Status:</dt>
<dd class="col-sm-8"><span class="case-status status-{{ case.status.value.lower() }}">{{ case.status.value }}</span></dd>
<dt class="col-sm-4">Created At:</dt>
<dd class="col-sm-8">{{ case.created_at.strftime('%Y-%m-%d %H:%M:%S') }}</dd>
<dt class="col-sm-4">Last Updated:</dt>
<dd class="col-sm-8">{{ case.updated_at.strftime('%Y-%m-%d %H:%M:%S') }}</dd>
<dt class="col-sm-4">Country Context:</dt>
<dd class="col-sm-8">{{ case.country_context.name if case.country_context else 'N/A' }}</dd>
</dl>
<hr>
<h6>Profile Details:</h6>
<div class="case-info-pre">{{ case.profile_details if case.profile_details else 'Not provided' }}</div>
<h6 class="mt-3">Evidence Summary:</h6>
<div class="case-info-pre">{{ case.evidence_summary if case.evidence_summary else 'Not provided' }}</div>
</div>
</div>
<div class="card mb-3">
<div class="card-header">
<i class="bi bi-journal-richtext me-2"></i>Generated Reports for this Case
</div>
<div class="card-body">
{% if case.reports %}
<ul class="list-group list-group-flush">
{% for report in case.reports %}
<li class="list-group-item d-flex justify-content-between align-items-center">
Report generated on {{ report.generated_at.strftime('%Y-%m-%d %H:%M') }} (Country: {{ report.report_country_context.name if report.report_country_context else 'N/A' }})
<a href="{{ url_for('view_report', report_id=report.id) }}" class="btn btn-sm btn-outline-info">View Report</a>
</li>
{% endfor %}
</ul>
{% else %}
<p class="text-muted">No reports generated for this case yet.</p>
{% endif %}
</div>
</div>
</div>
<div class="col-lg-5">
<div class="card mb-3">
<div class="card-header">
<i class="bi bi-patch-question-fill me-2"></i>Interrogation Questions
</div>
<div class="card-body">
<button id="generateQuestionsBtn" class="btn btn-primary w-100 mb-3" data-case-id="{{ case.id }}">
<i class="bi bi-magic me-1"></i> Generate Interrogation Questions (LLM)
</button>
<div id="questionsArea">
{% if case.interrogation_sessions %}
{% for session in case.interrogation_sessions | sort(attribute='session_date', reverse=True) %}
<div class="accordion mb-2" id="accordionSession{{ session.id }}">
<div class="accordion-item">
<h2 class="accordion-header" id="headingSession{{ session.id }}">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseSession{{ session.id }}" aria-expanded="false" aria-controls="collapseSession{{ session.id }}">
Session on {{ session.session_date.strftime('%Y-%m-%d %H:%M') }} ({{ session.generated_questions | length }} Qs)
</button>
</h2>
<div id="collapseSession{{ session.id }}" class="accordion-collapse collapse" aria-labelledby="headingSession{{ session.id }}" data-bs-parent="#accordionSession{{ session.id }}">
<div class="accordion-body">
{% if session.summary_notes %}
<p><strong>Notes:</strong> {{ session.summary_notes }}</p>
{% endif %}
{% if session.generated_questions %}
<ul class="list-group list-group-flush">
{% for q in session.generated_questions %}
<li class="list-group-item">{{ q.question_text }} <small class="text-muted">({{ q.category }})</small></li>
{% endfor %}
</ul>
{% else %}
<p class="text-muted">No questions recorded for this session.</p>
{% endif %}
</div>
</div>
</div>
</div>
{% endfor %}
{% else %}
<p class="text-muted text-center mt-3">No interrogation sessions found. Click button to generate questions for a new session.</p>
{% endif %}
</div>
</div>
</div>
<div class="card mb-3">
<div class="card-header">
<i class="bi bi-file-earmark-medical-fill me-2"></i>Generate New Report (LLM)
</div>
<div class="card-body">
<form id="generateReportForm">
<div class="mb-3">
<label for="country_id_report" class="form-label">Select Country for Report Recommendations: <span class="text-danger">*</span></label>
<select class="form-select" id="country_id_report" name="country_id" required>
<option value="">Select Country</option>
{% for country in countries %}
<option value="{{ country.id }}" {% if case.country_context and case.country_context.id == country.id %}selected{% endif %}>{{ country.name }}</option>
{% endfor %}
</select>
</div>
<div class="mb-3">
<label for="interrogation_summary_manual" class="form-label">Additional Interrogation Summary (Optional):</label>
<textarea class="form-control" id="interrogation_summary_manual" name="interrogation_summary" rows="4" placeholder="Add any manual notes or summary of the interrogation to be included in the report generation prompt. Data from saved questions/answers will be automatically included."></textarea>
</div>
<button type="submit" class="btn btn-success w-100" data-case-id="{{ case.id }}">
<i class="bi bi-lightning-charge-fill me-1"></i> Generate Report
</button>
</form>
<div id="reportResultArea" class="mt-3"></div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
document.addEventListener('DOMContentLoaded', function() {
const generateQuestionsBtn = document.getElementById('generateQuestionsBtn');
const questionsArea = document.getElementById('questionsArea');
if(generateQuestionsBtn) {
generateQuestionsBtn.addEventListener('click', function() {
const caseId = this.dataset.caseId;
this.disabled = true;
this.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Generating...';
fetch(`/generate_questions/${caseId}`, { method: 'POST' })
.then(response => {
if (!response.ok) {
return response.json().then(err => { throw err; });
}
return response.json();
})
.then(data => {
if(data.error) {
alert('Error: ' + data.error);
return;
}
// Instead of replacing, we just inform and ask to refresh for simplicity now
// Or, ideally, dynamically add the new session and questions to the accordion
alert('Questions generated successfully! They have been saved to a new interrogation session. Please refresh the page to see them.');
window.location.reload(); // Simple refresh to show new data
})
.catch(error => {
console.error('Error generating questions:', error);
alert('Failed to generate questions: ' + (error.error || 'Unknown error'));
})
.finally(() => {
this.disabled = false;
this.innerHTML = '<i class="bi bi-magic me-1"></i> Generate Interrogation Questions (LLM)';
});
});
}
const generateReportForm = document.getElementById('generateReportForm');
const reportResultArea = document.getElementById('reportResultArea');
if(generateReportForm) {
generateReportForm.addEventListener('submit', function(event) {
event.preventDefault();
const submitButton = this.querySelector('button[type="submit"]');
const caseId = submitButton.dataset.caseId;
const countryId = document.getElementById('country_id_report').value;
const interrogationSummary = document.getElementById('interrogation_summary_manual').value;
if (!countryId) {
alert('Please select a country for the report recommendations.');
return;
}
submitButton.disabled = true;
submitButton.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Generating Report...';
reportResultArea.innerHTML = '<div class="alert alert-info">Generating report, please wait...</div>';
fetch(`/generate_report/${caseId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ country_id: countryId, interrogation_summary: interrogationSummary })
})
.then(response => {
if (!response.ok) {
return response.json().then(err => { throw err; });
}
return response.json();
})
.then(data => {
if(data.error) {
reportResultArea.innerHTML = `<div class="alert alert-danger">Error: ${data.error}</div>`;
return;
}
let reportJsonParsed = {};
try {
reportJsonParsed = JSON.parse(data.raw_json_report);
} catch (e) {
console.warn("Could not parse raw_json_report for pretty print", e);
reportJsonParsed = data.raw_json_report; // show as string if not parsable
}
reportResultArea.innerHTML = `<div class="alert alert-success">Report generated successfully! Report ID: ${data.report_id}</div> \
<h6>Raw LLM Output (JSON):</h6> \
<div class="json-display">${JSON.stringify(reportJsonParsed, null, 2)}</div> \
<p class="mt-2"><a href="/report/${data.report_id}" class="btn btn-info mt-2"><i class="bi bi-eye-fill me-1"></i>View Formatted Report</a></p><p class="text-muted"><small>Page will refresh to show the new report in the list below.</small></p>`;
setTimeout(() => { window.location.reload(); }, 3000); // Refresh to update list
})
.catch(error => {
console.error('Error generating report:', error);
reportResultArea.innerHTML = `<div class="alert alert-danger">Failed to generate report: ${(error.error || 'Unknown error')}. Check console.</div>`;
})
.finally(() => {
submitButton.disabled = false;
submitButton.innerHTML = '<i class="bi bi-lightning-charge-fill me-1"></i> Generate Report';
});
});
}
});
</script>
{% endblock %}