当前位置:   article > 正文

java调用讯飞星火认知模型_java接入讯飞星火大模型

java接入讯飞星火大模型

 前往讯飞开发平台选择产品,获取appId、apiKey、APISecret,这里我选择的是v3.0模型。

java后端实现

本项目以及实现了基本的会话功能,小伙伴可以自己扩充其他的例如绘画功能。

注意:星火模型的api使用的是websocket协议,和chatGPT的http不一样,而且他的key也不但单单是APIKey,需要用特殊的算法得到验证令牌。详情可查看官网开发文档。

下面就来看看实现:

pom.xml,主要依赖

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <groupId>com.xyb</groupId>
  6. <artifactId>xfxh-sdk-java</artifactId>
  7. <version>1.0-SNAPSHOT</version>
  8. <name>xfxh-sdk-java</name>
  9. <description>Demo project for Spring Boot</description>
  10. <properties>
  11. <java.version>1.8</java.version>
  12. </properties>
  13. <dependencies>
  14. <dependency>
  15. <groupId>org.projectlombok</groupId>
  16. <artifactId>lombok</artifactId>
  17. <version>1.18.24</version>
  18. <scope>compile</scope>
  19. </dependency>
  20. <dependency>
  21. <groupId>org.slf4j</groupId>
  22. <artifactId>slf4j-api</artifactId>
  23. <version>2.0.6</version>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.slf4j</groupId>
  27. <artifactId>slf4j-simple</artifactId>
  28. <version>2.0.6</version>
  29. </dependency>
  30. <dependency>
  31. <groupId>cn.hutool</groupId>
  32. <artifactId>hutool-all</artifactId>
  33. <version>5.8.18</version>
  34. </dependency>
  35. <dependency>
  36. <groupId>com.alibaba</groupId>
  37. <artifactId>fastjson</artifactId>
  38. <version>1.2.67</version>
  39. </dependency>
  40. <dependency>
  41. <groupId>com.squareup.okhttp3</groupId>
  42. <artifactId>okhttp-sse</artifactId>
  43. <version>3.14.9</version>
  44. </dependency>
  45. <dependency>
  46. <groupId>com.squareup.okhttp3</groupId>
  47. <artifactId>logging-interceptor</artifactId>
  48. <version>3.14.9</version>
  49. </dependency>
  50. <dependency>
  51. <groupId>com.squareup.retrofit2</groupId>
  52. <artifactId>retrofit</artifactId>
  53. <version>2.9.0</version>
  54. </dependency>
  55. <dependency>
  56. <groupId>com.squareup.retrofit2</groupId>
  57. <artifactId>converter-jackson</artifactId>
  58. <version>2.9.0</version>
  59. </dependency>
  60. <dependency>
  61. <groupId>com.squareup.retrofit2</groupId>
  62. <artifactId>adapter-rxjava2</artifactId>
  63. <version>2.9.0</version>
  64. </dependency>
  65. <dependency>
  66. <groupId>junit</groupId>
  67. <artifactId>junit</artifactId>
  68. <version>4.13.2</version>
  69. <scope>test</scope>
  70. </dependency>
  71. <dependency>
  72. <groupId>org.jetbrains</groupId>
  73. <artifactId>annotations</artifactId>
  74. <version>RELEASE</version>
  75. <scope>compile</scope>
  76. </dependency>
  77. </dependencies>
  78. <build>
  79. <finalName>chatgpt-sdk-java</finalName>
  80. <plugins>
  81. <plugin>
  82. <groupId>org.apache.maven.plugins</groupId>
  83. <artifactId>maven-surefire-plugin</artifactId>
  84. <version>2.12.4</version>
  85. <configuration>
  86. <skipTests>true</skipTests>
  87. </configuration>
  88. </plugin>
  89. <plugin>
  90. <groupId>org.apache.maven.plugins</groupId>
  91. <artifactId>maven-compiler-plugin</artifactId>
  92. <configuration>
  93. <source>8</source>
  94. <target>8</target>
  95. </configuration>
  96. </plugin>
  97. </plugins>
  98. </build>
  99. </project>

