SpringBoot调用ChatGPT-API实现智能对话

news2025/1/11 5:51:43

目录

一、说明

二、代码

2.1、对话测试

2.2、单次对话

2.3、连续对话

2.4、AI绘画


一、说明

我们在登录chatgpt官网进行对话是不收费的,但需要魔法。在调用官网的API时,在代码层面上使用,通过API KEY进行对话是收费的,不过刚注册的小伙伴有免费5美金的体验额度,在不调用绘画模型,只是做为简单的问答,个人使用是没问题的。

ChatGPT官网

API使用情况

二、代码

2.1、对话测试

Gpt35TurboVO

import lombok.Data;

@Data
public class Gpt35TurboVO {
    private String role;     // 角色一般为 user
    private String content;  // 询问内容
}

Controller

    @GetMapping(value = "/test", produces = "text/event-stream;charset=UTF-8")
    public String test(@RequestParam String message) {
        //回复用户
        String apikey = "sk-****";
        //请求ChatGPT的URL
        String url = "https://api.openai.com/v1/chat/completions";

        Gpt35TurboVO gpt35TurboVO = new Gpt35TurboVO();
        gpt35TurboVO.setRole("user");
        gpt35TurboVO.setContent(message);
        List<Gpt35TurboVO> objects = new ArrayList<>();
        objects.add(gpt35TurboVO);
        Map<Object, Object> objectObjectHashMap = new HashMap<>();
        objectObjectHashMap.put("model", "gpt-3.5-turbo");  //使用的模型
        objectObjectHashMap.put("messages", objects);       //提问信息
        objectObjectHashMap.put("stream", false);            //流
        objectObjectHashMap.put("temperature", 0);          //GPT回答温度(随机因子)
        objectObjectHashMap.put("frequency_penalty", 0);    //重复度惩罚因子
        objectObjectHashMap.put("presence_penalty", 0.6);   //控制主题的重复度
        String postData = JSONUtil.toJsonStr(objectObjectHashMap);

        String result2 = HttpRequest.post(url)
                .header("Authorization", "Bearer " + apikey)//头信息,多个头信息多次调用此方法即可
                .header("Content-Type", "application/json")
                .body(postData)//表单内容
                .timeout(200000)//超时,毫秒
                .execute().body();

        System.out.println(result2);

        return result2;

    }

返回结果

2.2、单次对话

ChatBotSingleQuestionVO

import lombok.Data;

/**
 * 应用管理-单次提问-VO
 * @author lf
 * @date 2023/8/18
 */
@Data
public class ChatBotSingleQuestionVO {

    /**
     * 用户输入的询问内容
     */
    private String prompt;

    /**
     * 角色扮演ID
     */
    private Integer rolePlayId;

}

Redis锁工具类

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * redis锁工具类
 *
 * @author ruoyi
 */
@Component
public class RedisLock {
    @Autowired
    private RedissonClient redissonClient;

    /**
     * 获取锁
     *
     * @param lockKey 锁实例key
     * @return 锁信息
     */
    public RLock getRLock(String lockKey) {
        return redissonClient.getLock(lockKey);
    }

    /**
     * 加锁
     *
     * @param lockKey 锁实例key
     * @return 锁信息
     */
    public RLock lock(String lockKey) {
        RLock lock = getRLock(lockKey);
        lock.lock();
        return lock;
    }

    /**
     * 加锁
     *
     * @param lockKey   锁实例key
     * @param leaseTime 上锁后自动释放锁时间
     * @return true=成功;false=失败
     */
    public Boolean tryLock(String lockKey, long leaseTime) {
        return tryLock(lockKey, 0, leaseTime, TimeUnit.SECONDS);
    }

    /**
     * 加锁
     *
     * @param lockKey   锁实例key
     * @param leaseTime 上锁后自动释放锁时间
     * @param unit      时间颗粒度
     * @return true=加锁成功;false=加锁失败
     */
    public Boolean tryLock(String lockKey, long leaseTime, TimeUnit unit) {
        return tryLock(lockKey, 0, leaseTime, unit);
    }

    /**
     * 加锁
     *
     * @param lockKey   锁实例key
     * @param waitTime  最多等待时间
     * @param leaseTime 上锁后自动释放锁时间
     * @param unit      时间颗粒度
     * @return true=加锁成功;false=加锁失败
     */
    public Boolean tryLock(String lockKey, long waitTime, long leaseTime, TimeUnit unit) {
        RLock rLock = getRLock(lockKey);
        boolean tryLock = false;
        try {
            tryLock = rLock.tryLock(waitTime, leaseTime, unit);
        } catch (InterruptedException e) {
            return false;
        }
        return tryLock;
    }

    /**
     * 释放锁
     *
     * @param lockKey 锁实例key
     */
    public void unlock(String lockKey) {
        RLock lock = getRLock(lockKey);
        lock.unlock();
    }

