国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Spring boot實(shí)戰(zhàn)】Springboot+對話ai模型整體框架+高并發(fā)線程機(jī)制處理優(yōu)化+提示詞工程效果展示(按照框架自己修改可對接市面上百分之99的模型)

這篇具有很好參考價(jià)值的文章主要介紹了【Spring boot實(shí)戰(zhàn)】Springboot+對話ai模型整體框架+高并發(fā)線程機(jī)制處理優(yōu)化+提示詞工程效果展示(按照框架自己修改可對接市面上百分之99的模型)。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

?????歡迎光臨????

??我是蘇澤,一位對技術(shù)充滿熱情的探索者和分享者。????

??特別推薦給大家我的最新專欄《Spring 狂野之旅:底層原理高級進(jìn)階》 ??

本專欄純屬為愛發(fā)電永久免費(fèi)?。?!

這是蘇澤的個(gè)人主頁可以看到我其他的內(nèi)容哦????

努力的蘇澤http://suzee.blog.csdn.net/

大家好這里還是蘇澤,關(guān)于我的Spring狂野之旅已經(jīng)出了5期,基本都是從Spring的底層源碼去讀它,不僅能學(xué)會(huì)使用方法又能理解其工作機(jī)制以及原理,我認(rèn)為這是非常美妙的一件事,這幾期反響都還行,

于是這一章專門出一期運(yùn)用前面所講過的知識(shí)? 自己從0開始搭建一個(gè)后臺(tái)程序? 能夠?qū)邮忻嫔辖^大多數(shù)的ai對話api(不同公司的具體的鑒權(quán)方法你們找官網(wǎng)文檔copy就行了)

那么正片開始

目錄

大家好這里還是蘇澤,關(guān)于我的Spring狂野之旅已經(jīng)出了5期,基本都是從Spring的底層源碼去讀它,不僅能學(xué)會(huì)使用方法又能理解其工作機(jī)制以及原理,我認(rèn)為這是非常美妙的一件事,這幾期反響都還行,

于是這一章專門出一期運(yùn)用前面所講過的知識(shí)? 自己從0開始搭建一個(gè)后臺(tái)程序? 能夠?qū)邮忻嫔辖^大多數(shù)的ai對話api(不同公司的具體的鑒權(quán)方法你們找官網(wǎng)文檔copy就行了)

從零開始 搭建一個(gè)Spring boot程序

確保你已經(jīng)安裝了Java開發(fā)工具(JDK)。你可以在命令行中輸入java -version來驗(yàn)證是否已安裝Java,并確保版本符合Spring Boot的要求。?編輯安裝的部分我就不演示了默認(rèn)大家已經(jīng)裝好配置好環(huán)境

創(chuàng)建一個(gè)新的Spring Boot項(xiàng)目。你可以使用?編輯新建一個(gè)Springboot項(xiàng)目?編輯

手動(dòng)添加的依賴:

統(tǒng)一封裝一下返回結(jié)果

開干:

1.構(gòu)建好機(jī)器人需要的常量:

下面的部分就是存放對應(yīng)模型的url和Serverid以及秘鑰 這些是根據(jù)你們要選定的模型去改的

存歷史記錄 以及查詢歷史記錄的方法:

下面是獲取ai對話的回答內(nèi)容的部分 (這里是有線程優(yōu)化的處理的)

這段代碼實(shí)現(xiàn)了一個(gè)基于Spring和WebSocket的異步問答系統(tǒng)。主要的邏輯如下:

在并發(fā)場景下,這樣優(yōu)化的優(yōu)勢在于:

這一段代碼是可以應(yīng)用在其他使用WebSocket連接ai的業(yè)務(wù)上的

是基于WebSocket的與遠(yuǎn)程服務(wù)進(jìn)行問答的功能。主要的邏輯如下:

最后 就是鑒權(quán)方法 這個(gè)內(nèi)容 作為api的調(diào)用者? 我們是不需要理解的(并不影響使用),當(dāng)然如果對網(wǎng)絡(luò)協(xié)議以及加密感興趣的伙伴可以細(xì)看 我就直接放上來了,因?yàn)槊考夜镜蔫b權(quán)方法都不一樣,而且文檔中會(huì)直接給出鑒權(quán)方法 直接復(fù)制到代碼里面就可以的

實(shí)現(xiàn)效果?

