文档列表
官方API在线调试,帮助理解https://www.coze.cn/open/playground/list_conversations官方API文档,帮助理解
https://www.coze.cn/open/docs/developer_guides/create_conversationCoze_JavaSDK 文档
https://www.coze.cn/open/docs/developer_guides/java_overviewcoze_java_sdk_demo 示例
https://github.com/coze-dev/coze-java
demo中各工具类的Example有助于理解后按自己的需求编码,建议pull下来看一遍
引入依赖
父pom.xml
<properties><coze.version>0.3.0</coze.version>
</properties><dependencyManagement><dependencies><dependency><groupId>com.coze</groupId><artifactId>coze-api</artifactId><version>${coze.version}</version></dependency></dependencies>
</dependencyManagement>
子pom.xml
<dependencies><dependency><groupId>com.coze</groupId><artifactId>coze-api</artifactId></dependency>
</dependencies>
参数配置
clientId、publicKeyId、privateKey请参考教程OAuth应用的创建与授权
我的配置方式只是演示,并非最优唯一解,官方文档中都是建议把这些参数写入系统环境变量中
application.yml
coze:clientId: 123456789publicKeyId: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxprivateKeyFilePath: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx#privateKey: testwwwBase: https://www.coze.cnapiBase: https://api.coze.cnbotId: 987654321
新建配置类
package com.coze.config;import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;/*** @Author: Tenk* 扣子参数配置类*/
@Component
@ConfigurationProperties(prefix = "coze")
public class CozeConfig {//OAuth应用IDprivate String clientId;//公钥private String publicKeyId;//私钥private String privateKey;//私钥证书路径private String privateKeyFilePath;//coze官网private String wwwBase;//cozeApi请求地址private String apiBase;//智能体botIdprivate String botId;
编写工具类
package com.coze.util;import com.coze.openapi.service.auth.JWTOAuthClient;
import com.coze.openapi.service.auth.TokenAuth;
import com.coze.openapi.service.service.CozeAPI;
import com.coze.config.CozeConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;/*** 初始化CozeJWTOAuth授权工具** @url https://github.com/coze-dev/coze-java/blob/main/example/src/main/java/example/auth/JWTOAuthExample.java* @Author: Tenk*/
@Component
public class CozeJWTOAuthUtil {private static final Logger log = LoggerFactory.getLogger(CozeJWTOAuthUtil.class);//配置类@Autowiredprivate CozeConfig cozeConfig;//OAuth授权工具private JWTOAuthClient oauth;//getpublic CozeConfig getCozeConfig() {return cozeConfig;}//getpublic JWTOAuthClient getJWTOAuthClient() {return oauth;}//单例@PostConstructpublic void init() {this.oauth = createJWTOAuthClient();}/*** 初始化CozeJWTOAuth** @return*/public JWTOAuthClient createJWTOAuthClient() {try {//读取coze_private_key_pemString jwtOAuthPrivateKey = new String(Files.readAllBytes(Paths.get(cozeConfig.getPrivateKeyFilePath())), StandardCharsets.UTF_8);oauth = new JWTOAuthClient.JWTOAuthBuilder().clientID(cozeConfig.getClientId()).privateKey(jwtOAuthPrivateKey).publicKey(cozeConfig.getPublicKeyId()).baseURL(cozeConfig.getApiBase()).build();} catch (Exception e) {log.error("初始化CozeJWTOAuth失败", e);return null;}return oauth;}
}
service方法
/*** 常量** @Author: Tenk*/
public class CozeConstants {public static final String JWT_TOKEN = "coze:jwt_token:";public static final String CONVERSATION = "coze:conversation:";
}
1.OAuth JWT 授权
为什么需要会话隔离https://www.coze.cn/open/docs/developer_guides/session_isolation
引入上面编写的工具类和redis工具类@Autowiredprivate CozeJWTOAuthUtil cozeJWTOAuthUtil;@Autowiredprivate RedisService redisService;
//根据系统用户id,生成access_token,以达到会话隔离的效果
public OAuthToken getAccessToken(String userId) {OAuthToken accessToken;if (redisService.hasKey(CozeConstants.JWT_TOKEN + userId)) {accessToken = JSONObject.parseObject(redisService.getCacheObject(CozeConstants.JWT_TOKEN + userId).toString(), OAuthToken.class);} else {//token默认15分钟有效期,redis存14分钟accessToken = cozeJWTOAuthUtil.getJWTOAuthClient().getAccessToken(userId);redisService.setCacheObject(CozeConstants.JWT_TOKEN + userId, accessToken, 14L, TimeUnit.MINUTES);}return accessToken;
}
结果
2.向智能体发送消息
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Null;/*** @Author: Tenk* AI聊天业务对象*/
public class ChatBo {@NotBlank(message = "请输入内容")private String content;private String userId;
}
public String createChatMessage(ChatBo bo) {//获取用户jwtTokenOAuthToken accessToken = getAccessToken(bo.getUserId());//获取扣子Api工具CozeAPI cozeAPI = cozeJWTOAuthUtil.createCozeAPIByUser(accessToken.getAccessToken());//获取会话id,演示所设计的是每人是唯一的会话,可以单独new个表做管理String conversationId = null;if (redisService.hasKey(CozeConstants.CONVERSATION + bo.getUserId())) {conversationId = redisService.getCacheObject(CozeConstants.CONVERSATION + bo.getUserId()).toString();} else {//反之创建新会话CreateConversationResp resp = cozeAPI.conversations().create(new CreateConversationReq(null, null, cozeJWTOAuthUtil.getCozeConfig().getTripBotId()));conversationId = resp.getConversation().getId();redisService.setCacheObject(CozeConstants.CONVERSATION + bo.getUserId(), conversationId);}//先手动创建message,否则拿不到messageId等信息以存入数据库CreateMessageReq.CreateMessageReqBuilder<?, ?> msgReq = CreateMessageReq.builder().conversationID(conversationId).role(MessageRole.USER).content(bo.getContent()).contentType(MessageContentType.TEXT);CreateMessageResp msgResp = cozeAPI.conversations().messages().create(msgReq.build());//通过响应拿到user question的message信息Message userMsg = msgResp.getMessage();//创建对话请求,再将创建的message附加到对话中//.messages()中也可以直接传文字而不封装MessageCreateChatReq chatReq = CreateChatReq.builder().stream(false).autoSaveHistory(true).botID(cozeJWTOAuthUtil.getCozeConfig().getTripBotId()).conversationID(conversationId).userID(bo.getUserId()).messages(Collections.singletonList(userMsg))//.messages(Collections.singletonList(Message.buildUserQuestionText(bo.getContent())).build();ChatPoll chatPoll = null;try {//发送对话请求并自动轮询chatPoll = cozeAPI.chat().createAndPoll(chatReq);} catch (Exception e) {log.error("发送对话失败:{}", e.getMessage());return null;}//解析AI消息String content = null;for (Message message : chatPoll.getMessages()) {if (message.getType().getValue().equals(MessageType.ANSWER.getValue())) {// AI完成后的完整答复content = message.getContent();}}return content;//Tips//封装的userMessage和遍历chatPoll得到的botMessage可以自己整理写入数据库以记录。//无特殊需求,其实不用,因为coze有提供获取这些会话内消息列表的接口/工具类
}
结语
前期会花一些时间在官方文档里,吸收概念,理解透彻了才好动手,大家有不理解的,其它想法或经验欢迎留言提出、分享,后续研究更多使用方法会逐一分享出来 。