khoj 1.16.1.dev15__py3-none-any.whl → 1.17.1.dev229__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 +6 -6
- khoj/database/adapters/__init__.py +56 -12
- khoj/database/migrations/0053_agent_style_color_agent_style_icon.py +61 -0
- khoj/database/migrations/0054_alter_agent_style_color.py +38 -0
- khoj/database/models/__init__.py +35 -0
- khoj/interface/web/assets/icons/favicon-128x128.png +0 -0
- khoj/interface/web/assets/icons/favicon-256x256.png +0 -0
- khoj/interface/web/assets/icons/khoj-logo-sideways-200.png +0 -0
- khoj/interface/web/assets/icons/khoj-logo-sideways-500.png +0 -0
- khoj/interface/web/assets/icons/khoj-logo-sideways.svg +31 -5384
- khoj/interface/web/assets/icons/khoj.svg +26 -0
- khoj/interface/web/chat.html +191 -301
- khoj/interface/web/content_source_computer_input.html +3 -3
- khoj/interface/web/content_source_github_input.html +1 -1
- khoj/interface/web/content_source_notion_input.html +1 -1
- khoj/interface/web/public_conversation.html +1 -1
- khoj/interface/web/search.html +2 -2
- khoj/interface/web/{config.html → settings.html} +30 -30
- khoj/interface/web/utils.html +1 -1
- khoj/processor/content/docx/docx_to_entries.py +4 -9
- khoj/processor/content/github/github_to_entries.py +1 -3
- khoj/processor/content/images/image_to_entries.py +4 -9
- khoj/processor/content/markdown/markdown_to_entries.py +4 -9
- khoj/processor/content/notion/notion_to_entries.py +1 -3
- khoj/processor/content/org_mode/org_to_entries.py +4 -9
- khoj/processor/content/pdf/pdf_to_entries.py +4 -9
- khoj/processor/content/plaintext/plaintext_to_entries.py +4 -9
- khoj/processor/content/text_to_entries.py +1 -3
- khoj/processor/conversation/anthropic/anthropic_chat.py +10 -4
- khoj/processor/conversation/offline/chat_model.py +19 -7
- khoj/processor/conversation/offline/utils.py +2 -0
- khoj/processor/conversation/openai/gpt.py +9 -3
- khoj/processor/conversation/prompts.py +56 -25
- khoj/processor/conversation/utils.py +5 -6
- khoj/processor/tools/online_search.py +13 -7
- khoj/routers/api.py +60 -10
- khoj/routers/api_agents.py +3 -1
- khoj/routers/api_chat.py +335 -562
- khoj/routers/api_content.py +538 -0
- khoj/routers/api_model.py +156 -0
- khoj/routers/helpers.py +339 -26
- khoj/routers/notion.py +2 -8
- khoj/routers/web_client.py +43 -256
- khoj/search_type/text_search.py +5 -4
- khoj/utils/fs_syncer.py +4 -2
- khoj/utils/rawconfig.py +6 -1
- {khoj-1.16.1.dev15.dist-info → khoj-1.17.1.dev229.dist-info}/METADATA +3 -3
- {khoj-1.16.1.dev15.dist-info → khoj-1.17.1.dev229.dist-info}/RECORD +51 -49
- khoj/interface/web/assets/icons/favicon.icns +0 -0
- khoj/routers/api_config.py +0 -434
- khoj/routers/indexer.py +0 -349
- {khoj-1.16.1.dev15.dist-info → khoj-1.17.1.dev229.dist-info}/WHEEL +0 -0
- {khoj-1.16.1.dev15.dist-info → khoj-1.17.1.dev229.dist-info}/entry_points.txt +0 -0
- {khoj-1.16.1.dev15.dist-info → khoj-1.17.1.dev229.dist-info}/licenses/LICENSE +0 -0
khoj/configure.py
CHANGED
|
@@ -42,7 +42,7 @@ from khoj.database.adapters import (
|
|
|
42
42
|
)
|
|
43
43
|
from khoj.database.models import ClientApplication, KhojUser, ProcessLock, Subscription
|
|
44
44
|
from khoj.processor.embeddings import CrossEncoderModel, EmbeddingsModel
|
|
45
|
-
from khoj.routers.
|
|
45
|
+
from khoj.routers.api_content import configure_content, configure_search
|
|
46
46
|
from khoj.routers.twilio import is_twilio_enabled
|
|
47
47
|
from khoj.utils import constants, state
|
|
48
48
|
from khoj.utils.config import SearchType
|
|
@@ -308,16 +308,16 @@ def configure_routes(app):
|
|
|
308
308
|
from khoj.routers.api import api
|
|
309
309
|
from khoj.routers.api_agents import api_agents
|
|
310
310
|
from khoj.routers.api_chat import api_chat
|
|
311
|
-
from khoj.routers.
|
|
312
|
-
from khoj.routers.
|
|
311
|
+
from khoj.routers.api_content import api_content
|
|
312
|
+
from khoj.routers.api_model import api_model
|
|
313
313
|
from khoj.routers.notion import notion_router
|
|
314
314
|
from khoj.routers.web_client import web_client
|
|
315
315
|
|
|
316
316
|
app.include_router(api, prefix="/api")
|
|
317
317
|
app.include_router(api_chat, prefix="/api/chat")
|
|
318
318
|
app.include_router(api_agents, prefix="/api/agents")
|
|
319
|
-
app.include_router(
|
|
320
|
-
app.include_router(
|
|
319
|
+
app.include_router(api_model, prefix="/api/model")
|
|
320
|
+
app.include_router(api_content, prefix="/api/content")
|
|
321
321
|
app.include_router(notion_router, prefix="/api/notion")
|
|
322
322
|
app.include_router(web_client)
|
|
323
323
|
|
|
@@ -336,7 +336,7 @@ def configure_routes(app):
|
|
|
336
336
|
if is_twilio_enabled():
|
|
337
337
|
from khoj.routers.api_phone import api_phone
|
|
338
338
|
|
|
339
|
-
app.include_router(api_phone, prefix="/api/
|
|
339
|
+
app.include_router(api_phone, prefix="/api/phone")
|
|
340
340
|
logger.info("📞 Enabled Twilio")
|
|
341
341
|
|
|
342
342
|
|
|
@@ -559,7 +559,7 @@ class AgentAdapters:
|
|
|
559
559
|
if default_conversation_config is None:
|
|
560
560
|
logger.info("No default conversation config found, skipping default agent creation")
|
|
561
561
|
return None
|
|
562
|
-
default_personality = prompts.personality.format(current_date="placeholder")
|
|
562
|
+
default_personality = prompts.personality.format(current_date="placeholder", day_of_week="placeholder")
|
|
563
563
|
|
|
564
564
|
agent = Agent.objects.filter(name=AgentAdapters.DEFAULT_AGENT_NAME).first()
|
|
565
565
|
|
|
@@ -645,7 +645,11 @@ class ConversationAdapters:
|
|
|
645
645
|
|
|
646
646
|
@staticmethod
|
|
647
647
|
def get_conversation_sessions(user: KhojUser, client_application: ClientApplication = None):
|
|
648
|
-
return
|
|
648
|
+
return (
|
|
649
|
+
Conversation.objects.filter(user=user, client=client_application)
|
|
650
|
+
.prefetch_related("agent")
|
|
651
|
+
.order_by("-updated_at")
|
|
652
|
+
)
|
|
649
653
|
|
|
650
654
|
@staticmethod
|
|
651
655
|
async def aset_conversation_title(
|
|
@@ -680,19 +684,18 @@ class ConversationAdapters:
|
|
|
680
684
|
async def aget_conversation_by_user(
|
|
681
685
|
user: KhojUser, client_application: ClientApplication = None, conversation_id: int = None, title: str = None
|
|
682
686
|
) -> Optional[Conversation]:
|
|
687
|
+
query = Conversation.objects.filter(user=user, client=client_application).prefetch_related("agent")
|
|
688
|
+
|
|
683
689
|
if conversation_id:
|
|
684
|
-
return await
|
|
690
|
+
return await query.filter(id=conversation_id).afirst()
|
|
685
691
|
elif title:
|
|
686
|
-
return await
|
|
687
|
-
else:
|
|
688
|
-
conversation = Conversation.objects.filter(user=user, client=client_application).order_by("-updated_at")
|
|
692
|
+
return await query.filter(title=title).afirst()
|
|
689
693
|
|
|
690
|
-
|
|
691
|
-
return await conversation.prefetch_related("agent").afirst()
|
|
694
|
+
conversation = await query.order_by("-updated_at").afirst()
|
|
692
695
|
|
|
693
|
-
return await (
|
|
694
|
-
|
|
695
|
-
)
|
|
696
|
+
return conversation or await Conversation.objects.prefetch_related("agent").acreate(
|
|
697
|
+
user=user, client=client_application
|
|
698
|
+
)
|
|
696
699
|
|
|
697
700
|
@staticmethod
|
|
698
701
|
async def adelete_conversation_by_user(
|
|
@@ -799,11 +802,14 @@ class ConversationAdapters:
|
|
|
799
802
|
def create_conversation_from_public_conversation(
|
|
800
803
|
user: KhojUser, public_conversation: PublicConversation, client_app: ClientApplication
|
|
801
804
|
):
|
|
805
|
+
scrubbed_title = public_conversation.title if public_conversation.title else public_conversation.slug
|
|
806
|
+
if scrubbed_title:
|
|
807
|
+
scrubbed_title = scrubbed_title.replace("-", " ")
|
|
802
808
|
return Conversation.objects.create(
|
|
803
809
|
user=user,
|
|
804
810
|
conversation_log=public_conversation.conversation_log,
|
|
805
811
|
client=client_app,
|
|
806
|
-
slug=
|
|
812
|
+
slug=scrubbed_title,
|
|
807
813
|
title=public_conversation.title,
|
|
808
814
|
agent=public_conversation.agent,
|
|
809
815
|
)
|
|
@@ -944,6 +950,34 @@ class ConversationAdapters:
|
|
|
944
950
|
)
|
|
945
951
|
return new_config
|
|
946
952
|
|
|
953
|
+
@staticmethod
|
|
954
|
+
def add_files_to_filter(user: KhojUser, conversation_id: int, files: List[str]):
|
|
955
|
+
conversation = ConversationAdapters.get_conversation_by_user(user, conversation_id=conversation_id)
|
|
956
|
+
file_list = EntryAdapters.get_all_filenames_by_source(user, "computer")
|
|
957
|
+
for filename in files:
|
|
958
|
+
if filename in file_list and filename not in conversation.file_filters:
|
|
959
|
+
conversation.file_filters.append(filename)
|
|
960
|
+
conversation.save()
|
|
961
|
+
|
|
962
|
+
# remove files from conversation.file_filters that are not in file_list
|
|
963
|
+
conversation.file_filters = [file for file in conversation.file_filters if file in file_list]
|
|
964
|
+
conversation.save()
|
|
965
|
+
return conversation.file_filters
|
|
966
|
+
|
|
967
|
+
@staticmethod
|
|
968
|
+
def remove_files_from_filter(user: KhojUser, conversation_id: int, files: List[str]):
|
|
969
|
+
conversation = ConversationAdapters.get_conversation_by_user(user, conversation_id=conversation_id)
|
|
970
|
+
for filename in files:
|
|
971
|
+
if filename in conversation.file_filters:
|
|
972
|
+
conversation.file_filters.remove(filename)
|
|
973
|
+
conversation.save()
|
|
974
|
+
|
|
975
|
+
# remove files from conversation.file_filters that are not in file_list
|
|
976
|
+
file_list = EntryAdapters.get_all_filenames_by_source(user, "computer")
|
|
977
|
+
conversation.file_filters = [file for file in conversation.file_filters if file in file_list]
|
|
978
|
+
conversation.save()
|
|
979
|
+
return conversation.file_filters
|
|
980
|
+
|
|
947
981
|
|
|
948
982
|
class FileObjectAdapters:
|
|
949
983
|
@staticmethod
|
|
@@ -1072,6 +1106,16 @@ class EntryAdapters:
|
|
|
1072
1106
|
async def adelete_entry_by_file(user: KhojUser, file_path: str):
|
|
1073
1107
|
return await Entry.objects.filter(user=user, file_path=file_path).adelete()
|
|
1074
1108
|
|
|
1109
|
+
@staticmethod
|
|
1110
|
+
async def adelete_entries_by_filenames(user: KhojUser, filenames: List[str], batch_size=1000):
|
|
1111
|
+
deleted_count = 0
|
|
1112
|
+
for i in range(0, len(filenames), batch_size):
|
|
1113
|
+
batch = filenames[i : i + batch_size]
|
|
1114
|
+
count, _ = await Entry.objects.filter(user=user, file_path__in=batch).adelete()
|
|
1115
|
+
deleted_count += count
|
|
1116
|
+
|
|
1117
|
+
return deleted_count
|
|
1118
|
+
|
|
1075
1119
|
@staticmethod
|
|
1076
1120
|
def get_all_filenames_by_source(user: KhojUser, file_source: str):
|
|
1077
1121
|
return (
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Generated by Django 5.0.6 on 2024-07-13 16:26
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
dependencies = [
|
|
8
|
+
("database", "0052_alter_searchmodelconfig_bi_encoder_docs_encode_config_and_more"),
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
operations = [
|
|
12
|
+
migrations.AddField(
|
|
13
|
+
model_name="agent",
|
|
14
|
+
name="style_color",
|
|
15
|
+
field=models.CharField(
|
|
16
|
+
choices=[
|
|
17
|
+
("blue", "Blue"),
|
|
18
|
+
("green", "Green"),
|
|
19
|
+
("red", "Red"),
|
|
20
|
+
("yellow", "Yellow"),
|
|
21
|
+
("orange", "Orange"),
|
|
22
|
+
("purple", "Purple"),
|
|
23
|
+
("pink", "Pink"),
|
|
24
|
+
("teal", "Teal"),
|
|
25
|
+
("cyan", "Cyan"),
|
|
26
|
+
("lime", "Lime"),
|
|
27
|
+
("indigo", "Indigo"),
|
|
28
|
+
("fuschia", "Fuschia"),
|
|
29
|
+
("rose", "Rose"),
|
|
30
|
+
("sky", "Sky"),
|
|
31
|
+
("amber", "Amber"),
|
|
32
|
+
("emerald", "Emerald"),
|
|
33
|
+
],
|
|
34
|
+
default="blue",
|
|
35
|
+
max_length=200,
|
|
36
|
+
),
|
|
37
|
+
),
|
|
38
|
+
migrations.AddField(
|
|
39
|
+
model_name="agent",
|
|
40
|
+
name="style_icon",
|
|
41
|
+
field=models.CharField(
|
|
42
|
+
choices=[
|
|
43
|
+
("Lightbulb", "Lighbulb"),
|
|
44
|
+
("Health", "Health"),
|
|
45
|
+
("Robot", "Robot"),
|
|
46
|
+
("Aperture", "Aperture"),
|
|
47
|
+
("GraduationCap", "Graduation Cap"),
|
|
48
|
+
("Jeep", "Jeep"),
|
|
49
|
+
("Island", "Island"),
|
|
50
|
+
("MathOperations", "Math Operations"),
|
|
51
|
+
("Asclepius", "Asclepius"),
|
|
52
|
+
("Couch", "Couch"),
|
|
53
|
+
("Code", "Code"),
|
|
54
|
+
("Atom", "Atom"),
|
|
55
|
+
("ClockCounterClockwise", "Clock Counter Clockwise"),
|
|
56
|
+
],
|
|
57
|
+
default="Lightbulb",
|
|
58
|
+
max_length=200,
|
|
59
|
+
),
|
|
60
|
+
),
|
|
61
|
+
]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Generated by Django 5.0.7 on 2024-08-05 06:19
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
dependencies = [
|
|
8
|
+
("database", "0053_agent_style_color_agent_style_icon"),
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
operations = [
|
|
12
|
+
migrations.AlterField(
|
|
13
|
+
model_name="agent",
|
|
14
|
+
name="style_color",
|
|
15
|
+
field=models.CharField(
|
|
16
|
+
choices=[
|
|
17
|
+
("blue", "Blue"),
|
|
18
|
+
("green", "Green"),
|
|
19
|
+
("red", "Red"),
|
|
20
|
+
("yellow", "Yellow"),
|
|
21
|
+
("orange", "Orange"),
|
|
22
|
+
("purple", "Purple"),
|
|
23
|
+
("pink", "Pink"),
|
|
24
|
+
("teal", "Teal"),
|
|
25
|
+
("cyan", "Cyan"),
|
|
26
|
+
("lime", "Lime"),
|
|
27
|
+
("indigo", "Indigo"),
|
|
28
|
+
("fuchsia", "Fuchsia"),
|
|
29
|
+
("rose", "Rose"),
|
|
30
|
+
("sky", "Sky"),
|
|
31
|
+
("amber", "Amber"),
|
|
32
|
+
("emerald", "Emerald"),
|
|
33
|
+
],
|
|
34
|
+
default="blue",
|
|
35
|
+
max_length=200,
|
|
36
|
+
),
|
|
37
|
+
),
|
|
38
|
+
]
|
khoj/database/models/__init__.py
CHANGED
|
@@ -103,6 +103,39 @@ class VoiceModelOption(BaseModel):
|
|
|
103
103
|
|
|
104
104
|
|
|
105
105
|
class Agent(BaseModel):
|
|
106
|
+
class StyleColorTypes(models.TextChoices):
|
|
107
|
+
BLUE = "blue"
|
|
108
|
+
GREEN = "green"
|
|
109
|
+
RED = "red"
|
|
110
|
+
YELLOW = "yellow"
|
|
111
|
+
ORANGE = "orange"
|
|
112
|
+
PURPLE = "purple"
|
|
113
|
+
PINK = "pink"
|
|
114
|
+
TEAL = "teal"
|
|
115
|
+
CYAN = "cyan"
|
|
116
|
+
LIME = "lime"
|
|
117
|
+
INDIGO = "indigo"
|
|
118
|
+
FUCHSIA = "fuchsia"
|
|
119
|
+
ROSE = "rose"
|
|
120
|
+
SKY = "sky"
|
|
121
|
+
AMBER = "amber"
|
|
122
|
+
EMERALD = "emerald"
|
|
123
|
+
|
|
124
|
+
class StyleIconTypes(models.TextChoices):
|
|
125
|
+
LIGHBULB = "Lightbulb"
|
|
126
|
+
HEALTH = "Health"
|
|
127
|
+
ROBOT = "Robot"
|
|
128
|
+
APERTURE = "Aperture"
|
|
129
|
+
GRADUATION_CAP = "GraduationCap"
|
|
130
|
+
JEEP = "Jeep"
|
|
131
|
+
ISLAND = "Island"
|
|
132
|
+
MATH_OPERATIONS = "MathOperations"
|
|
133
|
+
ASCLEPIUS = "Asclepius"
|
|
134
|
+
COUCH = "Couch"
|
|
135
|
+
CODE = "Code"
|
|
136
|
+
ATOM = "Atom"
|
|
137
|
+
CLOCK_COUNTER_CLOCKWISE = "ClockCounterClockwise"
|
|
138
|
+
|
|
106
139
|
creator = models.ForeignKey(
|
|
107
140
|
KhojUser, on_delete=models.CASCADE, default=None, null=True, blank=True
|
|
108
141
|
) # Creator will only be null when the agents are managed by admin
|
|
@@ -114,6 +147,8 @@ class Agent(BaseModel):
|
|
|
114
147
|
managed_by_admin = models.BooleanField(default=False)
|
|
115
148
|
chat_model = models.ForeignKey(ChatModelOptions, on_delete=models.CASCADE)
|
|
116
149
|
slug = models.CharField(max_length=200)
|
|
150
|
+
style_color = models.CharField(max_length=200, choices=StyleColorTypes.choices, default=StyleColorTypes.BLUE)
|
|
151
|
+
style_icon = models.CharField(max_length=200, choices=StyleIconTypes.choices, default=StyleIconTypes.LIGHBULB)
|
|
117
152
|
|
|
118
153
|
|
|
119
154
|
class ProcessLock(BaseModel):
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|