khoj 1.36.7.dev7__py3-none-any.whl → 1.36.7.dev22__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 (61) hide show
  1. khoj/database/adapters/__init__.py +15 -0
  2. khoj/interface/compiled/404/index.html +2 -2
  3. khoj/interface/compiled/_next/static/chunks/{2327-02e86a50c65e575a.js → 2327-36d17f2483e80f60.js} +1 -1
  4. khoj/interface/compiled/_next/static/chunks/{8155-ad130153ddcc930f.js → 8155-87b4d2ea2cf725cc.js} +1 -1
  5. khoj/interface/compiled/_next/static/chunks/app/agents/{layout-64b81f8eeac13427.js → layout-447b58869479276c.js} +1 -1
  6. khoj/interface/compiled/_next/static/chunks/app/agents/{page-2f55f9d0da49bf31.js → page-fbe2c1c661cd14ac.js} +1 -1
  7. khoj/interface/compiled/_next/static/chunks/app/automations/{page-d0a630a2b4ecc41d.js → page-ad620b194fd508fe.js} +1 -1
  8. khoj/interface/compiled/_next/static/chunks/app/chat/{layout-9e151fb837f53026.js → layout-4d0b1ba93124fccb.js} +1 -1
  9. khoj/interface/compiled/_next/static/chunks/app/chat/{page-53ba9f1424043383.js → page-4108f46796c1c606.js} +1 -1
  10. khoj/interface/compiled/_next/static/chunks/app/{layout-26139159e500852a.js → layout-6dba801826c4fe59.js} +1 -1
  11. khoj/interface/compiled/_next/static/chunks/app/{page-642bd02fc4f16606.js → page-f91e6a6a849baf5e.js} +1 -1
  12. khoj/interface/compiled/_next/static/chunks/app/search/{layout-ff081947c70ea9b7.js → layout-ab5dbb69fb914900.js} +1 -1
  13. khoj/interface/compiled/_next/static/chunks/app/search/{page-7c80e369ee1cdfad.js → page-30e231665f1f3796.js} +1 -1
  14. khoj/interface/compiled/_next/static/chunks/app/settings/{page-c961681e308a334b.js → page-c580520d59d92267.js} +1 -1
  15. khoj/interface/compiled/_next/static/chunks/app/share/chat/{layout-94a33aa0eae034fc.js → layout-2ce0cb95b1219d97.js} +1 -1
  16. khoj/interface/compiled/_next/static/chunks/app/share/chat/{page-6253896a84300e9b.js → page-ffcb3ce5c6af9988.js} +1 -1
  17. khoj/interface/compiled/_next/static/chunks/{webpack-f813971dd4615afd.js → webpack-f83765a7accac982.js} +1 -1
  18. khoj/interface/compiled/_next/static/css/7889a30fe9c83846.css +1 -0
  19. khoj/interface/compiled/_next/static/css/{804ceddd6c935d4a.css → 8051073dc55b92b3.css} +1 -1
  20. khoj/interface/compiled/_next/static/css/f29752d6e1be7624.css +1 -0
  21. khoj/interface/compiled/_next/static/media/2aa11a72f7f24b58-s.woff2 +0 -0
  22. khoj/interface/compiled/_next/static/media/383a65b63658737d-s.woff2 +0 -0
  23. khoj/interface/compiled/_next/static/media/40381518f67e6cb9-s.p.woff2 +0 -0
  24. khoj/interface/compiled/_next/static/media/85fe2766c5e6072a-s.woff2 +0 -0
  25. khoj/interface/compiled/_next/static/media/8a6e4d7cd15e805a-s.woff2 +0 -0
  26. khoj/interface/compiled/agents/index.html +3 -3
  27. khoj/interface/compiled/agents/index.txt +3 -3
  28. khoj/interface/compiled/automations/index.html +2 -2
  29. khoj/interface/compiled/automations/index.txt +3 -3
  30. khoj/interface/compiled/chat/index.html +3 -3
  31. khoj/interface/compiled/chat/index.txt +3 -3
  32. khoj/interface/compiled/index.html +2 -2
  33. khoj/interface/compiled/index.txt +3 -3
  34. khoj/interface/compiled/search/index.html +2 -2
  35. khoj/interface/compiled/search/index.txt +3 -3
  36. khoj/interface/compiled/settings/index.html +3 -3
  37. khoj/interface/compiled/settings/index.txt +2 -2
  38. khoj/interface/compiled/share/chat/index.html +3 -3
  39. khoj/interface/compiled/share/chat/index.txt +3 -3
  40. khoj/processor/conversation/anthropic/anthropic_chat.py +6 -3
  41. khoj/processor/conversation/anthropic/utils.py +48 -13
  42. khoj/processor/conversation/google/gemini_chat.py +12 -12
  43. khoj/processor/conversation/google/utils.py +63 -63
  44. khoj/processor/conversation/prompts.py +100 -19
  45. khoj/processor/conversation/utils.py +6 -0
  46. khoj/processor/tools/run_code.py +163 -21
  47. khoj/routers/helpers.py +5 -0
  48. khoj/routers/research.py +1 -0
  49. khoj/utils/constants.py +6 -2
  50. khoj/utils/helpers.py +11 -2
  51. khoj/utils/initialization.py +24 -7
  52. {khoj-1.36.7.dev7.dist-info → khoj-1.36.7.dev22.dist-info}/METADATA +7 -6
  53. {khoj-1.36.7.dev7.dist-info → khoj-1.36.7.dev22.dist-info}/RECORD +58 -54
  54. khoj/interface/compiled/_next/static/css/089de1d8526b96e9.css +0 -1
  55. khoj/interface/compiled/_next/static/css/55d4a822f8d94b67.css +0 -1
  56. khoj/interface/compiled/_next/static/media/e098aaaecc9cfbb2-s.p.woff2 +0 -0
  57. /khoj/interface/compiled/_next/static/{bzWTm19u6qe1y98Xfrqoo → w25ObnntxL_4D4MY2j-Yc}/_buildManifest.js +0 -0
  58. /khoj/interface/compiled/_next/static/{bzWTm19u6qe1y98Xfrqoo → w25ObnntxL_4D4MY2j-Yc}/_ssgManifest.js +0 -0
  59. {khoj-1.36.7.dev7.dist-info → khoj-1.36.7.dev22.dist-info}/WHEEL +0 -0
  60. {khoj-1.36.7.dev7.dist-info → khoj-1.36.7.dev22.dist-info}/entry_points.txt +0 -0
  61. {khoj-1.36.7.dev7.dist-info → khoj-1.36.7.dev22.dist-info}/licenses/LICENSE +0 -0
