khoj 1.23.3.dev4__py3-none-any.whl → 1.23.4.dev4__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 (77) hide show
  1. khoj/database/adapters/__init__.py +8 -12
  2. khoj/database/migrations/0063_conversation_temp_id.py +36 -0
  3. khoj/database/migrations/0064_remove_conversation_temp_id_alter_conversation_id.py +86 -0
  4. khoj/database/models/__init__.py +1 -1
  5. khoj/interface/compiled/404/index.html +1 -1
  6. khoj/interface/compiled/_next/static/chunks/1603-d643510c2c0b8871.js +1 -0
  7. khoj/interface/compiled/_next/static/chunks/2697-5b013077cfa7aaf0.js +1 -0
  8. khoj/interface/compiled/_next/static/chunks/{1906-1747a36c336df02c.js → 4051-3dc2df557ccb5213.js} +2 -2
  9. khoj/interface/compiled/_next/static/chunks/8423-62ac6c832be2461b.js +1 -0
  10. khoj/interface/compiled/_next/static/chunks/9178-d8cec50b2cec38da.js +1 -0
  11. khoj/interface/compiled/_next/static/chunks/app/agents/page-830581af9f40707b.js +1 -0
  12. khoj/interface/compiled/_next/static/chunks/app/automations/{page-6ea3381528603372.js → page-cc875a656df43713.js} +1 -1
  13. khoj/interface/compiled/_next/static/chunks/app/chat/page-4b76ccfca1a6154c.js +1 -0
  14. khoj/interface/compiled/_next/static/chunks/app/factchecker/{page-04a19ab1a988976f.js → page-bb320ff7d4dee716.js} +1 -1
  15. khoj/interface/compiled/_next/static/chunks/app/page-60193524cf570002.js +1 -0
  16. khoj/interface/compiled/_next/static/chunks/app/search/page-4bceb5b0df9cfd66.js +1 -0
  17. khoj/interface/compiled/_next/static/chunks/app/settings/page-532ed8b778a0b40d.js +1 -0
  18. khoj/interface/compiled/_next/static/chunks/app/share/chat/page-3ddcb1cef09264fb.js +1 -0
  19. khoj/interface/compiled/_next/static/chunks/{webpack-072d1cbdec7e1782.js → webpack-de28762883e5816d.js} +1 -1
  20. khoj/interface/compiled/_next/static/css/{a3530ec58b0b660f.css → 3e1f1fdd70775091.css} +1 -1
  21. khoj/interface/compiled/_next/static/css/4cae6c0e5c72fb2d.css +1 -0
  22. khoj/interface/compiled/_next/static/css/507bf83cc17d2b53.css +1 -0
  23. khoj/interface/compiled/_next/static/css/6bde1f2045622ef7.css +1 -0
  24. khoj/interface/compiled/_next/static/css/93c1302668e4a828.css +25 -0
  25. khoj/interface/compiled/_next/static/css/e41ec62af8ee4e38.css +1 -0
  26. khoj/interface/compiled/agents/index.html +1 -1
  27. khoj/interface/compiled/agents/index.txt +2 -2
  28. khoj/interface/compiled/automations/index.html +1 -1
  29. khoj/interface/compiled/automations/index.txt +2 -2
  30. khoj/interface/compiled/chat/index.html +1 -1
  31. khoj/interface/compiled/chat/index.txt +2 -2
  32. khoj/interface/compiled/factchecker/index.html +1 -1
  33. khoj/interface/compiled/factchecker/index.txt +2 -2
  34. khoj/interface/compiled/index.html +1 -1
  35. khoj/interface/compiled/index.txt +2 -2
  36. khoj/interface/compiled/search/index.html +1 -1
  37. khoj/interface/compiled/search/index.txt +2 -2
  38. khoj/interface/compiled/settings/index.html +1 -1
  39. khoj/interface/compiled/settings/index.txt +2 -2
  40. khoj/interface/compiled/share/chat/index.html +1 -1
  41. khoj/interface/compiled/share/chat/index.txt +2 -2
  42. khoj/interface/email/task.html +31 -34
  43. khoj/interface/email/welcome.html +82 -53
  44. khoj/main.py +1 -1
  45. khoj/processor/content/images/image_to_entries.py +6 -4
  46. khoj/processor/conversation/utils.py +13 -8
  47. khoj/routers/api.py +1 -1
  48. khoj/routers/api_chat.py +14 -45
  49. khoj/routers/helpers.py +12 -7
  50. khoj/utils/cli.py +6 -0
  51. khoj/utils/constants.py +9 -2
  52. khoj/utils/initialization.py +158 -71
  53. {khoj-1.23.3.dev4.dist-info → khoj-1.23.4.dev4.dist-info}/METADATA +2 -2
  54. {khoj-1.23.3.dev4.dist-info → khoj-1.23.4.dev4.dist-info}/RECORD +60 -60
  55. khoj/database/migrations/0063_conversation_add_unique_id_field.py +0 -19
  56. khoj/database/migrations/0064_populate_unique_id.py +0 -20
  57. khoj/database/migrations/0065_add_unique_constraint_to_unique_id.py +0 -17
  58. khoj/interface/compiled/_next/static/chunks/1603-7914d7712a47690d.js +0 -1
  59. khoj/interface/compiled/_next/static/chunks/8423-14fc72aec9104ce9.js +0 -1
  60. khoj/interface/compiled/_next/static/chunks/9178-c153fc402c970365.js +0 -1
  61. khoj/interface/compiled/_next/static/chunks/app/agents/page-cd8e2ba85287e1f6.js +0 -1
  62. khoj/interface/compiled/_next/static/chunks/app/chat/page-5752b57c1e43e8a7.js +0 -1
  63. khoj/interface/compiled/_next/static/chunks/app/page-cd8d5d12595676d7.js +0 -1
  64. khoj/interface/compiled/_next/static/chunks/app/search/page-fa15807b1ad7e30b.js +0 -1
  65. khoj/interface/compiled/_next/static/chunks/app/settings/page-1a2acc46cdabaf4a.js +0 -1
  66. khoj/interface/compiled/_next/static/chunks/app/share/chat/page-e20f54450d3ce6c0.js +0 -1
  67. khoj/interface/compiled/_next/static/css/2272c73fc7a3b571.css +0 -1
  68. khoj/interface/compiled/_next/static/css/3e49e5ee49c6bda1.css +0 -25
  69. khoj/interface/compiled/_next/static/css/43939edc2f9b2043.css +0 -1
  70. khoj/interface/compiled/_next/static/css/553f9cdcc7a2bcd6.css +0 -1
  71. khoj/interface/compiled/_next/static/css/592ca99f5122e75a.css +0 -1
  72. /khoj/interface/compiled/_next/static/{d3ySlDLLYAYu1Jr-Dc35R → OnQKAWQ2iyKK5wApHgZtb}/_buildManifest.js +0 -0
  73. /khoj/interface/compiled/_next/static/{d3ySlDLLYAYu1Jr-Dc35R → OnQKAWQ2iyKK5wApHgZtb}/_ssgManifest.js +0 -0
  74. /khoj/interface/compiled/_next/static/chunks/{7023-52c1be60135eb057.js → 7023-1074a582ec989284.js} +0 -0
  75. {khoj-1.23.3.dev4.dist-info → khoj-1.23.4.dev4.dist-info}/WHEEL +0 -0
  76. {khoj-1.23.3.dev4.dist-info → khoj-1.23.4.dev4.dist-info}/entry_points.txt +0 -0
  77. {khoj-1.23.3.dev4.dist-info → khoj-1.23.4.dev4.dist-info}/licenses/LICENSE +0 -0