请求参数

  1. package com.xyb.xfxh.dto;
  2. import com.alibaba.fastjson.annotation.JSONField;
  3. import com.fasterxml.jackson.annotation.JsonProperty;
  4. import lombok.AllArgsConstructor;
  5. import lombok.Builder;
  6. import lombok.Data;
  7. import lombok.NoArgsConstructor;
  8. import java.util.List;
  9. /**
  10. * 请求参数
  11. */
  12. @NoArgsConstructor
  13. @Data
  14. @Builder
  15. @AllArgsConstructor
  16. public class RequestDTO {
  17. @JsonProperty("header")
  18. private HeaderDTO header;
  19. @JsonProperty("parameter")
  20. private ParameterDTO parameter;
  21. @JsonProperty("payload")
  22. private PayloadDTO payload;
  23. @NoArgsConstructor
  24. @Data
  25. @AllArgsConstructor
  26. @Builder
  27. public static class HeaderDTO {
  28. /**
  29. * 应用appid,从开放平台控制台创建的应用中获取
  30. */
  31. @JSONField(name = "app_id")
  32. private String appId;
  33. /**
  34. * 每个用户的id,用于区分不同用户,最大长度32
  35. */
  36. @JSONField(name = "uid")
  37. private String uid;
  38. }
  39. @NoArgsConstructor
  40. @Data
  41. @AllArgsConstructor
  42. @Builder
  43. public static class ParameterDTO {
  44. private ChatDTO chat;
  45. @NoArgsConstructor
  46. @Data
  47. @AllArgsConstructor
  48. @Builder
  49. public static class ChatDTO {
  50. /**
  51. * 指定访问的领域,generalv3指向V3.0版本!
  52. */
  53. @JsonProperty("domain")
  54. private String domain = "generalv3";
  55. /**
  56. * 核采样阈值。用于决定结果随机性,取值越高随机性越强即相同的问题得到的不同答案的可能性越高
  57. */
  58. @JsonProperty("temperature")
  59. private Float temperature = 0.5F;
  60. /**
  61. * 模型回答的tokens的最大长度
  62. */
  63. @JSONField(name = "max_tokens")
  64. private Integer maxTokens = 2048;
  65. }
  66. }
  67. @NoArgsConstructor
  68. @Data
  69. @AllArgsConstructor
  70. @Builder
  71. public static class PayloadDTO {
  72. @JsonProperty("message")
  73. private MessageDTO message;
  74. @NoArgsConstructor
  75. @Data
  76. @AllArgsConstructor
  77. @Builder
  78. public static class MessageDTO {
  79. @JsonProperty("text")
  80. private List<MsgDTO> text;
  81. }
  82. }
  83. }

注意:domain具体看你选择的模型

响应参数

  1. package com.xyb.xfxh.dto;
  2. import com.fasterxml.jackson.annotation.JsonProperty;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. import java.util.List;
  6. @NoArgsConstructor
  7. @Data
  8. public class ResponseDTO {
  9. @JsonProperty("header")
  10. private HeaderDTO header;
  11. @JsonProperty("payload")
  12. private PayloadDTO payload;
  13. @NoArgsConstructor
  14. @Data
  15. public static class HeaderDTO {
  16. /**
  17. * 错误码,0表示正常,非0表示出错
  18. */
  19. @JsonProperty("code")
  20. private Integer code;
  21. /**
  22. * 会话是否成功的描述信息
  23. */
  24. @JsonProperty("message")
  25. private String message;
  26. /**
  27. * 会话的唯一id,用于讯飞技术人员查询服务端会话日志使用,出现调用错误时建议留存该字段
  28. */
  29. @JsonProperty("sid")
  30. private String sid;
  31. /**
  32. * 会话状态,取值为[0,1,2];0代表首次结果;1代表中间结果;2代表最后一个结果
  33. */
  34. @JsonProperty("status")
  35. private Integer status;
  36. }
  37. @NoArgsConstructor
  38. @Data
  39. public static class PayloadDTO {
  40. @JsonProperty("choices")
  41. private ChoicesDTO choices;
  42. /**
  43. * 在最后一次结果返回
  44. */
  45. @JsonProperty("usage")
  46. private UsageDTO usage;
  47. @NoArgsConstructor
  48. @Data
  49. public static class ChoicesDTO {
  50. /**
  51. * 文本响应状态,取值为[0,1,2]; 0代表首个文本结果;1代表中间文本结果;2代表最后一个文本结果
  52. */
  53. @JsonProperty("status")
  54. private Integer status;
  55. /**
  56. * 返回的数据序号,取值为[0,9999999]
  57. */
  58. @JsonProperty("seq")
  59. private Integer seq;
  60. /**
  61. * 响应文本
  62. */
  63. @JsonProperty("text")
  64. private List<MsgDTO> text;
  65. }
  66. @NoArgsConstructor
  67. @Data
  68. public static class UsageDTO {
  69. @JsonProperty("text")
  70. private TextDTO text;
  71. @NoArgsConstructor
  72. @Data
  73. public static class TextDTO {
  74. /**
  75. * 保留字段,可忽略
  76. */
  77. @JsonProperty("question_tokens")
  78. private Integer questionTokens;
  79. /**
  80. * 包含历史问题的总tokens大小
  81. */
  82. @JsonProperty("prompt_tokens")
  83. private Integer promptTokens;
  84. /**
  85. * 回答的tokens大小
  86. */
  87. @JsonProperty("completion_tokens")
  88. private Integer completionTokens;
  89. /**
  90. * prompt_tokens和completion_tokens的和,也是本次交互计费的tokens大小
  91. */
  92. @JsonProperty("total_tokens")
  93. private Integer totalTokens;
  94. }
  95. }
  96. }
  97. }

