This commit is contained in:
hashcoko
2024-07-30 01:16:40 +09:00
73 changed files with 3735 additions and 1043 deletions

View File

@@ -1,4 +1,4 @@
import { get } from "svelte/store"
import { get, writable } from "svelte/store"
import { DataBase } from "./database"
import { hubURL } from "../characterCards"
import localforage from "localforage"
@@ -7,6 +7,10 @@ import { forageStorage, getUnpargeables, replaceDbResources } from "./globalApi"
import { encodeRisuSave } from "./risuSave"
import { v4 } from "uuid"
export const AccountWarning = writable('')
let seenWarnings:string[] = []
export class AccountStorage{
auth:string
usingSync:boolean
@@ -25,10 +29,23 @@ export class AccountStorage{
'X-Format': 'nocheck'
}
})
if(da.headers.get('Content-Type') === 'application/json'){
const json = (await da.json())
if(json?.warning){
if(!seenWarnings.includes(json.warning)){
seenWarnings.push(json.warning)
AccountWarning.set(json.warning)
}
}
}
if(da.status === 304){
return key
}
if(da.status === 403){
if(da.headers.get('x-risu-status') === 'warn'){
return
}
localStorage.setItem("fallbackRisuToken",await alertLogin())
this.checkAuth()
}

View File