    /**
     * 释放锁
     *
     * @param lock 锁信息
     */
    public void unlock(RLock lock) {
        lock.unlock();
    }
}

Controller

    @PostMapping("/chatBotSingleQuestion/api")
    public AjaxResult chatBotSingleQuestion(@RequestBody ChatBotSingleQuestionVO chatBotSingleQuestionVO) {
        String answerContent = iChatBotSingleQuestionService.chatBotSingleQuestion(chatBotSingleQuestionVO);
        return success("success", answerContent);
    }

Impl

    /**
     * 应用管理-用户单次提问-不支持续问对话
     * @param chatBotSingleQuestionVO
     * @return
     */
    @Override
    @Transactional
    public String chatBotSingleQuestion(ChatBotSingleQuestionVO chatBotSingleQuestionVO) {

        if (Objects.isNull(chatBotSingleQuestionVO.getRolePlayId())){
            throw new RuntimeException("参数不可为空");
        }


        String lockName = "QA_" + SecurityUtils.getUserId();

        //回答的内容
        String answerContent = "";

        try{
            RLock rLock = redisLock.getRLock(lockName);
            boolean locked = rLock.isLocked();

            if (locked) {
                throw new RuntimeException("正在回复中...");
            }

            //对同一用户访问加锁
            redisLock.lock(lockName);
            this.chatBefore(chatBotSingleQuestionVO);
            InputStream is = this.sendRequestBeforeChat(chatBotSingleQuestionVO);
            String line = "";
            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            while ((line = reader.readLine()) != null) {
                //首先对行数据进行处理
                if (StrUtil.isNotBlank(line) &&
                        !StrUtil.equals(line, "event: answer") &&
                        !StrUtil.equals(line, "event: chatResponse") &&
                        !StrUtil.contains(line, "data: {\"quoteLen\"")) {
                    line = CollectionUtil.removeEmpty(StrUtil.split(line, "data: ")).get(0);
                    if (!StrUtil.contains(line, "[DONE]")) {
                        String oneWord = catchTextGpt(line);
                        if (StrUtil.isNotBlank(oneWord)) {
                            answerContent = answerContent + oneWord;
                        }
                    }
                    WebSocketService.sendInfo(line, SecurityUtils.getUserId() + "");
                    TimeUnit.MILLISECONDS.sleep(50);
                }
            }
            //处理完了后将次条聊天记录进行记录
            if (StrUtil.isNotBlank(answerContent)) {
                //保存聊天记录
                this.saveDialogueProcess(chatBotSingleQuestionVO, answerContent);
                //更新提问次数
                this.upddateAppModel(chatBotSingleQuestionVO);
            }
            is.close();
            reader.close();


        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }finally {
            redisLock.unlock(lockName);
        }
        return answerContent;
    }

sendRequestBeforeChat方法

    /**
     * 这块为问询,不包含对话模式
     *
     * @param chatBotSingleQuestionVO
     * @return
     * @throws Exception
     */
    @Transactional
    public InputStream sendRequestBeforeChat(ChatBotSingleQuestionVO chatBotSingleQuestionVO) throws Exception {
        InputStream in = null;
        // 通知内容添加文本铭感词汇过滤
        //其余错误见返回码说明
        //正常返回0
        //违禁词检测
        this.disableWordCheck(chatBotSingleQuestionVO.getPrompt());
        String apikeyRefresh = getOpenAiKey();
        if (StrUtil.isBlank(apikeyRefresh)) {
            throw new RuntimeException("无可用key");
        }
        List<Gpt35TurboVO> chatContext = this.getChatContext(chatBotSingleQuestionVO);
        String requestUrl = iTbKeyManagerService.getproxyUrl();
        Map<Object, Object> objectObjectHashMap = new HashMap<>();
        objectObjectHashMap.put("model", "gpt-3.5-turbo");
        objectObjectHashMap.put("messages", chatContext);
        objectObjectHashMap.put("stream", true);
        objectObjectHashMap.put("temperature", 0);
        objectObjectHashMap.put("frequency_penalty", 0);
        objectObjectHashMap.put("presence_penalty", 0.6);
        String bodyJson = JSONUtil.toJsonStr(objectObjectHashMap);
        URL url = new URL(requestUrl); // 接口地址
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        urlConnection.setRequestMethod("POST");
        urlConnection.setDoOutput(true);
        urlConnection.setDoInput(true);
        urlConnection.setUseCaches(false);
        urlConnection.setRequestProperty("Connection", "Keep-Alive");
        urlConnection.setRequestProperty("Charset", "UTF-8");
        urlConnection.setRequestProperty("Authorization", "Bearer " + apikeyRefresh);
        urlConnection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
        byte[] dataBytes = bodyJson.getBytes();
        urlConnection.setRequestProperty("Content-Length", String.valueOf(dataBytes.length));
        OutputStream os = urlConnection.getOutputStream();
        os.write(dataBytes);
        in = new BufferedInputStream(urlConnection.getInputStream());
        os.flush();
        os.close();
        return in;

    }

