khoj 1.30.11.dev13__py3-none-any.whl → 1.30.11.dev56__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 (89) hide show
  1. khoj/app/settings.py +21 -0
  2. khoj/configure.py +3 -3
  3. khoj/database/adapters/__init__.py +15 -15
  4. khoj/database/admin.py +50 -40
  5. khoj/database/migrations/0075_migrate_generated_assets_and_validate.py +85 -0
  6. khoj/database/migrations/0076_rename_openaiprocessorconversationconfig_aimodelapi_and_more.py +26 -0
  7. khoj/database/models/__init__.py +171 -42
  8. khoj/interface/compiled/404/index.html +1 -1
  9. khoj/interface/compiled/_next/static/chunks/1603-e40aadd1e56ab030.js +1 -0
  10. khoj/interface/compiled/_next/static/chunks/5538-0ea2d3944ca051e1.js +1 -0
  11. khoj/interface/compiled/_next/static/chunks/app/agents/layout-1878cc328ea380bd.js +1 -0
  12. khoj/interface/compiled/_next/static/chunks/app/agents/{page-8eead7920b0ff92a.js → page-f5c0801b27a8e95e.js} +1 -1
  13. khoj/interface/compiled/_next/static/chunks/app/automations/layout-7f1b79a2c67af0b4.js +1 -0
  14. khoj/interface/compiled/_next/static/chunks/app/automations/{page-b5800b5286306140.js → page-8691f6c09a0acd44.js} +1 -1
  15. khoj/interface/compiled/_next/static/chunks/app/chat/layout-9219a85f3477e722.js +1 -0
  16. khoj/interface/compiled/_next/static/chunks/app/chat/{page-d7d2ab93e519f0b2.js → page-135d56dd4263e40d.js} +1 -1
  17. khoj/interface/compiled/_next/static/chunks/app/layout-6310c57b674dd6f5.js +1 -0
  18. khoj/interface/compiled/_next/static/chunks/app/{page-3c32ad5472f75965.js → page-e79ace822d51557b.js} +1 -1
  19. khoj/interface/compiled/_next/static/chunks/app/search/{page-faa998c71eb7ca8e.js → page-e8b578d155550386.js} +1 -1
  20. khoj/interface/compiled/_next/static/chunks/app/settings/layout-f285795bc3154b8c.js +1 -0
  21. khoj/interface/compiled/_next/static/chunks/app/settings/{page-cbe7f56b1f87d77a.js → page-b6c835050c970be7.js} +1 -1
  22. khoj/interface/compiled/_next/static/chunks/app/share/chat/layout-6f4879fbbf8b90f7.js +1 -0
  23. khoj/interface/compiled/_next/static/chunks/app/share/chat/{page-cd5757199539bbf2.js → page-635635e4fb39fe29.js} +1 -1
  24. khoj/interface/compiled/_next/static/chunks/{webpack-3a2dfd74acf6e193.js → webpack-5203c3872078c10c.js} +1 -1
  25. khoj/interface/compiled/_next/static/css/{bedf49fbfc598358.css → 089de1d8526b96e9.css} +1 -1
  26. khoj/interface/compiled/_next/static/css/4cae6c0e5c72fb2d.css +1 -0
  27. khoj/interface/compiled/_next/static/css/edd3abaf11580924.css +1 -0
  28. khoj/interface/compiled/_next/static/media/1d8a05b60287ae6c-s.p.woff2 +0 -0
  29. khoj/interface/compiled/_next/static/media/6f22fce21a7c433c-s.woff2 +0 -0
  30. khoj/interface/compiled/_next/static/media/77c207b095007c34-s.p.woff2 +0 -0
  31. khoj/interface/compiled/_next/static/media/82ef96de0e8f4d8c-s.p.woff2 +0 -0
  32. khoj/interface/compiled/_next/static/media/a6ecd16fa044d500-s.p.woff2 +0 -0
  33. khoj/interface/compiled/_next/static/media/bd82c78e5b7b3fe9-s.p.woff2 +0 -0
  34. khoj/interface/compiled/_next/static/media/c32c8052c071fc42-s.woff2 +0 -0
  35. khoj/interface/compiled/_next/static/media/c4250770ab8708b6-s.p.woff2 +0 -0
  36. khoj/interface/compiled/agents/index.html +1 -1
  37. khoj/interface/compiled/agents/index.txt +2 -2
  38. khoj/interface/compiled/assets/icons/khoj_lantern.svg +100 -0
  39. khoj/interface/compiled/assets/icons/khoj_lantern_128x128_dark.png +0 -0
  40. khoj/interface/compiled/automations/index.html +1 -1
  41. khoj/interface/compiled/automations/index.txt +3 -3
  42. khoj/interface/compiled/chat/index.html +1 -1
  43. khoj/interface/compiled/chat/index.txt +2 -2
  44. khoj/interface/compiled/index.html +1 -1
  45. khoj/interface/compiled/index.txt +2 -2
  46. khoj/interface/compiled/search/index.html +1 -1
  47. khoj/interface/compiled/search/index.txt +2 -2
  48. khoj/interface/compiled/settings/index.html +1 -1
  49. khoj/interface/compiled/settings/index.txt +5 -4
  50. khoj/interface/compiled/share/chat/index.html +1 -1
  51. khoj/interface/compiled/share/chat/index.txt +2 -2
  52. khoj/migrations/migrate_server_pg.py +3 -9
  53. khoj/processor/conversation/anthropic/anthropic_chat.py +11 -3
  54. khoj/processor/conversation/google/gemini_chat.py +11 -3
  55. khoj/processor/conversation/offline/chat_model.py +6 -2
  56. khoj/processor/conversation/openai/gpt.py +10 -2
  57. khoj/processor/conversation/openai/utils.py +1 -6
  58. khoj/processor/conversation/prompts.py +18 -0
  59. khoj/processor/conversation/utils.py +82 -26
  60. khoj/processor/image/generate.py +12 -15
  61. khoj/routers/api.py +5 -5
  62. khoj/routers/api_chat.py +49 -98
  63. khoj/routers/helpers.py +52 -12
  64. khoj/utils/initialization.py +10 -12
  65. {khoj-1.30.11.dev13.dist-info → khoj-1.30.11.dev56.dist-info}/METADATA +2 -1
  66. {khoj-1.30.11.dev13.dist-info → khoj-1.30.11.dev56.dist-info}/RECORD +71 -67
  67. khoj/interface/compiled/_next/static/chunks/1603-c68d44bc4ae6039a.js +0 -1
  68. khoj/interface/compiled/_next/static/chunks/5538-e5f3c9f4d67a64b9.js +0 -1
  69. khoj/interface/compiled/_next/static/chunks/app/agents/layout-f2ea2b26fc0e78b1.js +0 -1
  70. khoj/interface/compiled/_next/static/chunks/app/automations/layout-f1050c1f20a3af67.js +0 -1
  71. khoj/interface/compiled/_next/static/chunks/app/chat/layout-1072c3b0ab136e74.js +0 -1
  72. khoj/interface/compiled/_next/static/chunks/app/layout-72ec1be8afd0b1ab.js +0 -1
  73. khoj/interface/compiled/_next/static/chunks/app/settings/layout-fe8a2f65ccafd142.js +0 -1
  74. khoj/interface/compiled/_next/static/chunks/app/share/chat/layout-dc97434f0354a74e.js +0 -1
  75. khoj/interface/compiled/_next/static/css/2d097a35da6bfe8d.css +0 -1
  76. khoj/interface/compiled/_next/static/css/80bd6301fc657983.css +0 -1
  77. khoj/interface/compiled/_next/static/media/5455839c73f146e7-s.p.woff2 +0 -0
  78. khoj/interface/compiled/_next/static/media/5984b96ba4822821-s.p.woff2 +0 -0
  79. khoj/interface/compiled/_next/static/media/684adc3dde1b03f1-s.p.woff2 +0 -0
  80. khoj/interface/compiled/_next/static/media/82e3b9a1bdaf0c26-s.p.woff2 +0 -0
  81. khoj/interface/compiled/_next/static/media/8d1ea331386a0db8-s.p.woff2 +0 -0
  82. khoj/interface/compiled/_next/static/media/91475f6526542a4f-s.woff2 +0 -0
  83. khoj/interface/compiled/_next/static/media/b98b13dbc1c3b59c-s.p.woff2 +0 -0
  84. khoj/interface/compiled/_next/static/media/c824d7a20139e39d-s.woff2 +0 -0
  85. /khoj/interface/compiled/_next/static/{K_WyVARSz0loPVvwOW1gg → J7Vqh1vjCleYuVLeTaJL6}/_buildManifest.js +0 -0
  86. /khoj/interface/compiled/_next/static/{K_WyVARSz0loPVvwOW1gg → J7Vqh1vjCleYuVLeTaJL6}/_ssgManifest.js +0 -0
  87. {khoj-1.30.11.dev13.dist-info → khoj-1.30.11.dev56.dist-info}/WHEEL +0 -0
  88. {khoj-1.30.11.dev13.dist-info → khoj-1.30.11.dev56.dist-info}/entry_points.txt +0 -0
  89. {khoj-1.30.11.dev13.dist-info → khoj-1.30.11.dev56.dist-info}/licenses/LICENSE +0 -0
