khoj 1.33.3.dev32__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 (393) hide show
  1. khoj/__init__.py +0 -0
  2. khoj/app/README.md +94 -0
  3. khoj/app/__init__.py +0 -0
  4. khoj/app/asgi.py +16 -0
  5. khoj/app/settings.py +218 -0
  6. khoj/app/urls.py +25 -0
  7. khoj/configure.py +452 -0
  8. khoj/database/__init__.py +0 -0
  9. khoj/database/adapters/__init__.py +1821 -0
  10. khoj/database/admin.py +417 -0
  11. khoj/database/apps.py +6 -0
  12. khoj/database/management/__init__.py +0 -0
  13. khoj/database/management/commands/__init__.py +0 -0
  14. khoj/database/management/commands/change_default_model.py +116 -0
  15. khoj/database/management/commands/change_generated_images_url.py +61 -0
  16. khoj/database/management/commands/convert_images_png_to_webp.py +99 -0
  17. khoj/database/migrations/0001_khojuser.py +98 -0
  18. khoj/database/migrations/0002_googleuser.py +32 -0
  19. khoj/database/migrations/0003_vector_extension.py +10 -0
  20. khoj/database/migrations/0004_content_types_and_more.py +181 -0
  21. khoj/database/migrations/0005_embeddings_corpus_id.py +19 -0
  22. khoj/database/migrations/0006_embeddingsdates.py +33 -0
  23. khoj/database/migrations/0007_add_conversation.py +27 -0
  24. khoj/database/migrations/0008_alter_conversation_conversation_log.py +17 -0
  25. khoj/database/migrations/0009_khojapiuser.py +24 -0
  26. khoj/database/migrations/0010_chatmodeloptions_and_more.py +83 -0
  27. khoj/database/migrations/0010_rename_embeddings_entry_and_more.py +30 -0
  28. khoj/database/migrations/0011_merge_20231102_0138.py +14 -0
  29. khoj/database/migrations/0012_entry_file_source.py +21 -0
  30. khoj/database/migrations/0013_subscription.py +37 -0
  31. khoj/database/migrations/0014_alter_googleuser_picture.py +17 -0
  32. khoj/database/migrations/0015_alter_subscription_user.py +21 -0
  33. khoj/database/migrations/0016_alter_subscription_renewal_date.py +17 -0
  34. khoj/database/migrations/0017_searchmodel.py +32 -0
  35. khoj/database/migrations/0018_searchmodelconfig_delete_searchmodel.py +30 -0
  36. khoj/database/migrations/0019_alter_googleuser_family_name_and_more.py +27 -0
  37. khoj/database/migrations/0020_reflectivequestion.py +36 -0
  38. khoj/database/migrations/0021_speechtotextmodeloptions_and_more.py +42 -0
  39. khoj/database/migrations/0022_texttoimagemodelconfig.py +25 -0
  40. khoj/database/migrations/0023_usersearchmodelconfig.py +33 -0
  41. khoj/database/migrations/0024_alter_entry_embeddings.py +18 -0
  42. khoj/database/migrations/0025_clientapplication_khojuser_phone_number_and_more.py +46 -0
  43. khoj/database/migrations/0025_searchmodelconfig_embeddings_inference_endpoint_and_more.py +22 -0
  44. khoj/database/migrations/0026_searchmodelconfig_cross_encoder_inference_endpoint_and_more.py +22 -0
  45. khoj/database/migrations/0027_merge_20240118_1324.py +13 -0
  46. khoj/database/migrations/0028_khojuser_verified_phone_number.py +17 -0
  47. khoj/database/migrations/0029_userrequests.py +27 -0
  48. khoj/database/migrations/0030_conversation_slug_and_title.py +38 -0
  49. khoj/database/migrations/0031_agent_conversation_agent.py +53 -0
  50. khoj/database/migrations/0031_alter_googleuser_locale.py +30 -0
  51. khoj/database/migrations/0032_merge_20240322_0427.py +14 -0
  52. khoj/database/migrations/0033_rename_tuning_agent_personality.py +17 -0
  53. khoj/database/migrations/0034_alter_chatmodeloptions_chat_model.py +32 -0
  54. khoj/database/migrations/0035_processlock.py +26 -0
  55. khoj/database/migrations/0036_alter_processlock_name.py +19 -0
  56. khoj/database/migrations/0036_delete_offlinechatprocessorconversationconfig.py +15 -0
  57. khoj/database/migrations/0036_publicconversation.py +42 -0
  58. khoj/database/migrations/0037_chatmodeloptions_openai_config_and_more.py +51 -0
  59. khoj/database/migrations/0037_searchmodelconfig_bi_encoder_docs_encode_config_and_more.py +32 -0
  60. khoj/database/migrations/0038_merge_20240425_0857.py +14 -0
  61. khoj/database/migrations/0038_merge_20240426_1640.py +12 -0
  62. khoj/database/migrations/0039_merge_20240501_0301.py +12 -0
  63. khoj/database/migrations/0040_alter_processlock_name.py +26 -0
  64. khoj/database/migrations/0040_merge_20240504_1010.py +14 -0
  65. khoj/database/migrations/0041_merge_20240505_1234.py +14 -0
  66. khoj/database/migrations/0042_serverchatsettings.py +46 -0
  67. khoj/database/migrations/0043_alter_chatmodeloptions_model_type.py +21 -0
  68. khoj/database/migrations/0044_conversation_file_filters.py +17 -0
  69. khoj/database/migrations/0045_fileobject.py +37 -0
  70. khoj/database/migrations/0046_khojuser_email_verification_code_and_more.py +22 -0
  71. khoj/database/migrations/0047_alter_entry_file_type.py +31 -0
  72. khoj/database/migrations/0048_voicemodeloption_uservoicemodelconfig.py +52 -0
  73. khoj/database/migrations/0049_datastore.py +38 -0
  74. khoj/database/migrations/0049_texttoimagemodelconfig_api_key_and_more.py +58 -0
  75. khoj/database/migrations/0050_alter_processlock_name.py +25 -0
  76. khoj/database/migrations/0051_merge_20240702_1220.py +14 -0
  77. khoj/database/migrations/0052_alter_searchmodelconfig_bi_encoder_docs_encode_config_and_more.py +27 -0
  78. khoj/database/migrations/0053_agent_style_color_agent_style_icon.py +61 -0
  79. khoj/database/migrations/0054_alter_agent_style_color.py +38 -0
  80. khoj/database/migrations/0055_alter_agent_style_icon.py +37 -0
  81. khoj/database/migrations/0056_chatmodeloptions_vision_enabled.py +17 -0
  82. khoj/database/migrations/0056_searchmodelconfig_cross_encoder_model_config.py +17 -0
  83. khoj/database/migrations/0057_merge_20240816_1409.py +13 -0
  84. khoj/database/migrations/0057_remove_serverchatsettings_default_model_and_more.py +51 -0
  85. khoj/database/migrations/0058_alter_chatmodeloptions_chat_model.py +17 -0
  86. khoj/database/migrations/0059_searchmodelconfig_bi_encoder_confidence_threshold.py +17 -0
  87. khoj/database/migrations/0060_merge_20240905_1828.py +14 -0
  88. khoj/database/migrations/0061_alter_chatmodeloptions_model_type.py +26 -0
  89. khoj/database/migrations/0061_alter_texttoimagemodelconfig_model_type.py +21 -0
  90. khoj/database/migrations/0062_merge_20240913_0222.py +14 -0
  91. khoj/database/migrations/0063_conversation_temp_id.py +36 -0
  92. khoj/database/migrations/0064_remove_conversation_temp_id_alter_conversation_id.py +86 -0
  93. khoj/database/migrations/0065_remove_agent_avatar_remove_agent_public_and_more.py +49 -0
  94. khoj/database/migrations/0066_remove_agent_tools_agent_input_tools_and_more.py +69 -0
  95. khoj/database/migrations/0067_alter_agent_style_icon.py +50 -0
  96. khoj/database/migrations/0068_alter_agent_output_modes.py +24 -0
  97. khoj/database/migrations/0069_webscraper_serverchatsettings_web_scraper.py +89 -0
  98. khoj/database/migrations/0070_alter_agent_input_tools_alter_agent_output_modes.py +46 -0
  99. khoj/database/migrations/0071_subscription_enabled_trial_at_and_more.py +32 -0
  100. khoj/database/migrations/0072_entry_search_model.py +24 -0
  101. khoj/database/migrations/0073_delete_usersearchmodelconfig.py +15 -0
  102. khoj/database/migrations/0074_alter_conversation_title.py +17 -0
  103. khoj/database/migrations/0075_migrate_generated_assets_and_validate.py +85 -0
  104. khoj/database/migrations/0076_rename_openaiprocessorconversationconfig_aimodelapi_and_more.py +26 -0
  105. khoj/database/migrations/0077_chatmodel_alter_agent_chat_model_and_more.py +62 -0
  106. khoj/database/migrations/0078_khojuser_email_verification_code_expiry.py +17 -0
  107. khoj/database/migrations/__init__.py +0 -0
  108. khoj/database/models/__init__.py +725 -0
  109. khoj/database/tests.py +3 -0
  110. khoj/interface/compiled/404/index.html +1 -0
  111. khoj/interface/compiled/_next/static/Tg-vU1p1B-YKT5Qv8KSHt/_buildManifest.js +1 -0
  112. khoj/interface/compiled/_next/static/Tg-vU1p1B-YKT5Qv8KSHt/_ssgManifest.js +1 -0
  113. khoj/interface/compiled/_next/static/chunks/1010-8f39bb4648b5ba10.js +1 -0
  114. khoj/interface/compiled/_next/static/chunks/182-f1c48a203dc91e0e.js +20 -0
  115. khoj/interface/compiled/_next/static/chunks/1915-d3c36ad6ce697ce7.js +1 -0
  116. khoj/interface/compiled/_next/static/chunks/2117-165ef4747a5b836b.js +2 -0
  117. khoj/interface/compiled/_next/static/chunks/2581-455000f8aeb08fc3.js +1 -0
  118. khoj/interface/compiled/_next/static/chunks/3727.dcea8f2193111552.js +1 -0
  119. khoj/interface/compiled/_next/static/chunks/3789-a09e37a819171a9d.js +1 -0
  120. khoj/interface/compiled/_next/static/chunks/4124-6c28322ce218d2d5.js +1 -0
  121. khoj/interface/compiled/_next/static/chunks/5427-b52d95253e692bfa.js +1 -0
  122. khoj/interface/compiled/_next/static/chunks/5473-b1cf56dedac6577a.js +1 -0
  123. khoj/interface/compiled/_next/static/chunks/5477-0bbddb79c25a54a7.js +1 -0
  124. khoj/interface/compiled/_next/static/chunks/6065-64db9ad305ba0bcd.js +1 -0
  125. khoj/interface/compiled/_next/static/chunks/6293-469dd16402ea8a6f.js +3 -0
  126. khoj/interface/compiled/_next/static/chunks/688-b5b4391bbc0376f1.js +1 -0
  127. khoj/interface/compiled/_next/static/chunks/8667-b6bf63c72b2d76eb.js +1 -0
  128. khoj/interface/compiled/_next/static/chunks/9259-1172dbaca0515237.js +1 -0
  129. khoj/interface/compiled/_next/static/chunks/94ca1967.1d9b42d929a1ee8c.js +1 -0
  130. khoj/interface/compiled/_next/static/chunks/9597.83583248dfbf6e73.js +1 -0
  131. khoj/interface/compiled/_next/static/chunks/964ecbae.51d6faf8801d15e6.js +1 -0
  132. khoj/interface/compiled/_next/static/chunks/9665-391df1e5c51c960a.js +1 -0
  133. khoj/interface/compiled/_next/static/chunks/app/_not-found/page-a834eddae3e235df.js +1 -0
  134. khoj/interface/compiled/_next/static/chunks/app/agents/layout-e00fb81dca656a10.js +1 -0
  135. khoj/interface/compiled/_next/static/chunks/app/agents/page-28ce086a1129bca2.js +1 -0
  136. khoj/interface/compiled/_next/static/chunks/app/automations/layout-1fe1537449f43496.js +1 -0
  137. khoj/interface/compiled/_next/static/chunks/app/automations/page-bf365a60829d347f.js +1 -0
  138. khoj/interface/compiled/_next/static/chunks/app/chat/layout-33934fc2d6ae6838.js +1 -0
  139. khoj/interface/compiled/_next/static/chunks/app/chat/page-0e476e57eb2015e3.js +1 -0
  140. khoj/interface/compiled/_next/static/chunks/app/layout-30e7fda7262713ce.js +1 -0
  141. khoj/interface/compiled/_next/static/chunks/app/page-a5515ea71aec5ef0.js +1 -0
  142. khoj/interface/compiled/_next/static/chunks/app/search/layout-c02531d586972d7d.js +1 -0
  143. khoj/interface/compiled/_next/static/chunks/app/search/page-9140541e67ea307d.js +1 -0
  144. khoj/interface/compiled/_next/static/chunks/app/settings/layout-d09d6510a45cd4bd.js +1 -0
  145. khoj/interface/compiled/_next/static/chunks/app/settings/page-951ba40b5b94b23a.js +1 -0
  146. khoj/interface/compiled/_next/static/chunks/app/share/chat/layout-e8e5db7830bf3f47.js +1 -0
  147. khoj/interface/compiled/_next/static/chunks/app/share/chat/page-1beb80d8d741c932.js +1 -0
  148. khoj/interface/compiled/_next/static/chunks/d3ac728e-44ebd2a0c99b12a0.js +1 -0
  149. khoj/interface/compiled/_next/static/chunks/fd9d1056-4482b99a36fd1673.js +1 -0
  150. khoj/interface/compiled/_next/static/chunks/framework-8e0e0f4a6b83a956.js +1 -0
  151. khoj/interface/compiled/_next/static/chunks/main-app-de1f09df97a3cfc7.js +1 -0
  152. khoj/interface/compiled/_next/static/chunks/main-db4bfac6b0a8d00b.js +1 -0
  153. khoj/interface/compiled/_next/static/chunks/pages/_app-3c9ca398d360b709.js +1 -0
  154. khoj/interface/compiled/_next/static/chunks/pages/_error-cf5ca766ac8f493f.js +1 -0
  155. khoj/interface/compiled/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  156. khoj/interface/compiled/_next/static/chunks/webpack-a03962458328b163.js +1 -0
  157. khoj/interface/compiled/_next/static/css/089de1d8526b96e9.css +1 -0
  158. khoj/interface/compiled/_next/static/css/37a73b87f02df402.css +1 -0
  159. khoj/interface/compiled/_next/static/css/4e4e6a4a1c920d06.css +1 -0
  160. khoj/interface/compiled/_next/static/css/8d02837c730f8d13.css +25 -0
  161. khoj/interface/compiled/_next/static/css/8e6a3ca11a60b189.css +1 -0
  162. khoj/interface/compiled/_next/static/css/9c164d9727dd8092.css +1 -0
  163. khoj/interface/compiled/_next/static/css/dac88c17aaee5fcf.css +1 -0
  164. khoj/interface/compiled/_next/static/css/df4b47a2d0d85eae.css +1 -0
  165. khoj/interface/compiled/_next/static/css/e4eb883b5265d372.css +1 -0
  166. khoj/interface/compiled/_next/static/media/1d8a05b60287ae6c-s.p.woff2 +0 -0
  167. khoj/interface/compiled/_next/static/media/6f22fce21a7c433c-s.woff2 +0 -0
  168. khoj/interface/compiled/_next/static/media/77c207b095007c34-s.p.woff2 +0 -0
  169. khoj/interface/compiled/_next/static/media/82ef96de0e8f4d8c-s.p.woff2 +0 -0
  170. khoj/interface/compiled/_next/static/media/KaTeX_AMS-Regular.1608a09b.woff +0 -0
  171. khoj/interface/compiled/_next/static/media/KaTeX_AMS-Regular.4aafdb68.ttf +0 -0
  172. khoj/interface/compiled/_next/static/media/KaTeX_AMS-Regular.a79f1c31.woff2 +0 -0
  173. khoj/interface/compiled/_next/static/media/KaTeX_Caligraphic-Bold.b6770918.woff +0 -0
  174. khoj/interface/compiled/_next/static/media/KaTeX_Caligraphic-Bold.cce5b8ec.ttf +0 -0
  175. khoj/interface/compiled/_next/static/media/KaTeX_Caligraphic-Bold.ec17d132.woff2 +0 -0
  176. khoj/interface/compiled/_next/static/media/KaTeX_Caligraphic-Regular.07ef19e7.ttf +0 -0
  177. khoj/interface/compiled/_next/static/media/KaTeX_Caligraphic-Regular.55fac258.woff2 +0 -0
  178. khoj/interface/compiled/_next/static/media/KaTeX_Caligraphic-Regular.dad44a7f.woff +0 -0
  179. khoj/interface/compiled/_next/static/media/KaTeX_Fraktur-Bold.9f256b85.woff +0 -0
  180. khoj/interface/compiled/_next/static/media/KaTeX_Fraktur-Bold.b18f59e1.ttf +0 -0
  181. khoj/interface/compiled/_next/static/media/KaTeX_Fraktur-Bold.d42a5579.woff2 +0 -0
  182. khoj/interface/compiled/_next/static/media/KaTeX_Fraktur-Regular.7c187121.woff +0 -0
  183. khoj/interface/compiled/_next/static/media/KaTeX_Fraktur-Regular.d3c882a6.woff2 +0 -0
  184. khoj/interface/compiled/_next/static/media/KaTeX_Fraktur-Regular.ed38e79f.ttf +0 -0
  185. khoj/interface/compiled/_next/static/media/KaTeX_Main-Bold.b74a1a8b.ttf +0 -0
  186. khoj/interface/compiled/_next/static/media/KaTeX_Main-Bold.c3fb5ac2.woff2 +0 -0
  187. khoj/interface/compiled/_next/static/media/KaTeX_Main-Bold.d181c465.woff +0 -0
  188. khoj/interface/compiled/_next/static/media/KaTeX_Main-BoldItalic.6f2bb1df.woff2 +0 -0
  189. khoj/interface/compiled/_next/static/media/KaTeX_Main-BoldItalic.70d8b0a5.ttf +0 -0
  190. khoj/interface/compiled/_next/static/media/KaTeX_Main-BoldItalic.e3f82f9d.woff +0 -0
  191. khoj/interface/compiled/_next/static/media/KaTeX_Main-Italic.47373d1e.ttf +0 -0
  192. khoj/interface/compiled/_next/static/media/KaTeX_Main-Italic.8916142b.woff2 +0 -0
  193. khoj/interface/compiled/_next/static/media/KaTeX_Main-Italic.9024d815.woff +0 -0
  194. khoj/interface/compiled/_next/static/media/KaTeX_Main-Regular.0462f03b.woff2 +0 -0
  195. khoj/interface/compiled/_next/static/media/KaTeX_Main-Regular.7f51fe03.woff +0 -0
  196. khoj/interface/compiled/_next/static/media/KaTeX_Main-Regular.b7f8fe9b.ttf +0 -0
  197. khoj/interface/compiled/_next/static/media/KaTeX_Math-BoldItalic.572d331f.woff2 +0 -0
  198. khoj/interface/compiled/_next/static/media/KaTeX_Math-BoldItalic.a879cf83.ttf +0 -0
  199. khoj/interface/compiled/_next/static/media/KaTeX_Math-BoldItalic.f1035d8d.woff +0 -0
  200. khoj/interface/compiled/_next/static/media/KaTeX_Math-Italic.5295ba48.woff +0 -0
  201. khoj/interface/compiled/_next/static/media/KaTeX_Math-Italic.939bc644.ttf +0 -0
  202. khoj/interface/compiled/_next/static/media/KaTeX_Math-Italic.f28c23ac.woff2 +0 -0
  203. khoj/interface/compiled/_next/static/media/KaTeX_SansSerif-Bold.8c5b5494.woff2 +0 -0
  204. khoj/interface/compiled/_next/static/media/KaTeX_SansSerif-Bold.94e1e8dc.ttf +0 -0
  205. khoj/interface/compiled/_next/static/media/KaTeX_SansSerif-Bold.bf59d231.woff +0 -0
  206. khoj/interface/compiled/_next/static/media/KaTeX_SansSerif-Italic.3b1e59b3.woff2 +0 -0
  207. khoj/interface/compiled/_next/static/media/KaTeX_SansSerif-Italic.7c9bc82b.woff +0 -0
  208. khoj/interface/compiled/_next/static/media/KaTeX_SansSerif-Italic.b4c20c84.ttf +0 -0
  209. khoj/interface/compiled/_next/static/media/KaTeX_SansSerif-Regular.74048478.woff +0 -0
  210. khoj/interface/compiled/_next/static/media/KaTeX_SansSerif-Regular.ba21ed5f.woff2 +0 -0
  211. khoj/interface/compiled/_next/static/media/KaTeX_SansSerif-Regular.d4d7ba48.ttf +0 -0
  212. khoj/interface/compiled/_next/static/media/KaTeX_Script-Regular.03e9641d.woff2 +0 -0
  213. khoj/interface/compiled/_next/static/media/KaTeX_Script-Regular.07505710.woff +0 -0
  214. khoj/interface/compiled/_next/static/media/KaTeX_Script-Regular.fe9cbbe1.ttf +0 -0
  215. khoj/interface/compiled/_next/static/media/KaTeX_Size1-Regular.e1e279cb.woff +0 -0
  216. khoj/interface/compiled/_next/static/media/KaTeX_Size1-Regular.eae34984.woff2 +0 -0
  217. khoj/interface/compiled/_next/static/media/KaTeX_Size1-Regular.fabc004a.ttf +0 -0
  218. khoj/interface/compiled/_next/static/media/KaTeX_Size2-Regular.57727022.woff +0 -0
  219. khoj/interface/compiled/_next/static/media/KaTeX_Size2-Regular.5916a24f.woff2 +0 -0
  220. khoj/interface/compiled/_next/static/media/KaTeX_Size2-Regular.d6b476ec.ttf +0 -0
  221. khoj/interface/compiled/_next/static/media/KaTeX_Size3-Regular.9acaf01c.woff +0 -0
  222. khoj/interface/compiled/_next/static/media/KaTeX_Size3-Regular.a144ef58.ttf +0 -0
  223. khoj/interface/compiled/_next/static/media/KaTeX_Size3-Regular.b4230e7e.woff2 +0 -0
  224. khoj/interface/compiled/_next/static/media/KaTeX_Size4-Regular.10d95fd3.woff2 +0 -0
  225. khoj/interface/compiled/_next/static/media/KaTeX_Size4-Regular.7a996c9d.woff +0 -0
  226. khoj/interface/compiled/_next/static/media/KaTeX_Size4-Regular.fbccdabe.ttf +0 -0
  227. khoj/interface/compiled/_next/static/media/KaTeX_Typewriter-Regular.6258592b.woff +0 -0
  228. khoj/interface/compiled/_next/static/media/KaTeX_Typewriter-Regular.a8709e36.woff2 +0 -0
  229. khoj/interface/compiled/_next/static/media/KaTeX_Typewriter-Regular.d97aaf4a.ttf +0 -0
  230. khoj/interface/compiled/_next/static/media/a6ecd16fa044d500-s.p.woff2 +0 -0
  231. khoj/interface/compiled/_next/static/media/bd82c78e5b7b3fe9-s.p.woff2 +0 -0
  232. khoj/interface/compiled/_next/static/media/c32c8052c071fc42-s.woff2 +0 -0
  233. khoj/interface/compiled/_next/static/media/c4250770ab8708b6-s.p.woff2 +0 -0
  234. khoj/interface/compiled/_next/static/media/e098aaaecc9cfbb2-s.p.woff2 +0 -0
  235. khoj/interface/compiled/_next/static/media/flags.3afdda2f.webp +0 -0
  236. khoj/interface/compiled/_next/static/media/flags@2x.5fbe9fc1.webp +0 -0
  237. khoj/interface/compiled/_next/static/media/globe.98e105ca.webp +0 -0
  238. khoj/interface/compiled/_next/static/media/globe@2x.974df6f8.webp +0 -0
  239. khoj/interface/compiled/agents/index.html +1 -0
  240. khoj/interface/compiled/agents/index.txt +7 -0
  241. khoj/interface/compiled/agents.svg +6 -0
  242. khoj/interface/compiled/assets/icons/khoj_lantern.ico +0 -0
  243. khoj/interface/compiled/assets/icons/khoj_lantern.svg +100 -0
  244. khoj/interface/compiled/assets/icons/khoj_lantern_1200x1200.png +0 -0
  245. khoj/interface/compiled/assets/icons/khoj_lantern_128x128.png +0 -0
  246. khoj/interface/compiled/assets/icons/khoj_lantern_128x128_dark.png +0 -0
  247. khoj/interface/compiled/assets/icons/khoj_lantern_256x256.png +0 -0
  248. khoj/interface/compiled/assets/icons/khoj_lantern_512x512.png +0 -0
  249. khoj/interface/compiled/assets/icons/khoj_lantern_logomarktype_1200x630.png +0 -0
  250. khoj/interface/compiled/assets/samples/desktop-browse-draw-sample.png +0 -0
  251. khoj/interface/compiled/assets/samples/desktop-plain-chat-sample.png +0 -0
  252. khoj/interface/compiled/assets/samples/desktop-remember-plan-sample.png +0 -0
  253. khoj/interface/compiled/assets/samples/phone-browse-draw-sample.png +0 -0
  254. khoj/interface/compiled/assets/samples/phone-plain-chat-sample.png +0 -0
  255. khoj/interface/compiled/assets/samples/phone-remember-plan-sample.png +0 -0
  256. khoj/interface/compiled/automation.svg +37 -0
  257. khoj/interface/compiled/automations/index.html +1 -0
  258. khoj/interface/compiled/automations/index.txt +8 -0
  259. khoj/interface/compiled/chat/index.html +1 -0
  260. khoj/interface/compiled/chat/index.txt +7 -0
  261. khoj/interface/compiled/chat.svg +24 -0
  262. khoj/interface/compiled/close.svg +5 -0
  263. khoj/interface/compiled/copy-button-success.svg +6 -0
  264. khoj/interface/compiled/copy-button.svg +5 -0
  265. khoj/interface/compiled/index.html +1 -0
  266. khoj/interface/compiled/index.txt +7 -0
  267. khoj/interface/compiled/khoj.webmanifest +76 -0
  268. khoj/interface/compiled/logo.svg +24 -0
  269. khoj/interface/compiled/search/index.html +1 -0
  270. khoj/interface/compiled/search/index.txt +7 -0
  271. khoj/interface/compiled/send.svg +1 -0
  272. khoj/interface/compiled/settings/index.html +1 -0
  273. khoj/interface/compiled/settings/index.txt +9 -0
  274. khoj/interface/compiled/share/chat/index.html +1 -0
  275. khoj/interface/compiled/share/chat/index.txt +7 -0
  276. khoj/interface/compiled/share.svg +8 -0
  277. khoj/interface/compiled/thumbs-down.svg +6 -0
  278. khoj/interface/compiled/thumbs-up.svg +6 -0
  279. khoj/interface/email/feedback.html +34 -0
  280. khoj/interface/email/magic_link.html +40 -0
  281. khoj/interface/email/task.html +37 -0
  282. khoj/interface/email/welcome.html +90 -0
  283. khoj/interface/web/.well-known/assetlinks.json +11 -0
  284. khoj/interface/web/assets/icons/agents.svg +19 -0
  285. khoj/interface/web/assets/icons/automation.svg +43 -0
  286. khoj/interface/web/assets/icons/chat.svg +24 -0
  287. khoj/interface/web/assets/icons/github.svg +1 -0
  288. khoj/interface/web/assets/icons/khoj-logo-sideways-200.png +0 -0
  289. khoj/interface/web/assets/icons/khoj-logo-sideways-500.png +0 -0
  290. khoj/interface/web/assets/icons/khoj-logo-sideways.svg +32 -0
  291. khoj/interface/web/assets/icons/khoj.svg +26 -0
  292. khoj/interface/web/assets/icons/logotype.svg +1 -0
  293. khoj/interface/web/assets/icons/search.svg +57 -0
  294. khoj/interface/web/assets/icons/sync.svg +4 -0
  295. khoj/interface/web/assets/khoj.css +237 -0
  296. khoj/interface/web/assets/utils.js +33 -0
  297. khoj/interface/web/base_config.html +445 -0
  298. khoj/interface/web/content_source_github_input.html +208 -0
  299. khoj/interface/web/login.html +310 -0
  300. khoj/interface/web/utils.html +48 -0
  301. khoj/main.py +249 -0
  302. khoj/manage.py +22 -0
  303. khoj/migrations/__init__.py +0 -0
  304. khoj/migrations/migrate_offline_chat_default_model.py +69 -0
  305. khoj/migrations/migrate_offline_chat_default_model_2.py +71 -0
  306. khoj/migrations/migrate_offline_chat_schema.py +83 -0
  307. khoj/migrations/migrate_offline_model.py +29 -0
  308. khoj/migrations/migrate_processor_config_openai.py +67 -0
  309. khoj/migrations/migrate_server_pg.py +132 -0
  310. khoj/migrations/migrate_version.py +17 -0
  311. khoj/processor/__init__.py +0 -0
  312. khoj/processor/content/__init__.py +0 -0
  313. khoj/processor/content/docx/__init__.py +0 -0
  314. khoj/processor/content/docx/docx_to_entries.py +111 -0
  315. khoj/processor/content/github/__init__.py +0 -0
  316. khoj/processor/content/github/github_to_entries.py +226 -0
  317. khoj/processor/content/images/__init__.py +0 -0
  318. khoj/processor/content/images/image_to_entries.py +117 -0
  319. khoj/processor/content/markdown/__init__.py +0 -0
  320. khoj/processor/content/markdown/markdown_to_entries.py +160 -0
  321. khoj/processor/content/notion/notion_to_entries.py +259 -0
  322. khoj/processor/content/org_mode/__init__.py +0 -0
  323. khoj/processor/content/org_mode/org_to_entries.py +226 -0
  324. khoj/processor/content/org_mode/orgnode.py +532 -0
  325. khoj/processor/content/pdf/__init__.py +0 -0
  326. khoj/processor/content/pdf/pdf_to_entries.py +119 -0
  327. khoj/processor/content/plaintext/__init__.py +0 -0
  328. khoj/processor/content/plaintext/plaintext_to_entries.py +117 -0
  329. khoj/processor/content/text_to_entries.py +296 -0
  330. khoj/processor/conversation/__init__.py +0 -0
  331. khoj/processor/conversation/anthropic/__init__.py +0 -0
  332. khoj/processor/conversation/anthropic/anthropic_chat.py +243 -0
  333. khoj/processor/conversation/anthropic/utils.py +217 -0
  334. khoj/processor/conversation/google/__init__.py +0 -0
  335. khoj/processor/conversation/google/gemini_chat.py +253 -0
  336. khoj/processor/conversation/google/utils.py +260 -0
  337. khoj/processor/conversation/offline/__init__.py +0 -0
  338. khoj/processor/conversation/offline/chat_model.py +308 -0
  339. khoj/processor/conversation/offline/utils.py +80 -0
  340. khoj/processor/conversation/offline/whisper.py +15 -0
  341. khoj/processor/conversation/openai/__init__.py +0 -0
  342. khoj/processor/conversation/openai/gpt.py +243 -0
  343. khoj/processor/conversation/openai/utils.py +232 -0
  344. khoj/processor/conversation/openai/whisper.py +13 -0
  345. khoj/processor/conversation/prompts.py +1188 -0
  346. khoj/processor/conversation/utils.py +867 -0
  347. khoj/processor/embeddings.py +122 -0
  348. khoj/processor/image/generate.py +215 -0
  349. khoj/processor/speech/__init__.py +0 -0
  350. khoj/processor/speech/text_to_speech.py +51 -0
  351. khoj/processor/tools/__init__.py +0 -0
  352. khoj/processor/tools/online_search.py +472 -0
  353. khoj/processor/tools/run_code.py +179 -0
  354. khoj/routers/__init__.py +0 -0
  355. khoj/routers/api.py +760 -0
  356. khoj/routers/api_agents.py +295 -0
  357. khoj/routers/api_chat.py +1273 -0
  358. khoj/routers/api_content.py +634 -0
  359. khoj/routers/api_model.py +123 -0
  360. khoj/routers/api_phone.py +86 -0
  361. khoj/routers/api_subscription.py +144 -0
  362. khoj/routers/auth.py +307 -0
  363. khoj/routers/email.py +135 -0
  364. khoj/routers/helpers.py +2333 -0
  365. khoj/routers/notion.py +85 -0
  366. khoj/routers/research.py +364 -0
  367. khoj/routers/storage.py +63 -0
  368. khoj/routers/twilio.py +36 -0
  369. khoj/routers/web_client.py +141 -0
  370. khoj/search_filter/__init__.py +0 -0
  371. khoj/search_filter/base_filter.py +15 -0
  372. khoj/search_filter/date_filter.py +215 -0
  373. khoj/search_filter/file_filter.py +32 -0
  374. khoj/search_filter/word_filter.py +29 -0
  375. khoj/search_type/__init__.py +0 -0
  376. khoj/search_type/text_search.py +255 -0
  377. khoj/utils/__init__.py +0 -0
  378. khoj/utils/cli.py +101 -0
  379. khoj/utils/config.py +81 -0
  380. khoj/utils/constants.py +51 -0
  381. khoj/utils/fs_syncer.py +252 -0
  382. khoj/utils/helpers.py +627 -0
  383. khoj/utils/initialization.py +301 -0
  384. khoj/utils/jsonl.py +43 -0
  385. khoj/utils/models.py +47 -0
  386. khoj/utils/rawconfig.py +208 -0
  387. khoj/utils/state.py +48 -0
  388. khoj/utils/yaml.py +47 -0
  389. khoj-1.33.3.dev32.dist-info/METADATA +190 -0
  390. khoj-1.33.3.dev32.dist-info/RECORD +393 -0
  391. khoj-1.33.3.dev32.dist-info/WHEEL +4 -0
  392. khoj-1.33.3.dev32.dist-info/entry_points.txt +2 -0
  393. khoj-1.33.3.dev32.dist-info/licenses/LICENSE +661 -0
