[feat] automark plugin
This commit is contained in:
56
src/ts/plugins/automark.ts
Normal file
56
src/ts/plugins/automark.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
const reg:[RegExp,string][] = []
|
||||
|
||||
|
||||
export function autoMarkPlugin(data:string){
|
||||
if(reg.length === 0){
|
||||
const pluginRegex = [
|
||||
{
|
||||
"in": "“|”",
|
||||
"out": "\"",
|
||||
"flag": "g"
|
||||
},
|
||||
{
|
||||
"in": "‘|’",
|
||||
"out": "'",
|
||||
"flag": "g"
|
||||
},
|
||||
{
|
||||
"in": "^(?!\\d\\.)([\\wㄱ-ㅎ가-힣'])(?!.*[{<>}])|(?<=^\\[.*\\] *|^\\(.*\\) *)([\\wㄱ-ㅎ가-힣'])(?!.*[{<>}])",
|
||||
"out": "<em>$1$2",
|
||||
"flag": "gm"
|
||||
},
|
||||
{
|
||||
"in": "(?<!^ +.*)(\".*|<em>.*)(?<!\")$",
|
||||
"out": "$1</em>",
|
||||
"flag": "gm"
|
||||
},
|
||||
{
|
||||
"in": "(?<=<em>.*|^\".*)( +\"[\\S])|(?<=<em>.*|\" +.*)( *\\[)",
|
||||
"out": "</em>$1$2",
|
||||
"flag": "gm"
|
||||
},
|
||||
{
|
||||
"in": "(?<=^\".*|<\\/em>.*)([\\S]\" +|[\\S]\"(?=[,.…ㄱ-ㅎ가-힣]))|(?<=<\\/em>.*)( *\\] *)",
|
||||
"out": "$1$2<em>",
|
||||
"flag": "gm"
|
||||
},
|
||||
{
|
||||
"in": "(?<=<em>.*? +|\\[|\\[.* +|\\(|\\(.* +|\"|\".*? +)(?<!style=.*)(')|(?<=<em>)('[\\wㄱ-ㅎ가-힣])",
|
||||
"out": "<strong><em>$1$2",
|
||||
"flag": "gm"
|
||||
},
|
||||
{
|
||||
"in": "(?<=<strong><em>')(.*?')(?= +.+?|[ㄱ-ㅎ가-힣?!:;,.…—-])|(?<=<strong><em>'.*)(')(?=<\\/em>|\")|(?<=\\(<strong><em>')(?=\\))",
|
||||
"out": "$1$2</em></strong>",
|
||||
"flag": "gm"
|
||||
}
|
||||
]
|
||||
for(const r of pluginRegex){
|
||||
reg.push([new RegExp(r.in, r.flag),r.out])
|
||||
}
|
||||
}
|
||||
for(let i=0;i<reg.length;i++){
|
||||
data = data.replace(reg[i][0], reg[i][1])
|
||||
}
|
||||
return data
|
||||
}
|
||||
322
src/ts/plugins/plugins.ts
Normal file
322
src/ts/plugins/plugins.ts
Normal file
@@ -0,0 +1,322 @@
|
||||
import { get, writable } from "svelte/store";
|
||||
import { language } from "../../lang";
|
||||
import { alertError } from "../alert";
|
||||
import { DataBase } from "../storage/database";
|
||||
import { checkNullish, selectSingleFile, sleep } from "../util";
|
||||
import type { OpenAIChat } from "../process";
|
||||
import { globalFetch } from "../storage/globalApi";
|
||||
import { selectedCharID } from "../stores";
|
||||
|
||||
export const customProviderStore = writable([] as string[])
|
||||
|
||||
interface PluginRequest{
|
||||
url: string
|
||||
header?:{[key:string]:string}
|
||||
body: any,
|
||||
res: string
|
||||
}
|
||||
|
||||
interface ProviderPlugin{
|
||||
name:string
|
||||
displayName?:string
|
||||
script:string
|
||||
arguments:{[key:string]:'int'|'string'|string[]}
|
||||
realArg:{[key:string]:number|string}
|
||||
}
|
||||
|
||||
export type RisuPlugin = ProviderPlugin
|
||||
|
||||
export async function importPlugin(){
|
||||
try {
|
||||
let db = get(DataBase)
|
||||
const f = await selectSingleFile(['js'])
|
||||
if(!f){
|
||||
return
|
||||
}
|
||||
const jsFile = Buffer.from(f.data).toString('utf-8').replace(/^\uFEFF/gm, "");
|
||||
const splitedJs = jsFile.split('\n')
|
||||
let name = ''
|
||||
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()
|
||||
}
|
||||
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
|
||||
}
|
||||
name = provied.trim()
|
||||
}
|
||||
if(line.startsWith('//@risu-arg')){
|
||||
const provied = line.trim().split(' ')
|
||||
if(provied.length < 3){
|
||||
alertError('plugin argument is incorrect, did you put space in argument name?')
|
||||
return
|
||||
}
|
||||
const provKey = provied[1]
|
||||
|
||||
if(provied[2] !== 'int' && provied[2] !== 'string'){
|
||||
alertError(`plugin argument type is "${provied[2]}", which is an unknown type.`)
|
||||
return
|
||||
}
|
||||
if(provied[2] === 'int'){
|
||||
arg[provKey] = 'int'
|
||||
realArg[provKey] = 0
|
||||
}
|
||||
else if(provied[2] === 'string'){
|
||||
arg[provKey] = 'string'
|
||||
realArg[provKey] = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(name.length === 0){
|
||||
alertError('plugin name not found, did you put it correctly?')
|
||||
return
|
||||
}
|
||||
|
||||
let pluginData:RisuPlugin = {
|
||||
name: name,
|
||||
script: jsFile,
|
||||
realArg: realArg,
|
||||
arguments: arg,
|
||||
displayName: displayName
|
||||
}
|
||||
|
||||
db.plugins.push(pluginData)
|
||||
|
||||
DataBase.set(db)
|
||||
loadPlugins()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
alertError(language.errors.noData)
|
||||
}
|
||||
}
|
||||
|
||||
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 = get(DataBase)
|
||||
if(pluginWorker){
|
||||
pluginWorker.terminate()
|
||||
pluginWorker = null
|
||||
}
|
||||
if(db.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
|
||||
}
|
||||
case "fetch": {
|
||||
postMsgPluginWorker('fetchData',{
|
||||
id: data.body.id,
|
||||
data: await globalFetch(data.body.url, data.body.arg)
|
||||
})
|
||||
break
|
||||
}
|
||||
case "getArg":{
|
||||
try {
|
||||
const db = get(DataBase)
|
||||
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 = get(DataBase)
|
||||
const charid = get(selectedCharID)
|
||||
const char = db.characters[charid]
|
||||
postMsgPluginWorker('fetchData',{
|
||||
id: data.body.id,
|
||||
data: char
|
||||
})
|
||||
}
|
||||
case "setChar":{
|
||||
const db = get(DataBase)
|
||||
const charid = get(selectedCharID)
|
||||
db.characters[charid] = data.body
|
||||
}
|
||||
case "log":{
|
||||
console.log(data.body)
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function pluginProcess(arg:{
|
||||
prompt_chat: OpenAIChat,
|
||||
temperature: number,
|
||||
max_tokens: number,
|
||||
presence_penalty: number
|
||||
frequency_penalty: number
|
||||
bias: {[key:string]:string}
|
||||
}|{}){
|
||||
try {
|
||||
let db = get(DataBase)
|
||||
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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user