catchTextGpt方法

    /**
     * 处理单独打印的文字
     *
     * @param str
     * @return
     */
    public String catchTextGpt(String str) {
        String choices = JsonUtil.parseMiddleData(str, "choices");
        JSONArray jsonArray = JSONUtil.parseArray(choices);
        String string = jsonArray.getByPath("[0].delta").toString();
        String content = JsonUtil.parseMiddleData(string, "content");
        return content;
    }

getChatContext方法

    /**
     * 角色扮演
     * @param chatBotSingleQuestionVO
     * @return 结果
     */
    public List<Gpt35TurboVO> getChatContext(ChatBotSingleQuestionVO chatBotSingleQuestionVO) {

        List<Gpt35TurboVO> messages = new ArrayList<>();

        //首先获取角色,设置默认角色
        String default_role_content = iconfigService.selectConfigByKey("default_role");
        if (StrUtil.isBlank(default_role_content)) {
            default_role_content = "我是一个全能机器人,可以回答你任何问题";
        }

        TbAppModel tbAppModel = iTbAppModelService.selectTbAppModelById(Long.valueOf(chatBotSingleQuestionVO.getRolePlayId()));
        if (!Objects.isNull(tbAppModel)){
            default_role_content = tbAppModel.getAppModelContent();
        }
        //小程序专用
        //是否通过微信小程序审核的设定语
        String is_open_pass_wx_promt = iconfigService.selectConfigByKey("is_open_pass_wx_promt");
        if (StrUtil.isNotBlank(is_open_pass_wx_promt) && !StrUtil.equals(is_open_pass_wx_promt, "0")) {
            String pass_wx_promt = iconfigService.selectConfigByKey("pass_wx_promt");
            default_role_content = default_role_content + "。并且你必须遵循:" + pass_wx_promt;
        }

        //设定系统所扮演的角色
        Gpt35TurboVO gpt35TurboVOSys = new Gpt35TurboVO();
        gpt35TurboVOSys.setRole("system");
        gpt35TurboVOSys.setContent(default_role_content);
        messages.add(gpt35TurboVOSys);


        //最后查询用户最新询问的问题
        Gpt35TurboVO gpt35TurboUser = new Gpt35TurboVO();
        gpt35TurboUser.setRole("user");
        gpt35TurboUser.setContent(chatBotSingleQuestionVO.getPrompt());
        messages.add(gpt35TurboUser);
        return messages;
    }

getOpenAiKey方法

    /**
     * 查询key是否可用
     * @return 结果
     */
    public String getOpenAiKey() {
        //模仿查到的key集合
        TbKeyManager tbKeyManager = new TbKeyManager();
        tbKeyManager.setIsUse(1);
        //可用的key
        List<TbKeyManager> tbKeyManagers = iTbKeyManagerService.selectTbKeyManagerList(tbKeyManager);
        //判断是否key额度用完
        if (CollectionUtil.isEmpty(tbKeyManagers) || tbKeyManagers.size() <= 0) {
            throw new RuntimeException("key额度耗尽");
        }
        //获取第一个key,然后将第一个key存入缓存
        String key = tbKeyManagers.get(0).getSecretKey();
        redisTemplate.opsForValue().set("apikey", key);
        //检查key
        changeKey(tbKeyManagers.get(0));
        return key;
    }

2.3、连续对话

Controller

    @PostMapping(value = "/chatBotNoId/api")
    public AjaxResult continuousDialogue(@RequestBody StreamParametersVO streamParametersVO) {
        String answerContent = iChatGtpService.continuousDialogueSocketStream(streamParametersVO);
        return success("success", answerContent);
    }

