基于deepseek的智能語音客服【第二講】后端異步接口調用封裝

本篇內容主要講前端請求(不包含)訪問后端服務接口,接口通過檢索知識庫,封裝提示詞,調用deepseek的,并返回給前端的全過程,非完整代碼,不可直接運行。

1.基于servlet封裝異步請求

為什么要進行異步分裝?因為前段需要流式輸出,以減少用戶長時間等待造成的不良體驗

集成HttpServlet 實現POST方法,get方式多倫對話有數據了限制

@WebServlet(urlPatterns = "/ds",asyncSupported = true // 啟用異步支持
)
public class DeepseekApi extends HttpServlet 

2.設置跨域(如果沒有前后端分離可以忽略此步驟)

		response.setHeader("Access-Control-Allow-Origin", "*");response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");response.setHeader("Access-Control-Max-Age", "3600");response.setHeader("Access-Control-Allow-Headers", "x-requested-with, Content-Type");response.setHeader("Access-Control-Allow-Credentials", "true");// 設置SSE頭response.setContentType("text/event-stream");response.setCharacterEncoding("UTF-8");response.setHeader("Cache-Control", "no-cache");response.setHeader("Connection", "keep-alive");// 處理OPTIONS預檢請求if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {response.setStatus(HttpServletResponse.SC_OK);asyncContext.complete();return;}

3.獲取參數

我這里前段直接封裝好多輪對話參數和當前問題,當前問題為什么要分開,應為問題需要在知識庫做增強檢索,這樣好取參數

 // 獲取問題參數String question = request.getParameter("question");String his = request.getParameter("his");

4.封裝異步任務

asyncContext

 // 獲取異步上下文final AsyncContext asyncContext = request.startAsync();asyncContext.setTimeout(3*60*1000); // 超時 60 秒writer = response.getWriter();processRequest(asyncContext, writer, question,his);

