Remove V1 Plugin

This commit is contained in:
Kwaroran
2024-12-24 23:14:49 +09:00
parent 2f8904e567
commit 027a591424
11 changed files with 21 additions and 1353 deletions

View File

@@ -1,264 +0,0 @@
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
(function () {
var __risuPlugin__ = {
providers: [],
fetchResponseQueue: []
};
var sleep = function (ms) { return new Promise(function (r) { return setTimeout(r, ms); }); };
function transferDataAsync(type, body) {
return __awaiter(this, void 0, void 0, function () {
var id, i, q;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
id = "".concat(Date.now(), "_").concat(Math.random());
postMessage({
type: 'fetch',
body: __assign({ id: id }, body)
});
_a.label = 1;
case 1:
if (!true) return [3 /*break*/, 3];
return [4 /*yield*/, sleep(50)];
case 2:
_a.sent();
for (i = 0; i < __risuPlugin__.fetchResponseQueue.length; i++) {
q = __risuPlugin__.fetchResponseQueue[i];
if (q.id === id) {
__risuPlugin__.fetchResponseQueue.splice(i, 1);
return [2 /*return*/, q.data];
}
}
return [3 /*break*/, 1];
case 3: return [2 /*return*/];
}
});
});
}
function risuFetch(url, arg) {
return __awaiter(this, void 0, void 0, function () {
var id, i, q;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
id = "".concat(Date.now(), "_").concat(Math.random());
postMessage({
type: 'fetch',
body: {
id: id,
url: url,
arg: arg
}
});
_a.label = 1;
case 1:
if (!true) return [3 /*break*/, 3];
return [4 /*yield*/, sleep(50)];
case 2:
_a.sent();
for (i = 0; i < __risuPlugin__.fetchResponseQueue.length; i++) {
q = __risuPlugin__.fetchResponseQueue[i];
if (q.id === id) {
__risuPlugin__.fetchResponseQueue.splice(i, 1);
return [2 /*return*/, q.data];
}
}
return [3 /*break*/, 1];
case 3: return [2 /*return*/];
}
});
});
}
function getArg(arg) {
return __awaiter(this, void 0, void 0, function () {
var id, i, q;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
id = "".concat(Date.now(), "_").concat(Math.random());
postMessage({
type: 'getArg',
body: {
id: id,
arg: arg
}
});
_a.label = 1;
case 1:
if (!true) return [3 /*break*/, 3];
return [4 /*yield*/, sleep(50)];
case 2:
_a.sent();
for (i = 0; i < __risuPlugin__.fetchResponseQueue.length; i++) {
q = __risuPlugin__.fetchResponseQueue[i];
if (q.id === id) {
__risuPlugin__.fetchResponseQueue.splice(i, 1);
return [2 /*return*/, q.data];
}
}
return [3 /*break*/, 1];
case 3: return [2 /*return*/];
}
});
});
}
function addProvider(name, func) {
postMessage({
type: 'addProvider',
body: name
});
__risuPlugin__.providers.push({
name: name,
func: func
});
}
function printLog(data) {
postMessage({
type: 'log',
body: data
});
}
function getChar() {
return transferDataAsync('getChar', '');
}
function setChar(char) {
postMessage({
type: 'setChar',
body: char
});
}
function addCharaJs(code, position) {
if (position === void 0) { position = 'back'; }
var codeString = code.toString().replace(/.+?\{/, '{');
postMessage({
type: 'addCharaJs',
body: {
code: codeString,
position: position
}
});
}
function handleOnmessage(data) {
return __awaiter(this, void 0, void 0, function () {
var _a, body, providers, providerfunc, _i, providers_1, provider, _b, error_1;
var _c;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
if (!data.type) {
return [2 /*return*/];
}
_a = data.type;
switch (_a) {
case "requestProvider": return [3 /*break*/, 1];
case "fetchData": return [3 /*break*/, 6];
}
return [3 /*break*/, 7];
case 1:
body = data.body;
providers = __risuPlugin__.providers;
providerfunc = null;
for (_i = 0, providers_1 = providers; _i < providers_1.length; _i++) {
provider = providers_1[_i];
if (provider.name === body.key) {
providerfunc = provider.func;
}
}
if (!!providerfunc) return [3 /*break*/, 2];
postMessage({
type: 'resProvider',
body: {
'success': false,
'content': 'unknown provider'
}
});
return [3 /*break*/, 5];
case 2:
_d.trys.push([2, 4, , 5]);
_b = postMessage;
_c = {
type: 'resProvider'
};
return [4 /*yield*/, providerfunc(body.arg)];
case 3:
_b.apply(void 0, [(_c.body = _d.sent(),
_c)]);
return [3 /*break*/, 5];
case 4:
error_1 = _d.sent();
postMessage({
type: 'resProvider',
body: {
'success': false,
'content': "providerError: ".concat(error_1)
}
});
return [3 /*break*/, 5];
case 5: return [3 /*break*/, 7];
case 6:
{
__risuPlugin__.fetchResponseQueue.push(data.body);
return [3 /*break*/, 7];
}
_d.label = 7;
case 7: return [2 /*return*/];
}
});
});
}
onmessage = function (ev) {
handleOnmessage(ev.data);
var data = ev.data;
};
{
var __risuPlugin__1 = null;
var transferDataAsync_1 = null;
//{{placeholder}}
}
})();

