khoj 1.17.1.dev229__py3-none-any.whl → 1.20.3__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 (213) hide show
  1. khoj/app/settings.py +7 -2
  2. khoj/configure.py +21 -0
  3. khoj/database/adapters/__init__.py +9 -5
  4. khoj/database/admin.py +2 -0
  5. khoj/database/migrations/0055_alter_agent_style_icon.py +37 -0
  6. khoj/database/models/__init__.py +2 -0
  7. khoj/interface/compiled/404/index.html +1 -0
  8. khoj/interface/compiled/_next/static/chunks/1603-fb2d80ae73990df3.js +1 -0
  9. khoj/interface/compiled/_next/static/chunks/2614-7cf01576d4457a75.js +3 -0
  10. khoj/interface/compiled/_next/static/chunks/3062-a42d847c919a9ea4.js +29 -0
  11. khoj/interface/compiled/_next/static/chunks/3678-8c0e55c3b5d83a22.js +25 -0
  12. khoj/interface/compiled/_next/static/chunks/4504-1629487c8bc82203.js +1 -0
  13. khoj/interface/compiled/_next/static/chunks/6297-d1c842ed3f714ab0.js +1 -0
  14. khoj/interface/compiled/_next/static/chunks/6648-ff677e51f1b2bcf1.js +1 -0
  15. khoj/interface/compiled/_next/static/chunks/7023-52c1be60135eb057.js +2 -0
  16. khoj/interface/compiled/_next/static/chunks/7071-b4711cecca6619a8.js +1 -0
  17. khoj/interface/compiled/_next/static/chunks/743-1a64254447cda71f.js +1 -0
  18. khoj/interface/compiled/_next/static/chunks/8423-132ea64eac83fd43.js +1 -0
  19. khoj/interface/compiled/_next/static/chunks/9001-acbca3e19b1a5ddf.js +21 -0
  20. khoj/interface/compiled/_next/static/chunks/9162-4a6d0d0dc5e27618.js +11 -0
  21. khoj/interface/compiled/_next/static/chunks/9178-859894e0d9d67aa5.js +1 -0
  22. khoj/interface/compiled/_next/static/chunks/9417-2e54c6fd056982d8.js +1 -0
  23. khoj/interface/compiled/_next/static/chunks/9693-91b03052c5cabded.js +1 -0
  24. khoj/interface/compiled/_next/static/chunks/app/_not-found/page-07ff4ab42b07845e.js +1 -0
  25. khoj/interface/compiled/_next/static/chunks/app/agents/layout-e71c8e913cccf792.js +1 -0
  26. khoj/interface/compiled/_next/static/chunks/app/agents/page-922694b75f1fb67b.js +1 -0
  27. khoj/interface/compiled/_next/static/chunks/app/automations/layout-27c28e923c9b1ff0.js +1 -0
  28. khoj/interface/compiled/_next/static/chunks/app/automations/page-46913728bcb8f4c6.js +1 -0
  29. khoj/interface/compiled/_next/static/chunks/app/chat/layout-8102549127db3067.js +1 -0
  30. khoj/interface/compiled/_next/static/chunks/app/chat/page-51ab7c4b766ff344.js +1 -0
  31. khoj/interface/compiled/_next/static/chunks/app/factchecker/layout-7b30c541c05fb904.js +1 -0
  32. khoj/interface/compiled/_next/static/chunks/app/factchecker/page-60be5e3295e2c0bc.js +1 -0
  33. khoj/interface/compiled/_next/static/chunks/app/layout-f3e40d346da53112.js +1 -0
  34. khoj/interface/compiled/_next/static/chunks/app/page-635b30b582201b05.js +1 -0
  35. khoj/interface/compiled/_next/static/chunks/app/search/layout-3720f1362310bebb.js +1 -0
  36. khoj/interface/compiled/_next/static/chunks/app/search/page-dcd385f03255ef36.js +1 -0
  37. khoj/interface/compiled/_next/static/chunks/app/settings/layout-6f9314b0d7a26046.js +1 -0
  38. khoj/interface/compiled/_next/static/chunks/app/settings/page-e83f6fa32691ca64.js +1 -0
  39. khoj/interface/compiled/_next/static/chunks/app/share/chat/layout-39f03f9e32399f0f.js +1 -0
  40. khoj/interface/compiled/_next/static/chunks/app/share/chat/page-699b364dc6fbf139.js +1 -0
  41. khoj/interface/compiled/_next/static/chunks/d3ac728e-a9e3522eef9b6b28.js +1 -0
  42. khoj/interface/compiled/_next/static/chunks/fd9d1056-2b978342deb60015.js +1 -0
  43. khoj/interface/compiled/_next/static/chunks/framework-8e0e0f4a6b83a956.js +33 -0
  44. khoj/interface/compiled/_next/static/chunks/main-175c164f5e0f026c.js +1 -0
  45. khoj/interface/compiled/_next/static/chunks/main-app-6d6ee3495efe03d4.js +1 -0
  46. khoj/interface/compiled/_next/static/chunks/pages/_app-f870474a17b7f2fd.js +1 -0
  47. khoj/interface/compiled/_next/static/chunks/pages/_error-c66a4e8afc46f17b.js +1 -0
  48. khoj/interface/compiled/_next/static/chunks/polyfills-78c92fac7aa8fdd8.js +1 -0
  49. khoj/interface/compiled/_next/static/chunks/webpack-97d9516936918753.js +1 -0
  50. khoj/interface/compiled/_next/static/css/1538cedb321e3a97.css +1 -0
  51. khoj/interface/compiled/_next/static/css/1de368beed21dfba.css +25 -0
  52. khoj/interface/compiled/_next/static/css/2272c73fc7a3b571.css +1 -0
  53. khoj/interface/compiled/_next/static/css/4cae6c0e5c72fb2d.css +1 -0
  54. khoj/interface/compiled/_next/static/css/553f9cdcc7a2bcd6.css +1 -0
  55. khoj/interface/compiled/_next/static/css/a22d83f18a32957e.css +1 -0
  56. khoj/interface/compiled/_next/static/css/a3530ec58b0b660f.css +1 -0
  57. khoj/interface/compiled/_next/static/css/b81e909d403fb2df.css +1 -0
  58. khoj/interface/compiled/_next/static/css/df6f4c34ec280d53.css +1 -0
  59. khoj/interface/compiled/_next/static/iCI2Ycgat9pFGG9HeJvvH/_buildManifest.js +1 -0
  60. khoj/interface/compiled/_next/static/iCI2Ycgat9pFGG9HeJvvH/_ssgManifest.js +1 -0
  61. khoj/interface/compiled/_next/static/media/0e790e04fd40ad16-s.p.woff2 +0 -0
  62. khoj/interface/compiled/_next/static/media/4221e1667cd19c7d-s.woff2 +0 -0
  63. khoj/interface/compiled/_next/static/media/6c276159aa0eb14b-s.woff2 +0 -0
  64. khoj/interface/compiled/_next/static/media/6cc0b9500e4f9168-s.woff2 +0 -0
  65. khoj/interface/compiled/_next/static/media/9d9319a7a2ac39c6-s.woff2 +0 -0
  66. khoj/interface/compiled/_next/static/media/KaTeX_AMS-Regular.1608a09b.woff +0 -0
  67. khoj/interface/compiled/_next/static/media/KaTeX_AMS-Regular.4aafdb68.ttf +0 -0
  68. khoj/interface/compiled/_next/static/media/KaTeX_AMS-Regular.a79f1c31.woff2 +0 -0
  69. khoj/interface/compiled/_next/static/media/KaTeX_Caligraphic-Bold.b6770918.woff +0 -0
  70. khoj/interface/compiled/_next/static/media/KaTeX_Caligraphic-Bold.cce5b8ec.ttf +0 -0
  71. khoj/interface/compiled/_next/static/media/KaTeX_Caligraphic-Bold.ec17d132.woff2 +0 -0
  72. khoj/interface/compiled/_next/static/media/KaTeX_Caligraphic-Regular.07ef19e7.ttf +0 -0
  73. khoj/interface/compiled/_next/static/media/KaTeX_Caligraphic-Regular.55fac258.woff2 +0 -0
  74. khoj/interface/compiled/_next/static/media/KaTeX_Caligraphic-Regular.dad44a7f.woff +0 -0
  75. khoj/interface/compiled/_next/static/media/KaTeX_Fraktur-Bold.9f256b85.woff +0 -0
  76. khoj/interface/compiled/_next/static/media/KaTeX_Fraktur-Bold.b18f59e1.ttf +0 -0
  77. khoj/interface/compiled/_next/static/media/KaTeX_Fraktur-Bold.d42a5579.woff2 +0 -0
  78. khoj/interface/compiled/_next/static/media/KaTeX_Fraktur-Regular.7c187121.woff +0 -0
  79. khoj/interface/compiled/_next/static/media/KaTeX_Fraktur-Regular.d3c882a6.woff2 +0 -0
  80. khoj/interface/compiled/_next/static/media/KaTeX_Fraktur-Regular.ed38e79f.ttf +0 -0
  81. khoj/interface/compiled/_next/static/media/KaTeX_Main-Bold.b74a1a8b.ttf +0 -0
  82. khoj/interface/compiled/_next/static/media/KaTeX_Main-Bold.c3fb5ac2.woff2 +0 -0
  83. khoj/interface/compiled/_next/static/media/KaTeX_Main-Bold.d181c465.woff +0 -0
  84. khoj/interface/compiled/_next/static/media/KaTeX_Main-BoldItalic.6f2bb1df.woff2 +0 -0
  85. khoj/interface/compiled/_next/static/media/KaTeX_Main-BoldItalic.70d8b0a5.ttf +0 -0
  86. khoj/interface/compiled/_next/static/media/KaTeX_Main-BoldItalic.e3f82f9d.woff +0 -0
  87. khoj/interface/compiled/_next/static/media/KaTeX_Main-Italic.47373d1e.ttf +0 -0
  88. khoj/interface/compiled/_next/static/media/KaTeX_Main-Italic.8916142b.woff2 +0 -0
  89. khoj/interface/compiled/_next/static/media/KaTeX_Main-Italic.9024d815.woff +0 -0
  90. khoj/interface/compiled/_next/static/media/KaTeX_Main-Regular.0462f03b.woff2 +0 -0
  91. khoj/interface/compiled/_next/static/media/KaTeX_Main-Regular.7f51fe03.woff +0 -0
  92. khoj/interface/compiled/_next/static/media/KaTeX_Main-Regular.b7f8fe9b.ttf +0 -0
  93. khoj/interface/compiled/_next/static/media/KaTeX_Math-BoldItalic.572d331f.woff2 +0 -0
  94. khoj/interface/compiled/_next/static/media/KaTeX_Math-BoldItalic.a879cf83.ttf +0 -0
  95. khoj/interface/compiled/_next/static/media/KaTeX_Math-BoldItalic.f1035d8d.woff +0 -0
  96. khoj/interface/compiled/_next/static/media/KaTeX_Math-Italic.5295ba48.woff +0 -0
  97. khoj/interface/compiled/_next/static/media/KaTeX_Math-Italic.939bc644.ttf +0 -0
  98. khoj/interface/compiled/_next/static/media/KaTeX_Math-Italic.f28c23ac.woff2 +0 -0
  99. khoj/interface/compiled/_next/static/media/KaTeX_SansSerif-Bold.8c5b5494.woff2 +0 -0
  100. khoj/interface/compiled/_next/static/media/KaTeX_SansSerif-Bold.94e1e8dc.ttf +0 -0
  101. khoj/interface/compiled/_next/static/media/KaTeX_SansSerif-Bold.bf59d231.woff +0 -0
  102. khoj/interface/compiled/_next/static/media/KaTeX_SansSerif-Italic.3b1e59b3.woff2 +0 -0
  103. khoj/interface/compiled/_next/static/media/KaTeX_SansSerif-Italic.7c9bc82b.woff +0 -0
  104. khoj/interface/compiled/_next/static/media/KaTeX_SansSerif-Italic.b4c20c84.ttf +0 -0
  105. khoj/interface/compiled/_next/static/media/KaTeX_SansSerif-Regular.74048478.woff +0 -0
  106. khoj/interface/compiled/_next/static/media/KaTeX_SansSerif-Regular.ba21ed5f.woff2 +0 -0
  107. khoj/interface/compiled/_next/static/media/KaTeX_SansSerif-Regular.d4d7ba48.ttf +0 -0
  108. khoj/interface/compiled/_next/static/media/KaTeX_Script-Regular.03e9641d.woff2 +0 -0
  109. khoj/interface/compiled/_next/static/media/KaTeX_Script-Regular.07505710.woff +0 -0
  110. khoj/interface/compiled/_next/static/media/KaTeX_Script-Regular.fe9cbbe1.ttf +0 -0
  111. khoj/interface/compiled/_next/static/media/KaTeX_Size1-Regular.e1e279cb.woff +0 -0
  112. khoj/interface/compiled/_next/static/media/KaTeX_Size1-Regular.eae34984.woff2 +0 -0
  113. khoj/interface/compiled/_next/static/media/KaTeX_Size1-Regular.fabc004a.ttf +0 -0
  114. khoj/interface/compiled/_next/static/media/KaTeX_Size2-Regular.57727022.woff +0 -0
  115. khoj/interface/compiled/_next/static/media/KaTeX_Size2-Regular.5916a24f.woff2 +0 -0
  116. khoj/interface/compiled/_next/static/media/KaTeX_Size2-Regular.d6b476ec.ttf +0 -0
  117. khoj/interface/compiled/_next/static/media/KaTeX_Size3-Regular.9acaf01c.woff +0 -0
  118. khoj/interface/compiled/_next/static/media/KaTeX_Size3-Regular.a144ef58.ttf +0 -0
  119. khoj/interface/compiled/_next/static/media/KaTeX_Size3-Regular.b4230e7e.woff2 +0 -0
  120. khoj/interface/compiled/_next/static/media/KaTeX_Size4-Regular.10d95fd3.woff2 +0 -0
  121. khoj/interface/compiled/_next/static/media/KaTeX_Size4-Regular.7a996c9d.woff +0 -0
  122. khoj/interface/compiled/_next/static/media/KaTeX_Size4-Regular.fbccdabe.ttf +0 -0
  123. khoj/interface/compiled/_next/static/media/KaTeX_Typewriter-Regular.6258592b.woff +0 -0
  124. khoj/interface/compiled/_next/static/media/KaTeX_Typewriter-Regular.a8709e36.woff2 +0 -0
  125. khoj/interface/compiled/_next/static/media/KaTeX_Typewriter-Regular.d97aaf4a.ttf +0 -0
  126. khoj/interface/compiled/_next/static/media/a75c8ea86756d52d-s.woff2 +0 -0
  127. khoj/interface/compiled/_next/static/media/abce7c400ca31a51-s.woff2 +0 -0
  128. khoj/interface/compiled/_next/static/media/f759c939737fb668-s.woff2 +0 -0
  129. khoj/interface/compiled/_next/static/media/flags.3afdda2f.webp +0 -0
  130. khoj/interface/compiled/_next/static/media/flags@2x.5fbe9fc1.webp +0 -0
  131. khoj/interface/compiled/_next/static/media/globe.98e105ca.webp +0 -0
  132. khoj/interface/compiled/_next/static/media/globe@2x.974df6f8.webp +0 -0
  133. khoj/interface/compiled/agents/index.html +1 -0
  134. khoj/interface/compiled/agents/index.txt +7 -0
  135. khoj/interface/compiled/agents.svg +6 -0
  136. khoj/interface/compiled/automation.svg +37 -0
  137. khoj/interface/compiled/automations/index.html +1 -0
  138. khoj/interface/compiled/automations/index.txt +8 -0
  139. khoj/interface/compiled/chat/index.html +1 -0
  140. khoj/interface/compiled/chat/index.txt +7 -0
  141. khoj/interface/compiled/close.svg +5 -0
  142. khoj/interface/compiled/factchecker/index.html +1 -0
  143. khoj/interface/compiled/factchecker/index.txt +7 -0
  144. khoj/interface/compiled/favicon.ico +0 -0
  145. khoj/interface/compiled/index.html +1 -0
  146. khoj/interface/compiled/index.txt +7 -0
  147. khoj/interface/compiled/logo.svg +24 -0
  148. khoj/interface/compiled/search/index.html +1 -0
  149. khoj/interface/compiled/search/index.txt +7 -0
  150. khoj/interface/compiled/settings/index.html +1 -0
  151. khoj/interface/compiled/settings/index.txt +8 -0
  152. khoj/interface/compiled/share/chat/index.html +1 -0
  153. khoj/interface/compiled/share/chat/index.txt +7 -0
  154. khoj/interface/web/assets/icons/agents.svg +17 -5
  155. khoj/interface/web/assets/icons/automation.svg +40 -35
  156. khoj/interface/web/assets/icons/search.svg +40 -8
  157. khoj/interface/web/login.html +1 -1
  158. khoj/routers/api_chat.py +5 -16
  159. khoj/routers/helpers.py +74 -0
  160. khoj/routers/web_client.py +30 -131
  161. khoj/utils/constants.py +1 -0
  162. {khoj-1.17.1.dev229.dist-info → khoj-1.20.3.dist-info}/METADATA +1 -1
  163. khoj-1.20.3.dist-info/RECORD +353 -0
  164. khoj/interface/web/404.html +0 -56
  165. khoj/interface/web/agent.html +0 -312
  166. khoj/interface/web/agents.html +0 -276
  167. khoj/interface/web/assets/icons/cancel.svg +0 -3
  168. khoj/interface/web/assets/icons/collapse.svg +0 -17
  169. khoj/interface/web/assets/icons/computer.png +0 -0
  170. khoj/interface/web/assets/icons/confirm-icon.svg +0 -1
  171. khoj/interface/web/assets/icons/credit-card.png +0 -0
  172. khoj/interface/web/assets/icons/delete.svg +0 -26
  173. khoj/interface/web/assets/icons/docx.svg +0 -7
  174. khoj/interface/web/assets/icons/edit.svg +0 -4
  175. khoj/interface/web/assets/icons/key.svg +0 -4
  176. khoj/interface/web/assets/icons/markdown.svg +0 -1
  177. khoj/interface/web/assets/icons/new.svg +0 -23
  178. khoj/interface/web/assets/icons/notion.svg +0 -4
  179. khoj/interface/web/assets/icons/openai-logomark.svg +0 -1
  180. khoj/interface/web/assets/icons/org.svg +0 -1
  181. khoj/interface/web/assets/icons/pdf.svg +0 -23
  182. khoj/interface/web/assets/icons/pencil-edit.svg +0 -5
  183. khoj/interface/web/assets/icons/plaintext.svg +0 -1
  184. khoj/interface/web/assets/icons/question-mark-icon.svg +0 -1
  185. khoj/interface/web/assets/icons/speaker.svg +0 -4
  186. khoj/interface/web/assets/icons/stop-solid.svg +0 -37
  187. khoj/interface/web/assets/icons/user-silhouette.svg +0 -4
  188. khoj/interface/web/assets/icons/voice.svg +0 -8
  189. khoj/interface/web/assets/icons/web.svg +0 -2
  190. khoj/interface/web/assets/icons/whatsapp.svg +0 -17
  191. khoj/interface/web/assets/markdown-it.min.js +0 -8476
  192. khoj/interface/web/assets/natural-cron.min.js +0 -1
  193. khoj/interface/web/assets/org.min.js +0 -1823
  194. khoj/interface/web/assets/pico.min.css +0 -5
  195. khoj/interface/web/assets/purify.min.js +0 -3
  196. khoj/interface/web/chat.html +0 -3436
  197. khoj/interface/web/config_automation.html +0 -1103
  198. khoj/interface/web/content_source_computer_input.html +0 -139
  199. khoj/interface/web/content_source_notion_input.html +0 -94
  200. khoj/interface/web/public_conversation.html +0 -2006
  201. khoj/interface/web/search.html +0 -470
  202. khoj/interface/web/settings.html +0 -1011
  203. khoj-1.17.1.dev229.dist-info/RECORD +0 -244
  204. /khoj/interface/{web/assets/icons → compiled}/chat.svg +0 -0
  205. /khoj/interface/{web/assets/icons → compiled}/copy-button-success.svg +0 -0
  206. /khoj/interface/{web/assets/icons → compiled}/copy-button.svg +0 -0
  207. /khoj/interface/{web/assets/icons → compiled}/send.svg +0 -0
  208. /khoj/interface/{web/assets/icons → compiled}/share.svg +0 -0
  209. /khoj/interface/{web/assets/icons/thumbs-down-svgrepo-com.svg → compiled/thumbs-down.svg} +0 -0
  210. /khoj/interface/{web/assets/icons/thumbs-up-svgrepo-com.svg → compiled/thumbs-up.svg} +0 -0
  211. {khoj-1.17.1.dev229.dist-info → khoj-1.20.3.dist-info}/WHEEL +0 -0
  212. {khoj-1.17.1.dev229.dist-info → khoj-1.20.3.dist-info}/entry_points.txt +0 -0
  213. {khoj-1.17.1.dev229.dist-info → khoj-1.20.3.dist-info}/licenses/LICENSE +0 -0