如果朋友對定向提示詞工程有興趣的話可以專門出一期這個(gè)模塊的博客

提示詞工程主要的優(yōu)勢在于以下:


從零開始 搭建一個(gè)Spring boot程序

  1. 確保你已經(jīng)安裝了Java開發(fā)工具(JDK)。你可以在命令行中輸入java -version來驗(yàn)證是否已安裝Java,并確保版本符合Spring Boot的要求。


    【Spring boot實(shí)戰(zhàn)】Springboot+對話ai模型整體框架+高并發(fā)線程機(jī)制處理優(yōu)化+提示詞工程效果展示(按照框架自己修改可對接市面上百分之99的模型),java Spring后端項(xiàng)目實(shí)戰(zhàn) 所遇問題及解決方案,《Spring 狂野之旅:底層原理高級進(jìn)階》 ??,spring boot,后端,java,ai
    安裝的部分我就不演示了默認(rèn)大家已經(jīng)裝好配置好環(huán)境
    ?

  2. 創(chuàng)建一個(gè)新的Spring Boot項(xiàng)目。你可以使用
    【Spring boot實(shí)戰(zhàn)】Springboot+對話ai模型整體框架+高并發(fā)線程機(jī)制處理優(yōu)化+提示詞工程效果展示(按照框架自己修改可對接市面上百分之99的模型),java Spring后端項(xiàng)目實(shí)戰(zhàn) 所遇問題及解決方案,《Spring 狂野之旅:底層原理高級進(jìn)階》 ??,spring boot,后端,java,ai

    新建一個(gè)Springboot項(xiàng)目
    【Spring boot實(shí)戰(zhàn)】Springboot+對話ai模型整體框架+高并發(fā)線程機(jī)制處理優(yōu)化+提示詞工程效果展示(按照框架自己修改可對接市面上百分之99的模型),java Spring后端項(xiàng)目實(shí)戰(zhàn) 所遇問題及解決方案,《Spring 狂野之旅:底層原理高級進(jìn)階》 ??,spring boot,后端,java,ai

我這里選了Springboot版本2.6.13? 這個(gè)倒是不會(huì)有太大問題根據(jù)自己項(xiàng)目來就行?

【Spring boot實(shí)戰(zhàn)】Springboot+對話ai模型整體框架+高并發(fā)線程機(jī)制處理優(yōu)化+提示詞工程效果展示(按照框架自己修改可對接市面上百分之99的模型),java Spring后端項(xiàng)目實(shí)戰(zhàn) 所遇問題及解決方案,《Spring 狂野之旅:底層原理高級進(jìn)階》 ??,spring boot,后端,java,ai

旁邊這些依賴自己有需要的就加 我這邊不用這里的東西就不選了?

【Spring boot實(shí)戰(zhàn)】Springboot+對話ai模型整體框架+高并發(fā)線程機(jī)制處理優(yōu)化+提示詞工程效果展示(按照框架自己修改可對接市面上百分之99的模型),java Spring后端項(xiàng)目實(shí)戰(zhàn) 所遇問題及解決方案,《Spring 狂野之旅:底層原理高級進(jìn)階》 ??,spring boot,后端,java,ai

然后出來? 他就幫我們建立好了 這些依賴跟框架了 可以在pom文件里看到

【Spring boot實(shí)戰(zhàn)】Springboot+對話ai模型整體框架+高并發(fā)線程機(jī)制處理優(yōu)化+提示詞工程效果展示(按照框架自己修改可對接市面上百分之99的模型),java Spring后端項(xiàng)目實(shí)戰(zhàn) 所遇問題及解決方案,《Spring 狂野之旅:底層原理高級進(jìn)階》 ??,spring boot,后端,java,ai

手動(dòng)添加的依賴:

在Maven里輸入:

<!-- Hutool -->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-json</artifactId>
    <version>5.7.10</version>
</dependency>

<!-- Alibaba FastJSON -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.78</version>
</dependency>

<!-- Google Gson -->
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.9</version>
</dependency>

<!-- OkHttp -->
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.9.1</version>
</dependency>

<!-- Spring Data Redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <version>2.5.4</version>
</dependency>

<!-- Spring Web -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.5.4</version>
</dependency>

然后我們新建一個(gè)class文件
在里面加入導(dǎo)包:
?

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;

配置了那么多。終于可以開始項(xiàng)目了...

