最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java Springboot使用扣子Coze實(shí)現(xiàn)實(shí)時(shí)音頻對(duì)話智能客服功能

 更新時(shí)間:2025年07月23日 10:38:05   作者:普if加的帕  
公司為智能客服接入Coze平臺(tái),需開通專業(yè)版并配置Token,開發(fā)流程包括發(fā)布智能體、安裝Java SDK、實(shí)現(xiàn)WebSocket雙向流式對(duì)話,主要問(wèn)題SDK功能滯后、自動(dòng)打斷配置及工作流響應(yīng)慢,本文介紹java Springboot使用扣子Coze實(shí)現(xiàn)實(shí)時(shí)音頻對(duì)話智能客服,感興趣的朋友一起看看吧

一、背景

        因公司業(yè)務(wù)需求,需要使用智能客服實(shí)時(shí)接聽顧客電話。

        現(xiàn)在已經(jīng)完成的操作是,智能體已接入系統(tǒng)進(jìn)行對(duì)練,所以本文章不寫對(duì)聯(lián)相關(guān)的功能。只有coze對(duì)接~

        扣子提供了試用Realtime WebSocket,點(diǎn)擊右上角setting配置好智能體token之后就可以試用了

注意:只有扣子專業(yè)版支持實(shí)時(shí)音視頻,所以需要開通專業(yè)版,開發(fā)測(cè)試階段可以先充值1元買1000資源點(diǎn)對(duì)接測(cè)試, 注意超額會(huì)單獨(dú)收費(fèi)哦,

二、準(zhǔn)備工作

1、發(fā)布智能體為AI服務(wù)

        a.登陸扣子平臺(tái)注冊(cè)賬號(hào)

扣子

扣子是新一代 AI 大模型智能體開發(fā)平臺(tái)。整合了插件、長(zhǎng)短期記憶、工作流、卡片等豐富能力,扣子能幫你低門檻、快速搭建個(gè)性化或具備商業(yè)價(jià)值的智能體,并發(fā)布到豆包、飛書等各個(gè)平臺(tái)。     

https://www.coze.cn/home

  b. 在左側(cè)導(dǎo)航欄中選擇工作空間,并在頁(yè)面頂部空間列表中選擇個(gè)人空間或團(tuán)隊(duì)空間

        c. 在項(xiàng)目開發(fā)頁(yè)面,新建智能體

       d.創(chuàng)建智能體完成之后,點(diǎn)擊右上角的發(fā)布,在發(fā)布頁(yè)面,選擇API選項(xiàng),然后點(diǎn)擊發(fā)布

    c.獲取智能體ID,后續(xù)開發(fā)要用

        點(diǎn)開 工作空間->項(xiàng)目開發(fā)->你的智能體,點(diǎn)進(jìn)新建的智能體,鏈接地址后的數(shù)字則為智能體ID

2、獲取訪問(wèn)令牌

因公司業(yè)務(wù)需要經(jīng)過(guò)對(duì)比我們選用了JWT方式,開發(fā)測(cè)試階段也可以選擇個(gè)人訪問(wèn)令牌       

        a.在扣子API頁(yè)面,進(jìn)入授權(quán)-> Oauth應(yīng)用頁(yè)面->創(chuàng)建新應(yīng)用,注意客戶端類型為服務(wù)端應(yīng)用

       

        b.保存后進(jìn)行下一步授權(quán),將自動(dòng)生成的公鑰復(fù)制保存好,自動(dòng)下載的私鑰也要存儲(chǔ)好,后續(xù)接口認(rèn)證會(huì)用到!

        

3、安裝Java SDK,參考扣子官網(wǎng)

扣子

扣子是新一代 AI 大模型智能體開發(fā)平臺(tái)。整合了插件、長(zhǎng)短期記憶、工作流、卡片等豐富能力,扣子能幫你低門檻、快速搭建個(gè)性化或具備商業(yè)價(jià)值的智能體,并發(fā)布到豆包、飛書等各個(gè)平臺(tái)。

https://www.coze.cn/open/docs/developer_guides/java_installation

