khoj 1.24.1.dev7__py3-none-any.whl → 1.24.2.dev3__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 (49) hide show
  1. khoj/database/adapters/__init__.py +8 -1
  2. khoj/interface/compiled/404/index.html +1 -1
  3. khoj/interface/compiled/_next/static/chunks/1603-3e2e1528e3b6ea1d.js +1 -0
  4. khoj/interface/compiled/_next/static/chunks/{9178-f478bc3670cc0cb8.js → 9178-7e815211edcb3657.js} +1 -1
  5. khoj/interface/compiled/_next/static/chunks/app/automations/page-0a5de8c254c29a1c.js +1 -0
  6. khoj/interface/compiled/_next/static/chunks/app/chat/page-d96bf6a84bb05290.js +1 -0
  7. khoj/interface/compiled/_next/static/chunks/app/share/chat/page-f06ac16cfe5b5a16.js +1 -0
  8. khoj/interface/compiled/_next/static/chunks/{webpack-d5a40bbe9f041987.js → webpack-d4781cada9b58e75.js} +1 -1
  9. khoj/interface/compiled/agents/index.html +1 -1
  10. khoj/interface/compiled/agents/index.txt +2 -2
  11. khoj/interface/compiled/automations/index.html +1 -1
  12. khoj/interface/compiled/automations/index.txt +2 -2
  13. khoj/interface/compiled/chat/index.html +1 -1
  14. khoj/interface/compiled/chat/index.txt +2 -2
  15. khoj/interface/compiled/factchecker/index.html +1 -1
  16. khoj/interface/compiled/factchecker/index.txt +2 -2
  17. khoj/interface/compiled/index.html +1 -1
  18. khoj/interface/compiled/index.txt +2 -2
  19. khoj/interface/compiled/search/index.html +1 -1
  20. khoj/interface/compiled/search/index.txt +2 -2
  21. khoj/interface/compiled/settings/index.html +1 -1
  22. khoj/interface/compiled/settings/index.txt +2 -2
  23. khoj/interface/compiled/share/chat/index.html +1 -1
  24. khoj/interface/compiled/share/chat/index.txt +2 -2
  25. khoj/interface/web/login.html +261 -159
  26. khoj/processor/conversation/anthropic/anthropic_chat.py +2 -3
  27. khoj/processor/conversation/google/gemini_chat.py +2 -3
  28. khoj/processor/conversation/offline/chat_model.py +2 -3
  29. khoj/processor/conversation/openai/gpt.py +2 -3
  30. khoj/processor/tools/online_search.py +5 -5
  31. khoj/routers/api_chat.py +15 -6
  32. khoj/routers/helpers.py +3 -4
  33. khoj/utils/helpers.py +23 -0
  34. khoj/utils/rawconfig.py +11 -0
  35. {khoj-1.24.1.dev7.dist-info → khoj-1.24.2.dev3.dist-info}/METADATA +1 -1
  36. {khoj-1.24.1.dev7.dist-info → khoj-1.24.2.dev3.dist-info}/RECORD +45 -45
  37. khoj/interface/compiled/_next/static/chunks/1603-e13f41ec2cb3f147.js +0 -1
  38. khoj/interface/compiled/_next/static/chunks/app/automations/page-e0bedd962fcfa0dd.js +0 -1
  39. khoj/interface/compiled/_next/static/chunks/app/chat/page-1b886aa4f57af1fa.js +0 -1
  40. khoj/interface/compiled/_next/static/chunks/app/share/chat/page-7df9c23b5fec66de.js +0 -1
  41. /khoj/interface/compiled/_next/static/{iZkIzW249gxw1JKlivPbz → _29ceahp81LhuIHo5QgOD}/_buildManifest.js +0 -0
  42. /khoj/interface/compiled/_next/static/{iZkIzW249gxw1JKlivPbz → _29ceahp81LhuIHo5QgOD}/_ssgManifest.js +0 -0
  43. /khoj/interface/compiled/_next/static/chunks/{8423-7f5eb790353afe24.js → 8423-62ac6c832be2461b.js} +0 -0
  44. /khoj/interface/compiled/_next/static/chunks/{9417-2e54c6fd056982d8.js → 9417-5d14ac74aaab2c66.js} +0 -0
  45. /khoj/interface/compiled/_next/static/chunks/app/agents/{page-f41c3b57b5bfc0bd.js → page-d302911777a3e027.js} +0 -0
  46. /khoj/interface/compiled/_next/static/chunks/app/{page-a31799b4c4b78da6.js → page-96cab08c985716f4.js} +0 -0
  47. {khoj-1.24.1.dev7.dist-info → khoj-1.24.2.dev3.dist-info}/WHEEL +0 -0
  48. {khoj-1.24.1.dev7.dist-info → khoj-1.24.2.dev3.dist-info}/entry_points.txt +0 -0
  49. {khoj-1.24.1.dev7.dist-info → khoj-1.24.2.dev3.dist-info}/licenses/LICENSE +0 -0
