khoj 1.17.1.dev223__py3-none-any.whl → 1.20.1.dev1__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.
- khoj/app/settings.py +1 -1
- khoj/routers/web_client.py +29 -130
- {khoj-1.17.1.dev223.dist-info → khoj-1.20.1.dev1.dist-info}/METADATA +1 -1
- {khoj-1.17.1.dev223.dist-info → khoj-1.20.1.dev1.dist-info}/RECORD +7 -52
- khoj/interface/web/404.html +0 -56
- khoj/interface/web/agent.html +0 -312
- khoj/interface/web/agents.html +0 -276
- khoj/interface/web/assets/icons/cancel.svg +0 -3
- khoj/interface/web/assets/icons/collapse.svg +0 -17
- khoj/interface/web/assets/icons/computer.png +0 -0
- khoj/interface/web/assets/icons/confirm-icon.svg +0 -1
- khoj/interface/web/assets/icons/copy-button-success.svg +0 -6
- khoj/interface/web/assets/icons/copy-button.svg +0 -5
- khoj/interface/web/assets/icons/credit-card.png +0 -0
- khoj/interface/web/assets/icons/delete.svg +0 -26
- khoj/interface/web/assets/icons/docx.svg +0 -7
- khoj/interface/web/assets/icons/edit.svg +0 -4
- khoj/interface/web/assets/icons/key.svg +0 -4
- khoj/interface/web/assets/icons/markdown.svg +0 -1
- khoj/interface/web/assets/icons/new.svg +0 -23
- khoj/interface/web/assets/icons/notion.svg +0 -4
- khoj/interface/web/assets/icons/openai-logomark.svg +0 -1
- khoj/interface/web/assets/icons/org.svg +0 -1
- khoj/interface/web/assets/icons/pdf.svg +0 -23
- khoj/interface/web/assets/icons/pencil-edit.svg +0 -5
- khoj/interface/web/assets/icons/plaintext.svg +0 -1
- khoj/interface/web/assets/icons/question-mark-icon.svg +0 -1
- khoj/interface/web/assets/icons/send.svg +0 -1
- khoj/interface/web/assets/icons/share.svg +0 -8
- khoj/interface/web/assets/icons/speaker.svg +0 -4
- khoj/interface/web/assets/icons/stop-solid.svg +0 -37
- khoj/interface/web/assets/icons/thumbs-down-svgrepo-com.svg +0 -6
- khoj/interface/web/assets/icons/thumbs-up-svgrepo-com.svg +0 -6
- khoj/interface/web/assets/icons/user-silhouette.svg +0 -4
- khoj/interface/web/assets/icons/voice.svg +0 -8
- khoj/interface/web/assets/icons/web.svg +0 -2
- khoj/interface/web/assets/icons/whatsapp.svg +0 -17
- khoj/interface/web/assets/markdown-it.min.js +0 -8476
- khoj/interface/web/assets/natural-cron.min.js +0 -1
- khoj/interface/web/assets/org.min.js +0 -1823
- khoj/interface/web/assets/pico.min.css +0 -5
- khoj/interface/web/assets/purify.min.js +0 -3
- khoj/interface/web/chat.html +0 -3436
- khoj/interface/web/config_automation.html +0 -1103
- khoj/interface/web/content_source_computer_input.html +0 -139
- khoj/interface/web/content_source_notion_input.html +0 -94
- khoj/interface/web/public_conversation.html +0 -2006
- khoj/interface/web/search.html +0 -470
- khoj/interface/web/settings.html +0 -1011
- {khoj-1.17.1.dev223.dist-info → khoj-1.20.1.dev1.dist-info}/WHEEL +0 -0
- {khoj-1.17.1.dev223.dist-info → khoj-1.20.1.dev1.dist-info}/entry_points.txt +0 -0
- {khoj-1.17.1.dev223.dist-info → khoj-1.20.1.dev1.dist-info}/licenses/LICENSE +0 -0
khoj/interface/web/settings.html
DELETED
|
@@ -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 %}
|