@baiducloud/qianfan
Advanced tools
Comparing version 0.0.2 to 0.0.3-beta.0
@@ -1,33 +0,6 @@ | ||
import { ChatBody, ChatResp } from '../interface'; | ||
import { BaseClient } from '../Base'; | ||
import { ChatBody, Resp } from '../interface'; | ||
import { ChatModel } from './utils'; | ||
export declare class ChatCompletion { | ||
private controller; | ||
private QIANFAN_AK?; | ||
private QIANFAN_SK?; | ||
private QIANFAN_ACCESS_KEY?; | ||
private QIANFAN_SECRET_KEY?; | ||
private headers; | ||
private axiosInstance; | ||
access_token: string; | ||
expires_in: number; | ||
declare class ChatCompletion extends BaseClient { | ||
/** | ||
* 千帆大模型 | ||
* @param options 配置选项,可选参数包括 QIANFAN_AK、QIANFAN_SK、QIANFAN_ACCESS_KEY、QIANFAN_SECRET_KEY | ||
*/ | ||
constructor(options?: { | ||
QIANFAN_AK?: string; | ||
QIANFAN_SK?: string; | ||
QIANFAN_ACCESS_KEY?: string; | ||
QIANFAN_SECRET_KEY?: string; | ||
}); | ||
/** | ||
* 发送请求 | ||
* | ||
* @param model ChatModel类型参数 | ||
* @param body ChatBody类型参数 | ||
* @param stream 是否开启流式处理,默认为false | ||
* @returns Promise<ChatResp | AsyncIterable<ChatResp>> | ||
*/ | ||
private sendRequest; | ||
/** | ||
* chat | ||
@@ -39,4 +12,4 @@ * @param body 聊天请求体 | ||
*/ | ||
chat(body: ChatBody, model?: ChatModel): Promise<ChatResp | AsyncIterable<ChatResp>>; | ||
chat(body: ChatBody, model?: ChatModel): Promise<Resp | AsyncIterable<Resp>>; | ||
} | ||
export default ChatCompletion; |
@@ -1,28 +0,13 @@ | ||
import { RespBase, CompletionBody } from '../interface'; | ||
import { BaseClient } from '../Base'; | ||
import { CompletionBody, Resp } from '../interface'; | ||
import { CompletionModel } from './utils'; | ||
export declare class Completions { | ||
private controller; | ||
private QIANFAN_AK?; | ||
private QIANFAN_SK?; | ||
private QIANFAN_ACCESS_KEY?; | ||
private QIANFAN_SECRET_KEY?; | ||
private Endpoint?; | ||
private headers; | ||
private axiosInstance; | ||
access_token: string; | ||
expires_in: number; | ||
declare class Completions extends BaseClient { | ||
/** | ||
* 千帆大模型 | ||
* @param options 配置选项,可选参数包括 QIANFAN_AK、QIANFAN_SK、QIANFAN_ACCESS_KEY、QIANFAN_SECRET_KEY、Endpoint | ||
* 续写 | ||
* @param body 续写请求体 | ||
* @param model 续写模型,默认为 'ERNIE-Bot-turbo' | ||
* @returns 返回 Promise 对象,异步获取续写结果 | ||
*/ | ||
constructor(options?: { | ||
QIANFAN_AK?: string; | ||
QIANFAN_SK?: string; | ||
QIANFAN_ACCESS_KEY?: string; | ||
QIANFAN_SECRET_KEY?: string; | ||
Endpoint?: string; | ||
}); | ||
private sendRequest; | ||
completions(body: CompletionBody, model?: CompletionModel): Promise<RespBase | AsyncIterable<RespBase>>; | ||
completions(body: CompletionBody, model?: CompletionModel): Promise<Resp | AsyncIterable<Resp>>; | ||
} | ||
export default Completions; |
@@ -1,4 +0,5 @@ | ||
export declare const base_host = "https://aip.baidubce.com"; | ||
export declare const base_path = "/rpc/2.0/ai_custom/v1/wenxinworkshop"; | ||
export declare const api_base: string; | ||
import { APIErrorCode } from './enum'; | ||
export declare const BASE_HOST = "https://aip.baidubce.com"; | ||
export declare const BASE_PATH = "/rpc/2.0/ai_custom/v1/wenxinworkshop"; | ||
export declare const API_BASE: string; | ||
export declare const DEFAULT_HEADERS: { | ||
@@ -8,1 +9,2 @@ 'Content-Type': string; | ||
}; | ||
export declare const RETRYCODE: APIErrorCode[]; |
@@ -0,26 +1,13 @@ | ||
import { BaseClient } from '../Base'; | ||
import { EmbeddingBody, EmbeddingResp } from '../interface'; | ||
import { EmbeddingModel } from './utils'; | ||
export declare class Eembedding { | ||
private QIANFAN_AK?; | ||
private QIANFAN_SK?; | ||
private QIANFAN_ACCESS_KEY?; | ||
private QIANFAN_SECRET_KEY?; | ||
private Type; | ||
private headers; | ||
private axiosInstance; | ||
access_token: string; | ||
expires_in: number; | ||
declare class Eembedding extends BaseClient { | ||
/** | ||
* 千帆大模型 | ||
* @param options 配置选项,可选参数包括 QIANFAN_AK、QIANFAN_SK、QIANFAN_ACCESS_KEY、QIANFAN_SECRET_KEY | ||
* 向量化 | ||
* @param body 请求体 | ||
* @param model 向量化模型,默认为'Embedding-V1' | ||
* @returns Promise<Resp | AsyncIterable<Resp>> | ||
*/ | ||
constructor(options?: { | ||
QIANFAN_AK?: string; | ||
QIANFAN_SK?: string; | ||
QIANFAN_ACCESS_KEY?: string; | ||
QIANFAN_SECRET_KEY?: string; | ||
}); | ||
private sendRequest; | ||
embedding(body: EmbeddingBody, model?: EmbeddingModel): Promise<EmbeddingResp>; | ||
} | ||
export default Eembedding; |
@@ -14,3 +14,3 @@ /// <reference types="node" /> | ||
constructor(config: any); | ||
sendRequest(httpMethod: string, path: string, body?: string | Buffer | stream.Readable, headers?: Record<string, any>, outputStream?: boolean | stream.Writable, params?: Record<string, any>, signFunction?: () => [string, string] | string): Q.Promise<any>; | ||
sendRequest(httpMethod: string, path: string, body?: string | Buffer | stream.Readable | any, headers?: Record<string, any>, outputStream?: boolean | stream.Writable, params?: Record<string, any>, signFunction?: () => [string, string] | string): Q.Promise<any>; | ||
private _doRequest; | ||
@@ -17,0 +17,0 @@ establishSSEConnection(options: AxiosRequestConfig): Promise<AsyncIterable<any>>; |
@@ -1,5 +0,5 @@ | ||
import ChatCompletion from "./ChatCompletion"; | ||
import Completions from "./Completions"; | ||
import Eembedding from "./Embedding"; | ||
import { setEnvVariable } from "./utils"; | ||
import ChatCompletion from './ChatCompletion'; | ||
import Completions from './Completions'; | ||
import Eembedding from './Embedding'; | ||
import { setEnvVariable } from './utils'; | ||
export { ChatCompletion, Completions, Eembedding, setEnvVariable }; |
@@ -215,11 +215,11 @@ /** | ||
/** | ||
* 当前生成的结果是否被截断 | ||
*/ | ||
* 当前生成的结果是否被截断 | ||
*/ | ||
is_truncated?: boolean; | ||
/** | ||
* 表示用户输入是否存在安全,是否关闭当前会话,清理历史会话信息 | ||
* | ||
* true:是,表示用户输入存在安全风险,建议关闭当前会话,清理历史会话信息 | ||
* false:否,表示用户输入无安全风险 | ||
*/ | ||
* 表示用户输入是否存在安全,是否关闭当前会话,清理历史会话信息 | ||
* | ||
* true:是,表示用户输入存在安全风险,建议关闭当前会话,清理历史会话信息 | ||
* false:否,表示用户输入无安全风险 | ||
*/ | ||
need_clear_history: boolean; | ||
@@ -309,2 +309,5 @@ /** | ||
} | ||
export type ReqBody = ChatBody | CompletionBody | EmbeddingBody; | ||
export type Resp = RespBase | ChatResp | EmbeddingResp; | ||
export type AsyncIterableType = AsyncIterable<ChatResp | RespBase>; | ||
export {}; |
@@ -1,8 +0,10 @@ | ||
import { AxiosRequestConfig } from 'axios'; | ||
import { AccessTokenResp, ChatBody, CompletionBody, EmbeddingBody, IAMConfig, QfLLMInfoMap } from './interface'; | ||
import { ChatBody, CompletionBody, EmbeddingBody, IAMConfig, QfLLMInfoMap, ReqBody } from './interface'; | ||
/** | ||
* 使用 AK,SK 生成鉴权签名(Access Token) | ||
* @return string 鉴权签名信息(Access Token) | ||
* 获取访问令牌的URL地址 | ||
* | ||
* @param QIANFAN_AK 百度云AK | ||
* @param QIANFAN_SK 百度云SK | ||
* @returns 返回访问令牌的URL地址 | ||
*/ | ||
export declare function getAccessToken(API_KEY: string, SECRET_KEY: string, headers: AxiosRequestConfig['headers']): Promise<AccessTokenResp>; | ||
export declare function getAccessTokenUrl(QIANFAN_AK: string, QIANFAN_SK: string): string; | ||
export declare function getIAMConfig(ak: string, sk: string): IAMConfig; | ||
@@ -35,1 +37,16 @@ /** | ||
export declare function setEnvVariable(key: string, value: string): void; | ||
/** | ||
* 获取路径和请求体 | ||
* | ||
* @param model 模型 | ||
* @param modelInfoMap 模型信息映射 | ||
* @param body 请求体,可选 | ||
* @param endpoint 请求路径,可选 | ||
* @param type 请求类型,可选 | ||
* @returns 包含路径和请求体的对象 | ||
*/ | ||
export declare function getPathAndBody(model: string, modelInfoMap: QfLLMInfoMap, body?: ReqBody, endpoint?: string, type?: string): { | ||
IAMPath: string; | ||
AKPath: string; | ||
requestBody: string; | ||
}; |
{ | ||
"name": "@baiducloud/qianfan", | ||
"version": "0.0.2", | ||
"version": "0.0.3-beta.0", | ||
"publishConfig": { | ||
@@ -30,3 +30,2 @@ "access": "public", | ||
"rollup": "^4.9.6", | ||
"rollup-plugin-typescript2": "^0.36.0", | ||
"tslib": "^2.6.2", | ||
@@ -42,3 +41,3 @@ "typescript": "^5.3.3", | ||
"@babel/core": "^7.23.9", | ||
"@babel/eslint-parser": "^7.23.9", | ||
"@babel/eslint-parser": "^7.23.10", | ||
"@babel/eslint-plugin": "^7.23.5", | ||
@@ -48,3 +47,6 @@ "@babel/preset-env": "^7.23.9", | ||
"@ecomfe/eslint-config": "^8.0.0", | ||
"@rollup/plugin-commonjs": "^25.0.7", | ||
"@rollup/plugin-eslint": "^9.0.5", | ||
"@rollup/plugin-json": "^6.1.0", | ||
"@rollup/plugin-node-resolve": "^15.2.3", | ||
"@types/jest": "^29.5.11", | ||
@@ -54,7 +56,10 @@ "@types/node": "^20.11.13", | ||
"@types/underscore": "^1.11.15", | ||
"@typescript-eslint/parser": "^7.1.0", | ||
"babel-jest": "^29.7.0", | ||
"eslint": "^8.56.0", | ||
"eslint": "^8.57.0", | ||
"jest": "^29.7.0", | ||
"prettier": "^3.2.5", | ||
"rollup-plugin-typescript2": "^0.36.0", | ||
"ts-node": "^10.9.2" | ||
} | ||
} | ||
} |
@@ -116,3 +116,3 @@ # 百度千帆大模型平台 JavaScript SDK | ||
for await (const chunk of stream as AsyncIterableIterator<any>) { | ||
// process.stdout.write(chunk); | ||
// 返回结果 | ||
} | ||
@@ -153,3 +153,3 @@ } | ||
for await (const chunk of stream as AsyncIterableIterator<any>) { | ||
process.stdout.write(chunk); | ||
// 返回结果 | ||
} | ||
@@ -156,0 +156,0 @@ } |
@@ -15,97 +15,9 @@ // Copyright (c) 2024 Baidu, Inc. All Rights Reserved. | ||
import axios, {AxiosInstance} from 'axios'; | ||
import HttpClient from '../HttpClient'; | ||
import {api_base, DEFAULT_HEADERS, base_path} from '../constant'; | ||
import {getAccessToken, getRequestBody, getModelEndpoint, getIAMConfig, getDefaultConfig} from '../utils'; | ||
import {Stream} from '../streaming'; | ||
import {ChatBody, ChatResp} from '../interface'; | ||
import * as packageJson from '../../package.json'; | ||
import {BaseClient} from '../Base'; | ||
import {ChatBody, Resp} from '../interface'; | ||
import {modelInfoMap, ChatModel} from './utils'; | ||
import {getPathAndBody} from '../utils'; | ||
export class ChatCompletion { | ||
private controller: AbortController; | ||
private QIANFAN_AK?: string; | ||
private QIANFAN_SK?: string; | ||
private QIANFAN_ACCESS_KEY?: string; | ||
private QIANFAN_SECRET_KEY?: string; | ||
private headers = DEFAULT_HEADERS; | ||
private axiosInstance: AxiosInstance; | ||
access_token = ''; | ||
expires_in = 0; | ||
class ChatCompletion extends BaseClient { | ||
/** | ||
* 千帆大模型 | ||
* @param options 配置选项,可选参数包括 QIANFAN_AK、QIANFAN_SK、QIANFAN_ACCESS_KEY、QIANFAN_SECRET_KEY | ||
*/ | ||
constructor(options?: { QIANFAN_AK?: string, QIANFAN_SK?: string, QIANFAN_ACCESS_KEY?: string, QIANFAN_SECRET_KEY?: string}) { | ||
const defaultConfig = getDefaultConfig(); | ||
this.QIANFAN_AK = options?.QIANFAN_AK ?? defaultConfig.QIANFAN_AK; | ||
this.QIANFAN_SK = options?.QIANFAN_SK ?? defaultConfig.QIANFAN_SK; | ||
this.QIANFAN_ACCESS_KEY = options?.QIANFAN_ACCESS_KEY ?? defaultConfig.QIANFAN_ACCESS_KEY; | ||
this.QIANFAN_SECRET_KEY = options?.QIANFAN_SECRET_KEY ?? defaultConfig.QIANFAN_SECRET_KEY; | ||
this.axiosInstance = axios.create(); | ||
this.controller = new AbortController(); | ||
} | ||
/** | ||
* 发送请求 | ||
* | ||
* @param model ChatModel类型参数 | ||
* @param body ChatBody类型参数 | ||
* @param stream 是否开启流式处理,默认为false | ||
* @returns Promise<ChatResp | AsyncIterable<ChatResp>> | ||
*/ | ||
private async sendRequest(model: ChatModel, body: ChatBody, stream = false): Promise<ChatResp | AsyncIterable<ChatResp>> { | ||
const endpoint = getModelEndpoint(model, modelInfoMap); | ||
const requestBody = getRequestBody(body, packageJson.version); | ||
// IAM鉴权 | ||
if (this.QIANFAN_ACCESS_KEY && this.QIANFAN_SECRET_KEY) { | ||
const config = getIAMConfig(this.QIANFAN_ACCESS_KEY, this.QIANFAN_SECRET_KEY); | ||
const client = new HttpClient(config); | ||
const path = `${base_path}${endpoint}`; | ||
const response = await client.sendRequest('POST', path, requestBody, this.headers, stream); | ||
return response; | ||
} | ||
// AK/SK鉴权 | ||
if (this.QIANFAN_AK && this.QIANFAN_SK) { | ||
const access = await getAccessToken(this.QIANFAN_AK, this.QIANFAN_SK, this.headers); | ||
const url = `${api_base}${endpoint}?access_token=${access.access_token}`; | ||
const options = { | ||
method: 'POST', | ||
url: url, | ||
headers: this.headers, | ||
data: requestBody | ||
}; | ||
// 流式处理 | ||
if (stream) { | ||
try { | ||
const sseStream: AsyncIterable<ChatResp> = Stream.fromSSEResponse(await fetch(url, { | ||
method: 'POST', | ||
headers: this.headers, | ||
body: requestBody | ||
}), this.controller) as any; | ||
return sseStream; | ||
} | ||
catch (error) { | ||
throw new Error(error); | ||
} | ||
} | ||
else { | ||
try { | ||
const resp = await this.axiosInstance.request(options); | ||
return resp.data as ChatResp; | ||
} | ||
catch (error) { | ||
throw new Error(error); | ||
} | ||
} | ||
} | ||
throw new Error('请设置AK/SK或QIANFAN_ACCESS_KEY/QIANFAN_SECRET_KEY'); | ||
} | ||
/** | ||
* chat | ||
@@ -117,5 +29,6 @@ * @param body 聊天请求体 | ||
*/ | ||
public async chat(body: ChatBody, model: ChatModel = 'ERNIE-Bot-turbo'): Promise<ChatResp | AsyncIterable<ChatResp>> { | ||
public async chat(body: ChatBody, model: ChatModel = 'ERNIE-Bot-turbo'): Promise<Resp | AsyncIterable<Resp>> { | ||
const stream = body.stream ?? false; | ||
return this.sendRequest(model, body, stream); | ||
const {IAMPath, AKPath, requestBody} = getPathAndBody(model, modelInfoMap, body, this.Endpoint, 'chat'); | ||
return this.sendRequest(IAMPath, AKPath, requestBody, stream); | ||
} | ||
@@ -122,0 +35,0 @@ } |
@@ -15,92 +15,21 @@ // Copyright (c) 2024 Baidu, Inc. All Rights Reserved. | ||
import axios, {AxiosInstance} from 'axios'; | ||
import HttpClient from '../HttpClient'; | ||
import {DEFAULT_HEADERS} from '../constant'; | ||
import {getAccessToken, getRequestBody, getIAMConfig, getPath, getDefaultConfig} from '../utils'; | ||
import {Stream} from '../streaming'; | ||
import {RespBase, CompletionBody} from '../interface'; | ||
import * as packageJson from '../../package.json'; | ||
import {CompletionModel, modelInfoMap} from './utils'; | ||
import {BaseClient} from '../Base'; | ||
import {CompletionBody, Resp} from '../interface'; | ||
import {modelInfoMap, CompletionModel} from './utils'; | ||
import {getPathAndBody} from '../utils'; | ||
export class Completions { | ||
private controller: AbortController; | ||
private QIANFAN_AK?: string; | ||
private QIANFAN_SK?: string; | ||
private QIANFAN_ACCESS_KEY?: string; | ||
private QIANFAN_SECRET_KEY?: string; | ||
private Endpoint?: string = ''; | ||
private headers = DEFAULT_HEADERS; | ||
private axiosInstance: AxiosInstance; | ||
access_token = ''; | ||
expires_in = 0; | ||
class Completions extends BaseClient { | ||
/** | ||
* 千帆大模型 | ||
* @param options 配置选项,可选参数包括 QIANFAN_AK、QIANFAN_SK、QIANFAN_ACCESS_KEY、QIANFAN_SECRET_KEY、Endpoint | ||
* 续写 | ||
* @param body 续写请求体 | ||
* @param model 续写模型,默认为 'ERNIE-Bot-turbo' | ||
* @returns 返回 Promise 对象,异步获取续写结果 | ||
*/ | ||
constructor(options?: { QIANFAN_AK?: string, QIANFAN_SK?: string, QIANFAN_ACCESS_KEY?: string, QIANFAN_SECRET_KEY?: string, Endpoint?: string}) { | ||
const defaultConfig = getDefaultConfig(); | ||
this.QIANFAN_AK = options?.QIANFAN_AK ?? defaultConfig.QIANFAN_AK; | ||
this.QIANFAN_SK = options?.QIANFAN_SK ?? defaultConfig.QIANFAN_SK; | ||
this.QIANFAN_ACCESS_KEY = options?.QIANFAN_ACCESS_KEY ?? defaultConfig.QIANFAN_ACCESS_KEY; | ||
this.QIANFAN_SECRET_KEY = options?.QIANFAN_SECRET_KEY ?? defaultConfig.QIANFAN_SECRET_KEY; | ||
this.Endpoint = options?.Endpoint; | ||
this.axiosInstance = axios.create(); | ||
} | ||
private async sendRequest(model: CompletionModel, body: CompletionBody, stream = false, endpoint?:string): Promise<RespBase | AsyncIterable<RespBase>> { | ||
const path = getPath(model, modelInfoMap, endpoint, 'completions'); | ||
const requestBody = getRequestBody(body, packageJson.version); | ||
// IAM鉴权 | ||
if (this.QIANFAN_ACCESS_KEY && this.QIANFAN_SECRET_KEY) { | ||
const config = getIAMConfig(this.QIANFAN_ACCESS_KEY, this.QIANFAN_SECRET_KEY); | ||
const client = new HttpClient(config); | ||
const response = await client.sendRequest('POST', path, requestBody, this.headers, stream); | ||
return response as RespBase; | ||
} | ||
// AK/SK鉴权 | ||
if (this.QIANFAN_AK && this.QIANFAN_SK) { | ||
const access = await getAccessToken(this.QIANFAN_AK, this.QIANFAN_SK, this.headers); | ||
// 重试问题初始化进入不了 TODO!! | ||
// if (access.expires_in < Date.now() / 1000) { | ||
const url = `${path}?access_token=${access.access_token}`; | ||
const options = { | ||
method: 'POST', | ||
url: url, | ||
headers: this.headers, | ||
data: requestBody | ||
}; | ||
// 流式处理 | ||
if (stream) { | ||
try { | ||
const sseStream: AsyncIterable<RespBase> = Stream.fromSSEResponse(await fetch(url, { | ||
method: 'POST', | ||
headers: this.headers, | ||
body: requestBody | ||
}), this.controller) as any; | ||
return sseStream; | ||
} | ||
catch (error) { | ||
throw new Error(error); | ||
} | ||
} | ||
else { | ||
try { | ||
const resp = await this.axiosInstance.request(options); | ||
return resp.data as RespBase; | ||
} | ||
catch (error) { | ||
throw new Error(error); | ||
} | ||
} | ||
// } | ||
} | ||
throw new Error('请设置AK/SK或QIANFAN_ACCESS_KEY/QIANFAN_SECRET_KEY'); | ||
} | ||
public async completions(body: CompletionBody, model: CompletionModel = 'ERNIE-Bot-turbo'): Promise<RespBase | AsyncIterable<RespBase>> { | ||
public async completions( | ||
body: CompletionBody, | ||
model: CompletionModel = 'ERNIE-Bot-turbo' | ||
): Promise<Resp | AsyncIterable<Resp>> { | ||
const stream = body.stream ?? false; | ||
return this.sendRequest(model, body, stream, this.Endpoint); | ||
const {IAMPath, AKPath, requestBody} = getPathAndBody(model, modelInfoMap, body, this.Endpoint, 'completions'); | ||
return this.sendRequest(IAMPath, AKPath, requestBody, stream); | ||
} | ||
@@ -107,0 +36,0 @@ } |
@@ -14,9 +14,17 @@ // Copyright (c) 2024 Baidu, Inc. All Rights Reserved. | ||
// limitations under the License. | ||
import {APIErrorCode} from './enum'; | ||
export const base_host = 'https://aip.baidubce.com'; | ||
export const base_path = '/rpc/2.0/ai_custom/v1/wenxinworkshop'; | ||
export const api_base = base_host + base_path; | ||
export const BASE_HOST = 'https://aip.baidubce.com'; | ||
export const BASE_PATH = '/rpc/2.0/ai_custom/v1/wenxinworkshop'; | ||
export const API_BASE = BASE_HOST + BASE_PATH; | ||
export const DEFAULT_HEADERS = { | ||
'Content-Type': 'application/json', | ||
Accept: 'application/json', | ||
}; | ||
}; | ||
export const RETRYCODE = [ | ||
APIErrorCode.TPMLimitReached, | ||
APIErrorCode.ConsoleInternalError, | ||
APIErrorCode.ServerHighLoad, | ||
APIErrorCode.QPSLimitReached, | ||
]; |
@@ -15,73 +15,18 @@ // Copyright (c) 2024 Baidu, Inc. All Rights Reserved. | ||
import axios, {AxiosInstance} from 'axios'; | ||
import HttpClient from '../HttpClient'; | ||
import {api_base, DEFAULT_HEADERS, base_path} from '../constant'; | ||
import {getAccessToken, getRequestBody, getModelEndpoint, getIAMConfig, getDefaultConfig} from '../utils'; | ||
import {BaseClient} from '../Base'; | ||
import {EmbeddingBody, EmbeddingResp} from '../interface'; | ||
import * as packageJson from '../../package.json'; | ||
import {modelInfoMap, EmbeddingModel} from './utils'; | ||
import {getPathAndBody} from '../utils'; | ||
export class Eembedding { | ||
private QIANFAN_AK?: string; | ||
private QIANFAN_SK?: string; | ||
private QIANFAN_ACCESS_KEY?: string; | ||
private QIANFAN_SECRET_KEY?: string; | ||
private Type = 'IAM'; | ||
private headers = DEFAULT_HEADERS; | ||
private axiosInstance: AxiosInstance; | ||
access_token = ''; | ||
expires_in = 0; | ||
class Eembedding extends BaseClient { | ||
/** | ||
* 千帆大模型 | ||
* @param options 配置选项,可选参数包括 QIANFAN_AK、QIANFAN_SK、QIANFAN_ACCESS_KEY、QIANFAN_SECRET_KEY | ||
* 向量化 | ||
* @param body 请求体 | ||
* @param model 向量化模型,默认为'Embedding-V1' | ||
* @returns Promise<Resp | AsyncIterable<Resp>> | ||
*/ | ||
constructor(options?: { QIANFAN_AK?: string, QIANFAN_SK?: string, QIANFAN_ACCESS_KEY?: string, QIANFAN_SECRET_KEY?: string}) { | ||
const defaultConfig = getDefaultConfig(); | ||
this.QIANFAN_AK = options?.QIANFAN_AK ?? defaultConfig.QIANFAN_AK; | ||
this.QIANFAN_SK = options?.QIANFAN_SK ?? defaultConfig.QIANFAN_SK; | ||
this.QIANFAN_ACCESS_KEY = options?.QIANFAN_ACCESS_KEY ?? defaultConfig.QIANFAN_ACCESS_KEY; | ||
this.QIANFAN_SECRET_KEY = options?.QIANFAN_SECRET_KEY ?? defaultConfig.QIANFAN_SECRET_KEY; | ||
this.axiosInstance = axios.create(); | ||
} | ||
private async sendRequest(model: EmbeddingModel, body: EmbeddingBody): Promise<EmbeddingResp> { | ||
const endpoint = getModelEndpoint(model, modelInfoMap); | ||
const requestBody = getRequestBody(body, packageJson.version); | ||
// IAM鉴权 | ||
if (this.QIANFAN_ACCESS_KEY && this.QIANFAN_SECRET_KEY) { | ||
const config = getIAMConfig(this.QIANFAN_ACCESS_KEY, this.QIANFAN_SECRET_KEY); | ||
const client = new HttpClient(config); | ||
const path = `${base_path}${endpoint}`; | ||
const response = await client.sendRequest('POST', path, requestBody, this.headers); | ||
return response as EmbeddingResp; | ||
} | ||
// AK/SK鉴权 | ||
if (this.QIANFAN_AK && this.QIANFAN_SK) { | ||
const access = await getAccessToken(this.QIANFAN_AK, this.QIANFAN_SK, this.headers); | ||
// 重试问题初始化进入不了 TODO!! | ||
// if (access.expires_in < Date.now() / 1000) { | ||
const url = `${api_base}${endpoint}?access_token=${access.access_token}`; | ||
const options = { | ||
method: 'POST', | ||
url: url, | ||
headers: this.headers, | ||
data: requestBody | ||
}; | ||
try { | ||
const resp = await this.axiosInstance.request(options); | ||
return resp.data as EmbeddingResp; | ||
} | ||
catch (error) { | ||
throw new Error(error); | ||
} | ||
// } | ||
} | ||
throw new Error('请设置AK/SK或QIANFAN_ACCESS_KEY/QIANFAN_SECRET_KEY'); | ||
} | ||
public async embedding(body: EmbeddingBody, model: EmbeddingModel = 'Embedding-V1'): Promise<EmbeddingResp> { | ||
return this.sendRequest(model, body); | ||
const {IAMPath, AKPath, requestBody} = getPathAndBody(model, modelInfoMap, body, this.Endpoint, 'chat'); | ||
const resp = await this.sendRequest(IAMPath, AKPath, requestBody); | ||
return resp as EmbeddingResp; | ||
} | ||
@@ -88,0 +33,0 @@ } |
@@ -40,6 +40,7 @@ // Copyright (c) 2024 Baidu, Inc. All Rights Reserved. | ||
// 检查是否在浏览器环境中 | ||
[H.USER_AGENT]: typeof navigator !== 'undefined' && navigator.userAgent | ||
? navigator.userAgent | ||
: `bce-sdk-nodejs/${version}/${process.platform}/${process.version}`, | ||
[H.X_BCE_DATE]: new Date().toISOString().replace(/\.\d+Z$/, 'Z') | ||
[H.USER_AGENT]: | ||
typeof navigator !== 'undefined' && navigator.userAgent | ||
? navigator.userAgent | ||
: `bce-sdk-nodejs/${version}/${process.platform}/${process.version}`, | ||
[H.X_BCE_DATE]: new Date().toISOString().replace(/\.\d+Z$/, 'Z'), | ||
}; | ||
@@ -55,3 +56,3 @@ private axiosInstance: AxiosInstance; | ||
path: string, | ||
body?: string | Buffer | stream.Readable, | ||
body?: string | Buffer | stream.Readable | any, | ||
headers?: Record<string, any>, | ||
@@ -83,3 +84,3 @@ outputStream?: boolean | stream.Writable, | ||
headers: _headers, | ||
data: body | ||
data: body, | ||
}; | ||
@@ -102,3 +103,2 @@ return client._doRequest(requstOption, outputStream); | ||
} | ||
} | ||
@@ -109,7 +109,10 @@ | ||
try { | ||
const sseStream: AsyncIterable<any> = Stream.fromSSEResponse(await fetch(url, { | ||
method: 'POST', | ||
headers: headers as any, | ||
body: data | ||
}), this.controller) as any; | ||
const sseStream: AsyncIterable<any> = Stream.fromSSEResponse( | ||
await fetch(url, { | ||
method: 'POST', | ||
headers: headers as any, | ||
body: data, | ||
}), | ||
this.controller | ||
) as any; | ||
return sseStream; | ||
@@ -129,2 +132,6 @@ } | ||
const responseBody = response.data; | ||
if (responseBody.error_code) { | ||
const message = JSON.stringify(responseBody); | ||
throw new Error(message); | ||
} | ||
if (statusCode >= 100 && statusCode < 200) { | ||
@@ -136,3 +143,3 @@ throw this.failure(statusCode, 'Can not handle 1xx http status code.'); | ||
} | ||
return response; | ||
return responseBody; | ||
} | ||
@@ -148,3 +155,5 @@ | ||
private setAuthorizationHeader( | ||
signFunction: ((credentials: any, method: any, path: any, headers: any) => [string, string] | string) | undefined, | ||
signFunction: | ||
| ((credentials: any, method: any, path: any, headers: any) => [string, string] | string) | ||
| undefined, | ||
headers: Record<string, any>, | ||
@@ -201,3 +210,3 @@ options: http.RequestOptions | ||
// https://en.wikipedia.org/wiki/Percent-encoding | ||
return urlEncodeStr.replace(/[()'!~.*\-_]/g, (char : any) => { | ||
return urlEncodeStr.replace(/[()'!~.*\-_]/g, (char: any) => { | ||
return '%' + char.charCodeAt(0).toString(16); | ||
@@ -243,3 +252,2 @@ }); | ||
private isPromise(obj: any): obj is Q.Promise<any> { | ||
@@ -255,2 +263,2 @@ return obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function'; | ||
export default HttpClient; | ||
export default HttpClient; |
@@ -15,12 +15,7 @@ // Copyright (c) 2024 Baidu, Inc. All Rights Reserved. | ||
import ChatCompletion from "./ChatCompletion"; | ||
import Completions from "./Completions"; | ||
import Eembedding from "./Embedding"; | ||
import {setEnvVariable} from "./utils"; | ||
import ChatCompletion from './ChatCompletion'; | ||
import Completions from './Completions'; | ||
import Eembedding from './Embedding'; | ||
import {setEnvVariable} from './utils'; | ||
export { | ||
ChatCompletion, | ||
Completions, | ||
Eembedding, | ||
setEnvVariable | ||
} | ||
export {ChatCompletion, Completions, Eembedding, setEnvVariable}; |
@@ -39,3 +39,3 @@ // Copyright (c) 2024 Baidu, Inc. All Rights Reserved. | ||
export interface IAMConfig{ | ||
export interface IAMConfig { | ||
credentials: { | ||
@@ -207,3 +207,3 @@ ak: string; | ||
*/ | ||
export interface RespBase{ | ||
export interface RespBase { | ||
/** | ||
@@ -241,8 +241,8 @@ * 本轮对话的id | ||
export interface ChatResp extends RespBase{ | ||
/** | ||
export interface ChatResp extends RespBase { | ||
/** | ||
* 当前生成的结果是否被截断 | ||
*/ | ||
is_truncated?: boolean; | ||
/** | ||
is_truncated?: boolean; | ||
/** | ||
* 表示用户输入是否存在安全,是否关闭当前会话,清理历史会话信息 | ||
@@ -274,11 +274,10 @@ * | ||
export interface CompletionBody { | ||
/* | ||
* 请求信息 | ||
*/ | ||
prompt: string, | ||
* 请求信息 | ||
*/ | ||
prompt: string; | ||
/* | ||
* 是否以流式接口的形式返回数据,默认false | ||
*/ | ||
* 是否以流式接口的形式返回数据,默认false | ||
*/ | ||
stream?: boolean; | ||
@@ -288,30 +287,30 @@ /* | ||
* 2)范围 (0, 1.0],不能为0 | ||
*/ | ||
*/ | ||
temperature?: number; | ||
/* | ||
*Top-K 采样参数,在每轮token生成时,保留k个概率最高的token作为候选。说明: | ||
*(1)影响输出文本的多样性,取值越大,生成文本的多样性越强 | ||
*(2)取值范围:正整数 | ||
*/ | ||
top_k?: number; | ||
*Top-K 采样参数,在每轮token生成时,保留k个概率最高的token作为候选。说明: | ||
*(1)影响输出文本的多样性,取值越大,生成文本的多样性越强 | ||
*(2)取值范围:正整数 | ||
*/ | ||
top_k?: number; | ||
/* | ||
*(1)影响输出文本的多样性,取值越大,生成文本的多样性越强 | ||
*(2)取值范围 [0, 1.0] | ||
*/ | ||
top_p?: number; | ||
*(1)影响输出文本的多样性,取值越大,生成文本的多样性越强 | ||
*(2)取值范围 [0, 1.0] | ||
*/ | ||
top_p?: number; | ||
/* | ||
* 通过对已生成的token增加惩罚,减少重复生成的现象。说明: | ||
*(1)值越大表示惩罚越大 | ||
*(2)取值范围:[1.0, 2.0] | ||
*/ | ||
penalty_score? :number; | ||
* 通过对已生成的token增加惩罚,减少重复生成的现象。说明: | ||
*(1)值越大表示惩罚越大 | ||
*(2)取值范围:[1.0, 2.0] | ||
*/ | ||
penalty_score?: number; | ||
/* | ||
* 生成停止标识。当模型生成结果以stop中某个元素结尾时,停止文本生成。说明: | ||
*(1)每个元素长度不超过20字符。 | ||
*(2)最多4个元素 | ||
*/ | ||
* 生成停止标识。当模型生成结果以stop中某个元素结尾时,停止文本生成。说明: | ||
*(1)每个元素长度不超过20字符。 | ||
*(2)最多4个元素 | ||
*/ | ||
stop?: string[]; | ||
/* | ||
* 表示最终用户的唯一标识符 | ||
*/ | ||
* 表示最终用户的唯一标识符 | ||
*/ | ||
user_id?: string; | ||
@@ -326,3 +325,3 @@ extra_parameters?: { | ||
export interface EmbeddingBody{ | ||
export interface EmbeddingBody { | ||
/** | ||
@@ -332,3 +331,3 @@ * 输入文本以获取embeddings | ||
*(2)文本数量不超过16 | ||
* (3)每个文本token数不超过384且长度不超过1000个字符 | ||
* (3)每个文本token数不超过384且长度不超过1000个字符 | ||
*/ | ||
@@ -348,3 +347,3 @@ input: string[]; | ||
interface EmbeddingData{ | ||
interface EmbeddingData { | ||
/** | ||
@@ -357,10 +356,10 @@ * 固定值"embedding" | ||
*/ | ||
embedding: number[]; | ||
embedding: number[]; | ||
/* | ||
* 序号 | ||
*/ | ||
* 序号 | ||
*/ | ||
index: number; | ||
} | ||
export interface EmbeddingResp{ | ||
export interface EmbeddingResp { | ||
/** | ||
@@ -384,1 +383,5 @@ * 本轮对话的id | ||
} | ||
export type ReqBody = ChatBody | CompletionBody | EmbeddingBody; | ||
export type Resp = RespBase | ChatResp | EmbeddingResp; | ||
export type AsyncIterableType = AsyncIterable<ChatResp | RespBase>; |
112
src/utils.ts
@@ -15,7 +15,7 @@ // Copyright (c) 2024 Baidu, Inc. All Rights Reserved. | ||
import axios, {AxiosRequestConfig} from 'axios'; | ||
import * as dotenv from "dotenv"; | ||
import * as dotenv from 'dotenv'; | ||
import {base_host, base_path, api_base} from './constant'; | ||
import {AccessTokenResp, ChatBody, CompletionBody, EmbeddingBody, IAMConfig, QfLLMInfoMap} from './interface'; | ||
import {BASE_HOST, BASE_PATH, API_BASE} from './constant'; | ||
import {ChatBody, CompletionBody, EmbeddingBody, IAMConfig, QfLLMInfoMap, ReqBody} from './interface'; | ||
import * as packageJson from '../package.json'; | ||
@@ -25,21 +25,10 @@ dotenv.config(); | ||
/** | ||
* 使用 AK,SK 生成鉴权签名(Access Token) | ||
* @return string 鉴权签名信息(Access Token) | ||
* 获取访问令牌的URL地址 | ||
* | ||
* @param QIANFAN_AK 百度云AK | ||
* @param QIANFAN_SK 百度云SK | ||
* @returns 返回访问令牌的URL地址 | ||
*/ | ||
export async function getAccessToken( | ||
API_KEY: string, | ||
SECRET_KEY: string, | ||
headers: AxiosRequestConfig['headers'] | ||
): Promise<AccessTokenResp> { | ||
const url = `https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=${API_KEY}&client_secret=${SECRET_KEY}`; | ||
const resp = await axios.post(url, {}, {headers, withCredentials: false}); | ||
if (resp.data?.error && resp.data?.error_description) { | ||
throw new Error(resp.data.error_description); | ||
} | ||
const expires_in = resp.data.expires_in + Date.now() / 1000; | ||
return { | ||
access_token: resp.data.access_token, | ||
expires_in, | ||
}; | ||
export function getAccessTokenUrl(QIANFAN_AK: string, QIANFAN_SK: string): string { | ||
return `https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=${QIANFAN_AK}&client_secret=${QIANFAN_SK}`; | ||
} | ||
@@ -53,3 +42,3 @@ | ||
}, | ||
endpoint: base_host, | ||
endpoint: BASE_HOST, | ||
}; | ||
@@ -69,3 +58,3 @@ } | ||
...body.extra_parameters, | ||
'request_source': `qianfan_js_sdk_v${version}`, | ||
request_source: `qianfan_js_sdk_v${version}`, | ||
}; | ||
@@ -96,11 +85,19 @@ return JSON.stringify(body); | ||
* 获取请求路径 | ||
*/ | ||
export const getPath = (model: string, modelInfoMap: QfLLMInfoMap, Authentication:string, endpoint: string = '', type?: string): string => { | ||
*/ | ||
export const getPath = ( | ||
model: string, | ||
modelInfoMap: QfLLMInfoMap, | ||
Authentication: string, | ||
endpoint: string = '', | ||
type?: string | ||
): string => { | ||
let path: string; | ||
if (model && modelInfoMap[model]) { | ||
const _endpoint = getModelEndpoint(model, modelInfoMap); | ||
path = Authentication ==='IAM' ? `${base_path}${_endpoint}` : `${api_base}${_endpoint}`; | ||
} else if (endpoint && type) { | ||
path = Authentication ==='IAM' ? `${base_path}/${type}/${endpoint}` : `${api_base}/${type}/${endpoint}`; | ||
} else { | ||
path = Authentication === 'IAM' ? `${BASE_PATH}${_endpoint}` : `${API_BASE}${_endpoint}`; | ||
} | ||
else if (endpoint && type) { | ||
path = Authentication === 'IAM' ? `${BASE_PATH}/${type}/${endpoint}` : `${API_BASE}/${type}/${endpoint}`; | ||
} | ||
else { | ||
throw new Error('Path not found'); | ||
@@ -112,3 +109,5 @@ } | ||
export const castToError = (err: any): Error => { | ||
if (err instanceof Error) return err; | ||
if (err instanceof Error) { | ||
return err; | ||
} | ||
return new Error(err); | ||
@@ -128,12 +127,12 @@ }; | ||
export function getDefaultConfig(): Record<string, string> { | ||
const envVariables = ['QIANFAN_AK', 'QIANFAN_SK', 'QIANFAN_ACCESS_KEY', 'QIANFAN_SECRET_KEY']; | ||
const obj: Record<string, string> = {}; | ||
for (const key of envVariables) { | ||
const value = process.env[key]; | ||
if (value !== undefined) { | ||
obj[key] = value; | ||
const envVariables = ['QIANFAN_AK', 'QIANFAN_SK', 'QIANFAN_ACCESS_KEY', 'QIANFAN_SECRET_KEY']; | ||
const obj: Record<string, string> = {}; | ||
for (const key of envVariables) { | ||
const value = process.env[key]; | ||
if (value !== undefined) { | ||
obj[key] = value; | ||
} | ||
} | ||
} | ||
return obj; | ||
return obj; | ||
} | ||
@@ -143,3 +142,34 @@ | ||
export function setEnvVariable(key: string, value: string) { | ||
process.env[key] = value; | ||
} | ||
process.env[key] = value; | ||
} | ||
/** | ||
* 获取路径和请求体 | ||
* | ||
* @param model 模型 | ||
* @param modelInfoMap 模型信息映射 | ||
* @param body 请求体,可选 | ||
* @param endpoint 请求路径,可选 | ||
* @param type 请求类型,可选 | ||
* @returns 包含路径和请求体的对象 | ||
*/ | ||
export function getPathAndBody( | ||
model: string, | ||
modelInfoMap: QfLLMInfoMap, | ||
body?: ReqBody, | ||
endpoint?: string, | ||
type?: string | ||
): { | ||
IAMPath: string; | ||
AKPath: string; | ||
requestBody: string; // 根据您的实际情况替换成合适的类型 | ||
} { | ||
const IAMPath = getPath(model, modelInfoMap, 'IAM', endpoint, type); | ||
const AKPath = getPath(model, modelInfoMap, 'AK', endpoint, type); | ||
const requestBody = getRequestBody(body, packageJson.version); | ||
return { | ||
IAMPath, | ||
AKPath, | ||
requestBody, | ||
}; | ||
} |
{ | ||
"compilerOptions": { | ||
"declaration": true, | ||
"outDir": "./dist", | ||
"target": "ES2020", | ||
"lib": ["ES2020", "DOM", "DOM.Iterable"], | ||
"module": "ESNext", | ||
"sourceMap": true, | ||
"esModuleInterop": true, | ||
"allowSyntheticDefaultImports": true, | ||
"moduleResolution": "node", | ||
"resolveJsonModule": true, | ||
}, | ||
"include": ["src"], | ||
"exclude": ["node_modules", "dist"] | ||
"compilerOptions": { | ||
"declaration": true, | ||
"outDir": "./dist", | ||
"target": "ES2020", | ||
"lib": ["ES2020", "DOM", "DOM.Iterable", "dom", "esnext"], | ||
"module": "ES2015", | ||
"sourceMap": true, | ||
"esModuleInterop": true, | ||
"allowSyntheticDefaultImports": true, | ||
"moduleResolution": "node", | ||
"resolveJsonModule": true, | ||
"noEmit": true | ||
}, | ||
"include": ["src"], | ||
"exclude": ["node_modules", "dist"] | ||
} |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 4 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1307453
10
58
49350
21
36
13
- Removedrollup-plugin-typescript2@^0.36.0
- Removed@rollup/pluginutils@4.2.1(transitive)
- Removedcommondir@1.0.1(transitive)
- Removedestree-walker@2.0.2(transitive)
- Removedfind-cache-dir@3.3.2(transitive)
- Removedfind-up@4.1.0(transitive)
- Removedfs-extra@10.1.0(transitive)
- Removedgraceful-fs@4.2.11(transitive)
- Removedjsonfile@6.1.0(transitive)
- Removedlocate-path@5.0.0(transitive)
- Removedmake-dir@3.1.0(transitive)
- Removedp-limit@2.3.0(transitive)
- Removedp-locate@4.1.0(transitive)
- Removedp-try@2.2.0(transitive)
- Removedpath-exists@4.0.0(transitive)
- Removedpicomatch@2.3.1(transitive)
- Removedpkg-dir@4.2.0(transitive)
- Removedrollup-plugin-typescript2@0.36.0(transitive)
- Removedsemver@6.3.17.6.3(transitive)
- Removeduniversalify@2.0.1(transitive)