@@ -1,219 +1,321 @@
1
1
  <html>
2
- <head>
3
- <meta charset="utf-8">
4
- <meta name="viewport" content="width=device-width, initial-scale=1.0 maximum-scale=1.0">
5
- <title>Khoj - Login</title>
6
-
7
- <link rel="icon" type="image/png" sizes="128x128" href="https://assets.khoj.dev/khoj_lantern_128x128.png">
8
- <link rel="manifest" href="/static/khoj.webmanifest">
9
- <link rel="stylesheet" href="/static/assets/khoj.css">
10
- <meta property="og:image" content="https://assets.khoj.dev/khoj_hero.png">
11
- </head>
12
-
13
- <body>
14
- <div class="khoj-header"></div>
15
- <!-- Login Modal -->
2
+
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
6
+ <title>Khoj - Login</title>
7
+ <link rel="icon" type="image/png" sizes="128x128" href="https://assets.khoj.dev/khoj_lantern_128x128.png">
8
+ <link rel="manifest" href="/static/khoj.webmanifest">
9
+ <link rel="stylesheet" href="/static/assets/khoj.css">
10
+ <meta property="og:image" content="https://assets.khoj.dev/khoj_hero.png">
11
+ </head>
12
+
13
+ <body>
14
+ <div class="split-container">
15
+ <!-- Left side with login -->
16
+ <div class="split left">
16
17
  <div id="login-modal">
17
- <img class="khoj-logo" src="https://assets.khoj.dev/khoj_lantern_128x128.png" alt="Khoj"></img>
18
+ <img class="khoj-logo" src="https://assets.khoj.dev/khoj_lantern_128x128.png" alt="Khoj">
18
19
  <div class="login-modal-title">Login to Khoj</div>
20
+ <!-- Sign Up/Login with Google OAuth -->
21
+ <div class="g_id_signin" data-shape="circle" data-text="continue_with" data-logo_alignment="center"
22
+ data-size="large" data-type="standard"></div>
23
+ <div id="g_id_onload" data-client_id="{{ google_client_id }}" data-ux_mode="popup"
24
+ data-use_fedcm_for_prompt="true" data-login_uri="{{ redirect_uri }}" data-auto-select="true"></div>
25
+
26
+ <!-- Divider -->
27
+ <div class="divider">OR</div>
19
28
  <!-- Sign in with Magic Link -->
20
29
  <div class="khoj-magic-link">
21
30
  <input type="email" id="email" placeholder="Email" autofocus required>
22
- <button id="magic-link-button">Send Magic Link</button>
31
+ <button id="magic-link-button">Get Login Link</button>
23
32
  </div>
