Skip to content

Commit

Permalink
浏览器支持自主鉴权和proxy, (#682)
Browse files Browse the repository at this point in the history
* v0.1.5-beta.2

* v0.0.21

* feature: 浏览器支持自主鉴权和proxy

* feature: 浏览器支持自主鉴权和proxy

* feature: 浏览器支持自主鉴权和proxy

* fix: remove chunk

---------

Co-authored-by: wangting31 <wangting31@baidu.com>
Co-authored-by: zhonghanjun <zhonghanjun@baidu.com>
  • Loading branch information
3 people authored Jul 19, 2024
1 parent 408ae14 commit 1bcbbc7
Show file tree
Hide file tree
Showing 13 changed files with 215 additions and 163 deletions.
5 changes: 3 additions & 2 deletions javascript/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@baiducloud/qianfan",
"version": "0.1.5-beta.1",
"version": "0.1.5",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/"
Expand Down Expand Up @@ -34,6 +34,7 @@
"crypto-js": "^4.2.0",
"dotenv": "^16.4.5",
"node-fetch": "2.7.0",
"qianfan-wt": "^0.0.20",
"rollup": "^3.29.4",
"typescript": "^5.3.3",
"web-streams-polyfill": "^4.0.0"
Expand Down Expand Up @@ -63,4 +64,4 @@
"rollup-plugin-terser": "^7.0.2",
"ts-node": "^10.9.2"
}
}
}
93 changes: 47 additions & 46 deletions javascript/src/Base/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import HttpClient from '../HttpClient';
import Fetch, {FetchConfig} from '../Fetch/index';
import {DEFAULT_HEADERS} from '../constant';
import {getAccessTokenUrl, getIAMConfig, getDefaultConfig, getPath, getCurrentEnvironment} from '../utils';
import {getAccessTokenUrl, getIAMConfig, getDefaultConfig, getPath} from '../utils';
import {Resp, AsyncIterableType, AccessTokenResp} from '../interface';
import DynamicModelEndpoint from '../DynamicModelEndpoint';

Expand Down Expand Up @@ -100,17 +100,49 @@ export class BaseClient {
}
}

/**
* 获取 IAM 路径 (配置proxy情况下)
*
* @param type 路径类型
* @param model 模型名称
* @returns 返回 IAM 路径
* @throws 当 qianfanBaseUrl 包含 'aip.baidubce.com' 时,抛出错误提示设置 proxy 的 baseUrl
* @throws 当 qianfanConsoleApiBaseUrl 未设置时,抛出错误提示未设置 qianfanConsoleApiBaseUrl
* @throws 当 Endpoint 未设置且 qianfanConsoleApiBaseUrl 不包含 'qianfan.baidubce.com' 时,抛出错误提示未设置 Endpoint
*/
private async getIAMPath(type, model) {
if (this.qianfanBaseUrl.includes('aip.baidubce.com')) {
throw new Error('请设置proxy的baseUrl');
}
const dynamicModelEndpoint = new DynamicModelEndpoint(
null,
this.qianfanConsoleApiBaseUrl,
this.qianfanBaseUrl
);
return await dynamicModelEndpoint.getEndpoint(type, model);
}

public async getAllModels(type): Promise<string[]> {
const dynamicModelEndpoint = new DynamicModelEndpoint(
null,
this.qianfanConsoleApiBaseUrl,
this.qianfanBaseUrl
);
const map = await dynamicModelEndpoint.getDynamicMap(type);
const keysArray: string[] = Array.from(map.keys()); // 将Map的键转换为数组
return keysArray;
}

