Spaces:
Running
Running
/** | |
* Copyright (c) 2023 MERCENARIES.AI PTE. LTD. | |
* All rights reserved. | |
*/ | |
//@ts-check | |
import { runBlock } from './blocks.js'; | |
import { Llm, fixJsonString, generateModelId, deduceLlmTitle, deduceLlmDescription } from './llm.js'; | |
import { is_valid, clean_string } from './utils.js'; | |
import { Tokenizer_Openai } from './tokenizer_Openai.js'; | |
const LLM_PROVIDER_OPENAI_SERVER = 'openai'; // we may need to support Azure and other providers (e.g. Poe) | |
const LLM_MODEL_TYPE_OPENAI = 'openai'; | |
const BLOCK_OPENAI_ADVANCED_CHATGPT = 'openai.advancedChatGPT'; | |
const LLM_CONTEXT_SIZE_MARGIN = 500; | |
const GPT3_MODEL_SMALL = 'gpt-3.5-turbo'; | |
const GPT3_MODEL_LARGE = 'gpt-3.5-turbo-16k'; | |
const GPT4_MODEL_SMALL = 'gpt-4'; | |
const GPT4_MODEL_LARGE = 'gpt-4-32k'; | |
const GPT3_MODEL_PREVIEW = 'gpt-3.5-turbo-1106'; | |
const GPT4_MODEL_PREVIEW= 'gpt-4-1106-preview'; | |
const GPT4_SIZE_CUTOFF = 8192 - LLM_CONTEXT_SIZE_MARGIN; | |
const ICON_OPENAI = '💰'; | |
const llm_openai_models = [ | |
{ | |
model_name: GPT3_MODEL_SMALL, | |
model_type: LLM_MODEL_TYPE_OPENAI, | |
context_size: 4096, | |
provider: LLM_PROVIDER_OPENAI_SERVER | |
}, | |
{ | |
model_name: GPT3_MODEL_LARGE, | |
model_type: LLM_MODEL_TYPE_OPENAI, | |
context_size: 16385, | |
provider: LLM_PROVIDER_OPENAI_SERVER | |
}, | |
{ | |
model_name: GPT4_MODEL_SMALL, | |
model_type: LLM_MODEL_TYPE_OPENAI, | |
context_size: 8192, | |
provider: LLM_PROVIDER_OPENAI_SERVER | |
}, | |
{ | |
model_name: GPT4_MODEL_LARGE, | |
model_type: LLM_MODEL_TYPE_OPENAI, | |
context_size: 32768, | |
provider: LLM_PROVIDER_OPENAI_SERVER | |
}, | |
{ | |
model_name: GPT3_MODEL_PREVIEW, | |
model_type: LLM_MODEL_TYPE_OPENAI, | |
context_size: 16385, | |
provider: LLM_PROVIDER_OPENAI_SERVER | |
}, | |
{ | |
model_name: GPT4_MODEL_PREVIEW, | |
model_type: LLM_MODEL_TYPE_OPENAI, | |
context_size: 128000, | |
provider: LLM_PROVIDER_OPENAI_SERVER | |
} | |
]; | |
class Llm_Openai extends Llm { | |
constructor() { | |
const tokenizer_Openai = new Tokenizer_Openai(); | |
super(tokenizer_Openai); | |
// @ts-ignore | |
this.context_sizes[GPT3_MODEL_SMALL] = 4096; | |
// @ts-ignore | |
this.context_sizes[GPT3_MODEL_LARGE] = 16385; | |
// @ts-ignore | |
this.context_sizes[GPT4_MODEL_SMALL] = 8192; | |
// @ts-ignore | |
this.context_sizes[GPT4_MODEL_LARGE] = 32768; | |
// @ts-ignore | |
this.context_sizes[GPT3_MODEL_PREVIEW] = 16385; | |
// @ts-ignore | |
this.context_sizes[GPT4_MODEL_PREVIEW] = 128000; | |
} | |
// ----------------------------------------------------------------------- | |
/** | |
* @param {any} ctx | |
* @param {string} prompt | |
* @param {string} instruction | |
* @param {string} model_name | |
* @param {number} [temperature=0] | |
* @param {any} [args=null] | |
* @returns {Promise<{ answer_text: string; answer_json: any; }>} | |
*/ | |
async query(ctx, prompt, instruction, model_name, temperature = 0, args = null) { | |
const block_args = { ...args }; | |
block_args.user = ctx.userId; | |
if (prompt !== '') block_args.prompt = prompt; | |
if (instruction !== '') block_args.instruction = instruction; | |
block_args.temperature = temperature; | |
block_args.model = model_name; | |
const response = await this.runLlmBlock(ctx, block_args); | |
if (response.error) throw new Error(response.error); | |
const total_tokens = response?.usage?.total_tokens || 0; | |
let answer_text = response?.answer_text || ''; | |
const function_arguments_string = response?.function_arguments_string || ''; | |
let function_arguments = null; | |
if (is_valid(function_arguments_string)) function_arguments = await fixJsonString(ctx, function_arguments_string); | |
if (is_valid(answer_text)) answer_text = clean_string(answer_text); | |
const answer_json = {}; | |
answer_json.function_arguments_string = function_arguments_string; | |
answer_json.function_arguments = function_arguments; | |
answer_json.total_tokens = total_tokens; | |
answer_json.answer_text = answer_text; | |
const return_value = { | |
answer_text, | |
answer_json | |
}; | |
return return_value; | |
} | |
getProvider() { | |
return LLM_PROVIDER_OPENAI_SERVER; | |
} | |
getModelType() { | |
return LLM_MODEL_TYPE_OPENAI; | |
} | |
// @ts-ignore | |
async getModelChoices(choices, llm_model_types, llm_context_sizes) { | |
const models = Object.values(llm_openai_models); | |
for (const model of models) { | |
const model_name = model.model_name; | |
const provider = model.provider; | |
const model_id = generateModelId(model_name, provider); | |
// @ts-ignore | |
const title = model.title || deduceLlmTitle(model_name, provider, ICON_OPENAI); | |
// @ts-ignore | |
const description = model.description || deduceLlmDescription(model_name, model.context_size); | |
// @ts-ignore | |
llm_model_types[model_name] = model.type; | |
llm_context_sizes[model_name] = model.context_size; | |
const choice = { value: model_id, title, description }; | |
choices.push(choice); | |
} | |
} | |
// @ts-ignore | |
async runLlmBlock(ctx, args) { | |
// TBD ensure all the runLLM blocks have the same exact response format | |
// or clean it up here for openai | |
const prompt = args.prompt; | |
const instruction = args.instruction; | |
const model = args.model; | |
const prompt_cost = this.tokenizer.countTextTokens(prompt); | |
const instruction_cost = this.tokenizer.countTextTokens(instruction); | |
const cost = prompt_cost + instruction_cost; | |
let response = null; | |
try { | |
response = await runBlock(ctx, BLOCK_OPENAI_ADVANCED_CHATGPT, args); | |
} catch (err) { | |
// @ts-ignore | |
const error_message = `Error running openai.advancedChatGPT: ${err.message}`; | |
console.error(error_message); | |
throw err; | |
} | |
return response; | |
} | |
} | |
export { Llm_Openai }; | |