embed.html•23.5 kB
{% extends "base.html" %} {% block title %}Embed Document - ContextMore{%
endblock %} {% block content %}
<div class="bg-white shadow rounded-lg overflow-hidden">
<div class="px-4 py-5 sm:p-6">
<h2 class="text-2xl font-bold text-gray-900 mb-1">Embed Document</h2>
<p class="text-gray-600 mb-6">
Add a new document to your knowledge base by providing its URL or
uploading a file.
</p>
<!-- Tabs for URL or File Upload -->
<div class="mb-6">
<div class="border-b border-gray-200">
<nav class="-mb-px flex space-x-8" aria-label="Tabs">
<button
id="tab-url"
class="border-blue-500 text-blue-600 whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm"
>
URL Document
</button>
<button
id="tab-file"
class="border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm"
>
File Upload
</button>
</nav>
</div>
</div>
<!-- URL Embed Form -->
<div id="form-url" class="space-y-6">
<form id="embedForm" class="space-y-6">
<!-- Document URL -->
<div>
<label for="url" class="block text-sm font-medium text-gray-700"
>Document URL</label
>
<div class="mt-1 relative rounded-md shadow-sm">
<div
class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"
>
<svg
class="h-5 w-5 text-gray-400"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"
/>
</svg>
</div>
<input
type="url"
id="url"
required
placeholder="https://example.com/document"
class="focus:ring-blue-500 focus:border-blue-500 block w-full pl-10 pr-12 sm:text-sm border-gray-300 rounded-md"
/>
</div>
</div>
<!-- Call Name -->
<div>
<label for="callName" class="block text-sm font-medium text-gray-700"
>Call Name</label
>
<div class="mt-1 relative rounded-md shadow-sm">
<div
class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"
>
<svg
class="h-5 w-5 text-gray-400"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z"
/>
</svg>
</div>
<input
type="text"
id="callName"
required
placeholder="A name to identify this document"
class="focus:ring-blue-500 focus:border-blue-500 block w-full pl-10 pr-12 sm:text-sm border-gray-300 rounded-md"
/>
</div>
<p class="mt-1 text-sm text-gray-500">
This name will help you identify the document in search results.
</p>
</div>
<!-- Authentication Section -->
<div class="border border-gray-200 rounded-md p-4">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-medium text-gray-900">Authentication</h3>
<button
type="button"
id="addAuthBtn"
class="inline-flex items-center px-3 py-1.5 border border-transparent text-xs font-medium rounded shadow-sm text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
>
Add Authentication
</button>
</div>
<p class="text-sm text-gray-500 mb-4">
Required for protected documents
</p>
<!-- Authentication Form (hidden by default) -->
<div id="authForm" class="hidden space-y-4">
<div class="flex space-x-4">
<div class="flex-1">
<label
for="authType"
class="block text-sm font-medium text-gray-700"
>Auth Type</label
>
<select
id="authType"
class="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm rounded-md"
>
<option value="basic">Basic Auth</option>
<option value="header">Custom Headers</option>
</select>
</div>
</div>
<!-- Basic Auth Form -->
<div id="basicAuthForm">
<div class="flex space-x-4">
<div class="flex-1">
<label
for="username"
class="block text-sm font-medium text-gray-700"
>Username</label
>
<input
type="text"
id="username"
class="mt-1 focus:ring-blue-500 focus:border-blue-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md"
/>
</div>
<div class="flex-1">
<label
for="password"
class="block text-sm font-medium text-gray-700"
>Password</label
>
<input
type="password"
id="password"
class="mt-1 focus:ring-blue-500 focus:border-blue-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md"
/>
</div>
</div>
</div>
<!-- Custom Headers Form -->
<div id="headerAuthForm" class="hidden">
<div id="headersList" class="space-y-3">
<div class="flex space-x-4">
<div class="flex-1">
<label
for="headerName1"
class="block text-sm font-medium text-gray-700"
>Header Name</label
>
<input
type="text"
id="headerName1"
placeholder="Authorization"
class="mt-1 focus:ring-blue-500 focus:border-blue-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md"
/>
</div>
<div class="flex-1">
<label
for="headerValue1"
class="block text-sm font-medium text-gray-700"
>Value</label
>
<input
type="text"
id="headerValue1"
placeholder="Bearer token123"
class="mt-1 focus:ring-blue-500 focus:border-blue-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md"
/>
</div>
</div>
</div>
<button
type="button"
id="addHeaderBtn"
class="mt-3 inline-flex items-center px-2.5 py-1.5 border border-gray-300 shadow-sm text-xs font-medium rounded text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
>
Add Header
</button>
</div>
</div>
</div>
<!-- Submit Button -->
<div>
<button
type="submit"
id="embedBtn"
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
>
<svg
class="mr-2 -ml-1 h-5 w-5"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"
/>
</svg>
Embed Document
</button>
</div>
</form>
</div>
<!-- File Upload Form -->
<div id="form-file" class="space-y-6 hidden">
<form id="fileUploadForm" class="space-y-6" enctype="multipart/form-data">
<!-- File Input -->
<div>
<label class="block text-sm font-medium text-gray-700"
>Document File</label
>
<div
class="mt-1 flex justify-center px-6 pt-5 pb-6 border-2 border-gray-300 border-dashed rounded-md"
>
<div class="space-y-1 text-center">
<svg
class="mx-auto h-12 w-12 text-gray-400"
stroke="currentColor"
fill="none"
viewBox="0 0 48 48"
aria-hidden="true"
>
<path
d="M28 8H12a4 4 0 00-4 4v20m32-12v8m0 0v8a4 4 0 01-4 4H12a4 4 0 01-4-4v-4m32-4l-3.172-3.172a4 4 0 00-5.656 0L28 28M8 32l9.172-9.172a4 4 0 015.656 0L28 28m0 0l4 4m4-24h8m-4-4v8m-12 4h.02"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
<div class="flex text-sm text-gray-600">
<label
for="file-upload"
class="relative cursor-pointer bg-white rounded-md font-medium text-blue-600 hover:text-blue-500 focus-within:outline-none focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-blue-500"
>
<span>Upload a file</span>
<input
id="file-upload"
name="file"
type="file"
class="sr-only"
accept=".pdf,.docx,.txt"
required
/>
</label>
<p class="pl-1">or drag and drop</p>
</div>
<p class="text-xs text-gray-500">PDF, DOCX, or TXT up to 10MB</p>
</div>
</div>
<div id="file-name" class="mt-2 text-sm text-gray-500 hidden">
Selected file: <span class="font-medium"></span>
</div>
</div>
<!-- Call Name -->
<div>
<label
for="fileCallName"
class="block text-sm font-medium text-gray-700"
>Call Name</label
>
<div class="mt-1 relative rounded-md shadow-sm">
<div
class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"
>
<svg
class="h-5 w-5 text-gray-400"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z"
/>
</svg>
</div>
<input
type="text"
id="fileCallName"
name="call_name"
required
placeholder="A name to identify this document"
class="focus:ring-blue-500 focus:border-blue-500 block w-full pl-10 pr-12 sm:text-sm border-gray-300 rounded-md"
/>
</div>
<p class="mt-1 text-sm text-gray-500">
This name will help you identify the document in search results.
</p>
</div>
<!-- Submit Button -->
<div>
<button
type="submit"
id="uploadBtn"
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
>
<svg
class="mr-2 -ml-1 h-5 w-5"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"
/>
</svg>
Upload and Embed Document
</button>
</div>
</form>
</div>
<!-- Results -->
<div
id="results"
class="hidden mt-8 p-4 border border-green-200 bg-green-50 rounded-md"
>
<div class="flex items-start space-x-3">
<div class="flex-shrink-0">
<svg
class="h-6 w-6 text-green-500"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
</div>
<div>
<h3 class="text-sm font-medium text-green-800" id="resultTitle">
Success!
</h3>
<div class="mt-2 text-sm text-green-700">
<p id="resultMessage"></p>
</div>
</div>
</div>
</div>
<!-- Error -->
<div
id="error"
class="hidden mt-8 p-4 border border-red-200 bg-red-50 rounded-md"
>
<div class="flex items-start space-x-3">
<div class="flex-shrink-0">
<svg
class="h-6 w-6 text-red-500"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
</div>
<div>
<h3 class="text-sm font-medium text-red-800">Error</h3>
<div class="mt-2 text-sm text-red-700">
<p id="errorMessage"></p>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener("DOMContentLoaded", function () {
// Tab switching
const tabUrl = document.getElementById("tab-url");
const tabFile = document.getElementById("tab-file");
const formUrl = document.getElementById("form-url");
const formFile = document.getElementById("form-file");
tabUrl.addEventListener("click", function () {
tabUrl.classList.add("border-blue-500", "text-blue-600");
tabUrl.classList.remove("border-transparent", "text-gray-500");
tabFile.classList.add("border-transparent", "text-gray-500");
tabFile.classList.remove("border-blue-500", "text-blue-600");
formUrl.classList.remove("hidden");
formFile.classList.add("hidden");
});
tabFile.addEventListener("click", function () {
tabFile.classList.add("border-blue-500", "text-blue-600");
tabFile.classList.remove("border-transparent", "text-gray-500");
tabUrl.classList.add("border-transparent", "text-gray-500");
tabUrl.classList.remove("border-blue-500", "text-blue-600");
formFile.classList.remove("hidden");
formUrl.classList.add("hidden");
});
// URL Form Submission
const embedForm = document.getElementById("embedForm");
const results = document.getElementById("results");
const resultMessage = document.getElementById("resultMessage");
const error = document.getElementById("error");
const errorMessage = document.getElementById("errorMessage");
embedForm.addEventListener("submit", async function (e) {
e.preventDefault();
// Hide previous messages
results.classList.add("hidden");
error.classList.add("hidden");
// Create request body
const requestBody = {
url: document.getElementById("url").value,
call_name: document.getElementById("callName").value,
};
// Add authentication if provided
if (
document.getElementById("authForm").classList.contains("hidden") ===
false
) {
const authType = document.getElementById("authType").value;
if (authType === "basic") {
const username = document.getElementById("username").value;
const password = document.getElementById("password").value;
if (username && password) {
requestBody.basic_auth = {
username,
password,
};
}
} else if (authType === "header") {
const headers = {};
let headerCount = 1;
while (document.getElementById(`headerName${headerCount}`)) {
const name = document.getElementById(
`headerName${headerCount}`
).value;
const value = document.getElementById(
`headerValue${headerCount}`
).value;
if (name && value) {
headers[name] = value;
}
headerCount++;
}
if (Object.keys(headers).length > 0) {
requestBody.auth_headers = {
headers,
};
}
}
}
try {
// Send request
const response = await fetch("/embed", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(requestBody),
});
const data = await response.json();
if (response.ok) {
// Show success message
resultMessage.textContent = data.message;
results.classList.remove("hidden");
} else {
// Show error message
errorMessage.textContent = data.detail || "An error occurred";
error.classList.remove("hidden");
}
} catch (err) {
errorMessage.textContent = "Network error: " + err.message;
error.classList.remove("hidden");
}
});
// File Upload Form
const fileUploadForm = document.getElementById("fileUploadForm");
const fileUpload = document.getElementById("file-upload");
const fileName = document.getElementById("file-name");
fileUpload.addEventListener("change", function () {
if (this.files && this.files[0]) {
const file = this.files[0];
fileName.querySelector("span").textContent = file.name;
fileName.classList.remove("hidden");
} else {
fileName.classList.add("hidden");
}
});
fileUploadForm.addEventListener("submit", async function (e) {
e.preventDefault();
// Hide previous messages
results.classList.add("hidden");
error.classList.add("hidden");
// Check if file is selected
if (!fileUpload.files || !fileUpload.files[0]) {
errorMessage.textContent = "Please select a file to upload";
error.classList.remove("hidden");
return;
}
// Create form data
const formData = new FormData();
formData.append("file", fileUpload.files[0]);
formData.append(
"call_name",
document.getElementById("fileCallName").value
);
try {
// Send request
const response = await fetch("/upload-document", {
method: "POST",
body: formData,
});
const data = await response.json();
if (response.ok) {
// Show success message
resultMessage.textContent = data.message;
results.classList.remove("hidden");
// Reset file selection
fileUpload.value = "";
fileName.classList.add("hidden");
} else {
// Show error message
errorMessage.textContent = data.detail || "An error occurred";
error.classList.remove("hidden");
}
} catch (err) {
errorMessage.textContent = "Network error: " + err.message;
error.classList.remove("hidden");
}
});
// Auth toggles
const addAuthBtn = document.getElementById("addAuthBtn");
const authForm = document.getElementById("authForm");
const authType = document.getElementById("authType");
const basicAuthForm = document.getElementById("basicAuthForm");
const headerAuthForm = document.getElementById("headerAuthForm");
addAuthBtn.addEventListener("click", function () {
if (authForm.classList.contains("hidden")) {
authForm.classList.remove("hidden");
addAuthBtn.textContent = "Remove Authentication";
} else {
authForm.classList.add("hidden");
addAuthBtn.textContent = "Add Authentication";
}
});
authType.addEventListener("change", function () {
if (this.value === "basic") {
basicAuthForm.classList.remove("hidden");
headerAuthForm.classList.add("hidden");
} else {
basicAuthForm.classList.add("hidden");
headerAuthForm.classList.remove("hidden");
}
});
// Add header button
const addHeaderBtn = document.getElementById("addHeaderBtn");
const headersList = document.getElementById("headersList");
let headerCounter = 1;
addHeaderBtn.addEventListener("click", function () {
headerCounter++;
const headerRow = document.createElement("div");
headerRow.className = "flex space-x-4 mt-3";
headerRow.innerHTML = `
<div class="flex-1">
<label for="headerName${headerCounter}" class="block text-sm font-medium text-gray-700">Header Name</label>
<input type="text" id="headerName${headerCounter}" placeholder="X-Custom-Header" class="mt-1 focus:ring-blue-500 focus:border-blue-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md" />
</div>
<div class="flex-1">
<label for="headerValue${headerCounter}" class="block text-sm font-medium text-gray-700">Value</label>
<input type="text" id="headerValue${headerCounter}" placeholder="custom-value" class="mt-1 focus:ring-blue-500 focus:border-blue-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md" />
</div>
`;
headersList.appendChild(headerRow);
});
});
</script>
{% endblock %}