統(tǒng)一封裝一下返回結(jié)果

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;
/*/**
 *@author suze
 *@date 2023-10-25
 *@time 15:19
 **/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
    private Boolean success;
    private String errorMsg;
    private Object data;
    private Long total;

    public static Result ok(){
        return new Result(true, null, null, null);
    }
    public static Result ok(Object data){
        return new Result(true, null, data, null);
    }
    public static Result ok(List<?> data, Long total){
        return new Result(true, null, data, total);
    }
    public static Result fail(String errorMsg){
        return new Result(false, errorMsg, null, null);
    }
//    public static Result fail(int  errorCode, String errorMsg){
//        return new Result(false, errorMsg, null, null);
//    }
}

然后用到的地方就導(dǎo)入Result的包即可

import TopOne.dto.Result;

?

開干:

為了方便演示我把Controller和Server放在一個(gè)文件里 大家根據(jù)自己需要去調(diào)整

1.構(gòu)建好機(jī)器人需要的常量:

public static final Gson gson = new Gson();

    // 個(gè)性化參數(shù)
    private String userId;
    private Boolean wsCloseFlag;

    private static Boolean totalFlag=true; // 控制提示用戶是否輸入

    public  List<RoleContent> historyList=new ArrayList<>(); // 這個(gè)是臨時(shí)的 每次用完在線程中要注銷他


    //寫一個(gè)結(jié)構(gòu)專門來存機(jī)器的回答
    public static class BotText{
        String content=" ";
    }
    public static BotText botText=new BotText();


    //告訴控制器輸出完沒有
    public static Boolean outputFlag=true;
    private String botContent = "";

    //返回的json結(jié)果拆解
    class JsonParse {
        Header header;
        Payload payload;
    }

    class Header {
        int code;
        int status;
        String sid;
    }

    class Payload {
        Choices choices;
    }

    class Choices {
        List<Text> text;
    }

    class Text {
        String role;
        String content;
    }
    class RoleContent{

        String role;
        String content;

        public String getRole() {
            return role;
        }

        public void setRole(String role) {
            this.role = role;
        }

        public String getContent() {
            return content;
        }

        public void setContent(String content) {
            this.content = content;
        }
    }

下面的部分就是存放對應(yīng)模型的url和Serverid以及秘鑰 這些是根據(jù)你們要選定的模型去改的

public static final String hostUrl = "";
    public static final String appid = "";
    public static final String apiSecret = "";
    public static final String apiKey = "";

存歷史記錄 以及查詢歷史記錄的方法:

我這里做的緩存是2h? 用的是Redis,一開始構(gòu)建項(xiàng)目的時(shí)候可以用一個(gè)簡單的Map來代替Redis? 自行替換掉Redis部分代碼即可

// 將對話歷史存儲(chǔ)到 Redis
    public void saveHistory(String  history,String id) {
        // 設(shè)置有效期為 2 小時(shí)
        stringRedisTemplate.opsForValue().set("id:" + id + ":history", history, 2, TimeUnit.HOURS);
    }
    @RequestMapping("/SaveHistory")
    public Result SaveHistory(@RequestParam("userId") String id, @RequestBody String history)  {
        saveHistory(history,id);
        return Result.ok("保存歷史記錄成功有效時(shí)間:2h");
    }
    // 從 Redis 中獲取對話歷史
    public List<RoleContent> getHistory(String userId) {
        String historyStr = stringRedisTemplate.opsForValue().get("id:" + userId + ":history");
        if (historyStr==null){
            return null;
        }
        return JSONUtil.toList(JSONUtil.parseArray(historyStr), RoleContent.class);
    }
    //用于獲取歷史聊天記錄
    @RequestMapping("/history")
    public Result history(@RequestParam("userId") String id)  {

        String history = stringRedisTemplate.opsForValue().get("id:" + id + ":history");
        if (history == null) {
            return Result.fail("沒有找到歷史記錄");
        }

        JSONArray jsonObject = JSON.parseArray(history);
//        String jsonString = JSON.toJSONString(jsonObject);
        return Result.ok(jsonObject);
    }

下面是獲取ai對話的回答內(nèi)容的部分 (這里是有線程優(yōu)化的處理的)

