khoj 1.24.2.dev34__py3-none-any.whl → 1.25.1.dev9__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 +54 -26
- khoj/interface/compiled/404/index.html +1 -1
- khoj/interface/compiled/_next/static/chunks/7762-79f2205740622b5c.js +1 -0
- khoj/interface/compiled/_next/static/chunks/app/agents/page-b406d166301c4c7d.js +1 -0
- khoj/interface/compiled/_next/static/chunks/app/automations/{page-1688dead2f21270d.js → page-2edc21f30819def4.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/app/chat/{page-91abcb71846922b7.js → page-4309c98e6dc497dd.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/app/factchecker/{page-7ab093711c27041c.js → page-f2c83e3a87a28657.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/app/{page-fada198096eab47f.js → page-ab9beb5a26e396f7.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/app/search/{page-a7e036689b6507ff.js → page-b807caebd7f278c7.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/app/settings/{page-fa11cafaec7ab39f.js → page-2932356ad11c2f7b.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/app/share/chat/{page-c5d2b9076e5390b2.js → page-a736a0826570af2b.js} +1 -1
- khoj/interface/compiled/_next/static/chunks/{webpack-f52083d548d804fa.js → webpack-462819dcfa6a1e2b.js} +1 -1
- khoj/interface/compiled/_next/static/css/3e1f1fdd70775091.css +1 -0
- khoj/interface/compiled/_next/static/css/b1094827d745306b.css +1 -0
- khoj/interface/compiled/_next/static/css/b9a6bf04305d98d7.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/factchecker/index.html +1 -1
- khoj/interface/compiled/factchecker/index.txt +2 -2
- khoj/interface/compiled/index.html +1 -1
- khoj/interface/compiled/index.txt +2 -2
- khoj/interface/compiled/search/index.html +1 -1
- khoj/interface/compiled/search/index.txt +2 -2
- khoj/interface/compiled/settings/index.html +1 -1
- khoj/interface/compiled/settings/index.txt +2 -2
- khoj/interface/compiled/share/chat/index.html +1 -1
- khoj/interface/compiled/share/chat/index.txt +2 -2
- khoj/processor/image/generate.py +1 -2
- khoj/processor/tools/online_search.py +4 -4
- khoj/routers/api.py +1 -1
- khoj/routers/api_agents.py +4 -1
- khoj/routers/api_chat.py +9 -11
- 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.24.2.dev34.dist-info → khoj-1.25.1.dev9.dist-info}/METADATA +18 -13
- {khoj-1.24.2.dev34.dist-info → khoj-1.25.1.dev9.dist-info}/RECORD +52 -52
- khoj/interface/compiled/_next/static/chunks/1269-2e52d48e7d0e5c61.js +0 -1
- khoj/interface/compiled/_next/static/chunks/app/agents/page-1b494bb54aca52de.js +0 -1
- khoj/interface/compiled/_next/static/css/592ca99f5122e75a.css +0 -1
- khoj/interface/compiled/_next/static/css/7a2b0a2d7c3d86eb.css +0 -25
- khoj/interface/compiled/_next/static/css/dfb67a9287720a2b.css +0 -1
- /khoj/interface/compiled/_next/static/chunks/{9178-899fe9a6b754ecfe.js → 9178-f208a3e6404714a9.js} +0 -0
- /khoj/interface/compiled/_next/static/chunks/{9417-29502e39c3e7d60c.js → 9417-1d158bf46d3a0dc9.js} +0 -0
- /khoj/interface/compiled/_next/static/chunks/{9479-7eed36fc954ef804.js → 9479-563e4d61f91d5a7c.js} +0 -0
- /khoj/interface/compiled/_next/static/{Be65WE5esb8ZOxD33psmy → jRL5xyceUdI0nvEyCkgqF}/_buildManifest.js +0 -0
- /khoj/interface/compiled/_next/static/{Be65WE5esb8ZOxD33psmy → jRL5xyceUdI0nvEyCkgqF}/_ssgManifest.js +0 -0
- {khoj-1.24.2.dev34.dist-info → khoj-1.25.1.dev9.dist-info}/WHEEL +0 -0
- {khoj-1.24.2.dev34.dist-info → khoj-1.25.1.dev9.dist-info}/entry_points.txt +0 -0
- {khoj-1.24.2.dev34.dist-info → khoj-1.25.1.dev9.dist-info}/licenses/LICENSE +0 -0
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,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: khoj
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.25.1.dev9
|
4
4
|
Summary: Your Second Brain
|
5
5
|
Project-URL: Homepage, https://khoj.dev
|
6
6
|
Project-URL: Documentation, https://docs.khoj.dev
|
@@ -103,14 +103,14 @@ Description-Content-Type: text/markdown
|
|
103
103
|
<div align="center">
|
104
104
|
|
105
105
|
[](https://github.com/khoj-ai/khoj/actions/workflows/test.yml)
|
106
|
-
[](https://github.com/khoj-ai/khoj/pkgs/container/khoj)
|
107
107
|
[](https://pypi.org/project/khoj/)
|
108
|
-
](https://discord.gg/BDgyabRM6e)
|
109
109
|
|
110
110
|
</div>
|
111
111
|
|
112
112
|
<div align="center">
|
113
|
-
<b>
|
113
|
+
<b>Your AI second brain</b>
|
114
114
|
</div>
|
115
115
|
|
116
116
|
<br />
|
@@ -119,11 +119,13 @@ Description-Content-Type: text/markdown
|
|
119
119
|
|
120
120
|
[📑 Docs](https://docs.khoj.dev)
|
121
121
|
<span> • </span>
|
122
|
-
[
|
122
|
+
[🌐 Web](https://khoj.dev)
|
123
|
+
<span> • </span>
|
124
|
+
[🔥 App](https://app.khoj.dev)
|
123
125
|
<span> • </span>
|
124
126
|
[💬 Discord](https://discord.gg/BDgyabRM6e)
|
125
127
|
<span> • </span>
|
126
|
-
[
|
128
|
+
[✍🏽 Blog](https://blog.khoj.dev)
|
127
129
|
|
128
130
|
</div>
|
129
131
|
|
@@ -131,14 +133,17 @@ Description-Content-Type: text/markdown
|
|
131
133
|
|
132
134
|
***
|
133
135
|
|
134
|
-
[Khoj](https://khoj.dev) is a personal
|
135
|
-
|
136
|
-
-
|
137
|
-
-
|
138
|
-
-
|
139
|
-
-
|
140
|
-
-
|
136
|
+
[Khoj](https://khoj.dev) is a personal AI app to extend your capabilities. It smoothly scales up from an on-device personal AI to a cloud-scale enterprise AI.
|
137
|
+
|
138
|
+
- Chat with any local or online LLM (e.g llama3, qwen, gemma, mistral, gpt, claude, gemini).
|
139
|
+
- Get answers from the internet and your docs (including image, pdf, markdown, org-mode, word, notion files).
|
140
|
+
- Access it from your Browser, Obsidian, Emacs, Desktop, Phone or Whatsapp.
|
141
|
+
- Build agents with custom knowledge bases and tools.
|
142
|
+
- Create automations to get personal newsletters and smart notifications.
|
143
|
+
- Find relevant docs quickly and easily using our advanced semantic search.
|
144
|
+
- Generate images, talk out loud, play your messages.
|
141
145
|
- Khoj is open-source, self-hostable. Always.
|
146
|
+
- Run it privately on [your computer](https://docs.khoj.dev/get-started/setup) or try it on our [cloud app](https://app.khoj.dev).
|
142
147
|
|
143
148
|
***
|
144
149
|
|