Nils Durner commited on
Commit
61c26f2
1 Parent(s): 4ca4a77

file-based settings storage

Browse files
Files changed (2) hide show
  1. app.py +14 -0
  2. settings_mgr.py +85 -0
app.py CHANGED
@@ -3,6 +3,7 @@ import base64
3
  import os
4
  from openai import OpenAI
5
  import json
 
6
 
7
  from doc2json import process_docx
8
 
@@ -194,6 +195,8 @@ with gr.Blocks() as demo:
194
  max_tokens = gr.Slider(1, 4000, label="Max. Tokens", elem_id="max_tokens", value=800)
195
  save_button = gr.Button("Save Settings")
196
  load_button = gr.Button("Load Settings")
 
 
197
 
198
  load_button.click(load_settings, js="""
199
  () => {
@@ -218,6 +221,17 @@ with gr.Blocks() as demo:
218
  }
219
  """)
220
 
 
 
 
 
 
 
 
 
 
 
 
221
  chatbot = gr.Chatbot(
222
  [],
223
  elem_id="chatbot",
 
3
  import os
4
  from openai import OpenAI
5
  import json
6
+ from settings_mgr import generate_download_settings_js, generate_upload_settings_js
7
 
8
  from doc2json import process_docx
9
 
 
195
  max_tokens = gr.Slider(1, 4000, label="Max. Tokens", elem_id="max_tokens", value=800)
196
  save_button = gr.Button("Save Settings")
197
  load_button = gr.Button("Load Settings")
198
+ dl_settings_button = gr.Button("Download Settings")
199
+ ul_settings_button = gr.Button("Upload Settings")
200
 
201
  load_button.click(load_settings, js="""
202
  () => {
 
221
  }
222
  """)
223
 
224
+ control_ids = [('oai_key', '#oai_key textarea'),
225
+ ('system_prompt', '#system_prompt textarea'),
226
+ ('seed', '#seed textarea'),
227
+ ('temp', '#temp input'),
228
+ ('max_tokens', '#max_tokens input'),
229
+ ('model', '#model')]
230
+ controls = [oai_key, system_prompt, seed, temp, max_tokens, model]
231
+
232
+ dl_settings_button.click(None, controls, js=generate_download_settings_js("oai_chat_settings.bin", control_ids))
233
+ ul_settings_button.click(None, None, None, js=generate_upload_settings_js(control_ids))
234
+
235
  chatbot = gr.Chatbot(
236
  [],
237
  elem_id="chatbot",
settings_mgr.py ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ def generate_download_settings_js(dl_fn, control_ids):
2
+ js_code = """
3
+ async (""" + ", ".join([f'{ctrl[0]}' for ctrl in control_ids]) + """) => {
4
+ const password = prompt("Please enter a password for encryption", " ");
5
+ if (!password) {
6
+ alert("No password provided. Cancelling download.");
7
+ return;
8
+ }
9
+
10
+ let settings = {""" + ", ".join([f'"{ctrl[0]}": {ctrl[0]}' for ctrl in control_ids]) + """};
11
+ const settingsStr = JSON.stringify(settings);
12
+ const textEncoder = new TextEncoder();
13
+ const encodedSettings = textEncoder.encode(settingsStr);
14
+ const salt = crypto.getRandomValues(new Uint8Array(16));
15
+ const passwordBuffer = textEncoder.encode(password);
16
+ const keyMaterial = await crypto.subtle.importKey('raw', passwordBuffer, {name: 'PBKDF2'}, false, ['deriveKey']);
17
+ const key = await crypto.subtle.deriveKey(
18
+ {name: 'PBKDF2', salt: salt, iterations: 100000, hash: 'SHA-256'},
19
+ keyMaterial,
20
+ {name: 'AES-GCM', length: 256},
21
+ false,
22
+ ['encrypt']
23
+ );
24
+ const iv = crypto.getRandomValues(new Uint8Array(12));
25
+ const encryptedSettings = await crypto.subtle.encrypt({name: 'AES-GCM', iv: iv}, key, encodedSettings);
26
+ const blob = new Blob([salt, iv, new Uint8Array(encryptedSettings)], {type: 'application/octet-stream'});
27
+ const url = URL.createObjectURL(blob);
28
+ const a = document.createElement('a');
29
+ a.href = url;
30
+ a.download = '""" + dl_fn + """';
31
+ document.body.appendChild(a);
32
+ a.click();
33
+ document.body.removeChild(a);
34
+ URL.revokeObjectURL(url);
35
+ }"""
36
+ return js_code
37
+
38
+ def generate_upload_settings_js(control_ids):
39
+ js_code = """
40
+ async () => {
41
+ const input = document.createElement('input');
42
+ input.type = 'file';
43
+ input.onchange = async e => {
44
+ const file = e.target.files[0];
45
+ if (!file) {
46
+ alert("No file selected.");
47
+ return;
48
+ }
49
+
50
+ const password = prompt("Please enter the password for decryption", " ");
51
+ if (!password) {
52
+ alert("No password provided. Cancelling upload.");
53
+ return;
54
+ }
55
+
56
+ const arrayBuffer = await file.arrayBuffer();
57
+ const salt = arrayBuffer.slice(0, 16);
58
+ const iv = arrayBuffer.slice(16, 28);
59
+ const encryptedData = arrayBuffer.slice(28);
60
+ const textEncoder = new TextEncoder();
61
+ const passwordBuffer = textEncoder.encode(password);
62
+ const keyMaterial = await crypto.subtle.importKey('raw', passwordBuffer, {name: 'PBKDF2'}, false, ['deriveKey']);
63
+ const key = await crypto.subtle.deriveKey(
64
+ {name: 'PBKDF2', salt: salt, iterations: 100000, hash: 'SHA-256'},
65
+ keyMaterial,
66
+ {name: 'AES-GCM', length: 256},
67
+ false,
68
+ ['decrypt']
69
+ );
70
+
71
+ try {
72
+ const decryptedData = await crypto.subtle.decrypt({name: 'AES-GCM', iv: iv}, key, encryptedData);
73
+ const textDecoder = new TextDecoder();
74
+ const settingsStr = textDecoder.decode(decryptedData);
75
+ const settings = JSON.parse(settingsStr);
76
+ """ + "\n".join([f'document.querySelector("{ctrl[1]}").value = settings["{ctrl[0]}"];' for ctrl in control_ids]) + """
77
+ """ + "\n".join([f'document.querySelector("{ctrl[1]}").dispatchEvent(new InputEvent("input", {{ bubbles: true }}));' for ctrl in control_ids]) + """
78
+ } catch (err) {
79
+ alert("Failed to decrypt. Check your password and try again.");
80
+ console.error("Decryption failed:", err);
81
+ }
82
+ };
83
+ input.click();
84
+ }"""
85
+ return js_code