24
- <!-- Divider -->
25
- <div style="text-align: center; font-size: 16px; font-weight: 500; border-top: 1px solid black;">OR</div>
26
- <!-- Sign Up/Login with Google OAuth -->
27
- <div
28
- class="g_id_signin"
29
- data-shape="circle"
30
- data-text="continue_with"
31
- data-logo_alignment="center"
32
- data-size="large"
33
- data-type="standard">
34
- </div>
35
- <div id="g_id_onload"
36
- data-client_id="{{ google_client_id }}"
37
- data-ux_mode="popup"
38
- data-use_fedcm_for_prompt="true"
39
- data-login_uri="{{ redirect_uri }}"
40
- data-auto-select="true">
33
+
34
+ </div>
35
+ <!-- Footer links -->
36
+ <div class="footer-links">
37
+ <a href="https://khoj.dev/terms-of-service" target="_blank">Terms of Service</a>
38
+ <span class="divider-vertical"></span>
39
+ <a href="https://khoj.dev/privacy-policy" target="_blank">Privacy Policy</a>
40
+ </div>
41
+ </div>
42
+ <!-- Right side with content -->
43
+ <div class="split right">
44
+ <div class="right-content">
45
+ <h1>Unlock Your Second Brain</h1>
46
+ <p>Transform the way you think, create, and remember</p>
47
+ <div class="features">
48
+ <div class="feature">
49
+ <svg viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2"
50
+ fill="none">
51
+ <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
52
+ <path d="M14 2v6h6" />
53
+ <path d="M16 13H8" />
54
+ <path d="M16 17H8" />
55
+ <path d="M10 9H8" />
56
+ </svg>
57
+ <span>Get answers across your documents and the internet</span>
58
+ </div>
59
+ <div class="feature">
60
+ <svg viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2"
61
+ fill="none">
62
+ <path
63
+ d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" />
64
+ <path d="M3.3 7l8.7 5 8.7-5" />
65
+ </svg>
66
+ <span>Go deeper in the topics personal to you</span>
67
+ </div>
68
+ <div class="feature">
69
+ <svg viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2"
70
+ fill="none">
71
+ <path d="M12 2L2 7l10 5 10-5-10-5z" />
72
+ <path d="M2 17l10 5 10-5" />
73
+ <path d="M2 12l10 5 10-5" />
74
+ </svg>
75
+ <span>Use specialized agents</span>
76
+ </div>
41
77
  </div>
42
78
  </div>
43
-
44
- <div class="khoj-footer"></div>
45
79
  </div>
46
- </body>
80
+ </div>
47
81
 
48
- <script>
49
- const magicLinkButton = document.getElementById('magic-link-button');
50
- const emailInput = document.getElementById('email');
51
-
52
- magicLinkButton.addEventListener('click', async () => {
53
- const email = emailInput.value;
54
- if (!email) {
55
- alert('Please enter a valid email address');
56
- return;
57
- }
58
-
59
- if (!email.includes('@')) {
60
- alert('Please enter a valid email address');
61
- return;
62
- }
63
-
64
- magicLinkButton.disabled = true;
65
- magicLinkButton.innerText = 'Check your email for a sign-in link!';
82
+ <style>
83
+ body {
84
+ margin: 0;
85
+ height: 100vh;
86
+ font-family: 'Arial', sans-serif;
87
+ color: #333;
88
+ overflow: hidden;
89
+ }
66
90
 
67
- const response = await fetch('/auth/magic', {
68
- method: 'POST',
69
- headers: {
70
- 'Content-Type': 'application/json',
71
- },
72
- body: JSON.stringify({ "email": email }),
73
- })
91
+ .split-container {
92
+ display: flex;
93
+ height: 100vh;
94
+ }
74
95
 
75
- if (response.status === 200) {
76
- console.log('Magic link sent to your email');
77
- } else {
78
- alert('Failed to send magic link');
79
- }
80
- });
81
- </script>
96
+ .split {
97
+ flex: 1;
98
+ display: flex;
99
+ justify-content: center;
100
+ align-items: center;
101
+ flex-direction: column;
102
+ }
82
103
 
