文章目录

  • 1.common-openai-starter
  • 1.目录结构
  • 2.OpenAiProperties.java 新增apiUrl
  • 3.OpenAIAutoConfiguration.java
  • 4.OpenAiClient.java 使用gson重构
  • 2.common-openai-starter-demo
  • 1.目录结构
  • 2.application.yml 新增api-url
  • 3.OpenAiController.java
  • 4.OpenAiApplication.java
  • 5.测试
  • 1.common-openai-starter

    1.目录结构

    CleanShot 2025-01-02 at 16.40.21@2x

    2.OpenAiProperties.java 新增apiUrl
    package com.sunxiansheng.openai.config.properties;
    
    import lombok.Data;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    
    /**
     * Description: OpenAI配置属性类
     *
     * @Author sun
     * @Create 2024/12/14 11:44
     * @Version 1.0
     */
    @Data
    @ConfigurationProperties(prefix = "openai")
    public class OpenAiProperties {
    
        /**
         * OpenAI API Key
         */
        private String apiKey;
    
        /**
         * OpenAI API URL 有默认值
         */
        private String apiUrl = "https://api.openai.com/v1/chat/completions";
    }
    
    3.OpenAIAutoConfiguration.java
    package com.sunxiansheng.openai.config;
    
    import com.sunxiansheng.openai.client.OpenAiClient;
    import com.sunxiansheng.openai.config.properties.OpenAiProperties;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * Description: OpenAI自动配置类
     *
     * @Author sun
     * @Create 2024/12/14 11:39
     * @Version 1.0
     */
    @Configuration
    @EnableConfigurationProperties({OpenAiProperties.class}) // 启用配置类
    public class OpenAIAutoConfiguration {
    
        /**
         * 创建 OpenAiClient
         *
         * @return
         */
        @Bean
        @ConditionalOnMissingBean
        public OpenAiClient openAiClient() {
            return new OpenAiClient();
        }
    }
    
    4.OpenAiClient.java 使用gson重构
    package com.sunxiansheng.openai.client;
    
    import com.google.gson.JsonArray;
    import com.google.gson.JsonObject;
    import com.google.gson.JsonParser;
    import com.sunxiansheng.openai.config.properties.OpenAiProperties;
    import okhttp3.*;
    
    import javax.annotation.Resource;
    import java.io.IOException;
    import java.nio.charset.StandardCharsets;
    import java.util.Base64;
    import java.util.concurrent.TimeUnit;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    
    /**
     * Description: OpenAI 客户端类
     *
     * @Author sun
     * @Create 2024/12/14 11:56
     * @Version 1.1
     */
    public class OpenAiClient {
    
        @Resource
        private OpenAiProperties openAiProperties;
    
        private static final OkHttpClient CLIENT = new OkHttpClient.Builder()
                .connectTimeout(120, TimeUnit.SECONDS)
                .readTimeout(120, TimeUnit.SECONDS)
                .writeTimeout(120, TimeUnit.SECONDS)
                .build();
    
        private static final Logger LOGGER = Logger.getLogger(OpenAiClient.class.getName());
    
        /**
         * 向 AI 提问通用方法
         *
         * @param model        使用的 AI 模型,如 "gpt-4o"
         * @param prompt       提示内容
         * @param base64Encode 是否对内容进行 Base64 编码
         * @return AI 的响应内容
         */
        public String askAI(String model, String prompt, boolean base64Encode) {
            try {
                // 处理 Base64 编码
                String encodedPrompt = base64Encode ? encodeBase64(prompt) : prompt;
    
                // 构造请求体
                RequestBody body = RequestBody.create(
                        createJsonRequest(model, encodedPrompt), MediaType.get("application/json; charset=utf-8")
                );
    
                // 构建请求
                Request request = new Request.Builder()
                        .url(openAiProperties.getApiUrl())
                        .header("Authorization", "Bearer " + openAiProperties.getApiKey())
                        .header("Content-Type", "application/json")
                        .post(body)
                        .build();
    
                // 发送请求并获取响应
                try (Response response = CLIENT.newCall(request).execute()) {
                    if (!response.isSuccessful()) {
                        throw new IOException("Unexpected response: " + response);
                    }
    
                    // 解析 JSON 响应
                    return parseResponse(response.body().string());
                }
            } catch (IOException e) {
                LOGGER.log(Level.SEVERE, "Error occurred during API request: " + e.getMessage(), e);
                throw new RuntimeException("API request failed", e);
            }
        }
    
        /**
         * 对输入内容进行 Base64 编码
         *
         * @param prompt 输入内容
         * @return 编码后的字符串
         */
        private String encodeBase64(String prompt) {
            return Base64.getEncoder().encodeToString(prompt.getBytes(StandardCharsets.UTF_8));
        }
    
        /**
         * 构建请求的 JSON 数据
         *
         * @param model         使用的 AI 模型
         * @param encodedPrompt 编码后的输入内容
         * @return 构建好的 JSON 字符串
         */
        private String createJsonRequest(String model, String encodedPrompt) {
            JsonObject jsonRequest = new JsonObject();
            jsonRequest.addProperty("model", model);
    
            JsonArray messages = new JsonArray();
    
            // 添加 system 信息
            JsonObject systemMessage = new JsonObject();
            systemMessage.addProperty("role", "system");
            systemMessage.addProperty("content", "请根据以下内容提供问题的解决方案。使用中文回答,不要使用markdown语法和特殊符号**之类的,注意,内容可能经过 Base64 编码。");
            messages.add(systemMessage);
    
            // 添加 user 信息
            JsonObject userMessage = new JsonObject();
            userMessage.addProperty("role", "user");
            userMessage.addProperty("content", encodedPrompt);
            messages.add(userMessage);
    
            jsonRequest.add("messages", messages);
    
            return jsonRequest.toString();
        }
    
        /**
         * 解析 API 响应内容
         *
         * @param responseBody 响应的 JSON 内容
         * @return 解析后的结果
         */
        private String parseResponse(String responseBody) {
            JsonObject jsonObject = JsonParser.parseString(responseBody).getAsJsonObject();
            JsonArray choices = jsonObject.getAsJsonArray("choices");
    
            if (choices != null && choices.size() > 0) {
                JsonObject choice = choices.get(0).getAsJsonObject();
                JsonObject message = choice.getAsJsonObject("message");
                return message.get("content").getAsString();
            }
    
            throw new RuntimeException("Invalid response: No choices found.");
        }
    }
    

    2.common-openai-starter-demo

    1.目录结构

    CleanShot 2025-01-02 at 16.47.19@2x

    2.application.yml 新增api-url
    openai:
      api-key: guest # 必填,OpenAI API Key
      api-url: https://api.openai.com/v1/chat/completions # 可选,有默认值,为了防止以后 URL 变化
    
    3.OpenAiController.java
    package com.sunxiansheng.openai.controller;
    
    import com.sunxiansheng.openai.client.OpenAiClient;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.annotation.Resource;
    
    /**
     * Description: OpenAI 控制器类
     *
     * @Author sun
     * @Create 2024/12/14 12:27
     * @Version 1.0
     */
    @RestController
    public class OpenAiController {
    
        @Resource
        private OpenAiClient openAiClient;
    
        @RequestMapping("/ask")
        public String ask(String question) {
            String res = openAiClient.askAI("gpt-4o", question, false);
            return "AI回答:" + res;
        }
    }
    
    4.OpenAiApplication.java
    package com.sunxiansheng.openai;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    /**
     * Description: OpenAI启动类
     *
     * @Author sun
     * @Create 2024/12/14 12:23
     * @Version 1.0
     */
    @SpringBootApplication
    public class OpenAiApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(OpenAiApplication.class, args);
        }
    }
    
    5.测试

    CleanShot 2025-01-02 at 16.48.52@2x

    作者:S-X-S

    物联沃分享整理
    物联沃-IOTWORD物联网 » OpenAI模块重构

    发表回复