khoj 1.17.0__py3-none-any.whl → 1.17.1.dev217__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 (46) hide show
  1. khoj/configure.py +6 -6
  2. khoj/database/adapters/__init__.py +47 -2
  3. khoj/database/migrations/0053_agent_style_color_agent_style_icon.py +61 -0
  4. khoj/database/models/__init__.py +35 -0
  5. khoj/interface/web/assets/icons/favicon-128x128.png +0 -0
  6. khoj/interface/web/assets/icons/favicon-256x256.png +0 -0
  7. khoj/interface/web/assets/icons/khoj-logo-sideways-200.png +0 -0
  8. khoj/interface/web/assets/icons/khoj-logo-sideways-500.png +0 -0
  9. khoj/interface/web/assets/icons/khoj-logo-sideways.svg +31 -5384
  10. khoj/interface/web/assets/icons/khoj.svg +26 -0
  11. khoj/interface/web/chat.html +5 -5
  12. khoj/interface/web/content_source_computer_input.html +3 -3
  13. khoj/interface/web/content_source_github_input.html +1 -1
  14. khoj/interface/web/content_source_notion_input.html +1 -1
  15. khoj/interface/web/public_conversation.html +1 -1
  16. khoj/interface/web/search.html +2 -2
  17. khoj/interface/web/{config.html → settings.html} +30 -30
  18. khoj/interface/web/utils.html +1 -1
  19. khoj/processor/content/docx/docx_to_entries.py +4 -9
  20. khoj/processor/content/github/github_to_entries.py +1 -3
  21. khoj/processor/content/images/image_to_entries.py +4 -9
  22. khoj/processor/content/markdown/markdown_to_entries.py +4 -9
  23. khoj/processor/content/notion/notion_to_entries.py +1 -3
  24. khoj/processor/content/org_mode/org_to_entries.py +4 -9
  25. khoj/processor/content/pdf/pdf_to_entries.py +4 -9
  26. khoj/processor/content/plaintext/plaintext_to_entries.py +4 -9
  27. khoj/processor/content/text_to_entries.py +1 -3
  28. khoj/processor/tools/online_search.py +4 -4
  29. khoj/routers/api.py +49 -4
  30. khoj/routers/api_agents.py +3 -1
  31. khoj/routers/api_chat.py +80 -88
  32. khoj/routers/api_content.py +538 -0
  33. khoj/routers/api_model.py +156 -0
  34. khoj/routers/helpers.py +308 -7
  35. khoj/routers/notion.py +2 -8
  36. khoj/routers/web_client.py +43 -256
  37. khoj/search_type/text_search.py +5 -4
  38. khoj/utils/fs_syncer.py +3 -1
  39. khoj/utils/rawconfig.py +6 -1
  40. {khoj-1.17.0.dist-info → khoj-1.17.1.dev217.dist-info}/METADATA +2 -2
  41. {khoj-1.17.0.dist-info → khoj-1.17.1.dev217.dist-info}/RECORD +44 -42
  42. khoj/routers/api_config.py +0 -434
  43. khoj/routers/indexer.py +0 -349
  44. {khoj-1.17.0.dist-info → khoj-1.17.1.dev217.dist-info}/WHEEL +0 -0
  45. {khoj-1.17.0.dist-info → khoj-1.17.1.dev217.dist-info}/entry_points.txt +0 -0
  46. {khoj-1.17.0.dist-info → khoj-1.17.1.dev217.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.indexer import configure_content, configure_search
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.api_config import api_config
312
- from khoj.routers.indexer import indexer
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(api_config, prefix="/api/config")
320
- app.include_router(indexer, prefix="/api/v1/index")
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/config/phone")
339
+ app.include_router(api_phone, prefix="/api/phone")
340
340
  logger.info("📞 Enabled Twilio")
341
341
 
342
342
 
@@ -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 Conversation.objects.filter(user=user, client=client_application).order_by("-updated_at")
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(
@@ -798,11 +802,14 @@ class ConversationAdapters:
798
802
  def create_conversation_from_public_conversation(
799
803
  user: KhojUser, public_conversation: PublicConversation, client_app: ClientApplication
800
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("-", " ")
801
808
  return Conversation.objects.create(
802
809
  user=user,
803
810
  conversation_log=public_conversation.conversation_log,
804
811
  client=client_app,
805
- slug=public_conversation.slug,
812
+ slug=scrubbed_title,
806
813
  title=public_conversation.title,
807
814
  agent=public_conversation.agent,
808
815
  )
@@ -943,6 +950,34 @@ class ConversationAdapters:
943
950
  )
944
951
  return new_config
945
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
+
946
981
 
947
982
  class FileObjectAdapters:
948
983
  @staticmethod
@@ -1071,6 +1106,16 @@ class EntryAdapters:
1071
1106
  async def adelete_entry_by_file(user: KhojUser, file_path: str):
1072
1107
  return await Entry.objects.filter(user=user, file_path=file_path).adelete()
1073
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
+
1074
1119
  @staticmethod
1075
1120
  def get_all_filenames_by_source(user: KhojUser, file_source: str):
1076
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
+ ]
@@ -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
+ FUSCHIA = "fuschia"
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):