Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

浏览器支持自主鉴权和proxy, #682

Merged
merged 6 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

当前只提供Chat模型列表

}

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) || '';
danielhjz marked this conversation as resolved.
Show resolved Hide resolved
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) || '';
danielhjz marked this conversation as resolved.
Show resolved Hide resolved
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);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1

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