Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,23 @@ PDFJS_VERSION_DIST="pdfjs-4.0.379-dist"
# settings for PaddleOCR
PADDLE_DEVICE=gpu

# setting for Tavily API (for web search)
TAVILY_API_KEY=

# variable for authentication method selection
# for authentication with google leave empty
# for authentication with keycloak :
# AUTHENTICATION_METHOD="KEYCLOAK"

AUTHENTICATION_METHOD=

# settings for keycloak
KEYCLOAK_SERVER_URL=
KEYCLOAK_CLIENT_ID=
KEYCLOAK_REALM=
KEYCLOAK_CLIENT_SECRET=

# settings for Gradio UI
# maximum concurrent indexing jobs from the file/index page
KH_GRADIO_INDEX_CONCURRENCY_LIMIT=20
# maximum concurrent quick indexing jobs from the chat upload flow
KH_GRADIO_QUICK_INDEX_CONCURRENCY_LIMIT=10
7 changes: 6 additions & 1 deletion app.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@

app = App()
demo = app.make()
demo.queue().launch(
queue_kwargs = {}
default_concurrency_limit = os.getenv("KH_GRADIO_DEFAULT_CONCURRENCY_LIMIT")
if default_concurrency_limit:
queue_kwargs["default_concurrency_limit"] = int(default_concurrency_limit)

demo.queue(**queue_kwargs).launch(
favicon_path=app._favicon,
inbrowser=True,
allowed_paths=[
Expand Down
17 changes: 15 additions & 2 deletions libs/ktem/ktem/assets/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,12 @@ function run() {
);
var last_bot_message = bot_messages[bot_messages.length - 1];

// check if the last bot message has class "text_selection"
if (last_bot_message.classList.contains("text_selection")) {
if (!last_bot_message) {
return;
}

// check if the last bot message has already been initialized
if (last_bot_message.dataset.evidenceSearchReady === "true") {
return;
}

Expand All @@ -165,6 +169,10 @@ function run() {
);
console.log("Indexing evidences", evidences);

if (evidences.length === 0) {
return;
}

const segmenterEn = new Intl.Segmenter("en", { granularity: "sentence" });
// Split sentences and save to all_segments list
var all_segments = [];
Expand All @@ -191,13 +199,18 @@ function run() {
}
}

if (all_segments.length === 0) {
return;
}

let miniSearch = new MiniSearch({
fields: ["text"], // fields to index for full-text search
storeFields: ["text"],
});

// Index all documents
miniSearch.addAll(all_segments);
last_bot_message.dataset.evidenceSearchReady = "true";

last_bot_message.addEventListener("mouseup", () => {
let selection = window.getSelection().toString();
Expand Down
6 changes: 4 additions & 2 deletions libs/ktem/ktem/embeddings/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,12 @@ def _on_app_created(self):
self.list_embeddings,
inputs=[],
outputs=[self.emb_list],
show_progress="hidden",
)
self._app.app.load(
lambda: gr.update(choices=list(embedding_models_manager.vendors().keys())),
outputs=[self.emb_choices],
show_progress="hidden",
)

def on_emb_vendor_change(self, vendor):
Expand Down Expand Up @@ -206,7 +208,7 @@ def on_register_events(self):
inputs=[self.selected_emb_name],
outputs=[self.selected_emb_name],
show_progress="hidden",
).then(
).success(
self.list_embeddings,
inputs=[],
outputs=[self.emb_list],
Expand All @@ -231,7 +233,7 @@ def on_register_events(self):
],
outputs=[self.selected_emb_name],
show_progress="hidden",
).then(
).success(
self.list_embeddings,
inputs=[],
outputs=[self.emb_list],
Expand Down
52 changes: 42 additions & 10 deletions libs/ktem/ktem/index/file/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@
DOWNLOAD_MESSAGE = "Start download"
MAX_FILENAME_LENGTH = 20
MAX_FILE_COUNT = 200
DEFAULT_INDEX_CONCURRENCY_LIMIT = int(
os.getenv("KH_GRADIO_INDEX_CONCURRENCY_LIMIT", "20")
)
DEFAULT_QUICK_INDEX_CONCURRENCY_LIMIT = int(
os.getenv("KH_GRADIO_QUICK_INDEX_CONCURRENCY_LIMIT", "10")
)

chat_input_focus_js = """
function() {
Expand Down Expand Up @@ -723,7 +729,7 @@ def on_register_quick_uploads(self):
self._app.user_id,
],
outputs=self.quick_upload_state,
concurrency_limit=10,
concurrency_limit=DEFAULT_QUICK_INDEX_CONCURRENCY_LIMIT,
)
.success(
fn=lambda: [
Expand Down Expand Up @@ -752,10 +758,16 @@ def on_register_quick_uploads(self):
outputs=self._app.chat_page.quick_file_upload_status,
)
.then(
fn=self.list_file,
inputs=[self._app.user_id, self.filter],
fn=self.list_file_if_index_changed,
inputs=[
self.quick_upload_state,
self._app.user_id,
self.filter,
self.file_list_state,
self.file_list,
],
outputs=[self.file_list_state, self.file_list],
concurrency_limit=20,
concurrency_limit=DEFAULT_INDEX_CONCURRENCY_LIMIT,
)
.then(
fn=lambda: True,
Expand All @@ -782,7 +794,7 @@ def on_register_quick_uploads(self):
self._app.user_id,
],
outputs=self.quick_upload_state,
concurrency_limit=10,
concurrency_limit=DEFAULT_QUICK_INDEX_CONCURRENCY_LIMIT,
)
.success(
fn=lambda: [
Expand All @@ -809,10 +821,16 @@ def on_register_quick_uploads(self):

if not KH_DEMO_MODE:
quickURLUploadedEvent = quickURLUploadedEvent.then(
fn=self.list_file,
inputs=[self._app.user_id, self.filter],
fn=self.list_file_if_index_changed,
inputs=[
self.quick_upload_state,
self._app.user_id,
self.filter,
self.file_list_state,
self.file_list,
],
outputs=[self.file_list_state, self.file_list],
concurrency_limit=20,
concurrency_limit=DEFAULT_INDEX_CONCURRENCY_LIMIT,
)

quickURLUploadedEvent = quickURLUploadedEvent.then(
Expand Down Expand Up @@ -981,7 +999,7 @@ def on_register_events(self):
self._app.user_id,
],
outputs=[self.upload_result, self.upload_info],
concurrency_limit=20,
concurrency_limit=DEFAULT_INDEX_CONCURRENCY_LIMIT,
)
.then(
fn=lambda: gr.update(value=""),
Expand All @@ -993,7 +1011,7 @@ def on_register_events(self):
fn=self.list_file,
inputs=[self._app.user_id, self.filter],
outputs=[self.file_list_state, self.file_list],
concurrency_limit=20,
concurrency_limit=DEFAULT_INDEX_CONCURRENCY_LIMIT,
)
for event in self._app.get_event(f"onFileIndex{self._index.id}Changed"):
uploadedEvent = uploadedEvent.then(**event)
Expand Down Expand Up @@ -1532,6 +1550,20 @@ def list_file(self, user_id, name_pattern=""):

return results, file_list

def list_file_if_index_changed(
self,
indexed_ids,
user_id,
name_pattern,
current_file_list_state,
current_file_list,
):
if not isinstance(indexed_ids, (list, tuple, set)) or not any(
bool(item) for item in indexed_ids
):
return current_file_list_state, current_file_list
return self.list_file(user_id, name_pattern)

def list_file_names(self, file_list_state):
if file_list_state:
file_names = [(item["name"], item["id"]) for item in file_list_state]
Expand Down
6 changes: 4 additions & 2 deletions libs/ktem/ktem/index/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ def _on_app_created(self):
self.list_indices,
inputs=[],
outputs=[self.index_list],
show_progress="hidden",
)
self._app.app.load(
lambda: gr.update(
Expand All @@ -121,6 +122,7 @@ def _on_app_created(self):
]
),
outputs=[self.index_type],
show_progress="hidden",
)

def on_register_events(self):
Expand Down Expand Up @@ -184,7 +186,7 @@ def on_register_events(self):
inputs=[self.selected_index_id],
outputs=[self.selected_index_id],
show_progress="hidden",
).then(self.list_indices, inputs=[], outputs=[self.index_list],).success(
).success(self.list_indices, inputs=[], outputs=[self.index_list],).success(
update_current_module_atime
)
self.btn_delete_no.click(
Expand All @@ -211,7 +213,7 @@ def on_register_events(self):
self.edit_spec,
],
show_progress="hidden",
).then(
).success(
self.list_indices,
inputs=[],
outputs=[self.index_list],
Expand Down
6 changes: 4 additions & 2 deletions libs/ktem/ktem/llms/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,12 @@ def _on_app_created(self):
self.list_llms,
inputs=[],
outputs=[self.llm_list],
show_progress="hidden",
)
self._app.app.load(
lambda: gr.update(choices=list(llms.vendors().keys())),
outputs=[self.llm_choices],
show_progress="hidden",
)

def on_llm_vendor_change(self, vendor):
Expand Down Expand Up @@ -205,7 +207,7 @@ def on_register_events(self):
inputs=[self.selected_llm_name],
outputs=[self.selected_llm_name],
show_progress="hidden",
).then(
).success(
self.list_llms,
inputs=[],
outputs=[self.llm_list],
Expand All @@ -230,7 +232,7 @@ def on_register_events(self):
],
outputs=[self.selected_llm_name],
show_progress="hidden",
).then(
).success(
self.list_llms,
inputs=[],
outputs=[self.llm_list],
Expand Down
19 changes: 13 additions & 6 deletions libs/ktem/ktem/mcp/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def __init__(self, app):

def on_building_ui(self):
with gr.Tab(label="View"):
self.last_fetched_mcp_name = gr.State(value="")
self.mcp_list = gr.DataFrame(
headers=["name", "config"],
interactive=False,
Expand Down Expand Up @@ -95,6 +96,7 @@ def _on_app_created(self):
self.list_servers,
inputs=[],
outputs=[self.mcp_list],
show_progress="hidden",
)

def on_register_events(self):
Expand Down Expand Up @@ -140,9 +142,9 @@ def on_register_events(self):
],
show_progress="hidden",
).then(
self.fetch_tools_for_view,
inputs=[self.selected_mcp_name],
outputs=[self.edit_tools_display],
self.fetch_tools_for_view_if_needed,
inputs=[self.selected_mcp_name, self.last_fetched_mcp_name],
outputs=[self.edit_tools_display, self.last_fetched_mcp_name],
)

# Delete flow
Expand All @@ -157,7 +159,7 @@ def on_register_events(self):
inputs=[self.selected_mcp_name],
outputs=[self.selected_mcp_name],
show_progress="hidden",
).then(self.list_servers, inputs=[], outputs=[self.mcp_list])
).success(self.list_servers, inputs=[], outputs=[self.mcp_list])
for event in self._app.get_event("onMCPServersChanged"):
delete_chain = delete_chain.then(**event)
self.btn_delete_no.click(
Expand All @@ -179,7 +181,7 @@ def on_register_events(self):
outputs=[self.edit_tools_display],
show_progress="hidden",
)
.then(self.list_servers, inputs=[], outputs=[self.mcp_list])
.success(self.list_servers, inputs=[], outputs=[self.mcp_list])
.then(
self.fetch_tools_for_view,
inputs=[self.selected_mcp_name],
Expand All @@ -192,7 +194,12 @@ def on_register_events(self):
# Close panel
self.btn_close.click(lambda: "", outputs=[self.selected_mcp_name])

# --- Handlers ---
# --- Handlers ---

def fetch_tools_for_view_if_needed(self, selected_name, last_fetched_name):
if not selected_name or selected_name == last_fetched_name:
return gr.update(), last_fetched_name
return self.fetch_tools_for_view(selected_name), selected_name

def _fetch_tools_markdown(self, config: dict) -> str:
"""Fetch tools from MCP server and return as formatted HTML."""
Expand Down
Loading
Loading