Impl

    /**
     * 用户直接发起连续对话,系统同意创建对话主题,用户不用手动新建主题
     *
     * @param streamParametersVO
     */
    @Override
    public String continuousDialogueSocketStream(StreamParametersVO streamParametersVO) {

        //判断是否isNewOpen填写参数,表示是否先开对话
        if (Objects.isNull(streamParametersVO.getIsNewOpen())) {
            throw new RuntimeException("isNewOpen参数未填");
        }

        if (streamParametersVO.getIsNewOpen()) {
            //新开对话,创建新的对话主题
            tbModelTable = new TbModelTable();
            //主题名称
            tbModelTable.setModelName("Dialogue_" + SecurityUtils.getUserId() + "_" + DateTime.now());
            //设置模板角色
            if (Objects.nonNull(streamParametersVO.getDialogueRoleId())) {
                tbModelTable.setId(Long.valueOf(streamParametersVO.getDialogueRoleId()));
            } else {
                tbModelTable.setId(1L);
            }
            tbDialogueMain = tbDialogueMainService.creatNewDig(tbModelTable);
        } else {
            //非新开对话,查询本次的对话主题
            TbDialogueMain tbDialogueMainParam = new TbDialogueMain();
            //设置模板角色
            if (Objects.nonNull(streamParametersVO.getDialogueRoleId())) {
                tbDialogueMainParam.setDialogueRoleId(Long.valueOf(streamParametersVO.getDialogueRoleId()));
            } else {
                tbDialogueMainParam.setDialogueRoleId(1L);
            }

            tbDialogueMainParam.setUserId(SecurityUtils.getUserId());
            List<TbDialogueMain> tbDialogueMains = iTbDialogueMainService.selectTbDialogueMainList(tbDialogueMainParam);

            if (CollectionUtil.isEmpty(tbDialogueMains)) {
                //创建新的对话主题
                tbModelTable = new TbModelTable();
                //主题名称
                tbModelTable.setModelName("Dialogue_" + SecurityUtils.getUserId() + "_" + DateTime.now());
                //设置模板角色
                tbModelTable.setId(Long.valueOf(streamParametersVO.getDialogueRoleId()));
                tbDialogueMain = tbDialogueMainService.creatNewDig(tbModelTable);
            } else {
                tbDialogueMain = tbDialogueMains.get(0);
            }

        }

        //设置对话ID
        streamParametersVO.setDialogueId(tbDialogueMain.getId());

        String lockName = "chat_" + SecurityUtils.getUserId();
        //回答的内容
        String answerContent = "";
        try {

            RLock rLock = redisLock.getRLock(lockName);
            boolean locked = rLock.isLocked();

            if (locked) {
                throw new RuntimeException("正在回复中...");
            }

            //对同一用户访问加锁
            redisLock.lock(lockName);

            //进来做校验
            TbDialogueMain tbDialogueMain = this.paramVerify(streamParametersVO);

            String userId = SecurityUtils.getUserId() + "";

            //将提问数据封装为流,并请求OpenAI的接口
            InputStream inputStream = this.sendRequestBefore(streamParametersVO, tbDialogueMain);

            String line = null;

            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));

            while ((line = reader.readLine()) != null) {

                //首先对行数据进行处理
                if (StrUtil.isNotBlank(line) &&
                        !StrUtil.equals(line, "event: answer") &&
                        !StrUtil.equals(line, "event: chatResponse") &&
                        !StrUtil.contains(line, "data: {\"quoteLen\"")) {

                    line = CollectionUtil.removeEmpty(StrUtil.split(line, "data: ")).get(0);

                    if (StrUtil.contains(line, "[DONE]")) {
                    } else {

                        String oneWord = catchTextGpt(line);
                        if (StrUtil.isNotBlank(oneWord)) {
                            answerContent = answerContent + oneWord;
                        }
                    }

                    WebSocketService.sendInfo(line, userId);
                    TimeUnit.MILLISECONDS.sleep(50);

                }
            }

            //处理完了后,将此条聊天记录进行保存
            if (StrUtil.isNotBlank(answerContent)) {
                //保存聊天记录
                this.saveDig(streamParametersVO, answerContent);
            }
            inputStream.close();
            reader.close();

        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        } finally {
            //解锁
            redisLock.unlock(lockName);
            //清除正在问话的标识
            redisTemplate.delete(SecurityUtils.getUserId() + "");
        }

        return answerContent;
    }

sendRequestBefore方法

    /**
     * 这块为 - 流对话模式的封装
     *
     * @param streamParametersVO
     * @param tbDialogueMain
     * @return
     * @throws Exception
     */
    @Transactional
    public InputStream sendRequestBefore(StreamParametersVO streamParametersVO, TbDialogueMain tbDialogueMain) throws Exception {

        InputStream in = null;
        //提问内容
        String prompt = streamParametersVO.getPrompt();

        // 获取当前的用户
        String userId = SecurityUtils.getUserId() + "";
        Object o = redisTemplate.opsForValue().get(userId);

        if (!Objects.isNull(o)) {
            throw new RuntimeException("正在回复");
        }

        redisTemplate.opsForValue().set(userId, true, 30, TimeUnit.SECONDS);

        if (StrUtil.isBlank(prompt)) {
            throw new RuntimeException("输入内容为空");
        }

        // 通知内容添加文本铭感词汇过滤
        // 其余错误见返回码说明
        // 违禁词检测 正常返回0
        this.disableWordCheck(prompt);

        String apikeyRefresh = getOpenAiKey();
        if (StrUtil.isBlank(apikeyRefresh)) {
            throw new RuntimeException("无可用key");
        }

        //处理提问内容(指定系统角色+对话上下文+最新的提问内容)
        List<Gpt35TurboVO> chatContext = this.getChatDigContext(streamParametersVO, tbDialogueMain);

        String requestUrl = iTbKeyManagerService.getproxyUrl();
        Map<Object, Object> objectObjectHashMap = new HashMap<>();
        objectObjectHashMap.put("model", "gpt-3.5-turbo");
        objectObjectHashMap.put("messages", chatContext);
        objectObjectHashMap.put("stream", true);
        objectObjectHashMap.put("temperature", 0);
        objectObjectHashMap.put("frequency_penalty", 0);
        objectObjectHashMap.put("presence_penalty", 0.6);
        String bodyJson = JSONUtil.toJsonStr(objectObjectHashMap);
        URL url = new URL(requestUrl); // 接口地址
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        urlConnection.setRequestMethod("POST");
        urlConnection.setDoOutput(true);
        urlConnection.setDoInput(true);
        urlConnection.setUseCaches(false);
        urlConnection.setRequestProperty("Connection", "Keep-Alive");
        urlConnection.setRequestProperty("Charset", "UTF-8");
        urlConnection.setRequestProperty("Authorization", "Bearer " + apikeyRefresh);
        urlConnection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
        byte[] dataBytes = bodyJson.getBytes();
        urlConnection.setRequestProperty("Content-Length", String.valueOf(dataBytes.length));
        OutputStream os = urlConnection.getOutputStream();
        os.write(dataBytes);
        in = new BufferedInputStream(urlConnection.getInputStream());
        os.flush();
        os.close();
        return in;

    }

