mirror of
https://github.com/khoaliber/khoj.git
synced 2026-03-09 13:25:11 +00:00
Merge pull request #361 from khoj-ai/configure-offline-chat-from-emacs
- Configure using Offline Chat from Emacs: - Enable, Disable Offline Chat from Emacs - Use: Enable offline chat with `(setq khoj-chat-offline t)' during khoj setup - Benefits: Offline chat models are better for privacy but not great at answering questions
This commit is contained in:
@@ -231,6 +231,11 @@ for example), set this to the full interpreter path."
|
|||||||
:type 'string
|
:type 'string
|
||||||
:group 'khoj)
|
:group 'khoj)
|
||||||
|
|
||||||
|
(defcustom khoj-chat-offline nil
|
||||||
|
"Use offline model to chat with khoj."
|
||||||
|
:type 'boolean
|
||||||
|
:group 'khoj)
|
||||||
|
|
||||||
(defcustom khoj-auto-setup t
|
(defcustom khoj-auto-setup t
|
||||||
"Automate install, configure and start of khoj server.
|
"Automate install, configure and start of khoj server.
|
||||||
Auto invokes setup steps on calling main entrypoint."
|
Auto invokes setup steps on calling main entrypoint."
|
||||||
@@ -375,6 +380,7 @@ CONFIG is json obtained from Khoj config API."
|
|||||||
(default-chat-dir (khoj--get-directory-from-config default-config '(processor conversation conversation-logfile)))
|
(default-chat-dir (khoj--get-directory-from-config default-config '(processor conversation conversation-logfile)))
|
||||||
(chat-model (or khoj-chat-model (alist-get 'chat-model (alist-get 'openai (alist-get 'conversation (alist-get 'processor default-config))))))
|
(chat-model (or khoj-chat-model (alist-get 'chat-model (alist-get 'openai (alist-get 'conversation (alist-get 'processor default-config))))))
|
||||||
(default-model (alist-get 'model (alist-get 'conversation (alist-get 'processor default-config))))
|
(default-model (alist-get 'model (alist-get 'conversation (alist-get 'processor default-config))))
|
||||||
|
(enable-offline-chat (or khoj-chat-offline (alist-get 'enable-offline-chat (alist-get 'conversation (alist-get 'processor default-config)))))
|
||||||
(config (or current-config default-config)))
|
(config (or current-config default-config)))
|
||||||
|
|
||||||
;; Configure content types
|
;; Configure content types
|
||||||
@@ -428,40 +434,44 @@ CONFIG is json obtained from Khoj config API."
|
|||||||
(openai (assoc 'openai conversation)))
|
(openai (assoc 'openai conversation)))
|
||||||
(when openai
|
(when openai
|
||||||
;; Unset the `openai' field in the khoj conversation processor config
|
;; Unset the `openai' field in the khoj conversation processor config
|
||||||
(message "khoj.el: disable Khoj Chat using OpenAI as your OpenAI API key got removed from config")
|
(message "khoj.el: Disable Chat using OpenAI as your OpenAI API key got removed from config")
|
||||||
(setcdr conversation (delq openai (cdr conversation)))
|
(setcdr conversation (delq openai (cdr conversation)))
|
||||||
(setcdr processor (delq conversation (cdr processor)))
|
|
||||||
(setq config (delq processor config))
|
|
||||||
(push conversation (cdr processor))
|
(push conversation (cdr processor))
|
||||||
(push processor config))))
|
(push processor config))))
|
||||||
|
|
||||||
|
;; If khoj backend isn't configured yet
|
||||||
((not current-config)
|
((not current-config)
|
||||||
(message "khoj.el: Chat not configured yet.")
|
(message "khoj.el: Chat not configured yet.")
|
||||||
(setq config (delq (assoc 'processor config) config))
|
(setq config (delq (assoc 'processor config) config))
|
||||||
(cl-pushnew `(processor . ((conversation . ((conversation-logfile . ,(format "%s/conversation.json" default-chat-dir))
|
(cl-pushnew `(processor . ((conversation . ((conversation-logfile . ,(format "%s/conversation.json" default-chat-dir))
|
||||||
|
(enable-offline-chat . ,enable-offline-chat)
|
||||||
(openai . ((chat-model . ,chat-model)
|
(openai . ((chat-model . ,chat-model)
|
||||||
(api-key . ,khoj-openai-api-key)))))))
|
(api-key . ,khoj-openai-api-key)))))))
|
||||||
config))
|
config))
|
||||||
|
|
||||||
|
;; Else if chat isn't configured in khoj backend
|
||||||
((not (alist-get 'conversation (alist-get 'processor config)))
|
((not (alist-get 'conversation (alist-get 'processor config)))
|
||||||
(message "khoj.el: Chat not configured yet.")
|
(message "khoj.el: Chat not configured yet.")
|
||||||
(let ((new-processor-type (alist-get 'processor config)))
|
(let ((new-processor-type (alist-get 'processor config)))
|
||||||
(setq new-processor-type (delq (assoc 'conversation new-processor-type) new-processor-type))
|
(setq new-processor-type (delq (assoc 'conversation new-processor-type) new-processor-type))
|
||||||
(cl-pushnew `(conversation . ((conversation-logfile . ,(format "%s/conversation.json" default-chat-dir))
|
(cl-pushnew `(conversation . ((conversation-logfile . ,(format "%s/conversation.json" default-chat-dir))
|
||||||
|
(enable-offline-chat . ,enable-offline-chat)
|
||||||
(openai . ((chat-model . ,chat-model)
|
(openai . ((chat-model . ,chat-model)
|
||||||
(api-key . ,khoj-openai-api-key)))))
|
(api-key . ,khoj-openai-api-key)))))
|
||||||
new-processor-type)
|
new-processor-type)
|
||||||
(setq config (delq (assoc 'processor config) config))
|
(setq config (delq (assoc 'processor config) config))
|
||||||
(cl-pushnew `(processor . ,new-processor-type) config)))
|
(cl-pushnew `(processor . ,new-processor-type) config)))
|
||||||
|
|
||||||
;; Else if khoj is not configured with specified openai api key
|
;; Else if chat configuration in khoj backend has gone stale
|
||||||
((not (and (equal (alist-get 'api-key (alist-get 'openai (alist-get 'conversation (alist-get 'processor config)))) khoj-openai-api-key)
|
((not (and (equal (alist-get 'api-key (alist-get 'openai (alist-get 'conversation (alist-get 'processor config)))) khoj-openai-api-key)
|
||||||
(equal (alist-get 'chat-model (alist-get 'openai (alist-get 'conversation (alist-get 'processor config)))) khoj-chat-model)))
|
(equal (alist-get 'chat-model (alist-get 'openai (alist-get 'conversation (alist-get 'processor config)))) khoj-chat-model)
|
||||||
|
(equal (alist-get 'enable-offline-chat (alist-get 'conversation (alist-get 'processor config))) enable-offline-chat)))
|
||||||
(message "khoj.el: Chat configuration has gone stale.")
|
(message "khoj.el: Chat configuration has gone stale.")
|
||||||
(let* ((chat-directory (khoj--get-directory-from-config config '(processor conversation conversation-logfile)))
|
(let* ((chat-directory (khoj--get-directory-from-config config '(processor conversation conversation-logfile)))
|
||||||
(new-processor-type (alist-get 'processor config)))
|
(new-processor-type (alist-get 'processor config)))
|
||||||
(setq new-processor-type (delq (assoc 'conversation new-processor-type) new-processor-type))
|
(setq new-processor-type (delq (assoc 'conversation new-processor-type) new-processor-type))
|
||||||
(cl-pushnew `(conversation . ((conversation-logfile . ,(format "%s/conversation.json" chat-directory))
|
(cl-pushnew `(conversation . ((conversation-logfile . ,(format "%s/conversation.json" chat-directory))
|
||||||
|
(enable-offline-chat . ,enable-offline-chat)
|
||||||
(openai . ((chat-model . ,khoj-chat-model)
|
(openai . ((chat-model . ,khoj-chat-model)
|
||||||
(api-key . ,khoj-openai-api-key)))))
|
(api-key . ,khoj-openai-api-key)))))
|
||||||
new-processor-type)
|
new-processor-type)
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ def test_text_index_same_if_content_unchanged(content_config: ContentConfig, sea
|
|||||||
|
|
||||||
# ----------------------------------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------------------------------
|
||||||
@pytest.mark.anyio
|
@pytest.mark.anyio
|
||||||
async def test_asymmetric_search(content_config: ContentConfig, search_config: SearchConfig):
|
async def test_text_search(content_config: ContentConfig, search_config: SearchConfig):
|
||||||
# Arrange
|
# Arrange
|
||||||
search_models.text_search = text_search.initialize_model(search_config.asymmetric)
|
search_models.text_search = text_search.initialize_model(search_config.asymmetric)
|
||||||
content_index.org = text_search.setup(
|
content_index.org = text_search.setup(
|
||||||
@@ -93,7 +93,7 @@ async def test_asymmetric_search(content_config: ContentConfig, search_config: S
|
|||||||
results = text_search.collate_results(hits, entries, count=1)
|
results = text_search.collate_results(hits, entries, count=1)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
# Actual_data should contain "Khoj via Emacs" entry
|
# search results should contain "git clone" entry
|
||||||
search_result = results[0].entry
|
search_result = results[0].entry
|
||||||
assert "git clone" in search_result
|
assert "git clone" in search_result
|
||||||
|
|
||||||
@@ -262,7 +262,7 @@ def test_update_index_with_new_entry(content_config: ContentConfig, search_model
|
|||||||
|
|
||||||
# ----------------------------------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------------------------------
|
||||||
@pytest.mark.skipif(os.getenv("GITHUB_PAT_TOKEN") is None, reason="GITHUB_PAT_TOKEN not set")
|
@pytest.mark.skipif(os.getenv("GITHUB_PAT_TOKEN") is None, reason="GITHUB_PAT_TOKEN not set")
|
||||||
def test_asymmetric_setup_github(content_config: ContentConfig, search_models: SearchModels):
|
def test_text_search_setup_github(content_config: ContentConfig, search_models: SearchModels):
|
||||||
# Act
|
# Act
|
||||||
# Regenerate github embeddings to test asymmetric setup without caching
|
# Regenerate github embeddings to test asymmetric setup without caching
|
||||||
github_model = text_search.setup(
|
github_model = text_search.setup(
|
||||||
|
|||||||
Reference in New Issue
Block a user