khoj 2.0.0b12.dev5__py3-none-any.whl → 2.0.0b13.dev19__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- khoj/app/README.md +1 -1
- khoj/app/urls.py +1 -0
- khoj/configure.py +21 -54
- khoj/database/adapters/__init__.py +6 -15
- khoj/database/management/commands/delete_orphaned_fileobjects.py +0 -1
- khoj/database/migrations/0064_remove_conversation_temp_id_alter_conversation_id.py +1 -1
- khoj/database/migrations/0075_migrate_generated_assets_and_validate.py +1 -1
- khoj/database/migrations/0092_alter_chatmodel_model_type_alter_chatmodel_name_and_more.py +36 -0
- khoj/database/migrations/0093_remove_localorgconfig_user_and_more.py +36 -0
- khoj/database/models/__init__.py +10 -40
- khoj/database/tests.py +0 -2
- khoj/interface/compiled/404/index.html +2 -2
- khoj/interface/compiled/_next/static/chunks/{9245.a04e92d034540234.js → 1225.ecac11e7421504c4.js} +3 -3
- khoj/interface/compiled/_next/static/chunks/1320.ae930ad00affe685.js +5 -0
- khoj/interface/compiled/_next/static/chunks/{1327-1a9107b9a2a04a98.js → 1327-511bb0a862efce80.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/1626.15a8acc0d6639ec6.js +1 -0
- khoj/interface/compiled/_next/static/chunks/{3489.c523fe96a2eee74f.js → 1940.d082758bd04e08ae.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/{2327-ea623ca2d22f78e9.js → 2327-fe87dd989d71d0eb.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/2475.57a0d0fd93d07af0.js +93 -0
- khoj/interface/compiled/_next/static/chunks/2481.5ce6524ba0a73f90.js +55 -0
- khoj/interface/compiled/_next/static/chunks/297.4c4c823ff6e3255b.js +174 -0
- khoj/interface/compiled/_next/static/chunks/{5639-09e2009a2adedf8b.js → 3260-43d3019b92c315bb.js} +68 -23
- khoj/interface/compiled/_next/static/chunks/3353.1c6d553216a1acae.js +1 -0
- khoj/interface/compiled/_next/static/chunks/3855.f7b8131f78af046e.js +1 -0
- khoj/interface/compiled/_next/static/chunks/3973.dc54a39586ab48be.js +1 -0
- khoj/interface/compiled/_next/static/chunks/4241.c1cd170f7f37ac59.js +24 -0
- khoj/interface/compiled/_next/static/chunks/{4327.8d2a1b8f1ea78208.js → 4327.f3704dc398c67113.js} +19 -19
- khoj/interface/compiled/_next/static/chunks/4505.f09454a346269c3f.js +117 -0
- khoj/interface/compiled/_next/static/chunks/4801.96a152d49742b644.js +1 -0
- khoj/interface/compiled/_next/static/chunks/5427-a95ec748e52abb75.js +1 -0
- khoj/interface/compiled/_next/static/chunks/549.2bd27f59a91a9668.js +148 -0
- khoj/interface/compiled/_next/static/chunks/5765.71b1e1207b76b03f.js +1 -0
- khoj/interface/compiled/_next/static/chunks/584.d7ce3505f169b706.js +1 -0
- khoj/interface/compiled/_next/static/chunks/6240.34f7c1fa692edd61.js +24 -0
- khoj/interface/compiled/_next/static/chunks/6d3fe5a5-f9f3c16e0bc0cdf9.js +10 -0
- khoj/interface/compiled/_next/static/chunks/{7127-0f4a2a77d97fb5fa.js → 7127-97b83757db125ba6.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/7200-93ab0072359b8028.js +1 -0
- khoj/interface/compiled/_next/static/chunks/{2612.bcf5a623b3da209e.js → 7553.f5ad54b1f6e92c49.js} +2 -2
- khoj/interface/compiled/_next/static/chunks/7626-1b630f1654172341.js +1 -0
- khoj/interface/compiled/_next/static/chunks/764.dadd316e8e16d191.js +63 -0
- khoj/interface/compiled/_next/static/chunks/78.08169ab541abab4f.js +43 -0
- khoj/interface/compiled/_next/static/chunks/784.e03acf460df213d1.js +1 -0
- khoj/interface/compiled/_next/static/chunks/{9537-d9ab442ce15d1e20.js → 8072-e1440cb482a0940e.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/{3265.924139c4146ee344.js → 8086.8d39887215807fcd.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/8168.f074ab8c7c16d82d.js +59 -0
- khoj/interface/compiled/_next/static/chunks/{8694.2bd9c2f65d8c5847.js → 8223.1705878fa7a09292.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/8483.94f6c9e2bee86f50.js +215 -0
- khoj/interface/compiled/_next/static/chunks/{8888.ebe0e552b59e7fed.js → 8810.fc0e479de78c7c61.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/8828.bc74dc4ce94e78f6.js +1 -0
- khoj/interface/compiled/_next/static/chunks/{7303.d0612f812a967a08.js → 8909.14ac3f43d0070cf1.js} +5 -5
- khoj/interface/compiled/_next/static/chunks/90542734.b1a1629065ba199b.js +1 -0
- khoj/interface/compiled/_next/static/chunks/9167.098534184f03fe92.js +56 -0
- khoj/interface/compiled/_next/static/chunks/{4980.63500d68b3bb1222.js → 9537.e934ce37bf314509.js} +5 -5
- khoj/interface/compiled/_next/static/chunks/9574.3fe8e26e95bf1c34.js +1 -0
- khoj/interface/compiled/_next/static/chunks/9599.ec50b5296c27dae9.js +1 -0
- khoj/interface/compiled/_next/static/chunks/9643.b34248df52ffc77c.js +262 -0
- khoj/interface/compiled/_next/static/chunks/9747.2fd9065b1435abb1.js +1 -0
- khoj/interface/compiled/_next/static/chunks/9922.98f2b2a9959b4ebe.js +1 -0
- khoj/interface/compiled/_next/static/chunks/app/agents/layout-4e2a134ec26aa606.js +1 -0
- khoj/interface/compiled/_next/static/chunks/app/agents/page-e291b49977f43880.js +1 -0
- khoj/interface/compiled/_next/static/chunks/app/automations/page-198b26df6e09bbb0.js +1 -0
- khoj/interface/compiled/_next/static/chunks/app/chat/layout-ad4d1792ab1a4108.js +1 -0
- khoj/interface/compiled/_next/static/chunks/app/chat/{page-8e1c4f2af3c9429e.js → page-9a75d7369f2a7cd2.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/app/{page-2b3056cba8aa96ce.js → page-1567cac7b79a7c59.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/app/settings/{page-8be3b35178abf2ec.js → page-6081362437c82470.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/app/share/chat/{page-4a4b0c0f4749c2b2.js → page-e0dcb1762f8c8f88.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/webpack-d60b0c57a6c38d0f.js +1 -0
- khoj/interface/compiled/_next/static/css/{c34713c98384ee87.css → 2945c4a857922f3b.css} +1 -1
- khoj/interface/compiled/agents/index.html +2 -2
- khoj/interface/compiled/agents/index.txt +3 -3
- khoj/interface/compiled/automations/index.html +2 -2
- khoj/interface/compiled/automations/index.txt +4 -4
- khoj/interface/compiled/chat/index.html +2 -2
- khoj/interface/compiled/chat/index.txt +3 -3
- khoj/interface/compiled/index.html +2 -2
- khoj/interface/compiled/index.txt +3 -3
- khoj/interface/compiled/search/index.html +2 -2
- khoj/interface/compiled/search/index.txt +3 -3
- khoj/interface/compiled/settings/index.html +2 -2
- khoj/interface/compiled/settings/index.txt +5 -5
- khoj/interface/compiled/share/chat/index.html +2 -2
- khoj/interface/compiled/share/chat/index.txt +3 -3
- khoj/main.py +7 -9
- khoj/manage.py +1 -0
- khoj/processor/content/github/github_to_entries.py +6 -7
- khoj/processor/content/images/image_to_entries.py +0 -1
- khoj/processor/content/markdown/markdown_to_entries.py +2 -3
- khoj/processor/content/notion/notion_to_entries.py +5 -6
- khoj/processor/content/org_mode/org_to_entries.py +4 -5
- khoj/processor/content/org_mode/orgnode.py +4 -4
- khoj/processor/content/plaintext/plaintext_to_entries.py +1 -2
- khoj/processor/content/text_to_entries.py +1 -3
- khoj/processor/conversation/google/utils.py +3 -3
- khoj/processor/conversation/openai/utils.py +3 -4
- khoj/processor/conversation/prompts.py +0 -32
- khoj/processor/conversation/utils.py +25 -38
- khoj/processor/embeddings.py +0 -2
- khoj/processor/image/generate.py +3 -3
- khoj/processor/operator/__init__.py +2 -3
- khoj/processor/operator/grounding_agent.py +15 -2
- khoj/processor/operator/grounding_agent_uitars.py +34 -23
- khoj/processor/operator/operator_agent_anthropic.py +29 -4
- khoj/processor/operator/operator_agent_base.py +1 -1
- khoj/processor/operator/operator_agent_binary.py +4 -4
- khoj/processor/operator/operator_agent_openai.py +21 -6
- khoj/processor/operator/operator_environment_browser.py +1 -1
- khoj/processor/operator/operator_environment_computer.py +1 -1
- khoj/processor/speech/text_to_speech.py +0 -1
- khoj/processor/tools/online_search.py +1 -1
- khoj/processor/tools/run_code.py +1 -1
- khoj/routers/api.py +2 -15
- khoj/routers/api_agents.py +1 -2
- khoj/routers/api_automation.py +1 -1
- khoj/routers/api_chat.py +10 -16
- khoj/routers/api_content.py +3 -111
- khoj/routers/api_model.py +0 -1
- khoj/routers/api_subscription.py +1 -1
- khoj/routers/email.py +4 -4
- khoj/routers/helpers.py +26 -99
- khoj/routers/research.py +2 -4
- khoj/search_filter/base_filter.py +2 -4
- khoj/search_type/text_search.py +1 -2
- khoj/utils/cli.py +5 -53
- khoj/utils/config.py +0 -65
- khoj/utils/constants.py +0 -7
- khoj/utils/helpers.py +5 -13
- khoj/utils/initialization.py +7 -48
- khoj/utils/models.py +2 -4
- khoj/utils/rawconfig.py +1 -69
- khoj/utils/state.py +2 -8
- khoj/utils/yaml.py +0 -39
- {khoj-2.0.0b12.dev5.dist-info → khoj-2.0.0b13.dev19.dist-info}/METADATA +3 -3
- {khoj-2.0.0b12.dev5.dist-info → khoj-2.0.0b13.dev19.dist-info}/RECORD +145 -154
- khoj/interface/compiled/_next/static/chunks/1191.b547ec13349b4aed.js +0 -1
- khoj/interface/compiled/_next/static/chunks/1588.f0558a0bdffc4761.js +0 -117
- khoj/interface/compiled/_next/static/chunks/1918.925cb4a35518d258.js +0 -43
- khoj/interface/compiled/_next/static/chunks/2849.dc00ae5ba7219cfc.js +0 -1
- khoj/interface/compiled/_next/static/chunks/303.fe76de943e930fbd.js +0 -1
- khoj/interface/compiled/_next/static/chunks/4533.586e74b45a2bde25.js +0 -55
- khoj/interface/compiled/_next/static/chunks/4551.82ce1476b5516bc2.js +0 -5
- khoj/interface/compiled/_next/static/chunks/4748.0edd37cba3ea2809.js +0 -59
- khoj/interface/compiled/_next/static/chunks/5210.cd35a1c1ec594a20.js +0 -93
- khoj/interface/compiled/_next/static/chunks/5329.f8b3c5b3d16159cd.js +0 -1
- khoj/interface/compiled/_next/static/chunks/5427-13d6ffd380fdfab7.js +0 -1
- khoj/interface/compiled/_next/static/chunks/558-c14e76cff03f6a60.js +0 -1
- khoj/interface/compiled/_next/static/chunks/5830.8876eccb82da9b7d.js +0 -262
- khoj/interface/compiled/_next/static/chunks/6230.88a71d8145347b3f.js +0 -1
- khoj/interface/compiled/_next/static/chunks/7161.77e0530a40ad5ca8.js +0 -1
- khoj/interface/compiled/_next/static/chunks/7200-ac3b2e37ff30e126.js +0 -1
- khoj/interface/compiled/_next/static/chunks/7505.c31027a3695bdebb.js +0 -148
- khoj/interface/compiled/_next/static/chunks/7760.35649cc21d9585bd.js +0 -56
- khoj/interface/compiled/_next/static/chunks/83.48e2db193a940052.js +0 -1
- khoj/interface/compiled/_next/static/chunks/8427.844694e06133fb51.js +0 -1
- khoj/interface/compiled/_next/static/chunks/8665.4db7e6b2e8933497.js +0 -174
- khoj/interface/compiled/_next/static/chunks/872.caf84cc1a39ae59f.js +0 -1
- khoj/interface/compiled/_next/static/chunks/8890.6e8a59e4de6978bc.js +0 -215
- khoj/interface/compiled/_next/static/chunks/8950.5f2272e0ac923f9e.js +0 -1
- khoj/interface/compiled/_next/static/chunks/90542734.2c21f16f18b22411.js +0 -1
- khoj/interface/compiled/_next/static/chunks/9202.c703864fcedc8d1f.js +0 -63
- khoj/interface/compiled/_next/static/chunks/9320.6aca4885d541aa44.js +0 -24
- khoj/interface/compiled/_next/static/chunks/9535.f78cd92d03331e55.js +0 -1
- khoj/interface/compiled/_next/static/chunks/9968.b111fc002796da81.js +0 -1
- khoj/interface/compiled/_next/static/chunks/app/agents/layout-e00fb81dca656a10.js +0 -1
- khoj/interface/compiled/_next/static/chunks/app/agents/page-9a4610474cd59a71.js +0 -1
- khoj/interface/compiled/_next/static/chunks/app/automations/page-f7bb9d777b7745d4.js +0 -1
- khoj/interface/compiled/_next/static/chunks/app/chat/layout-33934fc2d6ae6838.js +0 -1
- khoj/interface/compiled/_next/static/chunks/f3e3247b-1758d4651e4457c2.js +0 -10
- khoj/interface/compiled/_next/static/chunks/webpack-338a5000c912cc94.js +0 -1
- khoj/migrations/__init__.py +0 -0
- khoj/migrations/migrate_offline_chat_default_model.py +0 -69
- khoj/migrations/migrate_offline_chat_default_model_2.py +0 -71
- khoj/migrations/migrate_offline_chat_schema.py +0 -83
- khoj/migrations/migrate_offline_model.py +0 -29
- khoj/migrations/migrate_processor_config_openai.py +0 -67
- khoj/migrations/migrate_server_pg.py +0 -132
- khoj/migrations/migrate_version.py +0 -17
- khoj/processor/conversation/offline/__init__.py +0 -0
- khoj/processor/conversation/offline/chat_model.py +0 -224
- khoj/processor/conversation/offline/utils.py +0 -80
- khoj/processor/conversation/offline/whisper.py +0 -15
- khoj/utils/fs_syncer.py +0 -252
- /khoj/interface/compiled/_next/static/{7GoMcE8WpP9fbfYZXv4Nv → N-GdBSXoYe-DuObnbXVRO}/_buildManifest.js +0 -0
- /khoj/interface/compiled/_next/static/{7GoMcE8WpP9fbfYZXv4Nv → N-GdBSXoYe-DuObnbXVRO}/_ssgManifest.js +0 -0
- /khoj/interface/compiled/_next/static/chunks/{1915-5c6508f6ebb62a30.js → 1915-fbfe167c84ad60c5.js} +0 -0
- /khoj/interface/compiled/_next/static/chunks/{2117-080746c8e170c81a.js → 2117-e78b6902ad6f75ec.js} +0 -0
- /khoj/interface/compiled/_next/static/chunks/{2939-4af3fd24b8ffc9ad.js → 2939-4d4084c5b888b960.js} +0 -0
- /khoj/interface/compiled/_next/static/chunks/{4447-cd95608f8e93e711.js → 4447-d6cf93724d57e34b.js} +0 -0
- /khoj/interface/compiled/_next/static/chunks/{8667-50b03a89e82e0ba7.js → 8667-4b7790573b08c50d.js} +0 -0
- /khoj/interface/compiled/_next/static/chunks/{9139-8ac4d9feb10f8869.js → 9139-ce1ae935dac9c871.js} +0 -0
- /khoj/interface/compiled/_next/static/chunks/app/search/{page-4885df3cd175c957.js → page-3639e50ec3e9acfd.js} +0 -0
- {khoj-2.0.0b12.dev5.dist-info → khoj-2.0.0b13.dev19.dist-info}/WHEEL +0 -0
- {khoj-2.0.0b12.dev5.dist-info → khoj-2.0.0b13.dev19.dist-info}/entry_points.txt +0 -0
- {khoj-2.0.0b12.dev5.dist-info → khoj-2.0.0b13.dev19.dist-info}/licenses/LICENSE +0 -0
@@ -11,7 +11,32 @@ from anthropic.types.beta import BetaContentBlock, BetaTextBlock, BetaToolUseBlo
|
|
11
11
|
from khoj.database.models import ChatModel
|
12
12
|
from khoj.processor.conversation.anthropic.utils import is_reasoning_model
|
13
13
|
from khoj.processor.conversation.utils import AgentMessage
|
14
|
-
from khoj.processor.operator.operator_actions import
|
14
|
+
from khoj.processor.operator.operator_actions import (
|
15
|
+
BackAction,
|
16
|
+
ClickAction,
|
17
|
+
CursorPositionAction,
|
18
|
+
DoubleClickAction,
|
19
|
+
DragAction,
|
20
|
+
GotoAction,
|
21
|
+
HoldKeyAction,
|
22
|
+
KeypressAction,
|
23
|
+
MouseDownAction,
|
24
|
+
MouseUpAction,
|
25
|
+
MoveAction,
|
26
|
+
NoopAction,
|
27
|
+
OperatorAction,
|
28
|
+
Point,
|
29
|
+
ScreenshotAction,
|
30
|
+
ScrollAction,
|
31
|
+
TerminalAction,
|
32
|
+
TextEditorCreateAction,
|
33
|
+
TextEditorInsertAction,
|
34
|
+
TextEditorStrReplaceAction,
|
35
|
+
TextEditorViewAction,
|
36
|
+
TripleClickAction,
|
37
|
+
TypeAction,
|
38
|
+
WaitAction,
|
39
|
+
)
|
15
40
|
from khoj.processor.operator.operator_agent_base import AgentActResult, OperatorAgent
|
16
41
|
from khoj.processor.operator.operator_environment_base import (
|
17
42
|
EnvironmentType,
|
@@ -518,7 +543,7 @@ class AnthropicOperatorAgent(OperatorAgent):
|
|
518
543
|
def model_default_headers(self) -> list[str]:
|
519
544
|
"""Get the default computer use headers for the given model."""
|
520
545
|
if self.vision_model.name.startswith("claude-3-7-sonnet"):
|
521
|
-
return [
|
546
|
+
return ["computer-use-2025-01-24", "token-efficient-tools-2025-02-19"]
|
522
547
|
elif self.vision_model.name.startswith("claude-sonnet-4") or self.vision_model.name.startswith("claude-opus-4"):
|
523
548
|
return ["computer-use-2025-01-24"]
|
524
549
|
else:
|
@@ -538,7 +563,7 @@ class AnthropicOperatorAgent(OperatorAgent):
|
|
538
563
|
* When viewing a webpage it can be helpful to zoom out so that you can see everything on the page. Either that, or make sure you scroll down to see everything before deciding something isn't available.
|
539
564
|
* When using your computer function calls, they take a while to run and send back to you. Where possible/feasible, try to chain multiple of these calls all into one function calls request.
|
540
565
|
* Perform web searches using DuckDuckGo. Don't use Google even if requested as the query will fail.
|
541
|
-
* The current date is {datetime.today().strftime(
|
566
|
+
* The current date is {datetime.today().strftime("%A, %B %-d, %Y")}.
|
542
567
|
* The current URL is {current_state.url}.
|
543
568
|
</SYSTEM_CAPABILITY>
|
544
569
|
|
@@ -563,7 +588,7 @@ class AnthropicOperatorAgent(OperatorAgent):
|
|
563
588
|
</SYSTEM_CAPABILITY>
|
564
589
|
|
565
590
|
<CONTEXT>
|
566
|
-
* The current date is {datetime.today().strftime(
|
591
|
+
* The current date is {datetime.today().strftime("%A, %B %-d, %Y")}.
|
567
592
|
</CONTEXT>
|
568
593
|
"""
|
569
594
|
).lstrip()
|
@@ -12,7 +12,7 @@ from khoj.processor.conversation.utils import (
|
|
12
12
|
)
|
13
13
|
from khoj.processor.operator.grounding_agent import GroundingAgent
|
14
14
|
from khoj.processor.operator.grounding_agent_uitars import GroundingAgentUitars
|
15
|
-
from khoj.processor.operator.operator_actions import
|
15
|
+
from khoj.processor.operator.operator_actions import OperatorAction, WaitAction
|
16
16
|
from khoj.processor.operator.operator_agent_base import AgentActResult, OperatorAgent
|
17
17
|
from khoj.processor.operator.operator_environment_base import (
|
18
18
|
EnvironmentType,
|
@@ -181,7 +181,7 @@ class BinaryOperatorAgent(OperatorAgent):
|
|
181
181
|
elif action.type == "key_down":
|
182
182
|
rendered_parts += [f'**Action**: Press Key "{action.key}"']
|
183
183
|
elif action.type == "screenshot" and not current_state.screenshot:
|
184
|
-
rendered_parts += [
|
184
|
+
rendered_parts += ["**Error**: Failed to take screenshot"]
|
185
185
|
elif action.type == "goto":
|
186
186
|
rendered_parts += [f"**Action**: Open URL {action.url}"]
|
187
187
|
else:
|
@@ -317,7 +317,7 @@ class BinaryOperatorAgent(OperatorAgent):
|
|
317
317
|
# Introduction
|
318
318
|
* You are Khoj, a smart and resourceful web browsing assistant. You help the user accomplish their task using a web browser.
|
319
319
|
* You are given the user's query and screenshots of the browser's state transitions.
|
320
|
-
* The current date is {datetime.today().strftime(
|
320
|
+
* The current date is {datetime.today().strftime("%A, %B %-d, %Y")}.
|
321
321
|
* The current URL is {env_state.url}.
|
322
322
|
|
323
323
|
# Your Task
|
@@ -362,7 +362,7 @@ class BinaryOperatorAgent(OperatorAgent):
|
|
362
362
|
# Introduction
|
363
363
|
* You are Khoj, a smart and resourceful computer assistant. You help the user accomplish their task using a computer.
|
364
364
|
* You are given the user's query and screenshots of the computer's state transitions.
|
365
|
-
* The current date is {datetime.today().strftime(
|
365
|
+
* The current date is {datetime.today().strftime("%A, %B %-d, %Y")}.
|
366
366
|
|
367
367
|
# Your Task
|
368
368
|
* First look at the screenshots carefully to notice all pertinent information.
|
@@ -1,6 +1,5 @@
|
|
1
1
|
import json
|
2
2
|
import logging
|
3
|
-
import platform
|
4
3
|
from copy import deepcopy
|
5
4
|
from datetime import datetime
|
6
5
|
from textwrap import dedent
|
@@ -10,7 +9,23 @@ from openai.types.responses import Response, ResponseOutputItem
|
|
10
9
|
|
11
10
|
from khoj.database.models import ChatModel
|
12
11
|
from khoj.processor.conversation.utils import AgentMessage
|
13
|
-
from khoj.processor.operator.operator_actions import
|
12
|
+
from khoj.processor.operator.operator_actions import (
|
13
|
+
BackAction,
|
14
|
+
ClickAction,
|
15
|
+
DoubleClickAction,
|
16
|
+
DragAction,
|
17
|
+
GotoAction,
|
18
|
+
KeypressAction,
|
19
|
+
MoveAction,
|
20
|
+
NoopAction,
|
21
|
+
OperatorAction,
|
22
|
+
Point,
|
23
|
+
RequestUserAction,
|
24
|
+
ScreenshotAction,
|
25
|
+
ScrollAction,
|
26
|
+
TypeAction,
|
27
|
+
WaitAction,
|
28
|
+
)
|
14
29
|
from khoj.processor.operator.operator_agent_base import AgentActResult, OperatorAgent
|
15
30
|
from khoj.processor.operator.operator_environment_base import (
|
16
31
|
EnvironmentType,
|
@@ -152,7 +167,7 @@ class OpenAIOperatorAgent(OperatorAgent):
|
|
152
167
|
# Add screenshot data in openai message format
|
153
168
|
action_result["output"] = {
|
154
169
|
"type": "input_image",
|
155
|
-
"image_url": f
|
170
|
+
"image_url": f"data:image/webp;base64,{result_content['image']}",
|
156
171
|
"current_url": result_content["url"],
|
157
172
|
}
|
158
173
|
elif action_result["type"] == "computer_call_output" and idx == len(env_steps) - 1:
|
@@ -311,7 +326,7 @@ class OpenAIOperatorAgent(OperatorAgent):
|
|
311
326
|
elif block.type == "function_call":
|
312
327
|
if block.name == "goto":
|
313
328
|
args = json.loads(block.arguments)
|
314
|
-
render_texts = [f
|
329
|
+
render_texts = [f"Open URL: {args.get('url', '[Missing URL]')}"]
|
315
330
|
else:
|
316
331
|
render_texts += [block.name]
|
317
332
|
elif block.type == "computer_call":
|
@@ -351,7 +366,7 @@ class OpenAIOperatorAgent(OperatorAgent):
|
|
351
366
|
* When viewing a webpage it can be helpful to zoom out so that you can see everything on the page. Either that, or make sure you scroll down to see everything before deciding something isn't available.
|
352
367
|
* When using your computer function calls, they take a while to run and send back to you. Where possible/feasible, try to chain multiple of these calls all into one function calls request.
|
353
368
|
* Perform web searches using DuckDuckGo. Don't use Google even if requested as the query will fail.
|
354
|
-
* The current date is {datetime.today().strftime(
|
369
|
+
* The current date is {datetime.today().strftime("%A, %B %-d, %Y")}.
|
355
370
|
* The current URL is {current_state.url}.
|
356
371
|
</SYSTEM_CAPABILITY>
|
357
372
|
|
@@ -374,7 +389,7 @@ class OpenAIOperatorAgent(OperatorAgent):
|
|
374
389
|
</SYSTEM_CAPABILITY>
|
375
390
|
|
376
391
|
<CONTEXT>
|
377
|
-
* The current date is {datetime.today().strftime(
|
392
|
+
* The current date is {datetime.today().strftime("%A, %B %-d, %Y")}.
|
378
393
|
</CONTEXT>
|
379
394
|
"""
|
380
395
|
).lstrip()
|
@@ -247,7 +247,7 @@ class BrowserEnvironment(Environment):
|
|
247
247
|
|
248
248
|
case "drag":
|
249
249
|
if not isinstance(action, DragAction):
|
250
|
-
raise TypeError(
|
250
|
+
raise TypeError("Invalid action type for drag")
|
251
251
|
path = action.path
|
252
252
|
if not path:
|
253
253
|
error = "Missing path for drag action"
|
@@ -532,7 +532,7 @@ class ComputerEnvironment(Environment):
|
|
532
532
|
else:
|
533
533
|
return {"success": False, "output": process.stdout, "error": process.stderr}
|
534
534
|
except asyncio.TimeoutError:
|
535
|
-
return {"success": False, "output": "", "error":
|
535
|
+
return {"success": False, "output": "", "error": "Command timed out after 120 seconds."}
|
536
536
|
except Exception as e:
|
537
537
|
return {"success": False, "output": "", "error": str(e)}
|
538
538
|
|
@@ -385,7 +385,7 @@ async def read_webpages(
|
|
385
385
|
tracer: dict = {},
|
386
386
|
):
|
387
387
|
"Infer web pages to read from the query and extract relevant information from them"
|
388
|
-
logger.info(
|
388
|
+
logger.info("Inferring web pages to read")
|
389
389
|
urls = await infer_webpage_urls(
|
390
390
|
query,
|
391
391
|
max_webpages_to_read,
|
khoj/processor/tools/run_code.py
CHANGED
@@ -93,7 +93,7 @@ async def run_code(
|
|
93
93
|
|
94
94
|
# Run Code
|
95
95
|
if send_status_func:
|
96
|
-
async for event in send_status_func(
|
96
|
+
async for event in send_status_func("**Running code snippet**"):
|
97
97
|
yield {ChatEvent.STATUS: event}
|
98
98
|
try:
|
99
99
|
with timer("Chat actor: Execute generated program", logger, log_level=logging.INFO):
|
khoj/routers/api.py
CHANGED
@@ -7,7 +7,6 @@ from typing import List, Optional, Union
|
|
7
7
|
|
8
8
|
import openai
|
9
9
|
from fastapi import APIRouter, Depends, File, HTTPException, Request, UploadFile
|
10
|
-
from fastapi.requests import Request
|
11
10
|
from fastapi.responses import Response
|
12
11
|
from starlette.authentication import has_required_scope, requires
|
13
12
|
|
@@ -15,7 +14,6 @@ from khoj.configure import initialize_content
|
|
15
14
|
from khoj.database import adapters
|
16
15
|
from khoj.database.adapters import ConversationAdapters, EntryAdapters, get_user_photo
|
17
16
|
from khoj.database.models import KhojUser, SpeechToTextModelOptions
|
18
|
-
from khoj.processor.conversation.offline.whisper import transcribe_audio_offline
|
19
17
|
from khoj.processor.conversation.openai.whisper import transcribe_audio
|
20
18
|
from khoj.routers.helpers import (
|
21
19
|
ApiUserRateLimiter,
|
@@ -88,22 +86,14 @@ def update(
|
|
88
86
|
force: Optional[bool] = False,
|
89
87
|
):
|
90
88
|
user = request.user.object
|
91
|
-
if not state.config:
|
92
|
-
error_msg = f"🚨 Khoj is not configured.\nConfigure it via http://localhost:42110/settings, plugins or by editing {state.config_file}."
|
93
|
-
logger.warning(error_msg)
|
94
|
-
raise HTTPException(status_code=500, detail=error_msg)
|
95
89
|
try:
|
96
90
|
initialize_content(user=user, regenerate=force, search_type=t)
|
97
91
|
except Exception as e:
|
98
|
-
error_msg = f"🚨 Failed to update server via API: {e}"
|
92
|
+
error_msg = f"🚨 Failed to update server indexed content via API: {e}"
|
99
93
|
logger.error(error_msg, exc_info=True)
|
100
94
|
raise HTTPException(status_code=500, detail=error_msg)
|
101
95
|
else:
|
102
|
-
|
103
|
-
if state.search_models:
|
104
|
-
components.append("Search models")
|
105
|
-
components_msg = ", ".join(components)
|
106
|
-
logger.info(f"📪 {components_msg} updated via API")
|
96
|
+
logger.info("📪 Server indexed content updated via API")
|
107
97
|
|
108
98
|
update_telemetry_state(
|
109
99
|
request=request,
|
@@ -150,9 +140,6 @@ async def transcribe(
|
|
150
140
|
if not speech_to_text_config:
|
151
141
|
# If the user has not configured a speech to text model, return an unsupported on server error
|
152
142
|
status_code = 501
|
153
|
-
elif speech_to_text_config.model_type == SpeechToTextModelOptions.ModelType.OFFLINE:
|
154
|
-
speech2text_model = speech_to_text_config.model_name
|
155
|
-
user_message = await transcribe_audio_offline(audio_filename, speech2text_model)
|
156
143
|
elif speech_to_text_config.model_type == SpeechToTextModelOptions.ModelType.OPENAI:
|
157
144
|
speech2text_model = speech_to_text_config.model_name
|
158
145
|
if speech_to_text_config.ai_model_api:
|
khoj/routers/api_agents.py
CHANGED
@@ -6,12 +6,11 @@ from typing import Dict, List, Optional
|
|
6
6
|
|
7
7
|
from asgiref.sync import sync_to_async
|
8
8
|
from fastapi import APIRouter, Request
|
9
|
-
from fastapi.requests import Request
|
10
9
|
from fastapi.responses import Response
|
11
10
|
from pydantic import BaseModel
|
12
11
|
from starlette.authentication import has_required_scope, requires
|
13
12
|
|
14
|
-
from khoj.database.adapters import AgentAdapters, ConversationAdapters
|
13
|
+
from khoj.database.adapters import AgentAdapters, ConversationAdapters
|
15
14
|
from khoj.database.models import Agent, Conversation, KhojUser, PriceTier
|
16
15
|
from khoj.routers.helpers import CommonQueryParams, acheck_if_safe_prompt
|
17
16
|
from khoj.utils.helpers import (
|
khoj/routers/api_automation.py
CHANGED
@@ -109,7 +109,7 @@ def post_automation(
|
|
109
109
|
except Exception as e:
|
110
110
|
logger.error(f"Error creating automation {q} for {user.email}: {e}", exc_info=True)
|
111
111
|
return Response(
|
112
|
-
content=
|
112
|
+
content="Unable to create automation. Ensure the automation doesn't already exist.",
|
113
113
|
media_type="text/plain",
|
114
114
|
status_code=500,
|
115
115
|
)
|
khoj/routers/api_chat.py
CHANGED
@@ -10,7 +10,6 @@ from functools import partial
|
|
10
10
|
from typing import Any, Dict, List, Optional
|
11
11
|
from urllib.parse import unquote
|
12
12
|
|
13
|
-
from asgiref.sync import sync_to_async
|
14
13
|
from fastapi import (
|
15
14
|
APIRouter,
|
16
15
|
Depends,
|
@@ -32,10 +31,10 @@ from khoj.database.adapters import (
|
|
32
31
|
PublicConversationAdapters,
|
33
32
|
aget_user_name,
|
34
33
|
)
|
35
|
-
from khoj.database.models import Agent,
|
34
|
+
from khoj.database.models import Agent, KhojUser
|
36
35
|
from khoj.processor.conversation import prompts
|
37
36
|
from khoj.processor.conversation.openai.utils import is_local_api
|
38
|
-
from khoj.processor.conversation.prompts import
|
37
|
+
from khoj.processor.conversation.prompts import no_entries_found
|
39
38
|
from khoj.processor.conversation.utils import (
|
40
39
|
OperatorRun,
|
41
40
|
ResponseWithThought,
|
@@ -65,11 +64,8 @@ from khoj.routers.helpers import (
|
|
65
64
|
acreate_title_from_history,
|
66
65
|
agenerate_chat_response,
|
67
66
|
aget_data_sources_and_output_format,
|
68
|
-
construct_automation_created_message,
|
69
|
-
create_automation,
|
70
67
|
gather_raw_query_files,
|
71
68
|
generate_mermaidjs_diagram,
|
72
|
-
generate_summary_from_files,
|
73
69
|
get_conversation_command,
|
74
70
|
get_message_from_queue,
|
75
71
|
is_query_empty,
|
@@ -89,13 +85,11 @@ from khoj.utils.helpers import (
|
|
89
85
|
convert_image_to_webp,
|
90
86
|
get_country_code_from_timezone,
|
91
87
|
get_country_name_from_timezone,
|
92
|
-
get_device,
|
93
88
|
is_env_var_true,
|
94
89
|
is_none_or_empty,
|
95
90
|
is_operator_enabled,
|
96
91
|
)
|
97
92
|
from khoj.utils.rawconfig import (
|
98
|
-
ChatRequestBody,
|
99
93
|
FileAttachment,
|
100
94
|
FileFilterRequest,
|
101
95
|
FilesFilterRequest,
|
@@ -689,7 +683,6 @@ async def event_generator(
|
|
689
683
|
region = body.region
|
690
684
|
country = body.country or get_country_name_from_timezone(body.timezone)
|
691
685
|
country_code = body.country_code or get_country_code_from_timezone(body.timezone)
|
692
|
-
timezone = body.timezone
|
693
686
|
raw_images = body.images
|
694
687
|
raw_query_files = body.files
|
695
688
|
|
@@ -853,7 +846,8 @@ async def event_generator(
|
|
853
846
|
if (
|
854
847
|
len(train_of_thought) > 0
|
855
848
|
and train_of_thought[-1]["type"] == ChatEvent.THOUGHT.value
|
856
|
-
and
|
849
|
+
and isinstance(train_of_thought[-1]["data"], str)
|
850
|
+
and isinstance(data, str)
|
857
851
|
):
|
858
852
|
train_of_thought[-1]["data"] += data
|
859
853
|
else:
|
@@ -1075,11 +1069,11 @@ async def event_generator(
|
|
1075
1069
|
|
1076
1070
|
# researched_results = await extract_relevant_info(q, researched_results, agent)
|
1077
1071
|
if state.verbose > 1:
|
1078
|
-
logger.debug(f
|
1072
|
+
logger.debug(f"Researched Results: {''.join(r.summarizedResult or '' for r in research_results)}")
|
1079
1073
|
|
1080
1074
|
# Gather Context
|
1081
1075
|
## Extract Document References
|
1082
|
-
if
|
1076
|
+
if ConversationCommand.Research not in conversation_commands:
|
1083
1077
|
try:
|
1084
1078
|
async for result in search_documents(
|
1085
1079
|
q,
|
@@ -1218,7 +1212,7 @@ async def event_generator(
|
|
1218
1212
|
else:
|
1219
1213
|
code_results = result
|
1220
1214
|
except ValueError as e:
|
1221
|
-
program_execution_context.append(
|
1215
|
+
program_execution_context.append("Failed to run code")
|
1222
1216
|
logger.warning(
|
1223
1217
|
f"Failed to use code tool: {e}. Attempting to respond without code results",
|
1224
1218
|
exc_info=True,
|
@@ -1297,7 +1291,7 @@ async def event_generator(
|
|
1297
1291
|
inferred_queries.append(improved_image_prompt)
|
1298
1292
|
if generated_image is None or status_code != 200:
|
1299
1293
|
program_execution_context.append(f"Failed to generate image with {improved_image_prompt}")
|
1300
|
-
async for result in send_event(ChatEvent.STATUS,
|
1294
|
+
async for result in send_event(ChatEvent.STATUS, "Failed to generate image"):
|
1301
1295
|
yield result
|
1302
1296
|
else:
|
1303
1297
|
generated_images.append(generated_image)
|
@@ -1315,7 +1309,7 @@ async def event_generator(
|
|
1315
1309
|
yield result
|
1316
1310
|
|
1317
1311
|
if ConversationCommand.Diagram in conversation_commands:
|
1318
|
-
async for result in send_event(ChatEvent.STATUS,
|
1312
|
+
async for result in send_event(ChatEvent.STATUS, "Creating diagram"):
|
1319
1313
|
yield result
|
1320
1314
|
|
1321
1315
|
inferred_queries = []
|
@@ -1372,7 +1366,7 @@ async def event_generator(
|
|
1372
1366
|
return
|
1373
1367
|
|
1374
1368
|
## Generate Text Output
|
1375
|
-
async for result in send_event(ChatEvent.STATUS,
|
1369
|
+
async for result in send_event(ChatEvent.STATUS, "**Generating a well-informed response**"):
|
1376
1370
|
yield result
|
1377
1371
|
|
1378
1372
|
llm_response, chat_metadata = await agenerate_chat_response(
|
khoj/routers/api_content.py
CHANGED
@@ -27,16 +27,7 @@ from khoj.database.adapters import (
|
|
27
27
|
get_user_notion_config,
|
28
28
|
)
|
29
29
|
from khoj.database.models import Entry as DbEntry
|
30
|
-
from khoj.database.models import
|
31
|
-
GithubConfig,
|
32
|
-
GithubRepoConfig,
|
33
|
-
KhojUser,
|
34
|
-
LocalMarkdownConfig,
|
35
|
-
LocalOrgConfig,
|
36
|
-
LocalPdfConfig,
|
37
|
-
LocalPlaintextConfig,
|
38
|
-
NotionConfig,
|
39
|
-
)
|
30
|
+
from khoj.database.models import GithubConfig, GithubRepoConfig, NotionConfig
|
40
31
|
from khoj.processor.content.docx.docx_to_entries import DocxToEntries
|
41
32
|
from khoj.processor.content.pdf.pdf_to_entries import PdfToEntries
|
42
33
|
from khoj.routers.helpers import (
|
@@ -47,17 +38,9 @@ from khoj.routers.helpers import (
|
|
47
38
|
get_user_config,
|
48
39
|
update_telemetry_state,
|
49
40
|
)
|
50
|
-
from khoj.utils import
|
51
|
-
from khoj.utils.
|
52
|
-
from khoj.utils.rawconfig import (
|
53
|
-
ContentConfig,
|
54
|
-
FullConfig,
|
55
|
-
GithubContentConfig,
|
56
|
-
NotionContentConfig,
|
57
|
-
SearchConfig,
|
58
|
-
)
|
41
|
+
from khoj.utils import state
|
42
|
+
from khoj.utils.rawconfig import GithubContentConfig, NotionContentConfig
|
59
43
|
from khoj.utils.state import SearchType
|
60
|
-
from khoj.utils.yaml import save_config_to_file_updated_state
|
61
44
|
|
62
45
|
logger = logging.getLogger(__name__)
|
63
46
|
|
@@ -192,8 +175,6 @@ async def set_content_github(
|
|
192
175
|
updated_config: Union[GithubContentConfig, None],
|
193
176
|
client: Optional[str] = None,
|
194
177
|
):
|
195
|
-
_initialize_config()
|
196
|
-
|
197
178
|
user = request.user.object
|
198
179
|
|
199
180
|
try:
|
@@ -225,8 +206,6 @@ async def set_content_notion(
|
|
225
206
|
updated_config: Union[NotionContentConfig, None],
|
226
207
|
client: Optional[str] = None,
|
227
208
|
):
|
228
|
-
_initialize_config()
|
229
|
-
|
230
209
|
user = request.user.object
|
231
210
|
|
232
211
|
try:
|
@@ -323,10 +302,6 @@ def get_content_types(request: Request, client: Optional[str] = None):
|
|
323
302
|
configured_content_types = set(EntryAdapters.get_unique_file_types(user))
|
324
303
|
configured_content_types |= {"all"}
|
325
304
|
|
326
|
-
if state.config and state.config.content_type:
|
327
|
-
for ctype in state.config.content_type.model_dump(exclude_none=True):
|
328
|
-
configured_content_types.add(ctype)
|
329
|
-
|
330
305
|
return list(configured_content_types & all_content_types)
|
331
306
|
|
332
307
|
|
@@ -606,28 +581,6 @@ async def indexer(
|
|
606
581
|
docx=index_files["docx"],
|
607
582
|
)
|
608
583
|
|
609
|
-
if state.config == None:
|
610
|
-
logger.info("📬 Initializing content index on first run.")
|
611
|
-
default_full_config = FullConfig(
|
612
|
-
content_type=None,
|
613
|
-
search_type=SearchConfig.model_validate(constants.default_config["search-type"]),
|
614
|
-
processor=None,
|
615
|
-
)
|
616
|
-
state.config = default_full_config
|
617
|
-
default_content_config = ContentConfig(
|
618
|
-
org=None,
|
619
|
-
markdown=None,
|
620
|
-
pdf=None,
|
621
|
-
docx=None,
|
622
|
-
image=None,
|
623
|
-
github=None,
|
624
|
-
notion=None,
|
625
|
-
plaintext=None,
|
626
|
-
)
|
627
|
-
state.config.content_type = default_content_config
|
628
|
-
save_config_to_file_updated_state()
|
629
|
-
configure_search(state.search_models, state.config.search_type)
|
630
|
-
|
631
584
|
loop = asyncio.get_event_loop()
|
632
585
|
success = await loop.run_in_executor(
|
633
586
|
None,
|
@@ -674,14 +627,6 @@ async def indexer(
|
|
674
627
|
return Response(content=indexed_filenames, status_code=200)
|
675
628
|
|
676
629
|
|
677
|
-
def configure_search(search_models: SearchModels, search_config: Optional[SearchConfig]) -> Optional[SearchModels]:
|
678
|
-
# Run Validation Checks
|
679
|
-
if search_models is None:
|
680
|
-
search_models = SearchModels()
|
681
|
-
|
682
|
-
return search_models
|
683
|
-
|
684
|
-
|
685
630
|
def map_config_to_object(content_source: str):
|
686
631
|
if content_source == DbEntry.EntrySource.GITHUB:
|
687
632
|
return GithubConfig
|
@@ -689,56 +634,3 @@ def map_config_to_object(content_source: str):
|
|
689
634
|
return NotionConfig
|
690
635
|
if content_source == DbEntry.EntrySource.COMPUTER:
|
691
636
|
return "Computer"
|
692
|
-
|
693
|
-
|
694
|
-
async def map_config_to_db(config: FullConfig, user: KhojUser):
|
695
|
-
if config.content_type:
|
696
|
-
if config.content_type.org:
|
697
|
-
await LocalOrgConfig.objects.filter(user=user).adelete()
|
698
|
-
await LocalOrgConfig.objects.acreate(
|
699
|
-
input_files=config.content_type.org.input_files,
|
700
|
-
input_filter=config.content_type.org.input_filter,
|
701
|
-
index_heading_entries=config.content_type.org.index_heading_entries,
|
702
|
-
user=user,
|
703
|
-
)
|
704
|
-
if config.content_type.markdown:
|
705
|
-
await LocalMarkdownConfig.objects.filter(user=user).adelete()
|
706
|
-
await LocalMarkdownConfig.objects.acreate(
|
707
|
-
input_files=config.content_type.markdown.input_files,
|
708
|
-
input_filter=config.content_type.markdown.input_filter,
|
709
|
-
index_heading_entries=config.content_type.markdown.index_heading_entries,
|
710
|
-
user=user,
|
711
|
-
)
|
712
|
-
if config.content_type.pdf:
|
713
|
-
await LocalPdfConfig.objects.filter(user=user).adelete()
|
714
|
-
await LocalPdfConfig.objects.acreate(
|
715
|
-
input_files=config.content_type.pdf.input_files,
|
716
|
-
input_filter=config.content_type.pdf.input_filter,
|
717
|
-
index_heading_entries=config.content_type.pdf.index_heading_entries,
|
718
|
-
user=user,
|
719
|
-
)
|
720
|
-
if config.content_type.plaintext:
|
721
|
-
await LocalPlaintextConfig.objects.filter(user=user).adelete()
|
722
|
-
await LocalPlaintextConfig.objects.acreate(
|
723
|
-
input_files=config.content_type.plaintext.input_files,
|
724
|
-
input_filter=config.content_type.plaintext.input_filter,
|
725
|
-
index_heading_entries=config.content_type.plaintext.index_heading_entries,
|
726
|
-
user=user,
|
727
|
-
)
|
728
|
-
if config.content_type.github:
|
729
|
-
await adapters.set_user_github_config(
|
730
|
-
user=user,
|
731
|
-
pat_token=config.content_type.github.pat_token,
|
732
|
-
repos=config.content_type.github.repos,
|
733
|
-
)
|
734
|
-
if config.content_type.notion:
|
735
|
-
await adapters.set_notion_config(
|
736
|
-
user=user,
|
737
|
-
token=config.content_type.notion.token,
|
738
|
-
)
|
739
|
-
|
740
|
-
|
741
|
-
def _initialize_config():
|
742
|
-
if state.config is None:
|
743
|
-
state.config = FullConfig()
|
744
|
-
state.config.search_type = SearchConfig.model_validate(constants.default_config["search-type"])
|
khoj/routers/api_model.py
CHANGED
khoj/routers/api_subscription.py
CHANGED
@@ -117,7 +117,7 @@ async def subscribe(request: Request):
|
|
117
117
|
)
|
118
118
|
logger.log(logging.INFO, f"🥳 New User Created: {user.user.uuid}")
|
119
119
|
|
120
|
-
logger.info(f
|
120
|
+
logger.info(f"Stripe subscription {event['type']} for {customer_email}")
|
121
121
|
return {"success": success}
|
122
122
|
|
123
123
|
|
khoj/routers/email.py
CHANGED
@@ -44,7 +44,7 @@ async def send_magic_link_email(email, unique_id, host):
|
|
44
44
|
{
|
45
45
|
"sender": os.environ.get("RESEND_EMAIL", "noreply@khoj.dev"),
|
46
46
|
"to": email,
|
47
|
-
"subject":
|
47
|
+
"subject": "Your login code to Khoj",
|
48
48
|
"html": html_content,
|
49
49
|
}
|
50
50
|
)
|
@@ -98,11 +98,11 @@ async def send_query_feedback(uquery, kquery, sentiment, user_email):
|
|
98
98
|
user_email=user_email if not is_none_or_empty(user_email) else "N/A",
|
99
99
|
)
|
100
100
|
# send feedback to fixed account
|
101
|
-
|
101
|
+
resend.Emails.send(
|
102
102
|
{
|
103
103
|
"sender": os.environ.get("RESEND_EMAIL", "noreply@khoj.dev"),
|
104
104
|
"to": "team@khoj.dev",
|
105
|
-
"subject":
|
105
|
+
"subject": "User Feedback",
|
106
106
|
"html": html_content,
|
107
107
|
}
|
108
108
|
)
|
@@ -127,7 +127,7 @@ def send_task_email(name, email, query, result, subject, is_image=False):
|
|
127
127
|
|
128
128
|
r = resend.Emails.send(
|
129
129
|
{
|
130
|
-
"sender": f
|
130
|
+
"sender": f"Khoj <{os.environ.get('RESEND_EMAIL', 'khoj@khoj.dev')}>",
|
131
131
|
"to": email,
|
132
132
|
"subject": f"✨ {subject}",
|
133
133
|
"html": html_content,
|