讯飞开放平台语音转写 golang实现demo

讯飞开放平台语音转写 golang实现demo:

package main

import (
	"bytes"
	"crypto/hmac"
	"crypto/md5"
	"crypto/sha1"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"time"
)

func main() {
	appId := "your appId"
	secretKey := "your secretKey"
	filePath := "upload file path"
	// 上传转写音频获取orderId
	orderId, err := upload(appId, secretKey, filePath)
	if err != nil {
		log.Fatal(err)
	}
	// 根据orderId 获取结果
	res, err := getOrderResult(appId, secretKey, orderId)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(res)

}

type uploadRes struct {
	Code     string `json:"code"`
	DescInfo string `json:"descInfo"`
	Content  struct {
		OrderId          string `json:"orderId"`          // 订单id
		TaskEstimateTime int    `json:"taskEstimateTime"` // 订单预估耗时,单位毫秒
	} `json:"content"`
}

type getOrderResultRes struct {
	Code     string `json:"code"`
	DescInfo string `json:"descInfo"`
	Content  struct {
		OrderInfo struct {
			OrderId          string `json:"orderId"`          // 订单id
			FailType         int    `json:"failType"`         // 订单失败类型,处理成功时响应0
			Status           int    `json:"status"`           // 订单流程状态
			OriginalDuration int    `json:"originalDuration"` // 上传设置音频时长,单位毫秒
			RealDuration     int    `json:"realDuration"`     // 实际处理音频时长,单位毫秒
			ExpireTime       int    `json:"expireTime"`       // 已完成订单删除时间戳,毫秒
		} `json:"orderInfo"`
		OrderResult string `json:"orderResult"` // 转写结果,json字符串
	} `json:"content"`

	TaskEstimateTime int `json:"taskEstimateTime"` // 订单预估耗时,单位毫秒
}

// upload 上传音频文件 获取订单ID
func upload(appId, secretKey, filePath string) (string, error) {
	// 获取文件名称
	fileName := filepath.Base(filePath)
	file, err := os.Open(filePath)
	if err != nil {
		return "", err
	}
	// 获取文件大小
	stat, err := file.Stat()
	if err != nil {
		return "", err
	}
	fileSize := strconv.FormatInt(stat.Size(), 10)
	// 读取文件
	fileBytes, err := os.ReadFile(filePath)
	if err != nil {
		return "", err
	}
	// 生成签名
	ts := fmt.Sprintf("%d", time.Now().Unix())
	signa := generateSignature(appId, secretKey, ts)
	// 上传
	client := &http.Client{}
	// 拼装请求信息
	request, _ := http.NewRequest("POST", "https://raasr.xfyun.cn/v2/api/upload", bytes.NewReader(fileBytes))
	// 请求参数(此处为必填项,其余参数参考文档)
	q := request.URL.Query()
	q.Add("appId", appId)
	q.Add("ts", ts)
	q.Add("signa", signa)
	q.Add("fileName", fileName)
	q.Add("fileSize", fileSize)
	q.Add("duration", "0")
	request.URL.RawQuery = q.Encode()
	// 设置请求头
	request.Header.Set("Content-Type", "application/json;charset=UTF-8")
	request.Header.Set("Chunked", "false")

	//处理返回结果
	response, _ := client.Do(request)
	defer response.Body.Close()
	body, _ := ioutil.ReadAll(response.Body)
	var res uploadRes
	_ = json.Unmarshal(body, &res)
	if res.Code == "000000" {
		return res.Content.OrderId, nil
	}
	return "", errors.New("res error :" + res.DescInfo)
}

