khoj 1.16.1.dev25__py3-none-any.whl → 1.17.1.dev216__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 (47) hide show
  1. khoj/configure.py +6 -6
  2. khoj/database/adapters/__init__.py +55 -26
  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 +191 -301
  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/conversation/utils.py +0 -4
  29. khoj/processor/tools/online_search.py +13 -7
  30. khoj/routers/api.py +58 -9
  31. khoj/routers/api_agents.py +3 -1
  32. khoj/routers/api_chat.py +335 -562
  33. khoj/routers/api_content.py +538 -0
  34. khoj/routers/api_model.py +156 -0
  35. khoj/routers/helpers.py +338 -23
  36. khoj/routers/notion.py +2 -8
  37. khoj/routers/web_client.py +43 -256
  38. khoj/search_type/text_search.py +5 -4
  39. khoj/utils/fs_syncer.py +4 -2
  40. khoj/utils/rawconfig.py +6 -1
  41. {khoj-1.16.1.dev25.dist-info → khoj-1.17.1.dev216.dist-info}/METADATA +2 -2
  42. {khoj-1.16.1.dev25.dist-info → khoj-1.17.1.dev216.dist-info}/RECORD +45 -43
  43. khoj/routers/api_config.py +0 -434
  44. khoj/routers/indexer.py +0 -349
  45. {khoj-1.16.1.dev25.dist-info → khoj-1.17.1.dev216.dist-info}/WHEEL +0 -0
  46. {khoj-1.16.1.dev25.dist-info → khoj-1.17.1.dev216.dist-info}/entry_points.txt +0 -0
  47. {khoj-1.16.1.dev25.dist-info → khoj-1.17.1.dev216.dist-info}/licenses/LICENSE +0 -0
@@ -1,30 +1,21 @@
1
1
  # System Packages
2
2
  import json
3
3
  import os
4
- from datetime import timedelta
5
4
  from typing import Optional
6
5
 
7
6
  from fastapi import APIRouter, Request
8
7
  from fastapi.responses import FileResponse, HTMLResponse, RedirectResponse
9
8
  from fastapi.templating import Jinja2Templates
10
- from starlette.authentication import has_required_scope, requires
9
+ from starlette.authentication import requires
11
10
 
12
- from khoj.database import adapters
13
11
  from khoj.database.adapters import (
14
12
  AgentAdapters,
15
- ConversationAdapters,
16
- EntryAdapters,
17
13
  PublicConversationAdapters,
18
14
  get_user_github_config,
19
- get_user_name,
20
15
  get_user_notion_config,
21
- get_user_subscription_state,
22
16
  )
23
17
  from khoj.database.models import KhojUser
24
- from khoj.processor.speech.text_to_speech import is_eleven_labs_enabled
25
- from khoj.routers.helpers import get_next_url
26
- from khoj.routers.notion import get_notion_auth_url
27
- from khoj.routers.twilio import is_twilio_enabled
18
+ from khoj.routers.helpers import get_next_url, get_user_config
28
19
  from khoj.utils import constants, state
