mirror of
https://github.com/khoaliber/khoj.git
synced 2026-03-09 21:29:11 +00:00
Merge pull request #228 from debanjum/features/pretty-config-page
Update the config page to be more usable
This commit is contained in:
@@ -50,7 +50,7 @@ pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
|
|||||||
if system() != 'Darwin':
|
if system() != 'Darwin':
|
||||||
# Add Splash screen to show on app launch
|
# Add Splash screen to show on app launch
|
||||||
splash = Splash(
|
splash = Splash(
|
||||||
'src/khoj/interface/web/assets/icons/favicon-144x144.png',
|
'src/khoj/interface/web/assets/icons/favicon-128x128.png',
|
||||||
binaries=a.binaries,
|
binaries=a.binaries,
|
||||||
datas=a.datas,
|
datas=a.datas,
|
||||||
text_pos=(10, 160),
|
text_pos=(10, 160),
|
||||||
@@ -82,7 +82,7 @@ if system() != 'Darwin':
|
|||||||
target_arch='x86_64',
|
target_arch='x86_64',
|
||||||
codesign_identity=None,
|
codesign_identity=None,
|
||||||
entitlements_file=None,
|
entitlements_file=None,
|
||||||
icon='src/khoj/interface/web/assets/icons/favicon-144x144.ico',
|
icon='src/khoj/interface/web/assets/icons/favicon-128x128.ico',
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
exe = EXE(
|
exe = EXE(
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
self.setFixedWidth(600)
|
self.setFixedWidth(600)
|
||||||
|
|
||||||
# Set Window Icon
|
# Set Window Icon
|
||||||
icon_path = constants.web_directory / "assets/icons/favicon-144x144.png"
|
icon_path = constants.web_directory / "assets/icons/favicon-128x128.png"
|
||||||
self.setWindowIcon(QtGui.QIcon(f"{icon_path.absolute()}"))
|
self.setWindowIcon(QtGui.QIcon(f"{icon_path.absolute()}"))
|
||||||
|
|
||||||
# Initialize Configure Window Layout
|
# Initialize Configure Window Layout
|
||||||
@@ -228,6 +228,8 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
# Search Type (re)-Enabled
|
# Search Type (re)-Enabled
|
||||||
if child.isChecked():
|
if child.isChecked():
|
||||||
current_search_config = self.current_config["content-type"].get(child.search_type, {})
|
current_search_config = self.current_config["content-type"].get(child.search_type, {})
|
||||||
|
if current_search_config == None:
|
||||||
|
current_search_config = {}
|
||||||
default_search_config = self.get_default_config(search_type=child.search_type)
|
default_search_config = self.get_default_config(search_type=child.search_type)
|
||||||
self.new_config["content-type"][child.search_type.value] = merge_dicts(
|
self.new_config["content-type"][child.search_type.value] = merge_dicts(
|
||||||
current_search_config, default_search_config
|
current_search_config, default_search_config
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ def create_system_tray(gui: QtWidgets.QApplication, main_window: MainWindow):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# Create the system tray with icon
|
# Create the system tray with icon
|
||||||
icon_path = constants.web_directory / "assets/icons/favicon-144x144.png"
|
icon_path = constants.web_directory / "assets/icons/favicon-128x128.png"
|
||||||
icon = QtGui.QIcon(f"{icon_path.absolute()}")
|
icon = QtGui.QIcon(f"{icon_path.absolute()}")
|
||||||
tray = QtWidgets.QSystemTrayIcon(icon)
|
tray = QtWidgets.QSystemTrayIcon(icon)
|
||||||
tray.setVisible(True)
|
tray.setVisible(True)
|
||||||
|
|||||||
22
src/khoj/interface/web/404.html
Normal file
22
src/khoj/interface/web/404.html
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Khoj: An AI Personal Assistant for your digital brain</title>
|
||||||
|
<link rel=”stylesheet” href=”static/styles.css”>
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@1/css/pico.min.css">
|
||||||
|
</head>
|
||||||
|
<body class="not-found">
|
||||||
|
<header class=”header”>
|
||||||
|
<h1>Oops, this is awkward. That page couldn't be found.</h1>
|
||||||
|
</header>
|
||||||
|
<a href="/config">Go Home</a>
|
||||||
|
|
||||||
|
<footer class=”footer”>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
<style>
|
||||||
|
body.not-found {
|
||||||
|
padding: 0 10%
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</html>
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
:root {
|
|
||||||
--primary-color: #ffffff;
|
|
||||||
--bold-color: #2073ee;
|
|
||||||
--complementary-color: #124408;
|
|
||||||
--accent-color-0: #57f0b5;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type=text] {
|
|
||||||
width: 40%;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.config-element {
|
|
||||||
color: var(--bold-color);
|
|
||||||
margin: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.config-title {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
span.config-element-value {
|
|
||||||
color: var(--complementary-color);
|
|
||||||
font-weight: normal;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
// Retrieve elements from the DOM.
|
|
||||||
var showConfig = document.getElementById("show-config");
|
|
||||||
var configForm = document.getElementById("config-form");
|
|
||||||
var regenerateButton = document.getElementById("config-regenerate");
|
|
||||||
|
|
||||||
// Global variables.
|
|
||||||
var rawConfig = {};
|
|
||||||
var emptyValueDefault = "🖊️";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch the existing config file.
|
|
||||||
*/
|
|
||||||
fetch("/api/config/data")
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => {
|
|
||||||
rawConfig = data;
|
|
||||||
configForm.style.display = "block";
|
|
||||||
processChildren(configForm, data);
|
|
||||||
|
|
||||||
var submitButton = document.createElement("button");
|
|
||||||
submitButton.type = "submit";
|
|
||||||
submitButton.innerHTML = "update";
|
|
||||||
configForm.appendChild(submitButton);
|
|
||||||
|
|
||||||
// The config form's submit handler.
|
|
||||||
configForm.addEventListener("submit", (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
console.log(rawConfig);
|
|
||||||
fetch("/api/config/data", {
|
|
||||||
method: "POST",
|
|
||||||
credentials: "same-origin",
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify(rawConfig)
|
|
||||||
})
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => console.log(data));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The click handler for the Regenerate button.
|
|
||||||
*/
|
|
||||||
regenerateButton.addEventListener("click", (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
regenerateButton.style.cursor = "progress";
|
|
||||||
regenerateButton.disabled = true;
|
|
||||||
fetch("/api/update?force=true&client=web")
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => {
|
|
||||||
regenerateButton.style.cursor = "pointer";
|
|
||||||
regenerateButton.disabled = false;
|
|
||||||
console.log(data);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds config elements to the DOM representing the sub-components
|
|
||||||
* of one of the fields in the raw config file.
|
|
||||||
* @param {the parent element} element
|
|
||||||
* @param {the data to be rendered for this element and its children} data
|
|
||||||
*/
|
|
||||||
function processChildren(element, data) {
|
|
||||||
for (let key in data) {
|
|
||||||
var child = document.createElement("div");
|
|
||||||
child.id = key;
|
|
||||||
child.className = "config-element";
|
|
||||||
child.appendChild(document.createTextNode(key + ": "));
|
|
||||||
if (data[key] === Object(data[key]) && !Array.isArray(data[key])) {
|
|
||||||
child.className+=" config-title";
|
|
||||||
processChildren(child, data[key]);
|
|
||||||
} else {
|
|
||||||
child.appendChild(createValueNode(data, key));
|
|
||||||
}
|
|
||||||
element.appendChild(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Takes an element, and replaces it with an editable
|
|
||||||
* element with the same data in place.
|
|
||||||
* @param {the original element to be replaced} original
|
|
||||||
* @param {the source data to be rendered for the new element} data
|
|
||||||
* @param {the key for this input in the source data} key
|
|
||||||
*/
|
|
||||||
function makeElementEditable(original, data, key) {
|
|
||||||
original.addEventListener("click", () => {
|
|
||||||
var inputNewText = document.createElement("input");
|
|
||||||
inputNewText.type = "text";
|
|
||||||
inputNewText.className = "config-element-edit";
|
|
||||||
inputNewText.value = (original.textContent == emptyValueDefault) ? "" : original.textContent;
|
|
||||||
fixInputOnFocusOut(inputNewText, data, key);
|
|
||||||
original.parentNode.replaceChild(inputNewText, original);
|
|
||||||
inputNewText.focus();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a node corresponding to the value of a config element.
|
|
||||||
* @param {the source data} data
|
|
||||||
* @param {the key corresponding to this node's data} key
|
|
||||||
* @returns A new element which corresponds to the value in some field.
|
|
||||||
*/
|
|
||||||
function createValueNode(data, key) {
|
|
||||||
var valueElement = document.createElement("span");
|
|
||||||
valueElement.className = "config-element-value";
|
|
||||||
valueElement.textContent = !data[key] ? emptyValueDefault : data[key];
|
|
||||||
makeElementEditable(valueElement, data, key);
|
|
||||||
return valueElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replaces an existing input element with an element with the same data, which is not an input.
|
|
||||||
* If the input data for this element was changed, update the corresponding data in the raw config.
|
|
||||||
* @param {the original element to be replaced} original
|
|
||||||
* @param {the source data} data
|
|
||||||
* @param {the key corresponding to this node's data} key
|
|
||||||
*/
|
|
||||||
function fixInputOnFocusOut(original, data, key) {
|
|
||||||
original.addEventListener("blur", () => {
|
|
||||||
data[key] = (original.value != emptyValueDefault) ? original.value : "";
|
|
||||||
original.parentNode.replaceChild(createValueNode(data, key), original);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
BIN
src/khoj/interface/web/assets/icons/favicon-128x128.ico
Normal file
BIN
src/khoj/interface/web/assets/icons/favicon-128x128.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 200 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 159 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 29 KiB |
Binary file not shown.
44
src/khoj/interface/web/base_config.html
Normal file
44
src/khoj/interface/web/base_config.html
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<link rel="icon" type="image/png" sizes="128x128" href="/static/assets/icons/favicon-128x128.png">
|
||||||
|
<title>Khoj - Settings</title>
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@1/css/pico.min.css">
|
||||||
|
</head>
|
||||||
|
<body class="khoj-configure">
|
||||||
|
<header>
|
||||||
|
<div>
|
||||||
|
<h1>Khoj Settings</h1>
|
||||||
|
<p>Check out our <a href="https://github.com/debanjum/khoj">source code on Github</a></p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2>Ready?</h2>
|
||||||
|
<div id="actions">
|
||||||
|
<button onclick="window.location.href='/';" >
|
||||||
|
Search
|
||||||
|
</button>
|
||||||
|
<button onclick="window.location.href='/chat';">
|
||||||
|
Chat
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div class=”content”>
|
||||||
|
{% block content %}
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<style>
|
||||||
|
header {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
grid-gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 600px) {
|
||||||
|
header {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</html>
|
||||||
27
src/khoj/interface/web/base_data_integration.html
Normal file
27
src/khoj/interface/web/base_data_integration.html
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Khoj: Data Settings</title>
|
||||||
|
<link rel=”stylesheet” href=”static/styles.css”>
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@1/css/pico.min.css">
|
||||||
|
</head>
|
||||||
|
<body class="data-integration">
|
||||||
|
<header class=”header”>
|
||||||
|
<h1>Configure your data integrations for Khoj</h1>
|
||||||
|
</header>
|
||||||
|
<a href="/config">Go back</a>
|
||||||
|
|
||||||
|
<div class=”content”>
|
||||||
|
{% block content %}
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class=”footer”>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
<style>
|
||||||
|
body.data-integration {
|
||||||
|
padding: 0 10%
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</html>
|
||||||
27
src/khoj/interface/web/base_processor_integration.html
Normal file
27
src/khoj/interface/web/base_processor_integration.html
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Khoj: Processor Settings</title>
|
||||||
|
<link rel=”stylesheet” href=”static/styles.css”>
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@1/css/pico.min.css">
|
||||||
|
</head>
|
||||||
|
<body class="data-integration">
|
||||||
|
<header class=”header”>
|
||||||
|
<h1>Configure your processor integrations for Khoj</h1>
|
||||||
|
</header>
|
||||||
|
<a href="/config">Go back</a>
|
||||||
|
|
||||||
|
<div class=”content”>
|
||||||
|
{% block content %}
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class=”footer”>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
<style>
|
||||||
|
body.data-integration {
|
||||||
|
padding: 0 10%
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</html>
|
||||||
@@ -4,8 +4,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0 maximum-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0 maximum-scale=1.0">
|
||||||
<title>Khoj</title>
|
<title>Khoj</title>
|
||||||
|
|
||||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 144 144%22><text y=%22.86em%22 font-size=%22144%22>🦅</text></svg>">
|
<link rel="icon" type="image/png" sizes="128x128" href="/static/assets/icons/favicon-128x128.png">
|
||||||
<link rel="icon" type="image/png" sizes="144x144" href="/static/assets/icons/favicon-144x144.png">
|
|
||||||
<link rel="manifest" href="/static/khoj_chat.webmanifest">
|
<link rel="manifest" href="/static/khoj_chat.webmanifest">
|
||||||
</head>
|
</head>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -1,14 +1,71 @@
|
|||||||
<!DOCTYPE html>
|
{% extends "base_config.html" %}
|
||||||
<head>
|
{% block content %}
|
||||||
<meta charset="utf-8">
|
<h2>Content Types</h2>
|
||||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🦅</text></svg>">
|
<div id="content-configuration">
|
||||||
<link rel="stylesheet" href="static/assets/config.css">
|
<button onclick="window.location.href='/config/content_type/pdf';">
|
||||||
<title>Khoj - Configure App</title>
|
PDF
|
||||||
</head>
|
</button>
|
||||||
<body>
|
<button onclick="window.location.href='/config/content_type/markdown';">
|
||||||
<form id="config-form">
|
Markdown
|
||||||
</form>
|
</button>
|
||||||
<button id="config-regenerate">regenerate</button>
|
<button onclick="window.location.href='/config/content_type/org';">
|
||||||
</body>
|
Org
|
||||||
<script src="static/assets/config.js"></script>
|
</button>
|
||||||
</html>
|
<button onclick="window.location.href='/config/content_type/ledger';">
|
||||||
|
Ledger
|
||||||
|
</button>
|
||||||
|
<button onclick="window.location.href='/config/content_type/github';">
|
||||||
|
GitHub
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<h2>Processors</h2>
|
||||||
|
<button onclick="window.location.href='/config/processor/conversation/';">
|
||||||
|
Conversation
|
||||||
|
</button>
|
||||||
|
<h1>Finalize</h1>
|
||||||
|
<button id="regenerate" type="submit">Regenerate</button>
|
||||||
|
<style>
|
||||||
|
body.khoj-configure {
|
||||||
|
padding: 0 10%
|
||||||
|
}
|
||||||
|
div#content-configuration, div#actions {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
grid-gap: 12px;
|
||||||
|
}
|
||||||
|
button#regenerate {
|
||||||
|
background-color: #4CAF50;
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
padding: 15px 32px;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
var regenerate = document.getElementById("regenerate");
|
||||||
|
regenerate.addEventListener("click", function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
regenerate.disabled = true;
|
||||||
|
regenerate.innerHTML = "Regenerating...";
|
||||||
|
fetch('/api/update?force=true&client=web', {
|
||||||
|
method: 'GET',
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
console.log('Success:', data);
|
||||||
|
alert("Regenerated!");
|
||||||
|
regenerate.disabled = false;
|
||||||
|
regenerate.innerHTML = "Regenerate";
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Error:', error);
|
||||||
|
alert("Regeneration was not successful. Check debug logs.");
|
||||||
|
regenerate.disabled = false;
|
||||||
|
regenerate.innerHTML = "Regenerate";
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|||||||
99
src/khoj/interface/web/content_type_github_input.html
Normal file
99
src/khoj/interface/web/content_type_github_input.html
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
{% extends "base_data_integration.html" %}
|
||||||
|
{% block content %}
|
||||||
|
<h2>Github</h2>
|
||||||
|
<form id="config-form">
|
||||||
|
<div id="success" style="display: none;"></div>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<label for="pat-token">Personal Access Token</label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="pat-token" name="pat" value="{{ current_config['pat_token'] }}">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<label for="repo-owner">Repository Owner</label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="repo-owner" name="repo_owner" value="{{ current_config['repo_owner'] }}">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<label for="repo-name">Repository Name</label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="repo-name" name="repo_name" value="{{ current_config['repo_name'] }}">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<label for="repo-branch">Repository Branch</label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="repo-branch" name="repo_branch" value="{{ current_config['repo_branch'] }}">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<h4>You probably don't need to edit these.</h4>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<label for="compressed-jsonl">Compressed JSONL (Output)</label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="compressed-jsonl" name="compressed-jsonl" value="{{ current_config['compressed_jsonl'] }}">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<label for="embeddings-file">Embeddings File (Output)</label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="embeddings-file" name="embeddings-file" value="{{ current_config['embeddings_file'] }}">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<button id="submit" type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
<script>
|
||||||
|
submit.addEventListener("click", function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
var compressed_jsonl = document.getElementById("compressed-jsonl").value;
|
||||||
|
var embeddings_file = document.getElementById("embeddings-file").value;
|
||||||
|
var pat_token = document.getElementById("pat-token").value;
|
||||||
|
var repo_owner = document.getElementById("repo-owner").value;
|
||||||
|
var repo_name = document.getElementById("repo-name").value;
|
||||||
|
var repo_branch = document.getElementById("repo-branch").value;
|
||||||
|
|
||||||
|
fetch('/api/config/data/content_type/github', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
"pat_token": pat_token,
|
||||||
|
"repo_owner": repo_owner,
|
||||||
|
"repo_name": repo_name,
|
||||||
|
"repo_branch": repo_branch,
|
||||||
|
"compressed_jsonl": compressed_jsonl,
|
||||||
|
"embeddings_file": embeddings_file,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data["status"] == "ok") {
|
||||||
|
document.getElementById("success").innerHTML = "✅ Successfully updated. Go to <a href='/config'>your settings</a> to regenerate your index.";
|
||||||
|
document.getElementById("success").style.display = "block";
|
||||||
|
} else {
|
||||||
|
document.getElementById("success").innerHTML = "⚠️ Failed to update settings.";
|
||||||
|
document.getElementById("success").style.display = "block";
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
150
src/khoj/interface/web/content_type_input.html
Normal file
150
src/khoj/interface/web/content_type_input.html
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
{% extends "base_data_integration.html" %}
|
||||||
|
{% block content %}
|
||||||
|
<h2>{{ content_type }}</h2>
|
||||||
|
<form id="config-form">
|
||||||
|
<div id="success" style="display: none;" ></div>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<label for="input-files">Input Files</label>
|
||||||
|
</td>
|
||||||
|
<td id="input-files-cell">
|
||||||
|
{% if current_config['input_files'] is none %}
|
||||||
|
<input type="text" id="input-files" name="input-files">
|
||||||
|
{% else %}
|
||||||
|
{% for input_file in current_config['input_files'] %}
|
||||||
|
<input type="text" id="input-files" name="input-files" value="{{ input_file }}">
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" id="input-files-button">Add</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<label for="input-filter">Input Filter</label>
|
||||||
|
</td>
|
||||||
|
<td id="input-filter-cell">
|
||||||
|
{% if current_config['input_filter'] is none %}
|
||||||
|
<input type="text" id="input-filter" name="input-filter">
|
||||||
|
{% else %}
|
||||||
|
{% for input_filter in current_config['input_filter'] %}
|
||||||
|
<input type="text" id="input-filter" name="input-filter" value="{{ input_filter }}">
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" id="input-filter-button">Add</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h4>You probably don't need to edit these.</h4>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<label for="compressed-jsonl">Compressed JSONL (Output)</label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="compressed-jsonl" name="compressed-jsonl" value="{{ current_config['compressed_jsonl'] }}">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<label for="embeddings-file">Embeddings File (Output)</label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="embeddings-file" name="embeddings-file" value="{{ current_config['embeddings_file'] }}">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<label for="index-heading-entries">Index Heading Entries</label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="index-heading-entries" name="index-heading-entries" value="{{ current_config['index_heading_entries'] }}">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<button id="submit" type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
<script>
|
||||||
|
function addButtonEventListener(fieldName) {
|
||||||
|
var button = document.getElementById(fieldName + "-button");
|
||||||
|
button.addEventListener("click", function(event) {
|
||||||
|
var cell = document.getElementById(fieldName + "-cell");
|
||||||
|
var newInput = document.createElement("input");
|
||||||
|
newInput.setAttribute("type", "text");
|
||||||
|
newInput.setAttribute("name", fieldName);
|
||||||
|
cell.appendChild(newInput);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
addButtonEventListener("input-files");
|
||||||
|
addButtonEventListener("input-filter");
|
||||||
|
|
||||||
|
function getValidInputNodes(nodes) {
|
||||||
|
var validNodes = [];
|
||||||
|
for (var i = 0; i < nodes.length; i++) {
|
||||||
|
const nodeValue = nodes[i].value;
|
||||||
|
if (nodeValue === "" || nodeValue === null || nodeValue === undefined || nodeValue === "None") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
validNodes.push(nodes[i]);
|
||||||
|
}
|
||||||
|
return validNodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
submit.addEventListener("click", function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
var inputFileNodes = document.getElementsByName("input-files");
|
||||||
|
var input_files = getValidInputNodes(inputFileNodes).map(node => node.value);
|
||||||
|
|
||||||
|
var inputFilterNodes = document.getElementsByName("input-filter");
|
||||||
|
var input_filter = getValidInputNodes(inputFilterNodes).map(node => node.value);
|
||||||
|
|
||||||
|
if (input_files.length === 0 && input_filter.length === 0) {
|
||||||
|
alert("You must specify at least one input file or input filter.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input_files.length == 0) {
|
||||||
|
input_files = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input_filter.length == 0) {
|
||||||
|
input_filter = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var compressed_jsonl = document.getElementById("compressed-jsonl").value;
|
||||||
|
var embeddings_file = document.getElementById("embeddings-file").value;
|
||||||
|
var index_heading_entries = document.getElementById("index-heading-entries").value;
|
||||||
|
|
||||||
|
fetch('/api/config/data/content_type/{{ content_type }}', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
"input_files": input_files,
|
||||||
|
"input_filter": input_filter,
|
||||||
|
"compressed_jsonl": compressed_jsonl,
|
||||||
|
"embeddings_file": embeddings_file,
|
||||||
|
"index_heading_entries": index_heading_entries
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data["status"] == "ok") {
|
||||||
|
document.getElementById("success").innerHTML = "✅ Successfully updated. Go to <a href='/config'>your settings</a> to regenerate your index.";
|
||||||
|
document.getElementById("success").style.display = "block";
|
||||||
|
} else {
|
||||||
|
document.getElementById("success").innerHTML = "⚠️ Failed to update settings.";
|
||||||
|
document.getElementById("success").style.display = "block";
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
@@ -4,8 +4,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0 maximum-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0 maximum-scale=1.0">
|
||||||
<title>Khoj</title>
|
<title>Khoj</title>
|
||||||
|
|
||||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 144 144%22><text y=%22.86em%22 font-size=%22144%22>🦅</text></svg>">
|
<link rel="icon" type="image/png" sizes="128x128" href="/static/assets/icons/favicon-128x128.png">
|
||||||
<link rel="icon" type="image/png" sizes="144x144" href="/static/assets/icons/favicon-144x144.png">
|
|
||||||
<link rel="manifest" href="/static/khoj.webmanifest">
|
<link rel="manifest" href="/static/khoj.webmanifest">
|
||||||
</head>
|
</head>
|
||||||
<script type="text/javascript" src="static/assets/org.min.js"></script>
|
<script type="text/javascript" src="static/assets/org.min.js"></script>
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
"description": "An AI search assistant for your digital brain",
|
"description": "An AI search assistant for your digital brain",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "/static/assets/icons/favicon-144x144.png",
|
"src": "/static/assets/icons/favicon-128x128.png",
|
||||||
"sizes": "144x144",
|
"sizes": "128x128",
|
||||||
"type": "image/png"
|
"type": "image/png"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
"description": "An AI personal assistant for your digital brain",
|
"description": "An AI personal assistant for your digital brain",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "/static/assets/icons/favicon-144x144.png",
|
"src": "/static/assets/icons/favicon-128x128.png",
|
||||||
"sizes": "144x144",
|
"sizes": "128x128",
|
||||||
"type": "image/png"
|
"type": "image/png"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
79
src/khoj/interface/web/processor_conversation_input.html
Normal file
79
src/khoj/interface/web/processor_conversation_input.html
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
{% extends "base_processor_integration.html" %}
|
||||||
|
{% block content %}
|
||||||
|
<h2>Conversation</h2>
|
||||||
|
<form id="config-form">
|
||||||
|
<div id="success" style="display: none;" ></div>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<label for="openai-api-key">OpenAI API key</label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="openai-api-key" name="openai-api-key" value="{{ current_config['openai_api_key'] }}">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h4>You probably don't need to edit these.</h4>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<label for="conversation-logfile">Conversation Logfile</label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="conversation-logfile" name="conversation-logfile" value="{{ current_config['conversation_logfile'] }}">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<label for="model">Model</label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="model" name="model" value="{{ current_config['model'] }}">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<label for="chat-model">Chat Model</label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="chat-model" name="chat-model" value="{{ current_config['chat_model'] }}">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<button id="submit" type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
<script>
|
||||||
|
submit.addEventListener("click", function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
var openai_api_key = document.getElementById("openai-api-key").value;
|
||||||
|
var conversation_logfile = document.getElementById("conversation-logfile").value;
|
||||||
|
var model = document.getElementById("model").value;
|
||||||
|
var chat_model = document.getElementById("chat-model").value;
|
||||||
|
|
||||||
|
fetch('/api/config/data/processor/conversation', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
"openai_api_key": openai_api_key,
|
||||||
|
"conversation_logfile": conversation_logfile,
|
||||||
|
"model": model,
|
||||||
|
"chat_model": chat_model
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data["status"] == "ok") {
|
||||||
|
document.getElementById("success").innerHTML = "✅ Successfully updated. Go to <a href='/config'>your settings</a> to regenerate your index.";
|
||||||
|
document.getElementById("success").style.display = "block";
|
||||||
|
} else {
|
||||||
|
document.getElementById("success").innerHTML = "⚠️ Failed to update settings.";
|
||||||
|
document.getElementById("success").style.display = "block";
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
@@ -15,9 +15,16 @@ from khoj.processor.conversation.gpt import converse, extract_questions
|
|||||||
from khoj.processor.conversation.utils import message_to_log, message_to_prompt
|
from khoj.processor.conversation.utils import message_to_log, message_to_prompt
|
||||||
from khoj.search_type import image_search, text_search
|
from khoj.search_type import image_search, text_search
|
||||||
from khoj.utils.helpers import log_telemetry, timer
|
from khoj.utils.helpers import log_telemetry, timer
|
||||||
from khoj.utils.rawconfig import FullConfig, SearchResponse
|
from khoj.utils.rawconfig import (
|
||||||
|
FullConfig,
|
||||||
|
SearchResponse,
|
||||||
|
TextContentConfig,
|
||||||
|
ConversationProcessorConfig,
|
||||||
|
GithubContentConfig,
|
||||||
|
)
|
||||||
from khoj.utils.state import SearchType
|
from khoj.utils.state import SearchType
|
||||||
from khoj.utils import state, constants
|
from khoj.utils import state, constants
|
||||||
|
from khoj.utils.yaml import save_config_to_file_updated_state
|
||||||
|
|
||||||
# Initialize Router
|
# Initialize Router
|
||||||
api = APIRouter()
|
api = APIRouter()
|
||||||
@@ -65,6 +72,36 @@ async def set_config_data(updated_config: FullConfig):
|
|||||||
return state.config
|
return state.config
|
||||||
|
|
||||||
|
|
||||||
|
@api.post("/config/data/content_type/github", status_code=200)
|
||||||
|
async def set_content_config_github_data(updated_config: GithubContentConfig):
|
||||||
|
state.config.content_type.github = updated_config
|
||||||
|
try:
|
||||||
|
save_config_to_file_updated_state()
|
||||||
|
return {"status": "ok"}
|
||||||
|
except Exception as e:
|
||||||
|
return {"status": "error", "message": str(e)}
|
||||||
|
|
||||||
|
|
||||||
|
@api.post("/config/data/content_type/{content_type}", status_code=200)
|
||||||
|
async def set_content_config_data(content_type: str, updated_config: TextContentConfig):
|
||||||
|
state.config.content_type[content_type] = updated_config
|
||||||
|
try:
|
||||||
|
save_config_to_file_updated_state()
|
||||||
|
return {"status": "ok"}
|
||||||
|
except Exception as e:
|
||||||
|
return {"status": "error", "message": str(e)}
|
||||||
|
|
||||||
|
|
||||||
|
@api.post("/config/data/processor/conversation", status_code=200)
|
||||||
|
async def set_processor_conversation_config_data(updated_config: ConversationProcessorConfig):
|
||||||
|
state.config.processor.conversation = updated_config
|
||||||
|
try:
|
||||||
|
save_config_to_file_updated_state()
|
||||||
|
return {"status": "ok"}
|
||||||
|
except Exception as e:
|
||||||
|
return {"status": "error", "message": str(e)}
|
||||||
|
|
||||||
|
|
||||||
@api.get("/search", response_model=List[SearchResponse])
|
@api.get("/search", response_model=List[SearchResponse])
|
||||||
def search(
|
def search(
|
||||||
q: str,
|
q: str,
|
||||||
|
|||||||
@@ -3,15 +3,21 @@ from fastapi import APIRouter
|
|||||||
from fastapi import Request
|
from fastapi import Request
|
||||||
from fastapi.responses import HTMLResponse, FileResponse
|
from fastapi.responses import HTMLResponse, FileResponse
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
|
from khoj.utils.rawconfig import TextContentConfig, ConversationProcessorConfig
|
||||||
|
|
||||||
# Internal Packages
|
# Internal Packages
|
||||||
from khoj.utils import constants
|
from khoj.utils import constants, state
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
# Initialize Router
|
# Initialize Router
|
||||||
web_client = APIRouter()
|
web_client = APIRouter()
|
||||||
templates = Jinja2Templates(directory=constants.web_directory)
|
templates = Jinja2Templates(directory=constants.web_directory)
|
||||||
|
|
||||||
|
VALID_CONTENT_TYPES = ["org", "ledger", "markdown", "pdf"]
|
||||||
|
|
||||||
|
|
||||||
# Create Routes
|
# Create Routes
|
||||||
@web_client.get("/", response_class=FileResponse)
|
@web_client.get("/", response_class=FileResponse)
|
||||||
@@ -24,6 +30,83 @@ def config_page(request: Request):
|
|||||||
return templates.TemplateResponse("config.html", context={"request": request})
|
return templates.TemplateResponse("config.html", context={"request": request})
|
||||||
|
|
||||||
|
|
||||||
|
@web_client.get("/config/content_type/github", response_class=HTMLResponse)
|
||||||
|
def github_config_page(request: Request):
|
||||||
|
default_copy = constants.default_config.copy()
|
||||||
|
default_github = default_copy["content-type"]["github"] # type: ignore
|
||||||
|
|
||||||
|
default_config = TextContentConfig(
|
||||||
|
compressed_jsonl=default_github["compressed-jsonl"],
|
||||||
|
embeddings_file=default_github["embeddings-file"],
|
||||||
|
)
|
||||||
|
|
||||||
|
current_config = (
|
||||||
|
state.config.content_type.github if state.config.content_type.github is not None else default_config
|
||||||
|
)
|
||||||
|
|
||||||
|
current_config = json.loads(current_config.json())
|
||||||
|
|
||||||
|
return templates.TemplateResponse(
|
||||||
|
"content_type_github_input.html", context={"request": request, "current_config": current_config}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@web_client.get("/config/content_type/{content_type}", response_class=HTMLResponse)
|
||||||
|
def content_config_page(request: Request, content_type: str):
|
||||||
|
if content_type not in VALID_CONTENT_TYPES:
|
||||||
|
return templates.TemplateResponse("config.html", context={"request": request})
|
||||||
|
|
||||||
|
default_copy = constants.default_config.copy()
|
||||||
|
default_content_type = default_copy["content-type"][content_type] # type: ignore
|
||||||
|
|
||||||
|
default_config = TextContentConfig(
|
||||||
|
compressed_jsonl=default_content_type["compressed-jsonl"],
|
||||||
|
embeddings_file=default_content_type["embeddings-file"],
|
||||||
|
)
|
||||||
|
current_config = (
|
||||||
|
state.config.content_type[content_type]
|
||||||
|
if state.config.content_type[content_type] is not None
|
||||||
|
else default_config
|
||||||
|
)
|
||||||
|
current_config = json.loads(current_config.json())
|
||||||
|
|
||||||
|
return templates.TemplateResponse(
|
||||||
|
"content_type_input.html",
|
||||||
|
context={
|
||||||
|
"request": request,
|
||||||
|
"current_config": current_config,
|
||||||
|
"content_type": content_type,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@web_client.get("/config/processor/conversation", response_class=HTMLResponse)
|
||||||
|
def conversation_processor_config_page(request: Request):
|
||||||
|
default_copy = constants.default_config.copy()
|
||||||
|
default_processor_config = default_copy["processor"]["conversation"] # type: ignore
|
||||||
|
default_processor_config = ConversationProcessorConfig(
|
||||||
|
openai_api_key="",
|
||||||
|
model=default_processor_config["model"],
|
||||||
|
conversation_logfile=default_processor_config["conversation-logfile"],
|
||||||
|
chat_model=default_processor_config["chat-model"],
|
||||||
|
)
|
||||||
|
|
||||||
|
current_processor_conversation_config = (
|
||||||
|
state.config.processor.conversation
|
||||||
|
if state.config.processor.conversation is not None
|
||||||
|
else default_processor_config
|
||||||
|
)
|
||||||
|
current_processor_conversation_config = json.loads(current_processor_conversation_config.json())
|
||||||
|
|
||||||
|
return templates.TemplateResponse(
|
||||||
|
"processor_conversation_input.html",
|
||||||
|
context={
|
||||||
|
"request": request,
|
||||||
|
"current_config": current_processor_conversation_config,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@web_client.get("/chat", response_class=FileResponse)
|
@web_client.get("/chat", response_class=FileResponse)
|
||||||
def chat_page():
|
def chat_page():
|
||||||
return FileResponse(constants.web_directory / "chat.html")
|
return FileResponse(constants.web_directory / "chat.html")
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ default_config = {
|
|||||||
"input-filter": None,
|
"input-filter": None,
|
||||||
"compressed-jsonl": "~/.khoj/content/org/org.jsonl.gz",
|
"compressed-jsonl": "~/.khoj/content/org/org.jsonl.gz",
|
||||||
"embeddings-file": "~/.khoj/content/org/org_embeddings.pt",
|
"embeddings-file": "~/.khoj/content/org/org_embeddings.pt",
|
||||||
"index_heading_entries": False,
|
"index-heading-entries": False,
|
||||||
},
|
},
|
||||||
"markdown": {
|
"markdown": {
|
||||||
"input-files": None,
|
"input-files": None,
|
||||||
@@ -74,6 +74,7 @@ default_config = {
|
|||||||
"openai-api-key": None,
|
"openai-api-key": None,
|
||||||
"model": "text-davinci-003",
|
"model": "text-davinci-003",
|
||||||
"conversation-logfile": "~/.khoj/processor/conversation/conversation_logs.json",
|
"conversation-logfile": "~/.khoj/processor/conversation/conversation_logs.json",
|
||||||
|
"chat-model": "gpt-3.5-turbo",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,12 @@ class ConfigBase(BaseModel):
|
|||||||
alias_generator = to_snake_case_from_dash
|
alias_generator = to_snake_case_from_dash
|
||||||
allow_population_by_field_name = True
|
allow_population_by_field_name = True
|
||||||
|
|
||||||
|
def __getitem__(self, item):
|
||||||
|
return getattr(self, item)
|
||||||
|
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
return setattr(self, key, value)
|
||||||
|
|
||||||
|
|
||||||
class TextConfigBase(ConfigBase):
|
class TextConfigBase(ConfigBase):
|
||||||
compressed_jsonl: Path
|
compressed_jsonl: Path
|
||||||
|
|||||||
@@ -6,12 +6,20 @@ import yaml
|
|||||||
|
|
||||||
# Internal Packages
|
# Internal Packages
|
||||||
from khoj.utils.rawconfig import FullConfig
|
from khoj.utils.rawconfig import FullConfig
|
||||||
|
from khoj.utils import state
|
||||||
|
|
||||||
|
|
||||||
# Do not emit tags when dumping to YAML
|
# Do not emit tags when dumping to YAML
|
||||||
yaml.emitter.Emitter.process_tag = lambda self, *args, **kwargs: None # type: ignore[assignment]
|
yaml.emitter.Emitter.process_tag = lambda self, *args, **kwargs: None # type: ignore[assignment]
|
||||||
|
|
||||||
|
|
||||||
|
def save_config_to_file_updated_state():
|
||||||
|
with open(state.config_file, "w") as outfile:
|
||||||
|
yaml.dump(yaml.safe_load(state.config.json(by_alias=True)), outfile)
|
||||||
|
outfile.close()
|
||||||
|
return state.config
|
||||||
|
|
||||||
|
|
||||||
def save_config_to_file(yaml_config: dict, yaml_config_file: Path):
|
def save_config_to_file(yaml_config: dict, yaml_config_file: Path):
|
||||||
"Write config to YML file"
|
"Write config to YML file"
|
||||||
# Create output directory, if it doesn't exist
|
# Create output directory, if it doesn't exist
|
||||||
|
|||||||
Reference in New Issue
Block a user