145 lines
3.6 KiB
HTML
145 lines
3.6 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>Searchcraft UI</title>
|
|
<style>
|
|
body {
|
|
font-family: sans-serif;
|
|
background: #1e1e1e;
|
|
color: #eee;
|
|
padding: 2rem;
|
|
}
|
|
input, textarea, button {
|
|
margin: 0.5rem 0;
|
|
width: 100%;
|
|
padding: 0.5rem;
|
|
font-size: 1rem;
|
|
}
|
|
textarea { height: 100px; }
|
|
.section {
|
|
margin-bottom: 2rem;
|
|
border-bottom: 1px solid #444;
|
|
padding-bottom: 1rem;
|
|
}
|
|
.results {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 1rem;
|
|
}
|
|
.card {
|
|
background: #2a2a2a;
|
|
border: 1px solid #444;
|
|
border-radius: 0.5rem;
|
|
padding: 1rem;
|
|
width: calc(50% - 1rem);
|
|
}
|
|
.card h3 {
|
|
margin: 0 0 0.5rem;
|
|
color: #00ffe0;
|
|
}
|
|
.card p {
|
|
margin: 0;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<h1>🔍 Searchcraft UI</h1>
|
|
|
|
<div class="section">
|
|
<h2>📄 Upload Document</h2>
|
|
<input id="doc-id" placeholder="Document ID (required)" />
|
|
<input id="doc-title" placeholder="Title" />
|
|
<textarea id="doc-body" placeholder="Body"></textarea>
|
|
<button onclick="uploadDocument()">Upload</button>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h2>✅ Commit Changes</h2>
|
|
<button onclick="commitChanges()">Commit</button>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h2>🔎 Search</h2>
|
|
<input id="search-query" placeholder="Search query..." oninput="debouncedSearch()" />
|
|
<div class="results" id="results"></div>
|
|
</div>
|
|
|
|
<script>
|
|
const BASE_URL = "http://0.0.0.0:8000";
|
|
const INDEX = "thoughts-links";
|
|
let debounceTimer = null;
|
|
|
|
async function uploadDocument() {
|
|
const id = document.getElementById("doc-id").value;
|
|
const title = document.getElementById("doc-title").value;
|
|
const body = document.getElementById("doc-body").value;
|
|
|
|
if (!id) {
|
|
alert("Document ID is required.");
|
|
return;
|
|
}
|
|
|
|
const response = await fetch(`${BASE_URL}/index/${INDEX}/documents`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify([{ id, title, body }]),
|
|
});
|
|
|
|
const result = await response.json();
|
|
alert("Upload: " + JSON.stringify(result));
|
|
}
|
|
|
|
async function commitChanges() {
|
|
const response = await fetch(`${BASE_URL}/index/${INDEX}/commit`, { method: "POST" });
|
|
const result = await response.json();
|
|
alert("Commit: " + JSON.stringify(result));
|
|
}
|
|
|
|
function debouncedSearch() {
|
|
clearTimeout(debounceTimer);
|
|
debounceTimer = setTimeout(search, 300); // 300ms debounce
|
|
}
|
|
|
|
async function search() {
|
|
const query = document.getElementById("search-query").value;
|
|
const resBox = document.getElementById("results");
|
|
resBox.innerHTML = '';
|
|
|
|
if (!query) return;
|
|
|
|
const response = await fetch(`${BASE_URL}/index/${INDEX}/search`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({
|
|
limit: 10,
|
|
offset: 0,
|
|
query: { fuzzy: { ctx: query } }
|
|
}),
|
|
});
|
|
|
|
const result = await response.json();
|
|
const hits = result?.data?.hits || [];
|
|
|
|
for (const hit of hits) {
|
|
const { title, body } = hit.doc;
|
|
|
|
const card = document.createElement("div");
|
|
card.className = "card";
|
|
|
|
const titleEl = document.createElement("h3");
|
|
titleEl.textContent = title || "Untitled";
|
|
|
|
const bodyEl = document.createElement("p");
|
|
bodyEl.textContent = body || "(no body)";
|
|
|
|
card.appendChild(titleEl);
|
|
card.appendChild(bodyEl);
|
|
resBox.appendChild(card);
|
|
}
|
|
}
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|