UNPKG

@langchain/community

Version:
1 lines 19.4 kB
{"version":3,"file":"base.cjs","names":["ChatMessage","BaseChatModel","ChatGenerationChunk","AIMessageChunk","IterableReadableStream","AIMessage"],"sources":["../../../src/chat_models/tencent_hunyuan/base.ts"],"sourcesContent":["import {\n BaseChatModel,\n type BaseChatModelParams,\n} from \"@langchain/core/language_models/chat_models\";\nimport {\n AIMessage,\n BaseMessage,\n ChatMessage,\n AIMessageChunk,\n} from \"@langchain/core/messages\";\nimport {\n ChatGeneration,\n ChatResult,\n ChatGenerationChunk,\n} from \"@langchain/core/outputs\";\nimport { CallbackManagerForLLMRun } from \"@langchain/core/callbacks/manager\";\nimport { getEnvironmentVariable } from \"@langchain/core/utils/env\";\nimport { IterableReadableStream } from \"@langchain/core/utils/stream\";\nimport { sign } from \"../../utils/tencent_hunyuan/common.js\";\n\n/**\n * Type representing the role of a message in the Hunyuan chat model.\n */\nexport type HunyuanMessageRole = \"system\" | \"assistant\" | \"user\";\n\n/**\n * Interface representing a message in the Hunyuan chat model.\n */\ninterface HunyuanMessage {\n Role: HunyuanMessageRole;\n Content: string;\n}\n\n/**\n * Models available, see https://cloud.tencent.com/document/product/1729/104753.\n */\ntype ModelName =\n | (string & NonNullable<unknown>)\n // hunyuan-lite\n | \"hunyuan-lite\" // context size: 4k, input size: 3k, output size: 1k\n // hunyuan-standard\n | \"hunyuan-standard\" // alias for hunyuan-standard-32K\n | \"hunyuan-standard-32K\" // context size: 32k, input size: 30k, output size: 2k\n | \"hunyuan-standard-256K\" // context size: 256k, input size: 250k, output size: 6k\n // hunyuan-pro\n | \"hunyuan-pro\"; // context size: 32k, input size: 28k, output size: 4k\n\n/**\n * Interface representing the usage of tokens in a chat completion.\n * See https://cloud.tencent.com/document/api/1729/101838#Usage.\n */\ninterface Usage {\n TotalTokens?: number;\n PromptTokens?: number;\n CompletionTokens?: number;\n}\n\n/**\n * Interface representing a request for a chat completion.\n * See https://cloud.tencent.com/document/api/1729/105701.\n */\ninterface ChatCompletionRequest {\n Model: ModelName;\n Messages: HunyuanMessage[];\n Stream?: boolean;\n StreamModeration?: boolean;\n EnableEnhancement?: boolean;\n Temperature?: number;\n TopP?: number;\n}\n\n/**\n * Interface representing a chat completion choice message.\n * See https://cloud.tencent.com/document/api/1729/101838#Message.\n */\ninterface ChoiceMessage {\n Role: string;\n Content: string;\n}\n\n/**\n * Interface representing a chat completion choice.\n * See https://cloud.tencent.com/document/api/1729/101838#Choice.\n */\ninterface Choice {\n FinishReason: \"stop\" | \"sensitive\" | \"\";\n Delta: ChoiceMessage;\n Message: ChoiceMessage;\n}\n\n/**\n * Interface representing a error response from a chat completion.\n */\ninterface Error {\n Code: string;\n Message: string;\n}\n\n/**\n * Interface representing a response from a chat completion.\n * See https://cloud.tencent.com/document/product/1729/105701.\n */\ninterface ChatCompletionResponse {\n Created: number;\n Usage: Usage;\n Note: string;\n Choices: Choice[];\n Id?: string;\n RequestId?: string;\n Error?: Error;\n ErrorMsg?: Error;\n}\n\n/**\n * Interface defining the input to the ChatTencentHunyuan class.\n */\nexport interface TencentHunyuanChatInput {\n /**\n * Tencent Cloud API Host.\n * @default \"hunyuan.tencentcloudapi.com\"\n */\n host?: string;\n\n /**\n * Model name to use.\n * @default \"hunyuan-pro\"\n */\n model: ModelName;\n\n /**\n * Whether to stream the results or not. Defaults to false.\n * @default false\n */\n streaming?: boolean;\n\n /**\n * SecretID to use when making requests, can be obtained from https://console.cloud.tencent.com/cam/capi.\n * Defaults to the value of `TENCENT_SECRET_ID` environment variable.\n */\n tencentSecretId?: string;\n\n /**\n * Secret key to use when making requests, can be obtained from https://console.cloud.tencent.com/cam/capi.\n * Defaults to the value of `TENCENT_SECRET_KEY` environment variable.\n */\n tencentSecretKey?: string;\n\n /**\n * Amount of randomness injected into the response. Ranges\n * from 0.0 to 2.0. Use temp closer to 0 for analytical /\n * multiple choice, and temp closer to 1 for creative\n * and generative tasks. Defaults to 1.0.95.\n */\n temperature?: number;\n\n /**\n * Total probability mass of tokens to consider at each step. Range\n * from 0 to 1.0. Defaults to 1.0.\n */\n topP?: number;\n}\n\n/**\n * Interface defining the input to the ChatTencentHunyuan class.\n */\ninterface TencentHunyuanChatInputWithSign extends TencentHunyuanChatInput {\n /**\n * Tencent Cloud API v3 sign method.\n */\n sign: sign;\n}\n\n/**\n * Function that converts a base message to a Hunyuan message role.\n * @param message Base message to convert.\n * @returns The Hunyuan message role.\n */\nfunction messageToRole(message: BaseMessage): HunyuanMessageRole {\n const type = message._getType();\n switch (type) {\n case \"ai\":\n return \"assistant\";\n case \"human\":\n return \"user\";\n case \"system\":\n return \"system\";\n case \"function\":\n throw new Error(\"Function messages not supported\");\n case \"generic\": {\n if (!ChatMessage.isInstance(message)) {\n throw new Error(\"Invalid generic chat message\");\n }\n if ([\"system\", \"assistant\", \"user\"].includes(message.role)) {\n return message.role as HunyuanMessageRole;\n }\n throw new Error(`Unknown message role: ${message.role}`);\n }\n default:\n throw new Error(`Unknown message type: ${type}`);\n }\n}\n\n/**\n * Wrapper around Tencent Hunyuan large language models that use the Chat endpoint.\n *\n * To use you should have the `TENCENT_SECRET_ID` and `TENCENT_SECRET_KEY`\n * environment variable set.\n *\n * @augments BaseLLM\n * @augments TencentHunyuanInput\n * @example\n * ```typescript\n * const messages = [new HumanMessage(\"Hello\")];\n *\n * const hunyuanLite = new ChatTencentHunyuan({\n * model: \"hunyuan-lite\",\n * tencentSecretId: \"YOUR-SECRET-ID\",\n * tencentSecretKey: \"YOUR-SECRET-KEY\",\n * });\n *\n * let res = await hunyuanLite.call(messages);\n *\n * const hunyuanPro = new ChatTencentHunyuan({\n * model: \"hunyuan-pro\",\n * temperature: 1,\n * tencentSecretId: \"YOUR-SECRET-ID\",\n * tencentSecretKey: \"YOUR-SECRET-KEY\",\n * });\n *\n * res = await hunyuanPro.call(messages);\n * ```\n */\nexport class ChatTencentHunyuan\n extends BaseChatModel\n implements TencentHunyuanChatInputWithSign\n{\n static lc_name() {\n return \"ChatTencentHunyuan\";\n }\n\n get callKeys(): string[] {\n return [\"stop\", \"signal\", \"options\"];\n }\n\n get lc_secrets(): { [key: string]: string } | undefined {\n return {\n tencentSecretId: \"TENCENT_SECRET_ID\",\n tencentSecretKey: \"TENCENT_SECRET_KEY\",\n };\n }\n\n get lc_aliases(): { [key: string]: string } | undefined {\n return undefined;\n }\n\n lc_serializable = true;\n\n tencentSecretId?: string;\n\n tencentSecretKey?: string;\n\n streaming = false;\n\n host = \"hunyuan.tencentcloudapi.com\";\n\n model = \"hunyuan-pro\";\n\n temperature?: number | undefined;\n\n topP?: number | undefined;\n\n sign: sign;\n\n constructor(\n fields?: Partial<TencentHunyuanChatInputWithSign> & BaseChatModelParams\n ) {\n super(fields ?? {});\n\n this.tencentSecretId =\n fields?.tencentSecretId ?? getEnvironmentVariable(\"TENCENT_SECRET_ID\");\n if (!this.tencentSecretId) {\n throw new Error(\"Tencent SecretID not found\");\n }\n\n this.tencentSecretKey =\n fields?.tencentSecretKey ?? getEnvironmentVariable(\"TENCENT_SECRET_KEY\");\n if (!this.tencentSecretKey) {\n throw new Error(\"Tencent SecretKey not found\");\n }\n\n this.host = fields?.host ?? this.host;\n this.topP = fields?.topP ?? this.topP;\n this.model = fields?.model ?? this.model;\n this.streaming = fields?.streaming ?? this.streaming;\n this.temperature = fields?.temperature ?? this.temperature;\n if (!fields?.sign) {\n throw new Error(\"Sign method undefined\");\n }\n this.sign = fields?.sign;\n }\n\n /**\n * Get the parameters used to invoke the model\n */\n invocationParams(): Omit<ChatCompletionRequest, \"Messages\"> {\n return {\n TopP: this.topP,\n Model: this.model,\n Stream: this.streaming,\n Temperature: this.temperature,\n };\n }\n\n /**\n * Get the HTTP headers used to invoke the model\n */\n invocationHeaders(request: object, timestamp: number): HeadersInit {\n const headers = {\n \"Content-Type\": \"application/json\",\n \"X-TC-Action\": \"ChatCompletions\",\n \"X-TC-Version\": \"2023-09-01\",\n \"X-TC-Timestamp\": timestamp.toString(),\n Authorization: \"\",\n };\n\n headers.Authorization = this.sign(\n this.host,\n request,\n timestamp,\n this.tencentSecretId ?? \"\",\n this.tencentSecretKey ?? \"\",\n headers\n );\n return headers;\n }\n\n async *_streamResponseChunks(\n messages: BaseMessage[],\n options: this[\"ParsedCallOptions\"],\n runManager?: CallbackManagerForLLMRun\n ): AsyncGenerator<ChatGenerationChunk> {\n const stream = await this.caller.call(async () =>\n this.createStream(\n {\n ...this.invocationParams(),\n Messages: messages.map((message) => ({\n Role: messageToRole(message),\n Content: message.content as string,\n })),\n },\n options?.signal\n )\n );\n\n for await (const chunk of stream) {\n // handle streaming error\n if (chunk.ErrorMsg?.Message) {\n throw new Error(`[${chunk.Id}] ${chunk.ErrorMsg?.Message}`);\n }\n\n const {\n Choices: [\n {\n Delta: { Content },\n FinishReason,\n },\n ],\n } = chunk;\n yield new ChatGenerationChunk({\n text: Content,\n message: new AIMessageChunk({ content: Content }),\n generationInfo: FinishReason\n ? {\n usage: chunk.Usage,\n request_id: chunk.Id,\n finish_reason: FinishReason,\n }\n : undefined,\n });\n await runManager?.handleLLMNewToken(Content);\n }\n }\n\n private async *createStream(\n request: ChatCompletionRequest,\n signal?: AbortSignal\n ): AsyncGenerator<ChatCompletionResponse> {\n const timestamp = Math.trunc(Date.now() / 1000);\n const headers = this.invocationHeaders(request, timestamp);\n const response = await fetch(`https://${this.host}`, {\n headers,\n method: \"POST\",\n body: JSON.stringify(request),\n signal,\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(\n `Hunyuan call failed with status code ${response.status}: ${text}`\n );\n }\n\n if (\n !response.headers.get(\"content-type\")?.startsWith(\"text/event-stream\")\n ) {\n const text = await response.text();\n try {\n const data = JSON.parse(text);\n if (data?.Response?.Error?.Message) {\n throw new Error(\n `[${data?.Response?.RequestId}] ${data?.Response?.Error?.Message}`\n );\n }\n } catch {\n throw new Error(\n `Could not begin Hunyuan stream, received a non-JSON parseable response: ${text}.`\n );\n }\n }\n\n if (!response.body) {\n throw new Error(\n `Could not begin Hunyuan stream, received empty body response.`\n );\n }\n\n const decoder = new TextDecoder(\"utf-8\");\n const stream = IterableReadableStream.fromReadableStream(response.body);\n let extra = \"\";\n for await (const chunk of stream) {\n const decoded = extra + decoder.decode(chunk);\n const lines = decoded.split(\"\\n\");\n extra = lines.pop() || \"\";\n for (const line of lines) {\n if (!line.startsWith(\"data:\")) {\n continue;\n }\n try {\n yield JSON.parse(line.slice(\"data:\".length).trim());\n } catch {\n console.warn(`Received a non-JSON parseable chunk: ${line}`);\n }\n }\n }\n }\n\n /** @ignore */\n async _generate(\n messages: BaseMessage[],\n options?: this[\"ParsedCallOptions\"],\n runManager?: CallbackManagerForLLMRun\n ): Promise<ChatResult> {\n const params = this.invocationParams();\n if (params.Stream) {\n let usage: Usage = {};\n const stream = this._streamResponseChunks(\n messages,\n options ?? {},\n runManager\n );\n\n const generations: ChatGeneration[] = [];\n for await (const chunk of stream) {\n const text = chunk.text ?? \"\";\n generations.push({\n text,\n message: new AIMessage(text),\n });\n usage = chunk.generationInfo?.usage;\n }\n return {\n generations,\n llmOutput: {\n tokenUsage: {\n totalTokens: usage.TotalTokens,\n promptTokens: usage.PromptTokens,\n completionTokens: usage.CompletionTokens,\n },\n },\n };\n }\n\n const data = await this.completionWithRetry(\n {\n ...params,\n Messages: messages.map((message) => ({\n Role: messageToRole(message),\n Content: message.content as string,\n })),\n },\n options?.signal\n ).then<ChatCompletionResponse>((data) => {\n const response: ChatCompletionResponse = data?.Response;\n if (response?.Error?.Message) {\n throw new Error(`[${response.RequestId}] ${response.Error.Message}`);\n }\n return response;\n });\n\n const text = data.Choices[0]?.Message?.Content ?? \"\";\n const {\n TotalTokens = 0,\n PromptTokens = 0,\n CompletionTokens = 0,\n } = data.Usage;\n\n return {\n generations: [\n {\n text,\n message: new AIMessage(text),\n },\n ],\n llmOutput: {\n tokenUsage: {\n totalTokens: TotalTokens,\n promptTokens: PromptTokens,\n completionTokens: CompletionTokens,\n },\n },\n };\n }\n\n /** @ignore */\n async completionWithRetry(\n request: ChatCompletionRequest,\n signal?: AbortSignal\n ) {\n return this.caller.call(async () => {\n const timestamp = Math.trunc(Date.now() / 1000);\n const headers = this.invocationHeaders(request, timestamp);\n const response = await fetch(`https://${this.host}`, {\n headers,\n method: \"POST\",\n body: JSON.stringify(request),\n signal,\n });\n\n return response.json();\n });\n }\n\n _llmType() {\n return \"tencenthunyuan\";\n }\n\n /** @ignore */\n _combineLLMOutput() {\n return [];\n }\n}\n"],"mappings":"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"}