@@ -0,0 +1,725 @@
1
+ import logging
2
+ import os
3
+ import re
4
+ import uuid
5
+ from random import choice
6
+ from typing import Dict, List, Optional, Union
7
+
8
+ from django.contrib.auth.models import AbstractUser
9
+ from django.contrib.postgres.fields import ArrayField
10
+ from django.core.exceptions import ValidationError
11
+ from django.db import models
12
+ from django.db.models.signals import pre_save
13
+ from django.dispatch import receiver
14
+ from pgvector.django import VectorField
15
+ from phonenumber_field.modelfields import PhoneNumberField
16
+ from pydantic import BaseModel as PydanticBaseModel
17
+ from pydantic import Field
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+
22
+ # Pydantic models for type Chat Message validation
23
+ class Context(PydanticBaseModel):
24
+ compiled: str
25
+ file: str
26
+
27
+
28
+ class CodeContextFile(PydanticBaseModel):
29
+ filename: str
30
+ b64_data: str
31
+
32
+
33
+ class CodeContextResult(PydanticBaseModel):
34
+ success: bool
35
+ output_files: List[CodeContextFile]
36
+ std_out: str
37
+ std_err: str
38
+ code_runtime: int
39
+
40
+
41
+ class CodeContextData(PydanticBaseModel):
42
+ code: str
43
+ result: Optional[CodeContextResult] = None
44
+
45
+
46
+ class WebPage(PydanticBaseModel):
47
+ link: str
48
+ query: Optional[str] = None
49
+ snippet: str
50
+
51
+
52
+ class AnswerBox(PydanticBaseModel):
53
+ link: Optional[str] = None
54
+ snippet: Optional[str] = None
55
+ title: str
56
+ snippetHighlighted: Optional[List[str]] = None
57
+
58
+
59
+ class PeopleAlsoAsk(PydanticBaseModel):
60
+ link: Optional[str] = None
61
+ question: Optional[str] = None
62
+ snippet: Optional[str] = None
63
+ title: str
64
+
65
+
66
+ class KnowledgeGraph(PydanticBaseModel):
67
+ attributes: Optional[Dict[str, str]] = None
68
+ description: Optional[str] = None
69
+ descriptionLink: Optional[str] = None
70
+ descriptionSource: Optional[str] = None
71
+ imageUrl: Optional[str] = None
72
+ title: str
73
+ type: Optional[str] = None
74
+
75
+
76
+ class OrganicContext(PydanticBaseModel):
77
+ snippet: str
78
+ title: str
79
+ link: str
80
+
81
+
82
+ class OnlineContext(PydanticBaseModel):
83
+ webpages: Optional[Union[WebPage, List[WebPage]]] = None
84
+ answerBox: Optional[AnswerBox] = None
85
+ peopleAlsoAsk: Optional[List[PeopleAlsoAsk]] = None
86
+ knowledgeGraph: Optional[KnowledgeGraph] = None
87
+ organicContext: Optional[List[OrganicContext]] = None
88
+
89
+
90
+ class Intent(PydanticBaseModel):
91
+ type: str
92
+ query: str
93
+ memory_type: str = Field(alias="memory-type")
94
+ inferred_queries: Optional[List[str]] = Field(default=None, alias="inferred-queries")
95
+
96
+
97
+ class TrainOfThought(PydanticBaseModel):
98
+ type: str
99
+ data: str
100
+
101
+
102
+ class ChatMessage(PydanticBaseModel):
103
+ message: str
104
+ trainOfThought: List[TrainOfThought] = []
105
+ context: List[Context] = []
106
+ onlineContext: Dict[str, OnlineContext] = {}
107
+ codeContext: Dict[str, CodeContextData] = {}
108
+ created: str
109
+ images: Optional[List[str]] = None
110
+ queryFiles: Optional[List[Dict]] = None
111
+ excalidrawDiagram: Optional[List[Dict]] = None
112
+ by: str
113
+ turnId: Optional[str] = None
114
+ intent: Optional[Intent] = None
115
+ automationId: Optional[str] = None
116
+
117
+
118
+ class DbBaseModel(models.Model):
119
+ created_at = models.DateTimeField(auto_now_add=True)
120
+ updated_at = models.DateTimeField(auto_now=True)
121
+
122
+ class Meta:
123
+ abstract = True
124
+
125
+
126
+ class ClientApplication(DbBaseModel):
127
+ name = models.CharField(max_length=200)
128
+ client_id = models.CharField(max_length=200)
129
+ client_secret = models.CharField(max_length=200)
130
+
131
+ def __str__(self):
132
+ return self.name
133
+
134
+
135
+ class KhojUser(AbstractUser):
136
+ uuid = models.UUIDField(models.UUIDField(default=uuid.uuid4, editable=False))
137
+ phone_number = PhoneNumberField(null=True, default=None, blank=True)
138
+ verified_phone_number = models.BooleanField(default=False)
139
+ verified_email = models.BooleanField(default=False)
140
+ email_verification_code = models.CharField(max_length=200, null=True, default=None, blank=True)
141
+ email_verification_code_expiry = models.DateTimeField(null=True, default=None, blank=True)
142
+
143
+ def save(self, *args, **kwargs):
144
+ if not self.uuid:
145
+ self.uuid = uuid.uuid4()
146
+ super().save(*args, **kwargs)
147
+
148
+ def __str__(self):
149
+ return f"{self.username} ({self.uuid})"
150
+
151
+
152
+ class GoogleUser(models.Model):
153
+ user = models.OneToOneField(KhojUser, on_delete=models.CASCADE)
154
+ sub = models.CharField(max_length=200)
155
+ azp = models.CharField(max_length=200)
156
+ email = models.CharField(max_length=200)
157
+ name = models.CharField(max_length=200, null=True, default=None, blank=True)
158
+ given_name = models.CharField(max_length=200, null=True, default=None, blank=True)
159
+ family_name = models.CharField(max_length=200, null=True, default=None, blank=True)
160
+ picture = models.CharField(max_length=200, null=True, default=None)
161
+ locale = models.CharField(max_length=200, null=True, default=None, blank=True)
162
+
163
+ def __str__(self):
164
+ return self.name
165
+
166
+
167
+ class KhojApiUser(models.Model):
168
+ """User issued API tokens to authenticate Khoj clients"""
169
+
170
+ user = models.ForeignKey(KhojUser, on_delete=models.CASCADE)
171
+ token = models.CharField(max_length=50, unique=True)
172
+ name = models.CharField(max_length=50)
173
+ accessed_at = models.DateTimeField(null=True, default=None)
174
+
175
+
176
+ class Subscription(DbBaseModel):
177
+ class Type(models.TextChoices):
178
+ TRIAL = "trial"
179
+ STANDARD = "standard"
180
+
181
+ user = models.OneToOneField(KhojUser, on_delete=models.CASCADE, related_name="subscription")
182
+ type = models.CharField(max_length=20, choices=Type.choices, default=Type.STANDARD)
183
+ is_recurring = models.BooleanField(default=False)
184
+ renewal_date = models.DateTimeField(null=True, default=None, blank=True)
185
+ enabled_trial_at = models.DateTimeField(null=True, default=None, blank=True)
186
+
187
+
188
+ class AiModelApi(DbBaseModel):
189
+ name = models.CharField(max_length=200)
190
+ api_key = models.CharField(max_length=200)
191
+ api_base_url = models.URLField(max_length=200, default=None, blank=True, null=True)
192
+
193
+ def __str__(self):
194
+ return self.name
195
+
196
+
197
+ class ChatModel(DbBaseModel):
198
+ class ModelType(models.TextChoices):
199
+ OPENAI = "openai"
200
+ OFFLINE = "offline"
201
+ ANTHROPIC = "anthropic"
202
+ GOOGLE = "google"
203
+
204
+ max_prompt_size = models.IntegerField(default=None, null=True, blank=True)
205
+ subscribed_max_prompt_size = models.IntegerField(default=None, null=True, blank=True)
206
+ tokenizer = models.CharField(max_length=200, default=None, null=True, blank=True)
207
+ name = models.CharField(max_length=200, default="bartowski/Meta-Llama-3.1-8B-Instruct-GGUF")
208
+ model_type = models.CharField(max_length=200, choices=ModelType.choices, default=ModelType.OFFLINE)
209
+ vision_enabled = models.BooleanField(default=False)
210
+ ai_model_api = models.ForeignKey(AiModelApi, on_delete=models.CASCADE, default=None, null=True, blank=True)
211
+
212
+ def __str__(self):
213
+ return self.name
214
+
215
+
216
+ class VoiceModelOption(DbBaseModel):
217
+ model_id = models.CharField(max_length=200)
218
+ name = models.CharField(max_length=200)
219
+
220
+
221
+ class Agent(DbBaseModel):
222
+ class StyleColorTypes(models.TextChoices):
223
+ BLUE = "blue"
224
+ GREEN = "green"
225
+ RED = "red"
226
+ YELLOW = "yellow"
227
+ ORANGE = "orange"
228
+ PURPLE = "purple"
229
+ PINK = "pink"
230
+ TEAL = "teal"
231
+ CYAN = "cyan"
232
+ LIME = "lime"
233
+ INDIGO = "indigo"
234
+ FUCHSIA = "fuchsia"
235
+ ROSE = "rose"
236
+ SKY = "sky"
237
+ AMBER = "amber"
238
+ EMERALD = "emerald"
239
+
240
+ class StyleIconTypes(models.TextChoices):
241
+ LIGHTBULB = "Lightbulb"
242
+ HEALTH = "Health"
243
+ ROBOT = "Robot"
244
+ APERTURE = "Aperture"
245
+ GRADUATION_CAP = "GraduationCap"
246
+ JEEP = "Jeep"
247
+ ISLAND = "Island"
248
+ MATH_OPERATIONS = "MathOperations"
249
+ ASCLEPIUS = "Asclepius"
250
+ COUCH = "Couch"
251
+ CODE = "Code"
252
+ ATOM = "Atom"
253
+ CLOCK_COUNTER_CLOCKWISE = "ClockCounterClockwise"
254
+ PENCIL_LINE = "PencilLine"
255
+ CHALKBOARD = "Chalkboard"
256
+ CIGARETTE = "Cigarette"
257
+ CRANE_TOWER = "CraneTower"
258
+ HEART = "Heart"
259
+ LEAF = "Leaf"
260
+ NEWSPAPER_CLIPPING = "NewspaperClipping"
261
+ ORANGE_SLICE = "OrangeSlice"
262
+ SMILEY_MELTING = "SmileyMelting"
263
+ YIN_YANG = "YinYang"
264
+ SNEAKER_MOVE = "SneakerMove"
265
+ STUDENT = "Student"
266
+ OVEN = "Oven"
267
+ GAVEL = "Gavel"
268
+ BROADCAST = "Broadcast"
269
+
270
+ class PrivacyLevel(models.TextChoices):
271
+ PUBLIC = "public"
272
+ PRIVATE = "private"
273
+ PROTECTED = "protected"
274
+
275
+ class InputToolOptions(models.TextChoices):
276
+ # These map to various ConversationCommand types
277
+ GENERAL = "general"
278
+ ONLINE = "online"
279
+ NOTES = "notes"
280
+ SUMMARIZE = "summarize"
281
+ WEBPAGE = "webpage"
282
+
283
+ class OutputModeOptions(models.TextChoices):
284
+ # These map to various ConversationCommand types
285
+ TEXT = "text"
286
+ IMAGE = "image"
287
+ AUTOMATION = "automation"
288
+
289
+ creator = models.ForeignKey(
290
+ KhojUser, on_delete=models.CASCADE, default=None, null=True, blank=True
291
+ ) # Creator will only be null when the agents are managed by admin
292
+ name = models.CharField(max_length=200)
293
+ personality = models.TextField()
294
+ input_tools = ArrayField(
295
+ models.CharField(max_length=200, choices=InputToolOptions.choices), default=list, null=True, blank=True
296
+ )
297
+ output_modes = ArrayField(
298
+ models.CharField(max_length=200, choices=OutputModeOptions.choices), default=list, null=True, blank=True
299
+ )
300
+ managed_by_admin = models.BooleanField(default=False)
301
+ chat_model = models.ForeignKey(ChatModel, on_delete=models.CASCADE)
302
+ slug = models.CharField(max_length=200, unique=True)
303
+ style_color = models.CharField(max_length=200, choices=StyleColorTypes.choices, default=StyleColorTypes.BLUE)
304
+ style_icon = models.CharField(max_length=200, choices=StyleIconTypes.choices, default=StyleIconTypes.LIGHTBULB)
305
+ privacy_level = models.CharField(max_length=30, choices=PrivacyLevel.choices, default=PrivacyLevel.PRIVATE)
306
+
307
+ def save(self, *args, **kwargs):
308
+ is_new = self._state.adding
309
+
310
+ if self.creator is None:
311
+ self.managed_by_admin = True
312
+
313
+ if is_new:
314
+ random_sequence = "".join(choice("0123456789") for i in range(6))
315
+ slug = f"{self.name.lower().replace(' ', '-')}-{random_sequence}"
316
+ self.slug = slug
317
+
318
+ super().save(*args, **kwargs)
319
+
320
+ def __str__(self):
321
+ return self.name
322
+
323
+
324
+ class ProcessLock(DbBaseModel):
325
+ class Operation(models.TextChoices):
326
+ INDEX_CONTENT = "index_content"
327
+ SCHEDULED_JOB = "scheduled_job"
328
+ SCHEDULE_LEADER = "schedule_leader"
329
+
330
+ # We need to make sure that some operations are thread-safe. To do so, add locks for potentially shared operations.
331
+ # For example, we need to make sure that only one process is updating the embeddings at a time.
332
+ name = models.CharField(max_length=200, choices=Operation.choices, unique=True)
333
+ started_at = models.DateTimeField(auto_now_add=True)
334
+ max_duration_in_seconds = models.IntegerField(default=60 * 60 * 12) # 12 hours
335
+
336
+
337
+ @receiver(pre_save, sender=Agent)
338
+ def verify_agent(sender, instance, **kwargs):
339
+ # check if this is a new instance
340
+ if instance._state.adding:
341
+ if Agent.objects.filter(name=instance.name, privacy_level=Agent.PrivacyLevel.PUBLIC).exists():
342
+ raise ValidationError(f"A public Agent with the name {instance.name} already exists.")
343
+ if Agent.objects.filter(name=instance.name, creator=instance.creator).exists():
344
+ raise ValidationError(f"A private Agent with the name {instance.name} already exists.")
345
+
346
+
347
+ class NotionConfig(DbBaseModel):
348
+ token = models.CharField(max_length=200)
349
+ user = models.ForeignKey(KhojUser, on_delete=models.CASCADE)
350
+
351
+
352
+ class GithubConfig(DbBaseModel):
353
+ pat_token = models.CharField(max_length=200)
354
+ user = models.ForeignKey(KhojUser, on_delete=models.CASCADE)
355
+
356
+
357
+ class GithubRepoConfig(DbBaseModel):
358
+ name = models.CharField(max_length=200)
359
+ owner = models.CharField(max_length=200)
360
+ branch = models.CharField(max_length=200)
361
+ github_config = models.ForeignKey(GithubConfig, on_delete=models.CASCADE, related_name="githubrepoconfig")
362
+
363
+
364
+ class WebScraper(DbBaseModel):
365
+ class WebScraperType(models.TextChoices):
366
+ FIRECRAWL = "Firecrawl"
367
+ OLOSTEP = "Olostep"
368
+ JINA = "Jina"
369
+ DIRECT = "Direct"
370
+
371
+ name = models.CharField(
372
+ max_length=200,
373
+ default=None,
374
+ null=True,
375
+ blank=True,
376
+ unique=True,
377
+ help_text="Friendly name. If not set, it will be set to the type of the scraper.",
378
+ )
379
+ type = models.CharField(max_length=20, choices=WebScraperType.choices, default=WebScraperType.JINA)
380
+ api_key = models.CharField(
381
+ max_length=200,
382
+ default=None,
383
+ null=True,
384
+ blank=True,
385
+ help_text="API key of the web scraper. Only set if scraper service requires an API key. Default is set from env var.",
386
+ )
387
+ api_url = models.URLField(
388
+ max_length=200,
389
+ default=None,
390
+ null=True,
391
+ blank=True,
392
+ help_text="API URL of the web scraper. Only set if scraper service on non-default URL.",
393
+ )
394
+ priority = models.IntegerField(
395
+ default=None,
396
+ null=True,
397
+ blank=True,
398
+ unique=True,
399
+ help_text="Priority of the web scraper. Lower numbers run first.",
400
+ )
401
+
402
+ def clean(self):
403
+ error = {}
404
+ if self.name is None:
405
+ self.name = self.type.capitalize()
406
+ if self.api_url is None:
407
+ if self.type == self.WebScraperType.FIRECRAWL:
408
+ self.api_url = os.getenv("FIRECRAWL_API_URL", "https://api.firecrawl.dev")
409
+ elif self.type == self.WebScraperType.OLOSTEP:
410
+ self.api_url = os.getenv("OLOSTEP_API_URL", "https://agent.olostep.com/olostep-p2p-incomingAPI")
411
+ elif self.type == self.WebScraperType.JINA:
412
+ self.api_url = os.getenv("JINA_READER_API_URL", "https://r.jina.ai/")
413
+ if self.api_key is None:
414
+ if self.type == self.WebScraperType.FIRECRAWL:
415
+ self.api_key = os.getenv("FIRECRAWL_API_KEY")
416
+ if not self.api_key and self.api_url == "https://api.firecrawl.dev":
417
+ error["api_key"] = "Set API key to use default Firecrawl. Get API key from https://firecrawl.dev."
418
+ elif self.type == self.WebScraperType.OLOSTEP:
419
+ self.api_key = os.getenv("OLOSTEP_API_KEY")
420
+ if self.api_key is None:
421
+ error["api_key"] = "Set API key to use Olostep. Get API key from https://olostep.com/."
422
+ elif self.type == self.WebScraperType.JINA:
423
+ self.api_key = os.getenv("JINA_API_KEY")
424
+ if error:
425
+ raise ValidationError(error)
426
+
427
+ def save(self, *args, **kwargs):
428
+ self.clean()
429
+
430
+ if self.priority is None:
431
+ max_priority = WebScraper.objects.aggregate(models.Max("priority"))["priority__max"]
432
+ self.priority = max_priority + 1 if max_priority else 1
433
+
434
+ super().save(*args, **kwargs)
435
+
436
+ def __str__(self):
437
+ return self.name
438
+
439
+
440
+ class ServerChatSettings(DbBaseModel):
441
+ chat_default = models.ForeignKey(
442
+ ChatModel, on_delete=models.CASCADE, default=None, null=True, blank=True, related_name="chat_default"
443
+ )
444
+ chat_advanced = models.ForeignKey(
445
+ ChatModel, on_delete=models.CASCADE, default=None, null=True, blank=True, related_name="chat_advanced"
446
+ )
447
+ web_scraper = models.ForeignKey(
448
+ WebScraper, on_delete=models.CASCADE, default=None, null=True, blank=True, related_name="web_scraper"
449
+ )
450
+
451
+
452
+ class LocalOrgConfig(DbBaseModel):
453
+ input_files = models.JSONField(default=list, null=True)
454
+ input_filter = models.JSONField(default=list, null=True)
455
+ index_heading_entries = models.BooleanField(default=False)
456
+ user = models.ForeignKey(KhojUser, on_delete=models.CASCADE)
457
+
458
+
459
+ class LocalMarkdownConfig(DbBaseModel):
460
+ input_files = models.JSONField(default=list, null=True)
461
+ input_filter = models.JSONField(default=list, null=True)
462
+ index_heading_entries = models.BooleanField(default=False)
463
+ user = models.ForeignKey(KhojUser, on_delete=models.CASCADE)
464
+
465
+
466
+ class LocalPdfConfig(DbBaseModel):
467
+ input_files = models.JSONField(default=list, null=True)
468
+ input_filter = models.JSONField(default=list, null=True)
469
+ index_heading_entries = models.BooleanField(default=False)
470
+ user = models.ForeignKey(KhojUser, on_delete=models.CASCADE)
471
+
472
+
473
+ class LocalPlaintextConfig(DbBaseModel):
474
+ input_files = models.JSONField(default=list, null=True)
475
+ input_filter = models.JSONField(default=list, null=True)
476
+ index_heading_entries = models.BooleanField(default=False)
477
+ user = models.ForeignKey(KhojUser, on_delete=models.CASCADE)
478
+
479
+
480
+ class SearchModelConfig(DbBaseModel):
481
+ class ModelType(models.TextChoices):
482
+ TEXT = "text"
483
+
484
+ # This is the model name exposed to users on their settings page
485
+ name = models.CharField(max_length=200, default="default")
486
+ # Type of content the model can generate embeddings for
487
+ model_type = models.CharField(max_length=200, choices=ModelType.choices, default=ModelType.TEXT)
488
+ # Bi-encoder model of sentence-transformer type to load from HuggingFace
489
+ bi_encoder = models.CharField(max_length=200, default="thenlper/gte-small")
490
+ # Config passed to the sentence-transformer model constructor. E.g. device="cuda:0", trust_remote_server=True etc.
491
+ bi_encoder_model_config = models.JSONField(default=dict, blank=True)
492
+ # Query encode configs like prompt, precision, normalize_embeddings, etc. for sentence-transformer models
493
+ bi_encoder_query_encode_config = models.JSONField(default=dict, blank=True)
494
+ # Docs encode configs like prompt, precision, normalize_embeddings, etc. for sentence-transformer models
495
+ bi_encoder_docs_encode_config = models.JSONField(default=dict, blank=True)
496
+ # Cross-encoder model of sentence-transformer type to load from HuggingFace
497
+ cross_encoder = models.CharField(max_length=200, default="mixedbread-ai/mxbai-rerank-xsmall-v1")
498
+ # Config passed to the cross-encoder model constructor. E.g. device="cuda:0", trust_remote_server=True etc.
499
+ cross_encoder_model_config = models.JSONField(default=dict, blank=True)
500
+ # Inference server API endpoint to use for embeddings inference. Bi-encoder model should be hosted on this server
501
+ embeddings_inference_endpoint = models.CharField(max_length=200, default=None, null=True, blank=True)
502
+ # Inference server API Key to use for embeddings inference. Bi-encoder model should be hosted on this server
503
+ embeddings_inference_endpoint_api_key = models.CharField(max_length=200, default=None, null=True, blank=True)
504
+ # Inference server API endpoint to use for embeddings inference. Cross-encoder model should be hosted on this server
505
+ cross_encoder_inference_endpoint = models.CharField(max_length=200, default=None, null=True, blank=True)
506
+ # Inference server API Key to use for embeddings inference. Cross-encoder model should be hosted on this server
507
+ cross_encoder_inference_endpoint_api_key = models.CharField(max_length=200, default=None, null=True, blank=True)
508
+ # The confidence threshold of the bi_encoder model to consider the embeddings as relevant
509
+ bi_encoder_confidence_threshold = models.FloatField(default=0.18)
510
+
511
+ def __str__(self):
512
+ return self.name
513
+
514
+
515
+ class TextToImageModelConfig(DbBaseModel):
516
+ class ModelType(models.TextChoices):
517
+ OPENAI = "openai"
518
+ STABILITYAI = "stability-ai"
519
+ REPLICATE = "replicate"
520
+
521
+ model_name = models.CharField(max_length=200, default="dall-e-3")
522
+ model_type = models.CharField(max_length=200, choices=ModelType.choices, default=ModelType.OPENAI)
523
+ api_key = models.CharField(max_length=200, default=None, null=True, blank=True)
524
+ ai_model_api = models.ForeignKey(AiModelApi, on_delete=models.CASCADE, default=None, null=True, blank=True)
525
+
526
+ def clean(self):
527
+ # Custom validation logic
528
+ error = {}
529
+ if self.model_type == self.ModelType.OPENAI:
530
+ if self.api_key and self.ai_model_api:
531
+ error[
532
+ "api_key"
533
+ ] = "Both API key and AI Model API cannot be set for OpenAI models. Please set only one of them."
534
+ error[
535
+ "ai_model_api"
536
+ ] = "Both API key and OpenAI config cannot be set for OpenAI models. Please set only one of them."
537
+ if self.model_type != self.ModelType.OPENAI:
538
+ if not self.api_key:
539
+ error["api_key"] = "The API key field must be set for non OpenAI models."
540
+ if self.ai_model_api:
541
+ error["ai_model_api"] = "AI Model API cannot be set for non OpenAI models."
542
+ if error:
543
+ raise ValidationError(error)
544
+
545
+ def save(self, *args, **kwargs):
546
+ self.clean()
547
+ super().save(*args, **kwargs)
548
+
549
+ def __str__(self):
550
+ return f"{self.model_name} - {self.model_type}"
551
+
552
+
553
+ class SpeechToTextModelOptions(DbBaseModel):
554
+ class ModelType(models.TextChoices):
555
+ OPENAI = "openai"
556
+ OFFLINE = "offline"
557
+
558
+ model_name = models.CharField(max_length=200, default="base")
559
+ model_type = models.CharField(max_length=200, choices=ModelType.choices, default=ModelType.OFFLINE)
560
+
561
+ def __str__(self):
562
+ return f"{self.model_name} - {self.model_type}"
563
+
564
+
565
+ class UserConversationConfig(DbBaseModel):
566
+ user = models.OneToOneField(KhojUser, on_delete=models.CASCADE)
567
+ setting = models.ForeignKey(ChatModel, on_delete=models.CASCADE, default=None, null=True, blank=True)
568
+
569
+
570
+ class UserVoiceModelConfig(DbBaseModel):
571
+ user = models.OneToOneField(KhojUser, on_delete=models.CASCADE)
572
+ setting = models.ForeignKey(VoiceModelOption, on_delete=models.CASCADE, default=None, null=True, blank=True)
573
+
574
+
575
+ class UserTextToImageModelConfig(DbBaseModel):
576
+ user = models.OneToOneField(KhojUser, on_delete=models.CASCADE)
577
+ setting = models.ForeignKey(TextToImageModelConfig, on_delete=models.CASCADE)
578
+
579
+
580
+ class Conversation(DbBaseModel):
581
+ user = models.ForeignKey(KhojUser, on_delete=models.CASCADE)
582
+ conversation_log = models.JSONField(default=dict)
583
+ client = models.ForeignKey(ClientApplication, on_delete=models.CASCADE, default=None, null=True, blank=True)
584
+
585
+ # Slug is an app-generated conversation identifier. Need not be unique. Used as display title essentially.
586
+ slug = models.CharField(max_length=200, default=None, null=True, blank=True)
587
+
588
+ # The title field is explicitly set by the user.
589
+ title = models.CharField(max_length=500, default=None, null=True, blank=True)
590
+ agent = models.ForeignKey(Agent, on_delete=models.SET_NULL, default=None, null=True, blank=True)
591
+ file_filters = models.JSONField(default=list)
592
+ id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True, primary_key=True, db_index=True)
593
+
594
+ def clean(self):
595
+ # Validate conversation_log structure
596
+ try:
597
+ messages = self.conversation_log.get("chat", [])
598
+ for msg in messages:
599
+ ChatMessage.model_validate(msg)
600
+ except Exception as e:
601
+ raise ValidationError(f"Invalid conversation_log format: {str(e)}")
602
+
603
+ def save(self, *args, **kwargs):
604
+ self.clean()
605
+ super().save(*args, **kwargs)
606
+
607
+ @property
608
+ def messages(self) -> List[ChatMessage]:
609
+ """Type-hinted accessor for conversation messages"""
610
+ validated_messages = []
611
+ for msg in self.conversation_log.get("chat", []):
612
+ try:
613
+ # Clean up inferred queries if they contain None
614
+ if msg.get("intent") and msg["intent"].get("inferred-queries"):
615
+ msg["intent"]["inferred-queries"] = [
616
+ q for q in msg["intent"]["inferred-queries"] if q is not None and isinstance(q, str)
617
+ ]
618
+ msg["message"] = str(msg.get("message", ""))
619
+ validated_messages.append(ChatMessage.model_validate(msg))
620
+ except ValidationError as e:
621
+ logger.warning(f"Skipping invalid message in conversation: {e}")
622
+ continue
623
+ return validated_messages
624
+
625
+
626
+ class PublicConversation(DbBaseModel):
627
+ source_owner = models.ForeignKey(KhojUser, on_delete=models.CASCADE)
628
+ conversation_log = models.JSONField(default=dict)
629
+ slug = models.CharField(max_length=200, default=None, null=True, blank=True)
630
+ title = models.CharField(max_length=200, default=None, null=True, blank=True)
631
+ agent = models.ForeignKey(Agent, on_delete=models.SET_NULL, default=None, null=True, blank=True)
632
+
633
+
634
+ @receiver(pre_save, sender=PublicConversation)
635
+ def verify_public_conversation(sender, instance, **kwargs):
636
+ def generate_random_alphanumeric(length):
637
+ characters = "0123456789abcdefghijklmnopqrstuvwxyz"
638
+ return "".join(choice(characters) for _ in range(length))
639
+
640
+ # check if this is a new instance
641
+ if instance._state.adding:
642
+ slug = re.sub(r"\W+", "-", instance.slug.lower())[:50] if instance.slug else uuid.uuid4().hex
643
+ observed_random_id = set()
644
+ while PublicConversation.objects.filter(slug=slug).exists():
645
+ try:
646
+ random_id = generate_random_alphanumeric(7)
647
+ except IndexError:
648
+ raise ValidationError(
649
+ "Unable to generate a unique slug for the Public Conversation. Please try again later."
650
+ )
651
+ observed_random_id.add(random_id)
652
+ slug = f"{slug}-{random_id}"
653
+ instance.slug = slug
654
+
655
+
656
+ class ReflectiveQuestion(DbBaseModel):
657
+ question = models.CharField(max_length=500)
658
+ user = models.ForeignKey(KhojUser, on_delete=models.CASCADE, default=None, null=True, blank=True)
659
+
660
+
661
+ class Entry(DbBaseModel):
662
+ class EntryType(models.TextChoices):
663
+ IMAGE = "image"
664
+ PDF = "pdf"
665
+ PLAINTEXT = "plaintext"
666
+ MARKDOWN = "markdown"
667
+ ORG = "org"
668
+ NOTION = "notion"
669
+ GITHUB = "github"
670
+ CONVERSATION = "conversation"
671
+ DOCX = "docx"
672
+
673
+ class EntrySource(models.TextChoices):
674
+ COMPUTER = "computer"
675
+ NOTION = "notion"
676
+ GITHUB = "github"
677
+
678
+ user = models.ForeignKey(KhojUser, on_delete=models.CASCADE, default=None, null=True, blank=True)
679
+ agent = models.ForeignKey(Agent, on_delete=models.CASCADE, default=None, null=True, blank=True)
680
+ embeddings = VectorField(dimensions=None)
681
+ raw = models.TextField()
682
+ compiled = models.TextField()
683
+ heading = models.CharField(max_length=1000, default=None, null=True, blank=True)
684
+ file_source = models.CharField(max_length=30, choices=EntrySource.choices, default=EntrySource.COMPUTER)
685
+ file_type = models.CharField(max_length=30, choices=EntryType.choices, default=EntryType.PLAINTEXT)
686
+ file_path = models.CharField(max_length=400, default=None, null=True, blank=True)
687
+ file_name = models.CharField(max_length=400, default=None, null=True, blank=True)
688
+ url = models.URLField(max_length=400, default=None, null=True, blank=True)
689
+ hashed_value = models.CharField(max_length=100)
690
+ corpus_id = models.UUIDField(default=uuid.uuid4, editable=False)
691
+ search_model = models.ForeignKey(SearchModelConfig, on_delete=models.SET_NULL, default=None, null=True, blank=True)
692
+
693
+ def save(self, *args, **kwargs):
694
+ if self.user and self.agent:
695
+ raise ValidationError("An Entry cannot be associated with both a user and an agent.")
696
+
697
+
698
+ class FileObject(DbBaseModel):
699
+ # Same as Entry but raw will be a much larger string
700
+ file_name = models.CharField(max_length=400, default=None, null=True, blank=True)
701
+ raw_text = models.TextField()
702
+ user = models.ForeignKey(KhojUser, on_delete=models.CASCADE, default=None, null=True, blank=True)
703
+ agent = models.ForeignKey(Agent, on_delete=models.CASCADE, default=None, null=True, blank=True)
704
+
705
+
706
+ class EntryDates(DbBaseModel):
707
+ date = models.DateField()
708
+ entry = models.ForeignKey(Entry, on_delete=models.CASCADE, related_name="embeddings_dates")
709
+
710
+ class Meta:
711
+ indexes = [
712
+ models.Index(fields=["date"]),
713
+ ]
714
+
715
+
716
+ class UserRequests(DbBaseModel):
717
+ user = models.ForeignKey(KhojUser, on_delete=models.CASCADE)
718
+ slug = models.CharField(max_length=200)
719
+
720
+
721
+ class DataStore(DbBaseModel):
722
+ key = models.CharField(max_length=200, unique=True)
723
+ value = models.JSONField(default=dict)
724
+ private = models.BooleanField(default=False)
725
+ owner = models.ForeignKey(KhojUser, on_delete=models.CASCADE, default=None, null=True, blank=True)