大模型項目:普通藍牙音響接入DeepSeek,解鎖語音交互新玩法

本文附帶視頻講解

【代碼宇宙019】技術方案:藍牙音響接入DeepSeek,解鎖語音交互新玩法_嗶哩嗶哩_bilibili


目錄

效果演示

核心邏輯

技術實現

大模型對話(技術: LangChain4j 接入 DeepSeek)

語音識別(技術:阿里云-實時語音識別)

語音生成(技術:阿里云-語音生成)

效果演示

核心邏輯

技術實現

大模型對話(技術: LangChain4j 接入 DeepSeek)

常用依賴都在這里(不是最簡),DeepSeek 目前沒有單獨的依賴,用 open-ai 協議的依賴可以兼容,官網這里有說明:OpenAI Official SDK | LangChain4j

<dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j-open-ai</artifactId><version>1.0.0-beta3</version>
</dependency>
<dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j</artifactId><version>1.0.0-beta3</version>
</dependency>
<dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j-spring-boot-starter</artifactId><version>1.0.0-beta3</version>
</dependency>

請求 ds 的核心類

package ai.voice.assistant.client;/*** @Author:超周到的程序員* @Date:2025/4/25*/import ai.voice.assistant.config.DaemonProcess;
import ai.voice.assistant.service.llm.BaseChatClient;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.SystemMessage;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.model.chat.response.ChatResponse;
import dev.langchain4j.model.chat.response.StreamingChatResponseHandler;
import dev.langchain4j.model.openai.OpenAiStreamingChatModel;import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;import com.alibaba.fastjson.JSON;@Component("deepSeekStreamClient")
public class DeepSeekStreamClient implements BaseChatClient {private static final Logger LOGGER = LogManager.getLogger(DeepSeekStreamClient.class);@Value("${certificate.llm.deepseek.key}")private String key;@Overridepublic String chat(String question) {if (question.isBlank()) {return "";}OpenAiStreamingChatModel model = OpenAiStreamingChatModel.builder().baseUrl("https://api.deepseek.com").apiKey(key).modelName("deepseek-chat").build();List<ChatMessage> messages = new ArrayList<>();messages.add(SystemMessage.from(prompt));messages.add(UserMessage.from(question));CountDownLatch countDownLatch = new CountDownLatch(1);StringBuilder answerBuilder = new StringBuilder();model.chat(messages, new StreamingChatResponseHandler() {@Overridepublic void onPartialResponse(String answerSplice) {// 語音生成(流式)//                voiceGenerateStreamService.process(new String[] {answerSplice});
//                System.out.println("== answerSplice: " + answerSplice);answerBuilder.append(answerSplice);}@Overridepublic void onCompleteResponse(ChatResponse chatResponse) {countDownLatch.countDown();}@Overridepublic void onError(Throwable throwable) {LOGGER.error("chat ds error, messages:{} err:", JSON.toJSON(messages), throwable);}});try {countDownLatch.await();} catch (InterruptedException e) {throw new RuntimeException(e);}String answer = answerBuilder.toString();LOGGER.info("chat ds end, answer:{}", answer);return answer;}
}

語音識別(技術:阿里云-實時語音識別)

開發參考_智能語音交互(ISI)-阿里云幫助中心

開發日志記錄——

這里在我的場景下遇到了會話斷連的問題:

  • 問題場景:阿里的實時語音識別,第一次對話后 10s 如果不說話那么會斷開連接(阿里側避免過多無用連接占用),本次做的藍牙音響訴求是讓他一直保活不斷開,有需要就和它對話并且不想要喚醒詞
  • 解決方式:因此這里用了 catch 斷連異常后再次執行監聽方法的方式來兼容這個問題,其實也可以定時發送一個空包過去,但是那樣不確定會不會額外增加費用,另外也要處理同時發送空包和人進行語音對話的問題,最終生成的音頻文件播放哪個的順序問題

<dependency><groupId>com.alibaba.nls</groupId><artifactId>nls-sdk-tts</artifactId><version>${ali-vioce-sdk.version}</version>
</dependency>
<dependency><groupId>com.alibaba.nls</groupId><artifactId>nls-sdk-transcriber</artifactId><version>${ali-vioce-sdk.version}</version>
</dependency>

package ai.voice.assistant.service.voice;import ai.voice.assistant.config.VoiceConfig;
import ai.voice.assistant.service.llm.BaseChatClient;
import ai.voice.assistant.util.WavPlayerUtil;
import com.alibaba.nls.client.protocol.Constant;
import com.alibaba.nls.client.protocol.InputFormatEnum;
import com.alibaba.nls.client.protocol.NlsClient;
import com.alibaba.nls.client.protocol.SampleRateEnum;
import com.alibaba.nls.client.protocol.asr.SpeechTranscriber;
import com.alibaba.nls.client.protocol.asr.SpeechTranscriberListener;
import com.alibaba.nls.client.protocol.asr.SpeechTranscriberResponse;
import jakarta.annotation.PreDestroy;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.TargetDataLine;/*** @Author:超周到的程序員* @Date:2025/4/23 此示例演示了從麥克風采集語音并實時識別的過程* (僅作演示,需用戶根據實際情況實現)*/
@Service
public class VoiceRecognitionService {private static final Logger LOGGER = LoggerFactory.getLogger(VoiceRecognitionService.class);@Autowiredprivate NlsClient client;@Autowiredprivate VoiceConfig voiceConfig;@Autowiredprivate VoiceGenerateService voiceGenerateService;@Autowired
//    @Qualifier("deepSeekStreamClient")@Qualifier("deepSeekMemoryClient")private BaseChatClient chatClient;public SpeechTranscriberListener getTranscriberListener() {SpeechTranscriberListener listener = new SpeechTranscriberListener() {//識別出中間結果.服務端識別出一個字或詞時會返回此消息.僅當setEnableIntermediateResult(true)時,才會有此類消息返回@Overridepublic void onTranscriptionResultChange(SpeechTranscriberResponse response) {// 重要提示: task_id很重要,是調用方和服務端通信的唯一ID標識,當遇到問題時,需要提供此task_id以便排查LOGGER.info("name: {}, status: {}, index: {}, result: {}, time: {}",response.getName(),response.getStatus(),response.getTransSentenceIndex(),response.getTransSentenceText(),response.getTransSentenceTime());}@Overridepublic void onTranscriberStart(SpeechTranscriberResponse response) {LOGGER.info("task_id: {}, name: {}, status: {}",response.getTaskId(),response.getName(),response.getStatus());}@Overridepublic void onSentenceBegin(SpeechTranscriberResponse response) {LOGGER.info("task_id: {}, name: {}, status: {}",response.getTaskId(),response.getName(),response.getStatus());}//識別出一句話.服務端會智能斷句,當識別到一句話結束時會返回此消息@Overridepublic void onSentenceEnd(SpeechTranscriberResponse response) {LOGGER.info("name: {}, status: {}, index: {}, result: {}, confidence: {}, begin_time: {}, time: {}",response.getName(),response.getStatus(),response.getTransSentenceIndex(),response.getTransSentenceText(),response.getConfidence(),response.getSentenceBeginTime(),response.getTransSentenceTime());if (response.getName().equals(Constant.VALUE_NAME_ASR_SENTENCE_END)) {if (response.getStatus() == 20000000) {// 識別完一句話,調用大模型String answer = chatClient.chat(response.getTransSentenceText());voiceGenerateService.process(answer);WavPlayerUtil.playWavFile("/Users/zhoulongchao/Desktop/file_code/project/p_me/ai-voice-assistant/tts_test.wav");}}}//識別完畢@Overridepublic void onTranscriptionComplete(SpeechTranscriberResponse response) {LOGGER.info("task_id: {}, name: {}, status: {}",response.getTaskId(),response.getName(),response.getStatus());}@Overridepublic void onFail(SpeechTranscriberResponse response) {// 重要提示: task_id很重要,是調用方和服務端通信的唯一ID標識,當遇到問題時,需要提供此task_id以便排查LOGGER.info("語音識別 task_id: {}, status: {}, status_text: {}",response.getTaskId(),response.getStatus(),response.getStatusText());}};return listener;}public void process() {SpeechTranscriber transcriber = null;try {// 創建實例,建立連接transcriber = new SpeechTranscriber(client, getTranscriberListener());transcriber.setAppKey(voiceConfig.getAppKey());// 輸入音頻編碼方式transcriber.setFormat(InputFormatEnum.PCM);// 輸入音頻采樣率transcriber.setSampleRate(SampleRateEnum.SAMPLE_RATE_16K);// 是否返回中間識別結果transcriber.setEnableIntermediateResult(true);// 是否生成并返回標點符號transcriber.setEnablePunctuation(true);// 是否將返回結果規整化,比如將一百返回為100transcriber.setEnableITN(false);//此方法將以上參數設置序列化為json發送給服務端,并等待服務端確認transcriber.start();AudioFormat audioFormat = new AudioFormat(16000.0F, 16, 1, true, false);DataLine.Info info = new DataLine.Info(TargetDataLine.class, audioFormat);TargetDataLine targetDataLine = (TargetDataLine) AudioSystem.getLine(info);targetDataLine.open(audioFormat);targetDataLine.start();System.out.println("You can speak now!");int nByte = 0;final int bufSize = 3200;byte[] buffer = new byte[bufSize];while ((nByte = targetDataLine.read(buffer, 0, bufSize)) > 0) {// 直接發送麥克風數據流transcriber.send(buffer, nByte);}transcriber.stop();} catch (Exception e) {LOGGER.info("語音識別 error: {}", e.getMessage());// 臨時兼容,用于保持連接在邏輯上不斷開,否則默認10s不說話會自動斷連process();} finally {if (null != transcriber) {transcriber.close();}}}@PreDestroypublic void shutdown() {client.shutdown();}
}

語音生成(技術:阿里云-語音生成)

開發參考_智能語音交互(ISI)-阿里云幫助中心

開發日志記錄——

  • 非線程安全:在調用完阿里的語音生成能力后,得到了音頻文件,和播放打通的方法是建立一個臨時文件,生成和播放都路由到這個文件,因為這個項目只是個人方便分階段單元測試用可以這么寫,如果有多個客戶端,那么這種方式就不是線程安全的
  • 回答延遲:這里我是使用的普通版的語音合成能力,初次接入支持免費體驗 3 個月,其實可以使用流式語音合成能力,是另一個 sdk,具體可見文檔:流式文本語音合成使用說明_智能語音交互(ISI)-阿里云幫助中心 因為目前流式語音合成能力需要付費,因此沒有接入流式,因此每次需要收集完 ds 大模型的回答流之后才可以進行語音生成,會有 8s 延遲

官網有 100 多種音色可以選:

<dependency><groupId>com.alibaba.nls</groupId><artifactId>nls-sdk-tts</artifactId><version>${ali-vioce-sdk.version}</version>
</dependency>
<dependency><groupId>com.alibaba.nls</groupId><artifactId>nls-sdk-transcriber</artifactId><version>${ali-vioce-sdk.version}</version>
</dependency>

package ai.voice.assistant.service.voice;import ai.voice.assistant.config.VoiceConfig;
import com.alibaba.nls.client.protocol.NlsClient;
import com.alibaba.nls.client.protocol.OutputFormatEnum;
import com.alibaba.nls.client.protocol.SampleRateEnum;
import com.alibaba.nls.client.protocol.tts.;
import com.alibaba.nls.client.protocol.tts.SpeechSynthesizerListener;
import com.alibaba.nls.client.protocol.tts.SpeechSynthesizerResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.ScheduledExecutorService;/*** @Author:超周到的程序員* @Date:2025/4/23* 語音合成API調用* 流式合成TTS* 首包延遲計算*/
@Service
public class VoiceGenerateService {private static final Logger LOGGER = LoggerFactory.getLogger(VoiceGenerateService.class);private static long startTime;@Autowiredprivate VoiceConfig voiceConfig;@Autowiredprivate NlsClient client;private static SpeechSynthesizerListener getSynthesizerListener() {SpeechSynthesizerListener listener = null;try {listener = new SpeechSynthesizerListener() {File f = new File("tts_test.wav");FileOutputStream fout = new FileOutputStream(f);private boolean firstRecvBinary = true;//語音合成結束@Overridepublic void onComplete(SpeechSynthesizerResponse response) {// TODO 當onComplete時表示所有TTS數據已經接收完成,因此這個是整個合成延遲,該延遲可能較大,未必滿足實時場景LOGGER.info("name:{} status:{} outputFile:{}", response.getStatus(), f.getAbsolutePath(), response.getName());}//語音合成的語音二進制數據@Overridepublic void onMessage(ByteBuffer message) {try {if (firstRecvBinary) {// TODO 此處是計算首包語音流的延遲,收到第一包語音流時,即可以進行語音播放,以提升響應速度(特別是實時交互場景下)firstRecvBinary = false;long now = System.currentTimeMillis();LOGGER.info("tts first latency : " + (now - VoiceGenerateService.startTime) + " ms");}byte[] bytesArray = new byte[message.remaining()];message.get(bytesArray, 0, bytesArray.length);fout.write(bytesArray);} catch (IOException e) {e.printStackTrace();}}@Overridepublic void onFail(SpeechSynthesizerResponse response) {// TODO 重要提示: task_id很重要,是調用方和服務端通信的唯一ID標識,當遇到問題時,需要提供此task_id以便排查LOGGER.info("語音合成 task_id: {}, status: {}, status_text: {}",response.getTaskId(),response.getStatus(),response.getStatusText());}@Overridepublic void onMetaInfo(SpeechSynthesizerResponse response) {
//                    System.out.println("MetaInfo event:{}" + response.getTaskId());}};} catch (Exception e) {e.printStackTrace();}return listener;}public void process(String text) {SpeechSynthesizer synthesizer = null;try {//創建實例,建立連接synthesizer = new SpeechSynthesizer(client, getSynthesizerListener());synthesizer.setAppKey(voiceConfig.getAppKey());//設置返回音頻的編碼格式synthesizer.setFormat(OutputFormatEnum.WAV);//設置返回音頻的采樣率synthesizer.setSampleRate(SampleRateEnum.SAMPLE_RATE_16K);//發音人synthesizer.setVoice("jielidou");//語調,范圍是-500~500,可選,默認是0synthesizer.setPitchRate(50);//語速,范圍是-500~500,默認是0synthesizer.setSpeechRate(30);//設置用于語音合成的文本synthesizer.setText(text);synthesizer.addCustomedParam("enable_subtitle", true);//此方法將以上參數設置序列化為json發送給服務端,并等待服務端確認long start = System.currentTimeMillis();synthesizer.start();LOGGER.info("tts start latency " + (System.currentTimeMillis() - start) + " ms");VoiceGenerateService.startTime = System.currentTimeMillis();//等待語音合成結束synthesizer.waitForComplete();LOGGER.info("tts stop latency " + (System.currentTimeMillis() - start) + " ms");} catch (Exception e) {e.printStackTrace();} finally {//關閉連接if (null != synthesizer) {synthesizer.close();}}}public void shutdown() {client.shutdown();}
}

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

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

相關文章

qt命名空間演示

#ifndef CIR_H #define CIR_Hnamespace cir {double PI3.141592653;//獲取圓行周長double getLenthOfCircle(double radius){return 2*PI*radius;}//獲取圓形面積double getAreaOfCircle(double radius){return PI*radius*radius;}} #endif // CIR_H#include <iostream> …

使用 Java 反射動態加載和操作類

Java 的反射機制(Reflection)是 Java 語言的一大特色,它允許程序在運行時檢查、加載和操作類、方法、字段等元信息。通過 java.lang.Class 和 java.lang.reflect 包,開發者可以動態加載類、創建實例、調用方法,甚至在運行時構造新類。反射是 Java 靈活性的核心,廣泛應用于…

《 C++ 點滴漫談: 三十七 》左值?右值?完美轉發?C++ 引用的真相超乎你想象!

摘要 本文全面系統地講解了 C 中的引用機制&#xff0c;涵蓋左值引用、右值引用、引用折疊、完美轉發等核心概念&#xff0c;并深入探討其底層實現原理及工程實踐應用。通過詳細的示例與對比&#xff0c;讀者不僅能掌握引用的語法規則和使用技巧&#xff0c;還能理解引用在性能…

【AutoGen深度解析】下一代AI代理編程框架實戰指南

目錄 &#x1f31f; 前言&#x1f3d7;? 技術背景與價值&#x1f6a7; 當前技術痛點&#x1f6e0;? 解決方案概述&#x1f465; 目標讀者說明 &#x1f50d; 一、技術原理剖析&#x1f5bc;? 核心概念圖解&#x1f4a1; 核心作用講解?? 關鍵技術模塊說明&#x1f504; 技術…

Python-AI調用大模型 給出大模型人格案例

Python調用通義千問模擬原神雷電將軍口吻 最近在用AI編輯器寫AI對話 嘗試給AI對話增加人格 以下是使用阿里通義千問大模型模擬《原神》中雷電將軍(雷電影)口吻的代碼案例&#xff0c;包含典型的高傲威嚴、略帶古風的說話風格。 完整后端代碼示例 import dashscope from dash…

csdn博客打賞功能

CSDN_專業開發者社區_已接入DeepSeekR1滿血版 官網: 最右下角 耳機 就是客服 可以轉人工 開啟打賞功能如下: 1.因為博主本人不可以對本人賬號文章進行打賞&#xff0c;因此本人賬號打開文章詳情頁不顯示打賞按鈕。為了驗證賬號設置的打賞功能是否生效所以讓您使用無痕模式模…

【深度學習】目標檢測算法大全

目錄 一、R-CNN 1、R-CNN概述 2、R-CNN 模型總體流程 3、核心模塊詳解 &#xff08;1&#xff09;候選框生成&#xff08;Selective Search&#xff09; &#xff08;2&#xff09;深度特征提取與微調 2.1 特征提取 2.2 網絡微調&#xff08;Fine-tuning&#xff09; …

26考研——中央處理器_指令流水線_指令流水線的基本概念 流水線的基本實現(5)

408答疑 文章目錄 六、指令流水線指令流水線的基本概念流水線的基本實現流水線設計的原則流水線的邏輯結構流水線的時空圖表示 八、參考資料鮑魚科技課件26王道考研書 六、指令流水線 前面介紹的指令都是在單周期處理機中采用串行方法執行的&#xff0c;同一時刻 CPU 中只有一…

配置集群(yarn)

在配置 YARN 集群前&#xff0c;要先完成以下準備工作&#xff1a; 集群環境規劃&#xff1a;明確各節點的角色&#xff0c;如 ResourceManager、NodeManager 等。網絡環境搭建&#xff1a;保證各個節點之間能夠通過網絡互通。時間同步設置&#xff1a;安裝 NTP 服務&#xff0…

vue實現與后臺springboot傳遞數據【傳值/取值 Axios 】

vue實現與后臺springboot傳遞數據【傳值/取值】 提示&#xff1a;幫幫志會陸續更新非常多的IT技術知識&#xff0c;希望分享的內容對您有用。本章分享的是node.js和vue的使用。前后每一小節的內容是存在的有&#xff1a;學習and理解的關聯性。【幫幫志系列文章】&#xff1a;每…

二叉樹路徑總和

一、給你二叉樹的根節點 root 和一個表示目標和的整數 targetSum 。判斷該樹中是否存在根節點到葉子節點的路徑&#xff0c;這條路徑上所有節點值相加等于目標和 targetSum 。如果存在&#xff0c;返回 true &#xff1b;否則&#xff0c;返回 false 。 112. 路徑總和 - 力扣&…

Matlab 模糊控制平行側邊自動泊車

1、內容簡介 Matlab 233-模糊控制平行側邊自動泊車 可以交流、咨詢、答疑 2、內容說明 略 3、仿真分析 略 4、參考論文 略

M0G3507完美移植江科大軟件IIC MPU6050

經過兩天兩夜的查閱文獻資料、整理學習&#xff0c;成功的把江科大的軟件IIC讀寫MPU6050移植到MSPM0G3507&#xff0c;親測有效&#xff01;&#xff01;包的&#xff0c;為了讓大家直觀地感受下&#xff0c;先上圖。記得點個贊哦&#xff01; 學過江科大的STM32的小伙伴是不是…

CI/CD與DevOps流程流程簡述(提供思路)

一 CI/CD流程詳解&#xff1a;代碼集成、測試與發布部署 引言 在軟件開發的世界里&#xff0c;CI/CD&#xff08;持續集成/持續交付&#xff09;就像是一套精密的流水線&#xff0c;確保代碼從開發到上線的整個過程高效、穩定。我作為一名資深的軟件工程師&#xff0c;接下來…

大數據基礎——Ubuntu 安裝

文章目錄 Ubuntu 安裝一、配置電腦二、安裝系統 Ubuntu 安裝 一、配置電腦 1、進入VMware 2、選擇配置類型 3、選擇硬件兼容性版本 4、當前虛擬機的操作系統 選擇“稍后安裝操作系統”&#xff08;修改&#xff09; 5、選擇虛擬機將來需要安裝的系統 選中“Linux”和選擇…

LeetCode百題刷003(449周賽一二題)

遇到的問題都有解決的方案&#xff0c;希望我的博客可以為你提供一些幫助 一、不同字符數量最多為 K 時的最少刪除數 &#xff08;哈希表空間換時間&#xff09; 不同字符數量最多為 K 時的最少刪除數 - 力扣 (LeetCode) 競賽https://leetcode.cn/contest/weekly-contest-449/…

【網安等保】OpenEuler 24.03系統主機安全加固及配置優化實踐指南

[ 知識是人生的燈塔&#xff0c;只有不斷學習&#xff0c;才能照亮前行的道路 ] &#x1f4e2; 大家好&#xff0c;我是 WeiyiGeek&#xff0c;一個正在向全棧工程師(SecDevOps)前進的計算機技術愛好者&#xff0c;歡迎各位道友一起學習交流、一起進步 &#x1f680;&#xff0…

大模型賦能:2D 寫實數字人開啟實時交互新時代

在數字化浪潮席卷全球的當下&#xff0c;人工智能技術不斷突破創新&#xff0c;其中大模型驅動的 2D 寫實數字人正成為實時交互領域的一顆新星&#xff0c;引領著行業變革&#xff0c;為人們帶來前所未有的交互體驗。 一、2D 寫實數字人概述 2D 寫實數字人是通過計算機圖形學…

Dockers部署oscarfonts/geoserver鏡像的Geoserver

Dockers部署oscarfonts/geoserver鏡像的Geoserver 說實話&#xff0c;最后發現要選擇合適的Geoserver鏡像才是關鍵&#xff0c;所以所以所以…&#x1f437; 推薦oscarfonts/geoserver的鏡像&#xff01; 一開始用kartoza/geoserver鏡像一直提示內存不足&#xff0c;不過還好…

關于解決MySQL的常見問題

一&#xff1a;MySQL輸入密碼時閃退 這有可能是因為MySQL服務沒有開啟。 打開系統配置&#xff08;直接搜索即可&#xff09;&#xff0c;查看MySQL服務是否開啟。 此時顯示的是已停止。確定是這個問題。 現在打開計算機管理&#xff08;直接搜索即可&#xff09;。 找到MyS…