khoj 1.30.11.dev13__py3-none-any.whl → 1.30.11.dev56__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/settings.py +21 -0
- khoj/configure.py +3 -3
- khoj/database/adapters/__init__.py +15 -15
- khoj/database/admin.py +50 -40
- khoj/database/migrations/0075_migrate_generated_assets_and_validate.py +85 -0
- khoj/database/migrations/0076_rename_openaiprocessorconversationconfig_aimodelapi_and_more.py +26 -0
- khoj/database/models/__init__.py +171 -42
- khoj/interface/compiled/404/index.html +1 -1
- khoj/interface/compiled/_next/static/chunks/1603-e40aadd1e56ab030.js +1 -0
- khoj/interface/compiled/_next/static/chunks/5538-0ea2d3944ca051e1.js +1 -0
- khoj/interface/compiled/_next/static/chunks/app/agents/layout-1878cc328ea380bd.js +1 -0
- khoj/interface/compiled/_next/static/chunks/app/agents/{page-8eead7920b0ff92a.js → page-f5c0801b27a8e95e.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/app/automations/layout-7f1b79a2c67af0b4.js +1 -0
- khoj/interface/compiled/_next/static/chunks/app/automations/{page-b5800b5286306140.js → page-8691f6c09a0acd44.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/app/chat/layout-9219a85f3477e722.js +1 -0
- khoj/interface/compiled/_next/static/chunks/app/chat/{page-d7d2ab93e519f0b2.js → page-135d56dd4263e40d.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/app/layout-6310c57b674dd6f5.js +1 -0
- khoj/interface/compiled/_next/static/chunks/app/{page-3c32ad5472f75965.js → page-e79ace822d51557b.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/app/search/{page-faa998c71eb7ca8e.js → page-e8b578d155550386.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/app/settings/layout-f285795bc3154b8c.js +1 -0
- khoj/interface/compiled/_next/static/chunks/app/settings/{page-cbe7f56b1f87d77a.js → page-b6c835050c970be7.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/app/share/chat/layout-6f4879fbbf8b90f7.js +1 -0
- khoj/interface/compiled/_next/static/chunks/app/share/chat/{page-cd5757199539bbf2.js → page-635635e4fb39fe29.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/{webpack-3a2dfd74acf6e193.js → webpack-5203c3872078c10c.js} +1 -1
- khoj/interface/compiled/_next/static/css/{bedf49fbfc598358.css → 089de1d8526b96e9.css} +1 -1
- khoj/interface/compiled/_next/static/css/4cae6c0e5c72fb2d.css +1 -0
- khoj/interface/compiled/_next/static/css/edd3abaf11580924.css +1 -0
- khoj/interface/compiled/_next/static/media/1d8a05b60287ae6c-s.p.woff2 +0 -0
- khoj/interface/compiled/_next/static/media/6f22fce21a7c433c-s.woff2 +0 -0
- khoj/interface/compiled/_next/static/media/77c207b095007c34-s.p.woff2 +0 -0
- khoj/interface/compiled/_next/static/media/82ef96de0e8f4d8c-s.p.woff2 +0 -0
- khoj/interface/compiled/_next/static/media/a6ecd16fa044d500-s.p.woff2 +0 -0
- khoj/interface/compiled/_next/static/media/bd82c78e5b7b3fe9-s.p.woff2 +0 -0
- khoj/interface/compiled/_next/static/media/c32c8052c071fc42-s.woff2 +0 -0
- khoj/interface/compiled/_next/static/media/c4250770ab8708b6-s.p.woff2 +0 -0
- khoj/interface/compiled/agents/index.html +1 -1
- khoj/interface/compiled/agents/index.txt +2 -2
- khoj/interface/compiled/assets/icons/khoj_lantern.svg +100 -0
- khoj/interface/compiled/assets/icons/khoj_lantern_128x128_dark.png +0 -0
- khoj/interface/compiled/automations/index.html +1 -1
- khoj/interface/compiled/automations/index.txt +3 -3
- khoj/interface/compiled/chat/index.html +1 -1
- khoj/interface/compiled/chat/index.txt +2 -2
- khoj/interface/compiled/index.html +1 -1
- khoj/interface/compiled/index.txt +2 -2
- khoj/interface/compiled/search/index.html +1 -1
- khoj/interface/compiled/search/index.txt +2 -2
- khoj/interface/compiled/settings/index.html +1 -1
- khoj/interface/compiled/settings/index.txt +5 -4
- khoj/interface/compiled/share/chat/index.html +1 -1
- khoj/interface/compiled/share/chat/index.txt +2 -2
- khoj/migrations/migrate_server_pg.py +3 -9
- khoj/processor/conversation/anthropic/anthropic_chat.py +11 -3
- khoj/processor/conversation/google/gemini_chat.py +11 -3
- khoj/processor/conversation/offline/chat_model.py +6 -2
- khoj/processor/conversation/openai/gpt.py +10 -2
- khoj/processor/conversation/openai/utils.py +1 -6
- khoj/processor/conversation/prompts.py +18 -0
- khoj/processor/conversation/utils.py +82 -26
- khoj/processor/image/generate.py +12 -15
- khoj/routers/api.py +5 -5
- khoj/routers/api_chat.py +49 -98
- khoj/routers/helpers.py +52 -12
- khoj/utils/initialization.py +10 -12
- {khoj-1.30.11.dev13.dist-info → khoj-1.30.11.dev56.dist-info}/METADATA +2 -1
- {khoj-1.30.11.dev13.dist-info → khoj-1.30.11.dev56.dist-info}/RECORD +71 -67
- khoj/interface/compiled/_next/static/chunks/1603-c68d44bc4ae6039a.js +0 -1
- khoj/interface/compiled/_next/static/chunks/5538-e5f3c9f4d67a64b9.js +0 -1
- khoj/interface/compiled/_next/static/chunks/app/agents/layout-f2ea2b26fc0e78b1.js +0 -1
- khoj/interface/compiled/_next/static/chunks/app/automations/layout-f1050c1f20a3af67.js +0 -1
- khoj/interface/compiled/_next/static/chunks/app/chat/layout-1072c3b0ab136e74.js +0 -1
- khoj/interface/compiled/_next/static/chunks/app/layout-72ec1be8afd0b1ab.js +0 -1
- khoj/interface/compiled/_next/static/chunks/app/settings/layout-fe8a2f65ccafd142.js +0 -1
- khoj/interface/compiled/_next/static/chunks/app/share/chat/layout-dc97434f0354a74e.js +0 -1
- khoj/interface/compiled/_next/static/css/2d097a35da6bfe8d.css +0 -1
- khoj/interface/compiled/_next/static/css/80bd6301fc657983.css +0 -1
- khoj/interface/compiled/_next/static/media/5455839c73f146e7-s.p.woff2 +0 -0
- khoj/interface/compiled/_next/static/media/5984b96ba4822821-s.p.woff2 +0 -0
- khoj/interface/compiled/_next/static/media/684adc3dde1b03f1-s.p.woff2 +0 -0
- khoj/interface/compiled/_next/static/media/82e3b9a1bdaf0c26-s.p.woff2 +0 -0
- khoj/interface/compiled/_next/static/media/8d1ea331386a0db8-s.p.woff2 +0 -0
- khoj/interface/compiled/_next/static/media/91475f6526542a4f-s.woff2 +0 -0
- khoj/interface/compiled/_next/static/media/b98b13dbc1c3b59c-s.p.woff2 +0 -0
- khoj/interface/compiled/_next/static/media/c824d7a20139e39d-s.woff2 +0 -0
- /khoj/interface/compiled/_next/static/{K_WyVARSz0loPVvwOW1gg → J7Vqh1vjCleYuVLeTaJL6}/_buildManifest.js +0 -0
- /khoj/interface/compiled/_next/static/{K_WyVARSz0loPVvwOW1gg → J7Vqh1vjCleYuVLeTaJL6}/_ssgManifest.js +0 -0
- {khoj-1.30.11.dev13.dist-info → khoj-1.30.11.dev56.dist-info}/WHEEL +0 -0
- {khoj-1.30.11.dev13.dist-info → khoj-1.30.11.dev56.dist-info}/entry_points.txt +0 -0
- {khoj-1.30.11.dev13.dist-info → khoj-1.30.11.dev56.dist-info}/licenses/LICENSE +0 -0
@@ -1,7 +1,7 @@
|
|
1
1
|
2:I[66513,[],"ClientPageRoot"]
|
2
|
-
3:I[5506,["3954","static/chunks/d3ac728e-a9e3522eef9b6b28.js","3072","static/chunks/3072-be830e4f8412b9d2.js","4752","static/chunks/4752-554a3db270186ce3.js","7592","static/chunks/7592-a09c39a38e60634b.js","3690","static/chunks/3690-51312931ba1eae30.js","3463","static/chunks/3463-081c031e873b7966.js","1603","static/chunks/1603-
|
2
|
+
3:I[5506,["3954","static/chunks/d3ac728e-a9e3522eef9b6b28.js","3072","static/chunks/3072-be830e4f8412b9d2.js","4752","static/chunks/4752-554a3db270186ce3.js","7592","static/chunks/7592-a09c39a38e60634b.js","3690","static/chunks/3690-51312931ba1eae30.js","3463","static/chunks/3463-081c031e873b7966.js","1603","static/chunks/1603-e40aadd1e56ab030.js","8423","static/chunks/8423-1dda16bc56236523.js","5538","static/chunks/5538-0ea2d3944ca051e1.js","3111","static/chunks/app/share/chat/page-635635e4fb39fe29.js"],"default",1]
|
3
3
|
4:I[39275,[],""]
|
4
4
|
5:I[61343,[],""]
|
5
|
-
0:["
|
5
|
+
0:["J7Vqh1vjCleYuVLeTaJL6",[[["",{"children":["share",{"children":["chat",{"children":["__PAGE__",{}]}]}]},"$undefined","$undefined",true],["",{"children":["share",{"children":["chat",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/3cf13271869a4aeb.css","precedence":"next","crossOrigin":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/_next/static/css/edd3abaf11580924.css","precedence":"next","crossOrigin":"$undefined"}],["$","link","2",{"rel":"stylesheet","href":"/_next/static/css/1f293605f2871853.css","precedence":"next","crossOrigin":"$undefined"}]]],null],null]},[[null,["$","html",null,{"lang":"en","className":"__variable_f36179 __variable_702545","children":[["$","meta",null,{"httpEquiv":"Content-Security-Policy","content":"default-src 'self' https://assets.khoj.dev; media-src * blob:; script-src 'self' https://assets.khoj.dev https://app.chatwoot.com 'unsafe-inline' 'unsafe-eval'; connect-src 'self' blob: https://ipapi.co/json ws://localhost:42110; style-src 'self' https://assets.khoj.dev 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: blob: https://*.khoj.dev https://*.googleusercontent.com https://*.google.com/ https://*.gstatic.com; font-src 'self' https://assets.khoj.dev https://fonts.gstatic.com; child-src 'self' https://app.chatwoot.com; object-src 'none';"}],["$","body",null,{"children":[["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","share","children","chat","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}],["$","script",null,{"dangerouslySetInnerHTML":{"__html":"window.EXCALIDRAW_ASSET_PATH = 'https://assets.khoj.dev/@excalidraw/excalidraw/dist/';"}}]]}]]}]],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","share","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/089de1d8526b96e9.css","precedence":"next","crossOrigin":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/_next/static/css/3c34171b174cc381.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","className":"__variable_f36179 __variable_702545","children":[["$","meta",null,{"httpEquiv":"Content-Security-Policy","content":"default-src 'self' https://assets.khoj.dev; media-src * blob:; script-src 'self' https://assets.khoj.dev https://app.chatwoot.com 'unsafe-inline' 'unsafe-eval'; connect-src 'self' blob: https://ipapi.co/json ws://localhost:42110; style-src 'self' https://assets.khoj.dev 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: blob: https://*.khoj.dev https://*.googleusercontent.com https://*.google.com/ https://*.gstatic.com; font-src 'self' https://assets.khoj.dev https://fonts.gstatic.com; child-src 'self' https://app.chatwoot.com; object-src 'none';"}],["$","body",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]]}]],null],null],["$L6",null]]]]
|
6
6
|
6:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Khoj AI - Chat"}],["$","meta","3",{"name":"description","content":"Use this page to view a chat with Khoj AI."}],["$","link","4",{"rel":"manifest","href":"/static/khoj.webmanifest","crossOrigin":"use-credentials"}],["$","meta","5",{"property":"og:title","content":"Khoj AI"}],["$","meta","6",{"property":"og:description","content":"Your Second Brain."}],["$","meta","7",{"property":"og:url","content":"https://app.khoj.dev/"}],["$","meta","8",{"property":"og:site_name","content":"Khoj AI"}],["$","meta","9",{"property":"og:image","content":"https://assets.khoj.dev/khoj_lantern_256x256.png"}],["$","meta","10",{"property":"og:image:width","content":"256"}],["$","meta","11",{"property":"og:image:height","content":"256"}],["$","meta","12",{"property":"og:image","content":"https://assets.khoj.dev/khoj_lantern_logomarktype_1200x630.png"}],["$","meta","13",{"property":"og:image:width","content":"1200"}],["$","meta","14",{"property":"og:image:height","content":"630"}],["$","meta","15",{"property":"og:type","content":"website"}],["$","meta","16",{"name":"twitter:card","content":"summary_large_image"}],["$","meta","17",{"name":"twitter:title","content":"Khoj AI"}],["$","meta","18",{"name":"twitter:description","content":"Your Second Brain."}],["$","meta","19",{"name":"twitter:image","content":"https://assets.khoj.dev/khoj_lantern_256x256.png"}],["$","meta","20",{"name":"twitter:image:width","content":"256"}],["$","meta","21",{"name":"twitter:image:height","content":"256"}],["$","meta","22",{"name":"twitter:image","content":"https://assets.khoj.dev/khoj_lantern_logomarktype_1200x630.png"}],["$","meta","23",{"name":"twitter:image:width","content":"1200"}],["$","meta","24",{"name":"twitter:image:height","content":"630"}],["$","link","25",{"rel":"icon","href":"/static/assets/icons/khoj_lantern.ico"}],["$","link","26",{"rel":"apple-touch-icon","href":"/static/assets/icons/khoj_lantern_256x256.png"}],["$","meta","27",{"name":"next-size-adjust"}]]
|
7
7
|
1:null
|
@@ -60,11 +60,7 @@ import logging
|
|
60
60
|
|
61
61
|
from packaging import version
|
62
62
|
|
63
|
-
from khoj.database.models import
|
64
|
-
ChatModelOptions,
|
65
|
-
OpenAIProcessorConversationConfig,
|
66
|
-
SearchModelConfig,
|
67
|
-
)
|
63
|
+
from khoj.database.models import AiModelApi, ChatModelOptions, SearchModelConfig
|
68
64
|
from khoj.utils.yaml import load_config_from_file, save_config_to_file
|
69
65
|
|
70
66
|
logger = logging.getLogger(__name__)
|
@@ -121,16 +117,14 @@ def migrate_server_pg(args):
|
|
121
117
|
if openai.get("chat-model") is None:
|
122
118
|
openai["chat-model"] = "gpt-3.5-turbo"
|
123
119
|
|
124
|
-
|
125
|
-
api_key=openai.get("api-key"), name="default"
|
126
|
-
)
|
120
|
+
openai_model_api = AiModelApi.objects.create(api_key=openai.get("api-key"), name="default")
|
127
121
|
|
128
122
|
ChatModelOptions.objects.create(
|
129
123
|
chat_model=openai.get("chat-model"),
|
130
124
|
tokenizer=processor_conversation.get("tokenizer"),
|
131
125
|
max_prompt_size=processor_conversation.get("max-prompt-size"),
|
132
126
|
model_type=ChatModelOptions.ModelType.OPENAI,
|
133
|
-
|
127
|
+
ai_model_api=openai_model_api,
|
134
128
|
)
|
135
129
|
|
136
130
|
save_config_to_file(raw_config, args.config_file)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import logging
|
2
2
|
from datetime import datetime, timedelta
|
3
|
-
from typing import Dict, Optional
|
3
|
+
from typing import Dict, List, Optional
|
4
4
|
|
5
5
|
import pyjson5
|
6
6
|
from langchain.schema import ChatMessage
|
@@ -23,7 +23,7 @@ from khoj.utils.helpers import (
|
|
23
23
|
is_none_or_empty,
|
24
24
|
truncate_code_context,
|
25
25
|
)
|
26
|
-
from khoj.utils.rawconfig import LocationData
|
26
|
+
from khoj.utils.rawconfig import FileAttachment, LocationData
|
27
27
|
from khoj.utils.yaml import yaml_dump
|
28
28
|
|
29
29
|
logger = logging.getLogger(__name__)
|
@@ -55,7 +55,7 @@ def extract_questions_anthropic(
|
|
55
55
|
[
|
56
56
|
f'User: {chat["intent"]["query"]}\nAssistant: {{"queries": {chat["intent"].get("inferred-queries") or list([chat["intent"]["query"]])}}}\nA: {chat["message"]}\n\n'
|
57
57
|
for chat in conversation_log.get("chat", [])[-4:]
|
58
|
-
if chat["by"] == "khoj"
|
58
|
+
if chat["by"] == "khoj"
|
59
59
|
]
|
60
60
|
)
|
61
61
|
|
@@ -157,6 +157,10 @@ def converse_anthropic(
|
|
157
157
|
query_images: Optional[list[str]] = None,
|
158
158
|
vision_available: bool = False,
|
159
159
|
query_files: str = None,
|
160
|
+
generated_images: Optional[list[str]] = None,
|
161
|
+
generated_files: List[FileAttachment] = None,
|
162
|
+
generated_excalidraw_diagram: Optional[str] = None,
|
163
|
+
program_execution_context: Optional[List[str]] = None,
|
160
164
|
tracer: dict = {},
|
161
165
|
):
|
162
166
|
"""
|
@@ -217,6 +221,10 @@ def converse_anthropic(
|
|
217
221
|
vision_enabled=vision_available,
|
218
222
|
model_type=ChatModelOptions.ModelType.ANTHROPIC,
|
219
223
|
query_files=query_files,
|
224
|
+
generated_excalidraw_diagram=generated_excalidraw_diagram,
|
225
|
+
generated_files=generated_files,
|
226
|
+
generated_images=generated_images,
|
227
|
+
program_execution_context=program_execution_context,
|
220
228
|
)
|
221
229
|
|
222
230
|
messages, system_prompt = format_messages_for_anthropic(messages, system_prompt)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import logging
|
2
2
|
from datetime import datetime, timedelta
|
3
|
-
from typing import Dict, Optional
|
3
|
+
from typing import Dict, List, Optional
|
4
4
|
|
5
5
|
import pyjson5
|
6
6
|
from langchain.schema import ChatMessage
|
@@ -23,7 +23,7 @@ from khoj.utils.helpers import (
|
|
23
23
|
is_none_or_empty,
|
24
24
|
truncate_code_context,
|
25
25
|
)
|
26
|
-
from khoj.utils.rawconfig import LocationData
|
26
|
+
from khoj.utils.rawconfig import FileAttachment, LocationData
|
27
27
|
from khoj.utils.yaml import yaml_dump
|
28
28
|
|
29
29
|
logger = logging.getLogger(__name__)
|
@@ -56,7 +56,7 @@ def extract_questions_gemini(
|
|
56
56
|
[
|
57
57
|
f'User: {chat["intent"]["query"]}\nAssistant: {{"queries": {chat["intent"].get("inferred-queries") or list([chat["intent"]["query"]])}}}\nA: {chat["message"]}\n\n'
|
58
58
|
for chat in conversation_log.get("chat", [])[-4:]
|
59
|
-
if chat["by"] == "khoj"
|
59
|
+
if chat["by"] == "khoj"
|
60
60
|
]
|
61
61
|
)
|
62
62
|
|
@@ -167,6 +167,10 @@ def converse_gemini(
|
|
167
167
|
query_images: Optional[list[str]] = None,
|
168
168
|
vision_available: bool = False,
|
169
169
|
query_files: str = None,
|
170
|
+
generated_images: Optional[list[str]] = None,
|
171
|
+
generated_files: List[FileAttachment] = None,
|
172
|
+
generated_excalidraw_diagram: Optional[str] = None,
|
173
|
+
program_execution_context: List[str] = None,
|
170
174
|
tracer={},
|
171
175
|
):
|
172
176
|
"""
|
@@ -228,6 +232,10 @@ def converse_gemini(
|
|
228
232
|
vision_enabled=vision_available,
|
229
233
|
model_type=ChatModelOptions.ModelType.GOOGLE,
|
230
234
|
query_files=query_files,
|
235
|
+
generated_excalidraw_diagram=generated_excalidraw_diagram,
|
236
|
+
generated_files=generated_files,
|
237
|
+
generated_images=generated_images,
|
238
|
+
program_execution_context=program_execution_context,
|
231
239
|
)
|
232
240
|
|
233
241
|
messages, system_prompt = format_messages_for_gemini(messages, system_prompt)
|
@@ -28,7 +28,7 @@ from khoj.utils.helpers import (
|
|
28
28
|
is_promptrace_enabled,
|
29
29
|
truncate_code_context,
|
30
30
|
)
|
31
|
-
from khoj.utils.rawconfig import LocationData
|
31
|
+
from khoj.utils.rawconfig import FileAttachment, LocationData
|
32
32
|
from khoj.utils.yaml import yaml_dump
|
33
33
|
|
34
34
|
logger = logging.getLogger(__name__)
|
@@ -69,7 +69,7 @@ def extract_questions_offline(
|
|
69
69
|
|
70
70
|
if use_history:
|
71
71
|
for chat in conversation_log.get("chat", [])[-4:]:
|
72
|
-
if chat["by"] == "khoj"
|
72
|
+
if chat["by"] == "khoj":
|
73
73
|
chat_history += f"Q: {chat['intent']['query']}\n"
|
74
74
|
chat_history += f"Khoj: {chat['message']}\n\n"
|
75
75
|
|
@@ -164,6 +164,8 @@ def converse_offline(
|
|
164
164
|
user_name: str = None,
|
165
165
|
agent: Agent = None,
|
166
166
|
query_files: str = None,
|
167
|
+
generated_files: List[FileAttachment] = None,
|
168
|
+
additional_context: List[str] = None,
|
167
169
|
tracer: dict = {},
|
168
170
|
) -> Union[ThreadedGenerator, Iterator[str]]:
|
169
171
|
"""
|
@@ -231,6 +233,8 @@ def converse_offline(
|
|
231
233
|
tokenizer_name=tokenizer_name,
|
232
234
|
model_type=ChatModelOptions.ModelType.OFFLINE,
|
233
235
|
query_files=query_files,
|
236
|
+
generated_files=generated_files,
|
237
|
+
program_execution_context=additional_context,
|
234
238
|
)
|
235
239
|
|
236
240
|
logger.debug(f"Conversation Context for {model}: {messages_to_print(messages)}")
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import logging
|
2
2
|
from datetime import datetime, timedelta
|
3
|
-
from typing import Dict, Optional
|
3
|
+
from typing import Dict, List, Optional
|
4
4
|
|
5
5
|
import pyjson5
|
6
6
|
from langchain.schema import ChatMessage
|
@@ -22,7 +22,7 @@ from khoj.utils.helpers import (
|
|
22
22
|
is_none_or_empty,
|
23
23
|
truncate_code_context,
|
24
24
|
)
|
25
|
-
from khoj.utils.rawconfig import LocationData
|
25
|
+
from khoj.utils.rawconfig import FileAttachment, LocationData
|
26
26
|
from khoj.utils.yaml import yaml_dump
|
27
27
|
|
28
28
|
logger = logging.getLogger(__name__)
|
@@ -157,6 +157,10 @@ def converse(
|
|
157
157
|
query_images: Optional[list[str]] = None,
|
158
158
|
vision_available: bool = False,
|
159
159
|
query_files: str = None,
|
160
|
+
generated_images: Optional[list[str]] = None,
|
161
|
+
generated_files: List[FileAttachment] = None,
|
162
|
+
generated_excalidraw_diagram: Optional[str] = None,
|
163
|
+
program_execution_context: List[str] = None,
|
160
164
|
tracer: dict = {},
|
161
165
|
):
|
162
166
|
"""
|
@@ -219,6 +223,10 @@ def converse(
|
|
219
223
|
vision_enabled=vision_available,
|
220
224
|
model_type=ChatModelOptions.ModelType.OPENAI,
|
221
225
|
query_files=query_files,
|
226
|
+
generated_excalidraw_diagram=generated_excalidraw_diagram,
|
227
|
+
generated_files=generated_files,
|
228
|
+
generated_images=generated_images,
|
229
|
+
program_execution_context=program_execution_context,
|
222
230
|
)
|
223
231
|
logger.debug(f"Conversation Context for GPT: {messages_to_print(messages)}")
|
224
232
|
|
@@ -19,12 +19,7 @@ from khoj.processor.conversation.utils import (
|
|
19
19
|
ThreadedGenerator,
|
20
20
|
commit_conversation_trace,
|
21
21
|
)
|
22
|
-
from khoj.utils import
|
23
|
-
from khoj.utils.helpers import (
|
24
|
-
get_chat_usage_metrics,
|
25
|
-
in_debug_mode,
|
26
|
-
is_promptrace_enabled,
|
27
|
-
)
|
22
|
+
from khoj.utils.helpers import get_chat_usage_metrics, is_promptrace_enabled
|
28
23
|
|
29
24
|
logger = logging.getLogger(__name__)
|
30
25
|
|
@@ -178,6 +178,18 @@ Improved Prompt:
|
|
178
178
|
""".strip()
|
179
179
|
)
|
180
180
|
|
181
|
+
generated_image_attachment = PromptTemplate.from_template(
|
182
|
+
f"""
|
183
|
+
Here is the image you generated based on my query. You can follow-up with a general response to my query. Limit to 1-2 sentences.
|
184
|
+
""".strip()
|
185
|
+
)
|
186
|
+
|
187
|
+
generated_diagram_attachment = PromptTemplate.from_template(
|
188
|
+
f"""
|
189
|
+
I've successfully created a diagram based on the user's query. The diagram will automatically be shared with the user. I can follow-up with a general response or summary. Limit to 1-2 sentences.
|
190
|
+
""".strip()
|
191
|
+
)
|
192
|
+
|
181
193
|
## Diagram Generation
|
182
194
|
## --
|
183
195
|
|
@@ -1029,6 +1041,12 @@ A:
|
|
1029
1041
|
""".strip()
|
1030
1042
|
)
|
1031
1043
|
|
1044
|
+
additional_program_context = PromptTemplate.from_template(
|
1045
|
+
"""
|
1046
|
+
Here are some additional results from the query execution:
|
1047
|
+
{context}
|
1048
|
+
""".strip()
|
1049
|
+
)
|
1032
1050
|
|
1033
1051
|
personality_prompt_safety_expert_lax = PromptTemplate.from_template(
|
1034
1052
|
"""
|
@@ -154,7 +154,7 @@ def construct_chat_history(conversation_history: dict, n: int = 4, agent_name="A
|
|
154
154
|
chat_history += f'{agent_name}: {{"queries": {chat["intent"].get("inferred-queries")}}}\n'
|
155
155
|
|
156
156
|
chat_history += f"{agent_name}: {chat['message']}\n\n"
|
157
|
-
elif chat["by"] == "khoj" and
|
157
|
+
elif chat["by"] == "khoj" and chat.get("images"):
|
158
158
|
chat_history += f"User: {chat['intent']['query']}\n"
|
159
159
|
chat_history += f"{agent_name}: [generated image redacted for space]\n"
|
160
160
|
elif chat["by"] == "khoj" and ("excalidraw" in chat["intent"].get("type")):
|
@@ -213,6 +213,7 @@ class ChatEvent(Enum):
|
|
213
213
|
END_LLM_RESPONSE = "end_llm_response"
|
214
214
|
MESSAGE = "message"
|
215
215
|
REFERENCES = "references"
|
216
|
+
GENERATED_ASSETS = "generated_assets"
|
216
217
|
STATUS = "status"
|
217
218
|
METADATA = "metadata"
|
218
219
|
USAGE = "usage"
|
@@ -225,7 +226,6 @@ def message_to_log(
|
|
225
226
|
user_message_metadata={},
|
226
227
|
khoj_message_metadata={},
|
227
228
|
conversation_log=[],
|
228
|
-
train_of_thought=[],
|
229
229
|
):
|
230
230
|
"""Create json logs from messages, metadata for conversation log"""
|
231
231
|
default_khoj_message_metadata = {
|
@@ -234,6 +234,10 @@ def message_to_log(
|
|
234
234
|
}
|
235
235
|
khoj_response_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
236
236
|
|
237
|
+
# Filter out any fields that are set to None
|
238
|
+
user_message_metadata = {k: v for k, v in user_message_metadata.items() if v is not None}
|
239
|
+
khoj_message_metadata = {k: v for k, v in khoj_message_metadata.items() if v is not None}
|
240
|
+
|
237
241
|
# Create json log from Human's message
|
238
242
|
human_log = merge_dicts({"message": user_message, "by": "you"}, user_message_metadata)
|
239
243
|
|
@@ -261,31 +265,41 @@ def save_to_conversation_log(
|
|
261
265
|
automation_id: str = None,
|
262
266
|
query_images: List[str] = None,
|
263
267
|
raw_query_files: List[FileAttachment] = [],
|
268
|
+
generated_images: List[str] = [],
|
269
|
+
raw_generated_files: List[FileAttachment] = [],
|
270
|
+
generated_excalidraw_diagram: str = None,
|
264
271
|
train_of_thought: List[Any] = [],
|
265
272
|
tracer: Dict[str, Any] = {},
|
266
273
|
):
|
267
274
|
user_message_time = user_message_time or datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
268
275
|
turn_id = tracer.get("mid") or str(uuid.uuid4())
|
276
|
+
|
277
|
+
user_message_metadata = {"created": user_message_time, "images": query_images, "turnId": turn_id}
|
278
|
+
|
279
|
+
if raw_query_files and len(raw_query_files) > 0:
|
280
|
+
user_message_metadata["queryFiles"] = [file.model_dump(mode="json") for file in raw_query_files]
|
281
|
+
|
282
|
+
khoj_message_metadata = {
|
283
|
+
"context": compiled_references,
|
284
|
+
"intent": {"inferred-queries": inferred_queries, "type": intent_type},
|
285
|
+
"onlineContext": online_results,
|
286
|
+
"codeContext": code_results,
|
287
|
+
"automationId": automation_id,
|
288
|
+
"trainOfThought": train_of_thought,
|
289
|
+
"turnId": turn_id,
|
290
|
+
"images": generated_images,
|
291
|
+
"queryFiles": [file.model_dump(mode="json") for file in raw_generated_files],
|
292
|
+
}
|
293
|
+
|
294
|
+
if generated_excalidraw_diagram:
|
295
|
+
khoj_message_metadata["excalidrawDiagram"] = generated_excalidraw_diagram
|
296
|
+
|
269
297
|
updated_conversation = message_to_log(
|
270
298
|
user_message=q,
|
271
299
|
chat_response=chat_response,
|
272
|
-
user_message_metadata=
|
273
|
-
|
274
|
-
"images": query_images,
|
275
|
-
"turnId": turn_id,
|
276
|
-
"queryFiles": [file.model_dump(mode="json") for file in raw_query_files],
|
277
|
-
},
|
278
|
-
khoj_message_metadata={
|
279
|
-
"context": compiled_references,
|
280
|
-
"intent": {"inferred-queries": inferred_queries, "type": intent_type},
|
281
|
-
"onlineContext": online_results,
|
282
|
-
"codeContext": code_results,
|
283
|
-
"automationId": automation_id,
|
284
|
-
"trainOfThought": train_of_thought,
|
285
|
-
"turnId": turn_id,
|
286
|
-
},
|
300
|
+
user_message_metadata=user_message_metadata,
|
301
|
+
khoj_message_metadata=khoj_message_metadata,
|
287
302
|
conversation_log=meta_log.get("chat", []),
|
288
|
-
train_of_thought=train_of_thought,
|
289
303
|
)
|
290
304
|
ConversationAdapters.save_conversation(
|
291
305
|
user,
|
@@ -303,13 +317,13 @@ def save_to_conversation_log(
|
|
303
317
|
Saved Conversation Turn
|
304
318
|
You ({user.username}): "{q}"
|
305
319
|
|
306
|
-
Khoj: "{
|
320
|
+
Khoj: "{chat_response}"
|
307
321
|
""".strip()
|
308
322
|
)
|
309
323
|
|
310
324
|
|
311
325
|
def construct_structured_message(
|
312
|
-
message: str, images: list[str], model_type: str, vision_enabled: bool, attached_file_context: str
|
326
|
+
message: str, images: list[str], model_type: str, vision_enabled: bool, attached_file_context: str = None
|
313
327
|
):
|
314
328
|
"""
|
315
329
|
Format messages into appropriate multimedia format for supported chat model types
|
@@ -327,7 +341,8 @@ def construct_structured_message(
|
|
327
341
|
constructed_messages.append({"type": "text", "text": attached_file_context})
|
328
342
|
if vision_enabled and images:
|
329
343
|
for image in images:
|
330
|
-
|
344
|
+
if image.startswith("https://"):
|
345
|
+
constructed_messages.append({"type": "image_url", "image_url": {"url": image}})
|
331
346
|
return constructed_messages
|
332
347
|
|
333
348
|
if not is_none_or_empty(attached_file_context):
|
@@ -365,6 +380,10 @@ def generate_chatml_messages_with_context(
|
|
365
380
|
model_type="",
|
366
381
|
context_message="",
|
367
382
|
query_files: str = None,
|
383
|
+
generated_images: Optional[list[str]] = None,
|
384
|
+
generated_files: List[FileAttachment] = None,
|
385
|
+
generated_excalidraw_diagram: str = None,
|
386
|
+
program_execution_context: List[str] = [],
|
368
387
|
):
|
369
388
|
"""Generate chat messages with appropriate context from previous conversation to send to the chat model"""
|
370
389
|
# Set max prompt size from user config or based on pre-configured for model and machine specs
|
@@ -384,6 +403,7 @@ def generate_chatml_messages_with_context(
|
|
384
403
|
message_attached_files = ""
|
385
404
|
|
386
405
|
chat_message = chat.get("message")
|
406
|
+
role = "user" if chat["by"] == "you" else "assistant"
|
387
407
|
|
388
408
|
if chat["by"] == "khoj" and "excalidraw" in chat["intent"].get("type", ""):
|
389
409
|
chat_message = chat["intent"].get("inferred-queries")[0]
|
@@ -404,7 +424,7 @@ def generate_chatml_messages_with_context(
|
|
404
424
|
query_files_dict[file["name"]] = file["content"]
|
405
425
|
|
406
426
|
message_attached_files = gather_raw_query_files(query_files_dict)
|
407
|
-
chatml_messages.append(ChatMessage(content=message_attached_files, role=
|
427
|
+
chatml_messages.append(ChatMessage(content=message_attached_files, role=role))
|
408
428
|
|
409
429
|
if not is_none_or_empty(chat.get("onlineContext")):
|
410
430
|
message_context += f"{prompts.online_search_conversation.format(online_results=chat.get('onlineContext'))}"
|
@@ -413,10 +433,20 @@ def generate_chatml_messages_with_context(
|
|
413
433
|
reconstructed_context_message = ChatMessage(content=message_context, role="user")
|
414
434
|
chatml_messages.insert(0, reconstructed_context_message)
|
415
435
|
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
436
|
+
if chat.get("images"):
|
437
|
+
if role == "assistant":
|
438
|
+
# Issue: the assistant role cannot accept an image as a message content, so send it in a separate user message.
|
439
|
+
file_attachment_message = construct_structured_message(
|
440
|
+
message=prompts.generated_image_attachment.format(),
|
441
|
+
images=chat.get("images"),
|
442
|
+
model_type=model_type,
|
443
|
+
vision_enabled=vision_enabled,
|
444
|
+
)
|
445
|
+
chatml_messages.append(ChatMessage(content=file_attachment_message, role="user"))
|
446
|
+
else:
|
447
|
+
message_content = construct_structured_message(
|
448
|
+
chat_message, chat.get("images"), model_type, vision_enabled
|
449
|
+
)
|
420
450
|
|
421
451
|
reconstructed_message = ChatMessage(content=message_content, role=role)
|
422
452
|
chatml_messages.insert(0, reconstructed_message)
|
@@ -425,6 +455,7 @@ def generate_chatml_messages_with_context(
|
|
425
455
|
break
|
426
456
|
|
427
457
|
messages = []
|
458
|
+
|
428
459
|
if not is_none_or_empty(user_message):
|
429
460
|
messages.append(
|
430
461
|
ChatMessage(
|
@@ -437,6 +468,31 @@ def generate_chatml_messages_with_context(
|
|
437
468
|
if not is_none_or_empty(context_message):
|
438
469
|
messages.append(ChatMessage(content=context_message, role="user"))
|
439
470
|
|
471
|
+
if generated_images:
|
472
|
+
messages.append(
|
473
|
+
ChatMessage(
|
474
|
+
content=construct_structured_message(
|
475
|
+
prompts.generated_image_attachment.format(), generated_images, model_type, vision_enabled
|
476
|
+
),
|
477
|
+
role="user",
|
478
|
+
)
|
479
|
+
)
|
480
|
+
|
481
|
+
if generated_files:
|
482
|
+
message_attached_files = gather_raw_query_files({file.name: file.content for file in generated_files})
|
483
|
+
messages.append(ChatMessage(content=message_attached_files, role="assistant"))
|
484
|
+
|
485
|
+
if generated_excalidraw_diagram:
|
486
|
+
messages.append(ChatMessage(content=prompts.generated_diagram_attachment.format(), role="assistant"))
|
487
|
+
|
488
|
+
if program_execution_context:
|
489
|
+
messages.append(
|
490
|
+
ChatMessage(
|
491
|
+
content=prompts.additional_program_context.format(context="\n".join(program_execution_context)),
|
492
|
+
role="assistant",
|
493
|
+
)
|
494
|
+
)
|
495
|
+
|
440
496
|
if len(chatml_messages) > 0:
|
441
497
|
messages += chatml_messages
|
442
498
|
|
khoj/processor/image/generate.py
CHANGED
@@ -12,7 +12,7 @@ from khoj.database.models import Agent, KhojUser, TextToImageModelConfig
|
|
12
12
|
from khoj.routers.helpers import ChatEvent, generate_better_image_prompt
|
13
13
|
from khoj.routers.storage import upload_image
|
14
14
|
from khoj.utils import state
|
15
|
-
from khoj.utils.helpers import
|
15
|
+
from khoj.utils.helpers import convert_image_to_webp, timer
|
16
16
|
from khoj.utils.rawconfig import LocationData
|
17
17
|
|
18
18
|
logger = logging.getLogger(__name__)
|
@@ -34,14 +34,13 @@ async def text_to_image(
|
|
34
34
|
status_code = 200
|
35
35
|
image = None
|
36
36
|
image_url = None
|
37
|
-
intent_type = ImageIntentType.TEXT_TO_IMAGE_V3
|
38
37
|
|
39
38
|
text_to_image_config = await ConversationAdapters.aget_user_text_to_image_model(user)
|
40
39
|
if not text_to_image_config:
|
41
40
|
# If the user has not configured a text to image model, return an unsupported on server error
|
42
41
|
status_code = 501
|
43
42
|
message = "Failed to generate image. Setup image generation on the server."
|
44
|
-
yield image_url or image, status_code, message
|
43
|
+
yield image_url or image, status_code, message
|
45
44
|
return
|
46
45
|
|
47
46
|
text2image_model = text_to_image_config.model_name
|
@@ -50,8 +49,8 @@ async def text_to_image(
|
|
50
49
|
if chat["by"] == "khoj" and chat["intent"].get("type") in ["remember", "reminder"]:
|
51
50
|
chat_history += f"Q: {chat['intent']['query']}\n"
|
52
51
|
chat_history += f"A: {chat['message']}\n"
|
53
|
-
elif chat["by"] == "khoj" and
|
54
|
-
chat_history += f"Q:
|
52
|
+
elif chat["by"] == "khoj" and chat.get("images"):
|
53
|
+
chat_history += f"Q: {chat['intent']['query']}\n"
|
55
54
|
chat_history += f"A: Improved Prompt: {chat['intent']['inferred-queries'][0]}\n"
|
56
55
|
|
57
56
|
if send_status_func:
|
@@ -92,31 +91,29 @@ async def text_to_image(
|
|
92
91
|
logger.error(f"Image Generation blocked by OpenAI: {e}")
|
93
92
|
status_code = e.status_code # type: ignore
|
94
93
|
message = f"Image generation blocked by OpenAI due to policy violation" # type: ignore
|
95
|
-
yield image_url or image, status_code, message
|
94
|
+
yield image_url or image, status_code, message
|
96
95
|
return
|
97
96
|
else:
|
98
97
|
logger.error(f"Image Generation failed with {e}", exc_info=True)
|
99
98
|
message = f"Image generation failed using OpenAI" # type: ignore
|
100
99
|
status_code = e.status_code # type: ignore
|
101
|
-
yield image_url or image, status_code, message
|
100
|
+
yield image_url or image, status_code, message
|
102
101
|
return
|
103
102
|
except requests.RequestException as e:
|
104
103
|
logger.error(f"Image Generation failed with {e}", exc_info=True)
|
105
104
|
message = f"Image generation using {text2image_model} via {text_to_image_config.model_type} failed due to a network error."
|
106
105
|
status_code = 502
|
107
|
-
yield image_url or image, status_code, message
|
106
|
+
yield image_url or image, status_code, message
|
108
107
|
return
|
109
108
|
|
110
109
|
# Decide how to store the generated image
|
111
110
|
with timer("Upload image to S3", logger):
|
112
111
|
image_url = upload_image(webp_image_bytes, user.uuid)
|
113
|
-
|
114
|
-
|
115
|
-
else:
|
116
|
-
intent_type = ImageIntentType.TEXT_TO_IMAGE_V3
|
112
|
+
|
113
|
+
if not image_url:
|
117
114
|
image = base64.b64encode(webp_image_bytes).decode("utf-8")
|
118
115
|
|
119
|
-
yield image_url or image, status_code, image_prompt
|
116
|
+
yield image_url or image, status_code, image_prompt
|
120
117
|
|
121
118
|
|
122
119
|
def generate_image_with_openai(
|
@@ -127,8 +124,8 @@ def generate_image_with_openai(
|
|
127
124
|
# Get the API key from the user's configuration
|
128
125
|
if text_to_image_config.api_key:
|
129
126
|
api_key = text_to_image_config.api_key
|
130
|
-
elif text_to_image_config.
|
131
|
-
api_key = text_to_image_config.
|
127
|
+
elif text_to_image_config.ai_model_api:
|
128
|
+
api_key = text_to_image_config.ai_model_api.api_key
|
132
129
|
elif state.openai_client:
|
133
130
|
api_key = state.openai_client.api_key
|
134
131
|
auth_header = {"Authorization": f"Bearer {api_key}"} if api_key else {}
|
khoj/routers/api.py
CHANGED
@@ -430,9 +430,8 @@ async def extract_references_and_questions(
|
|
430
430
|
tracer=tracer,
|
431
431
|
)
|
432
432
|
elif conversation_config.model_type == ChatModelOptions.ModelType.OPENAI:
|
433
|
-
|
434
|
-
|
435
|
-
base_url = openai_chat_config.api_base_url
|
433
|
+
api_key = conversation_config.ai_model_api.api_key
|
434
|
+
base_url = conversation_config.ai_model_api.api_base_url
|
436
435
|
chat_model = conversation_config.chat_model
|
437
436
|
inferred_queries = extract_questions(
|
438
437
|
defiltered_query,
|
@@ -449,7 +448,7 @@ async def extract_references_and_questions(
|
|
449
448
|
tracer=tracer,
|
450
449
|
)
|
451
450
|
elif conversation_config.model_type == ChatModelOptions.ModelType.ANTHROPIC:
|
452
|
-
api_key = conversation_config.
|
451
|
+
api_key = conversation_config.ai_model_api.api_key
|
453
452
|
chat_model = conversation_config.chat_model
|
454
453
|
inferred_queries = extract_questions_anthropic(
|
455
454
|
defiltered_query,
|
@@ -465,7 +464,7 @@ async def extract_references_and_questions(
|
|
465
464
|
tracer=tracer,
|
466
465
|
)
|
467
466
|
elif conversation_config.model_type == ChatModelOptions.ModelType.GOOGLE:
|
468
|
-
api_key = conversation_config.
|
467
|
+
api_key = conversation_config.ai_model_api.api_key
|
469
468
|
chat_model = conversation_config.chat_model
|
470
469
|
inferred_queries = extract_questions_gemini(
|
471
470
|
defiltered_query,
|
@@ -537,6 +536,7 @@ def user_info(request: Request) -> Response:
|
|
537
536
|
"photo": user_picture,
|
538
537
|
"is_active": is_active,
|
539
538
|
"has_documents": has_documents,
|
539
|
+
"khoj_version": state.khoj_version,
|
540
540
|
}
|
541
541
|
|
542
542
|
# Return user information as a JSON response
|