29
20
  from khoj.utils.rawconfig import (
30
21
  GithubContentConfig,
@@ -42,80 +33,36 @@ templates = Jinja2Templates([constants.web_directory, constants.next_js_director
42
33
  @requires(["authenticated"], redirect="login_page")
43
34
  def index(request: Request):
44
35
  user = request.user.object
45
- user_picture = request.session.get("user", {}).get("picture")
46
- has_documents = EntryAdapters.user_has_entries(user=user)
36
+ user_config = get_user_config(user, request)
47
37
 
48
- return templates.TemplateResponse(
49
- "chat.html",
50
- context={
51
- "request": request,
52
- "username": user.username,
53
- "user_photo": user_picture,
54
- "is_active": has_required_scope(request, ["premium"]),
55
- "has_documents": has_documents,
56
- "khoj_version": state.khoj_version,
57
- },
58
- )
38
+ return templates.TemplateResponse("chat.html", context=user_config)
59
39
 
60
40
 
61
41
  @web_client.post("/", response_class=FileResponse)
62
42
  @requires(["authenticated"], redirect="login_page")
63
43
  def index_post(request: Request):
64
44
  user = request.user.object
65
- user_picture = request.session.get("user", {}).get("picture")
66
- has_documents = EntryAdapters.user_has_entries(user=user)
45
+ user_config = get_user_config(user, request)
67
46
 
68
- return templates.TemplateResponse(
69
- "chat.html",
70
- context={
71
- "request": request,
72
- "username": user.username,
73
- "user_photo": user_picture,
74
- "is_active": has_required_scope(request, ["premium"]),
75
- "has_documents": has_documents,
76
- "khoj_version": state.khoj_version,
77
- },
78
- )
47
+ return templates.TemplateResponse("chat.html", context=user_config)
79
48
 
80
49
 
81
50
  @web_client.get("/search", response_class=FileResponse)
82
51
  @requires(["authenticated"], redirect="login_page")
83
52
  def search_page(request: Request):
84
53
  user = request.user.object
85
- user_picture = request.session.get("user", {}).get("picture")
86
- has_documents = EntryAdapters.user_has_entries(user=user)
54
+ user_config = get_user_config(user, request)
87
55
 
88
- return templates.TemplateResponse(
89
- "search.html",
90
- context={
91
- "request": request,
92
- "username": user.username,
93
- "user_photo": user_picture,
94
- "is_active": has_required_scope(request, ["premium"]),
95
- "has_documents": has_documents,
96
- "khoj_version": state.khoj_version,
97
- },
98
- )
56
+ return templates.TemplateResponse("search.html", context=user_config)
99
57
 
100
58
 
101
59
  @web_client.get("/chat", response_class=FileResponse)
102
60
  @requires(["authenticated"], redirect="login_page")
103
61
  def chat_page(request: Request):
104
62
  user = request.user.object
105
- user_picture = request.session.get("user", {}).get("picture")
106
- has_documents = EntryAdapters.user_has_entries(user=user)
63
+ user_config = get_user_config(user, request)
107
64
 
108
- return templates.TemplateResponse(
109
- "chat.html",
110
- context={
111
- "request": request,
112
- "username": user.username,
113
- "user_photo": user_picture,
114
- "is_active": has_required_scope(request, ["premium"]),
115
- "has_documents": has_documents,
116
- "khoj_version": state.khoj_version,
117
- },
118
- )
65
+ return templates.TemplateResponse("chat.html", context=user_config)
119
66
 
120
67
 
121
68
  @web_client.get("/experimental", response_class=FileResponse)
@@ -169,25 +116,14 @@ def agents_page(request: Request):
169
116
  @web_client.get("/agent/{agent_slug}", response_class=HTMLResponse)
170
117
  def agent_page(request: Request, agent_slug: str):
171
118
  user: KhojUser = request.user.object if request.user.is_authenticated else None
172
- user_picture = request.session.get("user", {}).get("picture") if user else None
173
-
119
+ user_config = get_user_config(user, request)
174
120
  agent = AgentAdapters.get_agent_by_slug(agent_slug)
175
- has_documents = EntryAdapters.user_has_entries(user=user)
176
121
 
177
122
  if agent == None:
178
- return templates.TemplateResponse(
179
- "404.html",
180
- context={
181
- "request": request,
182
- "khoj_version": state.khoj_version,
183
- "username": user.username if user else None,
184
- "has_documents": False,
185
- "is_active": has_required_scope(request, ["premium"]),
186
- "user_photo": user_picture,
187
- },
188
- )
123
+ user_config["has_documents"] = False
124
+ return templates.TemplateResponse("404.html", context=user_config)
189
125
 
190
- agent_metadata = {
126
+ user_config["agent"] = {
191
127
  "slug": agent.slug,
192
128
  "avatar": agent.avatar,
193
129
  "name": agent.name,
@@ -199,115 +135,23 @@ def agent_page(request: Request, agent_slug: str):
199
135
  "creator_not_self": agent.creator != user,
200
136
  }
201
137
 
202
- return templates.TemplateResponse(
203
- "agent.html",
204
- context={
205
- "request": request,
206
- "agent": agent_metadata,
207
- "khoj_version": state.khoj_version,
208
- "username": user.username if user else None,
209
- "has_documents": has_documents,
210
- "is_active": has_required_scope(request, ["premium"]),
211
- "user_photo": user_picture,
212
- },
213
- )
138
+ return templates.TemplateResponse("agent.html", context=user_config)
214
139
 
215
140
 
216
- @web_client.get("/config", response_class=HTMLResponse)
141
+ @web_client.get("/settings", response_class=HTMLResponse)
217
142
  @requires(["authenticated"], redirect="login_page")
218
143
  def config_page(request: Request):
219
144
  user: KhojUser = request.user.object
220
- user_picture = request.session.get("user", {}).get("picture")
221
- has_documents = EntryAdapters.user_has_entries(user=user)
222
-
223
- user_subscription_state = get_user_subscription_state(user.email)
224
- user_subscription = adapters.get_user_subscription(user.email)
225
- subscription_renewal_date = (
226
- user_subscription.renewal_date.strftime("%d %b %Y")
227
- if user_subscription and user_subscription.renewal_date
228
- else (user_subscription.created_at + timedelta(days=7)).strftime("%d %b %Y")
229
- )
230
- given_name = get_user_name(user)
231
-
232
- enabled_content_source = set(EntryAdapters.get_unique_file_sources(user))
233
- successfully_configured = {
234
- "computer": ("computer" in enabled_content_source),
235
- "github": ("github" in enabled_content_source),
236
- "notion": ("notion" in enabled_content_source),
237
- }
238
-
239
- selected_conversation_config = ConversationAdapters.get_conversation_config(user)
240
- conversation_options = ConversationAdapters.get_conversation_processor_options().all()
241
- all_conversation_options = list()
242
- for conversation_option in conversation_options:
243
- all_conversation_options.append({"chat_model": conversation_option.chat_model, "id": conversation_option.id})
244
-
245
- search_model_options = adapters.get_or_create_search_models().all()
246
- all_search_model_options = list()
247
- for search_model_option in search_model_options:
248
- all_search_model_options.append({"name": search_model_option.name, "id": search_model_option.id})
249
-
250
- current_search_model_option = adapters.get_user_search_model_or_default(user)
251
-
252
- selected_paint_model_config = ConversationAdapters.get_user_text_to_image_model_config(user)
253
- paint_model_options = ConversationAdapters.get_text_to_image_model_options().all()
254
- all_paint_model_options = list()
255
- for paint_model in paint_model_options:
256
- all_paint_model_options.append({"model_name": paint_model.model_name, "id": paint_model.id})
257
-
258
- notion_oauth_url = get_notion_auth_url(user)
145
+ user_config = get_user_config(user, request, is_detailed=True)
259
146
 
260
- eleven_labs_enabled = is_eleven_labs_enabled()
147
+ return templates.TemplateResponse("settings.html", context=user_config)
261
148
 
262
- voice_models = ConversationAdapters.get_voice_model_options()
263
- voice_model_options = list()
264
- for voice_model in voice_models:
265
- voice_model_options.append({"name": voice_model.name, "id": voice_model.model_id})
266
149
 
267
- if len(voice_model_options) == 0:
268
- eleven_labs_enabled = False
269
-
270
- selected_voice_config = ConversationAdapters.get_voice_model_config(user)
271
-
272
- return templates.TemplateResponse(
273
- "config.html",
274
- context={
275
- "request": request,
276
- "current_model_state": successfully_configured,
277
- "anonymous_mode": state.anonymous_mode,
278
- "username": user.username,
279
- "given_name": given_name,
280
- "search_model_options": all_search_model_options,
281
- "selected_search_model_config": current_search_model_option.id,
282
- "conversation_options": all_conversation_options,
283
- "selected_conversation_config": selected_conversation_config.id if selected_conversation_config else None,
284
- "paint_model_options": all_paint_model_options,
285
- "selected_paint_model_config": selected_paint_model_config.id if selected_paint_model_config else None,
286
- "user_photo": user_picture,
287
- "billing_enabled": state.billing_enabled,
288
- "subscription_state": user_subscription_state,
289
- "subscription_renewal_date": subscription_renewal_date,
290
- "khoj_cloud_subscription_url": os.getenv("KHOJ_CLOUD_SUBSCRIPTION_URL"),
291
- "is_active": has_required_scope(request, ["premium"]),
292
- "has_documents": has_documents,
293
- "is_twilio_enabled": is_twilio_enabled(),
294
- "is_eleven_labs_enabled": eleven_labs_enabled,
295
- "voice_model_options": voice_model_options,
296
- "selected_voice_config": selected_voice_config.model_id if selected_voice_config else None,
297
- "phone_number": user.phone_number,
298
- "is_phone_number_verified": user.verified_phone_number,
299
- "khoj_version": state.khoj_version,
300
- "notion_oauth_url": notion_oauth_url,
301
- },
302
- )
303
-
304
-
305
- @web_client.get("/config/content-source/github", response_class=HTMLResponse)
150
+ @web_client.get("/settings/content/github", response_class=HTMLResponse)
306
151
  @requires(["authenticated"], redirect="login_page")
307
152
  def github_config_page(request: Request):
308
153
  user = request.user.object
309
- user_picture = request.session.get("user", {}).get("picture")
310
- has_documents = EntryAdapters.user_has_entries(user=user)
154
+ user_config = get_user_config(user, request)
311
155
  current_github_config = get_user_github_config(user)
312
156
 
313
157
  if current_github_config:
@@ -329,66 +173,32 @@ def github_config_page(request: Request):
329
173
  else:
330
174
  current_config = {} # type: ignore
331
175
 
332
- return templates.TemplateResponse(
333
- "content_source_github_input.html",
334
- context={
335
- "request": request,
336
- "current_config": current_config,
337
- "username": user.username,
338
- "user_photo": user_picture,
339
- "is_active": has_required_scope(request, ["premium"]),
340
- "has_documents": has_documents,
341
- "khoj_version": state.khoj_version,
342
- },
343
- )
176
+ user_config["current_config"] = current_config
177
+ return templates.TemplateResponse("content_source_github_input.html", context=user_config)
344
178
 
345
179
 
346
- @web_client.get("/config/content-source/notion", response_class=HTMLResponse)
180
+ @web_client.get("/settings/content/notion", response_class=HTMLResponse)
347
181
  @requires(["authenticated"], redirect="login_page")
348
182
  def notion_config_page(request: Request):
349
183
  user = request.user.object
350
- user_picture = request.session.get("user", {}).get("picture")
351
- has_documents = EntryAdapters.user_has_entries(user=user)
352
- current_notion_config = get_user_notion_config(user)
353
-
354
- current_config = NotionContentConfig(
355
- token=current_notion_config.token if current_notion_config else "",
356
- )
184
+ user_config = get_user_config(user, request)
357
185
 
186
+ current_notion_config = get_user_notion_config(user)
187
+ token = current_notion_config.token if current_notion_config else ""
188
+ current_config = NotionContentConfig(token=token)
358
189
  current_config = json.loads(current_config.model_dump_json())
359
190
 
360
- return templates.TemplateResponse(
361
- "content_source_notion_input.html",
362
- context={
363
- "request": request,
364
- "current_config": current_config,
365
- "username": user.username,
366
- "user_photo": user_picture,
367
- "is_active": has_required_scope(request, ["premium"]),
368
- "has_documents": has_documents,
369
- "khoj_version": state.khoj_version,
370
- },
371
- )
191
+ user_config["current_config"] = current_config
192
+ return templates.TemplateResponse("content_source_notion_input.html", context=user_config)
372
193
 
373
194
 
374
- @web_client.get("/config/content-source/computer", response_class=HTMLResponse)
195
+ @web_client.get("/settings/content/computer", response_class=HTMLResponse)
375
196
  @requires(["authenticated"], redirect="login_page")
376
197
  def computer_config_page(request: Request):
377
198
  user = request.user.object if request.user.is_authenticated else None
378
- user_picture = request.session.get("user", {}).get("picture") if user else None
379
- has_documents = EntryAdapters.user_has_entries(user=user) if user else False
199
+ user_config = get_user_config(user, request)
380
200
 
381
- return templates.TemplateResponse(
382
- "content_source_computer_input.html",
383
- context={
384
- "request": request,
385
- "username": user.username,
386
- "user_photo": user_picture,
387
- "is_active": has_required_scope(request, ["premium"]),
388
- "has_documents": has_documents,
389
- "khoj_version": state.khoj_version,
390
- },
391
- )
201
+ return templates.TemplateResponse("content_source_computer_input.html", context=user_config)
392
202
 
393
203
 
394
204
  @web_client.get("/share/chat/{public_conversation_slug}", response_class=HTMLResponse)
@@ -404,8 +214,9 @@ def view_public_conversation(request: Request):
404
214
  },
405
215
  )
406
216
  user = request.user.object if request.user.is_authenticated else None
407
- user_picture = request.session.get("user", {}).get("picture") if user else None
408
- has_documents = EntryAdapters.user_has_entries(user=user) if user else False
217
+ user_config = get_user_config(user, request)
218
+ user_config["public_conversation_slug"] = public_conversation_slug
219
+ user_config["google_client_id"] = os.environ.get("GOOGLE_CLIENT_ID")
409
220
 
410
221
  all_agents = AgentAdapters.get_all_accessible_agents(request.user.object if request.user.is_authenticated else None)
411
222
 
@@ -420,28 +231,15 @@ def view_public_conversation(request: Request):
420
231
  "name": agent.name,
421
232
  }
422
233
  )