三、實(shí)踐開發(fā)

1、添加maven依賴

 <dependency>
            <groupId>com.coze</groupId>
            <artifactId>coze-api</artifactId>
            <version>0.3.0</version>
</dependency>
<!-- 以下非必須?。。。∥野阉借€文件放到resources下了,所以打包需要加上這個(gè)類型->
<build>
      <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.pem</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
</build>

2、獲取token

@Slf4j
@Component
public class CozeOAuth {
    /**
     * JWT鑒權(quán)token
     */
    public String getJWTToken() {
        String token = "";
        try {
            // 獲取私鑰文件
            String jwtOauthPrivateKeyFilePath = "這里是你的私鑰文件地址";
            ClassLoader classLoader = this.getClass().getClassLoader();
            java.net.URL resourceUrl = classLoader.getResource(jwtOauthPrivateKeyFilePath);
            if (resourceUrl == null) {
                log.info("私鑰資源文件未找到,{}", jwtOauthPrivateKeyFilePath);
                return token;
            }
            String jwtOauthPrivateKey = new String(
                    Files.readAllBytes(Paths.get(resourceUrl.toURI())), StandardCharsets.UTF_8);
            JWTOAuthClient oauth = new JWTOAuthClient.JWTOAuthBuilder()
                    .clientID("這里是你之前創(chuàng)建的OAuth應(yīng)用Id")
                    .privateKey(jwtOauthPrivateKey)
                    .publicKey("這里是你的公鑰")
                    .baseURL(com.coze.openapi.service.config.Consts.COZE_CN_BASE_URL)
                    .build();
            // 獲取token
            OAuthToken resp = oauth.getAccessToken();
            System.out.println(resp);
            if (Objects.nonNull(resp)) {
                token = resp.getAccessToken();
            }
        } catch (Exception e) {
            log.error("獲取coze JWT token異常!", e);
        }
        log.info("獲取coze JWT token:{}", token);
        return token;
    }
}

3、創(chuàng)建新類繼承WebsocketsChatCallbackHandler,接收扣子服務(wù)端返回消息并做業(yè)務(wù)處理