getChatDigContext方法

    /**
     * 获取对话上下文
     *
     * @param streamParametersVO
     * @return
     */
    public List<Gpt35TurboVO> getChatDigContext(StreamParametersVO streamParametersVO, TbDialogueMain tbDialogueMain) {

        List<Gpt35TurboVO> messages = new ArrayList<>();

        //首先获取角色,默认角色
        String default_role_content = iconfigService.selectConfigByKey("default_role");
        if (StrUtil.isBlank(default_role_content)) {
            default_role_content = "我是一个全能机器人,可以回答你任何问题";
        }

        //根据用户传递过来的Id查询角色模型数据
        TbModelTable tbModelTable = iTbModelTableService.selectTbModelTableById(tbDialogueMain.getDialogueRoleId());
        if (!Objects.isNull(tbModelTable)) {
            default_role_content = tbModelTable.getModelContent();
        }

        //小程序专用
        //是否通过微信小程序审核的设定语
        String is_open_pass_wx_promt = iconfigService.selectConfigByKey("is_open_pass_wx_promt");
        if (StrUtil.isNotBlank(is_open_pass_wx_promt) && !StrUtil.equals(is_open_pass_wx_promt, "0")) {
            String pass_wx_promt = iconfigService.selectConfigByKey("pass_wx_promt");
            default_role_content = default_role_content + "。并且你必须遵循:" + pass_wx_promt;
        }

        //设定系统所扮演的角色
        Gpt35TurboVO gpt35TurboVOSys = new Gpt35TurboVO();
        gpt35TurboVOSys.setRole("system");
        gpt35TurboVOSys.setContent(default_role_content);
        messages.add(gpt35TurboVOSys);

        //然后查询当前对话的上下文数据TbDialogueProcess
        TbDialogueProcess tbDialogueProcess = new TbDialogueProcess();
        tbDialogueProcess.setSessionId(streamParametersVO.getDialogueId());
        tbDialogueProcess.setUserId(SecurityUtils.getUserId());
        String default_context_num = iconfigService.selectConfigByKey("default_context_num");
        if (StrUtil.isBlank(default_context_num) || !NumberUtil.isNumber(default_context_num)) {
            default_context_num = "10";
        }
        tbDialogueProcess.setLimitNum(Integer.valueOf(default_context_num));

        //根据对话ID和用户ID查询到对话列表-根据时间倒叙获取后几条设定的数据
        List<TbDialogueProcess> tbDialogueProcessesDesc = iTbDialogueProcessService
                .selectTbDialogueProcessListByLimitDesc(tbDialogueProcess);

        if (CollectionUtil.isNotEmpty(tbDialogueProcessesDesc)) {
            //获取到倒数10条数据后将数据正序配好
            List<TbDialogueProcess> tbDialogueProcesses = tbDialogueProcessesDesc
                    .stream()
                    .sorted(Comparator.comparing(TbDialogueProcess::getCreateTime))
                    .collect(Collectors.toList());

            for (TbDialogueProcess tbDialogueProcessfor : tbDialogueProcesses) {
                Gpt35TurboVO gpt35TurboUser = new Gpt35TurboVO();
                //用户询问的问题
                gpt35TurboUser.setRole("user");
                gpt35TurboUser.setContent(tbDialogueProcessfor.getAskContent());
                messages.add(gpt35TurboUser);
                //机器人回答的问题
                Gpt35TurboVO gpt35TurAssistant = new Gpt35TurboVO();
                gpt35TurAssistant.setRole("assistant");
                gpt35TurAssistant.setContent(tbDialogueProcessfor.getAnswerContent());
                messages.add(gpt35TurAssistant);
            }

        }

        //最后查询用户最新询问的问题
        Gpt35TurboVO gpt35TurboUser = new Gpt35TurboVO();
        gpt35TurboUser.setRole("user");
        gpt35TurboUser.setContent(streamParametersVO.getPrompt());
        messages.add(gpt35TurboUser);

        return messages;
    }

