Compare commits

...

1 Commits

Author SHA1 Message Date
Flatlogic Bot
07aa353708 1 2025-11-24 15:14:58 +00:00
11 changed files with 907 additions and 131 deletions

230
api.php Normal file
View File

@ -0,0 +1,230 @@
<?php
header('Content-Type: application/json');
require_once 'db/config.php';
require_once 'templates/arrest_memo.php';
require_once 'templates/bail_reply.php';
require_once 'templates/chargesheet.php';
// Handle File Uploads
if (isset($_POST['action']) && $_POST['action'] == 'upload_file') {
$fir_no = $_POST['case_id'] ?? null; // This is the FIR No from the form
$file = $_FILES['file'] ?? null;
if ($fir_no && $file && $file['error'] == UPLOAD_ERR_OK) {
$pdo = db();
$stmt_case = $pdo->prepare("SELECT id FROM cases WHERE fir_no = :fir_no");
$stmt_case->execute([':fir_no' => $fir_no]);
$case = $stmt_case->fetch();
if ($case) {
$case_id = $case['id'];
$upload_dir = __DIR__ . '/uploads/';
// Sanitize the filename to prevent directory traversal issues
$file_basename = basename($file['name']);
$file_name = uniqid() . '-' . preg_replace("/[^a-zA-Z0-9._-]", "", $file_basename);
$file_path = $upload_dir . $file_name;
$relative_path = 'uploads/' . $file_name;
if (move_uploaded_file($file['tmp_name'], $file_path)) {
$stmt_insert = $pdo->prepare("INSERT INTO case_files (case_id, file_name, file_path) VALUES (:case_id, :file_name, :file_path)");
$stmt_insert->execute([
':case_id' => $case_id,
':file_name' => $file_basename, // Store original filename
':file_path' => $relative_path
]);
echo json_encode(['success' => true, 'message' => 'File uploaded successfully.', 'file_path' => $relative_path]);
} else {
echo json_encode(['success' => false, 'message' => 'Failed to move uploaded file. Check directory permissions.']);
}
} else {
echo json_encode(['success' => false, 'message' => 'Case with FIR No ' . htmlspecialchars($fir_no) . ' not found.']);
}
} else {
$error_message = 'Invalid request.';
if ($file && $file['error'] !== UPLOAD_ERR_OK) {
$error_message = 'File upload error: ' . $file['error'];
}
echo json_encode(['success' => false, 'message' => $error_message]);
}
exit;
}
$pdo = db();
if (isset($_GET['action']) && $_GET['action'] == 'get_reports') {
$stmt = $pdo->query("SELECT r.id, r.report_type, r.created_at, c.fir_no FROM reports r JOIN cases c ON r.case_id = c.id ORDER BY r.created_at DESC");
$reports = $stmt->fetchAll();
echo json_encode($reports);
exit;
}
if (isset($_GET['action']) && $_GET['action'] == 'get_case' && isset($_GET['fir_no'])) {
$stmt = $pdo->prepare("SELECT * FROM cases WHERE fir_no = :fir_no");
$stmt->execute([':fir_no' => $_GET['fir_no']]);
$case = $stmt->fetch();
if ($case) {
echo json_encode($case);
} else {
echo json_encode(['error' => 'Case not found']);
}
exit;
}
if (isset($_GET['action']) && $_GET['action'] == 'get_report' && isset($_GET['id'])) {
$stmt = $pdo->prepare("SELECT content FROM reports WHERE id = :id");
$stmt->execute([':id' => $_GET['id']]);
$report = $stmt->fetch();
if ($report) {
echo json_encode($report);
} else {
echo json_encode(['error' => 'Report not found']);
}
exit;
}
$input = json_decode(file_get_contents('php://input'), true);
$message = $input['message'] ?? '';
$reply = 'I am sorry, I do not understand. Please ask me to find a case, for example: \'find case 684/25\'.';
// Simple intent parsing
if (preg_match('/(find|search|get|show)\s+(case|fir|for|about)\s+(.+)/i', $message, $matches)) {
$search_term = trim($matches[3]);
$search_query = "%{$search_term}%";
$stmt = $pdo->prepare("SELECT * FROM cases WHERE fir_no LIKE :term OR accused_name LIKE :term OR sections LIKE :term OR ps LIKE :term");
$stmt->execute([':term' => $search_query]);
$found_cases = $stmt->fetchAll();
if ($found_cases) {
if (count($found_cases) == 1) {
$found_case = $found_cases[0];
$reply = "Found Case File: FIR-" . $found_case['fir_no'] . "\n";
$reply .= "PS: " . $found_case['ps'] . "\n";
$reply .= "Accused: " . $found_case['accused_name'] . "\n";
$reply .= "Sections: " . $found_case['sections'] . "\n";
$reply .= "Facts: " . $found_case['facts'];
} else {
$reply = "I found multiple cases. Please be more specific.\n\n";
foreach ($found_cases as $case) {
$reply .= "- FIR " . $case['fir_no'] . " (" . $case['accused_name'] . ")\n";
}
}
} else {
$reply = "I could not find any case matching '{$search_term}'.";
}
} elseif (preg_match('/^update case ([\d\/-]+) set (.+)/i', $message, $matches)) {
$fir_no = trim($matches[1]);
$update_string = trim($matches[2]);
// Check if case exists
$stmt = $pdo->prepare("SELECT id FROM cases WHERE fir_no = :fir_no");
$stmt->execute([':fir_no' => $fir_no]);
$case_to_update = $stmt->fetch();
if ($case_to_update) {
$allowed_fields = ['ps', 'accused_name', 'sections', 'complainant', 'address', 'facts'];
$updates = [];
$params = [':fir_no' => $fir_no];
// Parse the update string for key-value pairs
preg_match_all('/(\w+):((?:(?!, \w+:).)+)/i', $update_string, $update_matches, PREG_SET_ORDER);
foreach ($update_matches as $match) {
$field = strtolower(trim($match[1]));
$value = trim($match[2]);
if (in_array($field, $allowed_fields)) {
$updates[] = "{$field} = :{$field}";
$params[":{$field}"] = $value;
}
}
if (!empty($updates)) {
$sql = "UPDATE cases SET " . implode(', ', $updates) . " WHERE fir_no = :fir_no";
try {
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
$reply = "Successfully updated case FIR No: {$fir_no}.";
} catch (PDOException $e) {
$reply = "Error updating case: " . $e->getMessage();
}
} else {
$reply = "No valid fields to update. You can update: ps, accused_name, sections, complainant, address, facts.";
}
} else {
$reply = "Sorry, I couldn't find a case with FIR No: {$fir_no} to update.";
}
} elseif (preg_match('/^create case/i', $message)) {
// Parsing key-value pairs from the message
$fir_no = preg_match('/fir_no:([^,]+)/i', $message, $m) ? trim($m[1]) : '';
$ps = preg_match('/ps:([^,]+)/i', $message, $m) ? trim($m[1]) : '';
$accused_name = preg_match('/accused:([^,]+)/i', $message, $m) ? trim($m[1]) : '';
$sections = preg_match('/sections:([^,]+)/i', $message, $m) ? trim($m[1]) : '';
$complainant = preg_match('/complainant:([^,]+)/i', $message, $m) ? trim($m[1]) : '';
$address = preg_match('/address:([^,]+)/i', $message, $m) ? trim($m[1]) : '';
$facts = preg_match('/facts:(.+)/i', $message, $m) ? trim($m[1]) : '';
if ($fir_no && $ps && $accused_name && $sections) {
try {
$stmt = $pdo->prepare("INSERT INTO cases (fir_no, ps, accused_name, sections, complainant, address, facts) VALUES (:fir_no, :ps, :accused_name, :sections, :complainant, :address, :facts)");
$stmt->execute([
':fir_no' => $fir_no,
':ps' => $ps,
':accused_name' => $accused_name,
':sections' => $sections,
':complainant' => $complainant,
':address' => $address,
':facts' => $facts
]);
$reply = "Successfully created new case with FIR No: {$fir_no}.";
} catch (PDOException $e) {
$reply = "Error creating case: " . $e->getMessage();
}
} else {
$reply = "Sorry, I couldn't create the case. Please provide at least 'fir_no', 'ps', 'accused', and 'sections'.";
}
} elseif (preg_match('/generate\s+(.+?)\s+for\s+(case|fir)\s+([\d\/-]+)/i', $message, $matches)) {
$report_type = trim($matches[1]);
$fir_no = str_replace('-', '/', $matches[3]);
$stmt = $pdo->prepare("SELECT * FROM cases WHERE fir_no = :fir_no");
$stmt->execute([':fir_no' => $fir_no]);
$found_case = $stmt->fetch();
if ($found_case) {
$generated_report = null;
$report_type_code = '';
if (strcasecmp($report_type, 'arrest memo') === 0) {
$generated_report = generate_arrest_memo($found_case);
$report_type_code = 'ARREST_MEMO';
} elseif (strcasecmp($report_type, 'bail reply') === 0) {
$generated_report = generate_bail_reply($found_case);
$report_type_code = 'BAIL_REPLY';
} elseif (strcasecmp($report_type, 'chargesheet') === 0) {
$generated_report = generate_chargesheet($found_case);
$report_type_code = 'CHARGESHEET';
} else {
$reply = "I can generate 'arrest memo', 'bail reply', or 'chargesheet' reports.";
}
if ($generated_report) {
$stmt = $pdo->prepare("INSERT INTO reports (case_id, report_type, content) VALUES (:case_id, :report_type, :content)");
$stmt->execute([
':case_id' => $found_case['id'],
':report_type' => $report_type_code,
':content' => $generated_report
]);
$report_id = $pdo->lastInsertId();
$reply = "I have generated the '{$report_type}' (ID: {$report_id}) for FIR {$fir_no}. You can view it in the reports section.";
}
} else {
$reply = "I could not find any case file with FIR number: " . $fir_no . " to generate a report.";
}
}
echo json_encode(['reply' => $reply]);