@Slf4j
public class MyWebsocketsChatCallbackHandler extends WebsocketsChatCallbackHandler {
    public void onChatCreated(WebsocketsChatClient client, ChatCreatedEvent event) {
        log.info("扣子服務(wù)端返回,對(duì)話連接成功,{}", JSON.toJSONString(event));
    }
    public void onChatUpdated(WebsocketsChatClient client, ChatUpdatedEvent event) {
        log.info("扣子服務(wù)端返回,對(duì)話配置成功,{}", JSON.toJSONString(event));
    }
    public void onConversationChatCreated(WebsocketsChatClient client, ConversationChatCreatedEvent event) {
        log.info("扣子服務(wù)端返回,對(duì)話開始,{}", JSON.toJSONString(event));
    }
    public void onConversationChatInProgress(WebsocketsChatClient client, ConversationChatInProgressEvent event) {
        log.info("扣子服務(wù)端返回,對(duì)話正在處理,{}", JSON.toJSONString(event));
    }
    public void onConversationMessageDelta(WebsocketsChatClient client, ConversationMessageDeltaEvent event) {
        log.info("扣子服務(wù)端返回,增量消息,{}", JSON.toJSONString(event));
    }
    public void onConversationAudioDelta(WebsocketsChatClient client, ConversationAudioDeltaEvent event) {
        log.info("扣子服務(wù)端返回,增量語(yǔ)音,{}", JSON.toJSONString(event));
       // TODO 處理實(shí)際業(yè)務(wù),比如返回給用戶的語(yǔ)音
    }
    public void onConversationMessageCompleted(WebsocketsChatClient client, ConversationMessageCompletedEvent event) {
        log.info("扣子服務(wù)端返回,消息完成,{}", JSON.toJSONString(event));
    }
    public void onConversationAudioCompleted(WebsocketsChatClient client, ConversationAudioCompletedEvent event) {
        log.info("扣子服務(wù)端返回,語(yǔ)音回復(fù)完成,{}", JSON.toJSONString(event));
    }
    public void onConversationChatCompleted(WebsocketsChatClient client, ConversationChatCompletedEvent event) {
        log.info("扣子服務(wù)端返回,對(duì)話完成,{}", JSON.toJSONString(event));
    }
    public void onConversationChatFailed(WebsocketsChatClient client, ConversationChatFailedEvent event) {
        log.info("扣子服務(wù)端返回,對(duì)話失敗,{}", JSON.toJSONString(event));
    }
    public void onInputAudioBufferCompleted(WebsocketsChatClient client, InputAudioBufferCompletedEvent event) {
        log.info("扣子服務(wù)端返回,流式提交的音頻完成,{}", JSON.toJSONString(event));
    }
    public void onInputAudioBufferCleared(WebsocketsChatClient client, InputAudioBufferClearedEvent event) {
        log.info("扣子服務(wù)端返回,清除緩沖區(qū)音頻成功,{}", JSON.toJSONString(event));
    }
    public void onConversationCleared(WebsocketsChatClient client, ConversationClearedEvent event) {
        log.info("扣子服務(wù)端返回,上下文清除完成,{}", JSON.toJSONString(event));
    }
    public void onConversationChatCanceled(WebsocketsChatClient client, ConversationChatCanceledEvent event) {
        log.info("扣子服務(wù)端返回,智能體輸出中斷,{}", JSON.toJSONString(event));
    }
    public void onConversationAudioTranscriptUpdate(WebsocketsChatClient client, ConversationAudioTranscriptUpdateEvent event) {
        log.info("扣子服務(wù)端返回,用戶語(yǔ)音識(shí)別字幕,{}", JSON.toJSONString(event));
    }
    public void onConversationAudioTranscriptCompleted(WebsocketsChatClient client, ConversationAudioTranscriptCompletedEvent event) {
        log.info("扣子服務(wù)端返回,用戶語(yǔ)音識(shí)別完成,{}", JSON.toJSONString(event));
    }
    public void onConversationChatRequiresAction(WebsocketsChatClient client, ConversationChatRequiresActionEvent event) {
        log.info("扣子服務(wù)端返回,端插件請(qǐng)求,{}", JSON.toJSONString(event));
    }
    public void onInputAudioBufferSpeechStarted(WebsocketsChatClient client, InputAudioBufferSpeechStartedEvent event) {
        log.info("扣子服務(wù)端返回,用戶開始說(shuō)話,{}", JSON.toJSONString(event));
    }
    public void onInputAudioBufferSpeechStopped(WebsocketsChatClient client, InputAudioBufferSpeechStoppedEvent event) {
        log.info("扣子服務(wù)端返回,用戶結(jié)束說(shuō)話,{}", JSON.toJSONString(event));
    }
    public void onClosing(WebsocketsChatClient client, int code, String reason) {
        log.info("扣子服務(wù)端返回,onClosing,code:{},reason:{}",code, reason);
    }
    public void onClosed(WebsocketsChatClient client, int code, String reason) {
        log.info("扣子服務(wù)端返回,onClosed,code:{},reason:{}", code,reason);
    }
    public void onError(WebsocketsChatClient client, ErrorEvent event) {
        log.info("扣子服務(wù)端返回,onError,event:{}", JSON.toJSONString(event));
    }
    public void onFailure(WebsocketsChatClient client, Throwable t) {
        log.info("扣子服務(wù)端返回,onFailure,event:{}", JSON.toJSONString(t));
    }
    public void onClientException(WebsocketsChatClient client, Throwable t) {
        log.info("扣子服務(wù)端返回,onFailure,event:{}", JSON.toJSONString(t.getMessage()));
    }
}

4、創(chuàng)建工具類

抽取跟業(yè)務(wù)無(wú)關(guān)的代碼到該類中

