Merge pull request #269 from khoj-ai/features/simplify-configuration-steps

Simplify some common configuration steps
This commit is contained in:
sabaimran
2023-07-03 00:16:51 -07:00
committed by GitHub
8 changed files with 233 additions and 36 deletions

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 122.88 122.88"><defs><style>.cls-1{fill:#00a912;}.cls-1,.cls-2{fill-rule:evenodd;}.cls-2{fill:#fff;}</style></defs><title>confirm</title><path class="cls-1" d="M61.44,0A61.44,61.44,0,1,1,0,61.44,61.44,61.44,0,0,1,61.44,0Z"/><path class="cls-2" d="M42.37,51.68,53.26,62,79,35.87c2.13-2.16,3.47-3.9,6.1-1.19l8.53,8.74c2.8,2.77,2.66,4.4,0,7L58.14,85.34c-5.58,5.46-4.61,5.79-10.26.19L28,65.77c-1.18-1.28-1.05-2.57.24-3.84l9.9-10.27c1.5-1.58,2.7-1.44,4.22,0Z"/></svg>

After

Width:  |  Height:  |  Size: 549 B

View File

@@ -55,7 +55,7 @@
gap: 8px; gap: 8px;
padding: 24px 16px; padding: 24px 16px;
width: 320px; width: 320px;
height: 160px; height: 180px;
background: white; background: white;
border: 1px solid rgb(229, 229, 229); border: 1px solid rgb(229, 229, 229);
border-radius: 4px; border-radius: 4px;
@@ -114,6 +114,22 @@
font-size: 16px; font-size: 16px;
} }
button.card-button {
color: rgb(255, 136, 136);
background: transparent;
font-size: 16px;
cursor: pointer;
margin: 0;
padding: 0;
height: 32px;
text-align: right;
text-align: left;
}
img.configured-icon {
max-width: 16px;
}
@media screen and (max-width: 600px) { @media screen and (max-width: 600px) {
.section-cards { .section-cards {
grid-template-columns: 1fr; grid-template-columns: 1fr;

View File

@@ -8,62 +8,127 @@
<div class="card"> <div class="card">
<div class="card-title-row"> <div class="card-title-row">
<img class="card-icon" src="/static/assets/icons/github.svg" alt="Github"> <img class="card-icon" src="/static/assets/icons/github.svg" alt="Github">
<h3 class="card-title">Github</h3> <h3 class="card-title">
Github
{% if current_config.content_type.github %}
<img id="configured-icon-github" class="configured-icon" src="/static/assets/icons/confirm-icon.svg" alt="Configured">
{% endif %}
</h3>
</div> </div>
<div class="card-description-row"> <div class="card-description-row">
<p class="card-description">Set repositories for Khoj to index</p> <p class="card-description">Set repositories for Khoj to index</p>
</div> </div>
<div class="card-action-row"> <div class="card-action-row">
<a class="card-button" href="/config/content_type/github"> <a class="card-button" href="/config/content_type/github">
{% if current_config.content_type.github %}
Update
{% else %}
Setup Setup
{% endif %}
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"></path></svg>
</a> </a>
</div> </div>
{% if current_config.content_type.github %}
<div id="clear-github" class="card-action-row">
<button class="card-button" onclick="clearContentType('github')">
Disable
</button>
</div>
{% endif %}
</div> </div>
<div class="card"> <div class="card">
<div class="card-title-row"> <div class="card-title-row">
<img class="card-icon" src="/static/assets/icons/markdown.svg" alt="markdown"> <img class="card-icon" src="/static/assets/icons/markdown.svg" alt="markdown">
<h3 class="card-title">Markdown</h3> <h3 class="card-title">
Markdown
{% if current_config.content_type.markdown %}
<img id="configured-icon-markdown" class="configured-icon" src="/static/assets/icons/confirm-icon.svg" alt="Configured">
{% endif %}
</h3>
</div> </div>
<div class="card-description-row"> <div class="card-description-row">
<p class="card-description">Set markdown files for Khoj to index</p> <p class="card-description">Set markdown files for Khoj to index</p>
</div> </div>
<div class="card-action-row"> <div class="card-action-row">
<a class="card-button" href="/config/content_type/markdown"> <a class="card-button" href="/config/content_type/markdown">
{% if current_config.content_type.markdown %}
Update
{% else %}
Setup Setup
{% endif %}
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"></path></svg>
</a> </a>
</div> </div>
{% if current_config.content_type.markdown %}
<div id="clear-markdown" class="card-action-row">
<button class="card-button" onclick="clearContentType('markdown')">
Disable
</button>
</div>
{% endif %}
</div> </div>
<div class="card"> <div class="card">
<div class="card-title-row"> <div class="card-title-row">
<img class="card-icon" src="/static/assets/icons/org.svg" alt="org"> <img class="card-icon" src="/static/assets/icons/org.svg" alt="org">
<h3 class="card-title">Org</h3> <h3 class="card-title">
Org
{% if current_config.content_type.org %}
<img id="configured-icon-org" class="configured-icon" src="/static/assets/icons/confirm-icon.svg" alt="Configured">
{% endif %}
</h3>
</div> </div>
<div class="card-description-row"> <div class="card-description-row">
<p class="card-description">Set org files for Khoj to index</p> <p class="card-description">Set org files for Khoj to index</p>
</div> </div>
<div class="card-action-row"> <div class="card-action-row">
<a class="card-button" href="/config/content_type/org"> <a class="card-button" href="/config/content_type/org">
{% if current_config.content_type.org %}
Update
{% else %}
Setup Setup
{% endif %}
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"></path></svg>
</a> </a>
</div> </div>
{% if current_config.content_type.org %}
<div id="clear-org" class="card-action-row">
<button class="card-button" onclick="clearContentType('org')">
Disable
</button>
</div>
{% endif %}
</div> </div>
<div class="card"> <div class="card">
<div class="card-title-row"> <div class="card-title-row">
<img class="card-icon" src="/static/assets/icons/pdf.svg" alt="PDF"> <img class="card-icon" src="/static/assets/icons/pdf.svg" alt="PDF">
<h3 class="card-title">PDF</h3> <h3 class="card-title">
PDF
{% if current_config.content_type.pdf %}
<img id="configured-icon-pdf" class="configured-icon" src="/static/assets/icons/confirm-icon.svg" alt="Configured">
{% endif %}
</h3>
</div> </div>
<div class="card-description-row"> <div class="card-description-row">
<p class="card-description">Set PDF files for Khoj to index</p> <p class="card-description">Set PDF files for Khoj to index</p>
</div> </div>
<div class="card-action-row"> <div class="card-action-row">
<a class="card-button" href="/config/content_type/pdf"> <a class="card-button" href="/config/content_type/pdf">
{% if current_config.content_type.pdf %}
Update
{% else %}
Setup Setup
{% endif %}
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"></path></svg>
</a> </a>
</div> </div>
{% if current_config.content_type.pdf %}
<div id="clear-pdf" class="card-action-row">
<button class="card-button" onclick="clearContentType('pdf')">
Disable
</button>
</div>
{% endif %}
</div> </div>
</div> </div>
</div> </div>
@@ -73,26 +138,85 @@
<div class="card"> <div class="card">
<div class="card-title-row"> <div class="card-title-row">
<img class="card-icon" src="/static/assets/icons/chat.svg" alt="Chat"> <img class="card-icon" src="/static/assets/icons/chat.svg" alt="Chat">
<h3 class="card-title">Chat</h3> <h3 class="card-title">
Chat
{% if current_config.processor and current_config.processor.conversation %}
<img id="configured-icon-conversation-processor" class="configured-icon" src="/static/assets/icons/confirm-icon.svg" alt="Configured">
{% endif %}
</h3>
</div> </div>
<div class="card-description-row"> <div class="card-description-row">
<p class="card-description">Setup Khoj Chat</p> <p class="card-description">Setup Khoj Chat with OpenAI</p>
</div> </div>
<div class="card-action-row"> <div class="card-action-row">
<a class="card-button" href="/config/processor/conversation"> <a class="card-button" href="/config/processor/conversation">
{% if current_config.processor and current_config.processor.conversation %}
Update
{% else %}
Setup Setup
{% endif %}
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"></path></svg>
</a> </a>
</div> </div>
{% if current_config.processor and current_config.processor.conversation %}
<div id="clear-conversation" class="card-action-row">
<button class="card-button" onclick="clearConversationProcessor()">
Disable
</button>
</div>
{% endif %}
</div> </div>
</div> </div>
</div> </div>
<div class="section"> <div class="section">
<div id="status" style="display: none;"></div> <div id="status" style="display: none;"></div>
<button id="configure" type="submit">⚙️ Configure</button> <button id="configure" type="submit">⚙️ Configure</button>
<button id="reinitialize" type="submit">🔄 Reinitialize</button>
</div> </div>
</div> </div>
<script> <script>
function clearContentType(content_type) {
const csrfToken = document.cookie.split('; ').find(row => row.startsWith('csrftoken'))?.split('=')[1];
fetch('/api/delete/config/data/content_type/' + content_type, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
}
})
.then(response => response.json())
.then(data => {
if (data.status == "ok") {
var contentTypeClearButton = document.getElementById("clear-" + content_type);
contentTypeClearButton.style.display = "none";
var configuredIcon = document.getElementById("configured-icon-" + content_type);
configuredIcon.style.display = "none";
}
})
};
function clearConversationProcessor() {
const csrfToken = document.cookie.split('; ').find(row => row.startsWith('csrftoken'))?.split('=')[1];
fetch('/api/delete/config/data/processor/conversation', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
}
})
.then(response => response.json())
.then(data => {
if (data.status == "ok") {
var conversationClearButton = document.getElementById("clear-conversation");
conversationClearButton.style.display = "none";
var configuredIcon = document.getElementById("configured-icon-conversation-processor");
configuredIcon.style.display = "none";
}
})
};
var configure = document.getElementById("configure"); var configure = document.getElementById("configure");
configure.addEventListener("click", function(event) { configure.addEventListener("click", function(event) {
event.preventDefault(); event.preventDefault();
@@ -122,5 +246,35 @@
configure.innerHTML = "⚙️ Configure"; configure.innerHTML = "⚙️ Configure";
}); });
}); });
var reinitialize = document.getElementById("reinitialize");
reinitialize.addEventListener("click", function(event) {
event.preventDefault();
reinitialize.disabled = true;
reinitialize.innerHTML = "Reinitializing...";
const csrfToken = document.cookie.split('; ').find(row => row.startsWith('csrftoken'))?.split('=')[1];
fetch('/api/update?&client=web?force=true', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
}
})
.then(response => response.json())
.then(data => {
console.log('Success:', data);
document.getElementById("status").innerHTML = "Reinitialized successfully!";
document.getElementById("status").style.display = "block";
reinitialize.disabled = false;
reinitialize.innerHTML = "🔄 Reinitialized";
})
.catch((error) => {
console.error('Error:', error);
document.getElementById("status").innerHTML = "Unable to reinitialize. Raise issue on Khoj Discord or Github.";
document.getElementById("status").style.display = "block";
reinitialize.disabled = false;
reinitialize.innerHTML = "🔄 Reinitialize";
});
});
</script> </script>
{% endblock %} {% endblock %}