83
- <style>
84
- @media only screen and (max-width: 700px) {
85
- body {
86
- display: grid;
87
- grid-template-columns: 1fr;
88
- grid-template-rows: 1fr auto 1fr;
89
- font-size: small!important;
90
- }
91
- body > * {
92
- grid-column: 1;
93
- }
104
+ .left {
105
+ background-color: #fff;
94
106
  }
95
- @media only screen and (min-width: 700px) {
96
- body {
97
- display: grid;
98
- grid-template-columns: 1fr min(50vw, 100%) 1fr;
99
- grid-template-rows: 1fr auto 1fr;
100
- }
101
- body > * {
102
- grid-column: 2;
103
- }
107
+
108
+ .right {
109
+ background: linear-gradient(135deg, #FFA07A 0%, #c4e4c6 100%);
110
+ color: white;
111
+ position: relative;
112
+ overflow: hidden;
104
113
  }
105
- body {
106
- padding: 0px;
107
- margin: 0px;
108
- height: 100%;
109
- background: url('/static/assets/samples/desktop-plain-chat-sample.png') no-repeat center center fixed;
110
- background-size: contain;
111
- color: var(--main-text-color);
112
- font-family: var(--font-family);
113
- font-size: 20px;
114
- font-weight: 300;
115
- line-height: 1.5em;
116
- }
117
- body::before {
118
- content: "";
114
+
115
+ .right::before {
116
+ content: '';
119
117
  position: absolute;
120
118
  top: 0;
121
119
  left: 0;
122
- width: 100%;
123
- height: 100%;
124
- background: var(--frosted-background-color);
125
- backdrop-filter: blur(10px);
120
+ right: 0;
121
+ bottom: 0;
122
+ opacity: 0.1;
126
123
  }
127
- body > * {
128
- padding: 10px;
129
- margin: 10px;
124
+
125
+ .right-content {
126
+ text-align: center;
127
+ padding: 2rem;
128
+ position: relative;
129
+ z-index: 1;
130
130
  }
131
131
 
132
- @keyframes gradient {
133
- 0% {
134
- background-position: 0% 50%;
135
- }
136
- 50% {
137
- background-position: 100% 50%;
138
- }
139
- 100% {
140
- background-position: 0% 50%;
141
- }
132
+ .right-content h1 {
133
+ font-size: 3rem;
134
+ margin-bottom: 1rem;
135
+ font-weight: 700;
142
136
  }
143
137
 
144
- a.khoj-logo {
145
- text-align: center;
146
- justify-self: center;
138
+ .right-content p {
139
+ font-size: 1.2rem;
140
+ margin-bottom: 3rem;
141
+ opacity: 0.9;
147
142
  }
148
143
 
149
- div#login-modal {
150
- display: grid;
151
- grid-template-columns: 1fr;
152
- gap: 32px;
153
- min-height: 300px;
154
- margin-left: 25%;
155
- margin-right: 25%;
156
- z-index: 1;
144
+ .features {
145
+ display: flex;
146
+ flex-direction: column;
147
+ gap: 1.5rem;
148
+ align-items: center;
157
149
  }
158
150
 
159
- .khoj-magic-link {
151
+ .feature {
152
+ display: flex;
153
+ align-items: center;
154
+ gap: 1rem;
155
+ font-size: 1.1rem;
156
+ }
157
+
158
+ .feature svg {
159
+ width: 24px;
160
+ height: 24px;
161
+ stroke: white;
162
+ }
163
+
164
+ #login-modal {
160
165
  display: grid;
161
- grid-template-columns: 1fr;
162
- gap: 16px;
166
+ background: white;
167
+ border-radius: 10px;
168
+ padding: 40px;
169
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
163
170
  text-align: center;
171
+ width: max-content;
172
+ }
173
+
174
+ .khoj-logo {
175
+ width: 80px;
176
+ margin-bottom: 20px;
177
+ }
178
+
179
+ .login-modal-title {
180
+ font-size: 24px;
181
+ font-weight: 600;
182
+ margin-bottom: 20px;
183
+ }
184
+
185
+ .khoj-magic-link {
186
+ display: flex;
187
+ flex-direction: column;
188
+ gap: 10px;
164
189
  }
165
190
 
166
191
  #email {
167
192
  padding: 10px;
168
- font-size: 16px;
169
- border: 1px solid var(--main-text-color);
193
+ border: 1px solid #ccc;
170
194
  border-radius: 5px;
171
195
  width: 100%;
172
- }
173
-
174
- #email:focus {
175
- box-shadow: 0 0 10px var(--main-text-color);
196
+ font-size: 16px;
176
197
  }
177
198
 
178
199
  #magic-link-button {
179
200
  padding: 10px;
180
- font-size: 16px;
181
- border: 1px solid var(--main-text-color);
201
+ border: none;
182
202
  border-radius: 5px;
183
- width: 100%;
184
- background: var(--main-text-color);
185
- color: var(--frosted-background-color);
203
+ background-color: #FFA07A;
204
+ color: white;
186
205
  cursor: pointer;
206
+ font-size: 16px;
207
+ transition: background-color 0.3s;
187
208
  }
188
209
 
189
210
  #magic-link-button:hover {
190
- box-shadow: 0 0 10px var(--main-text-color);
211
+ background-color: #FFA07A
212
+ }
213
+
214
+ #magic-link-button:disabled {
215
+ background-color: #cccccc;
216
+ cursor: not-allowed;
191
217
  }
192
218
 
193
- div.g_id_signin {
219
+ .divider {
220
+ display: flex;
221
+ align-items: center;
222
+ text-align: center;
223
+ color: #000;
224
+ /* Adjust the text color as needed */
225
+ margin: 20px 0;
226
+ /* Adjust the margin as needed */
227
+ }
228
+
229
+ .divider::before,
230
+ .divider::after {
231
+ content: '';
232
+ flex: 1;
233
+ border-bottom: 1px solid #000;
234
+ /* Adjust the line color as needed */
235
+ margin: 0 10px;
236
+ /* Adjust the spacing as needed */
237
+ }
238
+
239
+ .g_id_signin {
194
240
  margin: 0 auto;
195
241
  display: block;
196
242
  }
197
243
 
198
- div.login-modal-title {
244
+ .footer-links {
245
+ width: 100%;
199
246
  text-align: center;
200
- line-height: 28px;
201
- font-size: 24px;
202
- font-weight: 500;
247
+ font-size: 0.9em;
248
+ color: #666;
249
+ margin-top: 20px;
250
+ }
251
+
252
+ .footer-links a {
253
+ color: #666;
254
+ text-decoration: none;
255
+ margin: 0 10px;
256
+ }
257
+
258
+ .footer-links a:hover {
259
+ text-decoration: underline;
260
+ }
261
+
262
+ .divider-vertical {
263
+ display: inline-block;
264
+ width: 1px;
265
+ height: 12px;
266
+ background-color: #666;
267
+ margin: 0 10px;
268
+ vertical-align: middle;
203
269
  }
204
270
 
205
- @media only screen and (max-width: 700px) {
206
- body{
207
- background: url('/static/assets/samples/phone-plain-chat-sample.png') no-repeat center center fixed;
208
- background-size: contain;
271
+ @media (max-width: 768px) {
272
+ .split-container {
273
+ flex-direction: column;
209
274
  }
210
- div#login-modal {
211
- margin-left: 10%;
212
- margin-right: 10%;
213
- z-index: 1;
275
+
276
+ .right {
277
+ display: none;
214
278
  }
215
- }
216
279
 
280
+ .left {
281
+ padding: 2rem;
282
+ }
283
+ }
217
284
  </style>
285
+
286
+ <script>
287
+ const magicLinkButton = document.getElementById('magic-link-button');
288
+ const emailInput = document.getElementById('email');
289
+ magicLinkButton.addEventListener('click', async () => {
290
+ const email = emailInput.value;
291
+ if (!email) {
292
+ alert('Please enter a valid email address');
293
+ return;
294
+ }
295
+ if (!email.includes('@')) {
296
+ alert('Please enter a valid email address');
297
+ return;
298
+ }
299
+ magicLinkButton.disabled = true;
300
+ magicLinkButton.innerText = 'Check your email for a sign-in link!';
301
+ const response = await fetch('/auth/magic', {
302
+ method: 'POST',
303
+ headers: {
304
+ 'Content-Type': 'application/json',
305
+ },
306
+ body: JSON.stringify({ "email": email }),
307
+ });
308
+ if (response.status === 200) {
309
+ console.log('Magic link sent to your email');
310
+ } else {
311
+ alert('Failed to send magic link');
312
+ magicLinkButton.disabled = false;
313
+ magicLinkButton.innerText = 'Get Login Link';
314
+ }
315
+ });
316
+ </script>
317
+
218
318
  <script src="https://accounts.google.com/gsi/client" async defer></script>
319
+ </body>
320
+
219
321
  </html>
@@ -32,7 +32,7 @@ def extract_questions_anthropic(
32
32
  Infer search queries to retrieve relevant notes to answer user query
33
33
  """
34
34
  # Extract Past User Message and Inferred Questions from Conversation Log
35
- location = f"{location_data.city}, {location_data.region}, {location_data.country}" if location_data else "Unknown"
35
+ location = f"{location_data}" if location_data else "Unknown"
36
36
  username = prompts.user_name.format(name=user.get_full_name()) if user and user.get_full_name() else ""
37
37
 
38
38
  # Extract Past User Message and Inferred Questions from Conversation Log
@@ -158,8 +158,7 @@ def converse_anthropic(
158
158
  )
159
159
 
160
160
  if location_data:
161
- location = f"{location_data.city}, {location_data.region}, {location_data.country}"
162
- location_prompt = prompts.user_location.format(location=location)
161
+ location_prompt = prompts.user_location.format(location=f"{location_data}")
163
162
  system_prompt = f"{system_prompt}\n{location_prompt}"
164
163
 
165
164
  if user_name:
@@ -33,7 +33,7 @@ def extract_questions_gemini(
33
33
  Infer search queries to retrieve relevant notes to answer user query
34
34
  """
35
35
  # Extract Past User Message and Inferred Questions from Conversation Log
36
- location = f"{location_data.city}, {location_data.region}, {location_data.country}" if location_data else "Unknown"
36
+ location = f"{location_data}" if location_data else "Unknown"
37
37
  username = prompts.user_name.format(name=user.get_full_name()) if user and user.get_full_name() else ""
38
38
 
39
39
  # Extract Past User Message and Inferred Questions from Conversation Log
@@ -163,8 +163,7 @@ def converse_gemini(
163
163
  )
164
164
 
165
165
  if location_data:
166
- location = f"{location_data.city}, {location_data.region}, {location_data.country}"
167
- location_prompt = prompts.user_location.format(location=location)
166
+ location_prompt = prompts.user_location.format(location=f"{location_data}")
168
167
  system_prompt = f"{system_prompt}\n{location_prompt}"
169
168
 
170
169
  if user_name:
@@ -46,7 +46,7 @@ def extract_questions_offline(
46
46
  assert loaded_model is None or isinstance(loaded_model, Llama), "loaded_model must be of type Llama, if configured"
47
47
  offline_chat_model = loaded_model or download_model(model, max_tokens=max_prompt_size)
48
48
 
49
- location = f"{location_data.city}, {location_data.region}, {location_data.country}" if location_data else "Unknown"
49
+ location = f"{location_data}" if location_data else "Unknown"
50
50
  username = prompts.user_name.format(name=user.get_full_name()) if user and user.get_full_name() else ""
51
51
 
52
52
  # Extract Past User Message and Inferred Questions from Conversation Log
@@ -171,8 +171,7 @@ def converse_offline(
171
171
  conversation_primer = prompts.query_prompt.format(query=user_query)
172
172
 
173
173
  if location_data:
174
- location = f"{location_data.city}, {location_data.region}, {location_data.country}"
175
- location_prompt = prompts.user_location.format(location=location)
174
+ location_prompt = prompts.user_location.format(location=f"{location_data}")
176
175
  system_prompt = f"{system_prompt}\n{location_prompt}"
177
176
 
178
177
  if user_name:
@@ -36,7 +36,7 @@ def extract_questions(
36
36
  """
37
37
  Infer search queries to retrieve relevant notes to answer user query
38
38
  """
39
- location = f"{location_data.city}, {location_data.region}, {location_data.country}" if location_data else "Unknown"
39
+ location = f"{location_data}" if location_data else "Unknown"
40
40
  username = prompts.user_name.format(name=user.get_full_name()) if user and user.get_full_name() else ""
41
41
 
42
42
  # Extract Past User Message and Inferred Questions from Conversation Log
@@ -159,8 +159,7 @@ def converse(
159
159
  )
160
160
 
161
161
  if location_data:
162
- location = f"{location_data.city}, {location_data.region}, {location_data.country}"
163
- location_prompt = prompts.user_location.format(location=location)
162
+ location_prompt = prompts.user_location.format(location=f"{location_data}")
164
163
  system_prompt = f"{system_prompt}\n{location_prompt}"
165
164
 
166
165
  if user_name:
@@ -7,7 +7,6 @@ from collections import defaultdict
7
7
  from typing import Callable, Dict, List, Optional, Tuple, Union
8
8
 
9
9
  import aiohttp
10
- import requests
11
10
  from bs4 import BeautifulSoup
12
11
  from markdownify import markdownify
13
12
 
@@ -80,7 +79,7 @@ async def search_online(
80
79
 
81
80
  with timer(f"Internet searches for {list(subqueries)} took", logger):
82
81
  search_func = search_with_google if SERPER_DEV_API_KEY else search_with_jina
83
- search_tasks = [search_func(subquery) for subquery in subqueries]
82
+ search_tasks = [search_func(subquery, location) for subquery in subqueries]
84
83
  search_results = await asyncio.gather(*search_tasks)
85
84
  response_dict = {subquery: search_result for subquery, search_result in search_results}
86
85
 
@@ -115,8 +114,9 @@ async def search_online(
115
114
  yield response_dict
116
115
 
117
116
 
118
- async def search_with_google(query: str) -> Tuple[str, Dict[str, List[Dict]]]:
119
- payload = json.dumps({"q": query})
117
+ async def search_with_google(query: str, location: LocationData) -> Tuple[str, Dict[str, List[Dict]]]:
118
+ country_code = location.country_code.lower() if location and location.country_code else "us"
119
+ payload = json.dumps({"q": query, "gl": country_code})
120
120
  headers = {"X-API-KEY": SERPER_DEV_API_KEY, "Content-Type": "application/json"}
121
121
 
122
122
  async with aiohttp.ClientSession() as session:
@@ -220,7 +220,7 @@ async def read_webpage_with_jina(web_url: str) -> str:
220
220
  return response_json["data"]["content"]
221
221
 
222
222
 
223
- async def search_with_jina(query: str) -> Tuple[str, Dict[str, List[Dict]]]:
223
+ async def search_with_jina(query: str, location: LocationData) -> Tuple[str, Dict[str, List[Dict]]]:
224
224
  encoded_query = urllib.parse.quote(query)
225
225
  jina_search_api_url = f"{JINA_SEARCH_API_URL}/{encoded_query}"
226
226
  headers = {"Accept": "application/json"}
khoj/routers/api_chat.py CHANGED
@@ -55,6 +55,8 @@ from khoj.utils.helpers import (
55
55
  ConversationCommand,
56
56
  command_descriptions,
57
57
  convert_image_to_webp,
58
+ get_country_code_from_timezone,
59
+ get_country_name_from_timezone,
58
60
  get_device,
59
61
  is_none_or_empty,
60
62
  )
@@ -529,8 +531,10 @@ class ChatRequestBody(BaseModel):
529
531
  city: Optional[str] = None
530
532
  region: Optional[str] = None
531
533
  country: Optional[str] = None
534
+ country_code: Optional[str] = None
532
535
  timezone: Optional[str] = None
533
536
  image: Optional[str] = None
537
+ create_new: Optional[bool] = False
534
538
 
535
539
 
536
540
  @api_chat.post("")
@@ -540,10 +544,10 @@ async def chat(
540
544
  common: CommonQueryParams,
541
545
  body: ChatRequestBody,
542
546
  rate_limiter_per_minute=Depends(
543
- ApiUserRateLimiter(requests=60, subscribed_requests=60, window=60, slug="chat_minute")
547
+ ApiUserRateLimiter(requests=60, subscribed_requests=200, window=60, slug="chat_minute")
544
548
  ),
545
549
  rate_limiter_per_day=Depends(
546
- ApiUserRateLimiter(requests=600, subscribed_requests=600, window=60 * 60 * 24, slug="chat_day")
550
+ ApiUserRateLimiter(requests=600, subscribed_requests=6000, window=60 * 60 * 24, slug="chat_day")
547
551
  ),
548
552
  ):
549
553
  # Access the parameters from the body
@@ -555,7 +559,8 @@ async def chat(
555
559
  conversation_id = body.conversation_id
556
560
  city = body.city
557
561
  region = body.region
558
- country = body.country
562
+ country = body.country or get_country_name_from_timezone(body.timezone)
563
+ country_code = body.country_code or get_country_code_from_timezone(body.timezone)
559
564
  timezone = body.timezone
560
565
  image = body.image
561
566
 
@@ -641,7 +646,11 @@ async def chat(
641
646
  conversation_commands = [get_conversation_command(query=q, any_references=True)]
642
647
 
643
648
  conversation = await ConversationAdapters.aget_conversation_by_user(
644
- user, client_application=request.user.client_app, conversation_id=conversation_id, title=title
649
+ user,
650
+ client_application=request.user.client_app,
651
+ conversation_id=conversation_id,
652
+ title=title,
653
+ create_new=body.create_new,
645
654
  )
646
655
  if not conversation:
647
656
  async for result in send_llm_response(f"Conversation {conversation_id} not found"):
@@ -653,8 +662,8 @@ async def chat(
653
662
 
654
663
  user_name = await aget_user_name(user)
655
664
  location = None
656
- if city or region or country:
657
- location = LocationData(city=city, region=region, country=country)
665
+ if city or region or country or country_code:
666
+ location = LocationData(city=city, region=region, country=country, country_code=country_code)
658
667
 
659
668
  if is_query_empty(q):
660
669
  async for result in send_llm_response("Please ask your query to get started."):