2.4、AI绘画

Controller

    @PostMapping("/image/api")
    public AjaxResult imageApi(@RequestBody StreamImageParametersVO streamImageParametersVO) {
        String answerContent = iChatGptImageService.imageSocketStream(streamImageParametersVO);
        return success("success",answerContent);
    }

Impl

    @Override
    public String imageSocketStream(StreamImageParametersVO imageParametersVO) {

        String lockName = "image_" + SecurityUtils.getUserId();

        String answerContent = "";

        try{
            RLock rLock = redisLock.getRLock(lockName);
            boolean locked = rLock.isLocked();
            if (locked){
                throw new RuntimeException("回复中");
            }
            //对同一用户访问加锁
            redisLock.lock(lockName);
            //校验是否输入内容,次数扣减
            this.imageBefore(imageParametersVO);
            String userId = SecurityUtils.getUserId() + "";
            InputStream is = this.sendRequestBeforeImage(imageParametersVO);
            String line = null;
            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            while((line = reader.readLine()) != null){
                //数据处理
                if (StrUtil.isNotBlank(line) &&
                        !StrUtil.equals(line, "event: answer") &&
                        !StrUtil.equals(line, "event: chatResponse") &&
                        !StrUtil.contains(line, "data: {\"quoteLen\"")) {
                    line = CollectionUtil.removeEmpty(StrUtil.split(line, "data: ")).get(0);
                    if (StrUtil.contains(line, "[DONE]")){

                    }else{
                        String oneWord = catchUrlImage(line);
                        if (StrUtil.isNotBlank(oneWord)){
                            answerContent = answerContent + oneWord;
                        }
                    }
                    WebSocketService.sendInfo(line,userId);
                    TimeUnit.MILLISECONDS.sleep(50);
                }
            }
            //处理完之后将次条聊天记录进行记录
            if (StrUtil.isNotBlank(answerContent)){
                //保存聊天记录
                this.saveDialogueLog(imageParametersVO, answerContent);
            }
            is.close();
            reader.close();

        }catch (Exception e){
            throw new RuntimeException(e.getMessage());
        }finally {
            //解锁
            redisLock.unlock(lockName);
            redisTemplate.delete(SecurityUtils.getUserId() + "");
        }

        return saveImageUrl(jsonImageUrl(answerContent));
    }

sendRequestBeforeImage方法

    /**
     * 问询,不包含对话模式
     */
    @Transactional
    public InputStream sendRequestBeforeImage(StreamImageParametersVO imageParametersVO) throws Exception{
        InputStream in = null;
        //通知内容添加文本敏感词汇过滤
        //其余错误见返回码说明
        //正常返回0
        //违禁词检测
        this.disbleWordImageCheck(imageParametersVO.getPrompt());
        String apikeyRefresh =  getOpenAiKey();
        if (StrUtil.isBlank(apikeyRefresh)){
            throw new RuntimeException("无可用key");
        }

//        List<Gpt35TurboVO> imageContext = this.getImageContext(imageParametersVO);
        String requestImageUrl = iTbKeyManagerService.getImageProxyUrl();
        Map<Object, Object> objectObjecHashtMap = new HashMap<>();
        objectObjecHashtMap.put("prompt", imageParametersVO.getPrompt());
        objectObjecHashtMap.put("n", 1);
        objectObjecHashtMap.put("size", "1024x1024");
        String bodyJson = JSONUtil.toJsonStr(objectObjecHashtMap);
        URL url = new URL(requestImageUrl); //接口地址
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        urlConnection.setRequestMethod("POST");
        urlConnection.setDoOutput(true);
        urlConnection.setDoInput(true);
        urlConnection.setUseCaches(false);
        urlConnection.setRequestProperty("Connection", "Keep-Alive");
        urlConnection.setRequestProperty("Charset", "UTF-8");
        urlConnection.setRequestProperty("Authorization", "Bearer " + apikeyRefresh);
        urlConnection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
        byte[] dataBytes = bodyJson.getBytes();
        urlConnection.setRequestProperty("Content-Length", String.valueOf(dataBytes.length));
        OutputStream os = urlConnection.getOutputStream();
        os.write(dataBytes);
        in = new BufferedInputStream(urlConnection.getInputStream());
        os.flush();
        os.close();
        return in;

    }

catchUrlImage方法

    /**
     * 对链接地址处理
     */
    public String catchUrlImage(String str){

        return str;

    }