@@ -1,61 +1,90 @@
1
1
  <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>Welcome to Khoj</title>
5
- </head>
6
- <body>
7
- <body style="font-family: 'Verdana', sans-serif; font-weight: 400; font-style: normal; padding: 0; text-align: left; width: 600px; margin: 20px auto;">
8
- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
9
- <a class="logo" href="https://khoj.dev" target="_blank" style="text-decoration: none; text-decoration: underline dotted;">
10
- <img src="https://assets.khoj.dev/khoj_logo.png" alt="Khoj Logo" style="width: 100px;">
11
- </a>
12
- <div class="calls-to-action" style="margin-top: 20px;">
13
- <div>
14
- <h1 style="color: #333; font-size: large; font-weight: bold; margin: 0; line-height: 1.5; background-color: #fee285; padding: 8px; box-shadow: 6px 6px rgba(0, 0, 0, 1.5);">Merge AI with your brain</h1>
15
- <p style="color: #333; font-size: medium; margin-top: 20px; padding: 0; line-height: 1.5;">Hi {{name}}! We are psyched to be part of your journey with personal AI. To better help you, we're committed to staying transparent, accessible, and completely open-source.</p>
16
- <a class="button" href="https://app.khoj.dev" target="_blank" style="display: block; width: 200px; text-align: center; padding: 10px; margin-top: 20px; color: #333; background-color: #fee285; text-decoration: none; border-radius: 5px; font-weight: bold; transition: background-color 0.3s ease; box-shadow: 6px 6px rgba(0, 0, 0, 1.0); padding: 4px; font-size: large; text-transform: uppercase;">Get Started</a>
17
- <p style="color: #333; font-size: medium; margin-top: 20px; padding: 0; line-height: 1.5;">You're about to get a whole lot more productive.</p>
18
-
19
- <div style="display: grid; grid-template-columns: 1fr 1fr; grid-gap: 12px; margin-top: 20px;">
20
- <div style="border: 1px solid black; border-radius: 8px; padding: 8px; box-shadow: 6px 6px rgba(0, 0, 0, 1.0); margin-top: 20px;">
21
- <a href="https://docs.khoj.dev/features/online_search" style="text-decoration: none; text-decoration: underline dotted;">
22
- <h3 style="color: #333; font-size: large; margin: 0; padding: 0; line-height: 2.0; background-color: #b8f1c7; padding: 8px; ">Ditch the search bar</h3>
23
- </a>
24
- <p style="color: #333; font-size: medium; margin-top: 20px; padding: 0; line-height: 1.5;">You don't need to click around Google results and sift through information yourself, because Khoj is connected to the internet.</p>
25
- </div>
26
- <div style="border: 1px solid black; border-radius: 8px; padding: 8px; box-shadow: 6px 6px rgba(0, 0, 0, 1.0); margin-top: 20px;">
27
- <a href="https://app.khoj.dev/agents" style="text-decoration: none; text-decoration: underline dotted;">
28
- <h3 style="color: #333; font-size: large; margin: 0; padding: 0; line-height: 2.0; background-color: #b8f1c7; padding: 8px;">Get a village, not just an agent</h3>
29
- </a>
30
- <p style="color: #333; font-size: medium; margin-top: 20px; padding: 0; line-height: 1.5;">Khoj can fill the need for more specialized assistance, <a href="https://blog.khoj.dev/posts/using-khoj-for-studying/">such as tutoring</a>, with its curated agents. You get a whole team, always available.</p>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Welcome to Khoj</title>
8
+ </head>
9
+
10
+ <body
11
+ style="font-family: 'Arial', sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px; background-color: #f5f5f5;">
12
+ <div
13
+ style="background-color: #ffffff; border-radius: 10px; box-shadow: 0 0 20px rgba(0, 0, 0, 0.1); padding: 30px;">
14
+ <a href="https://khoj.dev" target="_blank"
15
+ style="display: block; text-align: center; margin-bottom: 20px; text-decoration: none;">
16
+ <img src="https://assets.khoj.dev/khoj_logo.png" alt="Khoj Logo" style="width: 120px;">
17
+ </a>
18
+
19
+ <h1
20
+ style="font-size: 24px; color: #2c3e50; margin-bottom: 20px; text-align: center; border-bottom: 2px solid #FFA07A; padding-bottom: 10px;">
21
+ Merge AI with your brain</h1>
22
+
23
+ <p style="font-size: 16px; color: #333; margin-bottom: 20px;">Hi {{name}}! We are psyched to be part of your
24
+ journey with personal AI. To better help you, we're committed to staying transparent, accessible, and
25
+ completely open-source.</p>
26
+
27
+ <a href="https://app.khoj.dev" target="_blank"
28
+ style="display: block; width: 200px; text-align: center; padding: 10px; margin: 20px auto; background-color: #FFA07A; color: #ffffff; text-decoration: none; border-radius: 5px; font-weight: bold; font-size: 16px; text-transform: uppercase;">Get
29
+ Started</a>
30
+
31
+ <p style="font-size: 16px; color: #333; margin-bottom: 20px;">You're about to get a whole lot more productive.
32
+ </p>
33
+ <a href="https://docs.khoj.dev/features/online_search"
34
+ style="color: #FFA07A; text-decoration: none; font-weight: bold; font-size: 14px;">
35
+ <div style="display: grid; grid-template-columns: 1fr 1fr; grid-gap: 20px; margin-bottom: 20px;">
36
+ <div style="background-color: #f8f9fa; border-left: 4px solid #FFA07A; padding: 15px;">
37
+ <h3 style="color: #2c3e50; margin-top: 0; font-size: 18px;">Ditch the search bar</h3>
38
+ <p style="font-size: 14px; color: #666; margin-bottom: 0;">You don't need to click around Google
39
+ results
40
+ and sift through information yourself, because Khoj is connected to the internet.</p>
41
+ </div>
42
+ </a>
43
+ <a href="https://app.khoj.dev/agents"
44
+ style="color: #FFA07A; text-decoration: none; font-weight: bold; font-size: 14px;">
45
+ <div style="background-color: #f8f9fa; border-left: 4px solid #FFA07A; padding: 15px;">
46
+ <h3 style="color: #2c3e50; margin-top: 0; font-size: 18px;">Get a village, not just an agent</h3>
47
+ <p style="font-size: 14px; color: #666; margin-bottom: 0;">Khoj can fill the need for more specialized
48
+ assistance, such as tutoring, with its curated agents. You get a whole team, always available.</p>
31
49
  </div>
