赞
踩
Kimi,是月之暗面于2023年10月推出的一款智能助手,主要应用场景为专业学术论文的翻译和理解、辅助分析法律问题、快速理解API开发文档等,是全球首个支持输入20万汉字的智能助手产品
打开网址Moonshot AI - 开放平台 ,可以看到官网比较简洁,有两部分构成,api文档和用户中心
点击用户中心,可以用微信登录,然后在API Key管理中新建一个key,记录下来
由于跟kimi对接需要用到SSE(Server Send Event),我们使用okhttp库
- <dependency>
- <groupId>cn.hutool</groupId>
- <artifactId>hutool-all</artifactId>
- <version>5.8.25</version>
- </dependency>
- <dependency>
- <groupId>com.squareup.okhttp3</groupId>
- <artifactId>okhttp</artifactId>
- <version>4.10.0</version>
- </dependency>
- <dependency>
- <groupId>com.squareup.okhttp3</groupId>
- <artifactId>okhttp-sse</artifactId>
- <version>4.10.0</version>
- </dependency>
- @NoArgsConstructor
- @AllArgsConstructor
- @Data
- @Builder
- public class Message {
-
- private String role;
-
- private String content;
-
- }
- public enum RoleEnum {
- system,
- user,
- assistant;
- }
- public class MoonshotAiUtils {
- private static final String API_KEY = "api key";
- private static final String MODELS_URL = "https://api.moonshot.cn/v1/models";
- private static final String FILES_URL = "https://api.moonshot.cn/v1/files";
- private static final String ESTIMATE_TOKEN_COUNT_URL = "https://api.moonshot.cn/v1/tokenizers/estimate-token-count";
- private static final String CHAT_COMPLETION_URL = "https://api.moonshot.cn/v1/chat/completions";
-
- public static String getModelList() {
- return getCommonRequest(MODELS_URL)
- .execute()
- .body();
- }
-
- public static String uploadFile(@NonNull File file) {
- return getCommonRequest(FILES_URL)
- .method(Method.POST)
- .header("purpose", "file-extract")
- .form("file", file)
- .execute()
- .body();
- }
-
- public static String getFileList() {
- return getCommonRequest(FILES_URL)
- .execute()
- .body();
- }
-
- public static String deleteFile(@NonNull String fileId) {
- return getCommonRequest(FILES_URL + "/" + fileId)
- .method(Method.DELETE)
- .execute()
- .body();
- }
-
- public static String getFileDetail(@NonNull String fileId) {
- return getCommonRequest(FILES_URL + "/" + fileId)
- .execute()
- .body();
- }
-
- public static String getFileContent(@NonNull String fileId) {
- return getCommonRequest(FILES_URL + "/" + fileId + "/content")
- .execute()
- .body();
- }
-
- public static String estimateTokenCount(@NonNull String model, @NonNull List<Message> messages) {
- String requestBody = new JSONObject()
- .putOpt("model", model)
- .putOpt("messages", messages)
- .toString();
- return getCommonRequest(ESTIMATE_TOKEN_COUNT_URL)
- .method(Method.POST)
- .header(Header.CONTENT_TYPE, ContentType.JSON.getValue())
- .body(requestBody)
- .execute()
- .body();
- }
-
- @SneakyThrows
- public static String chat(@NonNull String model, @NonNull List<Message> messages) {
- StringBuilder sb = new StringBuilder();
- String requestBody = new JSONObject()
- .putOpt("model", model)
- .putOpt("messages", messages)
- .putOpt("stream", true)
- .toString();
- Request okhttpRequest = new Request.Builder()
- .url(CHAT_COMPLETION_URL)
- .post(RequestBody.create(requestBody, MediaType.get(ContentType.JSON.getValue())))
- .addHeader("Authorization", "Bearer " + API_KEY)
- .build();
- Call call = new OkHttpClient().newCall(okhttpRequest);
- Response okhttpResponse = call.execute();
- BufferedReader reader = new BufferedReader(okhttpResponse.body().charStream());
- try {
- String line;
- while ((line = reader.readLine()) != null) {
- if (StrUtil.isBlank(line)) {
- continue;
- }
- if (JSONUtil.isTypeJSON(line)) {
- Optional.of(JSONUtil.parseObj(line))
- .map(x -> x.getJSONObject("error"))
- .map(x -> x.getStr("message"))
- .ifPresent(x -> System.out.println("error: " + x));
- JSONObject jsonObject = JSONUtil.parseObj(line);
- throw new ServiceFailException(jsonObject.getJSONObject("error").getStr("message"));
- }
- line = StrUtil.replace(line, "data: ", StrUtil.EMPTY);
- if (StrUtil.equals("[DONE]", line) || !JSONUtil.isTypeJSON(line)) {
- return sb.toString();
- }
- Optional.of(JSONUtil.parseObj(line))
- .map(x -> x.getJSONArray("choices"))
- .filter(CollUtil::isNotEmpty)
- .map(x -> (JSONObject) x.get(0))
- .map(x -> x.getJSONObject("delta"))
- .map(x -> x.getStr("content"))
- .ifPresent(x -> sb.append(x));
- }
- return sb.toString();
- } finally {
- IoUtil.close(reader);
- }
- }
-
- private static HttpRequest getCommonRequest(@NonNull String url) {
- return HttpRequest.of(url).header(Header.AUTHORIZATION, "Bearer " + API_KEY);
- }
- }

- @RestController
- @RequestMapping("/kimi")
- @Tag(name = "kimi管理")
- public class KimiController extends BaseController {
- // 演示用,实际要存入用户session
- private List<Message> messages = new ArrayList<>();
-
- @Operation(summary = "聊天")
- @GetMapping("chat")
- public Result chat(String content) {
- Message message = new Message(RoleEnum.user.name(), content);
- messages.add(message);
- // 模型列表 https://platform.moonshot.cn/docs/intro#%E6%A8%A1%E5%9E%8B%E5%88%97%E8%A1%A8
- String result = MoonshotAiUtils.chat("moonshot-v1-8k", messages);
- return resultOk(result);
- }
- }

代码都挺简单的,需要注意的是用户的多次问答需要放到一个list中一起发送给kimi,这样kimi才能根据上下文回答问题
提取文档摘要我们先要把文档上传到kimi获取一个content,再调用聊天接口给提示词就行了
- @Operation(summary = "提取文档摘要")
- @GetMapping("docSummary")
- public Result docSummary() {
- String hint = "请简要描述文档中的内容";
- String content = MoonshotAiUtils.uploadFile(new File("d:/read.docx"));
- List<Message> messages = CollUtil.newArrayList(
- new Message(RoleEnum.system.name(), content),
- new Message(RoleEnum.user.name(), hint)
- );
- String result = MoonshotAiUtils.chat("moonshot-v1-32k", messages);
- return resultOk(result);
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。