token count for search

This commit is contained in:
sebseb7
2026-04-04 21:51:52 +02:00
parent 92b313fa79
commit d2920fd39a
10 changed files with 477 additions and 30 deletions

View File

@@ -289,6 +289,67 @@
text-decoration: underline;
}
/* Cost Breakdown Styles */
.cost-breakdown-details {
margin-top: 10px;
}
.cost-breakdown-summary {
cursor: pointer;
font-weight: 600;
color: #555;
padding: 12px 15px;
background: #f8f9fa;
border-radius: 6px;
border-left: 4px solid #667eea;
transition: background 0.2s;
list-style: none;
}
.cost-breakdown-summary:hover {
background: #e9ecef;
}
.cost-breakdown-summary::-webkit-details-marker {
display: none;
}
.cost-breakdown-content {
padding: 15px;
margin-top: 10px;
background: #fff;
border: 1px solid #e0e0e0;
border-radius: 6px;
}
.cost-table {
width: 100%;
border-collapse: collapse;
font-size: 0.9rem;
}
.cost-table th,
.cost-table td {
padding: 10px 12px;
text-align: left;
border-bottom: 1px solid #e0e0e0;
}
.cost-table th {
background: #f8f9fa;
font-weight: 600;
color: #555;
}
.cost-table tr:last-child td {
border-bottom: none;
font-weight: 600;
}
.cost-table tbody tr:hover {
background: #f8f9fa;
}
.error {
background: #fee;
color: #c00;
@@ -464,6 +525,7 @@
<button class="example-btn" onclick="setExample('Wie ist die Lage im Iran?')">Lage im Iran</button>
<button class="example-btn" onclick="setExample('Welche KI Modelle wurden in den letzten Tagen veröffentlicht?')">Neue KI-Modelle</button>
<button class="example-btn" onclick="setExample('Wie ist das Wetter in Dresden?')">Wetter in Dresden</button>
<button class="example-btn" onclick="setExample('Was ist neu in React 19.2?')">React 19.2</button>
</div>
<div class="search-box">
@@ -493,6 +555,29 @@
<h2>🔗 Most Relevant Sources</h2>
<ul class="sources" id="sources"></ul>
</div>
<!-- Cost Breakdown Section -->
<div class="result-section">
<details class="cost-breakdown-details" id="costBreakdownDetails">
<summary class="cost-breakdown-summary">💰 Cost Breakdown</summary>
<div class="cost-breakdown-content">
<table class="cost-table" id="costTable">
<thead>
<tr>
<th>#</th>
<th>Type</th>
<th>Input</th>
<th>Output</th>
<th>Cost (USD)</th>
</tr>
</thead>
<tbody id="costTableBody">
<!-- Cost rows will be inserted here -->
</tbody>
</table>
</div>
</details>
</div>
</div>
<!-- Log Panel -->
@@ -531,6 +616,10 @@
// SSE connection
let eventSource = null;
let logEntries = [];
// Clarification state
let isAwaitingClarification = false;
let clarificationData = null;
function connectToSSE() {
eventSource = new EventSource('/stream');
@@ -679,8 +768,109 @@
searchBtn.disabled = false;
}
}
async function performSearchWithClarification(clarificationText) {
if (!clarificationData || !clarificationData.originalQuestion) {
showError('Clarification data not available');
return;
}
// Show loading
hideError();
hideResults();
showLoading();
try {
const response = await fetch('/search', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
question: clarificationData.originalQuestion + ' ' + clarificationText,
previousClarification: clarificationText,
originalQuestion: clarificationData.originalQuestion
})
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || 'Search failed');
}
displayResults(data);
} catch (err) {
showError(err.message);
} finally {
hideLoading();
}
}
function displayResults(data) {
// Check if clarification is needed
if (data.clarificationNeeded) {
isAwaitingClarification = true;
clarificationData = {
originalQuestion: data.originalQuestion
};
// Show clarification prompt in the answer area
answerEl.innerHTML = `
<div style="background: #fff3cd; padding: 20px; border-radius: 8px; border-left: 4px solid #ffc107;">
<p style="margin-bottom: 15px; font-weight: 600;">${data.fullAnswerHTMLSnippet}</p>
<input
type="text"
id="clarificationInput"
class="search-input"
style="margin-bottom: 10px;"
>
<button
class="search-btn"
id="clarificationSubmitBtn"
style="padding: 10px 20px; font-size: 1rem;"
>
Submit Clarification
</button>
</div>
`;
// Clear sources since we're waiting for clarification
sourcesEl.innerHTML = '<li>Waiting for clarification...</li>';
// Add event listener for clarification submission
setTimeout(() => {
const clarificationInput = document.getElementById('clarificationInput');
const clarificationSubmitBtn = document.getElementById('clarificationSubmitBtn');
if (clarificationInput && clarificationSubmitBtn) {
clarificationInput.focus();
const handleClarification = () => {
const clarificationText = clarificationInput.value.trim();
if (clarificationText) {
// Search again with the clarification
performSearchWithClarification(clarificationText);
}
};
clarificationSubmitBtn.addEventListener('click', handleClarification);
clarificationInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
handleClarification();
}
});
}
}, 100);
showResults();
return;
}
// Reset clarification state for normal results
isAwaitingClarification = false;
clarificationData = null;
// Display answer as HTML
answerEl.innerHTML = data.fullAnswerHTMLSnippet || '<p>No answer generated</p>';
@@ -703,6 +893,27 @@
sourcesEl.appendChild(li);
}
// Display cost breakdown
const costTableBody = document.getElementById('costTableBody');
costTableBody.innerHTML = '';
if (data.costBreakdown && data.costBreakdown.length > 0) {
data.costBreakdown.forEach(item => {
const tr = document.createElement('tr');
tr.innerHTML = `
<td>${item.index}</td>
<td>${item.type}</td>
<td>${item.prompt_tokens || '-'}</td>
<td>${item.completion_tokens || '-'}</td>
<td>${item.cost}</td>
`;
costTableBody.appendChild(tr);
});
} else {
const tr = document.createElement('tr');
tr.innerHTML = '<td colspan="5">No cost data available</td>';
costTableBody.appendChild(tr);
}
showResults();
}