khoj 1.25.1.dev1__py3-none-any.whl → 1.25.1.dev7__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 +13 -4
- khoj/database/adapters/__init__.py +51 -25
- khoj/interface/compiled/404/index.html +1 -1
- khoj/interface/compiled/agents/index.html +1 -1
- khoj/interface/compiled/agents/index.txt +1 -1
- khoj/interface/compiled/automations/index.html +1 -1
- khoj/interface/compiled/automations/index.txt +1 -1
- khoj/interface/compiled/chat/index.html +1 -1
- khoj/interface/compiled/chat/index.txt +1 -1
- khoj/interface/compiled/factchecker/index.html +1 -1
- khoj/interface/compiled/factchecker/index.txt +1 -1
- khoj/interface/compiled/index.html +1 -1
- khoj/interface/compiled/index.txt +1 -1
- khoj/interface/compiled/search/index.html +1 -1
- khoj/interface/compiled/search/index.txt +1 -1
- khoj/interface/compiled/settings/index.html +1 -1
- khoj/interface/compiled/settings/index.txt +1 -1
- khoj/interface/compiled/share/chat/index.html +1 -1
- khoj/interface/compiled/share/chat/index.txt +1 -1
- khoj/processor/image/generate.py +1 -2
- khoj/processor/tools/online_search.py +4 -4
- khoj/routers/api.py +1 -1
- khoj/routers/api_chat.py +8 -10
- khoj/routers/api_model.py +1 -1
- khoj/routers/auth.py +9 -1
- khoj/routers/helpers.py +47 -49
- khoj/routers/subscription.py +18 -4
- khoj/utils/initialization.py +0 -3
- {khoj-1.25.1.dev1.dist-info → khoj-1.25.1.dev7.dist-info}/METADATA +1 -1
- {khoj-1.25.1.dev1.dist-info → khoj-1.25.1.dev7.dist-info}/RECORD +35 -35
- /khoj/interface/compiled/_next/static/{NK3HVZEBC1y-DabLawiP7 → rc-OVbl4ikReNwbN-LLwA}/_buildManifest.js +0 -0
- /khoj/interface/compiled/_next/static/{NK3HVZEBC1y-DabLawiP7 → rc-OVbl4ikReNwbN-LLwA}/_ssgManifest.js +0 -0
- {khoj-1.25.1.dev1.dist-info → khoj-1.25.1.dev7.dist-info}/WHEEL +0 -0
- {khoj-1.25.1.dev1.dist-info → khoj-1.25.1.dev7.dist-info}/entry_points.txt +0 -0
- {khoj-1.25.1.dev1.dist-info → khoj-1.25.1.dev7.dist-info}/licenses/LICENSE +0 -0
khoj/routers/api.py
CHANGED
@@ -395,7 +395,7 @@ async def extract_references_and_questions(
|
|
395
395
|
# Infer search queries from user message
|
396
396
|
with timer("Extracting search queries took", logger):
|
397
397
|
# If we've reached here, either the user has enabled offline chat or the openai model is enabled.
|
398
|
-
conversation_config = await ConversationAdapters.aget_default_conversation_config()
|
398
|
+
conversation_config = await ConversationAdapters.aget_default_conversation_config(user)
|
399
399
|
vision_enabled = conversation_config.vision_enabled
|
400
400
|
|
401
401
|
if conversation_config.model_type == ChatModelOptions.ModelType.OFFLINE:
|
khoj/routers/api_chat.py
CHANGED
@@ -194,7 +194,7 @@ def chat_history(
|
|
194
194
|
n: Optional[int] = None,
|
195
195
|
):
|
196
196
|
user = request.user.object
|
197
|
-
validate_conversation_config()
|
197
|
+
validate_conversation_config(user)
|
198
198
|
|
199
199
|
# Load Conversation History
|
200
200
|
conversation = ConversationAdapters.get_conversation_by_user(
|
@@ -305,7 +305,7 @@ def get_shared_chat(
|
|
305
305
|
update_telemetry_state(
|
306
306
|
request=request,
|
307
307
|
telemetry_type="api",
|
308
|
-
api="
|
308
|
+
api="get_shared_chat_history",
|
309
309
|
**common.__dict__,
|
310
310
|
)
|
311
311
|
|
@@ -694,7 +694,7 @@ async def chat(
|
|
694
694
|
q,
|
695
695
|
meta_log,
|
696
696
|
is_automated_task,
|
697
|
-
|
697
|
+
user=user,
|
698
698
|
uploaded_image_url=uploaded_image_url,
|
699
699
|
agent=agent,
|
700
700
|
)
|
@@ -704,7 +704,7 @@ async def chat(
|
|
704
704
|
):
|
705
705
|
yield result
|
706
706
|
|
707
|
-
mode = await aget_relevant_output_modes(q, meta_log, is_automated_task, uploaded_image_url, agent)
|
707
|
+
mode = await aget_relevant_output_modes(q, meta_log, is_automated_task, user, uploaded_image_url, agent)
|
708
708
|
async for result in send_event(ChatEvent.STATUS, f"**Decided Response Mode:** {mode.value}"):
|
709
709
|
yield result
|
710
710
|
if mode not in conversation_commands:
|
@@ -767,8 +767,8 @@ async def chat(
|
|
767
767
|
q,
|
768
768
|
contextual_data,
|
769
769
|
conversation_history=meta_log,
|
770
|
-
subscribed=subscribed,
|
771
770
|
uploaded_image_url=uploaded_image_url,
|
771
|
+
user=user,
|
772
772
|
agent=agent,
|
773
773
|
)
|
774
774
|
response_log = str(response)
|
@@ -957,7 +957,6 @@ async def chat(
|
|
957
957
|
location_data=location,
|
958
958
|
references=compiled_references,
|
959
959
|
online_results=online_results,
|
960
|
-
subscribed=subscribed,
|
961
960
|
send_status_func=partial(send_event, ChatEvent.STATUS),
|
962
961
|
uploaded_image_url=uploaded_image_url,
|
963
962
|
agent=agent,
|
@@ -1192,7 +1191,7 @@ async def get_chat(
|
|
1192
1191
|
|
1193
1192
|
if conversation_commands == [ConversationCommand.Default] or is_automated_task:
|
1194
1193
|
conversation_commands = await aget_relevant_information_sources(
|
1195
|
-
q, meta_log, is_automated_task,
|
1194
|
+
q, meta_log, is_automated_task, user=user, uploaded_image_url=uploaded_image_url
|
1196
1195
|
)
|
1197
1196
|
conversation_commands_str = ", ".join([cmd.value for cmd in conversation_commands])
|
1198
1197
|
async for result in send_event(
|
@@ -1200,7 +1199,7 @@ async def get_chat(
|
|
1200
1199
|
):
|
1201
1200
|
yield result
|
1202
1201
|
|
1203
|
-
mode = await aget_relevant_output_modes(q, meta_log, is_automated_task, uploaded_image_url)
|
1202
|
+
mode = await aget_relevant_output_modes(q, meta_log, is_automated_task, user, uploaded_image_url)
|
1204
1203
|
async for result in send_event(ChatEvent.STATUS, f"**Decided Response Mode:** {mode.value}"):
|
1205
1204
|
yield result
|
1206
1205
|
if mode not in conversation_commands:
|
@@ -1252,7 +1251,7 @@ async def get_chat(
|
|
1252
1251
|
q,
|
1253
1252
|
contextual_data,
|
1254
1253
|
conversation_history=meta_log,
|
1255
|
-
|
1254
|
+
user=user,
|
1256
1255
|
uploaded_image_url=uploaded_image_url,
|
1257
1256
|
)
|
1258
1257
|
response_log = str(response)
|
@@ -1438,7 +1437,6 @@ async def get_chat(
|
|
1438
1437
|
location_data=location,
|
1439
1438
|
references=compiled_references,
|
1440
1439
|
online_results=online_results,
|
1441
|
-
subscribed=subscribed,
|
1442
1440
|
send_status_func=partial(send_event, ChatEvent.STATUS),
|
1443
1441
|
uploaded_image_url=uploaded_image_url,
|
1444
1442
|
):
|
khoj/routers/api_model.py
CHANGED
@@ -40,7 +40,7 @@ def get_user_chat_model(
|
|
40
40
|
chat_model = ConversationAdapters.get_conversation_config(user)
|
41
41
|
|
42
42
|
if chat_model is None:
|
43
|
-
chat_model = ConversationAdapters.get_default_conversation_config()
|
43
|
+
chat_model = ConversationAdapters.get_default_conversation_config(user)
|
44
44
|
|
45
45
|
return Response(status_code=200, content=json.dumps({"id": chat_model.id, "chat_model": chat_model.chat_model}))
|
46
46
|
|
khoj/routers/auth.py
CHANGED
@@ -80,11 +80,19 @@ async def login_magic_link(request: Request, form: MagicLinkForm):
|
|
80
80
|
request.session.pop("user", None)
|
81
81
|
|
82
82
|
email = form.email
|
83
|
-
user = await aget_or_create_user_by_email(email)
|
83
|
+
user, is_new = await aget_or_create_user_by_email(email)
|
84
84
|
unique_id = user.email_verification_code
|
85
85
|
|
86
86
|
if user:
|
87
87
|
await send_magic_link_email(email, unique_id, request.base_url)
|
88
|
+
if is_new:
|
89
|
+
update_telemetry_state(
|
90
|
+
request=request,
|
91
|
+
telemetry_type="api",
|
92
|
+
api="create_user",
|
93
|
+
metadata={"user_id": str(user.uuid)},
|
94
|
+
)
|
95
|
+
logger.log(logging.INFO, f"🥳 New User Created: {user.uuid}")
|
88
96
|
|
89
97
|
return Response(status_code=200)
|
90
98
|
|
khoj/routers/helpers.py
CHANGED
@@ -39,6 +39,7 @@ from khoj.database.adapters import (
|
|
39
39
|
AutomationAdapters,
|
40
40
|
ConversationAdapters,
|
41
41
|
EntryAdapters,
|
42
|
+
ais_user_subscribed,
|
42
43
|
create_khoj_token,
|
43
44
|
get_khoj_tokens,
|
44
45
|
get_user_name,
|
@@ -119,20 +120,20 @@ def is_query_empty(query: str) -> bool:
|
|
119
120
|
return is_none_or_empty(query.strip())
|
120
121
|
|
121
122
|
|
122
|
-
def validate_conversation_config():
|
123
|
-
default_config = ConversationAdapters.get_default_conversation_config()
|
123
|
+
def validate_conversation_config(user: KhojUser):
|
124
|
+
default_config = ConversationAdapters.get_default_conversation_config(user)
|
124
125
|
|
125
126
|
if default_config is None:
|
126
|
-
raise HTTPException(status_code=500, detail="Contact the server administrator to
|
127
|
+
raise HTTPException(status_code=500, detail="Contact the server administrator to add a chat model.")
|
127
128
|
|
128
129
|
if default_config.model_type == "openai" and not default_config.openai_config:
|
129
|
-
raise HTTPException(status_code=500, detail="Contact the server administrator to
|
130
|
+
raise HTTPException(status_code=500, detail="Contact the server administrator to add a chat model.")
|
130
131
|
|
131
132
|
|
132
133
|
async def is_ready_to_chat(user: KhojUser):
|
133
|
-
user_conversation_config =
|
134
|
-
|
135
|
-
|
134
|
+
user_conversation_config = await ConversationAdapters.aget_user_conversation_config(user)
|
135
|
+
if user_conversation_config == None:
|
136
|
+
user_conversation_config = await ConversationAdapters.aget_default_conversation_config()
|
136
137
|
|
137
138
|
if user_conversation_config and user_conversation_config.model_type == ChatModelOptions.ModelType.OFFLINE:
|
138
139
|
chat_model = user_conversation_config.chat_model
|
@@ -246,19 +247,19 @@ async def agenerate_chat_response(*args):
|
|
246
247
|
return await loop.run_in_executor(executor, generate_chat_response, *args)
|
247
248
|
|
248
249
|
|
249
|
-
async def acreate_title_from_query(query: str) -> str:
|
250
|
+
async def acreate_title_from_query(query: str, user: KhojUser = None) -> str:
|
250
251
|
"""
|
251
252
|
Create a title from the given query
|
252
253
|
"""
|
253
254
|
title_generation_prompt = prompts.subject_generation.format(query=query)
|
254
255
|
|
255
256
|
with timer("Chat actor: Generate title from query", logger):
|
256
|
-
response = await send_message_to_model_wrapper(title_generation_prompt)
|
257
|
+
response = await send_message_to_model_wrapper(title_generation_prompt, user=user)
|
257
258
|
|
258
259
|
return response.strip()
|
259
260
|
|
260
261
|
|
261
|
-
async def acheck_if_safe_prompt(system_prompt: str) -> Tuple[bool, str]:
|
262
|
+
async def acheck_if_safe_prompt(system_prompt: str, user: KhojUser = None) -> Tuple[bool, str]:
|
262
263
|
"""
|
263
264
|
Check if the system prompt is safe to use
|
264
265
|
"""
|
@@ -267,7 +268,7 @@ async def acheck_if_safe_prompt(system_prompt: str) -> Tuple[bool, str]:
|
|
267
268
|
reason = ""
|
268
269
|
|
269
270
|
with timer("Chat actor: Check if safe prompt", logger):
|
270
|
-
response = await send_message_to_model_wrapper(safe_prompt_check)
|
271
|
+
response = await send_message_to_model_wrapper(safe_prompt_check, user=user)
|
271
272
|
|
272
273
|
response = response.strip()
|
273
274
|
try:
|
@@ -288,7 +289,7 @@ async def aget_relevant_information_sources(
|
|
288
289
|
query: str,
|
289
290
|
conversation_history: dict,
|
290
291
|
is_task: bool,
|
291
|
-
|
292
|
+
user: KhojUser,
|
292
293
|
uploaded_image_url: str = None,
|
293
294
|
agent: Agent = None,
|
294
295
|
):
|
@@ -326,7 +327,7 @@ async def aget_relevant_information_sources(
|
|
326
327
|
response = await send_message_to_model_wrapper(
|
327
328
|
relevant_tools_prompt,
|
328
329
|
response_type="json_object",
|
329
|
-
|
330
|
+
user=user,
|
330
331
|
)
|
331
332
|
|
332
333
|
try:
|
@@ -362,7 +363,12 @@ async def aget_relevant_information_sources(
|
|
362
363
|
|
363
364
|
|
364
365
|
async def aget_relevant_output_modes(
|
365
|
-
query: str,
|
366
|
+
query: str,
|
367
|
+
conversation_history: dict,
|
368
|
+
is_task: bool = False,
|
369
|
+
user: KhojUser = None,
|
370
|
+
uploaded_image_url: str = None,
|
371
|
+
agent: Agent = None,
|
366
372
|
):
|
367
373
|
"""
|
368
374
|
Given a query, determine which of the available tools the agent should use in order to answer appropriately.
|
@@ -398,7 +404,7 @@ async def aget_relevant_output_modes(
|
|
398
404
|
)
|
399
405
|
|
400
406
|
with timer("Chat actor: Infer output mode for chat response", logger):
|
401
|
-
response = await send_message_to_model_wrapper(relevant_mode_prompt, response_type="json_object")
|
407
|
+
response = await send_message_to_model_wrapper(relevant_mode_prompt, response_type="json_object", user=user)
|
402
408
|
|
403
409
|
try:
|
404
410
|
response = response.strip()
|
@@ -453,7 +459,7 @@ async def infer_webpage_urls(
|
|
453
459
|
|
454
460
|
with timer("Chat actor: Infer webpage urls to read", logger):
|
455
461
|
response = await send_message_to_model_wrapper(
|
456
|
-
online_queries_prompt, uploaded_image_url=uploaded_image_url, response_type="json_object"
|
462
|
+
online_queries_prompt, uploaded_image_url=uploaded_image_url, response_type="json_object", user=user
|
457
463
|
)
|
458
464
|
|
459
465
|
# Validate that the response is a non-empty, JSON-serializable list of URLs
|
@@ -499,7 +505,7 @@ async def generate_online_subqueries(
|
|
499
505
|
|
500
506
|
with timer("Chat actor: Generate online search subqueries", logger):
|
501
507
|
response = await send_message_to_model_wrapper(
|
502
|
-
online_queries_prompt, uploaded_image_url=uploaded_image_url, response_type="json_object"
|
508
|
+
online_queries_prompt, uploaded_image_url=uploaded_image_url, response_type="json_object", user=user
|
503
509
|
)
|
504
510
|
|
505
511
|
# Validate that the response is a non-empty, JSON-serializable list
|
@@ -517,7 +523,9 @@ async def generate_online_subqueries(
|
|
517
523
|
return [q]
|
518
524
|
|
519
525
|
|
520
|
-
async def schedule_query(
|
526
|
+
async def schedule_query(
|
527
|
+
q: str, conversation_history: dict, user: KhojUser, uploaded_image_url: str = None
|
528
|
+
) -> Tuple[str, ...]:
|
521
529
|
"""
|
522
530
|
Schedule the date, time to run the query. Assume the server timezone is UTC.
|
523
531
|
"""
|
@@ -529,7 +537,7 @@ async def schedule_query(q: str, conversation_history: dict, uploaded_image_url:
|
|
529
537
|
)
|
530
538
|
|
531
539
|
raw_response = await send_message_to_model_wrapper(
|
532
|
-
crontime_prompt, uploaded_image_url=uploaded_image_url, response_type="json_object"
|
540
|
+
crontime_prompt, uploaded_image_url=uploaded_image_url, response_type="json_object", user=user
|
533
541
|
)
|
534
542
|
|
535
543
|
# Validate that the response is a non-empty, JSON-serializable list
|
@@ -543,7 +551,7 @@ async def schedule_query(q: str, conversation_history: dict, uploaded_image_url:
|
|
543
551
|
raise AssertionError(f"Invalid response for scheduling query: {raw_response}")
|
544
552
|
|
545
553
|
|
546
|
-
async def extract_relevant_info(q: str, corpus: str,
|
554
|
+
async def extract_relevant_info(q: str, corpus: str, user: KhojUser = None, agent: Agent = None) -> Union[str, None]:
|
547
555
|
"""
|
548
556
|
Extract relevant information for a given query from the target corpus
|
549
557
|
"""
|
@@ -561,14 +569,11 @@ async def extract_relevant_info(q: str, corpus: str, subscribed: bool, agent: Ag
|
|
561
569
|
personality_context=personality_context,
|
562
570
|
)
|
563
571
|
|
564
|
-
chat_model: ChatModelOptions = await ConversationAdapters.aget_default_conversation_config()
|
565
|
-
|
566
572
|
with timer("Chat actor: Extract relevant information from data", logger):
|
567
573
|
response = await send_message_to_model_wrapper(
|
568
574
|
extract_relevant_information,
|
569
575
|
prompts.system_prompt_extract_relevant_information,
|
570
|
-
|
571
|
-
subscribed=subscribed,
|
576
|
+
user=user,
|
572
577
|
)
|
573
578
|
return response.strip()
|
574
579
|
|
@@ -577,8 +582,8 @@ async def extract_relevant_summary(
|
|
577
582
|
q: str,
|
578
583
|
corpus: str,
|
579
584
|
conversation_history: dict,
|
580
|
-
subscribed: bool = False,
|
581
585
|
uploaded_image_url: str = None,
|
586
|
+
user: KhojUser = None,
|
582
587
|
agent: Agent = None,
|
583
588
|
) -> Union[str, None]:
|
584
589
|
"""
|
@@ -601,14 +606,11 @@ async def extract_relevant_summary(
|
|
601
606
|
personality_context=personality_context,
|
602
607
|
)
|
603
608
|
|
604
|
-
chat_model: ChatModelOptions = await ConversationAdapters.aget_default_conversation_config()
|
605
|
-
|
606
609
|
with timer("Chat actor: Extract relevant information from data", logger):
|
607
610
|
response = await send_message_to_model_wrapper(
|
608
611
|
extract_relevant_information,
|
609
612
|
prompts.system_prompt_extract_relevant_summary,
|
610
|
-
|
611
|
-
subscribed=subscribed,
|
613
|
+
user=user,
|
612
614
|
uploaded_image_url=uploaded_image_url,
|
613
615
|
)
|
614
616
|
return response.strip()
|
@@ -621,8 +623,8 @@ async def generate_better_image_prompt(
|
|
621
623
|
note_references: List[Dict[str, Any]],
|
622
624
|
online_results: Optional[dict] = None,
|
623
625
|
model_type: Optional[str] = None,
|
624
|
-
subscribed: bool = False,
|
625
626
|
uploaded_image_url: Optional[str] = None,
|
627
|
+
user: KhojUser = None,
|
626
628
|
agent: Agent = None,
|
627
629
|
) -> str:
|
628
630
|
"""
|
@@ -672,12 +674,8 @@ async def generate_better_image_prompt(
|
|
672
674
|
personality_context=personality_context,
|
673
675
|
)
|
674
676
|
|
675
|
-
chat_model: ChatModelOptions = await ConversationAdapters.aget_default_conversation_config()
|
676
|
-
|
677
677
|
with timer("Chat actor: Generate contextual image prompt", logger):
|
678
|
-
response = await send_message_to_model_wrapper(
|
679
|
-
image_prompt, chat_model_option=chat_model, subscribed=subscribed, uploaded_image_url=uploaded_image_url
|
680
|
-
)
|
678
|
+
response = await send_message_to_model_wrapper(image_prompt, uploaded_image_url=uploaded_image_url, user=user)
|
681
679
|
response = response.strip()
|
682
680
|
if response.startswith(('"', "'")) and response.endswith(('"', "'")):
|
683
681
|
response = response[1:-1]
|
@@ -689,14 +687,10 @@ async def send_message_to_model_wrapper(
|
|
689
687
|
message: str,
|
690
688
|
system_message: str = "",
|
691
689
|
response_type: str = "text",
|
692
|
-
|
693
|
-
subscribed: bool = False,
|
690
|
+
user: KhojUser = None,
|
694
691
|
uploaded_image_url: str = None,
|
695
692
|
):
|
696
|
-
conversation_config: ChatModelOptions = (
|
697
|
-
chat_model_option or await ConversationAdapters.aget_default_conversation_config()
|
698
|
-
)
|
699
|
-
|
693
|
+
conversation_config: ChatModelOptions = await ConversationAdapters.aget_default_conversation_config(user)
|
700
694
|
vision_available = conversation_config.vision_enabled
|
701
695
|
if not vision_available and uploaded_image_url:
|
702
696
|
vision_enabled_config = await ConversationAdapters.aget_vision_enabled_config()
|
@@ -704,6 +698,7 @@ async def send_message_to_model_wrapper(
|
|
704
698
|
conversation_config = vision_enabled_config
|
705
699
|
vision_available = True
|
706
700
|
|
701
|
+
subscribed = await ais_user_subscribed(user)
|
707
702
|
chat_model = conversation_config.chat_model
|
708
703
|
max_tokens = (
|
709
704
|
conversation_config.subscribed_max_prompt_size
|
@@ -802,8 +797,9 @@ def send_message_to_model_wrapper_sync(
|
|
802
797
|
message: str,
|
803
798
|
system_message: str = "",
|
804
799
|
response_type: str = "text",
|
800
|
+
user: KhojUser = None,
|
805
801
|
):
|
806
|
-
conversation_config: ChatModelOptions = ConversationAdapters.get_default_conversation_config()
|
802
|
+
conversation_config: ChatModelOptions = ConversationAdapters.get_default_conversation_config(user)
|
807
803
|
|
808
804
|
if conversation_config is None:
|
809
805
|
raise HTTPException(status_code=500, detail="Contact the server administrator to set a default chat model.")
|
@@ -1182,7 +1178,7 @@ class CommonQueryParamsClass:
|
|
1182
1178
|
CommonQueryParams = Annotated[CommonQueryParamsClass, Depends()]
|
1183
1179
|
|
1184
1180
|
|
1185
|
-
def should_notify(original_query: str, executed_query: str, ai_response: str) -> bool:
|
1181
|
+
def should_notify(original_query: str, executed_query: str, ai_response: str, user: KhojUser) -> bool:
|
1186
1182
|
"""
|
1187
1183
|
Decide whether to notify the user of the AI response.
|
1188
1184
|
Default to notifying the user for now.
|
@@ -1199,7 +1195,7 @@ def should_notify(original_query: str, executed_query: str, ai_response: str) ->
|
|
1199
1195
|
with timer("Chat actor: Decide to notify user of automation response", logger):
|
1200
1196
|
try:
|
1201
1197
|
# TODO Replace with async call so we don't have to maintain a sync version
|
1202
|
-
response = send_message_to_model_wrapper_sync(to_notify_or_not)
|
1198
|
+
response = send_message_to_model_wrapper_sync(to_notify_or_not, user)
|
1203
1199
|
should_notify_result = "no" not in response.lower()
|
1204
1200
|
logger.info(f'Decided to {"not " if not should_notify_result else ""}notify user of automation response.')
|
1205
1201
|
return should_notify_result
|
@@ -1291,7 +1287,9 @@ def scheduled_chat(
|
|
1291
1287
|
ai_response = raw_response.text
|
1292
1288
|
|
1293
1289
|
# Notify user if the AI response is satisfactory
|
1294
|
-
if should_notify(
|
1290
|
+
if should_notify(
|
1291
|
+
original_query=scheduling_request, executed_query=cleaned_query, ai_response=ai_response, user=user
|
1292
|
+
):
|
1295
1293
|
if is_resend_enabled():
|
1296
1294
|
send_task_email(user.get_short_name(), user.email, cleaned_query, ai_response, subject, is_image)
|
1297
1295
|
else:
|
@@ -1301,7 +1299,7 @@ def scheduled_chat(
|
|
1301
1299
|
async def create_automation(
|
1302
1300
|
q: str, timezone: str, user: KhojUser, calling_url: URL, meta_log: dict = {}, conversation_id: str = None
|
1303
1301
|
):
|
1304
|
-
crontime, query_to_run, subject = await schedule_query(q, meta_log)
|
1302
|
+
crontime, query_to_run, subject = await schedule_query(q, meta_log, user)
|
1305
1303
|
job = await schedule_automation(query_to_run, subject, crontime, timezone, q, user, calling_url, conversation_id)
|
1306
1304
|
return job, crontime, query_to_run, subject
|
1307
1305
|
|
@@ -1495,9 +1493,9 @@ def get_user_config(user: KhojUser, request: Request, is_detailed: bool = False)
|
|
1495
1493
|
current_notion_config = get_user_notion_config(user)
|
1496
1494
|
notion_token = current_notion_config.token if current_notion_config else ""
|
1497
1495
|
|
1498
|
-
selected_chat_model_config = (
|
1499
|
-
|
1500
|
-
)
|
1496
|
+
selected_chat_model_config = ConversationAdapters.get_conversation_config(
|
1497
|
+
user
|
1498
|
+
) or ConversationAdapters.get_default_conversation_config(user)
|
1501
1499
|
chat_models = ConversationAdapters.get_conversation_processor_options().all()
|
1502
1500
|
chat_model_options = list()
|
1503
1501
|
for chat_model in chat_models:
|
khoj/routers/subscription.py
CHANGED
@@ -7,6 +7,7 @@ from fastapi import APIRouter, Request
|
|
7
7
|
from starlette.authentication import requires
|
8
8
|
|
9
9
|
from khoj.database import adapters
|
10
|
+
from khoj.routers.helpers import update_telemetry_state
|
10
11
|
from khoj.utils import state
|
11
12
|
|
12
13
|
# Stripe integration for Khoj Cloud Subscription
|
@@ -48,6 +49,8 @@ async def subscribe(request: Request):
|
|
48
49
|
customer_id = subscription["customer"]
|
49
50
|
customer = stripe.Customer.retrieve(customer_id)
|
50
51
|
customer_email = customer["email"]
|
52
|
+
user = None
|
53
|
+
is_new = False
|
51
54
|
|
52
55
|
# Handle valid stripe webhook events
|
53
56
|
success = True
|
@@ -55,7 +58,9 @@ async def subscribe(request: Request):
|
|
55
58
|
# Mark the user as subscribed and update the next renewal date on payment
|
56
59
|
subscription = stripe.Subscription.list(customer=customer_id).data[0]
|
57
60
|
renewal_date = datetime.fromtimestamp(subscription["current_period_end"], tz=timezone.utc)
|
58
|
-
user = await adapters.set_user_subscription(
|
61
|
+
user, is_new = await adapters.set_user_subscription(
|
62
|
+
customer_email, is_recurring=True, renewal_date=renewal_date
|
63
|
+
)
|
59
64
|
success = user is not None
|
60
65
|
elif event_type in {"customer.subscription.updated"}:
|
61
66
|
user_subscription = await sync_to_async(adapters.get_user_subscription)(customer_email)
|
@@ -63,15 +68,24 @@ async def subscribe(request: Request):
|
|
63
68
|
if user_subscription and user_subscription.renewal_date:
|
64
69
|
# Mark user as unsubscribed or resubscribed
|
65
70
|
is_recurring = not subscription["cancel_at_period_end"]
|
66
|
-
|
67
|
-
success =
|
71
|
+
user, is_new = await adapters.set_user_subscription(customer_email, is_recurring=is_recurring)
|
72
|
+
success = user is not None
|
68
73
|
elif event_type in {"customer.subscription.deleted"}:
|
69
74
|
# Reset the user to trial state
|
70
|
-
user = await adapters.set_user_subscription(
|
75
|
+
user, is_new = await adapters.set_user_subscription(
|
71
76
|
customer_email, is_recurring=False, renewal_date=False, type="trial"
|
72
77
|
)
|
73
78
|
success = user is not None
|
74
79
|
|
80
|
+
if user and is_new:
|
81
|
+
update_telemetry_state(
|
82
|
+
request=request,
|
83
|
+
telemetry_type="api",
|
84
|
+
api="create_user",
|
85
|
+
metadata={"user_id": str(user.user.uuid)},
|
86
|
+
)
|
87
|
+
logger.log(logging.INFO, f"🥳 New User Created: {user.user.uuid}")
|
88
|
+
|
75
89
|
logger.info(f'Stripe subscription {event["type"]} for {customer_email}')
|
76
90
|
return {"success": success}
|
77
91
|
|
khoj/utils/initialization.py
CHANGED
@@ -129,9 +129,6 @@ def initialization(interactive: bool = True):
|
|
129
129
|
if user_chat_model_name and ChatModelOptions.objects.filter(chat_model=user_chat_model_name).exists():
|
130
130
|
default_chat_model_name = user_chat_model_name
|
131
131
|
|
132
|
-
# Create a server chat settings object with the default chat model
|
133
|
-
default_chat_model = ChatModelOptions.objects.filter(chat_model=default_chat_model_name).first()
|
134
|
-
ServerChatSettings.objects.create(chat_default=default_chat_model)
|
135
132
|
logger.info("🗣️ Chat model configuration complete")
|
136
133
|
|
137
134
|
# Set up offline speech to text model
|
@@ -1,5 +1,5 @@
|
|
1
1
|
khoj/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
khoj/configure.py,sha256=
|
2
|
+
khoj/configure.py,sha256=Gh0F5xBswYBhmPxNJoUN7hRc6NmfzeVZNCwKHpP9DmA,17499
|
3
3
|
khoj/main.py,sha256=9YMJEaKlVin5hxU0TcVH5X1CP6wX9HE8Z7qWSxNGPd0,8161
|
4
4
|
khoj/manage.py,sha256=njo6uLxGaMamTPesHjFEOIBJbpIUrz39e1V59zKj544,664
|
5
5
|
khoj/app/README.md,sha256=PSQjKCdpU2hgszLVF8yEhV7TWhbEEb-1aYLTRuuAsKI,2832
|
@@ -11,7 +11,7 @@ khoj/database/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
11
|
khoj/database/admin.py,sha256=ZKywmGF3q_YdPtoTVUCCpxZ_zYm3d3bhGRzSf9wi7FM,9218
|
12
12
|
khoj/database/apps.py,sha256=pM4tkX5Odw4YW_hLLKK8Nd5kqGddf1en0oMCea44RZw,153
|
13
13
|
khoj/database/tests.py,sha256=mrbGGRNg5jwbTJtWWa7zSKdDyeB4vmgZCRc2nk6VY-g,60
|
14
|
-
khoj/database/adapters/__init__.py,sha256=
|
14
|
+
khoj/database/adapters/__init__.py,sha256=xeDypsTaPFlYfh8wm9p_QzYTJvP3yOLiXIrXTyBRuwY,60593
|
15
15
|
khoj/database/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
16
16
|
khoj/database/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
17
17
|
khoj/database/management/commands/change_generated_images_url.py,sha256=w52FwRlyOL4YRpp9O6jJUjSIuGLxVhaS2w1D7gtQgOE,2644
|
@@ -103,17 +103,15 @@ khoj/interface/compiled/chat.svg,sha256=l2JoYRRgk201adTTdvJ-buKUrc0WGfsudix5xEvt
|
|
103
103
|
khoj/interface/compiled/close.svg,sha256=hQ2iFLkNzHk0_iyTrSbwnWAeXYlgA-c2Eof2Iqh76n4,417
|
104
104
|
khoj/interface/compiled/copy-button-success.svg,sha256=byqWAYD3Pn9IOXRjOKudJ-TJbP2UESbQGvtLWazNGjY,829
|
105
105
|
khoj/interface/compiled/copy-button.svg,sha256=05bKM2eRxksfBlAPT7yMaoNJEk85bZCxQg67EVrPeHo,669
|
106
|
-
khoj/interface/compiled/index.html,sha256=
|
107
|
-
khoj/interface/compiled/index.txt,sha256=
|
106
|
+
khoj/interface/compiled/index.html,sha256=0MbMqdtbsexIat1GAFjrieHQa3uXc110-2X5ZBrrUUY,11791
|
107
|
+
khoj/interface/compiled/index.txt,sha256=suy7R4efcOwqx3EusUhD4qYlBeylZMlf4zIbc_YN5b4,5479
|
108
108
|
khoj/interface/compiled/khoj.webmanifest,sha256=lsknYkvEdMbRTOUYKXPM_8krN2gamJmM4u3qj8u9lrU,1682
|
109
109
|
khoj/interface/compiled/logo.svg,sha256=_QCKVYM4WT2Qhcf7aVFImjq_s5CwjynGXYAOgI7yf8w,8059
|
110
110
|
khoj/interface/compiled/send.svg,sha256=VdavOWkVddcwcGcld6pdfmwfz7S91M-9O28cfeiKJkM,635
|
111
111
|
khoj/interface/compiled/share.svg,sha256=91lwo75PvMDrgocuZQab6EQ62CxRbubh9Bhw7CWMKbg,1221
|
112
112
|
khoj/interface/compiled/thumbs-down.svg,sha256=JGNl-DwoRmH2XFMPWwFFklmoYtKxaQbkLE3nuYKe8ZY,1019
|
113
113
|
khoj/interface/compiled/thumbs-up.svg,sha256=yS1wxTRtiztkN-6nZciLoYQUB_KTYNPV8xFRwH2TQFw,1036
|
114
|
-
khoj/interface/compiled/404/index.html,sha256=
|
115
|
-
khoj/interface/compiled/_next/static/NK3HVZEBC1y-DabLawiP7/_buildManifest.js,sha256=6I9QUstNpJnhe3leR2Daw0pSXwzcbBscv6h2jmmPpms,224
|
116
|
-
khoj/interface/compiled/_next/static/NK3HVZEBC1y-DabLawiP7/_ssgManifest.js,sha256=Z49s4suAsf5y_GfnQSvm4qtq2ggxEbZPfEDTXjy6XgA,80
|
114
|
+
khoj/interface/compiled/404/index.html,sha256=E0zIxgVLZHVh-T3BRm7TCj0GsV9P8Lsr8Vvl52zHqw8,12051
|
117
115
|
khoj/interface/compiled/_next/static/chunks/121-7024f479c297aef0.js,sha256=CcRT2AArGYTo7Orl5w69nrnMqdI_EmyEP_YqIj3FU1c,20952
|
118
116
|
khoj/interface/compiled/_next/static/chunks/1269-2e52d48e7d0e5c61.js,sha256=8iWbeeo_pCFEivsCeLB8dCtO2mMw8Z3LqWi2g5bE-OA,33828
|
119
117
|
khoj/interface/compiled/_next/static/chunks/1603-67a89278e2c5dbe6.js,sha256=2ZLMR7DmmkCjtMyIwUy2FrHXh8fAmEEdlzhjr4Zll3k,71252
|
@@ -239,8 +237,10 @@ khoj/interface/compiled/_next/static/media/flags.3afdda2f.webp,sha256=M2AW_HLpBn
|
|
239
237
|
khoj/interface/compiled/_next/static/media/flags@2x.5fbe9fc1.webp,sha256=BBeRPBZkxY3-aKkMnYv5TSkxmbeMbyUH4VRIPfrWg1E,137406
|
240
238
|
khoj/interface/compiled/_next/static/media/globe.98e105ca.webp,sha256=g3ofb8-W9GM75zIhlvQhaS8I2py9TtrovOKR3_7Jf04,514
|
241
239
|
khoj/interface/compiled/_next/static/media/globe@2x.974df6f8.webp,sha256=I_N7Yke3IOoS-0CC6XD8o0IUWG8PdPbrHmf6lpgWlZY,1380
|
242
|
-
khoj/interface/compiled/
|
243
|
-
khoj/interface/compiled/
|
240
|
+
khoj/interface/compiled/_next/static/rc-OVbl4ikReNwbN-LLwA/_buildManifest.js,sha256=6I9QUstNpJnhe3leR2Daw0pSXwzcbBscv6h2jmmPpms,224
|
241
|
+
khoj/interface/compiled/_next/static/rc-OVbl4ikReNwbN-LLwA/_ssgManifest.js,sha256=Z49s4suAsf5y_GfnQSvm4qtq2ggxEbZPfEDTXjy6XgA,80
|
242
|
+
khoj/interface/compiled/agents/index.html,sha256=-hrqUMsZpK-gbp0SC1xuSj3K7MES6hW2QmdmYoGKfcw,12522
|
243
|
+
khoj/interface/compiled/agents/index.txt,sha256=OdM1blKmT0_WIGhj4BBa0ZkWEGLUS2AbhYSbw3oaneo,5993
|
244
244
|
khoj/interface/compiled/assets/icons/khoj_lantern.ico,sha256=eggu-B_v3z1R53EjOFhIqqPnICBGdoaw1xnc0NrzHck,174144
|
245
245
|
khoj/interface/compiled/assets/icons/khoj_lantern_128x128.png,sha256=aTxivDb3CYyThkVZWz8A19xl_dNut5DbkXhODWF3A9Q,5640
|
246
246
|
khoj/interface/compiled/assets/icons/khoj_lantern_256x256.png,sha256=xPCMLHiaL7lYOdQLZrKwWE-Qjn5ZaysSZB0ScYv4UZU,12312
|
@@ -251,18 +251,18 @@ khoj/interface/compiled/assets/samples/desktop-remember-plan-sample.png,sha256=i
|
|
251
251
|
khoj/interface/compiled/assets/samples/phone-browse-draw-sample.png,sha256=Dd4fPwtFl6BWqnHjeb1mCK_ND0hhHsWtx8sNE7EiMuE,406179
|
252
252
|
khoj/interface/compiled/assets/samples/phone-plain-chat-sample.png,sha256=DEDaNRCkfEWUeh3kYZWIQDTVK1a6KKnYdwj5ZWisN_Q,82985
|
253
253
|
khoj/interface/compiled/assets/samples/phone-remember-plan-sample.png,sha256=Ma3blirRmq3X4oYSsDbbT7MDn29rymDrjwmUfA9BMuM,236285
|
254
|
-
khoj/interface/compiled/automations/index.html,sha256=
|
255
|
-
khoj/interface/compiled/automations/index.txt,sha256=
|
256
|
-
khoj/interface/compiled/chat/index.html,sha256=
|
257
|
-
khoj/interface/compiled/chat/index.txt,sha256=
|
258
|
-
khoj/interface/compiled/factchecker/index.html,sha256=
|
259
|
-
khoj/interface/compiled/factchecker/index.txt,sha256=
|
260
|
-
khoj/interface/compiled/search/index.html,sha256=
|
261
|
-
khoj/interface/compiled/search/index.txt,sha256=
|
262
|
-
khoj/interface/compiled/settings/index.html,sha256=
|
263
|
-
khoj/interface/compiled/settings/index.txt,sha256=
|
264
|
-
khoj/interface/compiled/share/chat/index.html,sha256=
|
265
|
-
khoj/interface/compiled/share/chat/index.txt,sha256=
|
254
|
+
khoj/interface/compiled/automations/index.html,sha256=h4icOrj28vG-wD-nWPd54jJfCoQJFN_9r_jcSgEIjZ8,30932
|
255
|
+
khoj/interface/compiled/automations/index.txt,sha256=15qo4BG2DuCDz6qhxXavyBQMsjAKQZZ1EvHUrCWWztA,5627
|
256
|
+
khoj/interface/compiled/chat/index.html,sha256=Q245r0veLKIw2Y578xSP22mq5YuZrhShpzT78UHu_Ls,13724
|
257
|
+
khoj/interface/compiled/chat/index.txt,sha256=rpClzF5xhi2vuCytjPx9ZHzSdzqFGyHsvvmk4l0qI1w,6486
|
258
|
+
khoj/interface/compiled/factchecker/index.html,sha256=M6IUdC0eev9JBg6t9cmXb5Xz_Ag0tuA4m90wJ7HJHQg,29973
|
259
|
+
khoj/interface/compiled/factchecker/index.txt,sha256=hh9NqSb8UuVNeiXvFw-oEviHjd8pYXgiouNs1A_hRlU,5788
|
260
|
+
khoj/interface/compiled/search/index.html,sha256=kJDpfcKNcJoLvhzz4PtPyWWcH6xk5hO1JV_sxtMUMRc,30161
|
261
|
+
khoj/interface/compiled/search/index.txt,sha256=bjG8gC4yez9i2Ku94Ml7HOJNLy4Yli_fHkKuT8xVU_o,5256
|
262
|
+
khoj/interface/compiled/settings/index.html,sha256=c_SvHgk4jZtUcvSbJVByzxjhEq8QPHFdvB7LzZFN7xI,12831
|
263
|
+
khoj/interface/compiled/settings/index.txt,sha256=d399PHtOQ5KodiRrHqMCdmqwF7vUaV-i0WoriVMjt5w,6078
|
264
|
+
khoj/interface/compiled/share/chat/index.html,sha256=o2VZTw2oVchLNo3O4XDm4K6zfabR5wyIPsBkmSR_-8A,15049
|
265
|
+
khoj/interface/compiled/share/chat/index.txt,sha256=oocz2cm7AtcjjoaCqptysueNcXUfdbpw68z15QCK0mk,7297
|
266
266
|
khoj/interface/email/feedback.html,sha256=xksuPFamx4hGWyTTxZKRgX_eiYQQEuv-eK9Xmkt-nwU,1216
|
267
267
|
khoj/interface/email/magic_link.html,sha256=EoGKQucfPj3xQrWXhSZAzPFOYCHF_ZX94TWCd1XHl1M,941
|
268
268
|
khoj/interface/email/task.html,sha256=tY7a0gzVeQ2lSQNu7WyXR_s7VYeWTrxWEj1iHVuoVE4,2813
|
@@ -329,24 +329,24 @@ khoj/processor/conversation/openai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQe
|
|
329
329
|
khoj/processor/conversation/openai/gpt.py,sha256=j4z1zvDli_pYEs7rJiJp8nu3AWzqpo_kvaDnLFC8Q-E,7806
|
330
330
|
khoj/processor/conversation/openai/utils.py,sha256=tGRUauPfrRGPQ7W_9-lBxpRLld8EWzMuRiTY9EptFgY,5313
|
331
331
|
khoj/processor/conversation/openai/whisper.py,sha256=zoEeK1LNCg_tzP4xzYi5vRPzNPGuDGzpkrkG7d1LUn4,447
|
332
|
-
khoj/processor/image/generate.py,sha256=
|
332
|
+
khoj/processor/image/generate.py,sha256=sY0mYhFubeZqZ02KGBdAXGskTeCIsADwwf715tNVXvc,8961
|
333
333
|
khoj/processor/speech/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
334
334
|
khoj/processor/speech/text_to_speech.py,sha256=Q7sapi5Hv6woXOumtrGqR0t6izZrFBkWXFOGrHM6dJ4,1929
|
335
335
|
khoj/processor/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
336
|
-
khoj/processor/tools/online_search.py,sha256=
|
336
|
+
khoj/processor/tools/online_search.py,sha256=1F7z_73Vk75MHvYYGyLT5G-VB7vNHLxmRrgVdJOIJ14,10314
|
337
337
|
khoj/routers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
338
|
-
khoj/routers/api.py,sha256=
|
338
|
+
khoj/routers/api.py,sha256=rf31Pfs6mEA_SHXWNzjUHoFrIZJwiwN9hebRQ3Evq8Y,27590
|
339
339
|
khoj/routers/api_agents.py,sha256=ntG5CDbYDxTrxCh5T_dPhh-PQhG-mtmgg_Qa0cMXAW4,8808
|
340
|
-
khoj/routers/api_chat.py,sha256=
|
340
|
+
khoj/routers/api_chat.py,sha256=_gak5dA0qVVZQC--15FJBum62lmp2_34icol5b5O464,60461
|
341
341
|
khoj/routers/api_content.py,sha256=lWunOwVWYvnl1ue_D81g9ZSwBc0UxHmBIrdJoVPxN_A,17900
|
342
|
-
khoj/routers/api_model.py,sha256=
|
342
|
+
khoj/routers/api_model.py,sha256=CR6aMVwgbh6dZEq1NZEeUBRVMMZubBQHTWAu6uzckf8,4650
|
343
343
|
khoj/routers/api_phone.py,sha256=p9yfc4WeMHDC0hg3aQk60a2VBy8rZPdEnz9wdJ7DzkU,2208
|
344
|
-
khoj/routers/auth.py,sha256=
|
344
|
+
khoj/routers/auth.py,sha256=d3wzcysoYBQkPeqc1-gX8EnE7I_roVirMp5uzxOgobs,6560
|
345
345
|
khoj/routers/email.py,sha256=SGYNPQvfcvYeHf70F0YqpY0FLMRElF2ZekROXdwGI18,3821
|
346
|
-
khoj/routers/helpers.py,sha256=
|
346
|
+
khoj/routers/helpers.py,sha256=2MH0MllE1ZtqpVN9Y-yQeKuZtCs7gJNg124U30DYAJQ,67927
|
347
347
|
khoj/routers/notion.py,sha256=Lp67xP9rVgpAF9BQoGTjZFcVdF1HYtvPP0kjq6uurKU,2802
|
348
348
|
khoj/routers/storage.py,sha256=tJrwhFRVWv0MHv7V7huMc1Diwm-putZSwnZXJ3tqT_c,2338
|
349
|
-
khoj/routers/subscription.py,sha256=
|
349
|
+
khoj/routers/subscription.py,sha256=JsKYS00Z2QXlXTobP1vU8T5cN5SE2PYp50CGDAQXofU,4699
|
350
350
|
khoj/routers/twilio.py,sha256=MLsuCm4--ETvr3sLxbF0CL_ehlg_l2rKBSLR2Qh2Xls,1081
|
351
351
|
khoj/routers/web_client.py,sha256=-bmzl6yCLgYxCnyIOYS0DePNZtcC5z2k0lk-EmbK2pg,4741
|
352
352
|
khoj/search_filter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -362,14 +362,14 @@ khoj/utils/config.py,sha256=aiOkH0je8A30DAGYTHMRePrgJonFv_i07_7CdhhhcdA,1805
|
|
362
362
|
khoj/utils/constants.py,sha256=UwE7U9bNsfeqTb0K2lcdXdAscM4-7uuVoR3KbZS03Pg,1216
|
363
363
|
khoj/utils/fs_syncer.py,sha256=bQgcbYYC3x11RyCqI_kUzzqGpcKTodGgdT-3OTQsXqw,9977
|
364
364
|
khoj/utils/helpers.py,sha256=4DR3kWn5wrgrZRPAWNg1GB4JJdAvuqwJcIyzPwphes0,15976
|
365
|
-
khoj/utils/initialization.py,sha256=
|
365
|
+
khoj/utils/initialization.py,sha256=TjA2ZImYKI-J1tEBE_0TaOLnVQidVV5GDEFBOPq8aik,10048
|
366
366
|
khoj/utils/jsonl.py,sha256=0Ac_COqr8sLCXntzZtquxuCEVRM2c3yKeDRGhgOBRpQ,1192
|
367
367
|
khoj/utils/models.py,sha256=Q5tcC9-z25sCiub048fLnvZ6_IIO1bcPNxt5payekk0,2009
|
368
368
|
khoj/utils/rawconfig.py,sha256=kURDuk7x0MDtniGLU4x1IsvU4UIBS-V9dSM4GD8X-LY,4274
|
369
369
|
khoj/utils/state.py,sha256=x4GTewP1YhOA6c_32N4wOjnV-3AA3xG_qbY1-wC2Uxc,1559
|
370
370
|
khoj/utils/yaml.py,sha256=H0mfw0ZvBFUvFmCQn8pWkfxdmIebsrSykza7D8Wv6wQ,1430
|
371
|
-
khoj-1.25.1.
|
372
|
-
khoj-1.25.1.
|
373
|
-
khoj-1.25.1.
|
374
|
-
khoj-1.25.1.
|
375
|
-
khoj-1.25.1.
|
371
|
+
khoj-1.25.1.dev7.dist-info/METADATA,sha256=Ikt8bJJ8EjyOd_cKqhJe7dyRTVw8aaiS_hn5Brbpt0E,6495
|
372
|
+
khoj-1.25.1.dev7.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
373
|
+
khoj-1.25.1.dev7.dist-info/entry_points.txt,sha256=KBIcez5N_jCgq_ER4Uxf-e1lxTBMTE_BBjMwwfeZyAg,39
|
374
|
+
khoj-1.25.1.dev7.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
|
375
|
+
khoj-1.25.1.dev7.dist-info/RECORD,,
|
File without changes
|
File without changes
|