32
- <div style="border: 1px solid black; border-radius: 8px; padding: 8px; box-shadow: 6px 6px rgba(0, 0, 0, 1.0); margin-top: 20px;">
33
- <a href="https://docs.khoj.dev/category/clients" style="text-decoration: none; text-decoration: underline dotted;">
34
- <h3 style="color: #333; font-size: large; margin: 0; padding: 0; line-height: 2.0; background-color: #b8f1c7; padding: 8px;">Available where you are</h3>
35
- </a>
36
- <p style="color: #333; font-size: medium; margin-top: 20px; padding: 0; line-height: 1.5;">Build on top of your digital brain. Khoj stores whatever data you share with it, so you can get answers from your personal notes and documents in your native language. You can engage from your desktop, Obsidian, WhatsApp, or the web.</p>
50
+ </a>
51
+ <a href="https://docs.khoj.dev/category/clients"
52
+ style="color: #FFA07A; text-decoration: none; font-weight: bold; font-size: 14px;">
53
+ <div style="background-color: #f8f9fa; border-left: 4px solid #FFA07A; padding: 15px;">
54
+ <h3 style="color: #2c3e50; margin-top: 0; font-size: 18px;">Activate your data</h3>
55
+ <p style="font-size: 14px; color: #666; margin-bottom: 0;">Build on top of your digital brain. Khoj
56
+ stores whatever data you share with it, so you can get answers from your personal notes and
57
+ documents in your native language.</p>
37
58
  </div>