MsgDto类

  1. package com.xyb.xfxh.dto;
  2. import com.fasterxml.jackson.annotation.JsonInclude;
  3. import lombok.AllArgsConstructor;
  4. import lombok.Builder;
  5. import lombok.Data;
  6. import lombok.NoArgsConstructor;
  7. @Data
  8. @AllArgsConstructor
  9. @NoArgsConstructor
  10. @Builder
  11. @JsonInclude(JsonInclude.Include.NON_NULL)
  12. public class MsgDTO {
  13. /**
  14. * 角色
  15. */
  16. private String role;
  17. /**
  18. * 消息内容
  19. */
  20. private String content;
  21. /**
  22. * 响应结果字段:结果序号,取值为[0,10]; 当前为保留字段,开发者可忽略
  23. */
  24. private Integer index;
  25. public static final String ROLE_USER = "user";
  26. public static final String ROLE_ASSISTANT = "assistant";
  27. public static MsgDTO createUserMsg(String content) {
  28. return new MsgDTO(ROLE_USER, content, null);
  29. }
  30. public static MsgDTO createAssistantMsg(String content) {
  31. return new MsgDTO(ROLE_ASSISTANT, content, null);
  32. }
  33. }

定义接口

  1. public interface IOpenAiApi {
  2. String v1_chat_completions = "v3.1/chat/";
  3. /**
  4. * 默认 星火认知大模型 问答模型
  5. * @param chatCompletionRequest 请求信息
  6. * @return 返回结果
  7. */
  8. @POST(v1_chat_completions)
  9. Single<ResponseDTO> completions(@Body RequestDTO chatCompletionRequest);
  10. }

在IOpenAiApi 接口中定义访问接口,目前只有简单问答模型。

