微软云语音识别ASR示例Demo

对象存储服务 OSS 对应 Azure Blob Storage

语音识别 ASR 对应 Azure Speech-to-Text

语音合成 TTS 对应 Azure Text-to-Speech

上传..mp3文件或者上传OSS地址 返回音频的文字示例demo

依赖

复制代码
<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--   microsoft ASR     -->
        <dependency>
            <groupId>com.microsoft.cognitiveservices.speech</groupId>
            <artifactId>client-sdk</artifactId>
            <version>1.43.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

代码 在application.properties或者yaml中配置key和endpoint

复制代码
package com.example.microsoftasr.controller;

import com.microsoft.cognitiveservices.speech.*;
import com.microsoft.cognitiveservices.speech.audio.AudioConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.net.URI;
import java.nio.file.Files;

@RestController
@RequestMapping("/asr")
public class TestController {

    @Value("${azure.speech.key}")
    private String speechKey;

    @Value("${azure.speech.endpoint}")
    private String speechEndpoint;

    @GetMapping("/hello")
    public String test() {
        return "Hello World";
    }

    @PostMapping("/recognize")
    public String recognize(@RequestParam(value = "file", required = false) MultipartFile file,
                            @RequestParam(value = "url", required = false) String ossUrl) {
        if ((file == null || file.isEmpty()) && (ossUrl == null || ossUrl.isBlank())) {
            return "未提供音频文件或音频地址";
        }

        File tempInput = null;
        File tempWav = null;

        try {
            // 1. 保存临时原始音频
            if (file != null && !file.isEmpty()) {
                String suffix = getSuffix(file.getOriginalFilename());
                tempInput = File.createTempFile("audio-input-", "." + suffix);
                file.transferTo(tempInput);
            } else {
                String suffix = getSuffix(ossUrl);
                tempInput = File.createTempFile("audio-input-", "." + suffix);
                try (var in = new java.net.URL(ossUrl).openStream()) {
                    Files.copy(in, tempInput.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
                }
            }

            // 2. 转换成 WAV(16kHz 单声道)
            tempWav = File.createTempFile("audio-output-", ".wav");
            if (!getSuffix(tempInput.getName()).equalsIgnoreCase("wav")) {
                ProcessBuilder pb = new ProcessBuilder(
                        "F:\\ffmpeg-7.1.1-full_build\\ffmpeg-7.1.1-full_build\\bin\\ffmpeg.exe", "-y",
                        "-i", tempInput.getAbsolutePath(),
                        "-ar", "16000",
                        "-ac", "1",
                        tempWav.getAbsolutePath()
                );
                Process process = pb.inheritIO().start();
                int exitCode = process.waitFor();
                if (exitCode != 0) return "ffmpeg 转换失败,exitCode=" + exitCode;
            } else {
                Files.copy(tempInput.toPath(), tempWav.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
            }

            // 3. 调用微软 ASR 识别
            SpeechConfig speechConfig = SpeechConfig.fromEndpoint(new URI(speechEndpoint), speechKey);
            speechConfig.setSpeechRecognitionLanguage("zh-CN");

            try (AudioConfig audioConfig = AudioConfig.fromWavFileInput(tempWav.getAbsolutePath());
                 SpeechRecognizer recognizer = new SpeechRecognizer(speechConfig, audioConfig)) {
                SpeechRecognitionResult result = recognizer.recognizeOnceAsync().get();
                if (result.getReason() == ResultReason.RecognizedSpeech) {
                    return result.getText();
                } else {
                    return "识别失败: " + result.getReason();
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
            return "识别异常: " + e.getMessage();
        } finally {
            try {
                if (tempInput != null) Files.deleteIfExists(tempInput.toPath());
                if (tempWav != null) Files.deleteIfExists(tempWav.toPath());
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    private String getSuffix(String filenameOrUrl) {
        if (filenameOrUrl == null || !filenameOrUrl.contains(".")) return "tmp";
        return filenameOrUrl.substring(filenameOrUrl.lastIndexOf('.') + 1);
    }

}
相关推荐
Dcs18 分钟前
你的 Prompt 都该重写?
人工智能·ai编程
木卫二号Coding22 分钟前
第五十三篇-Ollama+V100+Qwen3:4B-性能
人工智能
飞哥数智坊25 分钟前
AI 不只是聊天:聊聊我最近在做的新方向
人工智能
学生高德1 小时前
小模型结合大模型的加速方法关键笔记
人工智能·深度学习·机器学习
蓝耘智算1 小时前
GPU算力租赁与算力云平台选型指南:从需求匹配到成本优化的实战思路
大数据·人工智能·ai·gpu算力·蓝耘
liliangcsdn1 小时前
如何用bootstrap模拟估计pass@k
大数据·人工智能·bootstrap
dagouaofei1 小时前
AI生成个性化年终总结PPT
人工智能·python·powerpoint
机器之心2 小时前
登顶SuperCLUE DeepSearch,openPangu-R-72B深度搜索能力跃升
人工智能·openai
DMD1682 小时前
AI赋能旅游与酒店业:技术逻辑与开发实践解析
大数据·人工智能·信息可视化·重构·旅游·产业升级
TG:@yunlaoda360 云老大2 小时前
谷歌云AI 时代的算力革命:CPU、GPU 到 TPU 的架构与定位解析
人工智能·架构·googlecloud