├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── src ├── main │ ├── java │ │ └── com │ │ │ └── tutu │ │ │ └── knowledge_box │ │ │ ├── vo │ │ │ └── QuestionVo.java │ │ │ ├── enums │ │ │ └── KnowledgeEntityEnum.java │ │ │ ├── module │ │ │ ├── knowledge │ │ │ │ ├── Item.java │ │ │ │ ├── AskQuestionUtil.java │ │ │ │ └── LoadKnowledgeUtil.java │ │ │ └── RedisModule.java │ │ │ ├── KnowledgeBoxApplication.java │ │ │ ├── ai │ │ │ ├── openai │ │ │ │ ├── edit │ │ │ │ │ ├── EditChoice.java │ │ │ │ │ ├── EditUsage.java │ │ │ │ │ ├── EditResult.java │ │ │ │ │ └── EditRequest.java │ │ │ │ ├── OpenAiResponse.java │ │ │ │ ├── completion │ │ │ │ │ ├── chat │ │ │ │ │ │ ├── ChatMessageRole.java │ │ │ │ │ │ ├── ChatCompletionChoice.java │ │ │ │ │ │ ├── ChatCompletionResult.java │ │ │ │ │ │ ├── ChatMessage.java │ │ │ │ │ │ └── ChatCompletionRequest.java │ │ │ │ │ ├── CompletionChoice.java │ │ │ │ │ ├── CompletionResult.java │ │ │ │ │ ├── LogProbResult.java │ │ │ │ │ └── CompletionRequest.java │ │ │ │ ├── DeleteResult.java │ │ │ │ ├── image │ │ │ │ │ ├── ImageResult.java │ │ │ │ │ ├── Image.java │ │ │ │ │ ├── CreateImageVariationRequest.java │ │ │ │ │ ├── CreateImageRequest.java │ │ │ │ │ └── CreateImageEditRequest.java │ │ │ │ ├── moderation │ │ │ │ │ ├── ModerationRequest.java │ │ │ │ │ ├── ModerationResult.java │ │ │ │ │ ├── ModerationCategories.java │ │ │ │ │ ├── ModerationCategoryScores.java │ │ │ │ │ └── Moderation.java │ │ │ │ ├── embedding │ │ │ │ │ ├── Embedding.java │ │ │ │ │ ├── EmbeddingResult.java │ │ │ │ │ └── EmbeddingRequest.java │ │ │ │ ├── Usage.java │ │ │ │ ├── engine │ │ │ │ │ └── Engine.java │ │ │ │ ├── finetune │ │ │ │ │ ├── FineTuneEvent.java │ │ │ │ │ ├── HyperParameters.java │ │ │ │ │ ├── FineTuneResult.java │ │ │ │ │ └── FineTuneRequest.java │ │ │ │ ├── file │ │ │ │ │ └── File.java │ │ │ │ ├── OpenAiHttpException.java │ │ │ │ ├── OpenAiError.java │ │ │ │ └── model │ │ │ │ │ ├── Model.java │ │ │ │ │ └── Permission.java │ │ │ ├── AuthenticationInterceptor.java │ │ │ ├── OpenAiApiExample.java │ │ │ ├── OpenAiModule.java │ │ │ ├── OpenAiApi.java │ │ │ └── OpenAiService.java │ │ │ ├── entity │ │ │ ├── BaseResponse.java │ │ │ └── knowledge │ │ │ │ └── OccupationClassification.java │ │ │ ├── controller │ │ │ └── AIController.java │ │ │ ├── config │ │ │ └── RedisConfig.java │ │ │ └── service │ │ │ └── AIService.java │ └── resources │ │ └── application.yaml └── test │ └── java │ └── com │ └── tutu │ └── knowledge_box │ └── KnowledgeBoxApplicationTests.java ├── .gitignore ├── README.md ├── pom.xml ├── mvnw.cmd └── mvnw /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FFFamily/knowledge_box/HEAD/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/vo/QuestionVo.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.vo; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class QuestionVo { 7 | /** 8 | * 问题 9 | */ 10 | private String question; 11 | } 12 | -------------------------------------------------------------------------------- /src/test/java/com/tutu/knowledge_box/KnowledgeBoxApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class KnowledgeBoxApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/enums/KnowledgeEntityEnum.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.enums; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | @AllArgsConstructor 7 | @Getter 8 | public enum KnowledgeEntityEnum { 9 | OccupationClassification("职业分类表.xlsx") 10 | ; 11 | private String value; 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/module/knowledge/Item.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.module.knowledge; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.math.BigDecimal; 8 | 9 | @Data 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | public class Item { 13 | private int index; 14 | private BigDecimal dot; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/KnowledgeBoxApplication.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class KnowledgeBoxApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(KnowledgeBoxApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/edit/EditChoice.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.edit; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * An edit generated by GPT-3 7 | * 8 | * https://beta.openai.com/docs/api-reference/edits/create 9 | */ 10 | @Data 11 | public class EditChoice { 12 | 13 | /** 14 | * The edited text. 15 | */ 16 | String text; 17 | 18 | /** 19 | * This index of this completion in the returned list. 20 | */ 21 | Integer index; 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/OpenAiResponse.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * A wrapper class to fit the OpenAI engine and search endpoints 9 | */ 10 | @Data 11 | public class OpenAiResponse { 12 | /** 13 | * A list containing the actual results 14 | */ 15 | public List data; 16 | 17 | /** 18 | * The type of object returned, should be "list" 19 | */ 20 | public String object; 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/entity/BaseResponse.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | 6 | @Data 7 | @AllArgsConstructor 8 | public class BaseResponse { 9 | private int code; 10 | private String msg; 11 | 12 | public static BaseResponse SUCCESS(){ 13 | return new BaseResponse(200,"成功"); 14 | } 15 | 16 | public static BaseResponse success(String message){ 17 | return new BaseResponse(200,message); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/completion/chat/ChatMessageRole.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.completion.chat; 2 | 3 | /** 4 | * see {@link ChatMessage} documentation. 5 | */ 6 | public enum ChatMessageRole { 7 | SYSTEM("system"), 8 | USER("user"), 9 | ASSISTANT("assistant"); 10 | 11 | private final String value; 12 | 13 | ChatMessageRole(final String value) { 14 | this.value = value; 15 | } 16 | 17 | public String value() { 18 | return value; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/DeleteResult.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * A response when deleting an object 7 | */ 8 | @Data 9 | public class DeleteResult { 10 | /** 11 | * The id of the object. 12 | */ 13 | String id; 14 | 15 | /** 16 | * The type of object deleted, for example "file" or "model" 17 | */ 18 | String object; 19 | 20 | /** 21 | * True if successfully deleted 22 | */ 23 | boolean deleted; 24 | } 25 | -------------------------------------------------------------------------------- /src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 # 端口 3 | redis: 4 | # Redis服务器地址 5 | host: 19.1.5.11 6 | # Redis服务器端口号 7 | port: 6379 8 | # 使用的数据库索引,默认是0 9 | database: 0 10 | # 连接超时时间 11 | timeout: 1800000 12 | # 设置密码 13 | password: "123456" 14 | lettuce: 15 | pool: 16 | # 最大阻塞等待时间,负数表示没有限制 17 | max-wait: -1 18 | # 连接池中的最大空闲连接 19 | max-idle: 5 20 | # 连接池中的最小空闲连接 21 | min-idle: 0 22 | # 连接池中最大连接数,负数表示没有限制 23 | max-active: 20 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/image/ImageResult.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.image; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * An object with a list of image results. 9 | * 10 | * https://beta.openai.com/docs/api-reference/images 11 | */ 12 | @Data 13 | public class ImageResult { 14 | 15 | /** 16 | * The creation time in epoch seconds. 17 | */ 18 | Long created; 19 | 20 | /** 21 | * List of image results. 22 | */ 23 | List data; 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/module/RedisModule.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.module; 2 | 3 | import jakarta.annotation.Resource; 4 | import org.springframework.data.redis.core.RedisTemplate; 5 | import org.springframework.stereotype.Component; 6 | 7 | @Component 8 | public class RedisModule { 9 | 10 | @Resource 11 | private RedisTemplate redisTemplate; 12 | 13 | /** 14 | * set 15 | */ 16 | public void set(String key,String value){ 17 | redisTemplate.opsForValue().set(key,value); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/image/Image.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.image; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.Data; 5 | 6 | /** 7 | * An object containing either a URL or a base 64 encoded image. 8 | * 9 | * https://beta.openai.com/docs/api-reference/images 10 | */ 11 | @Data 12 | public class Image { 13 | /** 14 | * The URL where the image can be accessed. 15 | */ 16 | String url; 17 | 18 | 19 | /** 20 | * Base64 encoded image string. 21 | */ 22 | @JsonProperty("b64_json") 23 | String b64Json; 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/moderation/ModerationRequest.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.moderation; 2 | 3 | import lombok.*; 4 | 5 | /** 6 | * A request for OpenAi to detect if text violates OpenAi's content policy. 7 | * 8 | * https://beta.openai.com/docs/api-reference/moderations/create 9 | */ 10 | @Builder 11 | @NoArgsConstructor 12 | @AllArgsConstructor 13 | @Data 14 | public class ModerationRequest { 15 | 16 | /** 17 | * The input text to classify. 18 | */ 19 | @NonNull 20 | String input; 21 | 22 | /** 23 | * The name of the model to use, defaults to text-moderation-stable. 24 | */ 25 | String model; 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/embedding/Embedding.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.embedding; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Represents an embedding returned by the embedding api 9 | * 10 | * https://beta.openai.com/docs/api-reference/classifications/create 11 | */ 12 | @Data 13 | public class Embedding { 14 | 15 | /** 16 | * The type of object returned, should be "embedding" 17 | */ 18 | String object; 19 | 20 | /** 21 | * The embedding vector 22 | */ 23 | List embedding; 24 | 25 | /** 26 | * The position of this embedding in the list 27 | */ 28 | Integer index; 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/moderation/ModerationResult.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.moderation; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * An object containing a response from the moderation api 9 | * 10 | * https://beta.openai.com/docs/api-reference/moderations/create 11 | */ 12 | @Data 13 | public class ModerationResult { 14 | /** 15 | * A unique id assigned to this moderation. 16 | */ 17 | public String id; 18 | 19 | /** 20 | * The GPT-3 model used. 21 | */ 22 | public String model; 23 | 24 | /** 25 | * A list of moderation scores. 26 | */ 27 | public List results; 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/Usage.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.Data; 5 | 6 | /** 7 | * The OpenAI resources used by a request 8 | */ 9 | @Data 10 | public class Usage { 11 | /** 12 | * The number of prompt tokens used. 13 | */ 14 | @JsonProperty("prompt_tokens") 15 | long promptTokens; 16 | 17 | /** 18 | * The number of completion tokens used. 19 | */ 20 | @JsonProperty("completion_tokens") 21 | long completionTokens; 22 | 23 | /** 24 | * The number of total tokens used 25 | */ 26 | @JsonProperty("total_tokens") 27 | long totalTokens; 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/edit/EditUsage.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.edit; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * An object containing the API usage for an edit request 7 | * 8 | * Deprecated, use {@link com.theokanning.openai.Usage} instead 9 | * 10 | * https://beta.openai.com/docs/api-reference/edits/create 11 | */ 12 | @Data 13 | @Deprecated 14 | public class EditUsage { 15 | 16 | /** 17 | * The number of prompt tokens consumed. 18 | */ 19 | String promptTokens; 20 | 21 | /** 22 | * The number of completion tokens consumed. 23 | */ 24 | String completionTokens; 25 | 26 | /** 27 | * The number of total tokens consumed. 28 | */ 29 | String totalTokens; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/completion/chat/ChatCompletionChoice.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.completion.chat; 2 | import com.fasterxml.jackson.annotation.JsonProperty; 3 | import lombok.Data; 4 | 5 | /** 6 | * A chat completion generated by GPT-3.5 7 | */ 8 | @Data 9 | public class ChatCompletionChoice { 10 | 11 | /** 12 | * This index of this completion in the returned list. 13 | */ 14 | Integer index; 15 | 16 | /** 17 | * The {@link ChatMessageRole#assistant} message which was generated. 18 | */ 19 | ChatMessage message; 20 | 21 | /** 22 | * The reason why GPT-3 stopped generating, for example "length". 23 | */ 24 | @JsonProperty("finish_reason") 25 | String finishReason; 26 | } 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # knowledge_box 2 | 抱歉已经暂停维护,以下需求皆为未能完成的需求开发任务 3 | 4 | 基于GPT搭建属于自己的知识库问答系统 5 | 6 | 现在GPT很是火热,各种针对GPT搭建的对话聊天、与PDF交流、代码生成、SQL编写等项目都冒了出来 7 | 本项目也是结合GPT的Demo以及公司需求构建,基于SpringBoot的知识库问答系统 8 | 9 | ## 场景 10 | 公司主要做保险业务,会有很多的客户问一些保险产品信息或者职业信息,这些都基本上是运营去查资料然后回答客户,或许会有某些复杂问题, 11 | 但遇到简单问题的时候运营也需要去查资料,这样会浪费很多时间,降低效率。现在GPT的火热,使得知识库这样的概念进入视野。 12 | 那么组建公司私有的知识库就显得很重要了。 13 | 14 | ## 需求整理 15 | - 基本的问答系统 16 | - 支持上下文对话问答 17 | - 目前知识库只有一个,未来肯定存在多个知识库的情况,如何训练GPT针对性的去某个知识库查询问题 18 | - 收集用户问答满意程度,为后续需求扩展做准备 19 | - 归纳整理问题,统计问题频率,为后续缓存做准备 20 | - 是否可以利用 ES 的矢量计算来存相关问题的回答情况 21 | - 是否可以结合数仓做数据分析 22 | - 接入微信机器人 23 | - 能否整合提词,做语义整理分析 24 | - 让项目更具灵活性,可自定义问答形式 25 | 26 | 27 | 28 | 最近开启维护,欢迎骚扰 29 | ![95831de27c5562cbf1f22c91210673f](https://github.com/FFFamily/knowledge_box/assets/49579222/92bbd0e8-6d22-4ae5-8a44-b64fd13197fa) 30 | 31 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/controller/AIController.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.controller; 2 | 3 | import com.tutu.knowledge_box.entity.BaseResponse; 4 | import com.tutu.knowledge_box.vo.QuestionVo; 5 | import jakarta.annotation.Resource; 6 | import org.springframework.web.bind.annotation.PostMapping; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | @RestController 10 | public class AIController { 11 | // @Resource 12 | // private AIService aiService; 13 | 14 | /** 15 | * 询问问题 16 | */ 17 | @PostMapping("/ask") 18 | public BaseResponse askQuestion(QuestionVo questionVo){ 19 | // String result = aiService.askQuestionFromAI(questionVo.getQuestion()); 20 | // return BaseResponse.success(result); 21 | return BaseResponse.SUCCESS(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/engine/Engine.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.engine; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * GPT-3 engine details 7 | * 8 | * https://beta.openai.com/docs/api-reference/retrieve-engine 9 | */ 10 | @Deprecated 11 | @Data 12 | public class Engine { 13 | /** 14 | * An identifier for this engine, used to specify an engine for completions or searching. 15 | */ 16 | public String id; 17 | 18 | /** 19 | * The type of object returned, should be "engine" 20 | */ 21 | public String object; 22 | 23 | /** 24 | * The owner of the GPT-3 engine, typically "openai" 25 | */ 26 | public String owner; 27 | 28 | /** 29 | * Whether the engine is ready to process requests or not 30 | */ 31 | public boolean ready; 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/AuthenticationInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai; 2 | 3 | import okhttp3.Interceptor; 4 | import okhttp3.Request; 5 | import okhttp3.Response; 6 | 7 | import java.io.IOException; 8 | 9 | /** 10 | * OkHttp Interceptor that adds an authorization token header 11 | */ 12 | public class AuthenticationInterceptor implements Interceptor { 13 | 14 | private final String token; 15 | 16 | AuthenticationInterceptor(String token) { 17 | this.token = token; 18 | } 19 | 20 | @Override 21 | public Response intercept(Chain chain) throws IOException { 22 | Request request = chain.request() 23 | .newBuilder() 24 | .header("Authorization", "Bearer " + token) 25 | .build(); 26 | return chain.proceed(request); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/edit/EditResult.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.edit; 2 | 3 | 4 | import com.tutu.knowledge_box.ai.openai.Usage; 5 | import lombok.Data; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * A list of edits generated by GPT-3 11 | * 12 | * https://beta.openai.com/docs/api-reference/edits/create 13 | */ 14 | @Data 15 | public class EditResult { 16 | 17 | /** 18 | * The type of object returned, should be "edit" 19 | */ 20 | public String object; 21 | 22 | /** 23 | * The creation time in epoch milliseconds. 24 | */ 25 | public long created; 26 | 27 | /** 28 | * A list of generated edits. 29 | */ 30 | public List choices; 31 | 32 | /** 33 | * The API usage for this request 34 | */ 35 | public Usage usage; 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/finetune/FineTuneEvent.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.finetune; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.Data; 5 | 6 | /** 7 | * An object representing an event in the lifecycle of a fine-tuning job 8 | * 9 | * https://beta.openai.com/docs/api-reference/fine-tunes 10 | */ 11 | @Data 12 | public class FineTuneEvent { 13 | /** 14 | * The type of object returned, should be "fine-tune-event". 15 | */ 16 | String object; 17 | 18 | /** 19 | * The creation time in epoch seconds. 20 | */ 21 | @JsonProperty("created_at") 22 | Long createdAt; 23 | 24 | /** 25 | * The log level of this message. 26 | */ 27 | String level; 28 | 29 | /** 30 | * The event message. 31 | */ 32 | String message; 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/OpenAiApiExample.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai; 2 | 3 | 4 | 5 | 6 | import com.tutu.knowledge_box.ai.openai.embedding.EmbeddingRequest; 7 | 8 | import java.util.Collections; 9 | 10 | class OpenAiApiExample { 11 | public static void main(String... args) { 12 | String token = System.getenv("OPENAI_TOKEN"); 13 | OpenAiService service = new OpenAiService(token); 14 | System.out.println("\nCreating completion..."); 15 | EmbeddingRequest completionRequest = EmbeddingRequest.builder() 16 | .model("text-embedding-ada-002") 17 | .input(Collections.singletonList("Somebody once told me the world is gonna roll me")) 18 | .build(); 19 | service.createEmbeddings(completionRequest).getData().forEach(System.out::println); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/embedding/EmbeddingResult.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.embedding; 2 | 3 | 4 | import com.tutu.knowledge_box.ai.openai.Usage; 5 | import lombok.Data; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * An object containing a response from the answer api 11 | * 12 | * https://beta.openai.com/docs/api-reference/embeddings/create 13 | */ 14 | @Data 15 | public class EmbeddingResult { 16 | 17 | /** 18 | * The GPT-3 model used for generating embeddings 19 | */ 20 | String model; 21 | 22 | /** 23 | * The type of object returned, should be "list" 24 | */ 25 | String object; 26 | 27 | /** 28 | * A list of the calculated embeddings 29 | */ 30 | List data; 31 | 32 | /** 33 | * The API usage for this request 34 | */ 35 | Usage usage; 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/moderation/ModerationCategories.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.moderation; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.Data; 5 | 6 | /** 7 | * An object containing the flags for each moderation category 8 | * 9 | * https://beta.openai.com/docs/api-reference/moderations/create 10 | */ 11 | @Data 12 | public class ModerationCategories { 13 | 14 | public boolean hate; 15 | 16 | @JsonProperty("hate/threatening") 17 | public boolean hateThreatening; 18 | 19 | @JsonProperty("self-harm") 20 | public boolean selfHarm; 21 | 22 | public boolean sexual; 23 | 24 | @JsonProperty("sexual/minors") 25 | public boolean sexualMinors; 26 | 27 | public boolean violence; 28 | 29 | @JsonProperty("violence/graphic") 30 | public boolean violenceGraphic; 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/moderation/ModerationCategoryScores.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.moderation; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.Data; 5 | 6 | /** 7 | * An object containing the scores for each moderation category 8 | * 9 | * https://beta.openai.com/docs/api-reference/moderations/create 10 | */ 11 | @Data 12 | public class ModerationCategoryScores { 13 | 14 | public double hate; 15 | 16 | @JsonProperty("hate/threatening") 17 | public double hateThreatening; 18 | 19 | @JsonProperty("self-harm") 20 | public double selfHarm; 21 | 22 | public double sexual; 23 | 24 | @JsonProperty("sexual/minors") 25 | public double sexualMinors; 26 | 27 | public double violence; 28 | 29 | @JsonProperty("violence/graphic") 30 | public double violenceGraphic; 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/completion/CompletionChoice.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.completion; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * A completion generated by GPT-3 7 | * 8 | * https://beta.openai.com/docs/api-reference/completions/create 9 | */ 10 | @Data 11 | public class CompletionChoice { 12 | /** 13 | * The generated text. Will include the prompt if {@link CompletionRequest#echo } is true 14 | */ 15 | String text; 16 | 17 | /** 18 | * This index of this completion in the returned list. 19 | */ 20 | Integer index; 21 | 22 | /** 23 | * The log probabilities of the chosen tokens and the top {@link CompletionRequest#logprobs} tokens 24 | */ 25 | LogProbResult logprobs; 26 | 27 | /** 28 | * The reason why GPT-3 stopped generating, for example "length". 29 | */ 30 | String finish_reason; 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/file/File.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.file; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.Data; 5 | 6 | /** 7 | * A file uploaded to OpenAi 8 | * 9 | * https://beta.openai.com/docs/api-reference/files 10 | */ 11 | @Data 12 | public class File { 13 | 14 | /** 15 | * The unique id of this file. 16 | */ 17 | String id; 18 | 19 | /** 20 | * The type of object returned, should be "file". 21 | */ 22 | String object; 23 | 24 | /** 25 | * File size in bytes. 26 | */ 27 | Long bytes; 28 | 29 | /** 30 | * The creation time in epoch seconds. 31 | */ 32 | @JsonProperty("created_at") 33 | Long createdAt; 34 | 35 | /** 36 | * The name of the file. 37 | */ 38 | String filename; 39 | 40 | /** 41 | * Description of the file's purpose. 42 | */ 43 | String purpose; 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/OpenAiHttpException.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai; 2 | 3 | public class OpenAiHttpException extends RuntimeException { 4 | 5 | /** 6 | * HTTP status code 7 | */ 8 | public final int statusCode; 9 | 10 | /** 11 | * OpenAI error code, for example "invalid_api_key" 12 | */ 13 | public final String code; 14 | 15 | 16 | public final String param; 17 | 18 | /** 19 | * OpenAI error type, for example "invalid_request_error" 20 | * https://platform.openai.com/docs/guides/error-codes/python-library-error-types 21 | */ 22 | public final String type; 23 | 24 | public OpenAiHttpException(OpenAiError error, Exception parent, int statusCode) { 25 | super(error.error.message, parent); 26 | this.statusCode = statusCode; 27 | this.code = error.error.code; 28 | this.param = error.error.param; 29 | this.type = error.error.type; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/finetune/HyperParameters.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.finetune; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.Data; 5 | 6 | /** 7 | * Fine-tuning job hyperparameters 8 | * 9 | * https://beta.openai.com/docs/api-reference/fine-tunes 10 | */ 11 | @Data 12 | public class HyperParameters { 13 | 14 | /** 15 | * The batch size to use for training. 16 | */ 17 | @JsonProperty("batch_size") 18 | Integer batchSize; 19 | 20 | /** 21 | * The learning rate multiplier to use for training. 22 | */ 23 | @JsonProperty("learning_rate_multiplier") 24 | Double learningRateMultiplier; 25 | 26 | /** 27 | * The number of epochs to train the model for. 28 | */ 29 | @JsonProperty("n_epochs") 30 | Integer nEpochs; 31 | 32 | /** 33 | * The weight to use for loss on the prompt tokens. 34 | */ 35 | @JsonProperty("prompt_loss_weight") 36 | Double promptLossWeight; 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/completion/chat/ChatCompletionResult.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.completion.chat; 2 | 3 | import com.tutu.knowledge_box.ai.openai.Usage; 4 | import lombok.Data; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * Object containing a response from the chat completions api. 10 | */ 11 | @Data 12 | public class ChatCompletionResult { 13 | 14 | /** 15 | * Unique id assigned to this chat completion. 16 | */ 17 | String id; 18 | 19 | /** 20 | * The type of object returned, should be "chat.completion" 21 | */ 22 | String object; 23 | 24 | /** 25 | * The creation time in epoch seconds. 26 | */ 27 | long created; 28 | 29 | /** 30 | * The GPT-3.5 model used. 31 | */ 32 | String model; 33 | 34 | /** 35 | * A list of all generated completions. 36 | */ 37 | List choices; 38 | 39 | /** 40 | * The API usage for this request. 41 | */ 42 | Usage usage; 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/OpenAiError.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | /** 8 | * Represents the error body when an OpenAI request fails 9 | */ 10 | @Data 11 | @NoArgsConstructor 12 | @AllArgsConstructor 13 | public class OpenAiError { 14 | 15 | public OpenAiErrorDetails error; 16 | 17 | @Data 18 | @NoArgsConstructor 19 | @AllArgsConstructor 20 | public static class OpenAiErrorDetails { 21 | /** 22 | * Human-readable error message 23 | */ 24 | String message; 25 | 26 | /** 27 | * OpenAI error type, for example "invalid_request_error" 28 | * https://platform.openai.com/docs/guides/error-codes/python-library-error-types 29 | */ 30 | String type; 31 | 32 | String param; 33 | 34 | /** 35 | * OpenAI error code, for example "invalid_api_key" 36 | */ 37 | String code; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip 18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar 19 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/completion/CompletionResult.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.completion; 2 | 3 | import com.tutu.knowledge_box.ai.openai.Usage; 4 | import lombok.Data; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * An object containing a response from the completion api 10 | * 11 | * https://beta.openai.com/docs/api-reference/completions/create 12 | */ 13 | @Data 14 | public class CompletionResult { 15 | /** 16 | * A unique id assigned to this completion. 17 | */ 18 | String id; 19 | 20 | /**https://beta.openai.com/docs/api-reference/create-completion 21 | * The type of object returned, should be "text_completion" 22 | */ 23 | String object; 24 | 25 | /** 26 | * The creation time in epoch seconds. 27 | */ 28 | long created; 29 | 30 | /** 31 | * The GPT-3 model used. 32 | */ 33 | String model; 34 | 35 | /** 36 | * A list of generated completions. 37 | */ 38 | List choices; 39 | 40 | /** 41 | * The API usage for this request 42 | */ 43 | Usage usage; 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/model/Model.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.Data; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * GPT-3 model details 10 | * 11 | * https://beta.openai.com/docs/api-reference/models 12 | */ 13 | @Data 14 | public class Model { 15 | /** 16 | * An identifier for this model, used to specify the model when making completions, etc 17 | */ 18 | public String id; 19 | 20 | /** 21 | * The type of object returned, should be "model" 22 | */ 23 | public String object; 24 | 25 | /** 26 | * The owner of the GPT-3 model, typically "openai" 27 | */ 28 | @JsonProperty("owned_by") 29 | public String ownedBy; 30 | 31 | /** 32 | * List of permissions for this model 33 | */ 34 | public List permission; 35 | 36 | /** 37 | * The root model that this and its parent (if applicable) are based on 38 | */ 39 | public String root; 40 | 41 | /** 42 | * The parent model that this is based on 43 | */ 44 | public String parent; 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/completion/LogProbResult.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.Data; 5 | 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | /** 10 | * Log probabilities of different token options 11 | * Returned if {@link CompletionRequest#logprobs} is greater than zero 12 | * 13 | * https://beta.openai.com/docs/api-reference/create-completion 14 | */ 15 | @Data 16 | public class LogProbResult { 17 | 18 | /** 19 | * The tokens chosen by the completion api 20 | */ 21 | List tokens; 22 | 23 | /** 24 | * The log probability of each token in {@link tokens} 25 | */ 26 | @JsonProperty("token_logprobs") 27 | List tokenLogprobs; 28 | 29 | /** 30 | * A map for each index in the completion result. 31 | * The map contains the top {@link CompletionRequest#logprobs} tokens and their probabilities 32 | */ 33 | @JsonProperty("top_logprobs") 34 | List> topLogprobs; 35 | 36 | /** 37 | * The character offset from the start of the returned text for each of the chosen tokens. 38 | */ 39 | List textOffset; 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/embedding/EmbeddingRequest.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.embedding; 2 | 3 | import lombok.*; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Creates an embedding vector representing the input text. 9 | * 10 | * https://beta.openai.com/docs/api-reference/embeddings/create 11 | */ 12 | @Builder 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | @Data 16 | public class EmbeddingRequest { 17 | 18 | /** 19 | * The name of the model to use. 20 | * Required if using the new v1/embeddings endpoint. 21 | */ 22 | String model; 23 | 24 | /** 25 | * Input text to get embeddings for, encoded as a string or array of tokens. 26 | * To get embeddings for multiple inputs in a single request, pass an array of strings or array of token arrays. 27 | * Each input must not exceed 2048 tokens in length. 28 | *

29 | * Unless you are embedding code, we suggest replacing newlines (\n) in your input with a single space, 30 | * as we have observed inferior results when newlines are present. 31 | */ 32 | @NonNull 33 | List input; 34 | 35 | /** 36 | * A unique identifier representing your end-user, which will help OpenAI to monitor and detect abuse. 37 | */ 38 | String user; 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/image/CreateImageVariationRequest.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.image; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | /** 10 | * A request for OpenAi to create a variation of an image 11 | * All fields are optional 12 | * 13 | * https://beta.openai.com/docs/api-reference/images/create-variation 14 | */ 15 | @Builder 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | @Data 19 | public class CreateImageVariationRequest { 20 | 21 | /** 22 | * The number of images to generate. Must be between 1 and 10. Defaults to 1. 23 | */ 24 | Integer n; 25 | 26 | /** 27 | * The size of the generated images. Must be one of "256x256", "512x512", or "1024x1024". Defaults to "1024x1024". 28 | */ 29 | String size; 30 | 31 | /** 32 | * The format in which the generated images are returned. Must be one of url or b64_json. Defaults to url. 33 | */ 34 | @JsonProperty("response_format") 35 | String responseFormat; 36 | 37 | /** 38 | * A unique identifier representing your end-user, which will help OpenAI to monitor and detect abuse. 39 | */ 40 | String user; 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/moderation/Moderation.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.moderation; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.Data; 5 | 6 | /** 7 | * An object containing the moderation data for a single input string 8 | * 9 | * https://beta.openai.com/docs/api-reference/moderations/create 10 | */ 11 | @Data 12 | public class Moderation { 13 | /** 14 | * Set to true if the model classifies the content as violating OpenAI's content policy, false otherwise 15 | */ 16 | public boolean flagged; 17 | 18 | /** 19 | * Object containing per-category binary content policy violation flags. 20 | * For each category, the value is true if the model flags the corresponding category as violated, false otherwise. 21 | */ 22 | public ModerationCategories categories; 23 | 24 | /** 25 | * Object containing per-category raw scores output by the model, denoting the model's confidence that the 26 | * input violates the OpenAI's policy for the category. 27 | * The value is between 0 and 1, where higher values denote higher confidence. 28 | * The scores should not be interpreted as probabilities. 29 | */ 30 | @JsonProperty("category_scores") 31 | public ModerationCategoryScores categoryScores; 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/entity/knowledge/OccupationClassification.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.entity.knowledge; 2 | 3 | import lombok.EqualsAndHashCode; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | /** 8 | * 职业分类表实体 9 | */ 10 | @Getter 11 | @Setter 12 | @EqualsAndHashCode 13 | public class OccupationClassification { 14 | private String type1; 15 | private String type2; 16 | private String type3; 17 | private String code; 18 | private String docs; 19 | private String type; 20 | 21 | @Override 22 | public String toString() { 23 | StringBuilder stringBuilder = new StringBuilder(); 24 | if (type1 != null){ 25 | stringBuilder.append("大分类是'" + type1 + '\''); 26 | } 27 | if (type2 != null){ 28 | stringBuilder.append("小分类是'" + type2 + '\''); 29 | } 30 | if (type3 != null){ 31 | stringBuilder.append("小分类是'" + type3 + '\''); 32 | } 33 | if (code != null){ 34 | stringBuilder.append("代码是'" + code + '\''); 35 | } 36 | if (docs != null){ 37 | stringBuilder.append("细类是'" + docs + '\''); 38 | } 39 | if (type != null){ 40 | stringBuilder.append("类别是'" + type + '\''); 41 | } 42 | return stringBuilder.toString(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/image/CreateImageRequest.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.image; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.*; 5 | 6 | /** 7 | * A request for OpenAi to create an image based on a prompt 8 | * All fields except prompt are optional 9 | * 10 | * https://beta.openai.com/docs/api-reference/images/create 11 | */ 12 | @Builder 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | @Data 16 | public class CreateImageRequest { 17 | 18 | /** 19 | * A text description of the desired image(s). The maximum length in 1000 characters. 20 | */ 21 | @NonNull 22 | String prompt; 23 | 24 | /** 25 | * The number of images to generate. Must be between 1 and 10. Defaults to 1. 26 | */ 27 | Integer n; 28 | 29 | /** 30 | * The size of the generated images. Must be one of "256x256", "512x512", or "1024x1024". Defaults to "1024x1024". 31 | */ 32 | String size; 33 | 34 | /** 35 | * The format in which the generated images are returned. Must be one of url or b64_json. Defaults to url. 36 | */ 37 | @JsonProperty("response_format") 38 | String responseFormat; 39 | 40 | /** 41 | * A unique identifier representing your end-user, which will help OpenAI to monitor and detect abuse. 42 | */ 43 | String user; 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/image/CreateImageEditRequest.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.image; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.*; 5 | 6 | /** 7 | * A request for OpenAi to edit an image based on a prompt 8 | * All fields except prompt are optional 9 | * 10 | * https://beta.openai.com/docs/api-reference/images/create-edit 11 | */ 12 | @Builder 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | @Data 16 | public class CreateImageEditRequest { 17 | 18 | /** 19 | * A text description of the desired image(s). The maximum length in 1000 characters. 20 | */ 21 | @NonNull 22 | String prompt; 23 | 24 | /** 25 | * The number of images to generate. Must be between 1 and 10. Defaults to 1. 26 | */ 27 | Integer n; 28 | 29 | /** 30 | * The size of the generated images. Must be one of "256x256", "512x512", or "1024x1024". Defaults to "1024x1024". 31 | */ 32 | String size; 33 | 34 | /** 35 | * The format in which the generated images are returned. Must be one of url or b64_json. Defaults to url. 36 | */ 37 | @JsonProperty("response_format") 38 | String responseFormat; 39 | 40 | /** 41 | * A unique identifier representing your end-user, which will help OpenAI to monitor and detect abuse. 42 | */ 43 | String user; 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/completion/chat/ChatMessage.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.completion.chat; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | /** 8 | *

Each object has a role (either “system”, “user”, or “assistant”) and content (the content of the message). Conversations can be as short as 1 message or fill many pages.

9 | *

Typically, a conversation is formatted with a system message first, followed by alternating user and assistant messages.

10 | *

The system message helps set the behavior of the assistant. In the example above, the assistant was instructed with “You are a helpful assistant.”
11 | * The user messages help instruct the assistant. They can be generated by the end users of an application, or set by a developer as an instruction.
12 | * The assistant messages help store prior responses. They can also be written by a developer to help give examples of desired behavior. 13 | *

14 | * 15 | * see OpenAi documentation 16 | */ 17 | @Data 18 | @NoArgsConstructor 19 | @AllArgsConstructor 20 | public class ChatMessage { 21 | 22 | /** 23 | * Must be either 'system', 'user', or 'assistant'.
24 | * You may use {@link ChatMessageRole} enum. 25 | */ 26 | String role; 27 | String content; 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/config/RedisConfig.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.data.redis.connection.RedisConnectionFactory; 6 | import org.springframework.data.redis.core.RedisTemplate; 7 | import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; 8 | import org.springframework.data.redis.serializer.RedisSerializer; 9 | 10 | @Configuration 11 | public class RedisConfig { 12 | @Bean 13 | public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) throws Exception { 14 | // 创建模板 15 | RedisTemplate redisTemplate = new RedisTemplate<>(); 16 | // 设置连接工厂 17 | redisTemplate.setConnectionFactory(redisConnectionFactory); 18 | // 设置序列化工具 19 | GenericJackson2JsonRedisSerializer jsonRedisSerializer = 20 | new GenericJackson2JsonRedisSerializer(); 21 | // key和 hashKey采用 string序列化 22 | redisTemplate.setKeySerializer(RedisSerializer.string()); 23 | redisTemplate.setHashKeySerializer(RedisSerializer.string()); 24 | // value和 hashValue采用 JSON序列化 25 | redisTemplate.setValueSerializer(jsonRedisSerializer); 26 | redisTemplate.setHashValueSerializer(jsonRedisSerializer); 27 | return redisTemplate; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/model/Permission.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.Data; 5 | 6 | /** 7 | * GPT-3 model permissions 8 | * I couldn't find documentation for the specific permissions, and I've elected to leave them undocumented rather than 9 | * write something incorrect. 10 | * 11 | * https://beta.openai.com/docs/api-reference/models 12 | */ 13 | @Data 14 | public class Permission { 15 | /** 16 | * An identifier for this model permission 17 | */ 18 | public String id; 19 | 20 | /** 21 | * The type of object returned, should be "model_permission" 22 | */ 23 | public String object; 24 | 25 | /** 26 | * The creation time in epoch seconds. 27 | */ 28 | public long created; 29 | 30 | @JsonProperty("allow_create_engine") 31 | public boolean allowCreateEngine; 32 | 33 | @JsonProperty("allow_sampling") 34 | public boolean allowSampling; 35 | 36 | @JsonProperty("allow_log_probs") 37 | public boolean allowLogProbs; 38 | 39 | @JsonProperty("allow_search_indices") 40 | public boolean allowSearchIndices; 41 | 42 | @JsonProperty("allow_view") 43 | public boolean allowView; 44 | 45 | @JsonProperty("allow_fine_tuning") 46 | public boolean allowFineTuning; 47 | 48 | public String organization; 49 | 50 | public String group; 51 | 52 | @JsonProperty("is_blocking") 53 | public boolean isBlocking; 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/edit/EditRequest.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.edit; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.*; 5 | 6 | /** 7 | * Given a prompt and an instruction, OpenAi will return an edited version of the prompt 8 | * 9 | * https://beta.openai.com/docs/api-reference/edits/create 10 | */ 11 | @Builder 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | @Data 15 | public class EditRequest { 16 | 17 | /** 18 | * The name of the model to use. 19 | * Required if using the new v1/edits endpoint. 20 | */ 21 | String model; 22 | 23 | /** 24 | * The input text to use as a starting point for the edit. 25 | */ 26 | String input; 27 | 28 | /** 29 | * The instruction that tells the model how to edit the prompt. 30 | * For example, "Fix the spelling mistakes" 31 | */ 32 | @NonNull 33 | String instruction; 34 | 35 | /** 36 | * How many edits to generate for the input and instruction. 37 | */ 38 | Integer n; 39 | 40 | /** 41 | * What sampling temperature to use. Higher values means the model will take more risks. 42 | * Try 0.9 for more creative applications, and 0 (argmax sampling) for ones with a well-defined answer. 43 | * 44 | * We generally recommend altering this or {@link EditRequest#topP} but not both. 45 | */ 46 | Double temperature; 47 | 48 | /** 49 | * An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of 50 | * the tokens with top_p probability mass.So 0.1 means only the tokens comprising the top 10% probability mass are 51 | * considered. 52 | * 53 | * We generally recommend altering this or {@link EditRequest#temperature} but not both. 54 | */ 55 | @JsonProperty("top_p") 56 | Double topP; 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/OpenAiModule.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai; 2 | 3 | 4 | import com.tutu.knowledge_box.ai.openai.completion.CompletionRequest; 5 | import com.tutu.knowledge_box.ai.openai.embedding.Embedding; 6 | import com.tutu.knowledge_box.ai.openai.embedding.EmbeddingRequest; 7 | 8 | import java.util.Collections; 9 | import java.util.List; 10 | 11 | public class OpenAiModule { 12 | private static final String TOKEN = System.getenv("OPENAI_TOKEN"); 13 | private static final OpenAiService service = new OpenAiService(TOKEN); 14 | 15 | /** 16 | * 计算 17 | */ 18 | public static List getEmbedding(String message){ 19 | EmbeddingRequest completionRequest = EmbeddingRequest.builder() 20 | .model("text-embedding-ada-002") 21 | .input(Collections.singletonList("Somebody once told me the world is gonna roll me")) 22 | .build(); 23 | List embeddings = service.createEmbeddings(completionRequest).getData(); 24 | return embeddings.get(0).getEmbedding(); 25 | } 26 | 27 | /** 28 | * 询问 29 | */ 30 | public static String getCompletion(String message,String questionMessage){ 31 | StringBuilder question = new StringBuilder(); 32 | question.append("使用提供的上下文尽可能如实回答问题,如果答案未包含在以下文本中,就说我不知道\n\n"); 33 | question.append("内容为:\n"); 34 | question.append(message); 35 | question.append("\n\n 问题是:"); 36 | question.append(questionMessage); 37 | question.append(message); 38 | question.append("\n回答:"); 39 | CompletionRequest completionRequest = CompletionRequest.builder() 40 | .model("text-davinci-003") 41 | .prompt(question.toString()) 42 | .temperature(0.0) 43 | .maxTokens(100) 44 | .build(); 45 | String result = service.createCompletion(completionRequest).getChoices().get(0).getText(); 46 | return result; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/finetune/FineTuneResult.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.finetune; 2 | 3 | 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.tutu.knowledge_box.ai.openai.file.File; 6 | import lombok.Data; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * An object describing a fine-tuned model. Returned by multiple fine-tune requests. 12 | * 13 | * https://beta.openai.com/docs/api-reference/fine-tunes 14 | */ 15 | @Data 16 | public class FineTuneResult { 17 | /** 18 | * The ID of the fine-tuning job. 19 | */ 20 | String id; 21 | 22 | /** 23 | * The type of object returned, should be "fine-tune". 24 | */ 25 | String object; 26 | 27 | /** 28 | * The name of the base model. 29 | */ 30 | String model; 31 | 32 | /** 33 | * The creation time in epoch seconds. 34 | */ 35 | @JsonProperty("created_at") 36 | Long createdAt; 37 | 38 | /** 39 | * List of events in this job's lifecycle. Null when getting a list of fine-tune jobs. 40 | */ 41 | List events; 42 | 43 | /** 44 | * The ID of the fine-tuned model, null if tuning job is not finished. 45 | * This is the id used to call the model. 46 | */ 47 | @JsonProperty("fine_tuned_model") 48 | String fineTunedModel; 49 | 50 | /** 51 | * The specified hyper-parameters for the tuning job. 52 | */ 53 | HyperParameters hyperparams; 54 | 55 | /** 56 | * The ID of the organization this model belongs to. 57 | */ 58 | @JsonProperty("organization_id") 59 | String organizationId; 60 | 61 | /** 62 | * Result files for this fine-tune job. 63 | */ 64 | @JsonProperty("result_files") 65 | List resultFiles; 66 | 67 | /** 68 | * The status os the fine-tune job. "pending", "succeeded", or "cancelled" 69 | */ 70 | String status; 71 | 72 | /** 73 | * Training files for this fine-tune job. 74 | */ 75 | @JsonProperty("training_files") 76 | List trainingFiles; 77 | 78 | /** 79 | * The last update time in epoch seconds. 80 | */ 81 | @JsonProperty("updated_at") 82 | Long updatedAt; 83 | 84 | /** 85 | * Validation files for this fine-tune job. 86 | */ 87 | @JsonProperty("validation_files") 88 | List validationFiles; 89 | } 90 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.0.5 9 | 10 | 11 | com.tutu 12 | knowledge_box 13 | 0.0.1-SNAPSHOT 14 | knowledge_box 15 | knowledge_box 16 | 17 | 17 18 | 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-data-redis 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-web 28 | 29 | 30 | 31 | org.projectlombok 32 | lombok 33 | true 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-starter-test 38 | test 39 | 40 | 41 | 42 | 43 | com.belerweb 44 | pinyin4j 45 | 2.5.1 46 | 47 | 48 | 49 | cn.hutool 50 | hutool-all 51 | 5.8.12 52 | 53 | 54 | 55 | com.alibaba 56 | easyexcel 57 | 3.2.1 58 | 59 | 60 | 61 | 62 | 63 | 64 | com.squareup.retrofit2 65 | retrofit 66 | 2.9.0 67 | 68 | 69 | 70 | io.reactivex.rxjava2 71 | rxjava 72 | 2.0.0 73 | 74 | 75 | com.squareup.retrofit2 76 | adapter-rxjava2 77 | 2.9.0 78 | 79 | 80 | com.squareup.retrofit2 81 | converter-jackson 82 | 2.9.0 83 | 84 | 85 | 86 | 87 | 88 | 89 | org.springframework.boot 90 | spring-boot-maven-plugin 91 | 92 | 93 | 94 | org.projectlombok 95 | lombok 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/module/knowledge/AskQuestionUtil.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.module.knowledge; 2 | 3 | 4 | 5 | import com.tutu.knowledge_box.ai.OpenAiModule; 6 | 7 | import java.math.BigDecimal; 8 | import java.math.RoundingMode; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | import java.util.Objects; 12 | import java.util.stream.Collectors; 13 | 14 | /** 15 | * 询问问题 16 | */ 17 | public class AskQuestionUtil { 18 | /** 19 | * 通过机器人从知识库中询问问题 20 | * @return 21 | */ 22 | public static String askQuestionFromAI(String question) { 23 | // System.out.println("您询问的问题是:" + question); 24 | // List embedding = OpenAiModule.getEmbedding(question).stream().map(item -> BigDecimal.valueOf(item)).collect(Collectors.toList()); 25 | // // 现在默认查询职业分类的知识库 26 | // List zhiyefenleibiaoEmbedding = RedisQuery.lrange("ZHIYEFENLEIBIAO_EMBEDDING", 0, -1); 27 | // List> collect = zhiyefenleibiaoEmbedding.stream().map(JSONUtil::parseArray) 28 | // .map(item -> item.stream().map(temp -> new BigDecimal(temp.toString())).collect(Collectors.toList())) 29 | // .collect(Collectors.toList()); 30 | //// BigDecimal dotProduct = BigDecimal.ZERO; 31 | // List res = new ArrayList<>(); 32 | // for (int i = 0; i < collect.size(); i++) { 33 | // List doubles = collect.get(i); 34 | // BigDecimal dotProduct = BigDecimal.ZERO; 35 | // BigDecimal norm1 = BigDecimal.ZERO; 36 | // BigDecimal norm2 = BigDecimal.ZERO; 37 | // for (int j = 0; j < doubles.size(); j++) { 38 | // BigDecimal multiply = doubles.get(j).multiply(embedding.get(j)); 39 | // dotProduct = dotProduct.add(multiply); 40 | // norm1 = norm1.add(doubles.get(j).multiply(doubles.get(j))); 41 | // norm2 = norm2.add(embedding.get(j).multiply(embedding.get(j))); 42 | // } 43 | // BigDecimal similarity = dotProduct.divide(BigDecimal.valueOf((Math.sqrt(norm1.doubleValue()) * Math.sqrt(norm2.doubleValue()))),20,RoundingMode.HALF_UP); 44 | // res.add(new Item(i,similarity)); 45 | // } 46 | // res.forEach(System.out::println); 47 | // List list = res.stream().filter(Objects::nonNull).sorted((a,b) -> b.getDot().compareTo(a.getDot())).filter(item -> item.getDot() != null && item.getDot().compareTo(BigDecimal.valueOf(0.8)) > 0).collect(Collectors.toList()); 48 | // 49 | // System.out.println("-----------------"); 50 | // list.forEach(System.out::println); 51 | // List zhiyefenleibiao = RedisQuery.lrange("ZHIYEFENLEIBIAO", 0, -1); 52 | // List result = new ArrayList<>(); 53 | // 54 | // for (int i = 0 ; i < 5 ; i ++){ 55 | // result.add(zhiyefenleibiao.get(list.get(i).getIndex())); 56 | // } 57 | // result.forEach(System.out::println); 58 | // System.out.println("我正在思考,请骚等"); 59 | // String join = String.join("", zhiyefenleibiao.subList(0,20)); 60 | // System.out.println(join); 61 | // String completion = OpenAiModule.getCompletion(join, question); 62 | // System.out.println(completion); 63 | return ""; 64 | } 65 | 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/service/AIService.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.service; 2 | 3 | import cn.hutool.json.JSONUtil; 4 | import com.tutu.knowledge_box.ai.OpenAiModule; 5 | import com.tutu.knowledge_box.module.knowledge.Item; 6 | import jakarta.annotation.Resource; 7 | import org.springframework.data.redis.core.RedisTemplate; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.math.BigDecimal; 11 | import java.math.RoundingMode; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | import java.util.Objects; 15 | import java.util.stream.Collectors; 16 | 17 | @Service 18 | public class AIService { 19 | @Resource 20 | private RedisTemplate redisTemplate; 21 | /** 22 | * 向GPT询问问题 23 | */ 24 | public String askQuestionFromAI(String question) { 25 | System.out.println("您询问的问题是:" + question); 26 | List embedding = OpenAiModule.getEmbedding(question).stream().map(item -> BigDecimal.valueOf(item)).collect(Collectors.toList()); 27 | // 现在默认查询职业分类的知识库 28 | List zhiyefenleibiaoEmbedding = redisTemplate.opsForList().range("ZHIYEFENLEIBIAO_EMBEDDING",0,-1); 29 | List> collect = zhiyefenleibiaoEmbedding.stream().map(JSONUtil::parseArray) 30 | .map(item -> item.stream().map(temp -> new BigDecimal(temp.toString())).collect(Collectors.toList())) 31 | .collect(Collectors.toList()); 32 | // BigDecimal dotProduct = BigDecimal.ZERO; 33 | List res = new ArrayList<>(); 34 | for (int i = 0; i < collect.size(); i++) { 35 | List doubles = collect.get(i); 36 | BigDecimal dotProduct = BigDecimal.ZERO; 37 | BigDecimal norm1 = BigDecimal.ZERO; 38 | BigDecimal norm2 = BigDecimal.ZERO; 39 | for (int j = 0; j < doubles.size(); j++) { 40 | BigDecimal multiply = doubles.get(j).multiply(embedding.get(j)); 41 | dotProduct = dotProduct.add(multiply); 42 | norm1 = norm1.add(doubles.get(j).multiply(doubles.get(j))); 43 | norm2 = norm2.add(embedding.get(j).multiply(embedding.get(j))); 44 | } 45 | BigDecimal similarity = dotProduct.divide(BigDecimal.valueOf((Math.sqrt(norm1.doubleValue()) * Math.sqrt(norm2.doubleValue()))),20, RoundingMode.HALF_UP); 46 | res.add(new Item(i,similarity)); 47 | } 48 | res.forEach(System.out::println); 49 | List list = res.stream().filter(Objects::nonNull).sorted((a, b) -> b.getDot().compareTo(a.getDot())).filter(item -> item.getDot() != null && item.getDot().compareTo(BigDecimal.valueOf(0.8)) > 0).collect(Collectors.toList()); 50 | 51 | System.out.println("-----------------"); 52 | list.forEach(System.out::println); 53 | List zhiyefenleibiao = redisTemplate.opsForList().range("ZHIYEFENLEIBIAO", 0, -1); 54 | List result = new ArrayList<>(); 55 | 56 | for (int i = 0 ; i < 5 ; i ++){ 57 | result.add(zhiyefenleibiao.get(list.get(i).getIndex())); 58 | } 59 | result.forEach(System.out::println); 60 | System.out.println("我正在思考,请骚等"); 61 | String join = String.join("", zhiyefenleibiao.subList(0,20)); 62 | System.out.println(join); 63 | String completion = OpenAiModule.getCompletion(join, question); 64 | System.out.println(completion); 65 | return null; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/completion/chat/ChatCompletionRequest.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.completion.chat; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | @Data 13 | @Builder 14 | @AllArgsConstructor 15 | @NoArgsConstructor 16 | public class ChatCompletionRequest { 17 | 18 | /** 19 | * ID of the model to use. Currently, only gpt-3.5-turbo and gpt-3.5-turbo-0301 are supported. 20 | */ 21 | String model; 22 | 23 | /** 24 | * The messages to generate chat completions for, in the chat format.
26 | * see {@link ChatMessage} 27 | */ 28 | List messages; 29 | 30 | /** 31 | * What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower 32 | * values like 0.2 will make it more focused and deterministic.
33 | * We generally recommend altering this or top_p but not both. 34 | */ 35 | Double temperature; 36 | 37 | /** 38 | * An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens 39 | * with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered.
40 | * We generally recommend altering this or temperature but not both. 41 | */ 42 | @JsonProperty("top_p") 43 | Double topP; 44 | 45 | /** 46 | * How many chat completion chatCompletionChoices to generate for each input message. 47 | */ 48 | Integer n; 49 | 50 | /** 51 | * If set, partial message deltas will be sent, like in ChatGPT. Tokens will be sent as data-only server-sent 53 | * events as they become available, with the stream terminated by a data: [DONE] message. 54 | */ 55 | Boolean stream; 56 | 57 | /** 58 | * Up to 4 sequences where the API will stop generating further tokens. 59 | */ 60 | List stop; 61 | 62 | /** 63 | * The maximum number of tokens allowed for the generated answer. By default, the number of tokens the model can return will 64 | * be (4096 - prompt tokens). 65 | */ 66 | @JsonProperty("max_tokens") 67 | Integer maxTokens; 68 | 69 | /** 70 | * Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, 71 | * increasing the model's likelihood to talk about new topics. 72 | */ 73 | @JsonProperty("presence_penalty") 74 | Double presencePenalty; 75 | 76 | /** 77 | * Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, 78 | * decreasing the model's likelihood to repeat the same line verbatim. 79 | */ 80 | @JsonProperty("frequency_penalty") 81 | Double frequencyPenalty; 82 | 83 | /** 84 | * Accepts a json object that maps tokens (specified by their token ID in the tokenizer) to an associated bias value from -100 85 | * to 100. Mathematically, the bias is added to the logits generated by the model prior to sampling. The exact effect will 86 | * vary per model, but values between -1 and 1 should decrease or increase likelihood of selection; values like -100 or 100 87 | * should result in a ban or exclusive selection of the relevant token. 88 | */ 89 | @JsonProperty("logit_bias") 90 | Map logitBias; 91 | 92 | 93 | /** 94 | * A unique identifier representing your end-user, which will help OpenAI to monitor and detect abuse. 95 | */ 96 | String user; 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/module/knowledge/LoadKnowledgeUtil.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.module.knowledge; 2 | 3 | import cn.hutool.extra.pinyin.PinyinUtil; 4 | import com.alibaba.excel.EasyExcel; 5 | import com.alibaba.excel.context.AnalysisContext; 6 | import com.alibaba.excel.metadata.CellExtra; 7 | import com.alibaba.excel.metadata.data.ReadCellData; 8 | import com.alibaba.excel.read.listener.ReadListener; 9 | import com.tutu.knowledge_box.ai.OpenAiModule; 10 | import com.tutu.knowledge_box.enums.KnowledgeEntityEnum; 11 | import lombok.Data; 12 | 13 | import java.io.File; 14 | import java.util.ArrayList; 15 | import java.util.Arrays; 16 | import java.util.List; 17 | import java.util.Map; 18 | import java.util.stream.Collectors; 19 | 20 | /** 21 | * 加载知识库 22 | */ 23 | public class LoadKnowledgeUtil { 24 | private static final String KNOWLEDGE_PATH = "./chatGPT/src/main/resources/knowledge"; 25 | private static final String ENTITY_PATH = "com.example.knowledgeEntity."; 26 | // EMBEDDING 后缀 27 | private static final String EMBEDDING_SUFFIX = "_EMBEDDING"; 28 | /** 29 | * 知识库名 30 | */ 31 | private static String knowledgeName = null; 32 | /** 33 | * 加载 Excel 文件 34 | * 解析 Excel 的框架: 35 | * 1,POI 36 | * 2,jxl 37 | */ 38 | public static void loadExcel(String path){ 39 | if (path == null || path.isBlank()){ 40 | path = KNOWLEDGE_PATH; 41 | } 42 | try { 43 | File directory = new File(path); 44 | if (directory.isDirectory()){ 45 | // 遍历 知识库 46 | for (File file : directory.listFiles()) { 47 | // 拿到文件名 48 | String fileName = file.getName(); 49 | System.out.println(fileName); 50 | String fileNamePinYin = PinyinUtil.getPinyin(fileName.split("\\.")[0]).trim().replaceAll(" ","").toUpperCase(); 51 | knowledgeName = fileNamePinYin; 52 | // 拿到文件名对应的实体对象 53 | KnowledgeEntityEnum knowledgeEntityEnum = Arrays.stream(KnowledgeEntityEnum.values()).filter(knowledge -> knowledge.getValue().equals(fileName)).findFirst().get(); 54 | Class aClass = Class.forName(ENTITY_PATH+knowledgeEntityEnum.name()); 55 | EasyExcel.read(file.getPath(),aClass,new DemoDataListener()).sheet().doRead(); 56 | } 57 | System.out.println("知识库遍历完成"); 58 | } 59 | }catch (Exception e){ 60 | e.printStackTrace(); 61 | } 62 | 63 | } 64 | 65 | 66 | 67 | static class DemoDataListener implements ReadListener { 68 | 69 | 70 | List knowledgeInfo = new ArrayList<>(); 71 | 72 | @Override 73 | public void onException(Exception exception, AnalysisContext context) throws Exception { 74 | System.out.println(exception.getMessage()); 75 | ReadListener.super.onException(exception, context); 76 | } 77 | 78 | @Override 79 | public void invokeHead(Map> headMap, AnalysisContext context) { 80 | 81 | } 82 | 83 | /** 84 | * 这个每一条数据解析都会来调用 85 | */ 86 | @Override 87 | public void invoke(Object data, AnalysisContext analysisContext) { 88 | // 限制只添加 10条,省 token 数量 89 | if (knowledgeInfo.size() < 10){ 90 | knowledgeInfo.add(data.toString()); 91 | // RedisQuery.lpush(knowledgeName,data.toString()); 92 | } 93 | // System.out.println(knowledgeInfo.toString()); 94 | } 95 | 96 | @Override 97 | public void extra(CellExtra extra, AnalysisContext context) { 98 | 99 | } 100 | 101 | /** 102 | * 所有数据解析完成 103 | */ 104 | @Override 105 | public void doAfterAllAnalysed(AnalysisContext analysisContext) { 106 | // RedisQuery.set(knowledgeName,knowledgeInfo); 107 | String knowledgeName_embedding = knowledgeName+EMBEDDING_SUFFIX; 108 | for (int i = 0; i < knowledgeInfo.size(); i++) { 109 | List embedding = OpenAiModule.getEmbedding(knowledgeInfo.get(i)).stream().map(item -> String.valueOf(item)).collect(Collectors.toList()); 110 | // RedisQuery.lpush(knowledgeName_embedding,embedding.toString()); 111 | } 112 | } 113 | 114 | @Override 115 | public boolean hasNext(AnalysisContext context) { 116 | return ReadListener.super.hasNext(context); 117 | } 118 | } 119 | 120 | /** 121 | * 知识库 Item 122 | */ 123 | @Data 124 | static class KnowledgeItem{ 125 | private int index; 126 | private String message; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/completion/CompletionRequest.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.completion; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | /** 13 | * A request for OpenAi to generate a predicted completion for a prompt. 14 | * All fields are nullable. 15 | * 16 | * https://beta.openai.com/docs/api-reference/completions/create 17 | */ 18 | @Builder 19 | @NoArgsConstructor 20 | @AllArgsConstructor 21 | @Data 22 | public class CompletionRequest { 23 | 24 | /** 25 | *要使用的模型的名称。 26 | *如果指定微调模型或使用新的v1/completions,则为必需。 27 | */ 28 | String model; 29 | 30 | /** 31 | * 一个可选的提示来完成 32 | */ 33 | String prompt; 34 | 35 | /** 36 | * The suffix that comes after a completion of inserted text. 37 | */ 38 | String suffix; 39 | 40 | /** 41 | *要生成的最大令牌数。 42 | *请求最多可以使用2048个在提示和完成之间共享的令牌。 43 | *(对于普通英语文本,一个标记大约为4个字符) 44 | */ 45 | @JsonProperty("max_tokens") 46 | Integer maxTokens; 47 | 48 | /** 49 | * What sampling temperature to use. Higher values means the model will take more risks. 50 | * Try 0.9 for more creative applications, and 0 (argmax sampling) for ones with a well-defined answer. 51 | * 52 | * We generally recommend using this or {@link CompletionRequest#topP} but not both. 53 | */ 54 | Double temperature; 55 | 56 | /** 57 | * An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of 58 | * the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are 59 | * considered. 60 | * 61 | * We generally recommend using this or {@link CompletionRequest#temperature} but not both. 62 | */ 63 | @JsonProperty("top_p") 64 | Double topP; 65 | 66 | /** 67 | * 为每个提示生成多少完成。 68 | * 69 | * 因为这个参数会产生很多完成,它会很快消耗你的令牌配额。 70 | * 小心使用并确保您对 {@link CompletionRequest#maxTokens} 和 {@link CompletionRequest#stop} 进行了合理的设置。 71 | */ 72 | Integer n; 73 | 74 | /** 75 | * Whether to stream back partial progress. 76 | * If set, tokens will be sent as data-only server-sent events as they become available, 77 | * with the stream terminated by a data: DONE message. 78 | */ 79 | Boolean stream; 80 | 81 | /** 82 | * Include the log probabilities on the logprobs most likely tokens, as well the chosen tokens. 83 | * For example, if logprobs is 10, the API will return a list of the 10 most likely tokens. 84 | * The API will always return the logprob of the sampled token, 85 | * so there may be up to logprobs+1 elements in the response. 86 | */ 87 | Integer logprobs; 88 | 89 | /** 90 | * 除了完成之外回显提示 91 | */ 92 | Boolean echo; 93 | 94 | /** 95 | * Up to 4 sequences where the API will stop generating further tokens. 96 | * The returned text will not contain the stop sequence. 97 | */ 98 | List stop; 99 | 100 | /** 101 | * Number between 0 and 1 (default 0) that penalizes new tokens based on whether they appear in the text so far. 102 | * Increases the model's likelihood to talk about new topics. 103 | */ 104 | @JsonProperty("presence_penalty") 105 | Double presencePenalty; 106 | 107 | /** 108 | * Number between 0 and 1 (default 0) that penalizes new tokens based on their existing frequency in the text so far. 109 | * Decreases the model's likelihood to repeat the same line verbatim. 110 | */ 111 | @JsonProperty("frequency_penalty") 112 | Double frequencyPenalty; 113 | 114 | /** 115 | * Generates best_of completions server-side and returns the "best" 116 | * (the one with the lowest log probability per token). 117 | * Results cannot be streamed. 118 | * 119 | * When used with {@link CompletionRequest#n}, best_of controls the number of candidate completions and n specifies how many to return, 120 | * best_of must be greater than n. 121 | */ 122 | @JsonProperty("best_of") 123 | Integer bestOf; 124 | 125 | /** 126 | * Modify the likelihood of specified tokens appearing in the completion. 127 | * 128 | * Maps tokens (specified by their token ID in the GPT tokenizer) to an associated bias value from -100 to 100. 129 | * 130 | * https://beta.openai.com/docs/api-reference/completions/create#completions/create-logit_bias 131 | */ 132 | @JsonProperty("logit_bias") 133 | Map logitBias; 134 | 135 | /** 136 | * 代表您的最终用户的唯一标识符,这将有助于 OpenAI 监控和检测滥用行为。 137 | */ 138 | String user; 139 | } 140 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/OpenAiApi.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai; 2 | 3 | 4 | import com.tutu.knowledge_box.ai.openai.DeleteResult; 5 | import com.tutu.knowledge_box.ai.openai.OpenAiResponse; 6 | import com.tutu.knowledge_box.ai.openai.completion.CompletionRequest; 7 | import com.tutu.knowledge_box.ai.openai.completion.CompletionResult; 8 | import com.tutu.knowledge_box.ai.openai.completion.chat.ChatCompletionRequest; 9 | import com.tutu.knowledge_box.ai.openai.completion.chat.ChatCompletionResult; 10 | import com.tutu.knowledge_box.ai.openai.edit.EditRequest; 11 | import com.tutu.knowledge_box.ai.openai.edit.EditResult; 12 | import com.tutu.knowledge_box.ai.openai.embedding.EmbeddingRequest; 13 | import com.tutu.knowledge_box.ai.openai.embedding.EmbeddingResult; 14 | import com.tutu.knowledge_box.ai.openai.engine.Engine; 15 | import com.tutu.knowledge_box.ai.openai.file.File; 16 | import com.tutu.knowledge_box.ai.openai.finetune.FineTuneEvent; 17 | import com.tutu.knowledge_box.ai.openai.finetune.FineTuneRequest; 18 | import com.tutu.knowledge_box.ai.openai.finetune.FineTuneResult; 19 | import com.tutu.knowledge_box.ai.openai.image.CreateImageRequest; 20 | import com.tutu.knowledge_box.ai.openai.image.ImageResult; 21 | import com.tutu.knowledge_box.ai.openai.model.Model; 22 | import com.tutu.knowledge_box.ai.openai.moderation.ModerationRequest; 23 | import com.tutu.knowledge_box.ai.openai.moderation.ModerationResult; 24 | import io.reactivex.Single; 25 | import okhttp3.MultipartBody; 26 | import okhttp3.RequestBody; 27 | import retrofit2.http.*; 28 | 29 | public interface OpenAiApi { 30 | 31 | @GET("v1/models") 32 | Single> listModels(); 33 | 34 | @GET("/v1/models/{model_id}") 35 | Single getModel(@Path("model_id") String modelId); 36 | 37 | @POST("/v1/completions") 38 | Single createCompletion(@Body CompletionRequest request); 39 | 40 | @POST("/v1/chat/completions") 41 | Single createChatCompletion(@Body ChatCompletionRequest request); 42 | 43 | @Deprecated 44 | @POST("/v1/engines/{engine_id}/completions") 45 | Single createCompletion(@Path("engine_id") String engineId, @Body CompletionRequest request); 46 | 47 | @POST("/v1/edits") 48 | Single createEdit(@Body EditRequest request); 49 | 50 | @Deprecated 51 | @POST("/v1/engines/{engine_id}/edits") 52 | Single createEdit(@Path("engine_id") String engineId, @Body EditRequest request); 53 | 54 | @POST("/v1/embeddings") 55 | Single createEmbeddings(@Body EmbeddingRequest request); 56 | 57 | @Deprecated 58 | @POST("/v1/engines/{engine_id}/embeddings") 59 | Single createEmbeddings(@Path("engine_id") String engineId, @Body EmbeddingRequest request); 60 | 61 | @GET("/v1/files") 62 | Single> listFiles(); 63 | 64 | @Multipart 65 | @POST("/v1/files") 66 | Single uploadFile(@Part("purpose") RequestBody purpose, @Part MultipartBody.Part file); 67 | 68 | @DELETE("/v1/files/{file_id}") 69 | Single deleteFile(@Path("file_id") String fileId); 70 | 71 | @GET("/v1/files/{file_id}") 72 | Single retrieveFile(@Path("file_id") String fileId); 73 | 74 | @POST("/v1/fine-tunes") 75 | Single createFineTune(@Body FineTuneRequest request); 76 | 77 | @POST("/v1/completions") 78 | Single createFineTuneCompletion(@Body CompletionRequest request); 79 | 80 | @GET("/v1/fine-tunes") 81 | Single> listFineTunes(); 82 | 83 | @GET("/v1/fine-tunes/{fine_tune_id}") 84 | Single retrieveFineTune(@Path("fine_tune_id") String fineTuneId); 85 | 86 | @POST("/v1/fine-tunes/{fine_tune_id}/cancel") 87 | Single cancelFineTune(@Path("fine_tune_id") String fineTuneId); 88 | 89 | @GET("/v1/fine-tunes/{fine_tune_id}/events") 90 | Single> listFineTuneEvents(@Path("fine_tune_id") String fineTuneId); 91 | 92 | @DELETE("/v1/models/{fine_tune_id}") 93 | Single deleteFineTune(@Path("fine_tune_id") String fineTuneId); 94 | 95 | @POST("/v1/images/generations") 96 | Single createImage(@Body CreateImageRequest request); 97 | 98 | @POST("/v1/images/edits") 99 | Single createImageEdit(@Body RequestBody requestBody); 100 | 101 | @POST("/v1/images/variations") 102 | Single createImageVariation(@Body RequestBody requestBody); 103 | 104 | @POST("/v1/moderations") 105 | Single createModeration(@Body ModerationRequest request); 106 | 107 | @Deprecated 108 | @GET("v1/engines") 109 | Single> getEngines(); 110 | 111 | @Deprecated 112 | @GET("/v1/engines/{engine_id}") 113 | Single getEngine(@Path("engine_id") String engineId); 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/openai/finetune/FineTuneRequest.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai.openai.finetune; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.*; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * A request for OpenAi to create a fine-tuned model 10 | * All fields except trainingFile are nullable. 11 | * 12 | * https://beta.openai.com/docs/api-reference/fine-tunes/create 13 | */ 14 | @Builder 15 | @NoArgsConstructor 16 | @AllArgsConstructor 17 | @Data 18 | public class FineTuneRequest { 19 | 20 | /** 21 | * The ID of an uploaded file that contains training data. 22 | */ 23 | @NonNull 24 | @JsonProperty("training_file") 25 | String trainingFile; 26 | 27 | /** 28 | * The ID of an uploaded file that contains validation data. 29 | */ 30 | @JsonProperty("validation_file") 31 | String validationFile; 32 | 33 | /** 34 | * The name of the base model to fine-tune. You can select one of "ada", "babbage", "curie", or "davinci". 35 | * To learn more about these models, see the Engines documentation. 36 | */ 37 | String model; 38 | 39 | /** 40 | * The number of epochs to train the model for. An epoch refers to one full cycle through the training dataset. 41 | */ 42 | @JsonProperty("n_epochs") 43 | Integer nEpochs; 44 | 45 | /** 46 | * The batch size to use for training. 47 | * The batch size is the number of training examples used to train a single forward and backward pass. 48 | * 49 | * By default, the batch size will be dynamically configured to be ~0.2% of the number of examples in the training 50 | * set, capped at 256 - in general, we've found that larger batch sizes tend to work better for larger datasets. 51 | */ 52 | @JsonProperty("batch_size") 53 | Integer batchSize; 54 | 55 | /** 56 | * The learning rate multiplier to use for training. 57 | * The fine-tuning learning rate is the original learning rate used for pretraining multiplied by this value. 58 | * 59 | * By default, the learning rate multiplier is the 0.05, 0.1, or 0.2 depending on final batch_size 60 | * (larger learning rates tend to perform better with larger batch sizes). 61 | * We recommend experimenting with values in the range 0.02 to 0.2 to see what produces the best results. 62 | */ 63 | @JsonProperty("learning_rate_multiplier") 64 | Double learningRateMultiplier; 65 | 66 | /** 67 | * The weight to use for loss on the prompt tokens. 68 | * This controls how much the model tries to learn to generate the prompt 69 | * (as compared to the completion which always has a weight of 1.0), 70 | * and can add a stabilizing effect to training when completions are short. 71 | * 72 | * If prompts are extremely long (relative to completions), it may make sense to reduce this weight so as to 73 | * avoid over-prioritizing learning the prompt. 74 | */ 75 | @JsonProperty("prompt_loss_weight") 76 | Double promptLossWeight; 77 | 78 | /** 79 | * If set, we calculate classification-specific metrics such as accuracy and F-1 score using the validation set 80 | * at the end of every epoch. These metrics can be viewed in the results file. 81 | * 82 | * In order to compute classification metrics, you must provide a validation_file. 83 | * Additionally, you must specify {@link FineTuneRequest#classificationNClasses} for multiclass 84 | * classification or {@link FineTuneRequest#classificationPositiveClass} for binary classification. 85 | */ 86 | @JsonProperty("compute_classification_metrics") 87 | Boolean computeClassificationMetrics; 88 | 89 | /** 90 | * The number of classes in a classification task. 91 | * 92 | * This parameter is required for multiclass classification. 93 | */ 94 | @JsonProperty("classification_n_classes") 95 | Integer classificationNClasses; 96 | 97 | /** 98 | * The positive class in binary classification. 99 | * 100 | * This parameter is needed to generate precision, recall, and F1 metrics when doing binary classification. 101 | */ 102 | @JsonProperty("classification_positive_class") 103 | String classificationPositiveClass; 104 | 105 | /** 106 | * If this is provided, we calculate F-beta scores at the specified beta values. 107 | * The F-beta score is a generalization of F-1 score. This is only used for binary classification. 108 | * 109 | * With a beta of 1 (i.e. the F-1 score), precision and recall are given the same weight. 110 | * A larger beta score puts more weight on recall and less on precision. 111 | * A smaller beta score puts more weight on precision and less on recall. 112 | */ 113 | @JsonProperty("classification_betas") 114 | List classificationBetas; 115 | 116 | /** 117 | * A string of up to 40 characters that will be added to your fine-tuned model name. 118 | */ 119 | String suffix; 120 | } 121 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* 50 | if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 124 | 125 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% ^ 162 | %JVM_CONFIG_MAVEN_PROPS% ^ 163 | %MAVEN_OPTS% ^ 164 | %MAVEN_DEBUG_OPTS% ^ 165 | -classpath %WRAPPER_JAR% ^ 166 | "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ 167 | %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 168 | if ERRORLEVEL 1 goto error 169 | goto end 170 | 171 | :error 172 | set ERROR_CODE=1 173 | 174 | :end 175 | @endlocal & set ERROR_CODE=%ERROR_CODE% 176 | 177 | if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost 178 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 179 | if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" 180 | if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" 181 | :skipRcPost 182 | 183 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 184 | if "%MAVEN_BATCH_PAUSE%"=="on" pause 185 | 186 | if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% 187 | 188 | cmd /C exit /B %ERROR_CODE% 189 | -------------------------------------------------------------------------------- /src/main/java/com/tutu/knowledge_box/ai/OpenAiService.java: -------------------------------------------------------------------------------- 1 | package com.tutu.knowledge_box.ai; 2 | 3 | 4 | import com.fasterxml.jackson.annotation.JsonInclude; 5 | import com.fasterxml.jackson.databind.DeserializationFeature; 6 | import com.fasterxml.jackson.databind.ObjectMapper; 7 | import com.fasterxml.jackson.databind.PropertyNamingStrategy; 8 | import com.tutu.knowledge_box.ai.openai.DeleteResult; 9 | import com.tutu.knowledge_box.ai.openai.OpenAiError; 10 | import com.tutu.knowledge_box.ai.openai.OpenAiHttpException; 11 | import com.tutu.knowledge_box.ai.openai.completion.CompletionRequest; 12 | import com.tutu.knowledge_box.ai.openai.completion.CompletionResult; 13 | import com.tutu.knowledge_box.ai.openai.completion.chat.ChatCompletionRequest; 14 | import com.tutu.knowledge_box.ai.openai.completion.chat.ChatCompletionResult; 15 | import com.tutu.knowledge_box.ai.openai.edit.EditRequest; 16 | import com.tutu.knowledge_box.ai.openai.edit.EditResult; 17 | import com.tutu.knowledge_box.ai.openai.embedding.EmbeddingRequest; 18 | import com.tutu.knowledge_box.ai.openai.embedding.EmbeddingResult; 19 | import com.tutu.knowledge_box.ai.openai.file.File; 20 | import com.tutu.knowledge_box.ai.openai.finetune.FineTuneEvent; 21 | import com.tutu.knowledge_box.ai.openai.finetune.FineTuneRequest; 22 | import com.tutu.knowledge_box.ai.openai.finetune.FineTuneResult; 23 | import com.tutu.knowledge_box.ai.openai.image.CreateImageEditRequest; 24 | import com.tutu.knowledge_box.ai.openai.image.CreateImageRequest; 25 | import com.tutu.knowledge_box.ai.openai.image.CreateImageVariationRequest; 26 | import com.tutu.knowledge_box.ai.openai.image.ImageResult; 27 | import com.tutu.knowledge_box.ai.openai.model.Model; 28 | import com.tutu.knowledge_box.ai.openai.moderation.ModerationRequest; 29 | import com.tutu.knowledge_box.ai.openai.moderation.ModerationResult; 30 | import io.reactivex.Single; 31 | import okhttp3.*; 32 | import retrofit2.HttpException; 33 | import retrofit2.Retrofit; 34 | import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; 35 | import retrofit2.converter.jackson.JacksonConverterFactory; 36 | 37 | import java.io.IOException; 38 | import java.time.Duration; 39 | import java.util.List; 40 | import java.util.Objects; 41 | import java.util.concurrent.TimeUnit; 42 | 43 | public class OpenAiService { 44 | 45 | private static final String BASE_URL = "https://api.openai.com/"; 46 | private static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(10); 47 | private static final ObjectMapper errorMapper = defaultObjectMapper(); 48 | 49 | private final OpenAiApi api; 50 | 51 | /** 52 | * Creates a new OpenAiService that wraps OpenAiApi 53 | * 54 | * @param token OpenAi token string "sk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" 55 | */ 56 | public OpenAiService(final String token) { 57 | this(token, DEFAULT_TIMEOUT); 58 | } 59 | 60 | /** 61 | * Creates a new OpenAiService that wraps OpenAiApi 62 | * 63 | * @param token OpenAi token string "sk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" 64 | * @param timeout http read timeout, Duration.ZERO means no timeout 65 | */ 66 | public OpenAiService(final String token, final Duration timeout) { 67 | this(buildApi(token, timeout)); 68 | } 69 | 70 | /** 71 | * Creates a new OpenAiService that wraps OpenAiApi. 72 | * Use this if you need more customization. 73 | * 74 | * @param api OpenAiApi instance to use for all methods 75 | */ 76 | public OpenAiService(final OpenAiApi api) { 77 | this.api = api; 78 | } 79 | 80 | public List listModels() { 81 | return execute(api.listModels()).data; 82 | } 83 | 84 | public Model getModel(String modelId) { 85 | return execute(api.getModel(modelId)); 86 | } 87 | 88 | public CompletionResult createCompletion(CompletionRequest request) { 89 | return execute(api.createCompletion(request)); 90 | } 91 | 92 | public ChatCompletionResult createChatCompletion(ChatCompletionRequest request) { 93 | return execute(api.createChatCompletion(request)); 94 | } 95 | 96 | public EditResult createEdit(EditRequest request) { 97 | return execute(api.createEdit(request)); 98 | } 99 | 100 | public EmbeddingResult createEmbeddings(EmbeddingRequest request) { 101 | return execute(api.createEmbeddings(request)); 102 | } 103 | 104 | public List listFiles() { 105 | return execute(api.listFiles()).data; 106 | } 107 | 108 | public File uploadFile(String purpose, String filepath) { 109 | java.io.File file = new java.io.File(filepath); 110 | RequestBody purposeBody = RequestBody.create(MultipartBody.FORM, purpose); 111 | RequestBody fileBody = RequestBody.create(MediaType.parse("text"), file); 112 | MultipartBody.Part body = MultipartBody.Part.createFormData("file", filepath, fileBody); 113 | 114 | return execute(api.uploadFile(purposeBody, body)); 115 | } 116 | 117 | public DeleteResult deleteFile(String fileId) { 118 | return execute(api.deleteFile(fileId)); 119 | } 120 | 121 | public File retrieveFile(String fileId) { 122 | return execute(api.retrieveFile(fileId)); 123 | } 124 | 125 | public FineTuneResult createFineTune(FineTuneRequest request) { 126 | return execute(api.createFineTune(request)); 127 | } 128 | 129 | public CompletionResult createFineTuneCompletion(CompletionRequest request) { 130 | return execute(api.createFineTuneCompletion(request)); 131 | } 132 | 133 | public List listFineTunes() { 134 | return execute(api.listFineTunes()).data; 135 | } 136 | 137 | public FineTuneResult retrieveFineTune(String fineTuneId) { 138 | return execute(api.retrieveFineTune(fineTuneId)); 139 | } 140 | 141 | public FineTuneResult cancelFineTune(String fineTuneId) { 142 | return execute(api.cancelFineTune(fineTuneId)); 143 | } 144 | 145 | public List listFineTuneEvents(String fineTuneId) { 146 | return execute(api.listFineTuneEvents(fineTuneId)).data; 147 | } 148 | 149 | public DeleteResult deleteFineTune(String fineTuneId) { 150 | return execute(api.deleteFineTune(fineTuneId)); 151 | } 152 | 153 | public ImageResult createImage(CreateImageRequest request) { 154 | return execute(api.createImage(request)); 155 | } 156 | 157 | public ImageResult createImageEdit(CreateImageEditRequest request, String imagePath, String maskPath) { 158 | java.io.File image = new java.io.File(imagePath); 159 | java.io.File mask = null; 160 | if (maskPath != null) { 161 | mask = new java.io.File(maskPath); 162 | } 163 | return createImageEdit(request, image, mask); 164 | } 165 | 166 | public ImageResult createImageEdit(CreateImageEditRequest request, java.io.File image, java.io.File mask) { 167 | RequestBody imageBody = RequestBody.create(MediaType.parse("image"), image); 168 | 169 | MultipartBody.Builder builder = new MultipartBody.Builder() 170 | .setType(MediaType.get("multipart/form-data")) 171 | .addFormDataPart("prompt", request.getPrompt()) 172 | .addFormDataPart("size", request.getSize()) 173 | .addFormDataPart("response_format", request.getResponseFormat()) 174 | .addFormDataPart("image", "image", imageBody); 175 | 176 | if (request.getN() != null) { 177 | builder.addFormDataPart("n", request.getN().toString()); 178 | } 179 | 180 | if (mask != null) { 181 | RequestBody maskBody = RequestBody.create(MediaType.parse("image"), mask); 182 | builder.addFormDataPart("mask", "mask", maskBody); 183 | } 184 | 185 | return execute(api.createImageEdit(builder.build())); 186 | } 187 | 188 | public ImageResult createImageVariation(CreateImageVariationRequest request, String imagePath) { 189 | java.io.File image = new java.io.File(imagePath); 190 | return createImageVariation(request, image); 191 | } 192 | 193 | public ImageResult createImageVariation(CreateImageVariationRequest request, java.io.File image) { 194 | RequestBody imageBody = RequestBody.create(MediaType.parse("image"), image); 195 | 196 | MultipartBody.Builder builder = new MultipartBody.Builder() 197 | .setType(MediaType.get("multipart/form-data")) 198 | .addFormDataPart("size", request.getSize()) 199 | .addFormDataPart("response_format", request.getResponseFormat()) 200 | .addFormDataPart("image", "image", imageBody); 201 | 202 | if (request.getN() != null) { 203 | builder.addFormDataPart("n", request.getN().toString()); 204 | } 205 | 206 | return execute(api.createImageVariation(builder.build())); 207 | } 208 | 209 | public ModerationResult createModeration(ModerationRequest request) { 210 | return execute(api.createModeration(request)); 211 | } 212 | 213 | /** 214 | * Calls the Open AI api, returns the response, and parses error messages if the request fails 215 | */ 216 | public static T execute(Single apiCall) { 217 | try { 218 | return apiCall.blockingGet(); 219 | } catch (HttpException e) { 220 | try { 221 | if (e.response() == null || e.response().errorBody() == null) { 222 | throw e; 223 | } 224 | String errorBody = e.response().errorBody().string(); 225 | 226 | OpenAiError error = errorMapper.readValue(errorBody, OpenAiError.class); 227 | throw new OpenAiHttpException(error, e, e.code()); 228 | } catch (IOException ex) { 229 | // couldn't parse OpenAI error 230 | throw e; 231 | } 232 | } 233 | } 234 | 235 | public static OpenAiApi buildApi(String token, Duration timeout) { 236 | Objects.requireNonNull(token, "OpenAI token required"); 237 | ObjectMapper mapper = defaultObjectMapper(); 238 | OkHttpClient client = defaultClient(token, timeout); 239 | Retrofit retrofit = defaultRetrofit(client, mapper); 240 | 241 | return retrofit.create(OpenAiApi.class); 242 | } 243 | 244 | public static ObjectMapper defaultObjectMapper() { 245 | ObjectMapper mapper = new ObjectMapper(); 246 | mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 247 | mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); 248 | mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); 249 | return mapper; 250 | } 251 | 252 | public static OkHttpClient defaultClient(String token, Duration timeout) { 253 | return new OkHttpClient.Builder() 254 | .addInterceptor(new AuthenticationInterceptor(token)) 255 | .connectionPool(new ConnectionPool(5, 1, TimeUnit.SECONDS)) 256 | .readTimeout(timeout.toMillis(), TimeUnit.MILLISECONDS) 257 | .build(); 258 | } 259 | 260 | public static Retrofit defaultRetrofit(OkHttpClient client, ObjectMapper mapper) { 261 | return new Retrofit.Builder() 262 | .baseUrl(BASE_URL) 263 | .client(client) 264 | .addConverterFactory(JacksonConverterFactory.create(mapper)) 265 | .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) 266 | .build(); 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # https://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /usr/local/etc/mavenrc ] ; then 40 | . /usr/local/etc/mavenrc 41 | fi 42 | 43 | if [ -f /etc/mavenrc ] ; then 44 | . /etc/mavenrc 45 | fi 46 | 47 | if [ -f "$HOME/.mavenrc" ] ; then 48 | . "$HOME/.mavenrc" 49 | fi 50 | 51 | fi 52 | 53 | # OS specific support. $var _must_ be set to either true or false. 54 | cygwin=false; 55 | darwin=false; 56 | mingw=false 57 | case "`uname`" in 58 | CYGWIN*) cygwin=true ;; 59 | MINGW*) mingw=true;; 60 | Darwin*) darwin=true 61 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 62 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 63 | if [ -z "$JAVA_HOME" ]; then 64 | if [ -x "/usr/libexec/java_home" ]; then 65 | export JAVA_HOME="`/usr/libexec/java_home`" 66 | else 67 | export JAVA_HOME="/Library/Java/Home" 68 | fi 69 | fi 70 | ;; 71 | esac 72 | 73 | if [ -z "$JAVA_HOME" ] ; then 74 | if [ -r /etc/gentoo-release ] ; then 75 | JAVA_HOME=`java-config --jre-home` 76 | fi 77 | fi 78 | 79 | if [ -z "$M2_HOME" ] ; then 80 | ## resolve links - $0 may be a link to maven's home 81 | PRG="$0" 82 | 83 | # need this for relative symlinks 84 | while [ -h "$PRG" ] ; do 85 | ls=`ls -ld "$PRG"` 86 | link=`expr "$ls" : '.*-> \(.*\)$'` 87 | if expr "$link" : '/.*' > /dev/null; then 88 | PRG="$link" 89 | else 90 | PRG="`dirname "$PRG"`/$link" 91 | fi 92 | done 93 | 94 | saveddir=`pwd` 95 | 96 | M2_HOME=`dirname "$PRG"`/.. 97 | 98 | # make it fully qualified 99 | M2_HOME=`cd "$M2_HOME" && pwd` 100 | 101 | cd "$saveddir" 102 | # echo Using m2 at $M2_HOME 103 | fi 104 | 105 | # For Cygwin, ensure paths are in UNIX format before anything is touched 106 | if $cygwin ; then 107 | [ -n "$M2_HOME" ] && 108 | M2_HOME=`cygpath --unix "$M2_HOME"` 109 | [ -n "$JAVA_HOME" ] && 110 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 111 | [ -n "$CLASSPATH" ] && 112 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 113 | fi 114 | 115 | # For Mingw, ensure paths are in UNIX format before anything is touched 116 | if $mingw ; then 117 | [ -n "$M2_HOME" ] && 118 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 119 | [ -n "$JAVA_HOME" ] && 120 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 121 | fi 122 | 123 | if [ -z "$JAVA_HOME" ]; then 124 | javaExecutable="`which javac`" 125 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 126 | # readlink(1) is not available as standard on Solaris 10. 127 | readLink=`which readlink` 128 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 129 | if $darwin ; then 130 | javaHome="`dirname \"$javaExecutable\"`" 131 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 132 | else 133 | javaExecutable="`readlink -f \"$javaExecutable\"`" 134 | fi 135 | javaHome="`dirname \"$javaExecutable\"`" 136 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 137 | JAVA_HOME="$javaHome" 138 | export JAVA_HOME 139 | fi 140 | fi 141 | fi 142 | 143 | if [ -z "$JAVACMD" ] ; then 144 | if [ -n "$JAVA_HOME" ] ; then 145 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 146 | # IBM's JDK on AIX uses strange locations for the executables 147 | JAVACMD="$JAVA_HOME/jre/sh/java" 148 | else 149 | JAVACMD="$JAVA_HOME/bin/java" 150 | fi 151 | else 152 | JAVACMD="`\\unset -f command; \\command -v java`" 153 | fi 154 | fi 155 | 156 | if [ ! -x "$JAVACMD" ] ; then 157 | echo "Error: JAVA_HOME is not defined correctly." >&2 158 | echo " We cannot execute $JAVACMD" >&2 159 | exit 1 160 | fi 161 | 162 | if [ -z "$JAVA_HOME" ] ; then 163 | echo "Warning: JAVA_HOME environment variable is not set." 164 | fi 165 | 166 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 167 | 168 | # traverses directory structure from process work directory to filesystem root 169 | # first directory with .mvn subdirectory is considered project base directory 170 | find_maven_basedir() { 171 | 172 | if [ -z "$1" ] 173 | then 174 | echo "Path not specified to find_maven_basedir" 175 | return 1 176 | fi 177 | 178 | basedir="$1" 179 | wdir="$1" 180 | while [ "$wdir" != '/' ] ; do 181 | if [ -d "$wdir"/.mvn ] ; then 182 | basedir=$wdir 183 | break 184 | fi 185 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 186 | if [ -d "${wdir}" ]; then 187 | wdir=`cd "$wdir/.."; pwd` 188 | fi 189 | # end of workaround 190 | done 191 | echo "${basedir}" 192 | } 193 | 194 | # concatenates all lines of a file 195 | concat_lines() { 196 | if [ -f "$1" ]; then 197 | echo "$(tr -s '\n' ' ' < "$1")" 198 | fi 199 | } 200 | 201 | BASE_DIR=`find_maven_basedir "$(pwd)"` 202 | if [ -z "$BASE_DIR" ]; then 203 | exit 1; 204 | fi 205 | 206 | ########################################################################################## 207 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 208 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 209 | ########################################################################################## 210 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 211 | if [ "$MVNW_VERBOSE" = true ]; then 212 | echo "Found .mvn/wrapper/maven-wrapper.jar" 213 | fi 214 | else 215 | if [ "$MVNW_VERBOSE" = true ]; then 216 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 217 | fi 218 | if [ -n "$MVNW_REPOURL" ]; then 219 | jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 220 | else 221 | jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 222 | fi 223 | while IFS="=" read key value; do 224 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 225 | esac 226 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 227 | if [ "$MVNW_VERBOSE" = true ]; then 228 | echo "Downloading from: $jarUrl" 229 | fi 230 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 231 | if $cygwin; then 232 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` 233 | fi 234 | 235 | if command -v wget > /dev/null; then 236 | if [ "$MVNW_VERBOSE" = true ]; then 237 | echo "Found wget ... using wget" 238 | fi 239 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 240 | wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 241 | else 242 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 243 | fi 244 | elif command -v curl > /dev/null; then 245 | if [ "$MVNW_VERBOSE" = true ]; then 246 | echo "Found curl ... using curl" 247 | fi 248 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 249 | curl -o "$wrapperJarPath" "$jarUrl" -f 250 | else 251 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f 252 | fi 253 | 254 | else 255 | if [ "$MVNW_VERBOSE" = true ]; then 256 | echo "Falling back to using Java to download" 257 | fi 258 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 259 | # For Cygwin, switch paths to Windows format before running javac 260 | if $cygwin; then 261 | javaClass=`cygpath --path --windows "$javaClass"` 262 | fi 263 | if [ -e "$javaClass" ]; then 264 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 265 | if [ "$MVNW_VERBOSE" = true ]; then 266 | echo " - Compiling MavenWrapperDownloader.java ..." 267 | fi 268 | # Compiling the Java class 269 | ("$JAVA_HOME/bin/javac" "$javaClass") 270 | fi 271 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 272 | # Running the downloader 273 | if [ "$MVNW_VERBOSE" = true ]; then 274 | echo " - Running MavenWrapperDownloader.java ..." 275 | fi 276 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 277 | fi 278 | fi 279 | fi 280 | fi 281 | ########################################################################################## 282 | # End of extension 283 | ########################################################################################## 284 | 285 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 286 | if [ "$MVNW_VERBOSE" = true ]; then 287 | echo $MAVEN_PROJECTBASEDIR 288 | fi 289 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 290 | 291 | # For Cygwin, switch paths to Windows format before running java 292 | if $cygwin; then 293 | [ -n "$M2_HOME" ] && 294 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 295 | [ -n "$JAVA_HOME" ] && 296 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 297 | [ -n "$CLASSPATH" ] && 298 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 299 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 300 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 301 | fi 302 | 303 | # Provide a "standardized" way to retrieve the CLI args that will 304 | # work with both Windows and non-Windows executions. 305 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 306 | export MAVEN_CMD_LINE_ARGS 307 | 308 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 309 | 310 | exec "$JAVACMD" \ 311 | $MAVEN_OPTS \ 312 | $MAVEN_DEBUG_OPTS \ 313 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 314 | "-Dmaven.home=${M2_HOME}" \ 315 | "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 316 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 317 | --------------------------------------------------------------------------------