diff --git a/pyproject.toml b/pyproject.toml index c374934a..bc5b04a2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -73,15 +73,15 @@ khoj = "khoj.main:run" [project.optional-dependencies] test = [ "pytest >= 7.1.2", + "freezegun >= 1.2.0", + "factory-boy >= 3.2.1", + "trio >= 0.22.0", ] dev = [ "khoj-assistant[test]", "mypy >= 1.0.1", "black >= 23.1.0", "pre-commit >= 3.0.4", - "freezegun >= 1.2.0", - "factory-boy==3.2.1", - "Faker==18.10.1", ] [tool.hatch.version] diff --git a/src/interface/emacs/khoj.el b/src/interface/emacs/khoj.el index 73c423e1..57f177cd 100644 --- a/src/interface/emacs/khoj.el +++ b/src/interface/emacs/khoj.el @@ -598,9 +598,19 @@ CONFIG is json obtained from Khoj config API." "Convert JSON-RESPONSE, QUERY from API to text entries." (thread-last json-response ;; extract and render entries from API response - (mapcar (lambda (args) (format "%s\n\n" (cdr (assoc 'entry args))))) + (mapcar (lambda (json-response-item) + (thread-last + ;; Extract pdf entry from each item in json response + (cdr (assoc 'entry json-response-item)) + (format "%s\n\n") + ;; Standardize results to 2nd level heading for consistent rendering + (replace-regexp-in-string "^\*+" "") + ;; Standardize results to 2nd level heading for consistent rendering + (replace-regexp-in-string "^\#+" "") + ;; Format entries as org entry string + (format "** %s")))) ;; Set query as heading in rendered results buffer - (format "# Query: %s\n\n%s\n" query) + (format "* %s\n%s\n" query) ;; remove leading (, ) or SPC from extracted entries string (replace-regexp-in-string "^[\(\) ]" "") ;; remove trailing (, ) or SPC from extracted entries string @@ -674,7 +684,8 @@ Render results in BUFFER-NAME using QUERY, CONTENT-TYPE." ((equal content-type "ledger") (khoj--extract-entries-as-ledger json-response query)) ((equal content-type "image") (khoj--extract-entries-as-images json-response query)) (t (khoj--extract-entries json-response query)))) - (cond ((or (equal content-type "pdf") + (cond ((or (equal content-type "all") + (equal content-type "pdf") (equal content-type "org")) (progn (visual-line-mode) (org-mode) @@ -1003,7 +1014,7 @@ Paragraph only starts at first text after blank line." ;; set content type to: last used > based on current buffer > default type :init-value (lambda (obj) (oset obj value (format "--content-type=%s" (or khoj--content-type (khoj--buffer-name-to-content-type (buffer-name)))))) ;; dynamically set choices to content types enabled on khoj backend - :choices (or (ignore-errors (mapcar #'symbol-name (khoj--get-enabled-content-types))) '("org" "markdown" "pdf" "ledger" "music" "image"))) + :choices (or (ignore-errors (mapcar #'symbol-name (khoj--get-enabled-content-types))) '("all" "org" "markdown" "pdf" "ledger" "music" "image"))) (transient-define-suffix khoj--search-command (&optional args) (interactive (list (transient-args transient-current-command))) diff --git a/src/khoj/configure.py b/src/khoj/configure.py index 1b3feea8..050cf069 100644 --- a/src/khoj/configure.py +++ b/src/khoj/configure.py @@ -3,6 +3,7 @@ import sys import logging import json from enum import Enum +from typing import Optional import requests # External Packages @@ -36,7 +37,7 @@ def configure_server(args, required=False): logger.error(f"Exiting as Khoj is not configured.\nConfigure it via GUI or by editing {state.config_file}.") sys.exit(1) else: - logger.warn( + logger.warning( f"Khoj is not configured.\nConfigure it via khoj GUI, plugins or by editing {state.config_file}." ) return @@ -78,16 +79,20 @@ def configure_search_types(config: FullConfig): core_search_types = {e.name: e.value for e in SearchType} # Extract configured plugin search types plugin_search_types = {} - if config.content_type.plugins: + if config.content_type and config.content_type.plugins: plugin_search_types = {plugin_type: plugin_type for plugin_type in config.content_type.plugins.keys()} # Dynamically generate search type enum by merging core search types with configured plugin search types return Enum("SearchType", merge_dicts(core_search_types, plugin_search_types)) -def configure_search(model: SearchModels, config: FullConfig, regenerate: bool, t: state.SearchType = None): +def configure_search(model: SearchModels, config: FullConfig, regenerate: bool, t: Optional[state.SearchType] = None): + if config is None or config.content_type is None or config.search_type is None: + logger.warning("🚨 No Content or Search type is configured.") + return + # Initialize Org Notes Search - if (t == state.SearchType.Org or t == None) and config.content_type.org: + if (t == state.SearchType.Org or t == None) and config.content_type.org and config.search_type.asymmetric: logger.info("🦄 Setting up search for orgmode notes") # Extract Entries, Generate Notes Embeddings model.org_search = text_search.setup( @@ -99,7 +104,7 @@ def configure_search(model: SearchModels, config: FullConfig, regenerate: bool, ) # Initialize Org Music Search - if (t == state.SearchType.Music or t == None) and config.content_type.music: + if (t == state.SearchType.Music or t == None) and config.content_type.music and config.search_type.asymmetric: logger.info("🎺 Setting up search for org-music") # Extract Entries, Generate Music Embeddings model.music_search = text_search.setup( @@ -111,7 +116,7 @@ def configure_search(model: SearchModels, config: FullConfig, regenerate: bool, ) # Initialize Markdown Search - if (t == state.SearchType.Markdown or t == None) and config.content_type.markdown: + if (t == state.SearchType.Markdown or t == None) and config.content_type.markdown and config.search_type.asymmetric: logger.info("💎 Setting up search for markdown notes") # Extract Entries, Generate Markdown Embeddings model.markdown_search = text_search.setup( @@ -123,7 +128,7 @@ def configure_search(model: SearchModels, config: FullConfig, regenerate: bool, ) # Initialize Ledger Search - if (t == state.SearchType.Ledger or t == None) and config.content_type.ledger: + if (t == state.SearchType.Ledger or t == None) and config.content_type.ledger and config.search_type.symmetric: logger.info("💸 Setting up search for ledger") # Extract Entries, Generate Ledger Embeddings model.ledger_search = text_search.setup( @@ -135,7 +140,7 @@ def configure_search(model: SearchModels, config: FullConfig, regenerate: bool, ) # Initialize PDF Search - if (t == state.SearchType.Pdf or t == None) and config.content_type.pdf: + if (t == state.SearchType.Pdf or t == None) and config.content_type.pdf and config.search_type.asymmetric: logger.info("🖨️ Setting up search for pdf") # Extract Entries, Generate PDF Embeddings model.pdf_search = text_search.setup( @@ -147,14 +152,14 @@ def configure_search(model: SearchModels, config: FullConfig, regenerate: bool, ) # Initialize Image Search - if (t == state.SearchType.Image or t == None) and config.content_type.image: + if (t == state.SearchType.Image or t == None) and config.content_type.image and config.search_type.image: logger.info("🌄 Setting up search for images") # Extract Entries, Generate Image Embeddings model.image_search = image_search.setup( config.content_type.image, search_config=config.search_type.image, regenerate=regenerate ) - if (t == state.SearchType.Github or t == None) and config.content_type.github: + if (t == state.SearchType.Github or t == None) and config.content_type.github and config.search_type.asymmetric: logger.info("🐙 Setting up search for github") # Extract Entries, Generate Github Embeddings model.github_search = text_search.setup( diff --git a/src/khoj/interface/web/index.html b/src/khoj/interface/web/index.html index 3bdb7b12..c9d69035 100644 --- a/src/khoj/interface/web/index.html +++ b/src/khoj/interface/web/index.html @@ -14,11 +14,13 @@