// getOrderResult 获取订单结果
func getOrderResult(appId, secretKey, orderId string) (string, error) {
	// 生成签名
	ts := fmt.Sprintf("%d", time.Now().Unix())
	signa := generateSignature(appId, secretKey, ts)
	// 获取结果
	client := &http.Client{}
	request, _ := http.NewRequest("GET", "https://raasr.xfyun.cn/v2/api/getResult", nil)
	// 请求参数
	q := request.URL.Query()
	q.Add("appId", appId)
	q.Add("ts", ts)
	q.Add("signa", signa)
	q.Add("orderId", orderId)
	q.Add("resultType", "transfer")
	request.URL.RawQuery = q.Encode()
	// 设置请求头
	request.Header.Set("Content-Type", "multipart/form-data")
	//处理返回结果
	response, _ := client.Do(request)
	defer response.Body.Close()
	body, _ := ioutil.ReadAll(response.Body)
	var res getOrderResultRes
	_ = json.Unmarshal(body, &res)
	if res.Code == "000000" {
		if res.Content.OrderInfo.Status != 4 {
			return "", errors.New(fmt.Sprintf("transfer err: status %d,failType %d", res.Content.OrderInfo.Status, res.Content.OrderInfo.FailType))
		}
		// 处理转写结果
		return orderResultHandle(res.Content.OrderResult)
	}
	return "", errors.New("res error :" + res.DescInfo)
}

// generateSignature 生成签名
func generateSignature(appId, secretKey, ts string) string {
	// 拼接字符串
	baseString := appId + ts
	// md5
	hasher := md5.New()
	hasher.Write([]byte(baseString))
	hashInBytes := hasher.Sum(nil)
	md5BaseString := hex.EncodeToString(hashInBytes)
	// HmacSHA1 加密
	sha1Byte := hmacSHA1(secretKey, md5BaseString)
	// base64
	base64Str := base64.StdEncoding.EncodeToString(sha1Byte)

	return base64Str
}

func hmacSHA1(key, message string) []byte {
	keyBytes := []byte(key)
	messageBytes := []byte(message)
	mac := hmac.New(sha1.New, keyBytes)
	mac.Write(messageBytes)
	return mac.Sum(nil)
}

type orderResult struct {
	Lattice []struct {
		Json1best string `json:"json_1best"`
	} `json:"lattice"` // 顺滑处理后的结果 是字符串
	Lattice2 []lattice `json:"lattice2"` // 未顺滑处理的结果 是json对象
}

// Lattice 单句转写结果
type lattice struct {
	Lid       string    `json:"lid"`
	Begin     string    `json:"begin"`
	End       string    `json:"end"`
	Json1best json1best `json:"json_1best"`
}

// json1best 单句转写结果
type json1best struct {
	St st `json:"st"`
}

// st 单句转写结果
type st struct {
	Sc string `json:"sc"`
	Pa string `json:"pa"`
	Rt []rt   `json:"rt"`
}

// rt 词语识别结果
type rt struct {
	Nb string `json:"nb"`
	Nc string `json:"nc"`
	Ws []ws   `json:"ws"`
}

// ws 词语识别结果
type ws struct {
	Wb int64 `json:"wb"` // 词语开始的帧数(注一帧 10ms),位置是相对 bg,仅支持中、英文语种
	We int64 `json:"we"` // 词语结束的帧数(注一帧 10ms),位置是相对 bg,仅支持中、英文语种
	Cw []cw  `json:"cw"` // 词语候选识别结果集合
}

// Cw 词语识别结果
type cw struct {
	W  string `json:"w"`  // 识别结果
	Wp string `json:"wp"` // 词语的属性 n:正常词 s:顺滑 p:标点 g:分段(按此标识进行分段)
	Wc string `json:"wc"`
}

func orderResultHandle(orderResultStr string) (string, error) {
	var res orderResult
	err := json.Unmarshal([]byte(orderResultStr), &res)
	if err != nil {
		return "", err
	}
	var spliceStr string
	for _, la := range res.Lattice2 {
		for _, rt := range la.Json1best.St.Rt {
			for _, ws := range rt.Ws {
				if len(ws.Cw) > 0 {
					cw := ws.Cw[0]
					if cw.Wp == "g" {
						spliceStr += "\n"
					} else {
						spliceStr += cw.W
					}
				}
			}
		}
	}
	return spliceStr, nil
}


posted @   元気田支店长  阅读(33)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示