Skip to content

Commit

Permalink
spike: trieve search
Browse files Browse the repository at this point in the history
  • Loading branch information
palkan committed Jul 16, 2024
1 parent be2ac68 commit 458bfc6
Show file tree
Hide file tree
Showing 2 changed files with 272 additions and 1 deletion.
268 changes: 268 additions & 0 deletions docs/assets/docsify-trieve-search.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
(function () {
/* eslint-disable no-unused-vars */

function escapeHtml(string) {
var entityMap = {
"&": "&",
"<": "&lt;",
">": "&gt;",
'"': "&quot;",
"'": "&#39;",
};

return String(string).replace(/[&<>"']/g, function (s) {
return entityMap[s];
});
}

var abortController;

/**
* @param {String} query Search query
* @returns {Array} Array of results
*/
async function search(query) {
if (abortController) abortController.abort();

abortController = new AbortController();

const response = await fetch(`https://api.trieve.ai/api/chunk/search`, {
method: "POST",
headers: {
Authorization: `${CONFIG.api_key}`,
"TR-Dataset": `${CONFIG.dataset}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
query: query,
search_type: "semantic",
highlight_delimiters: [" "],
highlight_max_length: 100,
highlight_max_num: 2,
highlight_window: 20,
score_threshold: 0.05,
}),
signal: abortController.signal,
});

if (!response.ok) {
throw new Error("Failed to fetch search results");
}

results = await response.json();

let matches = [];

results.score_chunks.forEach((chunk) => {
if (chunk.highlights.length === 0) return;

title =
chunk.metadata[0].metadata?.title ?? chunk.metadata[0].tracking_id;
content = "..." + chunk.highlights.join("<br/>") + "...";
url = chunk.metadata[0].link.replace(
/^https?:\/\/[^\/]+\//,
window.DOCSIFY_ROUTER_MODE == "hash" ? "#/" : "/"
);

matches.push({
title,
content,
url,
});
});

return matches;
}

/* eslint-disable no-unused-vars */

var NO_DATA_TEXT = "";
var options;

function style() {
var code =
"\n.sidebar {\n padding-top: 0;\n}\n\n.search {\n margin-bottom: 20px;\n padding: 6px;\n border-bottom: 1px solid #eee;\n}\n\n.search .input-wrap {\n display: flex;\n align-items: center;\n}\n\n.search .results-panel {\n display: none;\n}\n\n.search .results-panel.show {\n display: block;\n}\n\n.search input {\n outline: none;\n border: none;\n width: 100%;\n padding: 0 7px;\n line-height: 36px;\n font-size: 14px;\n border: 1px solid transparent;\n}\n\n.search input:focus {\n box-shadow: 0 0 5px var(--theme-color, #42b983);\n border: 1px solid var(--theme-color, #42b983);\n}\n\n.search input::-webkit-search-decoration,\n.search input::-webkit-search-cancel-button,\n.search input {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n.search .clear-button {\n cursor: pointer;\n width: 36px;\n text-align: right;\n display: none;\n}\n\n.search .clear-button.show {\n display: block;\n}\n\n.search .clear-button svg {\n transform: scale(.5);\n}\n\n.search h2 {\n font-size: 17px;\n margin: 10px 0;\n}\n\n.search a {\n text-decoration: none;\n color: inherit;\n}\n\n.search .matching-post {\n border-bottom: 1px solid #eee;\n}\n\n.search .matching-post:last-child {\n border-bottom: 0;\n}\n\n.search p {\n font-size: 14px;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 4;\n -webkit-box-orient: vertical;\n}\n\n.search p.empty {\n text-align: center;\n}\n\n.app-name.hide, .sidebar-nav.hide {\n display: none;\n}";

Docsify.dom.style(code);
}

function tpl(defaultValue) {
if (defaultValue === void 0) defaultValue = "";

var html =
'<div class="input-wrap">\n <input type="search" value="' +
defaultValue +
'" aria-label="Search text" />\n <div class="clear-button">\n <svg width="26" height="24">\n <circle cx="12" cy="12" r="11" fill="#ccc" />\n <path stroke="white" stroke-width="2" d="M8.25,8.25,15.75,15.75" />\n <path stroke="white" stroke-width="2"d="M8.25,15.75,15.75,8.25" />\n </svg>\n </div>\n </div>\n <div class="results-panel"></div>\n </div>';
var el = Docsify.dom.create("div", html);
var aside = Docsify.dom.find("aside");

Docsify.dom.toggleClass(el, "search");
Docsify.dom.before(aside, el);
}

async function doSearch(value) {
var $search = Docsify.dom.find("div.search");
var $panel = Docsify.dom.find($search, ".results-panel");
var $clearBtn = Docsify.dom.find($search, ".clear-button");
var $sidebarNav = Docsify.dom.find(".sidebar-nav");
var $appName = Docsify.dom.find(".app-name");

if (!value) {
$panel.classList.remove("show");
$clearBtn.classList.remove("show");
$panel.innerHTML = "";

if (options.hideOtherSidebarContent) {
$sidebarNav.classList.remove("hide");
$appName.classList.remove("hide");
}

return;
}

var matchs;

try {
matchs = await search(value);
} catch (e) {
if (e.name !== "AbortError") {
console.error(e);
}
return;
}

var html = "";
matchs.forEach(function (post) {
html +=
'<div class="matching-post">\n<a href="' +
post.url +
'">\n<h2>' +
post.title +
"</h2>\n<p>" +
post.content +
"</p>\n</a>\n</div>";
});

$panel.classList.add("show");
$clearBtn.classList.add("show");
$panel.innerHTML = html || '<p class="empty">' + NO_DATA_TEXT + "</p>";
if (options.hideOtherSidebarContent) {
$sidebarNav.classList.add("hide");
$appName.classList.add("hide");
}
}

function bindEvents() {
var $search = Docsify.dom.find("div.search");
var $input = Docsify.dom.find($search, "input");
var $inputWrap = Docsify.dom.find($search, ".input-wrap");

var timeId;

/**
Prevent to Fold sidebar.
When searching on the mobile end,
the sidebar is collapsed when you click the INPUT box,
making it impossible to search.
*/
Docsify.dom.on($search, "click", function (e) {
return (
["A", "H2", "P", "EM"].indexOf(e.target.tagName) === -1 &&
e.stopPropagation()
);
});
Docsify.dom.on($input, "input", function (e) {
clearTimeout(timeId);
timeId = setTimeout(function (_) {
return doSearch(e.target.value.trim());
}, 100);
});
Docsify.dom.on($inputWrap, "click", function (e) {
// Click input outside
if (e.target.tagName !== "INPUT") {
$input.value = "";
doSearch();
}
});
}

function updatePlaceholder(text, path) {
var $input = Docsify.dom.getNode('.search input[type="search"]');

if (!$input) {
return;
}

if (typeof text === "string") {
$input.placeholder = text;
} else {
var match = Object.keys(text).filter(function (key) {
return path.indexOf(key) > -1;
})[0];
$input.placeholder = text[match];
}
}

function updateNoData(text, path) {
if (typeof text === "string") {
NO_DATA_TEXT = text;
} else {
var match = Object.keys(text).filter(function (key) {
return path.indexOf(key) > -1;
})[0];
NO_DATA_TEXT = text[match];
}
}

function updateOptions(opts) {
options = opts;
}

function init(opts, vm) {
var keywords = vm.router.parse().query.s;

updateOptions(opts);
style();
tpl(keywords);
bindEvents();
keywords &&
setTimeout(function (_) {
return doSearch(keywords);
}, 500);
}

function update(opts, vm) {
updateOptions(opts);
updatePlaceholder(opts.placeholder, vm.route.path);
updateNoData(opts.noData, vm.route.path);
}

/* eslint-disable no-unused-vars */

var CONFIG = {
placeholder: "Type to search",
noData: "No Results!",
hideOtherSidebarContent: false,
api_key: window.TRIEVE_API_KEY,
dataset: window.TRIEVE_DATASET,
};

var install = function (hook, vm) {
var opts = vm.config.search || CONFIG;

CONFIG.placeholder = opts.placeholder || CONFIG.placeholder;
CONFIG.noData = opts.noData || CONFIG.noData;
CONFIG.hideOtherSidebarContent =
opts.hideOtherSidebarContent || CONFIG.hideOtherSidebarContent;

hook.mounted(function (_) {
init(CONFIG, vm);
});
hook.doneEach(function (_) {
update(CONFIG, vm);
});
};

$docsify.plugins = [].concat(install, $docsify.plugins);
})();
5 changes: 4 additions & 1 deletion docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
<script> !function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.async=!0,p.src=s.api_host+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys".split(" "),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);
posthog.init('phc_fc9VFWdFAAm5gSlCodHq93iaxxnTTKbjOwsWgAS1FMP',{api_host:'https://app.posthog.com'})</script>
<!-- End Posthog -->
<!-- Trieve -->
<script>window.TRIEVE_DATASET = "38d0ad51-82d5-45dc-b8b6-817bcf49da35"; window.TRIEVE_API_KEY = "tr-JtPZuXATfHbKLyKxsHFa66tVqXZ0wUvM"</script>
<!-- End Trieve -->
</head>
<body>
<div id="app"></div>
Expand Down Expand Up @@ -215,7 +218,7 @@
}
</script>
<script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
<script src="/assets/docsify-search.js"></script>
<script src="/assets/docsify-trieve-search.js"></script>
<script src="//unpkg.com/[email protected]/dist/docsify-namespaced.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/katex@latest/dist/katex.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/marked@4"></script>
Expand Down

0 comments on commit 458bfc6

Please sign in to comment.