5.設置異步事件監聽

 asyncContext.addListener(new AsyncListener() {@Overridepublic void onComplete(AsyncEvent event) {// 確保資源釋放}@Overridepublic void onTimeout(AsyncEvent event) {writer.write("event:error\ndata:請求超時\n\n");writer.flush();asyncContext.complete();}@Overridepublic void onError(AsyncEvent event) {asyncContext.complete();}@Overridepublic void onStartAsync(AsyncEvent event) {}});

6.檢索向量庫

   // 檢索向量庫List<Map<String, Object>> kl = KnowledgeBaseService.searchKnowledge(question, 40);

7.構建提示詞

 private static String buildPrompt(String question, List<Map<String, Object>> knowledge) {System.out.println("提示詞封裝!");String txtString="";for (Map<String, Object> map : knowledge) {txtString+=map.get("title")+"\n"+map.get("text")+"\n";}return "問題:\n" + question + "\n\n參考知識:" +txtString+ "\n\n請以參考知識為主,給出簡明扼要的回復,如果參考知識與問題沒有相關性或不存在請拒絕答復:";}

8.構建請求體

  // 新的對話內容JSONObject newMessage = new JSONObject();newMessage.put("role", "user");newMessage.put("content", prompt);// 插入新的對話messages.add(newMessage);System.out.println(messages.toJSONString());// 構建請求體Map<String, String> headers = new HashMap<>();headers.put("Authorization", "Bearer " + Consist.DEEPSEEK_API_KEY);headers.put("Content-Type", "application/json");JSONObject requestBody = new JSONObject();requestBody.put("model", Consist.MODEL_NAME);requestBody.put("messages", messages);requestBody.put("stream", true);requestBody.put("max_tokens", Consist.MAX_TOKENS);

9.進行異步調用

sendAsyncRequestWithCallback(Consist.DEEPSEEK_API_URL,headers,requestBody.toJSONString(),new StreamCallback() {@Overridepublic void onDataReceived(String content) {
//                    	System.out.print(content);writer.write("data:" + content+"\n\n");writer.flush();}@Overridepublic void onComplete() {System.out.println("調用完成!");writer.write("event:done\ndata:\n\n");writer.flush();asyncContext.complete();}@Overridepublic void onError(Exception ex) {
//                    	ex.printStackTrace();System.err.println("報錯!");writer.write("event:error\ndata:發生錯誤\n\n");writer.flush();asyncContext.complete();}});

10.監聽調用狀態,防止客戶端掉線造成的異常

  if (asyncClient == null || !asyncClient.isRunning()) {synchronized (DeepseekR1WebApiPost.class) {if (asyncClient == null || !asyncClient.isRunning()) {try {if (asyncClient != null) {asyncClient.close();}asyncClient = HttpAsyncClients.createDefault();asyncClient.start();} catch (IOException e) {e.printStackTrace();}}}}

11.封裝客戶端參數,調用deepseek官網接口

 HttpPost request = new HttpPost(new URI(url));request.setEntity(new StringEntity(requestBody, "UTF-8"));headers.forEach(request::setHeader);HttpHost target = new HttpHost(new URI(url).getHost(),new URI(url).getPort(),new URI(url).getScheme());

12.執行異步請求,并處理返回數據

   @Overrideprotected void onContentReceived(ContentDecoder decoder, IOControl ioctrl) {try {ByteBuffer bb = ByteBuffer.allocate(Consist.MAX_TOKENS);int read;while ((read = decoder.read(bb)) > 0) {bb.flip();byte[] bytes = new byte[bb.remaining()];bb.get(bytes);buffer.write(bytes);processBuffer(callback);bb.clear();}} catch (Exception e) {e.printStackTrace();System.out.println("報錯: " + e.getMessage().toString());callback.onError(e);}}

13.解析流式數據返回給前端

 private void processBuffer(StreamCallback callback) throws Exception {String chunk = buffer.toString("UTF-8");buffer.reset();// 按行分割并過濾空行String[] lines = chunk.split("\\r?\\n");for (String line : lines) {if (line.isEmpty()) continue;if (line.startsWith("data: ")) {String jsonStr = line.substring(6).trim();if ("[DONE]".equals(jsonStr)) {callback.onComplete();return; // 提前返回避免后續處理}try {if(isJsonComplete(jsonStr)) {JsonObject responseJson = JsonParser.parseString(jsonStr).getAsJsonObject();JsonArray choices = responseJson.getAsJsonArray("choices");callback.onDataReceived(choices.toString());};
//                             // callback.onDataReceived(jsonStr);} catch (Exception e) {callback.onError(new RuntimeException("解析 JSON 失敗: " + jsonStr, e));continue;}}}}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/74123.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/74123.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/74123.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

歸并排序的思路與實現

歸并排序主要是兩大模塊 分治 和 合并 即將已有序的子序列合并&#xff0c;得到完全有序的序列&#xff1b;即先使每個子序列有序&#xff0c;再使子序列段間有序。若將兩個有序表合并成一個有序表&#xff0c;稱為二路歸并 由于使用了新的數組 那么空間復雜度就為O(n) 但這…

Word中公式自動標號帶章節編號

&#xff08;1&#xff09;插入一行三列的表格&#xff0c;設置寬度分別為0.5&#xff0c;13.39和1.5&#xff0c;設置縱向居中&#xff0c;中間列居中對齊&#xff0c;最右側列靠右對齊&#xff0c;設置段落如下 &#xff08;2&#xff09;插入域代碼 【Word】利用域代碼快速實…

阿里云服務器環境部署 四 MySQL主從配置

安裝MySQL 導入mysql鏡像 docker load -i /opt/dockerinstall/mysql/mysql-8.1.0.tar docker run --privilegedtrue --name mysql8 --restartunless-stopped -e MYSQL_ROOT_PASSWORD123456 -p 3306:3306 -v /usr/local/mysql/logs:/var/log/mysql -v /usr/local/mysql/d…

[RH342]iscsi配置與排錯

[RH342]iscsi配置與排錯 1. 服務端配置1.1 安裝targetcli1.2 準備磁盤1.3 服務端配置1.4 防火墻配置 2. 客戶端配置2.1 安裝客戶端軟件2.2 配置客戶端2.3 連接登錄服務端2.4 掛載使用 3. 安全驗證擴展3.1 服務端3.2 客戶端 4. 常見的排錯點4.1 服務端常見錯誤4.2 客戶端常見錯誤…

服裝零售行業數字化時代的業務與IT轉型規劃P111(111頁PPT)(文末有下載方式)

服裝零售行業數字化時代的業務與IT轉型規劃P111 詳細資料請看本解讀文章的最后內容。 隨著數字化技術的迅猛發展&#xff0c;服裝零售行業正經歷著前所未有的變革。本文將對《服裝零售行業數字化時代的業務與IT轉型規劃P111》進行詳細解讀&#xff0c;探討未來幾年內該行業的…

基于javaweb的SSM+Maven寵物領養寵物商城流浪動物管理系統與實現(源碼+文檔+部署講解)

技術范圍&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬蟲、數據可視化、小程序、安卓app、大數據、物聯網、機器學習等設計與開發。 主要內容&#xff1a;免費功能設計、開題報告、任務書、中期檢查PPT、系統功能實現、代碼編寫、論文編寫和輔導、論…

PostgreSQL 數據庫中導入大量數據

在 PostgreSQL 數據庫中導入大量數據,可根據數據來源和格式選擇不同的方法。以下為你詳細介紹幾種常見的方式: 1. 使用 COPY 命令(適用于本地數據文件) COPY 命令是 PostgreSQL 內置的高效數據導入工具,適合處理本地的數據文件。 步驟 準備數據文件 確保你的數據文件格…

C++語法之命名空間二

A.h頭文件中代碼&#xff1a; namespace a {void 輸出(); }; A.cpp源文件中代碼&#xff1a; #include <iostream> #include "A.h" void a::輸出() {std::cout << "A.h里的輸出函數" << std::endl; } B.h頭文件中代碼&#xff1a; …

基于FPGA的DDS連續FFT 仿真驗證

基于FPGA的 DDS連續FFT 仿真驗證 1 摘要 本文聚焦 AMD LogiCORE IP Fast Fourier Transform (FFT) 核心,深入剖析其在 FPGA 設計中的應用。該 FFT 核心基于 Cooley - Tukey 算法,具備豐富特性,如支持多種數據精度、算術類型及靈活的運行時配置。文中詳細介紹了其架構選項、…

美團Leaf分布式ID生成器使用教程:號段模式與Snowflake模式詳解

引言 在分布式系統中&#xff0c;生成全局唯一ID是核心需求之一。美團開源的Leaf提供了兩種分布式ID生成方案&#xff1a;號段模式&#xff08;高可用、依賴數據庫&#xff09;和Snowflake模式&#xff08;高性能、去中心化&#xff09;。本文將手把手教你如何配置和使用這兩種…

Swift 并發任務的協作式取消

在 Swift 并發&#xff08;Swift Concurrency&#xff09;中&#xff0c;任務&#xff08;Task&#xff09;不會被強行終止&#xff0c;而是采用**協作式取消&#xff08;cooperative cancellation&#xff09;**機制。這意味著任務會被標記為“已取消”&#xff0c;但是否真正…

大數據(1.1)紐約出租車大數據分析實戰:從Hadoop到Azkaban的全鏈路解析與優化

目錄 一、背景與數據價值? ?二、技術選型與組件分工? ?三、數據準備與預處理? 四、實戰步驟詳解? ?1. 數據上傳至HDFS ?2. Hive數據建模與清洗? 4?.2.1 建表語句&#xff08;分區表按年份&#xff09;?&#xff1a; ?4?.2.2 數據清洗&#xff08;剔除無效…

代碼隨想錄刷題day50|(回溯算法篇)131.分割回文串▲

目錄 一、回溯算法基礎知識 二、分割回文串思路 2.1 如何切割 2.2 判斷回文 2.3 回溯三部曲 2.4 其他問題 三、相關算法題目 四、總結 一、回溯算法基礎知識 詳見&#xff1a;代碼隨想錄刷題day46|&#xff08;回溯算法篇&#xff09;77.組合-CSDN博客 二、分割回文…

VS Code PowerShell、Windows PowerShell、CMD 的區別與聯系

VS Code PowerShell、Windows PowerShell、CMD 的區別與聯系? VS Code PowerShell、Windows PowerShell、CMD 的區別與聯系&#xff1a; 一、核心概念對比 名稱 全稱 類型 定位 VS Code PowerShell Visual Studio Code PowerShell 代碼編輯器集成終端 開發/腳本編寫…

關于Unity的CanvasRenderer報錯

MissingReferenceException: The object of type ‘CanvasRenderer’ has been destroyed but you are still trying to access it. Your script should either check if it is null or you should not destroy the object. UnityEngine.UI.GraphicRaycaster.Raycast (UnityEng…

C++編譯流程

編譯器其實就是一個翻譯器&#xff0c;把我們的文件內容翻譯成機器能夠看懂的指令&#xff0c;但如何合理翻譯是核心。 C語言編譯 需要經過以下幾步&#xff1a; 詞法分析&#xff1a;掃描代碼&#xff0c;確定單詞類型&#xff0c;比如是變量還是函數&#xff0c;是標識符還…

python學智能算法(八)|決策樹

【1】引言 前序學習進程中&#xff0c;已經對KNN鄰近算法有了探索&#xff0c;相關文章鏈接為&#xff1a; python學智能算法&#xff08;七&#xff09;|KNN鄰近算法-CSDN博客 但KNN鄰近算法有一個特點是&#xff1a;它在分類的時候&#xff0c;不能知曉每個類別內事物的具…

使用 OpenCV 拼接進行圖像處理對比:以形態學操作為例

圖像處理在計算機視覺中起著至關重要的作用&#xff0c;而 OpenCV 作為一個強大的圖像處理庫&#xff0c;提供了豐富的函數來實現各類圖像處理任務。形態學操作&#xff08;Morphological Operations&#xff09;是其中常用的技術&#xff0c;尤其適用于二值圖像的處理。常見的…

版本控制器Git ,Gitee如何連接Linux Gitee和Github區別

&#x1f4d6; 示例場景 假設你和朋友在開發一個「在線筆記網站」&#xff0c;代碼需要頻繁修改和協作&#xff1a; 只用本地文件管理 每次修改后手動復制文件&#xff0c;命名為 v1.html、v2.html 問題&#xff1a;無法追蹤具體改動內容&#xff1b;多人修改易沖突&#xff1…

使用DeepSeek翻譯英文科技論文,以MarkDown格式輸出,使用Writage 3.3.1插件轉換為Word文件

一、使用DeepSeek翻譯英文科技論文&#xff0c;以MarkDown格式輸出 以科技論文“Electrical Power System Sizing within the Numerical Propulsion System Simulation”為例。 關于Writage 3.3.1的進一步了解&#xff0c;可發送郵件至郵箱pyengine163.com. 首先&#xff0c;打…