View File

@@ -1,192 +0,0 @@
(() => {
interface risuPlugin{
providers: {name:string, func:(arg:providerArgument) => Promise<{success:boolean,content:string}>}[]
fetchResponseQueue:{id:string,data:any}[]
}
let __risuPlugin__:risuPlugin = {
providers: [],
fetchResponseQueue: []
}
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
interface OpenAIChat{
role: 'system'|'user'|'assistant'
content: string
}
interface providerArgument{
prompt_chat?: OpenAIChat,
temperature?: number,
max_tokens?: number,
presence_penalty?: number
frequency_penalty?: number
bias?: {[key:string]:string}
}
async function transferDataAsync(type:string,body:any) {
const id = `${Date.now()}_${Math.random()}`
postMessage({
type: 'fetch',
body: {id: id, ...body}
})
while(true){
await sleep(50)
for(let i=0;i<__risuPlugin__.fetchResponseQueue.length;i++){
const q = __risuPlugin__.fetchResponseQueue[i]
if(q.id === id){
__risuPlugin__.fetchResponseQueue.splice(i, 1)
return q.data
}
}
}
}
async function risuFetch(url:string, arg:{body:any,headers?:{[key:string]:string}}){
const id = `${Date.now()}_${Math.random()}`
postMessage({
type: 'fetch',
body: {
id: id,
url: url,
arg: arg
}
})
while(true){
await sleep(50)
for(let i=0;i<__risuPlugin__.fetchResponseQueue.length;i++){
const q = __risuPlugin__.fetchResponseQueue[i]
if(q.id === id){
__risuPlugin__.fetchResponseQueue.splice(i, 1)
return q.data as {
ok: boolean;
data: any;
}
}
}
}
}
async function getArg(arg:string){
const id = `${Date.now()}_${Math.random()}`
postMessage({
type: 'getArg',
body: {
id: id,
arg: arg
}
})
while(true){
await sleep(50)
for(let i=0;i<__risuPlugin__.fetchResponseQueue.length;i++){
const q = __risuPlugin__.fetchResponseQueue[i]
if(q.id === id){
__risuPlugin__.fetchResponseQueue.splice(i, 1)
return q.data as (string|number|null)
}
}
}
}
function addProvider(name:string, func:(arg:providerArgument) => Promise<{success:boolean,content:string}>){
postMessage({
type: 'addProvider',
body: name
})
__risuPlugin__.providers.push({
name: name,
func: func
})
}
function printLog(data:any){
postMessage({
type: 'log',
body: data
})
}
function getChar(){
return transferDataAsync('getChar', '')
}
function setChar(char:any){
postMessage({
type: 'setChar',
body: char
})
}
function addCharaJs(code:Function, position:'front'|'back' = 'back'){
const codeString = code.toString().replace(/.+?\{/, '{')
postMessage({
type: 'addCharaJs',
body: {
code: codeString,
position: position
}
})
}
async function handleOnmessage(data:{type:string,body:any}) {
if(!data.type){
return
}
switch(data.type){
case "requestProvider":{
const body:{key:string,arg:providerArgument} = data.body
const providers = __risuPlugin__.providers
let providerfunc:((arg:providerArgument) => Promise<{success:boolean,content:string}>)|null= null
for(const provider of providers){
if(provider.name === body.key){
providerfunc = provider.func
}
}
if(!providerfunc){
postMessage({
type: 'resProvider',
body: {
'success': false,
'content': 'unknown provider'
}
})
}
else{
try {
postMessage({
type: 'resProvider',
body: await providerfunc(body.arg)
})
} catch (error) {
postMessage({
type: 'resProvider',
body: {
'success': false,
'content': `providerError: ${error}`
}
})
}
}
break
}
case "fetchData":{
__risuPlugin__.fetchResponseQueue.push(data.body)
break
}
}
}
onmessage = (ev) => {
handleOnmessage(ev.data)
const data:{type:string,body:any} = ev.data
}
{
const __risuPlugin__ = null
const transferDataAsync = null
//{{placeholder}}
}
})()

View File

@@ -1,115 +0,0 @@
//The @use comment tells the program what callable functions exist. If you omit this, the function will not be called.
//@use editInput
//@use editOutput
//@use editProcess
//@use editDisplay
//@use onButtonClick
//@use modifyRequestChat
async function editInput(text){
//editInput is a callable function that is called when the user inputs text into the input box.
//the first argument is the text that the user input.
//the text would replaced to return value, which would change the real value.
return text;
}
async function editOutput(text){
//editOutput is a callable function that is called when bot outputs text.
//the first argument is the text that the bot outputs.
//the text would replaced to return value, which would change the real value.
return text;
}
async function editProcess(text){
//editOutput is a callable function that is called when before request.
//the first argument is the original text.
//the text would replaced to return value and used in request, but it would not change the real value.
return text;
}
async function editDisplay(text){
//editDisplay is a callable function that is called when before display.
//the first argument is the original text.
//the text would replaced to return value and be displayed, but it would not change the real value.
return text
}
async function onButtonClick(code){
//onButtonClick is a callable function that is called when the user clicks the button.
//a button is a html element that has the attribute "risu-btn".
//the first argument is the code of the button.
//example: <button risu-btn="example-char">button</button> uses "example-char" as the code.
//return value is not used.
return
}
async function modifyRequestChat(chat){
//modifyRequestChat is a callable function that is called when before request.
//the first argument is the chat array. chat array is almost same as OpenAI's chat array.
//unlike editProcess, its called after other fixes is done, and its only called once, with the whole chat array.
//the chat array would replaced to return value and used in request.
return chat
}
async function showcase(){
//this is a function for just introducing the apis.
//getChat() returns the chat object.
const chat = await getChat()
//setChat(chat) sets the chat object.
//must be a valid chat object.
//returns true if success, false if failed.
await setChat(chat)
//getName() returns the name of the character.
const name = await getName()
//setName(name) sets the name of the character.
//must be a valid string.
//returns true if success, false if failed.
await setName(name)
//getDescription() returns the description of the character.
const description = await getDescription()
//setDescription(description) sets the description of the character.
//must be a valid string.
//returns true if success, false if failed.
await setDescription(description)
//getCharacterFirstMessage() returns the first message of the character.
const firstMessage = await getCharacterFirstMessage()
//setCharacterFirstMessage(firstMessage) sets the first message of the character.
//must be a valid string.
//returns true if success, false if failed.
await setCharacterFirstMessage(firstMessage)
//setState(stateName, data) sets the states of the character.
//states are used to store data, because the data would be lost every time when function is called.
//if data is string, it must be less or equal to 100000 characters.
//stateName must be a valid string.
//data must be a valid string, number or boolean.
//returns true if success, false if failed.
await setState("somedata", "data")
await setState("anotherdata", 123)
//getState(stateName) returns the state of the character.
//stateName must be a valid string.
//returns the data if success, null if failed.
const data = await getState("somedata")
const anotherdata = await getState("anotherdata")
}
// --- additional notes
// the code are parsed everytime, so complex codes would slow down the program.
// the function must be return in 400ms, or it would be timeout.
// for security reasons, you can only access limited apis.

View File

@@ -834,4 +834,5 @@ export const languageEnglish = {
menuSideBar: "Menu Side Bar",
home: "Home",
showSavingIcon: "Show Saving Icon",
pluginVersionWarn: "This is {{plugin_version}} version of the plugin. which is not compatible with this version of RisuAI. please update the plugin to {{required_version}} version.",
}

View File

@@ -38,7 +38,11 @@
<TrashIcon />
</button>
</div>
{#if Object.keys(plugin.arguments).length > 0}
{#if plugin.version !== 2}
<span class="text-draculared text-xs">
{language.pluginVersionWarn.replace('{{plugin_version}}', 'API V1').replace('{{required_version}}', 'API V2')}
</span>
{:else if Object.keys(plugin.arguments).length > 0}
<div class="flex flex-col mt-2 bg-dark-900 bg-opacity-50 p-3">
{#each Object.keys(plugin.arguments) as arg}
<span>{arg}</span>

View File

@@ -1,5 +1,4 @@
import { runTrigger } from "./process/triggers";
import { runCharacterJS } from "./plugins/embedscript";
import { sleep } from "./util";
import { getCurrentCharacter, getCurrentChat, setCurrentChat } from "./storage/database.svelte";
@@ -36,13 +35,6 @@ function nodeObserve(node:HTMLElement){
}
if(btnEvent){
node.addEventListener('click',async ()=>{
await runCharacterJS({
code: null,
mode: 'onButtonClick',
data: btnEvent
})
}, {passive: true})
node.setAttribute('risu-observer', 'true');
return
}

View File

@@ -1,324 +0,0 @@
import { get } from 'svelte/store'
import type { ScriptMode } from '../process/scripts'
//@ts-ignore
import WorkerUrl from './embedworker?worker&url'
import { getDatabase, type Message } from '../storage/database.svelte'
import { selectedCharID } from '../stores.svelte'
import { setDatabase } from '../storage/database.svelte'
let worker = new Worker(WorkerUrl, {type: 'module'})
let additionalCharaJS:string[] = []
export function addAdditionalCharaJS(code:string, position:'front'|'back' = 'back'){
if(position === 'front'){
additionalCharaJS.unshift(code)
}
else{
additionalCharaJS.push(code)
}
}
let results:{
id: string,
result: any
}[] = []
let workerFunctions: {
[key:string]: (...args:any[])=> Promise<any>
} = {}
worker.onmessage = ({data}) => {
if(data.type === 'api'){
workerFunctions[data.name](...data.args).then((result)=>{
worker.postMessage({
type: 'result',
id: data.id,
result
})
})
}
else{
results.push(data)
}
}
function addWorkerFunction(name:string, func: (...args:any[])=> Promise<any>){
workerFunctions[name] = func
worker.postMessage({
type: 'api',
name
})
}
function runVirtualJS(code:string){
const id = `id${Math.random()}`.replace('.','')
worker.postMessage({
id,code
})
let startTime = performance.now()
return new Promise((resolve,reject)=>{
const interval = setInterval(()=>{
const result = results.find(r=>r.id === id)
if(result){
clearInterval(interval)
resolve(result.result)
}
else if(performance.now() - startTime > 800){
clearInterval(interval)
//restart worker
worker.terminate()
worker = new Worker(WorkerUrl, {type: 'module'})
reject('timeout')
}
},10)
})
}
addWorkerFunction('getChat', async () => {
const db = getDatabase({
snapshot: true
})
const selectedChar = get(selectedCharID)
const char = db.characters[selectedChar]
return safeStructuredClone(char.chats[char.chatPage].message)
})
addWorkerFunction('setChat', async (data:Message[]) => {
const db = getDatabase()
const selectedChar = get(selectedCharID)
let newChat:Message[] = []
for(const dat of data){
if(dat.role !== 'char' && dat.role !== 'user'){
return false
}
if(typeof dat.data !== 'string'){
return false
}
if(typeof dat.saying !== 'string' && dat.saying !== null && dat.saying !== undefined){
return false
}
if(typeof dat.time !== 'number' && dat.time !== null && dat.time !== undefined){
return false
}
if(typeof dat.chatId !== 'string' && dat.chatId !== null && dat.chatId !== undefined){
return false
}
newChat.push({
role: dat.role,
data: dat.data,
saying: dat.saying,
time: dat.time,
chatId: dat.chatId
})
}
db.characters[selectedChar].chats[db.characters[selectedChar].chatPage].message = newChat
setDatabase(db)
return true
})
addWorkerFunction('getName', async () => {
const db = getDatabase()
const selectedChar = get(selectedCharID)
const char = db.characters[selectedChar]
return char.name
})
addWorkerFunction('setName', async (data:string) => {
const db = getDatabase()
const selectedChar = get(selectedCharID)
if(typeof data !== 'string'){
return false
}
db.characters[selectedChar].name = data
setDatabase(db)
return true
})
addWorkerFunction('getDescription', async () => {
const db = getDatabase()
const selectedChar = get(selectedCharID)
const char = db.characters[selectedChar]
if(char.type === 'group'){
return ''
}
return char.desc
})
addWorkerFunction('setDescription', async (data:string) => {
const db = getDatabase()
const selectedChar = get(selectedCharID)
const char =db.characters[selectedChar]
if(typeof data !== 'string'){
return false
}
if(char.type === 'group'){
return false
}
char.desc = data
db.characters[selectedChar] = char
setDatabase(db)
return true
})
addWorkerFunction('getCharacterFirstMessage', async () => {
const db = getDatabase()
const selectedChar = get(selectedCharID)
const char = db.characters[selectedChar]
return char.firstMessage
})
addWorkerFunction('setCharacterFirstMessage', async (data:string) => {
const db = getDatabase()
const selectedChar = get(selectedCharID)
const char = db.characters[selectedChar]
if(typeof data !== 'string'){
return false
}
char.firstMessage = data
db.characters[selectedChar] = char
setDatabase(db)
return true
})
addWorkerFunction('getBackgroundEmbedding', async () => {
const db = getDatabase()
const selectedChar = get(selectedCharID)
const char = db.characters[selectedChar]
return char.backgroundHTML
})
addWorkerFunction('setBackgroundEmbedding', async (data:string) => {
const db = getDatabase()
const selectedChar = get(selectedCharID)
if(typeof data !== 'string'){
return false
}
db.characters[selectedChar].backgroundHTML = data
setDatabase(db)
return true
})
addWorkerFunction('getState', async (statename) => {
const db = getDatabase()
const selectedChar = get(selectedCharID)
const char = db.characters[selectedChar]
const chat = char.chats[char.chatPage]
return (chat.scriptstate ?? {})[statename]
})
addWorkerFunction('setState', async (statename, data) => {
const db = getDatabase()
const selectedChar = get(selectedCharID)
const char = db.characters[selectedChar]
const chat = char.chats[char.chatPage]
if(typeof statename !== 'string'){
return false
}
if(typeof data !== 'string' && typeof data !== 'number' && typeof data !== 'boolean'){
return false
}
if(typeof data === 'string' && data.length > 100000){
return false
}
if(!chat.scriptstate){
chat.scriptstate = {}
}
if(Object.keys(chat.scriptstate).length > 50){
return false
}
chat.scriptstate[statename] = data
char.chats[char.chatPage] = chat
db.characters[selectedChar] = char
setDatabase(db)
return true
})
let compCode:{[key:string]:string[]} = {}
export async function runCharacterJS(arg:{
code: string|null,
mode: ScriptMode|'onButtonClick'|'modifyRequestChat'
data: any
}):Promise<any>{
const perf = performance.now()
try {
arg.code = arg.code ?? ''
const codes = {
"editinput": 'editInput',
"editoutput": 'editOutput',
"editprocess": 'editProcess',
"editdisplay": 'editDisplay',
'onButtonClick': "onButtonClick",
'modifyRequestChat': 'modifyRequestChat'
} as const
let runCodes = [...additionalCharaJS, arg.code]
let r = arg.data
for(const code of runCodes){
if(!code){
continue
}
if(!compCode[code]){
let modeList:string[] = []
const codesplit = code.split('\n')
for(let i = 0; i < codesplit.length; i++){
const line = codesplit[i].trim()
if(line.startsWith('//@use')){
modeList.push(line.replace('//@use','').trim())
}
}
compCode[code] = modeList
// compcode length max 100
if(Object.keys(compCode).length > 100){
delete compCode[Object.keys(compCode)[50]]
}
}
const runCode = codes[arg.mode]
if(!compCode[code].includes(runCode)){
continue
}
const result = await runVirtualJS(`${code}\n${runCode}(${JSON.stringify(r)})`)
if(!result){
continue
}
if(arg.mode !== 'modifyRequestChat'){
if(typeof result !== 'string'){
continue
}
}
else{
if(!Array.isArray(result)){
continue
}
}
r = result
if(runCode === 'onButtonClick'){
return r
}
}
return r
} catch (error) {
if(arg.mode !== 'editprocess'){
return `Error: ${error}`
}
return arg.data
}
finally{
console.log('runCharacterJS',performance.now() - perf)
}
}

View File

@@ -1,202 +0,0 @@
let globaly = globalThis
const whitelist = [
"Array",
"ArrayBuffer",
"BigInt",
"BigInt64Array",
"BigUint64Array",
"Boolean",
"DataView",
"Date",
"Error",
"EvalError",
"Float32Array",
"Float64Array",
"Function",
"Infinity",
"Int16Array",
"Int32Array",
"Int8Array",
"JSON",
"Map",
"Math",
"NaN",
"Number",
"Object",
"Promise",
"Proxy",
"RangeError",
"ReferenceError",
"Reflect",
"RegExp",
"Set",
"SharedArrayBuffer",
"String",
"Symbol",
"SyntaxError",
"TypeError",
"URIError",
"Uint16Array",
"Uint32Array",
"Uint8Array",
"Uint8ClampedArray",
"WeakMap",
"WeakSet",
"console",
"decodeURI",
"decodeURIComponent",
"encodeURI",
"encodeURIComponent",
"escape",
"globalThis",
"isFinite",
"isNaN",
"null",
"parseFloat",
"parseInt",
"undefined",
"unescape",
"queueMicrotask",
"setTimeout",
"clearTimeout",
"setInterval",
"clearInterval",
"setImmediate",
"clearImmediate",
"atob",
"btoa",
"Headers",
"Request",
"Response",
"Blob",
"postMessage",
"Node",
"Element",
"Text",
"Comment",
'onmessage',
"DOMParser",
"XMLSerializer",
"TextEncoder",
"TextDecoder",
"AbortController",
"AbortSignal",
"Event",
"CustomEvent",
"EventTarget",
"OffscreenCanvas",
"ImageBitmap",
"ImageBitmapRenderingContext",
"createImageBitmap",
"OffScreenCanvasRenderingContext2D",
"WebGL2RenderingContext",
"WebGLRenderingContext",
]
const evaluation = globaly.eval
const propa = Object.getOwnPropertyNames( this ?? {} )
const prop = Object.getOwnPropertyNames( globaly ).concat( propa)
prop.push(
//unsafe apis
'open',
'close',
'alert',
'confirm',
'prompt',
'print',
'fetch',
'navigator',
'Worker',
'WebSocket',
'XMLHttpRequest',
'localStorage',
'sessionStorage',
'importScripts',
'indexedDB',
'crypto',
'WebAssembly',
'WebSqlDatabase',
)
prop.forEach( function( prop ) {
if( (!whitelist.includes(prop)) && (!prop.startsWith('HTML')) ) {
try {
Object.defineProperty( globaly, prop, {
get : function() {
throw "Security Exception: cannot access "+prop;
return 1;
},
configurable : false
});
} catch (error) {
}
try {
Object.defineProperty( this, prop, {
get : function() {
throw "Security Exception: cannot access "+prop;
return 1;
},
configurable : false
});
} catch (error) {
}
}
else{
}
});
let workerResults:{
id: string,
result: any
}[] = []
self.onmessage = async (event) => {
const da = event.data
if(da.type === 'result'){
workerResults.push(da)
return
}
if(da.type === 'api'){
//add api
Object.defineProperty( globaly, da.name, {
get : function() {
return function (...args:any[]) {
return new Promise((resolve)=>{
const functionCallID = `id${Math.random()}`.replace('.','')
self.postMessage({
type: 'api',
name: da.name,
id: functionCallID,
args
})
const interval = setInterval(()=>{
const result = workerResults.find(r=>r.id === functionCallID)
if(result){
clearInterval(interval)
resolve(result.result)
}
},10)
})
}
}
});
return
}
try{
const d = await evaluation(da.code)
self.postMessage({
id: da.id,
result: d
})
}
catch(e){
console.error(e)
self.postMessage({
id: da.id,
result: e
})
}
}

View File

@@ -1,12 +1,11 @@
import { get, writable } from "svelte/store";
import { language } from "../../lang";
import { alertError } from "../alert";
import { alertError, alertMd } from "../alert";
import { getCurrentCharacter, getDatabase, setDatabaseLite } from "../storage/database.svelte";
import { checkNullish, selectSingleFile, sleep } from "../util";
import type { OpenAIChat } from "../process/index.svelte";
import { fetchNative, globalFetch } from "../globalApi.svelte";
import { selectedCharID } from "../stores.svelte";
import { addAdditionalCharaJS } from "./embedscript";
import type { ScriptMode } from "../process/scripts";
export const customProviderStore = writable([] as string[])
@@ -33,40 +32,30 @@ export async function importPlugin(){
const jsFile = Buffer.from(f.data).toString('utf-8').replace(/^\uFEFF/gm, "");
const splitedJs = jsFile.split('\n')
let name = ''
let version:1|2 = 1
let displayName:string = undefined
let arg:{[key:string]:'int'|'string'|string[]} = {}
let realArg:{[key:string]:number|string} = {}
for(const line of splitedJs){
if(line.startsWith('//@risu-name')){
const provied = line.slice(13)
if(provied === ''){
alertError('plugin name must be longer than "", did you put it correctly?')
return
}
name = provied.trim()
alertMd('V1 plugin is not supported anymore, please use V2 plugin instead. for more information, please check the documentation. `https://github.com/kwaroran/RisuAI/blob/main/plugins.md`')
return
}
if(line.startsWith('//@risu-display-name')){
alertMd('V1 plugin is not supported anymore, please use V2 plugin instead. for more information, please check the documentation. `https://github.com/kwaroran/RisuAI/blob/main/plugins.md`')
return
}
if(line.startsWith('//@name')){
const provied = line.slice(7)
if(provied === ''){
alertError('plugin name must be longer than "", did you put it correctly?')
alertError('plugin name must be longer than 0, did you put it correctly?')
return
}
version = 2
name = provied.trim()
}
if(line.startsWith('//@risu-display-name')){
const provied = line.slice('//@risu-display-name'.length + 1)
if(provied === ''){
alertError('plugin display name must be longer than "", did you put it correctly?')
return
}
displayName = provied.trim()
}
if(line.startsWith('//@display-name')){
const provied = line.slice('//@display-name'.length + 1)
if(provied === ''){
alertError('plugin display name must be longer than "", did you put it correctly?')
alertError('plugin display name must be longer than 0, did you put it correctly?')
return
}
displayName = provied.trim()
@@ -105,7 +94,7 @@ export async function importPlugin(){
realArg: realArg,
arguments: arg,
displayName: displayName,
version: version
version: 2
}
db.plugins ??= []
@@ -119,174 +108,15 @@ export async function importPlugin(){
}
}
export function getCurrentPluginMax(prov:string){
return 12000
}
let pluginWorker:Worker = null
let providerRes:{success:boolean, content:string} = null
let translatorRes:{success:boolean, content:string} = null
function postMsgPluginWorker(type:string, body:any){
const bod = {
type: type,
body: body
}
pluginWorker.postMessage(bod)
}
let pluginTranslator = false
export async function loadPlugins() {
let db = getDatabase()
if(pluginWorker){
pluginWorker.terminate()
pluginWorker = null
}
const plugins = safeStructuredClone(db.plugins).filter((a:RisuPlugin) => a.version === 1)
const pluginV2 = safeStructuredClone(db.plugins).filter((a:RisuPlugin) => a.version === 2)
await loadV2Plugin(pluginV2)
if(plugins.length > 0){
const da = await fetch("/pluginApi.js")
const pluginApiString = await da.text()
let pluginjs = `${pluginApiString}\n`
let pluginLoadedJs = ''
for(const plug of db.plugins){
pluginLoadedJs += `\n(() => {${plug.script}})();\n`
}
pluginjs = pluginjs.replace('//{{placeholder}}',pluginLoadedJs)
const blob = new Blob([pluginjs], {type: 'application/javascript'});
pluginWorker = new Worker(URL.createObjectURL(blob));
pluginWorker.addEventListener('message', async (msg) => {
const data:{type:string,body:any} = msg.data
switch(data.type){
case "addProvider":{
let provs = get(customProviderStore)
provs.push(data.body)
customProviderStore.set(provs)
console.log(provs)
break
}
case "resProvider":{
const provres:{success:boolean, content:string} = data.body
if(checkNullish(provres.success) || checkNullish(provres.content)){
providerRes = {
success: false,
content :"provider didn't respond 'success' or 'content' in response object"
}
}
else if(typeof(provres.content) !== 'string'){
providerRes = {
success: false,
content :"provider didn't respond 'content' in response object in string"
}
}
else{
providerRes = {
success: !!provres.success,
content: provres.content
}
}
break
}
case "resTrans":{
const provres:{success:boolean, content:string} = data.body
if(checkNullish(provres.success) || checkNullish(provres.content)){
translatorRes = {
success: false,
content :"plugin didn't respond 'success' or 'content' in response object"
}
}
else if(typeof(provres.content) !== 'string'){
translatorRes = {
success: false,
content :"plugin didn't respond 'content' in response object in string"
}
}
else{
translatorRes = {
success: !!provres.success,
content: provres.content
}
}
break
}
case "useTranslator": {
pluginTranslator = true
break
}
case "fetch": {
postMsgPluginWorker('fetchData',{
id: data.body.id,
data: await globalFetch(data.body.url, data.body.arg)
})
break
}
case 'addCharaJs': {
let c:string = data.body.code
c.trim()
if(c.startsWith('{') && c.endsWith('}')){
c = c.slice(1, -1)
}
addAdditionalCharaJS(c, data.body.position)
break
}
case "getArg":{
try {
const db = getDatabase()
const arg:string[] = data.body.arg.split('::')
for(const plug of db.plugins){
if(arg[0] === plug.name){
postMsgPluginWorker('fetchData',{
id: data.body.id,
data: plug.realArg[arg[1]]
})
return
}
}
postMsgPluginWorker('fetchData',{
id: data.body.id,
data: null
})
} catch (error) {
postMsgPluginWorker('fetchData',{
id: data.body.id,
data: null
})
}
break
}
case "getChar":{
const db = getDatabase()
const charid = get(selectedCharID)
const char = db.characters[charid]
postMsgPluginWorker('fetchData',{
id: data.body.id,
data: char
})
break
}
case "setChar":{
const db = getDatabase()
const charid = get(selectedCharID)
db.characters[charid] = data.body
break
}
case "log":{
console.log(data.body)
break
}
}
})
}
}
type PluginV2ProviderArgument = {
@@ -424,30 +254,7 @@ export async function loadV2Plugin(plugins:RisuPlugin[]){
}
export async function translatorPlugin(text:string, from:string, to:string) {
if(!pluginTranslator){
return false
}
else{
try {
translatorRes = null
postMsgPluginWorker("requestTrans", {text, from, to})
while(true){
await sleep(50)
if(providerRes){
break
}
}
return {
success: translatorRes.success,
content: translatorRes.content
}
} catch (error) {
return {
success: false,
content: "unknownError"
}
}
}
return false
}
export async function pluginProcess(arg:{
@@ -458,35 +265,10 @@ export async function pluginProcess(arg:{
frequency_penalty: number
bias: {[key:string]:string}
}|{}){
try {
let db = getDatabase()
if(!pluginWorker){
return {
success: false,
content: "plugin worker not found error"
}
}
postMsgPluginWorker("requestProvider", {
key: db.currentPluginProvider,
arg: arg
})
providerRes = null
while(true){
await sleep(50)
if(providerRes){
break
}
}
return {
success: providerRes.success,
content: providerRes.content
}
} catch (error) {
return {
success: false,
content: "unknownError"
}
}
return {
success: false,
content: "Plugin V1 is not supported anymore, please use V2 plugin instead."
}
}

View File

@@ -22,7 +22,6 @@ import { getInlayAsset, supportsInlayImage } from "./files/inlays";
import { getGenerationModelString } from "./models/modelString";
import { connectionOpen, peerRevertChat, peerSafeCheck, peerSync } from "../sync/multiuser";
import { runInlayScreen } from "./inlayScreen";
import { runCharacterJS } from "../plugins/embedscript";
import { addRerolls } from "./prereroll";
import { runImageEmbedding } from "./transformers";
import { hanuraiMemory } from "./memory/hanuraiMemory";
@@ -30,7 +29,6 @@ import { hypaMemoryV2 } from "./memory/hypav2";
import { runLuaEditTrigger } from "./lua";
import { parseChatML } from "../parser.svelte";
import { getModelInfo, LLMFlags } from "../model/modellist";
import { pluginV2 } from "../plugins/plugins";
export interface OpenAIChat{
role: 'system'|'user'|'assistant'|'function'
@@ -1114,12 +1112,6 @@ export async function sendChat(chatProcessIndex = -1,arg:{
})
}
formated = await runCharacterJS({
code: null,
mode: 'modifyRequestChat',
data: formated
})
formated = await runLuaEditTrigger(currentChar, 'editRequest', formated)
//token rechecking

View File

@@ -6,7 +6,6 @@ import { alertError, alertNormal } from "../alert";
import { language } from "src/lang";
import { selectSingleFile } from "../util";
import { assetRegex, type CbsConditions, risuChatParser as risuChatParserOrg, type simpleCharacterArgument } from "../parser.svelte";
import { runCharacterJS } from "../plugins/embedscript";
import { getModuleAssets, getModuleRegexScripts } from "./modules";
import { HypaProcesser } from "./memory/hypamemory";
import { runLuaEditTrigger } from "./lua";
@@ -104,11 +103,6 @@ export async function processScriptFull(char:character|groupChat|simpleCharacter
}
let emoChanged = false
const scripts = (db.globalscript ?? []).concat(char.customscript).concat(getModuleRegexScripts())
data = await runCharacterJS({
code: char.virtualscript ?? null,
mode,
data,
})
data = await runLuaEditTrigger(char, mode, data)
if(pluginV2[mode].size > 0){
for(const plugin of pluginV2[mode]){