[feat] openrouter apis
This commit is contained in:
321
src/ts/creation/creator.ts
Normal file
321
src/ts/creation/creator.ts
Normal file
@@ -0,0 +1,321 @@
|
||||
import { language } from "src/lang";
|
||||
import { alertError, alertInput, alertNormal, alertSelect, alertStore } from "../alert";
|
||||
import { requestChatData } from "../process/request";
|
||||
import { checkCharOrder, globalFetch, isNodeServer, isTauri, saveAsset } from "../storage/globalApi";
|
||||
import { tokenize } from "../tokenizer";
|
||||
import { createBlankChar } from "../characters";
|
||||
import { DataBase, setDatabase, type character } from "../storage/database";
|
||||
import { get } from "svelte/store";
|
||||
import { sleep } from "../util";
|
||||
|
||||
|
||||
async function createBotFromWebMain(prompt:string):Promise<{ ok: false; data:string }|{ok:"creation";data:character}>{
|
||||
|
||||
|
||||
|
||||
const usp = new URLSearchParams()
|
||||
usp.append("q","fandom " + prompt)
|
||||
|
||||
|
||||
const bd = await globalFetch("https://lite.duckduckgo.com/lite/", {
|
||||
body: usp,
|
||||
rawResponse: true,
|
||||
headers: {
|
||||
'Content-Type': "application/x-www-form-urlencoded"
|
||||
}
|
||||
})
|
||||
if(!bd.ok){
|
||||
return {
|
||||
ok: false,
|
||||
data: bd.data
|
||||
}
|
||||
}
|
||||
const searchDom = new DOMParser()
|
||||
const searchDoc = searchDom.parseFromString(Buffer.from(bd.data).toString('utf-8'), 'text/html')
|
||||
console.log(searchDoc)
|
||||
const links = searchDoc.querySelectorAll(".link-text")
|
||||
let url = ''
|
||||
const fandomURL = /(.+?)\.fandom\.com\/wiki\//g
|
||||
const wikiggURL = /(.+?)\.wiki\.gg\/wiki\//g
|
||||
|
||||
for(const link of links){
|
||||
try {
|
||||
let lurl = link.innerHTML.trim()
|
||||
if(fandomURL.test(lurl) || wikiggURL.test(lurl)){
|
||||
if(!lurl.startsWith("https://")){
|
||||
lurl = "https://" + lurl
|
||||
}
|
||||
const surl = new URL(lurl)
|
||||
const charname = surl.pathname.split("/")[2].toLocaleLowerCase()
|
||||
console.log(charname)
|
||||
if(charname.includes('main') ||charname.includes('home') || charname.includes('wiki')){
|
||||
continue
|
||||
}
|
||||
url = lurl
|
||||
break
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const surl = new URL(url)
|
||||
const urlPathName = surl.pathname.split("/")
|
||||
|
||||
while(urlPathName.length > 3){
|
||||
urlPathName.pop()
|
||||
}
|
||||
surl.pathname = urlPathName.join('/')
|
||||
url = surl.toString()
|
||||
|
||||
if(url === ''){
|
||||
return {
|
||||
ok: false,
|
||||
data: "Cannot find the character, is the character not popular, or did you misspelled?"
|
||||
}
|
||||
}
|
||||
|
||||
let val = ''
|
||||
let imgID = ''
|
||||
const charname = url.split('/').at(-1)
|
||||
|
||||
if(charname.toLocaleLowerCase().startsWith('main') || charname.toLocaleLowerCase().startsWith('wiki')){
|
||||
return {
|
||||
ok: false,
|
||||
data: "Cannot find the character, is the character not popular, or did you misspelled?"
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const v = await globalFetch(url, {rawResponse: true, method: 'GET'})
|
||||
if(!v.ok){
|
||||
throw ''
|
||||
}
|
||||
const parser = new DOMParser()
|
||||
|
||||
const vdom = parser.parseFromString(Buffer.from(v.data).toString(), 'text/html')
|
||||
const imgDoms = vdom.querySelectorAll("#mw-content-text .mw-parser-output img")
|
||||
|
||||
let qurl = ''
|
||||
let level = 0
|
||||
for(const dom of imgDoms){
|
||||
const thisLevel = dom.className.includes("thumbnail") ? 2 : 1
|
||||
if(thisLevel > level){
|
||||
qurl = dom.getAttribute("src") || qurl
|
||||
level = thisLevel
|
||||
}
|
||||
}
|
||||
|
||||
if(qurl){
|
||||
const v = await globalFetch(qurl, {rawResponse: true, method: 'GET'})
|
||||
if(!v.ok){
|
||||
throw ''
|
||||
}
|
||||
imgID = await saveAsset(v.data)
|
||||
}
|
||||
|
||||
|
||||
await sleep(2000)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
const vurl = `https://bluearchive.fandom.com/api.php?action=visualeditor&format=json&paction=wikitext&page=${charname}&uselang=en&formatversion=2`
|
||||
const fv = await globalFetch(vurl)
|
||||
if(!fv.ok){
|
||||
throw ''
|
||||
}
|
||||
val = fv.data?.visualeditor?.content ?? ''
|
||||
if(val === ''){
|
||||
throw ''
|
||||
}
|
||||
} catch (error) {
|
||||
const rurl = url + '?action=edit'
|
||||
const v = await globalFetch(rurl, {rawResponse: true, method: 'GET'})
|
||||
|
||||
if(!v.ok){
|
||||
console.log(v)
|
||||
return {
|
||||
ok: false,
|
||||
data: "Failed on Reading Site"
|
||||
}
|
||||
}
|
||||
|
||||
const parser = new DOMParser()
|
||||
const vdom = parser.parseFromString(Buffer.from(v.data).toString(), 'text/html')
|
||||
const ta:HTMLTextAreaElement = vdom.querySelector('textarea#wpTextbox1')
|
||||
|
||||
if((!ta) || (!ta.value)){
|
||||
console.log(vdom.body.outerHTML)
|
||||
return {
|
||||
ok: false,
|
||||
data: "Data cannot be found inside site."
|
||||
}
|
||||
}
|
||||
|
||||
val = ta.value
|
||||
}
|
||||
|
||||
let tokns = await tokenize(val)
|
||||
if (tokns > 3200){
|
||||
const v = val.split('\n')
|
||||
let chunks:[string,string,number][] = [["main","",0]]
|
||||
|
||||
for(const a of v){
|
||||
if(a.startsWith('==') && (a.endsWith('=='))){
|
||||
chunks.push([a, a + "\n", 0])
|
||||
}
|
||||
chunks.at(-1)[1] += a + "\n"
|
||||
}
|
||||
|
||||
for(let i=0;i<chunks.length;i++){
|
||||
chunks[i][2] = await tokenize(chunks[i][1])
|
||||
}
|
||||
|
||||
while(tokns > 3200){
|
||||
|
||||
const ind = chunks.length-1
|
||||
|
||||
tokns -= chunks[ind][2]
|
||||
|
||||
chunks.splice(ind, 1)
|
||||
}
|
||||
|
||||
val = chunks.map((v) => v[1]).join("\n")
|
||||
}
|
||||
|
||||
|
||||
alertStore.set({
|
||||
type: 'wait',
|
||||
msg: 'Loading..'
|
||||
})
|
||||
const rqv = val + "\n\n[[This was a character's wiki page data.]]"
|
||||
const ch = await requestChatData({
|
||||
formated: [{
|
||||
role: 'system',
|
||||
content: rqv
|
||||
},{
|
||||
role: 'system',
|
||||
content: "\n\n*Name*:\n*Age*:\n*gender*: \n*race*:\n*Hair style, color*:\n*color, shape of eye*:\n*Personality*:\n*Dress*:\n*Height (cm)*:\n*weight(kg)*:\n*Job*:\n*Specialty*:\n*Features*: \n*Likes*:\n*Dislikes*:\n*Character's background*: \n*Other informations*: \n\n[[This is a format that you must convert to. output the latest information If there is older information. If it is unknown, output as unknown. only output the converted result. now, output the converted result.]]"
|
||||
}],
|
||||
maxTokens: 600,
|
||||
temperature: 0,
|
||||
bias: {}
|
||||
}, 'submodel')
|
||||
|
||||
if(ch.type === 'multiline' || ch.type === 'fail' || ch.type === 'streaming'){
|
||||
return {
|
||||
ok: false,
|
||||
data: "Request Fail: " + ch.result
|
||||
}
|
||||
}
|
||||
|
||||
const char = createBlankChar()
|
||||
|
||||
char.name = charname.replaceAll("_"," ")
|
||||
char.desc = ch.result
|
||||
char.creatorNotes = `Generated by RisuAI, Data from ` + url
|
||||
if(imgID){
|
||||
char.image = imgID
|
||||
}
|
||||
return {
|
||||
ok: "creation",
|
||||
data: char
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
async function createBotByAI() {
|
||||
let search = await alertInput(language.inputBotGenerationPrompt)
|
||||
if(search.length < 3){
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function createFirstMsg(charDesc:string) {
|
||||
const v = await requestChatData({
|
||||
formated: [{
|
||||
role: "system",
|
||||
content: charDesc + `\n[This was the character's description]`
|
||||
},{
|
||||
role: "system",
|
||||
content: "Create and describe the situation where the character and {{user}} meet, reflecting about information of character and prompt. Line from {{user}} is not allowed."
|
||||
}],
|
||||
bias: {},
|
||||
maxTokens: 600,
|
||||
temperature: 0
|
||||
}, 'submodel')
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
async function createBotFromWeb() {
|
||||
if((!isTauri) && (!isNodeServer)){
|
||||
alertNormal(language.noweb)
|
||||
return
|
||||
}
|
||||
let search = (await alertInput(language.createBotInternetAlert)).split("#")[0]
|
||||
if(search.length < 3){
|
||||
return
|
||||
}
|
||||
alertStore.set({
|
||||
type: 'wait',
|
||||
msg: 'Fetching..'
|
||||
})
|
||||
const d = await createBotFromWebMain(search)
|
||||
if(d.ok === 'creation'){
|
||||
const db = get(DataBase)
|
||||
const cha = d.data
|
||||
const fm = await createFirstMsg(cha.desc)
|
||||
if(fm.type === 'multiline' || fm.type === 'fail' || fm.type === 'streaming'){
|
||||
return {
|
||||
ok: false,
|
||||
data: "Request Fail: " + fm.result
|
||||
}
|
||||
}
|
||||
cha.firstMessage = surroundTextWithAsterisks(fm.result)
|
||||
db.characters.push(d.data)
|
||||
checkCharOrder()
|
||||
setDatabase(db)
|
||||
alertNormal(language.creationSuccess)
|
||||
}
|
||||
else{
|
||||
alertError(d.data)
|
||||
}
|
||||
}
|
||||
|
||||
export const BotCreator = {
|
||||
createBotFromWeb
|
||||
}
|
||||
|
||||
function surroundTextWithAsterisks(fulltext:string) {
|
||||
let result:string[] = []
|
||||
|
||||
const splited = fulltext.split("\n")
|
||||
for(const text of splited){
|
||||
if(!text){
|
||||
result.push(text)
|
||||
continue
|
||||
}
|
||||
let output = '';
|
||||
let parts = text.split('"');
|
||||
for(let i = 0; i < parts.length; i++) {
|
||||
let part = parts[i];
|
||||
if(i % 2 === 0) {
|
||||
let trimmed = part.trim();
|
||||
output += trimmed ? '*' + trimmed + '*' : part;
|
||||
} else {
|
||||
output += '"' + part + '"';
|
||||
}
|
||||
}
|
||||
result.push(output)
|
||||
}
|
||||
|
||||
return result.join('\n');
|
||||
}
|
||||
8
src/ts/creation/license.ts
Normal file
8
src/ts/creation/license.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export const CCLicenseData = {
|
||||
"CC BY 4.0": ["by", "Requires Attribution"],
|
||||
"CC BY-NC 4.0": ["by-nc", "Requires Attribution and Non Commercial"],
|
||||
"CC BY-NC-SA 4.0": ["by-nc-sa", "Requires Attribution, Non Commercial and Share Alike"],
|
||||
"CC BY-SA 4.0": ["by-sa", "Requires Attribution and Share Alike"],
|
||||
"CC BY-ND 4.0": ["by-nd", "Requires Attribution and No Derivatives"],
|
||||
"CC BY-NC-ND 4.0": ["by-nc-nd", "Requires Attribution, Non Commercial and No Derivatives"],
|
||||
}
|
||||
Reference in New Issue
Block a user