View File

@@ -35,9 +35,7 @@
{% endfor %} {% endfor %}
</div> </div>
<button type="button" id="add-repository-button">Add Repository</button> <button type="button" id="add-repository-button">Add Repository</button>
<h4>You probably don't need to edit these.</h4> <table style="display: none;" >
<table>
<tr> <tr>
<td> <td>
<label for="compressed-jsonl">Compressed JSONL (Output)</label> <label for="compressed-jsonl">Compressed JSONL (Output)</label>
@@ -160,7 +158,7 @@
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
if (data["status"] == "ok") { if (data["status"] == "ok") {
document.getElementById("success").innerHTML = "✅ Successfully updated. Click Configure on your <a href='/config'>settings page</a> to complete your Khoj setup."; document.getElementById("success").innerHTML = "✅ Successfully updated. Go to your <a href='/config'>settings page</a> to complete setup.";
document.getElementById("success").style.display = "block"; document.getElementById("success").style.display = "block";
} else { } else {
document.getElementById("success").innerHTML = "⚠️ Failed to update settings."; document.getElementById("success").innerHTML = "⚠️ Failed to update settings.";

View File

@@ -44,9 +44,7 @@
</tr> </tr>
</table> </table>
<h4>You probably don't need to edit these.</h4> <table style="display: none;" >
<table>
<tr> <tr>
<td> <td>
<label for="compressed-jsonl">Compressed JSONL (Output)</label> <label for="compressed-jsonl">Compressed JSONL (Output)</label>
@@ -149,7 +147,7 @@
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
if (data["status"] == "ok") { if (data["status"] == "ok") {
document.getElementById("success").innerHTML = "✅ Successfully updated. Click Configure on your <a href='/config'>settings page</a> to complete your Khoj setup."; document.getElementById("success").innerHTML = "✅ Successfully updated. Go to your <a href='/config'>settings page</a> to complete setup.";
document.getElementById("success").style.display = "block"; document.getElementById("success").style.display = "block";
} else { } else {
document.getElementById("success").innerHTML = "⚠️ Failed to update settings."; document.getElementById("success").innerHTML = "⚠️ Failed to update settings.";

View File

@@ -17,11 +17,8 @@
</td> </td>
</tr> </tr>
</table> </table>
<h4>You probably don't need to edit these.</h4>
<table > <table >
<tr> <tr style="display: none;">
<td> <td>
<label for="conversation-logfile">Conversation Logfile</label> <label for="conversation-logfile">Conversation Logfile</label>
</td> </td>
@@ -78,7 +75,7 @@
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
if (data["status"] == "ok") { if (data["status"] == "ok") {
document.getElementById("success").innerHTML = "✅ Successfully updated. Click Configure on your <a href='/config'>settings page</a> to complete your Khoj setup."; document.getElementById("success").innerHTML = "✅ Successfully updated. Go to your <a href='/config'>settings page</a> to complete setup.";
document.getElementById("success").style.display = "block"; document.getElementById("success").style.display = "block";
} else { } else {
document.getElementById("success").innerHTML = "⚠️ Failed to update settings."; document.getElementById("success").innerHTML = "⚠️ Failed to update settings.";

View File

@@ -54,7 +54,7 @@ if not state.demo:
return state.config return state.config
@api.post("/config/data/content_type/github", status_code=200) @api.post("/config/data/content_type/github", status_code=200)
async def set_content_config_github_data(updated_config: GithubContentConfig): async def set_content_config_github_data(updated_config: Union[GithubContentConfig, None]):
if not state.config: if not state.config:
state.config = FullConfig() state.config = FullConfig()
state.config.search_type = SearchConfig.parse_obj(constants.default_config["search-type"]) state.config.search_type = SearchConfig.parse_obj(constants.default_config["search-type"])
@@ -70,8 +70,35 @@ if not state.demo:
except Exception as e: except Exception as e:
return {"status": "error", "message": str(e)} return {"status": "error", "message": str(e)}
@api.post("/delete/config/data/content_type/{content_type}", status_code=200)
async def remove_content_config_data(content_type: str):
if not state.config or not state.config.content_type:
return {"status": "ok"}
if state.config.content_type:
state.config.content_type[content_type] = None
try:
save_config_to_file_updated_state()
return {"status": "ok"}
except Exception as e:
return {"status": "error", "message": str(e)}
@api.post("/delete/config/data/processor/conversation", status_code=200)
async def remove_processor_conversation_config_data():
if not state.config or not state.config.processor or not state.config.processor.conversation:
return {"status": "ok"}
state.config.processor.conversation = None
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) @api.post("/config/data/content_type/{content_type}", status_code=200)
async def set_content_config_data(content_type: str, updated_config: TextContentConfig): async def set_content_config_data(content_type: str, updated_config: Union[TextContentConfig, None]):
if not state.config: if not state.config:
state.config = FullConfig() state.config = FullConfig()
state.config.search_type = SearchConfig.parse_obj(constants.default_config["search-type"]) state.config.search_type = SearchConfig.parse_obj(constants.default_config["search-type"])
@@ -88,7 +115,7 @@ if not state.demo:
return {"status": "error", "message": str(e)} return {"status": "error", "message": str(e)}
@api.post("/config/data/processor/conversation", status_code=200) @api.post("/config/data/processor/conversation", status_code=200)
async def set_processor_conversation_config_data(updated_config: ConversationProcessorConfig): async def set_processor_conversation_config_data(updated_config: Union[ConversationProcessorConfig, None]):
if not state.config: if not state.config:
state.config = FullConfig() state.config = FullConfig()
state.config.search_type = SearchConfig.parse_obj(constants.default_config["search-type"]) state.config.search_type = SearchConfig.parse_obj(constants.default_config["search-type"])
@@ -342,6 +369,7 @@ def update(
logger.info("📬 Search index updated via API") logger.info("📬 Search index updated via API")
try: try:
if state.config and state.config.processor:
state.processor_config = configure_processor(state.config.processor) state.processor_config = configure_processor(state.config.processor)
except ValueError as e: except ValueError as e:
logger.error(e) logger.error(e)

View File

@@ -3,12 +3,11 @@ 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 from khoj.utils.rawconfig import TextContentConfig, ConversationProcessorConfig, FullConfig
# Internal Packages # Internal Packages
from khoj.utils import constants, state from khoj.utils import constants, state
import logging
import json import json
@@ -34,7 +33,13 @@ if not state.demo:
@web_client.get("/config", response_class=HTMLResponse) @web_client.get("/config", response_class=HTMLResponse)
def config_page(request: Request): def config_page(request: Request):
return templates.TemplateResponse("config.html", context={"request": request}) default_full_config = FullConfig(
content_type=None,
search_type=None,
processor=None,
)
current_config = state.config or json.loads(default_full_config.json())
return templates.TemplateResponse("config.html", context={"request": request, "current_config": current_config})
@web_client.get("/config/content_type/github", response_class=HTMLResponse) @web_client.get("/config/content_type/github", response_class=HTMLResponse)
def github_config_page(request: Request): def github_config_page(request: Request):