@Slf4j
@Component
public class WebSocketUtils {
    @Resource
    private CozeOAuth cozeOAuth;
    /**
     * 更新對(duì)話配置 請(qǐng)求參數(shù)
     */
    public ChatUpdateEventData initChatUpdateEventData() {
        // 對(duì)話配置
        ChatConfig chatConfig = new ChatConfig();
        chatConfig.setAutoSaveHistory(true);
        // 輸入音頻格式
        InputAudio inputAudio = new InputAudio("pcm", "g711a", 8000, 1, 16);
       PCMConfig pcmConfig = new PCMConfig(100,8000);
        // 輸出音頻格式
        OutputAudio outputAudio = new OutputAudio("pcm", pcmConfig, null, null, null);
        // 轉(zhuǎn)檢測(cè)配置
        // server_vad 模式下,VAD 檢測(cè)到語(yǔ)音之前要包含的音頻量,單位為 ms。默認(rèn)為 600ms。
        // server_vad 模式下,檢測(cè)語(yǔ)音停止的靜音持續(xù)時(shí)間,單位為 ms。默認(rèn)為 500ms
        TurnDetection turnDetection = new TurnDetection("server_vad", 300, 500);
        return cChatUpdateEventData.builder()
                .inputAudio(inputAudio)
                .outputAudio(outputAudio)
                .chatConfig(chatConfig)
                .turnDetection(turnDetection)
                .build();
    }
    public CozeAPI getCozeApi(){
        return new CozeAPI.Builder()
                .baseURL(Consts.COZE_CN_BASE_URL)
                .auth(new TokenAuth(cozeOAuth.getJWTToken()))
                .readTimeout(10000)
                .build();
    }
}

5、使用websocket雙向流式對(duì)話

我們用到了第三方的用戶進(jìn)線傳輸,直接sip協(xié)議拿包,將包傳輸給扣子,之后再將扣子的增量語(yǔ)音返回給第三方就行。所以選擇了websocket的方式

        byte[] buffer = new byte[1500];
        CozeAPI cozeAPI = webSocketUtils.getCozeApi();
        WebsocketsChatClient websocketsChatClient = cozeAPI.websockets()
                .chat()
                .create(new WebsocketsChatCreateReq("這里是你的智能體ID", new MyWebsocketsChatCallbackHandler()));
        // 更新對(duì)話配置               
        websocketsChatClient.chatUpdate(webSocketUtils.initChatUpdateEventData());
        // 此處可以根據(jù)實(shí)際業(yè)務(wù)接收語(yǔ)音流
        byte[] audioData = 
        Files.readAllBytes(Paths.get("/音頻.pcm"));
        // 流式上傳音頻片段
        websocketsChatClient.inputAudioBufferAppend(audioData);

四、踩過(guò)的的坑

1、SDK版本會(huì)落后服務(wù)端功能

        扣子提供的SDK跟接口文檔中描述的功能有部分差異,比如更新對(duì)話接口的入?yún)imit_config,在SDK中是沒(méi)有的。

        遇到這種情況則需要自己封裝參數(shù),比如繼承某個(gè)SDK的類,然后在子類中寫自己需要但是SDK沒(méi)有的參數(shù)。

2、自動(dòng)打斷功能配置

        想要實(shí)現(xiàn)自動(dòng)打斷功能,需要使用server_vad模式,并且需要配置輸出音頻的限制limit_config,限制每次服務(wù)端返回的包,否則會(huì)等服務(wù)端返回完成之后才能打斷。

3、工作流模式服務(wù)端響應(yīng)較慢

        實(shí)際應(yīng)用場(chǎng)景中會(huì)需要給智能體傳配置好的參數(shù),目前智能通過(guò)工作流的方式記住上下文,但是該模式服務(wù)端響應(yīng)在3s左右,具體還在排查問(wèn)題

