Support Incremental Search on Web Interface

## Support Incremental Search on Khoj Web Interface
- Use default, fast path to query /search API while user is typing
- Upgrade to cross-encoder re-ranked results once user hits enter on search box

## Improve Render of Org Results on Web Interface
- We were previously just wrapping results from /search API into a pre formatted div field. This was not easy to read
- Use [org.js](https://mooz.github.io/org-js/) to render results from Khoj `/search` API as proper HTML
- Improve org.js to render all task states, stylize task tags and make org-mode results look more like original content

Closes #42 #41
This commit is contained in:
Debanjum
2022-07-28 09:31:57 -07:00
committed by GitHub
2 changed files with 1892 additions and 15 deletions

View File

@@ -3,6 +3,7 @@
<meta charset="utf-8"> <meta charset="utf-8">
<title>Khoj</title> <title>Khoj</title>
</head> </head>
<script type="text/javascript" src="static/org.js"></script>
<script> <script>
function render_image(item) { function render_image(item) {
@@ -14,22 +15,41 @@
</a>` </a>`
} }
function render_json(data) { function render_org(query, data) {
return `<pre id="json">${JSON.stringify(data, null, 2)}</pre>` var orgCode = `Query: ${query}\n` + data.map(function (item) {
return `${item.entry}`
}).join("\n")
var orgParser = new Org.Parser();
var orgDocument = orgParser.parse(orgCode);
var orgHTMLDocument = orgDocument.convert(Org.ConverterHTML);
return orgHTMLDocument.toString();
} }
function search() { function render_json(data, query, type) {
if (type === "org") {
return render_org(query, data);
} else if (type === "image") {
return data.map(render_image).join('');
} else {
return `<pre id="json">${JSON.stringify(data, null, 2)}</pre>`;
}
}
function search(rerank=false) {
query = document.getElementById("query").value; query = document.getElementById("query").value;
type = document.getElementById("type").value; type = document.getElementById("type").value;
console.log(query, type); console.log(query, type);
fetch(`/search?q=${query}&t=${type}&n=6`) url = type === "image"
? `/search?q=${query}&t=${type}&n=6`
: `/search?q=${query}&t=${type}&n=6&r=${rerank}`;
fetch(url)
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
console.log(data); console.log(data);
document.getElementById("results").innerHTML = document.getElementById("results").innerHTML =
type == "image" `<div id=results-${type}>`
? data.map(render_image).join('') + render_json(data, query, type)
: render_json(data); + `</div>`;
}); });
} }
@@ -44,9 +64,14 @@
}); });
} }
function search_on_enter(event) { function incremental_search(event) {
if (event.key == 'Enter') { type = document.getElementById("type").value;
search(); if (event.key === 'Enter') {
search(rerank=true);
}
// Limit incremental search to text types
else if (type !== "image") {
search(rerank=false);
} }
} }
</script> </script>
@@ -54,8 +79,8 @@
<body> <body>
<h1>Khoj</h1> <h1>Khoj</h1>
<!--Add Text Box To Enter Query --> <!--Add Text Box To Enter Query, Trigger Incremental Search OnChange -->
<input id="query" type="text" placeholder="Search" onkeydown=search_on_enter(event) autofocus> <input type="text" id="query" onkeyup=incremental_search(event) placeholder="What is the meaning of life?">
<!--Add Dropdown to Select Query Type. <!--Add Dropdown to Select Query Type.
Query Types can be: org, ledger, image, music, markdown. Query Types can be: org, ledger, image, music, markdown.
@@ -68,8 +93,6 @@
<option value="music">Music</option> <option value="music">Music</option>
</select> </select>
<!--Add Button To Search -->
<button id="search" onclick="search()">Search</button>
<!--Add Button To Regenerate --> <!--Add Button To Regenerate -->
<button id="regenerate" onclick="regenerate()">Regenerate</button> <button id="regenerate" onclick="regenerate()">Regenerate</button>
@@ -121,7 +144,7 @@
border-radius: 5px; border-radius: 5px;
border: 1px solid #ccc; border: 1px solid #ccc;
} }
#results { #results-image {
display: grid; display: grid;
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, 1fr);
} }
@@ -136,6 +159,31 @@
#json { #json {
white-space: pre-wrap; white-space: pre-wrap;
} }
#results-org {
text-align: left;
white-space: pre-line;
}
span.task-status {
color: white;
padding: 3.5px 3.5px 0;
margin-right: 5px;
border-radius: 5px;
background-color: #ed6f00;
}
span.task-status.todo {
background-color: #048ba8
}
span.task-status.done {
background-color: #06a77d;
}
span.task-tag {
color: white;
padding: 3.5px 3.5px 0;
margin-right: 5px;
border-radius: 5px;
background-color: #bbb;
}
</style> </style>
</html> </html>

1829
src/interface/web/org.js Normal file

File diff suppressed because it is too large Load Diff