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.
Files changed (82) hide show
  1. khoj/configure.py +4 -6
  2. khoj/database/adapters/__init__.py +124 -34
  3. khoj/database/models/__init__.py +4 -0
  4. khoj/interface/compiled/404/index.html +1 -1
  5. khoj/interface/compiled/_next/static/chunks/1603-2418b11d8e8dacb9.js +1 -0
  6. khoj/interface/compiled/_next/static/chunks/1970-c78f6acc8e16e30b.js +1 -0
  7. khoj/interface/compiled/_next/static/chunks/3124-a4cea2eda163128d.js +1 -0
  8. khoj/interface/compiled/_next/static/chunks/5538-5c4f2271e9377b74.js +1 -0
  9. khoj/interface/compiled/_next/static/chunks/8423-db6dad6d44869097.js +1 -0
  10. khoj/interface/compiled/_next/static/chunks/9417-7a8a6da918d37750.js +1 -0
  11. khoj/interface/compiled/_next/static/chunks/app/agents/{page-36da67f03a173e52.js → page-4353b1a532795ad1.js} +1 -1
  12. khoj/interface/compiled/_next/static/chunks/app/automations/{page-774ae3e033f938cd.js → page-c9f13c865e739607.js} +1 -1
  13. khoj/interface/compiled/_next/static/chunks/app/chat/page-97876b3bd3c5e69d.js +1 -0
  14. khoj/interface/compiled/_next/static/chunks/app/{page-322c37514a3a613a.js → page-c33ebe19a3b7b0b2.js} +1 -1
  15. khoj/interface/compiled/_next/static/chunks/app/search/{page-9b64f61caa5bd7f9.js → page-8e28deacb61f75aa.js} +1 -1
  16. khoj/interface/compiled/_next/static/chunks/app/settings/page-2fab613a557d3cc5.js +1 -0
  17. khoj/interface/compiled/_next/static/chunks/app/share/chat/page-3ee3da7e8dfe3572.js +1 -0
  18. khoj/interface/compiled/_next/static/chunks/{webpack-c9799fdebf88abb6.js → webpack-ff5eae43b8dba1d2.js} +1 -1
  19. khoj/interface/compiled/_next/static/css/23f801d22927d568.css +1 -0
  20. khoj/interface/compiled/_next/static/css/592ca99f5122e75a.css +1 -0
  21. khoj/interface/compiled/_next/static/css/af0f36f71f368260.css +25 -0
  22. khoj/interface/compiled/agents/index.html +1 -1
  23. khoj/interface/compiled/agents/index.txt +2 -2
  24. khoj/interface/compiled/automations/index.html +1 -1
  25. khoj/interface/compiled/automations/index.txt +2 -2
  26. khoj/interface/compiled/chat/index.html +1 -1
  27. khoj/interface/compiled/chat/index.txt +2 -2
  28. khoj/interface/compiled/index.html +1 -1
  29. khoj/interface/compiled/index.txt +3 -3
  30. khoj/interface/compiled/search/index.html +1 -1
  31. khoj/interface/compiled/search/index.txt +2 -2
  32. khoj/interface/compiled/settings/index.html +1 -1
  33. khoj/interface/compiled/settings/index.txt +2 -2
  34. khoj/interface/compiled/share/chat/index.html +1 -1
  35. khoj/interface/compiled/share/chat/index.txt +3 -3
  36. khoj/processor/content/docx/docx_to_entries.py +27 -21
  37. khoj/processor/content/github/github_to_entries.py +2 -2
  38. khoj/processor/content/images/image_to_entries.py +2 -2
  39. khoj/processor/content/markdown/markdown_to_entries.py +2 -2
  40. khoj/processor/content/notion/notion_to_entries.py +2 -2
  41. khoj/processor/content/org_mode/org_to_entries.py +2 -2
  42. khoj/processor/content/pdf/pdf_to_entries.py +37 -29
  43. khoj/processor/content/plaintext/plaintext_to_entries.py +2 -2
  44. khoj/processor/content/text_to_entries.py +2 -2
  45. khoj/processor/conversation/anthropic/anthropic_chat.py +7 -1
  46. khoj/processor/conversation/google/gemini_chat.py +15 -2
  47. khoj/processor/conversation/offline/chat_model.py +4 -0
  48. khoj/processor/conversation/openai/gpt.py +6 -1
  49. khoj/processor/conversation/prompts.py +48 -4
  50. khoj/processor/conversation/utils.py +69 -11
  51. khoj/processor/image/generate.py +2 -0
  52. khoj/processor/tools/online_search.py +19 -3
  53. khoj/processor/tools/run_code.py +4 -0
  54. khoj/routers/api.py +6 -1
  55. khoj/routers/api_agents.py +8 -10
  56. khoj/routers/api_chat.py +64 -13
  57. khoj/routers/api_content.py +80 -8
  58. khoj/routers/helpers.py +105 -34
  59. khoj/routers/notion.py +1 -1
  60. khoj/routers/research.py +9 -2
  61. khoj/search_type/text_search.py +1 -1
  62. khoj/utils/fs_syncer.py +2 -1
  63. khoj/utils/rawconfig.py +32 -0
  64. {khoj-1.28.4.dev23.dist-info → khoj-1.28.4.dev77.dist-info}/METADATA +1 -1
  65. {khoj-1.28.4.dev23.dist-info → khoj-1.28.4.dev77.dist-info}/RECORD +70 -70
  66. khoj/interface/compiled/_next/static/chunks/1603-c1568f45947e9f2c.js +0 -1
  67. khoj/interface/compiled/_next/static/chunks/1970-d44050bf658ae5cc.js +0 -1
  68. khoj/interface/compiled/_next/static/chunks/5538-bf582517a8dd3faa.js +0 -1
  69. khoj/interface/compiled/_next/static/chunks/8423-a1f432e4a8d9a6b0.js +0 -1
  70. khoj/interface/compiled/_next/static/chunks/8840-b8d7b9f0923c6651.js +0 -1
  71. khoj/interface/compiled/_next/static/chunks/9417-0d0fc7eb49a86abb.js +0 -1
  72. khoj/interface/compiled/_next/static/chunks/app/chat/page-a369e2bda9897794.js +0 -1
  73. khoj/interface/compiled/_next/static/chunks/app/settings/page-10b288c103f19468.js +0 -1
  74. khoj/interface/compiled/_next/static/chunks/app/share/chat/page-959d5f097cf38c93.js +0 -1
  75. khoj/interface/compiled/_next/static/css/4cae6c0e5c72fb2d.css +0 -1
  76. khoj/interface/compiled/_next/static/css/9d45de78fba367c1.css +0 -1
  77. khoj/interface/compiled/_next/static/css/d2bc549245313f26.css +0 -25
  78. /khoj/interface/compiled/_next/static/{s_mKS5kELaw2v4a7_yWNP → sE94pAZEifEKkz4WQtTNW}/_buildManifest.js +0 -0
  79. /khoj/interface/compiled/_next/static/{s_mKS5kELaw2v4a7_yWNP → sE94pAZEifEKkz4WQtTNW}/_ssgManifest.js +0 -0
  80. {khoj-1.28.4.dev23.dist-info → khoj-1.28.4.dev77.dist-info}/WHEEL +0 -0
  81. {khoj-1.28.4.dev23.dist-info → khoj-1.28.4.dev77.dist-info}/entry_points.txt +0 -0
  82. {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 = prompts.personality_prompt_safety_expert.format(prompt=system_prompt)
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
- file_object = None
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
- file_object = await FileObjectAdapters.async_get_file_objects_by_name(None, file_names.pop(), agent)
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(file_object) == 0:
661
- response_log = "Sorry, I couldn't find the full text of this file."
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
- contextual_data = " ".join([file.raw_text for file in file_object])
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
- async for result in send_status_func(f"**Constructing Summary Using:** {file_object[0].file_name}"):
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, query_images=query_images, user=user, tracer=tracer
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, user)
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]
@@ -208,7 +208,7 @@ def setup(
208
208
  text_to_entries: Type[TextToEntries],
209
209
  files: dict[str, str],
210
210
  regenerate: bool,
211
- user: KhojUser = None,
211
+ user: KhojUser,
212
212
  config=None,
213
213
  ) -> Tuple[int, int]:
214
214
  if config:
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, user=None) -> dict:
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: khoj
3
- Version: 1.28.4.dev23
3
+ Version: 1.28.4.dev77
4
4
  Summary: Your Second Brain
5
5
  Project-URL: Homepage, https://khoj.dev
6
6
  Project-URL: Documentation, https://docs.khoj.dev