图片处理,chatgpt返回的图片有效期是五分钟,我们需要将图片下载至本地或服务器。

    /**
     * 保存图片返回的结果
     */
    public String saveImageUrl(String jsonUrl){

        String imageURL = uploadFileImageAi(jsonUrl);

        // 找到下划线的索引位置
        int underscoreIndex = imageURL.indexOf('_');

        String result = "";

        if (underscoreIndex != -1) {
            // 截取从下划线的位置开始到字符串的末尾
            result = imageURL.substring(underscoreIndex - 9);
        } else {
            throw new RuntimeException("图片链接截取失败");
        }

        return TomcatConfig.getImageAiUrl() + "/" + result;
    }
    
    /**
     * 图片处理
     * @param imageUrl
     * @return
     */
    public String uploadFileImageAi(String imageUrl){

//        //服务器文件上传路径
        String path = TomcatConfig.setUploadImageAiUrl() + Constants.DRAW_PREFIX + "_" + Seq.getId(Seq.uploadSeqType) + ".png";
//        本地文件上传路径
//        String path = "D:\\BaiduNetdiskDownload\\image-use\\" + Constants.DRAW_PREFIX + "_" + Seq.getId(Seq.uploadSeqType) + ".png";

        try{
            URL url = new URL(imageUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                InputStream inputStream = connection.getInputStream();
                OutputStream outputStream = new FileOutputStream(path);

                byte[] buffer = new byte[4096];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }

                outputStream.close();
                inputStream.close();
            } else {
                throw new RuntimeException("文件无法下载");
            }
        }catch (IOException e){
            e.printStackTrace();
        }
        return path;
    }

    /**
     * JSON数据处理
     * @param imageContent
     * @return
     */
    public String jsonImageUrl(String imageContent){

        //解析json字符串
        JSONObject obj = JSON.parseObject(imageContent);

        //获取 "data"字段相应的JSON数组
        JSONArray dataArray = obj.getJSONArray("data");

        //获取第一个元素路径地址
        JSONObject dataObject = dataArray.getJSONObject(0);

        // 返回"url"字段的值
        return dataObject.getString("url");
    }

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1022446.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

企业架构LNMP学习笔记52

Redis安全限制&#xff1a; IP限制登录&#xff1a; 打开配置IP限制&#xff1a; 注意&#xff0c;如果有防火墙&#xff0c;先关闭防火墙&#xff0c;或者开启端口限制。 重启服务&#xff0c;检测是否启动成功。 远程连接测试&#xff1a; 密码验证&#xff1a; 修改配置…

成集云 | 金蝶云星辰集成聚水潭ERP(金蝶云星辰主管库存)| 解决方案

源系统成集云目标系统 方案介绍 金蝶云星辰是金蝶旗下的一款企业级SaaS管理云&#xff0c;其目标是帮助企业拓客开源、智能管理和实时决策。为了实现这一目标&#xff0c;它为企业提供了多种SaaS服务&#xff0c;包括财务云、税务云、进销存云、生产云、零售云、电商…

java调用天地图api获取地理信息

目录 1、注册账号登录 2、创建应用&#xff0c;获取key 3、查看接口示例 4、调用接口 4.1地理编码查询 4.2逆地理编码查询 天地图网址&#xff1a;天地图API 1、注册账号登录 2、创建应用&#xff0c;获取key 3、查看接口示例 4、调用接口 4.1地理编码查询 public cla…

Cesium 测量距离

Cesium 测量距离 需求分析第一种方式&#xff1a;使用测距 Measure第二中方式&#xff1a;使用 distance&#xff0c;自己封装第三种方式&#xff1a;自己封装&#xff08;样式不太好&#xff09; 需求 实际开发中我们经常需要用到量测工具&#xff0c;而Cesium没有直接提供量…

【AD操作】【原理图标注配置器】批量更新原理图的元件标签

原理图标注配置器 快捷键 T-A-A 1.调整编号顺序 2.设置起始编号 3.更新 和 执行变更 对 学习笔记&#xff0c;供自己复习参考。

Java基于微信小程序的自习室系统的设计,附源码、教程

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 文章目录 1 简介2 技术栈3 需求分析3.1用户需求分析3.1.1 学生用户3.1.3 管理员用户 4 数据库设计4.4.1 E…

使用Chatgpt编写的PHP数据库pdo操作类(增删改查)

摘要 将PDO封装成PHP类进行调用有很多好处&#xff0c;包括&#xff1a; 1、封装性和抽象性&#xff1a; 通过将PDO封装到一个类中&#xff0c;您可以将数据库操作逻辑与应用程序的其他部分分离开来&#xff0c;提高了代码的组织性和可维护性。这样&#xff0c;您只需在一个地…

面对IT部门和业务部门跨网文件交换的不同需求,怎样才能兼顾呢?

文件交换是企业中必不可少的一环&#xff0c;无论是内部员工之间&#xff0c;还是与外部客户、供应商、合作伙伴之间&#xff0c;都需要频繁地进行文件的发送和接收。然而&#xff0c;由于企业内外网之间的隔离&#xff0c;跨网文件交换往往面临着诸多困难和挑战。如何在保证文…