到此這篇關(guān)于java Springboot使用扣子Coze實(shí)現(xiàn)實(shí)時(shí)音頻對(duì)話智能客服功能的文章就介紹到這了,更多相關(guān)springboot音頻對(duì)話智能客服內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java實(shí)現(xiàn)訂單超時(shí)未支付自動(dòng)取消的8種方法總結(jié)

    Java實(shí)現(xiàn)訂單超時(shí)未支付自動(dòng)取消的8種方法總結(jié)

    這篇文章主要為大家介紹了Java實(shí)現(xiàn)訂單超時(shí)未支付自動(dòng)取消功能的8種不同方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2022-08-08
  • Java設(shè)計(jì)模式之裝飾器模式

    Java設(shè)計(jì)模式之裝飾器模式

    這篇文章介紹了Java設(shè)計(jì)模式之裝飾器模式,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-09-09
  • Java?Base64編碼方法詳解及實(shí)例解析

    Java?Base64編碼方法詳解及實(shí)例解析

    Base64是一種用于將二進(jìn)制數(shù)據(jù)轉(zhuǎn)換成文本數(shù)據(jù)的編碼方式,在本文中,我們介紹了Base64.encodeBase64String方法的用途和功能,它是Java語(yǔ)言中用于Base64編碼的一個(gè)重要工具,需要的朋友可以參考下
    2023-09-09
  • 詳談Enumeration接口和Iterator接口的區(qū)別

    詳談Enumeration接口和Iterator接口的區(qū)別

    下面小編就為大家?guī)?lái)一篇詳談Enumeration接口和Iterator接口的區(qū)別。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-08-08
  • 解決springboot?druid數(shù)據(jù)庫(kù)連接池連接失敗后一直重連問(wèn)題

    解決springboot?druid數(shù)據(jù)庫(kù)連接池連接失敗后一直重連問(wèn)題

    這篇文章主要介紹了解決springboot?druid數(shù)據(jù)庫(kù)連接池連接失敗后一直重連問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • spring BeanProcessor接口詳解

    spring BeanProcessor接口詳解

    這篇文章主要介紹了spring BeanProcessor接口的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用spring,感興趣的朋友可以了解下
    2021-03-03
  • mybatis查詢到了數(shù)據(jù),但是實(shí)體類個(gè)別字段為null問(wèn)題

    mybatis查詢到了數(shù)據(jù),但是實(shí)體類個(gè)別字段為null問(wèn)題

    這篇文章主要介紹了mybatis查詢到了數(shù)據(jù),但是實(shí)體類個(gè)別字段為null問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • Java 實(shí)現(xiàn)緩存的三種方式及問(wèn)題匯總

    Java 實(shí)現(xiàn)緩存的三種方式及問(wèn)題匯總

    這篇文章主要介紹了Java 實(shí)現(xiàn)緩存的三種方式及問(wèn)題匯總,HashMap實(shí)現(xiàn)緩存,可以實(shí)現(xiàn)簡(jiǎn)單的本地緩存,但是實(shí)際開發(fā)中不推薦,我們可以簡(jiǎn)單模擬一下緩存的實(shí)現(xiàn),本文通過(guò)示例代碼介紹的非常詳細(xì),感興趣的朋友一起看看吧
    2024-03-03
  • websocket在springboot+vue中的使用教程

    websocket在springboot+vue中的使用教程

    這篇文章主要介紹了websocket在springboot+vue中的使用教程,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-08-08
  • JavaWeb開發(fā)之【Tomcat 環(huán)境配置】MyEclipse+IDEA配置教程

    JavaWeb開發(fā)之【Tomcat 環(huán)境配置】MyEclipse+IDEA配置教程

    這篇文章主要介紹了JavaWeb開發(fā)之【Tomcat 環(huán)境配置】MyEclipse+IDEA配置教程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-10-10

最新評(píng)論

延边| 青河县| 盐亭县| 卢氏县| 诸暨市| 永修县| 怀化市| 岳池县| 信宜市| 六安市| 大同市| 清镇市| 马尔康县| 盐城市| 抚州市| 广平县| 达日县| 两当县| 丹阳市| 萍乡市| 将乐县| 德惠市| 中卫市| 内江市| 富川| 平和县| 威海市| 深泽县| 轮台县| 淮南市| 綦江县| 通州区| 江源县| 吉首市| 泰来县| 桑日县| 深水埗区| 中宁县| 璧山县| 秦皇岛市| 商水县|