Rework custom API

This commit is contained in:
kwaroran
2024-11-25 23:04:32 +09:00
parent 8274fae180
commit cc8d753dc8
4 changed files with 42 additions and 64 deletions

View File

@@ -27,6 +27,7 @@
import PromptSettings from "./PromptSettings.svelte"; import PromptSettings from "./PromptSettings.svelte";
import { openPresetList } from "src/ts/stores.svelte"; import { openPresetList } from "src/ts/stores.svelte";
import { selectSingleFile } from "src/ts/util"; import { selectSingleFile } from "src/ts/util";
import { LLMFormat } from "src/ts/model/modellist";
let tokens = $state({ let tokens = $state({
mainPrompt: 0, mainPrompt: 0,
@@ -133,39 +134,27 @@
<span class="text-textcolor mt-4"> {language.proxyAPIKey}</span> <span class="text-textcolor mt-4"> {language.proxyAPIKey}</span>
<TextInput hideText={DBState.db.hideApiKey} marginBottom={false} size={"sm"} placeholder="leave it blank if it hasn't password" bind:value={DBState.db.proxyKey} /> <TextInput hideText={DBState.db.hideApiKey} marginBottom={false} size={"sm"} placeholder="leave it blank if it hasn't password" bind:value={DBState.db.proxyKey} />
<span class="text-textcolor mt-4"> {language.proxyRequestModel}</span> <span class="text-textcolor mt-4"> {language.proxyRequestModel}</span>
<SelectInput className="mt-2" bind:value={DBState.db.proxyRequestModel}> <TextInput marginBottom={false} size={"sm"} bind:value={DBState.db.customProxyRequestModel} placeholder="Name" />
<OptionInput value="">None</OptionInput> <span class="text-textcolor mt-4"> {language.format}</span>
<OptionInput value="gpt35">GPT 3.5</OptionInput> <SelectInput value={DBState.db.customAPIFormat.toString()} onchange={(e) => {
<OptionInput value="gpt35_16k">GPT 3.5 16k</OptionInput> DBState.db.customAPIFormat = parseInt(e.currentTarget.value)
<OptionInput value="gpt4">GPT-4</OptionInput> }}>
<OptionInput value="gpt4o">GPT-4o</OptionInput> <OptionInput value={LLMFormat.OpenAICompatible.toString()}>
<OptionInput value="gpt4_32k">GPT-4 32k</OptionInput> OpenAI Compatible
<OptionInput value="gpt4_turbo">GPT-4 Turbo</OptionInput> </OptionInput>
<OptionInput value="gpt4_1106">GPT-4 Turbo 1106</OptionInput> <OptionInput value={LLMFormat.Anthropic.toString()}>
<OptionInput value="gptvi4_1106">GPT-4 Turbo 1106 Vision</OptionInput> Anthropic Claude
<OptionInput value="gpt35_0301">GPT-3.5 0301</OptionInput> </OptionInput>
<OptionInput value="gpt4_0301">GPT-4 0301</OptionInput> <OptionInput value={LLMFormat.Mistral.toString()}>
<OptionInput value="gpt35_0613">GPT-3.5 0613</OptionInput> Mistral
<OptionInput value="gpt4_0613">GPT-4 0613</OptionInput> </OptionInput>
<OptionInput value="claude-2.1">claude-2.1</OptionInput> <OptionInput value={LLMFormat.GoogleCloud.toString()}>
<OptionInput value="claude-2.0">claude-2.0</OptionInput> Google Cloud
<OptionInput value="claude-2">claude-2</OptionInput> </OptionInput>
<OptionInput value="claude-v1.3">claude-v1.3</OptionInput> <OptionInput value={LLMFormat.Cohere.toString()}>
<OptionInput value="claude-v1.3-100k">claude-v1.3-100k</OptionInput> Cohere
<OptionInput value="claude-v1.2">claude-v1.2</OptionInput> </OptionInput>
<OptionInput value="claude-instant-v1.1">claude-instant-v1.1</OptionInput>
<OptionInput value="claude-instant-v1.1-100k">claude-instant-v1.1-100k</OptionInput>
<OptionInput value="claude-3-opus-20240229">claude-3-opus-20240229</OptionInput>
<OptionInput value="claude-3-sonnet-20240229">claude-3-sonnet-20240229</OptionInput>
<OptionInput value="claude-3-5-sonnet-20240620">claude-3-5-sonnet-20240620</OptionInput>
<OptionInput value="claude-3-5-sonnet-20241022">claude-3-5-sonnet-20241022</OptionInput>
<OptionInput value="custom">Custom</OptionInput>
</SelectInput> </SelectInput>
{#if DBState.db.proxyRequestModel === 'custom'}
<TextInput marginBottom={true} size={"sm"} bind:value={DBState.db.customProxyRequestModel} placeholder="Name" />
{:else}
<div class="mb-4"></div>
{/if}
{/if} {/if}
{#if DBState.db.aiModel.startsWith('risullm')} {#if DBState.db.aiModel.startsWith('risullm')}
<span class="text-textcolor mt-4">Risu {language.apiKey}</span> <span class="text-textcolor mt-4">Risu {language.apiKey}</span>

View File

@@ -1,19 +1,16 @@
import { get } from "svelte/store";
import type { MultiModal, OpenAIChat, OpenAIChatFull } from "./index.svelte"; import type { MultiModal, OpenAIChat, OpenAIChatFull } from "./index.svelte";
import { getCurrentCharacter, getDatabase, type character } from "../storage/database.svelte"; import { getCurrentCharacter, getDatabase, type character } from "../storage/database.svelte";
import { pluginProcess } from "../plugins/plugins"; import { pluginProcess } from "../plugins/plugins";
import { language } from "../../lang"; import { language } from "../../lang";
import { stringlizeAINChat, stringlizeChat, getStopStrings, unstringlizeAIN, unstringlizeChat } from "./stringlize"; import { stringlizeAINChat, getStopStrings, unstringlizeAIN, unstringlizeChat } from "./stringlize";
import { addFetchLog, fetchNative, globalFetch, isNodeServer, isTauri, textifyReadableStream } from "../globalApi.svelte"; import { addFetchLog, fetchNative, globalFetch, isNodeServer, isTauri, textifyReadableStream } from "../globalApi.svelte";
import { sleep } from "../util"; import { sleep } from "../util";
import { NovelAIBadWordIds, stringlizeNAIChat } from "./models/nai"; import { NovelAIBadWordIds, stringlizeNAIChat } from "./models/nai";
import { strongBan, tokenize, tokenizeNum } from "../tokenizer"; import { strongBan, tokenize, tokenizeNum } from "../tokenizer";
import { runGGUFModel } from "./models/local";
import { risuChatParser } from "../parser.svelte"; import { risuChatParser } from "../parser.svelte";
import { SignatureV4 } from "@smithy/signature-v4"; import { SignatureV4 } from "@smithy/signature-v4";
import { HttpRequest } from "@smithy/protocol-http"; import { HttpRequest } from "@smithy/protocol-http";
import { Sha256 } from "@aws-crypto/sha256-js"; import { Sha256 } from "@aws-crypto/sha256-js";
import { v4 } from "uuid";
import { supportsInlayImage } from "./files/image"; import { supportsInlayImage } from "./files/image";
import { Capacitor } from "@capacitor/core"; import { Capacitor } from "@capacitor/core";
import { getFreeOpenRouterModel } from "../model/openrouter"; import { getFreeOpenRouterModel } from "../model/openrouter";
@@ -47,9 +44,9 @@ interface requestDataArgument{
interface RequestDataArgumentExtended extends requestDataArgument{ interface RequestDataArgumentExtended extends requestDataArgument{
aiModel?:string aiModel?:string
multiGen?:boolean multiGen?:boolean
realAIModel?:string
abortSignal?:AbortSignal abortSignal?:AbortSignal
modelInfo?:LLMModel modelInfo?:LLMModel
customURL?:string
} }
type requestDataResponse = { type requestDataResponse = {
@@ -199,19 +196,12 @@ export async function requestChatDataMain(arg:requestDataArgument, model:'model'
targ.biasString = arg.biasString ?? [] targ.biasString = arg.biasString ?? []
targ.aiModel = (model === 'model' ? db.aiModel : db.subModel) targ.aiModel = (model === 'model' ? db.aiModel : db.subModel)
targ.multiGen = ((db.genTime > 1 && targ.aiModel.startsWith('gpt') && (!arg.continue)) && (!arg.noMultiGen)) targ.multiGen = ((db.genTime > 1 && targ.aiModel.startsWith('gpt') && (!arg.continue)) && (!arg.noMultiGen))
targ.realAIModel = targ.aiModel
targ.abortSignal = abortSignal targ.abortSignal = abortSignal
targ.modelInfo = getModelInfo(targ.aiModel) targ.modelInfo = getModelInfo(targ.aiModel)
if(targ.aiModel === 'reverse_proxy'){ if(targ.aiModel === 'reverse_proxy'){
if(db.proxyRequestModel === 'custom' && db.customProxyRequestModel.startsWith('claude')){ targ.modelInfo.internalID = db.customProxyRequestModel
targ.realAIModel = db.customProxyRequestModel targ.modelInfo.format = db.customAPIFormat
} targ.customURL = db.forceReplaceUrl
if(db.proxyRequestModel.startsWith('claude')){
targ.realAIModel = db.proxyRequestModel
}
if(db.forceProxyAsOpenAI){
targ.realAIModel = 'reverse_proxy'
}
} }
const format = targ.modelInfo.format const format = targ.modelInfo.format
@@ -384,7 +374,7 @@ async function requestOpenAI(arg:RequestDataArgumentExtended):Promise<requestDat
const oaiFunctionCall = oaiFunctions ? (arg.useEmotion ? {"name": "set_emotion"} : "auto") : undefined const oaiFunctionCall = oaiFunctions ? (arg.useEmotion ? {"name": "set_emotion"} : "auto") : undefined
let requestModel = (aiModel === 'reverse_proxy' || aiModel === 'openrouter') ? db.proxyRequestModel : aiModel let requestModel = (aiModel === 'reverse_proxy' || aiModel === 'openrouter') ? db.proxyRequestModel : aiModel
let openrouterRequestModel = db.openrouterRequestModel let openrouterRequestModel = db.openrouterRequestModel
if(aiModel === 'reverse_proxy' && db.proxyRequestModel === 'custom'){ if(aiModel === 'reverse_proxy'){
requestModel = db.customProxyRequestModel requestModel = db.customProxyRequestModel
} }
@@ -393,7 +383,7 @@ async function requestOpenAI(arg:RequestDataArgumentExtended):Promise<requestDat
} }
console.log(formatedChat) console.log(formatedChat)
if(aiModel.startsWith('mistral') || aiModel === 'open-mistral-nemo'){ if(arg.modelInfo.format === LLMFormat.Mistral){
requestModel = aiModel requestModel = aiModel
let reformatedChat:OpenAIChatExtra[] = [] let reformatedChat:OpenAIChatExtra[] = []
@@ -446,7 +436,7 @@ async function requestOpenAI(arg:RequestDataArgumentExtended):Promise<requestDat
} }
} }
const res = await globalFetch("https://api.mistral.ai/v1/chat/completions", { const res = await globalFetch(arg.customURL ?? "https://api.mistral.ai/v1/chat/completions", {
body: { body: {
model: requestModel, model: requestModel,
messages: reformatedChat, messages: reformatedChat,
@@ -525,6 +515,7 @@ async function requestOpenAI(arg:RequestDataArgumentExtended):Promise<requestDat
: requestModel === 'gpt4o-chatgpt' ? 'chatgpt-4o-latest' : requestModel === 'gpt4o-chatgpt' ? 'chatgpt-4o-latest'
: requestModel === 'gpt4o1-preview' ? 'o1-preview' : requestModel === 'gpt4o1-preview' ? 'o1-preview'
: requestModel === 'gpt4o1-mini' ? 'o1-mini' : requestModel === 'gpt4o1-mini' ? 'o1-mini'
: arg.modelInfo.internalID ? arg.modelInfo.internalID
: (!requestModel) ? 'gpt-3.5-turbo' : (!requestModel) ? 'gpt-3.5-turbo'
: requestModel, : requestModel,
messages: formatedChat, messages: formatedChat,
@@ -608,7 +599,7 @@ async function requestOpenAI(arg:RequestDataArgumentExtended):Promise<requestDat
} }
let replacerURL = aiModel === 'openrouter' ? "https://openrouter.ai/api/v1/chat/completions" : let replacerURL = aiModel === 'openrouter' ? "https://openrouter.ai/api/v1/chat/completions" :
(aiModel === 'reverse_proxy') ? (db.forceReplaceUrl) : ('https://api.openai.com/v1/chat/completions') (aiModel === 'reverse_proxy') ? (arg.customURL) : ('https://api.openai.com/v1/chat/completions')
let risuIdentify = false let risuIdentify = false
if(replacerURL.startsWith("risu::")){ if(replacerURL.startsWith("risu::")){
@@ -768,7 +759,7 @@ async function requestOpenAI(arg:RequestDataArgumentExtended):Promise<requestDat
} }
} }
if(arg.realAIModel === 'reverse_proxy'){ if(aiModel === 'reverse_proxy'){
const additionalParams = db.additionalParams const additionalParams = db.additionalParams
for(let i=0;i<additionalParams.length;i++){ for(let i=0;i<additionalParams.length;i++){
let key = additionalParams[i][0] let key = additionalParams[i][0]
@@ -924,7 +915,7 @@ async function requestOpenAILegacyInstruct(arg:RequestDataArgumentExtended):Prom
//return `\n\n${author}: ${m.content.trim()}`; //return `\n\n${author}: ${m.content.trim()}`;
}).join("") + `\n## Response\n`; }).join("") + `\n## Response\n`;
const response = await globalFetch( "https://api.openai.com/v1/completions", { const response = await globalFetch(arg.customURL ?? "https://api.openai.com/v1/completions", {
body: { body: {
model: "gpt-3.5-turbo-instruct", model: "gpt-3.5-turbo-instruct",
prompt: prompt, prompt: prompt,
@@ -1481,9 +1472,9 @@ async function requestGoogleCloudVertex(arg:RequestDataArgumentExtended):Promise
headers['Authorization'] = "Bearer " + generateToken(db.google.clientEmail, db.google.privateKey) headers['Authorization'] = "Bearer " + generateToken(db.google.clientEmail, db.google.privateKey)
} }
const url = arg.modelInfo.format === LLMFormat.VertexAIGemini ? const url = arg.customURL ?? (arg.modelInfo.format === LLMFormat.VertexAIGemini ?
`https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/us-central1/publishers/google/models/${arg.modelInfo.internalID}:streamGenerateContent` `https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/us-central1/publishers/google/models/${arg.modelInfo.internalID}:streamGenerateContent`
: `https://generativelanguage.googleapis.com/v1beta/models/${arg.modelInfo.internalID}:generateContent?key=${db.google.accessToken}` : `https://generativelanguage.googleapis.com/v1beta/models/${arg.modelInfo.internalID}:generateContent?key=${db.google.accessToken}`)
const res = await globalFetch(url, { const res = await globalFetch(url, {
headers: headers, headers: headers,
body: body, body: body,
@@ -1624,7 +1615,7 @@ async function requestNovelList(arg:RequestDataArgumentExtended):Promise<request
logit_bias: (logit_bias.length > 0) ? logit_bias.join("<<|>>") : undefined, logit_bias: (logit_bias.length > 0) ? logit_bias.join("<<|>>") : undefined,
logit_bias_values: (logit_bias_values.length > 0) ? logit_bias_values.join("|") : undefined, logit_bias_values: (logit_bias_values.length > 0) ? logit_bias_values.join("|") : undefined,
}; };
const response = await globalFetch(api_server_url + '/api', { const response = await globalFetch(arg.customURL ?? api_server_url + '/api', {
method: 'POST', method: 'POST',
headers: headers, headers: headers,
body: send_body, body: send_body,
@@ -1771,7 +1762,7 @@ async function requestCohere(arg:RequestDataArgumentExtended):Promise<requestDat
console.log(body) console.log(body)
const res = await globalFetch('https://api.cohere.com/v1/chat', { const res = await globalFetch(arg.customURL ?? 'https://api.cohere.com/v1/chat', {
method: "POST", method: "POST",
headers: { headers: {
"Authorization": "Bearer " + db.cohereAPIKey, "Authorization": "Bearer " + db.cohereAPIKey,
@@ -1807,7 +1798,7 @@ async function requestClaude(arg:RequestDataArgumentExtended):Promise<requestDat
const db = getDatabase() const db = getDatabase()
const aiModel = arg.aiModel const aiModel = arg.aiModel
const useStreaming = arg.useStreaming const useStreaming = arg.useStreaming
let replacerURL = (aiModel === 'reverse_proxy') ? (db.forceReplaceUrl) : ('https://api.anthropic.com/v1/messages') let replacerURL = (aiModel === 'reverse_proxy') ? (arg.customURL) : ('https://api.anthropic.com/v1/messages')
let apiKey = (aiModel === 'reverse_proxy') ? db.proxyKey : db.claudeAPIKey let apiKey = (aiModel === 'reverse_proxy') ? db.proxyKey : db.claudeAPIKey
const maxTokens = arg.maxTokens const maxTokens = arg.maxTokens
if(aiModel === 'reverse_proxy' && db.autofillRequestUrl){ if(aiModel === 'reverse_proxy' && db.autofillRequestUrl){

View File

@@ -445,6 +445,7 @@ export function setDatabase(data:Database){
data.customQuotesData ??= ['“','”','',''] data.customQuotesData ??= ['“','”','','']
data.groupOtherBotRole ??= 'user' data.groupOtherBotRole ??= 'user'
data.customGUI ??= '' data.customGUI ??= ''
data.customAPIFormat ??= LLMFormat.OpenAICompatible
changeLanguage(data.language) changeLanguage(data.language)
setDatabaseLite(data) setDatabaseLite(data)
} }
@@ -819,6 +820,7 @@ export interface Database{
guiHTML:string guiHTML:string
logShare:boolean logShare:boolean
OAIPrediction:string OAIPrediction:string
customAPIFormat:LLMFormat
} }
export interface customscript{ export interface customscript{
@@ -1512,6 +1514,7 @@ import type { RisuModule } from '../process/modules';
import type { HypaV2Data } from '../process/memory/hypav2'; import type { HypaV2Data } from '../process/memory/hypav2';
import { decodeRPack, encodeRPack } from '../rpack/rpack_bg'; import { decodeRPack, encodeRPack } from '../rpack/rpack_bg';
import { DBState, selectedCharID } from '../stores.svelte'; import { DBState, selectedCharID } from '../stores.svelte';
import { LLMFormat } from '../model/modellist';
export async function downloadPreset(id:number, type:'json'|'risupreset'|'return' = 'json'){ export async function downloadPreset(id:number, type:'json'|'risupreset'|'return' = 'json'){
saveCurrentPreset() saveCurrentPreset()

View File

@@ -41,12 +41,7 @@ export async function encode(data:string):Promise<(number[]|Uint32Array|Int32Arr
case 'cohere': case 'cohere':
return await tokenizeWebTokenizers(data, 'cohere') return await tokenizeWebTokenizers(data, 'cohere')
default: default:
// Add exception for gpt-4o tokenizers on reverse_proxy return await tikJS(data, 'o200k_base')
if(db.proxyRequestModel?.startsWith('gpt4o') ||
(db.proxyRequestModel === 'custom' && db.customProxyRequestModel.startsWith('gpt-4o'))) {
return await tikJS(data, 'o200k_base')
}
return await tikJS(data)
} }
} }
if(db.aiModel.startsWith('novellist')){ if(db.aiModel.startsWith('novellist')){