会话接口

  1. public interface OpenAiSession {
  2. /**
  3. * 星火认知大模型
  4. * @param requestDTO
  5. * @param
  6. * @return
  7. */
  8. WebSocket completions(RequestDTO requestDTO, WebSocketListener listener) throws Exception;
  9. /**
  10. * 星火认知大模型, 用自己的数据
  11. * @param requestDTO
  12. * @param
  13. * @return
  14. */
  15. WebSocket completions(String apiHost, String apiKey, RequestDTO requestDTO, WebSocketListener listener) throws Exception;

会话接口 OpenAiSession 与 IOpenAiApi 看上去是有些类似的。但有了这样一个接口,就可以封装出各类需要的扩展方法了。

会话工厂

  1. public class DefaultOpenAiSessionFactory implements OpenAiSessionFactory {
  2. private final Configuration configuration;
  3. public DefaultOpenAiSessionFactory(Configuration configuration) {
  4. this.configuration = configuration;
  5. }
  6. @Override
  7. public OpenAiSession openSession() {
  8. // 日志配置
  9. HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
  10. httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
  11. // 创建http客户端
  12. OpenAiInterceptor openAiInterceptor = new OpenAiInterceptor(configuration.getApiKey(), configuration);
  13. OkHttpClient okHttpClient = new OkHttpClient
  14. .Builder()
  15. .addInterceptor(httpLoggingInterceptor)
  16. // .addInterceptor(openAiInterceptor)
  17. .connectTimeout(450, TimeUnit.SECONDS)
  18. .writeTimeout(450, TimeUnit.SECONDS)
  19. .readTimeout(450, TimeUnit.SECONDS)
  20. .build();
  21. configuration.setOkHttpClient(okHttpClient);
  22. // 开启openai会话
  23. IOpenAiApi openAiApi = new Retrofit.Builder()
  24. .baseUrl(configuration.getApiHost())
  25. .client(okHttpClient)
  26. .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
  27. .addConverterFactory(JacksonConverterFactory.create())
  28. .build().create(IOpenAiApi.class);
  29. configuration.setOpenAiApi(openAiApi);
  30. return new DefaultOpenAiSession(configuration);
  31. }
  32. }

本来的目的是为了把HTTP相关的配置统一在这里配好,结果星火API不支持http协议,如果某个api是用http请求的,可以在这里进行统一配置。

会话接口的实现

  1. public class DefaultOpenAiSession implements OpenAiSession {
  2. /** 配置信息 */
  3. private final Configuration configuration;
  4. private final EventSource.Factory factory;
  5. private final IOpenAiApi openAiApi;
  6. private static final String V = "v3.1/chat";
  7. public DefaultOpenAiSession(Configuration configuration) {
  8. this.configuration = configuration;
  9. this.openAiApi = configuration.getOpenAiApi();
  10. this.factory = configuration.createRequestFactory();
  11. }
  12. @Override
  13. public WebSocket completions(RequestDTO chatCompletionRequest, WebSocketListener listener) throws Exception {
  14. return this.completions(null, null, chatCompletionRequest, listener);
  15. }
  16. @Override
  17. public WebSocket completions(String apiHostByUser, String apiKeyByUser, RequestDTO chatCompletionRequest, WebSocketListener listener) throws Exception {
  18. // 动态设置 Host、Key,便于用户传递自己的信息
  19. String apiHost = apiHostByUser == null ? configuration.getApiHost() : apiHostByUser;
  20. String apiKey = apiKeyByUser == null ? configuration.getApiKey() : apiKeyByUser;
  21. // 构建请求信息
  22. String key = AuthUtil.getKey(apiKey, configuration);
  23. System.out.println(key);
  24. Request request = new Request.Builder()
  25. // 这里的url需注意,需要提前处理好key,具体请前往讯飞开发平台查看开发文档
  26. // 参考格式:wss://spark-api.xf-yun.com/v1.1/chat?authorization=YXBpX2tleT0iYWRkZDIyNzJiNmQ4YjdjOGFiZGQ3OTUzMTQyMGNhM2IiLCBhbGdvcml0aG09ImhtYWMtc2hhMjU2IiwgaGVhZGVycz0iaG9zdCBkYXRlIHJlcXVlc3QtbGluZSIsIHNpZ25hdHVyZT0iejVnSGR1M3B4VlY0QURNeWs0Njd3T1dEUTlxNkJRelIzbmZNVGpjL0RhUT0i&date=Fri%2C+05+May+2023+10%3A43%3A39+GMT&host=spark-api.xf-yun.com
  27. .url(key)
  28. .build();
  29. // 建立 wss 连接
  30. OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
  31. WebSocket webSocket = okHttpClient.newWebSocket(request, listener);
  32. // 发送请求
  33. webSocket.send(JSONObject.toJSONString(chatCompletionRequest));
  34. // 返回结果信息
  35. return webSocket;
  36. }
  37. }

这样就可以通过OpenAiSession接口调用此服务啦

websocket鉴权

开发者需要自行先在控制台创建应用,利用应用中提供的appid,APIKey, APISecret进行鉴权,生成最终请求的鉴权url

  1. public class AuthUtil {
  2. public static String getKey(String apiKeyBySystem, Configuration configuration) throws Exception {
  3. // 时间
  4. SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
  5. format.setTimeZone(TimeZone.getTimeZone("GMT"));
  6. String date = format.format(new Date());
  7. // 拼接
  8. URL url = new URL(configuration.getApiHost().concat("v3.1/chat"));
  9. String preStr = "host: " + url.getHost() + "\n" +
  10. "date: " + date + "\n" +
  11. "GET " + url.getPath() + " HTTP/1.1";
  12. System.out.println(preStr);
  13. // SHA256加密
  14. Mac mac = Mac.getInstance("hmacsha256");
  15. SecretKeySpec spec = new SecretKeySpec(configuration.getApiSecret().getBytes(StandardCharsets.UTF_8), "hmacsha256");
  16. mac.init(spec);
  17. byte[] hexDigits = mac.doFinal(preStr.getBytes(StandardCharsets.UTF_8));
  18. // Base64加密
  19. String sha = Base64.getEncoder().encodeToString(hexDigits);
  20. // 拼接
  21. String authorizationOrigin = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", apiKeyBySystem, "hmac-sha256", "host date request-line", sha);
  22. String encodeToString = Base64.getEncoder().encodeToString(authorizationOrigin.getBytes(StandardCharsets.UTF_8));
  23. String most_url = url+"?authorization="+encodeToString+"&date="+date+"&host="+url.getHost();
  24. return most_url;
  25. }
  26. }

一定得注意星火api的url格式,建议详读开发文档,星火认知大模型服务说明 | 讯飞开放平台文档中心 (xfyun.cn)

下面是测试代码

  1. @Slf4j
  2. public class ApiTest {
  3. private OpenAiSession openAiSession;
  4. private StringBuilder answer = new StringBuilder();
  5. @Before
  6. public void test_OpenAiSessionFactory() {
  7. // 1. 配置文件
  8. Configuration configuration = new Configuration();
  9. configuration.setAppId("你的appId");
  10. configuration.setApiHost("https://spark-api.xf-yun.com/");
  11. configuration.setApiKey("你的apikey");
  12. configuration.setApiSecret("你的apiSecret");
  13. // 可以根据课程首页评论置顶说明获取 apihost、apikey;https://t.zsxq.com/0d3o5FKvc
  14. // configuration.setAuthToken("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ4ZmciLCJleHAiOjE2ODMyNzIyMjAsImlhdCI6MTY4MzI2ODYyMCwianRpIjoiOTkwMmM4MjItNzI2MC00OGEwLWI0NDUtN2UwZGZhOGVhOGYwIiwidXNlcm5hbWUiOiJ4ZmcifQ.Om7SdWdiIevvaWdPn7D9PnWS-ZmgbNodYTh04Tfb124");
  15. // 2. 会话工厂
  16. OpenAiSessionFactory factory = new DefaultOpenAiSessionFactory(configuration);
  17. // 3. 开启会话
  18. this.openAiSession = factory.openSession();
  19. }
  20. /**
  21. * 【常用对话模式,推荐使用此模型进行测试】
  22. * 此对话模型 3.0 接近于官网体验 & 流式应答
  23. */
  24. @Test
  25. public void test_chat_completions_stream_channel() throws Exception {
  26. RequestDTO chatCompletion = RequestDTO
  27. .builder()
  28. .header(RequestDTO.HeaderDTO.builder().appId("你的appId").uid("111").build())
  29. .parameter(RequestDTO.ParameterDTO.builder().chat(RequestDTO.ParameterDTO.ChatDTO.builder().domain("generalv3").maxTokens(2048).temperature(0.5F).build()).build())
  30. .payload(RequestDTO.PayloadDTO.builder().message(RequestDTO.PayloadDTO.MessageDTO.builder().text(Collections.singletonList(MsgDTO.builder().role("user").content("你是谁").index(1).build())).build()).build()).build();
  31. // 3. 发起请求
  32. WebSocket webSocket = openAiSession.completions(chatCompletion, new WebSocketListener() {
  33. @Override
  34. public void onOpen(WebSocket webSocket, Response response) {
  35. super.onOpen(webSocket, response);
  36. log.info("连接成功");
  37. }
  38. @Override
  39. public void onMessage(WebSocket webSocket, String text) {
  40. super.onMessage(webSocket, text);
  41. // 将大模型回复的 JSON 文本转为 ResponseDTO 对象
  42. ResponseDTO responseData = JSONObject.parseObject(text, ResponseDTO.class);
  43. // 如果响应数据中的 header 的 code 值不为 0,则表示响应错误
  44. if (responseData.getHeader().getCode() != 0) {
  45. // 日志记录
  46. log.error("发生错误,错误码为:" + responseData.getHeader().getCode() + "; " + "信息:" + responseData.getHeader().getMessage());
  47. return;
  48. }
  49. // 将回答进行拼接
  50. for (MsgDTO msgDTO : responseData.getPayload().getChoices().getText()) {
  51. // apiTest.answer.append(msgDTO.getContent());
  52. log.info("text:"+msgDTO.getContent());
  53. }
  54. /* // 对最后一个文本结果进行处理
  55. if (2 == responseData.getHeader().getStatus()) {
  56. wsCloseFlag = true;
  57. }*/
  58. }
  59. @Override
  60. public void onFailure(WebSocket webSocket, Throwable t, Response response) {
  61. super.onFailure(webSocket, t, response);
  62. log.error("error:"+response.message());
  63. }
  64. });
  65. // 等待
  66. new CountDownLatch(1).await();
  67. }
  68. }

现在应该就能正常使用讯飞的星火大模型了

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号