38
- <div style="border: 1px solid black; border-radius: 8px; padding: 8px; box-shadow: 6px 6px rgba(0, 0, 0, 1.0); margin-top: 20px;">
39
- <a href="https://blog.khoj.dev/posts/how-khoj-generates-images/" style="text-decoration: none; text-decoration: underline dotted;">
40
- <h3 style="color: #333; font-size: large; margin: 0; padding: 0; line-height: 2.0; background-color: #b8f1c7; padding: 8px;">Create rich, contextual images</h3>
41
- </a>
42
- <p style="color: #333; font-size: medium; margin-top: 20px; padding: 0; line-height: 1.5;">With your shared data, Khoj can help you create astoundingly personal images depicting scenes of what's important to you.</p>
59
+ </a>
60
+ <a href="https://blog.khoj.dev/posts/how-khoj-generates-images/"
61
+ style="color: #FFA07A; text-decoration: none; font-weight: bold; font-size: 14px;">
62
+ <div style="background-color: #f8f9fa; border-left: 4px solid #FFA07A; padding: 15px;">
63
+ <h3 style="color: #2c3e50; margin-top: 0; font-size: 18px;">Create rich, contextual images</h3>
64
+ <p style="font-size: 14px; color: #666; margin-bottom: 0;">With your shared data, Khoj can help you
65
+ create astoundingly personal images depicting scenes of what's important to you.</p>
43
66
  </div>
44
- </div>
67
+ </a>
45
68
  </div>
46
- </div>
47
- <p style="color: #333; font-size: medium; margin-top: 20px; padding: 0; line-height: 1.5;">Like something? Dislike something? Searching for some other magical feature? Our inbox is always open for feedback! Reply to this email and say hi to introduce yourself 👋🏽.</p>
48
-
49
- <p style="color: #333; font-size: large; margin-top: 20px; padding: 0; line-height: 1.5;">- The Khoj Team</p>
50
- <table style="width: 100%; margin-top: 20px;">
51
- <tr>
52
- <td style="text-align: center;"><a href="https://docs.khoj.dev" target="_blank" style="padding: 8px; color: #333; background-color: #fee285; border-radius: 8px; box-shadow: 6px 6px rgba(0, 0, 0, 1.0);">Docs</a></td>
53
- <td style="text-align: center;"><a href="https://github.com/khoj-ai/khoj" target="_blank" style="padding: 8px; color: #333; background-color: #fee285; border-radius: 8px; box-shadow: 6px 6px rgba(0, 0, 0, 1.0);">GitHub</a></td>
54
- <td style="text-align: center;"><a href="https://twitter.com/khoj_ai" target="_blank" style="padding: 8px; color: #333; background-color: #fee285; border-radius: 8px; box-shadow: 6px 6px rgba(0, 0, 0, 1.0);">Twitter</a></td>
55
- <td style="text-align: center;"><a href="https://www.linkedin.com/company/khoj-ai" target="_blank" style="padding: 8px; color: #333; background-color: #fee285; border-radius: 8px; box-shadow: 6px 6px rgba(0, 0, 0, 1.0);">LinkedIn</a></td>
56
- <td style="text-align: center;"><a href="https://discord.gg/BDgyabRM6e" target="_blank" style="padding: 8px; color: #333; background-color: #fee285; border-radius: 8px; box-shadow: 6px 6px rgba(0, 0, 0, 1.0);">Discord</a></td>
57
- </tr>
58
- </table>
59
69
 
70
+ <p style="font-size: 16px; color: #333; margin-bottom: 20px;">Like something? Dislike something? Searching for
71
+ some other magical feature? Our inbox is always open for feedback! Reply to this email and say hi to
72
+ introduce yourself 👋🏽.</p>
73
+ <div style="font-size: 18px; font-weight: bold; margin-top: 30px; text-align: right;">- The Khoj Team</div>
74
+
75
+ <div style="margin-top: 30px; text-align: center;">
76
+ <a href="https://docs.khoj.dev" target="_blank"
77
+ style="display: inline-block; margin: 0 10px; padding: 8px 15px; background-color: #FFA07A; color: #ffffff; text-decoration: none; border-radius: 5px;">Docs</a>
78
+ <a href="https://github.com/khoj-ai/khoj" target="_blank"
79
+ style="display: inline-block; margin: 0 10px; padding: 8px 15px; background-color: #FFA07A; color: #ffffff; text-decoration: none; border-radius: 5px;">GitHub</a>
80
+ <a href="https://twitter.com/khoj_ai" target="_blank"
81
+ style="display: inline-block; margin: 0 10px; padding: 8px 15px; background-color: #FFA07A; color: #ffffff; text-decoration: none; border-radius: 5px;">Twitter</a>
82
+ <a href="https://www.linkedin.com/company/khoj-ai" target="_blank"
83
+ style="display: inline-block; margin: 0 10px; padding: 8px 15px; background-color: #FFA07A; color: #ffffff; text-decoration: none; border-radius: 5px;">LinkedIn</a>
84
+ <a href="https://discord.gg/BDgyabRM6e" target="_blank"
85
+ style="display: inline-block; margin: 0 10px; padding: 8px 15px; background-color: #FFA07A; color: #ffffff; text-decoration: none; border-radius: 5px;">Discord</a>
86
+ </div>
87
+ </div>
60
88
  </body>
