khoj 1.24.2.dev3__py3-none-any.whl → 1.25.1.dev34__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 (109) hide show
  1. khoj/configure.py +13 -4
  2. khoj/database/adapters/__init__.py +289 -52
  3. khoj/database/admin.py +20 -1
  4. khoj/database/migrations/0065_remove_agent_avatar_remove_agent_public_and_more.py +49 -0
  5. khoj/database/migrations/0066_remove_agent_tools_agent_input_tools_and_more.py +69 -0
  6. khoj/database/migrations/0067_alter_agent_style_icon.py +50 -0
  7. khoj/database/migrations/0068_alter_agent_output_modes.py +24 -0
  8. khoj/database/migrations/0069_webscraper_serverchatsettings_web_scraper.py +89 -0
  9. khoj/database/models/__init__.py +136 -18
  10. khoj/interface/compiled/404/index.html +1 -1
  11. khoj/interface/compiled/_next/static/chunks/1603-fa3ee48860b9dc5c.js +1 -0
  12. khoj/interface/compiled/_next/static/chunks/2697-a38d01981ad3bdf8.js +1 -0
  13. khoj/interface/compiled/_next/static/chunks/3110-ef2cacd1b8d79ad8.js +1 -0
  14. khoj/interface/compiled/_next/static/chunks/4086-2c74808ba38a5a0f.js +1 -0
  15. khoj/interface/compiled/_next/static/chunks/477-ec86e93db10571c1.js +1 -0
  16. khoj/interface/compiled/_next/static/chunks/51-e8f5bdb69b5ea421.js +1 -0
  17. khoj/interface/compiled/_next/static/chunks/7762-79f2205740622b5c.js +1 -0
  18. khoj/interface/compiled/_next/static/chunks/9178-899fe9a6b754ecfe.js +1 -0
  19. khoj/interface/compiled/_next/static/chunks/9417-29502e39c3e7d60c.js +1 -0
  20. khoj/interface/compiled/_next/static/chunks/9479-7eed36fc954ef804.js +1 -0
  21. khoj/interface/compiled/_next/static/chunks/app/agents/{layout-e71c8e913cccf792.js → layout-75636ab3a413fa8e.js} +1 -1
  22. khoj/interface/compiled/_next/static/chunks/app/agents/page-fa282831808ee536.js +1 -0
  23. khoj/interface/compiled/_next/static/chunks/app/automations/page-5480731341f34450.js +1 -0
  24. khoj/interface/compiled/_next/static/chunks/app/chat/{layout-8102549127db3067.js → layout-96fcf62857bf8f30.js} +1 -1
  25. khoj/interface/compiled/_next/static/chunks/app/chat/page-702057ccbcf27881.js +1 -0
  26. khoj/interface/compiled/_next/static/chunks/app/factchecker/page-e7b34316ec6f44de.js +1 -0
  27. khoj/interface/compiled/_next/static/chunks/app/{layout-f3e40d346da53112.js → layout-d0f0a9067427fb20.js} +1 -1
  28. khoj/interface/compiled/_next/static/chunks/app/page-10a5aad6e04f3cf8.js +1 -0
  29. khoj/interface/compiled/_next/static/chunks/app/search/page-d56541c746fded7d.js +1 -0
  30. khoj/interface/compiled/_next/static/chunks/app/settings/{layout-6f9314b0d7a26046.js → layout-a8f33dfe92f997fb.js} +1 -1
  31. khoj/interface/compiled/_next/static/chunks/app/settings/page-e044a999468a7c5d.js +1 -0
  32. khoj/interface/compiled/_next/static/chunks/app/share/chat/{layout-39f03f9e32399f0f.js → layout-2df56074e42adaa0.js} +1 -1
  33. khoj/interface/compiled/_next/static/chunks/app/share/chat/page-fbbd66a4d4633438.js +1 -0
  34. khoj/interface/compiled/_next/static/chunks/{webpack-d4781cada9b58e75.js → webpack-c0cd5a6afb1f0798.js} +1 -1
  35. khoj/interface/compiled/_next/static/css/2de69f0be774c768.css +1 -0
  36. khoj/interface/compiled/_next/static/css/467a524c75e7d7c0.css +1 -0
  37. khoj/interface/compiled/_next/static/css/592ca99f5122e75a.css +1 -0
  38. khoj/interface/compiled/_next/static/css/b9a6bf04305d98d7.css +25 -0
  39. khoj/interface/compiled/agents/index.html +1 -1
  40. khoj/interface/compiled/agents/index.txt +2 -2
  41. khoj/interface/compiled/automations/index.html +1 -1
  42. khoj/interface/compiled/automations/index.txt +2 -2
  43. khoj/interface/compiled/chat/index.html +1 -1
  44. khoj/interface/compiled/chat/index.txt +2 -2
  45. khoj/interface/compiled/factchecker/index.html +1 -1
  46. khoj/interface/compiled/factchecker/index.txt +2 -2
  47. khoj/interface/compiled/index.html +1 -1
  48. khoj/interface/compiled/index.txt +2 -2
  49. khoj/interface/compiled/search/index.html +1 -1
  50. khoj/interface/compiled/search/index.txt +2 -2
  51. khoj/interface/compiled/settings/index.html +1 -1
  52. khoj/interface/compiled/settings/index.txt +3 -3
  53. khoj/interface/compiled/share/chat/index.html +1 -1
  54. khoj/interface/compiled/share/chat/index.txt +2 -2
  55. khoj/interface/web/assets/icons/agents.svg +1 -0
  56. khoj/interface/web/assets/icons/automation.svg +1 -0
  57. khoj/interface/web/assets/icons/chat.svg +24 -0
  58. khoj/interface/web/login.html +11 -22
  59. khoj/processor/content/notion/notion_to_entries.py +2 -1
  60. khoj/processor/conversation/anthropic/anthropic_chat.py +2 -0
  61. khoj/processor/conversation/google/gemini_chat.py +6 -19
  62. khoj/processor/conversation/google/utils.py +33 -15
  63. khoj/processor/conversation/offline/chat_model.py +3 -1
  64. khoj/processor/conversation/openai/gpt.py +2 -0
  65. khoj/processor/conversation/prompts.py +67 -5
  66. khoj/processor/conversation/utils.py +3 -7
  67. khoj/processor/embeddings.py +6 -3
  68. khoj/processor/image/generate.py +4 -3
  69. khoj/processor/tools/online_search.py +139 -44
  70. khoj/routers/api.py +35 -6
  71. khoj/routers/api_agents.py +235 -4
  72. khoj/routers/api_chat.py +102 -530
  73. khoj/routers/api_content.py +14 -0
  74. khoj/routers/api_model.py +1 -1
  75. khoj/routers/auth.py +9 -1
  76. khoj/routers/helpers.py +181 -68
  77. khoj/routers/subscription.py +18 -4
  78. khoj/search_type/text_search.py +11 -3
  79. khoj/utils/helpers.py +64 -8
  80. khoj/utils/initialization.py +0 -3
  81. {khoj-1.24.2.dev3.dist-info → khoj-1.25.1.dev34.dist-info}/METADATA +19 -21
  82. {khoj-1.24.2.dev3.dist-info → khoj-1.25.1.dev34.dist-info}/RECORD +87 -81
  83. khoj/interface/compiled/_next/static/chunks/1603-3e2e1528e3b6ea1d.js +0 -1
  84. khoj/interface/compiled/_next/static/chunks/2697-a29cb9191a9e339c.js +0 -1
  85. khoj/interface/compiled/_next/static/chunks/6648-ee109f4ea33a74e2.js +0 -1
  86. khoj/interface/compiled/_next/static/chunks/7071-b4711cecca6619a8.js +0 -1
  87. khoj/interface/compiled/_next/static/chunks/743-1a64254447cda71f.js +0 -1
  88. khoj/interface/compiled/_next/static/chunks/8423-62ac6c832be2461b.js +0 -1
  89. khoj/interface/compiled/_next/static/chunks/9162-0be016519a18568b.js +0 -1
  90. khoj/interface/compiled/_next/static/chunks/9178-7e815211edcb3657.js +0 -1
  91. khoj/interface/compiled/_next/static/chunks/9417-5d14ac74aaab2c66.js +0 -1
  92. khoj/interface/compiled/_next/static/chunks/9984-e410179c6fac7cf1.js +0 -1
  93. khoj/interface/compiled/_next/static/chunks/app/agents/page-d302911777a3e027.js +0 -1
  94. khoj/interface/compiled/_next/static/chunks/app/automations/page-0a5de8c254c29a1c.js +0 -1
  95. khoj/interface/compiled/_next/static/chunks/app/chat/page-d96bf6a84bb05290.js +0 -1
  96. khoj/interface/compiled/_next/static/chunks/app/factchecker/page-32e61af29e6b431d.js +0 -1
  97. khoj/interface/compiled/_next/static/chunks/app/page-96cab08c985716f4.js +0 -1
  98. khoj/interface/compiled/_next/static/chunks/app/search/page-b3193d46c65571c5.js +0 -1
  99. khoj/interface/compiled/_next/static/chunks/app/settings/page-0db9b708366606ec.js +0 -1
  100. khoj/interface/compiled/_next/static/chunks/app/share/chat/page-f06ac16cfe5b5a16.js +0 -1
  101. khoj/interface/compiled/_next/static/css/1538cedb321e3a97.css +0 -1
  102. khoj/interface/compiled/_next/static/css/24f141a6e37cd204.css +0 -25
  103. khoj/interface/compiled/_next/static/css/4cae6c0e5c72fb2d.css +0 -1
  104. khoj/interface/compiled/_next/static/css/f768dddada62459d.css +0 -1
  105. /khoj/interface/compiled/_next/static/{_29ceahp81LhuIHo5QgOD → Jid9q6Qg851ioDaaO_fth}/_buildManifest.js +0 -0
  106. /khoj/interface/compiled/_next/static/{_29ceahp81LhuIHo5QgOD → Jid9q6Qg851ioDaaO_fth}/_ssgManifest.js +0 -0
  107. {khoj-1.24.2.dev3.dist-info → khoj-1.25.1.dev34.dist-info}/WHEEL +0 -0
  108. {khoj-1.24.2.dev3.dist-info → khoj-1.25.1.dev34.dist-info}/entry_points.txt +0 -0
  109. {khoj-1.24.2.dev3.dist-info → khoj-1.25.1.dev34.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,49 @@
1
+ # Generated by Django 5.0.8 on 2024-09-18 02:54
2
+
3
+ import django.db.models.deletion
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+ dependencies = [
9
+ ("database", "0064_remove_conversation_temp_id_alter_conversation_id"),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.RemoveField(
14
+ model_name="agent",
15
+ name="avatar",
16
+ ),
17
+ migrations.RemoveField(
18
+ model_name="agent",
19
+ name="public",
20
+ ),
21
+ migrations.AddField(
22
+ model_name="agent",
23
+ name="privacy_level",
24
+ field=models.CharField(
25
+ choices=[("public", "Public"), ("private", "Private"), ("protected", "Protected")],
26
+ default="private",
27
+ max_length=30,
28
+ ),
29
+ ),
30
+ migrations.AddField(
31
+ model_name="entry",
32
+ name="agent",
33
+ field=models.ForeignKey(
34
+ blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to="database.agent"
35
+ ),
36
+ ),
37
+ migrations.AddField(
38
+ model_name="fileobject",
39
+ name="agent",
40
+ field=models.ForeignKey(
41
+ blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to="database.agent"
42
+ ),
43
+ ),
44
+ migrations.AlterField(
45
+ model_name="agent",
46
+ name="slug",
47
+ field=models.CharField(max_length=200, unique=True),
48
+ ),
49
+ ]
@@ -0,0 +1,69 @@
1
+ # Generated by Django 5.0.8 on 2024-10-01 00:42
2
+
3
+ import django.contrib.postgres.fields
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+ dependencies = [
9
+ ("database", "0065_remove_agent_avatar_remove_agent_public_and_more"),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.RemoveField(
14
+ model_name="agent",
15
+ name="tools",
16
+ ),
17
+ migrations.AddField(
18
+ model_name="agent",
19
+ name="input_tools",
20
+ field=django.contrib.postgres.fields.ArrayField(
21
+ base_field=models.CharField(
22
+ choices=[
23
+ ("general", "General"),
24
+ ("online", "Online"),
25
+ ("notes", "Notes"),
26
+ ("summarize", "Summarize"),
27
+ ("webpage", "Webpage"),
28
+ ],
29
+ max_length=200,
30
+ ),
31
+ default=list,
32
+ size=None,
33
+ ),
34
+ ),
35
+ migrations.AddField(
36
+ model_name="agent",
37
+ name="output_modes",
38
+ field=django.contrib.postgres.fields.ArrayField(
39
+ base_field=models.CharField(choices=[("text", "Text"), ("image", "Image")], max_length=200),
40
+ default=list,
41
+ size=None,
42
+ ),
43
+ ),
44
+ migrations.AlterField(
45
+ model_name="agent",
46
+ name="style_icon",
47
+ field=models.CharField(
48
+ choices=[
49
+ ("Lightbulb", "Lightbulb"),
50
+ ("Health", "Health"),
51
+ ("Robot", "Robot"),
52
+ ("Aperture", "Aperture"),
53
+ ("GraduationCap", "Graduation Cap"),
54
+ ("Jeep", "Jeep"),
55
+ ("Island", "Island"),
56
+ ("MathOperations", "Math Operations"),
57
+ ("Asclepius", "Asclepius"),
58
+ ("Couch", "Couch"),
59
+ ("Code", "Code"),
60
+ ("Atom", "Atom"),
61
+ ("ClockCounterClockwise", "Clock Counter Clockwise"),
62
+ ("PencilLine", "Pencil Line"),
63
+ ("Chalkboard", "Chalkboard"),
64
+ ],
65
+ default="Lightbulb",
66
+ max_length=200,
67
+ ),
68
+ ),
69
+ ]
@@ -0,0 +1,50 @@
1
+ # Generated by Django 5.0.8 on 2024-10-01 18:42
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+ dependencies = [
8
+ ("database", "0066_remove_agent_tools_agent_input_tools_and_more"),
9
+ ]
10
+
11
+ operations = [
12
+ migrations.AlterField(
13
+ model_name="agent",
14
+ name="style_icon",
15
+ field=models.CharField(
16
+ choices=[
17
+ ("Lightbulb", "Lightbulb"),
18
+ ("Health", "Health"),
19
+ ("Robot", "Robot"),
20
+ ("Aperture", "Aperture"),
21
+ ("GraduationCap", "Graduation Cap"),
22
+ ("Jeep", "Jeep"),
23
+ ("Island", "Island"),
24
+ ("MathOperations", "Math Operations"),
25
+ ("Asclepius", "Asclepius"),
26
+ ("Couch", "Couch"),
27
+ ("Code", "Code"),
28
+ ("Atom", "Atom"),
29
+ ("ClockCounterClockwise", "Clock Counter Clockwise"),
30
+ ("PencilLine", "Pencil Line"),
31
+ ("Chalkboard", "Chalkboard"),
32
+ ("Cigarette", "Cigarette"),
33
+ ("CraneTower", "Crane Tower"),
34
+ ("Heart", "Heart"),
35
+ ("Leaf", "Leaf"),
36
+ ("NewspaperClipping", "Newspaper Clipping"),
37
+ ("OrangeSlice", "Orange Slice"),
38
+ ("SmileyMelting", "Smiley Melting"),
39
+ ("YinYang", "Yin Yang"),
40
+ ("SneakerMove", "Sneaker Move"),
41
+ ("Student", "Student"),
42
+ ("Oven", "Oven"),
43
+ ("Gavel", "Gavel"),
44
+ ("Broadcast", "Broadcast"),
45
+ ],
46
+ default="Lightbulb",
47
+ max_length=200,
48
+ ),
49
+ ),
50
+ ]
@@ -0,0 +1,24 @@
1
+ # Generated by Django 5.0.8 on 2024-10-17 18:13
2
+
3
+ import django.contrib.postgres.fields
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+ dependencies = [
9
+ ("database", "0067_alter_agent_style_icon"),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterField(
14
+ model_name="agent",
15
+ name="output_modes",
16
+ field=django.contrib.postgres.fields.ArrayField(
17
+ base_field=models.CharField(
18
+ choices=[("text", "Text"), ("image", "Image"), ("automation", "Automation")], max_length=200
19
+ ),
20
+ default=list,
21
+ size=None,
22
+ ),
23
+ ),
24
+ ]
@@ -0,0 +1,89 @@
1
+ # Generated by Django 5.0.8 on 2024-10-18 00:41
2
+
3
+ import django.db.models.deletion
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+ dependencies = [
9
+ ("database", "0068_alter_agent_output_modes"),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.CreateModel(
14
+ name="WebScraper",
15
+ fields=[
16
+ ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
17
+ ("created_at", models.DateTimeField(auto_now_add=True)),
18
+ ("updated_at", models.DateTimeField(auto_now=True)),
19
+ (
20
+ "name",
21
+ models.CharField(
22
+ blank=True,
23
+ default=None,
24
+ help_text="Friendly name. If not set, it will be set to the type of the scraper.",
25
+ max_length=200,
26
+ null=True,
27
+ unique=True,
28
+ ),
29
+ ),
30
+ (
31
+ "type",
32
+ models.CharField(
33
+ choices=[
34
+ ("Firecrawl", "Firecrawl"),
35
+ ("Olostep", "Olostep"),
36
+ ("Jina", "Jina"),
37
+ ("Direct", "Direct"),
38
+ ],
39
+ default="Jina",
40
+ max_length=20,
41
+ ),
42
+ ),
43
+ (
44
+ "api_key",
45
+ models.CharField(
46
+ blank=True,
47
+ default=None,
48
+ help_text="API key of the web scraper. Only set if scraper service requires an API key. Default is set from env var.",
49
+ max_length=200,
50
+ null=True,
51
+ ),
52
+ ),
53
+ (
54
+ "api_url",
55
+ models.URLField(
56
+ blank=True,
57
+ default=None,
58
+ help_text="API URL of the web scraper. Only set if scraper service on non-default URL.",
59
+ null=True,
60
+ ),
61
+ ),
62
+ (
63
+ "priority",
64
+ models.IntegerField(
65
+ blank=True,
66
+ default=None,
67
+ help_text="Priority of the web scraper. Lower numbers run first.",
68
+ null=True,
69
+ unique=True,
70
+ ),
71
+ ),
72
+ ],
73
+ options={
74
+ "abstract": False,
75
+ },
76
+ ),
77
+ migrations.AddField(
78
+ model_name="serverchatsettings",
79
+ name="web_scraper",
80
+ field=models.ForeignKey(
81
+ blank=True,
82
+ default=None,
83
+ null=True,
84
+ on_delete=django.db.models.deletion.CASCADE,
85
+ related_name="web_scraper",
86
+ to="database.webscraper",
87
+ ),
88
+ ),
89
+ ]
@@ -1,8 +1,10 @@
1
+ import os
1
2
  import re
2
3
  import uuid
3
4
  from random import choice
4
5
 
5
6
  from django.contrib.auth.models import AbstractUser
7
+ from django.contrib.postgres.fields import ArrayField
6
8
  from django.core.exceptions import ValidationError
7
9
  from django.db import models
8
10
  from django.db.models.signals import pre_save
@@ -125,7 +127,7 @@ class Agent(BaseModel):
125
127
  EMERALD = "emerald"
126
128
 
127
129
  class StyleIconTypes(models.TextChoices):
128
- LIGHBULB = "Lightbulb"
130
+ LIGHTBULB = "Lightbulb"
129
131
  HEALTH = "Health"
130
132
  ROBOT = "Robot"
131
133
  APERTURE = "Aperture"
@@ -140,20 +142,65 @@ class Agent(BaseModel):
140
142
  CLOCK_COUNTER_CLOCKWISE = "ClockCounterClockwise"
141
143
  PENCIL_LINE = "PencilLine"
142
144
  CHALKBOARD = "Chalkboard"
145
+ CIGARETTE = "Cigarette"
146
+ CRANE_TOWER = "CraneTower"
147
+ HEART = "Heart"
148
+ LEAF = "Leaf"
149
+ NEWSPAPER_CLIPPING = "NewspaperClipping"
150
+ ORANGE_SLICE = "OrangeSlice"
151
+ SMILEY_MELTING = "SmileyMelting"
152
+ YIN_YANG = "YinYang"
153
+ SNEAKER_MOVE = "SneakerMove"
154
+ STUDENT = "Student"
155
+ OVEN = "Oven"
156
+ GAVEL = "Gavel"
157
+ BROADCAST = "Broadcast"
158
+
159
+ class PrivacyLevel(models.TextChoices):
160
+ PUBLIC = "public"
161
+ PRIVATE = "private"
162
+ PROTECTED = "protected"
163
+
164
+ class InputToolOptions(models.TextChoices):
165
+ # These map to various ConversationCommand types
166
+ GENERAL = "general"
167
+ ONLINE = "online"
168
+ NOTES = "notes"
169
+ SUMMARIZE = "summarize"
170
+ WEBPAGE = "webpage"
171
+
172
+ class OutputModeOptions(models.TextChoices):
173
+ # These map to various ConversationCommand types
174
+ TEXT = "text"
175
+ IMAGE = "image"
176
+ AUTOMATION = "automation"
143
177
 
144
178
  creator = models.ForeignKey(
145
179
  KhojUser, on_delete=models.CASCADE, default=None, null=True, blank=True
146
180
  ) # Creator will only be null when the agents are managed by admin
147
181
  name = models.CharField(max_length=200)
148
182
  personality = models.TextField()
149
- avatar = models.URLField(max_length=400, default=None, null=True, blank=True)
150
- tools = models.JSONField(default=list) # List of tools the agent has access to, like online search or notes search
151
- public = models.BooleanField(default=False)
183
+ input_tools = ArrayField(models.CharField(max_length=200, choices=InputToolOptions.choices), default=list)
184
+ output_modes = ArrayField(models.CharField(max_length=200, choices=OutputModeOptions.choices), default=list)
152
185
  managed_by_admin = models.BooleanField(default=False)
153
186
  chat_model = models.ForeignKey(ChatModelOptions, on_delete=models.CASCADE)
154
- slug = models.CharField(max_length=200)
187
+ slug = models.CharField(max_length=200, unique=True)
155
188
  style_color = models.CharField(max_length=200, choices=StyleColorTypes.choices, default=StyleColorTypes.BLUE)
156
- style_icon = models.CharField(max_length=200, choices=StyleIconTypes.choices, default=StyleIconTypes.LIGHBULB)
189
+ style_icon = models.CharField(max_length=200, choices=StyleIconTypes.choices, default=StyleIconTypes.LIGHTBULB)
190
+ privacy_level = models.CharField(max_length=30, choices=PrivacyLevel.choices, default=PrivacyLevel.PRIVATE)
191
+
192
+ def save(self, *args, **kwargs):
193
+ is_new = self._state.adding
194
+
195
+ if self.creator is None:
196
+ self.managed_by_admin = True
197
+
198
+ if is_new:
199
+ random_sequence = "".join(choice("0123456789") for i in range(6))
200
+ slug = f"{self.name.lower().replace(' ', '-')}-{random_sequence}"
201
+ self.slug = slug
202
+
203
+ super().save(*args, **kwargs)
157
204
 
158
205
 
159
206
  class ProcessLock(BaseModel):
@@ -173,22 +220,11 @@ class ProcessLock(BaseModel):
173
220
  def verify_agent(sender, instance, **kwargs):
174
221
  # check if this is a new instance
175
222
  if instance._state.adding:
176
- if Agent.objects.filter(name=instance.name, public=True).exists():
223
+ if Agent.objects.filter(name=instance.name, privacy_level=Agent.PrivacyLevel.PUBLIC).exists():
177
224
  raise ValidationError(f"A public Agent with the name {instance.name} already exists.")
178
225
  if Agent.objects.filter(name=instance.name, creator=instance.creator).exists():
179
226
  raise ValidationError(f"A private Agent with the name {instance.name} already exists.")
180
227
 
181
- slug = instance.name.lower().replace(" ", "-")
182
- observed_random_numbers = set()
183
- while Agent.objects.filter(slug=slug).exists():
184
- try:
185
- random_number = choice([i for i in range(0, 1000) if i not in observed_random_numbers])
186
- except IndexError:
187
- raise ValidationError("Unable to generate a unique slug for the Agent. Please try again later.")
188
- observed_random_numbers.add(random_number)
189
- slug = f"{slug}-{random_number}"
190
- instance.slug = slug
191
-
192
228
 
193
229
  class NotionConfig(BaseModel):
194
230
  token = models.CharField(max_length=200)
@@ -207,6 +243,79 @@ class GithubRepoConfig(BaseModel):
207
243
  github_config = models.ForeignKey(GithubConfig, on_delete=models.CASCADE, related_name="githubrepoconfig")
208
244
 
209
245
 
246
+ class WebScraper(BaseModel):
247
+ class WebScraperType(models.TextChoices):
248
+ FIRECRAWL = "Firecrawl"
249
+ OLOSTEP = "Olostep"
250
+ JINA = "Jina"
251
+ DIRECT = "Direct"
252
+
253
+ name = models.CharField(
254
+ max_length=200,
255
+ default=None,
256
+ null=True,
257
+ blank=True,
258
+ unique=True,
259
+ help_text="Friendly name. If not set, it will be set to the type of the scraper.",
260
+ )
261
+ type = models.CharField(max_length=20, choices=WebScraperType.choices, default=WebScraperType.JINA)
262
+ api_key = models.CharField(
263
+ max_length=200,
264
+ default=None,
265
+ null=True,
266
+ blank=True,
267
+ help_text="API key of the web scraper. Only set if scraper service requires an API key. Default is set from env var.",
268
+ )
269
+ api_url = models.URLField(
270
+ max_length=200,
271
+ default=None,
272
+ null=True,
273
+ blank=True,
274
+ help_text="API URL of the web scraper. Only set if scraper service on non-default URL.",
275
+ )
276
+ priority = models.IntegerField(
277
+ default=None,
278
+ null=True,
279
+ blank=True,
280
+ unique=True,
281
+ help_text="Priority of the web scraper. Lower numbers run first.",
282
+ )
283
+
284
+ def clean(self):
285
+ error = {}
286
+ if self.name is None:
287
+ self.name = self.type.capitalize()
288
+ if self.api_url is None:
289
+ if self.type == self.WebScraperType.FIRECRAWL:
290
+ self.api_url = os.getenv("FIRECRAWL_API_URL", "https://api.firecrawl.dev")
291
+ elif self.type == self.WebScraperType.OLOSTEP:
292
+ self.api_url = os.getenv("OLOSTEP_API_URL", "https://agent.olostep.com/olostep-p2p-incomingAPI")
293
+ elif self.type == self.WebScraperType.JINA:
294
+ self.api_url = os.getenv("JINA_READER_API_URL", "https://r.jina.ai/")
295
+ if self.api_key is None:
296
+ if self.type == self.WebScraperType.FIRECRAWL:
297
+ self.api_key = os.getenv("FIRECRAWL_API_KEY")
298
+ if not self.api_key and self.api_url == "https://api.firecrawl.dev":
299
+ error["api_key"] = "Set API key to use default Firecrawl. Get API key from https://firecrawl.dev."
300
+ elif self.type == self.WebScraperType.OLOSTEP:
301
+ self.api_key = os.getenv("OLOSTEP_API_KEY")
302
+ if self.api_key is None:
303
+ error["api_key"] = "Set API key to use Olostep. Get API key from https://olostep.com/."
304
+ elif self.type == self.WebScraperType.JINA:
305
+ self.api_key = os.getenv("JINA_API_KEY")
306
+ if error:
307
+ raise ValidationError(error)
308
+
309
+ def save(self, *args, **kwargs):
310
+ self.clean()
311
+
312
+ if self.priority is None:
313
+ max_priority = WebScraper.objects.aggregate(models.Max("priority"))["priority__max"]
314
+ self.priority = max_priority + 1 if max_priority else 1
315
+
316
+ super().save(*args, **kwargs)
317
+
318
+
210
319
  class ServerChatSettings(BaseModel):
211
320
  chat_default = models.ForeignKey(
212
321
  ChatModelOptions, on_delete=models.CASCADE, default=None, null=True, blank=True, related_name="chat_default"
@@ -214,6 +323,9 @@ class ServerChatSettings(BaseModel):
214
323
  chat_advanced = models.ForeignKey(
215
324
  ChatModelOptions, on_delete=models.CASCADE, default=None, null=True, blank=True, related_name="chat_advanced"
216
325
  )
326
+ web_scraper = models.ForeignKey(
327
+ WebScraper, on_delete=models.CASCADE, default=None, null=True, blank=True, related_name="web_scraper"
328
+ )
217
329
 
218
330
 
219
331
  class LocalOrgConfig(BaseModel):
@@ -406,6 +518,7 @@ class Entry(BaseModel):
406
518
  GITHUB = "github"
407
519
 
408
520
  user = models.ForeignKey(KhojUser, on_delete=models.CASCADE, default=None, null=True, blank=True)
521
+ agent = models.ForeignKey(Agent, on_delete=models.CASCADE, default=None, null=True, blank=True)
409
522
  embeddings = VectorField(dimensions=None)
410
523
  raw = models.TextField()
411
524
  compiled = models.TextField()
@@ -418,12 +531,17 @@ class Entry(BaseModel):
418
531
  hashed_value = models.CharField(max_length=100)
419
532
  corpus_id = models.UUIDField(default=uuid.uuid4, editable=False)
420
533
 
534
+ def save(self, *args, **kwargs):
535
+ if self.user and self.agent:
536
+ raise ValidationError("An Entry cannot be associated with both a user and an agent.")
537
+
421
538
 
422
539
  class FileObject(BaseModel):
423
540
  # Same as Entry but raw will be a much larger string
424
541
  file_name = models.CharField(max_length=400, default=None, null=True, blank=True)
425
542
  raw_text = models.TextField()
426
543
  user = models.ForeignKey(KhojUser, on_delete=models.CASCADE, default=None, null=True, blank=True)
544
+ agent = models.ForeignKey(Agent, on_delete=models.CASCADE, default=None, null=True, blank=True)
427
545
 
428
546
 
429
547
  class EntryDates(BaseModel):
@@ -1 +1 @@
1
- <!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" href="/_next/static/media/0e790e04fd40ad16-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/css/1538cedb321e3a97.css" data-precedence="next"/><link rel="stylesheet" href="/_next/static/css/24f141a6e37cd204.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-d4781cada9b58e75.js"/><script src="/_next/static/chunks/fd9d1056-2b978342deb60015.js" async=""></script><script src="/_next/static/chunks/7023-a5bf5744d19b3bd3.js" async=""></script><script src="/_next/static/chunks/main-app-6d6ee3495efe03d4.js" async=""></script><meta name="robots" content="noindex"/><meta http-equiv="Content-Security-Policy" content="default-src &#x27;self&#x27; https://assets.khoj.dev; media-src * blob:; script-src &#x27;self&#x27; https://assets.khoj.dev &#x27;unsafe-inline&#x27; &#x27;unsafe-eval&#x27;; connect-src &#x27;self&#x27; blob: https://ipapi.co/json ws://localhost:42110; style-src &#x27;self&#x27; https://assets.khoj.dev &#x27;unsafe-inline&#x27; https://fonts.googleapis.com; img-src &#x27;self&#x27; data: blob: https://*.khoj.dev https://*.googleusercontent.com https://*.google.com/ https://*.gstatic.com; font-src &#x27;self&#x27; https://assets.khoj.dev https://fonts.gstatic.com; child-src &#x27;none&#x27;; object-src &#x27;none&#x27;;"/><title>404: This page could not be found.</title><title>Khoj AI - Home</title><meta name="description" content="Your Second Brain."/><link rel="manifest" href="/static/khoj.webmanifest" crossorigin="use-credentials"/><meta property="og:title" content="Khoj AI - Home"/><meta property="og:description" content="Your Second Brain."/><meta property="og:url" content="https://app.khoj.dev/"/><meta property="og:site_name" content="Khoj AI"/><meta property="og:image" content="https://assets.khoj.dev/khoj_lantern_256x256.png"/><meta property="og:image:width" content="256"/><meta property="og:image:height" content="256"/><meta property="og:image" content="https://assets.khoj.dev/khoj_lantern_logomarktype_1200x630.png"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:type" content="website"/><meta name="twitter:card" content="summary_large_image"/><meta name="twitter:title" content="Khoj AI - Home"/><meta name="twitter:description" content="Your Second Brain."/><meta name="twitter:image" content="https://assets.khoj.dev/khoj_lantern_256x256.png"/><meta name="twitter:image:width" content="256"/><meta name="twitter:image:height" content="256"/><meta name="twitter:image" content="https://assets.khoj.dev/khoj_lantern_logomarktype_1200x630.png"/><meta name="twitter:image:width" content="1200"/><meta name="twitter:image:height" content="630"/><link rel="icon" href="/static/assets/icons/khoj_lantern.ico"/><link rel="apple-touch-icon" href="/static/assets/icons/khoj_lantern_256x256.png"/><meta name="next-size-adjust"/><script src="/_next/static/chunks/polyfills-78c92fac7aa8fdd8.js" noModule=""></script></head><body class="__className_90df87"><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><script src="/_next/static/chunks/webpack-d4781cada9b58e75.js" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0]);self.__next_f.push([2,null])</script><script>self.__next_f.push([1,"1:HL[\"/_next/static/media/0e790e04fd40ad16-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n2:HL[\"/_next/static/css/1538cedb321e3a97.css\",\"style\"]\n3:HL[\"/_next/static/css/24f141a6e37cd204.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"4:I[95751,[],\"\"]\n6:I[39275,[],\"\"]\n7:I[61343,[],\"\"]\nd:I[76130,[],\"\"]\n8:{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"}\n9:{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"}\na:{\"display\":\"inline-block\"}\nb:{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0}\ne:[]\n"])</script><script>self.__next_f.push([1,"0:[\"$\",\"$L4\",null,{\"buildId\":\"_29ceahp81LhuIHo5QgOD\",\"assetPrefix\":\"\",\"urlParts\":[\"\",\"_not-found\",\"\"],\"initialTree\":[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],\"initialSeedData\":[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{},[[\"$L5\",[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":\"404\"}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],null],null],null]},[null,[\"$\",\"$L6\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\",\"/_not-found\",\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L7\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"notFoundStyles\":\"$undefined\"}]],null]},[[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/1538cedb321e3a97.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\"}],[\"$\",\"link\",\"1\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/24f141a6e37cd204.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"children\":[[\"$\",\"meta\",null,{\"httpEquiv\":\"Content-Security-Policy\",\"content\":\"default-src 'self' https://assets.khoj.dev; media-src * blob:; script-src 'self' https://assets.khoj.dev 'unsafe-inline' 'unsafe-eval'; connect-src 'self' blob: https://ipapi.co/json ws://localhost:42110; style-src 'self' https://assets.khoj.dev 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: blob: https://*.khoj.dev https://*.googleusercontent.com https://*.google.com/ https://*.gstatic.com; font-src 'self' https://assets.khoj.dev https://fonts.gstatic.com; child-src 'none'; object-src 'none';\"}],[\"$\",\"body\",null,{\"className\":\"__className_90df87\",\"children\":[\"$\",\"$L6\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L7\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":\"$8\",\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":\"$9\",\"children\":\"404\"}],[\"$\",\"div\",null,{\"style\":\"$a\",\"children\":[\"$\",\"h2\",null,{\"style\":\"$b\",\"children\":\"This page could not be found.\"}]}]]}]}]],\"notFoundStyles\":[]}]}]]}]],null],null],\"couldBeIntercepted\":false,\"initialHead\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],\"$Lc\"],\"globalErrorComponent\":\"$d\",\"missingSlots\":\"$We\"}]\n"])</script><script>self.__next_f.push([1,"c:[[\"$\",\"meta\",\"0\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"1\",{\"charSet\":\"utf-8\"}],[\"$\",\"title\",\"2\",{\"children\":\"Khoj AI - Home\"}],[\"$\",\"meta\",\"3\",{\"name\":\"description\",\"content\":\"Your Second Brain.\"}],[\"$\",\"link\",\"4\",{\"rel\":\"manifest\",\"href\":\"/static/khoj.webmanifest\",\"crossOrigin\":\"use-credentials\"}],[\"$\",\"meta\",\"5\",{\"property\":\"og:title\",\"content\":\"Khoj AI - Home\"}],[\"$\",\"meta\",\"6\",{\"property\":\"og:description\",\"content\":\"Your Second Brain.\"}],[\"$\",\"meta\",\"7\",{\"property\":\"og:url\",\"content\":\"https://app.khoj.dev/\"}],[\"$\",\"meta\",\"8\",{\"property\":\"og:site_name\",\"content\":\"Khoj AI\"}],[\"$\",\"meta\",\"9\",{\"property\":\"og:image\",\"content\":\"https://assets.khoj.dev/khoj_lantern_256x256.png\"}],[\"$\",\"meta\",\"10\",{\"property\":\"og:image:width\",\"content\":\"256\"}],[\"$\",\"meta\",\"11\",{\"property\":\"og:image:height\",\"content\":\"256\"}],[\"$\",\"meta\",\"12\",{\"property\":\"og:image\",\"content\":\"https://assets.khoj.dev/khoj_lantern_logomarktype_1200x630.png\"}],[\"$\",\"meta\",\"13\",{\"property\":\"og:image:width\",\"content\":\"1200\"}],[\"$\",\"meta\",\"14\",{\"property\":\"og:image:height\",\"content\":\"630\"}],[\"$\",\"meta\",\"15\",{\"property\":\"og:type\",\"content\":\"website\"}],[\"$\",\"meta\",\"16\",{\"name\":\"twitter:card\",\"content\":\"summary_large_image\"}],[\"$\",\"meta\",\"17\",{\"name\":\"twitter:title\",\"content\":\"Khoj AI - Home\"}],[\"$\",\"meta\",\"18\",{\"name\":\"twitter:description\",\"content\":\"Your Second Brain.\"}],[\"$\",\"meta\",\"19\",{\"name\":\"twitter:image\",\"content\":\"https://assets.khoj.dev/khoj_lantern_256x256.png\"}],[\"$\",\"meta\",\"20\",{\"name\":\"twitter:image:width\",\"content\":\"256\"}],[\"$\",\"meta\",\"21\",{\"name\":\"twitter:image:height\",\"content\":\"256\"}],[\"$\",\"meta\",\"22\",{\"name\":\"twitter:image\",\"content\":\"https://assets.khoj.dev/khoj_lantern_logomarktype_1200x630.png\"}],[\"$\",\"meta\",\"23\",{\"name\":\"twitter:image:width\",\"content\":\"1200\"}],[\"$\",\"meta\",\"24\",{\"name\":\"twitter:image:height\",\"content\":\"630\"}],[\"$\",\"link\",\"25\",{\"rel\":\"icon\",\"href\":\"/static/assets/icons/khoj_lantern.ico\"}],[\"$\",\"link\",\"26\",{\"rel\":\"apple-touch-icon\",\"href\":\"/static/assets/icons/khoj_lantern_256x256.png\"}],[\"$\",\"meta\",\"27\",{\"name\":\"next-size-adjust\"}]]\n"])</script><script>self.__next_f.push([1,"5:null\n"])</script></body></html>
1
+ <!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" href="/_next/static/media/0e790e04fd40ad16-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/css/467a524c75e7d7c0.css" data-precedence="next"/><link rel="stylesheet" href="/_next/static/css/b9a6bf04305d98d7.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-c0cd5a6afb1f0798.js"/><script src="/_next/static/chunks/fd9d1056-2b978342deb60015.js" async=""></script><script src="/_next/static/chunks/7023-a5bf5744d19b3bd3.js" async=""></script><script src="/_next/static/chunks/main-app-6d6ee3495efe03d4.js" async=""></script><meta name="robots" content="noindex"/><meta http-equiv="Content-Security-Policy" content="default-src &#x27;self&#x27; https://assets.khoj.dev; media-src * blob:; script-src &#x27;self&#x27; https://assets.khoj.dev &#x27;unsafe-inline&#x27; &#x27;unsafe-eval&#x27;; connect-src &#x27;self&#x27; blob: https://ipapi.co/json ws://localhost:42110; style-src &#x27;self&#x27; https://assets.khoj.dev &#x27;unsafe-inline&#x27; https://fonts.googleapis.com; img-src &#x27;self&#x27; data: blob: https://*.khoj.dev https://*.googleusercontent.com https://*.google.com/ https://*.gstatic.com; font-src &#x27;self&#x27; https://assets.khoj.dev https://fonts.gstatic.com; child-src &#x27;none&#x27;; object-src &#x27;none&#x27;;"/><title>404: This page could not be found.</title><title>Khoj AI - Home</title><meta name="description" content="Your Second Brain."/><link rel="manifest" href="/static/khoj.webmanifest" crossorigin="use-credentials"/><meta property="og:title" content="Khoj AI - Home"/><meta property="og:description" content="Your Second Brain."/><meta property="og:url" content="https://app.khoj.dev/"/><meta property="og:site_name" content="Khoj AI"/><meta property="og:image" content="https://assets.khoj.dev/khoj_lantern_256x256.png"/><meta property="og:image:width" content="256"/><meta property="og:image:height" content="256"/><meta property="og:image" content="https://assets.khoj.dev/khoj_lantern_logomarktype_1200x630.png"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:type" content="website"/><meta name="twitter:card" content="summary_large_image"/><meta name="twitter:title" content="Khoj AI - Home"/><meta name="twitter:description" content="Your Second Brain."/><meta name="twitter:image" content="https://assets.khoj.dev/khoj_lantern_256x256.png"/><meta name="twitter:image:width" content="256"/><meta name="twitter:image:height" content="256"/><meta name="twitter:image" content="https://assets.khoj.dev/khoj_lantern_logomarktype_1200x630.png"/><meta name="twitter:image:width" content="1200"/><meta name="twitter:image:height" content="630"/><link rel="icon" href="/static/assets/icons/khoj_lantern.ico"/><link rel="apple-touch-icon" href="/static/assets/icons/khoj_lantern_256x256.png"/><meta name="next-size-adjust"/><script src="/_next/static/chunks/polyfills-78c92fac7aa8fdd8.js" noModule=""></script></head><body class="__className_e594dd"><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><script src="/_next/static/chunks/webpack-c0cd5a6afb1f0798.js" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0]);self.__next_f.push([2,null])</script><script>self.__next_f.push([1,"1:HL[\"/_next/static/media/0e790e04fd40ad16-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n2:HL[\"/_next/static/css/467a524c75e7d7c0.css\",\"style\"]\n3:HL[\"/_next/static/css/b9a6bf04305d98d7.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"4:I[95751,[],\"\"]\n6:I[39275,[],\"\"]\n7:I[61343,[],\"\"]\nd:I[76130,[],\"\"]\n8:{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"}\n9:{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"}\na:{\"display\":\"inline-block\"}\nb:{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0}\ne:[]\n"])</script><script>self.__next_f.push([1,"0:[\"$\",\"$L4\",null,{\"buildId\":\"Jid9q6Qg851ioDaaO_fth\",\"assetPrefix\":\"\",\"urlParts\":[\"\",\"_not-found\",\"\"],\"initialTree\":[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],\"initialSeedData\":[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{},[[\"$L5\",[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":\"404\"}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],null],null],null]},[null,[\"$\",\"$L6\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\",\"/_not-found\",\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L7\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"notFoundStyles\":\"$undefined\"}]],null]},[[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/467a524c75e7d7c0.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\"}],[\"$\",\"link\",\"1\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/b9a6bf04305d98d7.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"children\":[[\"$\",\"meta\",null,{\"httpEquiv\":\"Content-Security-Policy\",\"content\":\"default-src 'self' https://assets.khoj.dev; media-src * blob:; script-src 'self' https://assets.khoj.dev 'unsafe-inline' 'unsafe-eval'; connect-src 'self' blob: https://ipapi.co/json ws://localhost:42110; style-src 'self' https://assets.khoj.dev 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: blob: https://*.khoj.dev https://*.googleusercontent.com https://*.google.com/ https://*.gstatic.com; font-src 'self' https://assets.khoj.dev https://fonts.gstatic.com; child-src 'none'; object-src 'none';\"}],[\"$\",\"body\",null,{\"className\":\"__className_e594dd\",\"children\":[\"$\",\"$L6\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L7\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":\"$8\",\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":\"$9\",\"children\":\"404\"}],[\"$\",\"div\",null,{\"style\":\"$a\",\"children\":[\"$\",\"h2\",null,{\"style\":\"$b\",\"children\":\"This page could not be found.\"}]}]]}]}]],\"notFoundStyles\":[]}]}]]}]],null],null],\"couldBeIntercepted\":false,\"initialHead\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],\"$Lc\"],\"globalErrorComponent\":\"$d\",\"missingSlots\":\"$We\"}]\n"])</script><script>self.__next_f.push([1,"c:[[\"$\",\"meta\",\"0\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"1\",{\"charSet\":\"utf-8\"}],[\"$\",\"title\",\"2\",{\"children\":\"Khoj AI - Home\"}],[\"$\",\"meta\",\"3\",{\"name\":\"description\",\"content\":\"Your Second Brain.\"}],[\"$\",\"link\",\"4\",{\"rel\":\"manifest\",\"href\":\"/static/khoj.webmanifest\",\"crossOrigin\":\"use-credentials\"}],[\"$\",\"meta\",\"5\",{\"property\":\"og:title\",\"content\":\"Khoj AI - Home\"}],[\"$\",\"meta\",\"6\",{\"property\":\"og:description\",\"content\":\"Your Second Brain.\"}],[\"$\",\"meta\",\"7\",{\"property\":\"og:url\",\"content\":\"https://app.khoj.dev/\"}],[\"$\",\"meta\",\"8\",{\"property\":\"og:site_name\",\"content\":\"Khoj AI\"}],[\"$\",\"meta\",\"9\",{\"property\":\"og:image\",\"content\":\"https://assets.khoj.dev/khoj_lantern_256x256.png\"}],[\"$\",\"meta\",\"10\",{\"property\":\"og:image:width\",\"content\":\"256\"}],[\"$\",\"meta\",\"11\",{\"property\":\"og:image:height\",\"content\":\"256\"}],[\"$\",\"meta\",\"12\",{\"property\":\"og:image\",\"content\":\"https://assets.khoj.dev/khoj_lantern_logomarktype_1200x630.png\"}],[\"$\",\"meta\",\"13\",{\"property\":\"og:image:width\",\"content\":\"1200\"}],[\"$\",\"meta\",\"14\",{\"property\":\"og:image:height\",\"content\":\"630\"}],[\"$\",\"meta\",\"15\",{\"property\":\"og:type\",\"content\":\"website\"}],[\"$\",\"meta\",\"16\",{\"name\":\"twitter:card\",\"content\":\"summary_large_image\"}],[\"$\",\"meta\",\"17\",{\"name\":\"twitter:title\",\"content\":\"Khoj AI - Home\"}],[\"$\",\"meta\",\"18\",{\"name\":\"twitter:description\",\"content\":\"Your Second Brain.\"}],[\"$\",\"meta\",\"19\",{\"name\":\"twitter:image\",\"content\":\"https://assets.khoj.dev/khoj_lantern_256x256.png\"}],[\"$\",\"meta\",\"20\",{\"name\":\"twitter:image:width\",\"content\":\"256\"}],[\"$\",\"meta\",\"21\",{\"name\":\"twitter:image:height\",\"content\":\"256\"}],[\"$\",\"meta\",\"22\",{\"name\":\"twitter:image\",\"content\":\"https://assets.khoj.dev/khoj_lantern_logomarktype_1200x630.png\"}],[\"$\",\"meta\",\"23\",{\"name\":\"twitter:image:width\",\"content\":\"1200\"}],[\"$\",\"meta\",\"24\",{\"name\":\"twitter:image:height\",\"content\":\"630\"}],[\"$\",\"link\",\"25\",{\"rel\":\"icon\",\"href\":\"/static/assets/icons/khoj_lantern.ico\"}],[\"$\",\"link\",\"26\",{\"rel\":\"apple-touch-icon\",\"href\":\"/static/assets/icons/khoj_lantern_256x256.png\"}],[\"$\",\"meta\",\"27\",{\"name\":\"next-size-adjust\"}]]\n"])</script><script>self.__next_f.push([1,"5:null\n"])</script></body></html>