234
+ user_config["agents"] = agents_packet
423
235
 
424
- google_client_id = os.environ.get("GOOGLE_CLIENT_ID")
425
236
  redirect_uri = str(request.app.url_path_for("auth"))
426
237
  next_url = str(
427
238
  request.app.url_path_for("view_public_conversation", public_conversation_slug=public_conversation_slug)
428
239
  )
240
+ user_config["redirect_uri"] = f"{redirect_uri}?next={next_url}"
429
241
 
430
- return templates.TemplateResponse(
431
- "public_conversation.html",
432
- context={
433
- "request": request,
434
- "username": user.username if user else None,
435
- "user_photo": user_picture,
436
- "is_active": has_required_scope(request, ["premium"]),
437
- "has_documents": has_documents,
438
- "khoj_version": state.khoj_version,
439
- "public_conversation_slug": public_conversation_slug,
440
- "agents": agents_packet,
441
- "google_client_id": google_client_id,
442
- "redirect_uri": f"{redirect_uri}?next={next_url}",
443
- },
444
- )
242
+ return templates.TemplateResponse("public_conversation.html", context=user_config)
445
243
 
446
244
 
447
245
  @web_client.get("/automations", response_class=HTMLResponse)
@@ -452,20 +250,9 @@ def automations_config_page(
452
250
  queryToRun: Optional[str] = None,
453
251
  ):
