import { randomIntBetween } from "#Source/basic/index.ts" import type { LoggerFriendly, LoggerFriendlyOptions } from "#Source/log/index.ts" import { Logger } from "#Source/log/index.ts" import type * as Openai from "#Source/openai/index.ts" import * as ChatCompletionAi from "./chat-completion-ai/index.ts" import * as EmbeddingAi from "./embedding-ai/index.ts" export type ChatCompletionOptions = Openai.OriginalChatCompletionOptions export type EmbeddingOptions = Openai.CustomEmbeddingOptions export interface WithAi { ai: Ai } export interface AiOptions extends LoggerFriendlyOptions { chatCompletionAiOptions?: ChatCompletionAi.ChatCompletionAi.ChatCompletionAiOptions | undefined embeddingAiOptions?: EmbeddingAi.EmbeddingAi.EmbeddingAiOptions | undefined /** * @deprecated */ instancePool: Openai.Openai[] /** * @deprecated */ indexChangeMode?: "random" | "poll" } export class Ai implements LoggerFriendly { readonly logger: Logger readonly chatCompletionAi: ChatCompletionAi.ChatCompletionAi.ChatCompletionAi readonly embeddingAi: EmbeddingAi.EmbeddingAi.EmbeddingAi protected instancePool: Openai.Openai[] protected indexChangeMode: "random" | "poll" protected index = 0 constructor(options: AiOptions) { this.logger = Logger.fromOptions(options).setDefaultName("Ai") this.chatCompletionAi = new ChatCompletionAi.ChatCompletionAi.ChatCompletionAi( options.chatCompletionAiOptions ?? { chatCompletionInstanceList: [], }, ) this.embeddingAi = new EmbeddingAi.EmbeddingAi.EmbeddingAi( options.embeddingAiOptions ?? { embeddingInstanceList: [], }, ) this.instancePool = options.instancePool this.indexChangeMode = options.indexChangeMode ?? "random" } protected changeIndex(): void { this.logger.info(`chang instance index, mode: ${this.indexChangeMode}`) switch (this.indexChangeMode) { case "random": { this.index = randomIntBetween(0, this.instancePool.length - 1) break } case "poll": { this.index = this.index + 1 if (this.index >= this.instancePool.length - 1) { this.index = 0 } break } default: { throw new Error(`unknown indexChangeMode: ${String(this.indexChangeMode)}`) } } this.logger.info(`change instance index success: ${this.index}`) } protected async getInstance(): Promise { this.logger.info(`get instance index: ${this.index}`) const instance = this.instancePool[this.index] if (instance === undefined) { throw new Error("can not find instance") } this.logger.info(`get instance success, index: ${this.index}`) this.logger.info(`get instance success, baseUrl: ${instance.getBaseUrl()}`) return await Promise.resolve(instance) } protected async changeIndexAndGetInstance(): Promise { this.changeIndex() return await this.getInstance() } /** * @deprecated */ async originalChatCompletionNoStreaming( options: ChatCompletionOptions, ): Promise { const instance = await this.changeIndexAndGetInstance() return await instance.originalChatCompletionNonStreaming(options) } /** * @deprecated */ async originalChatCompletionStreaming( options: ChatCompletionOptions, ): Promise> { const instance = await this.changeIndexAndGetInstance() return await instance.originalChatCompletionStreaming(options) } }