Merge pull request #54 from VE-FORBRYDERNE/scripts
Upload some example scripts
This commit is contained in:
commit
b32e42cb67
|
@ -0,0 +1 @@
|
||||||
|
*.min.lua linguist-vendored
|
|
@ -13,7 +13,8 @@ miniconda3/*
|
||||||
__pycache__
|
__pycache__
|
||||||
*.log
|
*.log
|
||||||
cache/*
|
cache/*
|
||||||
userscripts/*
|
userscripts/*.*
|
||||||
|
!userscripts/kaipreset_*.lua
|
||||||
softprompts/*
|
softprompts/*
|
||||||
|
|
||||||
# Ignore PyCharm project files.
|
# Ignore PyCharm project files.
|
||||||
|
|
|
@ -615,7 +615,7 @@ return function(_python, _bridged)
|
||||||
if not check_validity(t) then
|
if not check_validity(t) then
|
||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
return #kobold.worldinfo
|
return _python.builtins.len(bridged.vars.wifolders_l)
|
||||||
end
|
end
|
||||||
|
|
||||||
KoboldWorldInfoFolderSelector_mt._kobold_next = KoboldWorldInfoEntry_mt._kobold_next
|
KoboldWorldInfoFolderSelector_mt._kobold_next = KoboldWorldInfoEntry_mt._kobold_next
|
||||||
|
|
|
@ -0,0 +1,257 @@
|
||||||
|
-- Basic phrase bias
|
||||||
|
-- Makes certain sequences of tokens more or less likely to appear than normal.
|
||||||
|
|
||||||
|
-- This file is part of KoboldAI.
|
||||||
|
--
|
||||||
|
-- KoboldAI is free software: you can redistribute it and/or modify
|
||||||
|
-- it under the terms of the GNU Affero General Public License as published by
|
||||||
|
-- the Free Software Foundation, either version 3 of the License, or
|
||||||
|
-- (at your option) any later version.
|
||||||
|
--
|
||||||
|
-- This program is distributed in the hope that it will be useful,
|
||||||
|
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
-- GNU Affero General Public License for more details.
|
||||||
|
--
|
||||||
|
-- You should have received a copy of the GNU Affero General Public License
|
||||||
|
-- along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
kobold = require("bridge")() -- This line is optional and is only for EmmyLua type annotations
|
||||||
|
local userscript = {} ---@class KoboldUserScript
|
||||||
|
|
||||||
|
|
||||||
|
---@class PhraseBiasEntry
|
||||||
|
---@field starting_bias number
|
||||||
|
---@field ending_bias number
|
||||||
|
---@field tokens table<integer, integer>
|
||||||
|
---@field n_tokens integer
|
||||||
|
|
||||||
|
local example_config = [[# Phrase bias
|
||||||
|
#
|
||||||
|
# For each phrase you want to bias, add a new line into
|
||||||
|
# this config file as a comma-separated list in this format:
|
||||||
|
# <starting bias>, <ending bias>, <comma-separated list of token IDs>
|
||||||
|
# For <starting bias> and <ending bias>, this script accepts floating point
|
||||||
|
# numbers or -inf, where positive bias values make it more likely for tokens
|
||||||
|
# to appear, negative bias values make it less likely and -inf makes it
|
||||||
|
# impossible.
|
||||||
|
#
|
||||||
|
# Example 1 (makes it impossible for the word "CHAPTER", case-sensitive, to
|
||||||
|
# appear at the beginning of a line in the output):
|
||||||
|
# -inf, -inf, 41481
|
||||||
|
#
|
||||||
|
# Example 2 (makes it unlikely for the word " CHAPTER", case-sensitive, with
|
||||||
|
# a leading space, to appear in the output, with the unlikeliness increasing
|
||||||
|
# even more if the first token " CH" has appeared):
|
||||||
|
# -10.0, -20.0, 5870, 29485
|
||||||
|
#
|
||||||
|
# Example 3 (makes it more likely for " let the voice of love take you higher",
|
||||||
|
# case-sensitive, with a leading space, to appear in the output, with the
|
||||||
|
# bias increasing as each consecutive token in that phrase appears):
|
||||||
|
# 7, 25.4, 1309, 262, 3809, 286, 1842, 1011, 345, 2440
|
||||||
|
#
|
||||||
|
]]
|
||||||
|
|
||||||
|
-- If config file is empty, write example config
|
||||||
|
local f = kobold.get_config_file()
|
||||||
|
f:seek("set")
|
||||||
|
if f:read(1) == nil then
|
||||||
|
f:write(example_config)
|
||||||
|
end
|
||||||
|
f:seek("set")
|
||||||
|
example_config = nil
|
||||||
|
|
||||||
|
-- Read config
|
||||||
|
print("Loading phrase bias config...")
|
||||||
|
local bias_array = {} ---@type table<integer, PhraseBiasEntry>
|
||||||
|
local bias_array_count = 0
|
||||||
|
local val_count = 0
|
||||||
|
local line_count = 0
|
||||||
|
local row = {} ---@type PhraseBiasEntry
|
||||||
|
local val_orig
|
||||||
|
for line in f:lines("l") do
|
||||||
|
line_count = line_count + 1
|
||||||
|
if line:find("^ *#") == nil and line:find("%S") ~= nil then
|
||||||
|
bias_array_count = bias_array_count + 1
|
||||||
|
val_count = 0
|
||||||
|
row = {}
|
||||||
|
row.tokens = {}
|
||||||
|
row.n_tokens = 0
|
||||||
|
for val in line:gmatch("[^,%s]+") do
|
||||||
|
val_count = val_count + 1
|
||||||
|
val_orig = val
|
||||||
|
if val_count <= 2 then
|
||||||
|
val = val:lower()
|
||||||
|
if val:sub(-3) == "inf" then
|
||||||
|
val = math.tointeger(val:sub(1, -4) .. "1")
|
||||||
|
if val ~= val or type(val) ~= "number" or val > 0 then
|
||||||
|
f:close()
|
||||||
|
error("First two values of line " .. line_count .. " of config file must be finite floating-point numbers or -inf, but got '" .. val_orig .. "' as value #" .. val_count)
|
||||||
|
end
|
||||||
|
val = val * math.huge
|
||||||
|
else
|
||||||
|
val = tonumber(val)
|
||||||
|
if val ~= val or type(val) ~= "number" then
|
||||||
|
f:close()
|
||||||
|
error("First two values of line " .. line_count .. " of config file must be finite floating-point numbers or -inf, but got '" .. val_orig .. "' as value #" .. val_count)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if val_count == 1 then
|
||||||
|
row.starting_bias = val
|
||||||
|
else
|
||||||
|
row.ending_bias = val
|
||||||
|
end
|
||||||
|
else
|
||||||
|
val = math.tointeger(val)
|
||||||
|
if type(val) ~= "number" or val < 0 then
|
||||||
|
f:close()
|
||||||
|
error("All values after the first two values of line " .. line_count .. " of config file must be nonnegative integers, but got '" .. val_orig .. "' as value #" .. val_count)
|
||||||
|
end
|
||||||
|
row.n_tokens = row.n_tokens + 1
|
||||||
|
row.tokens[row.n_tokens] = val
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if val_count < 3 then
|
||||||
|
f:close()
|
||||||
|
error("Line " .. line_count .. " of config file must contain at least 3 values, but found " .. val_count)
|
||||||
|
end
|
||||||
|
bias_array[bias_array_count] = row
|
||||||
|
end
|
||||||
|
end
|
||||||
|
f:close()
|
||||||
|
print("Successfully loaded " .. bias_array_count .. " phrase bias entr" .. (bias_array_count == 1 and "y" or "ies") .. ".")
|
||||||
|
|
||||||
|
|
||||||
|
local genmod_run = false
|
||||||
|
|
||||||
|
---@param starting_val number
|
||||||
|
---@param ending_val number
|
||||||
|
---@param factor number
|
||||||
|
---@return number
|
||||||
|
local function logit_interpolate(starting_val, ending_val, factor)
|
||||||
|
-- First use the logistic function on the start and end values
|
||||||
|
starting_val = 1/(1 + math.exp(-starting_val))
|
||||||
|
ending_val = 1/(1 + math.exp(-ending_val))
|
||||||
|
|
||||||
|
-- Use linear interpolation between these two values
|
||||||
|
local val = starting_val + factor*(ending_val - starting_val)
|
||||||
|
|
||||||
|
-- Return logit of this value
|
||||||
|
return math.log(val/(1 - val))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function userscript.genmod()
|
||||||
|
genmod_run = true
|
||||||
|
|
||||||
|
local context_tokens = kobold.encode(kobold.worldinfo:compute_context(kobold.submission))
|
||||||
|
local factor ---@type number
|
||||||
|
local next_token ---@type integer
|
||||||
|
local sequences = {} ---@type table<integer, table<integer, integer>>
|
||||||
|
local n_tokens = 0
|
||||||
|
local max_overlap = {} ---@type table<integer, integer>
|
||||||
|
|
||||||
|
local biased_tokens = {} ---@type table<integer, table<integer, boolean>>
|
||||||
|
for i = 1, kobold.generated_rows do
|
||||||
|
biased_tokens[i] = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- For each partially-generated sequence...
|
||||||
|
for i, generated_row in ipairs(kobold.generated) do
|
||||||
|
|
||||||
|
-- Build an array `tokens` as the concatenation of the context
|
||||||
|
-- tokens and the generated tokens of this sequence
|
||||||
|
|
||||||
|
local tokens = {}
|
||||||
|
n_tokens = 0
|
||||||
|
for k, v in ipairs(context_tokens) do
|
||||||
|
n_tokens = n_tokens + 1
|
||||||
|
tokens[n_tokens] = v
|
||||||
|
end
|
||||||
|
for k, v in ipairs(generated_row) do
|
||||||
|
n_tokens = n_tokens + 1
|
||||||
|
tokens[n_tokens] = v
|
||||||
|
end
|
||||||
|
|
||||||
|
-- For each phrase bias entry in the config file...
|
||||||
|
for _, bias_entry in ipairs(bias_array) do
|
||||||
|
|
||||||
|
-- Determine the largest integer `max_overlap[i]` such that the last
|
||||||
|
-- `max_overlap[i]` elements of `tokens` equal the first
|
||||||
|
-- `max_overlap[i]` elements of `bias_entry.tokens`
|
||||||
|
|
||||||
|
max_overlap[i] = 0
|
||||||
|
local s = {}
|
||||||
|
local z = {[0] = 0}
|
||||||
|
local l = 1
|
||||||
|
local r = 1
|
||||||
|
local n_s = math.min(n_tokens, bias_entry.n_tokens)
|
||||||
|
local j = 0
|
||||||
|
for k = 1, n_s do
|
||||||
|
s[j] = bias_entry.tokens[k]
|
||||||
|
j = j + 1
|
||||||
|
end
|
||||||
|
for k = n_tokens - n_s + 1, n_tokens do
|
||||||
|
s[j] = tokens[k]
|
||||||
|
j = j + 1
|
||||||
|
end
|
||||||
|
for k = 1, (n_s<<1) - 1 do
|
||||||
|
if k <= r and z[k - l] - 1 < r - k then
|
||||||
|
z[k] = z[k - l]
|
||||||
|
else
|
||||||
|
l = k
|
||||||
|
if k > r then
|
||||||
|
r = k
|
||||||
|
end
|
||||||
|
while r < (n_s<<1) and s[r - l] == s[r] do
|
||||||
|
r = r + 1
|
||||||
|
end
|
||||||
|
z[k] = r - l
|
||||||
|
r = r - 1
|
||||||
|
end
|
||||||
|
if z[k] <= n_s and z[k] == (n_s<<1) - k then
|
||||||
|
max_overlap[i] = z[k]
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- For each phrase bias entry in the config file...
|
||||||
|
for _, bias_entry in ipairs(bias_array) do
|
||||||
|
|
||||||
|
-- For each partially-generated sequence...
|
||||||
|
for i, generated_row in ipairs(kobold.generated) do
|
||||||
|
|
||||||
|
-- Use `max_overlap` to determine which token in the bias entry to
|
||||||
|
-- apply bias to
|
||||||
|
|
||||||
|
if max_overlap[i] == 0 or max_overlap[i] == bias_entry.n_tokens then
|
||||||
|
if bias_entry.tokens[2] == nil then
|
||||||
|
factor = 1
|
||||||
|
else
|
||||||
|
factor = 0
|
||||||
|
end
|
||||||
|
next_token = bias_entry.tokens[1]
|
||||||
|
else
|
||||||
|
factor = max_overlap[i]/(bias_entry.n_tokens - 1)
|
||||||
|
next_token = bias_entry.tokens[max_overlap[i]+1]
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Apply bias
|
||||||
|
|
||||||
|
if not biased_tokens[i][next_token] then
|
||||||
|
kobold.logits[i][next_token + 1] = kobold.logits[i][next_token + 1] + logit_interpolate(bias_entry.starting_bias, bias_entry.ending_bias, factor)
|
||||||
|
biased_tokens[i][next_token] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function userscript.outmod()
|
||||||
|
if not genmod_run then
|
||||||
|
warn("WARNING: Generation modifier was not executed, so this script has had no effect")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return userscript
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,208 @@
|
||||||
|
-- Location scanner
|
||||||
|
-- Activates world info entries based on what the AI thinks the current location
|
||||||
|
-- is.
|
||||||
|
|
||||||
|
-- This file is part of KoboldAI.
|
||||||
|
--
|
||||||
|
-- KoboldAI is free software: you can redistribute it and/or modify
|
||||||
|
-- it under the terms of the GNU Affero General Public License as published by
|
||||||
|
-- the Free Software Foundation, either version 3 of the License, or
|
||||||
|
-- (at your option) any later version.
|
||||||
|
--
|
||||||
|
-- This program is distributed in the hope that it will be useful,
|
||||||
|
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
-- GNU Affero General Public License for more details.
|
||||||
|
--
|
||||||
|
-- You should have received a copy of the GNU Affero General Public License
|
||||||
|
-- along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
kobold = require("bridge")() -- This line is optional and is only for EmmyLua type annotations
|
||||||
|
local userscript = {} ---@class KoboldUserScript
|
||||||
|
|
||||||
|
|
||||||
|
local example_config = [[;-- Location scanner
|
||||||
|
;--
|
||||||
|
;-- Usage instructions:
|
||||||
|
;--
|
||||||
|
;-- 1. Create a world info folder with name containing the string
|
||||||
|
;-- "<||ls||>" (without the double quotes). The comment can be anything as
|
||||||
|
;-- long as it contains that inside it somewhere -- for example, you could
|
||||||
|
;-- set the name to "Locations <||ls||>".
|
||||||
|
;--
|
||||||
|
;-- 2. Create a non-selective, constant world info key _in that folder_ with key
|
||||||
|
;-- "<||lslocation||>" (without the double quotes). Every once in a while,
|
||||||
|
;-- this script will generate 20 tokens using "The current location"
|
||||||
|
;-- as the submission and save the output into the <||lslocation||> entry.
|
||||||
|
;--
|
||||||
|
;-- 3. Put some other world info entries into the world info folder. These
|
||||||
|
;-- entries will _only_ be triggered by the contents of the <||lslocation||>
|
||||||
|
;-- entry and not by your story itself, or if it has constant key turned on.
|
||||||
|
;--
|
||||||
|
;-- You can edit some of the configuration values below to modify some of this
|
||||||
|
;-- behaviour:
|
||||||
|
;--
|
||||||
|
return {
|
||||||
|
location_folder = "<||ls||>",
|
||||||
|
location_key = "<||lslocation||>",
|
||||||
|
submission = "\n\nThe current location:",
|
||||||
|
n_wait = 12, -- The script will run its extra generation every time your story grows by this many chunks.
|
||||||
|
n_tokens = 20, -- Number of tokens to generate in extra generation
|
||||||
|
singleline = true, -- true or false; true will result in the extra generation's output being cut off after the first line.
|
||||||
|
trim = true, -- true or false; true will result in the extra generation's output being cut off after the end of its last sentence.
|
||||||
|
}
|
||||||
|
]]
|
||||||
|
|
||||||
|
local cfg ---@type table<string, any>
|
||||||
|
do
|
||||||
|
-- If config file is empty, write example config
|
||||||
|
local f <close> = kobold.get_config_file()
|
||||||
|
f:seek("set")
|
||||||
|
if f:read(1) == nil then
|
||||||
|
f:write(example_config)
|
||||||
|
end
|
||||||
|
f:seek("set")
|
||||||
|
example_config = nil
|
||||||
|
|
||||||
|
-- Read config
|
||||||
|
local err
|
||||||
|
cfg, err = load(f:read("a"))
|
||||||
|
if err ~= nil then
|
||||||
|
error(err)
|
||||||
|
end
|
||||||
|
cfg = cfg()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local folder ---@type KoboldWorldInfoFolder|nil
|
||||||
|
local entry ---@type KoboldWorldInfoEntry|nil
|
||||||
|
local location = ""
|
||||||
|
local orig_entry_map = {} ---@type table<integer, KoboldWorldInfoEntry>
|
||||||
|
local repeated = false
|
||||||
|
local last_quotient = math.huge
|
||||||
|
|
||||||
|
local genamt = 0
|
||||||
|
|
||||||
|
function userscript.inmod()
|
||||||
|
if repeated then
|
||||||
|
kobold.submission = cfg.submission
|
||||||
|
genamt = kobold.settings.genamt
|
||||||
|
kobold.settings.genamt = cfg.n_tokens
|
||||||
|
end
|
||||||
|
|
||||||
|
if entry == nil or folder == nil or not entry:is_valid() or not folder:is_valid() then
|
||||||
|
folder = nil
|
||||||
|
entry = nil
|
||||||
|
for i, f in ipairs(kobold.worldinfo.folders) do
|
||||||
|
if f.name:find(cfg.location_folder, 1, true) ~= nil then
|
||||||
|
folder = f
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if folder ~= nil then
|
||||||
|
for i, e in ipairs(folder) do
|
||||||
|
if e.key:find(cfg.location_key, 1, true) ~= nil then
|
||||||
|
entry = e
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
orig_entry_map = {}
|
||||||
|
|
||||||
|
if entry ~= nil then
|
||||||
|
location = entry.content
|
||||||
|
entry.constant = false
|
||||||
|
end
|
||||||
|
|
||||||
|
if folder ~= nil then
|
||||||
|
for i, e in ipairs(folder) do
|
||||||
|
if entry == nil or e.uid ~= entry.uid then
|
||||||
|
orig_entry_map[e.uid] = {
|
||||||
|
constant = e.constant,
|
||||||
|
key = e.key,
|
||||||
|
keysecondary = e.keysecondary,
|
||||||
|
}
|
||||||
|
e.constant = e.constant or (not repeated and e:compute_context("") ~= e:compute_context(location))
|
||||||
|
e.key = ""
|
||||||
|
e.keysecondary = ""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function userscript.outmod()
|
||||||
|
if entry ~= nil and entry:is_valid() then
|
||||||
|
entry.constant = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if repeated then
|
||||||
|
local output = kobold.outputs[1]
|
||||||
|
kobold.outputs[1] = ""
|
||||||
|
|
||||||
|
output = output:match("^%s*(.*)%s*$")
|
||||||
|
|
||||||
|
print("Extra generation result (prior to formatting): " .. output)
|
||||||
|
|
||||||
|
if cfg.singleline then
|
||||||
|
output = output:match("^[^\n]*")
|
||||||
|
end
|
||||||
|
|
||||||
|
if cfg.trim then
|
||||||
|
local i = 0
|
||||||
|
while true do
|
||||||
|
local j = output:find("[.?!)]", i + 1)
|
||||||
|
if j == nil then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
i = j
|
||||||
|
end
|
||||||
|
if i > 0 then
|
||||||
|
if output:sub(i+1, i+1) == '"' then
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
output = output:sub(1, i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
location = output
|
||||||
|
if entry ~= nil and entry:is_valid() then
|
||||||
|
entry.content = output
|
||||||
|
end
|
||||||
|
|
||||||
|
kobold.settings.genamt = genamt
|
||||||
|
|
||||||
|
for chunk in kobold.story:reverse_iter() do
|
||||||
|
if chunk.content ~= "" then
|
||||||
|
chunk.content = ""
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
print("Extra generation result (after formatting): " .. output)
|
||||||
|
end
|
||||||
|
|
||||||
|
local size = 0
|
||||||
|
for _ in kobold.story:forward_iter() do
|
||||||
|
size = size + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
for uid, orig in pairs(orig_entry_map) do
|
||||||
|
for k, v in pairs(orig) do
|
||||||
|
kobold.worldinfo:finduid(uid)[k] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local quotient = math.floor(size / cfg.n_wait)
|
||||||
|
if repeated then
|
||||||
|
repeated = false
|
||||||
|
elseif quotient > last_quotient then
|
||||||
|
print("Running extra generation")
|
||||||
|
kobold.restart_generation()
|
||||||
|
repeated = true
|
||||||
|
end
|
||||||
|
last_quotient = quotient
|
||||||
|
end
|
||||||
|
|
||||||
|
return userscript
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* This file is part of KoboldAI.
|
||||||
|
*
|
||||||
|
* KoboldAI is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import lua.Table;
|
||||||
|
|
||||||
|
extern class KoboldLib {
|
||||||
|
@:luaDotMethod public function get_config_file(?clear:Bool):lua.FileHandle;
|
||||||
|
@:luaDotMethod public function halt_generation():Void;
|
||||||
|
@:luaDotMethod public function restart_generation(?sequence:Int):Void;
|
||||||
|
public var outputs:Null<Table<Int, String>>;
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
* This file is part of KoboldAI.
|
||||||
|
*
|
||||||
|
* KoboldAI is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import haxe.exceptions.PosException;
|
||||||
|
import lua.Lua;
|
||||||
|
|
||||||
|
@:expose class Main {
|
||||||
|
public static final kobold:KoboldLib = untyped __lua__("_G.kobold");
|
||||||
|
public static final exampleConfig = "return true";
|
||||||
|
|
||||||
|
public static var shouldRun:Bool;
|
||||||
|
|
||||||
|
public static var f:BigInt = -2;
|
||||||
|
public static var e:BigInt = 4;
|
||||||
|
public static var s:BigInt = 8;
|
||||||
|
public static var t:BigInt = 1;
|
||||||
|
public static var i:BigInt = 0;
|
||||||
|
public static var v:BigInt = 1;
|
||||||
|
public static var a:BigInt = 6;
|
||||||
|
public static var l:BigInt = 1;
|
||||||
|
|
||||||
|
public static function inmod() {
|
||||||
|
if (!shouldRun) return;
|
||||||
|
kobold.halt_generation();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function outmod() {
|
||||||
|
if (!shouldRun) return;
|
||||||
|
|
||||||
|
// Gibbons, Jeremy. (2004). Unbounded Spigot Algorithms for the Digits
|
||||||
|
// of Pi. American Mathematical Monthly. 113. 10.2307/27641917.
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
var x = i/v;
|
||||||
|
if (x == (i + t)/v) {
|
||||||
|
trace(x);
|
||||||
|
kobold.outputs[1] = Std.string(x);
|
||||||
|
t *= 10;
|
||||||
|
i -= x*v;
|
||||||
|
i *= 10;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
v *= s*a;
|
||||||
|
i *= s;
|
||||||
|
s += 8;
|
||||||
|
i += e * t;
|
||||||
|
e += 4;
|
||||||
|
i *= a;
|
||||||
|
a += 4;
|
||||||
|
t *= f*l;
|
||||||
|
l += 2;
|
||||||
|
f -= 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kobold.restart_generation(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function main() {
|
||||||
|
var f = kobold.get_config_file();
|
||||||
|
f.seek("set");
|
||||||
|
if (f.read(1) == null) f.write(exampleConfig);
|
||||||
|
f.seek("set");
|
||||||
|
|
||||||
|
var a = f.read("a");
|
||||||
|
f.close();
|
||||||
|
var result = Lua.load(a);
|
||||||
|
trace(result);
|
||||||
|
if (result.message != null) throw new PosException(result.message);
|
||||||
|
shouldRun = switch result.func() {
|
||||||
|
case false: false;
|
||||||
|
case null: false;
|
||||||
|
default: true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Installing dependencies:
|
||||||
|
|
||||||
|
* Install [Haxe](https://haxe.org/) 4 and Haxelib. Add them to your PATH. The specific version of Haxe used for this compilation was 4.2.4.
|
||||||
|
|
||||||
|
* Install the Haxelib package [littleBigInt](https://github.com/maitag/littleBigInt), version 0.1.3:
|
||||||
|
```
|
||||||
|
haxelib install littleBigInt 0.1.3
|
||||||
|
```
|
||||||
|
|
||||||
|
* Install [Node.js](https://nodejs.org/).
|
||||||
|
|
||||||
|
* Install https://github.com/FATH-Mechatronics/luamin/tree/d7359250cf28ab617ba5e43d1fda6ec411b1f9f7 using npm:
|
||||||
|
```
|
||||||
|
npm install FATH-Mechatronics/luamin#d7359250cf28ab617ba5e43d1fda6ec411b1f9f7
|
||||||
|
```
|
||||||
|
|
||||||
|
# Compilation:
|
||||||
|
|
||||||
|
* Run build.sh if you're running Linux or build.bat if you're running Windows.
|
||||||
|
|
||||||
|
* Use Node.js to run min.js:
|
||||||
|
```
|
||||||
|
node min.js
|
||||||
|
```
|
|
@ -0,0 +1,16 @@
|
||||||
|
:: This file is part of KoboldAI.
|
||||||
|
::
|
||||||
|
:: KoboldAI is free software: you can redistribute it and/or modify
|
||||||
|
:: it under the terms of the GNU Affero General Public License as published by
|
||||||
|
:: the Free Software Foundation, either version 3 of the License, or
|
||||||
|
:: (at your option) any later version.
|
||||||
|
::
|
||||||
|
:: This program is distributed in the hope that it will be useful,
|
||||||
|
:: but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
:: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
:: GNU Affero General Public License for more details.
|
||||||
|
::
|
||||||
|
:: You should have received a copy of the GNU Affero General Public License
|
||||||
|
:: along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
@powershell ./build.ps1 %1
|
|
@ -0,0 +1,21 @@
|
||||||
|
# This file is part of KoboldAI.
|
||||||
|
#
|
||||||
|
# KoboldAI is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
$path = "out.lua"
|
||||||
|
if ($args[0].length -gt 0) {
|
||||||
|
$path = $args[0]
|
||||||
|
}
|
||||||
|
haxe --lua $path -L littleBigInt --main Main
|
||||||
|
if (-not $?) { exit 1 }
|
||||||
|
(Get-Content $path).replace('_G.require("rex_pcre")', '({flags = function() return {CASELESS = 1, DOTALL = 1, MULTILINE = 1, UCP = 1, UTF8 = 1} end, gsub = function() return "" end, new = function() return {} end})').replace("return _hx_exports", "return _hx_exports.Main").replace(" _hx_bit_raw = _G.require('bit32')", " _hx_bit_raw = {arshift = function(x, n) local y = x >> n; if (x < 0) then y = y | ~(-1 >> n) end return y end, band = function(x, y) return x & y end, bor = function(x, y) return x | y end, bnot = function(x) return ~x end, bxor = function(x, y) return x ~ y end, lshift = function(x, n) return x << n end, rshift = function(x, n) return x >> n end}").replace('__lua_lib_luautf8_Utf8 = _G.require("lua-utf8")', "__lua_lib_luautf8_Utf8 = {byte = _G.string.byte, find = _G.string.find, gmatch = _G.string.gmatch, gsub = _G.string.gsub, lower = _G.string.lower, match = _G.string.match, reverse = _G.string.reverse, sub = _G.string.sub, upper = _G.string.upper}; for k, v in pairs(_G.utf8) do __lua_lib_luautf8_Utf8[k] = v end;").replace("_G.xpcall(Main.main, _hx_error)", 'local err; if not xpcall(Main.main, function(obj) err = ""; local _print = _G.print; _G.print = function(...) local args = table.pack(...) for i = 1, args.n do args[i] = tostring(args[i]) end err = err .. table.concat(args, "\t") .. "\n" end _hx_error(obj); _G.print = _print end) then _G.error(err) return end;') | Set-Content $path
|
|
@ -0,0 +1,27 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# This file is part of KoboldAI.
|
||||||
|
#
|
||||||
|
# KoboldAI is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
set -e
|
||||||
|
path=$1
|
||||||
|
if [ $# -eq 0 ]
|
||||||
|
then
|
||||||
|
path="out.lua"
|
||||||
|
fi
|
||||||
|
haxe --lua $path -L littleBigInt --main Main
|
||||||
|
perl -pe 's/\Q_G.require("rex_pcre")/\E({flags = function() return {CASELESS = 1, DOTALL = 1, MULTILINE = 1, UCP = 1, UTF8 = 1} end, gsub = function() return "" end, new = function() return {} end})/' -i $path
|
||||||
|
perl -pe 's/\Qreturn _hx_exports/\Ereturn _hx_exports.Main/' -i $path
|
||||||
|
perl -pe "s/\Q _hx_bit_raw = _G.require('bit32')/\E _hx_bit_raw = {arshift = function(x, n) local y = x >> n; if (x < 0) then y = y | ~(-1 >> n) end return y end, band = function(x, y) return x & y end, bor = function(x, y) return x | y end, bnot = function(x) return ~x end, bxor = function(x, y) return x ~ y end, lshift = function(x, n) return x << n end, rshift = function(x, n) return x >> n end}/" -i $path
|
||||||
|
perl -pe 's/\Q__lua_lib_luautf8_Utf8 = _G.require("lua-utf8")/\E__lua_lib_luautf8_Utf8 = {byte = _G.string.byte, find = _G.string.find, gmatch = _G.string.gmatch, gsub = _G.string.gsub, lower = _G.string.lower, match = _G.string.match, reverse = _G.string.reverse, sub = _G.string.sub, upper = _G.string.upper}; for k, v in pairs(_G.utf8) do __lua_lib_luautf8_Utf8[k] = v end;/' -i $path
|
||||||
|
perl -pe 's/\Q_G.xpcall(Main.main, _hx_error)/\Elocal err; if not xpcall(Main.main, function(obj) err = ""; local _print = _G.print; _G.print = function(...) local args = table.pack(...) for i = 1, args.n do args[i] = tostring(args[i]) end err = err .. table.concat(args, "\\t") .. "\\n" end _hx_error(obj); _G.print = _print end) then _G.error(err) return end;/' -i $path
|
|
@ -0,0 +1,54 @@
|
||||||
|
const fs = require("fs");
|
||||||
|
const luamin = require("luamin");
|
||||||
|
|
||||||
|
const in_path = "out.lua";
|
||||||
|
const out_path = "out.min.lua";
|
||||||
|
|
||||||
|
var data = fs.readFileSync(in_path, "utf8");
|
||||||
|
data = luamin.minify(data);
|
||||||
|
data = '-- Haxe transcendental test\n\
|
||||||
|
-- This is a script written in Haxe that prints the natural logarithm of the\n\
|
||||||
|
-- golden ratio in base 10 to arbitrarily many digits.\n\
|
||||||
|
\n\
|
||||||
|
-- This file is part of KoboldAI.\n\
|
||||||
|
--\n\
|
||||||
|
-- KoboldAI is free software: you can redistribute it and/or modify\n\
|
||||||
|
-- it under the terms of the GNU Affero General Public License as published by\n\
|
||||||
|
-- the Free Software Foundation, either version 3 of the License, or\n\
|
||||||
|
-- (at your option) any later version.\n\
|
||||||
|
--\n\
|
||||||
|
-- This program is distributed in the hope that it will be useful,\n\
|
||||||
|
-- but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
|
||||||
|
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\
|
||||||
|
-- GNU Affero General Public License for more details.\n\
|
||||||
|
--\n\
|
||||||
|
-- You should have received a copy of the GNU Affero General Public License\n\
|
||||||
|
-- along with this program. If not, see <https://www.gnu.org/licenses/>.\n\
|
||||||
|
\n\
|
||||||
|
--------------------------------------------------------------------------------\n\
|
||||||
|
\n\
|
||||||
|
-- License for littleBigInt:\n\
|
||||||
|
\n\
|
||||||
|
-- MIT License\n\
|
||||||
|
--\n\
|
||||||
|
-- Copyright (c) 2020 Sylvio Sell\n\
|
||||||
|
--\n\
|
||||||
|
-- Permission is hereby granted, free of charge, to any person obtaining a copy\n\
|
||||||
|
-- of this software and associated documentation files (the "Software"), to deal\n\
|
||||||
|
-- in the Software without restriction, including without limitation the rights\n\
|
||||||
|
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n\
|
||||||
|
-- copies of the Software, and to permit persons to whom the Software is\n\
|
||||||
|
-- furnished to do so, subject to the following conditions:\n\
|
||||||
|
--\n\
|
||||||
|
-- The above copyright notice and this permission notice shall be included in all\n\
|
||||||
|
-- copies or substantial portions of the Software.\n\
|
||||||
|
--\n\
|
||||||
|
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n\
|
||||||
|
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n\
|
||||||
|
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n\
|
||||||
|
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n\
|
||||||
|
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n\
|
||||||
|
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n\
|
||||||
|
-- SOFTWARE.\n\
|
||||||
|
\n' + data + "\n";
|
||||||
|
fs.writeFileSync(out_path, data);
|
|
@ -0,0 +1,65 @@
|
||||||
|
-- Word substitution
|
||||||
|
-- Performs a search-and-replace on the AI's output.
|
||||||
|
|
||||||
|
-- This file is part of KoboldAI.
|
||||||
|
--
|
||||||
|
-- KoboldAI is free software: you can redistribute it and/or modify
|
||||||
|
-- it under the terms of the GNU Affero General Public License as published by
|
||||||
|
-- the Free Software Foundation, either version 3 of the License, or
|
||||||
|
-- (at your option) any later version.
|
||||||
|
--
|
||||||
|
-- This program is distributed in the hope that it will be useful,
|
||||||
|
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
-- GNU Affero General Public License for more details.
|
||||||
|
--
|
||||||
|
-- You should have received a copy of the GNU Affero General Public License
|
||||||
|
-- along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
kobold = require("bridge")() -- This line is optional and is only for EmmyLua type annotations
|
||||||
|
local userscript = {} ---@class KoboldUserScript
|
||||||
|
|
||||||
|
|
||||||
|
local example_config = [[;-- Substitution
|
||||||
|
;--
|
||||||
|
;-- This example config causes all occurrences of "Hello," (without the double
|
||||||
|
;-- quotes) to be replaced with "Goodbye," (without the double quotes) and
|
||||||
|
;-- all occurrences of "test" to be replaced with "****".
|
||||||
|
;--
|
||||||
|
;-- The strings are parsed as Lua strings, so the standard escape sequences \",
|
||||||
|
;-- \n, \\, and so on apply here as well.
|
||||||
|
;--
|
||||||
|
return {
|
||||||
|
{"Hello,", "Goodbye,"},
|
||||||
|
{"test", "****"},
|
||||||
|
}
|
||||||
|
]]
|
||||||
|
|
||||||
|
-- If config file is empty, write example config
|
||||||
|
local f = kobold.get_config_file()
|
||||||
|
f:seek("set")
|
||||||
|
if f:read(1) == nil then
|
||||||
|
f:write(example_config)
|
||||||
|
end
|
||||||
|
f:seek("set")
|
||||||
|
example_config = nil
|
||||||
|
|
||||||
|
-- Read config
|
||||||
|
local cfg, err = load(f:read("a"))
|
||||||
|
f:close()
|
||||||
|
if err ~= nil then
|
||||||
|
error(err)
|
||||||
|
end
|
||||||
|
cfg = cfg()
|
||||||
|
|
||||||
|
|
||||||
|
function userscript.outmod()
|
||||||
|
for i, output in ipairs(kobold.outputs) do
|
||||||
|
for j, row in ipairs(cfg) do
|
||||||
|
output = output:gsub(row[1], row[2])
|
||||||
|
end
|
||||||
|
kobold.outputs[i] = output
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return userscript
|
|
@ -0,0 +1,108 @@
|
||||||
|
-- You bias
|
||||||
|
-- Makes the word "You" more or less common, optionally only if not between
|
||||||
|
-- double quotes.
|
||||||
|
-- Only works with models with a tokenizer based on GPT-2, such as GPT-2,
|
||||||
|
-- GPT-Neo and GPT-J.
|
||||||
|
|
||||||
|
-- This file is part of KoboldAI.
|
||||||
|
--
|
||||||
|
-- KoboldAI is free software: you can redistribute it and/or modify
|
||||||
|
-- it under the terms of the GNU Affero General Public License as published by
|
||||||
|
-- the Free Software Foundation, either version 3 of the License, or
|
||||||
|
-- (at your option) any later version.
|
||||||
|
--
|
||||||
|
-- This program is distributed in the hope that it will be useful,
|
||||||
|
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
-- GNU Affero General Public License for more details.
|
||||||
|
--
|
||||||
|
-- You should have received a copy of the GNU Affero General Public License
|
||||||
|
-- along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
kobold = require("bridge")() -- This line is optional and is only for EmmyLua type annotations
|
||||||
|
local userscript = {} ---@class KoboldUserScript
|
||||||
|
|
||||||
|
|
||||||
|
local example_config = [[;-- You bias
|
||||||
|
;--
|
||||||
|
return {
|
||||||
|
bias = -7.0, -- Negative numbers make it less likely, positive numbers more, and -math.huge impossible
|
||||||
|
only_if_outside_double_quotes = true,
|
||||||
|
}
|
||||||
|
]]
|
||||||
|
|
||||||
|
-- If config file is empty, write example config
|
||||||
|
local f = kobold.get_config_file()
|
||||||
|
f:seek("set")
|
||||||
|
if f:read(1) == nil then
|
||||||
|
f:write(example_config)
|
||||||
|
end
|
||||||
|
f:seek("set")
|
||||||
|
example_config = nil
|
||||||
|
|
||||||
|
-- Read config
|
||||||
|
local cfg, err = load(f:read("a"))
|
||||||
|
f:close()
|
||||||
|
if err ~= nil then
|
||||||
|
error(err)
|
||||||
|
end
|
||||||
|
cfg = cfg()
|
||||||
|
if type(cfg.bias) ~= "number" then
|
||||||
|
error("`bias` must be a number")
|
||||||
|
elseif cfg.bias ~= cfg.bias or cfg.bias == math.huge then
|
||||||
|
error("`bias` can't be `nan` or `math.huge`")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
---@type table<integer, integer>
|
||||||
|
local you_tokens <const> = {345, 921, 1639, 5832, 7013, 36981}
|
||||||
|
|
||||||
|
local genmod_run = false
|
||||||
|
|
||||||
|
function userscript.genmod()
|
||||||
|
genmod_run = true
|
||||||
|
local context
|
||||||
|
if cfg.only_if_outside_double_quotes then
|
||||||
|
context = " " .. kobold.worldinfo:compute_context(kobold.submission, {})
|
||||||
|
end
|
||||||
|
|
||||||
|
for i, generated_row in ipairs(kobold.generated) do
|
||||||
|
local should_bias = true
|
||||||
|
|
||||||
|
if cfg.only_if_outside_double_quotes then
|
||||||
|
local str = context .. kobold.decode(generated_row)
|
||||||
|
local last_open_quote = 0
|
||||||
|
local last_close_quote = 0
|
||||||
|
local i = 0
|
||||||
|
local j = 0
|
||||||
|
while true do
|
||||||
|
i, j = str:find('"', j+1)
|
||||||
|
if i == nil then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
if str:sub(i-1, i-1) == " " or str:sub(i-1, i-1) == "\n" then
|
||||||
|
last_open_quote = j
|
||||||
|
else
|
||||||
|
last_close_quote = j
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if last_open_quote > last_close_quote then
|
||||||
|
should_bias = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if should_bias then
|
||||||
|
for k, v in ipairs(you_tokens) do
|
||||||
|
kobold.logits[i][v+1] = kobold.logits[i][v+1] + cfg.bias
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function userscript.outmod()
|
||||||
|
if not genmod_run then
|
||||||
|
warn("WARNING: Generation modifier was not executed, so this script has had no effect")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return userscript
|
Loading…
Reference in New Issue