public static String totalAnswer=""; // 大模型的答案匯總

    // 可以寫原始問題
    public static  String NewQuestion = "";
    public WordUtils wordUtils=new WordUtils();
    //線程池
    public ThreadPoolExecutor pool = new ThreadPoolExecutor(13, 13, 1,
            TimeUnit.MINUTES, new ArrayBlockingQueue<>(6),
            Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
    @RequestMapping("/get")
    public DeferredResult<Result> get(@RequestParam("question") String question, @RequestParam("id") String id) {
        //創(chuàng)建了一個(gè)DeferredResult<Result>對象,并將其返回給前端。在異步任務(wù)執(zhí)行完畢后,
        // 通過調(diào)用deferredResult.setResult(result)方法將結(jié)果設(shè)置到DeferredResult對象中,從而實(shí)現(xiàn)異步返回結(jié)果給前端。
        DeferredResult<Result> deferredResult = new DeferredResult<>();
        CompletableFuture.supplyAsync(() -> {
            try {
                callable callable = new callable(question, id);
                String answer = callable.call();
                Result result = Result.ok(answer);
                
                return result;
            } catch (Exception e) {
                Result result = Result.fail(e.getMessage());
                return result;
            }
        }, pool).whenComplete((result, throwable) -> {
            if (throwable != null) {
                result = Result.fail(throwable.getMessage());
                deferredResult.setResult(result);

            } else {
                deferredResult.setResult(result);

            }
        });
        return deferredResult;
    }
    public class callable implements Callable<String>{
        private  String  id;
        private String question;
        public callable(String question,String id) {
            //這里處理一下userId的長度 因?yàn)橛嶏w那邊限制了
            if (id.length() >= 30) {
                id= id.substring(0, 30);
            }
            this.question = question;
            this.id=id;
        }
        @Override
        public String call() throws Exception {
            String answer =main(question,id);
            //System.out.println(answer);
            answer = JSONUtil.toJsonStr(answer);
            System.out.println("call");
            botText.content="";//清空
            //緩存歷史對話  時(shí)效兩小時(shí)
            //String historyStr = JSONUtil.toJsonStr();
            //stringRedisTemplate.opsForValue().set("id:"+id+":history", historyStr,2,TimeUnit.HOURS);
            return answer;
        }
    }
    // 主函數(shù)
    public String main(String newQuestion,String userid) throws Exception {
        // 個(gè)性化參數(shù)入口,如果是并發(fā)使用,可以在這里模擬
        System.out.println(totalFlag);
        if(totalFlag){
            totalFlag=false;
            NewQuestion=newQuestion;
            // 構(gòu)建鑒權(quán)url
            String authUrl = getAuthUrl(hostUrl, apiKey, apiSecret);
            OkHttpClient client = new OkHttpClient.Builder().build();
            String url = authUrl.toString().replace("http://", "ws://").replace("https://", "wss://");
         
            Request request = new Request.Builder().url(url).build();
            totalAnswer="";
//                    WebSocket webSocket = client.newWebSocket(request, new BigModelNew(i + "",false));
            //這里創(chuàng)建了大模型的新對象  實(shí)際上那些發(fā)送請求獲取答案的操作都是在這個(gè)線程中做的

            BigModelNew bigModelNew = null;
            if (getHistory(userid)!=null){
                bigModelNew=new BigModelNew(userid, false,getHistory(userid),stringRedisTemplate);
            }
            else {
                bigModelNew=new BigModelNew(userid, false,historyList,stringRedisTemplate);
            }
            // 等待 WebSocket 的 run() 方法執(zhí)行完畢
            int maxWaitTime = 10000; // 最大等待時(shí)間,單位:毫秒
            int currentWaitTime = 0; // 當(dāng)前已等待的時(shí)間,單位:毫秒
            int waitInterval = 1000;// 每次等待的時(shí)間間隔,單位:毫秒
            WebSocket webSocket = client.newWebSocket(request, bigModelNew);
            System.out.println(maxWaitTime);
            while (currentWaitTime < maxWaitTime) {
                if (bigModelNew.getBotContent().equals("")) {
                    // run() 方法還未執(zhí)行完畢,可以進(jìn)行一些其他操作或等待一段時(shí)間
                    Thread.sleep(waitInterval);
                    System.out.println("正在執(zhí)行線程"+Thread.currentThread().getName()+"...等待時(shí)間還剩:"+(maxWaitTime-currentWaitTime));
                    currentWaitTime += waitInterval;
                } else {
                    // run() 方法已執(zhí)行完畢,獲取 bot.content 值并進(jìn)行后續(xù)操作
                    //System.out.println("run執(zhí)行完畢");
                    return bigModelNew.getBotContent();
                    //System.out.println(botText.content);
                    // ...
                }
            }
        }
        totalFlag=true;
        return "網(wǎng)絡(luò)開了點(diǎn)小差 試試重新發(fā)送你的消息吧";
    }
    // 構(gòu)造函數(shù)
    public BigModelNew(@Value("${userId}") String userId
            ,@Value("${wsCloseFlag}") Boolean wsCloseFlag
            ,@Value("${HistoryList}")List<RoleContent> HistoryList
            ,@Value("${stringRedisTemplate}") StringRedisTemplate stringRedisTemplate) {
        this.userId = userId;
        this.wsCloseFlag = wsCloseFlag;
        this.historyList=HistoryList;
        this.stringRedisTemplate = stringRedisTemplate;
    }

這段代碼實(shí)現(xiàn)了一個(gè)基于Spring和WebSocket的異步問答系統(tǒng)。主要的邏輯如下:

  1. get()方法中,接收前端傳遞的問題和id參數(shù),并創(chuàng)建一個(gè)DeferredResult<Result>對象,用于異步返回結(jié)果給前端。

  2. 通過CompletableFuture.supplyAsync()方法創(chuàng)建一個(gè)異步任務(wù),該任務(wù)會(huì)在一個(gè)線程池中執(zhí)行。

  3. 異步任務(wù)的具體邏輯在callable類的call()方法中實(shí)現(xiàn)。在該方法中,調(diào)用main()方法進(jìn)行問題回答,并將結(jié)果轉(zhuǎn)換為JSON格式。

  4. 異步任務(wù)執(zhí)行完畢后,通過deferredResult.setResult(result)方法將結(jié)果設(shè)置到DeferredResult對象中,實(shí)現(xiàn)異步返回結(jié)果給前端。

  5. main()方法中,判斷是否是并發(fā)場景下的第一個(gè)請求。如果是第一個(gè)請求,則創(chuàng)建一個(gè)WebSocket連接,并等待run()方法執(zhí)行完畢。

  6. run()方法中,通過WebSocket與遠(yuǎn)程服務(wù)進(jìn)行通信,獲取問題的回答。

  7. 在并發(fā)場景下,如果有多個(gè)請求同時(shí)到達(dá),只有第一個(gè)請求會(huì)創(chuàng)建WebSocket連接,后續(xù)的請求會(huì)等待第一個(gè)請求的回答結(jié)果,并共享同一個(gè)totalAnswer。

在并發(fā)場景下,這樣優(yōu)化的優(yōu)勢在于:

  1. 使用線程池和異步任務(wù)可以提高并發(fā)處理能力,減少請求的等待時(shí)間。通過異步任務(wù),可以將耗時(shí)的操作(如遠(yuǎn)程服務(wù)調(diào)用)放在后臺(tái)線程中執(zhí)行,而不會(huì)阻塞主線程。

  2. 使用DeferredResult對象可以實(shí)現(xiàn)異步返回結(jié)果給前端。每個(gè)請求都會(huì)得到一個(gè)獨(dú)立的DeferredResult對象,通過設(shè)置結(jié)果到該對象中,可以實(shí)現(xiàn)異步返回給前端。

  3. 在并發(fā)場景下,只有第一個(gè)請求會(huì)創(chuàng)建WebSocket連接,后續(xù)的請求會(huì)等待第一個(gè)請求的回答結(jié)果。這樣可以減少對遠(yuǎn)程服務(wù)的重復(fù)請求,節(jié)省資源和提高性能。

然后我們把外面的調(diào)用的功能構(gòu)建好了 接下來就是WebSocket內(nèi)部當(dāng)中 重寫的具體方法 下面是重寫部分的方法:
?

//一個(gè)很關(guān)鍵的函數(shù) 用于得到botContent
    public String getBotContent() {
        return botContent;
    }


    public boolean canAddHistory(){  // 由于歷史記錄最大上線1.2W左右,需要判斷是能能加入歷史

        int history_length=0;
        for(RoleContent temp:historyList){
            history_length=history_length+temp.content.length();
        }
        if(history_length>12000){
            historyList=new ArrayList<>();
            return false;
        }else{
            return true;
        }

    }

    // 線程來發(fā)送音頻與參數(shù)
    class MyThread extends Thread {
        private WebSocket webSocket;
        private  String newAnswer;
        public MyThread(WebSocket webSocket) {
            this.webSocket = webSocket;
        }

        public void run() {
            try {
                JSONObject requestJson=new JSONObject();
                JSONObject header=new JSONObject();  // header參數(shù)
                header.put("app_id",appid);
                header.put("uid",userId);//這里放userId
                JSONObject parameter=new JSONObject(); // parameter參數(shù)
                JSONObject chat=new JSONObject();
                chat.put("domain","generalv3");
                chat.put("temperature",0.6);
                chat.put("max_tokens",8192);
                parameter.put("chat",chat);
                JSONObject payload=new JSONObject(); // payload參數(shù)
                JSONObject message=new JSONObject();
                JSONArray text=new JSONArray();
                // 歷史問題獲取
                if(historyList.size()>0){
                    for(RoleContent tempRoleContent:historyList){
                        text.add(JSON.toJSON(tempRoleContent));
                    }
                }
                // 最新問題
                RoleContent roleContent=new RoleContent();
                roleContent.role="user";
                roleContent.content=NewQuestion;
                text.add(JSON.toJSON(roleContent));
//                System.err.println("text:");
                historyList.add(roleContent);
//                historyList.forEach(System.out::println);
                //saveHistory(historyList);//在這里就把歷史記錄存到Redis了 就可以清空該線程的歷史記錄List了
                //historyList.clear();
                message.put("text",text);
                payload.put("message",message);
                requestJson.put("header",header);
                requestJson.put("parameter",parameter);
                requestJson.put("payload",payload);
//                  System.err.println(requestJson); // 可以打印看每次的傳參明細(xì)
                webSocket.send(requestJson.toString());
                // 等待服務(wù)端返回完畢后關(guān)閉
                while (true) {
                    // System.err.println(wsCloseFlag + "---");
                    Thread.sleep(200);
                    if (wsCloseFlag) {
                        break;
                    }
                }
                webSocket.close(1000, "");
//                System.out.println("answer"+botText.content);
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                botContent=botText.content;
            }
        }
    }

    @Override
    public void onOpen(WebSocket webSocket, Response response) {
        super.onOpen(webSocket, response);
        //System.out.print("AI:");
        MyThread myThread = new MyThread(webSocket);
        myThread.start();
    }

    @Override
    public void onMessage(WebSocket webSocket, String text) {
        // System.out.println(userId + "用來區(qū)分那個(gè)用戶的結(jié)果" + text);
        JsonParse myJsonParse = gson.fromJson(text, JsonParse.class);
        //System.out.println("AI:" + gson.toJson(myJsonParse.payload));
        if (myJsonParse.header.code != 0) {
            System.out.println("發(fā)生錯(cuò)誤,錯(cuò)誤碼為:" + myJsonParse.header.code);
            System.out.println("本次請求的sid為:" + myJsonParse.header.sid);
            webSocket.close(1000, "");
        }
        List<Text> textList = myJsonParse.payload.choices.text;

        for (Text temp : textList) {
            //System.out.println("這里存了機(jī)器的話"+temp.content);
            botText.content=botText.content+temp.content;//這里存機(jī)器的話
            totalAnswer=totalAnswer+temp.content;
        }
        //System.out.println("answeraaaa:"+botText.content);//這里能夠打印 但是打印很多次說明他調(diào)用了很多次
//        botText.content=totalAnswer;
        if (myJsonParse.header.status == 2) {
            // 可以關(guān)閉連接,釋放資源
//            System.out.println();
//            System.out.println("*************************************************************************************");
            if(canAddHistory()){
                RoleContent roleContent=new RoleContent();
                roleContent.setRole("assistant");
                roleContent.setContent(totalAnswer);
                historyList.add(roleContent);
                //System.out.println("OnMessage:"+historyList.toString());
                //String jsonString = JSON.toJSONString(historyList, SerializerFeature.PrettyFormat);
                //history.text=jsonString;//這里已經(jīng)把歷史記錄給保存了
                //在這里答案已經(jīng)輸出完了,就應(yīng)該outputFinished = true;
//                output=botText.content;
//                myHistory=history.text;
                outputFlag=true;
                System.out.println("AI:answer"+botText.content);
            }else{
                RoleContent roleContent=new RoleContent();
                roleContent.setRole("assistant");
                roleContent.setContent(totalAnswer);
                historyList.add(roleContent);
            }
            //saveHistory(historyList);//在這里就把歷史記錄存到Redis了 就可以清空該線程的歷史記錄List了
            historyList.clear();
            wsCloseFlag = true;//只有等消息傳過來了  才能夠結(jié)束
            totalFlag=true;
        }

    }

    @Override
    public void onFailure(WebSocket webSocket, Throwable t, Response response) {
        super.onFailure(webSocket, t, response);
        if (null != response) {
            int code = response.code();
                System.out.println("onFailure code:" + code);
            try {
                System.out.println("onFailure body:" + response.body().string());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            if (101 != code) {
                System.out.println("connection failed");
                System.exit(0);
            }
        }
    }

這一段代碼是可以應(yīng)用在其他使用WebSocket連接ai的業(yè)務(wù)上的

是基于WebSocket的與遠(yuǎn)程服務(wù)進(jìn)行問答的功能。主要的邏輯如下:

  1. MyThread類是一個(gè)繼承自Thread的線程類,用于發(fā)送問答請求和接收回答。在run()方法中,首先構(gòu)建請求的JSON對象,包括頭部參數(shù)、參數(shù)和載荷參數(shù)。然后通過WebSocket發(fā)送該JSON對象。接著,在一個(gè)循環(huán)中等待服務(wù)端返回結(jié)果,并將返回的結(jié)果拼接到botText.contenttotalAnswer中。最后,關(guān)閉WebSocket連接,并將botText.content賦值給botContent。

  2. onOpen()方法在WebSocket連接建立時(shí)被調(diào)用。在該方法中,創(chuàng)建一個(gè)MyThread對象并啟動(dòng)線程。

  3. onMessage()方法在接收到WebSocket消息時(shí)被調(diào)用。該方法首先解析收到的消息,并判斷是否存在錯(cuò)誤。如果沒有錯(cuò)誤,則將回答文本拼接到botText.contenttotalAnswer中,并根據(jù)返回的狀態(tài)碼進(jìn)行相應(yīng)的處理。如果狀態(tài)碼為2,表示回答已經(jīng)完整返回,此時(shí)可以關(guān)閉連接并進(jìn)行一些后續(xù)處理,如將回答文本添加到歷史記錄中。

  4. onFailure()方法在WebSocket連接失敗時(shí)被調(diào)用。在該方法中,可以根據(jù)失敗的原因進(jìn)行相應(yīng)的處理。

最后 就是鑒權(quán)方法 這個(gè)內(nèi)容 作為api的調(diào)用者? 我們是不需要理解的(并不影響使用),當(dāng)然如果對網(wǎng)絡(luò)協(xié)議以及加密感興趣的伙伴可以細(xì)看 我就直接放上來了,因?yàn)槊考夜镜蔫b權(quán)方法都不一樣,而且文檔中會(huì)直接給出鑒權(quán)方法 直接復(fù)制到代碼里面就可以的

// 鑒權(quán)方法
    public static String getAuthUrl(String hostUrl, String apiKey, String apiSecret) throws Exception {
        URL url = new URL(hostUrl);
        // 時(shí)間
        SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
        format.setTimeZone(TimeZone.getTimeZone("GMT"));
        String date = format.format(new Date());
        // 拼接
        String preStr = "host: " + url.getHost() + "\n" +
                "date: " + date + "\n" +
                "GET " + url.getPath() + " HTTP/1.1";
//        System.err.println(preStr);
        // SHA256加密
        Mac mac = Mac.getInstance("hmacsha256");
        SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(StandardCharsets.UTF_8), "hmacsha256");
        mac.init(spec);
        byte[] hexDigits = mac.doFinal(preStr.getBytes(StandardCharsets.UTF_8));

        // Base64加密
        String sha = Base64.getEncoder().encodeToString(hexDigits);
//        System.err.println(sha);
        // 拼接
        String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", apiKey, "hmac-sha256", "host date request-line", sha);
        // 拼接地址
        HttpUrl httpUrl = Objects.requireNonNull(HttpUrl.parse("https://" + url.getHost() + url.getPath())).newBuilder().//
                addQueryParameter("authorization", Base64.getEncoder().encodeToString(authorization.getBytes(StandardCharsets.UTF_8))).//
                addQueryParameter("date", date).//
                addQueryParameter("host", url.getHost()).//
                build();

//        System.err.println(httpUrl.toString());
        return httpUrl.toString();
    }

