import { libx } from 'libx.js/build/bundles/essentials.js'; import { network } from 'libx.js/build/modules/Network'; import { Streams } from 'libx.js/build/modules/Streams'; export interface IPromptConfig { wsId?: string; systemPrompt?: string; temperature?: number; stream?: boolean; model?: string; provider?: string; maxTokens?: number; frequencyPenalty?: number; presencePenalty?: number; topP?: number; user?: string; } export class FeedoxAIModule { public constructor(public options?: Partial) { this.options = { ...new ModuleOptions(), ...options }; // libx.log.v('AiModule:ctor: baseUrl:', this.baseUrl); } public async streamPrompt(workspaceId: string, promptId: string, variables: any, messages: IConvMessage[], config?: IPromptConfig) { const { url, payload } = this.prepareRequest(workspaceId, promptId, variables, messages, config); const stream = this.runStream(url, payload); return await stream; } public async runPrompt(workspaceId: string, promptId: string, variables: any, messages: IConvMessage[], config?: IPromptConfig) { const { url, payload } = this.prepareRequest(workspaceId, promptId, variables, messages, config); const res = await network.httpPost(url, payload, { headers: { "Content-Type": "application/json" } }); let ret = await res?.toString(); return ret; } private prepareRequest(workspaceId: string, promptId: string, variables: any, messages: IConvMessage[], config?: IPromptConfig) { let url = `${this.options.baseUrl}/completion/`; if (workspaceId && promptId) { url += `${config?.wsId ?? workspaceId}/${promptId}`; } const payload = { variables, messages, systemPrompt: undefined, config: { temperature: 0.1, stream: true, ...config, }, }; if (config?.systemPrompt) { payload.systemPrompt = config.systemPrompt; delete config.systemPrompt; } if (payload.config?.wsId) { delete payload.config.wsId; } return { url, payload }; } private async runStream(url: string, payload: any) { let { readable, writable } = new TransformStream(); let writer = writable.getWriter(); const textEncoder = new TextEncoder(); libx.log.v('runStream: using streams', url); const p = Streams.getStream(url, (msg) => { // libx.log.v('delta: ', msg); writer.write(textEncoder.encode(msg)); }, { method: 'POST', headers: { 'Content-Type': 'application/json', }, // payload: JSON.stringify({ payload }), // payload body: payload, // body: { "params": "query=test&hitsPerPage=2&getRankingInfo=1" } } ); p.then(done => { libx.log.v('runStream: closing stream...'); writer.close() }); libx.log.v('runStream: got stream'); return readable; } } export class ModuleOptions { baseUrl = process.env.FEEDOX_AI_URL; } export interface IConvMessage { role: 'system' | 'user' | 'assistant'; content: string; name?: string; type?: IConvMessageType; files?: IFile[]; } export enum IConvMessageType { text, image, audio, } export interface IFile { url: string; type?: string; }