89
+
61
90
  </html>
khoj/main.py CHANGED
@@ -131,7 +131,7 @@ def run(should_start_server=True):
131
131
  logger.info(f"📦 Initializing DB:\n{db_migrate_output.getvalue().strip()}")
132
132
  logger.debug(f"🌍 Initializing Web Client:\n{collectstatic_output.getvalue().strip()}")
133
133
 
134
- initialization()
134
+ initialization(not args.non_interactive)
135
135
 
136
136
  # Create app directory, if it doesn't exist
137
137
  state.config_file.parent.mkdir(parents=True, exist_ok=True)
@@ -4,8 +4,6 @@ import os
4
4
  from datetime import datetime
5
5
  from typing import Dict, List, Tuple
6
6
 
7
- from rapidocr_onnxruntime import RapidOCR
8
-
9
7
  from khoj.database.models import Entry as DbEntry
10
8
  from khoj.database.models import KhojUser
11
9
  from khoj.processor.content.text_to_entries import TextToEntries
@@ -58,7 +56,6 @@ class ImageToEntries(TextToEntries):
58
56
  entry_to_location_map: List[Tuple[str, str]] = []
59
57
  for image_file in image_files:
60
58
  try:
61
- loader = RapidOCR()
62
59
  bytes = image_files[image_file]
63
60
  # write the image to a temporary file
64
61
  timestamp_now = datetime.utcnow().timestamp()
@@ -71,13 +68,18 @@ class ImageToEntries(TextToEntries):
71
68
  bytes = image_files[image_file]
72
69
  f.write(bytes)
73
70
  try:
71
+ from rapidocr_onnxruntime import RapidOCR
72
+
73
+ loader = RapidOCR()
74
74
  image_entries_per_file = ""
75
75
  result, _ = loader(tmp_file)
76
76
  if result:
77
77
  expanded_entries = [text[1] for text in result]
78
78
  image_entries_per_file = " ".join(expanded_entries)
79
79
  except ImportError:
80
- logger.warning(f"Unable to process file: {image_file}. This file will not be indexed.")
80
+ logger.warning(
81
+ f"Unable to process image or scanned file for text: {image_file}. This file will not be indexed."
82
+ )
81
83
  continue
82
84
  entry_to_location_map.append((image_entries_per_file, image_file))
83
85
  entries.extend([image_entries_per_file])
@@ -18,13 +18,20 @@ from khoj.utils.helpers import is_none_or_empty, merge_dicts
18
18
 
19
19
  logger = logging.getLogger(__name__)