實(shí)現(xiàn)效果?

跟一個(gè)搞小程序的朋友借了個(gè)模板 套了一下前端 目前在小程序端實(shí)現(xiàn)了

響應(yīng)的內(nèi)容:

【Spring boot實(shí)戰(zhàn)】Springboot+對話ai模型整體框架+高并發(fā)線程機(jī)制處理優(yōu)化+提示詞工程效果展示(按照框架自己修改可對接市面上百分之99的模型),java Spring后端項(xiàng)目實(shí)戰(zhàn) 所遇問題及解決方案,《Spring 狂野之旅:底層原理高級進(jìn)階》 ??,spring boot,后端,java,ai

這是獲取聊天記錄的響應(yīng):

【Spring boot實(shí)戰(zhàn)】Springboot+對話ai模型整體框架+高并發(fā)線程機(jī)制處理優(yōu)化+提示詞工程效果展示(按照框架自己修改可對接市面上百分之99的模型),java Spring后端項(xiàng)目實(shí)戰(zhàn) 所遇問題及解決方案,《Spring 狂野之旅:底層原理高級進(jìn)階》 ??,spring boot,后端,java,ai

具體的業(yè)務(wù)我還做了提示詞工程,讓ai具備一點(diǎn)定向場景的傾向了,就像如下