454
252
  user = request.user.object if request.user.is_authenticated else None
455
- user_picture = request.session.get("user", {}).get("picture")
456
- has_documents = EntryAdapters.user_has_entries(user=user) if user else False
253
+ user_config = get_user_config(user, request)
254
+ user_config["subject"] = subject if subject else ""
255
+ user_config["crontime"] = crontime if crontime else ""
256
+ user_config["queryToRun"] = queryToRun if queryToRun else ""
457
257
 
458
- return templates.TemplateResponse(
459
- "config_automation.html",
460
- context={
461
- "request": request,
462
- "username": user.username if user else None,
463
- "user_photo": user_picture,
464
- "is_active": has_required_scope(request, ["premium"]),
465
- "has_documents": has_documents,
466
- "khoj_version": state.khoj_version,
467
- "subject": subject if subject else "",
468
- "crontime": crontime if crontime else "",
469
- "queryToRun": queryToRun if queryToRun else "",
470
- },
471
- )
258
+ return templates.TemplateResponse("config_automation.html", context=user_config)
@@ -199,17 +199,16 @@ def setup(
199
199
  text_to_entries: Type[TextToEntries],
200
200
  files: dict[str, str],
201
201
  regenerate: bool,
202
- full_corpus: bool = True,
203
202
  user: KhojUser = None,
204
203
  config=None,
205
- ) -> None:
204
+ ) -> Tuple[int, int]:
206
205
  if config:
