khoj 1.28.4.dev23__py3-none-any.whl → 1.28.4.dev77__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/configure.py +4 -6
- khoj/database/adapters/__init__.py +124 -34
- khoj/database/models/__init__.py +4 -0
- khoj/interface/compiled/404/index.html +1 -1
- khoj/interface/compiled/_next/static/chunks/1603-2418b11d8e8dacb9.js +1 -0
- khoj/interface/compiled/_next/static/chunks/1970-c78f6acc8e16e30b.js +1 -0
- khoj/interface/compiled/_next/static/chunks/3124-a4cea2eda163128d.js +1 -0
- khoj/interface/compiled/_next/static/chunks/5538-5c4f2271e9377b74.js +1 -0
- khoj/interface/compiled/_next/static/chunks/8423-db6dad6d44869097.js +1 -0
- khoj/interface/compiled/_next/static/chunks/9417-7a8a6da918d37750.js +1 -0
- khoj/interface/compiled/_next/static/chunks/app/agents/{page-36da67f03a173e52.js → page-4353b1a532795ad1.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/app/automations/{page-774ae3e033f938cd.js → page-c9f13c865e739607.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/app/chat/page-97876b3bd3c5e69d.js +1 -0
- khoj/interface/compiled/_next/static/chunks/app/{page-322c37514a3a613a.js → page-c33ebe19a3b7b0b2.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/app/search/{page-9b64f61caa5bd7f9.js → page-8e28deacb61f75aa.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/app/settings/page-2fab613a557d3cc5.js +1 -0
- khoj/interface/compiled/_next/static/chunks/app/share/chat/page-3ee3da7e8dfe3572.js +1 -0
- khoj/interface/compiled/_next/static/chunks/{webpack-c9799fdebf88abb6.js → webpack-ff5eae43b8dba1d2.js} +1 -1
- khoj/interface/compiled/_next/static/css/23f801d22927d568.css +1 -0
- khoj/interface/compiled/_next/static/css/592ca99f5122e75a.css +1 -0
- khoj/interface/compiled/_next/static/css/af0f36f71f368260.css +25 -0
- khoj/interface/compiled/agents/index.html +1 -1
- khoj/interface/compiled/agents/index.txt +2 -2
- khoj/interface/compiled/automations/index.html +1 -1
- khoj/interface/compiled/automations/index.txt +2 -2
- 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 +3 -3
- 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 +2 -2
- khoj/interface/compiled/share/chat/index.html +1 -1
- khoj/interface/compiled/share/chat/index.txt +3 -3
- khoj/processor/content/docx/docx_to_entries.py +27 -21
- khoj/processor/content/github/github_to_entries.py +2 -2
- khoj/processor/content/images/image_to_entries.py +2 -2
- khoj/processor/content/markdown/markdown_to_entries.py +2 -2
- khoj/processor/content/notion/notion_to_entries.py +2 -2
- khoj/processor/content/org_mode/org_to_entries.py +2 -2
- khoj/processor/content/pdf/pdf_to_entries.py +37 -29
- khoj/processor/content/plaintext/plaintext_to_entries.py +2 -2
- khoj/processor/content/text_to_entries.py +2 -2
- khoj/processor/conversation/anthropic/anthropic_chat.py +7 -1
- khoj/processor/conversation/google/gemini_chat.py +15 -2
- khoj/processor/conversation/offline/chat_model.py +4 -0
- khoj/processor/conversation/openai/gpt.py +6 -1
- khoj/processor/conversation/prompts.py +48 -4
- khoj/processor/conversation/utils.py +69 -11
- khoj/processor/image/generate.py +2 -0
- khoj/processor/tools/online_search.py +19 -3
- khoj/processor/tools/run_code.py +4 -0
- khoj/routers/api.py +6 -1
- khoj/routers/api_agents.py +8 -10
- khoj/routers/api_chat.py +64 -13
- khoj/routers/api_content.py +80 -8
- khoj/routers/helpers.py +105 -34
- khoj/routers/notion.py +1 -1
- khoj/routers/research.py +9 -2
- khoj/search_type/text_search.py +1 -1
- khoj/utils/fs_syncer.py +2 -1
- khoj/utils/rawconfig.py +32 -0
- {khoj-1.28.4.dev23.dist-info → khoj-1.28.4.dev77.dist-info}/METADATA +1 -1
- {khoj-1.28.4.dev23.dist-info → khoj-1.28.4.dev77.dist-info}/RECORD +70 -70
- khoj/interface/compiled/_next/static/chunks/1603-c1568f45947e9f2c.js +0 -1
- khoj/interface/compiled/_next/static/chunks/1970-d44050bf658ae5cc.js +0 -1
- khoj/interface/compiled/_next/static/chunks/5538-bf582517a8dd3faa.js +0 -1
- khoj/interface/compiled/_next/static/chunks/8423-a1f432e4a8d9a6b0.js +0 -1
- khoj/interface/compiled/_next/static/chunks/8840-b8d7b9f0923c6651.js +0 -1
- khoj/interface/compiled/_next/static/chunks/9417-0d0fc7eb49a86abb.js +0 -1
- khoj/interface/compiled/_next/static/chunks/app/chat/page-a369e2bda9897794.js +0 -1
- khoj/interface/compiled/_next/static/chunks/app/settings/page-10b288c103f19468.js +0 -1
- khoj/interface/compiled/_next/static/chunks/app/share/chat/page-959d5f097cf38c93.js +0 -1
- khoj/interface/compiled/_next/static/css/4cae6c0e5c72fb2d.css +0 -1
- khoj/interface/compiled/_next/static/css/9d45de78fba367c1.css +0 -1
- khoj/interface/compiled/_next/static/css/d2bc549245313f26.css +0 -25
- /khoj/interface/compiled/_next/static/{s_mKS5kELaw2v4a7_yWNP → sE94pAZEifEKkz4WQtTNW}/_buildManifest.js +0 -0
- /khoj/interface/compiled/_next/static/{s_mKS5kELaw2v4a7_yWNP → sE94pAZEifEKkz4WQtTNW}/_ssgManifest.js +0 -0
- {khoj-1.28.4.dev23.dist-info → khoj-1.28.4.dev77.dist-info}/WHEEL +0 -0
- {khoj-1.28.4.dev23.dist-info → khoj-1.28.4.dev77.dist-info}/entry_points.txt +0 -0
- {khoj-1.28.4.dev23.dist-info → khoj-1.28.4.dev77.dist-info}/licenses/LICENSE +0 -0
khoj/routers/helpers.py
CHANGED
@@ -105,6 +105,7 @@ from khoj.utils.config import OfflineChatProcessorModel
|
|
105
105
|
from khoj.utils.helpers import (
|
106
106
|
LRU,
|
107
107
|
ConversationCommand,
|
108
|
+
get_file_type,
|
108
109
|
is_none_or_empty,
|
109
110
|
is_valid_url,
|
110
111
|
log_telemetry,
|
@@ -112,7 +113,7 @@ from khoj.utils.helpers import (
|
|
112
113
|
timer,
|
113
114
|
tool_descriptions_for_llm,
|
114
115
|
)
|
115
|
-
from khoj.utils.rawconfig import LocationData
|
116
|
+
from khoj.utils.rawconfig import ChatRequestBody, FileAttachment, FileData, LocationData
|
116
117
|
|
117
118
|
logger = logging.getLogger(__name__)
|
118
119
|
|
@@ -168,6 +169,12 @@ async def is_ready_to_chat(user: KhojUser):
|
|
168
169
|
raise HTTPException(status_code=500, detail="Set your OpenAI API key or enable Local LLM via Khoj settings.")
|
169
170
|
|
170
171
|
|
172
|
+
def get_file_content(file: UploadFile):
|
173
|
+
file_content = file.file.read()
|
174
|
+
file_type, encoding = get_file_type(file.content_type, file_content)
|
175
|
+
return FileData(name=file.filename, content=file_content, file_type=file_type, encoding=encoding)
|
176
|
+
|
177
|
+
|
171
178
|
def update_telemetry_state(
|
172
179
|
request: Request,
|
173
180
|
telemetry_type: str,
|
@@ -249,6 +256,39 @@ async def agenerate_chat_response(*args):
|
|
249
256
|
return await loop.run_in_executor(executor, generate_chat_response, *args)
|
250
257
|
|
251
258
|
|
259
|
+
def gather_raw_query_files(
|
260
|
+
query_files: Dict[str, str],
|
261
|
+
):
|
262
|
+
"""
|
263
|
+
Gather contextual data from the given (raw) files
|
264
|
+
"""
|
265
|
+
|
266
|
+
if len(query_files) == 0:
|
267
|
+
return ""
|
268
|
+
|
269
|
+
contextual_data = " ".join(
|
270
|
+
[f"File: {file_name}\n\n{file_content}\n\n" for file_name, file_content in query_files.items()]
|
271
|
+
)
|
272
|
+
return f"I have attached the following files:\n\n{contextual_data}"
|
273
|
+
|
274
|
+
|
275
|
+
async def acreate_title_from_history(
|
276
|
+
user: KhojUser,
|
277
|
+
conversation: Conversation,
|
278
|
+
):
|
279
|
+
"""
|
280
|
+
Create a title from the given conversation history
|
281
|
+
"""
|
282
|
+
chat_history = construct_chat_history(conversation.conversation_log)
|
283
|
+
|
284
|
+
title_generation_prompt = prompts.conversation_title_generation.format(chat_history=chat_history)
|
285
|
+
|
286
|
+
with timer("Chat actor: Generate title from conversation history", logger):
|
287
|
+
response = await send_message_to_model_wrapper(title_generation_prompt, user=user)
|
288
|
+
|
289
|
+
return response.strip()
|
290
|
+
|
291
|
+
|
252
292
|
async def acreate_title_from_query(query: str, user: KhojUser = None) -> str:
|
253
293
|
"""
|
254
294
|
Create a title from the given query
|
@@ -261,11 +301,15 @@ async def acreate_title_from_query(query: str, user: KhojUser = None) -> str:
|
|
261
301
|
return response.strip()
|
262
302
|
|
263
303
|
|
264
|
-
async def acheck_if_safe_prompt(system_prompt: str, user: KhojUser = None) -> Tuple[bool, str]:
|
304
|
+
async def acheck_if_safe_prompt(system_prompt: str, user: KhojUser = None, lax: bool = False) -> Tuple[bool, str]:
|
265
305
|
"""
|
266
306
|
Check if the system prompt is safe to use
|
267
307
|
"""
|
268
|
-
safe_prompt_check =
|
308
|
+
safe_prompt_check = (
|
309
|
+
prompts.personality_prompt_safety_expert.format(prompt=system_prompt)
|
310
|
+
if not lax
|
311
|
+
else prompts.personality_prompt_safety_expert_lax.format(prompt=system_prompt)
|
312
|
+
)
|
269
313
|
is_safe = True
|
270
314
|
reason = ""
|
271
315
|
|
@@ -294,6 +338,7 @@ async def aget_relevant_information_sources(
|
|
294
338
|
user: KhojUser,
|
295
339
|
query_images: List[str] = None,
|
296
340
|
agent: Agent = None,
|
341
|
+
query_files: str = None,
|
297
342
|
tracer: dict = {},
|
298
343
|
):
|
299
344
|
"""
|
@@ -331,6 +376,7 @@ async def aget_relevant_information_sources(
|
|
331
376
|
relevant_tools_prompt,
|
332
377
|
response_type="json_object",
|
333
378
|
user=user,
|
379
|
+
query_files=query_files,
|
334
380
|
tracer=tracer,
|
335
381
|
)
|
336
382
|
|
@@ -440,6 +486,7 @@ async def infer_webpage_urls(
|
|
440
486
|
user: KhojUser,
|
441
487
|
query_images: List[str] = None,
|
442
488
|
agent: Agent = None,
|
489
|
+
query_files: str = None,
|
443
490
|
tracer: dict = {},
|
444
491
|
) -> List[str]:
|
445
492
|
"""
|
@@ -469,6 +516,7 @@ async def infer_webpage_urls(
|
|
469
516
|
query_images=query_images,
|
470
517
|
response_type="json_object",
|
471
518
|
user=user,
|
519
|
+
query_files=query_files,
|
472
520
|
tracer=tracer,
|
473
521
|
)
|
474
522
|
|
@@ -494,6 +542,7 @@ async def generate_online_subqueries(
|
|
494
542
|
user: KhojUser,
|
495
543
|
query_images: List[str] = None,
|
496
544
|
agent: Agent = None,
|
545
|
+
query_files: str = None,
|
497
546
|
tracer: dict = {},
|
498
547
|
) -> Set[str]:
|
499
548
|
"""
|
@@ -523,6 +572,7 @@ async def generate_online_subqueries(
|
|
523
572
|
query_images=query_images,
|
524
573
|
response_type="json_object",
|
525
574
|
user=user,
|
575
|
+
query_files=query_files,
|
526
576
|
tracer=tracer,
|
527
577
|
)
|
528
578
|
|
@@ -645,26 +695,38 @@ async def generate_summary_from_files(
|
|
645
695
|
query_images: List[str] = None,
|
646
696
|
agent: Agent = None,
|
647
697
|
send_status_func: Optional[Callable] = None,
|
698
|
+
query_files: str = None,
|
648
699
|
tracer: dict = {},
|
649
700
|
):
|
650
701
|
try:
|
651
|
-
|
702
|
+
file_objects = None
|
652
703
|
if await EntryAdapters.aagent_has_entries(agent):
|
653
704
|
file_names = await EntryAdapters.aget_agent_entry_filepaths(agent)
|
654
705
|
if len(file_names) > 0:
|
655
|
-
|
656
|
-
|
657
|
-
if len(file_filters) > 0:
|
658
|
-
file_object = await FileObjectAdapters.async_get_file_objects_by_name(user, file_filters[0])
|
706
|
+
file_objects = await FileObjectAdapters.aget_file_objects_by_name(None, file_names.pop(), agent)
|
659
707
|
|
660
|
-
if len(
|
661
|
-
response_log = "Sorry, I couldn't find
|
708
|
+
if (file_objects and len(file_objects) == 0 and not query_files) or (not file_objects and not query_files):
|
709
|
+
response_log = "Sorry, I couldn't find anything to summarize."
|
662
710
|
yield response_log
|
663
711
|
return
|
664
|
-
|
712
|
+
|
713
|
+
contextual_data = " ".join([f"File: {file.file_name}\n\n{file.raw_text}" for file in file_objects])
|
714
|
+
|
715
|
+
if query_files:
|
716
|
+
contextual_data += f"\n\n{query_files}"
|
717
|
+
|
665
718
|
if not q:
|
666
719
|
q = "Create a general summary of the file"
|
667
|
-
|
720
|
+
|
721
|
+
file_names = [file.file_name for file in file_objects]
|
722
|
+
file_names.extend(file_filters)
|
723
|
+
|
724
|
+
all_file_names = ""
|
725
|
+
|
726
|
+
for file_name in file_names:
|
727
|
+
all_file_names += f"- {file_name}\n"
|
728
|
+
|
729
|
+
async for result in send_status_func(f"**Constructing Summary Using:**\n{all_file_names}"):
|
668
730
|
yield {ChatEvent.STATUS: result}
|
669
731
|
|
670
732
|
response = await extract_relevant_summary(
|
@@ -694,6 +756,7 @@ async def generate_excalidraw_diagram(
|
|
694
756
|
user: KhojUser = None,
|
695
757
|
agent: Agent = None,
|
696
758
|
send_status_func: Optional[Callable] = None,
|
759
|
+
query_files: str = None,
|
697
760
|
tracer: dict = {},
|
698
761
|
):
|
699
762
|
if send_status_func:
|
@@ -709,6 +772,7 @@ async def generate_excalidraw_diagram(
|
|
709
772
|
query_images=query_images,
|
710
773
|
user=user,
|
711
774
|
agent=agent,
|
775
|
+
query_files=query_files,
|
712
776
|
tracer=tracer,
|
713
777
|
)
|
714
778
|
|
@@ -735,6 +799,7 @@ async def generate_better_diagram_description(
|
|
735
799
|
query_images: List[str] = None,
|
736
800
|
user: KhojUser = None,
|
737
801
|
agent: Agent = None,
|
802
|
+
query_files: str = None,
|
738
803
|
tracer: dict = {},
|
739
804
|
) -> str:
|
740
805
|
"""
|
@@ -773,7 +838,11 @@ async def generate_better_diagram_description(
|
|
773
838
|
|
774
839
|
with timer("Chat actor: Generate better diagram description", logger):
|
775
840
|
response = await send_message_to_model_wrapper(
|
776
|
-
improve_diagram_description_prompt,
|
841
|
+
improve_diagram_description_prompt,
|
842
|
+
query_images=query_images,
|
843
|
+
user=user,
|
844
|
+
query_files=query_files,
|
845
|
+
tracer=tracer,
|
777
846
|
)
|
778
847
|
response = response.strip()
|
779
848
|
if response.startswith(('"', "'")) and response.endswith(('"', "'")):
|
@@ -820,6 +889,7 @@ async def generate_better_image_prompt(
|
|
820
889
|
query_images: Optional[List[str]] = None,
|
821
890
|
user: KhojUser = None,
|
822
891
|
agent: Agent = None,
|
892
|
+
query_files: str = "",
|
823
893
|
tracer: dict = {},
|
824
894
|
) -> str:
|
825
895
|
"""
|
@@ -868,7 +938,7 @@ async def generate_better_image_prompt(
|
|
868
938
|
|
869
939
|
with timer("Chat actor: Generate contextual image prompt", logger):
|
870
940
|
response = await send_message_to_model_wrapper(
|
871
|
-
image_prompt, query_images=query_images, user=user, tracer=tracer
|
941
|
+
image_prompt, query_images=query_images, user=user, query_files=query_files, tracer=tracer
|
872
942
|
)
|
873
943
|
response = response.strip()
|
874
944
|
if response.startswith(('"', "'")) and response.endswith(('"', "'")):
|
@@ -884,6 +954,7 @@ async def send_message_to_model_wrapper(
|
|
884
954
|
user: KhojUser = None,
|
885
955
|
query_images: List[str] = None,
|
886
956
|
context: str = "",
|
957
|
+
query_files: str = None,
|
887
958
|
tracer: dict = {},
|
888
959
|
):
|
889
960
|
conversation_config: ChatModelOptions = await ConversationAdapters.aget_default_conversation_config(user)
|
@@ -923,6 +994,7 @@ async def send_message_to_model_wrapper(
|
|
923
994
|
max_prompt_size=max_tokens,
|
924
995
|
vision_enabled=vision_available,
|
925
996
|
model_type=conversation_config.model_type,
|
997
|
+
query_files=query_files,
|
926
998
|
)
|
927
999
|
|
928
1000
|
return send_message_to_model_offline(
|
@@ -949,6 +1021,7 @@ async def send_message_to_model_wrapper(
|
|
949
1021
|
vision_enabled=vision_available,
|
950
1022
|
query_images=query_images,
|
951
1023
|
model_type=conversation_config.model_type,
|
1024
|
+
query_files=query_files,
|
952
1025
|
)
|
953
1026
|
|
954
1027
|
return send_message_to_model(
|
@@ -971,6 +1044,7 @@ async def send_message_to_model_wrapper(
|
|
971
1044
|
vision_enabled=vision_available,
|
972
1045
|
query_images=query_images,
|
973
1046
|
model_type=conversation_config.model_type,
|
1047
|
+
query_files=query_files,
|
974
1048
|
)
|
975
1049
|
|
976
1050
|
return anthropic_send_message_to_model(
|
@@ -992,6 +1066,7 @@ async def send_message_to_model_wrapper(
|
|
992
1066
|
vision_enabled=vision_available,
|
993
1067
|
query_images=query_images,
|
994
1068
|
model_type=conversation_config.model_type,
|
1069
|
+
query_files=query_files,
|
995
1070
|
)
|
996
1071
|
|
997
1072
|
return gemini_send_message_to_model(
|
@@ -1006,6 +1081,7 @@ def send_message_to_model_wrapper_sync(
|
|
1006
1081
|
system_message: str = "",
|
1007
1082
|
response_type: str = "text",
|
1008
1083
|
user: KhojUser = None,
|
1084
|
+
query_files: str = "",
|
1009
1085
|
tracer: dict = {},
|
1010
1086
|
):
|
1011
1087
|
conversation_config: ChatModelOptions = ConversationAdapters.get_default_conversation_config(user)
|
@@ -1030,6 +1106,7 @@ def send_message_to_model_wrapper_sync(
|
|
1030
1106
|
max_prompt_size=max_tokens,
|
1031
1107
|
vision_enabled=vision_available,
|
1032
1108
|
model_type=conversation_config.model_type,
|
1109
|
+
query_files=query_files,
|
1033
1110
|
)
|
1034
1111
|
|
1035
1112
|
return send_message_to_model_offline(
|
@@ -1051,6 +1128,7 @@ def send_message_to_model_wrapper_sync(
|
|
1051
1128
|
max_prompt_size=max_tokens,
|
1052
1129
|
vision_enabled=vision_available,
|
1053
1130
|
model_type=conversation_config.model_type,
|
1131
|
+
query_files=query_files,
|
1054
1132
|
)
|
1055
1133
|
|
1056
1134
|
openai_response = send_message_to_model(
|
@@ -1072,6 +1150,7 @@ def send_message_to_model_wrapper_sync(
|
|
1072
1150
|
max_prompt_size=max_tokens,
|
1073
1151
|
vision_enabled=vision_available,
|
1074
1152
|
model_type=conversation_config.model_type,
|
1153
|
+
query_files=query_files,
|
1075
1154
|
)
|
1076
1155
|
|
1077
1156
|
return anthropic_send_message_to_model(
|
@@ -1091,6 +1170,7 @@ def send_message_to_model_wrapper_sync(
|
|
1091
1170
|
max_prompt_size=max_tokens,
|
1092
1171
|
vision_enabled=vision_available,
|
1093
1172
|
model_type=conversation_config.model_type,
|
1173
|
+
query_files=query_files,
|
1094
1174
|
)
|
1095
1175
|
|
1096
1176
|
return gemini_send_message_to_model(
|
@@ -1120,8 +1200,10 @@ def generate_chat_response(
|
|
1120
1200
|
user_name: Optional[str] = None,
|
1121
1201
|
meta_research: str = "",
|
1122
1202
|
query_images: Optional[List[str]] = None,
|
1123
|
-
tracer: dict = {},
|
1124
1203
|
train_of_thought: List[Any] = [],
|
1204
|
+
query_files: str = None,
|
1205
|
+
raw_query_files: List[FileAttachment] = None,
|
1206
|
+
tracer: dict = {},
|
1125
1207
|
) -> Tuple[Union[ThreadedGenerator, Iterator[str]], Dict[str, str]]:
|
1126
1208
|
# Initialize Variables
|
1127
1209
|
chat_response = None
|
@@ -1142,8 +1224,9 @@ def generate_chat_response(
|
|
1142
1224
|
client_application=client_application,
|
1143
1225
|
conversation_id=conversation_id,
|
1144
1226
|
query_images=query_images,
|
1145
|
-
tracer=tracer,
|
1146
1227
|
train_of_thought=train_of_thought,
|
1228
|
+
raw_query_files=raw_query_files,
|
1229
|
+
tracer=tracer,
|
1147
1230
|
)
|
1148
1231
|
|
1149
1232
|
query_to_run = q
|
@@ -1177,6 +1260,7 @@ def generate_chat_response(
|
|
1177
1260
|
location_data=location_data,
|
1178
1261
|
user_name=user_name,
|
1179
1262
|
agent=agent,
|
1263
|
+
query_files=query_files,
|
1180
1264
|
tracer=tracer,
|
1181
1265
|
)
|
1182
1266
|
|
@@ -1202,6 +1286,7 @@ def generate_chat_response(
|
|
1202
1286
|
user_name=user_name,
|
1203
1287
|
agent=agent,
|
1204
1288
|
vision_available=vision_available,
|
1289
|
+
query_files=query_files,
|
1205
1290
|
tracer=tracer,
|
1206
1291
|
)
|
1207
1292
|
|
@@ -1224,6 +1309,7 @@ def generate_chat_response(
|
|
1224
1309
|
user_name=user_name,
|
1225
1310
|
agent=agent,
|
1226
1311
|
vision_available=vision_available,
|
1312
|
+
query_files=query_files,
|
1227
1313
|
tracer=tracer,
|
1228
1314
|
)
|
1229
1315
|
elif conversation_config.model_type == ChatModelOptions.ModelType.GOOGLE:
|
@@ -1243,7 +1329,9 @@ def generate_chat_response(
|
|
1243
1329
|
location_data=location_data,
|
1244
1330
|
user_name=user_name,
|
1245
1331
|
agent=agent,
|
1332
|
+
query_images=query_images,
|
1246
1333
|
vision_available=vision_available,
|
1334
|
+
query_files=query_files,
|
1247
1335
|
tracer=tracer,
|
1248
1336
|
)
|
1249
1337
|
|
@@ -1256,23 +1344,6 @@ def generate_chat_response(
|
|
1256
1344
|
return chat_response, metadata
|
1257
1345
|
|
1258
1346
|
|
1259
|
-
class ChatRequestBody(BaseModel):
|
1260
|
-
q: str
|
1261
|
-
n: Optional[int] = 7
|
1262
|
-
d: Optional[float] = None
|
1263
|
-
stream: Optional[bool] = False
|
1264
|
-
title: Optional[str] = None
|
1265
|
-
conversation_id: Optional[str] = None
|
1266
|
-
turn_id: Optional[str] = None
|
1267
|
-
city: Optional[str] = None
|
1268
|
-
region: Optional[str] = None
|
1269
|
-
country: Optional[str] = None
|
1270
|
-
country_code: Optional[str] = None
|
1271
|
-
timezone: Optional[str] = None
|
1272
|
-
images: Optional[list[str]] = None
|
1273
|
-
create_new: Optional[bool] = False
|
1274
|
-
|
1275
|
-
|
1276
1347
|
class DeleteMessageRequestBody(BaseModel):
|
1277
1348
|
conversation_id: str
|
1278
1349
|
turn_id: str
|
@@ -1904,10 +1975,10 @@ def get_user_config(user: KhojUser, request: Request, is_detailed: bool = False)
|
|
1904
1975
|
|
1905
1976
|
|
1906
1977
|
def configure_content(
|
1978
|
+
user: KhojUser,
|
1907
1979
|
files: Optional[dict[str, dict[str, str]]],
|
1908
1980
|
regenerate: bool = False,
|
1909
1981
|
t: Optional[state.SearchType] = state.SearchType.All,
|
1910
|
-
user: KhojUser = None,
|
1911
1982
|
) -> bool:
|
1912
1983
|
success = True
|
1913
1984
|
if t == None:
|
khoj/routers/notion.py
CHANGED
@@ -80,6 +80,6 @@ async def notion_auth_callback(request: Request, background_tasks: BackgroundTas
|
|
80
80
|
notion_redirect = str(request.app.url_path_for("config_page"))
|
81
81
|
|
82
82
|
# Trigger an async job to configure_content. Let it run without blocking the response.
|
83
|
-
background_tasks.add_task(run_in_executor, configure_content, {}, False, SearchType.Notion
|
83
|
+
background_tasks.add_task(run_in_executor, configure_content, user, {}, False, SearchType.Notion)
|
84
84
|
|
85
85
|
return RedirectResponse(notion_redirect)
|
khoj/routers/research.py
CHANGED
@@ -11,6 +11,7 @@ from khoj.processor.conversation import prompts
|
|
11
11
|
from khoj.processor.conversation.utils import (
|
12
12
|
InformationCollectionIteration,
|
13
13
|
clean_json,
|
14
|
+
construct_chat_history,
|
14
15
|
construct_iteration_history,
|
15
16
|
construct_tool_chat_history,
|
16
17
|
)
|
@@ -19,8 +20,6 @@ from khoj.processor.tools.run_code import run_code
|
|
19
20
|
from khoj.routers.api import extract_references_and_questions
|
20
21
|
from khoj.routers.helpers import (
|
21
22
|
ChatEvent,
|
22
|
-
construct_chat_history,
|
23
|
-
extract_relevant_info,
|
24
23
|
generate_summary_from_files,
|
25
24
|
send_message_to_model_wrapper,
|
26
25
|
)
|
@@ -47,6 +46,7 @@ async def apick_next_tool(
|
|
47
46
|
max_iterations: int = 5,
|
48
47
|
send_status_func: Optional[Callable] = None,
|
49
48
|
tracer: dict = {},
|
49
|
+
query_files: str = None,
|
50
50
|
):
|
51
51
|
"""Given a query, determine which of the available tools the agent should use in order to answer appropriately."""
|
52
52
|
|
@@ -92,6 +92,7 @@ async def apick_next_tool(
|
|
92
92
|
response_type="json_object",
|
93
93
|
user=user,
|
94
94
|
query_images=query_images,
|
95
|
+
query_files=query_files,
|
95
96
|
tracer=tracer,
|
96
97
|
)
|
97
98
|
except Exception as e:
|
@@ -151,6 +152,7 @@ async def execute_information_collection(
|
|
151
152
|
location: LocationData = None,
|
152
153
|
file_filters: List[str] = [],
|
153
154
|
tracer: dict = {},
|
155
|
+
query_files: str = None,
|
154
156
|
):
|
155
157
|
current_iteration = 0
|
156
158
|
MAX_ITERATIONS = 5
|
@@ -174,6 +176,7 @@ async def execute_information_collection(
|
|
174
176
|
MAX_ITERATIONS,
|
175
177
|
send_status_func,
|
176
178
|
tracer=tracer,
|
179
|
+
query_files=query_files,
|
177
180
|
):
|
178
181
|
if isinstance(result, dict) and ChatEvent.STATUS in result:
|
179
182
|
yield result[ChatEvent.STATUS]
|
@@ -204,6 +207,7 @@ async def execute_information_collection(
|
|
204
207
|
previous_inferred_queries=previous_inferred_queries,
|
205
208
|
agent=agent,
|
206
209
|
tracer=tracer,
|
210
|
+
query_files=query_files,
|
207
211
|
):
|
208
212
|
if isinstance(result, dict) and ChatEvent.STATUS in result:
|
209
213
|
yield result[ChatEvent.STATUS]
|
@@ -265,6 +269,7 @@ async def execute_information_collection(
|
|
265
269
|
query_images=query_images,
|
266
270
|
agent=agent,
|
267
271
|
tracer=tracer,
|
272
|
+
query_files=query_files,
|
268
273
|
):
|
269
274
|
if isinstance(result, dict) and ChatEvent.STATUS in result:
|
270
275
|
yield result[ChatEvent.STATUS]
|
@@ -295,6 +300,7 @@ async def execute_information_collection(
|
|
295
300
|
send_status_func,
|
296
301
|
query_images=query_images,
|
297
302
|
agent=agent,
|
303
|
+
query_files=query_files,
|
298
304
|
tracer=tracer,
|
299
305
|
):
|
300
306
|
if isinstance(result, dict) and ChatEvent.STATUS in result:
|
@@ -320,6 +326,7 @@ async def execute_information_collection(
|
|
320
326
|
query_images=query_images,
|
321
327
|
agent=agent,
|
322
328
|
send_status_func=send_status_func,
|
329
|
+
query_files=query_files,
|
323
330
|
):
|
324
331
|
if isinstance(result, dict) and ChatEvent.STATUS in result:
|
325
332
|
yield result[ChatEvent.STATUS]
|
khoj/search_type/text_search.py
CHANGED
khoj/utils/fs_syncer.py
CHANGED
@@ -8,6 +8,7 @@ from bs4 import BeautifulSoup
|
|
8
8
|
from magika import Magika
|
9
9
|
|
10
10
|
from khoj.database.models import (
|
11
|
+
KhojUser,
|
11
12
|
LocalMarkdownConfig,
|
12
13
|
LocalOrgConfig,
|
13
14
|
LocalPdfConfig,
|
@@ -21,7 +22,7 @@ logger = logging.getLogger(__name__)
|
|
21
22
|
magika = Magika()
|
22
23
|
|
23
24
|
|
24
|
-
def collect_files(search_type: Optional[SearchType] = SearchType.All
|
25
|
+
def collect_files(user: KhojUser, search_type: Optional[SearchType] = SearchType.All) -> dict:
|
25
26
|
files: dict[str, dict] = {"docx": {}, "image": {}}
|
26
27
|
|
27
28
|
if search_type == SearchType.All or search_type == SearchType.Org:
|
khoj/utils/rawconfig.py
CHANGED
@@ -138,6 +138,38 @@ class SearchResponse(ConfigBase):
|
|
138
138
|
corpus_id: str
|
139
139
|
|
140
140
|
|
141
|
+
class FileData(BaseModel):
|
142
|
+
name: str
|
143
|
+
content: bytes
|
144
|
+
file_type: str
|
145
|
+
encoding: str | None = None
|
146
|
+
|
147
|
+
|
148
|
+
class FileAttachment(BaseModel):
|
149
|
+
name: str
|
150
|
+
content: str
|
151
|
+
file_type: str
|
152
|
+
size: int
|
153
|
+
|
154
|
+
|
155
|
+
class ChatRequestBody(BaseModel):
|
156
|
+
q: str
|
157
|
+
n: Optional[int] = 7
|
158
|
+
d: Optional[float] = None
|
159
|
+
stream: Optional[bool] = False
|
160
|
+
title: Optional[str] = None
|
161
|
+
conversation_id: Optional[str] = None
|
162
|
+
turn_id: Optional[str] = None
|
163
|
+
city: Optional[str] = None
|
164
|
+
region: Optional[str] = None
|
165
|
+
country: Optional[str] = None
|
166
|
+
country_code: Optional[str] = None
|
167
|
+
timezone: Optional[str] = None
|
168
|
+
images: Optional[list[str]] = None
|
169
|
+
files: Optional[list[FileAttachment]] = []
|
170
|
+
create_new: Optional[bool] = False
|
171
|
+
|
172
|
+
|
141
173
|
class Entry:
|
142
174
|
raw: str
|
143
175
|
compiled: str
|