khoj/app/settings.py CHANGED
@@ -13,6 +13,8 @@ https://docs.djangoproject.com/en/4.2/ref/settings/
13
13
  import os
14
14
  from pathlib import Path
15
15
 
16
+ from django.templatetags.static import static
17
+
16
18
  from khoj.utils.helpers import in_debug_mode, is_env_var_true
17
19
 
18
20
  # Build paths inside the project like this: BASE_DIR / 'subdir'.
@@ -72,6 +74,7 @@ INSTALLED_APPS = [
72
74
  "django.contrib.auth",
73
75
  "django.contrib.contenttypes",
74
76
  "khoj.database.apps.DatabaseConfig",
77
+ "unfold",
75
78
  "django.contrib.admin",
76
79
  "django.contrib.sessions",
77
80
  "django.contrib.messages",
@@ -195,3 +198,21 @@ APSCHEDULER_DATETIME_FORMAT = "N j, Y, f:s a"
195
198
  # that supports multiple background worker processes instead (e.g. Dramatiq, Celery, Django-RQ,
196
199
  # etc. See: https://djangopackages.org/grids/g/workers-queues-tasks/ for popular options).
197
200
  APSCHEDULER_RUN_NOW_TIMEOUT = 240 # Seconds
201
+
202
+ UNFOLD = {
203
+ "SITE_TITLE": "Khoj Admin Panel",
204
+ "SITE_HEADER": "Khoj Admin Panel",
205
+ "SITE_URL": "/",
206
+ "SITE_ICON": {
207
+ "light": lambda request: static("assets/icons/khoj_lantern_128x128.png"),
208
+ "dark": lambda request: static("assets/icons/khoj_lantern_128x128_dark.png"),
209
+ },
210
+ "SITE_FAVICONS": [
211
+ {
212
+ "rel": "icon",
213
+ "sizes": "32x32",
214
+ "type": "image/svg+xml",
215
+ "href": lambda request: static("assets/icons/khoj_lantern.svg"),
216
+ },
217
+ ],
218
+ }
khoj/configure.py CHANGED
@@ -232,9 +232,9 @@ def configure_server(
232
232
  config = FullConfig()
233
233
  state.config = config
234
234
 
235
- if ConversationAdapters.has_valid_openai_conversation_config():
236
- openai_config = ConversationAdapters.get_openai_conversation_config()
237
- state.openai_client = openai.OpenAI(api_key=openai_config.api_key)
235
+ if ConversationAdapters.has_valid_ai_model_api():
236
+ ai_model_api = ConversationAdapters.get_ai_model_api()
237
+ state.openai_client = openai.OpenAI(api_key=ai_model_api.api_key)
238
238
 
239
239
  # Initialize Search Models from Config and initialize content
240
240
  try:
@@ -35,6 +35,7 @@ from torch import Tensor
35
35
 
36
36
  from khoj.database.models import (
37
37
  Agent,
38
+ AiModelApi,
38
39
  ChatModelOptions,
39
40
  ClientApplication,
40
41
  Conversation,
@@ -46,7 +47,6 @@ from khoj.database.models import (
46
47
  KhojApiUser,
47
48
  KhojUser,
48
49
  NotionConfig,
49
- OpenAIProcessorConversationConfig,
50
50
  ProcessLock,
51
51
  PublicConversation,
52
52
  ReflectiveQuestion,
@@ -981,7 +981,7 @@ class ConversationAdapters:
981
981
 
982
982
  @staticmethod
983
983
  async def aget_all_conversation_configs():
984
- return await sync_to_async(list)(ChatModelOptions.objects.prefetch_related("openai_config").all())
984
+ return await sync_to_async(list)(ChatModelOptions.objects.prefetch_related("ai_model_api").all())
985
985
 
986
986
  @staticmethod
987
987
  def get_vision_enabled_config():
@@ -1000,12 +1000,12 @@ class ConversationAdapters:
1000
1000
  return None
1001
1001
 
1002
1002
  @staticmethod
1003
- def get_openai_conversation_config():
1004
- return OpenAIProcessorConversationConfig.objects.filter().first()
1003
+ def get_ai_model_api():
1004
+ return AiModelApi.objects.filter().first()
1005
1005
 
1006
1006
  @staticmethod
1007
- def has_valid_openai_conversation_config():
1008
- return OpenAIProcessorConversationConfig.objects.filter().exists()
1007
+ def has_valid_ai_model_api():
1008
+ return AiModelApi.objects.filter().exists()
1009
1009
 
1010
1010
  @staticmethod
1011
1011
  @arequire_valid_user
@@ -1093,7 +1093,7 @@ class ConversationAdapters:
1093
1093
  server_chat_settings: ServerChatSettings = (
1094
1094
  await ServerChatSettings.objects.filter()
1095
1095
  .prefetch_related(
1096
- "chat_default", "chat_default__openai_config", "chat_advanced", "chat_advanced__openai_config"
1096
+ "chat_default", "chat_default__ai_model_api", "chat_advanced", "chat_advanced__ai_model_api"
1097
1097
  )
1098
1098
  .afirst()
1099
1099
  )
@@ -1109,7 +1109,7 @@ class ConversationAdapters:
1109
1109
 
1110
1110
  # Get the user's chat settings, if the server chat settings are not set
1111
1111
  user_chat_settings = (
1112
- (await UserConversationConfig.objects.filter(user=user).prefetch_related("setting__openai_config").afirst())
1112
+ (await UserConversationConfig.objects.filter(user=user).prefetch_related("setting__ai_model_api").afirst())
1113
1113
  if user
1114
1114
  else None
1115
1115
  )
@@ -1117,7 +1117,7 @@ class ConversationAdapters:
1117
1117
  return user_chat_settings.setting
1118
1118
 
1119
1119
  # Get the first chat model if even the user chat settings are not set
1120
- return await ChatModelOptions.objects.filter().prefetch_related("openai_config").afirst()
1120
+ return await ChatModelOptions.objects.filter().prefetch_related("ai_model_api").afirst()
1121
1121
 
1122
1122
  @staticmethod
1123
1123
  def get_advanced_conversation_config(user: KhojUser):
@@ -1130,7 +1130,7 @@ class ConversationAdapters:
1130
1130
  async def aget_advanced_conversation_config(user: KhojUser = None):
1131
1131
  server_chat_settings: ServerChatSettings = (
1132
1132
  await ServerChatSettings.objects.filter()
1133
- .prefetch_related("chat_advanced", "chat_advanced__openai_config")
1133
+ .prefetch_related("chat_advanced", "chat_advanced__ai_model_api")
1134
1134
  .afirst()
1135
1135
  )
1136
1136
  if server_chat_settings is not None and server_chat_settings.chat_advanced is not None:
@@ -1258,7 +1258,7 @@ class ConversationAdapters:
1258
1258
  @staticmethod
1259
1259
  async def aget_user_conversation_config(user: KhojUser):
1260
1260
  config = (
1261
- await UserConversationConfig.objects.filter(user=user).prefetch_related("setting__openai_config").afirst()
1261
+ await UserConversationConfig.objects.filter(user=user).prefetch_related("setting__ai_model_api").afirst()
1262
1262
  )
1263
1263
  if not config:
1264
1264
  return None
@@ -1313,7 +1313,7 @@ class ConversationAdapters:
1313
1313
  ChatModelOptions.ModelType.OPENAI,
1314
1314
  ChatModelOptions.ModelType.GOOGLE,
1315
1315
  ]
1316
- ) and conversation_config.openai_config:
1316
+ ) and conversation_config.ai_model_api:
1317
1317
  return conversation_config
1318
1318
 
1319
1319
  else:
@@ -1321,7 +1321,7 @@ class ConversationAdapters:
1321
1321
 
1322
1322
  @staticmethod
1323
1323
  async def aget_text_to_image_model_config():
1324
- return await TextToImageModelConfig.objects.filter().prefetch_related("openai_config").afirst()
1324
+ return await TextToImageModelConfig.objects.filter().prefetch_related("ai_model_api").afirst()
1325
1325
 
1326
1326
  @staticmethod
1327
1327
  def get_text_to_image_model_config():
@@ -1343,9 +1343,9 @@ class ConversationAdapters:
1343
1343
 
1344
1344
  @staticmethod
1345
1345
  async def aget_user_text_to_image_model(user: KhojUser) -> Optional[TextToImageModelConfig]:
1346
- # Create a custom queryset for prefetching settings__openai_config, handling null cases
1346
+ # Create a custom queryset for prefetching settings__ai_model_api, handling null cases
1347
1347
  settings_prefetch = Prefetch(
1348
- "setting", queryset=TextToImageModelConfig.objects.prefetch_related("openai_config")
1348
+ "setting", queryset=TextToImageModelConfig.objects.prefetch_related("ai_model_api")
1349
1349
  )
1350
1350
 
1351
1351
  config = await UserTextToImageModelConfig.objects.filter(user=user).prefetch_related(settings_prefetch).afirst()
khoj/database/admin.py CHANGED
@@ -1,17 +1,21 @@
1
1
  import csv
2
2
  import json
3
- from datetime import date, datetime, timedelta, timezone
3
+ from datetime import datetime, timedelta
4
4
 
5
5
  from apscheduler.job import Job
6
6
  from django.contrib import admin, messages
7
- from django.contrib.auth.admin import UserAdmin
7
+ from django.contrib.auth.admin import GroupAdmin as BaseGroupAdmin
8
+ from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
9
+ from django.contrib.auth.models import Group
8
10
  from django.http import HttpResponse
9
- from django_apscheduler.admin import DjangoJobAdmin
11
+ from django_apscheduler.admin import DjangoJobAdmin, DjangoJobExecutionAdmin
10
12
  from django_apscheduler.jobstores import DjangoJobStore
11
- from django_apscheduler.models import DjangoJob
13
+ from django_apscheduler.models import DjangoJob, DjangoJobExecution
14
+ from unfold import admin as unfold_admin
12
15
 
13
16
  from khoj.database.models import (
14
17
  Agent,
18
+ AiModelApi,
15
19
  ChatModelOptions,
16
20
  ClientApplication,
17
21
  Conversation,
@@ -19,7 +23,6 @@ from khoj.database.models import (
19
23
  GithubConfig,
20
24
  KhojUser,
21
25
  NotionConfig,
22
- OpenAIProcessorConversationConfig,
23
26
  ProcessLock,
24
27
  ReflectiveQuestion,
25
28
  SearchModelConfig,
@@ -35,10 +38,8 @@ from khoj.database.models import (
35
38
  )
36
39
  from khoj.utils.helpers import ImageIntentType
37
40
 
38
- admin.site.unregister(DjangoJob)
39
-
40
41
 
41
- class KhojDjangoJobAdmin(DjangoJobAdmin):
42
+ class KhojDjangoJobAdmin(DjangoJobAdmin, unfold_admin.ModelAdmin):
42
43
  list_display = (
43
44
  "id",
44
45
  "next_run_time",
@@ -62,10 +63,25 @@ class KhojDjangoJobAdmin(DjangoJobAdmin):
62
63
  return queryset, use_distinct
63
64
 
64
65
 
66
+ class KhojDjangoJobExecutionAdmin(DjangoJobExecutionAdmin, unfold_admin.ModelAdmin):
67
+ pass
68
+
69
+
70
+ admin.site.unregister(DjangoJob)
65
71
  admin.site.register(DjangoJob, KhojDjangoJobAdmin)
72
+ admin.site.unregister(DjangoJobExecution)
73
+ admin.site.register(DjangoJobExecution, KhojDjangoJobExecutionAdmin)
66
74
 
67
75
 
68
- class KhojUserAdmin(UserAdmin):
76
+ class GroupAdmin(BaseGroupAdmin, unfold_admin.ModelAdmin):
77
+ pass
78
+
79
+
80
+ class UserAdmin(BaseUserAdmin, unfold_admin.ModelAdmin):
81
+ pass
82
+
83
+
84
+ class KhojUserAdmin(UserAdmin, unfold_admin.ModelAdmin):
69
85
  class DateJoinedAfterFilter(admin.SimpleListFilter):
70
86
  title = "Joined after"
71
87
  parameter_name = "joined_after"
@@ -137,21 +153,22 @@ class KhojUserAdmin(UserAdmin):
137
153
  get_email_login_url.short_description = "Get email login URL" # type: ignore
138
154
 
139
155
 
156
+ admin.site.unregister(Group)
140
157
  admin.site.register(KhojUser, KhojUserAdmin)
141
158
 
142
- admin.site.register(ProcessLock)
143
- admin.site.register(SpeechToTextModelOptions)
144
- admin.site.register(ReflectiveQuestion)
145
- admin.site.register(ClientApplication)
146
- admin.site.register(GithubConfig)
147
- admin.site.register(NotionConfig)
148
- admin.site.register(UserVoiceModelConfig)
149
- admin.site.register(VoiceModelOption)
150
- admin.site.register(UserRequests)
159
+ admin.site.register(ProcessLock, unfold_admin.ModelAdmin)
160
+ admin.site.register(SpeechToTextModelOptions, unfold_admin.ModelAdmin)
161
+ admin.site.register(ReflectiveQuestion, unfold_admin.ModelAdmin)
162
+ admin.site.register(ClientApplication, unfold_admin.ModelAdmin)
163
+ admin.site.register(GithubConfig, unfold_admin.ModelAdmin)
164
+ admin.site.register(NotionConfig, unfold_admin.ModelAdmin)
165
+ admin.site.register(UserVoiceModelConfig, unfold_admin.ModelAdmin)
166
+ admin.site.register(VoiceModelOption, unfold_admin.ModelAdmin)
167
+ admin.site.register(UserRequests, unfold_admin.ModelAdmin)
151
168
 
152
169
 
153
170
  @admin.register(Agent)
154
- class AgentAdmin(admin.ModelAdmin):
171
+ class AgentAdmin(unfold_admin.ModelAdmin):
155
172
  list_display = (
156
173
  "id",
157
174
  "name",
@@ -161,7 +178,7 @@ class AgentAdmin(admin.ModelAdmin):
161
178
 
162
179
 
163
180
  @admin.register(Entry)
164
- class EntryAdmin(admin.ModelAdmin):
181
+ class EntryAdmin(unfold_admin.ModelAdmin):
165
182
  list_display = (
166
183
  "id",
167
184
  "created_at",
@@ -183,7 +200,7 @@ class EntryAdmin(admin.ModelAdmin):
183
200
 
184
201
 
185
202
  @admin.register(Subscription)
186
- class KhojUserSubscription(admin.ModelAdmin):
203
+ class KhojUserSubscription(unfold_admin.ModelAdmin):
187
204
  list_display = (
188
205
  "id",
189
206
  "user",
@@ -195,7 +212,7 @@ class KhojUserSubscription(admin.ModelAdmin):
195
212
 
196
213
 
197
214
  @admin.register(ChatModelOptions)
198
- class ChatModelOptionsAdmin(admin.ModelAdmin):
215
+ class ChatModelOptionsAdmin(unfold_admin.ModelAdmin):
199
216
  list_display = (
200
217
  "id",
201
218
  "chat_model",
@@ -206,7 +223,7 @@ class ChatModelOptionsAdmin(admin.ModelAdmin):
206
223
 
207
224
 
208
225
  @admin.register(TextToImageModelConfig)
209
- class TextToImageModelOptionsAdmin(admin.ModelAdmin):
226
+ class TextToImageModelOptionsAdmin(unfold_admin.ModelAdmin):
210
227
  list_display = (
211
228
  "id",
212
229
  "model_name",
@@ -215,8 +232,8 @@ class TextToImageModelOptionsAdmin(admin.ModelAdmin):
215
232
  search_fields = ("id", "model_name", "model_type")
216
233
 
217
234
 
218
- @admin.register(OpenAIProcessorConversationConfig)
219
- class OpenAIProcessorConversationConfigAdmin(admin.ModelAdmin):
235
+ @admin.register(AiModelApi)
236
+ class AiModelApiAdmin(unfold_admin.ModelAdmin):
220
237
  list_display = (
221
238
  "id",
222
239
  "name",
@@ -227,7 +244,7 @@ class OpenAIProcessorConversationConfigAdmin(admin.ModelAdmin):
227
244
 
228
245
 
229
246
  @admin.register(SearchModelConfig)
230
- class SearchModelConfigAdmin(admin.ModelAdmin):
247
+ class SearchModelConfigAdmin(unfold_admin.ModelAdmin):
231
248
  list_display = (
232
249
  "id",
233
250
  "name",
@@ -238,7 +255,7 @@ class SearchModelConfigAdmin(admin.ModelAdmin):
238
255
 
239
256
 
240
257
  @admin.register(ServerChatSettings)
241
- class ServerChatSettingsAdmin(admin.ModelAdmin):
258
+ class ServerChatSettingsAdmin(unfold_admin.ModelAdmin):
242
259
  list_display = (
243
260
  "chat_default",
244
261
  "chat_advanced",
@@ -247,7 +264,7 @@ class ServerChatSettingsAdmin(admin.ModelAdmin):
247
264
 
248
265
 
249
266
  @admin.register(WebScraper)
250
- class WebScraperAdmin(admin.ModelAdmin):
267
+ class WebScraperAdmin(unfold_admin.ModelAdmin):
251
268
  list_display = (
252
269
  "priority",
253
270
  "name",
@@ -261,7 +278,7 @@ class WebScraperAdmin(admin.ModelAdmin):
261
278
 
262
279
 
263
280
  @admin.register(Conversation)
264
- class ConversationAdmin(admin.ModelAdmin):
281
+ class ConversationAdmin(unfold_admin.ModelAdmin):
265
282
  list_display = (
266
283
  "id",
267
284
  "user",
@@ -286,17 +303,10 @@ class ConversationAdmin(admin.ModelAdmin):
286
303
  modified_log = conversation.conversation_log
287
304
  chat_log = modified_log.get("chat", [])
288
305
  for idx, log in enumerate(chat_log):
289
- if (
290
- log["by"] == "khoj"
291
- and log["intent"]
292
- and log["intent"]["type"]
293
- and (
294
- log["intent"]["type"] == ImageIntentType.TEXT_TO_IMAGE.value
295
- or log["intent"]["type"] == ImageIntentType.TEXT_TO_IMAGE_V3.value
296
- )
297
- ):
298
- log["message"] = "inline image redacted for space"
306
+ if log["by"] == "khoj" and log["images"]:
307
+ log["images"] = ["inline image redacted for space"]
299
308
  chat_log[idx] = log
309
+
300
310
  modified_log["chat"] = chat_log
301
311
 
302
312
  writer.writerow(
@@ -367,7 +377,7 @@ class ConversationAdmin(admin.ModelAdmin):
367
377
 
368
378
 
369
379
  @admin.register(UserConversationConfig)
370
- class UserConversationConfigAdmin(admin.ModelAdmin):
380
+ class UserConversationConfigAdmin(unfold_admin.ModelAdmin):
371
381
  list_display = (
372
382
  "id",
373
383
  "get_user_email",
@@ -0,0 +1,85 @@
1
+ # Made manually by sabaimran for use by Django 5.0.9 on 2024-12-01 16:59
2
+
3
+ from django.db import migrations, models
4
+
5
+ # This script was written alongside when Pydantic validation was added to the Conversation conversation_log field.
6
+
7
+
8
+ def migrate_generated_assets(apps, schema_editor):
9
+ Conversation = apps.get_model("database", "Conversation")
10
+
11
+ # Process conversations in chunks
12
+ for conversation in Conversation.objects.iterator():
13
+ try:
14
+ meta_log = conversation.conversation_log
15
+ modified = False
16
+
17
+ for chat in meta_log.get("chat", []):
18
+ intent_type = chat.get("intent", {}).get("type")
19
+
20
+ if intent_type and chat["by"] == "khoj":
21
+ if intent_type and "text-to-image" in intent_type:
22
+ # Migrate the generated image to the new format
23
+ chat["images"] = [chat.get("message")]
24
+ chat["message"] = chat["intent"]["inferred-queries"][0]
25
+ modified = True
26
+
27
+ if intent_type and "excalidraw" in intent_type:
28
+ # Migrate the generated excalidraw to the new format
29
+ chat["excalidrawDiagram"] = chat.get("message")
30
+ chat["message"] = chat["intent"]["inferred-queries"][0]
31
+ modified = True
32
+
33
+ # Only save if changes were made
34
+ if modified:
35
+ conversation.conversation_log = meta_log
36
+ conversation.save()
37
+
38
+ except Exception as e:
39
+ print(f"Error processing conversation {conversation.id}: {str(e)}")
40
+ continue
41
+
42
+
43
+ def reverse_migration(apps, schema_editor):
44
+ Conversation = apps.get_model("database", "Conversation")
45
+
46
+ # Process conversations in chunks
47
+ for conversation in Conversation.objects.iterator():
48
+ try:
49
+ meta_log = conversation.conversation_log
50
+ modified = False
51
+
52
+ for chat in meta_log.get("chat", []):
53
+ intent_type = chat.get("intent", {}).get("type")
54
+
55
+ if intent_type and chat["by"] == "khoj":
56
+ if intent_type and "text-to-image" in intent_type:
57
+ # Migrate the generated image back to the old format
58
+ chat["message"] = chat.get("images", [])[0]
59
+ chat.pop("images", None)
60
+ modified = True
61
+
62
+ if intent_type and "excalidraw" in intent_type:
63
+ # Migrate the generated excalidraw back to the old format
64
+ chat["message"] = chat.get("excalidrawDiagram")
65
+ chat.pop("excalidrawDiagram", None)
66
+ modified = True
67
+
68
+ # Only save if changes were made
69
+ if modified:
70
+ conversation.conversation_log = meta_log
71
+ conversation.save()
72
+
73
+ except Exception as e:
74
+ print(f"Error processing conversation {conversation.id}: {str(e)}")
75
+ continue
76
+
77
+
78
+ class Migration(migrations.Migration):
79
+ dependencies = [
80
+ ("database", "0074_alter_conversation_title"),
81
+ ]
82
+
83
+ operations = [
84
+ migrations.RunPython(migrate_generated_assets, reverse_migration),
85
+ ]
@@ -0,0 +1,26 @@
1
+ # Generated by Django 5.0.9 on 2024-12-05 09:00
2
+
3
+ from django.db import migrations
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+ dependencies = [
8
+ ("database", "0075_migrate_generated_assets_and_validate"),
9
+ ]
10
+
11
+ operations = [
12
+ migrations.RenameModel(
13
+ old_name="OpenAIProcessorConversationConfig",
14
+ new_name="AiModelApi",
15
+ ),
16
+ migrations.RenameField(
17
+ model_name="chatmodeloptions",
18
+ old_name="openai_config",
19
+ new_name="ai_model_api",
20
+ ),
21
+ migrations.RenameField(
22
+ model_name="texttoimagemodelconfig",
23
+ old_name="openai_config",
24
+ new_name="ai_model_api",
25
+ ),
26
+ ]