207
206
  num_new_embeddings, num_deleted_embeddings = text_to_entries(config).process(
208
- files=files, full_corpus=full_corpus, user=user, regenerate=regenerate
207
+ files=files, user=user, regenerate=regenerate
209
208
  )
210
209
  else:
211
210
  num_new_embeddings, num_deleted_embeddings = text_to_entries().process(
212
- files=files, full_corpus=full_corpus, user=user, regenerate=regenerate
211
+ files=files, user=user, regenerate=regenerate
213
212
  )
214
213
 
215
214
  if files:
@@ -219,6 +218,8 @@ def setup(
219
218
  f"Deleted {num_deleted_embeddings} entries. Created {num_new_embeddings} new entries for user {user} from files {file_names[:10]} ..."
220
219
  )
221
220
 
221
+ return num_new_embeddings, num_deleted_embeddings
222
+
222
223
 
223
224
  def cross_encoder_score(query: str, hits: List[SearchResponse], search_model_name: str) -> List[SearchResponse]:
224
225
  """Score all retrieved entries using the cross-encoder"""
khoj/utils/fs_syncer.py CHANGED
@@ -22,7 +22,7 @@ magika = Magika()
22
22
 
23
23
 
24
24
  def collect_files(search_type: Optional[SearchType] = SearchType.All, user=None) -> dict:
