@llumiverse/common
Version:
Public types, enums and options used by Llumiverse API.
300 lines (276 loc) • 11.1 kB
text/typescript
import { ModelOptionInfoItem, ModelOptions, ModelOptionsInfo, OptionType, ReasoningEffort, SharedOptions } from "../types.js";
import { textOptionsFallback } from "./fallback.js";
// Union type of all OpenAI options
/**
* @discriminator _option_id
*/
export type OpenAiOptions = OpenAiThinkingOptions | OpenAiTextOptions | OpenAiDalleOptions | OpenAiGptImageOptions;
export interface OpenAiThinkingOptions {
_option_id: "openai-thinking",
max_tokens?: number,
stop_sequence?: string[],
effort?: ReasoningEffort,
reasoning_effort?: ReasoningEffort,
image_detail?: "low" | "high" | "auto",
}
export interface OpenAiTextOptions {
_option_id: "openai-text",
max_tokens?: number,
temperature?: number,
top_p?: number,
presence_penalty?: number,
frequency_penalty?: number,
stop_sequence?: string[],
image_detail?: "low" | "high" | "auto",
}
export interface OpenAiDalleOptions {
_option_id: "openai-dalle",
size?: "256x256" | "512x512" | "1024x1024" | "1792x1024" | "1024x1792",
image_quality?: "standard" | "hd",
style?: "vivid" | "natural",
response_format?: "url" | "b64_json",
n?: number,
}
export interface OpenAiGptImageOptions {
_option_id: "openai-gpt-image",
size?: "1024x1024" | "1024x1536" | "1536x1024" | "auto",
image_quality?: "low" | "medium" | "high" | "auto",
background?: "transparent" | "opaque" | "auto",
output_format?: "png" | "webp" | "jpeg",
}
export function getOpenAiOptions(model: string, _option?: ModelOptions): ModelOptionsInfo {
const visionOptions: ModelOptionInfoItem[] = isVisionModel(model) ? [
{
name: "image_detail", type: OptionType.enum, enum: { "Low": "low", "High": "high", "Auto": "auto" },
default: "auto", description: "Controls how the model processes an input image."
},
] : [];
// Image generation models
if (isImageModel(model)) {
const isGPTImage = model.includes("gpt-image") || model.includes("chatgpt-image");
const isDallE2 = model.includes("dall-e-2");
const isDallE3 = model.includes("dall-e-3");
const sizeOptions: Record<string, string> = {};
if (isGPTImage) {
sizeOptions["1024x1024"] = "1024x1024";
sizeOptions["1024x1536"] = "1024x1536";
sizeOptions["1536x1024"] = "1536x1024";
sizeOptions["Auto"] = "auto";
} else if (isDallE2) {
sizeOptions["256x256"] = "256x256";
sizeOptions["512x512"] = "512x512";
sizeOptions["1024x1024"] = "1024x1024";
} else if (isDallE3) {
sizeOptions["1024x1024"] = "1024x1024";
sizeOptions["1792x1024"] = "1792x1024";
sizeOptions["1024x1792"] = "1024x1792";
}
const baseImageOptions: ModelOptionInfoItem[] = [
{
name: "size",
type: OptionType.enum,
enum: sizeOptions,
default: "1024x1024",
description: "The size of the generated image"
}
];
const gptImageOptions: ModelOptionInfoItem[] = isGPTImage ? [
{
name: "image_quality",
type: OptionType.enum,
enum: { "Low": "low", "Medium": "medium", "High": "high", "Auto": "auto" },
default: "auto",
description: "The quality of the generated image"
},
{
name: "background",
type: OptionType.enum,
enum: { "Transparent": "transparent", "Opaque": "opaque", "Auto": "auto" },
default: "auto",
description: "The background setting for the image"
},
{
name: "output_format",
type: OptionType.enum,
enum: { "PNG": "png", "WebP": "webp", "JPEG": "jpeg" },
default: "png",
description: "The output format for the image"
}
] : [];
const dalleOptions: ModelOptionInfoItem[] = (isDallE2 || isDallE3) ? [
{
name: "image_quality",
type: OptionType.enum,
enum: isDallE3 ? { "Standard": "standard", "HD": "hd" } : { "Standard": "standard" },
default: "standard",
description: "The quality of the generated image"
},
{
name: "style",
type: OptionType.enum,
enum: { "Vivid": "vivid", "Natural": "natural" },
default: "vivid",
description: "The style of the generated image (DALL-E 3 only)"
},
{
name: "response_format",
type: OptionType.enum,
enum: { "URL": "url", "Base64 JSON": "b64_json" },
default: "b64_json",
description: "The format of the response"
}
] : [];
const nImagesOption: ModelOptionInfoItem[] = isDallE2 ? [
{
name: "n",
type: OptionType.numeric,
min: 1,
max: 10,
default: 1,
integer: true,
description: "Number of images to generate (DALL-E 2 only)"
}
] : [];
return {
_option_id: isGPTImage ? "openai-gpt-image" : "openai-dalle",
options: [
...baseImageOptions,
...gptImageOptions,
...dalleOptions,
...nImagesOption,
]
};
}
if (isReasoningModel(model)) {
//Is thinking text model
let max_tokens_limit = 4096;
if (model.includes("o1")) {
if (model.includes("preview")) {
max_tokens_limit = 32768;
}
else if (model.includes("mini")) {
max_tokens_limit = 65536;
}
else {
max_tokens_limit = 100000;
}
}
else if (model.includes("o3")) {
max_tokens_limit = 100000;
}
else if (model.includes("o4") || model.includes("gpt-5")) {
max_tokens_limit = 128000;
}
const commonOptions: ModelOptionInfoItem[] = [
{
name: SharedOptions.max_tokens, type: OptionType.numeric, min: 1, max: max_tokens_limit,
integer: true, description: "The maximum number of tokens to generate",
},
{
name: SharedOptions.stop_sequence, type: OptionType.string_list, value: [],
description: "The stop sequence of the generated image",
},
];
const reasoningOptions: ModelOptionInfoItem[] = isGpt5ProModel(model) ? [
{
name: SharedOptions.effort, type: OptionType.enum, enum: { "High": "high" },
default: "high", description: "GPT-5 Pro only supports high reasoning effort."
},
] : model.includes("o3") || model.includes("o4") || model.includes("gpt-5") || isO1Full(model) ? [
{
name: SharedOptions.effort, type: OptionType.enum, enum: { "Low": "low", "Medium": "medium", "High": "high" },
default: "medium", description: "How much effort the model should put into reasoning, lower values result in faster responses and less tokens used."
},
] : [];
return {
_option_id: "openai-thinking",
options: [
...commonOptions,
...reasoningOptions,
...visionOptions,
],
};
} else {
let max_tokens_limit = 4096;
if (model.includes("gpt-4o")) {
max_tokens_limit = 16384;
if (model.includes("gpt-4o-2024-05-13") || model.includes("realtime")) {
max_tokens_limit = 4096;
}
}
else if (model.includes("gpt-4")) {
if (model.includes("turbo")) {
max_tokens_limit = 4096;
} else {
max_tokens_limit = 8192;
}
}
else if (model.includes("gpt-3-5")) {
max_tokens_limit = 4096;
}
else if (model.includes("gpt-5")) {
max_tokens_limit = 128000;
}
//Is non-thinking text model
const commonOptions: ModelOptionInfoItem[] = [
{
name: SharedOptions.max_tokens, type: OptionType.numeric, min: 1, max: max_tokens_limit,
integer: true, step: 200, description: "The maximum number of tokens to generate",
},
{
name: "temperature", type: OptionType.numeric, min: 0.0, max: 2.0, default: 0.7,
integer: false, step: 0.1, description: "A higher temperature biases toward less likely tokens, making the model more creative"
},
{
name: "top_p", type: OptionType.numeric, min: 0, max: 1,
integer: false, step: 0.1, description: "Limits token sampling to the cumulative probability of the top p tokens"
},
{
name: "presence_penalty", type: OptionType.numeric, min: -2.0, max: 2.0,
integer: false, step: 0.1, description: "Penalise tokens if they appear at least once in the text"
},
{
name: "frequency_penalty", type: OptionType.numeric, min: -2.0, max: 2.0,
integer: false, step: 0.1, description: "Penalise tokens based on their frequency in the text"
},
{
name: SharedOptions.stop_sequence, type: OptionType.string_list, value: [],
description: "The generation will halt if one of the stop sequences is output",
}
]
return {
_option_id: "openai-text",
options: [
...commonOptions,
...visionOptions,
],
}
}
return textOptionsFallback;
}
function isO1Full(model: string): boolean {
if (model.includes("o1")) {
if (model.includes("mini") || model.includes("preview")) {
return false;
}
return true;
}
return false;
}
function isReasoningModel(model: string): boolean {
const normalized = model.toLowerCase();
return normalized.includes("o1")
|| normalized.includes("o3")
|| normalized.includes("o4")
|| normalized.includes("gpt-5");
}
function isGpt5ProModel(model: string): boolean {
const modelName = model.toLowerCase().split('/').pop() ?? model.toLowerCase();
return /^gpt-5(?:\.\d+)?-pro/.test(modelName);
}
function isVisionModel(model: string): boolean {
return model.includes("gpt-4o") || isO1Full(model) || model.includes("gpt-4-turbo");
}
function isImageModel(model: string): boolean {
return model.includes("dall-e") || model.includes("gpt-image") || model.includes("chatgpt-image");
}