具體的業(yè)務(wù)截圖回應(yīng)效果

【Spring boot實(shí)戰(zhàn)】Springboot+對話ai模型整體框架+高并發(fā)線程機(jī)制處理優(yōu)化+提示詞工程效果展示(按照框架自己修改可對接市面上百分之99的模型),java Spring后端項(xiàng)目實(shí)戰(zhàn) 所遇問題及解決方案,《Spring 狂野之旅:底層原理高級進(jìn)階》 ??,spring boot,后端,java,ai

如果朋友對定向提示詞工程有興趣的話可以專門出一期這個(gè)模塊的博客

提示詞工程主要的優(yōu)勢在于以下:

  1. 提高問答準(zhǔn)確性:通過給用戶提供定向場景的提示詞,可以引導(dǎo)用戶在特定領(lǐng)域或場景下提問。這樣做可以減少模糊或不相關(guān)的問題,從而提高問答的準(zhǔn)確性。提示詞可以限制用戶的問題范圍,使得AI能夠更好地理解用戶的意圖并給出相關(guān)的回答。

  2. 加速問題解決:定向場景的提示詞工程可以幫助用戶快速定位到他們感興趣的領(lǐng)域或問題類型,并提供相關(guān)的問題模板或關(guān)鍵詞。這樣可以節(jié)省用戶在描述問題上的時(shí)間和精力,使得問題能夠更快地得到解答,提高問題解決的效率。

  3. 提升用戶體驗(yàn):通過為用戶提供定向場景的提示詞,可以使用戶感到更加舒適和自信。用戶知道他們在與AI進(jìn)行交互時(shí)所處的場景,并且可以根據(jù)提示詞的指引進(jìn)行提問。這種引導(dǎo)性的交互方式可以減少用戶的迷茫和猶豫,提升用戶與AI的交互體驗(yàn)。

  4. 簡化系統(tǒng)配置:定向場景的提示詞工程可以幫助系統(tǒng)管理員或開發(fā)人員更好地配置和管理問答系統(tǒng)。通過定義和組織不同的場景和相關(guān)的提示詞,可以使系統(tǒng)的配置更加直觀和可控。管理員可以根據(jù)實(shí)際需求進(jìn)行提示詞的調(diào)整和更新,以適應(yīng)不同的應(yīng)用場景。

有興趣的小伙伴可以先關(guān)注一下我? 下一期出的話我會(huì)發(fā)粉絲通告哦文章來源地址http://www.zghlxwxcb.cn/news/detail-826757.html

到了這里,關(guān)于【Spring boot實(shí)戰(zhàn)】Springboot+對話ai模型整體框架+高并發(fā)線程機(jī)制處理優(yōu)化+提示詞工程效果展示(按照框架自己修改可對接市面上百分之99的模型)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包