rungalileo's picture
Update backend/api/templates/index.html
ccbfb32 verified
raw
history blame
21.3 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Finance Q/A Bot</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body class="bg-gray-100 min-h-screen flex">
<!-- Main Content -->
<div class="w-3/4 p-10">
<h1 class="text-3xl font-bold mb-6">Finance Q/A Bot</h1>
<form id="searchForm" class="space-y-4">
<input
type="text"
id="query"
name="query"
placeholder="Ask a question"
class="p-2 border w-3/4 rounded"
required
/>
<br />
<div class="flex items-center space-x-2">
<button
type="submit"
class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
>
Submit
</button>
<!-- Loading spinner -->
<div id="loadingSpinner" class="hidden">
<svg class="animate-spin h-5 w-5 text-blue-500" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
</div>
</div>
</form>
<!-- Context Adherence Message (above the result box) -->
<div id="adherenceMessage" class="mt-6 p-3 rounded hidden"></div>
<!-- Result area -->
<div id="result" class="mt-4 p-4 bg-white shadow rounded hidden"></div>
</div>
<!-- Sidebar on the right -->
<div class="w-1/4 bg-white shadow p-6">
<h2 class="text-xl font-bold mb-4">Options</h2>
<div class="flex flex-col space-y-4">
<label class="block">
<span class="text-gray-700">Top K:</span>
<input
type="number"
id="top_k"
name="top_k"
value="5"
class="mt-1 p-2 w-full border rounded"
/>
</label>
<label class="flex items-center space-x-2">
<input
type="checkbox"
id="protection"
name="protection"
class="form-checkbox text-green-600 focus:ring-green-500"
/>
<span>Enable Galileo Protection</span>
</label>
<label class="flex items-center space-x-2">
<input
type="checkbox"
id="hallucination_detection"
name="hallucination_detection"
class="form-checkbox text-blue-600 focus:ring-blue-500"
/>
<span>Enable Hallucination Detection</span>
</label>
<label class="flex items-center space-x-2">
<input
type="checkbox"
id="induce_hallucination"
name="induce_hallucination"
class="form-checkbox text-red-600 focus:ring-red-500"
/>
<span>Induce Hallucination</span>
</label>
</div>
</div>
<script>
$(document).ready(function () {
// Check for URL parameters and pre-fill form
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.has('query')) {
$('#query').val(urlParams.get('query'));
}
if (urlParams.has('top_k')) {
$('#top_k').val(urlParams.get('top_k'));
}
if (urlParams.has('protection')) {
$('#protection').prop('checked', urlParams.get('protection') === 'true');
}
if (urlParams.has('hallucination_detection')) {
$('#hallucination_detection').prop('checked', urlParams.get('hallucination_detection') === 'true');
}
if (urlParams.has('induce_hallucination')) {
$('#induce_hallucination').prop('checked', urlParams.get('induce_hallucination') === 'true');
}
$('#searchForm').on('submit', function (e) {
e.preventDefault();
const query = $('#query').val();
const top_k = $('#top_k').val();
const protection = $('#protection').is(':checked');
const hallucination_detection = $('#hallucination_detection').is(':checked');
const induce_hallucination = $('#induce_hallucination').is(':checked');
// Show loading spinner
$('#loadingSpinner').removeClass('hidden');
// Hide previous results
$('#adherenceMessage').addClass('hidden');
$('#result').addClass('hidden');
$.ajax({
type: 'POST',
url: '/search',
data: {
query: query,
top_k: top_k,
protection: protection,
hallucination_detection: hallucination_detection,
induce_hallucination: induce_hallucination
},
success: function (response) {
// Hide loading spinner
$('#loadingSpinner').addClass('hidden');
// Check for PII flag first
const piiFlag = response.metrics && response.metrics.pii_flag;
// Check if any PII types are detected
const piiDetected = piiFlag && Object.values(piiFlag).some(value => value === true);
// If PII is detected, display specific PII warning
if (piiDetected) {
// Build specific PII warning message
const detectedTypes = [];
if (piiFlag.phone_number) detectedTypes.push('phone number');
if (piiFlag.email) detectedTypes.push('<span style="color:yellow; font-weight: bold">email address</span>');
if (piiFlag.name) detectedTypes.push('<span style="color:yellow; font-weight: bold">personal name</span>');
if (piiFlag.company) detectedTypes.push('<span style="color:yellow; font-weight: bold">company name</span>');
let piiMessage = 'Sensitive personally identifiable information detected! The following types of PII were found: ';
if (detectedTypes.length === 1) {
piiMessage += detectedTypes[0];
} else if (detectedTypes.length === 2) {
piiMessage += detectedTypes.join(' and ');
} else {
piiMessage += detectedTypes.slice(0, -1).join(', ') + ', and ' + detectedTypes.slice(-1);
}
// Display the PII warning and response
$('#result')
.removeClass('hidden')
.html(`
<div class="space-y-4">
<!-- PII Warning Message with red background -->
<div class="bg-red-500 text-white p-3 rounded-lg">
<div class="flex items-start">
<div class="flex-shrink-0">
<svg class="h-5 w-5 text-white" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd" />
</svg>
</div>
<div class="ml-3">
<p class="font-medium">${piiMessage}</p>
</div>
</div>
</div>
<!-- Original Message in red text -->
<div class="bg-white border border-gray-200 rounded-lg p-4">
<p class="font-medium text-gray-700 mb-2">Original Message:</p>
<p class="text-black-600">
<style>
tag {
font-weight: bold;
background-color: yellow;
}
</style>
${response.message}</p>
</div>
<!-- Redacted Message in green text -->
<div class="bg-white border border-gray-200 rounded-lg p-4">
<p class="font-medium text-gray-700 mb-2">Redacted Message:</p>
<p class="text-black-600">
<style>
pii {
font-weight: bold;
background-color: yellow;
}
</style>
${response.redacted_message || 'No redacted version available'}
</p>
</div>
</div>
`);
} else if ((induce_hallucination && response.original_message && response.message) ||
(response.metrics && response.metrics.context_adherence < 0.8)) {
// Display hallucination warning and both responses
const adherenceScore = response.metrics ? response.metrics.context_adherence : 1;
const isInducedHallucination = induce_hallucination && response.original_message && response.message;
let warningMessage = '';
if (isInducedHallucination) {
warningMessage = 'Hallucination induced for demonstration purposes! Comparing original vs safe response.';
} else {
warningMessage = 'Potential hallucination detected! Comparing original vs safe response.';
}
$('#result')
.removeClass('hidden')
.html(`
<div class="space-y-4">
<!-- Hallucination Warning Message with orange background -->
<div class="bg-orange-500 text-white p-3 rounded-lg">
<div class="flex items-start">
<div class="flex-shrink-0">
<svg class="h-5 w-5 text-white" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
</svg>
</div>
<div class="ml-3">
<p class="font-medium">${warningMessage}</p>
</div>
</div>
</div>
<!-- Potentially Hallucinatory Response -->
<div class="bg-white border border-red-200 rounded-lg p-4">
<p class="font-medium text-red-700 mb-2">Original Hallucinatory Response:</p>
<p class="text-black-600">${response.message}</p>
</div>
<!-- Fallback Response -->
<div class="bg-white border border-green-200 rounded-lg p-4">
<p class="font-medium text-green-700 mb-2">Safe Response:</p>
<p class="text-black-600">I cannot provide a reliable answer to this question based on the available information! Please try again.</p>
</div>
<!-- Try Again Option -->
<div class="bg-blue-50 border border-blue-200 rounded-lg p-4">
<p class="font-medium text-blue-700 mb-3">Retry with different search parameters:</p>
<div class="flex items-center space-x-3">
<label class="text-sm text-blue-600">
Top K:
<input
type="number"
id="retry_top_k"
value="5"
min="1"
max="100"
class="ml-2 p-1 w-16 border border-blue-300 rounded text-sm"
/>
</label>
<button id="retry_button" class="bg-blue-500 text-white px-3 py-1 rounded text-sm hover:bg-blue-600">
Try Again
</button>
</div>
</div>
</div>
`);
} else {
// Display the main result in normal black color
$('#result')
.removeClass('hidden')
.html(`
<p class="text-black font-bold">${response.message}</p>
`);
}
// Always display context adherence message below the response (regardless of PII detection)
if (response.metrics && response.metrics.context_adherence !== undefined) {
const adherenceScore = response.metrics.context_adherence;
// Only show adherence message if score is not exactly 1 (default value)
if (adherenceScore !== 1.0 || hallucination_detection) {
let adherenceMessage = '';
let adherenceClass = '';
if (adherenceScore >= 0.8) {
adherenceMessage = 'No hallucination detected - The answer is reliable';
adherenceClass = 'bg-green-100 border border-green-300 text-green-800';
} else if (adherenceScore >= 0.3) {
adherenceMessage = 'Potential hallucination detected- The answer is unreliable';
adherenceClass = 'bg-orange-100 border border-orange-300 text-orange-800';
} else {
adherenceMessage = 'High hallucination detected - The answer is unusable';
adherenceClass = 'bg-red-100 border border-red-300 text-red-800';
}
$('#adherenceMessage')
.removeClass('hidden bg-green-100 bg-yellow-100 bg-orange-100 bg-red-100 border-green-300 border-yellow-300 border-orange-300 border-red-300 text-green-800 text-yellow-800 text-orange-800 text-red-800')
.addClass(adherenceClass)
.html(`
<div class="flex items-center justify-between">
<span class="font-medium">${adherenceMessage}</span>
${adherenceScore <= 0.8 ? `<span class="text-sm opacity-75">${((1-adherenceScore) * 100).toFixed(1)}% Hallucination detected</span>` : ''}
</div>
`);
} else {
$('#adherenceMessage').addClass('hidden');
}
} else {
$('#adherenceMessage').addClass('hidden');
}
},
error: function () {
// Hide loading spinner
$('#loadingSpinner').addClass('hidden');
$('#adherenceMessage').addClass('hidden');
$('#result')
.removeClass('hidden')
.html('<p class="text-red-600 font-bold">An error occurred while searching.</p>');
}
});
});
// Handle retry button click
$(document).on('click', '#retry_button', function() {
const query = $('#query').val();
const retry_top_k = $('#retry_top_k').val();
const protection = $('#protection').is(':checked');
const hallucination_detection = $('#hallucination_detection').is(':checked');
const induce_hallucination = $('#induce_hallucination').is(':checked');
// Create URL parameters to reload with form pre-filled
const params = new URLSearchParams();
params.set('query', query);
params.set('top_k', retry_top_k);
params.set('retry', 'true'); // Flag to indicate this is a retry attempt
if (protection) params.set('protection', 'true');
if (hallucination_detection) params.set('hallucination_detection', 'true');
if (induce_hallucination) params.set('induce_hallucination', 'true');
// Reload the page with parameters
window.location.href = window.location.pathname + '?' + params.toString();
});
// Auto-submit if this is a retry attempt (only once) - do this after all handlers are attached
if (urlParams.has('retry') && urlParams.get('retry') === 'true') {
$('#searchForm').submit();
}
});
</script>
</body>
</html>