UNPKG

@langchain/community

Version:
248 lines (247 loc) 7.71 kB
import { BaseChatModel } from "@langchain/core/language_models/chat_models"; import { AIMessage, ChatMessage } from "@langchain/core/messages"; import { getEnvironmentVariable } from "@langchain/core/utils/env"; import { IterableReadableStream } from "@langchain/core/utils/stream"; //#region src/chat_models/iflytek_xinghuo/common.ts /** * Function that extracts the custom role of a generic chat message. * @param message Chat message from which to extract the custom role. * @returns The custom role of the chat message. */ function extractGenericMessageCustomRole(message) { if (message.role !== "assistant" && message.role !== "user") console.warn(`Unknown message role: ${message.role}`); return message.role; } /** * Function that converts a base message to a Xinghuo message role. * @param message Base message to convert. * @returns The Xinghuo message role. */ function messageToXinghuoRole(message) { const type = message._getType(); switch (type) { case "ai": return "assistant"; case "human": return "user"; case "system": throw new Error("System messages should not be here"); case "function": throw new Error("Function messages not supported"); case "generic": if (!ChatMessage.isInstance(message)) throw new Error("Invalid generic chat message"); return extractGenericMessageCustomRole(message); default: throw new Error(`Unknown message type: ${type}`); } } /** * Wrapper around IflytekXingHuo large language models that use the Chat endpoint. * * To use you should have the `IFLYTEK_API_KEY` and `IFLYTEK_API_SECRET` and `IFLYTEK_APPID` * environment variable set. * * @augments BaseChatModel * @augments IflytekXinghuoChatInput */ var BaseChatIflytekXinghuo = class extends BaseChatModel { static lc_name() { return "ChatIflytekXinghuo"; } get callKeys() { return [ "stop", "signal", "options" ]; } get lc_secrets() { return { iflytekApiKey: "IFLYTEK_API_KEY", iflytekApiSecret: "IFLYTEK_API_SECRET" }; } get lc_aliases() {} lc_serializable = true; version = "v3.1"; iflytekAppid; iflytekApiKey; iflytekApiSecret; userId; apiUrl; domain; temperature = .5; max_tokens = 2048; top_k = 4; streaming = false; constructor(fields) { super(fields ?? {}); const iflytekAppid = fields?.iflytekAppid ?? getEnvironmentVariable("IFLYTEK_APPID"); if (!iflytekAppid) throw new Error("Iflytek APPID not found"); else this.iflytekAppid = iflytekAppid; const iflytekApiKey = fields?.iflytekApiKey ?? getEnvironmentVariable("IFLYTEK_API_KEY"); if (!iflytekApiKey) throw new Error("Iflytek API key not found"); else this.iflytekApiKey = iflytekApiKey; const iflytekApiSecret = fields?.iflytekApiSecret ?? getEnvironmentVariable("IFLYTEK_API_SECRET"); if (!iflytekApiSecret) throw new Error("Iflytek API secret not found"); else this.iflytekApiSecret = iflytekApiSecret; this.userId = fields?.userId ?? this.userId; this.streaming = fields?.streaming ?? this.streaming; this.temperature = fields?.temperature ?? this.temperature; this.max_tokens = fields?.max_tokens ?? this.max_tokens; this.top_k = fields?.top_k ?? this.top_k; this.version = fields?.version ?? this.version; if ([ "v1.1", "v2.1", "v3.1", "v3.5", "v4.0", "pro-128k" ].includes(this.version)) { this.apiUrl = `wss://spark-api.xf-yun.com/${this.version}/chat`; switch (this.version) { case "v1.1": this.domain = "general"; break; case "v2.1": this.domain = "generalv2"; break; case "v3.1": this.domain = "generalv3"; break; case "v3.5": this.domain = "generalv3.5"; break; case "v4.0": this.domain = "4.0Ultra"; break; case "pro-128k": this.domain = "pro-128k"; this.apiUrl = `wss://spark-api.xf-yun.com/chat/${this.version}`; break; default: this.domain = "generalv3"; } } else throw new Error(`Invalid model version: ${this.version}`); } /** * Get the identifying parameters for the model */ identifyingParams() { return { version: this.version, ...this.invocationParams() }; } /** * Get the parameters used to invoke the model */ invocationParams() { return { streaming: this.streaming, temperature: this.temperature, top_k: this.top_k }; } async completion(request, stream, signal) { const webSocketStream = await this.openWebSocketStream({ signal }); const connection = await webSocketStream.connection; const header = { app_id: this.iflytekAppid, uid: this.userId }; const parameter = { chat: { domain: this.domain, temperature: request.temperature ?? this.temperature, max_tokens: request.max_tokens ?? this.max_tokens, top_k: request.top_k ?? this.top_k } }; const payload = { message: { text: request.messages } }; const message = JSON.stringify({ header, parameter, payload }); const { writable, readable } = connection; await writable.getWriter().write(message); const streams = IterableReadableStream.fromReadableStream(readable); if (stream) return streams; else { let response = { result: "" }; for await (const chunk of streams) { const { header, payload } = JSON.parse(chunk); if (header.code === 0) { if (header.status === 0) response.result = payload.choices?.text[0]?.content ?? ""; else if (header.status === 1) response.result += payload.choices?.text[0]?.content ?? ""; else if (header.status === 2) { response = { ...response, usage: payload.usage?.text }; break; } } else break; } streams.cancel(); webSocketStream.close(); return response; } } async _generate(messages, options, runManager) { const tokenUsage = {}; const params = this.invocationParams(); const messagesMapped = messages.map((message) => { if (typeof message.content !== "string") throw new Error("ChatIflytekXinghuo does not support non-string message content."); return { role: messageToXinghuoRole(message), content: message.content }; }); const data = params.streaming ? await (async () => { const streams = await this.completion({ messages: messagesMapped, ...params }, true, options.signal); let response = { result: "" }; for await (const chunk of streams) { const { header, payload } = JSON.parse(chunk); if (header.code === 0) { if (header.status === 0) response.result = payload.choices?.text[0]?.content ?? ""; else if (header.status === 1) response.result += payload.choices?.text[0]?.content ?? ""; else if (header.status === 2) { response = { ...response, usage: payload.usage?.text }; break; } runManager?.handleLLMNewToken(payload.choices?.text[0]?.content); } else break; } streams.cancel(); return response; })() : await this.completion({ messages: messagesMapped, ...params }, false, options.signal); const { completion_tokens: completionTokens, prompt_tokens: promptTokens, total_tokens: totalTokens } = data.usage ?? {}; if (completionTokens) tokenUsage.completionTokens = (tokenUsage.completionTokens ?? 0) + completionTokens; if (promptTokens) tokenUsage.promptTokens = (tokenUsage.promptTokens ?? 0) + promptTokens; if (totalTokens) tokenUsage.totalTokens = (tokenUsage.totalTokens ?? 0) + totalTokens; const generations = []; const text = data.result ?? ""; generations.push({ text, message: new AIMessage(text) }); return { generations, llmOutput: { tokenUsage } }; } /** @ignore */ _combineLLMOutput() { return []; } _llmType() { return "iflytek_xinghuo"; } }; //#endregion export { BaseChatIflytekXinghuo }; //# sourceMappingURL=common.js.map