tspb commited on
Commit
4bfb33c
·
verified ·
1 Parent(s): c2bad5a

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +601 -18
index.html CHANGED
@@ -1,19 +1,602 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>RISU File Tools</title>
6
+ <script src="./pako.min.js"></script>
7
+ <script src="./msgpackr.min.js"></script>
8
+ <style>
9
+ .container { margin: 20px; }
10
+ textarea { width: 100%; height: 200px; margin: 10px 0; }
11
+ .output { margin-top: 20px; }
12
+ pre { white-space: pre-wrap; }
13
+ .tool-section { margin-bottom: 30px; padding: 20px; border: 1px solid #ddd; }
14
+ </style>
15
+ </head>
16
+ <body>
17
+ <div class="container">
18
+ <div class="tool-section">
19
+ <h1>ST to Risu Converter</h1>
20
+ <label for="stInput">Paste ST JSON here:</label>
21
+ <textarea id="stInput" placeholder="Paste ST JSON content..."></textarea>
22
+
23
+ <label for="risuDefault">Paste Risu Default JSON here:</label>
24
+ <textarea id="risuDefault" placeholder="Paste Risu Default JSON content...">
25
+ {
26
+ "name": "Default",
27
+ "apiType": "instructgpt35",
28
+ "openAIKey": "",
29
+ "mainPrompt": "",
30
+ "jailbreak": "",
31
+ "globalNote": "",
32
+ "temperature": 100,
33
+ "maxContext": 16000,
34
+ "maxResponse": 1000,
35
+ "frequencyPenalty": 0,
36
+ "PresensePenalty": 0,
37
+ "formatingOrder": [
38
+ "main",
39
+ "description",
40
+ "personaPrompt",
41
+ "chats",
42
+ "lastChat",
43
+ "jailbreak",
44
+ "lorebook",
45
+ "globalNote",
46
+ "authorNote"
47
+ ],
48
+ "aiModel": "reverse_proxy",
49
+ "subModel": "reverse_proxy",
50
+ "currentPluginProvider": "",
51
+ "textgenWebUIStreamURL": "",
52
+ "textgenWebUIBlockingURL": "",
53
+ "forceReplaceUrl": "",
54
+ "forceReplaceUrl2": "",
55
+ "promptPreprocess": false,
56
+ "bias": [],
57
+ "koboldURL": "http://localho.st:5001/api/v1",
58
+ "proxyKey": "",
59
+ "ooba": {
60
+ "max_new_tokens": 180,
61
+ "do_sample": true,
62
+ "temperature": 0.7,
63
+ "top_p": 0.9,
64
+ "typical_p": 1,
65
+ "repetition_penalty": 1.15,
66
+ "encoder_repetition_penalty": 1,
67
+ "top_k": 20,
68
+ "min_length": 0,
69
+ "no_repeat_ngram_size": 0,
70
+ "num_beams": 1,
71
+ "penalty_alpha": 0,
72
+ "length_penalty": 1,
73
+ "early_stopping": false,
74
+ "seed": -1,
75
+ "add_bos_token": true,
76
+ "truncation_length": 4096,
77
+ "ban_eos_token": false,
78
+ "skip_special_tokens": true,
79
+ "top_a": 0,
80
+ "tfs": 1,
81
+ "epsilon_cutoff": 0,
82
+ "eta_cutoff": 0,
83
+ "formating": {
84
+ "header": "Below is an instruction that describes a task. Write a response that appropriately completes the request.",
85
+ "systemPrefix": "### Instruction:",
86
+ "userPrefix": "### Input:",
87
+ "assistantPrefix": "### Response:",
88
+ "seperator": "",
89
+ "useName": false
90
+ }
91
+ },
92
+ "ainconfig": {
93
+ "top_p": 0.7,
94
+ "rep_pen": 1.0625,
95
+ "top_a": 0.08,
96
+ "rep_pen_slope": 1.7,
97
+ "rep_pen_range": 1024,
98
+ "typical_p": 1,
99
+ "badwords": "",
100
+ "stoptokens": "",
101
+ "top_k": 140
102
+ },
103
+ "proxyRequestModel": "claude-3-5-sonnet-20240620",
104
+ "openrouterRequestModel": "anthropic/claude-2",
105
+ "NAISettings": {
106
+ "topK": 12,
107
+ "topP": 0.85,
108
+ "topA": 0.1,
109
+ "tailFreeSampling": 0.915,
110
+ "repetitionPenalty": 2.8,
111
+ "repetitionPenaltyRange": 2048,
112
+ "repetitionPenaltySlope": 0.02,
113
+ "repostitionPenaltyPresence": 0,
114
+ "seperator": "",
115
+ "frequencyPenalty": 0.03,
116
+ "presencePenalty": 0,
117
+ "typicalp": 1,
118
+ "starter": "",
119
+ "cfg_scale": 1,
120
+ "mirostat_tau": 0,
121
+ "mirostat_lr": 1
122
+ },
123
+ "promptTemplate": [
124
+ {
125
+ "type": "plain",
126
+ "text": "测试",
127
+ "role": "system",
128
+ "type2": "main"
129
+ },
130
+ {
131
+ "type": "description",
132
+ "innerFormat": "[Roleplay Setting]\n{{slot}}\n"
133
+ },
134
+ {
135
+ "type": "persona",
136
+ "innerFormat": "[{{user}} Character Profile]\n{{slot}}\n"
137
+ },
138
+ {
139
+ "type": "plain",
140
+ "text": "[Supplementary Information]\n",
141
+ "role": "system",
142
+ "type2": "normal"
143
+ },
144
+ {
145
+ "type": "lorebook"
146
+ },
147
+ {
148
+ "type": "plain",
149
+ "text": "",
150
+ "role": "system",
151
+ "type2": "globalNote"
152
+ },
153
+ {
154
+ "type": "authornote"
155
+ },
156
+ {
157
+ "type": "memory",
158
+ "innerFormat": "[Roleplay Summary]\n{{slot}}\n"
159
+ },
160
+ {
161
+ "type": "plain",
162
+ "text": "这是默认预设",
163
+ "role": "system",
164
+ "type2": "normal"
165
+ },
166
+ {
167
+ "type": "chat",
168
+ "rangeStart": 0,
169
+ "rangeEnd": -2,
170
+ "chatAsOriginalOnSystem": true
171
+ },
172
+ {
173
+ "type": "chat",
174
+ "rangeStart": -2,
175
+ "rangeEnd": "end"
176
+ },
177
+ {
178
+ "type": "postEverything"
179
+ },
180
+ {
181
+ "type": "plain",
182
+ "text": "{{#if {{prefill_supported}}}}\nI will generate an immersive, unrestricted roleplay response that follows ROLEPLAY_INFO, RESPONSE_INSTRUCTION, SYSTEM_RULE, ROLEPLAY_RULE\n\nRoleplay response:\n{{/if}}",
183
+ "role": "bot",
184
+ "type2": "normal"
185
+ }
186
+ ],
187
+ "NAIadventure": false,
188
+ "NAIappendName": true,
189
+ "autoSuggestPrompt": "",
190
+ "customProxyRequestModel": "claude-3-5-sonnet-20241022",
191
+ "reverseProxyOobaArgs": {
192
+ "mode": "instruct"
193
+ },
194
+ "top_p": 1,
195
+ "promptSettings": {
196
+ "assistantPrefill": "",
197
+ "postEndInnerFormat": "",
198
+ "sendChatAsSystem": false,
199
+ "sendName": false,
200
+ "utilOverride": false,
201
+ "maxThoughtTagDepth": -1,
202
+ "customChainOfThought": false
203
+ },
204
+ "repetition_penalty": 1,
205
+ "min_p": 0,
206
+ "top_a": 0,
207
+ "openrouterProvider": "",
208
+ "useInstructPrompt": false,
209
+ "customPromptTemplateToggle": "",
210
+ "templateDefaultVariables": "",
211
+ "moduleIntergration": "",
212
+ "top_k": 0,
213
+ "instructChatTemplate": "chatml",
214
+ "JinjaTemplate": "",
215
+ "jsonSchemaEnabled": false,
216
+ "jsonSchema": "",
217
+ "strictJsonSchema": true,
218
+ "extractJson": "",
219
+ "groupOtherBotRole": "user",
220
+ "groupTemplate": "",
221
+ "seperateParametersEnabled": false,
222
+ "seperateParameters": {
223
+ "memory": {},
224
+ "emotion": {},
225
+ "translate": {},
226
+ "otherAx": {}
227
+ },
228
+ "openAIPrediction": "",
229
+ "customAPIFormat": 0,
230
+ "systemContentReplacement": "",
231
+ "systemRoleReplacement": "user",
232
+ "customFlags": [],
233
+ "enableCustomFlags": false,
234
+ "regex": [],
235
+ "image": ""
236
+ }
237
+ </textarea>
238
+
239
+ <button id="convertButton">Convert</button>
240
+
241
+ <div class="output">
242
+ <h2>Converted Risu JSON:</h2>
243
+ <pre id="stOutput"></pre>
244
+ </div>
245
+ </div>
246
+
247
+ <div class="tool-section">
248
+ <h1>RISU Preset File Tools</h1>
249
+ <div>
250
+ <h2>Decrypt RISU Preset</h2>
251
+ <input type="file" id="fileInput" accept=".risupreset,.risup"/>
252
+ <button id="recoverButton">Recover Preset</button>
253
+ </div>
254
+
255
+ <div style="margin-top: 20px;">
256
+ <h2>Encrypt to RISU Preset</h2>
257
+ <input type="file" id="jsonInput" accept=".json"/>
258
+ <button id="encryptButton">Create .risup</button>
259
+ </div>
260
+
261
+ <pre id="output"></pre>
262
+ </div>
263
+ </div>
264
+
265
+ <script>
266
+ // ST to Risu Converter Logic
267
+ document.getElementById('convertButton').addEventListener('click', function convert() {
268
+ try {
269
+ const stInput = JSON.parse(document.getElementById('stInput').value);
270
+ const risuDefault = JSON.parse(document.getElementById('risuDefault').value);
271
+
272
+ if (!stInput || !risuDefault) {
273
+ throw new Error('Invalid JSON input.');
274
+ }
275
+
276
+ const promptOrder = stInput.prompt_order.find(order => order.character_id === 100001);
277
+ if (!promptOrder) {
278
+ throw new Error('Character ID 100001 not found in ST prompt_order.');
279
+ }
280
+
281
+ const stPrompts = stInput.prompts;
282
+ const risuPrompts = risuDefault.promptTemplate;
283
+
284
+ const specialTypeOrder = ["description", "persona", "lorebook", "globalNote", "authornote", "memory", "chat"];
285
+ const specialTemplates = [];
286
+
287
+ specialTypeOrder.forEach(type => {
288
+ const templates = risuPrompts.filter(p => p.type === type || p.type2 === type);
289
+ if (templates.length > 0) {
290
+ specialTemplates.push(...templates);
291
+ } else {
292
+ if (type === "chat") {
293
+ const chatTemplates = risuPrompts.filter(p => p.type === "chat");
294
+ if (chatTemplates.length < 2) {
295
+ specialTemplates.push(...chatTemplates);
296
+ }
297
+ } else {
298
+ throw new Error(`Missing required special type: ${type}`);
299
+ }
300
+ }
301
+ });
302
+
303
+ const convertedPrompts = [];
304
+ const stPromptMap = new Map(stPrompts.map(p => [p.identifier, p]));
305
+
306
+ let mainPrompt;
307
+
308
+ promptOrder.order.forEach(({ identifier, enabled }) => {
309
+ if (!enabled) return;
310
+
311
+ if (identifier === "main") {
312
+ const mainPromptData = stPromptMap.get(identifier);
313
+ if (mainPromptData) {
314
+ const template = risuPrompts.find(p => p.type2 === "main");
315
+ if (template) {
316
+ mainPrompt = {
317
+ ...template,
318
+ text: mainPromptData.content || "未命名"
319
+ };
320
+ }
321
+ }
322
+ return;
323
+ }
324
+
325
+ if (["charDescription", "dialogueExamples", "charPersonality", "scenario", "worldInfoBefore", "worldInfoAfter"].includes(identifier)) {
326
+ return;
327
+ }
328
+
329
+ const stPrompt = stPromptMap.get(identifier);
330
+ if (!stPrompt) {
331
+ console.warn(`Prompt with identifier ${identifier} not found, skipping.`);
332
+ return;
333
+ }
334
+
335
+ const name = stPrompt.name || "未命名";
336
+ convertedPrompts.push({
337
+ type: "plain",
338
+ text: stPrompt.content || "\n",
339
+ role: stPrompt.role,
340
+ type2: "normal",
341
+ name
342
+ });
343
+ });
344
+
345
+ const charDescriptionIndex = promptOrder.order.findIndex(o => o.identifier === "charDescription");
346
+ if (charDescriptionIndex === -1) {
347
+ throw new Error('charDescription not found in prompt_order.');
348
+ }
349
+
350
+ const filteredSpecialTemplates = [
351
+ risuPrompts.find(p => p.type === "description"),
352
+ mainPrompt,
353
+ ...specialTemplates.filter(p => p.type !== "description" && p.type2 !== "main")
354
+ ];
355
+
356
+ const result = [
357
+ ...convertedPrompts.slice(0, charDescriptionIndex),
358
+ ...filteredSpecialTemplates,
359
+ ...convertedPrompts.slice(charDescriptionIndex)
360
+ ].filter(Boolean);
361
+
362
+ risuDefault.promptTemplate = result;
363
+
364
+ document.getElementById('stOutput').textContent = JSON.stringify(risuDefault, null, 2);
365
+ } catch (error) {
366
+ document.getElementById('stOutput').textContent = `Error: ${error.message}`;
367
+ }
368
+ });
369
+
370
+ // RISU Preset File Tools Logic
371
+ async function initWasm() {
372
+ try {
373
+ const response = await fetch('./rpack_bg.wasm');
374
+ if (!response.ok) throw new Error('Failed to fetch Wasm module');
375
+ const wasmModule = await response.arrayBuffer();
376
+ if (!WebAssembly.validate(wasmModule)) throw new Error('Invalid WebAssembly module');
377
+ const { instance } = await WebAssembly.instantiate(wasmModule);
378
+ return instance.exports;
379
+ } catch (error) {
380
+ console.error('Error initializing Wasm module:', error);
381
+ throw error;
382
+ }
383
+ }
384
+
385
+ function getUint8ArrayMemory0(wasmInstance) {
386
+ return new Uint8Array(wasmInstance.memory.buffer);
387
+ }
388
+
389
+ function passArray8ToWasm0(arg, malloc, wasmInstance) {
390
+ const ptr = malloc(arg.length * 1, 1) >>> 0;
391
+ getUint8ArrayMemory0(wasmInstance).set(arg, ptr / 1);
392
+ WASM_VECTOR_LEN = arg.length;
393
+ return ptr;
394
+ }
395
+
396
+ let WASM_VECTOR_LEN = 0;
397
+
398
+ function getDataViewMemory0(wasmInstance) {
399
+ return new DataView(wasmInstance.memory.buffer);
400
+ }
401
+
402
+ function getArrayU8FromWasm0(ptr, len, wasmInstance) {
403
+ return getUint8ArrayMemory0(wasmInstance).subarray(ptr / 1, ptr / 1 + len);
404
+ }
405
+
406
+ async function decodeRPack(datas, wasmInstance) {
407
+ try {
408
+ const retptr = wasmInstance.__wbindgen_add_to_stack_pointer(-16);
409
+ const ptr0 = passArray8ToWasm0(datas, wasmInstance.__wbindgen_malloc, wasmInstance);
410
+ const len0 = WASM_VECTOR_LEN;
411
+ wasmInstance.decode(retptr, ptr0, len0);
412
+ var r0 = getDataViewMemory0(wasmInstance).getInt32(retptr + 4 * 0, true);
413
+ var r1 = getDataViewMemory0(wasmInstance).getInt32(retptr + 4 * 1, true);
414
+ var v2 = getArrayU8FromWasm0(r0, r1, wasmInstance).slice();
415
+ wasmInstance.__wbindgen_free(r0, r1 * 1, 1);
416
+ return v2;
417
+ } finally {
418
+ wasmInstance.__wbindgen_add_to_stack_pointer(16);
419
+ }
420
+ }
421
+
422
+ async function encodeRPack(datas, wasmInstance) {
423
+ try {
424
+ const retptr = wasmInstance.__wbindgen_add_to_stack_pointer(-16);
425
+ const ptr0 = passArray8ToWasm0(datas, wasmInstance.__wbindgen_malloc, wasmInstance);
426
+ const len0 = WASM_VECTOR_LEN;
427
+ wasmInstance.encode(retptr, ptr0, len0);
428
+ var r0 = getDataViewMemory0(wasmInstance).getInt32(retptr + 4 * 0, true);
429
+ var r1 = getDataViewMemory0(wasmInstance).getInt32(retptr + 4 * 1, true);
430
+ var v2 = getArrayU8FromWasm0(r0, r1, wasmInstance).slice();
431
+ wasmInstance.__wbindgen_free(r0, r1 * 1, 1);
432
+ return v2;
433
+ } finally {
434
+ wasmInstance.__wbindgen_add_to_stack_pointer(16);
435
+ }
436
+ }
437
+
438
+ async function decryptBuffer(data, key) {
439
+ const encoder = new TextEncoder();
440
+ const keyData = encoder.encode(key);
441
+ const hash = await window.crypto.subtle.digest("SHA-256", keyData);
442
+ const cryptoKey = await window.crypto.subtle.importKey(
443
+ "raw",
444
+ hash,
445
+ "AES-GCM",
446
+ false,
447
+ ["decrypt"]
448
+ );
449
+ return await window.crypto.subtle.decrypt(
450
+ {
451
+ name: "AES-GCM",
452
+ iv: new Uint8Array(12)
453
+ },
454
+ cryptoKey,
455
+ data
456
+ );
457
+ }
458
+
459
+ async function encryptBuffer(data, key) {
460
+ const encoder = new TextEncoder();
461
+ const keyData = encoder.encode(key);
462
+ const hash = await window.crypto.subtle.digest("SHA-256", keyData);
463
+ const cryptoKey = await window.crypto.subtle.importKey(
464
+ "raw",
465
+ hash,
466
+ "AES-GCM",
467
+ false,
468
+ ["encrypt"]
469
+ );
470
+ return await window.crypto.subtle.encrypt(
471
+ {
472
+ name: "AES-GCM",
473
+ iv: new Uint8Array(12)
474
+ },
475
+ cryptoKey,
476
+ data
477
+ );
478
+ }
479
+
480
+ async function recoverPresetFromFile(file) {
481
+ try {
482
+ const arrayBuffer = await file.arrayBuffer();
483
+ const uint8Array = new Uint8Array(arrayBuffer);
484
+
485
+ let finalData;
486
+
487
+ if (file.name.endsWith('.risup')) {
488
+ // 处理 .risup 文件
489
+ const wasmInstance = await initWasm();
490
+ const decodedData = await decodeRPack(uint8Array, wasmInstance);
491
+ console.log("1. RPack decoded:", decodedData);
492
+
493
+ const decompressedData = pako.inflate(decodedData);
494
+ console.log("2. Decompressed:", decompressedData);
495
+
496
+ const firstDecode = msgpackr.decode(decompressedData);
497
+ console.log("3. First msgpack decode:", firstDecode);
498
+
499
+ const decryptedData = await decryptBuffer(firstDecode.preset, 'risupreset');
500
+ console.log("4. Decrypted data:", new Uint8Array(decryptedData));
501
+
502
+ finalData = msgpackr.decode(new Uint8Array(decryptedData));
503
+ console.log("5. Final decoded data:", finalData);
504
+
505
+ } else if (file.name.endsWith('.risupreset')) {
506
+ // 处理 .risupreset 文件
507
+ const decompressedData = pako.inflate(uint8Array);
508
+ console.log("1. Decompressed:", decompressedData);
509
+
510
+ const firstDecode = msgpackr.decode(decompressedData);
511
+ console.log("2. First msgpack decode:", firstDecode);
512
+
513
+ const encryptedPreset = firstDecode.preset ?? firstDecode.pres;
514
+ if (!encryptedPreset) {
515
+ throw new Error("Missing `preset` or `pres` field in .risupreset file.");
516
+ }
517
+
518
+ const decryptedData = await decryptBuffer(encryptedPreset, 'risupreset');
519
+ console.log("3. Decrypted data:", new Uint8Array(decryptedData));
520
+
521
+ finalData = msgpackr.decode(new Uint8Array(decryptedData));
522
+ console.log("4. Final decoded data:", finalData);
523
+
524
+ } else {
525
+ throw new Error('Unsupported file format');
526
+ }
527
+
528
+ // 成功解析数据后显示
529
+ console.log("Final decoded data:", finalData);
530
+ document.getElementById('output').textContent = JSON.stringify(finalData, null, 2);
531
+
532
+ } catch (error) {
533
+ // 捕获错误并显示
534
+ console.error('Error recovering preset:', error);
535
+ document.getElementById('output').textContent = `Error: ${error.message}\n\nStack: ${error.stack}`;
536
+ }
537
+ }
538
+
539
+
540
+ async function createPresetFile(file) {
541
+ try {
542
+ const text = await file.text();
543
+ const jsonData = JSON.parse(text);
544
+
545
+ const firstEncode = msgpackr.encode(jsonData);
546
+ console.log("1. First msgpack encode:", firstEncode);
547
+
548
+ const encryptedData = await encryptBuffer(firstEncode, 'risupreset');
549
+ console.log("2. Encrypted data:", new Uint8Array(encryptedData));
550
+
551
+ const wrapper = {
552
+ presetVersion: 2,
553
+ type: "preset",
554
+ preset: new Uint8Array(encryptedData)
555
+ };
556
+ const secondEncode = msgpackr.encode(wrapper);
557
+ console.log("3. Second msgpack encode:", secondEncode);
558
+
559
+ const compressedData = pako.deflate(secondEncode);
560
+ console.log("4. Compressed:", compressedData);
561
+
562
+ const wasmInstance = await initWasm();
563
+ const rpackData = await encodeRPack(compressedData, wasmInstance);
564
+ console.log("5. RPack encoded:", rpackData);
565
+
566
+ const blob = new Blob([rpackData], { type: 'application/octet-stream' });
567
+ const url = URL.createObjectURL(blob);
568
+ const a = document.createElement('a');
569
+ a.href = url;
570
+ a.download = file.name.replace('.json', '.risup');
571
+ a.click();
572
+ URL.revokeObjectURL(url);
573
+
574
+ document.getElementById('output').textContent = "Preset file created successfully!";
575
+ } catch (error) {
576
+ console.error('Error creating preset:', error);
577
+ document.getElementById('output').textContent = `Error: ${error.message}\n\nStack: ${error.stack}`;
578
+ }
579
+ }
580
+
581
+ document.getElementById('recoverButton').addEventListener('click', () => {
582
+ const fileInput = document.getElementById('fileInput');
583
+ const file = fileInput.files[0];
584
+ if (file) {
585
+ recoverPresetFromFile(file);
586
+ } else {
587
+ document.getElementById('output').textContent = 'Please select a file first.';
588
+ }
589
+ });
590
+
591
+ document.getElementById('encryptButton').addEventListener('click', () => {
592
+ const fileInput = document.getElementById('jsonInput');
593
+ const file = fileInput.files[0];
594
+ if (file) {
595
+ createPresetFile(file);
596
+ } else {
597
+ document.getElementById('output').textContent = 'Please select a JSON file first.';
598
+ }
599
+ });
600
+ </script>
601
+ </body>
602
  </html>