25
- files = {}
25
+ files: dict[str, dict] = {"docx": {}, "image": {}}
26
26
 
27
27
  if search_type == SearchType.All or search_type == SearchType.Org:
28
28
  org_config = LocalOrgConfig.objects.filter(user=user).first()
@@ -36,6 +36,8 @@ def collect_files(search_type: Optional[SearchType] = SearchType.All, user=None)
36
36
  if search_type == SearchType.All or search_type == SearchType.Pdf:
37
37
  pdf_config = LocalPdfConfig.objects.filter(user=user).first()
38
38
  files["pdf"] = get_pdf_files(construct_config_from_db(pdf_config)) if pdf_config else {}
39
+ files["image"] = {}
40
+ files["docx"] = {}
39
41
  return files
40
42
 
41
43
 
@@ -122,7 +124,7 @@ def get_org_files(config: TextContentConfig):
122
124
  logger.debug("At least one of org-files or org-file-filter is required to be specified")
123
125
  return {}
124
126
 
125
- "Get Org files to process"
127
+ # Get Org files to process
126
128
  absolute_org_files, filtered_org_files = set(), set()
127
129
  if org_files:
128
130
  absolute_org_files = {get_absolute_path(org_file) for org_file in org_files}
khoj/utils/rawconfig.py CHANGED
@@ -27,11 +27,16 @@ class LocationData(BaseModel):
27
27
  country: Optional[str]
28
28
 
29
29
 
30
- class FilterRequest(BaseModel):
30
+ class FileFilterRequest(BaseModel):
31
31
  filename: str
32
32
  conversation_id: str
33
33
 
34
34
 
35
+ class FilesFilterRequest(BaseModel):
36
+ filenames: List[str]
37
+ conversation_id: str
38
+
39
+
35
40
  class TextConfigBase(ConfigBase):
36
41
  compressed_jsonl: Path
37
42
  embeddings_file: Path
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: khoj
3
- Version: 1.16.1.dev25
4
- Summary: An AI copilot for your Second Brain
3
+ Version: 1.17.1.dev216
4
+ Summary: Your Second Brain
5
5
  Project-URL: Homepage, https://khoj.dev
6
6
  Project-URL: Documentation, https://docs.khoj.dev
7
7
  Project-URL: Code, https://github.com/khoj-ai/khoj