@@ -1,1011 +0,0 @@
1
- {% extends "base_config.html" %}
2
- {% block content %}
3
-
4
- <div class="page">
5
- <div id="content" class="section">
6
- <h2 class="section-title">Profile</h2>
7
- <div class="section-cards">
8
- <div class="card">
9
- <div class="card-title-row">
10
- <img class="card-icon" src="/static/assets/icons/user-silhouette.svg" alt="Profile Name">
11
- <h3 class="card-title">
12
- Name
13
- </h3>
14
- </div>
15
- <div class="card-description-row">
16
- <input type="text" id="profile_given_name" class="form-control" placeholder="Enter your name here" value="{% if given_name %}{{given_name}}{% endif %}">
17
- </div>
18
- <div class="card-action-row">
19
- <button id="save-model" class="card-button happy" onclick="saveProfileGivenName()">
20
- Save
21
- </button>
22
- </div>
23
- </div>
24
- </div>
25
- <h2 class="section-title" style="margin-top: 48px; padding-bottom: 8px;">Content</h2>
26
- <button id="compute-index-size" class="card-button" onclick="getIndexedDataSize()">
27
- Data Usage
28
- </button>
29
- <p id="indexed-data-size" class="card-description"></p>
30
- <div class="section-cards">
31
- <div class="card">
32
- <div class="card-title-row">
33
- <img class="card-icon" src="/static/assets/icons/computer.png" alt="Computer">
34
- <h3 id="card-title-computer" class="card-title">
35
- <span>Files</span>
36
- <img id="configured-icon-computer"
37
- style="display: {% if not enabled_content_source.computer %}none{% endif %}"
38
- class="configured-icon"
39
- src="/static/assets/icons/confirm-icon.svg"
40
- alt="Configured">
41
- </h3>
42
- </div>
43
- <div class="card-description-row">
44
- <p class="card-description">Manage files from your computer</p>
45
- </div>
46
- <div class="card-action-row">
47
- <a class="card-button" href="/settings/content/computer">
48
- {% if enabled_content_source.computer %}
49
- Update
50
- {% else %}
51
- Setup
52
- {% endif %}
53
- <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"></path></svg>
54
- </a>
55
- <div id="clear-computer" class="card-action-row"
56
- style="display: {% if not enabled_content_source.computer %}none{% endif %}">
57
- <button class="card-button" onclick="clearContentType('computer')">
58
- Disable
59
- </button>
60
- </div>
61
- </div>
62
- </div>
63
- <div class="card">
64
- <div class="card-title-row">
65
- <img class="card-icon" src="/static/assets/icons/github.svg" alt="Github">
66
- <h3 class="card-title">
67
- <span>Github</span>
68
- <img id="configured-icon-github"
69
- class="configured-icon"
70
- src="/static/assets/icons/confirm-icon.svg"
71
- alt="Configured"
72
- style="display: {% if not enabled_content_source.github %}none{% endif %}">
73
- </h3>
74
- </div>
75
- <div class="card-description-row">
76
- <p class="card-description">Set repositories to index</p>
77
- </div>
78
- <div class="card-action-row">
79
- <a class="card-button" href="/settings/content/github">
80
- {% if enabled_content_source.github %}
81
- Update
82
- {% else %}
83
- Setup
84
- {% endif %}
85
- <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"></path></svg>
86
- </a>
87
- <div id="clear-github"
88
- class="card-action-row"
89
- style="display: {% if not enabled_content_source.github %}none{% endif %}">
90
- <button class="card-button" onclick="clearContentType('github')">
91
- Disable
92
- </button>
93
- </div>
94
- </div>
95
- </div>
96
- <div class="card">
97
- <div class="card-title-row">
98
- <img class="card-icon" src="/static/assets/icons/notion.svg" alt="Notion">
99
- <h3 class="card-title">
100
- <span>Notion</span>
101
- <img id="configured-icon-notion"
102
- class="configured-icon"
103
- src="/static/assets/icons/confirm-icon.svg"
104
- alt="Configured"
105
- style="display: {% if not enabled_content_source.notion %}none{% endif %}">
106
- </h3>
107
- </div>
108
- <div class="card-description-row">
109
- <p class="card-description">Sync your Notion pages</p>
110
- </div>
111
- <div class="card-action-row">
112
- {% if enabled_content_source.notion %}
113
- <a class="card-button" href="/settings/content/notion">
114
- Update
115
- <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"></path></svg>
116
- </a>
117
- {% elif notion_oauth_url %}
118
- <a class="card-button" href="{{ notion_oauth_url }}">
119
- Connect
120
- <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"></path></svg>
121
- </a>
122
- {% else %}
123
- <a class="card-button" href="/settings/content/notion">
124
- Setup
125
- <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"></path></svg>
126
- </a>
127
- {% endif %}
128
-
129
- <div id="clear-notion"
130
- class="card-action-row"
131
- style="display: {% if not enabled_content_source.notion %}none{% endif %}">
132
- <button class="card-button" onclick="clearContentType('notion')">
133
- Disable
134
- </button>
135
- </div>
136
- </div>
137
- </div>
138
- <div class="card">
139
- <div class="card-title-row">
140
- <img class="card-icon" src="/static/assets/icons/web.svg" alt="Language">
141
- <h3 class="card-title">
142
- <span>Language</span>
143
- </h3>
144
- </div>
145
- <div class="card-description-row">
146
- <select id="search-models">
147
- {% for option in search_model_options %}
148
- <option value="{{ option.id }}" {% if option.id == selected_search_model_config %}selected{% endif %}>{{ option.name }}</option>
149
- {% endfor %}
150
- </select>
151
- </div>
152
- <div class="card-action-row">
153
- <button id="save-search-model" class="card-button happy" onclick="updateSearchModel()">
154
- Save
155
- </button>
156
- </div>
157
- </div>
158
- </div>
159
- <div class="general-settings section">
160
- <div id="status" style="display: none;"></div>
161
- </div>
162
- <div class="section finalize-actions general-settings">
163
- <div class="section-cards">
164
- <div class="finalize-buttons">
165
- <button id="sync" type="submit" title="Regenerate index from scratch for Notion, GitHub configuration" style="display: flex; justify-content: center;">
166
- </button>
167
- </div>
168
- </div>
169
- </div>
170
- </div>
171
- <div id ="features" class="section">
172
- <h2 class="section-title">Features</h2>
173
- <div id="features-hint-text"></div>
174
- <div class="section-cards">
175
- <div class="card">
176
- <div class="card-title-row">
177
- <img class="card-icon" src="/static/assets/icons/chat.svg" alt="Chat">
178
- <h3 class="card-title">
179
- <span>Chat</span>
180
- </h3>
181
- </div>
182
- <div class="card-description-row">
183
- <select id="chat-models">
184
- {% for option in chat_model_options %}
185
- <option value="{{ option.id }}" {% if option.id == selected_chat_model_config %}selected{% endif %}>{{ option.name }}</option>
186
- {% endfor %}
187
- </select>
188
- </div>
189
- <div class="card-action-row">
190
- {% if (not billing_enabled) or (subscription_state != 'unsubscribed' and subscription_state != 'expired') %}
191
- <button id="save-chat-model" class="card-button happy" onclick="updateChatModel()">
192
- Save
193
- </button>
194
- {% else %}
195
- <button id="save-chat-model" class="card-button" disabled>
196
- Subscribe to use different models
197
- </button>
198
- {% endif %}
199
- </div>
200
- </div>
201
- <div class="card">
202
- <div class="card-title-row">
203
- <img class="card-icon" src="/static/assets/icons/chat.svg" alt="Chat">
204
- <h3 class="card-title">
205
- <span>Paint</span>
206
- </h3>
207
- </div>
208
- <div class="card-description-row">
209
- <select id="paint-models">
210
- {% for option in paint_model_options %}
211
- <option value="{{ option.id }}" {% if option.id == selected_paint_model_config %}selected{% endif %}>{{ option.name }}</option>
212
- {% endfor %}
213
- </select>
214
- </div>
215
- <div class="card-action-row">
216
- {% if (not billing_enabled) or (subscription_state != 'unsubscribed' and subscription_state != 'expired') %}
217
- <button id="save-paint-model" class="card-button happy" onclick="updatePaintModel()">
218
- Save
219
- </button>
220
- {% else %}
221
- <button id="save-paint-model" class="card-button" disabled>
222
- Subscribe to use different models
223
- </button>
224
- {% endif %}
225
- </div>
226
- </div>
227
- {% if is_eleven_labs_enabled %}
228
- <div class="card">
229
- <div class="card-title-row">
230
- <img class="card-icon" src="/static/assets/icons/voice.svg" alt="Voice configuration">
231
- <h3 class="card-title">
232
- <span>Voice</span>
233
- </h3>
234
- </div>
235
- <div class="card-description-row">
236
- <select id="voice-models">
237
- {% for option in voice_model_options %}
238
- <option value="{{ option.id }}" {% if option.id == selected_voice_model_config %}selected{% endif %}>{{ option.name }}</option>
239
- {% endfor %}
240
- </select>
241
- </div>
242
- <div class="card-action-row">
243
- {% if (not billing_enabled) or (subscription_state != 'unsubscribed' and subscription_state != 'expired') %}
244
- <button id="save-voice-model" class="card-button happy" onclick="updateVoiceModel()">
245
- Save
246
- </button>
247
- {% else %}
248
- <button id="save-voice-model" class="card-button" disabled>
249
- You must be subscribed to use this feature
250
- </button>
251
- {% endif %}
252
- </div>
253
- </div>
254
- {% endif %}
255
- </div>
256
- </div>
257
- {% if not anonymous_mode or is_twilio_enabled %}
258
- <div id="clients" class="section">
259
- <h2 class="section-title">Clients</h2>
260
- {% if not anonymous_mode %}
261
- <div id="clients-api" class="api-settings">
262
- <div class="card-title-row">
263
- <img class="card-icon" src="/static/assets/icons/key.svg" alt="API Key">
264
- <h3 class="card-title">
265
- <span>API Keys</span>
266
- </h3>
267
- </div>
268
- <div class="card-description-row">
269
- <p id="api-settings-card-description" class="card-description">Manage access from your client apps to Khoj</p>
270
- </div>
271
- <table id="api-settings-keys-table">
272
- <thead>
273
- <tr>
274
- <th scope="col">Name</th>
275
- <th scope="col">Key</th>
276
- <th scope="col">Actions</th>
277
- </tr>
278
- </thead>
279
- <tbody id="api-key-list"></tbody>
280
- </table>
281
- <div class="card-action-row">
282
- <button class="card-button happy" id="generate-api-key" onclick="generateAPIKey()">
283
- Generate API Key
284
- </button>
285
- </div>
286
- </div>
287
- {% endif %}
288
- {% if is_twilio_enabled %}
289
- <div id="phone-number-input-card" class="api-settings">
290
- <div class="card-title-row">
291
- <img class="card-icon" src="/static/assets/icons/whatsapp.svg" alt="WhatsApp icon">
292
- <h3 class="card-title">
293
- <span>WhatsApp</span>
294
- </h3>
295
- </div>
296
- <div class="card-description-row">
297
- <p id="api-settings-card-description-verified" class="card-description" style="{{ 'display: none;' if not phone_number else '' }}">Your number is connected. You can now chat with Khoj on WhatsApp at <a href="https://wa.me/18488004242">+1-848-800-4242</a>. Learn more about the integration <a href="https://docs.khoj.dev/clients/whatsapp">here</a>.</p>
298
- <p id="api-settings-card-description-unverified" class="card-description" style="{{ 'display: none;' if phone_number else '' }}">Connect your number to chat with Khoj on WhatsApp. Learn more about the integration <a href="https://docs.khoj.dev/clients/whatsapp">here</a>.</p>
299
- </div>
300
- <div id="phone-number-input-element" class="card-action-row">
301
- {% if phone_number %}
302
- <input type="text" id="mobile_code" class="form-control" placeholder="Phone Number" name="name" value="{{ phone_number }}">
303
- {% else %}
304
- <input type="text" id="mobile_code" class="form-control" placeholder="Phone Number" name="name">
305
- {% endif %}
306
- </div>
307
- <div id="phone-number-update-callback" class="card-action-row" style="display: none;">
308
- </div>
309
- <div class="card-action-row">
310
- <button id="whatsapp-verify" class="card-button happy" style="display: none;">
311
- Get OTP on WhatsApp and Verify
312
- </button>
313
- <button id="whatsapp-remove" class="card-button" style="display: none;">
314
- Remove
315
- </button>
316
- <input type="number" maxlength="6" id="whatsapp_otp" class="whatsapp_otp" placeholder="OTP" name="otp_code" style="display: none;">
317
- <button id="whatsapp-verify-otp" class="card-button happy" style="display: none;">
318
- Verify OTP
319
- </button>
320
- </div>
321
- </div>
322
- {% endif %}
323
- </div>
324
- {% endif %}
325
- {% if billing_enabled %}
326
- <div id="billing" class="section">
327
- <h2 class="section-title">Billing</h2>
328
- <div class="section-cards">
329
- <div class="card">
330
- <div class="card-title-row">
331
- <img class="card-icon" src="/static/assets/icons/credit-card.png" alt="Credit Card">
332
- <h3 class="card-title">
333
- <span>Subscription</span>
334
- <img id="configured-icon-subscription"
335
- style="display: {% if subscription_state == 'trial' or subscription_state == 'expired' %}none{% endif %}"
336
- class="configured-icon"
337
- src="/static/assets/icons/confirm-icon.svg"
338
- alt="Configured">
339
- </h3>
340
- </div>
341
- <div class="card-description-row">
342
- <p id="trial-description"
343
- class="card-description"
344
- style="display: {% if subscription_state != 'trial' %}none{% endif %}">
345
- Subscribe to Khoj Cloud. See <a href="https://khoj.dev/pricing">pricing</a> for details.
346
- </p>
347
- <p id="unsubscribe-description"
348
- class="card-description"
349
- style="display: {% if subscription_state != 'subscribed' %}none{% endif %}">
350
- You are <b>subscribed</b> to Khoj Cloud. Subscription will <b>renew</b> on <b>{{ subscription_renewal_date }}</b>
351
- </p>
352
- <p id="resubscribe-description"
353
- class="card-description"
354
- style="display: {% if subscription_state != 'unsubscribed' %}none{% endif %}">
355
- You are <b>subscribed</b> to Khoj Cloud. Subscription will <b>expire</b> on <b>{{ subscription_renewal_date }}</b>
356
- </p>
357
- <p id="expire-description"
358
- class="card-description"
359
- style="display: {% if subscription_state != 'expired' %}none{% endif %}">
360
- Subscribe to Khoj Cloud. Subscription <b>expired</b> on <b>{{ subscription_renewal_date }}</b>
361
- </p>
362
- </div>
363
- <div class="card-action-row">
364
- <button id="unsubscribe-button"
365
- class="card-button"
366
- onclick="unsubscribe()"
367
- style="display: {% if subscription_state != 'subscribed' %}none{% endif %};">
368
- Unsubscribe
369
- </button>
370
- <button id="resubscribe-button"
371
- class="card-button happy"
372
- onclick="resubscribe()"
373
- style="display: {% if subscription_state != 'unsubscribed' %}none{% endif %};">
374
- Resubscribe
375
- </button>
376
- <a id="subscribe-button"
377
- class="card-button happy"
378
- href="{{ khoj_cloud_subscription_url }}?prefilled_email={{ username }}"
379
- style="display: {% if subscription_state == 'subscribed' or subscription_state == 'unsubscribed' %}none{% endif %};">
380
- Subscribe
381
- <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"></path></svg>
382
- </a>
383
- </div>
384
- </div>
385
- </div>
386
- </div>
387
- {% endif %}
388
- <div class="section"></div>
389
- <div class="section" id="notification-banner-parent">
390
- <div id="notification-banner" style="display: none;"></div>
391
- </div>
392
- </div>
393
- <script>
394
-
395
- function saveProfileGivenName() {
396
- const givenName = document.getElementById("profile_given_name").value;
397
- fetch('/api/user/name?name=' + givenName, {
398
- method: 'PATCH',
399
- headers: {
400
- 'Content-Type': 'application/json',
401
- }
402
- })
403
- .then(response => response.json())
404
- .then(data => {
405
- if (data.status == "ok") {
406
- let notificationBanner = document.getElementById("notification-banner");
407
- notificationBanner.innerHTML = "";
408
- notificationBanner.textContent = "Profile name has been updated!";
409
- notificationBanner.style.display = "block";
410
- setTimeout(function() {
411
- notificationBanner.style.display = "none";
412
- }, 5000);
413
- }
414
- })
415
- }
416
-
417
- function updateVoiceModel() {
418
- const voiceModel = document.getElementById("voice-models").value;
419
- const saveVoiceModelButton = document.getElementById("save-voice-model");
420
- saveVoiceModelButton.innerHTML = "";
421
- saveVoiceModelButton.disabled = true;
422
- saveVoiceModelButton.textContent = "Saving...";
423
-
424
- fetch('/api/model/voice?id=' + voiceModel, {
425
- method: 'POST',
426
- headers: {
427
- 'Content-Type': 'application/json',
428
- }
429
- })
430
- .then(response => response.json())
431
- .then(data => {
432
- if (data.status == "ok") {
433
- saveVoiceModelButton.textContent = "Save";
434
- saveVoiceModelButton.disabled = false;
435
-
436
- let notificationBanner = document.getElementById("notification-banner");
437
- notificationBanner.innerHTML = "";
438
- notificationBanner.textContent = "Voice model has been updated!";
439
- notificationBanner.style.display = "block";
440
- setTimeout(function() {
441
- notificationBanner.style.display = "none";
442
- }, 5000);
443
-
444
- } else {
445
- saveVoiceModelButton.textContent = "Error";
446
- saveVoiceModelButton.disabled = false;
447
- }
448
- })
449
- }
450
-
451
- function updateChatModel() {
452
- const chatModel = document.getElementById("chat-models").value;
453
- const saveModelButton = document.getElementById("save-chat-model");
454
- saveModelButton.disabled = true;
455
- saveModelButton.innerHTML = "";
456
- saveModelButton.textContent = "Saving...";
457
-
458
- fetch('/api/model/chat?id=' + chatModel, {
459
- method: 'POST',
460
- headers: {
461
- 'Content-Type': 'application/json',
462
- }
463
- })
464
- .then(response => response.json())
465
- .then(data => {
466
- if (data.status == "ok") {
467
- saveModelButton.textContent = "Save";
468
- saveModelButton.disabled = false;
469
-
470
- let notificationBanner = document.getElementById("notification-banner");
471
- notificationBanner.innerHTML = "";
472
- notificationBanner.textContent = "Conversation model has been updated!";
473
- notificationBanner.style.display = "block";
474
- setTimeout(function() {
475
- notificationBanner.style.display = "none";
476
- }, 5000);
477
-
478
- } else {
479
- saveModelButton.textContent = "Error";
480
- saveModelButton.disabled = false;
481
- }
482
- })
483
- };
484
-
485
- function updateSearchModel() {
486
- let confirmation = window.confirm("All your existing data will be deleted, and you will have to regenerate it. Are you sure you want to continue?");
487
- if (!confirmation) {
488
- return;
489
- }
490
-
491
- const searchModel = document.getElementById("search-models").value;
492
- const saveSearchModelButton = document.getElementById("save-search-model");
493
- saveSearchModelButton.innerHTML = "";
494
- saveSearchModelButton.disabled = true;
495
- saveSearchModelButton.textContent = "Saving...";
496
-
497
- fetch('/api/model/search?id=' + searchModel, {
498
- method: 'POST',
499
- headers: {
500
- 'Content-Type': 'application/json',
501
- }
502
- })
503
- .then(response => response.json())
504
- .then(data => {
505
- if (data.status == "ok") {
506
- saveSearchModelButton.textContent = "Save";
507
- saveSearchModelButton.disabled = false;
508
- } else {
509
- saveSearchModelButton.textContent = "Error";
510
- saveSearchModelButton.disabled = false;
511
- }
512
-
513
- let notificationBanner = document.getElementById("notification-banner");
514
- notificationBanner.innerHTML = "";
515
- notificationBanner.textContent = "Khoj can now better understand the language of your content! Manually sync your data from one of the Khoj clients to update your knowledge base.";
516
- notificationBanner.style.display = "block";
517
- setTimeout(function() {
518
- notificationBanner.style.display = "none";
519
- }, 5000);
520
- })
521
- };
522
-
523
- function updatePaintModel() {
524
- const paintModel = document.getElementById("paint-models").value;
525
- const saveModelButton = document.getElementById("save-paint-model");
526
- saveModelButton.disabled = true;
527
- saveModelButton.innerHTML = "Saving...";
528
-
529
- fetch('/api/model/paint?id=' + paintModel, {
530
- method: 'POST',
531
- headers: {
532
- 'Content-Type': 'application/json',
533
- }
534
- })
535
- .then(response => response.json())
536
- .then(data => {
537
- if (data.status == "ok") {
538
- saveModelButton.innerHTML = "Save";
539
- saveModelButton.disabled = false;
540
-
541
- let notificationBanner = document.getElementById("notification-banner");
542
- notificationBanner.innerHTML = "Paint model has been updated!";
543
- notificationBanner.style.display = "block";
544
- setTimeout(function() {
545
- notificationBanner.style.display = "none";
546
- }, 5000);
547
-
548
- } else {
549
- saveModelButton.innerHTML = "Error";
550
- saveModelButton.disabled = false;
551
- }
552
- })
553
- };
554
-
555
- function clearContentType(content_source) {
556
- fetch('/api/content/' + content_source, {
557
- method: 'DELETE',
558
- headers: {
559
- 'Content-Type': 'application/json',
560
- }
561
- })
562
- .then(response => response.json())
563
- .then(data => {
564
- if (data.status == "ok") {
565
- document.getElementById("configured-icon-" + content_source).style.display = "none";
566
- document.getElementById("clear-" + content_source).style.display = "none";
567
- } else {
568
- document.getElementById("configured-icon-" + content_source).style.display = "";
569
- document.getElementById("clear-" + content_source).style.display = "";
570
- }
571
- })
572
- };
573
-
574
- function unsubscribe() {
575
- fetch('/api/subscription?operation=cancel&email={{username}}', {
576
- method: 'PATCH',
577
- headers: {
578
- 'Content-Type': 'application/json',
579
- },
580
- })
581
- .then(response => response.json())
582
- .then(data => {
583
- if (data.success) {
584
- document.getElementById("unsubscribe-description").style.display = "none";
585
- document.getElementById("unsubscribe-button").style.display = "none";
586
-
587
- document.getElementById("resubscribe-description").style.display = "";
588
- document.getElementById("resubscribe-button").style.display = "";
589
-
590
- }
591
- })
592
- }
593
-
594
- function resubscribe() {
595
- fetch('/api/subscription?operation=resubscribe&email={{username}}', {
596
- method: 'PATCH',
597
- headers: {
598
- 'Content-Type': 'application/json',
599
- },
600
- })
601
- .then(response => response.json())
602
- .then(data => {
603
- if (data.success) {
604
- document.getElementById("resubscribe-description").style.display = "none";
605
- document.getElementById("resubscribe-button").style.display = "none";
606
-
607
- document.getElementById("unsubscribe-description").style.display = "";
608
- document.getElementById("unsubscribe-button").style.display = "";
609
- }
610
- })
611
- }
612
-
613
- function populateSyncButton() {
614
- let syncIconEl = document.createElement("img");
615
- syncIconEl.className = "card-icon";
616
- syncIconEl.src = "/static/assets/icons/sync.svg";
617
- syncIconEl.alt = "Sync";
618
-
619
- let syncButtonTitleEl = document.createElement("h3");
620
- syncButtonTitleEl.className = "card-title";
621
- syncButtonTitleEl.textContent = "Sync";
622
-
623
- return [syncButtonTitleEl, syncIconEl];
624
- }
625
-
626
- var syncButtonEl = document.getElementById("sync");
627
- syncButtonEl.innerHTML = "";
628
- syncButtonEl.append(...populateSyncButton());
629
- syncButtonEl.addEventListener("click", function(event) {
630
- event.preventDefault();
631
- updateIndex(
632
- force=true,
633
- successText="Synced!",
634
- errorText="Unable to sync. Raise issue on Khoj <a href='https://github.com/khoj-ai/khoj/issues'>Github</a> or <a href='https://discord.gg/BDgyabRM6e'>Discord</a>.",
635
- button=syncButtonEl,
636
- loadingText="Syncing...",
637
- emoji="");
638
- });
639
-
640
- function updateIndex(force, successText, errorText, button, loadingText, emoji) {
641
- const csrfToken = document.cookie.split('; ').find(row => row.startsWith('csrftoken'))?.split('=')[1];
642
- button.disabled = true;
643
- button.innerHTML = ""
644
- button.textContent = emoji + " " + loadingText;
645
- fetch('/api/update?&client=web&force=' + force, {
646
- method: 'GET',
647
- headers: {
648
- 'Content-Type': 'application/json',
649
- 'X-CSRFToken': csrfToken
650
- }
651
- })
652
- .then(response => response.json())
653
- .then(data => {
654
- if (data.detail != null) {
655
- throw new Error(data.detail);
656
- }
657
-
658
- document.getElementById("status").style.display = "none";
659
-
660
- button.disabled = false;
661
- button.textContent = `✅ ${successText}`;
662
- setTimeout(function() {
663
- button.append(...populateSyncButton());
664
- }, 2000);
665
- })
666
- .catch((error) => {
667
- console.error('Error:', error);
668
- document.getElementById("status").textContent = emoji + " " + errorText
669
- document.getElementById("status").style.display = "block";
670
- button.disabled = false;
671
- button.textContent = '⚠️ Unsuccessful';
672
- setTimeout(function() {
673
- button.append(...populateSyncButton());
674
- }, 2000);
675
- });
676
-
677
- content_sources = ["computer", "github", "notion"];
678
- content_sources.forEach(content_source => {
679
- fetch(`/api/content/${content_source}`, {
680
- method: 'GET',
681
- headers: {
682
- 'Content-Type': 'application/json',
683
- }
684
- })
685
- .then(response => response.json())
686
- .then(data => {
687
- if (data.length > 0) {
688
- document.getElementById("configured-icon-" + content_source).style.display = "";
689
- document.getElementById("clear-" + content_source).style.display = "";
690
- } else {
691
- document.getElementById("configured-icon-" + content_source).style.display = "none";
692
- document.getElementById("clear-" + content_source).style.display = "none";
693
- }
694
- });
695
- });
696
- }
697
-
698
- function generateAPIKey() {
699
- const apiKeyList = document.getElementById("api-key-list");
700
- fetch('/auth/token', {
701
- method: 'POST',
702
- headers: {
703
- 'Content-Type': 'application/json',
704
- },
705
- })
706
- .then(response => response.json())
707
- .then(tokenObj => {
708
- apiKeyList.appendChild(generateTokenRow(tokenObj));
709
- });
710
- }
711
-
712
- function copyAPIKey(token) {
713
- // Copy API key to clipboard
714
- navigator.clipboard.writeText(token);
715
- // Flash the API key copied icon
716
- const apiKeyColumn = document.getElementById(`api-key-${token}`);
717
- const original_text = apiKeyColumn.textContent;
718
- const copyApiKeyButton = document.getElementById(`api-key-copy-${token}`);
719
- setTimeout(function() {
720
- copyApiKeyButton.src = "/static/assets/icons/copy-button-success.svg";
721
- setTimeout(() => {
722
- copyApiKeyButton.src = "/static/assets/icons/copy-button.svg";
723
- }, 1000);
724
- apiKeyColumn.textContent = "✅ Copied!";
725
- setTimeout(function() {
726
- apiKeyColumn.textContent = original_text;
727
- }, 1000);
728
- }, 100);
729
- }
730
-
731
- function deleteAPIKey(token) {
732
- const apiKeyList = document.getElementById("api-key-list");
733
- fetch(`/auth/token?token=${token}`, {
734
- method: 'DELETE',
735
- })
736
- .then(response => {
737
- if (response.ok) {
738
- const apiKeyItem = document.getElementById(`api-key-item-${token}`);
739
- apiKeyList.removeChild(apiKeyItem);
740
- }
741
- });
742
- }
743
-
744
- function generateTokenRow(tokenObj) {
745
- let token = tokenObj.token;
746
- let tokenName = tokenObj.name;
747
- let truncatedToken = token.slice(0, 4) + "..." + token.slice(-4);
748
- let tokenId = `${tokenName}-${truncatedToken}`;
749
-
750
- // Create API Key Row
751
- let apiKeyItemEl = document.createElement("tr");
752
- apiKeyItemEl.id = `api-key-item-${token}`;
753
-
754
- // API Key Name Row
755
- let apiKeyNameEl = document.createElement("td");
756
- let apiKeyNameTextEl = document.createElement("b");
757
- apiKeyNameTextEl.textContent = tokenName;
758
-
759
- // API Key Token Row
760
- let apiKeyTokenEl = document.createElement("td");
761
- apiKeyTokenEl.id = `api-key-${token}`;
762
- apiKeyTokenEl.textContent = truncatedToken;
763
-
764
- // API Key Actions Row
765
- let apiKeyActionsEl = document.createElement("td");
766
- // Copy API Key Button
767
- let copyApiKeyButtonEl = document.createElement("img");
768
- copyApiKeyButtonEl.id = `api-key-copy-${token}`;
769
- copyApiKeyButtonEl.className = "configured-icon api-key-action enabled";
770
- copyApiKeyButtonEl.src = "/static/assets/icons/copy-button.svg";
771
- copyApiKeyButtonEl.alt = "Copy API Key";
772
- copyApiKeyButtonEl.title = "Copy API Key";
773
- copyApiKeyButtonEl.onclick = function() {
774
- copyAPIKey(token);
775
- };
776
- // Delete API Key Button
777
- let deleteApiKeyButtonEl = document.createElement("img");
778
- deleteApiKeyButtonEl.id = `api-key-delete-${token}`;
779
- deleteApiKeyButtonEl.className = "configured-icon api-key-action enabled";
780
- deleteApiKeyButtonEl.src = "/static/assets/icons/delete.svg";
781
- deleteApiKeyButtonEl.alt = "Delete API Key";
782
- deleteApiKeyButtonEl.title = "Delete API Key";
783
- deleteApiKeyButtonEl.onclick = function() {
784
- deleteAPIKey(token);
785
- };
786
-
787
- // Construct the API Key Row
788
- apiKeyNameEl.append(apiKeyNameTextEl);
789
- apiKeyActionsEl.append(copyApiKeyButtonEl, deleteApiKeyButtonEl);
790
- apiKeyItemEl.append(apiKeyNameEl, apiKeyTokenEl, apiKeyActionsEl);
791
-
792
- return apiKeyItemEl;
793
- }
794
-
795
- function listApiKeys() {
796
- const apiKeyList = document.getElementById("api-key-list");
797
- fetch('/auth/token')
798
- .then(response => response.json())
799
- .then(tokens => {
800
- if (!tokens?.length > 0) return;
801
- apiKeyList.append(...tokens?.map(generateTokenRow));
802
- });
803
- }
804
-
805
- // List user's API keys on page load
806
- listApiKeys();
807
-
808
- function getIndexedDataSize() {
809
- document.getElementById("indexed-data-size").textContent = "Calculating...";
810
- fetch('/api/content/size')
811
- .then(response => response.json())
812
- .then(data => {
813
- document.getElementById("indexed-data-size").textContent = data.indexed_data_size_in_mb + " MB used";
814
- });
815
- }
816
-
817
- function removeFile(path) {
818
- fetch('/api/content/file?filename=' + path, {
819
- method: 'DELETE',
820
- headers: {
821
- 'Content-Type': 'application/json',
822
- }
823
- })
824
- .then(response => response.json())
825
- .then(data => {
826
- if (data.status == "ok") {
827
- getAllFilenames();
828
- }
829
- })
830
- }
831
-
832
- var phoneInputField = document.querySelector("#mobile_code");
833
- const iti = window.intlTelInput(phoneInputField, {
834
- initialCountry: "auto",
835
- geoIpLookup: callback => {
836
- fetch("https://ipapi.co/json")
837
- .then(res => res.json())
838
- .then(data => callback(data.country_code))
839
- .catch(() => callback("us"))
840
- },
841
- separateDialCode: true,
842
- utilsScript: "https://assets.khoj.dev/intl-tel-input/utils.js",
843
- });
844
-
845
- const errorMap = ["Invalid number", "Invalid country code", "Too short", "Too long", "Invalid number"];
846
- const phoneNumberUpdateCallback = document.getElementById("phone-number-update-callback");
847
-
848
- const phonenumberVerifyButton = document.getElementById("whatsapp-verify");
849
- const phonenumberRemoveButton = document.getElementById("whatsapp-remove");
850
- const phonenumberVerifyOTPButton = document.getElementById("whatsapp-verify-otp");
851
- const phonenumberOTPInput = document.getElementById("whatsapp_otp");
852
- const phonenumberVerifiedText = document.getElementById("api-settings-card-description-verified");
853
- const phonenumberUnverifiedText = document.getElementById("api-settings-card-description-unverified");
854
-
855
- const preExistingPhoneNumber = "{{ phone_number }}";
856
- let isPhoneNumberVerified = "{{ is_phone_number_verified }}";
857
- let isTwilioEnabled = "{{ is_twilio_enabled }}";
858
- isPhoneNumberVerified = isPhoneNumberVerified.toLowerCase();
859
- isTwilioEnabled = isTwilioEnabled.toLowerCase();
860
-
861
- if (isTwilioEnabled !== "true" ) {
862
- const phoneNumberVerificationCard = document.getElementById("phone-number-input-card");
863
- phoneNumberVerificationCard.style.display = "none";
864
- }
865
- if (preExistingPhoneNumber != "None" && isPhoneNumberVerified === "true") {
866
- phonenumberVerifyButton.style.display = "none";
867
- phonenumberRemoveButton.style.display = "";
868
- } else if (preExistingPhoneNumber != "None" && isPhoneNumberVerified === "false") {
869
- if (isTwilioEnabled == "true") {
870
- phonenumberVerifyButton.style.display = "";
871
- phonenumberRemoveButton.style.display = "none";
872
- } else {
873
- phonenumberVerifyButton.style.display = "none";
874
- phonenumberRemoveButton.style.display = "none";
875
- }
876
- }
877
- else {
878
- phonenumberVerifyButton.style.display = "";
879
- phonenumberRemoveButton.style.display = "none";
880
- }
881
-
882
- phoneInputField.addEventListener("keyup", () => {
883
- if (iti.isValidNumber() == false) {
884
- phonenumberVerifyButton.style.display = "none";
885
- phonenumberRemoveButton.style.display = "none";
886
- } else {
887
- phonenumberVerifyButton.style.display = "";
888
- phonenumberRemoveButton.style.display = "none";
889
- }
890
- })
891
-
892
- phonenumberRemoveButton.addEventListener("click", () => {
893
- fetch('/api/phone', {
894
- method: 'DELETE',
895
- headers: {
896
- 'Content-Type': 'application/json',
897
- }
898
- })
899
- .then(response => response.json())
900
- .then(data => {
901
- if (data.status == "ok") {
902
- phonenumberVerifyButton.style.display = "";
903
- phonenumberRemoveButton.style.display = "none";
904
- phonenumberVerifiedText.style.display = "none";
905
- phonenumberUnverifiedText.style.display = "block";
906
- }
907
- })
908
- })
909
-
910
- phonenumberVerifyButton.addEventListener("click", () => {
911
- console.log(iti.getValidationError());
912
- if (iti.isValidNumber() == false) {
913
- phoneNumberUpdateCallback.textContent = "Invalid phone number: " + errorMap[iti.getValidationError()];
914
- phoneNumberUpdateCallback.style.display = "block";
915
- setTimeout(function() {
916
- phoneNumberUpdateCallback.style.display = "none";
917
- }, 5000);
918
- } else {
919
- const mobileNumber = iti.getNumber();
920
- fetch('/api/phone?phone_number=' + mobileNumber, {
921
- method: 'POST',
922
- headers: {
923
- 'Content-Type': 'application/json',
924
- }
925
- })
926
- .then(response => response.json())
927
- .then(data => {
928
- if (data.status == "ok") {
929
- if (isTwilioEnabled == "True" || isTwilioEnabled == "true") {
930
- phoneNumberUpdateCallback.textContent = "OTP sent to your phone number";
931
- phonenumberVerifyOTPButton.style.display = "block";
932
- phonenumberOTPInput.style.display = "block";
933
- } else {
934
- phonenumberVerifiedText.style.display = "block";
935
- phoneNumberUpdateCallback.textContent = "Phone number updated";
936
- phonenumberUnverifiedText.style.display = "none";
937
- }
938
- phonenumberVerifyButton.style.display = "none";
939
- phoneNumberUpdateCallback.style.display = "block";
940
- setTimeout(function() {
941
- phoneNumberUpdateCallback.style.display = "none";
942
- }, 5000);
943
- } else {
944
- phoneNumberUpdateCallback.textContent = "Error updating phone number";
945
- phoneNumberUpdateCallback.style.display = "block";
946
- setTimeout(function() {
947
- phoneNumberUpdateCallback.style.display = "none";
948
- }, 5000);
949
- }
950
- })
951
- .catch((error) => {
952
- console.error('Error:', error);
953
- phoneNumberUpdateCallback.textContent = "Error updating phone number";
954
- phoneNumberUpdateCallback.style.display = "block";
955
- setTimeout(function() {
956
- phoneNumberUpdateCallback.style.display = "none";
957
- }, 5000);
958
- });
959
- }
960
- })
961
-
962
- phonenumberVerifyOTPButton.addEventListener("click", () => {
963
- const otp = phonenumberOTPInput.value;
964
- if (otp.length != 6) {
965
- phoneNumberUpdateCallback.textContent = "Your OTP should be exactly 6 digits";
966
- phoneNumberUpdateCallback.style.display = "block";
967
- setTimeout(function() {
968
- phoneNumberUpdateCallback.style.display = "none";
969
- }, 5000);
970
- return;
971
- }
972
-
973
- fetch('/api/phone/verify?code=' + otp, {
974
- method: 'POST',
975
- headers: {
976
- 'Content-Type': 'application/json',
977
- }
978
- })
979
- .then(response => response.json())
980
- .then(data => {
981
- if (data.status == "ok") {
982
- phoneNumberUpdateCallback.textContent = "Phone number updated";
983
- phonenumberVerifiedText.style.display = "block";
984
- phonenumberUnverifiedText.style.display = "none";
985
- phoneNumberUpdateCallback.style.display = "block";
986
- phonenumberRemoveButton.style.display = "";
987
- phonenumberVerifyButton.style.display = "none";
988
- phonenumberVerifyOTPButton.style.display = "none";
989
- phonenumberOTPInput.style.display = "none";
990
- setTimeout(function() {
991
- phoneNumberUpdateCallback.style.display = "none";
992
- }, 5000);
993
- } else {
994
- phoneNumberUpdateCallback.textContent = "Error updating phone number";
995
- phoneNumberUpdateCallback.style.display = "block";
996
- setTimeout(function() {
997
- phoneNumberUpdateCallback.style.display = "none";
998
- }, 5000);
999
- }
1000
- })
1001
- .catch((error) => {
1002
- console.error('Error:', error);
1003
- phoneNumberUpdateCallback.textContent = "Error updating phone number";
1004
- phoneNumberUpdateCallback.style.display = "block";
1005
- setTimeout(function() {
1006
- phoneNumberUpdateCallback.style.display = "none";
1007
- }, 5000);
1008
- });
1009
- })
1010
- </script>
1011
- {% endblock %}