132
assets/css/custom.css Normal file
View File

@ -0,0 +1,132 @@
:root {
--primary-color: #0A2342;
--accent-color: #2CA58D;
--background-color: #F8F9FA;
--surface-color: #FFFFFF;
--text-color: #212529;
--font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}
body {
background-color: var(--background-color);
font-family: var(--font-family);
color: var(--text-color);
display: flex;
flex-direction: column;
height: 100vh;
margin: 0;
}
.header {
background: linear-gradient(135deg, var(--primary-color), #123A63);
color: white;
padding: 1rem 1.5rem;
display: flex;
align-items: center;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.header h1 {
margin: 0;
font-size: 1.5rem;
font-weight: 600;
}
.header .icon {
margin-right: 0.75rem;
}
.chat-container {
flex-grow: 1;
overflow-y: auto;
padding: 1.5rem;
display: flex;
flex-direction: column;
gap: 1rem;
}
.chat-bubble {
padding: 0.75rem 1.25rem;
border-radius: 0.75rem;
max-width: 75%;
line-height: 1.6;
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
}
.chat-bubble.user {
background-color: var(--primary-color);
color: white;
align-self: flex-end;
border-bottom-right-radius: 0.25rem;
}
.chat-bubble.ai {
background-color: var(--surface-color);
color: var(--text-color);
align-self: flex-start;
border-bottom-left-radius: 0.25rem;
}
.chat-bubble.ai pre {
white-space: pre-wrap;
font-family: inherit;
margin: 0;
}
.chat-input-form {
display: flex;
padding: 1rem 1.5rem;
background-color: var(--surface-color);
border-top: 1px solid #dee2e6;
}
.chat-input-form input {
flex-grow: 1;
border: 1px solid #ced4da;
padding: 0.75rem 1rem;
border-radius: 0.5rem;
margin-right: 0.5rem;
font-size: 1rem;
}
.chat-input-form input:focus {
outline: none;
border-color: var(--accent-color);
box-shadow: 0 0 0 2px rgba(44, 165, 141, 0.25);
}
.chat-input-form button {
background-color: var(--accent-color);
border: none;
color: white;
padding: 0.75rem 1.25rem;
border-radius: 0.5rem;
cursor: pointer;
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 1rem;
font-weight: 500;
transition: background-color 0.2s ease;
}
.chat-input-form button:hover {
background-color: #238a75;
}
.thinking-indicator span {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
background-color: #999;
animation: bounce 1.4s infinite ease-in-out both;
}
.thinking-indicator span:nth-child(1) { animation-delay: -0.32s; }
.thinking-indicator span:nth-child(2) { animation-delay: -0.16s; }
@keyframes bounce {
0%, 80%, 100% { transform: scale(0); }
40% { transform: scale(1.0); }
}

234
assets/js/main.js Normal file
View File

@ -0,0 +1,234 @@
document.addEventListener('DOMContentLoaded', () => {
const chatContainer = document.getElementById('chat-container');
const chatForm = document.getElementById('chat-form');
const messageInput = document.getElementById('message-input');
const reportsTab = document.getElementById('reports-tab');
const reportsContainer = document.getElementById('reports-container');
const uploadBtn = document.getElementById('upload-btn');
const uploadModal = new bootstrap.Modal(document.getElementById('uploadModal'));
const uploadForm = document.getElementById('upload-form');
const uploadCaseIdInput = document.getElementById('upload-case-id');
const fileInput = document.getElementById('file-input');
const scrollToBottom = () => {
chatContainer.scrollTop = chatContainer.scrollHeight;
};
const addMessage = (role, content, isThinking = false) => {
const bubble = document.createElement('div');
bubble.classList.add('chat-bubble', role);
if (isThinking) {
bubble.innerHTML = `<div class="thinking-indicator"><span></span><span></span><span></span></div>`;
bubble.id = 'thinking-bubble';
} else {
const pre = document.createElement('pre');
pre.innerHTML = content; // Use innerHTML to render links
bubble.appendChild(pre);
}
chatContainer.appendChild(bubble);
scrollToBottom();
return bubble;
};
const handleUploadCommand = (firNo) => {
// Simple check, backend will do the real validation
if(firNo) {
uploadCaseIdInput.value = firNo; // We'll use FIR no to find case in backend
const modalBody = document.querySelector('#uploadModal .modal-body p');
modalBody.innerHTML = `Select a file to upload for case <strong>${firNo}</strong>.`;
uploadModal.show();
} else {
addMessage('ai', 'Please specify a case FIR number to upload a file for, e.g., `upload file for case 123/25`.');
}
};
uploadBtn.addEventListener('click', () => {
// This just opens the modal. The user needs to have specified the case first.
const modalBody = document.querySelector('#uploadModal .modal-body p');
modalBody.innerHTML = 'To upload a file, please first type the command: `upload file for case [FIR NO]`';
uploadModal.show();
});
uploadForm.addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(uploadForm);
const caseId = uploadCaseIdInput.value; // This is the FIR no
formData.set('case_id', caseId); // Ensure case_id is set
if (!fileInput.files || fileInput.files.length === 0) {
addMessage('ai', 'Please select a file to upload.');
return;
}
uploadModal.hide();
addMessage('user', `Uploading file "${fileInput.files[0].name}" for case ${caseId}...`);
const thinkingBubble = addMessage('ai', '', true);
try {
const response = await fetch('api.php', {
method: 'POST',
body: formData
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
thinkingBubble.remove();
if (result.success) {
addMessage('ai', `File uploaded successfully. You can view it here: <a href="${result.file_path}" target="_blank">${result.file_path}</a>`);
} else {
addMessage('ai', `Upload failed: ${result.message || 'Unknown error'}`);
}
} catch (error) {
console.error('Error uploading file:', error);
thinkingBubble.remove();
addMessage('ai', 'An error occurred during the file upload.');
} finally {
uploadForm.reset();
}
});
chatForm.addEventListener('submit', async (e) => {
e.preventDefault();
const message = messageInput.value.trim();
if (!message) return;
addMessage('user', message);
messageInput.value = '';
const uploadMatch = message.match(/upload file for case ([\w\/-]+)/i);
if (uploadMatch && uploadMatch[1]) {
handleUploadCommand(uploadMatch[1]);
return;
}
const thinkingBubble = addMessage('ai', '', true);
try {
const response = await fetch('api.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ message })
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
thinkingBubble.remove();
addMessage('ai', data.reply);
} catch (error) {
console.error('Error fetching AI response:', error);
thinkingBubble.remove();
addMessage('ai', 'Sorry, something went wrong while connecting to the assistant.');
}
});
const fetchReports = async () => {
try {
const response = await fetch('api.php?action=get_reports');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const reports = await response.json();
renderReports(reports);
} catch (error) {
console.error('Error fetching reports:', error);
reportsContainer.innerHTML = '<p class="text-danger">Failed to load reports.</p>';
}
};
const renderReports = (reports) => {
if (!reports || reports.length === 0) {
reportsContainer.innerHTML = '<p>No reports generated yet.</p>';
return;
}
const table = document.createElement('table');
table.className = 'table table-striped';
table.innerHTML = `
<thead>
<tr>
<th>Report ID</th>
<th>FIR No.</th>
<th>Type</th>
<th>Date</th>
<th>Action</th>
</tr>
</thead>
<tbody>
</tbody>
`;
const tbody = table.querySelector('tbody');
reports.forEach(report => {
const tr = document.createElement('tr');
tr.innerHTML = `
<td>${report.id}</td>
<td>${report.fir_no}</td>
<td>${report.report_type}</td>
<td>${new Date(report.created_at).toLocaleString()}</td>
<td><button class="btn btn-sm btn-primary view-report-btn" data-id="${report.id}">View</button></td>
`;
tbody.appendChild(tr);
});
reportsContainer.innerHTML = '';
reportsContainer.appendChild(table);
};
reportsContainer.addEventListener('click', async (e) => {
if (e.target.classList.contains('view-report-btn')) {
const reportId = e.target.dataset.id;
try {
const response = await fetch(`api.php?action=get_report&id=${reportId}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const report = await response.json();
const modal = new bootstrap.Modal(document.getElementById('report-modal'));
document.getElementById('report-modal-title').textContent = `Report #${reportId}`;
document.getElementById('report-modal-body').textContent = report.content;
modal.show();
} catch (error) {
console.error('Error fetching report content:', error);
alert('Failed to load report content.');
}
}
});
reportsTab.addEventListener('show.bs.tab', fetchReports);
// Initial scroll to bottom
scrollToBottom();
// Add a modal for viewing reports to the body
const modalHtml = `
<div class="modal fade" id="report-modal" tabindex="-1" aria-labelledby="report-modal-label" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="report-modal-title">Report</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<pre id="report-modal-body"></pre>
</div>
</div>
</div>
</div>
`;
document.body.insertAdjacentHTML('beforeend', modalHtml);
});

23
data.php Normal file
View File

@ -0,0 +1,23 @@
<?php
function get_mock_cases() {
return [
[
'fir_no' => '684/25',
'ps' => 'Civil Lines',
'accused_name' => 'Raja S/o Ram Singh',
'sections' => '379/411 IPC',
'complainant' => 'Mahesh Kumar',
'address' => 'H.No 12, Block A, Delhi.',
'facts' => 'Accused caught with stolen bike DL-4S-1234.',
],
[
'fir_no' => '102/25',
'ps' => 'Karol Bagh',
'accused_name' => 'Sonu',
'sections' => '25/54/59 Arms Act',
'complainant' => null,
'address' => null,
'facts' => "ITEM: Button actuated knife\nLENGTH: 15cm\nRECOVERED FROM: Right pocket of accused.",
]
];
}

55
db/migrate.php Normal file
View File

@ -0,0 +1,55 @@
<?php
require_once __DIR__ . '/config.php';
try {
$pdo = db();
echo "Connected to database successfully.\n";
$migrations = glob(__DIR__ . '/migrations/*.sql');
sort($migrations);
foreach ($migrations as $migrationFile) {
if (!file_exists($migrationFile)) {
die("Migration file not found: $migrationFile\n");
}
echo "Applying migration: " . basename($migrationFile) . "...\n";
$sql = file_get_contents($migrationFile);
$pdo->exec($sql);
}
echo "Migrations applied successfully.\n";
// Now, let's insert the initial data from data.php into the new 'cases' table.
require_once __DIR__ . '/../data.php';
$stmt = $pdo->prepare(
"INSERT INTO cases (fir_no, ps, accused_name, sections, complainant, address, facts)
VALUES (:fir_no, :ps, :accused_name, :sections, :complainant, :address, :facts)
ON DUPLICATE KEY UPDATE
ps=VALUES(ps),
accused_name=VALUES(accused_name),
sections=VALUES(sections),
complainant=VALUES(complainant),
address=VALUES(address),
facts=VALUES(facts)"
);
$cases = get_mock_cases();
foreach ($cases as $case) {
$stmt->execute([
':fir_no' => $case['fir_no'],
':ps' => $case['ps'],
':accused_name' => $case['accused_name'],
':sections' => $case['sections'],
':complainant' => $case['complainant'],
':address' => $case['address'],
':facts' => $case['facts'],
]);
}
echo "Initial case data seeded into the database.\n";
} catch (PDOException $e) {
die("Database error: " . $e->getMessage() . "\n");
}

View File

@ -0,0 +1,24 @@
CREATE TABLE IF NOT EXISTS `cases` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`fir_no` varchar(255) NOT NULL,
`ps` varchar(255) DEFAULT NULL,
`accused_name` varchar(255) DEFAULT NULL,
`sections` varchar(255) DEFAULT NULL,
`complainant` varchar(255) DEFAULT NULL,
`address` text DEFAULT NULL,
`facts` text DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`),
UNIQUE KEY `fir_no` (`fir_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE IF NOT EXISTS `reports` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`case_id` int(11) NOT NULL,
`report_type` varchar(255) NOT NULL,
`content` longtext NOT NULL,
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`),
KEY `case_id` (`case_id`),
CONSTRAINT `reports_ibfk_1` FOREIGN KEY (`case_id`) REFERENCES `cases` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

View File

@ -0,0 +1,10 @@
CREATE TABLE IF NOT EXISTS `case_files` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`case_id` int(11) NOT NULL,
`file_name` varchar(255) NOT NULL,
`file_path` varchar(255) NOT NULL,
`uploaded_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `case_id` (`case_id`),
CONSTRAINT `case_files_ibfk_1` FOREIGN KEY (`case_id`) REFERENCES `cases` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

222
index.php
View File

@ -1,150 +1,112 @@
<?php <?php
declare(strict_types=1); // Read project preview data from environment
@ini_set('display_errors', '1'); $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'TRINETRA is a personal AI assistant for law enforcement.';
@error_reporting(E_ALL); $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
@date_default_timezone_set('UTC');
$phpVersion = PHP_VERSION;
$now = date('Y-m-d H:i:s');
?> ?>
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<title>New Style</title> <title>TRINETRA - AI Assistant</title>
<?php
// Read project preview data from environment <!-- Dynamic Meta Tags -->
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? ''; <meta name="description" content="<?= htmlspecialchars($projectDescription) ?>" />
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
?>
<?php if ($projectDescription): ?>
<!-- Meta description -->
<meta name="description" content='<?= htmlspecialchars($projectDescription) ?>' />
<!-- Open Graph meta tags -->
<meta property="og:description" content="<?= htmlspecialchars($projectDescription) ?>" />
<!-- Twitter meta tags -->
<meta property="twitter:description" content="<?= htmlspecialchars($projectDescription) ?>" />
<?php endif; ?>
<?php if ($projectImageUrl): ?> <?php if ($projectImageUrl): ?>
<!-- Open Graph image -->
<meta property="og:image" content="<?= htmlspecialchars($projectImageUrl) ?>" /> <meta property="og:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
<!-- Twitter image -->
<meta property="twitter:image" content="<?= htmlspecialchars($projectImageUrl) ?>" /> <meta property="twitter:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
<?php endif; ?> <?php endif; ?>
<meta property="og:title" content="TRINETRA - AI Assistant" />
<meta property="og:description" content="<?= htmlspecialchars($projectDescription) ?>" />
<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:title" content="TRINETRA - AI Assistant" />
<meta property="twitter:description" content="<?= htmlspecialchars($projectDescription) ?>" />
<!-- Fonts and Icons -->
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
<style> <script src="https://unpkg.com/lucide@latest"></script>
:root {
--bg-color-start: #6a11cb; <!-- Styles -->
--bg-color-end: #2575fc; <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
--text-color: #ffffff; <link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
--card-bg-color: rgba(255, 255, 255, 0.01);
--card-border-color: rgba(255, 255, 255, 0.1);
}
body {
margin: 0;
font-family: 'Inter', sans-serif;
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
color: var(--text-color);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
text-align: center;
overflow: hidden;
position: relative;
}
body::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><path d="M-10 10L110 10M10 -10L10 110" stroke-width="1" stroke="rgba(255,255,255,0.05)"/></svg>');
animation: bg-pan 20s linear infinite;
z-index: -1;
}
@keyframes bg-pan {
0% { background-position: 0% 0%; }
100% { background-position: 100% 100%; }
}
main {
padding: 2rem;
}
.card {
background: var(--card-bg-color);
border: 1px solid var(--card-border-color);
border-radius: 16px;
padding: 2rem;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.1);
}
.loader {
margin: 1.25rem auto 1.25rem;
width: 48px;
height: 48px;
border: 3px solid rgba(255, 255, 255, 0.25);
border-top-color: #fff;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.hint {
opacity: 0.9;
}
.sr-only {
position: absolute;
width: 1px; height: 1px;
padding: 0; margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap; border: 0;
}
h1 {
font-size: 3rem;
font-weight: 700;
margin: 0 0 1rem;
letter-spacing: -1px;
}
p {
margin: 0.5rem 0;
font-size: 1.1rem;
}
code {
background: rgba(0,0,0,0.2);
padding: 2px 6px;
border-radius: 4px;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
footer {
position: absolute;
bottom: 1rem;
font-size: 0.8rem;
opacity: 0.7;
}
</style>
</head> </head>
<body> <body>
<main>
<div class="card"> <header class="header">
<h1>Analyzing your requirements and generating your website…</h1> <i data-lucide="shield" class="icon"></i>
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes"> <h1>TRINETRA</h1>
<span class="sr-only">Loading…</span> </header>
</div>
<p class="hint"><?= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.</p> <div class="container-fluid">
<p class="hint">This page will update automatically as the plan is implemented.</p> <ul class="nav nav-tabs" id="main-tabs" role="tablist">
<p>Runtime: PHP <code><?= htmlspecialchars($phpVersion) ?></code> — UTC <code><?= htmlspecialchars($now) ?></code></p> <li class="nav-item" role="presentation">
<button class="nav-link active" id="chat-tab" data-bs-toggle="tab" data-bs-target="#chat-panel" type="button" role="tab" aria-controls="chat-panel" aria-selected="true">AI Assistant</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="reports-tab" data-bs-toggle="tab" data-bs-target="#reports-panel" type="button" role="tab" aria-controls="reports-panel" aria-selected="false">Reports</button>
</li>
</ul>
<div class="tab-content" id="myTabContent">
<div class="tab-pane fade show active" id="chat-panel" role="tabpanel" aria-labelledby="chat-tab">
<main id="chat-container" class="chat-container">
<div class="chat-bubble ai">
<pre>TRINETRA System Online.
I have access to your local case files. I can generate Arrest Memos, Bail Replies, and Case Diaries.
Command me, Officer. For example: `find case 684/25` or `generate arrest memo for case 684/25`</pre>
</div> </div>
</main> </main>
<footer> <footer class="chat-input-form">
Page updated: <?= htmlspecialchars($now) ?> (UTC) <form id="chat-form" style="display: flex; width: 100%; gap: 0.5rem;">
<input type="text" id="message-input" class="form-control" placeholder="Enter command..." autocomplete="off" required>
<button type="button" id="upload-btn" class="btn btn-secondary">
<i data-lucide="paperclip"></i>
</button>
<button type="submit" class="btn btn-primary">
<i data-lucide="send"></i>
</button>
</form>
</footer> </footer>
</div>
</div>
</div>
<!-- File Upload Modal -->
<div class="modal fade" id="uploadModal" tabindex="-1" aria-labelledby="uploadModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="uploadModalLabel">Upload File</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p>Select a file to upload. You must first specify the case, for example: `upload file for case 123/25`</p>
<form id="upload-form" enctype="multipart/form-data">
<input type="hidden" id="upload-case-id" name="case_id">
<input type="hidden" name="action" value="upload_file">
<div class="mb-3">
<label for="file-input" class="form-label">File</label>
<input class="form-control" type="file" id="file-input" name="file" required>
</div>
<div class="d-flex justify-content-end">
<button type="button" class="btn btn-secondary me-2" data-bs-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Upload</button>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- Scripts -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
<script>
lucide.createIcons();
</script>
</body> </body>
</html> </html>

21
templates/arrest_memo.php Normal file
View File

@ -0,0 +1,21 @@
<?php
function generate_arrest_memo($case) {
$content = "
ARREST MEMO
FIR No.: {$case['fir_no']}
Police Station: {$case['ps']}
Accused Name: {$case['accused_name']}
Sections: {$case['sections']}
This is to certify that the accused person named above has been arrested in connection with the above-mentioned case.
Date: " . date('Y-m-d') . "
Time: " . date('H:i:s') . "
Signature:
(Investigating Officer)
";
return $content;
}

44
templates/bail_reply.php Normal file
View File

@ -0,0 +1,44 @@
<?php
function generate_bail_reply($case) {
$case_fir_no = htmlspecialchars($case['fir_no']);
$case_ps = htmlspecialchars($case['ps']);
$case_sections = htmlspecialchars($case['sections']);
$accused_name = htmlspecialchars($case['accused_name']);
return <<<HTML
<div style="font-family: Arial, sans-serif; line-height: 1.6; padding: 20px; border: 1px solid #ccc;">
<h2 style="text-align: center; text-decoration: underline;">REPLY TO BAIL APPLICATION</h2>
<p style="text-align: center;"><strong>IN THE COURT OF [INSERT COURT NAME], [INSERT DISTRICT]</strong></p>
<br>
<p><strong>State</strong></p>
<p style="text-align: center;">VS</p>
<p><strong>{$accused_name}</strong></p>
<br>
<p><strong>FIR No.:</strong> {$case_fir_no}</p>
<p><strong>Police Station:</strong> {$case_ps}</p>
<p><strong>Under Section:</strong> {$case_sections}</p>
<hr>
<p><strong>Subject:</strong> Reply to the bail application filed on behalf of accused {$accused_name}.</p>
<p>Respected Sir/Madam,</p>
<p>It is most respectfully submitted as under:</p>
<ol>
<li>That the brief facts of the case are that [INSERT BRIEF FACTS OF THE CASE HERE]. The present case was registered on the statement of the complainant.</li>
<li>That during the course of investigation, the accused {$accused_name} was arrested and is currently in judicial/police custody.</li>
<li>That the investigation of the case is still in progress and some crucial evidence is yet to be collected.</li>
<li>That the offence committed by the accused is heinous and of a serious nature.</li>
<li>That if the accused is released on bail, they may tamper with the evidence, influence the witnesses, or abscond and evade the process of law.</li>
</ol>
<p><strong>PRAYER:</strong></p>
<p>It is, therefore, most respectfully prayed that the bail application of the accused {$accused_name} may kindly be dismissed in the interest of justice.</p>
<br>
<div style="text-align: right;">
<p><strong>Investigating Officer</strong></p>
<p>PS {$case_ps}</p>
<p>Date: {date('d-m-Y')}</p>
</div>
</div>
HTML;
}

41
templates/chargesheet.php Normal file
View File

@ -0,0 +1,41 @@
<?php
function generate_chargesheet($case) {
$case_fir_no = htmlspecialchars($case['fir_no']);
$case_ps = htmlspecialchars($case['ps']);
$case_sections = htmlspecialchars($case['sections']);
$accused_name = htmlspecialchars($case['accused_name']);
$complainant = htmlspecialchars($case['complainant']);
return <<<HTML
<div style="font-family: Arial, sans-serif; line-height: 1.6; padding: 20px; border: 1px solid #ccc;">
<h2 style="text-align: center; text-decoration: underline;">FINAL REPORT (CHARGESHEET)</h2>
<p style="text-align: center;"><strong>(Under Section 173 Cr.P.C.)</strong></p>
<br>
<p><strong>District:</strong> [INSERT DISTRICT]</p>
<p><strong>Police Station:</strong> {$case_ps}</p>
<p><strong>FIR No.:</strong> {$case_fir_no}</p>
<p><strong>Under Section:</strong> {$case_sections}</p>
<hr>
<p><strong>1. Name of Complainant/Informant:</strong> {$complainant}</p>
<p><strong>2. Name of Accused Person(s):</strong> {$accused_name}</p>
<p><strong>3. Details of property stolen/involved:</strong> [INSERT PROPERTY DETAILS]</p>
<p><strong>4. Brief facts of the case:</strong> {$case['facts']}</p>
<p><strong>5. Investigation conducted:</strong> During the course of investigation, the site plan was prepared, statements of witnesses were recorded under section 161 Cr.P.C. The accused was arrested, and the recovery was made at their instance.</p>
<p><strong>6. Evidence collected:</strong> [LIST OF EVIDENCE, e.g., Seizure Memo, Witness Statements, FSL Report, etc.]</p>
<p><strong>CONCLUSION:</strong></p>
<p>From the evidence collected during the investigation, a prima facie case under section <strong>{$case_sections}</strong> is made out against the accused <strong>{$accused_name}</strong>. It is, therefore, requested that the accused may be summoned and tried according to the law.</p>
<br>
<p>The final report is submitted herewith.</p>
<div style="text-align: right; margin-top: 50px;">
<p><strong>(Investigating Officer)</strong></p>
<p>Name: [IO NAME]</p>
<p>Rank: [IO RANK]</p>
<p>PS {$case_ps}</p>
<p>Date: {date('d-m-Y')}</p>
</div>
</div>
HTML;
}