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

feat: add support for qianfan console api calls #732

Merged
merged 1 commit into from
Aug 12, 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
6 changes: 3 additions & 3 deletions java/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<dependency>
<groupId>com.baidubce</groupId>
<artifactId>qianfan</artifactId>
<version>0.0.9</version>
<version>0.1.0</version>
</dependency>
```

Expand All @@ -21,13 +21,13 @@
对于Kotlin DSL,在build.gradle.kts的dependencies中添加依赖。

```kotlin
implementation("com.baidubce:qianfan:0.0.9")
implementation("com.baidubce:qianfan:0.1.0")
```

对于Groovy DSL,在build.gradle的dependencies中添加依赖。

```groovy
implementation 'com.baidubce:qianfan:0.0.9'
implementation 'com.baidubce:qianfan:0.1.0'
```

> 我们提供了一些 [示例](./examples),可以帮助快速了解 SDK 的使用方法并完成常见功能。
Expand Down
2 changes: 1 addition & 1 deletion java/example/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<dependency>
<groupId>com.baidubce</groupId>
<artifactId>qianfan</artifactId>
<version>0.0.9</version>
<version>0.1.0</version>
</dependency>
</dependencies>
</project>
64 changes: 64 additions & 0 deletions java/example/src/main/java/com/baidubce/ConsoleExample.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright (c) 2024 Baidu, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.baidubce;

import com.baidubce.qianfan.Qianfan;
import com.baidubce.qianfan.util.CollUtils;

import java.util.Map;

/**
* 本示例实现了Console管控API调用流程
* API文档可见 <a href="https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Ely8ai160">API列表</a>
*/
public class ConsoleExample {
public static void main(String[] args) {
describePresetServices();
describeTPMResource();
}

private static void describePresetServices() {
// 获取预置服务列表 https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Glygmrg7v
Map<String, Object> response = new Qianfan().console()
// 对应文档中请求地址的后缀
.route("/v2/service")
// 对应文档中Query参数的Action
.action("DescribePresetServices")
// 如果不传入任何Response类,则默认返回Map<String, Object>
.execute()
// 可以传入class或者TypeRef来指定反序列化后返回的Response类
// .execute(DescribePresetServicesResponse.class)
.getResult();
System.out.println(response);
}

private static void describeTPMResource() {
// 查询TPM配额信息详情 https://cloud.baidu.com/doc/WENXINWORKSHOP/s/ultmls9l9
Map<String, Object> response = new Qianfan().console().route("/v2/charge").action("DescribeTPMResource")
// 需要传入参数的场景,可以自行封装请求类,或者使用Map.of()来构建请求Body
// Java 8可以使用SDK提供的CollUtils.mapOf()来替代Map.of()
.body(CollUtils.mapOf(
"model", "ernie-4.0-8k",
"paymentTiming", "Postpaid"
))
.execute()
.getResult();
System.out.println(response);
}
}


113 changes: 113 additions & 0 deletions java/example/src/main/java/com/baidubce/SystemMemoryExample.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* Copyright (c) 2024 Baidu, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.baidubce;

import com.baidubce.qianfan.Qianfan;
import com.baidubce.qianfan.core.auth.Auth;
import com.baidubce.qianfan.core.builder.MessageBuilder;
import com.baidubce.qianfan.model.chat.Message;
import com.baidubce.qianfan.util.CollUtils;

import java.util.List;
import java.util.Map;

/**
* 本示例实现了简易的系统记忆管理接口及推理接口的全流程调用
* 系统记忆Console接口文档可见 <a href="https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Mlwg321zw">创建系统记忆</a>
*/
public class SystemMemoryExample {
// 在模型服务-应用接入中创建应用,即可获得应用的AppID、API Key和Secret Key
private static final String APP_ID = "替换为实际的AppId";
private static final String APP_API_KEY = "替换为实际的ApiKey";
private static final String APP_SECRET_KEY = "替换为实际的SecretKey";

public static void main(String[] args) throws InterruptedException {
// 注意,在生产环境中,应当手动创建一个系统记忆并维护记忆内容,然后在推理中重复使用该系统记忆
String systemMemoryId = createSystemMemory(APP_ID, "度小茶饮品店智能客服系统记忆");
System.out.println("系统记忆ID:" + systemMemoryId);

Boolean result = modifySystemMemory(systemMemoryId, CollUtils.listOf(
new MessageBuilder()
.add("user", "你的幸运数字是什么?")
.add("system", "我的幸运数字是42。")
.build(),
new MessageBuilder()
.add("user", "能推荐一款适合夏天饮用的饮品吗?")
.add("system", "当然可以,我们推荐冰镇柠檬绿茶,清新爽口,非常适合夏日消暑。")
.build()
));
System.out.println("修改系统记忆结果:" + result);

Thread.sleep(5000);

Map<String, Object> memories = describeSystemMemory(systemMemoryId);
System.out.println("记忆列表:" + memories);

String system = "你是度小茶饮品店的智能客服。";
String response = chat(systemMemoryId, system, "你的幸运数字是什么");
System.out.println("推理结果:" + response);
String response2 = chat(systemMemoryId, system, "推荐一个适合夏天的饮料");
System.out.println("推理结果2:" + response2);
}

private static String createSystemMemory(String appId, String description) {
return new Qianfan().console()
.route("/v2/memory")
.action("CreateSystemMemory")
.body(CollUtils.mapOf(
"appId", appId,
"description", description
))
.execute(String.class)
.getResult();
}

private static Boolean modifySystemMemory(String systemMemoryId, List<List<Message>> memories) {
return new Qianfan().console()
.route("/v2/memory")
.action("ModifySystemMemory")
.body(CollUtils.mapOf(
"systemMemoryId", systemMemoryId,
"memories", memories
))
.execute(Boolean.class)
.getResult();
}

private static Map<String, Object> describeSystemMemory(String systemMemoryId) {
return new Qianfan().console()
.route("/v2/memory")
.action("DescribeSystemMemory")
.body(CollUtils.mapOf(
"systemMemoryId", systemMemoryId
))
.execute()
.getResult();
}

private static String chat(String systemMemoryId, String system, String query) {
// 使用系统记忆时,鉴权需要使用OAuth方式,同时需要传入与系统记忆相同应用的Api Key和Secret Key
return new Qianfan(Auth.TYPE_OAUTH, APP_API_KEY, APP_SECRET_KEY).chatCompletion()
.model("ERNIE-3.5-8K")
.system(system)
.enableSystemMemory(true)
.systemMemoryId(systemMemoryId)
.addUserMessage(query)
.execute()
.getResult();
}
}
2 changes: 1 addition & 1 deletion java/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<groupId>com.baidubce</groupId>
<artifactId>qianfan</artifactId>
<version>0.0.9</version>
<version>0.1.0</version>
<packaging>jar</packaging>

<name>qianfan</name>
Expand Down
17 changes: 17 additions & 0 deletions java/src/main/java/com/baidubce/qianfan/Qianfan.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import com.baidubce.qianfan.model.chat.ChatResponse;
import com.baidubce.qianfan.model.completion.CompletionRequest;
import com.baidubce.qianfan.model.completion.CompletionResponse;
import com.baidubce.qianfan.model.console.ConsoleRequest;
import com.baidubce.qianfan.model.console.ConsoleResponse;
import com.baidubce.qianfan.model.embedding.EmbeddingRequest;
import com.baidubce.qianfan.model.embedding.EmbeddingResponse;
import com.baidubce.qianfan.model.image.Image2TextRequest;
Expand All @@ -37,6 +39,9 @@
import com.baidubce.qianfan.model.rerank.RerankRequest;
import com.baidubce.qianfan.model.rerank.RerankResponse;

import java.lang.reflect.Type;


public class Qianfan {
private final QianfanClient client;

Expand Down Expand Up @@ -138,11 +143,23 @@ public StreamIterator<PluginResponse> pluginStream(PluginRequest request) {
return requestStream(request, PluginResponse.class);
}

public ConsoleBuilder console() {
return new ConsoleBuilder(this);
}

public <T> ConsoleResponse<T> console(ConsoleRequest request, Type type) {
return consoleRequest(request, type);
}

public <T extends BaseResponse<T>, U extends BaseRequest<U>> T request(BaseRequest<U> request, Class<T> responseClass) {
return client.request(request, responseClass);
}

public <T extends BaseResponse<T>, U extends BaseRequest<U>> StreamIterator<T> requestStream(BaseRequest<U> request, Class<T> responseClass) {
return client.requestStream(request, responseClass);
}

public <T> ConsoleResponse<T> consoleRequest(ConsoleRequest request, Type type) {
return client.consoleRequest(request, type);
}
}
41 changes: 40 additions & 1 deletion java/src/main/java/com/baidubce/qianfan/QianfanClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,27 @@
import com.baidubce.qianfan.core.RateLimiter;
import com.baidubce.qianfan.core.StreamIterator;
import com.baidubce.qianfan.core.auth.Auth;
import com.baidubce.qianfan.core.auth.IAMAuth;
import com.baidubce.qianfan.core.auth.IAuth;
import com.baidubce.qianfan.model.*;
import com.baidubce.qianfan.model.console.ConsoleRequest;
import com.baidubce.qianfan.model.console.ConsoleResponse;
import com.baidubce.qianfan.model.exception.ApiException;
import com.baidubce.qianfan.model.exception.AuthException;
import com.baidubce.qianfan.model.exception.QianfanException;
import com.baidubce.qianfan.model.exception.RequestException;
import com.baidubce.qianfan.util.Json;
import com.baidubce.qianfan.util.ParameterizedTypeImpl;
import com.baidubce.qianfan.util.StringUtils;
import com.baidubce.qianfan.util.function.ThrowingFunction;
import com.baidubce.qianfan.util.http.*;

import java.lang.reflect.Type;

class QianfanClient {
private static final String SDK_VERSION = "0.0.9";
private static final String SDK_VERSION = "0.1.0";
private static final String CONSOLE_URL_NO_ACTION_TEMPLATE = "%s%s";
private static final String CONSOLE_URL_ACTION_TEMPLATE = "%s%s?Action=%s";
private static final String QIANFAN_URL_TEMPLATE = "%s/rpc/2.0/ai_custom/v1/wenxinworkshop%s";
private static final String EXTRA_PARAM_REQUEST_SOURCE = "request_source";
private static final String REQUEST_SOURCE_PREFIX = "qianfan_java_sdk_v";
Expand Down Expand Up @@ -120,6 +129,36 @@ private <T extends BaseRequest<T>, U, V, E extends Exception> V request(
throw new IllegalStateException("Request failed with unknown error");
}

public <T> ConsoleResponse<T> consoleRequest(ConsoleRequest request, Type type) {
try {
if (!(auth instanceof IAMAuth)) {
throw new AuthException("Console request requires IAM authentication");
}
String url = StringUtils.isNotEmpty(request.getAction())
? String.format(CONSOLE_URL_ACTION_TEMPLATE, QianfanConfig.getConsoleApiBaseUrl(), request.getRoute(), request.getAction())
: String.format(CONSOLE_URL_NO_ACTION_TEMPLATE, QianfanConfig.getConsoleApiBaseUrl(), request.getRoute());
HttpRequest httpRequest = HttpClient.request()
.post(url)
.body(request.getBody() == null ? new Object() : request.getBody());

Type respType = new ParameterizedTypeImpl(ConsoleResponse.class, new Type[]{type});
HttpResponse<ConsoleResponse<T>> resp = auth.signRequest(httpRequest).executeJson(respType);

if (resp.getCode() != HttpStatus.SUCCESS) {
throw new RequestException(String.format("Request failed with status code %d: %s", resp.getCode(), resp.getStringBody()));
}
ApiErrorResponse errorResp = Json.deserialize(resp.getStringBody(), ApiErrorResponse.class);
if (StringUtils.isNotEmpty(errorResp.getErrorMsg())) {
throw new ApiException("Request failed with api error", errorResp);
}
return resp.getBody();
} catch (QianfanException e) {
throw e;
} catch (Exception e) {
throw new RequestException(String.format("Request failed: %s", e.getMessage()), e);
}
}

private <T extends BaseRequest<T>, U, V, E extends Exception> V innerRequest(
BaseRequest<T> request,
ThrowingFunction<HttpRequest, HttpResponse<U>, E> reqProcessor,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import com.baidubce.qianfan.util.http.SSEIterator;

import java.io.Closeable;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
Expand Down
Loading