【Verilog语法】比较不同计数器的运算方式,其中有一个数是延迟打一拍的效果,目的是使得两个计数器的结果相同。

比较不同计数器的运算方式&#xff0c;其中有一个数是延迟打一拍的效果&#xff0c;目的是使得两个计数器的结果相同。 1&#xff0c;第一种2&#xff0c;第二种3&#xff0c;第三种 第三种方案&#xff0c;完成实现。 1&#xff0c;第一种 &#xff08;1&#xff09;RTL modu…

基于Python开发的火车票分析助手(源码+可执行程序+程序配置说明书+程序使用说明书)

一、项目简介 本项目是一套基于Python开发的火车票分析助手&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Python学习者。 包含&#xff1a;项目源码、项目文档等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;…

企业如何使员工保持工作的积极性?

保持员工的工作积极性对于企业来说至关重要。激发员工的热情和投入度可以提高工作效率、创造力和团队合作&#xff0c;进而为企业带来更好的成果和竞争优势。以下是一些企业可以采取的方法来确保员工保持积极性&#xff1a; 提供发展机会 员工希望在职业生涯中不断成长和发展…

数据库管理-第105期 安装Database Valut组件(20230919)

数据库管理-第105期 安装Database Valut组件&#xff08;20230919&#xff09; 之前无论是是EXPDP还是PDB中遇到的一些问题&#xff0c;其实都跟数据库的DV&#xff08;Database Valut&#xff09;组件有关&#xff0c;因为目标库没有安装DV导致启动时会出现问题。 1 DV/OLS …

Seata 源码篇之AT模式启动流程 - 上 - 02

Seata 源码篇之AT模式启动流程 - 02 自动配置两个关键点 初始化初始化TM初始化RM初始化TC 全局事务执行流程TM 发起全局事务GlobalTransactional 注解处理全局事务的开启 TM 和 RM 执行分支事务IntroductionDelegatingIntroductionInterceptorDelegatePerTargetObjectIntroduct…

Linux开发工具之编辑器-vim

vim简单来说就是一款文本编辑器&#xff0c;用于写代码&#xff0c;更是一款多模式编辑器 vim的基本概念 vim有许多种模式&#xff0c;但是铁三角是以下三种模式&#xff1a;命令模式&#xff0c;插入模式&#xff0c;底行模式 1 正常/普通/命令模式&#xff08;默认打开&…

搭建私人图床结合内网穿透实现公网访问,让您的摄影作品连接世界

文章目录 1. 树洞外链网站搭建1.1 下载安装树洞外链1.2 树洞外链网页测试1.3 cpolar的安装和注册 2.本地网页发布2.1 Cpolar临时数据隧道2.2 Cpolar稳定隧道&#xff08;云端设置&#xff09;2.3 Cpolar稳定隧道&#xff08;本地设置&#xff09; 3.公网访问测试 社交平台具有庞…

Go 语言学习总结(9)—— Go 与 Java 全面对比总结

基本语法格式 Golang: 编码风格相对统一&#xff0c;简单&#xff0c;没有太多的语法糖等&#xff0c;Java层次清晰&#xff0c;全面面向对象。 变量相关 变量的声明及使用 在Java或者PHP、Python中&#xff0c;声明了变量&#xff0c;可以不使用&#xff0c;也不报错。 p…

win11 新建markdown文件 添加到右键新建项 无反应(已解决)

需要操作 2 处注册表 1. win R输入【regedit】 定位路径 【计算机\HKEY_CLASSES_ROOT.md】 点击.md文件夹, 双击右侧(默认)项&#xff0c;将数值数据改为【Typora.md】 右键.md文件夹 > 新建 > 项&#xff0c;把新建的项命名为【ShellNew】 右键ShellNew > 新建 >…

基于Spring Boot+ Vue的健身房管理系统与实现

小熊学Java全能学面试指南&#xff1a;https://javaxiaobear.cn 摘要 随着健身行业的快速发展&#xff0c;健身房管理系统成为了提高管理效率和用户体验的重要工具。本论文旨在设计与实现一种基于前后端分离的健身房管理系统&#xff0c;通过前后端分离的架构模式&#xff0c;…

如何代码降重

目录 一、使用的相关工具二、冗余代码的分类和压缩策略2.1 无用代码2.2 重复代码2.3 相似代码 三、长久治理机制3.1 git-hooks 一、使用的相关工具 以下工具都有各自详细说明的文档。除非有必要&#xff0c;下文不再对其相关使用作详细说明。 仓库代码查重工具&#xff1a;http…

WebStorm 2023年下载、安装教程、亲测有效

文章目录 简介安装步骤常用快捷键 简介 WebStorm 是JetBrains公司旗下一款JavaScript 开发工具。已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源&#xff0c;继承了IntelliJ IDEA强大的JS部分的…