protected async sendRequest(
type: string,
model: string,
AKPath: string,
requestBody: string,
stream = false
): Promise<Resp | AsyncIterableType> {
// 判断当前环境,node需要鉴权,浏览器不需要鉴权(需要设置proxy的baseUrl、consoleUrl)·
const env = getCurrentEnvironment();
let fetchOptions;
if (env === 'node') {
// 如果baseUrl是aip.baidubce.com,证明用户未配置proxy url,则认为需要放开鉴权
if (this.qianfanBaseUrl.includes('aip.baidubce.com')) {
// 检查鉴权信息
if (!(this.qianfanAccessKey && this.qianfanSecretKey) && !(this.qianfanAk && this.qianfanSk)) {
throw new Error('请设置AK/SK或QIANFAN_ACCESS_KEY/QIANFAN_SECRET_KEY');
Expand Down Expand Up @@ -160,49 +192,18 @@ export class BaseClient {
};
}
}
else if (env === 'browser') {
// 浏览器环境 需要设置proxy
if (this.qianfanBaseUrl.includes('aip.baidubce.com')) {
throw new Error('请设置proxy的baseUrl');
}
// 如果设置了管控api,则使用管控api获取最新模型
if (this.qianfanConsoleApiBaseUrl && !this.qianfanConsoleApiBaseUrl.includes('qianfan.baidubce.com')) {
const dynamicModelEndpoint = new DynamicModelEndpoint(
null,
this.qianfanConsoleApiBaseUrl,
this.qianfanBaseUrl
);
let IAMPath = '';
if (this.Endpoint) {
IAMPath = getPath({
Authentication: 'IAM',
api_base: this.qianfanBaseUrl,
endpoint: this.Endpoint,
type,
});
}
else {
IAMPath = await dynamicModelEndpoint.getEndpoint(type, model);
}
if (!IAMPath) {
throw new Error(`${model} is not supported`);
}
fetchOptions = {
url: `${this.qianfanBaseUrl}${IAMPath}`,
method: 'POST',
headers: this.headers,
body: requestBody,
};
}
else {
const url = `${AKPath}`;
fetchOptions = {
url: url,
method: 'POST',
headers: this.headers,
body: requestBody,
};
else {
// 设置了proxy url走prxoy
const IAMPath = await this.getIAMPath(type, model);
if (!IAMPath) {
throw new Error(`${model} is not supported`);
}
fetchOptions = {
url: `${this.qianfanBaseUrl}${IAMPath}`,
method: 'POST',
headers: this.headers,
body: requestBody,
};
}
try {
const {url, ...rest} = fetchOptions;
Expand Down
22 changes: 11 additions & 11 deletions javascript/src/ChatCompletion/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@

import {BaseClient} from '../Base';
import {ChatBody, Resp} from '../interface';
import {modelInfoMap} from './utils';
import {getPathAndBody, getUpperCaseModelAndModelMap} from '../utils';
import {getPathAndBody} from '../utils';
import {getTypeMap, typeModelEndpointMap} from '../DynamicModelEndpoint/utils';
import {ModelType} from '../enum';

const type = ModelType.CHAT;
class ChatCompletion extends BaseClient {
/**
* chat
Expand All @@ -28,22 +29,21 @@ class ChatCompletion extends BaseClient {
*/
public async chat(body: ChatBody, model = 'ERNIE-Lite-8K'): Promise<Resp | AsyncIterable<Resp>> {
const stream = body.stream ?? false;
const {modelInfoMapUppercase, modelUppercase, modelLowercase} = getUpperCaseModelAndModelMap(
model,
modelInfoMap
);
const type = ModelType.CHAT;

const modelKey = model.toLowerCase();
const typeMap = getTypeMap(typeModelEndpointMap, type) ?? new Map();
const endPoint = typeMap.get(modelKey) || '';
const {AKPath, requestBody} = getPathAndBody({
model: Number(this.version) === 2 ? modelLowercase : modelUppercase,
modelInfoMap: modelInfoMapUppercase,
baseUrl: this.qianfanBaseUrl,
body,
endpoint: this.Endpoint,
endpoint: this.Endpoint ?? endPoint,
type,
});
return this.sendRequest(type, model, AKPath, requestBody, stream);
}

public async getModels(): Promise<string[]> {
return this.getAllModels(type);
}
}

export default ChatCompletion;
6 changes: 5 additions & 1 deletion javascript/src/Completions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {BaseClient} from '../Base';
import {ChatBody, CompletionBody, Resp} from '../interface';
import {modelInfoMap, isCompletionBody} from './utils';
import {getPathAndBody, getUpperCaseModelAndModelMap} from '../utils';
import {getTypeMap, typeModelEndpointMap} from '../DynamicModelEndpoint/utils';
import {ModelType} from '../enum';

class Completions extends BaseClient {
Expand Down Expand Up @@ -50,12 +51,15 @@ class Completions extends BaseClient {
else {
reqBody = body;
}
const modelKey = model.toLowerCase();
const typeMap = getTypeMap(typeModelEndpointMap, type) ?? new Map();
const endPoint = typeMap.get(modelKey) || '';
const {AKPath, requestBody} = getPathAndBody({
model: modelUppercase,
modelInfoMap: modelInfoMapUppercase,
baseUrl: this.qianfanBaseUrl,
body: reqBody,
endpoint: this.Endpoint,
endpoint: this.Endpoint ?? endPoint,
type,
});
return this.sendRequest(type, model, AKPath, requestBody, stream);
Expand Down
4 changes: 4 additions & 0 deletions javascript/src/DynamicModelEndpoint/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ class DynamicModelEndpoint {
// console.log('Failed to update dynamic model endpoint map', error);
}
}
public async getDynamicMap(type: string): Promise<Map<string, string> | undefined> {
await this.updateDynamicModelEndpoint(type);
return this.getDynamicTypeModelEndpointMap().get(type);
}

getDynamicMapExpireAt() {
return this.dynamicMapExpireAt;
Expand Down
12 changes: 6 additions & 6 deletions javascript/src/Embedding/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@

import {BaseClient} from '../Base';
import {EmbeddingBody, EmbeddingResp} from '../interface';
import {modelInfoMap} from './utils';
import {getPathAndBody, getUpperCaseModelAndModelMap} from '../utils';
import {getPathAndBody} from '../utils';
import {getTypeMap, typeModelEndpointMap} from '../DynamicModelEndpoint/utils';
import {ModelType} from '../enum';

class Eembedding extends BaseClient {
Expand All @@ -26,14 +26,14 @@ class Eembedding extends BaseClient {
* @returns Promise<Resp | AsyncIterable<Resp>>
*/
public async embedding(body: EmbeddingBody, model = 'Embedding-V1'): Promise<EmbeddingResp> {
const {modelInfoMapUppercase, modelUppercase} = getUpperCaseModelAndModelMap(model, modelInfoMap);
const type = ModelType.EMBEDDINGS;
const modelKey = model.toLowerCase();
const typeMap = getTypeMap(typeModelEndpointMap, type) ?? new Map();
const endPoint = typeMap.get(modelKey) || '';
const {AKPath, requestBody} = getPathAndBody({
model: modelUppercase,
modelInfoMap: modelInfoMapUppercase,
baseUrl: this.qianfanBaseUrl,
body,
endpoint: this.Endpoint,
endpoint: this.Endpoint ?? endPoint,
type,
});
const resp = await this.sendRequest(type, model, AKPath, requestBody);
Expand Down
12 changes: 6 additions & 6 deletions javascript/src/Images/image2text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@

import {BaseClient} from '../Base';
import {Image2TextBody, RespBase} from '../interface';
import {image2TextModelInfoMap} from './utils';
import {getPathAndBody, getUpperCaseModelAndModelMap} from '../utils';
import {getPathAndBody} from '../utils';
import {getTypeMap, typeModelEndpointMap} from '../DynamicModelEndpoint/utils';
import {ModelType} from '../enum';

class Image2Text extends BaseClient {
Expand All @@ -28,14 +28,14 @@ class Image2Text extends BaseClient {
body: Image2TextBody,
model = 'Fuyu-8B'
): Promise<RespBase> {
const {modelInfoMapUppercase, modelUppercase} = getUpperCaseModelAndModelMap(model, image2TextModelInfoMap);
const type = ModelType.IMAGE_2_TEXT;
const modelKey = model.toLowerCase();
const typeMap = getTypeMap(typeModelEndpointMap, type) ?? new Map();
const endPoint = typeMap.get(modelKey) || '';
const {AKPath, requestBody} = getPathAndBody({
model: modelUppercase,
modelInfoMap: modelInfoMapUppercase,
baseUrl: this.qianfanBaseUrl,
body,
endpoint: this.Endpoint,
endpoint: this.Endpoint ?? endPoint,
type,
});
const resp = await this.sendRequest(type, model, AKPath, requestBody);
Expand Down
9 changes: 5 additions & 4 deletions javascript/src/Images/text2image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {BaseClient} from '../Base';
import {Text2ImageBody, Text2ImageResp} from '../interface';
import {text2ImageModelInfoMap} from './utils';
import {getPathAndBody, getUpperCaseModelAndModelMap} from '../utils';
import {getTypeMap, typeModelEndpointMap} from '../DynamicModelEndpoint/utils';
import {ModelType} from '../enum';

class Text2Image extends BaseClient {
Expand All @@ -29,14 +30,14 @@ class Text2Image extends BaseClient {
body: Text2ImageBody,
model = 'Stable-Diffusion-XL'
): Promise<Text2ImageResp> {
const {modelInfoMapUppercase, modelUppercase} = getUpperCaseModelAndModelMap(model, text2ImageModelInfoMap);
const type = ModelType.TEXT_2_IMAGE;
const modelKey = model.toLowerCase();
const typeMap = getTypeMap(typeModelEndpointMap, type) ?? new Map();
const endPoint = typeMap.get(modelKey) || '';
const {AKPath, requestBody} = getPathAndBody({
model: modelUppercase,
modelInfoMap: modelInfoMapUppercase,
baseUrl: this.qianfanBaseUrl,
body,
endpoint: this.Endpoint,
endpoint: this.Endpoint ?? endPoint,
type,
});
const resp = await this.sendRequest(type, model, AKPath, requestBody);
Expand Down
12 changes: 7 additions & 5 deletions javascript/src/Plugin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
// limitations under the License.

import {BaseClient} from '../Base';
import {modelInfoMap} from './utilts';
import {PluginsBody, PluginsResp, YiYanPluginBody} from '../interface';
import {getPathAndBody, getUpperCaseModelAndModelMap} from '../utils';
import {getPathAndBody} from '../utils';
import {getTypeMap, typeModelEndpointMap} from '../DynamicModelEndpoint/utils';
import {ModelType} from '../enum';

class Plugin extends BaseClient {
Expand All @@ -30,15 +30,17 @@ class Plugin extends BaseClient {
model = 'EBPluginV2'
): Promise<PluginsResp | AsyncIterable<PluginsResp>> {
const stream = body.stream ?? false;
const {modelInfoMapUppercase, modelUppercase} = getUpperCaseModelAndModelMap(model, modelInfoMap);
const type = ModelType.PLUGIN;
const modelKey = model.toLowerCase();
const typeMap = getTypeMap(typeModelEndpointMap, type) ?? new Map();
const endPoint = typeMap.get(modelKey) || '';
const {AKPath, requestBody} = getPathAndBody({
model: modelUppercase,
modelInfoMap: modelInfoMapUppercase,
baseUrl: this.qianfanBaseUrl,
endpoint: endPoint,
body,
type,
});
console.log(AKPath);
return (await this.sendRequest(type, model, AKPath, requestBody, stream)) as
| PluginsResp
| AsyncIterable<PluginsResp>;
Expand Down
6 changes: 5 additions & 1 deletion javascript/src/Reranker/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,23 @@ import {BaseClient} from '../Base';
import {modelInfoMap} from './utilts';
import {getPathAndBody, getUpperCaseModelAndModelMap} from '../utils';
import {RerankerBody, RerankerResp} from '../interface';
import {getTypeMap, typeModelEndpointMap} from '../DynamicModelEndpoint/utils';
import {ModelType} from '../enum';

class Reranker extends BaseClient {

public async reranker(body: RerankerBody, model = 'bce-reranker-base_v1'): Promise<RerankerResp> {
const {modelInfoMapUppercase, modelUppercase} = getUpperCaseModelAndModelMap(model, modelInfoMap);
const type = ModelType.RERANKER;
const modelKey = model.toLowerCase();
const typeMap = getTypeMap(typeModelEndpointMap, type) ?? new Map();
const endPoint = typeMap.get(modelKey) || '';
const {AKPath, requestBody} = getPathAndBody({
model: modelUppercase,
modelInfoMap: modelInfoMapUppercase,
baseUrl: this.qianfanBaseUrl,
body,
endpoint: this.Endpoint,
endpoint: this.Endpoint ?? endPoint,
type,
});
const resp = await this.sendRequest(type, model, AKPath, requestBody);
Expand Down
3 changes: 0 additions & 3 deletions javascript/src/streaming/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,6 @@ export class Stream<Item> implements AsyncIterable<Item> {
const iter = readableStreamAsyncIterable<Bytes>(response.body);

for await (const chunk of iter) {
if (chunk[0] === 10) {
continue;
}
if (previousChunkLastByte === 10) {
buffer = concatUint8Arrays(buffer, chunk as Uint8Array);

Expand Down
1 change: 1 addition & 0 deletions javascript/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ export const getPath = ({
? `${BASE_PATH}${modelEndpoint}`
: `${api_base}${modelEndpoint}`;
}
throw new Error('Model is not supported');
};


Expand Down
Loading

0 comments on commit 1bcbbc7

Please sign in to comment.