@@ -31,10 +31,10 @@ logger = logging.getLogger(__name__)
31
31
 
32
32
  def extract_questions_gemini(
33
33
  text,
34
- model: Optional[str] = "gemini-1.5-flash",
34
+ model: Optional[str] = "gemini-2.0-flash",
35
35
  conversation_log={},
36
36
  api_key=None,
37
- temperature=0,
37
+ temperature=0.6,
38
38
  max_tokens=None,
39
39
  location_data: LocationData = None,
40
40
  user: KhojUser = None,
@@ -121,24 +121,24 @@ def gemini_send_message_to_model(
121
121
  api_key,
122
122
  model,
123
123
  response_type="text",
124
- temperature=0,
124
+ temperature=0.6,
125
125
  model_kwargs=None,
126
126
  tracer={},
127
127
  ):
128
128
  """
129
129
  Send message to model
130
130
  """
131
- messages, system_prompt = format_messages_for_gemini(messages)
131
+ messages_for_gemini, system_prompt = format_messages_for_gemini(messages)
132
132
 
133
133
  model_kwargs = {}
134
134
 
135
- # Sometimes, this causes unwanted behavior and terminates response early. Disable for now while it's flaky.
136
- # if response_type == "json_object":
137
- # model_kwargs["response_mime_type"] = "application/json"
135
+ # This caused unwanted behavior and terminates response early for gemini 1.5 series. Monitor for flakiness with 2.0 series.
136
+ if response_type == "json_object" and model in ["gemini-2.0-flash"]:
137
+ model_kwargs["response_mime_type"] = "application/json"
138
138
 
139
139
  # Get Response from Gemini
140
140
  return gemini_completion_with_backoff(
141
- messages=messages,
141
+ messages=messages_for_gemini,
142
142
  system_prompt=system_prompt,
143
143
  model_name=model,
144
144
  api_key=api_key,
@@ -154,9 +154,9 @@ def converse_gemini(
154
154
  online_results: Optional[Dict[str, Dict]] = None,
155
155
  code_results: Optional[Dict[str, Dict]] = None,
156
156
  conversation_log={},
157
- model: Optional[str] = "gemini-1.5-flash",
157
+ model: Optional[str] = "gemini-2.0-flash",
158
158
  api_key: Optional[str] = None,
159
- temperature: float = 0.2,
159
+ temperature: float = 0.6,
160
160
  completion_func=None,
161
161
  conversation_commands=[ConversationCommand.Default],
162
162
  max_prompt_size=None,
@@ -236,12 +236,12 @@ def converse_gemini(
236
236
  program_execution_context=program_execution_context,
237
237
  )
238
238
 
239
- messages, system_prompt = format_messages_for_gemini(messages, system_prompt)
239
+ messages_for_gemini, system_prompt = format_messages_for_gemini(messages, system_prompt)
240
240
  logger.debug(f"Conversation Context for Gemini: {messages_to_print(messages)}")
241
241
 
242
242
  # Get Response from Google AI
243
243
  return gemini_chat_completion_with_backoff(
244
- messages=messages,
244
+ messages=messages_for_gemini,
245
245
  compiled_references=references,
246
246
  online_results=online_results,
247
247
  model_name=model,
@@ -1,15 +1,11 @@
1
1
  import logging
2
2
  import random
3
+ from copy import deepcopy
3
4
  from threading import Thread
4
5
 
5
- import google.generativeai as genai
6
- from google.generativeai.types.answer_types import FinishReason
6
+ from google import genai
7
+ from google.genai import types as gtypes
7
8
  from google.generativeai.types.generation_types import StopCandidateException
8
- from google.generativeai.types.safety_types import (
9
- HarmBlockThreshold,
10
- HarmCategory,
11
- HarmProbability,
12
- )
13
9
  from langchain.schema import ChatMessage
14
10
  from tenacity import (
15
11
  before_sleep_log,
@@ -24,7 +20,6 @@ from khoj.processor.conversation.utils import (
24
20
  commit_conversation_trace,
25
21
  get_image_from_url,
26
22
  )
27
- from khoj.utils import state
28
23
  from khoj.utils.helpers import (
29
24
  get_chat_usage_metrics,
30
25
  is_none_or_empty,
@@ -35,6 +30,24 @@ logger = logging.getLogger(__name__)
35
30
 
36
31
 
37
32
  MAX_OUTPUT_TOKENS_GEMINI = 8192
33
+ SAFETY_SETTINGS = [
34
+ gtypes.SafetySetting(
35
+ category=gtypes.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
36
+ threshold=gtypes.HarmBlockThreshold.BLOCK_ONLY_HIGH,
37
+ ),
38
+ gtypes.SafetySetting(
39
+ category=gtypes.HarmCategory.HARM_CATEGORY_HARASSMENT,
40
+ threshold=gtypes.HarmBlockThreshold.BLOCK_ONLY_HIGH,
41
+ ),
42
+ gtypes.SafetySetting(
43
+ category=gtypes.HarmCategory.HARM_CATEGORY_HATE_SPEECH,
44
+ threshold=gtypes.HarmBlockThreshold.BLOCK_ONLY_HIGH,
45
+ ),
46
+ gtypes.SafetySetting(
47
+ category=gtypes.HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
48
+ threshold=gtypes.HarmBlockThreshold.BLOCK_ONLY_HIGH,
49
+ ),
50
+ ]
38
51
 
39
52
 
40
53
  @retry(
@@ -46,30 +59,19 @@ MAX_OUTPUT_TOKENS_GEMINI = 8192
46
59
  def gemini_completion_with_backoff(
47
60
  messages, system_prompt, model_name, temperature=0, api_key=None, model_kwargs=None, tracer={}
48
61
  ) -> str:
49
- genai.configure(api_key=api_key)
50
- model_kwargs = model_kwargs or dict()
51
- model_kwargs["temperature"] = temperature
52
- model_kwargs["max_output_tokens"] = MAX_OUTPUT_TOKENS_GEMINI
53
- model = genai.GenerativeModel(
54
- model_name,
55
- generation_config=model_kwargs,
62
+ client = genai.Client(api_key=api_key)
63
+ config = gtypes.GenerateContentConfig(
56
64
  system_instruction=system_prompt,
57
- safety_settings={
58
- HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_ONLY_HIGH,
59
- HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_ONLY_HIGH,
60
- HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_ONLY_HIGH,
61
- HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_ONLY_HIGH,
62
- },
65
+ temperature=temperature,
66
+ max_output_tokens=MAX_OUTPUT_TOKENS_GEMINI,
67
+ safety_settings=SAFETY_SETTINGS,
63
68
  )
64
69
 
65
- formatted_messages = [{"role": message.role, "parts": message.content} for message in messages]
66
-
67
- # Start chat session. All messages up to the last are considered to be part of the chat history
68
- chat_session = model.start_chat(history=formatted_messages[0:-1])
70
+ formatted_messages = [gtypes.Content(role=message.role, parts=message.content) for message in messages]
69
71
 
70
72
  try:
71
- # Generate the response. The last message is considered to be the current prompt
72
- response = chat_session.send_message(formatted_messages[-1]["parts"])
73
+ # Generate the response
74
+ response = client.models.generate_content(model=model_name, config=config, contents=formatted_messages)
73
75
  response_text = response.text
74
76
  except StopCandidateException as e:
75
77
  response = None
@@ -125,30 +127,21 @@ def gemini_llm_thread(
125
127
  g, messages, system_prompt, model_name, temperature, api_key, model_kwargs=None, tracer: dict = {}
126
128
  ):
127
129
  try:
128
- genai.configure(api_key=api_key)
129
- model_kwargs = model_kwargs or dict()
130
- model_kwargs["temperature"] = temperature
131
- model_kwargs["max_output_tokens"] = MAX_OUTPUT_TOKENS_GEMINI
132
- model_kwargs["stop_sequences"] = ["Notes:\n["]
133
- model = genai.GenerativeModel(
134
- model_name,
135
- generation_config=model_kwargs,
130
+ client = genai.Client(api_key=api_key)
131
+ config = gtypes.GenerateContentConfig(
136
132
  system_instruction=system_prompt,
137
- safety_settings={
138
- HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_ONLY_HIGH,
139
- HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_ONLY_HIGH,
140
- HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_ONLY_HIGH,
141
- HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_ONLY_HIGH,
142
- },
133
+ temperature=temperature,
134
+ max_output_tokens=MAX_OUTPUT_TOKENS_GEMINI,
135
+ stop_sequences=["Notes:\n["],
136
+ safety_settings=SAFETY_SETTINGS,
143
137
  )
144
138
 
145
139
  aggregated_response = ""
146
- formatted_messages = [{"role": message.role, "parts": message.content} for message in messages]
140
+ formatted_messages = [gtypes.Content(role=message.role, parts=message.content) for message in messages]
147
141
 
148
- # all messages up to the last are considered to be part of the chat history
149
- chat_session = model.start_chat(history=formatted_messages[0:-1])
150
- # the last message is considered to be the current prompt
151
- for chunk in chat_session.send_message(formatted_messages[-1]["parts"], stream=True):
142
+ for chunk in client.models.generate_content_stream(
143
+ model=model_name, config=config, contents=formatted_messages
144
+ ):
152
145
  message, stopped = handle_gemini_response(chunk.candidates, chunk.prompt_feedback)
153
146
  message = message or chunk.text
154
147
  aggregated_response += message
@@ -177,14 +170,16 @@ def gemini_llm_thread(
177
170
  g.close()
178
171
 
179
172
 
180
- def handle_gemini_response(candidates, prompt_feedback=None):
173
+ def handle_gemini_response(
174
+ candidates: list[gtypes.Candidate], prompt_feedback: gtypes.GenerateContentResponsePromptFeedback = None
175
+ ):
181
176
  """Check if Gemini response was blocked and return an explanatory error message."""
182
177
  # Check if the response was blocked due to safety concerns with the prompt
183
178
  if len(candidates) == 0 and prompt_feedback:
184
179
  message = f"\nI'd prefer to not respond to that due to **{prompt_feedback.block_reason.name}** issues with your query."
185
180
  stopped = True
186
181
  # Check if the response was blocked due to safety concerns with the generated content
187
- elif candidates[0].finish_reason == FinishReason.SAFETY:
182
+ elif candidates[0].finish_reason == gtypes.FinishReason.SAFETY:
188
183
  message = generate_safety_response(candidates[0].safety_ratings)
189
184
  stopped = True
190
185
  # Check if finish reason is empty, therefore generation is in progress
@@ -192,7 +187,7 @@ def handle_gemini_response(candidates, prompt_feedback=None):
192
187
  message = None
193
188
  stopped = False
194
189
  # Check if the response was stopped due to reaching maximum token limit or other reasons
195
- elif candidates[0].finish_reason != FinishReason.STOP:
190
+ elif candidates[0].finish_reason != gtypes.FinishReason.STOP:
196
191
  message = f"\nI can't talk further about that because of **{candidates[0].finish_reason.name} issue.**"
197
192
  stopped = True
198
193
  # Otherwise, the response is valid and can be used
@@ -202,18 +197,18 @@ def handle_gemini_response(candidates, prompt_feedback=None):
202
197
  return message, stopped
203
198
 
204
199
 
205
- def generate_safety_response(safety_ratings):
200
+ def generate_safety_response(safety_ratings: list[gtypes.SafetyRating]):
206
201
  """Generate a conversational response based on the safety ratings of the response."""
207
202
  # Get the safety rating with the highest probability
208
- max_safety_rating = sorted(safety_ratings, key=lambda x: x.probability, reverse=True)[0]
203
+ max_safety_rating: gtypes.SafetyRating = sorted(safety_ratings, key=lambda x: x.probability, reverse=True)[0]
209
204
  # Remove the "HARM_CATEGORY_" prefix and title case the category name
210
205
  max_safety_category = " ".join(max_safety_rating.category.name.split("_")[2:]).title()
211
206
  # Add a bit of variety to the discomfort level based on the safety rating probability
212
207
  discomfort_level = {
213
- HarmProbability.HARM_PROBABILITY_UNSPECIFIED: " ",
214
- HarmProbability.LOW: "a bit ",
215
- HarmProbability.MEDIUM: "moderately ",
216
- HarmProbability.HIGH: random.choice(["very ", "quite ", "fairly "]),
208
+ gtypes.HarmProbability.HARM_PROBABILITY_UNSPECIFIED: " ",
209
+ gtypes.HarmProbability.LOW: "a bit ",
210
+ gtypes.HarmProbability.MEDIUM: "moderately ",
211
+ gtypes.HarmProbability.HIGH: random.choice(["very ", "quite ", "fairly "]),
217
212
  }[max_safety_rating.probability]
218
213
  # Generate a response using a random response template
219
214
  safety_response_choice = random.choice(
@@ -229,9 +224,12 @@ def generate_safety_response(safety_ratings):
229
224
  )
230
225
 
231
226
 
232
- def format_messages_for_gemini(messages: list[ChatMessage], system_prompt: str = None) -> tuple[list[str], str]:
227
+ def format_messages_for_gemini(
228
+ original_messages: list[ChatMessage], system_prompt: str = None
229
+ ) -> tuple[list[str], str]:
233
230
  # Extract system message
234
231
  system_prompt = system_prompt or ""
232
+ messages = deepcopy(original_messages)
235
233
  for message in messages.copy():
236
234
  if message.role == "system":
237
235
  system_prompt += message.content
@@ -242,14 +240,16 @@ def format_messages_for_gemini(messages: list[ChatMessage], system_prompt: str =
242
240
  # Convert message content to string list from chatml dictionary list
243
241
  if isinstance(message.content, list):
244
242
  # Convert image_urls to PIL.Image and place them at beginning of list (better for Gemini)
245
- message.content = [
246
- get_image_from_url(item["image_url"]["url"]).content
247
- if item["type"] == "image_url"
248
- else item.get("text", "")
249
- for item in sorted(message.content, key=lambda x: 0 if x["type"] == "image_url" else 1)
250
- ]
243
+ message_content = []
244
+ for item in sorted(message.content, key=lambda x: 0 if x["type"] == "image_url" else 1):
245
+ if item["type"] == "image_url":
246
+ image = get_image_from_url(item["image_url"]["url"], type="bytes")
247
+ message_content += [gtypes.Part.from_bytes(data=image.content, mime_type=image.type)]
248
+ else:
249
+ message_content += [gtypes.Part.from_text(text=item.get("text", ""))]
250
+ message.content = message_content
251
251
  elif isinstance(message.content, str):
252
- message.content = [message.content]
252
+ message.content = [gtypes.Part.from_text(text=message.content)]
253
253
 
254
254
  if message.role == "assistant":
255
255
  message.role = "model"
@@ -974,11 +974,9 @@ Khoj:
974
974
  python_code_generation_prompt = PromptTemplate.from_template(
975
975
  """
976
976
  You are Khoj, an advanced python programmer. You are tasked with constructing a python program to best answer the user query.
977
- - The python program will run in a pyodide python sandbox with no network access.
977
+ - The python program will run in a sandbox with no network access.
978
978
  - You can write programs to run complex calculations, analyze data, create charts, generate documents to meticulously answer the query.
979
- - The sandbox has access to the standard library, matplotlib, panda, numpy, scipy, bs4 and sympy packages. The requests, torch, catboost, tensorflow and tkinter packages are not available.
980
- - List known file paths to required user documents in "input_files" and known links to required documents from the web in the "input_links" field.
981
- - The python program should be self-contained. It can only read data generated by the program itself and from provided input_files, input_links by their basename (i.e filename excluding file path).
979
+ - The python program should be self-contained. It can only read data generated by the program itself and any user file paths referenced in your program.
982
980
  - Do not try display images or plots in the code directly. The code should save the image or plot to a file instead.
983
981
  - Write any document, charts etc. to be shared with the user to file. These files can be seen by the user.
984
982
  - Use as much context from the previous questions and answers as required to generate your code.
@@ -989,24 +987,99 @@ Current Date: {current_date}
989
987
  User's Location: {location}
990
988
  {username}
991
989
 
992
- The response JSON schema is of the form {{"code": "<python_code>", "input_files": ["file_path_1", "file_path_2"], "input_links": ["link_1", "link_2"]}}
993
- Examples:
990
+ Your response should contain python code wrapped in markdown code blocks (i.e starting with```python and ending with ```)
991
+ Example 1:
994
992
  ---
995
- {{
996
- "code": "# Input values\\nprincipal = 43235\\nrate = 5.24\\nyears = 5\\n\\n# Convert rate to decimal\\nrate_decimal = rate / 100\\n\\n# Calculate final amount\\nfinal_amount = principal * (1 + rate_decimal) ** years\\n\\n# Calculate interest earned\\ninterest_earned = final_amount - principal\\n\\n# Print results with formatting\\nprint(f"Interest Earned: ${{interest_earned:,.2f}}")\\nprint(f"Final Amount: ${{final_amount:,.2f}}")"
997
- }}
993
+ Q: Calculate the interest earned and final amount for a principal of $43,235 invested at a rate of 5.24 percent for 5 years.
994
+ A: Ok, to calculate the interest earned and final amount, we can use the formula for compound interest: $T = P(1 + r/n)^{{nt}}$,
995
+ where T: total amount, P: principal, r: interest rate, n: number of times interest is compounded per year, and t: time in years.
998
996
 
999
- {{
1000
- "code": "import re\\n\\n# Read org file\\nfile_path = 'tasks.org'\\nwith open(file_path, 'r') as f:\\n content = f.read()\\n\\n# Get today's date in YYYY-MM-DD format\\ntoday = datetime.now().strftime('%Y-%m-%d')\\npattern = r'\*+\s+.*\\n.*SCHEDULED:\s+<' + today + r'.*>'\\n\\n# Find all matches using multiline mode\\nmatches = re.findall(pattern, content, re.MULTILINE)\\ncount = len(matches)\\n\\n# Display count\\nprint(f'Count of scheduled tasks for today: {{count}}')",
1001
- "input_files": ["/home/linux/tasks.org"]
1002
- }}
997
+ Let's write the Python program to calculate this.
1003
998
 
1004
- {{
1005
- "code": "import pandas as pd\\nimport matplotlib.pyplot as plt\\n\\n# Load the CSV file\\ndf = pd.read_csv('world_population_by_year.csv')\\n\\n# Plot the data\\nplt.figure(figsize=(10, 6))\\nplt.plot(df['Year'], df['Population'], marker='o')\\n\\n# Add titles and labels\\nplt.title('Population by Year')\\nplt.xlabel('Year')\\nplt.ylabel('Population')\\n\\n# Save the plot to a file\\nplt.savefig('population_by_year_plot.png')",
1006
- "input_links": ["https://population.un.org/world_population_by_year.csv"]
999
+ ```python
1000
+ # Input values
1001
+ principal = 43235
1002
+ rate = 5.24
1003
+ years = 5
1004
+
1005
+ # Convert rate to decimal
1006
+ rate_decimal = rate / 100
1007
+
1008
+ # Calculate final amount
1009
+ final_amount = principal * (1 + rate_decimal) ** years
1010
+
1011
+ # Calculate interest earned
1012
+ interest_earned = final_amount - principal
1013
+
1014
+ # Print results with formatting
1015
+ print(f"Interest Earned: ${{interest_earned:,.2f}}")
1016
+ print(f"Final Amount: ${{final_amount:,.2f}}")
1017
+ ```
1018
+
1019
+ Example 2:
1020
+ ---
1021
+ Q: Simplify first, then evaluate: $-7x+2(x^{{2}}-1)-(2x^{{2}}-x+3)$, where $x=1$.
1022
+ A: Certainly! Let's break down the problem step-by-step and utilize Python with SymPy to simplify and evaluate the expression.
1023
+
1024
+ 1. **Expression Simplification:**
1025
+ We start with the expression \\(-7x + 2(x^2 - 1) - (2x^2 - x + 3)\\).
1026
+
1027
+ 2. **Substitute \\(x=1\\) into the simplified expression:**
1028
+ Once simplified, we will substitute \\(x=1\\) into the expression to find its value.
1029
+
1030
+ Let's implement this in Python using SymPy (as the package is available in the sandbox):
1031
+
1032
+ ```python
1033
+ import sympy as sp
1034
+
1035
+ # Define the variable
1036
+ x = sp.symbols('x')
1037
+
1038
+ # Define the expression
1039
+ expression = -7*x + 2*(x**2 - 1) - (2*x**2 - x + 3)
1040
+
1041
+ # Simplify the expression
1042
+ simplified_expression = sp.simplify(expression)
1043
+
1044
+ # Substitute x = 1 into the simplified expression
1045
+ evaluated_expression = simplified_expression.subs(x, 1)
1046
+
1047
+ # Print the simplified expression and its evaluated value
1048
+ print(\"Simplified Expression:\", simplified_expression)
1049
+ print(\"Evaluated Expression at x=1:\", evaluated_expression)
1050
+ ```
1051
+
1052
+ Example 3:
1053
+ ---
1054
+ Q: Plot the world population growth over the years, given this year, world population world tuples: [(2000, 6), (2001, 7), (2002, 8), (2003, 9), (2004, 10)].
1055
+ A: Absolutely! We can utilize the Pandas and Matplotlib libraries (as both are available in the sandbox) to create the world population growth plot.
1056
+ ```python
1057
+ import pandas as pd
1058
+ import matplotlib.pyplot as plt
1059
+
1060
+ # Create a DataFrame of world population from the provided data
1061
+ data = {{
1062
+ 'Year': [2000, 2001, 2002, 2003, 2004],
1063
+ 'Population': [6, 7, 8, 9, 10]
1007
1064
  }}
1065
+ df = pd.DataFrame(data)
1066
+
1067
+ # Plot the data
1068
+ plt.figure(figsize=(10, 6))
1069
+ plt.plot(df['Year'], df['Population'], marker='o')
1070
+
1071
+ # Add titles and labels
1072
+ plt.title('Population by Year')
1073
+ plt.xlabel('Year')
1074
+ plt.ylabel('Population')
1075
+
1076
+ # Save the plot to a file
1077
+ plt.savefig('population_by_year_plot.png')
1078
+ ```
1079
+
1080
+ Now it's your turn to construct a python program to answer the user's query using the provided context and coversation provided below.
1081
+ Ensure you include the python code to execute and wrap it in a markdown code block.
1008
1082
 
1009
- Now it's your turn to construct a python program to answer the user's question. Provide the code, required input files and input links in a JSON object. Do not say anything else.
1010
1083
  Context:
1011
1084
  ---
1012
1085
  {context}
@@ -1015,8 +1088,9 @@ Chat History:
1015
1088
  ---
1016
1089
  {chat_history}
1017
1090
 
1018
- User: {query}
1019
- Khoj:
1091
+ User Query:
1092
+ ---
1093
+ {query}
1020
1094
  """.strip()
1021
1095
  )
1022
1096
 
@@ -1030,6 +1104,13 @@ Code Execution Results:
1030
1104
  """.strip()
1031
1105
  )
1032
1106
 
1107
+ e2b_sandbox_context = """
1108
+ - The sandbox has access to only the standard library, matplotlib, pandas, numpy, scipy, bs4, sympy, einops, biopython, shapely, plotly and rdkit packages. The requests, torch, catboost, tensorflow and tkinter packages are not available.
1109
+ """.strip()
1110
+
1111
+ terrarium_sandbox_context = """
1112
+ The sandbox has access to the standard library, matplotlib, pandas, numpy, scipy, bs4 and sympy packages. The requests, torch, catboost, tensorflow, rdkit and tkinter packages are not available.
1113
+ """.strip()
1033
1114
 
1034
1115
  # Automations
1035
1116
  # --
@@ -61,6 +61,9 @@ model_to_prompt_size = {
61
61
  "gemini-1.5-pro": 60000,
62
62
  # Anthropic Models
63
63
  "claude-3-5-sonnet-20241022": 60000,
64
+ "claude-3-5-sonnet-latest": 60000,
65
+ "claude-3-7-sonnet-20250219": 60000,
66
+ "claude-3-7-sonnet-latest": 60000,
64
67
  "claude-3-5-haiku-20241022": 60000,
65
68
  # Offline Models
66
69
  "bartowski/Qwen2.5-14B-Instruct-GGUF": 20000,
@@ -670,10 +673,13 @@ def get_image_from_url(image_url: str, type="pil"):
670
673
  content_type = response.headers.get("content-type") or mimetypes.guess_type(image_url)[0] or "image/webp"
671
674
 
672
675
  # Convert image to desired format
676
+ image_data: Any = None
673
677
  if type == "b64":
674
678
  image_data = base64.b64encode(response.content).decode("utf-8")
675
679
  elif type == "pil":
676
680
  image_data = PIL.Image.open(BytesIO(response.content))
681
+ elif type == "bytes":
682
+ image_data = response.content
677
683
  else:
678
684
  raise ValueError(f"Invalid image type: {type}")
679
685