@@ -1,3 +1,8 @@
export const DataBase = writable({} as any as Database)
export const loadedStore = writable(false)
export let appVer = "122.1.2"
export let webAppSubVer = ''
import { get, writable } from 'svelte/store';
import { checkNullish, decryptBuffer, encryptBuffer, selectSingleFile } from '../util';
import { changeLanguage, language } from '../../lang';
@@ -12,11 +17,6 @@ import { defaultColorScheme, type ColorScheme } from '../gui/colorscheme';
import type { PromptItem, PromptSettings } from '../process/prompt';
import type { OobaChatCompletionRequestParams } from '../model/ooba';
export const DataBase = writable({} as any as Database)
export const loadedStore = writable(false)
export let appVer = "115.0.1"
export let webAppSubVer = ''
export function setDatabase(data:Database){
if(checkNullish(data.characters)){
data.characters = []
@@ -419,6 +419,16 @@ export function setDatabase(data:Database){
data.stabilityModel ??= 'sd3-large'
data.stabllityStyle ??= ''
data.legacyTranslation ??= false
data.comfyUiUrl ??= 'http://localhost:8188'
data.comfyConfig ??= {
workflow: '',
posNodeID: '',
posInputName: 'text',
negNodeID: '',
negInputName: 'text',
timeout: 30
}
changeLanguage(data.language)
DataBase.set(data)
}
@@ -585,6 +595,7 @@ export interface Database{
name:string
icon:string
largePortrait?:boolean
id?:string
}[]
assetWidth:number
animationSpeed:number
@@ -695,6 +706,8 @@ export interface Database{
stabilityKey: string
stabllityStyle: string
legacyTranslation: boolean
comfyConfig: ComfyConfig
comfyUiUrl: string
}
export interface customscript{
@@ -826,6 +839,7 @@ export interface character{
}>
defaultVariables?:string
lowLevelAccess?:boolean
hideChatIcon?:boolean
}
@@ -873,6 +887,7 @@ export interface groupChat{
nickname?:string
defaultVariables?:string
lowLevelAccess?:boolean
hideChatIcon?:boolean
}
export interface botPreset{
@@ -965,6 +980,16 @@ interface NAIImgConfig{
InfoExtracted:number,
RefStrength:number
}
interface ComfyConfig{
workflow:string,
posNodeID: string,
posInputName:string,
negNodeID: string,
negInputName:string,
timeout: number
}
export type FormatingOrderItem = 'main'|'jailbreak'|'chats'|'lorebook'|'globalNote'|'authorNote'|'lastChat'|'description'|'postEverything'|'personaPrompt'
export interface Chat{
@@ -981,6 +1006,7 @@ export interface Chat{
scriptstate?:{[key:string]:string|number|boolean}
modules?:string[]
id?:string
bindedPersona?:string
}
export interface Message{
@@ -1299,9 +1325,9 @@ export async function downloadPreset(id:number, type:'json'|'risupreset'|'return
}
else if(type === 'risupreset' || type === 'return'){
const buf = fflate.compressSync(encodeMsgpack({
presetVersion: 0,
presetVersion: 2,
type: 'preset',
pres: await encryptBuffer(
preset: await encryptBuffer(
encodeMsgpack(pres),
'risupreset'
)
@@ -1342,8 +1368,8 @@ export async function importPreset(f:{
if(f.name.endsWith('.risupreset')){
const decoded = await decodeMsgpack(fflate.decompressSync(f.data))
console.log(decoded)
if(decoded.presetVersion === 0 && decoded.type === 'preset'){
pre = {...presetTemplate,...decodeMsgpack(Buffer.from(await decryptBuffer(decoded.pres, 'risupreset')))}
if((decoded.presetVersion === 0 || decoded.presetVersion === 2) && decoded.type === 'preset'){
pre = {...presetTemplate,...decodeMsgpack(Buffer.from(await decryptBuffer(decoded.preset ?? decoded.pres, 'risupreset')))}
}
}
else{
@@ -1484,4 +1510,4 @@ export async function importPreset(f:{
pre.name ??= "Imported"
db.botPresets.push(pre)
setDatabase(db)
}
}

View File

@@ -1,4 +1,5 @@
import { writeBinaryFile,BaseDirectory, readBinaryFile, exists, createDir, readDir, removeFile } from "@tauri-apps/api/fs"
import { changeFullscreen, checkNullish, findCharacterbyId, sleep } from "../util"
import { convertFileSrc, invoke } from "@tauri-apps/api/tauri"
import { v4 as uuidv4, v4 } from 'uuid';
@@ -11,7 +12,7 @@ import { checkRisuUpdate } from "../update";
import { botMakerMode, selectedCharID } from "../stores";
import { Body, ResponseType, fetch as TauriFetch } from "@tauri-apps/api/http";
import { loadPlugins } from "../plugins/plugins";
import { alertConfirm, alertError, alertNormal, alertNormalWait } from "../alert";
import { alertConfirm, alertError, alertNormal, alertNormalWait, alertSelect } from "../alert";
import { checkDriverInit, syncDrive } from "../drive/drive";
import { hasher } from "../parser";
import { characterURLImport, hubURL } from "../characterCards";
@@ -55,12 +56,26 @@ interface fetchLog{
let fetchLog:fetchLog[] = []
/**
* Downloads a file with the given name and data.
*
* @param {string} name - The name of the file to be downloaded.
* @param {Uint8Array|ArrayBuffer|string} dat - The data of the file to be downloaded.
*/
async function writeBinaryFileFast(appPath: string, data: Uint8Array) {
const secret = await invoke('get_http_secret') as string;
const port = await invoke('get_http_port') as number;
const apiUrl = `http://127.0.0.1:${port}/?path=${encodeURIComponent(appPath)}`;
const response = await fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/octet-stream',
'x-tauri-secret': secret
},
body: new Blob([data])
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
}
export async function downloadFile(name:string, dat:Uint8Array|ArrayBuffer|string) {
if(typeof(dat) === 'string'){
dat = Buffer.from(dat, 'utf-8')
@@ -266,7 +281,7 @@ export async function saveAsset(data:Uint8Array, customId:string = '', fileName:
fileExtension = fileName.split('.').pop()
}
if(isTauri){
await writeBinaryFile(`assets/${id}.${fileExtension}`, data ,{dir: BaseDirectory.AppData})
await writeBinaryFileFast(`assets/${id}.${fileExtension}`, data);
return `assets/${id}.${fileExtension}`
}
else{
@@ -341,13 +356,14 @@ export async function saveDb(){
changed = false
let db = get(DataBase)
db.saveTime = Math.floor(Date.now() / 1000)
const dbData = encodeRisuSave(db)
if(isTauri){
await writeBinaryFile('database/database.bin', dbData, {dir: BaseDirectory.AppData})
await writeBinaryFile(`database/dbbackup-${(Date.now()/100).toFixed()}.bin`, dbData, {dir: BaseDirectory.AppData})
const dbData = encodeRisuSave(db)
await writeBinaryFileFast('database/database.bin', dbData);
await writeBinaryFileFast(`database/dbbackup-${(Date.now()/100).toFixed()}.bin`, dbData);
}
else{
if(!forageStorage.isAccount){
const dbData = encodeRisuSave(db)
await forageStorage.setItem('database/database.bin', dbData)
await forageStorage.setItem(`database/dbbackup-${(Date.now()/100).toFixed()}.bin`, dbData)
}
@@ -386,7 +402,7 @@ export async function saveDb(){
async function getDbBackups() {
let db = get(DataBase)
if(db?.account?.useSync){
return
return []
}
if(isTauri){
const keys = await readDir('database', {dir: BaseDirectory.AppData})
@@ -446,14 +462,11 @@ export async function loadData() {
await createDir('assets', {dir: BaseDirectory.AppData})
}
if(!await exists('database/database.bin', {dir: BaseDirectory.AppData})){
await writeBinaryFile('database/database.bin',
encodeRisuSave({})
,{dir: BaseDirectory.AppData})
await writeBinaryFileFast('database/database.bin', encodeRisuSave({}));
}
try {
setDatabase(
decodeRisuSave(await readBinaryFile('database/database.bin',{dir: BaseDirectory.AppData}))
)
const decoded = decodeRisuSave(await readBinaryFile('database/database.bin',{dir: BaseDirectory.AppData}))
setDatabase(decoded)
} catch (error) {
const backups = await getDbBackups()
let backupLoaded = false
@@ -483,10 +496,11 @@ export async function loadData() {
await forageStorage.setItem('database/database.bin', gotStorage)
}
try {
setDatabase(
decodeRisuSave(gotStorage)
)
const decoded = decodeRisuSave(gotStorage)
console.log(decoded)
setDatabase(decoded)
} catch (error) {
console.error(error)
const backups = await getDbBackups()
let backupLoaded = false
for(const backup of backups){
@@ -1076,23 +1090,24 @@ async function checkNewFormat(): Promise<void> {
if (v.lorebook) {
v.lorebook = updateLorebooks(v.lorebook);
}
return v;
});
return v
})
if (!db.formatversion) {
/**
* Checks and updates the path of a given data string.
*
* @param {string} data - The data string to be checked and updated.
* @returns {string} - The updated data string with the correct path.
*/
function checkParge(data: string): string {
if (data.startsWith('assets') || (data.length < 3)) {
return data;
} else {
const d = 'assets/' + (data.replace(/\\/g, '/').split('assets/')[1]);
if (!d) {
return data;
db.personas = (db.personas ?? []).map((v) => {
v.id ??= uuidv4()
return v
})
if(!db.formatversion){
function checkParge(data:string){
if(data.startsWith('assets') || (data.length < 3)){
return data
}
else{
const d = 'assets/' + (data.replace(/\\/g, '/').split('assets/')[1])
if(!d){
return data
}
return d;
}
@@ -2021,4 +2036,47 @@ export class BlankWriter{
async end(){
//do nothing, just to make compatible with other writer
}
}
export async function loadInternalBackup(){
const keys = isTauri ? (await readDir('database', {dir: BaseDirectory.AppData})).map((v) => {
return v.name
}) : (await forageStorage.keys())
let internalBackups:string[] = []
for(const key of keys){
if(key.includes('dbbackup-')){
internalBackups.push(key)
}
}
const selectOptions = [
'Cancel',
...(internalBackups.map((a) => {
return (new Date(parseInt(a.replace('database/dbbackup-', '').replace('dbbackup-','')) * 100)).toLocaleString()
}))
]
const alertResult = parseInt(
await alertSelect(selectOptions)
) - 1
if(alertResult === -1){
return
}
const selectedBackup = internalBackups[alertResult]
const data = isTauri ? (
await readBinaryFile('database/' + selectedBackup, {dir: BaseDirectory.AppData})
) : (await forageStorage.getItem(selectedBackup))
setDatabase(
decodeRisuSave(data)
)
await alertNormal('Loaded backup')
}

View File

@@ -16,7 +16,7 @@ const magicCompressedHeader = new Uint8Array([0, 82, 73, 83, 85, 83, 65, 86, 69,
export function encodeRisuSave(data:any, compression:'noCompression'|'compression' = 'noCompression'){
let encoded:Uint8Array = packr.encode(data)
if(isTauri || compression === 'compression'){
if(compression === 'compression'){
encoded = fflate.compressSync(encoded)
const result = new Uint8Array(encoded.length + magicCompressedHeader.length);
result.set(magicCompressedHeader, 0)