20
20
  model_to_prompt_size = {
21
+ # OpenAI Models
21
22
  "gpt-3.5-turbo": 12000,
22
- "gpt-3.5-turbo-0125": 12000,
23
- "gpt-4-0125-preview": 20000,
24
23
  "gpt-4-turbo-preview": 20000,
24
+ "gpt-4o": 20000,
25
25
  "gpt-4o-mini": 20000,
26
26
  "o1-preview": 20000,
27
27
  "o1-mini": 20000,
28
+ # Google Models
29
+ "gemini-1.5-flash": 20000,
30
+ "gemini-1.5-pro": 20000,
31
+ # Anthropic Models
32
+ "claude-3-5-sonnet-20240620": 20000,
33
+ "claude-3-opus-20240229": 20000,
34
+ # Offline Models
28
35
  "TheBloke/Mistral-7B-Instruct-v0.2-GGUF": 3500,
29
36
  "NousResearch/Hermes-2-Pro-Mistral-7B-GGUF": 3500,
30
37
  "bartowski/Meta-Llama-3.1-8B-Instruct-GGUF": 20000,
@@ -100,7 +107,7 @@ def save_to_conversation_log(
100
107
  inferred_queries: List[str] = [],
101
108
  intent_type: str = "remember",
102
109
  client_application: ClientApplication = None,
103
- conversation_id: int = None,
110
+ conversation_id: str = None,
104
111
  automation_id: str = None,
105
112
  uploaded_image_url: str = None,
106
113
  ):
@@ -163,7 +170,7 @@ def generate_chatml_messages_with_context(
163
170
  if loaded_model:
164
171
  max_prompt_size = infer_max_tokens(loaded_model.n_ctx(), model_to_prompt_size.get(model_name, math.inf))
165
172
  else:
166
- max_prompt_size = model_to_prompt_size.get(model_name, 2000)
173
+ max_prompt_size = model_to_prompt_size.get(model_name, 10000)
167
174
 
168
175
  # Scale lookback turns proportional to max prompt size supported by model
169
176
  lookback_turns = max_prompt_size // 750
@@ -291,8 +298,6 @@ def reciprocal_conversation_to_chatml(message_pair):
291
298
  return [ChatMessage(content=message, role=role) for message, role in zip(message_pair, ["user", "assistant"])]
292
299
 
293
300
 
294
- def remove_json_codeblock(response):
301
+ def remove_json_codeblock(response: str):
295
302
  """Remove any markdown json codeblock formatting if present. Useful for non schema enforceable models"""
296
- if response.startswith("```json") and response.endswith("```"):
297
- response = response[7:-3]
298
- return response
303
+ return response.removeprefix("```json").removesuffix("```")
khoj/routers/api.py CHANGED
@@ -328,7 +328,7 @@ async def extract_references_and_questions(
328
328
  q: str,
329
329
  n: int,
330
330
  d: float,
331
- conversation_id: int,
331
+ conversation_id: str,
332
332
  conversation_commands: List[ConversationCommand] = [ConversationCommand.Default],
333
333
  location_data: LocationData = None,
334
334
  send_status_func: Optional[Callable] = None,
khoj/routers/api_chat.py CHANGED
@@ -77,9 +77,7 @@ from khoj.routers.email import send_query_feedback
77
77
  @api_chat.get("/conversation/file-filters/{conversation_id}", response_class=Response)
78
78
  @requires(["authenticated"])
79
79
  def get_file_filter(request: Request, conversation_id: str) -> Response:
80
- conversation = ConversationAdapters.get_conversation_by_user(
81
- request.user.object, conversation_id=int(conversation_id)
82
- )
80
+ conversation = ConversationAdapters.get_conversation_by_user(request.user.object, conversation_id=conversation_id)
83
81
  if not conversation:
84
82
  return Response(content=json.dumps({"status": "error", "message": "Conversation not found"}), status_code=404)
85
83
 
@@ -95,7 +93,7 @@ def get_file_filter(request: Request, conversation_id: str) -> Response:
95
93
  @api_chat.delete("/conversation/file-filters/bulk", response_class=Response)
96
94
  @requires(["authenticated"])
97
95
  def remove_files_filter(request: Request, filter: FilesFilterRequest) -> Response:
98
- conversation_id = int(filter.conversation_id)
96
+ conversation_id = filter.conversation_id
99
97
  files_filter = filter.filenames
100
98
  file_filters = ConversationAdapters.remove_files_from_filter(request.user.object, conversation_id, files_filter)
101
99
  return Response(content=json.dumps(file_filters), media_type="application/json", status_code=200)
@@ -105,7 +103,7 @@ def remove_files_filter(request: Request, filter: FilesFilterRequest) -> Respons
105
103
  @requires(["authenticated"])
106
104
  def add_files_filter(request: Request, filter: FilesFilterRequest):
107
105
  try:
108
- conversation_id = int(filter.conversation_id)
106
+ conversation_id = filter.conversation_id
109
107
  files_filter = filter.filenames
110
108
  file_filters = ConversationAdapters.add_files_to_filter(request.user.object, conversation_id, files_filter)
111
109
  return Response(content=json.dumps(file_filters), media_type="application/json", status_code=200)
@@ -118,7 +116,7 @@ def add_files_filter(request: Request, filter: FilesFilterRequest):
118
116
  @requires(["authenticated"])
119
117
  def add_file_filter(request: Request, filter: FileFilterRequest):
120
118
  try:
121
- conversation_id = int(filter.conversation_id)
119
+ conversation_id = filter.conversation_id
122
120
  files_filter = [filter.filename]
123
121
  file_filters = ConversationAdapters.add_files_to_filter(request.user.object, conversation_id, files_filter)
124
122
  return Response(content=json.dumps(file_filters), media_type="application/json", status_code=200)
@@ -130,7 +128,7 @@ def add_file_filter(request: Request, filter: FileFilterRequest):
130
128
  @api_chat.delete("/conversation/file-filters", response_class=Response)
131
129
  @requires(["authenticated"])
132
130
  def remove_file_filter(request: Request, filter: FileFilterRequest) -> Response:
133
- conversation_id = int(filter.conversation_id)
131
+ conversation_id = filter.conversation_id
134
132
  files_filter = [filter.filename]
135
133
  file_filters = ConversationAdapters.remove_files_from_filter(request.user.object, conversation_id, files_filter)
136
134
  return Response(content=json.dumps(file_filters), media_type="application/json", status_code=200)
@@ -189,7 +187,7 @@ async def chat_starters(
189
187
  def chat_history(
190
188
  request: Request,
191
189
  common: CommonQueryParams,
192
- conversation_id: Optional[int] = None,
190
+ conversation_id: Optional[str] = None,
193
191
  n: Optional[int] = None,
194
192
  ):
195
193
  user = request.user.object
@@ -224,7 +222,6 @@ def chat_history(
224
222
  "conversation_id": conversation.id,
225
223
  "slug": conversation.title if conversation.title else conversation.slug,
226
224
  "agent": agent_metadata,
227
- "unique_id": conversation.unique_id,
228
225
  }
229
226
  )
230
227
 
@@ -246,33 +243,6 @@ def chat_history(
246
243
  return {"status": "ok", "response": meta_log}
247
244
 
248
245
 
249
- @api_chat.get("/metadata")
250
- def get_chat_metadata(
251
- request: Request,
252
- common: CommonQueryParams,
253
- conversation_unique_id: str,
254
- ):
255
- user = request.user.object
256
-
257
- # Load Conversation Metadata
258
- conversation = ConversationAdapters.get_conversation_by_unique_id(user, conversation_unique_id)
259
-
260
- if conversation is None:
261
- return Response(
262
- content=json.dumps({"status": "error", "message": f"Conversation: {conversation_unique_id} not found"}),
263
- status_code=404,
264
- )
265
-
266
- update_telemetry_state(
267
- request=request,
268
- telemetry_type="api",
269
- api="chat_metadata",
270
- **common.__dict__,
271
- )
272
-
273
- return {"status": "ok", "conversationId": conversation.id}
274
-
275
-
276
246
  @api_chat.get("/share/history")
277
247
  def get_shared_chat(
278
248
  request: Request,
@@ -340,7 +310,7 @@ def get_shared_chat(
340
310
  async def clear_chat_history(
341
311
  request: Request,
342
312
  common: CommonQueryParams,
343
- conversation_id: Optional[int] = None,
313
+ conversation_id: Optional[str] = None,
344
314
  ):
345
315
  user = request.user.object
346
316
 
@@ -403,7 +373,7 @@ def fork_public_conversation(
403
373
  def duplicate_chat_history_public_conversation(
404
374
  request: Request,
405
375
  common: CommonQueryParams,
406
- conversation_id: int,
376
+ conversation_id: str,
407
377
  ):
408
378
  user = request.user.object
409
379
  domain = request.headers.get("host")
@@ -446,18 +416,17 @@ def chat_sessions(
446
416
  conversations = conversations[:8]
447
417
 
448
418
  sessions = conversations.values_list(
449
- "id", "slug", "title", "agent__slug", "agent__name", "agent__avatar", "created_at", "updated_at", "unique_id"
419
+ "id", "slug", "title", "agent__slug", "agent__name", "agent__avatar", "created_at", "updated_at"
450
420
  )
451
421
 
452
422
  session_values = [
453
423
  {
454
- "conversation_id": session[0],
424
+ "conversation_id": str(session[0]),
455
425
  "slug": session[2] or session[1],
456
426
  "agent_name": session[4],
457
427
  "agent_avatar": session[5],
458
428
  "created": session[6].strftime("%Y-%m-%d %H:%M:%S"),
459
429
  "updated": session[7].strftime("%Y-%m-%d %H:%M:%S"),
460
- "unique_id": str(session[8]),
461
430
  }
462
431
  for session in sessions
463
432
  ]
@@ -484,7 +453,7 @@ async def create_chat_session(
484
453
  # Create new Conversation Session
485
454
  conversation = await ConversationAdapters.acreate_conversation_session(user, request.user.client_app, agent_slug)
486
455
 
487
- response = {"conversation_id": conversation.id, "unique_id": str(conversation.unique_id)}
456
+ response = {"conversation_id": str(conversation.id)}
488
457
 
489
458
  conversation_metadata = {
490
459
  "agent": agent_slug,
@@ -526,7 +495,7 @@ async def set_conversation_title(
526
495
  request: Request,
527
496
  common: CommonQueryParams,
528
497
  title: str,
529
- conversation_id: Optional[int] = None,
498
+ conversation_id: Optional[str] = None,
530
499
  ) -> Response:
531
500
  user = request.user.object
532
501
  title = title.strip()[:200]
@@ -556,7 +525,7 @@ class ChatRequestBody(BaseModel):
556
525
  d: Optional[float] = None
557
526
  stream: Optional[bool] = False
558
527
  title: Optional[str] = None
559
- conversation_id: Optional[int] = None
528
+ conversation_id: Optional[str] = None
560
529
  city: Optional[str] = None
561
530
  region: Optional[str] = None
562
531
  country: Optional[str] = None
@@ -1045,7 +1014,7 @@ async def get_chat(
1045
1014
  d: float = None,
1046
1015
  stream: Optional[bool] = False,
1047
1016
  title: Optional[str] = None,
1048
- conversation_id: Optional[int] = None,
1017
+ conversation_id: Optional[str] = None,
1049
1018
  city: Optional[str] = None,
1050
1019
  region: Optional[str] = None,
1051
1020
  country: Optional[str] = None,
khoj/routers/helpers.py CHANGED
@@ -21,7 +21,7 @@ from typing import (
21
21
  Tuple,
22
22
  Union,
23
23
  )
24
- from urllib.parse import parse_qs, urljoin, urlparse
24
+ from urllib.parse import parse_qs, quote, urljoin, urlparse
25
25
 
26
26
  import cron_descriptor
27
27
  import pytz
@@ -632,6 +632,7 @@ async def send_message_to_model_wrapper(
632
632
  messages=truncated_messages,
633
633
  loaded_model=loaded_model,
634
634
  model=chat_model,
635
+ max_prompt_size=max_tokens,
635
636
  streaming=False,
636
637
  response_type=response_type,
637
638
  )
@@ -721,6 +722,7 @@ def send_message_to_model_wrapper_sync(
721
722
  system_message=system_message,
722
723
  model_name=chat_model,
723
724
  loaded_model=loaded_model,
725
+ max_prompt_size=max_tokens,
724
726
  vision_enabled=vision_available,
725
727
  model_type=conversation_config.model_type,
726
728
  )
@@ -729,6 +731,7 @@ def send_message_to_model_wrapper_sync(
729
731
  messages=truncated_messages,
730
732
  loaded_model=loaded_model,
731
733
  model=chat_model,
734
+ max_prompt_size=max_tokens,
732
735
  streaming=False,
733
736
  response_type=response_type,
734
737
  )
@@ -739,6 +742,7 @@ def send_message_to_model_wrapper_sync(
739
742
  user_message=message,
740
743
  system_message=system_message,
741
744
  model_name=chat_model,
745
+ max_prompt_size=max_tokens,
742
746
  vision_enabled=vision_available,
743
747
  model_type=conversation_config.model_type,
744
748
  )
@@ -795,7 +799,7 @@ def generate_chat_response(
795
799
  conversation_commands: List[ConversationCommand] = [ConversationCommand.Default],
796
800
  user: KhojUser = None,
797
801
  client_application: ClientApplication = None,
798
- conversation_id: int = None,
802
+ conversation_id: str = None,
799
803
  location_data: LocationData = None,
800
804
  user_name: Optional[str] = None,
801
805
  uploaded_image_url: Optional[str] = None,
@@ -1098,7 +1102,7 @@ def scheduled_chat(
1098
1102
  user: KhojUser,
1099
1103
  calling_url: URL,
1100
1104
  job_id: str = None,
1101
- conversation_id: int = None,
1105
+ conversation_id: str = None,
1102
1106
  ):
1103
1107
  logger.info(f"Processing scheduled_chat: {query_to_run}")
1104
1108
  if job_id:
@@ -1127,7 +1131,8 @@ def scheduled_chat(
1127
1131
 
1128
1132
  # Replace the original conversation_id with the conversation_id
1129
1133
  if conversation_id:
1130
- query_dict["conversation_id"] = [conversation_id]
1134
+ # encode the conversation_id to avoid any issues with special characters
1135
+ query_dict["conversation_id"] = [quote(conversation_id)]
1131
1136
 
1132
1137
  # Restructure the original query_dict into a valid JSON payload for the chat API
1133
1138
  json_payload = {key: values[0] for key, values in query_dict.items()}
@@ -1181,7 +1186,7 @@ def scheduled_chat(
1181
1186
 
1182
1187
 
1183
1188
  async def create_automation(
1184
- q: str, timezone: str, user: KhojUser, calling_url: URL, meta_log: dict = {}, conversation_id: int = None
1189
+ q: str, timezone: str, user: KhojUser, calling_url: URL, meta_log: dict = {}, conversation_id: str = None
1185
1190
  ):
1186
1191
  crontime, query_to_run, subject = await schedule_query(q, meta_log)
1187
1192
  job = await schedule_automation(query_to_run, subject, crontime, timezone, q, user, calling_url, conversation_id)
@@ -1196,7 +1201,7 @@ async def schedule_automation(
1196
1201
  scheduling_request: str,
1197
1202
  user: KhojUser,
1198
1203
  calling_url: URL,
1199
- conversation_id: int,
1204
+ conversation_id: str,
1200
1205
  ):
1201
1206
  # Disable minute level automation recurrence
1202
1207
  minute_value = crontime.split(" ")[0]
@@ -1214,7 +1219,7 @@ async def schedule_automation(
1214
1219
  "scheduling_request": scheduling_request,
1215
1220
  "subject": subject,
1216
1221
  "crontime": crontime,
1217
- "conversation_id": conversation_id,
1222
+ "conversation_id": str(conversation_id),
1218
1223
  }
1219
1224
  )
1220
1225
  query_id = hashlib.md5(f"{query_to_run}_{crontime}".encode("utf-8")).hexdigest()
khoj/utils/cli.py CHANGED
@@ -50,6 +50,12 @@ def cli(args=None):
50
50
  default=False,
51
51
  help="Run Khoj in anonymous mode. This does not require any login for connecting users.",
52
52
  )
53
+ parser.add_argument(
54
+ "--non-interactive",
55
+ action="store_true",
56
+ default=False,
57
+ help="Start Khoj in non-interactive mode. Assumes interactive shell unavailable for config. E.g when run via Docker.",
58
+ )
53
59
 
54
60
  args, remaining_args = parser.parse_known_args(args)
55
61
 
khoj/utils/constants.py CHANGED
@@ -8,8 +8,15 @@ empty_escape_sequences = "\n|\r|\t| "
8
8
  app_env_filepath = "~/.khoj/env"
9
9
  telemetry_server = "https://khoj.beta.haletic.com/v1/telemetry"
10
10
  content_directory = "~/.khoj/content/"
11
- default_offline_chat_model = "bartowski/Meta-Llama-3.1-8B-Instruct-GGUF"
12
- default_online_chat_model = "gpt-4o-mini"
11
+ default_offline_chat_models = [
12
+ "bartowski/Meta-Llama-3.1-8B-Instruct-GGUF",
13
+ "bartowski/gemma-2-9b-it-GGUF",
14
+ "bartowski/gemma-2-2b-it-GGUF",
15
+ "bartowski/Phi-3.5-mini-instruct-GGUF",
16
+ ]
17
+ default_openai_chat_models = ["gpt-4o-mini", "gpt-4o"]
18
+ default_gemini_chat_models = ["gemini-1.5-flash", "gemini-1.5-pro"]
19
+ default_anthropic_chat_models = ["claude-3-5-sonnet-20240620", "claude-3-opus-20240229"]
13
20
 
14
21
  empty_config = {
15
22
  "search-type": {